mirror of
https://github.com/Sea-Haven-Industries/shoc-backend.git
synced 2026-09-30 17:43:12 +00:00
Stamp WorkOrder.AccountId on all create paths and filter board/list/search/detail by server-derived account claims so scoped callers cannot cross accounts. Co-authored-by: Cursor <cursoragent@cursor.com>
73 lines
2.7 KiB
C#
73 lines
2.7 KiB
C#
using System.Security.Claims;
|
|
using SeaHaven.DataServices.Interfaces;
|
|
using SeaHaven.Services.Exceptions;
|
|
using SeaHaven.Services.Helpers;
|
|
using SeaHaven.Services.Interfaces;
|
|
|
|
namespace SeaHaven.Services.Implementation
|
|
{
|
|
public class WorkOrderAccountResolver : IWorkOrderAccountResolver
|
|
{
|
|
private readonly IAccountDataService _accounts;
|
|
|
|
public WorkOrderAccountResolver(IAccountDataService accounts)
|
|
{
|
|
_accounts = accounts;
|
|
}
|
|
|
|
public int? ResolveAccountFilter(ClaimsPrincipal user)
|
|
{
|
|
return WorkOrderMediaAuthorization.ResolveMediaScope(user) switch
|
|
{
|
|
MediaAccountScope.Account account => account.AccountId,
|
|
MediaAccountScope.OrgWide => null,
|
|
_ => throw new WorkOrderBoardValidationException(
|
|
"Forbidden",
|
|
"You are not allowed to access work orders without account scope.")
|
|
};
|
|
}
|
|
|
|
public async Task<int> ResolveForAuthenticatedCreateAsync(
|
|
ClaimsPrincipal user,
|
|
string? customer,
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
switch (WorkOrderMediaAuthorization.ResolveMediaScope(user))
|
|
{
|
|
case MediaAccountScope.Account account:
|
|
return account.AccountId;
|
|
|
|
case MediaAccountScope.OrgWide:
|
|
return await ResolveRequiredFromCustomerAsync(customer, cancellationToken);
|
|
|
|
default:
|
|
throw new WorkOrderBoardValidationException(
|
|
"Forbidden",
|
|
"You are not allowed to create work orders without account scope.");
|
|
}
|
|
}
|
|
|
|
public Task<int> ResolveForUnauthenticatedCreateAsync(
|
|
string? customer,
|
|
CancellationToken cancellationToken = default)
|
|
=> ResolveRequiredFromCustomerAsync(customer, cancellationToken);
|
|
|
|
public Task<int?> TryResolveFromCustomerAsync(
|
|
string? customer,
|
|
CancellationToken cancellationToken = default)
|
|
=> _accounts.TryGetUniqueActiveIdByExactNameAsync(customer, cancellationToken);
|
|
|
|
private async Task<int> ResolveRequiredFromCustomerAsync(
|
|
string? customer,
|
|
CancellationToken cancellationToken)
|
|
{
|
|
var resolved = await TryResolveFromCustomerAsync(customer, cancellationToken);
|
|
if (resolved is int accountId)
|
|
return accountId;
|
|
|
|
throw new WorkOrderBoardValidationException(
|
|
"AccountUnresolved",
|
|
"Work order account could not be resolved from customer.");
|
|
}
|
|
}
|
|
}
|