Better notes and bans (#14228)

Co-authored-by: Chief-Engineer <119664036+Chief-Engineer@users.noreply.github.com>
This commit is contained in:
Riggle
2023-07-21 13:38:52 +02:00
committed by GitHub
parent c6cb6ad928
commit 579913b617
84 changed files with 9820 additions and 886 deletions

View File

@@ -5,7 +5,9 @@ using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using Content.Server.Administration.Logs;
using Content.Server.Administration.Managers;
using Content.Shared.Administration.Logs;
using Content.Shared.Database;
using Content.Shared.Humanoid;
using Content.Shared.Humanoid.Markings;
using Content.Shared.Preferences;
@@ -30,7 +32,8 @@ namespace Content.Server.Database
.AsSingleQuery()
.SingleOrDefaultAsync(p => p.UserId == userId.UserId);
if (prefs is null) return null;
if (prefs is null)
return null;
var maxSlot = prefs.Profiles.Max(p => p.Slot) + 1;
var profiles = new Dictionary<int, ICharacterProfile>(maxSlot);
@@ -339,6 +342,21 @@ namespace Content.Server.Database
public abstract Task AddServerBanAsync(ServerBanDef serverBan);
public abstract Task AddServerUnbanAsync(ServerUnbanDef serverUnban);
public async Task EditServerBan(int id, string reason, NoteSeverity severity, DateTime? expiration, Guid editedBy, DateTime editedAt)
{
await using var db = await GetDb();
var ban = await db.DbContext.Ban.SingleOrDefaultAsync(b => b.Id == id);
if (ban is null)
return;
ban.Severity = severity;
ban.Reason = reason;
ban.ExpirationTime = expiration;
ban.LastEditedById = editedBy;
ban.LastEditedAt = editedAt;
await db.DbContext.SaveChangesAsync();
}
protected static async Task<ServerBanExemptFlags?> GetBanExemptionCore(DbGuard db, NetUserId? userId)
{
if (userId == null)
@@ -415,6 +433,21 @@ namespace Content.Server.Database
public abstract Task AddServerRoleBanAsync(ServerRoleBanDef serverRoleBan);
public abstract Task AddServerRoleUnbanAsync(ServerRoleUnbanDef serverRoleUnban);
public async Task EditServerRoleBan(int id, string reason, NoteSeverity severity, DateTime? expiration, Guid editedBy, DateTime editedAt)
{
await using var db = await GetDb();
var ban = await db.DbContext.RoleBan.SingleOrDefaultAsync(b => b.Id == id);
if (ban is null)
return;
ban.Severity = severity;
ban.Reason = reason;
ban.ExpirationTime = expiration;
ban.LastEditedById = editedBy;
ban.LastEditedAt = editedAt;
await db.DbContext.SaveChangesAsync();
}
#endregion
#region Playtime
@@ -959,12 +992,29 @@ INSERT INTO player_round (players_id, rounds_id) VALUES ({players[player]}, {id}
return note.Id;
}
public virtual async Task<int> AddAdminWatchlist(AdminWatchlist watchlist)
{
await using var db = await GetDb();
db.DbContext.AdminWatchlists.Add(watchlist);
await db.DbContext.SaveChangesAsync();
return watchlist.Id;
}
public virtual async Task<int> AddAdminMessage(AdminMessage message)
{
await using var db = await GetDb();
db.DbContext.AdminMessages.Add(message);
await db.DbContext.SaveChangesAsync();
return message.Id;
}
public async Task<AdminNote?> GetAdminNote(int id)
{
await using var db = await GetDb();
return await db.DbContext.AdminNotes
.Where(note => note.Id == id)
.Include(note => note.Round)
.ThenInclude(r => r!.Server)
.Include(note => note.CreatedBy)
.Include(note => note.LastEditedBy)
.Include(note => note.DeletedBy)
@@ -972,17 +1022,145 @@ INSERT INTO player_round (players_id, rounds_id) VALUES ({players[player]}, {id}
.SingleOrDefaultAsync();
}
public async Task<List<AdminNote>> GetAdminNotes(Guid player)
public async Task<AdminWatchlist?> GetAdminWatchlist(int id)
{
await using var db = await GetDb();
return await db.DbContext.AdminNotes
.Where(note => note.PlayerUserId == player)
.Where(note => !note.Deleted)
return await db.DbContext.AdminWatchlists
.Where(note => note.Id == id)
.Include(note => note.Round)
.ThenInclude(r => r!.Server)
.Include(note => note.CreatedBy)
.Include(note => note.LastEditedBy)
.Include(note => note.DeletedBy)
.Include(note => note.Player)
.SingleOrDefaultAsync();
}
public async Task<AdminMessage?> GetAdminMessage(int id)
{
await using var db = await GetDb();
return await db.DbContext.AdminMessages
.Where(note => note.Id == id)
.Include(note => note.Round)
.ThenInclude(r => r!.Server)
.Include(note => note.CreatedBy)
.Include(note => note.LastEditedBy)
.Include(note => note.DeletedBy)
.Include(note => note.Player)
.SingleOrDefaultAsync();
}
public async Task<ServerBanNote?> GetServerBanAsNoteAsync(int id)
{
await using var db = await GetDb();
var ban = await db.DbContext.Ban
.Include(ban => ban.Unban)
.Include(ban => ban.Round)
.ThenInclude(r => r!.Server)
.Include(ban => ban.CreatedBy)
.Include(ban => ban.LastEditedBy)
.Include(ban => ban.Unban)
.SingleOrDefaultAsync(b => b.Id == id);
if (ban is null)
return null;
var player = await db.DbContext.Player.SingleOrDefaultAsync(p => p.UserId == ban.PlayerUserId);
return new ServerBanNote(ban.Id, ban.RoundId, ban.Round, ban.PlayerUserId, player,
ban.PlaytimeAtNote, ban.Reason, ban.Severity, ban.CreatedBy, ban.BanTime,
ban.LastEditedBy, ban.LastEditedAt, ban.ExpirationTime, ban.Hidden,
ban.Unban?.UnbanningAdmin == null
? null
: await db.DbContext.Player.SingleOrDefaultAsync(p =>
p.UserId == ban.Unban.UnbanningAdmin.Value),
ban.Unban?.UnbanTime);
}
public async Task<ServerRoleBanNote?> GetServerRoleBanAsNoteAsync(int id)
{
await using var db = await GetDb();
var ban = await db.DbContext.RoleBan
.Include(b => b.Unban)
.SingleOrDefaultAsync(b => b.Id == id);
if (ban is null)
return null;
var player = await db.DbContext.Player.SingleOrDefaultAsync(p => p.UserId == ban.PlayerUserId);
var unbanningAdmin =
ban.Unban is null
? null
: await db.DbContext.Player.SingleOrDefaultAsync(b => b.UserId == ban.Unban.UnbanningAdmin);
return new ServerRoleBanNote(ban.Id, ban.RoundId, ban.Round, ban.PlayerUserId,
player, ban.PlaytimeAtNote, ban.Reason, ban.Severity, ban.CreatedBy,
ban.BanTime, ban.LastEditedBy, ban.LastEditedAt, ban.ExpirationTime,
ban.Hidden, new [] { ban.RoleId.Replace(BanManager.JobPrefix, null) },
unbanningAdmin, ban.Unban?.UnbanTime);
}
public async Task<List<IAdminRemarksCommon>> GetAllAdminRemarks(Guid player)
{
await using var db = await GetDb();
List<IAdminRemarksCommon> notes = new();
notes.AddRange(
await (from note in db.DbContext.AdminNotes
where note.PlayerUserId == player &&
!note.Deleted &&
(note.ExpirationTime == null || DateTime.UtcNow < note.ExpirationTime)
select note)
.Include(note => note.Round)
.ThenInclude(r => r!.Server)
.Include(note => note.CreatedBy)
.Include(note => note.LastEditedBy)
.Include(note => note.Player)
.ToListAsync();
.ToListAsync());
notes.AddRange(await GetActiveWatchlistsImpl(db, player));
notes.AddRange(await GetMessagesImpl(db, player));
notes.AddRange(await GetServerBansAsNotesForUser(db, player));
notes.AddRange(await GetGroupedServerRoleBansAsNotesForUser(db, player));
return notes;
}
public async Task EditAdminNote(int id, string message, NoteSeverity severity, bool secret, Guid editedBy, DateTime editedAt, DateTime? expiryTime)
{
await using var db = await GetDb();
var note = await db.DbContext.AdminNotes.Where(note => note.Id == id).SingleAsync();
note.Message = message;
note.Severity = severity;
note.Secret = secret;
note.LastEditedById = editedBy;
note.LastEditedAt = editedAt;
note.ExpirationTime = expiryTime;
await db.DbContext.SaveChangesAsync();
}
public async Task EditAdminWatchlist(int id, string message, Guid editedBy, DateTime editedAt, DateTime? expiryTime)
{
await using var db = await GetDb();
var note = await db.DbContext.AdminWatchlists.Where(note => note.Id == id).SingleAsync();
note.Message = message;
note.LastEditedById = editedBy;
note.LastEditedAt = editedAt;
note.ExpirationTime = expiryTime;
await db.DbContext.SaveChangesAsync();
}
public async Task EditAdminMessage(int id, string message, Guid editedBy, DateTime editedAt, DateTime? expiryTime)
{
await using var db = await GetDb();
var note = await db.DbContext.AdminMessages.Where(note => note.Id == id).SingleAsync();
note.Message = message;
note.LastEditedById = editedBy;
note.LastEditedAt = editedAt;
note.ExpirationTime = expiryTime;
await db.DbContext.SaveChangesAsync();
}
public async Task DeleteAdminNote(int id, Guid deletedBy, DateTime deletedAt)
@@ -998,18 +1176,204 @@ INSERT INTO player_round (players_id, rounds_id) VALUES ({players[player]}, {id}
await db.DbContext.SaveChangesAsync();
}
public async Task EditAdminNote(int id, string message, Guid editedBy, DateTime editedAt)
public async Task DeleteAdminWatchlist(int id, Guid deletedBy, DateTime deletedAt)
{
await using var db = await GetDb();
var note = await db.DbContext.AdminNotes.Where(note => note.Id == id).SingleAsync();
note.Message = message;
note.LastEditedById = editedBy;
note.LastEditedAt = editedAt;
var watchlist = await db.DbContext.AdminWatchlists.Where(note => note.Id == id).SingleAsync();
watchlist.Deleted = true;
watchlist.DeletedById = deletedBy;
watchlist.DeletedAt = deletedAt;
await db.DbContext.SaveChangesAsync();
}
public async Task DeleteAdminMessage(int id, Guid deletedBy, DateTime deletedAt)
{
await using var db = await GetDb();
var message = await db.DbContext.AdminMessages.Where(note => note.Id == id).SingleAsync();
message.Deleted = true;
message.DeletedById = deletedBy;
message.DeletedAt = deletedAt;
await db.DbContext.SaveChangesAsync();
}
public async Task HideServerBanFromNotes(int id, Guid deletedBy, DateTime deletedAt)
{
await using var db = await GetDb();
var ban = await db.DbContext.Ban.Where(ban => ban.Id == id).SingleAsync();
ban.Hidden = true;
ban.LastEditedById = deletedBy;
ban.LastEditedAt = deletedAt;
await db.DbContext.SaveChangesAsync();
}
public async Task HideServerRoleBanFromNotes(int id, Guid deletedBy, DateTime deletedAt)
{
await using var db = await GetDb();
var roleBan = await db.DbContext.RoleBan.Where(roleBan => roleBan.Id == id).SingleAsync();
roleBan.Hidden = true;
roleBan.LastEditedById = deletedBy;
roleBan.LastEditedAt = deletedAt;
await db.DbContext.SaveChangesAsync();
}
public async Task<List<IAdminRemarksCommon>> GetVisibleAdminRemarks(Guid player)
{
await using var db = await GetDb();
List<IAdminRemarksCommon> notesCol = new();
notesCol.AddRange(
await (from note in db.DbContext.AdminNotes
where note.PlayerUserId == player &&
!note.Secret &&
!note.Deleted &&
(note.ExpirationTime == null || DateTime.UtcNow < note.ExpirationTime)
select note)
.Include(note => note.Round)
.ThenInclude(r => r!.Server)
.Include(note => note.CreatedBy)
.Include(note => note.Player)
.ToListAsync());
notesCol.AddRange(await GetMessagesImpl(db, player));
return notesCol;
}
public async Task<List<AdminWatchlist>> GetActiveWatchlists(Guid player)
{
await using var db = await GetDb();
return await GetActiveWatchlistsImpl(db, player);
}
protected async Task<List<AdminWatchlist>> GetActiveWatchlistsImpl(DbGuard db, Guid player)
{
return await (from watchlist in db.DbContext.AdminWatchlists
where watchlist.PlayerUserId == player &&
!watchlist.Deleted &&
(watchlist.ExpirationTime == null || DateTime.UtcNow < watchlist.ExpirationTime)
select watchlist)
.Include(note => note.Round)
.ThenInclude(r => r!.Server)
.Include(note => note.CreatedBy)
.Include(note => note.LastEditedBy)
.Include(note => note.Player)
.ToListAsync();
}
public async Task<List<AdminMessage>> GetMessages(Guid player)
{
await using var db = await GetDb();
return await GetMessagesImpl(db, player);
}
protected async Task<List<AdminMessage>> GetMessagesImpl(DbGuard db, Guid player)
{
return await (from message in db.DbContext.AdminMessages
where message.PlayerUserId == player &&
!message.Deleted &&
(message.ExpirationTime == null || DateTime.UtcNow < message.ExpirationTime)
select message)
.Include(note => note.Round)
.ThenInclude(r => r!.Server)
.Include(note => note.CreatedBy)
.Include(note => note.LastEditedBy)
.Include(note => note.Player)
.ToListAsync();
}
public async Task MarkMessageAsSeen(int id)
{
await using var db = await GetDb();
var message = await db.DbContext.AdminMessages.SingleAsync(m => m.Id == id);
message.Seen = true;
await db.DbContext.SaveChangesAsync();
}
// These two are here because they get converted into notes later
protected async Task<List<ServerBanNote>> GetServerBansAsNotesForUser(DbGuard db, Guid user)
{
// You can't group queries, as player will not always exist. When it doesn't, the
// whole query returns nothing
var player = await db.DbContext.Player.SingleOrDefaultAsync(p => p.UserId == user);
return await (from ban in db.DbContext.Ban
where ban.PlayerUserId == user &&
!ban.Hidden
select ban)
.Include(ban => ban.Unban)
.Include(ban => ban.Round)
.ThenInclude(r => r!.Server)
.Include(ban => ban.CreatedBy)
.Include(ban => ban.LastEditedBy)
.Include(ban => ban.Unban)
.ToAsyncEnumerable()
.SelectAwait(async ban =>
new ServerBanNote(ban.Id, ban.RoundId, ban.Round, ban.PlayerUserId, player,
ban.PlaytimeAtNote, ban.Reason, ban.Severity, ban.CreatedBy, ban.BanTime,
ban.LastEditedBy, ban.LastEditedAt, ban.ExpirationTime, ban.Hidden,
ban.Unban?.UnbanningAdmin == null
? null
: await db.DbContext.Player.SingleOrDefaultAsync(p => p.UserId == ban.Unban.UnbanningAdmin.Value),
ban.Unban?.UnbanTime)
).ToListAsync();
}
protected async Task<List<ServerRoleBanNote>> GetGroupedServerRoleBansAsNotesForUser(DbGuard db, Guid user)
{
// Server side query
var bansQuery =
(from ban in db.DbContext.RoleBan
where ban.PlayerUserId == user &&
!ban.Hidden
select ban)
.Include(ban => ban.Unban)
.Include(ban => ban.Round)
.ThenInclude(r => r!.Server)
.Include(ban => ban.CreatedBy)
.Include(ban => ban.LastEditedBy)
.Include(ban => ban.Unban)
.ToAsyncEnumerable();
// Client side query, as EF can't do groups yet
var bansEnumerable =
(from ban in bansQuery
group ban by new
{
ban.BanTime,
ban.CreatedBy,
ban.Reason,
Unbanned = ban.Unban == null
}
into banGroup
select banGroup)
.AsAsyncEnumerable();
List<ServerRoleBanNote> bans = new();
var player = await db.DbContext.Player.SingleOrDefaultAsync(p => p.UserId == user);
await foreach (var banGroup in bansEnumerable)
{
var firstBan = await banGroup.FirstAsync();
Player? unbanningAdmin = null;
if (firstBan.Unban?.UnbanningAdmin is not null)
unbanningAdmin = await db.DbContext.Player.SingleOrDefaultAsync(p => p.UserId == firstBan.Unban.UnbanningAdmin.Value);
bans.Add(new ServerRoleBanNote(firstBan.Id, firstBan.RoundId, firstBan.Round, firstBan.PlayerUserId,
player, firstBan.PlaytimeAtNote, firstBan.Reason, firstBan.Severity, firstBan.CreatedBy,
firstBan.BanTime, firstBan.LastEditedBy, firstBan.LastEditedAt, firstBan.ExpirationTime,
firstBan.Hidden, await banGroup.Select(ban => ban.RoleId.Replace(BanManager.JobPrefix, null)).ToArrayAsync(),
unbanningAdmin, firstBan.Unban?.UnbanTime));
}
return bans;
}
#endregion
protected abstract Task<DbGuard> GetDb();