Skip to content
Snippets Groups Projects
Select Git revision
  • 02b5fd9f3e897795a07d997e34da65226c73708e
  • master default protected
  • gitkeep
  • dev protected
  • Issue/2309-docs
  • devops-aczepiel
  • Issue/2158-emailServicedesk
  • Issue/1938-internalHandling
  • Hotfix/2097-fixTimeFormat
  • Hotfix/2087-efNet6
  • Issue/1910-MigrationtoNET6.0
  • Issue/1826-versioning
  • Sprint/2022-01
  • Hotfix/1917-vocabCheck
  • Issue/1804-fixedValueFix
  • Hotfix/xxxx-notExposedGraphs
  • Sprint/2021-23
  • Issue/1746-ApplicationProfileStoringMethod
  • Hotfix/82-updateDepsOfAPIs
  • Product/1549-speedupQuerying
  • Topic/1598-speedupQuerying
  • v3.2.3
  • v3.2.2
  • v3.2.1
  • v3.2.0
  • v3.1.2
  • v3.1.1
  • v3.1.0
  • v3.0.2
  • v3.0.1
  • v3.0.0
  • v2.2.1
  • v2.2.0
  • v2.1.1
  • v2.1.0
  • v2.0.4
  • v2.0.3
  • v2.0.2
  • v2.0.1
  • v2.0.0
  • v1.7.1
41 results

MetadataController.cs

Blame
  • Code owners
    Assign users and groups as approvers for specific file changes. Learn more.
    MetadataController.cs 11.92 KiB
    using Coscine.Action;
    using Coscine.Action.EventArgs;
    using Coscine.Api.Metadata.ParameterObjects;
    using Coscine.ApiCommons;
    using Coscine.ApiCommons.Exceptions;
    using Coscine.Configuration;
    using Coscine.Database.Models;
    using Coscine.Database.Util;
    using Coscine.Metadata;
    using GitLabApiClient;
    using GitLabApiClient.Models.Branches.Requests;
    using GitLabApiClient.Models.Commits.Requests.CreateCommitRequest;
    using GitLabApiClient.Models.MergeRequests.Requests;
    using Microsoft.AspNetCore.Authorization;
    using Microsoft.AspNetCore.Mvc;
    using Newtonsoft.Json.Linq;
    using System;
    using System.Collections.Generic;
    using System.Net;
    using System.Threading.Tasks;
    using System.Web;
    using VDS.RDF;
    using VDS.RDF.Parsing;
    using VDS.RDF.Writing;
    
    namespace Coscine.Api.Metadata.Controllers
    {
        /// <summary>
        /// This controller represents the actions which can be performed with a Metadata storage.
        /// </summary>
        [Authorize]
        public class MetadataController : Controller
        {
            private readonly Authenticator _authenticator;
            private readonly Emitter _emitter;
            private readonly IConfiguration _configuration;
            private readonly ResourceModel _resourceModel;
            private readonly RdfStoreConnector _rdfStoreConnector;
            private static readonly string HostUrl = "https://git.rwth-aachen.de/";
            private readonly string ApplicationProfileUrl = "https://purl.org/coscine/ap/";
            private static readonly string ApplicationProfileProjectURL = HttpUtility.UrlEncode("coscine/graphs/applicationprofiles");
    
            /// <summary>
            /// MetadataController constructor specifying an authenticator and a ResourceModel.
            /// </summary>
            public MetadataController()
            {
                _configuration = Program.Configuration;
                _authenticator = new Authenticator(this, _configuration);
                _resourceModel = new ResourceModel();
                _rdfStoreConnector = new RdfStoreConnector(_configuration.GetStringAndWait("coscine/local/virtuoso/additional/url"));
                _emitter = new Emitter(_configuration);
            }
    
            /// <summary>
            /// This method returns all application profiles.
            /// </summary>
            /// <returns>profiles</returns>
            [HttpGet("[controller]/profiles/")]
            [AllowAnonymous]
            public IActionResult GetProfiles()
            {
                var applicationProfiles = _rdfStoreConnector.GetApplicationProfiles();
                return Json(new JArray(applicationProfiles));
            }
    
            /// <summary>
            /// This method returns the application profile for the given profileUrl.
            /// </summary>
            /// <param name="profile">Url of the application profile</param>
            /// <returns>Json with the application profile</returns>
            [HttpGet("[controller]/profiles/{profile}")]
            public IActionResult GetProfile(string profile)
            {
                var profileUrl = profile.StartsWith("http") ? HttpUtility.UrlDecode(profile) : $"{ApplicationProfileUrl}{profile}/";
    
                if (!profileUrl.StartsWith(ApplicationProfileUrl))
                {
                    return StatusCode((int)HttpStatusCode.Forbidden, $"Profile has to start with {ApplicationProfileUrl}!");
                }
    
                var graph = _rdfStoreConnector.GetGraph(profileUrl);
    
                var tripleStore = new TripleStore();
                tripleStore.Add(graph);
    
                var outStoreJson = VDS.RDF.Writing.StringWriter.Write(tripleStore, new JsonLdWriter());
    
                var json = JToken.Parse(outStoreJson);
    
                return Ok(json);
            }
    
            /// <summary>
            /// Returns the application profile with the fixed values for the given resource.
            /// </summary>
            /// <param name="profile">Url of the application profile</param>
            /// <param name="resourceId">Id of the resource</param>
            /// <returns>JSON with the application profile or StatusCode 403</returns>
            [HttpGet("[controller]/profiles/{profile}/{resourceId}")]
            public IActionResult GetApplicationProfileComplete(string profile, string resourceId)
            {
                var user = _authenticator.GetUser();
    
                var resource = _resourceModel.GetById(Guid.Parse(resourceId));
    
                if (user == null || !_resourceModel.HasAccess(user, resource, UserRoles.Owner, UserRoles.Member))
                {
                    return StatusCode((int)HttpStatusCode.Forbidden, "User is no project member!");
                }
    
                var profileUrl = profile.StartsWith("http") ? HttpUtility.UrlDecode(profile) : $"{ApplicationProfileUrl}{profile}/";
    
                if (!profileUrl.StartsWith(ApplicationProfileUrl))
                {
                    return StatusCode((int)HttpStatusCode.Forbidden, $"Profile has to start with {ApplicationProfileUrl}!");
                }
    
                var graph = _rdfStoreConnector.GetGraph(profileUrl);
                var fixedValuesGraph = new Graph();
    
                fixedValuesGraph.LoadFromString(resource.FixedValues, new RdfJsonParser());
    
                graph.Merge(fixedValuesGraph);
    
                var tripleStore = new TripleStore();
                tripleStore.Add(graph);
    
                var outStoreJson = VDS.RDF.Writing.StringWriter.Write(tripleStore, new JsonLdWriter());
    
                var json = JToken.Parse(outStoreJson);
    
                return Ok(json);
    
            }
    
            /// <summary>
            /// This method returns a list of all vocabularies.
            /// </summary>
            /// <throws>Exception for the code that has not been implemented</throws>
            [HttpGet("[controller]/vocabularies/")]
            public IActionResult GetVocabularies()
            {
                throw new NotImplementedException();
            }
    
            /// <summary>
            /// This method returns a specific vocabulary.
            /// </summary>
            /// <param name="path">Url of the vocabulary</param>
            /// <returns>JSON with the requested vocabulary</returns>
            [HttpGet("[controller]/vocabularies/{path}")]
            public IActionResult GetVocabulary(string path)
            {
                var graph = _rdfStoreConnector.GetGraph(HttpUtility.UrlDecode(path));
    
                var de = new JArray();
                foreach (var kv in _rdfStoreConnector.GetVocabularyLabels(graph, "de"))
                {
                    JObject obj = new JObject
                    {
                        ["value"] = kv.Key,
                        ["name"] = kv.Value
                    };
                    de.Add(obj);
                }
    
                var en = new JArray();
                foreach (var kv in _rdfStoreConnector.GetVocabularyLabels(graph, "en"))
                {
                    JObject obj = new JObject
                    {
                        ["value"] = kv.Key,
                        ["name"] = kv.Value
                    };
                    en.Add(obj);
                }
    
                JObject json = new JObject
                {
                    ["de"] = de,
                    ["en"] = en
                };
    
                return Json(json);
            }
    
            /// <summary>
            /// This method returns instances.
            /// </summary>
            /// <param name="projectId">Id of the project</param>
            /// <param name="className">class name</param>
            /// <returns>instances as Json, or throw an Exception if the user has not beed authorized</returns>
            [HttpGet("[controller]/instances/{projectId}/{className}")]
            public IActionResult GetClassInstances(Guid projectId, string className)
            {
                var user = _authenticator.GetUser();
                ProjectModel projectModel = new ProjectModel();
                if (projectModel.HasAccess(user, projectModel.GetById(projectId), UserRoles.Owner, UserRoles.Member))
                {
                    if (!Uri.TryCreate(HttpUtility.UrlDecode(className), UriKind.Absolute, out Uri uri))
                    {
                        throw new ArgumentException("ClassName is not a valid Uri.");
                    }
                    var graph = _rdfStoreConnector.GetClassGraph(uri);
    
                    var de = new JArray();
                    foreach (var kv in _rdfStoreConnector.GetVocabularyLabels(graph, "de"))
                    {
                        JObject obj = new JObject
                        {
                            ["value"] = kv.Key,
                            ["name"] = kv.Value
                        };
                        de.Add(obj);
                    }
    
                    var en = new JArray();
                    foreach (var kv in _rdfStoreConnector.GetVocabularyLabels(graph, "en"))
                    {
                        JObject obj = new JObject
                        {
                            ["value"] = kv.Key,
                            ["name"] = kv.Value
                        };
                        en.Add(obj);
                    }
    
                    JObject json = new JObject
                    {
                        ["de"] = de,
                        ["en"] = en
                    };
    
                    return Json(json);
                }
                else
                {
                    throw new NotAuthorizedException("User is no project member!");
                }
            }
    
            /// <summary>
            /// Create a request for storing a given application profile.
            /// </summary>
            /// <param name="applicationProfile">Object describing the application profile</param>
            /// <returns>NoContent</returns>
            [HttpPut("[controller]/profiles/")]
            public async Task<IActionResult> SaveApplicationProfileAsync([FromBody] ApplicationProfile applicationProfile)
            {
                var user = _authenticator.GetUser();
    
                if (string.IsNullOrWhiteSpace(user.EmailAddress))
                {
                    return BadRequest("The user's email has to be set!");
                }
    
                var token = _configuration.GetStringAndWait("coscine/global/gitlabtoken");
                var gitLabClient = new GitLabClient(HostUrl, token);
    
                var newBranchName = "Request/" + Guid.NewGuid().ToString();
    
                if (!applicationProfile.BaseURL.StartsWith(ApplicationProfileUrl))
                {
                    return BadRequest($"The Application Profile URL has to start with {ApplicationProfileUrl}.");
                }
                if (applicationProfile.MimeType.ToLower().Trim() != "text/turtle")
                {
                    return BadRequest("The mime type has to be text/turtle");
                }
    
                await gitLabClient.Branches.CreateAsync(ApplicationProfileProjectURL, new CreateBranchRequest(newBranchName, "master"));
    
                var folderName = applicationProfile.BaseURL.Replace(ApplicationProfileUrl, "");
                if (folderName.EndsWith("/"))
                {
                    folderName = folderName[..(folderName.Length - 1)];
                }
    
                var actions = new List<CreateCommitRequestAction>
                {
                    new CreateCommitRequestAction(
                        new CreateCommitRequestActionType(), 
                        $"profiles/{folderName}/index.ttl") { 
                            Content = applicationProfile.Definition 
                        }
                };
    
                var commitRequest = new CreateCommitRequest(newBranchName, $"{user.DisplayName} requests new application profile {applicationProfile.Name}", actions)
                {
                    AuthorEmail = user.EmailAddress,
                    AuthorName = user.DisplayName
                };
    
                await gitLabClient.Commits.CreateAsync(ApplicationProfileProjectURL, commitRequest, false);
    
                var newMergeRequest = await gitLabClient.MergeRequests.CreateAsync(ApplicationProfileProjectURL,
                    new CreateMergeRequest(newBranchName, "master", $"Merge request for new application profile {applicationProfile.Name}")
                    {
                        Description = $"Merge request created by {user.DisplayName}, {user.EmailAddress}, created at {DateTime.Now.ToString("dd/MM/yyyy HH:mm:ss tt")}"
                    });
    
                _emitter.EmitApplicationProfileRequest(new ApplicationProfileEventArgs(_configuration)
                {
                    RequestOwner = user,
                    ApplicationProfileName = applicationProfile.Name,
                    MergeRequestURL = newMergeRequest.WebUrl
                });
    
                return NoContent();
            }
        }
    }