Skip to content
Snippets Groups Projects
Select Git revision
  • 7737e456d76ece4de1cccf1ca439f408bfd2f3b4
  • master default protected
  • develop protected
  • feature/triangulation-qhull
  • jst
  • ti_lab_build
  • features/splines_and_piecewise_polynomials
  • ma_2018/erraji
  • fabian
  • ITABase_v2024a
  • VA_v2023b
  • VA_v2023a
  • VA_v2022a
  • before_cmake_rework
  • v2021.a
  • v2020.a
  • v2019.a
  • v2018.b
  • v2018.a
  • v2017.d
  • v2017.c
  • v2017.b
  • v2017.a
  • v2016.a
24 results

ITASampleBuffer.h

Blame
  • Code owners
    Assign users and groups as approvers for specific file changes. Learn more.
    BlobController.cs 17.88 KiB
    using Coscine.ApiCommons;
    using Coscine.Configuration;
    using Coscine.Database.DataModel;
    using Coscine.Database.Models;
    using Coscine.Database.Util;
    using Coscine.Logging;
    using Coscine.Metadata;
    using Coscine.ResourceLoader;
    using Coscine.ResourceTypeBase;
    using Coscine.WaterbutlerHelper.Services;
    using Microsoft.AspNetCore.Authorization;
    using Microsoft.AspNetCore.Http;
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.AspNetCore.StaticFiles;
    using Microsoft.Extensions.Logging;
    using Newtonsoft.Json.Linq;
    using System;
    using System.Collections.Generic;
    using System.Net;
    using System.Text.RegularExpressions;
    using System.Threading.Tasks;
    using System.Web;
    
    namespace Coscine.Api.Blob.Controllers
    {
        /// <summary>
        /// This controller represents the actions which can be taken with a Blob object.
        /// </summary>
        [Authorize]
    
        public class BlobController : Controller
        {
            private readonly IConfiguration _configuration;
            private readonly Authenticator _authenticator;
            private readonly ResourceModel _resourceModel;
            private readonly ProjectResourceModel _projectResourceModel;
            private readonly ProjectRoleModel _projectRoleModel;
            private readonly CoscineLogger _coscineLogger;
            private readonly AnalyticsLogObject _analyticsLogObject;
            private readonly RdfStoreConnector _rdfStoreConnector;
            private readonly string _prefix;
    
            /// <summary>
            /// Blob controller constructor
            /// </summary>
            /// <param name="logger">Logger</param>
            /// <param name="dataSourceService">Source service for data</param>
            public BlobController(ILogger<BlobController> logger, IDataSourceService dataSourceService)
            {
                _configuration = Program.Configuration;
                _authenticator = new Authenticator(this, _configuration);
                _resourceModel = new ResourceModel();
                _projectResourceModel = new ProjectResourceModel();
                _projectRoleModel = new ProjectRoleModel();
                _rdfStoreConnector = new RdfStoreConnector(_configuration.GetStringAndWait("coscine/local/virtuoso/additional/url"));
    
                _coscineLogger = new CoscineLogger(logger);
                _analyticsLogObject = new AnalyticsLogObject();
                _prefix = _configuration.GetStringAndWait("coscine/global/epic/prefix");
            }
    
            /// <summary>
            /// Generates Id
            /// </summary>
            /// <param name="resourceId">Id of the resource</param>
            /// <param name="path"> Path to file</param>
            /// <returns> Uri </returns>
            public Uri GenerateId(string resourceId, string path)
            {
                return new Uri($"https://hdl.handle.net/{_prefix}/{resourceId}@path={Uri.EscapeDataString(path)}");
            }
    
            /// <summary>
            /// This method returns the amount of allocated space for the given resource
            /// </summary>
            /// <param name="resourceId">Id of a resource</param>
            /// <returns>Data, file count and bytesize used or Status Code 400, 404, 401 or 500  </returns>
            [HttpGet("[controller]/{resourceId}/quota")]
            public IActionResult GetQuota(string resourceId)
            {
                if (!Guid.TryParse(resourceId, out Guid resourceGuid))
                {
                    return BadRequest($"{resourceId} is not a guid.");
                }
    
                var user = _authenticator.GetUser();
                Resource resource;
                try
                {
                    resource = _resourceModel.GetById(resourceGuid);
                    if (resource == null)
                    {
                        return NotFound($"Could not find resource with id: {resourceId}");
                    }
                }
                catch (Exception)
                {
                    return NotFound($"Could not find resource with id: {resourceId}");
                }
    
                if (resource.Type == null)
                {
                    ResourceTypeModel resourceTypeModel = new ResourceTypeModel();
                    resource.Type = resourceTypeModel.GetById(resource.TypeId);
                }
    
                if (user == null || !_resourceModel.HasAccess(user, resource, UserRoles.Owner, UserRoles.Member))
                {
                    return BadRequest("User does not have permission to the resource.");
                }
    
                if ((resource.Type.DisplayName.ToLower() == "rds" || resource.Type.DisplayName.ToLower() == "rdss3") && resource.ResourceTypeOptionId.HasValue)
                {
                    try
                    {
                        var resourceTypeOptions = _resourceModel.GetResourceTypeOptions(resource.Id);
                        var resourceTypeDefinition = ResourceTypeFactory.CreateResourceTypeObject(resource.Type.DisplayName, _configuration);
                        if (resourceTypeDefinition == null)
                        {
                            return BadRequest($"No provider for: \"{resource.Type.DisplayName}\".");
                        }
                        var totalFileSize = resourceTypeDefinition.GetResourceQuotaUsed(resourceId, resourceTypeOptions).Result;
                        return Ok($"{{ \"data\": {{ \"usedSizeByte\": {totalFileSize} }}}}");
                    }
                    catch
                    {
                        return BadRequest($"Error in communication with the resource");
                    }
                }
                else
                {
                    return BadRequest("The resource type must be rds.");
                }
            }
    
            /// <summary>
            ///  This method checks if the given file exists and returns it
            /// </summary>
            /// <param name="resourceId">Id of the resource</param>
            /// <param name="path"> Path to the file </param>
            /// <returns>File if file exists otherwise Statuscode 204, 400, 401 or 404 </returns>
            [HttpGet("[controller]/{resourceId}/{*path}")]
            [DisableRequestSizeLimit]
            public async Task<IActionResult> GetFile(string resourceId, string path)
            {
                var user = _authenticator.GetUser();
                path = $"/{path}";
                var checkPath = CheckPath(path);
                if (checkPath != null)
                {
                    return checkPath;
                }
                var checkResourceId = CheckResource(resourceId, out Resource resource);
                if (checkResourceId != null)
                {
                    return checkResourceId;
                }
                var checkUser = CheckUser(user, resource);
                if (checkUser != null)
                {
                    return checkUser;
                }
                var resourceTypeOptions = _resourceModel.GetResourceTypeOptions(resource.Id);
                try
                {
                    var resourceTypeDefinition = ResourceTypeFactory.CreateResourceTypeObject(resource.Type.DisplayName, _configuration);
                    if (resourceTypeDefinition == null)
                    {
                        return BadRequest($"No provider for: \"{resource.Type.DisplayName}\".");
                    }
                    var infos = await resourceTypeDefinition.GetEntry(resource.Id.ToString(), path, null, resourceTypeOptions);
                    var response = await resourceTypeDefinition.LoadEntry(resource.Id.ToString(), path, null, resourceTypeOptions);
                    new FileExtensionContentTypeProvider().TryGetContentType(path.Substring(path.LastIndexOf("/")), out string contentType);
                    LogAnalytics("Download File", resourceId, path.Substring(1), user);
                    return File(response, contentType ?? "application/octet-stream");
                }
                catch
                {
                    return BadRequest($"Error in communication with the resource");
                }
            }
    
            /// <summary>
            /// This method uploads a given File
            /// </summary>
            /// <param name="resourceId">Id of the resource </param>
            /// <param name="path">Path to the file</param>
            /// <param name="files">List of files.</param>
            /// <returns>Statuscode 204 if file is uploaded otherwise Statuscode 400 or 403</returns>
            [DisableRequestSizeLimit]
            [RequestFormLimits(MultipartBodyLengthLimit = long.MaxValue)]
            [HttpPut("[controller]/{resourceId}/{*path}")]
            public async Task<IActionResult> UploadFile(string resourceId, string path, List<IFormFile> files)
            {
                var user = _authenticator.GetUser();
                path = $"/{path}";
                var checkPath = CheckPath(path);
                if (checkPath != null)
                {
                    return checkPath;
                }
                var checkResourceId = CheckResource(resourceId, out Resource resource);
                if (checkResourceId != null)
                {
                    return checkResourceId;
                }
                var checkUser = CheckUser(user, resource);
                if (checkUser != null)
                {
                    return checkUser;
                }
    
                if (resource.Archived == "1")
                {
                    return BadRequest("The resource is readonly!");
                }
    
                if (files.Count != 1)
                {
                    return BadRequest($"Only one file can be uploaded per request.");
                }
    
                var id = GenerateId(resourceId, path);
                if (!_rdfStoreConnector.HasGraph(id.AbsoluteUri))
                {
                    return StatusCode((int)HttpStatusCode.Forbidden,
                        "No metadataset has been added for this file.");
                }
    
                try
                {
                    var resourceTypeOptions = _resourceModel.GetResourceTypeOptions(resource.Id);
                    var stream = files[0].OpenReadStream();
                    resourceTypeOptions.Add("ContentLength", stream.Length.ToString());
                    var resourceTypeDefinition = ResourceTypeFactory.CreateResourceTypeObject(resource.Type.DisplayName, _configuration);
                    if (resourceTypeDefinition == null)
                    {
                        return BadRequest($"No provider for: \"{resource.Type.DisplayName}\".");
                    }
                    ResourceEntry infos = null;
                    try
                    {
                        infos = await resourceTypeDefinition.GetEntry(resource.Id.ToString(), path, null, resourceTypeOptions);
                    }
                    catch
                    {
                        // do nothing
                    }
                    await resourceTypeDefinition.StoreEntry(resource.Id.ToString(), path, stream, resourceTypeOptions);
                    LogAnalytics(infos == null ? "Upload File" : "Update File", resourceId, path, user);
                    return NoContent();
                }
                catch (Exception e)
                {
                    return BadRequest($"Error in communication with the resource");
                }
            }
    
            /// <summary>
            /// This method deletes a given file
            /// </summary>
            /// <param name="resourceId">Id of the resource </param>
            /// <param name="path">Path to the file</param>
            /// <returns>Statuscode 204 if deletion successful otherwise Statuscode 400, 401 or 404 </returns>
            [HttpDelete("[controller]/{resourceId}/{*path}")]
            public async Task<IActionResult> DeleteFile(string resourceId, string path)
            {
                var user = _authenticator.GetUser();
                path = $"/{path}";
                var checkPath = CheckPath(path);
                if (checkPath != null)
                {
                    return checkPath;
                }
                var checkResourceId = CheckResource(resourceId, out Resource resource);
                if (checkResourceId != null)
                {
                    return checkResourceId;
                }
                var checkUser = CheckUser(user, resource);
                if (checkUser != null)
                {
                    return checkUser;
                }
    
                if (resource.Archived == "1")
                {
                    return BadRequest("The resource is readonly!");
                }
    
                try
                {
                    var resourceTypeOptions = _resourceModel.GetResourceTypeOptions(resource.Id);
                    var resourceTypeDefinition = ResourceTypeFactory.CreateResourceTypeObject(resource.Type.DisplayName, _configuration);
                    if (resourceTypeDefinition == null)
                    {
                        return BadRequest($"No provider for: \"{resource.Type.DisplayName}\".");
                    }
                    await resourceTypeDefinition.DeleteEntry(resource.Id.ToString(), path, resourceTypeOptions);
                    LogAnalytics("Delete File", resourceId, path, user);
                    return NoContent();
                }
                catch
                {
                    return BadRequest($"Error in communication with the resource");
                }
            }
    
            /// <summary>
            /// This method checks if the resource is valid
            /// </summary>
            /// <returns>Statuscode 204 if resource is valid otherwise Statuscode 400 or 404</returns>
            [HttpPost("[controller]/validate")]
            public async Task<IActionResult> IsResourceValid([FromBody] JToken resource)
            {
                var displayName = resource["type"]["displayName"].ToString().ToLower();
                var resourceTypeOptions = new Dictionary<string, string>();
                if (displayName == "s3")
                {
                    resourceTypeOptions.Add("accessKey", resource["resourceTypeOption"]["AccessKey"].ToString());
                    resourceTypeOptions.Add("secretKey", resource["resourceTypeOption"]["SecretKey"].ToString());
                    resourceTypeOptions.Add("bucketname", resource["resourceTypeOption"]["BucketName"].ToString());
                    resourceTypeOptions.Add("resourceUrl", resource["resourceTypeOption"]["ResourceUrl"].ToString());
                }
                else if (displayName == "gitlab")
                {
                    resourceTypeOptions.Add("token", resource["resourceTypeOption"]["Token"].ToString());
                    resourceTypeOptions.Add("repositoryUrl", resource["resourceTypeOption"]["RepositoryUrl"].ToString());
                    resourceTypeOptions.Add("repositoryNumber", resource["resourceTypeOption"]["RepositoryNumber"].ToString());
                }
                try
                {
                    var resourceTypeDefinition = ResourceTypeFactory.CreateResourceTypeObject(displayName, _configuration);
                    if (resourceTypeDefinition == null)
                    {
                        return BadRequest($"No provider for: \"{displayName}\".");
                    }
    
                    await resourceTypeDefinition.IsResourceCreated("", resourceTypeOptions);
                    return NoContent();
                }
                catch
                {
                    return BadRequest($"Error in communication with the resource");
                }
            }
    
            /// <summary>
            /// Tries to establish connection with resource and validates wether the given file/folder exists
            /// </summary>
            private IActionResult CheckResource(string resourceId,  out Resource resource)
            {
                resource = null;
    
                if (!Guid.TryParse(resourceId, out Guid resourceGuid))
                {
                    return BadRequest($"{resourceId} is not a guid.");
                }
    
                try
                {
                    resource = _resourceModel.GetById(resourceGuid);
                    if (resource == null)
                    {
                        return NotFound($"Could not find resource with id: {resourceId}");
                    }
                }
                catch (Exception)
                {
                    return NotFound($"Could not find resource with id: {resourceId}");
                }
    
                if (resource.Type == null)
                {
                    ResourceTypeModel resourceTypeModel = new ResourceTypeModel();
                    resource.Type = resourceTypeModel.GetById(resource.TypeId);
                }
                // All good
                return null;
            }
    
            /// <summary>
            /// Checks if the path is valid
            /// </summary>
            /// <param name="path">path</param>
            /// <returns>Statuscode 400 if the given path is not valid</returns>
            public IActionResult CheckPath(string path)
            {
                if (string.IsNullOrWhiteSpace(path))
                {
                    return BadRequest($"Your path \"{path}\" is empty.");
                }
    
                var rgx = new Regex(@"[\:?*<>|]+");
                if (rgx.IsMatch(path))
                {
                    return BadRequest($"Your path \"{path}\" contains bad characters. The following characters are not permissible: {@"\/:?*<>|"}.");
                }
    
                if (path.Contains("%2F") || path.Contains("%2f"))
                {
                    return BadRequest("Path can not contain the sequence %2F.");
                }
    
                return null;
            }
    
            /// <summary>
            /// Checks if the user has access to the resource
            /// </summary>
            /// <param name="user">user</param>
            /// <param name="resource">resource</param>
            /// <returns>Statuscode 403 if the user has no access</returns>
            public IActionResult CheckUser(User user, Resource resource)
            {
                if (user == null || !_resourceModel.HasAccess(user, resource, UserRoles.Owner, UserRoles.Member))
                {
                    return Forbid("User does not have permission to the resource.");
                }
                return null;
            }
    
            /// <summary>
            /// Writes an analytics log entry
            /// </summary>
            private void LogAnalytics(string operation, string resourceId, string path, User user)
            {
                if (CoscineLoggerConfiguration.IsLogLevelActivated(LogType.Analytics))
                {
                    _analyticsLogObject.Type = "Action";
                    _analyticsLogObject.FileId = resourceId + "/" + HttpUtility.UrlDecode(path)[1..];
                    _analyticsLogObject.ResourceId = resourceId;
                    _analyticsLogObject.ProjectId = _projectResourceModel.GetProjectForResource(new Guid(resourceId)).ToString();
                    _analyticsLogObject.RoleId = _projectRoleModel.GetGetUserRoleForProject(new Guid(_analyticsLogObject.ProjectId), user.Id).ToString();
                    _analyticsLogObject.Operation = operation;
                    _coscineLogger.AnalyticsLog(_analyticsLogObject);
                }
            }
        }
    }