Skip to content
Snippets Groups Projects
Select Git revision
  • master
  • gitkeep
  • dev protected
  • Issue/2309-docs
  • Hotfix/2455-missingQuotaCheck
  • Issue/2328-noFailOnLog
  • Issue/2414-resourceTypesAffilAndAllocQuota
  • Hotfix/2427-adminTrouble
  • Hotfix/2428-savingRwthRdsS3
  • Fix/xxxx-enableResTypesForAllOrgas
  • Hotfix/2392-fixEmptyResult
  • Issue/2326-supportedOrganizations
  • Hotfix/2382-guestStillBuggy
  • Hotfix/2377-hidingSensibleInformationGuestRole
  • Hotfix/2371-fixGitLabinRCV
  • Fix/xxxx-activateGitlab
  • Test/xxxx-enablingGitLab
  • Issue/2275-DocuGitlabResourceType
  • Issue/2349-gitlabHttps
  • Issue/2287-guestRole
  • v3.5.7
  • v3.5.6
  • v3.5.5
  • v3.5.4
  • v3.5.3
  • v3.5.2
  • v3.5.1
  • v3.5.0
  • v3.4.4
  • v3.4.3
  • v3.4.2
  • v3.4.1
  • v3.4.0
  • v3.3.3
  • v3.3.2
  • v3.3.1
  • v3.3.0
  • v3.2.5
  • v3.2.4
  • v3.2.3
40 results

ResourceController.cs

Blame
  • L. Ellenbeck's avatar
    L. Ellenbeck authored and Petar Hristov committed
    60b649de
    History
    Code owners
    Assign users and groups as approvers for specific file changes. Learn more.
    ResourceController.cs 26.64 KiB
    using Coscine.Action;
    using Coscine.Action.EventArgs;
    using Coscine.ApiCommons;
    using Coscine.Configuration;
    using Coscine.Database.DataModel;
    using Coscine.Database.Models;
    using Coscine.Database.ReturnObjects;
    using Coscine.Database.Util;
    using Coscine.Logging;
    using Coscine.ResourceTypes;
    using Coscine.ResourceTypes.ResourceTypeConfigs;
    using Microsoft.AspNetCore.Authorization;
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.Extensions.Logging;
    using Newtonsoft.Json.Linq;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    
    namespace Coscine.Api.Resources.Controllers
    {
        /// <summary>
        /// This controller represents the actions which can be taken with a resource object.
        /// </summary>
        [Authorize]
        public class ResourceController : Controller
        {
            private readonly Authenticator _authenticator;
            private readonly ResourceModel _resourceModel;
            private readonly IConfiguration _configuration;
            private readonly Emitter _emitter;
            private readonly ProjectRoleModel _projectRoleModel;
            private readonly ProjectResourceModel _projectResourceModel;
            private readonly CoscineLogger _coscineLogger;
            private readonly ResourceTypeModel _resourceTypeModel;
            private readonly VisibilityModel _visibilityModel;
            private readonly LicenseModel _licenseModel;
    
            /// <summary>
            /// ResourceController constructor specifying a ResourceModel.
            /// </summary>
            public ResourceController(ILogger<ResourceController> logger)
            {
                _authenticator = new Authenticator(this, Program.Configuration);
                _configuration = Program.Configuration;
                _resourceModel = new ResourceModel();
                _emitter = new Emitter(_configuration);
                _projectRoleModel = new ProjectRoleModel();
                _projectResourceModel = new ProjectResourceModel();
                _coscineLogger = new CoscineLogger(logger);
                _resourceTypeModel = new ResourceTypeModel();
                _visibilityModel = new VisibilityModel();
                _licenseModel = new LicenseModel();
            }
    
            /// <summary>
            /// Returns a list of all resources the current user has access to.
            /// </summary>
            /// <returns>List of Resources</returns>
            [Route("[controller]")]
            public IActionResult Index()
            {
                var user = _authenticator.GetUser();
                return Json(_resourceModel.GetAllWhere((resource) =>
                    (from projectResource in resource.ProjectResources
                     where (from projectRole in projectResource.Project.ProjectRoles
                            where projectRole.User == user
                            && (projectRole.Role.DisplayName == "Owner" || projectRole.Role.DisplayName == "Member")
                            && !projectRole.Project.Deleted
                            select projectRole).Any()
                     select projectResource).Any()
                ).Select((resource) => Helpers.CreateResourceReturnObject(resource)));
            }
    
            /// <summary>
            /// Returns the resource with a specified id.
            /// </summary>
            /// <param name="id">The resource id.</param>
            /// <returns>ResourceObject if OK, 401 if not authorized</returns>
            [HttpGet("[controller]/{id}")]
            public IActionResult Get(Guid id)
            {
                var resource = _resourceModel.GetById(id);
                var user = _authenticator.GetUser();
    
                // Rights Matrix (https://git.rwth-aachen.de/coscine/docs/private/internal-wiki/-/blob/master/coscine/Definition%20of%20rights%20Matrix.md)
                // - Resource: View Resource (RCV, Metadatamanager)
                if (_resourceModel.HasAccess(user, resource, UserRoles.Owner, UserRoles.Member, UserRoles.Guest))
                {
                    _resourceModel.SetType(resource);
    
                    var returnObject = Helpers.CreateResourceReturnObject(resource);
    
                    if (_resourceModel.HasAccess(user, resource, UserRoles.Guest))
                    {
                        returnObject.ResourceTypeOption = null;
                    }
    
                    return Json(returnObject);
                }
                else
                {
                    return Unauthorized("User does not own this resource!");
                }
            }
    
            /// <summary>
            /// Returns whether or not the current user is creator of a specified resource.
            /// </summary>
            /// <param name="id">The resource id.</param>
            /// <returns>JSON object.</returns>
            [HttpGet("[controller]/{id}/isCreator")]
            public IActionResult IsUserResourceCreator(Guid id)
            {
                var resource = _resourceModel.GetById(id);
                var user = _authenticator.GetUser();
                return Json(new JObject
                {
                    ["isResourceCreator"] = resource.Creator.Equals(user.Id)
                });
            }
    
            /// <summary>
            /// Updates a resource.
            /// </summary>
            /// <param name="id">The resource id.</param>
            /// <param name="resourceObject">Entry representing the user</param>
            /// <returns>JSON object.</returns>
            [HttpPost("[controller]/{id}")]
            public IActionResult Update(Guid id, [FromBody] ResourceObject resourceObject)
            {
                var resource = _resourceModel.GetById(id);
                var resourceTypeModel = new ResourceTypeModel();
                var resourceType = resourceTypeModel.GetById(resource.TypeId);
                if (resource.Archived == "0")
                {
                    // TODO: Consider making all those checks automatically as annotations over the Object<ResourceObject>
                    if (!(string.IsNullOrWhiteSpace(resourceObject.DisplayName) ||
                        string.IsNullOrWhiteSpace(resourceObject.ResourceName) ||
                        string.IsNullOrWhiteSpace(resourceObject.Description) ||
                        resourceObject.Disciplines?.Any() != true ||
                        resourceObject.Visibility == null))
                    {
                        var user = _authenticator.GetUser();
    
                        // Rights Matrix (https://git.rwth-aachen.de/coscine/docs/private/internal-wiki/-/blob/master/coscine/Definition%20of%20rights%20Matrix.md)
                        // - Resource: Change Resource Settings
                        if (_resourceModel.HasAccess(user, resource, UserRoles.Owner) ||
                            (_resourceModel.HasAccess(user, resource, UserRoles.Member) && resource.Creator.Equals(user.Id)))
                        {
                            LogAnalyticsEditResource(resource, _resourceModel.GetMetadataCompleteness(resourceObject), resourceObject.Disciplines, user);
    
                            var result = SetResourceTypeOptions(resource, resourceType, resourceObject);
                            if (result != null)
                            {
                                return result;
                            }
    
                            var resourceTypeDefinition = ResourceTypeFactory.Instance.GetResourceType(resource);
                            if (resourceTypeDefinition.GetResourceTypeInformation().Result.CanUpdateResource)
                            {
                                resourceTypeDefinition.UpdateResource(id.ToString());
                            }
                            return Json(_resourceModel.UpdateByObject(resource, resourceObject));
                        }
                        else
                        {
                            return Unauthorized("The user is not authorized to perform an update on the selected resource!");
                        }
                    }
                    else
                    {
                        return BadRequest("Mandatory information of the resource is missing!");
                    }
                }
                else
                {
                    return BadRequest("The resource is archived and cannot be modified!");
                }
            }
    
            /// <summary>
            /// Sets a read only status of a given resource.
            /// </summary>
            /// <param name="id">A GUID as a string that identifies the resource.</param>
            /// <param name="status">A boolean value that specifies if the resource is archived.</param>
            /// <returns>JSON object.</returns>
            [HttpPost("[controller]/{id}/setReadonly")]
            public IActionResult SetResourceReadonly(Guid id, bool status)
            {
                var resource = _resourceModel.GetById(id);
                var user = _authenticator.GetUser();
    
                // Rights Matrix (https://git.rwth-aachen.de/coscine/docs/private/internal-wiki/-/blob/master/coscine/Definition%20of%20rights%20Matrix.md)
                // - Resource: Change Resource Settings
                if (_resourceModel.HasAccess(user, resource, UserRoles.Owner) ||
                    (_resourceModel.HasAccess(user, resource, UserRoles.Member) && resource.Creator.Equals(user.Id)))
                {
                    var resourceTypeDefinition = ResourceTypeFactory.Instance.GetResourceType(resource);
                    if (resourceTypeDefinition.GetResourceTypeInformation().Result.CanSetResourceReadonly)
                    {
                        resourceTypeDefinition.SetResourceReadonly(id.ToString(), status);
                    }
    
                    // update archived status of the resource
                    resource.Archived = status ? "1" : "0";
                    _resourceModel.Update(resource);
    
                    var returnObject = Helpers.CreateResourceReturnObject(resource);
    
                    if (Request.Query != null && Request.Query["noanalyticslog"] != "true")
                    {
                        if (status)
                        {
                            LogAnalyticsArchiveResource(resource, user);
                        }
                        else
                        {
                            LogAnalyticsUnarchiveResource(resource, user);
                        }
                    }
                    return Json(returnObject);
                }
                else
                {
                    return Unauthorized("The user is not authorized to perform an update on the selected resource!");
                }
            }
    
            /// <summary>
            /// Deletes a resource.
            /// </summary>
            /// <param name="id">A GUID as a string that identifies the resource.</param>
            /// <returns>Deleted ResourceObject if OK, 401 if not</returns>
            [HttpDelete("[controller]/{id}")]
            public IActionResult Delete(Guid id)
            {
                var resource = _resourceModel.GetById(id);
                var user = _authenticator.GetUser();
    
                // Rights Matrix (https://git.rwth-aachen.de/coscine/docs/private/internal-wiki/-/blob/master/coscine/Definition%20of%20rights%20Matrix.md)
                // - Resource: Change Resource Settings
                if (_resourceModel.HasAccess(user, resource, UserRoles.Owner) ||
                    (_resourceModel.HasAccess(user, resource, UserRoles.Member) && resource.Creator.Equals(user.Id)))
                {
                    var resourceObject = Helpers.CreateResourceReturnObject(resource);
    
                    LogAnalyticsDeleteResource(resource, _resourceModel.GetMetadataCompleteness(resourceObject), resourceObject.Disciplines, user);
    
                    _emitter.EmitResourceDelete(new ResourceEventArgs(_configuration)
                    {
                        Resource = resource
                    });
    
                    _resourceModel.DeleteResource(resource);
    
                    return Json(resourceObject);
                }
                else
                {
                    return Unauthorized("The user is not authorized to perform an update on the selected resource!");
                }
            }
    
            /// <summary>
            /// Stores the provided resource object in a specified project.
            /// </summary>
            /// <param name="projectId">A GUID as a string that identifies the resource.</param>
            /// <param name="resourceObject">Entry representing the user</param>
            /// <returns>JSON object.</returns>
            [HttpPost("[controller]/project/{projectId}")]
            public async Task<IActionResult> StoreToProject(Guid projectId, [FromBody] ResourceObject resourceObject)
            {
                var projectModel = new ProjectModel();
                var resourceTypeModel = new ResourceTypeModel();
                var resourceType = resourceTypeModel.GetById(resourceObject.Type.Id);
                var project = projectModel.GetById(projectId);
                var user = _authenticator.GetUser();
    
                if (resourceType.Type == "gitlab")
                {
                    var parseTosAccepted = bool.TryParse(resourceObject.ResourceTypeOption["TosAccepted"]?.ToString(), out var gitlabTosAccepted);
    
                    if (!parseTosAccepted)
                    {
                        return BadRequest(@"""ResourceTypeOption"" does not contain a valid ""TosAccepted"".");
                    }
    
                    if (!gitlabTosAccepted)
                    {
                        return BadRequest("Gitlab Terms of Service not accepted!");
                    }
                }
    
                if (string.IsNullOrWhiteSpace(user.EmailAddress))
                {
                    return Unauthorized("Access denied!");
                }
    
                // Rights Matrix (https://git.rwth-aachen.de/coscine/docs/private/internal-wiki/-/blob/master/coscine/Definition%20of%20rights%20Matrix.md)
                // - Resource: Create Resource
                if (projectModel.HasAccess(user, project, UserRoles.Owner, UserRoles.Member))
                {
                    var orgs = Util.OrganizationsHelper.GetOrganization(user);
    
                    if (orgs?.Any() != true)
                    {
                        orgs = new List<string> { "*" };
                    }
    
                    if (!Util.ResourceTypeHelper.IsResourceTypeUsable(resourceType, projectId, orgs))
                    {
                        return Unauthorized("The user is not authorized to add a new resource of this type to the selected project!");
                    }
    
                    var totalReservedQuota = Helpers.CalculateTotalReservedQuota(resourceType, projectId);
                    var maximumQuota = Helpers.GetMaximumQuota(projectId, resourceType.Id);
    
                    var success = long.TryParse(resourceObject.ResourceTypeOption["Size"]?.ToString(), out long desiredResourceQuota);
    
                    var freeQuota = new QuotaDimObject
                    {
                        Value = Helpers.ConvertCapacityUnits(maximumQuota, QuotaUnit.GibiBYTE) - Helpers.ConvertCapacityUnits(totalReservedQuota, QuotaUnit.GibiBYTE),
                        Unit = QuotaUnit.GibiBYTE
                    };
    
                    if (success && desiredResourceQuota > freeQuota.Value)
                    {
                        return BadRequest($"You can not create a resource with a quota value of {desiredResourceQuota} GB. You have already reserved {Helpers.ConvertCapacityUnits(totalReservedQuota, QuotaUnit.GibiBYTE)} GB for {resourceObject.Type.DisplayName} resources and have only {freeQuota.Value} GB free.");
                    }
    
                    var resource = _resourceModel.StoreFromObject(resourceObject, user);
    
                    var result = SetResourceTypeOptions(resource, resourceType, resourceObject);
                    if (result != null)
                    {
                        return result;
                    }
    
                    var resourceTypeDefinition = ResourceTypeFactory.Instance.GetResourceType(resource);
    
                    await resourceTypeDefinition.CreateResource(resource.Id.ToString(), desiredResourceQuota);
                    projectModel.AddResource(project, resource);
    
                    _emitter.EmitResourceCreate(new ResourceEventArgs(_configuration)
                    {
                        Resource = resource
                    });
    
                    var resourceReturnObject = Helpers.CreateResourceReturnObject(resource);
                    LogAnalyticsAddResource(resource, _resourceModel.GetMetadataCompleteness(resourceReturnObject), resourceReturnObject.Disciplines, user);
                    return Json(resourceReturnObject);
                }
                else
                {
                    return Unauthorized("The user is not authorized to add a new resource to the selected project!");
                }
            }
    
            private IActionResult SetResourceTypeOptions(Database.DataModel.Resource resource, Database.DataModel.ResourceType resourceType, ResourceObject resourceObject)
            {
                GetResourceTypeConfigOptions getConfig = null;
    
                if (resourceType.Type == "rdss3" || resourceType.Type == "rdss3worm")
                {
                    getConfig = new GetRdsResourceTypeConfigOptions { Bucketname = resource.Id.ToString() };
                }
                else if (resourceType.Type == "gitlab")
                {
                    var accessToken = resourceObject.ResourceTypeOption["AccessToken"]?.ToString();
    
                    if (string.IsNullOrWhiteSpace(accessToken))
                    {
                        return BadRequest(@"""ResourceTypeOption"" does not contain an valid ""AccessToken"".");
                    }
    
                    var parseResult = int.TryParse(resourceObject.ResourceTypeOption["ProjectId"]?.ToString(), out var gitlabProjectId);
    
                    if (!parseResult)
                    {
                        return BadRequest(@"""ResourceTypeOption"" does not contain a valid ""ProjectId"".");
                    }
    
                    var repoUrl = resourceObject.ResourceTypeOption["RepoUrl"]?.ToString();
    
                    if (string.IsNullOrWhiteSpace(repoUrl))
                    {
                        return BadRequest(@"""ResourceTypeOption"" does not contain a valid ""RepoUrl"".");
                    }
    
                    var branch = resourceObject.ResourceTypeOption["Branch"]?.ToString();
    
                    if (string.IsNullOrWhiteSpace(branch))
                    {
                        return BadRequest(@"""ResourceTypeOption"" does not contain a valid ""Branch"".");
                    }
    
                    var parseTosAccepted = bool.TryParse(resourceObject.ResourceTypeOption["TosAccepted"]?.ToString(), out var gitlabTosAccepted);
    
                    if (!parseTosAccepted)
                    {
                        return BadRequest(@"""ResourceTypeOption"" does not contain a valid ""TosAccepted"".");
                    }
    
                    getConfig = new GetGitLabResourceTypeConfigOptions { AccessToken = accessToken, ProjectId = gitlabProjectId, RepoUrl = repoUrl, Branch = branch, TosAccepted = gitlabTosAccepted };
                }
                var config = ResourceTypeFactory.Instance.GetResourceTypeConfig(resourceType.Type, resourceType.SpecificType, getConfig);
                ResourceTypeFactory.Instance.SaveResourceTypeToDatabase(resourceType.Type, config, resource);
    
                return null;
            }
    
            private async Task LogAnalyticsEditResource(Database.DataModel.Resource resource, string metadataCompleteness, IEnumerable<DisciplineObject> disciplines, User user)
            {
                await Task.Run(() =>
                {
                    var resourceTypeDisplayName = _resourceTypeModel.GetById(resource.TypeId).DisplayName;
                    var projectId = _projectResourceModel.GetProjectForResource(resource.Id).Value;
                    var reserved = GetReservedResourceQuota(resource);
                    var maximum = GetMaximumResourceQuota(resource, projectId);
                    var analyticsLogObject = new AnalyticsLogObject
                    {
                        Operation = "Edit Resource",
                        Type = "Action",
                        RoleId = _projectRoleModel.GetGetUserRoleForProject(projectId, user.Id).ToString(),
                        ProjectId = projectId.ToString(),
                        QuotaSize = new List<string> { $"{resourceTypeDisplayName}: {reserved}/{maximum}" },
                        ResourceId = resource.Id.ToString(),
                        ApplicationsProfile = resource.ApplicationProfile,
                        MetadataCompleteness = metadataCompleteness,
                        License = resource.LicenseId.HasValue ? _licenseModel.GetById(resource.LicenseId.Value)?.DisplayName : null,
                        Disciplines = disciplines.Select(x => x.DisplayNameEn).ToList(),
                        Visibility = resource.VisibilityId.HasValue ? _visibilityModel.GetById(resource.VisibilityId.Value)?.DisplayName : null,
                    };
    
                    _coscineLogger.AnalyticsLog(analyticsLogObject);
                });
            }
    
            private async Task LogAnalyticsAddResource(Database.DataModel.Resource resource, string metadataCompleteness, IEnumerable<DisciplineObject> disciplines, User user)
            {
                await Task.Run(() =>
                {
                    var resourceTypeDisplayName = _resourceTypeModel.GetById(resource.TypeId).DisplayName;
                    var projectId = _projectResourceModel.GetProjectForResource(resource.Id).Value;
                    var reserved = GetReservedResourceQuota(resource);
                    var maximum = GetMaximumResourceQuota(resource, projectId);
                    var analyticsLogObject = new AnalyticsLogObject
                    {
                        Operation = "Add Resource",
                        Type = "Action",
                        RoleId = _projectRoleModel.GetGetUserRoleForProject(projectId, user.Id).ToString(),
                        ProjectId = projectId.ToString(),
                        QuotaSize = new List<string> { $"{resourceTypeDisplayName}: {reserved}/{maximum}" },
                        ResourceId = resource.Id.ToString(),
                        ApplicationsProfile = resource.ApplicationProfile,
                        MetadataCompleteness = metadataCompleteness,
                        License = resource.LicenseId.HasValue ? _licenseModel.GetById(resource.LicenseId.Value)?.DisplayName : null,
                        Disciplines = disciplines.Select(x => x.DisplayNameEn).ToList(),
                        Visibility = resource.VisibilityId.HasValue ? _visibilityModel.GetById(resource.VisibilityId.Value)?.DisplayName : null,
                    };
    
                    _coscineLogger.AnalyticsLog(analyticsLogObject);
                });
            }
    
            private async Task LogAnalyticsDeleteResource(Database.DataModel.Resource resource, string metadataCompleteness, IEnumerable<DisciplineObject> disciplines, User user)
            {
                await Task.Run(() =>
                {
                    var resourceTypeDisplayName = _resourceTypeModel.GetById(resource.TypeId).DisplayName;
                    var projectId = _projectResourceModel.GetProjectForResource(resource.Id).Value;
                    var reserved = GetReservedResourceQuota(resource);
                    var maximum = GetMaximumResourceQuota(resource, projectId);
                    var analyticsLogObject = new AnalyticsLogObject
                    {
                        Operation = "Delete Resource",
                        Type = "Action",
                        RoleId = _projectRoleModel.GetGetUserRoleForProject(projectId, user.Id).ToString(),
                        ProjectId = projectId.ToString(),
                        QuotaSize = new List<string> { $"{resourceTypeDisplayName}: {reserved}/{maximum}" },
                        ResourceId = resource.Id.ToString(),
                        ApplicationsProfile = resource.ApplicationProfile,
                        MetadataCompleteness = metadataCompleteness,
                        License = resource.LicenseId.HasValue ? _licenseModel.GetById(resource.LicenseId.Value)?.DisplayName : null,
                        Disciplines = disciplines.Select(x => x.DisplayNameEn).ToList(),
                        Visibility = resource.VisibilityId.HasValue ? _visibilityModel.GetById(resource.VisibilityId.Value)?.DisplayName : null,
                    };
    
                    _coscineLogger.AnalyticsLog(analyticsLogObject);
                });
            }
    
            private async Task LogAnalyticsArchiveResource(Database.DataModel.Resource resource, User user)
            {
                await Task.Run(() =>
                {
                    var projectId = _projectResourceModel.GetProjectForResource(resource.Id).Value;
                    var analyticsLogObject = new AnalyticsLogObject
                    {
                        Operation = "Archive Resource",
                        Type = "Action",
                        RoleId = _projectRoleModel.GetGetUserRoleForProject(projectId, user.Id).ToString(),
                        ProjectId = projectId.ToString(),
                        ResourceId = resource.Id.ToString(),
                        ApplicationsProfile = resource.ApplicationProfile,
                        License = resource.LicenseId.HasValue ? _licenseModel.GetById(resource.LicenseId.Value)?.DisplayName : null
                    };
    
                    _coscineLogger.AnalyticsLog(analyticsLogObject);
                });
            }
    
            private async Task LogAnalyticsUnarchiveResource(Database.DataModel.Resource resource, User user)
            {
                await Task.Run(() =>
                {
                    var projectId = _projectResourceModel.GetProjectForResource(resource.Id).Value;
                    var analyticsLogObject = new AnalyticsLogObject
                    {
                        Operation = "Unarchive Resource",
                        Type = "Action",
                        RoleId = _projectRoleModel.GetGetUserRoleForProject(projectId, user.Id).ToString(),
                        ProjectId = projectId.ToString(),
                        ResourceId = resource.Id.ToString(),
                        ApplicationsProfile = resource.ApplicationProfile,
                        License = resource.LicenseId.HasValue ? _licenseModel.GetById(resource.LicenseId.Value)?.DisplayName : null
                    };
    
                    _coscineLogger.AnalyticsLog(analyticsLogObject);
                });
            }
    
            private static int GetReservedResourceQuota(Database.DataModel.Resource resource)
            {
                var resourceTypeDefinition = ResourceTypeFactory.Instance.GetResourceType(resource);
                if (resourceTypeDefinition.GetResourceTypeInformation().Result.IsQuotaAvailable)
                {
                    try
                    {
                        return (int)resourceTypeDefinition.GetResourceQuotaAvailable(resource.Id.ToString()).Result;
                    }
                    catch (Exception)
                    {
                        // Error communicating with the resource
                    }
                }
                return 0;
            }
    
            private static int GetMaximumResourceQuota(Database.DataModel.Resource resource, Guid parentProjectId)
            {
                var projectQuotaModel = new ProjectQuotaModel();
                var projectQuota =
                    projectQuotaModel.GetWhere((x) =>
                        x.ProjectId == parentProjectId &&
                        x.ResourceTypeId == resource.TypeId);
                var reservedForCurrent = GetReservedResourceQuota(resource);
                var resourceTypeModel = new ResourceTypeModel();
                // Get the resource type
                var resourceType = resourceTypeModel.GetById(resource.TypeId);
                if (resourceType == null)
                {
                    throw new ArgumentNullException($"Could not find resourceType with id: {resource.TypeId}");
                }
                var totalReserved = Helpers.CalculateTotalReservedQuota(resourceType, parentProjectId);
                return (int)(projectQuota.Quota - (totalReserved.Value - reservedForCurrent));
            }
        }
    }