feat: implement member avatar commands

This commit is contained in:
dusk 2025-09-04 04:01:21 +03:00
parent 1196d87fe7
commit 15191171f5
No known key found for this signature in database
3 changed files with 178 additions and 59 deletions

View file

@ -16,6 +16,15 @@ public partial class CommandTree
Commands.MemberShow(var param, _) => ctx.Execute<Member>(MemberInfo, m => m.ViewMember(ctx, param.target)),
Commands.MemberNew(var param, _) => ctx.Execute<Member>(MemberNew, m => m.NewMember(ctx, param.name)),
Commands.MemberSoulscream(var param, _) => ctx.Execute<Member>(MemberInfo, m => m.Soulscream(ctx, param.target)),
Commands.MemberAvatarShow(var param, var flags) => ctx.Execute<MemberAvatar>(MemberAvatar, m => m.ShowAvatar(ctx, param.target, flags.GetReplyFormat())),
Commands.MemberAvatarClear(var param, var flags) => ctx.Execute<MemberAvatar>(MemberAvatar, m => m.ClearAvatar(ctx, param.target)),
Commands.MemberAvatarUpdate(var param, _) => ctx.Execute<MemberAvatar>(MemberAvatar, m => m.ChangeAvatar(ctx, param.target, param.avatar)),
Commands.MemberWebhookAvatarShow(var param, var flags) => ctx.Execute<MemberAvatar>(MemberAvatar, m => m.ShowWebhookAvatar(ctx, param.target, flags.GetReplyFormat())),
Commands.MemberWebhookAvatarClear(var param, var flags) => ctx.Execute<MemberAvatar>(MemberAvatar, m => m.ClearWebhookAvatar(ctx, param.target)),
Commands.MemberWebhookAvatarUpdate(var param, _) => ctx.Execute<MemberAvatar>(MemberAvatar, m => m.ChangeWebhookAvatar(ctx, param.target, param.avatar)),
Commands.MemberServerAvatarShow(var param, var flags) => ctx.Execute<MemberAvatar>(MemberAvatar, m => m.ShowServerAvatar(ctx, param.target, flags.GetReplyFormat())),
Commands.MemberServerAvatarClear(var param, var flags) => ctx.Execute<MemberAvatar>(MemberAvatar, m => m.ClearServerAvatar(ctx, param.target)),
Commands.MemberServerAvatarUpdate(var param, _) => ctx.Execute<MemberAvatar>(MemberAvatar, m => m.ChangeServerAvatar(ctx, param.target, param.avatar)),
Commands.MemberPronounsShow(var param, var flags) => ctx.Execute<MemberEdit>(MemberPronouns, m => m.ShowPronouns(ctx, param.target, flags.GetReplyFormat())),
Commands.MemberPronounsClear(var param, var flags) => ctx.Execute<MemberEdit>(MemberPronouns, m => m.ClearPronouns(ctx, param.target, flags.yes)),
Commands.MemberPronounsUpdate(var param, _) => ctx.Execute<MemberEdit>(MemberPronouns, m => m.ChangePronouns(ctx, param.target, param.pronouns)),
@ -435,11 +444,7 @@ public partial class CommandTree
private async Task HandleMemberCommandTargeted(Context ctx, PKMember target)
{
// Commands that have a member target (eg. pk;member <member> delete)
if (ctx.Match("avatar", "profile", "picture", "icon", "image", "pfp", "pic"))
await ctx.Execute<MemberAvatar>(MemberAvatar, m => m.Avatar(ctx, target));
else if (ctx.Match("proxyavatar", "proxypfp", "webhookavatar", "webhookpfp", "pa", "pavatar", "ppfp"))
await ctx.Execute<MemberAvatar>(MemberAvatar, m => m.WebhookAvatar(ctx, target));
else if (ctx.Match("group", "groups", "g"))
if (ctx.Match("group", "groups", "g"))
if (ctx.Match("add", "a"))
await ctx.Execute<GroupMember>(MemberGroupAdd,
m => m.AddRemoveGroups(ctx, target, Groups.AddRemoveOperation.Add));
@ -448,9 +453,6 @@ public partial class CommandTree
m => m.AddRemoveGroups(ctx, target, Groups.AddRemoveOperation.Remove));
else
await ctx.Execute<GroupMember>(MemberGroups, m => m.ListMemberGroups(ctx, target));
else if (ctx.Match("serveravatar", "sa", "servericon", "serverimage", "serverpfp", "serverpic", "savatar", "spic",
"guildavatar", "guildpic", "guildicon", "sicon", "spfp"))
await ctx.Execute<MemberAvatar>(MemberServerAvatar, m => m.ServerAvatar(ctx, target));
else if (ctx.Match("id"))
await ctx.Execute<Member>(MemberId, m => m.DisplayId(ctx, target));
else

View file

@ -19,6 +19,9 @@ public class MemberAvatar
private async Task AvatarClear(MemberAvatarLocation location, Context ctx, PKMember target, MemberGuildSettings? mgs)
{
ctx.CheckSystem().CheckOwnMember(target);
await ctx.ConfirmClear("this member's " + location.Name());
await UpdateAvatar(location, ctx, target, null);
if (location == MemberAvatarLocation.Server)
{
@ -47,7 +50,7 @@ public class MemberAvatar
}
private async Task AvatarShow(MemberAvatarLocation location, Context ctx, PKMember target,
MemberGuildSettings? guildData)
MemberGuildSettings? guildData, ReplyFormat format)
{
// todo: this privacy code is really confusing
// for now, we skip privacy flag/config parsing for this, but it would be good to fix that at some point
@ -86,7 +89,6 @@ public class MemberAvatar
if (location == MemberAvatarLocation.Server)
field += $" (for {ctx.Guild.Name})";
var format = ctx.MatchFormat();
if (format == ReplyFormat.Raw)
{
await ctx.Reply($"`{currentValue?.TryGetCleanCdnUrl()}`");
@ -110,58 +112,89 @@ public class MemberAvatar
else throw new PKError("Format Not Recognized");
}
public async Task ServerAvatar(Context ctx, PKMember target)
private async Task AvatarChange(MemberAvatarLocation location, Context ctx, PKMember target,
MemberGuildSettings? guildData, ParsedImage avatar)
{
ctx.CheckGuildContext();
var guildData = await ctx.Repository.GetMemberGuild(ctx.Guild.Id, target.Id);
await AvatarCommandTree(MemberAvatarLocation.Server, ctx, target, guildData);
}
public async Task Avatar(Context ctx, PKMember target)
{
var guildData = ctx.Guild != null
? await ctx.Repository.GetMemberGuild(ctx.Guild.Id, target.Id)
: null;
await AvatarCommandTree(MemberAvatarLocation.Member, ctx, target, guildData);
}
public async Task WebhookAvatar(Context ctx, PKMember target)
{
var guildData = ctx.Guild != null
? await ctx.Repository.GetMemberGuild(ctx.Guild.Id, target.Id)
: null;
await AvatarCommandTree(MemberAvatarLocation.MemberWebhook, ctx, target, guildData);
}
private async Task AvatarCommandTree(MemberAvatarLocation location, Context ctx, PKMember target,
MemberGuildSettings? guildData)
{
// First, see if we need to *clear*
if (ctx.MatchClear())
{
ctx.CheckSystem().CheckOwnMember(target);
await ctx.ConfirmClear("this member's " + location.Name());
await AvatarClear(location, ctx, target, guildData);
return;
}
// Then, parse an image from the command (from various sources...)
var avatarArg = await ctx.MatchImage();
if (avatarArg == null)
{
// If we didn't get any, just show the current avatar
await AvatarShow(location, ctx, target, guildData);
return;
}
ctx.CheckSystem().CheckOwnMember(target);
avatarArg = await _avatarHosting.TryRehostImage(avatarArg.Value, AvatarHostingService.RehostedImageType.Avatar, ctx.Author.Id, ctx.System);
await _avatarHosting.VerifyAvatarOrThrow(avatarArg.Value.Url);
await UpdateAvatar(location, ctx, target, avatarArg.Value.CleanUrl ?? avatarArg.Value.Url);
await PrintResponse(location, ctx, target, avatarArg.Value, guildData);
avatar = await _avatarHosting.TryRehostImage(avatar, AvatarHostingService.RehostedImageType.Avatar, ctx.Author.Id, ctx.System);
await _avatarHosting.VerifyAvatarOrThrow(avatar.Url);
await UpdateAvatar(location, ctx, target, avatar.CleanUrl ?? avatar.Url);
await PrintResponse(location, ctx, target, avatar, guildData);
}
private Task<MemberGuildSettings> GetServerAvatarGuildData(Context ctx, PKMember target)
{
ctx.CheckGuildContext();
return ctx.Repository.GetMemberGuild(ctx.Guild.Id, target.Id);
}
private async Task<MemberGuildSettings?> GetAvatarGuildData(Context ctx, PKMember target)
{
return ctx.Guild != null
? await ctx.Repository.GetMemberGuild(ctx.Guild.Id, target.Id)
: null;
}
private async Task<MemberGuildSettings?> GetWebhookAvatarGuildData(Context ctx, PKMember target)
{
return ctx.Guild != null
? await ctx.Repository.GetMemberGuild(ctx.Guild.Id, target.Id)
: null;
}
public async Task ShowServerAvatar(Context ctx, PKMember target, ReplyFormat format)
{
var guildData = await GetServerAvatarGuildData(ctx, target);
await AvatarShow(MemberAvatarLocation.Server, ctx, target, guildData, format);
}
public async Task ClearServerAvatar(Context ctx, PKMember target)
{
var guildData = await GetServerAvatarGuildData(ctx, target);
await AvatarClear(MemberAvatarLocation.Server, ctx, target, guildData);
}
public async Task ChangeServerAvatar(Context ctx, PKMember target, ParsedImage avatar)
{
var guildData = await GetServerAvatarGuildData(ctx, target);
await AvatarChange(MemberAvatarLocation.Server, ctx, target, guildData, avatar);
}
public async Task ShowAvatar(Context ctx, PKMember target, ReplyFormat format)
{
var guildData = await GetAvatarGuildData(ctx, target);
await AvatarShow(MemberAvatarLocation.Member, ctx, target, guildData, format);
}
public async Task ClearAvatar(Context ctx, PKMember target)
{
var guildData = await GetAvatarGuildData(ctx, target);
await AvatarClear(MemberAvatarLocation.Member, ctx, target, guildData);
}
public async Task ChangeAvatar(Context ctx, PKMember target, ParsedImage avatar)
{
var guildData = await GetAvatarGuildData(ctx, target);
await AvatarChange(MemberAvatarLocation.Member, ctx, target, guildData, avatar);
}
public async Task ShowWebhookAvatar(Context ctx, PKMember target, ReplyFormat format)
{
var guildData = await GetWebhookAvatarGuildData(ctx, target);
await AvatarShow(MemberAvatarLocation.MemberWebhook, ctx, target, guildData, format);
}
public async Task ClearWebhookAvatar(Context ctx, PKMember target)
{
var guildData = await GetWebhookAvatarGuildData(ctx, target);
await AvatarClear(MemberAvatarLocation.MemberWebhook, ctx, target, guildData);
}
public async Task ChangeWebhookAvatar(Context ctx, PKMember target, ParsedImage avatar)
{
var guildData = await GetWebhookAvatarGuildData(ctx, target);
await AvatarChange(MemberAvatarLocation.MemberWebhook, ctx, target, guildData, avatar);
}
private Task PrintResponse(MemberAvatarLocation location, Context ctx, PKMember target, ParsedImage avatar,

View file

@ -198,6 +198,89 @@ pub fn cmds() -> impl Iterator<Item = Command> {
.into_iter()
};
let member_avatar_cmd = {
let member_avatar = tokens!(
member_target,
(
"avatar",
["profile", "picture", "icon", "image", "pfp", "pic"]
)
);
[
command!(member_avatar => "member_avatar_show").help("Shows a member's avatar"),
command!(member_avatar, ("avatar", Avatar) => "member_avatar_update")
.help("Changes a member's avatar"),
command!(member_avatar, ("clear", ["c"]) => "member_avatar_clear")
.flag(("yes", ["y"]))
.help("Clears a member's avatar"),
]
.into_iter()
};
let member_webhook_avatar_cmd = {
let member_webhook_avatar = tokens!(
member_target,
(
"proxyavatar",
[
"proxypfp",
"webhookavatar",
"webhookpfp",
"pa",
"pavatar",
"ppfp"
]
)
);
[
command!(member_webhook_avatar => "member_webhook_avatar_show")
.help("Shows a member's proxy avatar"),
command!(member_webhook_avatar, ("avatar", Avatar) => "member_webhook_avatar_update")
.help("Changes a member's proxy avatar"),
command!(member_webhook_avatar, ("clear", ["c"]) => "member_webhook_avatar_clear")
.flag(("yes", ["y"]))
.help("Clears a member's proxy avatar"),
]
.into_iter()
};
let member_server_avatar_cmd = {
let member_server_avatar = tokens!(
member_target,
(
"serveravatar",
[
"sa",
"servericon",
"serverimage",
"serverpfp",
"serverpic",
"savatar",
"spic",
"guildavatar",
"guildpic",
"guildicon",
"sicon",
"spfp"
]
)
);
[
command!(member_server_avatar => "member_server_avatar_show")
.help("Shows a member's server-specific avatar"),
command!(member_server_avatar, ("avatar", Avatar) => "member_server_avatar_update")
.help("Changes a member's server-specific avatar"),
command!(member_server_avatar, ("clear", ["c"]) => "member_server_avatar_clear")
.flag(("yes", ["y"]))
.help("Clears a member's server-specific avatar"),
]
.into_iter()
};
let member_avatar_cmds = member_avatar_cmd
.chain(member_webhook_avatar_cmd)
.chain(member_server_avatar_cmd);
let member_delete_cmd =
[command!(member_target, delete => "member_delete").help("Deletes a member")].into_iter();
@ -217,6 +300,7 @@ pub fn cmds() -> impl Iterator<Item = Command> {
.chain(member_display_name_cmd)
.chain(member_server_name_cmd)
.chain(member_proxy_cmd)
.chain(member_avatar_cmds)
.chain(member_proxy_settings_cmd)
.chain(member_message_settings_cmd)
.chain(member_delete_cmd)