Skip to content
Snippets Groups Projects
Select Git revision
  • dfb379668b5106654c867b75304dba38cf8f102b
  • master default protected
  • gitkeep
  • dev protected
  • Issue/2309-docs
  • Hotfix/2427-adminTrouble
  • Issue/2330-fixNaNQuotainAdmin
  • Hotfix/2224-quotaSizeAnalytics
  • Fix/xxxx-resourceVisibility
  • Issue/1951-quotaImplementation
  • Issue/2072-wormResourceType
  • Issue/2061-activateResourceTypeRdss3nrw
  • Hotfix/2077-fixSupportAdminLog
  • Hotfix/2087-efNet6
  • Issue/1910-MigrationtoNET6.0
  • Sprint/2022-05
  • Issue/2001-extendAnalyticsLogger
  • Issue/1940ResouceKeysForNRWAndTUDO
  • Sprint/2022-01
  • Issue/1866-ExtendResourceTypeConfigurationTUDo
  • Issue/1877-ExtendResourceTypeConfigurationNRWFHs
  • v3.0.8
  • v3.0.7
  • v3.0.6
  • v3.0.5
  • v3.0.4
  • v3.0.3
  • v3.0.2
  • v3.0.1
  • v3.0.0
  • v2.6.1
  • v2.6.0
  • v2.5.4
  • v2.5.3
  • v2.5.2
  • v2.5.1
  • v2.5.0
  • v2.4.0
  • v2.3.2
  • v2.3.1
  • v2.3.0
41 results

AdminController.cs

  • Code owners
    Assign users and groups as approvers for specific file changes. Learn more.
    AdminController.cs 10.41 KiB
    using Coscine.Action;
    using Coscine.Action.EventArgs;
    using Coscine.Api.Admin.ParameterObjects;
    using Coscine.Api.Admin.ReturnObjects;
    using Coscine.ApiCommons;
    using Coscine.Configuration;
    using Coscine.Database.DataModel;
    using Coscine.Database.Models;
    using Coscine.Logging;
    using Coscine.Metadata;
    using Coscine.ResourceTypes;
    using Microsoft.AspNetCore.Authorization;
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.Extensions.Logging;
    using System;
    using System.Linq;
    
    namespace Coscine.Api.Admin.Controllers
    {
        /// <summary>
        /// This controller represents the actions which can be taken with a user object.
        /// </summary>
        [Authorize]
        public class AdminController : Controller
        {
            private readonly RdfStoreConnector _rdfStoreConnector = new(Program.Configuration.GetStringAndWait("coscine/local/virtuoso/additional/url"));
            private readonly Authenticator _authenticator;
            private readonly string _graphUrl;
            private readonly string _memberUrl;
            private readonly string _userUrlPrefix;
            private readonly string _roleUrl;
            private readonly string _roleUrlPrefix;
            private readonly string _adminRole;
            private readonly ResourceModel _resourceModel;
            private readonly ProjectModel _projectModel;
            private readonly ProjectQuotaModel _projectQuotaModel;
            private readonly ResourceTypeModel _resourceTypeModel;
            private readonly Emitter _emitter;
            private readonly float _oneGb = 1024 * 1024 * 1024;
            private readonly CoscineLogger _coscineLogger;
    
            /// <summary>
            /// Default Constructor.
            /// </summary>
            public AdminController(ILogger<AdminController> logger)
            {
                _authenticator = new Authenticator(this, Program.Configuration);
                _graphUrl = "https://ror.org/04xfq0f34/roles";
                _memberUrl = "http://www.w3.org/ns/org#member";
                _userUrlPrefix = "https://coscine.rwth-aachen.de/u/";
                _roleUrl = "http://www.w3.org/ns/org#role";
                _roleUrlPrefix = "https://purl.org/coscine/terms/role#";
                _adminRole = "supportAdmin";
                _resourceModel = new ResourceModel();
                _projectModel = new ProjectModel();
                _projectQuotaModel = new ProjectQuotaModel();
                _resourceTypeModel = new ResourceTypeModel();
                _emitter = new Emitter(Program.Configuration);
                _coscineLogger = new CoscineLogger(logger);
            }
    
            /// <summary>
            /// Check if the user has a specific role.
            /// </summary>
            /// <param name="userId">Id (GUID) if the user.</param>
            /// <param name="role">The role of the user.</param>
            /// <returns>True if user has the role and false if not.</returns>
            private bool HasRole(string userId, string role)
            {
                var graph = _rdfStoreConnector.GetGraph(_graphUrl);
    
                // Get the subject (blank node for the specific member)
                var userTriples = graph.GetTriplesWithPredicateObject(graph.CreateUriNode(new Uri(_memberUrl)), graph.CreateUriNode(new Uri($"{_userUrlPrefix}{userId.ToUpper()}")));
    
                // Extract the node
                var userSubject = userTriples?.FirstOrDefault()?.Subject;
                if (userSubject == null)
                {
                    return false;
                }
    
                // Get the role based on the blank node and compare it to the requested role
                var roleTriples = graph.GetTriplesWithSubjectPredicate(userSubject, graph.CreateUriNode(new Uri(_roleUrl)));
                return (roleTriples?.FirstOrDefault()?.Object.ToString()) == _roleUrlPrefix + role;
            }
    
            /// <summary>
            /// Sum up allocated quota for all resources of a given resource type within a project.
            /// </summary>
            /// <param name="resourceType">The used resource type.</param>
            /// <param name="projectId">The used project.</param>
            /// <returns>Allocated quota of the given resource type in the project.</returns>
            private int CalculateAllocatedForAll(ResourceType resourceType, Guid projectId)
            {
                var resources = _resourceModel.GetAllWhere((resource) =>
                            (from projectResource in resource.ProjectResources
                             where projectResource.ProjectId == projectId
                             select projectResource).Any() &&
                             resource.TypeId == resourceType.Id);
    
                var allocated = resources.Sum(resource => ResourceTypeFactory
                    .Instance
                    .GetResourceType(resource)
                    .GetResourceQuotaAvailable(resource.Id.ToString(), _resourceModel.GetResourceTypeOptions(resource.Id))
                    .Result);
    
                return (int)allocated;
            }
    
            /// <summary>
            /// Sum up used quota for all resources of a given resource type within a project.
            /// </summary>
            /// <param name="resourceType">The used resource type.</param>
            /// <param name="projectId">The used project.</param>
            /// <returns>Used quota of the given resource type in the project.</returns>
            private int CalculateUsedForAll(ResourceType resourceType, Guid projectId)
            {
                var resources = _resourceModel.GetAllWhere((resource) =>
                            (from projectResource in resource.ProjectResources
                             where projectResource.ProjectId == projectId
                             select projectResource).Any() &&
                             resource.TypeId == resourceType.Id);
    
                var used = Math.Ceiling(resources.Sum(resource => ResourceTypeFactory
                    .Instance
                    .GetResourceType(resource)
                    .GetResourceQuotaUsed(resource.Id.ToString(), _resourceModel.GetResourceTypeOptions(resource.Id))
                    .Result / _oneGb));
    
                return (int)used;
            }
    
            /// <summary>
            /// Find the project related to the projectString(GUID or slug)
            /// </summary>
            /// <param name="projectString">Either the id (GUID) of the project or the slug.</param>
            /// <returns>JSON list of all quotas.</returns>
            [HttpGet("[controller]/{projectString}")]
            public ActionResult<ProjectObject> GetProject(string projectString)
            {
                var user = _authenticator.GetUserId();
                if (!HasRole(user, _adminRole))
                {
                    return Unauthorized($@"User has not the role: ""{_adminRole}"".");
                }
    
                Project project;
    
                if (Guid.TryParse(projectString, out Guid guid))
                {
                    project = _projectModel.GetById(guid);
                }
                else
                {
                    project = _projectModel.GetBySlug(projectString);
                }
    
                if (project == null)
                {
                    return NotFound("Project was not found.");
                }
    
                var quotas = _projectQuotaModel.GetAllWhere(x => x.ProjectId == project.Id);
    
                return new ProjectObject
                {
                    GUID = project.Id,
                    Name = project.ProjectName,
                    ShortName = project.DisplayName,
                    Quotas = quotas.Select(x => new ProjectQuotaObject
                    {
                        QuotaId = x.RelationId,
                        ResourceType = _resourceTypeModel.GetById(x.ResourceTypeId).DisplayName,
                        Quota = x.Quota,
                        MaxQuota = x.MaxQuota,
                        Used = CalculateUsedForAll(_resourceTypeModel.GetById(x.ResourceTypeId), project.Id),
                        Allocated = CalculateAllocatedForAll(_resourceTypeModel.GetById(x.ResourceTypeId), project.Id)
                    }).ToList(),
                };
            }
    
            /// <summary>
            /// Update the project quota
            /// </summary>
            /// <param name="updateQuotaParameter">JSON object for updating quota.</param>
            /// <returns>NoContent (204) on success.</returns>
            [HttpPost("[controller]/")]
            public IActionResult UpdateQuota([FromBody] UpdateQuotaParameterObject updateQuotaParameter)
            {
                var user = _authenticator.GetUser();
                if (!HasRole(user.Id.ToString(), _adminRole))
                {
                    return Unauthorized($@"User has not the role: ""{_adminRole}"".");
                }
    
                var projectQuotaModel = new ProjectQuotaModel();
                var projectQuota = projectQuotaModel.GetById(updateQuotaParameter.QuotaId);
    
                if (projectQuota == null)
                {
                    return NotFound("Quota was not found.");
                }
    
                projectQuota.MaxQuota = (int)updateQuotaParameter.Quota;
                projectQuota.Quota = projectQuota.MaxQuota;
                projectQuotaModel.Update(projectQuota);
    
                _emitter.EmitQuotaChanged(new AdminEventArgs(Program.Configuration) { ProjectId = projectQuota.ProjectId });
    
                if (Request.Query != null && Request.Query["noanalyticslog"] != "true")
                {
                    LogAnalyticsAdminProjectQuotaChange(projectQuota.ProjectId, user);
                }
    
                return NoContent();
            }
    
            private void LogAnalyticsAdminProjectQuotaChange(Guid projectId, User user)
            {
                try
                {
                    var quotas = _projectQuotaModel.GetAllWhere(x => x.ProjectId == projectId);
                    var quotaObjects = quotas.Select(x => new ProjectQuotaObject
                    {
                        QuotaId = x.RelationId,
                        ResourceType = _resourceTypeModel.GetById(x.ResourceTypeId).DisplayName,
                        Quota = x.Quota,
                        MaxQuota = x.MaxQuota,
                        Used = x.Quota,
                        Allocated = CalculateAllocatedForAll(_resourceTypeModel.GetById(x.ResourceTypeId), projectId)
                    }).ToList();
    
                    _coscineLogger.AnalyticsLog(
                        new AnalyticsLogObject
                        {
                            Type = "Action",
                            Operation = "Admin Project Quota Change",
                            UserId = user.Id.ToString(),
                            ProjectId = projectId.ToString(),
                            QuotaSize = quotaObjects.ConvertAll(x => $"{x.ResourceType}: {x.Allocated}/{x.Used}")
                        });
                }
    #pragma warning disable RCS1075 // Avoid empty catch clause that catches System.Exception.
                catch (Exception)
    #pragma warning restore RCS1075 // Avoid empty catch clause that catches System.Exception.
                {
                }
            }
        }
    }