feat: implement member edit commands

This commit is contained in:
dusk 2025-09-04 00:12:31 +03:00
parent aa397137f2
commit 4a7ee0deb0
No known key found for this signature in database
3 changed files with 794 additions and 641 deletions

View file

@ -16,6 +16,41 @@ public partial class CommandTree
Commands.MemberShow(var param, _) => ctx.Execute<Member>(MemberInfo, m => m.ViewMember(ctx, param.target)), 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.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.MemberSoulscream(var param, _) => ctx.Execute<Member>(MemberInfo, m => m.Soulscream(ctx, param.target)),
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)),
Commands.MemberDescShow(var param, var flags) => ctx.Execute<MemberEdit>(MemberDesc, m => m.ShowDescription(ctx, param.target, flags.GetReplyFormat())),
Commands.MemberDescClear(var param, var flags) => ctx.Execute<MemberEdit>(MemberDesc, m => m.ClearDescription(ctx, param.target, flags.yes)),
Commands.MemberDescUpdate(var param, _) => ctx.Execute<MemberEdit>(MemberDesc, m => m.ChangeDescription(ctx, param.target, param.description)),
Commands.MemberNameShow(var param, var flags) => ctx.Execute<MemberEdit>(MemberInfo, m => m.ShowName(ctx, param.target, flags.GetReplyFormat())),
Commands.MemberNameUpdate(var param, _) => ctx.Execute<MemberEdit>(MemberInfo, m => m.ChangeName(ctx, param.target, param.name)),
Commands.MemberBannerShow(var param, var flags) => ctx.Execute<MemberEdit>(MemberBannerImage, m => m.ShowBannerImage(ctx, param.target, flags.GetReplyFormat())),
Commands.MemberBannerClear(var param, var flags) => ctx.Execute<MemberEdit>(MemberBannerImage, m => m.ClearBannerImage(ctx, param.target, flags.yes)),
Commands.MemberBannerUpdate(var param, _) => ctx.Execute<MemberEdit>(MemberBannerImage, m => m.ChangeBannerImage(ctx, param.target, param.banner)),
Commands.MemberColorShow(var param, var flags) => ctx.Execute<MemberEdit>(MemberColor, m => m.ShowColor(ctx, param.target, flags.GetReplyFormat())),
Commands.MemberColorClear(var param, var flags) => ctx.Execute<MemberEdit>(MemberColor, m => m.ClearColor(ctx, param.target, flags.yes)),
Commands.MemberColorUpdate(var param, _) => ctx.Execute<MemberEdit>(MemberColor, m => m.ChangeColor(ctx, param.target, param.color)),
Commands.MemberBirthdayShow(var param, var flags) => ctx.Execute<MemberEdit>(MemberBirthday, m => m.ShowBirthday(ctx, param.target, flags.GetReplyFormat())),
Commands.MemberBirthdayClear(var param, var flags) => ctx.Execute<MemberEdit>(MemberBirthday, m => m.ClearBirthday(ctx, param.target, flags.yes)),
Commands.MemberBirthdayUpdate(var param, _) => ctx.Execute<MemberEdit>(MemberBirthday, m => m.ChangeBirthday(ctx, param.target, param.birthday)),
Commands.MemberDisplaynameShow(var param, var flags) => ctx.Execute<MemberEdit>(MemberDisplayName, m => m.ShowDisplayName(ctx, param.target, flags.GetReplyFormat())),
Commands.MemberDisplaynameClear(var param, var flags) => ctx.Execute<MemberEdit>(MemberDisplayName, m => m.ClearDisplayName(ctx, param.target, flags.yes)),
Commands.MemberDisplaynameUpdate(var param, _) => ctx.Execute<MemberEdit>(MemberDisplayName, m => m.ChangeDisplayName(ctx, param.target, param.name)),
Commands.MemberServernameShow(var param, var flags) => ctx.Execute<MemberEdit>(MemberServerName, m => m.ShowServerName(ctx, param.target, flags.GetReplyFormat())),
Commands.MemberServernameClear(var param, var flags) => ctx.Execute<MemberEdit>(MemberServerName, m => m.ClearServerName(ctx, param.target, flags.yes)),
Commands.MemberServernameUpdate(var param, _) => ctx.Execute<MemberEdit>(MemberServerName, m => m.ChangeServerName(ctx, param.target, param.name)),
Commands.MemberKeepproxyShow(var param, _) => ctx.Execute<MemberEdit>(MemberKeepProxy, m => m.ShowKeepProxy(ctx, param.target)),
Commands.MemberKeepproxyUpdate(var param, _) => ctx.Execute<MemberEdit>(MemberKeepProxy, m => m.ChangeKeepProxy(ctx, param.target, param.value)),
Commands.MemberServerKeepproxyShow(var param, _) => ctx.Execute<MemberEdit>(MemberServerKeepProxy, m => m.ShowServerKeepProxy(ctx, param.target)),
Commands.MemberServerKeepproxyUpdate(var param, _) => ctx.Execute<MemberEdit>(MemberServerKeepProxy, m => m.ChangeServerKeepProxy(ctx, param.target, param.value)),
Commands.MemberServerKeepproxyClear(var param, var flags) => ctx.Execute<MemberEdit>(MemberServerKeepProxy, m => m.ClearServerKeepProxy(ctx, param.target, flags.yes)),
Commands.MemberTtsShow(var param, _) => ctx.Execute<MemberEdit>(MemberTts, m => m.ShowTts(ctx, param.target)),
Commands.MemberTtsUpdate(var param, _) => ctx.Execute<MemberEdit>(MemberTts, m => m.ChangeTts(ctx, param.target, param.value)),
Commands.MemberAutoproxyShow(var param, _) => ctx.Execute<MemberEdit>(MemberAutoproxy, m => m.ShowAutoproxy(ctx, param.target)),
Commands.MemberAutoproxyUpdate(var param, _) => ctx.Execute<MemberEdit>(MemberAutoproxy, m => m.ChangeAutoproxy(ctx, param.target, param.value)),
Commands.MemberDelete(var param, _) => ctx.Execute<MemberEdit>(MemberDelete, m => m.Delete(ctx, param.target)),
Commands.MemberPrivacyShow(var param, _) => ctx.Execute<MemberEdit>(MemberPrivacy, m => m.ShowPrivacy(ctx, param.target)),
Commands.MemberPrivacyUpdate(var param, _) => ctx.Execute<MemberEdit>(MemberPrivacy, m => m.ChangePrivacy(ctx, param.target, param.member_privacy_target, param.new_privacy_level)),
Commands.CfgApAccountShow => ctx.Execute<Config>(null, m => m.ViewAutoproxyAccount(ctx)), Commands.CfgApAccountShow => ctx.Execute<Config>(null, m => m.ViewAutoproxyAccount(ctx)),
Commands.CfgApAccountUpdate(var param, _) => ctx.Execute<Config>(null, m => m.EditAutoproxyAccount(ctx, param.toggle)), Commands.CfgApAccountUpdate(var param, _) => ctx.Execute<Config>(null, m => m.EditAutoproxyAccount(ctx, param.toggle)),
Commands.CfgApTimeoutShow => ctx.Execute<Config>(null, m => m.ViewAutoproxyTimeout(ctx)), Commands.CfgApTimeoutShow => ctx.Execute<Config>(null, m => m.ViewAutoproxyTimeout(ctx)),
@ -378,45 +413,29 @@ public partial class CommandTree
private async Task HandleMemberCommand(Context ctx) private async Task HandleMemberCommand(Context ctx)
{ {
// TODO: implement // TODO: implement
// if (ctx.Match("new", "n", "add", "create", "register")) if (ctx.Match("list"))
// await ctx.Execute<Member>(MemberNew, m => m.NewMember(ctx)); await ctx.Execute<SystemList>(SystemList, m => m.MemberList(ctx, ctx.System));
// else if (ctx.Match("list")) else if (ctx.Match("commands", "help"))
// await ctx.Execute<SystemList>(SystemList, m => m.MemberList(ctx, ctx.System)); await PrintCommandList(ctx, "members", MemberCommands);
// else if (ctx.Match("commands", "help")) else if (await ctx.MatchMember() is PKMember target)
// await PrintCommandList(ctx, "members", MemberCommands); await HandleMemberCommandTargeted(ctx, target);
// else if (await ctx.MatchMember() is PKMember target) else if (!ctx.HasNext())
// await HandleMemberCommandTargeted(ctx, target); await PrintCommandExpectedError(ctx, MemberNew, MemberInfo, MemberRename, MemberDisplayName,
// else if (!ctx.HasNext()) MemberServerName, MemberDesc, MemberPronouns,
// await PrintCommandExpectedError(ctx, MemberNew, MemberInfo, MemberRename, MemberDisplayName, MemberColor, MemberBirthday, MemberProxy, MemberDelete, MemberAvatar);
// MemberServerName, MemberDesc, MemberPronouns, else
// MemberColor, MemberBirthday, MemberProxy, MemberDelete, MemberAvatar); await ctx.Reply($"{Emojis.Error} {ctx.CreateNotFoundError("Member", ctx.PopArgument())}");
// else
// await ctx.Reply($"{Emojis.Error} {ctx.CreateNotFoundError("Member", ctx.PopArgument())}");
} }
private async Task HandleMemberCommandTargeted(Context ctx, PKMember target) private async Task HandleMemberCommandTargeted(Context ctx, PKMember target)
{ {
// Commands that have a member target (eg. pk;member <member> delete) // Commands that have a member target (eg. pk;member <member> delete)
if (ctx.Match("rename", "name", "changename", "setname", "rn")) if (ctx.Match("proxy", "tags", "proxytags", "brackets"))
await ctx.Execute<MemberEdit>(MemberRename, m => m.Name(ctx, target));
else if (ctx.Match("description", "desc", "describe", "d", "bio", "info", "text", "intro"))
await ctx.Execute<MemberEdit>(MemberDesc, m => m.Description(ctx, target));
else if (ctx.Match("pronouns", "pronoun", "prns", "pn"))
await ctx.Execute<MemberEdit>(MemberPronouns, m => m.Pronouns(ctx, target));
else if (ctx.Match("color", "colour"))
await ctx.Execute<MemberEdit>(MemberColor, m => m.Color(ctx, target));
else if (ctx.Match("birthday", "birth", "bday", "birthdate", "cakeday", "bdate", "bd"))
await ctx.Execute<MemberEdit>(MemberBirthday, m => m.Birthday(ctx, target));
else if (ctx.Match("proxy", "tags", "proxytags", "brackets"))
await ctx.Execute<MemberProxy>(MemberProxy, m => m.Proxy(ctx, target)); await ctx.Execute<MemberProxy>(MemberProxy, m => m.Proxy(ctx, target));
else if (ctx.Match("delete", "remove", "destroy", "erase", "yeet"))
await ctx.Execute<MemberEdit>(MemberDelete, m => m.Delete(ctx, target));
else if (ctx.Match("avatar", "profile", "picture", "icon", "image", "pfp", "pic")) else if (ctx.Match("avatar", "profile", "picture", "icon", "image", "pfp", "pic"))
await ctx.Execute<MemberAvatar>(MemberAvatar, m => m.Avatar(ctx, target)); await ctx.Execute<MemberAvatar>(MemberAvatar, m => m.Avatar(ctx, target));
else if (ctx.Match("proxyavatar", "proxypfp", "webhookavatar", "webhookpfp", "pa", "pavatar", "ppfp")) else if (ctx.Match("proxyavatar", "proxypfp", "webhookavatar", "webhookpfp", "pa", "pavatar", "ppfp"))
await ctx.Execute<MemberAvatar>(MemberAvatar, m => m.WebhookAvatar(ctx, target)); await ctx.Execute<MemberAvatar>(MemberAvatar, m => m.WebhookAvatar(ctx, target));
else if (ctx.Match("banner", "splash", "cover"))
await ctx.Execute<MemberEdit>(MemberBannerImage, m => m.BannerImage(ctx, target));
else if (ctx.Match("group", "groups", "g")) else if (ctx.Match("group", "groups", "g"))
if (ctx.Match("add", "a")) if (ctx.Match("add", "a"))
await ctx.Execute<GroupMember>(MemberGroupAdd, await ctx.Execute<GroupMember>(MemberGroupAdd,
@ -429,27 +448,8 @@ public partial class CommandTree
else if (ctx.Match("serveravatar", "sa", "servericon", "serverimage", "serverpfp", "serverpic", "savatar", "spic", else if (ctx.Match("serveravatar", "sa", "servericon", "serverimage", "serverpfp", "serverpic", "savatar", "spic",
"guildavatar", "guildpic", "guildicon", "sicon", "spfp")) "guildavatar", "guildpic", "guildicon", "sicon", "spfp"))
await ctx.Execute<MemberAvatar>(MemberServerAvatar, m => m.ServerAvatar(ctx, target)); await ctx.Execute<MemberAvatar>(MemberServerAvatar, m => m.ServerAvatar(ctx, target));
else if (ctx.Match("displayname", "dn", "dname", "nick", "nickname", "dispname"))
await ctx.Execute<MemberEdit>(MemberDisplayName, m => m.DisplayName(ctx, target));
else if (ctx.Match("servername", "sn", "sname", "snick", "snickname", "servernick", "servernickname",
"serverdisplayname", "guildname", "guildnick", "guildnickname", "serverdn"))
await ctx.Execute<MemberEdit>(MemberServerName, m => m.ServerName(ctx, target));
else if (ctx.Match("autoproxy", "ap"))
await ctx.Execute<MemberEdit>(MemberAutoproxy, m => m.MemberAutoproxy(ctx, target));
else if (ctx.Match("keepproxy", "keeptags", "showtags", "kp"))
await ctx.Execute<MemberEdit>(MemberKeepProxy, m => m.KeepProxy(ctx, target));
else if (ctx.Match("texttospeech", "text-to-speech", "tts"))
await ctx.Execute<MemberEdit>(MemberTts, m => m.Tts(ctx, target));
else if (ctx.Match("serverkeepproxy", "servershowtags", "guildshowtags", "guildkeeptags", "serverkeeptags", "skp"))
await ctx.Execute<MemberEdit>(MemberServerKeepProxy, m => m.ServerKeepProxy(ctx, target));
else if (ctx.Match("id")) else if (ctx.Match("id"))
await ctx.Execute<Member>(MemberId, m => m.DisplayId(ctx, target)); await ctx.Execute<Member>(MemberId, m => m.DisplayId(ctx, target));
else if (ctx.Match("privacy"))
await ctx.Execute<MemberEdit>(MemberPrivacy, m => m.Privacy(ctx, target, null));
else if (ctx.Match("private", "hidden", "hide"))
await ctx.Execute<MemberEdit>(MemberPrivacy, m => m.Privacy(ctx, target, PrivacyLevel.Private));
else if (ctx.Match("public", "shown", "show", "unhide", "unhidden"))
await ctx.Execute<MemberEdit>(MemberPrivacy, m => m.Privacy(ctx, target, PrivacyLevel.Public));
else else
await PrintCommandNotFoundError(ctx, MemberInfo, MemberRename, MemberDisplayName, MemberServerName, await PrintCommandNotFoundError(ctx, MemberInfo, MemberRename, MemberDisplayName, MemberServerName,
MemberDesc, MemberPronouns, MemberColor, MemberBirthday, MemberProxy, MemberDelete, MemberAvatar, MemberDesc, MemberPronouns, MemberColor, MemberBirthday, MemberProxy, MemberDelete, MemberAvatar,

View file

@ -21,11 +21,7 @@ public class MemberEdit
_avatarHosting = avatarHosting; _avatarHosting = avatarHosting;
} }
public async Task Name(Context ctx, PKMember target) public async Task ShowName(Context ctx, PKMember target, ReplyFormat format)
{
var format = ctx.MatchFormat();
if (!ctx.HasNext() || format != ReplyFormat.Standard)
{ {
var lctx = ctx.DirectLookupContextFor(target.System); var lctx = ctx.DirectLookupContextFor(target.System);
switch (format) switch (format)
@ -46,13 +42,12 @@ public class MemberEdit
await ctx.Reply(replyStrQ); await ctx.Reply(replyStrQ);
break; break;
} }
return;
} }
public async Task ChangeName(Context ctx, PKMember target, string newName)
{
ctx.CheckSystem().CheckOwnMember(target); ctx.CheckSystem().CheckOwnMember(target);
var newName = ctx.RemainderOrNull() ?? throw new PKSyntaxError("You must pass a new name for the member.");
// Hard name length cap // Hard name length cap
if (newName.Length > Limits.MaxMemberNameLength) if (newName.Length > Limits.MaxMemberNameLength)
throw Errors.StringTooLongError("Member name", newName.Length, Limits.MaxMemberNameLength); throw Errors.StringTooLongError("Member name", newName.Length, Limits.MaxMemberNameLength);
@ -85,7 +80,7 @@ public class MemberEdit
await ctx.Reply(replyStr); await ctx.Reply(replyStr);
} }
public async Task Description(Context ctx, PKMember target) public async Task ShowDescription(Context ctx, PKMember target, ReplyFormat format)
{ {
ctx.CheckSystemPrivacy(target.System, target.DescriptionPrivacy); ctx.CheckSystemPrivacy(target.System, target.DescriptionPrivacy);
@ -94,10 +89,8 @@ public class MemberEdit
noDescriptionSetMessage += noDescriptionSetMessage +=
$" To set one, type `{ctx.DefaultPrefix}member {target.Reference(ctx)} description <description>`."; $" To set one, type `{ctx.DefaultPrefix}member {target.Reference(ctx)} description <description>`.";
var format = ctx.MatchFormat();
// if there's nothing next or what's next is "raw"/"plaintext" we're doing a query, so check for null // if there's nothing next or what's next is "raw"/"plaintext" we're doing a query, so check for null
if (!ctx.HasNext(false) || format != ReplyFormat.Standard) if (format != ReplyFormat.Standard)
if (target.Description == null) if (target.Description == null)
{ {
await ctx.Reply(noDescriptionSetMessage); await ctx.Reply(noDescriptionSetMessage);
@ -117,8 +110,6 @@ public class MemberEdit
return; return;
} }
if (!ctx.HasNext(false))
{
await ctx.Reply(embed: new EmbedBuilder() await ctx.Reply(embed: new EmbedBuilder()
.Title("Member description") .Title("Member description")
.Description(target.Description) .Description(target.Description)
@ -129,20 +120,27 @@ public class MemberEdit
+ $" Using {target.Description.Length}/{Limits.MaxDescriptionLength} characters." + $" Using {target.Description.Length}/{Limits.MaxDescriptionLength} characters."
: ""))) : "")))
.Build()); .Build());
return;
} }
public async Task ClearDescription(Context ctx, PKMember target, bool confirmYes)
{
ctx.CheckSystemPrivacy(target.System, target.DescriptionPrivacy);
ctx.CheckOwnMember(target); ctx.CheckOwnMember(target);
if (ctx.MatchClear() && await ctx.ConfirmClear("this member's description")) if (await ctx.ConfirmClear("this member's description", confirmYes))
{ {
var patch = new MemberPatch { Description = Partial<string>.Null() }; var patch = new MemberPatch { Description = Partial<string>.Null() };
await ctx.Repository.UpdateMember(target.Id, patch); await ctx.Repository.UpdateMember(target.Id, patch);
await ctx.Reply($"{Emojis.Success} Member description cleared."); await ctx.Reply($"{Emojis.Success} Member description cleared.");
} }
else }
public async Task ChangeDescription(Context ctx, PKMember target, string _description)
{ {
var description = ctx.RemainderOrNull(false).NormalizeLineEndSpacing(); ctx.CheckSystemPrivacy(target.System, target.DescriptionPrivacy);
ctx.CheckOwnMember(target);
var description = _description.NormalizeLineEndSpacing();
if (description.IsLongerThan(Limits.MaxDescriptionLength)) if (description.IsLongerThan(Limits.MaxDescriptionLength))
throw Errors.StringTooLongError("Description", description.Length, Limits.MaxDescriptionLength); throw Errors.StringTooLongError("Description", description.Length, Limits.MaxDescriptionLength);
@ -151,20 +149,16 @@ public class MemberEdit
await ctx.Reply($"{Emojis.Success} Member description changed (using {description.Length}/{Limits.MaxDescriptionLength} characters)."); await ctx.Reply($"{Emojis.Success} Member description changed (using {description.Length}/{Limits.MaxDescriptionLength} characters).");
} }
}
public async Task Pronouns(Context ctx, PKMember target) public async Task ShowPronouns(Context ctx, PKMember target, ReplyFormat format)
{ {
ctx.CheckSystemPrivacy(target.System, target.PronounPrivacy);
var noPronounsSetMessage = "This member does not have pronouns set."; var noPronounsSetMessage = "This member does not have pronouns set.";
if (ctx.System?.Id == target.System) if (ctx.System?.Id == target.System)
noPronounsSetMessage += $" To set some, type `{ctx.DefaultPrefix}member {target.Reference(ctx)} pronouns <pronouns>`."; noPronounsSetMessage += $" To set some, type `{ctx.DefaultPrefix}member {target.Reference(ctx)} pronouns <pronouns>`.";
ctx.CheckSystemPrivacy(target.System, target.PronounPrivacy); if (format != ReplyFormat.Standard)
var format = ctx.MatchFormat();
// if there's nothing next or what's next is "raw"/"plaintext" we're doing a query, so check for null
if (!ctx.HasNext(false) || format != ReplyFormat.Standard)
if (target.Pronouns == null) if (target.Pronouns == null)
{ {
await ctx.Reply(noPronounsSetMessage); await ctx.Reply(noPronounsSetMessage);
@ -184,28 +178,31 @@ public class MemberEdit
return; return;
} }
if (!ctx.HasNext(false))
{
await ctx.Reply( await ctx.Reply(
$"**{target.NameFor(ctx)}**'s pronouns are **{target.Pronouns}**.\nTo print the pronouns with formatting, type `{ctx.DefaultPrefix}member {target.Reference(ctx)} pronouns -raw`." $"**{target.NameFor(ctx)}**'s pronouns are **{target.Pronouns}**.\nTo print the pronouns with formatting, type `{ctx.DefaultPrefix}member {target.Reference(ctx)} pronouns -raw`."
+ (ctx.System?.Id == target.System + (ctx.System?.Id == target.System
? $" To clear them, type `{ctx.DefaultPrefix}member {target.Reference(ctx)} pronouns -clear`." ? $" To clear them, type `{ctx.DefaultPrefix}member {target.Reference(ctx)} pronouns -clear`."
+ $" Using {target.Pronouns.Length}/{Limits.MaxPronounsLength} characters." + $" Using {target.Pronouns.Length}/{Limits.MaxPronounsLength} characters."
: "")); : ""));
return;
} }
public async Task ClearPronouns(Context ctx, PKMember target, bool confirmYes)
{
ctx.CheckOwnMember(target); ctx.CheckOwnMember(target);
if (ctx.MatchClear() && await ctx.ConfirmClear("this member's pronouns")) if (await ctx.ConfirmClear("this member's pronouns", confirmYes))
{ {
var patch = new MemberPatch { Pronouns = Partial<string>.Null() }; var patch = new MemberPatch { Pronouns = Partial<string>.Null() };
await ctx.Repository.UpdateMember(target.Id, patch); await ctx.Repository.UpdateMember(target.Id, patch);
await ctx.Reply($"{Emojis.Success} Member pronouns cleared."); await ctx.Reply($"{Emojis.Success} Member pronouns cleared.");
} }
else }
public async Task ChangePronouns(Context ctx, PKMember target, string pronouns)
{ {
var pronouns = ctx.RemainderOrNull(false).NormalizeLineEndSpacing(); ctx.CheckOwnMember(target);
pronouns = pronouns.NormalizeLineEndSpacing();
if (pronouns.IsLongerThan(Limits.MaxPronounsLength)) if (pronouns.IsLongerThan(Limits.MaxPronounsLength))
throw Errors.StringTooLongError("Pronouns", pronouns.Length, Limits.MaxPronounsLength); throw Errors.StringTooLongError("Pronouns", pronouns.Length, Limits.MaxPronounsLength);
@ -214,22 +211,58 @@ public class MemberEdit
await ctx.Reply($"{Emojis.Success} Member pronouns changed (using {pronouns.Length}/{Limits.MaxPronounsLength} characters)."); await ctx.Reply($"{Emojis.Success} Member pronouns changed (using {pronouns.Length}/{Limits.MaxPronounsLength} characters).");
} }
public async Task ShowBannerImage(Context ctx, PKMember target, ReplyFormat format)
{
ctx.CheckSystemPrivacy(target.System, target.BannerPrivacy);
var noBannerSetMessage = "This member does not have a banner image set.";
if (ctx.System?.Id == target.System)
noBannerSetMessage += $" To set one, type `{ctx.DefaultPrefix}member {target.Reference(ctx)} banner <url>` or attach an image.";
if (format != ReplyFormat.Standard)
if (string.IsNullOrWhiteSpace(target.BannerImage))
{
await ctx.Reply(noBannerSetMessage);
return;
} }
public async Task BannerImage(Context ctx, PKMember target) if (format == ReplyFormat.Raw)
{ {
async Task ClearBannerImage() await ctx.Reply($"```\n{target.BannerImage.TryGetCleanCdnUrl()}\n```");
return;
}
if (format == ReplyFormat.Plaintext)
{
var eb = new EmbedBuilder()
.Description($"Showing banner for member {target.NameFor(ctx)} (`{target.DisplayHid(ctx.Config)}`)");
await ctx.Reply(text: $"<{target.BannerImage.TryGetCleanCdnUrl()}>", embed: eb.Build());
return;
}
var embed = new EmbedBuilder()
.Title($"{target.NameFor(ctx)}'s banner image")
.Image(new Embed.EmbedImage(target.BannerImage.TryGetCleanCdnUrl()));
if (target.System == ctx.System?.Id)
embed.Description($"To clear, type `{ctx.DefaultPrefix}member {target.Reference(ctx)} banner -clear`.");
await ctx.Reply(embed: embed.Build());
}
public async Task ClearBannerImage(Context ctx, PKMember target, bool confirmYes)
{ {
ctx.CheckOwnMember(target); ctx.CheckOwnMember(target);
await ctx.ConfirmClear("this member's banner image");
if (await ctx.ConfirmClear("this member's banner image", confirmYes))
{
await ctx.Repository.UpdateMember(target.Id, new MemberPatch { BannerImage = null }); await ctx.Repository.UpdateMember(target.Id, new MemberPatch { BannerImage = null });
await ctx.Reply($"{Emojis.Success} Member banner image cleared."); await ctx.Reply($"{Emojis.Success} Member banner image cleared.");
} }
}
async Task SetBannerImage(ParsedImage img) public async Task ChangeBannerImage(Context ctx, PKMember target, ParsedImage img)
{ {
ctx.CheckOwnMember(target); ctx.CheckOwnMember(target);
img = await _avatarHosting.TryRehostImage(img, AvatarHostingService.RehostedImageType.Banner, ctx.Author.Id, ctx.System); img = await _avatarHosting.TryRehostImage(img, AvatarHostingService.RehostedImageType.Banner, ctx.Author.Id, ctx.System);
await _avatarHosting.VerifyAvatarOrThrow(img.Url, true); await _avatarHosting.VerifyAvatarOrThrow(img.Url, true);
@ -252,84 +285,57 @@ public class MemberEdit
: ctx.Reply(msg)); : ctx.Reply(msg));
} }
async Task ShowBannerImage() public async Task ShowColor(Context ctx, PKMember target, ReplyFormat format)
{
ctx.CheckSystemPrivacy(target.System, target.BannerPrivacy);
if ((target.BannerImage?.Trim() ?? "").Length > 0)
switch (ctx.MatchFormat())
{
case ReplyFormat.Raw:
await ctx.Reply($"`{target.BannerImage.TryGetCleanCdnUrl()}`");
break;
case ReplyFormat.Plaintext:
var ebP = new EmbedBuilder()
.Description($"Showing banner for member {target.NameFor(ctx)} (`{target.DisplayHid(ctx.Config)}`)");
await ctx.Reply(text: $"<{target.BannerImage.TryGetCleanCdnUrl()}>", embed: ebP.Build());
break;
default:
var ebS = new EmbedBuilder()
.Title($"{target.NameFor(ctx)}'s banner image")
.Image(new Embed.EmbedImage(target.BannerImage.TryGetCleanCdnUrl()));
if (target.System == ctx.System?.Id)
ebS.Description($"To clear, use `{ctx.DefaultPrefix}member {target.Reference(ctx)} banner clear`.");
await ctx.Reply(embed: ebS.Build());
break;
}
else
throw new PKSyntaxError(
"This member does not have a banner image set." + ((target.System == ctx.System?.Id) ? " Set one by attaching an image to this command, or by passing an image URL." : ""));
}
if (ctx.MatchClear())
await ClearBannerImage();
else if (await ctx.MatchImage() is { } img)
await SetBannerImage(img);
else
await ShowBannerImage();
}
public async Task Color(Context ctx, PKMember target)
{
var isOwnSystem = ctx.System?.Id == target.System;
var matchedFormat = ctx.MatchFormat();
var matchedClear = ctx.MatchClear();
if (!isOwnSystem || !(ctx.HasNext() || matchedClear))
{ {
if (target.Color == null) if (target.Color == null)
{
await ctx.Reply( await ctx.Reply(
"This member does not have a color set." + (isOwnSystem ? $" To set one, type `{ctx.DefaultPrefix}member {target.Reference(ctx)} color <color>`." : "")); "This member does not have a color set." + (ctx.System?.Id == target.System ? $" To set one, type `{ctx.DefaultPrefix}member {target.Reference(ctx)} color <color>`." : ""));
else if (matchedFormat == ReplyFormat.Raw) return;
}
if (format == ReplyFormat.Raw)
{
await ctx.Reply("```\n#" + target.Color + "\n```"); await ctx.Reply("```\n#" + target.Color + "\n```");
else if (matchedFormat == ReplyFormat.Plaintext) return;
}
if (format == ReplyFormat.Plaintext)
{
await ctx.Reply(target.Color); await ctx.Reply(target.Color);
else return;
}
await ctx.Reply(embed: new EmbedBuilder() await ctx.Reply(embed: new EmbedBuilder()
.Title("Member color") .Title("Member color")
.Color(target.Color.ToDiscordColor()) .Color(target.Color.ToDiscordColor())
.Thumbnail(new Embed.EmbedThumbnail($"attachment://color.gif")) .Thumbnail(new Embed.EmbedThumbnail($"attachment://color.gif"))
.Description($"This member's color is **#{target.Color}**." .Description($"This member's color is **#{target.Color}**."
+ (isOwnSystem ? $" To clear it, type `{ctx.DefaultPrefix}member {target.Reference(ctx)} color -clear`." : "")) + (ctx.System?.Id == target.System ? $" To clear it, type `{ctx.DefaultPrefix}member {target.Reference(ctx)} color -clear`." : ""))
.Build(), .Build(),
files: [MiscUtils.GenerateColorPreview(target.Color)]); files: [MiscUtils.GenerateColorPreview(target.Color)]);
return;
} }
public async Task ClearColor(Context ctx, PKMember target, bool confirmYes)
{
ctx.CheckSystem().CheckOwnMember(target); ctx.CheckSystem().CheckOwnMember(target);
if (matchedClear) if (await ctx.ConfirmClear("this member's color", confirmYes))
{ {
await ctx.Repository.UpdateMember(target.Id, new() { Color = Partial<string>.Null() }); await ctx.Repository.UpdateMember(target.Id, new() { Color = Partial<string>.Null() });
await ctx.Reply($"{Emojis.Success} Member color cleared."); await ctx.Reply($"{Emojis.Success} Member color cleared.");
} }
else }
{
var color = ctx.RemainderOrNull();
if (color.StartsWith("#")) color = color.Substring(1); public async Task ChangeColor(Context ctx, PKMember target, string color)
if (!Regex.IsMatch(color, "^[0-9a-fA-F]{6}$")) throw Errors.InvalidColorError(color); {
ctx.CheckSystem().CheckOwnMember(target);
if (color.StartsWith("#"))
color = color.Substring(1);
if (!Regex.IsMatch(color, "^[0-9a-fA-F]{6}$"))
throw Errors.InvalidColorError(color);
var patch = new MemberPatch { Color = Partial<string>.Present(color.ToLowerInvariant()) }; var patch = new MemberPatch { Color = Partial<string>.Present(color.ToLowerInvariant()) };
await ctx.Repository.UpdateMember(target.Id, patch); await ctx.Repository.UpdateMember(target.Id, patch);
@ -341,39 +347,57 @@ public class MemberEdit
.Build(), .Build(),
files: [MiscUtils.GenerateColorPreview(color)]); files: [MiscUtils.GenerateColorPreview(color)]);
} }
}
public async Task Birthday(Context ctx, PKMember target) public async Task ShowBirthday(Context ctx, PKMember target, ReplyFormat format)
{
if (ctx.MatchClear() && await ctx.ConfirmClear("this member's birthday"))
{
ctx.CheckOwnMember(target);
var patch = new MemberPatch { Birthday = Partial<LocalDate?>.Null() };
await ctx.Repository.UpdateMember(target.Id, patch);
await ctx.Reply($"{Emojis.Success} Member birthdate cleared.");
}
else if (!ctx.HasNext())
{ {
ctx.CheckSystemPrivacy(target.System, target.BirthdayPrivacy); ctx.CheckSystemPrivacy(target.System, target.BirthdayPrivacy);
var noBirthdaySetMessage = "This member does not have a birthdate set.";
if (ctx.System?.Id == target.System)
noBirthdaySetMessage += $" To set one, type `{ctx.DefaultPrefix}member {target.Reference(ctx)} birthday <birthdate>`.";
// if what's next is "raw"/"plaintext" we need to check for null
if (format != ReplyFormat.Standard)
if (target.Birthday == null) if (target.Birthday == null)
await ctx.Reply("This member does not have a birthdate set." {
+ (ctx.System?.Id == target.System await ctx.Reply(noBirthdaySetMessage);
? $" To set one, type `{ctx.DefaultPrefix}member {target.Reference(ctx)} birthdate <birthdate>`." return;
: "")); }
else
if (format == ReplyFormat.Raw)
{
await ctx.Reply($"```\n{target.Birthday}\n```");
return;
}
if (format == ReplyFormat.Plaintext)
{
var eb = new EmbedBuilder()
.Description($"Showing birthday for member {target.NameFor(ctx)} (`{target.DisplayHid(ctx.Config)}`)");
await ctx.Reply(target.BirthdayString, embed: eb.Build());
return;
}
await ctx.Reply($"This member's birthdate is **{target.BirthdayString}**." await ctx.Reply($"This member's birthdate is **{target.BirthdayString}**."
+ (ctx.System?.Id == target.System + (ctx.System?.Id == target.System
? $" To clear it, type `{ctx.DefaultPrefix}member {target.Reference(ctx)} birthdate -clear`." ? $" To clear it, type `{ctx.DefaultPrefix}member {target.Reference(ctx)} birthday -clear`."
: "")); : ""));
} }
else
public async Task ClearBirthday(Context ctx, PKMember target, bool confirmYes)
{ {
ctx.CheckOwnMember(target); ctx.CheckOwnMember(target);
var birthdayStr = ctx.RemainderOrNull(); if (await ctx.ConfirmClear("this member's birthday", confirmYes))
{
var patch = new MemberPatch { Birthday = Partial<LocalDate?>.Null() };
await ctx.Repository.UpdateMember(target.Id, patch);
await ctx.Reply($"{Emojis.Success} Member birthdate cleared.");
}
}
public async Task ChangeBirthday(Context ctx, PKMember target, string birthdayStr)
{
ctx.CheckOwnMember(target);
LocalDate? birthday; LocalDate? birthday;
if (birthdayStr == "today" || birthdayStr == "now") if (birthdayStr == "today" || birthdayStr == "now")
@ -381,14 +405,14 @@ public class MemberEdit
else else
birthday = DateUtils.ParseDate(birthdayStr, true); birthday = DateUtils.ParseDate(birthdayStr, true);
if (birthday == null) throw Errors.BirthdayParseError(birthdayStr); if (birthday == null)
throw Errors.BirthdayParseError(birthdayStr);
var patch = new MemberPatch { Birthday = Partial<LocalDate?>.Present(birthday) }; var patch = new MemberPatch { Birthday = Partial<LocalDate?>.Present(birthday) };
await ctx.Repository.UpdateMember(target.Id, patch); await ctx.Repository.UpdateMember(target.Id, patch);
await ctx.Reply($"{Emojis.Success} Member birthdate changed."); await ctx.Reply($"{Emojis.Success} Member birthdate changed.");
} }
}
private string boldIf(string str, bool condition) => condition ? $"**{str}**" : str; private string boldIf(string str, bool condition) => condition ? $"**{str}**" : str;
@ -429,33 +453,14 @@ public class MemberEdit
return eb; return eb;
} }
public async Task DisplayName(Context ctx, PKMember target) public async Task ShowDisplayName(Context ctx, PKMember target, ReplyFormat format)
{ {
async Task PrintSuccess(string text)
{
var successStr = text;
if (ctx.Guild != null)
{
var memberGuildConfig = await ctx.Repository.GetMemberGuild(ctx.Guild.Id, target.Id);
if (memberGuildConfig.DisplayName != null)
successStr +=
$" However, this member has a server name set in this server ({ctx.Guild.Name}), and will be proxied using that name, \"{memberGuildConfig.DisplayName}\", here.";
}
await ctx.Reply(successStr);
}
var isOwner = ctx.System?.Id == target.System; var isOwner = ctx.System?.Id == target.System;
var noDisplayNameSetMessage = $"This member does not have a display name set{(isOwner ? "" : " or name is private")}." var noDisplayNameSetMessage = $"This member does not have a display name set{(isOwner ? "" : " or name is private")}."
+ (isOwner ? $" To set one, type `{ctx.DefaultPrefix}member {target.Reference(ctx)} displayname <display name>`." : ""); + (isOwner ? $" To set one, type `{ctx.DefaultPrefix}member {target.Reference(ctx)} displayname <display name>`." : "");
// Whether displayname is shown or not should depend on if member name privacy is set. // Whether displayname is shown or not should depend on if member name privacy is set.
// If name privacy is on then displayname should look like name. // If name privacy is on then displayname should look like name.
var format = ctx.MatchFormat();
// if what's next is "raw"/"plaintext" we need to check for null
if (format != ReplyFormat.Standard)
if (target.DisplayName == null || !target.NamePrivacy.CanAccess(ctx.DirectLookupContextFor(target.System))) if (target.DisplayName == null || !target.NamePrivacy.CanAccess(ctx.DirectLookupContextFor(target.System)))
{ {
await ctx.Reply(noDisplayNameSetMessage); await ctx.Reply(noDisplayNameSetMessage);
@ -469,14 +474,12 @@ public class MemberEdit
} }
if (format == ReplyFormat.Plaintext) if (format == ReplyFormat.Plaintext)
{ {
var eb = new EmbedBuilder() var _eb = new EmbedBuilder()
.Description($"Showing displayname for member {target.NameFor(ctx)} (`{target.DisplayHid(ctx.Config)}`)"); .Description($"Showing displayname for member {target.NameFor(ctx)} (`{target.DisplayHid(ctx.Config)}`)");
await ctx.Reply(target.DisplayName, embed: eb.Build()); await ctx.Reply(target.DisplayName, embed: _eb.Build());
return; return;
} }
if (!ctx.HasNext(false))
{
var eb = await CreateMemberNameInfoEmbed(ctx, target); var eb = await CreateMemberNameInfoEmbed(ctx, target);
var reference = target.Reference(ctx); var reference = target.Reference(ctx);
if (ctx.System?.Id == target.System) if (ctx.System?.Id == target.System)
@ -485,38 +488,59 @@ public class MemberEdit
+ $"To clear it, type `{ctx.DefaultPrefix}member {reference} displayname -clear`.\n" + $"To clear it, type `{ctx.DefaultPrefix}member {reference} displayname -clear`.\n"
+ $"To print the raw display name, type `{ctx.DefaultPrefix}member {reference} displayname -raw`."); + $"To print the raw display name, type `{ctx.DefaultPrefix}member {reference} displayname -raw`.");
await ctx.Reply(embed: eb.Build()); await ctx.Reply(embed: eb.Build());
return;
} }
public async Task ClearDisplayName(Context ctx, PKMember target, bool confirmYes)
{
ctx.CheckOwnMember(target); ctx.CheckOwnMember(target);
if (ctx.MatchClear() && await ctx.ConfirmClear("this member's display name")) if (await ctx.ConfirmClear("this member's display name", confirmYes))
{ {
var patch = new MemberPatch { DisplayName = Partial<string>.Null() }; var patch = new MemberPatch { DisplayName = Partial<string>.Null() };
await ctx.Repository.UpdateMember(target.Id, patch); await ctx.Repository.UpdateMember(target.Id, patch);
await PrintSuccess( var successStr = $"{Emojis.Success} Member display name cleared. This member will now be proxied using their member name \"{target.Name}\".";
$"{Emojis.Success} Member display name cleared. This member will now be proxied using their member name \"{target.Name}\".");
if (ctx.Guild != null)
{
var memberGuildConfig = await ctx.Repository.GetMemberGuild(ctx.Guild.Id, target.Id);
if (memberGuildConfig.DisplayName != null)
successStr +=
$" However, this member has a server name set in this server ({ctx.Guild.Name}), and will be proxied using that name, \"{memberGuildConfig.DisplayName}\", here.";
}
await ctx.Reply(successStr);
if (target.NamePrivacy == PrivacyLevel.Private) if (target.NamePrivacy == PrivacyLevel.Private)
await ctx.Reply($"{Emojis.Warn} Since this member no longer has a display name set, their name privacy **can no longer take effect**."); await ctx.Reply($"{Emojis.Warn} Since this member no longer has a display name set, their name privacy **can no longer take effect**.");
} }
else }
{
var newDisplayName = ctx.RemainderOrNull(false).NormalizeLineEndSpacing();
public async Task ChangeDisplayName(Context ctx, PKMember target, string newDisplayName)
{
ctx.CheckOwnMember(target);
newDisplayName = newDisplayName.NormalizeLineEndSpacing();
if (newDisplayName.Length > Limits.MaxMemberNameLength) if (newDisplayName.Length > Limits.MaxMemberNameLength)
throw Errors.StringTooLongError("Member display name", newDisplayName.Length, Limits.MaxMemberNameLength); throw Errors.StringTooLongError("Member display name", newDisplayName.Length, Limits.MaxMemberNameLength);
var patch = new MemberPatch { DisplayName = Partial<string>.Present(newDisplayName) }; var patch = new MemberPatch { DisplayName = Partial<string>.Present(newDisplayName) };
await ctx.Repository.UpdateMember(target.Id, patch); await ctx.Repository.UpdateMember(target.Id, patch);
await PrintSuccess( var successStr = $"{Emojis.Success} Member display name changed (using {newDisplayName.Length}/{Limits.MaxMemberNameLength} characters). This member will now be proxied using the name \"{newDisplayName}\".";
$"{Emojis.Success} Member display name changed (using {newDisplayName.Length}/{Limits.MaxMemberNameLength} characters). This member will now be proxied using the name \"{newDisplayName}\".");
} if (ctx.Guild != null)
{
var memberGuildConfig = await ctx.Repository.GetMemberGuild(ctx.Guild.Id, target.Id);
if (memberGuildConfig.DisplayName != null)
successStr +=
$" However, this member has a server name set in this server ({ctx.Guild.Name}), and will be proxied using that name, \"{memberGuildConfig.DisplayName}\", here.";
} }
public async Task ServerName(Context ctx, PKMember target) await ctx.Reply(successStr);
}
public async Task ShowServerName(Context ctx, PKMember target, ReplyFormat format)
{ {
ctx.CheckGuildContext(); ctx.CheckGuildContext();
@ -525,12 +549,8 @@ public class MemberEdit
noServerNameSetMessage += noServerNameSetMessage +=
$" To set one, type `{ctx.DefaultPrefix}member {target.Reference(ctx)} servername <server name>`."; $" To set one, type `{ctx.DefaultPrefix}member {target.Reference(ctx)} servername <server name>`.";
// No perms check, display name isn't covered by member privacy
var memberGuildConfig = await ctx.Repository.GetMemberGuild(ctx.Guild.Id, target.Id); var memberGuildConfig = await ctx.Repository.GetMemberGuild(ctx.Guild.Id, target.Id);
var format = ctx.MatchFormat();
// if what's next is "raw"/"plaintext" we need to check for null
if (format != ReplyFormat.Standard) if (format != ReplyFormat.Standard)
if (memberGuildConfig.DisplayName == null) if (memberGuildConfig.DisplayName == null)
{ {
@ -545,26 +565,26 @@ public class MemberEdit
} }
if (format == ReplyFormat.Plaintext) if (format == ReplyFormat.Plaintext)
{ {
var eb = new EmbedBuilder() var _eb = new EmbedBuilder()
.Description($"Showing servername for member {target.NameFor(ctx)} (`{target.DisplayHid(ctx.Config)}`)"); .Description($"Showing servername for member {target.NameFor(ctx)} (`{target.DisplayHid(ctx.Config)}`)");
await ctx.Reply(memberGuildConfig.DisplayName, embed: eb.Build()); await ctx.Reply(memberGuildConfig.DisplayName, embed: _eb.Build());
return; return;
} }
if (!ctx.HasNext(false))
{
var eb = await CreateMemberNameInfoEmbed(ctx, target); var eb = await CreateMemberNameInfoEmbed(ctx, target);
var reference = target.Reference(ctx); var reference = target.Reference(ctx);
if (ctx.System?.Id == target.System) if (ctx.System?.Id == target.System)
eb.Description( eb.Description(
$"To change server name, type `{ctx.DefaultPrefix}member {reference} servername <server name>`.\nTo clear it, type `{ctx.DefaultPrefix}member {reference} servername -clear`.\nTo print the raw server name, type `{ctx.DefaultPrefix}member {reference} servername -raw`."); $"To change server name, type `{ctx.DefaultPrefix}member {reference} servername <server name>`.\nTo clear it, type `{ctx.DefaultPrefix}member {reference} servername -clear`.\nTo print the raw server name, type `{ctx.DefaultPrefix}member {reference} servername -raw`.");
await ctx.Reply(embed: eb.Build()); await ctx.Reply(embed: eb.Build());
return;
} }
public async Task ClearServerName(Context ctx, PKMember target, bool confirmYes)
{
ctx.CheckGuildContext();
ctx.CheckOwnMember(target); ctx.CheckOwnMember(target);
if (ctx.MatchClear() && await ctx.ConfirmClear("this member's server name")) if (await ctx.ConfirmClear("this member's server name", confirmYes))
{ {
await ctx.Repository.UpdateMemberGuild(target.Id, ctx.Guild.Id, new MemberGuildPatch { DisplayName = null }); await ctx.Repository.UpdateMemberGuild(target.Id, ctx.Guild.Id, new MemberGuildPatch { DisplayName = null });
@ -575,9 +595,16 @@ public class MemberEdit
await ctx.Reply( await ctx.Reply(
$"{Emojis.Success} Member server name cleared. This member will now be proxied using their member name \"{target.NameFor(ctx)}\" in this server ({ctx.Guild.Name})."); $"{Emojis.Success} Member server name cleared. This member will now be proxied using their member name \"{target.NameFor(ctx)}\" in this server ({ctx.Guild.Name}).");
} }
else }
public async Task ChangeServerName(Context ctx, PKMember target, string newServerName)
{ {
var newServerName = ctx.RemainderOrNull(false).NormalizeLineEndSpacing(); ctx.CheckGuildContext();
ctx.CheckOwnMember(target);
newServerName = newServerName.NormalizeLineEndSpacing();
if (newServerName.Length > Limits.MaxMemberNameLength)
throw Errors.StringTooLongError("Server name", newServerName.Length, Limits.MaxMemberNameLength);
await ctx.Repository.UpdateMemberGuild(target.Id, ctx.Guild.Id, await ctx.Repository.UpdateMemberGuild(target.Id, ctx.Guild.Id,
new MemberGuildPatch { DisplayName = newServerName }); new MemberGuildPatch { DisplayName = newServerName });
@ -585,31 +612,8 @@ public class MemberEdit
await ctx.Reply( await ctx.Reply(
$"{Emojis.Success} Member server name changed (using {newServerName.Length}/{Limits.MaxMemberNameLength} characters). This member will now be proxied using the name \"{newServerName}\" in this server ({ctx.Guild.Name})."); $"{Emojis.Success} Member server name changed (using {newServerName.Length}/{Limits.MaxMemberNameLength} characters). This member will now be proxied using the name \"{newServerName}\" in this server ({ctx.Guild.Name}).");
} }
}
public async Task KeepProxy(Context ctx, PKMember target) public async Task ShowKeepProxy(Context ctx, PKMember target)
{
ctx.CheckSystem().CheckOwnMember(target);
MemberGuildSettings? memberGuildConfig = null;
if (ctx.Guild != null)
{
memberGuildConfig = await ctx.Repository.GetMemberGuild(ctx.Guild.Id, target.Id);
}
bool newValue;
if (ctx.Match("on", "enabled", "true", "yes"))
{
newValue = true;
}
else if (ctx.Match("off", "disabled", "false", "no"))
{
newValue = false;
}
else if (ctx.HasNext())
{
throw new PKSyntaxError("You must pass either \"on\" or \"off\".");
}
else
{ {
string keepProxyStatusMessage = ""; string keepProxyStatusMessage = "";
@ -618,16 +622,25 @@ public class MemberEdit
else else
keepProxyStatusMessage += "This member has keepproxy **disabled**. Proxy tags will **not** be included in the resulting message when proxying."; keepProxyStatusMessage += "This member has keepproxy **disabled**. Proxy tags will **not** be included in the resulting message when proxying.";
if (memberGuildConfig != null && memberGuildConfig.KeepProxy.HasValue && memberGuildConfig.KeepProxy.Value) if (ctx.Guild != null)
keepProxyStatusMessage += $"\n{Emojis.Warn} This member has keepproxy **enabled in this server**, which means proxy tags will **always** be included when proxying in this server, regardless of the global keepproxy. To clear this setting in this server, type `{ctx.DefaultPrefix}m <member> serverkeepproxy clear`."; {
else if (memberGuildConfig != null && memberGuildConfig.KeepProxy.HasValue && !memberGuildConfig.KeepProxy.Value) var memberGuildConfig = await ctx.Repository.GetMemberGuild(ctx.Guild.Id, target.Id);
keepProxyStatusMessage += $"\n{Emojis.Warn} This member has keepproxy **disabled in this server**, which means proxy tags will **never** be included when proxying in this server, regardless of the global keepproxy. To clear this setting in this server, type `{ctx.DefaultPrefix}m <member> serverkeepproxy clear`.";
await ctx.Reply(keepProxyStatusMessage); if (memberGuildConfig?.KeepProxy.HasValue == true)
return; {
if (memberGuildConfig.KeepProxy.Value)
keepProxyStatusMessage += $"\n{Emojis.Warn} This member has keepproxy **enabled in this server**, which means proxy tags will **always** be included when proxying in this server, regardless of the global keepproxy. To clear this setting in this server, type `{ctx.DefaultPrefix}m <member> serverkeepproxy clear`.";
else
keepProxyStatusMessage += $"\n{Emojis.Warn} This member has keepproxy **disabled in this server**, which means proxy tags will **never** be included when proxying in this server, regardless of the global keepproxy. To clear this setting in this server, type `{ctx.DefaultPrefix}m <member> serverkeepproxy clear`.";
}
} }
; await ctx.Reply(keepProxyStatusMessage);
}
public async Task ChangeKeepProxy(Context ctx, PKMember target, bool newValue)
{
ctx.CheckSystem().CheckOwnMember(target);
var patch = new MemberPatch { KeepProxy = Partial<bool>.Present(newValue) }; var patch = new MemberPatch { KeepProxy = Partial<bool>.Present(newValue) };
await ctx.Repository.UpdateMember(target.Id, patch); await ctx.Repository.UpdateMember(target.Id, patch);
@ -639,47 +652,35 @@ public class MemberEdit
else else
keepProxyUpdateMessage += $"{Emojis.Success} this member now has keepproxy **disabled**. Member proxy tags will **not** be included in the resulting message when proxying."; keepProxyUpdateMessage += $"{Emojis.Success} this member now has keepproxy **disabled**. Member proxy tags will **not** be included in the resulting message when proxying.";
if (memberGuildConfig != null && memberGuildConfig.KeepProxy.HasValue && memberGuildConfig.KeepProxy.Value) if (ctx.Guild != null)
{
var memberGuildConfig = await ctx.Repository.GetMemberGuild(ctx.Guild.Id, target.Id);
if (memberGuildConfig?.KeepProxy.HasValue == true)
{
if (memberGuildConfig.KeepProxy.Value)
keepProxyUpdateMessage += $"\n{Emojis.Warn} This member has keepproxy **enabled in this server**, which means proxy tags will **always** be included when proxying in this server, regardless of the global keepproxy. To clear this setting in this server, type `{ctx.DefaultPrefix}m <member> serverkeepproxy clear`."; keepProxyUpdateMessage += $"\n{Emojis.Warn} This member has keepproxy **enabled in this server**, which means proxy tags will **always** be included when proxying in this server, regardless of the global keepproxy. To clear this setting in this server, type `{ctx.DefaultPrefix}m <member> serverkeepproxy clear`.";
else if (memberGuildConfig != null && memberGuildConfig.KeepProxy.HasValue && !memberGuildConfig.KeepProxy.Value) else
keepProxyUpdateMessage += $"\n{Emojis.Warn} This member has keepproxy **disabled in this server**, which means proxy tags will **never** be included when proxying in this server, regardless of the global keepproxy. To clear this setting in this server, type `{ctx.DefaultPrefix}m <member> serverkeepproxy clear`."; keepProxyUpdateMessage += $"\n{Emojis.Warn} This member has keepproxy **disabled in this server**, which means proxy tags will **never** be included when proxying in this server, regardless of the global keepproxy. To clear this setting in this server, type `{ctx.DefaultPrefix}m <member> serverkeepproxy clear`.";
}
}
await ctx.Reply(keepProxyUpdateMessage); await ctx.Reply(keepProxyUpdateMessage);
} }
public async Task ServerKeepProxy(Context ctx, PKMember target) public async Task ShowServerKeepProxy(Context ctx, PKMember target)
{ {
ctx.CheckGuildContext(); ctx.CheckGuildContext();
ctx.CheckSystem().CheckOwnMember(target);
var memberGuildConfig = await ctx.Repository.GetMemberGuild(ctx.Guild.Id, target.Id); var memberGuildConfig = await ctx.Repository.GetMemberGuild(ctx.Guild.Id, target.Id);
bool? newValue;
if (ctx.Match("on", "enabled", "true", "yes"))
{
newValue = true;
}
else if (ctx.Match("off", "disabled", "false", "no"))
{
newValue = false;
}
else if (ctx.MatchClear())
{
newValue = null;
}
else if (ctx.HasNext())
{
throw new PKSyntaxError("You must pass either \"on\", \"off\" or \"clear\".");
}
else
{
if (memberGuildConfig.KeepProxy.HasValue) if (memberGuildConfig.KeepProxy.HasValue)
{
if (memberGuildConfig.KeepProxy.Value) if (memberGuildConfig.KeepProxy.Value)
await ctx.Reply( await ctx.Reply($"This member has keepproxy **enabled** in the current server, which means proxy tags will be **included** in the resulting message when proxying. To clear this setting in this server, type `{ctx.DefaultPrefix}m <member> serverkeepproxy clear`.");
$"This member has keepproxy **enabled** in the current server, which means proxy tags will be **included** in the resulting message when proxying. To clear this setting in this server, type `{ctx.DefaultPrefix}m <member> serverkeepproxy clear`.");
else else
await ctx.Reply( await ctx.Reply($"This member has keepproxy **disabled** in the current server, which means proxy tags will **not** be included in the resulting message when proxying. To clear this setting in this server, type `{ctx.DefaultPrefix}m <member> serverkeepproxy clear`.");
$"This member has keepproxy **disabled** in the current server, which means proxy tags will **not** be included in the resulting message when proxying. To clear this setting in this server, type `{ctx.DefaultPrefix}m <member> serverkeepproxy clear`."); }
else else
{ {
var noServerKeepProxySetMessage = "This member does not have a server keepproxy override set."; var noServerKeepProxySetMessage = "This member does not have a server keepproxy override set.";
@ -690,23 +691,19 @@ public class MemberEdit
await ctx.Reply(noServerKeepProxySetMessage); await ctx.Reply(noServerKeepProxySetMessage);
} }
return;
} }
var patch = new MemberGuildPatch { KeepProxy = Partial<bool?>.Present(newValue) }; public async Task ClearServerKeepProxy(Context ctx, PKMember target, bool confirmYes)
{
ctx.CheckGuildContext();
ctx.CheckSystem().CheckOwnMember(target);
if (await ctx.ConfirmClear("this member's server keepproxy setting", confirmYes))
{
var patch = new MemberGuildPatch { KeepProxy = Partial<bool?>.Present(null) };
await ctx.Repository.UpdateMemberGuild(target.Id, ctx.Guild.Id, patch); await ctx.Repository.UpdateMemberGuild(target.Id, ctx.Guild.Id, patch);
if (newValue.HasValue)
if (newValue.Value)
await ctx.Reply(
$"{Emojis.Success} Member proxy tags will now be **included** in the resulting message when proxying **in the current server**. To clear this setting in this server, type `{ctx.DefaultPrefix}m <member> serverkeepproxy clear`.");
else
await ctx.Reply(
$"{Emojis.Success} Member proxy tags will now **not** be included in the resulting message when proxying **in the current server**. To clear this setting in this server, type `{ctx.DefaultPrefix}m <member> serverkeepproxy clear`.");
else
{
var serverKeepProxyClearedMessage = $"{Emojis.Success} Cleared server keepproxy settings for this member."; var serverKeepProxyClearedMessage = $"{Emojis.Success} Cleared server keepproxy settings for this member.";
if (target.KeepProxy) if (target.KeepProxy)
serverKeepProxyClearedMessage += " Member proxy tags will now be **included** in the resulting message when proxying."; serverKeepProxyClearedMessage += " Member proxy tags will now be **included** in the resulting message when proxying.";
else else
@ -716,24 +713,21 @@ public class MemberEdit
} }
} }
public async Task Tts(Context ctx, PKMember target) public async Task ChangeServerKeepProxy(Context ctx, PKMember target, bool newValue)
{ {
ctx.CheckGuildContext();
ctx.CheckSystem().CheckOwnMember(target); ctx.CheckSystem().CheckOwnMember(target);
bool newValue; var patch = new MemberGuildPatch { KeepProxy = Partial<bool?>.Present(newValue) };
if (ctx.Match("on", "enabled", "true", "yes")) await ctx.Repository.UpdateMemberGuild(target.Id, ctx.Guild.Id, patch);
{
newValue = true; if (newValue)
} await ctx.Reply($"{Emojis.Success} Member proxy tags will now be **included** in the resulting message when proxying **in the current server**. To clear this setting in this server, type `{ctx.DefaultPrefix}m <member> serverkeepproxy clear`.");
else if (ctx.Match("off", "disabled", "false", "no"))
{
newValue = false;
}
else if (ctx.HasNext())
{
throw new PKSyntaxError("You must pass either \"on\" or \"off\".");
}
else else
await ctx.Reply($"{Emojis.Success} Member proxy tags will now **not** be included in the resulting message when proxying **in the current server**. To clear this setting in this server, type `{ctx.DefaultPrefix}m <member> serverkeepproxy clear`.");
}
public async Task ShowTts(Context ctx, PKMember target)
{ {
if (target.Tts) if (target.Tts)
await ctx.Reply( await ctx.Reply(
@ -741,10 +735,11 @@ public class MemberEdit
else else
await ctx.Reply( await ctx.Reply(
"This member has text-to-speech **disabled**, which means their messages **will not** be sent as text-to-speech messages."); "This member has text-to-speech **disabled**, which means their messages **will not** be sent as text-to-speech messages.");
return;
} }
; public async Task ChangeTts(Context ctx, PKMember target, bool newValue)
{
ctx.CheckSystem().CheckOwnMember(target);
var patch = new MemberPatch { Tts = Partial<bool>.Present(newValue) }; var patch = new MemberPatch { Tts = Partial<bool>.Present(newValue) };
await ctx.Repository.UpdateMember(target.Id, patch); await ctx.Repository.UpdateMember(target.Id, patch);
@ -757,12 +752,7 @@ public class MemberEdit
$"{Emojis.Success} Member messages will no longer be sent as text-to-speech messages."); $"{Emojis.Success} Member messages will no longer be sent as text-to-speech messages.");
} }
public async Task MemberAutoproxy(Context ctx, PKMember target) public async Task ShowAutoproxy(Context ctx, PKMember target)
{
if (ctx.System == null) throw Errors.NoSystemError(ctx.DefaultPrefix);
if (target.System != ctx.System.Id) throw Errors.NotOwnMemberError;
if (!ctx.HasNext())
{ {
if (target.AllowAutoproxy) if (target.AllowAutoproxy)
await ctx.Reply( await ctx.Reply(
@ -770,10 +760,11 @@ public class MemberEdit
else else
await ctx.Reply( await ctx.Reply(
"Latch/front autoproxy are **disabled** for this member. This member will not be automatically proxied when autoproxy is set to latch or front mode."); "Latch/front autoproxy are **disabled** for this member. This member will not be automatically proxied when autoproxy is set to latch or front mode.");
return;
} }
var newValue = ctx.MatchToggle(); public async Task ChangeAutoproxy(Context ctx, PKMember target, bool newValue)
{
ctx.CheckSystem().CheckOwnMember(target);
var patch = new MemberPatch { AllowAutoproxy = Partial<bool>.Present(newValue) }; var patch = new MemberPatch { AllowAutoproxy = Partial<bool>.Present(newValue) };
await ctx.Repository.UpdateMember(target.Id, patch); await ctx.Repository.UpdateMember(target.Id, patch);
@ -784,12 +775,7 @@ public class MemberEdit
await ctx.Reply($"{Emojis.Success} Latch / front autoproxy have been **disabled** for this member."); await ctx.Reply($"{Emojis.Success} Latch / front autoproxy have been **disabled** for this member.");
} }
public async Task Privacy(Context ctx, PKMember target, PrivacyLevel? newValueFromCommand) public async Task ShowPrivacy(Context ctx, PKMember target)
{
ctx.CheckSystem().CheckOwnMember(target);
// Display privacy settings
if (!ctx.HasNext() && newValueFromCommand == null)
{ {
await ctx.Reply(embed: new EmbedBuilder() await ctx.Reply(embed: new EmbedBuilder()
.Title($"Current privacy settings for {target.NameFor(ctx)}") .Title($"Current privacy settings for {target.NameFor(ctx)}")
@ -807,16 +793,12 @@ public class MemberEdit
.Description( .Description(
$"To edit privacy settings, use the command:\n`{ctx.DefaultPrefix}member <member> privacy <subject> <level>`\n\n- `subject` is one of `name`, `description`, `banner`, `avatar`, `birthday`, `pronouns`, `proxies`, `metadata`, `visibility`, or `all`\n- `level` is either `public` or `private`.") $"To edit privacy settings, use the command:\n`{ctx.DefaultPrefix}member <member> privacy <subject> <level>`\n\n- `subject` is one of `name`, `description`, `banner`, `avatar`, `birthday`, `pronouns`, `proxies`, `metadata`, `visibility`, or `all`\n- `level` is either `public` or `private`.")
.Build()); .Build());
return;
} }
// Get guild settings (mostly for warnings and such) public async Task ChangeAllPrivacy(Context ctx, PKMember target, PrivacyLevel level)
MemberGuildSettings guildSettings = null;
if (ctx.Guild != null)
guildSettings = await ctx.Repository.GetMemberGuild(ctx.Guild.Id, target.Id);
async Task SetAll(PrivacyLevel level)
{ {
ctx.CheckSystem().CheckOwnMember(target);
await ctx.Repository.UpdateMember(target.Id, new MemberPatch().WithAllPrivacy(level)); await ctx.Repository.UpdateMember(target.Id, new MemberPatch().WithAllPrivacy(level));
if (level == PrivacyLevel.Private) if (level == PrivacyLevel.Private)
@ -827,8 +809,10 @@ public class MemberEdit
$"{Emojis.Success} All {target.NameFor(ctx)}'s privacy settings have been set to **{level.LevelName()}**. Other accounts will now see everything on the member card."); $"{Emojis.Success} All {target.NameFor(ctx)}'s privacy settings have been set to **{level.LevelName()}**. Other accounts will now see everything on the member card.");
} }
async Task SetLevel(MemberPrivacySubject subject, PrivacyLevel level) public async Task ChangePrivacy(Context ctx, PKMember target, MemberPrivacySubject subject, PrivacyLevel level)
{ {
ctx.CheckSystem().CheckOwnMember(target);
await ctx.Repository.UpdateMember(target.Id, new MemberPatch().WithPrivacy(subject, level)); await ctx.Repository.UpdateMember(target.Id, new MemberPatch().WithPrivacy(subject, level));
var subjectName = subject switch var subjectName = subject switch
@ -895,17 +879,14 @@ public class MemberEdit
replyStr += $"\n{Emojis.Warn} This member does not have a display name set, and name privacy **will not take effect**."; replyStr += $"\n{Emojis.Warn} This member does not have a display name set, and name privacy **will not take effect**.";
// Avatar privacy doesn't apply when proxying if no server avatar is set // Avatar privacy doesn't apply when proxying if no server avatar is set
if (subject == MemberPrivacySubject.Avatar && level == PrivacyLevel.Private && if (subject == MemberPrivacySubject.Avatar && level == PrivacyLevel.Private)
guildSettings?.AvatarUrl == null) {
var guildSettings = ctx.Guild != null ? await ctx.Repository.GetMemberGuild(ctx.Guild.Id, target.Id) : null;
if (guildSettings?.AvatarUrl == null)
replyStr += $"\n{Emojis.Warn} This member does not have a server avatar set, so *proxying* will **still show the member avatar**. If you want to hide your avatar when proxying here, set a server avatar: `{ctx.DefaultPrefix}member {target.Reference(ctx)} serveravatar`"; replyStr += $"\n{Emojis.Warn} This member does not have a server avatar set, so *proxying* will **still show the member avatar**. If you want to hide your avatar when proxying here, set a server avatar: `{ctx.DefaultPrefix}member {target.Reference(ctx)} serveravatar`";
await ctx.Reply(replyStr);
} }
if (ctx.Match("all") || newValueFromCommand != null) await ctx.Reply(replyStr);
await SetAll(newValueFromCommand ?? ctx.PopPrivacyLevel());
else
await SetLevel(ctx.PopMemberPrivacySubject(), ctx.PopPrivacyLevel());
} }
public async Task Delete(Context ctx, PKMember target) public async Task Delete(Context ctx, PKMember target)

View file

@ -2,23 +2,60 @@ use super::*;
pub fn cmds() -> impl Iterator<Item = Command> { pub fn cmds() -> impl Iterator<Item = Command> {
let member = ("member", ["m"]); let member = ("member", ["m"]);
let member_target = tokens!(member, MemberRef);
let name = ("name", ["n"]);
let description = ("description", ["desc"]); let description = ("description", ["desc"]);
let pronouns = ("pronouns", ["pronoun", "prns", "pn"]);
let privacy = ("privacy", ["priv"]); let privacy = ("privacy", ["priv"]);
let new = ("new", ["n"]); let new = ("new", ["n"]);
let banner = ("banner", ["bn"]);
let color = ("color", ["colour"]);
let birthday = ("birthday", ["bday", "bd"]);
let display_name = ("displayname", ["dname", "dn"]);
let server_name = ("servername", ["sname", "sn"]);
let keep_proxy = ("keepproxy", ["kp"]);
let server_keep_proxy = ("serverkeepproxy", ["skp"]);
let autoproxy = ("autoproxy", ["ap"]);
let tts = ("tts", ["texttospeech"]);
let delete = ("delete", ["del", "remove"]);
let member_target = tokens!(member, MemberRef); // Group commands by functionality
let member_desc = tokens!(member_target, description); let member_new_cmd = [
let member_privacy = tokens!(member_target, privacy);
[
command!(member, new, ("name", OpaqueString) => "member_new") command!(member, new, ("name", OpaqueString) => "member_new")
.help("Creates a new system member"), .help("Creates a new system member"),
].into_iter();
let member_info_cmd = [
command!(member_target => "member_show") command!(member_target => "member_show")
.flag("pt") .flag("pt")
.help("Shows information about a member"), .help("Shows information about a member"),
].into_iter();
let member_name_cmd = {
let member_name = tokens!(member_target, name);
[
command!(member_name => "member_name_show").help("Shows a member's name"),
command!(member_name, ("name", OpaqueStringRemainder) => "member_name_update")
.help("Changes a member's name"),
].into_iter()
};
let member_description_cmd = {
let member_desc = tokens!(member_target, description);
[
command!(member_desc => "member_desc_show").help("Shows a member's description"), command!(member_desc => "member_desc_show").help("Shows a member's description"),
command!(member_desc, ("clear", ["c"]) => "member_desc_clear")
.flag(("yes", ["y"]))
.help("Clears a member's description"),
command!(member_desc, ("description", OpaqueStringRemainder) => "member_desc_update") command!(member_desc, ("description", OpaqueStringRemainder) => "member_desc_update")
.help("Changes a member's description"), .help("Changes a member's description"),
].into_iter()
};
let member_privacy_cmd = {
let member_privacy = tokens!(member_target, privacy);
[
command!(member_privacy => "member_privacy_show") command!(member_privacy => "member_privacy_show")
.help("Displays a member's current privacy settings"), .help("Displays a member's current privacy settings"),
command!( command!(
@ -26,7 +63,142 @@ pub fn cmds() -> impl Iterator<Item = Command> {
=> "member_privacy_update" => "member_privacy_update"
) )
.help("Changes a member's privacy settings"), .help("Changes a member's privacy settings"),
].into_iter()
};
let member_pronouns_cmd = {
let member_pronouns = tokens!(member_target, pronouns);
[
command!(member_pronouns => "member_pronouns_show")
.help("Shows a member's pronouns"),
command!(member_pronouns, ("pronouns", OpaqueStringRemainder) => "member_pronouns_update")
.help("Changes a member's pronouns"),
command!(member_pronouns, ("clear", ["c"]) => "member_pronouns_clear")
.flag(("yes", ["y"]))
.help("Clears a member's pronouns"),
].into_iter()
};
let member_banner_cmd = {
let member_banner = tokens!(member_target, banner);
[
command!(member_banner => "member_banner_show")
.help("Shows a member's banner image"),
command!(member_banner, ("banner", Avatar) => "member_banner_update")
.help("Changes a member's banner image"),
command!(member_banner, ("clear", ["c"]) => "member_banner_clear")
.flag(("yes", ["y"]))
.help("Clears a member's banner image"),
].into_iter()
};
let member_color_cmd = {
let member_color = tokens!(member_target, color);
[
command!(member_color => "member_color_show")
.help("Shows a member's color"),
command!(member_color, ("color", OpaqueString) => "member_color_update")
.help("Changes a member's color"),
command!(member_color, ("clear", ["c"]) => "member_color_clear")
.flag(("yes", ["y"]))
.help("Clears a member's color"),
].into_iter()
};
let member_birthday_cmd = {
let member_birthday = tokens!(member_target, birthday);
[
command!(member_birthday => "member_birthday_show")
.help("Shows a member's birthday"),
command!(member_birthday, ("birthday", OpaqueString) => "member_birthday_update")
.help("Changes a member's birthday"),
command!(member_birthday, ("clear", ["c"]) => "member_birthday_clear")
.flag(("yes", ["y"]))
.help("Clears a member's birthday"),
].into_iter()
};
let member_display_name_cmd = {
let member_display_name = tokens!(member_target, display_name);
[
command!(member_display_name => "member_displayname_show")
.help("Shows a member's display name"),
command!(member_display_name, ("name", OpaqueStringRemainder) => "member_displayname_update")
.help("Changes a member's display name"),
command!(member_display_name, ("clear", ["c"]) => "member_displayname_clear")
.flag(("yes", ["y"]))
.help("Clears a member's display name"),
].into_iter()
};
let member_server_name_cmd = {
let member_server_name = tokens!(member_target, server_name);
[
command!(member_server_name => "member_servername_show")
.help("Shows a member's server name"),
command!(member_server_name, ("name", OpaqueStringRemainder) => "member_servername_update")
.help("Changes a member's server name"),
command!(member_server_name, ("clear", ["c"]) => "member_servername_clear")
.flag(("yes", ["y"]))
.help("Clears a member's server name"),
].into_iter()
};
let member_proxy_settings_cmd = {
let member_keep_proxy = tokens!(member_target, keep_proxy);
let member_server_keep_proxy = tokens!(member_target, server_keep_proxy);
[
command!(member_keep_proxy => "member_keepproxy_show")
.help("Shows a member's keep-proxy setting"),
command!(member_keep_proxy, ("value", Toggle) => "member_keepproxy_update")
.help("Changes a member's keep-proxy setting"),
command!(member_server_keep_proxy => "member_server_keepproxy_show")
.help("Shows a member's server-specific keep-proxy setting"),
command!(member_server_keep_proxy, ("value", Toggle) => "member_server_keepproxy_update")
.help("Changes a member's server-specific keep-proxy setting"),
command!(member_server_keep_proxy, ("clear", ["c"]) => "member_server_keepproxy_clear")
.flag(("yes", ["y"]))
.help("Clears a member's server-specific keep-proxy setting"),
].into_iter()
};
let member_message_settings_cmd = {
let member_tts = tokens!(member_target, tts);
let member_autoproxy = tokens!(member_target, autoproxy);
[
command!(member_tts => "member_tts_show")
.help("Shows whether a member's messages are sent as TTS"),
command!(member_tts, ("value", Toggle) => "member_tts_update")
.help("Changes whether a member's messages are sent as TTS"),
command!(member_autoproxy => "member_autoproxy_show")
.help("Shows whether a member can be autoproxied"),
command!(member_autoproxy, ("value", Toggle) => "member_autoproxy_update")
.help("Changes whether a member can be autoproxied"),
].into_iter()
};
let member_delete_cmd = [
command!(member_target, delete => "member_delete")
.help("Deletes a member"),
].into_iter();
let member_easter_eggs = [
command!(member_target, "soulscream" => "member_soulscream").show_in_suggestions(false), command!(member_target, "soulscream" => "member_soulscream").show_in_suggestions(false),
] ].into_iter();
.into_iter()
member_new_cmd
.chain(member_info_cmd)
.chain(member_name_cmd)
.chain(member_description_cmd)
.chain(member_privacy_cmd)
.chain(member_pronouns_cmd)
.chain(member_banner_cmd)
.chain(member_color_cmd)
.chain(member_birthday_cmd)
.chain(member_display_name_cmd)
.chain(member_server_name_cmd)
.chain(member_proxy_settings_cmd)
.chain(member_message_settings_cmd)
.chain(member_delete_cmd)
.chain(member_easter_eggs)
} }