From e2c3c2755f3ad6af612d4cedf7ef79dfbd37351d Mon Sep 17 00:00:00 2001 From: Jezz Santos Date: Mon, 2 Dec 2024 19:32:26 +1300 Subject: [PATCH] Changed all response DTOs to define 'required' properties by default. Fixed JsonClient to not require new() constraint on responses Fixed OpenAPI output for 'nullable' properties in responses. --- docs/how-to-guides/020-api-endpoint.md | 4 +- .../AuditsApiSpec.cs | 6 +- .../EmailsApiSpec.cs | 12 +- .../FeatureFlagsApiSpec.cs | 2 +- .../MailgunApiSpec.cs | 16 +-- .../ProvisioningsApiSpec.cs | 4 +- .../SmsesApiSpec.cs | 12 +- .../TwilioApiSpec.cs | 4 +- src/ApiHost1/Api/TestingOnly/TestingWebApi.cs | 41 +++--- .../BookingsApiSpec.cs | 12 +- .../CarsApiSpec.cs | 18 +-- .../CarsHttpServiceClient.cs | 4 +- .../EndUsersApiSpec.cs | 8 +- .../InvitationsApiSpec.cs | 26 ++-- .../MembershipsApiSpec.cs | 20 +-- .../AuthTokensApiSpec.cs | 4 +- .../IdentityApiSpec.cs | 6 +- .../MachineCredentialsApiSpec.cs | 6 +- .../MfaApiSpec.cs | 64 ++++----- .../PasswordCredentialsApiSpec.cs | 8 +- .../SingleSignOnApiSpec.cs | 6 +- .../ImagesApiSpec.cs | 6 +- .../External/MailgunClientSpec.cs | 3 +- .../FlagsmithHttpServiceClient.TestingOnly.cs | 4 +- .../GenericOAuth2HttpServiceClient.cs | 4 +- .../MailgunHttpServiceClient.MailgunClient.cs | 9 +- .../ApiDocsSpec.cs | 111 +++++++++------ .../AuthNApiSpec.cs | 2 +- .../MultiTenancySpec.cs | 10 +- .../IWebSearchResponse.cs | 2 +- .../Resources.Designer.cs | 2 +- .../Resources.resx | 2 +- .../SearchResponse.cs | 2 +- .../FlagsmithCreateEdgeIdentityResponse.cs | 4 +- .../FlagsmithCreateFeatureResponse.cs | 4 +- .../FlagsmithCreateIdentityRequest.cs | 2 +- .../FlagsmithCreateIdentityResponse.cs | 8 +- .../FlagsmithGetEdgeIdentitiesResponse.cs | 6 +- .../FlagsmithGetEnvironmentFlagsResponse.cs | 10 +- .../FlagsmithGetFeatureStatesResponse.cs | 2 +- .../Flagsmith/FlagsmithGetFeaturesResponse.cs | 2 +- .../Mailgun/MailgunSendMessageResponse.cs | 4 +- ...GenericOAuth2GrantAuthorizationResponse.cs | 2 +- .../3rdParties/Twilio/TwilioSendResponse.cs | 2 +- .../Ancillary/GetAllFeatureFlagsResponse.cs | 2 +- .../Ancillary/GetFeatureFlagResponse.cs | 2 +- .../Ancillary/SearchAllAuditsResponse.cs | 2 +- .../SearchEmailDeliveriesResponse.cs | 2 +- .../Ancillary/SearchSmsDeliveriesResponse.cs | 2 +- .../AuthenticateResponse.cs | 2 +- .../GetAllFeatureFlagsResponse.cs | 2 +- .../GetFeatureFlagResponse.cs | 2 +- .../Bookings/MakeBookingResponse.cs | 2 +- .../Bookings/SearchAllBookingsResponse.cs | 2 +- .../Cars/GetCarResponse.cs | 2 +- .../SearchAllCarUnavailabilitiesResponse.cs | 2 +- .../Cars/SearchAllCarsResponse.cs | 2 +- .../EndUsers/GetUserResponse.cs | 2 +- .../EndUsers/InviteGuestResponse.cs | 2 +- .../ListMembershipsForCallerResponse.cs | 2 +- .../EndUsers/UpdateUserResponse.cs | 2 +- .../EndUsers/VerifyGuestInvitationResponse.cs | 2 +- .../SearchAllDomainEventsResponse.cs | 2 +- .../Health/HealthCheckResponse.cs | 4 +- ...asswordMfaAuthenticatorForCallerRequest.cs | 2 +- ...sswordMfaAuthenticatorForCallerResponse.cs | 2 +- .../Identities/AuthenticateResponse.cs | 2 +- ...sswordMfaAuthenticatorForCallerResponse.cs | 2 +- .../Identities/ChangePasswordMfaResponse.cs | 2 +- .../Identities/CreateAPIKeyResponse.cs | 2 +- .../Identities/GetIdentityResponse.cs | 2 +- ...tRegistrationPersonConfirmationResponse.cs | 2 +- ...swordMfaAuthenticatorsForCallerResponse.cs | 2 +- .../Identities/RefreshTokenResponse.cs | 2 +- .../Identities/RegisterMachineResponse.cs | 2 +- .../RegisterPersonPasswordResponse.cs | 2 +- .../Identities/SearchAllAPIKeysResponse.cs | 2 +- .../Images/GetImageResponse.cs | 2 +- .../Images/UpdateImageResponse.cs | 2 +- .../Images/UploadImageResponse.cs | 2 +- .../Organizations/GetOrganizationResponse.cs | 2 +- .../GetOrganizationSettingsResponse.cs | 4 +- .../InviteMemberToOrganizationResponse.cs | 2 +- .../ListMembersForOrganizationResponse.cs | 2 +- .../UnInviteMemberFromOrganizationResponse.cs | 2 +- .../ExportSubscriptionsToMigrateResponse.cs | 2 +- .../Subscriptions/GetSubscriptionResponse.cs | 2 +- .../Subscriptions/ListPricingPlansResponse.cs | 2 +- .../MigrateSubscriptionResponse.cs | 2 +- .../SearchSubscriptionHistoryResponse.cs | 2 +- .../TestingOnly/FormatsTestingOnlyRequest.cs | 1 + .../GetCallerTestingOnlyResponse.cs | 2 +- .../OpenApiGetTestingOnlyRequest.cs | 6 +- ...ApiPostFormUrlEncodedTestingOnlyRequest.cs | 2 +- ...PostMultiPartFormDataTestingOnlyRequest.cs | 2 +- .../OpenApiPostTestingOnlyRequest.cs | 7 +- .../OpenApiPutTestingOnlyRequest.cs | 2 +- .../TestingOnly/OpenApiTestingOnlyResponse.cs | 23 ++++ .../StatusesTestingOnlyResponse.cs | 6 +- .../StringMessageTestingOnlyResponse.cs | 2 +- .../TestingOnly/Stubs/HelloResponse.cs | 2 +- .../ChangeProfileAvatarResponse.cs | 2 +- .../DeleteProfileAvatarResponse.cs | 2 +- .../GetProfileForCallerResponse.cs | 2 +- .../UserProfiles/GetProfileResponse.cs | 2 +- .../Clients/ApiServiceClient.cs | 19 +-- .../Clients/JsonClient.cs | 73 +++++++--- .../Resources.Designer.cs | 18 +++ src/Infrastructure.Web.Common/Resources.resx | 6 + .../DefaultResponsesFilterSpec.cs | 2 +- .../Documentation/AllSchemaFilter.cs | 4 + .../DataAnnotationsSchemaFilterExtensions.cs | 57 +++++++- .../XmlDocumentationOperationFilter.cs | 2 +- .../Extensions/HostExtensions.cs | 1 + .../Clients/IHttpJsonClient.cs | 14 +- .../Clients/IServiceClient.cs | 8 +- .../FeatureFlagsApiSpec.cs | 2 +- .../ReverseProxyApiSpec.cs | 4 +- .../WebsiteTestingExtensions.cs | 11 +- .../Stubs/StubServiceClient.cs | 11 +- .../WebApiSpec.cs | 6 +- .../OrganizationsApiSpec.cs | 128 +++++++++--------- src/SaaStack.sln.DotSettings | 1 + .../MigrationsApiSpec.cs | 2 +- .../PricingApiSpec.cs | 2 +- .../SubscriptionsApiSpec.cs | 18 +-- .../Api/StubFlagsmithApi.cs | 4 +- src/TestingStubApiHost/Api/StubTwilioApi.cs | 3 +- .../ApiLayerAnalyzerSpec.cs | 23 +++- .../UserProfileApiSpec.cs | 16 +-- .../Application/AuthenticationApplication.cs | 4 +- .../Application/FeatureFlagsApplication.cs | 2 +- 132 files changed, 651 insertions(+), 435 deletions(-) create mode 100644 src/Infrastructure.Web.Api.Operations.Shared/TestingOnly/OpenApiTestingOnlyResponse.cs diff --git a/docs/how-to-guides/020-api-endpoint.md b/docs/how-to-guides/020-api-endpoint.md index 5a23219c..dca18b76 100644 --- a/docs/how-to-guides/020-api-endpoint.md +++ b/docs/how-to-guides/020-api-endpoint.md @@ -477,7 +477,7 @@ An example response type would be: ```c# public class GetCarResponse : IWebResponse { - public Car? Car { get; set; } + public required Car Car { get; set; } } ``` @@ -486,7 +486,7 @@ However, there is one specific response type that you want to use for your SEARC ```c# public class SearchAllCarsResponse : SearchResponse { - public List? Cars { get; set; } + public List Cars { get; set; } = []; } ``` diff --git a/src/AncillaryInfrastructure.IntegrationTests/AuditsApiSpec.cs b/src/AncillaryInfrastructure.IntegrationTests/AuditsApiSpec.cs index 9e454831..978bce1e 100644 --- a/src/AncillaryInfrastructure.IntegrationTests/AuditsApiSpec.cs +++ b/src/AncillaryInfrastructure.IntegrationTests/AuditsApiSpec.cs @@ -58,7 +58,7 @@ public async Task WhenDeliverAudit_ThenDelivers() OrganizationId = tenantId }); - audits.Content.Value.Audits!.Count.Should().Be(1); + audits.Content.Value.Audits.Count.Should().Be(1); audits.Content.Value.Audits[0].OrganizationId.Should().Be(tenantId); audits.Content.Value.Audits[0].MessageTemplate.Should().Be("amessagetemplate"); audits.Content.Value.Audits[0].TemplateArguments.Count.Should().Be(2); @@ -82,7 +82,7 @@ public async Task WhenDrainAllAuditsAndNone_ThenDoesNotDrainAny() OrganizationId = tenantId }); - audits.Content.Value.Audits!.Count.Should().Be(0); + audits.Content.Value.Audits.Count.Should().Be(0); } #endif @@ -126,7 +126,7 @@ public async Task WhenDrainAllAuditsAndSomeWithUnknownTenancies_ThenDrains() OrganizationId = tenantId }); - audits.Content.Value.Audits!.Count.Should().Be(2); + audits.Content.Value.Audits.Count.Should().Be(2); audits.Content.Value.Audits[0].OrganizationId.Should().Be(tenantId); audits.Content.Value.Audits[0].AuditCode.Should().Be("anauditcode1"); audits.Content.Value.Audits[0].MessageTemplate.Should().Be("amessagetemplate1"); diff --git a/src/AncillaryInfrastructure.IntegrationTests/EmailsApiSpec.cs b/src/AncillaryInfrastructure.IntegrationTests/EmailsApiSpec.cs index 05329bcf..000acfd8 100644 --- a/src/AncillaryInfrastructure.IntegrationTests/EmailsApiSpec.cs +++ b/src/AncillaryInfrastructure.IntegrationTests/EmailsApiSpec.cs @@ -69,7 +69,7 @@ public async Task WhenSendEmailAndDeliverySucceeds_ThenDelivered() req => req.SetJWTBearerToken(login.AccessToken)); var now = DateTime.UtcNow; - deliveries.Content.Value.Emails!.Count.Should().Be(1); + deliveries.Content.Value.Emails.Count.Should().Be(1); deliveries.Content.Value.Emails[0].Subject.Should().Be("asubject"); deliveries.Content.Value.Emails[0].Body.Should().Be("anhtmlbody"); deliveries.Content.Value.Emails[0].ToEmailAddress.Should().Be("arecipient@company.com"); @@ -119,7 +119,7 @@ public async Task WhenSendEmailAndDeliveryFails_ThenNotDelivered() req => req.SetJWTBearerToken(login.AccessToken)); var now = DateTime.UtcNow; - deliveries.Content.Value.Emails!.Count.Should().Be(1); + deliveries.Content.Value.Emails.Count.Should().Be(1); deliveries.Content.Value.Emails[0].Subject.Should().Be("asubject"); deliveries.Content.Value.Emails[0].Body.Should().Be("anhtmlbody"); deliveries.Content.Value.Emails[0].ToEmailAddress.Should().Be("arecipient@company.com"); @@ -173,7 +173,7 @@ public async Task WhenSendEmailAndDeliveryFailsFirstTimeAndSucceedsSecondTime_Th req => req.SetJWTBearerToken(login.AccessToken)); var now = DateTime.UtcNow; - deliveries.Content.Value.Emails!.Count.Should().Be(1); + deliveries.Content.Value.Emails.Count.Should().Be(1); deliveries.Content.Value.Emails[0].Subject.Should().Be("asubject"); deliveries.Content.Value.Emails[0].Body.Should().Be("anhtmlbody"); deliveries.Content.Value.Emails[0].ToEmailAddress.Should().Be("arecipient@company.com"); @@ -230,7 +230,7 @@ await Api.PostAsync(new ConfirmEmailDeliveredRequest req => req.SetJWTBearerToken(login.AccessToken)); var now = DateTime.UtcNow; - deliveries.Content.Value.Emails!.Count.Should().Be(1); + deliveries.Content.Value.Emails.Count.Should().Be(1); deliveries.Content.Value.Emails[0].Subject.Should().Be("asubject"); deliveries.Content.Value.Emails[0].Body.Should().Be("anhtmlbody"); deliveries.Content.Value.Emails[0].ToEmailAddress.Should().Be("arecipient@company.com"); @@ -289,7 +289,7 @@ await Api.PostAsync(new ConfirmEmailDeliveryFailedRequest req => req.SetJWTBearerToken(login.AccessToken)); var now = DateTime.UtcNow; - deliveries.Content.Value.Emails!.Count.Should().Be(1); + deliveries.Content.Value.Emails.Count.Should().Be(1); deliveries.Content.Value.Emails[0].Subject.Should().Be("asubject"); deliveries.Content.Value.Emails[0].Body.Should().Be("anhtmlbody"); deliveries.Content.Value.Emails[0].ToEmailAddress.Should().Be("arecipient@company.com"); @@ -342,7 +342,7 @@ public async Task WhenSearchEmailDeliveriesWithTags_TheReturnsEmails() }, req => req.SetJWTBearerToken(login.AccessToken)); - deliveries.Content.Value.Emails!.Count.Should().Be(1); + deliveries.Content.Value.Emails.Count.Should().Be(1); deliveries.Content.Value.Emails[0].Subject.Should().Be("asubject"); deliveries.Content.Value.Emails[0].Tags.Count.Should().Be(3); deliveries.Content.Value.Emails[0].Tags[0].Should().Be("atag1"); diff --git a/src/AncillaryInfrastructure.IntegrationTests/FeatureFlagsApiSpec.cs b/src/AncillaryInfrastructure.IntegrationTests/FeatureFlagsApiSpec.cs index 0ccf22b0..4548e6dc 100644 --- a/src/AncillaryInfrastructure.IntegrationTests/FeatureFlagsApiSpec.cs +++ b/src/AncillaryInfrastructure.IntegrationTests/FeatureFlagsApiSpec.cs @@ -50,7 +50,7 @@ public async Task WhenGetFeatureFlag_ThenReturnsFlag() var result = await Api.GetAsync(request, req => req.SetHMACAuth(request, "asecret")); result.StatusCode.Should().Be(HttpStatusCode.OK); - result.Content.Value.Flag!.Name.Should().Be(Flag.TestingOnly.Name); + result.Content.Value.Flag.Name.Should().Be(Flag.TestingOnly.Name); _featureFlags.LastGetFlag.Should().Be(Flag.TestingOnly.Name); #endif } diff --git a/src/AncillaryInfrastructure.IntegrationTests/MailgunApiSpec.cs b/src/AncillaryInfrastructure.IntegrationTests/MailgunApiSpec.cs index a740a21e..25b9fc83 100644 --- a/src/AncillaryInfrastructure.IntegrationTests/MailgunApiSpec.cs +++ b/src/AncillaryInfrastructure.IntegrationTests/MailgunApiSpec.cs @@ -83,7 +83,7 @@ public async Task WhenNotifyMailgunEventAndDeliveredEvent_ThenReturnsOk() var deliveries = await Api.GetAsync(new SearchEmailDeliveriesRequest(), req => req.SetJWTBearerToken(login.AccessToken)); - deliveries.Content.Value.Emails!.Count.Should().Be(1); + deliveries.Content.Value.Emails.Count.Should().Be(1); deliveries.Content.Value.Emails[0].IsSent.Should().BeTrue(); deliveries.Content.Value.Emails[0].IsDelivered.Should().BeTrue(); deliveries.Content.Value.Emails[0].DeliveredAt.Should().Be(deliveredAt.FromUnixTimestamp()); @@ -131,7 +131,7 @@ public async Task WhenNotifyMailgunEventAndTemporaryFailedEvent_ThenReturnsOk() var deliveries = await Api.GetAsync(new SearchEmailDeliveriesRequest(), req => req.SetJWTBearerToken(login.AccessToken)); - deliveries.Content.Value.Emails!.Count.Should().Be(1); + deliveries.Content.Value.Emails.Count.Should().Be(1); deliveries.Content.Value.Emails[0].IsSent.Should().BeTrue(); deliveries.Content.Value.Emails[0].IsDelivered.Should().BeFalse(); deliveries.Content.Value.Emails[0].DeliveredAt.Should().BeNull(); @@ -179,12 +179,12 @@ public async Task WhenNotifyMailgunEventAndPermanentFailedEvent_ThenReturnsOk() var deliveries = await Api.GetAsync(new SearchEmailDeliveriesRequest(), req => req.SetJWTBearerToken(login.AccessToken)); - deliveries.Content.Value.Emails![0].IsSent.Should().BeTrue(); - deliveries.Content.Value.Emails![0].IsDelivered.Should().BeFalse(); - deliveries.Content.Value.Emails![0].DeliveredAt.Should().BeNull(); - deliveries.Content.Value.Emails![0].IsDeliveryFailed.Should().BeTrue(); - deliveries.Content.Value.Emails![0].FailedDeliveryAt.Should().Be(failedAt.FromUnixTimestamp()); - deliveries.Content.Value.Emails![0].FailedDeliveryReason.Should().Be("areason"); + deliveries.Content.Value.Emails[0].IsSent.Should().BeTrue(); + deliveries.Content.Value.Emails[0].IsDelivered.Should().BeFalse(); + deliveries.Content.Value.Emails[0].DeliveredAt.Should().BeNull(); + deliveries.Content.Value.Emails[0].IsDeliveryFailed.Should().BeTrue(); + deliveries.Content.Value.Emails[0].FailedDeliveryAt.Should().Be(failedAt.FromUnixTimestamp()); + deliveries.Content.Value.Emails[0].FailedDeliveryReason.Should().Be("areason"); } private async Task DeliveryEmailAsync() diff --git a/src/AncillaryInfrastructure.IntegrationTests/ProvisioningsApiSpec.cs b/src/AncillaryInfrastructure.IntegrationTests/ProvisioningsApiSpec.cs index eddefa53..a841535d 100644 --- a/src/AncillaryInfrastructure.IntegrationTests/ProvisioningsApiSpec.cs +++ b/src/AncillaryInfrastructure.IntegrationTests/ProvisioningsApiSpec.cs @@ -62,7 +62,7 @@ public async Task WhenNotifyProvisioning_ThenNotifies() Id = tenantId }, req => req.SetJWTBearerToken(login.AccessToken)); - organization.Content.Value.Settings!.Count.Should().Be(3); + organization.Content.Value.Settings.Count.Should().Be(3); organization.Content.Value.Settings["aname1"].Should().Be("avalue"); organization.Content.Value.Settings["aname2"].Should().Be("99"); organization.Content.Value.Settings["aname3"].Should().Be("True"); @@ -107,7 +107,7 @@ public async Task WhenDrainAllProvisioningsAndSomeWithUnknownTenancies_ThenDrain Id = tenantId! }, req => req.SetJWTBearerToken(login.AccessToken)); - organization.Content.Value.Settings!.Count.Should().Be(3); + organization.Content.Value.Settings.Count.Should().Be(3); organization.Content.Value.Settings["aname1"].Should().Be("avalue1"); organization.Content.Value.Settings["aname2"].Should().Be("99"); organization.Content.Value.Settings["aname3"].Should().Be("True"); diff --git a/src/AncillaryInfrastructure.IntegrationTests/SmsesApiSpec.cs b/src/AncillaryInfrastructure.IntegrationTests/SmsesApiSpec.cs index f29e56db..4dbc7ec5 100644 --- a/src/AncillaryInfrastructure.IntegrationTests/SmsesApiSpec.cs +++ b/src/AncillaryInfrastructure.IntegrationTests/SmsesApiSpec.cs @@ -65,7 +65,7 @@ public async Task WhenSendSmsAndDeliverySucceeds_ThenDelivered() req => req.SetJWTBearerToken(login.AccessToken)); var now = DateTime.UtcNow; - deliveries.Content.Value.Smses!.Count.Should().Be(1); + deliveries.Content.Value.Smses.Count.Should().Be(1); deliveries.Content.Value.Smses[0].Body.Should().Be("anhtmlbody"); deliveries.Content.Value.Smses[0].ToPhoneNumber.Should().Be("+6498876986"); deliveries.Content.Value.Smses[0].Attempts.Should() @@ -109,7 +109,7 @@ public async Task WhenSendSmsAndDeliveryFails_ThenNotDelivered() req => req.SetJWTBearerToken(login.AccessToken)); var now = DateTime.UtcNow; - deliveries.Content.Value.Smses!.Count.Should().Be(1); + deliveries.Content.Value.Smses.Count.Should().Be(1); deliveries.Content.Value.Smses[0].Body.Should().Be("anhtmlbody"); deliveries.Content.Value.Smses[0].ToPhoneNumber.Should().Be("+6498876986"); deliveries.Content.Value.Smses[0].Attempts.Should() @@ -157,7 +157,7 @@ public async Task WhenSendSmsAndDeliveryFailsFirstTimeAndSucceedsSecondTime_Then req => req.SetJWTBearerToken(login.AccessToken)); var now = DateTime.UtcNow; - deliveries.Content.Value.Smses!.Count.Should().Be(1); + deliveries.Content.Value.Smses.Count.Should().Be(1); deliveries.Content.Value.Smses[0].Body.Should().Be("anhtmlbody"); deliveries.Content.Value.Smses[0].ToPhoneNumber.Should().Be("+6498876986"); deliveries.Content.Value.Smses[0].Attempts.Should().HaveCount(2); @@ -208,7 +208,7 @@ await Api.PostAsync(new ConfirmSmsDeliveredRequest req => req.SetJWTBearerToken(login.AccessToken)); var now = DateTime.UtcNow; - deliveries.Content.Value.Smses!.Count.Should().Be(1); + deliveries.Content.Value.Smses.Count.Should().Be(1); deliveries.Content.Value.Smses[0].Body.Should().Be("anhtmlbody"); deliveries.Content.Value.Smses[0].ToPhoneNumber.Should().Be("+6498876986"); deliveries.Content.Value.Smses[0].Attempts.Should() @@ -261,7 +261,7 @@ await Api.PostAsync(new ConfirmSmsDeliveryFailedRequest req => req.SetJWTBearerToken(login.AccessToken)); var now = DateTime.UtcNow; - deliveries.Content.Value.Smses!.Count.Should().Be(1); + deliveries.Content.Value.Smses.Count.Should().Be(1); deliveries.Content.Value.Smses[0].Body.Should().Be("anhtmlbody"); deliveries.Content.Value.Smses[0].ToPhoneNumber.Should().Be("+6498876986"); deliveries.Content.Value.Smses[0].Attempts.Should() @@ -308,7 +308,7 @@ public async Task WhenSearchSmsDeliveriesWithTags_TheReturnsSmses() }, req => req.SetJWTBearerToken(login.AccessToken)); - deliveries.Content.Value.Smses!.Count.Should().Be(1); + deliveries.Content.Value.Smses.Count.Should().Be(1); deliveries.Content.Value.Smses[0].Tags.Count.Should().Be(3); deliveries.Content.Value.Smses[0].Tags[0].Should().Be("atag1"); deliveries.Content.Value.Smses[0].Tags[1].Should().Be("atag2"); diff --git a/src/AncillaryInfrastructure.IntegrationTests/TwilioApiSpec.cs b/src/AncillaryInfrastructure.IntegrationTests/TwilioApiSpec.cs index 94d5ad23..c6b8acb7 100644 --- a/src/AncillaryInfrastructure.IntegrationTests/TwilioApiSpec.cs +++ b/src/AncillaryInfrastructure.IntegrationTests/TwilioApiSpec.cs @@ -64,7 +64,7 @@ public async Task WhenNotifyTwilioEventAndDeliveredEvent_ThenReturnsOk() var deliveries = await Api.GetAsync(new SearchSmsDeliveriesRequest(), req => req.SetJWTBearerToken(login.AccessToken)); - deliveries.Content.Value.Smses!.Count.Should().Be(1); + deliveries.Content.Value.Smses.Count.Should().Be(1); deliveries.Content.Value.Smses[0].IsSent.Should().BeTrue(); deliveries.Content.Value.Smses[0].IsDelivered.Should().BeTrue(); deliveries.Content.Value.Smses[0].DeliveredAt.Should().Be(deliveredAt); @@ -92,7 +92,7 @@ public async Task WhenNotifyTwilioEventAndFailedEvent_ThenReturnsOk() var deliveries = await Api.GetAsync(new SearchSmsDeliveriesRequest(), req => req.SetJWTBearerToken(login.AccessToken)); - deliveries.Content.Value.Smses!.Count.Should().Be(1); + deliveries.Content.Value.Smses.Count.Should().Be(1); deliveries.Content.Value.Smses[0].IsSent.Should().BeTrue(); deliveries.Content.Value.Smses[0].IsDelivered.Should().BeFalse(); deliveries.Content.Value.Smses[0].DeliveredAt.Should().BeNull(); diff --git a/src/ApiHost1/Api/TestingOnly/TestingWebApi.cs b/src/ApiHost1/Api/TestingOnly/TestingWebApi.cs index 08c2415e..a93d082e 100644 --- a/src/ApiHost1/Api/TestingOnly/TestingWebApi.cs +++ b/src/ApiHost1/Api/TestingOnly/TestingWebApi.cs @@ -1,4 +1,5 @@ #if TESTINGONLY +using Application.Interfaces; using Application.Persistence.Interfaces; using Common; using Common.Extensions; @@ -167,50 +168,50 @@ public async Task GetInsecure( return () => new Result(); } - public async Task> OpenApiGet( - OpenApiGetTestingOnlyRequest request, CancellationToken cancellationToken) + public async Task> OpenApiFormUrlEncoded( + OpenApiPostFormUrlEncodedTestingOnlyRequest request, CancellationToken cancellationToken) { await Task.CompletedTask; - return () => new Result(new StringMessageTestingOnlyResponse - { Message = $"amessage{request.RequiredField}" }); + return () => + new PostResult( + new OpenApiTestingOnlyResponse { ARequiredField = "", Message = $"amessage{request.RequiredField}" }, + "alocation"); } - public async Task> OpenApiMultiPartForm( - OpenApiPostMultiPartFormDataTestingOnlyRequest request, CancellationToken cancellationToken) + public async Task> OpenApiGet( + OpenApiGetTestingOnlyRequest request, CancellationToken cancellationToken) { await Task.CompletedTask; - return () => - new PostResult( - new StringMessageTestingOnlyResponse { Message = $"amessage{request.RequiredField}" }, - "alocation"); + return () => new Result(new OpenApiTestingOnlyResponse + { ARequiredField = "", Message = $"amessage{request.RequiredField}" }); } - public async Task> OpenApiFormUrlEncoded( - OpenApiPostFormUrlEncodedTestingOnlyRequest request, CancellationToken cancellationToken) + public async Task> OpenApiMultiPartForm( + OpenApiPostMultiPartFormDataTestingOnlyRequest request, CancellationToken cancellationToken) { await Task.CompletedTask; return () => - new PostResult( - new StringMessageTestingOnlyResponse { Message = $"amessage{request.RequiredField}" }, + new PostResult( + new OpenApiTestingOnlyResponse { ARequiredField = "", Message = $"amessage{request.RequiredField}" }, "alocation"); } - public async Task> OpenApiPost( + public async Task> OpenApiPost( OpenApiPostTestingOnlyRequest request, CancellationToken cancellationToken) { await Task.CompletedTask; return () => - new PostResult( - new StringMessageTestingOnlyResponse { Message = $"amessage{request.RequiredField}" }, + new PostResult( + new OpenApiTestingOnlyResponse { ARequiredField = "", Message = $"amessage{request.RequiredField}" }, "alocation"); } - public async Task> OpenApiPut( + public async Task> OpenApiPut( OpenApiPutTestingOnlyRequest request, CancellationToken cancellationToken) { await Task.CompletedTask; return () => - new StringMessageTestingOnlyResponse { Message = $"amessage{request.RequiredField}" }; + new OpenApiTestingOnlyResponse { ARequiredField = "", Message = $"amessage{request.RequiredField}" }; } public async Task PostInsecure( @@ -284,7 +285,7 @@ public async Task> St await Task.CompletedTask; return () => new Result(new StatusesTestingOnlySearchResponse - { Messages = new List { "amessage" } }); + { Messages = ["amessage"], Metadata = new SearchResultMetadata() }); } public async Task> ValidationsUnvalidated( diff --git a/src/BookingsInfrastructure.IntegrationTests/BookingsApiSpec.cs b/src/BookingsInfrastructure.IntegrationTests/BookingsApiSpec.cs index 606e417c..e5a48aa2 100644 --- a/src/BookingsInfrastructure.IntegrationTests/BookingsApiSpec.cs +++ b/src/BookingsInfrastructure.IntegrationTests/BookingsApiSpec.cs @@ -37,7 +37,7 @@ public async Task WhenMakeBooking_ThenReturnsBooking() EndUtc = end }, req => req.SetJWTBearerToken(login.AccessToken)); - var booking = result.Content.Value.Booking!; + var booking = result.Content.Value.Booking; var location = result.Headers.Location?.ToString(); location.Should().BeNull(); booking.Id.Should().NotBeEmpty(); @@ -60,12 +60,12 @@ public async Task WhenSearchAllBookings_ThenReturnsBookings() CarId = car.Id, StartUtc = start, EndUtc = end - }, req => req.SetJWTBearerToken(login.AccessToken))).Content.Value.Booking!; + }, req => req.SetJWTBearerToken(login.AccessToken))).Content.Value.Booking; var result = await Api.GetAsync(new SearchAllBookingsRequest(), req => req.SetJWTBearerToken(login.AccessToken)); - var bookings = result.Content.Value.Bookings!; + var bookings = result.Content.Value.Bookings; bookings.Count.Should().Be(1); bookings[0].Id.Should().Be(booking.Id); bookings[0].BorrowerId.Should().Be(login.User.Id); @@ -87,7 +87,7 @@ public async Task WhenCancelBooking_ThenRemovesUnavailability() CarId = car.Id, StartUtc = start, EndUtc = end - }, req => req.SetJWTBearerToken(login.AccessToken))).Content.Value.Booking!; + }, req => req.SetJWTBearerToken(login.AccessToken))).Content.Value.Booking; await Api.DeleteAsync(new CancelBookingRequest { @@ -98,7 +98,7 @@ await Api.DeleteAsync(new CancelBookingRequest var unavailabilities = (await Api.GetAsync(new SearchAllCarUnavailabilitiesRequest { Id = car.Id - }, req => req.SetJWTBearerToken(login.AccessToken))).Content.Value.Unavailabilities!; + }, req => req.SetJWTBearerToken(login.AccessToken))).Content.Value.Unavailabilities; unavailabilities.Count.Should().Be(0); #endif @@ -120,6 +120,6 @@ private async Task RegisterNewCarAsync(LoginDetails login) NumberPlate = "aplate" }, req => req.SetJWTBearerToken(login.AccessToken)); - return car.Content.Value.Car!; + return car.Content.Value.Car; } } \ No newline at end of file diff --git a/src/CarsInfrastructure.IntegrationTests/CarsApiSpec.cs b/src/CarsInfrastructure.IntegrationTests/CarsApiSpec.cs index 38125db0..b23f6bd1 100644 --- a/src/CarsInfrastructure.IntegrationTests/CarsApiSpec.cs +++ b/src/CarsInfrastructure.IntegrationTests/CarsApiSpec.cs @@ -41,7 +41,7 @@ public async Task WhenGetCar_ThenReturnsCar() var result = (await Api.GetAsync(new GetCarRequest { Id = car.Id }, req => req.SetJWTBearerToken(login.AccessToken))) - .Content.Value.Car!; + .Content.Value.Car; result.Id.Should().Be(car.Id); result.Manufacturer!.Make.Should().Be(Manufacturer.AllowedMakes[0]); @@ -68,7 +68,7 @@ public async Task WhenRegisterCar_ThenReturnsCar() NumberPlate = "aplate" }, req => req.SetJWTBearerToken(login.AccessToken)); - var car = result.Content.Value.Car!; + var car = result.Content.Value.Car; var location = result.Headers.Location?.ToString(); location.Should().Be(new GetCarRequest { Id = car.Id }.ToUrl()); car.Id.Should().NotBeEmpty(); @@ -90,7 +90,7 @@ public async Task WhenSearchAllCars_ThenReturnsCars() var result = (await Api.GetAsync(new SearchAllCarsRequest(), req => req.SetJWTBearerToken(login.AccessToken))) - .Content.Value.Cars!; + .Content.Value.Cars; result.Count.Should().Be(1); result[0].Id.Should().Be(car.Id); @@ -114,7 +114,7 @@ await Api.PutAsync(new TakeOfflineCarRequest { FromUtc = datum, ToUtc = datum.AddDays(1) - }, req => req.SetJWTBearerToken(login.AccessToken))).Content.Value.Cars!; + }, req => req.SetJWTBearerToken(login.AccessToken))).Content.Value.Cars; cars.Count.Should().Be(1); cars[0].Id.Should().Be(car2.Id); @@ -132,7 +132,7 @@ public async Task WhenTakeCarOffline_ThenReturnsCar() Id = car.Id, FromUtc = datum, ToUtc = datum.AddHours(1) - }, req => req.SetJWTBearerToken(login.AccessToken))).Content.Value.Car!; + }, req => req.SetJWTBearerToken(login.AccessToken))).Content.Value.Car; result.Id.Should().Be(car.Id); @@ -140,7 +140,7 @@ public async Task WhenTakeCarOffline_ThenReturnsCar() var unavailabilities = (await Api.GetAsync(new SearchAllCarUnavailabilitiesRequest { Id = car.Id - }, req => req.SetJWTBearerToken(login.AccessToken))).Content.Value.Unavailabilities!; + }, req => req.SetJWTBearerToken(login.AccessToken))).Content.Value.Unavailabilities; unavailabilities.Count.Should().Be(1); unavailabilities[0].CarId.Should().Be(car.Id); @@ -161,7 +161,7 @@ public async Task WhenScheduleMaintenance_ThenReturnsCar() Id = car.Id, FromUtc = datum, ToUtc = datum.AddHours(1) - }, req => req.SetJWTBearerToken(login.AccessToken))).Content.Value.Car!; + }, req => req.SetJWTBearerToken(login.AccessToken))).Content.Value.Car; result.Id.Should().Be(car.Id); @@ -169,7 +169,7 @@ public async Task WhenScheduleMaintenance_ThenReturnsCar() var unavailabilities = (await Api.GetAsync(new SearchAllCarUnavailabilitiesRequest { Id = car.Id - }, req => req.SetJWTBearerToken(login.AccessToken))).Content.Value.Unavailabilities!; + }, req => req.SetJWTBearerToken(login.AccessToken))).Content.Value.Unavailabilities; unavailabilities.Count.Should().Be(1); unavailabilities[0].CarId.Should().Be(car.Id); @@ -194,6 +194,6 @@ private async Task RegisterNewCarAsync(LoginDetails login) NumberPlate = "aplate" }, req => req.SetJWTBearerToken(login.AccessToken)); - return car.Content.Value.Car!; + return car.Content.Value.Car; } } \ No newline at end of file diff --git a/src/CarsInfrastructure/ApplicationServices/CarsHttpServiceClient.cs b/src/CarsInfrastructure/ApplicationServices/CarsHttpServiceClient.cs index 808fc34a..ef577193 100644 --- a/src/CarsInfrastructure/ApplicationServices/CarsHttpServiceClient.cs +++ b/src/CarsInfrastructure/ApplicationServices/CarsHttpServiceClient.cs @@ -30,7 +30,7 @@ public async Task> GetCarAsync(ICallerContext caller, string Id = id }, null, cancellationToken); - return response.Match>(res => res.Value.Car!, error => error.ToError()); + return response.Match>(res => res.Value.Car, error => error.ToError()); } public async Task> ReleaseCarAvailabilityAsync(ICallerContext caller, string organizationId, @@ -44,7 +44,7 @@ public async Task> ReleaseCarAvailabilityAsync(ICallerContext ToUtc = toUtc }, null, cancellationToken); - return response.Match>(res => res.Value.Car!, error => error.ToError()); + return response.Match>(res => res.Value.Car, error => error.ToError()); } public async Task> ReserveCarIfAvailableAsync(ICallerContext caller, string organizationId, diff --git a/src/EndUsersInfrastructure.IntegrationTests/EndUsersApiSpec.cs b/src/EndUsersInfrastructure.IntegrationTests/EndUsersApiSpec.cs index cf138d0f..bf18b906 100644 --- a/src/EndUsersInfrastructure.IntegrationTests/EndUsersApiSpec.cs +++ b/src/EndUsersInfrastructure.IntegrationTests/EndUsersApiSpec.cs @@ -44,7 +44,7 @@ public async Task WhenAssignPlatformRoles_ThenAssignsRoles() Roles = [PlatformRoles.TestingOnly.Name] }, req => req.SetJWTBearerToken(login.AccessToken)); - result.Content.Value.User!.Roles.Should() + result.Content.Value.User.Roles.Should() .ContainInOrder(PlatformRoles.Standard.Name, PlatformRoles.TestingOnly.Name); #endif } @@ -66,7 +66,7 @@ await Api.PostAsync(new AssignPlatformRolesRequest Roles = [PlatformRoles.TestingOnly.Name] }, req => req.SetJWTBearerToken(login.AccessToken)); - result.Content.Value.User!.Roles.Should() + result.Content.Value.User.Roles.Should() .ContainInOrder(PlatformRoles.Operations.Name, PlatformRoles.Standard.Name); #endif } @@ -83,7 +83,7 @@ public async Task WhenAssignAndUnassignOperatorRoles_ThenRemainsStandardRole() Roles = [PlatformRoles.Operations.Name] }, req => req.SetJWTBearerToken(@operator.AccessToken)); - result1.Content.Value.User!.Roles.Should() + result1.Content.Value.User.Roles.Should() .ContainInOrder(PlatformRoles.Operations.Name, PlatformRoles.Standard.Name); var result2 = await Api.PatchAsync(new UnassignPlatformRolesRequest @@ -92,7 +92,7 @@ public async Task WhenAssignAndUnassignOperatorRoles_ThenRemainsStandardRole() Roles = [PlatformRoles.Operations.Name] }, req => req.SetJWTBearerToken(@operator.AccessToken)); - result2.Content.Value.User!.Roles.Should() + result2.Content.Value.User.Roles.Should() .OnlyContain(rol => rol == PlatformRoles.Standard.Name); #endif } diff --git a/src/EndUsersInfrastructure.IntegrationTests/InvitationsApiSpec.cs b/src/EndUsersInfrastructure.IntegrationTests/InvitationsApiSpec.cs index 03cda5a6..37cf05e5 100644 --- a/src/EndUsersInfrastructure.IntegrationTests/InvitationsApiSpec.cs +++ b/src/EndUsersInfrastructure.IntegrationTests/InvitationsApiSpec.cs @@ -41,9 +41,9 @@ public async Task WhenInviteGuestAndNotYetInvited_ThenInvites() Email = emailAddress }, req => req.SetJWTBearerToken(login.AccessToken)); - result.Content.Value.Invitation!.EmailAddress.Should().Be(emailAddress); - result.Content.Value.Invitation!.FirstName.Should().Be("Aninvitee"); - result.Content.Value.Invitation!.LastName.Should().BeNull(); + result.Content.Value.Invitation.EmailAddress.Should().Be(emailAddress); + result.Content.Value.Invitation.FirstName.Should().Be("Aninvitee"); + result.Content.Value.Invitation.LastName.Should().BeNull(); _userNotificationService.LastGuestInvitationEmailRecipient.Should().Be(emailAddress); } @@ -67,9 +67,9 @@ await Api.PostAsync(new InviteGuestRequest Email = emailAddress }, req => req.SetJWTBearerToken(login.AccessToken)); - result.Content.Value.Invitation!.EmailAddress.Should().Be(emailAddress); - result.Content.Value.Invitation!.FirstName.Should().Be("Aninvitee"); - result.Content.Value.Invitation!.LastName.Should().BeNull(); + result.Content.Value.Invitation.EmailAddress.Should().Be(emailAddress); + result.Content.Value.Invitation.FirstName.Should().Be("Aninvitee"); + result.Content.Value.Invitation.LastName.Should().BeNull(); _userNotificationService.LastGuestInvitationEmailRecipient.Should().Be(emailAddress); } @@ -95,9 +95,9 @@ await Api.PostAsync(new InviteGuestRequest Email = emailAddress }, req => req.SetJWTBearerToken(login.AccessToken)); - result.Content.Value.Invitation!.EmailAddress.Should().Be(emailAddress); - result.Content.Value.Invitation!.FirstName.Should().Be("afirstname"); - result.Content.Value.Invitation!.LastName.Should().Be("alastname"); + result.Content.Value.Invitation.EmailAddress.Should().Be(emailAddress); + result.Content.Value.Invitation.FirstName.Should().Be("afirstname"); + result.Content.Value.Invitation.LastName.Should().Be("alastname"); _userNotificationService.LastGuestInvitationEmailRecipient.Should().BeNull(); } @@ -140,7 +140,7 @@ await Api.PostAsync(new InviteGuestRequest Token = token }); - result.Content.Value.Invitation!.EmailAddress.Should().Be(emailAddress); + result.Content.Value.Invitation.EmailAddress.Should().Be(emailAddress); result.Content.Value.Invitation.FirstName.Should().Be("Aninvitee"); result.Content.Value.Invitation.LastName.Should().BeNull(); } @@ -203,7 +203,7 @@ public async Task WhenAcceptInvitationAndNotInvited_ThenRegistersUser() TermsAndConditionsAccepted = true }); - result.Content.Value.Credential!.Id.Should().NotBeEmpty(); + result.Content.Value.Credential.Id.Should().NotBeEmpty(); result.Content.Value.Credential.User.Id.Should().NotBeEmpty(); result.Content.Value.Credential.User.Access.Should().Be(EndUserAccess.Enabled); result.Content.Value.Credential.User.Status.Should().Be(EndUserStatus.Registered); @@ -235,7 +235,7 @@ await Api.PostAsync(new InviteGuestRequest TermsAndConditionsAccepted = true }); - result.Content.Value.Credential!.Id.Should().NotBeEmpty(); + result.Content.Value.Credential.Id.Should().NotBeEmpty(); result.Content.Value.Credential.User.Id.Should().NotBeEmpty(); result.Content.Value.Credential.User.Access.Should().Be(EndUserAccess.Enabled); result.Content.Value.Credential.User.Status.Should().Be(EndUserStatus.Registered); @@ -268,7 +268,7 @@ await Api.PostAsync(new InviteGuestRequest TermsAndConditionsAccepted = true }); - result.Content.Value.Credential!.Id.Should().NotBeEmpty(); + result.Content.Value.Credential.Id.Should().NotBeEmpty(); result.Content.Value.Credential.User.Id.Should().NotBeEmpty(); result.Content.Value.Credential.User.Access.Should().Be(EndUserAccess.Enabled); result.Content.Value.Credential.User.Status.Should().Be(EndUserStatus.Registered); diff --git a/src/EndUsersInfrastructure.IntegrationTests/MembershipsApiSpec.cs b/src/EndUsersInfrastructure.IntegrationTests/MembershipsApiSpec.cs index f31e9103..c4ad8b29 100644 --- a/src/EndUsersInfrastructure.IntegrationTests/MembershipsApiSpec.cs +++ b/src/EndUsersInfrastructure.IntegrationTests/MembershipsApiSpec.cs @@ -31,7 +31,7 @@ public async Task WhenChangeDefaultOrganization_ThenChangesDefault() Name = "aname" }, req => req.SetJWTBearerToken(login.AccessToken)); - var organizationId2 = organization2.Content.Value.Organization!.Id; + var organizationId2 = organization2.Content.Value.Organization.Id; login = await ReAuthenticateUserAsync(login); login.DefaultOrganizationId.Should().Be(organizationId2); @@ -55,10 +55,10 @@ public async Task WhenListMembershipsForCaller_ThenReturnsMemberships() Name = "aname" }, req => req.SetJWTBearerToken(login.AccessToken)); - var organizationId = result.Content.Value.Organization!.Id; - result.Content.Value.Organization!.CreatedById.Should().Be(login.User.Id); - result.Content.Value.Organization!.Name.Should().Be("aname"); - result.Content.Value.Organization!.Ownership.Should().Be(OrganizationOwnership.Shared); + var organizationId = result.Content.Value.Organization.Id; + result.Content.Value.Organization.CreatedById.Should().Be(login.User.Id); + result.Content.Value.Organization.Name.Should().Be("aname"); + result.Content.Value.Organization.Ownership.Should().Be(OrganizationOwnership.Shared); login = await ReAuthenticateUserAsync(login); login.DefaultOrganizationId.Should().Be(organizationId); @@ -66,11 +66,11 @@ public async Task WhenListMembershipsForCaller_ThenReturnsMemberships() var memberships = await Api.GetAsync(new ListMembershipsForCallerRequest(), req => req.SetJWTBearerToken(login.AccessToken)); - memberships.Content.Value.Memberships!.Count.Should().Be(2); - memberships.Content.Value.Memberships![0].OrganizationId.Should().NotBeNull(); - memberships.Content.Value.Memberships![0].Ownership.Should().Be(OrganizationOwnership.Personal); - memberships.Content.Value.Memberships![1].OrganizationId.Should().Be(organizationId); - memberships.Content.Value.Memberships![1].Ownership.Should().Be(OrganizationOwnership.Shared); + memberships.Content.Value.Memberships.Count.Should().Be(2); + memberships.Content.Value.Memberships[0].OrganizationId.Should().NotBeNull(); + memberships.Content.Value.Memberships[0].Ownership.Should().Be(OrganizationOwnership.Personal); + memberships.Content.Value.Memberships[1].OrganizationId.Should().Be(organizationId); + memberships.Content.Value.Memberships[1].Ownership.Should().Be(OrganizationOwnership.Shared); } private static void OverrideDependencies(IServiceCollection services) diff --git a/src/IdentityInfrastructure.IntegrationTests/AuthTokensApiSpec.cs b/src/IdentityInfrastructure.IntegrationTests/AuthTokensApiSpec.cs index 01f08d6b..fc7ac4a0 100644 --- a/src/IdentityInfrastructure.IntegrationTests/AuthTokensApiSpec.cs +++ b/src/IdentityInfrastructure.IntegrationTests/AuthTokensApiSpec.cs @@ -45,7 +45,7 @@ await Api.PostAsync(new ConfirmRegistrationPersonPasswordRequest Password = "1Password!" }); - oldTokens.Content.Value.Tokens!.AccessToken.Value.Should().NotBeNull(); + oldTokens.Content.Value.Tokens.AccessToken.Value.Should().NotBeNull(); oldTokens.Content.Value.Tokens.AccessToken.ExpiresOn.Should() .BeNear(DateTime.UtcNow.Add(AuthenticationConstants.Tokens.DefaultAccessTokenExpiry)); oldTokens.Content.Value.Tokens.RefreshToken.Value.Should().NotBeNull(); @@ -62,7 +62,7 @@ await Task.Delay(TimeSpan RefreshToken = oldRefreshToken }); - newTokens.Content.Value.Tokens!.AccessToken.Value.Should().NotBeNull().And.NotBe(oldAccessToken); + newTokens.Content.Value.Tokens.AccessToken.Value.Should().NotBeNull().And.NotBe(oldAccessToken); newTokens.Content.Value.Tokens.AccessToken.ExpiresOn.Should() .BeNear(DateTime.UtcNow.Add(AuthenticationConstants.Tokens.DefaultAccessTokenExpiry)); newTokens.Content.Value.Tokens.RefreshToken.Value.Should().NotBeNull().And.NotBe(oldRefreshToken); diff --git a/src/IdentityInfrastructure.IntegrationTests/IdentityApiSpec.cs b/src/IdentityInfrastructure.IntegrationTests/IdentityApiSpec.cs index 4433b3d0..44f08e61 100644 --- a/src/IdentityInfrastructure.IntegrationTests/IdentityApiSpec.cs +++ b/src/IdentityInfrastructure.IntegrationTests/IdentityApiSpec.cs @@ -25,8 +25,8 @@ public async Task WhenGetIdentity_ThenReturnsIdentity() var result = await Api.GetAsync(new GetIdentityForCallerRequest(), req => req.SetJWTBearerToken(login.AccessToken)); - result.Content.Value.Identity!.Id.Should().NotBeEmpty(); - result.Content.Value.Identity!.IsMfaEnabled.Should().BeFalse(); + result.Content.Value.Identity.Id.Should().NotBeEmpty(); + result.Content.Value.Identity.IsMfaEnabled.Should().BeFalse(); } [Fact] @@ -42,7 +42,7 @@ await Api.PutAsync(new ChangePasswordMfaForCallerRequest var result = await Api.GetAsync(new GetIdentityForCallerRequest(), req => req.SetJWTBearerToken(login.AccessToken)); - result.Content.Value.Identity!.IsMfaEnabled.Should().BeTrue(); + result.Content.Value.Identity.IsMfaEnabled.Should().BeTrue(); } private static void OverrideDependencies(IServiceCollection services) diff --git a/src/IdentityInfrastructure.IntegrationTests/MachineCredentialsApiSpec.cs b/src/IdentityInfrastructure.IntegrationTests/MachineCredentialsApiSpec.cs index 698a7106..0704ce09 100644 --- a/src/IdentityInfrastructure.IntegrationTests/MachineCredentialsApiSpec.cs +++ b/src/IdentityInfrastructure.IntegrationTests/MachineCredentialsApiSpec.cs @@ -31,7 +31,7 @@ public async Task WhenRegisterMachineByAnonymous_ThenRegisters() Name = "amachinename" }); - result.Content.Value.Machine!.Id.Should().NotBeEmpty(); + result.Content.Value.Machine.Id.Should().NotBeEmpty(); result.Content.Value.Machine.Description.Should().Be("amachinename"); result.Content.Value.Machine.ApiKey.Should().StartWith("apk_"); result.Content.Value.Machine.CreatedById.Should().Be(CallerConstants.AnonymousUserId); @@ -49,7 +49,7 @@ public async Task WhenRegisterMachineByUser_ThenRegisters() Name = "amachinename" }, req => req.SetJWTBearerToken(login.AccessToken)); - result.Content.Value.Machine!.Id.Should().NotBeEmpty(); + result.Content.Value.Machine.Id.Should().NotBeEmpty(); result.Content.Value.Machine.Description.Should().Be("amachinename"); result.Content.Value.Machine.ApiKey.Should().StartWith("apk_"); result.Content.Value.Machine.CreatedById.Should().Be(login.User.Id); @@ -66,7 +66,7 @@ public async Task WhenCallingSecureApiWithMachineApiKey_ThenReturnsResponse() }); await PropagateDomainEventsAsync(PropagationRounds.Twice); - var apiKey = machine.Content.Value.Machine!.ApiKey; + var apiKey = machine.Content.Value.Machine.ApiKey; #if TESTINGONLY var result = await Api.GetAsync(new GetCallerWithTokenOrAPIKeyTestingOnlyRequest(), req => req.SetAPIKey(apiKey)); diff --git a/src/IdentityInfrastructure.IntegrationTests/MfaApiSpec.cs b/src/IdentityInfrastructure.IntegrationTests/MfaApiSpec.cs index bd287b65..dddf59a3 100644 --- a/src/IdentityInfrastructure.IntegrationTests/MfaApiSpec.cs +++ b/src/IdentityInfrastructure.IntegrationTests/MfaApiSpec.cs @@ -54,7 +54,7 @@ public async Task WhenListMfaAuthenticatorsWithNone_ThenReturnsEmpty() MfaToken = mfaToken }); - result.Content.Value.Authenticators!.Count.Should().Be(0); + result.Content.Value.Authenticators.Count.Should().Be(0); } [Fact] @@ -70,7 +70,7 @@ public async Task WhenAssociateMfaAuthenticatorWithOtpAuthenticator_ThenAssociat PhoneNumber = null }); - result.Content.Value.Authenticator!.Type.Should() + result.Content.Value.Authenticator.Type.Should() .Be(PasswordCredentialMfaAuthenticatorType.TotpAuthenticator); result.Content.Value.Authenticator.RecoveryCodes.Should().NotBeEmpty(); result.Content.Value.Authenticator.OobCode.Should().BeNull(); @@ -99,7 +99,7 @@ public async Task WhenAssociateMfaAuthenticatorWithOobSms_ThenAssociates() PhoneNumber = "+6498876986" }); - result.Content.Value.Authenticator!.Type.Should().Be(PasswordCredentialMfaAuthenticatorType.OobSms); + result.Content.Value.Authenticator.Type.Should().Be(PasswordCredentialMfaAuthenticatorType.OobSms); result.Content.Value.Authenticator.RecoveryCodes.Should().NotBeEmpty(); result.Content.Value.Authenticator.OobCode.Should().NotBeNullOrEmpty(); result.Content.Value.Authenticator.BarCodeUri.Should().BeNull(); @@ -129,7 +129,7 @@ public async Task WhenAssociateMfaAuthenticatorWithOobEmail_ThenAssociates() PhoneNumber = null }); - result.Content.Value.Authenticator!.Type.Should().Be(PasswordCredentialMfaAuthenticatorType.OobEmail); + result.Content.Value.Authenticator.Type.Should().Be(PasswordCredentialMfaAuthenticatorType.OobEmail); result.Content.Value.Authenticator.RecoveryCodes.Should().NotBeEmpty(); result.Content.Value.Authenticator.OobCode.Should().NotBeNullOrEmpty(); result.Content.Value.Authenticator.BarCodeUri.Should().BeNull(); @@ -164,7 +164,7 @@ public async Task WhenAssociateMfaAuthenticatorAgainForSameAuthenticator_ThenUpd PhoneNumber = "+6498876982" }); - result.Content.Value.Authenticator!.Type.Should().Be(PasswordCredentialMfaAuthenticatorType.OobSms); + result.Content.Value.Authenticator.Type.Should().Be(PasswordCredentialMfaAuthenticatorType.OobSms); result.Content.Value.Authenticator.RecoveryCodes.Should().NotBeEmpty(); result.Content.Value.Authenticator.OobCode.Should().NotBeNullOrEmpty(); result.Content.Value.Authenticator.BarCodeUri.Should().BeNull(); @@ -295,8 +295,8 @@ public async Task WhenChallengeMfaAuthenticatorWithOtpAuthenticator_ThenChalleng AuthenticatorId = authenticator!.Id }); - result.Content.Value.Challenge!.Type.Should().Be(PasswordCredentialMfaAuthenticatorType.TotpAuthenticator); - result.Content.Value.Challenge!.OobCode.Should().BeNull(); + result.Content.Value.Challenge.Type.Should().Be(PasswordCredentialMfaAuthenticatorType.TotpAuthenticator); + result.Content.Value.Challenge.OobCode.Should().BeNull(); _userNotificationsService.LastMfaOobSmsRecipient.Should().BeNull(); _userNotificationsService.LastMfaOobEmailRecipient.Should().BeNull(); } @@ -319,8 +319,8 @@ public async Task WhenChallengeMfaAuthenticatorWithOobSms_ThenChallenges() AuthenticatorId = authenticator!.Id }); - result.Content.Value.Challenge!.Type.Should().Be(PasswordCredentialMfaAuthenticatorType.OobSms); - result.Content.Value.Challenge!.OobCode.Should().NotBeNullOrEmpty(); + result.Content.Value.Challenge.Type.Should().Be(PasswordCredentialMfaAuthenticatorType.OobSms); + result.Content.Value.Challenge.OobCode.Should().NotBeNullOrEmpty(); _userNotificationsService.LastMfaOobSmsRecipient.Should().Be("+6498876986"); _userNotificationsService.LastMfaOobCode.Should().NotBeEmpty(); } @@ -343,8 +343,8 @@ public async Task WhenChallengeMfaAuthenticatorWithOobEmail_ThenChallenges() AuthenticatorId = authenticator!.Id }); - result.Content.Value.Challenge!.Type.Should().Be(PasswordCredentialMfaAuthenticatorType.OobEmail); - result.Content.Value.Challenge!.OobCode.Should().NotBeNullOrEmpty(); + result.Content.Value.Challenge.Type.Should().Be(PasswordCredentialMfaAuthenticatorType.OobEmail); + result.Content.Value.Challenge.OobCode.Should().NotBeNullOrEmpty(); _userNotificationsService.LastMfaOobEmailRecipient.Should().Be(login.Profile!.EmailAddress); _userNotificationsService.LastMfaOobCode.Should().NotBeEmpty(); } @@ -372,7 +372,7 @@ public async Task WhenVerifyMfaAuthenticatorWithOtpAuthenticator_ThenAuthenticat ConfirmationCode = confirmationCode }); - result.Content.Value.Tokens!.AccessToken.Value.Should().NotBeNull(); + result.Content.Value.Tokens.AccessToken.Value.Should().NotBeNull(); result.Content.Value.Tokens.AccessToken.ExpiresOn.Should() .BeNear(DateTime.UtcNow.Add(AuthenticationConstants.Tokens.DefaultAccessTokenExpiry)); result.Content.Value.Tokens.RefreshToken.Value.Should().NotBeNull(); @@ -401,7 +401,7 @@ public async Task WhenVerifyMfaAuthenticatorWithOobSms_ThenAuthenticates() ConfirmationCode = confirmationCode }); - result.Content.Value.Tokens!.AccessToken.Value.Should().NotBeNull(); + result.Content.Value.Tokens.AccessToken.Value.Should().NotBeNull(); result.Content.Value.Tokens.AccessToken.ExpiresOn.Should() .BeNear(DateTime.UtcNow.Add(AuthenticationConstants.Tokens.DefaultAccessTokenExpiry)); result.Content.Value.Tokens.RefreshToken.Value.Should().NotBeNull(); @@ -430,7 +430,7 @@ public async Task WhenVerifyMfaAuthenticatorWithOobEmail_ThenAuthenticates() ConfirmationCode = confirmationCode }); - result.Content.Value.Tokens!.AccessToken.Value.Should().NotBeNull(); + result.Content.Value.Tokens.AccessToken.Value.Should().NotBeNull(); result.Content.Value.Tokens.AccessToken.ExpiresOn.Should() .BeNear(DateTime.UtcNow.Add(AuthenticationConstants.Tokens.DefaultAccessTokenExpiry)); result.Content.Value.Tokens.RefreshToken.Value.Should().NotBeNull(); @@ -460,7 +460,7 @@ public async Task WhenVerifyMfaAuthenticatorWithARecoveryCode_ThenAuthenticates( ConfirmationCode = recoveryCodes![0] }); - result.Content.Value.Tokens!.AccessToken.Value.Should().NotBeNull(); + result.Content.Value.Tokens.AccessToken.Value.Should().NotBeNull(); result.Content.Value.Tokens.AccessToken.ExpiresOn.Should() .BeNear(DateTime.UtcNow.Add(AuthenticationConstants.Tokens.DefaultAccessTokenExpiry)); result.Content.Value.Tokens.RefreshToken.Value.Should().NotBeNull(); @@ -477,7 +477,7 @@ public async Task WhenVerifyMfaAuthenticatorWithARecoveryCode_ThenAuthenticates( AuthenticatorId = authenticator!.Id }); - var oobCode = challenged.Content.Value.Challenge!.OobCode!; + var oobCode = challenged.Content.Value.Challenge.OobCode!; var confirmationCode = _mfaService.LastOobConfirmationCode!; return (oobCode, confirmationCode); @@ -491,7 +491,7 @@ public async Task WhenVerifyMfaAuthenticatorWithARecoveryCode_ThenAuthenticates( MfaToken = mfaToken }); - return authenticators.Content.Value.Authenticators! + return authenticators.Content.Value.Authenticators .FirstOrDefault(auth => auth.Type == type); } @@ -502,7 +502,7 @@ private async Task> GetAuthenticators(s MfaToken = mfaToken }); - return authenticators.Content.Value.Authenticators!; + return authenticators.Content.Value.Authenticators; } private async Task Confirm(PasswordCredentialMfaAuthenticatorType type, string mfaToken, string? oobCode = null, @@ -529,9 +529,9 @@ await Api.PutAsync(new ConfirmPasswordMfaAuthenticatorForCallerRequest : null }); - var oobCode = associated.Content.Value.Authenticator!.OobCode!; + var oobCode = associated.Content.Value.Authenticator.OobCode!; var confirmationCode = _mfaService.LastOobConfirmationCode!; - var recoveryCodes = associated.Content.Value.Authenticator!.RecoveryCodes; + var recoveryCodes = associated.Content.Value.Authenticator.RecoveryCodes; return (oobCode, confirmationCode, recoveryCodes); } @@ -591,7 +591,7 @@ public async Task WhenEnableMfa_ThenEnables() IsEnabled = true }, req => req.SetJWTBearerToken(login.AccessToken)); - result.Content.Value.Credential!.Id.Should().NotBeEmpty(); + result.Content.Value.Credential.Id.Should().NotBeEmpty(); result.Content.Value.Credential.IsMfaEnabled.Should().BeTrue(); } @@ -606,7 +606,7 @@ public async Task WhenDisableMfa_ThenDisables() IsEnabled = false }, req => req.SetJWTBearerToken(login.AccessToken)); - result.Content.Value.Credential!.Id.Should().NotBeEmpty(); + result.Content.Value.Credential.Id.Should().NotBeEmpty(); result.Content.Value.Credential.IsMfaEnabled.Should().BeFalse(); } @@ -626,7 +626,7 @@ public async Task WhenDisableMfa_ThenDeletesAllAuthenticatorsAndDisables() await EnableMfa(login); - result.Content.Value.Credential!.IsMfaEnabled.Should().BeFalse(); + result.Content.Value.Credential.IsMfaEnabled.Should().BeFalse(); var authenticators = await GetAuthenticators(login); authenticators.Count.Should().Be(0); } @@ -639,7 +639,7 @@ public async Task WhenListMfaAuthenticatorsWithNone_ThenReturnsEmpty() var result = await Api.GetAsync(new ListPasswordMfaAuthenticatorsForCallerRequest(), req => req.SetJWTBearerToken(login.AccessToken)); - result.Content.Value.Authenticators!.Count.Should().Be(0); + result.Content.Value.Authenticators.Count.Should().Be(0); } [Fact] @@ -654,7 +654,7 @@ public async Task WhenAssociateMfaAuthenticatorWithOtpAuthenticator_ThenAssociat }, req => req.SetJWTBearerToken(login.AccessToken)); - result.Content.Value.Authenticator!.Type.Should() + result.Content.Value.Authenticator.Type.Should() .Be(PasswordCredentialMfaAuthenticatorType.TotpAuthenticator); result.Content.Value.Authenticator.RecoveryCodes.Should().NotBeEmpty(); result.Content.Value.Authenticator.OobCode.Should().BeNull(); @@ -682,7 +682,7 @@ public async Task WhenAssociateMfaAuthenticatorWithOobSms_ThenAssociates() }, req => req.SetJWTBearerToken(login.AccessToken)); - result.Content.Value.Authenticator!.Type.Should().Be(PasswordCredentialMfaAuthenticatorType.OobSms); + result.Content.Value.Authenticator.Type.Should().Be(PasswordCredentialMfaAuthenticatorType.OobSms); result.Content.Value.Authenticator.RecoveryCodes.Should().NotBeEmpty(); result.Content.Value.Authenticator.OobCode.Should().NotBeNullOrEmpty(); result.Content.Value.Authenticator.BarCodeUri.Should().BeNull(); @@ -711,7 +711,7 @@ public async Task WhenAssociateMfaAuthenticatorWithOobEmail_ThenAssociates() }, req => req.SetJWTBearerToken(login.AccessToken)); - result.Content.Value.Authenticator!.Type.Should().Be(PasswordCredentialMfaAuthenticatorType.OobEmail); + result.Content.Value.Authenticator.Type.Should().Be(PasswordCredentialMfaAuthenticatorType.OobEmail); result.Content.Value.Authenticator.RecoveryCodes.Should().NotBeEmpty(); result.Content.Value.Authenticator.OobCode.Should().NotBeNullOrEmpty(); result.Content.Value.Authenticator.BarCodeUri.Should().BeNull(); @@ -745,7 +745,7 @@ public async Task WhenAssociateMfaAuthenticatorAgainForSameAuthenticator_ThenUpd }, req => req.SetJWTBearerToken(login.AccessToken)); - result.Content.Value.Authenticator!.Type.Should().Be(PasswordCredentialMfaAuthenticatorType.OobSms); + result.Content.Value.Authenticator.Type.Should().Be(PasswordCredentialMfaAuthenticatorType.OobSms); result.Content.Value.Authenticator.RecoveryCodes.Should().NotBeEmpty(); result.Content.Value.Authenticator.OobCode.Should().NotBeNullOrEmpty(); result.Content.Value.Authenticator.BarCodeUri.Should().BeNull(); @@ -778,7 +778,7 @@ public async Task WhenAssociateMfaAuthenticatorAgainForAnotherAuthenticator_Then }, req => req.SetJWTBearerToken(login.AccessToken)); - result.Content.Value.Authenticator!.Type.Should().Be(PasswordCredentialMfaAuthenticatorType.OobSms); + result.Content.Value.Authenticator.Type.Should().Be(PasswordCredentialMfaAuthenticatorType.OobSms); result.Content.Value.Authenticator.RecoveryCodes.Should().BeNull(); result.Content.Value.Authenticator.OobCode.Should().NotBeNullOrEmpty(); result.Content.Value.Authenticator.BarCodeUri.Should().BeNull(); @@ -964,9 +964,9 @@ public async Task WhenResetUserMfaByOperator_ThenResetsMfaToDefault() }, req => req.SetJWTBearerToken(login.AccessToken)); - var oobCode = associated.Content.Value.Authenticator!.OobCode!; + var oobCode = associated.Content.Value.Authenticator.OobCode!; var confirmationCode = _mfaService.LastOobConfirmationCode!; - var recoveryCodes = associated.Content.Value.Authenticator!.RecoveryCodes; + var recoveryCodes = associated.Content.Value.Authenticator.RecoveryCodes; return (oobCode, confirmationCode, recoveryCodes); } @@ -988,7 +988,7 @@ private async Task> GetAuthenticators(L var authenticators = await Api.GetAsync(new ListPasswordMfaAuthenticatorsForCallerRequest(), req => req.SetJWTBearerToken(login.AccessToken)); - return authenticators.Content.Value.Authenticators!; + return authenticators.Content.Value.Authenticators; } private async Task EnableMfa(LoginDetails login) diff --git a/src/IdentityInfrastructure.IntegrationTests/PasswordCredentialsApiSpec.cs b/src/IdentityInfrastructure.IntegrationTests/PasswordCredentialsApiSpec.cs index 5eb1856c..69052370 100644 --- a/src/IdentityInfrastructure.IntegrationTests/PasswordCredentialsApiSpec.cs +++ b/src/IdentityInfrastructure.IntegrationTests/PasswordCredentialsApiSpec.cs @@ -48,7 +48,7 @@ public async Task WhenRegisterPerson_ThenRegisters() TermsAndConditionsAccepted = true }); - result.Content.Value.Credential!.Id.Should().NotBeEmpty(); + result.Content.Value.Credential.Id.Should().NotBeEmpty(); result.Content.Value.Credential.User.Id.Should().NotBeEmpty(); result.Content.Value.Credential.User.Access.Should().Be(EndUserAccess.Enabled); result.Content.Value.Credential.User.Status.Should().Be(EndUserStatus.Registered); @@ -121,7 +121,7 @@ await Api.PostAsync(new ConfirmRegistrationPersonPasswordRequest Password = "1Password!" }); - result.Content.Value.Tokens!.AccessToken.Value.Should().NotBeNull(); + result.Content.Value.Tokens.AccessToken.Value.Should().NotBeNull(); result.Content.Value.Tokens.AccessToken.ExpiresOn.Should() .BeNear(DateTime.UtcNow.Add(AuthenticationConstants.Tokens.DefaultAccessTokenExpiry)); result.Content.Value.Tokens.RefreshToken.Value.Should().NotBeNull(); @@ -177,14 +177,14 @@ await Api.PostAsync(new ConfirmRegistrationPersonPasswordRequest Password = "1Password!" }); - var accessToken = authenticate.Content.Value.Tokens!.AccessToken.Value; + var accessToken = authenticate.Content.Value.Tokens.AccessToken.Value; #if TESTINGONLY var result = await Api.GetAsync(new GetCallerWithTokenOrAPIKeyTestingOnlyRequest(), req => req.SetJWTBearerToken(accessToken)); result.StatusCode.Should().Be(HttpStatusCode.OK); - result.Content.Value.CallerId.Should().Be(person.Content.Value.Credential!.User.Id); + result.Content.Value.CallerId.Should().Be(person.Content.Value.Credential.User.Id); #endif } diff --git a/src/IdentityInfrastructure.IntegrationTests/SingleSignOnApiSpec.cs b/src/IdentityInfrastructure.IntegrationTests/SingleSignOnApiSpec.cs index 21479d01..b33c05e7 100644 --- a/src/IdentityInfrastructure.IntegrationTests/SingleSignOnApiSpec.cs +++ b/src/IdentityInfrastructure.IntegrationTests/SingleSignOnApiSpec.cs @@ -75,7 +75,7 @@ public async Task WhenAuthenticateAndUserNotExists_ThenRegistersAndReturnsUser() AuthCode = "1234567890" }); - result.Content.Value.Tokens!.UserId.Should().NotBeNull(); + result.Content.Value.Tokens.UserId.Should().NotBeNull(); result.Content.Value.Tokens.AccessToken.Value.Should().NotBeNull(); result.Content.Value.Tokens.AccessToken.ExpiresOn.Should() .BeNear(DateTime.UtcNow.Add(AuthenticationConstants.Tokens.DefaultAccessTokenExpiry)); @@ -113,7 +113,7 @@ await Api.PostAsync(new ConfirmRegistrationPersonPasswordRequest AuthCode = "1234567890" }); - result.Content.Value.Tokens!.UserId.Should().Be(person.Content.Value.Credential!.User.Id); + result.Content.Value.Tokens.UserId.Should().Be(person.Content.Value.Credential.User.Id); result.Content.Value.Tokens.AccessToken.Value.Should().NotBeNull(); result.Content.Value.Tokens.AccessToken.ExpiresOn.Should() .BeNear(DateTime.UtcNow.Add(AuthenticationConstants.Tokens.DefaultAccessTokenExpiry)); @@ -134,7 +134,7 @@ public async Task WhenCallingSecureApiAfterAuthenticate_ThenReturnsResponse() AuthCode = "1234567890" }); - var accessToken = authenticate.Content.Value.Tokens!.AccessToken.Value; + var accessToken = authenticate.Content.Value.Tokens.AccessToken.Value; var result = await Api.GetAsync(new GetCallerWithTokenOrAPIKeyTestingOnlyRequest(), req => req.SetJWTBearerToken(accessToken)); diff --git a/src/ImagesInfrastructure.IntegrationTests/ImagesApiSpec.cs b/src/ImagesInfrastructure.IntegrationTests/ImagesApiSpec.cs index 3bd30c19..ba956d06 100644 --- a/src/ImagesInfrastructure.IntegrationTests/ImagesApiSpec.cs +++ b/src/ImagesInfrastructure.IntegrationTests/ImagesApiSpec.cs @@ -47,7 +47,7 @@ public async Task WhenGetImage_ThenReturnsImage() Id = image.Id }, req => req.SetJWTBearerToken(login.AccessToken)); - result.Content.Value.Image!.ContentType.Should().Be(HttpConstants.ContentTypes.ImagePng); + result.Content.Value.Image.ContentType.Should().Be(HttpConstants.ContentTypes.ImagePng); result.Content.Value.Image.Description.Should().Be("adescription"); result.Content.Value.Image.Filename.Should().Be("afilename.png"); result.Content.Value.Image.Url.Should().Be($@"https://localhost:5001/images/{image.Id}/download"); @@ -98,7 +98,7 @@ public async Task WhenUpdateImage_ThenReturnsImage() Description = "anewdescription" }, req => req.SetJWTBearerToken(login.AccessToken)); - result.Content.Value.Image!.ContentType.Should().Be(HttpConstants.ContentTypes.ImagePng); + result.Content.Value.Image.ContentType.Should().Be(HttpConstants.ContentTypes.ImagePng); result.Content.Value.Image.Description.Should().Be("anewdescription"); result.Content.Value.Image.Filename.Should().Be("afilename.png"); result.Content.Value.Image.Url.Should().Be($"https://localhost:5001/images/{image.Id}/download"); @@ -112,7 +112,7 @@ private async Task UploadImage(LoginDetails login, string description) }, new PostFile(GetTestImage(), HttpConstants.ContentTypes.ImagePng, "afilename"), req => req.SetJWTBearerToken(login.AccessToken)); - return result.Content.Value.Image!; + return result.Content.Value.Image; } private static void OverrideDependencies(IServiceCollection services) diff --git a/src/Infrastructure.Shared.UnitTests/ApplicationServices/External/MailgunClientSpec.cs b/src/Infrastructure.Shared.UnitTests/ApplicationServices/External/MailgunClientSpec.cs index a3b3921c..fd3cc187 100644 --- a/src/Infrastructure.Shared.UnitTests/ApplicationServices/External/MailgunClientSpec.cs +++ b/src/Infrastructure.Shared.UnitTests/ApplicationServices/External/MailgunClientSpec.cs @@ -35,7 +35,8 @@ public async Task WhenSendAsync_ThenSends() It.IsAny>(), It.IsAny())) .ReturnsAsync(new MailgunSendMessageResponse { - Id = "areceiptid" + Id = "areceiptid", + Message = "amessage" }); var result = await _client.SendHtmlAsync(_call.Object, "asubject", "afromemailaddress", "afromdisplayname", diff --git a/src/Infrastructure.Shared/ApplicationServices/External/FlagsmithHttpServiceClient.TestingOnly.cs b/src/Infrastructure.Shared/ApplicationServices/External/FlagsmithHttpServiceClient.TestingOnly.cs index 6dccad17..e131d121 100644 --- a/src/Infrastructure.Shared/ApplicationServices/External/FlagsmithHttpServiceClient.TestingOnly.cs +++ b/src/Infrastructure.Shared/ApplicationServices/External/FlagsmithHttpServiceClient.TestingOnly.cs @@ -66,7 +66,7 @@ await _testingOnlyClient.PostAsync(null, new FlagsmithCreateEdgeIdentityFeatureStateRequest { EnvironmentApiKey = _testingConfiguration.EnvironmentApiKey, - IdentityUuid = identityCreated.Value.IdentityUuid!, + IdentityUuid = identityCreated.Value.IdentityUuid, Feature = featureId, Enabled = enabled }, req => AddApiToken(req, _testingConfiguration)); @@ -97,7 +97,7 @@ public async Task DestroyAllIdentitiesAsync() var allIdentities = identitiesRetrieved.Value.Results; foreach (var identity in allIdentities) { - await DestroyIdentityAsync(identity.IdentityUuid!); + await DestroyIdentityAsync(identity.IdentityUuid); } } diff --git a/src/Infrastructure.Shared/ApplicationServices/External/GenericOAuth2HttpServiceClient.cs b/src/Infrastructure.Shared/ApplicationServices/External/GenericOAuth2HttpServiceClient.cs index 3666ea4d..13eb20f8 100644 --- a/src/Infrastructure.Shared/ApplicationServices/External/GenericOAuth2HttpServiceClient.cs +++ b/src/Infrastructure.Shared/ApplicationServices/External/GenericOAuth2HttpServiceClient.cs @@ -100,7 +100,7 @@ public static List ToTokens(this GenericOAuth2GrantAuthorizationRespo var tokens = new List(); var now = DateTime.UtcNow.ToNearestSecond(); var expiresOn = now.Add(TimeSpan.FromSeconds(response.ExpiresIn)); - tokens.Add(new AuthToken(TokenType.AccessToken, response.AccessToken!, expiresOn)); + tokens.Add(new AuthToken(TokenType.AccessToken, response.AccessToken, expiresOn)); if (response.RefreshToken.HasValue()) { // Note: Refresh tokens are typically long-lived, like: for days or weeks @@ -114,7 +114,7 @@ public static List ToTokens(this GenericOAuth2GrantAuthorizationRespo // Note: ID tokens are typically very short-lived, like: less than an hour or so var defaultIdTokenExpiry = TimeSpan.FromHours(1); //default from Microsoft Identity var idTokenExpiresOn = now.Add(defaultIdTokenExpiry); - tokens.Add(new AuthToken(TokenType.OtherToken, response.IdToken!, idTokenExpiresOn)); + tokens.Add(new AuthToken(TokenType.OtherToken, response.IdToken, idTokenExpiresOn)); } return tokens; diff --git a/src/Infrastructure.Shared/ApplicationServices/External/MailgunHttpServiceClient.MailgunClient.cs b/src/Infrastructure.Shared/ApplicationServices/External/MailgunHttpServiceClient.MailgunClient.cs index 1479f139..78668a8c 100644 --- a/src/Infrastructure.Shared/ApplicationServices/External/MailgunHttpServiceClient.MailgunClient.cs +++ b/src/Infrastructure.Shared/ApplicationServices/External/MailgunHttpServiceClient.MailgunClient.cs @@ -125,7 +125,7 @@ public async Task> SendHtmlAsync(ICallContex return new EmailDeliveryReceipt { - ReceiptId = response.Value.Id ?? string.Empty.TrimStart('<').TrimEnd('>') + ReceiptId = ToReceiptId(response.Value.Id) }; } catch (HttpRequestException ex) @@ -180,7 +180,7 @@ public async Task> SendTemplatedAsync(ICallC return new EmailDeliveryReceipt { - ReceiptId = response.Value.Id ?? string.Empty.TrimStart('<').TrimEnd('>') + ReceiptId = ToReceiptId(response.Value.Id) }; } catch (HttpRequestException ex) @@ -191,6 +191,11 @@ public async Task> SendTemplatedAsync(ICallC } } + private string ToReceiptId(string id) + { + return id.TrimStart('<').TrimEnd('>'); + } + private static void PrepareRequest(HttpRequestMessage message, string apiKey) { message.Headers.Add(HttpConstants.Headers.Authorization, diff --git a/src/Infrastructure.Web.Api.IntegrationTests/ApiDocsSpec.cs b/src/Infrastructure.Web.Api.IntegrationTests/ApiDocsSpec.cs index 5865f025..ad96c64e 100644 --- a/src/Infrastructure.Web.Api.IntegrationTests/ApiDocsSpec.cs +++ b/src/Infrastructure.Web.Api.IntegrationTests/ApiDocsSpec.cs @@ -1,3 +1,4 @@ +using ApiHost1; using Common.Extensions; using FluentAssertions; using HtmlAgilityPack; @@ -46,9 +47,9 @@ private static void VerifyGeneralErrorResponses(OpenApiResponses responses, stri [Trait("Category", "Integration.API")] [Collection("API")] - public class GivenAnyRequest : WebApiSpec + public class GivenAnyRequest : WebApiSpec { - public GivenAnyRequest(WebApiSetup setup) : base(setup) + public GivenAnyRequest(WebApiSetup setup) : base(setup) { } @@ -83,9 +84,10 @@ public async Task WhenFetchOpenApi_ThenHasXmlSummary() .Read(await result.Content.ReadAsStreamAsync(), out _); var operation = openApi!.Paths["/testingonly/openapi/{Id}"].Operations[OperationType.Get]; - operation.Description.Should().Be("(request type: OpenApiGetTestingOnlyRequest)"); + operation.Description.Should().Be($"(request type: {nameof(OpenApiGetTestingOnlyRequest)})"); operation.OperationId.Should().Be("OpenApiGetTestingOnly"); - operation.Summary.Should().Be("Tests OpenAPI swagger for GET requests"); + operation.Summary.Should() + .Be("Tests OpenAPI swagger for GET requests This includes multiple lines explaining things"); } [Fact] @@ -97,15 +99,38 @@ public async Task WhenFetchOpenApi_ThenHasXmlSpecialResponses() .Read(await result.Content.ReadAsStreamAsync(), out _); var operation = openApi!.Paths["/testingonly/openapi/{Id}"].Operations[OperationType.Post]; - operation.Description.Should().Be("(request type: OpenApiPostTestingOnlyRequest)"); + operation.Description.Should().Be($"(request type: {nameof(OpenApiPostTestingOnlyRequest)})"); operation.OperationId.Should().Be("OpenApiPostTestingOnly"); operation.Summary.Should().Be("Tests OpenAPI swagger for POST requests"); - operation.Responses["409"].Description.Should().Be("a custom conflict response"); + operation.Responses["409"].Description.Should() + .Be("a custom conflict response which spills over to the next line"); operation.Responses["419"].Description.Should().Be("a special response"); } [Fact] - public async Task WhenFetchOpenApi_ThenAnonymousAuthorizationHasNoSecurityScheme() + public async Task WhenFetchOpenApi_ThenHasNullableResponseFields() + { + var result = await HttpApi.GetAsync(WebConstants.SwaggerEndpointFormat.Format("v1")); + + var openApi = new OpenApiStreamReader() + .Read(await result.Content.ReadAsStreamAsync(), out _); + + var operation = openApi!.Paths["/testingonly/openapi/{Id}"].Operations[OperationType.Get]; + operation.Description.Should().Be($"(request type: {nameof(OpenApiGetTestingOnlyRequest)})"); + operation.OperationId.Should().Be("OpenApiGetTestingOnly"); + + var responseType = openApi.Components.Schemas[nameof(OpenApiTestingOnlyResponse)]; + responseType.Properties["anAnnotatedRequiredField"].Nullable.Should().BeFalse(); + responseType.Properties["anInitializedField"].Nullable.Should().BeFalse(); + responseType.Properties["aNullableField"].Nullable.Should().BeTrue(); + responseType.Properties["aRequiredField"].Nullable.Should().BeFalse(); + responseType.Properties["aValueTypeField"].Nullable.Should().BeFalse(); + responseType.Properties["aNullableValueTypeField"].Nullable.Should().BeTrue(); + responseType.Properties["message"].Nullable.Should().BeFalse(); + } + + [Fact] + public async Task WhenFetchOpenApiForNonSecuredEndpoint_ThenAnonymousAuthorizationHasNoSecurityScheme() { var result = await HttpApi.GetAsync(WebConstants.SwaggerEndpointFormat.Format("v1")); @@ -113,13 +138,13 @@ public async Task WhenFetchOpenApi_ThenAnonymousAuthorizationHasNoSecurityScheme .Read(await result.Content.ReadAsStreamAsync(), out _); var operation = openApi!.Paths["/testingonly/security/none"].Operations[OperationType.Get]; - operation.Description.Should().Be("(request type: GetInsecureTestingOnlyRequest)"); + operation.Description.Should().Be($"(request type: {nameof(GetInsecureTestingOnlyRequest)})"); operation.OperationId.Should().Be("GetInsecureTestingOnly"); operation.Security.Should().HaveCount(0); } [Fact] - public async Task WhenFetchOpenApi_ThenTokenAuthorizationHasSecurityScheme() + public async Task WhenFetchOpenApiForTokenSecuredEndpoint_ThenTokenAuthorizationHasSecurityScheme() { var result = await HttpApi.GetAsync(WebConstants.SwaggerEndpointFormat.Format("v1")); @@ -127,7 +152,8 @@ public async Task WhenFetchOpenApi_ThenTokenAuthorizationHasSecurityScheme() .Read(await result.Content.ReadAsStreamAsync(), out _); var operation = openApi!.Paths["/testingonly/authn/token/get"].Operations[OperationType.Get]; - operation.Description.Should().Be("(request type: GetCallerWithTokenOrAPIKeyTestingOnlyRequest)"); + operation.Description.Should() + .Be($"(request type: {nameof(GetCallerWithTokenOrAPIKeyTestingOnlyRequest)})"); operation.OperationId.Should().Be("GetCallerWithTokenOrAPIKeyTestingOnly"); operation.Security.Should().HaveCount(2); operation.Security[0].Values.Count.Should().Be(1); @@ -140,7 +166,7 @@ public async Task WhenFetchOpenApi_ThenTokenAuthorizationHasSecurityScheme() } [Fact] - public async Task WhenFetchOpenApi_ThenHMACAuthorizationHasSecurityScheme() + public async Task WhenFetchOpenApiForSecureHMACEndpoint_ThenHMACAuthorizationHasSecurityScheme() { var result = await HttpApi.GetAsync(WebConstants.SwaggerEndpointFormat.Format("v1")); @@ -148,7 +174,7 @@ public async Task WhenFetchOpenApi_ThenHMACAuthorizationHasSecurityScheme() .Read(await result.Content.ReadAsStreamAsync(), out _); var operation = openApi!.Paths["/testingonly/authn/hmac/get"].Operations[OperationType.Get]; - operation.Description.Should().Be("(request type: GetCallerWithHMACTestingOnlyRequest)"); + operation.Description.Should().Be($"(request type: {nameof(GetCallerWithHMACTestingOnlyRequest)})"); operation.OperationId.Should().Be("GetCallerWithHMACTestingOnly"); operation.Security.Should().HaveCount(1); operation.Security[0].Values.Count.Should().Be(1); @@ -159,9 +185,9 @@ public async Task WhenFetchOpenApi_ThenHMACAuthorizationHasSecurityScheme() [Trait("Category", "Integration.API")] [Collection("API")] - public class GivenAGetRequest : WebApiSpec + public class GivenAGetRequest : WebApiSpec { - public GivenAGetRequest(WebApiSetup setup) : base(setup) + public GivenAGetRequest(WebApiSetup setup) : base(setup) { } @@ -174,7 +200,7 @@ public async Task WhenFetchOpenApi_ThenParametersHaveDescriptions() .Read(await result.Content.ReadAsStreamAsync(), out _); var operation = openApi!.Paths["/testingonly/openapi/{Id}"].Operations[OperationType.Get]; - operation.Description.Should().Be("(request type: OpenApiGetTestingOnlyRequest)"); + operation.Description.Should().Be($"(request type: {nameof(OpenApiGetTestingOnlyRequest)})"); operation.OperationId.Should().Be("OpenApiGetTestingOnly"); operation.Parameters.Should().HaveCount(3); operation.Parameters[0].Name.Should().Be("Id"); @@ -200,9 +226,9 @@ public async Task WhenFetchOpenApi_ThenResponseHas200Response() operation.Responses["200"].Description.Should().Be("OK"); operation.Responses["200"].Content.Count.Should().Be(2); operation.Responses["200"].Content[HttpConstants.ContentTypes.Json].Schema.Reference.ReferenceV3.Should() - .Be("#/components/schemas/StringMessageTestingOnlyResponse"); + .Be($"#/components/schemas/{nameof(OpenApiTestingOnlyResponse)}"); operation.Responses["200"].Content[HttpConstants.ContentTypes.Xml].Schema.Reference.ReferenceV3.Should() - .Be("#/components/schemas/StringMessageTestingOnlyResponse"); + .Be($"#/components/schemas/{nameof(OpenApiTestingOnlyResponse)}"); } [Fact] @@ -221,9 +247,9 @@ public async Task WhenFetchOpenApi_ThenResponseHasGeneralErrorResponses() [Trait("Category", "Integration.API")] [Collection("API")] - public class GivenAPostRequest : WebApiSpec + public class GivenAPostRequest : WebApiSpec { - public GivenAPostRequest(WebApiSetup setup) : base(setup) + public GivenAPostRequest(WebApiSetup setup) : base(setup) { } @@ -236,9 +262,9 @@ public async Task WhenFetchOpenApi_ThenFieldsHaveDescriptions() .Read(await result.Content.ReadAsStreamAsync(), out _); var operation = openApi!.Paths["/testingonly/openapi/{Id}"].Operations[OperationType.Post]; - operation.Description.Should().Be("(request type: OpenApiPostTestingOnlyRequest)"); + operation.Description.Should().Be($"(request type: {nameof(OpenApiPostTestingOnlyRequest)})"); operation.OperationId.Should().Be("OpenApiPostTestingOnly"); - var schema = openApi.Components.Schemas["OpenApiPostTestingOnlyRequest"]; + var schema = openApi.Components.Schemas[nameof(OpenApiPostTestingOnlyRequest)]; schema.Description.Should().BeNull(); schema.Required.Should().BeEquivalentTo("id", "requiredField"); schema.Properties.Should().HaveCount(2); @@ -259,9 +285,9 @@ public async Task WhenFetchOpenApi_ThenResponseHas201Response() operation.Responses["201"].Description.Should().Be("Created"); operation.Responses["201"].Content.Count.Should().Be(2); operation.Responses["201"].Content[HttpConstants.ContentTypes.Json].Schema.Reference.ReferenceV3.Should() - .Be("#/components/schemas/StringMessageTestingOnlyResponse"); + .Be($"#/components/schemas/{nameof(OpenApiTestingOnlyResponse)}"); operation.Responses["201"].Content[HttpConstants.ContentTypes.Xml].Schema.Reference.ReferenceV3.Should() - .Be("#/components/schemas/StringMessageTestingOnlyResponse"); + .Be($"#/components/schemas/{nameof(OpenApiTestingOnlyResponse)}"); } [Fact] @@ -280,9 +306,9 @@ public async Task WhenFetchOpenApi_ThenResponseHasGeneralErrorResponses() [Trait("Category", "Integration.API")] [Collection("API")] - public class GivenAPutRequest : WebApiSpec + public class GivenAPutRequest : WebApiSpec { - public GivenAPutRequest(WebApiSetup setup) : base(setup) + public GivenAPutRequest(WebApiSetup setup) : base(setup) { } @@ -295,9 +321,9 @@ public async Task WhenFetchOpenApi_ThenFieldsHaveDescriptions() .Read(await result.Content.ReadAsStreamAsync(), out _); var operation = openApi!.Paths["/testingonly/openapi/{Id}"].Operations[OperationType.Put]; - operation.Description.Should().Be("(request type: OpenApiPutTestingOnlyRequest)"); + operation.Description.Should().Be($"(request type: {nameof(OpenApiPutTestingOnlyRequest)})"); operation.OperationId.Should().Be("OpenApiPutTestingOnly (Put)"); - var schema = openApi.Components.Schemas["OpenApiPutTestingOnlyRequest"]; + var schema = openApi.Components.Schemas[nameof(OpenApiPutTestingOnlyRequest)]; schema.Description.Should().BeNull(); schema.Required.Should().BeEquivalentTo("id", "requiredField"); schema.Properties.Should().HaveCount(2); @@ -318,9 +344,9 @@ public async Task WhenFetchOpenApi_ThenResponseHas201Response() operation.Responses["202"].Description.Should().Be("Accepted"); operation.Responses["202"].Content.Count.Should().Be(2); operation.Responses["202"].Content[HttpConstants.ContentTypes.Json].Schema.Reference.ReferenceV3.Should() - .Be("#/components/schemas/StringMessageTestingOnlyResponse"); + .Be($"#/components/schemas/{nameof(OpenApiTestingOnlyResponse)}"); operation.Responses["202"].Content[HttpConstants.ContentTypes.Xml].Schema.Reference.ReferenceV3.Should() - .Be("#/components/schemas/StringMessageTestingOnlyResponse"); + .Be($"#/components/schemas/{nameof(OpenApiTestingOnlyResponse)}"); } [Fact] @@ -339,14 +365,14 @@ public async Task WhenFetchOpenApi_ThenResponseHasGeneralErrorResponses() [Trait("Category", "Integration.API")] [Collection("API")] - public class GivenAPostMultiPartFormRequest : WebApiSpec + public class GivenAPostMultiPartFormDataRequest : WebApiSpec { - public GivenAPostMultiPartFormRequest(WebApiSetup setup) : base(setup) + public GivenAPostMultiPartFormDataRequest(WebApiSetup setup) : base(setup) { } [Fact] - public async Task WhenFetchOpenApiForMultiPartForm_ThenFieldsHaveDescriptions() + public async Task WhenFetchOpenApiForMultiPartFormData_ThenFieldsHaveDescriptions() { var result = await HttpApi.GetAsync(WebConstants.SwaggerEndpointFormat.Format("v1")); @@ -374,7 +400,7 @@ public async Task WhenFetchOpenApiForMultiPartForm_ThenFieldsHaveDescriptions() } [Fact] - public async Task WhenFetchOpenApiForMultiPartForm_ThenResponseHas201Response() + public async Task WhenFetchOpenApiForMultiPartFormData_ThenResponseHas201Response() { var result = await HttpApi.GetAsync(WebConstants.SwaggerEndpointFormat.Format("v1")); @@ -385,13 +411,13 @@ public async Task WhenFetchOpenApiForMultiPartForm_ThenResponseHas201Response() operation.Responses["201"].Description.Should().Be("Created"); operation.Responses["201"].Content.Count.Should().Be(2); operation.Responses["201"].Content[HttpConstants.ContentTypes.Json].Schema.Reference.ReferenceV3.Should() - .Be("#/components/schemas/StringMessageTestingOnlyResponse"); + .Be($"#/components/schemas/{nameof(OpenApiTestingOnlyResponse)}"); operation.Responses["201"].Content[HttpConstants.ContentTypes.Xml].Schema.Reference.ReferenceV3.Should() - .Be("#/components/schemas/StringMessageTestingOnlyResponse"); + .Be($"#/components/schemas/{nameof(OpenApiTestingOnlyResponse)}"); } [Fact] - public async Task WhenFetchOpenApiForMultiPartForm_ThenResponseHasGeneralErrorResponses() + public async Task WhenFetchOpenApiForMultiPartFormData_ThenResponseHasGeneralErrorResponses() { var result = await HttpApi.GetAsync(WebConstants.SwaggerEndpointFormat.Format("v1")); @@ -402,6 +428,15 @@ public async Task WhenFetchOpenApiForMultiPartForm_ThenResponseHasGeneralErrorRe operation.Responses.Count.Should().Be(10); VerifyGeneralErrorResponses(operation.Responses); } + } + + [Trait("Category", "Integration.API")] + [Collection("API")] + public class GivenAPostFormUrlEncodingRequest : WebApiSpec + { + public GivenAPostFormUrlEncodingRequest(WebApiSetup setup) : base(setup) + { + } [Fact] public async Task WhenFetchOpenApiForFormUrlEncoded_ThenFieldsHaveDescriptions() @@ -441,9 +476,9 @@ public async Task WhenFetchOpenApiForFormUrlEncoded_ThenResponseHas201Response() operation.Responses["201"].Description.Should().Be("Created"); operation.Responses["201"].Content.Count.Should().Be(2); operation.Responses["201"].Content[HttpConstants.ContentTypes.Json].Schema.Reference.ReferenceV3.Should() - .Be("#/components/schemas/StringMessageTestingOnlyResponse"); + .Be($"#/components/schemas/{nameof(OpenApiTestingOnlyResponse)}"); operation.Responses["201"].Content[HttpConstants.ContentTypes.Xml].Schema.Reference.ReferenceV3.Should() - .Be("#/components/schemas/StringMessageTestingOnlyResponse"); + .Be($"#/components/schemas/{nameof(OpenApiTestingOnlyResponse)}"); } [Fact] diff --git a/src/Infrastructure.Web.Api.IntegrationTests/AuthNApiSpec.cs b/src/Infrastructure.Web.Api.IntegrationTests/AuthNApiSpec.cs index 143c9082..993632b7 100644 --- a/src/Infrastructure.Web.Api.IntegrationTests/AuthNApiSpec.cs +++ b/src/Infrastructure.Web.Api.IntegrationTests/AuthNApiSpec.cs @@ -107,7 +107,7 @@ public async Task WhenGetApiKeyRequestWithAPIKey_ThenReturnsSuccess() req => req.SetJWTBearerToken(login.AccessToken)); var result = await Api.GetAsync(new GetCallerWithTokenOrAPIKeyTestingOnlyRequest(), - req => req.SetAPIKey(apiKey.Content.Value.ApiKey!)); + req => req.SetAPIKey(apiKey.Content.Value.ApiKey)); result.StatusCode.Should().Be(HttpStatusCode.OK); result.Content.Value.CallerId.Should().Be(login.User.Id); diff --git a/src/Infrastructure.Web.Api.IntegrationTests/MultiTenancySpec.cs b/src/Infrastructure.Web.Api.IntegrationTests/MultiTenancySpec.cs index c9bec85d..1399978f 100644 --- a/src/Infrastructure.Web.Api.IntegrationTests/MultiTenancySpec.cs +++ b/src/Infrastructure.Web.Api.IntegrationTests/MultiTenancySpec.cs @@ -99,11 +99,11 @@ public async Task WhenCreateTenantedDataToPhysicalTenantStores_ThenReturnsTenant var organization1 = (await Api.GetAsync(new GetOrganizationRequest { Id = organization1Id - }, req => req.SetJWTBearerToken(loginA.AccessToken))).Content.Value.Organization!; + }, req => req.SetJWTBearerToken(loginA.AccessToken))).Content.Value.Organization; var organization2 = (await Api.PostAsync(new CreateOrganizationRequest { Name = "anorganizationname2" - }, req => req.SetJWTBearerToken(loginA.AccessToken))).Content.Value.Organization!; + }, req => req.SetJWTBearerToken(loginA.AccessToken))).Content.Value.Organization; loginA = await ReAuthenticateUserAsync(loginA); var car1Id = await CreateUnregisteredCarAsync(loginA, organization1, 2010); @@ -125,11 +125,11 @@ public async Task WhenCreateTenantedDataToPhysicalTenantStores_ThenReturnsTenant }, req => req.SetJWTBearerToken(loginA.AccessToken))).Content.Value.Cars; // Proves the Data was logically partitioned - cars1!.Count.Should().Be(3); + cars1.Count.Should().Be(3); cars1[0].Id.Should().Be(car1Id); cars1[1].Id.Should().Be(car3Id); cars1[2].Id.Should().Be(car5Id); - cars2!.Count.Should().Be(3); + cars2.Count.Should().Be(3); cars2[0].Id.Should().Be(car2Id); cars2[1].Id.Should().Be(car4Id); cars2[2].Id.Should().Be(car6Id); @@ -196,7 +196,7 @@ private async Task CreateUnregisteredCarAsync(LoginDetails login, Organi NumberPlate = "aplate" }, req => req.SetJWTBearerToken(login.AccessToken)); - return car.Content.Value.Car!.Id; + return car.Content.Value.Car.Id; } #if TESTINGONLY diff --git a/src/Infrastructure.Web.Api.Interfaces/IWebSearchResponse.cs b/src/Infrastructure.Web.Api.Interfaces/IWebSearchResponse.cs index 913422bd..eb2e9fa8 100644 --- a/src/Infrastructure.Web.Api.Interfaces/IWebSearchResponse.cs +++ b/src/Infrastructure.Web.Api.Interfaces/IWebSearchResponse.cs @@ -7,5 +7,5 @@ namespace Infrastructure.Web.Api.Interfaces; /// public interface IWebSearchResponse : IWebResponse { - SearchResultMetadata? Metadata { get; set; } + SearchResultMetadata Metadata { get; set; } } \ No newline at end of file diff --git a/src/Infrastructure.Web.Api.Interfaces/Resources.Designer.cs b/src/Infrastructure.Web.Api.Interfaces/Resources.Designer.cs index a8c95c60..79553415 100644 --- a/src/Infrastructure.Web.Api.Interfaces/Resources.Designer.cs +++ b/src/Infrastructure.Web.Api.Interfaces/Resources.Designer.cs @@ -159,7 +159,7 @@ internal static string HttpConstants_StatusCodes_Reason_OK { } /// - /// Looks up a localized string similar to The client must have payment information to get ther requested response. + /// Looks up a localized string similar to The client must have payment information to get the requested response. /// internal static string HttpConstants_StatusCodes_Reason_PaymentRequired { get { diff --git a/src/Infrastructure.Web.Api.Interfaces/Resources.resx b/src/Infrastructure.Web.Api.Interfaces/Resources.resx index a7a08a2b..8c4fa1a9 100644 --- a/src/Infrastructure.Web.Api.Interfaces/Resources.resx +++ b/src/Infrastructure.Web.Api.Interfaces/Resources.resx @@ -64,7 +64,7 @@ Payment Required - The client must have payment information to get ther requested response + The client must have payment information to get the requested response Forbidden diff --git a/src/Infrastructure.Web.Api.Interfaces/SearchResponse.cs b/src/Infrastructure.Web.Api.Interfaces/SearchResponse.cs index 3ce3a161..6e30bb3d 100644 --- a/src/Infrastructure.Web.Api.Interfaces/SearchResponse.cs +++ b/src/Infrastructure.Web.Api.Interfaces/SearchResponse.cs @@ -9,5 +9,5 @@ namespace Infrastructure.Web.Api.Interfaces; public abstract class SearchResponse : IWebSearchResponse { [Description("Metadata about the search results")] - public SearchResultMetadata? Metadata { get; set; } + public required SearchResultMetadata Metadata { get; set; } } \ No newline at end of file diff --git a/src/Infrastructure.Web.Api.Operations.Shared/3rdParties/Flagsmith/FlagsmithCreateEdgeIdentityResponse.cs b/src/Infrastructure.Web.Api.Operations.Shared/3rdParties/Flagsmith/FlagsmithCreateEdgeIdentityResponse.cs index 39b18dab..12a07786 100644 --- a/src/Infrastructure.Web.Api.Operations.Shared/3rdParties/Flagsmith/FlagsmithCreateEdgeIdentityResponse.cs +++ b/src/Infrastructure.Web.Api.Operations.Shared/3rdParties/Flagsmith/FlagsmithCreateEdgeIdentityResponse.cs @@ -5,7 +5,7 @@ namespace Infrastructure.Web.Api.Operations.Shared._3rdParties.Flagsmith; public class FlagsmithCreateEdgeIdentityResponse : IWebResponse { - [JsonPropertyName("identifier")] public string? Identifier { get; set; } + [JsonPropertyName("identifier")] public required string Identifier { get; set; } - [JsonPropertyName("identity_uuid")] public string? IdentityUuid { get; set; } + [JsonPropertyName("identity_uuid")] public required string IdentityUuid { get; set; } } \ No newline at end of file diff --git a/src/Infrastructure.Web.Api.Operations.Shared/3rdParties/Flagsmith/FlagsmithCreateFeatureResponse.cs b/src/Infrastructure.Web.Api.Operations.Shared/3rdParties/Flagsmith/FlagsmithCreateFeatureResponse.cs index 1fc5f73c..399f9801 100644 --- a/src/Infrastructure.Web.Api.Operations.Shared/3rdParties/Flagsmith/FlagsmithCreateFeatureResponse.cs +++ b/src/Infrastructure.Web.Api.Operations.Shared/3rdParties/Flagsmith/FlagsmithCreateFeatureResponse.cs @@ -7,7 +7,7 @@ public class FlagsmithCreateFeatureResponse : IWebResponse { [JsonPropertyName("id")] public int Id { get; set; } - [JsonPropertyName("name")] public string? Name { get; set; } + [JsonPropertyName("name")] public required string Name { get; set; } - [JsonPropertyName("type")] public string? Type { get; set; } + [JsonPropertyName("type")] public required string Type { get; set; } } \ No newline at end of file diff --git a/src/Infrastructure.Web.Api.Operations.Shared/3rdParties/Flagsmith/FlagsmithCreateIdentityRequest.cs b/src/Infrastructure.Web.Api.Operations.Shared/3rdParties/Flagsmith/FlagsmithCreateIdentityRequest.cs index b81a773d..a6c8694c 100644 --- a/src/Infrastructure.Web.Api.Operations.Shared/3rdParties/Flagsmith/FlagsmithCreateIdentityRequest.cs +++ b/src/Infrastructure.Web.Api.Operations.Shared/3rdParties/Flagsmith/FlagsmithCreateIdentityRequest.cs @@ -14,5 +14,5 @@ public class { [JsonPropertyName("identifier")] public string? Identifier { get; set; } - [JsonPropertyName("traits")] public List Traits { get; set; } = new(); + [JsonPropertyName("traits")] public List Traits { get; set; } = []; } \ No newline at end of file diff --git a/src/Infrastructure.Web.Api.Operations.Shared/3rdParties/Flagsmith/FlagsmithCreateIdentityResponse.cs b/src/Infrastructure.Web.Api.Operations.Shared/3rdParties/Flagsmith/FlagsmithCreateIdentityResponse.cs index 46dd39b9..b0f3f7b2 100644 --- a/src/Infrastructure.Web.Api.Operations.Shared/3rdParties/Flagsmith/FlagsmithCreateIdentityResponse.cs +++ b/src/Infrastructure.Web.Api.Operations.Shared/3rdParties/Flagsmith/FlagsmithCreateIdentityResponse.cs @@ -6,17 +6,17 @@ namespace Infrastructure.Web.Api.Operations.Shared._3rdParties.Flagsmith; public class FlagsmithCreateIdentityResponse : IWebResponse { - [JsonPropertyName("flags")] public List Flags { get; set; } = new(); + [JsonPropertyName("flags")] public List Flags { get; set; } = []; [JsonPropertyName("identifier")] public string? Identifier { get; set; } - [JsonPropertyName("traits")] public List Traits { get; set; } = new(); + [JsonPropertyName("traits")] public List Traits { get; set; } = []; } [UsedImplicitly] public class FlagsmithTrait { - [JsonPropertyName("trait_key")] public string? Key { get; set; } + [JsonPropertyName("trait_key")] public required string Key { get; set; } - [JsonPropertyName("trait_value")] public object? Value { get; set; } + [JsonPropertyName("trait_value")] public required object Value { get; set; } } \ No newline at end of file diff --git a/src/Infrastructure.Web.Api.Operations.Shared/3rdParties/Flagsmith/FlagsmithGetEdgeIdentitiesResponse.cs b/src/Infrastructure.Web.Api.Operations.Shared/3rdParties/Flagsmith/FlagsmithGetEdgeIdentitiesResponse.cs index 83d6cf62..4cac5280 100644 --- a/src/Infrastructure.Web.Api.Operations.Shared/3rdParties/Flagsmith/FlagsmithGetEdgeIdentitiesResponse.cs +++ b/src/Infrastructure.Web.Api.Operations.Shared/3rdParties/Flagsmith/FlagsmithGetEdgeIdentitiesResponse.cs @@ -6,13 +6,13 @@ namespace Infrastructure.Web.Api.Operations.Shared._3rdParties.Flagsmith; public class FlagsmithGetEdgeIdentitiesResponse : IWebResponse { - [JsonPropertyName("results")] public List Results { get; set; } = new(); + [JsonPropertyName("results")] public List Results { get; set; } = []; } [UsedImplicitly] public class FlagsmithEdgeIdentity { - [JsonPropertyName("identifier")] public string? Identifier { get; set; } + [JsonPropertyName("identifier")] public required string Identifier { get; set; } - [JsonPropertyName("identity_uuid")] public string? IdentityUuid { get; set; } + [JsonPropertyName("identity_uuid")] public required string IdentityUuid { get; set; } } \ No newline at end of file diff --git a/src/Infrastructure.Web.Api.Operations.Shared/3rdParties/Flagsmith/FlagsmithGetEnvironmentFlagsResponse.cs b/src/Infrastructure.Web.Api.Operations.Shared/3rdParties/Flagsmith/FlagsmithGetEnvironmentFlagsResponse.cs index 700db8d0..889dfb5b 100644 --- a/src/Infrastructure.Web.Api.Operations.Shared/3rdParties/Flagsmith/FlagsmithGetEnvironmentFlagsResponse.cs +++ b/src/Infrastructure.Web.Api.Operations.Shared/3rdParties/Flagsmith/FlagsmithGetEnvironmentFlagsResponse.cs @@ -1,10 +1,12 @@ using System.Text.Json.Serialization; using Infrastructure.Web.Api.Interfaces; +using JetBrains.Annotations; namespace Infrastructure.Web.Api.Operations.Shared._3rdParties.Flagsmith; public class FlagsmithGetEnvironmentFlagsResponse : List, IWebResponse { + [UsedImplicitly] public FlagsmithGetEnvironmentFlagsResponse() { } @@ -18,17 +20,17 @@ public class FlagsmithFlag { [JsonPropertyName("enabled")] public bool Enabled { get; set; } - [JsonPropertyName("feature")] public FlagsmithFeature? Feature { get; set; } + [JsonPropertyName("feature")] public required FlagsmithFeature Feature { get; set; } - [JsonPropertyName("id")] public int? Id { get; set; } + [JsonPropertyName("id")] public required int Id { get; set; } [JsonPropertyName("feature_state_value")] - public string? Value { get; set; } + public required string Value { get; set; } } public class FlagsmithFeature { [JsonPropertyName("id")] public int Id { get; set; } - [JsonPropertyName("name")] public string? Name { get; set; } + [JsonPropertyName("name")] public required string Name { get; set; } } \ No newline at end of file diff --git a/src/Infrastructure.Web.Api.Operations.Shared/3rdParties/Flagsmith/FlagsmithGetFeatureStatesResponse.cs b/src/Infrastructure.Web.Api.Operations.Shared/3rdParties/Flagsmith/FlagsmithGetFeatureStatesResponse.cs index 06f72fad..797be41e 100644 --- a/src/Infrastructure.Web.Api.Operations.Shared/3rdParties/Flagsmith/FlagsmithGetFeatureStatesResponse.cs +++ b/src/Infrastructure.Web.Api.Operations.Shared/3rdParties/Flagsmith/FlagsmithGetFeatureStatesResponse.cs @@ -8,7 +8,7 @@ public class FlagsmithGetFeatureStatesResponse : IWebResponse { [JsonPropertyName("results")] // ReSharper disable once CollectionNeverUpdated.Global - public List Results { get; set; } = new(); + public List Results { get; set; } = []; } [UsedImplicitly] diff --git a/src/Infrastructure.Web.Api.Operations.Shared/3rdParties/Flagsmith/FlagsmithGetFeaturesResponse.cs b/src/Infrastructure.Web.Api.Operations.Shared/3rdParties/Flagsmith/FlagsmithGetFeaturesResponse.cs index 7311102b..8d3f5995 100644 --- a/src/Infrastructure.Web.Api.Operations.Shared/3rdParties/Flagsmith/FlagsmithGetFeaturesResponse.cs +++ b/src/Infrastructure.Web.Api.Operations.Shared/3rdParties/Flagsmith/FlagsmithGetFeaturesResponse.cs @@ -5,5 +5,5 @@ namespace Infrastructure.Web.Api.Operations.Shared._3rdParties.Flagsmith; public class FlagsmithGetFeaturesResponse : IWebResponse { - [JsonPropertyName("results")] public List Results { get; set; } = new(); + [JsonPropertyName("results")] public List Results { get; set; } = []; } \ No newline at end of file diff --git a/src/Infrastructure.Web.Api.Operations.Shared/3rdParties/Mailgun/MailgunSendMessageResponse.cs b/src/Infrastructure.Web.Api.Operations.Shared/3rdParties/Mailgun/MailgunSendMessageResponse.cs index 41b8579a..48037be6 100644 --- a/src/Infrastructure.Web.Api.Operations.Shared/3rdParties/Mailgun/MailgunSendMessageResponse.cs +++ b/src/Infrastructure.Web.Api.Operations.Shared/3rdParties/Mailgun/MailgunSendMessageResponse.cs @@ -5,7 +5,7 @@ namespace Infrastructure.Web.Api.Operations.Shared._3rdParties.Mailgun; public class MailgunSendMessageResponse : IWebResponse { - [JsonPropertyName("id")] public string? Id { get; set; } + [JsonPropertyName("id")] public required string Id { get; set; } - [JsonPropertyName("message")] public string? Message { get; set; } + [JsonPropertyName("message")] public required string Message { get; set; } } \ No newline at end of file diff --git a/src/Infrastructure.Web.Api.Operations.Shared/3rdParties/OAuth2/GenericOAuth2GrantAuthorizationResponse.cs b/src/Infrastructure.Web.Api.Operations.Shared/3rdParties/OAuth2/GenericOAuth2GrantAuthorizationResponse.cs index d6bd636f..80d0e26b 100644 --- a/src/Infrastructure.Web.Api.Operations.Shared/3rdParties/OAuth2/GenericOAuth2GrantAuthorizationResponse.cs +++ b/src/Infrastructure.Web.Api.Operations.Shared/3rdParties/OAuth2/GenericOAuth2GrantAuthorizationResponse.cs @@ -5,7 +5,7 @@ namespace Infrastructure.Web.Api.Operations.Shared._3rdParties.OAuth2; public class GenericOAuth2GrantAuthorizationResponse : IWebResponse { - [JsonPropertyName("access_token")] public string? AccessToken { get; set; } + [JsonPropertyName("access_token")] public required string AccessToken { get; set; } [JsonPropertyName("expires_in")] public int ExpiresIn { get; set; } // seconds from now diff --git a/src/Infrastructure.Web.Api.Operations.Shared/3rdParties/Twilio/TwilioSendResponse.cs b/src/Infrastructure.Web.Api.Operations.Shared/3rdParties/Twilio/TwilioSendResponse.cs index 4f9e2bca..2d0b4db0 100644 --- a/src/Infrastructure.Web.Api.Operations.Shared/3rdParties/Twilio/TwilioSendResponse.cs +++ b/src/Infrastructure.Web.Api.Operations.Shared/3rdParties/Twilio/TwilioSendResponse.cs @@ -6,7 +6,7 @@ namespace Infrastructure.Web.Api.Operations.Shared._3rdParties.Twilio; public class TwilioSendResponse : IWebResponse { - [JsonPropertyName("body")] public string? Body { get; set; } + [JsonPropertyName("body")] public required string Body { get; set; } [JsonPropertyName("sid")] public string? Sid { get; set; } diff --git a/src/Infrastructure.Web.Api.Operations.Shared/Ancillary/GetAllFeatureFlagsResponse.cs b/src/Infrastructure.Web.Api.Operations.Shared/Ancillary/GetAllFeatureFlagsResponse.cs index e165cf82..d6ac0cb0 100644 --- a/src/Infrastructure.Web.Api.Operations.Shared/Ancillary/GetAllFeatureFlagsResponse.cs +++ b/src/Infrastructure.Web.Api.Operations.Shared/Ancillary/GetAllFeatureFlagsResponse.cs @@ -5,5 +5,5 @@ namespace Infrastructure.Web.Api.Operations.Shared.Ancillary; public class GetAllFeatureFlagsResponse : IWebResponse { - public List Flags { get; set; } = new(); + public List Flags { get; set; } = []; } \ No newline at end of file diff --git a/src/Infrastructure.Web.Api.Operations.Shared/Ancillary/GetFeatureFlagResponse.cs b/src/Infrastructure.Web.Api.Operations.Shared/Ancillary/GetFeatureFlagResponse.cs index 1df2a466..5f39a2f5 100644 --- a/src/Infrastructure.Web.Api.Operations.Shared/Ancillary/GetFeatureFlagResponse.cs +++ b/src/Infrastructure.Web.Api.Operations.Shared/Ancillary/GetFeatureFlagResponse.cs @@ -5,5 +5,5 @@ namespace Infrastructure.Web.Api.Operations.Shared.Ancillary; public class GetFeatureFlagResponse : IWebResponse { - public FeatureFlag? Flag { get; set; } + public required FeatureFlag Flag { get; set; } } \ No newline at end of file diff --git a/src/Infrastructure.Web.Api.Operations.Shared/Ancillary/SearchAllAuditsResponse.cs b/src/Infrastructure.Web.Api.Operations.Shared/Ancillary/SearchAllAuditsResponse.cs index a89b8c2d..6a444895 100644 --- a/src/Infrastructure.Web.Api.Operations.Shared/Ancillary/SearchAllAuditsResponse.cs +++ b/src/Infrastructure.Web.Api.Operations.Shared/Ancillary/SearchAllAuditsResponse.cs @@ -6,7 +6,7 @@ namespace Infrastructure.Web.Api.Operations.Shared.Ancillary { public class SearchAllAuditsResponse : SearchResponse { - public List? Audits { get; set; } + public List Audits { get; set; } = []; } } #endif \ No newline at end of file diff --git a/src/Infrastructure.Web.Api.Operations.Shared/Ancillary/SearchEmailDeliveriesResponse.cs b/src/Infrastructure.Web.Api.Operations.Shared/Ancillary/SearchEmailDeliveriesResponse.cs index 3e6f4b54..74bcae7d 100644 --- a/src/Infrastructure.Web.Api.Operations.Shared/Ancillary/SearchEmailDeliveriesResponse.cs +++ b/src/Infrastructure.Web.Api.Operations.Shared/Ancillary/SearchEmailDeliveriesResponse.cs @@ -5,5 +5,5 @@ namespace Infrastructure.Web.Api.Operations.Shared.Ancillary; public class SearchEmailDeliveriesResponse : SearchResponse { - public List? Emails { get; set; } + public List Emails { get; set; } = []; } \ No newline at end of file diff --git a/src/Infrastructure.Web.Api.Operations.Shared/Ancillary/SearchSmsDeliveriesResponse.cs b/src/Infrastructure.Web.Api.Operations.Shared/Ancillary/SearchSmsDeliveriesResponse.cs index 1890b935..0c9f3f49 100644 --- a/src/Infrastructure.Web.Api.Operations.Shared/Ancillary/SearchSmsDeliveriesResponse.cs +++ b/src/Infrastructure.Web.Api.Operations.Shared/Ancillary/SearchSmsDeliveriesResponse.cs @@ -5,5 +5,5 @@ namespace Infrastructure.Web.Api.Operations.Shared.Ancillary; public class SearchSmsDeliveriesResponse : SearchResponse { - public List? Smses { get; set; } + public List Smses { get; set; } = []; } \ No newline at end of file diff --git a/src/Infrastructure.Web.Api.Operations.Shared/BackEndForFrontEnd/AuthenticateResponse.cs b/src/Infrastructure.Web.Api.Operations.Shared/BackEndForFrontEnd/AuthenticateResponse.cs index c80bb77d..a8d3f2dc 100644 --- a/src/Infrastructure.Web.Api.Operations.Shared/BackEndForFrontEnd/AuthenticateResponse.cs +++ b/src/Infrastructure.Web.Api.Operations.Shared/BackEndForFrontEnd/AuthenticateResponse.cs @@ -4,5 +4,5 @@ namespace Infrastructure.Web.Api.Operations.Shared.BackEndForFrontEnd; public class AuthenticateResponse : IWebResponse { - public string? UserId { get; set; } + public required string UserId { get; set; } } \ No newline at end of file diff --git a/src/Infrastructure.Web.Api.Operations.Shared/BackEndForFrontEnd/GetAllFeatureFlagsResponse.cs b/src/Infrastructure.Web.Api.Operations.Shared/BackEndForFrontEnd/GetAllFeatureFlagsResponse.cs index c858bd32..67b38c8b 100644 --- a/src/Infrastructure.Web.Api.Operations.Shared/BackEndForFrontEnd/GetAllFeatureFlagsResponse.cs +++ b/src/Infrastructure.Web.Api.Operations.Shared/BackEndForFrontEnd/GetAllFeatureFlagsResponse.cs @@ -5,5 +5,5 @@ namespace Infrastructure.Web.Api.Operations.Shared.BackEndForFrontEnd; public class GetAllFeatureFlagsResponse : IWebResponse { - public List Flags { get; set; } = new(); + public List Flags { get; set; } = []; } \ No newline at end of file diff --git a/src/Infrastructure.Web.Api.Operations.Shared/BackEndForFrontEnd/GetFeatureFlagResponse.cs b/src/Infrastructure.Web.Api.Operations.Shared/BackEndForFrontEnd/GetFeatureFlagResponse.cs index 4f474815..05d4d9c9 100644 --- a/src/Infrastructure.Web.Api.Operations.Shared/BackEndForFrontEnd/GetFeatureFlagResponse.cs +++ b/src/Infrastructure.Web.Api.Operations.Shared/BackEndForFrontEnd/GetFeatureFlagResponse.cs @@ -5,5 +5,5 @@ namespace Infrastructure.Web.Api.Operations.Shared.BackEndForFrontEnd; public class GetFeatureFlagResponse : IWebResponse { - public FeatureFlag? Flag { get; set; } + public required FeatureFlag Flag { get; set; } } \ No newline at end of file diff --git a/src/Infrastructure.Web.Api.Operations.Shared/Bookings/MakeBookingResponse.cs b/src/Infrastructure.Web.Api.Operations.Shared/Bookings/MakeBookingResponse.cs index 7303f7da..cd54dd25 100644 --- a/src/Infrastructure.Web.Api.Operations.Shared/Bookings/MakeBookingResponse.cs +++ b/src/Infrastructure.Web.Api.Operations.Shared/Bookings/MakeBookingResponse.cs @@ -5,5 +5,5 @@ namespace Infrastructure.Web.Api.Operations.Shared.Bookings; public class MakeBookingResponse : IWebResponse { - public Booking? Booking { get; set; } + public required Booking Booking { get; set; } } \ No newline at end of file diff --git a/src/Infrastructure.Web.Api.Operations.Shared/Bookings/SearchAllBookingsResponse.cs b/src/Infrastructure.Web.Api.Operations.Shared/Bookings/SearchAllBookingsResponse.cs index 5f5c624f..a980f695 100644 --- a/src/Infrastructure.Web.Api.Operations.Shared/Bookings/SearchAllBookingsResponse.cs +++ b/src/Infrastructure.Web.Api.Operations.Shared/Bookings/SearchAllBookingsResponse.cs @@ -5,5 +5,5 @@ namespace Infrastructure.Web.Api.Operations.Shared.Bookings; public class SearchAllBookingsResponse : SearchResponse { - public List? Bookings { get; set; } + public List Bookings { get; set; } = []; } \ No newline at end of file diff --git a/src/Infrastructure.Web.Api.Operations.Shared/Cars/GetCarResponse.cs b/src/Infrastructure.Web.Api.Operations.Shared/Cars/GetCarResponse.cs index 15a96568..d332d169 100644 --- a/src/Infrastructure.Web.Api.Operations.Shared/Cars/GetCarResponse.cs +++ b/src/Infrastructure.Web.Api.Operations.Shared/Cars/GetCarResponse.cs @@ -5,5 +5,5 @@ namespace Infrastructure.Web.Api.Operations.Shared.Cars; public class GetCarResponse : IWebResponse { - public Car? Car { get; set; } + public required Car Car { get; set; } } \ No newline at end of file diff --git a/src/Infrastructure.Web.Api.Operations.Shared/Cars/SearchAllCarUnavailabilitiesResponse.cs b/src/Infrastructure.Web.Api.Operations.Shared/Cars/SearchAllCarUnavailabilitiesResponse.cs index 09c34251..6052ef19 100644 --- a/src/Infrastructure.Web.Api.Operations.Shared/Cars/SearchAllCarUnavailabilitiesResponse.cs +++ b/src/Infrastructure.Web.Api.Operations.Shared/Cars/SearchAllCarUnavailabilitiesResponse.cs @@ -6,6 +6,6 @@ namespace Infrastructure.Web.Api.Operations.Shared.Cars; public class SearchAllCarUnavailabilitiesResponse : SearchResponse { - public List? Unavailabilities { get; set; } + public List Unavailabilities { get; set; } = []; } #endif \ No newline at end of file diff --git a/src/Infrastructure.Web.Api.Operations.Shared/Cars/SearchAllCarsResponse.cs b/src/Infrastructure.Web.Api.Operations.Shared/Cars/SearchAllCarsResponse.cs index 145558b2..2675f0cd 100644 --- a/src/Infrastructure.Web.Api.Operations.Shared/Cars/SearchAllCarsResponse.cs +++ b/src/Infrastructure.Web.Api.Operations.Shared/Cars/SearchAllCarsResponse.cs @@ -5,5 +5,5 @@ namespace Infrastructure.Web.Api.Operations.Shared.Cars; public class SearchAllCarsResponse : SearchResponse { - public List? Cars { get; set; } + public List Cars { get; set; } = []; } \ No newline at end of file diff --git a/src/Infrastructure.Web.Api.Operations.Shared/EndUsers/GetUserResponse.cs b/src/Infrastructure.Web.Api.Operations.Shared/EndUsers/GetUserResponse.cs index c0e9f206..c7e3672d 100644 --- a/src/Infrastructure.Web.Api.Operations.Shared/EndUsers/GetUserResponse.cs +++ b/src/Infrastructure.Web.Api.Operations.Shared/EndUsers/GetUserResponse.cs @@ -6,6 +6,6 @@ namespace Infrastructure.Web.Api.Operations.Shared.EndUsers; public class GetUserResponse : IWebResponse { - public EndUserWithMemberships? User { get; set; } + public required EndUserWithMemberships User { get; set; } } #endif \ No newline at end of file diff --git a/src/Infrastructure.Web.Api.Operations.Shared/EndUsers/InviteGuestResponse.cs b/src/Infrastructure.Web.Api.Operations.Shared/EndUsers/InviteGuestResponse.cs index a6799c6c..59efc126 100644 --- a/src/Infrastructure.Web.Api.Operations.Shared/EndUsers/InviteGuestResponse.cs +++ b/src/Infrastructure.Web.Api.Operations.Shared/EndUsers/InviteGuestResponse.cs @@ -5,5 +5,5 @@ namespace Infrastructure.Web.Api.Operations.Shared.EndUsers; public class InviteGuestResponse : IWebResponse { - public Invitation? Invitation { get; set; } + public required Invitation Invitation { get; set; } } \ No newline at end of file diff --git a/src/Infrastructure.Web.Api.Operations.Shared/EndUsers/ListMembershipsForCallerResponse.cs b/src/Infrastructure.Web.Api.Operations.Shared/EndUsers/ListMembershipsForCallerResponse.cs index b1c2dc81..34343a04 100644 --- a/src/Infrastructure.Web.Api.Operations.Shared/EndUsers/ListMembershipsForCallerResponse.cs +++ b/src/Infrastructure.Web.Api.Operations.Shared/EndUsers/ListMembershipsForCallerResponse.cs @@ -5,5 +5,5 @@ namespace Infrastructure.Web.Api.Operations.Shared.EndUsers; public class ListMembershipsForCallerResponse : SearchResponse { - public List? Memberships { get; set; } + public List Memberships { get; set; } = []; } \ No newline at end of file diff --git a/src/Infrastructure.Web.Api.Operations.Shared/EndUsers/UpdateUserResponse.cs b/src/Infrastructure.Web.Api.Operations.Shared/EndUsers/UpdateUserResponse.cs index 43c76079..25114c7d 100644 --- a/src/Infrastructure.Web.Api.Operations.Shared/EndUsers/UpdateUserResponse.cs +++ b/src/Infrastructure.Web.Api.Operations.Shared/EndUsers/UpdateUserResponse.cs @@ -5,5 +5,5 @@ namespace Infrastructure.Web.Api.Operations.Shared.EndUsers; public class UpdateUserResponse : IWebResponse { - public EndUser? User { get; set; } + public required EndUser User { get; set; } } \ No newline at end of file diff --git a/src/Infrastructure.Web.Api.Operations.Shared/EndUsers/VerifyGuestInvitationResponse.cs b/src/Infrastructure.Web.Api.Operations.Shared/EndUsers/VerifyGuestInvitationResponse.cs index a5fb6d58..9c3e5c0f 100644 --- a/src/Infrastructure.Web.Api.Operations.Shared/EndUsers/VerifyGuestInvitationResponse.cs +++ b/src/Infrastructure.Web.Api.Operations.Shared/EndUsers/VerifyGuestInvitationResponse.cs @@ -5,5 +5,5 @@ namespace Infrastructure.Web.Api.Operations.Shared.EndUsers; public class VerifyGuestInvitationResponse : IWebResponse { - public Invitation? Invitation { get; set; } + public required Invitation Invitation { get; set; } } \ No newline at end of file diff --git a/src/Infrastructure.Web.Api.Operations.Shared/EventNotifications/SearchAllDomainEventsResponse.cs b/src/Infrastructure.Web.Api.Operations.Shared/EventNotifications/SearchAllDomainEventsResponse.cs index e8a45c62..7139b128 100644 --- a/src/Infrastructure.Web.Api.Operations.Shared/EventNotifications/SearchAllDomainEventsResponse.cs +++ b/src/Infrastructure.Web.Api.Operations.Shared/EventNotifications/SearchAllDomainEventsResponse.cs @@ -6,7 +6,7 @@ namespace Infrastructure.Web.Api.Operations.Shared.EventNotifications { public class SearchAllDomainEventsResponse : SearchResponse { - public List? Events { get; set; } + public List Events { get; set; } = []; } } #endif \ No newline at end of file diff --git a/src/Infrastructure.Web.Api.Operations.Shared/Health/HealthCheckResponse.cs b/src/Infrastructure.Web.Api.Operations.Shared/Health/HealthCheckResponse.cs index 9fb32233..6191145d 100644 --- a/src/Infrastructure.Web.Api.Operations.Shared/Health/HealthCheckResponse.cs +++ b/src/Infrastructure.Web.Api.Operations.Shared/Health/HealthCheckResponse.cs @@ -4,7 +4,7 @@ namespace Infrastructure.Web.Api.Operations.Shared.Health; public class HealthCheckResponse : IWebResponse { - public string? Name { get; set; } + public required string Name { get; set; } - public string? Status { get; set; } + public required string Status { get; set; } } \ No newline at end of file diff --git a/src/Infrastructure.Web.Api.Operations.Shared/Identities/AssociatePasswordMfaAuthenticatorForCallerRequest.cs b/src/Infrastructure.Web.Api.Operations.Shared/Identities/AssociatePasswordMfaAuthenticatorForCallerRequest.cs index d311afe6..215dab83 100644 --- a/src/Infrastructure.Web.Api.Operations.Shared/Identities/AssociatePasswordMfaAuthenticatorForCallerRequest.cs +++ b/src/Infrastructure.Web.Api.Operations.Shared/Identities/AssociatePasswordMfaAuthenticatorForCallerRequest.cs @@ -10,7 +10,7 @@ namespace Infrastructure.Web.Api.Operations.Shared.Identities; /// Depending on the specific authenticator, this can send an SMS or email to the user containing a secret code. /// /// -/// The user has already associated at least one other authenticator, or this authenticator is already associated +/// The user has already associated at least one other authenticator, or this authenticator is already associated. /// You must make a challenge using an existing association /// /// diff --git a/src/Infrastructure.Web.Api.Operations.Shared/Identities/AssociatePasswordMfaAuthenticatorForCallerResponse.cs b/src/Infrastructure.Web.Api.Operations.Shared/Identities/AssociatePasswordMfaAuthenticatorForCallerResponse.cs index 5686fe1f..ee21685d 100644 --- a/src/Infrastructure.Web.Api.Operations.Shared/Identities/AssociatePasswordMfaAuthenticatorForCallerResponse.cs +++ b/src/Infrastructure.Web.Api.Operations.Shared/Identities/AssociatePasswordMfaAuthenticatorForCallerResponse.cs @@ -5,5 +5,5 @@ namespace Infrastructure.Web.Api.Operations.Shared.Identities; public class AssociatePasswordMfaAuthenticatorForCallerResponse : IWebResponse { - public PasswordCredentialMfaAuthenticatorAssociation? Authenticator { get; set; } + public required PasswordCredentialMfaAuthenticatorAssociation Authenticator { get; set; } } \ No newline at end of file diff --git a/src/Infrastructure.Web.Api.Operations.Shared/Identities/AuthenticateResponse.cs b/src/Infrastructure.Web.Api.Operations.Shared/Identities/AuthenticateResponse.cs index 24152ebf..689a114b 100644 --- a/src/Infrastructure.Web.Api.Operations.Shared/Identities/AuthenticateResponse.cs +++ b/src/Infrastructure.Web.Api.Operations.Shared/Identities/AuthenticateResponse.cs @@ -5,5 +5,5 @@ namespace Infrastructure.Web.Api.Operations.Shared.Identities; public class AuthenticateResponse : IWebResponse { - public AuthenticateTokens? Tokens { get; set; } + public required AuthenticateTokens Tokens { get; set; } } \ No newline at end of file diff --git a/src/Infrastructure.Web.Api.Operations.Shared/Identities/ChallengePasswordMfaAuthenticatorForCallerResponse.cs b/src/Infrastructure.Web.Api.Operations.Shared/Identities/ChallengePasswordMfaAuthenticatorForCallerResponse.cs index 3e62cd5b..0b66790e 100644 --- a/src/Infrastructure.Web.Api.Operations.Shared/Identities/ChallengePasswordMfaAuthenticatorForCallerResponse.cs +++ b/src/Infrastructure.Web.Api.Operations.Shared/Identities/ChallengePasswordMfaAuthenticatorForCallerResponse.cs @@ -5,5 +5,5 @@ namespace Infrastructure.Web.Api.Operations.Shared.Identities; public class ChallengePasswordMfaAuthenticatorForCallerResponse : IWebResponse { - public PasswordCredentialMfaAuthenticatorChallenge? Challenge { get; set; } + public required PasswordCredentialMfaAuthenticatorChallenge Challenge { get; set; } } \ No newline at end of file diff --git a/src/Infrastructure.Web.Api.Operations.Shared/Identities/ChangePasswordMfaResponse.cs b/src/Infrastructure.Web.Api.Operations.Shared/Identities/ChangePasswordMfaResponse.cs index 13be37cc..5373bea8 100644 --- a/src/Infrastructure.Web.Api.Operations.Shared/Identities/ChangePasswordMfaResponse.cs +++ b/src/Infrastructure.Web.Api.Operations.Shared/Identities/ChangePasswordMfaResponse.cs @@ -5,5 +5,5 @@ namespace Infrastructure.Web.Api.Operations.Shared.Identities; public class ChangePasswordMfaResponse : IWebResponse { - public PasswordCredential? Credential { get; set; } + public required PasswordCredential Credential { get; set; } } \ No newline at end of file diff --git a/src/Infrastructure.Web.Api.Operations.Shared/Identities/CreateAPIKeyResponse.cs b/src/Infrastructure.Web.Api.Operations.Shared/Identities/CreateAPIKeyResponse.cs index bbdd5f44..bab9e544 100644 --- a/src/Infrastructure.Web.Api.Operations.Shared/Identities/CreateAPIKeyResponse.cs +++ b/src/Infrastructure.Web.Api.Operations.Shared/Identities/CreateAPIKeyResponse.cs @@ -5,6 +5,6 @@ namespace Infrastructure.Web.Api.Operations.Shared.Identities; public class CreateAPIKeyResponse : IWebResponse { - public string? ApiKey { get; set; } + public required string ApiKey { get; set; } } #endif \ No newline at end of file diff --git a/src/Infrastructure.Web.Api.Operations.Shared/Identities/GetIdentityResponse.cs b/src/Infrastructure.Web.Api.Operations.Shared/Identities/GetIdentityResponse.cs index 4cab38fe..c7285dbf 100644 --- a/src/Infrastructure.Web.Api.Operations.Shared/Identities/GetIdentityResponse.cs +++ b/src/Infrastructure.Web.Api.Operations.Shared/Identities/GetIdentityResponse.cs @@ -5,5 +5,5 @@ namespace Infrastructure.Web.Api.Operations.Shared.Identities; public class GetIdentityResponse : IWebResponse { - public Identity? Identity { get; set; } + public required Identity Identity { get; set; } } \ No newline at end of file diff --git a/src/Infrastructure.Web.Api.Operations.Shared/Identities/GetRegistrationPersonConfirmationResponse.cs b/src/Infrastructure.Web.Api.Operations.Shared/Identities/GetRegistrationPersonConfirmationResponse.cs index 0f714e88..eb590c70 100644 --- a/src/Infrastructure.Web.Api.Operations.Shared/Identities/GetRegistrationPersonConfirmationResponse.cs +++ b/src/Infrastructure.Web.Api.Operations.Shared/Identities/GetRegistrationPersonConfirmationResponse.cs @@ -5,6 +5,6 @@ namespace Infrastructure.Web.Api.Operations.Shared.Identities; public class GetRegistrationPersonConfirmationResponse : IWebResponse { - public string? Token { get; set; } + public required string Token { get; set; } } #endif \ No newline at end of file diff --git a/src/Infrastructure.Web.Api.Operations.Shared/Identities/ListPasswordMfaAuthenticatorsForCallerResponse.cs b/src/Infrastructure.Web.Api.Operations.Shared/Identities/ListPasswordMfaAuthenticatorsForCallerResponse.cs index 643b60da..95be7238 100644 --- a/src/Infrastructure.Web.Api.Operations.Shared/Identities/ListPasswordMfaAuthenticatorsForCallerResponse.cs +++ b/src/Infrastructure.Web.Api.Operations.Shared/Identities/ListPasswordMfaAuthenticatorsForCallerResponse.cs @@ -5,5 +5,5 @@ namespace Infrastructure.Web.Api.Operations.Shared.Identities; public class ListPasswordMfaAuthenticatorsForCallerResponse : IWebResponse { - public List? Authenticators { get; set; } + public List Authenticators { get; set; } = []; } \ No newline at end of file diff --git a/src/Infrastructure.Web.Api.Operations.Shared/Identities/RefreshTokenResponse.cs b/src/Infrastructure.Web.Api.Operations.Shared/Identities/RefreshTokenResponse.cs index c295b1bc..fe58261a 100644 --- a/src/Infrastructure.Web.Api.Operations.Shared/Identities/RefreshTokenResponse.cs +++ b/src/Infrastructure.Web.Api.Operations.Shared/Identities/RefreshTokenResponse.cs @@ -5,5 +5,5 @@ namespace Infrastructure.Web.Api.Operations.Shared.Identities; public class RefreshTokenResponse : IWebResponse { - public AuthenticateTokens? Tokens { get; set; } + public required AuthenticateTokens Tokens { get; set; } } \ No newline at end of file diff --git a/src/Infrastructure.Web.Api.Operations.Shared/Identities/RegisterMachineResponse.cs b/src/Infrastructure.Web.Api.Operations.Shared/Identities/RegisterMachineResponse.cs index 3036aa5f..7fdc6ed3 100644 --- a/src/Infrastructure.Web.Api.Operations.Shared/Identities/RegisterMachineResponse.cs +++ b/src/Infrastructure.Web.Api.Operations.Shared/Identities/RegisterMachineResponse.cs @@ -5,5 +5,5 @@ namespace Infrastructure.Web.Api.Operations.Shared.Identities; public class RegisterMachineResponse : IWebResponse { - public MachineCredential? Machine { get; set; } + public required MachineCredential Machine { get; set; } } \ No newline at end of file diff --git a/src/Infrastructure.Web.Api.Operations.Shared/Identities/RegisterPersonPasswordResponse.cs b/src/Infrastructure.Web.Api.Operations.Shared/Identities/RegisterPersonPasswordResponse.cs index a74ff113..63f598ab 100644 --- a/src/Infrastructure.Web.Api.Operations.Shared/Identities/RegisterPersonPasswordResponse.cs +++ b/src/Infrastructure.Web.Api.Operations.Shared/Identities/RegisterPersonPasswordResponse.cs @@ -5,5 +5,5 @@ namespace Infrastructure.Web.Api.Operations.Shared.Identities; public class RegisterPersonPasswordResponse : IWebResponse { - public PasswordCredential? Credential { get; set; } + public required PasswordCredential Credential { get; set; } } \ No newline at end of file diff --git a/src/Infrastructure.Web.Api.Operations.Shared/Identities/SearchAllAPIKeysResponse.cs b/src/Infrastructure.Web.Api.Operations.Shared/Identities/SearchAllAPIKeysResponse.cs index e762d6ac..ab69db8b 100644 --- a/src/Infrastructure.Web.Api.Operations.Shared/Identities/SearchAllAPIKeysResponse.cs +++ b/src/Infrastructure.Web.Api.Operations.Shared/Identities/SearchAllAPIKeysResponse.cs @@ -5,5 +5,5 @@ namespace Infrastructure.Web.Api.Operations.Shared.Identities; public class SearchAllAPIKeysResponse : SearchResponse { - public List? Keys { get; set; } + public List Keys { get; set; } = []; } \ No newline at end of file diff --git a/src/Infrastructure.Web.Api.Operations.Shared/Images/GetImageResponse.cs b/src/Infrastructure.Web.Api.Operations.Shared/Images/GetImageResponse.cs index 8e77e53f..5f96bfc5 100644 --- a/src/Infrastructure.Web.Api.Operations.Shared/Images/GetImageResponse.cs +++ b/src/Infrastructure.Web.Api.Operations.Shared/Images/GetImageResponse.cs @@ -5,5 +5,5 @@ namespace Infrastructure.Web.Api.Operations.Shared.Images; public class GetImageResponse : IWebResponse { - public Image? Image { get; set; } + public required Image Image { get; set; } } \ No newline at end of file diff --git a/src/Infrastructure.Web.Api.Operations.Shared/Images/UpdateImageResponse.cs b/src/Infrastructure.Web.Api.Operations.Shared/Images/UpdateImageResponse.cs index 9e5b477d..9b346051 100644 --- a/src/Infrastructure.Web.Api.Operations.Shared/Images/UpdateImageResponse.cs +++ b/src/Infrastructure.Web.Api.Operations.Shared/Images/UpdateImageResponse.cs @@ -5,5 +5,5 @@ namespace Infrastructure.Web.Api.Operations.Shared.Images; public class UpdateImageResponse : IWebResponse { - public Image? Image { get; set; } + public required Image Image { get; set; } } \ No newline at end of file diff --git a/src/Infrastructure.Web.Api.Operations.Shared/Images/UploadImageResponse.cs b/src/Infrastructure.Web.Api.Operations.Shared/Images/UploadImageResponse.cs index fc723fd4..de59ed56 100644 --- a/src/Infrastructure.Web.Api.Operations.Shared/Images/UploadImageResponse.cs +++ b/src/Infrastructure.Web.Api.Operations.Shared/Images/UploadImageResponse.cs @@ -5,5 +5,5 @@ namespace Infrastructure.Web.Api.Operations.Shared.Images; public class UploadImageResponse : IWebResponse { - public Image? Image { get; set; } + public required Image Image { get; set; } } \ No newline at end of file diff --git a/src/Infrastructure.Web.Api.Operations.Shared/Organizations/GetOrganizationResponse.cs b/src/Infrastructure.Web.Api.Operations.Shared/Organizations/GetOrganizationResponse.cs index 780dca9e..0129bdec 100644 --- a/src/Infrastructure.Web.Api.Operations.Shared/Organizations/GetOrganizationResponse.cs +++ b/src/Infrastructure.Web.Api.Operations.Shared/Organizations/GetOrganizationResponse.cs @@ -5,5 +5,5 @@ namespace Infrastructure.Web.Api.Operations.Shared.Organizations; public class GetOrganizationResponse : IWebResponse { - public Organization? Organization { get; set; } + public required Organization Organization { get; set; } } \ No newline at end of file diff --git a/src/Infrastructure.Web.Api.Operations.Shared/Organizations/GetOrganizationSettingsResponse.cs b/src/Infrastructure.Web.Api.Operations.Shared/Organizations/GetOrganizationSettingsResponse.cs index 1b5e944a..5f72774e 100644 --- a/src/Infrastructure.Web.Api.Operations.Shared/Organizations/GetOrganizationSettingsResponse.cs +++ b/src/Infrastructure.Web.Api.Operations.Shared/Organizations/GetOrganizationSettingsResponse.cs @@ -5,7 +5,7 @@ namespace Infrastructure.Web.Api.Operations.Shared.Organizations; public class GetOrganizationSettingsResponse : IWebResponse { - public Organization? Organization { get; set; } + public required Organization Organization { get; set; } - public Dictionary? Settings { get; set; } + public Dictionary Settings { get; set; } = new(); } \ No newline at end of file diff --git a/src/Infrastructure.Web.Api.Operations.Shared/Organizations/InviteMemberToOrganizationResponse.cs b/src/Infrastructure.Web.Api.Operations.Shared/Organizations/InviteMemberToOrganizationResponse.cs index a151898d..05f13a2a 100644 --- a/src/Infrastructure.Web.Api.Operations.Shared/Organizations/InviteMemberToOrganizationResponse.cs +++ b/src/Infrastructure.Web.Api.Operations.Shared/Organizations/InviteMemberToOrganizationResponse.cs @@ -5,5 +5,5 @@ namespace Infrastructure.Web.Api.Operations.Shared.Organizations; public class InviteMemberToOrganizationResponse : IWebResponse { - public Organization? Organization { get; set; } + public required Organization Organization { get; set; } } \ No newline at end of file diff --git a/src/Infrastructure.Web.Api.Operations.Shared/Organizations/ListMembersForOrganizationResponse.cs b/src/Infrastructure.Web.Api.Operations.Shared/Organizations/ListMembersForOrganizationResponse.cs index 801c6eeb..df10421a 100644 --- a/src/Infrastructure.Web.Api.Operations.Shared/Organizations/ListMembersForOrganizationResponse.cs +++ b/src/Infrastructure.Web.Api.Operations.Shared/Organizations/ListMembersForOrganizationResponse.cs @@ -5,5 +5,5 @@ namespace Infrastructure.Web.Api.Operations.Shared.Organizations; public class ListMembersForOrganizationResponse : SearchResponse { - public List? Members { get; set; } + public List Members { get; set; } = []; } \ No newline at end of file diff --git a/src/Infrastructure.Web.Api.Operations.Shared/Organizations/UnInviteMemberFromOrganizationResponse.cs b/src/Infrastructure.Web.Api.Operations.Shared/Organizations/UnInviteMemberFromOrganizationResponse.cs index fa39c809..1deab328 100644 --- a/src/Infrastructure.Web.Api.Operations.Shared/Organizations/UnInviteMemberFromOrganizationResponse.cs +++ b/src/Infrastructure.Web.Api.Operations.Shared/Organizations/UnInviteMemberFromOrganizationResponse.cs @@ -5,5 +5,5 @@ namespace Infrastructure.Web.Api.Operations.Shared.Organizations; public class UnInviteMemberFromOrganizationResponse : IWebResponse { - public Organization? Organization { get; set; } + public required Organization Organization { get; set; } } \ No newline at end of file diff --git a/src/Infrastructure.Web.Api.Operations.Shared/Subscriptions/ExportSubscriptionsToMigrateResponse.cs b/src/Infrastructure.Web.Api.Operations.Shared/Subscriptions/ExportSubscriptionsToMigrateResponse.cs index 35972f62..6e4128ee 100644 --- a/src/Infrastructure.Web.Api.Operations.Shared/Subscriptions/ExportSubscriptionsToMigrateResponse.cs +++ b/src/Infrastructure.Web.Api.Operations.Shared/Subscriptions/ExportSubscriptionsToMigrateResponse.cs @@ -5,5 +5,5 @@ namespace Infrastructure.Web.Api.Operations.Shared.Subscriptions; public class ExportSubscriptionsToMigrateResponse : SearchResponse { - public List? Subscriptions { get; set; } + public List Subscriptions { get; set; } = []; } \ No newline at end of file diff --git a/src/Infrastructure.Web.Api.Operations.Shared/Subscriptions/GetSubscriptionResponse.cs b/src/Infrastructure.Web.Api.Operations.Shared/Subscriptions/GetSubscriptionResponse.cs index 6004b066..288afbba 100644 --- a/src/Infrastructure.Web.Api.Operations.Shared/Subscriptions/GetSubscriptionResponse.cs +++ b/src/Infrastructure.Web.Api.Operations.Shared/Subscriptions/GetSubscriptionResponse.cs @@ -5,5 +5,5 @@ namespace Infrastructure.Web.Api.Operations.Shared.Subscriptions; public class GetSubscriptionResponse : IWebResponse { - public SubscriptionWithPlan? Subscription { get; set; } + public required SubscriptionWithPlan Subscription { get; set; } } \ No newline at end of file diff --git a/src/Infrastructure.Web.Api.Operations.Shared/Subscriptions/ListPricingPlansResponse.cs b/src/Infrastructure.Web.Api.Operations.Shared/Subscriptions/ListPricingPlansResponse.cs index b08fc4c0..86251a03 100644 --- a/src/Infrastructure.Web.Api.Operations.Shared/Subscriptions/ListPricingPlansResponse.cs +++ b/src/Infrastructure.Web.Api.Operations.Shared/Subscriptions/ListPricingPlansResponse.cs @@ -5,5 +5,5 @@ namespace Infrastructure.Web.Api.Operations.Shared.Subscriptions; public class ListPricingPlansResponse : IWebResponse { - public PricingPlans? Plans { get; set; } + public required PricingPlans Plans { get; set; } } \ No newline at end of file diff --git a/src/Infrastructure.Web.Api.Operations.Shared/Subscriptions/MigrateSubscriptionResponse.cs b/src/Infrastructure.Web.Api.Operations.Shared/Subscriptions/MigrateSubscriptionResponse.cs index 998b9fa1..cf829473 100644 --- a/src/Infrastructure.Web.Api.Operations.Shared/Subscriptions/MigrateSubscriptionResponse.cs +++ b/src/Infrastructure.Web.Api.Operations.Shared/Subscriptions/MigrateSubscriptionResponse.cs @@ -5,5 +5,5 @@ namespace Infrastructure.Web.Api.Operations.Shared.Subscriptions; public class MigrateSubscriptionResponse : IWebResponse { - public Subscription? Subscription { get; set; } + public required Subscription Subscription { get; set; } } \ No newline at end of file diff --git a/src/Infrastructure.Web.Api.Operations.Shared/Subscriptions/SearchSubscriptionHistoryResponse.cs b/src/Infrastructure.Web.Api.Operations.Shared/Subscriptions/SearchSubscriptionHistoryResponse.cs index 791df3fc..c215a863 100644 --- a/src/Infrastructure.Web.Api.Operations.Shared/Subscriptions/SearchSubscriptionHistoryResponse.cs +++ b/src/Infrastructure.Web.Api.Operations.Shared/Subscriptions/SearchSubscriptionHistoryResponse.cs @@ -5,5 +5,5 @@ namespace Infrastructure.Web.Api.Operations.Shared.Subscriptions; public class SearchSubscriptionHistoryResponse : SearchResponse { - public List? Invoices { get; set; } + public List Invoices { get; set; } = []; } \ No newline at end of file diff --git a/src/Infrastructure.Web.Api.Operations.Shared/TestingOnly/FormatsTestingOnlyRequest.cs b/src/Infrastructure.Web.Api.Operations.Shared/TestingOnly/FormatsTestingOnlyRequest.cs index f0d8d7da..5f0c3057 100644 --- a/src/Infrastructure.Web.Api.Operations.Shared/TestingOnly/FormatsTestingOnlyRequest.cs +++ b/src/Infrastructure.Web.Api.Operations.Shared/TestingOnly/FormatsTestingOnlyRequest.cs @@ -39,6 +39,7 @@ public class CustomDto public enum CustomEnum { + None, One, TwentyOne, OneHundredAndOne diff --git a/src/Infrastructure.Web.Api.Operations.Shared/TestingOnly/GetCallerTestingOnlyResponse.cs b/src/Infrastructure.Web.Api.Operations.Shared/TestingOnly/GetCallerTestingOnlyResponse.cs index 079e7140..88d66739 100644 --- a/src/Infrastructure.Web.Api.Operations.Shared/TestingOnly/GetCallerTestingOnlyResponse.cs +++ b/src/Infrastructure.Web.Api.Operations.Shared/TestingOnly/GetCallerTestingOnlyResponse.cs @@ -5,6 +5,6 @@ namespace Infrastructure.Web.Api.Operations.Shared.TestingOnly; public class GetCallerTestingOnlyResponse : IWebResponse { - public string? CallerId { get; set; } + public required string CallerId { get; set; } } #endif \ No newline at end of file diff --git a/src/Infrastructure.Web.Api.Operations.Shared/TestingOnly/OpenApiGetTestingOnlyRequest.cs b/src/Infrastructure.Web.Api.Operations.Shared/TestingOnly/OpenApiGetTestingOnlyRequest.cs index ef98d7ef..94fcfd84 100644 --- a/src/Infrastructure.Web.Api.Operations.Shared/TestingOnly/OpenApiGetTestingOnlyRequest.cs +++ b/src/Infrastructure.Web.Api.Operations.Shared/TestingOnly/OpenApiGetTestingOnlyRequest.cs @@ -8,10 +8,14 @@ namespace Infrastructure.Web.Api.Operations.Shared.TestingOnly; /// /// Tests OpenAPI swagger for GET requests +/// This includes multiple lines explaining things /// +/// +/// This is some explanation +/// [Route("/testingonly/openapi/{Id}", OperationMethod.Get, isTestingOnly: true)] [UsedImplicitly] -public class OpenApiGetTestingOnlyRequest : WebRequest +public class OpenApiGetTestingOnlyRequest : WebRequest { [Description("anid")] public string? Id { get; set; } diff --git a/src/Infrastructure.Web.Api.Operations.Shared/TestingOnly/OpenApiPostFormUrlEncodedTestingOnlyRequest.cs b/src/Infrastructure.Web.Api.Operations.Shared/TestingOnly/OpenApiPostFormUrlEncodedTestingOnlyRequest.cs index bd678e6e..a6124a42 100644 --- a/src/Infrastructure.Web.Api.Operations.Shared/TestingOnly/OpenApiPostFormUrlEncodedTestingOnlyRequest.cs +++ b/src/Infrastructure.Web.Api.Operations.Shared/TestingOnly/OpenApiPostFormUrlEncodedTestingOnlyRequest.cs @@ -11,7 +11,7 @@ namespace Infrastructure.Web.Api.Operations.Shared.TestingOnly; [Route("/testingonly/openapi/{Id}/urlencoded", OperationMethod.Post, isTestingOnly: true)] [UsedImplicitly] public class OpenApiPostFormUrlEncodedTestingOnlyRequest : - WebRequest, + WebRequest, IHasFormUrlEncoded { public string? Id { get; set; } diff --git a/src/Infrastructure.Web.Api.Operations.Shared/TestingOnly/OpenApiPostMultiPartFormDataTestingOnlyRequest.cs b/src/Infrastructure.Web.Api.Operations.Shared/TestingOnly/OpenApiPostMultiPartFormDataTestingOnlyRequest.cs index 29d3bb4a..409d24e4 100644 --- a/src/Infrastructure.Web.Api.Operations.Shared/TestingOnly/OpenApiPostMultiPartFormDataTestingOnlyRequest.cs +++ b/src/Infrastructure.Web.Api.Operations.Shared/TestingOnly/OpenApiPostMultiPartFormDataTestingOnlyRequest.cs @@ -11,7 +11,7 @@ namespace Infrastructure.Web.Api.Operations.Shared.TestingOnly; [Route("/testingonly/openapi/{Id}/form-data", OperationMethod.Post, isTestingOnly: true)] [UsedImplicitly] public class OpenApiPostMultiPartFormDataTestingOnlyRequest : - WebRequest, + WebRequest, IHasMultipartFormData { public string? Id { get; set; } diff --git a/src/Infrastructure.Web.Api.Operations.Shared/TestingOnly/OpenApiPostTestingOnlyRequest.cs b/src/Infrastructure.Web.Api.Operations.Shared/TestingOnly/OpenApiPostTestingOnlyRequest.cs index e93854f0..dc480745 100644 --- a/src/Infrastructure.Web.Api.Operations.Shared/TestingOnly/OpenApiPostTestingOnlyRequest.cs +++ b/src/Infrastructure.Web.Api.Operations.Shared/TestingOnly/OpenApiPostTestingOnlyRequest.cs @@ -9,11 +9,14 @@ namespace Infrastructure.Web.Api.Operations.Shared.TestingOnly; /// /// Tests OpenAPI swagger for POST requests /// -/// a custom conflict response +/// +/// a custom conflict response +/// which spills over to the next line +/// /// a special response [Route("/testingonly/openapi/{Id}", OperationMethod.Post, isTestingOnly: true)] [UsedImplicitly] -public class OpenApiPostTestingOnlyRequest : WebRequest +public class OpenApiPostTestingOnlyRequest : WebRequest { [Description("anid")] public string? Id { get; set; } diff --git a/src/Infrastructure.Web.Api.Operations.Shared/TestingOnly/OpenApiPutTestingOnlyRequest.cs b/src/Infrastructure.Web.Api.Operations.Shared/TestingOnly/OpenApiPutTestingOnlyRequest.cs index bef4b45b..c9851d98 100644 --- a/src/Infrastructure.Web.Api.Operations.Shared/TestingOnly/OpenApiPutTestingOnlyRequest.cs +++ b/src/Infrastructure.Web.Api.Operations.Shared/TestingOnly/OpenApiPutTestingOnlyRequest.cs @@ -13,7 +13,7 @@ namespace Infrastructure.Web.Api.Operations.Shared.TestingOnly; /// a special response [Route("/testingonly/openapi/{Id}", OperationMethod.PutPatch, isTestingOnly: true)] [UsedImplicitly] -public class OpenApiPutTestingOnlyRequest : WebRequest +public class OpenApiPutTestingOnlyRequest : WebRequest { [Description("anid")] public string? Id { get; set; } diff --git a/src/Infrastructure.Web.Api.Operations.Shared/TestingOnly/OpenApiTestingOnlyResponse.cs b/src/Infrastructure.Web.Api.Operations.Shared/TestingOnly/OpenApiTestingOnlyResponse.cs new file mode 100644 index 00000000..7d666306 --- /dev/null +++ b/src/Infrastructure.Web.Api.Operations.Shared/TestingOnly/OpenApiTestingOnlyResponse.cs @@ -0,0 +1,23 @@ +using System.ComponentModel.DataAnnotations; +using Infrastructure.Web.Api.Interfaces; + +#if TESTINGONLY +namespace Infrastructure.Web.Api.Operations.Shared.TestingOnly; + +public class OpenApiTestingOnlyResponse : IWebResponse +{ + [Required] public string AnAnnotatedRequiredField { get; set; } = "avalue"; + + public string AnInitializedField { get; set; } = "avalue"; + + public string? ANullableField { get; set; } + + public bool? ANullableValueTypeField { get; set; } + + public required string ARequiredField { get; set; } + + public bool AValueTypeField { get; set; } + + public required string Message { get; set; } +} +#endif \ No newline at end of file diff --git a/src/Infrastructure.Web.Api.Operations.Shared/TestingOnly/StatusesTestingOnlyResponse.cs b/src/Infrastructure.Web.Api.Operations.Shared/TestingOnly/StatusesTestingOnlyResponse.cs index f651d7c2..70400acd 100644 --- a/src/Infrastructure.Web.Api.Operations.Shared/TestingOnly/StatusesTestingOnlyResponse.cs +++ b/src/Infrastructure.Web.Api.Operations.Shared/TestingOnly/StatusesTestingOnlyResponse.cs @@ -6,13 +6,13 @@ namespace Infrastructure.Web.Api.Operations.Shared.TestingOnly; public class StatusesTestingOnlyResponse : IWebResponse { - public string? Message { get; set; } + public required string Message { get; set; } } public class StatusesTestingOnlySearchResponse : IWebSearchResponse { - public List? Messages { get; set; } + public List Messages { get; set; } = []; - public SearchResultMetadata? Metadata { get; set; } + public required SearchResultMetadata Metadata { get; set; } } #endif \ No newline at end of file diff --git a/src/Infrastructure.Web.Api.Operations.Shared/TestingOnly/StringMessageTestingOnlyResponse.cs b/src/Infrastructure.Web.Api.Operations.Shared/TestingOnly/StringMessageTestingOnlyResponse.cs index e3b1183f..b71b65c6 100644 --- a/src/Infrastructure.Web.Api.Operations.Shared/TestingOnly/StringMessageTestingOnlyResponse.cs +++ b/src/Infrastructure.Web.Api.Operations.Shared/TestingOnly/StringMessageTestingOnlyResponse.cs @@ -5,6 +5,6 @@ namespace Infrastructure.Web.Api.Operations.Shared.TestingOnly; public class StringMessageTestingOnlyResponse : IWebResponse { - public string? Message { get; set; } + public required string Message { get; set; } } #endif \ No newline at end of file diff --git a/src/Infrastructure.Web.Api.Operations.Shared/TestingOnly/Stubs/HelloResponse.cs b/src/Infrastructure.Web.Api.Operations.Shared/TestingOnly/Stubs/HelloResponse.cs index 6d04806b..4a32c125 100644 --- a/src/Infrastructure.Web.Api.Operations.Shared/TestingOnly/Stubs/HelloResponse.cs +++ b/src/Infrastructure.Web.Api.Operations.Shared/TestingOnly/Stubs/HelloResponse.cs @@ -4,5 +4,5 @@ namespace Infrastructure.Web.Api.Operations.Shared.TestingOnly.Stubs; public class HelloResponse : IWebResponse { - public string? Message { get; set; } + public required string Message { get; set; } } \ No newline at end of file diff --git a/src/Infrastructure.Web.Api.Operations.Shared/UserProfiles/ChangeProfileAvatarResponse.cs b/src/Infrastructure.Web.Api.Operations.Shared/UserProfiles/ChangeProfileAvatarResponse.cs index 5a9e6718..b376b374 100644 --- a/src/Infrastructure.Web.Api.Operations.Shared/UserProfiles/ChangeProfileAvatarResponse.cs +++ b/src/Infrastructure.Web.Api.Operations.Shared/UserProfiles/ChangeProfileAvatarResponse.cs @@ -5,5 +5,5 @@ namespace Infrastructure.Web.Api.Operations.Shared.UserProfiles; public class ChangeProfileAvatarResponse : IWebResponse { - public UserProfile? Profile { get; set; } + public required UserProfile Profile { get; set; } } \ No newline at end of file diff --git a/src/Infrastructure.Web.Api.Operations.Shared/UserProfiles/DeleteProfileAvatarResponse.cs b/src/Infrastructure.Web.Api.Operations.Shared/UserProfiles/DeleteProfileAvatarResponse.cs index 1916f3e1..4d6e003b 100644 --- a/src/Infrastructure.Web.Api.Operations.Shared/UserProfiles/DeleteProfileAvatarResponse.cs +++ b/src/Infrastructure.Web.Api.Operations.Shared/UserProfiles/DeleteProfileAvatarResponse.cs @@ -5,5 +5,5 @@ namespace Infrastructure.Web.Api.Operations.Shared.UserProfiles; public class DeleteProfileAvatarResponse : IWebResponse { - public UserProfile? Profile { get; set; } + public required UserProfile Profile { get; set; } } \ No newline at end of file diff --git a/src/Infrastructure.Web.Api.Operations.Shared/UserProfiles/GetProfileForCallerResponse.cs b/src/Infrastructure.Web.Api.Operations.Shared/UserProfiles/GetProfileForCallerResponse.cs index c788ea8b..8295ac9b 100644 --- a/src/Infrastructure.Web.Api.Operations.Shared/UserProfiles/GetProfileForCallerResponse.cs +++ b/src/Infrastructure.Web.Api.Operations.Shared/UserProfiles/GetProfileForCallerResponse.cs @@ -5,5 +5,5 @@ namespace Infrastructure.Web.Api.Operations.Shared.UserProfiles; public class GetProfileForCallerResponse : IWebResponse { - public UserProfileForCaller? Profile { get; set; } + public required UserProfileForCaller Profile { get; set; } } \ No newline at end of file diff --git a/src/Infrastructure.Web.Api.Operations.Shared/UserProfiles/GetProfileResponse.cs b/src/Infrastructure.Web.Api.Operations.Shared/UserProfiles/GetProfileResponse.cs index 768e4b35..f333e348 100644 --- a/src/Infrastructure.Web.Api.Operations.Shared/UserProfiles/GetProfileResponse.cs +++ b/src/Infrastructure.Web.Api.Operations.Shared/UserProfiles/GetProfileResponse.cs @@ -5,5 +5,5 @@ namespace Infrastructure.Web.Api.Operations.Shared.UserProfiles; public class GetProfileResponse : IWebResponse { - public UserProfile? Profile { get; set; } + public required UserProfile Profile { get; set; } } \ No newline at end of file diff --git a/src/Infrastructure.Web.Common/Clients/ApiServiceClient.cs b/src/Infrastructure.Web.Common/Clients/ApiServiceClient.cs index db3358ba..e3738a94 100644 --- a/src/Infrastructure.Web.Common/Clients/ApiServiceClient.cs +++ b/src/Infrastructure.Web.Common/Clients/ApiServiceClient.cs @@ -66,7 +66,7 @@ await _retryPolicy.ExecuteAsync( public async Task> GetAsync(ICallerContext? context, IWebRequest request, Action? requestFilter = null, CancellationToken? cancellationToken = null) - where TResponse : IWebResponse, new() + where TResponse : IWebResponse { using var client = CreateJsonClient(context, requestFilter, out var modifiedRequestFilter); return await _retryPolicy.ExecuteAsync( @@ -107,7 +107,7 @@ public async Task> GetBinaryAsync(ICalle public async Task> PatchAsync(ICallerContext? context, IWebRequest request, Action? requestFilter = null, CancellationToken? cancellationToken = null) - where TResponse : IWebResponse, new() + where TResponse : IWebResponse { using var client = CreateJsonClient(context, requestFilter, out var modifiedRequestFilter); return await _retryPolicy.ExecuteAsync( @@ -118,7 +118,7 @@ public async Task> PatchAsync(ICal public async Task> PostAsync(ICallerContext? context, IWebRequest request, Action? requestFilter = null, CancellationToken? cancellationToken = null) - where TResponse : IWebResponse, new() + where TResponse : IWebResponse { using var client = CreateJsonClient(context, requestFilter, out var modifiedRequestFilter); return await _retryPolicy.ExecuteAsync( @@ -129,7 +129,7 @@ public async Task> PostAsync(ICall public async Task> PutAsync(ICallerContext? context, IWebRequest request, Action? requestFilter = null, CancellationToken? cancellationToken = null) - where TResponse : IWebResponse, new() + where TResponse : IWebResponse { using var client = CreateJsonClient(context, requestFilter, out var modifiedRequestFilter); return await _retryPolicy.ExecuteAsync( @@ -143,14 +143,9 @@ protected virtual JsonClient CreateJsonClient(ICallerContext? context, { var client = new JsonClient(ClientFactory, JsonOptions); client.SetBaseUrl(BaseUrl); - if (inboundRequestFilter.Exists()) - { - modifiedRequestFilter = inboundRequestFilter; - } - else - { - modifiedRequestFilter = _ => { }; - } + modifiedRequestFilter = inboundRequestFilter.Exists() + ? inboundRequestFilter + : _ => { }; return client; } diff --git a/src/Infrastructure.Web.Common/Clients/JsonClient.cs b/src/Infrastructure.Web.Common/Clients/JsonClient.cs index 98ede3ff..9f2ecf80 100644 --- a/src/Infrastructure.Web.Common/Clients/JsonClient.cs +++ b/src/Infrastructure.Web.Common/Clients/JsonClient.cs @@ -1,4 +1,5 @@ using System.Diagnostics.CodeAnalysis; +using System.Net; using System.Net.Http.Headers; using System.Net.Http.Json; using System.Text.Json; @@ -40,7 +41,7 @@ public void Dispose() GC.SuppressFinalize(this); } - protected virtual void Dispose(bool disposing) + private void Dispose(bool disposing) { if (disposing) { @@ -50,7 +51,7 @@ protected virtual void Dispose(bool disposing) public async Task> DeleteAsync(IWebRequest request, Action? requestFilter = null, CancellationToken? cancellationToken = default) - where TResponse : IWebResponse, new() + where TResponse : IWebResponse { var response = await SendRequestAsync(_httpClient, HttpMethod.Delete, request, null, requestFilter, cancellationToken); @@ -72,7 +73,7 @@ public async Task DeleteAsync(IWebRequest request, public async Task> GetAsync(IWebRequest request, Action? requestFilter = null, CancellationToken? cancellationToken = default) - where TResponse : IWebResponse, new() + where TResponse : IWebResponse { var response = await SendRequestAsync(_httpClient, HttpMethod.Get, request, null, requestFilter, cancellationToken); @@ -95,7 +96,7 @@ public async Task GetAsync(IWebRequest request, public async Task> PatchAsync(IWebRequest request, Action? requestFilter = null, CancellationToken? cancellationToken = default) - where TResponse : IWebResponse, new() + where TResponse : IWebResponse { var response = await SendRequestAsync(_httpClient, HttpMethod.Patch, request, null, requestFilter, cancellationToken); @@ -118,7 +119,7 @@ public async Task PatchAsync(IWebRequest request, public async Task> PostAsync(IWebRequest request, Action? requestFilter = null, CancellationToken? cancellationToken = default) - where TResponse : IWebResponse, new() + where TResponse : IWebResponse { var response = await SendRequestAsync(_httpClient, HttpMethod.Post, request, null, requestFilter, cancellationToken); @@ -141,7 +142,7 @@ public async Task PostAsync(IWebRequest request, public async Task> PostAsync(IWebRequest request, PostFile file, Action? requestFilter = null, CancellationToken? cancellationToken = default) - where TResponse : IWebResponse, new() + where TResponse : IWebResponse { var response = await SendRequestAsync(_httpClient, HttpMethod.Post, request, file, requestFilter, cancellationToken); @@ -164,7 +165,7 @@ public async Task PostAsync(IWebRequest request, PostFile file, public async Task> PutAsync(IWebRequest request, Action? requestFilter = null, CancellationToken? cancellationToken = default) - where TResponse : IWebResponse, new() + where TResponse : IWebResponse { var response = await SendRequestAsync(_httpClient, HttpMethod.Put, request, null, requestFilter, cancellationToken); @@ -176,7 +177,7 @@ public async Task> PutAsync(IWebRequest> PutAsync(IWebRequest request, PostFile file, Action? requestFilter = null, CancellationToken? cancellationToken = default) - where TResponse : IWebResponse, new() + where TResponse : IWebResponse { var response = await SendRequestAsync(_httpClient, HttpMethod.Put, request, file, requestFilter, cancellationToken); @@ -252,16 +253,33 @@ public async Task PutAsync(IWebRequest request, internal static async Task> GetTypedResponseAsync( HttpResponseMessage response, JsonSerializerOptions? jsonOptions, CancellationToken? cancellationToken) - where TResponse : IWebResponse, new() + where TResponse : IWebResponse { var contentType = response.Content.Headers.ContentType; if (contentType.NotExists()) { if (response.IsSuccessStatusCode) { - return new TResponse(); - } + if (typeof(EmptyResponse).IsAssignableTo(typeof(TResponse))) + { + return TryCreateEmptyResponse(); + } + // Assume JSON + try + { + var instance = await response.Content.ReadFromJsonAsync(jsonOptions, + cancellationToken ?? CancellationToken.None); + return instance.Exists() + ? instance + : TryCreateEmptyResponse(); + } + catch (JsonException) + { + return TryCreateEmptyResponse(); + } + } + return response.StatusCode.ToResponseProblem(response.ReasonPhrase); } @@ -277,8 +295,11 @@ internal static async Task> GetTypedResponseA { if (response.IsSuccessStatusCode) { - return await response.Content.ReadFromJsonAsync(jsonOptions, - cancellationToken ?? CancellationToken.None) ?? new TResponse(); + var instance = await response.Content.ReadFromJsonAsync(jsonOptions, + cancellationToken ?? CancellationToken.None); + return instance.Exists() + ? instance + : TryCreateEmptyResponse(); } if (response.Content.Headers.ContentType.Exists()) @@ -296,13 +317,14 @@ internal static async Task> GetTypedResponseA { if (response.IsSuccessStatusCode) { - return new TResponse(); + return TryCreateEmptyResponse(); } return response.StatusCode.ToResponseProblem(response.ReasonPhrase); } - return new TResponse(); + return HttpStatusCode.UnsupportedMediaType.ToResponseProblem( + string.Format(Resources.JsonClient_GetTypedResponse_UnsupportedMediaType, contentType.MediaType)); } public async Task SendOneWayAsync(IWebRequest request, Action? requestFilter = null, @@ -381,7 +403,7 @@ static FormUrlEncodedContent ToUrlEncodedContent(IWebRequest body) { var requestFields = body.SerializeToJson() .FromJson>()! - .ToDictionary(pair => pair.Key, pair => pair.Value.ToString() ?? string.Empty); + .ToDictionary(pair => pair.Key, pair => pair.Value.ToString() ?? string.Empty); return new FormUrlEncodedContent(requestFields); } @@ -392,6 +414,21 @@ public void SetBaseUrl(string baseUrl) _httpClient.BaseAddress = new Uri(baseUrl.WithTrailingSlash(), UriKind.Absolute); } + private static Result TryCreateEmptyResponse() + where TResponse : IWebResponse + { + try + { + return Activator.CreateInstance(); + } + catch (Exception ex) + { + return HttpStatusCode.InternalServerError.ToResponseProblem( + string.Format(Resources.JsonClient_TryCreateEmptyResponse_NotConstructable, typeof(TResponse), + ex.Message)); + } + } + private static async Task SendRequestAsync(HttpClient httpClient, HttpMethod method, string requestUri, HttpContent? requestContent, Action? requestFilter, CancellationToken? cancellationToken = default) @@ -484,7 +521,7 @@ private static JsonResponse CreateResponse(HttpResponseMessage response, Result< private static JsonResponse CreateResponse(HttpResponseMessage response, Result content) - where TResponse : IWebResponse, new() + where TResponse : IWebResponse { return new JsonResponse { @@ -493,7 +530,7 @@ private static JsonResponse CreateResponse(HttpResponseMes ContentHeaders = response.Content.Headers, Headers = response.Headers, RequestId = response.GetOrCreateRequestId(), - RawContent = content.IsSuccessful && !content.HasValue + RawContent = content is { IsSuccessful: true, HasValue: false } ? response.Content.ReadAsStream() : null }; diff --git a/src/Infrastructure.Web.Common/Resources.Designer.cs b/src/Infrastructure.Web.Common/Resources.Designer.cs index 1be03247..6488d3a5 100644 --- a/src/Infrastructure.Web.Common/Resources.Designer.cs +++ b/src/Infrastructure.Web.Common/Resources.Designer.cs @@ -58,5 +58,23 @@ internal Resources() { resourceCulture = value; } } + + /// + /// Looks up a localized string similar to Unsupported media type in response: {0}. + /// + internal static string JsonClient_GetTypedResponse_UnsupportedMediaType { + get { + return ResourceManager.GetString("JsonClient_GetTypedResponse_UnsupportedMediaType", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to An empty instance of '{0}' could not be created, likely due to the fact that it does not have a default parameterless constructor or it has properties that require initialization at construction time. More details: {1}. + /// + internal static string JsonClient_TryCreateEmptyResponse_NotConstructable { + get { + return ResourceManager.GetString("JsonClient_TryCreateEmptyResponse_NotConstructable", resourceCulture); + } + } } } diff --git a/src/Infrastructure.Web.Common/Resources.resx b/src/Infrastructure.Web.Common/Resources.resx index 755958fe..15d38f9a 100644 --- a/src/Infrastructure.Web.Common/Resources.resx +++ b/src/Infrastructure.Web.Common/Resources.resx @@ -24,4 +24,10 @@ PublicKeyToken=b77a5c561934e089 + + Unsupported media type in response: {0} + + + An empty instance of '{0}' could not be created, likely due to the fact that it does not have a default parameterless constructor or it has properties that require initialization at construction time. More details: {1} + \ No newline at end of file diff --git a/src/Infrastructure.Web.Hosting.Common.UnitTests/Documentation/DefaultResponsesFilterSpec.cs b/src/Infrastructure.Web.Hosting.Common.UnitTests/Documentation/DefaultResponsesFilterSpec.cs index cd10dca1..ccf29075 100644 --- a/src/Infrastructure.Web.Hosting.Common.UnitTests/Documentation/DefaultResponsesFilterSpec.cs +++ b/src/Infrastructure.Web.Hosting.Common.UnitTests/Documentation/DefaultResponsesFilterSpec.cs @@ -212,7 +212,7 @@ public class TestPostRequestTypedResponse : WebRequest + /// Determines if the type is a response type, which are the only ones that are annotatable + /// with attributes + /// + public static bool IsResponseType(this Type? parent) + { + return parent.Exists() && parent.IsAssignableTo(typeof(IWebResponse)); } /// @@ -143,6 +153,11 @@ public static void SetEnumValues(this OpenApiSchema schema, Type type) /// public static void SetPropertyDescription(this OpenApiSchema schema, MemberInfo property) { + if (property.MemberType != MemberTypes.Property) + { + return; + } + var descriptionAttribute = property.GetCustomAttribute(); if (descriptionAttribute.Exists()) { @@ -153,6 +168,46 @@ public static void SetPropertyDescription(this OpenApiSchema schema, MemberInfo } } + /// + /// Sets the nullability of a property of a responseType + /// + public static void SetPropertyNullable(this OpenApiSchema schema, MemberInfo property) + { + if (property.MemberType != MemberTypes.Property) + { + return; + } + + var propertyInfo = (property as PropertyInfo)!; + + var isNullable = false; + + // Check for the [Required] DataAnnotation attribute + if (property.GetCustomAttribute().Exists()) + { + isNullable = false; + } + + // Check for the 'required' C# keyword + if (property.GetCustomAttribute().Exists()) + { + isNullable = false; + } + + if (propertyInfo.PropertyType.IsValueType) + { + isNullable = Nullable.GetUnderlyingType(propertyInfo.PropertyType).Exists(); + } + + // Check for the ? nullable annotation + if (property.GetCustomAttribute().Exists()) + { + isNullable = true; + } + + schema.Nullable = isNullable; + } + public static void SetRequired(this OpenApiParameter parameter, ParameterInfo parameterInfo) { if (parameter.In == ParameterLocation.Path diff --git a/src/Infrastructure.Web.Hosting.Common/Documentation/XmlDocumentationOperationFilter.cs b/src/Infrastructure.Web.Hosting.Common/Documentation/XmlDocumentationOperationFilter.cs index 8cb286b5..7afdad27 100644 --- a/src/Infrastructure.Web.Hosting.Common/Documentation/XmlDocumentationOperationFilter.cs +++ b/src/Infrastructure.Web.Hosting.Common/Documentation/XmlDocumentationOperationFilter.cs @@ -70,7 +70,7 @@ private static OpenApiResponses GetClassCustomResponses(Class? requestClass) foreach (var docResponse in docResponses) { var code = docResponse.Xml.FirstAttribute!.Value; - var description = docResponse.Xml.Value; + var description = docResponse.ToText(); responses.Add(code, new OpenApiResponse { diff --git a/src/Infrastructure.Web.Hosting.Common/Extensions/HostExtensions.cs b/src/Infrastructure.Web.Hosting.Common/Extensions/HostExtensions.cs index b1049246..860ae758 100644 --- a/src/Infrastructure.Web.Hosting.Common/Extensions/HostExtensions.cs +++ b/src/Infrastructure.Web.Hosting.Common/Extensions/HostExtensions.cs @@ -128,6 +128,7 @@ void RegisterSharedServices() void RegisterConfiguration(bool isMultiTenanted) { + appBuilder.Configuration.AddJsonFile("appsettings.local.json", true); #if HOSTEDONAZURE appBuilder.Configuration.AddJsonFile("appsettings.Azure.json", true); #elif HOSTEDONAWS diff --git a/src/Infrastructure.Web.Interfaces/Clients/IHttpJsonClient.cs b/src/Infrastructure.Web.Interfaces/Clients/IHttpJsonClient.cs index d8010292..c3b15c50 100644 --- a/src/Infrastructure.Web.Interfaces/Clients/IHttpJsonClient.cs +++ b/src/Infrastructure.Web.Interfaces/Clients/IHttpJsonClient.cs @@ -10,7 +10,7 @@ public interface IHttpJsonClient Task> DeleteAsync(IWebRequest request, Action? requestFilter = null, CancellationToken? cancellationToken = default) - where TResponse : IWebResponse, new(); + where TResponse : IWebResponse; Task DeleteAsync(IWebRequest request, Action? requestFilter = null, @@ -19,7 +19,7 @@ Task DeleteAsync(IWebRequest request, Task> GetAsync(IWebRequest request, Action? requestFilter = null, CancellationToken? cancellationToken = default) - where TResponse : IWebResponse, new(); + where TResponse : IWebResponse; Task GetAsync(IWebRequest request, Action? requestFilter = null, @@ -27,32 +27,32 @@ Task GetAsync(IWebRequest request, Task> PatchAsync(IWebRequest request, Action? requestFilter = null, CancellationToken? cancellationToken = default) - where TResponse : IWebResponse, new(); + where TResponse : IWebResponse; Task PatchAsync(IWebRequest request, Action? requestFilter = null, CancellationToken? cancellationToken = default); Task> PostAsync(IWebRequest request, Action? requestFilter = null, CancellationToken? cancellationToken = default) - where TResponse : IWebResponse, new(); + where TResponse : IWebResponse; Task PostAsync(IWebRequest request, Action? requestFilter = null, CancellationToken? cancellationToken = default); Task> PostAsync(IWebRequest request, PostFile file, Action? requestFilter = null, CancellationToken? cancellationToken = default) - where TResponse : IWebResponse, new(); + where TResponse : IWebResponse; Task PostAsync(IWebRequest request, PostFile file, Action? requestFilter = null, CancellationToken? cancellationToken = default); Task> PutAsync(IWebRequest request, Action? requestFilter = null, CancellationToken? cancellationToken = default) - where TResponse : IWebResponse, new(); + where TResponse : IWebResponse; Task> PutAsync(IWebRequest request, PostFile file, Action? requestFilter = null, CancellationToken? cancellationToken = default) - where TResponse : IWebResponse, new(); + where TResponse : IWebResponse; Task PutAsync(IWebRequest request, Action? requestFilter = null, CancellationToken? cancellationToken = default); diff --git a/src/Infrastructure.Web.Interfaces/Clients/IServiceClient.cs b/src/Infrastructure.Web.Interfaces/Clients/IServiceClient.cs index 11b8806f..1e4e325f 100644 --- a/src/Infrastructure.Web.Interfaces/Clients/IServiceClient.cs +++ b/src/Infrastructure.Web.Interfaces/Clients/IServiceClient.cs @@ -17,7 +17,7 @@ public interface IServiceClient : IFireAndForgetServiceClient Task> GetAsync(ICallerContext? context, IWebRequest request, Action? requestFilter = null, CancellationToken? cancellationToken = null) - where TResponse : IWebResponse, new(); + where TResponse : IWebResponse; Task> GetBinaryAsync(ICallerContext? context, IWebRequest request, Action? requestFilter = null, CancellationToken? cancellationToken = null); @@ -28,17 +28,17 @@ Task> GetBinaryAsync(ICallerContext? con Task> PatchAsync(ICallerContext? context, IWebRequest request, Action? requestFilter = null, CancellationToken? cancellationToken = null) - where TResponse : IWebResponse, new(); + where TResponse : IWebResponse; Task> PostAsync(ICallerContext? context, IWebRequest request, Action? requestFilter = null, CancellationToken? cancellationToken = null) - where TResponse : IWebResponse, new(); + where TResponse : IWebResponse; Task> PutAsync(ICallerContext? context, IWebRequest request, Action? requestFilter = null, CancellationToken? cancellationToken = null) - where TResponse : IWebResponse, new(); + where TResponse : IWebResponse; } public class BinaryResponse diff --git a/src/Infrastructure.Web.Website.IntegrationTests/FeatureFlagsApiSpec.cs b/src/Infrastructure.Web.Website.IntegrationTests/FeatureFlagsApiSpec.cs index 69c4854b..bea1ccb8 100644 --- a/src/Infrastructure.Web.Website.IntegrationTests/FeatureFlagsApiSpec.cs +++ b/src/Infrastructure.Web.Website.IntegrationTests/FeatureFlagsApiSpec.cs @@ -50,7 +50,7 @@ public async Task WhenGetFeatureFlag_ThenReturnsFlag() var result = await HttpApi.GetAsync(request.MakeApiRoute()); result.StatusCode.Should().Be(HttpStatusCode.OK); - var flag = (await result.Content.ReadFromJsonAsync(JsonOptions))!.Flag!; + var flag = (await result.Content.ReadFromJsonAsync(JsonOptions))!.Flag; flag.Name.Should().Be(Flag.TestingOnly.Name); #endif } diff --git a/src/Infrastructure.Web.Website.IntegrationTests/ReverseProxyApiSpec.cs b/src/Infrastructure.Web.Website.IntegrationTests/ReverseProxyApiSpec.cs index 1e6a8115..e335955b 100644 --- a/src/Infrastructure.Web.Website.IntegrationTests/ReverseProxyApiSpec.cs +++ b/src/Infrastructure.Web.Website.IntegrationTests/ReverseProxyApiSpec.cs @@ -72,8 +72,8 @@ public async Task WhenRequestARemoteApi_ThenDoesReverseProxy() result.StatusCode.Should().Be(HttpStatusCode.OK); var response = await result.Content.ReadFromJsonAsync(JsonOptions); - response!.Profile!.IsAuthenticated.Should().BeFalse(); - response.Profile!.Id.Should().Be(CallerConstants.AnonymousUserId); + response!.Profile.IsAuthenticated.Should().BeFalse(); + response.Profile.Id.Should().Be(CallerConstants.AnonymousUserId); } [Fact] diff --git a/src/Infrastructure.Web.Website.IntegrationTests/WebsiteTestingExtensions.cs b/src/Infrastructure.Web.Website.IntegrationTests/WebsiteTestingExtensions.cs index 3b86b3d6..153c2941 100644 --- a/src/Infrastructure.Web.Website.IntegrationTests/WebsiteTestingExtensions.cs +++ b/src/Infrastructure.Web.Website.IntegrationTests/WebsiteTestingExtensions.cs @@ -34,9 +34,14 @@ public static class WebsiteTestingExtensions var authenticateUrl = authenticateRequest.MakeApiRoute(); var authenticated = await websiteClient.PostAsync(authenticateUrl, JsonContent.Create(authenticateRequest), (msg, cookies) => msg.WithCSRF(cookies, csrfService)); + if (authenticated.StatusCode == HttpStatusCode.Unauthorized) + { + return (null!, authenticated); + } + var authTokens = (await authenticated.Content.ReadFromJsonAsync(jsonOptions))!; - return (authTokens.UserId, authenticated)!; + return (authTokens.UserId, authenticated); } public static Optional GetCookie(this HttpResponseMessage responseMessage, string name) @@ -101,7 +106,7 @@ public static async Task RegisterPersonUserFromBrowserAsync(this IHttpClient web (msg, cookies) => msg.WithCSRF(cookies, csrfService)); var userId = (await person.Content.ReadFromJsonAsync(jsonOptions))! - .Credential!.User.Id; + .Credential.User.Id; #if TESTINGONLY await websiteClient.PropagateDomainEventsAsync(csrfService); @@ -117,7 +122,7 @@ public static async Task RegisterPersonUserFromBrowserAsync(this IHttpClient web .Token; var confirmationRequest = new ConfirmRegistrationPersonPasswordRequest { - Token = token! + Token = token }; var confirmationUrl = confirmationRequest.MakeApiRoute(); await websiteClient.PostAsync(confirmationUrl, JsonContent.Create(confirmationRequest), diff --git a/src/Infrastructure.Worker.Api.IntegrationTests/Stubs/StubServiceClient.cs b/src/Infrastructure.Worker.Api.IntegrationTests/Stubs/StubServiceClient.cs index 3365b576..5e8a7b24 100644 --- a/src/Infrastructure.Worker.Api.IntegrationTests/Stubs/StubServiceClient.cs +++ b/src/Infrastructure.Worker.Api.IntegrationTests/Stubs/StubServiceClient.cs @@ -34,7 +34,7 @@ public Task FireAsync(ICallerContext? context, IWebRequest public Task> GetAsync(ICallerContext? context, IWebRequest request, Action? requestFilter = null, CancellationToken? cancellationToken = null) - where TResponse : IWebResponse, new() + where TResponse : IWebResponse { throw new NotImplementedException(); } @@ -56,7 +56,7 @@ public Task> GetBinaryAsync(ICallerConte public Task> PatchAsync(ICallerContext? context, IWebRequest request, Action? requestFilter = null, CancellationToken? cancellationToken = null) - where TResponse : IWebResponse, new() + where TResponse : IWebResponse { throw new NotImplementedException(); } @@ -64,17 +64,18 @@ public Task> PatchAsync(ICallerCon public Task> PostAsync(ICallerContext? context, IWebRequest request, Action? requestFilter = null, CancellationToken? cancellationToken = null) - where TResponse : IWebResponse, new() + where TResponse : IWebResponse { LastPostedMessage = Optional.Some(request); - return Task.FromResult>(new TResponse()); + var response = Activator.CreateInstance(); + return Task.FromResult>(response); } public Task> PutAsync(ICallerContext? context, IWebRequest request, Action? requestFilter = null, CancellationToken? cancellationToken = null) - where TResponse : IWebResponse, new() + where TResponse : IWebResponse { throw new NotImplementedException(); } diff --git a/src/IntegrationTesting.WebApi.Common/WebApiSpec.cs b/src/IntegrationTesting.WebApi.Common/WebApiSpec.cs index d838cc3d..c7a8b443 100644 --- a/src/IntegrationTesting.WebApi.Common/WebApiSpec.cs +++ b/src/IntegrationTesting.WebApi.Common/WebApiSpec.cs @@ -278,7 +278,7 @@ protected async Task LoginUserAsync(LoginUser who = LoginUser.Pers var person = await RegisterUserAsync(emailAddress, firstName); - var user = person.Credential!.User; + var user = person.Credential.User; return await ReAuthenticateUserAsync(user, emailAddress); } @@ -313,11 +313,11 @@ protected async Task ReAuthenticateUserAsync(EndUser user, Password = password }); - var accessToken = login.Content.Value.Tokens!.AccessToken.Value; + var accessToken = login.Content.Value.Tokens.AccessToken.Value; var refreshToken = login.Content.Value.Tokens.RefreshToken.Value; var profile = (await Api.GetAsync(new GetProfileForCallerRequest(), - req => req.SetJWTBearerToken(accessToken))).Content.Value.Profile!; + req => req.SetJWTBearerToken(accessToken))).Content.Value.Profile; var defaultOrganizationId = profile.DefaultOrganizationId!; return new LoginDetails(accessToken, refreshToken, user, profile, defaultOrganizationId); diff --git a/src/OrganizationsInfrastructure.IntegrationTests/OrganizationsApiSpec.cs b/src/OrganizationsInfrastructure.IntegrationTests/OrganizationsApiSpec.cs index 91999756..2bc4cff3 100644 --- a/src/OrganizationsInfrastructure.IntegrationTests/OrganizationsApiSpec.cs +++ b/src/OrganizationsInfrastructure.IntegrationTests/OrganizationsApiSpec.cs @@ -37,9 +37,9 @@ public async Task WhenGetOrganization_ThenReturnsOrganization() Id = login.DefaultOrganizationId! }, req => req.SetJWTBearerToken(login.AccessToken)); - result.Content.Value.Organization!.CreatedById.Should().Be(login.User.Id); - result.Content.Value.Organization!.Name.Should().Be("persona alastname"); - result.Content.Value.Organization!.Ownership.Should().Be(OrganizationOwnership.Personal); + result.Content.Value.Organization.CreatedById.Should().Be(login.User.Id); + result.Content.Value.Organization.Name.Should().Be("persona alastname"); + result.Content.Value.Organization.Ownership.Should().Be(OrganizationOwnership.Personal); } [Fact] @@ -52,10 +52,10 @@ public async Task WhenCreateOrganization_ThenReturnsOrganization() Name = "aname" }, req => req.SetJWTBearerToken(login.AccessToken)); - var organizationId = result.Content.Value.Organization!.Id; - result.Content.Value.Organization!.CreatedById.Should().Be(login.User.Id); - result.Content.Value.Organization!.Name.Should().Be("aname"); - result.Content.Value.Organization!.Ownership.Should().Be(OrganizationOwnership.Shared); + var organizationId = result.Content.Value.Organization.Id; + result.Content.Value.Organization.CreatedById.Should().Be(login.User.Id); + result.Content.Value.Organization.Name.Should().Be("aname"); + result.Content.Value.Organization.Ownership.Should().Be(OrganizationOwnership.Shared); login = await ReAuthenticateUserAsync(login); login.DefaultOrganizationId.Should().Be(organizationId); @@ -65,7 +65,7 @@ public async Task WhenCreateOrganization_ThenReturnsOrganization() Id = organizationId }, req => req.SetJWTBearerToken(login.AccessToken)); - members.Content.Value.Members!.Count.Should().Be(1); + members.Content.Value.Members.Count.Should().Be(1); members.Content.Value.Members[0].IsDefault.Should().BeTrue(); members.Content.Value.Members[0].IsOwner.Should().BeTrue(); members.Content.Value.Members[0].IsRegistered.Should().BeTrue(); @@ -90,7 +90,7 @@ public async Task WhenInviteMembersToOrganization_ThenAddsMembers() Name = "aname" }, req => req.SetJWTBearerToken(loginA.AccessToken)); - var organizationId = organization.Content.Value.Organization!.Id; + var organizationId = organization.Content.Value.Organization.Id; loginA = await ReAuthenticateUserAsync(loginA); await Api.PostAsync(new InviteMemberToOrganizationRequest { @@ -118,7 +118,7 @@ await Api.PostAsync(new InviteMemberToOrganizationRequest Id = organizationId }, req => req.SetJWTBearerToken(loginA.AccessToken)); - members.Content.Value.Members!.Count.Should().Be(4); + members.Content.Value.Members.Count.Should().Be(4); members.Content.Value.Members[0].IsDefault.Should().BeTrue(); members.Content.Value.Members[0].IsOwner.Should().BeTrue(); members.Content.Value.Members[0].IsRegistered.Should().BeTrue(); @@ -150,7 +150,7 @@ await Api.PostAsync(new InviteMemberToOrganizationRequest members.Content.Value.Members[3].IsDefault.Should().BeTrue(); members.Content.Value.Members[3].IsOwner.Should().BeFalse(); members.Content.Value.Members[3].IsRegistered.Should().BeTrue(); - members.Content.Value.Members[3].UserId.Should().Be(machine.Content.Value.Machine!.Id); + members.Content.Value.Members[3].UserId.Should().Be(machine.Content.Value.Machine.Id); members.Content.Value.Members[3].EmailAddress.Should().BeNull(); members.Content.Value.Members[3].Name.FirstName.Should().Be("amachinename"); members.Content.Value.Members[3].Name.LastName.Should().BeNull(); @@ -186,7 +186,7 @@ public async Task WhenChangeAvatarByOrgMember_ThenForbidden() }, req => req.SetJWTBearerToken(loginA.AccessToken)); loginA = await ReAuthenticateUserAsync(loginA); - var organizationId = organization.Content.Value.Organization!.Id; + var organizationId = organization.Content.Value.Organization.Id; await Api.PostAsync(new InviteMemberToOrganizationRequest { Id = organizationId, @@ -215,7 +215,7 @@ public async Task WhenChangeAvatar_ThenChanges() }, new PostFile(GetTestImage(), HttpConstants.ContentTypes.ImagePng, "afilename"), req => req.SetJWTBearerToken(login.AccessToken)); - result.Content.Value.Organization!.AvatarUrl.Should().StartWith("https://localhost:5001/images/image_"); + result.Content.Value.Organization.AvatarUrl.Should().StartWith("https://localhost:5001/images/image_"); } [Fact] @@ -235,7 +235,7 @@ await Api.PutAsync(new ChangeOrganizationAvatarRequest Id = organizationId }, req => req.SetJWTBearerToken(login.AccessToken)); - result.Content.Value.Organization!.AvatarUrl.Should().BeNull(); + result.Content.Value.Organization.AvatarUrl.Should().BeNull(); } [Fact] @@ -250,7 +250,7 @@ public async Task WhenChangeDetails_ThenDeletes() Name = "anewname" }, req => req.SetJWTBearerToken(login.AccessToken)); - result.Content.Value.Organization!.Name.Should().Be("anewname"); + result.Content.Value.Organization.Name.Should().Be("anewname"); } [Fact] @@ -264,7 +264,7 @@ public async Task WhenUnInviteGuestFromOrganization_ThenRemovesMember() Name = "aname" }, req => req.SetJWTBearerToken(loginA.AccessToken)); - var organizationId = organization.Content.Value.Organization!.Id; + var organizationId = organization.Content.Value.Organization.Id; loginA = await ReAuthenticateUserAsync(loginA); await Api.PostAsync(new InviteMemberToOrganizationRequest { @@ -277,7 +277,7 @@ await Api.PostAsync(new InviteMemberToOrganizationRequest { Id = organizationId }, req => req.SetJWTBearerToken(loginA.AccessToken)); - var loginCId = members.Content.Value.Members![1].UserId; + var loginCId = members.Content.Value.Members[1].UserId; await Api.DeleteAsync(new UnInviteMemberFromOrganizationRequest { @@ -291,7 +291,7 @@ await Api.DeleteAsync(new UnInviteMemberFromOrganizationRequest Id = organizationId }, req => req.SetJWTBearerToken(loginA.AccessToken)); - members.Content.Value.Members!.Count.Should().Be(1); + members.Content.Value.Members.Count.Should().Be(1); members.Content.Value.Members[0].IsDefault.Should().BeTrue(); members.Content.Value.Members[0].IsOwner.Should().BeTrue(); members.Content.Value.Members[0].IsRegistered.Should().BeTrue(); @@ -315,7 +315,7 @@ public async Task WhenUnInviteRegisteredUserFromOrganization_ThenRemovesMember() Name = "aname" }, req => req.SetJWTBearerToken(loginA.AccessToken)); - var organizationId = organization.Content.Value.Organization!.Id; + var organizationId = organization.Content.Value.Organization.Id; loginA = await ReAuthenticateUserAsync(loginA); await Api.PostAsync(new InviteMemberToOrganizationRequest { @@ -328,7 +328,7 @@ await Api.PostAsync(new InviteMemberToOrganizationRequest { Id = organizationId }, req => req.SetJWTBearerToken(loginA.AccessToken)); - var loginBId = members.Content.Value.Members![1].UserId; + var loginBId = members.Content.Value.Members[1].UserId; await Api.DeleteAsync(new UnInviteMemberFromOrganizationRequest { @@ -342,7 +342,7 @@ await Api.DeleteAsync(new UnInviteMemberFromOrganizationRequest Id = organizationId }, req => req.SetJWTBearerToken(loginA.AccessToken)); - members.Content.Value.Members!.Count.Should().Be(1); + members.Content.Value.Members.Count.Should().Be(1); members.Content.Value.Members[0].IsDefault.Should().BeTrue(); members.Content.Value.Members[0].IsOwner.Should().BeTrue(); members.Content.Value.Members[0].IsRegistered.Should().BeTrue(); @@ -358,9 +358,9 @@ await Api.DeleteAsync(new UnInviteMemberFromOrganizationRequest var memberships = await Api.GetAsync(new ListMembershipsForCallerRequest(), req => req.SetJWTBearerToken(loginB.AccessToken)); - memberships.Content.Value.Memberships!.Count.Should().Be(1); - memberships.Content.Value.Memberships![0].OrganizationId.Should().NotBeNull(); - memberships.Content.Value.Memberships![0].Ownership.Should().Be(OrganizationOwnership.Personal); + memberships.Content.Value.Memberships.Count.Should().Be(1); + memberships.Content.Value.Memberships[0].OrganizationId.Should().NotBeNull(); + memberships.Content.Value.Memberships[0].Ownership.Should().Be(OrganizationOwnership.Personal); } [Fact] @@ -375,7 +375,7 @@ public async Task WhenUnInviteMembersFromOrganization_ThenRemovesMembers() Name = "aname" }, req => req.SetJWTBearerToken(loginA.AccessToken)); - var organizationId = organization.Content.Value.Organization!.Id; + var organizationId = organization.Content.Value.Organization.Id; loginA = await ReAuthenticateUserAsync(loginA); await Api.PostAsync(new InviteMemberToOrganizationRequest { @@ -402,9 +402,9 @@ await Api.PostAsync(new RegisterMachineRequest { Id = organizationId }, req => req.SetJWTBearerToken(loginA.AccessToken)); - var loginBId = members.Content.Value.Members![1].UserId; - var loginCId = members.Content.Value.Members![2].UserId; - var machineId = members.Content.Value.Members![3].UserId; + var loginBId = members.Content.Value.Members[1].UserId; + var loginCId = members.Content.Value.Members[2].UserId; + var machineId = members.Content.Value.Members[3].UserId; await Api.DeleteAsync(new UnInviteMemberFromOrganizationRequest { @@ -428,7 +428,7 @@ await Api.DeleteAsync(new UnInviteMemberFromOrganizationRequest Id = organizationId }, req => req.SetJWTBearerToken(loginA.AccessToken)); - members.Content.Value.Members!.Count.Should().Be(1); + members.Content.Value.Members.Count.Should().Be(1); members.Content.Value.Members[0].IsDefault.Should().BeTrue(); members.Content.Value.Members[0].IsOwner.Should().BeTrue(); members.Content.Value.Members[0].IsRegistered.Should().BeTrue(); @@ -452,7 +452,7 @@ public async Task WhenAssignRoles_ThenAssigns() Name = "aname" }, req => req.SetJWTBearerToken(loginA.AccessToken)); - var organizationId = organization.Content.Value.Organization!.Id; + var organizationId = organization.Content.Value.Organization.Id; loginA = await ReAuthenticateUserAsync(loginA); await Api.PostAsync(new InviteMemberToOrganizationRequest { @@ -472,13 +472,13 @@ await Api.PutAsync(new AssignRolesToOrganizationRequest var memberships = await Api.GetAsync(new ListMembershipsForCallerRequest(), req => req.SetJWTBearerToken(loginB.AccessToken)); - memberships.Content.Value.Memberships!.Count.Should().Be(2); - memberships.Content.Value.Memberships![0].OrganizationId.Should().NotBeNull(); - memberships.Content.Value.Memberships![0].Ownership.Should().Be(OrganizationOwnership.Personal); - memberships.Content.Value.Memberships![0].Roles.Should().ContainInOrder(TenantRoles.Owner.Name); - memberships.Content.Value.Memberships![1].OrganizationId.Should().Be(organizationId); - memberships.Content.Value.Memberships![1].Ownership.Should().Be(OrganizationOwnership.Shared); - memberships.Content.Value.Memberships![1].Roles.Should() + memberships.Content.Value.Memberships.Count.Should().Be(2); + memberships.Content.Value.Memberships[0].OrganizationId.Should().NotBeNull(); + memberships.Content.Value.Memberships[0].Ownership.Should().Be(OrganizationOwnership.Personal); + memberships.Content.Value.Memberships[0].Roles.Should().ContainInOrder(TenantRoles.Owner.Name); + memberships.Content.Value.Memberships[1].OrganizationId.Should().Be(organizationId); + memberships.Content.Value.Memberships[1].Ownership.Should().Be(OrganizationOwnership.Shared); + memberships.Content.Value.Memberships[1].Roles.Should() .ContainInOrder(TenantRoles.Owner.Name, TenantRoles.Member.Name); } @@ -493,7 +493,7 @@ public async Task WhenUnassignAssignedRole_ThenUnassigns() Name = "aname" }, req => req.SetJWTBearerToken(loginA.AccessToken)); - var organizationId = organization.Content.Value.Organization!.Id; + var organizationId = organization.Content.Value.Organization.Id; loginA = await ReAuthenticateUserAsync(loginA); await Api.PostAsync(new InviteMemberToOrganizationRequest { @@ -521,13 +521,13 @@ await Api.PutAsync(new UnassignRolesFromOrganizationRequest var memberships = await Api.GetAsync(new ListMembershipsForCallerRequest(), req => req.SetJWTBearerToken(loginB.AccessToken)); - memberships.Content.Value.Memberships!.Count.Should().Be(2); - memberships.Content.Value.Memberships![0].OrganizationId.Should().NotBeNull(); - memberships.Content.Value.Memberships![0].Ownership.Should().Be(OrganizationOwnership.Personal); - memberships.Content.Value.Memberships![0].Roles.Should().ContainInOrder(TenantRoles.Owner.Name); - memberships.Content.Value.Memberships![1].OrganizationId.Should().Be(organizationId); - memberships.Content.Value.Memberships![1].Ownership.Should().Be(OrganizationOwnership.Shared); - memberships.Content.Value.Memberships![1].Roles.Should().ContainInOrder(TenantRoles.Member.Name); + memberships.Content.Value.Memberships.Count.Should().Be(2); + memberships.Content.Value.Memberships[0].OrganizationId.Should().NotBeNull(); + memberships.Content.Value.Memberships[0].Ownership.Should().Be(OrganizationOwnership.Personal); + memberships.Content.Value.Memberships[0].Roles.Should().ContainInOrder(TenantRoles.Owner.Name); + memberships.Content.Value.Memberships[1].OrganizationId.Should().Be(organizationId); + memberships.Content.Value.Memberships[1].Ownership.Should().Be(OrganizationOwnership.Shared); + memberships.Content.Value.Memberships[1].Roles.Should().ContainInOrder(TenantRoles.Member.Name); } [Fact] @@ -541,7 +541,7 @@ public async Task WhenPromoteAndDemoteOwner_ThenDemotes() Name = "aname" }, req => req.SetJWTBearerToken(loginA.AccessToken)); - var organizationId = organization.Content.Value.Organization!.Id; + var organizationId = organization.Content.Value.Organization.Id; loginA = await ReAuthenticateUserAsync(loginA); await Api.PostAsync(new InviteMemberToOrganizationRequest { @@ -561,13 +561,13 @@ await Api.PutAsync(new AssignRolesToOrganizationRequest var memberships1 = await Api.GetAsync(new ListMembershipsForCallerRequest(), req => req.SetJWTBearerToken(loginB.AccessToken)); - memberships1.Content.Value.Memberships!.Count.Should().Be(2); - memberships1.Content.Value.Memberships![0].OrganizationId.Should().NotBeNull(); - memberships1.Content.Value.Memberships![0].Ownership.Should().Be(OrganizationOwnership.Personal); - memberships1.Content.Value.Memberships![0].Roles.Should().ContainInOrder(TenantRoles.Owner.Name); - memberships1.Content.Value.Memberships![1].OrganizationId.Should().Be(organizationId); - memberships1.Content.Value.Memberships![1].Ownership.Should().Be(OrganizationOwnership.Shared); - memberships1.Content.Value.Memberships![1].Roles.Should().ContainInOrder(TenantRoles.Owner.Name); + memberships1.Content.Value.Memberships.Count.Should().Be(2); + memberships1.Content.Value.Memberships[0].OrganizationId.Should().NotBeNull(); + memberships1.Content.Value.Memberships[0].Ownership.Should().Be(OrganizationOwnership.Personal); + memberships1.Content.Value.Memberships[0].Roles.Should().ContainInOrder(TenantRoles.Owner.Name); + memberships1.Content.Value.Memberships[1].OrganizationId.Should().Be(organizationId); + memberships1.Content.Value.Memberships[1].Ownership.Should().Be(OrganizationOwnership.Shared); + memberships1.Content.Value.Memberships[1].Roles.Should().ContainInOrder(TenantRoles.Owner.Name); await Api.PutAsync(new UnassignRolesFromOrganizationRequest { @@ -580,13 +580,13 @@ await Api.PutAsync(new UnassignRolesFromOrganizationRequest var memberships2 = await Api.GetAsync(new ListMembershipsForCallerRequest(), req => req.SetJWTBearerToken(loginB.AccessToken)); - memberships2.Content.Value.Memberships!.Count.Should().Be(2); - memberships2.Content.Value.Memberships![0].OrganizationId.Should().NotBeNull(); - memberships2.Content.Value.Memberships![0].Ownership.Should().Be(OrganizationOwnership.Personal); - memberships2.Content.Value.Memberships![0].Roles.Should().ContainInOrder(TenantRoles.Owner.Name); - memberships2.Content.Value.Memberships![1].OrganizationId.Should().Be(organizationId); - memberships2.Content.Value.Memberships![1].Ownership.Should().Be(OrganizationOwnership.Shared); - memberships2.Content.Value.Memberships![1].Roles.Should().ContainInOrder(TenantRoles.Member.Name); + memberships2.Content.Value.Memberships.Count.Should().Be(2); + memberships2.Content.Value.Memberships[0].OrganizationId.Should().NotBeNull(); + memberships2.Content.Value.Memberships[0].Ownership.Should().Be(OrganizationOwnership.Personal); + memberships2.Content.Value.Memberships[0].Roles.Should().ContainInOrder(TenantRoles.Owner.Name); + memberships2.Content.Value.Memberships[1].OrganizationId.Should().Be(organizationId); + memberships2.Content.Value.Memberships[1].Ownership.Should().Be(OrganizationOwnership.Shared); + memberships2.Content.Value.Memberships[1].Roles.Should().ContainInOrder(TenantRoles.Member.Name); } [Fact] @@ -600,7 +600,7 @@ public async Task WhenDeleteAndHasMembers_ThenReturnsError() Name = "aname" }, req => req.SetJWTBearerToken(loginA.AccessToken)); - var organizationId = organization.Content.Value.Organization!.Id; + var organizationId = organization.Content.Value.Organization.Id; loginA = await ReAuthenticateUserAsync(loginA); await Api.PostAsync(new InviteMemberToOrganizationRequest { @@ -628,7 +628,7 @@ public async Task WhenDeleteAndHasNoMembers_ThenDeletes() }, req => req.SetJWTBearerToken(loginA.AccessToken)); loginA = await ReAuthenticateUserAsync(loginA); - var organizationId = organization.Content.Value.Organization!.Id; + var organizationId = organization.Content.Value.Organization.Id; var result = await Api.DeleteAsync(new DeleteOrganizationRequest { @@ -658,7 +658,7 @@ public async Task WhenDeleteImageBehindTheAvatar_ThenRemovesAvatar() }, new PostFile(GetTestImage(), HttpConstants.ContentTypes.ImagePng, "afilename"), req => req.SetJWTBearerToken(login.AccessToken)); - var avatarUrl = organization.Content.Value.Organization!.AvatarUrl!; + var avatarUrl = organization.Content.Value.Organization.AvatarUrl!; var imageId = avatarUrl .Replace("https://localhost:5001/images/", string.Empty) .Replace("/download", string.Empty); @@ -675,7 +675,7 @@ await Api.DeleteAsync(new DeleteImageRequest Id = organizationId }, req => req.SetJWTBearerToken(login.AccessToken)); - result.Content.Value.Organization!.AvatarUrl.Should().BeNull(); + result.Content.Value.Organization.AvatarUrl.Should().BeNull(); } private static string CreateRandomEmailAddress() diff --git a/src/SaaStack.sln.DotSettings b/src/SaaStack.sln.DotSettings index d0daa2ee..6a838b06 100644 --- a/src/SaaStack.sln.DotSettings +++ b/src/SaaStack.sln.DotSettings @@ -19,6 +19,7 @@ SUGGESTION WARNING WARNING + True True <?xml version="1.0" encoding="utf-16"?><Profile name="SaaStack Full"><CSReformatCode>True</CSReformatCode><CSCodeStyleAttributes ArrangeVarStyle="True" ArrangeTypeAccessModifier="True" ArrangeTypeMemberAccessModifier="True" SortModifiers="True" ArrangeArgumentsStyle="True" RemoveRedundantParentheses="True" AddMissingParentheses="True" ArrangeBraces="True" ArrangeAttributes="True" ArrangeCodeBodyStyle="True" ArrangeTrailingCommas="True" ArrangeObjectCreation="True" ArrangeDefaultValue="True" ArrangeNamespaces="True" ArrangeNullCheckingPattern="True" /><CSArrangeQualifiers>True</CSArrangeQualifiers><CSFixBuiltinTypeReferences>True</CSFixBuiltinTypeReferences><CSharpFormatDocComments>True</CSharpFormatDocComments><CSReformatInactiveBranches>True</CSReformatInactiveBranches><CSOptimizeUsings><OptimizeUsings>True</OptimizeUsings></CSOptimizeUsings><CSShortenReferences>True</CSShortenReferences><HtmlReformatCode>True</HtmlReformatCode><FormatAttributeQuoteDescriptor>True</FormatAttributeQuoteDescriptor><Xaml.RemoveRedundantNamespaceAlias>True</Xaml.RemoveRedundantNamespaceAlias><AspOptimizeRegisterDirectives>True</AspOptimizeRegisterDirectives><RemoveCodeRedundancies>True</RemoveCodeRedundancies><CSUseAutoProperty>True</CSUseAutoProperty><CSMakeFieldReadonly>True</CSMakeFieldReadonly><CSMakeAutoPropertyGetOnly>True</CSMakeAutoPropertyGetOnly><IDEA_SETTINGS>&lt;profile version="1.0"&gt; &lt;option name="myName" value="SaaStack Full" /&gt; diff --git a/src/SubscriptionsInfrastructure.IntegrationTests/MigrationsApiSpec.cs b/src/SubscriptionsInfrastructure.IntegrationTests/MigrationsApiSpec.cs index 5af915fa..3b294099 100644 --- a/src/SubscriptionsInfrastructure.IntegrationTests/MigrationsApiSpec.cs +++ b/src/SubscriptionsInfrastructure.IntegrationTests/MigrationsApiSpec.cs @@ -33,7 +33,7 @@ public async Task WhenExportSubscriptionsToBeMigrated_ThenReturnsSubscriptions() var request = new ExportSubscriptionsToMigrateRequest(); var result = (await Api.GetAsync(request, req => req.SetHMACAuth(request, "asecret"))) - .Content.Value.Subscriptions!; + .Content.Value.Subscriptions; result.Count.Should().Be(1); result[0].BuyerId.Should().Be(login.Profile!.UserId); diff --git a/src/SubscriptionsInfrastructure.IntegrationTests/PricingApiSpec.cs b/src/SubscriptionsInfrastructure.IntegrationTests/PricingApiSpec.cs index 5d1791b6..362cc1f0 100644 --- a/src/SubscriptionsInfrastructure.IntegrationTests/PricingApiSpec.cs +++ b/src/SubscriptionsInfrastructure.IntegrationTests/PricingApiSpec.cs @@ -26,7 +26,7 @@ public GivenSimpleBillingProvider(WebApiSetup setup) : base(setup, Over [Fact] public async Task WhenListPricingPlans_ThenReturnsPlans() { - var result = (await Api.GetAsync(new ListPricingPlansRequest())).Content.Value.Plans!; + var result = (await Api.GetAsync(new ListPricingPlansRequest())).Content.Value.Plans; result.Eternally.Count.Should().Be(1); result.Eternally[0].Id.Should().Be(SinglePlanBillingStateInterpreter.Constants.DefaultPlanId); diff --git a/src/SubscriptionsInfrastructure.IntegrationTests/SubscriptionsApiSpec.cs b/src/SubscriptionsInfrastructure.IntegrationTests/SubscriptionsApiSpec.cs index 3d3e073d..d8258c9a 100644 --- a/src/SubscriptionsInfrastructure.IntegrationTests/SubscriptionsApiSpec.cs +++ b/src/SubscriptionsInfrastructure.IntegrationTests/SubscriptionsApiSpec.cs @@ -32,7 +32,7 @@ public GivenSimpleBillingProvider(WebApiSetup setup) : base(setup, Over [Fact] public async Task WhenListPricingPlans_ThenReturnsPlans() { - var result = (await Api.GetAsync(new ListPricingPlansRequest())).Content.Value.Plans!; + var result = (await Api.GetAsync(new ListPricingPlansRequest())).Content.Value.Plans; result.Eternally.Count.Should().Be(1); result.Eternally[0].Id.Should().Be(SinglePlanBillingStateInterpreter.Constants.DefaultPlanId); @@ -53,7 +53,7 @@ public async Task WhenGetSubscription_ThenReturns() var result = (await Api.GetAsync(new GetSubscriptionRequest { Id = login.DefaultOrganizationId! - }, req => req.SetJWTBearerToken(login.AccessToken))).Content.Value.Subscription!; + }, req => req.SetJWTBearerToken(login.AccessToken))).Content.Value.Subscription; result.BuyerId.Should().Be(login.Profile!.UserId); result.ProviderName.Should().Be(SinglePlanBillingStateInterpreter.Constants.ProviderName); @@ -73,7 +73,7 @@ public async Task WhenUpgradePlanByBuyer_ThenUpgradesToSamePlan() { Id = organizationId, PlanId = SinglePlanBillingStateInterpreter.Constants.DefaultPlanId - }, req => req.SetJWTBearerToken(login.AccessToken))).Content.Value.Subscription!; + }, req => req.SetJWTBearerToken(login.AccessToken))).Content.Value.Subscription; result.BuyerId.Should().Be(login.User.Id); result.OwningEntityId.Should().Be(organizationId); @@ -134,7 +134,7 @@ await Api.DeleteAsync(new ForceCancelSubscriptionRequest { Id = organizationId, PlanId = SinglePlanBillingStateInterpreter.Constants.DefaultPlanId - }, req => req.SetJWTBearerToken(loginB.AccessToken))).Content.Value.Subscription!; + }, req => req.SetJWTBearerToken(loginB.AccessToken))).Content.Value.Subscription; result.BuyerId.Should().Be(loginB.User.Id); result.OwningEntityId.Should().Be(organizationId); @@ -164,7 +164,7 @@ public async Task WhenCancel_ThenUnsubscribes() var result = (await Api.DeleteAsync(new CancelSubscriptionRequest { Id = organizationId - }, req => req.SetJWTBearerToken(loginA.AccessToken))).Content.Value.Subscription!; + }, req => req.SetJWTBearerToken(loginA.AccessToken))).Content.Value.Subscription; result.OwningEntityId.Should().Be(organizationId); result.BuyerReference.Should().Be(login.User.Id); @@ -193,7 +193,7 @@ public async Task WhenForceCancel_ThenUnsubscribes() var result = (await Api.DeleteAsync(new ForceCancelSubscriptionRequest { Id = organizationId - }, req => req.SetJWTBearerToken(@operator.AccessToken))).Content.Value.Subscription!; + }, req => req.SetJWTBearerToken(@operator.AccessToken))).Content.Value.Subscription; result.OwningEntityId.Should().Be(organizationId); result.BuyerReference.Should().Be(login.User.Id); @@ -225,7 +225,7 @@ public async Task WhenListBillingHistory_ThenReturnsHistory() Id = organizationId, FromUtc = fromUtc, ToUtc = null - }, req => req.SetJWTBearerToken(loginA.AccessToken))).Content.Value.Invoices!; + }, req => req.SetJWTBearerToken(loginA.AccessToken))).Content.Value.Invoices; result.Count.Should().Be(4); result[0].InvoicedOnUtc.Should().Be(new DateTime(2024, 06, 01, 0, 0, 0, DateTimeKind.Utc)); @@ -252,7 +252,7 @@ public async Task WhenTransferSubscriptionToOtherBillingAdmin_ThenTransfers() { Id = organizationId, UserId = loginB.User.Id - }, req => req.SetJWTBearerToken(loginA.AccessToken))).Content.Value.Subscription!; + }, req => req.SetJWTBearerToken(loginA.AccessToken))).Content.Value.Subscription; result.BuyerId.Should().Be(loginB.User.Id); result.OwningEntityId.Should().Be(organizationId); @@ -297,7 +297,7 @@ await Api.PutAsync(new AssignRolesToOrganizationRequest Name = "aname" }, req => req.SetJWTBearerToken(login.AccessToken)); - var organizationId = organization.Content.Value.Organization!.Id; + var organizationId = organization.Content.Value.Organization.Id; login = await ReAuthenticateUserAsync(login); return (login, organizationId); diff --git a/src/TestingStubApiHost/Api/StubFlagsmithApi.cs b/src/TestingStubApiHost/Api/StubFlagsmithApi.cs index d425d68c..dddd3748 100644 --- a/src/TestingStubApiHost/Api/StubFlagsmithApi.cs +++ b/src/TestingStubApiHost/Api/StubFlagsmithApi.cs @@ -49,9 +49,9 @@ private static List GetAllFlags() var counter = 1000; return allFlags.Select(f => new FlagsmithFlag { - Id = null, + Id = ++counter, Enabled = false, - Value = null, + Value = "avalue", Feature = new FlagsmithFeature { Id = ++counter, diff --git a/src/TestingStubApiHost/Api/StubTwilioApi.cs b/src/TestingStubApiHost/Api/StubTwilioApi.cs index 75307de6..7bc949d1 100644 --- a/src/TestingStubApiHost/Api/StubTwilioApi.cs +++ b/src/TestingStubApiHost/Api/StubTwilioApi.cs @@ -42,7 +42,8 @@ public async Task> SendMessage(TwilioS new PostResult(new TwilioSendResponse { Sid = receiptId, - Status = TwilioMessageStatus.Queued + Status = TwilioMessageStatus.Queued, + Body = request.Body! }); } } \ No newline at end of file diff --git a/src/Tools.Analyzers.NonPlatform.UnitTests/ApiLayerAnalyzerSpec.cs b/src/Tools.Analyzers.NonPlatform.UnitTests/ApiLayerAnalyzerSpec.cs index fc8c174f..7c1fd069 100644 --- a/src/Tools.Analyzers.NonPlatform.UnitTests/ApiLayerAnalyzerSpec.cs +++ b/src/Tools.Analyzers.NonPlatform.UnitTests/ApiLayerAnalyzerSpec.cs @@ -2414,11 +2414,13 @@ public async Task WhenAnyPropertyHasNoSetter_ThenAlerts() namespace Infrastructure.Web.Api.Operations.Shared.Test; public class AResponse : IWebResponse { - public string? AProperty { get; } + public string? AProperty1 { get; } + + public required string AProperty2 { get; set; } }"; await Verify.DiagnosticExists( - ApiLayerAnalyzer.Rule044, input, 7, 20, "AProperty"); + ApiLayerAnalyzer.Rule044, input, 7, 20, "AProperty1"); } } @@ -2456,6 +2458,21 @@ public class AResponse : IWebResponse await Verify.NoDiagnosticExists(input); } + + [Fact] + public async Task WhenAnyPropertyReferenceTypeIsRequired_ThenNoAlert() + { + const string input = @" +using System; +using Infrastructure.Web.Api.Interfaces; +namespace Infrastructure.Web.Api.Operations.Shared.Test; +public class AResponse : IWebResponse +{ + public required string AProperty { get; set; } +}"; + + await Verify.NoDiagnosticExists(input); + } } } } @@ -2469,7 +2486,7 @@ public class TestResponse : IWebResponse; [UsedImplicitly] public class TestSearchResponse : IWebSearchResponse { - public SearchResultMetadata? Metadata { get; set; } + public SearchResultMetadata Metadata { get; set; } = new(); } [UsedImplicitly] diff --git a/src/UserProfilesInfrastructure.IntegrationTests/UserProfileApiSpec.cs b/src/UserProfilesInfrastructure.IntegrationTests/UserProfileApiSpec.cs index f5bb42eb..3e7d4a9f 100644 --- a/src/UserProfilesInfrastructure.IntegrationTests/UserProfileApiSpec.cs +++ b/src/UserProfilesInfrastructure.IntegrationTests/UserProfileApiSpec.cs @@ -37,7 +37,7 @@ public async Task WhenChangeProfile_ThenChanges() Timezone = Timezones.Sydney.ToString() }, req => req.SetJWTBearerToken(login.AccessToken)); - result.Content.Value.Profile!.Name.FirstName.Should().Be("anewfirstname"); + result.Content.Value.Profile.Name.FirstName.Should().Be("anewfirstname"); result.Content.Value.Profile.Name.LastName.Should().Be("anewlastname"); result.Content.Value.Profile.DisplayName.Should().Be("anewdisplayname"); result.Content.Value.Profile.Timezone.Should().Be(Timezones.Sydney.ToString()); @@ -79,7 +79,7 @@ public async Task WhenChangeContactAddress_ThenChanges() Zip = "anewzipcode" }, req => req.SetJWTBearerToken(login.AccessToken)); - result.Content.Value.Profile!.Address.Line1.Should().Be("anewline1"); + result.Content.Value.Profile.Address.Line1.Should().Be("anewline1"); result.Content.Value.Profile.Address.Line2.Should().Be("anewline2"); result.Content.Value.Profile.Address.Line3.Should().Be("anewline3"); result.Content.Value.Profile.Address.City.Should().Be("anewcity"); @@ -135,7 +135,7 @@ public async Task WhenChangeAvatar_ThenChanges() }, new PostFile(GetTestImage(), HttpConstants.ContentTypes.ImagePng, "afilename"), req => req.SetJWTBearerToken(login.AccessToken)); - result.Content.Value.Profile!.AvatarUrl.Should().StartWith("https://localhost:5001/images/image_"); + result.Content.Value.Profile.AvatarUrl.Should().StartWith("https://localhost:5001/images/image_"); } [Fact] @@ -154,7 +154,7 @@ await Api.PutAsync(new ChangeProfileAvatarRequest UserId = login.User.Id }, req => req.SetJWTBearerToken(login.AccessToken)); - result.Content.Value.Profile!.AvatarUrl.Should().BeNull(); + result.Content.Value.Profile.AvatarUrl.Should().BeNull(); } [Fact] @@ -162,7 +162,7 @@ public async Task WhenGetProfileForCallerForAnonymous_ThenNotAuthenticated() { var result = await Api.GetAsync(new GetProfileForCallerRequest()); - result.Content.Value.Profile!.IsAuthenticated.Should().BeFalse(); + result.Content.Value.Profile.IsAuthenticated.Should().BeFalse(); result.Content.Value.Profile.Id.Should().Be(CallerConstants.AnonymousUserId); result.Content.Value.Profile.UserId.Should().Be(CallerConstants.AnonymousUserId); result.Content.Value.Profile.DefaultOrganizationId.Should().BeNull(); @@ -176,7 +176,7 @@ public async Task WhenGetProfileForCallerForAuthenticated_ThenAuthenticated() var result = await Api.GetAsync(new GetProfileForCallerRequest(), req => req.SetJWTBearerToken(login.AccessToken)); - result.Content.Value.Profile!.IsAuthenticated.Should().BeTrue(); + result.Content.Value.Profile.IsAuthenticated.Should().BeTrue(); result.Content.Value.Profile.Id.Should().NotBeNullOrEmpty(); result.Content.Value.Profile.UserId.Should().Be(login.User.Id); result.Content.Value.Profile.DefaultOrganizationId.Should().NotBeNullOrEmpty(); @@ -198,7 +198,7 @@ public async Task WhenDeleteImageBehindTheAvatar_ThenRemovesAvatar() }, new PostFile(GetTestImage(), HttpConstants.ContentTypes.ImagePng, "afilename"), req => req.SetJWTBearerToken(login.AccessToken)); - var avatarUrl = profile.Content.Value.Profile!.AvatarUrl!; + var avatarUrl = profile.Content.Value.Profile.AvatarUrl!; var imageId = avatarUrl .Replace("https://localhost:5001/images/", string.Empty) .Replace("/download", string.Empty); @@ -213,7 +213,7 @@ await Api.DeleteAsync(new DeleteImageRequest var result = await Api.GetAsync(new GetProfileForCallerRequest(), req => req.SetJWTBearerToken(login.AccessToken)); - result.Content.Value.Profile!.AvatarUrl.Should().BeNull(); + result.Content.Value.Profile.AvatarUrl.Should().BeNull(); } private static void OverrideDependencies(IServiceCollection services) diff --git a/src/WebsiteHost/Application/AuthenticationApplication.cs b/src/WebsiteHost/Application/AuthenticationApplication.cs index e56dc317..22af08f9 100644 --- a/src/WebsiteHost/Application/AuthenticationApplication.cs +++ b/src/WebsiteHost/Application/AuthenticationApplication.cs @@ -85,11 +85,11 @@ internal static class AuthenticationConversionExtensions { public static AuthenticateTokens ToTokens(this AuthenticateResponse response) { - return response.Tokens!; + return response.Tokens; } public static AuthenticateTokens ToTokens(this RefreshTokenResponse response) { - return response.Tokens!; + return response.Tokens; } } \ No newline at end of file diff --git a/src/WebsiteHost/Application/FeatureFlagsApplication.cs b/src/WebsiteHost/Application/FeatureFlagsApplication.cs index 257b635d..311985a5 100644 --- a/src/WebsiteHost/Application/FeatureFlagsApplication.cs +++ b/src/WebsiteHost/Application/FeatureFlagsApplication.cs @@ -49,6 +49,6 @@ public async Task> GetFeatureFlagForCallerAsync(ICall return retrieved.Error.ToError(); } - return retrieved.Value.Flag!; + return retrieved.Value.Flag; } } \ No newline at end of file