BotServ: add BOTLIST and AUTOASSIGN default bot
All checks were successful
CI / check (push) Successful in 3m33s

This commit is contained in:
Jean Chevronnet 2026-07-16 00:57:06 +00:00
parent cd6d8b1b93
commit dd43b9a331
No known key found for this signature in database
12 changed files with 162 additions and 0 deletions

View file

@ -0,0 +1,34 @@
use echo_api::{Priv, Sender, ServiceCtx, Store};
// AUTOASSIGN <bot> | OFF: set the bot automatically assigned to every newly
// registered channel, or turn auto-assignment off. Oper-only (Priv::Admin) —
// it's a network-wide default. No argument reports the current setting.
pub fn handle(me: &str, from: &Sender, args: &[&str], ctx: &mut ServiceCtx, db: &mut dyn Store) {
if !from.privs.has(Priv::Admin) {
ctx.notice(me, from.uid, "Access denied — AUTOASSIGN is for services operators.");
return;
}
let Some(&arg) = args.get(1) else {
match db.default_bot() {
Some(bot) => ctx.notice(me, from.uid, format!("New channels are auto-assigned \x02{bot}\x02. Use \x02AUTOASSIGN OFF\x02 to stop.")),
None => ctx.notice(me, from.uid, "No bot is auto-assigned to new channels. Set one with \x02AUTOASSIGN <bot>\x02."),
}
return;
};
if arg.eq_ignore_ascii_case("OFF") || arg.eq_ignore_ascii_case("NONE") {
match db.set_default_bot(None) {
Ok(()) => ctx.notice(me, from.uid, "New channels will no longer be auto-assigned a bot."),
Err(_) => ctx.notice(me, from.uid, "Sorry, that didn't work. Please try again in a moment."),
}
return;
}
// Store the bot's canonical nick, so the setting survives a re-cased lookup.
let Some(bot) = db.bots().into_iter().find(|b| b.nick.eq_ignore_ascii_case(arg)) else {
ctx.notice(me, from.uid, format!("There's no bot named \x02{arg}\x02. See \x02BOTLIST\x02."));
return;
};
match db.set_default_bot(Some(&bot.nick)) {
Ok(()) => ctx.notice(me, from.uid, format!("New channels will be auto-assigned \x02{}\x02.", bot.nick)),
Err(_) => ctx.notice(me, from.uid, "Sorry, that didn't work. Please try again in a moment."),
}
}

View file

@ -0,0 +1,19 @@
use echo_api::{Priv, Sender, ServiceCtx, Store};
// BOTLIST: show the bots a channel founder can assign. Available to everyone,
// unlike \x02BOT LIST\x02 (operator bot administration). Private bots are hidden
// from ordinary users but shown, flagged, to operators.
pub fn handle(me: &str, from: &Sender, ctx: &mut ServiceCtx, db: &dyn Store) {
let is_oper = from.privs.has(Priv::Admin);
let bots: Vec<_> = db.bots().into_iter().filter(|b| is_oper || !b.private).collect();
if bots.is_empty() {
ctx.notice(me, from.uid, "No bots are available.");
return;
}
ctx.notice(me, from.uid, format!("Available bots ({}):", bots.len()));
for b in &bots {
let flag = if b.private { " \x02[private]\x02" } else { "" };
ctx.notice(me, from.uid, format!(" \x02{}\x02 ({}@{}){flag}", b.nick, b.user, b.host));
}
ctx.notice(me, from.uid, "Assign one with \x02ASSIGN <#channel> <bot>\x02.");
}

View file

@ -6,6 +6,10 @@ use echo_api::{HelpEntry, NetView, Priv, Sender, Service, ServiceCtx, Store};
#[path = "bot.rs"]
mod bot;
#[path = "botlist.rs"]
mod botlist;
#[path = "autoassign.rs"]
mod autoassign;
#[path = "assign.rs"]
mod assign;
#[path = "info.rs"]
@ -50,6 +54,8 @@ const TOPICS: &[HelpEntry] = &[
HelpEntry { cmd: "BADWORDS", summary: "manage badword patterns", detail: "Syntax: \x02BADWORDS <#channel> ADD|DEL|LIST|CLEAR [pattern]\x02\nManages the channel's badword patterns." },
HelpEntry { cmd: "TRIGGER", summary: "manage auto-responses", detail: "Syntax: \x02TRIGGER <#channel> ADD <regex>|<response>[|<cooldown>] | DEL <num> | LIST | CLEAR\x02\nManages the channel's auto-response triggers." },
HelpEntry { cmd: "COPY", summary: "clone bot settings", detail: "Syntax: \x02COPY <#source> <#dest>\x02\nClones a channel's bot settings to another channel." },
HelpEntry { cmd: "BOTLIST", summary: "list assignable bots", detail: "Syntax: \x02BOTLIST\x02\nLists the service bots you can assign to a channel." },
HelpEntry { cmd: "AUTOASSIGN", summary: "default bot for new channels (operator)", detail: "Syntax: \x02AUTOASSIGN <bot> | OFF\x02\nSets the bot auto-assigned to every newly registered channel. Operators only." },
HelpEntry { cmd: "BOT", summary: "manage the bots (operator)", detail: "Syntax: \x02BOT ADD|CHANGE|DEL|LIST\x02\nCreates and manages the service bots themselves. Operators only." },
];
@ -76,6 +82,8 @@ impl Service for BotServ {
let me = self.uid.as_str();
match args.first().map(|s| s.to_ascii_uppercase()).as_deref() {
Some("BOT") => bot::handle(me, from, args, ctx, db),
Some("BOTLIST") => botlist::handle(me, from, ctx, db),
Some("AUTOASSIGN") => autoassign::handle(me, from, args, ctx, db),
Some("ASSIGN") => assign::handle(me, from, args, ctx, db, true),
Some("UNASSIGN") => assign::handle(me, from, args, ctx, db, false),
Some("INFO") => info::handle(me, from, args, ctx, db),