diff --git a/Content.Server/Administration/Managers/BanManager.cs b/Content.Server/Administration/Managers/BanManager.cs index 18bc4bc122b85d..0eab61f3ffe839 100644 --- a/Content.Server/Administration/Managers/BanManager.cs +++ b/Content.Server/Administration/Managers/BanManager.cs @@ -169,6 +169,8 @@ public async void CreateServerBan(NetUserId? target, string? targetUsername, Net _sawmill.Info(logMessage); _chat.SendAdminAlert(logMessage); + _arumoonBans.RaiseLocalBanEvent(targetUsername ?? Loc.GetString("system-user"), expires, reason, severity, adminName); + // If we're not banning a player we don't care about disconnecting people if (target == null) return; @@ -179,8 +181,6 @@ public async void CreateServerBan(NetUserId? target, string? targetUsername, Net // If they are, kick them var message = banDef.FormatBanMessage(_cfg, _localizationManager); targetPlayer.ConnectedClient.Disconnect(message); - - _arumoonBans.RaiseLocalBanEvent(targetUsername ?? "null", expires, reason); } #endregion @@ -204,6 +204,9 @@ public async void CreateRoleBan(NetUserId? target, string? targetUsername, NetUs _systems.TryGetEntitySystem(out GameTicker? ticker); int? roundId = ticker == null || ticker.RoundId == 0 ? null : ticker.RoundId; var playtime = target == null ? TimeSpan.Zero : (await _db.GetPlayTimes(target.Value)).Find(p => p.Tracker == PlayTimeTrackingShared.TrackerOverall)?.TimeSpent ?? TimeSpan.Zero; + var adminName = banningAdmin == null + ? Loc.GetString("system-user") + : (await _db.GetPlayerRecordByUserId(banningAdmin.Value))?.LastSeenUserName ?? Loc.GetString("system-user"); var banDef = new ServerRoleBanDef( null, @@ -234,7 +237,7 @@ public async void CreateRoleBan(NetUserId? target, string? targetUsername, NetUs SendRoleBans(target.Value); } - _arumoonBans.RaiseLocalJobBanEvent(targetUsername ?? "null", expires, jobPrototype, reason); + _arumoonBans.RaiseLocalJobBanEvent(targetUsername ?? "null", expires, jobPrototype, reason, severity, adminName); } public HashSet? GetJobBans(NetUserId playerUserId) diff --git a/Content.Server/AruMoon/BansNotificationsSystem.cs b/Content.Server/AruMoon/BansNotificationsSystem.cs index 1bda0901e1c04b..ee539d4eda2fbe 100644 --- a/Content.Server/AruMoon/BansNotificationsSystem.cs +++ b/Content.Server/AruMoon/BansNotificationsSystem.cs @@ -1,4 +1,5 @@ using Content.Shared.CCVar; +using Content.Shared.Database; using Content.Shared.GameTicking; using Content.Shared.Roles; using Robust.Shared.Configuration; @@ -16,10 +17,9 @@ namespace Content.Server.Arumoon.BansNotifications /// public interface IBansNotificationsSystem { - void RaiseLocalBanEvent(string username, DateTimeOffset? expires, string reason); - - void RaiseLocalJobBanEvent(string username, DateTimeOffset? expires, JobPrototype job, string reason); - void RaiseLocalDepartmentBanEvent(string username, DateTimeOffset? expires, DepartmentPrototype department, string reason); + void RaiseLocalBanEvent(string username, DateTimeOffset? expires, string reason, NoteSeverity severity, string adminusername); + void RaiseLocalJobBanEvent(string username, DateTimeOffset? expires, JobPrototype job, string reason, NoteSeverity severity, string adminusername); + void RaiseLocalDepartmentBanEvent(string username, DateTimeOffset? expires, DepartmentPrototype department, string reason, NoteSeverity severity, string adminusername); } public sealed class BansNotificationsSystem : EntitySystem, IBansNotificationsSystem @@ -37,19 +37,19 @@ public override void Initialize() _config.OnValueChanged(CCVars.DiscordBanWebhook, value => _webhookUrl = value, true); } - public void RaiseLocalBanEvent(string username, DateTimeOffset? expires, string reason) + public void RaiseLocalBanEvent(string username, DateTimeOffset? expires, string reason, NoteSeverity severity, string adminusername) { - RaiseLocalEvent(new BanEvent(username, expires, reason)); + RaiseLocalEvent(new BanEvent(username, expires, reason, severity, adminusername)); } - public void RaiseLocalJobBanEvent(string username, DateTimeOffset? expires, JobPrototype job, string reason) + public void RaiseLocalJobBanEvent(string username, DateTimeOffset? expires, JobPrototype job, string reason, NoteSeverity severity, string adminusername) { - RaiseLocalEvent(new JobBanEvent(username, expires, job, reason)); + RaiseLocalEvent(new JobBanEvent(username, expires, job, reason, severity, adminusername)); } - public void RaiseLocalDepartmentBanEvent(string username, DateTimeOffset? expires, DepartmentPrototype department, string reason) + public void RaiseLocalDepartmentBanEvent(string username, DateTimeOffset? expires, DepartmentPrototype department, string reason, NoteSeverity severity, string adminusername) { - RaiseLocalEvent(new DepartmentBanEvent(username, expires, department, reason)); + RaiseLocalEvent(new DepartmentBanEvent(username, expires, department, reason, severity, adminusername)); } private async void SendDiscordMessage(WebhookPayload payload) @@ -70,14 +70,43 @@ public void OnBan(BanEvent e) if (String.IsNullOrEmpty(_webhookUrl)) return; - var payload = new WebhookPayload(); var expires = e.Expires == null ? Loc.GetString("discord-permanent") : Loc.GetString("discord-expires-at", ("date", e.Expires)); - var text = Loc.GetString("discord-ban-msg", + var message = Loc.GetString("discord-ban-msg", ("username", e.Username), ("expires", expires), ("reason", e.Reason)); - payload.Content = text; + var color = e.Severity switch + { + NoteSeverity.None => 0x6aa84f, + NoteSeverity.Minor => 0x45818e, + NoteSeverity.Medium => 0xf1c232, + NoteSeverity.High => 0xff0000, + _ => 0xff0000, + }; + + var payload = new WebhookPayload + { + /* + Username = username, + AvatarUrl = string.IsNullOrWhiteSpace(_avatarUrl) ? null : _avatarUrl, + */ + Embeds = new List + { + new() + { + Description = message, + Color = color, + Footer = new EmbedFooter + { + Text = $"{e.AdminUsername}", + /* + IconUrl = string.IsNullOrWhiteSpace(_footerIconUrl) ? null : _footerIconUrl + */ + }, + }, + }, + }; SendDiscordMessage(payload); } @@ -87,15 +116,46 @@ public void OnJobBan(JobBanEvent e) if (String.IsNullOrEmpty(_webhookUrl)) return; - var payload = new WebhookPayload(); var expires = e.Expires == null ? Loc.GetString("discord-permanent") : Loc.GetString("discord-expires-at", ("date", e.Expires)); - var text = Loc.GetString("discord-jobban-msg", + var message = Loc.GetString("discord-jobban-msg", ("username", e.Username), ("role", e.Job.LocalizedName), ("expires", expires), ("reason", e.Reason)); - payload.Content = text; + + var color = e.Severity switch + { + NoteSeverity.None => 0x6aa84f, + NoteSeverity.Minor => 0x45818e, + NoteSeverity.Medium => 0xf1c232, + NoteSeverity.High => 0xff0000, + _ => 0xff0000, + }; + + var payload = new WebhookPayload + { + /* + Username = username, + AvatarUrl = string.IsNullOrWhiteSpace(_avatarUrl) ? null : _avatarUrl, + */ + Embeds = new List + { + new() + { + Description = message, + Color = color, + Footer = new EmbedFooter + { + Text = $"{e.AdminUsername}", + /* + IconUrl = string.IsNullOrWhiteSpace(_footerIconUrl) ? null : _footerIconUrl + */ + }, + }, + }, + }; + SendDiscordMessage(payload); } @@ -103,7 +163,7 @@ public void OnDepartmentBan(DepartmentBanEvent e) { if (String.IsNullOrEmpty(_webhookUrl)) return; - +/* var payload = new WebhookPayload(); var departamentLocName = Loc.GetString(string.Concat("department-", e.Department.ID)); var expires = e.Expires == null ? Loc.GetString("discord-permanent") : Loc.GetString("discord-expires-at", ("date", e.Expires)); @@ -115,8 +175,10 @@ public void OnDepartmentBan(DepartmentBanEvent e) payload.Content = text; SendDiscordMessage(payload); +*/ } +/* private struct WebhookPayload { [JsonPropertyName("content")] @@ -130,5 +192,73 @@ private struct WebhookPayload public WebhookPayload() {} } +*/ + private struct WebhookPayload + { + [JsonPropertyName("username")] + public string Username { get; set; } = ""; + + [JsonPropertyName("avatar_url")] + public string? AvatarUrl { get; set; } = ""; + + [JsonPropertyName("embeds")] + public List? Embeds { get; set; } = null; + + [JsonPropertyName("allowed_mentions")] + public Dictionary AllowedMentions { get; set; } = + new() + { + { "parse", Array.Empty() }, + }; + + public WebhookPayload() + { + } + } + + // https://discord.com/developers/docs/resources/channel#embed-object-embed-structure + private struct Embed + { + [JsonPropertyName("description")] + public string Description { get; set; } = ""; + + [JsonPropertyName("color")] + public int Color { get; set; } = 0; + + [JsonPropertyName("footer")] + public EmbedFooter? Footer { get; set; } = null; + + public Embed() + { + } + } + + // https://discord.com/developers/docs/resources/channel#embed-object-embed-footer-structure + private struct EmbedFooter + { + [JsonPropertyName("text")] + public string Text { get; set; } = ""; + + [JsonPropertyName("icon_url")] + public string? IconUrl { get; set; } + + public EmbedFooter() + { + } + } + + // https://discord.com/developers/docs/resources/webhook#webhook-object-webhook-structure + private struct WebhookData + { + [JsonPropertyName("guild_id")] + public string? GuildId { get; set; } = null; + + [JsonPropertyName("channel_id")] + public string? ChannelId { get; set; } = null; + + public WebhookData() + { + } + } } } diff --git a/Content.Server/GameTicking/Events/BanEvent.cs b/Content.Server/GameTicking/Events/BanEvent.cs index 4d549e658d5c6f..ade696fed1f574 100644 --- a/Content.Server/GameTicking/Events/BanEvent.cs +++ b/Content.Server/GameTicking/Events/BanEvent.cs @@ -1,3 +1,5 @@ +using Content.Shared.Database; + namespace Content.Shared.GameTicking; public sealed class BanEvent : EntityEventArgs @@ -5,12 +7,15 @@ public sealed class BanEvent : EntityEventArgs public string Username { get; } public DateTimeOffset? Expires { get; } public string Reason { get; } + public NoteSeverity Severity { get; } + public string AdminUsername { get; } - - public BanEvent(string username, DateTimeOffset? expires, string reason) + public BanEvent(string username, DateTimeOffset? expires, string reason, NoteSeverity severity, string adminusername) { Username = username; Expires = expires; Reason = reason; + Severity = severity; + AdminUsername = adminusername; } } diff --git a/Content.Server/GameTicking/Events/DepartmentBanEvent.cs b/Content.Server/GameTicking/Events/DepartmentBanEvent.cs index 1964d3facd006b..d3e396ec75aa40 100644 --- a/Content.Server/GameTicking/Events/DepartmentBanEvent.cs +++ b/Content.Server/GameTicking/Events/DepartmentBanEvent.cs @@ -1,3 +1,4 @@ +using Content.Shared.Database; using Content.Shared.Roles; namespace Content.Shared.GameTicking; @@ -8,13 +9,17 @@ public sealed class DepartmentBanEvent : EntityEventArgs public DepartmentPrototype Department { get; } public DateTimeOffset? Expires { get; } public string Reason { get; } + public NoteSeverity Severity { get; } + public string AdminUsername { get; } - public DepartmentBanEvent(string username, DateTimeOffset? expires, DepartmentPrototype department, string reason) + public DepartmentBanEvent(string username, DateTimeOffset? expires, DepartmentPrototype department, string reason, NoteSeverity severity, string adminusername) { Username = username; Department = department; Expires = expires; Reason = reason; + Severity = severity; + AdminUsername = adminusername; } } diff --git a/Content.Server/GameTicking/Events/JobBanEvent.cs b/Content.Server/GameTicking/Events/JobBanEvent.cs index b6e970d8791115..9ce2d6cd3d8a19 100644 --- a/Content.Server/GameTicking/Events/JobBanEvent.cs +++ b/Content.Server/GameTicking/Events/JobBanEvent.cs @@ -1,3 +1,4 @@ +using Content.Shared.Database; using Content.Shared.Roles; namespace Content.Shared.GameTicking; @@ -8,13 +9,16 @@ public sealed class JobBanEvent : EntityEventArgs public JobPrototype Job { get; } public DateTimeOffset? Expires { get; } public string Reason { get; } + public NoteSeverity Severity { get; } + public string AdminUsername { get; } - - public JobBanEvent(string username, DateTimeOffset? expires, JobPrototype job, string reason) + public JobBanEvent(string username, DateTimeOffset? expires, JobPrototype job, string reason, NoteSeverity severity, string adminusername) { Username = username; Job = job; Expires = expires; Reason = reason; + Severity = severity; + AdminUsername = adminusername; } }