Many updates for OAP

This commit is contained in:
2024-04-04 09:25:30 -05:00
parent 440ccba5d2
commit ff41d5203e
69 changed files with 316 additions and 174 deletions

View File

@@ -0,0 +1,33 @@
// <auto-generated>
// DO NOT EDIT: generated by fsdgencsharp
// </auto-generated>
using System;
using System.Collections.Generic;
using Facility.Core;
namespace OapApi.v1.Client
{
[System.CodeDom.Compiler.GeneratedCode("fsdgencsharp", "")]
public sealed partial class ApplicationChangeSetDto : ServiceDto<ApplicationChangeSetDto>
{
/// <summary>
/// Creates an instance.
/// </summary>
public ApplicationChangeSetDto()
{
}
/// <summary>
/// The JSON serializer.
/// </summary>
protected override JsonServiceSerializer JsonSerializer => SystemTextJsonServiceSerializer.Instance;
/// <summary>
/// Determines if two DTOs are equivalent.
/// </summary>
public override bool IsEquivalentTo(ApplicationChangeSetDto other)
{
return other != null;
}
}
}

View File

@@ -0,0 +1,60 @@
// <auto-generated>
// DO NOT EDIT: generated by fsdgencsharp
// </auto-generated>
using System;
using System.Collections.Generic;
using Facility.Core;
namespace OapApi.v1.Client
{
[System.CodeDom.Compiler.GeneratedCode("fsdgencsharp", "")]
public sealed partial class ApplicationCreateSetDto : ServiceDto<ApplicationCreateSetDto>
{
/// <summary>
/// Creates an instance.
/// </summary>
public ApplicationCreateSetDto()
{
}
/// <summary>
/// Terms a user must accept to start an application.
/// </summary>
public ApplicationTermsCreateSetDto Terms { get; set; }
/// <summary>
/// The JSON serializer.
/// </summary>
protected override JsonServiceSerializer JsonSerializer => SystemTextJsonServiceSerializer.Instance;
/// <summary>
/// Determines if two DTOs are equivalent.
/// </summary>
public override bool IsEquivalentTo(ApplicationCreateSetDto other)
{
return other != null &&
ServiceDataUtility.AreEquivalentDtos(Terms, other.Terms);
}
/// <summary>
/// Validates the DTO.
/// </summary>
public override bool Validate(out string errorMessage)
{
errorMessage = GetValidationErrorMessage();
return errorMessage == null;
}
private string GetValidationErrorMessage()
{
if (Terms == null)
return ServiceDataUtility.GetRequiredFieldErrorMessage("terms");
string errorMessage;
if (!ServiceDataUtility.ValidateFieldValue(Terms, "terms", out errorMessage))
return errorMessage;
return null;
}
}
}

View File

@@ -0,0 +1,54 @@
// <auto-generated>
// DO NOT EDIT: generated by fsdgencsharp
// </auto-generated>
using System;
using System.Collections.Generic;
using Facility.Core;
namespace OapApi.v1.Client
{
/// <summary>
/// An application.
/// </summary>
[System.CodeDom.Compiler.GeneratedCode("fsdgencsharp", "")]
public sealed partial class ApplicationDto : ServiceDto<ApplicationDto>
{
/// <summary>
/// Creates an instance.
/// </summary>
public ApplicationDto()
{
}
/// <summary>
/// A unique identifier for the application.
/// </summary>
public string Id { get; set; }
/// <summary>
/// The current status of this application.
/// </summary>
public ApplicationStatus? Status { get; set; }
/// <summary>
/// Terms the user must accept to start, continue an accept an application.
/// </summary>
public ApplicationTermsDto Terms { get; set; }
/// <summary>
/// The JSON serializer.
/// </summary>
protected override JsonServiceSerializer JsonSerializer => SystemTextJsonServiceSerializer.Instance;
/// <summary>
/// Determines if two DTOs are equivalent.
/// </summary>
public override bool IsEquivalentTo(ApplicationDto other)
{
return other != null &&
Id == other.Id &&
Status == other.Status &&
ServiceDataUtility.AreEquivalentDtos(Terms, other.Terms);
}
}
}

View File

@@ -0,0 +1,112 @@
// <auto-generated>
// DO NOT EDIT: generated by fsdgencsharp
// </auto-generated>
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using Facility.Core;
namespace OapApi.v1.Client
{
[System.CodeDom.Compiler.GeneratedCode("fsdgencsharp", "")]
[Newtonsoft.Json.JsonConverter(typeof(ApplicationStatusJsonConverter))]
[System.Text.Json.Serialization.JsonConverter(typeof(ApplicationStatusSystemTextJsonConverter))]
public partial struct ApplicationStatus : IEquatable<ApplicationStatus>
{
public static readonly ApplicationStatus InProgress = new ApplicationStatus(Strings.InProgress);
public static readonly ApplicationStatus Submitted = new ApplicationStatus(Strings.Submitted);
/// <summary>
/// Creates an instance.
/// </summary>
public ApplicationStatus(string value) => m_value = value;
/// <summary>
/// Converts the instance to a string.
/// </summary>
public override string ToString() => m_value != null && s_valueCache.TryGetValue(m_value, out var cachedValue) ? cachedValue : m_value ?? "";
/// <summary>
/// Checks for equality.
/// </summary>
public bool Equals(ApplicationStatus other) => StringComparer.OrdinalIgnoreCase.Equals(m_value ?? "", other.m_value ?? "");
/// <summary>
/// Checks for equality.
/// </summary>
public override bool Equals(object obj) => obj is ApplicationStatus && Equals((ApplicationStatus) obj);
/// <summary>
/// Gets the hash code.
/// </summary>
public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(m_value ?? "");
/// <summary>
/// Checks for equality.
/// </summary>
public static bool operator ==(ApplicationStatus left, ApplicationStatus right) => left.Equals(right);
/// <summary>
/// Checks for inequality.
/// </summary>
public static bool operator !=(ApplicationStatus left, ApplicationStatus right) => !left.Equals(right);
/// <summary>
/// Returns true if the instance is equal to one of the defined values.
/// </summary>
public bool IsDefined() => m_value != null && s_valueCache.ContainsKey(m_value);
/// <summary>
/// Returns all of the defined values.
/// </summary>
public static IReadOnlyList<ApplicationStatus> GetValues() => s_values;
/// <summary>
/// Provides string constants for defined values.
/// </summary>
public static class Strings
{
public const string InProgress = "InProgress";
public const string Submitted = "Submitted";
}
/// <summary>
/// Used for serialization.
/// </summary>
public sealed class ApplicationStatusJsonConverter : ServiceEnumJsonConverter<ApplicationStatus>
{
/// <summary>
/// Creates the value from a string.
/// </summary>
protected override ApplicationStatus CreateCore(string value) => new ApplicationStatus(value);
}
/// <summary>
/// Used for serialization.
/// </summary>
public sealed class ApplicationStatusSystemTextJsonConverter : ServiceEnumSystemTextJsonConverter<ApplicationStatus>
{
/// <summary>
/// Creates the value from a string.
/// </summary>
protected override ApplicationStatus CreateCore(string value) => new ApplicationStatus(value);
}
private static readonly ReadOnlyCollection<ApplicationStatus> s_values = new ReadOnlyCollection<ApplicationStatus>(
new[]
{
InProgress,
Submitted,
});
private static readonly IReadOnlyDictionary<string, string> s_valueCache = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
{
{ Strings.InProgress, Strings.InProgress },
{ Strings.Submitted, Strings.Submitted },
};
private readonly string m_value;
}
}

View File

@@ -0,0 +1,53 @@
// <auto-generated>
// DO NOT EDIT: generated by fsdgencsharp
// </auto-generated>
using System;
using System.Collections.Generic;
using Facility.Core;
namespace OapApi.v1.Client
{
[System.CodeDom.Compiler.GeneratedCode("fsdgencsharp", "")]
public sealed partial class ApplicationTermsCreateSetDto : ServiceDto<ApplicationTermsCreateSetDto>
{
/// <summary>
/// Creates an instance.
/// </summary>
public ApplicationTermsCreateSetDto()
{
}
public bool? HasReadInstructions { get; set; }
/// <summary>
/// The JSON serializer.
/// </summary>
protected override JsonServiceSerializer JsonSerializer => SystemTextJsonServiceSerializer.Instance;
/// <summary>
/// Determines if two DTOs are equivalent.
/// </summary>
public override bool IsEquivalentTo(ApplicationTermsCreateSetDto other)
{
return other != null &&
HasReadInstructions == other.HasReadInstructions;
}
/// <summary>
/// Validates the DTO.
/// </summary>
public override bool Validate(out string errorMessage)
{
errorMessage = GetValidationErrorMessage();
return errorMessage == null;
}
private string GetValidationErrorMessage()
{
if (HasReadInstructions == null)
return ServiceDataUtility.GetRequiredFieldErrorMessage("hasReadInstructions");
return null;
}
}
}

View File

@@ -0,0 +1,36 @@
// <auto-generated>
// DO NOT EDIT: generated by fsdgencsharp
// </auto-generated>
using System;
using System.Collections.Generic;
using Facility.Core;
namespace OapApi.v1.Client
{
[System.CodeDom.Compiler.GeneratedCode("fsdgencsharp", "")]
public sealed partial class ApplicationTermsDto : ServiceDto<ApplicationTermsDto>
{
/// <summary>
/// Creates an instance.
/// </summary>
public ApplicationTermsDto()
{
}
public bool? HasReadInstructions { get; set; }
/// <summary>
/// The JSON serializer.
/// </summary>
protected override JsonServiceSerializer JsonSerializer => SystemTextJsonServiceSerializer.Instance;
/// <summary>
/// Determines if two DTOs are equivalent.
/// </summary>
public override bool IsEquivalentTo(ApplicationTermsDto other)
{
return other != null &&
HasReadInstructions == other.HasReadInstructions;
}
}
}

View File

@@ -0,0 +1,60 @@
// <auto-generated>
// DO NOT EDIT: generated by fsdgencsharp
// </auto-generated>
using System;
using System.Collections.Generic;
using Facility.Core;
namespace OapApi.v1.Client
{
/// <summary>
/// Request for CreateApplication.
/// </summary>
[System.CodeDom.Compiler.GeneratedCode("fsdgencsharp", "")]
public sealed partial class CreateApplicationRequestDto : ServiceDto<CreateApplicationRequestDto>
{
/// <summary>
/// Creates an instance.
/// </summary>
public CreateApplicationRequestDto()
{
}
/// <summary>
/// The application to create.
/// </summary>
public ApplicationCreateSetDto ApplicationCreateSet { get; set; }
/// <summary>
/// The JSON serializer.
/// </summary>
protected override JsonServiceSerializer JsonSerializer => SystemTextJsonServiceSerializer.Instance;
/// <summary>
/// Determines if two DTOs are equivalent.
/// </summary>
public override bool IsEquivalentTo(CreateApplicationRequestDto other)
{
return other != null &&
ServiceDataUtility.AreEquivalentDtos(ApplicationCreateSet, other.ApplicationCreateSet);
}
/// <summary>
/// Validates the DTO.
/// </summary>
public override bool Validate(out string errorMessage)
{
errorMessage = GetValidationErrorMessage();
return errorMessage == null;
}
private string GetValidationErrorMessage()
{
string errorMessage;
if (!ServiceDataUtility.ValidateFieldValue(ApplicationCreateSet, "applicationCreateSet", out errorMessage))
return errorMessage;
return null;
}
}
}

View File

@@ -0,0 +1,42 @@
// <auto-generated>
// DO NOT EDIT: generated by fsdgencsharp
// </auto-generated>
using System;
using System.Collections.Generic;
using Facility.Core;
namespace OapApi.v1.Client
{
/// <summary>
/// Response for CreateApplication.
/// </summary>
[System.CodeDom.Compiler.GeneratedCode("fsdgencsharp", "")]
public sealed partial class CreateApplicationResponseDto : ServiceDto<CreateApplicationResponseDto>
{
/// <summary>
/// Creates an instance.
/// </summary>
public CreateApplicationResponseDto()
{
}
/// <summary>
/// The created application.
/// </summary>
public ApplicationDto Application { get; set; }
/// <summary>
/// The JSON serializer.
/// </summary>
protected override JsonServiceSerializer JsonSerializer => SystemTextJsonServiceSerializer.Instance;
/// <summary>
/// Determines if two DTOs are equivalent.
/// </summary>
public override bool IsEquivalentTo(CreateApplicationResponseDto other)
{
return other != null &&
ServiceDataUtility.AreEquivalentDtos(Application, other.Application);
}
}
}

View File

@@ -0,0 +1,49 @@
// <auto-generated>
// DO NOT EDIT: generated by fsdgencsharp
// </auto-generated>
using System;
using System.Threading;
using System.Threading.Tasks;
using Facility.Core;
namespace OapApi.v1.Client
{
/// <summary>
/// A delegating implementation of OapApiV1.
/// </summary>
[System.CodeDom.Compiler.GeneratedCode("fsdgencsharp", "")]
public partial class DelegatingOapApiV1 : IOapApiV1
{
/// <summary>
/// Creates an instance with the specified delegator.
/// </summary>
public DelegatingOapApiV1(ServiceDelegator delegator) =>
m_delegator = delegator ?? throw new ArgumentNullException(nameof(delegator));
/// <summary>
/// Gets applications for the current user.
/// </summary>
public virtual async Task<ServiceResult<GetApplicationsResponseDto>> GetApplicationsAsync(GetApplicationsRequestDto request, CancellationToken cancellationToken = default) =>
(await m_delegator(OapApiV1Methods.GetApplications, request, cancellationToken).ConfigureAwait(false)).Cast<GetApplicationsResponseDto>();
/// <summary>
/// Creates a new application for the current user.
/// </summary>
public virtual async Task<ServiceResult<CreateApplicationResponseDto>> CreateApplicationAsync(CreateApplicationRequestDto request, CancellationToken cancellationToken = default) =>
(await m_delegator(OapApiV1Methods.CreateApplication, request, cancellationToken).ConfigureAwait(false)).Cast<CreateApplicationResponseDto>();
/// <summary>
/// Gets the specified application for the current user.
/// </summary>
public virtual async Task<ServiceResult<GetApplicationResponseDto>> GetApplicationAsync(GetApplicationRequestDto request, CancellationToken cancellationToken = default) =>
(await m_delegator(OapApiV1Methods.GetApplication, request, cancellationToken).ConfigureAwait(false)).Cast<GetApplicationResponseDto>();
/// <summary>
/// Updates the application.
/// </summary>
public virtual async Task<ServiceResult<UpdateApplicationResponseDto>> UpdateApplicationAsync(UpdateApplicationRequestDto request, CancellationToken cancellationToken = default) =>
(await m_delegator(OapApiV1Methods.UpdateApplication, request, cancellationToken).ConfigureAwait(false)).Cast<UpdateApplicationResponseDto>();
private readonly ServiceDelegator m_delegator;
}
}

View File

@@ -0,0 +1,42 @@
// <auto-generated>
// DO NOT EDIT: generated by fsdgencsharp
// </auto-generated>
using System;
using System.Collections.Generic;
using Facility.Core;
namespace OapApi.v1.Client
{
/// <summary>
/// Request for GetApplication.
/// </summary>
[System.CodeDom.Compiler.GeneratedCode("fsdgencsharp", "")]
public sealed partial class GetApplicationRequestDto : ServiceDto<GetApplicationRequestDto>
{
/// <summary>
/// Creates an instance.
/// </summary>
public GetApplicationRequestDto()
{
}
/// <summary>
/// The widget ID.
/// </summary>
public string Id { get; set; }
/// <summary>
/// The JSON serializer.
/// </summary>
protected override JsonServiceSerializer JsonSerializer => SystemTextJsonServiceSerializer.Instance;
/// <summary>
/// Determines if two DTOs are equivalent.
/// </summary>
public override bool IsEquivalentTo(GetApplicationRequestDto other)
{
return other != null &&
Id == other.Id;
}
}
}

View File

@@ -0,0 +1,48 @@
// <auto-generated>
// DO NOT EDIT: generated by fsdgencsharp
// </auto-generated>
using System;
using System.Collections.Generic;
using Facility.Core;
namespace OapApi.v1.Client
{
/// <summary>
/// Response for GetApplication.
/// </summary>
[System.CodeDom.Compiler.GeneratedCode("fsdgencsharp", "")]
public sealed partial class GetApplicationResponseDto : ServiceDto<GetApplicationResponseDto>
{
/// <summary>
/// Creates an instance.
/// </summary>
public GetApplicationResponseDto()
{
}
/// <summary>
/// The requested widget.
/// </summary>
public ApplicationDto Application { get; set; }
public string ETag { get; set; }
public bool? NotModified { get; set; }
/// <summary>
/// The JSON serializer.
/// </summary>
protected override JsonServiceSerializer JsonSerializer => SystemTextJsonServiceSerializer.Instance;
/// <summary>
/// Determines if two DTOs are equivalent.
/// </summary>
public override bool IsEquivalentTo(GetApplicationResponseDto other)
{
return other != null &&
ServiceDataUtility.AreEquivalentDtos(Application, other.Application) &&
ETag == other.ETag &&
NotModified == other.NotModified;
}
}
}

View File

@@ -0,0 +1,54 @@
// <auto-generated>
// DO NOT EDIT: generated by fsdgencsharp
// </auto-generated>
using System;
using System.Collections.Generic;
using Facility.Core;
namespace OapApi.v1.Client
{
/// <summary>
/// Request for GetApplications.
/// </summary>
[System.CodeDom.Compiler.GeneratedCode("fsdgencsharp", "")]
public sealed partial class GetApplicationsRequestDto : ServiceDto<GetApplicationsRequestDto>
{
/// <summary>
/// Creates an instance.
/// </summary>
public GetApplicationsRequestDto()
{
}
/// <summary>
/// Filter applications by the given status.
/// </summary>
public ApplicationStatus? Status { get; set; }
/// <summary>
/// The limit of returned results.
/// </summary>
public int? Limit { get; set; }
/// <summary>
/// The token presenting the next page of applications to get.
/// </summary>
public string NextToken { get; set; }
/// <summary>
/// The JSON serializer.
/// </summary>
protected override JsonServiceSerializer JsonSerializer => SystemTextJsonServiceSerializer.Instance;
/// <summary>
/// Determines if two DTOs are equivalent.
/// </summary>
public override bool IsEquivalentTo(GetApplicationsRequestDto other)
{
return other != null &&
Status == other.Status &&
Limit == other.Limit &&
NextToken == other.NextToken;
}
}
}

View File

@@ -0,0 +1,60 @@
// <auto-generated>
// DO NOT EDIT: generated by fsdgencsharp
// </auto-generated>
using System;
using System.Collections.Generic;
using Facility.Core;
namespace OapApi.v1.Client
{
/// <summary>
/// Response for GetApplications.
/// </summary>
[System.CodeDom.Compiler.GeneratedCode("fsdgencsharp", "")]
public sealed partial class GetApplicationsResponseDto : ServiceDto<GetApplicationsResponseDto>
{
/// <summary>
/// Creates an instance.
/// </summary>
public GetApplicationsResponseDto()
{
}
/// <summary>
/// The applications.
/// </summary>
public IReadOnlyList<ApplicationDto> Applications { get; set; }
/// <summary>
/// The total number of applications.
/// </summary>
public long? Total { get; set; }
/// <summary>
/// The token representing the next page of results.
/// </summary>
public string NextToken { get; set; }
/// <summary>
/// True if this is the last page of results, false otherwise.
/// </summary>
public bool? IsLastPage { get; set; }
/// <summary>
/// The JSON serializer.
/// </summary>
protected override JsonServiceSerializer JsonSerializer => SystemTextJsonServiceSerializer.Instance;
/// <summary>
/// Determines if two DTOs are equivalent.
/// </summary>
public override bool IsEquivalentTo(GetApplicationsResponseDto other)
{
return other != null &&
ServiceDataUtility.AreEquivalentFieldValues(Applications, other.Applications) &&
Total == other.Total &&
NextToken == other.NextToken &&
IsLastPage == other.IsLastPage;
}
}
}

View File

@@ -0,0 +1,53 @@
// <auto-generated>
// DO NOT EDIT: generated by fsdgencsharp
// </auto-generated>
using System;
using System.Threading;
using System.Threading.Tasks;
using Facility.Core;
using Facility.Core.Http;
namespace OapApi.v1.Client.Http
{
[System.CodeDom.Compiler.GeneratedCode("fsdgencsharp", "")]
public sealed partial class HttpClientOapApiV1 : HttpClientService, IOapApiV1
{
/// <summary>
/// Creates the service.
/// </summary>
public HttpClientOapApiV1(HttpClientServiceSettings settings = null)
: base(settings, s_defaults)
{
}
/// <summary>
/// Gets applications for the current user.
/// </summary>
public Task<ServiceResult<GetApplicationsResponseDto>> GetApplicationsAsync(GetApplicationsRequestDto request, CancellationToken cancellationToken = default) =>
TrySendRequestAsync(OapApiV1HttpMapping.GetApplicationsMapping, request, cancellationToken);
/// <summary>
/// Creates a new application for the current user.
/// </summary>
public Task<ServiceResult<CreateApplicationResponseDto>> CreateApplicationAsync(CreateApplicationRequestDto request, CancellationToken cancellationToken = default) =>
TrySendRequestAsync(OapApiV1HttpMapping.CreateApplicationMapping, request, cancellationToken);
/// <summary>
/// Gets the specified application for the current user.
/// </summary>
public Task<ServiceResult<GetApplicationResponseDto>> GetApplicationAsync(GetApplicationRequestDto request, CancellationToken cancellationToken = default) =>
TrySendRequestAsync(OapApiV1HttpMapping.GetApplicationMapping, request, cancellationToken);
/// <summary>
/// Updates the application.
/// </summary>
public Task<ServiceResult<UpdateApplicationResponseDto>> UpdateApplicationAsync(UpdateApplicationRequestDto request, CancellationToken cancellationToken = default) =>
TrySendRequestAsync(OapApiV1HttpMapping.UpdateApplicationMapping, request, cancellationToken);
private static readonly HttpClientServiceDefaults s_defaults = new HttpClientServiceDefaults
{
BaseUri = new Uri("https://oaprotection.org/api/v1"),
ContentSerializer = HttpContentSerializer.Create(SystemTextJsonServiceSerializer.Instance),
};
}
}

View File

@@ -0,0 +1,80 @@
// <auto-generated>
// DO NOT EDIT: generated by fsdgencsharp
// </auto-generated>
using System;
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using Facility.Core;
using Facility.Core.Http;
namespace OapApi.v1.Client.Http
{
[System.CodeDom.Compiler.GeneratedCode("fsdgencsharp", "")]
public sealed partial class OapApiV1HttpHandler : ServiceHttpHandler
{
/// <summary>
/// Creates the handler.
/// </summary>
public OapApiV1HttpHandler(IOapApiV1 service, ServiceHttpHandlerSettings settings = null)
: base(settings, s_defaults)
{
m_service = service ?? throw new ArgumentNullException(nameof(service));
}
/// <summary>
/// Creates the handler.
/// </summary>
public OapApiV1HttpHandler(Func<HttpRequestMessage, IOapApiV1> getService, ServiceHttpHandlerSettings settings = null)
: base(settings, s_defaults)
{
m_getService = getService ?? throw new ArgumentNullException(nameof(getService));
}
/// <summary>
/// Attempts to handle the HTTP request.
/// </summary>
public override async Task<HttpResponseMessage> TryHandleHttpRequestAsync(HttpRequestMessage httpRequest, CancellationToken cancellationToken = default)
{
return await AdaptTask(TryHandleGetApplicationsAsync(httpRequest, cancellationToken)).ConfigureAwait(true) ??
await AdaptTask(TryHandleCreateApplicationAsync(httpRequest, cancellationToken)).ConfigureAwait(true) ??
await AdaptTask(TryHandleGetApplicationAsync(httpRequest, cancellationToken)).ConfigureAwait(true) ??
await AdaptTask(TryHandleUpdateApplicationAsync(httpRequest, cancellationToken)).ConfigureAwait(true);
}
/// <summary>
/// Gets applications for the current user.
/// </summary>
public Task<HttpResponseMessage> TryHandleGetApplicationsAsync(HttpRequestMessage httpRequest, CancellationToken cancellationToken = default) =>
TryHandleServiceMethodAsync(OapApiV1HttpMapping.GetApplicationsMapping, httpRequest, GetService(httpRequest).GetApplicationsAsync, cancellationToken);
/// <summary>
/// Creates a new application for the current user.
/// </summary>
public Task<HttpResponseMessage> TryHandleCreateApplicationAsync(HttpRequestMessage httpRequest, CancellationToken cancellationToken = default) =>
TryHandleServiceMethodAsync(OapApiV1HttpMapping.CreateApplicationMapping, httpRequest, GetService(httpRequest).CreateApplicationAsync, cancellationToken);
/// <summary>
/// Gets the specified application for the current user.
/// </summary>
public Task<HttpResponseMessage> TryHandleGetApplicationAsync(HttpRequestMessage httpRequest, CancellationToken cancellationToken = default) =>
TryHandleServiceMethodAsync(OapApiV1HttpMapping.GetApplicationMapping, httpRequest, GetService(httpRequest).GetApplicationAsync, cancellationToken);
/// <summary>
/// Updates the application.
/// </summary>
public Task<HttpResponseMessage> TryHandleUpdateApplicationAsync(HttpRequestMessage httpRequest, CancellationToken cancellationToken = default) =>
TryHandleServiceMethodAsync(OapApiV1HttpMapping.UpdateApplicationMapping, httpRequest, GetService(httpRequest).UpdateApplicationAsync, cancellationToken);
private IOapApiV1 GetService(HttpRequestMessage httpRequest) => m_service ?? m_getService(httpRequest);
private static readonly ServiceHttpHandlerDefaults s_defaults = new ServiceHttpHandlerDefaults
{
ContentSerializer = HttpContentSerializer.Create(SystemTextJsonServiceSerializer.Instance),
};
private readonly IOapApiV1 m_service;
private readonly Func<HttpRequestMessage, IOapApiV1> m_getService;
}
}

View File

@@ -0,0 +1,186 @@
// <auto-generated>
// DO NOT EDIT: generated by fsdgencsharp
// </auto-generated>
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Net;
using System.Net.Http;
using Facility.Core;
using Facility.Core.Http;
#pragma warning disable 612, 618 // member is obsolete
namespace OapApi.v1.Client.Http
{
[System.CodeDom.Compiler.GeneratedCode("fsdgencsharp", "")]
public static partial class OapApiV1HttpMapping
{
/// <summary>
/// Gets applications for the current user.
/// </summary>
public static readonly HttpMethodMapping<GetApplicationsRequestDto, GetApplicationsResponseDto> GetApplicationsMapping =
new HttpMethodMapping<GetApplicationsRequestDto, GetApplicationsResponseDto>.Builder
{
HttpMethod = HttpMethod.Get,
Path = "/applications",
GetUriParameters = request =>
new Dictionary<string, string>
{
{ "status", request.Status == null ? null : request.Status.Value.ToString() },
{ "limit", request.Limit == null ? null : request.Limit.Value.ToString(CultureInfo.InvariantCulture) },
{ "nextToken", request.NextToken },
},
SetUriParameters = (request, parameters) =>
{
parameters.TryGetValue("status", out var queryParameterStatus);
request.Status = queryParameterStatus == null ? default(ApplicationStatus?) : new ApplicationStatus(queryParameterStatus);
parameters.TryGetValue("limit", out var queryParameterLimit);
request.Limit = ServiceDataUtility.TryParseInt32(queryParameterLimit);
parameters.TryGetValue("nextToken", out var queryParameterNextToken);
request.NextToken = queryParameterNextToken;
return request;
},
ResponseMappings =
{
new HttpResponseMapping<GetApplicationsResponseDto>.Builder
{
StatusCode = (HttpStatusCode) 200,
ResponseBodyType = typeof(GetApplicationsResponseDto),
}.Build(),
},
}.Build();
/// <summary>
/// Creates a new application for the current user.
/// </summary>
public static readonly HttpMethodMapping<CreateApplicationRequestDto, CreateApplicationResponseDto> CreateApplicationMapping =
new HttpMethodMapping<CreateApplicationRequestDto, CreateApplicationResponseDto>.Builder
{
HttpMethod = HttpMethod.Post,
Path = "/applications/",
ValidateRequest = request =>
{
if (request.ApplicationCreateSet == null)
return ServiceResult.Failure(ServiceErrors.CreateRequestFieldRequired("applicationCreateSet"));
return ServiceResult.Success();
},
RequestBodyType = typeof(ApplicationCreateSetDto),
GetRequestBody = request => request.ApplicationCreateSet,
CreateRequest = body => new CreateApplicationRequestDto { ApplicationCreateSet = (ApplicationCreateSetDto) body },
ResponseMappings =
{
new HttpResponseMapping<CreateApplicationResponseDto>.Builder
{
StatusCode = (HttpStatusCode) 200,
ResponseBodyType = typeof(ApplicationDto),
MatchesResponse = response => response.Application != null,
GetResponseBody = response => response.Application,
CreateResponse = body => new CreateApplicationResponseDto { Application = (ApplicationDto) body },
}.Build(),
new HttpResponseMapping<CreateApplicationResponseDto>.Builder
{
StatusCode = (HttpStatusCode) 201,
}.Build(),
},
}.Build();
/// <summary>
/// Gets the specified application for the current user.
/// </summary>
public static readonly HttpMethodMapping<GetApplicationRequestDto, GetApplicationResponseDto> GetApplicationMapping =
new HttpMethodMapping<GetApplicationRequestDto, GetApplicationResponseDto>.Builder
{
HttpMethod = HttpMethod.Get,
Path = "/applications/{id}",
ValidateRequest = request =>
{
if (string.IsNullOrEmpty(request.Id))
return ServiceResult.Failure(ServiceErrors.CreateRequestFieldRequired("id"));
return ServiceResult.Success();
},
GetUriParameters = request =>
new Dictionary<string, string>
{
{ "id", request.Id },
},
SetUriParameters = (request, parameters) =>
{
parameters.TryGetValue("id", out var queryParameterId);
request.Id = queryParameterId;
return request;
},
ResponseMappings =
{
new HttpResponseMapping<GetApplicationResponseDto>.Builder
{
StatusCode = (HttpStatusCode) 200,
ResponseBodyType = typeof(ApplicationDto),
MatchesResponse = response => response.Application != null,
GetResponseBody = response => response.Application,
CreateResponse = body => new GetApplicationResponseDto { Application = (ApplicationDto) body },
}.Build(),
new HttpResponseMapping<GetApplicationResponseDto>.Builder
{
StatusCode = (HttpStatusCode) 304,
MatchesResponse = response => response.NotModified.GetValueOrDefault(),
CreateResponse = body => new GetApplicationResponseDto { NotModified = true },
}.Build(),
},
GetResponseHeaders = response =>
new Dictionary<string, string>
{
["eTag"] = response.ETag,
},
SetResponseHeaders = (response, headers) =>
{
headers.TryGetValue("eTag", out var headerETag);
response.ETag = headerETag;
return response;
},
}.Build();
/// <summary>
/// Updates the application.
/// </summary>
public static readonly HttpMethodMapping<UpdateApplicationRequestDto, UpdateApplicationResponseDto> UpdateApplicationMapping =
new HttpMethodMapping<UpdateApplicationRequestDto, UpdateApplicationResponseDto>.Builder
{
HttpMethod = new HttpMethod("PATCH"),
Path = "/applications/{id}",
ValidateRequest = request =>
{
if (string.IsNullOrEmpty(request.Id))
return ServiceResult.Failure(ServiceErrors.CreateRequestFieldRequired("id"));
if (request.ApplicationChangeSet == null)
return ServiceResult.Failure(ServiceErrors.CreateRequestFieldRequired("applicationChangeSet"));
return ServiceResult.Success();
},
GetUriParameters = request =>
new Dictionary<string, string>
{
{ "id", request.Id },
},
SetUriParameters = (request, parameters) =>
{
parameters.TryGetValue("id", out var queryParameterId);
request.Id = queryParameterId;
return request;
},
RequestBodyType = typeof(ApplicationChangeSetDto),
GetRequestBody = request => request.ApplicationChangeSet,
CreateRequest = body => new UpdateApplicationRequestDto { ApplicationChangeSet = (ApplicationChangeSetDto) body },
ResponseMappings =
{
new HttpResponseMapping<UpdateApplicationResponseDto>.Builder
{
StatusCode = (HttpStatusCode) 200,
ResponseBodyType = typeof(ApplicationDto),
MatchesResponse = response => response.Application != null,
GetResponseBody = response => response.Application,
CreateResponse = body => new UpdateApplicationResponseDto { Application = (ApplicationDto) body },
}.Build(),
},
}.Build();
}
}

View File

@@ -0,0 +1,34 @@
// <auto-generated>
// DO NOT EDIT: generated by fsdgencsharp
// </auto-generated>
using System;
using System.Threading;
using System.Threading.Tasks;
using Facility.Core;
namespace OapApi.v1.Client
{
[System.CodeDom.Compiler.GeneratedCode("fsdgencsharp", "")]
public partial interface IOapApiV1
{
/// <summary>
/// Gets applications for the current user.
/// </summary>
Task<ServiceResult<GetApplicationsResponseDto>> GetApplicationsAsync(GetApplicationsRequestDto request, CancellationToken cancellationToken = default);
/// <summary>
/// Creates a new application for the current user.
/// </summary>
Task<ServiceResult<CreateApplicationResponseDto>> CreateApplicationAsync(CreateApplicationRequestDto request, CancellationToken cancellationToken = default);
/// <summary>
/// Gets the specified application for the current user.
/// </summary>
Task<ServiceResult<GetApplicationResponseDto>> GetApplicationAsync(GetApplicationRequestDto request, CancellationToken cancellationToken = default);
/// <summary>
/// Updates the application.
/// </summary>
Task<ServiceResult<UpdateApplicationResponseDto>> UpdateApplicationAsync(UpdateApplicationRequestDto request, CancellationToken cancellationToken = default);
}
}

View File

@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Facility.Core" Version="2.27.0" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,28 @@
// <auto-generated>
// DO NOT EDIT: generated by fsdgencsharp
// </auto-generated>
using System;
using Facility.Core;
namespace OapApi.v1.Client
{
[System.CodeDom.Compiler.GeneratedCode("fsdgencsharp", "")]
internal static class OapApiV1Methods
{
public static readonly IServiceMethodInfo GetApplications =
ServiceMethodInfo.Create<IOapApiV1, GetApplicationsRequestDto, GetApplicationsResponseDto>(
"getApplications", "OapApiV1", x => x.GetApplicationsAsync);
public static readonly IServiceMethodInfo CreateApplication =
ServiceMethodInfo.Create<IOapApiV1, CreateApplicationRequestDto, CreateApplicationResponseDto>(
"createApplication", "OapApiV1", x => x.CreateApplicationAsync);
public static readonly IServiceMethodInfo GetApplication =
ServiceMethodInfo.Create<IOapApiV1, GetApplicationRequestDto, GetApplicationResponseDto>(
"getApplication", "OapApiV1", x => x.GetApplicationAsync);
public static readonly IServiceMethodInfo UpdateApplication =
ServiceMethodInfo.Create<IOapApiV1, UpdateApplicationRequestDto, UpdateApplicationResponseDto>(
"updateApplication", "OapApiV1", x => x.UpdateApplicationAsync);
}
}

View File

@@ -0,0 +1,48 @@
// <auto-generated>
// DO NOT EDIT: generated by fsdgencsharp
// </auto-generated>
using System;
using System.Collections.Generic;
using Facility.Core;
namespace OapApi.v1.Client
{
/// <summary>
/// Request for UpdateApplication.
/// </summary>
[System.CodeDom.Compiler.GeneratedCode("fsdgencsharp", "")]
public sealed partial class UpdateApplicationRequestDto : ServiceDto<UpdateApplicationRequestDto>
{
/// <summary>
/// Creates an instance.
/// </summary>
public UpdateApplicationRequestDto()
{
}
/// <summary>
/// The application ID.
/// </summary>
public string Id { get; set; }
/// <summary>
/// The application update set.
/// </summary>
public ApplicationChangeSetDto ApplicationChangeSet { get; set; }
/// <summary>
/// The JSON serializer.
/// </summary>
protected override JsonServiceSerializer JsonSerializer => SystemTextJsonServiceSerializer.Instance;
/// <summary>
/// Determines if two DTOs are equivalent.
/// </summary>
public override bool IsEquivalentTo(UpdateApplicationRequestDto other)
{
return other != null &&
Id == other.Id &&
ServiceDataUtility.AreEquivalentDtos(ApplicationChangeSet, other.ApplicationChangeSet);
}
}
}

View File

@@ -0,0 +1,42 @@
// <auto-generated>
// DO NOT EDIT: generated by fsdgencsharp
// </auto-generated>
using System;
using System.Collections.Generic;
using Facility.Core;
namespace OapApi.v1.Client
{
/// <summary>
/// Response for UpdateApplication.
/// </summary>
[System.CodeDom.Compiler.GeneratedCode("fsdgencsharp", "")]
public sealed partial class UpdateApplicationResponseDto : ServiceDto<UpdateApplicationResponseDto>
{
/// <summary>
/// Creates an instance.
/// </summary>
public UpdateApplicationResponseDto()
{
}
/// <summary>
/// The updated Application.
/// </summary>
public ApplicationDto Application { get; set; }
/// <summary>
/// The JSON serializer.
/// </summary>
protected override JsonServiceSerializer JsonSerializer => SystemTextJsonServiceSerializer.Instance;
/// <summary>
/// Determines if two DTOs are equivalent.
/// </summary>
public override bool IsEquivalentTo(UpdateApplicationResponseDto other)
{
return other != null &&
ServiceDataUtility.AreEquivalentDtos(Application, other.Application);
}
}
}

View File

@@ -0,0 +1,14 @@
using OrchardCore.Modules.Manifest;
[assembly: Module(
Id = "OAP.APIv1",
Name = "Overseas Auto Protection API v1",
Author = "Overseas Auto Protection",
Website = "https://oaprotection.org/api/v1/",
Version = "0.0.1",
Description = "API for OAP services",
Category = "Content Management",
Dependencies = [
"OAP.Content"
]
)]

View File

@@ -0,0 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<InvariantGlobalization>true</InvariantGlobalization>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Facility.AspNetCore" Version="3.9.0" />
<PackageReference Include="Facility.Core" Version="2.27.0" />
<PackageReference Include="OrchardCore.Module.Targets" Version="1.8.2" />
<PackageReference Include="OrchardCore.DisplayManagement" Version="1.8.2" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\OapApi.v1.Client\OapApi.v1.Client.csproj" />
<ProjectReference Include="..\OapApi.v1.Client\OapApi.v1.Client.csproj" />
<ProjectReference Include="..\OverseasAutoProtection\OverseasAutoProtection.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,35 @@
using Facility.Core;
using Microsoft.AspNetCore.Mvc;
using OapApi.v1.Client;
namespace OapApi.v1;
public sealed class OapApiV1 : IOapApiV1
{
public OapApiV1()
{
}
public Task<ServiceResult<CreateApplicationResponseDto>> CreateApplicationAsync(CreateApplicationRequestDto request, CancellationToken cancellationToken = default) => throw new NotImplementedException();
public Task<ServiceResult<GetApplicationResponseDto>> GetApplicationAsync(GetApplicationRequestDto request, CancellationToken cancellationToken = default)
{
return Task.FromResult(ServiceResult.Success(new GetApplicationResponseDto
{
Application = new ApplicationDto
{
Id = "1",
Status = ApplicationStatus.InProgress,
Terms = new ApplicationTermsDto
{
HasReadInstructions = true,
}
}
}));
}
public Task<ServiceResult<GetApplicationsResponseDto>> GetApplicationsAsync(GetApplicationsRequestDto request, CancellationToken cancellationToken = default) => throw new NotImplementedException();
public Task<ServiceResult<UpdateApplicationResponseDto>> UpdateApplicationAsync(UpdateApplicationRequestDto request, CancellationToken cancellationToken = default) => throw new NotImplementedException();
}

View File

@@ -0,0 +1,34 @@
using Facility.AspNetCore;
using Facility.Core.Http;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.DependencyInjection;
using OapApi.v1.Client;
using OapApi.v1.Client.Http;
namespace OapApi.v1
{
public class Startup : OrchardCore.Modules.StartupBase
{
public override void ConfigureServices(IServiceCollection services)
{
services.AddScoped<IOapApiV1, OapApiV1>();
services.AddScoped(sp =>
{
return new OapApiV1HttpHandler(
sp.GetRequiredService<IOapApiV1>(),
new ServiceHttpHandlerSettings
{
RootPath = "/oap/api/v1",
});
});
}
public override void Configure(IApplicationBuilder builder, IEndpointRouteBuilder routes, IServiceProvider serviceProvider)
{
builder.UseFacilityExceptionHandler();
builder.UseFacilityHttpHandler<OapApiV1HttpHandler>();
}
}
}

View File

@@ -0,0 +1,248 @@
{
"swagger": "2.0",
"info": {
"title": "OapApiV1",
"description": "API providing OAP functionality for the application form, calculator and more.\n\n## Heading\n\nUse a primary heading to indicate the member name.",
"version": "0.0.0",
"x-identifier": "OapApiV1",
"x-codegen": "DO NOT EDIT: generated by fsdgenswagger"
},
"host": "oaprotection.org",
"basePath": "/api/v1",
"schemes": [
"https"
],
"paths": {
"/applications": {
"get": {
"tags": [
"bob"
],
"summary": "Gets applications for the current user.",
"description": "Gets the current user's applications in pages.",
"operationId": "getApplications",
"produces": [
"application/json"
],
"parameters": [
{
"in": "query",
"name": "status",
"description": "Filter applications by the given status.",
"type": "string",
"enum": [
"InProgress",
"Submitted"
]
},
{
"in": "query",
"name": "limit",
"description": "The limit of returned results.",
"type": "integer",
"format": "int32"
},
{
"in": "query",
"name": "nextToken",
"description": "The token presenting the next page of applications to get.",
"type": "string"
}
],
"responses": {
"200": {
"description": "",
"schema": {
"$ref": "#/definitions/GetApplicationsResponse"
}
}
}
}
},
"/applications/": {
"post": {
"summary": "Creates a new application for the current user.",
"description": "Creates a new application for the current user.",
"operationId": "createApplication",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"parameters": [
{
"in": "body",
"name": "request",
"description": "The application to create.",
"required": true,
"schema": {
"$ref": "#/definitions/ApplicationCreateSet"
}
}
],
"responses": {
"200": {
"description": "The created application.",
"schema": {
"$ref": "#/definitions/Application"
},
"x-identifier": "application"
},
"201": {
"description": ""
}
}
}
},
"/applications/{id}": {
"get": {
"summary": "Gets the specified application for the current user.",
"operationId": "getApplication",
"produces": [
"application/json"
],
"parameters": [
{
"in": "path",
"name": "id",
"description": "The widget ID.",
"required": true,
"type": "string"
}
],
"responses": {
"200": {
"description": "The requested widget.",
"schema": {
"$ref": "#/definitions/Application"
},
"x-identifier": "application"
},
"304": {
"description": "",
"x-identifier": "notModified"
}
}
},
"patch": {
"summary": "Updates the application.",
"description": "Updates an application for the current user, given the ID of the application to update.",
"operationId": "updateApplication",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"parameters": [
{
"in": "path",
"name": "id",
"description": "The application ID.",
"required": true,
"type": "string"
},
{
"in": "body",
"name": "request",
"description": "The application update set.",
"required": true,
"schema": {
"$ref": "#/definitions/ApplicationChangeSet"
}
}
],
"responses": {
"200": {
"description": "The updated Application.",
"schema": {
"$ref": "#/definitions/Application"
},
"x-identifier": "application"
}
}
}
}
},
"definitions": {
"GetApplicationsResponse": {
"type": "object",
"properties": {
"applications": {
"description": "The applications.",
"type": "array",
"items": {
"$ref": "#/definitions/Application"
}
},
"total": {
"description": "The total number of applications.",
"type": "integer",
"format": "int64"
},
"nextToken": {
"description": "The token representing the next page of results.",
"type": "string"
},
"isLastPage": {
"description": "True if this is the last page of results, false otherwise.",
"type": "boolean"
}
}
},
"ApplicationCreateSet": {
"type": "object",
"properties": {
"terms": {
"$ref": "#/definitions/ApplicationTermsCreateSet"
}
}
},
"Application": {
"description": "An application.",
"type": "object",
"properties": {
"id": {
"description": "A unique identifier for the application.",
"type": "string"
},
"status": {
"description": "The current status of this application.",
"type": "string",
"enum": [
"InProgress",
"Submitted"
]
},
"terms": {
"$ref": "#/definitions/ApplicationTerms"
}
},
"x-remarks": "Represents a user's application, whether in progress or submitted."
},
"ApplicationChangeSet": {
"type": "object",
"properties": {}
},
"ApplicationTermsCreateSet": {
"required": [
"hasReadInstructions"
],
"type": "object",
"properties": {
"hasReadInstructions": {
"type": "boolean"
}
}
},
"ApplicationTerms": {
"type": "object",
"properties": {
"hasReadInstructions": {
"type": "boolean"
}
}
}
}
}

View File

@@ -0,0 +1,26 @@
module.exports = {
env: {
browser: true,
es2021: true,
},
extends: 'airbnb-base',
overrides: [
{
env: {
node: true,
},
files: [
'.eslintrc.{js,cjs}',
],
parserOptions: {
sourceType: 'script',
},
},
],
parserOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
},
rules: {
},
};

View File

@@ -0,0 +1,13 @@
using OrchardCore.DisplayManagement.Manifest;
[assembly: Theme(
Id = "OAP.Theme",
Name = "OAP Theme",
Author = "Overseas Auto Protection",
Website = "https://oaprotection.org/",
Version = "0.0.1",
Description = "Overseas Auto Protection site theme.",
Dependencies = [
"OAP.Content",
]
)]

View File

@@ -0,0 +1,41 @@
<Project Sdk="Microsoft.NET.Sdk.Razor">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<AddRazorSupportForMvc>true</AddRazorSupportForMvc>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<EmbeddedResource Remove="Views\HtmlBodyPart.cshtml" />
<EmbeddedResource Remove="Views\Layout.cshtml" />
<EmbeddedResource Remove="Views\_ViewImports.cshtml" />
</ItemGroup>
<ItemGroup>
<FrameworkReference Include="Microsoft.AspNetCore.App" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="OrchardCore.Autoroute" Version="1.8.2" />
<PackageReference Include="OrchardCore.ContentFields" Version="1.8.2" />
<PackageReference Include="OrchardCore.Flows" Version="1.8.2" />
<PackageReference Include="OrchardCore.Forms" Version="1.8.2" />
<PackageReference Include="OrchardCore.Html" Version="1.8.2" />
<PackageReference Include="OrchardCore.Lists" Version="1.8.2" />
<PackageReference Include="OrchardCore.Theme.Targets" Version="1.8.2" />
<PackageReference Include="OrchardCore.ContentManagement" Version="1.8.2" />
<PackageReference Include="OrchardCore.DisplayManagement" Version="1.8.2" />
<PackageReference Include="OrchardCore.ResourceManagement" Version="1.8.2" />
</ItemGroup>
<ItemGroup>
<Folder Include="wwwroot\" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\OverseasAutoProtection\OverseasAutoProtection.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,24 @@
using Microsoft.Extensions.Options;
using OrchardCore.ResourceManagement;
namespace OapTheme;
public class ResourceManagementOptionsConfiguration : IConfigureOptions<ResourceManagementOptions>
{
static ResourceManagementOptionsConfiguration()
{
m_manifest = new ResourceManifest();
m_manifest
.DefineStyle("OapTheme-styles")
.SetUrl("~/OapTheme/site.css")
.SetVersion("1.0.0");
}
public void Configure(ResourceManagementOptions options)
{
options.ResourceManifests.Add(m_manifest);
}
private static ResourceManifest m_manifest;
}

View File

@@ -0,0 +1,2 @@
import "../Styles/site.css";
import 'htmx.org';

View File

@@ -0,0 +1,14 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using OrchardCore.Modules;
using OrchardCore.ResourceManagement;
namespace OapTheme;
public class Startup : StartupBase
{
public override void ConfigureServices(IServiceCollection services)
{
services.AddTransient<IConfigureOptions<ResourceManagementOptions>, ResourceManagementOptionsConfiguration>();
}
}

View File

@@ -0,0 +1,23 @@
div.richtext a {
@apply text-blue-700 underline;
}
div.richtext ol, div.richtext ul {
@apply my-2 pl-8;
}
div.richtext ol li {
@apply list-decimal my-1;
}
div.richtext ul li {
@apply list-disc my-1;
}
div.richtext p {
@apply my-4;
}
div.richtext .red {
@apply text-red-500;
}

View File

@@ -0,0 +1,6 @@
@import "tailwindcss/base";
@import "tailwindcss/components";
@import "./richtext.css";
@import "./validation.css";
@import "tailwindcss/utilities";

View File

@@ -0,0 +1,3 @@
span.field-validation-error {
@apply text-sm text-red-600;
}

View File

@@ -0,0 +1,5 @@
@model OrchardCore.Html.ViewModels.HtmlBodyPartViewModel
<div class="richtext">
@Html.Raw(Model.Html)
</div>

View File

@@ -0,0 +1,36 @@
@using OrchardCore.Admin.Models
@using OrchardCore.DisplayManagement
@using OrchardCore.DisplayManagement.ModelBinding
@using OrchardCore.Entities
@using OrchardCore.Users.Models
<!DOCTYPE html>
<html lang="@Orchard.CultureName()" dir="@Orchard.CultureDir()">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>@RenderTitleSegments(Site.SiteName, "before")</title>
<resources type="Meta" />
<link type="image/x-icon" rel="shortcut icon" href="~/OapTheme/assets/favicon.ico">
<style asp-name="oaptheme-styles"></style>
<resources type="HeadLink" />
<resources type="Stylesheet" />
<resources type="HeadScript" />
@await RenderSectionAsync("HeadMeta", required: false)
</head>
<body>
@await RenderSectionAsync("Header", required: false)
@await RenderBodyAsync()
@await RenderSectionAsync("Footer", required: false)
<resources type="FootScript" />
</body>
</html>

View File

@@ -0,0 +1,13 @@
@*
For more information on enabling MVC for empty projects, visit http://go.microsoft.com/fwlink/?LinkID=397860
*@
@inherits OrchardCore.DisplayManagement.Razor.RazorPage<TModel>
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@addTagHelper *, OrchardCore.DisplayManagement
@addTagHelper *, OrchardCore.ResourceManagement
@addTagHelper *, OrchardCore.Menu
@using Microsoft.AspNetCore.Routing
@using Microsoft.Extensions.Options
@using OrchardCore.ContentManagement
@using OrchardCore.ContentManagement.Routing

10429
src/OAP/OapTheme/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,27 @@
{
"version": "1.0.0",
"name": "tailwindtheme",
"private": true,
"scripts": {
"build": "webpack"
},
"browserslist": "> 5%",
"devDependencies": {
"aspnet-client-validation": "0.9.2",
"autoprefixer": "^10.4.16",
"css-loader": "^6.8.1",
"css-minimizer-webpack-plugin": "^5.0.1",
"eslint": "^8.56.0",
"eslint-config-airbnb-base": "^15.0.0",
"eslint-plugin-import": "^2.29.1",
"htmx.org": "^1.9.8",
"mini-css-extract-plugin": "^2.7.6",
"postcss": "^8.4.31",
"postcss-import": "^15.1.0",
"postcss-loader": "^7.3.3",
"style-loader": "^3.3.3",
"tailwindcss": "3.3.5",
"webpack": "^5.89.0",
"webpack-cli": "^5.1.4"
}
}

View File

@@ -0,0 +1,7 @@
module.exports = {
plugins: {
'postcss-import': {},
tailwindcss: {},
autoprefixer: {},
},
};

View File

@@ -0,0 +1,8 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
content: ['./**/*.cshtml', './**/*.liquid'],
theme: {
extend: {},
},
plugins: [],
};

View File

@@ -0,0 +1,28 @@
/// <binding ProjectOpened='Watch - Development' />
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
module.exports = {
entry: {
site: './Scripts/site.js',
},
output: {
path: path.resolve(__dirname, 'wwwroot'),
filename: '[name].js',
},
plugins: [new MiniCssExtractPlugin()],
module: {
rules: [
{
test: /\.css$/i,
use: [MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader'],
},
],
},
optimization: {
minimizer: [
new CssMinimizerPlugin(),
],
},
};

View File

@@ -0,0 +1,528 @@
/*!*************************************************************************************************************!*\
!*** css ./node_modules/css-loader/dist/cjs.js!./node_modules/postcss-loader/dist/cjs.js!./Styles/site.css ***!
\*************************************************************************************************************/
/*
! tailwindcss v3.3.5 | MIT License | https://tailwindcss.com
*//*
1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4)
2. Allow adding a border to an element by just adding a border-width. (https://github.com/tailwindcss/tailwindcss/pull/116)
*/
*,
::before,
::after {
box-sizing: border-box; /* 1 */
border-width: 0; /* 2 */
border-style: solid; /* 2 */
border-color: #e5e7eb; /* 2 */
}
::before,
::after {
--tw-content: '';
}
/*
1. Use a consistent sensible line-height in all browsers.
2. Prevent adjustments of font size after orientation changes in iOS.
3. Use a more readable tab size.
4. Use the user's configured `sans` font-family by default.
5. Use the user's configured `sans` font-feature-settings by default.
6. Use the user's configured `sans` font-variation-settings by default.
*/
html {
line-height: 1.5; /* 1 */
-webkit-text-size-adjust: 100%; /* 2 */ /* 3 */
tab-size: 4; /* 3 */
font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; /* 4 */
font-feature-settings: normal; /* 5 */
font-variation-settings: normal; /* 6 */
}
/*
1. Remove the margin in all browsers.
2. Inherit line-height from `html` so users can set them as a class directly on the `html` element.
*/
body {
margin: 0; /* 1 */
line-height: inherit; /* 2 */
}
/*
1. Add the correct height in Firefox.
2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655)
3. Ensure horizontal rules are visible by default.
*/
hr {
height: 0; /* 1 */
color: inherit; /* 2 */
border-top-width: 1px; /* 3 */
}
/*
Add the correct text decoration in Chrome, Edge, and Safari.
*/
abbr:where([title]) {
text-decoration: underline dotted;
}
/*
Remove the default font size and weight for headings.
*/
h1,
h2,
h3,
h4,
h5,
h6 {
font-size: inherit;
font-weight: inherit;
}
/*
Reset links to optimize for opt-in styling instead of opt-out.
*/
a {
color: inherit;
text-decoration: inherit;
}
/*
Add the correct font weight in Edge and Safari.
*/
b,
strong {
font-weight: bolder;
}
/*
1. Use the user's configured `mono` font family by default.
2. Correct the odd `em` font sizing in all browsers.
*/
code,
kbd,
samp,
pre {
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; /* 1 */
font-size: 1em; /* 2 */
}
/*
Add the correct font size in all browsers.
*/
small {
font-size: 80%;
}
/*
Prevent `sub` and `sup` elements from affecting the line height in all browsers.
*/
sub,
sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
}
sub {
bottom: -0.25em;
}
sup {
top: -0.5em;
}
/*
1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297)
2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016)
3. Remove gaps between table borders by default.
*/
table {
text-indent: 0; /* 1 */
border-color: inherit; /* 2 */
border-collapse: collapse; /* 3 */
}
/*
1. Change the font styles in all browsers.
2. Remove the margin in Firefox and Safari.
3. Remove default padding in all browsers.
*/
button,
input,
optgroup,
select,
textarea {
font-family: inherit; /* 1 */
font-feature-settings: inherit; /* 1 */
font-variation-settings: inherit; /* 1 */
font-size: 100%; /* 1 */
font-weight: inherit; /* 1 */
line-height: inherit; /* 1 */
color: inherit; /* 1 */
margin: 0; /* 2 */
padding: 0; /* 3 */
}
/*
Remove the inheritance of text transform in Edge and Firefox.
*/
button,
select {
text-transform: none;
}
/*
1. Correct the inability to style clickable types in iOS and Safari.
2. Remove default button styles.
*/
button,
[type='button'],
[type='reset'],
[type='submit'] {
-webkit-appearance: button; /* 1 */
background-color: transparent; /* 2 */
background-image: none; /* 2 */
}
/*
Use the modern Firefox focus style for all focusable elements.
*/
:-moz-focusring {
outline: auto;
}
/*
Remove the additional `:invalid` styles in Firefox. (https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737)
*/
:-moz-ui-invalid {
box-shadow: none;
}
/*
Add the correct vertical alignment in Chrome and Firefox.
*/
progress {
vertical-align: baseline;
}
/*
Correct the cursor style of increment and decrement buttons in Safari.
*/
::-webkit-inner-spin-button,
::-webkit-outer-spin-button {
height: auto;
}
/*
1. Correct the odd appearance in Chrome and Safari.
2. Correct the outline style in Safari.
*/
[type='search'] {
-webkit-appearance: textfield; /* 1 */
outline-offset: -2px; /* 2 */
}
/*
Remove the inner padding in Chrome and Safari on macOS.
*/
::-webkit-search-decoration {
-webkit-appearance: none;
}
/*
1. Correct the inability to style clickable types in iOS and Safari.
2. Change font properties to `inherit` in Safari.
*/
::-webkit-file-upload-button {
-webkit-appearance: button; /* 1 */
font: inherit; /* 2 */
}
/*
Add the correct display in Chrome and Safari.
*/
summary {
display: list-item;
}
/*
Removes the default spacing and border for appropriate elements.
*/
blockquote,
dl,
dd,
h1,
h2,
h3,
h4,
h5,
h6,
hr,
figure,
p,
pre {
margin: 0;
}
fieldset {
margin: 0;
padding: 0;
}
legend {
padding: 0;
}
ol,
ul,
menu {
list-style: none;
margin: 0;
padding: 0;
}
/*
Reset default styling for dialogs.
*/
dialog {
padding: 0;
}
/*
Prevent resizing textareas horizontally by default.
*/
textarea {
resize: vertical;
}
/*
1. Reset the default placeholder opacity in Firefox. (https://github.com/tailwindlabs/tailwindcss/issues/3300)
2. Set the default placeholder color to the user's configured gray 400 color.
*/
input::placeholder,
textarea::placeholder {
opacity: 1; /* 1 */
color: #9ca3af; /* 2 */
}
/*
Set the default cursor for buttons.
*/
button,
[role="button"] {
cursor: pointer;
}
/*
Make sure disabled buttons don't get the pointer cursor.
*/
:disabled {
cursor: default;
}
/*
1. Make replaced elements `display: block` by default. (https://github.com/mozdevs/cssremedy/issues/14)
2. Add `vertical-align: middle` to align replaced elements more sensibly by default. (https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210)
This can trigger a poorly considered lint error in some tools but is included by design.
*/
img,
svg,
video,
canvas,
audio,
iframe,
embed,
object {
display: block; /* 1 */
vertical-align: middle; /* 2 */
}
/*
Constrain images and videos to the parent width and preserve their intrinsic aspect ratio. (https://github.com/mozdevs/cssremedy/issues/14)
*/
img,
video {
max-width: 100%;
height: auto;
}
/* Make elements with the HTML hidden attribute stay hidden by default */
[hidden] {
display: none;
}
*, ::before, ::after {
--tw-border-spacing-x: 0;
--tw-border-spacing-y: 0;
--tw-translate-x: 0;
--tw-translate-y: 0;
--tw-rotate: 0;
--tw-skew-x: 0;
--tw-skew-y: 0;
--tw-scale-x: 1;
--tw-scale-y: 1;
--tw-pan-x: ;
--tw-pan-y: ;
--tw-pinch-zoom: ;
--tw-scroll-snap-strictness: proximity;
--tw-gradient-from-position: ;
--tw-gradient-via-position: ;
--tw-gradient-to-position: ;
--tw-ordinal: ;
--tw-slashed-zero: ;
--tw-numeric-figure: ;
--tw-numeric-spacing: ;
--tw-numeric-fraction: ;
--tw-ring-inset: ;
--tw-ring-offset-width: 0px;
--tw-ring-offset-color: #fff;
--tw-ring-color: rgb(59 130 246 / 0.5);
--tw-ring-offset-shadow: 0 0 #0000;
--tw-ring-shadow: 0 0 #0000;
--tw-shadow: 0 0 #0000;
--tw-shadow-colored: 0 0 #0000;
--tw-blur: ;
--tw-brightness: ;
--tw-contrast: ;
--tw-grayscale: ;
--tw-hue-rotate: ;
--tw-invert: ;
--tw-saturate: ;
--tw-sepia: ;
--tw-drop-shadow: ;
--tw-backdrop-blur: ;
--tw-backdrop-brightness: ;
--tw-backdrop-contrast: ;
--tw-backdrop-grayscale: ;
--tw-backdrop-hue-rotate: ;
--tw-backdrop-invert: ;
--tw-backdrop-opacity: ;
--tw-backdrop-saturate: ;
--tw-backdrop-sepia: ;
}
::backdrop {
--tw-border-spacing-x: 0;
--tw-border-spacing-y: 0;
--tw-translate-x: 0;
--tw-translate-y: 0;
--tw-rotate: 0;
--tw-skew-x: 0;
--tw-skew-y: 0;
--tw-scale-x: 1;
--tw-scale-y: 1;
--tw-pan-x: ;
--tw-pan-y: ;
--tw-pinch-zoom: ;
--tw-scroll-snap-strictness: proximity;
--tw-gradient-from-position: ;
--tw-gradient-via-position: ;
--tw-gradient-to-position: ;
--tw-ordinal: ;
--tw-slashed-zero: ;
--tw-numeric-figure: ;
--tw-numeric-spacing: ;
--tw-numeric-fraction: ;
--tw-ring-inset: ;
--tw-ring-offset-width: 0px;
--tw-ring-offset-color: #fff;
--tw-ring-color: rgb(59 130 246 / 0.5);
--tw-ring-offset-shadow: 0 0 #0000;
--tw-ring-shadow: 0 0 #0000;
--tw-shadow: 0 0 #0000;
--tw-shadow-colored: 0 0 #0000;
--tw-blur: ;
--tw-brightness: ;
--tw-contrast: ;
--tw-grayscale: ;
--tw-hue-rotate: ;
--tw-invert: ;
--tw-saturate: ;
--tw-sepia: ;
--tw-drop-shadow: ;
--tw-backdrop-blur: ;
--tw-backdrop-brightness: ;
--tw-backdrop-contrast: ;
--tw-backdrop-grayscale: ;
--tw-backdrop-hue-rotate: ;
--tw-backdrop-invert: ;
--tw-backdrop-opacity: ;
--tw-backdrop-saturate: ;
--tw-backdrop-sepia: ;
}
div.richtext a {
--tw-text-opacity: 1;
color: rgb(29 78 216 / var(--tw-text-opacity));
text-decoration-line: underline;
}
div.richtext ol, div.richtext ul {
margin-top: 0.5rem;
margin-bottom: 0.5rem;
padding-left: 2rem;
}
div.richtext ol li {
margin-top: 0.25rem;
margin-bottom: 0.25rem;
list-style-type: decimal;
}
div.richtext ul li {
margin-top: 0.25rem;
margin-bottom: 0.25rem;
list-style-type: disc;
}
div.richtext p {
margin-top: 1rem;
margin-bottom: 1rem;
}
div.richtext .red {
--tw-text-opacity: 1;
color: rgb(239 68 68 / var(--tw-text-opacity));
}
span.field-validation-error {
font-size: 0.875rem;
line-height: 1.25rem;
--tw-text-opacity: 1;
color: rgb(220 38 38 / var(--tw-text-opacity));
}
.my-1 {
margin-top: 0.25rem;
margin-bottom: 0.25rem;
}
.table {
display: table;
}
.hidden {
display: none;
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,7 @@
namespace OverseasAutoProtection;
public static class ContentTypes
{
public const string OapApplication = nameof(OapApplication);
public const string OapApplicationForm = nameof(OapApplicationForm);
public const string OapApplicationFormStep = nameof(OapApplicationFormStep);
}

View File

@@ -0,0 +1,20 @@
using OrchardCore.Modules.Manifest;
[assembly: Module(
Id = "OAP.Content",
Name = "Overseas Auto Protection",
Author = "Overseas Auto Protection",
Website = "https://oaprotection.org/",
Version = "0.0.1",
Description = "The base OAP module, providing content types, parts, etc",
Category = "Content Management",
Dependencies = [
"OrchardCore.ContentFields",
"OrchardCore.Autoroute",
"OrchardCore.Flows",
"OrchardCore.Forms",
"OrchardCore.Html",
"OrchardCore.Lists",
"OrchardCore.Title",
]
)]

View File

@@ -0,0 +1,118 @@
using OrchardCore.Autoroute.Models;
using OrchardCore.ContentFields.Fields;
using OrchardCore.ContentFields.Settings;
using OrchardCore.ContentManagement.Metadata;
using OrchardCore.ContentManagement.Metadata.Settings;
using OrchardCore.Data.Migration;
using OrchardCore.Flows.Models;
using OrchardCore.Html.Models;
using OrchardCore.Html.Settings;
using OrchardCore.Lists.Models;
using OrchardCore.Mvc.Utilities;
using OrchardCore.Title.Models;
using OverseasAutoProtection.OapApplication;
namespace OverseasAutoProtection;
public class Migrations : DataMigration
{
public Migrations(IContentDefinitionManager contentDefinitionManager)
{
m_contentDefinitionManager = contentDefinitionManager;
}
public async Task<int> CreateAsync()
{
await m_contentDefinitionManager
.AlterTypeDefinitionAsync(ContentTypes.OapApplicationFormStep, type => type
.Securable()
.Draftable()
.Versionable()
.WithPart(nameof(TitlePart), part => part
.WithPosition("1"))
.WithPart(nameof(AutoroutePart), part => part
.WithPosition("2")
.WithSettings(new AutoroutePartSettings
{
AllowCustomPath = true,
AllowUpdatePath = true,
}))
.WithPart(nameof(FlowPart), part => part
.WithPosition("3")));
await m_contentDefinitionManager
.AlterTypeDefinitionAsync(ContentTypes.OapApplicationForm, type => type
.Creatable()
.Listable()
.Securable()
.Draftable()
.Versionable()
.WithPart(nameof(AutoroutePart), part => part
.WithPosition("2")
.WithSettings(new AutoroutePartSettings
{
AllowCustomPath = true,
AllowUpdatePath = true,
}))
.WithPart(nameof(ListPart), part => part
.WithDisplayName("Form Steps")
.WithPosition("3")
.WithSettings(new ListPartSettings
{
PageSize = 10,
EnableOrdering = true,
ContainedContentTypes = [ContentTypes.OapApplicationFormStep]
})
));
await m_contentDefinitionManager
.AlterPartDefinitionAsync(nameof(OapApplicationPart), builder => builder
.Attachable()
.WithField(nameof(OapApplicationPart.Status), field => field
.OfType(nameof(TextField))
.WithDisplayName(nameof(OapApplicationPart.Status))
.WithDescription("The status of the OAP Application.")
.WithEditor("PredefinedList")
.WithSettings(new TextFieldPredefinedListEditorSettings
{
Options = new[]
{
new ListValueOption { Name = OapApplicationStatuses.InProgress, Value = OapApplicationStatuses.InProgress.HtmlClassify() },
new ListValueOption { Name = OapApplicationStatuses.Submitted, Value = OapApplicationStatuses.Submitted.HtmlClassify() },
},
DefaultValue = OapApplicationStatuses.InProgress.HtmlClassify(),
Editor = EditorOption.Radio,
}))
.WithDescription("Makes a content item into an OAP Application."));
await m_contentDefinitionManager
.AlterTypeDefinitionAsync(ContentTypes.OapApplication, type => type
.Creatable()
.Listable()
.Securable()
.WithPart(nameof(HtmlBodyPart), part => part
.WithDisplayName("Notes")
.WithSettings(new ContentTypePartSettings { Editor = "Wysiwyg", })
)
.WithPart(nameof(OapApplicationPart)));
return 1;
}
public async Task<int> UpdateFrom1Async()
{
await m_contentDefinitionManager
.AlterTypeDefinitionAsync(ContentTypes.OapApplicationFormStep, type => type
.WithPart(nameof(HtmlBodyPart), part => part
.WithPosition("2")
.WithEditor("Wysiwyg")
.WithSettings(new HtmlBodyPartSettings
{
SanitizeHtml = true,
})));
return 2;
}
private readonly IContentDefinitionManager m_contentDefinitionManager;
}

View File

@@ -0,0 +1,10 @@
using OrchardCore.ContentFields.Fields;
using OrchardCore.ContentManagement;
namespace OverseasAutoProtection.OapApplication;
public class OapApplicationPart : ContentPart
{
public TextField ApplicationId { get; set; } = new();
public int Year { get; set; }
public TextField Status { get; set; } = new();
}

View File

@@ -0,0 +1,7 @@
namespace OverseasAutoProtection.OapApplication;
public static class OapApplicationStatuses
{
public const string InProgress = nameof(InProgress);
public const string Submitted = nameof(Submitted);
}

View File

@@ -0,0 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="OrchardCore.Autoroute" Version="1.8.2" />
<PackageReference Include="OrchardCore.ContentFields" Version="1.8.2" />
<PackageReference Include="OrchardCore.Flows" Version="1.8.2" />
<PackageReference Include="OrchardCore.Forms" Version="1.8.2" />
<PackageReference Include="OrchardCore.Html" Version="1.8.2" />
<PackageReference Include="OrchardCore.Lists" Version="1.8.2" />
<PackageReference Include="OrchardCore.Module.Targets" Version="1.8.2" />
<PackageReference Include="OrchardCore.ContentManagement" Version="1.8.2" />
<PackageReference Include="OrchardCore.ContentTypes.Abstractions" Version="1.8.2" />
<PackageReference Include="OrchardCore.DisplayManagement" Version="1.8.2" />
<PackageReference Include="OrchardCore.Title" Version="1.8.2" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,21 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.DependencyInjection;
using OrchardCore.Data.Migration;
using OverseasAutoProtection.OapApplication;
namespace OverseasAutoProtection;
public class Startup : OrchardCore.Modules.StartupBase
{
public override void ConfigureServices(IServiceCollection services)
{
services.AddScoped<OapApplicationPart>();
services.AddDataMigration<Migrations>();
}
public override void Configure(IApplicationBuilder builder, IEndpointRouteBuilder routes, IServiceProvider serviceProvider)
{
}
}