:drunk: AI trying to fix bugs
This commit is contained in:
203
DysonNetwork.Common/Services/Permission/PermissionService.cs
Normal file
203
DysonNetwork.Common/Services/Permission/PermissionService.cs
Normal file
@ -0,0 +1,203 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using NodaTime;
|
||||
using System.Text.Json;
|
||||
using DysonNetwork.Common.Models;
|
||||
using DysonNetwork.Common.Services;
|
||||
|
||||
namespace DysonNetwork.Common.Services.Permission;
|
||||
|
||||
public class PermissionService<TDbContext> where TDbContext : DbContext
|
||||
{
|
||||
private readonly TDbContext _db;
|
||||
private readonly ICacheService _cache;
|
||||
private static readonly TimeSpan CacheExpiration = TimeSpan.FromMinutes(1);
|
||||
|
||||
private const string PermCacheKeyPrefix = "perm:";
|
||||
private const string PermGroupCacheKeyPrefix = "perm-cg:";
|
||||
private const string PermissionGroupPrefix = "perm-g:";
|
||||
|
||||
public PermissionService(TDbContext db, ICacheService cache)
|
||||
{
|
||||
_db = db;
|
||||
_cache = cache;
|
||||
}
|
||||
|
||||
private static string GetPermissionCacheKey(string actor, string area, string key) =>
|
||||
PermCacheKeyPrefix + actor + ":" + area + ":" + key;
|
||||
|
||||
private static string GetGroupsCacheKey(string actor) =>
|
||||
PermGroupCacheKeyPrefix + actor;
|
||||
|
||||
private static string GetPermissionGroupKey(string actor) =>
|
||||
PermissionGroupPrefix + actor;
|
||||
|
||||
public async Task<bool> HasPermissionAsync(string actor, string area, string key)
|
||||
{
|
||||
var value = await GetPermissionAsync<bool>(actor, area, key);
|
||||
return value;
|
||||
}
|
||||
|
||||
public async Task<T?> GetPermissionAsync<T>(string actor, string area, string key)
|
||||
{
|
||||
var cacheKey = GetPermissionCacheKey(actor, area, key);
|
||||
|
||||
var (hit, cachedValue) = await _cache.GetAsyncWithStatus<T>(cacheKey);
|
||||
if (hit)
|
||||
return cachedValue;
|
||||
|
||||
var now = SystemClock.Instance.GetCurrentInstant();
|
||||
var groupsKey = GetGroupsCacheKey(actor);
|
||||
|
||||
var groupsId = await _cache.GetAsync<List<Guid>>(groupsKey);
|
||||
if (groupsId == null)
|
||||
{
|
||||
groupsId = await _db.Set<PermissionGroupMember>()
|
||||
.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();
|
||||
|
||||
await _cache.SetWithGroupsAsync(groupsKey, groupsId,
|
||||
[GetPermissionGroupKey(actor)],
|
||||
CacheExpiration);
|
||||
}
|
||||
|
||||
var permission = await _db.Set<PermissionNode>()
|
||||
.Where(n => (n.GroupId == null && n.Actor == actor) ||
|
||||
(n.GroupId != null && groupsId.Contains(n.GroupId.Value)))
|
||||
.Where(n => n.Key == key && n.Area == area)
|
||||
.Where(n => n.ExpiredAt == null || n.ExpiredAt > now)
|
||||
.Where(n => n.AffectedAt == null || n.AffectedAt <= now)
|
||||
.FirstOrDefaultAsync();
|
||||
|
||||
var result = permission is not null ? DeserializePermissionValue<T>(permission.Value) : default;
|
||||
|
||||
await _cache.SetWithGroupsAsync(cacheKey, result,
|
||||
[GetPermissionGroupKey(actor)],
|
||||
CacheExpiration);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<PermissionNode> AddPermissionNode<T>(
|
||||
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.Set<PermissionNode>().Add(node);
|
||||
await _db.SaveChangesAsync();
|
||||
|
||||
// Invalidate related caches
|
||||
await InvalidatePermissionCacheAsync(actor, area, key);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
public async Task<PermissionNode> AddPermissionNodeToGroup<T>(
|
||||
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.Set<PermissionNode>().Add(node);
|
||||
await _db.SaveChangesAsync();
|
||||
|
||||
// Invalidate related caches
|
||||
await InvalidatePermissionCacheAsync(actor, area, key);
|
||||
await _cache.RemoveAsync(GetGroupsCacheKey(actor));
|
||||
await _cache.RemoveGroupAsync(GetPermissionGroupKey(actor));
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
public async Task RemovePermissionNode(string actor, string area, string key)
|
||||
{
|
||||
var node = await _db.Set<PermissionNode>()
|
||||
.Where(n => n.Actor == actor && n.Area == area && n.Key == key)
|
||||
.FirstOrDefaultAsync();
|
||||
if (node is not null) _db.Set<PermissionNode>().Remove(node);
|
||||
await _db.SaveChangesAsync();
|
||||
|
||||
// Invalidate cache
|
||||
await InvalidatePermissionCacheAsync(actor, area, key);
|
||||
}
|
||||
|
||||
public async Task RemovePermissionNodeFromGroup(PermissionGroup group, string actor, string area, string key)
|
||||
{
|
||||
var node = await _db.Set<PermissionNode>()
|
||||
.Where(n => n.GroupId == group.Id)
|
||||
.Where(n => n.Actor == actor && n.Area == area && n.Key == key)
|
||||
.FirstOrDefaultAsync();
|
||||
if (node is null) return;
|
||||
_db.Set<PermissionNode>().Remove(node);
|
||||
await _db.SaveChangesAsync();
|
||||
|
||||
// Invalidate caches
|
||||
await InvalidatePermissionCacheAsync(actor, area, key);
|
||||
await _cache.RemoveAsync(GetGroupsCacheKey(actor));
|
||||
await _cache.RemoveGroupAsync(GetPermissionGroupKey(actor));
|
||||
}
|
||||
|
||||
private async Task InvalidatePermissionCacheAsync(string actor, string area, string key)
|
||||
{
|
||||
var cacheKey = GetPermissionCacheKey(actor, area, key);
|
||||
await _cache.RemoveAsync(cacheKey);
|
||||
}
|
||||
|
||||
private static T? DeserializePermissionValue<T>(JsonDocument json)
|
||||
{
|
||||
return JsonSerializer.Deserialize<T>(json.RootElement.GetRawText());
|
||||
}
|
||||
|
||||
private static JsonDocument SerializePermissionValue<T>(T obj)
|
||||
{
|
||||
var str = JsonSerializer.Serialize(obj);
|
||||
return JsonDocument.Parse(str);
|
||||
}
|
||||
|
||||
public static PermissionNode NewPermissionNode<T>(string actor, string area, string key, T value)
|
||||
{
|
||||
return new PermissionNode
|
||||
{
|
||||
Actor = actor,
|
||||
Area = area,
|
||||
Key = key,
|
||||
Value = SerializePermissionValue(value),
|
||||
};
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user