Files
server/MareSynchronosServer/MareSynchronosServer/Hubs/MareHub.Functions.cs
rootdarkarchon ca16b08a2f Server rework for API change and paradigm shift (#23)
* start with group permissions implementation

* some minor refactoring

* adjust hub for api changes

* fixes and database migration

* fixes sending online/offline message to clients stuff

* remove admin stuff from server

* fixes get server permissions

* send group pair info to client on joining a group

* send online only on sending connection dto

---------

Co-authored-by: rootdarkarchon <root.darkarchon@outlook.com>
2023-01-29 15:15:02 +01:00

165 lines
7.9 KiB
C#

using MareSynchronosShared.Models;
using Microsoft.EntityFrameworkCore;
using MareSynchronosServer.Utils;
using MareSynchronosShared.Utils;
using Microsoft.IdentityModel.Tokens;
namespace MareSynchronosServer.Hubs;
public partial class MareHub
{
private async Task UpdateUserOnRedis()
{
await _redis.AddAsync("UID:" + UserUID, UserCharaIdent, TimeSpan.FromSeconds(60), StackExchange.Redis.When.Always, StackExchange.Redis.CommandFlags.FireAndForget).ConfigureAwait(false);
}
private async Task RemoveUserFromRedis()
{
await _redis.RemoveAsync("UID:" + UserUID, StackExchange.Redis.CommandFlags.FireAndForget).ConfigureAwait(false);
}
private async Task<string> GetUserIdent(string uid)
{
if (uid.IsNullOrEmpty()) return string.Empty;
return await _redis.GetAsync<string>("UID:" + uid).ConfigureAwait(false);
}
private async Task<Dictionary<string, string>> GetOnlineUsers(List<string> uids)
{
var result = await _redis.GetAllAsync<string>(uids.Select(u => "UID:" + u).ToArray()).ConfigureAwait(false);
return uids.Where(u => result.TryGetValue("UID:" + u, out var ident) && !string.IsNullOrEmpty(ident)).ToDictionary(u => u, u => result["UID:" + u], StringComparer.Ordinal);
}
private async Task<List<PausedEntry>> GetAllPairedClientsWithPauseState(string? uid = null)
{
uid ??= UserUID;
var query = await (from userPair in _dbContext.ClientPairs
join otherUserPair in _dbContext.ClientPairs on userPair.OtherUserUID equals otherUserPair.UserUID
where otherUserPair.OtherUserUID == uid && userPair.UserUID == uid
select new
{
UID = Convert.ToString(userPair.OtherUserUID),
GID = "DIRECT",
PauseStateSelf = userPair.IsPaused,
PauseStateOther = otherUserPair.IsPaused,
})
.Union(
(from userGroupPair in _dbContext.GroupPairs
join otherGroupPair in _dbContext.GroupPairs on userGroupPair.GroupGID equals otherGroupPair.GroupGID
where
userGroupPair.GroupUserUID == uid
&& otherGroupPair.GroupUserUID != uid
select new
{
UID = Convert.ToString(otherGroupPair.GroupUserUID),
GID = Convert.ToString(otherGroupPair.GroupGID),
PauseStateSelf = userGroupPair.IsPaused,
PauseStateOther = otherGroupPair.IsPaused,
})
).AsNoTracking().ToListAsync().ConfigureAwait(false);
return query.GroupBy(g => g.UID, g => (g.GID, g.PauseStateSelf, g.PauseStateOther),
(key, g) => new PausedEntry
{
UID = key,
PauseStates = g.Select(p => new PauseState() { GID = string.Equals(p.GID, "DIRECT", StringComparison.Ordinal) ? null : p.GID, IsSelfPaused = p.PauseStateSelf, IsOtherPaused = p.PauseStateOther })
.ToList(),
}, StringComparer.Ordinal).ToList();
}
private async Task<List<string>> GetAllPairedUnpausedUsers(string? uid = null)
{
uid ??= UserUID;
var ret = await GetAllPairedClientsWithPauseState(uid).ConfigureAwait(false);
return ret.Where(k => !k.IsPaused).Select(k => k.UID).ToList();
}
private async Task<List<string>> SendOnlineToAllPairedUsers()
{
var usersToSendDataTo = await GetAllPairedUnpausedUsers().ConfigureAwait(false);
var self = await _dbContext.Users.AsNoTracking().SingleAsync(u => u.UID == UserUID).ConfigureAwait(false);
await Clients.Users(usersToSendDataTo).Client_UserSendOnline(new(self.ToUserData(), UserCharaIdent)).ConfigureAwait(false);
return usersToSendDataTo;
}
private async Task<List<string>> SendOfflineToAllPairedUsers()
{
var usersToSendDataTo = await GetAllPairedUnpausedUsers().ConfigureAwait(false);
var self = await _dbContext.Users.AsNoTracking().SingleAsync(u => u.UID == UserUID).ConfigureAwait(false);
await Clients.Users(usersToSendDataTo).Client_UserSendOffline(new(self.ToUserData())).ConfigureAwait(false);
return usersToSendDataTo;
}
public string UserUID => Context.User?.Claims?.SingleOrDefault(c => string.Equals(c.Type, MareClaimTypes.Uid, StringComparison.Ordinal))?.Value ?? throw new Exception("No UID in Claims");
public string UserCharaIdent => Context.User?.Claims?.SingleOrDefault(c => string.Equals(c.Type, MareClaimTypes.CharaIdent, StringComparison.Ordinal))?.Value ?? throw new Exception("No Chara Ident in Claims");
private async Task UserGroupLeave(GroupPair groupUserPair, List<PausedEntry> allUserPairs, string userIdent, string? uid = null)
{
uid ??= UserUID;
var userPair = allUserPairs.SingleOrDefault(p => string.Equals(p.UID, groupUserPair.GroupUserUID, StringComparison.Ordinal));
if (userPair != null)
{
if (userPair.IsDirectlyPaused != PauseInfo.NoConnection) return;
if (userPair.IsPausedPerGroup is PauseInfo.Unpaused) return;
}
var groupUserIdent = await GetUserIdent(groupUserPair.GroupUserUID).ConfigureAwait(false);
if (!string.IsNullOrEmpty(groupUserIdent))
{
await Clients.User(uid).Client_UserSendOffline(new(new(groupUserPair.GroupUserUID))).ConfigureAwait(false);
await Clients.User(groupUserPair.GroupUserUID).Client_UserSendOffline(new(new(uid))).ConfigureAwait(false);
}
}
private async Task SendGroupDeletedToAll(List<GroupPair> groupUsers)
{
foreach (var pair in groupUsers)
{
var pairIdent = await GetUserIdent(pair.GroupUserUID).ConfigureAwait(false);
if (string.IsNullOrEmpty(pairIdent)) continue;
var pairs = await GetAllPairedClientsWithPauseState(pair.GroupUserUID).ConfigureAwait(false);
foreach (var groupUserPair in groupUsers.Where(g => !string.Equals(g.GroupUserUID, pair.GroupUserUID, StringComparison.Ordinal)))
{
await UserGroupLeave(groupUserPair, pairs, pairIdent, pair.GroupUserUID).ConfigureAwait(false);
}
}
}
private async Task<(bool IsValid, GroupPair ReferredPair)> TryValidateUserInGroup(string gid, string? uid = null)
{
uid ??= UserUID;
var groupPair = await _dbContext.GroupPairs.Include(c => c.GroupUser)
.SingleOrDefaultAsync(g => g.GroupGID == gid && (g.GroupUserUID == uid || g.GroupUser.Alias == uid)).ConfigureAwait(false);
if (groupPair == null) return (false, null);
return (true, groupPair);
}
private async Task<(bool IsValid, Group ReferredGroup)> TryValidateGroupModeratorOrOwner(string gid)
{
var isOwnerResult = await TryValidateOwner(gid).ConfigureAwait(false);
if (isOwnerResult.isValid) return (true, isOwnerResult.ReferredGroup);
if (isOwnerResult.ReferredGroup == null) return (false, null);
var groupPairSelf = await _dbContext.GroupPairs.SingleOrDefaultAsync(g => g.GroupGID == gid && g.GroupUserUID == UserUID).ConfigureAwait(false);
if (groupPairSelf == null || !groupPairSelf.IsModerator) return (false, null);
return (true, isOwnerResult.ReferredGroup);
}
private async Task<(bool isValid, Group ReferredGroup)> TryValidateOwner(string gid)
{
var group = await _dbContext.Groups.SingleOrDefaultAsync(g => g.GID == gid).ConfigureAwait(false);
if (group == null) return (false, null);
return (string.Equals(group.OwnerUID, UserUID, StringComparison.Ordinal), group);
}
}