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

@@ -1,6 +1,7 @@
using System.Collections.Immutable;
using System.Collections.Immutable;
using System.Net;
using Content.Shared.CCVar;
using Content.Shared.Database;
using Robust.Shared.Configuration;
using Robust.Shared.Network;
@@ -16,7 +17,10 @@ namespace Content.Server.Database
public DateTimeOffset BanTime { get; }
public DateTimeOffset? ExpirationTime { get; }
public int? RoundId { get; }
public TimeSpan PlaytimeAtNote { get; }
public string Reason { get; }
public NoteSeverity Severity { get; set; }
public NetUserId? BanningAdmin { get; }
public ServerUnbanDef? Unban { get; }
@@ -27,7 +31,10 @@ namespace Content.Server.Database
ImmutableArray<byte>? hwId,
DateTimeOffset banTime,
DateTimeOffset? expirationTime,
int? roundId,
TimeSpan playtimeAtNote,
string reason,
NoteSeverity severity,
NetUserId? banningAdmin,
ServerUnbanDef? unban)
{
@@ -49,7 +56,10 @@ namespace Content.Server.Database
HWId = hwId;
BanTime = banTime;
ExpirationTime = expirationTime;
RoundId = roundId;
PlaytimeAtNote = playtimeAtNote;
Reason = reason;
Severity = severity;
BanningAdmin = banningAdmin;
Unban = unban;
}
@@ -66,10 +76,9 @@ namespace Content.Server.Database
else
{
var appeal = cfg.GetCVar(CCVars.InfoLinksAppeal);
if (!string.IsNullOrWhiteSpace(appeal))
expires = loc.GetString("ban-banned-permanent-appeal", ("link", appeal));
else
expires = loc.GetString("ban-banned-permanent");
expires = !string.IsNullOrWhiteSpace(appeal)
? loc.GetString("ban-banned-permanent-appeal", ("link", appeal))
: loc.GetString("ban-banned-permanent");
}
return $"""

View File

@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Content.Shared.Database;
namespace Content.Server.Database
{
public record ServerBanNote(int Id, int? RoundId, Round? Round, Guid? PlayerUserId, Player? Player,
TimeSpan PlaytimeAtNote, string Message, NoteSeverity Severity, Player? CreatedBy, DateTime CreatedAt,
Player? LastEditedBy, DateTime? LastEditedAt, DateTime? ExpirationTime, bool Deleted, Player? UnbanningAdmin,
DateTime? UnbanTime) : IAdminRemarksCommon;
}

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();

View File

@@ -1,4 +1,4 @@
using System.Collections.Immutable;
using System.Collections.Immutable;
using System.IO;
using System.Net;
using System.Text.Json;
@@ -7,6 +7,7 @@ using System.Threading.Tasks;
using Content.Server.Administration.Logs;
using Content.Shared.Administration.Logs;
using Content.Shared.CCVar;
using Content.Shared.Database;
using Content.Shared.Preferences;
using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore;
@@ -87,6 +88,14 @@ namespace Content.Server.Database
Task AddServerBanAsync(ServerBanDef serverBan);
Task AddServerUnbanAsync(ServerUnbanDef serverBan);
public Task EditServerBan(
int id,
string reason,
NoteSeverity severity,
DateTime? expiration,
Guid editedBy,
DateTime editedAt);
/// <summary>
/// Update ban exemption information for a player.
/// </summary>
@@ -132,6 +141,14 @@ namespace Content.Server.Database
Task AddServerRoleBanAsync(ServerRoleBanDef serverBan);
Task AddServerRoleUnbanAsync(ServerRoleUnbanDef serverBan);
public Task EditServerRoleBan(
int id,
string reason,
NoteSeverity severity,
DateTime? expiration,
Guid editedBy,
DateTime editedAt);
#endregion
#region Playtime
@@ -236,11 +253,27 @@ namespace Content.Server.Database
#region Admin Notes
Task<int> AddAdminNote(int? roundId, Guid player, string message, Guid createdBy, DateTime createdAt);
Task<int> AddAdminNote(int? roundId, Guid player, TimeSpan playtimeAtNote, string message, NoteSeverity severity, bool secret, Guid createdBy, DateTime createdAt, DateTime? expiryTime);
Task<int> AddAdminWatchlist(int? roundId, Guid player, TimeSpan playtimeAtNote, string message, Guid createdBy, DateTime createdAt, DateTime? expiryTime);
Task<int> AddAdminMessage(int? roundId, Guid player, TimeSpan playtimeAtNote, string message, Guid createdBy, DateTime createdAt, DateTime? expiryTime);
Task<AdminNote?> GetAdminNote(int id);
Task<List<AdminNote>> GetAdminNotes(Guid player);
Task<AdminWatchlist?> GetAdminWatchlist(int id);
Task<AdminMessage?> GetAdminMessage(int id);
Task<ServerBanNote?> GetServerBanAsNoteAsync(int id);
Task<ServerRoleBanNote?> GetServerRoleBanAsNoteAsync(int id);
Task<List<IAdminRemarksCommon>> GetAllAdminRemarks(Guid player);
Task<List<IAdminRemarksCommon>> GetVisibleAdminNotes(Guid player);
Task<List<AdminWatchlist>> GetActiveWatchlists(Guid player);
Task<List<AdminMessage>> GetMessages(Guid player);
Task EditAdminNote(int id, string message, NoteSeverity severity, bool secret, Guid editedBy, DateTime editedAt, DateTime? expiryTime);
Task EditAdminWatchlist(int id, string message, Guid editedBy, DateTime editedAt, DateTime? expiryTime);
Task EditAdminMessage(int id, string message, Guid editedBy, DateTime editedAt, DateTime? expiryTime);
Task DeleteAdminNote(int id, Guid deletedBy, DateTime deletedAt);
Task EditAdminNote(int id, string message, Guid editedBy, DateTime editedAt);
Task DeleteAdminWatchlist(int id, Guid deletedBy, DateTime deletedAt);
Task DeleteAdminMessage(int id, Guid deletedBy, DateTime deletedAt);
Task HideServerBanFromNotes(int id, Guid deletedBy, DateTime deletedAt);
Task HideServerRoleBanFromNotes(int id, Guid deletedBy, DateTime deletedAt);
Task MarkMessageAsSeen(int id);
#endregion
}
@@ -384,16 +417,22 @@ namespace Content.Server.Database
return RunDbCommand(() => _db.AddServerUnbanAsync(serverUnban));
}
public Task EditServerBan(int id, string reason, NoteSeverity severity, DateTime? expiration, Guid editedBy, DateTime editedAt)
{
DbWriteOpsMetric.Inc();
return RunDbCommand(() => _db.EditServerBan(id, reason, severity, expiration, editedBy, editedAt));
}
public Task UpdateBanExemption(NetUserId userId, ServerBanExemptFlags flags)
{
DbWriteOpsMetric.Inc();
return _db.UpdateBanExemption(userId, flags);
return RunDbCommand(() => _db.UpdateBanExemption(userId, flags));
}
public Task<ServerBanExemptFlags> GetBanExemption(NetUserId userId)
{
DbReadOpsMetric.Inc();
return _db.GetBanExemption(userId);
return RunDbCommand(() => _db.GetBanExemption(userId));
}
#region Role Ban
@@ -424,6 +463,12 @@ namespace Content.Server.Database
DbWriteOpsMetric.Inc();
return RunDbCommand(() => _db.AddServerRoleUnbanAsync(serverRoleUnban));
}
public Task EditServerRoleBan(int id, string reason, NoteSeverity severity, DateTime? expiration, Guid editedBy, DateTime editedAt)
{
DbWriteOpsMetric.Inc();
return RunDbCommand(() => _db.EditServerRoleBan(id, reason, severity, expiration, editedBy, editedAt));
}
#endregion
#region Playtime
@@ -637,7 +682,7 @@ namespace Content.Server.Database
return RunDbCommand(() => _db.SetLastReadRules(player, time));
}
public Task<int> AddAdminNote(int? roundId, Guid player, string message, Guid createdBy, DateTime createdAt)
public Task<int> AddAdminNote(int? roundId, Guid player, TimeSpan playtimeAtNote, string message, NoteSeverity severity, bool secret, Guid createdBy, DateTime createdAt, DateTime? expiryTime)
{
DbWriteOpsMetric.Inc();
var note = new AdminNote
@@ -646,24 +691,123 @@ namespace Content.Server.Database
CreatedById = createdBy,
LastEditedById = createdBy,
PlayerUserId = player,
PlaytimeAtNote = playtimeAtNote,
Message = message,
Severity = severity,
Secret = secret,
CreatedAt = createdAt,
LastEditedAt = createdAt
LastEditedAt = createdAt,
ExpirationTime = expiryTime
};
return RunDbCommand(() => _db.AddAdminNote(note));
}
public Task<int> AddAdminWatchlist(int? roundId, Guid player, TimeSpan playtimeAtNote, string message, Guid createdBy, DateTime createdAt, DateTime? expiryTime)
{
DbWriteOpsMetric.Inc();
var note = new AdminWatchlist
{
RoundId = roundId,
CreatedById = createdBy,
LastEditedById = createdBy,
PlayerUserId = player,
PlaytimeAtNote = playtimeAtNote,
Message = message,
CreatedAt = createdAt,
LastEditedAt = createdAt,
ExpirationTime = expiryTime
};
return RunDbCommand(() => _db.AddAdminWatchlist(note));
}
public Task<int> AddAdminMessage(int? roundId, Guid player, TimeSpan playtimeAtNote, string message, Guid createdBy, DateTime createdAt, DateTime? expiryTime)
{
DbWriteOpsMetric.Inc();
var note = new AdminMessage
{
RoundId = roundId,
CreatedById = createdBy,
LastEditedById = createdBy,
PlayerUserId = player,
PlaytimeAtNote = playtimeAtNote,
Message = message,
CreatedAt = createdAt,
LastEditedAt = createdAt,
ExpirationTime = expiryTime
};
return RunDbCommand(() => _db.AddAdminMessage(note));
}
public Task<AdminNote?> GetAdminNote(int id)
{
DbReadOpsMetric.Inc();
return RunDbCommand(() => _db.GetAdminNote(id));
}
public Task<List<AdminNote>> GetAdminNotes(Guid player)
public Task<AdminWatchlist?> GetAdminWatchlist(int id)
{
DbReadOpsMetric.Inc();
return RunDbCommand(() => _db.GetAdminNotes(player));
return RunDbCommand(() => _db.GetAdminWatchlist(id));
}
public Task<AdminMessage?> GetAdminMessage(int id)
{
DbReadOpsMetric.Inc();
return RunDbCommand(() => _db.GetAdminMessage(id));
}
public Task<ServerBanNote?> GetServerBanAsNoteAsync(int id)
{
DbReadOpsMetric.Inc();
return RunDbCommand(() => _db.GetServerBanAsNoteAsync(id));
}
public Task<ServerRoleBanNote?> GetServerRoleBanAsNoteAsync(int id)
{
DbReadOpsMetric.Inc();
return RunDbCommand(() => _db.GetServerRoleBanAsNoteAsync(id));
}
public Task<List<IAdminRemarksCommon>> GetAllAdminRemarks(Guid player)
{
DbReadOpsMetric.Inc();
return RunDbCommand(() => _db.GetAllAdminRemarks(player));
}
public Task<List<IAdminRemarksCommon>> GetVisibleAdminNotes(Guid player)
{
DbReadOpsMetric.Inc();
return RunDbCommand(() => _db.GetVisibleAdminRemarks(player));
}
public Task<List<AdminWatchlist>> GetActiveWatchlists(Guid player)
{
DbReadOpsMetric.Inc();
return RunDbCommand(() => _db.GetActiveWatchlists(player));
}
public Task<List<AdminMessage>> GetMessages(Guid player)
{
DbReadOpsMetric.Inc();
return RunDbCommand(() => _db.GetMessages(player));
}
public Task EditAdminNote(int id, string message, NoteSeverity severity, bool secret, Guid editedBy, DateTime editedAt, DateTime? expiryTime)
{
DbWriteOpsMetric.Inc();
return RunDbCommand(() => _db.EditAdminNote(id, message, severity, secret, editedBy, editedAt, expiryTime));
}
public Task EditAdminWatchlist(int id, string message, Guid editedBy, DateTime editedAt, DateTime? expiryTime)
{
DbWriteOpsMetric.Inc();
return RunDbCommand(() => _db.EditAdminWatchlist(id, message, editedBy, editedAt, expiryTime));
}
public Task EditAdminMessage(int id, string message, Guid editedBy, DateTime editedAt, DateTime? expiryTime)
{
DbWriteOpsMetric.Inc();
return RunDbCommand(() => _db.EditAdminMessage(id, message, editedBy, editedAt, expiryTime));
}
public Task DeleteAdminNote(int id, Guid deletedBy, DateTime deletedAt)
@@ -672,10 +816,34 @@ namespace Content.Server.Database
return RunDbCommand(() => _db.DeleteAdminNote(id, deletedBy, deletedAt));
}
public Task EditAdminNote(int id, string message, Guid editedBy, DateTime editedAt)
public Task DeleteAdminWatchlist(int id, Guid deletedBy, DateTime deletedAt)
{
DbWriteOpsMetric.Inc();
return RunDbCommand(() => _db.EditAdminNote(id, message, editedBy, editedAt));
return RunDbCommand(() => _db.DeleteAdminWatchlist(id, deletedBy, deletedAt));
}
public Task DeleteAdminMessage(int id, Guid deletedBy, DateTime deletedAt)
{
DbWriteOpsMetric.Inc();
return RunDbCommand(() => _db.DeleteAdminMessage(id, deletedBy, deletedAt));
}
public Task HideServerBanFromNotes(int id, Guid deletedBy, DateTime deletedAt)
{
DbWriteOpsMetric.Inc();
return RunDbCommand(() => _db.HideServerBanFromNotes(id, deletedBy, deletedAt));
}
public Task HideServerRoleBanFromNotes(int id, Guid deletedBy, DateTime deletedAt)
{
DbWriteOpsMetric.Inc();
return RunDbCommand(() => _db.HideServerRoleBanFromNotes(id, deletedBy, deletedAt));
}
public Task MarkMessageAsSeen(int id)
{
DbWriteOpsMetric.Inc();
return RunDbCommand(() => _db.MarkMessageAsSeen(id));
}
// Wrapper functions to run DB commands from the thread pool.

View File

@@ -1,4 +1,4 @@
using System.Collections.Immutable;
using System.Collections.Immutable;
using System.Data;
using System.Linq;
using System.Net;
@@ -120,7 +120,7 @@ namespace Content.Server.Database
{
var newQ = db.PgDbContext.Ban
.Include(p => p.Unban)
.Where(b => b.UserId == uid.UserId);
.Where(b => b.PlayerUserId == uid.UserId);
query = query == null ? newQ : query.Union(newQ);
}
@@ -169,7 +169,7 @@ namespace Content.Server.Database
}
NetUserId? uid = null;
if (ban.UserId is {} guid)
if (ban.PlayerUserId is {} guid)
{
uid = new NetUserId(guid);
}
@@ -189,7 +189,10 @@ namespace Content.Server.Database
ban.HWId == null ? null : ImmutableArray.Create(ban.HWId),
ban.BanTime,
ban.ExpirationTime,
ban.RoundId,
ban.PlaytimeAtNote,
ban.Reason,
ban.Severity,
aUid,
unbanDef);
}
@@ -222,10 +225,13 @@ namespace Content.Server.Database
Address = serverBan.Address,
HWId = serverBan.HWId?.ToArray(),
Reason = serverBan.Reason,
Severity = serverBan.Severity,
BanningAdmin = serverBan.BanningAdmin?.UserId,
BanTime = serverBan.BanTime.UtcDateTime,
ExpirationTime = serverBan.ExpirationTime?.UtcDateTime,
UserId = serverBan.UserId?.UserId
RoundId = serverBan.RoundId,
PlaytimeAtNote = serverBan.PlaytimeAtNote,
PlayerUserId = serverBan.UserId?.UserId
});
await db.PgDbContext.SaveChangesAsync();
@@ -310,7 +316,7 @@ namespace Content.Server.Database
{
var newQ = db.PgDbContext.RoleBan
.Include(p => p.Unban)
.Where(b => b.UserId == uid.UserId);
.Where(b => b.PlayerUserId == uid.UserId);
query = query == null ? newQ : query.Union(newQ);
}
@@ -351,7 +357,7 @@ namespace Content.Server.Database
}
NetUserId? uid = null;
if (ban.UserId is {} guid)
if (ban.PlayerUserId is {} guid)
{
uid = new NetUserId(guid);
}
@@ -371,7 +377,10 @@ namespace Content.Server.Database
ban.HWId == null ? null : ImmutableArray.Create(ban.HWId),
ban.BanTime,
ban.ExpirationTime,
ban.RoundId,
ban.PlaytimeAtNote,
ban.Reason,
ban.Severity,
aUid,
unbanDef,
ban.RoleId);
@@ -405,10 +414,13 @@ namespace Content.Server.Database
Address = serverRoleBan.Address,
HWId = serverRoleBan.HWId?.ToArray(),
Reason = serverRoleBan.Reason,
Severity = serverRoleBan.Severity,
BanningAdmin = serverRoleBan.BanningAdmin?.UserId,
BanTime = serverRoleBan.BanTime.UtcDateTime,
ExpirationTime = serverRoleBan.ExpirationTime?.UtcDateTime,
UserId = serverRoleBan.UserId?.UserId,
RoundId = serverRoleBan.RoundId,
PlaytimeAtNote = serverRoleBan.PlaytimeAtNote,
PlayerUserId = serverRoleBan.UserId?.UserId,
RoleId = serverRoleBan.Role,
});

View File

@@ -133,22 +133,17 @@ namespace Content.Server.Database
ServerBanExemptFlags? exemptFlags)
{
if (!exemptFlags.GetValueOrDefault(ServerBanExemptFlags.None).HasFlag(ServerBanExemptFlags.IP)
&& address != null && ban.Address is not null && IPAddressExt.IsInSubnet(address, ban.Address.Value))
&& address != null && ban.Address is not null && address.IsInSubnet(ban.Address.Value))
{
return true;
}
if (userId is { } id && ban.UserId == id.UserId)
if (userId is { } id && ban.PlayerUserId == id.UserId)
{
return true;
}
if (hwId is { } hwIdVar && hwIdVar.Length > 0 && hwIdVar.AsSpan().SequenceEqual(ban.HWId))
{
return true;
}
return false;
return hwId is { Length: > 0 } hwIdVar && hwIdVar.AsSpan().SequenceEqual(ban.HWId);
}
public override async Task AddServerBanAsync(ServerBanDef serverBan)
@@ -159,11 +154,14 @@ namespace Content.Server.Database
{
Address = serverBan.Address,
Reason = serverBan.Reason,
Severity = serverBan.Severity,
BanningAdmin = serverBan.BanningAdmin?.UserId,
HWId = serverBan.HWId?.ToArray(),
BanTime = serverBan.BanTime.UtcDateTime,
ExpirationTime = serverBan.ExpirationTime?.UtcDateTime,
UserId = serverBan.UserId?.UserId
RoundId = serverBan.RoundId,
PlaytimeAtNote = serverBan.PlaytimeAtNote,
PlayerUserId = serverBan.UserId?.UserId
});
await db.SqliteDbContext.SaveChangesAsync();
@@ -197,7 +195,8 @@ namespace Content.Server.Database
return ConvertRoleBan(ban);
}
public override async Task<List<ServerRoleBanDef>> GetServerRoleBansAsync(IPAddress? address,
public override async Task<List<ServerRoleBanDef>> GetServerRoleBansAsync(
IPAddress? address,
NetUserId? userId,
ImmutableArray<byte>? hwId,
bool includeUnbanned)
@@ -234,22 +233,17 @@ namespace Content.Server.Database
NetUserId? userId,
ImmutableArray<byte>? hwId)
{
if (address != null && ban.Address is not null && IPAddressExt.IsInSubnet(address, ban.Address.Value))
if (address != null && ban.Address is not null && address.IsInSubnet(ban.Address.Value))
{
return true;
}
if (userId is { } id && ban.UserId == id.UserId)
if (userId is { } id && ban.PlayerUserId == id.UserId)
{
return true;
}
if (hwId is { } hwIdVar && hwIdVar.Length > 0 && hwIdVar.AsSpan().SequenceEqual(ban.HWId))
{
return true;
}
return false;
return hwId is { Length: > 0 } hwIdVar && hwIdVar.AsSpan().SequenceEqual(ban.HWId);
}
public override async Task AddServerRoleBanAsync(ServerRoleBanDef serverBan)
@@ -260,11 +254,14 @@ namespace Content.Server.Database
{
Address = serverBan.Address,
Reason = serverBan.Reason,
Severity = serverBan.Severity,
BanningAdmin = serverBan.BanningAdmin?.UserId,
HWId = serverBan.HWId?.ToArray(),
BanTime = serverBan.BanTime.UtcDateTime,
ExpirationTime = serverBan.ExpirationTime?.UtcDateTime,
UserId = serverBan.UserId?.UserId,
RoundId = serverBan.RoundId,
PlaytimeAtNote = serverBan.PlaytimeAtNote,
PlayerUserId = serverBan.UserId?.UserId,
RoleId = serverBan.Role,
});
@@ -293,7 +290,7 @@ namespace Content.Server.Database
}
NetUserId? uid = null;
if (ban.UserId is { } guid)
if (ban.PlayerUserId is { } guid)
{
uid = new NetUserId(guid);
}
@@ -314,7 +311,10 @@ namespace Content.Server.Database
// SQLite apparently always reads DateTime as unspecified, but we always write as UTC.
DateTime.SpecifyKind(ban.BanTime, DateTimeKind.Utc),
ban.ExpirationTime == null ? null : DateTime.SpecifyKind(ban.ExpirationTime.Value, DateTimeKind.Utc),
ban.RoundId,
ban.PlaytimeAtNote,
ban.Reason,
ban.Severity,
aUid,
unban,
ban.RoleId);
@@ -360,7 +360,7 @@ namespace Content.Server.Database
}
NetUserId? uid = null;
if (ban.UserId is { } guid)
if (ban.PlayerUserId is { } guid)
{
uid = new NetUserId(guid);
}
@@ -381,7 +381,10 @@ namespace Content.Server.Database
// SQLite apparently always reads DateTime as unspecified, but we always write as UTC.
DateTime.SpecifyKind(ban.BanTime, DateTimeKind.Utc),
ban.ExpirationTime == null ? null : DateTime.SpecifyKind(ban.ExpirationTime.Value, DateTimeKind.Utc),
ban.RoundId,
ban.PlaytimeAtNote,
ban.Reason,
ban.Severity,
aUid,
unban);
}
@@ -483,7 +486,7 @@ namespace Content.Server.Database
var nextId = 1;
if (await db.DbContext.AdminNotes.AnyAsync())
{
nextId = await db.DbContext.AdminNotes.MaxAsync(dbVersion => dbVersion.Id) + 1;
nextId = await db.DbContext.AdminNotes.MaxAsync(adminNote => adminNote.Id) + 1;
}
note.Id = nextId;
@@ -491,6 +494,37 @@ namespace Content.Server.Database
return await base.AddAdminNote(note);
}
public override async Task<int> AddAdminWatchlist(AdminWatchlist watchlist)
{
await using (var db = await GetDb())
{
var nextId = 1;
if (await db.DbContext.AdminWatchlists.AnyAsync())
{
nextId = await db.DbContext.AdminWatchlists.MaxAsync(adminWatchlist => adminWatchlist.Id) + 1;
}
watchlist.Id = nextId;
}
return await base.AddAdminWatchlist(watchlist);
}
public override async Task<int> AddAdminMessage(AdminMessage message)
{
await using (var db = await GetDb())
{
var nextId = 1;
if (await db.DbContext.AdminMessages.AnyAsync())
{
nextId = await db.DbContext.AdminMessages.MaxAsync(adminMessage => adminMessage.Id) + 1;
}
message.Id = nextId;
}
return await base.AddAdminMessage(message);
}
private async Task<DbGuardImpl> GetDbImpl()
{

View File

@@ -1,5 +1,6 @@
using System.Collections.Immutable;
using System.Collections.Immutable;
using System.Net;
using Content.Shared.Database;
using Robust.Shared.Network;
namespace Content.Server.Database;
@@ -13,7 +14,10 @@ public sealed class ServerRoleBanDef
public DateTimeOffset BanTime { get; }
public DateTimeOffset? ExpirationTime { get; }
public int? RoundId { get; }
public TimeSpan PlaytimeAtNote { get; }
public string Reason { get; }
public NoteSeverity Severity { get; set; }
public NetUserId? BanningAdmin { get; }
public ServerRoleUnbanDef? Unban { get; }
public string Role { get; }
@@ -25,7 +29,10 @@ public sealed class ServerRoleBanDef
ImmutableArray<byte>? hwId,
DateTimeOffset banTime,
DateTimeOffset? expirationTime,
int? roundId,
TimeSpan playtimeAtNote,
string reason,
NoteSeverity severity,
NetUserId? banningAdmin,
ServerRoleUnbanDef? unban,
string role)
@@ -48,7 +55,10 @@ public sealed class ServerRoleBanDef
HWId = hwId;
BanTime = banTime;
ExpirationTime = expirationTime;
RoundId = roundId;
PlaytimeAtNote = playtimeAtNote;
Reason = reason;
Severity = severity;
BanningAdmin = banningAdmin;
Unban = unban;
Role = role;

View File

@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Content.Shared.Database;
namespace Content.Server.Database
{
public record ServerRoleBanNote(int Id, int? RoundId, Round? Round, Guid? PlayerUserId, Player? Player,
TimeSpan PlaytimeAtNote, string Message, NoteSeverity Severity, Player? CreatedBy, DateTime CreatedAt,
Player? LastEditedBy, DateTime? LastEditedAt, DateTime? ExpirationTime, bool Deleted, string[] Roles,
Player? UnbanningAdmin, DateTime? UnbanTime) : IAdminRemarksCommon;
}