Skip to content

Commit 71cd7d9

Browse files
authored
Support new DB schema (#82)
* Support new DB schema * Fix newline in banstable displaying multiple GUIDs * Update submodule
1 parent 199e493 commit 71cd7d9

File tree

14 files changed

+220
-117
lines changed

14 files changed

+220
-117
lines changed

SS14

Submodule SS14 updated 365 files

SS14.Admin/Helpers/BanHelper.cs

Lines changed: 49 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -34,41 +34,45 @@ public BanHelper(
3434
_httpContext = httpContext;
3535
}
3636

37-
public IQueryable<BanJoin<ServerBan, ServerUnban>> CreateServerBanJoin()
37+
public IQueryable<BanJoin> CreateServerBanJoin()
3838
{
39-
return CreateBanJoin<ServerBan, ServerUnban>(_dbContext.Ban);
39+
return CreateBanJoin().Where(b => b.Ban.Type == BanType.Server);
4040
}
4141

42-
public IQueryable<BanJoin<ServerRoleBan, ServerRoleUnban>> CreateRoleBanJoin()
42+
public IQueryable<BanJoin> CreateRoleBanJoin()
4343
{
44-
return CreateBanJoin<ServerRoleBan, ServerRoleUnban>(_dbContext.RoleBan);
44+
return CreateBanJoin().Where(b => b.Ban.Type == BanType.Role);
4545
}
4646

47-
private IQueryable<BanJoin<TBan, TUnban>> CreateBanJoin<TBan, TUnban>(DbSet<TBan> bans)
48-
where TBan : class, IBanCommon<TUnban>
49-
where TUnban : IUnbanCommon
47+
private IQueryable<BanJoin> CreateBanJoin()
5048
{
51-
return bans
49+
return _dbContext.Ban
50+
.AsSplitQuery()
5251
.Include(b => b.Unban)
52+
.Include(b => b.Players)
53+
.Include(b => b.Addresses)
54+
.Include(b => b.Hwids)
55+
.Include(b => b.Roles)
56+
.Include(b => b.Rounds)
5357
.LeftJoin(_dbContext.Player,
54-
ban => ban.PlayerUserId, player => player.UserId,
55-
(ban, player) => new { ban, player })
56-
.LeftJoin(_dbContext.Player,
57-
ban => ban.ban.BanningAdmin, admin => admin.UserId,
58-
(ban, admin) => new { ban.ban, ban.player, admin })
58+
ban => ban.BanningAdmin, admin => admin.UserId,
59+
(ban, admin) => new { ban, admin })
5960
.LeftJoin(_dbContext.Player,
6061
ban => ban.ban.Unban!.UnbanningAdmin, unbanAdmin => unbanAdmin.UserId,
61-
(ban, unbanAdmin) => new BanJoin<TBan, TUnban>
62+
(ban, unbanAdmin) => new BanJoin
6263
{
64+
Players = ban.ban.Players!
65+
.Select(p => _dbContext.Player.SingleOrDefault(pp => p.UserId == pp.UserId))
66+
.Where(p => p != null)
67+
.ToArray()!,
6368
Ban = ban.ban,
64-
Player = ban.player,
6569
Admin = ban.admin,
6670
UnbanAdmin = unbanAdmin
6771
});
6872
}
6973

7074
[Pure]
71-
public static bool IsBanActive<TUnban>(IBanCommon<TUnban> b) where TUnban : IUnbanCommon
75+
public static bool IsBanActive(Ban b)
7276
{
7377
return (b.ExpirationTime == null || b.ExpirationTime > DateTime.UtcNow) && b.Unban == null;
7478
}
@@ -80,11 +84,11 @@ public static bool IsBanActive<TUnban>(IBanCommon<TUnban> b) where TUnban : IUnb
8084
return hwid?.ToString();
8185
}
8286

83-
public sealed class BanJoin<TBan, TUnban> where TBan: IBanCommon<TUnban> where TUnban : IUnbanCommon
87+
public sealed class BanJoin
8488
{
85-
public TBan Ban { get; set; } = default!;
86-
public Player? Player { get; set; }
89+
public Ban Ban { get; set; } = default!;
8790
public Player? Admin { get; set; }
91+
public Player[] Players { get; set; } = [];
8892
public Player? UnbanAdmin { get; set; }
8993
}
9094

@@ -111,14 +115,13 @@ public sealed class BanJoin<TBan, TUnban> where TBan: IBanCommon<TUnban> where T
111115
}
112116

113117
/// <returns>Non-null string if an error occured that must be reported to the user.</returns>
114-
public async Task<string?> FillBanCommon<TUnban>(
115-
IBanCommon<TUnban> ban,
118+
public async Task<string?> FillBanCommon(
119+
Ban ban,
116120
string? nameOrUid,
117121
string? ip,
118122
string? hwid,
119123
int lengthMinutes,
120124
string reason)
121-
where TUnban : IUnbanCommon
122125
{
123126
if (string.IsNullOrWhiteSpace(nameOrUid) && string.IsNullOrWhiteSpace(ip) && string.IsNullOrWhiteSpace(hwid))
124127
return "Must provide at least one of name/UID, IP address or HWID.";
@@ -128,9 +131,17 @@ public sealed class BanJoin<TBan, TUnban> where TBan: IBanCommon<TUnban> where T
128131

129132
if (!string.IsNullOrWhiteSpace(nameOrUid))
130133
{
131-
ban.PlayerUserId = await _playerLocator.Resolve(nameOrUid);
132-
if (ban.PlayerUserId == null)
134+
var userId = await _playerLocator.Resolve(nameOrUid);
135+
if (userId == null)
133136
return $"Unable to find user with name {nameOrUid}";
137+
138+
ban.Players =
139+
[
140+
new BanPlayer
141+
{
142+
UserId = userId.Value,
143+
}
144+
];
134145
}
135146

136147
if (!string.IsNullOrWhiteSpace(ip))
@@ -144,7 +155,13 @@ public sealed class BanJoin<TBan, TUnban> where TBan: IBanCommon<TUnban> where T
144155
// Ban /64 on IPv6.
145156
parsedCidr ??= (byte)(parsedIp.AddressFamily == AddressFamily.InterNetwork ? 32 : 64);
146157

147-
ban.Address = new NpgsqlInet(parsedIp, parsedCidr.Value);
158+
ban.Addresses =
159+
[
160+
new BanAddress
161+
{
162+
Address = new NpgsqlInet(parsedIp, parsedCidr.Value)
163+
}
164+
];
148165
}
149166

150167
if (!string.IsNullOrWhiteSpace(hwid))
@@ -153,7 +170,13 @@ public sealed class BanJoin<TBan, TUnban> where TBan: IBanCommon<TUnban> where T
153170
if (!ImmutableTypedHwid.TryParse(hwid, out var parsedHwid))
154171
return "Invalid HWID";
155172

156-
ban.HWId = parsedHwid;
173+
ban.Hwids =
174+
[
175+
new BanHwid
176+
{
177+
HWId = parsedHwid,
178+
}
179+
];
157180
}
158181

159182
if (lengthMinutes != 0)

SS14.Admin/Helpers/SearchHelper.cs

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -35,59 +35,57 @@ public static IQueryable<ConnectionLog> SearchConnectionLog(IQueryable<Connectio
3535
return query.Where(expr);
3636
}
3737

38-
private static Expression<Func<BanHelper.BanJoin<TBan, TUnban>, bool>> MakeCommonBanSearchExpression<TBan, TUnban>(
38+
private static Expression<Func<BanHelper.BanJoin, bool>> MakeCommonBanSearchExpression(
3939
string search, ClaimsPrincipal user)
40-
where TBan : IBanCommon<TUnban>
41-
where TUnban : IUnbanCommon
4240
{
4341
var normalized = search.ToUpperInvariant();
4442

45-
Expression<Func<BanHelper.BanJoin<TBan, TUnban>, bool>> expr = u =>
46-
u.Player!.LastSeenUserName.ToUpper().Contains(normalized) ||
43+
Expression<Func<BanHelper.BanJoin, bool>> expr = u =>
44+
u.Players.Any(p => p.LastSeenUserName.ToUpper().Contains(normalized)) ||
4745
u.Admin!.LastSeenUserName.ToUpper().Contains(normalized);
4846

4947
if (Guid.TryParse(search, out var guid))
50-
CombineSearch(ref expr, b => b.Ban.PlayerUserId == guid);
48+
CombineSearch(ref expr, b => b.Ban.Players!.Any(p => p.UserId == guid));
5149

5250
if (user.IsInRole(Constants.PIIRole) && IPHelper.TryParseCidr(search, out var cidr))
53-
CombineSearch(ref expr, b => EF.Functions.ContainsOrEqual(cidr, b.Ban.Address!.Value));
51+
CombineSearch(ref expr, b => b.Ban.Addresses!.Any(a => EF.Functions.ContainsOrEqual(cidr, a.Address)));
5452

5553
if (user.IsInRole(Constants.PIIRole) && IPAddress.TryParse(search, out var ip))
56-
CombineSearch(ref expr, u => EF.Functions.ContainsOrEqual(u.Ban.Address!.Value, ip));
54+
CombineSearch(ref expr, u => u.Ban.Addresses!.Any(a => EF.Functions.ContainsOrEqual(a.Address, ip)));
5755

5856
if (user.IsInRole(Constants.PIIRole) && ImmutableTypedHwid.TryParse(search, out var hwid))
59-
CombineSearch(ref expr, u => u.Ban.HWId!.Type == hwid.Type && u.Ban.HWId.Hwid == hwid.Hwid.ToArray());
57+
CombineSearch(ref expr, u => u.Ban.Hwids!.Any(h => h.HWId.Type == hwid.Type && h.HWId.Hwid == hwid.Hwid.ToArray()));
6058

6159
return expr;
6260
}
6361

64-
public static IQueryable<BanHelper.BanJoin<ServerBan, ServerUnban>> SearchServerBans(
65-
IQueryable<BanHelper.BanJoin<ServerBan, ServerUnban>> query,
62+
public static IQueryable<BanHelper.BanJoin> SearchServerBans(
63+
IQueryable<BanHelper.BanJoin> query,
6664
string? search, ClaimsPrincipal user)
6765
{
6866
if (string.IsNullOrEmpty(search))
6967
return query;
7068

7169
search = search.Trim();
7270

73-
var expr = MakeCommonBanSearchExpression<ServerBan, ServerUnban>(search, user);
71+
var expr = MakeCommonBanSearchExpression(search, user);
7472

7573
return query.Where(expr);
7674
}
7775

78-
public static IQueryable<BanHelper.BanJoin<ServerRoleBan, ServerRoleUnban>> SearchRoleBans(
79-
IQueryable<BanHelper.BanJoin<ServerRoleBan, ServerRoleUnban>> query,
76+
public static IQueryable<BanHelper.BanJoin> SearchRoleBans(
77+
IQueryable<BanHelper.BanJoin> query,
8078
string? search, ClaimsPrincipal user)
8179
{
8280
if (string.IsNullOrEmpty(search))
8381
return query;
8482

8583
search = search.Trim();
8684

87-
var expr = MakeCommonBanSearchExpression<ServerRoleBan, ServerRoleUnban>(search, user);
85+
var expr = MakeCommonBanSearchExpression(search, user);
8886

8987
// Match role name exactly.
90-
CombineSearch(ref expr, u => u.Ban.RoleId == search);
88+
CombineSearch(ref expr, u => u.Ban.Roles!.Any(r => r.RoleId == search));
9189

9290
return query.Where(expr);
9391
}

SS14.Admin/Helpers/SortState.cs

Lines changed: 55 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -87,12 +87,59 @@ private static SortOrder Flip(SortOrder order)
8787

8888
public void AddColumn<TKey>(string name, Expression<Func<T, TKey>> expr, SortOrder? sortDefault = null)
8989
{
90-
_columns.Add(name, new ColumnReg<TKey>(expr, sortDefault));
90+
AddColumn(name, expr, expr, sortDefault);
91+
}
92+
93+
/// <summary>
94+
/// Add a column that can be sorted.
95+
/// </summary>
96+
/// <param name="name">The ID of the column, used in the HTML.</param>
97+
/// <param name="exprDesc">Expression to use as sort key when sorting descending.</param>
98+
/// <param name="exprAsc">Expression to use as sort key when sorting ascending.</param>
99+
/// <param name="sortDefault">If given, this column is the default sort column, with the given order.</param>
100+
/// <typeparam name="TKey">The type of items to use as sort key.</typeparam>
101+
public void AddColumn<TKey>(
102+
string name,
103+
Expression<Func<T, TKey>> exprDesc,
104+
Expression<Func<T, TKey>> exprAsc,
105+
SortOrder? sortDefault = null)
106+
{
107+
_columns.Add(name, new ColumnReg<TKey>(exprAsc, exprDesc, sortDefault));
91108

92109
if (sortDefault != null)
93110
DefaultColumn = name;
94111
}
95112

113+
/// <summary>
114+
/// Add a column that can be sorted, containing multiple values.
115+
/// </summary>
116+
/// <remarks>
117+
/// The values in the column are used as a sort key by their min/max,
118+
/// depending on how the column is being sorted.
119+
/// </remarks>
120+
/// <param name="name">The ID of the column, used in the HTML.</param>
121+
/// <param name="expr">Expression to use as sort key.</param>
122+
/// <param name="sortDefault">If given, this column is the default sort column, with the given order.</param>
123+
/// <typeparam name="TKey">The type of items to use as sort key.</typeparam>
124+
public void AddColumnMultiple<TKey>(
125+
string name,
126+
Expression<Func<T, IEnumerable<TKey>>> expr,
127+
SortOrder? sortDefault = null)
128+
{
129+
var param = Expression.Parameter(typeof(T));
130+
var invokeExpr = Expression.Invoke(expr, param);
131+
132+
AddColumn(
133+
name,
134+
Expression.Lambda<Func<T, TKey>>(
135+
Expression.Call(typeof(Enumerable), "Max", [typeof(TKey)], invokeExpr),
136+
param),
137+
Expression.Lambda<Func<T, TKey>>(
138+
Expression.Call(typeof(Enumerable), "Min", [typeof(TKey)], invokeExpr),
139+
param),
140+
sortDefault);
141+
}
142+
96143
public IOrderedQueryable<T> ApplyToQuery(IQueryable<T> query)
97144
{
98145
var col = _columns[CurColumn!];
@@ -104,14 +151,18 @@ private abstract record ColumnReg(SortOrder? SortDefault)
104151
public abstract IOrderedQueryable<T> ApplyToQuery(IQueryable<T> query, SortOrder order);
105152
}
106153

107-
private sealed record ColumnReg<TKey>(Expression<Func<T, TKey>> Expr, SortOrder? SortDefault) : ColumnReg(SortDefault)
154+
private sealed record ColumnReg<TKey>(
155+
Expression<Func<T, TKey>> ExprAscending,
156+
Expression<Func<T, TKey>> ExprDescending,
157+
SortOrder? SortDefault)
158+
: ColumnReg(SortDefault)
108159
{
109160
public override IOrderedQueryable<T> ApplyToQuery(IQueryable<T> query, SortOrder order)
110161
{
111162
return order switch
112163
{
113-
SortOrder.Ascending => query.OrderBy(Expr),
114-
SortOrder.Descending => query.OrderByDescending(Expr),
164+
SortOrder.Ascending => query.OrderBy(ExprAscending),
165+
SortOrder.Descending => query.OrderByDescending(ExprDescending),
115166
_ => throw new InvalidOperationException()
116167
};
117168
}

SS14.Admin/Pages/Bans/Create.cshtml.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,10 @@ public async Task<IActionResult> OnPostCreateAsync()
5555

5656
ExemptFlags = BanExemptions.GetExemptionFromForm(Request.Form);
5757

58-
var ban = new ServerBan();
58+
var ban = new Ban
59+
{
60+
Type = BanType.Server,
61+
};
5962

6063
var ipAddr = Input.IP;
6164
var hwid = Input.HWid;

SS14.Admin/Pages/Bans/CreateMassBan.cshtml.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System.Globalization;
22
using Content.Server.Database;
3+
using Content.Shared.Database;
34
using Microsoft.AspNetCore.Authorization;
45
using Microsoft.AspNetCore.Mvc;
56
using Microsoft.AspNetCore.Mvc.RazorPages;
@@ -60,7 +61,10 @@ public async Task<IActionResult> OnPostAsync(IFormFile file)
6061

6162
foreach (var entry in entries)
6263
{
63-
var ban = new ServerBan();
64+
var ban = new Ban
65+
{
66+
Type = BanType.Server,
67+
};
6468

6569
var ipAddr = entry.Address;
6670
var hwid = entry.Hwid;

SS14.Admin/Pages/Bans/Hits.cshtml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,15 @@
1313

1414
<dl class="row">
1515
<dt class="col-sm-2">Name:</dt>
16-
<dd class="col-sm-10">@Model.Ban.Player?.LastSeenUserName</dd>
16+
<dd class="col-sm-10">@(string.Join(", ", Model.Ban.Players.Select(p => p.LastSeenUserName)))</dd>
1717
<dt class="col-sm-2">User ID:</dt>
18-
<dd class="col-sm-10 font-monospace">@Model.Ban.Ban.PlayerUserId</dd>
18+
<dd class="col-sm-10 font-monospace">@(string.Join(", ", Model.Ban.Ban.Id))</dd>
1919
@if (User.IsInRole(Constants.PIIRole))
2020
{
2121
<dt class="col-sm-2">IP:</dt>
22-
<dd class="col-sm-10 font-monospace">@Model.Ban.Ban.Address?.FormatCidr()</dd>
22+
<dd class="col-sm-10 font-monospace">@(string.Join(", ", Model.Ban.Ban.Addresses!.Select(ba => ba.Address.FormatCidr())))</dd>
2323
<dt class="col-sm-2">HWID:</dt>
24-
<dd class="col-sm-10 font-monospace">@BanHelper.FormatHwid(Model.Ban.Ban.HWId)</dd>
24+
<dd class="col-sm-10 font-monospace">@(string.Join(", ", Model.Ban.Ban.Hwids!.Select(ba => ba.HWId.ToImmutable().ToString())))</dd>
2525
}
2626
<dt class="col-sm-2">Time:</dt>
2727
<dd class="col-sm-10">@Model.Ban.Ban.BanTime.ToString("yyyy-MM-dd HH:mm:ss")</dd>

SS14.Admin/Pages/Bans/Hits.cshtml.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ public class Hits : PageModel
1313
private readonly PostgresServerDbContext _dbContext;
1414
private readonly BanHelper _banHelper;
1515

16-
public BanHelper.BanJoin<ServerBan, ServerUnban> Ban { get; set; } = default!;
16+
public BanHelper.BanJoin Ban { get; set; } = default!;
1717

1818
public ISortState SortState { get; private set; } = default!;
1919
public PaginationState<ConnectionsIndexModel.Connection> Pagination { get; } = new(100);

0 commit comments

Comments
 (0)