using System.Text.Json; using Microsoft.EntityFrameworkCore; using NodaTime; namespace DysonNetwork.Sphere.Permission; public class PermissionService(AppDatabase db) { public async Task HasPermissionAsync(string actor, string area, string key) { var value = await GetPermissionAsync(actor, area, key); return value; } public async Task GetPermissionAsync(string actor, string area, string key) { var now = SystemClock.Instance.GetCurrentInstant(); var groupsId = await db.PermissionGroupMembers .Where(n => n.Actor == actor) .Where(n => n.ExpiredAt == null || n.ExpiredAt < now) .Where(n => n.AffectedAt == null || n.AffectedAt >= now) .Select(e => e.GroupId) .ToListAsync(); var permission = await db.PermissionNodes .Where(n => n.GroupId == null || groupsId.Contains(n.GroupId.Value)) .Where(n => n.Key == key && (n.GroupId != null || n.Actor == actor) && n.Area == area) .Where(n => n.ExpiredAt == null || n.ExpiredAt < now) .Where(n => n.AffectedAt == null || n.AffectedAt >= now) .FirstOrDefaultAsync(); return permission is not null ? _DeserializePermissionValue(permission.Value) : default; } public async Task AddPermissionNode( string actor, string area, string key, T value, Instant? expiredAt = null, Instant? affectedAt = null ) { if (value is null) throw new ArgumentNullException(nameof(value)); var node = new PermissionNode { Actor = actor, Key = key, Area = area, Value = _SerializePermissionValue(value), ExpiredAt = expiredAt, AffectedAt = affectedAt }; db.PermissionNodes.Add(node); await db.SaveChangesAsync(); return node; } public async Task AddPermissionNodeToGroup( PermissionGroup group, string actor, string area, string key, T value, Instant? expiredAt = null, Instant? affectedAt = null ) { if (value is null) throw new ArgumentNullException(nameof(value)); var node = new PermissionNode { Actor = actor, Key = key, Area = area, Value = _SerializePermissionValue(value), ExpiredAt = expiredAt, AffectedAt = affectedAt, Group = group, GroupId = group.Id }; db.PermissionNodes.Add(node); await db.SaveChangesAsync(); return node; } public async Task RemovePermissionNode(string actor, string area, string key) { var node = await db.PermissionNodes .Where(n => n.Actor == actor && n.Area == area && n.Key == key) .FirstOrDefaultAsync(); if (node is not null) db.PermissionNodes.Remove(node); await db.SaveChangesAsync(); } public async Task RemovePermissionNodeFromGroup(PermissionGroup group, string actor, string area, string key) { var node = await db.PermissionNodes .Where(n => n.GroupId == group.Id) .Where(n => n.Actor == actor && n.Area == area && n.Key == key) .FirstOrDefaultAsync(); if (node is null) return; db.PermissionNodes.Remove(node); await db.SaveChangesAsync(); } private static T? _DeserializePermissionValue(JsonDocument json) { return JsonSerializer.Deserialize(json.RootElement.GetRawText()); } private static JsonDocument _SerializePermissionValue(T obj) { var str = JsonSerializer.Serialize(obj); return JsonDocument.Parse(str); } public static PermissionNode NewPermissionNode(string actor, string area, string key, T value) { return new PermissionNode { Actor = actor, Area = area, Key = key, Value = _SerializePermissionValue(value), }; } }