Skip to content

Commit

Permalink
Share My Information - ZIP FILE - Document download (#755)
Browse files Browse the repository at this point in the history
* Share My Information - ZIP FILE - Document download

* Fix merge issue
  • Loading branch information
dharmverma authored Oct 15, 2024
1 parent 33f2a94 commit ade4bc6
Show file tree
Hide file tree
Showing 23 changed files with 192 additions and 128 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public async Task OnGetDownload_ShouldReturnFile_WhenPdfIsDownloadedSuccessfully
var fileResponseMock = new WebApiClient.FileResponse(200, headers, stream, clientMock.Object, responseMock.Object);

_dataSharingApiClientMock
.Setup(x => x.GetSharedDataPdfAsync(shareCode))
.Setup(x => x.GetSharedDataFileAsync(shareCode))
.ReturnsAsync(fileResponseMock);

_pageModel.ShareCode = shareCode;
Expand Down Expand Up @@ -79,7 +79,7 @@ public async Task OnGetDownload_ShouldRedirectToPageNotFound_WhenFileIsNotFound(
var shareCode = "HDJ2123F";

_dataSharingApiClientMock
.Setup(x => x.GetSharedDataPdfAsync(shareCode))
.Setup(x => x.GetSharedDataFileAsync(shareCode))
.ReturnsAsync((WebApiClient.FileResponse?)null);

var result = await _pageModel.OnGetDownload();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ public async Task OnGetDownload_ShouldReturnFileResult_WhenPdfIsDownloadedSucces
var stream = new MemoryStream(pdfBytes);
var fileResponseMock = new WebApiClient.FileResponse(200, headers, stream, clientMock.Object, responseMock.Object);

_dataSharingApiClientMock.Setup(x => x.GetSharedDataPdfAsync(shareCode))
_dataSharingApiClientMock.Setup(x => x.GetSharedDataFileAsync(shareCode))
.ReturnsAsync(fileResponseMock);

var result = await _pageModel.OnGetDownload(shareCode);
Expand All @@ -108,7 +108,7 @@ public async Task OnGetDownload_ShouldRedirectToPageNotFound_WhenPdfResponseIsNu
{
var shareCode = "HDJ2123F";

_dataSharingApiClientMock.Setup(x => x.GetSharedDataPdfAsync(shareCode))
_dataSharingApiClientMock.Setup(x => x.GetSharedDataFileAsync(shareCode))
.ReturnsAsync((WebApiClient.FileResponse?)null);

var result = await _pageModel.OnGetDownload(shareCode);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ public async Task OnGetDownload_ShouldReturnFile_WhenPdfIsDownloadedSuccessfully
var fileResponseMock = new WebApiClient.FileResponse(200, headers, stream, clientMock.Object, responseMock.Object);

_dataSharingApiClientMock
.Setup(x => x.GetSharedDataPdfAsync(shareCode))
.Setup(x => x.GetSharedDataFileAsync(shareCode))
.ReturnsAsync(fileResponseMock);

var result = await _pageModel.OnGetDownload(shareCode);
Expand All @@ -137,7 +137,7 @@ public async Task OnGetDownload_ShouldRedirectToPageNotFound_WhenFileIsNotFound(
var shareCode = "HDJ2123F";

_dataSharingApiClientMock
.Setup(x => x.GetSharedDataPdfAsync(shareCode))
.Setup(x => x.GetSharedDataFileAsync(shareCode))
.ReturnsAsync((WebApiClient.FileResponse?)null);

var result = await _pageModel.OnGetDownload(shareCode);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public async Task<IActionResult> OnGetDownload()
return Redirect("/page-not-found");
}

var fileResponse = await dataSharingClient.GetSharedDataPdfAsync(ShareCode);
var fileResponse = await dataSharingClient.GetSharedDataFileAsync(ShareCode);

if (fileResponse == null)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public async Task<IActionResult> OnGetDownload(string shareCode)
return Redirect("/page-not-found");
}

var fileResponse = await dataSharingClient.GetSharedDataPdfAsync(shareCode);
var fileResponse = await dataSharingClient.GetSharedDataFileAsync(shareCode);

if (fileResponse == null)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public async Task<IActionResult> OnGetDownload(string shareCode)
return Redirect("/page-not-found");
}

var fileResponse = await dataSharingClient.GetSharedDataPdfAsync(shareCode);
var fileResponse = await dataSharingClient.GetSharedDataFileAsync(shareCode);

if (fileResponse == null)
{
Expand Down
13 changes: 6 additions & 7 deletions Libraries/CO.CDP.Authentication.Tests/ClaimServiceTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,14 @@ namespace CO.CDP.Authentication.Tests;
public class ClaimServiceTests
{
private readonly Mock<IOrganisationRepository> mockOrgRepo = new();
private readonly Mock<IPersonRepository> mockPersonRepo = new();

[Fact]
public void GetUserUrn_ShouldReturnUrn_WhenUserHasSubClaim()
{
var userUrn = "urn:fdc:gov.uk:2022:rynbwxUssDAcmU38U5gxd7dBfu9N7KFP9_nqDuZ66Hg";
var httpContextAccessor = GivenHttpContextWith([new(ClaimType.Subject, userUrn)]);

var claimService = new ClaimService(httpContextAccessor.Object, mockOrgRepo.Object, mockPersonRepo.Object);
var claimService = new ClaimService(httpContextAccessor.Object, mockOrgRepo.Object);

var result = claimService.GetUserUrn();
result.Should().Be(userUrn);
Expand All @@ -29,7 +28,7 @@ public void GetUserUrn_ShouldReturnNull_WhenUserHasNoSubClaim()
{
var httpContextAccessor = GivenHttpContextWith([]);

var claimService = new ClaimService(httpContextAccessor.Object, mockOrgRepo.Object, mockPersonRepo.Object);
var claimService = new ClaimService(httpContextAccessor.Object, mockOrgRepo.Object);
var result = claimService.GetUserUrn();

result.Should().BeNull();
Expand All @@ -40,7 +39,7 @@ public async Task HaveAccessToOrganisation_ShouldReturnFalse_WhenUserHasNoSubCla
{
var httpContextAccessor = GivenHttpContextWith([]);

var claimService = new ClaimService(httpContextAccessor.Object, mockOrgRepo.Object, mockPersonRepo.Object);
var claimService = new ClaimService(httpContextAccessor.Object, mockOrgRepo.Object);
var result = await claimService.HaveAccessToOrganisation(Guid.NewGuid());

result.Should().BeFalse();
Expand All @@ -56,7 +55,7 @@ public async Task HaveAccessToOrganisation_ShouldReturnFalse_WhenUserHasNoTenant
mockOrgRepo.Setup(m => m.FindOrganisationPerson(organisationId, userUrn))
.ReturnsAsync((OrganisationPerson?)default);

var claimService = new ClaimService(httpContextAccessor.Object, mockOrgRepo.Object, mockPersonRepo.Object);
var claimService = new ClaimService(httpContextAccessor.Object, mockOrgRepo.Object);
var result = await claimService.HaveAccessToOrganisation(organisationId);

result.Should().BeFalse();
Expand All @@ -77,7 +76,7 @@ public async Task HaveAccessToOrganisation_ShouldReturnTrue_WhenDoesHaveAccessTo
Scopes = ["Admin"]
});

var claimService = new ClaimService(httpContextAccessor.Object, mockOrgRepo.Object, mockPersonRepo.Object);
var claimService = new ClaimService(httpContextAccessor.Object, mockOrgRepo.Object);
var result = await claimService.HaveAccessToOrganisation(organisationId);

result.Should().BeTrue();
Expand All @@ -98,7 +97,7 @@ public async Task HaveAccessToOrganisation_ShouldReturnTrue_WhenUserIsSupportAdm
Scopes = []
});

var claimService = new ClaimService(httpContextAccessor.Object, mockOrgRepo.Object, mockPersonRepo.Object);
var claimService = new ClaimService(httpContextAccessor.Object, mockOrgRepo.Object);
var result = await claimService.HaveAccessToOrganisation(organisationId, null, [PersonScope.SupportAdmin]);

result.Should().BeTrue();
Expand Down
30 changes: 17 additions & 13 deletions Libraries/CO.CDP.Authentication/ClaimService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,34 @@ namespace CO.CDP.Authentication;

public class ClaimService(
IHttpContextAccessor httpContextAccessor,
IOrganisationRepository organisationRepository,
IPersonRepository personRepository) : IClaimService
IOrganisationRepository organisationRepository) : IClaimService
{
public string? GetUserUrn()
{
return httpContextAccessor.HttpContext?.User?.FindFirst(ClaimType.Subject)?.Value;
}

public IEnumerable<string> GetUserRoles()
{
var roles = httpContextAccessor.HttpContext?.User?.FindFirst(ClaimType.Roles)?.Value;
return string.IsNullOrWhiteSpace(roles) ? [] : roles.Split(",", StringSplitOptions.RemoveEmptyEntries);
}

public Guid? GetOrganisationId()
{
if (Guid.TryParse(httpContextAccessor.HttpContext?.User?.FindFirst(ClaimType.OrganisationId)?.Value, out Guid result))
{
return result;
}
return null;
}

public async Task<bool> HaveAccessToOrganisation(Guid organisationId, string[]? scopes = null, string[]? personScopes = null)
{
var userUrn = GetUserUrn();
if (string.IsNullOrWhiteSpace(userUrn)) return false;

var person = await personRepository.FindByUrn(userUrn);
if (person != null && personScopes != null && person.Scopes.Intersect(personScopes).Any())
if (personScopes != null && GetUserRoles().Intersect(personScopes).Any())
{
return true;
}
Expand All @@ -32,13 +45,4 @@ public async Task<bool> HaveAccessToOrganisation(Guid organisationId, string[]?

return organisationPerson.Scopes.Intersect(scopes).Any();
}

public Guid? GetOrganisationId()
{
if (Guid.TryParse(httpContextAccessor.HttpContext?.User?.FindFirst(ClaimType.OrganisationId)?.Value, out Guid result))
{
return result;
}
return null;
}
}
2 changes: 2 additions & 0 deletions Libraries/CO.CDP.Authentication/IClaimService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ public interface IClaimService
{
string? GetUserUrn();

IEnumerable<string> GetUserRoles();

Guid? GetOrganisationId();

Task<bool> HaveAccessToOrganisation(Guid organisationId, string[] scopes, string[]? personScopes = null);
Expand Down
2 changes: 2 additions & 0 deletions Libraries/CO.CDP.AwsServices/IFileHostManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ public interface IFileHostManager
{
Task UploadFile(Stream fileStream, string filename, string contentType);

Task<Stream> DownloadFile(string filename);

Task CopyToPermanentBucket(string filename, bool deleteInSource = true);

Task RemoveFromPermanentBucket(string filename);
Expand Down
10 changes: 10 additions & 0 deletions Libraries/CO.CDP.AwsServices/S3/AwsFileManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,16 @@ await s3Client.PutObjectAsync(
}
}

public async Task<Stream> DownloadFile(string filename)
{
ArgumentException.ThrowIfNullOrWhiteSpace(filename);

var permanentBucket = awsConfig.Buckets?.PermanentBucket
?? throw new Exception($"Missing Aws configuration '{nameof(awsConfig.Buckets.PermanentBucket)}' key.");

return await s3Client.GetObjectStreamAsync(permanentBucket, filename, new Dictionary<string, object>());
}

public async Task CopyToPermanentBucket(string filename, bool deleteInSource = true)
{
ArgumentException.ThrowIfNullOrWhiteSpace(filename);
Expand Down
11 changes: 6 additions & 5 deletions Services/CO.CDP.DataSharing.WebApi.Tests/Api/DataSharingTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ namespace CO.CDP.DataSharing.WebApi.Tests.Api;
public class DataSharingTests
{
private readonly Mock<IUseCase<string, SupplierInformation?>> _getSharedDataUseCase = new();
private readonly Mock<IUseCase<string, byte[]?>> _getSharedDataPdfUseCase = new();
private readonly Mock<IUseCase<string, SharedDataFile?>> _getSharedDataFileUseCase = new();
private readonly Mock<IUseCase<ShareRequest, ShareReceipt>> _generateShareCodeUseCase = new();
private readonly Mock<IUseCase<ShareVerificationRequest, ShareVerificationReceipt>> _getShareCodeVerifyUseCase = new();
private readonly Mock<IUseCase<Guid, List<SharedConsent>?>> _getShareCodesUseCase = new();
Expand Down Expand Up @@ -73,17 +73,18 @@ public async Task GetSharedDataDocumentDownloadUrl_Authorization_ReturnsExpected
[InlineData(Forbidden, Channel.ServiceKey)]
[InlineData(Forbidden, Channel.OrganisationKey)]
[InlineData(Forbidden, "unknown_channel")]
public async Task GetSharedDataPdf_Authorization_ReturnsExpectedStatusCode(
public async Task GetSharedDataFile_Authorization_ReturnsExpectedStatusCode(
HttpStatusCode expectedStatusCode, string channel)
{
var shareCode = "valid-share-code";

_getSharedDataPdfUseCase.Setup(uc => uc.Execute(shareCode)).ReturnsAsync(new byte[1]);
_getSharedDataFileUseCase.Setup(uc => uc.Execute(shareCode))
.ReturnsAsync(new SharedDataFile { Content = new byte[1], ContentType = "application/pdf", FileName = "test_file.pdf" });

var factory = new TestAuthorizationWebApplicationFactory<Program>(
channel, serviceCollection: s => s.AddScoped(_ => _getSharedDataPdfUseCase.Object));
channel, serviceCollection: s => s.AddScoped(_ => _getSharedDataFileUseCase.Object));

var response = await factory.CreateClient().GetAsync($"/share/data/{shareCode}/pdf");
var response = await factory.CreateClient().GetAsync($"/share/data/{shareCode}/file");

response.StatusCode.Should().Be(expectedStatusCode);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ public void GenerateBasicInformationPdf_ShouldGeneratePdfWithAllInformation()
OrganisationId = Guid.NewGuid(),
BasicInformation = DataSharingFactory.CreateMockBasicInformation(),
ConnectedPersonInformation = DataSharingFactory.CreateMockConnectedPersonInformation(),
FormAnswerSetForPdfs = DataSharingFactory.CreateMockFormAnswerSetForPdfs()
FormAnswerSetForPdfs = DataSharingFactory.CreateMockFormAnswerSetForPdfs(),
AttachedDocuments = []
};

var pdfBytes = _pdfGenerator.GenerateBasicInformationPdf(supplierInformation);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,51 +1,23 @@
using CO.CDP.Authentication;
using CO.CDP.DataSharing.WebApi;
using CO.CDP.AwsServices;
using CO.CDP.DataSharing.WebApi.DataService;
using CO.CDP.DataSharing.WebApi.Model;
using CO.CDP.DataSharing.WebApi.Tests;
using CO.CDP.DataSharing.WebApi.UseCase;
using FluentAssertions;
using Moq;
using static CO.CDP.Authentication.Constants;

namespace CO.CDP.DataSharing.WebApi.Tests.UseCase;

public class GetSharedDataPdfUseCaseTests
public class GetSharedDataFileUseCaseTests
{
private readonly Mock<IDataService> _dataService = new();
private readonly Mock<IPdfGenerator> _pdfGenerator = new();
private readonly Mock<IClaimService> _claimService = new();
private readonly Mock<IFileHostManager> _fileHostManager = new();
private string[] requiredClaims = [OrganisationPersonScope.Admin, OrganisationPersonScope.Editor, OrganisationPersonScope.Viewer];

private GetSharedDataPdfUseCase UseCase => new(_pdfGenerator.Object, _dataService.Object, _claimService.Object);

[Fact]
public async Task Execute_ShouldReturnPdfBytes_WhenShareCodeExists()
{
var organisationId = Guid.NewGuid();
var sharecode = "valid-sharecode";
var sharedSupplierInformation = new SharedSupplierInformation
{
OrganisationId = organisationId,
BasicInformation = DataSharingFactory.CreateMockBasicInformation(),
ConnectedPersonInformation = DataSharingFactory.CreateMockConnectedPersonInformation(),
FormAnswerSetForPdfs = DataSharingFactory.CreateMockFormAnswerSetForPdfs()
};

var pdfBytes = new byte[] { 1, 2, 3 };

_dataService.Setup(service => service.GetSharedSupplierInformationAsync(sharecode))
.ReturnsAsync(sharedSupplierInformation);

_pdfGenerator.Setup(generator => generator.GenerateBasicInformationPdf(sharedSupplierInformation))
.Returns(pdfBytes);
_claimService.Setup(cs => cs.HaveAccessToOrganisation(organisationId, requiredClaims, It.IsAny<string[]?>()))
.ReturnsAsync(true);

var result = await UseCase.Execute(sharecode);

result.Should().BeEquivalentTo(pdfBytes);
}
private GetSharedDataFileUseCase UseCase => new(_pdfGenerator.Object, _dataService.Object, _claimService.Object, _fileHostManager.Object);

[Fact]
public async Task Execute_ShouldCallDataServiceAndPdfGenerator_WhenShareCodeExists()
Expand All @@ -58,7 +30,8 @@ public async Task Execute_ShouldCallDataServiceAndPdfGenerator_WhenShareCodeExis
OrganisationId = organisationId,
BasicInformation = DataSharingFactory.CreateMockBasicInformation(),
ConnectedPersonInformation = DataSharingFactory.CreateMockConnectedPersonInformation(),
FormAnswerSetForPdfs = DataSharingFactory.CreateMockFormAnswerSetForPdfs()
FormAnswerSetForPdfs = DataSharingFactory.CreateMockFormAnswerSetForPdfs(),
AttachedDocuments = []
};

var pdfBytes = new byte[] { 1, 2, 3 };
Expand All @@ -67,13 +40,16 @@ public async Task Execute_ShouldCallDataServiceAndPdfGenerator_WhenShareCodeExis
.ReturnsAsync(sharedSupplierInformation);

_pdfGenerator.Setup(generator => generator.GenerateBasicInformationPdf(sharedSupplierInformation))
.Returns(pdfBytes);
.Returns(new MemoryStream(pdfBytes));
_claimService.Setup(cs => cs.HaveAccessToOrganisation(organisationId, requiredClaims, It.IsAny<string[]?>()))
.ReturnsAsync(true);

var result = await UseCase.Execute(sharecode);

result.Should().BeEquivalentTo(pdfBytes);
result.Should().NotBeNull();
result.As<SharedDataFile>().FileName.Should().BeEquivalentTo("valid-sharecode.pdf");
result.As<SharedDataFile>().Content.Should().BeEquivalentTo(pdfBytes);
result.As<SharedDataFile>().ContentType.Should().BeEquivalentTo("application/pdf");
}

[Fact]
Expand All @@ -89,7 +65,8 @@ public async Task Execute_WhenDoesNotHaveAccessToOrganisation_ThrowsUserUnauthor
OrganisationId = organisationId,
BasicInformation = DataSharingFactory.CreateMockBasicInformation(),
ConnectedPersonInformation = DataSharingFactory.CreateMockConnectedPersonInformation(),
FormAnswerSetForPdfs = DataSharingFactory.CreateMockFormAnswerSetForPdfs()
FormAnswerSetForPdfs = DataSharingFactory.CreateMockFormAnswerSetForPdfs(),
AttachedDocuments = []
});

_claimService.Setup(cs => cs.HaveAccessToOrganisation(organisationId, invalidscope, null))
Expand Down
Loading

0 comments on commit ade4bc6

Please sign in to comment.