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

DP-516 BE- Share my information - Data sharing endpoint (API) - Form answers #503

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,9 @@ public async Task ItTalksToTheDataSharingApi()

Func<Task> act = async () => { await client.GetSharedDataAsync("HDJ2123F"); };

var exception = await act.Should().NotThrowAsync<ApiException<ProblemDetails>>();
var exception = await act.Should().ThrowAsync<ApiException<ProblemDetails>>();

exception.Should().NotBe(404);
exception.And.StatusCode.Should().Be(404);
exception.And.Result!.Title.Should().Contain("SharedConsentNotFoundException");
}
}
4 changes: 2 additions & 2 deletions Services/CO.CDP.DataSharing.WebApi.Tests/EntityFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ internal static ShareRequest GetShareRequest(Guid organisationGuid, Guid formId)

internal static OrganisationInformation.Persistence.Forms.SharedConsent GetSharedConsent(int organisationId, Guid organisationGuid, Guid formId)
{
var form = new Form
var form = new CO.CDP.OrganisationInformation.Persistence.Forms.Form
{
Guid = formId,
Name = string.Empty,
Expand Down Expand Up @@ -48,7 +48,7 @@ internal static OrganisationInformation.Persistence.Forms.SharedConsent GetShare
SubmissionState = SubmissionState.Draft,
SubmittedAt = DateTime.UtcNow,
FormVersionId = string.Empty,
BookingReference = string.Empty
ShareCode = string.Empty
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ public class GenerateShareCodeUseCaseTest(AutoMapperFixture mapperFixture) : ICl
private readonly Mock<IClaimService> _claimService = new();
private readonly Mock<IOrganisationRepository> _organisationRepository = new();
private readonly Mock<IFormRepository> _formRepository = new();
private GenerateShareCodeUseCase UseCase => new(_claimService.Object, _organisationRepository.Object, _formRepository.Object, mapperFixture.Mapper);
private readonly Mock<IShareCodeRepository> _shareCodeRepository = new();
private GenerateShareCodeUseCase UseCase => new(_claimService.Object, _organisationRepository.Object, _formRepository.Object, _shareCodeRepository.Object, mapperFixture.Mapper);

[Fact]
public async Task ThrowsInvalidOrganisationRequestedException_WhenShareCodeRequestedForNonExistentOrganisation()
Expand Down Expand Up @@ -61,7 +62,7 @@ public async Task ThrowsSharedConsentNotFoundException_WhenNoSharedConsentOrNone

_claimService.Setup(x => x.HaveAccessToOrganisation(organisationGuid)).Returns(true);
_organisationRepository.Setup(x => x.Find(organisationGuid)).ReturnsAsync(sharedConsent.Organisation);
_formRepository.Setup(r => r.GetSharedConsentDraftAsync(shareRequest.FormId, shareRequest.OrganisationId)).ReturnsAsync((OrganisationInformation.Persistence.Forms.SharedConsent?)null);
_shareCodeRepository.Setup(r => r.GetSharedConsentDraftAsync(shareRequest.FormId, shareRequest.OrganisationId)).ReturnsAsync((OrganisationInformation.Persistence.Forms.SharedConsent?)null);

var shareReceipt = async () => await UseCase.Execute(shareRequest);

Expand All @@ -81,7 +82,7 @@ public async Task ReturnsRelevantShareReceipt_WhenAuthorisedAndShareRequestForVa

_claimService.Setup(x => x.HaveAccessToOrganisation(organisationGuid)).Returns(true);
_organisationRepository.Setup(x => x.Find(organisationGuid)).ReturnsAsync(sharedConsent.Organisation);
_formRepository.Setup(r => r.GetSharedConsentDraftAsync(shareRequest.FormId, shareRequest.OrganisationId)).ReturnsAsync(sharedConsent);
_shareCodeRepository.Setup(r => r.GetSharedConsentDraftAsync(shareRequest.FormId, shareRequest.OrganisationId)).ReturnsAsync(sharedConsent);

var found = await UseCase.Execute(shareRequest);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
using CO.CDP.DataSharing.WebApi.Model;
using CO.CDP.DataSharing.WebApi.UseCase;
using CO.CDP.DataSharing.WebApi.Tests.AutoMapper;
using CO.CDP.OrganisationInformation.Persistence;
using FluentAssertions;
using Moq;
using CO.CDP.OrganisationInformation.Persistence.Forms;
using CO.CDP.DataSharing.WebApi.Extensions;


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ namespace CO.CDP.DataSharing.WebApi.Tests.UseCase;

public class GetShareCodesUseCaseTest(AutoMapperFixture mapperFixture) : IClassFixture<AutoMapperFixture>
{
private readonly Mock<IFormRepository> _formRepository = new();
private GetShareCodesUseCase UseCase => new(_formRepository.Object, mapperFixture.Mapper);
private readonly Mock<IShareCodeRepository> _shareCodeRepository = new();
private GetShareCodesUseCase UseCase => new(_shareCodeRepository.Object, mapperFixture.Mapper);

[Fact]
public async Task ItReturnsEmptyIfNoSharedCodeIsFound()
Expand All @@ -32,18 +32,18 @@ public async Task ItReturnsTheSharedCodeList()
var sharedConsent = EntityFactory.GetSharedConsent(organisationId: organisationId, organisationGuid: organisationGuid, formId: formId);

var shareCode = ShareCodeExtensions.GenerateShareCode();
sharedConsent.BookingReference = shareCode;
sharedConsent.ShareCode = shareCode;
sharedConsent.SubmissionState = SubmissionState.Submitted;
sharedConsent.SubmittedAt = DateTime.UtcNow;

_formRepository.Setup(r => r.GetShareCodesAsync(shareRequest.OrganisationId)).ReturnsAsync(new List<OrganisationInformation.Persistence.Forms.SharedConsent> { sharedConsent });
_shareCodeRepository.Setup(r => r.GetShareCodesAsync(shareRequest.OrganisationId)).ReturnsAsync(new List<OrganisationInformation.Persistence.Forms.SharedConsent> { sharedConsent });

var result = await UseCase.Execute(sharedConsent.Organisation.Guid);

result?.Should().NotBeEmpty();
result?.Should().HaveCount(1);

result?.First().As<CO.CDP.DataSharing.WebApi.Model.SharedConsent>().SubmittedAt.Should().Be(sharedConsent.SubmittedAt);
result?.First().As<CO.CDP.DataSharing.WebApi.Model.SharedConsent>().ShareCode.Should().Be(sharedConsent.BookingReference);
result?.First().As<Model.SharedConsent>().SubmittedAt.Should().Be(sharedConsent.SubmittedAt);
result?.First().As<Model.SharedConsent>().ShareCode.Should().Be(sharedConsent.ShareCode);
}
}
164 changes: 8 additions & 156 deletions Services/CO.CDP.DataSharing.WebApi/Api/DataSharing.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,156 +17,9 @@ public static class EndpointExtensions
{
public static void UseDataSharingEndpoints(this WebApplication app)
{
app.MapGet("/share/data/{sharecode}", (string sharecode) => new SupplierInformation
{
Id = Guid.Parse("1e39d0ce-3abd-43c5-9f23-78c92e437f2a"),
Name = "Acme Corporation",
AssociatedPersons =
[
new AssociatedPerson
{
Id = Guid.Parse("c16f9f7b-3f10-42db-86f8-93607b034a4c"),
Name = "Alice Doe",
Relationship = "Company Director",
Uri = new Uri(
"https://cdp.cabinetoffice.gov.uk/persons/c16f9f7b-3f10-42db-86f8-93607b034a4c"),
Roles = [PartyRole.Tenderer]
}
],
AdditionalParties =
[
new OrganisationReference
{
Id = Guid.Parse("f4596cdd-12e5-4f25-9db1-4312474e516f"),
Name = "Acme Group Ltd",
Roles = [PartyRole.Tenderer],
Uri = new Uri(
"https://cdp.cabinetoffice.gov.uk/organisations/f4596cdd-12e5-4f25-9db1-4312474e516f")
}
],
AdditionalEntities =
[
new OrganisationReference
{
Id = Guid.Parse("f4596cdd-12e5-4f25-9db1-4312474e516f"),
Name = "Acme Group Ltd",
Roles = [PartyRole.Tenderer],
Uri = new Uri(
"https://cdp.cabinetoffice.gov.uk/organisations/f4596cdd-12e5-4f25-9db1-4312474e516f")
}
],
Identifier = new Identifier
{
Scheme = "CDP-PPON",
Id = "1e39d0ce-3abd-43c5-9f23-78c92e437f2a",
LegalName = "Acme Corporation Ltd",
Uri = new Uri(
"https://cdp.cabinetoffice.gov.uk/organisations/1e39d0ce-3abd-43c5-9f23-78c92e437f2a")
},
AdditionalIdentifiers =
[
new Identifier
{
Id = "06368740",
Scheme = "GB-COH",
LegalName = "Acme Corporation Ltd",
Uri = new Uri("http://data.companieshouse.gov.uk/doc/company/06368740")
}
],
Address = new Address
{
StreetAddress = "82 St. John’s Road",
Locality = "CHESTER",
Region = "Lancashire",
PostalCode = "CH43 7UR",
CountryName = "United Kingdom",
Type = AddressType.Registered,
},
ContactPoint = new ContactPoint
{
Name = "Procurement Team",
Email = "info@example.com",
Telephone = "+441234567890"
},
Roles = [PartyRole.Tenderer],
Details = new Details(),
SupplierInformationData = new SupplierInformationData
{
Form = new Form
{
Name = "Standard Questions",
SubmissionState = FormSubmissionState.Submitted,
SubmittedAt = DateTime.Parse("2024-03-28T18:24:00.000Z"),
OrganisationId = Guid.Parse("1e39d0ce-3abd-43c5-9f23-78c92e437f2a"),
FormId = Guid.Parse("f174b921-0c58-4644-80f1-8707d8300130"),
FormVersionId = "20240309",
IsRequired = true,
BookingReference = "AGMT-2024-XYZ",
Scope = 0,
Type = 0
},
Questions =
[
new FormQuestion
{
Name = "_Steel01",
Type = FormQuestionType.Text,
Text =
"<span style='font-weight: bold;'>Central Government Only - UK</span><span style='font-size:16.000000000000004px'><br /></span><p><span style='font-size:13.333299999999998px'>For contracts which relate to projects/programmes (i) with a value of \u00a310 million or more; or (ii) a value of less than \u00a310 million where it is anticipated that the project will require in excess of 500 tonnes of steel; please describe the steel specific supply chain management systems, policies, standards and procedures you have in place to ensure robust supply chain management and compliance with relevant legislation.</span><span style='font-size:16.000000000000004px'></span></p><span style='font-size:13.333299999999998px'>Please provide details of previous similar projects where you have demonstrated a high level of competency and effectiveness in managing all supply chain members involved in steel supply or production to ensure a sustainable and resilient supply of steel.</span>",
IsRequired = false,
SectionName = "Steel"
},
new FormQuestion
{
Name = "_Steel02",
Type = FormQuestionType.Text,
Text =
"<p>Please provide all the relevant details of previous breaches of health and safety legislation in the last 5 years, applicable to the country in which you operate, on comparable projects, for both:&nbsp;<span style='font-size:13.333299999999998px'>Your organisation</span></p><span style='font-size:13.333299999999998px'>All your supply chain members involved in the production or supply of steel</span>",
IsRequired = true,
SectionName = "Steel"
},
new FormQuestion
{
Name = "_ModernSlavery01",
Type = FormQuestionType.Text,
Text =
"Central Government Only - Tackling Modern Slavery in Supply Chains<span style='font-size:16.000000000000004px'><br /></span><span style='font-size:13.333299999999998px'>If you are a relevant commercial organisation subject to Section 54 of the Modern Slavery Act 2015, and if your latest statement is available electronically please provide:</span><span style='font-size:16.000000000000004px'><br /></span><span style='font-size:13.333299999999998px'i. the web address,</span><span style='font-size:16.000000000000004px'><br /></span><span style='font-size:13.333299999999998px>ii. precise reference of the documents.</span><span style='font-size:16.000000000000004px'><br /></span><span style='font-size:13.333299999999998p'>iii. If your latest statement is not available electronically, please provide a copy.</span>",
IsRequired = true,
SectionName = "Modern slavery"
},
new FormQuestion
{
Name = "_CarbonNetZero01",
Type = FormQuestionType.Boolean,
Text =
"Please confirm that you have detailed your environmental management measures by completing and publishing a Carbon Reduction Plan which meets the required reporting standard.",
IsRequired = true,
SectionName = "Carbon Net Zero"
}
],
Answers =
[
new FormAnswer
{
QuestionName = "_Steel02",
TextValue = "Answer to question 1.",
},

new FormAnswer
{
QuestionName = "_CarbonNetZero01",
BoolValue = true
},

// Use GeneratePresignedUrl method from IFileHostManager to Get PresignedUrl for a file
//new FormAnswer
//{
// QuestionName = "_FinancialAccountFile",
// TextValue = CO.CDP.AwsServices.IFileHostManager.GeneratePresignedUrl(fileName, urlExpiryInMinutes)
//}
]
},
})
app.MapGet("/share/data/{sharecode}", async (string sharecode,
IUseCase<string, SupplierInformation?> useCase) => await useCase.Execute(sharecode)
.AndThen(supplierInformation => supplierInformation != null ? Results.Ok(supplierInformation) : Results.NotFound()))
.Produces<SupplierInformation>(StatusCodes.Status200OK, "application/json")
.Produces<ProblemDetails>(StatusCodes.Status401Unauthorized)
.Produces<ProblemDetails>(StatusCodes.Status404NotFound)
Expand All @@ -175,15 +28,14 @@ public static void UseDataSharingEndpoints(this WebApplication app)
{
operation.OperationId = "GetSharedData";
operation.Description =
"[STUB] Operation to obtain Supplier information which has been shared as part of a notice. [STUB]";
operation.Summary = "[STUB] Request Supplier Submitted Information. [STUB]";
"Operation to obtain Supplier information which has been shared as part of a notice. ";
operation.Summary = "Request Supplier Submitted Information. ";
operation.Responses["200"].Description = "Organisation Information including Form Answers.";
operation.Responses["401"].Description = "Valid authentication credentials are missing in the request.";
operation.Responses["404"].Description = "Share code not found or the caller is not authorised to use it.";
operation.Responses["500"].Description = "Internal server error.";
return operation;
})
.RequireAuthorization(Constants.OrganisationApiKeyPolicy);
});

app.MapPost("/share/data", async (ShareRequest shareRequest, IUseCase<ShareRequest, ShareReceipt> useCase) =>
await useCase.Execute(shareRequest)
Expand Down Expand Up @@ -221,8 +73,8 @@ await useCase.Execute(shareRequest)
{
operation.OperationId = "VerifySharedData";
operation.Description =
"[STUB] Operation to verify if shared data is the latest version available. [STUB]";
operation.Summary = "[STUB] Create Supplier Submitted Information. [STUB]";
"Operation to verify if shared data is the latest version available. ";
operation.Summary = "Create Supplier Submitted Information. ";
operation.Responses["200"].Description = "Share code and version verification.";
operation.Responses["401"].Description = "Valid authentication credentials are missing in the request.";
operation.Responses["404"].Description = "Share code not found or the caller is not authorised to use it.";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using AutoMapper;
using CO.CDP.DataSharing.WebApi.Model;
using CO.CDP.OrganisationInformation.Persistence.Forms;
using Persistence = CO.CDP.OrganisationInformation.Persistence.Forms;

namespace CO.CDP.DataSharing.WebApi.AutoMapper;

public class DataSharingProfile : Profile
Expand All @@ -10,12 +10,10 @@ public DataSharingProfile()
{
CreateMap<Persistence.SharedConsent, ShareReceipt>()
.ForMember(m => m.FormId, o => o.MapFrom(m => m.Guid))
.ForMember(m => m.FormVersionId, o => o.MapFrom(m => m.FormVersionId))
.ForMember(m => m.ShareCode, o => o.MapFrom(m => m.BookingReference));
.ForMember(m => m.FormVersionId, o => o.MapFrom(m => m.FormVersionId));

CreateMap<Persistence.SharedConsent, Model.SharedConsent>()
.ForMember(m => m.SubmittedAt, o => o.MapFrom(m => m.SubmittedAt))
.ForMember(m => m.ShareCode, o => o.MapFrom(m => m.BookingReference));
.ForMember(m => m.SubmittedAt, o => o.MapFrom(m => m.SubmittedAt));

CreateMap<Persistence.SharedConsentQuestionAnswer, Model.SharedConsentQuestionAnswer>()
.ForMember(m => m.QuestionId, o => o.MapFrom(m => m.QuestionId))
Expand All @@ -24,7 +22,7 @@ public DataSharingProfile()

CreateMap<Persistence.SharedConsentDetails, Model.SharedConsentDetails>()
.ForMember(m => m.SubmittedAt, o => o.MapFrom(m => m.SubmittedAt))
.ForMember(m => m.ShareCode, o => o.MapFrom(m => m.ShareCode));
.ForMember(m => m.ShareCode, o => o.MapFrom(m => m.ShareCode));
}
}
public class CustomResolver : IValueResolver<Persistence.SharedConsentQuestionAnswer, Model.SharedConsentQuestionAnswer, string?>
Expand All @@ -47,7 +45,7 @@ public class CustomResolver : IValueResolver<Persistence.SharedConsentQuestionAn
}
}

private string ToHtmlString(FormAddress source)
private string ToHtmlString(Persistence.FormAddress source)
{
return $"{source.StreetAddress}<br/>{source.Locality}<br/>{source.PostalCode}<br/>{source.Region}<br/>{source.CountryName}";
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

namespace CO.CDP.DataSharing.WebApi.Model;

internal record AssociatedPerson
public record AssociatedPerson
{
/// <example>"c16f9f7b-3f10-42db-86f8-93607b034a4c"</example>
[Required] public required Guid Id { get; init; }
Expand Down
2 changes: 1 addition & 1 deletion Services/CO.CDP.DataSharing.WebApi/Model/Details.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
namespace CO.CDP.DataSharing.WebApi.Model;

internal record Details;
public record Details;
Loading