Add centralized HELP with per-command subcommands
New echo-api primitive: a HelpEntry table plus a shared help() renderer. HELP lists a service's commands; HELP <command> prints that command's detail. Every service routes its HELP arm through the one renderer, so the shape is identical across the network. Wired into NickServ and the six newer services so far.
This commit is contained in:
parent
973d2826de
commit
c9e392630b
8 changed files with 137 additions and 14 deletions
|
|
@ -1130,6 +1130,37 @@ fn glob_match(pattern: &str, text: &str) -> bool {
|
||||||
pi == p.len()
|
pi == p.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// One command's help: its name, a one-line summary shown in the command list,
|
||||||
|
// and the detail shown for `HELP <command>` (newline-separated lines).
|
||||||
|
pub struct HelpEntry {
|
||||||
|
pub cmd: &'static str,
|
||||||
|
pub summary: &'static str,
|
||||||
|
pub detail: &'static str,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Centralized HELP for a service: `HELP` lists the commands, `HELP <command>`
|
||||||
|
// prints that command's detail. Every service routes its HELP command here, so
|
||||||
|
// the shape is identical across every service on the network.
|
||||||
|
pub fn help(me: &str, from: &Sender, ctx: &mut ServiceCtx, blurb: &str, topics: &[HelpEntry], topic: Option<&str>) {
|
||||||
|
match topic {
|
||||||
|
None => {
|
||||||
|
ctx.notice(me, from.uid, blurb);
|
||||||
|
for e in topics {
|
||||||
|
ctx.notice(me, from.uid, format!(" \x02{}\x02 {}", e.cmd, e.summary));
|
||||||
|
}
|
||||||
|
ctx.notice(me, from.uid, "Type \x02HELP <command>\x02 for detail on one command.");
|
||||||
|
}
|
||||||
|
Some(t) => match topics.iter().find(|e| e.cmd.eq_ignore_ascii_case(t)) {
|
||||||
|
Some(e) => {
|
||||||
|
for line in e.detail.lines() {
|
||||||
|
ctx.notice(me, from.uid, line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => ctx.notice(me, from.uid, format!("No help for \x02{}\x02. Type \x02HELP\x02 for the command list.", t.to_ascii_uppercase())),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Format a Unix timestamp (seconds) as "YYYY-MM-DD HH:MM:SS UTC", using Howard
|
// Format a Unix timestamp (seconds) as "YYYY-MM-DD HH:MM:SS UTC", using Howard
|
||||||
// Hinnant's civil-from-days algorithm so no date crate is needed.
|
// Hinnant's civil-from-days algorithm so no date crate is needed.
|
||||||
pub fn human_time(ts: u64) -> String {
|
pub fn human_time(ts: u64) -> String {
|
||||||
|
|
|
||||||
|
|
@ -6,13 +6,28 @@
|
||||||
//! SCORES <#channel> shows the standings; CHANFIX <#channel> performs the fix.
|
//! SCORES <#channel> shows the standings; CHANFIX <#channel> performs the fix.
|
||||||
//! `lib.rs` holds the dispatcher; each command lives in its own file.
|
//! `lib.rs` holds the dispatcher; each command lives in its own file.
|
||||||
|
|
||||||
use echo_api::{NetView, Sender, Service, ServiceCtx, Store};
|
use echo_api::{HelpEntry, NetView, Sender, Service, ServiceCtx, Store};
|
||||||
|
|
||||||
#[path = "scores.rs"]
|
#[path = "scores.rs"]
|
||||||
mod scores;
|
mod scores;
|
||||||
#[path = "fix.rs"]
|
#[path = "fix.rs"]
|
||||||
mod fix;
|
mod fix;
|
||||||
|
|
||||||
|
const BLURB: &str = "ChanFix recovers opless channels from accumulated op-time. It defers to ChanServ and won't touch a registered channel. Operator-only.";
|
||||||
|
|
||||||
|
const TOPICS: &[HelpEntry] = &[
|
||||||
|
HelpEntry {
|
||||||
|
cmd: "SCORES",
|
||||||
|
summary: "show a channel's op-time standings",
|
||||||
|
detail: "Syntax: \x02SCORES <#channel>\x02\nShows the accumulated op-time scores, highest first. These are the identities ChanFix would reop.",
|
||||||
|
},
|
||||||
|
HelpEntry {
|
||||||
|
cmd: "CHANFIX",
|
||||||
|
summary: "reop a channel's trusted regulars",
|
||||||
|
detail: "Syntax: \x02CHANFIX <#channel>\x02\nReops the present regulars of an opless channel by their accumulated op-time. Needs the channel opless (under three ops) with real history, and refuses a ChanServ-registered channel.",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
pub struct ChanFix {
|
pub struct ChanFix {
|
||||||
pub uid: String,
|
pub uid: String,
|
||||||
}
|
}
|
||||||
|
|
@ -38,7 +53,7 @@ impl Service for ChanFix {
|
||||||
match args.first().map(|s| s.to_ascii_uppercase()).as_deref() {
|
match args.first().map(|s| s.to_ascii_uppercase()).as_deref() {
|
||||||
Some("SCORES") => scores::handle(me, from, args.get(1).copied(), ctx, net),
|
Some("SCORES") => scores::handle(me, from, args.get(1).copied(), ctx, net),
|
||||||
Some("CHANFIX") | Some("FIX") => fix::handle(me, from, args.get(1).copied(), ctx, net, db),
|
Some("CHANFIX") | Some("FIX") => fix::handle(me, from, args.get(1).copied(), ctx, net, db),
|
||||||
Some("HELP") | None => ctx.notice(me, from.uid, "ChanFix recovers opless channels from accumulated op-time. \x02SCORES\x02 <#channel> shows the standings; \x02CHANFIX\x02 <#channel> reops its trusted regulars. It won't touch a ChanServ-registered channel."),
|
Some("HELP") | None => echo_api::help(me, from, ctx, BLURB, TOPICS, args.get(1).copied()),
|
||||||
Some(other) => ctx.notice(me, from.uid, format!("I don't know \x02{other}\x02. Try \x02SCORES\x02 or \x02CHANFIX\x02 <#channel>.")),
|
Some(other) => ctx.notice(me, from.uid, format!("I don't know \x02{other}\x02. Try \x02SCORES\x02 or \x02CHANFIX\x02 <#channel>.")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,13 +6,22 @@
|
||||||
//! `lib.rs` holds the dispatcher; the command lives in roll.rs and the
|
//! `lib.rs` holds the dispatcher; the command lives in roll.rs and the
|
||||||
//! expression evaluator in expr.rs.
|
//! expression evaluator in expr.rs.
|
||||||
|
|
||||||
use echo_api::{NetView, Sender, Service, ServiceCtx, Store};
|
use echo_api::{HelpEntry, NetView, Sender, Service, ServiceCtx, Store};
|
||||||
|
|
||||||
#[path = "expr.rs"]
|
#[path = "expr.rs"]
|
||||||
mod expr;
|
mod expr;
|
||||||
#[path = "roll.rs"]
|
#[path = "roll.rs"]
|
||||||
mod roll;
|
mod roll;
|
||||||
|
|
||||||
|
const BLURB: &str = "DiceServ rolls dice and evaluates maths for tabletop games. Dice: \x022d6\x02, \x02d20\x02, \x02d%\x02. Also + - * / ^ %, parentheses, functions (sqrt, floor, min, ...), \x02pi\x02/\x02e\x02, and \x023~2d6\x02 to repeat.";
|
||||||
|
|
||||||
|
const TOPICS: &[HelpEntry] = &[
|
||||||
|
HelpEntry { cmd: "ROLL", summary: "roll dice, whole-number result", detail: "Syntax: \x02ROLL <expr>\x02\nEvaluates a dice/math expression and rounds to a whole number, e.g. ROLL 2d6+3." },
|
||||||
|
HelpEntry { cmd: "CALC", summary: "evaluate, keeping decimals", detail: "Syntax: \x02CALC <expr>\x02\nEvaluates an expression and keeps the decimals." },
|
||||||
|
HelpEntry { cmd: "EXROLL", summary: "ROLL and show each die", detail: "Syntax: \x02EXROLL <expr>\x02\nLike ROLL, and also shows each individual die rolled." },
|
||||||
|
HelpEntry { cmd: "EXCALC", summary: "CALC and show each die", detail: "Syntax: \x02EXCALC <expr>\x02\nLike CALC, and also shows each individual die rolled." },
|
||||||
|
];
|
||||||
|
|
||||||
pub struct DiceServ {
|
pub struct DiceServ {
|
||||||
pub uid: String,
|
pub uid: String,
|
||||||
}
|
}
|
||||||
|
|
@ -35,7 +44,7 @@ impl Service for DiceServ {
|
||||||
Some("EXROLL") => roll::handle(me, from, &args[1..], ctx, true, true),
|
Some("EXROLL") => roll::handle(me, from, &args[1..], ctx, true, true),
|
||||||
Some("CALC") => roll::handle(me, from, &args[1..], ctx, false, false),
|
Some("CALC") => roll::handle(me, from, &args[1..], ctx, false, false),
|
||||||
Some("EXCALC") => roll::handle(me, from, &args[1..], ctx, true, false),
|
Some("EXCALC") => roll::handle(me, from, &args[1..], ctx, true, false),
|
||||||
Some("HELP") | None => ctx.notice(me, from.uid, "DiceServ rolls dice and does maths. \x02ROLL\x02 <expr> (whole-number result), \x02CALC\x02 <expr> (keeps decimals), \x02EXROLL\x02/\x02EXCALC\x02 also show each die. Dice: \x022d6\x02, \x02d20\x02, \x02d%\x02. Also + - * / ^ %, parentheses, functions (sqrt, floor, min, …), \x02pi\x02/\x02e\x02, and \x023~2d6\x02 to repeat."),
|
Some("HELP") | None => echo_api::help(me, from, ctx, BLURB, TOPICS, args.get(1).copied()),
|
||||||
Some(other) => ctx.notice(me, from.uid, format!("I don't know \x02{other}\x02. Try \x02ROLL\x02, \x02CALC\x02, or \x02HELP\x02.")),
|
Some(other) => ctx.notice(me, from.uid, format!("I don't know \x02{other}\x02. Try \x02ROLL\x02, \x02CALC\x02, or \x02HELP\x02.")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
//! `lib.rs` holds the dispatcher and the two shared guards; each command lives
|
//! `lib.rs` holds the dispatcher and the two shared guards; each command lives
|
||||||
//! in its own file.
|
//! in its own file.
|
||||||
|
|
||||||
use echo_api::{NetView, Sender, Service, ServiceCtx, Store};
|
use echo_api::{HelpEntry, NetView, Sender, Service, ServiceCtx, Store};
|
||||||
|
|
||||||
#[path = "register.rs"]
|
#[path = "register.rs"]
|
||||||
mod register;
|
mod register;
|
||||||
|
|
@ -25,6 +25,18 @@ mod del;
|
||||||
#[path = "flags.rs"]
|
#[path = "flags.rs"]
|
||||||
mod flags;
|
mod flags;
|
||||||
|
|
||||||
|
const BLURB: &str = "GroupServ manages user groups: a \x02!name\x02 owning member accounts. A channel can grant access to a group, and every member then inherits it.";
|
||||||
|
|
||||||
|
const TOPICS: &[HelpEntry] = &[
|
||||||
|
HelpEntry { cmd: "REGISTER", summary: "create a group you found", detail: "Syntax: \x02REGISTER <!group>\x02\nCreates a group with you as founder. A group name starts with '!', e.g. !staff." },
|
||||||
|
HelpEntry { cmd: "DROP", summary: "delete a group you founded", detail: "Syntax: \x02DROP <!group>\x02\nDeletes a group. Founder only." },
|
||||||
|
HelpEntry { cmd: "INFO", summary: "show a group's founder and size", detail: "Syntax: \x02INFO <!group>\x02\nShows a group's founder and member count." },
|
||||||
|
HelpEntry { cmd: "LIST", summary: "list groups you belong to", detail: "Syntax: \x02LIST\x02\nLists the groups you belong to. Operators see every group." },
|
||||||
|
HelpEntry { cmd: "ADD", summary: "add a member", detail: "Syntax: \x02ADD <!group> <account>\x02\nAdds a plain member. Needs the founder or the 'f' flag." },
|
||||||
|
HelpEntry { cmd: "DEL", summary: "remove a member", detail: "Syntax: \x02DEL <!group> <account>\x02\nRemoves a member. Needs the founder or the 'f' flag." },
|
||||||
|
HelpEntry { cmd: "FLAGS", summary: "view or change group flags", detail: "Syntax: \x02FLAGS <!group> [account [+/-flags]]\x02\nLists, shows, or changes group-access flags (F founder, f manage, i invite, c channel-access, s set, m memo). Changing needs the founder or the 'f' flag." },
|
||||||
|
];
|
||||||
|
|
||||||
pub struct GroupServ {
|
pub struct GroupServ {
|
||||||
pub uid: String,
|
pub uid: String,
|
||||||
}
|
}
|
||||||
|
|
@ -50,7 +62,7 @@ impl Service for GroupServ {
|
||||||
Some("ADD") => add::handle(me, from, args.get(1).copied(), args.get(2).copied(), ctx, db),
|
Some("ADD") => add::handle(me, from, args.get(1).copied(), args.get(2).copied(), ctx, db),
|
||||||
Some("DEL") => del::handle(me, from, args.get(1).copied(), args.get(2).copied(), ctx, db),
|
Some("DEL") => del::handle(me, from, args.get(1).copied(), args.get(2).copied(), ctx, db),
|
||||||
Some("FLAGS") => flags::handle(me, from, args.get(1).copied(), args.get(2).copied(), args.get(3).copied(), ctx, db),
|
Some("FLAGS") => flags::handle(me, from, args.get(1).copied(), args.get(2).copied(), args.get(3).copied(), ctx, db),
|
||||||
Some("HELP") | None => ctx.notice(me, from.uid, "GroupServ manages user groups. \x02REGISTER\x02 <!group>, \x02DROP\x02 <!group>, \x02INFO\x02 <!group>, \x02LIST\x02, \x02ADD\x02/\x02DEL\x02 <!group> <account>, \x02FLAGS\x02 <!group> [account [+/-flags]]. Grant a group channel access with ChanServ \x02FLAGS #chan !group +o\x02 — every member then inherits it."),
|
Some("HELP") | None => echo_api::help(me, from, ctx, BLURB, TOPICS, args.get(1).copied()),
|
||||||
Some(other) => ctx.notice(me, from.uid, format!("I don't know \x02{other}\x02. Try \x02HELP\x02.")),
|
Some(other) => ctx.notice(me, from.uid, format!("I don't know \x02{other}\x02. Try \x02HELP\x02.")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
//! `lib.rs` holds the dispatcher and the shared guard/claim helpers; each
|
//! `lib.rs` holds the dispatcher and the shared guard/claim helpers; each
|
||||||
//! command lives in its own file.
|
//! command lives in its own file.
|
||||||
|
|
||||||
use echo_api::{NetView, Sender, Service, ServiceCtx, Store};
|
use echo_api::{HelpEntry, NetView, Sender, Service, ServiceCtx, Store};
|
||||||
|
|
||||||
#[path = "request.rs"]
|
#[path = "request.rs"]
|
||||||
mod request;
|
mod request;
|
||||||
|
|
@ -24,6 +24,18 @@ mod next;
|
||||||
#[path = "close.rs"]
|
#[path = "close.rs"]
|
||||||
mod close;
|
mod close;
|
||||||
|
|
||||||
|
const BLURB: &str = "HelpServ is the help desk. Open a ticket with \x02REQUEST\x02; operators work the queue.";
|
||||||
|
|
||||||
|
const TOPICS: &[HelpEntry] = &[
|
||||||
|
HelpEntry { cmd: "REQUEST", summary: "open a help-desk ticket", detail: "Syntax: \x02REQUEST <message>\x02\nOpens a ticket for the staff. Also \x02HELPME\x02." },
|
||||||
|
HelpEntry { cmd: "CANCEL", summary: "withdraw your ticket", detail: "Syntax: \x02CANCEL\x02\nWithdraws your own newest open ticket." },
|
||||||
|
HelpEntry { cmd: "LIST", summary: "list the ticket queue", detail: "Syntax: \x02LIST [ALL]\x02\nOperators: list open tickets, or every ticket with ALL." },
|
||||||
|
HelpEntry { cmd: "VIEW", summary: "read a ticket", detail: "Syntax: \x02VIEW <id>\x02\nOperators: read a ticket in full. Also \x02READ\x02." },
|
||||||
|
HelpEntry { cmd: "TAKE", summary: "claim a ticket", detail: "Syntax: \x02TAKE <id>\x02\nOperators: claim a specific ticket. Also \x02ASSIGN\x02." },
|
||||||
|
HelpEntry { cmd: "NEXT", summary: "claim the oldest ticket", detail: "Syntax: \x02NEXT\x02\nOperators: claim the oldest unassigned ticket." },
|
||||||
|
HelpEntry { cmd: "CLOSE", summary: "resolve a ticket", detail: "Syntax: \x02CLOSE <id>\x02\nOperators: resolve a ticket. Also \x02RESOLVE\x02." },
|
||||||
|
];
|
||||||
|
|
||||||
pub struct HelpServ {
|
pub struct HelpServ {
|
||||||
pub uid: String,
|
pub uid: String,
|
||||||
}
|
}
|
||||||
|
|
@ -49,7 +61,7 @@ impl Service for HelpServ {
|
||||||
Some("TAKE") | Some("ASSIGN") => take::handle(me, from, args.get(1).copied(), ctx, db),
|
Some("TAKE") | Some("ASSIGN") => take::handle(me, from, args.get(1).copied(), ctx, db),
|
||||||
Some("NEXT") => next::handle(me, from, ctx, db),
|
Some("NEXT") => next::handle(me, from, ctx, db),
|
||||||
Some("CLOSE") | Some("RESOLVE") => close::handle(me, from, args.get(1).copied(), ctx, db),
|
Some("CLOSE") | Some("RESOLVE") => close::handle(me, from, args.get(1).copied(), ctx, db),
|
||||||
Some("HELP") | None => ctx.notice(me, from.uid, "HelpServ is the help desk. \x02REQUEST\x02 <message> opens a ticket for the staff; \x02CANCEL\x02 withdraws yours. Operators: \x02LIST\x02 [ALL], \x02VIEW\x02 <id>, \x02TAKE\x02 <id>, \x02NEXT\x02, \x02CLOSE\x02 <id>."),
|
Some("HELP") | None => echo_api::help(me, from, ctx, BLURB, TOPICS, args.get(1).copied()),
|
||||||
Some(other) => ctx.notice(me, from.uid, format!("I don't know \x02{other}\x02. Try \x02REQUEST\x02 <message> or \x02HELP\x02.")),
|
Some(other) => ctx.notice(me, from.uid, format!("I don't know \x02{other}\x02. Try \x02REQUEST\x02 <message> or \x02HELP\x02.")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@
|
||||||
//! and any operator may OLIST. `lib.rs` holds the dispatcher; each command
|
//! and any operator may OLIST. `lib.rs` holds the dispatcher; each command
|
||||||
//! (parameterised by bulletin kind) lives in its own file.
|
//! (parameterised by bulletin kind) lives in its own file.
|
||||||
|
|
||||||
use echo_api::{NetView, Sender, Service, ServiceCtx, Store};
|
use echo_api::{HelpEntry, NetView, Sender, Service, ServiceCtx, Store};
|
||||||
|
|
||||||
#[path = "post.rs"]
|
#[path = "post.rs"]
|
||||||
mod post;
|
mod post;
|
||||||
|
|
@ -22,6 +22,17 @@ mod list;
|
||||||
const PUBLIC: &str = "logon";
|
const PUBLIC: &str = "logon";
|
||||||
const OPER: &str = "oper";
|
const OPER: &str = "oper";
|
||||||
|
|
||||||
|
const BLURB: &str = "InfoServ holds the network's information bulletins: public ones show on connect, oper ones on login.";
|
||||||
|
|
||||||
|
const TOPICS: &[HelpEntry] = &[
|
||||||
|
HelpEntry { cmd: "POST", summary: "post a public bulletin", detail: "Syntax: \x02POST <message>\x02\nAdds a public bulletin, shown to everyone on connect. Admin only. Also \x02ADD\x02." },
|
||||||
|
HelpEntry { cmd: "LIST", summary: "show public bulletins", detail: "Syntax: \x02LIST\x02\nShows the public bulletins. Open to everyone." },
|
||||||
|
HelpEntry { cmd: "DEL", summary: "remove a public bulletin", detail: "Syntax: \x02DEL <number>\x02\nRemoves a public bulletin by its listed number. Admin only. Also \x02REMOVE\x02." },
|
||||||
|
HelpEntry { cmd: "OPOST", summary: "post an oper bulletin", detail: "Syntax: \x02OPOST <message>\x02\nAdds an oper bulletin, shown to operators on login. Admin only." },
|
||||||
|
HelpEntry { cmd: "OLIST", summary: "show oper bulletins", detail: "Syntax: \x02OLIST\x02\nShows the oper bulletins. Operators only." },
|
||||||
|
HelpEntry { cmd: "ODEL", summary: "remove an oper bulletin", detail: "Syntax: \x02ODEL <number>\x02\nRemoves an oper bulletin by its listed number. Admin only." },
|
||||||
|
];
|
||||||
|
|
||||||
pub struct InfoServ {
|
pub struct InfoServ {
|
||||||
pub uid: String,
|
pub uid: String,
|
||||||
}
|
}
|
||||||
|
|
@ -48,7 +59,7 @@ impl Service for InfoServ {
|
||||||
Some("LIST") | None => list::handle(me, from, PUBLIC, false, ctx, db),
|
Some("LIST") | None => list::handle(me, from, PUBLIC, false, ctx, db),
|
||||||
// Oper bulletins are for operators only.
|
// Oper bulletins are for operators only.
|
||||||
Some("OLIST") => list::handle(me, from, OPER, true, ctx, db),
|
Some("OLIST") => list::handle(me, from, OPER, true, ctx, db),
|
||||||
Some("HELP") => ctx.notice(me, from.uid, "InfoServ holds the network's information bulletins. \x02LIST\x02 shows the public ones. Operators: \x02POST\x02 <message> / \x02DEL\x02 <number> (public, shown on connect), \x02OPOST\x02 / \x02OLIST\x02 / \x02ODEL\x02 (oper-only, shown on login)."),
|
Some("HELP") => echo_api::help(me, from, ctx, BLURB, TOPICS, args.get(1).copied()),
|
||||||
Some(other) => ctx.notice(me, from.uid, format!("I don't know \x02{other}\x02. Try \x02LIST\x02 or \x02HELP\x02.")),
|
Some(other) => ctx.notice(me, from.uid, format!("I don't know \x02{other}\x02. Try \x02LIST\x02 or \x02HELP\x02.")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use echo_api::Store;
|
use echo_api::Store;
|
||||||
use echo_api::{Sender, Service, ServiceCtx};
|
use echo_api::{HelpEntry, Sender, Service, ServiceCtx};
|
||||||
use echo_api::NetView;
|
use echo_api::NetView;
|
||||||
|
|
||||||
#[path = "register.rs"]
|
#[path = "register.rs"]
|
||||||
|
|
@ -38,6 +38,29 @@ mod noexpire;
|
||||||
#[path = "password.rs"]
|
#[path = "password.rs"]
|
||||||
mod password;
|
mod password;
|
||||||
|
|
||||||
|
const BLURB: &str = "NickServ looks after your nickname and account: register it, identify to it, and manage its settings.";
|
||||||
|
|
||||||
|
const TOPICS: &[HelpEntry] = &[
|
||||||
|
HelpEntry { cmd: "REGISTER", summary: "register your nick as an account", detail: "Syntax: \x02REGISTER <password> [email]\x02\nRegisters your current nick as an account. If an email is given and confirmation is on, you get a code to \x02CONFIRM\x02." },
|
||||||
|
HelpEntry { cmd: "IDENTIFY", summary: "log in to your account", detail: "Syntax: \x02IDENTIFY [account] <password>\x02\nLogs you in. Also \x02ID\x02." },
|
||||||
|
HelpEntry { cmd: "LOGOUT", summary: "log out to a guest nick", detail: "Syntax: \x02LOGOUT\x02\nLogs you out and moves you to a guest nick. Also \x02LOGOFF\x02." },
|
||||||
|
HelpEntry { cmd: "INFO", summary: "show account information", detail: "Syntax: \x02INFO [account]\x02\nShows account information. The email is shown only to the owner." },
|
||||||
|
HelpEntry { cmd: "ALIST", summary: "list channels you have access on", detail: "Syntax: \x02ALIST\x02\nLists the channels you hold access on." },
|
||||||
|
HelpEntry { cmd: "SET", summary: "change password or email", detail: "Syntax: \x02SET PASSWORD <new>\x02 or \x02SET EMAIL <address>\x02\nChanges your account password or email." },
|
||||||
|
HelpEntry { cmd: "GROUP", summary: "link this nick to an account", detail: "Syntax: \x02GROUP <account> <password>\x02\nLinks your current nick to an account as an alias, so identifying under it logs into that account." },
|
||||||
|
HelpEntry { cmd: "GLIST", summary: "list your grouped nicks", detail: "Syntax: \x02GLIST\x02\nLists the nicks grouped to your account." },
|
||||||
|
HelpEntry { cmd: "UNGROUP", summary: "remove a grouped nick", detail: "Syntax: \x02UNGROUP [nick]\x02\nRemoves a grouped nick (your current one by default)." },
|
||||||
|
HelpEntry { cmd: "GHOST", summary: "disconnect a session on your nick", detail: "Syntax: \x02GHOST <nick> [password]\x02\nDisconnects a session using a nick you own. Also \x02RECOVER\x02." },
|
||||||
|
HelpEntry { cmd: "RESETPASS", summary: "reset your password by email", detail: "Syntax: \x02RESETPASS <account>\x02, then \x02RESETPASS <account> <code> <newpassword>\x02\nEmails a reset code, then sets a new password with it." },
|
||||||
|
HelpEntry { cmd: "CONFIRM", summary: "confirm your email", detail: "Syntax: \x02CONFIRM <code>\x02\nConfirms the email on a newly registered account with the code you were sent." },
|
||||||
|
HelpEntry { cmd: "DROP", summary: "delete your account", detail: "Syntax: \x02DROP <password>\x02\nDeletes your account and releases the channels you founded." },
|
||||||
|
HelpEntry { cmd: "CERT", summary: "manage SASL EXTERNAL certs", detail: "Syntax: \x02CERT ADD <password> [fingerprint]\x02, \x02CERT DEL <fingerprint>\x02, \x02CERT LIST\x02\nManages the TLS certificate fingerprints that can log in via SASL EXTERNAL." },
|
||||||
|
HelpEntry { cmd: "AJOIN", summary: "auto-join channels on login", detail: "Syntax: \x02AJOIN ADD <#channel>\x02, \x02AJOIN DEL <#channel>\x02, \x02AJOIN LIST\x02\nChannels you are auto-joined to when you identify." },
|
||||||
|
HelpEntry { cmd: "SUSPEND", summary: "block an account (operator)", detail: "Syntax: \x02SUSPEND <account> [reason]\x02\nBlocks an account from logging in. Operators only." },
|
||||||
|
HelpEntry { cmd: "UNSUSPEND", summary: "lift a suspension (operator)", detail: "Syntax: \x02UNSUSPEND <account>\x02\nLifts a suspension. Operators only." },
|
||||||
|
HelpEntry { cmd: "NOEXPIRE", summary: "pin against expiry (operator)", detail: "Syntax: \x02NOEXPIRE <account> {ON|OFF}\x02\nPins an account so inactivity expiry never drops it. Operators only." },
|
||||||
|
];
|
||||||
|
|
||||||
pub struct NickServ {
|
pub struct NickServ {
|
||||||
pub uid: String,
|
pub uid: String,
|
||||||
// Nick prefix assigned on LOGOUT (default "Guest"); a per-session sequence is
|
// Nick prefix assigned on LOGOUT (default "Guest"); a per-session sequence is
|
||||||
|
|
@ -88,7 +111,7 @@ impl Service for NickServ {
|
||||||
Some("SUSPEND") => suspend::handle(me, from, args, ctx, net, db, true),
|
Some("SUSPEND") => suspend::handle(me, from, args, ctx, net, db, true),
|
||||||
Some("UNSUSPEND") => suspend::handle(me, from, args, ctx, net, db, false),
|
Some("UNSUSPEND") => suspend::handle(me, from, args, ctx, net, db, false),
|
||||||
Some("NOEXPIRE") => noexpire::handle(me, from, args, ctx, db),
|
Some("NOEXPIRE") => noexpire::handle(me, from, args, ctx, db),
|
||||||
Some("HELP") => ctx.notice(me, from.uid, "NickServ looks after your nickname. Commands: \x02REGISTER\x02 <password> [email], \x02IDENTIFY\x02 [account] <password>, \x02INFO\x02 [account], \x02ALIST\x02, \x02GROUP\x02/\x02GLIST\x02/\x02UNGROUP\x02, \x02GHOST\x02 <nick> [password], \x02SET\x02 PASSWORD|EMAIL, \x02AJOIN\x02 ADD|DEL|LIST, \x02RESETPASS\x02 <account>, \x02CONFIRM\x02 <code>, \x02DROP\x02 <password>, \x02LOGOUT\x02, \x02CERT\x02 ADD|DEL|LIST <password> [fingerprint]. Operators also have \x02SUSPEND\x02/\x02UNSUSPEND\x02 and \x02NOEXPIRE\x02 <account> {ON|OFF}."),
|
Some("HELP") => echo_api::help(me, from, ctx, BLURB, TOPICS, args.get(1).copied()),
|
||||||
Some(other) => ctx.notice(me, from.uid, format!("I don't know the command \x02{other}\x02. Try \x02HELP\x02.")),
|
Some(other) => ctx.notice(me, from.uid, format!("I don't know the command \x02{other}\x02. Try \x02HELP\x02.")),
|
||||||
None => {}
|
None => {}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
//! `lib.rs` holds the dispatcher and the shared oper guard; each command lives
|
//! `lib.rs` holds the dispatcher and the shared oper guard; each command lives
|
||||||
//! in its own file.
|
//! in its own file.
|
||||||
|
|
||||||
use echo_api::{NetView, Sender, Service, ServiceCtx, Store};
|
use echo_api::{HelpEntry, NetView, Sender, Service, ServiceCtx, Store};
|
||||||
|
|
||||||
#[path = "report.rs"]
|
#[path = "report.rs"]
|
||||||
mod report;
|
mod report;
|
||||||
|
|
@ -21,6 +21,16 @@ mod close;
|
||||||
#[path = "del.rs"]
|
#[path = "del.rs"]
|
||||||
mod del;
|
mod del;
|
||||||
|
|
||||||
|
const BLURB: &str = "ReportServ takes abuse reports. Anyone can \x02REPORT\x02; operators review the queue.";
|
||||||
|
|
||||||
|
const TOPICS: &[HelpEntry] = &[
|
||||||
|
HelpEntry { cmd: "REPORT", summary: "file an abuse report", detail: "Syntax: \x02REPORT <nick|#channel> <reason>\x02\nTells the staff about a problem. Rate-limited." },
|
||||||
|
HelpEntry { cmd: "LIST", summary: "list reports", detail: "Syntax: \x02LIST [ALL]\x02\nOperators: list open reports, or every report with ALL." },
|
||||||
|
HelpEntry { cmd: "VIEW", summary: "read a report", detail: "Syntax: \x02VIEW <id>\x02\nOperators: read a report in full. Also \x02READ\x02." },
|
||||||
|
HelpEntry { cmd: "CLOSE", summary: "resolve a report", detail: "Syntax: \x02CLOSE <id>\x02\nOperators: mark a report resolved. Also \x02RESOLVE\x02." },
|
||||||
|
HelpEntry { cmd: "DEL", summary: "delete a report", detail: "Syntax: \x02DEL <id>\x02\nOperators: delete a report outright. Also \x02REMOVE\x02." },
|
||||||
|
];
|
||||||
|
|
||||||
pub struct ReportServ {
|
pub struct ReportServ {
|
||||||
pub uid: String,
|
pub uid: String,
|
||||||
}
|
}
|
||||||
|
|
@ -44,7 +54,7 @@ impl Service for ReportServ {
|
||||||
Some("VIEW") | Some("READ") => view::handle(me, from, args.get(1).copied(), ctx, db),
|
Some("VIEW") | Some("READ") => view::handle(me, from, args.get(1).copied(), ctx, db),
|
||||||
Some("CLOSE") | Some("RESOLVE") => close::handle(me, from, args.get(1).copied(), ctx, db),
|
Some("CLOSE") | Some("RESOLVE") => close::handle(me, from, args.get(1).copied(), ctx, db),
|
||||||
Some("DEL") | Some("REMOVE") => del::handle(me, from, args.get(1).copied(), ctx, db),
|
Some("DEL") | Some("REMOVE") => del::handle(me, from, args.get(1).copied(), ctx, db),
|
||||||
Some("HELP") | None => ctx.notice(me, from.uid, "ReportServ takes abuse reports. \x02REPORT\x02 <nick|#channel> <reason> tells the staff about a problem. Operators review with \x02LIST\x02 [ALL], \x02VIEW\x02 <id>, \x02CLOSE\x02 <id>, \x02DEL\x02 <id>."),
|
Some("HELP") | None => echo_api::help(me, from, ctx, BLURB, TOPICS, args.get(1).copied()),
|
||||||
Some(other) => ctx.notice(me, from.uid, format!("I don't know \x02{other}\x02. Try \x02REPORT\x02 <nick|#channel> <reason> or \x02HELP\x02.")),
|
Some(other) => ctx.notice(me, from.uid, format!("I don't know \x02{other}\x02. Try \x02REPORT\x02 <nick|#channel> <reason> or \x02HELP\x02.")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue