Finishline #92
@@ -0,0 +1,38 @@
|
||||
using PostFundManagement.Application.Abstractions.Services;
|
||||
using PostFundManagement.Application.Extensions;
|
||||
using PostFundManagement.Domain.Abstractions;
|
||||
using PostFundManagement.Domain.Errors;
|
||||
using PostFundManagement.Domain.Extensions;
|
||||
using PostFundManagement.Domain.Models;
|
||||
using PostFundManagement.Domain.Security;
|
||||
using static PostFundManagement.Application.Extensions.General;
|
||||
using Problems = Microsoft.AspNetCore.Mvc.ProblemDetails;
|
||||
|
||||
namespace PostFundManagement.Api.Endpoints.Communications;
|
||||
|
||||
[ApiVersionTarget(1)]
|
||||
public sealed class GetNotificationsEndpoint : IEndpoint
|
||||
{
|
||||
public void Map(IEndpointRouteBuilder builder)
|
||||
{
|
||||
builder.MapGet("api/communications/invites/{organisationId}", async (string organisationId,
|
||||
ICommunicationsService service, CancellationToken cancellationToken = default) =>
|
||||
await service.GetNotificationsAsync(organisationId, cancellationToken) switch
|
||||
{
|
||||
{ IsSuccess: true, Value: var notifications } => Results.Ok(notifications),
|
||||
var r when r.HasError<IdDecodeError>() => Results.Forbid(),
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems()),
|
||||
})
|
||||
.WithDescription("Retrieves the notification system report")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(GetNotificationsEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces<Notification[]>(StatusCodes.Status200OK)
|
||||
.Produces(StatusCodes.Status403Forbidden)
|
||||
.Produces(StatusCodes.Status401Unauthorized)
|
||||
.Produces<Notification[]>(StatusCodes.Status404NotFound)
|
||||
.Produces<Problems>(StatusCodes.Status500InternalServerError)
|
||||
.WithTags(EndpointTags.Communications)
|
||||
.CacheOutput();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
using PostFundManagement.Application.Abstractions.Services;
|
||||
using PostFundManagement.Application.Extensions;
|
||||
using PostFundManagement.Application.Services.Governance;
|
||||
using PostFundManagement.Domain.Abstractions;
|
||||
using PostFundManagement.Domain.Errors;
|
||||
using PostFundManagement.Domain.Extensions;
|
||||
using PostFundManagement.Domain.Security;
|
||||
using Problems = Microsoft.AspNetCore.Mvc.ProblemDetails;
|
||||
|
||||
namespace PostFundManagement.Api.Endpoints.Governance;
|
||||
|
||||
[ApiVersionTarget(1)]
|
||||
public sealed class CreateTenantEndpoint : IEndpoint
|
||||
{
|
||||
public void Map(IEndpointRouteBuilder builder)
|
||||
{
|
||||
builder.MapPost("api/governance/tenants", async (CreateTenantRequest request, IGovernanceService service, HttpContext context,
|
||||
CancellationToken cancellationToken = default) =>
|
||||
await service.CreateTenantAsync(request, context.GetUserId(), cancellationToken) switch
|
||||
{
|
||||
{ IsSuccess: true } => Results.Ok(),
|
||||
var r when r.HasError<ValidationError>() => Results.BadRequest(r.Errors.ToProblems()),
|
||||
var r when r.HasError<CreateError>() => Results.BadRequest(r.Errors.ToProblems()),
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Create a new tenant")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(CreateTenantEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces(StatusCodes.Status200OK)
|
||||
.Produces(StatusCodes.Status401Unauthorized)
|
||||
.Produces<Problems>(StatusCodes.Status400BadRequest)
|
||||
.Produces<Problems>(StatusCodes.Status500InternalServerError)
|
||||
.WithTags(EndpointTags.Governance);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
using PostFundManagement.Application.Abstractions.Services;
|
||||
using PostFundManagement.Application.Extensions;
|
||||
using PostFundManagement.Domain.Abstractions;
|
||||
using PostFundManagement.Domain.Errors;
|
||||
using PostFundManagement.Domain.Extensions;
|
||||
using PostFundManagement.Domain.Models;
|
||||
using PostFundManagement.Domain.Security;
|
||||
using Problems = Microsoft.AspNetCore.Mvc.ProblemDetails;
|
||||
|
||||
namespace PostFundManagement.Api.Endpoints.Governance;
|
||||
|
||||
[ApiVersionTarget(1)]
|
||||
public sealed class GetTenantEndpoint : IEndpoint
|
||||
{
|
||||
public void Map(IEndpointRouteBuilder builder)
|
||||
{
|
||||
builder.MapGet("api/governance/tenants/{tenantId}", async (string tenantId, IGovernanceService service,
|
||||
CancellationToken cancellationToken = default) =>
|
||||
await service.GetTenantAsync(tenantId, cancellationToken) switch
|
||||
{
|
||||
{ IsSuccess: true, Value: var tenant } => Results.Ok(tenant),
|
||||
var r when r.HasError<IdDecodeError>() => Results.Forbid(),
|
||||
var r when r.HasError<NotFoundError>() => Results.NotFound(r.Errors.ToProblems()),
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Gets system tenants")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(GetTenantsEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces<Tenant>(StatusCodes.Status200OK)
|
||||
.Produces(StatusCodes.Status403Forbidden)
|
||||
.Produces(StatusCodes.Status401Unauthorized)
|
||||
.Produces<Problems>(StatusCodes.Status404NotFound)
|
||||
.Produces<Problems>(StatusCodes.Status500InternalServerError)
|
||||
.WithTags(EndpointTags.Governance);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
using PostFundManagement.Application.Abstractions.Services;
|
||||
using PostFundManagement.Application.Extensions;
|
||||
using PostFundManagement.Domain.Abstractions;
|
||||
using PostFundManagement.Domain.Entities;
|
||||
using PostFundManagement.Domain.Extensions;
|
||||
using PostFundManagement.Domain.Security;
|
||||
using Problems = Microsoft.AspNetCore.Mvc.ProblemDetails;
|
||||
|
||||
namespace PostFundManagement.Api.Endpoints.Governance;
|
||||
|
||||
[ApiVersionTarget(1)]
|
||||
public sealed class GetTenantsEndpoint : IEndpoint
|
||||
{
|
||||
public void Map(IEndpointRouteBuilder builder)
|
||||
{
|
||||
builder.MapGet("api/governance/tenants", async (IGovernanceService service,
|
||||
CancellationToken cancellationToken = default) =>
|
||||
await service.GetTenantsAsync(cancellationToken) switch
|
||||
{
|
||||
{ IsSuccess: true, Value: var tenants } => Results.Ok(tenants),
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Gets system tenants")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(GetTenantsEndpoint).ToEndpointName("Retrieval"))
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces<Tenant[]>(StatusCodes.Status200OK)
|
||||
.Produces(StatusCodes.Status401Unauthorized)
|
||||
.Produces<Problems>(StatusCodes.Status500InternalServerError)
|
||||
.WithTags(EndpointTags.Governance);
|
||||
}
|
||||
}
|
||||
@@ -15,11 +15,13 @@ public sealed class UpdateOrganisationEndpoint : IEndpoint
|
||||
public void Map(IEndpointRouteBuilder builder)
|
||||
{
|
||||
builder.MapPut("api/governance/organisations", async (UpdateOrganisationRequest request,
|
||||
IGovernanceService service, CancellationToken cancellationToken = default) =>
|
||||
await service.UpdateOrganisationAsync(request, cancellationToken) switch
|
||||
IGovernanceService service, HttpContext context, CancellationToken cancellationToken = default) =>
|
||||
await service.UpdateOrganisationAsync(request, context.GetUserId(), cancellationToken) switch
|
||||
{
|
||||
{ IsSuccess: true } => Results.Ok(),
|
||||
var r when r.HasError<IdDecodeError>() => Results.Forbid(),
|
||||
var r when r.HasError<UpdateError>() => Results.BadRequest(r.Errors.ToProblems()),
|
||||
var r when r.HasError<ValidationError>() => Results.BadRequest(r.Errors.ToProblems()),
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Update an existing organization profile")
|
||||
@@ -27,10 +29,10 @@ public sealed class UpdateOrganisationEndpoint : IEndpoint
|
||||
.WithName(typeof(UpdateOrganisationEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces(StatusCodes.Status200OK)
|
||||
.Produces(StatusCodes.Status404NotFound)
|
||||
.Produces(StatusCodes.Status403Forbidden)
|
||||
.Produces(StatusCodes.Status401Unauthorized)
|
||||
.Produces<Problems>(StatusCodes.Status400BadRequest)
|
||||
.Produces<Problems>(StatusCodes.Status500InternalServerError)
|
||||
.Produces(StatusCodes.Status401Unauthorized)
|
||||
.WithTags(EndpointTags.Governance);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
using PostFundManagement.Application.Abstractions.Services;
|
||||
using PostFundManagement.Application.Extensions;
|
||||
using PostFundManagement.Application.Services.Governance;
|
||||
using PostFundManagement.Domain.Abstractions;
|
||||
using PostFundManagement.Domain.Errors;
|
||||
using PostFundManagement.Domain.Extensions;
|
||||
using PostFundManagement.Domain.Security;
|
||||
using Problems = Microsoft.AspNetCore.Mvc.ProblemDetails;
|
||||
|
||||
namespace PostFundManagement.Api.Endpoints.Governance;
|
||||
|
||||
[ApiVersionTarget(1)]
|
||||
public sealed class UpdateTenantEndpoint : IEndpoint
|
||||
{
|
||||
public void Map(IEndpointRouteBuilder builder)
|
||||
{
|
||||
builder.MapPut("api/governance/tenants", async (UpdateTenantRequest request, HttpContext context,
|
||||
IGovernanceService service, CancellationToken cancellationToken = default) =>
|
||||
await service.UpdateTenantAsync(request, context.GetUserId(), cancellationToken) switch
|
||||
{
|
||||
{ IsSuccess: true } => Results.Ok(),
|
||||
var r when r.HasError<ValidationError>() => Results.BadRequest(r.Errors.ToProblems()),
|
||||
var r when r.HasError<UpdateError>() => Results.BadRequest(r.Errors.ToProblems()),
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Updates a specific tenant")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(UpdateTenantEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces(StatusCodes.Status200OK)
|
||||
.Produces(StatusCodes.Status401Unauthorized)
|
||||
.Produces<Problems>(StatusCodes.Status400BadRequest)
|
||||
.Produces<Problems>(StatusCodes.Status500InternalServerError)
|
||||
.WithTags(EndpointTags.Governance);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
using PostFundManagement.Application.Abstractions.Services;
|
||||
using PostFundManagement.Application.Extensions;
|
||||
using PostFundManagement.Application.Services.Projects;
|
||||
using PostFundManagement.Domain.Abstractions;
|
||||
using PostFundManagement.Domain.Errors;
|
||||
using PostFundManagement.Domain.Extensions;
|
||||
using PostFundManagement.Domain.Security;
|
||||
using Problems = Microsoft.AspNetCore.Mvc.ProblemDetails;
|
||||
|
||||
namespace PostFundManagement.Api.Endpoints.Projects;
|
||||
|
||||
[ApiVersionTarget(1)]
|
||||
public sealed class CreateBeneficiaryEndpoint : IEndpoint
|
||||
{
|
||||
public void Map(IEndpointRouteBuilder builder)
|
||||
{
|
||||
builder.MapPost("api/projects/beneficiaries", async (CreateBeneficiaryRequest request, HttpContext context,
|
||||
IProjectService service, CancellationToken cancellationToken = default) =>
|
||||
await service.CreateBeneficiaryAsync(request, context.GetUserId(), cancellationToken) switch
|
||||
{
|
||||
{ IsSuccess: true } => Results.Ok(),
|
||||
var r when r.HasError<CreateError>() => Results.BadRequest(r.Errors.ToProblems()),
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Add a new project beneficiary")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(CreateBeneficiaryEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces(StatusCodes.Status200OK)
|
||||
.Produces<Problems>(StatusCodes.Status400BadRequest)
|
||||
.Produces<Problems>(StatusCodes.Status500InternalServerError)
|
||||
.Produces(StatusCodes.Status401Unauthorized)
|
||||
.WithTags(EndpointTags.Projects);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
using PostFundManagement.Application.Abstractions.Services;
|
||||
using PostFundManagement.Application.Extensions;
|
||||
using PostFundManagement.Application.Services.Projects;
|
||||
using PostFundManagement.Domain.Abstractions;
|
||||
using PostFundManagement.Domain.Errors;
|
||||
using PostFundManagement.Domain.Extensions;
|
||||
using PostFundManagement.Domain.Security;
|
||||
using Problems = Microsoft.AspNetCore.Mvc.ProblemDetails;
|
||||
|
||||
namespace PostFundManagement.Api.Endpoints.Projects;
|
||||
|
||||
[ApiVersionTarget(1)]
|
||||
public sealed class CreateChangeRequestEndpoint : IEndpoint
|
||||
{
|
||||
public void Map(IEndpointRouteBuilder builder)
|
||||
{
|
||||
builder.MapPost("api/projects/changerequests", async (CreateChangeRequest request, IProjectService service,
|
||||
HttpContext context, CancellationToken cancellationToken = default) =>
|
||||
await service.CreateChangeRequestAsync(request, context.GetUserId(), cancellationToken) switch
|
||||
{
|
||||
{ IsSuccess: true } => Results.Ok(),
|
||||
var r when r.HasError<IdDecodeError>() => Results.Forbid(),
|
||||
var r when r.HasError<ValidationError>() => Results.BadRequest(r.Errors.ToProblems()),
|
||||
var r when r.HasError<CreateError>() => Results.BadRequest(r.Errors.ToProblems()),
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems()),
|
||||
})
|
||||
.WithDescription("Create a new change request against an existing project")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(CreateChangeRequestEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces(StatusCodes.Status200OK)
|
||||
.Produces(StatusCodes.Status403Forbidden)
|
||||
.Produces(StatusCodes.Status401Unauthorized)
|
||||
.Produces<Problems>(StatusCodes.Status400BadRequest)
|
||||
.Produces<Problems>(StatusCodes.Status500InternalServerError)
|
||||
.WithTags(EndpointTags.Projects);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
using PostFundManagement.Application.Abstractions.Services;
|
||||
using PostFundManagement.Application.Extensions;
|
||||
using PostFundManagement.Application.Services.Projects;
|
||||
using PostFundManagement.Domain.Abstractions;
|
||||
using PostFundManagement.Domain.Errors;
|
||||
using PostFundManagement.Domain.Extensions;
|
||||
using PostFundManagement.Domain.Security;
|
||||
using Problems = Microsoft.AspNetCore.Mvc.ProblemDetails;
|
||||
|
||||
namespace PostFundManagement.Api.Endpoints.Projects;
|
||||
|
||||
[ApiVersionTarget(1)]
|
||||
public sealed class CreateComplianceItemEndpoint : IEndpoint
|
||||
{
|
||||
public void Map(IEndpointRouteBuilder builder)
|
||||
{
|
||||
builder.MapPost("api/projects/complianceitems", async (CreateComplianceItemRequest request, HttpContext context,
|
||||
IProjectService service, CancellationToken cancellationToken = default) =>
|
||||
await service.CreateComplianceItemAsync(request, context.GetUserId(), cancellationToken) switch
|
||||
{
|
||||
{ IsSuccess: true } => Results.Ok(),
|
||||
var r when r.HasError<ValidationError>() => Results.BadRequest(r.Errors.ToProblems()),
|
||||
var r when r.HasError<CreateError>() => Results.BadRequest(r.Errors.ToProblems()),
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Add a new beneficiary compliance item")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(CreateComplianceItemEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces(StatusCodes.Status200OK)
|
||||
.Produces<Problems>(StatusCodes.Status400BadRequest)
|
||||
.Produces<Problems>(StatusCodes.Status500InternalServerError)
|
||||
.Produces(StatusCodes.Status401Unauthorized)
|
||||
.WithTags(EndpointTags.Projects);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
using PostFundManagement.Application.Abstractions.Services;
|
||||
using PostFundManagement.Application.Extensions;
|
||||
using PostFundManagement.Application.Services.Projects;
|
||||
using PostFundManagement.Domain.Abstractions;
|
||||
using PostFundManagement.Domain.Errors;
|
||||
using PostFundManagement.Domain.Extensions;
|
||||
using PostFundManagement.Domain.Security;
|
||||
using Problems = Microsoft.AspNetCore.Mvc.ProblemDetails;
|
||||
|
||||
namespace PostFundManagement.Api.Endpoints.Projects;
|
||||
|
||||
[ApiVersionTarget(1)]
|
||||
public sealed class CreateIssueEndpoint : IEndpoint
|
||||
{
|
||||
public void Map(IEndpointRouteBuilder builder)
|
||||
{
|
||||
builder.MapPost("api/projects/issues", async (CreateIssueRequest request, HttpContext context,
|
||||
IProjectService service, CancellationToken cancellationToken = default) =>
|
||||
await service.CreateIssueAsync(request, context.GetUserId(), cancellationToken) switch
|
||||
{
|
||||
{ IsSuccess: true } => Results.Ok(),
|
||||
var r when r.HasError<CreateError>() => Results.BadRequest(r.Errors.ToProblems()),
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Add a new project issue")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(CreateIssueEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces(StatusCodes.Status200OK)
|
||||
.Produces<Problems>(StatusCodes.Status400BadRequest)
|
||||
.Produces<Problems>(StatusCodes.Status500InternalServerError)
|
||||
.Produces(StatusCodes.Status401Unauthorized)
|
||||
.WithTags(EndpointTags.Projects);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
using PostFundManagement.Application.Abstractions.Services;
|
||||
using PostFundManagement.Application.Extensions;
|
||||
using PostFundManagement.Application.Services.Projects;
|
||||
using PostFundManagement.Domain.Abstractions;
|
||||
using PostFundManagement.Domain.Errors;
|
||||
using PostFundManagement.Domain.Extensions;
|
||||
using PostFundManagement.Domain.Security;
|
||||
using Problems = Microsoft.AspNetCore.Mvc.ProblemDetails;
|
||||
|
||||
namespace PostFundManagement.Api.Endpoints.Projects;
|
||||
|
||||
[ApiVersionTarget(1)]
|
||||
public sealed class CreateOutcomeEndpoint : IEndpoint
|
||||
{
|
||||
public void Map(IEndpointRouteBuilder builder)
|
||||
{
|
||||
builder.MapPost("api/projects/beneficiaris/outcomes", async (CreateOutcomeRequest request, HttpContext context,
|
||||
IProjectService service, CancellationToken cancellationToken = default) =>
|
||||
await service.CreateOutcomeAsync(request, context.GetUserId(), cancellationToken) switch
|
||||
{
|
||||
{ IsSuccess: true } => Results.Ok(),
|
||||
var r when r.HasError<CreateError>() => Results.BadRequest(r.Errors.ToProblems()),
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Add a new beneficiary outcome")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(CreateOutcomeEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces(StatusCodes.Status200OK)
|
||||
.Produces<Problems>(StatusCodes.Status400BadRequest)
|
||||
.Produces<Problems>(StatusCodes.Status500InternalServerError)
|
||||
.Produces(StatusCodes.Status401Unauthorized)
|
||||
.WithTags(EndpointTags.Projects);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
using PostFundManagement.Application.Abstractions.Services;
|
||||
using PostFundManagement.Application.Extensions;
|
||||
using PostFundManagement.Application.Services.Projects;
|
||||
using PostFundManagement.Domain.Abstractions;
|
||||
using PostFundManagement.Domain.Errors;
|
||||
using PostFundManagement.Domain.Extensions;
|
||||
using PostFundManagement.Domain.Security;
|
||||
using Problems = Microsoft.AspNetCore.Mvc.ProblemDetails;
|
||||
|
||||
namespace PostFundManagement.Api.Endpoints.Projects;
|
||||
|
||||
[ApiVersionTarget(1)]
|
||||
public sealed class CreateSiteVisitEndpoint : IEndpoint
|
||||
{
|
||||
public void Map(IEndpointRouteBuilder builder)
|
||||
{
|
||||
builder.MapPost("api/projects/sitevisits", async (CreateSiteVisitRequest request, HttpContext context,
|
||||
IProjectService service, CancellationToken cancellationToken = default) =>
|
||||
await service.CreateSiteVisitAsync(request, context.GetUserId(), cancellationToken) switch
|
||||
{
|
||||
{ IsSuccess: true } => Results.Ok(),
|
||||
var r when r.HasError<CreateError>() => Results.BadRequest(r.Errors.ToProblems()),
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Add a new project site visit")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(CreateSiteVisitEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces(StatusCodes.Status200OK)
|
||||
.Produces<Problems>(StatusCodes.Status400BadRequest)
|
||||
.Produces<Problems>(StatusCodes.Status500InternalServerError)
|
||||
.Produces(StatusCodes.Status401Unauthorized)
|
||||
.WithTags(EndpointTags.Projects);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
using PostFundManagement.Application.Abstractions.Services;
|
||||
using PostFundManagement.Application.Extensions;
|
||||
using PostFundManagement.Domain.Abstractions;
|
||||
using PostFundManagement.Domain.Errors;
|
||||
using PostFundManagement.Domain.Extensions;
|
||||
using PostFundManagement.Domain.Models;
|
||||
using PostFundManagement.Domain.Security;
|
||||
using Problems = Microsoft.AspNetCore.Mvc.ProblemDetails;
|
||||
|
||||
namespace PostFundManagement.Api.Endpoints.Projects;
|
||||
|
||||
[ApiVersionTarget(1)]
|
||||
public sealed class GetBeneficiariesEndpoint : IEndpoint
|
||||
{
|
||||
public void Map(IEndpointRouteBuilder builder)
|
||||
{
|
||||
builder.MapGet("api/projects/beneficiaries/{projectId}", async (string projectId, IProjectService service,
|
||||
CancellationToken cancellationToken = default) =>
|
||||
await service.GetBeneficiariesAsync(projectId, cancellationToken) switch
|
||||
{
|
||||
{ IsSuccess: true, Value: var beneficiaries } => Results.Ok(beneficiaries),
|
||||
var r when r.HasError<IdDecodeError>() => Results.Forbid(),
|
||||
var r when r.HasError<NotFoundError>() => Results.NotFound(),
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Gets project beneficiaries")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(GetBeneficiariesEndpoint).ToEndpointName("Retrieval"))
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces<Beneficiary[]>(StatusCodes.Status200OK)
|
||||
.Produces(StatusCodes.Status404NotFound)
|
||||
.Produces(StatusCodes.Status403Forbidden)
|
||||
.Produces(StatusCodes.Status401Unauthorized)
|
||||
.Produces<Problems>(StatusCodes.Status500InternalServerError)
|
||||
.WithTags(EndpointTags.Projects)
|
||||
.CacheOutput();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
using PostFundManagement.Application.Abstractions.Services;
|
||||
using PostFundManagement.Application.Extensions;
|
||||
using PostFundManagement.Domain.Abstractions;
|
||||
using PostFundManagement.Domain.Errors;
|
||||
using PostFundManagement.Domain.Extensions;
|
||||
using PostFundManagement.Domain.Models;
|
||||
using PostFundManagement.Domain.Security;
|
||||
using Problems = Microsoft.AspNetCore.Mvc.ProblemDetails;
|
||||
|
||||
namespace PostFundManagement.Api.Endpoints.Projects;
|
||||
|
||||
[ApiVersionTarget(1)]
|
||||
public sealed class GetBeneficiaryEndpoint : IEndpoint
|
||||
{
|
||||
public void Map(IEndpointRouteBuilder builder)
|
||||
{
|
||||
builder.MapGet("api/projects/beneficiaries/{beneficiaryId}", async (string beneficiaryId, IProjectService service,
|
||||
CancellationToken cancellationToken = default) =>
|
||||
await service.GetBeneficiaryAsync(beneficiaryId, cancellationToken) switch
|
||||
{
|
||||
{ IsSuccess: true, Value: var beneficiary } => Results.Ok(beneficiary),
|
||||
var r when r.HasError<IdDecodeError>() => Results.Forbid(),
|
||||
var r when r.HasError<NotFoundError>() => Results.NotFound(),
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Gets project beneficiaries")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(GetBeneficiariesEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces<Beneficiary>(StatusCodes.Status200OK)
|
||||
.Produces(StatusCodes.Status404NotFound)
|
||||
.Produces(StatusCodes.Status403Forbidden)
|
||||
.Produces(StatusCodes.Status401Unauthorized)
|
||||
.Produces<Problems>(StatusCodes.Status500InternalServerError)
|
||||
.WithTags(EndpointTags.Projects)
|
||||
.CacheOutput();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
using PostFundManagement.Application.Abstractions.Services;
|
||||
using PostFundManagement.Application.Extensions;
|
||||
using PostFundManagement.Domain.Abstractions;
|
||||
using PostFundManagement.Domain.Errors;
|
||||
using PostFundManagement.Domain.Extensions;
|
||||
using PostFundManagement.Domain.Models;
|
||||
using PostFundManagement.Domain.Security;
|
||||
using Problems = Microsoft.AspNetCore.Mvc.ProblemDetails;
|
||||
|
||||
namespace PostFundManagement.Api.Endpoints.Projects;
|
||||
|
||||
[ApiVersionTarget(1)]
|
||||
public sealed class GetChangeRequestEndpoint : IEndpoint
|
||||
{
|
||||
public void Map(IEndpointRouteBuilder builder)
|
||||
{
|
||||
builder.MapGet("api/projects/changerequests/{changeRequestId}", async (string changeRequestId, IProjectService service,
|
||||
CancellationToken cancellationToken = default) =>
|
||||
await service.GetChangeRequestAsync(changeRequestId, cancellationToken) switch
|
||||
{
|
||||
{ IsSuccess: true, Value: var changeRequest } => Results.Ok(changeRequest),
|
||||
var r when r.HasError<IdDecodeError>() => Results.Forbid(),
|
||||
var r when r.HasError<NotFoundError>() => Results.NotFound(),
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Gets a specific project change request")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(GetChangeRequestEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces<ChangeRequest>(StatusCodes.Status200OK)
|
||||
.Produces(StatusCodes.Status404NotFound)
|
||||
.Produces(StatusCodes.Status403Forbidden)
|
||||
.Produces(StatusCodes.Status401Unauthorized)
|
||||
.Produces<Problems>(StatusCodes.Status500InternalServerError)
|
||||
.WithTags(EndpointTags.Projects)
|
||||
.CacheOutput();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
using PostFundManagement.Application.Abstractions.Services;
|
||||
using PostFundManagement.Application.Extensions;
|
||||
using PostFundManagement.Domain.Abstractions;
|
||||
using PostFundManagement.Domain.Errors;
|
||||
using PostFundManagement.Domain.Extensions;
|
||||
using PostFundManagement.Domain.Models;
|
||||
using PostFundManagement.Domain.Security;
|
||||
using Problems = Microsoft.AspNetCore.Mvc.ProblemDetails;
|
||||
|
||||
namespace PostFundManagement.Api.Endpoints.Projects;
|
||||
|
||||
[ApiVersionTarget(1)]
|
||||
public sealed class GetChangeRequestsEndpoint : IEndpoint
|
||||
{
|
||||
public void Map(IEndpointRouteBuilder builder)
|
||||
{
|
||||
builder.MapGet("api/projects/changerequests/{projectId}", async (string projectId, IProjectService service,
|
||||
CancellationToken cancellationToken = default) =>
|
||||
await service.GetChangeRequestsAsync(projectId, cancellationToken) switch
|
||||
{
|
||||
{ IsSuccess: true, Value: var changeRequests } => Results.Ok(changeRequests),
|
||||
var r when r.HasError<IdDecodeError>() => Results.Forbid(),
|
||||
var r when r.HasError<NotFoundError>() => Results.NotFound(),
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Gets project change requests")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(GetChangeRequestsEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces<ChangeRequest[]>(StatusCodes.Status200OK)
|
||||
.Produces(StatusCodes.Status404NotFound)
|
||||
.Produces(StatusCodes.Status403Forbidden)
|
||||
.Produces(StatusCodes.Status401Unauthorized)
|
||||
.Produces<Problems>(StatusCodes.Status500InternalServerError)
|
||||
.WithTags(EndpointTags.Projects)
|
||||
.CacheOutput();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
using PostFundManagement.Application.Abstractions.Services;
|
||||
using PostFundManagement.Application.Extensions;
|
||||
using PostFundManagement.Domain.Abstractions;
|
||||
using PostFundManagement.Domain.Errors;
|
||||
using PostFundManagement.Domain.Extensions;
|
||||
using PostFundManagement.Domain.Models;
|
||||
using PostFundManagement.Domain.Security;
|
||||
using Problems = Microsoft.AspNetCore.Mvc.ProblemDetails;
|
||||
|
||||
namespace PostFundManagement.Api.Endpoints.Projects;
|
||||
|
||||
[ApiVersionTarget(1)]
|
||||
public sealed class GetComplianceItemEndpoint : IEndpoint
|
||||
{
|
||||
public void Map(IEndpointRouteBuilder builder)
|
||||
{
|
||||
builder.MapGet("api/projects/complianceitems/{complianceItemId}", async (string complianceItemId, IProjectService service,
|
||||
CancellationToken cancellationToken = default) =>
|
||||
await service.GetComplianceItemAsync(complianceItemId, cancellationToken) switch
|
||||
{
|
||||
{ IsSuccess: true, Value: var complianceItem } => Results.Ok(complianceItem),
|
||||
var r when r.HasError<IdDecodeError>() => Results.Forbid(),
|
||||
var r when r.HasError<NotFoundError>() => Results.NotFound(),
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Gets a specific project compliance item")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(GetComplianceItemEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces<ComplianceItem>(StatusCodes.Status200OK)
|
||||
.Produces(StatusCodes.Status404NotFound)
|
||||
.Produces(StatusCodes.Status403Forbidden)
|
||||
.Produces(StatusCodes.Status401Unauthorized)
|
||||
.Produces<Problems>(StatusCodes.Status500InternalServerError)
|
||||
.WithTags(EndpointTags.Projects)
|
||||
.CacheOutput();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
using PostFundManagement.Application.Abstractions.Services;
|
||||
using PostFundManagement.Application.Extensions;
|
||||
using PostFundManagement.Domain.Abstractions;
|
||||
using PostFundManagement.Domain.Errors;
|
||||
using PostFundManagement.Domain.Extensions;
|
||||
using PostFundManagement.Domain.Models;
|
||||
using PostFundManagement.Domain.Security;
|
||||
using Problems = Microsoft.AspNetCore.Mvc.ProblemDetails;
|
||||
|
||||
namespace PostFundManagement.Api.Endpoints.Projects;
|
||||
|
||||
[ApiVersionTarget(1)]
|
||||
public sealed class GetComplianceItemsEndpoint : IEndpoint
|
||||
{
|
||||
public void Map(IEndpointRouteBuilder builder)
|
||||
{
|
||||
builder.MapGet("api/projects/complianceitems/{projectId}", async (string projectId, IProjectService service,
|
||||
CancellationToken cancellationToken = default) =>
|
||||
await service.GetComplianceItemsAsync(projectId, cancellationToken) switch
|
||||
{
|
||||
{ IsSuccess: true, Value: var complianceItems } => Results.Ok(complianceItems),
|
||||
var r when r.HasError<IdDecodeError>() => Results.Forbid(),
|
||||
var r when r.HasError<NotFoundError>() => Results.NotFound(),
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Gets project compliance items")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(GetComplianceItemsEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces<ComplianceItem[]>(StatusCodes.Status200OK)
|
||||
.Produces(StatusCodes.Status404NotFound)
|
||||
.Produces(StatusCodes.Status403Forbidden)
|
||||
.Produces(StatusCodes.Status401Unauthorized)
|
||||
.Produces<Problems>(StatusCodes.Status500InternalServerError)
|
||||
.WithTags(EndpointTags.Projects)
|
||||
.CacheOutput();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
using PostFundManagement.Application.Abstractions.Services;
|
||||
using PostFundManagement.Application.Extensions;
|
||||
using PostFundManagement.Domain.Abstractions;
|
||||
using PostFundManagement.Domain.Errors;
|
||||
using PostFundManagement.Domain.Extensions;
|
||||
using PostFundManagement.Domain.Models;
|
||||
using PostFundManagement.Domain.Security;
|
||||
using Problems = Microsoft.AspNetCore.Mvc.ProblemDetails;
|
||||
|
||||
namespace PostFundManagement.Api.Endpoints.Projects;
|
||||
|
||||
[ApiVersionTarget(1)]
|
||||
public sealed class GetIssueEndpoint : IEndpoint
|
||||
{
|
||||
public void Map(IEndpointRouteBuilder builder)
|
||||
{
|
||||
builder.MapGet("api/projects/issues/{issueId}", async (string issueId, IProjectService service,
|
||||
CancellationToken cancellationToken = default) =>
|
||||
await service.GetIssueAsync(issueId, cancellationToken) switch
|
||||
{
|
||||
{ IsSuccess: true, Value: var issue } => Results.Ok(issue),
|
||||
var r when r.HasError<IdDecodeError>() => Results.Forbid(),
|
||||
var r when r.HasError<NotFoundError>() => Results.NotFound(),
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Gets a specific project issue")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(GetIssueEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces<Issue>(StatusCodes.Status200OK)
|
||||
.Produces(StatusCodes.Status404NotFound)
|
||||
.Produces(StatusCodes.Status403Forbidden)
|
||||
.Produces(StatusCodes.Status401Unauthorized)
|
||||
.Produces<Problems>(StatusCodes.Status500InternalServerError)
|
||||
.WithTags(EndpointTags.Projects)
|
||||
.CacheOutput();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
using PostFundManagement.Application.Abstractions.Services;
|
||||
using PostFundManagement.Application.Extensions;
|
||||
using PostFundManagement.Domain.Abstractions;
|
||||
using PostFundManagement.Domain.Errors;
|
||||
using PostFundManagement.Domain.Extensions;
|
||||
using PostFundManagement.Domain.Models;
|
||||
using PostFundManagement.Domain.Security;
|
||||
using Problems = Microsoft.AspNetCore.Mvc.ProblemDetails;
|
||||
|
||||
namespace PostFundManagement.Api.Endpoints.Projects;
|
||||
|
||||
[ApiVersionTarget(1)]
|
||||
public sealed class GetIssuesEndpoint : IEndpoint
|
||||
{
|
||||
public void Map(IEndpointRouteBuilder builder)
|
||||
{
|
||||
builder.MapGet("api/projects/issues/{projectId}", async (string projectId, IProjectService service,
|
||||
CancellationToken cancellationToken = default) =>
|
||||
await service.GetIssuesAsync(projectId, cancellationToken) switch
|
||||
{
|
||||
{ IsSuccess: true, Value: var issues } => Results.Ok(issues),
|
||||
var r when r.HasError<IdDecodeError>() => Results.Forbid(),
|
||||
var r when r.HasError<NotFoundError>() => Results.NotFound(),
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Gets project issues")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(GetIssuesEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces<Issue[]>(StatusCodes.Status200OK)
|
||||
.Produces(StatusCodes.Status404NotFound)
|
||||
.Produces(StatusCodes.Status403Forbidden)
|
||||
.Produces(StatusCodes.Status401Unauthorized)
|
||||
.Produces<Problems>(StatusCodes.Status500InternalServerError)
|
||||
.WithTags(EndpointTags.Projects)
|
||||
.CacheOutput();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
using PostFundManagement.Application.Abstractions.Services;
|
||||
using PostFundManagement.Application.Extensions;
|
||||
using PostFundManagement.Domain.Abstractions;
|
||||
using PostFundManagement.Domain.Errors;
|
||||
using PostFundManagement.Domain.Extensions;
|
||||
using PostFundManagement.Domain.Models;
|
||||
using PostFundManagement.Domain.Security;
|
||||
using Problems = Microsoft.AspNetCore.Mvc.ProblemDetails;
|
||||
|
||||
namespace PostFundManagement.Api.Endpoints.Projects;
|
||||
|
||||
[ApiVersionTarget(1)]
|
||||
public sealed class GetOutcomeEndpoint : IEndpoint
|
||||
{
|
||||
public void Map(IEndpointRouteBuilder builder)
|
||||
{
|
||||
builder.MapGet("api/projects/outcomes/{outcomeId}", async (string outcomeId, IProjectService service,
|
||||
CancellationToken cancellationToken = default) =>
|
||||
await service.GetOutcomeAsync(outcomeId, cancellationToken) switch
|
||||
{
|
||||
{ IsSuccess: true, Value: var outcome } => Results.Ok(outcome),
|
||||
var r when r.HasError<IdDecodeError>() => Results.Forbid(),
|
||||
var r when r.HasError<NotFoundError>() => Results.NotFound(),
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Gets a specific project outcome")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(GetOutcomeEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces<Outcome>(StatusCodes.Status200OK)
|
||||
.Produces(StatusCodes.Status404NotFound)
|
||||
.Produces(StatusCodes.Status403Forbidden)
|
||||
.Produces(StatusCodes.Status401Unauthorized)
|
||||
.Produces<Problems>(StatusCodes.Status500InternalServerError)
|
||||
.WithTags(EndpointTags.Projects)
|
||||
.CacheOutput();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
using PostFundManagement.Application.Abstractions.Services;
|
||||
using PostFundManagement.Application.Extensions;
|
||||
using PostFundManagement.Domain.Abstractions;
|
||||
using PostFundManagement.Domain.Errors;
|
||||
using PostFundManagement.Domain.Extensions;
|
||||
using PostFundManagement.Domain.Models;
|
||||
using PostFundManagement.Domain.Security;
|
||||
using Problems = Microsoft.AspNetCore.Mvc.ProblemDetails;
|
||||
|
||||
namespace PostFundManagement.Api.Endpoints.Projects;
|
||||
|
||||
[ApiVersionTarget(1)]
|
||||
public sealed class GetOutcomesEndpoint : IEndpoint
|
||||
{
|
||||
public void Map(IEndpointRouteBuilder builder)
|
||||
{
|
||||
builder.MapGet("api/projects/outcomes/{beneficiatyId}", async (string beneficiatyId, IProjectService service,
|
||||
CancellationToken cancellationToken = default) =>
|
||||
await service.GetOutcomesAsync(beneficiatyId, cancellationToken) switch
|
||||
{
|
||||
{ IsSuccess: true, Value: var outcomes } => Results.Ok(outcomes),
|
||||
var r when r.HasError<IdDecodeError>() => Results.Forbid(),
|
||||
var r when r.HasError<NotFoundError>() => Results.NotFound(),
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Gets project beneficiary outcomes")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(GetOutcomesEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces<Outcome[]>(StatusCodes.Status200OK)
|
||||
.Produces(StatusCodes.Status404NotFound)
|
||||
.Produces(StatusCodes.Status403Forbidden)
|
||||
.Produces(StatusCodes.Status401Unauthorized)
|
||||
.Produces<Problems>(StatusCodes.Status500InternalServerError)
|
||||
.WithTags(EndpointTags.Projects)
|
||||
.CacheOutput();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
using PostFundManagement.Application.Abstractions.Services;
|
||||
using PostFundManagement.Application.Extensions;
|
||||
using PostFundManagement.Domain.Abstractions;
|
||||
using PostFundManagement.Domain.Errors;
|
||||
using PostFundManagement.Domain.Extensions;
|
||||
using PostFundManagement.Domain.Models;
|
||||
using PostFundManagement.Domain.Security;
|
||||
using Problems = Microsoft.AspNetCore.Mvc.ProblemDetails;
|
||||
|
||||
namespace PostFundManagement.Api.Endpoints.Projects;
|
||||
|
||||
[ApiVersionTarget(1)]
|
||||
public sealed class GetSiteVisitEndpoint : IEndpoint
|
||||
{
|
||||
public void Map(IEndpointRouteBuilder builder)
|
||||
{
|
||||
builder.MapGet("api/projects/sitevisits/{siteVisitId}", async (string siteVisitId, IProjectService service,
|
||||
CancellationToken cancellationToken = default) =>
|
||||
await service.GetSiteVisitAsync(siteVisitId, cancellationToken) switch
|
||||
{
|
||||
{ IsSuccess: true, Value: var siteVisit } => Results.Ok(siteVisit),
|
||||
var r when r.HasError<IdDecodeError>() => Results.Forbid(),
|
||||
var r when r.HasError<NotFoundError>() => Results.NotFound(),
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Gets project site visit")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(GetSiteVisitEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces<SiteVisit>(StatusCodes.Status200OK)
|
||||
.Produces(StatusCodes.Status404NotFound)
|
||||
.Produces(StatusCodes.Status403Forbidden)
|
||||
.Produces(StatusCodes.Status401Unauthorized)
|
||||
.Produces<Problems>(StatusCodes.Status500InternalServerError)
|
||||
.WithTags(EndpointTags.Projects)
|
||||
.CacheOutput();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
using PostFundManagement.Application.Abstractions.Services;
|
||||
using PostFundManagement.Application.Extensions;
|
||||
using PostFundManagement.Domain.Abstractions;
|
||||
using PostFundManagement.Domain.Errors;
|
||||
using PostFundManagement.Domain.Extensions;
|
||||
using PostFundManagement.Domain.Models;
|
||||
using PostFundManagement.Domain.Security;
|
||||
using Problems = Microsoft.AspNetCore.Mvc.ProblemDetails;
|
||||
|
||||
namespace PostFundManagement.Api.Endpoints.Projects;
|
||||
|
||||
[ApiVersionTarget(1)]
|
||||
public sealed class GetSiteVisitsEndpoint : IEndpoint
|
||||
{
|
||||
public void Map(IEndpointRouteBuilder builder)
|
||||
{
|
||||
builder.MapGet("api/projects/sitevisits/{projectId}", async (string projectId, IProjectService service,
|
||||
CancellationToken cancellationToken = default) =>
|
||||
await service.GetSiteVisitsAsync(projectId, cancellationToken) switch
|
||||
{
|
||||
{ IsSuccess: true, Value: var siteVisits } => Results.Ok(siteVisits),
|
||||
var r when r.HasError<IdDecodeError>() => Results.Forbid(),
|
||||
var r when r.HasError<NotFoundError>() => Results.NotFound(),
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Gets project site visits")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(GetSiteVisitsEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces<SiteVisit[]>(StatusCodes.Status200OK)
|
||||
.Produces(StatusCodes.Status404NotFound)
|
||||
.Produces(StatusCodes.Status403Forbidden)
|
||||
.Produces(StatusCodes.Status401Unauthorized)
|
||||
.Produces<Problems>(StatusCodes.Status500InternalServerError)
|
||||
.WithTags(EndpointTags.Projects)
|
||||
.CacheOutput();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
using PostFundManagement.Application.Abstractions.Services;
|
||||
using PostFundManagement.Application.Extensions;
|
||||
using PostFundManagement.Application.Services.Projects;
|
||||
using PostFundManagement.Domain.Abstractions;
|
||||
using PostFundManagement.Domain.Errors;
|
||||
using PostFundManagement.Domain.Extensions;
|
||||
using PostFundManagement.Domain.Security;
|
||||
using Problems = Microsoft.AspNetCore.Mvc.ProblemDetails;
|
||||
|
||||
namespace PostFundManagement.Api.Endpoints.Projects;
|
||||
|
||||
[ApiVersionTarget(1)]
|
||||
public sealed class UpdateBeneficiaryEndpoint : IEndpoint
|
||||
{
|
||||
public void Map(IEndpointRouteBuilder builder)
|
||||
{
|
||||
builder.MapPut("api/projects/beneficiaries", async (UpdateBeneficiaryRequest request, HttpContext context,
|
||||
IProjectService service, CancellationToken cancellationToken = default) =>
|
||||
await service.UpdateBeneficiaryAsync(request, context.GetUserId(), cancellationToken) switch
|
||||
{
|
||||
{ IsSuccess: true } => Results.Ok(),
|
||||
var r when r.HasError<UpdateError>() => Results.BadRequest(r.Errors.ToProblems()),
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Update project beneficiary")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(UpdateBeneficiaryEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces(StatusCodes.Status200OK)
|
||||
.Produces(StatusCodes.Status401Unauthorized)
|
||||
.Produces<Problems>(StatusCodes.Status400BadRequest)
|
||||
.Produces<Problems>(StatusCodes.Status500InternalServerError)
|
||||
.WithTags(EndpointTags.Projects);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
using PostFundManagement.Application.Abstractions.Services;
|
||||
using PostFundManagement.Application.Extensions;
|
||||
using PostFundManagement.Application.Services.Projects;
|
||||
using PostFundManagement.Domain.Abstractions;
|
||||
using PostFundManagement.Domain.Errors;
|
||||
using PostFundManagement.Domain.Extensions;
|
||||
using PostFundManagement.Domain.Security;
|
||||
using Problems = Microsoft.AspNetCore.Mvc.ProblemDetails;
|
||||
|
||||
namespace PostFundManagement.Api.Endpoints.Projects;
|
||||
|
||||
[ApiVersionTarget(1)]
|
||||
public sealed class UpdateChangeRequestEndpoint : IEndpoint
|
||||
{
|
||||
public void Map(IEndpointRouteBuilder builder)
|
||||
{
|
||||
builder.MapPut("api/projects/changerequests", async (UpdateChangeRequest request, HttpContext context,
|
||||
IProjectService service, CancellationToken cancellationToken = default) =>
|
||||
await service.UpdateChangeRequestAsync(request, context.GetUserId(), cancellationToken) switch
|
||||
{
|
||||
{ IsSuccess: true } => Results.Ok(),
|
||||
var r when r.HasError<UpdateError>() => Results.BadRequest(r.Errors.ToProblems()),
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Update a specific project change request")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(UpdateChangeRequestEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces(StatusCodes.Status200OK)
|
||||
.Produces(StatusCodes.Status401Unauthorized)
|
||||
.Produces<Problems>(StatusCodes.Status400BadRequest)
|
||||
.Produces<Problems>(StatusCodes.Status500InternalServerError)
|
||||
.WithTags(EndpointTags.Projects);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
using PostFundManagement.Application.Abstractions.Services;
|
||||
using PostFundManagement.Application.Extensions;
|
||||
using PostFundManagement.Application.Services.Projects;
|
||||
using PostFundManagement.Domain.Abstractions;
|
||||
using PostFundManagement.Domain.Errors;
|
||||
using PostFundManagement.Domain.Extensions;
|
||||
using PostFundManagement.Domain.Security;
|
||||
using Problems = Microsoft.AspNetCore.Mvc.ProblemDetails;
|
||||
|
||||
namespace PostFundManagement.Api.Endpoints.Projects;
|
||||
|
||||
[ApiVersionTarget(1)]
|
||||
public sealed class UpdateComplianceItemEndpoint : IEndpoint
|
||||
{
|
||||
public void Map(IEndpointRouteBuilder builder)
|
||||
{
|
||||
builder.MapPut("api/projects/complianceitems", async (UpdateComplianceItemRequest request, HttpContext context,
|
||||
IProjectService service, CancellationToken cancellationToken = default) =>
|
||||
await service.UpdateComplianceItemAsync(request, context.GetUserId(), cancellationToken) switch
|
||||
{
|
||||
{ IsSuccess: true } => Results.Ok(),
|
||||
var r when r.HasError<UpdateError>() => Results.BadRequest(r.Errors.ToProblems()),
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Update a specific compliance item")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(UpdateComplianceItemEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces(StatusCodes.Status200OK)
|
||||
.Produces(StatusCodes.Status401Unauthorized)
|
||||
.Produces<Problems>(StatusCodes.Status400BadRequest)
|
||||
.Produces<Problems>(StatusCodes.Status500InternalServerError)
|
||||
.WithTags(EndpointTags.Projects);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
using PostFundManagement.Application.Abstractions.Services;
|
||||
using PostFundManagement.Application.Extensions;
|
||||
using PostFundManagement.Application.Services.Projects;
|
||||
using PostFundManagement.Domain.Abstractions;
|
||||
using PostFundManagement.Domain.Errors;
|
||||
using PostFundManagement.Domain.Extensions;
|
||||
using PostFundManagement.Domain.Security;
|
||||
using Problems = Microsoft.AspNetCore.Mvc.ProblemDetails;
|
||||
|
||||
namespace PostFundManagement.Api.Endpoints.Projects;
|
||||
|
||||
[ApiVersionTarget(1)]
|
||||
public sealed class UpdateIssueEndpoint : IEndpoint
|
||||
{
|
||||
public void Map(IEndpointRouteBuilder builder)
|
||||
{
|
||||
builder.MapPut("api/projects/issues", async (UpdateIssueRequest request, HttpContext context,
|
||||
IProjectService service, CancellationToken cancellationToken = default) =>
|
||||
await service.UpdateIssueAsync(request, context.GetUserId(), cancellationToken) switch
|
||||
{
|
||||
{ IsSuccess: true } => Results.Ok(),
|
||||
var r when r.HasError<UpdateError>() => Results.BadRequest(r.Errors.ToProblems()),
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Update a specific project issue")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(UpdateIssueEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces(StatusCodes.Status200OK)
|
||||
.Produces(StatusCodes.Status401Unauthorized)
|
||||
.Produces<Problems>(StatusCodes.Status400BadRequest)
|
||||
.Produces<Problems>(StatusCodes.Status500InternalServerError)
|
||||
.WithTags(EndpointTags.Projects);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
using PostFundManagement.Application.Abstractions.Services;
|
||||
using PostFundManagement.Application.Extensions;
|
||||
using PostFundManagement.Application.Services.Projects;
|
||||
using PostFundManagement.Domain.Abstractions;
|
||||
using PostFundManagement.Domain.Errors;
|
||||
using PostFundManagement.Domain.Extensions;
|
||||
using PostFundManagement.Domain.Security;
|
||||
using Problems = Microsoft.AspNetCore.Mvc.ProblemDetails;
|
||||
|
||||
namespace PostFundManagement.Api.Endpoints.Projects;
|
||||
|
||||
[ApiVersionTarget(1)]
|
||||
public sealed class UpdateOutcomeEndpoint : IEndpoint
|
||||
{
|
||||
public void Map(IEndpointRouteBuilder builder)
|
||||
{
|
||||
builder.MapPut("api/projects/outcomes", async (UpdateOutcomeRequest request, HttpContext context,
|
||||
IProjectService service, CancellationToken cancellationToken = default) =>
|
||||
await service.UpdateOutcomeAsync(request, context.GetUserId(), cancellationToken) switch
|
||||
{
|
||||
{ IsSuccess: true } => Results.Ok(),
|
||||
var r when r.HasError<UpdateError>() => Results.BadRequest(r.Errors.ToProblems()),
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Update project beneficiary outcome")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(UpdateOutcomeEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces(StatusCodes.Status200OK)
|
||||
.Produces(StatusCodes.Status401Unauthorized)
|
||||
.Produces<Problems>(StatusCodes.Status400BadRequest)
|
||||
.Produces<Problems>(StatusCodes.Status500InternalServerError)
|
||||
.WithTags(EndpointTags.Projects);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
using PostFundManagement.Application.Abstractions.Services;
|
||||
using PostFundManagement.Application.Extensions;
|
||||
using PostFundManagement.Application.Services.Projects;
|
||||
using PostFundManagement.Domain.Abstractions;
|
||||
using PostFundManagement.Domain.Errors;
|
||||
using PostFundManagement.Domain.Extensions;
|
||||
using PostFundManagement.Domain.Security;
|
||||
using Problems = Microsoft.AspNetCore.Mvc.ProblemDetails;
|
||||
|
||||
namespace PostFundManagement.Api.Endpoints.Projects;
|
||||
|
||||
[ApiVersionTarget(1)]
|
||||
public sealed class UpdateSiteVisitEndpoint : IEndpoint
|
||||
{
|
||||
public void Map(IEndpointRouteBuilder builder)
|
||||
{
|
||||
builder.MapPut("api/projects/sitevisits", async (UpdateSiteVisitRequest request, HttpContext context,
|
||||
IProjectService service, CancellationToken cancellationToken = default) =>
|
||||
await service.UpdateSiteVisitAsync(request, context.GetUserId(), cancellationToken) switch
|
||||
{
|
||||
{ IsSuccess: true } => Results.Ok(),
|
||||
var r when r.HasError<UpdateError>() => Results.BadRequest(r.Errors.ToProblems()),
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||
})
|
||||
.WithDescription("Update project site visit")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(UpdateSiteVisitEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces(StatusCodes.Status200OK)
|
||||
.Produces(StatusCodes.Status401Unauthorized)
|
||||
.Produces<Problems>(StatusCodes.Status400BadRequest)
|
||||
.Produces<Problems>(StatusCodes.Status500InternalServerError)
|
||||
.WithTags(EndpointTags.Projects);
|
||||
}
|
||||
}
|
||||
@@ -26,7 +26,7 @@ public interface ICommunicationsService
|
||||
|
||||
[Log]
|
||||
[Audit]
|
||||
Task<Result> UpdateNotificationAsync(UpdateNotificationRequest request, Guid userId, CancellationToken cancellationToken = default);
|
||||
Task<Result> UpdateNotificationAsync(UpdateNotificationRequest request, CancellationToken cancellationToken = default);
|
||||
|
||||
[Log]
|
||||
Task<Result<Notification[]>> GetNotificationsAsync(string organisationIdHash, CancellationToken cancellationToken = default);
|
||||
|
||||
@@ -31,7 +31,7 @@ public interface IGovernanceService
|
||||
|
||||
[Log]
|
||||
[Audit]
|
||||
Task<Result<Organisation>> UpdateOrganisationAsync(UpdateOrganisationRequest request, CancellationToken cancellationToken = default);
|
||||
Task<Result<Organisation>> UpdateOrganisationAsync(UpdateOrganisationRequest request, Guid userId, CancellationToken cancellationToken = default);
|
||||
|
||||
[Log]
|
||||
[Audit]
|
||||
|
||||
@@ -77,7 +77,7 @@ public interface IProjectService
|
||||
|
||||
[Log]
|
||||
[Audit]
|
||||
Task<Result> UpdateChangeRequestAsync(UpdatehangeRequest request, Guid userId, CancellationToken cancellationToken = default);
|
||||
Task<Result> UpdateChangeRequestAsync(UpdateChangeRequest request, Guid userId, CancellationToken cancellationToken = default);
|
||||
|
||||
[Log]
|
||||
Task<Result<ChangeRequest[]>> GetChangeRequestsAsync(string projectIdHash, CancellationToken cancellationToken = default);
|
||||
@@ -105,7 +105,7 @@ public interface IProjectService
|
||||
|
||||
[Log]
|
||||
[Audit]
|
||||
Task<Result> UpdateBeneficiaryItemAsync(UpdateBeneficiaryRequest request, Guid userId, CancellationToken cancellationToken = default);
|
||||
Task<Result> UpdateBeneficiaryAsync(UpdateBeneficiaryRequest request, Guid userId, CancellationToken cancellationToken = default);
|
||||
|
||||
[Log]
|
||||
Task<Result<Beneficiary[]>> GetBeneficiariesAsync(string projectIdHash, CancellationToken cancellationToken = default);
|
||||
@@ -153,5 +153,5 @@ public interface IProjectService
|
||||
Task<Result<SiteVisit[]>> GetSiteVisitsAsync(string projectIdHash, CancellationToken cancellationToken = default);
|
||||
|
||||
[Log]
|
||||
Task<Result<SiteVisit>> GetSiteVisitAsync(string SiteVisitIdHash, CancellationToken cancellationToken = default);
|
||||
Task<Result<SiteVisit>> GetSiteVisitAsync(string siteVisitIdHash, CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
||||
+2
-2
@@ -135,6 +135,6 @@ public sealed class CommunicationsCacheService(CommunicationsService service, ID
|
||||
public async Task<Result<Invite>> SendInviteAsync(InviteRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await service.SendInviteAsync(request, userId, cancellationToken);
|
||||
|
||||
public async Task<Result> UpdateNotificationAsync(UpdateNotificationRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await service.UpdateNotificationAsync(request, userId, cancellationToken);
|
||||
public async Task<Result> UpdateNotificationAsync(UpdateNotificationRequest request, CancellationToken cancellationToken = default) =>
|
||||
await service.UpdateNotificationAsync(request, cancellationToken);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using PostFundManagement.Application.Abstractions.Services;
|
||||
using PostFundManagement.Application.Services.Shared;
|
||||
using PostFundManagement.Domain;
|
||||
using PostFundManagement.Domain.Abstractions;
|
||||
using PostFundManagement.Domain.Errors;
|
||||
@@ -8,39 +9,35 @@ using PostFundManagement.Infrastructure.Database;
|
||||
|
||||
namespace PostFundManagement.Application.Services.Communications;
|
||||
|
||||
public sealed class CommunicationsService(IDbContextFactory<ApplicationDbContext> contextFactory, ITenantContextService tenantContext) : ICommunicationsService
|
||||
{
|
||||
public sealed class CommunicationsService(IDbContextFactory<ApplicationDbContext> contextFactory,
|
||||
HashService hashService, ITenantContextService tenantContext) : ICommunicationsService
|
||||
{
|
||||
public async Task<Result<Invite>> SendInviteAsync(InviteRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Invite>>>)(async () =>
|
||||
{
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
var invite = new Domain.Entities.Invite
|
||||
{
|
||||
{
|
||||
OrganisationId = request.OrganisationId,
|
||||
InvitedOrganisationId = request.InvitedOrganisationId,
|
||||
AwardId = request.AwardId,
|
||||
ContractId = request.ContractId,
|
||||
Recipient = request.Recipient,
|
||||
CreatedBy = userId,
|
||||
CreatedAt = DateTime.UtcNow
|
||||
CreatedAt = DateTime.UtcNow,
|
||||
TenantId = tenantContext.TenantId
|
||||
};
|
||||
|
||||
context.Invites.Add(invite);
|
||||
|
||||
context.Notifications.Add(new Domain.Entities.Notification
|
||||
{
|
||||
OrganisationId = request.OrganisationId,
|
||||
Recipient = request.Recipient,
|
||||
Platform = request.Platform,
|
||||
Status = NotificationStatus.Pending,
|
||||
Subject = "Invitation to Onboard",
|
||||
Message = request.Message,
|
||||
CreatedAt = DateTime.UtcNow,
|
||||
TenantId = tenantContext.TenantId
|
||||
});
|
||||
var notificationRequest = new CreateNotificationRequest(request.InvitedOrganisationId, request.Recipient,
|
||||
request.Platform, "Invitation to Onboard", string.Empty, request.Message);
|
||||
|
||||
return Result.FailIf(await context.SaveChangesAsync(cancellationToken) <= 0, CreateError.New)
|
||||
var notificationResult = await CreateNotificationAsync(notificationRequest, userId, cancellationToken);
|
||||
|
||||
return Result.FailIf(await context.SaveChangesAsync(cancellationToken) <= 0 && notificationResult.IsFailed,
|
||||
CreateError.Create().CausedBy(notificationResult.Errors))
|
||||
.ToResult(invite.Map());
|
||||
}));
|
||||
|
||||
@@ -82,23 +79,78 @@ public sealed class CommunicationsService(IDbContextFactory<ApplicationDbContext
|
||||
return Result.Ok(invites.Select(i => i.Map()).ToArray());
|
||||
}));
|
||||
|
||||
public Task<Result> CreateNotificationAsync(CreateNotificationRequest request, Guid userId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
public async Task<Result> CreateNotificationAsync(CreateNotificationRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result>>)(async () =>
|
||||
{
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
public Task<Result> UpdateNotificationAsync(UpdateNotificationRequest request, Guid userId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
context.Notifications.Add(new Domain.Entities.Notification
|
||||
{
|
||||
CreatedAt = DateTime.UtcNow,
|
||||
Recipient = request.Recipient,
|
||||
OrganisationId = request.OrganisationId,
|
||||
Destination = request.Destination,
|
||||
Subject = request.Subject,
|
||||
Message = request.Message,
|
||||
Platform = request.Platform,
|
||||
Status = NotificationStatus.Queued,
|
||||
TenantId = tenantContext.TenantId
|
||||
});
|
||||
|
||||
public Task<Result<Notification[]>> GetNotificationsAsync(string organisationIdHash, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
return Result.OkIf(await context.SaveChangesAsync(cancellationToken) > 0, CreateError.Create("Failed to create entry"));
|
||||
}));
|
||||
|
||||
public Task<Result<Notification>> GetNotificationAsync(string notificationIdHash, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
public async Task<Result> UpdateNotificationAsync(UpdateNotificationRequest request, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result>>)(async () =>
|
||||
{
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
var changedTotal = await context.Notifications
|
||||
.Where(n => n.Id == request.NotificationId)
|
||||
.ExecuteUpdateAsync(f => f
|
||||
.SetProperty(u => u.Destination, request.Destination)
|
||||
.SetProperty(u => u.SentAt, request.SentAt)
|
||||
.SetProperty(u => u.Error, request.Error)
|
||||
.SetProperty(u => u.UpdatedAt, DateTime.UtcNow)
|
||||
.SetProperty(u => u.Status, request.Status), cancellationToken);
|
||||
|
||||
return Result.OkIf(changedTotal > 0, UpdateError.Create($"Failed to update notification: {request.NotificationId}"));
|
||||
}));
|
||||
|
||||
public async Task<Result<Notification[]>> GetNotificationsAsync(string organisationIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Notification[]>>>)(async () =>
|
||||
{
|
||||
var decodeResult = hashService.DecodeLongIdHash(organisationIdHash);
|
||||
|
||||
if (decodeResult.IsFailed)
|
||||
return Result.Fail(IdDecodeError.Create()
|
||||
.CausedBy(decodeResult.Errors));
|
||||
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
var notifications = await context.Notifications.AsNoTracking()
|
||||
.Where(n => n.OrganisationId == decodeResult.Value)
|
||||
.OrderByDescending(o => o.Id)
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
return Result.Ok(notifications?.Select(i => i.Map()).ToArray() ?? []);
|
||||
}));
|
||||
|
||||
public async Task<Result<Notification>> GetNotificationAsync(string notificationIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Notification>>>)(async () =>
|
||||
{
|
||||
var decodeResult = hashService.DecodeLongIdHash(notificationIdHash);
|
||||
|
||||
if (decodeResult.IsFailed)
|
||||
return Result.Fail(IdDecodeError.Create()
|
||||
.CausedBy(decodeResult.Errors));
|
||||
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
var notification = await context.Notifications.AsNoTracking()
|
||||
.FirstOrDefaultAsync(n => n.Id == decodeResult.Value, cancellationToken);
|
||||
|
||||
return Result.FailIf(notification is null, NotFoundError.New)
|
||||
.ToResult(notification!.Map());
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -3,10 +3,10 @@ using static PostFundManagement.Domain.Extensions.Constants;
|
||||
|
||||
namespace PostFundManagement.Application.Services.Communications;
|
||||
|
||||
public sealed record UpdateNotificationRequest([Required] long NotificationId,
|
||||
public sealed record UpdateNotificationRequest([Required] long NotificationId, string? Destination,
|
||||
[Required] NotificationStatus Status,
|
||||
[Required] DateTime SentAt,
|
||||
[Required][MaxLength(TextLength)] string Error);
|
||||
[MaxLength(TextLength)] string? Error);
|
||||
|
||||
public sealed record CreateNotificationRequest([Required] long OrganisationId,
|
||||
[Required] Guid Recipient,
|
||||
|
||||
@@ -215,28 +215,104 @@ public sealed class GovernanceCacheService(GovernanceService service, IDistribut
|
||||
return Result.Ok(cached.FromJson<Programme[]>());
|
||||
}));
|
||||
|
||||
public Task<Result<Tenant>> GetTenantAsync(string tenantIdHash, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
public async Task<Result<Tenant>> GetTenantAsync(string tenantIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Tenant>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetTenantAsync(tenantIdHash, cancellationToken);
|
||||
|
||||
public Task<Result<TenantOrganisation>> GetTenantOrganisationAsync(string tenantOrganisationIdHash, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
var cacheKey = HashService.ToMd5Hash($"gettenant-{tenantIdHash}").Value;
|
||||
|
||||
public Task<Result<TenantOrganisation[]>> GetTenantOrganisationsAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
|
||||
|
||||
public Task<Result<Tenant[]>> GetTenantsAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
if (string.IsNullOrWhiteSpace(cached))
|
||||
{
|
||||
var result = await service.GetTenantAsync(tenantIdHash, cancellationToken);
|
||||
|
||||
public async Task<Result<Organisation>> UpdateOrganisationAsync(UpdateOrganisationRequest request, CancellationToken cancellationToken = default) =>
|
||||
await service.UpdateOrganisationAsync(request, cancellationToken);
|
||||
if (result.IsFailed) return result;
|
||||
|
||||
await cache.SetStringAsync(cacheKey, result.Value.ToJson(), cacheOptions, cancellationToken);
|
||||
|
||||
return result.Value;
|
||||
}
|
||||
|
||||
return Result.Ok(cached.FromJson<Tenant>());
|
||||
}));
|
||||
|
||||
public async Task<Result<TenantOrganisation>> GetTenantOrganisationAsync(string tenantOrganisationIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<TenantOrganisation>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetTenantOrganisationAsync(tenantOrganisationIdHash, cancellationToken);
|
||||
|
||||
var cacheKey = HashService.ToMd5Hash($"gettenantorganisation-{tenantOrganisationIdHash}").Value;
|
||||
|
||||
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(cached))
|
||||
{
|
||||
var result = await service.GetTenantOrganisationAsync(tenantOrganisationIdHash, cancellationToken);
|
||||
|
||||
if (result.IsFailed) return result;
|
||||
|
||||
await cache.SetStringAsync(cacheKey, result.Value.ToJson(), cacheOptions, cancellationToken);
|
||||
|
||||
return result.Value;
|
||||
}
|
||||
|
||||
return Result.Ok(cached.FromJson<TenantOrganisation>());
|
||||
}));
|
||||
|
||||
public async Task<Result<TenantOrganisation[]>> GetTenantOrganisationsAsync(CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<TenantOrganisation[]>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetTenantOrganisationsAsync(cancellationToken);
|
||||
|
||||
var cacheKey = HashService.ToMd5Hash($"gettenantorganisations").Value;
|
||||
|
||||
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(cached))
|
||||
{
|
||||
var result = await service.GetTenantOrganisationsAsync(cancellationToken);
|
||||
|
||||
if (result.IsFailed) return result;
|
||||
|
||||
await cache.SetStringAsync(cacheKey, result.Value.ToJson(), cacheOptions, cancellationToken);
|
||||
|
||||
return result.Value;
|
||||
}
|
||||
|
||||
return Result.Ok(cached.FromJson<TenantOrganisation[]>());
|
||||
}));
|
||||
|
||||
public async Task<Result<Tenant[]>> GetTenantsAsync(CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Tenant[]>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetTenantsAsync(cancellationToken);
|
||||
|
||||
var cacheKey = HashService.ToMd5Hash($"gettenants").Value;
|
||||
|
||||
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(cached))
|
||||
{
|
||||
var result = await service.GetTenantsAsync(cancellationToken);
|
||||
|
||||
if (result.IsFailed) return result;
|
||||
|
||||
await cache.SetStringAsync(cacheKey, result.Value.ToJson(), cacheOptions, cancellationToken);
|
||||
|
||||
return result.Value;
|
||||
}
|
||||
|
||||
return Result.Ok(cached.FromJson<Tenant[]>());
|
||||
}));
|
||||
|
||||
public async Task<Result<Organisation>> UpdateOrganisationAsync(UpdateOrganisationRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await service.UpdateOrganisationAsync(request, userId, cancellationToken);
|
||||
|
||||
public async Task<Result> UpdatePortfolioAsync(UpdatePortfolioRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await service.UpdatePortfolioAsync(request, userId, cancellationToken);
|
||||
|
||||
@@ -10,7 +10,7 @@ using PostFundManagement.Infrastructure.Database;
|
||||
|
||||
namespace PostFundManagement.Application.Services.Governance;
|
||||
|
||||
public sealed class GovernanceService(IDbContextFactory<ApplicationDbContext> contextFactory, HashService hashService,
|
||||
public sealed class GovernanceService(IDbContextFactory<ApplicationDbContext> contextFactory, HashService hashService,
|
||||
ITenantContextService tenantContext) : IGovernanceService
|
||||
{
|
||||
public async Task<Result<Programme[]>> GetProgrammesAsync(string portfolioIdHash, CancellationToken cancellationToken = default) =>
|
||||
@@ -56,13 +56,14 @@ public sealed class GovernanceService(IDbContextFactory<ApplicationDbContext> co
|
||||
{
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
var organisations = await context.Organisations.AsNoTracking()
|
||||
.OrderBy(o => o.Name)
|
||||
var organisations = await context.TenantOrganisations.AsNoTracking()
|
||||
.Include(i => i.Organisation)
|
||||
.OrderBy(o => o.Organisation!.Name)
|
||||
.Skip((pagination.Page - 1) * pagination.PageSize)
|
||||
.Take(pagination.PageSize)
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
return Result.Ok(organisations.Select(o => o.Map()).ToArray());
|
||||
return Result.Ok(organisations.Select(o => o.Organisation!.Map()).ToArray());
|
||||
}));
|
||||
|
||||
public async Task<Result<Organisation>> GetOrganisationAsync(string organisationIdHash, CancellationToken cancellationToken = default) =>
|
||||
@@ -76,11 +77,12 @@ public sealed class GovernanceService(IDbContextFactory<ApplicationDbContext> co
|
||||
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
var organisation = await context.Organisations.AsNoTracking()
|
||||
.FirstOrDefaultAsync(o => o.Id == decodeResult.Value, cancellationToken);
|
||||
var tenantOrganisation = await context.TenantOrganisations.AsNoTracking()
|
||||
.Include(i => i.OrganisationId)
|
||||
.FirstOrDefaultAsync(o => o.OrganisationId == decodeResult.Value, cancellationToken);
|
||||
|
||||
return Result.FailIf(organisation is null, NotFoundError.New)
|
||||
.ToResult(organisation!.Map());
|
||||
return Result.FailIf(tenantOrganisation is null, NotFoundError.New)
|
||||
.ToResult(tenantOrganisation!.Organisation!.Map());
|
||||
}));
|
||||
|
||||
public async Task<Result<Instrument[]>> GetInstrumentsAsync(string programmeIdHash, CancellationToken cancellationToken = default) =>
|
||||
@@ -138,7 +140,7 @@ public sealed class GovernanceService(IDbContextFactory<ApplicationDbContext> co
|
||||
if (await context.Organisations.AnyAsync(o => o.RegistrationNo == registrationNo, cancellationToken))
|
||||
return Result.Fail(CreateError.Create("Organisation with the same registration number already exists"));
|
||||
|
||||
context.Organisations.Add(new Domain.Entities.Organisation
|
||||
var organisation = context.Organisations.Add(new Domain.Entities.Organisation
|
||||
{
|
||||
Name = request.Name.Humanize(LetterCasing.Title).Trim(),
|
||||
RegistrationNo = registrationNo,
|
||||
@@ -146,13 +148,18 @@ public sealed class GovernanceService(IDbContextFactory<ApplicationDbContext> co
|
||||
Type = request.Type,
|
||||
Status = ActivityStatus.Active,
|
||||
CreatedBy = userId,
|
||||
CreatedAt = DateTime.UtcNow
|
||||
CreatedAt = DateTime.UtcNow
|
||||
});
|
||||
|
||||
return Result.OkIf(await context.SaveChangesAsync(cancellationToken) > 0, CreateError.New);
|
||||
await context.SaveChangesAsync(cancellationToken);
|
||||
|
||||
var mapResult = await CreateTenantOrganisationAsync(hashService.HashEncodeLongId(organisation.Entity.Id).Value,
|
||||
hashService.HashEncodeLongId(tenantContext.TenantId).Value, userId, cancellationToken);
|
||||
|
||||
return Result.FailIf(mapResult.IsFailed, CreateError.Create("Failed to create organisation"));
|
||||
}));
|
||||
|
||||
public async Task<Result<Organisation>> UpdateOrganisationAsync(UpdateOrganisationRequest request, CancellationToken cancellationToken = default) =>
|
||||
public async Task<Result<Organisation>> UpdateOrganisationAsync(UpdateOrganisationRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Organisation>>>)(async () =>
|
||||
{
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
@@ -163,9 +170,17 @@ public sealed class GovernanceService(IDbContextFactory<ApplicationDbContext> co
|
||||
.SetProperty(u => u.Name, request.Name.Humanize(LetterCasing.Title).Trim())
|
||||
.SetProperty(u => u.RegistrationNo, request.RegistrationNo.Clean())
|
||||
.SetProperty(u => u.Email, request.Email.ToLower(CultureInfo.InvariantCulture).Clean())
|
||||
.SetProperty(u => u.Type, request.Type), cancellationToken);
|
||||
.SetProperty(u => u.Type, request.Type)
|
||||
.SetProperty(u => u.Status, request.Status), cancellationToken);
|
||||
|
||||
return Result.OkIf(changedTotal > 0, UpdateError.New);
|
||||
var tenantOrganisation = await context.TenantOrganisations.AsNoTracking().FirstOrDefaultAsync(f => f.OrganisationId == request.OrganisationId, cancellationToken);
|
||||
|
||||
if (tenantOrganisation is null)
|
||||
return Result.Fail(ValidationError.Create("Failed to find linked tenant organisation"));
|
||||
|
||||
var updateResult = await UpdateTenantOrganisationAsync(hashService.HashEncodeLongId(tenantOrganisation.Id).Value, request.Status, userId, cancellationToken);
|
||||
|
||||
return Result.OkIf(changedTotal > 0 && updateResult.IsFailed, UpdateError.Create("Failed to update organisation"));
|
||||
}));
|
||||
|
||||
public async Task<Result> CreatePortfolioAsync(CreatePortfolioRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
@@ -253,48 +268,171 @@ public sealed class GovernanceService(IDbContextFactory<ApplicationDbContext> co
|
||||
.ToResult(portfolio!.Map());
|
||||
}));
|
||||
|
||||
public Task<Result> CreateTenantAsync(CreateTenantRequest request, Guid userId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
public async Task<Result> CreateTenantAsync(CreateTenantRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result>>)(async () =>
|
||||
{
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
public Task<Result<Tenant[]>> GetTenantsAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
var requestedName = request.Name.Humanize(LetterCasing.Title).Trim();
|
||||
|
||||
public Task<Result<Tenant>> GetTenantAsync(string tenantIdHash, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
if (await context.Tenants.AnyAsync(t => t.Name == requestedName, cancellationToken))
|
||||
return Result.Fail(ValidationError.Create("A tenant with an equivalent name exists."));
|
||||
|
||||
public Task<Result> UpdateTenantAsync(UpdateTenantRequest request, Guid userId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
context.Tenants.Add(new Domain.Entities.Tenant
|
||||
{
|
||||
CreatedAt = DateTime.UtcNow,
|
||||
CreatedBy = userId,
|
||||
Name = requestedName,
|
||||
Status = ActivityStatus.Active
|
||||
});
|
||||
|
||||
public Task<Result> UpdateTenantUserAsync(UpdateTenantUserRequest request, Guid userId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
return Result.OkIf(await context.SaveChangesAsync(cancellationToken) > 0,
|
||||
CreateError.Create("Failed to create new tenant"));
|
||||
}));
|
||||
|
||||
public Task<Result> CreateTenantOrganisationAsync(string organisationIdHash, string tenantIdHash, Guid userId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
public async Task<Result<Tenant[]>> GetTenantsAsync(CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Tenant[]>>>)(async () =>
|
||||
{
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
public Task<Result> UpdateTenantOrganisationAsync(string tenantOrganisationIdHash, ActivityStatus status, Guid userId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
var tenants = await context.Tenants.AsNoTracking()
|
||||
.OrderByDescending(o => o.Id)
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
public Task<Result<TenantOrganisation[]>> GetTenantOrganisationsAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
return Result.Ok(tenants?.Select(t => t.Map()).ToArray() ?? []);
|
||||
}));
|
||||
|
||||
public Task<Result<TenantOrganisation>> GetTenantOrganisationAsync(string tenantOrganisationIdHash, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
public async Task<Result<Tenant>> GetTenantAsync(string tenantIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Tenant>>>)(async () =>
|
||||
{
|
||||
var decodeResult = hashService.DecodeLongIdHash(tenantIdHash);
|
||||
|
||||
if (decodeResult.IsFailed)
|
||||
return Result.Fail(IdDecodeError.Create()
|
||||
.CausedBy(decodeResult.Errors));
|
||||
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
var tenant = await context.Tenants.AsNoTracking().FirstOrDefaultAsync(t => t.Id == decodeResult.Value, cancellationToken);
|
||||
|
||||
return Result.FailIf(tenant is null, NotFoundError.Create("Failed to retrieve tenants"))
|
||||
.ToResult(tenant!.Map());
|
||||
}));
|
||||
|
||||
public async Task<Result> UpdateTenantAsync(UpdateTenantRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result>>)(async () =>
|
||||
{
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
var requestedName = request.Name.Humanize(LetterCasing.Title).Trim();
|
||||
|
||||
if (await context.Tenants.AnyAsync(t => t.Name == requestedName, cancellationToken))
|
||||
return Result.Fail(ValidationError.Create("A tenant with an equivalent name exists."));
|
||||
|
||||
var changedTotal = await context.Tenants
|
||||
.Where(f => f.Id == request.TenantId)
|
||||
.ExecuteUpdateAsync(f => f
|
||||
.SetProperty(u => u.UpdatedAt, DateTime.UtcNow)
|
||||
.SetProperty(u => u.UpdatedBy, userId)
|
||||
.SetProperty(u => u.Status, request.Status)
|
||||
.SetProperty(u => u.Name, requestedName), cancellationToken);
|
||||
|
||||
return Result.OkIf(changedTotal > 0, UpdateError.Create("No records updated"));
|
||||
}));
|
||||
|
||||
public async Task<Result> UpdateTenantUserAsync(UpdateTenantUserRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result>>)(async () =>
|
||||
{
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
var changedTotal = await context.TenantUsers
|
||||
.Where(f => f.UserId == request.UserId)
|
||||
.ExecuteUpdateAsync(f => f.SetProperty(u => u.Status, request.Status), cancellationToken);
|
||||
|
||||
return Result.OkIf(changedTotal > 0, UpdateError.Create("No records updated"));
|
||||
}));
|
||||
|
||||
public async Task<Result> CreateTenantOrganisationAsync(string organisationIdHash, string tenantIdHash, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result>>)(async () =>
|
||||
{
|
||||
var organisationDecodeResult = hashService.DecodeLongIdHash(organisationIdHash);
|
||||
|
||||
if (organisationDecodeResult.IsFailed)
|
||||
return Result.Fail(IdDecodeError.Create()
|
||||
.CausedBy(organisationDecodeResult.Errors));
|
||||
|
||||
var tenantDecodeResult = hashService.DecodeLongIdHash(tenantIdHash);
|
||||
|
||||
if (tenantDecodeResult.IsFailed)
|
||||
return Result.Fail(IdDecodeError.Create()
|
||||
.CausedBy(tenantDecodeResult.Errors));
|
||||
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
if (await context.TenantOrganisations.AnyAsync(to => to.OrganisationId == organisationDecodeResult.Value && to.TenantId == tenantDecodeResult.Value, cancellationToken))
|
||||
return Result.Fail(ValidationError.Create("Already exists"));
|
||||
|
||||
context.TenantOrganisations.Add(new Domain.Entities.TenantOrganisation
|
||||
{
|
||||
CreatedAt = DateTime.UtcNow,
|
||||
CreatedBy = userId,
|
||||
OrganisationId = organisationDecodeResult.Value,
|
||||
TenantId = tenantDecodeResult.ValueOrDefault
|
||||
});
|
||||
|
||||
return Result.OkIf(await context.SaveChangesAsync(cancellationToken) > 0,
|
||||
CreateError.Create("Failed to create tenant organisation map"));
|
||||
}));
|
||||
|
||||
public async Task<Result> UpdateTenantOrganisationAsync(string tenantOrganisationIdHash, ActivityStatus status, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result>>)(async () =>
|
||||
{
|
||||
var decodeResult = hashService.DecodeLongIdHash(tenantOrganisationIdHash);
|
||||
|
||||
if (decodeResult.IsFailed)
|
||||
return Result.Fail(IdDecodeError.Create()
|
||||
.CausedBy(decodeResult.Errors));
|
||||
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
var changedTotal = await context.TenantOrganisations
|
||||
.Where(f => f.Id == decodeResult.Value)
|
||||
.ExecuteUpdateAsync(f => f.SetProperty(u => u.Status, status), cancellationToken);
|
||||
|
||||
return Result.OkIf(changedTotal > 0, UpdateError.Create("Failed to update tenant organisation map"));
|
||||
}));
|
||||
|
||||
public async Task<Result<TenantOrganisation[]>> GetTenantOrganisationsAsync(CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<TenantOrganisation[]>>>)(async () =>
|
||||
{
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
var tenantOrganisations = await context.TenantOrganisations.AsNoTracking()
|
||||
.Include(i => i.Organisation)
|
||||
.Include(i => i.Tenant)
|
||||
.Where(f => f.TenantId == tenantContext.TenantId)
|
||||
.ToListAsync();
|
||||
|
||||
return Result.Ok(tenantOrganisations?.Select(i => i.Map()).ToArray() ?? []);
|
||||
}));
|
||||
|
||||
public async Task<Result<TenantOrganisation>> GetTenantOrganisationAsync(string tenantOrganisationIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<TenantOrganisation>>>)(async () =>
|
||||
{
|
||||
var decodeResult = hashService.DecodeLongIdHash(tenantOrganisationIdHash);
|
||||
|
||||
if (decodeResult.IsFailed)
|
||||
return Result.Fail(IdDecodeError.Create()
|
||||
.CausedBy(decodeResult.Errors));
|
||||
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
var tenantOrganisation = await context.TenantOrganisations.AsNoTracking()
|
||||
.Include(i => i.Organisation)
|
||||
.Include(i => i.Tenant)
|
||||
.FirstOrDefaultAsync(f => f.TenantId == tenantContext.TenantId, cancellationToken);
|
||||
|
||||
return Result.FailIf(tenantOrganisation is null, NotFoundError.Create("Failed to find tenant organisation map"))
|
||||
.ToResult(tenantOrganisation!.Map());
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@ using static PostFundManagement.Domain.Extensions.Constants;
|
||||
|
||||
namespace PostFundManagement.Application.Services.Governance;
|
||||
|
||||
public sealed record CreateTenantRequest([Required][MaxLength(LabelLength)] string Name);
|
||||
|
||||
public sealed record UpdateTenantUserRequest([Required] Guid UserId, [Required] ActivityStatus Status);
|
||||
|
||||
public sealed record CreateTenantUserRequest([Required] long TenantId, [Required] Guid UserId);
|
||||
@@ -11,8 +13,6 @@ public sealed record UpdateTenantRequest([Required] long TenantId,
|
||||
[Required][MaxLength(LabelLength)] string Name,
|
||||
[Required] ActivityStatus Status);
|
||||
|
||||
public sealed record CreateTenantRequest([Required] long TenantId, [Required][MaxLength(LabelLength)] string Name);
|
||||
|
||||
public sealed record UpdatePortfolioRequest([Required] long PortfolioId,
|
||||
[Required][MaxLength(LabelLength)] string Name,
|
||||
[Required][MaxLength(TextLength)] string Description,
|
||||
@@ -27,7 +27,8 @@ public sealed record UpdateOrganisationRequest([Required] long OrganisationId,
|
||||
[Required][MaxLength(LabelLength)] string Name,
|
||||
[Required][MaxLength(LabelLength)] string RegistrationNo,
|
||||
[Required][EmailAddress][MaxLength(LabelLength)] string Email,
|
||||
[Required] OrganisationType Type);
|
||||
[Required] OrganisationType Type,
|
||||
[Required] ActivityStatus Status);
|
||||
|
||||
public sealed record CreateOrganisationRequest([Required][MaxLength(LabelLength)] string Name,
|
||||
[Required][MaxLength(LabelLength)] string RegistrationNo,
|
||||
|
||||
@@ -86,45 +86,197 @@ public sealed class ProjectCacheService(ProjectService service, IDistributedCach
|
||||
return Result.Ok(cached.FromJson<Domain.Models.Activity>());
|
||||
}));
|
||||
|
||||
public Task<Result<Beneficiary[]>> GetBeneficiariesAsync(string projectIdHash, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
public async Task<Result<Beneficiary[]>> GetBeneficiariesAsync(string projectIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Beneficiary[]>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetBeneficiariesAsync(projectIdHash, cancellationToken);
|
||||
|
||||
public Task<Result<Beneficiary>> GetBeneficiaryAsync(string beneficiaryIdHash, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
var cacheKey = HashService.ToMd5Hash($"getbeneficiaries-{projectIdHash}").Value;
|
||||
|
||||
public Task<Result<ChangeRequest>> GetChangeRequestAsync(string changeRequestIdHash, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
|
||||
|
||||
public Task<Result<ChangeRequest[]>> GetChangeRequestsAsync(string projectIdHash, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
if (string.IsNullOrWhiteSpace(cached))
|
||||
{
|
||||
var result = await service.GetBeneficiariesAsync(projectIdHash, cancellationToken);
|
||||
|
||||
public Task<Result<ComplianceItem>> GetComplianceItemAsync(string complianceItemIdHash, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
if (result.IsFailed) return result;
|
||||
|
||||
public Task<Result<ComplianceItem[]>> GetComplianceItemsAsync(string projectIdHash, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
await cache.SetStringAsync(cacheKey, result.Value.ToJson(), cacheOptions, cancellationToken);
|
||||
|
||||
public Task<Result<Issue>> GetIssueAsync(string issueIdHash, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
return result.Value;
|
||||
}
|
||||
|
||||
public Task<Result<Issue[]>> GetIssuesAsync(string projectIdHash, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
return Result.Ok(cached.FromJson<Beneficiary[]>());
|
||||
}));
|
||||
|
||||
public async Task<Result<Beneficiary>> GetBeneficiaryAsync(string beneficiaryIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Beneficiary>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetBeneficiaryAsync(beneficiaryIdHash, cancellationToken);
|
||||
|
||||
var cacheKey = HashService.ToMd5Hash($"getbeneficiary-{beneficiaryIdHash}").Value;
|
||||
|
||||
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(cached))
|
||||
{
|
||||
var result = await service.GetBeneficiaryAsync(beneficiaryIdHash, cancellationToken);
|
||||
|
||||
if (result.IsFailed) return result;
|
||||
|
||||
await cache.SetStringAsync(cacheKey, result.Value.ToJson(), cacheOptions, cancellationToken);
|
||||
|
||||
return result.Value;
|
||||
}
|
||||
|
||||
return Result.Ok(cached.FromJson<Beneficiary>());
|
||||
}));
|
||||
|
||||
public async Task<Result<ChangeRequest>> GetChangeRequestAsync(string changeRequestIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<ChangeRequest>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetChangeRequestAsync(changeRequestIdHash, cancellationToken);
|
||||
|
||||
var cacheKey = HashService.ToMd5Hash($"getchangerequest-{changeRequestIdHash}").Value;
|
||||
|
||||
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(cached))
|
||||
{
|
||||
var result = await service.GetChangeRequestAsync(changeRequestIdHash, cancellationToken);
|
||||
|
||||
if (result.IsFailed) return result;
|
||||
|
||||
await cache.SetStringAsync(cacheKey, result.Value.ToJson(), cacheOptions, cancellationToken);
|
||||
|
||||
return result.Value;
|
||||
}
|
||||
|
||||
return Result.Ok(cached.FromJson<ChangeRequest>());
|
||||
}));
|
||||
|
||||
public async Task<Result<ChangeRequest[]>> GetChangeRequestsAsync(string projectIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<ChangeRequest[]>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetChangeRequestsAsync(projectIdHash, cancellationToken);
|
||||
|
||||
var cacheKey = HashService.ToMd5Hash($"getchangerequests-{projectIdHash}").Value;
|
||||
|
||||
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(cached))
|
||||
{
|
||||
var result = await service.GetChangeRequestsAsync(projectIdHash, cancellationToken);
|
||||
|
||||
if (result.IsFailed) return result;
|
||||
|
||||
await cache.SetStringAsync(cacheKey, result.Value.ToJson(), cacheOptions, cancellationToken);
|
||||
|
||||
return result.Value;
|
||||
}
|
||||
|
||||
return Result.Ok(cached.FromJson<ChangeRequest[]>());
|
||||
}));
|
||||
|
||||
public async Task<Result<ComplianceItem>> GetComplianceItemAsync(string complianceItemIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<ComplianceItem>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetComplianceItemAsync(complianceItemIdHash, cancellationToken);
|
||||
|
||||
var cacheKey = HashService.ToMd5Hash($"getcomplianceitem-{complianceItemIdHash}").Value;
|
||||
|
||||
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(cached))
|
||||
{
|
||||
var result = await service.GetComplianceItemAsync(complianceItemIdHash, cancellationToken);
|
||||
|
||||
if (result.IsFailed) return result;
|
||||
|
||||
await cache.SetStringAsync(cacheKey, result.Value.ToJson(), cacheOptions, cancellationToken);
|
||||
|
||||
return result.Value;
|
||||
}
|
||||
|
||||
return Result.Ok(cached.FromJson<ComplianceItem>());
|
||||
}));
|
||||
|
||||
public async Task<Result<ComplianceItem[]>> GetComplianceItemsAsync(string projectIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<ComplianceItem[]>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetComplianceItemsAsync(projectIdHash, cancellationToken);
|
||||
|
||||
var cacheKey = HashService.ToMd5Hash($"getcomplianceitems-{projectIdHash}").Value;
|
||||
|
||||
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(cached))
|
||||
{
|
||||
var result = await service.GetComplianceItemsAsync(projectIdHash, cancellationToken);
|
||||
|
||||
if (result.IsFailed) return result;
|
||||
|
||||
await cache.SetStringAsync(cacheKey, result.Value.ToJson(), cacheOptions, cancellationToken);
|
||||
|
||||
return result.Value;
|
||||
}
|
||||
|
||||
return Result.Ok(cached.FromJson<ComplianceItem[]>());
|
||||
}));
|
||||
|
||||
public async Task<Result<Issue>> GetIssueAsync(string issueIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Issue>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetIssueAsync(issueIdHash, cancellationToken);
|
||||
|
||||
var cacheKey = HashService.ToMd5Hash($"getissue-{issueIdHash}").Value;
|
||||
|
||||
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(cached))
|
||||
{
|
||||
var result = await service.GetIssueAsync(issueIdHash, cancellationToken);
|
||||
|
||||
if (result.IsFailed) return result;
|
||||
|
||||
await cache.SetStringAsync(cacheKey, result.Value.ToJson(), cacheOptions, cancellationToken);
|
||||
|
||||
return result.Value;
|
||||
}
|
||||
|
||||
return Result.Ok(cached.FromJson<Issue>());
|
||||
}));
|
||||
|
||||
public async Task<Result<Issue[]>> GetIssuesAsync(string projectIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Issue[]>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetIssuesAsync(projectIdHash, cancellationToken);
|
||||
|
||||
var cacheKey = HashService.ToMd5Hash($"getissues-{projectIdHash}").Value;
|
||||
|
||||
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(cached))
|
||||
{
|
||||
var result = await service.GetIssuesAsync(projectIdHash, cancellationToken);
|
||||
|
||||
if (result.IsFailed) return result;
|
||||
|
||||
await cache.SetStringAsync(cacheKey, result.Value.ToJson(), cacheOptions, cancellationToken);
|
||||
|
||||
return result.Value;
|
||||
}
|
||||
|
||||
return Result.Ok(cached.FromJson<Issue[]>());
|
||||
}));
|
||||
|
||||
public async Task<Result<Milestone>> GetMilestoneAsync(string milestoneIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Milestone>>>)(async () =>
|
||||
@@ -174,15 +326,53 @@ public sealed class ProjectCacheService(ProjectService service, IDistributedCach
|
||||
return Result.Ok(cached.FromJson<Milestone[]>());
|
||||
}));
|
||||
|
||||
public Task<Result<Outcome>> GetOutcomeAsync(string outcomeIdHash, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
public async Task<Result<Outcome>> GetOutcomeAsync(string outcomeIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Outcome>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetOutcomeAsync(outcomeIdHash, cancellationToken);
|
||||
|
||||
public Task<Result<Outcome[]>> GetOutcomesAsync(string beneficiaryIdHash, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
var cacheKey = HashService.ToMd5Hash($"getoutcome-{outcomeIdHash}").Value;
|
||||
|
||||
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(cached))
|
||||
{
|
||||
var result = await service.GetOutcomeAsync(outcomeIdHash, cancellationToken);
|
||||
|
||||
if (result.IsFailed) return result;
|
||||
|
||||
await cache.SetStringAsync(cacheKey, result.Value.ToJson(), cacheOptions, cancellationToken);
|
||||
|
||||
return result.Value;
|
||||
}
|
||||
|
||||
return Result.Ok(cached.FromJson<Outcome>());
|
||||
}));
|
||||
|
||||
public async Task<Result<Outcome[]>> GetOutcomesAsync(string beneficiaryIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Outcome[]>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetOutcomesAsync(beneficiaryIdHash, cancellationToken);
|
||||
|
||||
var cacheKey = HashService.ToMd5Hash($"getoutcomes-{beneficiaryIdHash}").Value;
|
||||
|
||||
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(cached))
|
||||
{
|
||||
var result = await service.GetOutcomesAsync(beneficiaryIdHash, cancellationToken);
|
||||
|
||||
if (result.IsFailed) return result;
|
||||
|
||||
await cache.SetStringAsync(cacheKey, result.Value.ToJson(), cacheOptions, cancellationToken);
|
||||
|
||||
return result.Value;
|
||||
}
|
||||
|
||||
return Result.Ok(cached.FromJson<Outcome[]>());
|
||||
}));
|
||||
|
||||
public async Task<Result<Programme>> GetProgrammeAsync(string programmeIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Programme>>>)(async () =>
|
||||
@@ -376,20 +566,58 @@ public sealed class ProjectCacheService(ProjectService service, IDistributedCach
|
||||
return Result.Ok(cached.FromJson<Project[]>());
|
||||
}));
|
||||
|
||||
public Task<Result<SiteVisit>> GetSiteVisitAsync(string SiteVisitIdHash, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
public async Task<Result<SiteVisit>> GetSiteVisitAsync(string siteVisitIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<SiteVisit>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetSiteVisitAsync(siteVisitIdHash, cancellationToken);
|
||||
|
||||
public Task<Result<SiteVisit[]>> GetSiteVisitsAsync(string projectIdHash, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
var cacheKey = HashService.ToMd5Hash($"getsitevisit-{siteVisitIdHash}").Value;
|
||||
|
||||
public async Task<Result> UpdateBeneficiaryItemAsync(UpdateBeneficiaryRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await service.UpdateBeneficiaryItemAsync(request, userId, cancellationToken);
|
||||
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
|
||||
|
||||
public async Task<Result> UpdateChangeRequestAsync(UpdatehangeRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
if (string.IsNullOrWhiteSpace(cached))
|
||||
{
|
||||
var result = await service.GetSiteVisitAsync(siteVisitIdHash, cancellationToken);
|
||||
|
||||
if (result.IsFailed) return result;
|
||||
|
||||
await cache.SetStringAsync(cacheKey, result.Value.ToJson(), cacheOptions, cancellationToken);
|
||||
|
||||
return result.Value;
|
||||
}
|
||||
|
||||
return Result.Ok(cached.FromJson<SiteVisit>());
|
||||
}));
|
||||
|
||||
public async Task<Result<SiteVisit[]>> GetSiteVisitsAsync(string projectIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<SiteVisit[]>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetSiteVisitsAsync(projectIdHash, cancellationToken);
|
||||
|
||||
var cacheKey = HashService.ToMd5Hash($"getsitevisits-{projectIdHash}").Value;
|
||||
|
||||
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(cached))
|
||||
{
|
||||
var result = await service.GetSiteVisitsAsync(projectIdHash, cancellationToken);
|
||||
|
||||
if (result.IsFailed) return result;
|
||||
|
||||
await cache.SetStringAsync(cacheKey, result.Value.ToJson(), cacheOptions, cancellationToken);
|
||||
|
||||
return result.Value;
|
||||
}
|
||||
|
||||
return Result.Ok(cached.FromJson<SiteVisit[]>());
|
||||
}));
|
||||
|
||||
public async Task<Result> UpdateBeneficiaryAsync(UpdateBeneficiaryRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await service.UpdateBeneficiaryAsync(request, userId, cancellationToken);
|
||||
|
||||
public async Task<Result> UpdateChangeRequestAsync(UpdateChangeRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await service.UpdateChangeRequestAsync(request, userId, cancellationToken);
|
||||
|
||||
public async Task<Result> UpdateComplianceItemAsync(UpdateComplianceItemRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
|
||||
@@ -383,123 +383,443 @@ public sealed class ProjectService(IDbContextFactory<ApplicationDbContext> conte
|
||||
return Result.Ok(projects.Select(i => i.Map()).ToArray());
|
||||
}));
|
||||
|
||||
public Task<Result> CreateChangeRequestAsync(CreateChangeRequest request, Guid userId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
public async Task<Result> CreateChangeRequestAsync(CreateChangeRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result>>)(async () =>
|
||||
{
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
public Task<Result> UpdateChangeRequestAsync(UpdatehangeRequest request, Guid userId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
if (await context.Projects.AnyAsync(p => p.Id == request.ProjectId, cancellationToken))
|
||||
return Result.Fail(ValidationError.Create("Project does not exist"));
|
||||
|
||||
public Task<Result<ChangeRequest[]>> GetChangeRequestsAsync(string projectIdHash, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
context.ChangeRequests.Add(new Domain.Entities.ChangeRequest
|
||||
{
|
||||
ProjectId = request.ProjectId,
|
||||
Title = request.Title,
|
||||
Justification = request.Justification,
|
||||
RevisedBudget = request.RevisedBudget,
|
||||
RevisedEndedAt = request.RevisionDate,
|
||||
Status = ApprovalStatus.Pending,
|
||||
CreatedAt = DateTime.UtcNow,
|
||||
CreatedBy = userId,
|
||||
TenantId = tenantContext.TenantId,
|
||||
});
|
||||
|
||||
public Task<Result<ChangeRequest>> GetChangeRequestAsync(string changeRequestIdHash, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
return Result.OkIf(await context.SaveChangesAsync(cancellationToken) > 0,
|
||||
CreateError.Create("Failed to create change request"));
|
||||
}));
|
||||
|
||||
public Task<Result> CreateComplianceItemAsync(CreateComplianceItemRequest request, Guid userId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
public async Task<Result> UpdateChangeRequestAsync(UpdateChangeRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result>>)(async () =>
|
||||
{
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
public Task<Result> UpdateComplianceItemAsync(UpdateComplianceItemRequest request, Guid userId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
var changedTotal = await context.ChangeRequests
|
||||
.Where(c => c.Id == request.ChangeRequestId)
|
||||
.ExecuteUpdateAsync(f => f
|
||||
.SetProperty(u => u.Status, request.Status)
|
||||
.SetProperty(u => u.RevisedBudget, request.RevisedBudget)
|
||||
.SetProperty(u => u.RevisedEndedAt, DateTime.UtcNow)
|
||||
.SetProperty(u => u.Title, request.Title.Humanize(LetterCasing.Title).Trim())
|
||||
.SetProperty(u => u.Justification, request.Justification), cancellationToken);
|
||||
|
||||
public Task<Result<ComplianceItem[]>> GetComplianceItemsAsync(string projectIdHash, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
return Result.OkIf(changedTotal > 0, UpdateError.Create("No records were changed"));
|
||||
}));
|
||||
|
||||
public Task<Result<ComplianceItem>> GetComplianceItemAsync(string complianceItemIdHash, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
public async Task<Result<ChangeRequest[]>> GetChangeRequestsAsync(string projectIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<ChangeRequest[]>>>)(async () =>
|
||||
{
|
||||
var decodeResult = hashService.DecodeLongIdHash(projectIdHash);
|
||||
|
||||
public Task<Result> CreateBeneficiaryAsync(CreateBeneficiaryRequest request, Guid userId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
if (decodeResult.IsFailed)
|
||||
return Result.Fail<ChangeRequest[]>(IdDecodeError.Create()
|
||||
.CausedBy(decodeResult.Errors));
|
||||
|
||||
public Task<Result> UpdateBeneficiaryItemAsync(UpdateBeneficiaryRequest request, Guid userId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
public Task<Result<Beneficiary[]>> GetBeneficiariesAsync(string projectIdHash, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
var changeRequests = await context.ChangeRequests.AsNoTracking()
|
||||
.Where(c => c.ProjectId == decodeResult.Value)
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
public Task<Result<Beneficiary>> GetBeneficiaryAsync(string beneficiaryIdHash, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
return Result.Ok(changeRequests?.Select(i => i.Map()).ToArray() ?? []);
|
||||
}));
|
||||
|
||||
public Task<Result> CreateIssueAsync(CreateIssueRequest request, Guid userId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
public async Task<Result<ChangeRequest>> GetChangeRequestAsync(string changeRequestIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<ChangeRequest>>>)(async () =>
|
||||
{
|
||||
var decodeResult = hashService.DecodeLongIdHash(changeRequestIdHash);
|
||||
|
||||
public Task<Result> UpdateIssueAsync(UpdateIssueRequest request, Guid userId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
if (decodeResult.IsFailed)
|
||||
return Result.Fail<ChangeRequest>(IdDecodeError.Create()
|
||||
.CausedBy(decodeResult.Errors));
|
||||
|
||||
public Task<Result<Issue[]>> GetIssuesAsync(string projectIdHash, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
public Task<Result<Issue>> GetIssueAsync(string issueIdHash, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
var changeRequest = await context.ChangeRequests.AsNoTracking().FirstOrDefaultAsync(c => c.Id == decodeResult.Value, cancellationToken);
|
||||
|
||||
public Task<Result> CreateOutcomeAsync(CreateOutcomeRequest request, Guid userId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
return Result.FailIf(changeRequest is null, NotFoundError.New)
|
||||
.ToResult(changeRequest!.Map());
|
||||
}));
|
||||
|
||||
public Task<Result> UpdateOutcomeAsync(UpdateOutcomeRequest request, Guid userId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
public async Task<Result> CreateComplianceItemAsync(CreateComplianceItemRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result>>)(async () =>
|
||||
{
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
public Task<Result<Outcome[]>> GetOutcomesAsync(string beneficiaryIdHash, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
if (await context.Projects.AnyAsync(p => p.Id == request.ProjectId, cancellationToken))
|
||||
return Result.Fail(ValidationError.Create("Project does not exist"));
|
||||
|
||||
public Task<Result<Outcome>> GetOutcomeAsync(string outcomeIdHash, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
context.ComplianceItems.Add(new Domain.Entities.ComplianceItem
|
||||
{
|
||||
CreatedAt = DateTime.UtcNow,
|
||||
CreatedBy = userId,
|
||||
ProjectId = request.ProjectId,
|
||||
Requirements = request.Requirements,
|
||||
Status = ApprovalStatus.Pending,
|
||||
TenantId = tenantContext.TenantId,
|
||||
Title = request.Title.Humanize(LetterCasing.Title).Trim()
|
||||
});
|
||||
|
||||
public Task<Result> CreateSiteVisitAsync(CreateSiteVisitRequest request, Guid userId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
return Result.OkIf(await context.SaveChangesAsync(cancellationToken) > 0, CreateError.Create("Failed to create compliance item"));
|
||||
}));
|
||||
|
||||
public Task<Result> UpdateSiteVisitAsync(UpdateSiteVisitRequest request, Guid userId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
public async Task<Result> UpdateComplianceItemAsync(UpdateComplianceItemRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result>>)(async () =>
|
||||
{
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
public Task<Result<SiteVisit[]>> GetSiteVisitsAsync(string projectIdHash, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
var changedTotal = await context.ComplianceItems
|
||||
.Where(f => f.Id == request.ComplianceItemId)
|
||||
.ExecuteUpdateAsync(f => f
|
||||
.SetProperty(u => u.Title, request.Title.Humanize(LetterCasing.Title).Trim())
|
||||
.SetProperty(u => u.Requirements, request.Requirements)
|
||||
.SetProperty(u => u.Status, request.Status), cancellationToken);
|
||||
|
||||
public Task<Result<SiteVisit>> GetSiteVisitAsync(string SiteVisitIdHash, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
return Result.OkIf(changedTotal > 0, UpdateError.Create("No records changed"));
|
||||
}));
|
||||
|
||||
public async Task<Result<ComplianceItem[]>> GetComplianceItemsAsync(string projectIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<ComplianceItem[]>>>)(async () =>
|
||||
{
|
||||
var decodeResult = hashService.DecodeLongIdHash(projectIdHash);
|
||||
|
||||
if (decodeResult.IsFailed)
|
||||
return Result.Fail<ComplianceItem[]>(IdDecodeError.Create()
|
||||
.CausedBy(decodeResult.Errors));
|
||||
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
var complianceItems = await context.ComplianceItems.AsNoTracking()
|
||||
.Where(c => c.ProjectId == decodeResult.Value)
|
||||
.OrderByDescending(o => o.Id)
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
return Result.Ok(complianceItems?.Select(i => i.Map()).ToArray() ?? []);
|
||||
}));
|
||||
|
||||
public async Task<Result<ComplianceItem>> GetComplianceItemAsync(string complianceItemIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<ComplianceItem>>>)(async () =>
|
||||
{
|
||||
var decodeResult = hashService.DecodeLongIdHash(complianceItemIdHash);
|
||||
|
||||
if (decodeResult.IsFailed)
|
||||
return Result.Fail<ComplianceItem>(IdDecodeError.Create()
|
||||
.CausedBy(decodeResult.Errors));
|
||||
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
var compliancItem = await context.ComplianceItems.AsNoTracking().FirstOrDefaultAsync(c => c.Id == decodeResult.Value, cancellationToken);
|
||||
|
||||
return Result.FailIf(compliancItem is null, NotFoundError.New)
|
||||
.ToResult(compliancItem!.Map());
|
||||
}));
|
||||
|
||||
public async Task<Result> CreateBeneficiaryAsync(CreateBeneficiaryRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result>>)(async () =>
|
||||
{
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
context.Beneficiaries.Add(new Domain.Entities.Beneficiary
|
||||
{
|
||||
Category = request.Category,
|
||||
CreatedAt = DateTime.UtcNow,
|
||||
CreatedBy = userId,
|
||||
Location = request.Location,
|
||||
Name = request.Name.Humanize(LetterCasing.Title).Trim(),
|
||||
ProjectId = request.ProjectId,
|
||||
ReachedCount = request.ReachedCount,
|
||||
TargetCount = request.TargetCount,
|
||||
UserId = userId,
|
||||
TenantId = tenantContext.TenantId
|
||||
});
|
||||
|
||||
return Result.OkIf(await context.SaveChangesAsync(cancellationToken) > 0,
|
||||
CreateError.Create("Failed to create beneficiary"));
|
||||
}));
|
||||
|
||||
public async Task<Result> UpdateBeneficiaryAsync(UpdateBeneficiaryRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result>>)(async () =>
|
||||
{
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
var changedTotal = await context.Beneficiaries
|
||||
.Where(f => f.Id == request.BeneficiaryId)
|
||||
.ExecuteUpdateAsync(f => f
|
||||
.SetProperty(u => u.ReachedCount, request.ReachedCount)
|
||||
.SetProperty(u => u.TargetCount, request.TargetCount)
|
||||
.SetProperty(u => u.Location, request.Location)
|
||||
.SetProperty(u => u.Category, request.Category.Humanize(LetterCasing.Title).Trim())
|
||||
.SetProperty(u => u.Name, request.Name.Humanize(LetterCasing.Title).Trim()), cancellationToken);
|
||||
|
||||
return Result.OkIf(changedTotal > 0, UpdateError.Create("No records changed"));
|
||||
}));
|
||||
|
||||
public async Task<Result<Beneficiary[]>> GetBeneficiariesAsync(string projectIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Beneficiary[]>>>)(async () =>
|
||||
{
|
||||
var decodeResult = hashService.DecodeLongIdHash(projectIdHash);
|
||||
|
||||
if (decodeResult.IsFailed)
|
||||
return Result.Fail<Beneficiary[]>(IdDecodeError.Create()
|
||||
.CausedBy(decodeResult.Errors));
|
||||
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
var beneficiaries = await context.Beneficiaries.AsNoTracking()
|
||||
.Where(b => b.ProjectId == decodeResult.Value)
|
||||
.OrderByDescending(o => o.Id)
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
return Result.Ok(beneficiaries?.Select(i => i.Map()).ToArray() ?? []);
|
||||
}));
|
||||
|
||||
public async Task<Result<Beneficiary>> GetBeneficiaryAsync(string beneficiaryIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Beneficiary>>>)(async () =>
|
||||
{
|
||||
var decodeResult = hashService.DecodeLongIdHash(beneficiaryIdHash);
|
||||
|
||||
if (decodeResult.IsFailed)
|
||||
return Result.Fail<Beneficiary>(IdDecodeError.Create()
|
||||
.CausedBy(decodeResult.Errors));
|
||||
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
var beneficiary = await context.Beneficiaries.AsNoTracking()
|
||||
.FirstOrDefaultAsync(b => b.Id == decodeResult.Value, cancellationToken);
|
||||
|
||||
return Result.FailIf(beneficiary is null, NotFoundError.New)
|
||||
.ToResult(beneficiary!.Map());
|
||||
}));
|
||||
|
||||
public async Task<Result> CreateIssueAsync(CreateIssueRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result>>)(async () =>
|
||||
{
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
context.Issues.Add(new Domain.Entities.Issue
|
||||
{
|
||||
AssignedTo = request.AssignedTo,
|
||||
CreatedAt = DateTime.UtcNow,
|
||||
CreatedBy = userId,
|
||||
Description = request.Description,
|
||||
Priority = request.Priority,
|
||||
ProjectId = request.ProjectId,
|
||||
Status = ActivityStatus.Active,
|
||||
TenantId = tenantContext.TenantId,
|
||||
Title = request.Title.Humanize(LetterCasing.Title).Trim()
|
||||
});
|
||||
|
||||
return Result.OkIf(await context.SaveChangesAsync(cancellationToken) > 0, CreateError.Create("Failed to create issue"));
|
||||
}));
|
||||
|
||||
public async Task<Result> UpdateIssueAsync(UpdateIssueRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result>>)(async () =>
|
||||
{
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
var changedTotal = await context.Issues
|
||||
.Where(i => i.Id == request.IssueId)
|
||||
.ExecuteUpdateAsync(f => f
|
||||
.SetProperty(u => u.Title, request.Title.Humanize(LetterCasing.Title).Trim())
|
||||
.SetProperty(u => u.Description, request.Description)
|
||||
.SetProperty(u => u.Resolution, request.Resolution)
|
||||
.SetProperty(u => u.ResolvedAt, DateTime.UtcNow)
|
||||
.SetProperty(u => u.Status, request.Status)
|
||||
.SetProperty(u => u.AssignedTo, request.AssignedTo), cancellationToken);
|
||||
|
||||
return Result.OkIf(changedTotal > 0, UpdateError.Create("No records changes"));
|
||||
}));
|
||||
|
||||
public async Task<Result<Issue[]>> GetIssuesAsync(string projectIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Issue[]>>>)(async () =>
|
||||
{
|
||||
var decodeResult = hashService.DecodeLongIdHash(projectIdHash);
|
||||
|
||||
if (decodeResult.IsFailed)
|
||||
return Result.Fail<Issue[]>(IdDecodeError.Create()
|
||||
.CausedBy(decodeResult.Errors));
|
||||
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
var issues = await context.Issues.AsNoTracking()
|
||||
.Where(i => i.ProjectId == decodeResult.Value)
|
||||
.OrderByDescending(o => o.Id)
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
return Result.Ok(issues?.Select(i => i.Map()).ToArray() ?? []);
|
||||
}));
|
||||
|
||||
public async Task<Result<Issue>> GetIssueAsync(string issueIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Issue>>>)(async () =>
|
||||
{
|
||||
var decodeResult = hashService.DecodeLongIdHash(issueIdHash);
|
||||
|
||||
if (decodeResult.IsFailed)
|
||||
return Result.Fail<Issue>(IdDecodeError.Create()
|
||||
.CausedBy(decodeResult.Errors));
|
||||
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
var issue = await context.Issues.AsNoTracking().FirstOrDefaultAsync(i => i.Id == decodeResult.Value, cancellationToken);
|
||||
|
||||
return Result.FailIf(issue is null, NotFoundError.New)
|
||||
.ToResult(issue!.Map());
|
||||
}));
|
||||
|
||||
public async Task<Result> CreateOutcomeAsync(CreateOutcomeRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result>>)(async () =>
|
||||
{
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
context.Outcomes.Add(new Domain.Entities.Outcome
|
||||
{
|
||||
BeneficiaryId = request.BeneficiaryId,
|
||||
CreatedAt = DateTime.UtcNow,
|
||||
CreatedBy = userId,
|
||||
Description = request.Description,
|
||||
Name = request.Name.Humanize(LetterCasing.Title).Trim(),
|
||||
TenantId = tenantContext.TenantId
|
||||
});
|
||||
|
||||
return Result.OkIf(await context.SaveChangesAsync(cancellationToken) > 0, CreateError.Create("Failed to create outcome"));
|
||||
}));
|
||||
|
||||
public async Task<Result> UpdateOutcomeAsync(UpdateOutcomeRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result>>)(async () =>
|
||||
{
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
var changedTotal = await context.Outcomes
|
||||
.Where(o => o.Id == request.OutcomeId)
|
||||
.ExecuteUpdateAsync(f => f
|
||||
.SetProperty(u => u.Description, request.Description)
|
||||
.SetProperty(u => u.Name, request.Name.Humanize(LetterCasing.Title).Trim()), cancellationToken);
|
||||
|
||||
return Result.OkIf(changedTotal > 0, UpdateError.Create("No records changed"));
|
||||
}));
|
||||
|
||||
public async Task<Result<Outcome[]>> GetOutcomesAsync(string beneficiaryIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Outcome[]>>>)(async () =>
|
||||
{
|
||||
var decodeResult = hashService.DecodeLongIdHash(beneficiaryIdHash);
|
||||
|
||||
if (decodeResult.IsFailed)
|
||||
return Result.Fail<Outcome[]>(IdDecodeError.Create()
|
||||
.CausedBy(decodeResult.Errors));
|
||||
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
var outcomes = await context.Outcomes.AsNoTracking()
|
||||
.Where(o => o.BeneficiaryId == decodeResult.Value)
|
||||
.OrderByDescending(o => o.Id)
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
return Result.Ok(outcomes?.Select(o => o.Map()).ToArray() ?? []);
|
||||
}));
|
||||
|
||||
public async Task<Result<Outcome>> GetOutcomeAsync(string outcomeIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Outcome>>>)(async () =>
|
||||
{
|
||||
var decodeResult = hashService.DecodeLongIdHash(outcomeIdHash);
|
||||
|
||||
if (decodeResult.IsFailed)
|
||||
return Result.Fail<Outcome>(IdDecodeError.Create()
|
||||
.CausedBy(decodeResult.Errors));
|
||||
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
var outcome = await context.Outcomes.AsNoTracking()
|
||||
.FirstOrDefaultAsync(o => o.Id == decodeResult.Value, cancellationToken);
|
||||
|
||||
return Result.FailIf(outcome is null, NotFoundError.New)
|
||||
.ToResult(outcome!.Map());
|
||||
}));
|
||||
|
||||
public async Task<Result> CreateSiteVisitAsync(CreateSiteVisitRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result>>)(async () =>
|
||||
{
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
context.SiteVisits.Add(new Domain.Entities.SiteVisit
|
||||
{
|
||||
CreatedAt = DateTime.UtcNow,
|
||||
CreatedBy = userId,
|
||||
InspectorName = request.InspectorName.Humanize(LetterCasing.Title).Trim(),
|
||||
Findings = request.Findings,
|
||||
VisitedAt = request.VisitedAt
|
||||
});
|
||||
|
||||
return Result.OkIf(await context.SaveChangesAsync(cancellationToken) > 0, CreateError.Create("Failed to create site visit"));
|
||||
}));
|
||||
|
||||
public async Task<Result> UpdateSiteVisitAsync(UpdateSiteVisitRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result>>)(async () =>
|
||||
{
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
var changedTotal = await context.SiteVisits
|
||||
.Where(v => v.Id == request.SiteVisitId)
|
||||
.ExecuteUpdateAsync(f => f
|
||||
.SetProperty(u => u.InspectorName, request.InspectorName.Humanize(LetterCasing.Title).Trim())
|
||||
.SetProperty(u => u.Findings, request.Findings)
|
||||
.SetProperty(u => u.Status, request.Status)
|
||||
.SetProperty(u => u.VisitedAt, request.VisitedAt), cancellationToken);
|
||||
|
||||
return Result.OkIf(changedTotal > 0, UpdateError.Create("Failed to update site visit"));
|
||||
}));
|
||||
|
||||
public async Task<Result<SiteVisit[]>> GetSiteVisitsAsync(string projectIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<SiteVisit[]>>>)(async () =>
|
||||
{
|
||||
var decodeResult = hashService.DecodeLongIdHash(projectIdHash);
|
||||
|
||||
if (decodeResult.IsFailed)
|
||||
return Result.Fail<SiteVisit[]>(IdDecodeError.Create()
|
||||
.CausedBy(decodeResult.Errors));
|
||||
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
var visits = await context.SiteVisits.AsNoTracking()
|
||||
.Where(v => v.ProjectId == decodeResult.Value)
|
||||
.OrderByDescending(o => o.Id)
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
return Result.Ok(visits?.Select(i => i.Map()).ToArray() ?? []);
|
||||
}));
|
||||
|
||||
public async Task<Result<SiteVisit>> GetSiteVisitAsync(string siteVisitIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<SiteVisit>>>)(async () =>
|
||||
{
|
||||
var decodeResult = hashService.DecodeLongIdHash(siteVisitIdHash);
|
||||
|
||||
if (decodeResult.IsFailed)
|
||||
return Result.Fail<SiteVisit>(IdDecodeError.Create()
|
||||
.CausedBy(decodeResult.Errors));
|
||||
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
var visit = await context.SiteVisits.AsNoTracking().FirstOrDefaultAsync(v => v.Id == decodeResult.Value, cancellationToken);
|
||||
|
||||
return Result.FailIf(visit is null, NotFoundError.New)
|
||||
.ToResult(visit!.Map());
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ public sealed record CreateComplianceItemRequest([Required] long ProjectId,
|
||||
[Required][MaxLength(LabelLength)] string Title,
|
||||
[Required][MaxLength(TextLength)] string Requirements);
|
||||
|
||||
public sealed record UpdatehangeRequest([Required] long ChangeRequestId,
|
||||
public sealed record UpdateChangeRequest([Required] long ChangeRequestId,
|
||||
[Required][MaxLength(LabelLength)] string Title,
|
||||
[Required][MaxLength(TextLength)] string Justification,
|
||||
[Required] decimal RevisedBudget,
|
||||
|
||||
@@ -12,6 +12,7 @@ public sealed class IdentityService(IDbContextFactory<ApplicationDbContext> cont
|
||||
{
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
// TODO: Ensure TenantUser status is checked
|
||||
var userExistsAndActive = await context.Users
|
||||
.AnyAsync(u => u.Id == userId && u.Status == ActivityStatus.Active, cancellationToken);
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using PostFundManagement.Application.Abstractions.Services;
|
||||
using PostFundManagement.Domain;
|
||||
using PostFundManagement.Domain.Abstractions;
|
||||
using PostFundManagement.Domain.Errors;
|
||||
using PostFundManagement.Domain.Extensions;
|
||||
using PostFundManagement.Domain.Models;
|
||||
@@ -7,16 +8,19 @@ using PostFundManagement.Infrastructure.Database;
|
||||
|
||||
namespace PostFundManagement.Application.Services.Users;
|
||||
|
||||
public sealed class UserService(IDbContextFactory<ApplicationDbContext> contextFactory) : IUserService
|
||||
public sealed class UserService(IDbContextFactory<ApplicationDbContext> contextFactory, ITenantContextService tenantContext) : IUserService
|
||||
{
|
||||
public async Task<Result> SyncUserAsync(Guid userId, string email, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result>>)(async () =>
|
||||
{
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
var user = await context.Users.FirstOrDefaultAsync(u => u.Id == userId, cancellationToken);
|
||||
var tenantUser = await context.TenantUsers
|
||||
.Include(i => i.User)
|
||||
.FirstOrDefaultAsync(u => u.UserId == userId, cancellationToken);
|
||||
|
||||
if (user is null)
|
||||
if (tenantUser is null)
|
||||
{
|
||||
context.Users.Add(new Domain.Entities.User
|
||||
{
|
||||
Id = userId,
|
||||
@@ -24,12 +28,22 @@ public sealed class UserService(IDbContextFactory<ApplicationDbContext> contextF
|
||||
Status = ActivityStatus.Active,
|
||||
LastLoginAt = DateTime.UtcNow
|
||||
});
|
||||
|
||||
context.TenantUsers.Add(new Domain.Entities.TenantUser
|
||||
{
|
||||
CreatedAt = DateTime.UtcNow,
|
||||
CreatedBy = userId,
|
||||
Status = ActivityStatus.Active,
|
||||
TenantId = tenantContext.TenantId,
|
||||
UserId = userId
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
user!.Email = email;
|
||||
user.LastLoginAt = DateTime.UtcNow;
|
||||
tenantUser.User!.Email = email;
|
||||
tenantUser.User.LastLoginAt = DateTime.UtcNow;
|
||||
|
||||
context.Users.Update(user);
|
||||
context.Users.Update(tenantUser.User);
|
||||
}
|
||||
|
||||
return Result.OkIf(await context.SaveChangesAsync(cancellationToken) > 0, CreateError.New);
|
||||
@@ -40,19 +54,19 @@ public sealed class UserService(IDbContextFactory<ApplicationDbContext> contextF
|
||||
{
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
var query = context.Users.AsNoTracking();
|
||||
var query = context.TenantUsers.Include(i => i.User).AsNoTracking();
|
||||
|
||||
if (request.Status.HasValue)
|
||||
query = query.Where(u => u.Status == request.Status.Value);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(request.Email))
|
||||
query = query.Where(u => u.Email != null && u.Email.Contains(request.Email));
|
||||
query = query.Where(u => u.User!.Email != null && u.User!.Email.Contains(request.Email));
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(request.SortBy))
|
||||
query = request.SortBy.ToLowerInvariant() switch
|
||||
{
|
||||
"email" => request.SortDescending ? query.OrderByDescending(u => u.Email) : query.OrderBy(u => u.Email),
|
||||
"lastloginat" => request.SortDescending ? query.OrderByDescending(u => u.LastLoginAt) : query.OrderBy(u => u.LastLoginAt),
|
||||
"email" => request.SortDescending ? query.OrderByDescending(u => u.User!.Email) : query.OrderBy(u => u.User!.Email),
|
||||
"lastloginat" => request.SortDescending ? query.OrderByDescending(u => u.User!.LastLoginAt) : query.OrderBy(u => u.User!.LastLoginAt),
|
||||
"status" => request.SortDescending ? query.OrderByDescending(u => u.Status) : query.OrderBy(u => u.Status),
|
||||
_ => request.SortDescending ? query.OrderByDescending(u => u.Id) : query.OrderBy(u => u.Id)
|
||||
};
|
||||
@@ -62,7 +76,7 @@ public sealed class UserService(IDbContextFactory<ApplicationDbContext> contextF
|
||||
var users = await query.Skip((pagination.Page - 1) * pagination.PageSize)
|
||||
.Take(pagination.PageSize).ToListAsync(cancellationToken);
|
||||
|
||||
return Result.Ok(users.Select(u => u.Map()).ToArray());
|
||||
return Result.Ok(users.Select(u => u.User!.Map()).ToArray());
|
||||
}));
|
||||
|
||||
public async Task<Result> UpdateUserStatusAsync(Guid userId, ActivityStatus status, CancellationToken cancellationToken = default) =>
|
||||
@@ -70,8 +84,13 @@ public sealed class UserService(IDbContextFactory<ApplicationDbContext> contextF
|
||||
{
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
var changedTotal = await context.Users
|
||||
.Where(f => f.Id == userId)
|
||||
var changedTotal = await context.TenantUsers
|
||||
.Include(i => i.User)
|
||||
.Where(f => f.UserId == userId)
|
||||
.ExecuteUpdateAsync(f => f
|
||||
.SetProperty(u => u.Status, status), cancellationToken);
|
||||
|
||||
changedTotal += await context.Users.Where(f => f.Id == userId)
|
||||
.ExecuteUpdateAsync(f => f.SetProperty(u => u.Status, status), cancellationToken);
|
||||
|
||||
return Result.OkIf(changedTotal > 0, UpdateError.New);
|
||||
@@ -82,10 +101,11 @@ public sealed class UserService(IDbContextFactory<ApplicationDbContext> contextF
|
||||
{
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
var user = await context.Users.AsNoTracking()
|
||||
.FirstOrDefaultAsync(f => f.Id == userId, cancellationToken);
|
||||
var tenantUser = await context.TenantUsers.AsNoTracking()
|
||||
.Include(i => i.User)
|
||||
.FirstOrDefaultAsync(f => f.UserId == userId, cancellationToken);
|
||||
|
||||
return Result.FailIf(user == null, NotFoundError.New)
|
||||
.ToResult(user?.Map()!);
|
||||
return Result.FailIf(tenantUser == null, NotFoundError.New)
|
||||
.ToResult(tenantUser!.User?.Map()!);
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ public static class Mappers
|
||||
public static Activity Map(this Entities.Activity entity) => new()
|
||||
{
|
||||
Id = entity.Id,
|
||||
TenantId = entity.TenantId,
|
||||
Amount = entity.Amount,
|
||||
ApprovedBy = entity.ApprovedBy,
|
||||
Category = entity.Category,
|
||||
@@ -56,6 +57,7 @@ public static class Mappers
|
||||
public static AuditLog Map(this Entities.AuditLog entity) => new()
|
||||
{
|
||||
Id = entity.Id,
|
||||
TenantId = entity.TenantId,
|
||||
Action = entity.Action,
|
||||
Changes = entity.Changes,
|
||||
EntityId = entity.EntityId,
|
||||
@@ -83,6 +85,7 @@ public static class Mappers
|
||||
public static Beneficiary Map(this Entities.Beneficiary entity) => new()
|
||||
{
|
||||
Id = entity.Id,
|
||||
TenantId = entity.TenantId,
|
||||
Category = entity.Category,
|
||||
CreatedAt = entity.CreatedAt,
|
||||
CreatedBy = entity.CreatedBy,
|
||||
@@ -97,6 +100,7 @@ public static class Mappers
|
||||
public static Budget Map(this Entities.Budget entity) => new()
|
||||
{
|
||||
Id = entity.Id,
|
||||
TenantId = entity.TenantId,
|
||||
Amount = entity.Amount,
|
||||
ApprovedBy = entity.ApprovedBy,
|
||||
CreatedAt = entity.CreatedAt,
|
||||
@@ -106,9 +110,26 @@ public static class Mappers
|
||||
UpdatedAt = entity.UpdatedAt
|
||||
};
|
||||
|
||||
public static ChangeRequest Map(this Entities.ChangeRequest entity) => new()
|
||||
{
|
||||
ApprovedBy = entity.ApprovedBy,
|
||||
CreatedAt = entity.CreatedAt,
|
||||
CreatedBy = entity.CreatedBy,
|
||||
Id = entity.Id,
|
||||
Justification = entity.Justification,
|
||||
ProjectId = entity.ProjectId,
|
||||
RevisedBudget = entity.RevisedBudget,
|
||||
RevisedEndedAt = entity.RevisedEndedAt,
|
||||
Status = entity.Status,
|
||||
TenantId = entity.TenantId,
|
||||
Title = entity.Title,
|
||||
UpdatedAt = entity.UpdatedAt
|
||||
};
|
||||
|
||||
public static ComplianceItem Map(this Entities.ComplianceItem entity) => new()
|
||||
{
|
||||
Id = entity.Id,
|
||||
TenantId = entity.TenantId,
|
||||
CreatedAt = entity.CreatedAt,
|
||||
CreatedBy = entity.CreatedBy,
|
||||
ProjectId = entity.ProjectId,
|
||||
@@ -122,6 +143,7 @@ public static class Mappers
|
||||
public static Contract Map(this Entities.Contract entity) => new()
|
||||
{
|
||||
Id = entity.Id,
|
||||
TenantId = entity.TenantId,
|
||||
AwardId = entity.AwardId,
|
||||
CreatedAt = entity.CreatedAt,
|
||||
CreatedBy = entity.CreatedBy,
|
||||
@@ -136,6 +158,7 @@ public static class Mappers
|
||||
public static Disbursement Map(this Entities.Disbursement entity) => new()
|
||||
{
|
||||
Id = entity.Id,
|
||||
TenantId = entity.TenantId,
|
||||
Amount = entity.Amount,
|
||||
CreatedAt = entity.CreatedAt,
|
||||
CreatedBy = entity.CreatedBy,
|
||||
@@ -149,6 +172,7 @@ public static class Mappers
|
||||
public static Evidence Map(this Entities.Evidence entity) => new()
|
||||
{
|
||||
Id = entity.Id,
|
||||
TenantId = entity.TenantId,
|
||||
CreatedAt = entity.CreatedAt,
|
||||
CreatedBy = entity.CreatedBy,
|
||||
DocumentUrl = entity.DocumentUrl,
|
||||
@@ -166,6 +190,7 @@ public static class Mappers
|
||||
public static Indicator Map(this Entities.Indicator entity) => new()
|
||||
{
|
||||
Id = entity.Id,
|
||||
TenantId = entity.TenantId,
|
||||
ActualAmount = entity.ActualAmount,
|
||||
BaselineAmount = entity.BaselineAmount,
|
||||
CreatedAt = entity.CreatedAt,
|
||||
@@ -180,6 +205,7 @@ public static class Mappers
|
||||
{
|
||||
Id = entity.Id,
|
||||
Code = entity.Code,
|
||||
TenantId = entity.TenantId,
|
||||
CreatedAt = entity.CreatedAt,
|
||||
CreatedBy = entity.CreatedBy,
|
||||
Description = entity.Description,
|
||||
@@ -191,6 +217,7 @@ public static class Mappers
|
||||
public static Invite Map(this Entities.Invite entity) => new()
|
||||
{
|
||||
Id = entity.Id,
|
||||
TenantId = entity.TenantId,
|
||||
AwardId = entity.AwardId,
|
||||
ContractId = entity.ContractId,
|
||||
CreatedAt = entity.CreatedAt,
|
||||
@@ -205,6 +232,7 @@ public static class Mappers
|
||||
public static Issue Map(this Entities.Issue entity) => new()
|
||||
{
|
||||
Id = entity.Id,
|
||||
TenantId = entity.TenantId,
|
||||
CreatedAt = entity.CreatedAt,
|
||||
CreatedBy = entity.CreatedBy,
|
||||
Description = entity.Description,
|
||||
@@ -220,6 +248,7 @@ public static class Mappers
|
||||
public static Milestone Map(this Entities.Milestone entity) => new()
|
||||
{
|
||||
Id = entity.Id,
|
||||
TenantId = entity.TenantId,
|
||||
CreatedAt = entity.CreatedAt,
|
||||
CreatedBy = entity.CreatedBy,
|
||||
DueAt = entity.DueAt,
|
||||
@@ -233,7 +262,7 @@ public static class Mappers
|
||||
|
||||
public static Organisation Map(this Entities.Organisation entity) => new()
|
||||
{
|
||||
Id = entity.Id,
|
||||
Id = entity.Id,
|
||||
CreatedAt = entity.CreatedAt,
|
||||
CreatedBy = entity.CreatedBy,
|
||||
Email = entity.Email,
|
||||
@@ -246,6 +275,7 @@ public static class Mappers
|
||||
public static Outcome Map(this Entities.Outcome entity) => new()
|
||||
{
|
||||
Id = entity.Id,
|
||||
TenantId = entity.TenantId,
|
||||
BeneficiaryId = entity.BeneficiaryId,
|
||||
CreatedAt = entity.CreatedAt,
|
||||
CreatedBy = entity.CreatedBy,
|
||||
@@ -317,6 +347,7 @@ public static class Mappers
|
||||
public static Risk Map(this Entities.Risk entity) => new()
|
||||
{
|
||||
Id = entity.Id,
|
||||
TenantId = entity.TenantId,
|
||||
CreatedAt = entity.CreatedAt,
|
||||
CreatedBy = entity.CreatedBy,
|
||||
Description = entity.Description,
|
||||
@@ -329,6 +360,7 @@ public static class Mappers
|
||||
public static Rule Map(this Entities.Rule entity) => new()
|
||||
{
|
||||
Id = entity.Id,
|
||||
TenantId = entity.TenantId,
|
||||
CreatedAt = entity.CreatedAt,
|
||||
CreatedBy = entity.CreatedBy,
|
||||
Name = entity.Name,
|
||||
@@ -342,6 +374,7 @@ public static class Mappers
|
||||
public static SiteVisit Map(this Entities.SiteVisit entity) => new()
|
||||
{
|
||||
Id = entity.Id,
|
||||
TenantId = entity.TenantId,
|
||||
ProjectId = entity.ProjectId,
|
||||
CreatedAt = entity.CreatedAt,
|
||||
CreatedBy = entity.CreatedBy,
|
||||
|
||||
Reference in New Issue
Block a user