diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 4545f2b..57eea90 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -15,6 +15,10 @@ updates: labels: - "type: change" - "area: build/ci" + # For all packages, ignore all patch updates + ignore: + - dependency-name: "*" + update-types: [ "version-update:semver-patch" ] - package-ecosystem: "nuget" # See documentation for possible values directory: "/" # Location of package manifests @@ -30,3 +34,7 @@ updates: remora: patterns: - "Remora.Discord.*" + # For all packages, ignore all patch updates + ignore: + - dependency-name: "*" + update-types: [ "version-update:semver-patch" ] diff --git a/.github/workflows/build-pr.yml b/.github/workflows/build-pr.yml index 859f8fa..c92386e 100644 --- a/.github/workflows/build-pr.yml +++ b/.github/workflows/build-pr.yml @@ -23,7 +23,7 @@ jobs: uses: actions/checkout@v4 - name: ReSharper CLI InspectCode - uses: muno92/resharper_inspectcode@1.11.8 + uses: muno92/resharper_inspectcode@1.11.10 with: solutionPath: ./Octobot.sln ignoreIssueType: InvertIf, ConvertIfStatementToSwitchStatement, ConvertToPrimaryConstructor diff --git a/Octobot.sln b/Octobot.sln index 9dd2b89..b82f7a9 100644 --- a/Octobot.sln +++ b/Octobot.sln @@ -1,6 +1,6 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Octobot", "Octobot.csproj", "{9CA7A44F-167C-46D4-923D-88CE71044144}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TeamOctolings.Octobot", "TeamOctolings.Octobot\TeamOctolings.Octobot.csproj", "{A1679BA2-3A36-4D98-80C0-EEE771398FBD}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -8,9 +8,9 @@ Global Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {9CA7A44F-167C-46D4-923D-88CE71044144}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {9CA7A44F-167C-46D4-923D-88CE71044144}.Debug|Any CPU.Build.0 = Debug|Any CPU - {9CA7A44F-167C-46D4-923D-88CE71044144}.Release|Any CPU.ActiveCfg = Release|Any CPU - {9CA7A44F-167C-46D4-923D-88CE71044144}.Release|Any CPU.Build.0 = Release|Any CPU + {A1679BA2-3A36-4D98-80C0-EEE771398FBD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A1679BA2-3A36-4D98-80C0-EEE771398FBD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A1679BA2-3A36-4D98-80C0-EEE771398FBD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A1679BA2-3A36-4D98-80C0-EEE771398FBD}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection EndGlobal diff --git a/src/Attributes/StaticCallersOnlyAttribute.cs b/TeamOctolings.Octobot/Attributes/StaticCallersOnlyAttribute.cs similarity index 88% rename from src/Attributes/StaticCallersOnlyAttribute.cs rename to TeamOctolings.Octobot/Attributes/StaticCallersOnlyAttribute.cs index e8787bf..0256f62 100644 --- a/src/Attributes/StaticCallersOnlyAttribute.cs +++ b/TeamOctolings.Octobot/Attributes/StaticCallersOnlyAttribute.cs @@ -1,4 +1,4 @@ -namespace Octobot.Attributes; +namespace TeamOctolings.Octobot.Attributes; /// /// Any property marked with should only be accessed by static methods. diff --git a/src/BuildInfo.cs b/TeamOctolings.Octobot/BuildInfo.cs similarity index 93% rename from src/BuildInfo.cs rename to TeamOctolings.Octobot/BuildInfo.cs index 2eb6059..4b9a09f 100644 --- a/src/BuildInfo.cs +++ b/TeamOctolings.Octobot/BuildInfo.cs @@ -1,4 +1,4 @@ -namespace Octobot; +namespace TeamOctolings.Octobot; public static class BuildInfo { diff --git a/src/ColorsList.cs b/TeamOctolings.Octobot/ColorsList.cs similarity index 95% rename from src/ColorsList.cs rename to TeamOctolings.Octobot/ColorsList.cs index cd40313..3b66c0a 100644 --- a/src/ColorsList.cs +++ b/TeamOctolings.Octobot/ColorsList.cs @@ -1,6 +1,6 @@ using System.Drawing; -namespace Octobot; +namespace TeamOctolings.Octobot; /// /// Contains all colors used in embeds. diff --git a/src/Commands/AboutCommandGroup.cs b/TeamOctolings.Octobot/Commands/AboutCommandGroup.cs similarity index 95% rename from src/Commands/AboutCommandGroup.cs rename to TeamOctolings.Octobot/Commands/AboutCommandGroup.cs index 02384f8..dbb8b12 100644 --- a/src/Commands/AboutCommandGroup.cs +++ b/TeamOctolings.Octobot/Commands/AboutCommandGroup.cs @@ -1,9 +1,6 @@ using System.ComponentModel; using System.Text; using JetBrains.Annotations; -using Octobot.Data; -using Octobot.Extensions; -using Octobot.Services; using Remora.Commands.Attributes; using Remora.Commands.Groups; using Remora.Discord.API.Abstractions.Objects; @@ -18,14 +15,17 @@ using Remora.Discord.Extensions.Embeds; using Remora.Discord.Extensions.Formatting; using Remora.Rest.Core; using Remora.Results; +using TeamOctolings.Octobot.Data; +using TeamOctolings.Octobot.Extensions; +using TeamOctolings.Octobot.Services; -namespace Octobot.Commands; +namespace TeamOctolings.Octobot.Commands; /// /// Handles the command to show information about this bot: /about. /// [UsedImplicitly] -public class AboutCommandGroup : CommandGroup +public sealed class AboutCommandGroup : CommandGroup { private static readonly (string Username, Snowflake Id)[] Developers = [ @@ -36,9 +36,9 @@ public class AboutCommandGroup : CommandGroup private readonly ICommandContext _context; private readonly IFeedbackService _feedback; + private readonly IDiscordRestGuildAPI _guildApi; private readonly GuildDataService _guildData; private readonly IDiscordRestUserAPI _userApi; - private readonly IDiscordRestGuildAPI _guildApi; public AboutCommandGroup( ICommandContext context, GuildDataService guildData, diff --git a/src/Commands/BanCommandGroup.cs b/TeamOctolings.Octobot/Commands/BanCommandGroup.cs similarity index 97% rename from src/Commands/BanCommandGroup.cs rename to TeamOctolings.Octobot/Commands/BanCommandGroup.cs index 7cfdc85..db3a8ce 100644 --- a/src/Commands/BanCommandGroup.cs +++ b/TeamOctolings.Octobot/Commands/BanCommandGroup.cs @@ -2,11 +2,6 @@ using System.ComponentModel; using System.ComponentModel.DataAnnotations; using System.Text; using JetBrains.Annotations; -using Octobot.Data; -using Octobot.Extensions; -using Octobot.Parsers; -using Octobot.Services; -using Octobot.Services.Update; using Remora.Commands.Attributes; using Remora.Commands.Groups; using Remora.Discord.API.Abstractions.Objects; @@ -19,14 +14,19 @@ using Remora.Discord.Extensions.Embeds; using Remora.Discord.Extensions.Formatting; using Remora.Rest.Core; using Remora.Results; +using TeamOctolings.Octobot.Data; +using TeamOctolings.Octobot.Extensions; +using TeamOctolings.Octobot.Parsers; +using TeamOctolings.Octobot.Services; +using TeamOctolings.Octobot.Services.Update; -namespace Octobot.Commands; +namespace TeamOctolings.Octobot.Commands; /// /// Handles commands related to ban management: /ban and /unban. /// [UsedImplicitly] -public class BanCommandGroup : CommandGroup +public sealed class BanCommandGroup : CommandGroup { private readonly AccessControlService _access; private readonly IDiscordRestChannelAPI _channelApi; diff --git a/src/Commands/ClearCommandGroup.cs b/TeamOctolings.Octobot/Commands/ClearCommandGroup.cs similarity index 95% rename from src/Commands/ClearCommandGroup.cs rename to TeamOctolings.Octobot/Commands/ClearCommandGroup.cs index 84b69db..7c1b516 100644 --- a/src/Commands/ClearCommandGroup.cs +++ b/TeamOctolings.Octobot/Commands/ClearCommandGroup.cs @@ -1,9 +1,6 @@ using System.ComponentModel; using System.Text; using JetBrains.Annotations; -using Octobot.Data; -using Octobot.Extensions; -using Octobot.Services; using Remora.Commands.Attributes; using Remora.Commands.Groups; using Remora.Discord.API.Abstractions.Objects; @@ -16,14 +13,17 @@ using Remora.Discord.Extensions.Embeds; using Remora.Discord.Extensions.Formatting; using Remora.Rest.Core; using Remora.Results; +using TeamOctolings.Octobot.Data; +using TeamOctolings.Octobot.Extensions; +using TeamOctolings.Octobot.Services; -namespace Octobot.Commands; +namespace TeamOctolings.Octobot.Commands; /// /// Handles the command to clear messages in a channel: /clear. /// [UsedImplicitly] -public class ClearCommandGroup : CommandGroup +public sealed class ClearCommandGroup : CommandGroup { private readonly IDiscordRestChannelAPI _channelApi; private readonly ICommandContext _context; @@ -64,6 +64,7 @@ public class ClearCommandGroup : CommandGroup public async Task ExecuteClear( [Description("Number of messages to remove (2-100)")] [MinValue(2)] [MaxValue(100)] int amount, + [Description("Ignore messages except from the specified author")] IUser? author = null) { if (!_context.TryGetContextIDs(out var guildId, out var channelId, out var executorId)) diff --git a/src/Commands/Events/ErrorLoggingPostExecutionEvent.cs b/TeamOctolings.Octobot/Commands/Events/ErrorLoggingPostExecutionEvent.cs similarity index 94% rename from src/Commands/Events/ErrorLoggingPostExecutionEvent.cs rename to TeamOctolings.Octobot/Commands/Events/ErrorLoggingPostExecutionEvent.cs index 551c2d0..7409d3b 100644 --- a/src/Commands/Events/ErrorLoggingPostExecutionEvent.cs +++ b/TeamOctolings.Octobot/Commands/Events/ErrorLoggingPostExecutionEvent.cs @@ -1,6 +1,5 @@ using JetBrains.Annotations; using Microsoft.Extensions.Logging; -using Octobot.Extensions; using Remora.Discord.API.Abstractions.Objects; using Remora.Discord.API.Abstractions.Rest; using Remora.Discord.API.Objects; @@ -11,14 +10,15 @@ using Remora.Discord.Commands.Services; using Remora.Discord.Extensions.Embeds; using Remora.Discord.Extensions.Formatting; using Remora.Results; +using TeamOctolings.Octobot.Extensions; -namespace Octobot.Commands.Events; +namespace TeamOctolings.Octobot.Commands.Events; /// /// Handles error logging for slash command groups. /// [UsedImplicitly] -public class ErrorLoggingPostExecutionEvent : IPostExecutionEvent +public sealed class ErrorLoggingPostExecutionEvent : IPostExecutionEvent { private readonly IFeedbackService _feedback; private readonly ILogger _logger; diff --git a/src/Commands/Events/LoggingPreparationErrorEvent.cs b/TeamOctolings.Octobot/Commands/Events/LoggingPreparationErrorEvent.cs similarity index 88% rename from src/Commands/Events/LoggingPreparationErrorEvent.cs rename to TeamOctolings.Octobot/Commands/Events/LoggingPreparationErrorEvent.cs index 87b4090..9e69a7f 100644 --- a/src/Commands/Events/LoggingPreparationErrorEvent.cs +++ b/TeamOctolings.Octobot/Commands/Events/LoggingPreparationErrorEvent.cs @@ -1,17 +1,17 @@ using JetBrains.Annotations; using Microsoft.Extensions.Logging; -using Octobot.Extensions; using Remora.Discord.Commands.Contexts; using Remora.Discord.Commands.Services; using Remora.Results; +using TeamOctolings.Octobot.Extensions; -namespace Octobot.Commands.Events; +namespace TeamOctolings.Octobot.Commands.Events; /// /// Handles error logging for slash commands that couldn't be successfully prepared. /// [UsedImplicitly] -public class LoggingPreparationErrorEvent : IPreparationErrorEvent +public sealed class LoggingPreparationErrorEvent : IPreparationErrorEvent { private readonly ILogger _logger; diff --git a/src/Commands/ToolsCommandGroup.cs b/TeamOctolings.Octobot/Commands/InfoCommandGroup.cs similarity index 56% rename from src/Commands/ToolsCommandGroup.cs rename to TeamOctolings.Octobot/Commands/InfoCommandGroup.cs index d4f3f75..d7798f3 100644 --- a/src/Commands/ToolsCommandGroup.cs +++ b/TeamOctolings.Octobot/Commands/InfoCommandGroup.cs @@ -2,10 +2,6 @@ using System.ComponentModel; using System.Drawing; using System.Text; using JetBrains.Annotations; -using Octobot.Data; -using Octobot.Extensions; -using Octobot.Parsers; -using Octobot.Services; using Remora.Commands.Attributes; using Remora.Commands.Groups; using Remora.Discord.API.Abstractions.Objects; @@ -17,14 +13,17 @@ using Remora.Discord.Extensions.Embeds; using Remora.Discord.Extensions.Formatting; using Remora.Rest.Core; using Remora.Results; +using TeamOctolings.Octobot.Data; +using TeamOctolings.Octobot.Extensions; +using TeamOctolings.Octobot.Services; -namespace Octobot.Commands; +namespace TeamOctolings.Octobot.Commands; /// -/// Handles tool commands: /userinfo, /guildinfo, /random, /timestamp, /8ball. +/// Handles info commands: /userinfo, /guildinfo. /// [UsedImplicitly] -public class ToolsCommandGroup : CommandGroup +public sealed class InfoCommandGroup : CommandGroup { private readonly ICommandContext _context; private readonly IFeedbackService _feedback; @@ -32,7 +31,7 @@ public class ToolsCommandGroup : CommandGroup private readonly GuildDataService _guildData; private readonly IDiscordRestUserAPI _userApi; - public ToolsCommandGroup( + public InfoCommandGroup( ICommandContext context, IFeedbackService feedback, GuildDataService guildData, IDiscordRestGuildAPI guildApi, IDiscordRestUserAPI userApi) @@ -327,235 +326,4 @@ public class ToolsCommandGroup : CommandGroup return _feedback.SendContextualEmbedResultAsync(embed, ct: ct); } - - /// - /// A slash command that generates a random number using maximum and minimum numbers. - /// - /// The first number used for randomization. - /// The second number used for randomization. Default value: 0 - /// - /// A feedback sending result which may or may not have succeeded. - /// - [Command("random")] - [DiscordDefaultDMPermission(false)] - [Description("Generates a random number")] - [UsedImplicitly] - public async Task ExecuteRandomAsync( - [Description("First number")] long first, - [Description("Second number (Default: 0)")] - long? second = null) - { - if (!_context.TryGetContextIDs(out var guildId, out _, out var executorId)) - { - return new ArgumentInvalidError(nameof(_context), "Unable to retrieve necessary IDs from command context"); - } - - var executorResult = await _userApi.GetUserAsync(executorId, CancellationToken); - if (!executorResult.IsDefined(out var executor)) - { - return ResultExtensions.FromError(executorResult); - } - - var data = await _guildData.GetData(guildId, CancellationToken); - Messages.Culture = GuildSettings.Language.Get(data.Settings); - - return await SendRandomNumberAsync(first, second, executor, CancellationToken); - } - - private Task SendRandomNumberAsync(long first, long? secondNullable, - IUser executor, CancellationToken ct) - { - const long secondDefault = 0; - var second = secondNullable ?? secondDefault; - - var min = Math.Min(first, second); - var max = Math.Max(first, second); - - var i = Random.Shared.NextInt64(min, max + 1); - - var description = new StringBuilder().Append("# ").Append(i); - - description.AppendLine().AppendBulletPoint(string.Format( - Messages.RandomMin, Markdown.InlineCode(min.ToString()))); - if (secondNullable is null && first >= secondDefault) - { - description.Append(' ').Append(Messages.Default); - } - - description.AppendLine().AppendBulletPoint(string.Format( - Messages.RandomMax, Markdown.InlineCode(max.ToString()))); - if (secondNullable is null && first < secondDefault) - { - description.Append(' ').Append(Messages.Default); - } - - var embedColor = ColorsList.Blue; - if (secondNullable is not null && min == max) - { - description.AppendLine().Append(Markdown.Italicise(Messages.RandomMinMaxSame)); - embedColor = ColorsList.Red; - } - - var embed = new EmbedBuilder().WithSmallTitle( - string.Format(Messages.RandomTitle, executor.GetTag()), executor) - .WithDescription(description.ToString()) - .WithColour(embedColor) - .Build(); - - return _feedback.SendContextualEmbedResultAsync(embed, ct: ct); - } - - private static readonly TimestampStyle[] AllStyles = - [ - TimestampStyle.ShortDate, - TimestampStyle.LongDate, - TimestampStyle.ShortTime, - TimestampStyle.LongTime, - TimestampStyle.ShortDateTime, - TimestampStyle.LongDateTime, - TimestampStyle.RelativeTime - ]; - - /// - /// A slash command that shows the current timestamp with an optional offset in all styles supported by Discord. - /// - /// The offset for the current timestamp. - /// - /// A feedback sending result which may or may not have succeeded. - /// - [Command("timestamp")] - [DiscordDefaultDMPermission(false)] - [Description("Shows a timestamp in all styles")] - [UsedImplicitly] - public async Task ExecuteTimestampAsync( - [Description("Offset from current time")] [Option("offset")] - string? stringOffset = null) - { - if (!_context.TryGetContextIDs(out var guildId, out _, out var executorId)) - { - return new ArgumentInvalidError(nameof(_context), "Unable to retrieve necessary IDs from command context"); - } - - var botResult = await _userApi.GetCurrentUserAsync(CancellationToken); - if (!botResult.IsDefined(out var bot)) - { - return ResultExtensions.FromError(botResult); - } - - var executorResult = await _userApi.GetUserAsync(executorId, CancellationToken); - if (!executorResult.IsDefined(out var executor)) - { - return ResultExtensions.FromError(executorResult); - } - - var data = await _guildData.GetData(guildId, CancellationToken); - Messages.Culture = GuildSettings.Language.Get(data.Settings); - - if (stringOffset is null) - { - return await SendTimestampAsync(null, executor, CancellationToken); - } - - var parseResult = TimeSpanParser.TryParse(stringOffset); - if (!parseResult.IsDefined(out var offset)) - { - var failedEmbed = new EmbedBuilder() - .WithSmallTitle(Messages.InvalidTimeSpan, bot) - .WithDescription(Messages.TimeSpanExample) - .WithColour(ColorsList.Red) - .Build(); - - return await _feedback.SendContextualEmbedResultAsync(failedEmbed, ct: CancellationToken); - } - - return await SendTimestampAsync(offset, executor, CancellationToken); - } - - private Task SendTimestampAsync(TimeSpan? offset, IUser executor, CancellationToken ct) - { - var timestamp = DateTimeOffset.UtcNow.Add(offset ?? TimeSpan.Zero).ToUnixTimeSeconds(); - - var description = new StringBuilder().Append("# ").AppendLine(timestamp.ToString()); - - if (offset is not null) - { - description.AppendLine(string.Format( - Messages.TimestampOffset, Markdown.InlineCode(offset.ToString() ?? string.Empty))).AppendLine(); - } - - foreach (var markdownTimestamp in AllStyles.Select(style => Markdown.Timestamp(timestamp, style))) - { - description.AppendBulletPoint(Markdown.InlineCode(markdownTimestamp)) - .Append(" → ").AppendLine(markdownTimestamp); - } - - var embed = new EmbedBuilder().WithSmallTitle( - string.Format(Messages.TimestampTitle, executor.GetTag()), executor) - .WithDescription(description.ToString()) - .WithColour(ColorsList.Blue) - .Build(); - - return _feedback.SendContextualEmbedResultAsync(embed, ct: ct); - } - - /// - /// A slash command that shows a random answer from the Magic 8-Ball. - /// - /// Unused input. - /// - /// The 8-Ball answers were taken from Wikipedia. - /// - /// - /// A feedback sending result which may or may not have succeeded. - /// - [Command("8ball")] - [DiscordDefaultDMPermission(false)] - [Description("Ask the Magic 8-Ball a question")] - [UsedImplicitly] - public async Task ExecuteEightBallAsync( - // let the user think he's actually asking the ball a question - [Description("Question to ask")] string question) - { - if (!_context.TryGetContextIDs(out var guildId, out _, out _)) - { - return new ArgumentInvalidError(nameof(_context), "Unable to retrieve necessary IDs from command context"); - } - - var botResult = await _userApi.GetCurrentUserAsync(CancellationToken); - if (!botResult.IsDefined(out var bot)) - { - return ResultExtensions.FromError(botResult); - } - - var data = await _guildData.GetData(guildId, CancellationToken); - Messages.Culture = GuildSettings.Language.Get(data.Settings); - - return await AnswerEightBallAsync(bot, CancellationToken); - } - - private static readonly string[] AnswerTypes = - [ - "Positive", "Questionable", "Neutral", "Negative" - ]; - - private Task AnswerEightBallAsync(IUser bot, CancellationToken ct) - { - var typeNumber = Random.Shared.Next(0, 4); - var embedColor = typeNumber switch - { - 0 => ColorsList.Blue, - 1 => ColorsList.Green, - 2 => ColorsList.Yellow, - 3 => ColorsList.Red, - _ => throw new ArgumentOutOfRangeException(null, nameof(typeNumber)) - }; - - var answer = $"EightBall{AnswerTypes[typeNumber]}{Random.Shared.Next(1, 6)}".Localized(); - - var embed = new EmbedBuilder().WithSmallTitle(answer, bot) - .WithColour(embedColor) - .Build(); - - return _feedback.SendContextualEmbedResultAsync(embed, ct: ct); - } } diff --git a/src/Commands/KickCommandGroup.cs b/TeamOctolings.Octobot/Commands/KickCommandGroup.cs similarity index 97% rename from src/Commands/KickCommandGroup.cs rename to TeamOctolings.Octobot/Commands/KickCommandGroup.cs index b1c1aa5..ccbe2a1 100644 --- a/src/Commands/KickCommandGroup.cs +++ b/TeamOctolings.Octobot/Commands/KickCommandGroup.cs @@ -1,9 +1,6 @@ using System.ComponentModel; using System.ComponentModel.DataAnnotations; using JetBrains.Annotations; -using Octobot.Data; -using Octobot.Extensions; -using Octobot.Services; using Remora.Commands.Attributes; using Remora.Commands.Groups; using Remora.Discord.API.Abstractions.Objects; @@ -15,14 +12,17 @@ using Remora.Discord.Commands.Feedback.Services; using Remora.Discord.Extensions.Embeds; using Remora.Rest.Core; using Remora.Results; +using TeamOctolings.Octobot.Data; +using TeamOctolings.Octobot.Extensions; +using TeamOctolings.Octobot.Services; -namespace Octobot.Commands; +namespace TeamOctolings.Octobot.Commands; /// /// Handles the command to kick members of a guild: /kick. /// [UsedImplicitly] -public class KickCommandGroup : CommandGroup +public sealed class KickCommandGroup : CommandGroup { private readonly AccessControlService _access; private readonly IDiscordRestChannelAPI _channelApi; diff --git a/src/Commands/MuteCommandGroup.cs b/TeamOctolings.Octobot/Commands/MuteCommandGroup.cs similarity index 98% rename from src/Commands/MuteCommandGroup.cs rename to TeamOctolings.Octobot/Commands/MuteCommandGroup.cs index d26bc6c..5b5dff0 100644 --- a/src/Commands/MuteCommandGroup.cs +++ b/TeamOctolings.Octobot/Commands/MuteCommandGroup.cs @@ -2,11 +2,6 @@ using System.ComponentModel; using System.ComponentModel.DataAnnotations; using System.Text; using JetBrains.Annotations; -using Octobot.Data; -using Octobot.Extensions; -using Octobot.Parsers; -using Octobot.Services; -using Octobot.Services.Update; using Remora.Commands.Attributes; using Remora.Commands.Groups; using Remora.Discord.API.Abstractions.Objects; @@ -19,14 +14,19 @@ using Remora.Discord.Extensions.Embeds; using Remora.Discord.Extensions.Formatting; using Remora.Rest.Core; using Remora.Results; +using TeamOctolings.Octobot.Data; +using TeamOctolings.Octobot.Extensions; +using TeamOctolings.Octobot.Parsers; +using TeamOctolings.Octobot.Services; +using TeamOctolings.Octobot.Services.Update; -namespace Octobot.Commands; +namespace TeamOctolings.Octobot.Commands; /// /// Handles commands related to mute management: /mute and /unmute. /// [UsedImplicitly] -public class MuteCommandGroup : CommandGroup +public sealed class MuteCommandGroup : CommandGroup { private readonly AccessControlService _access; private readonly ICommandContext _context; diff --git a/src/Commands/PingCommandGroup.cs b/TeamOctolings.Octobot/Commands/PingCommandGroup.cs similarity index 94% rename from src/Commands/PingCommandGroup.cs rename to TeamOctolings.Octobot/Commands/PingCommandGroup.cs index d64c6dd..01a1ee2 100644 --- a/src/Commands/PingCommandGroup.cs +++ b/TeamOctolings.Octobot/Commands/PingCommandGroup.cs @@ -1,8 +1,5 @@ using System.ComponentModel; using JetBrains.Annotations; -using Octobot.Data; -using Octobot.Extensions; -using Octobot.Services; using Remora.Commands.Attributes; using Remora.Commands.Groups; using Remora.Discord.API.Abstractions.Objects; @@ -15,14 +12,17 @@ using Remora.Discord.Extensions.Embeds; using Remora.Discord.Gateway; using Remora.Rest.Core; using Remora.Results; +using TeamOctolings.Octobot.Data; +using TeamOctolings.Octobot.Extensions; +using TeamOctolings.Octobot.Services; -namespace Octobot.Commands; +namespace TeamOctolings.Octobot.Commands; /// /// Handles the command to get the time taken for the gateway to respond to the last heartbeat: /ping /// [UsedImplicitly] -public class PingCommandGroup : CommandGroup +public sealed class PingCommandGroup : CommandGroup { private readonly IDiscordRestChannelAPI _channelApi; private readonly DiscordGatewayClient _client; diff --git a/src/Commands/RemindCommandGroup.cs b/TeamOctolings.Octobot/Commands/RemindCommandGroup.cs similarity index 98% rename from src/Commands/RemindCommandGroup.cs rename to TeamOctolings.Octobot/Commands/RemindCommandGroup.cs index aa1ef7e..bf59d67 100644 --- a/src/Commands/RemindCommandGroup.cs +++ b/TeamOctolings.Octobot/Commands/RemindCommandGroup.cs @@ -2,9 +2,6 @@ using System.ComponentModel; using System.ComponentModel.DataAnnotations; using System.Text; using JetBrains.Annotations; -using Octobot.Data; -using Octobot.Extensions; -using Octobot.Services; using Remora.Commands.Attributes; using Remora.Commands.Groups; using Remora.Discord.API.Abstractions.Objects; @@ -17,21 +14,24 @@ using Remora.Discord.Extensions.Embeds; using Remora.Discord.Extensions.Formatting; using Remora.Rest.Core; using Remora.Results; -using Octobot.Parsers; +using TeamOctolings.Octobot.Data; +using TeamOctolings.Octobot.Extensions; +using TeamOctolings.Octobot.Parsers; +using TeamOctolings.Octobot.Services; -namespace Octobot.Commands; +namespace TeamOctolings.Octobot.Commands; /// /// Handles commands to manage reminders: /remind, /listremind, /delremind /// [UsedImplicitly] -public class RemindCommandGroup : CommandGroup +public sealed class RemindCommandGroup : CommandGroup { private readonly IInteractionCommandContext _context; private readonly IFeedbackService _feedback; private readonly GuildDataService _guildData; - private readonly IDiscordRestUserAPI _userApi; private readonly IDiscordRestInteractionAPI _interactionApi; + private readonly IDiscordRestUserAPI _userApi; public RemindCommandGroup( IInteractionCommandContext context, GuildDataService guildData, IFeedbackService feedback, diff --git a/src/Commands/SettingsCommandGroup.cs b/TeamOctolings.Octobot/Commands/SettingsCommandGroup.cs similarity index 95% rename from src/Commands/SettingsCommandGroup.cs rename to TeamOctolings.Octobot/Commands/SettingsCommandGroup.cs index 8b1699f..a03f20d 100644 --- a/src/Commands/SettingsCommandGroup.cs +++ b/TeamOctolings.Octobot/Commands/SettingsCommandGroup.cs @@ -3,10 +3,6 @@ using System.ComponentModel.DataAnnotations; using System.Text; using System.Text.Json.Nodes; using JetBrains.Annotations; -using Octobot.Data; -using Octobot.Data.Options; -using Octobot.Extensions; -using Octobot.Services; using Remora.Commands.Attributes; using Remora.Commands.Groups; using Remora.Discord.API.Abstractions.Objects; @@ -19,23 +15,27 @@ using Remora.Discord.Extensions.Embeds; using Remora.Discord.Extensions.Formatting; using Remora.Rest.Core; using Remora.Results; +using TeamOctolings.Octobot.Data; +using TeamOctolings.Octobot.Data.Options; +using TeamOctolings.Octobot.Extensions; +using TeamOctolings.Octobot.Services; -namespace Octobot.Commands; +namespace TeamOctolings.Octobot.Commands; /// /// Handles the commands to list and modify per-guild settings: /settings and /settings list. /// [UsedImplicitly] -public class SettingsCommandGroup : CommandGroup +public sealed class SettingsCommandGroup : CommandGroup { /// - /// Represents all options as an array of objects implementing . + /// Represents all options as an array of objects implementing . /// /// /// WARNING: If you update this array in any way, you must also update and make sure /// that the orders match. /// - private static readonly IOption[] AllOptions = + private static readonly IGuildOption[] AllOptions = [ GuildSettings.Language, GuildSettings.WarnPunishment, @@ -202,7 +202,7 @@ public class SettingsCommandGroup : CommandGroup } private async Task EditSettingAsync( - IOption option, string value, GuildData data, Snowflake channelId, IUser executor, IUser bot, + IGuildOption option, string value, GuildData data, Snowflake channelId, IUser executor, IUser bot, CancellationToken ct = default) { var setResult = option.Set(data.Settings, value); @@ -273,7 +273,7 @@ public class SettingsCommandGroup : CommandGroup } private async Task ResetSingleSettingAsync(JsonNode cfg, IUser bot, - IOption option, CancellationToken ct = default) + IGuildOption option, CancellationToken ct = default) { var resetResult = option.Reset(cfg); if (!resetResult.IsSuccess) diff --git a/TeamOctolings.Octobot/Commands/ToolsCommandGroup.cs b/TeamOctolings.Octobot/Commands/ToolsCommandGroup.cs new file mode 100644 index 0000000..b4c3488 --- /dev/null +++ b/TeamOctolings.Octobot/Commands/ToolsCommandGroup.cs @@ -0,0 +1,272 @@ +using System.ComponentModel; +using System.Text; +using JetBrains.Annotations; +using Remora.Commands.Attributes; +using Remora.Commands.Groups; +using Remora.Discord.API.Abstractions.Objects; +using Remora.Discord.API.Abstractions.Rest; +using Remora.Discord.Commands.Attributes; +using Remora.Discord.Commands.Contexts; +using Remora.Discord.Commands.Feedback.Services; +using Remora.Discord.Extensions.Embeds; +using Remora.Discord.Extensions.Formatting; +using Remora.Results; +using TeamOctolings.Octobot.Data; +using TeamOctolings.Octobot.Extensions; +using TeamOctolings.Octobot.Parsers; +using TeamOctolings.Octobot.Services; + +namespace TeamOctolings.Octobot.Commands; + +/// +/// Handles tool commands: /random, /timestamp, /8ball. +/// +[UsedImplicitly] +public sealed class ToolsCommandGroup : CommandGroup +{ + private static readonly TimestampStyle[] AllStyles = + [ + TimestampStyle.ShortDate, + TimestampStyle.LongDate, + TimestampStyle.ShortTime, + TimestampStyle.LongTime, + TimestampStyle.ShortDateTime, + TimestampStyle.LongDateTime, + TimestampStyle.RelativeTime + ]; + + private static readonly string[] AnswerTypes = + [ + "Positive", "Questionable", "Neutral", "Negative" + ]; + + private readonly ICommandContext _context; + private readonly IFeedbackService _feedback; + private readonly GuildDataService _guildData; + private readonly IDiscordRestUserAPI _userApi; + + public ToolsCommandGroup( + ICommandContext context, IFeedbackService feedback, + GuildDataService guildData, IDiscordRestUserAPI userApi) + { + _context = context; + _guildData = guildData; + _feedback = feedback; + _userApi = userApi; + } + + /// + /// A slash command that generates a random number using maximum and minimum numbers. + /// + /// The first number used for randomization. + /// The second number used for randomization. Default value: 0 + /// + /// A feedback sending result which may or may not have succeeded. + /// + [Command("random")] + [DiscordDefaultDMPermission(false)] + [Description("Generates a random number")] + [UsedImplicitly] + public async Task ExecuteRandomAsync( + [Description("First number")] long first, + [Description("Second number (Default: 0)")] + long? second = null) + { + if (!_context.TryGetContextIDs(out var guildId, out _, out var executorId)) + { + return new ArgumentInvalidError(nameof(_context), "Unable to retrieve necessary IDs from command context"); + } + + var executorResult = await _userApi.GetUserAsync(executorId, CancellationToken); + if (!executorResult.IsDefined(out var executor)) + { + return ResultExtensions.FromError(executorResult); + } + + var data = await _guildData.GetData(guildId, CancellationToken); + Messages.Culture = GuildSettings.Language.Get(data.Settings); + + return await SendRandomNumberAsync(first, second, executor, CancellationToken); + } + + private Task SendRandomNumberAsync(long first, long? secondNullable, + IUser executor, CancellationToken ct) + { + const long secondDefault = 0; + var second = secondNullable ?? secondDefault; + + var min = Math.Min(first, second); + var max = Math.Max(first, second); + + var i = Random.Shared.NextInt64(min, max + 1); + + var description = new StringBuilder().Append("# ").Append(i); + + description.AppendLine().AppendBulletPoint(string.Format( + Messages.RandomMin, Markdown.InlineCode(min.ToString()))); + if (secondNullable is null && first >= secondDefault) + { + description.Append(' ').Append(Messages.Default); + } + + description.AppendLine().AppendBulletPoint(string.Format( + Messages.RandomMax, Markdown.InlineCode(max.ToString()))); + if (secondNullable is null && first < secondDefault) + { + description.Append(' ').Append(Messages.Default); + } + + var embedColor = ColorsList.Blue; + if (secondNullable is not null && min == max) + { + description.AppendLine().Append(Markdown.Italicise(Messages.RandomMinMaxSame)); + embedColor = ColorsList.Red; + } + + var embed = new EmbedBuilder().WithSmallTitle( + string.Format(Messages.RandomTitle, executor.GetTag()), executor) + .WithDescription(description.ToString()) + .WithColour(embedColor) + .Build(); + + return _feedback.SendContextualEmbedResultAsync(embed, ct: ct); + } + + /// + /// A slash command that shows the current timestamp with an optional offset in all styles supported by Discord. + /// + /// The offset for the current timestamp. + /// + /// A feedback sending result which may or may not have succeeded. + /// + [Command("timestamp")] + [DiscordDefaultDMPermission(false)] + [Description("Shows a timestamp in all styles")] + [UsedImplicitly] + public async Task ExecuteTimestampAsync( + [Description("Offset from current time")] [Option("offset")] + string? stringOffset = null) + { + if (!_context.TryGetContextIDs(out var guildId, out _, out var executorId)) + { + return new ArgumentInvalidError(nameof(_context), "Unable to retrieve necessary IDs from command context"); + } + + var botResult = await _userApi.GetCurrentUserAsync(CancellationToken); + if (!botResult.IsDefined(out var bot)) + { + return ResultExtensions.FromError(botResult); + } + + var executorResult = await _userApi.GetUserAsync(executorId, CancellationToken); + if (!executorResult.IsDefined(out var executor)) + { + return ResultExtensions.FromError(executorResult); + } + + var data = await _guildData.GetData(guildId, CancellationToken); + Messages.Culture = GuildSettings.Language.Get(data.Settings); + + if (stringOffset is null) + { + return await SendTimestampAsync(null, executor, CancellationToken); + } + + var parseResult = TimeSpanParser.TryParse(stringOffset); + if (!parseResult.IsDefined(out var offset)) + { + var failedEmbed = new EmbedBuilder() + .WithSmallTitle(Messages.InvalidTimeSpan, bot) + .WithDescription(Messages.TimeSpanExample) + .WithColour(ColorsList.Red) + .Build(); + + return await _feedback.SendContextualEmbedResultAsync(failedEmbed, ct: CancellationToken); + } + + return await SendTimestampAsync(offset, executor, CancellationToken); + } + + private Task SendTimestampAsync(TimeSpan? offset, IUser executor, CancellationToken ct) + { + var timestamp = DateTimeOffset.UtcNow.Add(offset ?? TimeSpan.Zero).ToUnixTimeSeconds(); + + var description = new StringBuilder().Append("# ").AppendLine(timestamp.ToString()); + + if (offset is not null) + { + description.AppendLine(string.Format( + Messages.TimestampOffset, Markdown.InlineCode(offset.ToString() ?? string.Empty))).AppendLine(); + } + + foreach (var markdownTimestamp in AllStyles.Select(style => Markdown.Timestamp(timestamp, style))) + { + description.AppendBulletPoint(Markdown.InlineCode(markdownTimestamp)) + .Append(" → ").AppendLine(markdownTimestamp); + } + + var embed = new EmbedBuilder().WithSmallTitle( + string.Format(Messages.TimestampTitle, executor.GetTag()), executor) + .WithDescription(description.ToString()) + .WithColour(ColorsList.Blue) + .Build(); + + return _feedback.SendContextualEmbedResultAsync(embed, ct: ct); + } + + /// + /// A slash command that shows a random answer from the Magic 8-Ball. + /// + /// Unused input. + /// + /// The 8-Ball answers were taken from Wikipedia. + /// + /// + /// A feedback sending result which may or may not have succeeded. + /// + [Command("8ball")] + [DiscordDefaultDMPermission(false)] + [Description("Ask the Magic 8-Ball a question")] + [UsedImplicitly] + public async Task ExecuteEightBallAsync( + // let the user think he's actually asking the ball a question + [Description("Question to ask")] string question) + { + if (!_context.TryGetContextIDs(out var guildId, out _, out _)) + { + return new ArgumentInvalidError(nameof(_context), "Unable to retrieve necessary IDs from command context"); + } + + var botResult = await _userApi.GetCurrentUserAsync(CancellationToken); + if (!botResult.IsDefined(out var bot)) + { + return ResultExtensions.FromError(botResult); + } + + var data = await _guildData.GetData(guildId, CancellationToken); + Messages.Culture = GuildSettings.Language.Get(data.Settings); + + return await AnswerEightBallAsync(bot, CancellationToken); + } + + private Task AnswerEightBallAsync(IUser bot, CancellationToken ct) + { + var typeNumber = Random.Shared.Next(0, 4); + var embedColor = typeNumber switch + { + 0 => ColorsList.Blue, + 1 => ColorsList.Green, + 2 => ColorsList.Yellow, + 3 => ColorsList.Red, + _ => throw new ArgumentOutOfRangeException(null, nameof(typeNumber)) + }; + + var answer = $"EightBall{AnswerTypes[typeNumber]}{Random.Shared.Next(1, 6)}".Localized(); + + var embed = new EmbedBuilder().WithSmallTitle(answer, bot) + .WithColour(embedColor) + .Build(); + + return _feedback.SendContextualEmbedResultAsync(embed, ct: ct); + } +} diff --git a/src/Commands/WarnCommandGroup.cs b/TeamOctolings.Octobot/Commands/WarnCommandGroup.cs similarity index 99% rename from src/Commands/WarnCommandGroup.cs rename to TeamOctolings.Octobot/Commands/WarnCommandGroup.cs index 8f4eb29..4b8d712 100644 --- a/src/Commands/WarnCommandGroup.cs +++ b/TeamOctolings.Octobot/Commands/WarnCommandGroup.cs @@ -4,9 +4,6 @@ using System.ComponentModel.DataAnnotations; using System.Text; using System.Text.Json.Nodes; using JetBrains.Annotations; -using Octobot.Data; -using Octobot.Extensions; -using Octobot.Services; using Remora.Commands.Attributes; using Remora.Commands.Groups; using Remora.Discord.API.Abstractions.Objects; @@ -19,9 +16,12 @@ using Remora.Discord.Extensions.Embeds; using Remora.Discord.Extensions.Formatting; using Remora.Rest.Core; using Remora.Results; +using TeamOctolings.Octobot.Data; +using TeamOctolings.Octobot.Extensions; +using TeamOctolings.Octobot.Services; using static System.DateTimeOffset; -namespace Octobot.Commands; +namespace TeamOctolings.Octobot.Commands; [UsedImplicitly] public class WarnCommandGroup : CommandGroup diff --git a/src/Data/GuildData.cs b/TeamOctolings.Octobot/Data/GuildData.cs similarity index 97% rename from src/Data/GuildData.cs rename to TeamOctolings.Octobot/Data/GuildData.cs index 5a903d6..f393323 100644 --- a/src/Data/GuildData.cs +++ b/TeamOctolings.Octobot/Data/GuildData.cs @@ -1,7 +1,7 @@ using System.Text.Json.Nodes; using Remora.Rest.Core; -namespace Octobot.Data; +namespace TeamOctolings.Octobot.Data; /// /// Stores information about a guild. This information is not accessible via the Discord API. diff --git a/src/Data/GuildSettings.cs b/TeamOctolings.Octobot/Data/GuildSettings.cs similarity index 93% rename from src/Data/GuildSettings.cs rename to TeamOctolings.Octobot/Data/GuildSettings.cs index fc616bd..26e325a 100644 --- a/src/Data/GuildSettings.cs +++ b/TeamOctolings.Octobot/Data/GuildSettings.cs @@ -1,8 +1,8 @@ -using Octobot.Data.Options; -using Octobot.Responders; using Remora.Discord.API.Abstractions.Objects; +using TeamOctolings.Octobot.Data.Options; +using TeamOctolings.Octobot.Responders; -namespace Octobot.Data; +namespace TeamOctolings.Octobot.Data; /// /// Contains all per-guild settings that can be set by a member @@ -24,7 +24,7 @@ public static class GuildSettings /// /// /// - public static readonly Option WelcomeMessage = new("WelcomeMessage", "default"); + public static readonly GuildOption WelcomeMessage = new("WelcomeMessage", "default"); /// /// Controls what message should be sent in when a member leaves the guild. @@ -36,7 +36,7 @@ public static class GuildSettings /// /// /// - public static readonly Option LeaveMessage = new("LeaveMessage", "default"); + public static readonly GuildOption LeaveMessage = new("LeaveMessage", "default"); /// /// Controls whether or not the message should be sent diff --git a/src/Data/MemberData.cs b/TeamOctolings.Octobot/Data/MemberData.cs similarity index 94% rename from src/Data/MemberData.cs rename to TeamOctolings.Octobot/Data/MemberData.cs index fe29e7f..57b5cc9 100644 --- a/src/Data/MemberData.cs +++ b/TeamOctolings.Octobot/Data/MemberData.cs @@ -1,4 +1,4 @@ -namespace Octobot.Data; +namespace TeamOctolings.Octobot.Data; /// /// Stores information about a member diff --git a/src/Data/Options/AllOptionsEnum.cs b/TeamOctolings.Octobot/Data/Options/AllOptionsEnum.cs similarity index 92% rename from src/Data/Options/AllOptionsEnum.cs rename to TeamOctolings.Octobot/Data/Options/AllOptionsEnum.cs index 01c3827..53b7f63 100644 --- a/src/Data/Options/AllOptionsEnum.cs +++ b/TeamOctolings.Octobot/Data/Options/AllOptionsEnum.cs @@ -1,7 +1,7 @@ using JetBrains.Annotations; -using Octobot.Commands; +using TeamOctolings.Octobot.Commands; -namespace Octobot.Data.Options; +namespace TeamOctolings.Octobot.Data.Options; /// /// Represents all options as enums. diff --git a/src/Data/Options/BoolOption.cs b/TeamOctolings.Octobot/Data/Options/BoolOption.cs similarity index 91% rename from src/Data/Options/BoolOption.cs rename to TeamOctolings.Octobot/Data/Options/BoolOption.cs index 6876164..6a3c899 100644 --- a/src/Data/Options/BoolOption.cs +++ b/TeamOctolings.Octobot/Data/Options/BoolOption.cs @@ -1,9 +1,9 @@ using System.Text.Json.Nodes; using Remora.Results; -namespace Octobot.Data.Options; +namespace TeamOctolings.Octobot.Data.Options; -public sealed class BoolOption : Option +public sealed class BoolOption : GuildOption { public BoolOption(string name, bool defaultValue) : base(name, defaultValue) { } diff --git a/src/Data/Options/Option.cs b/TeamOctolings.Octobot/Data/Options/GuildOption.cs similarity index 90% rename from src/Data/Options/Option.cs rename to TeamOctolings.Octobot/Data/Options/GuildOption.cs index 5d703a8..5d9f1a2 100644 --- a/src/Data/Options/Option.cs +++ b/TeamOctolings.Octobot/Data/Options/GuildOption.cs @@ -2,18 +2,18 @@ using System.Text.Json.Nodes; using Remora.Discord.Extensions.Formatting; using Remora.Results; -namespace Octobot.Data.Options; +namespace TeamOctolings.Octobot.Data.Options; /// -/// Represents an per-guild option. +/// Represents a per-guild option. /// /// The type of the option. -public class Option : IOption +public class GuildOption : IGuildOption where T : notnull { protected readonly T DefaultValue; - public Option(string name, T defaultValue) + public GuildOption(string name, T defaultValue) { Name = name; DefaultValue = defaultValue; diff --git a/src/Data/Options/IOption.cs b/TeamOctolings.Octobot/Data/Options/IGuildOption.cs similarity index 73% rename from src/Data/Options/IOption.cs rename to TeamOctolings.Octobot/Data/Options/IGuildOption.cs index b8ed03c..a8c3e6e 100644 --- a/src/Data/Options/IOption.cs +++ b/TeamOctolings.Octobot/Data/Options/IGuildOption.cs @@ -1,9 +1,9 @@ using System.Text.Json.Nodes; using Remora.Results; -namespace Octobot.Data.Options; +namespace TeamOctolings.Octobot.Data.Options; -public interface IOption +public interface IGuildOption { string Name { get; } string Display(JsonNode settings); diff --git a/src/Data/Options/IntOption.cs b/TeamOctolings.Octobot/Data/Options/IntOption.cs similarity index 88% rename from src/Data/Options/IntOption.cs rename to TeamOctolings.Octobot/Data/Options/IntOption.cs index 62b2883..3cdeb39 100644 --- a/src/Data/Options/IntOption.cs +++ b/TeamOctolings.Octobot/Data/Options/IntOption.cs @@ -1,9 +1,9 @@ using System.Text.Json.Nodes; using Remora.Results; -namespace Octobot.Data.Options; +namespace TeamOctolings.Octobot.Data.Options; -public sealed class IntOption : Option +public sealed class IntOption : GuildOption { public IntOption(string name, int defaultValue) : base(name, defaultValue) { } diff --git a/src/Data/Options/LanguageOption.cs b/TeamOctolings.Octobot/Data/Options/LanguageOption.cs similarity index 91% rename from src/Data/Options/LanguageOption.cs rename to TeamOctolings.Octobot/Data/Options/LanguageOption.cs index 22f98df..15ab6ff 100644 --- a/src/Data/Options/LanguageOption.cs +++ b/TeamOctolings.Octobot/Data/Options/LanguageOption.cs @@ -3,10 +3,10 @@ using System.Text.Json.Nodes; using Remora.Discord.Extensions.Formatting; using Remora.Results; -namespace Octobot.Data.Options; +namespace TeamOctolings.Octobot.Data.Options; /// -public sealed class LanguageOption : Option +public sealed class LanguageOption : GuildOption { private static readonly Dictionary CultureInfoCache = new() { diff --git a/src/Data/Options/PunishmentOption.cs b/TeamOctolings.Octobot/Data/Options/PunishmentOption.cs similarity index 85% rename from src/Data/Options/PunishmentOption.cs rename to TeamOctolings.Octobot/Data/Options/PunishmentOption.cs index f8d5414..b65ee68 100644 --- a/src/Data/Options/PunishmentOption.cs +++ b/TeamOctolings.Octobot/Data/Options/PunishmentOption.cs @@ -1,10 +1,10 @@ using System.Text.Json.Nodes; using Remora.Results; -namespace Octobot.Data.Options; +namespace TeamOctolings.Octobot.Data.Options; /// -public sealed class PunishmentOption : Option +public sealed class PunishmentOption : GuildOption { private static readonly List AllowedValues = [ diff --git a/src/Data/Options/SnowflakeOption.cs b/TeamOctolings.Octobot/Data/Options/SnowflakeOption.cs similarity index 87% rename from src/Data/Options/SnowflakeOption.cs rename to TeamOctolings.Octobot/Data/Options/SnowflakeOption.cs index 7118da8..b7405f2 100644 --- a/src/Data/Options/SnowflakeOption.cs +++ b/TeamOctolings.Octobot/Data/Options/SnowflakeOption.cs @@ -1,13 +1,13 @@ using System.Text.Json.Nodes; using System.Text.RegularExpressions; -using Octobot.Extensions; using Remora.Discord.Extensions.Formatting; using Remora.Rest.Core; using Remora.Results; +using TeamOctolings.Octobot.Extensions; -namespace Octobot.Data.Options; +namespace TeamOctolings.Octobot.Data.Options; -public sealed partial class SnowflakeOption : Option +public sealed partial class SnowflakeOption : GuildOption { public SnowflakeOption(string name) : base(name, 0UL.ToSnowflake()) { } diff --git a/src/Data/Options/TimeSpanOption.cs b/TeamOctolings.Octobot/Data/Options/TimeSpanOption.cs similarity index 82% rename from src/Data/Options/TimeSpanOption.cs rename to TeamOctolings.Octobot/Data/Options/TimeSpanOption.cs index d237b6e..3501f09 100644 --- a/src/Data/Options/TimeSpanOption.cs +++ b/TeamOctolings.Octobot/Data/Options/TimeSpanOption.cs @@ -1,10 +1,10 @@ using System.Text.Json.Nodes; -using Octobot.Parsers; using Remora.Results; +using TeamOctolings.Octobot.Parsers; -namespace Octobot.Data.Options; +namespace TeamOctolings.Octobot.Data.Options; -public sealed class TimeSpanOption : Option +public sealed class TimeSpanOption : GuildOption { public TimeSpanOption(string name, TimeSpan defaultValue) : base(name, defaultValue) { } diff --git a/src/Data/Reminder.cs b/TeamOctolings.Octobot/Data/Reminder.cs similarity index 83% rename from src/Data/Reminder.cs rename to TeamOctolings.Octobot/Data/Reminder.cs index f21b222..c3936da 100644 --- a/src/Data/Reminder.cs +++ b/TeamOctolings.Octobot/Data/Reminder.cs @@ -1,4 +1,4 @@ -namespace Octobot.Data; +namespace TeamOctolings.Octobot.Data; public struct Reminder { diff --git a/src/Data/ScheduledEventData.cs b/TeamOctolings.Octobot/Data/ScheduledEventData.cs similarity index 97% rename from src/Data/ScheduledEventData.cs rename to TeamOctolings.Octobot/Data/ScheduledEventData.cs index 59efc63..7ba6e92 100644 --- a/src/Data/ScheduledEventData.cs +++ b/TeamOctolings.Octobot/Data/ScheduledEventData.cs @@ -1,7 +1,7 @@ using System.Text.Json.Serialization; using Remora.Discord.API.Abstractions.Objects; -namespace Octobot.Data; +namespace TeamOctolings.Octobot.Data; /// /// Stores information about scheduled events. This information is not provided by the Discord API. diff --git a/src/Data/Warn.cs b/TeamOctolings.Octobot/Data/Warn.cs similarity index 78% rename from src/Data/Warn.cs rename to TeamOctolings.Octobot/Data/Warn.cs index f70d46e..ab512e6 100644 --- a/src/Data/Warn.cs +++ b/TeamOctolings.Octobot/Data/Warn.cs @@ -1,4 +1,4 @@ -namespace Octobot.Data; +namespace TeamOctolings.Octobot.Data; public struct Warn { diff --git a/src/Extensions/ChannelApiExtensions.cs b/TeamOctolings.Octobot/Extensions/ChannelApiExtensions.cs similarity index 74% rename from src/Extensions/ChannelApiExtensions.cs rename to TeamOctolings.Octobot/Extensions/ChannelApiExtensions.cs index 99eff67..82f8889 100644 --- a/src/Extensions/ChannelApiExtensions.cs +++ b/TeamOctolings.Octobot/Extensions/ChannelApiExtensions.cs @@ -5,18 +5,19 @@ using Remora.Discord.API.Objects; using Remora.Rest.Core; using Remora.Results; -namespace Octobot.Extensions; +namespace TeamOctolings.Octobot.Extensions; public static class ChannelApiExtensions { public static async Task CreateMessageWithEmbedResultAsync(this IDiscordRestChannelAPI channelApi, Snowflake channelId, Optional message = default, Optional nonce = default, Optional isTextToSpeech = default, Optional> embedResult = default, - Optional allowedMentions = default, Optional messageRefenence = default, + Optional allowedMentions = default, Optional messageReference = default, Optional> components = default, Optional> stickerIds = default, Optional>> attachments = default, - Optional flags = default, CancellationToken ct = default) + Optional flags = default, Optional enforceNonce = default, + Optional poll = default, CancellationToken ct = default) { if (!embedResult.IsDefined() || !embedResult.Value.IsDefined(out var embed)) { @@ -24,6 +25,6 @@ public static class ChannelApiExtensions } return (Result)await channelApi.CreateMessageAsync(channelId, message, nonce, isTextToSpeech, new[] { embed }, - allowedMentions, messageRefenence, components, stickerIds, attachments, flags, ct); + allowedMentions, messageReference, components, stickerIds, attachments, flags, enforceNonce, poll, ct); } } diff --git a/src/Extensions/CollectionExtensions.cs b/TeamOctolings.Octobot/Extensions/CollectionExtensions.cs similarity index 96% rename from src/Extensions/CollectionExtensions.cs rename to TeamOctolings.Octobot/Extensions/CollectionExtensions.cs index 2369532..3ea13a8 100644 --- a/src/Extensions/CollectionExtensions.cs +++ b/TeamOctolings.Octobot/Extensions/CollectionExtensions.cs @@ -1,6 +1,6 @@ using Remora.Results; -namespace Octobot.Extensions; +namespace TeamOctolings.Octobot.Extensions; public static class CollectionExtensions { diff --git a/src/Extensions/CommandContextExtensions.cs b/TeamOctolings.Octobot/Extensions/CommandContextExtensions.cs similarity index 92% rename from src/Extensions/CommandContextExtensions.cs rename to TeamOctolings.Octobot/Extensions/CommandContextExtensions.cs index a0c02f2..16b8b56 100644 --- a/src/Extensions/CommandContextExtensions.cs +++ b/TeamOctolings.Octobot/Extensions/CommandContextExtensions.cs @@ -2,7 +2,7 @@ using Remora.Discord.Commands.Extensions; using Remora.Rest.Core; -namespace Octobot.Extensions; +namespace TeamOctolings.Octobot.Extensions; public static class CommandContextExtensions { diff --git a/src/Extensions/DiffPaneModelExtensions.cs b/TeamOctolings.Octobot/Extensions/DiffPaneModelExtensions.cs similarity index 94% rename from src/Extensions/DiffPaneModelExtensions.cs rename to TeamOctolings.Octobot/Extensions/DiffPaneModelExtensions.cs index 1c3a098..3bb707b 100644 --- a/src/Extensions/DiffPaneModelExtensions.cs +++ b/TeamOctolings.Octobot/Extensions/DiffPaneModelExtensions.cs @@ -1,7 +1,7 @@ using System.Text; using DiffPlex.DiffBuilder.Model; -namespace Octobot.Extensions; +namespace TeamOctolings.Octobot.Extensions; public static class DiffPaneModelExtensions { diff --git a/src/Extensions/EmbedBuilderExtensions.cs b/TeamOctolings.Octobot/Extensions/EmbedBuilderExtensions.cs similarity index 99% rename from src/Extensions/EmbedBuilderExtensions.cs rename to TeamOctolings.Octobot/Extensions/EmbedBuilderExtensions.cs index 2d61403..dab0265 100644 --- a/src/Extensions/EmbedBuilderExtensions.cs +++ b/TeamOctolings.Octobot/Extensions/EmbedBuilderExtensions.cs @@ -4,7 +4,7 @@ using Remora.Discord.API.Objects; using Remora.Discord.Extensions.Embeds; using Remora.Rest.Core; -namespace Octobot.Extensions; +namespace TeamOctolings.Octobot.Extensions; public static class EmbedBuilderExtensions { diff --git a/src/Extensions/FeedbackServiceExtensions.cs b/TeamOctolings.Octobot/Extensions/FeedbackServiceExtensions.cs similarity index 93% rename from src/Extensions/FeedbackServiceExtensions.cs rename to TeamOctolings.Octobot/Extensions/FeedbackServiceExtensions.cs index e6ef376..c66c946 100644 --- a/src/Extensions/FeedbackServiceExtensions.cs +++ b/TeamOctolings.Octobot/Extensions/FeedbackServiceExtensions.cs @@ -3,7 +3,7 @@ using Remora.Discord.Commands.Feedback.Messages; using Remora.Discord.Commands.Feedback.Services; using Remora.Results; -namespace Octobot.Extensions; +namespace TeamOctolings.Octobot.Extensions; public static class FeedbackServiceExtensions { diff --git a/src/Extensions/GuildScheduledEventExtensions.cs b/TeamOctolings.Octobot/Extensions/GuildScheduledEventExtensions.cs similarity index 95% rename from src/Extensions/GuildScheduledEventExtensions.cs rename to TeamOctolings.Octobot/Extensions/GuildScheduledEventExtensions.cs index f1b6985..b8eb2d1 100644 --- a/src/Extensions/GuildScheduledEventExtensions.cs +++ b/TeamOctolings.Octobot/Extensions/GuildScheduledEventExtensions.cs @@ -2,7 +2,7 @@ using Remora.Rest.Core; using Remora.Results; -namespace Octobot.Extensions; +namespace TeamOctolings.Octobot.Extensions; public static class GuildScheduledEventExtensions { diff --git a/src/Extensions/LoggerExtensions.cs b/TeamOctolings.Octobot/Extensions/LoggerExtensions.cs similarity index 96% rename from src/Extensions/LoggerExtensions.cs rename to TeamOctolings.Octobot/Extensions/LoggerExtensions.cs index fca3702..76fa386 100644 --- a/src/Extensions/LoggerExtensions.cs +++ b/TeamOctolings.Octobot/Extensions/LoggerExtensions.cs @@ -1,7 +1,7 @@ using Microsoft.Extensions.Logging; using Remora.Results; -namespace Octobot.Extensions; +namespace TeamOctolings.Octobot.Extensions; public static class LoggerExtensions { diff --git a/src/Extensions/MarkdownExtensions.cs b/TeamOctolings.Octobot/Extensions/MarkdownExtensions.cs similarity index 88% rename from src/Extensions/MarkdownExtensions.cs rename to TeamOctolings.Octobot/Extensions/MarkdownExtensions.cs index 7b7f780..202cd37 100644 --- a/src/Extensions/MarkdownExtensions.cs +++ b/TeamOctolings.Octobot/Extensions/MarkdownExtensions.cs @@ -1,4 +1,4 @@ -namespace Octobot.Extensions; +namespace TeamOctolings.Octobot.Extensions; public static class MarkdownExtensions { diff --git a/src/Extensions/ResultExtensions.cs b/TeamOctolings.Octobot/Extensions/ResultExtensions.cs similarity index 82% rename from src/Extensions/ResultExtensions.cs rename to TeamOctolings.Octobot/Extensions/ResultExtensions.cs index f456dac..d7ef7d7 100644 --- a/src/Extensions/ResultExtensions.cs +++ b/TeamOctolings.Octobot/Extensions/ResultExtensions.cs @@ -2,7 +2,7 @@ using Microsoft.Extensions.Logging; using Remora.Results; -namespace Octobot.Extensions; +namespace TeamOctolings.Octobot.Extensions; public static class ResultExtensions { @@ -21,21 +21,25 @@ public static class ResultExtensions return casted; } - [Conditional("DEBUG")] private static void LogResultStackTrace(Result result) { - if (Octobot.StaticLogger is null || result.IsSuccess) + if (result.IsSuccess) { return; } - Octobot.StaticLogger.LogError("{ErrorType}: {ErrorMessage}{NewLine}{StackTrace}", + if (Utility.StaticLogger is null) + { + throw new InvalidOperationException(); + } + + Utility.StaticLogger.LogError("{ErrorType}: {ErrorMessage}{NewLine}{StackTrace}", result.Error.GetType().FullName, result.Error.Message, Environment.NewLine, ConstructStackTrace()); var inner = result.Inner; while (inner is { IsSuccess: false }) { - Octobot.StaticLogger.LogError("Caused by: {ResultType}: {ResultMessage}", + Utility.StaticLogger.LogError("Caused by: {ResultType}: {ResultMessage}", inner.Error.GetType().FullName, inner.Error.Message); inner = inner.Inner; diff --git a/src/Extensions/SnowflakeExtensions.cs b/TeamOctolings.Octobot/Extensions/SnowflakeExtensions.cs similarity index 96% rename from src/Extensions/SnowflakeExtensions.cs rename to TeamOctolings.Octobot/Extensions/SnowflakeExtensions.cs index e60bc44..70810ef 100644 --- a/src/Extensions/SnowflakeExtensions.cs +++ b/TeamOctolings.Octobot/Extensions/SnowflakeExtensions.cs @@ -1,6 +1,6 @@ using Remora.Rest.Core; -namespace Octobot.Extensions; +namespace TeamOctolings.Octobot.Extensions; public static class SnowflakeExtensions { diff --git a/src/Extensions/StringBuilderExtensions.cs b/TeamOctolings.Octobot/Extensions/StringBuilderExtensions.cs similarity index 98% rename from src/Extensions/StringBuilderExtensions.cs rename to TeamOctolings.Octobot/Extensions/StringBuilderExtensions.cs index ddd24a3..25b7b5b 100644 --- a/src/Extensions/StringBuilderExtensions.cs +++ b/TeamOctolings.Octobot/Extensions/StringBuilderExtensions.cs @@ -1,6 +1,6 @@ using System.Text; -namespace Octobot.Extensions; +namespace TeamOctolings.Octobot.Extensions; public static class StringBuilderExtensions { diff --git a/src/Extensions/StringExtensions.cs b/TeamOctolings.Octobot/Extensions/StringExtensions.cs similarity index 98% rename from src/Extensions/StringExtensions.cs rename to TeamOctolings.Octobot/Extensions/StringExtensions.cs index cb8d606..bf7f6c8 100644 --- a/src/Extensions/StringExtensions.cs +++ b/TeamOctolings.Octobot/Extensions/StringExtensions.cs @@ -1,7 +1,7 @@ using System.Net; using Remora.Discord.Extensions.Formatting; -namespace Octobot.Extensions; +namespace TeamOctolings.Octobot.Extensions; public static class StringExtensions { diff --git a/src/Extensions/UInt64Extensions.cs b/TeamOctolings.Octobot/Extensions/UInt64Extensions.cs similarity index 82% rename from src/Extensions/UInt64Extensions.cs rename to TeamOctolings.Octobot/Extensions/UInt64Extensions.cs index 5d1db00..2b9c0a2 100644 --- a/src/Extensions/UInt64Extensions.cs +++ b/TeamOctolings.Octobot/Extensions/UInt64Extensions.cs @@ -1,7 +1,7 @@ using Remora.Discord.API; using Remora.Rest.Core; -namespace Octobot.Extensions; +namespace TeamOctolings.Octobot.Extensions; public static class UInt64Extensions { diff --git a/src/Extensions/UserExtensions.cs b/TeamOctolings.Octobot/Extensions/UserExtensions.cs similarity index 85% rename from src/Extensions/UserExtensions.cs rename to TeamOctolings.Octobot/Extensions/UserExtensions.cs index 38fe985..d9eff33 100644 --- a/src/Extensions/UserExtensions.cs +++ b/TeamOctolings.Octobot/Extensions/UserExtensions.cs @@ -1,6 +1,6 @@ using Remora.Discord.API.Abstractions.Objects; -namespace Octobot.Extensions; +namespace TeamOctolings.Octobot.Extensions; public static class UserExtensions { diff --git a/src/Messages.Designer.cs b/TeamOctolings.Octobot/Messages.Designer.cs similarity index 91% rename from src/Messages.Designer.cs rename to TeamOctolings.Octobot/Messages.Designer.cs index 8266e7f..d56dc77 100644 --- a/src/Messages.Designer.cs +++ b/TeamOctolings.Octobot/Messages.Designer.cs @@ -7,7 +7,10 @@ // //------------------------------------------------------------------------------ -namespace Octobot { +namespace TeamOctolings.Octobot { + using System; + + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] [System.Diagnostics.DebuggerNonUserCodeAttribute()] [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] @@ -25,7 +28,7 @@ namespace Octobot { internal static System.Resources.ResourceManager ResourceManager { get { if (object.Equals(null, resourceMan)) { - System.Resources.ResourceManager temp = new System.Resources.ResourceManager("Octobot.locale.Messages", typeof(Messages).Assembly); + System.Resources.ResourceManager temp = new System.Resources.ResourceManager("TeamOctolings.Octobot.Messages", typeof(Messages).Assembly); resourceMan = temp; } return resourceMan; @@ -120,9 +123,9 @@ namespace Octobot { } } - internal static string SettingsLang { + internal static string SettingsLanguage { get { - return ResourceManager.GetString("SettingsLang", resourceCulture); + return ResourceManager.GetString("SettingsLanguage", resourceCulture); } } @@ -204,18 +207,6 @@ namespace Octobot { } } - internal static string InvalidRole { - get { - return ResourceManager.GetString("InvalidRole", resourceCulture); - } - } - - internal static string InvalidChannel { - get { - return ResourceManager.GetString("InvalidChannel", resourceCulture); - } - } - internal static string DurationRequiredForTimeOuts { get { return ResourceManager.GetString("DurationRequiredForTimeOuts", resourceCulture); @@ -282,6 +273,12 @@ namespace Octobot { } } + internal static string MissingUser { + get { + return ResourceManager.GetString("MissingUser", resourceCulture); + } + } + internal static string UserCannotBanMembers { get { return ResourceManager.GetString("UserCannotBanMembers", resourceCulture); @@ -300,9 +297,15 @@ namespace Octobot { } } - internal static string UserCannotModerateMembers { + internal static string UserCannotMuteMembers { get { - return ResourceManager.GetString("UserCannotModerateMembers", resourceCulture); + return ResourceManager.GetString("UserCannotMuteMembers", resourceCulture); + } + } + + internal static string UserCannotUnmuteMembers { + get { + return ResourceManager.GetString("UserCannotUnmuteMembers", resourceCulture); } } @@ -702,6 +705,12 @@ namespace Octobot { } } + internal static string SettingsRenameHoistedUsers { + get { + return ResourceManager.GetString("SettingsRenameHoistedUsers", resourceCulture); + } + } + internal static string Page { get { return ResourceManager.GetString("Page", resourceCulture); @@ -798,21 +807,15 @@ namespace Octobot { } } - internal static string InformationAbout { - get { - return ResourceManager.GetString("InformationAbout", resourceCulture); - } - } - internal static string UserInfoDisplayName { get { return ResourceManager.GetString("UserInfoDisplayName", resourceCulture); } } - internal static string UserInfoDiscordUserSince { + internal static string InformationAbout { get { - return ResourceManager.GetString("UserInfoDiscordUserSince", resourceCulture); + return ResourceManager.GetString("InformationAbout", resourceCulture); } } @@ -822,6 +825,12 @@ namespace Octobot { } } + internal static string UserInfoDiscordUserSince { + get { + return ResourceManager.GetString("UserInfoDiscordUserSince", resourceCulture); + } + } + internal static string UserInfoBanned { get { return ResourceManager.GetString("UserInfoBanned", resourceCulture); @@ -882,157 +891,122 @@ namespace Octobot { } } - internal static string RandomTitle - { + internal static string RandomTitle { get { return ResourceManager.GetString("RandomTitle", resourceCulture); } } - internal static string RandomMinMaxSame - { + internal static string RandomMinMaxSame { get { return ResourceManager.GetString("RandomMinMaxSame", resourceCulture); } } - internal static string RandomMax - { - get { - return ResourceManager.GetString("RandomMax", resourceCulture); - } - } - - internal static string RandomMin - { + internal static string RandomMin { get { return ResourceManager.GetString("RandomMin", resourceCulture); } } - internal static string Default - { + internal static string RandomMax { + get { + return ResourceManager.GetString("RandomMax", resourceCulture); + } + } + + internal static string Default { get { return ResourceManager.GetString("Default", resourceCulture); } } - internal static string TimestampTitle - { - get - { + internal static string TimestampTitle { + get { return ResourceManager.GetString("TimestampTitle", resourceCulture); } } - internal static string TimestampOffset - { - get - { + internal static string TimestampOffset { + get { return ResourceManager.GetString("TimestampOffset", resourceCulture); } } - internal static string GuildInfoDescription - { - get - { + internal static string GuildInfoDescription { + get { return ResourceManager.GetString("GuildInfoDescription", resourceCulture); } } - internal static string GuildInfoCreatedAt - { - get - { + internal static string GuildInfoCreatedAt { + get { return ResourceManager.GetString("GuildInfoCreatedAt", resourceCulture); } } - internal static string GuildInfoOwner - { - get - { + internal static string GuildInfoOwner { + get { return ResourceManager.GetString("GuildInfoOwner", resourceCulture); } } - internal static string GuildInfoServerBoost - { - get - { + internal static string GuildInfoServerBoost { + get { return ResourceManager.GetString("GuildInfoServerBoost", resourceCulture); } } - internal static string GuildInfoBoostTier - { - get - { + internal static string GuildInfoBoostTier { + get { return ResourceManager.GetString("GuildInfoBoostTier", resourceCulture); } } - internal static string GuildInfoBoostCount - { - get - { + internal static string GuildInfoBoostCount { + get { return ResourceManager.GetString("GuildInfoBoostCount", resourceCulture); } } - internal static string NoMessagesToClear - { - get - { + internal static string NoMessagesToClear { + get { return ResourceManager.GetString("NoMessagesToClear", resourceCulture); } } - internal static string MessagesClearedFiltered - { - get - { + internal static string MessagesClearedFiltered { + get { return ResourceManager.GetString("MessagesClearedFiltered", resourceCulture); } } - internal static string DataLoadFailedTitle - { - get - { + internal static string DataLoadFailedTitle { + get { return ResourceManager.GetString("DataLoadFailedTitle", resourceCulture); } } - internal static string DataLoadFailedDescription - { - get - { + internal static string DataLoadFailedDescription { + get { return ResourceManager.GetString("DataLoadFailedDescription", resourceCulture); } } - internal static string CommandExecutionFailed - { - get - { + internal static string CommandExecutionFailed { + get { return ResourceManager.GetString("CommandExecutionFailed", resourceCulture); } } - internal static string ContactDevelopers - { - get - { + internal static string ContactDevelopers { + get { return ResourceManager.GetString("ContactDevelopers", resourceCulture); } } - internal static string ButtonReportIssue - { - get - { + internal static string ButtonReportIssue { + get { return ResourceManager.GetString("ButtonReportIssue", resourceCulture); } } @@ -1205,62 +1179,53 @@ namespace Octobot { } } - internal static string UserWarned - { + internal static string UserWarned { get { return ResourceManager.GetString("UserWarned", resourceCulture); } } - internal static string UserWarnsRemoved - { + internal static string UserWarnsRemoved { get { return ResourceManager.GetString("UserWarnsRemoved", resourceCulture); } } - internal static string YouHaveBeenWarned - { + internal static string YouHaveBeenWarned { get { return ResourceManager.GetString("YouHaveBeenWarned", resourceCulture); } } - internal static string YourWarningsHaveBeenRevoked - { + internal static string YourWarningsHaveBeenRevoked { get { return ResourceManager.GetString("YourWarningsHaveBeenRevoked", resourceCulture); } } - internal static string DescriptionWarns - { + internal static string DescriptionWarns { get { return ResourceManager.GetString("DescriptionWarns", resourceCulture); } } - internal static string UserHasNoWarnings - { + internal static string UserHasNoWarnings { get { return ResourceManager.GetString("UserHasNoWarnings", resourceCulture); } } - internal static string YouHaveNoWarnings - { + internal static string YouHaveNoWarnings { get { return ResourceManager.GetString("YouHaveNoWarnings", resourceCulture); } } - internal static string ReceivedTooManyWarnings - { + internal static string ReceivedTooManyWarnings { get { return ResourceManager.GetString("ReceivedTooManyWarnings", resourceCulture); } } - internal static string ButtonDirty { get { return ResourceManager.GetString("ButtonDirty", resourceCulture); @@ -1273,82 +1238,74 @@ namespace Octobot { } } - internal static string ListTargetWarnsTitle - { + internal static string SettingsModeratorRole { + get { + return ResourceManager.GetString("SettingsModeratorRole", resourceCulture); + } + } + + internal static string ListTargetWarnsTitle { get { return ResourceManager.GetString("ListTargetWarnsTitle", resourceCulture); } } - internal static string ReceivedOn - { + internal static string ReceivedOn { get { return ResourceManager.GetString("ReceivedOn", resourceCulture); } } - internal static string UserWarnRemoved - { + internal static string UserWarnRemoved { get { return ResourceManager.GetString("UserWarnRemoved", resourceCulture); } } - internal static string YourWarningHasBeenRevoked - { + internal static string YourWarningHasBeenRevoked { get { return ResourceManager.GetString("YourWarningHasBeenRevoked", resourceCulture); } } - internal static string WrongWarningNumberSelected - { + internal static string WrongWarningNumberSelected { get { return ResourceManager.GetString("WrongWarningNumberSelected", resourceCulture); } } - internal static string ListExecutorWarnsTitle - { + internal static string ListExecutorWarnsTitle { get { return ResourceManager.GetString("ListExecutorWarnsTitle", resourceCulture); } } - internal static string DescriptionPunishmentType - { + internal static string DescriptionPunishmentType { get { return ResourceManager.GetString("DescriptionPunishmentType", resourceCulture); } } - internal static string WarnThresholdExceeded - { + internal static string WarnThresholdExceeded { get { return ResourceManager.GetString("WarnThresholdExceeded", resourceCulture); } } - internal static string WarnPunishmentDurationNotSet - { - get - { + internal static string WarnPunishmentDurationNotSet { + get { return ResourceManager.GetString("WarnPunishmentDurationNotSet", resourceCulture); } } - internal static string WarnThresholdExceededDescription - { - get - { + internal static string WarnThresholdExceededDescription { + get { return ResourceManager.GetString("WarnThresholdExceededDescription", resourceCulture); } } - internal static string InvalidWarnPunishment - { - get - { + internal static string InvalidWarnPunishment { + get { return ResourceManager.GetString("InvalidWarnPunishment", resourceCulture); } } diff --git a/locale/Messages.resx b/TeamOctolings.Octobot/Messages.resx similarity index 100% rename from locale/Messages.resx rename to TeamOctolings.Octobot/Messages.resx diff --git a/locale/Messages.ru.resx b/TeamOctolings.Octobot/Messages.ru.resx similarity index 100% rename from locale/Messages.ru.resx rename to TeamOctolings.Octobot/Messages.ru.resx diff --git a/src/Parsers/TimeSpanParser.cs b/TeamOctolings.Octobot/Parsers/TimeSpanParser.cs similarity index 98% rename from src/Parsers/TimeSpanParser.cs rename to TeamOctolings.Octobot/Parsers/TimeSpanParser.cs index 1f44d46..99a8b90 100644 --- a/src/Parsers/TimeSpanParser.cs +++ b/TeamOctolings.Octobot/Parsers/TimeSpanParser.cs @@ -4,7 +4,7 @@ using JetBrains.Annotations; using Remora.Commands.Parsers; using Remora.Results; -namespace Octobot.Parsers; +namespace TeamOctolings.Octobot.Parsers; /// /// Parses s. diff --git a/src/Octobot.cs b/TeamOctolings.Octobot/Program.cs similarity index 86% rename from src/Octobot.cs rename to TeamOctolings.Octobot/Program.cs index 065967e..d1d6220 100644 --- a/src/Octobot.cs +++ b/TeamOctolings.Octobot/Program.cs @@ -2,13 +2,8 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; -using Octobot.Attributes; -using Octobot.Commands.Events; -using Octobot.Services; -using Octobot.Services.Update; using Remora.Discord.API.Abstractions.Gateway.Commands; using Remora.Discord.API.Abstractions.Objects; -using Remora.Discord.API.Objects; using Remora.Discord.Caching.Extensions; using Remora.Discord.Caching.Services; using Remora.Discord.Commands.Extensions; @@ -16,24 +11,20 @@ using Remora.Discord.Commands.Services; using Remora.Discord.Extensions.Extensions; using Remora.Discord.Gateway; using Remora.Discord.Hosting.Extensions; -using Remora.Rest.Core; using Serilog.Extensions.Logging; +using TeamOctolings.Octobot.Commands.Events; +using TeamOctolings.Octobot.Services; +using TeamOctolings.Octobot.Services.Update; -namespace Octobot; +namespace TeamOctolings.Octobot; -public sealed class Octobot +public sealed class Program { - public static readonly AllowedMentions NoMentions = new( - Array.Empty(), Array.Empty(), Array.Empty()); - - [StaticCallersOnly] - public static ILogger? StaticLogger { get; private set; } - public static async Task Main(string[] args) { var host = CreateHostBuilder(args).UseConsoleLifetime().Build(); var services = host.Services; - StaticLogger = services.GetRequiredService>(); + Utility.StaticLogger = services.GetRequiredService>(); var slashService = services.GetRequiredService(); // Providing a guild ID to this call will result in command duplicates! @@ -82,8 +73,8 @@ public sealed class Octobot // Init .AddDiscordCaching() .AddDiscordCommands(true, false) - .AddRespondersFromAssembly(typeof(Octobot).Assembly) - .AddCommandGroupsFromAssembly(typeof(Octobot).Assembly) + .AddRespondersFromAssembly(typeof(Program).Assembly) + .AddCommandGroupsFromAssembly(typeof(Program).Assembly) // Slash command event handlers .AddPreparationErrorEvent() .AddPostExecutionEvent() diff --git a/src/Responders/GuildLoadedResponder.cs b/TeamOctolings.Octobot/Responders/GuildLoadedResponder.cs similarity index 95% rename from src/Responders/GuildLoadedResponder.cs rename to TeamOctolings.Octobot/Responders/GuildLoadedResponder.cs index 55e9673..cebb1ea 100644 --- a/src/Responders/GuildLoadedResponder.cs +++ b/TeamOctolings.Octobot/Responders/GuildLoadedResponder.cs @@ -1,8 +1,5 @@ using JetBrains.Annotations; using Microsoft.Extensions.Logging; -using Octobot.Data; -using Octobot.Extensions; -using Octobot.Services; using Remora.Discord.API.Abstractions.Gateway.Events; using Remora.Discord.API.Abstractions.Objects; using Remora.Discord.API.Abstractions.Rest; @@ -11,15 +8,18 @@ using Remora.Discord.API.Objects; using Remora.Discord.Extensions.Embeds; using Remora.Discord.Gateway.Responders; using Remora.Results; +using TeamOctolings.Octobot.Data; +using TeamOctolings.Octobot.Extensions; +using TeamOctolings.Octobot.Services; -namespace Octobot.Responders; +namespace TeamOctolings.Octobot.Responders; /// /// Handles sending a message to a guild that has just initialized if that guild /// has enabled /// [UsedImplicitly] -public class GuildLoadedResponder : IResponder +public sealed class GuildLoadedResponder : IResponder { private readonly IDiscordRestChannelAPI _channelApi; private readonly GuildDataService _guildData; diff --git a/src/Responders/GuildMemberJoinedResponder.cs b/TeamOctolings.Octobot/Responders/GuildMemberJoinedResponder.cs similarity index 92% rename from src/Responders/GuildMemberJoinedResponder.cs rename to TeamOctolings.Octobot/Responders/GuildMemberJoinedResponder.cs index 61ef5cc..c1f1da0 100644 --- a/src/Responders/GuildMemberJoinedResponder.cs +++ b/TeamOctolings.Octobot/Responders/GuildMemberJoinedResponder.cs @@ -1,16 +1,16 @@ using System.Text.Json.Nodes; using JetBrains.Annotations; -using Octobot.Data; -using Octobot.Extensions; -using Octobot.Services; using Remora.Discord.API.Abstractions.Gateway.Events; using Remora.Discord.API.Abstractions.Rest; using Remora.Discord.Extensions.Embeds; using Remora.Discord.Gateway.Responders; using Remora.Rest.Core; using Remora.Results; +using TeamOctolings.Octobot.Data; +using TeamOctolings.Octobot.Extensions; +using TeamOctolings.Octobot.Services; -namespace Octobot.Responders; +namespace TeamOctolings.Octobot.Responders; /// /// Handles sending a guild's if one is set. @@ -18,7 +18,7 @@ namespace Octobot.Responders; /// /// [UsedImplicitly] -public class GuildMemberJoinedResponder : IResponder +public sealed class GuildMemberJoinedResponder : IResponder { private readonly IDiscordRestChannelAPI _channelApi; private readonly IDiscordRestGuildAPI _guildApi; @@ -77,7 +77,7 @@ public class GuildMemberJoinedResponder : IResponder return await _channelApi.CreateMessageWithEmbedResultAsync( GuildSettings.WelcomeMessagesChannel.Get(cfg), embedResult: embed, - allowedMentions: Octobot.NoMentions, ct: ct); + allowedMentions: Utility.NoMentions, ct: ct); } private async Task TryReturnRolesAsync( diff --git a/src/Responders/GuildMemberLeftResponder.cs b/TeamOctolings.Octobot/Responders/GuildMemberLeftResponder.cs similarity index 89% rename from src/Responders/GuildMemberLeftResponder.cs rename to TeamOctolings.Octobot/Responders/GuildMemberLeftResponder.cs index 90cc64c..9774899 100644 --- a/src/Responders/GuildMemberLeftResponder.cs +++ b/TeamOctolings.Octobot/Responders/GuildMemberLeftResponder.cs @@ -1,21 +1,21 @@ using JetBrains.Annotations; -using Octobot.Data; -using Octobot.Extensions; -using Octobot.Services; using Remora.Discord.API.Abstractions.Gateway.Events; using Remora.Discord.API.Abstractions.Rest; using Remora.Discord.Extensions.Embeds; using Remora.Discord.Gateway.Responders; using Remora.Results; +using TeamOctolings.Octobot.Data; +using TeamOctolings.Octobot.Extensions; +using TeamOctolings.Octobot.Services; -namespace Octobot.Responders; +namespace TeamOctolings.Octobot.Responders; /// /// Handles sending a guild's if one is set. /// /// [UsedImplicitly] -public class GuildMemberLeftResponder : IResponder +public sealed class GuildMemberLeftResponder : IResponder { private readonly IDiscordRestChannelAPI _channelApi; private readonly IDiscordRestGuildAPI _guildApi; @@ -67,6 +67,6 @@ public class GuildMemberLeftResponder : IResponder return await _channelApi.CreateMessageWithEmbedResultAsync( GuildSettings.WelcomeMessagesChannel.Get(cfg), embedResult: embed, - allowedMentions: Octobot.NoMentions, ct: ct); + allowedMentions: Utility.NoMentions, ct: ct); } } diff --git a/src/Responders/GuildUnloadedResponder.cs b/TeamOctolings.Octobot/Responders/GuildUnloadedResponder.cs similarity index 84% rename from src/Responders/GuildUnloadedResponder.cs rename to TeamOctolings.Octobot/Responders/GuildUnloadedResponder.cs index b49d136..c73c134 100644 --- a/src/Responders/GuildUnloadedResponder.cs +++ b/TeamOctolings.Octobot/Responders/GuildUnloadedResponder.cs @@ -1,18 +1,18 @@ using JetBrains.Annotations; using Microsoft.Extensions.Logging; -using Octobot.Data; -using Octobot.Services; using Remora.Discord.API.Abstractions.Gateway.Events; using Remora.Discord.Gateway.Responders; using Remora.Results; +using TeamOctolings.Octobot.Data; +using TeamOctolings.Octobot.Services; -namespace Octobot.Responders; +namespace TeamOctolings.Octobot.Responders; /// /// Handles removing guild ID from if the guild becomes unavailable. /// [UsedImplicitly] -public class GuildUnloadedResponder : IResponder +public sealed class GuildUnloadedResponder : IResponder { private readonly GuildDataService _guildData; private readonly ILogger _logger; diff --git a/src/Responders/MessageDeletedResponder.cs b/TeamOctolings.Octobot/Responders/MessageDeletedResponder.cs similarity index 92% rename from src/Responders/MessageDeletedResponder.cs rename to TeamOctolings.Octobot/Responders/MessageDeletedResponder.cs index 5a69273..88a8de2 100644 --- a/src/Responders/MessageDeletedResponder.cs +++ b/TeamOctolings.Octobot/Responders/MessageDeletedResponder.cs @@ -1,8 +1,5 @@ using System.Text; using JetBrains.Annotations; -using Octobot.Data; -using Octobot.Extensions; -using Octobot.Services; using Remora.Discord.API.Abstractions.Gateway.Events; using Remora.Discord.API.Abstractions.Objects; using Remora.Discord.API.Abstractions.Rest; @@ -10,15 +7,18 @@ using Remora.Discord.Extensions.Embeds; using Remora.Discord.Extensions.Formatting; using Remora.Discord.Gateway.Responders; using Remora.Results; +using TeamOctolings.Octobot.Data; +using TeamOctolings.Octobot.Extensions; +using TeamOctolings.Octobot.Services; -namespace Octobot.Responders; +namespace TeamOctolings.Octobot.Responders; /// /// Handles logging the contents of a deleted message and the user who deleted the message /// to a guild's if one is set. /// [UsedImplicitly] -public class MessageDeletedResponder : IResponder +public sealed class MessageDeletedResponder : IResponder { private readonly IDiscordRestAuditLogAPI _auditLogApi; private readonly IDiscordRestChannelAPI _channelApi; @@ -102,6 +102,6 @@ public class MessageDeletedResponder : IResponder return await _channelApi.CreateMessageWithEmbedResultAsync( GuildSettings.PrivateFeedbackChannel.Get(cfg), embedResult: embed, - allowedMentions: Octobot.NoMentions, ct: ct); + allowedMentions: Utility.NoMentions, ct: ct); } } diff --git a/src/Responders/MessageEditedResponder.cs b/TeamOctolings.Octobot/Responders/MessageEditedResponder.cs similarity index 93% rename from src/Responders/MessageEditedResponder.cs rename to TeamOctolings.Octobot/Responders/MessageEditedResponder.cs index 1143652..2968562 100644 --- a/src/Responders/MessageEditedResponder.cs +++ b/TeamOctolings.Octobot/Responders/MessageEditedResponder.cs @@ -1,9 +1,6 @@ using System.Text; using DiffPlex.DiffBuilder; using JetBrains.Annotations; -using Octobot.Data; -using Octobot.Extensions; -using Octobot.Services; using Remora.Discord.API.Abstractions.Gateway.Events; using Remora.Discord.API.Abstractions.Objects; using Remora.Discord.API.Abstractions.Rest; @@ -12,15 +9,18 @@ using Remora.Discord.Caching.Services; using Remora.Discord.Extensions.Embeds; using Remora.Discord.Gateway.Responders; using Remora.Results; +using TeamOctolings.Octobot.Data; +using TeamOctolings.Octobot.Extensions; +using TeamOctolings.Octobot.Services; -namespace Octobot.Responders; +namespace TeamOctolings.Octobot.Responders; /// /// Handles logging the difference between an edited message's old and new content /// to a guild's if one is set. /// [UsedImplicitly] -public class MessageEditedResponder : IResponder +public sealed class MessageEditedResponder : IResponder { private readonly CacheService _cacheService; private readonly IDiscordRestChannelAPI _channelApi; @@ -104,6 +104,6 @@ public class MessageEditedResponder : IResponder return await _channelApi.CreateMessageWithEmbedResultAsync( GuildSettings.PrivateFeedbackChannel.Get(cfg), embedResult: embed, - allowedMentions: Octobot.NoMentions, ct: ct); + allowedMentions: Utility.NoMentions, ct: ct); } } diff --git a/src/Responders/MessageReceivedResponder.cs b/TeamOctolings.Octobot/Responders/MessageReceivedResponder.cs similarity index 91% rename from src/Responders/MessageReceivedResponder.cs rename to TeamOctolings.Octobot/Responders/MessageReceivedResponder.cs index 4c26d8d..24d53a5 100644 --- a/src/Responders/MessageReceivedResponder.cs +++ b/TeamOctolings.Octobot/Responders/MessageReceivedResponder.cs @@ -5,13 +5,13 @@ using Remora.Discord.Gateway.Responders; using Remora.Rest.Core; using Remora.Results; -namespace Octobot.Responders; +namespace TeamOctolings.Octobot.Responders; /// /// Handles sending replies to easter egg messages. /// [UsedImplicitly] -public class MessageCreateResponder : IResponder +public sealed class MessageCreateResponder : IResponder { private readonly IDiscordRestChannelAPI _channelApi; diff --git a/src/Services/AccessControlService.cs b/TeamOctolings.Octobot/Services/AccessControlService.cs similarity index 71% rename from src/Services/AccessControlService.cs rename to TeamOctolings.Octobot/Services/AccessControlService.cs index d164ed1..826983e 100644 --- a/src/Services/AccessControlService.cs +++ b/TeamOctolings.Octobot/Services/AccessControlService.cs @@ -1,11 +1,11 @@ -using Octobot.Data; -using Octobot.Extensions; -using Remora.Discord.API.Abstractions.Objects; +using Remora.Discord.API.Abstractions.Objects; using Remora.Discord.API.Abstractions.Rest; using Remora.Rest.Core; using Remora.Results; +using TeamOctolings.Octobot.Data; +using TeamOctolings.Octobot.Extensions; -namespace Octobot.Services; +namespace TeamOctolings.Octobot.Services; public sealed class AccessControlService { @@ -20,18 +20,17 @@ public sealed class AccessControlService _userApi = userApi; } - private static bool CheckPermission(IEnumerable roles, GuildData data, Snowflake memberId, - IGuildMember member, + private static bool CheckPermission(IEnumerable roles, GuildData data, MemberData memberData, DiscordPermission permission) { var moderatorRole = GuildSettings.ModeratorRole.Get(data.Settings); - if (!moderatorRole.Empty() && data.GetOrCreateMemberData(memberId).Roles.Contains(moderatorRole.Value)) + if (!moderatorRole.Empty() && memberData.Roles.Contains(moderatorRole.Value)) { return true; } return roles - .Where(r => member.Roles.Contains(r.ID)) + .Where(r => memberData.Roles.Contains(r.ID.Value)) .Any(r => r.Permissions.HasPermission(permission) ); @@ -80,38 +79,23 @@ public sealed class AccessControlService return Result.FromError(botResult); } - var botMemberResult = await _guildApi.GetGuildMemberAsync(guildId, bot.ID, ct); - if (!botMemberResult.IsDefined(out var botMember)) - { - return Result.FromError(botMemberResult); - } - - var targetMemberResult = await _guildApi.GetGuildMemberAsync(guildId, targetId, ct); - if (!targetMemberResult.IsDefined(out var targetMember)) - { - return Result.FromSuccess(null); - } - var rolesResult = await _guildApi.GetGuildRolesAsync(guildId, ct); if (!rolesResult.IsDefined(out var roles)) { return Result.FromError(rolesResult); } + var data = await _data.GetData(guildId, ct); + var targetData = data.GetOrCreateMemberData(targetId); + var botData = data.GetOrCreateMemberData(bot.ID); + if (interacterId is null) { - return CheckInteractions(action, guild, roles, targetMember, botMember, botMember); + return CheckInteractions(action, guild, roles, targetData, botData, botData); } - var interacterResult = await _guildApi.GetGuildMemberAsync(guildId, interacterId.Value, ct); - if (!interacterResult.IsDefined(out var interacter)) - { - return Result.FromError(interacterResult); - } - - var data = await _data.GetData(guildId, ct); - - var hasPermission = CheckPermission(roles, data, interacterId.Value, interacter, + var interacterData = data.GetOrCreateMemberData(interacterId.Value); + var hasPermission = CheckPermission(roles, data, interacterData, action switch { "Ban" => DiscordPermission.BanMembers, @@ -122,31 +106,26 @@ public sealed class AccessControlService }); return hasPermission - ? CheckInteractions(action, guild, roles, targetMember, botMember, interacter) + ? CheckInteractions(action, guild, roles, targetData, botData, interacterData) : Result.FromSuccess($"UserCannot{action}Members".Localized()); } private static Result CheckInteractions( - string action, IGuild guild, IReadOnlyList roles, IGuildMember targetMember, IGuildMember botMember, - IGuildMember interacter) + string action, IGuild guild, IReadOnlyList roles, MemberData targetData, MemberData botData, + MemberData interacterData) { - if (!targetMember.User.IsDefined(out var targetUser)) - { - return new ArgumentNullError(nameof(targetMember.User)); - } - - if (botMember.User == targetMember.User) + if (botData.Id == targetData.Id) { return Result.FromSuccess($"UserCannot{action}Bot".Localized()); } - if (targetUser.ID == guild.OwnerID) + if (targetData.Id == guild.OwnerID) { return Result.FromSuccess($"UserCannot{action}Owner".Localized()); } - var targetRoles = roles.Where(r => targetMember.Roles.Contains(r.ID)).ToList(); - var botRoles = roles.Where(r => botMember.Roles.Contains(r.ID)); + var targetRoles = roles.Where(r => targetData.Roles.Contains(r.ID.Value)).ToList(); + var botRoles = roles.Where(r => botData.Roles.Contains(r.ID.Value)); var targetBotRoleDiff = targetRoles.MaxOrDefault(r => r.Position) - botRoles.MaxOrDefault(r => r.Position); if (targetBotRoleDiff >= 0) @@ -154,7 +133,7 @@ public sealed class AccessControlService return Result.FromSuccess($"BotCannot{action}Target".Localized()); } - var interacterRoles = roles.Where(r => interacter.Roles.Contains(r.ID)); + var interacterRoles = roles.Where(r => interacterData.Roles.Contains(r.ID.Value)); var targetInteracterRoleDiff = targetRoles.MaxOrDefault(r => r.Position) - interacterRoles.MaxOrDefault(r => r.Position); return targetInteracterRoleDiff < 0 diff --git a/src/Services/GuildDataService.cs b/TeamOctolings.Octobot/Services/GuildDataService.cs similarity index 98% rename from src/Services/GuildDataService.cs rename to TeamOctolings.Octobot/Services/GuildDataService.cs index e503d22..866ee08 100644 --- a/src/Services/GuildDataService.cs +++ b/TeamOctolings.Octobot/Services/GuildDataService.cs @@ -3,10 +3,10 @@ using System.Text.Json; using System.Text.Json.Nodes; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; -using Octobot.Data; using Remora.Rest.Core; +using TeamOctolings.Octobot.Data; -namespace Octobot.Services; +namespace TeamOctolings.Octobot.Services; /// /// Handles saving, loading, initializing and providing . diff --git a/src/Services/Update/MemberUpdateService.cs b/TeamOctolings.Octobot/Services/Update/MemberUpdateService.cs similarity index 98% rename from src/Services/Update/MemberUpdateService.cs rename to TeamOctolings.Octobot/Services/Update/MemberUpdateService.cs index e177fca..51cf647 100644 --- a/src/Services/Update/MemberUpdateService.cs +++ b/TeamOctolings.Octobot/Services/Update/MemberUpdateService.cs @@ -2,16 +2,16 @@ using System.Text; using System.Text.RegularExpressions; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; -using Octobot.Data; -using Octobot.Extensions; using Remora.Discord.API.Abstractions.Objects; using Remora.Discord.API.Abstractions.Rest; using Remora.Discord.Extensions.Embeds; using Remora.Discord.Extensions.Formatting; using Remora.Rest.Core; using Remora.Results; +using TeamOctolings.Octobot.Data; +using TeamOctolings.Octobot.Extensions; -namespace Octobot.Services.Update; +namespace TeamOctolings.Octobot.Services.Update; public sealed partial class MemberUpdateService : BackgroundService { diff --git a/src/Services/Update/ScheduledEventUpdateService.cs b/TeamOctolings.Octobot/Services/Update/ScheduledEventUpdateService.cs similarity index 99% rename from src/Services/Update/ScheduledEventUpdateService.cs rename to TeamOctolings.Octobot/Services/Update/ScheduledEventUpdateService.cs index cb87779..ce9c212 100644 --- a/src/Services/Update/ScheduledEventUpdateService.cs +++ b/TeamOctolings.Octobot/Services/Update/ScheduledEventUpdateService.cs @@ -1,8 +1,6 @@ using System.Text.Json.Nodes; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; -using Octobot.Data; -using Octobot.Extensions; using Remora.Discord.API.Abstractions.Objects; using Remora.Discord.API.Abstractions.Rest; using Remora.Discord.API.Objects; @@ -10,8 +8,10 @@ using Remora.Discord.Extensions.Embeds; using Remora.Discord.Extensions.Formatting; using Remora.Rest.Core; using Remora.Results; +using TeamOctolings.Octobot.Data; +using TeamOctolings.Octobot.Extensions; -namespace Octobot.Services.Update; +namespace TeamOctolings.Octobot.Services.Update; public sealed class ScheduledEventUpdateService : BackgroundService { diff --git a/src/Services/Update/SongUpdateService.cs b/TeamOctolings.Octobot/Services/Update/SongUpdateService.cs similarity index 98% rename from src/Services/Update/SongUpdateService.cs rename to TeamOctolings.Octobot/Services/Update/SongUpdateService.cs index 41d5bf3..b07256f 100644 --- a/src/Services/Update/SongUpdateService.cs +++ b/TeamOctolings.Octobot/Services/Update/SongUpdateService.cs @@ -4,7 +4,7 @@ using Remora.Discord.API.Gateway.Commands; using Remora.Discord.API.Objects; using Remora.Discord.Gateway; -namespace Octobot.Services.Update; +namespace TeamOctolings.Octobot.Services.Update; public sealed class SongUpdateService : BackgroundService { diff --git a/Octobot.csproj b/TeamOctolings.Octobot/TeamOctolings.Octobot.csproj similarity index 85% rename from Octobot.csproj rename to TeamOctolings.Octobot/TeamOctolings.Octobot.csproj index bdfb46a..19e37f9 100644 --- a/Octobot.csproj +++ b/TeamOctolings.Octobot/TeamOctolings.Octobot.csproj @@ -1,4 +1,4 @@ - + Exe @@ -16,31 +16,31 @@ TeamOctolings en A general-purpose Discord bot for moderation written in C# - docs/octobot.ico + ../docs/octobot.ico false - + - - - - + + + + - + ResXFileCodeGenerator Messages.Designer.cs - + diff --git a/src/Services/Utility.cs b/TeamOctolings.Octobot/Utility.cs similarity index 92% rename from src/Services/Utility.cs rename to TeamOctolings.Octobot/Utility.cs index 3b9ab19..463212b 100644 --- a/src/Services/Utility.cs +++ b/TeamOctolings.Octobot/Utility.cs @@ -1,16 +1,19 @@ using System.Drawing; using System.Text; using System.Text.Json.Nodes; -using Octobot.Data; -using Octobot.Extensions; +using Microsoft.Extensions.Logging; using Remora.Discord.API.Abstractions.Objects; using Remora.Discord.API.Abstractions.Rest; +using Remora.Discord.API.Objects; using Remora.Discord.Extensions.Embeds; using Remora.Discord.Extensions.Formatting; using Remora.Rest.Core; using Remora.Results; +using TeamOctolings.Octobot.Attributes; +using TeamOctolings.Octobot.Data; +using TeamOctolings.Octobot.Extensions; -namespace Octobot.Services; +namespace TeamOctolings.Octobot; /// /// Provides utility methods that cannot be transformed to extension methods because they require usage @@ -18,6 +21,9 @@ namespace Octobot.Services; /// public sealed class Utility { + public static readonly AllowedMentions NoMentions = new( + Array.Empty(), Array.Empty(), Array.Empty()); + private readonly IDiscordRestChannelAPI _channelApi; private readonly IDiscordRestGuildScheduledEventAPI _eventApi; private readonly IDiscordRestGuildAPI _guildApi; @@ -30,6 +36,9 @@ public sealed class Utility _guildApi = guildApi; } + [StaticCallersOnly] + public static ILogger? StaticLogger { get; set; } + /// /// Gets the string mentioning the and event subscribers related to /// a scheduled