public async Task Name(Context ctx, PKMember 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 if (newName.Length > Limits.MaxMemberNameLength) { throw Errors.StringTooLongError("Member name", newName.Length, Limits.MaxMemberNameLength); } // Warn if there's already a member by this name var existingMember = await ctx.Repository.GetMemberByName(ctx.System.Id, newName); if (existingMember != null && existingMember.Id != target.Id) { var msg = $"{Emojis.Warn} You already have a member in your system with the name \"{existingMember.NameFor(ctx)}\" (`{existingMember.Hid}`). Do you want to rename this member to that name too?"; if (!await ctx.PromptYesNo(msg, "Rename")) { throw new PKError("Member renaming cancelled."); } } // Rename the member var patch = new MemberPatch { Name = Partial <string> .Present(newName) }; await ctx.Repository.UpdateMember(target.Id, patch); await ctx.Reply($"{Emojis.Success} Member renamed."); if (newName.Contains(" ")) { await ctx.Reply( $"{Emojis.Note} Note that this member's name now contains spaces. You will need to surround it with \"double quotes\" when using commands referring to it."); } if (target.DisplayName != null) { await ctx.Reply( $"{Emojis.Note} Note that this member has a display name set ({target.DisplayName}), and will be proxied using that name instead."); } if (ctx.Guild != null) { var memberGuildConfig = await ctx.Repository.GetMemberGuild(ctx.Guild.Id, target.Id); if (memberGuildConfig.DisplayName != null) { await ctx.Reply( $"{Emojis.Note} Note that this member has a server name set ({memberGuildConfig.DisplayName}) in this server ({ctx.Guild.Name}), and will be proxied using that name here."); } } }
public async Task Description(Context ctx, PKMember target) { if (MatchClear(ctx)) { CheckEditMemberPermission(ctx, target); target.Description = null; await _data.SaveMember(target); await ctx.Reply($"{Emojis.Success} Member description cleared."); } else if (!ctx.HasNext()) { CheckReadMemberPermission(ctx, target); if (target.Description == null) { if (ctx.System?.Id == target.System) { await ctx.Reply($"This member does not have a description set. To set one, type `pk;member {target.Hid} description <description>`."); } else { await ctx.Reply("This member does not have a description set."); } } else if (ctx.MatchFlag("r", "raw")) { await ctx.Reply($"```\n{target.Description.SanitizeMentions()}\n```"); } else { await ctx.Reply(embed : new DiscordEmbedBuilder() .WithTitle("Member description") .WithDescription(target.Description) .AddField("\u200B", $"To print the description with formatting, type `pk;member {target.Hid} description -raw`." + (ctx.System?.Id == target.System ? $" To clear it, type `pk;member {target.Hid} description -clear`." : "")) .Build()); } } else { CheckEditMemberPermission(ctx, target); var description = ctx.RemainderOrNull().NormalizeLineEndSpacing(); if (description.IsLongerThan(Limits.MaxDescriptionLength)) { throw Errors.DescriptionTooLongError(description.Length); } target.Description = description; await _data.SaveMember(target); await ctx.Reply($"{Emojis.Success} Member description changed."); } }
public async Task DisplayName(Context ctx, PKMember target) { async Task PrintSuccess(string text) { var successStr = text; if (ctx.Guild != null) { var memberGuildConfig = await _db.Execute(c => c.QueryOrInsertMemberGuildConfig(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 (ctx.MatchClear()) { CheckEditMemberPermission(ctx, target); var patch = new MemberPatch { DisplayName = Partial <string> .Null() }; await _db.Execute(conn => conn.UpdateMember(target.Id, patch)); await PrintSuccess($"{Emojis.Success} Member display name cleared. This member will now be proxied using their member name \"{target.NameFor(ctx)}\"."); } else if (!ctx.HasNext()) { // No perms check, display name isn't covered by member privacy var eb = await CreateMemberNameInfoEmbed(ctx, target); if (ctx.System?.Id == target.System) { eb.WithDescription($"To change display name, type `pk;member {target.Hid} displayname <display name>`.\nTo clear it, type `pk;member {target.Hid} displayname -clear`."); } await ctx.Reply(embed : eb.Build()); } else { CheckEditMemberPermission(ctx, target); var newDisplayName = ctx.RemainderOrNull(); var patch = new MemberPatch { DisplayName = Partial <string> .Present(newDisplayName) }; await _db.Execute(conn => conn.UpdateMember(target.Id, patch)); await PrintSuccess($"{Emojis.Success} Member display name changed. This member will now be proxied using the name \"{newDisplayName}\"."); } }
public async Task Pronouns(Context ctx, PKMember target) { if (await ctx.MatchClear("this member's pronouns")) { ctx.CheckOwnMember(target); var patch = new MemberPatch { Pronouns = Partial <string> .Null() }; await _db.Execute(conn => _repo.UpdateMember(conn, target.Id, patch)); await ctx.Reply($"{Emojis.Success} Member pronouns cleared."); } else if (!ctx.HasNext()) { if (!target.PronounPrivacy.CanAccess(ctx.LookupContextFor(target.System))) { throw Errors.LookupNotAllowed; } if (target.Pronouns == null) { if (ctx.System?.Id == target.System) { await ctx.Reply($"This member does not have pronouns set. To set some, type `pk;member {target.Reference()} pronouns <pronouns>`."); } else { await ctx.Reply("This member does not have pronouns set."); } } else { await ctx.Reply($"**{target.NameFor(ctx)}**'s pronouns are **{target.Pronouns}**." + (ctx.System?.Id == target.System ? $" To clear them, type `pk;member {target.Reference()} pronouns -clear`." : "")); } } else { ctx.CheckOwnMember(target); var pronouns = ctx.RemainderOrNull().NormalizeLineEndSpacing(); if (pronouns.IsLongerThan(Limits.MaxPronounsLength)) { throw Errors.MemberPronounsTooLongError(pronouns.Length); } var patch = new MemberPatch { Pronouns = Partial <string> .Present(pronouns) }; await _db.Execute(conn => _repo.UpdateMember(conn, target.Id, patch)); await ctx.Reply($"{Emojis.Success} Member pronouns changed."); } }
public Embed CreateLoggedMessageEmbed(PKSystem system, PKMember member, ulong messageId, ulong originalMsgId, IUser sender, string content, IGuildChannel channel) { // TODO: pronouns in ?-reacted response using this card var timestamp = SnowflakeUtils.FromSnowflake(messageId); return(new EmbedBuilder() .WithAuthor($"#{channel.Name}: {member.Name}", member.AvatarUrl) .WithDescription(content) .WithFooter($"System ID: {system.Hid} | Member ID: {member.Hid} | Sender: {sender.Username}#{sender.Discriminator} ({sender.Id}) | Message ID: {messageId} | Original Message ID: {originalMsgId}") .WithTimestamp(timestamp) .Build()); }
private async Task AutoproxyMember(Context ctx, PKMember member) { ctx.CheckOwnMember(member); var settings = await _data.GetSystemGuildSettings(ctx.System, ctx.Guild.Id); settings.AutoproxyMode = AutoproxyMode.Member; settings.AutoproxyMember = member.Id; await _data.SetSystemGuildSettings(ctx.System, ctx.Guild.Id, settings); await ctx.Reply($"{Emojis.Success} Autoproxy set to **{member.Name}** in this server."); }
private async Task HandleMemberCommandTargeted(Context ctx, PKMember target) { // Commands that have a member target (eg. pk;member <member> delete) if (ctx.Match("rename", "name", "changename", "setname")) { await ctx.Execute <MemberCommands>(MemberRename, m => m.RenameMember(ctx, target)); } else if (ctx.Match("description", "info", "bio", "text", "desc")) { await ctx.Execute <MemberCommands>(MemberDesc, m => m.MemberDescription(ctx, target)); } else if (ctx.Match("pronouns", "pronoun")) { await ctx.Execute <MemberCommands>(MemberPronouns, m => m.MemberPronouns(ctx, target)); } else if (ctx.Match("color", "colour")) { await ctx.Execute <MemberCommands>(MemberColor, m => m.MemberColor(ctx, target)); } else if (ctx.Match("birthday", "bday", "birthdate", "cakeday", "bdate")) { await ctx.Execute <MemberCommands>(MemberBirthday, m => m.MemberBirthday(ctx, target)); } else if (ctx.Match("proxy", "tags", "proxytags", "brackets")) { await ctx.Execute <MemberCommands>(MemberProxy, m => m.MemberProxy(ctx, target)); } else if (ctx.Match("delete", "remove", "destroy", "erase", "yeet")) { await ctx.Execute <MemberCommands>(MemberDelete, m => m.MemberDelete(ctx, target)); } else if (ctx.Match("avatar", "profile", "picture", "icon", "image", "pfp", "pic")) { await ctx.Execute <MemberCommands>(MemberAvatar, m => m.MemberAvatar(ctx, target)); } else if (ctx.Match("displayname", "dn", "dname", "nick", "nickname")) { await ctx.Execute <MemberCommands>(MemberDisplayName, m => m.MemberDisplayName(ctx, target)); } else if (ctx.Match("keepproxy", "keeptags", "showtags")) { await ctx.Execute <MemberCommands>(MemberKeepProxy, m => m.MemberKeepProxy(ctx, target)); } else if (!ctx.HasNext()) // Bare command { await ctx.Execute <MemberCommands>(MemberInfo, m => m.ViewMember(ctx, target)); } else { await PrintCommandNotFoundError(ctx, MemberInfo, MemberRename, MemberDisplayName, MemberDesc, MemberPronouns, MemberColor, MemberBirthday, MemberProxy, MemberDelete, MemberAvatar, SystemList); } }
public async Task KeepProxy(Context ctx, PKMember target) { if (ctx.System == null) { throw Errors.NoSystemError; } if (target.System != ctx.System.Id) { throw Errors.NotOwnMemberError; } 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 { if (target.KeepProxy) { await ctx.Reply("This member has keepproxy **enabled**, which means proxy tags will be **included** in the resulting message when proxying."); } else { await ctx.Reply("This member has keepproxy **disabled**, which means proxy tags will **not** be included in the resulting message when proxying."); } return; }; var patch = new MemberPatch { KeepProxy = Partial <bool> .Present(newValue) }; await _db.Execute(conn => _repo.UpdateMember(conn, target.Id, patch)); if (newValue) { await ctx.Reply($"{Emojis.Success} Member proxy tags will now be included in the resulting message when proxying."); } else { await ctx.Reply($"{Emojis.Success} Member proxy tags will now not be included in the resulting message when proxying."); } }
public async Task MemberAutoproxy(Context ctx, PKMember target) { if (ctx.System == null) { throw Errors.NoSystemError; } if (target.System != ctx.System.Id) { throw Errors.NotOwnMemberError; } bool newValue; if (ctx.Match("on", "enabled", "true", "yes") || ctx.MatchFlag("on", "enabled", "true", "yes")) { newValue = true; } else if (ctx.Match("off", "disabled", "false", "no") || ctx.MatchFlag("off", "disabled", "false", "no")) { newValue = false; } else if (ctx.HasNext()) { throw new PKSyntaxError("You must pass either \"on\" or \"off\"."); } else { if (target.AllowAutoproxy) { await ctx.Reply("Latch/front autoproxy are **enabled** for this member. This member will be automatically proxied when autoproxy is set to latch or front mode."); } else { 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."); } return; }; var patch = new MemberPatch { AllowAutoproxy = Partial <bool> .Present(newValue) }; await _db.Execute(conn => _repo.UpdateMember(conn, target.Id, patch)); if (newValue) { await ctx.Reply($"{Emojis.Success} Latch / front autoproxy have been **enabled** for this member."); } else { await ctx.Reply($"{Emojis.Success} Latch / front autoproxy have been **disabled** for this member."); } }
public DiscordEmbed CreateLoggedMessageEmbed(PKSystem system, PKMember member, ulong messageId, ulong originalMsgId, DiscordUser sender, string content, DiscordChannel channel) { // TODO: pronouns in ?-reacted response using this card var timestamp = DiscordUtils.SnowflakeToInstant(messageId); return(new DiscordEmbedBuilder() .WithAuthor($"#{channel.Name}: {member.Name}", iconUrl: DiscordUtils.WorkaroundForUrlBug(member.AvatarUrl)) .WithThumbnailUrl(member.AvatarUrl) .WithDescription(content?.NormalizeLineEndSpacing()) .WithFooter($"System ID: {system.Hid} | Member ID: {member.Hid} | Sender: {sender.Username}#{sender.Discriminator} ({sender.Id}) | Message ID: {messageId} | Original Message ID: {originalMsgId}") .WithTimestamp(timestamp.ToDateTimeOffset()) .Build()); }
public async Task <ActionResult <PKMember> > PostMember([FromBody] PKMember newMember) { var system = _auth.CurrentSystem; if (newMember.Name == null) { return(BadRequest("Member name cannot be null.")); } // Explicit bounds checks if (newMember.Name != null && newMember.Name.Length > Limits.MaxMemberNameLength) { return(BadRequest($"Member name too long ({newMember.Name.Length} > {Limits.MaxMemberNameLength}.")); } if (newMember.Pronouns != null && newMember.Pronouns.Length > Limits.MaxPronounsLength) { return(BadRequest($"Member pronouns too long ({newMember.Pronouns.Length} > {Limits.MaxPronounsLength}.")); } if (newMember.Description != null && newMember.Description.Length > Limits.MaxDescriptionLength) { return(BadRequest($"Member descriptions too long ({newMember.Description.Length} > {Limits.MaxDescriptionLength}.")); } // Sanity bounds checks if (newMember.AvatarUrl != null && newMember.AvatarUrl.Length > 1000) { return(BadRequest()); } if (newMember.Prefix != null && newMember.Prefix.Length > 1000) { return(BadRequest()); } if (newMember.Suffix != null && newMember.Suffix.Length > 1000) { return(BadRequest()); } var member = await _members.Create(system, newMember.Name); member.Name = newMember.Name; member.Color = newMember.Color; member.AvatarUrl = newMember.AvatarUrl; member.Birthday = newMember.Birthday; member.Pronouns = newMember.Pronouns; member.Description = newMember.Description; member.Prefix = newMember.Prefix; member.Suffix = newMember.Suffix; await _members.Save(member); return(Ok(member)); }
public static JObject ToJson(this PKMember member, LookupContext ctx) { var includePrivacy = ctx == LookupContext.ByOwner; var o = new JObject(); o.Add("id", member.Hid); o.Add("name", member.NameFor(ctx)); // o.Add("color", member.ColorPrivacy.CanAccess(ctx) ? member.Color : null); o.Add("color", member.Color); o.Add("display_name", member.NamePrivacy.CanAccess(ctx) ? member.DisplayName : null); o.Add("birthday", member.BirthdayFor(ctx)?.FormatExport()); o.Add("pronouns", member.PronounsFor(ctx)); o.Add("avatar_url", member.AvatarFor(ctx)); o.Add("description", member.DescriptionFor(ctx)); var tagArray = new JArray(); foreach (var tag in member.ProxyTags) { tagArray.Add(new JObject { { "prefix", tag.Prefix }, { "suffix", tag.Suffix } }); } o.Add("proxy_tags", tagArray); o.Add("keep_proxy", member.KeepProxy); o.Add("privacy", includePrivacy ? (member.MemberVisibility.LevelName()) : null); o.Add("visibility", includePrivacy ? (member.MemberVisibility.LevelName()) : null); o.Add("name_privacy", includePrivacy ? (member.NamePrivacy.LevelName()) : null); o.Add("description_privacy", includePrivacy ? (member.DescriptionPrivacy.LevelName()) : null); o.Add("birthday_privacy", includePrivacy ? (member.BirthdayPrivacy.LevelName()) : null); o.Add("pronoun_privacy", includePrivacy ? (member.PronounPrivacy.LevelName()) : null); o.Add("avatar_privacy", includePrivacy ? (member.AvatarPrivacy.LevelName()) : null); // o.Add("color_privacy", ctx == LookupContext.ByOwner ? (member.ColorPrivacy.LevelName()) : null); o.Add("metadata_privacy", includePrivacy ? (member.MetadataPrivacy.LevelName()) : null); o.Add("created", member.CreatedFor(ctx)?.FormatExport()); if (member.ProxyTags.Count > 0) { // Legacy compatibility only, TODO: remove at some point o.Add("prefix", member.ProxyTags?.FirstOrDefault().Prefix); o.Add("suffix", member.ProxyTags?.FirstOrDefault().Suffix); } return(o); }
private async Task AvatarCommandTree(AvatarLocation location, Context ctx, PKMember target, MemberGuildSettings?guildData) { if (ctx.Match("clear", "remove", "reset") || ctx.MatchFlag("c", "clear")) { await AvatarClear(location, ctx, target, guildData); } else if (ctx.RemainderOrNull() == null && ctx.Message.Attachments.Count == 0) { await AvatarShow(location, ctx, target, guildData); } else if (await ctx.MatchUser() is {} user) { await AvatarFromUser(location, ctx, target, user); }
public async Task Pronouns(Context ctx, PKMember target) { if (MatchClear(ctx)) { CheckEditMemberPermission(ctx, target); target.Pronouns = null; await _data.SaveMember(target); await ctx.Reply($"{Emojis.Success} Member pronouns cleared."); } else if (!ctx.HasNext()) { if (!target.PronounPrivacy.CanAccess(ctx.LookupContextFor(target.System))) { throw Errors.LookupNotAllowed; } if (target.Pronouns == null) { if (ctx.System?.Id == target.System) { await ctx.Reply($"This member does not have pronouns set. To set some, type `pk;member {target.Hid} pronouns <pronouns>`."); } else { await ctx.Reply("This member does not have pronouns set."); } } else { await ctx.Reply($"**{target.NameFor(ctx)}**'s pronouns are **{target.Pronouns}**." + (ctx.System?.Id == target.System ? $" To clear them, type `pk;member {target.Hid} pronouns -clear`." : "")); } } else { CheckEditMemberPermission(ctx, target); var pronouns = ctx.RemainderOrNull().NormalizeLineEndSpacing(); if (pronouns.IsLongerThan(Limits.MaxPronounsLength)) { throw Errors.MemberPronounsTooLongError(pronouns.Length); } target.Pronouns = pronouns; await _data.SaveMember(target); await ctx.Reply($"{Emojis.Success} Member pronouns changed."); } }
private async Task <DataFileMember> ExportMember(PKMember member) => new DataFileMember { Id = member.Hid, Name = member.Name, Description = member.Description, Birthday = member.Birthday != null?Formats.DateExportFormat.Format(member.Birthday.Value) : null, Pronouns = member.Pronouns, Color = member.Color, AvatarUrl = member.AvatarUrl, Prefix = member.Prefix, Suffix = member.Suffix, Created = Formats.TimestampExportFormat.Format(member.Created), MessageCount = await _members.MessageCount(member) };
public async Task RenameMember(Context ctx, PKMember target) { // TODO: this method is pretty much a 1:1 copy/paste of the above creation method, find a way to clean? if (ctx.System == null) { throw Errors.NoSystemError; } if (target.System != ctx.System.Id) { throw Errors.NotOwnMemberError; } var newName = ctx.RemainderOrNull(); // Hard name length cap if (newName.Length > Limits.MaxMemberNameLength) { throw Errors.MemberNameTooLongError(newName.Length); } // Warn if there's already a member by this name var existingMember = await _data.GetMemberByName(ctx.System, newName); if (existingMember != null) { var msg = await ctx.Reply($"{Emojis.Warn} You already have a member in your system with the name \"{existingMember.Name.SanitizeMentions()}\" (`{existingMember.Hid}`). Do you want to rename this member to that name too?"); if (!await ctx.PromptYesNo(msg)) { throw new PKError("Member renaming cancelled."); } } // Rename the member target.Name = newName; await _data.SaveMember(target); await ctx.Reply($"{Emojis.Success} Member renamed."); if (newName.Contains(" ")) { await ctx.Reply($"{Emojis.Note} Note that this member's name now contains spaces. You will need to surround it with \"double quotes\" when using commands referring to it."); } if (target.DisplayName != null) { await ctx.Reply($"{Emojis.Note} Note that this member has a display name set ({target.DisplayName.SanitizeMentions()}), and will be proxied using that name instead."); } await _proxyCache.InvalidateResultsForSystem(ctx.System); }
private async Task <EmbedBuilder> CreateMemberNameInfoEmbed(Context ctx, PKMember target) { var lcx = ctx.LookupContextFor(target); MemberGuildSettings memberGuildConfig = null; if (ctx.Guild != null) { memberGuildConfig = await _db.Execute(c => _repo.GetMemberGuild(c, ctx.Guild.Id, target.Id)); } var eb = new EmbedBuilder() .Title($"Member names") .Footer(new($"Member ID: {target.Hid} | Active name in bold. Server name overrides display name, which overrides base name.")); if (target.DisplayName == null && memberGuildConfig?.DisplayName == null) { eb.Field(new("Name", $"**{target.NameFor(ctx)}**")); } else { eb.Field(new("Name", target.NameFor(ctx))); } if (target.NamePrivacy.CanAccess(lcx)) { if (target.DisplayName != null && memberGuildConfig?.DisplayName == null) { eb.Field(new("Display Name", $"**{target.DisplayName}**")); } else { eb.Field(new("Display Name", target.DisplayName ?? "*(none)*")); } } if (ctx.Guild != null) { if (memberGuildConfig?.DisplayName != null) { eb.Field(new($"Server Name (in {ctx.Guild.Name})", $"**{memberGuildConfig.DisplayName}**")); } else { eb.Field(new($"Server Name (in {ctx.Guild.Name})", memberGuildConfig?.DisplayName ?? "*(none)*")); } } return(eb); }
public Embed CreateEditedMessageEmbed(PKSystem system, PKMember member, ulong messageId, ulong originalMsgId, User sender, string content, string oldContent, Channel channel) { var timestamp = DiscordUtils.SnowflakeToInstant(messageId); var name = member.NameFor(LookupContext.ByNonOwner); return(new EmbedBuilder() .Author(new($"[Edited] #{channel.Name}: {name}", IconUrl: DiscordUtils.WorkaroundForUrlBug(member.AvatarFor(LookupContext.ByNonOwner)))) .Thumbnail(new(member.AvatarFor(LookupContext.ByNonOwner))) .Field(new("Old message", oldContent?.NormalizeLineEndSpacing().Truncate(1000))) .Description(content?.NormalizeLineEndSpacing()) .Footer(new($"System ID: {system.Hid} | Member ID: {member.Hid} | Sender: {sender.Username}#{sender.Discriminator} ({sender.Id}) | Message ID: {messageId} | Original Message ID: {originalMsgId}")) .Timestamp(timestamp.ToDateTimeOffset().ToString("O")) .Build()); }
public async Task Birthday(Context ctx, PKMember target) { if (await ctx.MatchClear("this member's birthday")) { ctx.CheckOwnMember(target); var patch = new MemberPatch { Birthday = Partial <LocalDate?> .Null() }; await _db.Execute(conn => _repo.UpdateMember(conn, target.Id, patch)); await ctx.Reply($"{Emojis.Success} Member birthdate cleared."); } else if (!ctx.HasNext()) { if (!target.BirthdayPrivacy.CanAccess(ctx.LookupContextFor(target.System))) { throw Errors.LookupNotAllowed; } if (target.Birthday == null) { await ctx.Reply("This member does not have a birthdate set." + (ctx.System?.Id == target.System ? $" To set one, type `pk;member {target.Reference()} birthdate <birthdate>`." : "")); } else { await ctx.Reply($"This member's birthdate is **{target.BirthdayString}**." + (ctx.System?.Id == target.System ? $" To clear it, type `pk;member {target.Reference()} birthdate -clear`." : "")); } } else { ctx.CheckOwnMember(target); var birthdayStr = ctx.RemainderOrNull(); var birthday = DateUtils.ParseDate(birthdayStr, true); if (birthday == null) { throw Errors.BirthdayParseError(birthdayStr); } var patch = new MemberPatch { Birthday = Partial <LocalDate?> .Present(birthday) }; await _db.Execute(conn => _repo.UpdateMember(conn, target.Id, patch)); await ctx.Reply($"{Emojis.Success} Member birthdate changed."); } }
public async Task LogMessage(PKSystem system, PKMember member, ulong messageId, ulong originalMsgId, IGuildChannel originalChannel, IUser sender, string content) { var logChannel = await GetLogChannel(originalChannel.Guild); if (logChannel == null) { return; } var embed = _embed.CreateLoggedMessageEmbed(system, member, messageId, originalMsgId, sender, content, originalChannel); var url = $"https://discordapp.com/channels/{originalChannel.GuildId}/{originalChannel.Id}/{messageId}"; await logChannel.SendMessageAsync(text : url, embed : embed); }
public async Task DisplayName(Context ctx, PKMember target) { async Task PrintSuccess(string text) { var successStr = text; if (ctx.Guild != null) { var memberGuildConfig = await _data.GetMemberGuildSettings(target, ctx.Guild.Id); if (memberGuildConfig.DisplayName != null) { successStr += $" However, this member has a server name set in this server ({ctx.Guild.Name.SanitizeMentions()}), and will be proxied using that name, \"{memberGuildConfig.DisplayName.SanitizeMentions()}\", here."; } } await ctx.Reply(successStr); } if (MatchClear(ctx)) { CheckEditMemberPermission(ctx, target); target.DisplayName = null; await _data.SaveMember(target); await PrintSuccess($"{Emojis.Success} Member display name cleared. This member will now be proxied using their member name \"{target.Name.SanitizeMentions()}\"."); } else if (!ctx.HasNext()) { // No perms check, display name isn't covered by member privacy var eb = await CreateMemberNameInfoEmbed(ctx, target); if (ctx.System?.Id == target.System) { eb.WithDescription($"To change display name, type `pk;member {target.Hid} displayname <display name>`.\nTo clear it, type `pk;member {target.Hid} displayname -clear`."); } await ctx.Reply(embed : eb.Build()); } else { CheckEditMemberPermission(ctx, target); var newDisplayName = ctx.RemainderOrNull(); target.DisplayName = newDisplayName; await _data.SaveMember(target); await PrintSuccess($"{Emojis.Success} Member display name changed. This member will now be proxied using the name \"{newDisplayName.SanitizeMentions()}\"."); } }
public async Task Delete(Context ctx, PKMember target) { ctx.CheckSystem().CheckOwnMember(target); await ctx.Reply($"{Emojis.Warn} Are you sure you want to delete \"{target.NameFor(ctx)}\"? If so, reply to this message with the member's ID (`{target.Hid}`). __***This cannot be undone!***__"); if (!await ctx.ConfirmWithReply(target.Hid)) { throw Errors.MemberDeleteCancelled; } await _db.Execute(conn => _repo.DeleteMember(conn, target.Id)); await ctx.Reply($"{Emojis.Success} Member deleted."); }
public async Task ServerName(Context ctx, PKMember target) { ctx.CheckGuildContext(); if (await ctx.MatchClear("this member's server name")) { ctx.CheckOwnMember(target); var patch = new MemberGuildPatch { DisplayName = null }; await _db.Execute(conn => _repo.UpsertMemberGuild(conn, target.Id, ctx.Guild.Id, patch)); if (target.DisplayName != null) { await ctx.Reply($"{Emojis.Success} Member server name cleared. This member will now be proxied using their global display name \"{target.DisplayName}\" in this server ({ctx.Guild.Name})."); } else { 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})."); } } else if (!ctx.HasNext()) { // No perms check, server name isn't covered by member privacy var eb = await CreateMemberNameInfoEmbed(ctx, target); if (ctx.System?.Id == target.System) { eb.Description($"To change server name, type `pk;member {target.Reference()} servername <server name>`.\nTo clear it, type `pk;member {target.Reference()} servername -clear`."); } await ctx.Reply(embed : eb.Build()); } else { ctx.CheckOwnMember(target); var newServerName = ctx.RemainderOrNull(); var patch = new MemberGuildPatch { DisplayName = newServerName }; await _db.Execute(conn => _repo.UpsertMemberGuild(conn, target.Id, ctx.Guild.Id, patch)); await ctx.Reply($"{Emojis.Success} Member server name changed. This member will now be proxied using the name \"{newServerName}\" in this server ({ctx.Guild.Name})."); } }
public async Task ServerName(Context ctx, PKMember target) { ctx.CheckGuildContext(); if (MatchClear(ctx)) { CheckEditMemberPermission(ctx, target); await _db.Execute(c => c.ExecuteAsync("update member_guild set display_name = null where member = @member and guild = @guild", new { member = target.Id, guild = ctx.Guild.Id })); if (target.DisplayName != null) { await ctx.Reply($"{Emojis.Success} Member server name cleared. This member will now be proxied using their global display name \"{target.DisplayName.SanitizeMentions()}\" in this server ({ctx.Guild.Name.SanitizeMentions()})."); } else { await ctx.Reply($"{Emojis.Success} Member server name cleared. This member will now be proxied using their member name \"{target.Name.SanitizeMentions()}\" in this server ({ctx.Guild.Name.SanitizeMentions()})."); } } else if (!ctx.HasNext()) { // No perms check, server name isn't covered by member privacy var eb = await CreateMemberNameInfoEmbed(ctx, target); if (ctx.System?.Id == target.System) { eb.WithDescription($"To change server name, type `pk;member {target.Hid} servername <server name>`.\nTo clear it, type `pk;member {target.Hid} servername -clear`."); } await ctx.Reply(embed : eb.Build()); } else { CheckEditMemberPermission(ctx, target); var newServerName = ctx.RemainderOrNull(); await _db.Execute(c => c.ExecuteAsync("update member_guild set display_name = @newServerName where member = @member and guild = @guild", new { member = target.Id, guild = ctx.Guild.Id, newServerName })); await ctx.Reply($"{Emojis.Success} Member server name changed. This member will now be proxied using the name \"{newServerName.SanitizeMentions()}\" in this server ({ctx.Guild.Name.SanitizeMentions()})."); } }
private Task UpdateAvatar(AvatarLocation location, Context ctx, PKMember target, string?url) { switch (location) { case AvatarLocation.Server: return(ctx.Repository.UpdateMemberGuild(target.Id, ctx.Guild.Id, new MemberGuildPatch { AvatarUrl = url })); case AvatarLocation.Member: return(ctx.Repository.UpdateMember(target.Id, new MemberPatch { AvatarUrl = url })); default: throw new ArgumentOutOfRangeException($"Unknown avatar location {location}"); } }
private async Task AvatarFromArg(AvatarLocation location, Context ctx, PKMember target, string url) { ctx.CheckSystem().CheckOwnMember(target); if (url.Length > Limits.MaxUriLength) { throw Errors.InvalidUrl(url); } await AvatarUtils.VerifyAvatarOrThrow(url); await UpdateAvatar(location, ctx, target, url); var embed = new DiscordEmbedBuilder().WithImageUrl(url).Build(); if (location == AvatarLocation.Server) { await ctx.Reply($"{Emojis.Success} Member server avatar changed. This avatar will now be used when proxying in this server (**{ctx.Guild.Name}**).", embed : embed); } }
public async Task Birthday(Context ctx, PKMember target) { if (MatchClear(ctx)) { CheckEditMemberPermission(ctx, target); target.Birthday = null; await _data.SaveMember(target); await ctx.Reply($"{Emojis.Success} Member birthdate cleared."); } else if (!ctx.HasNext()) { if (!target.BirthdayPrivacy.CanAccess(ctx.LookupContextFor(target.System))) { throw Errors.LookupNotAllowed; } if (target.Birthday == null) { await ctx.Reply("This member does not have a birthdate set." + (ctx.System?.Id == target.System ? $" To set one, type `pk;member {target.Hid} birthdate <birthdate>`." : "")); } else { await ctx.Reply($"This member's birthdate is **{target.BirthdayString}**." + (ctx.System?.Id == target.System ? $" To clear it, type `pk;member {target.Hid} birthdate -clear`." : "")); } } else { CheckEditMemberPermission(ctx, target); var birthdayStr = ctx.RemainderOrNull(); var birthday = DateUtils.ParseDate(birthdayStr, true); if (birthday == null) { throw Errors.BirthdayParseError(birthdayStr); } target.Birthday = birthday; await _data.SaveMember(target); await ctx.Reply($"{Emojis.Success} Member birthdate changed."); } }
private async Task <EmbedBuilder> CreateMemberNameInfoEmbed(Context ctx, PKMember target) { MemberGuildSettings memberGuildConfig = null; if (ctx.Guild != null) { memberGuildConfig = await _data.GetMemberGuildSettings(target, ctx.Guild.Id); } var eb = new EmbedBuilder().WithTitle($"Member names") .WithFooter($"Member ID: {target.Hid} | Active name in bold. Server name overrides display name, which overrides base name."); if (target.DisplayName == null && memberGuildConfig?.DisplayName == null) { eb.AddField($"Name", $"**{target.Name}**"); } else { eb.AddField("Name", target.Name); } if (target.DisplayName != null && memberGuildConfig?.DisplayName == null) { eb.AddField($"Display Name", $"**{target.DisplayName}**"); } else { eb.AddField("Display Name", target.DisplayName ?? "*(none)*"); } if (ctx.Guild != null) { if (memberGuildConfig?.DisplayName != null) { eb.AddField($"Server Name (in {ctx.Guild.Name.SanitizeMentions()})", $"**{memberGuildConfig.DisplayName}**"); } else { eb.AddField($"Server Name (in {ctx.Guild.Name.SanitizeMentions()})", memberGuildConfig?.DisplayName ?? "*(none)*"); } } return(eb); }
private async Task AvatarShow(AvatarLocation location, Context ctx, PKMember target, MemberGuildSettings?guildData) { // 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 var currentValue = location == AvatarLocation.Member ? target.AvatarUrl : guildData?.AvatarUrl; var canAccess = location != AvatarLocation.Member || target.AvatarPrivacy.CanAccess(ctx.DirectLookupContextFor(target.System)); if (string.IsNullOrEmpty(currentValue) || !canAccess) { if (location == AvatarLocation.Member) { if (target.System == ctx.System?.Id) { throw new PKSyntaxError( "This member does not have an avatar set. Set one by attaching an image to this command, or by passing an image URL or @mention."); } throw new PKError("This member does not have an avatar set."); } if (location == AvatarLocation.Server) { throw new PKError( $"This member does not have a server avatar set. Type `pk;member {target.Reference(ctx)} avatar` to see their global avatar."); } } var field = location == AvatarLocation.Server ? $"server avatar (for {ctx.Guild.Name})" : "avatar"; var cmd = location == AvatarLocation.Server ? "serveravatar" : "avatar"; var eb = new EmbedBuilder() .Title($"{target.NameFor(ctx)}'s {field}") .Image(new Embed.EmbedImage(currentValue?.TryGetCleanCdnUrl())); if (target.System == ctx.System?.Id) { eb.Description($"To clear, use `pk;member {target.Reference(ctx)} {cmd} clear`."); } await ctx.Reply(embed : eb.Build()); }
private Task UpdateAvatar(AvatarLocation location, Context ctx, PKMember target, string?url) { switch (location) { case AvatarLocation.Server: var serverPatch = new MemberGuildPatch { AvatarUrl = url }; return(_db.Execute(c => c.UpsertMemberGuild(target.Id, ctx.Guild.Id, serverPatch))); case AvatarLocation.Member: var memberPatch = new MemberPatch { AvatarUrl = url }; return(_db.Execute(c => c.UpdateMember(target.Id, memberPatch))); default: throw new ArgumentOutOfRangeException($"Unknown avatar location {location}"); } }