ChangeAsync(CurrentBifrostActor actor, Guid userAccountId, string? reason, bool suspend, CancellationToken cancellationToken)
+ {
+ if (!actor.CanManageMembership || actor.UserAccount is null)
+ {
+ return SuspensionOutcome.NotAdmin;
+ }
+
+ if (string.IsNullOrWhiteSpace(reason))
+ {
+ return SuspensionOutcome.NoReason;
+ }
+
+ var user = await dbContext.UserAccounts.Include(x => x.Membership).SingleOrDefaultAsync(x => x.Id == userAccountId, cancellationToken);
+ if (user?.Membership is not { } membership)
+ {
+ return SuspensionOutcome.NoSuchAccount;
+ }
+
+ // An admin cannot suspend themselves or another platform admin here: bootstrap admins are re-promoted at sign-in by configuration.
+ if (suspend && (user.Id == actor.UserAccount.Id || membership.IsPlatformAdmin))
+ {
+ return SuspensionOutcome.ProtectedAccount;
+ }
+
+ if (suspend == (membership.Status == MembershipStatus.Suspended))
+ {
+ return SuspensionOutcome.NotApplicable;
+ }
+
+ var before = membership.Status;
+ membership.Status = suspend
+ ? MembershipStatus.Suspended
+ : membership.ApprovedAtUtc is null ? MembershipStatus.Authenticated : MembershipStatus.Active;
+ var clipped = reason.Trim().Length > MaxReasonLength ? reason.Trim()[..MaxReasonLength] : reason.Trim();
+ await dbContext.SaveChangesAsync(cancellationToken);
+ await auditTrailService.RecordAsync(
+ actor.UserAccount.Id,
+ nameof(Membership),
+ membership.Id,
+ suspend ? "membership.suspended" : "membership.unsuspended",
+ $"{(suspend ? "Suspended" : "Unsuspended")} {user.DisplayName} ({before} -> {membership.Status}): {clipped}",
+ cancellationToken);
+ return SuspensionOutcome.Done;
+ }
+}
diff --git a/src/Bifrost.Web/Pages/App/Members/Index.cshtml b/src/Bifrost.Web/Pages/App/Members/Index.cshtml
index 0d9d546..b4d67e5 100644
--- a/src/Bifrost.Web/Pages/App/Members/Index.cshtml
+++ b/src/Bifrost.Web/Pages/App/Members/Index.cshtml
@@ -176,7 +176,7 @@
|
- @if (Model.Actor.CanManageMembership && user.Status != MembershipStatus.Active)
+ @if (Model.Actor.CanManageMembership && user.Status != MembershipStatus.Active && user.Status != MembershipStatus.Suspended)
{
}
+ @if (Model.Actor.CanManageMembership)
+ {
+
+ }
+
@if (Model.Actor.CanManageMembership)
{
|