Skip to content
This repository was archived by the owner on Nov 24, 2022. It is now read-only.

Commit 862c89b

Browse files
Merge pull request #65 from InfinityGhost/command-improvements
Command improvements
2 parents 3abba19 + 424d3a7 commit 862c89b

12 files changed

Lines changed: 114 additions & 67 deletions

File tree

TabletBot.Common/Attributes/Bot/CommandAttribute.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
namespace TabletBot.Common.Attributes.Bot
55
{
66
[AttributeUsage(AttributeTargets.Method)]
7-
[MeansImplicitUse(ImplicitUseTargetFlags.Members)]
7+
[MeansImplicitUse(ImplicitUseTargetFlags.Itself)]
88
public class CommandAttribute : Attribute
99
{
1010
public CommandAttribute(params string[] arguments)

TabletBot.Common/Log.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,6 @@ public static void Write(string group, string text, LogLevel level = LogLevel.In
1212
Output?.Invoke(new LogMessage(group, text, level));
1313
}
1414

15-
public static async Task WriteAsync(string group, string text, LogLevel level = LogLevel.Info) => await Task.Run(() => Write(group, text, level));
16-
1715
public static void Debug(string group, string text)
1816
{
1917
Write(group, text, LogLevel.Debug);

TabletBot.Common/Settings.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,10 @@ public sealed class Settings
3939

4040
public async Task Write(FileInfo file)
4141
{
42-
if (!file.Directory.Exists)
42+
if (file.Directory is { Exists: false })
4343
file.Directory.Create();
4444
await using (var fs = file.Create())
45-
await JsonSerializer.SerializeAsync<Settings>(fs, this, SerializerOptions);
45+
await JsonSerializer.SerializeAsync(fs, this, SerializerOptions);
4646
}
4747

4848
public static async Task<Settings> Read(FileInfo file)
@@ -55,7 +55,7 @@ public async Task<string> ExportAsync()
5555
{
5656
await using (var ms = new MemoryStream())
5757
{
58-
await JsonSerializer.SerializeAsync<Settings>(ms, this, SerializerOptions);
58+
await JsonSerializer.SerializeAsync(ms, this, SerializerOptions);
5959
ms.Position = 0;
6060
using (var sr = new StreamReader(ms))
6161
return await sr.ReadToEndAsync();

TabletBot.Discord/Commands/ModerationCommands.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ public async Task ForceSaveSettings()
3535
{
3636
await _settings.Write(Platform.SettingsFile);
3737
await ReplyAsync("Settings force saved.", allowedMentions: AllowedMentions.None);
38-
await Log.WriteAsync("Settings", $"{Context.Message.Author.Username} force-saved the configuration to {Platform.SettingsFile.FullName}");
38+
Log.Write("Settings", $"{Context.Message.Author.Username} force-saved the configuration to {Platform.SettingsFile.FullName}");
3939
}
4040

4141
[Command("kill-bot", RunMode = RunMode.Async), Name("Kill Bot"), RequireOwner]

TabletBot.Discord/Formatting.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
using Discord;
2+
13
namespace TabletBot.Discord
24
{
35
public static class Formatting
@@ -8,5 +10,7 @@ public static class Formatting
810
public const string CODE_AFFIX = "`";
911
public const string QUOTE_PREFIX = "> ";
1012
public const string CODE_BLOCK = "```";
13+
14+
public static string UrlString(IAttachment attachment) => $"[{attachment.Filename}]({attachment.Url})";
1115
}
1216
}

TabletBot.Discord/LogExtensions.cs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,25 +7,29 @@ namespace TabletBot.Discord
77
{
88
public static class LogExtensions
99
{
10-
public static async Task WriteAsync(IMessage message)
10+
public static Task WriteAsync(IMessage message)
1111
{
12-
await Log.WriteAsync("Message", string.Format(
12+
Log.Write("Message", string.Format(
1313
"#{1}/{2}#{3}: {0}",
1414
message.CleanContent,
1515
message.Channel.Name,
1616
message.Author.Username,
1717
message.Author.Discriminator
1818
));
19+
20+
return Task.CompletedTask;
1921
}
2022

21-
public static async Task WriteAsync(LogMessage message)
23+
public static Task WriteAsync(LogMessage message)
2224
{
23-
await Log.WriteAsync("Client", string.Format(
25+
Log.Write("Client", string.Format(
2426
"{1} [{2}]: {0}",
2527
message.Message,
2628
message.Source,
2729
message.Severity
2830
));
31+
32+
return Task.CompletedTask;
2933
}
3034
}
3135
}

TabletBot.Discord/Watchers/Commands/CommandMessageWatcher.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ IEnumerable<Type> commands
3535

3636
public async Task Receive(IMessage message)
3737
{
38-
if (message.Content.StartsWith(_settings.CommandPrefix) && !message.Author.IsBot)
38+
if (message.Channel is IGuildChannel && !message.Author.IsBot && message.Content.StartsWith(_settings.CommandPrefix))
3939
{
4040
try
4141
{
@@ -70,7 +70,7 @@ public async Task InitializeAsync()
7070
foreach (var module in _commands)
7171
{
7272
await _commandService.AddModuleAsync(module, _serviceProvider);
73-
await Log.WriteAsync("CommandSvc", $"Registered command module '{module.Name}'.", LogLevel.Debug);
73+
Log.Write("CommandSvc", $"Registered command module '{module.Name}'.", LogLevel.Debug);
7474
}
7575

7676
_commandService.CommandExecuted += CommandExecuted;

TabletBot.Discord/Watchers/Commands/SlashCommandInteractionWatcher.cs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -64,25 +64,24 @@ public async Task InitializeAsync()
6464
if (_registered)
6565
return;
6666

67-
await Task.WhenAll(_commands.Select(RegisterCommand));
67+
await Task.WhenAll(_commands.Select(RegisterCommandModule));
6868
_registered = true;
6969
}
7070

71-
private async Task RegisterCommand(SlashCommandModule module)
71+
private async Task RegisterCommandModule(SlashCommandModule module)
7272
{
73-
module.BuildCommandHandlers();
74-
7573
var moderatorCommands = new List<RestGuildCommand>();
76-
foreach (var command in module.CommandHandlers)
74+
foreach (var command in module.BuildCommandHandlers())
7775
{
7876
var guildCommand = await _client.Rest.CreateGuildCommand(command.Build(), _settings.GuildID);
7977
if (guildCommand.IsDefaultPermission == false)
8078
moderatorCommands.Add(guildCommand);
8179
}
8280

8381
await ApplyCommandPermissions(_client, moderatorCommands);
84-
8582
module.Update += UpdateModule;
83+
84+
Log.Write("Setup", $"Registered slash command module '{module.GetType().Name}'.");
8685
}
8786

8887
private async Task ApplyCommandPermissions(DiscordSocketClient client, IEnumerable<RestGuildCommand> moderatorCommands)

TabletBot.Discord/Watchers/DirectMessage/ModMailMessageWatcher.cs

Lines changed: 49 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
using System;
2+
using System.Collections.Generic;
13
using System.Linq;
24
using System.Threading.Tasks;
35
using Discord;
@@ -18,28 +20,62 @@ public ModMailMessageWatcher(DiscordSocketClient client, Settings settings)
1820
_settings = settings;
1921
}
2022

21-
private IMessageChannel? _directMessageLogChannel;
23+
private ITextChannel? _directMessageLogChannel;
2224

2325
public async Task Receive(IMessage message)
2426
{
2527
if (message.Channel is IDMChannel dmChannel)
2628
{
27-
if (_directMessageLogChannel == null)
29+
await DirectMessage(message, dmChannel);
30+
}
31+
}
32+
33+
private async Task DirectMessage(IMessage message, IDMChannel dmChannel)
34+
{
35+
var embed = new EmbedBuilder
36+
{
37+
Description = message.Content,
38+
Timestamp = message.Timestamp,
39+
Author = dmChannel.Recipient.ToEmbedAuthor(),
40+
Color = Color.Blue,
41+
Fields = GetFieldForAttachments(message),
42+
Footer = new EmbedFooterBuilder
2843
{
29-
var channel = await _client.Rest.GetChannelAsync(_settings.ModMailChannelID);
30-
_directMessageLogChannel = (IMessageChannel) channel;
44+
Text = dmChannel.Id.ToString()
3145
}
46+
};
3247

33-
var embed = new EmbedBuilder
34-
{
35-
Description = message.Content,
36-
Timestamp = message.Timestamp,
37-
Author = dmChannel.Recipient.ToEmbedAuthor(),
38-
Color = Color.Blue
39-
};
48+
var existingEmbeds = message.Embeds.Any() ? message.Embeds : Array.Empty<IEmbed>();
4049

41-
await _directMessageLogChannel.SendMessageAsync(embed: embed.Build());
42-
}
50+
var embeds = from emb in existingEmbeds.Prepend(embed.Build())
51+
where emb is Embed
52+
select emb as Embed;
53+
54+
var channel = await GetModMailChannel();
55+
await channel.SendMessageAsync(embeds: embeds.ToArray());
56+
}
57+
58+
private async Task<ITextChannel> GetModMailChannel()
59+
{
60+
if (_directMessageLogChannel != null)
61+
return _directMessageLogChannel;
62+
63+
var channel = await _client.Rest.GetChannelAsync(_settings.ModMailChannelID);
64+
return _directMessageLogChannel = (ITextChannel) channel;
65+
}
66+
67+
private static List<EmbedFieldBuilder> GetFieldForAttachments(IMessage message)
68+
{
69+
return message.Attachments.Select(GetFieldForAttachment).ToList();
70+
}
71+
72+
private static EmbedFieldBuilder GetFieldForAttachment(IAttachment attachment)
73+
{
74+
return new EmbedFieldBuilder
75+
{
76+
Name = attachment.Filename,
77+
Value = Formatting.UrlString(attachment)
78+
};
4379
}
4480

4581
public Task Deleted(Cacheable<IMessage, ulong> message, Cacheable<IMessageChannel, ulong> channel) => Task.CompletedTask;
Lines changed: 33 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
using System;
21
using System.Collections.Generic;
32
using System.Linq;
43
using System.Text.RegularExpressions;
@@ -7,6 +6,7 @@
76
using Octokit;
87
using TabletBot.Common;
98
using TabletBot.Discord.Embeds;
9+
using TabletBot.Discord.Commands;
1010

1111
#nullable enable
1212

@@ -26,49 +26,55 @@ public IssueMessageWatcher(Settings settings, GitHubClient gitHubClient)
2626
private const string OWNER = "OpenTabletDriver";
2727
private const string NAME = "OpenTabletDriver";
2828

29+
private static readonly Regex IssueRefRegex = new Regex(@" ?#([0-9]+[0-9]) ?");
30+
2931
public async Task Receive(IMessage message)
3032
{
31-
if (message.Author.IsBot)
33+
if (message.Author.IsBot || message is not IUserMessage userMessage)
3234
return;
3335

34-
if (TryGetIssueRefNumbers(message.Content, out var refs))
36+
var rateLimits = await _gitHubClient.Miscellaneous.GetRateLimits();
37+
if (rateLimits.Rate.Remaining < 2)
38+
return;
39+
40+
if (GetIssueRefNumbers(userMessage.Content) is IList<uint> refs)
3541
{
36-
uint refNum = 0;
37-
foreach (int issueRef in refs)
42+
using (userMessage.Channel.EnterTypingState())
3843
{
39-
if (refNum == _settings.GitHubIssueRefLimit)
40-
break;
41-
42-
var issues = await _gitHubClient.Issue.GetAllForRepository(OWNER, NAME);
43-
var prs = await _gitHubClient.PullRequest.GetAllForRepository(OWNER, NAME);
44-
if (issues.FirstOrDefault(i => i.Number == issueRef) is Issue issue)
45-
{
46-
var pr = prs.FirstOrDefault(pr => pr.Number == issue.Number);
47-
var embed = pr == null ? GitHubEmbeds.GetIssueEmbed(issue) : GitHubEmbeds.GetPullRequestEmbed(pr);
48-
await message.Channel.SendMessageAsync(embed: embed);
49-
}
50-
refNum++;
44+
await ReplyWithEmbeds(userMessage, refs);
5145
}
5246
}
5347
}
5448

5549
public Task Deleted(Cacheable<IMessage, ulong> message, Cacheable<IMessageChannel, ulong> channel) => Task.CompletedTask;
5650

57-
public static bool TryGetIssueRefNumbers(string message, out IEnumerable<int> refNums)
51+
private async Task ReplyWithEmbeds(IUserMessage message, IList<uint> refs)
5852
{
59-
refNums = Array.Empty<int>();
53+
var issues = await _gitHubClient.Issue.GetAllForRepository(OWNER, NAME);
54+
var prs = await _gitHubClient.PullRequest.GetAllForRepository(OWNER, NAME);
55+
var embeds = GetEmbedsForRefs(issues, prs, refs).ToArray();
6056

61-
var matches = IssueRefRegex.Matches(message);
62-
if (matches.Count > 0)
57+
await message.Channel.SendMessageAsync(embeds: embeds, messageReference: message.ToReference());
58+
}
59+
60+
private IEnumerable<Embed> GetEmbedsForRefs(IReadOnlyList<Issue> issues, IReadOnlyList<PullRequest> prs, IList<uint> refs)
61+
{
62+
for (var i = 0; i < refs.Count && i < _settings.GitHubIssueRefLimit; i++)
6363
{
64-
refNums = from match in matches
65-
select int.Parse(match.Groups[1].Value);
66-
return true;
67-
}
64+
var issueRef = refs[i];
6865

69-
return false;
66+
if (issues.FirstOrDefault(s => s.Number == issueRef) is Issue issue)
67+
{
68+
var pr = prs.FirstOrDefault(pr => pr.Number == issue.Number);
69+
yield return pr == null ? GitHubEmbeds.GetIssueEmbed(issue) : GitHubEmbeds.GetPullRequestEmbed(pr);
70+
}
71+
}
7072
}
7173

72-
private static readonly Regex IssueRefRegex = new Regex(@" ?#([0-9]+[0-9]) ?");
74+
private static IEnumerable<uint>? GetIssueRefNumbers(string message)
75+
{
76+
var matches = IssueRefRegex.Matches(message);
77+
return matches.Any() ? matches.Select(m => uint.Parse(m.Groups[1].Value)).ToList() : null;
78+
}
7379
}
7480
}

0 commit comments

Comments
 (0)