Skip to content
Snippets Groups Projects

WIP: Update: Adapt analytics logs (coscine/issues#1188)

Files

@@ -9,10 +9,12 @@ using Coscine.Database.ReturnObjects;
using Coscine.Database.Util;
using Coscine.Logging;
using Coscine.Metadata;
using Coscine.Metadata.Models;
using Coscine.ResourceLoader;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -32,8 +34,11 @@ namespace Coscine.Api.Project.Controllers
private readonly Emitter _emitter;
private readonly ActivatedFeaturesModel _activatedFeaturesModel;
private readonly ProjectRoleModel _projectRoleModel;
private readonly ProjectQuotaModel _projectQuotaModel;
private readonly VisibilityModel _visibilityModel;
private readonly CoscineLogger _coscineLogger;
private readonly AnalyticsLogObject _analyticsLogObject;
private readonly ProjectInstituteModel _projectInstituteModel;
/// <summary>
/// ProjectController constructor
@@ -47,8 +52,11 @@ namespace Coscine.Api.Project.Controllers
_emitter = new Emitter(_configuration);
_activatedFeaturesModel = new ActivatedFeaturesModel();
_projectRoleModel = new ProjectRoleModel();
_projectQuotaModel = new ProjectQuotaModel();
_visibilityModel = new VisibilityModel();
_coscineLogger = new CoscineLogger(logger);
_analyticsLogObject = new AnalyticsLogObject();
_projectInstituteModel = new ProjectInstituteModel();
}
/// <summary>
@@ -94,7 +102,7 @@ namespace Coscine.Api.Project.Controllers
/// <summary>
/// This returns the the project if the user has access to it
/// </summary>
/// <param name="id">Id of the resource</param>
/// <param name="id">Id of the project</param>
/// <returns>Ok or Statuscode 401</returns>
[HttpGet("[controller]/{id}")]
public ActionResult<ProjectObject> Get(string id)
@@ -105,7 +113,7 @@ namespace Coscine.Api.Project.Controllers
{
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))
{
@@ -144,7 +152,17 @@ namespace Coscine.Api.Project.Controllers
}).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
var projectObject = _projectModel.CreateReturnObjectFromDatabaseObject(_projectModel.GetById(project.Id));
LogAnalytics("View Project", // intentionally log as view project to help identify the related user action
null,
resources,
id,
user,
GetProjectQuotas(project.Id),
null,
projectObject.Disciplines,
projectObject.Organizations,
projectObject.Visibility.DisplayName);
}
return Json(resources);
}
@@ -157,7 +175,7 @@ namespace Coscine.Api.Project.Controllers
/// <summary>
/// Retrieves the quota for the selected project
/// </summary>
/// <param name="id">Id of the resource</param>
/// <param name="id">Id of the project</param>
/// <returns>Json object or Statuscode 401</returns>
[HttpGet("[controller]/{id}/quotas")]
public ActionResult<IEnumerable<ProjectQuota>> Quotas(string id)
@@ -168,38 +186,7 @@ namespace Coscine.Api.Project.Controllers
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);
return Json(GetProjectQuotas(guidId));
}
else
{
@@ -208,9 +195,9 @@ namespace Coscine.Api.Project.Controllers
}
/// <summary>
/// Updates the selected project
/// Updates the selected project
/// </summary>
/// <param name="id">Id of the resource</param>
/// <param name="id">Id of the project</param>
/// <returns>Ok or Statuscode 401</returns>
[HttpPost("[controller]/{id}")]
public IActionResult Update(string id)
@@ -218,9 +205,19 @@ namespace Coscine.Api.Project.Controllers
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);
LogAnalytics("Edit Project", // intentionally log as view project to help identify the related user action
null,
null,
id,
user,
GetProjectQuotas(project.Id),
_projectModel.GetMetadataCompleteness(projectObject).ToString(),
projectObject.Disciplines,
projectObject.Organizations,
projectObject.Visibility.DisplayName);
return Ok(_projectModel.UpdateByObject(project, projectObject));
}
else
@@ -232,16 +229,26 @@ namespace Coscine.Api.Project.Controllers
/// <summary>
/// Deletes the selected project
/// </summary>
/// <param name="id">Id of the resource</param>
/// <param name="id">Id of the project</param>
/// <returns>Json object or Statuscode 401</returns>
[HttpDelete("[controller]/{id}")]
public IActionResult Delete(string id)
{
var user = _authenticator.GetUser();
var project = _projectModel.GetById(Guid.Parse(id));
var projectObject = _projectModel.CreateReturnObjectFromDatabaseObject(project);
if (_projectModel.HasAccess(user, project, UserRoles.Owner))
{
LogAnalytics("Delete Project", null, null, id, user);
LogAnalytics("Delete Project", // intentionally log as view project to help identify the related user action
null,
null,
id,
user,
GetProjectQuotas(project.Id),
null,
projectObject.Disciplines,
projectObject.Organizations,
projectObject.Visibility.DisplayName);
DeleteProject(project);
return Json(_projectModel.CreateReturnObjectFromDatabaseObject(project));
}
@@ -376,14 +383,22 @@ namespace Coscine.Api.Project.Controllers
Project = project,
ProjectOwner = user
});
LogAnalytics("Add Project", null, null, project.Id.ToString(), user);
LogAnalytics("Add Project",
null,
null,
project.Id.ToString(),
user,
GetProjectQuotas(project.Id),
_projectModel.GetMetadataCompleteness(projectObject).ToString(),
projectObject.Disciplines,
projectObject.Organizations,
projectObject.Visibility.DisplayName);
return Json(_projectModel.CreateReturnObjectFromDatabaseObject(project));
}
/// <summary>
/// Checks if the given user is a member of the RWTH
/// Checks if the given user is a member of the RWTH
/// </summary>
/// <param name="user">User object</param>
/// <returns>True, if member of RWTH or false, if not a member of RWTH</returns>
@@ -395,7 +410,7 @@ namespace Coscine.Api.Project.Controllers
return false;
}
var externalIdList = new List<string>();
foreach (var externalId in externalIds)
{
externalIdList.Add(externalId.ExternalIdColumn);
@@ -411,17 +426,32 @@ namespace Coscine.Api.Project.Controllers
/// <param name="resources">Resources</param>
/// <param name="projectId">Id of the project</param>
/// <param name="user">User object</param>
/// <param name="quotaSize"></param>
/// <param name="metadataCompleteness"></param>
/// <param name="disciplines"></param>
/// <param name="organizations"></param>
/// <param name="visibility"></param>
private void LogAnalytics(string operation,
IEnumerable<ProjectObject> projects = null,
IEnumerable<ResourceObject> resources = null,
string projectId = null,
User user = null
User user = null,
List<dynamic> quotaSize = null,
string metadataCompleteness = null,
IEnumerable<DisciplineObject> disciplines = null,
IEnumerable<OrganizationObject> organizations = null,
string visibility = null
)
{
if (CoscineLoggerConfiguration.IsLogLevelActivated(LogType.Analytics))
{
var _rdfStoreConnector = new RdfStoreConnector(Program.Configuration.GetStringAndWait("coscine/local/virtuoso/additional/url"));
List<string> organizationsList = new List<string>();
List<string> disciplinesList = new List<string>();
_analyticsLogObject.Type = "Action";
_analyticsLogObject.Operation = operation;
_analyticsLogObject.MetadataCompleteness = metadataCompleteness;
if (projects != null)
{
@@ -449,8 +479,75 @@ namespace Coscine.Api.Project.Controllers
_analyticsLogObject.RoleId = _projectRoleModel.GetGetUserRoleForProject(new Guid(_analyticsLogObject.ProjectId), user.Id).ToString();
}
}
if (quotaSize != null)
{
string serialized = "";
foreach(var resourceQuota in quotaSize)
{
serialized += $"[{resourceQuota.type}: {resourceQuota.allocated}/{resourceQuota.available}],";
}
serialized = serialized.Remove(serialized.Length - 1);
_analyticsLogObject.QuoteSize = serialized;
}
if (disciplines != null && disciplines.Count() > 0)
{
foreach (var discipline in disciplines)
{
disciplinesList.Add(discipline.DisplayNameEn);
}
_analyticsLogObject.Disciplines = disciplinesList;
}
if (organizations != null && organizations.Count() > 0)
{
foreach (var organization in organizations)
{
organizationsList.Add(organization.Url);
}
_analyticsLogObject.Organizations = organizationsList;
}
if (visibility != null)
{
_analyticsLogObject.Visibility = visibility;
}
_coscineLogger.AnalyticsLog(_analyticsLogObject);
}
}
private List<dynamic> GetProjectQuotas(Guid guidId)
{
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 returnList;
}
}
}
Loading