ProjectController.cs 16.5 KB
Newer Older
1
using Coscine.Action;
2
using Coscine.Action.EventArgs;
Marcel Nellesen's avatar
Marcel Nellesen committed
3
4
using Coscine.Database.Models;
using Coscine.Database.ReturnObjects;
5
6
using Coscine.ApiCommons;
using Coscine.ApiCommons.Factories;
7
8
9
using Microsoft.AspNetCore.Mvc;
using System;
using System.Linq;
10
using Coscine.Configuration;
11
using Microsoft.AspNetCore.Authorization;
Marcel Nellesen's avatar
Marcel Nellesen committed
12
using Coscine.Database.Util;
13
14
15
16
17
using Coscine.Logging;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json.Linq;
using Coscine.Database.DataModel;
using System.Collections.Generic;
18
using System.Text.RegularExpressions;
19
using Coscine.Metadata;
Benedikt Heinrichs's avatar
Benedikt Heinrichs committed
20
21
22

namespace Coscine.Api.Project.Controllers
{
23
    [Authorize]
Benedikt Heinrichs's avatar
Benedikt Heinrichs committed
24
25
26
    public class ProjectController : Controller
    {
        private readonly Authenticator _authenticator;
Benedikt Heinrichs's avatar
Benedikt Heinrichs committed
27
        private readonly ProjectModel _projectModel;
28
        private readonly IConfiguration _configuration;
29
        private readonly Emitter _emitter;
Marcel Nellesen's avatar
Marcel Nellesen committed
30
        private readonly ActivatedFeaturesModel _activatedFeaturesModel;
31
32
33
        private readonly ProjectRoleModel _projectRoleModel;
        private readonly CoscineLogger _coscineLogger;
        private readonly AnalyticsLogObject _analyticsLogObject;
34

35
        public ProjectController(ILogger<ProjectController> logger)
Benedikt Heinrichs's avatar
Benedikt Heinrichs committed
36
        {
37
            _authenticator = new Authenticator(this, Program.Configuration);
38
            _configuration = Program.Configuration;
Benedikt Heinrichs's avatar
Benedikt Heinrichs committed
39
            _projectModel = new ProjectModel();
40
            _emitter = new Emitter(_configuration);
Marcel Nellesen's avatar
Marcel Nellesen committed
41
            _activatedFeaturesModel = new ActivatedFeaturesModel();
42
43
44
            _projectRoleModel = new ProjectRoleModel();
            _coscineLogger = new CoscineLogger(logger);
            _analyticsLogObject = new AnalyticsLogObject();
Benedikt Heinrichs's avatar
Benedikt Heinrichs committed
45
        }
46
        
Benedikt Heinrichs's avatar
Benedikt Heinrichs committed
47
48
49
        [Route("[controller]")]
        public IActionResult Index()
        {
50
            var user = _authenticator.GetUser();
51
            var result = _projectModel.GetWithAccess(user, UserRoles.Member, UserRoles.Owner).ToList()
52
                .Select((project) => _projectModel.CreateReturnObjectFromDatabaseObject(project))
53
54
                .OrderBy(element => element.DisplayName);

55
            if (Request.Query != null && Request.Query["noanalyticslog"] != "true")
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
            {
                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")
72
73
74
            {
                LogAnalytics("View Home", result);
            }
75
76

            return Ok(result);
Benedikt Heinrichs's avatar
Benedikt Heinrichs committed
77
78
79
80
81
        }

        [HttpGet("[controller]/{id}")]
        public IActionResult Get(string id)
        {
82
83
84
85
            var user = _authenticator.GetUser();
            var project = _projectModel.GetById(Guid.Parse(id));
            if (_projectModel.HasAccess(user, project, UserRoles.Member, UserRoles.Owner))
            {
86
                SubProjectModel subProjectModel = new SubProjectModel();
87
                var subProjectRel = subProjectModel.GetAllWhere((subProject) => subProject.SubProjectId == project.Id && project.Deleted == false);
88
89
90
91
92
93
                
                var parentProjectRelation = subProjectRel.FirstOrDefault();
                if (parentProjectRelation != null && _projectModel.HasAccess(user, parentProjectRelation.ProjectId, UserRoles.Member, UserRoles.Owner))
                {
                    return Ok(_projectModel.CreateReturnObjectFromDatabaseObject(project, parentProjectRelation.ProjectId));
                }
94
95
96
97
98
99
                return Ok(_projectModel.CreateReturnObjectFromDatabaseObject(project));
            }
            else
            {
                return Unauthorized($"User is not allowed to see given the project {id}");
            }
Benedikt Heinrichs's avatar
Benedikt Heinrichs committed
100
101
        }

102
103
104
        [HttpGet("[controller]/{id}/resources")]
        public IActionResult GetResources(string id)
        {
105
106
107
108
109
110
111
            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))
            {
112
                var resources = resourceModel.GetAllWhere((resource) =>
113
114
115
116
117
118
                        (from projectResource in resource.ProjectResourceResourceIdIds
                         where projectResource.ProjectId == project.Id
                         select projectResource).Any())
                        .Select((resource) =>
                        {
                            return resourceModel.CreateReturnObjectFromDatabaseObject(resource);
119
                        }).OrderBy(element => element.DisplayName);
120
121
122
123
                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
                }
124
                return Json(resources);
125
126
127
128
129
            }
            else
            {
                return Unauthorized($"User is not allowed to see given the project {id}");
            }
130
131
        }

132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
        [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));

148

149
150
151
152
153
154
155
156
157
                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) =>
158
159
160
161
                                            resource.TypeId == projectQuota.ResourceType.Id
                                            && (from connection in resource.ProjectResourceResourceIdIds
                                                where connection.ProjectId == guidId
                                                select connection).Any());
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
                        
                        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!");
            }
        }
179

Benedikt Heinrichs's avatar
Benedikt Heinrichs committed
180
181
182
        [HttpPost("[controller]/{id}")]
        public IActionResult Update(string id)
        {
183
184
185
            var user = _authenticator.GetUser();
            var projectObject = ObjectFactory<ProjectObject>.DeserializeFromStream(Request.Body);
            var project = _projectModel.GetById(Guid.Parse(id));
186
            if (_projectModel.HasAccess(user, project, UserRoles.Owner))
187
            {
188
                LogAnalytics("Edit Project", null, null, id, user);
189
190
191
192
193
194
                return Ok(_projectModel.UpdateByObject(project, projectObject));
            }
            else
            {
                return Unauthorized("The user is not authorized to perform an update on the selected project!");
            }
Benedikt Heinrichs's avatar
Benedikt Heinrichs committed
195
196
        }

197
198
199
        [HttpDelete("[controller]/{id}")]
        public IActionResult Delete(string id)
        {
200
201
202
203
            var user = _authenticator.GetUser();
            var project = _projectModel.GetById(Guid.Parse(id));
            if (_projectModel.HasAccess(user, project, UserRoles.Owner))
            {
204
                LogAnalytics("Delete Project", null, null, id, user);
205
206
207
208
209
210
211
                DeleteProject(project);
                return Json(_projectModel.CreateReturnObjectFromDatabaseObject(project));
            }
            else
            {
                return Unauthorized("The user is not authorized to perform an update on the selected project!");
            }
212
213
        }

Marcel Nellesen's avatar
Marcel Nellesen committed
214
        public void DeleteProject(Database.DataModel.Project project, bool isHard = false, bool propegateAction = true)
215
        {
216
            var subProjectModel = new SubProjectModel();
217
218
219
220
            foreach (var subProject in subProjectModel.GetAllWhere(
                (subProject) => subProject.ProjectId == project.Id
                                && (subProject.SubProject_FK.Deleted == false || isHard)
            ))
221
            {
Marcel Nellesen's avatar
Marcel Nellesen committed
222
                Database.DataModel.Project subProjectObject;
223
224
225
                if (isHard)
                {
                    subProjectObject = _projectModel.GetByIdIncludingDeleted(subProject.SubProjectId);
226
                    subProjectModel.Delete(subProject);
227
228
229
230
231
232
                }
                else
                {
                    subProjectObject = _projectModel.GetById(subProject.SubProjectId);
                }
                DeleteProject(subProjectObject, isHard, propegateAction);
233
234
235
236
            }

            foreach (var subProject in subProjectModel.GetAllWhere((subProject) => subProject.SubProjectId == project.Id))
            {
237
238
239
240
                if (isHard)
                {
                    subProjectModel.Delete(subProject);
                }
241
242
            }

Marcel Nellesen's avatar
Marcel Nellesen committed
243
            if (isHard)
244
            {
Marcel Nellesen's avatar
Marcel Nellesen committed
245
246
247
                var projectResourceModel = new ProjectResourceModel();
                ResourceModel resourceModel = new ResourceModel();
                foreach (var projectResource in projectResourceModel.GetAllWhere((projectResource) => projectResource.ProjectId == project.Id))
248
249
250
251
                {
                    projectResourceModel.Delete(projectResource);
                    resourceModel.Delete(resourceModel.GetById(projectResource.ResourceId));
                }
252

Marcel Nellesen's avatar
Marcel Nellesen committed
253
254
                var projectRoleModel = new ProjectRoleModel();
                foreach (var projectRole in projectRoleModel.GetAllWhere((projectRole) => projectRole.ProjectId == project.Id))
255
256
257
                {
                    projectRoleModel.Delete(projectRole);
                }
258

Marcel Nellesen's avatar
Marcel Nellesen committed
259
260
                var projectDisciplineModel = new ProjectDisciplineModel();
                foreach (var projectDiscipline in projectDisciplineModel.GetAllWhere((projectDiscipline) => projectDiscipline.ProjectId == project.Id))
261
262
263
                {
                    projectDisciplineModel.Delete(projectDiscipline);
                }
264

Marcel Nellesen's avatar
Marcel Nellesen committed
265
266
                var projectInstituteModel = new ProjectInstituteModel();
                foreach (var projectInstitute in projectInstituteModel.GetAllWhere((projectInstitute) => projectInstitute.ProjectId == project.Id))
267
                {
Marcel Nellesen's avatar
Marcel Nellesen committed
268
269
270
271
272
273
274
                     projectInstituteModel.Delete(projectInstitute);
                }

                var projectQuotaModel = new ProjectQuotaModel();
                foreach (var projectQuota in projectQuotaModel.GetAllWhere((Quota) => Quota.ProjectId == project.Id))
                {
                    projectQuotaModel.Delete(projectQuota);
275
                }
276

Marcel Nellesen's avatar
Marcel Nellesen committed
277
278
                _activatedFeaturesModel.DeactivateAllFeatures(project);

279
280
281
282
283
284
285
                if (propegateAction)
                {
                    _emitter.EmitProjectDelete(new ProjectEventArgs(_configuration)
                    {
                        Project = project
                    });
                }
286

287
                _projectModel.HardDelete(project);
Marcel Nellesen's avatar
Marcel Nellesen committed
288
            }
289
290
291
292
            else
            {
                _projectModel.Delete(project);
            }
293
294
        }

295
        [HttpPost("[controller]")]
Benedikt Heinrichs's avatar
Benedikt Heinrichs committed
296
297
        public IActionResult Store()
        {
298
            var user = _authenticator.GetUser();
299
            var isRWTHMember = IsRWTHMember(user);
300
301
302
303
304
305
306
307
308
            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.");
            }

309
            var project = _projectModel.StoreFromObject(projectObject, user, isRWTHMember);
310

311
            if (projectObject.ParentId != null
312
313
314
315
316
317
318
319
320
321
322
323
324
325
                && 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
            });

326
327
            LogAnalytics("Add Project", null, null, project.Id.ToString(), user);

328
            return Json(_projectModel.CreateReturnObjectFromDatabaseObject(project));
Benedikt Heinrichs's avatar
Benedikt Heinrichs committed
329
        }
330

331
332
333
334
335
336
337
338
339
340
341
342
343
        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);
            }
344
            return new RdfStoreConnector(Program.Configuration.GetStringAndWait("coscine/local/virtuoso/additional/url")).GetTriples(new Uri("https://ror.org/04xfq0f34"), null, null, 1, externalIdList).Count() != 0;
345
346
        }

347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
        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);
            }
        }
Benedikt Heinrichs's avatar
Benedikt Heinrichs committed
388
389
    }
}