feat: redirect commands
This commit is contained in:
parent
03dc16b0b3
commit
bacbc6db0e
7 changed files with 212 additions and 7 deletions
|
|
@ -166,7 +166,7 @@ public class IgnoreChannelCommands(
|
||||||
var value = string.Join("\n", visibleCategories.Select(c => $"<#{c.Id}>"));
|
var value = string.Join("\n", visibleCategories.Select(c => $"<#{c.Id}>"));
|
||||||
if (nonVisibleCategories != 0)
|
if (nonVisibleCategories != 0)
|
||||||
value +=
|
value +=
|
||||||
$"\n\n{nonVisibleCategories} channel(s) were ignored as you do not have access to them.";
|
$"\n\n{nonVisibleCategories} channel(s) are not shown as you do not have access to them.";
|
||||||
|
|
||||||
embed.AddField("Categories", value);
|
embed.AddField("Categories", value);
|
||||||
}
|
}
|
||||||
|
|
@ -183,7 +183,7 @@ public class IgnoreChannelCommands(
|
||||||
var value = string.Join("\n", visibleBase.Select(c => $"<#{c.Id}>"));
|
var value = string.Join("\n", visibleBase.Select(c => $"<#{c.Id}>"));
|
||||||
if (nonVisibleBase != 0)
|
if (nonVisibleBase != 0)
|
||||||
value +=
|
value +=
|
||||||
$"\n\n{nonVisibleBase} channel(s) were ignored as you do not have access to them.";
|
$"\n\n{nonVisibleBase} channel(s) are not shown as you do not have access to them.";
|
||||||
|
|
||||||
embed.AddField("Channels", value);
|
embed.AddField("Channels", value);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -90,6 +90,12 @@ public class InviteCommands(
|
||||||
))
|
))
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
|
if (fields.Count == 0)
|
||||||
|
return await feedbackService.ReplyAsync(
|
||||||
|
"No invites found for this server.",
|
||||||
|
isEphemeral: true
|
||||||
|
);
|
||||||
|
|
||||||
return await feedbackService.SendContextualPaginatedMessageAsync(
|
return await feedbackService.SendContextualPaginatedMessageAsync(
|
||||||
userId,
|
userId,
|
||||||
DiscordUtils.PaginateFields(
|
DiscordUtils.PaginateFields(
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,7 @@ public class MetaCommands(
|
||||||
IFeedbackService feedbackService,
|
IFeedbackService feedbackService,
|
||||||
ContextInjectionService contextInjection,
|
ContextInjectionService contextInjection,
|
||||||
GuildCache guildCache,
|
GuildCache guildCache,
|
||||||
|
RoleCache roleCache,
|
||||||
ChannelCache channelCache,
|
ChannelCache channelCache,
|
||||||
EmojiCache emojiCache,
|
EmojiCache emojiCache,
|
||||||
IDiscordRestChannelAPI channelApi
|
IDiscordRestChannelAPI channelApi
|
||||||
|
|
@ -109,7 +110,8 @@ public class MetaCommands(
|
||||||
embed.AddField(
|
embed.AddField(
|
||||||
"Numbers",
|
"Numbers",
|
||||||
$"{CataloggerMetrics.MessagesStored.Value:N0} messages "
|
$"{CataloggerMetrics.MessagesStored.Value:N0} messages "
|
||||||
+ $"from {guildCache.Size:N0} servers\nCached {channelCache.Size:N0} channels, {emojiCache.Size:N0}",
|
+ $"from {guildCache.Size:N0} servers\n"
|
||||||
|
+ $"Cached {channelCache.Size:N0} channels, {roleCache.Size:N0} roles, {emojiCache.Size:N0} emojis",
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
196
Catalogger.Backend/Bot/Commands/RedirectCommands.cs
Normal file
196
Catalogger.Backend/Bot/Commands/RedirectCommands.cs
Normal file
|
|
@ -0,0 +1,196 @@
|
||||||
|
// Copyright (C) 2021-present sam (starshines.gay)
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Affero General Public License as published
|
||||||
|
// by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Affero General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
using System.ComponentModel;
|
||||||
|
using Catalogger.Backend.Cache.InMemoryCache;
|
||||||
|
using Catalogger.Backend.Database;
|
||||||
|
using Catalogger.Backend.Database.Queries;
|
||||||
|
using Catalogger.Backend.Extensions;
|
||||||
|
using Remora.Commands.Attributes;
|
||||||
|
using Remora.Commands.Groups;
|
||||||
|
using Remora.Discord.API.Abstractions.Objects;
|
||||||
|
using Remora.Discord.API.Objects;
|
||||||
|
using Remora.Discord.Commands.Attributes;
|
||||||
|
using Remora.Discord.Commands.Feedback.Services;
|
||||||
|
using Remora.Discord.Commands.Services;
|
||||||
|
using Remora.Discord.Pagination.Extensions;
|
||||||
|
using IResult = Remora.Results.IResult;
|
||||||
|
|
||||||
|
namespace Catalogger.Backend.Bot.Commands;
|
||||||
|
|
||||||
|
[Group("redirects")]
|
||||||
|
[Description("Commands for configuring log redirects.")]
|
||||||
|
[DiscordDefaultMemberPermissions(DiscordPermission.ManageGuild)]
|
||||||
|
public class RedirectCommands(
|
||||||
|
DatabaseContext db,
|
||||||
|
GuildCache guildCache,
|
||||||
|
ChannelCache channelCache,
|
||||||
|
ContextInjectionService contextInjectionService,
|
||||||
|
FeedbackService feedbackService
|
||||||
|
) : CommandGroup
|
||||||
|
{
|
||||||
|
[Command("add")]
|
||||||
|
[Description("Redirect message logs from a channel or category to another channel.")]
|
||||||
|
public async Task<IResult> AddRedirectAsync(
|
||||||
|
[ChannelTypes(
|
||||||
|
ChannelType.GuildCategory,
|
||||||
|
ChannelType.GuildText,
|
||||||
|
ChannelType.GuildAnnouncement,
|
||||||
|
ChannelType.GuildForum,
|
||||||
|
ChannelType.GuildMedia,
|
||||||
|
ChannelType.GuildVoice
|
||||||
|
)]
|
||||||
|
[Description("The channel to redirect logs from")]
|
||||||
|
IChannel source,
|
||||||
|
[ChannelTypes(ChannelType.GuildText)]
|
||||||
|
[Description("The channel to redirect logs to")]
|
||||||
|
IChannel target
|
||||||
|
)
|
||||||
|
{
|
||||||
|
var (_, guildId) = contextInjectionService.GetUserAndGuild();
|
||||||
|
var guildConfig = await db.GetGuildAsync(guildId);
|
||||||
|
guildConfig.Channels.Redirects[source.ID.Value] = target.ID.Value;
|
||||||
|
db.Update(guildConfig);
|
||||||
|
await db.SaveChangesAsync();
|
||||||
|
|
||||||
|
var output =
|
||||||
|
$"Success! Edited and deleted messages from {FormatChannel(source)} will now be redirected to <#{target.ID}>.";
|
||||||
|
|
||||||
|
// Notify the user if the channel they started redirecting from was already covered by a category-level redirect.
|
||||||
|
if (
|
||||||
|
source.ParentID.IsDefined(out var parentId)
|
||||||
|
&& guildConfig.Channels.Redirects.TryGetValue(
|
||||||
|
parentId.Value.Value,
|
||||||
|
out var parentRedirect
|
||||||
|
)
|
||||||
|
&& parentRedirect != 0
|
||||||
|
)
|
||||||
|
{
|
||||||
|
output +=
|
||||||
|
$"\n**Note:** channels from the category {FormatChannel(source)} is in were already being redirected to <#{parentRedirect}>.";
|
||||||
|
}
|
||||||
|
|
||||||
|
return await feedbackService.ReplyAsync(output);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command("remove")]
|
||||||
|
[Description("Stop redirecting message logs from a channel.")]
|
||||||
|
public async Task<IResult> RemoveRedirectAsync(
|
||||||
|
[ChannelTypes(
|
||||||
|
ChannelType.GuildCategory,
|
||||||
|
ChannelType.GuildText,
|
||||||
|
ChannelType.GuildAnnouncement,
|
||||||
|
ChannelType.GuildForum,
|
||||||
|
ChannelType.GuildMedia,
|
||||||
|
ChannelType.GuildVoice
|
||||||
|
)]
|
||||||
|
IChannel source
|
||||||
|
)
|
||||||
|
{
|
||||||
|
var (_, guildId) = contextInjectionService.GetUserAndGuild();
|
||||||
|
var guildConfig = await db.GetGuildAsync(guildId);
|
||||||
|
|
||||||
|
var wasSet = guildConfig.Channels.Redirects.Remove(source.ID.Value);
|
||||||
|
var output = wasSet
|
||||||
|
? $"Removed the redirect for {FormatChannel(source)}! Message logs from"
|
||||||
|
+ $"{(source.Type == ChannelType.GuildCategory ? "that category's channels" : "that channel")}"
|
||||||
|
+ "will now be logged to the default channel, if any."
|
||||||
|
: $"Message logs from {FormatChannel(source)} were already not being redirected to another channel.";
|
||||||
|
|
||||||
|
// Warn the user if this is a non-category channel and *all* of this category's channels are being redirected.
|
||||||
|
if (
|
||||||
|
source.ParentID.IsDefined(out var parentId)
|
||||||
|
&& guildConfig.Channels.Redirects.TryGetValue(
|
||||||
|
parentId.Value.Value,
|
||||||
|
out var parentRedirect
|
||||||
|
)
|
||||||
|
&& parentRedirect != 0
|
||||||
|
)
|
||||||
|
{
|
||||||
|
var parentChannelName = $"<#{parentId}>";
|
||||||
|
if (channelCache.TryGet(parentId.Value, out var parentChannel))
|
||||||
|
parentChannelName = parentChannel.Name.Value!;
|
||||||
|
|
||||||
|
if (wasSet)
|
||||||
|
output +=
|
||||||
|
$"\nHowever, all channels in the {parentChannelName} category are being redirected to <#{parentRedirect}>, "
|
||||||
|
+ $"so removing the redirect for {FormatChannel(source)} will not take effect until that is removed as well.";
|
||||||
|
else
|
||||||
|
output +=
|
||||||
|
$"\nHowever, all channels in the {parentChannelName} category are being redirected to <#{parentRedirect}>.";
|
||||||
|
}
|
||||||
|
|
||||||
|
db.Update(guildConfig);
|
||||||
|
await db.SaveChangesAsync();
|
||||||
|
|
||||||
|
return await feedbackService.ReplyAsync(output);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command("list")]
|
||||||
|
[Description("List currently redirected channels.")]
|
||||||
|
public async Task<IResult> ListRedirectsAsync()
|
||||||
|
{
|
||||||
|
var (userId, guildId) = contextInjectionService.GetUserAndGuild();
|
||||||
|
if (!guildCache.TryGet(guildId, out var guild))
|
||||||
|
throw new CataloggerError("Guild was not cached");
|
||||||
|
var guildChannels = channelCache.GuildChannels(guildId).ToList();
|
||||||
|
var guildConfig = await db.GetGuildAsync(guildId);
|
||||||
|
|
||||||
|
var fields = new List<IEmbedField>();
|
||||||
|
|
||||||
|
foreach (var (source, target) in guildConfig.Channels.Redirects)
|
||||||
|
{
|
||||||
|
fields.Add(
|
||||||
|
new EmbedField(
|
||||||
|
Name: FormatChannelHeader(
|
||||||
|
source,
|
||||||
|
guildChannels.FirstOrDefault(c => c.ID.Value == source)
|
||||||
|
),
|
||||||
|
Value: FormatChannelText(
|
||||||
|
target,
|
||||||
|
guildChannels.FirstOrDefault(c => c.ID.Value == target)
|
||||||
|
),
|
||||||
|
IsInline: false
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fields.Count == 0)
|
||||||
|
return await feedbackService.ReplyAsync(
|
||||||
|
"No channels are being redirected right now.",
|
||||||
|
isEphemeral: true
|
||||||
|
);
|
||||||
|
|
||||||
|
return await feedbackService.SendContextualPaginatedMessageAsync(
|
||||||
|
userId,
|
||||||
|
DiscordUtils.PaginateFields(fields, $"Channel redirects for {guild.Name}")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string FormatChannel(IChannel channel) =>
|
||||||
|
channel.Type == ChannelType.GuildCategory ? channel.Name.Value! : $"<#{channel.ID}>";
|
||||||
|
|
||||||
|
private static string FormatChannelHeader(ulong id, IChannel? channel) =>
|
||||||
|
channel != null
|
||||||
|
? channel.Type == ChannelType.GuildCategory
|
||||||
|
? $"Category {channel.Name}"
|
||||||
|
: $"#{channel.Name}"
|
||||||
|
: $"*unknown channel {id}*";
|
||||||
|
|
||||||
|
private static string FormatChannelText(ulong id, IChannel? channel) =>
|
||||||
|
channel != null
|
||||||
|
? $"#{channel.Name} (<#{channel.ID}>)"
|
||||||
|
: $"*unknown channel {id}* (<#{id}>)";
|
||||||
|
}
|
||||||
|
|
@ -137,7 +137,7 @@ public static class DiscordExtensions
|
||||||
permissionSet.GetPermissions().Select(p => p.Humanize(LetterCasing.Title))
|
permissionSet.GetPermissions().Select(p => p.Humanize(LetterCasing.Title))
|
||||||
);
|
);
|
||||||
|
|
||||||
public static (Snowflake, Snowflake) GetUserAndGuild(
|
public static (Snowflake UserId, Snowflake GuildId) GetUserAndGuild(
|
||||||
this ContextInjectionService contextInjectionService
|
this ContextInjectionService contextInjectionService
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -88,6 +88,7 @@ builder
|
||||||
.WithCommandGroup<KeyRoleCommands>()
|
.WithCommandGroup<KeyRoleCommands>()
|
||||||
.WithCommandGroup<InviteCommands>()
|
.WithCommandGroup<InviteCommands>()
|
||||||
.WithCommandGroup<IgnoreChannelCommands>()
|
.WithCommandGroup<IgnoreChannelCommands>()
|
||||||
|
.WithCommandGroup<RedirectCommands>()
|
||||||
// End command tree
|
// End command tree
|
||||||
.Finish()
|
.Finish()
|
||||||
.AddPagination()
|
.AddPagination()
|
||||||
|
|
|
||||||
|
|
@ -321,9 +321,9 @@ public class WebhookExecutorService(
|
||||||
guild.Channels.Redirects.TryGetValue(channelId.Value.Value, out var channelRedirect)
|
guild.Channels.Redirects.TryGetValue(channelId.Value.Value, out var channelRedirect)
|
||||||
)
|
)
|
||||||
return channelRedirect;
|
return channelRedirect;
|
||||||
if (categoryRedirect != 0)
|
return categoryRedirect != 0
|
||||||
return categoryRedirect;
|
? categoryRedirect
|
||||||
return GetDefaultLogChannel(guild, logChannelType);
|
: GetDefaultLogChannel(guild, logChannelType);
|
||||||
}
|
}
|
||||||
|
|
||||||
return GetDefaultLogChannel(guild, logChannelType);
|
return GetDefaultLogChannel(guild, logChannelType);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue