Various additional tweaks/additions to groups

This commit is contained in:
Ske 2020-08-20 21:43:17 +02:00
parent 9e251352c7
commit 1bb5d203df
12 changed files with 109 additions and 25 deletions

View File

@ -50,6 +50,7 @@ namespace PluralKit.Bot
public static Command GroupList = new Command("group list", "group list", "Lists all groups in this system"); public static Command GroupList = new Command("group list", "group list", "Lists all groups in this system");
public static Command GroupMemberList = new Command("group members", "group <group> list", "Lists all members in a group"); public static Command GroupMemberList = new Command("group members", "group <group> list", "Lists all members in a group");
public static Command GroupRename = new Command("group rename", "group <group> name <new name>", "Renames a group"); public static Command GroupRename = new Command("group rename", "group <group> name <new name>", "Renames a group");
public static Command GroupDisplayName = new Command("group displayname", "group <member> displayname [display name]", "Changes a group's display name");
public static Command GroupDesc = new Command("group description", "group <group> description [description]", "Changes a group's description"); public static Command GroupDesc = new Command("group description", "group <group> description [description]", "Changes a group's description");
public static Command GroupAdd = new Command("group add", "group <group> add <member> [member 2] [member 3...]", "Adds one or more members to a group"); public static Command GroupAdd = new Command("group add", "group <group> add <member> [member 2] [member 3...]", "Adds one or more members to a group");
public static Command GroupRemove = new Command("group remove", "group <group> remove <member> [member 2] [member 3...]", "Removes one or more members from a group"); public static Command GroupRemove = new Command("group remove", "group <group> remove <member> [member 2] [member 3...]", "Removes one or more members from a group");
@ -355,6 +356,8 @@ namespace PluralKit.Bot
// Commands with group argument // Commands with group argument
if (ctx.Match("rename", "name", "changename", "setname")) if (ctx.Match("rename", "name", "changename", "setname"))
await ctx.Execute<Groups>(GroupRename, g => g.RenameGroup(ctx, target)); await ctx.Execute<Groups>(GroupRename, g => g.RenameGroup(ctx, target));
else if (ctx.Match("dn", "displayname", "nickname"))
await ctx.Execute<Groups>(GroupDisplayName, g => g.GroupDisplayName(ctx, target));
else if (ctx.Match("description", "info", "bio", "text", "desc")) else if (ctx.Match("description", "info", "bio", "text", "desc"))
await ctx.Execute<Groups>(GroupDesc, g => g.GroupDescription(ctx, target)); await ctx.Execute<Groups>(GroupDesc, g => g.GroupDescription(ctx, target));
else if (ctx.Match("add", "a")) else if (ctx.Match("add", "a"))

View File

@ -80,7 +80,43 @@ namespace PluralKit.Bot
await conn.UpdateGroup(target.Id, new GroupPatch {Name = newName}); await conn.UpdateGroup(target.Id, new GroupPatch {Name = newName});
await ctx.Reply($"{Emojis.Success} Group name changed from \"**{target.Name}**\" to \"**{newName}**\"."); await ctx.Reply($"{Emojis.Success} Group name changed from **{target.Name}** to **{newName}**.");
}
public async Task GroupDisplayName(Context ctx, PKGroup target)
{
if (ctx.MatchClear())
{
ctx.CheckOwnGroup(target);
var patch = new GroupPatch {DisplayName = Partial<string>.Null()};
await _db.Execute(conn => conn.UpdateGroup(target.Id, patch));
await ctx.Reply($"{Emojis.Success} Group display name cleared.");
}
else if (!ctx.HasNext())
{
// No perms check, display name isn't covered by member privacy
var eb = new DiscordEmbedBuilder()
.AddField("Name", target.Name)
.AddField("Display Name", target.DisplayName ?? "*(none)*");
if (ctx.System?.Id == target.System)
eb.WithDescription($"To change display name, type `pk;group {GroupReference(target)} displayname <display name>`.\nTo clear it, type `pk;group {GroupReference(target)} displayname -clear`.");
await ctx.Reply(embed: eb.Build());
}
else
{
ctx.CheckOwnGroup(target);
var newDisplayName = ctx.RemainderOrNull();
var patch = new GroupPatch {DisplayName = Partial<string>.Present(newDisplayName)};
await _db.Execute(conn => conn.UpdateGroup(target.Id, patch));
await ctx.Reply($"{Emojis.Success} Group display name changed.");
}
} }
public async Task GroupDescription(Context ctx, PKGroup target) public async Task GroupDescription(Context ctx, PKGroup target)
@ -195,8 +231,7 @@ namespace PluralKit.Bot
system = ctx.System; system = ctx.System;
} }
// should this be split off to a separate permission? ctx.CheckSystemPrivacy(system, system.GroupListPrivacy);
ctx.CheckSystemPrivacy(system, system.MemberListPrivacy);
// TODO: integrate with the normal "search" system // TODO: integrate with the normal "search" system
await using var conn = await _db.Obtain(); await using var conn = await _db.Obtain();
@ -209,8 +244,7 @@ namespace PluralKit.Bot
else else
throw new PKError("You do not have permission to access this information."); throw new PKError("You do not have permission to access this information.");
} }
var groups = (await conn.QueryGroupsInSystem(system.Id)) var groups = (await conn.QueryGroupsInSystem(system.Id))
.Where(g => g.Visibility.CanAccess(pctx)) .Where(g => g.Visibility.CanAccess(pctx))
.ToList(); .ToList();
@ -218,9 +252,10 @@ namespace PluralKit.Bot
if (groups.Count == 0) if (groups.Count == 0)
{ {
if (system.Id == ctx.System?.Id) if (system.Id == ctx.System?.Id)
await ctx.Reply($"This system has no groups. To create one, use the command `pk;group new <name>`."); await ctx.Reply("This system has no groups. To create one, use the command `pk;group new <name>`.");
else else
await ctx.Reply($"This system has no groups."); await ctx.Reply("This system has no groups.");
return; return;
} }
@ -229,7 +264,13 @@ namespace PluralKit.Bot
Task Renderer(DiscordEmbedBuilder eb, IEnumerable<PKGroup> page) Task Renderer(DiscordEmbedBuilder eb, IEnumerable<PKGroup> page)
{ {
eb.WithSimpleLineContent(page.Select(g => $"[`{g.Hid}`] **{g.Name}**")); eb.WithSimpleLineContent(page.Select(g =>
{
if (g.DisplayName != null)
return $"[`{g.Hid}`] **{g.Name}** ({g.DisplayName})";
else
return $"[`{g.Hid}`] **{g.Name}**";
}));
eb.WithFooter($"{groups.Count} total."); eb.WithFooter($"{groups.Count} total.");
return Task.CompletedTask; return Task.CompletedTask;
} }
@ -251,10 +292,17 @@ namespace PluralKit.Bot
.WithAuthor(nameField, iconUrl: DiscordUtils.WorkaroundForUrlBug(target.IconFor(pctx))) .WithAuthor(nameField, iconUrl: DiscordUtils.WorkaroundForUrlBug(target.IconFor(pctx)))
.WithFooter($"System ID: {system.Hid} | Group ID: {target.Hid} | Created on {target.Created.FormatZoned(system)}"); .WithFooter($"System ID: {system.Hid} | Group ID: {target.Hid} | Created on {target.Created.FormatZoned(system)}");
if (memberCount == 0) if (target.DisplayName != null)
eb.AddField("Members (0)", $"Add one with `pk;group {GroupReference(target)} add <member>`!", true); eb.AddField("Display Name", target.DisplayName);
else
eb.AddField($"Members ({memberCount})", $"(see `pk;group {GroupReference(target)} list`)", true); if (target.ListPrivacy.CanAccess(pctx))
{
if (memberCount == 0 && pctx == LookupContext.ByOwner)
// Only suggest the add command if this is actually the owner lol
eb.AddField("Members (0)", $"Add one with `pk;group {GroupReference(target)} add <member>`!", true);
else
eb.AddField($"Members ({memberCount})", $"(see `pk;group {GroupReference(target)} list`)", true);
}
if (target.DescriptionFor(pctx) is {} desc) if (target.DescriptionFor(pctx) is {} desc)
eb.AddField("Description", desc); eb.AddField("Description", desc);
@ -275,14 +323,15 @@ namespace PluralKit.Bot
var existingMembersInGroup = (await conn.QueryMemberList(target.System, var existingMembersInGroup = (await conn.QueryMemberList(target.System,
new DatabaseViewsExt.MemberListQueryOptions {GroupFilter = target.Id})) new DatabaseViewsExt.MemberListQueryOptions {GroupFilter = target.Id}))
.Select(m => m.Id) .Select(m => m.Id.Value)
.ToHashSet(); .ToHashSet();
if (op == AddRemoveOperation.Add) if (op == AddRemoveOperation.Add)
{ {
var membersNotInGroup = members var membersNotInGroup = members
.Where(m => !existingMembersInGroup.Contains(m.Id)) .Where(m => !existingMembersInGroup.Contains(m.Id.Value))
.Select(m => m.Id) .Select(m => m.Id)
.Distinct()
.ToList(); .ToList();
await conn.AddMembersToGroup(target.Id, membersNotInGroup); await conn.AddMembersToGroup(target.Id, membersNotInGroup);
@ -294,8 +343,9 @@ namespace PluralKit.Bot
else if (op == AddRemoveOperation.Remove) else if (op == AddRemoveOperation.Remove)
{ {
var membersInGroup = members var membersInGroup = members
.Where(m => existingMembersInGroup.Contains(m.Id)) .Where(m => existingMembersInGroup.Contains(m.Id.Value))
.Select(m => m.Id) .Select(m => m.Id)
.Distinct()
.ToList(); .ToList();
await conn.RemoveMembersFromGroup(target.Id, membersInGroup); await conn.RemoveMembersFromGroup(target.Id, membersInGroup);
@ -311,12 +361,12 @@ namespace PluralKit.Bot
await using var conn = await _db.Obtain(); await using var conn = await _db.Obtain();
var targetSystem = await GetGroupSystem(ctx, target, conn); var targetSystem = await GetGroupSystem(ctx, target, conn);
ctx.CheckSystemPrivacy(targetSystem, target.Visibility); ctx.CheckSystemPrivacy(targetSystem, target.ListPrivacy);
var opts = ctx.ParseMemberListOptions(ctx.LookupContextFor(target.System)); var opts = ctx.ParseMemberListOptions(ctx.LookupContextFor(target.System));
opts.GroupFilter = target.Id; opts.GroupFilter = target.Id;
var title = new StringBuilder($"Members of {target.Name} (`{target.Hid}`) in "); var title = new StringBuilder($"Members of {target.DisplayName ?? target.Name} (`{target.Hid}`) in ");
if (targetSystem.Name != null) if (targetSystem.Name != null)
title.Append($"{targetSystem.Name} (`{targetSystem.Hid}`)"); title.Append($"{targetSystem.Name} (`{targetSystem.Hid}`)");
else else
@ -363,8 +413,9 @@ namespace PluralKit.Bot
.WithTitle($"Current privacy settings for {target.Name}") .WithTitle($"Current privacy settings for {target.Name}")
.AddField("Description", target.DescriptionPrivacy.Explanation()) .AddField("Description", target.DescriptionPrivacy.Explanation())
.AddField("Icon", target.IconPrivacy.Explanation()) .AddField("Icon", target.IconPrivacy.Explanation())
.AddField("Member list", target.ListPrivacy.Explanation())
.AddField("Visibility", target.Visibility.Explanation()) .AddField("Visibility", target.Visibility.Explanation())
.WithDescription($"To edit privacy settings, use the command:\n> pk;group **{GroupReference(target)}** privacy **<subject>** **<level>**\n\n- `subject` is one of `description`, `icon`, `visibility`, or `all`\n- `level` is either `public` or `private`.") .WithDescription($"To edit privacy settings, use the command:\n> pk;group **{GroupReference(target)}** privacy **<subject>** **<level>**\n\n- `subject` is one of `description`, `icon`, `members`, `visibility`, or `all`\n- `level` is either `public` or `private`.")
.Build()); .Build());
return; return;
} }
@ -387,6 +438,7 @@ namespace PluralKit.Bot
{ {
GroupPrivacySubject.Description => "description privacy", GroupPrivacySubject.Description => "description privacy",
GroupPrivacySubject.Icon => "icon privacy", GroupPrivacySubject.Icon => "icon privacy",
GroupPrivacySubject.List => "member list",
GroupPrivacySubject.Visibility => "visibility", GroupPrivacySubject.Visibility => "visibility",
_ => throw new ArgumentOutOfRangeException($"Unknown privacy subject {subject}") _ => throw new ArgumentOutOfRangeException($"Unknown privacy subject {subject}")
}; };
@ -396,10 +448,12 @@ namespace PluralKit.Bot
(GroupPrivacySubject.Description, PrivacyLevel.Private) => "This group's description is now hidden from other systems.", (GroupPrivacySubject.Description, PrivacyLevel.Private) => "This group's description is now hidden from other systems.",
(GroupPrivacySubject.Icon, PrivacyLevel.Private) => "This group's icon is now hidden from other systems.", (GroupPrivacySubject.Icon, PrivacyLevel.Private) => "This group's icon is now hidden from other systems.",
(GroupPrivacySubject.Visibility, PrivacyLevel.Private) => "This group is now hidden from group lists and member cards.", (GroupPrivacySubject.Visibility, PrivacyLevel.Private) => "This group is now hidden from group lists and member cards.",
(GroupPrivacySubject.List, PrivacyLevel.Private) => "This group's member list is now hidden from other systems.",
(GroupPrivacySubject.Description, PrivacyLevel.Public) => "This group's description is no longer hidden from other systems.", (GroupPrivacySubject.Description, PrivacyLevel.Public) => "This group's description is no longer hidden from other systems.",
(GroupPrivacySubject.Icon, PrivacyLevel.Public) => "This group's icon is no longer hidden from other systems.", (GroupPrivacySubject.Icon, PrivacyLevel.Public) => "This group's icon is no longer hidden from other systems.",
(GroupPrivacySubject.Visibility, PrivacyLevel.Public) => "This group is no longer hidden from group lists and member cards.", (GroupPrivacySubject.Visibility, PrivacyLevel.Public) => "This group is no longer hidden from group lists and member cards.",
(GroupPrivacySubject.List, PrivacyLevel.Public) => "This group's member list is no longer hidden from other systems.",
_ => throw new InvalidOperationException($"Invalid subject/level tuple ({subject}, {level})") _ => throw new InvalidOperationException($"Invalid subject/level tuple ({subject}, {level})")
}; };

View File

@ -268,9 +268,10 @@ namespace PluralKit.Bot
.WithTitle("Current privacy settings for your system") .WithTitle("Current privacy settings for your system")
.AddField("Description", ctx.System.DescriptionPrivacy.Explanation()) .AddField("Description", ctx.System.DescriptionPrivacy.Explanation())
.AddField("Member list", ctx.System.MemberListPrivacy.Explanation()) .AddField("Member list", ctx.System.MemberListPrivacy.Explanation())
.AddField("Group list", ctx.System.GroupListPrivacy.Explanation())
.AddField("Current fronter(s)", ctx.System.FrontPrivacy.Explanation()) .AddField("Current fronter(s)", ctx.System.FrontPrivacy.Explanation())
.AddField("Front/switch history", ctx.System.FrontHistoryPrivacy.Explanation()) .AddField("Front/switch history", ctx.System.FrontHistoryPrivacy.Explanation())
.WithDescription("To edit privacy settings, use the command:\n`pk;system privacy <subject> <level>`\n\n- `subject` is one of `description`, `list`, `front`, `fronthistory`, or `all` \n- `level` is either `public` or `private`."); .WithDescription("To edit privacy settings, use the command:\n`pk;system privacy <subject> <level>`\n\n- `subject` is one of `description`, `list`, `front`, `fronthistory`, `groups`, or `all` \n- `level` is either `public` or `private`.");
return ctx.Reply(embed: eb.Build()); return ctx.Reply(embed: eb.Build());
} }
@ -291,6 +292,7 @@ namespace PluralKit.Bot
SystemPrivacySubject.Front => "front", SystemPrivacySubject.Front => "front",
SystemPrivacySubject.FrontHistory => "front history", SystemPrivacySubject.FrontHistory => "front history",
SystemPrivacySubject.MemberList => "member list", SystemPrivacySubject.MemberList => "member list",
SystemPrivacySubject.GroupList => "group list",
_ => "" _ => ""
}; };
@ -304,7 +306,7 @@ namespace PluralKit.Bot
var msg = level switch var msg = level switch
{ {
PrivacyLevel.Private => $"All system privacy settings have been set to **{level.LevelName()}**. Other accounts will now not be able to view your member list, front history, or system description.", PrivacyLevel.Private => $"All system privacy settings have been set to **{level.LevelName()}**. Other accounts will now not be able to view your member list, group list, front history, or system description.",
PrivacyLevel.Public => $"All system privacy settings have been set to **{level.LevelName()}**. Other accounts will now be able to view everything.", PrivacyLevel.Public => $"All system privacy settings have been set to **{level.LevelName()}**. Other accounts will now be able to view everything.",
_ => "" _ => ""
}; };

View File

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

View File

@ -7,12 +7,14 @@ create table groups (
system int not null references systems(id) on delete cascade, system int not null references systems(id) on delete cascade,
name text not null, name text not null,
display_name text,
description text, description text,
icon text, icon text,
-- Description columns follow the same pattern as usual: 1 = public, 2 = private -- Description columns follow the same pattern as usual: 1 = public, 2 = private
description_privacy integer check (description_privacy in (1, 2)) not null default 1, description_privacy integer check (description_privacy in (1, 2)) not null default 1,
icon_privacy integer check (icon_privacy in (1, 2)) not null default 1, icon_privacy integer check (icon_privacy in (1, 2)) not null default 1,
list_privacy integer check (list_privacy in (1, 2)) not null default 1,
visibility integer check (visibility in (1, 2)) not null default 1, visibility integer check (visibility in (1, 2)) not null default 1,
created timestamp with time zone not null default (current_timestamp at time zone 'utc') created timestamp with time zone not null default (current_timestamp at time zone 'utc')
@ -24,4 +26,6 @@ create table group_members (
primary key (group_id, member_id) primary key (group_id, member_id)
); );
alter table systems add column group_list_privacy integer check (group_list_privacy in (1, 2)) not null default systems.member_list_privacy;
update info set schema_version = 9; update info set schema_version = 9;

View File

@ -10,11 +10,13 @@ namespace PluralKit.Core
public SystemId System { get; } public SystemId System { get; }
public string Name { get; } = null!; public string Name { get; } = null!;
public string? DisplayName { get; }
public string? Description { get; } public string? Description { get; }
public string? Icon { get; } public string? Icon { get; }
public PrivacyLevel DescriptionPrivacy { get; } public PrivacyLevel DescriptionPrivacy { get; }
public PrivacyLevel IconPrivacy { get; } public PrivacyLevel IconPrivacy { get; }
public PrivacyLevel ListPrivacy { get; }
public PrivacyLevel Visibility { get; } public PrivacyLevel Visibility { get; }
public Instant Created { get; } public Instant Created { get; }

View File

@ -22,6 +22,7 @@ namespace PluralKit.Core {
public PrivacyLevel MemberListPrivacy { get;} public PrivacyLevel MemberListPrivacy { get;}
public PrivacyLevel FrontPrivacy { get; } public PrivacyLevel FrontPrivacy { get; }
public PrivacyLevel FrontHistoryPrivacy { get; } public PrivacyLevel FrontHistoryPrivacy { get; }
public PrivacyLevel GroupListPrivacy { get; }
[JsonIgnore] public DateTimeZone Zone => DateTimeZoneProviders.Tzdb.GetZoneOrNull(UiTz); [JsonIgnore] public DateTimeZone Zone => DateTimeZoneProviders.Tzdb.GetZoneOrNull(UiTz);
} }

View File

@ -4,19 +4,23 @@ namespace PluralKit.Core
public class GroupPatch: PatchObject public class GroupPatch: PatchObject
{ {
public Partial<string> Name { get; set; } public Partial<string> Name { get; set; }
public Partial<string?> DisplayName { get; set; }
public Partial<string?> Description { get; set; } public Partial<string?> Description { get; set; }
public Partial<string?> Icon { get; set; } public Partial<string?> Icon { get; set; }
public Partial<PrivacyLevel> DescriptionPrivacy { get; set; } public Partial<PrivacyLevel> DescriptionPrivacy { get; set; }
public Partial<PrivacyLevel> IconPrivacy { get; set; } public Partial<PrivacyLevel> IconPrivacy { get; set; }
public Partial<PrivacyLevel> ListPrivacy { get; set; }
public Partial<PrivacyLevel> Visibility { get; set; } public Partial<PrivacyLevel> Visibility { get; set; }
public override UpdateQueryBuilder Apply(UpdateQueryBuilder b) => b public override UpdateQueryBuilder Apply(UpdateQueryBuilder b) => b
.With("name", Name) .With("name", Name)
.With("display_name", DisplayName)
.With("description", Description) .With("description", Description)
.With("icon", Icon) .With("icon", Icon)
.With("description_privacy", DescriptionPrivacy) .With("description_privacy", DescriptionPrivacy)
.With("icon_privacy", IconPrivacy) .With("icon_privacy", IconPrivacy)
.With("list_privacy", ListPrivacy)
.With("visibility", Visibility); .With("visibility", Visibility);
} }
} }

View File

@ -11,6 +11,7 @@ namespace PluralKit.Core
public Partial<string> UiTz { get; set; } public Partial<string> UiTz { get; set; }
public Partial<PrivacyLevel> DescriptionPrivacy { get; set; } public Partial<PrivacyLevel> DescriptionPrivacy { get; set; }
public Partial<PrivacyLevel> MemberListPrivacy { get; set; } public Partial<PrivacyLevel> MemberListPrivacy { get; set; }
public Partial<PrivacyLevel> GroupListPrivacy { get; set; }
public Partial<PrivacyLevel> FrontPrivacy { get; set; } public Partial<PrivacyLevel> FrontPrivacy { get; set; }
public Partial<PrivacyLevel> FrontHistoryPrivacy { get; set; } public Partial<PrivacyLevel> FrontHistoryPrivacy { get; set; }
public Partial<bool> PingsEnabled { get; set; } public Partial<bool> PingsEnabled { get; set; }
@ -24,6 +25,7 @@ namespace PluralKit.Core
.With("ui_tz", UiTz) .With("ui_tz", UiTz)
.With("description_privacy", DescriptionPrivacy) .With("description_privacy", DescriptionPrivacy)
.With("member_list_privacy", MemberListPrivacy) .With("member_list_privacy", MemberListPrivacy)
.With("group_list_privacy", GroupListPrivacy)
.With("front_privacy", FrontPrivacy) .With("front_privacy", FrontPrivacy)
.With("front_history_privacy", FrontHistoryPrivacy) .With("front_history_privacy", FrontHistoryPrivacy)
.With("pings_enabled", PingsEnabled); .With("pings_enabled", PingsEnabled);

View File

@ -6,6 +6,7 @@ namespace PluralKit.Core
{ {
Description, Description,
Icon, Icon,
List,
Visibility Visibility
} }
@ -18,6 +19,7 @@ namespace PluralKit.Core
{ {
GroupPrivacySubject.Description => group.DescriptionPrivacy = level, GroupPrivacySubject.Description => group.DescriptionPrivacy = level,
GroupPrivacySubject.Icon => group.IconPrivacy = level, GroupPrivacySubject.Icon => group.IconPrivacy = level,
GroupPrivacySubject.List => group.ListPrivacy = level,
GroupPrivacySubject.Visibility => group.Visibility = level, GroupPrivacySubject.Visibility => group.Visibility = level,
_ => throw new ArgumentOutOfRangeException($"Unknown privacy subject {subject}") _ => throw new ArgumentOutOfRangeException($"Unknown privacy subject {subject}")
}; };
@ -52,9 +54,13 @@ namespace PluralKit.Core
case "hidden": case "hidden":
case "shown": case "shown":
case "visible": case "visible":
case "list":
subject = GroupPrivacySubject.Visibility; subject = GroupPrivacySubject.Visibility;
break; break;
case "list":
case "listing":
case "members":
subject = GroupPrivacySubject.List;
break;
default: default:
subject = default; subject = default;
return false; return false;

View File

@ -16,8 +16,8 @@ namespace PluralKit.Core
public static string Explanation(this PrivacyLevel level) => public static string Explanation(this PrivacyLevel level) =>
level switch level switch
{ {
PrivacyLevel.Private => "**Private** (visible only when queried by you)", PrivacyLevel.Private => "Private *(visible only when queried by you)*",
PrivacyLevel.Public => "**Public** (visible to everyone)", PrivacyLevel.Public => "Public *(visible to everyone)*",
_ => throw new ArgumentOutOfRangeException(nameof(level), level, null) _ => throw new ArgumentOutOfRangeException(nameof(level), level, null)
}; };

View File

@ -6,6 +6,7 @@ namespace PluralKit.Core
{ {
Description, Description,
MemberList, MemberList,
GroupList,
Front, Front,
FrontHistory FrontHistory
} }
@ -21,6 +22,7 @@ namespace PluralKit.Core
SystemPrivacySubject.Front => system.FrontPrivacy = level, SystemPrivacySubject.Front => system.FrontPrivacy = level,
SystemPrivacySubject.FrontHistory => system.FrontHistoryPrivacy = level, SystemPrivacySubject.FrontHistory => system.FrontHistoryPrivacy = level,
SystemPrivacySubject.MemberList => system.MemberListPrivacy = level, SystemPrivacySubject.MemberList => system.MemberListPrivacy = level,
SystemPrivacySubject.GroupList => system.GroupListPrivacy = level,
_ => throw new ArgumentOutOfRangeException($"Unknown privacy subject {subject}") _ => throw new ArgumentOutOfRangeException($"Unknown privacy subject {subject}")
}; };
@ -61,6 +63,10 @@ namespace PluralKit.Core
case "fh": case "fh":
subject = SystemPrivacySubject.FrontHistory; subject = SystemPrivacySubject.FrontHistory;
break; break;
case "groups":
case "gs":
subject = SystemPrivacySubject.GroupList;
break;
default: default:
subject = default; subject = default;
return false; return false;