diff --git a/src/Altinn.Correspondence.API/Controllers/LegacyCorrespondenceController.cs b/src/Altinn.Correspondence.API/Controllers/LegacyCorrespondenceController.cs index 925ed961..32a9902a 100644 --- a/src/Altinn.Correspondence.API/Controllers/LegacyCorrespondenceController.cs +++ b/src/Altinn.Correspondence.API/Controllers/LegacyCorrespondenceController.cs @@ -1,18 +1,11 @@ +using System.Runtime.CompilerServices; using Altinn.Correspondence.API.Models; -using Altinn.Correspondence.API.Models.Enums; using Altinn.Correspondence.Application; using Altinn.Correspondence.Application.Configuration; using Altinn.Correspondence.Application.DownloadCorrespondenceAttachment; -using Altinn.Correspondence.Application.GetCorrespondenceDetails; using Altinn.Correspondence.Application.GetCorrespondenceHistory; using Altinn.Correspondence.Application.GetCorrespondenceOverview; using Altinn.Correspondence.Application.GetCorrespondences; -using Altinn.Correspondence.Application.InitializeCorrespondences; -using Altinn.Correspondence.Application.PurgeCorrespondence; -using Altinn.Correspondence.Application.UpdateCorrespondenceStatus; -using Altinn.Correspondence.Application.UpdateMarkAsUnread; -using Altinn.Correspondence.Core.Models.Enums; -using Altinn.Correspondence.Helpers; using Altinn.Correspondence.Mappers; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; @@ -115,6 +108,30 @@ public async Task> GetCorrespondences( ); } + /// + /// Download an attachment from a Correspondence + /// + [HttpGet] + [Route("{correspondenceId}/attachment/{attachmentId}/download")] + [ApiExplorerSettings(IgnoreApi = true)] + public async Task DownloadCorrespondenceAttachment( + Guid correspondenceId, + Guid attachmentId, + [FromServices] LegacyDownloadCorrespondenceAttachmentHandler handler, + CancellationToken cancellationToken) + { + var commandResult = await handler.Process(new DownloadCorrespondenceAttachmentRequest() + { + CorrespondenceId = correspondenceId, + AttachmentId = attachmentId + }, cancellationToken); + + return commandResult.Match( + result => File(result.Stream, "application/octet-stream", result.FileName), + Problem + ); + } + private ActionResult Problem(Error error) => Problem(detail: error.Message, statusCode: (int)error.StatusCode); } } diff --git a/src/Altinn.Correspondence.Application/DependencyInjection.cs b/src/Altinn.Correspondence.Application/DependencyInjection.cs index 3bc0ca57..a99cff07 100644 --- a/src/Altinn.Correspondence.Application/DependencyInjection.cs +++ b/src/Altinn.Correspondence.Application/DependencyInjection.cs @@ -58,6 +58,7 @@ public static void AddApplicationHandlers(this IServiceCollection services) services.AddScoped(); services.AddScoped(); services.AddScoped(); + services.AddScoped(); // Migration services.AddScoped(); diff --git a/src/Altinn.Correspondence.Application/DownloadCorrespondenceAttachment/LegacyDownloadCorrespondenceAttachmentHandler.cs b/src/Altinn.Correspondence.Application/DownloadCorrespondenceAttachment/LegacyDownloadCorrespondenceAttachmentHandler.cs new file mode 100644 index 00000000..53635bf6 --- /dev/null +++ b/src/Altinn.Correspondence.Application/DownloadCorrespondenceAttachment/LegacyDownloadCorrespondenceAttachmentHandler.cs @@ -0,0 +1,69 @@ +using Altinn.Correspondence.Application.Helpers; +using Altinn.Correspondence.Core.Repositories; +using Altinn.Correspondence.Core.Services; +using Altinn.Correspondence.Core.Services.Enums; +using Hangfire; +using OneOf; + +namespace Altinn.Correspondence.Application.DownloadCorrespondenceAttachment; + +public class LegacyDownloadCorrespondenceAttachmentHandler : IHandler +{ + private readonly ICorrespondenceRepository _correspondenceRepository; + private readonly IStorageRepository _storageRepository; + private readonly IAttachmentRepository _attachmentRepository; + private readonly IAltinnRegisterService _altinnRegisterService; + private readonly UserClaimsHelper _userClaimsHelper; + private readonly IBackgroundJobClient _backgroundJobClient; + + public LegacyDownloadCorrespondenceAttachmentHandler(IStorageRepository storageRepository, IAttachmentRepository attachmentRepository, ICorrespondenceRepository correspondenceRepository, UserClaimsHelper userClaimsHelper, IBackgroundJobClient backgroundJobClient, IAltinnRegisterService altinnRegisterService) + { + _correspondenceRepository = correspondenceRepository; + _storageRepository = storageRepository; + _attachmentRepository = attachmentRepository; + _altinnRegisterService = altinnRegisterService; + _userClaimsHelper = userClaimsHelper; + _backgroundJobClient = backgroundJobClient; + } + + public async Task> Process(DownloadCorrespondenceAttachmentRequest request, CancellationToken cancellationToken) + { + var partyId = _userClaimsHelper.GetPartyId(); + if (partyId is null) + { + return Errors.InvalidPartyId; + } + var party = await _altinnRegisterService.LookUpPartyByPartyId(partyId.Value, cancellationToken); + if (party is null || (string.IsNullOrEmpty(party.SSN) && string.IsNullOrEmpty(party.OrgNumber))) + { + return Errors.CouldNotFindOrgNo; + } + + var correspondence = await _correspondenceRepository.GetCorrespondenceById(request.CorrespondenceId, true, false, cancellationToken); + if (correspondence is null) + { + return Errors.CorrespondenceNotFound; + } + var attachment = await _attachmentRepository.GetAttachmentByCorrespondenceIdAndAttachmentId(request.CorrespondenceId, request.AttachmentId, cancellationToken); + if (attachment is null) + { + return Errors.AttachmentNotFound; + } + bool isRecipient = correspondence.Recipient == ("0192:"+party.OrgNumber) || correspondence.Recipient == party.SSN; + if (!isRecipient) + { + return Errors.CorrespondenceNotFound; + } + var latestStatus = correspondence.GetLatestStatus(); + if (!latestStatus.Status.IsAvailableForRecipient()) + { + return Errors.CorrespondenceNotFound; + } + var attachmentStream = await _storageRepository.DownloadAttachment(attachment.Id, cancellationToken); + _backgroundJobClient.Enqueue((dialogportenService) => dialogportenService.CreateInformationActivity(request.CorrespondenceId, DialogportenActorType.Recipient, DialogportenTextType.DownloadStarted, attachment.FileName ?? attachment.Name)); + return new DownloadCorrespondenceAttachmentResponse(){ + FileName = attachment.FileName ?? attachment.Name, + Stream = attachmentStream + }; + } +} diff --git a/src/Altinn.Correspondence.Application/Helpers/UserClaimsHelper.cs b/src/Altinn.Correspondence.Application/Helpers/UserClaimsHelper.cs index 001408ea..b7fbd28f 100644 --- a/src/Altinn.Correspondence.Application/Helpers/UserClaimsHelper.cs +++ b/src/Altinn.Correspondence.Application/Helpers/UserClaimsHelper.cs @@ -18,6 +18,7 @@ public class UserClaimsHelper private const string _consumerClaim = "consumer"; private const string _IdProperty = "ID"; private const string _dialogportenOrgClaim = "p"; + private const string _partyIdClaim = "urn:altinn:partyid"; public UserClaimsHelper(IHttpContextAccessor httpContextAccessor, IOptions dialogportenSettings, IOptions idportenSettings) { @@ -26,6 +27,13 @@ public UserClaimsHelper(IHttpContextAccessor httpContextAccessor, IOptions c.Type == _partyIdClaim)?.Value; + if (partyId is null) return null; + if (int.TryParse(partyId, out int id)) return id; + return null; + } public bool IsAffiliatedWithCorrespondence(string recipientId, string senderId) { return IsRecipient(recipientId) || IsSender(senderId);