diff --git a/UI_DSM/UI_DSM.Client.Tests/Components/Administration/ModelManagement/CometConnectionTestFixture.cs b/UI_DSM/UI_DSM.Client.Tests/Components/Administration/ModelManagement/CometConnectionTestFixture.cs new file mode 100644 index 00000000..a3f51c8f --- /dev/null +++ b/UI_DSM/UI_DSM.Client.Tests/Components/Administration/ModelManagement/CometConnectionTestFixture.cs @@ -0,0 +1,145 @@ +// -------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2022 RHEA System S.A. +// +// Author: Antoine Théate, Sam Gerené, Alex Vorobiev, Alexander van Delft, Martin Risseeuw, Nabil Abbar +// +// This file is part of UI-DSM. +// The UI-DSM web application is used to review an ECSS-E-TM-10-25 model. +// +// The UI-DSM application is provided to the community under the Apache License 2.0. +// +// -------------------------------------------------------------------------------------------------------- + +namespace UI_DSM.Client.Tests.Components.Administration.ModelManagement +{ + using Bunit; + + using Microsoft.AspNetCore.Components; + using Microsoft.AspNetCore.Components.Forms; + + using Moq; + + using NUnit.Framework; + + using UI_DSM.Client.Components.Administration.ModelManagement; + using UI_DSM.Client.Services.Administration.CometService; + using UI_DSM.Client.Tests.Helpers; + using UI_DSM.Client.ViewModels.Components.Administration.ModelManagement; + using UI_DSM.Shared.DTO.CometData; + + using TestContext = Bunit.TestContext; + + [TestFixture] + public class CometConnectionTestFixture + { + private TestContext context; + private ICometConnectionViewModel viewModel; + private Mock cometService; + + [SetUp] + public void Setup() + { + this.context = new TestContext(); + this.context.ConfigureDevExpressBlazor(); + this.cometService = new Mock(); + this.viewModel = new CometConnectionViewModel(this.cometService.Object); + } + + [TearDown] + public void Teardown() + { + this.context.CleanContext(); + this.viewModel.Dispose(); + } + + [Test] + public async Task VerifyComponent() + { + var renderer = this.context.RenderComponent(parameters => + { + parameters.Add(p => p.ViewModel, this.viewModel); + }); + + this.viewModel.InitializeProperties(); + + var editForm = renderer.FindComponent(); + + this.viewModel.AuthenticationData.Url = "http://localhost"; + this.viewModel.AuthenticationData.UserName = "admin"; + this.viewModel.AuthenticationData.Password = "password"; + + this.cometService.Setup(x => x.Login(this.viewModel.AuthenticationData)).ReturnsAsync(new CometAuthenticationResponse() + { + IsRequestSuccessful = false + }); + + await renderer.InvokeAsync(editForm.Instance.OnValidSubmit.InvokeAsync); + Assert.That(renderer.Instance.ConnectButtonText, Is.EqualTo("Retry")); + + var sessionId = Guid.NewGuid(); + + this.cometService.Setup(x => x.Login(this.viewModel.AuthenticationData)).ReturnsAsync(new CometAuthenticationResponse() + { + IsRequestSuccessful = true, + SessionId = sessionId + }); + + var modelGuid = Guid.NewGuid(); + var iterationGuid = Guid.NewGuid(); + + var modelsData = new ModelsDataResponse() + { + ModelNames = new Dictionary(), + AvailableModels = new Dictionary>>() + }; + + modelsData.ModelNames[modelGuid] = "LOFT"; + + modelsData.AvailableModels[modelGuid] = new List> + { + new (iterationGuid, "Iteration 1") + }; + + this.cometService.Setup(x => x.GetAvailableEngineeringModels(It.IsAny())) + .ReturnsAsync(modelsData); + + await renderer.InvokeAsync(editForm.Instance.OnValidSubmit.InvokeAsync); + Assert.That(this.viewModel.AuthenticationData.Password, Is.Empty); + + this.viewModel.OnEventCallback = new EventCallbackFactory().Create(this.viewModel, async () => + { + var upload = await this.cometService.Object.UploadIteration(sessionId, modelGuid, iterationGuid); + + if(!upload.IsRequestSuccessful) + { + this.viewModel.HandleUploadFailure(upload); + } + else + { + await this.viewModel.CometLogout(); + } + }); + + this.viewModel.SelectedEngineeringModelSetup = new Tuple(modelGuid, "LOFT"); + + this.cometService.Setup(x => x.UploadIteration(sessionId, modelGuid, iterationGuid)) + .ReturnsAsync(new ModelUploadResponse() + { + IsRequestSuccessful = false, + Errors = new List{"Error during uploading"} + }); + + await renderer.InvokeAsync(this.viewModel.OnEventCallback.InvokeAsync); + Assert.That(renderer.Instance.UploadText, Is.EqualTo("Retry...")); + + this.cometService.Setup(x => x.UploadIteration(sessionId, modelGuid, iterationGuid)) + .ReturnsAsync(new ModelUploadResponse() + { + IsRequestSuccessful = true + }); + + await renderer.InvokeAsync(this.viewModel.OnEventCallback.InvokeAsync); + } + } +} diff --git a/UI_DSM/UI_DSM.Client.Tests/Helpers/JsonSerializerHelper.cs b/UI_DSM/UI_DSM.Client.Tests/Helpers/JsonSerializerHelper.cs deleted file mode 100644 index 45f4893a..00000000 --- a/UI_DSM/UI_DSM.Client.Tests/Helpers/JsonSerializerHelper.cs +++ /dev/null @@ -1,85 +0,0 @@ -// -------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2022 RHEA System S.A. -// -// Author: Antoine Théate, Sam Gerené, Alex Vorobiev, Alexander van Delft -// -// This file is part of UI-DSM. -// The UI-DSM web application is used to review an ECSS-E-TM-10-25 model. -// -// The UI-DSM application is provided to the community under the Apache License 2.0. -// -// -------------------------------------------------------------------------------------------------------- - -namespace UI_DSM.Client.Tests.Helpers -{ - using System.Text.Json; - - using UI_DSM.Serializer.Json; - using UI_DSM.Shared.DTO.Common; - using UI_DSM.Shared.DTO.Models; - - using JsonSerializer = UI_DSM.Serializer.Json.JsonSerializer; - - /// - /// Helper class for all call to Json Serialization inside tests - /// - public static class JsonSerializerHelper - { - /// - /// The - /// - private static readonly JsonWriterOptions Settings = new() - { - Indented = true - }; - - private static readonly IJsonSerializer Serializer = new JsonSerializer(); - - /// - /// Serialize the to a Json with the correct settings applied - /// - /// The to serialize - /// The Json output - public static string SerializeObject(object model) - { - var stream = new MemoryStream(); - - if (model is EntityDto dto) - { - Serializer.Serialize(dto, stream, Settings); - return ReadStreamResult(stream); - } - - if (model is IEnumerable dtos) - { - Serializer.Serialize(dtos, stream, Settings); - return ReadStreamResult(stream); - } - - if (model is EntityRequestResponseDto entityRequest) - { - Serializer.SerializeEntityRequestDto(entityRequest, stream, Settings); - return ReadStreamResult(stream); - } - - return System.Text.Json.JsonSerializer.Serialize(model, new JsonSerializerOptions - { - PropertyNameCaseInsensitive = false - }); - } - - /// - /// Reads the content of a - /// - /// The - /// The content of the - private static string ReadStreamResult(Stream stream) - { - using var reader = new StreamReader(stream); - stream.Seek(0, SeekOrigin.Begin); - var serialized = reader.ReadToEnd(); - return serialized; - } - } -} diff --git a/UI_DSM/UI_DSM.Client.Tests/Pages/Administration/ProjectPages/ProjectPageTestFixture.cs b/UI_DSM/UI_DSM.Client.Tests/Pages/Administration/ProjectPages/ProjectPageTestFixture.cs index dc699495..2cdaf123 100644 --- a/UI_DSM/UI_DSM.Client.Tests/Pages/Administration/ProjectPages/ProjectPageTestFixture.cs +++ b/UI_DSM/UI_DSM.Client.Tests/Pages/Administration/ProjectPages/ProjectPageTestFixture.cs @@ -26,6 +26,8 @@ namespace UI_DSM.Client.Tests.Pages.Administration.ProjectPages using UI_DSM.Client.Services.Administration.ParticipantService; using UI_DSM.Client.Services.Administration.ProjectService; using UI_DSM.Client.Services.Administration.RoleService; + using UI_DSM.Client.Services.ArtifactService; + using UI_DSM.Client.ViewModels.Components.Administration.ModelManagement; using UI_DSM.Client.ViewModels.Pages.Administration.ProjectPages; using UI_DSM.Shared.Models; using UI_DSM.Shared.Types; @@ -40,6 +42,8 @@ public class ProjectPageTestFixture private Mock projectService; private Mock participantService; private Mock roleService; + private Mock artifactService; + private Mock cometConnexionViewModel; [SetUp] public void Setup() @@ -48,7 +52,12 @@ public void Setup() this.projectService = new Mock(); this.participantService = new Mock(); this.roleService = new Mock(); - this.viewModel = new ProjectPageViewModel(this.projectService.Object, this.participantService.Object, this.roleService.Object); + this.cometConnexionViewModel = new Mock(); + this.artifactService = new Mock(); + + this.viewModel = new ProjectPageViewModel(this.projectService.Object, this.participantService.Object, this.roleService.Object, + this.cometConnexionViewModel.Object, this.artifactService.Object); + this.context.Services.AddSingleton(this.viewModel); } diff --git a/UI_DSM/UI_DSM.Client.Tests/Services/Administration/CometService/CometServiceTestFixture.cs b/UI_DSM/UI_DSM.Client.Tests/Services/Administration/CometService/CometServiceTestFixture.cs new file mode 100644 index 00000000..63ceec2e --- /dev/null +++ b/UI_DSM/UI_DSM.Client.Tests/Services/Administration/CometService/CometServiceTestFixture.cs @@ -0,0 +1,128 @@ +// -------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2022 RHEA System S.A. +// +// Author: Antoine Théate, Sam Gerené, Alex Vorobiev, Alexander van Delft, Martin Risseeuw, Nabil Abbar +// +// This file is part of UI-DSM. +// The UI-DSM web application is used to review an ECSS-E-TM-10-25 model. +// +// The UI-DSM application is provided to the community under the Apache License 2.0. +// +// -------------------------------------------------------------------------------------------------------- + +namespace UI_DSM.Client.Tests.Services.Administration.CometService +{ + using System.Net; + + using NUnit.Framework; + + using RichardSzalay.MockHttp; + + using UI_DSM.Client.Services; + using UI_DSM.Client.Services.Administration.CometService; + using UI_DSM.Client.Services.JsonDeserializerProvider; + using UI_DSM.Serializer.Json; + using UI_DSM.Shared.DTO.CometData; + + [TestFixture] + public class CometServiceTestFixture + { + private CometService service; + private MockHttpMessageHandler httpMessageHandler; + private IJsonService jsonService; + + [SetUp] + public void Setup() + { + this.httpMessageHandler = new MockHttpMessageHandler(); + var httpClient = this.httpMessageHandler.ToHttpClient(); + httpClient.BaseAddress = new Uri("http://localhost/api"); + + ServiceBase.RegisterService(); + this.jsonService = new JsonService(new JsonDeserializer(), new JsonSerializer()); + this.service = new CometService(httpClient, this.jsonService); + } + + [Test] + public async Task VerifyLogin() + { + var httpResponse = new HttpResponseMessage(); + var request = this.httpMessageHandler.When(HttpMethod.Post, "/Comet/Login"); + + var cometAuthentication = new CometAuthenticationData(); + + request.Respond(_ => httpResponse); + Assert.That(async () => await this.service.Login(cometAuthentication), Throws.Exception); + + httpResponse.Content = new StringContent(this.jsonService.Serialize(new CometAuthenticationResponse() + { + IsRequestSuccessful = false + })); + + Assert.That((await this.service.Login(cometAuthentication)).IsRequestSuccessful, Is.False); + + httpResponse.Content = new StringContent(this.jsonService.Serialize(new CometAuthenticationResponse() + { + SessionId = Guid.NewGuid(), + IsRequestSuccessful = true + })); + + Assert.That((await this.service.Login(cometAuthentication)).IsRequestSuccessful, Is.True); + } + + [Test] + public async Task VerifyLogout() + { + var sessionId = Guid.NewGuid(); + var httpResponse = new HttpResponseMessage(); + httpResponse.StatusCode = HttpStatusCode.NotFound; + var request = this.httpMessageHandler.When(HttpMethod.Delete, $"/Comet/{sessionId}"); + request.Respond(_ => httpResponse); + + Assert.That(await this.service.Logout(sessionId), Is.False); + + httpResponse.StatusCode = HttpStatusCode.OK; + Assert.That(await this.service.Logout(sessionId), Is.True); + } + + [Test] + public async Task VerifyGetAvailableEngineeringModels() + { + var sessionId = Guid.NewGuid(); + var httpResponse = new HttpResponseMessage(); + httpResponse.StatusCode = HttpStatusCode.NotFound; + var request = this.httpMessageHandler.When(HttpMethod.Get, $"/Comet/{sessionId}/Models"); + request.Respond(_ => httpResponse); + + Assert.That(async () => await this.service.GetAvailableEngineeringModels(sessionId), Throws.Exception); + + httpResponse.StatusCode = HttpStatusCode.OK; + + var modelDataResponse = new ModelsDataResponse() + { + IsRequestSuccessful = true, + }; + + httpResponse.Content = new StringContent(this.jsonService.Serialize(modelDataResponse)); + Assert.That((await this.service.GetAvailableEngineeringModels(sessionId)).IsRequestSuccessful, Is.True); + } + + [Test] + public async Task VerifyUploadIteration() + { + var sessionId = Guid.NewGuid(); + var httpResponse = new HttpResponseMessage(); + var request = this.httpMessageHandler.When(HttpMethod.Post, $"/Comet/{sessionId}/Models/Upload"); + request.Respond(_ => httpResponse); + + var modelUploadResponse = new ModelUploadResponse() + { + IsRequestSuccessful = true + }; + + httpResponse.Content = new StringContent(this.jsonService.Serialize(modelUploadResponse)); + Assert.That((await this.service.UploadIteration(sessionId, Guid.NewGuid(),Guid.NewGuid())).IsRequestSuccessful, Is.True); + } + } +} diff --git a/UI_DSM/UI_DSM.Client.Tests/Services/Administration/ParticipantService/ParticipantServiceTestFixture.cs b/UI_DSM/UI_DSM.Client.Tests/Services/Administration/ParticipantService/ParticipantServiceTestFixture.cs index 6bfdf9e6..36e28764 100644 --- a/UI_DSM/UI_DSM.Client.Tests/Services/Administration/ParticipantService/ParticipantServiceTestFixture.cs +++ b/UI_DSM/UI_DSM.Client.Tests/Services/Administration/ParticipantService/ParticipantServiceTestFixture.cs @@ -22,7 +22,6 @@ namespace UI_DSM.Client.Tests.Services.Administration.ParticipantService using UI_DSM.Client.Services; using UI_DSM.Client.Services.Administration.ParticipantService; using UI_DSM.Client.Services.JsonDeserializerProvider; - using UI_DSM.Client.Tests.Helpers; using UI_DSM.Serializer.Json; using UI_DSM.Shared.DTO.Common; using UI_DSM.Shared.DTO.Models; @@ -35,7 +34,7 @@ public class ParticipantServiceTestFixture { private ParticipantService service; private MockHttpMessageHandler httpMessageHandler; - private IJsonDeserializerService jsonDeserializerService; + private IJsonService jsonService; [SetUp] public void Setup() @@ -45,8 +44,8 @@ public void Setup() httpClient.BaseAddress = new Uri("http://localhost/api"); ServiceBase.RegisterService(); - this.jsonDeserializerService = new JsonDeserializerService(new JsonDeserializer()); - this.service = new ParticipantService(httpClient, this.jsonDeserializerService); + this.jsonService = new JsonService(new JsonDeserializer(), new JsonSerializer()); + this.service = new ParticipantService(httpClient, this.jsonService); } [Test] @@ -110,7 +109,7 @@ public async Task VerifyGetParticipants() } }; - httpResponse.Content = new StringContent(JsonSerializerHelper.SerializeObject(entitiesDto)); + httpResponse.Content = new StringContent(this.jsonService.Serialize(entitiesDto)); var participants = await this.service.GetParticipantsOfProject(projectId); Assert.That(participants, Has.Count.EqualTo(2)); @@ -159,7 +158,7 @@ public async Task VerifyGetParticipant() } }; - httpResponse.Content = new StringContent(JsonSerializerHelper.SerializeObject(entitiesDto)); + httpResponse.Content = new StringContent(this.jsonService.Serialize(entitiesDto)); participant = await this.service.GetParticipantOfProject(projectId,guid); Assert.That(participant.Id, Is.EqualTo(guid)); @@ -197,7 +196,7 @@ public async Task VerifyCreateParticipant() IsRequestSuccessful = false }; - httpResponse.Content = new StringContent(JsonSerializerHelper.SerializeObject(entityRequestResponse)); + httpResponse.Content = new StringContent(this.jsonService.Serialize(entityRequestResponse)); var request = this.httpMessageHandler.When(HttpMethod.Post, $"/Project/{projectId}/Participant/Create"); request.Respond(_ => httpResponse); @@ -209,7 +208,7 @@ public async Task VerifyCreateParticipant() entityRequestResponse.Entities = participant.GetAssociatedEntities().ToDtos(); - httpResponse.Content = new StringContent(JsonSerializerHelper.SerializeObject(entityRequestResponse)); + httpResponse.Content = new StringContent(this.jsonService.Serialize(entityRequestResponse)); requestResponse = await this.service.CreateParticipant(projectId, participant); @@ -247,7 +246,7 @@ public async Task VerifyDeleteParticipant() var httpResponse = new HttpResponseMessage(); var requestResponse = new RequestResponseDto() { IsRequestSuccessful = true }; - httpResponse.Content = new StringContent(JsonSerializerHelper.SerializeObject(requestResponse)); + httpResponse.Content = new StringContent(this.jsonService.Serialize(requestResponse)); var request = this.httpMessageHandler.When(HttpMethod.Delete, $"/Project/{project.Id}/Participant/{participant.Id}"); request.Respond(_ => httpResponse); @@ -284,7 +283,7 @@ public async Task VerifyUpdateParticipant() var httpResponse = new HttpResponseMessage(); var requestResponse = new EntityRequestResponseDto() { IsRequestSuccessful = false }; - httpResponse.Content = new StringContent(JsonSerializerHelper.SerializeObject(requestResponse)); + httpResponse.Content = new StringContent(this.jsonService.Serialize(requestResponse)); var request = this.httpMessageHandler.When(HttpMethod.Put, $"/Project/{project.Id}/Participant/{participant.Id}"); request.Respond(_ => httpResponse); @@ -299,7 +298,7 @@ public async Task VerifyUpdateParticipant() requestResponse.Entities = participant.GetAssociatedEntities().ToDtos(); - httpResponse.Content = new StringContent(JsonSerializerHelper.SerializeObject(requestResponse)); + httpResponse.Content = new StringContent(this.jsonService.Serialize(requestResponse)); requestResult = await this.service.UpdateParticipant(participant); Assert.That(requestResult.IsRequestSuccessful, Is.True); @@ -338,7 +337,7 @@ public async Task VerifyGetAvailableUsersForCreation() } }; - httpResponse.Content = new StringContent(JsonSerializerHelper.SerializeObject(usersEntities.ToDtos())); + httpResponse.Content = new StringContent(this.jsonService.Serialize(usersEntities.ToDtos())); var availableUsers = await this.service.GetAvailableUsersForCreation(projectId); Assert.That(availableUsers, Has.Count.EqualTo(3)); } diff --git a/UI_DSM/UI_DSM.Client.Tests/Services/Administration/ProjectService/ProjectServiceTestFixture.cs b/UI_DSM/UI_DSM.Client.Tests/Services/Administration/ProjectService/ProjectServiceTestFixture.cs index a8c62592..a1034956 100644 --- a/UI_DSM/UI_DSM.Client.Tests/Services/Administration/ProjectService/ProjectServiceTestFixture.cs +++ b/UI_DSM/UI_DSM.Client.Tests/Services/Administration/ProjectService/ProjectServiceTestFixture.cs @@ -23,7 +23,6 @@ namespace UI_DSM.Client.Tests.Services.Administration.ProjectService using UI_DSM.Client.Services; using UI_DSM.Client.Services.Administration.ProjectService; using UI_DSM.Client.Services.JsonDeserializerProvider; - using UI_DSM.Client.Tests.Helpers; using UI_DSM.Serializer.Json; using UI_DSM.Shared.DTO.Common; using UI_DSM.Shared.DTO.Models; @@ -35,7 +34,7 @@ public class ProjectServiceTestFixture { private ProjectService service; private MockHttpMessageHandler httpMessageHandler; - private IJsonDeserializerService jsonDeserializerService; + private IJsonService jsonService; [SetUp] public void Setup() @@ -45,8 +44,8 @@ public void Setup() httpClient.BaseAddress = new Uri("http://localhost/api"); ServiceBase.RegisterService(); - this.jsonDeserializerService = new JsonDeserializerService(new JsonDeserializer()); - this.service = new ProjectService(httpClient, this.jsonDeserializerService); + this.jsonService = new JsonService(new JsonDeserializer(), new JsonSerializer()); + this.service = new ProjectService(httpClient, this.jsonService); } [Test] @@ -69,7 +68,7 @@ public void VerifyGetProjects() } }; - httpResponse.Content = new StringContent(JsonSerializerHelper.SerializeObject(projectDtos)); + httpResponse.Content = new StringContent(this.jsonService.Serialize(projectDtos)); var projects = this.service.GetProjects().Result; Assert.That(projects.Count, Is.EqualTo(1)); @@ -92,7 +91,7 @@ public async Task VerifyCreateProject() IsRequestSuccessful = false }; - httpResponse.Content = new StringContent(JsonSerializerHelper.SerializeObject(entityRequestResponse)); + httpResponse.Content = new StringContent(this.jsonService.Serialize(entityRequestResponse)); var request = this.httpMessageHandler.When(HttpMethod.Post, "/Project/Create"); request.Respond(_ => httpResponse); @@ -105,7 +104,7 @@ public async Task VerifyCreateProject() project.ToDto() }; - httpResponse.Content = new StringContent(JsonSerializerHelper.SerializeObject(entityRequestResponse)); + httpResponse.Content = new StringContent(this.jsonService.Serialize(entityRequestResponse)); var result = await this.service.CreateProject(project); @@ -125,7 +124,7 @@ public void VerifyDeleteProject() var project = new Project(Guid.NewGuid()); var httpResponse = new HttpResponseMessage(); var requestResponse = new RequestResponseDto() { IsRequestSuccessful = true }; - httpResponse.Content = new StringContent(JsonSerializerHelper.SerializeObject(requestResponse)); + httpResponse.Content = new StringContent(this.jsonService.Serialize(requestResponse)); var request = this.httpMessageHandler.When(HttpMethod.Delete, $"/Project/{project.Id}"); request.Respond(_ => httpResponse); @@ -155,7 +154,7 @@ public async Task VerifyGetProject() ProjectName = "Project" }; - httpResponse.Content = new StringContent(JsonSerializerHelper.SerializeObject(new List(){projectDto})); + httpResponse.Content = new StringContent(this.jsonService.Serialize(new List(){projectDto})); project = await this.service.GetProject(guid); Assert.That(project.Id, Is.EqualTo(guid)); @@ -181,7 +180,7 @@ public async Task VerifyGetUserParticipation() }; httpResponse.StatusCode = HttpStatusCode.OK; - httpResponse.Content = new StringContent(JsonSerializerHelper.SerializeObject(projects.ToDtos())); + httpResponse.Content = new StringContent(this.jsonService.Serialize(projects.ToDtos())); var foundProject = await this.service.GetUserParticipation(); Assert.That(foundProject, Has.Count.EqualTo(2)); } diff --git a/UI_DSM/UI_DSM.Client.Tests/Services/Administration/RoleService/RoleServiceTestFixture.cs b/UI_DSM/UI_DSM.Client.Tests/Services/Administration/RoleService/RoleServiceTestFixture.cs index 8aa0f59c..daf9dc32 100644 --- a/UI_DSM/UI_DSM.Client.Tests/Services/Administration/RoleService/RoleServiceTestFixture.cs +++ b/UI_DSM/UI_DSM.Client.Tests/Services/Administration/RoleService/RoleServiceTestFixture.cs @@ -22,7 +22,6 @@ namespace UI_DSM.Client.Tests.Services.Administration.RoleService using UI_DSM.Client.Services; using UI_DSM.Client.Services.Administration.RoleService; using UI_DSM.Client.Services.JsonDeserializerProvider; - using UI_DSM.Client.Tests.Helpers; using UI_DSM.Serializer.Json; using UI_DSM.Shared.DTO.Common; using UI_DSM.Shared.DTO.Models; @@ -34,7 +33,7 @@ public class RoleServiceTestFixture { private RoleService service; private MockHttpMessageHandler httpMessageHandler; - private IJsonDeserializerService jsonDeserializerService; + private IJsonService jsonService; [SetUp] public void Setup() @@ -44,8 +43,8 @@ public void Setup() httpClient.BaseAddress = new Uri("http://localhost/api"); ServiceBase.RegisterService(); - this.jsonDeserializerService = new JsonDeserializerService(new JsonDeserializer()); - this.service = new RoleService(httpClient, this.jsonDeserializerService); + this.jsonService = new JsonService(new JsonDeserializer(), new JsonSerializer()); + this.service = new RoleService(httpClient, this.jsonService); } [Test] @@ -72,7 +71,7 @@ public void VerifyGetRoles() } }; - httpResponse.Content = new StringContent(JsonSerializerHelper.SerializeObject(rolesDtos)); + httpResponse.Content = new StringContent(this.jsonService.Serialize(rolesDtos)); var roles = this.service.GetRoles().Result; Assert.That(roles.Count, Is.EqualTo(1)); @@ -104,7 +103,7 @@ public async Task VerifyGetRole() } }; - httpResponse.Content = new StringContent(JsonSerializerHelper.SerializeObject(new List(){ roleDto })); + httpResponse.Content = new StringContent(this.jsonService.Serialize(new List(){ roleDto })); role = await this.service.GetRole(guid); Assert.That(role.Id, Is.EqualTo(guid)); @@ -133,7 +132,7 @@ public async Task VerifyCreateRole() IsRequestSuccessful = false }; - httpResponse.Content = new StringContent(JsonSerializerHelper.SerializeObject(entityRequestResponse)); + httpResponse.Content = new StringContent(this.jsonService.Serialize(entityRequestResponse)); var request = this.httpMessageHandler.When(HttpMethod.Post, "/Role/Create"); request.Respond(_ => httpResponse); @@ -146,7 +145,7 @@ public async Task VerifyCreateRole() role.ToDto() }; - httpResponse.Content = new StringContent(JsonSerializerHelper.SerializeObject(entityRequestResponse)); + httpResponse.Content = new StringContent(this.jsonService.Serialize(entityRequestResponse)); var result = await this.service.CreateRole(role); Assert.Multiple(() => @@ -165,7 +164,7 @@ public void VerifyDeleteRole() var role = new Role(Guid.NewGuid()); var httpResponse = new HttpResponseMessage(); var requestResponse = new RequestResponseDto() { IsRequestSuccessful = true }; - httpResponse.Content = new StringContent(JsonSerializerHelper.SerializeObject(requestResponse)); + httpResponse.Content = new StringContent(this.jsonService.Serialize(requestResponse)); var request = this.httpMessageHandler.When(HttpMethod.Delete, $"/Role/{role.Id}"); request.Respond(_ => httpResponse); @@ -189,7 +188,7 @@ public void VerifyUpdateRole() var httpResponse = new HttpResponseMessage(); var requestResponse = new EntityRequestResponseDto() { IsRequestSuccessful = false }; - httpResponse.Content = new StringContent(JsonSerializerHelper.SerializeObject(requestResponse)); + httpResponse.Content = new StringContent(this.jsonService.Serialize(requestResponse)); var request = this.httpMessageHandler.When(HttpMethod.Put, $"/Role/{role.Id}"); request.Respond(_ => httpResponse); @@ -202,7 +201,7 @@ public void VerifyUpdateRole() role.ToDto() }; - httpResponse.Content = new StringContent(JsonSerializerHelper.SerializeObject(requestResponse)); + httpResponse.Content = new StringContent(this.jsonService.Serialize(requestResponse)); Assert.That(this.service.UpdateRole(role).Result.IsRequestSuccessful, Is.True); httpResponse.Content = new StringContent(string.Empty); diff --git a/UI_DSM/UI_DSM.Client.Tests/Services/Administration/UserService/UserServiceTestFixture.cs b/UI_DSM/UI_DSM.Client.Tests/Services/Administration/UserService/UserServiceTestFixture.cs index 43c5d914..7fc26360 100644 --- a/UI_DSM/UI_DSM.Client.Tests/Services/Administration/UserService/UserServiceTestFixture.cs +++ b/UI_DSM/UI_DSM.Client.Tests/Services/Administration/UserService/UserServiceTestFixture.cs @@ -22,7 +22,6 @@ namespace UI_DSM.Client.Tests.Services.Administration.UserService using UI_DSM.Client.Services; using UI_DSM.Client.Services.Administration.UserService; using UI_DSM.Client.Services.JsonDeserializerProvider; - using UI_DSM.Client.Tests.Helpers; using UI_DSM.Serializer.Json; using UI_DSM.Shared.DTO.Common; using UI_DSM.Shared.DTO.Models; @@ -33,7 +32,7 @@ public class UserServiceTestFixture { private UserService service; private MockHttpMessageHandler httpMessageHandler; - private IJsonDeserializerService jsonDeserializerService; + private IJsonService jsonService; [SetUp] public void Setup() @@ -43,8 +42,8 @@ public void Setup() httpClient.BaseAddress = new Uri("http://localhost/api"); ServiceBase.RegisterService(); - this.jsonDeserializerService = new JsonDeserializerService(new JsonDeserializer()); - this.service = new UserService(httpClient, this.jsonDeserializerService); + this.jsonService = new JsonService(new JsonDeserializer(), new JsonSerializer()); + this.service = new UserService(httpClient, this.jsonService); } [Test] @@ -74,7 +73,7 @@ public void VerifyGetUsers() } }; - httpResponse.Content = new StringContent(JsonSerializerHelper.SerializeObject(users)); + httpResponse.Content = new StringContent(this.jsonService.Serialize(users)); var retrievedUsers = this.service.GetUsers().Result; Assert.That(retrievedUsers.Count, Is.EqualTo(users.Count)); @@ -94,7 +93,7 @@ public void VerifyRegisterUser() IsRequestSuccessful = false }; - httpResponse.Content = new StringContent(JsonSerializerHelper.SerializeObject(registrationResponse)); + httpResponse.Content = new StringContent(this.jsonService.Serialize(registrationResponse)); var registrationResult = this.service.RegisterUser(new RegistrationDto()).Result; Assert.That(registrationResult.IsRequestSuccessful, Is.False); @@ -110,7 +109,7 @@ public void VerifyRegisterUser() Id = Guid.NewGuid() }; - httpResponse.Content = new StringContent(JsonSerializerHelper.SerializeObject(registrationResponse)); + httpResponse.Content = new StringContent(this.jsonService.Serialize(registrationResponse)); registrationResult = this.service.RegisterUser(new RegistrationDto()).Result; Assert.That(registrationResult.IsRequestSuccessful, Is.True); Assert.That(registrationResult.CreatedUserEntity.Id, Is.EqualTo(registrationResponse.CreatedUserEntity.Id)); @@ -139,14 +138,14 @@ public void VerifyDeleteUser() httpResponse.StatusCode = HttpStatusCode.BadRequest; var requestResponse = new RequestResponseDto(); - httpResponse.Content = new StringContent(JsonSerializerHelper.SerializeObject(requestResponse)); + httpResponse.Content = new StringContent(this.jsonService.Serialize(requestResponse)); deleteResponse = this.service.DeleteUser(userToDelete).Result; Assert.That(deleteResponse.IsRequestSuccessful, Is.False); requestResponse.IsRequestSuccessful = true; - httpResponse.Content = new StringContent(JsonSerializerHelper.SerializeObject(requestResponse)); + httpResponse.Content = new StringContent(this.jsonService.Serialize(requestResponse)); deleteResponse = this.service.DeleteUser(userToDelete).Result; Assert.That(deleteResponse.IsRequestSuccessful, Is.True); diff --git a/UI_DSM/UI_DSM.Client.Tests/Services/AnnotationService/AnnotationServiceTestFixture.cs b/UI_DSM/UI_DSM.Client.Tests/Services/AnnotationService/AnnotationServiceTestFixture.cs index f956cbe3..c4693bab 100644 --- a/UI_DSM/UI_DSM.Client.Tests/Services/AnnotationService/AnnotationServiceTestFixture.cs +++ b/UI_DSM/UI_DSM.Client.Tests/Services/AnnotationService/AnnotationServiceTestFixture.cs @@ -22,7 +22,6 @@ namespace UI_DSM.Client.Tests.Services.AnnotationService using UI_DSM.Client.Services; using UI_DSM.Client.Services.AnnotationService; using UI_DSM.Client.Services.JsonDeserializerProvider; - using UI_DSM.Client.Tests.Helpers; using UI_DSM.Serializer.Json; using UI_DSM.Shared.DTO.Common; using UI_DSM.Shared.DTO.Models; @@ -36,7 +35,7 @@ public class AnnotationServiceTestFixture private AnnotationService service; private MockHttpMessageHandler httpMessageHandler; private List entitiesDto; - private JsonDeserializerService jsonDeserializerService; + private JsonService jsonService; [SetUp] public void Setup() @@ -115,8 +114,8 @@ public void Setup() ServiceBase.RegisterService(); - this.jsonDeserializerService = new JsonDeserializerService(new JsonDeserializer()); - this.service = new AnnotationService(httpClient, this.jsonDeserializerService); + this.jsonService = new JsonService(new JsonDeserializer(), new JsonSerializer()); + this.service = new AnnotationService(httpClient, this.jsonService); } [Test] @@ -132,7 +131,7 @@ public async Task VerifyGetAnnotations() Assert.That(async () => await this.service.GetAnnotationsOfProject(projectId), Throws.Exception); httpResponse.StatusCode = HttpStatusCode.OK; - httpResponse.Content = new StringContent(JsonSerializerHelper.SerializeObject(this.entitiesDto)); + httpResponse.Content = new StringContent(this.jsonService.Serialize(this.entitiesDto)); var annotations = await this.service.GetAnnotationsOfProject(projectId); Assert.That(annotations, Has.Count.EqualTo(3)); httpResponse.Content = new StringContent(string.Empty); @@ -155,7 +154,7 @@ public async Task VerifyGetAnnotation() httpResponse.StatusCode = HttpStatusCode.OK; - httpResponse.Content = new StringContent(JsonSerializerHelper.SerializeObject(this.entitiesDto)); + httpResponse.Content = new StringContent(this.jsonService.Serialize(this.entitiesDto)); annotation = await this.service.GetAnnotation(projectId, guid); Assert.Multiple(() => @@ -186,7 +185,7 @@ public async Task VerifyCreateAnnotation() IsRequestSuccessful = false }; - httpResponse.Content = new StringContent(JsonSerializerHelper.SerializeObject(entityRequestResponse)); + httpResponse.Content = new StringContent(this.jsonService.Serialize(entityRequestResponse)); var request = this.httpMessageHandler.When(HttpMethod.Post, $"/Project/{projectId}/Annotation/Create"); request.Respond(_ => httpResponse); @@ -197,7 +196,7 @@ public async Task VerifyCreateAnnotation() entityRequestResponse.Entities = annotation.GetAssociatedEntities().ToDtos(); - httpResponse.Content = new StringContent(JsonSerializerHelper.SerializeObject(entityRequestResponse)); + httpResponse.Content = new StringContent(this.jsonService.Serialize(entityRequestResponse)); requestResponse = await this.service.CreateAnnotation(projectId, annotation); @@ -224,7 +223,7 @@ public async Task VerifyDeleteAnnotation() var httpResponse = new HttpResponseMessage(); var requestResponse = new RequestResponseDto() { IsRequestSuccessful = true }; - httpResponse.Content = new StringContent(JsonSerializerHelper.SerializeObject(requestResponse)); + httpResponse.Content = new StringContent(this.jsonService.Serialize(requestResponse)); var request = this.httpMessageHandler.When(HttpMethod.Delete, $"/Project/{project.Id}/Annotation/{annotation.Id}"); request.Respond(_ => httpResponse); @@ -254,7 +253,7 @@ public async Task VerifyUpdateAnnotation() var httpResponse = new HttpResponseMessage(); var requestResponse = new EntityRequestResponseDto() { IsRequestSuccessful = false }; - httpResponse.Content = new StringContent(JsonSerializerHelper.SerializeObject(requestResponse)); + httpResponse.Content = new StringContent(this.jsonService.Serialize(requestResponse)); var request = this.httpMessageHandler.When(HttpMethod.Put, $"/Project/{project.Id}/Annotation/{annotation.Id}"); request.Respond(_ => httpResponse); @@ -269,7 +268,7 @@ public async Task VerifyUpdateAnnotation() requestResponse.Entities = annotation.GetAssociatedEntities().ToDtos(); - httpResponse.Content = new StringContent(JsonSerializerHelper.SerializeObject(requestResponse)); + httpResponse.Content = new StringContent(this.jsonService.Serialize(requestResponse)); requestResult = await this.service.UpdateAnnotation(annotation); Assert.That(requestResult.IsRequestSuccessful, Is.True); diff --git a/UI_DSM/UI_DSM.Client.Tests/Services/ArtifactService/ArtifactServiceTestFixture.cs b/UI_DSM/UI_DSM.Client.Tests/Services/ArtifactService/ArtifactServiceTestFixture.cs new file mode 100644 index 00000000..cd8f42b8 --- /dev/null +++ b/UI_DSM/UI_DSM.Client.Tests/Services/ArtifactService/ArtifactServiceTestFixture.cs @@ -0,0 +1,88 @@ +// -------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2022 RHEA System S.A. +// +// Author: Antoine Théate, Sam Gerené, Alex Vorobiev, Alexander van Delft, Martin Risseeuw, Nabil Abbar +// +// This file is part of UI-DSM. +// The UI-DSM web application is used to review an ECSS-E-TM-10-25 model. +// +// The UI-DSM application is provided to the community under the Apache License 2.0. +// +// -------------------------------------------------------------------------------------------------------- + +namespace UI_DSM.Client.Tests.Services.ArtifactService +{ + using NUnit.Framework; + + using RichardSzalay.MockHttp; + + using UI_DSM.Client.Services; + using UI_DSM.Client.Services.ArtifactService; + using UI_DSM.Client.Services.JsonDeserializerProvider; + using UI_DSM.Serializer.Json; + using UI_DSM.Shared.DTO.Common; + using UI_DSM.Shared.Extensions; + using UI_DSM.Shared.Models; + + [TestFixture] + public class ArtifactServiceTestFixture + { + private ArtifactService service; + private MockHttpMessageHandler httpMessageHandler; + private JsonService jsonService; + + [SetUp] + public void Setup() + { + this.httpMessageHandler = new MockHttpMessageHandler(); + var httpClient = this.httpMessageHandler.ToHttpClient(); + httpClient.BaseAddress = new Uri("http://localhost/api"); + + ServiceBase.RegisterService(); + + this.jsonService = new JsonService(new JsonDeserializer(), new JsonSerializer()); + this.service = new ArtifactService(httpClient, this.jsonService); + } + + [Test] + public async Task VerifyUploadModel() + { + var projectId = Guid.NewGuid(); + var fileName = $"{Guid.NewGuid()}.zip"; + var modelName = "A Model - Iteration 1"; + + var httpResponse = new HttpResponseMessage(); + + var entityRequestResponse = new EntityRequestResponseDto() + { + IsRequestSuccessful = false + }; + + httpResponse.Content = new StringContent(this.jsonService.Serialize(entityRequestResponse)); + var request = this.httpMessageHandler.When(HttpMethod.Post, $"/Project/{projectId}/Artifact/Create"); + request.Respond(_ => httpResponse); + + var requestResponse = await this.service.UploadModel(projectId, fileName, modelName); + Assert.That(requestResponse.IsRequestSuccessful, Is.False); + + entityRequestResponse.IsRequestSuccessful = true; + + entityRequestResponse.Entities = new Model().GetAssociatedEntities().ToDtos(); + + httpResponse.Content = new StringContent(this.jsonService.Serialize(entityRequestResponse)); + + requestResponse = await this.service.UploadModel(projectId, fileName, modelName); + + Assert.Multiple(() => + { + Assert.That(requestResponse.IsRequestSuccessful, Is.True); + Assert.That(requestResponse.Entity, Is.Not.Null); + }); + + httpResponse.Content = new StringContent(string.Empty); + + Assert.That(async () => await this.service.UploadModel(projectId, fileName, modelName), Throws.Exception); + } + } +} diff --git a/UI_DSM/UI_DSM.Client.Tests/Services/AuthenticationService/AuthenticationServiceTestFixture.cs b/UI_DSM/UI_DSM.Client.Tests/Services/AuthenticationService/AuthenticationServiceTestFixture.cs index b842c4f1..040c7647 100644 --- a/UI_DSM/UI_DSM.Client.Tests/Services/AuthenticationService/AuthenticationServiceTestFixture.cs +++ b/UI_DSM/UI_DSM.Client.Tests/Services/AuthenticationService/AuthenticationServiceTestFixture.cs @@ -26,7 +26,6 @@ namespace UI_DSM.Client.Tests.Services.AuthenticationService using UI_DSM.Client.Services; using UI_DSM.Client.Services.AuthenticationService; using UI_DSM.Client.Services.JsonDeserializerProvider; - using UI_DSM.Client.Tests.Helpers; using UI_DSM.Serializer.Json; using UI_DSM.Shared.DTO.UserManagement; @@ -37,7 +36,7 @@ public class AuthenticationServiceTestFixture private MockHttpMessageHandler httpMessageHandler; private Mock authenticationProvider; private Mock sessionStorage; - private IJsonDeserializerService jsonDeserializerService; + private IJsonService jsonService; [SetUp] public void Setup() @@ -48,9 +47,9 @@ public void Setup() var httpClient = this.httpMessageHandler.ToHttpClient(); httpClient.BaseAddress = new Uri("http://localhost/api"); ServiceBase.RegisterService(); - this.jsonDeserializerService = new JsonDeserializerService(new JsonDeserializer()); + this.jsonService = new JsonService(new JsonDeserializer(), new JsonSerializer()); - this.service = new AuthenticationService(httpClient, this.jsonDeserializerService, + this.service = new AuthenticationService(httpClient, this.jsonService, this.authenticationProvider.Object, this.sessionStorage.Object); } @@ -62,7 +61,7 @@ public void VerifyLogin() var httpResponseMessage = new HttpResponseMessage() { StatusCode = HttpStatusCode.Unauthorized, - Content = new StringContent(JsonSerializerHelper.SerializeObject(new AuthenticationResponseDto() + Content = new StringContent(this.jsonService.Serialize(new AuthenticationResponseDto() { Errors = new List() { @@ -83,7 +82,7 @@ public void VerifyLogin() httpResponseMessage.StatusCode = HttpStatusCode.OK; - httpResponseMessage.Content = new StringContent(JsonSerializerHelper.SerializeObject(new AuthenticationResponseDto() + httpResponseMessage.Content = new StringContent(this.jsonService.Serialize(new AuthenticationResponseDto() { IsRequestSuccessful = true, Token = Guid.NewGuid().ToString() diff --git a/UI_DSM/UI_DSM.Client.Tests/Services/ReplyService/ReplyServiceTestFixture.cs b/UI_DSM/UI_DSM.Client.Tests/Services/ReplyService/ReplyServiceTestFixture.cs index 09952d00..ef1859cd 100644 --- a/UI_DSM/UI_DSM.Client.Tests/Services/ReplyService/ReplyServiceTestFixture.cs +++ b/UI_DSM/UI_DSM.Client.Tests/Services/ReplyService/ReplyServiceTestFixture.cs @@ -22,7 +22,6 @@ namespace UI_DSM.Client.Tests.Services.ReplyService using UI_DSM.Client.Services; using UI_DSM.Client.Services.JsonDeserializerProvider; using UI_DSM.Client.Services.ReplyService; - using UI_DSM.Client.Tests.Helpers; using UI_DSM.Serializer.Json; using UI_DSM.Shared.DTO.Common; using UI_DSM.Shared.DTO.Models; @@ -35,7 +34,7 @@ public class ReplyServiceTestFixture private ReplyService service; private MockHttpMessageHandler httpMessageHandler; private List entitiesDto; - private IJsonDeserializerService jsonDeserializerService; + private IJsonService jsonService; [SetUp] public void Setup() @@ -72,8 +71,8 @@ public void Setup() }; ServiceBase.RegisterService(); - this.jsonDeserializerService = new JsonDeserializerService(new JsonDeserializer()); - this.service = new ReplyService(httpClient, this.jsonDeserializerService); + this.jsonService = new JsonService(new JsonDeserializer(), new JsonSerializer()); + this.service = new ReplyService(httpClient, this.jsonService); } [Test] @@ -90,7 +89,7 @@ public async Task VerifyGetReplies() Assert.That(async () => await this.service.GetRepliesOfComment(projectId, annotationId), Throws.Exception); httpResponse.StatusCode = HttpStatusCode.OK; - httpResponse.Content = new StringContent(JsonSerializerHelper.SerializeObject(this.entitiesDto)); + httpResponse.Content = new StringContent(this.jsonService.Serialize(this.entitiesDto)); var replies = await this.service.GetRepliesOfComment(projectId, annotationId); Assert.That(replies, Has.Count.EqualTo(1)); httpResponse.Content = new StringContent(string.Empty); @@ -114,7 +113,7 @@ public async Task VerifyGetReply() httpResponse.StatusCode = HttpStatusCode.OK; - httpResponse.Content = new StringContent(JsonSerializerHelper.SerializeObject(this.entitiesDto)); + httpResponse.Content = new StringContent(this.jsonService.Serialize(this.entitiesDto)); reply = await this.service.GetReplyOfComment(projectId, annotationId, guid); Assert.That(reply.Id, Is.EqualTo(guid)); @@ -141,7 +140,7 @@ public async Task VerifyCreateReply() IsRequestSuccessful = false }; - httpResponse.Content = new StringContent(JsonSerializerHelper.SerializeObject(entityRequestResponse)); + httpResponse.Content = new StringContent(this.jsonService.Serialize(entityRequestResponse)); var request = this.httpMessageHandler.When(HttpMethod.Post, $"/Project/{projectId}/Annotation/{annotationId}/Reply/Create"); request.Respond(_ => httpResponse); @@ -152,7 +151,7 @@ public async Task VerifyCreateReply() entityRequestResponse.Entities = reply.GetAssociatedEntities().ToDtos(); - httpResponse.Content = new StringContent(JsonSerializerHelper.SerializeObject(entityRequestResponse)); + httpResponse.Content = new StringContent(this.jsonService.Serialize(entityRequestResponse)); requestResponse = await this.service.CreateReply(projectId, annotationId, reply); @@ -181,7 +180,7 @@ public async Task VerifyDeleteReply() var httpResponse = new HttpResponseMessage(); var requestResponse = new RequestResponseDto() { IsRequestSuccessful = true }; - httpResponse.Content = new StringContent(JsonSerializerHelper.SerializeObject(requestResponse)); + httpResponse.Content = new StringContent(this.jsonService.Serialize(requestResponse)); var request = this.httpMessageHandler.When(HttpMethod.Delete, $"/Project/{projectId}/Annotation/{annotation.Id}/Reply/{reply.Id}"); request.Respond(_ => httpResponse); @@ -213,7 +212,7 @@ public async Task VerifyUpdateReview() var httpResponse = new HttpResponseMessage(); var requestResponse = new EntityRequestResponseDto() { IsRequestSuccessful = false }; - httpResponse.Content = new StringContent(JsonSerializerHelper.SerializeObject(requestResponse)); + httpResponse.Content = new StringContent(this.jsonService.Serialize(requestResponse)); var request = this.httpMessageHandler.When(HttpMethod.Put, $"/Project/{projectId}/Annotation/{comment.Id}/Reply/{reply.Id}"); request.Respond(_ => httpResponse); @@ -228,7 +227,7 @@ public async Task VerifyUpdateReview() requestResponse.Entities = reply.GetAssociatedEntities().ToDtos(); - httpResponse.Content = new StringContent(JsonSerializerHelper.SerializeObject(requestResponse)); + httpResponse.Content = new StringContent(this.jsonService.Serialize(requestResponse)); requestResult = await this.service.UpdateReply(projectId, reply); Assert.That(requestResult.IsRequestSuccessful, Is.True); diff --git a/UI_DSM/UI_DSM.Client.Tests/Services/ReviewObjectiveService/ReviewObjectiveServiceTestFixture.cs b/UI_DSM/UI_DSM.Client.Tests/Services/ReviewObjectiveService/ReviewObjectiveServiceTestFixture.cs index 11b992f0..b84d5a18 100644 --- a/UI_DSM/UI_DSM.Client.Tests/Services/ReviewObjectiveService/ReviewObjectiveServiceTestFixture.cs +++ b/UI_DSM/UI_DSM.Client.Tests/Services/ReviewObjectiveService/ReviewObjectiveServiceTestFixture.cs @@ -36,7 +36,7 @@ public class ReviewObjectiveServiceTestFixture private ReviewObjectiveService service; private MockHttpMessageHandler httpMessageHandler; private List entitiesDto; - private IJsonDeserializerService jsonDeserializerService; + private IJsonService jsonService; [SetUp] public void Setup() @@ -76,8 +76,8 @@ public void Setup() }; ServiceBase.RegisterService(); - this.jsonDeserializerService = new JsonDeserializerService(new JsonDeserializer()); - this.service = new ReviewObjectiveService(httpClient, this.jsonDeserializerService); + this.jsonService = new JsonService(new JsonDeserializer(), new JsonSerializer()); + this.service = new ReviewObjectiveService(httpClient, this.jsonService); } [Test] @@ -94,7 +94,7 @@ public async Task VerifyGetReviewObjectives() Assert.That(async () => await this.service.GetReviewsObjectivesOfReview(projectId, reviewId), Throws.Exception); httpResponse.StatusCode = HttpStatusCode.OK; - httpResponse.Content = new StringContent(JsonSerializerHelper.SerializeObject(this.entitiesDto)); + httpResponse.Content = new StringContent(this.jsonService.Serialize(this.entitiesDto)); var reviewObjectives = await this.service.GetReviewsObjectivesOfReview(projectId, reviewId); Assert.That(reviewObjectives, Has.Count.EqualTo(1)); httpResponse.Content = new StringContent(string.Empty); @@ -118,7 +118,7 @@ public async Task VerifyGetReviewObjective() httpResponse.StatusCode = HttpStatusCode.OK; - httpResponse.Content = new StringContent(JsonSerializerHelper.SerializeObject(this.entitiesDto)); + httpResponse.Content = new StringContent(this.jsonService.Serialize(this.entitiesDto)); reviewObjective = await this.service.GetReviewObjectiveOfReview(projectId, reviewId, guid); Assert.That(reviewObjective.Id, Is.EqualTo(guid)); @@ -146,7 +146,7 @@ public async Task VerifyCreateReviewObjective() IsRequestSuccessful = false }; - httpResponse.Content = new StringContent(JsonSerializerHelper.SerializeObject(entityRequestResponse)); + httpResponse.Content = new StringContent(this.jsonService.Serialize(entityRequestResponse)); var request = this.httpMessageHandler.When(HttpMethod.Post, $"/Project/{projectId}/Review/{reviewId}/ReviewObjective/Create"); request.Respond(_ => httpResponse); @@ -157,7 +157,7 @@ public async Task VerifyCreateReviewObjective() entityRequestResponse.Entities = reviewObjective.GetAssociatedEntities().ToDtos(); - httpResponse.Content = new StringContent(JsonSerializerHelper.SerializeObject(entityRequestResponse)); + httpResponse.Content = new StringContent(this.jsonService.Serialize(entityRequestResponse)); requestResponse = await this.service.CreateReviewObjective(projectId, reviewId, reviewObjective); @@ -188,7 +188,7 @@ public async Task VerifyDeleteReviewObjective() var httpResponse = new HttpResponseMessage(); var requestResponse = new RequestResponseDto() { IsRequestSuccessful = true }; - httpResponse.Content = new StringContent(JsonSerializerHelper.SerializeObject(requestResponse)); + httpResponse.Content = new StringContent(this.jsonService.Serialize(requestResponse)); var request = this.httpMessageHandler.When(HttpMethod.Delete, $"/Project/{projectId}/Review/{review.Id}/ReviewObjective/{reviewObjective.Id}"); request.Respond(_ => httpResponse); @@ -222,7 +222,7 @@ public async Task VerifyUpdateReview() var httpResponse = new HttpResponseMessage(); var requestResponse = new EntityRequestResponseDto() { IsRequestSuccessful = false }; - httpResponse.Content = new StringContent(JsonSerializerHelper.SerializeObject(requestResponse)); + httpResponse.Content = new StringContent(this.jsonService.Serialize(requestResponse)); var request = this.httpMessageHandler.When(HttpMethod.Put, $"/Project/{projectId}/Review/{review.Id}/ReviewObjective/{reviewObjective.Id}"); request.Respond(_ => httpResponse); @@ -237,7 +237,7 @@ public async Task VerifyUpdateReview() requestResponse.Entities = reviewObjective.GetAssociatedEntities().ToDtos(); - httpResponse.Content = new StringContent(JsonSerializerHelper.SerializeObject(requestResponse)); + httpResponse.Content = new StringContent(this.jsonService.Serialize(requestResponse)); requestResult = await this.service.UpdateReviewObjective(projectId, reviewObjective); Assert.That(requestResult.IsRequestSuccessful, Is.True); diff --git a/UI_DSM/UI_DSM.Client.Tests/Services/ReviewService/ReviewServiceTestFixture.cs b/UI_DSM/UI_DSM.Client.Tests/Services/ReviewService/ReviewServiceTestFixture.cs index 085bc76b..d291e478 100644 --- a/UI_DSM/UI_DSM.Client.Tests/Services/ReviewService/ReviewServiceTestFixture.cs +++ b/UI_DSM/UI_DSM.Client.Tests/Services/ReviewService/ReviewServiceTestFixture.cs @@ -22,7 +22,6 @@ namespace UI_DSM.Client.Tests.Services.ReviewService using UI_DSM.Client.Services; using UI_DSM.Client.Services.JsonDeserializerProvider; using UI_DSM.Client.Services.ReviewService; - using UI_DSM.Client.Tests.Helpers; using UI_DSM.Serializer.Json; using UI_DSM.Shared.DTO.Common; using UI_DSM.Shared.DTO.Models; @@ -35,7 +34,7 @@ public class ReviewServiceTestFixture private ReviewService service; private MockHttpMessageHandler httpMessageHandler; private List entitiesDto; - private IJsonDeserializerService jsonDeserializerService; + private IJsonService jsonService; [SetUp] public void Setup() @@ -74,8 +73,8 @@ public void Setup() }; ServiceBase.RegisterService(); - this.jsonDeserializerService = new JsonDeserializerService(new JsonDeserializer()); - this.service = new ReviewService(httpClient, this.jsonDeserializerService); + this.jsonService = new JsonService(new JsonDeserializer(), new JsonSerializer()); + this.service = new ReviewService(httpClient, this.jsonService); } [Test] @@ -91,7 +90,7 @@ public async Task VerifyGetReviews() Assert.That(async () => await this.service.GetReviewsOfProject(projectId), Throws.Exception); httpResponse.StatusCode = HttpStatusCode.OK; - httpResponse.Content = new StringContent(JsonSerializerHelper.SerializeObject(this.entitiesDto)); + httpResponse.Content = new StringContent(this.jsonService.Serialize(this.entitiesDto)); var reviews = await this.service.GetReviewsOfProject(projectId); Assert.That(reviews, Has.Count.EqualTo(1)); httpResponse.Content = new StringContent(string.Empty); @@ -114,7 +113,7 @@ public async Task VerifyGetReview() httpResponse.StatusCode = HttpStatusCode.OK; - httpResponse.Content = new StringContent(JsonSerializerHelper.SerializeObject(this.entitiesDto)); + httpResponse.Content = new StringContent(this.jsonService.Serialize(this.entitiesDto)); review = await this.service.GetReviewOfProject(projectId, guid); Assert.That(review.Id, Is.EqualTo(guid)); @@ -141,7 +140,7 @@ public async Task VerifyCreateReview() IsRequestSuccessful = false }; - httpResponse.Content = new StringContent(JsonSerializerHelper.SerializeObject(entityRequestResponse)); + httpResponse.Content = new StringContent(this.jsonService.Serialize(entityRequestResponse)); var request = this.httpMessageHandler.When(HttpMethod.Post, $"/Project/{projectId}/Review/Create"); request.Respond(_ => httpResponse); @@ -152,7 +151,7 @@ public async Task VerifyCreateReview() entityRequestResponse.Entities = review.GetAssociatedEntities().ToDtos(); - httpResponse.Content = new StringContent(JsonSerializerHelper.SerializeObject(entityRequestResponse)); + httpResponse.Content = new StringContent(this.jsonService.Serialize(entityRequestResponse)); requestResponse = await this.service.CreateReview(projectId, review); @@ -182,7 +181,7 @@ public async Task VerifyDeleteReview() var httpResponse = new HttpResponseMessage(); var requestResponse = new RequestResponseDto() { IsRequestSuccessful = true }; - httpResponse.Content = new StringContent(JsonSerializerHelper.SerializeObject(requestResponse)); + httpResponse.Content = new StringContent(this.jsonService.Serialize(requestResponse)); var request = this.httpMessageHandler.When(HttpMethod.Delete, $"/Project/{project.Id}/Review/{review.Id}"); request.Respond(_ => httpResponse); @@ -215,7 +214,7 @@ public async Task VerifyUpdateReview() var httpResponse = new HttpResponseMessage(); var requestResponse = new EntityRequestResponseDto() { IsRequestSuccessful = false }; - httpResponse.Content = new StringContent(JsonSerializerHelper.SerializeObject(requestResponse)); + httpResponse.Content = new StringContent(this.jsonService.Serialize(requestResponse)); var request = this.httpMessageHandler.When(HttpMethod.Put, $"/Project/{project.Id}/Review/{review.Id}"); request.Respond(_ => httpResponse); @@ -230,7 +229,7 @@ public async Task VerifyUpdateReview() requestResponse.Entities = review.GetAssociatedEntities().ToDtos(); - httpResponse.Content = new StringContent(JsonSerializerHelper.SerializeObject(requestResponse)); + httpResponse.Content = new StringContent(this.jsonService.Serialize(requestResponse)); requestResult = await this.service.UpdateReview(review); Assert.That(requestResult.IsRequestSuccessful, Is.True); diff --git a/UI_DSM/UI_DSM.Client.Tests/Services/ReviewTaskService/ReviewTaskServiceTestFixture.cs b/UI_DSM/UI_DSM.Client.Tests/Services/ReviewTaskService/ReviewTaskServiceTestFixture.cs index 95051bc9..1c9ea58f 100644 --- a/UI_DSM/UI_DSM.Client.Tests/Services/ReviewTaskService/ReviewTaskServiceTestFixture.cs +++ b/UI_DSM/UI_DSM.Client.Tests/Services/ReviewTaskService/ReviewTaskServiceTestFixture.cs @@ -22,7 +22,6 @@ namespace UI_DSM.Client.Tests.Services.ReviewTaskService using UI_DSM.Client.Services; using UI_DSM.Client.Services.JsonDeserializerProvider; using UI_DSM.Client.Services.ReviewTaskService; - using UI_DSM.Client.Tests.Helpers; using UI_DSM.Serializer.Json; using UI_DSM.Shared.DTO.Common; using UI_DSM.Shared.DTO.Models; @@ -39,7 +38,7 @@ public class ReviewTaskServiceTestFixture private Guid projectId; private Guid reviewId; private Guid reviewObjectiveId; - private IJsonDeserializerService jsonDeserializerService; + private IJsonService jsonService; [SetUp] public void Setup() @@ -83,8 +82,8 @@ public void Setup() }; ServiceBase.RegisterService(); - this.jsonDeserializerService = new JsonDeserializerService(new JsonDeserializer()); - this.service = new ReviewTaskService(httpClient, this.jsonDeserializerService); + this.jsonService = new JsonService(new JsonDeserializer(), new JsonSerializer()); + this.service = new ReviewTaskService(httpClient, this.jsonService); } [Test] @@ -99,7 +98,7 @@ public async Task VerifyGetReviewTasks() Assert.That(async () => await this.service.GetTasksOfReviewObjectives(this.projectId, this.reviewId, this.reviewObjectiveId), Throws.Exception); httpResponse.StatusCode = HttpStatusCode.OK; - httpResponse.Content = new StringContent(JsonSerializerHelper.SerializeObject(this.entitiesDto)); + httpResponse.Content = new StringContent(this.jsonService.Serialize(this.entitiesDto)); var reviewTasks = await this.service.GetTasksOfReviewObjectives(this.projectId, this.reviewId, this.reviewObjectiveId); Assert.That(reviewTasks, Has.Count.EqualTo(1)); httpResponse.Content = new StringContent(string.Empty); @@ -121,7 +120,7 @@ public async Task VerifyGetReviewTask() httpResponse.StatusCode = HttpStatusCode.OK; - httpResponse.Content = new StringContent(JsonSerializerHelper.SerializeObject(this.entitiesDto)); + httpResponse.Content = new StringContent(this.jsonService.Serialize(this.entitiesDto)); reviewTask = await this.service.GetTaskOfReviewObjective(this.projectId, this.reviewId, this.reviewObjectiveId, guid); Assert.That(reviewTask.Id, Is.EqualTo(guid)); @@ -147,7 +146,7 @@ public async Task VerifyCreateReviewTask() IsRequestSuccessful = false }; - httpResponse.Content = new StringContent(JsonSerializerHelper.SerializeObject(entityRequestResponse)); + httpResponse.Content = new StringContent(this.jsonService.Serialize(entityRequestResponse)); var request = this.httpMessageHandler.When(HttpMethod.Post, $"/Project/{this.projectId}/Review/{this.reviewId}/ReviewObjective/{this.reviewObjectiveId}/ReviewTask/Create"); request.Respond(_ => httpResponse); @@ -158,7 +157,7 @@ public async Task VerifyCreateReviewTask() entityRequestResponse.Entities = reviewTask.GetAssociatedEntities().ToDtos(); - httpResponse.Content = new StringContent(JsonSerializerHelper.SerializeObject(entityRequestResponse)); + httpResponse.Content = new StringContent(this.jsonService.Serialize(entityRequestResponse)); requestResponse = await this.service.CreateReviewTask(this.projectId, this.reviewId, this.reviewObjectiveId, reviewTask); @@ -187,7 +186,7 @@ public async Task VerifyDeleteReviewTask() var reviewObjective = new ReviewObjective(this.reviewObjectiveId); var httpResponse = new HttpResponseMessage(); var requestResponse = new RequestResponseDto() { IsRequestSuccessful = true }; - httpResponse.Content = new StringContent(JsonSerializerHelper.SerializeObject(requestResponse)); + httpResponse.Content = new StringContent(this.jsonService.Serialize(requestResponse)); var request = this.httpMessageHandler.When(HttpMethod.Delete, $"/Project/{this.projectId}/Review/{this.reviewId}/ReviewObjective/{this.reviewObjectiveId}/ReviewTask/{reviewTask.Id}"); request.Respond(_ => httpResponse); @@ -220,7 +219,7 @@ public async Task VerifyUpdateReview() var httpResponse = new HttpResponseMessage(); var requestResponse = new EntityRequestResponseDto() { IsRequestSuccessful = false }; - httpResponse.Content = new StringContent(JsonSerializerHelper.SerializeObject(requestResponse)); + httpResponse.Content = new StringContent(this.jsonService.Serialize(requestResponse)); var request = this.httpMessageHandler.When(HttpMethod.Put, $"/Project/{this.projectId}/Review/{this.reviewId}/ReviewObjective/{this.reviewObjectiveId}/ReviewTask/{reviewTask.Id}"); request.Respond(_ => httpResponse); @@ -235,7 +234,7 @@ public async Task VerifyUpdateReview() requestResponse.Entities = reviewTask.GetAssociatedEntities().ToDtos(); - httpResponse.Content = new StringContent(JsonSerializerHelper.SerializeObject(requestResponse)); + httpResponse.Content = new StringContent(this.jsonService.Serialize(requestResponse)); requestResult = await this.service.UpdateReviewTask(this.projectId, this.reviewId, reviewTask); Assert.That(requestResult.IsRequestSuccessful, Is.True); diff --git a/UI_DSM/UI_DSM.Client.Tests/UI_DSM.Client.Tests.csproj b/UI_DSM/UI_DSM.Client.Tests/UI_DSM.Client.Tests.csproj index bbe20824..6a561567 100644 --- a/UI_DSM/UI_DSM.Client.Tests/UI_DSM.Client.Tests.csproj +++ b/UI_DSM/UI_DSM.Client.Tests/UI_DSM.Client.Tests.csproj @@ -23,6 +23,8 @@ runtime; build; native; contentfiles; analyzers; buildtransitive + + diff --git a/UI_DSM/UI_DSM.Client/Components/Administration/ModelManagement/CometConnection.razor b/UI_DSM/UI_DSM.Client/Components/Administration/ModelManagement/CometConnection.razor new file mode 100644 index 00000000..d5f6ff50 --- /dev/null +++ b/UI_DSM/UI_DSM.Client/Components/Administration/ModelManagement/CometConnection.razor @@ -0,0 +1,58 @@ + +@using UI_DSM.Client.Enumerator +@using CDP4Common.SiteDirectoryData + +@if (this.ViewModel.CometConnectionStatus != AuthenticationStatus.Success) +{ + + +

@this.ViewModel.ErrorMessage

+ + + + + + + + + + + + +
+} +else +{ + + +

@this.ViewModel.ErrorMessage

+ + + + + + + + + +
+} + diff --git a/UI_DSM/UI_DSM.Client/Components/Administration/ModelManagement/CometConnection.razor.cs b/UI_DSM/UI_DSM.Client/Components/Administration/ModelManagement/CometConnection.razor.cs new file mode 100644 index 00000000..0a3477af --- /dev/null +++ b/UI_DSM/UI_DSM.Client/Components/Administration/ModelManagement/CometConnection.razor.cs @@ -0,0 +1,132 @@ +// -------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2022 RHEA System S.A. +// +// Author: Antoine Théate, Sam Gerené, Alex Vorobiev, Alexander van Delft, Martin Risseeuw +// +// This file is part of UI-DSM. +// The UI-DSM web application is used to review an ECSS-E-TM-10-25 model. +// +// The UI-DSM application is provided to the community under the Apache License 2.0. +// +// -------------------------------------------------------------------------------------------------------- + +namespace UI_DSM.Client.Components.Administration.ModelManagement +{ + using CDP4Common.SiteDirectoryData; + + using Microsoft.AspNetCore.Components; + + using ReactiveUI; + + using UI_DSM.Client.Enumerator; + using UI_DSM.Client.ViewModels.Components.Administration.ModelManagement; + + /// + /// Component that gave the possibility to connect to a COMET instance + /// + public partial class CometConnection : IDisposable + { + /// + /// A collection of + /// + private List disposables = new(); + + /// + /// The + /// + [Parameter] + public ICometConnectionViewModel ViewModel { get; set; } + + /// + /// The text to display inside the connection button + /// + public string ConnectButtonText { get; private set; } + + /// + /// The text to display inside the upload button + /// + public string UploadText { get; set; } + + /// + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + /// + public void Dispose() + { + this.disposables.ForEach(x => x.Dispose()); + this.disposables.Clear(); + } + + /// + /// Method invoked when the component is ready to start, having received its + /// initial parameters from its parent in the render tree. + /// Override this method if you will perform an asynchronous operation and + /// want the component to refresh when that operation is completed. + /// + /// A representing any asynchronous operation. + protected override Task OnInitializedAsync() + { + this.disposables.Add(this.WhenAnyValue(x => x.ViewModel.CometConnectionStatus) + .Subscribe(_ => this.OnCometConnectionStatusChanged())); + + this.disposables.Add(this.WhenAnyValue(x => x.ViewModel.IterationUploadStatus) + .Subscribe(_ => this.OnIterationUploadStatusChanged())); + + this.disposables.Add(this.WhenAnyValue(x => x.ViewModel.ErrorMessage) + .Subscribe(_ => this.InvokeAsync(this.StateHasChanged))); + + return base.OnInitializedAsync(); + } + + /// + /// Sets properties when the has changed + /// + private void OnIterationUploadStatusChanged() + { + switch (this.ViewModel.IterationUploadStatus) + { + case UploadStatus.None: + this.UploadText = "Upload"; + break; + case UploadStatus.Uploading: + this.UploadText = "Uploading"; + break; + case UploadStatus.Fail: + this.UploadText = "Retry..."; + break; + case UploadStatus.Done: + break; + default: + throw new InvalidDataException("Unsupported value"); + } + + this.InvokeAsync(this.StateHasChanged); + } + + /// + /// Sets properties when the has changed + /// + private void OnCometConnectionStatusChanged() + { + switch (this.ViewModel.CometConnectionStatus) + { + case AuthenticationStatus.None: + this.ConnectButtonText = "Login to COMET"; + break; + case AuthenticationStatus.Authenticating: + this.ConnectButtonText = "Authenticating..."; + break; + case AuthenticationStatus.Fail: + case AuthenticationStatus.ServerFailure: + this.ConnectButtonText = "Retry"; + break; + case AuthenticationStatus.Success: + break; + default: + throw new InvalidDataException("Unsupported value"); + } + + this.InvokeAsync(this.StateHasChanged); + } + } +} diff --git a/UI_DSM/UI_DSM.Client/Enumerator/AuthenticationStatus.cs b/UI_DSM/UI_DSM.Client/Enumerator/AuthenticationStatus.cs index 63dbe75c..7e86664d 100644 --- a/UI_DSM/UI_DSM.Client/Enumerator/AuthenticationStatus.cs +++ b/UI_DSM/UI_DSM.Client/Enumerator/AuthenticationStatus.cs @@ -14,28 +14,33 @@ namespace UI_DSM.Client.Enumerator { /// - /// Enumeration that defines possible status for the authentication process + /// Enumeration that defines possible status for the authentication process /// public enum AuthenticationStatus { /// - /// Defaut status, when no authentication process has been performed + /// Defaut status, when no authentication process has been performed /// None, /// - /// Status when the authentication process is in progress + /// Status when the authentication process is in progress /// Authenticating, /// - /// Status when the authentication process ends succesfully + /// Status when the authentication process ends succesfully /// Success, /// - /// Status when the authentication process failed + /// Status when the authentication process failed /// - Fail + Fail, + + /// + /// Status when the server cannot be reached + /// + ServerFailure } } diff --git a/UI_DSM/UI_DSM.Client/Enumerator/UploadStatus.cs b/UI_DSM/UI_DSM.Client/Enumerator/UploadStatus.cs new file mode 100644 index 00000000..2f5fabb0 --- /dev/null +++ b/UI_DSM/UI_DSM.Client/Enumerator/UploadStatus.cs @@ -0,0 +1,41 @@ +// -------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2022 RHEA System S.A. +// +// Author: Antoine Théate, Sam Gerené, Alex Vorobiev, Alexander van Delft, Martin Risseeuw +// +// This file is part of UI-DSM. +// The UI-DSM web application is used to review an ECSS-E-TM-10-25 model. +// +// The UI-DSM application is provided to the community under the Apache License 2.0. +// +// -------------------------------------------------------------------------------------------------------- + +namespace UI_DSM.Client.Enumerator +{ + /// + /// Enumerator for the current status of an upload process + /// + public enum UploadStatus + { + /// + /// When the upload is not started + /// + None, + + /// + /// When the upload has been started + /// + Uploading, + + /// + /// When the upload is finished + /// + Done, + + /// + /// When the upload has failed + /// + Fail + } +} diff --git a/UI_DSM/UI_DSM.Client/Pages/Administration/ProjectPages/ProjectPage.razor b/UI_DSM/UI_DSM.Client/Pages/Administration/ProjectPages/ProjectPage.razor index 4b033cca..ae4ef99c 100644 --- a/UI_DSM/UI_DSM.Client/Pages/Administration/ProjectPages/ProjectPage.razor +++ b/UI_DSM/UI_DSM.Client/Pages/Administration/ProjectPages/ProjectPage.razor @@ -33,4 +33,14 @@ else +
+ + Add COMET Model + + + + + + +
} \ No newline at end of file diff --git a/UI_DSM/UI_DSM.Client/Pages/Administration/ProjectPages/ProjectPage.razor.cs b/UI_DSM/UI_DSM.Client/Pages/Administration/ProjectPages/ProjectPage.razor.cs index 59656229..c137cd37 100644 --- a/UI_DSM/UI_DSM.Client/Pages/Administration/ProjectPages/ProjectPage.razor.cs +++ b/UI_DSM/UI_DSM.Client/Pages/Administration/ProjectPages/ProjectPage.razor.cs @@ -48,6 +48,7 @@ public partial class ProjectPage : IDisposable public void Dispose() { this.disposables.ForEach(x => x.Dispose()); + this.disposables.Clear(); } /// @@ -65,6 +66,11 @@ protected override async Task OnInitializedAsync() this.disposables.Add(this.WhenAnyValue(x => x.ViewModel.IsOnCreationMode) .Subscribe(_ => this.InvokeAsync(this.StateHasChanged))); + this.disposables.Add(this.WhenAnyValue(x => x.ViewModel.IsOnCometConnectionMode) + .Subscribe(_ => this.InvokeAsync(this.StateHasChanged))); + + this.disposables.Add(this.ViewModel); + await this.ViewModel.OnInitializedAsync(new Guid(this.ProjectId)); } } diff --git a/UI_DSM/UI_DSM.Client/Program.cs b/UI_DSM/UI_DSM.Client/Program.cs index a5b1b43f..d39816ee 100644 --- a/UI_DSM/UI_DSM.Client/Program.cs +++ b/UI_DSM/UI_DSM.Client/Program.cs @@ -79,6 +79,7 @@ private static void AddViewModels(WebAssemblyHostBuilder builder) private static void AddServices(WebAssemblyHostBuilder builder) { builder.Services.AddScoped(); + builder.Services.AddScoped(); builder.Services.AddScoped(_ => new HttpClient { BaseAddress = new Uri(builder.Configuration["apiUri"]) }); diff --git a/UI_DSM/UI_DSM.Client/Services/Administration/CometService/CometService.cs b/UI_DSM/UI_DSM.Client/Services/Administration/CometService/CometService.cs new file mode 100644 index 00000000..56cd351d --- /dev/null +++ b/UI_DSM/UI_DSM.Client/Services/Administration/CometService/CometService.cs @@ -0,0 +1,106 @@ +// -------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2022 RHEA System S.A. +// +// Author: Antoine Théate, Sam Gerené, Alex Vorobiev, Alexander van Delft, Martin Risseeuw +// +// This file is part of UI-DSM. +// The UI-DSM web application is used to review an ECSS-E-TM-10-25 model. +// +// The UI-DSM application is provided to the community under the Apache License 2.0. +// +// -------------------------------------------------------------------------------------------------------- + +namespace UI_DSM.Client.Services.Administration.CometService +{ + using System.Text; + using System.Text.Json; + + using CDP4Common.EngineeringModelData; + using CDP4Common.SiteDirectoryData; + + using CDP4Dal; + + using Microsoft.AspNetCore.Components; + + using UI_DSM.Client.Services.JsonDeserializerProvider; + using UI_DSM.Shared.DTO.CometData; + + /// + /// The provide capabilities to interact with a Comet instance + /// + [Route("Comet")] + public class CometService : ServiceBase, ICometService + { + /// + /// Initializes a new instance of the class. + /// + /// The + /// The + public CometService(HttpClient httpClient, IJsonService jsonService) : base(httpClient, jsonService) + { + } + + /// + /// Tries to login to a Comet + /// + /// The + /// A with the result of the connection + public async Task Login(CometAuthenticationData authenticationData) + { + var content = JsonSerializer.Serialize(authenticationData); + var bodyContent = new StringContent(content, Encoding.UTF8, "application/json"); + var response = await this.HttpClient.PostAsync(Path.Combine(this.MainRoute, "Login"), bodyContent); + return this.jsonService.Deserialize(await response.Content.ReadAsStreamAsync()); + } + + /// + /// Closes the current + /// + /// The of the session + /// A + public async Task Logout(Guid sessionId) + { + var response = await this.HttpClient.DeleteAsync($"{this.MainRoute}/{sessionId}"); + return response.IsSuccessStatusCode; + } + + /// + /// Gets a collection of available + /// + /// The of the session + /// A with a + public async Task GetAvailableEngineeringModels(Guid sessionId) + { + var response = await this.HttpClient.GetAsync($"{this.MainRoute}/{sessionId}/Models"); + + if (!response.IsSuccessStatusCode) + { + throw new ArgumentException("Invalid session id"); + } + + return this.jsonService.Deserialize(await response.Content.ReadAsStreamAsync()); + } + + /// + /// Upload an to the server + /// + /// The of the session + /// The of the + /// The of the to upload + /// A with the + public async Task UploadIteration(Guid sessionId, Guid modelId, Guid iterationId) + { + var modelUpload = new ModelUploadData() + { + IterationId = iterationId, + ModelId = modelId + }; + + var content = JsonSerializer.Serialize(modelUpload); + var bodyContent = new StringContent(content, Encoding.UTF8, "application/json"); + var response = await this.HttpClient.PostAsync($"{this.MainRoute}/{sessionId}/Models/Upload", bodyContent); + return this.jsonService.Deserialize(await response.Content.ReadAsStreamAsync()); + } + } +} diff --git a/UI_DSM/UI_DSM.Client/Services/Administration/CometService/ICometService.cs b/UI_DSM/UI_DSM.Client/Services/Administration/CometService/ICometService.cs new file mode 100644 index 00000000..8ac82c4e --- /dev/null +++ b/UI_DSM/UI_DSM.Client/Services/Administration/CometService/ICometService.cs @@ -0,0 +1,58 @@ +// -------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2022 RHEA System S.A. +// +// Author: Antoine Théate, Sam Gerené, Alex Vorobiev, Alexander van Delft, Martin Risseeuw +// +// This file is part of UI-DSM. +// The UI-DSM web application is used to review an ECSS-E-TM-10-25 model. +// +// The UI-DSM application is provided to the community under the Apache License 2.0. +// +// -------------------------------------------------------------------------------------------------------- + +namespace UI_DSM.Client.Services.Administration.CometService +{ + using CDP4Common.EngineeringModelData; + using CDP4Common.SiteDirectoryData; + + using CDP4Dal; + + using UI_DSM.Shared.DTO.CometData; + + /// + /// Interface definition for + /// + public interface ICometService + { + /// + /// Tries to login to a Comet + /// + /// The + /// A with the result of the connection + Task Login(CometAuthenticationData authenticationData); + + /// + /// Closes the current + /// + /// The of the session + /// A + Task Logout(Guid sessionId); + + /// + /// Gets a collection of available + /// + /// The of the session + /// A with a + Task GetAvailableEngineeringModels(Guid sessionId); + + /// + /// Upload an to the server + /// + /// The of the session + /// The of the + /// The of the to upload + /// A with the + Task UploadIteration(Guid sessionId, Guid modelId, Guid iterationId); + } +} diff --git a/UI_DSM/UI_DSM.Client/Services/Administration/ParticipantService/ParticipantService.cs b/UI_DSM/UI_DSM.Client/Services/Administration/ParticipantService/ParticipantService.cs index 429cfbbd..2a05401f 100644 --- a/UI_DSM/UI_DSM.Client/Services/Administration/ParticipantService/ParticipantService.cs +++ b/UI_DSM/UI_DSM.Client/Services/Administration/ParticipantService/ParticipantService.cs @@ -33,8 +33,8 @@ public class ParticipantService : EntityServiceBase /// Initializes a new instance of the class. /// /// The - /// The - public ParticipantService(HttpClient httpClient, IJsonDeserializerService deserializer) : base(httpClient, deserializer) + /// The + public ParticipantService(HttpClient httpClient, IJsonService jsonService) : base(httpClient, jsonService) { } @@ -154,7 +154,7 @@ public async Task> GetAvailableUsersForCreation(Guid projectId) throw new HttpRequestException(await getResponse.Content.ReadAsStringAsync()); } - var dtos = this.Deserializer.Deserialize>(await getResponse.Content.ReadAsStreamAsync()); + var dtos = this.jsonService.Deserialize>(await getResponse.Content.ReadAsStreamAsync()); return Assembler.CreateEntities(dtos).ToList(); } catch (Exception exception) diff --git a/UI_DSM/UI_DSM.Client/Services/Administration/ProjectService/ProjectService.cs b/UI_DSM/UI_DSM.Client/Services/Administration/ProjectService/ProjectService.cs index c966b98b..dfa46f3d 100644 --- a/UI_DSM/UI_DSM.Client/Services/Administration/ProjectService/ProjectService.cs +++ b/UI_DSM/UI_DSM.Client/Services/Administration/ProjectService/ProjectService.cs @@ -32,8 +32,8 @@ public class ProjectService : EntityServiceBase, IProjectSe /// Initializes a new instance of the class. /// /// The - /// The - public ProjectService(HttpClient httpClient, IJsonDeserializerService deserializer) : base(httpClient,deserializer) + /// The + public ProjectService(HttpClient httpClient, IJsonService jsonService) : base(httpClient,jsonService) { } @@ -121,7 +121,7 @@ public async Task> GetUserParticipation() throw new HttpRequestException(await response.Content.ReadAsStringAsync()); } - var dtos = this.Deserializer.Deserialize>(await response.Content.ReadAsStreamAsync()); + var dtos = this.jsonService.Deserialize>(await response.Content.ReadAsStreamAsync()); return Assembler.CreateEntities(dtos).ToList(); } catch (Exception exception) diff --git a/UI_DSM/UI_DSM.Client/Services/Administration/RoleService/RoleService.cs b/UI_DSM/UI_DSM.Client/Services/Administration/RoleService/RoleService.cs index d2668a3f..7a875a4e 100644 --- a/UI_DSM/UI_DSM.Client/Services/Administration/RoleService/RoleService.cs +++ b/UI_DSM/UI_DSM.Client/Services/Administration/RoleService/RoleService.cs @@ -31,8 +31,8 @@ public class RoleService : EntityServiceBase, IRoleService /// Initializes a new instance of the class. /// /// The - /// The - public RoleService(HttpClient httpClient, IJsonDeserializerService deserializer) : base(httpClient, deserializer) + /// The + public RoleService(HttpClient httpClient, IJsonService jsonService) : base(httpClient, jsonService) { } diff --git a/UI_DSM/UI_DSM.Client/Services/Administration/UserService/UserService.cs b/UI_DSM/UI_DSM.Client/Services/Administration/UserService/UserService.cs index 9f428c7d..cc7b8261 100644 --- a/UI_DSM/UI_DSM.Client/Services/Administration/UserService/UserService.cs +++ b/UI_DSM/UI_DSM.Client/Services/Administration/UserService/UserService.cs @@ -34,8 +34,8 @@ public class UserService : ServiceBase, IUserService /// Initializes a new instance of the class. /// /// The - /// The - public UserService(HttpClient httpClient, IJsonDeserializerService deserializer) : base(httpClient, deserializer) + /// The + public UserService(HttpClient httpClient, IJsonService jsonService) : base(httpClient, jsonService) { } @@ -52,7 +52,7 @@ public async Task> GetUsers() throw new HttpRequestException(await response.Content.ReadAsStringAsync()); } - var entities = this.Deserializer.Deserialize>(await response.Content.ReadAsStreamAsync()); + var entities = this.jsonService.Deserialize>(await response.Content.ReadAsStreamAsync()); return entities.Where(x => x.GetType() == typeof(UserEntityDto)).Cast().ToList(); } @@ -67,7 +67,7 @@ public async Task RegisterUser(RegistrationDto newUser) var bodyContent = new StringContent(content, Encoding.UTF8, "application/json"); var registerResponse = await this.HttpClient.PostAsync(Path.Combine(this.MainRoute, "Register"), bodyContent); - return this.Deserializer.Deserialize(await registerResponse.Content.ReadAsStreamAsync()); + return this.jsonService.Deserialize(await registerResponse.Content.ReadAsStreamAsync()); } /// @@ -82,7 +82,7 @@ public async Task DeleteUser(UserEntityDto userEntityToDelet var url = Path.Combine(this.MainRoute, userEntityToDelete.Id.ToString()); var deleteResponse = await this.HttpClient.DeleteAsync(url); - return this.Deserializer.Deserialize(await deleteResponse.Content.ReadAsStreamAsync()); + return this.jsonService.Deserialize(await deleteResponse.Content.ReadAsStreamAsync()); } return new RequestResponseDto diff --git a/UI_DSM/UI_DSM.Client/Services/AnnotationService/AnnotationService.cs b/UI_DSM/UI_DSM.Client/Services/AnnotationService/AnnotationService.cs index 7fb74b70..ec993991 100644 --- a/UI_DSM/UI_DSM.Client/Services/AnnotationService/AnnotationService.cs +++ b/UI_DSM/UI_DSM.Client/Services/AnnotationService/AnnotationService.cs @@ -32,8 +32,8 @@ public class AnnotationService : EntityServiceBase, I /// Initializes a new instance of the class. /// /// The - /// The - public AnnotationService(HttpClient httpClient, IJsonDeserializerService deserializer) : base(httpClient, deserializer) + /// The + public AnnotationService(HttpClient httpClient, IJsonService jsonService) : base(httpClient, jsonService) { } diff --git a/UI_DSM/UI_DSM.Client/Services/ArtifactService/ArtifactService.cs b/UI_DSM/UI_DSM.Client/Services/ArtifactService/ArtifactService.cs new file mode 100644 index 00000000..ae99deb5 --- /dev/null +++ b/UI_DSM/UI_DSM.Client/Services/ArtifactService/ArtifactService.cs @@ -0,0 +1,77 @@ +// -------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2022 RHEA System S.A. +// +// Author: Antoine Théate, Sam Gerené, Alex Vorobiev, Alexander van Delft, Martin Risseeuw +// +// This file is part of UI-DSM. +// The UI-DSM web application is used to review an ECSS-E-TM-10-25 model. +// +// The UI-DSM application is provided to the community under the Apache License 2.0. +// +// -------------------------------------------------------------------------------------------------------- + +namespace UI_DSM.Client.Services.ArtifactService +{ + using Microsoft.AspNetCore.Components; + + using UI_DSM.Client.Services.JsonDeserializerProvider; + using UI_DSM.Shared.DTO.Models; + using UI_DSM.Shared.Models; + using UI_DSM.Shared.Types; + + /// + /// The provide capability to manage s inside a + /// + /// + [Route("Project/{0}/Artifact")] + public class ArtifactService : EntityServiceBase, IArtifactService + { + /// + /// Initializes a new instance of the class. + /// + /// The + /// The + public ArtifactService(HttpClient httpClient, IJsonService jsonService) : base(httpClient, jsonService) + { + } + + /// + /// Tries to upload a + /// + /// The of the where the will belongs + /// The file path + /// The name of the model + /// A with the + public Task> UploadModel(Guid projectId, string temporaryFileName, string modelName) + { + var model = new Model + { + FileName = temporaryFileName, + ModelName = modelName + }; + + return this.CreateArtifact(projectId, model); + } + + /// + /// Uploads a File into the server and creates the corresponding + /// + /// The of the where the will belongs to + /// The to create + /// A with the created result + private async Task> CreateArtifact(Guid projectId, TArtifact artifact) + where TArtifact : Artifact + { + this.ComputeMainRoute(projectId); + var createdArtifact = await this.CreateEntity(artifact, 0); + + return new EntityRequestResponse + { + IsRequestSuccessful = createdArtifact.IsRequestSuccessful, + Errors = createdArtifact.Errors, + Entity = (TArtifact)createdArtifact.Entity + }; + } + } +} diff --git a/UI_DSM/UI_DSM.Client/Services/ArtifactService/IArtifactService.cs b/UI_DSM/UI_DSM.Client/Services/ArtifactService/IArtifactService.cs new file mode 100644 index 00000000..de26c7da --- /dev/null +++ b/UI_DSM/UI_DSM.Client/Services/ArtifactService/IArtifactService.cs @@ -0,0 +1,33 @@ +// -------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2022 RHEA System S.A. +// +// Author: Antoine Théate, Sam Gerené, Alex Vorobiev, Alexander van Delft, Martin Risseeuw +// +// This file is part of UI-DSM. +// The UI-DSM web application is used to review an ECSS-E-TM-10-25 model. +// +// The UI-DSM application is provided to the community under the Apache License 2.0. +// +// -------------------------------------------------------------------------------------------------------- + +namespace UI_DSM.Client.Services.ArtifactService +{ + using UI_DSM.Shared.Models; + using UI_DSM.Shared.Types; + + /// + /// Interface definition for + /// + public interface IArtifactService + { + /// + /// Tries to upload a + /// + /// The of the where the will belongs + /// The file name + /// The name of the model + /// A with the result + Task> UploadModel(Guid projectId, string temporaryFileName, string modelName); + } +} diff --git a/UI_DSM/UI_DSM.Client/Services/AuthenticationService/AuthenticationService.cs b/UI_DSM/UI_DSM.Client/Services/AuthenticationService/AuthenticationService.cs index 652f5bbf..dc06b8bb 100644 --- a/UI_DSM/UI_DSM.Client/Services/AuthenticationService/AuthenticationService.cs +++ b/UI_DSM/UI_DSM.Client/Services/AuthenticationService/AuthenticationService.cs @@ -44,11 +44,11 @@ public class AuthenticationService : ServiceBase, IAuthenticationService /// Initializes a new instance of the class. /// The - /// The + /// The /// The /// The - public AuthenticationService(HttpClient httpClient, IJsonDeserializerService deserializer, AuthenticationStateProvider stateProvider, ISessionStorageService sessionStorageService) : - base(httpClient, deserializer) + public AuthenticationService(HttpClient httpClient, IJsonService jsonService, AuthenticationStateProvider stateProvider, ISessionStorageService sessionStorageService) : + base(httpClient, jsonService) { this.stateProvider = stateProvider; this.sessionStorageService = sessionStorageService; @@ -67,7 +67,7 @@ public async Task Login(AuthenticationDto authenticat var authenticationResult = await this.HttpClient.PostAsync(Path.Combine(this.MainRoute, "Login"), bodyContent); - var result = this.Deserializer.Deserialize(await authenticationResult.Content.ReadAsStreamAsync()); + var result = this.jsonService.Deserialize(await authenticationResult.Content.ReadAsStreamAsync()); if (!authenticationResult.IsSuccessStatusCode) { diff --git a/UI_DSM/UI_DSM.Client/Services/EntityServiceBase.cs b/UI_DSM/UI_DSM.Client/Services/EntityServiceBase.cs index 25c89152..76eeb10a 100644 --- a/UI_DSM/UI_DSM.Client/Services/EntityServiceBase.cs +++ b/UI_DSM/UI_DSM.Client/Services/EntityServiceBase.cs @@ -17,8 +17,6 @@ namespace UI_DSM.Client.Services using Microsoft.AspNetCore.WebUtilities; - using Newtonsoft.Json; - using UI_DSM.Client.Services.JsonDeserializerProvider; using UI_DSM.Shared.Assembler; using UI_DSM.Shared.DTO.Common; @@ -37,8 +35,8 @@ public abstract class EntityServiceBase : ServiceBase where /// Initializes a new instance of the class. /// /// The - /// The - protected EntityServiceBase(HttpClient httpClient, IJsonDeserializerService deserializer) : base(httpClient, deserializer) + /// The + protected EntityServiceBase(HttpClient httpClient, IJsonService jsonService) : base(httpClient, jsonService) { } @@ -54,7 +52,7 @@ protected async Task> GetEntityDto(Guid entityId, int dee return !getResponse.IsSuccessStatusCode ? default - : this.Deserializer.Deserialize>(await getResponse.Content.ReadAsStreamAsync()); + : this.jsonService.Deserialize>(await getResponse.Content.ReadAsStreamAsync()); } /// @@ -91,7 +89,7 @@ protected async Task> GetEntitiesDto(int deepLevel) throw new HttpRequestException(await response.Content.ReadAsStringAsync()); } - return this.Deserializer.Deserialize>(await response.Content.ReadAsStreamAsync()).ToList(); + return this.jsonService.Deserialize>(await response.Content.ReadAsStreamAsync()).ToList(); } /// @@ -114,10 +112,10 @@ protected async Task> GetEntities(int deepLevel) /// A with the protected async Task CreateEntityAndGetResponseDto(TEntity entity, int deepLevel) { - var content = JsonConvert.SerializeObject((TEntityDto)entity.ToDto()); + var content = this.jsonService.Serialize((TEntityDto)entity.ToDto()); var bodyContent = new StringContent(content, Encoding.UTF8, "application/json"); var response = await this.HttpClient.PostAsync(this.CreateUri(Path.Combine(this.MainRoute, "Create"), deepLevel), bodyContent); - return this.Deserializer.Deserialize(await response.Content.ReadAsStreamAsync()); + return this.jsonService.Deserialize(await response.Content.ReadAsStreamAsync()); } /// @@ -130,16 +128,37 @@ protected async Task> CreateEntity(TEntity entity { var entityRequest = await this.CreateEntityAndGetResponseDto(entity, deepLevel); + return HandleEntityRequestResponse(entityRequest); + } + + /// + /// Handles the result of the + /// + /// The + /// The + protected static EntityRequestResponse HandleEntityRequestResponse(EntityRequestResponseDto entityRequest) + { + return HandleEntityRequestResponse(entityRequest); + } + + /// + /// Handles the result of the + /// + /// The + /// An + /// The + protected static EntityRequestResponse HandleEntityRequestResponse(EntityRequestResponseDto entityRequest) where TTEntity : Entity + { if (!entityRequest!.IsRequestSuccessful) { - return EntityRequestResponse.Fail(entityRequest.Errors); + return EntityRequestResponse.Fail(entityRequest.Errors); } - var poco = Assembler.CreateEntities(entityRequest.Entities).FirstOrDefault(); + var poco = Assembler.CreateEntities(entityRequest.Entities).FirstOrDefault(); return poco == null - ? EntityRequestResponse.Fail(new List { "Error during the creation of the entity" }) - : EntityRequestResponse.Success(poco); + ? EntityRequestResponse.Fail(new List { "Error during the creation of the entity" }) + : EntityRequestResponse.Success(poco); } /// @@ -150,11 +169,11 @@ protected async Task> CreateEntity(TEntity entity /// A with the protected async Task UpdateEntityAndGetResponseDto(TEntity entity, int deepLevel) { - var content = JsonConvert.SerializeObject((TEntityDto)entity.ToDto()); + var content = this.jsonService.Serialize((TEntityDto)entity.ToDto()); var bodyContent = new StringContent(content, Encoding.UTF8, "application/json"); var response = await this.HttpClient.PutAsync(this.CreateUri(Path.Combine(this.MainRoute, entity.Id.ToString()), deepLevel), bodyContent); - return this.Deserializer.Deserialize(await response.Content.ReadAsStreamAsync()); + return this.jsonService.Deserialize(await response.Content.ReadAsStreamAsync()); } /// @@ -167,16 +186,7 @@ protected async Task> UpdateEntity(TEntity entity { var entityRequest = await this.UpdateEntityAndGetResponseDto(entity, deepLevel); - if (!entityRequest!.IsRequestSuccessful) - { - return EntityRequestResponse.Fail(entityRequest.Errors); - } - - var poco = Assembler.CreateEntities(entityRequest.Entities).FirstOrDefault(); - - return poco == null - ? EntityRequestResponse.Fail(new List { "Error during the creation of the entity" }) - : EntityRequestResponse.Success(poco); + return HandleEntityRequestResponse(entityRequest); } /// @@ -189,7 +199,7 @@ protected async Task DeleteEntity(TEntity entityToDelete) var url = Path.Combine(this.MainRoute, entityToDelete.Id.ToString()); var deleteResponse = await this.HttpClient.DeleteAsync(url); - var response = this.Deserializer.Deserialize(await deleteResponse.Content.ReadAsStreamAsync()); + var response = this.jsonService.Deserialize(await deleteResponse.Content.ReadAsStreamAsync()); if (response == null) { diff --git a/UI_DSM/UI_DSM.Client/Services/JsonDeserializerProvider/IJsonDeserializerService.cs b/UI_DSM/UI_DSM.Client/Services/JsonDeserializerProvider/IJsonService.cs similarity index 72% rename from UI_DSM/UI_DSM.Client/Services/JsonDeserializerProvider/IJsonDeserializerService.cs rename to UI_DSM/UI_DSM.Client/Services/JsonDeserializerProvider/IJsonService.cs index 62d2dc70..075d1366 100644 --- a/UI_DSM/UI_DSM.Client/Services/JsonDeserializerProvider/IJsonDeserializerService.cs +++ b/UI_DSM/UI_DSM.Client/Services/JsonDeserializerProvider/IJsonService.cs @@ -14,9 +14,9 @@ namespace UI_DSM.Client.Services.JsonDeserializerProvider { /// - /// Interface definition for + /// Interface definition for /// - public interface IJsonDeserializerService + public interface IJsonService { /// /// Deserialize a into a object @@ -25,5 +25,13 @@ public interface IJsonDeserializerService /// The to deserialize /// The object T Deserialize(Stream stream) where T : class; + + /// + /// Serialize a into a + /// + /// An object + /// The object to serialize + /// The serialized value + string Serialize(T value) where T : class; } } diff --git a/UI_DSM/UI_DSM.Client/Services/JsonDeserializerProvider/JsonDeserializerService.cs b/UI_DSM/UI_DSM.Client/Services/JsonDeserializerProvider/JsonService.cs similarity index 58% rename from UI_DSM/UI_DSM.Client/Services/JsonDeserializerProvider/JsonDeserializerService.cs rename to UI_DSM/UI_DSM.Client/Services/JsonDeserializerProvider/JsonService.cs index 9ea66436..52906b67 100644 --- a/UI_DSM/UI_DSM.Client/Services/JsonDeserializerProvider/JsonDeserializerService.cs +++ b/UI_DSM/UI_DSM.Client/Services/JsonDeserializerProvider/JsonService.cs @@ -24,7 +24,7 @@ namespace UI_DSM.Client.Services.JsonDeserializerProvider /// /// This service provides capabilities to detects the correct JSON deserializer depending on the type of the object /// - public class JsonDeserializerService : IJsonDeserializerService + public class JsonService : IJsonService { /// /// The to deserialize @@ -37,17 +37,34 @@ public class JsonDeserializerService : IJsonDeserializerService private readonly JsonSerializerOptions options; /// - /// Initializes a new instance of the class. + /// The + /// + private readonly IJsonSerializer serializer; + + /// + /// The + /// + private readonly JsonWriterOptions writerOptions; + + /// + /// Initializes a new instance of the class. /// /// The - public JsonDeserializerService(IJsonDeserializer deserializer) + /// The + public JsonService(IJsonDeserializer deserializer, IJsonSerializer serializer) { this.deserializer = deserializer; + this.serializer = serializer; this.options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true }; + + this.writerOptions = new JsonWriterOptions + { + Indented = true + }; } /// @@ -70,5 +87,36 @@ public T Deserialize(Stream stream) where T : class return JsonSerializer.Deserialize(stream, this.options); } + + /// + /// Serialize a into a + /// + /// An object + /// The object to serialize + /// The serialized value + public string Serialize(T value) where T : class + { + using var stream = new MemoryStream(); + + switch (value) + { + case EntityDto dto: + this.serializer.Serialize(dto, stream, this.writerOptions); + break; + case IEnumerable dtos: + this.serializer.Serialize(dtos, stream, this.writerOptions); + break; + case EntityRequestResponseDto requestDto: + this.serializer.SerializeEntityRequestDto(requestDto, stream, this.writerOptions); + break; + default: + JsonSerializer.Serialize(stream, value); + break; + } + + stream.Position = 0; + using var streamReader = new StreamReader(stream); + return streamReader.ReadToEnd(); + } } } diff --git a/UI_DSM/UI_DSM.Client/Services/ReplyService/ReplyService.cs b/UI_DSM/UI_DSM.Client/Services/ReplyService/ReplyService.cs index dea17b36..a6747285 100644 --- a/UI_DSM/UI_DSM.Client/Services/ReplyService/ReplyService.cs +++ b/UI_DSM/UI_DSM.Client/Services/ReplyService/ReplyService.cs @@ -32,8 +32,8 @@ public class ReplyService : EntityServiceBase, IReplyService /// Initializes a new instance of the class. /// /// The - /// The - public ReplyService(HttpClient httpClient, IJsonDeserializerService deserializer) : base(httpClient, deserializer) + /// The + public ReplyService(HttpClient httpClient, IJsonService jsonService) : base(httpClient, jsonService) { } diff --git a/UI_DSM/UI_DSM.Client/Services/ReviewObjectiveService/ReviewObjectiveService.cs b/UI_DSM/UI_DSM.Client/Services/ReviewObjectiveService/ReviewObjectiveService.cs index 2b7f0e53..e6d5dad7 100644 --- a/UI_DSM/UI_DSM.Client/Services/ReviewObjectiveService/ReviewObjectiveService.cs +++ b/UI_DSM/UI_DSM.Client/Services/ReviewObjectiveService/ReviewObjectiveService.cs @@ -31,8 +31,8 @@ public class ReviewObjectiveService : EntityServiceBase class. /// /// The - /// The - public ReviewObjectiveService(HttpClient httpClient, IJsonDeserializerService deserializer) : base(httpClient, deserializer) + /// The + public ReviewObjectiveService(HttpClient httpClient, IJsonService jsonService) : base(httpClient, jsonService) { } diff --git a/UI_DSM/UI_DSM.Client/Services/ReviewService/ReviewService.cs b/UI_DSM/UI_DSM.Client/Services/ReviewService/ReviewService.cs index d198021d..0aeab185 100644 --- a/UI_DSM/UI_DSM.Client/Services/ReviewService/ReviewService.cs +++ b/UI_DSM/UI_DSM.Client/Services/ReviewService/ReviewService.cs @@ -32,8 +32,8 @@ public class ReviewService : EntityServiceBase, IReviewServic /// Initializes a new instance of the class. /// /// The - /// The - public ReviewService(HttpClient httpClient, IJsonDeserializerService deserializer) : base(httpClient, deserializer) + /// The + public ReviewService(HttpClient httpClient, IJsonService jsonService) : base(httpClient, jsonService) { } diff --git a/UI_DSM/UI_DSM.Client/Services/ReviewTaskService/ReviewTaskService.cs b/UI_DSM/UI_DSM.Client/Services/ReviewTaskService/ReviewTaskService.cs index df72cb79..630d5379 100644 --- a/UI_DSM/UI_DSM.Client/Services/ReviewTaskService/ReviewTaskService.cs +++ b/UI_DSM/UI_DSM.Client/Services/ReviewTaskService/ReviewTaskService.cs @@ -31,8 +31,8 @@ public class ReviewTaskService : EntityServiceBase, I /// Initializes a new instance of the class. /// /// The - /// The - public ReviewTaskService(HttpClient httpClient, IJsonDeserializerService deserializer) : base(httpClient, deserializer) + /// The + public ReviewTaskService(HttpClient httpClient, IJsonService jsonService) : base(httpClient, jsonService) { } diff --git a/UI_DSM/UI_DSM.Client/Services/ServiceBase.cs b/UI_DSM/UI_DSM.Client/Services/ServiceBase.cs index bbb9f4b6..84d41ccf 100644 --- a/UI_DSM/UI_DSM.Client/Services/ServiceBase.cs +++ b/UI_DSM/UI_DSM.Client/Services/ServiceBase.cs @@ -28,20 +28,20 @@ public abstract class ServiceBase protected HttpClient HttpClient; /// - /// The + /// The /// - protected IJsonDeserializerService Deserializer { get; private set; } + protected IJsonService jsonService { get; private set; } /// /// Initializes a new instance of the class. /// /// The - /// The - protected ServiceBase(HttpClient httpClient, IJsonDeserializerService deserializer) + /// The + protected ServiceBase(HttpClient httpClient, IJsonService jsonService) { this.HttpClient = httpClient; this.MainRoute = this.GetRoute(); - this.Deserializer = deserializer; + this.jsonService = jsonService; } /// diff --git a/UI_DSM/UI_DSM.Client/UI_DSM.Client.csproj b/UI_DSM/UI_DSM.Client/UI_DSM.Client.csproj index 2b67d0ac..85888736 100644 --- a/UI_DSM/UI_DSM.Client/UI_DSM.Client.csproj +++ b/UI_DSM/UI_DSM.Client/UI_DSM.Client.csproj @@ -1,14 +1,13 @@  - net6.0 enable - 1.0.0 + 1.0.0 - - + + @@ -18,10 +17,8 @@ - - - + \ No newline at end of file diff --git a/UI_DSM/UI_DSM.Client/ViewModels/Components/Administration/ModelManagement/CometConnectionViewModel.cs b/UI_DSM/UI_DSM.Client/ViewModels/Components/Administration/ModelManagement/CometConnectionViewModel.cs new file mode 100644 index 00000000..cb3e1190 --- /dev/null +++ b/UI_DSM/UI_DSM.Client/ViewModels/Components/Administration/ModelManagement/CometConnectionViewModel.cs @@ -0,0 +1,263 @@ +// -------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2022 RHEA System S.A. +// +// Author: Antoine Théate, Sam Gerené, Alex Vorobiev, Alexander van Delft, Martin Risseeuw +// +// This file is part of UI-DSM. +// The UI-DSM web application is used to review an ECSS-E-TM-10-25 model. +// +// The UI-DSM application is provided to the community under the Apache License 2.0. +// +// -------------------------------------------------------------------------------------------------------- + +namespace UI_DSM.Client.ViewModels.Components.Administration.ModelManagement +{ + using System.ComponentModel.DataAnnotations; + + using CDP4Common.EngineeringModelData; + + using Microsoft.AspNetCore.Components; + + using ReactiveUI; + + using UI_DSM.Client.Components.Administration.ModelManagement; + using UI_DSM.Client.Enumerator; + using UI_DSM.Client.Services.Administration.CometService; + using UI_DSM.Shared.DTO.CometData; + using UI_DSM.Shared.DTO.Common; + + /// + /// View model for the component + /// + public class CometConnectionViewModel : ReactiveObject, ICometConnectionViewModel + { + /// + /// The + /// + private readonly ICometService cometService; + + /// + /// A collection of + /// + private readonly List disposables = new(); + + /// + /// that stores available models with frozen Iteration + /// + private Dictionary>> availableModels; + + /// + /// Backing field for + /// + private AuthenticationStatus cometConnectionStatus; + + /// + /// Backing field for + /// + private string errorMessage; + + /// + /// Backing field for + /// + private UploadStatus iterationUploadStatus; + + /// + /// Backing field for + /// + private Tuple selectedEngineeringModelSetup; + + /// + /// Backing field for + /// + private Tuple selectedIterationSetup; + + /// + /// The of the session with the API + /// + private Guid sessionId; + + /// + /// Initializes a new instance of the class. + /// + /// The + public CometConnectionViewModel(ICometService cometService) + { + this.cometService = cometService; + } + + /// + /// A collection of available + /// + public IEnumerable> AvailableEngineeringModels { get; set; } = new List>(); + + /// + /// A collection of available + /// + public IEnumerable> AvailableIterationsSetup { get; set; } = new List>(); + + /// + /// The currently selected + /// + public Tuple SelectedEngineeringModelSetup + { + get => this.selectedEngineeringModelSetup; + set => this.RaiseAndSetIfChanged(ref this.selectedEngineeringModelSetup, value); + } + + /// + /// The currently selected + /// + [Required] + public Tuple SelectedIterationSetup + { + get => this.selectedIterationSetup; + set => this.RaiseAndSetIfChanged(ref this.selectedIterationSetup, value); + } + + /// + /// Value indicating the current status of the COMET connection + /// + public AuthenticationStatus CometConnectionStatus + { + get => this.cometConnectionStatus; + set => this.RaiseAndSetIfChanged(ref this.cometConnectionStatus, value); + } + + /// + /// Value indicating the current status of the upload + /// + public UploadStatus IterationUploadStatus + { + get => this.iterationUploadStatus; + private set => this.RaiseAndSetIfChanged(ref this.iterationUploadStatus, value); + } + + /// + /// The error message + /// + public string ErrorMessage + { + get => this.errorMessage; + private set => this.RaiseAndSetIfChanged(ref this.errorMessage, value); + } + + /// + /// Gets the + /// + public CometAuthenticationData AuthenticationData { get; } = new(); + + /// + /// to be called after the has been set + /// + public EventCallback OnEventCallback { get; set; } + + /// + /// Tries to establish a connection to a Comet instance + /// + /// A + public async Task CometLogin() + { + this.CometConnectionStatus = AuthenticationStatus.Authenticating; + var response = await this.cometService.Login(this.AuthenticationData); + + if (response.IsRequestSuccessful) + { + this.sessionId = response.SessionId; + this.CometConnectionStatus = AuthenticationStatus.Success; + this.AuthenticationData.Password = string.Empty; + this.ErrorMessage = string.Empty; + var models = await this.cometService.GetAvailableEngineeringModels(this.sessionId); + this.availableModels = models.AvailableModels; + + this.AvailableEngineeringModels = models.ModelNames.Keys + .Select(modelName => new Tuple(modelName, models.ModelNames[modelName])).ToList(); + } + else + { + this.ErrorMessage = response.Errors.FirstOrDefault(); + this.CometConnectionStatus = AuthenticationStatus.Fail; + } + } + + /// + /// Closes the connection to the Comet Session + /// + /// A + public async Task CometLogout() + { + if (this.sessionId != Guid.Empty) + { + await this.cometService.Logout(this.sessionId); + } + + this.CometConnectionStatus = AuthenticationStatus.None; + } + + /// + /// Initializes the view model properties + /// + public void InitializeProperties() + { + this.CometConnectionStatus = AuthenticationStatus.None; + this.AuthenticationData.UserName = string.Empty; + this.AuthenticationData.Password = string.Empty; + this.ErrorMessage = string.Empty; + this.AuthenticationData.Url = string.Empty; + this.AvailableEngineeringModels = new List>(); + this.SelectedEngineeringModelSetup = null; + this.SelectedIterationSetup = null; + this.IterationUploadStatus = UploadStatus.None; + this.availableModels = new Dictionary>>(); + + this.disposables.Add(this.WhenAnyValue(x => x.SelectedEngineeringModelSetup) + .Subscribe(_ => this.UpdateAvailableIterationsSetup())); + } + + /// + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + /// + public void Dispose() + { + this.disposables.ForEach(x => x.Dispose()); + this.disposables.Clear(); + } + + /// + /// Uploads the selected + /// + /// A with the + public Task UploadSelectedIteration() + { + this.IterationUploadStatus = UploadStatus.Uploading; + return this.cometService.UploadIteration(this.sessionId, this.SelectedEngineeringModelSetup.Item1, this.SelectedIterationSetup.Item1); + } + + /// + /// Handle an upload failure + /// + /// The that contains information about the failure + public void HandleUploadFailure(RequestResponseDto response) + { + this.IterationUploadStatus = UploadStatus.Fail; + this.ErrorMessage = response.Errors.FirstOrDefault(); + } + + /// + /// Fills the collection + /// + private void UpdateAvailableIterationsSetup() + { + if (this.SelectedEngineeringModelSetup == null) + { + return; + } + + this.AvailableIterationsSetup = this.availableModels.TryGetValue(this.SelectedEngineeringModelSetup.Item1, out var iterations) + ? iterations + : new List>(); + + this.SelectedIterationSetup = this.AvailableIterationsSetup?.FirstOrDefault(); + } + } +} diff --git a/UI_DSM/UI_DSM.Client/ViewModels/Components/Administration/ModelManagement/ICometConnectionViewModel.cs b/UI_DSM/UI_DSM.Client/ViewModels/Components/Administration/ModelManagement/ICometConnectionViewModel.cs new file mode 100644 index 00000000..c7c5e004 --- /dev/null +++ b/UI_DSM/UI_DSM.Client/ViewModels/Components/Administration/ModelManagement/ICometConnectionViewModel.cs @@ -0,0 +1,104 @@ +// -------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2022 RHEA System S.A. +// +// Author: Antoine Théate, Sam Gerené, Alex Vorobiev, Alexander van Delft, Martin Risseeuw +// +// This file is part of UI-DSM. +// The UI-DSM web application is used to review an ECSS-E-TM-10-25 model. +// +// The UI-DSM application is provided to the community under the Apache License 2.0. +// +// -------------------------------------------------------------------------------------------------------- + +namespace UI_DSM.Client.ViewModels.Components.Administration.ModelManagement +{ + using CDP4Common.EngineeringModelData; + using CDP4Common.SiteDirectoryData; + + using Microsoft.AspNetCore.Components; + + using UI_DSM.Client.Enumerator; + using UI_DSM.Shared.DTO.CometData; + using UI_DSM.Shared.DTO.Common; + + /// + /// Interface definition for + /// + public interface ICometConnectionViewModel : IDisposable + { + /// + /// A collection of available + /// + IEnumerable> AvailableEngineeringModels { get; set; } + + /// + /// A collection of available + /// + IEnumerable> AvailableIterationsSetup { get; set; } + + /// + /// The currently selected + /// + Tuple SelectedEngineeringModelSetup { get; set; } + + /// + /// The currently selected + /// + Tuple SelectedIterationSetup { get; set; } + + /// + /// to invoke after selecting the + /// + EventCallback OnEventCallback { get; set; } + + /// + /// Value indicating the current status of the COMET connection + /// + AuthenticationStatus CometConnectionStatus { get; set; } + + /// + /// Value indicating the current status of the upload + /// + UploadStatus IterationUploadStatus { get; } + + /// + /// Gets the + /// + CometAuthenticationData AuthenticationData { get; } + + /// + /// The error message + /// + string ErrorMessage { get; } + + /// + /// Tries to establish a connection to a Comet instance + /// + /// A + Task CometLogin(); + + /// + /// Closes the connection to the Comet Session + /// + /// A + Task CometLogout(); + + /// + /// Initializes the view model properties + /// + void InitializeProperties(); + + /// + /// Creates an Annex C file for the provided iteration + /// + /// A with the + Task UploadSelectedIteration(); + + /// + /// Handle an upload failure + /// + /// The that contains information about the failure + void HandleUploadFailure(RequestResponseDto response); + } +} diff --git a/UI_DSM/UI_DSM.Client/ViewModels/Pages/Administration/ProjectPages/IProjectPageViewModel.cs b/UI_DSM/UI_DSM.Client/ViewModels/Pages/Administration/ProjectPages/IProjectPageViewModel.cs index 7148a01e..5977e273 100644 --- a/UI_DSM/UI_DSM.Client/ViewModels/Pages/Administration/ProjectPages/IProjectPageViewModel.cs +++ b/UI_DSM/UI_DSM.Client/ViewModels/Pages/Administration/ProjectPages/IProjectPageViewModel.cs @@ -13,9 +13,11 @@ namespace UI_DSM.Client.ViewModels.Pages.Administration.ProjectPages { + using UI_DSM.Client.Components.Administration.ModelManagement; using UI_DSM.Client.Components.Administration.ParticipantManagement; using UI_DSM.Client.Components.Administration.ProjectManagement; using UI_DSM.Client.ViewModels.Components; + using UI_DSM.Client.ViewModels.Components.Administration.ModelManagement; using UI_DSM.Client.ViewModels.Components.Administration.ParticipantManagement; using UI_DSM.Client.ViewModels.Components.Administration.ProjectManagement; using UI_DSM.Shared.Models; @@ -23,7 +25,7 @@ namespace UI_DSM.Client.ViewModels.Pages.Administration.ProjectPages /// /// Interface definition for /// - public interface IProjectPageViewModel + public interface IProjectPageViewModel : IDisposable { /// /// The for the component @@ -31,10 +33,15 @@ public interface IProjectPageViewModel IProjectDetailsViewModel ProjectDetailsViewModel { get; } /// - /// Value indicating the user is currently creating a new + /// Value indicating the user is currently creating a new /// bool IsOnCreationMode { get; set; } + /// + /// Value indicating whether the user is currently trying to establish a connection to COMET + /// + bool IsOnCometConnectionMode { get; set; } + /// /// Gets the /// @@ -45,6 +52,11 @@ public interface IProjectPageViewModel /// IParticipantCreationViewModel ParticipantCreationViewModel { get; } + /// + /// The for the component + /// + ICometConnectionViewModel CometConnectionViewModel { get; } + /// /// Method invoked when the component is ready to start, having received its /// initial parameters from its parent in the render tree. @@ -59,5 +71,10 @@ public interface IProjectPageViewModel /// Opens the popup /// Task OpenCreateParticipantPopup(); + + /// + /// Opens the popup + /// + void OpenCometConnectionPopup(); } } diff --git a/UI_DSM/UI_DSM.Client/ViewModels/Pages/Administration/ProjectPages/ProjectPageViewModel.cs b/UI_DSM/UI_DSM.Client/ViewModels/Pages/Administration/ProjectPages/ProjectPageViewModel.cs index 6b747517..b9efbf0e 100644 --- a/UI_DSM/UI_DSM.Client/ViewModels/Pages/Administration/ProjectPages/ProjectPageViewModel.cs +++ b/UI_DSM/UI_DSM.Client/ViewModels/Pages/Administration/ProjectPages/ProjectPageViewModel.cs @@ -13,7 +13,9 @@ namespace UI_DSM.Client.ViewModels.Pages.Administration.ProjectPages { - using DevExpress.Blazor; + using System.Reactive.Linq; + + using CDP4Common.EngineeringModelData; using DynamicData; @@ -21,13 +23,17 @@ namespace UI_DSM.Client.ViewModels.Pages.Administration.ProjectPages using ReactiveUI; + using UI_DSM.Client.Components.Administration.ModelManagement; using UI_DSM.Client.Components.Administration.ParticipantManagement; using UI_DSM.Client.Components.Administration.ProjectManagement; + using UI_DSM.Client.Enumerator; using UI_DSM.Client.Pages.Administration.ProjectPages; using UI_DSM.Client.Services.Administration.ParticipantService; using UI_DSM.Client.Services.Administration.ProjectService; using UI_DSM.Client.Services.Administration.RoleService; + using UI_DSM.Client.Services.ArtifactService; using UI_DSM.Client.ViewModels.Components; + using UI_DSM.Client.ViewModels.Components.Administration.ModelManagement; using UI_DSM.Client.ViewModels.Components.Administration.ParticipantManagement; using UI_DSM.Client.ViewModels.Components.Administration.ProjectManagement; using UI_DSM.Shared.Models; @@ -37,6 +43,16 @@ namespace UI_DSM.Client.ViewModels.Pages.Administration.ProjectPages /// public class ProjectPageViewModel : ReactiveObject, IProjectPageViewModel { + /// + /// The + /// + private readonly IArtifactService artifactService; + + /// + /// A collection of + /// + private readonly List disposables = new(); + /// /// The /// @@ -47,6 +63,11 @@ public class ProjectPageViewModel : ReactiveObject, IProjectPageViewModel /// private readonly IProjectService projectService; + /// + /// Backing field for + /// + private bool isOnCometConnectionMode; + /// /// Backing field for /// @@ -58,24 +79,42 @@ public class ProjectPageViewModel : ReactiveObject, IProjectPageViewModel /// The /// The /// The - public ProjectPageViewModel(IProjectService projectService, IParticipantService participantService, IRoleService roleService) + /// The + /// The + public ProjectPageViewModel(IProjectService projectService, IParticipantService participantService, IRoleService roleService, + ICometConnectionViewModel cometConnectionViewModel, IArtifactService artifactService) { this.projectService = projectService; this.participantService = participantService; + this.artifactService = artifactService; this.ParticipantCreationViewModel = new ParticipantCreationViewModel(this.participantService, roleService) { OnValidSubmit = new EventCallbackFactory().Create(this, this.CreateParticipant) }; + + this.CometConnectionViewModel = cometConnectionViewModel; + this.CometConnectionViewModel.OnEventCallback = new EventCallbackFactory().Create(this, _ => this.UploadIteration()); + + this.disposables.Add(this.WhenAnyValue(x => x.IsOnCometConnectionMode) + .Where(x => !x).Subscribe(async _ => await this.CometConnectionViewModel.CometLogout())); + + this.disposables.Add(this.WhenAnyValue(x => x.IsOnCometConnectionMode) + .Where(x => x).Subscribe(_ => this.CometConnectionViewModel.InitializeProperties())); } + /// + /// The for the component + /// + public ICometConnectionViewModel CometConnectionViewModel { get; } + /// /// The for the component /// public IProjectDetailsViewModel ProjectDetailsViewModel { get; } = new ProjectDetailsViewModel(); /// - /// Value indicating the user is currently creating a new + /// Value indicating the user is currently creating a new /// public bool IsOnCreationMode { @@ -83,6 +122,15 @@ public bool IsOnCreationMode set => this.RaiseAndSetIfChanged(ref this.isOnCreationMode, value); } + /// + /// Value indicating whether the user is currently trying to establish a connection to COMET + /// + public bool IsOnCometConnectionMode + { + get => this.isOnCometConnectionMode; + set => this.RaiseAndSetIfChanged(ref this.isOnCometConnectionMode, value); + } + /// /// Gets the /// @@ -117,7 +165,53 @@ public async Task OpenCreateParticipantPopup() } /// - /// Create a new with the provided data + /// Opens the popup + /// + public void OpenCometConnectionPopup() + { + this.IsOnCometConnectionMode = true; + } + + /// + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + /// + public void Dispose() + { + this.disposables.ForEach(x => x.Dispose()); + this.disposables.Clear(); + } + + /// + /// Uploads an to the server + /// + /// A + private async Task UploadIteration() + { + var uploadResponse = await this.CometConnectionViewModel.UploadSelectedIteration(); + + if (uploadResponse.IsRequestSuccessful) + { + var uploadModelResponse = await this.artifactService.UploadModel(this.ProjectDetailsViewModel.Project.Id, uploadResponse.UploadedFilePath, + $"{this.CometConnectionViewModel.SelectedEngineeringModelSetup.Item2} - {this.CometConnectionViewModel.SelectedIterationSetup.Item2}"); + + if (uploadModelResponse.IsRequestSuccessful) + { + this.ProjectDetailsViewModel.Project.Artifacts.Add(uploadModelResponse.Entity); + this.IsOnCometConnectionMode = false; + } + else + { + this.CometConnectionViewModel.HandleUploadFailure(uploadModelResponse); + } + } + else + { + this.CometConnectionViewModel.HandleUploadFailure(uploadResponse); + } + } + + /// + /// Create a new with the provided data /// /// A private async Task CreateParticipant() diff --git a/UI_DSM/UI_DSM.Client/_Imports.razor b/UI_DSM/UI_DSM.Client/_Imports.razor index 0afe514a..bda39225 100644 --- a/UI_DSM/UI_DSM.Client/_Imports.razor +++ b/UI_DSM/UI_DSM.Client/_Imports.razor @@ -13,6 +13,7 @@ @using UI_DSM.Client.Components.Administration.ProjectManagement @using UI_DSM.Client.Components.Administration.RoleManagement @using UI_DSM.Client.Components.Administration.ParticipantManagement +@using UI_DSM.Client.Components.Administration.ModelManagement @using DevExpress.Blazor @using Microsoft.AspNetCore.Authorization @using AppComponents diff --git a/UI_DSM/UI_DSM.CodeGenerator/Helpers/PropertyReflectionHelper.cs b/UI_DSM/UI_DSM.CodeGenerator/Helpers/PropertyReflectionHelper.cs index 870fc7b6..720365d2 100644 --- a/UI_DSM/UI_DSM.CodeGenerator/Helpers/PropertyReflectionHelper.cs +++ b/UI_DSM/UI_DSM.CodeGenerator/Helpers/PropertyReflectionHelper.cs @@ -21,6 +21,7 @@ namespace UI_DSM.CodeGenerator.Helpers using HandlebarsDotNet; using UI_DSM.CodeGenerator.Extensions; + using UI_DSM.Shared.Annotations; using UI_DSM.Shared.Models; /// @@ -113,6 +114,11 @@ public static void RegisterPropertyReflectionHelper(this IHandlebars handlebars) return propertyInfo.Name != nameof(UserEntity.UserId); } + if (propertyInfo.PropertyType.GetCorrectTypeToCheck().IsAssignableTo(typeof(Entity))) + { + return propertyInfo.GetCustomAttributes().Any(); + } + return true; }); diff --git a/UI_DSM/UI_DSM.CodeGenerator/Templates/dto-class-template.hbs b/UI_DSM/UI_DSM.CodeGenerator/Templates/dto-class-template.hbs index 6a03f755..c0780e1e 100644 --- a/UI_DSM/UI_DSM.CodeGenerator/Templates/dto-class-template.hbs +++ b/UI_DSM/UI_DSM.CodeGenerator/Templates/dto-class-template.hbs @@ -30,7 +30,9 @@ namespace UI_DSM.Shared.DTO.Models { {{#each (PropertyReflection.GetProperties this) as | property |}} {{#if (PropertyReflection.IsEnumerable property)}} + {{#if (PropertyReflection.IsSerialized property)}} this.{{ property.Name }} = new {{#PropertyReflection.GetPropertyType property}}(); + {{/if}} {{/if}} {{/each}} } @@ -40,7 +42,9 @@ namespace UI_DSM.Shared.DTO.Models { {{#each (PropertyReflection.GetProperties this) as | property |}} {{#if (PropertyReflection.IsEnumerable property)}} - this.{{ property.Name }} = new {{#PropertyReflection.GetPropertyType property}}(); + {{#if (PropertyReflection.IsSerialized property)}} + this.{{ property.Name }} = new {{#PropertyReflection.GetPropertyType property}}(); + {{/if}} {{/if}} {{/each}} } diff --git a/UI_DSM/UI_DSM.Serializer.Json.Tests/Data/sample.json b/UI_DSM/UI_DSM.Serializer.Json.Tests/Data/sample.json index 3f7da7e2..66860644 100644 --- a/UI_DSM/UI_DSM.Serializer.Json.Tests/Data/sample.json +++ b/UI_DSM/UI_DSM.Serializer.Json.Tests/Data/sample.json @@ -13,6 +13,9 @@ "bb5a4d0b-ee35-4d8a-8cb9-d471e6326abb", "a8b86b4f-3b2e-441f-a607-3090cfbb5359" ], + "artifacts": [ + "5aac9fe3-2659-47ba-88ba-d642b8d0c94b" + ], "id": "9417d7ea-ce53-4187-897f-f1a1cc2d104e" }, { @@ -117,5 +120,10 @@ "author": "3542293d-cdcd-4143-a546-436bc9d9a118", "isAssignedTo": "3542293d-cdcd-4143-a546-436bc9d9a118", "id": "d6fde0cd-fa4c-4897-a9ea-b81d90396595" + }, { + "@type": "ModelDto", + "modelName": "Envision - Iteration 1", + "fileName": "161A0A63-DFFE-4DFA-8A33-D80B31DEC9FE.zip", + "id": "5aac9fe3-2659-47ba-88ba-d642b8d0c94b" } ] diff --git a/UI_DSM/UI_DSM.Serializer.Json.Tests/JsonDeserializerTestFixture.cs b/UI_DSM/UI_DSM.Serializer.Json.Tests/JsonDeserializerTestFixture.cs index ff02b2d4..3ef6ab8f 100644 --- a/UI_DSM/UI_DSM.Serializer.Json.Tests/JsonDeserializerTestFixture.cs +++ b/UI_DSM/UI_DSM.Serializer.Json.Tests/JsonDeserializerTestFixture.cs @@ -38,7 +38,7 @@ public void VerifyDeserialize() Assert.Multiple(() => { - Assert.That(data, Has.Count.EqualTo(11)); + Assert.That(data, Has.Count.EqualTo(12)); Assert.That(data.OfType(), Is.Not.Empty); Assert.That(data.OfType().First().Id, Is.EqualTo(Guid.Parse("9417d7ea-ce53-4187-897f-f1a1cc2d104e"))); Assert.That(data.OfType().FirstOrDefault(x => x.Id == Guid.Parse("3542293d-cdcd-4143-a546-436bc9d9a118")), Is.Not.Null); diff --git a/UI_DSM/UI_DSM.Serializer.Json.Tests/JsonSerializerTestFixture.cs b/UI_DSM/UI_DSM.Serializer.Json.Tests/JsonSerializerTestFixture.cs index 8ea13397..1d7e96a8 100644 --- a/UI_DSM/UI_DSM.Serializer.Json.Tests/JsonSerializerTestFixture.cs +++ b/UI_DSM/UI_DSM.Serializer.Json.Tests/JsonSerializerTestFixture.cs @@ -130,17 +130,25 @@ public void VerifyCollectionSerialization() ReviewObjectives = new List{reviewObjective.Id} }; + var model = new ModelDto(Guid.NewGuid()) + { + FileName = "161A0A63-DFFE-4DFA-8A33-D80B31DEC9FE.zip", + ModelName = "Envision - Iteration 1" + }; + var project = new ProjectDto(Guid.NewGuid()) { ProjectName = "Project", Participants = new List{participant.Id}, Reviews = new List{review.Id}, - Annotations = new List{commentGuid, noteGuid, feedbackGuid} + Annotations = new List{commentGuid, noteGuid, feedbackGuid}, + Artifacts = new List{model.Id} }; var dtos = new List { - project, participant, user, role, reply, comment, feedback, note, review, reviewObjective, reviewTask + project, participant, user, role, reply, comment, feedback, note, review, reviewObjective, reviewTask, + model }; var stream = new MemoryStream(); diff --git a/UI_DSM/UI_DSM.Serializer.Json/AutoGenDtoDeserializer/DeserializationProvider.cs b/UI_DSM/UI_DSM.Serializer.Json/AutoGenDtoDeserializer/DeserializationProvider.cs index 9d3e0e98..24108bb5 100644 --- a/UI_DSM/UI_DSM.Serializer.Json/AutoGenDtoDeserializer/DeserializationProvider.cs +++ b/UI_DSM/UI_DSM.Serializer.Json/AutoGenDtoDeserializer/DeserializationProvider.cs @@ -32,6 +32,7 @@ internal static class DeserializationProvider { { "CommentDto", CommentDtoDeserializer.Deserialize }, { "FeedbackDto", FeedbackDtoDeserializer.Deserialize }, + { "ModelDto", ModelDtoDeserializer.Deserialize }, { "NoteDto", NoteDtoDeserializer.Deserialize }, { "ParticipantDto", ParticipantDtoDeserializer.Deserialize }, { "ProjectDto", ProjectDtoDeserializer.Deserialize }, diff --git a/UI_DSM/UI_DSM.Serializer.Json/AutoGenDtoDeserializer/ModelDtoDeserializer.cs b/UI_DSM/UI_DSM.Serializer.Json/AutoGenDtoDeserializer/ModelDtoDeserializer.cs new file mode 100644 index 00000000..ced84815 --- /dev/null +++ b/UI_DSM/UI_DSM.Serializer.Json/AutoGenDtoDeserializer/ModelDtoDeserializer.cs @@ -0,0 +1,77 @@ +// -------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2022 RHEA System S.A. +// +// Author: Antoine Théate, Sam Gerené, Alex Vorobiev, Alexander van Delft +// +// This file is part of UI-DSM. +// The UI-DSM web application is used to review an ECSS-E-TM-10-25 model. +// +// The UI-DSM application is provided to the community under the Apache License 2.0. +// +// -------------------------------------------------------------------------------------------------------- + +// -------------------------------------------------------------------------------------------------------- +// ------------THIS IS AN AUTOMATICALLY GENERATED FILE. ANY MANUAL CHANGES WILL BE OVERWRITTEN!------------ +// -------------------------------------------------------------------------------------------------------- + +namespace UI_DSM.Serializer.Json +{ + using System.Text.Json; + + using UI_DSM.Shared.DTO.Models; + + /// + /// The purpose of the is to provide deserialization capabilities + /// + internal static class ModelDtoDeserializer + { + /// + /// Deserializes an instance of using an + /// + /// The that contains the json object + /// An instance of + internal static ModelDto Deserialize(JsonElement jsonElement) + { + if (!jsonElement.TryGetProperty("@type", out var type)) + { + throw new InvalidOperationException("The @type property is not available, the ModelDtoDeSerializer cannot be used to deserialize this JsonElement"); + } + + if (type.GetString() != "ModelDto") + { + throw new InvalidOperationException($"The ModelDtoDeserializer can only be used to deserialize objects of type ModelDto, a {type.GetString()} was provided"); + } + + var dto = new ModelDto(); + + if (jsonElement.TryGetProperty("id", out var idProperty)) + { + var propertyValue = idProperty.GetString(); + + if (propertyValue == null) + { + throw new JsonException("The id property is not present, the ModelDto cannot be deserialized"); + } + + dto.Id = Guid.Parse(propertyValue); + } + + if (jsonElement.TryGetProperty("modelName", out var modelNameProperty)) + { + dto.ModelName = modelNameProperty.GetString(); + } + + if (jsonElement.TryGetProperty("fileName", out var fileNameProperty)) + { + dto.FileName = fileNameProperty.GetString(); + } + + return dto; + } + } +} + +// ------------------------------------------------------------------------------------------------ +// --------THIS IS AN AUTOMATICALLY GENERATED FILE. ANY MANUAL CHANGES WILL BE OVERWRITTEN!-------- +// ------------------------------------------------------------------------------------------------ \ No newline at end of file diff --git a/UI_DSM/UI_DSM.Serializer.Json/AutoGenDtoDeserializer/ProjectDtoDeserializer.cs b/UI_DSM/UI_DSM.Serializer.Json/AutoGenDtoDeserializer/ProjectDtoDeserializer.cs index d0b575ae..b2b2096c 100644 --- a/UI_DSM/UI_DSM.Serializer.Json/AutoGenDtoDeserializer/ProjectDtoDeserializer.cs +++ b/UI_DSM/UI_DSM.Serializer.Json/AutoGenDtoDeserializer/ProjectDtoDeserializer.cs @@ -101,6 +101,19 @@ internal static ProjectDto Deserialize(JsonElement jsonElement) } } + if (jsonElement.TryGetProperty("artifacts", out var artifactsProperty)) + { + foreach (var item in artifactsProperty.EnumerateArray()) + { + var propertyValue = item.GetString(); + + if (propertyValue != null) + { + dto.Artifacts.Add(Guid.Parse(propertyValue)); + } + } + } + return dto; } } diff --git a/UI_DSM/UI_DSM.Serializer.Json/AutoGenDtoDeserializer/ReviewDtoDeserializer.cs b/UI_DSM/UI_DSM.Serializer.Json/AutoGenDtoDeserializer/ReviewDtoDeserializer.cs index 6b9b22b8..0dfaffe8 100644 --- a/UI_DSM/UI_DSM.Serializer.Json/AutoGenDtoDeserializer/ReviewDtoDeserializer.cs +++ b/UI_DSM/UI_DSM.Serializer.Json/AutoGenDtoDeserializer/ReviewDtoDeserializer.cs @@ -115,6 +115,19 @@ internal static ReviewDto Deserialize(JsonElement jsonElement) } } + if (jsonElement.TryGetProperty("artifacts", out var artifactsProperty)) + { + foreach (var item in artifactsProperty.EnumerateArray()) + { + var propertyValue = item.GetString(); + + if (propertyValue != null) + { + dto.Artifacts.Add(Guid.Parse(propertyValue)); + } + } + } + return dto; } } diff --git a/UI_DSM/UI_DSM.Serializer.Json/AutoGenDtoSerializer/ModelDtoSerializer.cs b/UI_DSM/UI_DSM.Serializer.Json/AutoGenDtoSerializer/ModelDtoSerializer.cs new file mode 100644 index 00000000..b53e54b5 --- /dev/null +++ b/UI_DSM/UI_DSM.Serializer.Json/AutoGenDtoSerializer/ModelDtoSerializer.cs @@ -0,0 +1,62 @@ +// -------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2022 RHEA System S.A. +// +// Author: Antoine Théate, Sam Gerené, Alex Vorobiev, Alexander van Delft +// +// This file is part of UI-DSM. +// The UI-DSM web application is used to review an ECSS-E-TM-10-25 model. +// +// The UI-DSM application is provided to the community under the Apache License 2.0. +// +// -------------------------------------------------------------------------------------------------------- + +// -------------------------------------------------------------------------------------------------------- +// ------------THIS IS AN AUTOMATICALLY GENERATED FILE. ANY MANUAL CHANGES WILL BE OVERWRITTEN!------------ +// -------------------------------------------------------------------------------------------------------- + +namespace UI_DSM.Serializer.Json +{ + using System.Text.Json; + + using UI_DSM.Shared.DTO.Models; + + /// + /// The purpose of the is to provide serialization capabilities + /// + internal static class ModelDtoSerializer + { + /// + /// Serializes an instance of using an + /// + /// The to serialize + /// The target + internal static void Serialize(object obj, Utf8JsonWriter writer) + { + if (obj is not ModelDto dto) + { + throw new ArgumentException("The object shall be an ModelDto", nameof(obj)); + } + + writer.WriteStartObject(); + + writer.WritePropertyName("@type"); + writer.WriteStringValue("ModelDto"); + + writer.WritePropertyName("modelName"); + writer.WriteStringValue(dto.ModelName); + + writer.WritePropertyName("fileName"); + writer.WriteStringValue(dto.FileName); + + writer.WritePropertyName("id"); + writer.WriteStringValue(dto.Id); + + writer.WriteEndObject(); + } + } +} + +// ------------------------------------------------------------------------------------------------ +// --------THIS IS AN AUTOMATICALLY GENERATED FILE. ANY MANUAL CHANGES WILL BE OVERWRITTEN!-------- +// ------------------------------------------------------------------------------------------------ \ No newline at end of file diff --git a/UI_DSM/UI_DSM.Serializer.Json/AutoGenDtoSerializer/ProjectDtoSerializer.cs b/UI_DSM/UI_DSM.Serializer.Json/AutoGenDtoSerializer/ProjectDtoSerializer.cs index 32b81dbb..efc2c530 100644 --- a/UI_DSM/UI_DSM.Serializer.Json/AutoGenDtoSerializer/ProjectDtoSerializer.cs +++ b/UI_DSM/UI_DSM.Serializer.Json/AutoGenDtoSerializer/ProjectDtoSerializer.cs @@ -73,6 +73,15 @@ internal static void Serialize(object obj, Utf8JsonWriter writer) writer.WriteEndArray(); + writer.WriteStartArray("artifacts"); + + foreach (var item in dto.Artifacts) + { + writer.WriteStringValue(item); + } + + writer.WriteEndArray(); + writer.WritePropertyName("id"); writer.WriteStringValue(dto.Id); diff --git a/UI_DSM/UI_DSM.Serializer.Json/AutoGenDtoSerializer/ReviewDtoSerializer.cs b/UI_DSM/UI_DSM.Serializer.Json/AutoGenDtoSerializer/ReviewDtoSerializer.cs index b8335f6a..6c883c07 100644 --- a/UI_DSM/UI_DSM.Serializer.Json/AutoGenDtoSerializer/ReviewDtoSerializer.cs +++ b/UI_DSM/UI_DSM.Serializer.Json/AutoGenDtoSerializer/ReviewDtoSerializer.cs @@ -70,6 +70,15 @@ internal static void Serialize(object obj, Utf8JsonWriter writer) writer.WriteEndArray(); + writer.WriteStartArray("artifacts"); + + foreach (var item in dto.Artifacts) + { + writer.WriteStringValue(item); + } + + writer.WriteEndArray(); + writer.WritePropertyName("id"); writer.WriteStringValue(dto.Id); diff --git a/UI_DSM/UI_DSM.Serializer.Json/AutoGenDtoSerializer/SerializationProvider.cs b/UI_DSM/UI_DSM.Serializer.Json/AutoGenDtoSerializer/SerializationProvider.cs index 6b4b88ea..22cbb28b 100644 --- a/UI_DSM/UI_DSM.Serializer.Json/AutoGenDtoSerializer/SerializationProvider.cs +++ b/UI_DSM/UI_DSM.Serializer.Json/AutoGenDtoSerializer/SerializationProvider.cs @@ -32,6 +32,7 @@ internal static class SerializationProvider { { typeof(CommentDto), CommentDtoSerializer.Serialize }, { typeof(FeedbackDto), FeedbackDtoSerializer.Serialize }, + { typeof(ModelDto), ModelDtoSerializer.Serialize }, { typeof(NoteDto), NoteDtoSerializer.Serialize }, { typeof(ParticipantDto), ParticipantDtoSerializer.Serialize }, { typeof(ProjectDto), ProjectDtoSerializer.Serialize }, diff --git a/UI_DSM/UI_DSM.Serializer.Json/UI_DSM.Serializer.Json.csproj b/UI_DSM/UI_DSM.Serializer.Json/UI_DSM.Serializer.Json.csproj index affe0cb9..2d0bda45 100644 --- a/UI_DSM/UI_DSM.Serializer.Json/UI_DSM.Serializer.Json.csproj +++ b/UI_DSM/UI_DSM.Serializer.Json/UI_DSM.Serializer.Json.csproj @@ -1,4 +1,4 @@ - + net6.0 diff --git a/UI_DSM/UI_DSM.Server.Tests/Data/26699a14-79d0-4f10-bcf1-15979ef3968f.zip b/UI_DSM/UI_DSM.Server.Tests/Data/26699a14-79d0-4f10-bcf1-15979ef3968f.zip new file mode 100644 index 00000000..daa2a6a6 Binary files /dev/null and b/UI_DSM/UI_DSM.Server.Tests/Data/26699a14-79d0-4f10-bcf1-15979ef3968f.zip differ diff --git a/UI_DSM/UI_DSM.Server.Tests/Helpers/ModuleTestHelper.cs b/UI_DSM/UI_DSM.Server.Tests/Helpers/ModuleTestHelper.cs index ce6a46db..c8f3cb3b 100644 --- a/UI_DSM/UI_DSM.Server.Tests/Helpers/ModuleTestHelper.cs +++ b/UI_DSM/UI_DSM.Server.Tests/Helpers/ModuleTestHelper.cs @@ -41,7 +41,7 @@ public static class ModuleTestHelper /// The /// The public static void Setup(AbstractValidator validator, out Mock context, - out Mock response, out Mock request, out Mock serviceProvider) where TModule : ModuleBase, new() where TDto : EntityDto + out Mock response, out Mock request, out Mock serviceProvider) where TModule : ModuleBase where TDto : class { response = new Mock(); response.SetupSet(response => response.StatusCode = It.IsAny()).Verifiable(); diff --git a/UI_DSM/UI_DSM.Server.Tests/Managers/ArtifactManagerTestFixture.cs b/UI_DSM/UI_DSM.Server.Tests/Managers/ArtifactManagerTestFixture.cs new file mode 100644 index 00000000..7a305f95 --- /dev/null +++ b/UI_DSM/UI_DSM.Server.Tests/Managers/ArtifactManagerTestFixture.cs @@ -0,0 +1,174 @@ +// -------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2022 RHEA System S.A. +// +// Author: Antoine Théate, Sam Gerené, Alex Vorobiev, Alexander van Delft, Martin Risseeuw, Nabil Abbar +// +// This file is part of UI-DSM. +// The UI-DSM web application is used to review an ECSS-E-TM-10-25 model. +// +// The UI-DSM application is provided to the community under the Apache License 2.0. +// +// -------------------------------------------------------------------------------------------------------- + +namespace UI_DSM.Server.Tests.Managers +{ + using System.Diagnostics.CodeAnalysis; + + using Moq; + + using NUnit.Framework; + + using UI_DSM.Server.Managers.ArtifactManager; + using UI_DSM.Server.Managers.ModelManager; + using UI_DSM.Server.Types; + using UI_DSM.Shared.DTO.Models; + using UI_DSM.Shared.Models; + + [TestFixture] + public class ArtifactManagerTestFixture + { + private ArtifactManager manager; + private Mock modelManager; + + [SetUp] + public void Setup() + { + this.modelManager = new Mock(); + this.manager = new ArtifactManager(this.modelManager.Object); + } + + [Test] + public async Task VerifyGetEntities() + { + var models = new List + { + new(Guid.NewGuid()) + { + FileName = "AFileName.zip", + ModelName = "Envision - Iteration 1" + }, + new(Guid.NewGuid()) + { + FileName = "AFileName2.zip", + ModelName = "Envision - Iteration 2" + } + }; + + var project = new Project(Guid.NewGuid()); + project.Artifacts.Add(models.First()); + + var project2 = new Project(Guid.NewGuid()); + project2.Artifacts.Add(models.Last()); + + this.modelManager.Setup(x => x.GetEntities(0)) + .ReturnsAsync(models.SelectMany(x => x.GetAssociatedEntities()).DistinctBy(x => x.Id)); + + var entities = await this.manager.GetEntities(); + Assert.That(entities.ToList(), Has.Count.EqualTo(2)); + + foreach (var model in models) + { + this.modelManager.Setup(x => x.FindEntity(model.Id)).ReturnsAsync(model); + this.modelManager.Setup(x => x.FindEntityWithContainer(model.Id)).ReturnsAsync(model); + } + + entities = await this.manager.GetEntity(Guid.NewGuid()); + Assert.That(entities, Is.Empty); + + var foundEntities = await this.manager.FindEntities(new List + { + models.First().Id, + Guid.NewGuid() + }); + + Assert.That(foundEntities.ToList(), Has.Count.EqualTo(1)); + + var entity = await this.manager.FindEntityWithContainer(models.First().Id); + + Assert.Multiple(async () => + { + Assert.That(entity, Is.Not.Null); + Assert.That(await this.manager.EntityIsContainedBy(models.First().Id, Guid.NewGuid()), Is.False); + Assert.That(await this.manager.EntityIsContainedBy(models.Last().Id, Guid.NewGuid()), Is.False); + Assert.That(await this.manager.EntityIsContainedBy(models.First().Id, project.Id), Is.True); + }); + + this.modelManager.Setup(x => x.GetContainedEntities(project.Id,0)) + .ReturnsAsync(new List + { + models.First() + }); + + Assert.That(await this.manager.GetContainedEntities(project.Id), Is.Not.Empty); + } + + [Test] + public async Task VerifyCreateEntity() + { + var artifact = new Model(); + this.modelManager.Setup(x => x.CreateEntity(artifact)).ReturnsAsync(EntityOperationResult.Failed()); + Assert.That((await this.manager.CreateEntity(artifact)).Succeeded, Is.False); + + this.modelManager.Setup(x => x.CreateEntity(artifact)).ReturnsAsync(EntityOperationResult.Success(artifact)); + Assert.That((await this.manager.CreateEntity(artifact)).Succeeded, Is.True); + + var invalidArtifact = new InvalidArtifact(); + Assert.That((await this.manager.CreateEntity(invalidArtifact)).Succeeded, Is.False); + } + + [Test] + public async Task VerifyUpdateEntity() + { + var artifact = new Model(); + this.modelManager.Setup(x => x.UpdateEntity(artifact)).ReturnsAsync(EntityOperationResult.Failed()); + Assert.That((await this.manager.UpdateEntity(artifact)).Succeeded, Is.False); + + this.modelManager.Setup(x => x.UpdateEntity(artifact)).ReturnsAsync(EntityOperationResult.Success(artifact)); + Assert.That((await this.manager.UpdateEntity(artifact)).Succeeded, Is.True); + + var invalidArtifact = new InvalidArtifact(); + Assert.That((await this.manager.UpdateEntity(invalidArtifact)).Succeeded, Is.False); + } + + [Test] + public async Task VerifyDeleteEntity() + { + var artifact = new Model(); + this.modelManager.Setup(x => x.DeleteEntity(artifact)).ReturnsAsync(EntityOperationResult.Failed()); + Assert.That((await this.manager.DeleteEntity(artifact)).Succeeded, Is.False); + + this.modelManager.Setup(x => x.DeleteEntity(artifact)).ReturnsAsync(EntityOperationResult.Success(artifact)); + Assert.That((await this.manager.DeleteEntity(artifact)).Succeeded, Is.True); + + var invalidArtifact = new InvalidArtifact(); + Assert.That((await this.manager.DeleteEntity(invalidArtifact)).Succeeded, Is.False); + } + + [Test] + public async Task VerifyResolveProperties() + { + var artifact = new Model(); + var dto = new ModelDto(); + var invalidArtifact = new InvalidArtifact(); + + await this.manager.ResolveProperties(artifact, dto); + await this.manager.ResolveProperties(invalidArtifact, dto); + + this.modelManager.Verify(x => x.ResolveProperties(artifact, dto), Times.Once); + } + } + + [ExcludeFromCodeCoverage] + internal class InvalidArtifact : Artifact + { + /// + /// Instantiate a from a + /// + /// A new + public override EntityDto ToDto() + { + return null; + } + } +} diff --git a/UI_DSM/UI_DSM.Server.Tests/Managers/ModelManagerTestFixture.cs b/UI_DSM/UI_DSM.Server.Tests/Managers/ModelManagerTestFixture.cs new file mode 100644 index 00000000..65ce6b46 --- /dev/null +++ b/UI_DSM/UI_DSM.Server.Tests/Managers/ModelManagerTestFixture.cs @@ -0,0 +1,157 @@ +// -------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2022 RHEA System S.A. +// +// Author: Antoine Théate, Sam Gerené, Alex Vorobiev, Alexander van Delft, Martin Risseeuw, Nabil Abbar +// +// This file is part of UI-DSM. +// The UI-DSM web application is used to review an ECSS-E-TM-10-25 model. +// +// The UI-DSM application is provided to the community under the Apache License 2.0. +// +// -------------------------------------------------------------------------------------------------------- + +namespace UI_DSM.Server.Tests.Managers +{ + using Moq; + + using NUnit.Framework; + + using UI_DSM.Server.Context; + using UI_DSM.Server.Managers.ModelManager; + using UI_DSM.Server.Tests.Helpers; + using UI_DSM.Shared.DTO.Models; + using UI_DSM.Shared.Models; + + [TestFixture] + public class ModelManagerTestFixture + { + private ModelManager manager; + private Mock context; + + [SetUp] + public void Setup() + { + this.context = new Mock(); + + this.manager = new ModelManager(this.context.Object); + } + + [Test] + public async Task VerifyGetEntities() + { + var models = new List + { + new(Guid.NewGuid()) + { + FileName = "AFileName.zip", + ModelName = "Envision - Iteration 1" + }, + new(Guid.NewGuid()) + { + FileName = "AFileName2.zip", + ModelName = "Envision - Iteration 2" + } + }; + + var dbSet = DbSetMockHelper.CreateMock(models); + this.context.Setup(x => x.Models).Returns(dbSet.Object); + + foreach (var model in models) + { + dbSet.Setup(x => x.FindAsync(model.Id)).ReturnsAsync(model); + } + + var allEntities = await this.manager.GetEntities(1); + Assert.That(allEntities.ToList(), Has.Count.EqualTo(2)); + + var invalidGuid = Guid.NewGuid(); + dbSet.Setup(x => x.FindAsync(invalidGuid)).ReturnsAsync((Model)null); + var foundReview = await this.manager.FindEntity(invalidGuid); + Assert.That(foundReview, Is.Null); + + var foundEntities = await this.manager.FindEntities(models.Select(x => x.Id)); + Assert.That(foundEntities.ToList(), Has.Count.EqualTo(2)); + + var deepEntity = await this.manager.GetEntity(models.First().Id, 1); + Assert.That(deepEntity.ToList(), Has.Count.EqualTo(1)); + + var project = new Project(Guid.NewGuid()) + { + Artifacts = { models.First() } + }; + + var containedEntities = await this.manager.GetContainedEntities(project.Id); + Assert.That(containedEntities.ToList(), Has.Count.EqualTo(1)); + } + + [Test] + public async Task VerifyCreateEntity() + { + var model = new Model() + { + FileName = "filename.zip", + ModelName = "Envision - Iteration 1" + }; + + var operationResult = await this.manager.CreateEntity(model); + Assert.That(operationResult.Succeeded, Is.False); + + var projects = new List() + { + new(Guid.NewGuid()) + { + Artifacts = + { + model + } + } + }; + + var projectDbSet = DbSetMockHelper.CreateMock(projects); + this.context.Setup(x => x.Projects).Returns(projectDbSet.Object); + projectDbSet.Setup(x => x.FindAsync(projects.First().Id)).ReturnsAsync(projects.First()); + + await this.manager.CreateEntity(model); + this.context.Verify(x => x.Add(model), Times.Once); + + this.context.Setup(x => x.SaveChangesAsync(default)).ThrowsAsync(new InvalidOperationException()); + operationResult = await this.manager.CreateEntity(model); + Assert.That(operationResult.Succeeded, Is.False); + } + + [Test] + public async Task VerifyUpdateAndDelete() + { + var model = new Model(Guid.NewGuid()) + { + FileName = "filename.zip", + ModelName = "Envision - Iteration 1" + }; + + var operationResult = await this.manager.DeleteEntity(model); + Assert.That(operationResult.Succeeded, Is.False); + + operationResult = await this.manager.UpdateEntity(model); + Assert.That(operationResult.Succeeded, Is.False); + } + + [Test] + public async Task VerifyUpdateProperties() + { + var model = new Model(); + var dto = new ReviewDto() as EntityDto; + + Assert.That(async () => await this.manager.ResolveProperties(model, dto), Throws.Nothing); + + dto = new ModelDto() + { + FileName = "file.zip", + ModelName = "model name" + }; + + await this.manager.ResolveProperties(model, dto); + Assert.That(model.ModelName, Is.EqualTo(((ModelDto)dto).ModelName)); + } + } +} diff --git a/UI_DSM/UI_DSM.Server.Tests/Managers/ProjectManagerTestFixture.cs b/UI_DSM/UI_DSM.Server.Tests/Managers/ProjectManagerTestFixture.cs index c2a620c5..fe7288bc 100644 --- a/UI_DSM/UI_DSM.Server.Tests/Managers/ProjectManagerTestFixture.cs +++ b/UI_DSM/UI_DSM.Server.Tests/Managers/ProjectManagerTestFixture.cs @@ -21,6 +21,7 @@ namespace UI_DSM.Server.Tests.Managers using UI_DSM.Server.Context; using UI_DSM.Server.Managers.AnnotationManager; + using UI_DSM.Server.Managers.ArtifactManager; using UI_DSM.Server.Managers.ParticipantManager; using UI_DSM.Server.Managers.ProjectManager; using UI_DSM.Server.Managers.ReviewManager; @@ -35,6 +36,7 @@ public class ProjectManagerTestFixture private Mock participantManager; private Mock reviewManager; private Mock annotationManager; + private Mock artifactManager; [SetUp] public void Setup() @@ -43,7 +45,9 @@ public void Setup() this.participantManager = new Mock(); this.reviewManager = new Mock(); this.annotationManager = new Mock(); - this.manager = new ProjectManager(this.context.Object, this.participantManager.Object, this.reviewManager.Object, this.annotationManager.Object); + this.artifactManager = new Mock(); + this.manager = new ProjectManager(this.context.Object, this.participantManager.Object, this.reviewManager.Object, + this.annotationManager.Object, this.artifactManager.Object); } [Test] diff --git a/UI_DSM/UI_DSM.Server.Tests/Managers/ReviewManagerTestFixture.cs b/UI_DSM/UI_DSM.Server.Tests/Managers/ReviewManagerTestFixture.cs index d340174d..20f64a59 100644 --- a/UI_DSM/UI_DSM.Server.Tests/Managers/ReviewManagerTestFixture.cs +++ b/UI_DSM/UI_DSM.Server.Tests/Managers/ReviewManagerTestFixture.cs @@ -18,6 +18,7 @@ namespace UI_DSM.Server.Tests.Managers using NUnit.Framework; using UI_DSM.Server.Context; + using UI_DSM.Server.Managers.ArtifactManager; using UI_DSM.Server.Managers.ParticipantManager; using UI_DSM.Server.Managers.ReviewManager; using UI_DSM.Server.Managers.ReviewObjectiveManager; @@ -33,6 +34,7 @@ public class ReviewManagerTestFixture private Mock context; private Mock participantManager; private Mock reviewObjectiveManager; + private Mock artifactManager; [SetUp] public void Setup() @@ -40,7 +42,10 @@ public void Setup() this.context = new Mock(); this.participantManager = new Mock(); this.reviewObjectiveManager = new Mock(); - this.manager = new ReviewManager(this.context.Object, this.participantManager.Object, this.reviewObjectiveManager.Object); + this.artifactManager = new Mock(); + + this.manager = new ReviewManager(this.context.Object, this.participantManager.Object, this.reviewObjectiveManager.Object, + this.artifactManager.Object); } [Test] diff --git a/UI_DSM/UI_DSM.Server.Tests/Modules/AnnotationModuleTestFixture.cs b/UI_DSM/UI_DSM.Server.Tests/Modules/AnnotationModuleTestFixture.cs index acbcbdce..fb07ddd2 100644 --- a/UI_DSM/UI_DSM.Server.Tests/Modules/AnnotationModuleTestFixture.cs +++ b/UI_DSM/UI_DSM.Server.Tests/Modules/AnnotationModuleTestFixture.cs @@ -135,11 +135,15 @@ public async Task VerifyGetEntity() this.participantManager.Setup(x => x.GetParticipantForProject(It.IsAny(), "user")).ReturnsAsync(this.participant); - this.annotationManager.Setup(x => x.FindEntity(annotation.Id)).ReturnsAsync((Annotation)null); + this.annotationManager.As>() + .Setup(x => x.FindEntityWithContainer(annotation.Id)).ReturnsAsync((Annotation)null); + await this.module.GetEntity(this.annotationManager.Object, annotation.Id, this.context.Object); this.response.VerifySet(x => x.StatusCode = 404, Times.Once); - this.annotationManager.Setup(x => x.FindEntity(annotation.Id)).ReturnsAsync(annotation); + this.annotationManager.As>() + .Setup(x => x.FindEntityWithContainer(annotation.Id)).ReturnsAsync(annotation); + await this.module.GetEntity(this.annotationManager.Object, annotation.Id, this.context.Object); this.response.VerifySet(x => x.StatusCode = 400, Times.Once); diff --git a/UI_DSM/UI_DSM.Server.Tests/Modules/ArtifactModuleTestFixture.cs b/UI_DSM/UI_DSM.Server.Tests/Modules/ArtifactModuleTestFixture.cs new file mode 100644 index 00000000..84a970b2 --- /dev/null +++ b/UI_DSM/UI_DSM.Server.Tests/Modules/ArtifactModuleTestFixture.cs @@ -0,0 +1,151 @@ +// -------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2022 RHEA System S.A. +// +// Author: Antoine Théate, Sam Gerené, Alex Vorobiev, Alexander van Delft, Martin Risseeuw, Nabil Abbar +// +// This file is part of UI-DSM. +// The UI-DSM web application is used to review an ECSS-E-TM-10-25 model. +// +// The UI-DSM application is provided to the community under the Apache License 2.0. +// +// -------------------------------------------------------------------------------------------------------- + +namespace UI_DSM.Server.Tests.Modules +{ + using Microsoft.AspNetCore.Http; + using Microsoft.AspNetCore.Routing; + + using Moq; + + using NUnit.Framework; + + using UI_DSM.Server.Managers; + using UI_DSM.Server.Managers.ArtifactManager; + using UI_DSM.Server.Modules; + using UI_DSM.Server.Services.FileService; + using UI_DSM.Server.Tests.Helpers; + using UI_DSM.Server.Validator; + using UI_DSM.Shared.DTO.Models; + using UI_DSM.Shared.Models; + + [TestFixture] + public class ArtifactModuleTestFixture + { + private ArtifactModule module; + private Mock> artifactManager; + private Mock context; + private Mock response; + private Mock request; + private Mock serviceProvider; + private Mock> projectManager; + private RouteValueDictionary routeValues; + private Guid projectId; + private Mock fileService; + + [SetUp] + public void Setup() + { + this.projectManager = new Mock>(); + this.artifactManager = new Mock>(); + this.artifactManager.As(); + this.artifactManager.As>(); + + ModuleTestHelper.Setup(new ArtifactValidator(), out this.context, + out this.response, out this.request, out this.serviceProvider); + + this.projectId = Guid.NewGuid(); + + this.routeValues = new RouteValueDictionary + { + ["projectId"] = this.projectId.ToString() + }; + + this.request.Setup(x => x.RouteValues).Returns(this.routeValues); + this.serviceProvider.Setup(x => x.GetService(typeof(IEntityManager))).Returns(this.projectManager.Object); + this.fileService = new Mock(); + this.module = new ArtifactModule(this.fileService.Object); + } + + [Test] + public async Task VerifyGetEntities() + { + var artifacts = new List + { + new Model(Guid.NewGuid()) + }; + + this.artifactManager.As().Setup(x => x.GetContainedEntities(this.projectId, 0)) + .ReturnsAsync(artifacts); + + await this.module.GetEntities(this.artifactManager.Object, this.context.Object); + this.artifactManager.As().Verify(x => x.GetContainedEntities(this.projectId, 0), Times.Once); + } + + [Test] + public async Task VerifyGetEntity() + { + var project = new Project(Guid.NewGuid()); + + var artifact = new Model(Guid.NewGuid()); + + this.artifactManager.As>() + .Setup(x => x.FindEntityWithContainer(artifact.Id)).ReturnsAsync((Artifact)null); + + await this.module.GetEntity(this.artifactManager.Object, artifact.Id, this.context.Object); + this.response.VerifySet(x => x.StatusCode = 404, Times.Once); + + this.artifactManager.As>() + .Setup(x => x.FindEntityWithContainer(artifact.Id)).ReturnsAsync(artifact); + + await this.module.GetEntity(this.artifactManager.Object, artifact.Id, this.context.Object); + this.response.VerifySet(x => x.StatusCode = 400, Times.Once); + + project.Artifacts.Add(artifact); + await this.module.GetEntity(this.artifactManager.Object, artifact.Id, this.context.Object); + this.response.VerifySet(x => x.StatusCode = 400, Times.Exactly(2)); + + this.routeValues["projectId"] = project.Id.ToString(); + await this.module.GetEntity(this.artifactManager.Object, artifact.Id, this.context.Object); + this.response.VerifySet(x => x.StatusCode = 400, Times.Exactly(2)); + } + + [Test] + public async Task VerifyCreateEntity() + { + var modelDto = new ModelDto() + { + FileName = "filename.zip", + ModelName = "Model" + }; + + this.fileService.Setup(x => x.TempFileExists(modelDto.FileName)).Returns(false); + await this.module.CreateEntity(this.artifactManager.Object, modelDto, this.context.Object); + this.response.VerifySet(x => x.StatusCode=404, Times.Once); + + this.fileService.Setup(x => x.TempFileExists(modelDto.FileName)).Returns(true); + this.fileService.Setup(x => x.Exists(this.projectId.ToString(), modelDto.FileName)).Returns(true); + await this.module.CreateEntity(this.artifactManager.Object, modelDto, this.context.Object); + this.response.VerifySet(x => x.StatusCode = 400, Times.Once); + + this.fileService.Setup(x => x.Exists(this.projectId.ToString(), modelDto.FileName)).Returns(false); + this.fileService.Setup(x => x.IsAnnexC3File(modelDto.FileName)).ReturnsAsync(false); + await this.module.CreateEntity(this.artifactManager.Object, modelDto, this.context.Object); + this.response.VerifySet(x => x.StatusCode = 400, Times.Exactly(2)); + + this.fileService.Setup(x => x.IsAnnexC3File(modelDto.FileName)).ReturnsAsync(true); + await this.module.CreateEntity(this.artifactManager.Object, modelDto, this.context.Object); + this.fileService.Verify(x => x.MoveFile(It.IsAny(), It.IsAny()), Times.Once()); + } + + [Test] + public async Task VerifyUpdateAndDeleteEntity() + { + var dto = new ModelDto(Guid.NewGuid()); + + await this.module.UpdateEntity(this.artifactManager.Object, dto.Id, dto, this.context.Object); + await this.module.DeleteEntity(this.artifactManager.Object, dto.Id, this.context.Object); + this.response.VerifySet(x => x.StatusCode = 403, Times.Exactly(2)); + } + } +} diff --git a/UI_DSM/UI_DSM.Server.Tests/Modules/CometModuleTestFixture.cs b/UI_DSM/UI_DSM.Server.Tests/Modules/CometModuleTestFixture.cs new file mode 100644 index 00000000..7ba4849d --- /dev/null +++ b/UI_DSM/UI_DSM.Server.Tests/Modules/CometModuleTestFixture.cs @@ -0,0 +1,161 @@ +// -------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2022 RHEA System S.A. +// +// Author: Antoine Théate, Sam Gerené, Alex Vorobiev, Alexander van Delft, Martin Risseeuw, Nabil Abbar +// +// This file is part of UI-DSM. +// The UI-DSM web application is used to review an ECSS-E-TM-10-25 model. +// +// The UI-DSM application is provided to the community under the Apache License 2.0. +// +// -------------------------------------------------------------------------------------------------------- + +namespace UI_DSM.Server.Tests.Modules +{ + using Carter; + + using CDP4Common.EngineeringModelData; + using CDP4Common.SiteDirectoryData; + + using Microsoft.AspNetCore.Http; + using Moq; + + using NUnit.Framework; + + using UI_DSM.Client.Enumerator; + using UI_DSM.Server.Modules; + using UI_DSM.Server.Services.CometService; + using UI_DSM.Server.Tests.Helpers; + using UI_DSM.Server.Validator; + using UI_DSM.Shared.DTO.CometData; + + [TestFixture] + public class CometModuleTestFixture + { + private CometModule module; + private Mock cometService; + private Mock context; + private Mock response; + private Mock serviceProvider; + + [SetUp] + public void Setup() + { + this.cometService = new Mock(); + + ModuleTestHelper.Setup(new CometAuthenticationDataValidator(), out this.context, + out this.response, out _, out this.serviceProvider); + + this.module = new CometModule(this.cometService.Object); + } + + [Test] + public async Task VerifyLogin() + { + var authenticationData = new CometAuthenticationData(); + await this.module.Login(authenticationData, this.context.Object); + this.response.VerifySet(x => x.StatusCode = 400,Times.Once); + + authenticationData.UserName = "user"; + authenticationData.Password = "pass"; + authenticationData.Url = "http://localhost"; + var authenticationReply = new Tuple(AuthenticationStatus.Fail, Guid.Empty); + this.cometService.Setup(x => x.Login(authenticationData)).ReturnsAsync(authenticationReply); + await this.module.Login(authenticationData, this.context.Object); + this.response.VerifySet(x => x.StatusCode = 401, Times.Once); + + authenticationReply = new Tuple(AuthenticationStatus.ServerFailure, Guid.Empty); + this.cometService.Setup(x => x.Login(authenticationData)).ReturnsAsync(authenticationReply); + await this.module.Login(authenticationData, this.context.Object); + this.response.VerifySet(x => x.StatusCode = 500, Times.Once); + + authenticationReply = new Tuple(AuthenticationStatus.Success, Guid.NewGuid()); + this.cometService.Setup(x => x.Login(authenticationData)).ReturnsAsync(authenticationReply); + await this.module.Login(authenticationData, this.context.Object); + } + + [Test] + public async Task VerifyGetAvailableEngineeringModels() + { + var sessionId = Guid.NewGuid(); + + this.cometService.Setup(x => x.GetAvailableEngineeringModel(sessionId)).Throws(); + await this.module.GetAvailableEngineeringModels(sessionId,this.context.Object); + this.response.VerifySet(x => x.StatusCode = 404, Times.Once); + + var engineeringModels = new List + { + new () + { + Iid = Guid.NewGuid(), + Name = "Model", + IterationSetup = + { + new IterationSetup() + { + IsDeleted = true + }, + new IterationSetup(), + new IterationSetup() + { + FrozenOn = DateTime.UtcNow, + IterationNumber = 1, + IterationIid = Guid.NewGuid() + } + } + } + }; + + this.cometService.Setup(x => x.GetAvailableEngineeringModel(sessionId)).Returns(engineeringModels); + await this.module.GetAvailableEngineeringModels(sessionId, this.context.Object); + this.response.VerifySet(x => x.StatusCode = 404, Times.Once); + } + + [Test] + public async Task VerifyLogout() + { + var sessionId = Guid.NewGuid(); + await this.module.Logout(sessionId, this.context.Object); + this.response.VerifySet(x => x.StatusCode = 404, Times.Never); + + this.cometService.Setup(x => x.Close(sessionId)).Throws(); + await this.module.Logout(sessionId, this.context.Object); + this.response.VerifySet(x => x.StatusCode = 404, Times.Once); + } + + [Test] + public async Task VerifyUploadIteration() + { + var validatorService = new Mock(); + validatorService.Setup(x => x.GetValidator()).Returns(new ModelUploadDataValidator()); + this.serviceProvider.Setup(x => x.GetService(typeof(IValidatorLocator))).Returns(validatorService.Object); + + var sessionId = Guid.NewGuid(); + var modelUpload = new ModelUploadData(); + await this.module.UploadIteration(sessionId, modelUpload, this.context.Object); + this.response.VerifySet(x => x.StatusCode = 400, Times.Once); + + modelUpload.ModelId = Guid.NewGuid(); + modelUpload.IterationId = Guid.NewGuid(); + + var iterationSetup = new IterationSetup(); + + this.cometService.Setup(x => x.GetIterationSetup(sessionId, modelUpload.ModelId, modelUpload.IterationId)) + .Returns(iterationSetup); + + var iteration = new Iteration(); + this.cometService.Setup(x => x.ReadIteration(sessionId, iterationSetup)).ReturnsAsync(iteration); + this.cometService.Setup(x => x.CreateAnnexC3File(iteration)).ReturnsAsync("filename.zip"); + + await this.module.UploadIteration(sessionId, modelUpload, this.context.Object); + this.response.VerifySet(x => x.StatusCode = 400, Times.Once); + + this.cometService.Setup(x => x.GetIterationSetup(sessionId, modelUpload.ModelId, modelUpload.IterationId)) + .Throws(); + + await this.module.UploadIteration(sessionId, modelUpload, this.context.Object); + this.response.VerifySet(x => x.StatusCode = 400, Times.Exactly(2)); + } + } +} diff --git a/UI_DSM/UI_DSM.Server.Tests/Modules/ParticipantModuleTestFixture.cs b/UI_DSM/UI_DSM.Server.Tests/Modules/ParticipantModuleTestFixture.cs index 74cc13f8..9d59b69d 100644 --- a/UI_DSM/UI_DSM.Server.Tests/Modules/ParticipantModuleTestFixture.cs +++ b/UI_DSM/UI_DSM.Server.Tests/Modules/ParticipantModuleTestFixture.cs @@ -47,6 +47,7 @@ public void Setup() this.projectManager = new Mock>(); this.participantManager = new Mock>(); this.participantManager.As(); + this.participantManager.As>(); ModuleTestHelper.Setup(new ParticipantDtoValidator(), out this.context, out this.response, out this.request, out this.serviceProvider); @@ -99,11 +100,16 @@ public async Task VerifyGetEntity() }; this.routeValues["projectId"] = Guid.NewGuid().ToString(); - this.participantManager.Setup(x => x.FindEntity(participant.Id)).ReturnsAsync((Participant)null); + + this.participantManager.As>() + .Setup(x => x.FindEntityWithContainer(participant.Id)).ReturnsAsync((Participant)null); + await this.module.GetEntity(this.participantManager.Object, participant.Id, this.context.Object); this.response.VerifySet(x => x.StatusCode = 404, Times.Once); - this.participantManager.Setup(x => x.FindEntity(participant.Id)).ReturnsAsync(participant); + this.participantManager.As>() + .Setup(x => x.FindEntityWithContainer(participant.Id)).ReturnsAsync(participant); + await this.module.GetEntity(this.participantManager.Object, participant.Id, this.context.Object); this.response.VerifySet(x => x.StatusCode = 400, Times.Once); diff --git a/UI_DSM/UI_DSM.Server.Tests/Modules/ReplyModuleTestFixture.cs b/UI_DSM/UI_DSM.Server.Tests/Modules/ReplyModuleTestFixture.cs index 1a4eb6ad..ca47a2ab 100644 --- a/UI_DSM/UI_DSM.Server.Tests/Modules/ReplyModuleTestFixture.cs +++ b/UI_DSM/UI_DSM.Server.Tests/Modules/ReplyModuleTestFixture.cs @@ -173,7 +173,8 @@ public async Task VerifyGetEntity() this.annotationManager.As>() .Setup(x => x.EntityIsContainedBy(this.commentId, this.projectId)).ReturnsAsync(false); - this.replyManager.Setup(x => x.FindEntity(reply.Id)).ReturnsAsync(reply); + this.replyManager.As>() + .Setup(x => x.FindEntityWithContainer(reply.Id)).ReturnsAsync(reply); await this.module.GetEntity(this.replyManager.Object, reply.Id, this.context.Object); this.response.VerifySet(x => x.StatusCode = 400, Times.Exactly(2)); @@ -182,7 +183,7 @@ public async Task VerifyGetEntity() .Setup(x => x.EntityIsContainedBy(this.commentId, this.projectId)).ReturnsAsync(true); await this.module.GetEntity(this.replyManager.Object, reply.Id, this.context.Object); - this.replyManager.Verify(x => x.FindEntity(reply.Id), Times.Once); + this.replyManager.As>().Verify(x => x.FindEntityWithContainer(reply.Id), Times.Once); } [Test] diff --git a/UI_DSM/UI_DSM.Server.Tests/Modules/ReviewModuleTestFixture.cs b/UI_DSM/UI_DSM.Server.Tests/Modules/ReviewModuleTestFixture.cs index 28568adb..cea9eb2a 100644 --- a/UI_DSM/UI_DSM.Server.Tests/Modules/ReviewModuleTestFixture.cs +++ b/UI_DSM/UI_DSM.Server.Tests/Modules/ReviewModuleTestFixture.cs @@ -139,11 +139,15 @@ public async Task VerifyGetEntity() this.participantManager.Setup(x => x.GetParticipantForProject(It.IsAny(), "user")).ReturnsAsync(review.Author); - this.reviewManager.Setup(x => x.FindEntity(review.Id)).ReturnsAsync((Review)null); + this.reviewManager.As>() + .Setup(x => x.FindEntityWithContainer(review.Id)).ReturnsAsync((Review)null); + await this.module.GetEntity(this.reviewManager.Object, review.Id, this.context.Object); this.response.VerifySet(x => x.StatusCode = 404, Times.Once); - this.reviewManager.Setup(x => x.FindEntity(review.Id)).ReturnsAsync(review); + this.reviewManager.As>() + .Setup(x => x.FindEntityWithContainer(review.Id)).ReturnsAsync(review); + await this.module.GetEntity(this.reviewManager.Object, review.Id, this.context.Object); this.response.VerifySet(x => x.StatusCode = 400, Times.Once); diff --git a/UI_DSM/UI_DSM.Server.Tests/Modules/ReviewObjectiveModuleTestFixture.cs b/UI_DSM/UI_DSM.Server.Tests/Modules/ReviewObjectiveModuleTestFixture.cs index 3bea5b7f..c9abfa12 100644 --- a/UI_DSM/UI_DSM.Server.Tests/Modules/ReviewObjectiveModuleTestFixture.cs +++ b/UI_DSM/UI_DSM.Server.Tests/Modules/ReviewObjectiveModuleTestFixture.cs @@ -171,7 +171,8 @@ public async Task VerifyGetEntity() this.reviewManager.As>() .Setup(x => x.EntityIsContainedBy(this.reviewId, this.projectId)).ReturnsAsync(false); - this.reviewObjectiveManager.Setup(x => x.FindEntity(reviewObjective.Id)).ReturnsAsync(reviewObjective); + this.reviewObjectiveManager.As>() + .Setup(x => x.FindEntityWithContainer(reviewObjective.Id)).ReturnsAsync(reviewObjective); await this.module.GetEntity(this.reviewObjectiveManager.Object, reviewObjective.Id, this.context.Object); this.response.VerifySet(x => x.StatusCode = 400, Times.Once); @@ -180,7 +181,9 @@ public async Task VerifyGetEntity() .Setup(x => x.EntityIsContainedBy(this.reviewId, this.projectId)).ReturnsAsync(true); await this.module.GetEntity(this.reviewObjectiveManager.Object, reviewObjective.Id, this.context.Object); - this.reviewObjectiveManager.Verify(x => x.FindEntity(reviewObjective.Id), Times.Once); + + this.reviewObjectiveManager.As>() + .Verify(x => x.FindEntityWithContainer(reviewObjective.Id), Times.Once); } [Test] diff --git a/UI_DSM/UI_DSM.Server.Tests/Modules/ReviewTaskModuleTestFixture.cs b/UI_DSM/UI_DSM.Server.Tests/Modules/ReviewTaskModuleTestFixture.cs index 49111cea..dc39801f 100644 --- a/UI_DSM/UI_DSM.Server.Tests/Modules/ReviewTaskModuleTestFixture.cs +++ b/UI_DSM/UI_DSM.Server.Tests/Modules/ReviewTaskModuleTestFixture.cs @@ -187,7 +187,8 @@ public async Task VerifyGetEntity() this.reviewObjectiveManager.As>() .Setup(x => x.EntityIsContainedBy(this.reviewObjectiveId, this.reviewId)).ReturnsAsync(false); - this.reviewTaskManager.Setup(x => x.FindEntity(reviewTask.Id)).ReturnsAsync(reviewTask); + this.reviewTaskManager.As>().Setup(x => + x.FindEntityWithContainer(reviewTask.Id)).ReturnsAsync(reviewTask); await this.module.GetEntity(this.reviewTaskManager.Object, reviewTask.Id, this.context.Object); this.response.VerifySet(x => x.StatusCode = 400, Times.Once); @@ -205,7 +206,9 @@ public async Task VerifyGetEntity() .Setup(x => x.EntityIsContainedBy(this.reviewId, this.projectId)).ReturnsAsync(true); await this.module.GetEntity(this.reviewTaskManager.Object, reviewTask.Id, this.context.Object); - this.reviewTaskManager.Verify(x => x.FindEntity(reviewTask.Id), Times.Once); + + this.reviewTaskManager.As>().Verify(x => + x.FindEntityWithContainer(reviewTask.Id), Times.Once); } [Test] diff --git a/UI_DSM/UI_DSM.Server.Tests/Negotiator/JsonNegotiatorTestFixture.cs b/UI_DSM/UI_DSM.Server.Tests/Negotiator/JsonNegotiatorTestFixture.cs new file mode 100644 index 00000000..85f53af0 --- /dev/null +++ b/UI_DSM/UI_DSM.Server.Tests/Negotiator/JsonNegotiatorTestFixture.cs @@ -0,0 +1,81 @@ +// -------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2022 RHEA System S.A. +// +// Author: Antoine Théate, Sam Gerené, Alex Vorobiev, Alexander van Delft, Martin Risseeuw, Nabil Abbar +// +// This file is part of UI-DSM. +// The UI-DSM web application is used to review an ECSS-E-TM-10-25 model. +// +// The UI-DSM application is provided to the community under the Apache License 2.0. +// +// -------------------------------------------------------------------------------------------------------- + +namespace UI_DSM.Server.Tests.Negotiator +{ + using System.Text.Json; + + using Microsoft.AspNetCore.Http; + using Microsoft.Net.Http.Headers; + + using Moq; + + using NUnit.Framework; + + using UI_DSM.Serializer.Json; + using UI_DSM.Server.ResponseNegotiator; + using UI_DSM.Shared.DTO.Common; + using UI_DSM.Shared.DTO.Models; + + [TestFixture] + public class JsonNegotiatorTestFixture + { + private JsonNegotiator negotiator; + private Mock serializer; + + [SetUp] + public void Setup() + { + this.serializer = new Mock(); + this.negotiator = new JsonNegotiator(this.serializer.Object); + } + + [Test] + public void VerifyCanHandle() + { + Assert.Multiple(() => + { + Assert.That(this.negotiator.CanHandle(new MediaTypeHeaderValue("application/json")), Is.True); + Assert.That(this.negotiator.CanHandle(new MediaTypeHeaderValue("application/xml")), Is.False); + }); + } + + [Test] + public async Task VerifyHandle() + { + var request = new Mock(); + var response = new Mock(); + var cancellationToken = new CancellationToken(); + + await this.negotiator.Handle(request.Object, response.Object, new ProjectDto(), cancellationToken); + + this.serializer.Verify(x => + x.SerializeAsync(It.IsAny(), It.IsAny(), It.IsAny()), + Times.Once); + + await this.negotiator.Handle(request.Object, response.Object, new List(), cancellationToken); + + this.serializer.Verify(x => + x.SerializeAsync(It.IsAny>(), It.IsAny(), It.IsAny()), + Times.Once); + + await this.negotiator.Handle(request.Object, response.Object, new EntityRequestResponseDto(), cancellationToken); + + this.serializer.Verify(x => + x.SerializeEntityRequestDtoAsync(It.IsAny(), It.IsAny(), It.IsAny()), + Times.Once); + + Assert.That(async ()=> await this.negotiator.Handle(request.Object, response.Object, "45", cancellationToken), Throws.Exception); + } + } +} diff --git a/UI_DSM/UI_DSM.Server.Tests/Services/CometServiceTestFixture.cs b/UI_DSM/UI_DSM.Server.Tests/Services/CometServiceTestFixture.cs new file mode 100644 index 00000000..cda3e796 --- /dev/null +++ b/UI_DSM/UI_DSM.Server.Tests/Services/CometServiceTestFixture.cs @@ -0,0 +1,66 @@ +// -------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2022 RHEA System S.A. +// +// Author: Antoine Théate, Sam Gerené, Alex Vorobiev, Alexander van Delft, Martin Risseeuw, Nabil Abbar +// +// This file is part of UI-DSM. +// The UI-DSM web application is used to review an ECSS-E-TM-10-25 model. +// +// The UI-DSM application is provided to the community under the Apache License 2.0. +// +// -------------------------------------------------------------------------------------------------------- + +namespace UI_DSM.Server.Tests.Services +{ + using CDP4Common.SiteDirectoryData; + + using Moq; + + using NUnit.Framework; + + using UI_DSM.Server.Services.CometService; + using UI_DSM.Server.Services.FileService; + using UI_DSM.Shared.DTO.CometData; + + [TestFixture] + public class CometServiceTestFixture + { + private CometService cometService; + private Mock fileService; + + [SetUp] + public void Setup() + { + this.fileService = new Mock(); + this.cometService = new CometService(this.fileService.Object); + } + + [Test] + public void VerifyLogin() + { + var authenticationData = new CometAuthenticationData() + { + Url = "http://test.abc:5000", + UserName = "admin", + Password = "pass" + }; + + Assert.That(async () => await this.cometService.Login(authenticationData), Throws.Nothing); + } + + [Test] + public void VerifyThatOtherMethodsThrows() + { + var sessionId = Guid.NewGuid(); + + Assert.Multiple( () => + { + Assert.That(async () => await this.cometService.Close(sessionId), Throws.Exception); + Assert.That(async () => await this.cometService.ReadIteration(sessionId, new IterationSetup()), Throws.Exception); + Assert.That(() => this.cometService.GetIterationSetup(sessionId, Guid.NewGuid(), Guid.NewGuid()), Throws.Exception); + Assert.That(() => this.cometService.GetAvailableEngineeringModel(sessionId), Throws.Exception); + }); + } + } +} diff --git a/UI_DSM/UI_DSM.Server.Tests/Services/FileServiceTestFixture.cs b/UI_DSM/UI_DSM.Server.Tests/Services/FileServiceTestFixture.cs new file mode 100644 index 00000000..2e7383f9 --- /dev/null +++ b/UI_DSM/UI_DSM.Server.Tests/Services/FileServiceTestFixture.cs @@ -0,0 +1,84 @@ +// -------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2022 RHEA System S.A. +// +// Author: Antoine Théate, Sam Gerené, Alex Vorobiev, Alexander van Delft, Martin Risseeuw, Nabil Abbar +// +// This file is part of UI-DSM. +// The UI-DSM web application is used to review an ECSS-E-TM-10-25 model. +// +// The UI-DSM application is provided to the community under the Apache License 2.0. +// +// -------------------------------------------------------------------------------------------------------- + +namespace UI_DSM.Server.Tests.Services +{ + using NUnit.Framework; + + using UI_DSM.Server.Services.FileService; + + [TestFixture] + public class FileServiceTestFixture + { + private FileService fileService; + private Guid projectId; + + [SetUp] + public void Setup() + { + this.fileService= new FileService(TestContext.CurrentContext.TestDirectory); + this.projectId = Guid.NewGuid(); + } + + [TearDown] + public void TearDown() + { + Directory.Delete(this.fileService.GetTempFolder(), true); + Directory.Delete(Path.Combine(TestContext.CurrentContext.TestDirectory, this.projectId.ToString()), true); + } + + [Test] + public void VerifyService() + { + const string fileName = "26699a14-79d0-4f10-bcf1-15979ef3968f.zip"; + + Assert.Multiple(async () => + { + Assert.That(this.fileService.Exists("Data", fileName), Is.True); + Assert.That(this.fileService.TempFileExists(fileName), Is.False); + Assert.That(await this.fileService.IsAnnexC3File(fileName), Is.False); + }); + + File.Copy(Path.Combine("Data", fileName), + Path.Combine(this.fileService.GetTempFolder(), fileName)); + + Assert.Multiple(async () => + { + Assert.That(this.fileService.TempFileExists(fileName), Is.True); + Assert.That(await this.fileService.IsAnnexC3File(fileName), Is.True); + }); + + Assert.That(this.fileService.Exists(this.projectId.ToString(), fileName), Is.False); + this.fileService.MoveFile(fileName, this.projectId.ToString()); + + Assert.Multiple(() => + { + Assert.That(this.fileService.Exists(this.projectId.ToString(), fileName), Is.True); + Assert.That(() => this.fileService.DeleteFile(Path.Combine(this.projectId.ToString(), fileName)), Throws.Nothing); + Assert.That(this.fileService.Exists(this.projectId.ToString(), fileName), Is.False); + Assert.That(() => this.fileService.DeleteFile(Path.Combine(this.projectId.ToString(), fileName)), Throws.Nothing); + }); + + File.Copy(Path.Combine("Data", fileName), + Path.Combine(this.fileService.GetTempFolder(), fileName)); + + Assert.Multiple(() => + { + Assert.That(this.fileService.TempFileExists(fileName), Is.True); + Assert.That(() => this.fileService.DeleteTemporaryFile(fileName), Throws.Nothing); + Assert.That(this.fileService.TempFileExists(fileName), Is.False); + Assert.That(() => this.fileService.DeleteTemporaryFile(fileName), Throws.Nothing); + }); + } + } +} diff --git a/UI_DSM/UI_DSM.Server.Tests/UI_DSM.Server.Tests.csproj b/UI_DSM/UI_DSM.Server.Tests/UI_DSM.Server.Tests.csproj index 269c5317..f066401d 100644 --- a/UI_DSM/UI_DSM.Server.Tests/UI_DSM.Server.Tests.csproj +++ b/UI_DSM/UI_DSM.Server.Tests/UI_DSM.Server.Tests.csproj @@ -27,4 +27,10 @@ + + + PreserveNewest + + + diff --git a/UI_DSM/UI_DSM.Server/Context/DatabaseContext.cs b/UI_DSM/UI_DSM.Server/Context/DatabaseContext.cs index baf948a5..3d437185 100644 --- a/UI_DSM/UI_DSM.Server/Context/DatabaseContext.cs +++ b/UI_DSM/UI_DSM.Server/Context/DatabaseContext.cs @@ -98,6 +98,11 @@ protected DatabaseContext() /// public virtual DbSet Notes { get; set; } + /// + /// A of + /// + public virtual DbSet Models { get; set; } + /// /// Tries to validate an object /// @@ -124,6 +129,7 @@ protected override void OnModelCreating(ModelBuilder builder) builder.Entity().HasIndex(x => x.ProjectName).IsUnique(); builder.Entity().HasIndex(x => x.RoleName).IsUnique(); + builder.Entity().HasIndex(x => x.FileName).IsUnique(); builder.Entity().HasMany(p => p.Participants) .WithOne(p => (Project)p.EntityContainer) @@ -140,15 +146,26 @@ protected override void OnModelCreating(ModelBuilder builder) .HasForeignKey("EntityContainerId") .OnDelete(DeleteBehavior.Cascade); + builder.Entity().HasMany(p => p.Artifacts) + .WithOne(p => (Project)p.EntityContainer) + .HasForeignKey("EntityContainerId") + .OnDelete(DeleteBehavior.Cascade); + builder.Entity().Navigation(x => x.Participants).AutoInclude(); builder.Entity().Navigation(x => x.Reviews).AutoInclude(); builder.Entity().Navigation(x => x.Annotations).AutoInclude(); + builder.Entity().Navigation(x => x.Artifacts).AutoInclude(); builder.Entity().Navigation(x => x.Role).AutoInclude(); builder.Entity().Navigation(x => x.User).AutoInclude(); builder.Entity().Navigation(x => x.Author).AutoInclude(); builder.Entity().Navigation(x => x.ReviewObjectives).AutoInclude(); + + builder.Entity().HasMany(x => x.Artifacts) + .WithMany(x => x.Reviews); + + builder.Entity().Navigation(x => x.Artifacts).AutoInclude(); builder.Entity().HasMany(x => x.ReviewObjectives) .WithOne(ro => (Review)ro.EntityContainer) @@ -168,7 +185,7 @@ protected override void OnModelCreating(ModelBuilder builder) builder.Entity().HasMany(x => x.Annotations); builder.Entity().Navigation(x => x.Annotations).AutoInclude(); - + builder.Entity().HasMany(a => a.AnnotatableItems); builder.Entity().Navigation(x => x.Author).AutoInclude(); diff --git a/UI_DSM/UI_DSM.Server/Managers/ArtifactManager/ArtifactManager.cs b/UI_DSM/UI_DSM.Server/Managers/ArtifactManager/ArtifactManager.cs new file mode 100644 index 00000000..35308cb5 --- /dev/null +++ b/UI_DSM/UI_DSM.Server/Managers/ArtifactManager/ArtifactManager.cs @@ -0,0 +1,210 @@ +// -------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2022 RHEA System S.A. +// +// Author: Antoine Théate, Sam Gerené, Alex Vorobiev, Alexander van Delft, Martin Risseeuw +// +// This file is part of UI-DSM. +// The UI-DSM web application is used to review an ECSS-E-TM-10-25 model. +// +// The UI-DSM application is provided to the community under the Apache License 2.0. +// +// -------------------------------------------------------------------------------------------------------- + +namespace UI_DSM.Server.Managers.ArtifactManager +{ + using UI_DSM.Server.Context; + using UI_DSM.Server.Managers.ModelManager; + using UI_DSM.Server.Types; + using UI_DSM.Shared.DTO.Models; + using UI_DSM.Shared.Models; + + /// + /// This manager handles operation to the Database for s + /// + public class ArtifactManager : IArtifactManager + { + /// + /// The + /// + private readonly IModelManager modelManager; + + /// + /// Initializes a new instance of the class. + /// + /// The + public ArtifactManager(IModelManager modelManager) + { + this.modelManager = modelManager; + } + + /// + /// Gets a collection of all s and associated + /// + /// The level of deepnest that we need to retrieve associated + /// A with a collection of as result + public async Task> GetEntities(int deepLevel = 0) + { + var annotatableItems = new List(); + annotatableItems.AddRange(await this.modelManager.GetEntities(deepLevel)); + return annotatableItems.DistinctBy(x => x.Id); + } + + /// + /// Tries to get a based on its and its associated + /// + /// The + /// The level of deepnest that we need to retrieve associated + /// A with a collection of if found + public async Task> GetEntity(Guid entityId, int deepLevel = 0) + { + var artifact = await this.FindEntity(entityId); + + return artifact == null ? Enumerable.Empty() : artifact.GetAssociatedEntities(deepLevel); + } + + /// + /// Tries to get a based on its + /// + /// The + /// A with the if found + public async Task FindEntity(Guid entityId) + { + return await this.modelManager.FindEntity(entityId); + } + + /// + /// Tries to get all based on their + /// + /// A collection of + /// A collection of + public async Task> FindEntities(IEnumerable entitiesId) + { + var entities = new List(); + + foreach (var id in entitiesId) + { + var entity = await this.FindEntity(id); + + if (entity != null) + { + entities.Add(entity); + } + } + + return entities; + } + + /// + /// Creates a new and store it into the + /// + /// The to create + /// A with the result of the creation + public async Task> CreateEntity(Artifact entity) + { + switch (entity) + { + case Model model: + var modelResult = await this.modelManager.CreateEntity(model); + + return modelResult.Succeeded + ? EntityOperationResult.Success(modelResult.Entity) + : EntityOperationResult.Failed(modelResult.Errors.ToArray()); + } + + return EntityOperationResult.Failed("Unknowned Annotation subclass"); + } + + /// + /// Updates a + /// + /// The to update + /// A with the result of the update + public async Task> UpdateEntity(Artifact entity) + { + switch (entity) + { + case Model model: + var modelResult = await this.modelManager.UpdateEntity(model); + + return modelResult.Succeeded + ? EntityOperationResult.Success(modelResult.Entity) + : EntityOperationResult.Failed(modelResult.Errors.ToArray()); + } + + return EntityOperationResult.Failed("Unknowned Annotation subclass"); + } + + /// + /// Deletes a + /// + /// The to delete + /// A with the result of the deletion + public async Task> DeleteEntity(Artifact entity) + { + switch (entity) + { + case Model model: + var modelResult = await this.modelManager.DeleteEntity(model); + + return modelResult.Succeeded + ? EntityOperationResult.Success(modelResult.Entity) + : EntityOperationResult.Failed(modelResult.Errors.ToArray()); + } + + return EntityOperationResult.Failed("Unknowned Annotation subclass"); + } + + /// + /// Resolve all properties for the + /// + /// The + /// The + /// A + public async Task ResolveProperties(Artifact entity, EntityDto dto) + { + switch (entity) + { + case Model model: + await this.modelManager.ResolveProperties(model, dto); + break; + } + } + + /// + /// Finds an and includes his container + /// + /// The id + /// A with the + public async Task FindEntityWithContainer(Guid entityId) + { + return await this.modelManager.FindEntityWithContainer(entityId); + } + + /// + /// Gets all that are contained by the with the Id + /// and associated + /// + /// The of the container + /// The deep level + /// A with a collection of + public async Task> GetContainedEntities(Guid containerId, int deepLevel = 0) + { + var artifacts = new List(); + artifacts.AddRange(await this.modelManager.GetContainedEntities(containerId, deepLevel)); + return artifacts.DistinctBy(x => x.Id); + } + + /// + /// Verifies if the container of the has the given + /// + /// The of the + /// The of the container + /// A with the value of the check + public async Task EntityIsContainedBy(Guid entityId, Guid containerId) + { + var artifact = await this.FindEntityWithContainer(entityId); + return artifact != null && artifact.EntityContainer.Id == containerId; + } + } +} diff --git a/UI_DSM/UI_DSM.Server/Managers/ArtifactManager/IArtifactManager.cs b/UI_DSM/UI_DSM.Server/Managers/ArtifactManager/IArtifactManager.cs new file mode 100644 index 00000000..eb052ca3 --- /dev/null +++ b/UI_DSM/UI_DSM.Server/Managers/ArtifactManager/IArtifactManager.cs @@ -0,0 +1,24 @@ +// -------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2022 RHEA System S.A. +// +// Author: Antoine Théate, Sam Gerené, Alex Vorobiev, Alexander van Delft, Martin Risseeuw +// +// This file is part of UI-DSM. +// The UI-DSM web application is used to review an ECSS-E-TM-10-25 model. +// +// The UI-DSM application is provided to the community under the Apache License 2.0. +// +// -------------------------------------------------------------------------------------------------------- + +namespace UI_DSM.Server.Managers.ArtifactManager +{ + using UI_DSM.Shared.Models; + + /// + /// Interface definition for + /// + public interface IArtifactManager : IContainedEntityManager + { + } +} diff --git a/UI_DSM/UI_DSM.Server/Managers/ModelManager/IModelManager.cs b/UI_DSM/UI_DSM.Server/Managers/ModelManager/IModelManager.cs new file mode 100644 index 00000000..36fb3ae4 --- /dev/null +++ b/UI_DSM/UI_DSM.Server/Managers/ModelManager/IModelManager.cs @@ -0,0 +1,24 @@ +// -------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2022 RHEA System S.A. +// +// Author: Antoine Théate, Sam Gerené, Alex Vorobiev, Alexander van Delft, Martin Risseeuw +// +// This file is part of UI-DSM. +// The UI-DSM web application is used to review an ECSS-E-TM-10-25 model. +// +// The UI-DSM application is provided to the community under the Apache License 2.0. +// +// -------------------------------------------------------------------------------------------------------- + +namespace UI_DSM.Server.Managers.ModelManager +{ + using UI_DSM.Shared.Models; + + /// + /// Interface definition for + /// + public interface IModelManager : IContainedEntityManager + { + } +} diff --git a/UI_DSM/UI_DSM.Server/Managers/ModelManager/ModelManager.cs b/UI_DSM/UI_DSM.Server/Managers/ModelManager/ModelManager.cs new file mode 100644 index 00000000..664c3d49 --- /dev/null +++ b/UI_DSM/UI_DSM.Server/Managers/ModelManager/ModelManager.cs @@ -0,0 +1,231 @@ +// -------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2022 RHEA System S.A. +// +// Author: Antoine Théate, Sam Gerené, Alex Vorobiev, Alexander van Delft, Martin Risseeuw +// +// This file is part of UI-DSM. +// The UI-DSM web application is used to review an ECSS-E-TM-10-25 model. +// +// The UI-DSM application is provided to the community under the Apache License 2.0. +// +// -------------------------------------------------------------------------------------------------------- + +namespace UI_DSM.Server.Managers.ModelManager +{ + using Microsoft.EntityFrameworkCore; + + using NLog; + + using UI_DSM.Server.Context; + using UI_DSM.Server.Extensions; + using UI_DSM.Server.Types; + using UI_DSM.Shared.DTO.Models; + using UI_DSM.Shared.Models; + + /// + /// This manager handles operation to the Database for s + /// + public class ModelManager : IModelManager + { + /// + /// The + /// + private readonly DatabaseContext context; + + /// + /// The logger + /// + private readonly Logger logger = LogManager.GetCurrentClassLogger(); + + /// + /// Initializes a new instance of the class. + /// + /// The + public ModelManager(DatabaseContext context) + { + this.context = context; + } + + /// + /// Gets a collection of all s and associated + /// + /// The level of deepnest that we need to retrieve associated + /// A with a collection of as result + public async Task> GetEntities(int deepLevel = 0) + { + var models = await this.context.Models.ToListAsync(); + return models.SelectMany(x => x.GetAssociatedEntities(deepLevel)).DistinctBy(x => x.Id); + } + + /// + /// Tries to get a based on its and its associated + /// + /// The + /// The level of deepnest that we need to retrieve associated + /// A with a collection of if found + public async Task> GetEntity(Guid entityId, int deepLevel = 0) + { + var model = await this.FindEntity(entityId); + return model == null ? Enumerable.Empty() : model.GetAssociatedEntities(deepLevel); + } + + /// + /// Tries to get a based on its + /// + /// The + /// A with the if found + public async Task FindEntity(Guid entityId) + { + return await this.context.Models.FindAsync(entityId); + } + + /// + /// Tries to get all based on their + /// + /// A collection of + /// A collection of + public async Task> FindEntities(IEnumerable entitiesId) + { + var entities = new List(); + + foreach (var id in entitiesId) + { + var entity = await this.FindEntity(id); + + if (entity != null) + { + entities.Add(entity); + } + } + + return entities; + } + + /// + /// Creates a new and store it into the + /// + /// The to create + /// A with the result of the creation + public async Task> CreateEntity(Model entity) + { + var validations = this.context.ValidateModel(entity); + + if (validations.Any()) + { + return EntityOperationResult.Failed(validations.ToArray()); + } + + if (!await this.VerifyContainer(entity)) + { + return EntityOperationResult.Failed($"Unable to compute the container the current entity with the id {entity.Id}"); + } + + var operationResult = new EntityOperationResult(this.context.Add(entity), EntityState.Added); + + try + { + await this.context.SaveChangesAsync(); + } + catch (Exception exception) + { + if (ExceptionHelper.IsUniqueConstraintViolation(exception)) + { + operationResult.HandleExpection($"The Model {entity.FileName} is already exist"); + } + else + { + operationResult.HandleExpection(exception); + this.logger.Error(exception.Message); + } + } + + return operationResult; + } + + /// + /// Updates a + /// + /// The to update + /// A with the result of the update + public async Task> UpdateEntity(Model entity) + { + await Task.CompletedTask; + return EntityOperationResult.Failed("A Model cannot be updated"); + } + + /// + /// Deletes a + /// + /// The to delete + /// A with the result of the deletion + public async Task> DeleteEntity(Model entity) + { + await Task.CompletedTask; + return EntityOperationResult.Failed("A Model cannot be deleted"); + } + + /// + /// Resolve all properties for the + /// + /// The + /// The + /// A + public Task ResolveProperties(Model entity, EntityDto dto) + { + if (dto is not ModelDto modelDto) + { + return Task.CompletedTask; + } + + entity.ResolveProperties(modelDto, new Dictionary()); + return Task.CompletedTask; + } + + /// + /// Finds an and includes his container + /// + /// The id + /// A with the + public async Task FindEntityWithContainer(Guid entityId) + { + return await this.context.Models.Where(x => x.Id == entityId) + .Include(x => x.EntityContainer).FirstOrDefaultAsync(); + } + + /// + /// Gets all that are contained by the with the Id + /// and associated + /// + /// The of the container + /// The deep level + /// A with a collection of + public async Task> GetContainedEntities(Guid containerId, int deepLevel = 0) + { + var models = await this.context.Models.Where(x => x.EntityContainer != null && x.EntityContainer.Id == containerId).ToListAsync(); + return models.SelectMany(x => x.GetAssociatedEntities(deepLevel)).DistinctBy(x => x.Id); + } + + /// + /// Verifies if the container of the has the given + /// + /// The of the + /// The of the container + /// A with the value of the check + public async Task EntityIsContainedBy(Guid entityId, Guid containerId) + { + var model = await this.FindEntityWithContainer(entityId); + return model != null && model.EntityContainer.Id == containerId; + } + + /// + /// Check if the container of the exists inside the database + /// + /// The + /// A with the result of the check + private async Task VerifyContainer(Entity entity) + { + return entity.EntityContainer != null && await this.context.Projects.FindAsync(entity.EntityContainer.Id) != null; + } + } +} diff --git a/UI_DSM/UI_DSM.Server/Managers/ProjectManager/ProjectManager.cs b/UI_DSM/UI_DSM.Server/Managers/ProjectManager/ProjectManager.cs index 44cc8193..0e381ca7 100644 --- a/UI_DSM/UI_DSM.Server/Managers/ProjectManager/ProjectManager.cs +++ b/UI_DSM/UI_DSM.Server/Managers/ProjectManager/ProjectManager.cs @@ -20,6 +20,7 @@ namespace UI_DSM.Server.Managers.ProjectManager using UI_DSM.Server.Context; using UI_DSM.Server.Extensions; using UI_DSM.Server.Managers.AnnotationManager; + using UI_DSM.Server.Managers.ArtifactManager; using UI_DSM.Server.Managers.ParticipantManager; using UI_DSM.Server.Managers.ReviewManager; using UI_DSM.Server.Types; @@ -31,6 +32,16 @@ namespace UI_DSM.Server.Managers.ProjectManager /// public class ProjectManager : IProjectManager { + /// + /// The + /// + private readonly IAnnotationManager annotationManager; + + /// + /// The + /// + private readonly IArtifactManager artifactManager; + /// /// The /// @@ -51,24 +62,22 @@ public class ProjectManager : IProjectManager /// private readonly IReviewManager reviewManager; - /// - /// The - /// - private readonly IAnnotationManager annotationManager; - /// /// Initializes a new instance of the class. /// /// The /// The - /// The - /// The - public ProjectManager(DatabaseContext context, IParticipantManager participantManager, IReviewManager reviewManager, IAnnotationManager annotationManager) + /// The + /// The + /// The + public ProjectManager(DatabaseContext context, IParticipantManager participantManager, IReviewManager reviewManager, + IAnnotationManager annotationManager, IArtifactManager artifactManager) { this.context = context; this.participantManager = participantManager; this.reviewManager = reviewManager; this.annotationManager = annotationManager; + this.artifactManager = artifactManager; } /// @@ -229,13 +238,14 @@ public async Task ResolveProperties(Project entity, EntityDto dto) relatedEntities.InsertEntityCollection(await this.participantManager.FindEntities(projectDto.Participants)); relatedEntities.InsertEntityCollection(await this.reviewManager.FindEntities(projectDto.Reviews)); relatedEntities.InsertEntityCollection(await this.annotationManager.FindEntities(projectDto.Annotations)); + relatedEntities.InsertEntityCollection(await this.artifactManager.FindEntities(projectDto.Artifacts)); entity.ResolveProperties(projectDto, relatedEntities); } /// /// Get a collection of where a is a /// - /// The name of the + /// The name of the /// A with a collection of public async Task> GetAvailableProjectsForUser(string userName) { diff --git a/UI_DSM/UI_DSM.Server/Managers/ReviewManager/ReviewManager.cs b/UI_DSM/UI_DSM.Server/Managers/ReviewManager/ReviewManager.cs index 495d7c6b..22775be5 100644 --- a/UI_DSM/UI_DSM.Server/Managers/ReviewManager/ReviewManager.cs +++ b/UI_DSM/UI_DSM.Server/Managers/ReviewManager/ReviewManager.cs @@ -19,6 +19,7 @@ namespace UI_DSM.Server.Managers.ReviewManager using UI_DSM.Server.Context; using UI_DSM.Server.Extensions; + using UI_DSM.Server.Managers.ArtifactManager; using UI_DSM.Server.Managers.ParticipantManager; using UI_DSM.Server.Managers.ReviewObjectiveManager; using UI_DSM.Server.Types; @@ -31,6 +32,11 @@ namespace UI_DSM.Server.Managers.ReviewManager /// public class ReviewManager : IReviewManager { + /// + /// The + /// + private readonly IArtifactManager artifactManager; + /// /// The /// @@ -56,12 +62,15 @@ public class ReviewManager : IReviewManager /// /// The /// The - /// The - public ReviewManager(DatabaseContext context, IParticipantManager participantManager, IReviewObjectiveManager reviewObjectiveManager) + /// The + /// The + public ReviewManager(DatabaseContext context, IParticipantManager participantManager, IReviewObjectiveManager reviewObjectiveManager, + IArtifactManager artifactManager) { this.context = context; this.participantManager = participantManager; this.reviewObjectiveManager = reviewObjectiveManager; + this.artifactManager = artifactManager; } /// @@ -232,6 +241,7 @@ public async Task ResolveProperties(Review entity, EntityDto dto) var relatedEntities = new Dictionary(); relatedEntities.InsertEntity(await this.participantManager.FindEntity(reviewDto.Author)); relatedEntities.InsertEntityCollection(await this.reviewObjectiveManager.FindEntities(reviewDto.ReviewObjectives)); + relatedEntities.InsertEntityCollection(await this.artifactManager.FindEntities(reviewDto.Artifacts)); entity.ResolveProperties(reviewDto, relatedEntities); } diff --git a/UI_DSM/UI_DSM.Server/Migrations/20220922150534_ModelMigration.Designer.cs b/UI_DSM/UI_DSM.Server/Migrations/20220922150534_ModelMigration.Designer.cs new file mode 100644 index 00000000..0d00e96b --- /dev/null +++ b/UI_DSM/UI_DSM.Server/Migrations/20220922150534_ModelMigration.Designer.cs @@ -0,0 +1,1003 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; +using UI_DSM.Server.Context; + +#nullable disable + +namespace UI_DSM.Server.Migrations +{ + [DbContext(typeof(DatabaseContext))] + [Migration("20220922150534_ModelMigration")] + partial class ModelMigration + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "6.0.7") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("AnnotatableItemAnnotation", b => + { + b.Property("AnnotatableItemsId") + .HasColumnType("uuid"); + + b.Property("AnnotationsId") + .HasColumnType("uuid"); + + b.HasKey("AnnotatableItemsId", "AnnotationsId"); + + b.HasIndex("AnnotationsId"); + + b.ToTable("AnnotatableItemAnnotation"); + }); + + modelBuilder.Entity("ArtifactReview", b => + { + b.Property("ArtifactsId") + .HasColumnType("uuid"); + + b.Property("ReviewsId") + .HasColumnType("uuid"); + + b.HasKey("ArtifactsId", "ReviewsId"); + + b.HasIndex("ReviewsId"); + + b.ToTable("ArtifactReview"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("text"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex"); + + b.ToTable("AspNetRoles", (string)null); + + b.HasData( + new + { + Id = "AF8956F8-CA85-4DF2-8CB6-C46D0845B987", + ConcurrencyStamp = "bdaed18c-5e74-46bd-8536-c1255071fd03", + Name = "Administrator", + NormalizedName = "ADMINISTRATOR" + }); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("text"); + + b.Property("ClaimValue") + .HasColumnType("text"); + + b.Property("RoleId") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("text"); + + b.Property("ClaimValue") + .HasColumnType("text"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("text"); + + b.Property("ProviderKey") + .HasColumnType("text"); + + b.Property("ProviderDisplayName") + .HasColumnType("text"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("text"); + + b.Property("RoleId") + .HasColumnType("text"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles", (string)null); + + b.HasData( + new + { + UserId = "F3E3BACF-5F7C-4657-88E9-FA904EFB64D7", + RoleId = "AF8956F8-CA85-4DF2-8CB6-C46D0845B987" + }); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("text"); + + b.Property("LoginProvider") + .HasColumnType("text"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("Value") + .HasColumnType("text"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens", (string)null); + }); + + modelBuilder.Entity("UI_DSM.Shared.Models.Entity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.ToTable("Entity"); + }); + + modelBuilder.Entity("UI_DSM.Shared.Models.User", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("AccessFailedCount") + .HasColumnType("integer"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("text"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("EmailConfirmed") + .HasColumnType("boolean"); + + b.Property("IsAdmin") + .HasColumnType("boolean"); + + b.Property("LockoutEnabled") + .HasColumnType("boolean"); + + b.Property("LockoutEnd") + .HasColumnType("timestamp with time zone"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("PasswordHash") + .HasColumnType("text"); + + b.Property("PhoneNumber") + .HasColumnType("text"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("boolean"); + + b.Property("SecurityStamp") + .HasColumnType("text"); + + b.Property("TwoFactorEnabled") + .HasColumnType("boolean"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex"); + + b.ToTable("AspNetUsers", (string)null); + + b.HasData( + new + { + Id = "F3E3BACF-5F7C-4657-88E9-FA904EFB64D7", + AccessFailedCount = 0, + ConcurrencyStamp = "3f1e53a3-5e68-4514-b53a-5f2afba551f1", + EmailConfirmed = false, + IsAdmin = true, + LockoutEnabled = false, + NormalizedUserName = "ADMIN", + PasswordHash = "AQAAAAEAACcQAAAAEDr2GVdqM38+1tymdhti7jnMdCMq/DgMJicqe7P1sRgZ50asePWsDN40KjHaC59odw==", + PhoneNumberConfirmed = false, + SecurityStamp = "facbc854-1ec0-4c4d-8a08-0551243724d4", + TwoFactorEnabled = false, + UserName = "admin" + }); + }); + + modelBuilder.Entity("UI_DSM.Shared.Models.AnnotatableItem", b => + { + b.HasBaseType("UI_DSM.Shared.Models.Entity"); + + b.Property("AuthorId") + .HasColumnType("uuid"); + + b.Property("CreatedOn") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone"); + + b.HasIndex("AuthorId"); + + b.ToTable("AnnotatableItem"); + }); + + modelBuilder.Entity("UI_DSM.Shared.Models.Annotation", b => + { + b.HasBaseType("UI_DSM.Shared.Models.Entity"); + + b.Property("AuthorId") + .HasColumnType("uuid"); + + b.Property("Content") + .IsRequired() + .HasColumnType("text"); + + b.Property("CreatedOn") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone"); + + b.Property("EntityContainerId") + .HasColumnType("uuid"); + + b.HasIndex("AuthorId"); + + b.HasIndex("EntityContainerId"); + + b.ToTable("Annotation"); + }); + + modelBuilder.Entity("UI_DSM.Shared.Models.Artifact", b => + { + b.HasBaseType("UI_DSM.Shared.Models.Entity"); + + b.Property("EntityContainerId") + .HasColumnType("uuid"); + + b.Property("FileName") + .ValueGeneratedOnAdd() + .HasColumnType("text"); + + b.HasIndex("EntityContainerId"); + + b.ToTable("Artifact"); + }); + + modelBuilder.Entity("UI_DSM.Shared.Models.Participant", b => + { + b.HasBaseType("UI_DSM.Shared.Models.Entity"); + + b.Property("EntityContainerId") + .HasColumnType("uuid"); + + b.Property("RoleId") + .HasColumnType("uuid"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasIndex("EntityContainerId"); + + b.HasIndex("RoleId"); + + b.HasIndex("UserId"); + + b.ToTable("Participant"); + }); + + modelBuilder.Entity("UI_DSM.Shared.Models.Project", b => + { + b.HasBaseType("UI_DSM.Shared.Models.Entity"); + + b.Property("EntityContainerId") + .HasColumnType("uuid"); + + b.Property("ProjectName") + .IsRequired() + .HasColumnType("text"); + + b.HasIndex("EntityContainerId"); + + b.HasIndex("ProjectName") + .IsUnique(); + + b.ToTable("Project"); + }); + + modelBuilder.Entity("UI_DSM.Shared.Models.Reply", b => + { + b.HasBaseType("UI_DSM.Shared.Models.Entity"); + + b.Property("AuthorId") + .HasColumnType("uuid"); + + b.Property("Content") + .IsRequired() + .HasColumnType("text"); + + b.Property("CreatedOn") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone"); + + b.Property("EntityContainerId") + .HasColumnType("uuid"); + + b.HasIndex("AuthorId"); + + b.HasIndex("EntityContainerId"); + + b.ToTable("Reply"); + }); + + modelBuilder.Entity("UI_DSM.Shared.Models.Review", b => + { + b.HasBaseType("UI_DSM.Shared.Models.Entity"); + + b.Property("AuthorId") + .HasColumnType("uuid"); + + b.Property("CreatedOn") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("EntityContainerId") + .HasColumnType("uuid"); + + b.Property("ReviewNumber") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("ReviewNumber")); + + b.Property("Status") + .HasColumnType("integer"); + + b.Property("Title") + .IsRequired() + .HasColumnType("text"); + + b.HasIndex("AuthorId"); + + b.HasIndex("EntityContainerId"); + + b.ToTable("Review"); + }); + + modelBuilder.Entity("UI_DSM.Shared.Models.ReviewTask", b => + { + b.HasBaseType("UI_DSM.Shared.Models.Entity"); + + b.Property("AuthorId") + .HasColumnType("uuid"); + + b.Property("CreatedOn") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("EntityContainerId") + .HasColumnType("uuid"); + + b.Property("IsAssignedToId") + .HasColumnType("uuid"); + + b.Property("Status") + .HasColumnType("integer"); + + b.Property("TaskNumber") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("TaskNumber")); + + b.Property("Title") + .IsRequired() + .HasColumnType("text"); + + b.HasIndex("AuthorId"); + + b.HasIndex("EntityContainerId"); + + b.HasIndex("IsAssignedToId"); + + b.ToTable("ReviewTask"); + }); + + modelBuilder.Entity("UI_DSM.Shared.Models.Role", b => + { + b.HasBaseType("UI_DSM.Shared.Models.Entity"); + + b.Property("AccessRights") + .IsRequired() + .HasColumnType("integer[]"); + + b.Property("EntityContainerId") + .HasColumnType("uuid"); + + b.Property("RoleName") + .IsRequired() + .HasColumnType("text"); + + b.HasIndex("EntityContainerId"); + + b.HasIndex("RoleName") + .IsUnique(); + + b.ToTable("Role"); + + b.HasData( + new + { + Id = new Guid("fd580a55-9666-4abe-a02b-3a99478996f7"), + AccessRights = new[] { 0, 1, 2, 3 }, + RoleName = "Project Administrator" + }, + new + { + Id = new Guid("28b83519-fb7c-4a9a-8279-194140bfcfbe"), + AccessRights = new[] { 4 }, + RoleName = "Reviewer" + }); + }); + + modelBuilder.Entity("UI_DSM.Shared.Models.UserEntity", b => + { + b.HasBaseType("UI_DSM.Shared.Models.Entity"); + + b.Property("EntityContainerId") + .HasColumnType("uuid"); + + b.Property("IsAdmin") + .HasColumnType("boolean"); + + b.Property("UserId") + .HasColumnType("text"); + + b.Property("UserName") + .HasColumnType("text"); + + b.HasIndex("EntityContainerId"); + + b.HasIndex("UserId"); + + b.ToTable("UserEntity"); + + b.HasData( + new + { + Id = new Guid("3503bf4c-1211-41eb-b369-aaa6bbdf5ff8"), + IsAdmin = true, + UserId = "F3E3BACF-5F7C-4657-88E9-FA904EFB64D7", + UserName = "admin" + }); + }); + + modelBuilder.Entity("UI_DSM.Shared.Models.Comment", b => + { + b.HasBaseType("UI_DSM.Shared.Models.Annotation"); + + b.ToTable("Comment"); + }); + + modelBuilder.Entity("UI_DSM.Shared.Models.Feedback", b => + { + b.HasBaseType("UI_DSM.Shared.Models.Annotation"); + + b.ToTable("Feedback"); + }); + + modelBuilder.Entity("UI_DSM.Shared.Models.Model", b => + { + b.HasBaseType("UI_DSM.Shared.Models.Artifact"); + + b.Property("ModelName") + .ValueGeneratedOnAdd() + .HasColumnType("text"); + + b.ToTable("Model"); + }); + + modelBuilder.Entity("UI_DSM.Shared.Models.Note", b => + { + b.HasBaseType("UI_DSM.Shared.Models.Annotation"); + + b.ToTable("Note"); + }); + + modelBuilder.Entity("UI_DSM.Shared.Models.ReviewObjective", b => + { + b.HasBaseType("UI_DSM.Shared.Models.AnnotatableItem"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("EntityContainerId") + .HasColumnType("uuid"); + + b.Property("ReviewObjectiveNumber") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("ReviewObjectiveNumber")); + + b.Property("Status") + .HasColumnType("integer"); + + b.Property("Title") + .IsRequired() + .HasColumnType("text"); + + b.HasIndex("EntityContainerId"); + + b.ToTable("ReviewObjective"); + }); + + modelBuilder.Entity("AnnotatableItemAnnotation", b => + { + b.HasOne("UI_DSM.Shared.Models.AnnotatableItem", null) + .WithMany() + .HasForeignKey("AnnotatableItemsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("UI_DSM.Shared.Models.Annotation", null) + .WithMany() + .HasForeignKey("AnnotationsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ArtifactReview", b => + { + b.HasOne("UI_DSM.Shared.Models.Artifact", null) + .WithMany() + .HasForeignKey("ArtifactsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("UI_DSM.Shared.Models.Review", null) + .WithMany() + .HasForeignKey("ReviewsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("UI_DSM.Shared.Models.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("UI_DSM.Shared.Models.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("UI_DSM.Shared.Models.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("UI_DSM.Shared.Models.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("UI_DSM.Shared.Models.AnnotatableItem", b => + { + b.HasOne("UI_DSM.Shared.Models.Participant", "Author") + .WithMany() + .HasForeignKey("AuthorId"); + + b.HasOne("UI_DSM.Shared.Models.Entity", null) + .WithOne() + .HasForeignKey("UI_DSM.Shared.Models.AnnotatableItem", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Author"); + }); + + modelBuilder.Entity("UI_DSM.Shared.Models.Annotation", b => + { + b.HasOne("UI_DSM.Shared.Models.Participant", "Author") + .WithMany() + .HasForeignKey("AuthorId"); + + b.HasOne("UI_DSM.Shared.Models.Project", "EntityContainer") + .WithMany("Annotations") + .HasForeignKey("EntityContainerId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("UI_DSM.Shared.Models.Entity", null) + .WithOne() + .HasForeignKey("UI_DSM.Shared.Models.Annotation", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Author"); + + b.Navigation("EntityContainer"); + }); + + modelBuilder.Entity("UI_DSM.Shared.Models.Artifact", b => + { + b.HasOne("UI_DSM.Shared.Models.Project", "EntityContainer") + .WithMany("Artifacts") + .HasForeignKey("EntityContainerId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("UI_DSM.Shared.Models.Entity", null) + .WithOne() + .HasForeignKey("UI_DSM.Shared.Models.Artifact", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("EntityContainer"); + }); + + modelBuilder.Entity("UI_DSM.Shared.Models.Participant", b => + { + b.HasOne("UI_DSM.Shared.Models.Project", "EntityContainer") + .WithMany("Participants") + .HasForeignKey("EntityContainerId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("UI_DSM.Shared.Models.Entity", null) + .WithOne() + .HasForeignKey("UI_DSM.Shared.Models.Participant", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("UI_DSM.Shared.Models.Role", "Role") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("UI_DSM.Shared.Models.UserEntity", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("EntityContainer"); + + b.Navigation("Role"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("UI_DSM.Shared.Models.Project", b => + { + b.HasOne("UI_DSM.Shared.Models.Entity", "EntityContainer") + .WithMany() + .HasForeignKey("EntityContainerId"); + + b.HasOne("UI_DSM.Shared.Models.Entity", null) + .WithOne() + .HasForeignKey("UI_DSM.Shared.Models.Project", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("EntityContainer"); + }); + + modelBuilder.Entity("UI_DSM.Shared.Models.Reply", b => + { + b.HasOne("UI_DSM.Shared.Models.Participant", "Author") + .WithMany() + .HasForeignKey("AuthorId"); + + b.HasOne("UI_DSM.Shared.Models.Comment", "EntityContainer") + .WithMany("Replies") + .HasForeignKey("EntityContainerId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("UI_DSM.Shared.Models.Entity", null) + .WithOne() + .HasForeignKey("UI_DSM.Shared.Models.Reply", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Author"); + + b.Navigation("EntityContainer"); + }); + + modelBuilder.Entity("UI_DSM.Shared.Models.Review", b => + { + b.HasOne("UI_DSM.Shared.Models.Participant", "Author") + .WithMany() + .HasForeignKey("AuthorId"); + + b.HasOne("UI_DSM.Shared.Models.Project", "EntityContainer") + .WithMany("Reviews") + .HasForeignKey("EntityContainerId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("UI_DSM.Shared.Models.Entity", null) + .WithOne() + .HasForeignKey("UI_DSM.Shared.Models.Review", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Author"); + + b.Navigation("EntityContainer"); + }); + + modelBuilder.Entity("UI_DSM.Shared.Models.ReviewTask", b => + { + b.HasOne("UI_DSM.Shared.Models.Participant", "Author") + .WithMany() + .HasForeignKey("AuthorId"); + + b.HasOne("UI_DSM.Shared.Models.ReviewObjective", "EntityContainer") + .WithMany("ReviewTasks") + .HasForeignKey("EntityContainerId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("UI_DSM.Shared.Models.Entity", null) + .WithOne() + .HasForeignKey("UI_DSM.Shared.Models.ReviewTask", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("UI_DSM.Shared.Models.Participant", "IsAssignedTo") + .WithMany() + .HasForeignKey("IsAssignedToId"); + + b.Navigation("Author"); + + b.Navigation("EntityContainer"); + + b.Navigation("IsAssignedTo"); + }); + + modelBuilder.Entity("UI_DSM.Shared.Models.Role", b => + { + b.HasOne("UI_DSM.Shared.Models.Entity", "EntityContainer") + .WithMany() + .HasForeignKey("EntityContainerId"); + + b.HasOne("UI_DSM.Shared.Models.Entity", null) + .WithOne() + .HasForeignKey("UI_DSM.Shared.Models.Role", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("EntityContainer"); + }); + + modelBuilder.Entity("UI_DSM.Shared.Models.UserEntity", b => + { + b.HasOne("UI_DSM.Shared.Models.Entity", "EntityContainer") + .WithMany() + .HasForeignKey("EntityContainerId"); + + b.HasOne("UI_DSM.Shared.Models.Entity", null) + .WithOne() + .HasForeignKey("UI_DSM.Shared.Models.UserEntity", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("UI_DSM.Shared.Models.User", "User") + .WithMany() + .HasForeignKey("UserId"); + + b.Navigation("EntityContainer"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("UI_DSM.Shared.Models.Comment", b => + { + b.HasOne("UI_DSM.Shared.Models.Annotation", null) + .WithOne() + .HasForeignKey("UI_DSM.Shared.Models.Comment", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("UI_DSM.Shared.Models.Feedback", b => + { + b.HasOne("UI_DSM.Shared.Models.Annotation", null) + .WithOne() + .HasForeignKey("UI_DSM.Shared.Models.Feedback", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("UI_DSM.Shared.Models.Model", b => + { + b.HasOne("UI_DSM.Shared.Models.Artifact", null) + .WithOne() + .HasForeignKey("UI_DSM.Shared.Models.Model", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("UI_DSM.Shared.Models.Note", b => + { + b.HasOne("UI_DSM.Shared.Models.Annotation", null) + .WithOne() + .HasForeignKey("UI_DSM.Shared.Models.Note", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("UI_DSM.Shared.Models.ReviewObjective", b => + { + b.HasOne("UI_DSM.Shared.Models.Review", "EntityContainer") + .WithMany("ReviewObjectives") + .HasForeignKey("EntityContainerId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("UI_DSM.Shared.Models.AnnotatableItem", null) + .WithOne() + .HasForeignKey("UI_DSM.Shared.Models.ReviewObjective", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("EntityContainer"); + }); + + modelBuilder.Entity("UI_DSM.Shared.Models.Project", b => + { + b.Navigation("Annotations"); + + b.Navigation("Artifacts"); + + b.Navigation("Participants"); + + b.Navigation("Reviews"); + }); + + modelBuilder.Entity("UI_DSM.Shared.Models.Review", b => + { + b.Navigation("ReviewObjectives"); + }); + + modelBuilder.Entity("UI_DSM.Shared.Models.Comment", b => + { + b.Navigation("Replies"); + }); + + modelBuilder.Entity("UI_DSM.Shared.Models.ReviewObjective", b => + { + b.Navigation("ReviewTasks"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/UI_DSM/UI_DSM.Server/Migrations/20220922150534_ModelMigration.cs b/UI_DSM/UI_DSM.Server/Migrations/20220922150534_ModelMigration.cs new file mode 100644 index 00000000..fe705f0a --- /dev/null +++ b/UI_DSM/UI_DSM.Server/Migrations/20220922150534_ModelMigration.cs @@ -0,0 +1,133 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace UI_DSM.Server.Migrations +{ + using System.Diagnostics.CodeAnalysis; + + [ExcludeFromCodeCoverage] + public partial class ModelMigration : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "Artifact", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false), + FileName = table.Column(type: "text", nullable: true), + EntityContainerId = table.Column(type: "uuid", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Artifact", x => x.Id); + table.ForeignKey( + name: "FK_Artifact_Entity_Id", + column: x => x.Id, + principalTable: "Entity", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_Artifact_Project_EntityContainerId", + column: x => x.EntityContainerId, + principalTable: "Project", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "ArtifactReview", + columns: table => new + { + ArtifactsId = table.Column(type: "uuid", nullable: false), + ReviewsId = table.Column(type: "uuid", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_ArtifactReview", x => new { x.ArtifactsId, x.ReviewsId }); + table.ForeignKey( + name: "FK_ArtifactReview_Artifact_ArtifactsId", + column: x => x.ArtifactsId, + principalTable: "Artifact", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_ArtifactReview_Review_ReviewsId", + column: x => x.ReviewsId, + principalTable: "Review", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "Model", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false), + ModelName = table.Column(type: "text", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Model", x => x.Id); + table.ForeignKey( + name: "FK_Model_Artifact_Id", + column: x => x.Id, + principalTable: "Artifact", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.UpdateData( + table: "AspNetRoles", + keyColumn: "Id", + keyValue: "AF8956F8-CA85-4DF2-8CB6-C46D0845B987", + column: "ConcurrencyStamp", + value: "bdaed18c-5e74-46bd-8536-c1255071fd03"); + + migrationBuilder.UpdateData( + table: "AspNetUsers", + keyColumn: "Id", + keyValue: "F3E3BACF-5F7C-4657-88E9-FA904EFB64D7", + columns: new[] { "ConcurrencyStamp", "PasswordHash", "SecurityStamp" }, + values: new object[] { "3f1e53a3-5e68-4514-b53a-5f2afba551f1", "AQAAAAEAACcQAAAAEDr2GVdqM38+1tymdhti7jnMdCMq/DgMJicqe7P1sRgZ50asePWsDN40KjHaC59odw==", "facbc854-1ec0-4c4d-8a08-0551243724d4" }); + + migrationBuilder.CreateIndex( + name: "IX_Artifact_EntityContainerId", + table: "Artifact", + column: "EntityContainerId"); + + migrationBuilder.CreateIndex( + name: "IX_ArtifactReview_ReviewsId", + table: "ArtifactReview", + column: "ReviewsId"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "ArtifactReview"); + + migrationBuilder.DropTable( + name: "Model"); + + migrationBuilder.DropTable( + name: "Artifact"); + + migrationBuilder.UpdateData( + table: "AspNetRoles", + keyColumn: "Id", + keyValue: "AF8956F8-CA85-4DF2-8CB6-C46D0845B987", + column: "ConcurrencyStamp", + value: "9a2b04bc-fbf1-4bbb-aef3-214084843ecd"); + + migrationBuilder.UpdateData( + table: "AspNetUsers", + keyColumn: "Id", + keyValue: "F3E3BACF-5F7C-4657-88E9-FA904EFB64D7", + columns: new[] { "ConcurrencyStamp", "PasswordHash", "SecurityStamp" }, + values: new object[] { "4a038e0b-f742-4b04-95fd-2de6f7895f23", "AQAAAAEAACcQAAAAEDQkHLx6aVgzvBDau1UCK8kmQ9nCCLdpmx/7Daop5C5Oo5ntq+2S7l3+WTFjSp0rug==", "ef330ed2-78fa-47d2-b15d-f94b6e75a9c1" }); + } + } +} diff --git a/UI_DSM/UI_DSM.Server/Migrations/DatabaseContextModelSnapshot.cs b/UI_DSM/UI_DSM.Server/Migrations/DatabaseContextModelSnapshot.cs index d33e759a..c0b2ca5b 100644 --- a/UI_DSM/UI_DSM.Server/Migrations/DatabaseContextModelSnapshot.cs +++ b/UI_DSM/UI_DSM.Server/Migrations/DatabaseContextModelSnapshot.cs @@ -40,6 +40,21 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("AnnotatableItemAnnotation"); }); + modelBuilder.Entity("ArtifactReview", b => + { + b.Property("ArtifactsId") + .HasColumnType("uuid"); + + b.Property("ReviewsId") + .HasColumnType("uuid"); + + b.HasKey("ArtifactsId", "ReviewsId"); + + b.HasIndex("ReviewsId"); + + b.ToTable("ArtifactReview"); + }); + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => { b.Property("Id") @@ -69,7 +84,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) new { Id = "AF8956F8-CA85-4DF2-8CB6-C46D0845B987", - ConcurrencyStamp = "9a2b04bc-fbf1-4bbb-aef3-214084843ecd", + ConcurrencyStamp = "bdaed18c-5e74-46bd-8536-c1255071fd03", Name = "Administrator", NormalizedName = "ADMINISTRATOR" }); @@ -270,14 +285,14 @@ protected override void BuildModel(ModelBuilder modelBuilder) { Id = "F3E3BACF-5F7C-4657-88E9-FA904EFB64D7", AccessFailedCount = 0, - ConcurrencyStamp = "4a038e0b-f742-4b04-95fd-2de6f7895f23", + ConcurrencyStamp = "3f1e53a3-5e68-4514-b53a-5f2afba551f1", EmailConfirmed = false, IsAdmin = true, LockoutEnabled = false, NormalizedUserName = "ADMIN", - PasswordHash = "AQAAAAEAACcQAAAAEDQkHLx6aVgzvBDau1UCK8kmQ9nCCLdpmx/7Daop5C5Oo5ntq+2S7l3+WTFjSp0rug==", + PasswordHash = "AQAAAAEAACcQAAAAEDr2GVdqM38+1tymdhti7jnMdCMq/DgMJicqe7P1sRgZ50asePWsDN40KjHaC59odw==", PhoneNumberConfirmed = false, - SecurityStamp = "ef330ed2-78fa-47d2-b15d-f94b6e75a9c1", + SecurityStamp = "facbc854-1ec0-4c4d-8a08-0551243724d4", TwoFactorEnabled = false, UserName = "admin" }); @@ -324,6 +339,22 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("Annotation"); }); + modelBuilder.Entity("UI_DSM.Shared.Models.Artifact", b => + { + b.HasBaseType("UI_DSM.Shared.Models.Entity"); + + b.Property("EntityContainerId") + .HasColumnType("uuid"); + + b.Property("FileName") + .ValueGeneratedOnAdd() + .HasColumnType("text"); + + b.HasIndex("EntityContainerId"); + + b.ToTable("Artifact"); + }); + modelBuilder.Entity("UI_DSM.Shared.Models.Participant", b => { b.HasBaseType("UI_DSM.Shared.Models.Entity"); @@ -554,6 +585,17 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("Feedback"); }); + modelBuilder.Entity("UI_DSM.Shared.Models.Model", b => + { + b.HasBaseType("UI_DSM.Shared.Models.Artifact"); + + b.Property("ModelName") + .ValueGeneratedOnAdd() + .HasColumnType("text"); + + b.ToTable("Model"); + }); + modelBuilder.Entity("UI_DSM.Shared.Models.Note", b => { b.HasBaseType("UI_DSM.Shared.Models.Annotation"); @@ -605,6 +647,21 @@ protected override void BuildModel(ModelBuilder modelBuilder) .IsRequired(); }); + modelBuilder.Entity("ArtifactReview", b => + { + b.HasOne("UI_DSM.Shared.Models.Artifact", null) + .WithMany() + .HasForeignKey("ArtifactsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("UI_DSM.Shared.Models.Review", null) + .WithMany() + .HasForeignKey("ReviewsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => { b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) @@ -693,6 +750,22 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Navigation("EntityContainer"); }); + modelBuilder.Entity("UI_DSM.Shared.Models.Artifact", b => + { + b.HasOne("UI_DSM.Shared.Models.Project", "EntityContainer") + .WithMany("Artifacts") + .HasForeignKey("EntityContainerId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("UI_DSM.Shared.Models.Entity", null) + .WithOne() + .HasForeignKey("UI_DSM.Shared.Models.Artifact", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("EntityContainer"); + }); + modelBuilder.Entity("UI_DSM.Shared.Models.Participant", b => { b.HasOne("UI_DSM.Shared.Models.Project", "EntityContainer") @@ -866,6 +939,15 @@ protected override void BuildModel(ModelBuilder modelBuilder) .IsRequired(); }); + modelBuilder.Entity("UI_DSM.Shared.Models.Model", b => + { + b.HasOne("UI_DSM.Shared.Models.Artifact", null) + .WithOne() + .HasForeignKey("UI_DSM.Shared.Models.Model", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + modelBuilder.Entity("UI_DSM.Shared.Models.Note", b => { b.HasOne("UI_DSM.Shared.Models.Annotation", null) @@ -895,6 +977,8 @@ protected override void BuildModel(ModelBuilder modelBuilder) { b.Navigation("Annotations"); + b.Navigation("Artifacts"); + b.Navigation("Participants"); b.Navigation("Reviews"); diff --git a/UI_DSM/UI_DSM.Server/Modules/ArtifactModule.cs b/UI_DSM/UI_DSM.Server/Modules/ArtifactModule.cs new file mode 100644 index 00000000..267e502f --- /dev/null +++ b/UI_DSM/UI_DSM.Server/Modules/ArtifactModule.cs @@ -0,0 +1,188 @@ +// -------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2022 RHEA System S.A. +// +// Author: Antoine Théate, Sam Gerené, Alex Vorobiev, Alexander van Delft, Martin Risseeuw, Nabil Abbar +// +// This file is part of UI-DSM. +// The UI-DSM web application is used to review an ECSS-E-TM-10-25 model. +// +// The UI-DSM application is provided to the community under the Apache License 2.0. +// +// -------------------------------------------------------------------------------------------------------- + +namespace UI_DSM.Server.Modules +{ + using Carter.Response; + + using Microsoft.AspNetCore.Authorization; + using Microsoft.AspNetCore.Components; + + using UI_DSM.Server.Managers; + using UI_DSM.Server.Services.FileService; + using UI_DSM.Shared.DTO.Common; + using UI_DSM.Shared.DTO.Models; + using UI_DSM.Shared.Models; + + /// + /// The is a + /// to manage + /// related to a + /// + [Route("api/Project/{projectId:guid}/Artifact")] + public class ArtifactModule : ContainedEntityModule + { + /// + /// The + /// + private readonly IFileService fileService; + + /// + /// Initializes a new instance of the class. + /// + /// The + public ArtifactModule(IFileService fileService) + { + this.fileService = fileService; + } + + /// + /// Gets a collection of all + /// + /// The + /// The + /// An optional parameters for the deep level + /// A + [Authorize] + public override Task GetEntities(IEntityManager manager, HttpContext context, int deepLevel = 0) + { + return base.GetEntities(manager, context, deepLevel); + } + + /// + /// Get a based on its with all associated entities + /// + /// The + /// The + /// The + /// An optional parameters for the deep level + /// A + [Authorize] + public override Task GetEntity(IEntityManager manager, Guid entityId, HttpContext context, int deepLevel = 0) + { + return base.GetEntity(manager, entityId, context, deepLevel); + } + + /// + /// Tries to create a new based on its + /// + /// The + /// The + /// The + /// An optional parameters for the deep level + /// A + [Authorize] + public override async Task CreateEntity(IEntityManager manager, ArtifactDto dto, HttpContext context, int deepLevel = 0) + { + var requestResponse = new EntityRequestResponseDto(); + + if (!this.fileService.TempFileExists(dto.FileName)) + { + context.Response.StatusCode = 404; + + requestResponse.Errors = new List + { + "Invalid artifact fileName" + }; + + await context.Response.Negotiate(requestResponse); + return; + } + + var projectId = this.GetAdditionalRouteId(context.Request, this.ContainerRouteKey); + + if (this.fileService.Exists(projectId.ToString(), dto.FileName)) + { + context.Response.StatusCode = 400; + + requestResponse.Errors = new List + { + "The artifact already exists !" + }; + + this.fileService.DeleteTemporaryFile(dto.FileName); + await context.Response.Negotiate(requestResponse); + return; + } + + if (dto is ModelDto && !await this.fileService.IsAnnexC3File(dto.FileName)) + { + context.Response.StatusCode = 400; + + requestResponse.Errors = new List + { + "The artifact is not a valid Annex C3 file" + }; + + this.fileService.DeleteTemporaryFile(dto.FileName); + await context.Response.Negotiate(requestResponse); + return; + } + + dto.FileName = this.fileService.MoveFile(dto.FileName, projectId.ToString()); + await base.CreateEntity(manager, dto, context, deepLevel); + } + + /// + /// Tries to delete an defined by the given + /// + /// The + /// The of the to delete + /// The + /// A with the as result + [Authorize] + public override async Task DeleteEntity(IEntityManager manager, Guid entityId, HttpContext context) + { + context.Response.StatusCode = 403; + await Task.CompletedTask; + return new RequestResponseDto { Errors = { "Forbidden to delete an artifact" } }; + } + + /// + /// Tries to update an existing + /// + /// The + /// The of the + /// The + /// The + /// An optional parameters for the deep level + /// A as result + [Authorize] + public override Task UpdateEntity(IEntityManager manager, Guid entityId, ArtifactDto dto, HttpContext context, int deepLevel = 0) + { + context.Response.StatusCode = 403; + return Task.CompletedTask; + } + + /// + /// Adds the into the corresponding collection of the + /// + /// The + /// The + protected override void AddEntityIntoContainerCollection(Artifact entity, Project container) + { + container.Artifacts.Add(entity); + } + + /// + /// Verifies if the provided routes is correctly formatted with all containment + /// + /// The + /// A with the result of the check + protected override async Task AdditionalRouteValidation(HttpContext context) + { + await Task.CompletedTask; + return true; + } + } +} diff --git a/UI_DSM/UI_DSM.Server/Modules/CometModule.cs b/UI_DSM/UI_DSM.Server/Modules/CometModule.cs new file mode 100644 index 00000000..fb5f8f75 --- /dev/null +++ b/UI_DSM/UI_DSM.Server/Modules/CometModule.cs @@ -0,0 +1,228 @@ +// -------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2022 RHEA System S.A. +// +// Author: Antoine Théate, Sam Gerené, Alex Vorobiev, Alexander van Delft, Martin Risseeuw, Nabil Abbar +// +// This file is part of UI-DSM. +// The UI-DSM web application is used to review an ECSS-E-TM-10-25 model. +// +// The UI-DSM application is provided to the community under the Apache License 2.0. +// +// -------------------------------------------------------------------------------------------------------- + +namespace UI_DSM.Server.Modules +{ + using System.Diagnostics.CodeAnalysis; + + using Carter.ModelBinding; + using Carter.Response; + + using CDP4Common.EngineeringModelData; + + using Microsoft.AspNetCore.Authorization; + using Microsoft.AspNetCore.Mvc; + + using UI_DSM.Client.Enumerator; + using UI_DSM.Server.Services.CometService; + using UI_DSM.Shared.DTO.CometData; + using UI_DSM.Shared.DTO.Common; + + /// + /// The is a module that handles a connection to a Comet server + /// to be able to download an + /// + [Microsoft.AspNetCore.Components.Route("api/Comet")] + public class CometModule : ModuleBase + { + /// + /// The + /// + private readonly ICometService cometService; + + /// + /// Initializes a new instance of the class. + /// + /// The + public CometModule(ICometService cometService) + { + this.cometService = cometService; + } + + /// + /// Adds routes to the + /// + /// The + [ExcludeFromCodeCoverage] + public override void AddRoutes(IEndpointRouteBuilder app) + { + app.MapPost($"{this.MainRoute}/Login", this.Login) + .Accepts("application/json") + .Produces() + .Produces(400) + .Produces(401) + .Produces(500) + .WithTags("Comet") + .WithName("Comet/Login"); + + app.MapGet(this.MainRoute + "/{sessionId:guid}/Models", this.GetAvailableEngineeringModels) + .Produces() + .Produces(404) + .WithTags("Comet") + .WithName("Comet/Models"); + + app.MapPost(this.MainRoute + "/{sessionId:guid}/Models/Upload", this.UploadIteration) + .Accepts("application/json") + .Produces() + .Produces(400) + .WithTags("Comet") + .WithName("Comet/Upload"); + + app.MapDelete(this.MainRoute + "/{sessionId:guid}", this.Logout) + .Produces() + .Produces(404) + .WithTags("Comet") + .WithName("Comet/Logout"); + } + + /// + /// Close the at the given + /// + /// The of the + /// The + /// A + [Authorize(Roles = "Administrator")] + public async Task Logout(Guid sessionId, HttpContext context) + { + var response = new RequestResponseDto(); + + try + { + await this.cometService.Close(sessionId); + response.IsRequestSuccessful = true; + } + catch (Exception exception) + { + response.Errors = new List { exception.Message }; + context.Response.StatusCode = 404; + } + + await context.Response.Negotiate(response); + } + + /// + /// Gets all available inside a that contains frozen + /// + /// + /// The of the + /// The + /// A + [Authorize(Roles = "Administrator")] + public async Task GetAvailableEngineeringModels(Guid sessionId, HttpContext context) + { + var response = new ModelsDataResponse(); + + try + { + var models = this.cometService.GetAvailableEngineeringModel(sessionId); + + foreach (var model in models) + { + var frozenIteration = model.IterationSetup.Where(iteration => !iteration.IsDeleted && iteration.FrozenOn != null); + + response.AvailableModels[model.Iid] = frozenIteration.Select(x => + new Tuple(x.IterationIid, $"Iteration {x.IterationNumber}")).ToList(); + + response.ModelNames[model.Iid] = model.Name; + } + } + catch (Exception exception) + { + context.Response.StatusCode = 404; + response.Errors = new List { exception.Message }; + } + + await context.Response.Negotiate(response); + } + + /// + /// Tries to log to a Comet session + /// + /// The to use to establish the connection + /// The + /// A + [Authorize(Roles = "Administrator")] + public async Task Login([FromBody] CometAuthenticationData authenticationData, HttpContext context) + { + var cometResponse = new CometAuthenticationResponse(); + var validationResult = context.Request.Validate(authenticationData); + + if (!validationResult.IsValid) + { + cometResponse.Errors = validationResult.Errors.Select(x => x.ErrorMessage).ToList(); + context.Response.StatusCode = 400; + await context.Response.Negotiate(cometResponse); + return; + } + + var result = await this.cometService.Login(authenticationData); + + switch (result.Item1) + { + case AuthenticationStatus.Success: + cometResponse.SessionId = result.Item2; + cometResponse.IsRequestSuccessful = true; + break; + case AuthenticationStatus.Fail: + cometResponse.Errors = new List { "Invalid username/password" }; + context.Response.StatusCode = 401; + break; + case AuthenticationStatus.ServerFailure: + cometResponse.Errors = new List { $"Comet server not reachable at the folling url {authenticationData.Url}" }; + context.Response.StatusCode = 500; + break; + } + + await context.Response.Negotiate(cometResponse); + } + + /// + /// Saves the selected into an Annex C3 file + /// + /// The of the + /// The + /// The + /// A + [Authorize(Roles = "Administrator")] + public async Task UploadIteration(Guid sessionId, [FromBody] ModelUploadData modelUpload, HttpContext context) + { + var response = new ModelUploadResponse(); + + var validationResult = context.Request.Validate(modelUpload); + + if (!validationResult.IsValid) + { + response.Errors = validationResult.Errors.Select(x => x.ErrorMessage).ToList(); + context.Response.StatusCode = 400; + await context.Response.Negotiate(response); + return; + } + + try + { + var iterationSetup = this.cometService.GetIterationSetup(sessionId, modelUpload.ModelId, modelUpload.IterationId); + var iteration = await this.cometService.ReadIteration(sessionId, iterationSetup); + var annexC3File = await this.cometService.CreateAnnexC3File(iteration); + response.UploadedFilePath = annexC3File; + response.IsRequestSuccessful = true; + } + catch (Exception exception) + { + context.Response.StatusCode = 400; + response.Errors = new List { exception.Message }; + } + + await context.Response.Negotiate(response); + } + } +} diff --git a/UI_DSM/UI_DSM.Server/Modules/ContainedEntityModule.cs b/UI_DSM/UI_DSM.Server/Modules/ContainedEntityModule.cs index 2051840d..ae91892f 100644 --- a/UI_DSM/UI_DSM.Server/Modules/ContainedEntityModule.cs +++ b/UI_DSM/UI_DSM.Server/Modules/ContainedEntityModule.cs @@ -84,7 +84,8 @@ public override async Task GetEntity(IEntityManager manager, Guid entit return; } - var entity = await manager.FindEntity(entityId); + var containedManager = manager as IContainedEntityManager; + var entity = await containedManager!.FindEntityWithContainer(entityId); if (entity == null) { diff --git a/UI_DSM/UI_DSM.Server/Modules/EntityModule.cs b/UI_DSM/UI_DSM.Server/Modules/EntityModule.cs index 607ecf98..b4c24069 100644 --- a/UI_DSM/UI_DSM.Server/Modules/EntityModule.cs +++ b/UI_DSM/UI_DSM.Server/Modules/EntityModule.cs @@ -20,6 +20,7 @@ namespace UI_DSM.Server.Modules using Microsoft.AspNetCore.Mvc; + using UI_DSM.Serializer.Json; using UI_DSM.Server.Managers; using UI_DSM.Server.Types; using UI_DSM.Shared.DTO.Common; @@ -65,7 +66,7 @@ public override void AddRoutes(IEndpointRouteBuilder app) .WithTags(this.EntityName) .WithName($"{this.EntityName}/GetEntity"); - app.MapPost($"{this.MainRoute}/Create", this.CreateEntity) + app.MapPost($"{this.MainRoute}/Create", this.ConvertEntityAndCreate) .Accepts("application/json") .Produces(201) .Produces(422) @@ -80,7 +81,7 @@ public override void AddRoutes(IEndpointRouteBuilder app) .WithTags(this.EntityName) .WithName($"{this.EntityName}/DeleteEntity"); - app.MapPut(this.MainRoute + "/{entityId:guid}", this.UpdateEntity) + app.MapPut(this.MainRoute + "/{entityId:guid}", this.ConvertEntityAndUpdate) .Produces() .Produces(404) .Produces(422) @@ -139,8 +140,8 @@ public virtual async Task CreateEntity(IEntityManager manager, TEntityD if (entity == null) { - await context.Response.Negotiate(requestReponse); - return; + await context.Response.Negotiate(requestReponse); + return; } await manager.ResolveProperties(entity, dto); @@ -214,16 +215,33 @@ public virtual async Task UpdateEntity(IEntityManager manager, Guid ent } /// - /// Validates the found and tries to update the + /// Deserialize the body of the request as an + /// + /// The + /// The + /// The deserialized + protected TEntityDto DeserializeBodyRequest(IJsonDeserializer deserializer, HttpContext context) + { + if (!context.Request.HasJsonContentType()) + { + return null; + } + + var dto = deserializer.Deserialize(context.Request.BodyReader.AsStream()).FirstOrDefault() as TEntityDto; + return dto; + } + + /// + /// Validates the found and tries to update the /// - /// The - /// The - /// The - /// The - /// The + /// The + /// The + /// The + /// The + /// The /// The deep level - /// A - protected async Task ValidateAndUpdateEntity(IEntityManager manager, TEntity entity, TEntityDto dto, HttpContext context, EntityRequestResponseDto requestResponse, int deepLevel) + /// A + protected async Task ValidateAndUpdateEntity(IEntityManager manager, TEntity entity, TEntityDto dto, HttpContext context, EntityRequestResponseDto requestResponse, int deepLevel) { var validationResult = context.Request.Validate(dto); @@ -333,5 +351,34 @@ protected bool ValidateEntityAndContainer(Entity entity, string keyId, HttpConte return true; } + + /// + /// Deserialize the and tries to create the corresponding POCO + /// + /// The + /// The + /// The + /// The deepLevel + /// A + private Task ConvertEntityAndCreate(IEntityManager manager, IJsonDeserializer deserializer, HttpContext context, [FromQuery] int deepLevel = 0) + { + var dto = this.DeserializeBodyRequest(deserializer, context); + return this.CreateEntity(manager, dto, context, deepLevel); + } + + /// + /// Deserialize the and tries to update the corresponding POCO + /// + /// The + /// The + /// The of the + /// The + /// The deepLevel + /// A + private Task ConvertEntityAndUpdate(IEntityManager manager, IJsonDeserializer deserializer, Guid entityId, HttpContext context, [FromQuery] int deepLevel = 0) + { + var dto = this.DeserializeBodyRequest(deserializer, context); + return this.UpdateEntity(manager, entityId, dto, context, deepLevel); + } } } diff --git a/UI_DSM/UI_DSM.Server/Program.cs b/UI_DSM/UI_DSM.Server/Program.cs index ec47b6fd..d72293e2 100644 --- a/UI_DSM/UI_DSM.Server/Program.cs +++ b/UI_DSM/UI_DSM.Server/Program.cs @@ -29,6 +29,8 @@ namespace UI_DSM.Server using UI_DSM.Serializer.Json; using UI_DSM.Server.Context; using UI_DSM.Server.Modules; + using UI_DSM.Server.Services.CometService; + using UI_DSM.Server.Services.FileService; using UI_DSM.Shared.Models; /// @@ -47,10 +49,11 @@ public class Program /// /// A collection of public static void Main(string[] args) - { + { var builder = WebApplication.CreateBuilder(args); // Add services to the container. + builder.Services.AddCarter(); builder.Services.AddAuthorization(); @@ -69,6 +72,9 @@ public static void Main(string[] args) builder.Services.AddIdentity().AddEntityFrameworkStores(); builder.Services.AddSingleton(); + builder.Services.AddSingleton(); + builder.Services.AddSingleton(); + builder.Services.AddSingleton(_ => new FileService(builder.Configuration["StoragePath"])); RegisterManagers(builder); RegisterModules(); diff --git a/UI_DSM/UI_DSM.Server/Services/CometService/CometService.cs b/UI_DSM/UI_DSM.Server/Services/CometService/CometService.cs new file mode 100644 index 00000000..205c0b36 --- /dev/null +++ b/UI_DSM/UI_DSM.Server/Services/CometService/CometService.cs @@ -0,0 +1,233 @@ +// -------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2022 RHEA System S.A. +// +// Author: Antoine Théate, Sam Gerené, Alex Vorobiev, Alexander van Delft, Martin Risseeuw, Nabil Abbar +// +// This file is part of UI-DSM. +// The UI-DSM web application is used to review an ECSS-E-TM-10-25 model. +// +// The UI-DSM application is provided to the community under the Apache License 2.0. +// +// -------------------------------------------------------------------------------------------------------- + +namespace UI_DSM.Server.Services.CometService +{ + using CDP4Common.EngineeringModelData; + using CDP4Common.SiteDirectoryData; + + using CDP4Dal; + using CDP4Dal.DAL; + using CDP4Dal.Exceptions; + using CDP4Dal.Operations; + + using CDP4JsonFileDal; + + using CDP4ServicesDal; + + using UI_DSM.Client.Enumerator; + using UI_DSM.Server.Services.FileService; + using UI_DSM.Shared.DTO.CometData; + + /// + /// Service that provides helper methods related to Comet + /// + public class CometService : ICometService + { + /// + /// A to keep track of current + /// + private readonly Dictionary currentSessions = new(); + + /// + /// The + /// + private readonly IFileService fileService; + + /// + /// Initializes a new instance of the class. + /// + /// The + public CometService(IFileService fileService) + { + this.fileService = fileService; + } + + /// + /// Tries to login to a Comet + /// + /// The + /// A with the result of the login process + public async Task> Login(CometAuthenticationData authenticationData) + { + var sessionId = Guid.NewGuid(); + var uri = new Uri(authenticationData.Url); + var dal = new CdpServicesDal(); + var credentials = new Credentials(authenticationData.UserName, authenticationData.Password, uri); + var session = new Session(dal, credentials); + + try + { + await session.Open(); + + if (session.RetrieveSiteDirectory() == null) + { + return Tuple.Create(AuthenticationStatus.Fail, Guid.Empty); + } + + this.currentSessions[sessionId] = session; + return Tuple.Create(AuthenticationStatus.Success, sessionId); + } + catch (DalReadException) + { + return Tuple.Create(AuthenticationStatus.Fail, Guid.Empty); + } + catch (HttpRequestException) + { + return Tuple.Create(AuthenticationStatus.ServerFailure, Guid.Empty); + } + } + + /// + /// Closes a + /// + /// The of the to close + /// A + public async Task Close(Guid sessionId) + { + var session = this.GetSession(sessionId); + + foreach (var iteration in session.OpenIterations.Select(x => x.Key)) + { + await session.CloseIterationSetup(iteration.IterationSetup); + } + + await session.Close(); + this.currentSessions.Remove(sessionId); + } + + /// + /// Gets a collection of available + /// + /// + /// The of the to get + /// + /// + /// A collection of + public IEnumerable GetAvailableEngineeringModel(Guid sessionId) + { + var session = this.GetSession(sessionId); + + var siteDirectory = session.RetrieveSiteDirectory(); + + return siteDirectory.Model + .Where(x => x.Participant.Any(p => p.IsActive && p.Person.Iid == session.ActivePerson.Iid) + && x.IterationSetup.Any(iteration => !iteration.IsDeleted && iteration.FrozenOn != null)); + } + + /// + /// Reads an to get the corresponding + /// + /// + /// The of the + /// The + /// A with the + public async Task ReadIteration(Guid sessionId, IterationSetup iterationSetup) + { + var session = this.GetSession(sessionId); + + var modelSetup = (EngineeringModelSetup)iterationSetup.Container; + var participant = modelSetup.Participant.FirstOrDefault(x => x.IsActive && x.Person.Iid == session.ActivePerson.Iid); + + if (participant == null) + { + throw new InvalidOperationException("The logged in Person is not part of the provided IterationSetup"); + } + + var model = new EngineeringModel(modelSetup.EngineeringModelIid, session.Assembler.Cache, session.Credentials.Uri); + var iteration = new Iteration(iterationSetup.IterationIid, session.Assembler.Cache, session.Credentials.Uri); + model.Iteration.Add(iteration); + + await session.Read(iteration, participant.SelectedDomain); + + if (session.OpenIterations.All(x => x.Key.Iid != iteration.Iid)) + { + throw new InvalidOperationException("An error occured during opening the iteration"); + } + + return session.OpenIterations.First(x => x.Key.Iid == iteration.Iid).Key; + } + + /// + /// Creates an Annex C3 file for the provided iteration + /// + /// The + /// A with the name of the created file + public async Task CreateAnnexC3File(Iteration iteration) + { + var fileName = $"{iteration.Iid}.zip"; + var path = Path.Combine(this.fileService.GetTempFolder(),fileName); + var credentials = new Credentials("admin", "pass", new Uri(path)); + var dal = new JsonFileDal(); + _ = new Session(dal, credentials); + + var operationContainers = new List(); + var transactionContext = TransactionContextResolver.ResolveContext(iteration); + var operationContainer = new OperationContainer(transactionContext.ContextRoute()); + var dto = iteration.ToDto(); + + var operation = new Operation(null, dto, OperationKind.Create); + operationContainer.AddOperation(operation); + operationContainers.Add(operationContainer); + await dal.Write(operationContainers); + return fileName; + } + + /// + /// Gets an based on provided s + /// + /// The of the + /// The of the + /// The of the + /// The + public IterationSetup GetIterationSetup(Guid sessionId, Guid modelId, Guid iterationId) + { + var session = this.GetSession(sessionId); + var siteDirectory = session.RetrieveSiteDirectory(); + var model = siteDirectory.Model.FirstOrDefault(x => x.Iid == modelId); + + if (model == null) + { + throw new ArgumentException("Invalid model id"); + } + + var iteration = model.IterationSetup.FirstOrDefault(x => x.IterationIid == iterationId); + + if (iteration == null) + { + throw new ArgumentException("Invalid iteration id"); + } + + return iteration; + } + + /// + /// Gets the correct . + /// + /// The of the + /// The + /// + /// If the provided does not correspond to any + /// + /// + private ISession GetSession(Guid sessionId) + { + if (!this.currentSessions.TryGetValue(sessionId, out var session)) + { + throw new ArgumentException("Invalid session id"); + } + + return session; + } + } +} diff --git a/UI_DSM/UI_DSM.Server/Services/CometService/ICometService.cs b/UI_DSM/UI_DSM.Server/Services/CometService/ICometService.cs new file mode 100644 index 00000000..37dcc5ec --- /dev/null +++ b/UI_DSM/UI_DSM.Server/Services/CometService/ICometService.cs @@ -0,0 +1,78 @@ +// -------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2022 RHEA System S.A. +// +// Author: Antoine Théate, Sam Gerené, Alex Vorobiev, Alexander van Delft, Martin Risseeuw, Nabil Abbar +// +// This file is part of UI-DSM. +// The UI-DSM web application is used to review an ECSS-E-TM-10-25 model. +// +// The UI-DSM application is provided to the community under the Apache License 2.0. +// +// -------------------------------------------------------------------------------------------------------- + +namespace UI_DSM.Server.Services.CometService +{ + using CDP4Common.EngineeringModelData; + using CDP4Common.SiteDirectoryData; + + using CDP4Dal; + + using UI_DSM.Client.Enumerator; + using UI_DSM.Shared.DTO.CometData; + + /// + /// Interface definition for + /// + public interface ICometService + { + /// + /// Tries to login to a Comet + /// + /// The + /// A with the result of the login process + Task> Login(CometAuthenticationData authenticationData); + + /// + /// Closes a + /// + /// The of the to close + /// A + Task Close(Guid sessionId); + + /// + /// Gets a collection of available + /// + /// + /// The of the to get + /// + /// + /// A collection of + IEnumerable GetAvailableEngineeringModel(Guid sessionId); + + /// + /// Reads an to get the corresponding + /// + /// + /// The of the + /// The + /// A with the + Task ReadIteration(Guid sessionId, IterationSetup iterationSetup); + + /// + /// Creates an Annex C3 file for the provided iteration + /// + /// The + /// A with the name of the created file + Task CreateAnnexC3File(Iteration iteration); + + /// + /// Gets an based on provided s + /// + /// The of the + /// The of the + /// The of the + /// The + IterationSetup GetIterationSetup(Guid sessionId, Guid modelId, Guid iterationId); + } +} diff --git a/UI_DSM/UI_DSM.Server/Services/FileService/FileService.cs b/UI_DSM/UI_DSM.Server/Services/FileService/FileService.cs new file mode 100644 index 00000000..19acd539 --- /dev/null +++ b/UI_DSM/UI_DSM.Server/Services/FileService/FileService.cs @@ -0,0 +1,163 @@ +// -------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2022 RHEA System S.A. +// +// Author: Antoine Théate, Sam Gerené, Alex Vorobiev, Alexander van Delft, Martin Risseeuw, Nabil Abbar +// +// This file is part of UI-DSM. +// The UI-DSM web application is used to review an ECSS-E-TM-10-25 model. +// +// The UI-DSM application is provided to the community under the Apache License 2.0. +// +// -------------------------------------------------------------------------------------------------------- + +namespace UI_DSM.Server.Services.FileService +{ + using CDP4Dal; + using CDP4Dal.DAL; + + using CDP4JsonFileDal; + + /// + /// This service provides capabilities to write and read that represents Annex C files or Budget Templates + /// + public class FileService : IFileService + { + /// + /// The name of the temporary folder + /// + private const string TempFolderName = "tmp"; + + /// + /// The main path to store files + /// + private readonly string mainPath; + + /// + /// Initializes a new + /// + /// The path where the should store files + public FileService(string storagePath) + { + if (storagePath == null) + { + throw new ArgumentNullException(nameof(storagePath)); + } + + if (!Directory.Exists(storagePath)) + { + Directory.CreateDirectory(storagePath); + } + + this.mainPath = storagePath; + } + + /// + /// Verifies if the at the provided correspond to a valid Annex C file + /// + /// The path of the file + /// A with the result of the verification + public async Task IsAnnexC3File(string fileName) + { + try + { + var credentials = new Credentials("admin", "pass", new Uri(Path.Combine(this.GetTempFolder(), fileName))); + var dal = new JsonFileDal(); + var session = new Session(dal, credentials); + await session.Open(); + var isSessionOpen = session.RetrieveSiteDirectory() != null; + await session.Close(); + return isSessionOpen; + } + catch + { + return false; + } + } + + /// + /// Deletes the at the provided if it exists + /// + /// The path of the + public void DeleteFile(string filePath) + { + var fullPath = Path.Combine(this.mainPath, filePath); + + if (File.Exists(fullPath)) + { + File.Delete(fullPath); + } + } + + /// + /// Deletes a temporary + /// + /// The name of the + public void DeleteTemporaryFile(string fileName) + { + var fullPath = Path.Combine(this.GetTempFolder(), fileName); + + if (File.Exists(fullPath)) + { + File.Delete(fullPath); + } + } + + /// + /// Verifies if a already exists + /// + /// The path of the folder + /// The name + /// A value indicating if the exists + public bool Exists(string folderPath, string fileName) + { + return File.Exists(Path.Combine(this.mainPath, folderPath, fileName)); + } + + /// + /// Gets the path of the Temporary folder + /// + /// The path of the folder + public string GetTempFolder() + { + var path = Path.Combine(this.mainPath, TempFolderName); + + if (!Directory.Exists(path)) + { + Directory.CreateDirectory(path); + } + + return path; + } + + /// + /// Verifies if a temporary exists + /// + /// The name of the temporary + /// True if exists + public bool TempFileExists(string tempFileName) + { + return File.Exists(Path.Combine(this.GetTempFolder(), tempFileName)); + } + + /// + /// Moves a temporary to its final destination + /// + /// The name of the temporary + /// The folder destination + /// The new location + public string MoveFile(string tempFileName, string newFolderPath) + { + var destinationDirectory = Path.Combine(this.mainPath, newFolderPath); + + if (!Directory.Exists(destinationDirectory)) + { + Directory.CreateDirectory(destinationDirectory); + } + + File.Move(Path.Combine(this.GetTempFolder(), tempFileName), Path.Combine(this.mainPath, newFolderPath, tempFileName)); + + return Path.Combine(newFolderPath, tempFileName); + } + } +} diff --git a/UI_DSM/UI_DSM.Server/Services/FileService/IFileService.cs b/UI_DSM/UI_DSM.Server/Services/FileService/IFileService.cs new file mode 100644 index 00000000..f6dc420f --- /dev/null +++ b/UI_DSM/UI_DSM.Server/Services/FileService/IFileService.cs @@ -0,0 +1,69 @@ +// -------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2022 RHEA System S.A. +// +// Author: Antoine Théate, Sam Gerené, Alex Vorobiev, Alexander van Delft, Martin Risseeuw, Nabil Abbar +// +// This file is part of UI-DSM. +// The UI-DSM web application is used to review an ECSS-E-TM-10-25 model. +// +// The UI-DSM application is provided to the community under the Apache License 2.0. +// +// -------------------------------------------------------------------------------------------------------- + +namespace UI_DSM.Server.Services.FileService +{ + /// + /// Interface definition for + /// + public interface IFileService + { + /// + /// Verifies if the at the provided correspond to a valid Annex C file + /// + /// The path of the file + /// A with the result of the verification + Task IsAnnexC3File(string fileName); + + /// + /// Deletes the at the provided if it exists + /// + /// The path of the + void DeleteFile(string filePath); + + /// + /// Gets the path of the Temporary folder + /// + /// The path of the folder + string GetTempFolder(); + + /// + /// Verifies if a temporary exists + /// + /// The name of the temporary + /// True if exists + bool TempFileExists(string tempFileName); + + /// + /// Moves a temporary to its final destination + /// + /// The name of the temporary + /// The folder destination + /// The new location + string MoveFile(string tempFileName, string newFolderPath); + + /// + /// Deletes a temporary + /// + /// The name of the + void DeleteTemporaryFile(string fileName); + + /// + /// Verifies if a already exists + /// + /// The path of the folder + /// The name + /// A value indicating if the exists + bool Exists(string folderPath, string fileName); + } +} diff --git a/UI_DSM/UI_DSM.Server/Validator/ArtifactValidator.cs b/UI_DSM/UI_DSM.Server/Validator/ArtifactValidator.cs new file mode 100644 index 00000000..bcddc667 --- /dev/null +++ b/UI_DSM/UI_DSM.Server/Validator/ArtifactValidator.cs @@ -0,0 +1,32 @@ +// -------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2022 RHEA System S.A. +// +// Author: Antoine Théate, Sam Gerené, Alex Vorobiev, Alexander van Delft, Martin Risseeuw, Nabil Abbar +// +// This file is part of UI-DSM. +// The UI-DSM web application is used to review an ECSS-E-TM-10-25 model. +// +// The UI-DSM application is provided to the community under the Apache License 2.0. +// +// -------------------------------------------------------------------------------------------------------- + +namespace UI_DSM.Server.Validator +{ + using FluentValidation; + + using UI_DSM.Shared.DTO.Models; + + /// + /// for the + /// + public class ArtifactValidator : AbstractValidator + { + /// + /// Initializes a new + /// + public ArtifactValidator() + { + } + } +} diff --git a/UI_DSM/UI_DSM.Server/Validator/CometAuthenticationDataValidator.cs b/UI_DSM/UI_DSM.Server/Validator/CometAuthenticationDataValidator.cs new file mode 100644 index 00000000..b139a038 --- /dev/null +++ b/UI_DSM/UI_DSM.Server/Validator/CometAuthenticationDataValidator.cs @@ -0,0 +1,35 @@ +// -------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2022 RHEA System S.A. +// +// Author: Antoine Théate, Sam Gerené, Alex Vorobiev, Alexander van Delft, Martin Risseeuw, Nabil Abbar +// +// This file is part of UI-DSM. +// The UI-DSM web application is used to review an ECSS-E-TM-10-25 model. +// +// The UI-DSM application is provided to the community under the Apache License 2.0. +// +// -------------------------------------------------------------------------------------------------------- + +namespace UI_DSM.Server.Validator +{ + using FluentValidation; + + using UI_DSM.Shared.DTO.CometData; + + /// + /// for + /// + public class CometAuthenticationDataValidator : AbstractValidator + { + /// + /// Initializes a new + /// + public CometAuthenticationDataValidator() + { + this.RuleFor(x => x.Url).NotEmpty(); + this.RuleFor(x => x.UserName).NotEmpty(); + this.RuleFor(x => x.Password).NotEmpty(); + } + } +} diff --git a/UI_DSM/UI_DSM.Server/Validator/ModelUploadDataValidator.cs b/UI_DSM/UI_DSM.Server/Validator/ModelUploadDataValidator.cs new file mode 100644 index 00000000..21913419 --- /dev/null +++ b/UI_DSM/UI_DSM.Server/Validator/ModelUploadDataValidator.cs @@ -0,0 +1,34 @@ +// -------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2022 RHEA System S.A. +// +// Author: Antoine Théate, Sam Gerené, Alex Vorobiev, Alexander van Delft, Martin Risseeuw, Nabil Abbar +// +// This file is part of UI-DSM. +// The UI-DSM web application is used to review an ECSS-E-TM-10-25 model. +// +// The UI-DSM application is provided to the community under the Apache License 2.0. +// +// -------------------------------------------------------------------------------------------------------- + +namespace UI_DSM.Server.Validator +{ + using FluentValidation; + + using UI_DSM.Shared.DTO.CometData; + + /// + /// for + /// + public class ModelUploadDataValidator : AbstractValidator + { + /// + /// Initialize a new + /// + public ModelUploadDataValidator() + { + this.RuleFor(x => x.ModelId).NotEqual(Guid.Empty); + this.RuleFor(x => x.IterationId).NotEqual(Guid.Empty); + } + } +} diff --git a/UI_DSM/UI_DSM.Server/Validator/ReviewDtoValidator.cs b/UI_DSM/UI_DSM.Server/Validator/ReviewDtoValidator.cs index efd157ea..438fa2b0 100644 --- a/UI_DSM/UI_DSM.Server/Validator/ReviewDtoValidator.cs +++ b/UI_DSM/UI_DSM.Server/Validator/ReviewDtoValidator.cs @@ -30,6 +30,7 @@ public ReviewDtoValidator() this.RuleFor(x => x.Description).NotEmpty(); this.RuleFor(x => x.Title).NotEmpty(); this.RuleFor(x => x.Author).NotEqual(Guid.Empty); + this.RuleFor(x => x.Artifacts.Count).LessThanOrEqualTo(1); } } } diff --git a/UI_DSM/UI_DSM.Server/appsettings.json b/UI_DSM/UI_DSM.Server/appsettings.json index 01ae4fba..5094e5bc 100644 --- a/UI_DSM/UI_DSM.Server/appsettings.json +++ b/UI_DSM/UI_DSM.Server/appsettings.json @@ -6,6 +6,7 @@ } }, "DataBaseConnection": "Server=localhost;Port=5433;Database=ui-dsm;Password=pass;User ID=postgres", + "StoragePath": "C:\\CODE\\DSM\\Storage", "JWTSettings": { "securityKey": "UI-DSM-SecretKey", "validIssuer": "UI-DSM-Api", diff --git a/UI_DSM/UI_DSM.Shared/DTO/CometData/CometAuthenticationData.cs b/UI_DSM/UI_DSM.Shared/DTO/CometData/CometAuthenticationData.cs new file mode 100644 index 00000000..96313f48 --- /dev/null +++ b/UI_DSM/UI_DSM.Shared/DTO/CometData/CometAuthenticationData.cs @@ -0,0 +1,44 @@ +// -------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2022 RHEA System S.A. +// +// Author: Antoine Théate, Sam Gerené, Alex Vorobiev, Alexander van Delft, Martin Risseeuw +// +// This file is part of UI-DSM. +// The UI-DSM web application is used to review an ECSS-E-TM-10-25 model. +// +// The UI-DSM application is provided to the community under the Apache License 2.0. +// +// -------------------------------------------------------------------------------------------------------- + +namespace UI_DSM.Shared.DTO.CometData +{ + using System.ComponentModel; + using System.ComponentModel.DataAnnotations; + + /// + /// Data used to establish a connection to a Comet session + /// + public class CometAuthenticationData + { + /// + /// Gets or sets the Url where the Comet instance can be reached + /// + [Required] + [Url] + public string Url { get; set; } + + /// + /// Gets or sets the Username for the Comet login + /// + [Required] + public string UserName { get; set; } + + /// + /// Gets or sets the Password for the Comet login + /// + [Required] + [PasswordPropertyText] + public string Password { get; set; } + } +} diff --git a/UI_DSM/UI_DSM.Shared/DTO/CometData/CometAuthenticationResponse.cs b/UI_DSM/UI_DSM.Shared/DTO/CometData/CometAuthenticationResponse.cs new file mode 100644 index 00000000..b9c56971 --- /dev/null +++ b/UI_DSM/UI_DSM.Shared/DTO/CometData/CometAuthenticationResponse.cs @@ -0,0 +1,28 @@ +// -------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2022 RHEA System S.A. +// +// Author: Antoine Théate, Sam Gerené, Alex Vorobiev, Alexander van Delft, Martin Risseeuw, Nabil Abbar +// +// This file is part of UI-DSM. +// The UI-DSM web application is used to review an ECSS-E-TM-10-25 model. +// +// The UI-DSM application is provided to the community under the Apache License 2.0. +// +// -------------------------------------------------------------------------------------------------------- + +using UI_DSM.Shared.DTO.Common; + +namespace UI_DSM.Shared.DTO.CometData +{ + /// + /// A for a to use after tries to log to Comet + /// + public class CometAuthenticationResponse : RequestResponseDto + { + /// + /// The of the current session to Comet + /// + public Guid SessionId { get; set; } + } +} diff --git a/UI_DSM/UI_DSM.Shared/DTO/CometData/ModelUploadData.cs b/UI_DSM/UI_DSM.Shared/DTO/CometData/ModelUploadData.cs new file mode 100644 index 00000000..204d2c25 --- /dev/null +++ b/UI_DSM/UI_DSM.Shared/DTO/CometData/ModelUploadData.cs @@ -0,0 +1,31 @@ +// -------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2022 RHEA System S.A. +// +// Author: Antoine Théate, Sam Gerené, Alex Vorobiev, Alexander van Delft, Martin Risseeuw, Nabil Abbar +// +// This file is part of UI-DSM. +// The UI-DSM web application is used to review an ECSS-E-TM-10-25 model. +// +// The UI-DSM application is provided to the community under the Apache License 2.0. +// +// -------------------------------------------------------------------------------------------------------- + +namespace UI_DSM.Shared.DTO.CometData +{ + /// + /// Data used to upload a specific iteration from a specific Engineering model + /// + public class ModelUploadData + { + /// + /// The of the Engineering Model + /// + public Guid ModelId { get; set; } + + /// + /// The of the frozen Iteration + /// + public Guid IterationId { get; set; } + } +} diff --git a/UI_DSM/UI_DSM.Shared/DTO/CometData/ModelUploadResponse.cs b/UI_DSM/UI_DSM.Shared/DTO/CometData/ModelUploadResponse.cs new file mode 100644 index 00000000..52a8adea --- /dev/null +++ b/UI_DSM/UI_DSM.Shared/DTO/CometData/ModelUploadResponse.cs @@ -0,0 +1,28 @@ +// -------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2022 RHEA System S.A. +// +// Author: Antoine Théate, Sam Gerené, Alex Vorobiev, Alexander van Delft, Martin Risseeuw, Nabil Abbar +// +// This file is part of UI-DSM. +// The UI-DSM web application is used to review an ECSS-E-TM-10-25 model. +// +// The UI-DSM application is provided to the community under the Apache License 2.0. +// +// -------------------------------------------------------------------------------------------------------- + +namespace UI_DSM.Shared.DTO.CometData +{ + using UI_DSM.Shared.DTO.Common; + + /// + /// Data used to has response to an upload of a Comet model + /// + public class ModelUploadResponse : RequestResponseDto + { + /// + /// The Path of the uploaded file + /// + public string UploadedFilePath { get; set; } + } +} diff --git a/UI_DSM/UI_DSM.Shared/DTO/CometData/ModelsDataResponse.cs b/UI_DSM/UI_DSM.Shared/DTO/CometData/ModelsDataResponse.cs new file mode 100644 index 00000000..adb8740e --- /dev/null +++ b/UI_DSM/UI_DSM.Shared/DTO/CometData/ModelsDataResponse.cs @@ -0,0 +1,33 @@ +// -------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2022 RHEA System S.A. +// +// Author: Antoine Théate, Sam Gerené, Alex Vorobiev, Alexander van Delft, Martin Risseeuw, Nabil Abbar +// +// This file is part of UI-DSM. +// The UI-DSM web application is used to review an ECSS-E-TM-10-25 model. +// +// The UI-DSM application is provided to the community under the Apache License 2.0. +// +// -------------------------------------------------------------------------------------------------------- + +namespace UI_DSM.Shared.DTO.CometData +{ + using UI_DSM.Shared.DTO.Common; + + /// + /// Data used to reply to the get query for getting available EngineeringModel + /// + public class ModelsDataResponse : RequestResponseDto + { + /// + /// A that represents available models with the Frozen Iteration + /// + public Dictionary>> AvailableModels { get; set; } = new(); + + /// + /// A that contains the correspondance between the Model id and the Model name + /// + public Dictionary ModelNames { get; set; } = new(); + } +} diff --git a/UI_DSM/UI_DSM.Shared/DTO/Models/ArtifactDto.cs b/UI_DSM/UI_DSM.Shared/DTO/Models/ArtifactDto.cs new file mode 100644 index 00000000..296926a5 --- /dev/null +++ b/UI_DSM/UI_DSM.Shared/DTO/Models/ArtifactDto.cs @@ -0,0 +1,32 @@ +// -------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2022 RHEA System S.A. +// +// Author: Antoine Théate, Sam Gerené, Alex Vorobiev, Alexander van Delft, Martin Risseeuw +// +// This file is part of UI-DSM. +// The UI-DSM web application is used to review an ECSS-E-TM-10-25 model. +// +// The UI-DSM application is provided to the community under the Apache License 2.0. +// +// -------------------------------------------------------------------------------------------------------- + +namespace UI_DSM.Shared.DTO.Models +{ + using UI_DSM.Shared.Models; + + /// + /// The Data Transfer Object representing the class. + /// + public partial class ArtifactDto + { + /// + /// Includes common properties for from an + /// + /// The + public void IncludeCommonProperties(Artifact artifact) + { + this.FileName = artifact.FileName; + } + } +} diff --git a/UI_DSM/UI_DSM.Shared/DTO/Models/AutoGenDto/ArtifactDto.cs b/UI_DSM/UI_DSM.Shared/DTO/Models/AutoGenDto/ArtifactDto.cs new file mode 100644 index 00000000..df363d4b --- /dev/null +++ b/UI_DSM/UI_DSM.Shared/DTO/Models/AutoGenDto/ArtifactDto.cs @@ -0,0 +1,51 @@ +// -------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2022 RHEA System S.A. +// +// Author: Antoine Théate, Sam Gerené, Alex Vorobiev, Alexander van Delft +// +// This file is part of UI-DSM. +// The UI-DSM web application is used to review an ECSS-E-TM-10-25 model. +// +// The UI-DSM application is provided to the community under the Apache License 2.0. +// +// -------------------------------------------------------------------------------------------------------- + +// -------------------------------------------------------------------------------------------------------- +// ------------THIS IS AN AUTOMATICALLY GENERATED FILE. ANY MANUAL CHANGES WILL BE OVERWRITTEN!------------ +// -------------------------------------------------------------------------------------------------------- + +namespace UI_DSM.Shared.DTO.Models +{ + using UI_DSM.Shared.Models; + + /// + /// The Data Transfer Object representing the class. + /// + public abstract partial class ArtifactDto : EntityDto + { + /// + /// Initializes a new class. + /// + protected ArtifactDto() + { + } + + /// + /// Initializes a new class. + /// + /// The of the represented + protected ArtifactDto(Guid id) : base(id) + { + } + + /// + /// Gets or sets the FileName of the Artifact + /// + public string FileName { get; set; } + } +} + +// ------------------------------------------------------------------------------------------------ +// --------THIS IS AN AUTOMATICALLY GENERATED FILE. ANY MANUAL CHANGES WILL BE OVERWRITTEN!-------- +// ------------------------------------------------------------------------------------------------ \ No newline at end of file diff --git a/UI_DSM/UI_DSM.Shared/DTO/Models/AutoGenDto/ModelDto.cs b/UI_DSM/UI_DSM.Shared/DTO/Models/AutoGenDto/ModelDto.cs new file mode 100644 index 00000000..bfee968c --- /dev/null +++ b/UI_DSM/UI_DSM.Shared/DTO/Models/AutoGenDto/ModelDto.cs @@ -0,0 +1,59 @@ +// -------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2022 RHEA System S.A. +// +// Author: Antoine Théate, Sam Gerené, Alex Vorobiev, Alexander van Delft +// +// This file is part of UI-DSM. +// The UI-DSM web application is used to review an ECSS-E-TM-10-25 model. +// +// The UI-DSM application is provided to the community under the Apache License 2.0. +// +// -------------------------------------------------------------------------------------------------------- + +// -------------------------------------------------------------------------------------------------------- +// ------------THIS IS AN AUTOMATICALLY GENERATED FILE. ANY MANUAL CHANGES WILL BE OVERWRITTEN!------------ +// -------------------------------------------------------------------------------------------------------- + +namespace UI_DSM.Shared.DTO.Models +{ + using UI_DSM.Shared.Models; + + /// + /// The Data Transfer Object representing the class. + /// + public partial class ModelDto : ArtifactDto + { + /// + /// Initializes a new class. + /// + public ModelDto() + { + } + + /// + /// Initializes a new class. + /// + /// The of the represented + public ModelDto(Guid id) : base(id) + { + } + + /// + /// Gets or sets the ModelName of the Model + /// + public string ModelName { get; set; } + + /// + /// Instantiate a from a + /// + public override Entity InstantiatePoco() + { + return new Model(this.Id); + } + } +} + +// ------------------------------------------------------------------------------------------------ +// --------THIS IS AN AUTOMATICALLY GENERATED FILE. ANY MANUAL CHANGES WILL BE OVERWRITTEN!-------- +// ------------------------------------------------------------------------------------------------ \ No newline at end of file diff --git a/UI_DSM/UI_DSM.Shared/DTO/Models/AutoGenDto/ProjectDto.cs b/UI_DSM/UI_DSM.Shared/DTO/Models/AutoGenDto/ProjectDto.cs index 7919460e..f46333fe 100644 --- a/UI_DSM/UI_DSM.Shared/DTO/Models/AutoGenDto/ProjectDto.cs +++ b/UI_DSM/UI_DSM.Shared/DTO/Models/AutoGenDto/ProjectDto.cs @@ -32,6 +32,7 @@ public ProjectDto() this.Participants = new List(); this.Reviews = new List(); this.Annotations = new List(); + this.Artifacts = new List(); } /// @@ -43,6 +44,7 @@ public ProjectDto(Guid id) : base(id) this.Participants = new List(); this.Reviews = new List(); this.Annotations = new List(); + this.Artifacts = new List(); } /// @@ -65,6 +67,11 @@ public ProjectDto(Guid id) : base(id) /// public List Annotations { get; set; } + /// + /// Gets or sets the Artifacts of the Project + /// + public List Artifacts { get; set; } + /// /// Instantiate a from a /// diff --git a/UI_DSM/UI_DSM.Shared/DTO/Models/AutoGenDto/ReviewDto.cs b/UI_DSM/UI_DSM.Shared/DTO/Models/AutoGenDto/ReviewDto.cs index 3ca86013..9133661c 100644 --- a/UI_DSM/UI_DSM.Shared/DTO/Models/AutoGenDto/ReviewDto.cs +++ b/UI_DSM/UI_DSM.Shared/DTO/Models/AutoGenDto/ReviewDto.cs @@ -31,6 +31,7 @@ public partial class ReviewDto : EntityDto public ReviewDto() { this.ReviewObjectives = new List(); + this.Artifacts = new List(); } /// @@ -40,6 +41,7 @@ public ReviewDto() public ReviewDto(Guid id) : base(id) { this.ReviewObjectives = new List(); + this.Artifacts = new List(); } /// @@ -77,6 +79,11 @@ public ReviewDto(Guid id) : base(id) /// public List ReviewObjectives { get; set; } + /// + /// Gets or sets the Artifacts of the Review + /// + public List Artifacts { get; set; } + /// /// Instantiate a from a /// diff --git a/UI_DSM/UI_DSM.Shared/Models/Artifact.cs b/UI_DSM/UI_DSM.Shared/Models/Artifact.cs new file mode 100644 index 00000000..ac3094a1 --- /dev/null +++ b/UI_DSM/UI_DSM.Shared/Models/Artifact.cs @@ -0,0 +1,69 @@ +// -------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2022 RHEA System S.A. +// +// Author: Antoine Théate, Sam Gerené, Alex Vorobiev, Alexander van Delft, Martin Risseeuw +// +// This file is part of UI-DSM. +// The UI-DSM web application is used to review an ECSS-E-TM-10-25 model. +// +// The UI-DSM application is provided to the community under the Apache License 2.0. +// +// -------------------------------------------------------------------------------------------------------- + +namespace UI_DSM.Shared.Models +{ + using System.ComponentModel.DataAnnotations.Schema; + + using UI_DSM.Shared.DTO.Models; + + /// + /// Represents a file artifact that is uploaded to the system and linked to a project. + /// + [Table(nameof(Artifact))] + public abstract class Artifact : Entity + { + /// + /// Initializes a new + /// + protected Artifact() + { + this.Reviews = new List(); + } + + /// + /// Inilializes a new + /// + /// The of the + protected Artifact(Guid id) : base(id) + { + this.Reviews = new List(); + } + + /// + /// The name of the represented file + /// + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public string FileName { get; set; } + + /// + /// A collection of where this is used + /// + public List Reviews { get; set; } + + /// + /// Resolve the properties of the current from its counter-part + /// + /// The source + /// A of all others + public override void ResolveProperties(EntityDto entityDto, Dictionary resolvedEntity) + { + if (entityDto is not ArtifactDto annotationDto) + { + throw new InvalidOperationException($"The DTO {entityDto.GetType()} does not match with the current Artifact POCO"); + } + + this.FileName = annotationDto.FileName; + } + } +} diff --git a/UI_DSM/UI_DSM.Shared/Models/Model.cs b/UI_DSM/UI_DSM.Shared/Models/Model.cs new file mode 100644 index 00000000..7f4d51a3 --- /dev/null +++ b/UI_DSM/UI_DSM.Shared/Models/Model.cs @@ -0,0 +1,79 @@ +// -------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2022 RHEA System S.A. +// +// Author: Antoine Théate, Sam Gerené, Alex Vorobiev, Alexander van Delft, Martin Risseeuw +// +// This file is part of UI-DSM. +// The UI-DSM web application is used to review an ECSS-E-TM-10-25 model. +// +// The UI-DSM application is provided to the community under the Apache License 2.0. +// +// -------------------------------------------------------------------------------------------------------- + +namespace UI_DSM.Shared.Models +{ + using System.ComponentModel.DataAnnotations.Schema; + + using UI_DSM.Shared.DTO.Models; + + /// + /// Represents a E-TM-10-25 model uploaded and linked to the project. + /// + [Table(nameof(Model))] + public class Model : Artifact + { + /// + /// Initializes a new + /// + public Model() + { + } + + /// + /// Inilializes a new + /// + /// The of the + public Model(Guid id) : base(id) + { + } + + /// + /// The name of the + /// + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public string ModelName { get; set; } + + /// + /// Resolve the properties of the current from its counter-part + /// + /// The source + /// A of all others + public override void ResolveProperties(EntityDto entityDto, Dictionary resolvedEntity) + { + base.ResolveProperties(entityDto, resolvedEntity); + + if (entityDto is not ModelDto modelDto) + { + throw new InvalidOperationException($"The DTO {entityDto.GetType()} does not match with the current Model POCO"); + } + + this.ModelName = modelDto.ModelName; + } + + /// + /// Instantiate a from a + /// + /// A new + public override EntityDto ToDto() + { + var dto = new ModelDto(this.Id) + { + ModelName = this.ModelName + }; + + dto.IncludeCommonProperties(this); + return dto; + } + } +} diff --git a/UI_DSM/UI_DSM.Shared/Models/Project.cs b/UI_DSM/UI_DSM.Shared/Models/Project.cs index a31ff393..e5ef16c9 100644 --- a/UI_DSM/UI_DSM.Shared/Models/Project.cs +++ b/UI_DSM/UI_DSM.Shared/Models/Project.cs @@ -68,6 +68,12 @@ public Project(Guid id) : base(id) [DeepLevel(1)] public EntityContainerList Annotations { get; set; } + /// + /// A collection of contained + /// + [DeepLevel(1)] + public EntityContainerList Artifacts { get; set; } + /// /// Instantiate a from a /// @@ -79,7 +85,8 @@ public override EntityDto ToDto() ProjectName = this.ProjectName, Participants = new List(this.Participants.Select(x => x.Id)), Reviews = new List(this.Reviews.Select(x => x.Id)), - Annotations = new List(this.Annotations.Select(x => x.Id)) + Annotations = new List(this.Annotations.Select(x => x.Id)), + Artifacts = new List(this.Artifacts.Select(x => x.Id)) }; return dto; @@ -101,6 +108,7 @@ public override void ResolveProperties(EntityDto entityDto, Dictionary @@ -111,6 +119,7 @@ private void InitializeCollections() this.Participants = new EntityContainerList(this); this.Reviews = new EntityContainerList(this); this.Annotations = new EntityContainerList(this); + this.Artifacts = new EntityContainerList(this); } } } diff --git a/UI_DSM/UI_DSM.Shared/Models/Review.cs b/UI_DSM/UI_DSM.Shared/Models/Review.cs index 67f26fe2..fcf77a63 100644 --- a/UI_DSM/UI_DSM.Shared/Models/Review.cs +++ b/UI_DSM/UI_DSM.Shared/Models/Review.cs @@ -87,6 +87,12 @@ public Review(Guid id) : base(id) [DeepLevel(1)] public EntityContainerList ReviewObjectives { get; protected set; } + /// + /// A collection of + /// + [DeepLevel(1)] + public List Artifacts { get; protected set; } + /// /// Instantiate a from a /// @@ -101,7 +107,8 @@ public override EntityDto ToDto() Title = this.Title, Description = this.Description, Status = this.Status, - ReviewObjectives = this.ReviewObjectives.Select(x => x.Id).ToList() + ReviewObjectives = this.ReviewObjectives.Select(x => x.Id).ToList(), + Artifacts = this.Artifacts.Select(x => x.Id).ToList() }; } @@ -124,6 +131,7 @@ public override void ResolveProperties(EntityDto entityDto, Dictionary @@ -132,6 +140,7 @@ public override void ResolveProperties(EntityDto entityDto, Dictionary(this); + this.Artifacts = new List(); } } } diff --git a/UI_DSM/UI_DSM.sln b/UI_DSM/UI_DSM.sln index 869c239f..5cdf539a 100644 --- a/UI_DSM/UI_DSM.sln +++ b/UI_DSM/UI_DSM.sln @@ -19,7 +19,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UI_DSM.CodeGenerator.Tests" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UI_DSM.Serializer.Json", "UI_DSM.Serializer.Json\UI_DSM.Serializer.Json.csproj", "{26FCB51E-B8BF-429C-861E-B4BFD1B84908}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UI_DSM.Serializer.Json.Tests", "UI_DSM.Serializer.Json.Tests\UI_DSM.Serializer.Json.Tests.csproj", "{F7AE939B-C8C2-40B9-9BD4-7104A3AE46F2}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UI_DSM.Serializer.Json.Tests", "UI_DSM.Serializer.Json.Tests\UI_DSM.Serializer.Json.Tests.csproj", "{F7AE939B-C8C2-40B9-9BD4-7104A3AE46F2}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution