Move most references to PKMember.Name to go through helper extepsions for privacy

This commit is contained in:
Ske 2020-06-18 17:08:36 +02:00
parent 761270f0c3
commit 56eae82b0a
22 changed files with 97 additions and 62 deletions

View File

@ -44,7 +44,7 @@ namespace PluralKit.API
{ {
var o = new JObject(); var o = new JObject();
o.Add("id", member.Hid); o.Add("id", member.Hid);
o.Add("name", member.NamePrivacy.CanAccess(ctx) ? member.Name : member.DisplayName ?? member.Name); o.Add("name", member.NameFor(ctx));
// o.Add("color", member.ColorPrivacy.CanAccess(ctx) ? member.Color : null); // o.Add("color", member.ColorPrivacy.CanAccess(ctx) ? member.Color : null);
o.Add("color", member.Color); o.Add("color", member.Color);
o.Add("display_name", member.NamePrivacy.CanAccess(ctx) ? member.DisplayName : null); o.Add("display_name", member.NamePrivacy.CanAccess(ctx) ? member.DisplayName : null);

View File

@ -279,6 +279,9 @@ namespace PluralKit.Bot
public LookupContext LookupContextFor(SystemId systemId) => public LookupContext LookupContextFor(SystemId systemId) =>
System?.Id == systemId ? LookupContext.ByOwner : LookupContext.ByNonOwner; System?.Id == systemId ? LookupContext.ByOwner : LookupContext.ByNonOwner;
public LookupContext LookupContextFor(PKMember target) =>
System?.Id == target.System ? LookupContext.ByOwner : LookupContext.ByNonOwner;
public Context CheckSystemPrivacy(PKSystem target, PrivacyLevel level) public Context CheckSystemPrivacy(PKSystem target, PrivacyLevel level)
{ {
if (level.CanAccess(LookupContextFor(target))) return this; if (level.CanAccess(LookupContextFor(target))) return this;

View File

@ -76,7 +76,7 @@ namespace PluralKit.Bot
ctx.CheckOwnMember(member); ctx.CheckOwnMember(member);
await UpdateAutoproxy(ctx, AutoproxyMode.Member, member.Id); await UpdateAutoproxy(ctx, AutoproxyMode.Member, member.Id);
await ctx.Reply($"{Emojis.Success} Autoproxy set to **{member.Name}** in this server."); await ctx.Reply($"{Emojis.Success} Autoproxy set to **{member.NameFor(ctx)}** in this server.");
} }
private async Task<DiscordEmbed> CreateAutoproxyStatusEmbed(Context ctx) private async Task<DiscordEmbed> CreateAutoproxyStatusEmbed(Context ctx)
@ -103,14 +103,14 @@ namespace PluralKit.Bot
{ {
if (relevantMember == null) if (relevantMember == null)
throw new ArgumentException("Attempted to print member autoproxy status, but the linked member ID wasn't found in the database. Should be handled appropriately."); throw new ArgumentException("Attempted to print member autoproxy status, but the linked member ID wasn't found in the database. Should be handled appropriately.");
eb.WithDescription($"Autoproxy is currently set to **front mode** in this server. The current (first) fronter is **{relevantMember.Name.EscapeMarkdown()}** (`{relevantMember.Hid}`). To disable, type `pk;autoproxy off`."); eb.WithDescription($"Autoproxy is currently set to **front mode** in this server. The current (first) fronter is **{relevantMember.NameFor(ctx).EscapeMarkdown()}** (`{relevantMember.Hid}`). To disable, type `pk;autoproxy off`.");
} }
break; break;
} }
// AutoproxyMember is never null if Mode is Member, this is just to make the compiler shut up // AutoproxyMember is never null if Mode is Member, this is just to make the compiler shut up
case AutoproxyMode.Member when relevantMember != null: { case AutoproxyMode.Member when relevantMember != null: {
eb.WithDescription($"Autoproxy is active for member **{relevantMember.Name}** (`{relevantMember.Hid}`) in this server. To disable, type `pk;autoproxy off`."); eb.WithDescription($"Autoproxy is active for member **{relevantMember.NameFor(ctx)}** (`{relevantMember.Hid}`) in this server. To disable, type `pk;autoproxy off`.");
break; break;
} }
case AutoproxyMode.Latch: case AutoproxyMode.Latch:

View File

@ -28,7 +28,7 @@ namespace PluralKit.Bot
// Warn if there's already a member by this name // Warn if there's already a member by this name
var existingMember = await _data.GetMemberByName(ctx.System, memberName); var existingMember = await _data.GetMemberByName(ctx.System, memberName);
if (existingMember != null) { if (existingMember != null) {
var msg = await ctx.Reply($"{Emojis.Warn} You already have a member in your system with the name \"{existingMember.Name.SanitizeMentions()}\" (with ID `{existingMember.Hid}`). Do you want to create another member with the same name?"); var msg = await ctx.Reply($"{Emojis.Warn} You already have a member in your system with the name \"{existingMember.NameFor(ctx).SanitizeMentions()}\" (with ID `{existingMember.Hid}`). Do you want to create another member with the same name?");
if (!await ctx.PromptYesNo(msg)) throw new PKError("Member creation cancelled."); if (!await ctx.PromptYesNo(msg)) throw new PKError("Member creation cancelled.");
} }

View File

@ -61,7 +61,7 @@ namespace PluralKit.Bot
} }
var eb = new DiscordEmbedBuilder() var eb = new DiscordEmbedBuilder()
.WithTitle($"{target.Name.SanitizeMentions()}'s {field}") .WithTitle($"{target.NameFor(ctx).SanitizeMentions()}'s {field}")
.WithImageUrl(currentValue); .WithImageUrl(currentValue);
if (target.System == ctx.System?.Id) if (target.System == ctx.System?.Id)
eb.WithDescription($"To clear, use `pk;member {target.Hid} {cmd} clear`."); eb.WithDescription($"To clear, use `pk;member {target.Hid} {cmd} clear`.");

View File

@ -35,7 +35,7 @@ namespace PluralKit.Bot
// Warn if there's already a member by this name // Warn if there's already a member by this name
var existingMember = await _data.GetMemberByName(ctx.System, newName); var existingMember = await _data.GetMemberByName(ctx.System, newName);
if (existingMember != null) { 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?"); var msg = await ctx.Reply($"{Emojis.Warn} You already have a member in your system with the name \"{existingMember.NameFor(ctx).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."); if (!await ctx.PromptYesNo(msg)) throw new PKError("Member renaming cancelled.");
} }
@ -124,7 +124,7 @@ namespace PluralKit.Bot
else else
await ctx.Reply("This member does not have pronouns set."); await ctx.Reply("This member does not have pronouns set.");
else else
await ctx.Reply($"**{target.Name.SanitizeMentions()}**'s pronouns are **{target.Pronouns.SanitizeMentions()}**." await ctx.Reply($"**{target.NameFor(ctx).SanitizeMentions()}**'s pronouns are **{target.Pronouns.SanitizeMentions()}**."
+ (ctx.System?.Id == target.System ? $" To clear them, type `pk;member {target.Hid} pronouns -clear`." : "")); + (ctx.System?.Id == target.System ? $" To clear them, type `pk;member {target.Hid} pronouns -clear`." : ""));
} }
else else
@ -223,6 +223,8 @@ namespace PluralKit.Bot
private async Task<DiscordEmbedBuilder> CreateMemberNameInfoEmbed(Context ctx, PKMember target) private async Task<DiscordEmbedBuilder> CreateMemberNameInfoEmbed(Context ctx, PKMember target)
{ {
var lcx = ctx.LookupContextFor(target);
MemberGuildSettings memberGuildConfig = null; MemberGuildSettings memberGuildConfig = null;
if (ctx.Guild != null) if (ctx.Guild != null)
memberGuildConfig = await _db.Execute(c => c.QueryOrInsertMemberGuildConfig(ctx.Guild.Id, target.Id)); memberGuildConfig = await _db.Execute(c => c.QueryOrInsertMemberGuildConfig(ctx.Guild.Id, target.Id));
@ -231,14 +233,17 @@ namespace PluralKit.Bot
.WithFooter($"Member ID: {target.Hid} | Active name in bold. Server name overrides display name, which overrides base name."); .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) if (target.DisplayName == null && memberGuildConfig?.DisplayName == null)
eb.AddField($"Name", $"**{target.Name}**"); eb.AddField("Name", $"**{target.NameFor(ctx)}**");
else else
eb.AddField("Name", target.Name); eb.AddField("Name", target.NameFor(ctx));
if (target.DisplayName != null && memberGuildConfig?.DisplayName == null) if (target.NamePrivacy.CanAccess(lcx))
eb.AddField($"Display Name", $"**{target.DisplayName}**"); {
else if (target.DisplayName != null && memberGuildConfig?.DisplayName == null)
eb.AddField("Display Name", target.DisplayName ?? "*(none)*"); eb.AddField("Display Name", $"**{target.DisplayName}**");
else
eb.AddField("Display Name", target.DisplayName ?? "*(none)*");
}
if (ctx.Guild != null) if (ctx.Guild != null)
{ {
@ -272,7 +277,7 @@ namespace PluralKit.Bot
target.DisplayName = null; target.DisplayName = null;
await _data.SaveMember(target); 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()}\"."); await PrintSuccess($"{Emojis.Success} Member display name cleared. This member will now be proxied using their member name \"{target.NameFor(ctx).SanitizeMentions()}\".");
} }
else if (!ctx.HasNext()) else if (!ctx.HasNext())
{ {
@ -309,7 +314,7 @@ namespace PluralKit.Bot
if (target.DisplayName != null) 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()})."); 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 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()})."); await ctx.Reply($"{Emojis.Success} Member server name cleared. This member will now be proxied using their member name \"{target.NameFor(ctx).SanitizeMentions()}\" in this server ({ctx.Guild.Name.SanitizeMentions()}).");
} }
else if (!ctx.HasNext()) else if (!ctx.HasNext())
{ {
@ -360,7 +365,7 @@ namespace PluralKit.Bot
await ctx.Reply($"{Emojis.Success} Member proxy tags will now not be included in the resulting message when proxying."); await ctx.Reply($"{Emojis.Success} Member proxy tags will now not be included in the resulting message when proxying.");
} }
private DiscordEmbed CreatePrivacyEmbed(PKMember member) private DiscordEmbed CreatePrivacyEmbed(Context ctx, PKMember member)
{ {
string PrivacyLevelString(PrivacyLevel level) => level switch string PrivacyLevelString(PrivacyLevel level) => level switch
{ {
@ -370,7 +375,7 @@ namespace PluralKit.Bot
}; };
var eb = new DiscordEmbedBuilder() var eb = new DiscordEmbedBuilder()
.WithTitle($"Current privacy settings for {member.Name}") .WithTitle($"Current privacy settings for {member.NameFor(ctx)}")
.AddField("Name (replaces name with display name if member has one)",PrivacyLevelString(member.NamePrivacy)) .AddField("Name (replaces name with display name if member has one)",PrivacyLevelString(member.NamePrivacy))
.AddField("Description", PrivacyLevelString(member.DescriptionPrivacy)) .AddField("Description", PrivacyLevelString(member.DescriptionPrivacy))
.AddField("Birthday", PrivacyLevelString(member.BirthdayPrivacy)) .AddField("Birthday", PrivacyLevelString(member.BirthdayPrivacy))
@ -390,7 +395,7 @@ namespace PluralKit.Bot
// Display privacy settings // Display privacy settings
if (!ctx.HasNext() && newValueFromCommand == null) if (!ctx.HasNext() && newValueFromCommand == null)
{ {
await ctx.Reply(embed: CreatePrivacyEmbed(target)); await ctx.Reply(embed: CreatePrivacyEmbed(ctx, target));
return; return;
} }
@ -440,7 +445,7 @@ namespace PluralKit.Bot
(MemberPrivacySubject.Visibility, PrivacyLevel.Public) => "This member is no longer hidden from member lists.", (MemberPrivacySubject.Visibility, PrivacyLevel.Public) => "This member is no longer hidden from member lists.",
}; };
await ctx.Reply($"{Emojis.Success} {target.Name.SanitizeMentions()}'s {subject.Name()} has been set to **{newLevel.Name()}**. {explanation}"); await ctx.Reply($"{Emojis.Success} {target.NameFor(ctx).SanitizeMentions()}'s {subject.Name()} has been set to **{newLevel.Name()}**. {explanation}");
} }
else if (ctx.Match("all") || newValueFromCommand != null) else if (ctx.Match("all") || newValueFromCommand != null)
{ {
@ -449,9 +454,9 @@ namespace PluralKit.Bot
await _data.SaveMember(target); await _data.SaveMember(target);
if(newLevel == PrivacyLevel.Private) if(newLevel == PrivacyLevel.Private)
await ctx.Reply($"All {target.Name.SanitizeMentions()}'s privacy settings have been set to **{newLevel.Name()}**. Other accounts will now see nothing on the member card."); await ctx.Reply($"All {target.NameFor(ctx).SanitizeMentions()}'s privacy settings have been set to **{newLevel.Name()}**. Other accounts will now see nothing on the member card.");
else else
await ctx.Reply($"All {target.Name.SanitizeMentions()}'s privacy settings have been set to **{newLevel.Name()}**. Other accounts will now see everything on the member card."); await ctx.Reply($"All {target.NameFor(ctx).SanitizeMentions()}'s privacy settings have been set to **{newLevel.Name()}**. Other accounts will now see everything on the member card.");
} }
else else
{ {
@ -469,7 +474,7 @@ namespace PluralKit.Bot
if (ctx.System == null) throw Errors.NoSystemError; if (ctx.System == null) throw Errors.NoSystemError;
if (target.System != ctx.System.Id) throw Errors.NotOwnMemberError; if (target.System != ctx.System.Id) throw Errors.NotOwnMemberError;
await ctx.Reply($"{Emojis.Warn} Are you sure you want to delete \"{target.Name.SanitizeMentions()}\"? If so, reply to this message with the member's ID (`{target.Hid}`). __***This cannot be undone!***__"); await ctx.Reply($"{Emojis.Warn} Are you sure you want to delete \"{target.NameFor(ctx).SanitizeMentions()}\"? 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; if (!await ctx.ConfirmWithReply(target.Hid)) throw Errors.MemberDeleteCancelled;
await _data.DeleteMember(target); await _data.DeleteMember(target);
await ctx.Reply($"{Emojis.Success} Member deleted."); await ctx.Reply($"{Emojis.Success} Member deleted.");

View File

@ -36,7 +36,7 @@ namespace PluralKit.Bot
if (conflicts.Count <= 0) return true; if (conflicts.Count <= 0) return true;
var conflictList = conflicts.Select(m => $"- **{m.Name}**"); var conflictList = conflicts.Select(m => $"- **{m.NameFor(ctx)}**");
var msg = await ctx.Reply( var msg = await ctx.Reply(
$"{Emojis.Warn} The following members have conflicting proxy tags:\n{string.Join('\n', conflictList)}\nDo you want to proceed anyway?"); $"{Emojis.Warn} The following members have conflicting proxy tags:\n{string.Join('\n', conflictList)}\nDo you want to proceed anyway?");
return await ctx.PromptYesNo(msg); return await ctx.PromptYesNo(msg);

View File

@ -62,7 +62,7 @@ namespace PluralKit.Bot
var lastSwitchMembers = _data.GetSwitchMembers(lastSwitch); var lastSwitchMembers = _data.GetSwitchMembers(lastSwitch);
// Make sure the requested switch isn't identical to the last one // Make sure the requested switch isn't identical to the last one
if (await lastSwitchMembers.Select(m => m.Id).SequenceEqualAsync(members.Select(m => m.Id).ToAsyncEnumerable())) if (await lastSwitchMembers.Select(m => m.Id).SequenceEqualAsync(members.Select(m => m.Id).ToAsyncEnumerable()))
throw Errors.SameSwitch(members); throw Errors.SameSwitch(members, ctx.LookupContextFor(ctx.System));
} }
await _data.AddSwitch(ctx.System.Id, members); await _data.AddSwitch(ctx.System.Id, members);
@ -70,7 +70,7 @@ namespace PluralKit.Bot
if (members.Count == 0) if (members.Count == 0)
await ctx.Reply($"{Emojis.Success} Switch-out registered."); await ctx.Reply($"{Emojis.Success} Switch-out registered.");
else else
await ctx.Reply($"{Emojis.Success} Switch registered. Current fronter is now {string.Join(", ", members.Select(m => m.Name)).SanitizeMentions()}."); await ctx.Reply($"{Emojis.Success} Switch registered. Current fronter is now {string.Join(", ", members.Select(m => m.NameFor(ctx))).SanitizeMentions()}.");
} }
public async Task SwitchMove(Context ctx) public async Task SwitchMove(Context ctx)
@ -102,7 +102,7 @@ namespace PluralKit.Bot
// Now we can actually do the move, yay! // Now we can actually do the move, yay!
// But, we do a prompt to confirm. // But, we do a prompt to confirm.
var lastSwitchMembers = _data.GetSwitchMembers(lastTwoSwitches[0]); var lastSwitchMembers = _data.GetSwitchMembers(lastTwoSwitches[0]);
var lastSwitchMemberStr = string.Join(", ", await lastSwitchMembers.Select(m => m.Name).ToListAsync()); var lastSwitchMemberStr = string.Join(", ", await lastSwitchMembers.Select(m => m.NameFor(ctx)).ToListAsync());
var lastSwitchTimeStr = DateTimeFormats.ZonedDateTimeFormat.Format(lastTwoSwitches[0].Timestamp.InZone(ctx.System.Zone)); var lastSwitchTimeStr = DateTimeFormats.ZonedDateTimeFormat.Format(lastTwoSwitches[0].Timestamp.InZone(ctx.System.Zone));
var lastSwitchDeltaStr = DateTimeFormats.DurationFormat.Format(SystemClock.Instance.GetCurrentInstant() - lastTwoSwitches[0].Timestamp); var lastSwitchDeltaStr = DateTimeFormats.DurationFormat.Format(SystemClock.Instance.GetCurrentInstant() - lastTwoSwitches[0].Timestamp);
var newSwitchTimeStr = DateTimeFormats.ZonedDateTimeFormat.Format(time); var newSwitchTimeStr = DateTimeFormats.ZonedDateTimeFormat.Format(time);
@ -137,7 +137,7 @@ namespace PluralKit.Bot
if (lastTwoSwitches.Count == 0) throw Errors.NoRegisteredSwitches; if (lastTwoSwitches.Count == 0) throw Errors.NoRegisteredSwitches;
var lastSwitchMembers = _data.GetSwitchMembers(lastTwoSwitches[0]); var lastSwitchMembers = _data.GetSwitchMembers(lastTwoSwitches[0]);
var lastSwitchMemberStr = string.Join(", ", await lastSwitchMembers.Select(m => m.Name).ToListAsync()); var lastSwitchMemberStr = string.Join(", ", await lastSwitchMembers.Select(m => m.NameFor(ctx)).ToListAsync());
var lastSwitchDeltaStr = DateTimeFormats.DurationFormat.Format(SystemClock.Instance.GetCurrentInstant() - lastTwoSwitches[0].Timestamp); var lastSwitchDeltaStr = DateTimeFormats.DurationFormat.Format(SystemClock.Instance.GetCurrentInstant() - lastTwoSwitches[0].Timestamp);
DiscordMessage msg; DiscordMessage msg;
@ -149,7 +149,7 @@ namespace PluralKit.Bot
else else
{ {
var secondSwitchMembers = _data.GetSwitchMembers(lastTwoSwitches[1]); var secondSwitchMembers = _data.GetSwitchMembers(lastTwoSwitches[1]);
var secondSwitchMemberStr = string.Join(", ", await secondSwitchMembers.Select(m => m.Name).ToListAsync()); var secondSwitchMemberStr = string.Join(", ", await secondSwitchMembers.Select(m => m.NameFor(ctx)).ToListAsync());
var secondSwitchDeltaStr = DateTimeFormats.DurationFormat.Format(SystemClock.Instance.GetCurrentInstant() - lastTwoSwitches[1].Timestamp); var secondSwitchDeltaStr = DateTimeFormats.DurationFormat.Format(SystemClock.Instance.GetCurrentInstant() - lastTwoSwitches[1].Timestamp);
msg = await ctx.Reply( msg = await ctx.Reply(
$"{Emojis.Warn} This will delete the latest switch ({lastSwitchMemberStr.SanitizeMentions()}, {lastSwitchDeltaStr} ago). The next latest switch is {secondSwitchMemberStr.SanitizeMentions()} ({secondSwitchDeltaStr} ago). Is this okay?"); $"{Emojis.Warn} This will delete the latest switch ({lastSwitchMemberStr.SanitizeMentions()}, {lastSwitchDeltaStr} ago). The next latest switch is {secondSwitchMemberStr.SanitizeMentions()} ({secondSwitchDeltaStr} ago). Is this okay?");

View File

@ -39,7 +39,7 @@ namespace PluralKit.Bot
var sw = await _data.GetLatestSwitch(system.Id); var sw = await _data.GetLatestSwitch(system.Id);
if (sw == null) throw Errors.NoRegisteredSwitches; if (sw == null) throw Errors.NoRegisteredSwitches;
await ctx.Reply(embed: await _embeds.CreateFronterEmbed(sw, system.Zone)); await ctx.Reply(embed: await _embeds.CreateFronterEmbed(sw, system.Zone, ctx.LookupContextFor(system)));
} }
public async Task SystemFrontHistory(Context ctx, PKSystem system) public async Task SystemFrontHistory(Context ctx, PKSystem system)
@ -68,7 +68,7 @@ namespace PluralKit.Bot
var sw = entry.ThisSwitch; var sw = entry.ThisSwitch;
// Fetch member list and format // Fetch member list and format
var members = await _data.GetSwitchMembers(sw).ToListAsync(); var members = await _data.GetSwitchMembers(sw).ToListAsync();
var membersStr = members.Any() ? string.Join(", ", members.Select(m => m.Name)) : "no fronter"; var membersStr = members.Any() ? string.Join(", ", members.Select(m => m.NameFor(ctx))) : "no fronter";
var switchSince = SystemClock.Instance.GetCurrentInstant() - sw.Timestamp; var switchSince = SystemClock.Instance.GetCurrentInstant() - sw.Timestamp;
@ -113,7 +113,7 @@ namespace PluralKit.Bot
if (rangeStart.Value.ToInstant() > now) throw Errors.FrontPercentTimeInFuture; if (rangeStart.Value.ToInstant() > now) throw Errors.FrontPercentTimeInFuture;
var frontpercent = await _data.GetFrontBreakdown(system, rangeStart.Value.ToInstant(), now); var frontpercent = await _data.GetFrontBreakdown(system, rangeStart.Value.ToInstant(), now);
await ctx.Reply(embed: await _embeds.CreateFrontPercentEmbed(frontpercent, system.Zone)); await ctx.Reply(embed: await _embeds.CreateFrontPercentEmbed(frontpercent, system.Zone, ctx.LookupContextFor(system)));
} }
} }
} }

View File

@ -24,7 +24,7 @@ namespace PluralKit.Bot
var renderer = GetRendererFor(ctx); var renderer = GetRendererFor(ctx);
var opts = GetOptions(ctx, target); var opts = GetOptions(ctx, target);
var members = (await _db.Execute(c => opts.Execute(c, target))).ToList(); var members = (await _db.Execute(c => opts.Execute(c, target, ctx.LookupContextFor(target)))).ToList();
await ctx.Paginate( await ctx.Paginate(
members.ToAsyncEnumerable(), members.ToAsyncEnumerable(),
members.Count, members.Count,

View File

@ -68,11 +68,11 @@ namespace PluralKit.Bot {
public static PKError MemberLinkCancelled => new PKError("Member link cancelled."); public static PKError MemberLinkCancelled => new PKError("Member link cancelled.");
public static PKError MemberUnlinkCancelled => new PKError("Member unlink cancelled."); public static PKError MemberUnlinkCancelled => new PKError("Member unlink cancelled.");
public static PKError SameSwitch(ICollection<PKMember> members) public static PKError SameSwitch(ICollection<PKMember> members, LookupContext ctx)
{ {
if (members.Count == 0) return new PKError("There's already no one in front."); if (members.Count == 0) return new PKError("There's already no one in front.");
if (members.Count == 1) return new PKError($"Member {members.First().Name.SanitizeMentions()} is already fronting."); if (members.Count == 1) return new PKError($"Member {members.First().NameFor(ctx).SanitizeMentions()} is already fronting.");
return new PKError($"Members {string.Join(", ", members.Select(m => m.Name.SanitizeMentions()))} are already fronting."); return new PKError($"Members {string.Join(", ", members.Select(m => m.NameFor(ctx).SanitizeMentions()))} are already fronting.");
} }
public static PKError DuplicateSwitchMembers => new PKError("Duplicate members in member list."); public static PKError DuplicateSwitchMembers => new PKError("Duplicate members in member list.");

View File

@ -105,14 +105,14 @@ namespace PluralKit.Bot
{ {
// If the system has pings enabled, go ahead // If the system has pings enabled, go ahead
var embed = new DiscordEmbedBuilder().WithDescription($"[Jump to pinged message]({evt.Message.JumpLink})"); var embed = new DiscordEmbedBuilder().WithDescription($"[Jump to pinged message]({evt.Message.JumpLink})");
await evt.Channel.SendMessageAsync($"Psst, **{msg.Member.DisplayName ?? msg.Member.Name}** (<@{msg.Message.Sender}>), you have been pinged by <@{evt.User.Id}>.", embed: embed.Build()); await evt.Channel.SendMessageAsync($"Psst, **{msg.Member.DisplayName()}** (<@{msg.Message.Sender}>), you have been pinged by <@{evt.User.Id}>.", embed: embed.Build());
} }
else else
{ {
// If not, tell them in DMs (if we can) // If not, tell them in DMs (if we can)
try try
{ {
await guildUser.SendMessageAsync($"{Emojis.Error} {msg.Member.DisplayName ?? msg.Member.Name}'s system has disabled reaction pings. If you want to mention them anyway, you can copy/paste the following message:"); await guildUser.SendMessageAsync($"{Emojis.Error} {msg.Member.DisplayName()}'s system has disabled reaction pings. If you want to mention them anyway, you can copy/paste the following message:");
await guildUser.SendMessageAsync($"`<@{msg.Message.Sender}>`"); await guildUser.SendMessageAsync($"`<@{msg.Message.Sender}>`");
} }
catch (UnauthorizedException) { } catch (UnauthorizedException) { }

View File

@ -38,8 +38,7 @@ namespace PluralKit.Bot
if (_fields.ShowPrivacy && m.MemberVisibility == PrivacyLevel.Private) if (_fields.ShowPrivacy && m.MemberVisibility == PrivacyLevel.Private)
profile += "\n*(this member is hidden)*"; profile += "\n*(this member is hidden)*";
var memberName = m.NamePrivacy.CanAccess(ctx) ? m.Name : (m.DisplayName ?? m.Name); eb.AddField(m.NameFor(ctx), profile.Truncate(1024));
eb.AddField(memberName, profile.Truncate(1024));
} }
} }

View File

@ -22,11 +22,10 @@ namespace PluralKit.Bot
var proxyTagsString = m.ProxyTagsString().SanitizeMentions(); var proxyTagsString = m.ProxyTagsString().SanitizeMentions();
if (proxyTagsString.Length > 100) // arbitrary threshold for now, tweak? if (proxyTagsString.Length > 100) // arbitrary threshold for now, tweak?
proxyTagsString = "tags too long, see member card"; proxyTagsString = "tags too long, see member card";
var memberName = m.NamePrivacy.CanAccess(ctx) ? m.Name : (m.DisplayName ?? m.Name); return $"[`{m.Hid}`] **{m.NameFor(ctx).SanitizeMentions()}** *({proxyTagsString})*";
return $"[`{m.Hid}`] **{memberName.SanitizeMentions()}** *({proxyTagsString})*";
} }
return $"[`{m.Hid}`] **{m.Name.SanitizeMentions()}**"; return $"[`{m.Hid}`] **{m.NameFor(ctx).SanitizeMentions()}**";
} }
var buf = new StringBuilder(); var buf = new StringBuilder();

View File

@ -52,10 +52,10 @@ namespace PluralKit.Bot
return str.ToString(); return str.ToString();
} }
public async Task<IEnumerable<ListedMember>> Execute(IPKConnection conn, PKSystem system) public async Task<IEnumerable<ListedMember>> Execute(IPKConnection conn, PKSystem system, LookupContext ctx)
{ {
var filtered = await QueryWithFilter(conn, system); var filtered = await QueryWithFilter(conn, system);
return Sort(filtered); return Sort(filtered, ctx);
} }
private Task<IEnumerable<ListedMember>> QueryWithFilter(IPKConnection conn, PKSystem system) => private Task<IEnumerable<ListedMember>> QueryWithFilter(IPKConnection conn, PKSystem system) =>
@ -67,7 +67,7 @@ namespace PluralKit.Bot
_ => throw new ArgumentOutOfRangeException($"Unknown privacy filter {PrivacyFilter}") _ => throw new ArgumentOutOfRangeException($"Unknown privacy filter {PrivacyFilter}")
}, Filter, SearchInDescription); }, Filter, SearchInDescription);
private IEnumerable<ListedMember> Sort(IEnumerable<ListedMember> input) private IEnumerable<ListedMember> Sort(IEnumerable<ListedMember> input, LookupContext ctx)
{ {
IComparer<T> ReverseMaybe<T>(IComparer<T> c) => IComparer<T> ReverseMaybe<T>(IComparer<T> c) =>
Reverse ? Comparer<T>.Create((a, b) => c.Compare(b, a)) : c; Reverse ? Comparer<T>.Create((a, b) => c.Compare(b, a)) : c;
@ -78,7 +78,7 @@ namespace PluralKit.Bot
// As for the OrderByDescending HasValue calls: https://www.jerriepelser.com/blog/orderby-with-null-values/ // As for the OrderByDescending HasValue calls: https://www.jerriepelser.com/blog/orderby-with-null-values/
// We want nulls last no matter what, even if orders are reversed // We want nulls last no matter what, even if orders are reversed
SortProperty.Hid => input.OrderBy(m => m.Hid, ReverseMaybe(culture)), SortProperty.Hid => input.OrderBy(m => m.Hid, ReverseMaybe(culture)),
SortProperty.Name => input.OrderBy(m => m.Name, ReverseMaybe(culture)), SortProperty.Name => input.OrderBy(m => m.NameFor(ctx), ReverseMaybe(culture)),
SortProperty.CreationDate => input.OrderBy(m => m.Created, ReverseMaybe(Comparer<Instant>.Default)), SortProperty.CreationDate => input.OrderBy(m => m.Created, ReverseMaybe(Comparer<Instant>.Default)),
SortProperty.MessageCount => input.OrderByDescending(m => m.MessageCount, ReverseMaybe(Comparer<int>.Default)), SortProperty.MessageCount => input.OrderByDescending(m => m.MessageCount, ReverseMaybe(Comparer<int>.Default)),
SortProperty.DisplayName => input SortProperty.DisplayName => input
@ -96,7 +96,7 @@ namespace PluralKit.Bot
_ => throw new ArgumentOutOfRangeException($"Unknown sort property {SortProperty}") _ => throw new ArgumentOutOfRangeException($"Unknown sort property {SortProperty}")
}) })
// Lastly, add a by-name fallback order for collisions (generally hits w/ lots of null values) // Lastly, add a by-name fallback order for collisions (generally hits w/ lots of null values)
.ThenBy(m => m.Name, culture); .ThenBy(m => m.NameFor(ctx), culture);
} }
public static SortFilterOptions FromFlags(Context ctx) public static SortFilterOptions FromFlags(Context ctx)

View File

@ -47,7 +47,7 @@ namespace PluralKit.Bot {
var switchMembers = await _data.GetSwitchMembers(latestSwitch).ToListAsync(); var switchMembers = await _data.GetSwitchMembers(latestSwitch).ToListAsync();
if (switchMembers.Count > 0) if (switchMembers.Count > 0)
eb.AddField("Fronter".ToQuantity(switchMembers.Count(), ShowQuantityAs.None), eb.AddField("Fronter".ToQuantity(switchMembers.Count(), ShowQuantityAs.None),
string.Join(", ", switchMembers.Select(m => m.Name))); string.Join(", ", switchMembers.Select(m => m.NameFor(ctx))));
} }
if (system.Tag != null) eb.AddField("Tag", system.Tag.EscapeMarkdown()); if (system.Tag != null) eb.AddField("Tag", system.Tag.EscapeMarkdown());
@ -70,7 +70,7 @@ namespace PluralKit.Bot {
public DiscordEmbed CreateLoggedMessageEmbed(PKSystem system, PKMember member, ulong messageId, ulong originalMsgId, DiscordUser sender, string content, DiscordChannel channel) { 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 // TODO: pronouns in ?-reacted response using this card
var timestamp = DiscordUtils.SnowflakeToInstant(messageId); var timestamp = DiscordUtils.SnowflakeToInstant(messageId);
var name = member.NamePrivacy == PrivacyLevel.Public ? member.Name : member.DisplayName ?? member.Name; var name = member.NameFor(LookupContext.ByNonOwner);
return new DiscordEmbedBuilder() return new DiscordEmbedBuilder()
.WithAuthor($"#{channel.Name}: {name}", iconUrl: DiscordUtils.WorkaroundForUrlBug(member.AvatarUrl)) .WithAuthor($"#{channel.Name}: {name}", iconUrl: DiscordUtils.WorkaroundForUrlBug(member.AvatarUrl))
.WithThumbnailUrl(member.AvatarUrl) .WithThumbnailUrl(member.AvatarUrl)
@ -85,8 +85,8 @@ namespace PluralKit.Bot {
// string FormatTimestamp(Instant timestamp) => DateTimeFormats.ZonedDateTimeFormat.Format(timestamp.InZone(system.Zone)); // string FormatTimestamp(Instant timestamp) => DateTimeFormats.ZonedDateTimeFormat.Format(timestamp.InZone(system.Zone));
var name = member.NamePrivacy.CanAccess(ctx) ? member.Name : member.DisplayName ?? member.Name; var name = member.NameFor(ctx);
if (system.Name != null) name = $"{member.Name} ({system.Name})"; if (system.Name != null) name = $"{name} ({system.Name})";
DiscordColor color; DiscordColor color;
try try
@ -142,19 +142,21 @@ namespace PluralKit.Bot {
return eb.Build(); return eb.Build();
} }
public async Task<DiscordEmbed> CreateFronterEmbed(PKSwitch sw, DateTimeZone zone) public async Task<DiscordEmbed> CreateFronterEmbed(PKSwitch sw, DateTimeZone zone, LookupContext ctx)
{ {
var members = await _data.GetSwitchMembers(sw).ToListAsync(); var members = await _data.GetSwitchMembers(sw).ToListAsync();
var timeSinceSwitch = SystemClock.Instance.GetCurrentInstant() - sw.Timestamp; var timeSinceSwitch = SystemClock.Instance.GetCurrentInstant() - sw.Timestamp;
return new DiscordEmbedBuilder() return new DiscordEmbedBuilder()
.WithColor(members.FirstOrDefault()?.Color?.ToDiscordColor() ?? DiscordUtils.Gray) .WithColor(members.FirstOrDefault()?.Color?.ToDiscordColor() ?? DiscordUtils.Gray)
.AddField($"Current {"fronter".ToQuantity(members.Count, ShowQuantityAs.None)}", members.Count > 0 ? string.Join(", ", members.Select(m => m.Name)) : "*(no fronter)*") .AddField($"Current {"fronter".ToQuantity(members.Count, ShowQuantityAs.None)}", members.Count > 0 ? string.Join(", ", members.Select(m => m.NameFor(ctx))) : "*(no fronter)*")
.AddField("Since", $"{DateTimeFormats.ZonedDateTimeFormat.Format(sw.Timestamp.InZone(zone))} ({DateTimeFormats.DurationFormat.Format(timeSinceSwitch)} ago)") .AddField("Since", $"{DateTimeFormats.ZonedDateTimeFormat.Format(sw.Timestamp.InZone(zone))} ({DateTimeFormats.DurationFormat.Format(timeSinceSwitch)} ago)")
.Build(); .Build();
} }
public async Task<DiscordEmbed> CreateMessageInfoEmbed(DiscordClient client, FullMessage msg) public async Task<DiscordEmbed> CreateMessageInfoEmbed(DiscordClient client, FullMessage msg)
{ {
var ctx = LookupContext.ByNonOwner;
var channel = await client.GetChannelAsync(msg.Message.Channel); var channel = await client.GetChannelAsync(msg.Message.Channel);
var serverMsg = channel != null ? await channel.GetMessageAsync(msg.Message.Mid) : null; var serverMsg = channel != null ? await channel.GetMessageAsync(msg.Message.Mid) : null;
@ -177,12 +179,12 @@ namespace PluralKit.Bot {
// Put it all together // Put it all together
var eb = new DiscordEmbedBuilder() var eb = new DiscordEmbedBuilder()
.WithAuthor(msg.Member.Name, iconUrl: DiscordUtils.WorkaroundForUrlBug(msg.Member.AvatarUrl)) .WithAuthor(msg.Member.NameFor(ctx), iconUrl: DiscordUtils.WorkaroundForUrlBug(msg.Member.AvatarUrl))
.WithDescription(serverMsg?.Content?.NormalizeLineEndSpacing() ?? "*(message contents deleted or inaccessible)*") .WithDescription(serverMsg?.Content?.NormalizeLineEndSpacing() ?? "*(message contents deleted or inaccessible)*")
.WithImageUrl(serverMsg?.Attachments?.FirstOrDefault()?.Url) .WithImageUrl(serverMsg?.Attachments?.FirstOrDefault()?.Url)
.AddField("System", .AddField("System",
msg.System.Name != null ? $"{msg.System.Name} (`{msg.System.Hid}`)" : $"`{msg.System.Hid}`", true) msg.System.Name != null ? $"{msg.System.Name} (`{msg.System.Hid}`)" : $"`{msg.System.Hid}`", true)
.AddField("Member", $"{msg.Member.Name} (`{msg.Member.Hid}`)", true) .AddField("Member", $"{msg.Member.NameFor(ctx)} (`{msg.Member.Hid}`)", true)
.AddField("Sent by", userStr, inline: true) .AddField("Sent by", userStr, inline: true)
.WithTimestamp(DiscordUtils.SnowflakeToInstant(msg.Message.Mid).ToDateTimeOffset()); .WithTimestamp(DiscordUtils.SnowflakeToInstant(msg.Message.Mid).ToDateTimeOffset());
@ -193,7 +195,7 @@ namespace PluralKit.Bot {
return eb.Build(); return eb.Build();
} }
public Task<DiscordEmbed> CreateFrontPercentEmbed(FrontBreakdown breakdown, DateTimeZone tz) public Task<DiscordEmbed> CreateFrontPercentEmbed(FrontBreakdown breakdown, DateTimeZone tz, LookupContext ctx)
{ {
var actualPeriod = breakdown.RangeEnd - breakdown.RangeStart; var actualPeriod = breakdown.RangeEnd - breakdown.RangeStart;
var eb = new DiscordEmbedBuilder() var eb = new DiscordEmbedBuilder()
@ -212,7 +214,7 @@ namespace PluralKit.Bot {
foreach (var pair in membersOrdered) foreach (var pair in membersOrdered)
{ {
var frac = pair.Value / actualPeriod; var frac = pair.Value / actualPeriod;
eb.AddField(pair.Key?.Name ?? "*(no fronter)*", $"{frac*100:F0}% ({DateTimeFormats.DurationFormat.Format(pair.Value)})"); eb.AddField(pair.Key?.NameFor(ctx) ?? "*(no fronter)*", $"{frac*100:F0}% ({DateTimeFormats.DurationFormat.Format(pair.Value)})");
} }
if (membersOrdered.Count > maxEntriesToDisplay) if (membersOrdered.Count > maxEntriesToDisplay)

View File

@ -0,0 +1,13 @@
using PluralKit.Core;
namespace PluralKit.Bot
{
public static class ModelUtils
{
public static string NameFor(this PKMember member, Context ctx) =>
member.NameFor(ctx.LookupContextFor(member));
public static string DisplayName(this PKMember member) =>
member.DisplayName ?? member.Name;
}
}

View File

@ -20,5 +20,7 @@
public static bool operator !=(MemberId left, MemberId right) => !left.Equals(right); public static bool operator !=(MemberId left, MemberId right) => !left.Equals(right);
public int CompareTo(MemberId other) => Value.CompareTo(other.Value); public int CompareTo(MemberId other) => Value.CompareTo(other.Value);
public override string ToString() => $"Member #{Value}";
} }
} }

View File

@ -0,0 +1,8 @@
namespace PluralKit.Core
{
public static class ModelExtensions
{
public static string NameFor(this PKMember member, LookupContext ctx) =>
member.NamePrivacy.CanAccess(ctx) ? member.Name : member.DisplayName ?? member.Name;
}
}

View File

@ -20,5 +20,7 @@
public static bool operator !=(SwitchId left, SwitchId right) => !left.Equals(right); public static bool operator !=(SwitchId left, SwitchId right) => !left.Equals(right);
public int CompareTo(SwitchId other) => Value.CompareTo(other.Value); public int CompareTo(SwitchId other) => Value.CompareTo(other.Value);
public override string ToString() => $"Switch #{Value}";
} }
} }

View File

@ -20,5 +20,7 @@
public static bool operator !=(SystemId left, SystemId right) => !left.Equals(right); public static bool operator !=(SystemId left, SystemId right) => !left.Equals(right);
public int CompareTo(SystemId other) => Value.CompareTo(other.Value); public int CompareTo(SystemId other) => Value.CompareTo(other.Value);
public override string ToString() => $"System #{Value}";
} }
} }

View File

@ -137,7 +137,7 @@ namespace PluralKit.Core
// Otherwise, write to importer // Otherwise, write to importer
await importer.StartRowAsync(); await importer.StartRowAsync();
await importer.WriteAsync(_systemId, NpgsqlDbType.Integer); await importer.WriteAsync(_systemId.Value, NpgsqlDbType.Integer);
await importer.WriteAsync(sw.Timestamp, NpgsqlDbType.Timestamp); await importer.WriteAsync(sw.Timestamp, NpgsqlDbType.Timestamp);
// Note that we've imported a switch with this timestamp // Note that we've imported a switch with this timestamp
@ -170,8 +170,8 @@ namespace PluralKit.Core
throw new Exception($"Attempted to import switch with member identifier {memberIdentifier} but could not find an entry in the id map for this! :/"); throw new Exception($"Attempted to import switch with member identifier {memberIdentifier} but could not find an entry in the id map for this! :/");
await importer.StartRowAsync(); await importer.StartRowAsync();
await importer.WriteAsync(justAddedSwitch.Id, NpgsqlDbType.Integer); await importer.WriteAsync(justAddedSwitch.Id.Value, NpgsqlDbType.Integer);
await importer.WriteAsync(memberId, NpgsqlDbType.Integer); await importer.WriteAsync(memberId.Value, NpgsqlDbType.Integer);
} }
} }