Skip to content

Commit

Permalink
Endpoint for updating task name (#11814)
Browse files Browse the repository at this point in the history
* Endpoint for updating task name

* Added the actual endpoint

* exception handling and update tests

* Format changes

* imports ordering
  • Loading branch information
nkylstad authored Dec 7, 2023
1 parent 0f50ca7 commit 2605647
Show file tree
Hide file tree
Showing 6 changed files with 197 additions and 1 deletion.
22 changes: 22 additions & 0 deletions backend/src/Designer/Controllers/ProcessModelingController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -73,5 +73,27 @@ public async Task<FileStreamResult> SaveProcessDefinitionFromTemplate(string org
Stream processDefinitionStream = _processModelingService.GetProcessDefinitionStream(editingContext);
return new FileStreamResult(processDefinitionStream, MediaTypeNames.Text.Plain);
}

[HttpPut("tasks/{taskId}/{taskName}")]
public async Task<ActionResult> UpdateProcessTaskName(string org, string repo, string taskId, string taskName, CancellationToken cancellationToken)
{
Guard.AssertArgumentNotNull(taskId, nameof(taskId));
Guard.AssertArgumentNotNull(taskName, nameof(taskName));
string developer = AuthenticationHelper.GetDeveloperUserName(HttpContext);
var editingContext = AltinnRepoEditingContext.FromOrgRepoDeveloper(org, repo, developer);
try
{
Stream updatedProcessDefinitionStream = await _processModelingService.UpdateProcessTaskNameAsync(editingContext, taskId, taskName, cancellationToken);
return new FileStreamResult(updatedProcessDefinitionStream, MediaTypeNames.Text.Plain);
}
catch (InvalidOperationException)
{
return BadRequest("Could not deserialize process definition.");
}
catch (ArgumentException)
{
return BadRequest("Could not find task with given id.");
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
using System;
#nullable enable
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Xml.Serialization;
using Altinn.App.Core.Internal.Process.Elements;
using Altinn.Studio.Designer.Infrastructure.GitRepository;
using Altinn.Studio.Designer.Models;
using Altinn.Studio.Designer.Services.Interfaces;
Expand Down Expand Up @@ -52,6 +55,37 @@ public Stream GetProcessDefinitionStream(AltinnRepoEditingContext altinnRepoEdit
return altinnAppGitRepository.GetProcessDefinitionFile();
}

public async Task<Stream> UpdateProcessTaskNameAsync(AltinnRepoEditingContext altinnRepoEditingContext, string taskId, string taskName, CancellationToken cancellationToken = default)
{
cancellationToken.ThrowIfCancellationRequested();
AltinnAppGitRepository altinnAppGitRepository = _altinnGitRepositoryFactory.GetAltinnAppGitRepository(altinnRepoEditingContext.Org, altinnRepoEditingContext.Repo, altinnRepoEditingContext.Developer);
XmlSerializer serializer = new(typeof(Definitions));
Definitions? definitions;
using (Stream processDefinitionStream = GetProcessDefinitionStream(altinnRepoEditingContext))
{
definitions = (Definitions?)serializer.Deserialize(processDefinitionStream);
}

if (definitions == null)
{
throw new InvalidOperationException("Could not deserialize process definition.");
}

ProcessTask? processTask = (definitions.Process.Tasks?.FirstOrDefault(t => t.Id == taskId)) ?? throw new ArgumentException($"Could not find task with id {taskId}.");
processTask.Name = taskName;

Stream processStream = new MemoryStream();
serializer.Serialize(processStream, definitions);

// Reset stream position to beginning after serialization
processStream.Seek(0, SeekOrigin.Begin);
await altinnAppGitRepository.SaveProcessDefinitionFileAsync(processStream, cancellationToken);

// Reset stream position to beginning after saving
processStream.Seek(0, SeekOrigin.Begin);
return processStream;
}

private IEnumerable<string> EnumerateTemplateResources(Version version)
{
return typeof(ProcessModelingService).Assembly.GetManifestResourceNames()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,15 @@ public interface IProcessModelingService
/// <param name="altinnRepoEditingContext">An <see cref="AltinnRepoEditingContext"/>.</param>
/// <returns>A <see cref="Stream"/> of a process definition file.</returns>
Stream GetProcessDefinitionStream(AltinnRepoEditingContext altinnRepoEditingContext);

/// <summary>
/// Updates the name of a task in the process definition file.
/// </summary>
/// <param name="altinnRepoEditingContext">n <see cref="AltinnRepoEditingContext"/>.</param>
/// <param name="taskId">The ID of the task to update</param>
/// <param name="taskName">The name to set for the task</param>
/// <param name="cancellationToken">A <see cref="CancellationToken"/> that observes if operation is cancelled.</param>
/// <returns></returns>
Task<Stream> UpdateProcessTaskNameAsync(AltinnRepoEditingContext altinnRepoEditingContext, string taskId, string taskName, CancellationToken cancellationToken = default);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
using System.Net;
using System.Net.Http;
using System.Net.Mime;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
using Designer.Tests.Controllers.ApiTests;
using Designer.Tests.Utils;
using FluentAssertions;
using Microsoft.AspNetCore.Mvc.Testing;
using Xunit;

namespace Designer.Tests.Controllers.ProcessModelingController
{
public class UpdateProcessTaskName : DisagnerEndpointsTestsBase<UpdateProcessTaskName>, IClassFixture<WebApplicationFactory<Program>>
{
private static string Url(string org, string repository, string taskId, string taskName) => $"/designer/api/{org}/{repository}/process-modelling/tasks/{taskId}/{taskName}";

public UpdateProcessTaskName(WebApplicationFactory<Program> factory) : base(factory)
{
}

[Theory]
[InlineData("ttd", "app-with-process", "testUser", "Task_1", "NewTaskName")]
public async Task UpdateProcessTaskName_ShouldReturnUpdatedProcess(string org, string app, string developer, string taskId, string taskName)
{
string targetRepository = TestDataHelper.GenerateTestRepoName();
await CopyRepositoryForTest(org, app, developer, targetRepository);

string url = Url(org, targetRepository, taskId, taskName);

using var response = await HttpClient.PutAsync(url, null);
response.StatusCode.Should().Be(HttpStatusCode.OK);

string responseContent = await response.Content.ReadAsStringAsync();

responseContent.Should().NotBeNullOrEmpty();
responseContent.Should().Contain(taskName);
}

[Theory]
[InlineData("ttd", "app-with-process", "testUser", "Does_not_exist", "NewTaskName")]
public async Task InvalidTaskId_ShouldReturnBadRequest(string org, string app, string developer, string taskId, string taskName)
{
string targetRepository = TestDataHelper.GenerateTestRepoName();
await CopyRepositoryForTest(org, app, developer, targetRepository);

string url = Url(org, targetRepository, taskId, taskName);

using var response = await HttpClient.PutAsync(url, null);
response.StatusCode.Should().Be(HttpStatusCode.BadRequest);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml.Serialization;
using Altinn.App.Core.Internal.Process.Elements;
using Altinn.Studio.Designer.Factories;
using Altinn.Studio.Designer.Models;
using Altinn.Studio.Designer.Services.Implementation.ProcessModeling;
using Altinn.Studio.Designer.Services.Interfaces;
using Designer.Tests.Utils;
using FluentAssertions;
using Moq;
using SharedResources.Tests;
Expand Down Expand Up @@ -30,6 +36,34 @@ public void GetProcessDefinitionTemplates_GivenVersion_ReturnsListOfTemplates(st
}
}

[Theory]
[InlineData("ttd", "app-with-process", "testUser", "Task_1", "NewTaskName")]
public async void UpdateProcessTaskNameAsync_GivenTaskIdAndTaskName_UpdatesTaskName(string org, string repo, string developer, string taskId, string newTaskName)
{
// Arrange
string targetRepository = TestDataHelper.GenerateTestRepoName();
var editingContext = AltinnRepoEditingContext.FromOrgRepoDeveloper(org, targetRepository, developer);
await TestDataHelper.CopyRepositoryForTest(org, repo, developer, targetRepository);

try
{
var altinnGitRepositoryFactory = new AltinnGitRepositoryFactory(TestDataHelper.GetTestDataRepositoriesRootDirectory());
IProcessModelingService processModelingService = new ProcessModelingService(altinnGitRepositoryFactory);

// Act
using Stream result = await processModelingService.UpdateProcessTaskNameAsync(editingContext, taskId, newTaskName);
XmlSerializer serializer = new(typeof(Definitions));
Definitions definitions = (Definitions)serializer.Deserialize(result);

// Assert
definitions.Process.Tasks.First(t => t.Id == taskId).Name.Should().Be(newTaskName);
}
finally
{
TestDataHelper.DeleteAppRepository(org, targetRepository, developer);
}
}

public static IEnumerable<object[]> TemplatesTestData => new List<object[]>
{
new object[]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<bpmn:definitions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:altinn="http://altinn.no" xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" id="Altinn_SingleDataTask_Process_Definition" targetNamespace="http://bpmn.io/schema/bpmn">
<bpmn:process id="SingleDataTask" isExecutable="false">
<bpmn:startEvent id="StartEvent_1">
<bpmn:outgoing>SequenceFlow_1n56yn5</bpmn:outgoing>
</bpmn:startEvent>
<bpmn:endEvent id="EndEvent_1">
<bpmn:incoming>Flow_1htunjv</bpmn:incoming>
</bpmn:endEvent>
<bpmn:sequenceFlow id="SequenceFlow_1n56yn5" sourceRef="StartEvent_1" targetRef="Task_1" />
<bpmn:task id="Task_1" name="Utfylling">
<bpmn:extensionElements>
<altinn:taskExtension>
<altinn:taskType>data</altinn:taskType>
</altinn:taskExtension>
</bpmn:extensionElements>
<bpmn:incoming>SequenceFlow_1n56yn5</bpmn:incoming>
<bpmn:outgoing>Flow_1htunjv</bpmn:outgoing>
</bpmn:task>
<bpmn:sequenceFlow id="Flow_1htunjv" sourceRef="Task_1" targetRef="EndEvent_1" />
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="SingleDataTask">
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
<dc:Bounds x="156" y="81" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Task_1_di" bpmnElement="Task_1">
<dc:Bounds x="260" y="59" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="EndEvent_1_di" bpmnElement="EndEvent_1">
<dc:Bounds x="422" y="81" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="SequenceFlow_1n56yn5_di" bpmnElement="SequenceFlow_1n56yn5">
<di:waypoint x="192" y="99" />
<di:waypoint x="260" y="99" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1htunjv_di" bpmnElement="Flow_1htunjv">
<di:waypoint x="360" y="99" />
<di:waypoint x="422" y="99" />
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>

0 comments on commit 2605647

Please sign in to comment.