Compare commits

..

3 Commits

Author SHA1 Message Date
cake
f6cc919e2d Resolve alias if used 2026-01-04 05:15:06 +01:00
cake
3a6adc520a Check if UID even exist in lightless 2026-01-04 05:11:51 +01:00
cake
6a8a2e22a8 Changed group ban so it works differently. 2026-01-04 05:07:20 +01:00
3 changed files with 157 additions and 150 deletions

View File

@@ -28,25 +28,72 @@ public partial class LightlessHub
var (userHasRights, group) = await TryValidateGroupModeratorOrOwner(dto.Group.GID).ConfigureAwait(false); var (userHasRights, group) = await TryValidateGroupModeratorOrOwner(dto.Group.GID).ConfigureAwait(false);
if (!userHasRights) return; if (!userHasRights) return;
var (userExists, groupPair) = await TryValidateUserInGroup(dto.Group.GID, dto.User.UID).ConfigureAwait(false); var targetUid = dto.User.UID?.Trim();
if (!userExists) return; if (string.IsNullOrWhiteSpace(targetUid)) return;
if (groupPair.IsModerator || string.Equals(group.OwnerUID, dto.User.UID, StringComparison.Ordinal)) return; if (string.Equals(group.OwnerUID, targetUid, StringComparison.Ordinal))
return;
var alias = string.IsNullOrEmpty(groupPair.GroupUser.Alias) ? "-" : groupPair.GroupUser.Alias; var groupPair = await DbContext.GroupPairs
var ban = new GroupBan() .Include(p => p.GroupUser)
.SingleOrDefaultAsync(p => p.GroupGID == dto.Group.GID && p.GroupUserUID == targetUid, cancellationToken: RequestAbortedToken).ConfigureAwait(false);
if (groupPair?.IsModerator == true)
return;
var now = DateTime.UtcNow;
var existingBan = await DbContext.Set<GroupBan>().SingleOrDefaultAsync(b => b.GroupGID == dto.Group.GID && b.BannedUserUID == targetUid, cancellationToken: RequestAbortedToken).ConfigureAwait(false);
var userExists = await DbContext.Users.AsNoTracking().AnyAsync(u => u.UID == targetUid || u.Alias == targetUid, RequestAbortedToken).ConfigureAwait(false);
if (!userExists && existingBan == null)
return;
const string marker = " (Alias at time of ban:";
string suffix;
if (existingBan?.BannedReason is { } existingReason)
{
var idx = existingReason.IndexOf(marker, StringComparison.Ordinal);
suffix = idx >= 0 ? existingReason.Substring(startIndex: idx) : string.Empty;
}
else
{
var alias = groupPair?.GroupUser?.Alias;
alias = string.IsNullOrWhiteSpace(alias) ? "-" : alias;
suffix = $" (Alias at time of ban: {alias})";
}
var baseReason = (reason ?? string.Empty).Trim();
var finalReason = string.IsNullOrEmpty(suffix) ? baseReason : (baseReason + suffix);
if (existingBan != null)
{
existingBan.BannedByUID = UserUID;
existingBan.BannedReason = finalReason;
DbContext.Update(existingBan);
}
else
{
var ban = new GroupBan
{ {
BannedByUID = UserUID, BannedByUID = UserUID,
BannedReason = $"{reason} (Alias at time of ban: {alias})", BannedReason = finalReason,
BannedOn = DateTime.UtcNow, BannedOn = now,
BannedUserUID = dto.User.UID, BannedUserUID = targetUid,
GroupGID = dto.Group.GID, GroupGID = dto.Group.GID,
}; };
DbContext.Add(ban); DbContext.Add(ban);
await DbContext.SaveChangesAsync().ConfigureAwait(false); }
await DbContext.SaveChangesAsync(RequestAbortedToken).ConfigureAwait(false);
if (groupPair != null)
{
await GroupRemoveUser(dto).ConfigureAwait(false); await GroupRemoveUser(dto).ConfigureAwait(false);
}
_logger.LogCallInfo(LightlessHubLogger.Args(dto, "Success")); _logger.LogCallInfo(LightlessHubLogger.Args(dto, "Success"));
} }
@@ -400,9 +447,9 @@ public partial class LightlessHub
var banEntries = await DbContext.GroupBans.Include(b => b.BannedUser).Where(g => g.GroupGID == dto.Group.GID).AsNoTracking().ToListAsync(cancellationToken: RequestAbortedToken).ConfigureAwait(false); var banEntries = await DbContext.GroupBans.Include(b => b.BannedUser).Where(g => g.GroupGID == dto.Group.GID).AsNoTracking().ToListAsync(cancellationToken: RequestAbortedToken).ConfigureAwait(false);
List<BannedGroupUserDto> bannedGroupUsers = banEntries.Select(b => List<BannedGroupUserDto> bannedGroupUsers = [.. banEntries.Select(b =>
new BannedGroupUserDto(group.ToGroupData(), b.BannedUser.ToUserData(), b.BannedReason, b.BannedOn, new BannedGroupUserDto(group.ToGroupData(), b.BannedUser.ToUserData(), b.BannedReason, b.BannedOn,
b.BannedByUID)).ToList(); b.BannedByUID))];
_logger.LogCallInfo(LightlessHubLogger.Args(dto, bannedGroupUsers.Count)); _logger.LogCallInfo(LightlessHubLogger.Args(dto, bannedGroupUsers.Count));

View File

@@ -2,19 +2,15 @@
using LightlessSyncShared.Data; using LightlessSyncShared.Data;
using LightlessSyncShared.Models; using LightlessSyncShared.Models;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using StackExchange.Redis.Extensions.Core.Abstractions;
namespace LightlessSyncServer.Services namespace LightlessSyncServer.Services
{ {
public class PruneService(LightlessDbContext dbContext, IRedisDatabase redis) : IPruneService public class PruneService(LightlessDbContext dbContext) : IPruneService
{ {
private readonly LightlessDbContext _dbContext = dbContext; private readonly LightlessDbContext _dbContext = dbContext;
private readonly IRedisDatabase _redis = redis;
public async Task<int> CountPrunableUsersAsync(string groupGid, int days, CancellationToken ct) public async Task<int> CountPrunableUsersAsync(string groupGid, int days, CancellationToken ct)
{ {
var onlineUids = await GetOnlineUidsAsync().ConfigureAwait(false);
var allGroupUsers = await _dbContext.GroupPairs var allGroupUsers = await _dbContext.GroupPairs
.Include(p => p.GroupUser) .Include(p => p.GroupUser)
.Include(p => p.Group) .Include(p => p.Group)
@@ -24,14 +20,17 @@ namespace LightlessSyncServer.Services
var inactivitySpan = GetInactivitySpan(days); var inactivitySpan = GetInactivitySpan(days);
var now = DateTime.UtcNow; var now = DateTime.UtcNow;
var usersToPrune = GetPruneUserList(allGroupUsers, onlineUids, inactivitySpan, now); var usersToPrune = allGroupUsers.Where(p =>
return usersToPrune.Count; !p.IsPinned &&
!p.IsModerator &&
!string.Equals(p.Group.OwnerUID, p.GroupUserUID, StringComparison.Ordinal) &&
p.GroupUser.LastLoggedIn < now - inactivitySpan);
return usersToPrune.Count();
} }
public async Task<IReadOnlyList<GroupPair>> ExecutePruneAsync(string groupGid, int days, CancellationToken ct) public async Task<IReadOnlyList<GroupPair>> ExecutePruneAsync(string groupGid, int days, CancellationToken ct)
{ {
var onlineUids = await GetOnlineUidsAsync().ConfigureAwait(false);
var allGroupUsers = await _dbContext.GroupPairs var allGroupUsers = await _dbContext.GroupPairs
.Include(p => p.GroupUser) .Include(p => p.GroupUser)
.Include(p => p.Group) .Include(p => p.Group)
@@ -41,7 +40,12 @@ namespace LightlessSyncServer.Services
var inactivitySpan = GetInactivitySpan(days); var inactivitySpan = GetInactivitySpan(days);
var now = DateTime.UtcNow; var now = DateTime.UtcNow;
var usersToPrune = GetPruneUserList(allGroupUsers, onlineUids, inactivitySpan, now); var usersToPrune = allGroupUsers.Where(p =>
!p.IsPinned &&
!p.IsModerator &&
!string.Equals(p.Group.OwnerUID, p.GroupUserUID, StringComparison.Ordinal) &&
p.GroupUser.LastLoggedIn < now - inactivitySpan)
.ToList();
_dbContext.GroupPairs.RemoveRange(usersToPrune); _dbContext.GroupPairs.RemoveRange(usersToPrune);
await _dbContext.SaveChangesAsync(ct).ConfigureAwait(false); await _dbContext.SaveChangesAsync(ct).ConfigureAwait(false);
@@ -49,52 +53,8 @@ namespace LightlessSyncServer.Services
return usersToPrune; return usersToPrune;
} }
private static List<GroupPair> GetPruneUserList( private static TimeSpan GetInactivitySpan(int days) => days == 0
List<GroupPair> allGroupUsers, ? TimeSpan.FromMinutes(15)
HashSet<string> onlineUids, : TimeSpan.FromDays(days);
TimeSpan inactivitySpan,
DateTime now)
{
return
[
.. allGroupUsers.Where(p =>
!p.IsPinned &&
!p.IsModerator &&
!string.Equals(p.Group.OwnerUID, p.GroupUserUID, StringComparison.Ordinal) &&
!onlineUids.Contains(p.GroupUserUID) &&
p.GroupUser.LastLoggedIn < now - inactivitySpan),
];
}
private async Task<HashSet<string>> GetOnlineUidsAsync()
{
var keys = await _redis.SearchKeysAsync("UID:*").ConfigureAwait(false);
var set = new HashSet<string>(StringComparer.Ordinal);
foreach (var k in keys)
{
if (string.IsNullOrEmpty(k)) continue;
const string prefix = "UID:";
if (k.StartsWith(prefix, StringComparison.Ordinal))
{
var uid = k.Substring(prefix.Length);
if (!string.IsNullOrEmpty(uid))
set.Add(uid);
}
else
{
var idx = k.IndexOf(':', StringComparison.Ordinal);
if (idx >= 0 && idx < k.Length - 1)
set.Add(k[(idx + 1)..]);
}
}
return set;
}
private static TimeSpan GetInactivitySpan(int days) =>
days == 0 ? TimeSpan.FromHours(2) : TimeSpan.FromDays(days);
} }
} }

View File

@@ -24,7 +24,7 @@ namespace LightlessSyncServer.Worker
var hubContext = scope.ServiceProvider.GetRequiredService<IHubContext<LightlessHub>>(); var hubContext = scope.ServiceProvider.GetRequiredService<IHubContext<LightlessHub>>();
var groups = await db.Groups var groups = await db.Groups
.Where(g => g.AutoPruneEnabled) .Where(g => g.AutoPruneEnabled && g.AutoPruneDays > 0)
.ToListAsync(stoppingToken).ConfigureAwait(false); .ToListAsync(stoppingToken).ConfigureAwait(false);
foreach (var group in groups) foreach (var group in groups)