feat: implement system privacy commands (yay system edit done)

This commit is contained in:
dusk 2025-04-04 06:14:17 +09:00
parent cb0a9eaf9f
commit 3eece261fd
No known key found for this signature in database
10 changed files with 154 additions and 75 deletions

View file

@ -100,6 +100,9 @@ public partial class CommandTree
Commands.SystemShowProxy(var param, _) => ctx.Execute<SystemEdit>(SystemProxy, m => m.ShowSystemProxy(ctx, param.target)), Commands.SystemShowProxy(var param, _) => ctx.Execute<SystemEdit>(SystemProxy, m => m.ShowSystemProxy(ctx, param.target)),
Commands.SystemToggleProxyCurrent(var param, _) => ctx.Execute<SystemEdit>(SystemProxy, m => m.ToggleSystemProxy(ctx, ctx.Guild, param.toggle)), Commands.SystemToggleProxyCurrent(var param, _) => ctx.Execute<SystemEdit>(SystemProxy, m => m.ToggleSystemProxy(ctx, ctx.Guild, param.toggle)),
Commands.SystemToggleProxy(var param, _) => ctx.Execute<SystemEdit>(SystemProxy, m => m.ToggleSystemProxy(ctx, param.target, param.toggle)), Commands.SystemToggleProxy(var param, _) => ctx.Execute<SystemEdit>(SystemProxy, m => m.ToggleSystemProxy(ctx, param.target, param.toggle)),
Commands.SystemShowPrivacy(var param, _) => ctx.Execute<SystemEdit>(SystemPrivacy, m => m.ShowSystemPrivacy(ctx, ctx.System)),
Commands.SystemChangePrivacyAll(var param, _) => ctx.Execute<SystemEdit>(SystemPrivacy, m => m.ChangeSystemPrivacyAll(ctx, ctx.System, param.level)),
Commands.SystemChangePrivacy(var param, _) => ctx.Execute<SystemEdit>(SystemPrivacy, m => m.ChangeSystemPrivacy(ctx, ctx.System, param.privacy, param.level)),
_ => _ =>
// this should only ever occur when deving if commands are not implemented... // this should only ever occur when deving if commands are not implemented...
ctx.Reply( ctx.Reply(
@ -363,8 +366,6 @@ public partial class CommandTree
await ctx.CheckSystem(target).Execute<SystemFront>(SystemFrontPercent, m => m.FrontPercent(ctx, system: target)); await ctx.CheckSystem(target).Execute<SystemFront>(SystemFrontPercent, m => m.FrontPercent(ctx, system: target));
else if (ctx.Match("groups", "gs")) else if (ctx.Match("groups", "gs"))
await ctx.CheckSystem(target).Execute<Groups>(GroupList, g => g.ListSystemGroups(ctx, target)); await ctx.CheckSystem(target).Execute<Groups>(GroupList, g => g.ListSystemGroups(ctx, target));
else if (ctx.Match("privacy"))
await ctx.CheckSystem(target).Execute<SystemEdit>(SystemPrivacy, m => m.SystemPrivacy(ctx, target));
else if (ctx.Match("id")) else if (ctx.Match("id"))
await ctx.CheckSystem(target).Execute<System>(SystemId, m => m.DisplayId(ctx, target)); await ctx.CheckSystem(target).Execute<System>(SystemId, m => m.DisplayId(ctx, target));
else if (ctx.Match("random", "rand", "r")) else if (ctx.Match("random", "rand", "r"))

View file

@ -36,7 +36,7 @@ public static class ContextFlagsExt
); );
} }
public static async Task<string?> FlagResolvePrivacyLevel(this Context ctx, string param_name) public static async Task<PrivacyLevel?> FlagResolvePrivacyLevel(this Context ctx, string param_name)
{ {
return await ctx.Parameters.ResolveFlag( return await ctx.Parameters.ResolveFlag(
ctx, param_name, ctx, param_name,

View file

@ -36,7 +36,15 @@ public static class ContextParametersExt
); );
} }
public static async Task<string?> ParamResolvePrivacyLevel(this Context ctx, string param_name) public static async Task<SystemPrivacySubject?> ParamResolveSystemPrivacyTarget(this Context ctx, string param_name)
{
return await ctx.Parameters.ResolveParameter(
ctx, param_name,
param => (param as Parameter.SystemPrivacyTarget)?.target
);
}
public static async Task<PrivacyLevel?> ParamResolvePrivacyLevel(this Context ctx, string param_name)
{ {
return await ctx.Parameters.ResolveParameter( return await ctx.Parameters.ResolveParameter(
ctx, param_name, ctx, param_name,

View file

@ -1,4 +1,3 @@
using System.Diagnostics;
using Myriad.Types; using Myriad.Types;
using PluralKit.Core; using PluralKit.Core;
using uniffi.commands; using uniffi.commands;
@ -12,7 +11,8 @@ public abstract record Parameter()
public record SystemRef(PKSystem system): Parameter; public record SystemRef(PKSystem system): Parameter;
public record GuildRef(Guild guild): Parameter; public record GuildRef(Guild guild): Parameter;
public record MemberPrivacyTarget(MemberPrivacySubject target): Parameter; public record MemberPrivacyTarget(MemberPrivacySubject target): Parameter;
public record PrivacyLevel(string level): Parameter; public record SystemPrivacyTarget(SystemPrivacySubject target): Parameter;
public record PrivacyLevel(Core.PrivacyLevel level): Parameter;
public record Toggle(bool value): Parameter; public record Toggle(bool value): Parameter;
public record Opaque(string value): Parameter; public record Opaque(string value): Parameter;
public record Avatar(ParsedImage avatar): Parameter; public record Avatar(ParsedImage avatar): Parameter;
@ -72,12 +72,16 @@ public class Parameters
); );
case uniffi.commands.Parameter.MemberPrivacyTarget memberPrivacyTarget: case uniffi.commands.Parameter.MemberPrivacyTarget memberPrivacyTarget:
// this should never really fail... // this should never really fail...
// todo: we shouldn't have *three* different MemberPrivacyTarget types (rust, ffi, c#) syncing the cases will be annoying... if (!MemberPrivacyUtils.TryParseMemberPrivacy(memberPrivacyTarget.target, out var memberPrivacy))
if (!MemberPrivacyUtils.TryParseMemberPrivacy(memberPrivacyTarget.target, out var target))
throw new PKError($"Invalid member privacy target {memberPrivacyTarget.target}"); throw new PKError($"Invalid member privacy target {memberPrivacyTarget.target}");
return new Parameter.MemberPrivacyTarget(target); return new Parameter.MemberPrivacyTarget(memberPrivacy);
case uniffi.commands.Parameter.SystemPrivacyTarget systemPrivacyTarget:
// this should never really fail...
if (!SystemPrivacyUtils.TryParseSystemPrivacy(systemPrivacyTarget.target, out var systemPrivacy))
throw new PKError($"Invalid system privacy target {systemPrivacyTarget.target}");
return new Parameter.SystemPrivacyTarget(systemPrivacy);
case uniffi.commands.Parameter.PrivacyLevel privacyLevel: case uniffi.commands.Parameter.PrivacyLevel privacyLevel:
return new Parameter.PrivacyLevel(privacyLevel.level); return new Parameter.PrivacyLevel(privacyLevel.level == "public" ? PrivacyLevel.Public : privacyLevel.level == "private" ? PrivacyLevel.Private : throw new PKError($"Invalid privacy level {privacyLevel.level}"));
case uniffi.commands.Parameter.Toggle toggle: case uniffi.commands.Parameter.Toggle toggle:
return new Parameter.Toggle(toggle.toggle); return new Parameter.Toggle(toggle.toggle);
case uniffi.commands.Parameter.OpaqueString opaque: case uniffi.commands.Parameter.OpaqueString opaque:

View file

@ -874,12 +874,10 @@ public class SystemEdit
$"Proxying in {serverText} is currently **disabled** for your system. To enable it, type `{ctx.DefaultPrefix}system proxy on`."); $"Proxying in {serverText} is currently **disabled** for your system. To enable it, type `{ctx.DefaultPrefix}system proxy on`.");
} }
public async Task SystemPrivacy(Context ctx, PKSystem target) public async Task ShowSystemPrivacy(Context ctx, PKSystem target)
{ {
ctx.CheckSystem().CheckOwnSystem(target); ctx.CheckSystem().CheckOwnSystem(target);
Task PrintEmbed()
{
var eb = new EmbedBuilder() var eb = new EmbedBuilder()
.Title("Current privacy settings for your system") .Title("Current privacy settings for your system")
.Field(new Embed.Field("Name", target.NamePrivacy.Explanation())) .Field(new Embed.Field("Name", target.NamePrivacy.Explanation()))
@ -893,11 +891,13 @@ public class SystemEdit
.Field(new Embed.Field("Front/switch history", target.FrontHistoryPrivacy.Explanation())) .Field(new Embed.Field("Front/switch history", target.FrontHistoryPrivacy.Explanation()))
.Description( .Description(
$"To edit privacy settings, use the command:\n`{ctx.DefaultPrefix}system privacy <subject> <level>`\n\n- `subject` is one of `name`, `avatar`, `description`, `banner`, `pronouns`, `list`, `front`, `fronthistory`, `groups`, or `all` \n- `level` is either `public` or `private`."); $"To edit privacy settings, use the command:\n`{ctx.DefaultPrefix}system privacy <subject> <level>`\n\n- `subject` is one of `name`, `avatar`, `description`, `banner`, `pronouns`, `list`, `front`, `fronthistory`, `groups`, or `all` \n- `level` is either `public` or `private`.");
return ctx.Reply(embed: eb.Build()); await ctx.Reply(embed: eb.Build());
} }
async Task SetLevel(SystemPrivacySubject subject, PrivacyLevel level) public async Task ChangeSystemPrivacy(Context ctx, PKSystem target, SystemPrivacySubject subject, PrivacyLevel level)
{ {
ctx.CheckSystem().CheckOwnSystem(target);
await ctx.Repository.UpdateSystem(target.Id, new SystemPatch().WithPrivacy(subject, level)); await ctx.Repository.UpdateSystem(target.Id, new SystemPatch().WithPrivacy(subject, level));
var levelExplanation = level switch var levelExplanation = level switch
@ -921,13 +921,14 @@ public class SystemEdit
_ => "" _ => ""
}; };
var msg = var msg = $"System {subjectStr} privacy has been set to **{level.LevelName()}**. Other accounts will now {levelExplanation} your system {subjectStr}.";
$"System {subjectStr} privacy has been set to **{level.LevelName()}**. Other accounts will now {levelExplanation} your system {subjectStr}.";
await ctx.Reply($"{Emojis.Success} {msg}"); await ctx.Reply($"{Emojis.Success} {msg}");
} }
async Task SetAll(PrivacyLevel level) public async Task ChangeSystemPrivacyAll(Context ctx, PKSystem target, PrivacyLevel level)
{ {
ctx.CheckSystem().CheckOwnSystem(target);
await ctx.Repository.UpdateSystem(target.Id, new SystemPatch().WithAllPrivacy(level)); await ctx.Repository.UpdateSystem(target.Id, new SystemPatch().WithAllPrivacy(level));
var msg = level switch var msg = level switch
@ -941,12 +942,4 @@ public class SystemEdit
await ctx.Reply($"{Emojis.Success} {msg}"); await ctx.Reply($"{Emojis.Success} {msg}");
} }
if (!ctx.HasNext())
await PrintEmbed();
else if (ctx.Match("all"))
await SetAll(ctx.PopPrivacyLevel());
else
await SetLevel(ctx.PopSystemPrivacySubject(), ctx.PopPrivacyLevel());
}
} }

View file

@ -202,12 +202,25 @@ pub fn edit() -> impl Iterator<Item = Command> {
let system_proxy = tokens!(system, "proxy"); let system_proxy = tokens!(system, "proxy");
let system_proxy_cmd = [ let system_proxy_cmd = [
command!(system_proxy => "system_show_proxy_current").help("Shows your system's proxy setting for the guild you are in"), command!(system_proxy => "system_show_proxy_current")
.help("Shows your system's proxy setting for the guild you are in"),
command!(system_proxy, Toggle => "system_toggle_proxy_current") command!(system_proxy, Toggle => "system_toggle_proxy_current")
.help("Toggle your system's proxy for the guild you are in"), .help("Toggle your system's proxy for the guild you are in"),
command!(system_proxy, GuildRef => "system_show_proxy").help("Shows your system's proxy setting for a guild"), command!(system_proxy, GuildRef => "system_show_proxy")
.help("Shows your system's proxy setting for a guild"),
command!(system_proxy, GuildRef, Toggle => "system_toggle_proxy") command!(system_proxy, GuildRef, Toggle => "system_toggle_proxy")
.help("Toggle your system's proxy for a guild"), .help("Toggle your system's proxy for a guild"),
]
.into_iter();
let system_privacy = tokens!(system, ("privacy", ["priv"]));
let system_privacy_cmd = [
command!(system_privacy => "system_show_privacy")
.help("Shows your system's privacy settings"),
command!(system_privacy, ("all", ["a"]), ("level", PrivacyLevel) => "system_change_privacy_all")
.help("Changes all privacy settings for your system"),
command!(system_privacy, ("privacy", SystemPrivacyTarget), ("level", PrivacyLevel) => "system_change_privacy")
.help("Changes a specific privacy setting for your system"),
].into_iter(); ].into_iter();
system_new_cmd system_new_cmd
@ -222,6 +235,7 @@ pub fn edit() -> impl Iterator<Item = Command> {
.chain(system_server_avatar_self_cmd) .chain(system_server_avatar_self_cmd)
.chain(system_banner_self_cmd) .chain(system_banner_self_cmd)
.chain(system_delete) .chain(system_delete)
.chain(system_privacy_cmd)
.chain(system_proxy_cmd) .chain(system_proxy_cmd)
.chain(system_name_cmd) .chain(system_name_cmd)
.chain(system_server_name_cmd) .chain(system_server_name_cmd)

View file

@ -14,6 +14,7 @@ pub enum ParameterValue {
SystemRef(String), SystemRef(String),
GuildRef(String), GuildRef(String),
MemberPrivacyTarget(String), MemberPrivacyTarget(String),
SystemPrivacyTarget(String),
PrivacyLevel(String), PrivacyLevel(String),
Toggle(bool), Toggle(bool),
Avatar(String), Avatar(String),
@ -45,6 +46,7 @@ impl Display for Parameter {
ParameterKind::SystemRef => write!(f, "<target system>"), ParameterKind::SystemRef => write!(f, "<target system>"),
ParameterKind::GuildRef => write!(f, "<target guild>"), ParameterKind::GuildRef => write!(f, "<target guild>"),
ParameterKind::MemberPrivacyTarget => write!(f, "<privacy target>"), ParameterKind::MemberPrivacyTarget => write!(f, "<privacy target>"),
ParameterKind::SystemPrivacyTarget => write!(f, "<privacy target>"),
ParameterKind::PrivacyLevel => write!(f, "[privacy level]"), ParameterKind::PrivacyLevel => write!(f, "[privacy level]"),
ParameterKind::Toggle => write!(f, "on/off"), ParameterKind::Toggle => write!(f, "on/off"),
ParameterKind::Avatar => write!(f, "<url|@mention>"), ParameterKind::Avatar => write!(f, "<url|@mention>"),
@ -78,6 +80,7 @@ pub enum ParameterKind {
SystemRef, SystemRef,
GuildRef, GuildRef,
MemberPrivacyTarget, MemberPrivacyTarget,
SystemPrivacyTarget,
PrivacyLevel, PrivacyLevel,
Toggle, Toggle,
Avatar, Avatar,
@ -92,6 +95,7 @@ impl ParameterKind {
ParameterKind::SystemRef => "target", ParameterKind::SystemRef => "target",
ParameterKind::GuildRef => "target", ParameterKind::GuildRef => "target",
ParameterKind::MemberPrivacyTarget => "member_privacy_target", ParameterKind::MemberPrivacyTarget => "member_privacy_target",
ParameterKind::SystemPrivacyTarget => "system_privacy_target",
ParameterKind::PrivacyLevel => "privacy_level", ParameterKind::PrivacyLevel => "privacy_level",
ParameterKind::Toggle => "toggle", ParameterKind::Toggle => "toggle",
ParameterKind::Avatar => "avatar", ParameterKind::Avatar => "avatar",
@ -112,6 +116,9 @@ impl ParameterKind {
ParameterKind::SystemRef => Ok(ParameterValue::SystemRef(input.into())), ParameterKind::SystemRef => Ok(ParameterValue::SystemRef(input.into())),
ParameterKind::MemberPrivacyTarget => MemberPrivacyTargetKind::from_str(input) ParameterKind::MemberPrivacyTarget => MemberPrivacyTargetKind::from_str(input)
.map(|target| ParameterValue::MemberPrivacyTarget(target.as_ref().into())), .map(|target| ParameterValue::MemberPrivacyTarget(target.as_ref().into())),
ParameterKind::SystemPrivacyTarget => SystemPrivacyTargetKind::from_str(input).map(
|target| ParameterValue::SystemPrivacyTarget(target.as_ref().into()),
),
ParameterKind::PrivacyLevel => PrivacyLevelKind::from_str(input) ParameterKind::PrivacyLevel => PrivacyLevelKind::from_str(input)
.map(|level| ParameterValue::PrivacyLevel(level.as_ref().into())), .map(|level| ParameterValue::PrivacyLevel(level.as_ref().into())),
ParameterKind::Toggle => { ParameterKind::Toggle => {
@ -176,6 +183,53 @@ impl FromStr for MemberPrivacyTargetKind {
} }
} }
pub enum SystemPrivacyTargetKind {
Name,
Avatar,
Description,
Banner,
Pronouns,
MemberList,
GroupList,
Front,
FrontHistory,
}
impl AsRef<str> for SystemPrivacyTargetKind {
fn as_ref(&self) -> &str {
match self {
Self::Name => "name",
Self::Avatar => "avatar",
Self::Description => "description",
Self::Banner => "banner",
Self::Pronouns => "pronouns",
Self::MemberList => "members",
Self::GroupList => "groups",
Self::Front => "front",
Self::FrontHistory => "fronthistory",
}
}
}
impl FromStr for SystemPrivacyTargetKind {
type Err = SmolStr;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.to_lowercase().as_str() {
"name" => Ok(Self::Name),
"avatar" | "pfp" | "pic" | "icon" => Ok(Self::Avatar),
"description" | "desc" | "bio" | "info" => Ok(Self::Description),
"banner" | "splash" | "cover" => Ok(Self::Banner),
"pronouns" | "prns" | "pn" => Ok(Self::Pronouns),
"members" | "memberlist" | "list" => Ok(Self::MemberList),
"groups" | "gs" => Ok(Self::GroupList),
"front" | "fronter" | "fronters" => Ok(Self::Front),
"fronthistory" | "fh" | "switches" => Ok(Self::FrontHistory),
_ => Err("invalid system privacy target".into()),
}
}
}
pub enum PrivacyLevelKind { pub enum PrivacyLevelKind {
Public, Public,
Private, Private,

View file

@ -169,7 +169,8 @@ fn get_param_ty(kind: ParameterKind) -> &'static str {
ParameterKind::MemberRef => "PKMember", ParameterKind::MemberRef => "PKMember",
ParameterKind::SystemRef => "PKSystem", ParameterKind::SystemRef => "PKSystem",
ParameterKind::MemberPrivacyTarget => "MemberPrivacySubject", ParameterKind::MemberPrivacyTarget => "MemberPrivacySubject",
ParameterKind::PrivacyLevel => "string", ParameterKind::SystemPrivacyTarget => "SystemPrivacySubject",
ParameterKind::PrivacyLevel => "PrivacyLevel",
ParameterKind::Toggle => "bool", ParameterKind::Toggle => "bool",
ParameterKind::Avatar => "ParsedImage", ParameterKind::Avatar => "ParsedImage",
ParameterKind::GuildRef => "Guild", ParameterKind::GuildRef => "Guild",
@ -182,6 +183,7 @@ fn get_param_param_ty(kind: ParameterKind) -> &'static str {
ParameterKind::MemberRef => "Member", ParameterKind::MemberRef => "Member",
ParameterKind::SystemRef => "System", ParameterKind::SystemRef => "System",
ParameterKind::MemberPrivacyTarget => "MemberPrivacyTarget", ParameterKind::MemberPrivacyTarget => "MemberPrivacyTarget",
ParameterKind::SystemPrivacyTarget => "SystemPrivacyTarget",
ParameterKind::PrivacyLevel => "PrivacyLevel", ParameterKind::PrivacyLevel => "PrivacyLevel",
ParameterKind::Toggle => "Toggle", ParameterKind::Toggle => "Toggle",
ParameterKind::Avatar => "Avatar", ParameterKind::Avatar => "Avatar",

View file

@ -12,6 +12,7 @@ interface Parameter {
SystemRef(string system); SystemRef(string system);
GuildRef(string guild); GuildRef(string guild);
MemberPrivacyTarget(string target); MemberPrivacyTarget(string target);
SystemPrivacyTarget(string target);
PrivacyLevel(string level); PrivacyLevel(string level);
OpaqueString(string raw); OpaqueString(string raw);
Toggle(boolean toggle); Toggle(boolean toggle);

View file

@ -26,6 +26,7 @@ pub enum Parameter {
SystemRef { system: String }, SystemRef { system: String },
GuildRef { guild: String }, GuildRef { guild: String },
MemberPrivacyTarget { target: String }, MemberPrivacyTarget { target: String },
SystemPrivacyTarget { target: String },
PrivacyLevel { level: String }, PrivacyLevel { level: String },
OpaqueString { raw: String }, OpaqueString { raw: String },
Toggle { toggle: bool }, Toggle { toggle: bool },
@ -38,6 +39,7 @@ impl From<ParameterValue> for Parameter {
ParameterValue::MemberRef(member) => Self::MemberRef { member }, ParameterValue::MemberRef(member) => Self::MemberRef { member },
ParameterValue::SystemRef(system) => Self::SystemRef { system }, ParameterValue::SystemRef(system) => Self::SystemRef { system },
ParameterValue::MemberPrivacyTarget(target) => Self::MemberPrivacyTarget { target }, ParameterValue::MemberPrivacyTarget(target) => Self::MemberPrivacyTarget { target },
ParameterValue::SystemPrivacyTarget(target) => Self::SystemPrivacyTarget { target },
ParameterValue::PrivacyLevel(level) => Self::PrivacyLevel { level }, ParameterValue::PrivacyLevel(level) => Self::PrivacyLevel { level },
ParameterValue::OpaqueString(raw) => Self::OpaqueString { raw }, ParameterValue::OpaqueString(raw) => Self::OpaqueString { raw },
ParameterValue::Toggle(toggle) => Self::Toggle { toggle }, ParameterValue::Toggle(toggle) => Self::Toggle { toggle },