Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat #559 As a user i want to manipulate the folder-file structure of a filestore #578

Merged
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ namespace COMET.Web.Common.Tests.Services.SessionManagement

using CDP4Dal;
using CDP4Dal.DAL;
using CDP4Dal.Exceptions;
using CDP4Dal.Operations;

using COMET.Web.Common.Enumerations;
using COMET.Web.Common.Services.SessionManagement;
Expand Down Expand Up @@ -335,10 +337,23 @@ public void VerifyUpdateThings()
Owner = this.sessionService.GetDomainOfExpertise(this.iteration)
};

this.iteration.Element.Add(element);

var clone = element.Clone(false);
clone.Name = "Satellite";
thingsToUpdate.Add(clone);
Assert.DoesNotThrow(() => this.sessionService.UpdateThings(this.iteration, thingsToUpdate));
Assert.That(async () => await this.sessionService.UpdateThings(this.iteration, thingsToUpdate), Throws.Nothing);

var filesToUpload = new List<string> { this.uri.LocalPath };

Assert.Multiple(() =>
{
Assert.That(async () => await this.sessionService.UpdateThings(this.iteration, thingsToUpdate, filesToUpload), Throws.Nothing);
this.session.Verify(x => x.Write(It.IsAny<OperationContainer>(), It.IsAny<IEnumerable<string>>()), Times.Once);
});

this.session.Setup(x => x.Write(It.IsAny<OperationContainer>(), It.IsAny<IEnumerable<string>>())).Throws(new DalWriteException());
Assert.That(async () => await this.sessionService.UpdateThings(this.iteration, thingsToUpdate, filesToUpload), Throws.Nothing);
}

[Test]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,15 @@ public interface ISessionService
/// <returns>An asynchronous operation with a <see cref="Result"/></returns>
Task<Result> UpdateThings(Thing container, IEnumerable<Thing> thingsToUpdate);

/// <summary>
/// Write updated Things in an <see cref="Iteration" /> and uploads the given files to the filestore
/// </summary>
/// <param name="container">The <see cref="Thing" /> where the <see cref="Thing" />s should be updated</param>
/// <param name="thingsToUpdate">List of Things to update in the session</param>
/// <param name="files">>A collection of file paths for files to be send to the file store</param>
/// <returns>An asynchronous operation with a <see cref="Result" /></returns>
Task<Result> UpdateThings(Thing container, IEnumerable<Thing> thingsToUpdate, IEnumerable<string> files);

/// <summary>
/// Deletes a <see cref="Thing"/> from it's container
/// </summary>
Expand Down
57 changes: 57 additions & 0 deletions COMET.Web.Common/Services/SessionManagement/SessionService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,63 @@ public async Task<Result> UpdateThings(Thing container, IEnumerable<Thing> thing
return result;
}

/// <summary>
/// Write updated Things in an <see cref="Iteration" /> and uploads the given files to the filestore
/// </summary>
/// <param name="container">The <see cref="Thing" /> where the <see cref="Thing" />s should be updated</param>
/// <param name="thingsToUpdate">List of Things to update in the session</param>
/// <param name="files">>A collection of file paths for files to be send to the file store</param>
/// <returns>An asynchronous operation with a <see cref="Result" /></returns>
public async Task<Result> UpdateThings(Thing container, IEnumerable<Thing> thingsToUpdate, IEnumerable<string> files)
{
var result = new Result();

if (thingsToUpdate == null)
{
result.Errors.Add(new Error("The things to update can't be null"));
return result;
}

var sw = Stopwatch.StartNew();

// CreateThings a shallow clone of the thing. The cached Thing object should not be changed, so we record the change on a clone.
var thingClone = container;

if (container.Original == null)
{
thingClone = container.Clone(false);
}

// set the context of the transaction to the thing changes need to be added to.
var context = TransactionContextResolver.ResolveContext(thingClone);
var transaction = new ThingTransaction(context);

// register all updates with the transaction.
thingsToUpdate.ToList().ForEach(transaction.CreateOrUpdate);

// finalize the transaction, the result is an OperationContainer that the session class uses to write the changes to the Thing object.
var operationContainer = transaction.FinalizeTransaction();
result = new Result();

try
{
await this.Session.Write(operationContainer, files);
this.logger.LogInformation("Update writing done in {swElapsedMilliseconds} [ms]", sw.ElapsedMilliseconds);
result.Successes.Add(new Success($"Update writing done in {sw.ElapsedMilliseconds} [ms]"));
}
catch (DalWriteException ex)
{
this.logger.LogError("The update operation failed: {exMessage}", ex.Message);
result.Errors.Add(new Error($"The update operation failed: {ex.Message}"));
}
finally
{
sw.Stop();
}

return result;
}

/// <summary>
/// Deletes a <see cref="Thing" /> from it's container
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="FileFormTestFixture.cs" company="RHEA System S.A.">
// Copyright (c) 2023-2024 RHEA System S.A.
//
// Authors: Sam Gerené, Alex Vorobiev, Alexander van Delft, Jaime Bernar, Antoine Théate, João Rua
//
// This file is part of CDP4-COMET WEB Community Edition
// The CDP4-COMET WEB Community Edition is the RHEA Web Application implementation of ECSS-E-TM-10-25 Annex A and Annex C.
//
// The CDP4-COMET WEB Community Edition is free software; you can redistribute it and/or
// modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation; either
// version 3 of the License, or (at your option) any later version.
//
// The CDP4-COMET WEB Community Edition is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------

namespace COMETwebapp.Tests.Components.EngineeringModel.FileStore
{
using System.Linq;

using Bunit;

using CDP4Common.EngineeringModelData;

using COMET.Web.Common.Test.Helpers;

using COMETwebapp.Components.EngineeringModel.FileStore;
using COMETwebapp.ViewModels.Components.EngineeringModel.FileStore.FileHandler;

using DevExpress.Blazor;

using Microsoft.AspNetCore.Components.Forms;

using Moq;

using NUnit.Framework;

using TestContext = Bunit.TestContext;

[TestFixture]
public class FileFormTestFixture
{
private TestContext context;
private IRenderedComponent<FileForm> renderer;
private Mock<IFileHandlerViewModel> viewModel;

[SetUp]
public void SetUp()
{
this.context = new TestContext();
this.viewModel = new Mock<IFileHandlerViewModel>();

this.viewModel.Setup(x => x.File).Returns(new File());
this.context.ConfigureDevExpressBlazor();

this.renderer = this.context.RenderComponent<FileForm>(parameters =>
{
parameters.Add(p => p.ViewModel, this.viewModel.Object);
});
}

[TearDown]
public void Teardown()
{
this.context.CleanContext();
this.context.Dispose();
}

[Test]
public async Task VerifyOnValidSubmitAndDelete()
{
Assert.That(this.renderer.Instance.IsDeletePopupVisible, Is.EqualTo(false));

var form = this.renderer.FindComponent<EditForm>();
await this.renderer.InvokeAsync(form.Instance.OnValidSubmit.InvokeAsync);
this.viewModel.Verify(x => x.CreateOrEditFile(It.IsAny<bool>()), Times.Once);

var deleteFileButton = this.renderer.FindComponents<DxButton>().First(x => x.Instance.Id == "deleteFileButton");
await this.renderer.InvokeAsync(deleteFileButton.Instance.Click.InvokeAsync);
Assert.That(this.renderer.Instance.IsDeletePopupVisible, Is.EqualTo(true));

var deleteFilePopupButton = this.renderer.FindComponents<DxButton>().First(x => x.Instance.Id == "deleteFilePopupButton");
await this.renderer.InvokeAsync(deleteFilePopupButton.Instance.Click.InvokeAsync);

Assert.Multiple(() =>
{
Assert.That(this.renderer.Instance.IsDeletePopupVisible, Is.EqualTo(false));
this.viewModel.Verify(x => x.DeleteFile(), Times.Once);
});
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="FileRevisionsTableTestFixture.cs" company="RHEA System S.A.">
// Copyright (c) 2023-2024 RHEA System S.A.
//
// Authors: Sam Gerené, Alex Vorobiev, Alexander van Delft, Jaime Bernar, Antoine Théate, João Rua
//
// This file is part of CDP4-COMET WEB Community Edition
// The CDP4-COMET WEB Community Edition is the RHEA Web Application implementation of ECSS-E-TM-10-25 Annex A and Annex C.
//
// The CDP4-COMET WEB Community Edition is free software; you can redistribute it and/or
// modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation; either
// version 3 of the License, or (at your option) any later version.
//
// The CDP4-COMET WEB Community Edition is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------

namespace COMETwebapp.Tests.Components.EngineeringModel.FileStore
{
using System.Linq;

using Bunit;

using CDP4Common.EngineeringModelData;

using COMET.Web.Common.Test.Helpers;

using COMETwebapp.Components.EngineeringModel.FileStore;
using COMETwebapp.ViewModels.Components.EngineeringModel.FileStore.FileRevisionHandler;

using DevExpress.Blazor;

using Microsoft.AspNetCore.Components.Forms;

using Moq;

using NUnit.Framework;

using TestContext = Bunit.TestContext;

[TestFixture]
public class FileRevisionsTableTestFixture
{
private TestContext context;
private IRenderedComponent<FileRevisionsTable> renderer;
private Mock<IFileRevisionHandlerViewModel> viewModel;
private List<FileRevision> fileRevisions;

[SetUp]
public void SetUp()
{
this.context = new TestContext();
this.viewModel = new Mock<IFileRevisionHandlerViewModel>();
this.fileRevisions = [new FileRevision()];

this.viewModel.Setup(x => x.FileRevision).Returns(new FileRevision());
this.viewModel.Setup(x => x.CurrentFile).Returns(new File());
this.context.ConfigureDevExpressBlazor();

this.renderer = this.context.RenderComponent<FileRevisionsTable>(parameters =>
{
parameters.Add(p => p.ViewModel, this.viewModel.Object);
parameters.Add(p => p.FileRevisions, this.fileRevisions);
});
}

[TearDown]
public void Teardown()
{
this.context.CleanContext();
this.context.Dispose();
}

[Test]
public async Task VerifyRowActions()
{
var timesFileRevisionsWasChanged = 0;

this.renderer.SetParametersAndRender(parameters =>
{
parameters.Add(p => p.FileRevisionsChanged, () => { timesFileRevisionsWasChanged += 1; });
});

var downloadButton = this.renderer.FindComponents<DxButton>().First(x => x.Instance.Id == "downloadFileRevisionButton");
await this.renderer.InvokeAsync(downloadButton.Instance.Click.InvokeAsync);
this.viewModel.Verify(x => x.DownloadFileRevision(It.IsAny<FileRevision>()), Times.Once);

var removeFileRevisionButton = this.renderer.FindComponents<DxButton>().First(x => x.Instance.Id == "removeFileRevisionButton");
await this.renderer.InvokeAsync(removeFileRevisionButton.Instance.Click.InvokeAsync);
Assert.That(timesFileRevisionsWasChanged, Is.EqualTo(1));
}

[Test]
public async Task VerifyFileRevisionCreation()
{
var timesFileRevisionsWasChanged = 0;

this.renderer.SetParametersAndRender(parameters =>
{
parameters.Add(p => p.FileRevisionsChanged, () => { timesFileRevisionsWasChanged += 1; });
});

var addFileRevisionButton = this.renderer.FindComponents<DxButton>().First(x => x.Instance.Id == "addFileRevisionButton");
await this.renderer.InvokeAsync(addFileRevisionButton.Instance.Click.InvokeAsync);

var fileInput = this.renderer.FindComponent<InputFile>();
var fileMock = new Mock<IBrowserFile>();
var changeArgs = new InputFileChangeEventArgs([fileMock.Object]);
await this.renderer.InvokeAsync(() => fileInput.Instance.OnChange.InvokeAsync(changeArgs));
this.viewModel.Verify(x => x.UploadFile(fileMock.Object), Times.Once);

var grid = this.renderer.FindComponent<DxGrid>();
await this.renderer.InvokeAsync(grid.Instance.EditModelSaving.InvokeAsync);
Assert.That(timesFileRevisionsWasChanged, Is.EqualTo(1));
}
}
}
Loading
Loading