Compare commits
15
Commits
79c63107e9
...
garages3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2d0f2b494a | ||
|
|
d428f6e17c | ||
|
|
5829bffaa0 | ||
|
|
b703b0c64d | ||
|
|
6d554d19a7 | ||
|
|
ec777fabf8 | ||
|
|
41bf9b63bf | ||
|
|
940630f0ed | ||
|
|
6de3d30a8b | ||
|
|
831d57a8a0 | ||
|
|
2d74f7f1bd | ||
|
|
ebf35d7f12 | ||
|
|
77307f4bf0 | ||
|
|
464c21e41d | ||
|
|
364fe65e0d |
+12
-3
@@ -11,6 +11,7 @@
|
||||
*.sln.docstates
|
||||
*.env
|
||||
*.env.json
|
||||
certificates/
|
||||
|
||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||
*.userprefs
|
||||
@@ -51,6 +52,8 @@ bld/
|
||||
|
||||
# Build results on 'Bin' directories
|
||||
**/[Bb]in/*
|
||||
dist/assets/
|
||||
dist/
|
||||
# Uncomment if you have tasks that rely on *.refresh files to move binaries
|
||||
# (https://github.com/github/gitignore/pull/3736)
|
||||
#!**/[Bb]in/*.refresh
|
||||
@@ -58,8 +61,7 @@ bld/
|
||||
# Visual Studio 2015/2017 cache/options directory
|
||||
.vs/
|
||||
.vscode/
|
||||
bin/
|
||||
certificates/
|
||||
|
||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||
#wwwroot/
|
||||
|
||||
@@ -347,6 +349,7 @@ _Pvt_Extensions
|
||||
|
||||
# Paket dependency manager
|
||||
**/.paket/paket.exe
|
||||
**/.paket/paket.exe
|
||||
paket-files/
|
||||
|
||||
# FAKE - F# Make
|
||||
@@ -431,4 +434,10 @@ FodyWeavers.xsd
|
||||
*.msi
|
||||
*.msix
|
||||
*.msm
|
||||
*.msp
|
||||
*.msp
|
||||
/PostFundManagement.ConsoleUI/dist/config.json
|
||||
/PostFundManagement.ConsoleUI/dist/env-config.js
|
||||
/PostFundManagement.ConsoleUI/dist/assets/index-BaOzkVJi.css
|
||||
/PostFundManagement.ConsoleUI/dist/assets/index-BU8qSe7k.js
|
||||
/PostFundManagement.ConsoleUI/dist/favicon.svg
|
||||
/PostFundManagement.ConsoleUI/dist/index.html
|
||||
|
||||
@@ -22,7 +22,7 @@ COPY . .
|
||||
|
||||
# Build from the project folder using relative filename
|
||||
WORKDIR "/src/PostFundManagement.Api"
|
||||
RUN dotnet build "PostFundManagement.Api.csproj" -c Release -o /app/build -v n
|
||||
RUN dotnet build "PostFundManagement.Api.csproj" -c Release -o /app/build
|
||||
|
||||
# Stage 3: Publish
|
||||
FROM build AS publish
|
||||
|
||||
@@ -23,6 +23,7 @@ public sealed class GetApplicantInviteEndpoint : IEndpoint
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems()),
|
||||
})
|
||||
.WithDescription("Gets an applicant's invite")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(GetApplicantInviteEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces<Invite>(StatusCodes.Status200OK)
|
||||
|
||||
@@ -23,6 +23,7 @@ public sealed class GetApplicantInvitesEndpoint : IEndpoint
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems()),
|
||||
})
|
||||
.WithDescription("Gets an applicant's invite list")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(GetApplicantInvitesEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces<Invite[]>(StatusCodes.Status200OK)
|
||||
|
||||
@@ -23,6 +23,7 @@ public sealed class GetInvitesEndpoint : IEndpoint
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Get a list of sent invitations")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(GetInvitesEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces<Invite[]>(StatusCodes.Status200OK)
|
||||
|
||||
@@ -24,6 +24,7 @@ public sealed class SendInviteEndpoint : IEndpoint
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Trigger an invite to an organization or candidate (specifying NotificationPlatform)")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(SendInviteEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces<Invite>(StatusCodes.Status200OK)
|
||||
|
||||
@@ -34,9 +34,9 @@ public class CreateEvidenceEndpoint : IEndpoint
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
};
|
||||
})
|
||||
.RequireAuthorization()
|
||||
.DisableAntiforgery()
|
||||
.WithDescription("Upload supporting evidence file to S3 and register metadata (M14)")
|
||||
.DisableAntiforgery()
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(CreateEvidenceEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces(StatusCodes.Status200OK)
|
||||
|
||||
@@ -24,6 +24,7 @@ public class CreateIndicatorEndpoint : IEndpoint
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Define indicators and baselines/targets (M08)")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(CreateIndicatorEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces(StatusCodes.Status200OK)
|
||||
|
||||
@@ -24,6 +24,7 @@ public class CreateMilestoneEndpoint : IEndpoint
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Define contractual milestones (M07)")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(CreateMilestoneRequest).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces(StatusCodes.Status200OK)
|
||||
|
||||
@@ -23,6 +23,7 @@ public sealed class GetEvidenceEndpoint : IEndpoint
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Get a specific evidence record and assiciated file URLs")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(GetEvidenceEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces<Domain.Models.Evidence>(StatusCodes.Status200OK)
|
||||
|
||||
@@ -21,6 +21,7 @@ public class GetEvidenceFilesEndpoint : IEndpoint
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Get a list of all uploaded evidence files metadata")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(GetEvidenceFilesEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces<Domain.Models.Evidence[]>(StatusCodes.Status200OK)
|
||||
|
||||
@@ -23,6 +23,7 @@ public sealed class GetEvidenceUrlEndpoint : IEndpoint
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Gets a secure download URL of the evidence file, URL expires (default: 15min)")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(GetEvidenceUrlEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces<string>(StatusCodes.Status200OK)
|
||||
|
||||
@@ -24,6 +24,7 @@ public sealed class GetIndicatorEndpoint : IEndpoint
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Get a specific indicator.")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(GetIndicatorEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces<Indicator>(StatusCodes.Status200OK)
|
||||
|
||||
@@ -22,6 +22,7 @@ public class GetIndicatorsEndpoint : IEndpoint
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems()),
|
||||
})
|
||||
.WithDescription("Get a list of indicators")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(GetIndicatorsEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces<Indicator[]>(StatusCodes.Status200OK)
|
||||
|
||||
@@ -22,6 +22,7 @@ public class GetMilestoneEvidenceEndpoint : IEndpoint
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Get a list of all uploaded evidence metadata for a specific mliestone")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(GetMilestoneEvidenceEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces<Domain.Models.Evidence[]>(StatusCodes.Status200OK)
|
||||
|
||||
@@ -22,6 +22,7 @@ public class GetProjectEvidenceEndpoint : IEndpoint
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems()),
|
||||
})
|
||||
.WithDescription("Get a list of all uploaded evidence metadata for a specific project")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(GetProjectEvidenceEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces<Domain.Models.Evidence[]>(StatusCodes.Status200OK)
|
||||
|
||||
@@ -23,6 +23,7 @@ public class RecordIndicatorAmountEndpoint : IEndpoint
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Record actual values for indicators (M08)")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(RecordIndicatorAmountEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces(StatusCodes.Status200OK)
|
||||
|
||||
@@ -24,6 +24,8 @@ public sealed class UpdateEvidenceEndpoint : IEndpoint
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Updates a specific evidence record metadata")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.DisableAntiforgery()
|
||||
.WithName(typeof(UpdateEvidenceEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces(StatusCodes.Status200OK)
|
||||
|
||||
@@ -23,6 +23,7 @@ public class ApproveDisbursementEndpoint : IEndpoint
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems()),
|
||||
})
|
||||
.WithDescription("Approve disbursement and release payment (M06)")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(ApproveDisbursementEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces(StatusCodes.Status200OK)
|
||||
|
||||
@@ -24,6 +24,7 @@ public class CreateDisbursementEndpoint : IEndpoint
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems()),
|
||||
})
|
||||
.WithDescription("Create a new disbursement schedule (M06)")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(CreateDisbursementEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces(StatusCodes.Status200OK)
|
||||
|
||||
@@ -24,6 +24,7 @@ public class CreateRiskEndpoint : IEndpoint
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Add risk to risk register (M09)")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(CreateRiskEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces(StatusCodes.Status200OK)
|
||||
|
||||
@@ -24,6 +24,7 @@ public sealed class GetDisbursementEndpoint : IEndpoint
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Get a specific disbursement")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(GetDisbursementEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces<Disbursement>(StatusCodes.Status200OK)
|
||||
|
||||
@@ -22,6 +22,7 @@ public class GetDisbursementsEndpoint : IEndpoint
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Get a list of disbursements")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(GetDisbursementsEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces<Disbursement[]>(StatusCodes.Status200OK)
|
||||
|
||||
@@ -24,6 +24,7 @@ public sealed class GetRiskEndpoint : IEndpoint
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Get a specific risk")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(GetRiskEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces<Risk>(StatusCodes.Status200OK)
|
||||
|
||||
@@ -21,6 +21,7 @@ public class GetRisksEndpoint : IEndpoint
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Get a list of all risks")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(GetRisksEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces(StatusCodes.Status200OK)
|
||||
|
||||
@@ -23,6 +23,7 @@ public sealed class UpdateDisbursementEndpoint : IEndpoint
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Update the details of a specific disbursement")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(UpdateDisbursementEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces(StatusCodes.Status200OK)
|
||||
|
||||
@@ -23,6 +23,7 @@ public sealed class UpdateRiskEndpoint : IEndpoint
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Update the details of a specific risk")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(UpdateRiskEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces(StatusCodes.Status200OK)
|
||||
|
||||
@@ -23,6 +23,7 @@ public sealed class CreateOrganisationEndpoint : IEndpoint
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Create a new organization profile")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(CreateOrganisationEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces(StatusCodes.Status200OK)
|
||||
|
||||
@@ -25,6 +25,7 @@ public sealed class CreatePortfolioEndpoint : IEndpoint
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Create a new organization portfolio")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(CreatePortfolioEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces(StatusCodes.Status200OK)
|
||||
|
||||
@@ -21,6 +21,7 @@ public class DashboardEndpoint : IEndpoint
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Get executive portfolio dashboard metrics and KPIs")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(DashboardEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces<Dashboard>(StatusCodes.Status200OK)
|
||||
|
||||
@@ -23,6 +23,7 @@ public class GetInstrumentsEndpoint : IEndpoint
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems()),
|
||||
})
|
||||
.WithDescription("Get all funding instruments")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(GetInstrumentsEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces<Instrument[]>(StatusCodes.Status200OK)
|
||||
|
||||
@@ -24,6 +24,7 @@ public class GetOrganisationEndpoint : IEndpoint
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Get organization profile by ID")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(GetOrganisationEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces<Organisation>(StatusCodes.Status200OK)
|
||||
|
||||
@@ -22,6 +22,7 @@ public class GetOrganisationsEndpoint : IEndpoint
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Get a paginated directory of organizations")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(GetOrganisationsEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces<Organisation[]>(StatusCodes.Status200OK)
|
||||
|
||||
@@ -23,6 +23,7 @@ public sealed class GetPortfolioEndpoint : IEndpoint
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Get a specific portfolios")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(GetPortfolioEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces<Portfolio[]>(StatusCodes.Status200OK)
|
||||
|
||||
@@ -24,6 +24,7 @@ public sealed class GetPortfolioProgrammesEndpoint : IEndpoint
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Get a programme's portfolios")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(GetPortfolioProgrammesEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces<Programme[]>(StatusCodes.Status200OK)
|
||||
|
||||
@@ -23,6 +23,7 @@ public class GetPortfoliosEndpoint : IEndpoint
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Get all portfolios")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(GetPortfoliosEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces<Portfolio[]>(StatusCodes.Status200OK)
|
||||
|
||||
@@ -23,6 +23,7 @@ public class GetProgrammesEndpoint : IEndpoint
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Get all programmes")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(GetProgrammesEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces<Programme[]>(StatusCodes.Status200OK)
|
||||
|
||||
@@ -23,6 +23,7 @@ public sealed class UpdateOrganisationEndpoint : IEndpoint
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Update an existing organization profile")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(UpdateOrganisationEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces(StatusCodes.Status200OK)
|
||||
|
||||
@@ -25,6 +25,7 @@ public sealed class UpdatePortfolioEndpoint : IEndpoint
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Update an existing organization portfolio")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(UpdatePortfolioEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces(StatusCodes.Status200OK)
|
||||
|
||||
@@ -25,6 +25,7 @@ public class CreateAwardEndpoint : IEndpoint
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Register an approved funding award (M01)")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(CreateAwardEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces(StatusCodes.Status200OK)
|
||||
|
||||
@@ -25,6 +25,7 @@ public class CreateBudgetEndpoint : IEndpoint
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Create a new budget line (M05)")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(CreateBudgetEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces(StatusCodes.Status200OK)
|
||||
|
||||
@@ -24,6 +24,7 @@ public class CreateContractEndpoint : IEndpoint
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Create a contract record from an approved award (M02)")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(CreateContractEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces(StatusCodes.Status200OK)
|
||||
|
||||
@@ -23,6 +23,7 @@ public class ExecuteContractEndpoint : IEndpoint
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Execute the contract and lock the contractual version")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(ExecuteContractEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces(StatusCodes.Status200OK)
|
||||
|
||||
@@ -24,6 +24,7 @@ public class GetAwardEndpoint : IEndpoint
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Get award by ID")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(GetAwardEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces<Award>(StatusCodes.Status200OK)
|
||||
|
||||
@@ -22,6 +22,7 @@ public class GetAwardsEndpoint : IEndpoint
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Get a list of awards")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(GetAwardsEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces<Award[]>(StatusCodes.Status200OK)
|
||||
|
||||
@@ -24,6 +24,7 @@ public class GetBudgetEndpoint : IEndpoint
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Get budget by ID")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(GetBudgetEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces<Budget>(StatusCodes.Status200OK)
|
||||
|
||||
@@ -22,6 +22,7 @@ public class GetBudgetsEndpoint : IEndpoint
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Get all budgets")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(GetBudgetsEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces<Budget[]>(StatusCodes.Status200OK)
|
||||
|
||||
@@ -24,6 +24,7 @@ public class GetContractEndpoint : IEndpoint
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Get contract by ID")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(GetContractEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces<Contract>(StatusCodes.Status200OK)
|
||||
|
||||
@@ -23,6 +23,7 @@ public sealed class GetContractUrlEndpoint : IEndpoint
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Gets a secure download URL, has expiry period (default 15min)")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(GetContractUrlEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces<string>(StatusCodes.Status200OK)
|
||||
|
||||
@@ -22,6 +22,7 @@ public class GetContractsEndpoint : IEndpoint
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Get all contracts")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(GetContractsEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces<Contract[]>(StatusCodes.Status200OK)
|
||||
|
||||
@@ -25,6 +25,7 @@ public sealed class UpdateContractEndpoint : IEndpoint
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Updates a specific contract")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(UpdateContractEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces(StatusCodes.Status200OK)
|
||||
|
||||
@@ -33,6 +33,8 @@ public sealed class UploadContractEndpoint : IEndpoint
|
||||
};
|
||||
})
|
||||
.WithDescription("Uploads a contract file securely")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.DisableAntiforgery()
|
||||
.WithName(typeof(UploadContractEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces(StatusCodes.Status200OK)
|
||||
|
||||
@@ -23,6 +23,7 @@ public class CreateActivityEndpoint : IEndpoint
|
||||
var r when r.HasError<CreateError>() => Results.BadRequest(r.Errors.ToProblems()),
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithDescription("Add a new activity under project (M04)")
|
||||
.WithName(typeof(CreateActivityEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
|
||||
@@ -25,6 +25,7 @@ public sealed class CreateProgrammeEndpoint : IEndpoint
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Create programme")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(CreateProgrammeEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces(StatusCodes.Status200OK)
|
||||
|
||||
@@ -25,6 +25,7 @@ public class CreateProjectEndpoint : IEndpoint
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Create a new project (M04)")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(CreateProjectEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces(StatusCodes.Status200OK)
|
||||
|
||||
@@ -22,6 +22,7 @@ public class GetActivitiesEndpoint : IEndpoint
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Get a list of activities for a project")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(GetActivitiesEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces<Domain.Models.Activity[]>(StatusCodes.Status200OK)
|
||||
|
||||
@@ -23,6 +23,7 @@ public class GetActivityEndpoint : IEndpoint
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Gets a specific activity by it's id")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(GetActivityEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces<Domain.Models.Activity>(StatusCodes.Status200OK)
|
||||
|
||||
@@ -24,6 +24,7 @@ public class GetMilestoneEndpoint : IEndpoint
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Gets a specific milestone")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(GetMilestoneEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces<Milestone>(StatusCodes.Status200OK)
|
||||
|
||||
@@ -22,6 +22,7 @@ public class GetMilestonesEndpoint : IEndpoint
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Get a list of all milestones")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(GetMilestonesEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces<Milestone[]>(StatusCodes.Status200OK)
|
||||
|
||||
@@ -24,6 +24,7 @@ public sealed class GetProgrammeEndpoint : IEndpoint
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Get specific programme")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(GetProgrammeEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces<Programme>(StatusCodes.Status200OK)
|
||||
|
||||
@@ -24,6 +24,7 @@ public sealed class GetProgrammeProjectsEndpoint : IEndpoint
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems()),
|
||||
})
|
||||
.WithDescription("Get a list of all projects under a programme")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(GetProgrammeProjectsEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces<Project[]>(StatusCodes.Status200OK)
|
||||
|
||||
@@ -22,6 +22,7 @@ public sealed class GetProgrammesEndpoint : IEndpoint
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Get a list of all programmes")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(GetProgrammesEndpoint).ToEndpointName("Projects"))
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces<Programme[]>(StatusCodes.Status200OK)
|
||||
|
||||
@@ -24,6 +24,7 @@ public class GetProjectEndpoint : IEndpoint
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Get project by ID")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(GetProjectEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces<Project[]>(StatusCodes.Status200OK)
|
||||
|
||||
@@ -23,6 +23,7 @@ public class GetProjectIndicatorsEndpoint : IEndpoint
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Get get a detailed list of project indicators")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(GetProjectIndicatorsEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces<Indicator[]>(StatusCodes.Status200OK)
|
||||
|
||||
@@ -23,6 +23,7 @@ public class GetProjectMilestonesEndpoint : IEndpoint
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Get a list of milestones for a project")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(GetProjectMilestonesEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces<Milestone[]>(StatusCodes.Status200OK)
|
||||
|
||||
@@ -23,6 +23,7 @@ public class GetProjectRisksEndpoint : IEndpoint
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Get a list of risks for a project")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(GetProjectRisksEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces<Risk[]>(StatusCodes.Status200OK)
|
||||
|
||||
@@ -22,6 +22,7 @@ public class GetProjectsEndpoint : IEndpoint
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Get a list of projects")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(GetProjectsEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces<Project[]>(StatusCodes.Status200OK)
|
||||
|
||||
@@ -21,6 +21,7 @@ public sealed class UpdateMilestoneEndpoint : IEndpoint
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Update project milestone details")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(UpdateMilestoneEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces(StatusCodes.Status200OK)
|
||||
|
||||
@@ -24,6 +24,7 @@ public sealed class UpdateProgrammeEndpoint : IEndpoint
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Update existing programme")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(UpdateProgrammeEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces(StatusCodes.Status200OK)
|
||||
|
||||
@@ -23,6 +23,7 @@ public sealed class UpdateProjectEndpoint : IEndpoint
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Update project details")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(UpdateProjectEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces(StatusCodes.Status200OK)
|
||||
|
||||
@@ -24,6 +24,7 @@ public class UpdateProjectStatusEndpoint : IEndpoint
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Update project status (M04)")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(UpdateProjectStatusEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces(StatusCodes.Status200OK)
|
||||
|
||||
@@ -22,6 +22,7 @@ public sealed class EncodeIdEndpoint : IEndpoint
|
||||
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)
|
||||
|
||||
@@ -23,6 +23,7 @@ public sealed class GetUserEndpoint : IEndpoint
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Gets the metadata of a single user.")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(GetUserEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces<User>(StatusCodes.Status200OK)
|
||||
|
||||
@@ -23,6 +23,7 @@ public class GetUsersEndpoint : IEndpoint
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Paginated, searchable directory of system users. Supports filtering by ActivityStatus, searching by Email, and sorting")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(GetUsersEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces<User[]>(StatusCodes.Status200OK)
|
||||
|
||||
@@ -30,6 +30,7 @@ public class SyncUserEndpoint : IEndpoint
|
||||
};
|
||||
})
|
||||
.WithDescription("Trigger integration and data synchronization in the background")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(SyncUserEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces(StatusCodes.Status200OK)
|
||||
|
||||
@@ -23,6 +23,7 @@ public sealed class UpdateUserStatusEndpoint : IEndpoint
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Changes the Activity status of the user in the system")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(UpdateUserStatusEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces(StatusCodes.Status200OK)
|
||||
|
||||
@@ -25,8 +25,8 @@
|
||||
<PackageReference Include="IdentityServer4.AccessTokenValidation" Version="3.0.1" />
|
||||
<PackageReference Include="IdentityModel" Version="6.2.0" />
|
||||
<PackageReference Include="KubernetesClient" Version="19.0.2" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.Certificate" Version="10.0.11" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="10.0.11" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.Certificate" Version="10.0.12" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="10.0.12" />
|
||||
|
||||
<Using Include="Microsoft.AspNetCore.Authentication" />
|
||||
<Using Include="Microsoft.AspNetCore.Authentication.Cookies" />
|
||||
@@ -60,8 +60,8 @@
|
||||
|
||||
<!-- API Documentation -->
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="10.0.11" />
|
||||
<PackageReference Include="Scalar.AspNetCore" Version="2.17.2" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="10.0.12" />
|
||||
<PackageReference Include="Scalar.AspNetCore" Version="2.17.4" />
|
||||
|
||||
<Using Include="Scalar.AspNetCore" />
|
||||
<Using Include="Microsoft.OpenApi" />
|
||||
|
||||
@@ -1,16 +1,31 @@
|
||||
using Microsoft.FeatureManagement;
|
||||
using PostFundManagement.Application.Extensions;
|
||||
using PostFundManagement.Application.Filters;
|
||||
using PostFundManagement.Domain.Extensions;
|
||||
using PostFundManagement.Domain.Health;
|
||||
using PostFundManagement.Domain.Mediator;
|
||||
using static PostFundManagement.Domain.Extensions.Constants;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
builder.Services.AddEndpointsApiExplorer()
|
||||
.AddApiVersioning(options => options.ApiVersionReader = new HeaderApiVersionReader());
|
||||
builder.Services.AddFeatureManagement();
|
||||
|
||||
builder.Services.AddEndpointsApiExplorer();
|
||||
builder.Services.AddApiVersioning(options =>
|
||||
{
|
||||
options.DefaultApiVersion = new ApiVersion(1, 0);
|
||||
options.AssumeDefaultVersionWhenUnspecified = true;
|
||||
options.ApiVersionReader = ApiVersionReader.Combine(
|
||||
new UrlSegmentApiVersionReader(),
|
||||
new HeaderApiVersionReader("x-api-version"),
|
||||
new MediaTypeApiVersionReader("version")
|
||||
);
|
||||
})
|
||||
.AddApiExplorer(options =>
|
||||
{
|
||||
options.GroupNameFormat = "'v'VVV";
|
||||
options.SubstituteApiVersionInUrl = true;
|
||||
});
|
||||
|
||||
builder.Services.AddApiVersioning().AddApiExplorer();
|
||||
builder.Services.AddScoped<ActiveUserFilter>();
|
||||
|
||||
builder.Services.AddEndpoints(Assembly.GetExecutingAssembly());
|
||||
@@ -95,7 +110,7 @@ var allowedOrigins = builder.Configuration.GetSection("CorsOrigins").Get<string[
|
||||
|
||||
builder.Services.AddCors(options =>
|
||||
{
|
||||
options.AddPolicy("AllowConfiguredOrigins", policy =>
|
||||
options.AddPolicy(CorsPolicy, policy =>
|
||||
{
|
||||
policy.WithOrigins(allowedOrigins)
|
||||
.AllowAnyHeader()
|
||||
@@ -107,15 +122,15 @@ builder.Services.AddCors(options =>
|
||||
var app = builder.Build();
|
||||
|
||||
var schedulerFactory = app.Services.GetRequiredService<ISchedulerFactory>();
|
||||
var scheduler = await schedulerFactory.GetScheduler(DefaultSchedulerName);
|
||||
var scheduler = await schedulerFactory.GetScheduler();
|
||||
|
||||
if (!scheduler!.IsStarted)
|
||||
if (scheduler!.Status != SchedulerStatus.Running)
|
||||
await scheduler.Start();
|
||||
|
||||
app.UseHsts();
|
||||
app.UseHttpsRedirection();
|
||||
app.UseRouting();
|
||||
app.UseCors("AllowConfiguredOrigins");
|
||||
app.UseCors(CorsPolicy);
|
||||
app.UseOutputCache();
|
||||
|
||||
app.UseAuthentication();
|
||||
@@ -130,7 +145,16 @@ var versionGroups = new Dictionary<int, RouteGroupBuilder>
|
||||
{
|
||||
{
|
||||
1, app.MapGroup("v{version:apiVersion}").WithApiVersionSet(versionSet)
|
||||
.RequireAuthorization("ApiScope").AddEndpointFilter<ActiveUserFilter>()
|
||||
.RequireCors(CorsPolicy)
|
||||
.AddEndpointFilter(async (context, next) =>
|
||||
{
|
||||
if (HttpMethods.IsOptions(context.HttpContext.Request.Method))
|
||||
return await next(context);
|
||||
|
||||
var filter = context.HttpContext.RequestServices.GetRequiredService<ActiveUserFilter>();
|
||||
|
||||
return await filter.InvokeAsync(context, next);
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"EnableServiceCaching": true,
|
||||
"CorsOrigins": [
|
||||
"https://console.ifri.khongisa.co.za",
|
||||
"https://localhost:7208"
|
||||
|
||||
@@ -2,7 +2,7 @@ using PostFundManagement.Domain.Abstractions;
|
||||
using PostFundManagement.Domain.Quartz;
|
||||
using static PostFundManagement.Domain.Extensions.Constants;
|
||||
|
||||
namespace PostFundManagement.Domain.Extensions;
|
||||
namespace PostFundManagement.Application.Extensions;
|
||||
|
||||
public static class Quartz
|
||||
{
|
||||
@@ -10,35 +10,33 @@ public static class Quartz
|
||||
{
|
||||
var connectionString = configuration.GetConnectionString(DatabaseConfigName);
|
||||
|
||||
services.Configure<QuartzOptions>(options =>
|
||||
{
|
||||
options.Properties["quartz.scheduler.instanceName"] = schedulerName;
|
||||
options.Properties["quartz.scheduler.instanceId"] = "AUTO";
|
||||
});
|
||||
|
||||
services.ConfigureCommon();
|
||||
|
||||
services.AddQuartz(config =>
|
||||
{
|
||||
config.SchedulerName = schedulerName;
|
||||
config.SchedulerId = "AUTO";
|
||||
|
||||
config.UseSimpleTypeLoader();
|
||||
config.UseDefaultThreadPool(options => options.MaxConcurrency = 0);
|
||||
config.UseTimeZoneConverter();
|
||||
|
||||
config.UsePersistentStore(storage =>
|
||||
{
|
||||
storage.PerformSchemaValidation = false;
|
||||
storage.ProvisionSchema();
|
||||
storage.UsePostgres(options => options.ConnectionString = connectionString!);
|
||||
|
||||
storage.UseSystemTextJsonSerializer();
|
||||
storage.SetProperty("quartz.jobStore.clustered", "true");
|
||||
|
||||
storage.UsePostgres(options =>
|
||||
{
|
||||
options.ConnectionString = connectionString!;
|
||||
options.TablePrefix = "quartz.qrtz_";
|
||||
});
|
||||
|
||||
storage.UseClustering(cluster =>
|
||||
{
|
||||
cluster.CheckinInterval = TimeSpan.FromSeconds(30);
|
||||
cluster.CheckinMisfireThreshold = TimeSpan.FromSeconds(90);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
return services;
|
||||
@@ -48,36 +46,37 @@ public static class Quartz
|
||||
{
|
||||
var connectionString = configuration.GetConnectionString(DatabaseConfigName);
|
||||
|
||||
services.Configure<QuartzOptions>(options =>
|
||||
{
|
||||
options.Properties["quartz.scheduler.instanceName"] = schedulerName;
|
||||
options.Properties["quartz.scheduler.instanceId"] = "AUTO";
|
||||
options.Properties["quartz.scheduler.batchTriggerAcquisitionMaxCount"] = "5";
|
||||
options.Properties["quartz.jobStore.misfireThreshold"] = TimeSpan.FromMinutes(2).TotalMilliseconds.ToString(CultureInfo.InvariantCulture);
|
||||
|
||||
options.Properties["quartz.plugin.jobHistory.type"] = "Quartz.Plugin.History.LoggingJobHistoryPlugin, Quartz.Plugins";
|
||||
options.Properties["quartz.plugin.triggerHistory.type"] = "Quartz.Plugin.History.LoggingTriggerHistoryPlugin, Quartz.Plugins";
|
||||
});
|
||||
|
||||
services.ConfigureCommon();
|
||||
|
||||
services.AddQuartzHostedService(options => options.WaitForJobsToComplete = true);
|
||||
services.AddQuartzHostedService(options =>
|
||||
{
|
||||
options.WaitForJobsToComplete = true;
|
||||
});
|
||||
|
||||
services.AddQuartz(config =>
|
||||
{
|
||||
config.SchedulerName = schedulerName;
|
||||
config.SchedulerId = "AUTO";
|
||||
config.InterruptJobsOnShutdown = true;
|
||||
config.InterruptJobsOnShutdownWithWait = true;
|
||||
config.MaxBatchSize = 5;
|
||||
|
||||
config.UseSimpleTypeLoader();
|
||||
config.UseDefaultThreadPool(options => options.MaxConcurrency = 1);
|
||||
config.UseDefaultThreadPool(options => options.MaxConcurrency = 5);
|
||||
config.UseTimeZoneConverter();
|
||||
|
||||
config.SetProperty("quartz.jobStore.misfireThreshold", TimeSpan.FromMinutes(2).TotalMilliseconds.ToString(CultureInfo.InvariantCulture));
|
||||
|
||||
config.UsePersistentStore(storage =>
|
||||
{
|
||||
storage.PerformSchemaValidation = false;
|
||||
storage.ProvisionSchema();
|
||||
storage.UsePostgres(options => options.ConnectionString = connectionString!);
|
||||
|
||||
storage.UseSystemTextJsonSerializer();
|
||||
storage.SetProperty("quartz.jobStore.clustered", "true");
|
||||
|
||||
storage.UsePostgres(options =>
|
||||
{
|
||||
options.ConnectionString = connectionString!;
|
||||
options.TablePrefix = "quartz.qrtz_";
|
||||
});
|
||||
storage.UseClustering(cluster =>
|
||||
{
|
||||
cluster.CheckinInterval = TimeSpan.FromSeconds(30);
|
||||
@@ -91,18 +90,10 @@ public static class Quartz
|
||||
|
||||
private static IServiceCollection ConfigureCommon(this IServiceCollection services)
|
||||
{
|
||||
services.Configure<QuartzOptions>(options =>
|
||||
{
|
||||
options.Scheduling.IgnoreDuplicates = true;
|
||||
options.Scheduling.OverWriteExistingData = true;
|
||||
|
||||
options["quartz.plugin.jobHistory.type"] = "Quartz.Plugin.History.LoggingJobHistoryPlugin, Quartz.Plugins";
|
||||
options["quartz.plugin.triggerHistory.type"] = "Quartz.Plugin.History.LoggingTriggerHistoryPlugin, Quartz.Plugins";
|
||||
});
|
||||
|
||||
services.Configure<QuartzOptions>(options => options.Scheduling.IgnoreDuplicates = true);
|
||||
services.AddTransient<RetryJobListener>();
|
||||
services.AddTransient<IJobOrchestrator, JobOrchestrator>();
|
||||
|
||||
|
||||
return services;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using PostFundManagement.Application.Services.Shared;
|
||||
using PostFundManagement.Domain.Security.Configuration;
|
||||
using PostFundManagement.Domain.Extensions;
|
||||
using PostFundManagement.Domain.Security.Sdk;
|
||||
using PostFundManagement.Infrastructure.Database;
|
||||
|
||||
@@ -138,7 +139,7 @@ public static class Security
|
||||
{
|
||||
options.MapInboundClaims = false;
|
||||
options.Authority = authOptions.Authority;
|
||||
options.Audience = authOptions.Audience;
|
||||
options.Audience = authOptions.Audience;
|
||||
|
||||
options.TokenValidationParameters = new TokenValidationParameters
|
||||
{
|
||||
@@ -150,7 +151,7 @@ public static class Security
|
||||
});
|
||||
|
||||
services.AddAuthorizationBuilder()
|
||||
.AddPolicy("ApiScope", policy =>
|
||||
.AddPolicy(Constants.MainScope, policy =>
|
||||
{
|
||||
policy.RequireAuthenticatedUser();
|
||||
policy.RequireClaim("scope", authOptions.Audience!);
|
||||
|
||||
@@ -24,9 +24,9 @@
|
||||
|
||||
<!-- API Documentation -->
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="10.0.11" />
|
||||
<PackageReference Include="Microsoft.Extensions.Validation" Version="10.0.11" />
|
||||
<PackageReference Include="Scalar.AspNetCore" Version="2.17.2" />
|
||||
<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" />
|
||||
|
||||
<Using Include="Scalar.AspNetCore" />
|
||||
<Using Include="Microsoft.OpenApi" />
|
||||
@@ -36,6 +36,7 @@
|
||||
<!-- Shared Usings -->
|
||||
<ItemGroup>
|
||||
<Using Include="Humanizer" />
|
||||
<Using Include="Microsoft.FeatureManagement" />
|
||||
<Using Include="System.ComponentModel.DataAnnotations" />
|
||||
<Using Include="Microsoft.Extensions.Caching.Distributed" />
|
||||
<Using Include="Microsoft.Extensions.Caching.Hybrid" />
|
||||
|
||||
+13
-2
@@ -4,14 +4,19 @@ using PostFundManagement.Application.Extensions;
|
||||
using PostFundManagement.Application.Services.Shared;
|
||||
using PostFundManagement.Domain;
|
||||
using PostFundManagement.Domain.Models;
|
||||
using static PostFundManagement.Domain.Extensions.Constants;
|
||||
|
||||
namespace PostFundManagement.Application.Services.Communications;
|
||||
|
||||
public sealed class CommunicationsCacheService(CommunicationsService service, IDistributedCache cache) : ServiceCacheBase, ICommunicationsService
|
||||
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 () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetApplicantInviteAsync(applicantUserId, cancellationToken);
|
||||
|
||||
var cacheKey = HashService.ToMd5Hash($"getapplicantinvite-{applicantUserId}").Value;
|
||||
|
||||
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
|
||||
@@ -31,11 +36,14 @@ public sealed class CommunicationsCacheService(CommunicationsService service, ID
|
||||
public async ValueTask<Result<Invite[]>> GetApplicantInvitesAsync(Guid applicantUserId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Invite[]>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetApplicantInvitesAsync(applicantUserId, cancellationToken);
|
||||
|
||||
var cacheKey = HashService.ToMd5Hash($"getapplicantinvites-{applicantUserId}").Value;
|
||||
|
||||
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
|
||||
|
||||
if(string.IsNullOrWhiteSpace(cached))
|
||||
if (string.IsNullOrWhiteSpace(cached))
|
||||
{
|
||||
var result = await service.GetApplicantInvitesAsync(applicantUserId, cancellationToken);
|
||||
|
||||
@@ -52,6 +60,9 @@ public sealed class CommunicationsCacheService(CommunicationsService service, ID
|
||||
public async ValueTask<Result<Invite[]>> GetInvitesAsync(Pagination pagination, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Invite[]>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetInvitesAsync(pagination, cancellationToken);
|
||||
|
||||
var cacheKey = HashService.ToMd5Hash($"getinvites-{pagination.Page}-{pagination.PageSize}").Value;
|
||||
|
||||
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
|
||||
|
||||
@@ -4,10 +4,12 @@ using PostFundManagement.Application.Extensions;
|
||||
using PostFundManagement.Application.Services.Shared;
|
||||
using PostFundManagement.Domain;
|
||||
using PostFundManagement.Domain.Models;
|
||||
using static PostFundManagement.Domain.Extensions.Constants;
|
||||
|
||||
namespace PostFundManagement.Application.Services.Evidence;
|
||||
|
||||
public sealed class EvidenceCacheService(EvidenceService service, IDistributedCache cache) : ServiceCacheBase, IEvidenceService
|
||||
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) =>
|
||||
await service.CreateEvidenceAsync(userId, form, file, cancellationToken);
|
||||
@@ -21,6 +23,9 @@ public sealed class EvidenceCacheService(EvidenceService service, IDistributedCa
|
||||
public async ValueTask<Result<Domain.Models.Evidence>> GetEvidenceAsync(string evidenceId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Domain.Models.Evidence>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetEvidenceAsync(evidenceId, cancellationToken);
|
||||
|
||||
var cacheKey = HashService.ToMd5Hash($"getevidence-{evidenceId}").Value;
|
||||
|
||||
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
|
||||
@@ -42,6 +47,9 @@ public sealed class EvidenceCacheService(EvidenceService service, IDistributedCa
|
||||
public async ValueTask<Result<Domain.Models.Evidence[]>> GetEvidenceFilesAsync(Pagination pagination, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Domain.Models.Evidence[]>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetEvidenceFilesAsync(pagination, cancellationToken);
|
||||
|
||||
var cacheKey = HashService.ToMd5Hash($"getevidencefiles-{pagination.Page}-{pagination.PageSize}").Value;
|
||||
|
||||
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
|
||||
@@ -63,6 +71,9 @@ public sealed class EvidenceCacheService(EvidenceService service, IDistributedCa
|
||||
public async ValueTask<Result<string>> GetEvidenceUrlAsync(string evidenceIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<string>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetEvidenceUrlAsync(evidenceIdHash, cancellationToken);
|
||||
|
||||
var cacheKey = HashService.ToMd5Hash($"getevidenceurl-{evidenceIdHash}").Value;
|
||||
|
||||
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
|
||||
@@ -84,6 +95,9 @@ public sealed class EvidenceCacheService(EvidenceService service, IDistributedCa
|
||||
public async ValueTask<Result<Indicator>> GetIndicatorAsync(string indicatorId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Indicator>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetIndicatorAsync(indicatorId, cancellationToken);
|
||||
|
||||
var cacheKey = HashService.ToMd5Hash($"getindicator-{indicatorId}").Value;
|
||||
|
||||
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
|
||||
@@ -105,6 +119,9 @@ public sealed class EvidenceCacheService(EvidenceService service, IDistributedCa
|
||||
public async ValueTask<Result<Indicator[]>> GetIndicatorsAsync(Pagination pagination, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Indicator[]>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetIndicatorsAsync(pagination, cancellationToken);
|
||||
|
||||
var cacheKey = HashService.ToMd5Hash($"getindicators-{pagination.Page}-{pagination.PageSize}").Value;
|
||||
|
||||
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
|
||||
@@ -126,11 +143,14 @@ public sealed class EvidenceCacheService(EvidenceService service, IDistributedCa
|
||||
public async ValueTask<Result<Domain.Models.Evidence[]>> GetMilestoneEvidencesAsync(string milestoneIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Domain.Models.Evidence[]>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetMilestoneEvidencesAsync(milestoneIdHash, cancellationToken);
|
||||
|
||||
var cacheKey = HashService.ToMd5Hash($"getmilestoneevidences-{milestoneIdHash}").Value;
|
||||
|
||||
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
|
||||
|
||||
if(string.IsNullOrWhiteSpace(cached))
|
||||
if (string.IsNullOrWhiteSpace(cached))
|
||||
{
|
||||
var result = await service.GetMilestoneEvidencesAsync(milestoneIdHash, cancellationToken);
|
||||
|
||||
@@ -147,11 +167,14 @@ public sealed class EvidenceCacheService(EvidenceService service, IDistributedCa
|
||||
public async ValueTask<Result<Domain.Models.Evidence[]>> GetProjectEvidencesAsync(string projectIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Domain.Models.Evidence[]>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetProjectEvidencesAsync(projectIdHash, cancellationToken);
|
||||
|
||||
var cacheKey = HashService.ToMd5Hash($"getprojectevidences-{projectIdHash}").Value;
|
||||
|
||||
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
|
||||
|
||||
if(string.IsNullOrWhiteSpace(cached))
|
||||
if (string.IsNullOrWhiteSpace(cached))
|
||||
{
|
||||
var result = await service.GetProjectEvidencesAsync(projectIdHash, cancellationToken);
|
||||
|
||||
|
||||
@@ -4,10 +4,12 @@ using PostFundManagement.Application.Extensions;
|
||||
using PostFundManagement.Application.Services.Shared;
|
||||
using PostFundManagement.Domain;
|
||||
using PostFundManagement.Domain.Models;
|
||||
using static PostFundManagement.Domain.Extensions.Constants;
|
||||
|
||||
namespace PostFundManagement.Application.Services.Execution;
|
||||
|
||||
public sealed class ExecutionCacheService(ExecutionService service, IDistributedCache cache) : ServiceCacheBase, IExecutionService
|
||||
public sealed class ExecutionCacheService(ExecutionService service, IDistributedCache cache,
|
||||
IFeatureManager featureManager) : ServiceCacheBase, IExecutionService
|
||||
{
|
||||
public async ValueTask<Result> ApproveDisbursementAsync(string disbursementIdHash, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await service.ApproveDisbursementAsync(disbursementIdHash, userId, cancellationToken);
|
||||
@@ -21,6 +23,9 @@ public sealed class ExecutionCacheService(ExecutionService service, IDistributed
|
||||
public async ValueTask<Result<Disbursement>> GetDisbursementAsync(string disbursementIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Disbursement>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetDisbursementAsync(disbursementIdHash, cancellationToken);
|
||||
|
||||
var cacheKey = HashService.ToMd5Hash($"getdisbursement-{disbursementIdHash}").Value;
|
||||
|
||||
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
|
||||
@@ -42,6 +47,9 @@ public sealed class ExecutionCacheService(ExecutionService service, IDistributed
|
||||
public async ValueTask<Result<Disbursement[]>> GetDisbursementsAsync(Pagination pagination, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Disbursement[]>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetDisbursementsAsync(pagination, cancellationToken);
|
||||
|
||||
var cacheKey = HashService.ToMd5Hash($"getdisbursements-{pagination.Page}-{pagination.PageSize}-{pagination.Index}").Value;
|
||||
|
||||
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
|
||||
@@ -63,6 +71,9 @@ public sealed class ExecutionCacheService(ExecutionService service, IDistributed
|
||||
public async ValueTask<Result<Risk>> GetRiskAsync(string riskIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Risk>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetRiskAsync(riskIdHash, cancellationToken);
|
||||
|
||||
var cacheKey = HashService.ToMd5Hash($"getrisk-{riskIdHash}").Value;
|
||||
|
||||
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
|
||||
@@ -84,6 +95,9 @@ public sealed class ExecutionCacheService(ExecutionService service, IDistributed
|
||||
public async ValueTask<Result<Risk[]>> GetRisksAsync(Pagination pagination, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Risk[]>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetRisksAsync(pagination, cancellationToken);
|
||||
|
||||
var cacheKey = HashService.ToMd5Hash($"getrisks-{pagination.Page}-{pagination.PageSize}-{pagination.Index}").Value;
|
||||
|
||||
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
|
||||
|
||||
@@ -4,10 +4,12 @@ using PostFundManagement.Application.Extensions;
|
||||
using PostFundManagement.Application.Services.Shared;
|
||||
using PostFundManagement.Domain;
|
||||
using PostFundManagement.Domain.Models;
|
||||
using static PostFundManagement.Domain.Extensions.Constants;
|
||||
|
||||
namespace PostFundManagement.Application.Services.Governance;
|
||||
|
||||
public sealed class GovernanceCacheService(GovernanceService service, IDistributedCache cache) : ServiceCacheBase, IGovernanceService
|
||||
public sealed class GovernanceCacheService(GovernanceService service, IDistributedCache cache,
|
||||
IFeatureManager featureManager) : ServiceCacheBase, IGovernanceService
|
||||
{
|
||||
public async ValueTask<Result> CreateOrganisationAsync(CreateOrganisationRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await service.CreateOrganisationAsync(request, userId, cancellationToken);
|
||||
@@ -18,6 +20,9 @@ public sealed class GovernanceCacheService(GovernanceService service, IDistribut
|
||||
public async ValueTask<Result<Dashboard>> GetDashboardAsync(CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Dashboard>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetDashboardAsync(cancellationToken);
|
||||
|
||||
var cacheKey = HashService.ToMd5Hash($"getdashboard").Value;
|
||||
|
||||
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
|
||||
@@ -39,6 +44,9 @@ public sealed class GovernanceCacheService(GovernanceService service, IDistribut
|
||||
public async ValueTask<Result<Instrument[]>> GetInstrumentsAsync(string programmeIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Instrument[]>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetInstrumentsAsync(programmeIdHash, cancellationToken);
|
||||
|
||||
var cacheKey = HashService.ToMd5Hash($"getinstruments").Value;
|
||||
|
||||
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
|
||||
@@ -60,6 +68,9 @@ public sealed class GovernanceCacheService(GovernanceService service, IDistribut
|
||||
public async ValueTask<Result<Organisation>> GetOrganisationAsync(string organisationIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Organisation>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetOrganisationAsync(organisationIdHash, cancellationToken);
|
||||
|
||||
var cacheKey = HashService.ToMd5Hash($"getorganisation-{organisationIdHash}").Value;
|
||||
|
||||
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
|
||||
@@ -81,6 +92,9 @@ public sealed class GovernanceCacheService(GovernanceService service, IDistribut
|
||||
public async ValueTask<Result<Organisation[]>> GetOrganisationsAsync(Pagination pagination, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Organisation[]>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetOrganisationsAsync(pagination, cancellationToken);
|
||||
|
||||
var cacheKey = HashService.ToMd5Hash($"getorganisations-{pagination.Page}-{pagination.PageSize}").Value;
|
||||
|
||||
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
|
||||
@@ -102,6 +116,9 @@ public sealed class GovernanceCacheService(GovernanceService service, IDistribut
|
||||
public async ValueTask<Result<Portfolio[]>> GetPorfoliosAsync(string organisationIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Portfolio[]>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetPorfoliosAsync(organisationIdHash, cancellationToken);
|
||||
|
||||
var cacheKey = HashService.ToMd5Hash($"getportfolios-{organisationIdHash}").Value;
|
||||
|
||||
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
|
||||
@@ -123,11 +140,14 @@ public sealed class GovernanceCacheService(GovernanceService service, IDistribut
|
||||
public async ValueTask<Result<Portfolio>> GetPortfolioAsync(string portfolioIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Portfolio>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetPortfolioAsync(portfolioIdHash, cancellationToken);
|
||||
|
||||
var cacheKey = HashService.ToMd5Hash($"getportfolio-{portfolioIdHash}").Value;
|
||||
|
||||
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
|
||||
|
||||
if(string.IsNullOrWhiteSpace(cached))
|
||||
if (string.IsNullOrWhiteSpace(cached))
|
||||
{
|
||||
var result = await service.GetPortfolioAsync(portfolioIdHash, cancellationToken);
|
||||
|
||||
@@ -144,11 +164,14 @@ public sealed class GovernanceCacheService(GovernanceService service, IDistribut
|
||||
public async ValueTask<Result<Programme[]>> GetPortfolioProgrammesAsync(string portfolioIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Programme[]>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetPortfolioProgrammesAsync(portfolioIdHash, cancellationToken);
|
||||
|
||||
var cacheKey = HashService.ToMd5Hash($"getportfolioprogrammes-{portfolioIdHash}").Value;
|
||||
|
||||
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
|
||||
|
||||
if(string.IsNullOrWhiteSpace(cached))
|
||||
if (string.IsNullOrWhiteSpace(cached))
|
||||
{
|
||||
var result = await service.GetPortfolioProgrammesAsync(portfolioIdHash, cancellationToken);
|
||||
|
||||
@@ -165,6 +188,9 @@ public sealed class GovernanceCacheService(GovernanceService service, IDistribut
|
||||
public async ValueTask<Result<Programme[]>> GetProgrammesAsync(string portfolioIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Programme[]>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetProgrammesAsync(portfolioIdHash, cancellationToken);
|
||||
|
||||
var cacheKey = HashService.ToMd5Hash($"getprogrammes-{portfolioIdHash}").Value;
|
||||
|
||||
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
|
||||
|
||||
@@ -4,10 +4,12 @@ using PostFundManagement.Application.Extensions;
|
||||
using PostFundManagement.Application.Services.Shared;
|
||||
using PostFundManagement.Domain;
|
||||
using PostFundManagement.Domain.Models;
|
||||
using static PostFundManagement.Domain.Extensions.Constants;
|
||||
|
||||
namespace PostFundManagement.Application.Services.Grants;
|
||||
|
||||
public sealed class GrantsCacheService(GrantsService service, IDistributedCache cache) : ServiceCacheBase, IGrantsService
|
||||
public sealed class GrantsCacheService(GrantsService service, IDistributedCache cache,
|
||||
IFeatureManager featureManager) : ServiceCacheBase, IGrantsService
|
||||
{
|
||||
public async ValueTask<Result> CreateAwardAsync(CreateAwardRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await service.CreateAwardAsync(request, userId, cancellationToken);
|
||||
@@ -24,6 +26,9 @@ public sealed class GrantsCacheService(GrantsService service, IDistributedCache
|
||||
public async ValueTask<Result<Award>> GetAwardAsync(string awardIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Award>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetAwardAsync(awardIdHash, cancellationToken);
|
||||
|
||||
var cacheKey = HashService.ToMd5Hash($"getaward-{awardIdHash}").Value;
|
||||
|
||||
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
|
||||
@@ -45,6 +50,9 @@ public sealed class GrantsCacheService(GrantsService service, IDistributedCache
|
||||
public async ValueTask<Result<Award[]>> GetAwardsAsync(Pagination pagination, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Award[]>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetAwardsAsync(pagination, cancellationToken);
|
||||
|
||||
var cacheKey = HashService.ToMd5Hash($"getawards-{pagination.Page}-{pagination.PageSize}-{pagination.Index}").Value;
|
||||
|
||||
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
|
||||
@@ -66,6 +74,9 @@ public sealed class GrantsCacheService(GrantsService service, IDistributedCache
|
||||
public async ValueTask<Result<Budget>> GetBudgetAsync(string budgetIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Budget>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetBudgetAsync(budgetIdHash, cancellationToken);
|
||||
|
||||
var cacheKey = HashService.ToMd5Hash($"getbudget-{budgetIdHash}").Value;
|
||||
|
||||
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
|
||||
@@ -87,6 +98,9 @@ public sealed class GrantsCacheService(GrantsService service, IDistributedCache
|
||||
public async ValueTask<Result<Budget[]>> GetBudgetsAsync(Pagination pagination, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Budget[]>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetBudgetsAsync(pagination, cancellationToken);
|
||||
|
||||
var cacheKey = HashService.ToMd5Hash($"getbudgets-{pagination.Page}-{pagination.PageSize}-{pagination.Index}").Value;
|
||||
|
||||
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
|
||||
@@ -108,6 +122,9 @@ public sealed class GrantsCacheService(GrantsService service, IDistributedCache
|
||||
public async ValueTask<Result<Contract>> GetContractAsync(string contractIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Contract>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetContractAsync(contractIdHash, cancellationToken);
|
||||
|
||||
var cacheKey = HashService.ToMd5Hash($"getctract-{contractIdHash}").Value;
|
||||
|
||||
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
|
||||
@@ -129,6 +146,9 @@ public sealed class GrantsCacheService(GrantsService service, IDistributedCache
|
||||
public async ValueTask<Result<Contract[]>> GetContractsAsync(Pagination pagination, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Contract[]>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetContractsAsync(pagination, cancellationToken);
|
||||
|
||||
var cacheKey = HashService.ToMd5Hash($"getcontracts-{pagination.Index}-{pagination.PageSize}-{pagination.Page}").Value;
|
||||
|
||||
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
|
||||
@@ -150,15 +170,18 @@ public sealed class GrantsCacheService(GrantsService service, IDistributedCache
|
||||
public async ValueTask<Result<string>> GetContractUrlAsync(string contractIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<string>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetContractUrlAsync(contractIdHash, cancellationToken);
|
||||
|
||||
var cacheKey = HashService.ToMd5Hash($"getcontracturl-{contractIdHash}").Value;
|
||||
|
||||
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
|
||||
|
||||
if(string.IsNullOrWhiteSpace(cached))
|
||||
if (string.IsNullOrWhiteSpace(cached))
|
||||
{
|
||||
var result = await service.GetContractUrlAsync(contractIdHash, cancellationToken);
|
||||
|
||||
if(result.IsFailed) return result;
|
||||
if (result.IsFailed) return result;
|
||||
|
||||
await cache.SetStringAsync(cacheKey, result.Value, cancellationToken);
|
||||
|
||||
|
||||
@@ -4,10 +4,12 @@ using PostFundManagement.Application.Extensions;
|
||||
using PostFundManagement.Application.Services.Shared;
|
||||
using PostFundManagement.Domain;
|
||||
using PostFundManagement.Domain.Models;
|
||||
using static PostFundManagement.Domain.Extensions.Constants;
|
||||
|
||||
namespace PostFundManagement.Application.Services.Projects;
|
||||
|
||||
public sealed class ProjectCacheService(ProjectService service, IDistributedCache cache) : ServiceCacheBase, IProjectService
|
||||
public sealed class ProjectCacheService(ProjectService service, IDistributedCache cache,
|
||||
IFeatureManager featureManager) : ServiceCacheBase, IProjectService
|
||||
{
|
||||
public async ValueTask<Result> CreateActivityAsync(CreateActivityRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await service.CreateActivityAsync(request, userId, cancellationToken);
|
||||
@@ -21,6 +23,9 @@ public sealed class ProjectCacheService(ProjectService service, IDistributedCach
|
||||
public async ValueTask<Result<Domain.Models.Activity[]>> GetActivitiesAsync(string projectIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Domain.Models.Activity[]>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetActivitiesAsync(projectIdHash, cancellationToken);
|
||||
|
||||
var cacheKey = HashService.ToMd5Hash($"getactivities-{projectIdHash}").Value;
|
||||
|
||||
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
|
||||
@@ -42,11 +47,14 @@ public sealed class ProjectCacheService(ProjectService service, IDistributedCach
|
||||
public async ValueTask<Result<Domain.Models.Activity>> GetActivityAsync(string activityIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Domain.Models.Activity>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetActivityAsync(activityIdHash, cancellationToken);
|
||||
|
||||
var cacheKey = HashService.ToMd5Hash($"getactivity-{activityIdHash}").Value;
|
||||
|
||||
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
|
||||
|
||||
if(string.IsNullOrWhiteSpace(cached))
|
||||
if (string.IsNullOrWhiteSpace(cached))
|
||||
{
|
||||
var result = await service.GetActivityAsync(activityIdHash, cancellationToken);
|
||||
|
||||
@@ -63,6 +71,9 @@ public sealed class ProjectCacheService(ProjectService service, IDistributedCach
|
||||
public async ValueTask<Result<Milestone>> GetMilestoneAsync(string milestoneIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Milestone>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetMilestoneAsync(milestoneIdHash, cancellationToken);
|
||||
|
||||
var cacheKey = HashService.ToMd5Hash($"getmilestone-{milestoneIdHash}").Value;
|
||||
|
||||
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
|
||||
@@ -84,11 +95,14 @@ public sealed class ProjectCacheService(ProjectService service, IDistributedCach
|
||||
public async ValueTask<Result<Milestone[]>> GetMilestonesAsync(Pagination pagination, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Milestone[]>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetMilestonesAsync(pagination, cancellationToken);
|
||||
|
||||
var cacheKey = HashService.ToMd5Hash($"getmilestones-{pagination.Index}-{pagination.PageSize}-{pagination.Page}").Value;
|
||||
|
||||
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(cached))
|
||||
if (string.IsNullOrWhiteSpace(cached))
|
||||
{
|
||||
var result = await service.GetMilestonesAsync(pagination, cancellationToken);
|
||||
|
||||
@@ -105,11 +119,14 @@ public sealed class ProjectCacheService(ProjectService service, IDistributedCach
|
||||
public async ValueTask<Result<Programme>> GetProgrammeAsync(string programmeIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Programme>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetProgrammeAsync(programmeIdHash, cancellationToken);
|
||||
|
||||
var cacheKey = HashService.ToMd5Hash($"getprogramme-{programmeIdHash}").Value;
|
||||
|
||||
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
|
||||
|
||||
if(string.IsNullOrWhiteSpace(cached))
|
||||
if (string.IsNullOrWhiteSpace(cached))
|
||||
{
|
||||
var result = await service.GetProgrammeAsync(programmeIdHash, cancellationToken);
|
||||
|
||||
@@ -126,11 +143,14 @@ public sealed class ProjectCacheService(ProjectService service, IDistributedCach
|
||||
public async ValueTask<Result<Project[]>> GetProgrammeProjectsAsync(string programmeIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Project[]>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetProgrammeProjectsAsync(programmeIdHash, cancellationToken);
|
||||
|
||||
var cacheKey = HashService.ToMd5Hash($"getprogrammeprojects-{programmeIdHash}").Value;
|
||||
|
||||
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
|
||||
|
||||
if(string.IsNullOrWhiteSpace(cached))
|
||||
if (string.IsNullOrWhiteSpace(cached))
|
||||
{
|
||||
var result = await service.GetProgrammeProjectsAsync(programmeIdHash, cancellationToken);
|
||||
|
||||
@@ -147,11 +167,14 @@ public sealed class ProjectCacheService(ProjectService service, IDistributedCach
|
||||
public async ValueTask<Result<Programme[]>> GetProgrammesAsync(Pagination pagination, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Programme[]>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetProgrammesAsync(pagination, cancellationToken);
|
||||
|
||||
var cacheKey = HashService.ToMd5Hash($"getprogrammes-{pagination.Index}-{pagination.PageSize}-{pagination.Page}").Value;
|
||||
|
||||
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
|
||||
|
||||
if(string.IsNullOrWhiteSpace(cached))
|
||||
if (string.IsNullOrWhiteSpace(cached))
|
||||
{
|
||||
var result = await service.GetProgrammesAsync(pagination, cancellationToken);
|
||||
|
||||
@@ -168,6 +191,9 @@ public sealed class ProjectCacheService(ProjectService service, IDistributedCach
|
||||
public async ValueTask<Result<Project>> GetProjectAsync(string projectIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Project>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetProjectAsync(projectIdHash, cancellationToken);
|
||||
|
||||
var cacheKey = HashService.ToMd5Hash($"getproject-{projectIdHash}").Value;
|
||||
|
||||
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
|
||||
@@ -189,6 +215,9 @@ public sealed class ProjectCacheService(ProjectService service, IDistributedCach
|
||||
public async ValueTask<Result<Indicator[]>> GetProjectIndicatorsAsync(string projectIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Indicator[]>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetProjectIndicatorsAsync(projectIdHash, cancellationToken);
|
||||
|
||||
var cacheKey = HashService.ToMd5Hash($"getprojectindicators-{projectIdHash}").Value;
|
||||
|
||||
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
|
||||
@@ -197,7 +226,7 @@ public sealed class ProjectCacheService(ProjectService service, IDistributedCach
|
||||
{
|
||||
var result = await service.GetProjectIndicatorsAsync(projectIdHash, cancellationToken);
|
||||
|
||||
if(result.IsFailed) return result;
|
||||
if (result.IsFailed) return result;
|
||||
|
||||
await cache.SetStringAsync(cacheKey, result.Value.ToJson(), cacheOptions, cancellationToken);
|
||||
|
||||
@@ -210,15 +239,18 @@ public sealed class ProjectCacheService(ProjectService service, IDistributedCach
|
||||
public async ValueTask<Result<Milestone[]>> GetProjectMilestonesAsync(string projectIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Milestone[]>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetProjectMilestonesAsync(projectIdHash, cancellationToken);
|
||||
|
||||
var cacheKey = HashService.ToMd5Hash($"getprojectmilestones-{projectIdHash}").Value;
|
||||
|
||||
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
|
||||
|
||||
if(string.IsNullOrWhiteSpace(cached))
|
||||
if (string.IsNullOrWhiteSpace(cached))
|
||||
{
|
||||
var result = await service.GetProjectMilestonesAsync(projectIdHash, cancellationToken);
|
||||
|
||||
if(result.IsFailed) return result;
|
||||
if (result.IsFailed) return result;
|
||||
|
||||
await cache.SetStringAsync(cacheKey, result.Value.ToJson(), cacheOptions, cancellationToken);
|
||||
|
||||
@@ -231,6 +263,9 @@ public sealed class ProjectCacheService(ProjectService service, IDistributedCach
|
||||
public async ValueTask<Result<Risk[]>> GetProjectRisksAsync(string projectIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Risk[]>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetProjectRisksAsync(projectIdHash, cancellationToken);
|
||||
|
||||
var cacheKey = HashService.ToMd5Hash($"getprojectrisks-{projectIdHash}").Value;
|
||||
|
||||
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
|
||||
@@ -239,7 +274,7 @@ public sealed class ProjectCacheService(ProjectService service, IDistributedCach
|
||||
{
|
||||
var result = await service.GetProjectRisksAsync(projectIdHash, cancellationToken);
|
||||
|
||||
if(result.IsFailed) return result;
|
||||
if (result.IsFailed) return result;
|
||||
|
||||
await cache.SetStringAsync(cacheKey, result.Value.ToJson(), cacheOptions, cancellationToken);
|
||||
|
||||
@@ -252,6 +287,9 @@ public sealed class ProjectCacheService(ProjectService service, IDistributedCach
|
||||
public async ValueTask<Result<Project[]>> GetProjectsAsync(Pagination pagination, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Project[]>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetProjectsAsync(pagination, cancellationToken);
|
||||
|
||||
var cacheKey = HashService.ToMd5Hash($"getprojects-{pagination.Index}-{pagination.Page}-{pagination.PageSize}").Value;
|
||||
|
||||
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
|
||||
@@ -260,7 +298,7 @@ public sealed class ProjectCacheService(ProjectService service, IDistributedCach
|
||||
{
|
||||
var result = await service.GetProjectsAsync(pagination, cancellationToken);
|
||||
|
||||
if(result.IsFailed) return result;
|
||||
if (result.IsFailed) return result;
|
||||
|
||||
await cache.SetStringAsync(cacheKey, result.Value.ToJson(), cacheOptions, cancellationToken);
|
||||
|
||||
|
||||
@@ -1,14 +1,19 @@
|
||||
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) : ServiceCacheBase, IToolService
|
||||
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);
|
||||
|
||||
@@ -4,14 +4,19 @@ using PostFundManagement.Application.Extensions;
|
||||
using PostFundManagement.Application.Services.Shared;
|
||||
using PostFundManagement.Domain;
|
||||
using PostFundManagement.Domain.Models;
|
||||
using static PostFundManagement.Domain.Extensions.Constants;
|
||||
|
||||
namespace PostFundManagement.Application.Services.Users;
|
||||
|
||||
public sealed class UserCacheService(UserService service, IDistributedCache cache) : ServiceCacheBase, IUserService
|
||||
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 () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetUserAsync(userId, cancellationToken);
|
||||
|
||||
var cacheKey = HashService.ToMd5Hash($"getuser-{userId}").Value;
|
||||
|
||||
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
|
||||
@@ -33,6 +38,9 @@ public sealed class UserCacheService(UserService service, IDistributedCache cach
|
||||
public async ValueTask<Result<User[]>> GetUsersAsync(Pagination pagination, UserFilterRequest request, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<User[]>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetUsersAsync(pagination, request, cancellationToken);
|
||||
|
||||
var cacheKey = HashService.ToMd5Hash($"getusers-{pagination.Page}-{pagination.PageSize}-" +
|
||||
$"{request.Email}-{request.Status}-{request.SortBy}-{request.SortDescending}").Value;
|
||||
|
||||
|
||||
@@ -16,3 +16,13 @@ VITE_OIDC_CLIENT_SECRET="secret_71f88570a46eb22eb5270b47f69e3332c84d8db85d008f02
|
||||
|
||||
# PFM Backend API Base URL
|
||||
VITE_API_BASE_URL="https://api.ifri.khongisa.co.za/"
|
||||
|
||||
# Protocol / SSL Settings for local development
|
||||
# HTTPS is enabled by default when running locally via @vitejs/plugin-basic-ssl.
|
||||
# Set to 'false' if you ever need to run local dev over plain HTTP.
|
||||
HTTPS="true"
|
||||
VITE_ENABLE_HTTPS="true"
|
||||
|
||||
# HasherSettings for HashIds compatibility with backend pfm-api
|
||||
VITE_HASHER_MIN_LENGTH="11"
|
||||
VITE_HASHER_SALT="TGlnaHQgQ2hhcm1zLCBNaWRyYW5kQm9va3MgbWFrZSBsb3RzIG9mIG1vbmV5IGFuZCBhcmUgYSBzdWNjZXNzZnVsIHZpcmFsIHN0b3J5IGluIFNvdXRoIEFmcmljYQ=="
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
<div align="center">
|
||||
<img width="1200" height="475" alt="GHBanner" src="https://ai.google.dev/static/site-assets/images/share-ais-513315318.png" />
|
||||
</div>
|
||||
|
||||
# Run and deploy your AI Studio app
|
||||
|
||||
This contains everything you need to run your app locally.
|
||||
|
||||
View your app in AI Studio: https://ai.studio/apps/b2519d4f-e797-44fe-be2e-0d30bec6814d
|
||||
|
||||
## Run Locally
|
||||
|
||||
**Prerequisites:** Node.js
|
||||
|
||||
|
||||
1. Install dependencies:
|
||||
`npm install`
|
||||
2. Set the `GEMINI_API_KEY` in [.env.local](.env.local) to your Gemini API key
|
||||
3. Run the app:
|
||||
`npm run dev`
|
||||
File diff suppressed because it is too large
Load Diff
+717
-3573
File diff suppressed because it is too large
Load Diff
@@ -1,19 +0,0 @@
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
pfm-console:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
container_name: pfm-console
|
||||
ports:
|
||||
- "8076:3000"
|
||||
environment:
|
||||
# OIDC Identity Provider Configuration
|
||||
- OIDC_AUTHORITY=${OIDC_AUTHORITY}
|
||||
- OIDC_AUDIENCE=${OIDC_AUDIENCE}
|
||||
- OIDC_CLIENT_ID=${OIDC_CLIENT_ID}
|
||||
- OIDC_CLIENT_SECRET=${OIDC_CLIENT_SECRET}
|
||||
# Backend API Configuration
|
||||
- API_BASE_URL=${API_BASE_URL}
|
||||
restart: unless-stopped
|
||||
@@ -1,4 +1,102 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
# Target directory for Nginx static assets in container
|
||||
TARGET_DIR="/usr/share/nginx/html"
|
||||
|
||||
# If not in standard nginx container, fallback to ./dist or ./public if present
|
||||
if [ ! -d "$TARGET_DIR" ]; then
|
||||
if [ -d "./dist" ]; then
|
||||
TARGET_DIR="./dist"
|
||||
elif [ -d "./public" ]; then
|
||||
TARGET_DIR="./public"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Prioritize deployment environment variables from all common naming patterns:
|
||||
# 1. API Base URL
|
||||
API_BASE_URL="${VITE_API_BASE_URL:-${API_BASE_URL:-${ApiSettings__BaseUrl:-${ApiSettings_BaseUrl:-${PFM_API_BASE_URL:-}}}}}"
|
||||
|
||||
# 2. OIDC Security Authority
|
||||
OIDC_AUTHORITY="${VITE_OIDC_AUTHORITY:-${OIDC_AUTHORITY:-${SecuritySettings__Authority:-${SecuritySettings_Authority:-${AUTHORITY:-}}}}}"
|
||||
|
||||
# 3. OIDC Audience
|
||||
OIDC_AUDIENCE="${VITE_OIDC_AUDIENCE:-${OIDC_AUDIENCE:-${SecuritySettings__Audience:-${SecuritySettings_Audience:-${AUDIENCE:-}}}}}"
|
||||
|
||||
# 4. OIDC Client ID
|
||||
OIDC_CLIENT_ID="${VITE_OIDC_CLIENT_ID:-${OIDC_CLIENT_ID:-${SecuritySettings__ClientId:-${SecuritySettings_ClientId:-${CLIENT_ID:-}}}}}"
|
||||
|
||||
# 5. OIDC Client Secret
|
||||
OIDC_CLIENT_SECRET="${VITE_OIDC_CLIENT_SECRET:-${OIDC_CLIENT_SECRET:-${SecuritySettings__ClientSecret:-${SecuritySettings_ClientSecret:-${CLIENT_SECRET:-}}}}}"
|
||||
|
||||
# 6. OIDC Scope
|
||||
OIDC_SCOPE="${VITE_OIDC_SCOPE:-${OIDC_SCOPE:-${SecuritySettings__Scope:-${SecuritySettings_Scope:-${SCOPE:-}}}}}"
|
||||
|
||||
# 7. Hasher Settings
|
||||
HASHER_SALT="${VITE_HASHER_SALT:-${HASHER_SALT:-${HasherSettings__Salt:-${HasherSettings_Salt:-}}}}}"
|
||||
HASHER_MIN_LENGTH="${VITE_HASHER_MIN_LENGTH:-${HASHER_MIN_LENGTH:-${HasherSettings__MinLength:-${HasherSettings_MinLength:-}}}}}"
|
||||
|
||||
if [ -d "$TARGET_DIR" ]; then
|
||||
echo "[docker-entrypoint] Generating runtime configuration files in $TARGET_DIR..."
|
||||
|
||||
# Generate env-config.js for instant, synchronous window.__RUNTIME_CONFIG__ initialization
|
||||
cat <<EOF > "$TARGET_DIR/env-config.js"
|
||||
// Generated dynamically at container startup from deployment environment variables
|
||||
window.__RUNTIME_CONFIG__ = {
|
||||
API_BASE_URL: "${API_BASE_URL}",
|
||||
VITE_API_BASE_URL: "${API_BASE_URL}",
|
||||
OIDC_AUTHORITY: "${OIDC_AUTHORITY}",
|
||||
VITE_OIDC_AUTHORITY: "${OIDC_AUTHORITY}",
|
||||
OIDC_AUDIENCE: "${OIDC_AUDIENCE}",
|
||||
VITE_OIDC_AUDIENCE: "${OIDC_AUDIENCE}",
|
||||
OIDC_CLIENT_ID: "${OIDC_CLIENT_ID}",
|
||||
VITE_OIDC_CLIENT_ID: "${OIDC_CLIENT_ID}",
|
||||
OIDC_CLIENT_SECRET: "${OIDC_CLIENT_SECRET}",
|
||||
VITE_OIDC_CLIENT_SECRET: "${OIDC_CLIENT_SECRET}",
|
||||
OIDC_SCOPE: "${OIDC_SCOPE}",
|
||||
VITE_OIDC_SCOPE: "${OIDC_SCOPE}",
|
||||
HASHER_SALT: "${HASHER_SALT}",
|
||||
VITE_HASHER_SALT: "${HASHER_SALT}",
|
||||
HASHER_MIN_LENGTH: "${HASHER_MIN_LENGTH}",
|
||||
VITE_HASHER_MIN_LENGTH: "${HASHER_MIN_LENGTH}",
|
||||
ApiSettings: {
|
||||
BaseUrl: "${API_BASE_URL}"
|
||||
},
|
||||
SecuritySettings: {
|
||||
Authority: "${OIDC_AUTHORITY}",
|
||||
Audience: "${OIDC_AUDIENCE}",
|
||||
ClientId: "${OIDC_CLIENT_ID}",
|
||||
ClientSecret: "${OIDC_CLIENT_SECRET}",
|
||||
Scope: "${OIDC_SCOPE}"
|
||||
},
|
||||
HasherSettings: {
|
||||
Salt: "${HASHER_SALT}",
|
||||
MinHashLength: "${HASHER_MIN_LENGTH}"
|
||||
}
|
||||
};
|
||||
EOF
|
||||
|
||||
# Generate config.json for REST-based runtime retrieval
|
||||
cat <<EOF > "$TARGET_DIR/config.json"
|
||||
{
|
||||
"ApiSettings": {
|
||||
"BaseUrl": "${API_BASE_URL}"
|
||||
},
|
||||
"SecuritySettings": {
|
||||
"Authority": "${OIDC_AUTHORITY}",
|
||||
"Audience": "${OIDC_AUDIENCE}",
|
||||
"ClientId": "${OIDC_CLIENT_ID}",
|
||||
"ClientSecret": "${OIDC_CLIENT_SECRET}",
|
||||
"Scope": "${OIDC_SCOPE}"
|
||||
},
|
||||
"HasherSettings": {
|
||||
"Salt": "${HASHER_SALT}",
|
||||
"MinHashLength": "${HASHER_MIN_LENGTH}"
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
echo "[docker-entrypoint] Successfully wrote $TARGET_DIR/env-config.js and $TARGET_DIR/config.json."
|
||||
fi
|
||||
|
||||
exec "$@"
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" fill="none">
|
||||
<defs>
|
||||
<!-- Ambient Radial Glow -->
|
||||
<radialGradient id="pfm-ambient-glow" cx="50%" cy="50%" r="50%">
|
||||
<stop offset="0%" stop-color="#38bdf8" stop-opacity="0.4" />
|
||||
<stop offset="70%" stop-color="#2563eb" stop-opacity="0.1" />
|
||||
<stop offset="100%" stop-color="#1e1b4b" stop-opacity="0" />
|
||||
</radialGradient>
|
||||
|
||||
<!-- Top facet: Governance & Portfolios (Indigo / Radiant Violet) -->
|
||||
<linearGradient id="pfm-grad-top" x1="12" y1="8" x2="52" y2="26" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0%" stop-color="#a5b4fc" />
|
||||
<stop offset="35%" stop-color="#6366f1" />
|
||||
<stop offset="100%" stop-color="#4338ca" />
|
||||
</linearGradient>
|
||||
|
||||
<!-- Left facet: Capital & Disbursement Vault (Electric Sapphire) -->
|
||||
<linearGradient id="pfm-grad-left" x1="10" y1="22" x2="30" y2="56" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0%" stop-color="#38bdf8" />
|
||||
<stop offset="45%" stop-color="#2563eb" />
|
||||
<stop offset="100%" stop-color="#1e40af" />
|
||||
</linearGradient>
|
||||
|
||||
<!-- Right facet: Milestones, Evidence & Impact Delivery (Cyan to Emerald) -->
|
||||
<linearGradient id="pfm-grad-right" x1="34" y1="28" x2="54" y2="56" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0%" stop-color="#22d3ee" />
|
||||
<stop offset="50%" stop-color="#06b6d4" />
|
||||
<stop offset="100%" stop-color="#10b981" />
|
||||
</linearGradient>
|
||||
|
||||
<!-- Center Radiant Diamond -->
|
||||
<linearGradient id="pfm-grad-core" x1="27" y1="27" x2="37" y2="37" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0%" stop-color="#ffffff" />
|
||||
<stop offset="40%" stop-color="#e0f2fe" />
|
||||
<stop offset="100%" stop-color="#38bdf8" />
|
||||
</linearGradient>
|
||||
|
||||
<!-- Soft outer glow filter -->
|
||||
<filter id="pfm-glow" x="-20%" y="-20%" width="140%" height="140%">
|
||||
<feGaussianBlur stdDeviation="1.5" result="blur" />
|
||||
<feComposite in="SourceGraphic" in2="blur" operator="over" />
|
||||
</filter>
|
||||
</defs>
|
||||
|
||||
<!-- Deep Contrast Foundation Disk for Dark & Light browser tabs -->
|
||||
<circle cx="32" cy="32" r="31" fill="#090d16" />
|
||||
<circle cx="32" cy="32" r="30" stroke="#1e293b" stroke-width="1" />
|
||||
<circle cx="32" cy="32" r="28" fill="url(#pfm-ambient-glow)" />
|
||||
|
||||
<!-- Outer Hexagonal Structural Shield Outline -->
|
||||
<path
|
||||
d="M32 6.5 L53.5 19 C55 19.8 56 21.5 56 23.2 L56 40.8 C56 42.5 55 44.2 53.5 45 L32 57.5 C30.5 58.3 28.5 58.3 27 57.5 L5.5 45 C4 44.2 3 42.5 3 40.8 L3 23.2 C3 21.5 4 19.8 5.5 19 L27 6.5 C28.5 5.7 30.5 5.7 32 6.5 Z"
|
||||
stroke="#3b82f6"
|
||||
stroke-opacity="0.3"
|
||||
stroke-width="1.2"
|
||||
fill="none"
|
||||
/>
|
||||
|
||||
<!-- Facet 1: Top Canopy (Governance / Oversight Architecture) -->
|
||||
<path
|
||||
d="M32 9 L51.5 20.2 L43 25.2 L32 18.8 L21 25.2 L12.5 20.2 Z"
|
||||
fill="url(#pfm-grad-top)"
|
||||
/>
|
||||
|
||||
<!-- Facet 2: Left Vault (Fund Management & Capital Allocation) -->
|
||||
<path
|
||||
d="M10 23 L19.2 28.4 L19.2 44.5 L30 50.8 L30 55.5 L10 43.8 Z"
|
||||
fill="url(#pfm-grad-left)"
|
||||
/>
|
||||
|
||||
<!-- Facet 3: Right Wing (Milestone Performance & Impact Assurance) -->
|
||||
<path
|
||||
d="M54 23 L54 43.8 L34 55.5 L34 50.8 L44.8 44.5 L44.8 28.4 Z"
|
||||
fill="url(#pfm-grad-right)"
|
||||
/>
|
||||
|
||||
<!-- Center Geometric Hub (The PFM Nexus Plate) -->
|
||||
<path
|
||||
d="M22 28.5 L32 22.8 L42 28.5 L42 35.5 L32 41.2 L22 35.5 Z"
|
||||
fill="#0b1120"
|
||||
stroke="#334155"
|
||||
stroke-width="1"
|
||||
/>
|
||||
|
||||
<!-- Kinetic Stepped Prisms -->
|
||||
<path
|
||||
d="M25 31.5 L32 27.5 L39 31.5 L32 35.5 Z"
|
||||
fill="url(#pfm-grad-top)"
|
||||
opacity="0.9"
|
||||
/>
|
||||
<path
|
||||
d="M25 37 L32 41 L39 37 L32 33 L25 37 Z"
|
||||
fill="url(#pfm-grad-right)"
|
||||
opacity="0.9"
|
||||
/>
|
||||
|
||||
<!-- Center Radiant Milestone Diamond -->
|
||||
<polygon
|
||||
points="32,27 36.5,32 32,37 27.5,32"
|
||||
fill="url(#pfm-grad-core)"
|
||||
filter="url(#pfm-glow)"
|
||||
/>
|
||||
|
||||
<!-- Center Pure White Optical Star Point -->
|
||||
<circle cx="32" cy="32" r="1.5" fill="#ffffff" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.8 KiB |
@@ -1,6 +1,6 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Post Fund Management Console</title>
|
||||
@@ -9,10 +9,18 @@
|
||||
<meta property="og:description" content="Enterprise backoffice portal for Funders to manage portfolios, programmes, projects, grants, disbursements, and evidence workflows." />
|
||||
<meta property="og:type" content="website" />
|
||||
<meta name="twitter:card" content="summary_large_image" />
|
||||
</head>
|
||||
<body>
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||
<link rel="alternate icon" href="/favicon.svg" />
|
||||
<link rel="mask-icon" href="/favicon.svg" color="#2563eb" />
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600;700&family=Plus+Jakarta+Sans:wght@300;400;500;600;700;800&display=swap" rel="stylesheet" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<!-- Runtime Environment Configuration (Populated dynamically during deployment) -->
|
||||
<script src="/env-config.js"></script>
|
||||
<script type="module" src="/src/main.tsx"></script>
|
||||
</body>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
@@ -2,5 +2,5 @@
|
||||
"name": "Post Fund Management Console",
|
||||
"description": "Enterprise backoffice portal for Funders to manage portfolios, programmes, projects, grants, disbursements, and evidence workflows.",
|
||||
"requestFramePermissions": [],
|
||||
"majorCapabilities": [ "MAJOR_CAPABILITY_SERVER_SIDE_GEMINI_API" ]
|
||||
"majorCapabilities": ["MAJOR_CAPABILITY_SERVER_SIDE_GEMINI_API"]
|
||||
}
|
||||
|
||||
@@ -12,17 +12,17 @@ server {
|
||||
gzip_proxied expired no-cache no-store private auth;
|
||||
gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/xml application/json image/svg+xml;
|
||||
|
||||
# Cache control for static assets
|
||||
location ~* \.(?:css|js|jpg|jpeg|gif|png|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm|htc)$ {
|
||||
expires 1y;
|
||||
access_log off;
|
||||
add_header Cache-Control "public";
|
||||
# Never cache dynamic runtime configuration files or index.html
|
||||
location ~* ^/(?:config\.json|env-config\.js|index\.html)$ {
|
||||
expires -1;
|
||||
add_header Cache-Control "no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0";
|
||||
}
|
||||
|
||||
# Disable caching for appsettings.json so changes take effect immediately
|
||||
location = /appsettings.json {
|
||||
expires -1;
|
||||
add_header Cache-Control "no-store, no-cache, must-revalidate, post-check=0, pre-check=0";
|
||||
# Cache control for static assets (CSS, JS, fonts, images)
|
||||
location ~* \.(?:css|js|jpg|jpeg|gif|png|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm|htc|woff|woff2|ttf|eot)$ {
|
||||
expires 1y;
|
||||
access_log off;
|
||||
add_header Cache-Control "public, immutable";
|
||||
}
|
||||
|
||||
# HTML5 SPA History Mode Support
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user