diff --git a/src/Altinn.App.Api/Controllers/ProcessController.cs b/src/Altinn.App.Api/Controllers/ProcessController.cs index 9f9eb47c6..f3e29404e 100644 --- a/src/Altinn.App.Api/Controllers/ProcessController.cs +++ b/src/Altinn.App.Api/Controllers/ProcessController.cs @@ -1,9 +1,9 @@ +#nullable enable using System.Net; using Altinn.App.Api.Infrastructure.Filters; using Altinn.App.Api.Models; using Altinn.App.Core.Features.Validation; using Altinn.App.Core.Helpers; -using Altinn.App.Core.Internal.Auth; using Altinn.App.Core.Internal.Instances; using Altinn.App.Core.Internal.Process; using Altinn.App.Core.Internal.Process.Elements; @@ -115,9 +115,9 @@ public async Task> StartProcess( [FromRoute] string app, [FromRoute] int instanceOwnerPartyId, [FromRoute] Guid instanceGuid, - [FromQuery] string startEvent = null) + [FromQuery] string? startEvent = null) { - Instance instance = null; + Instance? instance = null; try { @@ -170,8 +170,8 @@ public async Task>> GetNextElements( [FromRoute] int instanceOwnerPartyId, [FromRoute] Guid instanceGuid) { - Instance instance = null; - string currentTaskId = null; + Instance? instance = null; + string? currentTaskId = null; try { @@ -244,8 +244,8 @@ public async Task> NextElement( [FromRoute] string app, [FromRoute] int instanceOwnerPartyId, [FromRoute] Guid instanceGuid, - [FromQuery] string elementId = null, - [FromQuery] string lang = null) + [FromQuery] string? elementId = null, + [FromQuery] string? lang = null) { try { @@ -267,7 +267,7 @@ public async Task> NextElement( return Conflict($"Process is ended."); } - string altinnTaskType = instance.Process.CurrentTask?.AltinnTaskType; + string? altinnTaskType = instance?.Process?.CurrentTask?.AltinnTaskType; if (altinnTaskType == null) { @@ -275,8 +275,8 @@ public async Task> NextElement( } bool authorized; - string checkedAction = EnsureActionNotTaskType(processNext?.Action ?? altinnTaskType); - authorized = await AuthorizeAction(checkedAction, org, app, instanceOwnerPartyId, instanceGuid, instance.Process.CurrentTask?.ElementId); + string? checkedAction = EnsureActionNotTaskType(processNext?.Action ?? altinnTaskType); + authorized = await AuthorizeAction(checkedAction, org, app, instanceOwnerPartyId, instanceGuid, instance?.Process?.CurrentTask?.ElementId); if (!authorized) { @@ -370,9 +370,9 @@ public async Task> CompleteProcess( int counter = 0; do { - string altinnTaskType = EnsureActionNotTaskType(instance.Process.CurrentTask?.AltinnTaskType); + string? altinnTaskType = EnsureActionNotTaskType(instance?.Process?.CurrentTask?.AltinnTaskType); - bool authorized = await AuthorizeAction(altinnTaskType, org, app, instanceOwnerPartyId, instanceGuid, instance.Process.CurrentTask?.ElementId); + bool authorized = await AuthorizeAction(altinnTaskType, org, app, instanceOwnerPartyId, instanceGuid, instance?.Process?.CurrentTask?.ElementId); if (!authorized) { return Forbid(); @@ -413,7 +413,7 @@ public async Task> CompleteProcess( counter++; } - while (instance.Process.EndEvent == null || counter > MaxIterationsAllowed); + while (instance?.Process?.EndEvent == null || counter > MaxIterationsAllowed); if (counter > MaxIterationsAllowed) { @@ -491,12 +491,12 @@ private ActionResult ExceptionResponse(Exception exception, string message) return StatusCode(500, $"{message}"); } - private async Task AuthorizeAction(string action, string org, string app, int instanceOwnerPartyId, Guid instanceGuid, string taskId = null) + private async Task AuthorizeAction(string action, string org, string app, int instanceOwnerPartyId, Guid instanceGuid, string? taskId = null) { return await _authorization.AuthorizeAction(new AppIdentifier(org, app), new InstanceIdentifier(instanceOwnerPartyId, instanceGuid), HttpContext.User, action, taskId); } - private static string EnsureActionNotTaskType(string actionOrTaskType) + private static string? EnsureActionNotTaskType(string? actionOrTaskType) { switch (actionOrTaskType) { @@ -531,7 +531,7 @@ private ActionResult HandlePlatformHttpException(PlatformHttpException e, string return ExceptionResponse(e, defaultMessage); } - private static async Task DeserializeFromStream(Stream stream) + private static async Task DeserializeFromStream(Stream stream) { using StreamReader reader = new StreamReader(stream); string text = await reader.ReadToEndAsync(); diff --git a/src/Altinn.App.Api/Models/ProcessNext.cs b/src/Altinn.App.Api/Models/ProcessNext.cs index 675e9f841..cfa277a87 100644 --- a/src/Altinn.App.Api/Models/ProcessNext.cs +++ b/src/Altinn.App.Api/Models/ProcessNext.cs @@ -1,3 +1,4 @@ +#nullable enable using System.Text.Json.Serialization; namespace Altinn.App.Api.Models; diff --git a/src/Altinn.App.Core/Features/Action/SigningUserAction.cs b/src/Altinn.App.Core/Features/Action/SigningUserAction.cs index db065791e..f450bdf7f 100644 --- a/src/Altinn.App.Core/Features/Action/SigningUserAction.cs +++ b/src/Altinn.App.Core/Features/Action/SigningUserAction.cs @@ -1,5 +1,4 @@ using Altinn.App.Core.Internal.App; -using Altinn.App.Core.Internal.Data; using Altinn.App.Core.Internal.Process; using Altinn.App.Core.Internal.Process.Elements; using Altinn.App.Core.Internal.Profile; @@ -19,7 +18,6 @@ public class SigningUserAction: IUserAction { private readonly IProcessReader _processReader; private readonly ILogger _logger; - private readonly IAppMetadata _appMetadata; private readonly IProfileClient _profileClient; private readonly ISignClient _signClient; @@ -28,11 +26,11 @@ public class SigningUserAction: IUserAction /// /// The process reader /// The logger - /// The application metadata service - public SigningUserAction(IProcessReader processReader, ILogger logger, IAppMetadata appMetadata, IProfileClient profileClient, ISignClient signClient) + /// The profile client + /// The sign client + public SigningUserAction(IProcessReader processReader, ILogger logger, IProfileClient profileClient, ISignClient signClient) { _logger = logger; - _appMetadata = appMetadata; _profileClient = profileClient; _signClient = signClient; _processReader = processReader; @@ -64,7 +62,7 @@ public async Task HandleAction(UserActionContext context) return false; } - private List GetDataElementSignatures(List dataElements, List dataTypesToSign) + private static List GetDataElementSignatures(List dataElements, List dataTypesToSign) { var connectedDataElements = new List(); foreach (var dataType in dataTypesToSign) diff --git a/src/Altinn.App.Core/Features/IUserAction.cs b/src/Altinn.App.Core/Features/IUserAction.cs index 2f1b5d652..61052b564 100644 --- a/src/Altinn.App.Core/Features/IUserAction.cs +++ b/src/Altinn.App.Core/Features/IUserAction.cs @@ -2,9 +2,20 @@ namespace Altinn.App.Core.Features; +/// +/// Interface for implementing custom code for user actions +/// public interface IUserAction { + /// + /// The id of the user action + /// string Id { get; } + /// + /// Method for handling the user action + /// + /// The user action context + /// If the handling of the action was a success Task HandleAction(UserActionContext context); } \ No newline at end of file diff --git a/src/Altinn.App.Core/Infrastructure/Clients/Register/AltinnPartyClient.cs b/src/Altinn.App.Core/Infrastructure/Clients/Register/AltinnPartyClient.cs index f5a03058d..b7c90cbfa 100644 --- a/src/Altinn.App.Core/Infrastructure/Clients/Register/AltinnPartyClient.cs +++ b/src/Altinn.App.Core/Infrastructure/Clients/Register/AltinnPartyClient.cs @@ -33,8 +33,6 @@ public class AltinnPartyClient : IAltinnPartyClient /// Initializes a new instance of the class /// /// The current platform settings. - /// The dsf - /// The organizationClient /// The logger /// The http context accessor /// The application settings. @@ -43,7 +41,6 @@ public class AltinnPartyClient : IAltinnPartyClient /// The platform access token generator public AltinnPartyClient( IOptions platformSettings, - IOrganizationClient organizationClient, ILogger logger, IHttpContextAccessor httpContextAccessor, IOptionsMonitor settings, diff --git a/src/Altinn.App.Core/Internal/Process/ExpressionsExclusiveGateway.cs b/src/Altinn.App.Core/Internal/Process/ExpressionsExclusiveGateway.cs index 26c441a45..f105e2210 100644 --- a/src/Altinn.App.Core/Internal/Process/ExpressionsExclusiveGateway.cs +++ b/src/Altinn.App.Core/Internal/Process/ExpressionsExclusiveGateway.cs @@ -77,7 +77,7 @@ private async Task GetLayoutEvaluatorState(Instance instan return state; } - private bool EvaluateSequenceFlow(LayoutEvaluatorState state, SequenceFlow sequenceFlow) + private static bool EvaluateSequenceFlow(LayoutEvaluatorState state, SequenceFlow sequenceFlow) { if (sequenceFlow.ConditionExpression != null) { @@ -123,8 +123,8 @@ private static Expression GetExpressionFromCondition(string condition) LayoutSet? layoutSet = null; if (!string.IsNullOrEmpty(layoutSetsString)) { - LayoutSets? layoutSets = JsonSerializer.Deserialize(layoutSetsString, options)!; - layoutSet = layoutSets?.Sets?.FirstOrDefault(t => t.Tasks.Contains(taskId)); + LayoutSets? layoutSets = JsonSerializer.Deserialize(layoutSetsString, options); + layoutSet = layoutSets?.Sets?.Find(t => t.Tasks.Contains(taskId)); } return layoutSet; @@ -136,15 +136,15 @@ private static Expression GetExpressionFromCondition(string condition) DataType? dataType; if (dataTypeId != null) { - dataType = (await _appMetadata.GetApplicationMetadata()).DataTypes.FirstOrDefault(d => d.Id == dataTypeId && d.AppLogic != null); + dataType = (await _appMetadata.GetApplicationMetadata()).DataTypes.Find(d => d.Id == dataTypeId && d.AppLogic != null); } else if (layoutSet != null) { - dataType = (await _appMetadata.GetApplicationMetadata()).DataTypes.FirstOrDefault(d => d.Id == layoutSet.DataType && d.AppLogic != null); + dataType = (await _appMetadata.GetApplicationMetadata()).DataTypes.Find(d => d.Id == layoutSet.DataType && d.AppLogic != null); } else { - dataType = (await _appMetadata.GetApplicationMetadata()).DataTypes.FirstOrDefault(d => d.TaskId == instance.Process.CurrentTask.ElementId && d.AppLogic != null); + dataType = (await _appMetadata.GetApplicationMetadata()).DataTypes.Find(d => d.TaskId == instance.Process.CurrentTask.ElementId && d.AppLogic != null); } if (dataType != null) @@ -157,7 +157,7 @@ private static Expression GetExpressionFromCondition(string condition) private static Guid? GetDataId(Instance instance, string dataType) { - string? dataId = instance.Data.FirstOrDefault(d => d.DataType == dataType)?.Id; + string? dataId = instance.Data.Find(d => d.DataType == dataType)?.Id; if (dataId != null) { return new Guid(dataId); diff --git a/src/Altinn.App.Core/Internal/Process/ProcessEngine.cs b/src/Altinn.App.Core/Internal/Process/ProcessEngine.cs index 7a17004ef..08f1ece2f 100644 --- a/src/Altinn.App.Core/Internal/Process/ProcessEngine.cs +++ b/src/Altinn.App.Core/Internal/Process/ProcessEngine.cs @@ -72,9 +72,9 @@ public async Task StartProcess(ProcessStartRequest processS // start process ProcessStateChange? startChange = await ProcessStart(processStartRequest.Instance, validStartElement!, processStartRequest.User); - InstanceEvent? startEvent = startChange?.Events?.First().CopyValues(); + InstanceEvent? startEvent = startChange?.Events?[0].CopyValues(); ProcessStateChange? nextChange = await ProcessNext(processStartRequest.Instance, processStartRequest.User); - InstanceEvent? goToNextEvent = nextChange?.Events?.First().CopyValues(); + InstanceEvent? goToNextEvent = nextChange?.Events?[0].CopyValues(); List events = new List(); if (startEvent is not null) { diff --git a/src/Altinn.App.Core/Models/UserAction/UserActionContext.cs b/src/Altinn.App.Core/Models/UserAction/UserActionContext.cs index 1f8ea3136..1076c49e2 100644 --- a/src/Altinn.App.Core/Models/UserAction/UserActionContext.cs +++ b/src/Altinn.App.Core/Models/UserAction/UserActionContext.cs @@ -2,15 +2,29 @@ namespace Altinn.App.Core.Models.UserAction; +/// +/// Context for user actions +/// public class UserActionContext { + /// + /// Creates a new instance of the class + /// + /// The instance the action is performed on + /// The user performing the action public UserActionContext(Instance instance, int userId) { Instance = instance; UserId = userId; } + /// + /// The instance the action is performed on + /// public Instance Instance { get; } + /// + /// The user performing the action + /// public int UserId { get; } } \ No newline at end of file diff --git a/test/Altinn.App.Core.Tests/Features/Action/SigningUserActionTests.cs b/test/Altinn.App.Core.Tests/Features/Action/SigningUserActionTests.cs index 552e47845..7b77a6c26 100644 --- a/test/Altinn.App.Core.Tests/Features/Action/SigningUserActionTests.cs +++ b/test/Altinn.App.Core.Tests/Features/Action/SigningUserActionTests.cs @@ -111,14 +111,7 @@ public async void HandleAction_throws_ApplicationConfigException_if_SignatureDat private static (SigningUserAction SigningUserAction, Mock SignClientMock) CreateSigningUserAction(UserProfile userProfileToReturn = null, PlatformHttpException platformHttpExceptionToThrow = null, string testBpmnfilename = "signing-task-process.bpmn") { IProcessReader processReader = ProcessTestUtils.SetupProcessReader(testBpmnfilename, Path.Combine("Features", "Action", "TestData")); - AppSettings appSettings = new AppSettings() - { - AppBasePath = Path.Combine("Features", "Action"), - ConfigurationFolder = "TestData", - ApplicationMetadataFileName = "appmetadata.json" - }; - IAppMetadata appMetadata = new AppMetadata(Options.Create(appSettings), new FrontendFeatures(new Mock().Object)); var profileClientMock = new Mock(); var signingClientMock = new Mock(); profileClientMock.Setup(p => p.GetUserProfile(It.IsAny())).ReturnsAsync(userProfileToReturn); @@ -127,7 +120,7 @@ private static (SigningUserAction SigningUserAction, Mock SignClien signingClientMock.Setup(p => p.SignDataElements(It.IsAny())).ThrowsAsync(platformHttpExceptionToThrow); } - return (new SigningUserAction(processReader, new NullLogger(), appMetadata, profileClientMock.Object, signingClientMock.Object), signingClientMock); + return (new SigningUserAction(processReader, new NullLogger(), profileClientMock.Object, signingClientMock.Object), signingClientMock); } private bool AssertSigningContextAsExpected(SignatureContext s1, SignatureContext s2)