mirror of
https://github.com/TeamOctolings/Octobot.git
synced 2025-01-31 09:09:00 +03:00
i think this should work
This commit is contained in:
commit
006f0888de
68 changed files with 617 additions and 627 deletions
8
.github/dependabot.yml
vendored
8
.github/dependabot.yml
vendored
|
@ -15,6 +15,10 @@ updates:
|
||||||
labels:
|
labels:
|
||||||
- "type: change"
|
- "type: change"
|
||||||
- "area: build/ci"
|
- "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
|
- package-ecosystem: "nuget" # See documentation for possible values
|
||||||
directory: "/" # Location of package manifests
|
directory: "/" # Location of package manifests
|
||||||
|
@ -30,3 +34,7 @@ updates:
|
||||||
remora:
|
remora:
|
||||||
patterns:
|
patterns:
|
||||||
- "Remora.Discord.*"
|
- "Remora.Discord.*"
|
||||||
|
# For all packages, ignore all patch updates
|
||||||
|
ignore:
|
||||||
|
- dependency-name: "*"
|
||||||
|
update-types: [ "version-update:semver-patch" ]
|
||||||
|
|
2
.github/workflows/build-pr.yml
vendored
2
.github/workflows/build-pr.yml
vendored
|
@ -23,7 +23,7 @@ jobs:
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: ReSharper CLI InspectCode
|
- name: ReSharper CLI InspectCode
|
||||||
uses: muno92/resharper_inspectcode@1.11.8
|
uses: muno92/resharper_inspectcode@1.11.10
|
||||||
with:
|
with:
|
||||||
solutionPath: ./Octobot.sln
|
solutionPath: ./Octobot.sln
|
||||||
ignoreIssueType: InvertIf, ConvertIfStatementToSwitchStatement, ConvertToPrimaryConstructor
|
ignoreIssueType: InvertIf, ConvertIfStatementToSwitchStatement, ConvertToPrimaryConstructor
|
||||||
|
|
10
Octobot.sln
10
Octobot.sln
|
@ -1,6 +1,6 @@
|
||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
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
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
@ -8,9 +8,9 @@ Global
|
||||||
Release|Any CPU = Release|Any CPU
|
Release|Any CPU = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
{9CA7A44F-167C-46D4-923D-88CE71044144}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{A1679BA2-3A36-4D98-80C0-EEE771398FBD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{9CA7A44F-167C-46D4-923D-88CE71044144}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{A1679BA2-3A36-4D98-80C0-EEE771398FBD}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{9CA7A44F-167C-46D4-923D-88CE71044144}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{A1679BA2-3A36-4D98-80C0-EEE771398FBD}.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}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
namespace Octobot.Attributes;
|
namespace TeamOctolings.Octobot.Attributes;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Any property marked with <see cref="StaticCallersOnlyAttribute"/> should only be accessed by static methods.
|
/// Any property marked with <see cref="StaticCallersOnlyAttribute"/> should only be accessed by static methods.
|
|
@ -1,4 +1,4 @@
|
||||||
namespace Octobot;
|
namespace TeamOctolings.Octobot;
|
||||||
|
|
||||||
public static class BuildInfo
|
public static class BuildInfo
|
||||||
{
|
{
|
|
@ -1,6 +1,6 @@
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
|
|
||||||
namespace Octobot;
|
namespace TeamOctolings.Octobot;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Contains all colors used in embeds.
|
/// Contains all colors used in embeds.
|
|
@ -1,9 +1,6 @@
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Octobot.Data;
|
|
||||||
using Octobot.Extensions;
|
|
||||||
using Octobot.Services;
|
|
||||||
using Remora.Commands.Attributes;
|
using Remora.Commands.Attributes;
|
||||||
using Remora.Commands.Groups;
|
using Remora.Commands.Groups;
|
||||||
using Remora.Discord.API.Abstractions.Objects;
|
using Remora.Discord.API.Abstractions.Objects;
|
||||||
|
@ -18,14 +15,17 @@ using Remora.Discord.Extensions.Embeds;
|
||||||
using Remora.Discord.Extensions.Formatting;
|
using Remora.Discord.Extensions.Formatting;
|
||||||
using Remora.Rest.Core;
|
using Remora.Rest.Core;
|
||||||
using Remora.Results;
|
using Remora.Results;
|
||||||
|
using TeamOctolings.Octobot.Data;
|
||||||
|
using TeamOctolings.Octobot.Extensions;
|
||||||
|
using TeamOctolings.Octobot.Services;
|
||||||
|
|
||||||
namespace Octobot.Commands;
|
namespace TeamOctolings.Octobot.Commands;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles the command to show information about this bot: /about.
|
/// Handles the command to show information about this bot: /about.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[UsedImplicitly]
|
[UsedImplicitly]
|
||||||
public class AboutCommandGroup : CommandGroup
|
public sealed class AboutCommandGroup : CommandGroup
|
||||||
{
|
{
|
||||||
private static readonly (string Username, Snowflake Id)[] Developers =
|
private static readonly (string Username, Snowflake Id)[] Developers =
|
||||||
[
|
[
|
||||||
|
@ -36,9 +36,9 @@ public class AboutCommandGroup : CommandGroup
|
||||||
|
|
||||||
private readonly ICommandContext _context;
|
private readonly ICommandContext _context;
|
||||||
private readonly IFeedbackService _feedback;
|
private readonly IFeedbackService _feedback;
|
||||||
|
private readonly IDiscordRestGuildAPI _guildApi;
|
||||||
private readonly GuildDataService _guildData;
|
private readonly GuildDataService _guildData;
|
||||||
private readonly IDiscordRestUserAPI _userApi;
|
private readonly IDiscordRestUserAPI _userApi;
|
||||||
private readonly IDiscordRestGuildAPI _guildApi;
|
|
||||||
|
|
||||||
public AboutCommandGroup(
|
public AboutCommandGroup(
|
||||||
ICommandContext context, GuildDataService guildData,
|
ICommandContext context, GuildDataService guildData,
|
|
@ -2,11 +2,6 @@ using System.ComponentModel;
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using JetBrains.Annotations;
|
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.Attributes;
|
||||||
using Remora.Commands.Groups;
|
using Remora.Commands.Groups;
|
||||||
using Remora.Discord.API.Abstractions.Objects;
|
using Remora.Discord.API.Abstractions.Objects;
|
||||||
|
@ -19,14 +14,19 @@ using Remora.Discord.Extensions.Embeds;
|
||||||
using Remora.Discord.Extensions.Formatting;
|
using Remora.Discord.Extensions.Formatting;
|
||||||
using Remora.Rest.Core;
|
using Remora.Rest.Core;
|
||||||
using Remora.Results;
|
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;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles commands related to ban management: /ban and /unban.
|
/// Handles commands related to ban management: /ban and /unban.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[UsedImplicitly]
|
[UsedImplicitly]
|
||||||
public class BanCommandGroup : CommandGroup
|
public sealed class BanCommandGroup : CommandGroup
|
||||||
{
|
{
|
||||||
private readonly AccessControlService _access;
|
private readonly AccessControlService _access;
|
||||||
private readonly IDiscordRestChannelAPI _channelApi;
|
private readonly IDiscordRestChannelAPI _channelApi;
|
|
@ -1,9 +1,6 @@
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Octobot.Data;
|
|
||||||
using Octobot.Extensions;
|
|
||||||
using Octobot.Services;
|
|
||||||
using Remora.Commands.Attributes;
|
using Remora.Commands.Attributes;
|
||||||
using Remora.Commands.Groups;
|
using Remora.Commands.Groups;
|
||||||
using Remora.Discord.API.Abstractions.Objects;
|
using Remora.Discord.API.Abstractions.Objects;
|
||||||
|
@ -16,14 +13,17 @@ using Remora.Discord.Extensions.Embeds;
|
||||||
using Remora.Discord.Extensions.Formatting;
|
using Remora.Discord.Extensions.Formatting;
|
||||||
using Remora.Rest.Core;
|
using Remora.Rest.Core;
|
||||||
using Remora.Results;
|
using Remora.Results;
|
||||||
|
using TeamOctolings.Octobot.Data;
|
||||||
|
using TeamOctolings.Octobot.Extensions;
|
||||||
|
using TeamOctolings.Octobot.Services;
|
||||||
|
|
||||||
namespace Octobot.Commands;
|
namespace TeamOctolings.Octobot.Commands;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles the command to clear messages in a channel: /clear.
|
/// Handles the command to clear messages in a channel: /clear.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[UsedImplicitly]
|
[UsedImplicitly]
|
||||||
public class ClearCommandGroup : CommandGroup
|
public sealed class ClearCommandGroup : CommandGroup
|
||||||
{
|
{
|
||||||
private readonly IDiscordRestChannelAPI _channelApi;
|
private readonly IDiscordRestChannelAPI _channelApi;
|
||||||
private readonly ICommandContext _context;
|
private readonly ICommandContext _context;
|
||||||
|
@ -64,6 +64,7 @@ public class ClearCommandGroup : CommandGroup
|
||||||
public async Task<Result> ExecuteClear(
|
public async Task<Result> ExecuteClear(
|
||||||
[Description("Number of messages to remove (2-100)")] [MinValue(2)] [MaxValue(100)]
|
[Description("Number of messages to remove (2-100)")] [MinValue(2)] [MaxValue(100)]
|
||||||
int amount,
|
int amount,
|
||||||
|
[Description("Ignore messages except from the specified author")]
|
||||||
IUser? author = null)
|
IUser? author = null)
|
||||||
{
|
{
|
||||||
if (!_context.TryGetContextIDs(out var guildId, out var channelId, out var executorId))
|
if (!_context.TryGetContextIDs(out var guildId, out var channelId, out var executorId))
|
|
@ -1,6 +1,5 @@
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Octobot.Extensions;
|
|
||||||
using Remora.Discord.API.Abstractions.Objects;
|
using Remora.Discord.API.Abstractions.Objects;
|
||||||
using Remora.Discord.API.Abstractions.Rest;
|
using Remora.Discord.API.Abstractions.Rest;
|
||||||
using Remora.Discord.API.Objects;
|
using Remora.Discord.API.Objects;
|
||||||
|
@ -11,14 +10,15 @@ using Remora.Discord.Commands.Services;
|
||||||
using Remora.Discord.Extensions.Embeds;
|
using Remora.Discord.Extensions.Embeds;
|
||||||
using Remora.Discord.Extensions.Formatting;
|
using Remora.Discord.Extensions.Formatting;
|
||||||
using Remora.Results;
|
using Remora.Results;
|
||||||
|
using TeamOctolings.Octobot.Extensions;
|
||||||
|
|
||||||
namespace Octobot.Commands.Events;
|
namespace TeamOctolings.Octobot.Commands.Events;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles error logging for slash command groups.
|
/// Handles error logging for slash command groups.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[UsedImplicitly]
|
[UsedImplicitly]
|
||||||
public class ErrorLoggingPostExecutionEvent : IPostExecutionEvent
|
public sealed class ErrorLoggingPostExecutionEvent : IPostExecutionEvent
|
||||||
{
|
{
|
||||||
private readonly IFeedbackService _feedback;
|
private readonly IFeedbackService _feedback;
|
||||||
private readonly ILogger<ErrorLoggingPostExecutionEvent> _logger;
|
private readonly ILogger<ErrorLoggingPostExecutionEvent> _logger;
|
|
@ -1,17 +1,17 @@
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Octobot.Extensions;
|
|
||||||
using Remora.Discord.Commands.Contexts;
|
using Remora.Discord.Commands.Contexts;
|
||||||
using Remora.Discord.Commands.Services;
|
using Remora.Discord.Commands.Services;
|
||||||
using Remora.Results;
|
using Remora.Results;
|
||||||
|
using TeamOctolings.Octobot.Extensions;
|
||||||
|
|
||||||
namespace Octobot.Commands.Events;
|
namespace TeamOctolings.Octobot.Commands.Events;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles error logging for slash commands that couldn't be successfully prepared.
|
/// Handles error logging for slash commands that couldn't be successfully prepared.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[UsedImplicitly]
|
[UsedImplicitly]
|
||||||
public class LoggingPreparationErrorEvent : IPreparationErrorEvent
|
public sealed class LoggingPreparationErrorEvent : IPreparationErrorEvent
|
||||||
{
|
{
|
||||||
private readonly ILogger<LoggingPreparationErrorEvent> _logger;
|
private readonly ILogger<LoggingPreparationErrorEvent> _logger;
|
||||||
|
|
|
@ -2,10 +2,6 @@ using System.ComponentModel;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Octobot.Data;
|
|
||||||
using Octobot.Extensions;
|
|
||||||
using Octobot.Parsers;
|
|
||||||
using Octobot.Services;
|
|
||||||
using Remora.Commands.Attributes;
|
using Remora.Commands.Attributes;
|
||||||
using Remora.Commands.Groups;
|
using Remora.Commands.Groups;
|
||||||
using Remora.Discord.API.Abstractions.Objects;
|
using Remora.Discord.API.Abstractions.Objects;
|
||||||
|
@ -17,14 +13,17 @@ using Remora.Discord.Extensions.Embeds;
|
||||||
using Remora.Discord.Extensions.Formatting;
|
using Remora.Discord.Extensions.Formatting;
|
||||||
using Remora.Rest.Core;
|
using Remora.Rest.Core;
|
||||||
using Remora.Results;
|
using Remora.Results;
|
||||||
|
using TeamOctolings.Octobot.Data;
|
||||||
|
using TeamOctolings.Octobot.Extensions;
|
||||||
|
using TeamOctolings.Octobot.Services;
|
||||||
|
|
||||||
namespace Octobot.Commands;
|
namespace TeamOctolings.Octobot.Commands;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles tool commands: /userinfo, /guildinfo, /random, /timestamp, /8ball.
|
/// Handles info commands: /userinfo, /guildinfo.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[UsedImplicitly]
|
[UsedImplicitly]
|
||||||
public class ToolsCommandGroup : CommandGroup
|
public sealed class InfoCommandGroup : CommandGroup
|
||||||
{
|
{
|
||||||
private readonly ICommandContext _context;
|
private readonly ICommandContext _context;
|
||||||
private readonly IFeedbackService _feedback;
|
private readonly IFeedbackService _feedback;
|
||||||
|
@ -32,7 +31,7 @@ public class ToolsCommandGroup : CommandGroup
|
||||||
private readonly GuildDataService _guildData;
|
private readonly GuildDataService _guildData;
|
||||||
private readonly IDiscordRestUserAPI _userApi;
|
private readonly IDiscordRestUserAPI _userApi;
|
||||||
|
|
||||||
public ToolsCommandGroup(
|
public InfoCommandGroup(
|
||||||
ICommandContext context, IFeedbackService feedback,
|
ICommandContext context, IFeedbackService feedback,
|
||||||
GuildDataService guildData, IDiscordRestGuildAPI guildApi,
|
GuildDataService guildData, IDiscordRestGuildAPI guildApi,
|
||||||
IDiscordRestUserAPI userApi)
|
IDiscordRestUserAPI userApi)
|
||||||
|
@ -327,235 +326,4 @@ public class ToolsCommandGroup : CommandGroup
|
||||||
|
|
||||||
return _feedback.SendContextualEmbedResultAsync(embed, ct: ct);
|
return _feedback.SendContextualEmbedResultAsync(embed, ct: ct);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A slash command that generates a random number using maximum and minimum numbers.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="first">The first number used for randomization.</param>
|
|
||||||
/// <param name="second">The second number used for randomization. Default value: 0</param>
|
|
||||||
/// <returns>
|
|
||||||
/// A feedback sending result which may or may not have succeeded.
|
|
||||||
/// </returns>
|
|
||||||
[Command("random")]
|
|
||||||
[DiscordDefaultDMPermission(false)]
|
|
||||||
[Description("Generates a random number")]
|
|
||||||
[UsedImplicitly]
|
|
||||||
public async Task<Result> 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<Result> 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
|
|
||||||
];
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A slash command that shows the current timestamp with an optional offset in all styles supported by Discord.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="stringOffset">The offset for the current timestamp.</param>
|
|
||||||
/// <returns>
|
|
||||||
/// A feedback sending result which may or may not have succeeded.
|
|
||||||
/// </returns>
|
|
||||||
[Command("timestamp")]
|
|
||||||
[DiscordDefaultDMPermission(false)]
|
|
||||||
[Description("Shows a timestamp in all styles")]
|
|
||||||
[UsedImplicitly]
|
|
||||||
public async Task<Result> 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<Result> 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A slash command that shows a random answer from the Magic 8-Ball.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="question">Unused input.</param>
|
|
||||||
/// <remarks>
|
|
||||||
/// The 8-Ball answers were taken from <a href="https://en.wikipedia.org/wiki/Magic_8_Ball#Possible_answers">Wikipedia</a>.
|
|
||||||
/// </remarks>
|
|
||||||
/// <returns>
|
|
||||||
/// A feedback sending result which may or may not have succeeded.
|
|
||||||
/// </returns>
|
|
||||||
[Command("8ball")]
|
|
||||||
[DiscordDefaultDMPermission(false)]
|
|
||||||
[Description("Ask the Magic 8-Ball a question")]
|
|
||||||
[UsedImplicitly]
|
|
||||||
public async Task<Result> 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<Result> 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);
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -1,9 +1,6 @@
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Octobot.Data;
|
|
||||||
using Octobot.Extensions;
|
|
||||||
using Octobot.Services;
|
|
||||||
using Remora.Commands.Attributes;
|
using Remora.Commands.Attributes;
|
||||||
using Remora.Commands.Groups;
|
using Remora.Commands.Groups;
|
||||||
using Remora.Discord.API.Abstractions.Objects;
|
using Remora.Discord.API.Abstractions.Objects;
|
||||||
|
@ -15,14 +12,17 @@ using Remora.Discord.Commands.Feedback.Services;
|
||||||
using Remora.Discord.Extensions.Embeds;
|
using Remora.Discord.Extensions.Embeds;
|
||||||
using Remora.Rest.Core;
|
using Remora.Rest.Core;
|
||||||
using Remora.Results;
|
using Remora.Results;
|
||||||
|
using TeamOctolings.Octobot.Data;
|
||||||
|
using TeamOctolings.Octobot.Extensions;
|
||||||
|
using TeamOctolings.Octobot.Services;
|
||||||
|
|
||||||
namespace Octobot.Commands;
|
namespace TeamOctolings.Octobot.Commands;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles the command to kick members of a guild: /kick.
|
/// Handles the command to kick members of a guild: /kick.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[UsedImplicitly]
|
[UsedImplicitly]
|
||||||
public class KickCommandGroup : CommandGroup
|
public sealed class KickCommandGroup : CommandGroup
|
||||||
{
|
{
|
||||||
private readonly AccessControlService _access;
|
private readonly AccessControlService _access;
|
||||||
private readonly IDiscordRestChannelAPI _channelApi;
|
private readonly IDiscordRestChannelAPI _channelApi;
|
|
@ -2,11 +2,6 @@ using System.ComponentModel;
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using JetBrains.Annotations;
|
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.Attributes;
|
||||||
using Remora.Commands.Groups;
|
using Remora.Commands.Groups;
|
||||||
using Remora.Discord.API.Abstractions.Objects;
|
using Remora.Discord.API.Abstractions.Objects;
|
||||||
|
@ -19,14 +14,19 @@ using Remora.Discord.Extensions.Embeds;
|
||||||
using Remora.Discord.Extensions.Formatting;
|
using Remora.Discord.Extensions.Formatting;
|
||||||
using Remora.Rest.Core;
|
using Remora.Rest.Core;
|
||||||
using Remora.Results;
|
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;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles commands related to mute management: /mute and /unmute.
|
/// Handles commands related to mute management: /mute and /unmute.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[UsedImplicitly]
|
[UsedImplicitly]
|
||||||
public class MuteCommandGroup : CommandGroup
|
public sealed class MuteCommandGroup : CommandGroup
|
||||||
{
|
{
|
||||||
private readonly AccessControlService _access;
|
private readonly AccessControlService _access;
|
||||||
private readonly ICommandContext _context;
|
private readonly ICommandContext _context;
|
|
@ -1,8 +1,5 @@
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Octobot.Data;
|
|
||||||
using Octobot.Extensions;
|
|
||||||
using Octobot.Services;
|
|
||||||
using Remora.Commands.Attributes;
|
using Remora.Commands.Attributes;
|
||||||
using Remora.Commands.Groups;
|
using Remora.Commands.Groups;
|
||||||
using Remora.Discord.API.Abstractions.Objects;
|
using Remora.Discord.API.Abstractions.Objects;
|
||||||
|
@ -15,14 +12,17 @@ using Remora.Discord.Extensions.Embeds;
|
||||||
using Remora.Discord.Gateway;
|
using Remora.Discord.Gateway;
|
||||||
using Remora.Rest.Core;
|
using Remora.Rest.Core;
|
||||||
using Remora.Results;
|
using Remora.Results;
|
||||||
|
using TeamOctolings.Octobot.Data;
|
||||||
|
using TeamOctolings.Octobot.Extensions;
|
||||||
|
using TeamOctolings.Octobot.Services;
|
||||||
|
|
||||||
namespace Octobot.Commands;
|
namespace TeamOctolings.Octobot.Commands;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles the command to get the time taken for the gateway to respond to the last heartbeat: /ping
|
/// Handles the command to get the time taken for the gateway to respond to the last heartbeat: /ping
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[UsedImplicitly]
|
[UsedImplicitly]
|
||||||
public class PingCommandGroup : CommandGroup
|
public sealed class PingCommandGroup : CommandGroup
|
||||||
{
|
{
|
||||||
private readonly IDiscordRestChannelAPI _channelApi;
|
private readonly IDiscordRestChannelAPI _channelApi;
|
||||||
private readonly DiscordGatewayClient _client;
|
private readonly DiscordGatewayClient _client;
|
|
@ -2,9 +2,6 @@ using System.ComponentModel;
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Octobot.Data;
|
|
||||||
using Octobot.Extensions;
|
|
||||||
using Octobot.Services;
|
|
||||||
using Remora.Commands.Attributes;
|
using Remora.Commands.Attributes;
|
||||||
using Remora.Commands.Groups;
|
using Remora.Commands.Groups;
|
||||||
using Remora.Discord.API.Abstractions.Objects;
|
using Remora.Discord.API.Abstractions.Objects;
|
||||||
|
@ -17,21 +14,24 @@ using Remora.Discord.Extensions.Embeds;
|
||||||
using Remora.Discord.Extensions.Formatting;
|
using Remora.Discord.Extensions.Formatting;
|
||||||
using Remora.Rest.Core;
|
using Remora.Rest.Core;
|
||||||
using Remora.Results;
|
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;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles commands to manage reminders: /remind, /listremind, /delremind
|
/// Handles commands to manage reminders: /remind, /listremind, /delremind
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[UsedImplicitly]
|
[UsedImplicitly]
|
||||||
public class RemindCommandGroup : CommandGroup
|
public sealed class RemindCommandGroup : CommandGroup
|
||||||
{
|
{
|
||||||
private readonly IInteractionCommandContext _context;
|
private readonly IInteractionCommandContext _context;
|
||||||
private readonly IFeedbackService _feedback;
|
private readonly IFeedbackService _feedback;
|
||||||
private readonly GuildDataService _guildData;
|
private readonly GuildDataService _guildData;
|
||||||
private readonly IDiscordRestUserAPI _userApi;
|
|
||||||
private readonly IDiscordRestInteractionAPI _interactionApi;
|
private readonly IDiscordRestInteractionAPI _interactionApi;
|
||||||
|
private readonly IDiscordRestUserAPI _userApi;
|
||||||
|
|
||||||
public RemindCommandGroup(
|
public RemindCommandGroup(
|
||||||
IInteractionCommandContext context, GuildDataService guildData, IFeedbackService feedback,
|
IInteractionCommandContext context, GuildDataService guildData, IFeedbackService feedback,
|
|
@ -3,10 +3,6 @@ using System.ComponentModel.DataAnnotations;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.Json.Nodes;
|
using System.Text.Json.Nodes;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Octobot.Data;
|
|
||||||
using Octobot.Data.Options;
|
|
||||||
using Octobot.Extensions;
|
|
||||||
using Octobot.Services;
|
|
||||||
using Remora.Commands.Attributes;
|
using Remora.Commands.Attributes;
|
||||||
using Remora.Commands.Groups;
|
using Remora.Commands.Groups;
|
||||||
using Remora.Discord.API.Abstractions.Objects;
|
using Remora.Discord.API.Abstractions.Objects;
|
||||||
|
@ -19,23 +15,27 @@ using Remora.Discord.Extensions.Embeds;
|
||||||
using Remora.Discord.Extensions.Formatting;
|
using Remora.Discord.Extensions.Formatting;
|
||||||
using Remora.Rest.Core;
|
using Remora.Rest.Core;
|
||||||
using Remora.Results;
|
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;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles the commands to list and modify per-guild settings: /settings and /settings list.
|
/// Handles the commands to list and modify per-guild settings: /settings and /settings list.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[UsedImplicitly]
|
[UsedImplicitly]
|
||||||
public class SettingsCommandGroup : CommandGroup
|
public sealed class SettingsCommandGroup : CommandGroup
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents all options as an array of objects implementing <see cref="IOption" />.
|
/// Represents all options as an array of objects implementing <see cref="IGuildOption" />.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// WARNING: If you update this array in any way, you must also update <see cref="AllOptionsEnum" /> and make sure
|
/// WARNING: If you update this array in any way, you must also update <see cref="AllOptionsEnum" /> and make sure
|
||||||
/// that the orders match.
|
/// that the orders match.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
private static readonly IOption[] AllOptions =
|
private static readonly IGuildOption[] AllOptions =
|
||||||
[
|
[
|
||||||
GuildSettings.Language,
|
GuildSettings.Language,
|
||||||
GuildSettings.WarnPunishment,
|
GuildSettings.WarnPunishment,
|
||||||
|
@ -202,7 +202,7 @@ public class SettingsCommandGroup : CommandGroup
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<Result> EditSettingAsync(
|
private async Task<Result> 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)
|
CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
var setResult = option.Set(data.Settings, value);
|
var setResult = option.Set(data.Settings, value);
|
||||||
|
@ -273,7 +273,7 @@ public class SettingsCommandGroup : CommandGroup
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<Result> ResetSingleSettingAsync(JsonNode cfg, IUser bot,
|
private async Task<Result> ResetSingleSettingAsync(JsonNode cfg, IUser bot,
|
||||||
IOption option, CancellationToken ct = default)
|
IGuildOption option, CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
var resetResult = option.Reset(cfg);
|
var resetResult = option.Reset(cfg);
|
||||||
if (!resetResult.IsSuccess)
|
if (!resetResult.IsSuccess)
|
272
TeamOctolings.Octobot/Commands/ToolsCommandGroup.cs
Normal file
272
TeamOctolings.Octobot/Commands/ToolsCommandGroup.cs
Normal file
|
@ -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;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handles tool commands: /random, /timestamp, /8ball.
|
||||||
|
/// </summary>
|
||||||
|
[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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A slash command that generates a random number using maximum and minimum numbers.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="first">The first number used for randomization.</param>
|
||||||
|
/// <param name="second">The second number used for randomization. Default value: 0</param>
|
||||||
|
/// <returns>
|
||||||
|
/// A feedback sending result which may or may not have succeeded.
|
||||||
|
/// </returns>
|
||||||
|
[Command("random")]
|
||||||
|
[DiscordDefaultDMPermission(false)]
|
||||||
|
[Description("Generates a random number")]
|
||||||
|
[UsedImplicitly]
|
||||||
|
public async Task<Result> 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<Result> 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A slash command that shows the current timestamp with an optional offset in all styles supported by Discord.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="stringOffset">The offset for the current timestamp.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// A feedback sending result which may or may not have succeeded.
|
||||||
|
/// </returns>
|
||||||
|
[Command("timestamp")]
|
||||||
|
[DiscordDefaultDMPermission(false)]
|
||||||
|
[Description("Shows a timestamp in all styles")]
|
||||||
|
[UsedImplicitly]
|
||||||
|
public async Task<Result> 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<Result> 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A slash command that shows a random answer from the Magic 8-Ball.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="question">Unused input.</param>
|
||||||
|
/// <remarks>
|
||||||
|
/// The 8-Ball answers were taken from <a href="https://en.wikipedia.org/wiki/Magic_8_Ball#Possible_answers">Wikipedia</a>.
|
||||||
|
/// </remarks>
|
||||||
|
/// <returns>
|
||||||
|
/// A feedback sending result which may or may not have succeeded.
|
||||||
|
/// </returns>
|
||||||
|
[Command("8ball")]
|
||||||
|
[DiscordDefaultDMPermission(false)]
|
||||||
|
[Description("Ask the Magic 8-Ball a question")]
|
||||||
|
[UsedImplicitly]
|
||||||
|
public async Task<Result> 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<Result> 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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,9 +4,6 @@ using System.ComponentModel.DataAnnotations;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.Json.Nodes;
|
using System.Text.Json.Nodes;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Octobot.Data;
|
|
||||||
using Octobot.Extensions;
|
|
||||||
using Octobot.Services;
|
|
||||||
using Remora.Commands.Attributes;
|
using Remora.Commands.Attributes;
|
||||||
using Remora.Commands.Groups;
|
using Remora.Commands.Groups;
|
||||||
using Remora.Discord.API.Abstractions.Objects;
|
using Remora.Discord.API.Abstractions.Objects;
|
||||||
|
@ -19,9 +16,12 @@ using Remora.Discord.Extensions.Embeds;
|
||||||
using Remora.Discord.Extensions.Formatting;
|
using Remora.Discord.Extensions.Formatting;
|
||||||
using Remora.Rest.Core;
|
using Remora.Rest.Core;
|
||||||
using Remora.Results;
|
using Remora.Results;
|
||||||
|
using TeamOctolings.Octobot.Data;
|
||||||
|
using TeamOctolings.Octobot.Extensions;
|
||||||
|
using TeamOctolings.Octobot.Services;
|
||||||
using static System.DateTimeOffset;
|
using static System.DateTimeOffset;
|
||||||
|
|
||||||
namespace Octobot.Commands;
|
namespace TeamOctolings.Octobot.Commands;
|
||||||
|
|
||||||
[UsedImplicitly]
|
[UsedImplicitly]
|
||||||
public class WarnCommandGroup : CommandGroup
|
public class WarnCommandGroup : CommandGroup
|
|
@ -1,7 +1,7 @@
|
||||||
using System.Text.Json.Nodes;
|
using System.Text.Json.Nodes;
|
||||||
using Remora.Rest.Core;
|
using Remora.Rest.Core;
|
||||||
|
|
||||||
namespace Octobot.Data;
|
namespace TeamOctolings.Octobot.Data;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Stores information about a guild. This information is not accessible via the Discord API.
|
/// Stores information about a guild. This information is not accessible via the Discord API.
|
|
@ -1,8 +1,8 @@
|
||||||
using Octobot.Data.Options;
|
|
||||||
using Octobot.Responders;
|
|
||||||
using Remora.Discord.API.Abstractions.Objects;
|
using Remora.Discord.API.Abstractions.Objects;
|
||||||
|
using TeamOctolings.Octobot.Data.Options;
|
||||||
|
using TeamOctolings.Octobot.Responders;
|
||||||
|
|
||||||
namespace Octobot.Data;
|
namespace TeamOctolings.Octobot.Data;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Contains all per-guild settings that can be set by a member
|
/// Contains all per-guild settings that can be set by a member
|
||||||
|
@ -24,7 +24,7 @@ public static class GuildSettings
|
||||||
/// </list>
|
/// </list>
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
/// <seealso cref="GuildMemberJoinedResponder" />
|
/// <seealso cref="GuildMemberJoinedResponder" />
|
||||||
public static readonly Option<string> WelcomeMessage = new("WelcomeMessage", "default");
|
public static readonly GuildOption<string> WelcomeMessage = new("WelcomeMessage", "default");
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Controls what message should be sent in <see cref="PublicFeedbackChannel" /> when a member leaves the guild.
|
/// Controls what message should be sent in <see cref="PublicFeedbackChannel" /> when a member leaves the guild.
|
||||||
|
@ -36,7 +36,7 @@ public static class GuildSettings
|
||||||
/// </list>
|
/// </list>
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
/// <seealso cref="GuildMemberLeftResponder" />
|
/// <seealso cref="GuildMemberLeftResponder" />
|
||||||
public static readonly Option<string> LeaveMessage = new("LeaveMessage", "default");
|
public static readonly GuildOption<string> LeaveMessage = new("LeaveMessage", "default");
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Controls whether or not the <see cref="Messages.Ready" /> message should be sent
|
/// Controls whether or not the <see cref="Messages.Ready" /> message should be sent
|
|
@ -1,4 +1,4 @@
|
||||||
namespace Octobot.Data;
|
namespace TeamOctolings.Octobot.Data;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Stores information about a member
|
/// Stores information about a member
|
|
@ -1,7 +1,7 @@
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Octobot.Commands;
|
using TeamOctolings.Octobot.Commands;
|
||||||
|
|
||||||
namespace Octobot.Data.Options;
|
namespace TeamOctolings.Octobot.Data.Options;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents all options as enums.
|
/// Represents all options as enums.
|
|
@ -1,9 +1,9 @@
|
||||||
using System.Text.Json.Nodes;
|
using System.Text.Json.Nodes;
|
||||||
using Remora.Results;
|
using Remora.Results;
|
||||||
|
|
||||||
namespace Octobot.Data.Options;
|
namespace TeamOctolings.Octobot.Data.Options;
|
||||||
|
|
||||||
public sealed class BoolOption : Option<bool>
|
public sealed class BoolOption : GuildOption<bool>
|
||||||
{
|
{
|
||||||
public BoolOption(string name, bool defaultValue) : base(name, defaultValue) { }
|
public BoolOption(string name, bool defaultValue) : base(name, defaultValue) { }
|
||||||
|
|
|
@ -2,18 +2,18 @@ using System.Text.Json.Nodes;
|
||||||
using Remora.Discord.Extensions.Formatting;
|
using Remora.Discord.Extensions.Formatting;
|
||||||
using Remora.Results;
|
using Remora.Results;
|
||||||
|
|
||||||
namespace Octobot.Data.Options;
|
namespace TeamOctolings.Octobot.Data.Options;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents an per-guild option.
|
/// Represents a per-guild option.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T">The type of the option.</typeparam>
|
/// <typeparam name="T">The type of the option.</typeparam>
|
||||||
public class Option<T> : IOption
|
public class GuildOption<T> : IGuildOption
|
||||||
where T : notnull
|
where T : notnull
|
||||||
{
|
{
|
||||||
protected readonly T DefaultValue;
|
protected readonly T DefaultValue;
|
||||||
|
|
||||||
public Option(string name, T defaultValue)
|
public GuildOption(string name, T defaultValue)
|
||||||
{
|
{
|
||||||
Name = name;
|
Name = name;
|
||||||
DefaultValue = defaultValue;
|
DefaultValue = defaultValue;
|
|
@ -1,9 +1,9 @@
|
||||||
using System.Text.Json.Nodes;
|
using System.Text.Json.Nodes;
|
||||||
using Remora.Results;
|
using Remora.Results;
|
||||||
|
|
||||||
namespace Octobot.Data.Options;
|
namespace TeamOctolings.Octobot.Data.Options;
|
||||||
|
|
||||||
public interface IOption
|
public interface IGuildOption
|
||||||
{
|
{
|
||||||
string Name { get; }
|
string Name { get; }
|
||||||
string Display(JsonNode settings);
|
string Display(JsonNode settings);
|
|
@ -1,9 +1,9 @@
|
||||||
using System.Text.Json.Nodes;
|
using System.Text.Json.Nodes;
|
||||||
using Remora.Results;
|
using Remora.Results;
|
||||||
|
|
||||||
namespace Octobot.Data.Options;
|
namespace TeamOctolings.Octobot.Data.Options;
|
||||||
|
|
||||||
public sealed class IntOption : Option<int>
|
public sealed class IntOption : GuildOption<int>
|
||||||
{
|
{
|
||||||
public IntOption(string name, int defaultValue) : base(name, defaultValue) { }
|
public IntOption(string name, int defaultValue) : base(name, defaultValue) { }
|
||||||
|
|
|
@ -3,10 +3,10 @@ using System.Text.Json.Nodes;
|
||||||
using Remora.Discord.Extensions.Formatting;
|
using Remora.Discord.Extensions.Formatting;
|
||||||
using Remora.Results;
|
using Remora.Results;
|
||||||
|
|
||||||
namespace Octobot.Data.Options;
|
namespace TeamOctolings.Octobot.Data.Options;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public sealed class LanguageOption : Option<CultureInfo>
|
public sealed class LanguageOption : GuildOption<CultureInfo>
|
||||||
{
|
{
|
||||||
private static readonly Dictionary<string, CultureInfo> CultureInfoCache = new()
|
private static readonly Dictionary<string, CultureInfo> CultureInfoCache = new()
|
||||||
{
|
{
|
|
@ -1,10 +1,10 @@
|
||||||
using System.Text.Json.Nodes;
|
using System.Text.Json.Nodes;
|
||||||
using Remora.Results;
|
using Remora.Results;
|
||||||
|
|
||||||
namespace Octobot.Data.Options;
|
namespace TeamOctolings.Octobot.Data.Options;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public sealed class PunishmentOption : Option<string>
|
public sealed class PunishmentOption : GuildOption<string>
|
||||||
{
|
{
|
||||||
private static readonly List<string> AllowedValues =
|
private static readonly List<string> AllowedValues =
|
||||||
[
|
[
|
|
@ -1,13 +1,13 @@
|
||||||
using System.Text.Json.Nodes;
|
using System.Text.Json.Nodes;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using Octobot.Extensions;
|
|
||||||
using Remora.Discord.Extensions.Formatting;
|
using Remora.Discord.Extensions.Formatting;
|
||||||
using Remora.Rest.Core;
|
using Remora.Rest.Core;
|
||||||
using Remora.Results;
|
using Remora.Results;
|
||||||
|
using TeamOctolings.Octobot.Extensions;
|
||||||
|
|
||||||
namespace Octobot.Data.Options;
|
namespace TeamOctolings.Octobot.Data.Options;
|
||||||
|
|
||||||
public sealed partial class SnowflakeOption : Option<Snowflake>
|
public sealed partial class SnowflakeOption : GuildOption<Snowflake>
|
||||||
{
|
{
|
||||||
public SnowflakeOption(string name) : base(name, 0UL.ToSnowflake()) { }
|
public SnowflakeOption(string name) : base(name, 0UL.ToSnowflake()) { }
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
using System.Text.Json.Nodes;
|
using System.Text.Json.Nodes;
|
||||||
using Octobot.Parsers;
|
|
||||||
using Remora.Results;
|
using Remora.Results;
|
||||||
|
using TeamOctolings.Octobot.Parsers;
|
||||||
|
|
||||||
namespace Octobot.Data.Options;
|
namespace TeamOctolings.Octobot.Data.Options;
|
||||||
|
|
||||||
public sealed class TimeSpanOption : Option<TimeSpan>
|
public sealed class TimeSpanOption : GuildOption<TimeSpan>
|
||||||
{
|
{
|
||||||
public TimeSpanOption(string name, TimeSpan defaultValue) : base(name, defaultValue) { }
|
public TimeSpanOption(string name, TimeSpan defaultValue) : base(name, defaultValue) { }
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
namespace Octobot.Data;
|
namespace TeamOctolings.Octobot.Data;
|
||||||
|
|
||||||
public struct Reminder
|
public struct Reminder
|
||||||
{
|
{
|
|
@ -1,7 +1,7 @@
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
using Remora.Discord.API.Abstractions.Objects;
|
using Remora.Discord.API.Abstractions.Objects;
|
||||||
|
|
||||||
namespace Octobot.Data;
|
namespace TeamOctolings.Octobot.Data;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Stores information about scheduled events. This information is not provided by the Discord API.
|
/// Stores information about scheduled events. This information is not provided by the Discord API.
|
|
@ -1,4 +1,4 @@
|
||||||
namespace Octobot.Data;
|
namespace TeamOctolings.Octobot.Data;
|
||||||
|
|
||||||
public struct Warn
|
public struct Warn
|
||||||
{
|
{
|
|
@ -5,18 +5,19 @@ using Remora.Discord.API.Objects;
|
||||||
using Remora.Rest.Core;
|
using Remora.Rest.Core;
|
||||||
using Remora.Results;
|
using Remora.Results;
|
||||||
|
|
||||||
namespace Octobot.Extensions;
|
namespace TeamOctolings.Octobot.Extensions;
|
||||||
|
|
||||||
public static class ChannelApiExtensions
|
public static class ChannelApiExtensions
|
||||||
{
|
{
|
||||||
public static async Task<Result> CreateMessageWithEmbedResultAsync(this IDiscordRestChannelAPI channelApi,
|
public static async Task<Result> CreateMessageWithEmbedResultAsync(this IDiscordRestChannelAPI channelApi,
|
||||||
Snowflake channelId, Optional<string> message = default, Optional<string> nonce = default,
|
Snowflake channelId, Optional<string> message = default, Optional<string> nonce = default,
|
||||||
Optional<bool> isTextToSpeech = default, Optional<Result<Embed>> embedResult = default,
|
Optional<bool> isTextToSpeech = default, Optional<Result<Embed>> embedResult = default,
|
||||||
Optional<IAllowedMentions> allowedMentions = default, Optional<IMessageReference> messageRefenence = default,
|
Optional<IAllowedMentions> allowedMentions = default, Optional<IMessageReference> messageReference = default,
|
||||||
Optional<IReadOnlyList<IMessageComponent>> components = default,
|
Optional<IReadOnlyList<IMessageComponent>> components = default,
|
||||||
Optional<IReadOnlyList<Snowflake>> stickerIds = default,
|
Optional<IReadOnlyList<Snowflake>> stickerIds = default,
|
||||||
Optional<IReadOnlyList<OneOf<FileData, IPartialAttachment>>> attachments = default,
|
Optional<IReadOnlyList<OneOf<FileData, IPartialAttachment>>> attachments = default,
|
||||||
Optional<MessageFlags> flags = default, CancellationToken ct = default)
|
Optional<MessageFlags> flags = default, Optional<bool> enforceNonce = default,
|
||||||
|
Optional<IPollCreateRequest> poll = default, CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
if (!embedResult.IsDefined() || !embedResult.Value.IsDefined(out var embed))
|
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 },
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
using Remora.Results;
|
using Remora.Results;
|
||||||
|
|
||||||
namespace Octobot.Extensions;
|
namespace TeamOctolings.Octobot.Extensions;
|
||||||
|
|
||||||
public static class CollectionExtensions
|
public static class CollectionExtensions
|
||||||
{
|
{
|
|
@ -2,7 +2,7 @@
|
||||||
using Remora.Discord.Commands.Extensions;
|
using Remora.Discord.Commands.Extensions;
|
||||||
using Remora.Rest.Core;
|
using Remora.Rest.Core;
|
||||||
|
|
||||||
namespace Octobot.Extensions;
|
namespace TeamOctolings.Octobot.Extensions;
|
||||||
|
|
||||||
public static class CommandContextExtensions
|
public static class CommandContextExtensions
|
||||||
{
|
{
|
|
@ -1,7 +1,7 @@
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using DiffPlex.DiffBuilder.Model;
|
using DiffPlex.DiffBuilder.Model;
|
||||||
|
|
||||||
namespace Octobot.Extensions;
|
namespace TeamOctolings.Octobot.Extensions;
|
||||||
|
|
||||||
public static class DiffPaneModelExtensions
|
public static class DiffPaneModelExtensions
|
||||||
{
|
{
|
|
@ -4,7 +4,7 @@ using Remora.Discord.API.Objects;
|
||||||
using Remora.Discord.Extensions.Embeds;
|
using Remora.Discord.Extensions.Embeds;
|
||||||
using Remora.Rest.Core;
|
using Remora.Rest.Core;
|
||||||
|
|
||||||
namespace Octobot.Extensions;
|
namespace TeamOctolings.Octobot.Extensions;
|
||||||
|
|
||||||
public static class EmbedBuilderExtensions
|
public static class EmbedBuilderExtensions
|
||||||
{
|
{
|
|
@ -3,7 +3,7 @@ using Remora.Discord.Commands.Feedback.Messages;
|
||||||
using Remora.Discord.Commands.Feedback.Services;
|
using Remora.Discord.Commands.Feedback.Services;
|
||||||
using Remora.Results;
|
using Remora.Results;
|
||||||
|
|
||||||
namespace Octobot.Extensions;
|
namespace TeamOctolings.Octobot.Extensions;
|
||||||
|
|
||||||
public static class FeedbackServiceExtensions
|
public static class FeedbackServiceExtensions
|
||||||
{
|
{
|
|
@ -2,7 +2,7 @@
|
||||||
using Remora.Rest.Core;
|
using Remora.Rest.Core;
|
||||||
using Remora.Results;
|
using Remora.Results;
|
||||||
|
|
||||||
namespace Octobot.Extensions;
|
namespace TeamOctolings.Octobot.Extensions;
|
||||||
|
|
||||||
public static class GuildScheduledEventExtensions
|
public static class GuildScheduledEventExtensions
|
||||||
{
|
{
|
|
@ -1,7 +1,7 @@
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Remora.Results;
|
using Remora.Results;
|
||||||
|
|
||||||
namespace Octobot.Extensions;
|
namespace TeamOctolings.Octobot.Extensions;
|
||||||
|
|
||||||
public static class LoggerExtensions
|
public static class LoggerExtensions
|
||||||
{
|
{
|
|
@ -1,4 +1,4 @@
|
||||||
namespace Octobot.Extensions;
|
namespace TeamOctolings.Octobot.Extensions;
|
||||||
|
|
||||||
public static class MarkdownExtensions
|
public static class MarkdownExtensions
|
||||||
{
|
{
|
|
@ -2,7 +2,7 @@
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Remora.Results;
|
using Remora.Results;
|
||||||
|
|
||||||
namespace Octobot.Extensions;
|
namespace TeamOctolings.Octobot.Extensions;
|
||||||
|
|
||||||
public static class ResultExtensions
|
public static class ResultExtensions
|
||||||
{
|
{
|
||||||
|
@ -21,21 +21,25 @@ public static class ResultExtensions
|
||||||
return casted;
|
return casted;
|
||||||
}
|
}
|
||||||
|
|
||||||
[Conditional("DEBUG")]
|
|
||||||
private static void LogResultStackTrace(Result result)
|
private static void LogResultStackTrace(Result result)
|
||||||
{
|
{
|
||||||
if (Octobot.StaticLogger is null || result.IsSuccess)
|
if (result.IsSuccess)
|
||||||
{
|
{
|
||||||
return;
|
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());
|
result.Error.GetType().FullName, result.Error.Message, Environment.NewLine, ConstructStackTrace());
|
||||||
|
|
||||||
var inner = result.Inner;
|
var inner = result.Inner;
|
||||||
while (inner is { IsSuccess: false })
|
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.Error.GetType().FullName, inner.Error.Message);
|
||||||
|
|
||||||
inner = inner.Inner;
|
inner = inner.Inner;
|
|
@ -1,6 +1,6 @@
|
||||||
using Remora.Rest.Core;
|
using Remora.Rest.Core;
|
||||||
|
|
||||||
namespace Octobot.Extensions;
|
namespace TeamOctolings.Octobot.Extensions;
|
||||||
|
|
||||||
public static class SnowflakeExtensions
|
public static class SnowflakeExtensions
|
||||||
{
|
{
|
|
@ -1,6 +1,6 @@
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace Octobot.Extensions;
|
namespace TeamOctolings.Octobot.Extensions;
|
||||||
|
|
||||||
public static class StringBuilderExtensions
|
public static class StringBuilderExtensions
|
||||||
{
|
{
|
|
@ -1,7 +1,7 @@
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using Remora.Discord.Extensions.Formatting;
|
using Remora.Discord.Extensions.Formatting;
|
||||||
|
|
||||||
namespace Octobot.Extensions;
|
namespace TeamOctolings.Octobot.Extensions;
|
||||||
|
|
||||||
public static class StringExtensions
|
public static class StringExtensions
|
||||||
{
|
{
|
|
@ -1,7 +1,7 @@
|
||||||
using Remora.Discord.API;
|
using Remora.Discord.API;
|
||||||
using Remora.Rest.Core;
|
using Remora.Rest.Core;
|
||||||
|
|
||||||
namespace Octobot.Extensions;
|
namespace TeamOctolings.Octobot.Extensions;
|
||||||
|
|
||||||
public static class UInt64Extensions
|
public static class UInt64Extensions
|
||||||
{
|
{
|
|
@ -1,6 +1,6 @@
|
||||||
using Remora.Discord.API.Abstractions.Objects;
|
using Remora.Discord.API.Abstractions.Objects;
|
||||||
|
|
||||||
namespace Octobot.Extensions;
|
namespace TeamOctolings.Octobot.Extensions;
|
||||||
|
|
||||||
public static class UserExtensions
|
public static class UserExtensions
|
||||||
{
|
{
|
|
@ -7,7 +7,10 @@
|
||||||
// </auto-generated>
|
// </auto-generated>
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
namespace Octobot {
|
namespace TeamOctolings.Octobot {
|
||||||
|
using System;
|
||||||
|
|
||||||
|
|
||||||
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
|
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
|
||||||
[System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
[System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||||
[System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
[System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||||
|
@ -25,7 +28,7 @@ namespace Octobot {
|
||||||
internal static System.Resources.ResourceManager ResourceManager {
|
internal static System.Resources.ResourceManager ResourceManager {
|
||||||
get {
|
get {
|
||||||
if (object.Equals(null, resourceMan)) {
|
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;
|
resourceMan = temp;
|
||||||
}
|
}
|
||||||
return resourceMan;
|
return resourceMan;
|
||||||
|
@ -120,9 +123,9 @@ namespace Octobot {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static string SettingsLang {
|
internal static string SettingsLanguage {
|
||||||
get {
|
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 {
|
internal static string DurationRequiredForTimeOuts {
|
||||||
get {
|
get {
|
||||||
return ResourceManager.GetString("DurationRequiredForTimeOuts", resourceCulture);
|
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 {
|
internal static string UserCannotBanMembers {
|
||||||
get {
|
get {
|
||||||
return ResourceManager.GetString("UserCannotBanMembers", resourceCulture);
|
return ResourceManager.GetString("UserCannotBanMembers", resourceCulture);
|
||||||
|
@ -300,9 +297,15 @@ namespace Octobot {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static string UserCannotModerateMembers {
|
internal static string UserCannotMuteMembers {
|
||||||
get {
|
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 {
|
internal static string Page {
|
||||||
get {
|
get {
|
||||||
return ResourceManager.GetString("Page", resourceCulture);
|
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 {
|
internal static string UserInfoDisplayName {
|
||||||
get {
|
get {
|
||||||
return ResourceManager.GetString("UserInfoDisplayName", resourceCulture);
|
return ResourceManager.GetString("UserInfoDisplayName", resourceCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static string UserInfoDiscordUserSince {
|
internal static string InformationAbout {
|
||||||
get {
|
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 {
|
internal static string UserInfoBanned {
|
||||||
get {
|
get {
|
||||||
return ResourceManager.GetString("UserInfoBanned", resourceCulture);
|
return ResourceManager.GetString("UserInfoBanned", resourceCulture);
|
||||||
|
@ -882,157 +891,122 @@ namespace Octobot {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static string RandomTitle
|
internal static string RandomTitle {
|
||||||
{
|
|
||||||
get {
|
get {
|
||||||
return ResourceManager.GetString("RandomTitle", resourceCulture);
|
return ResourceManager.GetString("RandomTitle", resourceCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static string RandomMinMaxSame
|
internal static string RandomMinMaxSame {
|
||||||
{
|
|
||||||
get {
|
get {
|
||||||
return ResourceManager.GetString("RandomMinMaxSame", resourceCulture);
|
return ResourceManager.GetString("RandomMinMaxSame", resourceCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static string RandomMax
|
internal static string RandomMin {
|
||||||
{
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("RandomMax", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static string RandomMin
|
|
||||||
{
|
|
||||||
get {
|
get {
|
||||||
return ResourceManager.GetString("RandomMin", resourceCulture);
|
return ResourceManager.GetString("RandomMin", resourceCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static string Default
|
internal static string RandomMax {
|
||||||
{
|
get {
|
||||||
|
return ResourceManager.GetString("RandomMax", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static string Default {
|
||||||
get {
|
get {
|
||||||
return ResourceManager.GetString("Default", resourceCulture);
|
return ResourceManager.GetString("Default", resourceCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static string TimestampTitle
|
internal static string TimestampTitle {
|
||||||
{
|
get {
|
||||||
get
|
|
||||||
{
|
|
||||||
return ResourceManager.GetString("TimestampTitle", resourceCulture);
|
return ResourceManager.GetString("TimestampTitle", resourceCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static string TimestampOffset
|
internal static string TimestampOffset {
|
||||||
{
|
get {
|
||||||
get
|
|
||||||
{
|
|
||||||
return ResourceManager.GetString("TimestampOffset", resourceCulture);
|
return ResourceManager.GetString("TimestampOffset", resourceCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static string GuildInfoDescription
|
internal static string GuildInfoDescription {
|
||||||
{
|
get {
|
||||||
get
|
|
||||||
{
|
|
||||||
return ResourceManager.GetString("GuildInfoDescription", resourceCulture);
|
return ResourceManager.GetString("GuildInfoDescription", resourceCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static string GuildInfoCreatedAt
|
internal static string GuildInfoCreatedAt {
|
||||||
{
|
get {
|
||||||
get
|
|
||||||
{
|
|
||||||
return ResourceManager.GetString("GuildInfoCreatedAt", resourceCulture);
|
return ResourceManager.GetString("GuildInfoCreatedAt", resourceCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static string GuildInfoOwner
|
internal static string GuildInfoOwner {
|
||||||
{
|
get {
|
||||||
get
|
|
||||||
{
|
|
||||||
return ResourceManager.GetString("GuildInfoOwner", resourceCulture);
|
return ResourceManager.GetString("GuildInfoOwner", resourceCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static string GuildInfoServerBoost
|
internal static string GuildInfoServerBoost {
|
||||||
{
|
get {
|
||||||
get
|
|
||||||
{
|
|
||||||
return ResourceManager.GetString("GuildInfoServerBoost", resourceCulture);
|
return ResourceManager.GetString("GuildInfoServerBoost", resourceCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static string GuildInfoBoostTier
|
internal static string GuildInfoBoostTier {
|
||||||
{
|
get {
|
||||||
get
|
|
||||||
{
|
|
||||||
return ResourceManager.GetString("GuildInfoBoostTier", resourceCulture);
|
return ResourceManager.GetString("GuildInfoBoostTier", resourceCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static string GuildInfoBoostCount
|
internal static string GuildInfoBoostCount {
|
||||||
{
|
get {
|
||||||
get
|
|
||||||
{
|
|
||||||
return ResourceManager.GetString("GuildInfoBoostCount", resourceCulture);
|
return ResourceManager.GetString("GuildInfoBoostCount", resourceCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static string NoMessagesToClear
|
internal static string NoMessagesToClear {
|
||||||
{
|
get {
|
||||||
get
|
|
||||||
{
|
|
||||||
return ResourceManager.GetString("NoMessagesToClear", resourceCulture);
|
return ResourceManager.GetString("NoMessagesToClear", resourceCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static string MessagesClearedFiltered
|
internal static string MessagesClearedFiltered {
|
||||||
{
|
get {
|
||||||
get
|
|
||||||
{
|
|
||||||
return ResourceManager.GetString("MessagesClearedFiltered", resourceCulture);
|
return ResourceManager.GetString("MessagesClearedFiltered", resourceCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static string DataLoadFailedTitle
|
internal static string DataLoadFailedTitle {
|
||||||
{
|
get {
|
||||||
get
|
|
||||||
{
|
|
||||||
return ResourceManager.GetString("DataLoadFailedTitle", resourceCulture);
|
return ResourceManager.GetString("DataLoadFailedTitle", resourceCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static string DataLoadFailedDescription
|
internal static string DataLoadFailedDescription {
|
||||||
{
|
get {
|
||||||
get
|
|
||||||
{
|
|
||||||
return ResourceManager.GetString("DataLoadFailedDescription", resourceCulture);
|
return ResourceManager.GetString("DataLoadFailedDescription", resourceCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static string CommandExecutionFailed
|
internal static string CommandExecutionFailed {
|
||||||
{
|
get {
|
||||||
get
|
|
||||||
{
|
|
||||||
return ResourceManager.GetString("CommandExecutionFailed", resourceCulture);
|
return ResourceManager.GetString("CommandExecutionFailed", resourceCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static string ContactDevelopers
|
internal static string ContactDevelopers {
|
||||||
{
|
get {
|
||||||
get
|
|
||||||
{
|
|
||||||
return ResourceManager.GetString("ContactDevelopers", resourceCulture);
|
return ResourceManager.GetString("ContactDevelopers", resourceCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static string ButtonReportIssue
|
internal static string ButtonReportIssue {
|
||||||
{
|
get {
|
||||||
get
|
|
||||||
{
|
|
||||||
return ResourceManager.GetString("ButtonReportIssue", resourceCulture);
|
return ResourceManager.GetString("ButtonReportIssue", resourceCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1205,62 +1179,53 @@ namespace Octobot {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static string UserWarned
|
internal static string UserWarned {
|
||||||
{
|
|
||||||
get {
|
get {
|
||||||
return ResourceManager.GetString("UserWarned", resourceCulture);
|
return ResourceManager.GetString("UserWarned", resourceCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static string UserWarnsRemoved
|
internal static string UserWarnsRemoved {
|
||||||
{
|
|
||||||
get {
|
get {
|
||||||
return ResourceManager.GetString("UserWarnsRemoved", resourceCulture);
|
return ResourceManager.GetString("UserWarnsRemoved", resourceCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static string YouHaveBeenWarned
|
internal static string YouHaveBeenWarned {
|
||||||
{
|
|
||||||
get {
|
get {
|
||||||
return ResourceManager.GetString("YouHaveBeenWarned", resourceCulture);
|
return ResourceManager.GetString("YouHaveBeenWarned", resourceCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static string YourWarningsHaveBeenRevoked
|
internal static string YourWarningsHaveBeenRevoked {
|
||||||
{
|
|
||||||
get {
|
get {
|
||||||
return ResourceManager.GetString("YourWarningsHaveBeenRevoked", resourceCulture);
|
return ResourceManager.GetString("YourWarningsHaveBeenRevoked", resourceCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static string DescriptionWarns
|
internal static string DescriptionWarns {
|
||||||
{
|
|
||||||
get {
|
get {
|
||||||
return ResourceManager.GetString("DescriptionWarns", resourceCulture);
|
return ResourceManager.GetString("DescriptionWarns", resourceCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static string UserHasNoWarnings
|
internal static string UserHasNoWarnings {
|
||||||
{
|
|
||||||
get {
|
get {
|
||||||
return ResourceManager.GetString("UserHasNoWarnings", resourceCulture);
|
return ResourceManager.GetString("UserHasNoWarnings", resourceCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static string YouHaveNoWarnings
|
internal static string YouHaveNoWarnings {
|
||||||
{
|
|
||||||
get {
|
get {
|
||||||
return ResourceManager.GetString("YouHaveNoWarnings", resourceCulture);
|
return ResourceManager.GetString("YouHaveNoWarnings", resourceCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static string ReceivedTooManyWarnings
|
internal static string ReceivedTooManyWarnings {
|
||||||
{
|
|
||||||
get {
|
get {
|
||||||
return ResourceManager.GetString("ReceivedTooManyWarnings", resourceCulture);
|
return ResourceManager.GetString("ReceivedTooManyWarnings", resourceCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static string ButtonDirty {
|
internal static string ButtonDirty {
|
||||||
get {
|
get {
|
||||||
return ResourceManager.GetString("ButtonDirty", resourceCulture);
|
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 {
|
get {
|
||||||
return ResourceManager.GetString("ListTargetWarnsTitle", resourceCulture);
|
return ResourceManager.GetString("ListTargetWarnsTitle", resourceCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static string ReceivedOn
|
internal static string ReceivedOn {
|
||||||
{
|
|
||||||
get {
|
get {
|
||||||
return ResourceManager.GetString("ReceivedOn", resourceCulture);
|
return ResourceManager.GetString("ReceivedOn", resourceCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static string UserWarnRemoved
|
internal static string UserWarnRemoved {
|
||||||
{
|
|
||||||
get {
|
get {
|
||||||
return ResourceManager.GetString("UserWarnRemoved", resourceCulture);
|
return ResourceManager.GetString("UserWarnRemoved", resourceCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static string YourWarningHasBeenRevoked
|
internal static string YourWarningHasBeenRevoked {
|
||||||
{
|
|
||||||
get {
|
get {
|
||||||
return ResourceManager.GetString("YourWarningHasBeenRevoked", resourceCulture);
|
return ResourceManager.GetString("YourWarningHasBeenRevoked", resourceCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static string WrongWarningNumberSelected
|
internal static string WrongWarningNumberSelected {
|
||||||
{
|
|
||||||
get {
|
get {
|
||||||
return ResourceManager.GetString("WrongWarningNumberSelected", resourceCulture);
|
return ResourceManager.GetString("WrongWarningNumberSelected", resourceCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static string ListExecutorWarnsTitle
|
internal static string ListExecutorWarnsTitle {
|
||||||
{
|
|
||||||
get {
|
get {
|
||||||
return ResourceManager.GetString("ListExecutorWarnsTitle", resourceCulture);
|
return ResourceManager.GetString("ListExecutorWarnsTitle", resourceCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static string DescriptionPunishmentType
|
internal static string DescriptionPunishmentType {
|
||||||
{
|
|
||||||
get {
|
get {
|
||||||
return ResourceManager.GetString("DescriptionPunishmentType", resourceCulture);
|
return ResourceManager.GetString("DescriptionPunishmentType", resourceCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static string WarnThresholdExceeded
|
internal static string WarnThresholdExceeded {
|
||||||
{
|
|
||||||
get {
|
get {
|
||||||
return ResourceManager.GetString("WarnThresholdExceeded", resourceCulture);
|
return ResourceManager.GetString("WarnThresholdExceeded", resourceCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static string WarnPunishmentDurationNotSet
|
internal static string WarnPunishmentDurationNotSet {
|
||||||
{
|
get {
|
||||||
get
|
|
||||||
{
|
|
||||||
return ResourceManager.GetString("WarnPunishmentDurationNotSet", resourceCulture);
|
return ResourceManager.GetString("WarnPunishmentDurationNotSet", resourceCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static string WarnThresholdExceededDescription
|
internal static string WarnThresholdExceededDescription {
|
||||||
{
|
get {
|
||||||
get
|
|
||||||
{
|
|
||||||
return ResourceManager.GetString("WarnThresholdExceededDescription", resourceCulture);
|
return ResourceManager.GetString("WarnThresholdExceededDescription", resourceCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static string InvalidWarnPunishment
|
internal static string InvalidWarnPunishment {
|
||||||
{
|
get {
|
||||||
get
|
|
||||||
{
|
|
||||||
return ResourceManager.GetString("InvalidWarnPunishment", resourceCulture);
|
return ResourceManager.GetString("InvalidWarnPunishment", resourceCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -4,7 +4,7 @@ using JetBrains.Annotations;
|
||||||
using Remora.Commands.Parsers;
|
using Remora.Commands.Parsers;
|
||||||
using Remora.Results;
|
using Remora.Results;
|
||||||
|
|
||||||
namespace Octobot.Parsers;
|
namespace TeamOctolings.Octobot.Parsers;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Parses <see cref="TimeSpan"/>s.
|
/// Parses <see cref="TimeSpan"/>s.
|
|
@ -2,13 +2,8 @@ using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Hosting;
|
||||||
using Microsoft.Extensions.Logging;
|
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.Gateway.Commands;
|
||||||
using Remora.Discord.API.Abstractions.Objects;
|
using Remora.Discord.API.Abstractions.Objects;
|
||||||
using Remora.Discord.API.Objects;
|
|
||||||
using Remora.Discord.Caching.Extensions;
|
using Remora.Discord.Caching.Extensions;
|
||||||
using Remora.Discord.Caching.Services;
|
using Remora.Discord.Caching.Services;
|
||||||
using Remora.Discord.Commands.Extensions;
|
using Remora.Discord.Commands.Extensions;
|
||||||
|
@ -16,24 +11,20 @@ using Remora.Discord.Commands.Services;
|
||||||
using Remora.Discord.Extensions.Extensions;
|
using Remora.Discord.Extensions.Extensions;
|
||||||
using Remora.Discord.Gateway;
|
using Remora.Discord.Gateway;
|
||||||
using Remora.Discord.Hosting.Extensions;
|
using Remora.Discord.Hosting.Extensions;
|
||||||
using Remora.Rest.Core;
|
|
||||||
using Serilog.Extensions.Logging;
|
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<MentionType>(), Array.Empty<Snowflake>(), Array.Empty<Snowflake>());
|
|
||||||
|
|
||||||
[StaticCallersOnly]
|
|
||||||
public static ILogger<Octobot>? StaticLogger { get; private set; }
|
|
||||||
|
|
||||||
public static async Task Main(string[] args)
|
public static async Task Main(string[] args)
|
||||||
{
|
{
|
||||||
var host = CreateHostBuilder(args).UseConsoleLifetime().Build();
|
var host = CreateHostBuilder(args).UseConsoleLifetime().Build();
|
||||||
var services = host.Services;
|
var services = host.Services;
|
||||||
StaticLogger = services.GetRequiredService<ILogger<Octobot>>();
|
Utility.StaticLogger = services.GetRequiredService<ILogger<Program>>();
|
||||||
|
|
||||||
var slashService = services.GetRequiredService<SlashService>();
|
var slashService = services.GetRequiredService<SlashService>();
|
||||||
// Providing a guild ID to this call will result in command duplicates!
|
// Providing a guild ID to this call will result in command duplicates!
|
||||||
|
@ -82,8 +73,8 @@ public sealed class Octobot
|
||||||
// Init
|
// Init
|
||||||
.AddDiscordCaching()
|
.AddDiscordCaching()
|
||||||
.AddDiscordCommands(true, false)
|
.AddDiscordCommands(true, false)
|
||||||
.AddRespondersFromAssembly(typeof(Octobot).Assembly)
|
.AddRespondersFromAssembly(typeof(Program).Assembly)
|
||||||
.AddCommandGroupsFromAssembly(typeof(Octobot).Assembly)
|
.AddCommandGroupsFromAssembly(typeof(Program).Assembly)
|
||||||
// Slash command event handlers
|
// Slash command event handlers
|
||||||
.AddPreparationErrorEvent<LoggingPreparationErrorEvent>()
|
.AddPreparationErrorEvent<LoggingPreparationErrorEvent>()
|
||||||
.AddPostExecutionEvent<ErrorLoggingPostExecutionEvent>()
|
.AddPostExecutionEvent<ErrorLoggingPostExecutionEvent>()
|
|
@ -1,8 +1,5 @@
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Microsoft.Extensions.Logging;
|
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.Gateway.Events;
|
||||||
using Remora.Discord.API.Abstractions.Objects;
|
using Remora.Discord.API.Abstractions.Objects;
|
||||||
using Remora.Discord.API.Abstractions.Rest;
|
using Remora.Discord.API.Abstractions.Rest;
|
||||||
|
@ -11,15 +8,18 @@ using Remora.Discord.API.Objects;
|
||||||
using Remora.Discord.Extensions.Embeds;
|
using Remora.Discord.Extensions.Embeds;
|
||||||
using Remora.Discord.Gateway.Responders;
|
using Remora.Discord.Gateway.Responders;
|
||||||
using Remora.Results;
|
using Remora.Results;
|
||||||
|
using TeamOctolings.Octobot.Data;
|
||||||
|
using TeamOctolings.Octobot.Extensions;
|
||||||
|
using TeamOctolings.Octobot.Services;
|
||||||
|
|
||||||
namespace Octobot.Responders;
|
namespace TeamOctolings.Octobot.Responders;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles sending a <see cref="Ready" /> message to a guild that has just initialized if that guild
|
/// Handles sending a <see cref="Ready" /> message to a guild that has just initialized if that guild
|
||||||
/// has <see cref="GuildSettings.ReceiveStartupMessages" /> enabled
|
/// has <see cref="GuildSettings.ReceiveStartupMessages" /> enabled
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[UsedImplicitly]
|
[UsedImplicitly]
|
||||||
public class GuildLoadedResponder : IResponder<IGuildCreate>
|
public sealed class GuildLoadedResponder : IResponder<IGuildCreate>
|
||||||
{
|
{
|
||||||
private readonly IDiscordRestChannelAPI _channelApi;
|
private readonly IDiscordRestChannelAPI _channelApi;
|
||||||
private readonly GuildDataService _guildData;
|
private readonly GuildDataService _guildData;
|
|
@ -1,16 +1,16 @@
|
||||||
using System.Text.Json.Nodes;
|
using System.Text.Json.Nodes;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Octobot.Data;
|
|
||||||
using Octobot.Extensions;
|
|
||||||
using Octobot.Services;
|
|
||||||
using Remora.Discord.API.Abstractions.Gateway.Events;
|
using Remora.Discord.API.Abstractions.Gateway.Events;
|
||||||
using Remora.Discord.API.Abstractions.Rest;
|
using Remora.Discord.API.Abstractions.Rest;
|
||||||
using Remora.Discord.Extensions.Embeds;
|
using Remora.Discord.Extensions.Embeds;
|
||||||
using Remora.Discord.Gateway.Responders;
|
using Remora.Discord.Gateway.Responders;
|
||||||
using Remora.Rest.Core;
|
using Remora.Rest.Core;
|
||||||
using Remora.Results;
|
using Remora.Results;
|
||||||
|
using TeamOctolings.Octobot.Data;
|
||||||
|
using TeamOctolings.Octobot.Extensions;
|
||||||
|
using TeamOctolings.Octobot.Services;
|
||||||
|
|
||||||
namespace Octobot.Responders;
|
namespace TeamOctolings.Octobot.Responders;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles sending a guild's <see cref="GuildSettings.WelcomeMessage" /> if one is set.
|
/// Handles sending a guild's <see cref="GuildSettings.WelcomeMessage" /> if one is set.
|
||||||
|
@ -18,7 +18,7 @@ namespace Octobot.Responders;
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <seealso cref="GuildSettings.WelcomeMessage" />
|
/// <seealso cref="GuildSettings.WelcomeMessage" />
|
||||||
[UsedImplicitly]
|
[UsedImplicitly]
|
||||||
public class GuildMemberJoinedResponder : IResponder<IGuildMemberAdd>
|
public sealed class GuildMemberJoinedResponder : IResponder<IGuildMemberAdd>
|
||||||
{
|
{
|
||||||
private readonly IDiscordRestChannelAPI _channelApi;
|
private readonly IDiscordRestChannelAPI _channelApi;
|
||||||
private readonly IDiscordRestGuildAPI _guildApi;
|
private readonly IDiscordRestGuildAPI _guildApi;
|
||||||
|
@ -77,7 +77,7 @@ public class GuildMemberJoinedResponder : IResponder<IGuildMemberAdd>
|
||||||
|
|
||||||
return await _channelApi.CreateMessageWithEmbedResultAsync(
|
return await _channelApi.CreateMessageWithEmbedResultAsync(
|
||||||
GuildSettings.WelcomeMessagesChannel.Get(cfg), embedResult: embed,
|
GuildSettings.WelcomeMessagesChannel.Get(cfg), embedResult: embed,
|
||||||
allowedMentions: Octobot.NoMentions, ct: ct);
|
allowedMentions: Utility.NoMentions, ct: ct);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<Result> TryReturnRolesAsync(
|
private async Task<Result> TryReturnRolesAsync(
|
|
@ -1,21 +1,21 @@
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Octobot.Data;
|
|
||||||
using Octobot.Extensions;
|
|
||||||
using Octobot.Services;
|
|
||||||
using Remora.Discord.API.Abstractions.Gateway.Events;
|
using Remora.Discord.API.Abstractions.Gateway.Events;
|
||||||
using Remora.Discord.API.Abstractions.Rest;
|
using Remora.Discord.API.Abstractions.Rest;
|
||||||
using Remora.Discord.Extensions.Embeds;
|
using Remora.Discord.Extensions.Embeds;
|
||||||
using Remora.Discord.Gateway.Responders;
|
using Remora.Discord.Gateway.Responders;
|
||||||
using Remora.Results;
|
using Remora.Results;
|
||||||
|
using TeamOctolings.Octobot.Data;
|
||||||
|
using TeamOctolings.Octobot.Extensions;
|
||||||
|
using TeamOctolings.Octobot.Services;
|
||||||
|
|
||||||
namespace Octobot.Responders;
|
namespace TeamOctolings.Octobot.Responders;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles sending a guild's <see cref="GuildSettings.LeaveMessage" /> if one is set.
|
/// Handles sending a guild's <see cref="GuildSettings.LeaveMessage" /> if one is set.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <seealso cref="GuildSettings.LeaveMessage" />
|
/// <seealso cref="GuildSettings.LeaveMessage" />
|
||||||
[UsedImplicitly]
|
[UsedImplicitly]
|
||||||
public class GuildMemberLeftResponder : IResponder<IGuildMemberRemove>
|
public sealed class GuildMemberLeftResponder : IResponder<IGuildMemberRemove>
|
||||||
{
|
{
|
||||||
private readonly IDiscordRestChannelAPI _channelApi;
|
private readonly IDiscordRestChannelAPI _channelApi;
|
||||||
private readonly IDiscordRestGuildAPI _guildApi;
|
private readonly IDiscordRestGuildAPI _guildApi;
|
||||||
|
@ -67,6 +67,6 @@ public class GuildMemberLeftResponder : IResponder<IGuildMemberRemove>
|
||||||
|
|
||||||
return await _channelApi.CreateMessageWithEmbedResultAsync(
|
return await _channelApi.CreateMessageWithEmbedResultAsync(
|
||||||
GuildSettings.WelcomeMessagesChannel.Get(cfg), embedResult: embed,
|
GuildSettings.WelcomeMessagesChannel.Get(cfg), embedResult: embed,
|
||||||
allowedMentions: Octobot.NoMentions, ct: ct);
|
allowedMentions: Utility.NoMentions, ct: ct);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,18 +1,18 @@
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Octobot.Data;
|
|
||||||
using Octobot.Services;
|
|
||||||
using Remora.Discord.API.Abstractions.Gateway.Events;
|
using Remora.Discord.API.Abstractions.Gateway.Events;
|
||||||
using Remora.Discord.Gateway.Responders;
|
using Remora.Discord.Gateway.Responders;
|
||||||
using Remora.Results;
|
using Remora.Results;
|
||||||
|
using TeamOctolings.Octobot.Data;
|
||||||
|
using TeamOctolings.Octobot.Services;
|
||||||
|
|
||||||
namespace Octobot.Responders;
|
namespace TeamOctolings.Octobot.Responders;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles removing guild ID from <see cref="GuildData" /> if the guild becomes unavailable.
|
/// Handles removing guild ID from <see cref="GuildData" /> if the guild becomes unavailable.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[UsedImplicitly]
|
[UsedImplicitly]
|
||||||
public class GuildUnloadedResponder : IResponder<IGuildDelete>
|
public sealed class GuildUnloadedResponder : IResponder<IGuildDelete>
|
||||||
{
|
{
|
||||||
private readonly GuildDataService _guildData;
|
private readonly GuildDataService _guildData;
|
||||||
private readonly ILogger<GuildUnloadedResponder> _logger;
|
private readonly ILogger<GuildUnloadedResponder> _logger;
|
|
@ -1,8 +1,5 @@
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Octobot.Data;
|
|
||||||
using Octobot.Extensions;
|
|
||||||
using Octobot.Services;
|
|
||||||
using Remora.Discord.API.Abstractions.Gateway.Events;
|
using Remora.Discord.API.Abstractions.Gateway.Events;
|
||||||
using Remora.Discord.API.Abstractions.Objects;
|
using Remora.Discord.API.Abstractions.Objects;
|
||||||
using Remora.Discord.API.Abstractions.Rest;
|
using Remora.Discord.API.Abstractions.Rest;
|
||||||
|
@ -10,15 +7,18 @@ using Remora.Discord.Extensions.Embeds;
|
||||||
using Remora.Discord.Extensions.Formatting;
|
using Remora.Discord.Extensions.Formatting;
|
||||||
using Remora.Discord.Gateway.Responders;
|
using Remora.Discord.Gateway.Responders;
|
||||||
using Remora.Results;
|
using Remora.Results;
|
||||||
|
using TeamOctolings.Octobot.Data;
|
||||||
|
using TeamOctolings.Octobot.Extensions;
|
||||||
|
using TeamOctolings.Octobot.Services;
|
||||||
|
|
||||||
namespace Octobot.Responders;
|
namespace TeamOctolings.Octobot.Responders;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles logging the contents of a deleted message and the user who deleted the message
|
/// Handles logging the contents of a deleted message and the user who deleted the message
|
||||||
/// to a guild's <see cref="GuildSettings.PrivateFeedbackChannel" /> if one is set.
|
/// to a guild's <see cref="GuildSettings.PrivateFeedbackChannel" /> if one is set.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[UsedImplicitly]
|
[UsedImplicitly]
|
||||||
public class MessageDeletedResponder : IResponder<IMessageDelete>
|
public sealed class MessageDeletedResponder : IResponder<IMessageDelete>
|
||||||
{
|
{
|
||||||
private readonly IDiscordRestAuditLogAPI _auditLogApi;
|
private readonly IDiscordRestAuditLogAPI _auditLogApi;
|
||||||
private readonly IDiscordRestChannelAPI _channelApi;
|
private readonly IDiscordRestChannelAPI _channelApi;
|
||||||
|
@ -102,6 +102,6 @@ public class MessageDeletedResponder : IResponder<IMessageDelete>
|
||||||
|
|
||||||
return await _channelApi.CreateMessageWithEmbedResultAsync(
|
return await _channelApi.CreateMessageWithEmbedResultAsync(
|
||||||
GuildSettings.PrivateFeedbackChannel.Get(cfg), embedResult: embed,
|
GuildSettings.PrivateFeedbackChannel.Get(cfg), embedResult: embed,
|
||||||
allowedMentions: Octobot.NoMentions, ct: ct);
|
allowedMentions: Utility.NoMentions, ct: ct);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,9 +1,6 @@
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using DiffPlex.DiffBuilder;
|
using DiffPlex.DiffBuilder;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Octobot.Data;
|
|
||||||
using Octobot.Extensions;
|
|
||||||
using Octobot.Services;
|
|
||||||
using Remora.Discord.API.Abstractions.Gateway.Events;
|
using Remora.Discord.API.Abstractions.Gateway.Events;
|
||||||
using Remora.Discord.API.Abstractions.Objects;
|
using Remora.Discord.API.Abstractions.Objects;
|
||||||
using Remora.Discord.API.Abstractions.Rest;
|
using Remora.Discord.API.Abstractions.Rest;
|
||||||
|
@ -12,15 +9,18 @@ using Remora.Discord.Caching.Services;
|
||||||
using Remora.Discord.Extensions.Embeds;
|
using Remora.Discord.Extensions.Embeds;
|
||||||
using Remora.Discord.Gateway.Responders;
|
using Remora.Discord.Gateway.Responders;
|
||||||
using Remora.Results;
|
using Remora.Results;
|
||||||
|
using TeamOctolings.Octobot.Data;
|
||||||
|
using TeamOctolings.Octobot.Extensions;
|
||||||
|
using TeamOctolings.Octobot.Services;
|
||||||
|
|
||||||
namespace Octobot.Responders;
|
namespace TeamOctolings.Octobot.Responders;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles logging the difference between an edited message's old and new content
|
/// Handles logging the difference between an edited message's old and new content
|
||||||
/// to a guild's <see cref="GuildSettings.PrivateFeedbackChannel" /> if one is set.
|
/// to a guild's <see cref="GuildSettings.PrivateFeedbackChannel" /> if one is set.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[UsedImplicitly]
|
[UsedImplicitly]
|
||||||
public class MessageEditedResponder : IResponder<IMessageUpdate>
|
public sealed class MessageEditedResponder : IResponder<IMessageUpdate>
|
||||||
{
|
{
|
||||||
private readonly CacheService _cacheService;
|
private readonly CacheService _cacheService;
|
||||||
private readonly IDiscordRestChannelAPI _channelApi;
|
private readonly IDiscordRestChannelAPI _channelApi;
|
||||||
|
@ -104,6 +104,6 @@ public class MessageEditedResponder : IResponder<IMessageUpdate>
|
||||||
|
|
||||||
return await _channelApi.CreateMessageWithEmbedResultAsync(
|
return await _channelApi.CreateMessageWithEmbedResultAsync(
|
||||||
GuildSettings.PrivateFeedbackChannel.Get(cfg), embedResult: embed,
|
GuildSettings.PrivateFeedbackChannel.Get(cfg), embedResult: embed,
|
||||||
allowedMentions: Octobot.NoMentions, ct: ct);
|
allowedMentions: Utility.NoMentions, ct: ct);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -5,13 +5,13 @@ using Remora.Discord.Gateway.Responders;
|
||||||
using Remora.Rest.Core;
|
using Remora.Rest.Core;
|
||||||
using Remora.Results;
|
using Remora.Results;
|
||||||
|
|
||||||
namespace Octobot.Responders;
|
namespace TeamOctolings.Octobot.Responders;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles sending replies to easter egg messages.
|
/// Handles sending replies to easter egg messages.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[UsedImplicitly]
|
[UsedImplicitly]
|
||||||
public class MessageCreateResponder : IResponder<IMessageCreate>
|
public sealed class MessageCreateResponder : IResponder<IMessageCreate>
|
||||||
{
|
{
|
||||||
private readonly IDiscordRestChannelAPI _channelApi;
|
private readonly IDiscordRestChannelAPI _channelApi;
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
using Octobot.Data;
|
using Remora.Discord.API.Abstractions.Objects;
|
||||||
using Octobot.Extensions;
|
|
||||||
using Remora.Discord.API.Abstractions.Objects;
|
|
||||||
using Remora.Discord.API.Abstractions.Rest;
|
using Remora.Discord.API.Abstractions.Rest;
|
||||||
using Remora.Rest.Core;
|
using Remora.Rest.Core;
|
||||||
using Remora.Results;
|
using Remora.Results;
|
||||||
|
using TeamOctolings.Octobot.Data;
|
||||||
|
using TeamOctolings.Octobot.Extensions;
|
||||||
|
|
||||||
namespace Octobot.Services;
|
namespace TeamOctolings.Octobot.Services;
|
||||||
|
|
||||||
public sealed class AccessControlService
|
public sealed class AccessControlService
|
||||||
{
|
{
|
||||||
|
@ -20,18 +20,17 @@ public sealed class AccessControlService
|
||||||
_userApi = userApi;
|
_userApi = userApi;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool CheckPermission(IEnumerable<IRole> roles, GuildData data, Snowflake memberId,
|
private static bool CheckPermission(IEnumerable<IRole> roles, GuildData data, MemberData memberData,
|
||||||
IGuildMember member,
|
|
||||||
DiscordPermission permission)
|
DiscordPermission permission)
|
||||||
{
|
{
|
||||||
var moderatorRole = GuildSettings.ModeratorRole.Get(data.Settings);
|
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 true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return roles
|
return roles
|
||||||
.Where(r => member.Roles.Contains(r.ID))
|
.Where(r => memberData.Roles.Contains(r.ID.Value))
|
||||||
.Any(r =>
|
.Any(r =>
|
||||||
r.Permissions.HasPermission(permission)
|
r.Permissions.HasPermission(permission)
|
||||||
);
|
);
|
||||||
|
@ -80,38 +79,23 @@ public sealed class AccessControlService
|
||||||
return Result<string?>.FromError(botResult);
|
return Result<string?>.FromError(botResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
var botMemberResult = await _guildApi.GetGuildMemberAsync(guildId, bot.ID, ct);
|
|
||||||
if (!botMemberResult.IsDefined(out var botMember))
|
|
||||||
{
|
|
||||||
return Result<string?>.FromError(botMemberResult);
|
|
||||||
}
|
|
||||||
|
|
||||||
var targetMemberResult = await _guildApi.GetGuildMemberAsync(guildId, targetId, ct);
|
|
||||||
if (!targetMemberResult.IsDefined(out var targetMember))
|
|
||||||
{
|
|
||||||
return Result<string?>.FromSuccess(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
var rolesResult = await _guildApi.GetGuildRolesAsync(guildId, ct);
|
var rolesResult = await _guildApi.GetGuildRolesAsync(guildId, ct);
|
||||||
if (!rolesResult.IsDefined(out var roles))
|
if (!rolesResult.IsDefined(out var roles))
|
||||||
{
|
{
|
||||||
return Result<string?>.FromError(rolesResult);
|
return Result<string?>.FromError(rolesResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var data = await _data.GetData(guildId, ct);
|
||||||
|
var targetData = data.GetOrCreateMemberData(targetId);
|
||||||
|
var botData = data.GetOrCreateMemberData(bot.ID);
|
||||||
|
|
||||||
if (interacterId is null)
|
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);
|
var interacterData = data.GetOrCreateMemberData(interacterId.Value);
|
||||||
if (!interacterResult.IsDefined(out var interacter))
|
var hasPermission = CheckPermission(roles, data, interacterData,
|
||||||
{
|
|
||||||
return Result<string?>.FromError(interacterResult);
|
|
||||||
}
|
|
||||||
|
|
||||||
var data = await _data.GetData(guildId, ct);
|
|
||||||
|
|
||||||
var hasPermission = CheckPermission(roles, data, interacterId.Value, interacter,
|
|
||||||
action switch
|
action switch
|
||||||
{
|
{
|
||||||
"Ban" => DiscordPermission.BanMembers,
|
"Ban" => DiscordPermission.BanMembers,
|
||||||
|
@ -122,31 +106,26 @@ public sealed class AccessControlService
|
||||||
});
|
});
|
||||||
|
|
||||||
return hasPermission
|
return hasPermission
|
||||||
? CheckInteractions(action, guild, roles, targetMember, botMember, interacter)
|
? CheckInteractions(action, guild, roles, targetData, botData, interacterData)
|
||||||
: Result<string?>.FromSuccess($"UserCannot{action}Members".Localized());
|
: Result<string?>.FromSuccess($"UserCannot{action}Members".Localized());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Result<string?> CheckInteractions(
|
private static Result<string?> CheckInteractions(
|
||||||
string action, IGuild guild, IReadOnlyList<IRole> roles, IGuildMember targetMember, IGuildMember botMember,
|
string action, IGuild guild, IReadOnlyList<IRole> roles, MemberData targetData, MemberData botData,
|
||||||
IGuildMember interacter)
|
MemberData interacterData)
|
||||||
{
|
{
|
||||||
if (!targetMember.User.IsDefined(out var targetUser))
|
if (botData.Id == targetData.Id)
|
||||||
{
|
|
||||||
return new ArgumentNullError(nameof(targetMember.User));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (botMember.User == targetMember.User)
|
|
||||||
{
|
{
|
||||||
return Result<string?>.FromSuccess($"UserCannot{action}Bot".Localized());
|
return Result<string?>.FromSuccess($"UserCannot{action}Bot".Localized());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (targetUser.ID == guild.OwnerID)
|
if (targetData.Id == guild.OwnerID)
|
||||||
{
|
{
|
||||||
return Result<string?>.FromSuccess($"UserCannot{action}Owner".Localized());
|
return Result<string?>.FromSuccess($"UserCannot{action}Owner".Localized());
|
||||||
}
|
}
|
||||||
|
|
||||||
var targetRoles = roles.Where(r => targetMember.Roles.Contains(r.ID)).ToList();
|
var targetRoles = roles.Where(r => targetData.Roles.Contains(r.ID.Value)).ToList();
|
||||||
var botRoles = roles.Where(r => botMember.Roles.Contains(r.ID));
|
var botRoles = roles.Where(r => botData.Roles.Contains(r.ID.Value));
|
||||||
|
|
||||||
var targetBotRoleDiff = targetRoles.MaxOrDefault(r => r.Position) - botRoles.MaxOrDefault(r => r.Position);
|
var targetBotRoleDiff = targetRoles.MaxOrDefault(r => r.Position) - botRoles.MaxOrDefault(r => r.Position);
|
||||||
if (targetBotRoleDiff >= 0)
|
if (targetBotRoleDiff >= 0)
|
||||||
|
@ -154,7 +133,7 @@ public sealed class AccessControlService
|
||||||
return Result<string?>.FromSuccess($"BotCannot{action}Target".Localized());
|
return Result<string?>.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
|
var targetInteracterRoleDiff
|
||||||
= targetRoles.MaxOrDefault(r => r.Position) - interacterRoles.MaxOrDefault(r => r.Position);
|
= targetRoles.MaxOrDefault(r => r.Position) - interacterRoles.MaxOrDefault(r => r.Position);
|
||||||
return targetInteracterRoleDiff < 0
|
return targetInteracterRoleDiff < 0
|
|
@ -3,10 +3,10 @@ using System.Text.Json;
|
||||||
using System.Text.Json.Nodes;
|
using System.Text.Json.Nodes;
|
||||||
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Hosting;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Octobot.Data;
|
|
||||||
using Remora.Rest.Core;
|
using Remora.Rest.Core;
|
||||||
|
using TeamOctolings.Octobot.Data;
|
||||||
|
|
||||||
namespace Octobot.Services;
|
namespace TeamOctolings.Octobot.Services;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles saving, loading, initializing and providing <see cref="GuildData" />.
|
/// Handles saving, loading, initializing and providing <see cref="GuildData" />.
|
|
@ -2,16 +2,16 @@ using System.Text;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Hosting;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
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.Discord.API.Abstractions.Rest;
|
||||||
using Remora.Discord.Extensions.Embeds;
|
using Remora.Discord.Extensions.Embeds;
|
||||||
using Remora.Discord.Extensions.Formatting;
|
using Remora.Discord.Extensions.Formatting;
|
||||||
using Remora.Rest.Core;
|
using Remora.Rest.Core;
|
||||||
using Remora.Results;
|
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
|
public sealed partial class MemberUpdateService : BackgroundService
|
||||||
{
|
{
|
|
@ -1,8 +1,6 @@
|
||||||
using System.Text.Json.Nodes;
|
using System.Text.Json.Nodes;
|
||||||
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Hosting;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
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.Discord.API.Abstractions.Rest;
|
||||||
using Remora.Discord.API.Objects;
|
using Remora.Discord.API.Objects;
|
||||||
|
@ -10,8 +8,10 @@ using Remora.Discord.Extensions.Embeds;
|
||||||
using Remora.Discord.Extensions.Formatting;
|
using Remora.Discord.Extensions.Formatting;
|
||||||
using Remora.Rest.Core;
|
using Remora.Rest.Core;
|
||||||
using Remora.Results;
|
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
|
public sealed class ScheduledEventUpdateService : BackgroundService
|
||||||
{
|
{
|
|
@ -4,7 +4,7 @@ using Remora.Discord.API.Gateway.Commands;
|
||||||
using Remora.Discord.API.Objects;
|
using Remora.Discord.API.Objects;
|
||||||
using Remora.Discord.Gateway;
|
using Remora.Discord.Gateway;
|
||||||
|
|
||||||
namespace Octobot.Services.Update;
|
namespace TeamOctolings.Octobot.Services.Update;
|
||||||
|
|
||||||
public sealed class SongUpdateService : BackgroundService
|
public sealed class SongUpdateService : BackgroundService
|
||||||
{
|
{
|
|
@ -1,4 +1,4 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
|
@ -16,31 +16,31 @@
|
||||||
<Company>TeamOctolings</Company>
|
<Company>TeamOctolings</Company>
|
||||||
<NeutralLanguage>en</NeutralLanguage>
|
<NeutralLanguage>en</NeutralLanguage>
|
||||||
<Description>A general-purpose Discord bot for moderation written in C#</Description>
|
<Description>A general-purpose Discord bot for moderation written in C#</Description>
|
||||||
<ApplicationIcon>docs/octobot.ico</ApplicationIcon>
|
<ApplicationIcon>../docs/octobot.ico</ApplicationIcon>
|
||||||
<GitVersion>false</GitVersion>
|
<GitVersion>false</GitVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="DiffPlex" Version="1.7.2" />
|
<PackageReference Include="DiffPlex" Version="1.7.2" />
|
||||||
<PackageReference Include="GitInfo" Version="3.3.4" />
|
<PackageReference Include="GitInfo" Version="3.3.5" />
|
||||||
<PackageReference Include="Humanizer.Core.ru" Version="2.14.1" />
|
<PackageReference Include="Humanizer.Core.ru" Version="2.14.1" />
|
||||||
<PackageReference Include="JetBrains.Annotations" Version="2023.3.0" />
|
<PackageReference Include="JetBrains.Annotations" Version="2023.3.0" />
|
||||||
<PackageReference Include="Microsoft.CodeAnalysis.BannedApiAnalyzers" Version="3.3.4" />
|
<PackageReference Include="Microsoft.CodeAnalysis.BannedApiAnalyzers" Version="3.3.4" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
|
||||||
<PackageReference Include="Remora.Commands" Version="10.0.5" />
|
<PackageReference Include="Remora.Commands" Version="10.0.5" />
|
||||||
<PackageReference Include="Remora.Discord.Caching" Version="38.0.1" />
|
<PackageReference Include="Remora.Discord.Caching" Version="39.0.0" />
|
||||||
<PackageReference Include="Remora.Discord.Extensions" Version="5.3.4" />
|
<PackageReference Include="Remora.Discord.Extensions" Version="5.3.5" />
|
||||||
<PackageReference Include="Remora.Discord.Hosting" Version="6.0.9" />
|
<PackageReference Include="Remora.Discord.Hosting" Version="6.0.10" />
|
||||||
<PackageReference Include="Remora.Discord.Interactivity" Version="4.5.3" />
|
<PackageReference Include="Remora.Discord.Interactivity" Version="4.5.4" />
|
||||||
<PackageReference Include="Serilog.Extensions.Logging.File" Version="3.0.0" />
|
<PackageReference Include="Serilog.Extensions.Logging.File" Version="3.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<EmbeddedResource Update="locale\Messages.resx">
|
<EmbeddedResource Update="Messages.resx">
|
||||||
<Generator>ResXFileCodeGenerator</Generator>
|
<Generator>ResXFileCodeGenerator</Generator>
|
||||||
<LastGenOutput>Messages.Designer.cs</LastGenOutput>
|
<LastGenOutput>Messages.Designer.cs</LastGenOutput>
|
||||||
</EmbeddedResource>
|
</EmbeddedResource>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<AdditionalFiles Include="CodeAnalysis\BannedSymbols.txt" />
|
<AdditionalFiles Include="..\CodeAnalysis\BannedSymbols.txt" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
|
@ -1,16 +1,19 @@
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.Json.Nodes;
|
using System.Text.Json.Nodes;
|
||||||
using Octobot.Data;
|
using Microsoft.Extensions.Logging;
|
||||||
using Octobot.Extensions;
|
|
||||||
using Remora.Discord.API.Abstractions.Objects;
|
using Remora.Discord.API.Abstractions.Objects;
|
||||||
using Remora.Discord.API.Abstractions.Rest;
|
using Remora.Discord.API.Abstractions.Rest;
|
||||||
|
using Remora.Discord.API.Objects;
|
||||||
using Remora.Discord.Extensions.Embeds;
|
using Remora.Discord.Extensions.Embeds;
|
||||||
using Remora.Discord.Extensions.Formatting;
|
using Remora.Discord.Extensions.Formatting;
|
||||||
using Remora.Rest.Core;
|
using Remora.Rest.Core;
|
||||||
using Remora.Results;
|
using Remora.Results;
|
||||||
|
using TeamOctolings.Octobot.Attributes;
|
||||||
|
using TeamOctolings.Octobot.Data;
|
||||||
|
using TeamOctolings.Octobot.Extensions;
|
||||||
|
|
||||||
namespace Octobot.Services;
|
namespace TeamOctolings.Octobot;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Provides utility methods that cannot be transformed to extension methods because they require usage
|
/// Provides utility methods that cannot be transformed to extension methods because they require usage
|
||||||
|
@ -18,6 +21,9 @@ namespace Octobot.Services;
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class Utility
|
public sealed class Utility
|
||||||
{
|
{
|
||||||
|
public static readonly AllowedMentions NoMentions = new(
|
||||||
|
Array.Empty<MentionType>(), Array.Empty<Snowflake>(), Array.Empty<Snowflake>());
|
||||||
|
|
||||||
private readonly IDiscordRestChannelAPI _channelApi;
|
private readonly IDiscordRestChannelAPI _channelApi;
|
||||||
private readonly IDiscordRestGuildScheduledEventAPI _eventApi;
|
private readonly IDiscordRestGuildScheduledEventAPI _eventApi;
|
||||||
private readonly IDiscordRestGuildAPI _guildApi;
|
private readonly IDiscordRestGuildAPI _guildApi;
|
||||||
|
@ -30,6 +36,9 @@ public sealed class Utility
|
||||||
_guildApi = guildApi;
|
_guildApi = guildApi;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[StaticCallersOnly]
|
||||||
|
public static ILogger<Program>? StaticLogger { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the string mentioning the <see cref="GuildSettings.EventNotificationRole" /> and event subscribers related to
|
/// Gets the string mentioning the <see cref="GuildSettings.EventNotificationRole" /> and event subscribers related to
|
||||||
/// a scheduled
|
/// a scheduled
|
Loading…
Reference in a new issue