using Coscine.Action; using Coscine.Action.EventArgs; using Coscine.Database.Models; using Coscine.Database.ReturnObjects; using Coscine.ApiCommons; using Coscine.ApiCommons.Factories; using Microsoft.AspNetCore.Mvc; using System; using System.Linq; using Coscine.Configuration; using Microsoft.AspNetCore.Authorization; using Coscine.Database.Util; using Coscine.Logging; using Microsoft.Extensions.Logging; using Newtonsoft.Json.Linq; using Coscine.Database.DataModel; using System.Collections.Generic; using System.Text.RegularExpressions; using Coscine.Metadata; namespace Coscine.Api.Project.Controllers { [Authorize] public class ProjectController : Controller { private readonly Authenticator _authenticator; private readonly ProjectModel _projectModel; private readonly IConfiguration _configuration; private readonly Emitter _emitter; private readonly ActivatedFeaturesModel _activatedFeaturesModel; private readonly ProjectRoleModel _projectRoleModel; private readonly CoscineLogger _coscineLogger; private readonly AnalyticsLogObject _analyticsLogObject; public ProjectController(ILogger<ProjectController> logger) { _authenticator = new Authenticator(this, Program.Configuration); _configuration = Program.Configuration; _projectModel = new ProjectModel(); _emitter = new Emitter(_configuration); _activatedFeaturesModel = new ActivatedFeaturesModel(); _projectRoleModel = new ProjectRoleModel(); _coscineLogger = new CoscineLogger(logger); _analyticsLogObject = new AnalyticsLogObject(); } [Route("[controller]")] public IActionResult Index() { var user = _authenticator.GetUser(); var result = _projectModel.GetWithAccess(user, UserRoles.Member, UserRoles.Owner).ToList() .Select((project) => _projectModel.CreateReturnObjectFromDatabaseObject(project)) .OrderBy(element => element.DisplayName); if (Request.Query != null && Request.Query["noanalyticslog"] != "true") { LogAnalytics("List Projects", result); } return Ok(result); } [Route("[controller]/-/topLevel")] public IActionResult GetTopLevelProjects() { var user = _authenticator.GetUser(); var result = _projectModel.GetTopLevelWithAccess(user, UserRoles.Member, UserRoles.Owner).ToList() .Select((project) => _projectModel.CreateReturnObjectFromDatabaseObject(project)) .OrderBy(element => element.DisplayName); if (Request.Query != null && Request.Query["noanalyticslog"] != "true") { LogAnalytics("View Home", result); } return Ok(result); } [HttpGet("[controller]/{id}")] public IActionResult Get(string id) { var user = _authenticator.GetUser(); var project = _projectModel.GetById(Guid.Parse(id)); if (_projectModel.HasAccess(user, project, UserRoles.Member, UserRoles.Owner)) { SubProjectModel subProjectModel = new SubProjectModel(); var subProjectRel = subProjectModel.GetAllWhere((subProject) => subProject.SubProjectId == project.Id && project.Deleted == false); var parentProjectRelation = subProjectRel.FirstOrDefault(); if (parentProjectRelation != null && _projectModel.HasAccess(user, parentProjectRelation.ProjectId, UserRoles.Member, UserRoles.Owner)) { return Ok(_projectModel.CreateReturnObjectFromDatabaseObject(project, parentProjectRelation.ProjectId)); } return Ok(_projectModel.CreateReturnObjectFromDatabaseObject(project)); } else { return Unauthorized($"User is not allowed to see given the project {id}"); } } [HttpGet("[controller]/{id}/resources")] public IActionResult GetResources(string id) { var project = _projectModel.GetById(Guid.Parse(id)); var user = _authenticator.GetUser(); var resourceModel = new ResourceModel(); var resourceTypeModel = new ResourceTypeModel(); if (_projectModel.HasAccess(user, project, UserRoles.Member, UserRoles.Owner)) { var resources = resourceModel.GetAllWhere((resource) => (from projectResource in resource.ProjectResourceResourceIdIds where projectResource.ProjectId == project.Id select projectResource).Any()) .Select((resource) => { return resourceModel.CreateReturnObjectFromDatabaseObject(resource); }).OrderBy(element => element.DisplayName); if (Request.Query != null && Request.Query["noanalyticslog"] != "true") { LogAnalytics("View Project", null, resources, id, user); // intentionally log as view project to help identify the related user action } return Json(resources); } else { return Unauthorized($"User is not allowed to see given the project {id}"); } } [HttpGet("[controller]/{id}/quotas")] public IActionResult Quotas(string id) { var user = _authenticator.GetUser(); var projectObject = ObjectFactory<ProjectObject>.DeserializeFromStream(Request.Body); var guidId = Guid.Parse(id); var project = _projectModel.GetById(guidId); if (_projectModel.HasAccess(user, project, UserRoles.Owner)) { ProjectQuotaModel projectQuotaModel = new ProjectQuotaModel(); var projectQuotas = projectQuotaModel.GetAllWhere((projectQuota) => projectQuota.ProjectId == guidId && projectQuota.ResourceType.Enabled == true) .Select((projectQuota) => projectQuotaModel.CreateReturnObjectFromDatabaseObject(projectQuota)); ResourceModel resourceModel = new ResourceModel(); RDSResourceTypeModel rdsResourceTypeModel = new RDSResourceTypeModel(); var returnList = new List<dynamic>(); foreach (var projectQuota in projectQuotas) { // TODO: Cleanup quota and give it to every resource, this hard coded solution seems not scalable if (projectQuota.ResourceType.DisplayName == "rds") { var resources = resourceModel.GetAllWhere((resource) => resource.TypeId == projectQuota.ResourceType.Id && (from connection in resource.ProjectResourceResourceIdIds where connection.ProjectId == guidId select connection).Any()); var size = resources.Sum((resource) => rdsResourceTypeModel.GetById(resource.ResourceTypeOptionId.Value).Size); returnList.Add(new { type = projectQuota.ResourceType.DisplayName, available = projectQuota.Quotas, allocated = size }); } } return Json(returnList); } else { return Unauthorized("The user is not authorized to perform a get on the selected project!"); } } [HttpPost("[controller]/{id}")] public IActionResult Update(string id) { var user = _authenticator.GetUser(); var projectObject = ObjectFactory<ProjectObject>.DeserializeFromStream(Request.Body); var project = _projectModel.GetById(Guid.Parse(id)); if (_projectModel.HasAccess(user, project, UserRoles.Owner)) { LogAnalytics("Edit Project", null, null, id, user); return Ok(_projectModel.UpdateByObject(project, projectObject)); } else { return Unauthorized("The user is not authorized to perform an update on the selected project!"); } } [HttpDelete("[controller]/{id}")] public IActionResult Delete(string id) { var user = _authenticator.GetUser(); var project = _projectModel.GetById(Guid.Parse(id)); if (_projectModel.HasAccess(user, project, UserRoles.Owner)) { LogAnalytics("Delete Project", null, null, id, user); DeleteProject(project); return Json(_projectModel.CreateReturnObjectFromDatabaseObject(project)); } else { return Unauthorized("The user is not authorized to perform an update on the selected project!"); } } public void DeleteProject(Database.DataModel.Project project, bool isHard = false, bool propegateAction = true) { var subProjectModel = new SubProjectModel(); foreach (var subProject in subProjectModel.GetAllWhere( (subProject) => subProject.ProjectId == project.Id && (subProject.SubProject_FK.Deleted == false || isHard) )) { Database.DataModel.Project subProjectObject; if (isHard) { subProjectObject = _projectModel.GetByIdIncludingDeleted(subProject.SubProjectId); subProjectModel.Delete(subProject); } else { subProjectObject = _projectModel.GetById(subProject.SubProjectId); } DeleteProject(subProjectObject, isHard, propegateAction); } foreach (var subProject in subProjectModel.GetAllWhere((subProject) => subProject.SubProjectId == project.Id)) { if (isHard) { subProjectModel.Delete(subProject); } } if (isHard) { var projectResourceModel = new ProjectResourceModel(); ResourceModel resourceModel = new ResourceModel(); foreach (var projectResource in projectResourceModel.GetAllWhere((projectResource) => projectResource.ProjectId == project.Id)) { projectResourceModel.Delete(projectResource); resourceModel.Delete(resourceModel.GetById(projectResource.ResourceId)); } var projectRoleModel = new ProjectRoleModel(); foreach (var projectRole in projectRoleModel.GetAllWhere((projectRole) => projectRole.ProjectId == project.Id)) { projectRoleModel.Delete(projectRole); } var projectDisciplineModel = new ProjectDisciplineModel(); foreach (var projectDiscipline in projectDisciplineModel.GetAllWhere((projectDiscipline) => projectDiscipline.ProjectId == project.Id)) { projectDisciplineModel.Delete(projectDiscipline); } var projectInstituteModel = new ProjectInstituteModel(); foreach (var projectInstitute in projectInstituteModel.GetAllWhere((projectInstitute) => projectInstitute.ProjectId == project.Id)) { projectInstituteModel.Delete(projectInstitute); } var projectQuotaModel = new ProjectQuotaModel(); foreach (var projectQuota in projectQuotaModel.GetAllWhere((Quota) => Quota.ProjectId == project.Id)) { projectQuotaModel.Delete(projectQuota); } _activatedFeaturesModel.DeactivateAllFeatures(project); if (propegateAction) { _emitter.EmitProjectDelete(new ProjectEventArgs(_configuration) { Project = project }); } _projectModel.HardDelete(project); } else { _projectModel.Delete(project); } } [HttpPost("[controller]")] public IActionResult Store() { var user = _authenticator.GetUser(); var isRWTHMember = IsRWTHMember(user); var projectObject = ObjectFactory<ProjectObject>.DeserializeFromStream(Request.Body); if (projectObject.ParentId != null && projectObject.ParentId != new Guid() && !_projectModel.HasAccess(user, _projectModel.GetById(projectObject.ParentId), UserRoles.Owner)) { return Unauthorized("User is not allowed to create SubProjects."); } var project = _projectModel.StoreFromObject(projectObject, user, isRWTHMember); if (projectObject.ParentId != null && projectObject.ParentId != new Guid() // for now, only an owner can add subprojects to projects && _projectModel.HasAccess(user, _projectModel.GetById(projectObject.ParentId), UserRoles.Owner)) { var subProjectModel = new SubProjectModel(); subProjectModel.LinkSubProject(projectObject.ParentId, project.Id); } _emitter.EmitProjectCreate(new ProjectEventArgs(_configuration) { Project = project, ProjectOwner = user }); LogAnalytics("Add Project", null, null, project.Id.ToString(), user); return Json(_projectModel.CreateReturnObjectFromDatabaseObject(project)); } private bool IsRWTHMember(User user) { var externalIds = new ExternalIdModel().GetAllWhere((externalId) => externalId.UserId == user.Id); if(externalIds.Count() == 0) { return false; } var externalIdList = new List<string>(); foreach (var externalId in externalIds) { externalIdList.Add(externalId.ExternalIdColumn); } return new RdfStoreConnector(Program.Configuration.GetStringAndWait("coscine/local/virtuoso/additional/url")).GetTriples(new Uri("https://ror.org/04xfq0f34"), null, null, 1, externalIdList).Count() != 0; } private void LogAnalytics(string operation, IEnumerable<ProjectObject> projects = null, IEnumerable<ResourceObject> resources = null, string projectId = null, User user = null ) { if (CoscineLoggerConfiguration.IsLogLevelActivated(LogType.Analytics)) { _analyticsLogObject.Type = "Action"; _analyticsLogObject.Operation = operation; if (projects != null) { List<string> projectList = new List<string>(); foreach (var entry in projects) { projectList.Add(entry.Id.ToString()); } _analyticsLogObject.ProjectList = projectList; } if (resources != null) { List<string> shownResources = new List<string>(); foreach (var entry in resources) { shownResources.Add(entry.Id.ToString()); } _analyticsLogObject.ResourceList = shownResources; } if (projectId != null) { _analyticsLogObject.ProjectId = projectId; if (user != null) { _analyticsLogObject.RoleId = _projectRoleModel.GetGetUserRoleForProject(new Guid(_analyticsLogObject.ProjectId), user.Id).ToString(); } } _coscineLogger.AnalyticsLog(_analyticsLogObject); } } } }