137 lines
7.0 KiB
C#
137 lines
7.0 KiB
C#
using Microsoft.EntityFrameworkCore;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
using Tiku.Application.PlatformAdmin;
|
|
using Tiku.Application.Security;
|
|
using Tiku.Domain.Identity;
|
|
using Tiku.Domain.Operations;
|
|
using Tiku.Domain.Tenancy;
|
|
|
|
namespace Tiku.Infrastructure.PlatformAdmin;
|
|
|
|
internal sealed class PlatformStaffAccessService(PlatformAdministrationDependencies dependencies)
|
|
: PlatformAdministrationServiceBase(dependencies), IPlatformStaffAccessService
|
|
{
|
|
public async Task<PlatformStaffList> GetStaffAsync(
|
|
PlatformAdminActor actor,
|
|
PlatformAdminQuery query,
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
await AssertPlatformPermissionAsync(actor, BackendPermissions.PlatformStaffManage, cancellationToken);
|
|
return await ExecuteSystemAsync("platform staff list", async dbContext =>
|
|
{
|
|
var roleRows = await (
|
|
from userRole in dbContext.PlatformBackendUserRoles.AsNoTracking()
|
|
join role in dbContext.PlatformBackendRoles.AsNoTracking() on userRole.RoleId equals role.Id
|
|
join user in dbContext.Users.AsNoTracking() on userRole.UserId equals user.Id
|
|
select new { user, role.Code })
|
|
.ToArrayAsync(cancellationToken);
|
|
var items = roleRows
|
|
.GroupBy(row => row.user.Id)
|
|
.Select(group => ToStaffItem(group.First().user,
|
|
group.Select(row => row.Code).Distinct(StringComparer.Ordinal).Order(StringComparer.Ordinal)
|
|
.ToArray()))
|
|
.OrderBy(item => item.Email ?? item.PhoneMasked ?? item.UserId.ToString())
|
|
.Take(Limit(query.Limit))
|
|
.ToArray();
|
|
return new PlatformStaffList(items);
|
|
}, cancellationToken);
|
|
}
|
|
|
|
public async Task<PlatformStaffItem> UpsertStaffAsync(
|
|
PlatformAdminActor actor,
|
|
UpsertPlatformStaffCommand command,
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
await AssertPlatformPermissionAsync(actor, BackendPermissions.PlatformStaffManage, cancellationToken);
|
|
return await ExecuteSystemAsync("platform staff upsert", async (provider, dbContext) =>
|
|
{
|
|
var user = command.UserId.HasValue
|
|
? await dbContext.Users.SingleOrDefaultAsync(item => item.Id == command.UserId.Value, cancellationToken)
|
|
: await dbContext.Users.SingleOrDefaultAsync(item =>
|
|
(!string.IsNullOrWhiteSpace(command.Email) && item.Email == command.Email) ||
|
|
(!string.IsNullOrWhiteSpace(command.Phone) && item.Phone == command.Phone),
|
|
cancellationToken);
|
|
if (user is null)
|
|
{
|
|
user = new User
|
|
{
|
|
Email = Normalize(command.Email),
|
|
NormalizedEmail = Normalize(command.Email)?.ToUpperInvariant(),
|
|
UserName = Normalize(command.Email) ?? Normalize(command.Phone),
|
|
NormalizedUserName = (Normalize(command.Email) ?? Normalize(command.Phone))?.ToUpperInvariant(),
|
|
Phone = Normalize(command.Phone),
|
|
PhoneNumber = Normalize(command.Phone),
|
|
Name = Normalize(command.Name),
|
|
PrimaryRole = "platform_admin",
|
|
Status = command.Status,
|
|
ForcePasswordChange = true
|
|
};
|
|
dbContext.Users.Add(user);
|
|
}
|
|
else
|
|
{
|
|
user.Email = Normalize(command.Email) ?? user.Email;
|
|
user.NormalizedEmail = user.Email?.ToUpperInvariant();
|
|
user.Phone = Normalize(command.Phone) ?? user.Phone;
|
|
user.PhoneNumber = user.Phone;
|
|
user.Name = Normalize(command.Name) ?? user.Name;
|
|
user.Status = command.Status;
|
|
user.PrimaryRole = "platform_admin";
|
|
}
|
|
|
|
var roleIds = command.RoleIds.Distinct().ToArray();
|
|
var roleCount =
|
|
await dbContext.PlatformBackendRoles.CountAsync(role => roleIds.Contains(role.Id), cancellationToken);
|
|
if (roleCount != roleIds.Length)
|
|
throw new PlatformAdminException("One or more platform roles were not found.", "role_not_found");
|
|
|
|
await dbContext.SaveChangesAsync(cancellationToken);
|
|
await dbContext.PlatformBackendUserRoles.Where(binding => binding.UserId == user.Id)
|
|
.ExecuteDeleteAsync(cancellationToken);
|
|
dbContext.PlatformBackendUserRoles.AddRange(roleIds.Select(roleId => new PlatformBackendUserRole
|
|
{
|
|
UserId = user.Id,
|
|
RoleId = roleId
|
|
}));
|
|
AddAudit(dbContext, actor, "platform.staff.upserted", user.Id,
|
|
new { user.Email, Phone = MaskPhone(user.Phone), user.Status, RoleIds = roleIds });
|
|
await dbContext.SaveChangesAsync(cancellationToken);
|
|
var invalidator = provider.GetRequiredService<IAuthorizationStateInvalidator>();
|
|
await invalidator.InvalidateUserAsync(user.Id, cancellationToken);
|
|
await invalidator.BumpScopeAsync(AuthRealm.Platform, null, cancellationToken);
|
|
var roleCodes = await dbContext.PlatformBackendRoles.AsNoTracking()
|
|
.Where(role => roleIds.Contains(role.Id))
|
|
.Select(role => role.Code)
|
|
.ToArrayAsync(cancellationToken);
|
|
return ToStaffItem(user, roleCodes);
|
|
}, cancellationToken);
|
|
}
|
|
|
|
public async Task<PlatformStaffItem> UpdateStaffStatusAsync(
|
|
PlatformAdminActor actor,
|
|
UpdatePlatformStaffStatusCommand command,
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
await AssertPlatformPermissionAsync(actor, BackendPermissions.PlatformStaffManage, cancellationToken);
|
|
return await ExecuteSystemAsync("platform staff status update", async (provider, dbContext) =>
|
|
{
|
|
var user = await dbContext.Users.SingleOrDefaultAsync(item => item.Id == command.UserId, cancellationToken)
|
|
?? throw new PlatformAdminException("Platform staff user was not found.", "staff_not_found");
|
|
var from = user.Status;
|
|
user.Status = command.Status;
|
|
AddAudit(dbContext, actor, "platform.staff.status_changed", user.Id,
|
|
new { From = from, To = command.Status, command.Reason });
|
|
await dbContext.SaveChangesAsync(cancellationToken);
|
|
await provider.GetRequiredService<IAuthorizationStateInvalidator>()
|
|
.InvalidateUserAsync(user.Id, cancellationToken);
|
|
var roleCodes = await (
|
|
from binding in dbContext.PlatformBackendUserRoles.AsNoTracking()
|
|
join role in dbContext.PlatformBackendRoles.AsNoTracking() on binding.RoleId equals role.Id
|
|
where binding.UserId == user.Id
|
|
select role.Code)
|
|
.ToArrayAsync(cancellationToken);
|
|
return ToStaffItem(user, roleCodes);
|
|
}, cancellationToken);
|
|
}
|
|
}
|