コード例 #1
0
ファイル: MemberEdit.cs プロジェクト: guccigang17/PluralKit
        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);
        }
コード例 #2
0
        private async Task AvatarShow(AvatarLocation location, Context ctx, PKMember target, MemberGuildSettings?guildData)
        {
            var currentValue = location == AvatarLocation.Member ? target.AvatarUrl : guildData?.AvatarUrl;
            var canAccess    = location != AvatarLocation.Member || target.AvatarPrivacy.CanAccess(ctx.LookupContextFor(target));

            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.Hid} 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 DiscordEmbedBuilder()
                     .WithTitle($"{target.NameFor(ctx)}'s {field}")
                     .WithImageUrl(currentValue);

            if (target.System == ctx.System?.Id)
            {
                eb.WithDescription($"To clear, use `pk;member {target.Hid} {cmd} clear`.");
            }
            await ctx.Reply(embed : eb.Build());
        }
コード例 #3
0
        public async Task Soulscream(Context ctx, PKMember target)
        {
            // this is for a meme, please don't take this code seriously. :)

            var name    = target.NameFor(ctx.LookupContextFor(target));
            var encoded = HttpUtility.UrlEncode(name);

            var resp = await _client.GetAsync($"https://onomancer.sibr.dev/api/generateStats2?name={encoded}");

            if (resp.StatusCode != HttpStatusCode.OK)
            {
                // lol
                return;
            }

            var data   = JObject.Parse(await resp.Content.ReadAsStringAsync());
            var scream = data["soulscream"] !.Value <string>();

            var eb = new DiscordEmbedBuilder()
                     .WithColor(DiscordColor.Red)
                     .WithTitle(name)
                     .WithUrl($"https://onomancer.sibr.dev/reflect?name={encoded}")
                     .WithDescription($"*{scream}*");
            await ctx.Reply(embed : eb.Build());
        }
コード例 #4
0
    public async Task BannerImage(Context ctx, PKMember target)
    {
        ctx.CheckOwnMember(target);

        async Task ClearBannerImage()
        {
            await ctx.Repository.UpdateMember(target.Id, new MemberPatch { BannerImage = null });

            await ctx.Reply($"{Emojis.Success} Member banner image cleared.");
        }

        async Task SetBannerImage(ParsedImage img)
        {
            await AvatarUtils.VerifyAvatarOrThrow(_client, img.Url, true);

            await ctx.Repository.UpdateMember(target.Id, new MemberPatch { BannerImage = img.Url });

            var msg = img.Source switch
            {
                AvatarSource.Url => $"{Emojis.Success} Member banner image changed to the image at the given URL.",
                AvatarSource.Attachment =>
                $"{Emojis.Success} Member banner image changed to attached image.\n{Emojis.Warn} If you delete the message containing the attachment, the banner image will stop working.",
                AvatarSource.User => throw new PKError("Cannot set a banner image to an user's avatar."),
                      _ => throw new ArgumentOutOfRangeException()
            };

            // The attachment's already right there, no need to preview it.
            var hasEmbed = img.Source != AvatarSource.Attachment;

            await(hasEmbed
                ? ctx.Reply(msg, new EmbedBuilder().Image(new Embed.EmbedImage(img.Url)).Build())
                : ctx.Reply(msg));
        }

        async Task ShowBannerImage()
        {
            if ((target.BannerImage?.Trim() ?? "").Length > 0)
            {
                var eb = new EmbedBuilder()
                         .Title($"{target.NameFor(ctx)}'s banner image")
                         .Image(new Embed.EmbedImage(target.BannerImage))
                         .Description($"To clear, use `pk;member {target.Hid} banner clear`.");
                await ctx.Reply(embed : eb.Build());
            }
            else
            {
                throw new PKSyntaxError(
                          "This member does not have a banner image set. Set one by attaching an image to this command, or by passing an image URL or @mention.");
            }
        }

        if (await ctx.MatchClear("this member's banner image"))
        {
            await ClearBannerImage();
        }
        else if (await ctx.MatchImage() is { } img)
        {
            await SetBannerImage(img);
        }
コード例 #5
0
    public static JObject ToJson(this PKMember member, LookupContext ctx, bool needsLegacyProxyTags = false,
                                 string systemStr = null)
    {
        var includePrivacy = ctx == LookupContext.ByOwner;

        var o = new JObject();

        o.Add("id", member.Hid);

        o.Add("uuid", member.Uuid.ToString());
        if (systemStr != null)
        {
            o.Add("system", systemStr);
        }

        o.Add("name", member.NameFor(ctx));

        o.Add("display_name", member.NamePrivacy.CanAccess(ctx) ? member.DisplayName : null);
        // o.Add("color", member.ColorPrivacy.CanAccess(ctx) ? member.Color : null);
        o.Add("color", member.Color);
        o.Add("birthday", member.BirthdayFor(ctx)?.FormatExport());
        o.Add("pronouns", member.PronounsFor(ctx));
        o.Add("avatar_url", member.AvatarFor(ctx).TryGetCleanCdnUrl());
        o.Add("banner", member.DescriptionPrivacy.Get(ctx, member.BannerImage).TryGetCleanCdnUrl());
        o.Add("description", member.DescriptionFor(ctx));
        o.Add("created", member.CreatedFor(ctx)?.FormatExport());
        o.Add("keep_proxy", member.KeepProxy);

        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);

        if (includePrivacy)
        {
            var p = new JObject();

            p.Add("visibility", member.MemberVisibility.ToJsonString());
            p.Add("name_privacy", member.NamePrivacy.ToJsonString());
            p.Add("description_privacy", member.DescriptionPrivacy.ToJsonString());
            p.Add("birthday_privacy", member.BirthdayPrivacy.ToJsonString());
            p.Add("pronoun_privacy", member.PronounPrivacy.ToJsonString());
            p.Add("avatar_privacy", member.AvatarPrivacy.ToJsonString());
            p.Add("metadata_privacy", member.MetadataPrivacy.ToJsonString());

            o.Add("privacy", p);
        }
        else
        {
            o.Add("privacy", null);
        }

        return(o);
    }
コード例 #6
0
ファイル: Autoproxy.cs プロジェクト: SwiftAusterity/PluralKit
        private async Task AutoproxyMember(Context ctx, PKMember member)
        {
            ctx.CheckOwnMember(member);

            await UpdateAutoproxy(ctx, AutoproxyMode.Member, member.Id);

            await ctx.Reply($"{Emojis.Success} Autoproxy set to **{member.NameFor(ctx)}** in this server.");
        }
コード例 #7
0
ファイル: MemberEdit.cs プロジェクト: starshine-sys/PluralKit
        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 if (ctx.MatchFlag("r", "raw"))
                {
                    await ctx.Reply($"```\n{target.Pronouns}\n```");
                }
                else
                {
                    await ctx.Reply($"**{target.NameFor(ctx)}**'s pronouns are **{target.Pronouns}**.\nTo print the pronouns with formatting, type `pk;member {target.Reference()} pronouns -raw`."
                                    + (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.");
            }
        }
コード例 #8
0
    private async Task AutoproxyMember(Context ctx, PKMember member)
    {
        ctx.CheckOwnMember(member);

        // todo: why does this not throw an error if the member is already set

        await UpdateAutoproxy(ctx, AutoproxyMode.Member, member.Id);

        await ctx.Reply($"{Emojis.Success} Autoproxy set to **{member.NameFor(ctx)}** in this server.");
    }
コード例 #9
0
        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);
            var name      = member.NameFor(LookupContext.ByNonOwner);

            return(new DiscordEmbedBuilder()
                   .WithAuthor($"#{channel.Name}: {name}", iconUrl: DiscordUtils.WorkaroundForUrlBug(member.AvatarFor(LookupContext.ByNonOwner)))
                   .WithThumbnail(member.AvatarFor(LookupContext.ByNonOwner))
                   .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());
        }
コード例 #10
0
        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.");
            }
        }
コード例 #11
0
        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());
        }
コード例 #12
0
        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);
        }
コード例 #13
0
ファイル: MemberEdit.cs プロジェクト: guccigang17/PluralKit
        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.");
        }
コード例 #14
0
ファイル: MemberAvatar.cs プロジェクト: xSke/PluralKit
    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());
    }
コード例 #15
0
        public async Task Delete(Context ctx, PKMember target)
        {
            if (ctx.System == null)
            {
                throw Errors.NoSystemError;
            }
            if (target.System != ctx.System.Id)
            {
                throw Errors.NotOwnMemberError;
            }

            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 _data.DeleteMember(target);

            await ctx.Reply($"{Emojis.Success} Member deleted.");
        }
コード例 #16
0
        private DiscordEmbed CreatePrivacyEmbed(Context ctx, PKMember member)
        {
            string PrivacyLevelString(PrivacyLevel level) => level switch
            {
                PrivacyLevel.Private => "**Private** (visible only when queried by you)",
                PrivacyLevel.Public => "**Public** (visible to everyone)",
                _ => throw new ArgumentOutOfRangeException(nameof(level), level, null)
            };

            var eb = new DiscordEmbedBuilder()
                     .WithTitle($"Current privacy settings for {member.NameFor(ctx)}")
                     .AddField("Name (replaces name with display name if member has one)", PrivacyLevelString(member.NamePrivacy))
                     .AddField("Description", PrivacyLevelString(member.DescriptionPrivacy))
                     .AddField("Avatar", PrivacyLevelString(member.AvatarPrivacy))
                     .AddField("Birthday", PrivacyLevelString(member.BirthdayPrivacy))
                     .AddField("Pronouns", PrivacyLevelString(member.PronounPrivacy))
                     // .AddField("Color", PrivacyLevelString(target.ColorPrivacy))
                     .AddField("Meta (message count, last front, last message)", PrivacyLevelString(member.MetadataPrivacy))
                     .AddField("Visibility", PrivacyLevelString(member.MemberVisibility))
                     .WithDescription("To edit privacy settings, use the command:\n`pk;member <member> privacy <subject> <level>`\n\n- `subject` is one of `name`, `description`, `avatar`, `birthday`, `pronouns`, `created`, `messages`, `visibility`, or `all`\n- `level` is either `public` or `private`.");

            return(eb.Build());
        }
コード例 #17
0
ファイル: ModelUtils.cs プロジェクト: xSke/PluralKit
 public static string Reference(this PKMember member, Context ctx) => EntityReference(member.Hid, member.NameFor(ctx));
コード例 #18
0
ファイル: MemberEdit.cs プロジェクト: guccigang17/PluralKit
        public async Task Privacy(Context ctx, PKMember target, PrivacyLevel?newValueFromCommand)
        {
            ctx.CheckSystem().CheckOwnMember(target);

            // Display privacy settings
            if (!ctx.HasNext() && newValueFromCommand == null)
            {
                await ctx.Reply(embed : new EmbedBuilder()
                                .Title($"Current privacy settings for {target.NameFor(ctx)}")
                                .Field(new("Name (replaces name with display name if member has one)", target.NamePrivacy.Explanation()))
                                .Field(new("Description", target.DescriptionPrivacy.Explanation()))
                                .Field(new("Avatar", target.AvatarPrivacy.Explanation()))
                                .Field(new("Birthday", target.BirthdayPrivacy.Explanation()))
                                .Field(new("Pronouns", target.PronounPrivacy.Explanation()))
                                .Field(new("Meta (message count, last front, last message)", target.MetadataPrivacy.Explanation()))
                                .Field(new("Visibility", target.MemberVisibility.Explanation()))
                                .Description("To edit privacy settings, use the command:\n`pk;member <member> privacy <subject> <level>`\n\n- `subject` is one of `name`, `description`, `avatar`, `birthday`, `pronouns`, `created`, `messages`, `visibility`, or `all`\n- `level` is either `public` or `private`.")
                                .Build());

                return;
            }

            // Get guild settings (mostly for warnings and such)
            MemberGuildSettings guildSettings = null;

            if (ctx.Guild != null)
            {
                guildSettings = await _db.Execute(c => _repo.GetMemberGuild(c, ctx.Guild.Id, target.Id));
            }

            async Task SetAll(PrivacyLevel level)
            {
                await _db.Execute(c => _repo.UpdateMember(c, target.Id, new MemberPatch().WithAllPrivacy(level)));

                if (level == PrivacyLevel.Private)
                {
                    await ctx.Reply($"{Emojis.Success} All {target.NameFor(ctx)}'s privacy settings have been set to **{level.LevelName()}**. Other accounts will now see nothing on the member card.");
                }
                else
                {
                    await ctx.Reply($"{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)
            {
                await _db.Execute(c => _repo.UpdateMember(c, target.Id, new MemberPatch().WithPrivacy(subject, level)));

                var subjectName = subject switch
                {
                    MemberPrivacySubject.Name => "name privacy",
                    MemberPrivacySubject.Description => "description privacy",
                    MemberPrivacySubject.Avatar => "avatar privacy",
                    MemberPrivacySubject.Pronouns => "pronoun privacy",
                    MemberPrivacySubject.Birthday => "birthday privacy",
                    MemberPrivacySubject.Metadata => "metadata privacy",
                    MemberPrivacySubject.Visibility => "visibility",
                    _ => throw new ArgumentOutOfRangeException($"Unknown privacy subject {subject}")
                };

                var explanation = (subject, level) switch
                {
                    (MemberPrivacySubject.Name, PrivacyLevel.Private) => "This member's name is now hidden from other systems, and will be replaced by the member's display name.",
                    (MemberPrivacySubject.Description, PrivacyLevel.Private) => "This member's description is now hidden from other systems.",
                    (MemberPrivacySubject.Avatar, PrivacyLevel.Private) => "This member's avatar is now hidden from other systems.",
                    (MemberPrivacySubject.Birthday, PrivacyLevel.Private) => "This member's birthday is now hidden from other systems.",
                    (MemberPrivacySubject.Pronouns, PrivacyLevel.Private) => "This member's pronouns are now hidden from other systems.",
                    (MemberPrivacySubject.Metadata, PrivacyLevel.Private) => "This member's metadata (eg. created timestamp, message count, etc) is now hidden from other systems.",
                    (MemberPrivacySubject.Visibility, PrivacyLevel.Private) => "This member is now hidden from member lists.",

                    (MemberPrivacySubject.Name, PrivacyLevel.Public) => "This member's name is no longer hidden from other systems.",
                    (MemberPrivacySubject.Description, PrivacyLevel.Public) => "This member's description is no longer hidden from other systems.",
                    (MemberPrivacySubject.Avatar, PrivacyLevel.Public) => "This member's avatar is no longer hidden from other systems.",
                    (MemberPrivacySubject.Birthday, PrivacyLevel.Public) => "This member's birthday is no longer hidden from other systems.",
                    (MemberPrivacySubject.Pronouns, PrivacyLevel.Public) => "This member's pronouns are no longer hidden other systems.",
                    (MemberPrivacySubject.Metadata, PrivacyLevel.Public) => "This member's metadata (eg. created timestamp, message count, etc) is no longer hidden from other systems.",
                    (MemberPrivacySubject.Visibility, PrivacyLevel.Public) => "This member is no longer hidden from member lists.",

                    _ => throw new InvalidOperationException($"Invalid subject/level tuple ({subject}, {level})")
                };

                await ctx.Reply($"{Emojis.Success} {target.NameFor(ctx)}'s **{subjectName}** has been set to **{level.LevelName()}**. {explanation}");

                // Name privacy only works given a display name
                if (subject == MemberPrivacySubject.Name && level == PrivacyLevel.Private && target.DisplayName == null)
                {
                    await ctx.Reply($"{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
                if (subject == MemberPrivacySubject.Avatar && level == PrivacyLevel.Private && guildSettings?.AvatarUrl == null)
                {
                    await ctx.Reply($"{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: `pk;member {target.Reference()} serveravatar`");
                }
            }

            if (ctx.Match("all") || newValueFromCommand != null)
            {
                await SetAll(newValueFromCommand ?? ctx.PopPrivacyLevel());
            }
            else
            {
                await SetLevel(ctx.PopMemberPrivacySubject(), ctx.PopPrivacyLevel());
            }
        }
コード例 #19
0
    public async Task Pronouns(Context ctx, PKMember target)
    {
        var noPronounsSetMessage = "This member does not have pronouns set.";

        if (ctx.System?.Id == target.System)
        {
            noPronounsSetMessage += $"To set some, type `pk;member {target.Reference(ctx)} pronouns <pronouns>`.";
        }

        ctx.CheckSystemPrivacy(target.System, target.PronounPrivacy);

        if (ctx.MatchRaw())
        {
            if (target.Pronouns == null)
            {
                await ctx.Reply(noPronounsSetMessage);
            }
            else
            {
                await ctx.Reply($"```\n{target.Pronouns}\n```");
            }
            return;
        }

        if (!ctx.HasNext(false))
        {
            if (target.Pronouns == null)
            {
                await ctx.Reply(noPronounsSetMessage);
            }
            else
            {
                await ctx.Reply(
                    $"**{target.NameFor(ctx)}**'s pronouns are **{target.Pronouns}**.\nTo print the pronouns with formatting, type `pk;member {target.Reference(ctx)} pronouns -raw`."
                    + (ctx.System?.Id == target.System
                        ? $" To clear them, type `pk;member {target.Reference(ctx)} pronouns -clear`."
                        : ""));
            }
            return;
        }

        ctx.CheckOwnMember(target);

        if (await ctx.MatchClear("this member's pronouns"))
        {
            var patch = new MemberPatch {
                Pronouns = Partial <string> .Null()
            };
            await ctx.Repository.UpdateMember(target.Id, patch);

            await ctx.Reply($"{Emojis.Success} Member pronouns cleared.");
        }
        else
        {
            var pronouns = ctx.RemainderOrNull(false).NormalizeLineEndSpacing();
            if (pronouns.IsLongerThan(Limits.MaxPronounsLength))
            {
                throw Errors.StringTooLongError("Pronouns", pronouns.Length, Limits.MaxPronounsLength);
            }

            var patch = new MemberPatch {
                Pronouns = Partial <string> .Present(pronouns)
            };
            await ctx.Repository.UpdateMember(target.Id, patch);

            await ctx.Reply($"{Emojis.Success} Member pronouns changed.");
        }
    }
コード例 #20
0
ファイル: MemberEdit.cs プロジェクト: guccigang17/PluralKit
        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 => _repo.GetMemberGuild(c, 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 (await ctx.MatchClear("this member's display name"))
            {
                ctx.CheckOwnMember(target);

                var patch = new MemberPatch {
                    DisplayName = Partial <string> .Null()
                };
                await _db.Execute(conn => _repo.UpdateMember(conn, 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.Description($"To change display name, type `pk;member {target.Reference()} displayname <display name>`.\nTo clear it, type `pk;member {target.Reference()} displayname -clear`.");
                }
                await ctx.Reply(embed : eb.Build());
            }
            else
            {
                ctx.CheckOwnMember(target);

                var newDisplayName = ctx.RemainderOrNull();

                var patch = new MemberPatch {
                    DisplayName = Partial <string> .Present(newDisplayName)
                };
                await _db.Execute(conn => _repo.UpdateMember(conn, target.Id, patch));

                await PrintSuccess($"{Emojis.Success} Member display name changed. This member will now be proxied using the name \"{newDisplayName}\".");
            }
        }
コード例 #21
0
ファイル: MemberEdit.cs プロジェクト: guccigang17/PluralKit
        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}).");
            }
        }
コード例 #22
0
        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 (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.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();
                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}\".");
            }
        }
コード例 #23
0
        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}\" 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.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}\" in this server ({ctx.Guild.Name}).");
            }
        }
コード例 #24
0
        public async Task Privacy(Context ctx, PKMember target, PrivacyLevel?newValueFromCommand)
        {
            if (ctx.System == null)
            {
                throw Errors.NoSystemError;
            }
            if (target.System != ctx.System.Id)
            {
                throw Errors.NotOwnMemberError;
            }

            // Display privacy settings
            if (!ctx.HasNext() && newValueFromCommand == null)
            {
                await ctx.Reply(embed : CreatePrivacyEmbed(ctx, target));

                return;
            }

            // Get guild settings (mostly for warnings and such)
            MemberGuildSettings guildSettings = null;

            if (ctx.Guild != null)
            {
                guildSettings = await _db.Execute(c => c.QueryOrInsertMemberGuildConfig(ctx.Guild.Id, target.Id));
            }

            // Set Privacy Settings
            PrivacyLevel PopPrivacyLevel(string subjectName)
            {
                if (ctx.Match("public", "show", "shown", "visible"))
                {
                    return(PrivacyLevel.Public);
                }

                if (ctx.Match("private", "hide", "hidden"))
                {
                    return(PrivacyLevel.Private);
                }

                if (!ctx.HasNext())
                {
                    throw new PKSyntaxError($"You must pass a privacy level for `{subjectName}` (`public` or `private`)");
                }
                throw new PKSyntaxError($"Invalid privacy level `{ctx.PopArgument()}` (must be `public` or `private`).");
            }

            // See if we have a subject given
            PrivacyLevel newLevel;

            if (PrivacyUtils.TryParseMemberPrivacy(ctx.PeekArgument(), out var subject))
            {
                // We peeked before, pop it now
                ctx.PopArgument();

                // Read the privacy level from args
                newLevel = PopPrivacyLevel(subject.Name());

                // Set the level on the given subject
                target.SetPrivacy(subject, newLevel);
                await _data.SaveMember(target);

                // Print response
                var explanation = (subject, newLevel) switch
                {
                    (MemberPrivacySubject.Name, PrivacyLevel.Private) => "This member's name is now hidden from other systems, and will be replaced by the member's display name.",
                    (MemberPrivacySubject.Description, PrivacyLevel.Private) => "This member's description is now hidden from other systems.",
                    (MemberPrivacySubject.Avatar, PrivacyLevel.Private) => "This member's avatar is now hidden from other systems.",
                    (MemberPrivacySubject.Birthday, PrivacyLevel.Private) => "This member's birthday is now hidden from other systems.",
                    (MemberPrivacySubject.Pronouns, PrivacyLevel.Private) => "This member's pronouns are now hidden from other systems.",
                    (MemberPrivacySubject.Metadata, PrivacyLevel.Private) => "This member's metadata (eg. created timestamp, message count, etc) is now hidden from other systems.",
                    (MemberPrivacySubject.Visibility, PrivacyLevel.Private) => "This member is now hidden from member lists.",

                    (MemberPrivacySubject.Name, PrivacyLevel.Public) => "This member's name is no longer hidden from other systems.",
                    (MemberPrivacySubject.Description, PrivacyLevel.Public) => "This member's description is no longer hidden from other systems.",
                    (MemberPrivacySubject.Avatar, PrivacyLevel.Public) => "This member's avatar is no longer hidden from other systems.",
                    (MemberPrivacySubject.Birthday, PrivacyLevel.Public) => "This member's birthday is no longer hidden from other systems.",
                    (MemberPrivacySubject.Pronouns, PrivacyLevel.Public) => "This member's pronouns are no longer hidden other systems.",
                    (MemberPrivacySubject.Metadata, PrivacyLevel.Public) => "This member's metadata (eg. created timestamp, message count, etc) is no longer hidden from other systems.",
                    (MemberPrivacySubject.Visibility, PrivacyLevel.Public) => "This member is no longer hidden from member lists.",

                    _ => throw new InvalidOperationException($"Invalid subject/level tuple ({subject}, {newLevel})")
                };

                await ctx.Reply($"{Emojis.Success} {target.NameFor(ctx)}'s {subject.Name()} has been set to **{newLevel.LevelName()}**. {explanation}");
            }
            else if (ctx.Match("all") || newValueFromCommand != null)
            {
                newLevel = newValueFromCommand ?? PopPrivacyLevel("all");
                target.SetAllPrivacy(newLevel);
                await _data.SaveMember(target);

                if (newLevel == PrivacyLevel.Private)
                {
                    await ctx.Reply($"All {target.NameFor(ctx)}'s privacy settings have been set to **{newLevel.LevelName()}**. Other accounts will now see nothing on the member card.");
                }
                else
                {
                    await ctx.Reply($"All {target.NameFor(ctx)}'s privacy settings have been set to **{newLevel.LevelName()}**. Other accounts will now see everything on the member card.");
                }
            }
            else
            {
                var subjectList = "`name`, `description`, `avatar`, `birthday`, `pronouns`, `metadata`, `visibility`, or `all`";
                throw new PKSyntaxError($"Invalid privacy subject `{ctx.PopArgument()}` (must be {subjectList}).");
            }

            // Name privacy only works given a display name
            if (subject == MemberPrivacySubject.Name && newLevel == PrivacyLevel.Private && target.DisplayName == null)
            {
                await ctx.Reply($"{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
            if (subject == MemberPrivacySubject.Avatar && newLevel == PrivacyLevel.Private &&
                guildSettings?.AvatarUrl == null)
            {
                await ctx.Reply($"{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: `pk;member {target.Hid} serveravatar`");
            }
        }
コード例 #25
0
    public static JObject ToJson(this PKMember member, LookupContext ctx, bool needsLegacyProxyTags = false,
                                 string systemStr = null, APIVersion v = APIVersion.V1)
    {
        var includePrivacy = ctx == LookupContext.ByOwner;

        var o = new JObject();

        o.Add("id", member.Hid);

        if (v == APIVersion.V2)
        {
            o.Add("uuid", member.Uuid.ToString());
            if (systemStr != null)
            {
                o.Add("system", systemStr);
            }
        }

        o.Add("name", member.NameFor(ctx));

        // o.Add("color", member.ColorPrivacy.CanAccess(ctx) ? member.Color : null);
        o.Add("display_name", member.NamePrivacy.CanAccess(ctx) ? member.DisplayName : null);
        o.Add("color", member.Color);
        o.Add("birthday", member.BirthdayFor(ctx)?.FormatExport());
        o.Add("pronouns", member.PronounsFor(ctx));
        o.Add("avatar_url", member.AvatarFor(ctx).TryGetCleanCdnUrl());
        o.Add("banner", member.DescriptionPrivacy.Get(ctx, member.BannerImage).TryGetCleanCdnUrl());
        o.Add("description", member.DescriptionFor(ctx));
        o.Add("created", member.CreatedFor(ctx)?.FormatExport());
        o.Add("keep_proxy", member.KeepProxy);

        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);

        switch (v)
        {
        case APIVersion.V1:
        {
            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);

            if (member.ProxyTags.Count > 0 && needsLegacyProxyTags)
            {
                // Legacy compatibility only, TODO: remove at some point
                o.Add("prefix", member.ProxyTags?.FirstOrDefault().Prefix);
                o.Add("suffix", member.ProxyTags?.FirstOrDefault().Suffix);
            }

            break;
        }

        case APIVersion.V2:
        {
            if (includePrivacy)
            {
                var p = new JObject();

                p.Add("visibility", member.MemberVisibility.ToJsonString());
                p.Add("name_privacy", member.NamePrivacy.ToJsonString());
                p.Add("description_privacy", member.DescriptionPrivacy.ToJsonString());
                p.Add("birthday_privacy", member.BirthdayPrivacy.ToJsonString());
                p.Add("pronoun_privacy", member.PronounPrivacy.ToJsonString());
                p.Add("avatar_privacy", member.AvatarPrivacy.ToJsonString());
                p.Add("metadata_privacy", member.MetadataPrivacy.ToJsonString());

                o.Add("privacy", p);
            }
            else
            {
                o.Add("privacy", null);
            }

            break;
        }
        }

        return(o);
    }
コード例 #26
0
    public async Task <Embed> CreateMemberEmbed(PKSystem system, PKMember member, Guild guild, LookupContext ctx, DateTimeZone zone)
    {
        // string FormatTimestamp(Instant timestamp) => DateTimeFormats.ZonedDateTimeFormat.Format(timestamp.InZone(system.Zone));

        var name = member.NameFor(ctx);

        if (system.Name != null)
        {
            name = $"{name} ({system.Name})";
        }

        uint color;

        try
        {
            color = member.Color?.ToDiscordColor() ?? DiscordUtils.Gray;
        }
        catch (ArgumentException)
        {
            // Bad API use can cause an invalid color string
            // this is now fixed in the API, but might still have some remnants in the database
            // so we just default to a blank color, yolo
            color = DiscordUtils.Gray;
        }

        var guildSettings = guild != null ? await _repo.GetMemberGuild(guild.Id, member.Id) : null;

        var guildDisplayName = guildSettings?.DisplayName;
        var avatar           = guildSettings?.AvatarUrl ?? member.AvatarFor(ctx);

        var groups = await _repo.GetMemberGroups(member.Id)
                     .Where(g => g.Visibility.CanAccess(ctx))
                     .OrderBy(g => g.Name, StringComparer.InvariantCultureIgnoreCase)
                     .ToListAsync();

        var eb = new EmbedBuilder()
                 .Author(new Embed.EmbedAuthor(name, IconUrl: avatar.TryGetCleanCdnUrl(), Url: $"https://dash.pluralkit.me/profile/m/{member.Hid}"))
                 // .WithColor(member.ColorPrivacy.CanAccess(ctx) ? color : DiscordUtils.Gray)
                 .Color(color)
                 .Footer(new Embed.EmbedFooter(
                             $"System ID: {system.Hid} | Member ID: {member.Hid} {(member.MetadataPrivacy.CanAccess(ctx) ? $"| Created on {member.Created.FormatZoned(zone)}" : "")}"));

        if (member.DescriptionPrivacy.CanAccess(ctx))
        {
            eb.Image(new Embed.EmbedImage(member.BannerImage));
        }

        var description = "";

        if (member.MemberVisibility == PrivacyLevel.Private)
        {
            description += "*(this member is hidden)*\n";
        }
        if (guildSettings?.AvatarUrl != null)
        {
            if (member.AvatarFor(ctx) != null)
            {
                description +=
                    $"*(this member has a server-specific avatar set; [click here]({member.AvatarUrl.TryGetCleanCdnUrl()}) to see the global avatar)*\n";
            }
            else
            {
                description += "*(this member has a server-specific avatar set)*\n";
            }
        }
        if (description != "")
        {
            eb.Description(description);
        }

        if (avatar != null)
        {
            eb.Thumbnail(new Embed.EmbedThumbnail(avatar.TryGetCleanCdnUrl()));
        }

        if (!member.DisplayName.EmptyOrNull() && member.NamePrivacy.CanAccess(ctx))
        {
            eb.Field(new Embed.Field("Display Name", member.DisplayName.Truncate(1024), true));
        }
        if (guild != null && guildDisplayName != null)
        {
            eb.Field(new Embed.Field($"Server Nickname (for {guild.Name})", guildDisplayName.Truncate(1024), true));
        }
        if (member.BirthdayFor(ctx) != null)
        {
            eb.Field(new Embed.Field("Birthdate", member.BirthdayString, true));
        }
        if (member.PronounsFor(ctx) is { } pronouns&& !string.IsNullOrWhiteSpace(pronouns))
        {
            eb.Field(new Embed.Field("Pronouns", pronouns.Truncate(1024), true));
        }
        if (member.MessageCountFor(ctx) is { } count&& count > 0)
        {
            eb.Field(new Embed.Field("Message Count", member.MessageCount.ToString(), true));
        }
        if (member.HasProxyTags)
        {
            eb.Field(new Embed.Field("Proxy Tags", member.ProxyTagsString("\n").Truncate(1024), true));
        }
        // --- For when this gets added to the member object itself or however they get added
        // if (member.LastMessage != null && member.MetadataPrivacy.CanAccess(ctx)) eb.AddField("Last message:" FormatTimestamp(DiscordUtils.SnowflakeToInstant(m.LastMessage.Value)));
        // if (member.LastSwitchTime != null && m.MetadataPrivacy.CanAccess(ctx)) eb.AddField("Last switched in:", FormatTimestamp(member.LastSwitchTime.Value));
        // if (!member.Color.EmptyOrNull() && member.ColorPrivacy.CanAccess(ctx)) eb.AddField("Color", $"#{member.Color}", true);
        if (!member.Color.EmptyOrNull())
        {
            eb.Field(new Embed.Field("Color", $"#{member.Color}", true));
        }

        if (groups.Count > 0)
        {
            // More than 5 groups show in "compact" format without ID
            var content = groups.Count > 5
                ? string.Join(", ", groups.Select(g => g.DisplayName ?? g.Name))
                : string.Join("\n", groups.Select(g => $"[`{g.Hid}`] **{g.DisplayName ?? g.Name}**"));
            eb.Field(new Embed.Field($"Groups ({groups.Count})", content.Truncate(1000)));
        }

        if (member.DescriptionFor(ctx) is { } desc)
        {
            eb.Field(new Embed.Field("Description", member.Description.NormalizeLineEndSpacing()));
        }

        return(eb.Build());
    }
コード例 #27
0
        public async Task <DiscordEmbed> CreateMemberEmbed(PKSystem system, PKMember member, DiscordGuild guild, LookupContext ctx)
        {
            // string FormatTimestamp(Instant timestamp) => DateTimeFormats.ZonedDateTimeFormat.Format(timestamp.InZone(system.Zone));

            var name = member.NameFor(ctx);

            if (system.Name != null)
            {
                name = $"{name} ({system.Name})";
            }

            DiscordColor color;

            try
            {
                color = member.Color?.ToDiscordColor() ?? DiscordUtils.Gray;
            }
            catch (ArgumentException)
            {
                // Bad API use can cause an invalid color string
                // TODO: fix that in the API
                // for now we just default to a blank color, yolo
                color = DiscordUtils.Gray;
            }

            await using var conn = await _db.Obtain();

            var guildSettings = guild != null ? await conn.QueryOrInsertMemberGuildConfig(guild.Id, member.Id) : null;

            var guildDisplayName = guildSettings?.DisplayName;
            var avatar           = guildSettings?.AvatarUrl ?? member.AvatarFor(ctx);

            var groups = (await conn.QueryMemberGroups(member.Id)).Where(g => g.Visibility.CanAccess(ctx)).ToList();

            var eb = new DiscordEmbedBuilder()
                     // TODO: add URL of website when that's up
                     .WithAuthor(name, iconUrl: DiscordUtils.WorkaroundForUrlBug(avatar))
                     // .WithColor(member.ColorPrivacy.CanAccess(ctx) ? color : DiscordUtils.Gray)
                     .WithColor(color)
                     .WithFooter($"System ID: {system.Hid} | Member ID: {member.Hid} {(member.MetadataPrivacy.CanAccess(ctx) ? $"| Created on {member.Created.FormatZoned(system)}":"")}");

            var description = "";

            if (member.MemberVisibility == PrivacyLevel.Private)
            {
                description += "*(this member is hidden)*\n";
            }
            if (guildSettings?.AvatarUrl != null)
            {
                if (member.AvatarFor(ctx) != null)
                {
                    description += $"*(this member has a server-specific avatar set; [click here]({member.AvatarUrl}) to see the global avatar)*\n";
                }
                else
                {
                    description += "*(this member has a server-specific avatar set)*\n";
                }
            }
            if (description != "")
            {
                eb.WithDescription(description);
            }

            if (avatar != null)
            {
                eb.WithThumbnail(avatar);
            }

            if (!member.DisplayName.EmptyOrNull() && member.NamePrivacy.CanAccess(ctx))
            {
                eb.AddField("Display Name", member.DisplayName.Truncate(1024), true);
            }
            if (guild != null && guildDisplayName != null)
            {
                eb.AddField($"Server Nickname (for {guild.Name})", guildDisplayName.Truncate(1024), true);
            }
            if (member.BirthdayFor(ctx) != null)
            {
                eb.AddField("Birthdate", member.BirthdayString, true);
            }
            if (member.PronounsFor(ctx) is {} pronouns&& !string.IsNullOrWhiteSpace(pronouns))
            {
                eb.AddField("Pronouns", pronouns.Truncate(1024), true);
            }
            if (member.MessageCountFor(ctx) is {} count&& count > 0)
            {
                eb.AddField("Message Count", member.MessageCount.ToString(), true);
            }
            if (member.HasProxyTags)
            {
                eb.AddField("Proxy Tags", member.ProxyTagsString("\n").Truncate(1024), true);
            }
            // --- For when this gets added to the member object itself or however they get added
            // if (member.LastMessage != null && member.MetadataPrivacy.CanAccess(ctx)) eb.AddField("Last message:" FormatTimestamp(DiscordUtils.SnowflakeToInstant(m.LastMessage.Value)));
            // if (member.LastSwitchTime != null && m.MetadataPrivacy.CanAccess(ctx)) eb.AddField("Last switched in:", FormatTimestamp(member.LastSwitchTime.Value));
            // if (!member.Color.EmptyOrNull() && member.ColorPrivacy.CanAccess(ctx)) eb.AddField("Color", $"#{member.Color}", true);
            if (!member.Color.EmptyOrNull())
            {
                eb.AddField("Color", $"#{member.Color}", true);
            }

            if (groups.Count > 0)
            {
                // More than 5 groups show in "compact" format without ID
                var content = groups.Count > 5
                    ? string.Join(", ", groups.Select(g => g.DisplayName ?? g.Name))
                    : string.Join("\n", groups.Select(g => $"[`{g.Hid}`] **{g.DisplayName ?? g.Name}**"));
                eb.AddField($"Groups ({groups.Count})", content.Truncate(1000));
            }

            if (member.DescriptionFor(ctx) is {} desc)
            {
                eb.AddField("Description", member.Description.NormalizeLineEndSpacing(), false);
            }

            return(eb.Build());
        }
コード例 #28
0
 public static string NameFor(this PKMember member, Context ctx) =>
 member.NameFor(ctx.LookupContextFor(member));