Feature/granular member privacy (#174)
* Some reasons this needs to exist for it to run on my machine? I don't think it would hurt to have it in other machines so * Add options to member model * Add Privacy to member embed * Added member privacy display list * Update database settings * apparetnly this is nolonger needed? * Fix sql call * Fix more sql errors * Added in settings control * Add all subject to system privacy * Basic API Privacy * Name privacy in logs * update todo * remove CheckReadMemberPermission * Added name privacy to log embed * update todo * Update todo * Update api to handle privacy * update todo * Update systemlist full to respect privacy (as well as system list) * include colour as option for member privacy subject * move todo file (why was it there?) * Update TODO.md * Update TODO.md * Update TODO.md * Deleted to create pr * Update command usage and add to the command tree * Make api respect created privacy * Add editing privacy through the api * Fix pronoun privacy field in api * Fix info leak of display name in api * deprecate privacy field in api * Deprecate privacy diffrently * Update API * Update documentation * Update documentation * Remove comment in yml * Update userguide * Update migration (fix typo in 5.sql too) * Sanatize names * some full stops * Fix after merge * update migration * update schema version * update edit command * update privacy filter * fix a dumb mistake * clarify on what name privacy does * make it easier on someone else * Update docs * Comment out unused code * Add aliases for `member privacy all public` and `member privacy all private`
This commit is contained in:
@@ -24,8 +24,8 @@ namespace PluralKit.Bot
|
||||
public static Command SystemFronter = new Command("system fronter", "system [system] fronter", "Shows a system's fronter(s)");
|
||||
public static Command SystemFrontHistory = new Command("system fronthistory", "system [system] fronthistory", "Shows a system's front history");
|
||||
public static Command SystemFrontPercent = new Command("system frontpercent", "system [system] frontpercent [timespan]", "Shows a system's front breakdown");
|
||||
public static Command SystemPrivacy = new Command("system privacy", "system privacy <description|members|fronter|fronthistory> <public|private>", "Changes your system's privacy settings");
|
||||
public static Command SystemPing = new Command("system ping", "system ping <enable|disable>", "Changes your system's ping preferences");
|
||||
public static Command SystemPrivacy = new Command("system privacy", "system privacy <description|members|fronter|fronthistory|all> <public|private>", "Changes your system's privacy settings");
|
||||
public static Command Autoproxy = new Command("autoproxy", "autoproxy [off|front|latch|member]", "Sets your system's autoproxy mode for this server");
|
||||
public static Command MemberInfo = new Command("member", "member <member>", "Looks up information about a member");
|
||||
public static Command MemberNew = new Command("member new", "member new <name>", "Creates a new member");
|
||||
@@ -42,7 +42,7 @@ namespace PluralKit.Bot
|
||||
public static Command MemberServerName = new Command("member servername", "member <member> servername [server name]", "Changes a member's display name in the current server");
|
||||
public static Command MemberKeepProxy = new Command("member keepproxy", "member <member> keepproxy [on|off]", "Sets whether to include a member's proxy tags when proxying");
|
||||
public static Command MemberRandom = new Command("random", "random", "Looks up a random member from your system");
|
||||
public static Command MemberPrivacy = new Command("member privacy", "member <member> privacy [on|off]", "Sets whether a member is private or public");
|
||||
public static Command MemberPrivacy = new Command("member privacy", "member <member> privacy <name|description|birthday|pronouns|color|metadata|visibility|all> <public|private>", "Changes a members's privacy settings");
|
||||
public static Command Switch = new Command("switch", "switch <member> [member 2] [member 3...]", "Registers a switch");
|
||||
public static Command SwitchOut = new Command("switch out", "switch out", "Registers a switch with no members");
|
||||
public static Command SwitchMove = new Command("switch move", "switch move <date/time>", "Moves the latest switch in time");
|
||||
@@ -72,7 +72,7 @@ namespace PluralKit.Bot
|
||||
|
||||
public static Command[] MemberCommands = {
|
||||
MemberInfo, MemberNew, MemberRename, MemberDisplayName, MemberServerName, MemberDesc, MemberPronouns,
|
||||
MemberColor, MemberBirthday, MemberProxy, MemberKeepProxy, MemberDelete, MemberAvatar, MemberServerAvatar,
|
||||
MemberColor, MemberBirthday, MemberProxy, MemberKeepProxy, MemberDelete, MemberAvatar, MemberServerAvatar, MemberPrivacy,
|
||||
MemberRandom
|
||||
};
|
||||
|
||||
@@ -297,9 +297,9 @@ namespace PluralKit.Bot
|
||||
await ctx.Execute<MemberEdit>(MemberKeepProxy, m => m.KeepProxy(ctx, target));
|
||||
else if (ctx.Match("privacy"))
|
||||
await ctx.Execute<MemberEdit>(MemberPrivacy, m => m.Privacy(ctx, target, null));
|
||||
else if (ctx.Match("private", "hidden"))
|
||||
else if (ctx.Match("private", "hidden", "hide"))
|
||||
await ctx.Execute<MemberEdit>(MemberPrivacy, m => m.Privacy(ctx, target, PrivacyLevel.Private));
|
||||
else if (ctx.Match("public", "shown"))
|
||||
else if (ctx.Match("public", "shown", "show"))
|
||||
await ctx.Execute<MemberEdit>(MemberPrivacy, m => m.Privacy(ctx, target, PrivacyLevel.Public));
|
||||
else if (!ctx.HasNext()) // Bare command
|
||||
await ctx.Execute<Member>(MemberInfo, m => m.ViewMember(ctx, target));
|
||||
|
@@ -59,7 +59,7 @@ namespace PluralKit.Bot
|
||||
//Maybe move this somewhere else in the file structure since it doesn't need to get created at every command
|
||||
|
||||
// TODO: don't buffer these, find something else to do ig
|
||||
var members = await _data.GetSystemMembers(ctx.System).Where(m => m.MemberPrivacy == PrivacyLevel.Public).ToListAsync();
|
||||
var members = await _data.GetSystemMembers(ctx.System).Where(m => m.MemberVisibility == PrivacyLevel.Public).ToListAsync();
|
||||
if (members == null || !members.Any())
|
||||
throw Errors.NoMembersError;
|
||||
var randInt = randGen.Next(members.Count);
|
||||
|
@@ -1,5 +1,7 @@
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using System;
|
||||
|
||||
|
||||
using Dapper;
|
||||
|
||||
@@ -53,12 +55,6 @@ namespace PluralKit.Bot
|
||||
}
|
||||
}
|
||||
|
||||
private void CheckReadMemberPermission(Context ctx, PKMember target)
|
||||
{
|
||||
if (!target.MemberPrivacy.CanAccess(ctx.LookupContextFor(target.System)))
|
||||
throw Errors.LookupNotAllowed;
|
||||
}
|
||||
|
||||
private void CheckEditMemberPermission(Context ctx, PKMember target)
|
||||
{
|
||||
if (target.System != ctx.System?.Id) throw Errors.NotOwnMemberError;
|
||||
@@ -78,7 +74,8 @@ namespace PluralKit.Bot
|
||||
}
|
||||
else if (!ctx.HasNext())
|
||||
{
|
||||
CheckReadMemberPermission(ctx, target);
|
||||
if (!target.DescriptionPrivacy.CanAccess(ctx.LookupContextFor(target.System)))
|
||||
throw Errors.LookupNotAllowed;
|
||||
if (target.Description == null)
|
||||
if (ctx.System?.Id == target.System)
|
||||
await ctx.Reply($"This member does not have a description set. To set one, type `pk;member {target.Hid} description <description>`.");
|
||||
@@ -119,7 +116,8 @@ namespace PluralKit.Bot
|
||||
}
|
||||
else if (!ctx.HasNext())
|
||||
{
|
||||
CheckReadMemberPermission(ctx, target);
|
||||
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>`.");
|
||||
@@ -155,7 +153,8 @@ namespace PluralKit.Bot
|
||||
}
|
||||
else if (!ctx.HasNext())
|
||||
{
|
||||
CheckReadMemberPermission(ctx, target);
|
||||
if (!target.ColorPrivacy.CanAccess(ctx.LookupContextFor(target.System)))
|
||||
throw Errors.LookupNotAllowed;
|
||||
|
||||
if (target.Color == null)
|
||||
if (ctx.System?.Id == target.System)
|
||||
@@ -199,7 +198,8 @@ namespace PluralKit.Bot
|
||||
}
|
||||
else if (!ctx.HasNext())
|
||||
{
|
||||
CheckReadMemberPermission(ctx, target);
|
||||
if (!target.BirthdayPrivacy.CanAccess(ctx.LookupContextFor(target.System)))
|
||||
throw Errors.LookupNotAllowed;
|
||||
|
||||
if (target.Birthday == null)
|
||||
await ctx.Reply("This member does not have a birthdate set."
|
||||
@@ -365,29 +365,137 @@ namespace PluralKit.Bot
|
||||
if (ctx.System == null) throw Errors.NoSystemError;
|
||||
if (target.System != ctx.System.Id) throw Errors.NotOwnMemberError;
|
||||
|
||||
PrivacyLevel newValue;
|
||||
if (ctx.Match("private", "hide", "hidden", "on", "enable", "yes")) newValue = PrivacyLevel.Private;
|
||||
else if (ctx.Match("public", "show", "shown", "displayed", "off", "disable", "no")) newValue = PrivacyLevel.Public;
|
||||
else if (ctx.HasNext()) throw new PKSyntaxError("You must pass either \"private\" or \"public\".");
|
||||
// If we're getting a value from command (eg. "pk;m <name> private" == always private, "pk;m <name> public == always public"), use that instead of parsing
|
||||
else if (newValueFromCommand != null) newValue = newValueFromCommand.Value;
|
||||
else
|
||||
// Display privacy settings
|
||||
if (!ctx.HasNext() && newValueFromCommand == null)
|
||||
{
|
||||
if (target.MemberPrivacy == PrivacyLevel.Public)
|
||||
await ctx.Reply("This member's privacy is currently set to **public**. This member will show up in member lists and will return all information when queried by other accounts.");
|
||||
else
|
||||
await ctx.Reply("This member's privacy is currently set to **private**. This member will not show up in member lists and will return limited information when queried by other accounts.");
|
||||
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 {target.Name}")
|
||||
.AddField("Name (replaces name with display name if member has one)",PrivacyLevelString(target.NamePrivacy))
|
||||
.AddField("Description", PrivacyLevelString(target.DescriptionPrivacy))
|
||||
.AddField("Birthday", PrivacyLevelString(target.BirthdayPrivacy))
|
||||
.AddField("Pronouns", PrivacyLevelString(target.PronounPrivacy))
|
||||
.AddField("Color", PrivacyLevelString(target.ColorPrivacy))
|
||||
.AddField("Meta (message count, last front, last message)", PrivacyLevelString(target.MetadataPrivacy))
|
||||
.AddField("Visibility", PrivacyLevelString(target.MemberVisibility))
|
||||
.WithDescription("To edit privacy settings, use the command:\n`pk;member <member> privacy <subject> <level>`\n\n- `subject` is one of `name`, `description`, `birthday`, `pronouns`, `color`, `created`, `messages`, `visibility`, or `all`\n- `level` is either `public` or `private`.");
|
||||
await ctx.Reply(embed: eb.Build());
|
||||
return;
|
||||
}
|
||||
|
||||
target.MemberPrivacy = newValue;
|
||||
await _data.SaveMember(target);
|
||||
// Set Privacy Settings
|
||||
PrivacyLevel PopPrivacyLevel(string subject, out string levelStr, out string levelExplanation)
|
||||
{
|
||||
if (ctx.Match("public", "show", "shown", "visible"))
|
||||
{
|
||||
levelStr = "public";
|
||||
levelExplanation = "be shown on the member card";
|
||||
return PrivacyLevel.Public;
|
||||
}
|
||||
|
||||
if (newValue == PrivacyLevel.Private)
|
||||
await ctx.Reply($"{Emojis.Success} Member privacy set to **private**. This member will no longer show up in member lists and will return limited information when queried by other accounts.");
|
||||
if (ctx.Match("private", "hide", "hidden"))
|
||||
{
|
||||
levelStr = "private";
|
||||
levelExplanation = "*not* be shown on the member card";
|
||||
if(subject == "name") levelExplanation += " unless no display name is set";
|
||||
return PrivacyLevel.Private;
|
||||
}
|
||||
|
||||
if (!ctx.HasNext())
|
||||
throw new PKSyntaxError($"You must pass a privacy level for `{subject}` (`public` or `private`)");
|
||||
throw new PKSyntaxError($"Invalid privacy level `{ctx.PopArgument().SanitizeMentions()}` (must be `public` or `private`).");
|
||||
}
|
||||
|
||||
string levelStr, levelExplanation, subjectStr;
|
||||
var subjectList = "`name`, `description`, `birthday`, `pronouns`, `color`, `metadata`, `visibility`, or `all`";
|
||||
if(ctx.Match("name"))
|
||||
{
|
||||
subjectStr = "name";
|
||||
target.NamePrivacy = PopPrivacyLevel("name", out levelStr, out levelExplanation);
|
||||
}
|
||||
else if(ctx.Match("description", "desc", "text", "info"))
|
||||
{
|
||||
subjectStr = "description";
|
||||
target.DescriptionPrivacy = PopPrivacyLevel("description", out levelStr, out levelExplanation);
|
||||
}
|
||||
else if(ctx.Match("birthday", "birth", "bday"))
|
||||
{
|
||||
subjectStr = "birthday";
|
||||
target.BirthdayPrivacy = PopPrivacyLevel("birthday", out levelStr, out levelExplanation);
|
||||
}
|
||||
else if(ctx.Match("pronouns", "pronoun"))
|
||||
{
|
||||
subjectStr = "pronouns";
|
||||
target.PronounPrivacy = PopPrivacyLevel("pronouns", out levelStr, out levelExplanation);
|
||||
}
|
||||
else if(ctx.Match("color","colour"))
|
||||
{
|
||||
subjectStr = "color";
|
||||
target.ColorPrivacy = PopPrivacyLevel("color", out levelStr, out levelExplanation);
|
||||
}
|
||||
else if(ctx.Match("meta","metadata"))
|
||||
{
|
||||
subjectStr = "metadata (date created, message count, last fronted, and last message)";
|
||||
target.MetadataPrivacy = PopPrivacyLevel("metadata", out levelStr, out levelExplanation);
|
||||
}
|
||||
else if(ctx.Match("visibility","hidden","shown","visible"))
|
||||
{
|
||||
subjectStr = "visibility";
|
||||
target.MemberVisibility = PopPrivacyLevel("visibility", out levelStr, out levelExplanation);
|
||||
}
|
||||
else if(ctx.Match("all") || newValueFromCommand != null){
|
||||
subjectStr = "all";
|
||||
PrivacyLevel level;
|
||||
if(newValueFromCommand != null)
|
||||
{
|
||||
if(newValueFromCommand == PrivacyLevel.Public)
|
||||
{
|
||||
level = PrivacyLevel.Public;
|
||||
levelStr = "public";
|
||||
levelExplanation = "be shown on the member card";
|
||||
}
|
||||
else
|
||||
{
|
||||
level = PrivacyLevel.Private;
|
||||
levelStr = "private";
|
||||
levelExplanation = "*not* be shown on the member card";
|
||||
}
|
||||
}
|
||||
else
|
||||
level = PopPrivacyLevel("all", out levelStr, out levelExplanation);
|
||||
target.MemberVisibility = level;
|
||||
target.NamePrivacy = level;
|
||||
target.DescriptionPrivacy = level;
|
||||
target.BirthdayPrivacy = level;
|
||||
target.PronounPrivacy = level;
|
||||
target.ColorPrivacy = level;
|
||||
target.MetadataPrivacy = level;
|
||||
}
|
||||
else
|
||||
await ctx.Reply($"{Emojis.Success} Member privacy set to **public**. This member will now show up in member lists and will return all information when queried by other accounts.");
|
||||
throw new PKSyntaxError($"Invalid privacy subject `{ctx.PopArgument().SanitizeMentions()}` (must be {subjectList}).");
|
||||
|
||||
|
||||
await _data.SaveMember(target);
|
||||
//Handle "all" subject
|
||||
if(subjectStr == "all"){
|
||||
if(levelStr == "private")
|
||||
await ctx.Reply($"All {target.Name.SanitizeMentions()}'s privacy settings have been set to **{levelStr}**. Other accounts will now see nothing on the member card.");
|
||||
else
|
||||
await ctx.Reply($"All {target.Name.SanitizeMentions()}'s privacy settings have been set to **{levelStr}**. Other accounts will now see everything on the member card.");
|
||||
}
|
||||
//Handle other subjects
|
||||
else
|
||||
await ctx.Reply($"{target.Name.SanitizeMentions()}'s {subjectStr} has been set to **{levelStr}**. Other accounts will now {levelExplanation}.");
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
public async Task Delete(Context ctx, PKMember target)
|
||||
|
@@ -262,7 +262,7 @@ namespace PluralKit.Bot
|
||||
.AddField("Member list", PrivacyLevelString(ctx.System.MemberListPrivacy))
|
||||
.AddField("Current fronter(s)", PrivacyLevelString(ctx.System.FrontPrivacy))
|
||||
.AddField("Front/switch history", PrivacyLevelString(ctx.System.FrontHistoryPrivacy))
|
||||
.WithDescription("To edit privacy settings, use the command:\n`pk;system privacy <subject> <level>`\n\n- `subject` is one of `description`, `list`, `front` or `fronthistory`\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`, or `all` \n- `level` is either `public` or `private`.");
|
||||
await ctx.Reply(embed: eb.Build());
|
||||
return;
|
||||
}
|
||||
@@ -289,7 +289,7 @@ namespace PluralKit.Bot
|
||||
}
|
||||
|
||||
string levelStr, levelExplanation, subjectStr;
|
||||
var subjectList = "`description`, `members`, `front` or `fronthistory`";
|
||||
var subjectList = "`description`, `members`, `front`, `fronthistory`, or `all`";
|
||||
if (ctx.Match("description", "desc", "text", "info"))
|
||||
{
|
||||
subjectStr = "description";
|
||||
@@ -310,10 +310,27 @@ namespace PluralKit.Bot
|
||||
subjectStr = "front history";
|
||||
ctx.System.FrontHistoryPrivacy = PopPrivacyLevel("fronthistory", out levelStr, out levelExplanation);
|
||||
}
|
||||
else if (ctx.Match("all")){
|
||||
subjectStr = "all";
|
||||
PrivacyLevel level = PopPrivacyLevel("all", out levelStr, out levelExplanation);
|
||||
ctx.System.DescriptionPrivacy = level;
|
||||
ctx.System.MemberListPrivacy = level;
|
||||
ctx.System.FrontPrivacy = level;
|
||||
ctx.System.FrontHistoryPrivacy = level;
|
||||
|
||||
}
|
||||
else
|
||||
throw new PKSyntaxError($"Invalid privacy subject `{ctx.PopArgument().SanitizeMentions()}` (must be {subjectList}).");
|
||||
|
||||
await _data.SaveSystem(ctx.System);
|
||||
if(subjectStr == "all"){
|
||||
if(levelStr == "private")
|
||||
await ctx.Reply($"All of your systems privacy settings have been set to **{levelStr}**. Other accounts will now see nothing on the member card.");
|
||||
else
|
||||
await ctx.Reply($"All of your systems privacy have been set to **{levelStr}**. Other accounts will now see everything on the member card.");
|
||||
}
|
||||
//Handle other subjects
|
||||
else
|
||||
await ctx.Reply($"System {subjectStr} privacy has been set to **{levelStr}**. Other accounts will now {levelExplanation} your system {subjectStr}.");
|
||||
}
|
||||
|
||||
|
@@ -33,7 +33,7 @@ namespace PluralKit.Bot
|
||||
(eb, ms) =>
|
||||
{
|
||||
eb.WithFooter($"{opts.CreateFilterString()}. {members.Count} results.");
|
||||
renderer.RenderPage(eb, ctx.System.Zone, ms);
|
||||
renderer.RenderPage(eb, ctx.System.Zone, ms, ctx.LookupContextFor(target));
|
||||
return Task.CompletedTask;
|
||||
});
|
||||
}
|
||||
|
Reference in New Issue
Block a user