mirror of
https://github.com/Sea-Haven-Industries/shoc-backend.git
synced 2026-09-30 04:53:11 +00:00
fix(dashboard): scope Trend by picker and admit Scheduler to dispatcher picker
ResolveDispatcherScope now admits the Scheduler role, which owns the viewAllDispatchersOnDashboard permission, so it can load Stats, Workload, Performance, Regions and Trend instead of being denied. GetTrendAsync now resolves scope via the shared ResolveDispatcherScope so a picker DispatcherId selection scopes Trend consistently with the other endpoints and unauthorized roles fail closed. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
f564e1b112
commit
564bd70301
2 changed files with 24 additions and 6 deletions
|
|
@ -517,6 +517,23 @@ public class DashboardServiceTests
|
|||
stats.Total.Should().Be(1);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetStatsAsync_SchedulerSelectionScopesStats()
|
||||
{
|
||||
using var ctx = NewContext();
|
||||
ctx.workOrders.AddRange(
|
||||
new WorkOrder { AccountId = 1, Status = "Open", AssignTo = "dispatcher-1" },
|
||||
new WorkOrder { AccountId = 1, Status = "Open", AssignTo = "dispatcher-2" });
|
||||
ctx.SaveChanges();
|
||||
|
||||
var stats = await NewService(ctx).GetStatsAsync(
|
||||
AccountUser(1, "scheduler-1", "Scheduler"),
|
||||
new DashboardStatsQueryDTO { DispatcherId = "dispatcher-2" },
|
||||
CancellationToken.None);
|
||||
|
||||
stats.Total.Should().Be(1);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetDashboardAsync_UnauthorizedRoleFailsClosed()
|
||||
{
|
||||
|
|
@ -543,6 +560,11 @@ public class DashboardServiceTests
|
|||
user, new DashboardStatsQueryDTO(), CancellationToken.None);
|
||||
var regionsException = await regionsAct.Should().ThrowAsync<WorkOrderBoardValidationException>();
|
||||
regionsException.Which.Code.Should().Be("Forbidden");
|
||||
|
||||
var trendAct = () => service.GetTrendAsync(
|
||||
user, new DashboardTrendQueryDTO(), CancellationToken.None);
|
||||
var trendException = await trendAct.Should().ThrowAsync<WorkOrderBoardValidationException>();
|
||||
trendException.Which.Code.Should().Be("Forbidden");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
|
|||
|
|
@ -183,11 +183,7 @@ namespace SeaHaven.Services.Implementation
|
|||
CancellationToken cancellationToken)
|
||||
{
|
||||
var accountId = _accountResolver.ResolveAccountFilter(user);
|
||||
var dispatcherId = user.IsInRole("Dispatcher")
|
||||
? user.FindFirstValue(ClaimTypes.NameIdentifier)
|
||||
: null;
|
||||
if (user.IsInRole("Dispatcher") && string.IsNullOrWhiteSpace(dispatcherId))
|
||||
throw new WorkOrderBoardValidationException("Forbidden", "Dispatcher identity is required.");
|
||||
var dispatcherId = ResolveDispatcherScope(user, query);
|
||||
|
||||
var today = DashboardBusinessTime.Today();
|
||||
var (windowFrom, windowTo, granularity) = ResolveTrendWindow(query, today);
|
||||
|
|
@ -402,7 +398,7 @@ namespace SeaHaven.Services.Implementation
|
|||
return dispatcherId;
|
||||
}
|
||||
|
||||
if (user.IsInRole("Admin") || user.IsInRole("Manager"))
|
||||
if (user.IsInRole("Admin") || user.IsInRole("Manager") || user.IsInRole("Scheduler"))
|
||||
{
|
||||
var selected = query.DispatcherId;
|
||||
if (string.IsNullOrWhiteSpace(selected))
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue