Compare commits
14
Commits
garages3
...
24697776d0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
24697776d0 | ||
|
|
4b806a3202 | ||
|
|
26df423180 | ||
|
|
f39eb9d8fe | ||
|
|
593219db8c | ||
|
|
020bdee36f | ||
|
|
8e0c099867 | ||
|
|
ef134a5b3c | ||
|
|
717b891554 | ||
|
|
91d325ce4e | ||
|
|
3cc8514136 | ||
|
|
11311421ad | ||
|
|
f4024d563a | ||
|
|
78b03b6996 |
@@ -1,36 +0,0 @@
|
||||
using PostFundManagement.Application.Abstractions.Services;
|
||||
using PostFundManagement.Application.Extensions;
|
||||
using PostFundManagement.Domain.Abstractions;
|
||||
using PostFundManagement.Domain.Errors;
|
||||
using PostFundManagement.Domain.Extensions;
|
||||
using PostFundManagement.Domain.Security;
|
||||
using Problems = Microsoft.AspNetCore.Mvc.ProblemDetails;
|
||||
|
||||
namespace PostFundManagement.Api.Endpoints.Tools;
|
||||
|
||||
[ApiVersionTarget(1)]
|
||||
public sealed class EncodeIdEndpoint : IEndpoint
|
||||
{
|
||||
public void Map(IEndpointRouteBuilder builder)
|
||||
{
|
||||
builder.MapGet("api/tools/hashid/{id64:long}", async (long id64, IToolService service,
|
||||
CancellationToken cancellationToken) =>
|
||||
await service.EncodeLong(id64, cancellationToken) switch
|
||||
{
|
||||
{ IsSuccess: true, Value: var hash } => Results.Ok(hash),
|
||||
var r when r.HasError<ValidationError>() => Results.BadRequest(r.Errors.ToProblems()),
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Hashes an int64 identifier")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(EncodeIdEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces<string>(StatusCodes.Status200OK)
|
||||
.Produces(StatusCodes.Status401Unauthorized)
|
||||
.Produces(StatusCodes.Status403Forbidden)
|
||||
.Produces<Problems>(StatusCodes.Status400BadRequest)
|
||||
.Produces<Problems>(StatusCodes.Status500InternalServerError)
|
||||
.WithTags(EndpointTags.Tools)
|
||||
.CacheOutput();
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,10 @@
|
||||
using Microsoft.FeatureManagement;
|
||||
using PostFundManagement.Application.Extensions;
|
||||
using PostFundManagement.Application.Filters;
|
||||
using PostFundManagement.Domain.Abstractions;
|
||||
using PostFundManagement.Domain.Health;
|
||||
using PostFundManagement.Domain.Mediator;
|
||||
using PostFundManagement.Infrastructure.Database.Services;
|
||||
using static PostFundManagement.Domain.Extensions.Constants;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
@@ -27,6 +29,7 @@ builder.Services.AddApiVersioning(options =>
|
||||
});
|
||||
|
||||
builder.Services.AddScoped<ActiveUserFilter>();
|
||||
builder.Services.AddTransient<ITenantContextService, TenantContextService>();
|
||||
|
||||
builder.Services.AddEndpoints(Assembly.GetExecutingAssembly());
|
||||
builder.Services.AddApiServices(builder.Configuration);
|
||||
|
||||
@@ -20,8 +20,11 @@
|
||||
},
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
"Default": "Warning",
|
||||
"Quartz": "Error",
|
||||
"Microsoft.AspNetCore": "Warning",
|
||||
"Microsoft.EntityFrameworkCore.Database": "Error",
|
||||
"Microsoft.EntityFrameworkCore.Update": "Error"
|
||||
}
|
||||
},
|
||||
"EmailProcessorCron": "0 */5 * * * ?",
|
||||
|
||||
@@ -12,8 +12,8 @@ public abstract class S3ServiceBase(IAmazonS3 amazonS3)
|
||||
|
||||
public string GenerateCdnUrl(string fileKey) => $"{CdnBaseUrl}/{fileKey}";
|
||||
|
||||
public virtual async ValueTask<Result<string>> GeneratePresignedUrlAsync(string fileKey, TimeSpan duration, string? contentType = null, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<string>>>)(async () =>
|
||||
public virtual async Task<Result<string>> GeneratePresignedUrlAsync(string fileKey, TimeSpan duration, string? contentType = null, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<string>>>)(async () =>
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(BucketName))
|
||||
return Result.Fail(ValidationError.Create("Bucket name is not configured."));
|
||||
@@ -51,8 +51,8 @@ public abstract class S3ServiceBase(IAmazonS3 amazonS3)
|
||||
: $"{cleanSubPath}/{fileHash.ToLower(CultureInfo.InvariantCulture)}_{fileName}";
|
||||
}
|
||||
|
||||
public virtual async ValueTask<Result<string>> UploadFileAsync(string fileName, string subPath, Stream fileStream, string contentType, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<string>>>)(async () =>
|
||||
public virtual async Task<Result<string>> UploadFileAsync(string fileName, string subPath, Stream fileStream, string contentType, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<string>>>)(async () =>
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(BucketName))
|
||||
return Result.Fail<string>(ValidationError.Create("Bucket name is not configured."));
|
||||
@@ -92,8 +92,8 @@ public abstract class S3ServiceBase(IAmazonS3 amazonS3)
|
||||
: Result.Ok(fileKey);
|
||||
}));
|
||||
|
||||
public virtual async ValueTask<Result> DeleteFileAsync(string fileKey, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result>>)(async () =>
|
||||
public virtual async Task<Result> DeleteFileAsync(string fileKey, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result>>)(async () =>
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(BucketName))
|
||||
return Result.Fail(NotFoundError.Create("Bucket name is not configured."));
|
||||
|
||||
@@ -1,16 +1,36 @@
|
||||
using PostFundManagement.Application.Services.Communications;
|
||||
using PostFundManagement.Domain;
|
||||
using PostFundManagement.Domain.Attributes;
|
||||
using PostFundManagement.Domain.Models;
|
||||
|
||||
namespace PostFundManagement.Application.Abstractions.Services;
|
||||
|
||||
public interface ICommunicationsService
|
||||
{
|
||||
ValueTask<Result<Invite>> SendInviteAsync(InviteRequest request, Guid userId, CancellationToken cancellationToken = default);
|
||||
[Log]
|
||||
[Audit]
|
||||
Task<Result<Invite>> SendInviteAsync(InviteRequest request, Guid userId, CancellationToken cancellationToken = default);
|
||||
|
||||
ValueTask<Result<Invite[]>> GetInvitesAsync(Pagination pagination, CancellationToken cancellationToken = default);
|
||||
[Log]
|
||||
Task<Result<Invite[]>> GetInvitesAsync(Pagination pagination, CancellationToken cancellationToken = default);
|
||||
|
||||
ValueTask<Result<Invite>> GetApplicantInviteAsync(Guid applicantUserId, CancellationToken cancellationToken = default);
|
||||
[Log]
|
||||
Task<Result<Invite>> GetApplicantInviteAsync(Guid applicantUserId, CancellationToken cancellationToken = default);
|
||||
|
||||
ValueTask<Result<Invite[]>> GetApplicantInvitesAsync(Guid applicantUserId, CancellationToken cancellationToken = default);
|
||||
[Log]
|
||||
Task<Result<Invite[]>> GetApplicantInvitesAsync(Guid applicantUserId, CancellationToken cancellationToken = default);
|
||||
|
||||
[Log]
|
||||
[Audit]
|
||||
Task<Result> CreateNotificationAsync(CreateNotificationRequest request, Guid userId, CancellationToken cancellationToken = default);
|
||||
|
||||
[Log]
|
||||
[Audit]
|
||||
Task<Result> UpdateNotificationAsync(UpdateNotificationRequest request, Guid userId, CancellationToken cancellationToken = default);
|
||||
|
||||
[Log]
|
||||
Task<Result<Notification[]>> GetNotificationsAsync(string organisationIdHash, CancellationToken cancellationToken = default);
|
||||
|
||||
[Log]
|
||||
Task<Result<Notification>> GetNotificationAsync(string notificationIdHash, CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
||||
@@ -1,32 +1,50 @@
|
||||
using PostFundManagement.Application.Services.Evidence;
|
||||
using PostFundManagement.Domain;
|
||||
using PostFundManagement.Domain.Attributes;
|
||||
using PostFundManagement.Domain.Models;
|
||||
|
||||
namespace PostFundManagement.Application.Abstractions.Services;
|
||||
|
||||
public interface IEvidenceService
|
||||
{
|
||||
ValueTask<Result> CreateEvidenceAsync(Guid userId, IFormCollection form, IFormFile file, CancellationToken cancellationToken = default);
|
||||
[Log]
|
||||
[Audit]
|
||||
Task<Result> CreateEvidenceAsync(Guid userId, IFormCollection form, IFormFile file, CancellationToken cancellationToken = default);
|
||||
|
||||
ValueTask<Result> RecordIndicatorActualAmountAsync(string indicatorIdHash, decimal amount, Guid userId, CancellationToken cancellationToken = default);
|
||||
[Log]
|
||||
[Audit]
|
||||
Task<Result> RecordIndicatorActualAmountAsync(string indicatorIdHash, decimal amount, Guid userId, CancellationToken cancellationToken = default);
|
||||
|
||||
ValueTask<Result<Indicator[]>> GetIndicatorsAsync(Pagination pagination, CancellationToken cancellationToken = default);
|
||||
[Log]
|
||||
Task<Result<Indicator[]>> GetIndicatorsAsync(Pagination pagination, CancellationToken cancellationToken = default);
|
||||
|
||||
ValueTask<Result<Evidence[]>> GetEvidenceFilesAsync(Pagination pagination, CancellationToken cancellationToken = default);
|
||||
[Log]
|
||||
Task<Result<Evidence[]>> GetEvidenceFilesAsync(Pagination pagination, CancellationToken cancellationToken = default);
|
||||
|
||||
ValueTask<Result> CreateMilestoneAsync(CreateMilestoneRequest request, Guid userId, CancellationToken cancellationToken = default);
|
||||
[Log]
|
||||
[Audit]
|
||||
Task<Result> CreateMilestoneAsync(CreateMilestoneRequest request, Guid userId, CancellationToken cancellationToken = default);
|
||||
|
||||
ValueTask<Result> CreateIndicatorAsync(CreateIndicatorRequest request, Guid userId, CancellationToken cancellationToken = default);
|
||||
[Log]
|
||||
[Audit]
|
||||
Task<Result> CreateIndicatorAsync(CreateIndicatorRequest request, Guid userId, CancellationToken cancellationToken = default);
|
||||
|
||||
ValueTask<Result<Indicator>> GetIndicatorAsync(string indicatorId, CancellationToken cancellationToken);
|
||||
[Log]
|
||||
Task<Result<Indicator>> GetIndicatorAsync(string indicatorId, CancellationToken cancellationToken);
|
||||
|
||||
ValueTask<Result<Evidence>> GetEvidenceAsync(string evidenceId, CancellationToken cancellationToken = default);
|
||||
[Log]
|
||||
Task<Result<Evidence>> GetEvidenceAsync(string evidenceId, CancellationToken cancellationToken = default);
|
||||
|
||||
ValueTask<Result<Evidence[]>> GetMilestoneEvidencesAsync(string milestoneIdHash, CancellationToken cancellationToken = default);
|
||||
[Log]
|
||||
Task<Result<Evidence[]>> GetMilestoneEvidencesAsync(string milestoneIdHash, CancellationToken cancellationToken = default);
|
||||
|
||||
ValueTask<Result<Evidence[]>> GetProjectEvidencesAsync(string projectIdHash, CancellationToken cancellationToken = default);
|
||||
[Log]
|
||||
Task<Result<Evidence[]>> GetProjectEvidencesAsync(string projectIdHash, CancellationToken cancellationToken = default);
|
||||
|
||||
ValueTask<Result> UpdateEvidenceAsync(UpdateEvidenceRequest request, Guid userId, CancellationToken cancellationToken = default);
|
||||
[Log]
|
||||
[Audit]
|
||||
Task<Result> UpdateEvidenceAsync(UpdateEvidenceRequest request, Guid userId, CancellationToken cancellationToken = default);
|
||||
|
||||
ValueTask<Result<string>> GetEvidenceUrlAsync(string evidenceIdHash, CancellationToken cancellationToken = default);
|
||||
[Log]
|
||||
Task<Result<string>> GetEvidenceUrlAsync(string evidenceIdHash, CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
||||
@@ -1,26 +1,41 @@
|
||||
using PostFundManagement.Application.Services.Execution;
|
||||
using PostFundManagement.Domain;
|
||||
using PostFundManagement.Domain.Attributes;
|
||||
using PostFundManagement.Domain.Models;
|
||||
|
||||
namespace PostFundManagement.Application.Abstractions.Services;
|
||||
|
||||
public interface IExecutionService
|
||||
{
|
||||
ValueTask<Result<Risk[]>> GetRisksAsync(Pagination pagination, CancellationToken cancellationToken = default);
|
||||
[Log]
|
||||
Task<Result<Risk[]>> GetRisksAsync(Pagination pagination, CancellationToken cancellationToken = default);
|
||||
|
||||
ValueTask<Result<Disbursement[]>> GetDisbursementsAsync(Pagination pagination, CancellationToken cancellationToken = default);
|
||||
[Log]
|
||||
Task<Result<Disbursement[]>> GetDisbursementsAsync(Pagination pagination, CancellationToken cancellationToken = default);
|
||||
|
||||
ValueTask<Result> CreateRiskAsync(CreateRiskRequest request, Guid userId, CancellationToken cancellationToken = default);
|
||||
[Log]
|
||||
[Audit]
|
||||
Task<Result> CreateRiskAsync(CreateRiskRequest request, Guid userId, CancellationToken cancellationToken = default);
|
||||
|
||||
ValueTask<Result> CreateDisbursementAsync(CreateDisbursementRequest request, Guid userId, CancellationToken cancellationToken = default);
|
||||
[Log]
|
||||
[Audit]
|
||||
Task<Result> CreateDisbursementAsync(CreateDisbursementRequest request, Guid userId, CancellationToken cancellationToken = default);
|
||||
|
||||
ValueTask<Result> ApproveDisbursementAsync(string disbursementIdHash, Guid userId, CancellationToken cancellationToken = default);
|
||||
[Log]
|
||||
[Audit]
|
||||
Task<Result> ApproveDisbursementAsync(string disbursementIdHash, Guid userId, CancellationToken cancellationToken = default);
|
||||
|
||||
ValueTask<Result<Disbursement>> GetDisbursementAsync(string disbursementIdHash, CancellationToken cancellationToken = default);
|
||||
[Log]
|
||||
Task<Result<Disbursement>> GetDisbursementAsync(string disbursementIdHash, CancellationToken cancellationToken = default);
|
||||
|
||||
ValueTask<Result<Risk>> GetRiskAsync(string riskIdHash, CancellationToken cancellationToken = default);
|
||||
[Log]
|
||||
Task<Result<Risk>> GetRiskAsync(string riskIdHash, CancellationToken cancellationToken = default);
|
||||
|
||||
ValueTask<Result> UpdateRiskAsync(UpdateRiskRequest request, CancellationToken cancellationToken = default);
|
||||
[Log]
|
||||
[Audit]
|
||||
Task<Result> UpdateRiskAsync(UpdateRiskRequest request, CancellationToken cancellationToken = default);
|
||||
|
||||
ValueTask<Result> UpdateDisbursementAsync(UpdateDisbursementRequest request, Guid userId, CancellationToken cancellationToken = default);
|
||||
[Log]
|
||||
[Audit]
|
||||
Task<Result> UpdateDisbursementAsync(UpdateDisbursementRequest request, Guid userId, CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
||||
@@ -1,32 +1,81 @@
|
||||
using PostFundManagement.Application.Services.Governance;
|
||||
using PostFundManagement.Domain;
|
||||
using PostFundManagement.Domain.Attributes;
|
||||
using PostFundManagement.Domain.Models;
|
||||
|
||||
namespace PostFundManagement.Application.Abstractions.Services;
|
||||
|
||||
public interface IGovernanceService
|
||||
{
|
||||
ValueTask<Result<Programme[]>> GetProgrammesAsync(string portfolioIdHash, CancellationToken cancellationToken = default);
|
||||
[Log]
|
||||
Task<Result<Programme[]>> GetProgrammesAsync(string portfolioIdHash, CancellationToken cancellationToken = default);
|
||||
|
||||
ValueTask<Result<Portfolio[]>> GetPorfoliosAsync(string organisationIdHash, CancellationToken cancellationToken = default);
|
||||
[Log]
|
||||
Task<Result<Portfolio[]>> GetPorfoliosAsync(string organisationIdHash, CancellationToken cancellationToken = default);
|
||||
|
||||
ValueTask<Result<Organisation[]>> GetOrganisationsAsync(Pagination pagination, CancellationToken cancellationToken = default);
|
||||
[Log]
|
||||
Task<Result<Organisation[]>> GetOrganisationsAsync(Pagination pagination, CancellationToken cancellationToken = default);
|
||||
|
||||
ValueTask<Result<Organisation>> GetOrganisationAsync(string organisationIdHash, CancellationToken cancellationToken = default);
|
||||
[Log]
|
||||
Task<Result<Organisation>> GetOrganisationAsync(string organisationIdHash, CancellationToken cancellationToken = default);
|
||||
|
||||
ValueTask<Result<Instrument[]>> GetInstrumentsAsync(string programmeIdHash, CancellationToken cancellationToken = default);
|
||||
[Log]
|
||||
Task<Result<Instrument[]>> GetInstrumentsAsync(string programmeIdHash, CancellationToken cancellationToken = default);
|
||||
|
||||
ValueTask<Result<Dashboard>> GetDashboardAsync(CancellationToken cancellationToken = default);
|
||||
[Log]
|
||||
Task<Result<Dashboard>> GetDashboardAsync(CancellationToken cancellationToken = default);
|
||||
|
||||
ValueTask<Result> CreateOrganisationAsync(CreateOrganisationRequest request, Guid userId, CancellationToken cancellationToken = default);
|
||||
[Log]
|
||||
[Audit]
|
||||
Task<Result> CreateOrganisationAsync(CreateOrganisationRequest request, Guid userId, CancellationToken cancellationToken = default);
|
||||
|
||||
ValueTask<Result<Organisation>> UpdateOrganisationAsync(UpdateOrganisationRequest request, CancellationToken cancellationToken = default);
|
||||
[Log]
|
||||
[Audit]
|
||||
Task<Result<Organisation>> UpdateOrganisationAsync(UpdateOrganisationRequest request, CancellationToken cancellationToken = default);
|
||||
|
||||
ValueTask<Result> CreatePortfolioAsync(CreatePortfolioRequest request, Guid userId, CancellationToken cancellationToken = default);
|
||||
[Log]
|
||||
[Audit]
|
||||
Task<Result> CreatePortfolioAsync(CreatePortfolioRequest request, Guid userId, CancellationToken cancellationToken = default);
|
||||
|
||||
ValueTask<Result> UpdatePortfolioAsync(UpdatePortfolioRequest request, Guid userId, CancellationToken cancellationToken = default);
|
||||
[Log]
|
||||
[Audit]
|
||||
Task<Result> UpdatePortfolioAsync(UpdatePortfolioRequest request, Guid userId, CancellationToken cancellationToken = default);
|
||||
|
||||
ValueTask<Result<Programme[]>> GetPortfolioProgrammesAsync(string portfolioIdHash, CancellationToken cancellationToken = default);
|
||||
[Log]
|
||||
Task<Result<Programme[]>> GetPortfolioProgrammesAsync(string portfolioIdHash, CancellationToken cancellationToken = default);
|
||||
|
||||
ValueTask<Result<Portfolio>> GetPortfolioAsync(string portfolioIdHash, CancellationToken cancellationToken = default);
|
||||
[Log]
|
||||
Task<Result<Portfolio>> GetPortfolioAsync(string portfolioIdHash, CancellationToken cancellationToken = default);
|
||||
|
||||
[Log]
|
||||
[Audit]
|
||||
Task<Result> CreateTenantAsync(CreateTenantRequest request, Guid userId, CancellationToken cancellationToken = default);
|
||||
|
||||
[Log]
|
||||
Task<Result<Tenant[]>> GetTenantsAsync(CancellationToken cancellationToken = default);
|
||||
|
||||
[Log]
|
||||
Task<Result<Tenant>> GetTenantAsync(string tenantIdHash, CancellationToken cancellationToken = default);
|
||||
|
||||
[Log]
|
||||
[Audit]
|
||||
Task<Result> UpdateTenantAsync(UpdateTenantRequest request, Guid userId, CancellationToken cancellationToken = default);
|
||||
|
||||
[Log]
|
||||
[Audit]
|
||||
Task<Result> UpdateTenantUserAsync(UpdateTenantUserRequest request, Guid userId, CancellationToken cancellationToken = default);
|
||||
|
||||
[Log]
|
||||
[Audit]
|
||||
Task<Result> CreateTenantOrganisationAsync(string organisationIdHash, string tenantIdHash, Guid userId, CancellationToken cancellationToken = default);
|
||||
|
||||
[Log]
|
||||
[Audit]
|
||||
Task<Result> UpdateTenantOrganisationAsync(string tenantOrganisationIdHash, ActivityStatus status, Guid userId, CancellationToken cancellationToken = default);
|
||||
|
||||
[Log]
|
||||
Task<Result<TenantOrganisation[]>> GetTenantOrganisationsAsync(CancellationToken cancellationToken = default);
|
||||
|
||||
[Log]
|
||||
Task<Result<TenantOrganisation>> GetTenantOrganisationAsync(string tenantOrganisationIdHash, CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
||||
@@ -1,34 +1,55 @@
|
||||
using PostFundManagement.Application.Services.Grants;
|
||||
using PostFundManagement.Domain;
|
||||
using PostFundManagement.Domain.Attributes;
|
||||
using PostFundManagement.Domain.Models;
|
||||
|
||||
namespace PostFundManagement.Application.Abstractions.Services;
|
||||
|
||||
public interface IGrantsService
|
||||
{
|
||||
ValueTask<Result<Contract[]>> GetContractsAsync(Pagination pagination, CancellationToken cancellationToken = default);
|
||||
[Log]
|
||||
Task<Result<Contract[]>> GetContractsAsync(Pagination pagination, CancellationToken cancellationToken = default);
|
||||
|
||||
ValueTask<Result<Contract>> GetContractAsync(string contractIdHash, CancellationToken cancellationToken = default);
|
||||
[Log]
|
||||
Task<Result<Contract>> GetContractAsync(string contractIdHash, CancellationToken cancellationToken = default);
|
||||
|
||||
ValueTask<Result<Budget[]>> GetBudgetsAsync(Pagination pagination, CancellationToken cancellationToken = default);
|
||||
[Log]
|
||||
Task<Result<Budget[]>> GetBudgetsAsync(Pagination pagination, CancellationToken cancellationToken = default);
|
||||
|
||||
ValueTask<Result<Budget>> GetBudgetAsync(string budgetIdHash, CancellationToken cancellationToken = default);
|
||||
[Log]
|
||||
Task<Result<Budget>> GetBudgetAsync(string budgetIdHash, CancellationToken cancellationToken = default);
|
||||
|
||||
ValueTask<Result<Award[]>> GetAwardsAsync(Pagination pagination, CancellationToken cancellationToken = default);
|
||||
[Log]
|
||||
Task<Result<Award[]>> GetAwardsAsync(Pagination pagination, CancellationToken cancellationToken = default);
|
||||
|
||||
ValueTask<Result<Award>> GetAwardAsync(string awardIdHash, CancellationToken cancellationToken = default);
|
||||
[Log]
|
||||
Task<Result<Award>> GetAwardAsync(string awardIdHash, CancellationToken cancellationToken = default);
|
||||
|
||||
ValueTask<Result> ExecuteContractAsync(ExecuteContractRequest request, Guid userId, CancellationToken cancellationToken = default);
|
||||
[Log]
|
||||
[Audit]
|
||||
Task<Result> ExecuteContractAsync(ExecuteContractRequest request, Guid userId, CancellationToken cancellationToken = default);
|
||||
|
||||
ValueTask<Result> CreateContractAsync(CreateContractRequest request, Guid userId, CancellationToken cancellationToken = default);
|
||||
[Log]
|
||||
[Audit]
|
||||
Task<Result> CreateContractAsync(CreateContractRequest request, Guid userId, CancellationToken cancellationToken = default);
|
||||
|
||||
ValueTask<Result> CreateBudgetAsync(CreateBudgetRequest request, Guid userId, CancellationToken cancellationToken = default);
|
||||
[Log]
|
||||
[Audit]
|
||||
Task<Result> CreateBudgetAsync(CreateBudgetRequest request, Guid userId, CancellationToken cancellationToken = default);
|
||||
|
||||
ValueTask<Result> CreateAwardAsync(CreateAwardRequest request, Guid userId, CancellationToken cancellationToken = default);
|
||||
[Log]
|
||||
[Audit]
|
||||
Task<Result> CreateAwardAsync(CreateAwardRequest request, Guid userId, CancellationToken cancellationToken = default);
|
||||
|
||||
ValueTask<Result<string>> GetContractUrlAsync(string contractIdHash, CancellationToken cancellationToken = default);
|
||||
[Log]
|
||||
[Audit]
|
||||
Task<Result<string>> GetContractUrlAsync(string contractIdHash, CancellationToken cancellationToken = default);
|
||||
|
||||
ValueTask<Result> UploadContractAsync(string contractIdHash, Guid userId, IFormFile file, CancellationToken cancellationToken = default);
|
||||
[Log]
|
||||
[Audit]
|
||||
Task<Result> UploadContractAsync(string contractIdHash, Guid userId, IFormFile file, CancellationToken cancellationToken = default);
|
||||
|
||||
ValueTask<Result> UpdateContractAsync(UpdateContractRequest request, CancellationToken cancellationToken = default);
|
||||
[Log]
|
||||
[Audit]
|
||||
Task<Result> UpdateContractAsync(UpdateContractRequest request, CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
namespace PostFundManagement.Application.Abstractions.Services;
|
||||
using PostFundManagement.Domain.Attributes;
|
||||
|
||||
namespace PostFundManagement.Application.Abstractions.Services;
|
||||
|
||||
public interface IIdentityService
|
||||
{
|
||||
ValueTask<Result> UserIsAuthorisedAsync(Guid userId, CancellationToken cancellationToken = default);
|
||||
[Log]
|
||||
[Audit]
|
||||
Task<Result> UserIsAuthorisedAsync(Guid userId, CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
||||
@@ -1,46 +1,157 @@
|
||||
using PostFundManagement.Application.Services.Projects;
|
||||
using PostFundManagement.Domain;
|
||||
using PostFundManagement.Domain.Attributes;
|
||||
using PostFundManagement.Domain.Models;
|
||||
|
||||
namespace PostFundManagement.Application.Abstractions.Services;
|
||||
|
||||
public interface IProjectService
|
||||
{
|
||||
ValueTask<Result> UpdateProjectStatusAsync(UpdateProjectStatusRequest request, Guid userId, CancellationToken cancellationToken = default);
|
||||
[Log]
|
||||
[Audit]
|
||||
Task<Result> UpdateProjectStatusAsync(UpdateProjectStatusRequest request, Guid userId, CancellationToken cancellationToken = default);
|
||||
|
||||
ValueTask<Result<Project[]>> GetProjectsAsync(Pagination pagination, CancellationToken cancellationToken = default);
|
||||
[Log]
|
||||
Task<Result<Project[]>> GetProjectsAsync(Pagination pagination, CancellationToken cancellationToken = default);
|
||||
|
||||
ValueTask<Result<Project>> GetProjectAsync(string projectIdHash, CancellationToken cancellationToken = default);
|
||||
[Log]
|
||||
Task<Result<Project>> GetProjectAsync(string projectIdHash, CancellationToken cancellationToken = default);
|
||||
|
||||
ValueTask<Result<Domain.Models.Activity[]>> GetActivitiesAsync(string projectIdHash, CancellationToken cancellationToken = default);
|
||||
[Log]
|
||||
Task<Result<Domain.Models.Activity[]>> GetActivitiesAsync(string projectIdHash, CancellationToken cancellationToken = default);
|
||||
|
||||
ValueTask<Result> CreateProjectAsync(CreateProjectRequest request, Guid userId, CancellationToken cancellationToken = default);
|
||||
[Log]
|
||||
[Audit]
|
||||
Task<Result> CreateProjectAsync(CreateProjectRequest request, Guid userId, CancellationToken cancellationToken = default);
|
||||
|
||||
ValueTask<Result> CreateActivityAsync(CreateActivityRequest request, Guid userId, CancellationToken cancellationToken = default);
|
||||
[Log]
|
||||
[Audit]
|
||||
Task<Result> CreateActivityAsync(CreateActivityRequest request, Guid userId, CancellationToken cancellationToken = default);
|
||||
|
||||
ValueTask<Result<Milestone[]>> GetProjectMilestonesAsync(string projectIdHash, CancellationToken cancellationToken = default);
|
||||
[Log]
|
||||
Task<Result<Milestone[]>> GetProjectMilestonesAsync(string projectIdHash, CancellationToken cancellationToken = default);
|
||||
|
||||
ValueTask<Result<Indicator[]>> GetProjectIndicatorsAsync(string projectIdHash, CancellationToken cancellationToken = default);
|
||||
[Log]
|
||||
Task<Result<Indicator[]>> GetProjectIndicatorsAsync(string projectIdHash, CancellationToken cancellationToken = default);
|
||||
|
||||
ValueTask<Result<Milestone>> GetMilestoneAsync(string milestoneIdHash, CancellationToken cancellationToken = default);
|
||||
[Log]
|
||||
Task<Result<Milestone>> GetMilestoneAsync(string milestoneIdHash, CancellationToken cancellationToken = default);
|
||||
|
||||
ValueTask<Result<Milestone[]>> GetMilestonesAsync(Pagination pagination, CancellationToken cancellationToken = default);
|
||||
[Log]
|
||||
Task<Result<Milestone[]>> GetMilestonesAsync(Pagination pagination, CancellationToken cancellationToken = default);
|
||||
|
||||
ValueTask<Result> UpdateMilestoneAsync(UpdateMilestoneRequest request, Guid userId, CancellationToken cancellationToken = default);
|
||||
[Log]
|
||||
[Audit]
|
||||
Task<Result> UpdateMilestoneAsync(UpdateMilestoneRequest request, Guid userId, CancellationToken cancellationToken = default);
|
||||
|
||||
ValueTask<Result> UpdateProjectAsync(UpdateProjectRequest request, Guid userId, CancellationToken cancellationToken = default);
|
||||
[Log]
|
||||
[Audit]
|
||||
Task<Result> UpdateProjectAsync(UpdateProjectRequest request, Guid userId, CancellationToken cancellationToken = default);
|
||||
|
||||
ValueTask<Result<Domain.Models.Activity>> GetActivityAsync(string activityIdHash, CancellationToken cancellationToken = default);
|
||||
[Log]
|
||||
Task<Result<Domain.Models.Activity>> GetActivityAsync(string activityIdHash, CancellationToken cancellationToken = default);
|
||||
|
||||
ValueTask<Result<Risk[]>> GetProjectRisksAsync(string projectIdHash, CancellationToken cancellationToken = default);
|
||||
[Log]
|
||||
Task<Result<Risk[]>> GetProjectRisksAsync(string projectIdHash, CancellationToken cancellationToken = default);
|
||||
|
||||
ValueTask<Result> CreateProgrammeAsync(CreateProgrammeRequest request, Guid userId, CancellationToken cancellationToken = default);
|
||||
[Log]
|
||||
[Audit]
|
||||
Task<Result> CreateProgrammeAsync(CreateProgrammeRequest request, Guid userId, CancellationToken cancellationToken = default);
|
||||
|
||||
ValueTask<Result> UpdateProgrammeAsync(UpdateProgrammeRequest request, Guid userId, CancellationToken cancellationToken = default);
|
||||
[Log]
|
||||
[Audit]
|
||||
Task<Result> UpdateProgrammeAsync(UpdateProgrammeRequest request, Guid userId, CancellationToken cancellationToken = default);
|
||||
|
||||
ValueTask<Result<Programme>> GetProgrammeAsync(string programmeIdHash, CancellationToken cancellationToken = default);
|
||||
[Log]
|
||||
Task<Result<Programme>> GetProgrammeAsync(string programmeIdHash, CancellationToken cancellationToken = default);
|
||||
|
||||
ValueTask<Result<Programme[]>> GetProgrammesAsync(Pagination pagination, CancellationToken cancellationToken = default);
|
||||
[Log]
|
||||
Task<Result<Programme[]>> GetProgrammesAsync(Pagination pagination, CancellationToken cancellationToken = default);
|
||||
|
||||
ValueTask<Result<Project[]>> GetProgrammeProjectsAsync(string programmeIdHash, CancellationToken cancellationToken = default);
|
||||
[Log]
|
||||
Task<Result<Project[]>> GetProgrammeProjectsAsync(string programmeIdHash, CancellationToken cancellationToken = default);
|
||||
|
||||
[Log]
|
||||
[Audit]
|
||||
Task<Result> CreateChangeRequestAsync(CreateChangeRequest request, Guid userId, CancellationToken cancellationToken = default);
|
||||
|
||||
[Log]
|
||||
[Audit]
|
||||
Task<Result> UpdateChangeRequestAsync(UpdatehangeRequest request, Guid userId, CancellationToken cancellationToken = default);
|
||||
|
||||
[Log]
|
||||
Task<Result<ChangeRequest[]>> GetChangeRequestsAsync(string projectIdHash, CancellationToken cancellationToken = default);
|
||||
|
||||
[Log]
|
||||
Task<Result<ChangeRequest>> GetChangeRequestAsync(string changeRequestIdHash, CancellationToken cancellationToken = default);
|
||||
|
||||
[Log]
|
||||
[Audit]
|
||||
Task<Result> CreateComplianceItemAsync(CreateComplianceItemRequest request, Guid userId, CancellationToken cancellationToken = default);
|
||||
|
||||
[Log]
|
||||
[Audit]
|
||||
Task<Result> UpdateComplianceItemAsync(UpdateComplianceItemRequest request, Guid userId, CancellationToken cancellationToken = default);
|
||||
|
||||
[Log]
|
||||
Task<Result<ComplianceItem[]>> GetComplianceItemsAsync(string projectIdHash, CancellationToken cancellationToken = default);
|
||||
|
||||
[Log]
|
||||
Task<Result<ComplianceItem>> GetComplianceItemAsync(string complianceItemIdHash, CancellationToken cancellationToken = default);
|
||||
|
||||
[Log]
|
||||
[Audit]
|
||||
Task<Result> CreateBeneficiaryAsync(CreateBeneficiaryRequest request, Guid userId, CancellationToken cancellationToken = default);
|
||||
|
||||
[Log]
|
||||
[Audit]
|
||||
Task<Result> UpdateBeneficiaryItemAsync(UpdateBeneficiaryRequest request, Guid userId, CancellationToken cancellationToken = default);
|
||||
|
||||
[Log]
|
||||
Task<Result<Beneficiary[]>> GetBeneficiariesAsync(string projectIdHash, CancellationToken cancellationToken = default);
|
||||
|
||||
[Log]
|
||||
Task<Result<Beneficiary>> GetBeneficiaryAsync(string beneficiaryIdHash, CancellationToken cancellationToken = default);
|
||||
|
||||
[Log]
|
||||
[Audit]
|
||||
Task<Result> CreateIssueAsync(CreateIssueRequest request, Guid userId, CancellationToken cancellationToken = default);
|
||||
|
||||
[Log]
|
||||
[Audit]
|
||||
Task<Result> UpdateIssueAsync(UpdateIssueRequest request, Guid userId, CancellationToken cancellationToken = default);
|
||||
|
||||
[Log]
|
||||
Task<Result<Issue[]>> GetIssuesAsync(string projectIdHash, CancellationToken cancellationToken = default);
|
||||
|
||||
[Log]
|
||||
Task<Result<Issue>> GetIssueAsync(string issueIdHash, CancellationToken cancellationToken = default);
|
||||
|
||||
[Log]
|
||||
[Audit]
|
||||
Task<Result> CreateOutcomeAsync(CreateOutcomeRequest request, Guid userId, CancellationToken cancellationToken = default);
|
||||
|
||||
[Log]
|
||||
[Audit]
|
||||
Task<Result> UpdateOutcomeAsync(UpdateOutcomeRequest request, Guid userId, CancellationToken cancellationToken = default);
|
||||
|
||||
[Log]
|
||||
Task<Result<Outcome[]>> GetOutcomesAsync(string beneficiaryIdHash, CancellationToken cancellationToken = default);
|
||||
|
||||
[Log]
|
||||
Task<Result<Outcome>> GetOutcomeAsync(string outcomeIdHash, CancellationToken cancellationToken = default);
|
||||
|
||||
[Log]
|
||||
[Audit]
|
||||
Task<Result> CreateSiteVisitAsync(CreateSiteVisitRequest request, Guid userId, CancellationToken cancellationToken = default);
|
||||
|
||||
[Log]
|
||||
[Audit]
|
||||
Task<Result> UpdateSiteVisitAsync(UpdateSiteVisitRequest request, Guid userId, CancellationToken cancellationToken = default);
|
||||
|
||||
[Log]
|
||||
Task<Result<SiteVisit[]>> GetSiteVisitsAsync(string projectIdHash, CancellationToken cancellationToken = default);
|
||||
|
||||
[Log]
|
||||
Task<Result<SiteVisit>> GetSiteVisitAsync(string siteVisitIdHash, CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
||||
@@ -2,5 +2,5 @@
|
||||
|
||||
public interface IToolService
|
||||
{
|
||||
ValueTask<Result<string>> EncodeLong(long id, CancellationToken cancellationToken);
|
||||
Task<Result<string>> EncodeLong(long id, CancellationToken cancellationToken);
|
||||
}
|
||||
|
||||
@@ -1,16 +1,23 @@
|
||||
using PostFundManagement.Application.Services.Users;
|
||||
using PostFundManagement.Domain;
|
||||
using PostFundManagement.Domain.Attributes;
|
||||
using PostFundManagement.Domain.Models;
|
||||
|
||||
namespace PostFundManagement.Application.Abstractions.Services;
|
||||
|
||||
public interface IUserService
|
||||
{
|
||||
ValueTask<Result> SyncUserAsync(Guid userId, string email, CancellationToken cancellationToken = default);
|
||||
[Log]
|
||||
[Audit]
|
||||
Task<Result> SyncUserAsync(Guid userId, string email, CancellationToken cancellationToken = default);
|
||||
|
||||
ValueTask<Result<User[]>> GetUsersAsync(Pagination pagination, UserFilterRequest request, CancellationToken cancellationToken = default);
|
||||
[Log]
|
||||
Task<Result<User[]>> GetUsersAsync(Pagination pagination, UserFilterRequest request, CancellationToken cancellationToken = default);
|
||||
|
||||
ValueTask<Result> UpdateUserStatusAsync(Guid userId, ActivityStatus status, CancellationToken cancellationToken = default);
|
||||
[Log]
|
||||
[Audit]
|
||||
Task<Result> UpdateUserStatusAsync(Guid userId, ActivityStatus status, CancellationToken cancellationToken = default);
|
||||
|
||||
ValueTask<Result<User>> GetUserAsync(Guid userId, CancellationToken cancellationToken);
|
||||
[Log]
|
||||
Task<Result<User>> GetUserAsync(Guid userId, CancellationToken cancellationToken);
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ public static class Quartz
|
||||
{
|
||||
public static IServiceCollection AddQuartzSchedulerClient(this IServiceCollection services, string schedulerName, IConfiguration configuration)
|
||||
{
|
||||
var connectionString = configuration.GetConnectionString(DatabaseConfigName);
|
||||
var connectionString = configuration.GetConnectionString(SchedulerDatabaseConfigName);
|
||||
|
||||
services.Configure<QuartzOptions>(options =>
|
||||
{
|
||||
@@ -44,7 +44,7 @@ public static class Quartz
|
||||
|
||||
public static IServiceCollection AddQuartzScheduler(this IServiceCollection services, string schedulerName, IConfiguration configuration)
|
||||
{
|
||||
var connectionString = configuration.GetConnectionString(DatabaseConfigName);
|
||||
var connectionString = configuration.GetConnectionString(SchedulerDatabaseConfigName);
|
||||
|
||||
services.Configure<QuartzOptions>(options =>
|
||||
{
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using PostFundManagement.Application.Abstractions;
|
||||
using PostFundManagement.Application.Abstractions.Services;
|
||||
using PostFundManagement.Application.Interceptors;
|
||||
using PostFundManagement.Application.Services.Communications;
|
||||
using PostFundManagement.Application.Services.Evidence;
|
||||
using PostFundManagement.Application.Services.Execution;
|
||||
@@ -7,7 +8,6 @@ using PostFundManagement.Application.Services.Governance;
|
||||
using PostFundManagement.Application.Services.Grants;
|
||||
using PostFundManagement.Application.Services.Projects;
|
||||
using PostFundManagement.Application.Services.Shared;
|
||||
using PostFundManagement.Application.Services.Tools;
|
||||
using PostFundManagement.Application.Services.Users;
|
||||
using PostFundManagement.Domain.Abstractions;
|
||||
|
||||
@@ -15,34 +15,71 @@ namespace PostFundManagement.Application.Extensions;
|
||||
|
||||
public static class Services
|
||||
{
|
||||
public static IServiceCollection AddLoggedCachedServiceScoped<TInterface, TImplementation, TCacheDecorator>(this IServiceCollection services)
|
||||
where TInterface : class
|
||||
where TImplementation : class, TInterface
|
||||
where TCacheDecorator : class, TInterface
|
||||
{
|
||||
services.AddScoped<TImplementation>();
|
||||
services.AddScoped<TCacheDecorator>();
|
||||
|
||||
services.AddScoped(sp =>
|
||||
{
|
||||
var proxyGenerator = sp.GetRequiredService<ProxyGenerator>();
|
||||
var loggingInterceptor = sp.GetRequiredService<LoggingInterceptor>();
|
||||
|
||||
var actual = sp.GetRequiredService<TImplementation>();
|
||||
|
||||
var cached = ActivatorUtilities.CreateInstance<TCacheDecorator>(sp, actual);
|
||||
|
||||
return proxyGenerator.CreateInterfaceProxyWithTarget<TInterface>(cached,
|
||||
loggingInterceptor.ToInterceptor());
|
||||
});
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
public static IServiceCollection AddLoggedAuditedCachedServiceScoped<TInterface, TImplementation, TCacheDecorator>(this IServiceCollection services)
|
||||
where TInterface : class
|
||||
where TImplementation : class, TInterface
|
||||
where TCacheDecorator : class, TInterface
|
||||
{
|
||||
services.AddScoped<TImplementation>();
|
||||
services.AddScoped<TCacheDecorator>();
|
||||
|
||||
services.AddScoped(sp =>
|
||||
{
|
||||
var proxyGenerator = sp.GetRequiredService<ProxyGenerator>();
|
||||
var auditInterceptor = sp.GetRequiredService<AuditInterceptor>();
|
||||
var loggingInterceptor = sp.GetRequiredService<LoggingInterceptor>();
|
||||
|
||||
var actual = sp.GetRequiredService<TImplementation>();
|
||||
|
||||
var cached = ActivatorUtilities.CreateInstance<TCacheDecorator>(sp, actual);
|
||||
|
||||
return proxyGenerator.CreateInterfaceProxyWithTarget<TInterface>(cached,
|
||||
loggingInterceptor.ToInterceptor(),
|
||||
auditInterceptor.ToInterceptor());
|
||||
});
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
public static IServiceCollection AddRegisterServicesWithCaching(this IServiceCollection services, IConfiguration configuration)
|
||||
{
|
||||
services.AddScoped<ICommunicationsService, CommunicationsService>();
|
||||
services.Decorate<ICommunicationsService, CommunicationsCacheService>();
|
||||
services.AddScoped<AuditInterceptor>();
|
||||
services.AddScoped<LoggingInterceptor>();
|
||||
services.AddSingleton<ProxyGenerator>();
|
||||
|
||||
services.AddScoped<IEvidenceService, EvidenceService>();
|
||||
services.Decorate<IEvidenceService, EvidenceCacheService>();
|
||||
services.AddLoggedAuditedCachedServiceScoped<ICommunicationsService, CommunicationsService, CommunicationsCacheService>();
|
||||
services.AddLoggedAuditedCachedServiceScoped<IEvidenceService, EvidenceService, EvidenceCacheService>();
|
||||
services.AddLoggedAuditedCachedServiceScoped<IUserService, UserService, UserCacheService>();
|
||||
services.AddLoggedAuditedCachedServiceScoped<IExecutionService, ExecutionService, ExecutionCacheService>();
|
||||
services.AddLoggedAuditedCachedServiceScoped<IGovernanceService, GovernanceService, GovernanceCacheService>();
|
||||
services.AddLoggedAuditedCachedServiceScoped<IGrantsService, GrantsService, GrantsCacheService>();
|
||||
services.AddLoggedAuditedCachedServiceScoped<IProjectService, ProjectService, ProjectCacheService>();
|
||||
|
||||
services.AddScoped<IUserService, UserService>();
|
||||
services.Decorate<IUserService, UserCacheService>();
|
||||
|
||||
services.AddScoped<IIdentityService, IdentityService>();
|
||||
services.Decorate<IIdentityService, IdentityCacheService>();
|
||||
|
||||
services.AddScoped<IExecutionService, ExecutionService>();
|
||||
services.Decorate<IExecutionService, ExecutionCacheService>();
|
||||
|
||||
services.AddScoped<IGovernanceService, GovernanceService>();
|
||||
services.Decorate<IGovernanceService, GovernanceCacheService>();
|
||||
|
||||
services.AddScoped<IGrantsService, GrantsService>();
|
||||
services.Decorate<IGrantsService, GrantsCacheService>();
|
||||
|
||||
services.AddScoped<IProjectService, ProjectService>();
|
||||
services.Decorate<IProjectService, ProjectCacheService>();
|
||||
|
||||
services.AddScoped<IToolService, ToolService>();
|
||||
services.Decorate<IToolService, ToolCacheService>();
|
||||
services.AddLoggedCachedServiceScoped<IIdentityService, IdentityService, IdentityCacheService>();
|
||||
|
||||
services.AddStackExchangeRedisCache(options =>
|
||||
{
|
||||
|
||||
@@ -25,8 +25,12 @@ public sealed class ActiveUserFilter(IIdentityService identityService) : IEndpoi
|
||||
var path = context.HttpContext.Request.Path.Value;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(path) && !path!.EndsWith("integration/sync", StringComparison.InvariantCultureIgnoreCase))
|
||||
if ((await identityService.UserIsAuthorisedAsync(userId, context.HttpContext.RequestAborted)).IsFailed)
|
||||
return (object?)Results.Json(new { message = "Account approval is pending or inactive." }, statusCode: StatusCodes.Status403Forbidden);
|
||||
{
|
||||
var userAuthResult = await identityService.UserIsAuthorisedAsync(userId, context.HttpContext.RequestAborted);
|
||||
|
||||
if (userAuthResult.IsFailed)
|
||||
return Results.Json(new { message = "Account approval is pending or inactive." }, statusCode: StatusCodes.Status403Forbidden);
|
||||
}
|
||||
|
||||
context.HttpContext.Items[UserIdItemKey] = userId;
|
||||
context.HttpContext.Items[EmailtemKey] = email;
|
||||
|
||||
@@ -0,0 +1,211 @@
|
||||
using PostFundManagement.Application.Services.Shared;
|
||||
using PostFundManagement.Domain.Attributes;
|
||||
|
||||
namespace PostFundManagement.Application.Interceptors;
|
||||
|
||||
public sealed class AuditInterceptor(AuditService auditService, IHttpContextAccessor httpContextAccessor) : IAsyncInterceptor
|
||||
{
|
||||
public void InterceptSynchronous(IInvocation invocation) => invocation.Proceed();
|
||||
|
||||
public void InterceptAsynchronous(IInvocation invocation) =>
|
||||
invocation.ReturnValue = InternalInterceptAsynchronous(invocation);
|
||||
|
||||
public void InterceptAsynchronous<TResult>(IInvocation invocation) =>
|
||||
invocation.ReturnValue = InternalInterceptAsynchronous<TResult>(invocation);
|
||||
|
||||
private static async Task InternalInterceptAsynchronous(IInvocation invocation)
|
||||
{
|
||||
invocation.Proceed();
|
||||
|
||||
var task = (Task)invocation.ReturnValue;
|
||||
|
||||
await task.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async Task<TResult> InternalInterceptAsynchronous<TResult>(IInvocation invocation)
|
||||
{
|
||||
invocation.Proceed();
|
||||
|
||||
var task = (Task<TResult>)invocation.ReturnValue;
|
||||
var resultObj = await task.ConfigureAwait(false);
|
||||
|
||||
var method = invocation.MethodInvocationTarget ?? invocation.Method;
|
||||
var auditAttr = method.GetCustomAttribute<AuditAttribute>()
|
||||
?? invocation.Method.GetCustomAttribute<AuditAttribute>();
|
||||
|
||||
if (auditAttr == null) return resultObj;
|
||||
|
||||
if (resultObj is IResultBase result && result.IsSuccess)
|
||||
{
|
||||
try
|
||||
{
|
||||
var action = ResolveActionName(method.Name);
|
||||
var entityName = ResolveEntityName(method, resultObj, invocation.Arguments);
|
||||
var entityId = ResolveEntityId(resultObj, invocation.Arguments);
|
||||
var changes = BuildPayloadSummary(invocation.Method.GetParameters(), invocation.Arguments);
|
||||
var performedBy = ResolveUserId();
|
||||
|
||||
await auditService.LogActionAsync(
|
||||
entityId: entityId,
|
||||
entityName: entityName,
|
||||
action: action,
|
||||
changes: changes,
|
||||
performedBy: performedBy).ConfigureAwait(false);
|
||||
}
|
||||
catch { /* eat all exceptions, don't interrupt program flow */ }
|
||||
}
|
||||
|
||||
return resultObj;
|
||||
}
|
||||
|
||||
private static string ResolveActionName(string methodName) =>
|
||||
methodName.EndsWith("Async", StringComparison.Ordinal)
|
||||
? methodName[..^5]
|
||||
: methodName;
|
||||
|
||||
private static string ResolveEntityName(MethodInfo method, object? resultObj, object[] args)
|
||||
{
|
||||
var returnType = method.ReturnType;
|
||||
|
||||
Type? innerType = null;
|
||||
|
||||
if (returnType.IsGenericType)
|
||||
{
|
||||
var genericDef = returnType.GetGenericTypeDefinition();
|
||||
|
||||
if (genericDef == typeof(Task<>) || genericDef == typeof(Task<>))
|
||||
innerType = returnType.GetGenericArguments()[0];
|
||||
}
|
||||
|
||||
if (innerType != null && innerType.IsGenericType && typeof(IResultBase).IsAssignableFrom(innerType))
|
||||
{
|
||||
var valueType = innerType.GetGenericArguments().FirstOrDefault();
|
||||
|
||||
if (valueType != null && valueType != typeof(bool) && valueType != typeof(int) && valueType != typeof(string))
|
||||
return valueType.Name;
|
||||
}
|
||||
|
||||
foreach (var arg in args)
|
||||
{
|
||||
if (arg == null || arg is CancellationToken or IFormFile) continue;
|
||||
|
||||
var argTypeName = arg.GetType().Name;
|
||||
|
||||
if (argTypeName.EndsWith("Request", StringComparison.Ordinal))
|
||||
{
|
||||
var trimmed = argTypeName[..^7];
|
||||
|
||||
return trimmed.Replace("Create", "").Replace("Update", "");
|
||||
}
|
||||
}
|
||||
|
||||
return ResolveActionName(method.Name);
|
||||
}
|
||||
|
||||
private static string ResolveEntityId(object? resultObj, object[] args)
|
||||
{
|
||||
if (resultObj != null)
|
||||
{
|
||||
var valueProp = resultObj.GetType().GetProperty("Value");
|
||||
if (valueProp != null)
|
||||
{
|
||||
var value = valueProp.GetValue(resultObj);
|
||||
if (value != null)
|
||||
{
|
||||
var idProp = value.GetType().GetProperty("Id") ?? value.GetType().GetProperty("id");
|
||||
if (idProp != null)
|
||||
{
|
||||
var idVal = idProp.GetValue(value);
|
||||
if (idVal != null) return idVal.ToString()!;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var arg in args)
|
||||
{
|
||||
if (arg is long or int or Guid or string)
|
||||
return arg.ToString()!;
|
||||
|
||||
if (arg != null && arg is not CancellationToken and not IFormFile)
|
||||
{
|
||||
var idProp = arg.GetType().GetProperty("Id") ?? arg.GetType().GetProperty("id");
|
||||
|
||||
if (idProp != null)
|
||||
{
|
||||
var idVal = idProp.GetValue(arg);
|
||||
|
||||
if (idVal != null) return idVal.ToString()!;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return "N/A";
|
||||
}
|
||||
|
||||
private static string[] BuildPayloadSummary(ParameterInfo[] parameters, object[] args)
|
||||
{
|
||||
var entries = new List<string>();
|
||||
|
||||
for (var i = 0; i < parameters.Length; i++)
|
||||
{
|
||||
var param = parameters[i];
|
||||
var arg = args[i];
|
||||
|
||||
if (param.ParameterType == typeof(CancellationToken))
|
||||
continue;
|
||||
|
||||
if (arg == null)
|
||||
{
|
||||
entries.Add($"{param.Name}: null");
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (arg is IFormFile file)
|
||||
{
|
||||
entries.Add($"{param.Name}: [File] Name='{file.FileName}', Size={file.Length} bytes, Type='{file.ContentType}'");
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (arg is IEnumerable<IFormFile> files)
|
||||
{
|
||||
var fileSummaries = files.Select(f => $"'{f.FileName}' ({f.Length} bytes)");
|
||||
|
||||
entries.Add($"{param.Name}: [Files] count={fileSummaries.Count()} [{string.Join(", ", fileSummaries)}]");
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (arg is Stream stream)
|
||||
{
|
||||
entries.Add($"{param.Name}: [Stream] Length={(stream.CanSeek ? stream.Length : -1)} bytes");
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var json = JsonSerializer.Serialize(arg);
|
||||
|
||||
entries.Add($"{param.Name}: {json}");
|
||||
}
|
||||
catch
|
||||
{
|
||||
entries.Add($"{param.Name}: [Unserializable]");
|
||||
}
|
||||
}
|
||||
|
||||
return [.. entries];
|
||||
}
|
||||
|
||||
private Guid ResolveUserId()
|
||||
{
|
||||
var user = httpContextAccessor.HttpContext?.User;
|
||||
|
||||
var sub = user?.FindFirst(ClaimTypes.NameIdentifier)?.Value ?? user?.FindFirst("sub")?.Value;
|
||||
|
||||
return Guid.TryParse(sub, out var guid) ? guid : Guid.Empty;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
using PostFundManagement.Domain.Attributes;
|
||||
|
||||
namespace PostFundManagement.Application.Interceptors;
|
||||
|
||||
public sealed class LoggingInterceptor(ILogger<LoggingInterceptor> logger) : IAsyncInterceptor
|
||||
{
|
||||
public void InterceptSynchronous(IInvocation invocation)
|
||||
{
|
||||
invocation.Proceed();
|
||||
|
||||
CheckAndLogIfFailed(invocation, invocation.ReturnValue);
|
||||
}
|
||||
|
||||
public void InterceptAsynchronous(IInvocation invocation) =>
|
||||
invocation.ReturnValue = InternalInterceptAsynchronous(invocation);
|
||||
|
||||
public void InterceptAsynchronous<TResult>(IInvocation invocation) =>
|
||||
invocation.ReturnValue = InternalInterceptAsynchronous<TResult>(invocation);
|
||||
|
||||
private static async Task InternalInterceptAsynchronous(IInvocation invocation)
|
||||
{
|
||||
invocation.Proceed();
|
||||
|
||||
var task = (Task)invocation.ReturnValue;
|
||||
|
||||
await task.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async Task<TResult> InternalInterceptAsynchronous<TResult>(IInvocation invocation)
|
||||
{
|
||||
invocation.Proceed();
|
||||
|
||||
var task = (Task<TResult>)invocation.ReturnValue;
|
||||
var resultObj = await task.ConfigureAwait(false);
|
||||
|
||||
var method = invocation.MethodInvocationTarget ?? invocation.Method;
|
||||
var auditAttr = method.GetCustomAttribute<LogAttribute>()
|
||||
?? invocation.Method.GetCustomAttribute<LogAttribute>();
|
||||
|
||||
if (auditAttr == null) return resultObj;
|
||||
|
||||
CheckAndLogIfFailed(invocation, resultObj);
|
||||
|
||||
return resultObj;
|
||||
}
|
||||
|
||||
private void CheckAndLogIfFailed(IInvocation invocation, object? resultObj)
|
||||
{
|
||||
if (resultObj is IResultBase result && result.IsFailed)
|
||||
{
|
||||
try
|
||||
{
|
||||
var method = invocation.MethodInvocationTarget ?? invocation.Method;
|
||||
var parameters = BuildPayloadSummary(method.GetParameters(), invocation.Arguments);
|
||||
|
||||
var errorMessages = new List<string>();
|
||||
|
||||
if (result.Reasons != null)
|
||||
{
|
||||
foreach (var reason in result.Reasons)
|
||||
if (reason is IError error)
|
||||
errorMessages.Add(error.Message);
|
||||
}
|
||||
|
||||
var errorsString = string.Join("; ", errorMessages);
|
||||
|
||||
logger.LogError("Method {MethodName} failed. Errors: [{ErrorType}] {Errors}. Parameters: {@Parameters}",
|
||||
method.Name, result.Reasons?.FirstOrDefault()?.GetType().Name.Replace("Error", string.Empty), errorsString, parameters);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogWarning(ex, "Failed to write error log for method {MethodName}.", invocation.Method.Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static string[] BuildPayloadSummary(ParameterInfo[] parameters, object[] args)
|
||||
{
|
||||
var entries = new List<string>();
|
||||
|
||||
for (var i = 0; i < parameters.Length; i++)
|
||||
{
|
||||
var param = parameters[i];
|
||||
var arg = args[i];
|
||||
|
||||
if (param.ParameterType == typeof(CancellationToken))
|
||||
continue;
|
||||
|
||||
if (arg == null)
|
||||
{
|
||||
entries.Add($"{param.Name}: null");
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (arg is IFormFile file)
|
||||
{
|
||||
entries.Add($"{param.Name}: [File] Name='{file.FileName}', Size={file.Length} bytes, Type='{file.ContentType}'");
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (arg is IEnumerable<IFormFile> files)
|
||||
{
|
||||
var fileSummaries = new List<string>();
|
||||
|
||||
foreach (var f in files)
|
||||
fileSummaries.Add($"'{f.FileName}' ({f.Length} bytes)");
|
||||
|
||||
entries.Add($"{param.Name}: [Files] count={fileSummaries.Count} [{string.Join(", ", fileSummaries)}]");
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (arg is Stream stream)
|
||||
{
|
||||
entries.Add($"{param.Name}: [Stream] Length={(stream.CanSeek ? stream.Length : -1)} bytes");
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var json = JsonSerializer.Serialize(arg);
|
||||
|
||||
entries.Add($"{param.Name}: {json}");
|
||||
}
|
||||
catch
|
||||
{
|
||||
entries.Add($"{param.Name}: [Unserializable]");
|
||||
}
|
||||
}
|
||||
|
||||
return [.. entries];
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,7 @@
|
||||
|
||||
<!-- API Documentation -->
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Castle.Core.AsyncInterceptor" Version="2.1.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="10.0.12" />
|
||||
<PackageReference Include="Microsoft.Extensions.Validation" Version="10.0.12" />
|
||||
<PackageReference Include="Scalar.AspNetCore" Version="2.17.4" />
|
||||
@@ -36,6 +37,7 @@
|
||||
<!-- Shared Usings -->
|
||||
<ItemGroup>
|
||||
<Using Include="Humanizer" />
|
||||
<Using Include="Castle.DynamicProxy" />
|
||||
<Using Include="Microsoft.FeatureManagement" />
|
||||
<Using Include="System.ComponentModel.DataAnnotations" />
|
||||
<Using Include="Microsoft.Extensions.Caching.Distributed" />
|
||||
|
||||
+62
-8
@@ -11,8 +11,11 @@ namespace PostFundManagement.Application.Services.Communications;
|
||||
public sealed class CommunicationsCacheService(CommunicationsService service, IDistributedCache cache,
|
||||
IFeatureManager featureManager) : ServiceCacheBase, ICommunicationsService
|
||||
{
|
||||
public async ValueTask<Result<Invite>> GetApplicantInviteAsync(Guid applicantUserId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Invite>>>)(async () =>
|
||||
public async Task<Result> CreateNotificationAsync(CreateNotificationRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await service.CreateNotificationAsync(request, userId, cancellationToken);
|
||||
|
||||
public async Task<Result<Invite>> GetApplicantInviteAsync(Guid applicantUserId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Invite>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetApplicantInviteAsync(applicantUserId, cancellationToken);
|
||||
@@ -33,8 +36,8 @@ public sealed class CommunicationsCacheService(CommunicationsService service, ID
|
||||
return Result.Ok(cached!.FromJson<Invite>());
|
||||
}));
|
||||
|
||||
public async ValueTask<Result<Invite[]>> GetApplicantInvitesAsync(Guid applicantUserId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Invite[]>>>)(async () =>
|
||||
public async Task<Result<Invite[]>> GetApplicantInvitesAsync(Guid applicantUserId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Invite[]>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetApplicantInvitesAsync(applicantUserId, cancellationToken);
|
||||
@@ -57,8 +60,8 @@ public sealed class CommunicationsCacheService(CommunicationsService service, ID
|
||||
return Result.Ok(cached.FromJson<Invite[]>());
|
||||
}));
|
||||
|
||||
public async ValueTask<Result<Invite[]>> GetInvitesAsync(Pagination pagination, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Invite[]>>>)(async () =>
|
||||
public async Task<Result<Invite[]>> GetInvitesAsync(Pagination pagination, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Invite[]>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetInvitesAsync(pagination, cancellationToken);
|
||||
@@ -81,6 +84,57 @@ public sealed class CommunicationsCacheService(CommunicationsService service, ID
|
||||
return Result.Ok(cached.FromJson<Invite[]>());
|
||||
}));
|
||||
|
||||
public async ValueTask<Result<Invite>> SendInviteAsync(InviteRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await service.SendInviteAsync(request, userId, cancellationToken);
|
||||
public async Task<Result<Notification>> GetNotificationAsync(string notificationIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Notification>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetNotificationAsync(notificationIdHash, cancellationToken);
|
||||
|
||||
var cacheKey = HashService.ToMd5Hash($"getnotification-{notificationIdHash}").Value;
|
||||
|
||||
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(cached))
|
||||
{
|
||||
var result = await service.GetNotificationAsync(notificationIdHash, cancellationToken);
|
||||
|
||||
if (result.IsFailed) return result;
|
||||
|
||||
await cache.SetStringAsync(cacheKey, result.Value.ToJson(), cacheOptions, cancellationToken);
|
||||
|
||||
return Result.Ok(result.Value);
|
||||
}
|
||||
|
||||
return Result.Ok(cached.FromJson<Notification>());
|
||||
}));
|
||||
|
||||
public async Task<Result<Notification[]>> GetNotificationsAsync(string organisationIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Notification[]>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetNotificationsAsync(organisationIdHash, cancellationToken);
|
||||
|
||||
var cacheKey = HashService.ToMd5Hash($"getnotifications-{organisationIdHash}").Value;
|
||||
|
||||
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(cached))
|
||||
{
|
||||
var result = await service.GetNotificationsAsync(organisationIdHash, cancellationToken);
|
||||
|
||||
if (result.IsFailed) return result;
|
||||
|
||||
await cache.SetStringAsync(cacheKey, result.Value.ToJson(), cacheOptions, cancellationToken);
|
||||
|
||||
return Result.Ok(result.Value);
|
||||
}
|
||||
|
||||
return Result.Ok(cached.FromJson<Notification[]>());
|
||||
}));
|
||||
|
||||
public async Task<Result<Invite>> SendInviteAsync(InviteRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await service.SendInviteAsync(request, userId, cancellationToken);
|
||||
|
||||
public async Task<Result> UpdateNotificationAsync(UpdateNotificationRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await service.UpdateNotificationAsync(request, userId, cancellationToken);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using PostFundManagement.Application.Abstractions.Services;
|
||||
using PostFundManagement.Domain;
|
||||
using PostFundManagement.Domain.Abstractions;
|
||||
using PostFundManagement.Domain.Errors;
|
||||
using PostFundManagement.Domain.Extensions;
|
||||
using PostFundManagement.Domain.Models;
|
||||
@@ -7,10 +8,10 @@ using PostFundManagement.Infrastructure.Database;
|
||||
|
||||
namespace PostFundManagement.Application.Services.Communications;
|
||||
|
||||
public sealed class CommunicationsService(IDbContextFactory<ApplicationDbContext> contextFactory) : ICommunicationsService
|
||||
public sealed class CommunicationsService(IDbContextFactory<ApplicationDbContext> contextFactory, ITenantContextService tenantContext) : ICommunicationsService
|
||||
{
|
||||
public async ValueTask<Result<Invite>> SendInviteAsync(InviteRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Invite>>>)(async () =>
|
||||
public async Task<Result<Invite>> SendInviteAsync(InviteRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Invite>>>)(async () =>
|
||||
{
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
@@ -35,15 +36,16 @@ public sealed class CommunicationsService(IDbContextFactory<ApplicationDbContext
|
||||
Status = NotificationStatus.Pending,
|
||||
Subject = "Invitation to Onboard",
|
||||
Message = request.Message,
|
||||
CreatedAt = DateTime.UtcNow
|
||||
CreatedAt = DateTime.UtcNow,
|
||||
TenantId = tenantContext.TenantId
|
||||
});
|
||||
|
||||
return Result.FailIf(await context.SaveChangesAsync(cancellationToken) <= 0, CreateError.New)
|
||||
.ToResult(invite.Map());
|
||||
}));
|
||||
|
||||
public async ValueTask<Result<Invite[]>> GetInvitesAsync(Pagination pagination, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Invite[]>>>)(async () =>
|
||||
public async Task<Result<Invite[]>> GetInvitesAsync(Pagination pagination, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Invite[]>>>)(async () =>
|
||||
{
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
@@ -56,8 +58,8 @@ public sealed class CommunicationsService(IDbContextFactory<ApplicationDbContext
|
||||
return Result.Ok(invites.Select(i => i.Map()).ToArray());
|
||||
}));
|
||||
|
||||
public async ValueTask<Result<Invite>> GetApplicantInviteAsync(Guid applicantUserId, CancellationToken cancellationToken) =>
|
||||
await Result.Try((Func<ValueTask<Result<Invite>>>)(async () =>
|
||||
public async Task<Result<Invite>> GetApplicantInviteAsync(Guid applicantUserId, CancellationToken cancellationToken) =>
|
||||
await Result.Try((Func<Task<Result<Invite>>>)(async () =>
|
||||
{
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
@@ -67,8 +69,8 @@ public sealed class CommunicationsService(IDbContextFactory<ApplicationDbContext
|
||||
.ToResult(invite!.Map());
|
||||
}));
|
||||
|
||||
public async ValueTask<Result<Invite[]>> GetApplicantInvitesAsync(Guid applicantUserId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Invite[]>>>)(async () =>
|
||||
public async Task<Result<Invite[]>> GetApplicantInvitesAsync(Guid applicantUserId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Invite[]>>>)(async () =>
|
||||
{
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
@@ -79,4 +81,24 @@ public sealed class CommunicationsService(IDbContextFactory<ApplicationDbContext
|
||||
|
||||
return Result.Ok(invites.Select(i => i.Map()).ToArray());
|
||||
}));
|
||||
|
||||
public Task<Result> CreateNotificationAsync(CreateNotificationRequest request, Guid userId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<Result> UpdateNotificationAsync(UpdateNotificationRequest request, Guid userId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<Result<Notification[]>> GetNotificationsAsync(string organisationIdHash, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<Result<Notification>> GetNotificationAsync(string notificationIdHash, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,18 @@ using static PostFundManagement.Domain.Extensions.Constants;
|
||||
|
||||
namespace PostFundManagement.Application.Services.Communications;
|
||||
|
||||
public sealed record UpdateNotificationRequest([Required] long NotificationId,
|
||||
[Required] NotificationStatus Status,
|
||||
[Required] DateTime SentAt,
|
||||
[Required][MaxLength(TextLength)] string Error);
|
||||
|
||||
public sealed record CreateNotificationRequest([Required] long OrganisationId,
|
||||
[Required] Guid Recipient,
|
||||
[Required] NotificationPlatform Platform,
|
||||
[Required][MaxLength(LabelLength)] string? Subject,
|
||||
[Required][MaxLength(LabelLength)] string? Destination,
|
||||
[Required][MaxLength(TextLength)] string Message);
|
||||
|
||||
public sealed record InviteRequest([Required] long OrganisationId,
|
||||
[Required] long InvitedOrganisationId,
|
||||
[Required] long AwardId,
|
||||
|
||||
@@ -11,17 +11,17 @@ namespace PostFundManagement.Application.Services.Evidence;
|
||||
public sealed class EvidenceCacheService(EvidenceService service, IDistributedCache cache,
|
||||
IFeatureManager featureManager) : ServiceCacheBase, IEvidenceService
|
||||
{
|
||||
public async ValueTask<Result> CreateEvidenceAsync(Guid userId, IFormCollection form, IFormFile file, CancellationToken cancellationToken = default) =>
|
||||
public async Task<Result> CreateEvidenceAsync(Guid userId, IFormCollection form, IFormFile file, CancellationToken cancellationToken = default) =>
|
||||
await service.CreateEvidenceAsync(userId, form, file, cancellationToken);
|
||||
|
||||
public async ValueTask<Result> CreateIndicatorAsync(CreateIndicatorRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
public async Task<Result> CreateIndicatorAsync(CreateIndicatorRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await service.CreateIndicatorAsync(request, userId, cancellationToken);
|
||||
|
||||
public async ValueTask<Result> CreateMilestoneAsync(CreateMilestoneRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
public async Task<Result> CreateMilestoneAsync(CreateMilestoneRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await service.CreateMilestoneAsync(request, userId, cancellationToken);
|
||||
|
||||
public async ValueTask<Result<Domain.Models.Evidence>> GetEvidenceAsync(string evidenceId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Domain.Models.Evidence>>>)(async () =>
|
||||
public async Task<Result<Domain.Models.Evidence>> GetEvidenceAsync(string evidenceId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Domain.Models.Evidence>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetEvidenceAsync(evidenceId, cancellationToken);
|
||||
@@ -44,8 +44,8 @@ public sealed class EvidenceCacheService(EvidenceService service, IDistributedCa
|
||||
return Result.Ok(cached.FromJson<Domain.Models.Evidence>());
|
||||
}));
|
||||
|
||||
public async ValueTask<Result<Domain.Models.Evidence[]>> GetEvidenceFilesAsync(Pagination pagination, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Domain.Models.Evidence[]>>>)(async () =>
|
||||
public async Task<Result<Domain.Models.Evidence[]>> GetEvidenceFilesAsync(Pagination pagination, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Domain.Models.Evidence[]>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetEvidenceFilesAsync(pagination, cancellationToken);
|
||||
@@ -68,8 +68,8 @@ public sealed class EvidenceCacheService(EvidenceService service, IDistributedCa
|
||||
return Result.Ok(cached.FromJson<Domain.Models.Evidence[]>());
|
||||
}));
|
||||
|
||||
public async ValueTask<Result<string>> GetEvidenceUrlAsync(string evidenceIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<string>>>)(async () =>
|
||||
public async Task<Result<string>> GetEvidenceUrlAsync(string evidenceIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<string>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetEvidenceUrlAsync(evidenceIdHash, cancellationToken);
|
||||
@@ -92,8 +92,8 @@ public sealed class EvidenceCacheService(EvidenceService service, IDistributedCa
|
||||
return Result.Ok(cached);
|
||||
}));
|
||||
|
||||
public async ValueTask<Result<Indicator>> GetIndicatorAsync(string indicatorId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Indicator>>>)(async () =>
|
||||
public async Task<Result<Indicator>> GetIndicatorAsync(string indicatorId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Indicator>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetIndicatorAsync(indicatorId, cancellationToken);
|
||||
@@ -116,8 +116,8 @@ public sealed class EvidenceCacheService(EvidenceService service, IDistributedCa
|
||||
return Result.Ok(cached.FromJson<Indicator>());
|
||||
}));
|
||||
|
||||
public async ValueTask<Result<Indicator[]>> GetIndicatorsAsync(Pagination pagination, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Indicator[]>>>)(async () =>
|
||||
public async Task<Result<Indicator[]>> GetIndicatorsAsync(Pagination pagination, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Indicator[]>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetIndicatorsAsync(pagination, cancellationToken);
|
||||
@@ -140,8 +140,8 @@ public sealed class EvidenceCacheService(EvidenceService service, IDistributedCa
|
||||
return Result.Ok(cached.FromJson<Indicator[]>());
|
||||
}));
|
||||
|
||||
public async ValueTask<Result<Domain.Models.Evidence[]>> GetMilestoneEvidencesAsync(string milestoneIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Domain.Models.Evidence[]>>>)(async () =>
|
||||
public async Task<Result<Domain.Models.Evidence[]>> GetMilestoneEvidencesAsync(string milestoneIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Domain.Models.Evidence[]>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetMilestoneEvidencesAsync(milestoneIdHash, cancellationToken);
|
||||
@@ -164,8 +164,8 @@ public sealed class EvidenceCacheService(EvidenceService service, IDistributedCa
|
||||
return Result.Ok(cached.FromJson<Domain.Models.Evidence[]>());
|
||||
}));
|
||||
|
||||
public async ValueTask<Result<Domain.Models.Evidence[]>> GetProjectEvidencesAsync(string projectIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Domain.Models.Evidence[]>>>)(async () =>
|
||||
public async Task<Result<Domain.Models.Evidence[]>> GetProjectEvidencesAsync(string projectIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Domain.Models.Evidence[]>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetProjectEvidencesAsync(projectIdHash, cancellationToken);
|
||||
@@ -188,9 +188,9 @@ public sealed class EvidenceCacheService(EvidenceService service, IDistributedCa
|
||||
return Result.Ok(cached.FromJson<Domain.Models.Evidence[]>());
|
||||
}));
|
||||
|
||||
public async ValueTask<Result> RecordIndicatorActualAmountAsync(string indicatorIdHash, decimal amount, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
public async Task<Result> RecordIndicatorActualAmountAsync(string indicatorIdHash, decimal amount, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await service.RecordIndicatorActualAmountAsync(indicatorIdHash, amount, userId, cancellationToken);
|
||||
|
||||
public async ValueTask<Result> UpdateEvidenceAsync(UpdateEvidenceRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
public async Task<Result> UpdateEvidenceAsync(UpdateEvidenceRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await service.UpdateEvidenceAsync(request, userId, cancellationToken);
|
||||
}
|
||||
|
||||
@@ -12,8 +12,8 @@ namespace PostFundManagement.Application.Services.Evidence;
|
||||
public sealed class EvidenceService(IDbContextFactory<ApplicationDbContext> contextFactory, HashService hashService,
|
||||
[FromKeyedServices(Constants.GeneralBucketName)] IS3Service s3Service) : IEvidenceService
|
||||
{
|
||||
public async ValueTask<Result> CreateEvidenceAsync(Guid userId, IFormCollection form, IFormFile file, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result>>)(async () =>
|
||||
public async Task<Result> CreateEvidenceAsync(Guid userId, IFormCollection form, IFormFile file, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result>>)(async () =>
|
||||
{
|
||||
if (!long.TryParse(form["projectId"], out var projectId) || !long.TryParse(form["milestoneId"], out var milestoneId) ||
|
||||
!long.TryParse(form["indicatorId"], out var indicatorId) || !long.TryParse(form["activityId"], out var activityId) ||
|
||||
@@ -49,8 +49,8 @@ public sealed class EvidenceService(IDbContextFactory<ApplicationDbContext> cont
|
||||
return Result.OkIf(await context.SaveChangesAsync(cancellationToken) > 0, CreateError.New);
|
||||
}));
|
||||
|
||||
public async ValueTask<Result> RecordIndicatorActualAmountAsync(string indicatorIdHash, decimal amount, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result>>)(async () =>
|
||||
public async Task<Result> RecordIndicatorActualAmountAsync(string indicatorIdHash, decimal amount, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result>>)(async () =>
|
||||
{
|
||||
var decodeResult = hashService.DecodeLongIdHash(indicatorIdHash);
|
||||
|
||||
@@ -68,8 +68,8 @@ public sealed class EvidenceService(IDbContextFactory<ApplicationDbContext> cont
|
||||
return Result.OkIf(changedTotal > 0, UpdateError.New);
|
||||
}));
|
||||
|
||||
public async ValueTask<Result<Indicator[]>> GetIndicatorsAsync(Pagination pagination, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Indicator[]>>>)(async () =>
|
||||
public async Task<Result<Indicator[]>> GetIndicatorsAsync(Pagination pagination, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Indicator[]>>>)(async () =>
|
||||
{
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
@@ -82,8 +82,8 @@ public sealed class EvidenceService(IDbContextFactory<ApplicationDbContext> cont
|
||||
return Result.Ok(indicators.Select(i => i.Map()).ToArray());
|
||||
}));
|
||||
|
||||
public async ValueTask<Result<Domain.Models.Evidence[]>> GetEvidenceFilesAsync(Pagination pagination, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Domain.Models.Evidence[]>>>)(async () =>
|
||||
public async Task<Result<Domain.Models.Evidence[]>> GetEvidenceFilesAsync(Pagination pagination, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Domain.Models.Evidence[]>>>)(async () =>
|
||||
{
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
@@ -96,8 +96,8 @@ public sealed class EvidenceService(IDbContextFactory<ApplicationDbContext> cont
|
||||
return Result.Ok(evidence.Select(i => i.Map()).ToArray());
|
||||
}));
|
||||
|
||||
public async ValueTask<Result> CreateMilestoneAsync(CreateMilestoneRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result>>)(async () =>
|
||||
public async Task<Result> CreateMilestoneAsync(CreateMilestoneRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result>>)(async () =>
|
||||
{
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
@@ -122,8 +122,8 @@ public sealed class EvidenceService(IDbContextFactory<ApplicationDbContext> cont
|
||||
CreateError.Create("No record could be created."));
|
||||
}));
|
||||
|
||||
public async ValueTask<Result> CreateIndicatorAsync(CreateIndicatorRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result>>)(async () =>
|
||||
public async Task<Result> CreateIndicatorAsync(CreateIndicatorRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result>>)(async () =>
|
||||
{
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
@@ -145,8 +145,8 @@ public sealed class EvidenceService(IDbContextFactory<ApplicationDbContext> cont
|
||||
return Result.OkIf(await context.SaveChangesAsync(cancellationToken) > 0, CreateError.New);
|
||||
}));
|
||||
|
||||
public async ValueTask<Result<Indicator>> GetIndicatorAsync(string indicatorId, CancellationToken cancellationToken) =>
|
||||
await Result.Try((Func<ValueTask<Result<Indicator>>>)(async () =>
|
||||
public async Task<Result<Indicator>> GetIndicatorAsync(string indicatorId, CancellationToken cancellationToken) =>
|
||||
await Result.Try((Func<Task<Result<Indicator>>>)(async () =>
|
||||
{
|
||||
var decodeResult = hashService.DecodeLongIdHash(indicatorId);
|
||||
|
||||
@@ -162,8 +162,8 @@ public sealed class EvidenceService(IDbContextFactory<ApplicationDbContext> cont
|
||||
.ToResult(indicator!.Map());
|
||||
}));
|
||||
|
||||
public async ValueTask<Result<Domain.Models.Evidence>> GetEvidenceAsync(string evidenceId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Domain.Models.Evidence>>>)(async () =>
|
||||
public async Task<Result<Domain.Models.Evidence>> GetEvidenceAsync(string evidenceId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Domain.Models.Evidence>>>)(async () =>
|
||||
{
|
||||
var decodeResult = hashService.DecodeLongIdHash(evidenceId);
|
||||
|
||||
@@ -179,8 +179,8 @@ public sealed class EvidenceService(IDbContextFactory<ApplicationDbContext> cont
|
||||
.ToResult(evidence!.Map());
|
||||
}));
|
||||
|
||||
public async ValueTask<Result<Domain.Models.Evidence[]>> GetMilestoneEvidencesAsync(string milestoneIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Domain.Models.Evidence[]>>>)(async () =>
|
||||
public async Task<Result<Domain.Models.Evidence[]>> GetMilestoneEvidencesAsync(string milestoneIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Domain.Models.Evidence[]>>>)(async () =>
|
||||
{
|
||||
var decodeResult = hashService.DecodeLongIdHash(milestoneIdHash);
|
||||
|
||||
@@ -199,8 +199,8 @@ public sealed class EvidenceService(IDbContextFactory<ApplicationDbContext> cont
|
||||
return Result.Ok(evidences.Select(e => e.Map()).ToArray());
|
||||
}));
|
||||
|
||||
public async ValueTask<Result<Domain.Models.Evidence[]>> GetProjectEvidencesAsync(string projectIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Domain.Models.Evidence[]>>>)(async () =>
|
||||
public async Task<Result<Domain.Models.Evidence[]>> GetProjectEvidencesAsync(string projectIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Domain.Models.Evidence[]>>>)(async () =>
|
||||
{
|
||||
var decodeResult = hashService.DecodeLongIdHash(projectIdHash);
|
||||
|
||||
@@ -219,8 +219,8 @@ public sealed class EvidenceService(IDbContextFactory<ApplicationDbContext> cont
|
||||
return Result.Ok(evidences.Select(e => e.Map()).ToArray());
|
||||
}));
|
||||
|
||||
public async ValueTask<Result> UpdateEvidenceAsync(UpdateEvidenceRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result>>)(async () =>
|
||||
public async Task<Result> UpdateEvidenceAsync(UpdateEvidenceRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result>>)(async () =>
|
||||
{
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
@@ -238,8 +238,8 @@ public sealed class EvidenceService(IDbContextFactory<ApplicationDbContext> cont
|
||||
return Result.OkIf(changedTotal > 0, UpdateError.New);
|
||||
}));
|
||||
|
||||
public async ValueTask<Result<string>> GetEvidenceUrlAsync(string evidenceIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<string>>>)(async () =>
|
||||
public async Task<Result<string>> GetEvidenceUrlAsync(string evidenceIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<string>>>)(async () =>
|
||||
{
|
||||
var decodeResult = hashService.DecodeLongIdHash(evidenceIdHash);
|
||||
|
||||
|
||||
@@ -11,17 +11,17 @@ namespace PostFundManagement.Application.Services.Execution;
|
||||
public sealed class ExecutionCacheService(ExecutionService service, IDistributedCache cache,
|
||||
IFeatureManager featureManager) : ServiceCacheBase, IExecutionService
|
||||
{
|
||||
public async ValueTask<Result> ApproveDisbursementAsync(string disbursementIdHash, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
public async Task<Result> ApproveDisbursementAsync(string disbursementIdHash, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await service.ApproveDisbursementAsync(disbursementIdHash, userId, cancellationToken);
|
||||
|
||||
public async ValueTask<Result> CreateDisbursementAsync(CreateDisbursementRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
public async Task<Result> CreateDisbursementAsync(CreateDisbursementRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await service.CreateDisbursementAsync(request, userId, cancellationToken);
|
||||
|
||||
public async ValueTask<Result> CreateRiskAsync(CreateRiskRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
public async Task<Result> CreateRiskAsync(CreateRiskRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await service.CreateRiskAsync(request, userId, cancellationToken);
|
||||
|
||||
public async ValueTask<Result<Disbursement>> GetDisbursementAsync(string disbursementIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Disbursement>>>)(async () =>
|
||||
public async Task<Result<Disbursement>> GetDisbursementAsync(string disbursementIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Disbursement>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetDisbursementAsync(disbursementIdHash, cancellationToken);
|
||||
@@ -44,8 +44,8 @@ public sealed class ExecutionCacheService(ExecutionService service, IDistributed
|
||||
return Result.Ok(cached.FromJson<Disbursement>());
|
||||
}));
|
||||
|
||||
public async ValueTask<Result<Disbursement[]>> GetDisbursementsAsync(Pagination pagination, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Disbursement[]>>>)(async () =>
|
||||
public async Task<Result<Disbursement[]>> GetDisbursementsAsync(Pagination pagination, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Disbursement[]>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetDisbursementsAsync(pagination, cancellationToken);
|
||||
@@ -68,8 +68,8 @@ public sealed class ExecutionCacheService(ExecutionService service, IDistributed
|
||||
return Result.Ok(cached.FromJson<Disbursement[]>());
|
||||
}));
|
||||
|
||||
public async ValueTask<Result<Risk>> GetRiskAsync(string riskIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Risk>>>)(async () =>
|
||||
public async Task<Result<Risk>> GetRiskAsync(string riskIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Risk>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetRiskAsync(riskIdHash, cancellationToken);
|
||||
@@ -92,8 +92,8 @@ public sealed class ExecutionCacheService(ExecutionService service, IDistributed
|
||||
return Result.Ok(cached.FromJson<Risk>());
|
||||
}));
|
||||
|
||||
public async ValueTask<Result<Risk[]>> GetRisksAsync(Pagination pagination, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Risk[]>>>)(async () =>
|
||||
public async Task<Result<Risk[]>> GetRisksAsync(Pagination pagination, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Risk[]>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetRisksAsync(pagination, cancellationToken);
|
||||
@@ -116,9 +116,9 @@ public sealed class ExecutionCacheService(ExecutionService service, IDistributed
|
||||
return Result.Ok(cached.FromJson<Risk[]>());
|
||||
}));
|
||||
|
||||
public async ValueTask<Result> UpdateDisbursementAsync(UpdateDisbursementRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
public async Task<Result> UpdateDisbursementAsync(UpdateDisbursementRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await service.UpdateDisbursementAsync(request, userId, cancellationToken);
|
||||
|
||||
public async ValueTask<Result> UpdateRiskAsync(UpdateRiskRequest request, CancellationToken cancellationToken = default) =>
|
||||
public async Task<Result> UpdateRiskAsync(UpdateRiskRequest request, CancellationToken cancellationToken = default) =>
|
||||
await service.UpdateRiskAsync(request, cancellationToken);
|
||||
}
|
||||
|
||||
@@ -10,8 +10,8 @@ namespace PostFundManagement.Application.Services.Execution;
|
||||
|
||||
public sealed class ExecutionService(IDbContextFactory<ApplicationDbContext> contextFactory, HashService hashService) : IExecutionService
|
||||
{
|
||||
public async ValueTask<Result<Risk[]>> GetRisksAsync(Pagination pagination, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Risk[]>>>)(async () =>
|
||||
public async Task<Result<Risk[]>> GetRisksAsync(Pagination pagination, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Risk[]>>>)(async () =>
|
||||
{
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
@@ -24,8 +24,8 @@ public sealed class ExecutionService(IDbContextFactory<ApplicationDbContext> con
|
||||
return Result.Ok(risks.Select(i => i.Map()).ToArray());
|
||||
}));
|
||||
|
||||
public async ValueTask<Result<Disbursement[]>> GetDisbursementsAsync(Pagination pagination, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Disbursement[]>>>)(async () =>
|
||||
public async Task<Result<Disbursement[]>> GetDisbursementsAsync(Pagination pagination, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Disbursement[]>>>)(async () =>
|
||||
{
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
@@ -38,8 +38,8 @@ public sealed class ExecutionService(IDbContextFactory<ApplicationDbContext> con
|
||||
return Result.Ok(disbursements.Select(i => i.Map()).ToArray());
|
||||
}));
|
||||
|
||||
public async ValueTask<Result> CreateRiskAsync(CreateRiskRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result>>)(async () =>
|
||||
public async Task<Result> CreateRiskAsync(CreateRiskRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result>>)(async () =>
|
||||
{
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
@@ -60,8 +60,8 @@ public sealed class ExecutionService(IDbContextFactory<ApplicationDbContext> con
|
||||
return Result.OkIf(await context.SaveChangesAsync(cancellationToken) > 0, CreateError.New);
|
||||
}));
|
||||
|
||||
public async ValueTask<Result> CreateDisbursementAsync(CreateDisbursementRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result>>)(async () =>
|
||||
public async Task<Result> CreateDisbursementAsync(CreateDisbursementRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result>>)(async () =>
|
||||
{
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
@@ -81,8 +81,8 @@ public sealed class ExecutionService(IDbContextFactory<ApplicationDbContext> con
|
||||
return Result.OkIf(await context.SaveChangesAsync(cancellationToken) > 0, CreateError.New);
|
||||
}));
|
||||
|
||||
public async ValueTask<Result> ApproveDisbursementAsync(string disbursementIdHash, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result>>)(async () =>
|
||||
public async Task<Result> ApproveDisbursementAsync(string disbursementIdHash, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result>>)(async () =>
|
||||
{
|
||||
var decodeResult = hashService.DecodeLongIdHash(disbursementIdHash);
|
||||
|
||||
@@ -101,8 +101,8 @@ public sealed class ExecutionService(IDbContextFactory<ApplicationDbContext> con
|
||||
return Result.OkIf(changedTotal > 0, UpdateError.New);
|
||||
}));
|
||||
|
||||
public async ValueTask<Result<Disbursement>> GetDisbursementAsync(string disbursementIdHash, CancellationToken cancellationToken) =>
|
||||
await Result.Try((Func<ValueTask<Result<Disbursement>>>)(async () =>
|
||||
public async Task<Result<Disbursement>> GetDisbursementAsync(string disbursementIdHash, CancellationToken cancellationToken) =>
|
||||
await Result.Try((Func<Task<Result<Disbursement>>>)(async () =>
|
||||
{
|
||||
var decodeResult = hashService.DecodeLongIdHash(disbursementIdHash);
|
||||
|
||||
@@ -119,8 +119,8 @@ public sealed class ExecutionService(IDbContextFactory<ApplicationDbContext> con
|
||||
.ToResult(disbursement!.Map());
|
||||
}));
|
||||
|
||||
public async ValueTask<Result<Risk>> GetRiskAsync(string riskIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Risk>>>)(async () =>
|
||||
public async Task<Result<Risk>> GetRiskAsync(string riskIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Risk>>>)(async () =>
|
||||
{
|
||||
var decodeResult = hashService.DecodeLongIdHash(riskIdHash);
|
||||
|
||||
@@ -137,8 +137,8 @@ public sealed class ExecutionService(IDbContextFactory<ApplicationDbContext> con
|
||||
.ToResult(risk!.Map());
|
||||
}));
|
||||
|
||||
public async ValueTask<Result> UpdateRiskAsync(UpdateRiskRequest request, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result>>)(async () =>
|
||||
public async Task<Result> UpdateRiskAsync(UpdateRiskRequest request, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result>>)(async () =>
|
||||
{
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
@@ -153,8 +153,8 @@ public sealed class ExecutionService(IDbContextFactory<ApplicationDbContext> con
|
||||
return Result.OkIf(changedTotal > 0, UpdateError.New);
|
||||
}));
|
||||
|
||||
public async ValueTask<Result> UpdateDisbursementAsync(UpdateDisbursementRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result>>)(async () =>
|
||||
public async Task<Result> UpdateDisbursementAsync(UpdateDisbursementRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result>>)(async () =>
|
||||
{
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
|
||||
@@ -11,14 +11,20 @@ namespace PostFundManagement.Application.Services.Governance;
|
||||
public sealed class GovernanceCacheService(GovernanceService service, IDistributedCache cache,
|
||||
IFeatureManager featureManager) : ServiceCacheBase, IGovernanceService
|
||||
{
|
||||
public async ValueTask<Result> CreateOrganisationAsync(CreateOrganisationRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
public async Task<Result> CreateOrganisationAsync(CreateOrganisationRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await service.CreateOrganisationAsync(request, userId, cancellationToken);
|
||||
|
||||
public async ValueTask<Result> CreatePortfolioAsync(CreatePortfolioRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
public async Task<Result> CreatePortfolioAsync(CreatePortfolioRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await service.CreatePortfolioAsync(request, userId, cancellationToken);
|
||||
|
||||
public async ValueTask<Result<Dashboard>> GetDashboardAsync(CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Dashboard>>>)(async () =>
|
||||
public async Task<Result> CreateTenantAsync(CreateTenantRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await service.CreateTenantAsync(request, userId, cancellationToken);
|
||||
|
||||
public async Task<Result> CreateTenantOrganisationAsync(string organisationIdHash, string tenantIdHash, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await service.CreateTenantOrganisationAsync(organisationIdHash, tenantIdHash, userId, cancellationToken);
|
||||
|
||||
public async Task<Result<Dashboard>> GetDashboardAsync(CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Dashboard>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetDashboardAsync(cancellationToken);
|
||||
@@ -41,8 +47,8 @@ public sealed class GovernanceCacheService(GovernanceService service, IDistribut
|
||||
return Result.Ok(cached.FromJson<Dashboard>());
|
||||
}));
|
||||
|
||||
public async ValueTask<Result<Instrument[]>> GetInstrumentsAsync(string programmeIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Instrument[]>>>)(async () =>
|
||||
public async Task<Result<Instrument[]>> GetInstrumentsAsync(string programmeIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Instrument[]>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetInstrumentsAsync(programmeIdHash, cancellationToken);
|
||||
@@ -65,8 +71,8 @@ public sealed class GovernanceCacheService(GovernanceService service, IDistribut
|
||||
return Result.Ok(cached.FromJson<Instrument[]>());
|
||||
}));
|
||||
|
||||
public async ValueTask<Result<Organisation>> GetOrganisationAsync(string organisationIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Organisation>>>)(async () =>
|
||||
public async Task<Result<Organisation>> GetOrganisationAsync(string organisationIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Organisation>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetOrganisationAsync(organisationIdHash, cancellationToken);
|
||||
@@ -89,8 +95,8 @@ public sealed class GovernanceCacheService(GovernanceService service, IDistribut
|
||||
return Result.Ok(cached.FromJson<Organisation>());
|
||||
}));
|
||||
|
||||
public async ValueTask<Result<Organisation[]>> GetOrganisationsAsync(Pagination pagination, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Organisation[]>>>)(async () =>
|
||||
public async Task<Result<Organisation[]>> GetOrganisationsAsync(Pagination pagination, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Organisation[]>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetOrganisationsAsync(pagination, cancellationToken);
|
||||
@@ -113,8 +119,8 @@ public sealed class GovernanceCacheService(GovernanceService service, IDistribut
|
||||
return Result.Ok(cached.FromJson<Organisation[]>());
|
||||
}));
|
||||
|
||||
public async ValueTask<Result<Portfolio[]>> GetPorfoliosAsync(string organisationIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Portfolio[]>>>)(async () =>
|
||||
public async Task<Result<Portfolio[]>> GetPorfoliosAsync(string organisationIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Portfolio[]>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetPorfoliosAsync(organisationIdHash, cancellationToken);
|
||||
@@ -137,8 +143,8 @@ public sealed class GovernanceCacheService(GovernanceService service, IDistribut
|
||||
return Result.Ok(cached.FromJson<Portfolio[]>());
|
||||
}));
|
||||
|
||||
public async ValueTask<Result<Portfolio>> GetPortfolioAsync(string portfolioIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Portfolio>>>)(async () =>
|
||||
public async Task<Result<Portfolio>> GetPortfolioAsync(string portfolioIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Portfolio>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetPortfolioAsync(portfolioIdHash, cancellationToken);
|
||||
@@ -161,8 +167,8 @@ public sealed class GovernanceCacheService(GovernanceService service, IDistribut
|
||||
return Result.Ok(cached.FromJson<Portfolio>());
|
||||
}));
|
||||
|
||||
public async ValueTask<Result<Programme[]>> GetPortfolioProgrammesAsync(string portfolioIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Programme[]>>>)(async () =>
|
||||
public async Task<Result<Programme[]>> GetPortfolioProgrammesAsync(string portfolioIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Programme[]>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetPortfolioProgrammesAsync(portfolioIdHash, cancellationToken);
|
||||
@@ -185,8 +191,8 @@ public sealed class GovernanceCacheService(GovernanceService service, IDistribut
|
||||
return Result.Ok(cached.FromJson<Programme[]>());
|
||||
}));
|
||||
|
||||
public async ValueTask<Result<Programme[]>> GetProgrammesAsync(string portfolioIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Programme[]>>>)(async () =>
|
||||
public async Task<Result<Programme[]>> GetProgrammesAsync(string portfolioIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Programme[]>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetProgrammesAsync(portfolioIdHash, cancellationToken);
|
||||
@@ -209,9 +215,114 @@ public sealed class GovernanceCacheService(GovernanceService service, IDistribut
|
||||
return Result.Ok(cached.FromJson<Programme[]>());
|
||||
}));
|
||||
|
||||
public async ValueTask<Result<Organisation>> UpdateOrganisationAsync(UpdateOrganisationRequest request, CancellationToken cancellationToken = default) =>
|
||||
public async Task<Result<Tenant>> GetTenantAsync(string tenantIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Tenant>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetTenantAsync(tenantIdHash, cancellationToken);
|
||||
|
||||
var cacheKey = HashService.ToMd5Hash($"gettenant-{tenantIdHash}").Value;
|
||||
|
||||
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(cached))
|
||||
{
|
||||
var result = await service.GetTenantAsync(tenantIdHash, cancellationToken);
|
||||
|
||||
if (result.IsFailed) return result;
|
||||
|
||||
await cache.SetStringAsync(cacheKey, result.Value.ToJson(), cacheOptions, cancellationToken);
|
||||
|
||||
return result.Value;
|
||||
}
|
||||
|
||||
return Result.Ok(cached.FromJson<Tenant>());
|
||||
}));
|
||||
|
||||
public async Task<Result<TenantOrganisation>> GetTenantOrganisationAsync(string tenantOrganisationIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<TenantOrganisation>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetTenantOrganisationAsync(tenantOrganisationIdHash, cancellationToken);
|
||||
|
||||
var cacheKey = HashService.ToMd5Hash($"gettenantorganisation-{tenantOrganisationIdHash}").Value;
|
||||
|
||||
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(cached))
|
||||
{
|
||||
var result = await service.GetTenantOrganisationAsync(tenantOrganisationIdHash, cancellationToken);
|
||||
|
||||
if (result.IsFailed) return result;
|
||||
|
||||
await cache.SetStringAsync(cacheKey, result.Value.ToJson(), cacheOptions, cancellationToken);
|
||||
|
||||
return result.Value;
|
||||
}
|
||||
|
||||
return Result.Ok(cached.FromJson<TenantOrganisation>());
|
||||
}));
|
||||
|
||||
public async Task<Result<TenantOrganisation[]>> GetTenantOrganisationsAsync(CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<TenantOrganisation[]>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetTenantOrganisationsAsync(cancellationToken);
|
||||
|
||||
var cacheKey = HashService.ToMd5Hash($"gettenantorganisations").Value;
|
||||
|
||||
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(cached))
|
||||
{
|
||||
var result = await service.GetTenantOrganisationsAsync(cancellationToken);
|
||||
|
||||
if (result.IsFailed) return result;
|
||||
|
||||
await cache.SetStringAsync(cacheKey, result.Value.ToJson(), cacheOptions, cancellationToken);
|
||||
|
||||
return result.Value;
|
||||
}
|
||||
|
||||
return Result.Ok(cached.FromJson<TenantOrganisation[]>());
|
||||
}));
|
||||
|
||||
public async Task<Result<Tenant[]>> GetTenantsAsync(CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Tenant[]>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetTenantsAsync(cancellationToken);
|
||||
|
||||
var cacheKey = HashService.ToMd5Hash($"gettenants").Value;
|
||||
|
||||
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(cached))
|
||||
{
|
||||
var result = await service.GetTenantsAsync(cancellationToken);
|
||||
|
||||
if (result.IsFailed) return result;
|
||||
|
||||
await cache.SetStringAsync(cacheKey, result.Value.ToJson(), cacheOptions, cancellationToken);
|
||||
|
||||
return result.Value;
|
||||
}
|
||||
|
||||
return Result.Ok(cached.FromJson<Tenant[]>());
|
||||
}));
|
||||
|
||||
public async Task<Result<Organisation>> UpdateOrganisationAsync(UpdateOrganisationRequest request, CancellationToken cancellationToken = default) =>
|
||||
await service.UpdateOrganisationAsync(request, cancellationToken);
|
||||
|
||||
public async ValueTask<Result> UpdatePortfolioAsync(UpdatePortfolioRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
public async Task<Result> UpdatePortfolioAsync(UpdatePortfolioRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await service.UpdatePortfolioAsync(request, userId, cancellationToken);
|
||||
|
||||
public async Task<Result> UpdateTenantAsync(UpdateTenantRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await service.UpdateTenantAsync(request, userId, cancellationToken);
|
||||
|
||||
public async Task<Result> UpdateTenantOrganisationAsync(string tenantOrganisationIdHash, ActivityStatus status, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await service.UpdateTenantOrganisationAsync(tenantOrganisationIdHash, status, userId, cancellationToken);
|
||||
|
||||
public async Task<Result> UpdateTenantUserAsync(UpdateTenantUserRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await service.UpdateTenantUserAsync(request, userId, cancellationToken);
|
||||
}
|
||||
|
||||
@@ -1,18 +1,20 @@
|
||||
using PostFundManagement.Application.Abstractions.Services;
|
||||
using PostFundManagement.Application.Extensions;
|
||||
using PostFundManagement.Application.Services.Shared;
|
||||
using PostFundManagement.Domain;
|
||||
using PostFundManagement.Domain.Abstractions;
|
||||
using PostFundManagement.Domain.Errors;
|
||||
using PostFundManagement.Domain.Extensions;
|
||||
using PostFundManagement.Domain.Models;
|
||||
using PostFundManagement.Infrastructure.Database;
|
||||
using PostFundManagement.Application.Extensions;
|
||||
|
||||
namespace PostFundManagement.Application.Services.Governance;
|
||||
|
||||
public sealed class GovernanceService(IDbContextFactory<ApplicationDbContext> contextFactory, HashService hashService) : IGovernanceService
|
||||
public sealed class GovernanceService(IDbContextFactory<ApplicationDbContext> contextFactory, HashService hashService,
|
||||
ITenantContextService tenantContext) : IGovernanceService
|
||||
{
|
||||
public async ValueTask<Result<Programme[]>> GetProgrammesAsync(string portfolioIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Programme[]>>>)(async () =>
|
||||
public async Task<Result<Programme[]>> GetProgrammesAsync(string portfolioIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Programme[]>>>)(async () =>
|
||||
{
|
||||
var decodeResult = hashService.DecodeLongIdHash(portfolioIdHash);
|
||||
|
||||
@@ -30,8 +32,8 @@ public sealed class GovernanceService(IDbContextFactory<ApplicationDbContext> co
|
||||
return Result.Ok(programmes.Select(p => p.Map()).ToArray());
|
||||
}));
|
||||
|
||||
public async ValueTask<Result<Portfolio[]>> GetPorfoliosAsync(string organisationIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Portfolio[]>>>)(async () =>
|
||||
public async Task<Result<Portfolio[]>> GetPorfoliosAsync(string organisationIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Portfolio[]>>>)(async () =>
|
||||
{
|
||||
var decodeResult = hashService.DecodeLongIdHash(organisationIdHash);
|
||||
|
||||
@@ -49,22 +51,23 @@ public sealed class GovernanceService(IDbContextFactory<ApplicationDbContext> co
|
||||
return Result.Ok(portfolios.Select(p => p.Map()).ToArray());
|
||||
}));
|
||||
|
||||
public async ValueTask<Result<Organisation[]>> GetOrganisationsAsync(Pagination pagination, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Organisation[]>>>)(async () =>
|
||||
public async Task<Result<Organisation[]>> GetOrganisationsAsync(Pagination pagination, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Organisation[]>>>)(async () =>
|
||||
{
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
var organisations = await context.Organisations.AsNoTracking()
|
||||
.OrderBy(o => o.Name)
|
||||
var organisations = await context.TenantOrganisations.AsNoTracking()
|
||||
.Include(i => i.Organisation)
|
||||
.OrderBy(o => o.Organisation!.Name)
|
||||
.Skip((pagination.Page - 1) * pagination.PageSize)
|
||||
.Take(pagination.PageSize)
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
return Result.Ok(organisations.Select(o => o.Map()).ToArray());
|
||||
return Result.Ok(organisations.Select(o => o.Organisation!.Map()).ToArray());
|
||||
}));
|
||||
|
||||
public async ValueTask<Result<Organisation>> GetOrganisationAsync(string organisationIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Organisation>>>)(async () =>
|
||||
public async Task<Result<Organisation>> GetOrganisationAsync(string organisationIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Organisation>>>)(async () =>
|
||||
{
|
||||
var decodeResult = hashService.DecodeLongIdHash(organisationIdHash);
|
||||
|
||||
@@ -74,15 +77,16 @@ public sealed class GovernanceService(IDbContextFactory<ApplicationDbContext> co
|
||||
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
var organisation = await context.Organisations.AsNoTracking()
|
||||
.FirstOrDefaultAsync(o => o.Id == decodeResult.Value, cancellationToken);
|
||||
var tenantOrganisation = await context.TenantOrganisations.AsNoTracking()
|
||||
.Include(i => i.OrganisationId)
|
||||
.FirstOrDefaultAsync(o => o.OrganisationId == decodeResult.Value, cancellationToken);
|
||||
|
||||
return Result.FailIf(organisation is null, NotFoundError.New)
|
||||
.ToResult(organisation!.Map());
|
||||
return Result.FailIf(tenantOrganisation is null, NotFoundError.New)
|
||||
.ToResult(tenantOrganisation!.Organisation!.Map());
|
||||
}));
|
||||
|
||||
public async ValueTask<Result<Instrument[]>> GetInstrumentsAsync(string programmeIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Instrument[]>>>)(async () =>
|
||||
public async Task<Result<Instrument[]>> GetInstrumentsAsync(string programmeIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Instrument[]>>>)(async () =>
|
||||
{
|
||||
var decodeResult = hashService.DecodeLongIdHash(programmeIdHash);
|
||||
|
||||
@@ -100,8 +104,8 @@ public sealed class GovernanceService(IDbContextFactory<ApplicationDbContext> co
|
||||
return Result.Ok(instruments.Select(i => i.Map()).ToArray());
|
||||
}));
|
||||
|
||||
public async ValueTask<Result<Dashboard>> GetDashboardAsync(CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Dashboard>>>)(async () =>
|
||||
public async Task<Result<Dashboard>> GetDashboardAsync(CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Dashboard>>>)(async () =>
|
||||
{
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
@@ -126,8 +130,8 @@ public sealed class GovernanceService(IDbContextFactory<ApplicationDbContext> co
|
||||
disbursedAmount, onTrackPercentage, atRiskCount, beneficiariesReached));
|
||||
}));
|
||||
|
||||
public async ValueTask<Result> CreateOrganisationAsync(CreateOrganisationRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result>>)(async () =>
|
||||
public async Task<Result> CreateOrganisationAsync(CreateOrganisationRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result>>)(async () =>
|
||||
{
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
@@ -150,8 +154,8 @@ public sealed class GovernanceService(IDbContextFactory<ApplicationDbContext> co
|
||||
return Result.OkIf(await context.SaveChangesAsync(cancellationToken) > 0, CreateError.New);
|
||||
}));
|
||||
|
||||
public async ValueTask<Result<Organisation>> UpdateOrganisationAsync(UpdateOrganisationRequest request, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Organisation>>>)(async () =>
|
||||
public async Task<Result<Organisation>> UpdateOrganisationAsync(UpdateOrganisationRequest request, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Organisation>>>)(async () =>
|
||||
{
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
@@ -166,8 +170,8 @@ public sealed class GovernanceService(IDbContextFactory<ApplicationDbContext> co
|
||||
return Result.OkIf(changedTotal > 0, UpdateError.New);
|
||||
}));
|
||||
|
||||
public async ValueTask<Result> CreatePortfolioAsync(CreatePortfolioRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result>>)(async () =>
|
||||
public async Task<Result> CreatePortfolioAsync(CreatePortfolioRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result>>)(async () =>
|
||||
{
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
@@ -189,14 +193,15 @@ public sealed class GovernanceService(IDbContextFactory<ApplicationDbContext> co
|
||||
OrganisationId = request.OrganisationId,
|
||||
OwnedBy = request.OwnerId,
|
||||
Name = name,
|
||||
Description = request.Description.Humanize(LetterCasing.Sentence).Trim()
|
||||
Description = request.Description.Humanize(LetterCasing.Sentence).Trim(),
|
||||
TenantId = tenantContext.TenantId
|
||||
});
|
||||
|
||||
return Result.OkIf(await context.SaveChangesAsync(cancellationToken) > 0, CreateError.New);
|
||||
}));
|
||||
|
||||
public async ValueTask<Result> UpdatePortfolioAsync(UpdatePortfolioRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result>>)(async () =>
|
||||
public async Task<Result> UpdatePortfolioAsync(UpdatePortfolioRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result>>)(async () =>
|
||||
{
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
@@ -213,8 +218,8 @@ public sealed class GovernanceService(IDbContextFactory<ApplicationDbContext> co
|
||||
return Result.OkIf(changedTotal > 0, UpdateError.Create("Nothing was saved, no change detected."));
|
||||
}));
|
||||
|
||||
public async ValueTask<Result<Programme[]>> GetPortfolioProgrammesAsync(string portfolioIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Programme[]>>>)(async () =>
|
||||
public async Task<Result<Programme[]>> GetPortfolioProgrammesAsync(string portfolioIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Programme[]>>>)(async () =>
|
||||
{
|
||||
var decodeResult = hashService.DecodeLongIdHash(portfolioIdHash);
|
||||
|
||||
@@ -232,8 +237,8 @@ public sealed class GovernanceService(IDbContextFactory<ApplicationDbContext> co
|
||||
return Result.Ok(programmes.Select(p => p.Map()).ToArray());
|
||||
}));
|
||||
|
||||
public async ValueTask<Result<Portfolio>> GetPortfolioAsync(string portfolioIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Portfolio>>>)(async () =>
|
||||
public async Task<Result<Portfolio>> GetPortfolioAsync(string portfolioIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Portfolio>>>)(async () =>
|
||||
{
|
||||
var decodeResult = hashService.DecodeLongIdHash(portfolioIdHash);
|
||||
|
||||
@@ -249,4 +254,49 @@ public sealed class GovernanceService(IDbContextFactory<ApplicationDbContext> co
|
||||
return Result.FailIf(portfolio is null, NotFoundError.New)
|
||||
.ToResult(portfolio!.Map());
|
||||
}));
|
||||
|
||||
public Task<Result> CreateTenantAsync(CreateTenantRequest request, Guid userId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<Result<Tenant[]>> GetTenantsAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<Result<Tenant>> GetTenantAsync(string tenantIdHash, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<Result> UpdateTenantAsync(UpdateTenantRequest request, Guid userId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<Result> UpdateTenantUserAsync(UpdateTenantUserRequest request, Guid userId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<Result> CreateTenantOrganisationAsync(string organisationIdHash, string tenantIdHash, Guid userId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<Result> UpdateTenantOrganisationAsync(string tenantOrganisationIdHash, ActivityStatus status, Guid userId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<Result<TenantOrganisation[]>> GetTenantOrganisationsAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<Result<TenantOrganisation>> GetTenantOrganisationAsync(string tenantOrganisationIdHash, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,16 @@ using static PostFundManagement.Domain.Extensions.Constants;
|
||||
|
||||
namespace PostFundManagement.Application.Services.Governance;
|
||||
|
||||
public sealed record UpdateTenantUserRequest([Required] Guid UserId, [Required] ActivityStatus Status);
|
||||
|
||||
public sealed record CreateTenantUserRequest([Required] long TenantId, [Required] Guid UserId);
|
||||
|
||||
public sealed record UpdateTenantRequest([Required] long TenantId,
|
||||
[Required][MaxLength(LabelLength)] string Name,
|
||||
[Required] ActivityStatus Status);
|
||||
|
||||
public sealed record CreateTenantRequest([Required] long TenantId, [Required][MaxLength(LabelLength)] string Name);
|
||||
|
||||
public sealed record UpdatePortfolioRequest([Required] long PortfolioId,
|
||||
[Required][MaxLength(LabelLength)] string Name,
|
||||
[Required][MaxLength(TextLength)] string Description,
|
||||
|
||||
@@ -11,20 +11,20 @@ namespace PostFundManagement.Application.Services.Grants;
|
||||
public sealed class GrantsCacheService(GrantsService service, IDistributedCache cache,
|
||||
IFeatureManager featureManager) : ServiceCacheBase, IGrantsService
|
||||
{
|
||||
public async ValueTask<Result> CreateAwardAsync(CreateAwardRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
public async Task<Result> CreateAwardAsync(CreateAwardRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await service.CreateAwardAsync(request, userId, cancellationToken);
|
||||
|
||||
public async ValueTask<Result> CreateBudgetAsync(CreateBudgetRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
public async Task<Result> CreateBudgetAsync(CreateBudgetRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await service.CreateBudgetAsync(request, userId, cancellationToken);
|
||||
|
||||
public async ValueTask<Result> CreateContractAsync(CreateContractRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
public async Task<Result> CreateContractAsync(CreateContractRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await service.CreateContractAsync(request, userId, cancellationToken);
|
||||
|
||||
public async ValueTask<Result> ExecuteContractAsync(ExecuteContractRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
public async Task<Result> ExecuteContractAsync(ExecuteContractRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await service.ExecuteContractAsync(request, userId, cancellationToken);
|
||||
|
||||
public async ValueTask<Result<Award>> GetAwardAsync(string awardIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Award>>>)(async () =>
|
||||
public async Task<Result<Award>> GetAwardAsync(string awardIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Award>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetAwardAsync(awardIdHash, cancellationToken);
|
||||
@@ -47,8 +47,8 @@ public sealed class GrantsCacheService(GrantsService service, IDistributedCache
|
||||
return Result.Ok(cached.FromJson<Award>());
|
||||
}));
|
||||
|
||||
public async ValueTask<Result<Award[]>> GetAwardsAsync(Pagination pagination, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Award[]>>>)(async () =>
|
||||
public async Task<Result<Award[]>> GetAwardsAsync(Pagination pagination, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Award[]>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetAwardsAsync(pagination, cancellationToken);
|
||||
@@ -71,8 +71,8 @@ public sealed class GrantsCacheService(GrantsService service, IDistributedCache
|
||||
return Result.Ok(cached.FromJson<Award[]>());
|
||||
}));
|
||||
|
||||
public async ValueTask<Result<Budget>> GetBudgetAsync(string budgetIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Budget>>>)(async () =>
|
||||
public async Task<Result<Budget>> GetBudgetAsync(string budgetIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Budget>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetBudgetAsync(budgetIdHash, cancellationToken);
|
||||
@@ -95,8 +95,8 @@ public sealed class GrantsCacheService(GrantsService service, IDistributedCache
|
||||
return Result.Ok(cached.FromJson<Budget>());
|
||||
}));
|
||||
|
||||
public async ValueTask<Result<Budget[]>> GetBudgetsAsync(Pagination pagination, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Budget[]>>>)(async () =>
|
||||
public async Task<Result<Budget[]>> GetBudgetsAsync(Pagination pagination, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Budget[]>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetBudgetsAsync(pagination, cancellationToken);
|
||||
@@ -119,8 +119,8 @@ public sealed class GrantsCacheService(GrantsService service, IDistributedCache
|
||||
return Result.Ok(cached.FromJson<Budget[]>());
|
||||
}));
|
||||
|
||||
public async ValueTask<Result<Contract>> GetContractAsync(string contractIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Contract>>>)(async () =>
|
||||
public async Task<Result<Contract>> GetContractAsync(string contractIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Contract>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetContractAsync(contractIdHash, cancellationToken);
|
||||
@@ -143,8 +143,8 @@ public sealed class GrantsCacheService(GrantsService service, IDistributedCache
|
||||
return Result.Ok(cached.FromJson<Contract>());
|
||||
}));
|
||||
|
||||
public async ValueTask<Result<Contract[]>> GetContractsAsync(Pagination pagination, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Contract[]>>>)(async () =>
|
||||
public async Task<Result<Contract[]>> GetContractsAsync(Pagination pagination, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Contract[]>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetContractsAsync(pagination, cancellationToken);
|
||||
@@ -167,8 +167,8 @@ public sealed class GrantsCacheService(GrantsService service, IDistributedCache
|
||||
return Result.Ok(cached.FromJson<Contract[]>());
|
||||
}));
|
||||
|
||||
public async ValueTask<Result<string>> GetContractUrlAsync(string contractIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<string>>>)(async () =>
|
||||
public async Task<Result<string>> GetContractUrlAsync(string contractIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<string>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetContractUrlAsync(contractIdHash, cancellationToken);
|
||||
@@ -191,9 +191,9 @@ public sealed class GrantsCacheService(GrantsService service, IDistributedCache
|
||||
return Result.Ok(cached!);
|
||||
}));
|
||||
|
||||
public async ValueTask<Result> UpdateContractAsync(UpdateContractRequest request, CancellationToken cancellationToken = default) =>
|
||||
public async Task<Result> UpdateContractAsync(UpdateContractRequest request, CancellationToken cancellationToken = default) =>
|
||||
await service.UpdateContractAsync(request, cancellationToken);
|
||||
|
||||
public async ValueTask<Result> UploadContractAsync(string contractIdHash, Guid userId, IFormFile file, CancellationToken cancellationToken = default) =>
|
||||
public async Task<Result> UploadContractAsync(string contractIdHash, Guid userId, IFormFile file, CancellationToken cancellationToken = default) =>
|
||||
await service.UploadContractAsync(contractIdHash, userId, file, cancellationToken);
|
||||
}
|
||||
|
||||
@@ -10,10 +10,10 @@ using PostFundManagement.Infrastructure.Database;
|
||||
namespace PostFundManagement.Application.Services.Grants;
|
||||
|
||||
public sealed class GrantsService(IDbContextFactory<ApplicationDbContext> contextFactory, HashService hashService,
|
||||
[FromKeyedServices(Constants.GeneralBucketName)] IS3Service s3Service) : IGrantsService
|
||||
[FromKeyedServices(Constants.GeneralBucketName)] IS3Service s3Service, ITenantContextService tenantContext) : IGrantsService
|
||||
{
|
||||
public async ValueTask<Result<Contract[]>> GetContractsAsync(Pagination pagination, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Contract[]>>>)(async () =>
|
||||
public async Task<Result<Contract[]>> GetContractsAsync(Pagination pagination, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Contract[]>>>)(async () =>
|
||||
{
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
@@ -26,8 +26,8 @@ public sealed class GrantsService(IDbContextFactory<ApplicationDbContext> contex
|
||||
return Result.Ok(contracts.Select(c => c.Map()).ToArray());
|
||||
}));
|
||||
|
||||
public async ValueTask<Result<Contract>> GetContractAsync(string contractIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Contract>>>)(async () =>
|
||||
public async Task<Result<Contract>> GetContractAsync(string contractIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Contract>>>)(async () =>
|
||||
{
|
||||
var decodeResult = hashService.DecodeLongIdHash(contractIdHash);
|
||||
|
||||
@@ -44,8 +44,8 @@ public sealed class GrantsService(IDbContextFactory<ApplicationDbContext> contex
|
||||
.ToResult(contract!.Map());
|
||||
}));
|
||||
|
||||
public async ValueTask<Result<Budget[]>> GetBudgetsAsync(Pagination pagination, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Budget[]>>>)(async () =>
|
||||
public async Task<Result<Budget[]>> GetBudgetsAsync(Pagination pagination, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Budget[]>>>)(async () =>
|
||||
{
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
@@ -58,8 +58,8 @@ public sealed class GrantsService(IDbContextFactory<ApplicationDbContext> contex
|
||||
return Result.Ok(budgets.Select(b => b.Map()).ToArray());
|
||||
}));
|
||||
|
||||
public async ValueTask<Result<Budget>> GetBudgetAsync(string budgetIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Budget>>>)(async () =>
|
||||
public async Task<Result<Budget>> GetBudgetAsync(string budgetIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Budget>>>)(async () =>
|
||||
{
|
||||
var decodeResult = hashService.DecodeLongIdHash(budgetIdHash);
|
||||
|
||||
@@ -76,8 +76,8 @@ public sealed class GrantsService(IDbContextFactory<ApplicationDbContext> contex
|
||||
.ToResult(budget!.Map());
|
||||
}));
|
||||
|
||||
public async ValueTask<Result<Award[]>> GetAwardsAsync(Pagination pagination, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Award[]>>>)(async () =>
|
||||
public async Task<Result<Award[]>> GetAwardsAsync(Pagination pagination, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Award[]>>>)(async () =>
|
||||
{
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
@@ -90,8 +90,8 @@ public sealed class GrantsService(IDbContextFactory<ApplicationDbContext> contex
|
||||
return Result.Ok(awards.Select(a => a.Map()).ToArray());
|
||||
}));
|
||||
|
||||
public async ValueTask<Result<Award>> GetAwardAsync(string awardIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Award>>>)(async () =>
|
||||
public async Task<Result<Award>> GetAwardAsync(string awardIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Award>>>)(async () =>
|
||||
{
|
||||
var decodeResult = hashService.DecodeLongIdHash(awardIdHash);
|
||||
|
||||
@@ -107,8 +107,8 @@ public sealed class GrantsService(IDbContextFactory<ApplicationDbContext> contex
|
||||
.ToResult(award!.Map());
|
||||
}));
|
||||
|
||||
public async ValueTask<Result> ExecuteContractAsync(ExecuteContractRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result>>)(async () =>
|
||||
public async Task<Result> ExecuteContractAsync(ExecuteContractRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result>>)(async () =>
|
||||
{
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
@@ -123,8 +123,8 @@ public sealed class GrantsService(IDbContextFactory<ApplicationDbContext> contex
|
||||
return Result.OkIf(await context.SaveChangesAsync(cancellationToken) > 0, UpdateError.New);
|
||||
}));
|
||||
|
||||
public async ValueTask<Result> CreateContractAsync(CreateContractRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result>>)(async () =>
|
||||
public async Task<Result> CreateContractAsync(CreateContractRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result>>)(async () =>
|
||||
{
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
@@ -150,8 +150,8 @@ public sealed class GrantsService(IDbContextFactory<ApplicationDbContext> contex
|
||||
return Result.OkIf(await context.SaveChangesAsync(cancellationToken) > 0, CreateError.New);
|
||||
}));
|
||||
|
||||
public async ValueTask<Result> CreateBudgetAsync(CreateBudgetRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result>>)(async () =>
|
||||
public async Task<Result> CreateBudgetAsync(CreateBudgetRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result>>)(async () =>
|
||||
{
|
||||
if (request.Amount <= 0)
|
||||
return Result.Fail(ValidationError.Create("Budget amount must be greater than zero."));
|
||||
@@ -175,8 +175,8 @@ public sealed class GrantsService(IDbContextFactory<ApplicationDbContext> contex
|
||||
return Result.OkIf(await context.SaveChangesAsync(cancellationToken) > 0, CreateError.New);
|
||||
}));
|
||||
|
||||
public async ValueTask<Result> CreateAwardAsync(CreateAwardRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result>>)(async () =>
|
||||
public async Task<Result> CreateAwardAsync(CreateAwardRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result>>)(async () =>
|
||||
{
|
||||
if (request.Amount <= 0)
|
||||
return Result.Fail(ValidationError.Create("Approved amount must be greater than zero."));
|
||||
@@ -196,7 +196,8 @@ public sealed class GrantsService(IDbContextFactory<ApplicationDbContext> contex
|
||||
Amount = request.Amount,
|
||||
Status = ApprovalStatus.Pending,
|
||||
CreatedBy = userId,
|
||||
CreatedAt = DateTime.UtcNow
|
||||
CreatedAt = DateTime.UtcNow,
|
||||
TenantId = tenantContext.TenantId
|
||||
};
|
||||
|
||||
context.Awards.Add(award);
|
||||
@@ -204,8 +205,8 @@ public sealed class GrantsService(IDbContextFactory<ApplicationDbContext> contex
|
||||
return Result.OkIf(await context.SaveChangesAsync(cancellationToken) > 0, CreateError.New);
|
||||
}));
|
||||
|
||||
public async ValueTask<Result<string>> GetContractUrlAsync(string contractIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<string>>>)(async () =>
|
||||
public async Task<Result<string>> GetContractUrlAsync(string contractIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<string>>>)(async () =>
|
||||
{
|
||||
var decodeResult = hashService.DecodeLongIdHash(contractIdHash);
|
||||
|
||||
@@ -231,8 +232,8 @@ public sealed class GrantsService(IDbContextFactory<ApplicationDbContext> contex
|
||||
.ToResult(secureDownloadUrlResult.Value);
|
||||
}));
|
||||
|
||||
public async ValueTask<Result> UploadContractAsync(string contractIdHash, Guid userId, IFormFile file, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result>>)(async () =>
|
||||
public async Task<Result> UploadContractAsync(string contractIdHash, Guid userId, IFormFile file, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result>>)(async () =>
|
||||
{
|
||||
var decodeResult = hashService.DecodeLongIdHash(contractIdHash);
|
||||
|
||||
@@ -261,8 +262,8 @@ public sealed class GrantsService(IDbContextFactory<ApplicationDbContext> contex
|
||||
CreateError.Create("Failed to upload contract file"));
|
||||
}));
|
||||
|
||||
public async ValueTask<Result> UpdateContractAsync(UpdateContractRequest request, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result>>)(async () =>
|
||||
public async Task<Result> UpdateContractAsync(UpdateContractRequest request, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result>>)(async () =>
|
||||
{
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
|
||||
@@ -11,17 +11,35 @@ namespace PostFundManagement.Application.Services.Projects;
|
||||
public sealed class ProjectCacheService(ProjectService service, IDistributedCache cache,
|
||||
IFeatureManager featureManager) : ServiceCacheBase, IProjectService
|
||||
{
|
||||
public async ValueTask<Result> CreateActivityAsync(CreateActivityRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
public async Task<Result> CreateActivityAsync(CreateActivityRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await service.CreateActivityAsync(request, userId, cancellationToken);
|
||||
|
||||
public async ValueTask<Result> CreateProgrammeAsync(CreateProgrammeRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
public async Task<Result> CreateBeneficiaryAsync(CreateBeneficiaryRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await service.CreateBeneficiaryAsync(request, userId, cancellationToken);
|
||||
|
||||
public async Task<Result> CreateChangeRequestAsync(CreateChangeRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await service.CreateChangeRequestAsync(request, userId, cancellationToken);
|
||||
|
||||
public async Task<Result> CreateComplianceItemAsync(CreateComplianceItemRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await service.CreateComplianceItemAsync(request, userId, cancellationToken);
|
||||
|
||||
public async Task<Result> CreateIssueAsync(CreateIssueRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await service.CreateIssueAsync(request, userId, cancellationToken);
|
||||
|
||||
public async Task<Result> CreateOutcomeAsync(CreateOutcomeRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await service.CreateOutcomeAsync(request, userId, cancellationToken);
|
||||
|
||||
public async Task<Result> CreateProgrammeAsync(CreateProgrammeRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await service.CreateProgrammeAsync(request, userId, cancellationToken);
|
||||
|
||||
public async ValueTask<Result> CreateProjectAsync(CreateProjectRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
public async Task<Result> CreateProjectAsync(CreateProjectRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await service.CreateProjectAsync(request, userId, cancellationToken);
|
||||
|
||||
public async ValueTask<Result<Domain.Models.Activity[]>> GetActivitiesAsync(string projectIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Domain.Models.Activity[]>>>)(async () =>
|
||||
public async Task<Result> CreateSiteVisitAsync(CreateSiteVisitRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await service.CreateSiteVisitAsync(request, userId, cancellationToken);
|
||||
|
||||
public async Task<Result<Domain.Models.Activity[]>> GetActivitiesAsync(string projectIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Domain.Models.Activity[]>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetActivitiesAsync(projectIdHash, cancellationToken);
|
||||
@@ -44,8 +62,8 @@ public sealed class ProjectCacheService(ProjectService service, IDistributedCach
|
||||
return Result.Ok(cached.FromJson<Domain.Models.Activity[]>());
|
||||
}));
|
||||
|
||||
public async ValueTask<Result<Domain.Models.Activity>> GetActivityAsync(string activityIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Domain.Models.Activity>>>)(async () =>
|
||||
public async Task<Result<Domain.Models.Activity>> GetActivityAsync(string activityIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Domain.Models.Activity>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetActivityAsync(activityIdHash, cancellationToken);
|
||||
@@ -68,8 +86,200 @@ public sealed class ProjectCacheService(ProjectService service, IDistributedCach
|
||||
return Result.Ok(cached.FromJson<Domain.Models.Activity>());
|
||||
}));
|
||||
|
||||
public async ValueTask<Result<Milestone>> GetMilestoneAsync(string milestoneIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Milestone>>>)(async () =>
|
||||
public async Task<Result<Beneficiary[]>> GetBeneficiariesAsync(string projectIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Beneficiary[]>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetBeneficiariesAsync(projectIdHash, cancellationToken);
|
||||
|
||||
var cacheKey = HashService.ToMd5Hash($"getbeneficiaries-{projectIdHash}").Value;
|
||||
|
||||
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(cached))
|
||||
{
|
||||
var result = await service.GetBeneficiariesAsync(projectIdHash, cancellationToken);
|
||||
|
||||
if (result.IsFailed) return result;
|
||||
|
||||
await cache.SetStringAsync(cacheKey, result.Value.ToJson(), cacheOptions, cancellationToken);
|
||||
|
||||
return result.Value;
|
||||
}
|
||||
|
||||
return Result.Ok(cached.FromJson<Beneficiary[]>());
|
||||
}));
|
||||
|
||||
public async Task<Result<Beneficiary>> GetBeneficiaryAsync(string beneficiaryIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Beneficiary>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetBeneficiaryAsync(beneficiaryIdHash, cancellationToken);
|
||||
|
||||
var cacheKey = HashService.ToMd5Hash($"getbeneficiary-{beneficiaryIdHash}").Value;
|
||||
|
||||
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(cached))
|
||||
{
|
||||
var result = await service.GetBeneficiaryAsync(beneficiaryIdHash, cancellationToken);
|
||||
|
||||
if (result.IsFailed) return result;
|
||||
|
||||
await cache.SetStringAsync(cacheKey, result.Value.ToJson(), cacheOptions, cancellationToken);
|
||||
|
||||
return result.Value;
|
||||
}
|
||||
|
||||
return Result.Ok(cached.FromJson<Beneficiary>());
|
||||
}));
|
||||
|
||||
public async Task<Result<ChangeRequest>> GetChangeRequestAsync(string changeRequestIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<ChangeRequest>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetChangeRequestAsync(changeRequestIdHash, cancellationToken);
|
||||
|
||||
var cacheKey = HashService.ToMd5Hash($"getchangerequest-{changeRequestIdHash}").Value;
|
||||
|
||||
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(cached))
|
||||
{
|
||||
var result = await service.GetChangeRequestAsync(changeRequestIdHash, cancellationToken);
|
||||
|
||||
if (result.IsFailed) return result;
|
||||
|
||||
await cache.SetStringAsync(cacheKey, result.Value.ToJson(), cacheOptions, cancellationToken);
|
||||
|
||||
return result.Value;
|
||||
}
|
||||
|
||||
return Result.Ok(cached.FromJson<ChangeRequest>());
|
||||
}));
|
||||
|
||||
public async Task<Result<ChangeRequest[]>> GetChangeRequestsAsync(string projectIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<ChangeRequest[]>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetChangeRequestsAsync(projectIdHash, cancellationToken);
|
||||
|
||||
var cacheKey = HashService.ToMd5Hash($"getchangerequests-{projectIdHash}").Value;
|
||||
|
||||
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(cached))
|
||||
{
|
||||
var result = await service.GetChangeRequestsAsync(projectIdHash, cancellationToken);
|
||||
|
||||
if (result.IsFailed) return result;
|
||||
|
||||
await cache.SetStringAsync(cacheKey, result.Value.ToJson(), cacheOptions, cancellationToken);
|
||||
|
||||
return result.Value;
|
||||
}
|
||||
|
||||
return Result.Ok(cached.FromJson<ChangeRequest[]>());
|
||||
}));
|
||||
|
||||
public async Task<Result<ComplianceItem>> GetComplianceItemAsync(string complianceItemIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<ComplianceItem>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetComplianceItemAsync(complianceItemIdHash, cancellationToken);
|
||||
|
||||
var cacheKey = HashService.ToMd5Hash($"getcomplianceitem-{complianceItemIdHash}").Value;
|
||||
|
||||
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(cached))
|
||||
{
|
||||
var result = await service.GetComplianceItemAsync(complianceItemIdHash, cancellationToken);
|
||||
|
||||
if (result.IsFailed) return result;
|
||||
|
||||
await cache.SetStringAsync(cacheKey, result.Value.ToJson(), cacheOptions, cancellationToken);
|
||||
|
||||
return result.Value;
|
||||
}
|
||||
|
||||
return Result.Ok(cached.FromJson<ComplianceItem>());
|
||||
}));
|
||||
|
||||
public async Task<Result<ComplianceItem[]>> GetComplianceItemsAsync(string projectIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<ComplianceItem[]>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetComplianceItemsAsync(projectIdHash, cancellationToken);
|
||||
|
||||
var cacheKey = HashService.ToMd5Hash($"getcomplianceitems-{projectIdHash}").Value;
|
||||
|
||||
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(cached))
|
||||
{
|
||||
var result = await service.GetComplianceItemsAsync(projectIdHash, cancellationToken);
|
||||
|
||||
if (result.IsFailed) return result;
|
||||
|
||||
await cache.SetStringAsync(cacheKey, result.Value.ToJson(), cacheOptions, cancellationToken);
|
||||
|
||||
return result.Value;
|
||||
}
|
||||
|
||||
return Result.Ok(cached.FromJson<ComplianceItem[]>());
|
||||
}));
|
||||
|
||||
public async Task<Result<Issue>> GetIssueAsync(string issueIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Issue>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetIssueAsync(issueIdHash, cancellationToken);
|
||||
|
||||
var cacheKey = HashService.ToMd5Hash($"getissue-{issueIdHash}").Value;
|
||||
|
||||
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(cached))
|
||||
{
|
||||
var result = await service.GetIssueAsync(issueIdHash, cancellationToken);
|
||||
|
||||
if (result.IsFailed) return result;
|
||||
|
||||
await cache.SetStringAsync(cacheKey, result.Value.ToJson(), cacheOptions, cancellationToken);
|
||||
|
||||
return result.Value;
|
||||
}
|
||||
|
||||
return Result.Ok(cached.FromJson<Issue>());
|
||||
}));
|
||||
|
||||
public async Task<Result<Issue[]>> GetIssuesAsync(string projectIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Issue[]>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetIssuesAsync(projectIdHash, cancellationToken);
|
||||
|
||||
var cacheKey = HashService.ToMd5Hash($"getissues-{projectIdHash}").Value;
|
||||
|
||||
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(cached))
|
||||
{
|
||||
var result = await service.GetIssuesAsync(projectIdHash, cancellationToken);
|
||||
|
||||
if (result.IsFailed) return result;
|
||||
|
||||
await cache.SetStringAsync(cacheKey, result.Value.ToJson(), cacheOptions, cancellationToken);
|
||||
|
||||
return result.Value;
|
||||
}
|
||||
|
||||
return Result.Ok(cached.FromJson<Issue[]>());
|
||||
}));
|
||||
|
||||
public async Task<Result<Milestone>> GetMilestoneAsync(string milestoneIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Milestone>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetMilestoneAsync(milestoneIdHash, cancellationToken);
|
||||
@@ -92,8 +302,8 @@ public sealed class ProjectCacheService(ProjectService service, IDistributedCach
|
||||
return Result.Ok(cached.FromJson<Milestone>());
|
||||
}));
|
||||
|
||||
public async ValueTask<Result<Milestone[]>> GetMilestonesAsync(Pagination pagination, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Milestone[]>>>)(async () =>
|
||||
public async Task<Result<Milestone[]>> GetMilestonesAsync(Pagination pagination, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Milestone[]>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetMilestonesAsync(pagination, cancellationToken);
|
||||
@@ -116,8 +326,56 @@ public sealed class ProjectCacheService(ProjectService service, IDistributedCach
|
||||
return Result.Ok(cached.FromJson<Milestone[]>());
|
||||
}));
|
||||
|
||||
public async ValueTask<Result<Programme>> GetProgrammeAsync(string programmeIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Programme>>>)(async () =>
|
||||
public async Task<Result<Outcome>> GetOutcomeAsync(string outcomeIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Outcome>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetOutcomeAsync(outcomeIdHash, cancellationToken);
|
||||
|
||||
var cacheKey = HashService.ToMd5Hash($"getoutcome-{outcomeIdHash}").Value;
|
||||
|
||||
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(cached))
|
||||
{
|
||||
var result = await service.GetOutcomeAsync(outcomeIdHash, cancellationToken);
|
||||
|
||||
if (result.IsFailed) return result;
|
||||
|
||||
await cache.SetStringAsync(cacheKey, result.Value.ToJson(), cacheOptions, cancellationToken);
|
||||
|
||||
return result.Value;
|
||||
}
|
||||
|
||||
return Result.Ok(cached.FromJson<Outcome>());
|
||||
}));
|
||||
|
||||
public async Task<Result<Outcome[]>> GetOutcomesAsync(string beneficiaryIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Outcome[]>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetOutcomesAsync(beneficiaryIdHash, cancellationToken);
|
||||
|
||||
var cacheKey = HashService.ToMd5Hash($"getoutcomes-{beneficiaryIdHash}").Value;
|
||||
|
||||
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(cached))
|
||||
{
|
||||
var result = await service.GetOutcomesAsync(beneficiaryIdHash, cancellationToken);
|
||||
|
||||
if (result.IsFailed) return result;
|
||||
|
||||
await cache.SetStringAsync(cacheKey, result.Value.ToJson(), cacheOptions, cancellationToken);
|
||||
|
||||
return result.Value;
|
||||
}
|
||||
|
||||
return Result.Ok(cached.FromJson<Outcome[]>());
|
||||
}));
|
||||
|
||||
public async Task<Result<Programme>> GetProgrammeAsync(string programmeIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Programme>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetProgrammeAsync(programmeIdHash, cancellationToken);
|
||||
@@ -140,8 +398,8 @@ public sealed class ProjectCacheService(ProjectService service, IDistributedCach
|
||||
return Result.Ok(cached!.FromJson<Programme>());
|
||||
}));
|
||||
|
||||
public async ValueTask<Result<Project[]>> GetProgrammeProjectsAsync(string programmeIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Project[]>>>)(async () =>
|
||||
public async Task<Result<Project[]>> GetProgrammeProjectsAsync(string programmeIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Project[]>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetProgrammeProjectsAsync(programmeIdHash, cancellationToken);
|
||||
@@ -164,8 +422,8 @@ public sealed class ProjectCacheService(ProjectService service, IDistributedCach
|
||||
return Result.Ok(cached.FromJson<Project[]>());
|
||||
}));
|
||||
|
||||
public async ValueTask<Result<Programme[]>> GetProgrammesAsync(Pagination pagination, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Programme[]>>>)(async () =>
|
||||
public async Task<Result<Programme[]>> GetProgrammesAsync(Pagination pagination, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Programme[]>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetProgrammesAsync(pagination, cancellationToken);
|
||||
@@ -188,8 +446,8 @@ public sealed class ProjectCacheService(ProjectService service, IDistributedCach
|
||||
return Result.Ok(cached.FromJson<Programme[]>());
|
||||
}));
|
||||
|
||||
public async ValueTask<Result<Project>> GetProjectAsync(string projectIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Project>>>)(async () =>
|
||||
public async Task<Result<Project>> GetProjectAsync(string projectIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Project>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetProjectAsync(projectIdHash, cancellationToken);
|
||||
@@ -212,8 +470,8 @@ public sealed class ProjectCacheService(ProjectService service, IDistributedCach
|
||||
return Result.Ok(cached.FromJson<Project>());
|
||||
}));
|
||||
|
||||
public async ValueTask<Result<Indicator[]>> GetProjectIndicatorsAsync(string projectIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Indicator[]>>>)(async () =>
|
||||
public async Task<Result<Indicator[]>> GetProjectIndicatorsAsync(string projectIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Indicator[]>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetProjectIndicatorsAsync(projectIdHash, cancellationToken);
|
||||
@@ -236,8 +494,8 @@ public sealed class ProjectCacheService(ProjectService service, IDistributedCach
|
||||
return Result.Ok(cached.FromJson<Indicator[]>());
|
||||
}));
|
||||
|
||||
public async ValueTask<Result<Milestone[]>> GetProjectMilestonesAsync(string projectIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Milestone[]>>>)(async () =>
|
||||
public async Task<Result<Milestone[]>> GetProjectMilestonesAsync(string projectIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Milestone[]>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetProjectMilestonesAsync(projectIdHash, cancellationToken);
|
||||
@@ -260,8 +518,8 @@ public sealed class ProjectCacheService(ProjectService service, IDistributedCach
|
||||
return Result.Ok(cached.FromJson<Milestone[]>());
|
||||
}));
|
||||
|
||||
public async ValueTask<Result<Risk[]>> GetProjectRisksAsync(string projectIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Risk[]>>>)(async () =>
|
||||
public async Task<Result<Risk[]>> GetProjectRisksAsync(string projectIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Risk[]>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetProjectRisksAsync(projectIdHash, cancellationToken);
|
||||
@@ -284,8 +542,8 @@ public sealed class ProjectCacheService(ProjectService service, IDistributedCach
|
||||
return Result.Ok(cached.FromJson<Risk[]>());
|
||||
}));
|
||||
|
||||
public async ValueTask<Result<Project[]>> GetProjectsAsync(Pagination pagination, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Project[]>>>)(async () =>
|
||||
public async Task<Result<Project[]>> GetProjectsAsync(Pagination pagination, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Project[]>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetProjectsAsync(pagination, cancellationToken);
|
||||
@@ -308,15 +566,81 @@ public sealed class ProjectCacheService(ProjectService service, IDistributedCach
|
||||
return Result.Ok(cached.FromJson<Project[]>());
|
||||
}));
|
||||
|
||||
public async ValueTask<Result> UpdateMilestoneAsync(UpdateMilestoneRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
public async Task<Result<SiteVisit>> GetSiteVisitAsync(string siteVisitIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<SiteVisit>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetSiteVisitAsync(siteVisitIdHash, cancellationToken);
|
||||
|
||||
var cacheKey = HashService.ToMd5Hash($"getsitevisit-{siteVisitIdHash}").Value;
|
||||
|
||||
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(cached))
|
||||
{
|
||||
var result = await service.GetSiteVisitAsync(siteVisitIdHash, cancellationToken);
|
||||
|
||||
if (result.IsFailed) return result;
|
||||
|
||||
await cache.SetStringAsync(cacheKey, result.Value.ToJson(), cacheOptions, cancellationToken);
|
||||
|
||||
return result.Value;
|
||||
}
|
||||
|
||||
return Result.Ok(cached.FromJson<SiteVisit>());
|
||||
}));
|
||||
|
||||
public async Task<Result<SiteVisit[]>> GetSiteVisitsAsync(string projectIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<SiteVisit[]>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetSiteVisitsAsync(projectIdHash, cancellationToken);
|
||||
|
||||
var cacheKey = HashService.ToMd5Hash($"getsitevisits-{projectIdHash}").Value;
|
||||
|
||||
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(cached))
|
||||
{
|
||||
var result = await service.GetSiteVisitsAsync(projectIdHash, cancellationToken);
|
||||
|
||||
if (result.IsFailed) return result;
|
||||
|
||||
await cache.SetStringAsync(cacheKey, result.Value.ToJson(), cacheOptions, cancellationToken);
|
||||
|
||||
return result.Value;
|
||||
}
|
||||
|
||||
return Result.Ok(cached.FromJson<SiteVisit[]>());
|
||||
}));
|
||||
|
||||
public async Task<Result> UpdateBeneficiaryItemAsync(UpdateBeneficiaryRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await service.UpdateBeneficiaryItemAsync(request, userId, cancellationToken);
|
||||
|
||||
public async Task<Result> UpdateChangeRequestAsync(UpdatehangeRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await service.UpdateChangeRequestAsync(request, userId, cancellationToken);
|
||||
|
||||
public async Task<Result> UpdateComplianceItemAsync(UpdateComplianceItemRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await service.UpdateComplianceItemAsync(request, userId, cancellationToken);
|
||||
|
||||
public async Task<Result> UpdateIssueAsync(UpdateIssueRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await service.UpdateIssueAsync(request, userId, cancellationToken);
|
||||
|
||||
public async Task<Result> UpdateMilestoneAsync(UpdateMilestoneRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await service.UpdateMilestoneAsync(request, userId, cancellationToken);
|
||||
|
||||
public async ValueTask<Result> UpdateProgrammeAsync(UpdateProgrammeRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
public async Task<Result> UpdateOutcomeAsync(UpdateOutcomeRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await service.UpdateOutcomeAsync(request, userId, cancellationToken);
|
||||
|
||||
public async Task<Result> UpdateProgrammeAsync(UpdateProgrammeRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await service.UpdateProgrammeAsync(request, userId, cancellationToken);
|
||||
|
||||
public async ValueTask<Result> UpdateProjectAsync(UpdateProjectRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
public async Task<Result> UpdateProjectAsync(UpdateProjectRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await service.UpdateProjectAsync(request, userId, cancellationToken);
|
||||
|
||||
public async ValueTask<Result> UpdateProjectStatusAsync(UpdateProjectStatusRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
public async Task<Result> UpdateProjectStatusAsync(UpdateProjectStatusRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await service.UpdateProjectStatusAsync(request, userId, cancellationToken);
|
||||
|
||||
public async Task<Result> UpdateSiteVisitAsync(UpdateSiteVisitRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await service.UpdateSiteVisitAsync(request, userId, cancellationToken);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using PostFundManagement.Application.Abstractions.Services;
|
||||
using PostFundManagement.Application.Services.Shared;
|
||||
using PostFundManagement.Domain;
|
||||
using PostFundManagement.Domain.Abstractions;
|
||||
using PostFundManagement.Domain.Errors;
|
||||
using PostFundManagement.Domain.Extensions;
|
||||
using PostFundManagement.Domain.Models;
|
||||
@@ -8,10 +9,11 @@ using PostFundManagement.Infrastructure.Database;
|
||||
|
||||
namespace PostFundManagement.Application.Services.Projects;
|
||||
|
||||
public sealed class ProjectService(IDbContextFactory<ApplicationDbContext> contextFactory, HashService hashService) : IProjectService
|
||||
public sealed class ProjectService(IDbContextFactory<ApplicationDbContext> contextFactory, HashService hashService,
|
||||
ITenantContextService tenantContext) : IProjectService
|
||||
{
|
||||
public async ValueTask<Result> UpdateProjectStatusAsync(UpdateProjectStatusRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result>>)(async () =>
|
||||
public async Task<Result> UpdateProjectStatusAsync(UpdateProjectStatusRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result>>)(async () =>
|
||||
{
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
@@ -28,8 +30,8 @@ public sealed class ProjectService(IDbContextFactory<ApplicationDbContext> conte
|
||||
return Result.OkIf(changedTotal > 0, UpdateError.Create("No changes detected, update cancelled."));
|
||||
}));
|
||||
|
||||
public async ValueTask<Result<Project[]>> GetProjectsAsync(Pagination pagination, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Project[]>>>)(async () =>
|
||||
public async Task<Result<Project[]>> GetProjectsAsync(Pagination pagination, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Project[]>>>)(async () =>
|
||||
{
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
@@ -41,8 +43,8 @@ public sealed class ProjectService(IDbContextFactory<ApplicationDbContext> conte
|
||||
return Result.Ok(projects.Select(p => p.Map()).ToArray());
|
||||
}));
|
||||
|
||||
public async ValueTask<Result<Project>> GetProjectAsync(string projectIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Project>>>)(async () =>
|
||||
public async Task<Result<Project>> GetProjectAsync(string projectIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Project>>>)(async () =>
|
||||
{
|
||||
var decodeResult = hashService.DecodeLongIdHash(projectIdHash);
|
||||
|
||||
@@ -59,8 +61,8 @@ public sealed class ProjectService(IDbContextFactory<ApplicationDbContext> conte
|
||||
.ToResult(project!.Map());
|
||||
}));
|
||||
|
||||
public async ValueTask<Result<Domain.Models.Activity[]>> GetActivitiesAsync(string projectIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Domain.Models.Activity[]>>>)(async () =>
|
||||
public async Task<Result<Domain.Models.Activity[]>> GetActivitiesAsync(string projectIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Domain.Models.Activity[]>>>)(async () =>
|
||||
{
|
||||
var decodeResult = hashService.DecodeLongIdHash(projectIdHash);
|
||||
|
||||
@@ -77,8 +79,8 @@ public sealed class ProjectService(IDbContextFactory<ApplicationDbContext> conte
|
||||
return Result.Ok(activities.Select(a => a.Map()).ToArray());
|
||||
}));
|
||||
|
||||
public async ValueTask<Result> CreateProjectAsync(CreateProjectRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result>>)(async () =>
|
||||
public async Task<Result> CreateProjectAsync(CreateProjectRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result>>)(async () =>
|
||||
{
|
||||
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
@@ -101,15 +103,16 @@ public sealed class ProjectService(IDbContextFactory<ApplicationDbContext> conte
|
||||
ProjectType = request.ProjectType,
|
||||
Status = ApprovalStatus.Pending,
|
||||
CreatedBy = userId,
|
||||
CreatedAt = DateTime.UtcNow
|
||||
CreatedAt = DateTime.UtcNow,
|
||||
TenantId = tenantContext.TenantId
|
||||
});
|
||||
|
||||
return Result.OkIf(await context.SaveChangesAsync(cancellationToken) > 0,
|
||||
CreateError.Create("No changes detected, update cancelled."));
|
||||
}));
|
||||
|
||||
public async ValueTask<Result> CreateActivityAsync(CreateActivityRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result>>)(async () =>
|
||||
public async Task<Result> CreateActivityAsync(CreateActivityRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result>>)(async () =>
|
||||
{
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
@@ -138,8 +141,8 @@ public sealed class ProjectService(IDbContextFactory<ApplicationDbContext> conte
|
||||
CreateError.Create("No record was created."));
|
||||
}));
|
||||
|
||||
public async ValueTask<Result<Milestone[]>> GetProjectMilestonesAsync(string projectIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Milestone[]>>>)(async () =>
|
||||
public async Task<Result<Milestone[]>> GetProjectMilestonesAsync(string projectIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Milestone[]>>>)(async () =>
|
||||
{
|
||||
var decodeResult = hashService.DecodeLongIdHash(projectIdHash);
|
||||
|
||||
@@ -157,8 +160,8 @@ public sealed class ProjectService(IDbContextFactory<ApplicationDbContext> conte
|
||||
return Result.Ok(milestones.Select(i => i.Map()).ToArray());
|
||||
}));
|
||||
|
||||
public async ValueTask<Result<Indicator[]>> GetProjectIndicatorsAsync(string projectIdHash, CancellationToken cancellationToken) =>
|
||||
await Result.Try((Func<ValueTask<Result<Indicator[]>>>)(async () =>
|
||||
public async Task<Result<Indicator[]>> GetProjectIndicatorsAsync(string projectIdHash, CancellationToken cancellationToken) =>
|
||||
await Result.Try((Func<Task<Result<Indicator[]>>>)(async () =>
|
||||
{
|
||||
var decodeResult = hashService.DecodeLongIdHash(projectIdHash);
|
||||
|
||||
@@ -176,8 +179,8 @@ public sealed class ProjectService(IDbContextFactory<ApplicationDbContext> conte
|
||||
return Result.Ok(evidences.Select(e => e.Map()).ToArray());
|
||||
}));
|
||||
|
||||
public async ValueTask<Result<Milestone>> GetMilestoneAsync(string milestoneIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Milestone>>>)(async () =>
|
||||
public async Task<Result<Milestone>> GetMilestoneAsync(string milestoneIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Milestone>>>)(async () =>
|
||||
{
|
||||
var decodeResult = hashService.DecodeLongIdHash(milestoneIdHash);
|
||||
|
||||
@@ -193,8 +196,8 @@ public sealed class ProjectService(IDbContextFactory<ApplicationDbContext> conte
|
||||
.ToResult(milestone!.Map());
|
||||
}));
|
||||
|
||||
public async ValueTask<Result<Milestone[]>> GetMilestonesAsync(Pagination pagination, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Milestone[]>>>)(async () =>
|
||||
public async Task<Result<Milestone[]>> GetMilestonesAsync(Pagination pagination, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Milestone[]>>>)(async () =>
|
||||
{
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
@@ -207,8 +210,8 @@ public sealed class ProjectService(IDbContextFactory<ApplicationDbContext> conte
|
||||
return Result.Ok(milestones.Select(i => i.Map()).ToArray());
|
||||
}));
|
||||
|
||||
public async ValueTask<Result> UpdateMilestoneAsync(UpdateMilestoneRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result>>)(async () =>
|
||||
public async Task<Result> UpdateMilestoneAsync(UpdateMilestoneRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result>>)(async () =>
|
||||
{
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
@@ -227,8 +230,8 @@ public sealed class ProjectService(IDbContextFactory<ApplicationDbContext> conte
|
||||
return Result.OkIf(changedTotal > 0, UpdateError.Create("No changes detected, update cancelled."));
|
||||
}));
|
||||
|
||||
public async ValueTask<Result> UpdateProjectAsync(UpdateProjectRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result>>)(async () =>
|
||||
public async Task<Result> UpdateProjectAsync(UpdateProjectRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result>>)(async () =>
|
||||
{
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
@@ -246,8 +249,8 @@ public sealed class ProjectService(IDbContextFactory<ApplicationDbContext> conte
|
||||
return Result.OkIf(changedTotal > 0, UpdateError.Create("No changes detected, update cancelled."));
|
||||
}));
|
||||
|
||||
public async ValueTask<Result<Domain.Models.Activity>> GetActivityAsync(string activityIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Domain.Models.Activity>>>)(async () =>
|
||||
public async Task<Result<Domain.Models.Activity>> GetActivityAsync(string activityIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Domain.Models.Activity>>>)(async () =>
|
||||
{
|
||||
var decodeResult = hashService.DecodeLongIdHash(activityIdHash);
|
||||
|
||||
@@ -264,8 +267,8 @@ public sealed class ProjectService(IDbContextFactory<ApplicationDbContext> conte
|
||||
.ToResult(activity!.Map());
|
||||
}));
|
||||
|
||||
public async ValueTask<Result<Risk[]>> GetProjectRisksAsync(string projectIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Risk[]>>>)(async () =>
|
||||
public async Task<Result<Risk[]>> GetProjectRisksAsync(string projectIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Risk[]>>>)(async () =>
|
||||
{
|
||||
var decodeResult = hashService.DecodeLongIdHash(projectIdHash);
|
||||
|
||||
@@ -283,8 +286,8 @@ public sealed class ProjectService(IDbContextFactory<ApplicationDbContext> conte
|
||||
return Result.Ok(risks.Select(i => i.Map()).ToArray());
|
||||
}));
|
||||
|
||||
public async ValueTask<Result> CreateProgrammeAsync(CreateProgrammeRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result>>)(async () =>
|
||||
public async Task<Result> CreateProgrammeAsync(CreateProgrammeRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result>>)(async () =>
|
||||
{
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
@@ -303,14 +306,15 @@ public sealed class ProjectService(IDbContextFactory<ApplicationDbContext> conte
|
||||
Name = name,
|
||||
CreatedBy = userId,
|
||||
CreatedAt = DateTime.UtcNow,
|
||||
Status = ApprovalStatus.Pending
|
||||
Status = ApprovalStatus.Pending,
|
||||
TenantId = tenantContext.TenantId
|
||||
});
|
||||
|
||||
return Result.OkIf(await context.SaveChangesAsync(cancellationToken) > 0, CreateError.New);
|
||||
}));
|
||||
|
||||
public async ValueTask<Result> UpdateProgrammeAsync(UpdateProgrammeRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result>>)(async () =>
|
||||
public async Task<Result> UpdateProgrammeAsync(UpdateProgrammeRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result>>)(async () =>
|
||||
{
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
@@ -328,8 +332,8 @@ public sealed class ProjectService(IDbContextFactory<ApplicationDbContext> conte
|
||||
return Result.OkIf(changedTotal > 0, UpdateError.Create("No changes detected, update cancelled."));
|
||||
}));
|
||||
|
||||
public async ValueTask<Result<Programme>> GetProgrammeAsync(string programmeIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Programme>>>)(async () =>
|
||||
public async Task<Result<Programme>> GetProgrammeAsync(string programmeIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Programme>>>)(async () =>
|
||||
{
|
||||
var decodeResult = hashService.DecodeLongIdHash(programmeIdHash);
|
||||
|
||||
@@ -344,8 +348,8 @@ public sealed class ProjectService(IDbContextFactory<ApplicationDbContext> conte
|
||||
.ToResult(programme!.Map());
|
||||
}));
|
||||
|
||||
public async ValueTask<Result<Programme[]>> GetProgrammesAsync(Pagination pagination, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Programme[]>>>)(async () =>
|
||||
public async Task<Result<Programme[]>> GetProgrammesAsync(Pagination pagination, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Programme[]>>>)(async () =>
|
||||
{
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
@@ -358,8 +362,8 @@ public sealed class ProjectService(IDbContextFactory<ApplicationDbContext> conte
|
||||
return Result.Ok(programmes.Select(i => i.Map()).ToArray());
|
||||
}));
|
||||
|
||||
public async ValueTask<Result<Project[]>> GetProgrammeProjectsAsync(string programmeIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Project[]>>>)(async () =>
|
||||
public async Task<Result<Project[]>> GetProgrammeProjectsAsync(string programmeIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Project[]>>>)(async () =>
|
||||
{
|
||||
var decodeResult = hashService.DecodeLongIdHash(programmeIdHash);
|
||||
|
||||
@@ -378,4 +382,124 @@ public sealed class ProjectService(IDbContextFactory<ApplicationDbContext> conte
|
||||
|
||||
return Result.Ok(projects.Select(i => i.Map()).ToArray());
|
||||
}));
|
||||
|
||||
public Task<Result> CreateChangeRequestAsync(CreateChangeRequest request, Guid userId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<Result> UpdateChangeRequestAsync(UpdatehangeRequest request, Guid userId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<Result<ChangeRequest[]>> GetChangeRequestsAsync(string projectIdHash, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<Result<ChangeRequest>> GetChangeRequestAsync(string changeRequestIdHash, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<Result> CreateComplianceItemAsync(CreateComplianceItemRequest request, Guid userId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<Result> UpdateComplianceItemAsync(UpdateComplianceItemRequest request, Guid userId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<Result<ComplianceItem[]>> GetComplianceItemsAsync(string projectIdHash, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<Result<ComplianceItem>> GetComplianceItemAsync(string complianceItemIdHash, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<Result> CreateBeneficiaryAsync(CreateBeneficiaryRequest request, Guid userId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<Result> UpdateBeneficiaryItemAsync(UpdateBeneficiaryRequest request, Guid userId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<Result<Beneficiary[]>> GetBeneficiariesAsync(string projectIdHash, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<Result<Beneficiary>> GetBeneficiaryAsync(string beneficiaryIdHash, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<Result> CreateIssueAsync(CreateIssueRequest request, Guid userId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<Result> UpdateIssueAsync(UpdateIssueRequest request, Guid userId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<Result<Issue[]>> GetIssuesAsync(string projectIdHash, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<Result<Issue>> GetIssueAsync(string issueIdHash, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<Result> CreateOutcomeAsync(CreateOutcomeRequest request, Guid userId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<Result> UpdateOutcomeAsync(UpdateOutcomeRequest request, Guid userId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<Result<Outcome[]>> GetOutcomesAsync(string beneficiaryIdHash, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<Result<Outcome>> GetOutcomeAsync(string outcomeIdHash, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<Result> CreateSiteVisitAsync(CreateSiteVisitRequest request, Guid userId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<Result> UpdateSiteVisitAsync(UpdateSiteVisitRequest request, Guid userId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<Result<SiteVisit[]>> GetSiteVisitsAsync(string projectIdHash, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<Result<SiteVisit>> GetSiteVisitAsync(string siteVisitIdHash, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,75 @@ using static PostFundManagement.Domain.Extensions.Constants;
|
||||
|
||||
namespace PostFundManagement.Application.Services.Projects;
|
||||
|
||||
public sealed record UpdateSiteVisitRequest([Required] long SiteVisitId,
|
||||
[Required][MaxLength(LabelLength)] string InspectorName,
|
||||
[Required][MaxLength(TextLength)] string Findings,
|
||||
[Required] ApprovalStatus Status,
|
||||
[Required] DateTime VisitedAt);
|
||||
|
||||
public sealed record CreateSiteVisitRequest([Required] long ProjectId,
|
||||
[Required][MaxLength(LabelLength)] string InspectorName,
|
||||
[Required][MaxLength(TextLength)] string Findings,
|
||||
[Required] DateTime VisitedAt);
|
||||
|
||||
public sealed record UpdateOutcomeRequest([Required] long OutcomeId,
|
||||
[Required][MaxLength(LabelLength)] string Name,
|
||||
[Required][MaxLength(TextLength)] string Description);
|
||||
|
||||
public sealed record CreateOutcomeRequest([Required] long BeneficiaryId,
|
||||
[Required][MaxLength(LabelLength)] string Name,
|
||||
[Required][MaxLength(TextLength)] string Description);
|
||||
|
||||
public sealed record UpdateIssueRequest([Required] long IssueId,
|
||||
[Required][MaxLength(LabelLength)] string Title,
|
||||
[Required][MaxLength(TextLength)] string Description,
|
||||
[Required][MaxLength(TextLength)] string Resolution,
|
||||
[Required] DateTime? ResolvedAt,
|
||||
[Required] Priority Priority,
|
||||
[Required] ActivityStatus Status,
|
||||
[Required] Guid AssignedTo);
|
||||
|
||||
public sealed record CreateIssueRequest([Required] long ProjectId,
|
||||
[Required][MaxLength(LabelLength)] string Title,
|
||||
[Required][MaxLength(TextLength)] string Description,
|
||||
[Required] Priority Priority,
|
||||
[Required] Guid AssignedTo);
|
||||
|
||||
public sealed record UpdateBeneficiaryRequest([Required] long BeneficiaryId,
|
||||
[Required][MaxLength(LabelLength)] string Name,
|
||||
[Required][MaxLength(LabelLength)] string Category,
|
||||
[Required][MaxLength(LabelLength)] string Location,
|
||||
[Required] int TargetCount,
|
||||
[Required] int ReachedCount);
|
||||
|
||||
public sealed record CreateBeneficiaryRequest([Required] long ProjectId,
|
||||
[Required][MaxLength(LabelLength)] string Name,
|
||||
[Required][MaxLength(LabelLength)] string Category,
|
||||
[Required][MaxLength(LabelLength)] string Location,
|
||||
[Required] int TargetCount,
|
||||
[Required] int ReachedCount);
|
||||
|
||||
public sealed record UpdateComplianceItemRequest([Required] long ComplianceItemId,
|
||||
[Required][MaxLength(LabelLength)] string Title,
|
||||
[Required][MaxLength(TextLength)] string Requirements,
|
||||
[Required] ApprovalStatus Status);
|
||||
|
||||
public sealed record CreateComplianceItemRequest([Required] long ProjectId,
|
||||
[Required][MaxLength(LabelLength)] string Title,
|
||||
[Required][MaxLength(TextLength)] string Requirements);
|
||||
|
||||
public sealed record UpdatehangeRequest([Required] long ChangeRequestId,
|
||||
[Required][MaxLength(LabelLength)] string Title,
|
||||
[Required][MaxLength(TextLength)] string Justification,
|
||||
[Required] decimal RevisedBudget,
|
||||
[Required] ApprovalStatus Status);
|
||||
|
||||
public sealed record CreateChangeRequest([Required] long ProjectId,
|
||||
[Required][MaxLength(LabelLength)] string Title,
|
||||
[Required][MaxLength(TextLength)] string Justification,
|
||||
[Required] decimal RevisedBudget,
|
||||
[Required] DateTime RevisionDate);
|
||||
|
||||
public sealed record UpdateProgrammeRequest([Required] long ProgrammeId,
|
||||
[Required][MaxLength(LabelLength)] string Name,
|
||||
[Required] Guid OwnerId,
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
using PostFundManagement.Domain.Abstractions;
|
||||
using PostFundManagement.Domain.Errors;
|
||||
using PostFundManagement.Infrastructure.Database;
|
||||
|
||||
namespace PostFundManagement.Application.Services.Shared;
|
||||
|
||||
public sealed class AuditService(IDbContextFactory<ApplicationDbContext> contextFactory, ITenantContextService tenantContextService) : IService
|
||||
{
|
||||
public async Task<Result> LogActionAsync(string entityId, string entityName, string action, string[] changes, Guid performedBy, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result>>)(async () =>
|
||||
{
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
context.Add(new Domain.Entities.AuditLog
|
||||
{
|
||||
EntityId = entityId,
|
||||
Action = action,
|
||||
Changes = changes,
|
||||
EntityName = entityName,
|
||||
PerformedBy = performedBy,
|
||||
Timestamp = DateTime.UtcNow,
|
||||
TenantId = tenantContextService.TenantId > 0 ? tenantContextService.TenantId : null,
|
||||
});
|
||||
|
||||
return Result.FailIf(await context.SaveChangesAsync(cancellationToken) <= 0, CreateError.New);
|
||||
}));
|
||||
}
|
||||
@@ -4,32 +4,32 @@ namespace PostFundManagement.Application.Services.Shared;
|
||||
|
||||
public sealed class BrowserLocalStorageService(ProtectedLocalStorage storage)
|
||||
{
|
||||
public async ValueTask<Result> DeleteAsync(string key) =>
|
||||
await Result.Try((Func<ValueTask<Result>>)(async () =>
|
||||
public async Task<Result> DeleteAsync(string key) =>
|
||||
await Result.Try((Func<Task<Result>>)(async () =>
|
||||
{
|
||||
await storage.DeleteAsync(key);
|
||||
|
||||
return Result.Ok();
|
||||
}));
|
||||
|
||||
public async ValueTask<Result> SaveAsync(string key, string value) =>
|
||||
await Result.Try((Func<ValueTask<Result>>)(async () =>
|
||||
public async Task<Result> SaveAsync(string key, string value) =>
|
||||
await Result.Try((Func<Task<Result>>)(async () =>
|
||||
{
|
||||
await storage.SetAsync(key, value);
|
||||
|
||||
return Result.Ok();
|
||||
}));
|
||||
|
||||
public async ValueTask<Result> SaveAsync<TValue>(string key, TValue value) where TValue : class =>
|
||||
await Result.Try((Func<ValueTask<Result>>)(async () =>
|
||||
public async Task<Result> SaveAsync<TValue>(string key, TValue value) where TValue : class =>
|
||||
await Result.Try((Func<Task<Result>>)(async () =>
|
||||
{
|
||||
await storage.SetAsync(key, value);
|
||||
|
||||
return Result.Ok();
|
||||
}));
|
||||
|
||||
public async ValueTask<Result<string>> GetAsync(string key) =>
|
||||
await Result.Try((Func<ValueTask<Result<string>>>)(async () =>
|
||||
public async Task<Result<string>> GetAsync(string key) =>
|
||||
await Result.Try((Func<Task<Result<string>>>)(async () =>
|
||||
{
|
||||
var retrieval = await storage.GetAsync<string>(key);
|
||||
|
||||
@@ -38,8 +38,8 @@ public sealed class BrowserLocalStorageService(ProtectedLocalStorage storage)
|
||||
.ToResult(retrieval.Value!);
|
||||
}));
|
||||
|
||||
public async ValueTask<Result<TValue>> GetAsync<TValue>(string key) where TValue : class =>
|
||||
await Result.Try((Func<ValueTask<Result<TValue>>>)(async () =>
|
||||
public async Task<Result<TValue>> GetAsync<TValue>(string key) where TValue : class =>
|
||||
await Result.Try((Func<Task<Result<TValue>>>)(async () =>
|
||||
{
|
||||
var retrieval = await storage.GetAsync<TValue>(key);
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ public sealed class EmailService(IOptions<SmtpSettings> options) : IDisposable
|
||||
|
||||
public EmailStatuses Status { get; private set; } = EmailStatuses.Disconnected;
|
||||
|
||||
public async ValueTask<Result<Response>> SendEmailAsync(Message message, CancellationToken cancellationToken = default)
|
||||
public async Task<Result<Response>> SendEmailAsync(Message message, CancellationToken cancellationToken = default)
|
||||
{
|
||||
using var activity = EmailTelemetry.Source.StartActivity("Email Send");
|
||||
|
||||
@@ -121,7 +121,7 @@ public sealed class EmailService(IOptions<SmtpSettings> options) : IDisposable
|
||||
return Result.Fail<Response>(response);
|
||||
}
|
||||
|
||||
public async ValueTask<Result<Response>> ConnectAsync(CancellationToken cancellationToken = default)
|
||||
public async Task<Result<Response>> ConnectAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
using var activity = EmailTelemetry.Source.StartActivity("Email Connect");
|
||||
activity?.SetTag("email.smtp.connect", settings.Host);
|
||||
@@ -174,7 +174,7 @@ public sealed class EmailService(IOptions<SmtpSettings> options) : IDisposable
|
||||
}
|
||||
}
|
||||
|
||||
public async ValueTask<Result> DisconnectAsync(CancellationToken cancellationToken = default)
|
||||
public async Task<Result> DisconnectAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
using var activity = EmailTelemetry.Source.StartActivity("Email Disconnect");
|
||||
activity?.SetTag("email.smtp.disconnect", settings.Host);
|
||||
|
||||
@@ -67,7 +67,7 @@ public sealed partial class HashService(IHashids hasher) : IService
|
||||
}
|
||||
|
||||
public async Task<Result<string>> DecodeHexHash(string hex) =>
|
||||
await Result.Try((Func<ValueTask<Result<string>>>)(async () =>
|
||||
await Result.Try((Func<Task<Result<string>>>)(async () =>
|
||||
{
|
||||
string decoded = hasher.DecodeHex(hex);
|
||||
|
||||
|
||||
@@ -5,6 +5,6 @@ namespace PostFundManagement.Application.Services.Shared;
|
||||
|
||||
public sealed class IdentityCacheService(IdentityService service) : ServiceCacheBase, IIdentityService
|
||||
{
|
||||
public async ValueTask<Result> UserIsAuthorisedAsync(Guid userId, CancellationToken cancellationToken = default) =>
|
||||
public async Task<Result> UserIsAuthorisedAsync(Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await service.UserIsAuthorisedAsync(userId, cancellationToken);
|
||||
}
|
||||
|
||||
@@ -7,11 +7,12 @@ namespace PostFundManagement.Application.Services.Shared;
|
||||
|
||||
public sealed class IdentityService(IDbContextFactory<ApplicationDbContext> contextFactory) : IIdentityService
|
||||
{
|
||||
public async ValueTask<Result> UserIsAuthorisedAsync(Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result>>)(async () =>
|
||||
public async Task<Result> UserIsAuthorisedAsync(Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result>>)(async () =>
|
||||
{
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
// TODO: Ensure TenantUser status is checked
|
||||
var userExistsAndActive = await context.Users
|
||||
.AnyAsync(u => u.Id == userId && u.Status == ActivityStatus.Active, cancellationToken);
|
||||
|
||||
|
||||
@@ -9,8 +9,8 @@ public sealed class TokenService(ISecurityConnectApi connectApi, IOptions<Securi
|
||||
{
|
||||
private readonly SecurityClientSettings clientSettings = clientOptions.Value;
|
||||
|
||||
public async ValueTask<Result<Domain.Security.Models.TokenResponse>> GenerateAsync(CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Domain.Security.Models.TokenResponse>>>)(async () =>
|
||||
public async Task<Result<Domain.Security.Models.TokenResponse>> GenerateAsync(CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Domain.Security.Models.TokenResponse>>>)(async () =>
|
||||
{
|
||||
using var response = await connectApi.GetToken(new Domain.Security.Models.TokenRequest
|
||||
{
|
||||
@@ -34,7 +34,7 @@ public sealed class TokenService(ISecurityConnectApi connectApi, IOptions<Securi
|
||||
.ToResult(tokenResponse!);
|
||||
}
|
||||
|
||||
return await Result.Try((Func<ValueTask<Result<Domain.Security.Models.TokenResponse>>>)(async () =>
|
||||
return await Result.Try((Func<Task<Result<Domain.Security.Models.TokenResponse>>>)(async () =>
|
||||
{
|
||||
var errorResult = JsonSerializer.Deserialize<TokenErrorResponse>(contentRaw);
|
||||
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
using PostFundManagement.Application.Abstractions;
|
||||
using PostFundManagement.Application.Abstractions.Services;
|
||||
using PostFundManagement.Application.Services.Shared;
|
||||
using static PostFundManagement.Domain.Extensions.Constants;
|
||||
|
||||
namespace PostFundManagement.Application.Services.Tools;
|
||||
|
||||
public sealed class ToolCacheService(ToolService service, IDistributedCache cache,
|
||||
IFeatureManager featureManager) : ServiceCacheBase, IToolService
|
||||
{
|
||||
public async ValueTask<Result<string>> EncodeLong(long id, CancellationToken cancellationToken) =>
|
||||
await Result.Try((Func<ValueTask<Result<string>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.EncodeLong(id, cancellationToken);
|
||||
|
||||
var cacheKey = HashService.ToMd5Hash($"encodelonghash-{id}").Value;
|
||||
|
||||
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
|
||||
|
||||
if(string.IsNullOrWhiteSpace(cached))
|
||||
{
|
||||
var result = (await service.EncodeLong(id).ConfigureAwait(false));
|
||||
|
||||
if (result.IsFailed) return result;
|
||||
|
||||
await cache.SetStringAsync(cacheKey, result.Value, cacheOptions, cancellationToken);
|
||||
|
||||
return result.Value;
|
||||
}
|
||||
|
||||
return Result.Ok(cached);
|
||||
}));
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
using PostFundManagement.Application.Abstractions.Services;
|
||||
using PostFundManagement.Application.Services.Shared;
|
||||
|
||||
namespace PostFundManagement.Application.Services.Tools;
|
||||
|
||||
public sealed class ToolService(HashService service) : IToolService
|
||||
{
|
||||
public ValueTask<Result<string>> EncodeLong(long id, CancellationToken cancellationToken = default) =>
|
||||
ValueTask.FromResult(service.HashEncodeLongId(id));
|
||||
}
|
||||
@@ -11,8 +11,8 @@ namespace PostFundManagement.Application.Services.Users;
|
||||
public sealed class UserCacheService(UserService service, IDistributedCache cache,
|
||||
IFeatureManager featureManager) : ServiceCacheBase, IUserService
|
||||
{
|
||||
public async ValueTask<Result<User>> GetUserAsync(Guid userId, CancellationToken cancellationToken) =>
|
||||
await Result.Try((Func<ValueTask<Result<User>>>)(async () =>
|
||||
public async Task<Result<User>> GetUserAsync(Guid userId, CancellationToken cancellationToken) =>
|
||||
await Result.Try((Func<Task<Result<User>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetUserAsync(userId, cancellationToken);
|
||||
@@ -35,8 +35,8 @@ public sealed class UserCacheService(UserService service, IDistributedCache cach
|
||||
return Result.Ok(cached.FromJson<User>());
|
||||
}));
|
||||
|
||||
public async ValueTask<Result<User[]>> GetUsersAsync(Pagination pagination, UserFilterRequest request, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<User[]>>>)(async () =>
|
||||
public async Task<Result<User[]>> GetUsersAsync(Pagination pagination, UserFilterRequest request, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<User[]>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetUsersAsync(pagination, request, cancellationToken);
|
||||
@@ -61,9 +61,9 @@ public sealed class UserCacheService(UserService service, IDistributedCache cach
|
||||
return Result.Ok(cached.FromJson<User[]>());
|
||||
}));
|
||||
|
||||
public async ValueTask<Result> SyncUserAsync(Guid userId, string email, CancellationToken cancellationToken = default) =>
|
||||
public async Task<Result> SyncUserAsync(Guid userId, string email, CancellationToken cancellationToken = default) =>
|
||||
await service.SyncUserAsync(userId, email, cancellationToken);
|
||||
|
||||
public async ValueTask<Result> UpdateUserStatusAsync(Guid userId, ActivityStatus status, CancellationToken cancellationToken = default) =>
|
||||
public async Task<Result> UpdateUserStatusAsync(Guid userId, ActivityStatus status, CancellationToken cancellationToken = default) =>
|
||||
await service.UpdateUserStatusAsync(userId, status, cancellationToken);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using PostFundManagement.Application.Abstractions.Services;
|
||||
using PostFundManagement.Domain;
|
||||
using PostFundManagement.Domain.Abstractions;
|
||||
using PostFundManagement.Domain.Errors;
|
||||
using PostFundManagement.Domain.Extensions;
|
||||
using PostFundManagement.Domain.Models;
|
||||
@@ -7,16 +8,19 @@ using PostFundManagement.Infrastructure.Database;
|
||||
|
||||
namespace PostFundManagement.Application.Services.Users;
|
||||
|
||||
public sealed class UserService(IDbContextFactory<ApplicationDbContext> contextFactory) : IUserService
|
||||
public sealed class UserService(IDbContextFactory<ApplicationDbContext> contextFactory, ITenantContextService tenantContext) : IUserService
|
||||
{
|
||||
public async ValueTask<Result> SyncUserAsync(Guid userId, string email, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result>>)(async () =>
|
||||
public async Task<Result> SyncUserAsync(Guid userId, string email, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result>>)(async () =>
|
||||
{
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
var user = await context.Users.FirstOrDefaultAsync(u => u.Id == userId, cancellationToken);
|
||||
var tenantUser = await context.TenantUsers
|
||||
.Include(i => i.User)
|
||||
.FirstOrDefaultAsync(u => u.UserId == userId, cancellationToken);
|
||||
|
||||
if (user is null)
|
||||
if (tenantUser is null)
|
||||
{
|
||||
context.Users.Add(new Domain.Entities.User
|
||||
{
|
||||
Id = userId,
|
||||
@@ -24,35 +28,45 @@ public sealed class UserService(IDbContextFactory<ApplicationDbContext> contextF
|
||||
Status = ActivityStatus.Active,
|
||||
LastLoginAt = DateTime.UtcNow
|
||||
});
|
||||
|
||||
context.TenantUsers.Add(new Domain.Entities.TenantUser
|
||||
{
|
||||
CreatedAt = DateTime.UtcNow,
|
||||
CreatedBy = userId,
|
||||
Status = ActivityStatus.Active,
|
||||
TenantId = tenantContext.TenantId,
|
||||
UserId = userId
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
user!.Email = email;
|
||||
user.LastLoginAt = DateTime.UtcNow;
|
||||
tenantUser.User!.Email = email;
|
||||
tenantUser.User.LastLoginAt = DateTime.UtcNow;
|
||||
|
||||
context.Users.Update(user);
|
||||
context.Users.Update(tenantUser.User);
|
||||
}
|
||||
|
||||
return Result.OkIf(await context.SaveChangesAsync(cancellationToken) > 0, CreateError.New);
|
||||
}));
|
||||
|
||||
public async ValueTask<Result<User[]>> GetUsersAsync(Pagination pagination, UserFilterRequest request, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<User[]>>>)(async () =>
|
||||
public async Task<Result<User[]>> GetUsersAsync(Pagination pagination, UserFilterRequest request, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<User[]>>>)(async () =>
|
||||
{
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
var query = context.Users.AsNoTracking();
|
||||
var query = context.TenantUsers.Include(i => i.User).AsNoTracking();
|
||||
|
||||
if (request.Status.HasValue)
|
||||
query = query.Where(u => u.Status == request.Status.Value);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(request.Email))
|
||||
query = query.Where(u => u.Email != null && u.Email.Contains(request.Email));
|
||||
query = query.Where(u => u.User!.Email != null && u.User!.Email.Contains(request.Email));
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(request.SortBy))
|
||||
query = request.SortBy.ToLowerInvariant() switch
|
||||
{
|
||||
"email" => request.SortDescending ? query.OrderByDescending(u => u.Email) : query.OrderBy(u => u.Email),
|
||||
"lastloginat" => request.SortDescending ? query.OrderByDescending(u => u.LastLoginAt) : query.OrderBy(u => u.LastLoginAt),
|
||||
"email" => request.SortDescending ? query.OrderByDescending(u => u.User!.Email) : query.OrderBy(u => u.User!.Email),
|
||||
"lastloginat" => request.SortDescending ? query.OrderByDescending(u => u.User!.LastLoginAt) : query.OrderBy(u => u.User!.LastLoginAt),
|
||||
"status" => request.SortDescending ? query.OrderByDescending(u => u.Status) : query.OrderBy(u => u.Status),
|
||||
_ => request.SortDescending ? query.OrderByDescending(u => u.Id) : query.OrderBy(u => u.Id)
|
||||
};
|
||||
@@ -62,30 +76,36 @@ public sealed class UserService(IDbContextFactory<ApplicationDbContext> contextF
|
||||
var users = await query.Skip((pagination.Page - 1) * pagination.PageSize)
|
||||
.Take(pagination.PageSize).ToListAsync(cancellationToken);
|
||||
|
||||
return Result.Ok(users.Select(u => u.Map()).ToArray());
|
||||
return Result.Ok(users.Select(u => u.User!.Map()).ToArray());
|
||||
}));
|
||||
|
||||
public async ValueTask<Result> UpdateUserStatusAsync(Guid userId, ActivityStatus status, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result>>)(async () =>
|
||||
public async Task<Result> UpdateUserStatusAsync(Guid userId, ActivityStatus status, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result>>)(async () =>
|
||||
{
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
var changedTotal = await context.Users
|
||||
.Where(f => f.Id == userId)
|
||||
var changedTotal = await context.TenantUsers
|
||||
.Include(i => i.User)
|
||||
.Where(f => f.UserId == userId)
|
||||
.ExecuteUpdateAsync(f => f
|
||||
.SetProperty(u => u.Status, status), cancellationToken);
|
||||
|
||||
changedTotal += await context.Users.Where(f => f.Id == userId)
|
||||
.ExecuteUpdateAsync(f => f.SetProperty(u => u.Status, status), cancellationToken);
|
||||
|
||||
return Result.OkIf(changedTotal > 0, UpdateError.New);
|
||||
}));
|
||||
|
||||
public async ValueTask<Result<User>> GetUserAsync(Guid userId, CancellationToken cancellationToken) =>
|
||||
await Result.Try((Func<ValueTask<Result<User>>>)(async () =>
|
||||
public async Task<Result<User>> GetUserAsync(Guid userId, CancellationToken cancellationToken) =>
|
||||
await Result.Try((Func<Task<Result<User>>>)(async () =>
|
||||
{
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
var user = await context.Users.AsNoTracking()
|
||||
.FirstOrDefaultAsync(f => f.Id == userId, cancellationToken);
|
||||
var tenantUser = await context.TenantUsers.AsNoTracking()
|
||||
.Include(i => i.User)
|
||||
.FirstOrDefaultAsync(f => f.UserId == userId, cancellationToken);
|
||||
|
||||
return Result.FailIf(user is null, NotFoundError.New)
|
||||
.ToResult(user!.Map());
|
||||
return Result.FailIf(tenantUser == null, NotFoundError.New)
|
||||
.ToResult(tenantUser!.User?.Map()!);
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ namespace PostFundManagement.Domain.Abstractions;
|
||||
public interface IS3Service
|
||||
{
|
||||
string GenerateCdnUrl(string fileKey);
|
||||
ValueTask<Result<string>> GeneratePresignedUrlAsync(string fileKey, TimeSpan duration, string? contentType = null, CancellationToken cancellationToken = default);
|
||||
ValueTask<Result<string>> UploadFileAsync(string fileName, string subPath, Stream fileStream, string contentType, CancellationToken cancellationToken = default);
|
||||
ValueTask<Result> DeleteFileAsync(string fileKey, CancellationToken cancellationToken = default);
|
||||
Task<Result<string>> GeneratePresignedUrlAsync(string fileKey, TimeSpan duration, string? contentType = null, CancellationToken cancellationToken = default);
|
||||
Task<Result<string>> UploadFileAsync(string fileName, string subPath, Stream fileStream, string contentType, CancellationToken cancellationToken = default);
|
||||
Task<Result> DeleteFileAsync(string fileKey, CancellationToken cancellationToken = default);
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace PostFundManagement.Domain.Abstractions;
|
||||
|
||||
public interface ITenantContextService
|
||||
{
|
||||
string? TenantName { get; }
|
||||
long TenantId { get; }
|
||||
bool IsAdmin { get; }
|
||||
bool HasTenantFilter { get; }
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace PostFundManagement.Domain.Abstractions;
|
||||
|
||||
public interface ITenantEntity
|
||||
{
|
||||
public long TenantId { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
namespace PostFundManagement.Domain.Attributes;
|
||||
|
||||
[AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = false)]
|
||||
public sealed class AuditAttribute : Attribute;
|
||||
@@ -0,0 +1,4 @@
|
||||
namespace PostFundManagement.Domain.Attributes;
|
||||
|
||||
[AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = false)]
|
||||
public sealed class LogAttribute : Attribute;
|
||||
@@ -1,57 +0,0 @@
|
||||
using static PostFundManagement.Domain.Extensions.Constants;
|
||||
|
||||
namespace PostFundManagement.Domain.Configuration.Entities;
|
||||
|
||||
public sealed class Activity : IEntityTypeConfiguration<Domain.Entities.Activity>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<Domain.Entities.Activity> builder)
|
||||
{
|
||||
builder.ToTable(nameof(Domain.Entities.Activity).Pluralize());
|
||||
|
||||
builder.HasKey(pk => pk.Id);
|
||||
builder.Property(f => f.ProjectId).IsRequired();
|
||||
builder.Property(f => f.MilestoneId).IsRequired();
|
||||
builder.Property(f => f.CreatedBy).IsRequired();
|
||||
builder.Property(f => f.UpdatedBy).IsRequired(false);
|
||||
builder.Property(f => f.ApprovedBy).IsRequired(false);
|
||||
builder.Property(f => f.CreatedAt).IsRequired().HasDefaultValueSql("now()");
|
||||
builder.Property(f => f.UpdatedAt).IsRequired(false);
|
||||
builder.Property(f => f.PerformedAt).IsRequired(false);
|
||||
builder.Property(f => f.Category).IsRequired().HasMaxLength(LabelLength);
|
||||
builder.Property(f => f.Status).IsRequired().HasDefaultValueSql("1")
|
||||
.HasSentinel(ApprovalStatus.Pending);
|
||||
builder.Property(f => f.Amount).IsRequired().HasPrecision(18, 2);
|
||||
builder.Property(f => f.Title).IsRequired().HasMaxLength(LabelLength);
|
||||
builder.Property(f => f.Description).IsRequired().HasMaxLength(TextLength);
|
||||
|
||||
builder.HasOne(f => f.Project)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.ProjectId)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
builder.HasOne(f => f.Milestone)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.MilestoneId)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
builder.HasOne(f => f.Creator)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.CreatedBy)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
|
||||
builder.HasOne(f => f.Updator)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.UpdatedBy)
|
||||
.IsRequired(false)
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
|
||||
builder.HasOne(f => f.Approver)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.ApprovedBy)
|
||||
.IsRequired(false)
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
using static PostFundManagement.Domain.Extensions.Constants;
|
||||
|
||||
namespace PostFundManagement.Domain.Configuration.Entities;
|
||||
|
||||
public sealed class AuditLog : IEntityTypeConfiguration<Domain.Entities.AuditLog>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<Domain.Entities.AuditLog> builder)
|
||||
{
|
||||
builder.ToTable(nameof(Domain.Entities.AuditLog).Pluralize());
|
||||
|
||||
builder.HasKey(pk => pk.Id);
|
||||
builder.Property(f => f.EntityName).IsRequired().HasMaxLength(LabelLength);
|
||||
builder.Property(f => f.EntityId).IsRequired();
|
||||
builder.Property(f => f.Action).IsRequired().HasMaxLength(ShortLabelLength);
|
||||
builder.Property(f => f.Changes).IsRequired(false).HasColumnType("jsonb");
|
||||
builder.Property(f => f.PerformedBy).IsRequired();
|
||||
builder.Property(f => f.Timestamp).IsRequired().HasDefaultValueSql("now()");
|
||||
|
||||
builder.HasOne(f => f.Performer)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.PerformedBy)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
}
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
namespace PostFundManagement.Domain.Configuration.Entities;
|
||||
|
||||
public sealed class Award : IEntityTypeConfiguration<Domain.Entities.Award>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<Domain.Entities.Award> builder)
|
||||
{
|
||||
builder.ToTable(nameof(Domain.Entities.Award).Pluralize());
|
||||
|
||||
builder.HasKey(pk => pk.Id);
|
||||
builder.Property(f => f.OrganisationId).IsRequired();
|
||||
builder.Property(f => f.ProgrammeId).IsRequired();
|
||||
builder.Property(f => f.ProjectId).IsRequired(false);
|
||||
builder.Property(f => f.CreatedBy).IsRequired();
|
||||
builder.Property(f => f.UpdatedBy).IsRequired(false);
|
||||
builder.Property(f => f.ApprovedBy).IsRequired(false);
|
||||
builder.Property(f => f.CreatedAt).IsRequired().HasDefaultValueSql("now()");
|
||||
builder.Property(f => f.UpdatedAt).IsRequired(false);
|
||||
builder.Property(f => f.Status).IsRequired().HasConversion<int>().HasDefaultValueSql("1")
|
||||
.HasSentinel(ApprovalStatus.Pending);
|
||||
builder.Property(f => f.Amount).IsRequired().HasPrecision(18, 2);
|
||||
|
||||
builder.HasOne(f => f.Organisation)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.OrganisationId)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
builder.HasOne(f => f.Programme)
|
||||
.WithMany(f => f.Awards)
|
||||
.HasForeignKey(fk => fk.ProgrammeId)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
builder.HasOne(f => f.Project)
|
||||
.WithMany(f => f.Awards)
|
||||
.HasForeignKey(fk => fk.ProjectId)
|
||||
.IsRequired(false)
|
||||
.OnDelete(DeleteBehavior.SetNull);
|
||||
|
||||
builder.HasOne(f => f.Creator)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.CreatedBy)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
|
||||
builder.HasOne(f => f.Updator)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.UpdatedBy)
|
||||
.IsRequired(false)
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
|
||||
builder.HasOne(f => f.Approver)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.ApprovedBy)
|
||||
.IsRequired(false)
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
}
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
using static PostFundManagement.Domain.Extensions.Constants;
|
||||
|
||||
namespace PostFundManagement.Domain.Configuration.Entities;
|
||||
|
||||
public sealed class Beneficiary : IEntityTypeConfiguration<Domain.Entities.Beneficiary>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<Domain.Entities.Beneficiary> builder)
|
||||
{
|
||||
builder.ToTable(nameof(Domain.Entities.Beneficiary).Pluralize());
|
||||
|
||||
builder.HasKey(pk => pk.Id);
|
||||
builder.Property(f => f.ProjectId).IsRequired();
|
||||
builder.Property(f => f.CreatedBy).IsRequired();
|
||||
builder.Property(f => f.UserId).IsRequired();
|
||||
builder.Property(f => f.CreatedAt).IsRequired().HasDefaultValueSql("now()");
|
||||
builder.Property(f => f.Name).IsRequired().HasMaxLength(LabelLength);
|
||||
builder.Property(f => f.Category).IsRequired().HasMaxLength(ShortLabelLength);
|
||||
builder.Property(f => f.TargetCount).IsRequired();
|
||||
builder.Property(f => f.ReachedCount).IsRequired();
|
||||
builder.Property(f => f.Location).IsRequired();
|
||||
|
||||
builder.HasOne(f => f.Project)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.ProjectId)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
builder.HasOne(f => f.Creator)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.CreatedBy)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
|
||||
builder.HasOne(f => f.User)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.UserId)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
}
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
using static PostFundManagement.Domain.Extensions.Constants;
|
||||
|
||||
namespace PostFundManagement.Domain.Configuration.Entities;
|
||||
|
||||
public sealed class Budget : IEntityTypeConfiguration<Domain.Entities.Budget>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<Domain.Entities.Budget> builder)
|
||||
{
|
||||
builder.ToTable(nameof(Domain.Entities.Budget).Pluralize());
|
||||
|
||||
builder.HasKey(pk => pk.Id);
|
||||
builder.Property(f => f.ProjectId).IsRequired();
|
||||
builder.Property(f => f.CreatedBy).IsRequired();
|
||||
builder.Property(f => f.ApprovedBy).IsRequired(false);
|
||||
builder.Property(f => f.CreatedAt).IsRequired().HasDefaultValueSql("now()");
|
||||
builder.Property(f => f.UpdatedAt).IsRequired(false);
|
||||
builder.Property(f => f.Name).IsRequired().HasMaxLength(LabelLength);
|
||||
builder.Property(f => f.Amount).IsRequired().HasPrecision(18, 2);
|
||||
|
||||
builder.HasOne(f => f.Project)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.ProjectId)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
builder.HasOne(f => f.Creator)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.CreatedBy)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
|
||||
builder.HasOne(f => f.Approver)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.ApprovedBy)
|
||||
.IsRequired(false)
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
}
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
using static PostFundManagement.Domain.Extensions.Constants;
|
||||
|
||||
namespace PostFundManagement.Domain.Configuration.Entities;
|
||||
|
||||
public sealed class ChangeRequest : IEntityTypeConfiguration<Domain.Entities.ChangeRequest>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<Domain.Entities.ChangeRequest> builder)
|
||||
{
|
||||
builder.ToTable(nameof(Domain.Entities.ChangeRequest).Pluralize());
|
||||
|
||||
builder.HasKey(pk => pk.Id);
|
||||
builder.Property(f => f.ProjectId).IsRequired();
|
||||
builder.Property(f => f.CreatedBy).IsRequired();
|
||||
builder.Property(f => f.ApprovedBy).IsRequired(false);
|
||||
builder.Property(f => f.CreatedAt).IsRequired().HasDefaultValueSql("now()");
|
||||
builder.Property(f => f.UpdatedAt).IsRequired(false);
|
||||
builder.Property(f => f.Title).IsRequired().HasMaxLength(LabelLength);
|
||||
builder.Property(f => f.Justification).IsRequired().HasMaxLength(TextLength);
|
||||
builder.Property(f => f.RevisedBudget).IsRequired(false).HasPrecision(18, 2);
|
||||
builder.Property(f => f.RevisedEndedAt).IsRequired(false);
|
||||
builder.Property(f => f.Status).IsRequired().HasConversion<int>().HasDefaultValueSql("1")
|
||||
.HasSentinel(ApprovalStatus.Pending);
|
||||
|
||||
builder.HasOne(f => f.Project)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.ProjectId)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
builder.HasOne(f => f.Creator)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.CreatedBy)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
|
||||
builder.HasOne(f => f.Approver)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.ApprovedBy)
|
||||
.IsRequired(false)
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
}
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
using static PostFundManagement.Domain.Extensions.Constants;
|
||||
|
||||
namespace PostFundManagement.Domain.Configuration.Entities;
|
||||
|
||||
public sealed class ComplianceItem : IEntityTypeConfiguration<Domain.Entities.ComplianceItem>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<Domain.Entities.ComplianceItem> builder)
|
||||
{
|
||||
builder.ToTable(nameof(Domain.Entities.ComplianceItem).Pluralize());
|
||||
|
||||
builder.HasKey(pk => pk.Id);
|
||||
builder.Property(f => f.ProjectId).IsRequired();
|
||||
builder.Property(f => f.CreatedBy).IsRequired();
|
||||
builder.Property(f => f.VerifiedBy).IsRequired(false);
|
||||
builder.Property(f => f.CreatedAt).IsRequired().HasDefaultValueSql("now()");
|
||||
builder.Property(f => f.UpdatedAt).IsRequired(false);
|
||||
builder.Property(f => f.Title).IsRequired().HasMaxLength(LabelLength);
|
||||
builder.Property(f => f.Requirements).IsRequired().HasMaxLength(MediumTextLength);
|
||||
builder.Property(f => f.Status).IsRequired().HasConversion<int>().HasDefaultValueSql("1")
|
||||
.HasSentinel(ApprovalStatus.Pending);
|
||||
|
||||
builder.HasOne(f => f.Project)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.ProjectId)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
builder.HasOne(f => f.Creator)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.CreatedBy)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
|
||||
builder.HasOne(f => f.Verifier)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.VerifiedBy)
|
||||
.IsRequired(false)
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
namespace PostFundManagement.Domain.Configuration.Entities;
|
||||
|
||||
public sealed class Contract : IEntityTypeConfiguration<Domain.Entities.Contract>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<Domain.Entities.Contract> builder)
|
||||
{
|
||||
builder.ToTable(nameof(Domain.Entities.Contract).Pluralize());
|
||||
|
||||
builder.HasKey(pk => pk.Id);
|
||||
builder.HasIndex(f => f.AwardId).IsUnique();
|
||||
|
||||
builder.Property(f => f.AwardId).IsRequired();
|
||||
builder.Property(f => f.CreatedBy).IsRequired();
|
||||
builder.Property(f => f.CreatedAt).IsRequired().HasDefaultValueSql("now()");
|
||||
builder.Property(f => f.ExternalSignatureId).IsRequired(false);
|
||||
builder.Property(f => f.SignedDocumentUrl).IsRequired(false);
|
||||
builder.Property(f => f.EffectiveAt).IsRequired(false);
|
||||
builder.Property(f => f.ExpiresAt).IsRequired(false);
|
||||
builder.Property(f => f.TotalValue).IsRequired().HasPrecision(18, 2);
|
||||
builder.Property(f => f.Status).IsRequired().HasConversion<int>().HasDefaultValueSql("1")
|
||||
.HasSentinel(ContractStatus.Draft);
|
||||
|
||||
builder.HasOne(f => f.Award)
|
||||
.WithOne(f => f.Contract)
|
||||
.HasForeignKey<Domain.Entities.Contract>(fk => fk.AwardId)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
builder.HasOne(f => f.Creator)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.CreatedBy)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
}
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
namespace PostFundManagement.Domain.Configuration.Entities;
|
||||
|
||||
public sealed class Disbursement : IEntityTypeConfiguration<Domain.Entities.Disbursement>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<Domain.Entities.Disbursement> builder)
|
||||
{
|
||||
builder.ToTable(nameof(Domain.Entities.Disbursement).Pluralize());
|
||||
|
||||
builder.HasKey(pk => pk.Id);
|
||||
builder.Property(f => f.ProjectId).IsRequired();
|
||||
builder.Property(f => f.MilestoneId).IsRequired(false);
|
||||
builder.Property(f => f.CreatedBy).IsRequired();
|
||||
builder.Property(f => f.UpdatedBy).IsRequired(false);
|
||||
builder.Property(f => f.CreatedAt).IsRequired().HasDefaultValueSql("now()");
|
||||
builder.Property(f => f.UpdatedAt).IsRequired(false);
|
||||
builder.Property(f => f.Amount).IsRequired().HasPrecision(18, 2);
|
||||
builder.Property(f => f.Status).IsRequired().HasConversion<int>().HasDefaultValueSql("1")
|
||||
.HasSentinel(ApprovalStatus.Pending);
|
||||
|
||||
builder.HasOne(f => f.Project)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.ProjectId)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
builder.HasOne(f => f.Milestone)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.MilestoneId)
|
||||
.IsRequired(false)
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
builder.HasOne(f => f.Creator)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.CreatedBy)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
|
||||
builder.HasOne(f => f.Updator)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.UpdatedBy)
|
||||
.IsRequired(false)
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
}
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
namespace PostFundManagement.Domain.Configuration.Entities;
|
||||
|
||||
public sealed class Evidence : IEntityTypeConfiguration<Domain.Entities.Evidence>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<Domain.Entities.Evidence> builder)
|
||||
{
|
||||
builder.ToTable(nameof(Domain.Entities.Evidence).Pluralize());
|
||||
|
||||
builder.HasKey(f => f.Id);
|
||||
builder.Property(f => f.ProjectId).IsRequired();
|
||||
builder.Property(f => f.MilestoneId).IsRequired();
|
||||
builder.Property(f => f.IndicatorId).IsRequired();
|
||||
builder.Property(f => f.ActivityId).IsRequired();
|
||||
builder.Property(f => f.CreatedBy).IsRequired();
|
||||
builder.Property(f => f.UpdatedBy).IsRequired();
|
||||
builder.Property(f => f.CreatedAt).IsRequired().HasDefaultValueSql("now()");
|
||||
builder.Property(f => f.UpdatedAt).IsRequired(false);
|
||||
builder.Property(f => f.Version).IsRequired().HasDefaultValue(1);
|
||||
builder.Property(f => f.DocumentUrl).IsRequired();
|
||||
builder.Property(f => f.Status).IsRequired().HasConversion<int>().HasDefaultValueSql("1")
|
||||
.HasSentinel(ApprovalStatus.Pending);
|
||||
builder.Property(f => f.Type).IsRequired().HasConversion<int>().HasDefaultValueSql("9")
|
||||
.HasSentinel(EvidenceType.ProcurementDocument);
|
||||
|
||||
builder.HasOne(f => f.Project)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.ProjectId)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
builder.HasOne(f => f.Milestone)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.MilestoneId)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
builder.HasOne(f => f.Indicator)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.IndicatorId)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
builder.HasOne(f => f.Activity)
|
||||
.WithMany(f => f.Evidences)
|
||||
.HasForeignKey(fk => fk.ActivityId)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
builder.HasOne(f => f.Creator)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.CreatedBy)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
|
||||
builder.HasOne(f => f.Updator)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.UpdatedBy)
|
||||
.IsRequired(false)
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
using static PostFundManagement.Domain.Extensions.Constants;
|
||||
|
||||
namespace PostFundManagement.Domain.Configuration.Entities;
|
||||
|
||||
public sealed class Indicator : IEntityTypeConfiguration<Domain.Entities.Indicator>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<Domain.Entities.Indicator> builder)
|
||||
{
|
||||
builder.ToTable(nameof(Domain.Entities.Indicator).Pluralize());
|
||||
|
||||
builder.HasKey(pk => pk.Id);
|
||||
builder.Property(f => f.ProjectId).IsRequired();
|
||||
builder.Property(f => f.CreatedBy).IsRequired();
|
||||
builder.Property(f => f.CreatedAt).IsRequired().HasDefaultValueSql("now()");
|
||||
builder.Property(f => f.Name).IsRequired().HasMaxLength(LabelLength);
|
||||
builder.Property(f => f.UnitOfMeasure).IsRequired().HasConversion<int>().HasDefaultValueSql("2");
|
||||
builder.Property(f => f.BaselineAmount).IsRequired().HasPrecision(18, 2);
|
||||
builder.Property(f => f.TargetAmount).IsRequired().HasPrecision(18, 2);
|
||||
builder.Property(f => f.ActualAmount).IsRequired().HasPrecision(18, 2);
|
||||
|
||||
builder.HasOne(f => f.Project)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.ProjectId)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
builder.HasOne(f => f.Creator)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.CreatedBy)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
using static PostFundManagement.Domain.Extensions.Constants;
|
||||
|
||||
namespace PostFundManagement.Domain.Configuration.Entities;
|
||||
|
||||
public sealed class Instrument : IEntityTypeConfiguration<Domain.Entities.Instrument>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<Domain.Entities.Instrument> builder)
|
||||
{
|
||||
builder.ToTable(nameof(Domain.Entities.Instrument).Pluralize());
|
||||
|
||||
builder.HasKey(pk => pk.Id);
|
||||
builder.Property(f => f.ProgrammeId).IsRequired();
|
||||
builder.Property(f => f.Code).IsRequired().HasMaxLength(ShortLabelLength);
|
||||
builder.Property(f => f.Name).IsRequired().HasMaxLength(LabelLength);
|
||||
builder.Property(f => f.Description).IsRequired(false).HasMaxLength(TextLength);
|
||||
builder.Property(f => f.Status).IsRequired().HasConversion<int>().HasDefaultValueSql("2")
|
||||
.HasSentinel(ActivityStatus.Inactive);
|
||||
builder.Property(f => f.CreatedBy).IsRequired();
|
||||
builder.Property(f => f.CreatedAt).IsRequired().HasDefaultValueSql("now()");
|
||||
|
||||
builder.HasOne(f => f.Programme)
|
||||
.WithMany(f => f.Instruments)
|
||||
.HasForeignKey(fk => fk.ProgrammeId)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
builder.HasOne(f => f.Creator)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.CreatedBy)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
}
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
|
||||
namespace PostFundManagement.Domain.Configuration.Entities;
|
||||
|
||||
public sealed class Invite : IEntityTypeConfiguration<Domain.Entities.Invite>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<Domain.Entities.Invite> builder)
|
||||
{
|
||||
builder.ToTable(nameof(Domain.Entities.Invite).Pluralize());
|
||||
|
||||
builder.HasKey(pk => pk.Id);
|
||||
builder.Property(f => f.OrganisationId).IsRequired();
|
||||
builder.Property(f => f.InvitedOrganisationId).IsRequired();
|
||||
builder.Property(f => f.AwardId).IsRequired();
|
||||
builder.Property(f => f.ContractId).IsRequired();
|
||||
builder.Property(f => f.Recipient).IsRequired();
|
||||
builder.Property(f => f.CreatedBy).IsRequired();
|
||||
builder.Property(f => f.UpdatedBy).IsRequired(false);
|
||||
builder.Property(f => f.CreatedAt).IsRequired().HasDefaultValueSql("now()");
|
||||
builder.Property(f => f.UpdatedAt).IsRequired(false);
|
||||
|
||||
builder.HasOne(f => f.Organisation)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.OrganisationId)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
builder.HasOne(f => f.InvitedOrganisation)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.InvitedOrganisationId)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
builder.HasOne(f => f.Award)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.AwardId)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
builder.HasOne(f => f.Contract)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.ContractId)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
builder.HasOne(f => f.RecipientUser)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.Recipient)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
using static PostFundManagement.Domain.Extensions.Constants;
|
||||
|
||||
namespace PostFundManagement.Domain.Configuration.Entities;
|
||||
|
||||
public sealed class Issue : IEntityTypeConfiguration<Domain.Entities.Issue>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<Domain.Entities.Issue> builder)
|
||||
{
|
||||
builder.ToTable(nameof(Domain.Entities.Issue).Pluralize());
|
||||
|
||||
builder.HasKey(pk => pk.Id);
|
||||
builder.Property(f => f.ProjectId).IsRequired();
|
||||
builder.Property(f => f.CreatedBy).IsRequired();
|
||||
builder.Property(f => f.CreatedAt).IsRequired().HasDefaultValueSql("now()");
|
||||
builder.Property(f => f.ResolvedAt).IsRequired(false);
|
||||
builder.Property(f => f.AssignedTo).IsRequired(false);
|
||||
builder.Property(f => f.Title).IsRequired().HasMaxLength(LabelLength);
|
||||
builder.Property(f => f.Description).IsRequired().HasMaxLength(TextLength);
|
||||
builder.Property(f => f.Priority).IsRequired().HasConversion<int>().HasDefaultValueSql("1")
|
||||
.HasSentinel(Priority.Low);
|
||||
builder.Property(f => f.Status).IsRequired().HasConversion<int>().HasDefaultValueSql("1")
|
||||
.HasSentinel(ActivityStatus.Active);
|
||||
builder.Property(f => f.Resolution).IsRequired();
|
||||
|
||||
builder.HasOne(f => f.Project)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.ProjectId)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
builder.HasOne(f => f.Creator)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.CreatedBy)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
|
||||
builder.HasOne(f => f.Assignee)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.AssignedTo)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.SetNull);
|
||||
}
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
using static PostFundManagement.Domain.Extensions.Constants;
|
||||
|
||||
namespace PostFundManagement.Domain.Configuration.Entities;
|
||||
|
||||
public sealed class Milestone : IEntityTypeConfiguration<Domain.Entities.Milestone>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<Domain.Entities.Milestone> builder)
|
||||
{
|
||||
builder.ToTable(nameof(Domain.Entities.Milestone).Pluralize());
|
||||
|
||||
builder.HasKey(pk => pk.Id);
|
||||
builder.Property(f => f.ProjectId).IsRequired();
|
||||
builder.Property(f => f.CreatedBy).IsRequired();
|
||||
builder.Property(f => f.UpdatedBy).IsRequired(false);
|
||||
builder.Property(f => f.CreatedAt).IsRequired().HasDefaultValueSql("now()");
|
||||
builder.Property(f => f.UpdatedAt).IsRequired(false);
|
||||
builder.Property(f => f.DueAt).IsRequired();
|
||||
builder.Property(f => f.Name).IsRequired().HasMaxLength(LabelLength);
|
||||
builder.Property(f => f.Status).IsRequired().HasConversion<int>().HasDefaultValueSql("1")
|
||||
.HasSentinel(ApprovalStatus.Pending);
|
||||
builder.Property(f => f.Priority).IsRequired().HasConversion<int>().HasDefaultValueSql("1")
|
||||
.HasSentinel(Priority.Low);
|
||||
|
||||
builder.HasOne(f => f.Project)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.ProjectId)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
builder.HasOne(f => f.Creator)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.CreatedBy)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
|
||||
builder.HasOne(f => f.Updator)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.UpdatedBy)
|
||||
.IsRequired(false)
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
}
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
using static PostFundManagement.Domain.Extensions.Constants;
|
||||
|
||||
namespace PostFundManagement.Domain.Configuration.Entities;
|
||||
|
||||
public sealed class Notification : IEntityTypeConfiguration<Domain.Entities.Notification>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<Domain.Entities.Notification> builder)
|
||||
{
|
||||
builder.ToTable(nameof(Domain.Entities.Notification).Pluralize());
|
||||
|
||||
builder.HasKey(pk => pk.Id);
|
||||
builder.Property(f => f.CreatedAt).IsRequired().HasDefaultValueSql("now()");
|
||||
builder.Property(f => f.UpdatedAt).IsRequired(false);
|
||||
builder.Property(f => f.SentAt).IsRequired(false);
|
||||
builder.Property(f => f.Recipient).IsRequired();
|
||||
builder.Property(f => f.OrganisationId).IsRequired();
|
||||
builder.Property(f => f.Platform).IsRequired().HasConversion<int>().HasDefaultValueSql("1")
|
||||
.HasSentinel(NotificationPlatform.Email);
|
||||
builder.Property(f => f.Status).IsRequired().HasConversion<int>().HasDefaultValueSql("1")
|
||||
.HasSentinel(NotificationStatus.Pending);
|
||||
builder.Property(f => f.Subject).IsRequired(false).HasMaxLength(LabelLength);
|
||||
builder.Property(f => f.Message).IsRequired().HasMaxLength(LargeTextLength);
|
||||
builder.Property(f => f.Destination).IsRequired().HasMaxLength(LabelLength);
|
||||
builder.Property(f => f.Error).IsRequired(false);
|
||||
|
||||
builder.HasOne(f => f.Organisation)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.OrganisationId)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
builder.HasOne(f => f.RecipientUser)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.Recipient)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
using static PostFundManagement.Domain.Extensions.Constants;
|
||||
|
||||
namespace PostFundManagement.Domain.Configuration.Entities;
|
||||
|
||||
public sealed class Organisation : IEntityTypeConfiguration<Domain.Entities.Organisation>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<Domain.Entities.Organisation> builder)
|
||||
{
|
||||
builder.ToTable(nameof(Domain.Entities.Organisation).Pluralize());
|
||||
|
||||
builder.HasKey(pk => pk.Id);
|
||||
builder.Property(f => f.CreatedBy).IsRequired();
|
||||
builder.Property(f => f.CreatedAt).IsRequired().HasDefaultValueSql("now()");
|
||||
builder.Property(f => f.RegistrationNo).IsRequired().HasMaxLength(LabelLength);
|
||||
builder.Property(f => f.Name).IsRequired().HasMaxLength(LabelLength);
|
||||
builder.Property(f => f.Email).IsRequired().HasMaxLength(LabelLength);
|
||||
builder.Property(f => f.Type).IsRequired().HasConversion<int>().HasDefaultValueSql("5")
|
||||
.HasSentinel(OrganisationType.PrivateLimitedCompany);
|
||||
builder.Property(f => f.Status).IsRequired().HasConversion<int>().HasDefaultValueSql("1")
|
||||
.HasSentinel(ActivityStatus.Active);
|
||||
|
||||
builder.HasOne(f => f.Creator)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.CreatedBy)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
using static PostFundManagement.Domain.Extensions.Constants;
|
||||
|
||||
namespace PostFundManagement.Domain.Configuration.Entities;
|
||||
|
||||
public sealed class Outcome : IEntityTypeConfiguration<Domain.Entities.Outcome>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<Domain.Entities.Outcome> builder)
|
||||
{
|
||||
builder.ToTable(nameof(Domain.Entities.Outcome).Pluralize());
|
||||
|
||||
builder.HasKey(pk => pk.Id);
|
||||
builder.Property(f => f.BeneficiaryId).IsRequired();
|
||||
builder.Property(f => f.CreatedBy).IsRequired();
|
||||
builder.Property(f => f.CreatedAt).IsRequired().HasDefaultValueSql("now()");
|
||||
builder.Property(f => f.Name).IsRequired().HasMaxLength(LabelLength);
|
||||
builder.Property(f => f.Description).IsRequired().HasMaxLength(TextLength);
|
||||
|
||||
builder.HasOne(f => f.Beneficiary)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.BeneficiaryId)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
builder.HasOne(f => f.Creator)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.CreatedBy)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
using static PostFundManagement.Domain.Extensions.Constants;
|
||||
|
||||
namespace PostFundManagement.Domain.Configuration.Entities;
|
||||
|
||||
public sealed class Portfolio : IEntityTypeConfiguration<Domain.Entities.Portfolio>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<Domain.Entities.Portfolio> builder)
|
||||
{
|
||||
builder.ToTable(nameof(Domain.Entities.Portfolio).Pluralize());
|
||||
|
||||
builder.HasKey(pk => pk.Id);
|
||||
builder.Property(f => f.OrganisationId).IsRequired();
|
||||
builder.Property(f => f.CreatedBy).IsRequired();
|
||||
builder.Property(f => f.OwnedBy).IsRequired();
|
||||
builder.Property(f => f.CreatedAt).IsRequired().HasDefaultValueSql("now()");
|
||||
builder.Property(f => f.Name).IsRequired().HasMaxLength(LabelLength);
|
||||
builder.Property(f => f.Description).IsRequired(false).HasMaxLength(TextLength);
|
||||
|
||||
builder.HasOne(f => f.Organisation)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.OrganisationId)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
builder.HasOne(f => f.Creator)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.CreatedBy)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
|
||||
builder.HasOne(f => f.Owner)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.OwnedBy)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
}
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
using static PostFundManagement.Domain.Extensions.Constants;
|
||||
|
||||
namespace PostFundManagement.Domain.Configuration.Entities;
|
||||
|
||||
public sealed class Programme : IEntityTypeConfiguration<Domain.Entities.Programme>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<Domain.Entities.Programme> builder)
|
||||
{
|
||||
builder.ToTable(nameof(Domain.Entities.Programme).Pluralize());
|
||||
|
||||
builder.HasKey(pk => pk.Id);
|
||||
builder.Property(f => f.PortfolioId).IsRequired();
|
||||
builder.Property(f => f.OwnedBy).IsRequired();
|
||||
builder.Property(f => f.CreatedBy).IsRequired();
|
||||
builder.Property(f => f.UpdatedBy).IsRequired(false);
|
||||
builder.Property(f => f.CreatedAt).IsRequired().HasDefaultValueSql("now()");
|
||||
builder.Property(f => f.UpdatedAt).IsRequired(false);
|
||||
builder.Property(f => f.Name).IsRequired().HasMaxLength(LabelLength);
|
||||
builder.Property(f => f.Status).IsRequired().HasConversion<int>().HasDefaultValueSql("1")
|
||||
.HasSentinel(ApprovalStatus.Pending);
|
||||
|
||||
builder.HasOne(f => f.Portfolio)
|
||||
.WithMany(f => f.Programmes)
|
||||
.HasForeignKey(fk => fk.PortfolioId)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
|
||||
builder.HasOne(f => f.Creator)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.CreatedBy)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
|
||||
builder.HasOne(f => f.Owner)
|
||||
.WithMany()
|
||||
.IsRequired()
|
||||
.HasForeignKey(fk => fk.OwnedBy)
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
}
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
using static PostFundManagement.Domain.Extensions.Constants;
|
||||
|
||||
namespace PostFundManagement.Domain.Configuration.Entities;
|
||||
|
||||
public sealed class Project : IEntityTypeConfiguration<Domain.Entities.Project>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<Domain.Entities.Project> builder)
|
||||
{
|
||||
builder.ToTable(nameof(Domain.Entities.Project).Pluralize());
|
||||
|
||||
builder.HasKey(pk => pk.Id);
|
||||
builder.Property(f => f.ProgrammeId).IsRequired();
|
||||
builder.Property(f => f.CreatedBy).IsRequired();
|
||||
builder.Property(f => f.UpdatedBy).IsRequired(false);
|
||||
builder.Property(f => f.CreatedAt).IsRequired().HasDefaultValueSql("now()");
|
||||
builder.Property(f => f.UpdatedAt).IsRequired(false);
|
||||
builder.Property(f => f.StartedAt).IsRequired(false);
|
||||
builder.Property(f => f.EndedAt).IsRequired(false);
|
||||
builder.Property(f => f.Name).IsRequired().HasMaxLength(LabelLength);
|
||||
builder.Property(f => f.Description).IsRequired().HasMaxLength(TextLength);
|
||||
builder.Property(f => f.Sector).IsRequired().HasConversion<int>().HasDefaultValueSql("11")
|
||||
.HasSentinel(IndustrySector.InformationCommunicationTechnology);
|
||||
builder.Property(f => f.ProjectType).IsRequired().HasConversion<int>().HasDefaultValueSql("10")
|
||||
.HasSentinel(ProjectType.Innovation);
|
||||
builder.Property(f => f.Status).IsRequired().HasConversion<int>().HasDefaultValueSql("1")
|
||||
.HasSentinel(ApprovalStatus.Pending);
|
||||
|
||||
builder.HasOne(f => f.Programme)
|
||||
.WithMany(f => f.Projects)
|
||||
.HasForeignKey(fk => fk.ProgrammeId)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
builder.HasOne(f => f.Creator)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.CreatedBy)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
|
||||
builder.HasOne(f => f.Updator)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.UpdatedBy)
|
||||
.IsRequired(false)
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
using static PostFundManagement.Domain.Extensions.Constants;
|
||||
|
||||
namespace PostFundManagement.Domain.Configuration.Entities;
|
||||
|
||||
public sealed class Risk : IEntityTypeConfiguration<Domain.Entities.Risk>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<Domain.Entities.Risk> builder)
|
||||
{
|
||||
builder.ToTable(nameof(Domain.Entities.Risk).Pluralize());
|
||||
|
||||
builder.HasKey(pk => pk.Id);
|
||||
builder.Property(f => f.ProjectId).IsRequired();
|
||||
builder.Property(f => f.CreatedBy).IsRequired();
|
||||
builder.Property(f => f.CreatedAt).IsRequired().HasDefaultValueSql("now()");
|
||||
builder.Property(f => f.Likelihood).IsRequired().HasConversion<int>().HasDefaultValueSql("3")
|
||||
.HasSentinel(RiskLikelihood.Possible);
|
||||
builder.Property(f => f.Impact).IsRequired().HasConversion<int>().HasDefaultValueSql("1")
|
||||
.HasSentinel(RiskImpact.Negligible);
|
||||
builder.Property(f => f.Name).IsRequired().HasMaxLength(LabelLength);
|
||||
builder.Property(f => f.Description).IsRequired().HasMaxLength(TextLength);
|
||||
|
||||
builder.HasOne(f => f.Project)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.ProjectId)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
builder.HasOne(f => f.Creator)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.CreatedBy)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
}
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
using static PostFundManagement.Domain.Extensions.Constants;
|
||||
|
||||
namespace PostFundManagement.Domain.Configuration.Entities;
|
||||
|
||||
public sealed class Rule : IEntityTypeConfiguration<Domain.Entities.Rule>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<Domain.Entities.Rule> builder)
|
||||
{
|
||||
builder.ToTable(nameof(Domain.Entities.Rule).Pluralize());
|
||||
|
||||
builder.HasKey(fk => fk.Id);
|
||||
builder.Property(f => f.ProgrammeId).IsRequired();
|
||||
builder.Property(f => f.CreatedBy).IsRequired();
|
||||
builder.Property(f => f.UpdatedBy).IsRequired(false);
|
||||
builder.Property(f => f.CreatedAt).IsRequired().HasDefaultValueSql("now()");
|
||||
builder.Property(f => f.UpdatedAt).IsRequired(false);
|
||||
builder.Property(f => f.Name).IsRequired().HasMaxLength(LabelLength);
|
||||
builder.Property(f => f.Version).IsRequired().HasDefaultValue(1);
|
||||
builder.Property(f => f.Status).IsRequired().HasConversion<int>().HasDefaultValueSql("2")
|
||||
.HasSentinel(ActivityStatus.Inactive);
|
||||
|
||||
builder.HasOne(f => f.Programme)
|
||||
.WithMany(f => f.Rules)
|
||||
.HasForeignKey(fk => fk.ProgrammeId)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
|
||||
builder.HasOne(f => f.Creator)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.CreatedBy)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
|
||||
builder.HasOne(f => f.Updator)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.UpdatedBy)
|
||||
.IsRequired(false)
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
using static PostFundManagement.Domain.Extensions.Constants;
|
||||
|
||||
namespace PostFundManagement.Domain.Configuration.Entities;
|
||||
|
||||
public sealed class SiteVisit : IEntityTypeConfiguration<Domain.Entities.SiteVisit>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<Domain.Entities.SiteVisit> builder)
|
||||
{
|
||||
builder.ToTable(nameof(Domain.Entities.SiteVisit).Pluralize());
|
||||
|
||||
builder.HasKey(pk => pk.Id);
|
||||
builder.Property(f => f.ProjectId).IsRequired();
|
||||
builder.Property(f => f.CreatedBy).IsRequired();
|
||||
builder.Property(f => f.CreatedAt).IsRequired().HasDefaultValueSql("now()");
|
||||
builder.Property(f => f.VisitedAt).IsRequired();
|
||||
builder.Property(f => f.InspectorName).IsRequired();
|
||||
builder.Property(f => f.Findings).IsRequired(false).HasMaxLength(LargeTextLength);
|
||||
builder.Property(f => f.Status).IsRequired().HasConversion<int>().HasDefaultValueSql("1")
|
||||
.HasSentinel(ApprovalStatus.Pending);
|
||||
|
||||
builder.HasOne(f => f.Project)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.ProjectId)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
builder.HasOne(f => f.Creator)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.CreatedBy)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
using static PostFundManagement.Domain.Extensions.Constants;
|
||||
|
||||
namespace PostFundManagement.Domain.Configuration.Entities;
|
||||
|
||||
public sealed class User : IEntityTypeConfiguration<Domain.Entities.User>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<Domain.Entities.User> builder)
|
||||
{
|
||||
builder.ToTable(nameof(Domain.Entities.User).Pluralize());
|
||||
|
||||
builder.HasKey(pk => pk.Id);
|
||||
builder.Property(f => f.Email).IsRequired().HasMaxLength(LabelLength);
|
||||
builder.Property(f => f.Status).IsRequired().HasConversion<int>().HasDefaultValueSql("2")
|
||||
.HasSentinel(ActivityStatus.Inactive);
|
||||
builder.Property(f => f.LastLoginAt).IsRequired(false);
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,13 @@
|
||||
using PostFundManagement.Domain.Abstractions;
|
||||
using static PostFundManagement.Domain.Extensions.Constants;
|
||||
|
||||
namespace PostFundManagement.Domain.Entities;
|
||||
|
||||
[EntityTypeConfiguration<Configuration.Entities.Activity, Activity>]
|
||||
public class Activity : Models.Activity
|
||||
[EntityTypeConfiguration<ActivityConfiguration, Activity>]
|
||||
public class Activity : Models.Activity, ITenantEntity
|
||||
{
|
||||
public virtual Tenant? Tenant { get; set; }
|
||||
|
||||
public virtual User? Creator { get; set; }
|
||||
|
||||
public virtual User? Updator { get; set; }
|
||||
@@ -15,3 +20,64 @@ public class Activity : Models.Activity
|
||||
|
||||
public virtual ICollection<Evidence> Evidences { get; set; } = [];
|
||||
}
|
||||
|
||||
public sealed class ActivityConfiguration : IEntityTypeConfiguration<Activity>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<Activity> builder)
|
||||
{
|
||||
builder.ToTable(nameof(Activity).Pluralize());
|
||||
|
||||
builder.HasKey(pk => pk.Id);
|
||||
builder.Property(f => f.ProjectId).IsRequired();
|
||||
builder.Property(f => f.TenantId).IsRequired();
|
||||
builder.Property(f => f.MilestoneId).IsRequired();
|
||||
builder.Property(f => f.CreatedBy).IsRequired();
|
||||
builder.Property(f => f.UpdatedBy).IsRequired(false);
|
||||
builder.Property(f => f.ApprovedBy).IsRequired(false);
|
||||
builder.Property(f => f.CreatedAt).IsRequired().HasDefaultValueSql("now()");
|
||||
builder.Property(f => f.UpdatedAt).IsRequired(false);
|
||||
builder.Property(f => f.PerformedAt).IsRequired(false);
|
||||
builder.Property(f => f.Category).IsRequired().HasMaxLength(LabelLength);
|
||||
builder.Property(f => f.Status).IsRequired().HasDefaultValueSql("1")
|
||||
.HasSentinel(ApprovalStatus.Pending);
|
||||
builder.Property(f => f.Amount).IsRequired().HasPrecision(18, 2);
|
||||
builder.Property(f => f.Title).IsRequired().HasMaxLength(LabelLength);
|
||||
builder.Property(f => f.Description).IsRequired().HasMaxLength(TextLength);
|
||||
|
||||
builder.HasOne(f => f.Tenant)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.TenantId)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
|
||||
builder.HasOne(f => f.Project)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.ProjectId)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
builder.HasOne(f => f.Milestone)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.MilestoneId)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
builder.HasOne(f => f.Creator)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.CreatedBy)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
|
||||
builder.HasOne(f => f.Updator)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.UpdatedBy)
|
||||
.IsRequired(false)
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
|
||||
builder.HasOne(f => f.Approver)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.ApprovedBy)
|
||||
.IsRequired(false)
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,23 @@
|
||||
using static PostFundManagement.Domain.Extensions.Constants;
|
||||
|
||||
namespace PostFundManagement.Domain.Entities;
|
||||
|
||||
[EntityTypeConfiguration<Configuration.Entities.AuditLog, AuditLog>]
|
||||
public class AuditLog : Models.AuditLog
|
||||
[EntityTypeConfiguration<AuditLogConfiguration, AuditLog>]
|
||||
public sealed class AuditLog : Models.AuditLog;
|
||||
|
||||
public sealed class AuditLogConfiguration : IEntityTypeConfiguration<AuditLog>
|
||||
{
|
||||
public virtual User? Performer { get; set; }
|
||||
public void Configure(EntityTypeBuilder<AuditLog> builder)
|
||||
{
|
||||
builder.ToTable(nameof(AuditLog).Pluralize());
|
||||
|
||||
builder.HasKey(pk => pk.Id);
|
||||
builder.Property(f => f.TenantId).IsRequired(false);
|
||||
builder.Property(f => f.EntityName).IsRequired().HasMaxLength(LabelLength);
|
||||
builder.Property(f => f.EntityId).IsRequired();
|
||||
builder.Property(f => f.Action).IsRequired().HasMaxLength(ShortLabelLength);
|
||||
builder.Property(f => f.Changes).IsRequired(false);
|
||||
builder.Property(f => f.PerformedBy).IsRequired();
|
||||
builder.Property(f => f.Timestamp).IsRequired().HasDefaultValueSql("now()");
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,9 @@
|
||||
using PostFundManagement.Domain.Abstractions;
|
||||
|
||||
namespace PostFundManagement.Domain.Entities;
|
||||
|
||||
[EntityTypeConfiguration<Configuration.Entities.Award, Award>]
|
||||
public class Award : Models.Award
|
||||
[EntityTypeConfiguration<AwardConfiguration, Award>]
|
||||
public class Award : Models.Award, ITenantEntity
|
||||
{
|
||||
public virtual User? Creator { get; set; }
|
||||
|
||||
@@ -9,6 +11,8 @@ public class Award : Models.Award
|
||||
|
||||
public virtual User? Approver { get; set; }
|
||||
|
||||
public virtual Tenant? Tenant { get; set; }
|
||||
|
||||
public virtual Organisation? Organisation { get; set; }
|
||||
|
||||
public virtual Programme? Programme { get; set; }
|
||||
@@ -17,3 +21,67 @@ public class Award : Models.Award
|
||||
|
||||
public virtual Contract? Contract { get; set; }
|
||||
}
|
||||
|
||||
public sealed class AwardConfiguration : IEntityTypeConfiguration<Award>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<Award> builder)
|
||||
{
|
||||
builder.ToTable(nameof(Award).Pluralize());
|
||||
|
||||
builder.HasKey(pk => pk.Id);
|
||||
builder.Property(f => f.OrganisationId).IsRequired();
|
||||
builder.Property(f => f.ProgrammeId).IsRequired();
|
||||
builder.Property(f => f.TenantId).IsRequired();
|
||||
builder.Property(f => f.ProjectId).IsRequired(false);
|
||||
builder.Property(f => f.CreatedBy).IsRequired();
|
||||
builder.Property(f => f.UpdatedBy).IsRequired(false);
|
||||
builder.Property(f => f.ApprovedBy).IsRequired(false);
|
||||
builder.Property(f => f.CreatedAt).IsRequired().HasDefaultValueSql("now()");
|
||||
builder.Property(f => f.UpdatedAt).IsRequired(false);
|
||||
builder.Property(f => f.Status).IsRequired().HasConversion<int>().HasDefaultValueSql("1")
|
||||
.HasSentinel(ApprovalStatus.Pending);
|
||||
builder.Property(f => f.Amount).IsRequired().HasPrecision(18, 2);
|
||||
|
||||
builder.HasOne(f => f.Tenant)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.TenantId)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
builder.HasOne(f => f.Organisation)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.OrganisationId)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
builder.HasOne(f => f.Programme)
|
||||
.WithMany(f => f.Awards)
|
||||
.HasForeignKey(fk => fk.ProgrammeId)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
builder.HasOne(f => f.Project)
|
||||
.WithMany(f => f.Awards)
|
||||
.HasForeignKey(fk => fk.ProjectId)
|
||||
.IsRequired(false)
|
||||
.OnDelete(DeleteBehavior.SetNull);
|
||||
|
||||
builder.HasOne(f => f.Creator)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.CreatedBy)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
|
||||
builder.HasOne(f => f.Updator)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.UpdatedBy)
|
||||
.IsRequired(false)
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
|
||||
builder.HasOne(f => f.Approver)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.ApprovedBy)
|
||||
.IsRequired(false)
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,62 @@
|
||||
using PostFundManagement.Domain.Abstractions;
|
||||
using static PostFundManagement.Domain.Extensions.Constants;
|
||||
|
||||
namespace PostFundManagement.Domain.Entities;
|
||||
|
||||
[EntityTypeConfiguration<Configuration.Entities.Beneficiary, Beneficiary>]
|
||||
public class Beneficiary : Models.Beneficiary
|
||||
[EntityTypeConfiguration<BeneficiaryConfiguration, Beneficiary>]
|
||||
public class Beneficiary : Models.Beneficiary, ITenantEntity
|
||||
{
|
||||
public virtual Tenant? Tenant { get; set; }
|
||||
|
||||
public virtual Project? Project { get; set; }
|
||||
|
||||
[ForeignKey(nameof(CreatedBy))]
|
||||
public virtual User? Creator { get; set; }
|
||||
|
||||
[ForeignKey(nameof(UserId))]
|
||||
public virtual User? User { get; set; }
|
||||
}
|
||||
|
||||
public sealed class BeneficiaryConfiguration : IEntityTypeConfiguration<Beneficiary>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<Beneficiary> builder)
|
||||
{
|
||||
builder.ToTable(nameof(Beneficiary).Pluralize());
|
||||
|
||||
builder.HasKey(pk => pk.Id);
|
||||
builder.Property(f => f.TenantId).IsRequired();
|
||||
builder.Property(f => f.ProjectId).IsRequired();
|
||||
builder.Property(f => f.CreatedBy).IsRequired();
|
||||
builder.Property(f => f.UserId).IsRequired();
|
||||
builder.Property(f => f.CreatedAt).IsRequired().HasDefaultValueSql("now()");
|
||||
builder.Property(f => f.Name).IsRequired().HasMaxLength(LabelLength);
|
||||
builder.Property(f => f.Category).IsRequired().HasMaxLength(ShortLabelLength);
|
||||
builder.Property(f => f.TargetCount).IsRequired();
|
||||
builder.Property(f => f.ReachedCount).IsRequired();
|
||||
builder.Property(f => f.Location).IsRequired();
|
||||
|
||||
builder.HasOne(f => f.Tenant)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.TenantId)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
|
||||
builder.HasOne(f => f.Project)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.ProjectId)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
builder.HasOne(f => f.Creator)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.CreatedBy)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
|
||||
builder.HasOne(f => f.User)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.UserId)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,58 @@
|
||||
using PostFundManagement.Domain.Abstractions;
|
||||
using static PostFundManagement.Domain.Extensions.Constants;
|
||||
|
||||
namespace PostFundManagement.Domain.Entities;
|
||||
|
||||
[EntityTypeConfiguration<Configuration.Entities.Budget, Budget>]
|
||||
public class Budget : Models.Budget
|
||||
[EntityTypeConfiguration<BudgetConfiguration, Budget>]
|
||||
public class Budget : Models.Budget, ITenantEntity
|
||||
{
|
||||
public virtual Tenant? Tenant { get; set; }
|
||||
|
||||
public virtual Project? Project { get; set; }
|
||||
|
||||
public virtual User? Creator { get; set; }
|
||||
|
||||
public virtual User? Approver { get; set; }
|
||||
}
|
||||
|
||||
public sealed class BudgetConfiguration : IEntityTypeConfiguration<Budget>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<Budget> builder)
|
||||
{
|
||||
builder.ToTable(nameof(Budget).Pluralize());
|
||||
|
||||
builder.HasKey(pk => pk.Id);
|
||||
builder.Property(f => f.TenantId).IsRequired();
|
||||
builder.Property(f => f.ProjectId).IsRequired();
|
||||
builder.Property(f => f.CreatedBy).IsRequired();
|
||||
builder.Property(f => f.ApprovedBy).IsRequired(false);
|
||||
builder.Property(f => f.CreatedAt).IsRequired().HasDefaultValueSql("now()");
|
||||
builder.Property(f => f.UpdatedAt).IsRequired(false);
|
||||
builder.Property(f => f.Name).IsRequired().HasMaxLength(LabelLength);
|
||||
builder.Property(f => f.Amount).IsRequired().HasPrecision(18, 2);
|
||||
|
||||
builder.HasOne(f => f.Tenant)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.TenantId)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
|
||||
builder.HasOne(f => f.Project)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.ProjectId)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
builder.HasOne(f => f.Creator)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.CreatedBy)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
|
||||
builder.HasOne(f => f.Approver)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.ApprovedBy)
|
||||
.IsRequired(false)
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,62 @@
|
||||
using PostFundManagement.Domain.Abstractions;
|
||||
using static PostFundManagement.Domain.Extensions.Constants;
|
||||
|
||||
namespace PostFundManagement.Domain.Entities;
|
||||
|
||||
[EntityTypeConfiguration<Configuration.Entities.ChangeRequest, ChangeRequest>]
|
||||
public class ChangeRequest : Models.ChangeRequest
|
||||
[EntityTypeConfiguration<ChangeRequestConfiguration, ChangeRequest>]
|
||||
public class ChangeRequest : Models.ChangeRequest, ITenantEntity
|
||||
{
|
||||
public virtual Tenant? Tenant { get; set; }
|
||||
|
||||
public virtual Project? Project { get; set; }
|
||||
|
||||
public virtual User? Creator { get; set; }
|
||||
|
||||
public virtual User? Approver { get; set; }
|
||||
}
|
||||
|
||||
public sealed class ChangeRequestConfiguration : IEntityTypeConfiguration<ChangeRequest>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<ChangeRequest> builder)
|
||||
{
|
||||
builder.ToTable(nameof(ChangeRequest).Pluralize());
|
||||
|
||||
builder.HasKey(pk => pk.Id);
|
||||
builder.Property(f => f.TenantId).IsRequired();
|
||||
builder.Property(f => f.ProjectId).IsRequired();
|
||||
builder.Property(f => f.CreatedBy).IsRequired();
|
||||
builder.Property(f => f.ApprovedBy).IsRequired(false);
|
||||
builder.Property(f => f.CreatedAt).IsRequired().HasDefaultValueSql("now()");
|
||||
builder.Property(f => f.UpdatedAt).IsRequired(false);
|
||||
builder.Property(f => f.Title).IsRequired().HasMaxLength(LabelLength);
|
||||
builder.Property(f => f.Justification).IsRequired().HasMaxLength(TextLength);
|
||||
builder.Property(f => f.RevisedBudget).IsRequired(false).HasPrecision(18, 2);
|
||||
builder.Property(f => f.RevisedEndedAt).IsRequired(false);
|
||||
builder.Property(f => f.Status).IsRequired().HasConversion<int>().HasDefaultValueSql("1")
|
||||
.HasSentinel(ApprovalStatus.Pending);
|
||||
|
||||
builder.HasOne(f => f.Tenant)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.TenantId)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
|
||||
builder.HasOne(f => f.Project)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.ProjectId)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
builder.HasOne(f => f.Creator)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.CreatedBy)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
|
||||
builder.HasOne(f => f.Approver)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.ApprovedBy)
|
||||
.IsRequired(false)
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,54 @@
|
||||
using PostFundManagement.Domain.Abstractions;
|
||||
using static PostFundManagement.Domain.Extensions.Constants;
|
||||
|
||||
namespace PostFundManagement.Domain.Entities;
|
||||
|
||||
[EntityTypeConfiguration<Configuration.Entities.ComplianceItem, ComplianceItem>]
|
||||
public class ComplianceItem : Models.ComplianceItem
|
||||
[EntityTypeConfiguration<ComplianceItemConfiguration, ComplianceItem>]
|
||||
public class ComplianceItem : Models.ComplianceItem, ITenantEntity
|
||||
{
|
||||
public virtual Tenant? Tenant { get; set; }
|
||||
|
||||
public virtual Project? Project { get; set; }
|
||||
|
||||
public virtual User? Creator { get; set; }
|
||||
|
||||
public virtual User? Verifier { get; set; }
|
||||
}
|
||||
|
||||
public sealed class ComplianceItemConfiguration : IEntityTypeConfiguration<ComplianceItem>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<ComplianceItem> builder)
|
||||
{
|
||||
builder.ToTable(nameof(ComplianceItem).Pluralize());
|
||||
|
||||
builder.HasKey(pk => pk.Id);
|
||||
builder.Property(f => f.TenantId).IsRequired();
|
||||
builder.Property(f => f.ProjectId).IsRequired();
|
||||
builder.Property(f => f.CreatedBy).IsRequired();
|
||||
builder.Property(f => f.VerifiedBy).IsRequired(false);
|
||||
builder.Property(f => f.CreatedAt).IsRequired().HasDefaultValueSql("now()");
|
||||
builder.Property(f => f.UpdatedAt).IsRequired(false);
|
||||
builder.Property(f => f.Title).IsRequired().HasMaxLength(LabelLength);
|
||||
builder.Property(f => f.Requirements).IsRequired().HasMaxLength(MediumTextLength);
|
||||
builder.Property(f => f.Status).IsRequired().HasConversion<int>().HasDefaultValueSql("1")
|
||||
.HasSentinel(ApprovalStatus.Pending);
|
||||
|
||||
builder.HasOne(f => f.Project)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.ProjectId)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
builder.HasOne(f => f.Creator)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.CreatedBy)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
|
||||
builder.HasOne(f => f.Verifier)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.VerifiedBy)
|
||||
.IsRequired(false)
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,53 @@
|
||||
using PostFundManagement.Domain.Abstractions;
|
||||
|
||||
namespace PostFundManagement.Domain.Entities;
|
||||
|
||||
[EntityTypeConfiguration<Configuration.Entities.Contract, Contract>]
|
||||
public class Contract : Models.Contract
|
||||
[EntityTypeConfiguration<ContractConfiguration, Contract>]
|
||||
public class Contract : Models.Contract, ITenantEntity
|
||||
{
|
||||
public virtual Tenant? Tenant { get; set; }
|
||||
|
||||
public virtual Award? Award { get; set; }
|
||||
|
||||
public virtual User? Creator { get; set; }
|
||||
}
|
||||
|
||||
public sealed class ContractConfiguration : IEntityTypeConfiguration<Contract>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<Contract> builder)
|
||||
{
|
||||
builder.ToTable(nameof(Contract).Pluralize());
|
||||
|
||||
builder.HasKey(pk => pk.Id);
|
||||
builder.Property(f => f.TenantId).IsRequired();
|
||||
builder.HasIndex(f => f.AwardId).IsUnique();
|
||||
builder.Property(f => f.AwardId).IsRequired();
|
||||
builder.Property(f => f.CreatedBy).IsRequired();
|
||||
builder.Property(f => f.CreatedAt).IsRequired().HasDefaultValueSql("now()");
|
||||
builder.Property(f => f.ExternalSignatureId).IsRequired(false);
|
||||
builder.Property(f => f.SignedDocumentUrl).IsRequired(false);
|
||||
builder.Property(f => f.EffectiveAt).IsRequired(false);
|
||||
builder.Property(f => f.ExpiresAt).IsRequired(false);
|
||||
builder.Property(f => f.TotalValue).IsRequired().HasPrecision(18, 2);
|
||||
builder.Property(f => f.Status).IsRequired().HasConversion<int>().HasDefaultValueSql("1")
|
||||
.HasSentinel(ContractStatus.Draft);
|
||||
|
||||
builder.HasOne(f => f.Tenant)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.TenantId)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
|
||||
builder.HasOne(f => f.Award)
|
||||
.WithOne(f => f.Contract)
|
||||
.HasForeignKey<Domain.Entities.Contract>(fk => fk.AwardId)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
builder.HasOne(f => f.Creator)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.CreatedBy)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,12 @@
|
||||
using PostFundManagement.Domain.Abstractions;
|
||||
|
||||
namespace PostFundManagement.Domain.Entities;
|
||||
|
||||
[EntityTypeConfiguration<Configuration.Entities.Disbursement, Disbursement>]
|
||||
public class Disbursement : Models.Disbursement
|
||||
[EntityTypeConfiguration<DisbursementConfiguration, Disbursement>]
|
||||
public class Disbursement : Models.Disbursement, ITenantEntity
|
||||
{
|
||||
public virtual Tenant? Tenant { get; set; }
|
||||
|
||||
public virtual Project? Project { get; set; }
|
||||
|
||||
public virtual Milestone? Milestone { get; set; }
|
||||
@@ -11,3 +15,53 @@ public class Disbursement : Models.Disbursement
|
||||
|
||||
public virtual User? Updator { get; set; }
|
||||
}
|
||||
|
||||
public sealed class DisbursementConfiguration : IEntityTypeConfiguration<Disbursement>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<Disbursement> builder)
|
||||
{
|
||||
builder.ToTable(nameof(Disbursement).Pluralize());
|
||||
|
||||
builder.HasKey(pk => pk.Id);
|
||||
builder.Property(f => f.TenantId).IsRequired();
|
||||
builder.Property(f => f.ProjectId).IsRequired();
|
||||
builder.Property(f => f.MilestoneId).IsRequired(false);
|
||||
builder.Property(f => f.CreatedBy).IsRequired();
|
||||
builder.Property(f => f.UpdatedBy).IsRequired(false);
|
||||
builder.Property(f => f.CreatedAt).IsRequired().HasDefaultValueSql("now()");
|
||||
builder.Property(f => f.UpdatedAt).IsRequired(false);
|
||||
builder.Property(f => f.Amount).IsRequired().HasPrecision(18, 2);
|
||||
builder.Property(f => f.Status).IsRequired().HasConversion<int>().HasDefaultValueSql("1")
|
||||
.HasSentinel(ApprovalStatus.Pending);
|
||||
|
||||
builder.HasOne(f => f.Tenant)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.TenantId)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
|
||||
builder.HasOne(f => f.Project)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.ProjectId)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
builder.HasOne(f => f.Milestone)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.MilestoneId)
|
||||
.IsRequired(false)
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
builder.HasOne(f => f.Creator)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.CreatedBy)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
|
||||
builder.HasOne(f => f.Updator)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.UpdatedBy)
|
||||
.IsRequired(false)
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,12 @@
|
||||
using PostFundManagement.Domain.Abstractions;
|
||||
|
||||
namespace PostFundManagement.Domain.Entities;
|
||||
|
||||
[EntityTypeConfiguration<Configuration.Entities.Evidence, Evidence>]
|
||||
public class Evidence : Models.Evidence
|
||||
[EntityTypeConfiguration<EvidenceConfiguration, Evidence>]
|
||||
public class Evidence : Models.Evidence, ITenantEntity
|
||||
{
|
||||
public virtual Tenant? Tenant { get; set; }
|
||||
|
||||
public virtual Project? Project { get; set; }
|
||||
|
||||
public virtual Milestone? Milestone { get; set; }
|
||||
@@ -15,3 +19,70 @@ public class Evidence : Models.Evidence
|
||||
|
||||
public virtual User? Updator { get; set; }
|
||||
}
|
||||
|
||||
public sealed class EvidenceConfiguration : IEntityTypeConfiguration<Evidence>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<Evidence> builder)
|
||||
{
|
||||
builder.ToTable(nameof(Evidence).Pluralize());
|
||||
|
||||
builder.HasKey(f => f.Id);
|
||||
builder.Property(f => f.TenantId).IsRequired();
|
||||
builder.Property(f => f.ProjectId).IsRequired();
|
||||
builder.Property(f => f.MilestoneId).IsRequired();
|
||||
builder.Property(f => f.IndicatorId).IsRequired();
|
||||
builder.Property(f => f.ActivityId).IsRequired();
|
||||
builder.Property(f => f.CreatedBy).IsRequired();
|
||||
builder.Property(f => f.UpdatedBy).IsRequired();
|
||||
builder.Property(f => f.CreatedAt).IsRequired().HasDefaultValueSql("now()");
|
||||
builder.Property(f => f.UpdatedAt).IsRequired(false);
|
||||
builder.Property(f => f.Version).IsRequired().HasDefaultValue(1);
|
||||
builder.Property(f => f.DocumentUrl).IsRequired();
|
||||
builder.Property(f => f.Status).IsRequired().HasConversion<int>().HasDefaultValueSql("1")
|
||||
.HasSentinel(ApprovalStatus.Pending);
|
||||
builder.Property(f => f.Type).IsRequired().HasConversion<int>().HasDefaultValueSql("9")
|
||||
.HasSentinel(EvidenceType.ProcurementDocument);
|
||||
|
||||
builder.HasOne(f => f.Tenant)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.TenantId)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
|
||||
builder.HasOne(f => f.Project)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.ProjectId)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
builder.HasOne(f => f.Milestone)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.MilestoneId)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
builder.HasOne(f => f.Indicator)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.IndicatorId)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
builder.HasOne(f => f.Activity)
|
||||
.WithMany(f => f.Evidences)
|
||||
.HasForeignKey(fk => fk.ActivityId)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
builder.HasOne(f => f.Creator)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.CreatedBy)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
|
||||
builder.HasOne(f => f.Updator)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.UpdatedBy)
|
||||
.IsRequired(false)
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,51 @@
|
||||
using PostFundManagement.Domain.Abstractions;
|
||||
using static PostFundManagement.Domain.Extensions.Constants;
|
||||
|
||||
namespace PostFundManagement.Domain.Entities;
|
||||
|
||||
[EntityTypeConfiguration<Configuration.Entities.Indicator, Indicator>]
|
||||
public class Indicator : Models.Indicator
|
||||
[EntityTypeConfiguration<IndicatorConfiguration, Indicator>]
|
||||
public class Indicator : Models.Indicator, ITenantEntity
|
||||
{
|
||||
public virtual Tenant? Tenant { get; set; }
|
||||
|
||||
public virtual Project? Project { get; set; }
|
||||
|
||||
public virtual User? Creator { get; set; }
|
||||
}
|
||||
|
||||
public sealed class IndicatorConfiguration : IEntityTypeConfiguration<Indicator>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<Indicator> builder)
|
||||
{
|
||||
builder.ToTable(nameof(Indicator).Pluralize());
|
||||
|
||||
builder.HasKey(pk => pk.Id);
|
||||
builder.Property(f => f.TenantId).IsRequired();
|
||||
builder.Property(f => f.ProjectId).IsRequired();
|
||||
builder.Property(f => f.CreatedBy).IsRequired();
|
||||
builder.Property(f => f.CreatedAt).IsRequired().HasDefaultValueSql("now()");
|
||||
builder.Property(f => f.Name).IsRequired().HasMaxLength(LabelLength);
|
||||
builder.Property(f => f.UnitOfMeasure).IsRequired().HasConversion<int>().HasDefaultValueSql("2");
|
||||
builder.Property(f => f.BaselineAmount).IsRequired().HasPrecision(18, 2);
|
||||
builder.Property(f => f.TargetAmount).IsRequired().HasPrecision(18, 2);
|
||||
builder.Property(f => f.ActualAmount).IsRequired().HasPrecision(18, 2);
|
||||
|
||||
builder.HasOne(f => f.Tenant)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.TenantId)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
|
||||
builder.HasOne(f => f.Project)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.ProjectId)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
builder.HasOne(f => f.Creator)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.CreatedBy)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,51 @@
|
||||
using PostFundManagement.Domain.Abstractions;
|
||||
using static PostFundManagement.Domain.Extensions.Constants;
|
||||
|
||||
namespace PostFundManagement.Domain.Entities;
|
||||
|
||||
[EntityTypeConfiguration<Configuration.Entities.Instrument, Instrument>]
|
||||
public class Instrument : Models.Instrument
|
||||
[EntityTypeConfiguration<InstrumentConfiguration, Instrument>]
|
||||
public class Instrument : Models.Instrument, ITenantEntity
|
||||
{
|
||||
public virtual Tenant? Tenant { get; set; }
|
||||
|
||||
public virtual User? Creator { get; set; }
|
||||
|
||||
public virtual Programme? Programme { get; set; }
|
||||
}
|
||||
|
||||
public sealed class InstrumentConfiguration : IEntityTypeConfiguration<Instrument>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<Instrument> builder)
|
||||
{
|
||||
builder.ToTable(nameof(Instrument).Pluralize());
|
||||
|
||||
builder.HasKey(pk => pk.Id);
|
||||
builder.Property(f => f.TenantId).IsRequired();
|
||||
builder.Property(f => f.ProgrammeId).IsRequired();
|
||||
builder.Property(f => f.Code).IsRequired().HasMaxLength(ShortLabelLength);
|
||||
builder.Property(f => f.Name).IsRequired().HasMaxLength(LabelLength);
|
||||
builder.Property(f => f.Description).IsRequired(false).HasMaxLength(TextLength);
|
||||
builder.Property(f => f.Status).IsRequired().HasConversion<int>().HasDefaultValueSql("2")
|
||||
.HasSentinel(ActivityStatus.Inactive);
|
||||
builder.Property(f => f.CreatedBy).IsRequired();
|
||||
builder.Property(f => f.CreatedAt).IsRequired().HasDefaultValueSql("now()");
|
||||
|
||||
builder.HasOne(f => f.Tenant)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.TenantId)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
|
||||
builder.HasOne(f => f.Programme)
|
||||
.WithMany(f => f.Instruments)
|
||||
.HasForeignKey(fk => fk.ProgrammeId)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
builder.HasOne(f => f.Creator)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.CreatedBy)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
using PostFundManagement.Domain.Abstractions;
|
||||
|
||||
namespace PostFundManagement.Domain.Entities;
|
||||
|
||||
[EntityTypeConfiguration<Configuration.Entities.Invite, Invite>]
|
||||
public class Invite : Models.Invite
|
||||
[EntityTypeConfiguration<InviteConfiguration, Invite>]
|
||||
public class Invite : Models.Invite, ITenantEntity
|
||||
{
|
||||
public virtual Tenant? Tenant { get; set; }
|
||||
|
||||
public virtual Organisation? Organisation { get; set; }
|
||||
|
||||
public virtual Organisation? InvitedOrganisation { get; set; }
|
||||
@@ -13,3 +17,59 @@ public class Invite : Models.Invite
|
||||
|
||||
public virtual User? RecipientUser { get; set; }
|
||||
}
|
||||
|
||||
public sealed class InviteConfiguration : IEntityTypeConfiguration<Invite>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<Invite> builder)
|
||||
{
|
||||
builder.ToTable(nameof(Invite).Pluralize());
|
||||
|
||||
builder.HasKey(pk => pk.Id);
|
||||
builder.Property(f => f.TenantId).IsRequired();
|
||||
builder.Property(f => f.OrganisationId).IsRequired();
|
||||
builder.Property(f => f.InvitedOrganisationId).IsRequired();
|
||||
builder.Property(f => f.AwardId).IsRequired();
|
||||
builder.Property(f => f.ContractId).IsRequired();
|
||||
builder.Property(f => f.Recipient).IsRequired();
|
||||
builder.Property(f => f.CreatedBy).IsRequired();
|
||||
builder.Property(f => f.UpdatedBy).IsRequired(false);
|
||||
builder.Property(f => f.CreatedAt).IsRequired().HasDefaultValueSql("now()");
|
||||
builder.Property(f => f.UpdatedAt).IsRequired(false);
|
||||
|
||||
builder.HasOne(f => f.Tenant)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.TenantId)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
|
||||
builder.HasOne(f => f.Organisation)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.OrganisationId)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
builder.HasOne(f => f.InvitedOrganisation)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.InvitedOrganisationId)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
builder.HasOne(f => f.Award)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.AwardId)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
builder.HasOne(f => f.Contract)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.ContractId)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
builder.HasOne(f => f.RecipientUser)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.Recipient)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,63 @@
|
||||
using PostFundManagement.Domain.Abstractions;
|
||||
using static PostFundManagement.Domain.Extensions.Constants;
|
||||
|
||||
namespace PostFundManagement.Domain.Entities;
|
||||
|
||||
[EntityTypeConfiguration<Configuration.Entities.Issue, Issue>]
|
||||
public class Issue : Models.Issue
|
||||
[EntityTypeConfiguration<IssueConfiguration, Issue>]
|
||||
public class Issue : Models.Issue, ITenantEntity
|
||||
{
|
||||
public virtual Tenant? Tenant { get; set; }
|
||||
|
||||
public virtual Project? Project { get; set; }
|
||||
|
||||
public virtual User? Creator { get; set; }
|
||||
|
||||
public virtual User? Assignee { get; set; }
|
||||
}
|
||||
|
||||
public sealed class IssueConfiguration : IEntityTypeConfiguration<Issue>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<Issue> builder)
|
||||
{
|
||||
builder.ToTable(nameof(Issue).Pluralize());
|
||||
|
||||
builder.HasKey(pk => pk.Id);
|
||||
builder.Property(f => f.TenantId).IsRequired();
|
||||
builder.Property(f => f.ProjectId).IsRequired();
|
||||
builder.Property(f => f.CreatedBy).IsRequired();
|
||||
builder.Property(f => f.CreatedAt).IsRequired().HasDefaultValueSql("now()");
|
||||
builder.Property(f => f.ResolvedAt).IsRequired(false);
|
||||
builder.Property(f => f.AssignedTo).IsRequired(false);
|
||||
builder.Property(f => f.Title).IsRequired().HasMaxLength(LabelLength);
|
||||
builder.Property(f => f.Description).IsRequired().HasMaxLength(TextLength);
|
||||
builder.Property(f => f.Priority).IsRequired().HasConversion<int>().HasDefaultValueSql("1")
|
||||
.HasSentinel(Priority.Low);
|
||||
builder.Property(f => f.Status).IsRequired().HasConversion<int>().HasDefaultValueSql("1")
|
||||
.HasSentinel(ActivityStatus.Active);
|
||||
builder.Property(f => f.Resolution).IsRequired();
|
||||
|
||||
builder.HasOne(f => f.Tenant)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.TenantId)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
|
||||
builder.HasOne(f => f.Project)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.ProjectId)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
builder.HasOne(f => f.Creator)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.CreatedBy)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
|
||||
builder.HasOne(f => f.Assignee)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.AssignedTo)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.SetNull);
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,62 @@
|
||||
using PostFundManagement.Domain.Abstractions;
|
||||
using static PostFundManagement.Domain.Extensions.Constants;
|
||||
|
||||
namespace PostFundManagement.Domain.Entities;
|
||||
|
||||
[EntityTypeConfiguration<Configuration.Entities.Milestone, Milestone>]
|
||||
public class Milestone : Models.Milestone
|
||||
[EntityTypeConfiguration<MilestoneConfiguration, Milestone>]
|
||||
public class Milestone : Models.Milestone, ITenantEntity
|
||||
{
|
||||
public virtual Tenant? Tenant { get; set; }
|
||||
|
||||
public virtual Project? Project { get; set; }
|
||||
|
||||
public virtual User? Creator { get; set; }
|
||||
|
||||
public virtual User? Updator { get; set; }
|
||||
}
|
||||
|
||||
public sealed class MilestoneConfiguration : IEntityTypeConfiguration<Milestone>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<Milestone> builder)
|
||||
{
|
||||
builder.ToTable(nameof(Milestone).Pluralize());
|
||||
|
||||
builder.HasKey(pk => pk.Id);
|
||||
builder.Property(f => f.TenantId).IsRequired();
|
||||
builder.Property(f => f.ProjectId).IsRequired();
|
||||
builder.Property(f => f.CreatedBy).IsRequired();
|
||||
builder.Property(f => f.UpdatedBy).IsRequired(false);
|
||||
builder.Property(f => f.CreatedAt).IsRequired().HasDefaultValueSql("now()");
|
||||
builder.Property(f => f.UpdatedAt).IsRequired(false);
|
||||
builder.Property(f => f.DueAt).IsRequired();
|
||||
builder.Property(f => f.Name).IsRequired().HasMaxLength(LabelLength);
|
||||
builder.Property(f => f.Status).IsRequired().HasConversion<int>().HasDefaultValueSql("1")
|
||||
.HasSentinel(ApprovalStatus.Pending);
|
||||
builder.Property(f => f.Priority).IsRequired().HasConversion<int>().HasDefaultValueSql("1")
|
||||
.HasSentinel(Priority.Low);
|
||||
|
||||
builder.HasOne(f => f.Tenant)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.TenantId)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
|
||||
builder.HasOne(f => f.Project)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.ProjectId)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
builder.HasOne(f => f.Creator)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.CreatedBy)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
|
||||
builder.HasOne(f => f.Updator)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.UpdatedBy)
|
||||
.IsRequired(false)
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,56 @@
|
||||
using PostFundManagement.Domain.Abstractions;
|
||||
using static PostFundManagement.Domain.Extensions.Constants;
|
||||
|
||||
namespace PostFundManagement.Domain.Entities;
|
||||
|
||||
[EntityTypeConfiguration<Configuration.Entities.Notification, Notification>]
|
||||
public class Notification : Models.Notification
|
||||
[EntityTypeConfiguration<NotificationConfiguration, Notification>]
|
||||
public class Notification : Models.Notification, ITenantEntity
|
||||
{
|
||||
public virtual Tenant? Tenant { get; set; }
|
||||
|
||||
public virtual Organisation? Organisation { get; set; }
|
||||
|
||||
public virtual User? RecipientUser { get; set; }
|
||||
}
|
||||
|
||||
public sealed class NotificationConfiguration : IEntityTypeConfiguration<Notification>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<Notification> builder)
|
||||
{
|
||||
builder.ToTable(nameof(Notification).Pluralize());
|
||||
|
||||
builder.HasKey(pk => pk.Id);
|
||||
builder.Property(f => f.CreatedAt).IsRequired().HasDefaultValueSql("now()");
|
||||
builder.Property(f => f.UpdatedAt).IsRequired(false);
|
||||
builder.Property(f => f.SentAt).IsRequired(false);
|
||||
builder.Property(f => f.Recipient).IsRequired();
|
||||
builder.Property(f => f.OrganisationId).IsRequired();
|
||||
builder.Property(f => f.TenantId).IsRequired();
|
||||
builder.Property(f => f.Platform).IsRequired().HasConversion<int>().HasDefaultValueSql("1")
|
||||
.HasSentinel(NotificationPlatform.Email);
|
||||
builder.Property(f => f.Status).IsRequired().HasConversion<int>().HasDefaultValueSql("1")
|
||||
.HasSentinel(NotificationStatus.Pending);
|
||||
builder.Property(f => f.Subject).IsRequired(false).HasMaxLength(LabelLength);
|
||||
builder.Property(f => f.Message).IsRequired().HasMaxLength(LargeTextLength);
|
||||
builder.Property(f => f.Destination).IsRequired().HasMaxLength(LabelLength);
|
||||
builder.Property(f => f.Error).IsRequired(false);
|
||||
|
||||
builder.HasOne(f => f.Tenant)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.TenantId)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
builder.HasOne(f => f.Organisation)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.OrganisationId)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
builder.HasOne(f => f.RecipientUser)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.Recipient)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,34 @@
|
||||
using static PostFundManagement.Domain.Extensions.Constants;
|
||||
|
||||
namespace PostFundManagement.Domain.Entities;
|
||||
|
||||
[EntityTypeConfiguration<Configuration.Entities.Organisation, Organisation>]
|
||||
[EntityTypeConfiguration<OrganisationConfiguration, Organisation>]
|
||||
public class Organisation : Models.Organisation
|
||||
{
|
||||
public virtual User? Creator { get; set; }
|
||||
}
|
||||
|
||||
public sealed class OrganisationConfiguration : IEntityTypeConfiguration<Organisation>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<Organisation> builder)
|
||||
{
|
||||
builder.ToTable(nameof(Organisation).Pluralize());
|
||||
|
||||
builder.HasKey(pk => pk.Id);
|
||||
builder.Property(f => f.CreatedBy).IsRequired();
|
||||
builder.Property(f => f.CreatedAt).IsRequired().HasDefaultValueSql("now()");
|
||||
builder.Property(f => f.RegistrationNo).IsRequired().HasMaxLength(LabelLength);
|
||||
builder.Property(f => f.Name).IsRequired().HasMaxLength(LabelLength);
|
||||
builder.Property(f => f.Email).IsRequired().HasMaxLength(LabelLength);
|
||||
builder.Property(f => f.Type).IsRequired().HasConversion<int>().HasDefaultValueSql("5")
|
||||
.HasSentinel(OrganisationType.PrivateLimitedCompany);
|
||||
builder.Property(f => f.Status).IsRequired().HasConversion<int>().HasDefaultValueSql("1")
|
||||
.HasSentinel(ActivityStatus.Active);
|
||||
|
||||
builder.HasOne(f => f.Creator)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.CreatedBy)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,48 @@
|
||||
using PostFundManagement.Domain.Abstractions;
|
||||
using static PostFundManagement.Domain.Extensions.Constants;
|
||||
|
||||
namespace PostFundManagement.Domain.Entities;
|
||||
|
||||
[EntityTypeConfiguration<Configuration.Entities.Outcome, Outcome>]
|
||||
public class Outcome : Models.Outcome
|
||||
[EntityTypeConfiguration<OutcomeConfiguration, Outcome>]
|
||||
public class Outcome : Models.Outcome, ITenantEntity
|
||||
{
|
||||
public virtual Tenant? Tenant { get; set; }
|
||||
|
||||
public virtual Beneficiary? Beneficiary { get; set; }
|
||||
|
||||
public virtual User? Creator { get; set; }
|
||||
}
|
||||
|
||||
public sealed class OutcomeConfiguration : IEntityTypeConfiguration<Outcome>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<Outcome> builder)
|
||||
{
|
||||
builder.ToTable(nameof(Outcome).Pluralize());
|
||||
|
||||
builder.HasKey(pk => pk.Id);
|
||||
builder.Property(f => f.TenantId).IsRequired();
|
||||
builder.Property(f => f.BeneficiaryId).IsRequired();
|
||||
builder.Property(f => f.CreatedBy).IsRequired();
|
||||
builder.Property(f => f.CreatedAt).IsRequired().HasDefaultValueSql("now()");
|
||||
builder.Property(f => f.Name).IsRequired().HasMaxLength(LabelLength);
|
||||
builder.Property(f => f.Description).IsRequired().HasMaxLength(TextLength);
|
||||
|
||||
builder.HasOne(f => f.Tenant)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.TenantId)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
|
||||
builder.HasOne(f => f.Beneficiary)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.BeneficiaryId)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
builder.HasOne(f => f.Creator)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.CreatedBy)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,59 @@
|
||||
using PostFundManagement.Domain.Abstractions;
|
||||
using static PostFundManagement.Domain.Extensions.Constants;
|
||||
|
||||
namespace PostFundManagement.Domain.Entities;
|
||||
|
||||
[EntityTypeConfiguration<Configuration.Entities.Portfolio, Portfolio>]
|
||||
public class Portfolio : Models.Portfolio
|
||||
[EntityTypeConfiguration<PortfolioConfiguration, Portfolio>]
|
||||
public class Portfolio : Models.Portfolio, ITenantEntity
|
||||
{
|
||||
public virtual User? Creator { get; set; }
|
||||
|
||||
public virtual User? Owner { get; set; }
|
||||
|
||||
public virtual Tenant? Tenant { get; set; }
|
||||
|
||||
public virtual Organisation? Organisation { get; set; }
|
||||
|
||||
public virtual ICollection<Programme> Programmes { get; set; } = [];
|
||||
}
|
||||
|
||||
public sealed class PortfolioConfiguration : IEntityTypeConfiguration<Portfolio>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<Portfolio> builder)
|
||||
{
|
||||
builder.ToTable(nameof(Portfolio).Pluralize());
|
||||
|
||||
builder.HasKey(pk => pk.Id);
|
||||
builder.Property(f => f.TenantId).IsRequired();
|
||||
builder.Property(f => f.OrganisationId).IsRequired();
|
||||
builder.Property(f => f.CreatedBy).IsRequired();
|
||||
builder.Property(f => f.OwnedBy).IsRequired();
|
||||
builder.Property(f => f.CreatedAt).IsRequired().HasDefaultValueSql("now()");
|
||||
builder.Property(f => f.Name).IsRequired().HasMaxLength(LabelLength);
|
||||
builder.Property(f => f.Description).IsRequired(false).HasMaxLength(TextLength);
|
||||
|
||||
builder.HasOne(f => f.Tenant)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.TenantId)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
builder.HasOne(f => f.Organisation)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.OrganisationId)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
builder.HasOne(f => f.Creator)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.CreatedBy)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
|
||||
builder.HasOne(f => f.Owner)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.OwnedBy)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,17 @@
|
||||
using PostFundManagement.Domain.Abstractions;
|
||||
using static PostFundManagement.Domain.Extensions.Constants;
|
||||
|
||||
namespace PostFundManagement.Domain.Entities;
|
||||
|
||||
[EntityTypeConfiguration<Configuration.Entities.Programme, Programme>]
|
||||
public class Programme : Models.Programme
|
||||
[EntityTypeConfiguration<ProgrammeConfiguration, Programme>]
|
||||
public class Programme : Models.Programme, ITenantEntity
|
||||
{
|
||||
public virtual User? Creator { get; set; }
|
||||
|
||||
public virtual User? Owner { get; set; }
|
||||
|
||||
public virtual Tenant? Tenant { get; set; }
|
||||
|
||||
public virtual Portfolio? Portfolio { get; set; }
|
||||
|
||||
public virtual ICollection<Instrument> Instruments { get; set; } = [];
|
||||
@@ -17,3 +22,47 @@ public class Programme : Models.Programme
|
||||
|
||||
public virtual ICollection<Award> Awards { get; set; } = [];
|
||||
}
|
||||
|
||||
public sealed class ProgrammeConfiguration : IEntityTypeConfiguration<Programme>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<Programme> builder)
|
||||
{
|
||||
builder.ToTable(nameof(Programme).Pluralize());
|
||||
|
||||
builder.HasKey(pk => pk.Id);
|
||||
builder.Property(f => f.TenantId).IsRequired();
|
||||
builder.Property(f => f.PortfolioId).IsRequired();
|
||||
builder.Property(f => f.OwnedBy).IsRequired();
|
||||
builder.Property(f => f.CreatedBy).IsRequired();
|
||||
builder.Property(f => f.UpdatedBy).IsRequired(false);
|
||||
builder.Property(f => f.CreatedAt).IsRequired().HasDefaultValueSql("now()");
|
||||
builder.Property(f => f.UpdatedAt).IsRequired(false);
|
||||
builder.Property(f => f.Name).IsRequired().HasMaxLength(LabelLength);
|
||||
builder.Property(f => f.Status).IsRequired().HasConversion<int>().HasDefaultValueSql("1")
|
||||
.HasSentinel(ApprovalStatus.Pending);
|
||||
|
||||
builder.HasOne(f => f.Tenant)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.TenantId)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
|
||||
builder.HasOne(f => f.Portfolio)
|
||||
.WithMany(f => f.Programmes)
|
||||
.HasForeignKey(fk => fk.PortfolioId)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
|
||||
builder.HasOne(f => f.Creator)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.CreatedBy)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
|
||||
builder.HasOne(f => f.Owner)
|
||||
.WithMany()
|
||||
.IsRequired()
|
||||
.HasForeignKey(fk => fk.OwnedBy)
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,68 @@
|
||||
using PostFundManagement.Domain.Abstractions;
|
||||
using static PostFundManagement.Domain.Extensions.Constants;
|
||||
|
||||
namespace PostFundManagement.Domain.Entities;
|
||||
|
||||
[EntityTypeConfiguration<Configuration.Entities.Project, Project>]
|
||||
public class Project : Models.Project
|
||||
[EntityTypeConfiguration<ProjectConfiguration, Project>]
|
||||
public class Project : Models.Project, ITenantEntity
|
||||
{
|
||||
public virtual User? Creator { get; set; }
|
||||
|
||||
public virtual User? Updator { get; set; }
|
||||
|
||||
public virtual Tenant? Tenant { get; set; }
|
||||
|
||||
public virtual Programme? Programme { get; set; }
|
||||
|
||||
public virtual ICollection<Award> Awards { get; set; } = [];
|
||||
}
|
||||
|
||||
public sealed class ProjectConfiguration : IEntityTypeConfiguration<Project>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<Project> builder)
|
||||
{
|
||||
builder.ToTable(nameof(Project).Pluralize());
|
||||
|
||||
builder.HasKey(pk => pk.Id);
|
||||
builder.Property(f => f.TenantId).IsRequired();
|
||||
builder.Property(f => f.ProgrammeId).IsRequired();
|
||||
builder.Property(f => f.CreatedBy).IsRequired();
|
||||
builder.Property(f => f.UpdatedBy).IsRequired(false);
|
||||
builder.Property(f => f.CreatedAt).IsRequired().HasDefaultValueSql("now()");
|
||||
builder.Property(f => f.UpdatedAt).IsRequired(false);
|
||||
builder.Property(f => f.StartedAt).IsRequired(false);
|
||||
builder.Property(f => f.EndedAt).IsRequired(false);
|
||||
builder.Property(f => f.Name).IsRequired().HasMaxLength(LabelLength);
|
||||
builder.Property(f => f.Description).IsRequired().HasMaxLength(TextLength);
|
||||
builder.Property(f => f.Sector).IsRequired().HasConversion<int>().HasDefaultValueSql("11")
|
||||
.HasSentinel(IndustrySector.InformationCommunicationTechnology);
|
||||
builder.Property(f => f.ProjectType).IsRequired().HasConversion<int>().HasDefaultValueSql("10")
|
||||
.HasSentinel(ProjectType.Innovation);
|
||||
builder.Property(f => f.Status).IsRequired().HasConversion<int>().HasDefaultValueSql("1")
|
||||
.HasSentinel(ApprovalStatus.Pending);
|
||||
|
||||
builder.HasOne(f => f.Tenant)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.TenantId)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
builder.HasOne(f => f.Programme)
|
||||
.WithMany(f => f.Projects)
|
||||
.HasForeignKey(fk => fk.ProgrammeId)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
builder.HasOne(f => f.Creator)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.CreatedBy)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
|
||||
builder.HasOne(f => f.Updator)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.UpdatedBy)
|
||||
.IsRequired(false)
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,52 @@
|
||||
using PostFundManagement.Domain.Abstractions;
|
||||
using static PostFundManagement.Domain.Extensions.Constants;
|
||||
|
||||
namespace PostFundManagement.Domain.Entities;
|
||||
|
||||
[EntityTypeConfiguration<Configuration.Entities.Risk, Risk>]
|
||||
public class Risk : Models.Risk
|
||||
[EntityTypeConfiguration<RiskConfiguration, Risk>]
|
||||
public class Risk : Models.Risk, ITenantEntity
|
||||
{
|
||||
public virtual Tenant? Tenant { get; set; }
|
||||
|
||||
public virtual Project? Project { get; set; }
|
||||
|
||||
public virtual User? Creator { get; set; }
|
||||
}
|
||||
|
||||
public sealed class RiskConfiguration : IEntityTypeConfiguration<Risk>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<Risk> builder)
|
||||
{
|
||||
builder.ToTable(nameof(Risk).Pluralize());
|
||||
|
||||
builder.HasKey(pk => pk.Id);
|
||||
builder.Property(f => f.TenantId).IsRequired();
|
||||
builder.Property(f => f.ProjectId).IsRequired();
|
||||
builder.Property(f => f.CreatedBy).IsRequired();
|
||||
builder.Property(f => f.CreatedAt).IsRequired().HasDefaultValueSql("now()");
|
||||
builder.Property(f => f.Likelihood).IsRequired().HasConversion<int>().HasDefaultValueSql("3")
|
||||
.HasSentinel(RiskLikelihood.Possible);
|
||||
builder.Property(f => f.Impact).IsRequired().HasConversion<int>().HasDefaultValueSql("1")
|
||||
.HasSentinel(RiskImpact.Negligible);
|
||||
builder.Property(f => f.Name).IsRequired().HasMaxLength(LabelLength);
|
||||
builder.Property(f => f.Description).IsRequired().HasMaxLength(TextLength);
|
||||
|
||||
builder.HasOne(f => f.Tenant)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.TenantId)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
|
||||
builder.HasOne(f => f.Project)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.ProjectId)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
builder.HasOne(f => f.Creator)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.CreatedBy)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,60 @@
|
||||
using PostFundManagement.Domain.Abstractions;
|
||||
using static PostFundManagement.Domain.Extensions.Constants;
|
||||
|
||||
namespace PostFundManagement.Domain.Entities;
|
||||
|
||||
[EntityTypeConfiguration<Configuration.Entities.Rule, Rule>]
|
||||
public class Rule : Models.Rule
|
||||
[EntityTypeConfiguration<RuleConfiguration, Rule>]
|
||||
public class Rule : Models.Rule, ITenantEntity
|
||||
{
|
||||
public virtual Tenant? Tenant { get; set; }
|
||||
|
||||
public virtual User? Creator { get; set; }
|
||||
|
||||
public virtual User? Updator { get; set; }
|
||||
|
||||
public virtual Programme? Programme { get; set; }
|
||||
}
|
||||
|
||||
public sealed class RuleConfiguration : IEntityTypeConfiguration<Rule>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<Rule> builder)
|
||||
{
|
||||
builder.ToTable(nameof(Rule).Pluralize());
|
||||
|
||||
builder.HasKey(fk => fk.Id);
|
||||
builder.Property(f => f.TenantId).IsRequired();
|
||||
builder.Property(f => f.ProgrammeId).IsRequired();
|
||||
builder.Property(f => f.CreatedBy).IsRequired();
|
||||
builder.Property(f => f.UpdatedBy).IsRequired(false);
|
||||
builder.Property(f => f.CreatedAt).IsRequired().HasDefaultValueSql("now()");
|
||||
builder.Property(f => f.UpdatedAt).IsRequired(false);
|
||||
builder.Property(f => f.Name).IsRequired().HasMaxLength(LabelLength);
|
||||
builder.Property(f => f.Version).IsRequired().HasDefaultValue(1);
|
||||
builder.Property(f => f.Status).IsRequired().HasConversion<int>().HasDefaultValueSql("2")
|
||||
.HasSentinel(ActivityStatus.Inactive);
|
||||
|
||||
builder.HasOne(f => f.Tenant)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.TenantId)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
|
||||
builder.HasOne(f => f.Programme)
|
||||
.WithMany(f => f.Rules)
|
||||
.HasForeignKey(fk => fk.ProgrammeId)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
|
||||
builder.HasOne(f => f.Creator)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.CreatedBy)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
|
||||
builder.HasOne(f => f.Updator)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.UpdatedBy)
|
||||
.IsRequired(false)
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,51 @@
|
||||
using PostFundManagement.Domain.Abstractions;
|
||||
using static PostFundManagement.Domain.Extensions.Constants;
|
||||
|
||||
namespace PostFundManagement.Domain.Entities;
|
||||
|
||||
[EntityTypeConfiguration<Configuration.Entities.SiteVisit, SiteVisit>]
|
||||
public class SiteVisit : Models.SiteVisit
|
||||
[EntityTypeConfiguration<SiteVisitConfiguration, SiteVisit>]
|
||||
public class SiteVisit : Models.SiteVisit, ITenantEntity
|
||||
{
|
||||
public virtual Tenant? Tenant { get; set; }
|
||||
|
||||
public virtual Project? Project { get; set; }
|
||||
|
||||
public virtual User? Creator { get; set; }
|
||||
}
|
||||
|
||||
public sealed class SiteVisitConfiguration : IEntityTypeConfiguration<SiteVisit>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<SiteVisit> builder)
|
||||
{
|
||||
builder.ToTable(nameof(SiteVisit).Pluralize());
|
||||
|
||||
builder.HasKey(pk => pk.Id);
|
||||
builder.Property(f => f.TenantId).IsRequired();
|
||||
builder.Property(f => f.ProjectId).IsRequired();
|
||||
builder.Property(f => f.CreatedBy).IsRequired();
|
||||
builder.Property(f => f.CreatedAt).IsRequired().HasDefaultValueSql("now()");
|
||||
builder.Property(f => f.VisitedAt).IsRequired();
|
||||
builder.Property(f => f.InspectorName).IsRequired();
|
||||
builder.Property(f => f.Findings).IsRequired(false).HasMaxLength(LargeTextLength);
|
||||
builder.Property(f => f.Status).IsRequired().HasConversion<int>().HasDefaultValueSql("1")
|
||||
.HasSentinel(ApprovalStatus.Pending);
|
||||
|
||||
builder.HasOne(f => f.Tenant)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.TenantId)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
|
||||
builder.HasOne(f => f.Project)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.ProjectId)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
builder.HasOne(f => f.Creator)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.CreatedBy)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
using static PostFundManagement.Domain.Extensions.Constants;
|
||||
|
||||
namespace PostFundManagement.Domain.Entities;
|
||||
|
||||
[EntityTypeConfiguration<TenantConfiguration, Tenant>]
|
||||
public class Tenant : Models.Tenant
|
||||
{
|
||||
public virtual User? Creator { get; set; }
|
||||
|
||||
public virtual User? Updator { get; set; }
|
||||
}
|
||||
|
||||
public sealed class TenantConfiguration : IEntityTypeConfiguration<Tenant>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<Tenant> builder)
|
||||
{
|
||||
builder.ToTable(nameof(Tenant).Pluralize());
|
||||
|
||||
builder.HasKey(pk => pk.Id);
|
||||
builder.Property(f => f.CreatedAt).IsRequired().HasDefaultValueSql("now()");
|
||||
builder.Property(f => f.CreatedBy).IsRequired();
|
||||
builder.Property(f => f.UpdatedBy).IsRequired(false);
|
||||
builder.Property(f => f.UpdatedAt).IsRequired(false);
|
||||
builder.Property(f => f.Name).IsRequired().HasMaxLength(LabelLength);
|
||||
builder.Property(f => f.Status).IsRequired().HasConversion<int>().HasDefaultValueSql("1")
|
||||
.HasSentinel(ActivityStatus.Active);
|
||||
|
||||
builder.HasOne(f => f.Creator)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.CreatedBy)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
builder.HasOne(f => f.Updator)
|
||||
.WithMany()
|
||||
.HasForeignKey(fk => fk.UpdatedBy)
|
||||
.IsRequired(false)
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user