mirror of
https://github.com/PluralKit/PluralKit.git
synced 2026-02-15 18:20:11 +00:00
Compare commits
3 commits
b83109b65a
...
79da083a74
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
79da083a74 | ||
|
|
2f5cabc8e0 | ||
|
|
fbf51b41c1 |
22 changed files with 700 additions and 40 deletions
|
|
@ -18,7 +18,7 @@ sea-query = { version = "1.0.0-rc.10", features = ["with-chrono"] }
|
|||
sentry = { version = "0.36.0", default-features = false, features = ["backtrace", "contexts", "panic", "debug-images", "reqwest", "rustls"] } # replace native-tls with rustls
|
||||
serde = { version = "1.0.196", features = ["derive"] }
|
||||
serde_json = "1.0.117"
|
||||
sqlx = { version = "0.8.2", features = ["runtime-tokio", "postgres", "time", "macros", "uuid"] }
|
||||
sqlx = { version = "0.8.2", features = ["runtime-tokio", "postgres", "time", "chrono", "macros", "uuid"] }
|
||||
tokio = { version = "1.36.0", features = ["full"] }
|
||||
tracing = "0.1"
|
||||
tracing-subscriber = { version = "0.3.16", features = ["env-filter", "json"] }
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ public record MessageRequest
|
|||
public bool Tts { get; set; }
|
||||
public AllowedMentions? AllowedMentions { get; set; }
|
||||
public Embed[]? Embeds { get; set; }
|
||||
public Message.MessageFlags Flags { get; set; }
|
||||
public MessageComponent[]? Components { get; set; }
|
||||
public Message.Reference? MessageReference { get; set; }
|
||||
}
|
||||
13
Myriad/Types/Component/ComponentMedia.cs
Normal file
13
Myriad/Types/Component/ComponentMedia.cs
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
namespace Myriad.Types;
|
||||
|
||||
public record ComponentMedia
|
||||
{
|
||||
public string? Url { get; init; }
|
||||
}
|
||||
|
||||
public record ComponentMediaItem
|
||||
{
|
||||
public ComponentMedia Media { get; init; }
|
||||
public string? Description { get; init; }
|
||||
public bool Spoiler { get; init; } = false;
|
||||
}
|
||||
|
|
@ -3,5 +3,12 @@ namespace Myriad.Types;
|
|||
public enum ComponentType
|
||||
{
|
||||
ActionRow = 1,
|
||||
Button = 2
|
||||
Button = 2,
|
||||
StringSelect = 3,
|
||||
Section = 9,
|
||||
Text = 10,
|
||||
Thumbnail = 11,
|
||||
MediaGallery = 12,
|
||||
Separator = 14,
|
||||
Container = 17,
|
||||
}
|
||||
|
|
@ -5,9 +5,15 @@ public record MessageComponent
|
|||
public ComponentType Type { get; init; }
|
||||
public ButtonStyle? Style { get; set; }
|
||||
public string? Label { get; init; }
|
||||
public string? Content { get; init; }
|
||||
public Emoji? Emoji { get; init; }
|
||||
public string? CustomId { get; init; }
|
||||
public string? Url { get; init; }
|
||||
public bool? Disabled { get; init; }
|
||||
public uint? AccentColor { get; init; }
|
||||
public ComponentMedia? Media { get; init; }
|
||||
public ComponentMediaItem[]? Items { get; init; }
|
||||
|
||||
public MessageComponent? Accessory { get; init; }
|
||||
public MessageComponent[]? Components { get; init; }
|
||||
}
|
||||
|
|
@ -17,6 +17,7 @@ public record Message
|
|||
Ephemeral = 1 << 6,
|
||||
SuppressNotifications = 1 << 12,
|
||||
VoiceMessage = 1 << 13,
|
||||
IsComponentsV2 = 1 << 15,
|
||||
}
|
||||
|
||||
public enum MessageType
|
||||
|
|
@ -73,8 +74,6 @@ public record Message
|
|||
|
||||
public MessagePoll? Poll { get; init; }
|
||||
|
||||
// public MessageComponent[]? Components { get; init; }
|
||||
|
||||
public record Reference(ulong? GuildId, ulong? ChannelId, ulong? MessageId);
|
||||
|
||||
public record MessageActivity(int Type, string PartyId);
|
||||
|
|
|
|||
|
|
@ -139,7 +139,8 @@ public class ApplicationCommandProxiedMessage
|
|||
if (member == null || !(await _cache.PermissionsForMemberInChannel(ctx.GuildId, ctx.ChannelId, member)).HasFlag(requiredPerms))
|
||||
{
|
||||
throw new PKError("You do not have permission to send messages in this channel.");
|
||||
};
|
||||
}
|
||||
;
|
||||
|
||||
var config = await _repo.GetSystemConfig(msg.System.Id);
|
||||
|
||||
|
|
|
|||
|
|
@ -592,6 +592,8 @@ public partial class CommandTree
|
|||
return ctx.Execute<Config>(null, m => m.HidDisplayCaps(ctx));
|
||||
if (ctx.MatchMultiple(new[] { "pad" }, new[] { "id", "ids" }) || ctx.MatchMultiple(new[] { "id" }, new[] { "pad", "padding" }) || ctx.Match("idpad", "padid", "padids"))
|
||||
return ctx.Execute<Config>(null, m => m.HidListPadding(ctx));
|
||||
if (ctx.MatchMultiple(new[] { "show" }, new[] { "color", "colour", "colors", "colours" }) || ctx.Match("showcolor", "showcolour", "showcolors", "showcolours", "colorcode", "colorhex"))
|
||||
return ctx.Execute<Config>(null, m => m.CardShowColorHex(ctx));
|
||||
if (ctx.MatchMultiple(new[] { "name" }, new[] { "format" }) || ctx.Match("nameformat", "nf"))
|
||||
return ctx.Execute<Config>(null, m => m.NameFormat(ctx));
|
||||
if (ctx.MatchMultiple(new[] { "member", "group" }, new[] { "limit" }) || ctx.Match("limit"))
|
||||
|
|
|
|||
|
|
@ -119,6 +119,41 @@ public class Context
|
|||
return msg;
|
||||
}
|
||||
|
||||
public async Task<Message> Reply(MessageComponent[] components = null, AllowedMentions? mentions = null, MultipartFile[]? files = null)
|
||||
{
|
||||
var botPerms = await BotPermissions;
|
||||
|
||||
if (!botPerms.HasFlag(PermissionSet.SendMessages))
|
||||
// Will be "swallowed" during the error handler anyway, this message is never shown.
|
||||
throw new PKError("PluralKit does not have permission to send messages in this channel.");
|
||||
|
||||
if (files != null && !botPerms.HasFlag(PermissionSet.AttachFiles))
|
||||
throw new PKError("PluralKit does not have permission to attach files in this channel. Please ensure I have the **Attach Files** permission enabled.");
|
||||
|
||||
var msg = await Rest.CreateMessage(Channel.Id, new MessageRequest
|
||||
{
|
||||
Components = components,
|
||||
Flags = Message.MessageFlags.IsComponentsV2,
|
||||
|
||||
// Default to an empty allowed mentions object instead of null (which means no mentions allowed)
|
||||
AllowedMentions = mentions ?? new AllowedMentions()
|
||||
}, files: files);
|
||||
|
||||
// store log of sent message, so it can be queried or deleted later
|
||||
// skip DMs as DM messages can always be deleted
|
||||
if (Guild != null)
|
||||
await Repository.AddCommandMessage(new Core.CommandMessage
|
||||
{
|
||||
Mid = msg.Id,
|
||||
Guild = Guild!.Id,
|
||||
Channel = Channel.Id,
|
||||
Sender = Author.Id,
|
||||
OriginalMid = Message.Id,
|
||||
});
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
public async Task Execute<T>(Command? commandDef, Func<T, Task> handler, bool deprecated = false)
|
||||
{
|
||||
_currentCommand = commandDef;
|
||||
|
|
|
|||
|
|
@ -123,6 +123,13 @@ public class Config
|
|||
"off"
|
||||
));
|
||||
|
||||
items.Add(new(
|
||||
"show color",
|
||||
"Whether to show color codes in system/member/group cards",
|
||||
EnabledDisabled(ctx.Config.CardShowColorHex),
|
||||
"disabled"
|
||||
));
|
||||
|
||||
items.Add(new(
|
||||
"Proxy Switch",
|
||||
"Switching behavior when proxy tags are used",
|
||||
|
|
@ -570,6 +577,20 @@ public class Config
|
|||
else throw new PKError(badInputError);
|
||||
}
|
||||
|
||||
public async Task CardShowColorHex(Context ctx)
|
||||
{
|
||||
if (!ctx.HasNext())
|
||||
{
|
||||
var msg = $"Showing color codes on system/member/group cards is currently **{EnabledDisabled(ctx.Config.CardShowColorHex)}**.";
|
||||
await ctx.Reply(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
var newVal = ctx.MatchToggle(false);
|
||||
await ctx.Repository.UpdateSystemConfig(ctx.System.Id, new() { CardShowColorHex = newVal });
|
||||
await ctx.Reply($"Showing color codes on system/member/group cards is now {EnabledDisabled(newVal)}.");
|
||||
}
|
||||
|
||||
public async Task ProxySwitch(Context ctx)
|
||||
{
|
||||
if (!ctx.HasNext())
|
||||
|
|
|
|||
|
|
@ -520,7 +520,13 @@ public class Groups
|
|||
public async Task ShowGroupCard(Context ctx, PKGroup target)
|
||||
{
|
||||
var system = await GetGroupSystem(ctx, target);
|
||||
await ctx.Reply(embed: await _embeds.CreateGroupEmbed(ctx, system, target));
|
||||
if (ctx.MatchFlag("show-embed", "se"))
|
||||
{
|
||||
await ctx.Reply(text: EmbedService.LEGACY_EMBED_WARNING, embed: await _embeds.CreateGroupEmbed(ctx, system, target));
|
||||
return;
|
||||
}
|
||||
|
||||
await ctx.Reply(components: await _embeds.CreateGroupMessageComponents(ctx, system, target));
|
||||
}
|
||||
|
||||
public async Task GroupPrivacy(Context ctx, PKGroup target, PrivacyLevel? newValueFromCommand)
|
||||
|
|
|
|||
|
|
@ -7,12 +7,94 @@ namespace PluralKit.Bot;
|
|||
|
||||
public class Help
|
||||
{
|
||||
public Task HelpRoot(Context ctx)
|
||||
{
|
||||
if (ctx.MatchFlag("show-embed", "se"))
|
||||
return HelpRootOld(ctx);
|
||||
|
||||
return ctx.Reply(BuildComponents(ctx.Author.Id, Help.Description.Replace("{prefix}", ctx.DefaultPrefix), -1));
|
||||
}
|
||||
|
||||
public static Task ButtonClick(InteractionContext ctx, string prefix)
|
||||
{
|
||||
if (!ctx.CustomId.Contains(ctx.User.Id.ToString()))
|
||||
return ctx.Ignore();
|
||||
|
||||
if (ctx.CustomId.StartsWith("new-"))
|
||||
{
|
||||
Console.WriteLine($"{ctx.Event.Message.Components.First().Components.Length}");
|
||||
if (ctx.Event.Message.Components.First().Components[1].Components.Where(x => x.CustomId == ctx.CustomId).First().Style == ButtonStyle.Primary)
|
||||
return ctx.Respond(InteractionResponse.ResponseType.UpdateMessage, new()
|
||||
{
|
||||
Components = BuildComponents(ctx.User.Id, Help.Description.Replace("{prefix}", prefix), -1),
|
||||
Flags = Message.MessageFlags.IsComponentsV2,
|
||||
});
|
||||
|
||||
var text = helpEmbedPages.GetValueOrDefault(ctx.CustomId.Split("-")[3]).Select(
|
||||
(item, index) => $"### {item.Name.Replace("{prefix}", prefix)}\n{item.Value.Replace("{prefix}", prefix)}"
|
||||
).ToArray();
|
||||
|
||||
var index = Array.FindIndex(ctx.Event.Message.Components.First().Components[1].Components, x => x.CustomId == ctx.CustomId);
|
||||
var components = BuildComponents(ctx.User.Id, Help.Description.Replace("{prefix}", prefix), index);
|
||||
|
||||
components.First().Components[ctx.Event.Message.Components.First().Components.Length - 1] = new MessageComponent()
|
||||
{
|
||||
Type = ComponentType.Text,
|
||||
Content = String.Join("\n", text),
|
||||
};
|
||||
|
||||
return ctx.Respond(InteractionResponse.ResponseType.UpdateMessage, new()
|
||||
{
|
||||
Components = components,
|
||||
Flags = Message.MessageFlags.IsComponentsV2,
|
||||
});
|
||||
}
|
||||
|
||||
return ButtonClickOld(ctx, prefix);
|
||||
}
|
||||
|
||||
private static MessageComponent[] BuildComponents(ulong userId, string textContent, int menuIndex)
|
||||
{
|
||||
return [
|
||||
new MessageComponent()
|
||||
{
|
||||
Type = ComponentType.Container,
|
||||
AccentColor = DiscordUtils.Blue,
|
||||
Components = [
|
||||
new MessageComponent()
|
||||
{
|
||||
Type = ComponentType.Text,
|
||||
Content = "# PluralKit\n-# Use the buttons below to see more info!"
|
||||
},
|
||||
helpPageButtons(userId, "new-", menuIndex),
|
||||
new MessageComponent()
|
||||
{
|
||||
Type = ComponentType.Separator,
|
||||
},
|
||||
new MessageComponent()
|
||||
{
|
||||
Type = ComponentType.Text,
|
||||
Content = textContent,
|
||||
},
|
||||
],
|
||||
},
|
||||
new MessageComponent()
|
||||
{
|
||||
Type = ComponentType.Text,
|
||||
Content = EmbedFooter("\n-# "),
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
///
|
||||
|
||||
private static string Description = "PluralKit is a bot designed for plural communities on Discord, and is open for anyone to use. It allows you to register systems, maintain system information, set up message proxying, log switches, and more.\n\n" +
|
||||
"**System recovery:** in the case of your Discord account getting lost or deleted, the PluralKit staff can help you recover your system, **only if you save the system token from `{prefix}token`**. See [this FAQ entry](https://pluralkit.me/faq/#can-i-recover-my-system-if-i-lose-access-to-my-discord-account) for more details.\n\n" +
|
||||
"If PluralKit is useful to you, please consider donating on [Patreon](https://patreon.com/pluralkit) or [Buy Me A Coffee](https://buymeacoffee.com/pluralkit).\n" +
|
||||
"## Use the buttons below to see more info!";
|
||||
"If PluralKit is useful to you, please consider donating on [Patreon](https://patreon.com/pluralkit) or [Buy Me A Coffee](https://buymeacoffee.com/pluralkit).";
|
||||
|
||||
public static string EmbedFooter = "-# PluralKit by @ske and contributors | Myriad design by @layl, icon by @tedkalashnikov, banner by @fulmine | GitHub: https://github.com/PluralKit/PluralKit/ | Website: https://pluralkit.me/";
|
||||
private static string DescriptionOld = $"{Description}\n## Use the buttons below to see more info!";
|
||||
|
||||
public static string EmbedFooter(string linkSeparator) => $"-# PluralKit by @ske and contributors | Myriad design by @layl, icon by @tedkalashnikov, banner by @fulmine{linkSeparator}GitHub: https://github.com/PluralKit/PluralKit/ | Website: https://pluralkit.me/";
|
||||
|
||||
public static Embed helpEmbed = new()
|
||||
{
|
||||
|
|
@ -98,7 +180,7 @@ public class Help
|
|||
}
|
||||
};
|
||||
|
||||
private static MessageComponent helpPageButtons(ulong userId) => new MessageComponent
|
||||
private static MessageComponent helpPageButtons(ulong userId, string pfx = "", int menuIndex = -1) => new MessageComponent
|
||||
{
|
||||
Type = ComponentType.ActionRow,
|
||||
Components = new[]
|
||||
|
|
@ -106,58 +188,54 @@ public class Help
|
|||
new MessageComponent
|
||||
{
|
||||
Type = ComponentType.Button,
|
||||
Style = ButtonStyle.Secondary,
|
||||
Style = menuIndex == 0 ? ButtonStyle.Primary : ButtonStyle.Secondary,
|
||||
Label = "Basic Info",
|
||||
CustomId = $"help-menu-basicinfo-{userId}",
|
||||
CustomId = $"{pfx}help-menu-basicinfo-{userId}",
|
||||
Emoji = new() { Name = "\u2139" },
|
||||
},
|
||||
new()
|
||||
{
|
||||
Type = ComponentType.Button,
|
||||
Style = ButtonStyle.Secondary,
|
||||
Style = menuIndex == 1 ? ButtonStyle.Primary : ButtonStyle.Secondary,
|
||||
Label = "Getting Started",
|
||||
CustomId = $"help-menu-gettingstarted-{userId}",
|
||||
CustomId = $"{pfx}help-menu-gettingstarted-{userId}",
|
||||
Emoji = new() { Name = "\u2753", },
|
||||
},
|
||||
new()
|
||||
{
|
||||
Type = ComponentType.Button,
|
||||
Style = ButtonStyle.Secondary,
|
||||
Style = menuIndex == 2 ? ButtonStyle.Primary : ButtonStyle.Secondary,
|
||||
Label = "Useful Tips",
|
||||
CustomId = $"help-menu-usefultips-{userId}",
|
||||
CustomId = $"{pfx}help-menu-usefultips-{userId}",
|
||||
Emoji = new() { Name = "\U0001f4a1", },
|
||||
|
||||
},
|
||||
new()
|
||||
{
|
||||
Type = ComponentType.Button,
|
||||
Style = ButtonStyle.Secondary,
|
||||
Style = menuIndex == 3 ? ButtonStyle.Primary : ButtonStyle.Secondary,
|
||||
Label = "More Info",
|
||||
CustomId = $"help-menu-moreinfo-{userId}",
|
||||
CustomId = $"{pfx}help-menu-moreinfo-{userId}",
|
||||
Emoji = new() { Id = 986379675066593330, },
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public Task HelpRoot(Context ctx)
|
||||
public Task HelpRootOld(Context ctx)
|
||||
=> ctx.Rest.CreateMessage(ctx.Channel.Id, new MessageRequest
|
||||
{
|
||||
Content = $"{Emojis.Warn} If you cannot see the rest of this message see [the FAQ](<https://pluralkit.me/faq/#why-do-most-of-pluralkit-s-messages-look-blank-or-empty>)",
|
||||
Embeds = new[] { helpEmbed with { Description = Help.Description.Replace("{prefix}", ctx.DefaultPrefix), Fields = new Embed.Field[] { new("", EmbedFooter) } } },
|
||||
Embeds = new[] { helpEmbed with { Description = Help.DescriptionOld.Replace("{prefix}", ctx.DefaultPrefix), Fields = new Embed.Field[] { new("", EmbedFooter(" | ")) } } },
|
||||
Components = new[] { helpPageButtons(ctx.Author.Id) },
|
||||
});
|
||||
|
||||
public static Task ButtonClick(InteractionContext ctx, string prefix)
|
||||
public static Task ButtonClickOld(InteractionContext ctx, string prefix)
|
||||
{
|
||||
if (!ctx.CustomId.Contains(ctx.User.Id.ToString()))
|
||||
return ctx.Ignore();
|
||||
|
||||
var buttons = helpPageButtons(ctx.User.Id);
|
||||
|
||||
if (ctx.Event.Message.Components.First().Components.Where(x => x.CustomId == ctx.CustomId).First().Style == ButtonStyle.Primary)
|
||||
return ctx.Respond(InteractionResponse.ResponseType.UpdateMessage, new()
|
||||
{
|
||||
Embeds = new[] { helpEmbed with { Description = Help.Description.Replace("{prefix}", prefix), Fields = new Embed.Field[] { new("", EmbedFooter) } } },
|
||||
Embeds = new[] { helpEmbed with { Description = Help.DescriptionOld.Replace("{prefix}", prefix), Fields = new Embed.Field[] { new("", EmbedFooter(" | ")) } } },
|
||||
Components = new[] { buttons }
|
||||
});
|
||||
|
||||
|
|
@ -167,7 +245,7 @@ public class Help
|
|||
{
|
||||
Embeds = new[] { helpEmbed with { Fields = helpEmbedPages.GetValueOrDefault(ctx.CustomId.Split("-")[2]).Select(
|
||||
(item, index) => new Embed.Field(item.Name.Replace("{prefix}", prefix), item.Value.Replace("{prefix}", prefix))
|
||||
).Append(new("", EmbedFooter)).ToArray() } },
|
||||
).Append(new("", EmbedFooter(" | "))).ToArray() } },
|
||||
Components = new[] { buttons }
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -122,8 +122,16 @@ public class Member
|
|||
public async Task ViewMember(Context ctx, PKMember target)
|
||||
{
|
||||
var system = await ctx.Repository.GetSystem(target.System);
|
||||
if (ctx.MatchFlag("show-embed", "se"))
|
||||
{
|
||||
await ctx.Reply(
|
||||
text: EmbedService.LEGACY_EMBED_WARNING,
|
||||
embed: await _embeds.CreateMemberEmbed(system, target, ctx.Guild, ctx.Config, ctx.LookupContextFor(system.Id), ctx.Zone));
|
||||
return;
|
||||
}
|
||||
|
||||
await ctx.Reply(
|
||||
embed: await _embeds.CreateMemberEmbed(system, target, ctx.Guild, ctx.Config, ctx.LookupContextFor(system.Id), ctx.Zone));
|
||||
components: await _embeds.CreateMemberMessageComponents(system, target, ctx.Guild, ctx.Config, ctx.LookupContextFor(system.Id), ctx.Zone));
|
||||
}
|
||||
|
||||
public async Task Soulscream(Context ctx, PKMember target)
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@ public class Misc
|
|||
+ $"**{stats.db.switches:N0}** switches, **{stats.db.messages:N0}** messages\n" +
|
||||
$"**{stats.db.guilds:N0}** servers with **{stats.db.channels:N0}** channels"));
|
||||
|
||||
embed.Field(new("", Help.EmbedFooter));
|
||||
embed.Field(new("", Help.EmbedFooter(" | ")));
|
||||
|
||||
var uptime = ((DateTimeOffset)process.StartTime).ToUnixTimeSeconds();
|
||||
embed.Description($"### PluralKit [{BuildInfoService.Version}](https://github.com/pluralkit/pluralkit/commit/{BuildInfoService.FullVersion})\n" +
|
||||
|
|
|
|||
|
|
@ -36,8 +36,17 @@ public class Random
|
|||
"This system has no members!");
|
||||
|
||||
var randInt = randGen.Next(members.Count);
|
||||
await ctx.Reply(embed: await _embeds.CreateMemberEmbed(target, members[randInt], ctx.Guild,
|
||||
ctx.Config, ctx.LookupContextFor(target.Id), ctx.Zone));
|
||||
|
||||
if (ctx.MatchFlag("show-embed", "se"))
|
||||
{
|
||||
await ctx.Reply(
|
||||
text: EmbedService.LEGACY_EMBED_WARNING,
|
||||
embed: await _embeds.CreateMemberEmbed(target, members[randInt], ctx.Guild, ctx.Config, ctx.LookupContextFor(target.Id), ctx.Zone));
|
||||
return;
|
||||
}
|
||||
|
||||
await ctx.Reply(
|
||||
components: await _embeds.CreateMemberMessageComponents(target, members[randInt], ctx.Guild, ctx.Config, ctx.LookupContextFor(target.Id), ctx.Zone));
|
||||
}
|
||||
|
||||
public async Task Group(Context ctx, PKSystem target)
|
||||
|
|
@ -60,7 +69,17 @@ public class Random
|
|||
$"This system has no groups!");
|
||||
|
||||
var randInt = randGen.Next(groups.Count());
|
||||
await ctx.Reply(embed: await _embeds.CreateGroupEmbed(ctx, target, groups.ToArray()[randInt]));
|
||||
|
||||
if (ctx.MatchFlag("show-embed", "se"))
|
||||
{
|
||||
await ctx.Reply(
|
||||
text: EmbedService.LEGACY_EMBED_WARNING,
|
||||
embed: await _embeds.CreateGroupEmbed(ctx, target, groups.ToArray()[randInt]));
|
||||
return;
|
||||
}
|
||||
|
||||
await ctx.Reply(
|
||||
components: await _embeds.CreateGroupMessageComponents(ctx, target, groups.ToArray()[randInt]));
|
||||
}
|
||||
|
||||
public async Task GroupMember(Context ctx, PKGroup group)
|
||||
|
|
@ -92,7 +111,16 @@ public class Random
|
|||
system = await ctx.Repository.GetSystem(group.System);
|
||||
|
||||
var randInt = randGen.Next(ms.Count);
|
||||
await ctx.Reply(embed: await _embeds.CreateMemberEmbed(system, ms[randInt], ctx.Guild,
|
||||
ctx.Config, ctx.LookupContextFor(group.System), ctx.Zone));
|
||||
|
||||
if (ctx.MatchFlag("show-embed", "se"))
|
||||
{
|
||||
await ctx.Reply(
|
||||
text: EmbedService.LEGACY_EMBED_WARNING,
|
||||
embed: await _embeds.CreateMemberEmbed(system, ms[randInt], ctx.Guild, ctx.Config, ctx.LookupContextFor(system.Id), ctx.Zone));
|
||||
return;
|
||||
}
|
||||
|
||||
await ctx.Reply(
|
||||
components: await _embeds.CreateMemberMessageComponents(system, ms[randInt], ctx.Guild, ctx.Config, ctx.LookupContextFor(system.Id), ctx.Zone));
|
||||
}
|
||||
}
|
||||
|
|
@ -17,8 +17,13 @@ public class System
|
|||
public async Task Query(Context ctx, PKSystem system)
|
||||
{
|
||||
if (system == null) throw Errors.NoSystemError(ctx.DefaultPrefix);
|
||||
if (ctx.MatchFlag("show-embed", "se"))
|
||||
{
|
||||
await ctx.Reply(text: EmbedService.LEGACY_EMBED_WARNING, embed: await _embeds.CreateSystemEmbed(ctx, system, ctx.LookupContextFor(system.Id)));
|
||||
return;
|
||||
}
|
||||
|
||||
await ctx.Reply(embed: await _embeds.CreateSystemEmbed(ctx, system, ctx.LookupContextFor(system.Id)));
|
||||
await ctx.Reply(components: await _embeds.CreateSystemMessageComponents(ctx, system, ctx.LookupContextFor(system.Id)));
|
||||
}
|
||||
|
||||
public async Task New(Context ctx)
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@ public class InteractionCreated: IEventHandler<InteractionCreateEvent>
|
|||
// got some unhandled command, log and ignore
|
||||
_logger.Warning(@"Unhandled ApplicationCommand interaction: {EventId} {CommandName}", evt.Id, evt.Data?.Name);
|
||||
break;
|
||||
};
|
||||
}
|
||||
;
|
||||
}
|
||||
}
|
||||
|
|
@ -15,17 +15,21 @@ namespace PluralKit.Bot;
|
|||
|
||||
public class EmbedService
|
||||
{
|
||||
public const string LEGACY_EMBED_WARNING = "\u26A0\uFE0F The \"legacy\" embeds for system/member/group cards are deprecated, and will be removed in future.";
|
||||
|
||||
private readonly IDiscordCache _cache;
|
||||
private readonly IDatabase _db;
|
||||
private readonly ModelRepository _repo;
|
||||
private readonly DiscordApiClient _rest;
|
||||
private readonly CoreConfig _coreConfig;
|
||||
|
||||
public EmbedService(IDatabase db, ModelRepository repo, IDiscordCache cache, DiscordApiClient rest)
|
||||
public EmbedService(IDatabase db, ModelRepository repo, IDiscordCache cache, DiscordApiClient rest, CoreConfig coreConfig)
|
||||
{
|
||||
_db = db;
|
||||
_repo = repo;
|
||||
_cache = cache;
|
||||
_rest = rest;
|
||||
_coreConfig = coreConfig;
|
||||
}
|
||||
|
||||
private Task<(ulong Id, User? User)[]> GetUsers(IEnumerable<ulong> ids)
|
||||
|
|
@ -39,6 +43,169 @@ public class EmbedService
|
|||
return Task.WhenAll(ids.Select(Inner));
|
||||
}
|
||||
|
||||
public async Task<MessageComponent[]> CreateSystemMessageComponents(Context cctx, PKSystem system, LookupContext ctx)
|
||||
{
|
||||
// Fetch/render info for all accounts simultaneously
|
||||
var accounts = await _repo.GetSystemAccounts(system.Id);
|
||||
var users = (await GetUsers(accounts)).Select(x => x.User?.NameAndMention() ?? $"(deleted account {x.Id})");
|
||||
var linkedAccounts = new MessageComponent()
|
||||
{
|
||||
Type = ComponentType.Text,
|
||||
Content = "**Linked accounts:**\n" + string.Join("\n", users).Truncate(1000),
|
||||
};
|
||||
|
||||
var countctx = LookupContext.ByNonOwner;
|
||||
if (cctx.MatchFlag("a", "all"))
|
||||
{
|
||||
if (system.Id == cctx.System.Id)
|
||||
countctx = LookupContext.ByOwner;
|
||||
else
|
||||
throw Errors.LookupNotAllowed;
|
||||
}
|
||||
|
||||
var memberCount = await _repo.GetSystemMemberCount(system.Id, countctx == LookupContext.ByOwner ? null : PrivacyLevel.Public);
|
||||
var guildSettings = cctx.Guild != null ? await _repo.GetSystemGuild(cctx.Guild.Id, system.Id) : null;
|
||||
|
||||
var avatar = system.AvatarFor(ctx);
|
||||
var headerText = "";
|
||||
|
||||
if (system.PronounPrivacy.CanAccess(ctx) && system.Pronouns != null)
|
||||
headerText += $"\n**Pronouns:** {system.Pronouns}";
|
||||
|
||||
if (system.Tag != null)
|
||||
headerText += $"\n**Tag:** {system.Tag.EscapeMarkdown()}";
|
||||
|
||||
if (cctx.Config.CardShowColorHex && !system.Color.EmptyOrNull())
|
||||
headerText += $"\n**Color:** #{system.Color}";
|
||||
|
||||
if (cctx.Guild != null)
|
||||
{
|
||||
if (guildSettings.Tag != null && guildSettings.TagEnabled)
|
||||
headerText += $"\n**Tag (in server '{cctx.Guild.Name}'):** {guildSettings.Tag.EscapeMarkdown()}";
|
||||
if (!guildSettings.TagEnabled)
|
||||
headerText += $"\n**Tag (in server '{cctx.Guild.Name}'):** *(tag is disabled in this server)*";
|
||||
}
|
||||
|
||||
if (system.MemberListPrivacy.CanAccess(ctx))
|
||||
{
|
||||
headerText += $"\n**Members:** {memberCount}";
|
||||
if (system.Id == cctx.System.Id)
|
||||
if (memberCount > 0)
|
||||
headerText += $" (see `{cctx.DefaultPrefix}system list`)";
|
||||
else
|
||||
headerText += $" (add one with `{cctx.DefaultPrefix}member new`!)";
|
||||
else if (memberCount > 0)
|
||||
headerText += $" (see `{cctx.DefaultPrefix}system {system.DisplayHid(cctx.Config)} list`)";
|
||||
}
|
||||
|
||||
List<MessageComponent> switchComponent = [];
|
||||
var latestSwitch = await _repo.GetLatestSwitch(system.Id);
|
||||
if (latestSwitch != null && system.FrontPrivacy.CanAccess(ctx))
|
||||
{
|
||||
var switchMembers =
|
||||
await _db.Execute(conn => _repo.GetSwitchMembers(conn, latestSwitch.Id)).ToListAsync();
|
||||
if (switchMembers.Count > 0)
|
||||
{
|
||||
var memberStr = string.Join(", ", switchMembers.Select(m => m.NameFor(ctx)));
|
||||
if (memberStr.Length > 200)
|
||||
memberStr = $"(too many to show, see `{cctx.DefaultPrefix}system {system.DisplayHid(cctx.Config)} fronters`)";
|
||||
|
||||
switchComponent.Add(new()
|
||||
{
|
||||
Type = ComponentType.Text,
|
||||
Content = $"**{"Current fronter".ToQuantity(switchMembers.Count, ShowQuantityAs.None)}:** {memberStr}",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
List<MessageComponent> descComponents = [];
|
||||
if (system.DescriptionFor(ctx) is { } desc)
|
||||
{
|
||||
descComponents.Add(new()
|
||||
{
|
||||
Type = ComponentType.Separator,
|
||||
});
|
||||
|
||||
descComponents.Add(new()
|
||||
{
|
||||
Type = ComponentType.Text,
|
||||
Content = desc.NormalizeLineEndSpacing().Truncate(1024),
|
||||
});
|
||||
}
|
||||
|
||||
if (system.BannerPrivacy.CanAccess(ctx) && !string.IsNullOrWhiteSpace(system.BannerImage))
|
||||
descComponents.Add(new()
|
||||
{
|
||||
Type = ComponentType.MediaGallery,
|
||||
Items = [new() { Media = new() { Url = system.BannerImage } }],
|
||||
});
|
||||
|
||||
var systemName = (cctx.Guild != null && guildSettings?.DisplayName != null) ? guildSettings?.DisplayName! : system.NameFor(ctx);
|
||||
var premiumText = ""; // TODO(iris): "\n\U0001F31F *PluralKit Premium supporter!*";
|
||||
List<MessageComponent> header = [
|
||||
new MessageComponent()
|
||||
{
|
||||
Type = ComponentType.Text,
|
||||
Content = $"### {systemName ?? $"`{system.DisplayHid(cctx.Config)}`"}{premiumText}",
|
||||
},
|
||||
];
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(headerText))
|
||||
header.Add(new MessageComponent()
|
||||
{
|
||||
Type = ComponentType.Text,
|
||||
Content = headerText,
|
||||
});
|
||||
|
||||
if (cctx.Guild != null)
|
||||
{
|
||||
var guildAvatar = guildSettings.AvatarUrl.TryGetCleanCdnUrl();
|
||||
if (!string.IsNullOrWhiteSpace(guildAvatar))
|
||||
avatar = guildAvatar;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(avatar))
|
||||
header = [
|
||||
new MessageComponent()
|
||||
{
|
||||
Type = ComponentType.Section,
|
||||
Components = [.. header],
|
||||
Accessory = new MessageComponent()
|
||||
{
|
||||
Type = ComponentType.Thumbnail,
|
||||
Media = new() { Url = avatar },
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
return [
|
||||
new MessageComponent()
|
||||
{
|
||||
Type = ComponentType.Container,
|
||||
AccentColor = system.Color?.ToDiscordColor(),
|
||||
Components = [ ..header, ..switchComponent, linkedAccounts, ..descComponents ],
|
||||
},
|
||||
new MessageComponent()
|
||||
{
|
||||
Type = ComponentType.Section,
|
||||
Components = [
|
||||
new MessageComponent()
|
||||
{
|
||||
Type = ComponentType.Text,
|
||||
Content = $"-# System ID: `{system.DisplayHid(cctx.Config)}`\n-# Created: {system.Created.FormatZoned(cctx.Zone)}",
|
||||
},
|
||||
],
|
||||
Accessory = new MessageComponent()
|
||||
{
|
||||
Type = ComponentType.Button,
|
||||
Style = ButtonStyle.Link,
|
||||
Label = "View on dashboard",
|
||||
Url = $"{_coreConfig.DashboardBaseUrl}/profile/s/{system.Hid}",
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
public async Task<Embed> CreateSystemEmbed(Context cctx, PKSystem system, LookupContext ctx)
|
||||
{
|
||||
// Fetch/render info for all accounts simultaneously
|
||||
|
|
@ -61,7 +228,7 @@ public class EmbedService
|
|||
.Footer(new Embed.EmbedFooter(
|
||||
$"System ID: {system.DisplayHid(cctx.Config)} | Created on {system.Created.FormatZoned(cctx.Zone)}"))
|
||||
.Color(system.Color?.ToDiscordColor())
|
||||
.Url($"https://dash.pluralkit.me/profile/s/{system.Hid}");
|
||||
.Url($"{_coreConfig.DashboardBaseUrl}/profile/s/{system.Hid}");
|
||||
|
||||
var avatar = system.AvatarFor(ctx);
|
||||
if (avatar != null)
|
||||
|
|
@ -164,6 +331,158 @@ public class EmbedService
|
|||
return embed.Build();
|
||||
}
|
||||
|
||||
public async Task<MessageComponent[]> CreateMemberMessageComponents(PKSystem system, PKMember member, Guild guild, SystemConfig? ccfg, LookupContext ctx, DateTimeZone zone)
|
||||
{
|
||||
var name = member.NameFor(ctx);
|
||||
var systemGuildSettings = guild != null ? await _repo.GetSystemGuild(guild.Id, system.Id) : null;
|
||||
var systemName = (guild != null && systemGuildSettings?.DisplayName != null) ? systemGuildSettings?.DisplayName! : system.NameFor(ctx);
|
||||
|
||||
var guildSettings = guild != null ? await _repo.GetMemberGuild(guild.Id, member.Id) : null;
|
||||
var guildDisplayName = guildSettings?.DisplayName;
|
||||
var webhook_avatar = guildSettings?.AvatarUrl ?? member.WebhookAvatarFor(ctx) ?? member.AvatarFor(ctx);
|
||||
var avatar = guildSettings?.AvatarUrl ?? member.AvatarFor(ctx);
|
||||
|
||||
var groups = await _repo.GetMemberGroups(member.Id)
|
||||
.Where(g => g.Visibility.CanAccess(ctx))
|
||||
.OrderBy(g => g.Name, StringComparer.InvariantCultureIgnoreCase)
|
||||
.ToListAsync();
|
||||
|
||||
var headerText = "";
|
||||
if (member.MemberVisibility == PrivacyLevel.Private)
|
||||
headerText += "*(this member is hidden)*\n";
|
||||
if (guildSettings?.AvatarUrl != null)
|
||||
if (member.AvatarFor(ctx) != null)
|
||||
headerText +=
|
||||
$"*(this member has a server-specific avatar set; [click here]({member.AvatarUrl.TryGetCleanCdnUrl()}) to see the global avatar)*\n";
|
||||
else
|
||||
headerText += "*(this member has a server-specific avatar set)*\n";
|
||||
|
||||
if (!member.DisplayName.EmptyOrNull() && member.NamePrivacy.CanAccess(ctx))
|
||||
headerText += $"\n**Display name:** {member.DisplayName.Truncate(1024)}";
|
||||
if (guild != null && guildDisplayName != null)
|
||||
headerText += $"\n**Server nickname (for '{guild.Name}'):** {guildDisplayName.Truncate(1024)}";
|
||||
if (ccfg.CardShowColorHex && !member.Color.EmptyOrNull())
|
||||
headerText += $"\n**Color:** #{member.Color}";
|
||||
if (member.PronounsFor(ctx) is { } pronouns && !string.IsNullOrWhiteSpace(pronouns))
|
||||
headerText += $"\n**Pronouns:** {pronouns}";
|
||||
if (member.BirthdayFor(ctx) != null)
|
||||
headerText += $"\n**Birthday:** {member.BirthdayString}";
|
||||
if (member.MessageCountFor(ctx) is { } count && count > 0)
|
||||
headerText += $"\n**Message count:** {member.MessageCount}";
|
||||
|
||||
List<MessageComponent> extraData = [];
|
||||
if (member.HasProxyTags && member.ProxyPrivacy.CanAccess(ctx))
|
||||
{
|
||||
extraData.Add(new MessageComponent
|
||||
{
|
||||
Type = ComponentType.Separator,
|
||||
});
|
||||
|
||||
extraData.Add(new MessageComponent
|
||||
{
|
||||
Type = ComponentType.Text,
|
||||
Content = $"**Proxy tags:**\n{member.ProxyTagsString("\n").Truncate(1024)}",
|
||||
});
|
||||
}
|
||||
|
||||
if (groups.Count > 0)
|
||||
{
|
||||
// More than 5 groups show in "compact" format without ID
|
||||
var content = groups.Count > 5
|
||||
? string.Join(", ", groups.Select(g => g.DisplayName ?? g.Name))
|
||||
: string.Join("\n", groups.Select(g => $"[`{g.DisplayHid(ccfg, isList: true)}`] **{g.DisplayName ?? g.Name}**"));
|
||||
|
||||
extraData.Add(new MessageComponent
|
||||
{
|
||||
Type = ComponentType.Separator,
|
||||
});
|
||||
|
||||
extraData.Add(new MessageComponent
|
||||
{
|
||||
Type = ComponentType.Text,
|
||||
Content = $"**Groups ({groups.Count}):**\n{content.Truncate(1000)}",
|
||||
});
|
||||
}
|
||||
|
||||
List<MessageComponent> descComponents = [];
|
||||
if (member.DescriptionFor(ctx) is { } desc)
|
||||
{
|
||||
descComponents.Add(new()
|
||||
{
|
||||
Type = ComponentType.Separator,
|
||||
});
|
||||
|
||||
descComponents.Add(new()
|
||||
{
|
||||
Type = ComponentType.Text,
|
||||
Content = desc.NormalizeLineEndSpacing().Truncate(1024),
|
||||
});
|
||||
}
|
||||
|
||||
if (member.BannerPrivacy.CanAccess(ctx) && !string.IsNullOrWhiteSpace(member.BannerImage))
|
||||
descComponents.Add(new()
|
||||
{
|
||||
Type = ComponentType.MediaGallery,
|
||||
Items = [new() { Media = new() { Url = member.BannerImage } }],
|
||||
});
|
||||
|
||||
List<MessageComponent> header = [
|
||||
new MessageComponent()
|
||||
{
|
||||
Type = ComponentType.Text,
|
||||
Content = $"### {name}{(systemName != null ? $" ({systemName})" : "")}",
|
||||
},
|
||||
];
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(headerText))
|
||||
header.Add(new MessageComponent()
|
||||
{
|
||||
Type = ComponentType.Text,
|
||||
Content = headerText,
|
||||
});
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(avatar))
|
||||
header = [
|
||||
new MessageComponent()
|
||||
{
|
||||
Type = ComponentType.Section,
|
||||
Components = [.. header],
|
||||
Accessory = new MessageComponent()
|
||||
{
|
||||
Type = ComponentType.Thumbnail,
|
||||
Media = new() { Url = avatar },
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
return [
|
||||
new MessageComponent()
|
||||
{
|
||||
Type = ComponentType.Container,
|
||||
AccentColor = member.Color?.ToDiscordColor(),
|
||||
Components = [ ..header, ..extraData, ..descComponents ],
|
||||
},
|
||||
new MessageComponent()
|
||||
{
|
||||
Type = ComponentType.Section,
|
||||
Components = [
|
||||
new MessageComponent()
|
||||
{
|
||||
Type = ComponentType.Text,
|
||||
Content = $"-# System ID: `{system.DisplayHid(ccfg)}` \u2219 Member ID: `{member.DisplayHid(ccfg)}`{(member.MetadataPrivacy.CanAccess(ctx) ? $"\n-# Created: {member.Created.FormatZoned(zone)}" : "")}",
|
||||
},
|
||||
],
|
||||
Accessory = new MessageComponent()
|
||||
{
|
||||
Type = ComponentType.Button,
|
||||
Style = ButtonStyle.Link,
|
||||
Label = "View on dashboard",
|
||||
Url = $"{_coreConfig.DashboardBaseUrl}/profile/m/{member.Hid}",
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
public async Task<Embed> CreateMemberEmbed(PKSystem system, PKMember member, Guild guild, SystemConfig? ccfg, LookupContext ctx, DateTimeZone zone)
|
||||
{
|
||||
// string FormatTimestamp(Instant timestamp) => DateTimeFormats.ZonedDateTimeFormat.Format(timestamp.InZone(system.Zone));
|
||||
|
|
@ -188,7 +507,7 @@ public class EmbedService
|
|||
.ToListAsync();
|
||||
|
||||
var eb = new EmbedBuilder()
|
||||
.Author(new Embed.EmbedAuthor(name, IconUrl: webhook_avatar.TryGetCleanCdnUrl(), Url: $"https://dash.pluralkit.me/profile/m/{member.Hid}"))
|
||||
.Author(new Embed.EmbedAuthor(name, IconUrl: webhook_avatar.TryGetCleanCdnUrl(), Url: $"{_coreConfig.DashboardBaseUrl}/profile/m/{member.Hid}"))
|
||||
// .WithColor(member.ColorPrivacy.CanAccess(ctx) ? color : null)
|
||||
.Color(member.Color?.ToDiscordColor())
|
||||
.Footer(new Embed.EmbedFooter(
|
||||
|
|
@ -241,6 +560,119 @@ public class EmbedService
|
|||
return eb.Build();
|
||||
}
|
||||
|
||||
public async Task<MessageComponent[]> CreateGroupMessageComponents(Context ctx, PKSystem system, PKGroup target)
|
||||
{
|
||||
var pctx = ctx.LookupContextFor(system.Id);
|
||||
var name = target.NameFor(ctx);
|
||||
var systemGuildSettings = ctx.Guild != null ? await _repo.GetSystemGuild(ctx.Guild.Id, system.Id) : null;
|
||||
var systemName = (ctx.Guild != null && systemGuildSettings?.DisplayName != null) ? systemGuildSettings?.DisplayName! : system.NameFor(ctx);
|
||||
|
||||
var countctx = LookupContext.ByNonOwner;
|
||||
if (ctx.MatchFlag("a", "all"))
|
||||
{
|
||||
if (system.Id == ctx.System.Id)
|
||||
countctx = LookupContext.ByOwner;
|
||||
else
|
||||
throw Errors.LookupNotAllowed;
|
||||
}
|
||||
|
||||
var memberCount = await _repo.GetGroupMemberCount(target.Id, countctx == LookupContext.ByOwner ? null : PrivacyLevel.Public);
|
||||
var headerText = "";
|
||||
|
||||
if (target.NamePrivacy.CanAccess(pctx) && target.DisplayName != null)
|
||||
headerText += $"\n**Display name:** {target.DisplayName}";
|
||||
|
||||
if (ctx.Config.CardShowColorHex && !target.Color.EmptyOrNull())
|
||||
headerText += $"\n**Color:** #{target.Color}";
|
||||
|
||||
if (target.ListPrivacy.CanAccess(pctx))
|
||||
{
|
||||
headerText += $"\n**Members:** {memberCount}";
|
||||
if (system.Id == ctx.System.Id && memberCount == 0)
|
||||
headerText += $" (add one with `{ctx.DefaultPrefix}group {target.Reference(ctx)} add <member>`!)";
|
||||
else if (memberCount > 0)
|
||||
headerText += $" (see `{ctx.DefaultPrefix}group {target.Reference(ctx)} list`)";
|
||||
}
|
||||
|
||||
List<MessageComponent> descComponents = [];
|
||||
if (target.DescriptionFor(pctx) is { } desc)
|
||||
{
|
||||
descComponents.Add(new()
|
||||
{
|
||||
Type = ComponentType.Separator,
|
||||
});
|
||||
|
||||
descComponents.Add(new()
|
||||
{
|
||||
Type = ComponentType.Text,
|
||||
Content = desc.NormalizeLineEndSpacing().Truncate(1024),
|
||||
});
|
||||
}
|
||||
|
||||
if (target.BannerPrivacy.CanAccess(pctx) && !string.IsNullOrWhiteSpace(target.BannerImage))
|
||||
descComponents.Add(new()
|
||||
{
|
||||
Type = ComponentType.MediaGallery,
|
||||
Items = [new() { Media = new() { Url = target.BannerImage } }],
|
||||
});
|
||||
|
||||
List<MessageComponent> header = [
|
||||
new MessageComponent()
|
||||
{
|
||||
Type = ComponentType.Text,
|
||||
Content = $"### {name}{(systemName != null ? $" ({systemName})" : "")}",
|
||||
},
|
||||
];
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(headerText))
|
||||
header.Add(new MessageComponent()
|
||||
{
|
||||
Type = ComponentType.Text,
|
||||
Content = headerText,
|
||||
});
|
||||
|
||||
if (target.IconFor(pctx) is { } icon)
|
||||
header = [
|
||||
new MessageComponent()
|
||||
{
|
||||
Type = ComponentType.Section,
|
||||
Components = [.. header],
|
||||
Accessory = new MessageComponent()
|
||||
{
|
||||
Type = ComponentType.Thumbnail,
|
||||
Media = new() { Url = icon.TryGetCleanCdnUrl() },
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
return [
|
||||
new MessageComponent()
|
||||
{
|
||||
Type = ComponentType.Container,
|
||||
AccentColor = target.Color?.ToDiscordColor(),
|
||||
Components = [ ..header, ..descComponents ],
|
||||
},
|
||||
new MessageComponent()
|
||||
{
|
||||
Type = ComponentType.Section,
|
||||
Components = [
|
||||
new MessageComponent()
|
||||
{
|
||||
Type = ComponentType.Text,
|
||||
Content = $"-# System ID: `{system.DisplayHid(ctx.Config)}` \u2219 Group ID: `{target.DisplayHid(ctx.Config)}`{(target.MetadataPrivacy.CanAccess(pctx) ? $"\n-# Created: {target.Created.FormatZoned(ctx.Zone)}" : "")}",
|
||||
},
|
||||
],
|
||||
Accessory = new MessageComponent()
|
||||
{
|
||||
Type = ComponentType.Button,
|
||||
Style = ButtonStyle.Link,
|
||||
Label = "View on dashboard",
|
||||
Url = $"{_coreConfig.DashboardBaseUrl}/profile/g/{target.Hid}",
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
public async Task<Embed> CreateGroupEmbed(Context ctx, PKSystem system, PKGroup target)
|
||||
{
|
||||
var pctx = ctx.LookupContextFor(system.Id);
|
||||
|
|
@ -266,7 +698,7 @@ public class EmbedService
|
|||
nameField = $"{nameField}";
|
||||
|
||||
var eb = new EmbedBuilder()
|
||||
.Author(new Embed.EmbedAuthor(nameField, IconUrl: target.IconFor(pctx), Url: $"https://dash.pluralkit.me/profile/g/{target.Hid}"))
|
||||
.Author(new Embed.EmbedAuthor(nameField, IconUrl: target.IconFor(pctx), Url: $"{_coreConfig.DashboardBaseUrl}/profile/g/{target.Hid}"))
|
||||
.Color(target.Color?.ToDiscordColor());
|
||||
|
||||
eb.Footer(new Embed.EmbedFooter($"System ID: {system.DisplayHid(ctx.Config)} | Group ID: {target.DisplayHid(ctx.Config)}{(target.MetadataPrivacy.CanAccess(pctx) ? $" | Created on {target.Created.FormatZoned(ctx.Zone)}" : "")}"));
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ public class CoreConfig
|
|||
public string? SeqLogUrl { get; set; }
|
||||
public string? DispatchProxyUrl { get; set; }
|
||||
public string? DispatchProxyToken { get; set; }
|
||||
public string DashboardBaseUrl { get; set; } = "https://dash.pluralkit.local";
|
||||
|
||||
public LogEventLevel ConsoleLogLevel { get; set; } = LogEventLevel.Debug;
|
||||
public LogEventLevel ElasticLogLevel { get; set; } = LogEventLevel.Information;
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ public class SystemConfigPatch: PatchObject
|
|||
public Partial<bool> ProxyErrorMessageEnabled { get; set; }
|
||||
public Partial<bool> HidDisplaySplit { get; set; }
|
||||
public Partial<bool> HidDisplayCaps { get; set; }
|
||||
public Partial<bool> CardShowColorHex { get; set; }
|
||||
public Partial<string?> NameFormat { get; set; }
|
||||
public Partial<SystemConfig.HidPadFormat> HidListPadding { get; set; }
|
||||
public Partial<SystemConfig.ProxySwitchAction> ProxySwitch { get; set; }
|
||||
|
|
@ -41,6 +42,7 @@ public class SystemConfigPatch: PatchObject
|
|||
.With("hid_display_split", HidDisplaySplit)
|
||||
.With("hid_display_caps", HidDisplayCaps)
|
||||
.With("hid_list_padding", HidListPadding)
|
||||
.With("card_show_color_hex", CardShowColorHex)
|
||||
.With("proxy_switch", ProxySwitch)
|
||||
.With("name_format", NameFormat)
|
||||
);
|
||||
|
|
@ -107,6 +109,9 @@ public class SystemConfigPatch: PatchObject
|
|||
if (HidListPadding.IsPresent)
|
||||
o.Add("hid_list_padding", HidListPadding.Value.ToUserString());
|
||||
|
||||
if (CardShowColorHex.IsPresent)
|
||||
o.Add("card_show_color_hex", CardShowColorHex.Value);
|
||||
|
||||
if (ProxySwitch.IsPresent)
|
||||
o.Add("proxy_switch", ProxySwitch.Value.ToUserString());
|
||||
|
||||
|
|
@ -150,6 +155,9 @@ public class SystemConfigPatch: PatchObject
|
|||
if (o.ContainsKey("hid_display_caps"))
|
||||
patch.HidDisplayCaps = o.Value<bool>("hid_display_caps");
|
||||
|
||||
if (o.ContainsKey("card_show_color_hex"))
|
||||
patch.CardShowColorHex = o.Value<bool>("card_show_color_hex");
|
||||
|
||||
if (o.ContainsKey("proxy_switch"))
|
||||
patch.ProxySwitch = o.Value<string>("proxy_switch") switch
|
||||
{
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ public class SystemConfig
|
|||
public bool ProxyErrorMessageEnabled { get; }
|
||||
public bool HidDisplaySplit { get; }
|
||||
public bool HidDisplayCaps { get; }
|
||||
public bool CardShowColorHex { get; }
|
||||
public HidPadFormat HidListPadding { get; }
|
||||
public ProxySwitchAction ProxySwitch { get; }
|
||||
public string NameFormat { get; }
|
||||
|
|
@ -60,6 +61,7 @@ public static class SystemConfigExt
|
|||
o.Add("hid_display_split", cfg.HidDisplaySplit);
|
||||
o.Add("hid_display_caps", cfg.HidDisplayCaps);
|
||||
o.Add("hid_list_padding", cfg.HidListPadding.ToUserString());
|
||||
o.Add("card_show_color_hex", cfg.CardShowColorHex);
|
||||
o.Add("proxy_switch", cfg.ProxySwitch.ToUserString());
|
||||
o.Add("name_format", cfg.NameFormat);
|
||||
|
||||
|
|
|
|||
6
crates/migrate/data/migrations/53.sql
Normal file
6
crates/migrate/data/migrations/53.sql
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
-- database version 53
|
||||
-- add toggle for showing color codes on cv2 cards
|
||||
|
||||
alter table system_config add column card_show_color_hex bool default false;
|
||||
|
||||
update info set schema_version = 53;
|
||||
Loading…
Add table
Add a link
Reference in a new issue