implement admin commands

This commit is contained in:
dusk 2025-10-04 01:57:48 +00:00
parent 5198f7d83b
commit a268f75d32
No known key found for this signature in database
15 changed files with 263 additions and 287 deletions

View file

@ -1 +1,64 @@
use super::*;
pub fn admin() -> &'static str {
"admin"
}
pub fn cmds() -> impl Iterator<Item = Command> {
let admin = admin();
let abuselog = tokens!(admin, ("abuselog", ["al"]));
let make_abuselog_cmds = |log_param: Parameter| {
[
command!(abuselog, ("show", ["s"]), log_param => format!("admin_abuselog_show_{}", log_param.name()))
.help("Shows an abuse log entry"),
command!(abuselog, ("flagdeny", ["fd"]), log_param, Optional(("value", Toggle)) => format!("admin_abuselog_flag_deny_{}", log_param.name()))
.help("Sets the deny flag on an abuse log entry"),
command!(abuselog, ("description", ["desc"]), log_param, Optional(("desc", OpaqueStringRemainder)) => format!("admin_abuselog_description_{}", log_param.name()))
.flag(("clear", ["c"]))
.help("Sets the description of an abuse log entry"),
command!(abuselog, ("adduser", ["au"]), log_param => format!("admin_abuselog_add_user_{}", log_param.name()))
.help("Adds a user to an abuse log entry"),
command!(abuselog, ("removeuser", ["ru"]), log_param => format!("admin_abuselog_remove_user_{}", log_param.name()))
.help("Removes a user from an abuse log entry"),
command!(abuselog, ("delete", ["d"]), log_param => format!("admin_abuselog_delete_{}", log_param.name()))
.help("Deletes an abuse log entry"),
].into_iter()
};
let abuselog_cmds = [
command!(abuselog, ("create", ["c", "new"]), ("account", UserRef), Optional(("description", OpaqueStringRemainder)) => "admin_abuselog_create")
.flag(("deny-boy-usage", ["deny"]))
.help("Creates an abuse log entry")
]
.into_iter()
.chain(make_abuselog_cmds(Skip(("account", UserRef)).into())) // falls through to log_id
.chain(make_abuselog_cmds(("log_id", OpaqueString).into()));
[
command!(admin, ("updatesystemid", ["usid"]), SystemRef, ("new_hid", OpaqueString) => "admin_update_system_id")
.help("Updates a system's ID"),
command!(admin, ("updatememberid", ["umid"]), MemberRef, ("new_hid", OpaqueString) => "admin_update_member_id")
.help("Updates a member's ID"),
command!(admin, ("updategroupid", ["ugid"]), GroupRef, ("new_hid", OpaqueString) => "admin_update_group_id")
.help("Updates a group's ID"),
command!(admin, ("rerollsystemid", ["rsid"]), SystemRef => "admin_reroll_system_id")
.help("Rerolls a system's ID"),
command!(admin, ("rerollmemberid", ["rmid"]), MemberRef => "admin_reroll_member_id")
.help("Rerolls a member's ID"),
command!(admin, ("rerollgroupid", ["rgid"]), GroupRef => "admin_reroll_group_id")
.help("Rerolls a group's ID"),
command!(admin, ("updatememberlimit", ["uml"]), SystemRef, Optional(("limit", OpaqueInt)) => "admin_system_member_limit")
.help("Updates a system's member limit"),
command!(admin, ("updategrouplimit", ["ugl"]), SystemRef, Optional(("limit", OpaqueInt)) => "admin_system_group_limit")
.help("Updates a system's group limit"),
command!(admin, ("systemrecover", ["sr"]), ("token", OpaqueString), ("account", UserRef) => "admin_system_recover")
.flag(("reroll-token", ["rt"]))
.help("Recovers a system"),
command!(admin, ("systemdelete", ["sd"]), SystemRef => "admin_system_delete")
.help("Deletes a system"),
command!(admin, ("sendmessage", ["sendmsg"]), ("account", UserRef), ("content", OpaqueStringRemainder) => "admin_send_message")
.help("Sends a message to a user"),
]
.into_iter()
.chain(abuselog_cmds)
}

View file

@ -5,9 +5,7 @@ pub fn cmds() -> impl Iterator<Item = Command> {
[
command!(("dashboard", ["dash"]) => "dashboard"),
command!("explain" => "explain"),
command!(help => "help")
.flag(("foo", OpaqueString)) // todo: just for testing
.help("Shows the help command"),
command!(help => "help").help("Shows the help command"),
command!(help, "commands" => "help_commands").help("help commands"),
command!(help, "proxy" => "help_proxy").help("help proxy"),
]

View file

@ -3,7 +3,6 @@ pub mod api;
pub mod autoproxy;
pub mod commands;
pub mod config;
pub mod dashboard;
pub mod debug;
pub mod fun;
pub mod group;
@ -40,10 +39,12 @@ pub fn all() -> impl Iterator<Item = Command> {
.chain(debug::cmds())
.chain(message::cmds())
.chain(import_export::cmds())
.chain(admin::cmds())
.map(|cmd| {
cmd.hidden_flag(("plaintext", ["pt"]))
.hidden_flag(("raw", ["r"]))
.hidden_flag(("show-embed", ["se"]))
.hidden_flag(("by-id", ["id"]))
})
}

View file

@ -25,7 +25,7 @@ pub fn cmds() -> impl Iterator<Item = Command> {
.help("Deletes a proxied message"),
apply_edit(command!(message, edit => "message_edit")),
apply_edit(command!(edit => "message_edit")),
command!(("reproxy", ["rp", "crimes", "crime"]), MessageRef => "message_reproxy")
command!(("reproxy", ["rp", "crimes", "crime"]), ("msg", MessageRef), ("member", MemberRef) => "message_reproxy")
.help("Reproxies a message with a different member"),
]
.into_iter()

View file

@ -3,18 +3,21 @@ use std::{
str::FromStr,
};
use smol_str::SmolStr;
use regex::Regex;
use smol_str::{SmolStr, format_smolstr};
use crate::token::{Token, TokenMatchResult};
#[derive(Debug, Clone)]
pub enum ParameterValue {
OpaqueString(String),
OpaqueInt(i32),
MemberRef(String),
MemberRefs(Vec<String>),
GroupRef(String),
GroupRefs(Vec<String>),
SystemRef(String),
UserRef(u64),
MessageRef(Option<u64>, Option<u64>, u64),
ChannelRef(u64),
GuildRef(u64),
@ -85,6 +88,10 @@ impl Parameter {
ParameterKind::OpaqueString | ParameterKind::OpaqueStringRemainder => {
Ok(ParameterValue::OpaqueString(input.into()))
}
ParameterKind::OpaqueInt => input
.parse::<i32>()
.map(|num| ParameterValue::OpaqueInt(num))
.map_err(|err| format_smolstr!("invalid integer: {err}")),
ParameterKind::GroupRef => Ok(ParameterValue::GroupRef(input.into())),
ParameterKind::GroupRefs => Ok(ParameterValue::GroupRefs(
input.split(' ').map(|s| s.trim().to_string()).collect(),
@ -94,6 +101,22 @@ impl Parameter {
input.split(' ').map(|s| s.trim().to_string()).collect(),
)),
ParameterKind::SystemRef => Ok(ParameterValue::SystemRef(input.into())),
ParameterKind::UserRef => {
if let Ok(user_id) = input.parse::<u64>() {
return Ok(ParameterValue::UserRef(user_id));
}
static RE: std::sync::LazyLock<Regex> =
std::sync::LazyLock::new(|| Regex::new(r"<@!?(\\d{17,19})>").unwrap());
if let Some(captures) = RE.captures(&input) {
return captures[1]
.parse::<u64>()
.map(|id| ParameterValue::UserRef(id))
.map_err(|_| SmolStr::new("invalid user ID"));
}
Err(SmolStr::new("invalid user ID"))
}
ParameterKind::MemberPrivacyTarget => MemberPrivacyTargetKind::from_str(input)
.map(|target| ParameterValue::MemberPrivacyTarget(target.as_ref().into())),
ParameterKind::GroupPrivacyTarget => GroupPrivacyTargetKind::from_str(input)
@ -166,6 +189,9 @@ impl Display for Parameter {
ParameterKind::OpaqueString => {
write!(f, "[{}]", self.name)
}
ParameterKind::OpaqueInt => {
write!(f, "[{}]", self.name)
}
ParameterKind::OpaqueStringRemainder => {
write!(f, "[{}]...", self.name)
}
@ -174,6 +200,7 @@ impl Display for Parameter {
ParameterKind::GroupRef => write!(f, "<target group>"),
ParameterKind::GroupRefs => write!(f, "<group 1> <group 2> <group 3>..."),
ParameterKind::SystemRef => write!(f, "<target system>"),
ParameterKind::UserRef => write!(f, "<target user>"),
ParameterKind::MessageRef => write!(f, "<target message>"),
ParameterKind::ChannelRef => write!(f, "<target channel>"),
ParameterKind::GuildRef => write!(f, "<target guild>"),
@ -246,12 +273,14 @@ impl<P: Into<Parameter>> From<Skip<P>> for Parameter {
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ParameterKind {
OpaqueString,
OpaqueInt,
OpaqueStringRemainder,
MemberRef,
MemberRefs,
GroupRef,
GroupRefs,
SystemRef,
UserRef,
MessageRef,
ChannelRef,
GuildRef,
@ -267,12 +296,14 @@ impl ParameterKind {
pub(crate) fn default_name(&self) -> &str {
match self {
ParameterKind::OpaqueString => "string",
ParameterKind::OpaqueInt => "number",
ParameterKind::OpaqueStringRemainder => "string",
ParameterKind::MemberRef => "target",
ParameterKind::MemberRefs => "targets",
ParameterKind::GroupRef => "target",
ParameterKind::GroupRefs => "targets",
ParameterKind::SystemRef => "target",
ParameterKind::UserRef => "target",
ParameterKind::MessageRef => "target",
ParameterKind::ChannelRef => "target",
ParameterKind::GuildRef => "target",

View file

@ -260,11 +260,13 @@ fn command_callback_to_name(cb: &str) -> String {
fn get_param_ty(kind: ParameterKind) -> &'static str {
match kind {
ParameterKind::OpaqueString | ParameterKind::OpaqueStringRemainder => "string",
ParameterKind::OpaqueInt => "int",
ParameterKind::MemberRef => "PKMember",
ParameterKind::MemberRefs => "List<PKMember>",
ParameterKind::GroupRef => "PKGroup",
ParameterKind::GroupRefs => "List<PKGroup>",
ParameterKind::SystemRef => "PKSystem",
ParameterKind::UserRef => "User",
ParameterKind::MemberPrivacyTarget => "MemberPrivacySubject",
ParameterKind::GroupPrivacyTarget => "GroupPrivacySubject",
ParameterKind::SystemPrivacyTarget => "SystemPrivacySubject",
@ -280,11 +282,13 @@ fn get_param_ty(kind: ParameterKind) -> &'static str {
fn get_param_param_ty(kind: ParameterKind) -> &'static str {
match kind {
ParameterKind::OpaqueString | ParameterKind::OpaqueStringRemainder => "Opaque",
ParameterKind::OpaqueInt => "Number",
ParameterKind::MemberRef => "Member",
ParameterKind::MemberRefs => "Members",
ParameterKind::GroupRef => "Group",
ParameterKind::GroupRefs => "Groups",
ParameterKind::SystemRef => "System",
ParameterKind::UserRef => "User",
ParameterKind::MemberPrivacyTarget => "MemberPrivacyTarget",
ParameterKind::GroupPrivacyTarget => "GroupPrivacyTarget",
ParameterKind::SystemPrivacyTarget => "SystemPrivacyTarget",

View file

@ -13,6 +13,7 @@ interface Parameter {
GroupRef(string group);
GroupRefs(sequence<string> groups);
SystemRef(string system);
UserRef(u64 user_id);
MessageRef(u64? guild_id, u64? channel_id, u64 message_id);
ChannelRef(u64 channel_id);
GuildRef(u64 guild_id);
@ -21,6 +22,7 @@ interface Parameter {
SystemPrivacyTarget(string target);
PrivacyLevel(string level);
OpaqueString(string raw);
OpaqueInt(i32 raw);
Toggle(boolean toggle);
Avatar(string avatar);
Null();

View file

@ -37,6 +37,9 @@ pub enum Parameter {
SystemRef {
system: String,
},
UserRef {
user_id: u64,
},
MessageRef {
guild_id: Option<u64>,
channel_id: Option<u64>,
@ -63,6 +66,9 @@ pub enum Parameter {
OpaqueString {
raw: String,
},
OpaqueInt {
raw: i32,
},
Toggle {
toggle: bool,
},
@ -80,11 +86,13 @@ impl From<ParameterValue> for Parameter {
ParameterValue::GroupRef(group) => Self::GroupRef { group },
ParameterValue::GroupRefs(groups) => Self::GroupRefs { groups },
ParameterValue::SystemRef(system) => Self::SystemRef { system },
ParameterValue::UserRef(user_id) => Self::UserRef { user_id },
ParameterValue::MemberPrivacyTarget(target) => Self::MemberPrivacyTarget { target },
ParameterValue::GroupPrivacyTarget(target) => Self::GroupPrivacyTarget { target },
ParameterValue::SystemPrivacyTarget(target) => Self::SystemPrivacyTarget { target },
ParameterValue::PrivacyLevel(level) => Self::PrivacyLevel { level },
ParameterValue::OpaqueString(raw) => Self::OpaqueString { raw },
ParameterValue::OpaqueInt(raw) => Self::OpaqueInt { raw },
ParameterValue::Toggle(toggle) => Self::Toggle { toggle },
ParameterValue::Avatar(avatar) => Self::Avatar { avatar },
ParameterValue::MessageRef(guild_id, channel_id, message_id) => Self::MessageRef {