THE RETURN OF THE KING

This reverts commit c18d07538a.
This commit is contained in:
DrSmugleaf
2021-11-22 19:08:27 +01:00
parent 14e342663e
commit c3fe5909ad
65 changed files with 7021 additions and 236 deletions

View File

@@ -3,14 +3,18 @@ using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Net;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using Content.Server.Administration.Logs;
using Content.Shared.Administration.Logs;
using Content.Shared.CharacterAppearance;
using Content.Shared.Preferences;
using Microsoft.EntityFrameworkCore;
using Robust.Shared.Enums;
using Robust.Shared.Maths;
using Robust.Shared.Network;
using Robust.Shared.Utility;
namespace Content.Server.Database
{
@@ -440,6 +444,54 @@ namespace Content.Server.Database
await db.DbContext.SaveChangesAsync(cancel);
}
public virtual async Task<int> AddNewRound(params Guid[] playerIds)
{
await using var db = await GetDb();
var players = await db.DbContext.Player
.Where(player => playerIds.Contains(player.UserId))
.ToListAsync();
var round = new Round
{
Players = players
};
db.DbContext.Round.Add(round);
await db.DbContext.SaveChangesAsync();
return round.Id;
}
public async Task<Round> GetRound(int id)
{
await using var db = await GetDb();
var round = await db.DbContext.Round
.Include(round => round.Players)
.SingleAsync(round => round.Id == id);
return round;
}
public async Task AddRoundPlayers(int id, Guid[] playerIds)
{
await using var db = await GetDb();
var round = await db.DbContext.Round
.Include(round => round.Players)
.SingleAsync(round => round.Id == id);
var players = await db.DbContext.Player
.Where(player => playerIds.Contains(player.UserId))
.ToListAsync();
round.Players.AddRange(players);
await db.DbContext.SaveChangesAsync();
}
public async Task UpdateAdminRankAsync(AdminRank rank, CancellationToken cancel)
{
await using var db = await GetDb();
@@ -455,6 +507,160 @@ namespace Content.Server.Database
}
#endregion
#region Admin Logs
public virtual async Task AddAdminLogs(List<QueuedLog> logs)
{
await using var db = await GetDb();
var entities = new Dictionary<int, AdminLogEntity>();
foreach (var (log, entityData) in logs)
{
var logEntities = new List<AdminLogEntity>(entityData.Count);
foreach (var (id, name) in entityData)
{
var entity = entities.GetOrNew(id);
entity.Name = name;
logEntities.Add(entity);
}
log.Entities = logEntities;
db.DbContext.AdminLog.Add(log);
}
await db.DbContext.SaveChangesAsync();
}
private async Task<IQueryable<AdminLog>> GetAdminLogsQuery(ServerDbContext db, LogFilter? filter = null)
{
IQueryable<AdminLog> query = db.AdminLog;
if (filter == null)
{
return query.OrderBy(log => log.Date);
}
if (filter.Round != null)
{
query = query.Where(log => log.RoundId == filter.Round);
}
if (filter.Search != null)
{
query = query.Where(log => log.Message.Contains(filter.Search));
}
if (filter.Types != null)
{
query = query.Where(log => filter.Types.Contains(log.Type));
}
if (filter.Impacts != null)
{
query = query.Where(log => filter.Impacts.Contains(log.Impact));
}
if (filter.Before != null)
{
query = query.Where(log => log.Date < filter.Before);
}
if (filter.After != null)
{
query = query.Where(log => log.Date > filter.After);
}
if (filter.AnyPlayers != null)
{
var players = await db.AdminLogPlayer
.Where(player => filter.AnyPlayers.Contains(player.PlayerUserId))
.ToListAsync();
if (players.Count > 0)
{
query = from log in query
join player in db.AdminLogPlayer on log.Id equals player.LogId
where filter.AnyPlayers.Contains(player.Player.UserId)
select log;
}
}
if (filter.AllPlayers != null)
{
// TODO ADMIN LOGGING
}
query = query.Distinct();
if (filter.LastLogId != null)
{
query = filter.DateOrder switch
{
DateOrder.Ascending => query.Where(log => log.Id < filter.LastLogId),
DateOrder.Descending => query.Where(log => log.Id > filter.LastLogId),
_ => throw new ArgumentOutOfRangeException(nameof(filter),
$"Unknown {nameof(DateOrder)} value {filter.DateOrder}")
};
}
query = filter.DateOrder switch
{
DateOrder.Ascending => query.OrderBy(log => log.Date),
DateOrder.Descending => query.OrderByDescending(log => log.Date),
_ => throw new ArgumentOutOfRangeException(nameof(filter),
$"Unknown {nameof(DateOrder)} value {filter.DateOrder}")
};
if (filter.Limit != null)
{
query = query.Take(filter.Limit.Value);
}
return query;
}
public async IAsyncEnumerable<string> GetAdminLogMessages(LogFilter? filter = null)
{
await using var db = await GetDb();
var query = await GetAdminLogsQuery(db.DbContext, filter);
await foreach (var log in query.Select(log => log.Message).AsAsyncEnumerable())
{
yield return log;
}
}
public async IAsyncEnumerable<LogRecord> GetAdminLogs(LogFilter? filter = null)
{
await using var db = await GetDb();
var query = await GetAdminLogsQuery(db.DbContext, filter);
await foreach (var log in query.AsAsyncEnumerable())
{
var players = new Guid[log.Players.Count];
for (var i = 0; i < log.Players.Count; i++)
{
players[i] = log.Players[i].PlayerUserId;
}
yield return new LogRecord(log.Id, log.RoundId, log.Type, log.Impact, log.Date, log.Message, players);
}
}
public async IAsyncEnumerable<JsonDocument> GetAdminLogsJson(LogFilter? filter = null)
{
await using var db = await GetDb();
var query = await GetAdminLogsQuery(db.DbContext, filter);
await foreach (var json in query.Select(log => log.Json).AsAsyncEnumerable())
{
yield return json;
}
}
#endregion
protected abstract Task<DbGuard> GetDb();
protected abstract class DbGuard : IAsyncDisposable

View File

@@ -3,8 +3,10 @@ using System.Collections.Generic;
using System.Collections.Immutable;
using System.IO;
using System.Net;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using Content.Server.Administration.Logs;
using Content.Shared.CCVar;
using Content.Shared.Preferences;
using Microsoft.Data.Sqlite;
@@ -17,17 +19,17 @@ using Robust.Shared.IoC;
using Robust.Shared.Log;
using Robust.Shared.Maths;
using Robust.Shared.Network;
using Logger = Robust.Shared.Log.Logger;
using LogLevel = Robust.Shared.Log.LogLevel;
using MSLogLevel = Microsoft.Extensions.Logging.LogLevel;
namespace Content.Server.Database
{
public interface IServerDbManager
{
void Init();
// Preferences
#region Preferences
Task<PlayerPreferences> InitPrefsAsync(NetUserId userId, ICharacterProfile defaultProfile);
Task SaveSelectedCharacterIndexAsync(NetUserId userId, int index);
@@ -38,12 +40,15 @@ namespace Content.Server.Database
// Single method for two operations for transaction.
Task DeleteSlotAndSetSelectedIndex(NetUserId userId, int deleteSlot, int newSlot);
Task<PlayerPreferences?> GetPlayerPreferencesAsync(NetUserId userId);
#endregion
#region User Ids
// Username assignment (for guest accounts, so they persist GUID)
Task AssignUserIdAsync(string name, NetUserId userId);
Task<NetUserId?> GetAssignedUserIdAsync(string name);
#endregion
// Ban stuff
#region Bans
/// <summary>
/// Looks up a ban by id.
/// This will return a pardoned ban as well.
@@ -82,8 +87,9 @@ namespace Content.Server.Database
Task AddServerBanAsync(ServerBanDef serverBan);
Task AddServerUnbanAsync(ServerUnbanDef serverBan);
#endregion
// Player records
#region Player Records
Task UpdatePlayerRecordAsync(
NetUserId userId,
string userName,
@@ -91,15 +97,17 @@ namespace Content.Server.Database
ImmutableArray<byte> hwId);
Task<PlayerRecord?> GetPlayerRecordByUserName(string userName, CancellationToken cancel = default);
Task<PlayerRecord?> GetPlayerRecordByUserId(NetUserId userId, CancellationToken cancel = default);
#endregion
// Connection log
#region Connection Logs
Task AddConnectionLogAsync(
NetUserId userId,
string userName,
IPAddress address,
ImmutableArray<byte> hwId);
#endregion
// Admins
#region Admin Ranks
Task<Admin?> GetAdminDataForAsync(NetUserId userId, CancellationToken cancel = default);
Task<AdminRank?> GetAdminRankAsync(int id, CancellationToken cancel = default);
@@ -113,6 +121,24 @@ namespace Content.Server.Database
Task RemoveAdminRankAsync(int rankId, CancellationToken cancel = default);
Task AddAdminRankAsync(AdminRank rank, CancellationToken cancel = default);
Task UpdateAdminRankAsync(AdminRank rank, CancellationToken cancel = default);
#endregion
#region Rounds
Task<int> AddNewRound(params Guid[] playerIds);
Task<Round> GetRound(int id);
Task AddRoundPlayers(int id, params Guid[] playerIds);
#endregion
#region Admin Logs
Task AddAdminLogs(List<QueuedLog> logs);
IAsyncEnumerable<string> GetAdminLogMessages(LogFilter? filter = null);
IAsyncEnumerable<LogRecord> GetAdminLogs(LogFilter? filter = null);
IAsyncEnumerable<JsonDocument> GetAdminLogsJson(LogFilter? filter = null);
#endregion
}
public sealed class ServerDbManager : IServerDbManager
@@ -290,11 +316,46 @@ namespace Content.Server.Database
return _db.AddAdminRankAsync(rank, cancel);
}
public Task<int> AddNewRound(params Guid[] playerIds)
{
return _db.AddNewRound(playerIds);
}
public Task<Round> GetRound(int id)
{
return _db.GetRound(id);
}
public Task AddRoundPlayers(int id, params Guid[] playerIds)
{
return _db.AddRoundPlayers(id, playerIds);
}
public Task UpdateAdminRankAsync(AdminRank rank, CancellationToken cancel = default)
{
return _db.UpdateAdminRankAsync(rank, cancel);
}
public Task AddAdminLogs(List<QueuedLog> logs)
{
return _db.AddAdminLogs(logs);
}
public IAsyncEnumerable<string> GetAdminLogMessages(LogFilter? filter = null)
{
return _db.GetAdminLogMessages(filter);
}
public IAsyncEnumerable<LogRecord> GetAdminLogs(LogFilter? filter = null)
{
return _db.GetAdminLogs(filter);
}
public IAsyncEnumerable<JsonDocument> GetAdminLogsJson(LogFilter? filter = null)
{
return _db.GetAdminLogsJson(filter);
}
private DbContextOptions<ServerDbContext> CreatePostgresOptions()
{
var host = _cfg.GetCVar(CCVars.DatabasePgHost);

View File

@@ -3,15 +3,19 @@ using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Net;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using Content.Server.Administration.Logs;
using Content.Server.IP;
using Content.Server.Preferences.Managers;
using Content.Shared.Administration.Logs;
using Content.Shared.CCVar;
using Microsoft.EntityFrameworkCore;
using Robust.Shared.Configuration;
using Robust.Shared.IoC;
using Robust.Shared.Network;
using Robust.Shared.Utility;
namespace Content.Server.Database
{
@@ -246,6 +250,65 @@ namespace Content.Server.Database
return (admins.Select(p => (p.a, p.LastSeenUserName)).ToArray(), adminRanks)!;
}
private async Task<int> NextId<TModel>(DbSet<TModel> set, Func<TModel, int> selector) where TModel : class
{
var id = 1;
if (await set.AnyAsync())
{
id = set.Max(selector) + 1;
}
return id;
}
public override async Task<int> AddNewRound(params Guid[] playerIds)
{
await using var db = await GetDb();
var players = await db.DbContext.Player
.Where(player => playerIds.Contains(player.UserId))
.ToListAsync();
var round = new Round
{
Id = await NextId(db.DbContext.Round, round => round.Id),
Players = players
};
db.DbContext.Round.Add(round);
await db.DbContext.SaveChangesAsync();
return round.Id;
}
public override async Task AddAdminLogs(List<QueuedLog> logs)
{
await using var db = await GetDb();
var nextId = await NextId(db.DbContext.AdminLog, log => log.Id);
var entities = new Dictionary<int, AdminLogEntity>();
foreach (var (log, entityData) in logs)
{
log.Id = nextId++;
var logEntities = new List<AdminLogEntity>(entityData.Count);
foreach (var (id, name) in entityData)
{
var entity = entities.GetOrNew(id);
entity.Name = name;
logEntities.Add(entity);
}
log.Entities = logEntities;
db.DbContext.AdminLog.Add(log);
}
await db.DbContext.SaveChangesAsync();
}
private async Task<DbGuardImpl> GetDbImpl()
{
await _dbReadyTask;