Update: Text Channel Stuff
Bugs: Files don't work Bugs: Video In-Line don't work Added: idk, everything?
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -2,16 +2,13 @@ using System.Text.Json;
|
||||
using RelayServer.Models;
|
||||
using RelayServer.Services.Chat;
|
||||
using RelayServer.Services.Crypto;
|
||||
using RelayShared.Services;
|
||||
using SurrealDb.Net;
|
||||
|
||||
namespace RelayServer.Services.Core;
|
||||
|
||||
public sealed class ServerBootstrapService
|
||||
{
|
||||
// TODO: Make channels dynamically addable
|
||||
// TODO: Add logic for channel types (ENUM)
|
||||
// TODO: Add logic for channel groups for future UI use
|
||||
|
||||
private readonly SurrealDbClient _db;
|
||||
private readonly CoreClientService _coreClient;
|
||||
private readonly ChannelCryptoService _cryptoService;
|
||||
@@ -29,8 +26,8 @@ public sealed class ServerBootstrapService
|
||||
public async Task InitializeAsync()
|
||||
{
|
||||
var keeper = await _coreClient.GetUserByUsernameAsync("Keeper317");
|
||||
var kira = await _coreClient.GetUserByUsernameAsync("Ru_Kira");
|
||||
var test = await _coreClient.GetUserByUsernameAsync("Test");
|
||||
var kira = await _coreClient.GetUserByUsernameAsync("Ru_Kira");
|
||||
var test = await _coreClient.GetUserByUsernameAsync("Test");
|
||||
|
||||
if (keeper is null || kira is null || test is null)
|
||||
throw new InvalidOperationException("One or more required users do not exist in RelayCore.");
|
||||
@@ -38,9 +35,7 @@ public sealed class ServerBootstrapService
|
||||
if (!keeper.Licensed || !kira.Licensed || !test.Licensed)
|
||||
throw new InvalidOperationException("One or more required users are not licensed.");
|
||||
|
||||
Console.WriteLine($"Core verified user: {keeper.Username}");
|
||||
Console.WriteLine($"Core verified user: {kira.Username}");
|
||||
Console.WriteLine($"Core verified user: {test.Username}");
|
||||
Console.WriteLine($"Core verified: {keeper.Username}, {kira.Username}, {test.Username}");
|
||||
|
||||
var server = await GetServerByNameAsync("Test Server");
|
||||
|
||||
@@ -52,44 +47,61 @@ public sealed class ServerBootstrapService
|
||||
OwnerUserId = keeper.Id,
|
||||
CreatedAt = DateTime.UtcNow
|
||||
});
|
||||
|
||||
Console.WriteLine($"Server created: {ToJsonString(server)}");
|
||||
Console.WriteLine($"Server created: {ToJson(server)}");
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine($"Server already exists: {ToJsonString(server)}");
|
||||
Console.WriteLine($"Server already exists: {server.Name}");
|
||||
}
|
||||
|
||||
await EnsureServerMemberAsync(keeper.Id, true);
|
||||
await EnsureServerMemberAsync(kira.Id, false);
|
||||
await EnsureServerMemberAsync(test.Id, false);
|
||||
|
||||
await EnsureServerMemberAsync(keeper.Id, isOwner: true);
|
||||
await EnsureServerMemberAsync(kira.Id, isOwner: false);
|
||||
await EnsureServerMemberAsync(test.Id, isOwner: false);
|
||||
Console.WriteLine("Server members ensured.");
|
||||
|
||||
var channel = await EnsureChannelAsync("general", DateTime.UtcNow);
|
||||
var channel2 = await EnsureChannelAsync("files", DateTime.UtcNow.Subtract(new TimeSpan(0, 4, 0, 0)));
|
||||
var channel3 = await EnsureChannelAsync("welcome", DateTime.UtcNow.Subtract(new TimeSpan(1, 4, 4, 4)));
|
||||
var channel4 = await EnsureChannelAsync("voice-general", DateTime.UtcNow.Subtract(new TimeSpan(0, 2, 0, 0)));
|
||||
var tBase = new DateTime(2024, 1, 1, 0, 0, 0, DateTimeKind.Utc);
|
||||
|
||||
Console.WriteLine($"Resolved channelId: {GetRecordId(channel.Id)}");
|
||||
Console.WriteLine($"Resolved channelId: {GetRecordId(channel2.Id)}");
|
||||
Console.WriteLine($"Resolved channelId: {GetRecordId(channel3.Id)}");
|
||||
Console.WriteLine($"Resolved channelId: {GetRecordId(channel4.Id)}");
|
||||
var chWelcome = await EnsureChannelAsync("welcome", ChannelType.Text, group: "General", isReadOnly: true, createdAt: tBase);
|
||||
var chGeneral = await EnsureChannelAsync("general", ChannelType.Text, group: "General", isReadOnly: false, createdAt: tBase.AddHours(1));
|
||||
var chFiles = await EnsureChannelAsync("files", ChannelType.File, group: "General", isReadOnly: true, createdAt: tBase.AddHours(2));
|
||||
var chVoice = await EnsureChannelAsync("voice-general", ChannelType.Voice, group: "General", isReadOnly: false, createdAt: tBase.AddHours(3));
|
||||
|
||||
Console.WriteLine($"Channels: {GetRecordId(chWelcome.Id)} | {GetRecordId(chGeneral.Id)} | {GetRecordId(chFiles.Id)} | {GetRecordId(chVoice.Id)}");
|
||||
|
||||
await EnsureFileChannelLinkAsync(chGeneral, GetRecordId(chFiles.Id));
|
||||
|
||||
var adminRole = await EnsureRoleAsync("Admin", PermissionFlags.Administrator, priority: 0);
|
||||
var modRole = await EnsureRoleAsync("Moderator", PermissionFlags.ReadMessages | PermissionFlags.SendMessages | PermissionFlags.ManageMessages, priority: 1);
|
||||
var memberRole = await EnsureRoleAsync("Member", PermissionFlags.ReadMessages | PermissionFlags.SendMessages, priority: 2);
|
||||
|
||||
Console.WriteLine($"Roles ensured: Admin={GetRecordId(adminRole.Id)}, Mod={GetRecordId(modRole.Id)}, Member={GetRecordId(memberRole.Id)}");
|
||||
|
||||
await SetUserRoleAsync(keeper.Id, GetRecordId(adminRole.Id));
|
||||
await SetUserRoleAsync(kira.Id, GetRecordId(modRole.Id));
|
||||
await SetUserRoleAsync(test.Id, GetRecordId(memberRole.Id));
|
||||
Console.WriteLine("User roles set.");
|
||||
|
||||
await EnsureChannelPermissionAsync(GetRecordId(chWelcome.Id), GetRecordId(memberRole.Id),
|
||||
allow: PermissionFlags.ReadMessages, deny: PermissionFlags.SendMessages);
|
||||
await EnsureChannelPermissionAsync(GetRecordId(chFiles.Id), GetRecordId(memberRole.Id),
|
||||
allow: PermissionFlags.ReadMessages, deny: PermissionFlags.SendMessages);
|
||||
|
||||
Console.WriteLine("Channel permissions ensured.");
|
||||
|
||||
var existingKey = await GetLatestServerEncryptionKeyAsync();
|
||||
|
||||
if (existingKey is null)
|
||||
{
|
||||
var keyBase64 = _cryptoService.GenerateKey();
|
||||
var keyBase64 = _cryptoService.GenerateKey();
|
||||
var serverKeys = E2EeHelper.GenerateRsaKeyPair();
|
||||
|
||||
existingKey = await _db.Create("server_encryption_keys", new ServerEncryptionKeys
|
||||
{
|
||||
KeyBase64 = keyBase64,
|
||||
PublicKey = serverKeys.publicKey,
|
||||
KeyBase64 = keyBase64,
|
||||
PublicKey = serverKeys.publicKey,
|
||||
PrivateKey = serverKeys.privateKey,
|
||||
CreatedAt = DateTime.UtcNow,
|
||||
UpdatedAt = DateTime.UtcNow
|
||||
CreatedAt = DateTime.UtcNow,
|
||||
UpdatedAt = DateTime.UtcNow
|
||||
});
|
||||
|
||||
Console.WriteLine("Server encryption key created.");
|
||||
@@ -104,92 +116,181 @@ public sealed class ServerBootstrapService
|
||||
ChatSocketBehavior.ChannelDbKey = existingKey.KeyBase64;
|
||||
}
|
||||
|
||||
private static string ToJsonString(object? obj)
|
||||
private async Task EnsureServerMemberAsync(string userId, bool isOwner)
|
||||
{
|
||||
return JsonSerializer.Serialize(obj, new JsonSerializerOptions
|
||||
var members = await _db.Select<ServerMembers>("server_members");
|
||||
var existing = members.FirstOrDefault(m => m.UserId == userId);
|
||||
|
||||
if (existing is not null)
|
||||
{
|
||||
WriteIndented = true,
|
||||
Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping
|
||||
if (existing.IsOwner != isOwner)
|
||||
{
|
||||
existing.IsOwner = isOwner;
|
||||
await _db.Merge<ServerMembers, ServerMembers>(existing);
|
||||
Console.WriteLine($"Member IsOwner updated: {userId} → {isOwner}");
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine($"Member already correct: {userId}");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
await _db.Create("server_members", new ServerMembers
|
||||
{
|
||||
UserId = userId,
|
||||
JoinedAt = DateTime.UtcNow,
|
||||
IsOwner = isOwner
|
||||
});
|
||||
Console.WriteLine($"Member created: {userId} (IsOwner={isOwner})");
|
||||
}
|
||||
|
||||
private static string GetRecordId(object? id)
|
||||
private async Task<Channels> EnsureChannelAsync(
|
||||
string name, ChannelType type, string group, bool isReadOnly, DateTime createdAt)
|
||||
{
|
||||
if (id is null)
|
||||
return string.Empty;
|
||||
var channels = await _db.Select<Channels>("channels");
|
||||
var existing = channels.FirstOrDefault(c => c.Name == name);
|
||||
|
||||
var json = JsonSerializer.Serialize(id);
|
||||
if (existing is not null)
|
||||
{
|
||||
bool dirty = existing.Type != type || existing.Group != group || existing.IsReadOnly != isReadOnly;
|
||||
if (dirty)
|
||||
{
|
||||
existing.Type = type;
|
||||
existing.Group = group;
|
||||
existing.IsReadOnly = isReadOnly;
|
||||
await _db.Merge<Channels, Channels>(existing);
|
||||
Console.WriteLine($"Channel updated: {name}");
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine($"Channel already correct: {name}");
|
||||
}
|
||||
return existing;
|
||||
}
|
||||
|
||||
using var doc = JsonDocument.Parse(json);
|
||||
var root = doc.RootElement;
|
||||
var channel = await _db.Create("channels", new Channels
|
||||
{
|
||||
Name = name,
|
||||
Type = type,
|
||||
Group = group,
|
||||
IsReadOnly = isReadOnly,
|
||||
CreatedAt = createdAt
|
||||
});
|
||||
|
||||
var recordId = root.GetProperty("Id").GetString() ?? string.Empty;
|
||||
var table = root.GetProperty("Table").GetString() ?? string.Empty;
|
||||
|
||||
return $"{table}:{recordId}";
|
||||
Console.WriteLine($"Channel created: {name} ({type})");
|
||||
return channel;
|
||||
}
|
||||
|
||||
|
||||
private async Task EnsureFileChannelLinkAsync(Channels channel, string fileChannelId)
|
||||
{
|
||||
if (channel.LinkedFileChannelId == fileChannelId)
|
||||
{
|
||||
Console.WriteLine($"File link already correct: {channel.Name} → {fileChannelId}");
|
||||
return;
|
||||
}
|
||||
|
||||
channel.LinkedFileChannelId = fileChannelId;
|
||||
await _db.Merge<Channels, Channels>(channel);
|
||||
Console.WriteLine($"File link set: {channel.Name} → {fileChannelId}");
|
||||
}
|
||||
|
||||
private async Task<Roles> EnsureRoleAsync(string name, PermissionFlags permissions, int priority)
|
||||
{
|
||||
var roles = await _db.Select<Roles>("roles");
|
||||
var existing = roles.FirstOrDefault(r => r.Name == name);
|
||||
|
||||
if (existing is not null)
|
||||
{
|
||||
Console.WriteLine($"Role already exists: {name}");
|
||||
return existing;
|
||||
}
|
||||
|
||||
var role = await _db.Create("roles", new Roles
|
||||
{
|
||||
Name = name,
|
||||
Permissions = permissions,
|
||||
Priority = priority,
|
||||
CreatedAt = DateTime.UtcNow
|
||||
});
|
||||
Console.WriteLine($"Role created: {name}");
|
||||
return role;
|
||||
}
|
||||
|
||||
private async Task SetUserRoleAsync(string userId, string roleId)
|
||||
{
|
||||
var userRoles = await _db.Select<UserRoles>("user_roles");
|
||||
var existing = userRoles
|
||||
.Where(ur => string.Equals(ur.UserId, userId, StringComparison.OrdinalIgnoreCase))
|
||||
.ToList();
|
||||
|
||||
bool alreadyCorrect = existing.Count == 1 && existing[0].RoleId == roleId;
|
||||
if (alreadyCorrect)
|
||||
{
|
||||
Console.WriteLine($"UserRole already correct: {userId} → {roleId}");
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var stale in existing)
|
||||
{
|
||||
if (stale.Id is not null)
|
||||
await _db.Delete(stale.Id);
|
||||
}
|
||||
|
||||
await _db.Create("user_roles", new UserRoles
|
||||
{
|
||||
UserId = userId,
|
||||
RoleId = roleId,
|
||||
AssignedAt = DateTime.UtcNow
|
||||
});
|
||||
Console.WriteLine($"UserRole set: {userId} → {roleId}");
|
||||
}
|
||||
|
||||
private async Task EnsureChannelPermissionAsync(
|
||||
string channelId, string roleId, PermissionFlags allow, PermissionFlags deny)
|
||||
{
|
||||
var perms = await _db.Select<ChannelPermissions>("channel_permissions");
|
||||
if (perms.Any(cp => cp.ChannelId == channelId && cp.RoleId == roleId))
|
||||
{
|
||||
Console.WriteLine($"ChannelPermission already exists: {channelId} → {roleId}");
|
||||
return;
|
||||
}
|
||||
|
||||
await _db.Create("channel_permissions", new ChannelPermissions
|
||||
{
|
||||
ChannelId = channelId,
|
||||
RoleId = roleId,
|
||||
Allow = allow,
|
||||
Deny = deny
|
||||
});
|
||||
Console.WriteLine($"ChannelPermission created: {channelId} → {roleId} | allow={allow}, deny={deny}");
|
||||
}
|
||||
|
||||
private async Task<Servers?> GetServerByNameAsync(string name)
|
||||
{
|
||||
var servers = await _db.Select<Servers>("servers");
|
||||
return servers.FirstOrDefault(x => x.Name == name);
|
||||
}
|
||||
|
||||
private async Task<ServerMembers?> GetServerMemberByUserIdAsync(string userId)
|
||||
{
|
||||
var members = await _db.Select<ServerMembers>("server_members");
|
||||
return members.FirstOrDefault(x => x.UserId == userId);
|
||||
}
|
||||
|
||||
private async Task<Channels?> GetChannelByNameAsync(string name)
|
||||
{
|
||||
var channels = await _db.Select<Channels>("channels");
|
||||
return channels.FirstOrDefault(x => x.Name == name);
|
||||
}
|
||||
|
||||
private async Task<ServerEncryptionKeys?> GetLatestServerEncryptionKeyAsync()
|
||||
{
|
||||
var keys = await _db.Select<ServerEncryptionKeys>("server_encryption_keys");
|
||||
return keys
|
||||
.OrderByDescending(x => x.CreatedAt)
|
||||
.FirstOrDefault();
|
||||
return keys.OrderByDescending(x => x.CreatedAt).FirstOrDefault();
|
||||
}
|
||||
|
||||
private async Task EnsureServerMemberAsync(string userId, bool isOwner)
|
||||
|
||||
private static string GetRecordId(object? id)
|
||||
{
|
||||
var existing = await GetServerMemberByUserIdAsync(userId);
|
||||
if (existing is not null)
|
||||
{
|
||||
Console.WriteLine($"Server member already exists for {userId}");
|
||||
return;
|
||||
}
|
||||
|
||||
await _db.Create("server_members", new ServerMembers
|
||||
{
|
||||
UserId = userId,
|
||||
JoinedAt = DateTime.UtcNow,
|
||||
IsOwner = isOwner
|
||||
});
|
||||
|
||||
Console.WriteLine($"Server member created for {userId}");
|
||||
if (id is null) return string.Empty;
|
||||
var json = JsonSerializer.Serialize(id);
|
||||
using var doc = JsonDocument.Parse(json);
|
||||
var root = doc.RootElement;
|
||||
return $"{root.GetProperty("Table").GetString()}:{root.GetProperty("Id").GetString()}";
|
||||
}
|
||||
|
||||
private async Task<Channels> EnsureChannelAsync(string name, DateTime createdAt)
|
||||
{
|
||||
var existing = await GetChannelByNameAsync(name);
|
||||
if (existing is not null)
|
||||
{
|
||||
Console.WriteLine($"Channel already exists: {name}");
|
||||
return existing;
|
||||
}
|
||||
|
||||
var channel = await _db.Create("channels", new Channels
|
||||
private static string ToJson(object? obj) =>
|
||||
JsonSerializer.Serialize(obj, new JsonSerializerOptions
|
||||
{
|
||||
Name = name,
|
||||
CreatedAt = createdAt
|
||||
WriteIndented = true,
|
||||
Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping
|
||||
});
|
||||
|
||||
Console.WriteLine($"Channel created: {ToJsonString(channel)}");
|
||||
return channel;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
160
RelayServer/Services/Data/PermissionService.cs
Normal file
160
RelayServer/Services/Data/PermissionService.cs
Normal file
@@ -0,0 +1,160 @@
|
||||
using RelayServer.Models;
|
||||
using SurrealDb.Net;
|
||||
|
||||
namespace RelayServer.Services.Data;
|
||||
|
||||
public sealed class PermissionService
|
||||
{
|
||||
private readonly SurrealDbClient _db;
|
||||
|
||||
public PermissionService(SurrealDbClient db)
|
||||
{
|
||||
_db = db;
|
||||
}
|
||||
|
||||
public async Task<bool> CanSendMessagesAsync(string username, string channelId)
|
||||
{
|
||||
if (await IsOwnerOrAdminAsync(username))
|
||||
return true;
|
||||
|
||||
if (await IsChannelReadOnlyAsync(channelId))
|
||||
return false;
|
||||
|
||||
return await HasPermissionAsync(username, channelId, PermissionFlags.SendMessages);
|
||||
}
|
||||
|
||||
public async Task<bool> CanManageChannelsAsync(string username) =>
|
||||
await IsOwnerOrAdminAsync(username) ||
|
||||
await HasGlobalPermissionAsync(username, PermissionFlags.ManageChannels);
|
||||
|
||||
public async Task<bool> CanManageMessagesAsync(string username, string channelId) =>
|
||||
await IsOwnerOrAdminAsync(username) ||
|
||||
await HasPermissionAsync(username, channelId, PermissionFlags.ManageMessages);
|
||||
|
||||
public async Task<bool> IsAdministratorAsync(string username) =>
|
||||
await IsOwnerOrAdminAsync(username);
|
||||
|
||||
public async Task<bool> CanViewChannelAsync(string username, string channelId)
|
||||
{
|
||||
if (await IsOwnerOrAdminAsync(username)) return true;
|
||||
return !await IsDeniedByChannelAsync(username, channelId, PermissionFlags.ViewChannel);
|
||||
}
|
||||
|
||||
public async Task<bool> CanSpeakAsync(string username, string channelId)
|
||||
{
|
||||
if (await IsOwnerOrAdminAsync(username)) return true;
|
||||
return !await IsDeniedByChannelAsync(username, channelId, PermissionFlags.Speak);
|
||||
}
|
||||
|
||||
public async Task<bool> CanDeleteChannelAsync(string username) =>
|
||||
await IsOwnerOrAdminAsync(username) ||
|
||||
await HasGlobalPermissionAsync(username, PermissionFlags.ManageChannels) ||
|
||||
await HasGlobalPermissionAsync(username, PermissionFlags.DeleteChannel);
|
||||
|
||||
public async Task<bool> CanEditChannelAsync(string username) =>
|
||||
await IsOwnerOrAdminAsync(username) ||
|
||||
await HasGlobalPermissionAsync(username, PermissionFlags.ManageChannels) ||
|
||||
await HasGlobalPermissionAsync(username, PermissionFlags.EditChannel);
|
||||
|
||||
private async Task<bool> IsOwnerOrAdminAsync(string username)
|
||||
{
|
||||
if (await IsServerOwnerAsync(username))
|
||||
return true;
|
||||
|
||||
var roles = await GetUserRolesAsync(username);
|
||||
return roles.Any(r => r.Permissions.HasFlag(PermissionFlags.Administrator));
|
||||
}
|
||||
|
||||
private async Task<bool> HasPermissionAsync(
|
||||
string username, string channelId, PermissionFlags flag)
|
||||
{
|
||||
if (await IsOwnerOrAdminAsync(username))
|
||||
return true;
|
||||
|
||||
var userRoles = await GetUserRolesAsync(username);
|
||||
if (userRoles.Count == 0) return false;
|
||||
|
||||
var channelOverrides = await GetChannelPermissionsAsync(channelId);
|
||||
var userRoleIds = new HashSet<string>(userRoles.Select(r => GetRecordIdString(r.Id)));
|
||||
|
||||
foreach (var co in channelOverrides.Where(co => userRoleIds.Contains(co.RoleId)))
|
||||
if (co.Deny.HasFlag(flag)) return false;
|
||||
|
||||
foreach (var co in channelOverrides.Where(co => userRoleIds.Contains(co.RoleId)))
|
||||
if (co.Allow.HasFlag(flag)) return true;
|
||||
|
||||
return userRoles.Any(r => r.Permissions.HasFlag(flag));
|
||||
}
|
||||
|
||||
private async Task<bool> HasGlobalPermissionAsync(string username, PermissionFlags flag)
|
||||
{
|
||||
var roles = await GetUserRolesAsync(username);
|
||||
return roles.Any(r =>
|
||||
r.Permissions.HasFlag(PermissionFlags.Administrator) ||
|
||||
r.Permissions.HasFlag(flag));
|
||||
}
|
||||
|
||||
private async Task<bool> IsDeniedByChannelAsync(string username, string channelId, PermissionFlags flag)
|
||||
{
|
||||
var userRoles = await GetUserRolesAsync(username);
|
||||
if (userRoles.Count == 0) return false;
|
||||
|
||||
var channelOverrides = await GetChannelPermissionsAsync(channelId);
|
||||
var userRoleIds = new HashSet<string>(userRoles.Select(r => GetRecordIdString(r.Id)));
|
||||
|
||||
return channelOverrides
|
||||
.Where(co => userRoleIds.Contains(co.RoleId))
|
||||
.Any(co => co.Deny.HasFlag(flag));
|
||||
}
|
||||
|
||||
private async Task<bool> IsServerOwnerAsync(string username)
|
||||
{
|
||||
var userId = $"users:{username.ToLower()}";
|
||||
var members = await _db.Select<ServerMembers>("server_members");
|
||||
return members.Any(m =>
|
||||
string.Equals(m.UserId, userId, StringComparison.OrdinalIgnoreCase) &&
|
||||
m.IsOwner);
|
||||
}
|
||||
|
||||
private async Task<List<Roles>> GetUserRolesAsync(string username)
|
||||
{
|
||||
var userId = $"users:{username.ToLower()}";
|
||||
|
||||
var userRoleLinks = await _db.Select<UserRoles>("user_roles");
|
||||
var userRoleIds = userRoleLinks
|
||||
.Where(ur => string.Equals(ur.UserId, userId, StringComparison.OrdinalIgnoreCase))
|
||||
.Select(ur => ur.RoleId)
|
||||
.ToHashSet();
|
||||
|
||||
if (userRoleIds.Count == 0) return [];
|
||||
|
||||
var allRoles = await _db.Select<Roles>("roles");
|
||||
return allRoles
|
||||
.Where(r => userRoleIds.Contains(GetRecordIdString(r.Id)))
|
||||
.ToList();
|
||||
}
|
||||
|
||||
private async Task<List<ChannelPermissions>> GetChannelPermissionsAsync(string channelId)
|
||||
{
|
||||
var all = await _db.Select<ChannelPermissions>("channel_permissions");
|
||||
return all.Where(cp => cp.ChannelId == channelId).ToList();
|
||||
}
|
||||
|
||||
private async Task<bool> IsChannelReadOnlyAsync(string channelId)
|
||||
{
|
||||
var channels = await _db.Select<Channels>("channels");
|
||||
var channel = channels.FirstOrDefault(c => GetRecordIdString(c.Id) == channelId);
|
||||
return channel?.IsReadOnly ?? false;
|
||||
}
|
||||
|
||||
private static string GetRecordIdString(object? id)
|
||||
{
|
||||
if (id is null) return string.Empty;
|
||||
var json = System.Text.Json.JsonSerializer.Serialize(id);
|
||||
using var doc = System.Text.Json.JsonDocument.Parse(json);
|
||||
var root = doc.RootElement;
|
||||
var recordId = root.GetProperty("Id").GetString() ?? string.Empty;
|
||||
var table = root.GetProperty("Table").GetString() ?? string.Empty;
|
||||
return $"{table}:{recordId}";
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user