[feat] Разделение банов по серверам.

# Conflicts:
#	Content.Client/Administration/UI/BanList/BanListLine.xaml.cs
#	Content.Client/Administration/UI/BanList/Bans/BanListHeader.xaml
#	Content.Client/Administration/UI/BanList/Bans/BanListLine.xaml
#	Content.Client/Administration/UI/Tabs/AdminTab/BanWindow.xaml
#	Content.Client/Administration/UI/Tabs/AdminTab/BanWindow.xaml.cs
#	Content.IntegrationTests/Tests/Commands/PardonCommand.cs
#	Content.Server/Administration/Commands/BanCommand.cs
#	Content.Server/Administration/Commands/DepartmentBanCommand.cs
#	Content.Server/Administration/Commands/RoleBanCommand.cs
#	Content.Server/Administration/Managers/RoleBanManager.cs
#	Content.Server/Database/ServerDbManager.cs
#	Content.Server/Database/ServerDbPostgres.cs
#	Content.Server/Database/ServerDbSqlite.cs
This commit is contained in:
rhailrake
2023-04-30 14:27:27 +06:00
committed by Remuchi
parent 8bd6754472
commit 977e075086
42 changed files with 5825 additions and 328 deletions

View File

@@ -92,6 +92,7 @@ public sealed class BanListEui : BaseEui
}
line.BanningAdmin.Text = ban.BanningAdminName;
line.ServerName.Text = ban.ServerName == "unknown" ? "GLOBAL" : ban.ServerName;
}
private void OnLineIdsClicked<T>(IBanListLine<T> line) where T : SharedServerBan

View File

@@ -25,6 +25,11 @@
<Label Text="{Loc ban-list-header-banning-admin}"
SizeFlagsStretchRatio="2"
HorizontalExpand="True"/>
<cc:VSeparator/>
<Label Text="{Loc ban-list-header-server}"
SizeFlagsStretchRatio="2"
HorizontalExpand="True"/>
<cc:VSeparator/>
</BoxContainer>
</PanelContainer>
</ContainerButton>

View File

@@ -38,4 +38,11 @@
SizeFlagsStretchRatio="2"
HorizontalExpand="True"
ClipText="True"/>
<cc:VSeparator/>
<Label Name="ServerName"
Access="Public"
SizeFlagsStretchRatio="2"
HorizontalExpand="True"
ClipText="True"/>
<cc:VSeparator/>
</BoxContainer>

View File

@@ -10,4 +10,5 @@ public interface IBanListLine<T> where T : SharedServerBan
Label BanTime { get; }
Label Expires { get; }
Label BanningAdmin { get; }
Label ServerName { get; }
}

View File

@@ -29,6 +29,11 @@
<Label Text="{Loc ban-list-header-banning-admin}"
SizeFlagsStretchRatio="2"
HorizontalExpand="True"/>
<cc:VSeparator/>
<Label Text="{Loc ban-list-header-server}"
SizeFlagsStretchRatio="2"
HorizontalExpand="True"/>
<cc:VSeparator/>
</BoxContainer>
</PanelContainer>
</ContainerButton>

View File

@@ -43,4 +43,11 @@
SizeFlagsStretchRatio="2"
HorizontalExpand="True"
ClipText="True"/>
<cc:VSeparator/>
<Label Name="ServerName"
Access="Public"
SizeFlagsStretchRatio="2"
HorizontalExpand="True"
ClipText="True"/>
<cc:VSeparator/>
</BoxContainer>

View File

@@ -29,21 +29,12 @@
<Control MinWidth="50" />
<Label Name="ExpiresLabel" />
</BoxContainer>
<BoxContainer Orientation="Horizontal" Margin="4">
<OptionButton Name="TypeOption" />
<Control MinWidth="30" />
<Label Text="{Loc ban-panel-severity}" />
<OptionButton Name="SeverityOption" />
</BoxContainer>
<CheckBox Name="GlobalBanCheckbox" Margin="2" Text="Глобальный бан?" Pressed="False" />
<cc:HSeparator Margin="1"/>
<TextEdit Name="ReasonTextEdit" MinHeight="100" VerticalExpand="True" HorizontalExpand="True" />
</BoxContainer>
<!-- Player List -->
<cc:PlayerListControl Name="PlayerList" VerticalExpand="True" />
<!-- Role list (auto-generated) -->
<ScrollContainer>
<BoxContainer Name="RolesContainer" Orientation="Vertical" />
</ScrollContainer>
</TabContainer>
<Button Name="SubmitButton" Text="{Loc ban-panel-submit}" HorizontalExpand="True" />
</BoxContainer>

View File

@@ -1,17 +1,13 @@
using System.Linq;
using System.Net;
using System.Net.Sockets;
using Content.Client.Administration.UI.CustomControls;
using Content.Shared.Administration;
using Content.Shared.Database;
using Content.Shared.Roles;
using Robust.Client.AutoGenerated;
using Robust.Client.Graphics;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Prototypes;
using Robust.Shared.Timing;
using Robust.Shared.Utility;
@@ -20,7 +16,7 @@ namespace Content.Client.Administration.UI.BanPanel;
[GenerateTypedNameReferences]
public sealed partial class BanPanel : DefaultWindow
{
public event Action<string?, (IPAddress, int)?, bool, byte[]?, bool, uint, string, NoteSeverity, string[]?, bool>? BanSubmitted;
public event Action<string?, (IPAddress, int)?, bool, byte[]?, bool, uint, string, NoteSeverity, bool, bool>? BanSubmitted;
public event Action<string>? PlayerChanged;
private string? PlayerUsername { get; set; }
private (IPAddress, int)? IpAddress { get; set; }
@@ -29,9 +25,6 @@ public sealed partial class BanPanel : DefaultWindow
private uint Multiplier { get; set; }
private bool HasBanFlag { get; set; }
private TimeSpan? ButtonResetOn { get; set; }
// This is less efficient than just holding a reference to the root control and enumerating children, but you
// have to know how the controls are nested, which makes the code more complicated.
private readonly List<CheckBox> _roleCheckboxes = new();
[Dependency] private readonly IGameTiming _gameTiming = default!;
@@ -39,8 +32,7 @@ public sealed partial class BanPanel : DefaultWindow
{
BasicInfo,
//Text,
Players,
Roles
Players
}
private enum Multipliers
@@ -54,13 +46,6 @@ public sealed partial class BanPanel : DefaultWindow
Permanent
}
private enum Types
{
None,
Server,
Role
}
public BanPanel()
{
RobustXamlLoader.Load(this);
@@ -90,11 +75,6 @@ public sealed partial class BanPanel : DefaultWindow
HwidLine.Editable = HwidCheckbox.Pressed;
OnHwidChanged();
};
TypeOption.OnItemSelected += args =>
{
TypeOption.SelectId(args.Id);
OnTypeChanged();
};
LastConnCheckbox.OnPressed += args =>
{
IpLine.ModulateSelfOverride = null;
@@ -104,13 +84,6 @@ public sealed partial class BanPanel : DefaultWindow
};
SubmitButton.OnPressed += SubmitButtonOnOnPressed;
SeverityOption.AddItem(Loc.GetString("admin-note-editor-severity-none"), (int) NoteSeverity.None);
SeverityOption.AddItem(Loc.GetString("admin-note-editor-severity-low"), (int) NoteSeverity.Minor);
SeverityOption.AddItem(Loc.GetString("admin-note-editor-severity-medium"), (int) NoteSeverity.Medium);
SeverityOption.AddItem(Loc.GetString("admin-note-editor-severity-high"), (int) NoteSeverity.High);
SeverityOption.SelectId((int) NoteSeverity.Medium);
SeverityOption.OnItemSelected += args => SeverityOption.SelectId(args.Id);
MultiplierOption.AddItem(Loc.GetString("ban-panel-minutes"), (int) Multipliers.Minutes);
MultiplierOption.AddItem(Loc.GetString("ban-panel-hours"), (int) Multipliers.Hours);
MultiplierOption.AddItem(Loc.GetString("ban-panel-days"), (int) Multipliers.Days);
@@ -124,90 +97,8 @@ public sealed partial class BanPanel : DefaultWindow
Tabs.SetTabTitle((int) TabNumbers.BasicInfo, Loc.GetString("ban-panel-tabs-basic"));
//Tabs.SetTabTitle((int) TabNumbers.Text, Loc.GetString("ban-panel-tabs-reason"));
Tabs.SetTabTitle((int) TabNumbers.Players, Loc.GetString("ban-panel-tabs-players"));
Tabs.SetTabTitle((int) TabNumbers.Roles, Loc.GetString("ban-panel-tabs-role"));
Tabs.SetTabVisible((int) TabNumbers.Roles, false);
TypeOption.AddItem(Loc.GetString("ban-panel-select"), (int) Types.None);
TypeOption.AddItem(Loc.GetString("ban-panel-server"), (int) Types.Server);
TypeOption.AddItem(Loc.GetString("ban-panel-role"), (int) Types.Role);
ReasonTextEdit.Placeholder = new Rope.Leaf(Loc.GetString("ban-panel-reason"));
var prototypeManager = IoCManager.Resolve<IPrototypeManager>();
foreach (var proto in prototypeManager.EnumeratePrototypes<DepartmentPrototype>())
{
CreateRoleGroup(proto.ID, proto.Roles, proto.Color);
}
CreateRoleGroup("Antagonist", prototypeManager.EnumeratePrototypes<AntagPrototype>().Select(p => p.ID), Color.Red);
}
private void CreateRoleGroup(string roleName, IEnumerable<string> roleList, Color color)
{
var outerContainer = new BoxContainer
{
Name = $"{roleName}GroupOuterBox",
HorizontalExpand = true,
VerticalExpand = true,
Orientation = BoxContainer.LayoutOrientation.Vertical,
Margin = new Thickness(4)
};
var departmentCheckbox = new CheckBox
{
Name = $"{roleName}GroupCheckbox",
Text = roleName,
Modulate = color,
HorizontalAlignment = HAlignment.Left
};
outerContainer.AddChild(departmentCheckbox);
var innerContainer = new BoxContainer
{
Name = $"{roleName}GroupInnerBox",
HorizontalExpand = true,
Orientation = BoxContainer.LayoutOrientation.Horizontal
};
departmentCheckbox.OnToggled += args =>
{
foreach (var child in innerContainer.Children)
{
if (child is CheckBox c)
{
c.Pressed = args.Pressed;
}
}
};
outerContainer.AddChild(innerContainer);
foreach (var role in roleList)
{
AddRoleCheckbox(role, innerContainer, departmentCheckbox);
}
RolesContainer.AddChild(new PanelContainer
{
PanelOverride = new StyleBoxFlat
{
BackgroundColor = color
}
});
RolesContainer.AddChild(outerContainer);
RolesContainer.AddChild(new HSeparator());
}
private void AddRoleCheckbox(string role, Control container, CheckBox header)
{
var roleCheckbox = new CheckBox
{
Name = $"{role}RoleCheckbox",
Text = role
};
roleCheckbox.OnToggled += args =>
{
if (args is { Pressed: true, Button.Parent: { } } && args.Button.Parent.Children.Where(e => e is CheckBox).All(e => ((CheckBox) e).Pressed))
header.Pressed = args.Pressed;
else
header.Pressed = false;
};
container.AddChild(roleCheckbox);
_roleCheckboxes.Add(roleCheckbox);
}
public void UpdateBanFlag(bool newFlag)
@@ -349,12 +240,6 @@ public sealed partial class BanPanel : DefaultWindow
Hwid = Convert.FromHexString(hwidString);
}
private void OnTypeChanged()
{
TypeOption.ModulateSelfOverride = null;
Tabs.SetTabVisible((int) TabNumbers.Roles, TypeOption.SelectedId == (int) Types.Role);
}
private void UpdateSubmitEnabled()
{
SubmitButton.Disabled = ErrorLevel != ErrorLevelEnum.None;
@@ -390,31 +275,6 @@ public sealed partial class BanPanel : DefaultWindow
private void SubmitButtonOnOnPressed(BaseButton.ButtonEventArgs obj)
{
string[]? roles = null;
if (TypeOption.SelectedId == (int) Types.Role)
{
var rolesList = new List<string>();
if (_roleCheckboxes.Count == 0)
throw new DebugAssertException("RoleCheckboxes was empty");
rolesList.AddRange(_roleCheckboxes.Where(c => c is { Pressed: true, Text: { } }).Select(c => c.Text!));
if (rolesList.Count == 0)
{
Tabs.CurrentTab = (int) TabNumbers.Roles;
return;
}
roles = rolesList.ToArray();
}
if (TypeOption.SelectedId == (int) Types.None)
{
TypeOption.ModulateSelfOverride = Color.Red;
Tabs.CurrentTab = (int) TabNumbers.BasicInfo;
return;
}
var reason = Rope.Collapse(ReasonTextEdit.TextRope);
if (string.IsNullOrWhiteSpace(reason))
{
@@ -437,9 +297,10 @@ public sealed partial class BanPanel : DefaultWindow
var player = PlayerCheckbox.Pressed ? PlayerUsername : null;
var useLastIp = IpCheckbox.Pressed && LastConnCheckbox.Pressed && IpAddress is null;
var useLastHwid = HwidCheckbox.Pressed && LastConnCheckbox.Pressed && Hwid is null;
var severity = (NoteSeverity) SeverityOption.SelectedId;
var erase = EraseCheckbox.Pressed;
BanSubmitted?.Invoke(player, IpAddress, useLastIp, Hwid, useLastHwid, (uint) (TimeEntered * Multiplier), reason, severity, roles, erase);
var isGlobalBan = GlobalBanCheckbox.Pressed;
BanSubmitted?.Invoke(player, IpAddress, useLastIp, Hwid, useLastHwid, (uint) (TimeEntered * Multiplier), reason, NoteSeverity.Medium, erase, isGlobalBan);
}
protected override void FrameUpdate(FrameEventArgs args)

View File

@@ -14,8 +14,8 @@ public sealed class BanPanelEui : BaseEui
{
BanPanel = new BanPanel();
BanPanel.OnClose += () => SendMessage(new CloseEuiMessage());
BanPanel.BanSubmitted += (player, ip, useLastIp, hwid, useLastHwid, minutes, reason, severity, roles, erase)
=> SendMessage(new BanPanelEuiStateMsg.CreateBanRequest(player, ip, useLastIp, hwid, useLastHwid, minutes, reason, severity, roles, erase));
BanPanel.BanSubmitted += (player, ip, useLastIp, hwid, useLastHwid, minutes, reason, severity, erase, isGlobalBan)
=> SendMessage(new BanPanelEuiStateMsg.CreateBanRequest(player, ip, useLastIp, hwid, useLastHwid, minutes, reason, severity, erase, isGlobalBan));
BanPanel.PlayerChanged += player => SendMessage(new BanPanelEuiStateMsg.GetPlayerInfoRequest(player));
}

View File

@@ -131,6 +131,8 @@ namespace Content.Client.Administration.UI
var title = string.IsNullOrWhiteSpace(popup.TitleEdit.Text) ? null : popup.TitleEdit.Text;
var adminServer = string.IsNullOrWhiteSpace(popup.ServerNameEdit.Text) ? "unknown" : popup.ServerNameEdit.Text;
if (popup.SourceData is { } src)
{
SendMessage(new UpdateAdmin
@@ -139,7 +141,8 @@ namespace Content.Client.Administration.UI
Title = title,
PosFlags = pos,
NegFlags = neg,
RankId = rank
RankId = rank,
AdminServer = adminServer
});
}
else
@@ -152,7 +155,8 @@ namespace Content.Client.Administration.UI
Title = title,
PosFlags = pos,
NegFlags = neg,
RankId = rank
RankId = rank,
AdminServer = adminServer
});
}
@@ -251,6 +255,11 @@ namespace Content.Client.Administration.UI
HorizontalAlignment = Control.HAlignment.Center,
});
al.AddChild(new Label
{
Text = admin.AdminServer,
});
var editButton = new Button { Text = Loc.GetString("permissions-eui-edit-title-button") };
editButton.OnPressed += _ => OnEditPressed(admin);
al.AddChild(editButton);
@@ -351,6 +360,7 @@ namespace Content.Client.Administration.UI
public readonly OptionButton RankButton;
public readonly Button SaveButton;
public readonly Button? RemoveButton;
public readonly LineEdit ServerNameEdit;
public readonly Dictionary<AdminFlags, (Button inherit, Button sub, Button plus)> FlagButtons
= new();
@@ -380,6 +390,7 @@ namespace Content.Client.Administration.UI
TitleEdit = new LineEdit { PlaceHolder = Loc.GetString("permissions-eui-edit-admin-window-title-edit-placeholder") };
RankButton = new OptionButton();
SaveButton = new Button { Text = Loc.GetString("permissions-eui-edit-admin-window-save-button"), HorizontalAlignment = HAlignment.Right };
ServerNameEdit = new LineEdit { PlaceHolder = Loc.GetString("permissions-eui-edit-admin-window-server-edit-placeholder") };
RankButton.AddItem(Loc.GetString("permissions-eui-edit-admin-window-no-rank-button"), NoRank);
foreach (var (rId, rank) in ui._ranks)
@@ -496,6 +507,7 @@ namespace Content.Client.Administration.UI
{
nameControl,
TitleEdit,
ServerNameEdit,
RankButton
}
},

View File

@@ -0,0 +1,30 @@
<DefaultWindow
xmlns="https://spacestation14.io"
xmlns:cc="clr-namespace:Content.Client.Administration.UI.CustomControls"
Title="{Loc Ban}" MinSize="425 325">
<BoxContainer Orientation="Vertical">
<BoxContainer Orientation="Horizontal">
<Label Text="{Loc Player}" MinWidth="100" />
<Control MinWidth="50" />
<LineEdit Name="PlayerNameLine" MinWidth="100" HorizontalExpand="True" />
</BoxContainer>
<BoxContainer Orientation="Horizontal">
<Label Text="{Loc Reason}" MinSize="100 0" />
<Control MinSize="50 0" />
<LineEdit Name="ReasonLine" MinSize="100 0" HorizontalExpand="True" />
</BoxContainer>
<BoxContainer Orientation="Horizontal">
<Label Text="{Loc Minutes}" MinWidth="100" />
<Control MinWidth="50" />
<LineEdit Name="MinutesLine" MinWidth="100" HorizontalExpand="True" PlaceHolder="{Loc 0 minutes for a permanent ban}" />
<Button Name="HourButton" Text="+1h (0)"/>
<Button Name="DayButton" Text="+1d (0)"/>
<Button Name="WeekButton" Text="+1w (0)"/>
<Button Name="MonthButton" Text="+1M (0)"/>
</BoxContainer>
<CheckBox Name="GlobalBan" Text="Global Ban"/>
<cc:PlayerListControl Name="PlayerList" VerticalExpand="True" />
<Control MinWidth="50" />
<Button Name="SubmitButton" Text="{Loc Ban}" />
</BoxContainer>
</DefaultWindow>

View File

@@ -0,0 +1,84 @@
using Content.Shared.Administration;
using JetBrains.Annotations;
using Robust.Client.AutoGenerated;
using Robust.Client.Console;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.IoC;
using Robust.Shared.Utility;
using static Robust.Client.UserInterface.Controls.LineEdit;
namespace Content.Client.Administration.UI.Tabs.AdminTab
{
[GenerateTypedNameReferences]
[UsedImplicitly]
public sealed partial class BanWindow : DefaultWindow
{
public BanWindow()
{
RobustXamlLoader.Load(this);
PlayerNameLine.OnTextChanged += _ => OnPlayerNameChanged();
PlayerList.OnSelectionChanged += OnPlayerSelectionChanged;
SubmitButton.OnPressed += SubmitButtonOnOnPressed;
MinutesLine.OnTextChanged += UpdateButtonsText;
HourButton.OnPressed += _ => AddMinutes(60);
DayButton.OnPressed += _ => AddMinutes(1440);
WeekButton.OnPressed += _ => AddMinutes(10080);
MonthButton.OnPressed += _ => AddMinutes(43200);
}
private bool TryGetMinutes(string str, out uint minutes)
{
if(string.IsNullOrWhiteSpace(str))
{
minutes = 0;
return true;
}
return uint.TryParse(str, out minutes);
}
private void AddMinutes(uint add)
{
if (!TryGetMinutes(MinutesLine.Text, out var minutes))
return;
MinutesLine.Text = $"{minutes + add}";
UpdateButtons(minutes+add);
}
private void UpdateButtonsText(LineEditEventArgs obj)
{
if (!TryGetMinutes(obj.Text, out var minutes))
return;
UpdateButtons(minutes);
}
private void UpdateButtons(uint minutes)
{
HourButton.Text = $"+1h ({minutes / 60})";
DayButton.Text = $"+1d ({minutes / 1440})";
WeekButton.Text = $"+1w ({minutes / 10080})";
MonthButton.Text = $"+1M ({minutes / 43200})";
}
private void OnPlayerNameChanged()
{
SubmitButton.Disabled = string.IsNullOrEmpty(PlayerNameLine.Text);
}
public void OnPlayerSelectionChanged(PlayerInfo? player)
{
PlayerNameLine.Text = player?.Username ?? string.Empty;
OnPlayerNameChanged();
}
private void SubmitButtonOnOnPressed(BaseButton.ButtonEventArgs obj)
{
// Small verification if Player Name exists
IoCManager.Resolve<IClientConsoleHost>().ExecuteCommand(
$"ban \"{PlayerNameLine.Text}\" \"{CommandParsing.Escape(ReasonLine.Text)}\" \"{MinutesLine.Text}\" \"{GlobalBan.Pressed}\"");
}
}
}