Migrate interpolated service messages to the t! macro (8 modules)
This commit is contained in:
parent
b462d37bd5
commit
d207c3d60d
133 changed files with 782 additions and 702 deletions
|
|
@ -1,5 +1,6 @@
|
|||
use echo_api::Store;
|
||||
use echo_api::{Sender, ServiceCtx};
|
||||
use echo_api::t;
|
||||
|
||||
// The named tiers ACCESS ADD accepts, high to low; the granular FLAGS command
|
||||
// covers anything finer. Kept in step with the XOP presets in `level_caps`.
|
||||
|
|
@ -13,12 +14,12 @@ pub fn handle(me: &str, from: &Sender, args: &[&str], ctx: &mut ServiceCtx, db:
|
|||
};
|
||||
match args.get(2).map(|s| s.to_ascii_uppercase()).as_deref() {
|
||||
None | Some("LIST") => match db.channel(chan) {
|
||||
None => ctx.notice(me, from.uid, format!("\x02{chan}\x02 isn't registered.")),
|
||||
None => ctx.notice(me, from.uid, t!(ctx, "\x02{chan}\x02 isn't registered.", chan = chan)),
|
||||
Some(info) => {
|
||||
ctx.notice(me, from.uid, format!("Access list for \x02{}\x02:", info.name));
|
||||
ctx.notice(me, from.uid, format!(" \x02{}\x02 (founder)", info.founder));
|
||||
ctx.notice(me, from.uid, t!(ctx, "Access list for \x02{name}\x02:", name = info.name));
|
||||
ctx.notice(me, from.uid, t!(ctx, " \x02{founder}\x02 (founder)", founder = info.founder));
|
||||
for a in &info.access {
|
||||
ctx.notice(me, from.uid, format!(" \x02{}\x02 ({})", a.account, a.level));
|
||||
ctx.notice(me, from.uid, t!(ctx, " \x02{account}\x02 ({level})", account = a.account, level = a.level));
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
@ -36,7 +37,7 @@ pub fn handle(me: &str, from: &Sender, args: &[&str], ctx: &mut ServiceCtx, db:
|
|||
return;
|
||||
}
|
||||
match db.access_add(chan, account, &level) {
|
||||
Ok(()) => ctx.notice(me, from.uid, format!("Added \x02{account}\x02 to \x02{chan}\x02 as \x02{level}\x02.")),
|
||||
Ok(()) => ctx.notice(me, from.uid, t!(ctx, "Added \x02{account}\x02 to \x02{chan}\x02 as \x02{level}\x02.", account = account, chan = chan, level = level)),
|
||||
Err(_) => ctx.notice(me, from.uid, "Sorry, that didn't work. Please try again in a moment."),
|
||||
}
|
||||
}
|
||||
|
|
@ -49,8 +50,8 @@ pub fn handle(me: &str, from: &Sender, args: &[&str], ctx: &mut ServiceCtx, db:
|
|||
return;
|
||||
}
|
||||
match db.access_del(chan, account) {
|
||||
Ok(true) => ctx.notice(me, from.uid, format!("Removed \x02{account}\x02 from \x02{chan}\x02.")),
|
||||
Ok(false) => ctx.notice(me, from.uid, format!("\x02{account}\x02 has no access to \x02{chan}\x02.")),
|
||||
Ok(true) => ctx.notice(me, from.uid, t!(ctx, "Removed \x02{account}\x02 from \x02{chan}\x02.", account = account, chan = chan)),
|
||||
Ok(false) => ctx.notice(me, from.uid, t!(ctx, "\x02{account}\x02 has no access to \x02{chan}\x02.", account = account, chan = chan)),
|
||||
Err(_) => ctx.notice(me, from.uid, "Sorry, that didn't work. Please try again in a moment."),
|
||||
}
|
||||
}
|
||||
|
|
@ -62,11 +63,11 @@ pub fn handle(me: &str, from: &Sender, args: &[&str], ctx: &mut ServiceCtx, db:
|
|||
fn is_founder(me: &str, from: &Sender, chan: &str, ctx: &mut ServiceCtx, db: &dyn Store) -> bool {
|
||||
match db.channel(chan) {
|
||||
None => {
|
||||
ctx.notice(me, from.uid, format!("\x02{chan}\x02 isn't registered."));
|
||||
ctx.notice(me, from.uid, t!(ctx, "\x02{chan}\x02 isn't registered.", chan = chan));
|
||||
false
|
||||
}
|
||||
Some(info) if from.account != Some(info.founder.as_str()) => {
|
||||
ctx.notice(me, from.uid, format!("Only \x02{chan}\x02's founder can change access."));
|
||||
ctx.notice(me, from.uid, t!(ctx, "Only \x02{chan}\x02's founder can change access.", chan = chan));
|
||||
false
|
||||
}
|
||||
// Founder, but a staff-suspended channel is frozen — no access changes.
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use echo_api::Store;
|
||||
use echo_api::{Sender, ServiceCtx};
|
||||
use echo_api::t;
|
||||
|
||||
// AKICK <#channel> ADD <mask> [reason] | DEL <mask> | LIST | CLEAR
|
||||
// A mask is a nick!user@host glob or any extban the ircd advertises (named or by
|
||||
|
|
@ -14,12 +15,12 @@ pub fn handle(me: &str, from: &Sender, args: &[&str], ctx: &mut ServiceCtx, db:
|
|||
};
|
||||
match args.get(2).map(|s| s.to_ascii_uppercase()).as_deref() {
|
||||
None | Some("LIST") => match db.channel(chan) {
|
||||
None => ctx.notice(me, from.uid, format!("\x02{chan}\x02 isn't registered.")),
|
||||
Some(info) if info.akick.is_empty() => ctx.notice(me, from.uid, format!("\x02{chan}\x02 has an empty auto-kick list.")),
|
||||
None => ctx.notice(me, from.uid, t!(ctx, "\x02{chan}\x02 isn't registered.", chan = chan)),
|
||||
Some(info) if info.akick.is_empty() => ctx.notice(me, from.uid, t!(ctx, "\x02{chan}\x02 has an empty auto-kick list.", chan = chan)),
|
||||
Some(info) => {
|
||||
ctx.notice(me, from.uid, format!("Auto-kick list for \x02{}\x02:", info.name));
|
||||
ctx.notice(me, from.uid, t!(ctx, "Auto-kick list for \x02{name}\x02:", name = info.name));
|
||||
for k in &info.akick {
|
||||
ctx.notice(me, from.uid, format!(" \x02{}\x02 ({})", k.mask, k.reason));
|
||||
ctx.notice(me, from.uid, t!(ctx, " \x02{mask}\x02 ({reason})", mask = k.mask, reason = k.reason));
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
@ -37,25 +38,25 @@ pub fn handle(me: &str, from: &Sender, args: &[&str], ctx: &mut ServiceCtx, db:
|
|||
echo_api::AkickMask::Host(_) => {}
|
||||
echo_api::AkickMask::Ext(eb, _) => {
|
||||
if !db.extban_offered(eb.name) {
|
||||
ctx.notice(me, from.uid, format!("This network's ircd doesn't offer the \x02{}\x02 extban.", eb.name));
|
||||
ctx.notice(me, from.uid, t!(ctx, "This network's ircd doesn't offer the \x02{name}\x02 extban.", name = eb.name));
|
||||
return;
|
||||
}
|
||||
if !db.extban_enabled(eb.name) {
|
||||
ctx.notice(me, from.uid, format!("The \x02{}\x02 extban isn't enabled on this network.", eb.name));
|
||||
ctx.notice(me, from.uid, t!(ctx, "The \x02{name}\x02 extban isn't enabled on this network.", name = eb.name));
|
||||
return;
|
||||
}
|
||||
}
|
||||
echo_api::AkickMask::Unknown(token) => match db.extban_lookup(token) {
|
||||
None => {
|
||||
ctx.notice(me, from.uid, format!("\x02{token}\x02 isn't a host mask or an extban this network offers."));
|
||||
ctx.notice(me, from.uid, t!(ctx, "\x02{token}\x02 isn't a host mask or an extban this network offers.", token = token));
|
||||
return;
|
||||
}
|
||||
Some(cap) if cap.acting => {
|
||||
ctx.notice(me, from.uid, format!("\x02{}\x02 is an acting extban; auto-kick needs a matching extban or a host mask.", cap.name));
|
||||
ctx.notice(me, from.uid, t!(ctx, "\x02{name}\x02 is an acting extban; auto-kick needs a matching extban or a host mask.", name = cap.name));
|
||||
return;
|
||||
}
|
||||
Some(cap) if !db.extban_enabled(&cap.name) => {
|
||||
ctx.notice(me, from.uid, format!("The \x02{}\x02 extban isn't enabled on this network.", cap.name));
|
||||
ctx.notice(me, from.uid, t!(ctx, "The \x02{name}\x02 extban isn't enabled on this network.", name = cap.name));
|
||||
return;
|
||||
}
|
||||
Some(_) => {}
|
||||
|
|
@ -73,7 +74,7 @@ pub fn handle(me: &str, from: &Sender, args: &[&str], ctx: &mut ServiceCtx, db:
|
|||
if echo_api::ircd_enforced(mask) {
|
||||
ctx.channel_mode(me, chan, &format!("+b {mask}"));
|
||||
}
|
||||
ctx.notice(me, from.uid, format!("Added \x02{mask}\x02 to \x02{chan}\x02's auto-kick list."));
|
||||
ctx.notice(me, from.uid, t!(ctx, "Added \x02{mask}\x02 to \x02{chan}\x02's auto-kick list.", mask = mask, chan = chan));
|
||||
}
|
||||
Err(_) => ctx.notice(me, from.uid, "Sorry, that didn't work. Please try again in a moment."),
|
||||
}
|
||||
|
|
@ -92,9 +93,9 @@ pub fn handle(me: &str, from: &Sender, args: &[&str], ctx: &mut ServiceCtx, db:
|
|||
if echo_api::ircd_enforced(mask) {
|
||||
ctx.channel_mode(me, chan, &format!("-b {mask}"));
|
||||
}
|
||||
ctx.notice(me, from.uid, format!("Removed \x02{mask}\x02 from \x02{chan}\x02's auto-kick list."));
|
||||
ctx.notice(me, from.uid, t!(ctx, "Removed \x02{mask}\x02 from \x02{chan}\x02's auto-kick list.", mask = mask, chan = chan));
|
||||
}
|
||||
Ok(false) => ctx.notice(me, from.uid, format!("\x02{mask}\x02 isn't on \x02{chan}\x02's auto-kick list.")),
|
||||
Ok(false) => ctx.notice(me, from.uid, t!(ctx, "\x02{mask}\x02 isn't on \x02{chan}\x02's auto-kick list.", mask = mask, chan = chan)),
|
||||
Err(_) => ctx.notice(me, from.uid, "Sorry, that didn't work. Please try again in a moment."),
|
||||
}
|
||||
}
|
||||
|
|
@ -110,7 +111,7 @@ pub fn handle(me: &str, from: &Sender, args: &[&str], ctx: &mut ServiceCtx, db:
|
|||
ctx.channel_mode(me, chan, &format!("-b {mask}"));
|
||||
}
|
||||
}
|
||||
ctx.notice(me, from.uid, format!("Cleared \x02{}\x02 entr{} from \x02{chan}\x02's auto-kick list.", masks.len(), if masks.len() == 1 { "y" } else { "ies" }));
|
||||
ctx.notice(me, from.uid, t!(ctx, "Cleared \x02{count}\x02 entr{suffix} from \x02{chan}\x02's auto-kick list.", count = masks.len(), suffix = if masks.len() == 1 { "y" } else { "ies" }, chan = chan));
|
||||
}
|
||||
_ => ctx.notice(me, from.uid, "Syntax: AKICK <#channel> ADD <mask> [reason] | DEL <mask> | LIST | CLEAR"),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use echo_api::Store;
|
||||
use echo_api::{Sender, ServiceCtx};
|
||||
use echo_api::NetView;
|
||||
use echo_api::t;
|
||||
|
||||
// BAN <#channel> <nick> [reason]: ban *!*@host and kick the user.
|
||||
pub fn handle(me: &str, from: &Sender, args: &[&str], ctx: &mut ServiceCtx, net: &dyn NetView, db: &dyn Store) {
|
||||
|
|
@ -12,7 +13,7 @@ pub fn handle(me: &str, from: &Sender, args: &[&str], ctx: &mut ServiceCtx, net:
|
|||
return;
|
||||
}
|
||||
let Some(target) = net.uid_by_nick(nick).map(str::to_string) else {
|
||||
ctx.notice(me, from.uid, format!("\x02{nick}\x02 isn't here."));
|
||||
ctx.notice(me, from.uid, t!(ctx, "\x02{nick}\x02 isn't here.", nick = nick));
|
||||
return;
|
||||
};
|
||||
if super::peace_blocks(me, from, chan, &target, ctx, net, db) {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use echo_api::Store;
|
||||
use echo_api::{Sender, ServiceCtx};
|
||||
use echo_api::t;
|
||||
|
||||
// CLONE <source> <target>: copy a channel's settings (mode lock, access,
|
||||
// auto-kick, description, entry message) into another. Founder of both.
|
||||
|
|
@ -34,5 +35,5 @@ pub fn handle(me: &str, from: &Sender, args: &[&str], ctx: &mut ServiceCtx, db:
|
|||
if let Some(info) = db.channel(dest) {
|
||||
ctx.channel_mode(me, dest, &info.lock_modes());
|
||||
}
|
||||
ctx.notice(me, from.uid, format!("Copied \x02{src}\x02's settings to \x02{dest}\x02."));
|
||||
ctx.notice(me, from.uid, t!(ctx, "Copied \x02{src}\x02's settings to \x02{dest}\x02.", src = src, dest = dest));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use echo_api::Store;
|
||||
use echo_api::{status_mode, Sender, ServiceCtx};
|
||||
use echo_api::NetView;
|
||||
use echo_api::t;
|
||||
|
||||
// ENFORCE <#channel>: re-apply the channel's settings to everyone present —
|
||||
// the mode lock, access status modes, and the auto-kick list.
|
||||
|
|
@ -35,5 +36,5 @@ pub fn handle(me: &str, from: &Sender, args: &[&str], ctx: &mut ServiceCtx, net:
|
|||
}
|
||||
}
|
||||
}
|
||||
ctx.notice(me, from.uid, format!("Re-applied \x02{chan}\x02's settings to everyone present."));
|
||||
ctx.notice(me, from.uid, t!(ctx, "Re-applied \x02{chan}\x02's settings to everyone present.", chan = chan));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use echo_api::Store;
|
||||
use echo_api::{Sender, ServiceCtx};
|
||||
use echo_api::t;
|
||||
|
||||
// ENTRYMSG <#channel> [CLEAR | <text>]: message noticed to users as they join.
|
||||
// With no argument, show the current message.
|
||||
|
|
@ -10,16 +11,16 @@ pub fn handle(me: &str, from: &Sender, args: &[&str], ctx: &mut ServiceCtx, db:
|
|||
};
|
||||
match args.get(2) {
|
||||
None => match db.channel(chan) {
|
||||
None => ctx.notice(me, from.uid, format!("\x02{chan}\x02 isn't registered.")),
|
||||
Some(info) if info.entrymsg.is_empty() => ctx.notice(me, from.uid, format!("\x02{chan}\x02 has no entry message.")),
|
||||
Some(info) => ctx.notice(me, from.uid, format!("Entry message for \x02{chan}\x02: {}", info.entrymsg)),
|
||||
None => ctx.notice(me, from.uid, t!(ctx, "\x02{chan}\x02 isn't registered.", chan = chan)),
|
||||
Some(info) if info.entrymsg.is_empty() => ctx.notice(me, from.uid, t!(ctx, "\x02{chan}\x02 has no entry message.", chan = chan)),
|
||||
Some(info) => ctx.notice(me, from.uid, t!(ctx, "Entry message for \x02{chan}\x02: {msg}", chan = chan, msg = info.entrymsg)),
|
||||
},
|
||||
Some(&kw) if kw.eq_ignore_ascii_case("CLEAR") => {
|
||||
if !super::require_op(me, from, chan, ctx, db) {
|
||||
return;
|
||||
}
|
||||
match db.set_entrymsg(chan, "") {
|
||||
Ok(()) => ctx.notice(me, from.uid, format!("Entry message for \x02{chan}\x02 cleared.")),
|
||||
Ok(()) => ctx.notice(me, from.uid, t!(ctx, "Entry message for \x02{chan}\x02 cleared.", chan = chan)),
|
||||
Err(_) => ctx.notice(me, from.uid, "Sorry, that didn't work. Please try again in a moment."),
|
||||
}
|
||||
}
|
||||
|
|
@ -28,7 +29,7 @@ pub fn handle(me: &str, from: &Sender, args: &[&str], ctx: &mut ServiceCtx, db:
|
|||
return;
|
||||
}
|
||||
match db.set_entrymsg(chan, &args[2..].join(" ")) {
|
||||
Ok(()) => ctx.notice(me, from.uid, format!("Entry message for \x02{chan}\x02 updated.")),
|
||||
Ok(()) => ctx.notice(me, from.uid, t!(ctx, "Entry message for \x02{chan}\x02 updated.", chan = chan)),
|
||||
Err(_) => ctx.notice(me, from.uid, "Sorry, that didn't work. Please try again in a moment."),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
use echo_api::{Flags, Sender, ServiceCtx, Store, ACCESS_FLAGS};
|
||||
use echo_api::t;
|
||||
|
||||
// FLAGS <#channel> [account [+/-flags]]: the granular access model. With no
|
||||
// account, list the access entries and their flags; with an account, show or
|
||||
|
|
@ -8,7 +9,7 @@ use echo_api::{Flags, Sender, ServiceCtx, Store, ACCESS_FLAGS};
|
|||
// preset ("op"/"sop"/…) or a raw flag string — resolves through `Flags`.
|
||||
pub fn handle(me: &str, from: &Sender, chan: &str, args: &[&str], ctx: &mut ServiceCtx, db: &mut dyn Store) {
|
||||
let Some(info) = db.channel(chan) else {
|
||||
ctx.notice(me, from.uid, format!("\x02{chan}\x02 isn't registered."));
|
||||
ctx.notice(me, from.uid, t!(ctx, "\x02{chan}\x02 isn't registered.", chan = chan));
|
||||
return;
|
||||
};
|
||||
let is_founder = from.account == Some(info.founder.as_str());
|
||||
|
|
@ -17,15 +18,15 @@ pub fn handle(me: &str, from: &Sender, chan: &str, args: &[&str], ctx: &mut Serv
|
|||
// FLAGS <#chan> — list.
|
||||
let Some(&target) = args.get(2) else {
|
||||
if !is_founder && !caps.op {
|
||||
ctx.notice(me, from.uid, format!("You need access to \x02{chan}\x02 to view its flags."));
|
||||
ctx.notice(me, from.uid, t!(ctx, "You need access to \x02{chan}\x02 to view its flags.", chan = chan));
|
||||
return;
|
||||
}
|
||||
ctx.notice(me, from.uid, format!("Access flags for \x02{chan}\x02:"));
|
||||
ctx.notice(me, from.uid, format!(" \x02{}\x02 (founder): \x02f\x02", info.founder));
|
||||
ctx.notice(me, from.uid, t!(ctx, "Access flags for \x02{chan}\x02:", chan = chan));
|
||||
ctx.notice(me, from.uid, t!(ctx, " \x02{founder}\x02 (founder): \x02f\x02", founder = info.founder));
|
||||
for a in &info.access {
|
||||
ctx.notice(me, from.uid, format!(" \x02{}\x02: \x02{}\x02", a.account, Flags::from_level(&a.level).to_letters()));
|
||||
ctx.notice(me, from.uid, t!(ctx, " \x02{account}\x02: \x02{flags}\x02", account = a.account, flags = Flags::from_level(&a.level).to_letters()));
|
||||
}
|
||||
ctx.notice(me, from.uid, format!("End of flags ({} entr{}).", info.access.len() + 1, if info.access.is_empty() { "y" } else { "ies" }));
|
||||
ctx.notice(me, from.uid, t!(ctx, "End of flags ({count} entr{suffix}).", count = info.access.len() + 1, suffix = if info.access.is_empty() { "y" } else { "ies" }));
|
||||
return;
|
||||
};
|
||||
|
||||
|
|
@ -34,15 +35,15 @@ pub fn handle(me: &str, from: &Sender, chan: &str, args: &[&str], ctx: &mut Serv
|
|||
// FLAGS <#chan> <account> — show one.
|
||||
let Some(&delta) = args.get(3) else {
|
||||
match entry.as_deref().map(|l| Flags::from_level(l).to_letters()) {
|
||||
Some(f) if !f.is_empty() => ctx.notice(me, from.uid, format!("\x02{target}\x02 on \x02{chan}\x02: \x02{f}\x02")),
|
||||
_ => ctx.notice(me, from.uid, format!("\x02{target}\x02 has no access to \x02{chan}\x02.")),
|
||||
Some(f) if !f.is_empty() => ctx.notice(me, from.uid, t!(ctx, "\x02{target}\x02 on \x02{chan}\x02: \x02{flags}\x02", target = target, chan = chan, flags = f)),
|
||||
_ => ctx.notice(me, from.uid, t!(ctx, "\x02{target}\x02 has no access to \x02{chan}\x02.", target = target, chan = chan)),
|
||||
}
|
||||
return;
|
||||
};
|
||||
|
||||
// FLAGS <#chan> <account> <+/-flags> — modify.
|
||||
if !is_founder && !caps.access {
|
||||
ctx.notice(me, from.uid, format!("You need the founder or the \x02a\x02 flag to change access on \x02{chan}\x02."));
|
||||
ctx.notice(me, from.uid, t!(ctx, "You need the founder or the \x02a\x02 flag to change access on \x02{chan}\x02.", chan = chan));
|
||||
return;
|
||||
}
|
||||
if super::suspended_block(me, from, chan, ctx, db) {
|
||||
|
|
@ -55,7 +56,7 @@ pub fn handle(me: &str, from: &Sender, chan: &str, args: &[&str], ctx: &mut Serv
|
|||
let updated = match Flags::from_level(entry.as_deref().unwrap_or("")).apply_delta(delta) {
|
||||
Ok(f) => f,
|
||||
Err(bad) => {
|
||||
ctx.notice(me, from.uid, format!("\x02{bad}\x02 isn't a valid flag. Valid flags: \x02{ACCESS_FLAGS}\x02."));
|
||||
ctx.notice(me, from.uid, t!(ctx, "\x02{bad}\x02 isn't a valid flag. Valid flags: \x02{valid}\x02.", bad = bad, valid = ACCESS_FLAGS));
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
|
@ -63,19 +64,19 @@ pub fn handle(me: &str, from: &Sender, chan: &str, args: &[&str], ctx: &mut Serv
|
|||
// `f` (founder/co-founder) — otherwise a delegate could mint a founder-equivalent
|
||||
// entry (Rank::Founder) and seize the channel.
|
||||
if !is_founder && updated.has(echo_api::Flag::Founder) {
|
||||
ctx.notice(me, from.uid, format!("Only the founder can grant the \x02f\x02 flag on \x02{chan}\x02."));
|
||||
ctx.notice(me, from.uid, t!(ctx, "Only the founder can grant the \x02f\x02 flag on \x02{chan}\x02.", chan = chan));
|
||||
return;
|
||||
}
|
||||
if updated.is_empty() {
|
||||
match db.access_del(chan, target) {
|
||||
Ok(true) => ctx.notice(me, from.uid, format!("Cleared \x02{target}\x02's access to \x02{chan}\x02.")),
|
||||
_ => ctx.notice(me, from.uid, format!("\x02{target}\x02 had no access to \x02{chan}\x02.")),
|
||||
Ok(true) => ctx.notice(me, from.uid, t!(ctx, "Cleared \x02{target}\x02's access to \x02{chan}\x02.", target = target, chan = chan)),
|
||||
_ => ctx.notice(me, from.uid, t!(ctx, "\x02{target}\x02 had no access to \x02{chan}\x02.", target = target, chan = chan)),
|
||||
}
|
||||
return;
|
||||
}
|
||||
let letters = updated.to_letters();
|
||||
match db.access_add(chan, target, &letters) {
|
||||
Ok(()) => ctx.notice(me, from.uid, format!("\x02{target}\x02 on \x02{chan}\x02 now holds \x02{letters}\x02.")),
|
||||
Ok(()) => ctx.notice(me, from.uid, t!(ctx, "\x02{target}\x02 on \x02{chan}\x02 now holds \x02{letters}\x02.", target = target, chan = chan, letters = letters)),
|
||||
Err(_) => ctx.notice(me, from.uid, "Sorry, that didn't work. Please try again in a moment."),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use echo_api::Store;
|
||||
use echo_api::{Sender, ServiceCtx};
|
||||
use echo_api::NetView;
|
||||
use echo_api::t;
|
||||
|
||||
// GETKEY <#channel>: report the channel key (+k), for ops who need to let
|
||||
// someone in.
|
||||
|
|
@ -13,7 +14,7 @@ pub fn handle(me: &str, from: &Sender, args: &[&str], ctx: &mut ServiceCtx, net:
|
|||
return;
|
||||
}
|
||||
match net.channel_key(chan) {
|
||||
Some(key) => ctx.notice(me, from.uid, format!("Key for \x02{chan}\x02 is \x02{key}\x02.")),
|
||||
None => ctx.notice(me, from.uid, format!("\x02{chan}\x02 has no key set.")),
|
||||
Some(key) => ctx.notice(me, from.uid, t!(ctx, "Key for \x02{chan}\x02 is \x02{key}\x02.", chan = chan, key = key)),
|
||||
None => ctx.notice(me, from.uid, t!(ctx, "\x02{chan}\x02 has no key set.", chan = chan)),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use echo_api::Store;
|
||||
use echo_api::{Sender, ServiceCtx};
|
||||
use echo_api::NetView;
|
||||
use echo_api::t;
|
||||
|
||||
// INVITE <#channel> [nick]: invite a user (self if no nick) into the channel.
|
||||
pub fn handle(me: &str, from: &Sender, args: &[&str], ctx: &mut ServiceCtx, net: &dyn NetView, db: &dyn Store) {
|
||||
|
|
@ -15,12 +16,12 @@ pub fn handle(me: &str, from: &Sender, args: &[&str], ctx: &mut ServiceCtx, net:
|
|||
Some(&nick) => match net.uid_by_nick(nick) {
|
||||
Some(u) => u.to_string(),
|
||||
None => {
|
||||
ctx.notice(me, from.uid, format!("\x02{nick}\x02 isn't here."));
|
||||
ctx.notice(me, from.uid, t!(ctx, "\x02{nick}\x02 isn't here.", nick = nick));
|
||||
return;
|
||||
}
|
||||
},
|
||||
None => from.uid.to_string(),
|
||||
};
|
||||
ctx.invite(me, &target, chan);
|
||||
ctx.notice(me, from.uid, format!("Invited to \x02{chan}\x02."));
|
||||
ctx.notice(me, from.uid, t!(ctx, "Invited to \x02{chan}\x02.", chan = chan));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use echo_api::Store;
|
||||
use echo_api::{Sender, ServiceCtx};
|
||||
use echo_api::NetView;
|
||||
use echo_api::t;
|
||||
|
||||
// KICK <#channel> <nick> [reason]: kick a user.
|
||||
pub fn handle(me: &str, from: &Sender, args: &[&str], ctx: &mut ServiceCtx, net: &dyn NetView, db: &dyn Store) {
|
||||
|
|
@ -12,7 +13,7 @@ pub fn handle(me: &str, from: &Sender, args: &[&str], ctx: &mut ServiceCtx, net:
|
|||
return;
|
||||
}
|
||||
let Some(target) = net.uid_by_nick(nick) else {
|
||||
ctx.notice(me, from.uid, format!("\x02{nick}\x02 isn't here."));
|
||||
ctx.notice(me, from.uid, t!(ctx, "\x02{nick}\x02 isn't here.", nick = nick));
|
||||
return;
|
||||
};
|
||||
if super::peace_blocks(me, from, chan, target, ctx, net, db) {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use echo_api::Store;
|
||||
use echo_api::{AccessRole, LevelCap, Sender, ServiceCtx};
|
||||
use echo_api::t;
|
||||
|
||||
// LEVELS <#channel> [SET <capability> <tier> | RESET <capability>]
|
||||
// Tune which access tier holds each channel capability (OP, TOPIC, INVITE, ACCESS).
|
||||
|
|
@ -20,16 +21,16 @@ pub fn handle(me: &str, from: &Sender, args: &[&str], ctx: &mut ServiceCtx, db:
|
|||
|
||||
fn list(me: &str, from: &Sender, chan: &str, ctx: &mut ServiceCtx, db: &dyn Store) {
|
||||
let Some(info) = db.channel(chan) else {
|
||||
ctx.notice(me, from.uid, format!("\x02{chan}\x02 isn't registered."));
|
||||
ctx.notice(me, from.uid, t!(ctx, "\x02{chan}\x02 isn't registered.", chan = chan));
|
||||
return;
|
||||
};
|
||||
ctx.notice(me, from.uid, format!("Access levels for \x02{}\x02 (capability → minimum tier):", info.name));
|
||||
ctx.notice(me, from.uid, t!(ctx, "Access levels for \x02{name}\x02 (capability → minimum tier):", name = info.name));
|
||||
for cap in LevelCap::ALL {
|
||||
let (tier, tag) = match info.levels.iter().find(|(c, _)| *c == cap) {
|
||||
Some((_, role)) => (*role, " (custom)"),
|
||||
None => (cap.default_role(), ""),
|
||||
};
|
||||
ctx.notice(me, from.uid, format!(" \x02{}\x02 — {}{}", cap.name(), tier_word(tier), tag));
|
||||
ctx.notice(me, from.uid, t!(ctx, " \x02{cap}\x02 — {tier}{tag}", cap = cap.name(), tier = tier_word(tier), tag = tag));
|
||||
}
|
||||
ctx.notice(me, from.uid, "Founder: \x02LEVELS <#chan> SET <capability> <tier>\x02 grants it to that tier and above; \x02RESET\x02 restores the default.");
|
||||
}
|
||||
|
|
@ -58,7 +59,7 @@ fn set(me: &str, from: &Sender, chan: &str, rest: &[&str], ctx: &mut ServiceCtx,
|
|||
}
|
||||
};
|
||||
match db.level_set(chan, cap.name(), tier_word(role)) {
|
||||
Ok(()) => ctx.notice(me, from.uid, format!("\x02{}\x02 on \x02{chan}\x02 is now held by \x02{}\x02 and above.", cap.name(), tier_word(role))),
|
||||
Ok(()) => ctx.notice(me, from.uid, t!(ctx, "\x02{cap}\x02 on \x02{chan}\x02 is now held by \x02{tier}\x02 and above.", cap = cap.name(), chan = chan, tier = tier_word(role))),
|
||||
Err(_) => ctx.notice(me, from.uid, "Sorry, that didn't work. Please try again in a moment."),
|
||||
}
|
||||
}
|
||||
|
|
@ -76,8 +77,8 @@ fn reset(me: &str, from: &Sender, chan: &str, cap_arg: Option<&str>, ctx: &mut S
|
|||
return;
|
||||
};
|
||||
match db.level_reset(chan, cap.name()) {
|
||||
Ok(true) => ctx.notice(me, from.uid, format!("\x02{}\x02 on \x02{chan}\x02 is back to its default tier (\x02{}\x02).", cap.name(), tier_word(cap.default_role()))),
|
||||
Ok(false) => ctx.notice(me, from.uid, format!("\x02{}\x02 on \x02{chan}\x02 has no custom level.", cap.name())),
|
||||
Ok(true) => ctx.notice(me, from.uid, t!(ctx, "\x02{cap}\x02 on \x02{chan}\x02 is back to its default tier (\x02{tier}\x02).", cap = cap.name(), chan = chan, tier = tier_word(cap.default_role()))),
|
||||
Ok(false) => ctx.notice(me, from.uid, t!(ctx, "\x02{cap}\x02 on \x02{chan}\x02 has no custom level.", cap = cap.name(), chan = chan)),
|
||||
Err(_) => ctx.notice(me, from.uid, "Sorry, that didn't work. Please try again in a moment."),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use echo_api::{ChanError, ChannelView, ForbidKind, Priv, Store};
|
||||
use echo_api::{HelpEntry, Sender, Service, ServiceCtx};
|
||||
use echo_api::NetView;
|
||||
use echo_api::t;
|
||||
|
||||
#[path = "mode.rs"]
|
||||
mod mode;
|
||||
|
|
@ -141,11 +142,11 @@ impl Service for ChanServ {
|
|||
};
|
||||
// You can only register a channel you actually control right now.
|
||||
if !net.is_op(chan, from.uid) {
|
||||
ctx.notice(me, from.uid, format!("You must be a channel operator (\x02@\x02) in \x02{chan}\x02 to register it."));
|
||||
ctx.notice(me, from.uid, t!(ctx, "You must be a channel operator (\x02@\x02) in \x02{chan}\x02 to register it.", chan = chan));
|
||||
return;
|
||||
}
|
||||
if let Some(reason) = db.is_forbidden(ForbidKind::Chan, chan) {
|
||||
ctx.notice(me, from.uid, format!("\x02{chan}\x02 can't be registered: {reason}"));
|
||||
ctx.notice(me, from.uid, t!(ctx, "\x02{chan}\x02 can't be registered: {reason}", chan = chan, reason = reason));
|
||||
return;
|
||||
}
|
||||
// Refuse a look-alike / mixed-script channel name (e.g. a Cyrillic
|
||||
|
|
@ -161,15 +162,15 @@ impl Service for ChanServ {
|
|||
Ok(()) => {
|
||||
ctx.channel_mode(me, chan, "+r"); // mark the channel registered
|
||||
ctx.count("chanserv.register");
|
||||
ctx.notice(me, from.uid, format!("\x02{chan}\x02 is now registered and you are its founder. Enjoy!"));
|
||||
ctx.notice(me, from.uid, t!(ctx, "\x02{chan}\x02 is now registered and you are its founder. Enjoy!", chan = chan));
|
||||
// Auto-assign the network's default bot, if one is set (BotServ AUTOASSIGN).
|
||||
if let Some(bot) = db.default_bot() {
|
||||
if db.assign_bot(chan, &bot).is_ok() {
|
||||
ctx.notice(me, from.uid, format!("Assigned \x02{bot}\x02 to \x02{chan}\x02. Change it with \x02/msg BotServ ASSIGN\x02."));
|
||||
ctx.notice(me, from.uid, t!(ctx, "Assigned \x02{bot}\x02 to \x02{chan}\x02. Change it with \x02/msg BotServ ASSIGN\x02.", bot = bot, chan = chan));
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(ChanError::Exists) => ctx.notice(me, from.uid, format!("\x02{chan}\x02 is already registered. Try \x02INFO {chan}\x02 to see who owns it.")),
|
||||
Err(ChanError::Exists) => ctx.notice(me, from.uid, t!(ctx, "\x02{chan}\x02 is already registered. Try \x02INFO {chan}\x02 to see who owns it.", chan = chan)),
|
||||
Err(_) => ctx.notice(me, from.uid, "Sorry, that didn't work. Please try again in a moment."),
|
||||
}
|
||||
}
|
||||
|
|
@ -180,20 +181,20 @@ impl Service for ChanServ {
|
|||
};
|
||||
match db.channel(chan) {
|
||||
Some(info) => {
|
||||
ctx.notice(me, from.uid, format!("Information for \x02{}\x02:", info.name));
|
||||
ctx.notice(me, from.uid, format!(" Founder : \x02{}\x02", info.founder));
|
||||
ctx.notice(me, from.uid, t!(ctx, "Information for \x02{name}\x02:", name = info.name));
|
||||
ctx.notice(me, from.uid, t!(ctx, " Founder : \x02{founder}\x02", founder = info.founder));
|
||||
if !info.desc.is_empty() {
|
||||
ctx.notice(me, from.uid, format!(" Description: {}", info.desc));
|
||||
ctx.notice(me, from.uid, t!(ctx, " Description: {desc}", desc = info.desc));
|
||||
}
|
||||
if !info.url.is_empty() {
|
||||
ctx.notice(me, from.uid, format!(" URL : {}", info.url));
|
||||
ctx.notice(me, from.uid, t!(ctx, " URL : {url}", url = info.url));
|
||||
}
|
||||
if !info.email.is_empty() {
|
||||
ctx.notice(me, from.uid, format!(" Email : {}", info.email));
|
||||
ctx.notice(me, from.uid, t!(ctx, " Email : {email}", email = info.email));
|
||||
}
|
||||
ctx.notice(me, from.uid, format!(" Registered : {}", echo_api::human_time(info.ts)));
|
||||
ctx.notice(me, from.uid, t!(ctx, " Registered : {when}", when = echo_api::human_time(info.ts)));
|
||||
if let Some(s) = db.channel_suspension(chan) {
|
||||
ctx.notice(me, from.uid, format!(" Suspended : by \x02{}\x02 — {}", s.by, s.reason));
|
||||
ctx.notice(me, from.uid, t!(ctx, " Suspended : by \x02{by}\x02 — {reason}", by = s.by, reason = s.reason));
|
||||
}
|
||||
let mut opts = Vec::new();
|
||||
if info.signkick { opts.push("SIGNKICK"); }
|
||||
|
|
@ -203,16 +204,16 @@ impl Service for ChanServ {
|
|||
if info.keeptopic { opts.push("KEEPTOPIC"); }
|
||||
if info.topiclock { opts.push("TOPICLOCK"); }
|
||||
if !opts.is_empty() {
|
||||
ctx.notice(me, from.uid, format!(" Options : {}", opts.join(", ")));
|
||||
ctx.notice(me, from.uid, t!(ctx, " Options : {options}", options = opts.join(", ")));
|
||||
}
|
||||
// A staff note is shown to operators only.
|
||||
if from.privs.has(Priv::Auspex) {
|
||||
if let Some(note) = db.channel_note(chan) {
|
||||
ctx.notice(me, from.uid, format!(" Staff note : {note}"));
|
||||
ctx.notice(me, from.uid, t!(ctx, " Staff note : {note}", note = note));
|
||||
}
|
||||
}
|
||||
}
|
||||
None => ctx.notice(me, from.uid, format!("\x02{chan}\x02 isn't registered.")),
|
||||
None => ctx.notice(me, from.uid, t!(ctx, "\x02{chan}\x02 isn't registered.", chan = chan)),
|
||||
}
|
||||
}
|
||||
Some("DROP") => {
|
||||
|
|
@ -224,12 +225,12 @@ impl Service for ChanServ {
|
|||
let founder = match db.channel(chan) {
|
||||
Some(info) => info.founder.clone(),
|
||||
None => {
|
||||
ctx.notice(me, from.uid, format!("\x02{chan}\x02 isn't registered."));
|
||||
ctx.notice(me, from.uid, t!(ctx, "\x02{chan}\x02 isn't registered.", chan = chan));
|
||||
return;
|
||||
}
|
||||
};
|
||||
if from.account != Some(founder.as_str()) {
|
||||
ctx.notice(me, from.uid, format!("Only \x02{chan}\x02's founder can drop it."));
|
||||
ctx.notice(me, from.uid, t!(ctx, "Only \x02{chan}\x02's founder can drop it.", chan = chan));
|
||||
return;
|
||||
}
|
||||
if suspended_block(me, from, chan, ctx, db) {
|
||||
|
|
@ -239,7 +240,7 @@ impl Service for ChanServ {
|
|||
Ok(()) => {
|
||||
ctx.channel_mode(me, chan, "-r"); // no longer registered
|
||||
ctx.count("chanserv.drop");
|
||||
ctx.notice(me, from.uid, format!("\x02{chan}\x02 has been dropped and is no longer registered."));
|
||||
ctx.notice(me, from.uid, t!(ctx, "\x02{chan}\x02 has been dropped and is no longer registered.", chan = chan));
|
||||
}
|
||||
Err(_) => ctx.notice(me, from.uid, "Sorry, that didn't work. Please try again in a moment."),
|
||||
}
|
||||
|
|
@ -252,11 +253,11 @@ impl Service for ChanServ {
|
|||
// No modes given: show the current lock.
|
||||
if args.len() <= 2 {
|
||||
match db.channel(chan) {
|
||||
None => ctx.notice(me, from.uid, format!("\x02{chan}\x02 isn't registered.")),
|
||||
None => ctx.notice(me, from.uid, t!(ctx, "\x02{chan}\x02 isn't registered.", chan = chan)),
|
||||
Some(info) if info.lock_on.is_empty() && info.lock_off.is_empty() => {
|
||||
ctx.notice(me, from.uid, format!("\x02{}\x02 has no mode lock set.", info.name));
|
||||
ctx.notice(me, from.uid, t!(ctx, "\x02{name}\x02 has no mode lock set.", name = info.name));
|
||||
}
|
||||
Some(info) => ctx.notice(me, from.uid, format!("Mode lock for \x02{}\x02: \x02{}\x02", info.name, show_mlock(&info))),
|
||||
Some(info) => ctx.notice(me, from.uid, t!(ctx, "Mode lock for \x02{name}\x02: \x02{lock}\x02", name = info.name, lock = show_mlock(&info))),
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
@ -264,12 +265,12 @@ impl Service for ChanServ {
|
|||
let founder = match db.channel(chan) {
|
||||
Some(info) => info.founder.clone(),
|
||||
None => {
|
||||
ctx.notice(me, from.uid, format!("\x02{chan}\x02 isn't registered."));
|
||||
ctx.notice(me, from.uid, t!(ctx, "\x02{chan}\x02 isn't registered.", chan = chan));
|
||||
return;
|
||||
}
|
||||
};
|
||||
if from.account != Some(founder.as_str()) {
|
||||
ctx.notice(me, from.uid, format!("Only \x02{chan}\x02's founder can set its mode lock."));
|
||||
ctx.notice(me, from.uid, t!(ctx, "Only \x02{chan}\x02's founder can set its mode lock.", chan = chan));
|
||||
return;
|
||||
}
|
||||
if suspended_block(me, from, chan, ctx, db) {
|
||||
|
|
@ -281,7 +282,7 @@ impl Service for ChanServ {
|
|||
if let Some(info) = db.channel(chan) {
|
||||
ctx.channel_mode(me, chan, &info.lock_modes()); // apply it now
|
||||
}
|
||||
ctx.notice(me, from.uid, format!("Mode lock for \x02{chan}\x02 updated."));
|
||||
ctx.notice(me, from.uid, t!(ctx, "Mode lock for \x02{chan}\x02 updated.", chan = chan));
|
||||
}
|
||||
Err(_) => ctx.notice(me, from.uid, "Sorry, that didn't work. Please try again in a moment."),
|
||||
}
|
||||
|
|
@ -334,7 +335,7 @@ impl Service for ChanServ {
|
|||
Some("HELP") => echo_api::help(me, from, ctx, BLURB, TOPICS, args.get(1).copied()),
|
||||
// Direct `/msg ChanServ FOO` earns this reply; the fantasy router
|
||||
// gates on COMMANDS first so an in-channel `!foo` stays silent.
|
||||
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, t!(ctx, "I don't know the command \x02{other}\x02. Try \x02HELP\x02.", other = other)),
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
|
|
@ -347,12 +348,12 @@ fn require_founder(me: &str, from: &Sender, chan: &str, ctx: &mut ServiceCtx, db
|
|||
}
|
||||
match db.channel(chan) {
|
||||
None => {
|
||||
ctx.notice(me, from.uid, format!("\x02{chan}\x02 isn't registered."));
|
||||
ctx.notice(me, from.uid, t!(ctx, "\x02{chan}\x02 isn't registered.", chan = chan));
|
||||
false
|
||||
}
|
||||
Some(info) if from.account == Some(info.founder.as_str()) => true,
|
||||
_ => {
|
||||
ctx.notice(me, from.uid, format!("Only \x02{chan}\x02's founder can do that."));
|
||||
ctx.notice(me, from.uid, t!(ctx, "Only \x02{chan}\x02's founder can do that.", chan = chan));
|
||||
false
|
||||
}
|
||||
}
|
||||
|
|
@ -365,12 +366,12 @@ fn require_op(me: &str, from: &Sender, chan: &str, ctx: &mut ServiceCtx, db: &dy
|
|||
}
|
||||
match (from.account, db.channel(chan)) {
|
||||
(_, None) => {
|
||||
ctx.notice(me, from.uid, format!("\x02{chan}\x02 isn't registered."));
|
||||
ctx.notice(me, from.uid, t!(ctx, "\x02{chan}\x02 isn't registered.", chan = chan));
|
||||
false
|
||||
}
|
||||
(Some(acc), Some(info)) if info.is_op(acc) => true,
|
||||
_ => {
|
||||
ctx.notice(me, from.uid, format!("You need operator access to \x02{chan}\x02."));
|
||||
ctx.notice(me, from.uid, t!(ctx, "You need operator access to \x02{chan}\x02.", chan = chan));
|
||||
false
|
||||
}
|
||||
}
|
||||
|
|
@ -379,7 +380,7 @@ fn require_op(me: &str, from: &Sender, chan: &str, ctx: &mut ServiceCtx, db: &dy
|
|||
// A suspended channel is frozen: ChanServ won't manage it (returns true + notices).
|
||||
fn suspended_block(me: &str, from: &Sender, chan: &str, ctx: &mut ServiceCtx, db: &dyn Store) -> bool {
|
||||
if db.is_channel_suspended(chan) {
|
||||
ctx.notice(me, from.uid, format!("\x02{chan}\x02 is suspended by network staff and can't be managed right now."));
|
||||
ctx.notice(me, from.uid, t!(ctx, "\x02{chan}\x02 is suspended by network staff and can't be managed right now.", chan = chan));
|
||||
return true;
|
||||
}
|
||||
false
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use echo_api::Store;
|
||||
use echo_api::{Sender, ServiceCtx};
|
||||
use echo_api::t;
|
||||
|
||||
// LIST: show all registered channels.
|
||||
pub fn handle(me: &str, from: &Sender, _args: &[&str], ctx: &mut ServiceCtx, db: &dyn Store) {
|
||||
|
|
@ -10,8 +11,8 @@ pub fn handle(me: &str, from: &Sender, _args: &[&str], ctx: &mut ServiceCtx, db:
|
|||
return;
|
||||
}
|
||||
names.sort_unstable();
|
||||
ctx.notice(me, from.uid, format!("Registered channels ({}):", names.len()));
|
||||
ctx.notice(me, from.uid, t!(ctx, "Registered channels ({count}):", count = names.len()));
|
||||
for n in names {
|
||||
ctx.notice(me, from.uid, format!(" \x02{n}\x02"));
|
||||
ctx.notice(me, from.uid, t!(ctx, " \x02{n}\x02", n = n));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use echo_api::Store;
|
||||
use echo_api::{Sender, ServiceCtx};
|
||||
use echo_api::t;
|
||||
|
||||
// MODE <#channel> <modes>: the founder sets channel modes via ChanServ. Extban
|
||||
// arguments on the ban-family list modes (+b/+e/+I) are held to the same
|
||||
|
|
@ -16,12 +17,12 @@ pub fn handle(me: &str, from: &Sender, args: &[&str], ctx: &mut ServiceCtx, db:
|
|||
let founder = match db.channel(chan) {
|
||||
Some(info) => info.founder.clone(),
|
||||
None => {
|
||||
ctx.notice(me, from.uid, format!("\x02{chan}\x02 isn't registered."));
|
||||
ctx.notice(me, from.uid, t!(ctx, "\x02{chan}\x02 isn't registered.", chan = chan));
|
||||
return;
|
||||
}
|
||||
};
|
||||
if from.account != Some(founder.as_str()) {
|
||||
ctx.notice(me, from.uid, format!("Only \x02{chan}\x02's founder can change its modes."));
|
||||
ctx.notice(me, from.uid, t!(ctx, "Only \x02{chan}\x02's founder can change its modes.", chan = chan));
|
||||
return;
|
||||
}
|
||||
if super::suspended_block(me, from, chan, ctx, db) {
|
||||
|
|
@ -32,18 +33,18 @@ pub fn handle(me: &str, from: &Sender, args: &[&str], ctx: &mut ServiceCtx, db:
|
|||
let core = mask.strip_prefix('!').unwrap_or(mask); // extbans may be inverted
|
||||
if let echo_api::AkickMask::Ext(eb, _) = echo_api::AkickMask::parse(core) {
|
||||
if !db.extban_offered(eb.name) {
|
||||
ctx.notice(me, from.uid, format!("This network's ircd doesn't offer the \x02{}\x02 extban.", eb.name));
|
||||
ctx.notice(me, from.uid, t!(ctx, "This network's ircd doesn't offer the \x02{name}\x02 extban.", name = eb.name));
|
||||
return;
|
||||
}
|
||||
if !db.extban_enabled(eb.name) {
|
||||
ctx.notice(me, from.uid, format!("The \x02{}\x02 extban isn't enabled on this network.", eb.name));
|
||||
ctx.notice(me, from.uid, t!(ctx, "The \x02{name}\x02 extban isn't enabled on this network.", name = eb.name));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
let modes = args[2..].join(" ");
|
||||
ctx.channel_mode(me, chan, &modes);
|
||||
ctx.notice(me, from.uid, format!("Set \x02{modes}\x02 on \x02{chan}\x02."));
|
||||
ctx.notice(me, from.uid, t!(ctx, "Set \x02{modes}\x02 on \x02{chan}\x02.", modes = modes, chan = chan));
|
||||
}
|
||||
|
||||
// The parameters attached to +b/-b/+e/-e/+I/-I in a `<modes> [params...]` change.
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
use echo_api::{Priv, Sender, ServiceCtx, Store};
|
||||
use echo_api::t;
|
||||
|
||||
// NOEXPIRE <#channel> {ON|OFF}: pin a channel so inactivity-expiry never drops
|
||||
// it (or lift the pin). Oper-only (Priv::Admin).
|
||||
|
|
@ -12,13 +13,13 @@ pub fn handle(me: &str, from: &Sender, args: &[&str], ctx: &mut ServiceCtx, db:
|
|||
return;
|
||||
};
|
||||
if db.channel(chan).is_none() {
|
||||
ctx.notice(me, from.uid, format!("\x02{chan}\x02 isn't registered."));
|
||||
ctx.notice(me, from.uid, t!(ctx, "\x02{chan}\x02 isn't registered.", chan = chan));
|
||||
return;
|
||||
}
|
||||
match db.set_channel_noexpire(chan, on) {
|
||||
Ok(true) if on => ctx.notice(me, from.uid, format!("\x02{chan}\x02 will no longer expire.")),
|
||||
Ok(true) => ctx.notice(me, from.uid, format!("\x02{chan}\x02 can expire from inactivity again.")),
|
||||
Ok(false) => ctx.notice(me, from.uid, format!("\x02{chan}\x02 was already set that way.")),
|
||||
Ok(true) if on => ctx.notice(me, from.uid, t!(ctx, "\x02{chan}\x02 will no longer expire.", chan = chan)),
|
||||
Ok(true) => ctx.notice(me, from.uid, t!(ctx, "\x02{chan}\x02 can expire from inactivity again.", chan = chan)),
|
||||
Ok(false) => ctx.notice(me, from.uid, t!(ctx, "\x02{chan}\x02 was already set that way.", chan = chan)),
|
||||
Err(_) => ctx.notice(me, from.uid, "Sorry, that didn't work. Please try again in a moment."),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use echo_api::Store;
|
||||
use echo_api::{Sender, ServiceCtx};
|
||||
use echo_api::NetView;
|
||||
use echo_api::t;
|
||||
|
||||
// OP/DEOP/VOICE/DEVOICE <#channel> [nick]: set a status mode on a user (self if
|
||||
// no nick given). `mode` is the mode to apply, e.g. "+o".
|
||||
|
|
@ -22,7 +23,7 @@ pub fn handle(me: &str, from: &Sender, mode: &str, args: &[&str], ctx: &mut Serv
|
|||
Some(&nick) => match net.uid_by_nick(nick) {
|
||||
Some(u) => u.to_string(),
|
||||
None => {
|
||||
ctx.notice(me, from.uid, format!("\x02{nick}\x02 isn't here."));
|
||||
ctx.notice(me, from.uid, t!(ctx, "\x02{nick}\x02 isn't here.", nick = nick));
|
||||
return;
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use echo_api::{Sender, ServiceCtx};
|
||||
use echo_api::NetView;
|
||||
use echo_api::t;
|
||||
|
||||
// SEEN <nick> — network-wide: when a nick was last seen, and doing what.
|
||||
// SEEN <#channel> <nick> — channel-scoped: when last active there, and their last
|
||||
|
|
@ -15,26 +16,26 @@ pub fn handle(me: &str, from: &Sender, args: &[&str], ctx: &mut ServiceCtx, net:
|
|||
// Present in THIS channel right now — online elsewhere doesn't count.
|
||||
let here = net.uid_by_nick(nick).is_some_and(|uid| net.channel_members(chan).iter().any(|m| m == uid));
|
||||
if here {
|
||||
ctx.notice(me, from.uid, format!("{}: \x02{nick}\x02 is here right now.", from.nick));
|
||||
ctx.notice(me, from.uid, t!(ctx, "{who}: \x02{nick}\x02 is here right now.", who = from.nick, nick = nick));
|
||||
return;
|
||||
}
|
||||
match net.channel_seen(chan, nick) {
|
||||
Some(s) => ctx.notice(me, from.uid, format!(
|
||||
"{}: \x02{}\x02 was last seen on \x02{chan}\x02 {}, last saying: {}",
|
||||
from.nick, s.nick, echo_api::human_time(s.ts), s.msg
|
||||
Some(s) => ctx.notice(me, from.uid, t!(ctx,
|
||||
"{who}: \x02{nick}\x02 was last seen on \x02{chan}\x02 {when}, last saying: {msg}",
|
||||
who = from.nick, nick = s.nick, chan = chan, when = echo_api::human_time(s.ts), msg = s.msg
|
||||
)),
|
||||
None => ctx.notice(me, from.uid, format!("{}: I have no record of \x02{nick}\x02 talking in \x02{chan}\x02.", from.nick)),
|
||||
None => ctx.notice(me, from.uid, t!(ctx, "{who}: I have no record of \x02{nick}\x02 talking in \x02{chan}\x02.", who = from.nick, nick = nick, chan = chan)),
|
||||
}
|
||||
}
|
||||
// Network-wide.
|
||||
Some(&nick) => {
|
||||
if net.uid_by_nick(nick).is_some() {
|
||||
ctx.notice(me, from.uid, format!("\x02{nick}\x02 is currently online."));
|
||||
ctx.notice(me, from.uid, t!(ctx, "\x02{nick}\x02 is currently online.", nick = nick));
|
||||
return;
|
||||
}
|
||||
match net.last_seen(nick) {
|
||||
Some(s) => ctx.notice(me, from.uid, format!("\x02{}\x02 was last seen {} ({}).", s.nick, echo_api::human_time(s.ts), s.what)),
|
||||
None => ctx.notice(me, from.uid, format!("I have no record of \x02{nick}\x02.")),
|
||||
Some(s) => ctx.notice(me, from.uid, t!(ctx, "\x02{nick}\x02 was last seen {when} ({what}).", nick = s.nick, when = echo_api::human_time(s.ts), what = s.what)),
|
||||
None => ctx.notice(me, from.uid, t!(ctx, "I have no record of \x02{nick}\x02.", nick = nick)),
|
||||
}
|
||||
}
|
||||
None => ctx.notice(me, from.uid, "Syntax: SEEN <nick> | SEEN <#channel> <nick>"),
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
use echo_api::{ChanSetting, Sender, ServiceCtx, Store};
|
||||
use echo_api::t;
|
||||
|
||||
// SET <#channel> FOUNDER <account> | DESC <text>: founder-only channel settings.
|
||||
pub fn handle(me: &str, from: &Sender, args: &[&str], ctx: &mut ServiceCtx, db: &mut dyn Store) {
|
||||
|
|
@ -8,13 +9,13 @@ pub fn handle(me: &str, from: &Sender, args: &[&str], ctx: &mut ServiceCtx, db:
|
|||
};
|
||||
let founder = match db.channel(chan) {
|
||||
None => {
|
||||
ctx.notice(me, from.uid, format!("\x02{chan}\x02 isn't registered."));
|
||||
ctx.notice(me, from.uid, t!(ctx, "\x02{chan}\x02 isn't registered.", chan = chan));
|
||||
return;
|
||||
}
|
||||
Some(info) => info.founder.clone(),
|
||||
};
|
||||
if from.account != Some(founder.as_str()) {
|
||||
ctx.notice(me, from.uid, format!("Only \x02{chan}\x02's founder can change its settings."));
|
||||
ctx.notice(me, from.uid, t!(ctx, "Only \x02{chan}\x02's founder can change its settings.", chan = chan));
|
||||
return;
|
||||
}
|
||||
if super::suspended_block(me, from, chan, ctx, db) {
|
||||
|
|
@ -27,11 +28,11 @@ pub fn handle(me: &str, from: &Sender, args: &[&str], ctx: &mut ServiceCtx, db:
|
|||
return;
|
||||
};
|
||||
if !db.exists(account) {
|
||||
ctx.notice(me, from.uid, format!("\x02{account}\x02 isn't a registered account."));
|
||||
ctx.notice(me, from.uid, t!(ctx, "\x02{account}\x02 isn't a registered account.", account = account));
|
||||
return;
|
||||
}
|
||||
match db.set_founder(chan, account) {
|
||||
Ok(()) => ctx.notice(me, from.uid, format!("Founder of \x02{chan}\x02 transferred to \x02{account}\x02.")),
|
||||
Ok(()) => ctx.notice(me, from.uid, t!(ctx, "Founder of \x02{chan}\x02 transferred to \x02{account}\x02.", chan = chan, account = account)),
|
||||
Err(_) => ctx.notice(me, from.uid, "Sorry, that didn't work. Please try again in a moment."),
|
||||
}
|
||||
}
|
||||
|
|
@ -39,7 +40,7 @@ pub fn handle(me: &str, from: &Sender, args: &[&str], ctx: &mut ServiceCtx, db:
|
|||
match args.get(3) {
|
||||
Some(&acct) if !acct.eq_ignore_ascii_case("OFF") => {
|
||||
if !db.exists(acct) {
|
||||
ctx.notice(me, from.uid, format!("\x02{acct}\x02 isn't a registered account."));
|
||||
ctx.notice(me, from.uid, t!(ctx, "\x02{account}\x02 isn't a registered account.", account = acct));
|
||||
return;
|
||||
}
|
||||
if acct.eq_ignore_ascii_case(&founder) {
|
||||
|
|
@ -47,12 +48,12 @@ pub fn handle(me: &str, from: &Sender, args: &[&str], ctx: &mut ServiceCtx, db:
|
|||
return;
|
||||
}
|
||||
match db.set_successor(chan, Some(acct)) {
|
||||
Ok(()) => ctx.notice(me, from.uid, format!("Successor of \x02{chan}\x02 set to \x02{acct}\x02. They inherit it if your account is dropped or expires.")),
|
||||
Ok(()) => ctx.notice(me, from.uid, t!(ctx, "Successor of \x02{chan}\x02 set to \x02{acct}\x02. They inherit it if your account is dropped or expires.", chan = chan, acct = acct)),
|
||||
Err(_) => ctx.notice(me, from.uid, "Sorry, that didn't work. Please try again in a moment."),
|
||||
}
|
||||
}
|
||||
_ => match db.set_successor(chan, None) {
|
||||
Ok(()) => ctx.notice(me, from.uid, format!("Successor of \x02{chan}\x02 cleared.")),
|
||||
Ok(()) => ctx.notice(me, from.uid, t!(ctx, "Successor of \x02{chan}\x02 cleared.", chan = chan)),
|
||||
Err(_) => ctx.notice(me, from.uid, "Sorry, that didn't work. Please try again in a moment."),
|
||||
},
|
||||
}
|
||||
|
|
@ -60,23 +61,23 @@ pub fn handle(me: &str, from: &Sender, args: &[&str], ctx: &mut ServiceCtx, db:
|
|||
Some("DESC") => {
|
||||
let desc = if args.len() > 3 { args[3..].join(" ") } else { String::new() };
|
||||
match db.set_desc(chan, &desc) {
|
||||
Ok(()) => ctx.notice(me, from.uid, format!("Description for \x02{chan}\x02 updated.")),
|
||||
Ok(()) => ctx.notice(me, from.uid, t!(ctx, "Description for \x02{chan}\x02 updated.", chan = chan)),
|
||||
Err(_) => ctx.notice(me, from.uid, "Sorry, that didn't work. Please try again in a moment."),
|
||||
}
|
||||
}
|
||||
Some("URL") => {
|
||||
let url = if args.len() > 3 { args[3..].join(" ") } else { String::new() };
|
||||
match db.set_url(chan, &url) {
|
||||
Ok(()) if url.is_empty() => ctx.notice(me, from.uid, format!("URL for \x02{chan}\x02 cleared.")),
|
||||
Ok(()) => ctx.notice(me, from.uid, format!("URL for \x02{chan}\x02 updated.")),
|
||||
Ok(()) if url.is_empty() => ctx.notice(me, from.uid, t!(ctx, "URL for \x02{chan}\x02 cleared.", chan = chan)),
|
||||
Ok(()) => ctx.notice(me, from.uid, t!(ctx, "URL for \x02{chan}\x02 updated.", chan = chan)),
|
||||
Err(_) => ctx.notice(me, from.uid, "Sorry, that didn't work. Please try again in a moment."),
|
||||
}
|
||||
}
|
||||
Some("EMAIL") => {
|
||||
let email = args.get(3).copied().unwrap_or("");
|
||||
match db.set_channel_email(chan, email) {
|
||||
Ok(()) if email.is_empty() => ctx.notice(me, from.uid, format!("Contact email for \x02{chan}\x02 cleared.")),
|
||||
Ok(()) => ctx.notice(me, from.uid, format!("Contact email for \x02{chan}\x02 updated.")),
|
||||
Ok(()) if email.is_empty() => ctx.notice(me, from.uid, t!(ctx, "Contact email for \x02{chan}\x02 cleared.", chan = chan)),
|
||||
Ok(()) => ctx.notice(me, from.uid, t!(ctx, "Contact email for \x02{chan}\x02 updated.", chan = chan)),
|
||||
Err(_) => ctx.notice(me, from.uid, "Sorry, that didn't work. Please try again in a moment."),
|
||||
}
|
||||
}
|
||||
|
|
@ -115,12 +116,12 @@ fn toggle(me: &str, from: &Sender, ctx: &mut ServiceCtx, db: &mut dyn Store, cha
|
|||
Some("ON") => true,
|
||||
Some("OFF") => false,
|
||||
_ => {
|
||||
ctx.notice(me, from.uid, format!("Syntax: SET <#channel> {name} {{ON|OFF}}"));
|
||||
ctx.notice(me, from.uid, t!(ctx, "Syntax: SET <#channel> {name} {ON|OFF}", name = name));
|
||||
return;
|
||||
}
|
||||
};
|
||||
match db.set_channel_setting(chan, setting, on) {
|
||||
Ok(()) => ctx.notice(me, from.uid, format!("\x02{name}\x02 for \x02{chan}\x02 is now \x02{}\x02.", if on { "on" } else { "off" })),
|
||||
Ok(()) => ctx.notice(me, from.uid, t!(ctx, "\x02{name}\x02 for \x02{chan}\x02 is now \x02{state}\x02.", name = name, chan = chan, state = if on { "on" } else { "off" })),
|
||||
Err(_) => ctx.notice(me, from.uid, "Sorry, that didn't work. Please try again in a moment."),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use echo_api::Store;
|
||||
use echo_api::{access_role, Sender, ServiceCtx};
|
||||
use echo_api::NetView;
|
||||
use echo_api::t;
|
||||
|
||||
// STATUS <#channel> [nick]: show a user's access level (self if no nick).
|
||||
pub fn handle(me: &str, from: &Sender, args: &[&str], ctx: &mut ServiceCtx, net: &dyn NetView, db: &dyn Store) {
|
||||
|
|
@ -9,7 +10,7 @@ pub fn handle(me: &str, from: &Sender, args: &[&str], ctx: &mut ServiceCtx, net:
|
|||
return;
|
||||
};
|
||||
let Some(info) = db.channel(chan) else {
|
||||
ctx.notice(me, from.uid, format!("\x02{chan}\x02 isn't registered."));
|
||||
ctx.notice(me, from.uid, t!(ctx, "\x02{chan}\x02 isn't registered.", chan = chan));
|
||||
return;
|
||||
};
|
||||
let (label, account) = match args.get(2) {
|
||||
|
|
@ -26,5 +27,5 @@ pub fn handle(me: &str, from: &Sender, args: &[&str], ctx: &mut ServiceCtx, net:
|
|||
None => "none",
|
||||
},
|
||||
};
|
||||
ctx.notice(me, from.uid, format!("\x02{label}\x02 access on \x02{chan}\x02: \x02{level}\x02"));
|
||||
ctx.notice(me, from.uid, t!(ctx, "\x02{label}\x02 access on \x02{chan}\x02: \x02{level}\x02", label = label, chan = chan, level = level));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
use echo_api::{parse_duration, NetView, Priv, Sender, ServiceCtx, Store};
|
||||
use echo_api::t;
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
|
||||
// SUSPEND <#channel> [+expiry] [reason] / UNSUSPEND <#channel>: freeze or unfreeze
|
||||
|
|
@ -15,14 +16,14 @@ pub fn handle(me: &str, from: &Sender, args: &[&str], ctx: &mut ServiceCtx, net:
|
|||
return;
|
||||
};
|
||||
if db.channel(chan).is_none() {
|
||||
ctx.notice(me, from.uid, format!("\x02{chan}\x02 isn't registered."));
|
||||
ctx.notice(me, from.uid, t!(ctx, "\x02{chan}\x02 isn't registered.", chan = chan));
|
||||
return;
|
||||
}
|
||||
|
||||
if !suspending {
|
||||
match db.unsuspend_channel(chan) {
|
||||
Ok(true) => ctx.notice(me, from.uid, format!("\x02{chan}\x02 is no longer suspended.")),
|
||||
Ok(false) => ctx.notice(me, from.uid, format!("\x02{chan}\x02 isn't suspended.")),
|
||||
Ok(true) => ctx.notice(me, from.uid, t!(ctx, "\x02{chan}\x02 is no longer suspended.", chan = chan)),
|
||||
Ok(false) => ctx.notice(me, from.uid, t!(ctx, "\x02{chan}\x02 isn't suspended.", chan = chan)),
|
||||
Err(_) => ctx.notice(me, from.uid, "Sorry, that didn't work. Please try again in a moment."),
|
||||
}
|
||||
return;
|
||||
|
|
@ -42,7 +43,7 @@ pub fn handle(me: &str, from: &Sender, args: &[&str], ctx: &mut ServiceCtx, net:
|
|||
ctx.kick(me, chan, &uid, &reason);
|
||||
}
|
||||
let expiry = if expires.is_some() { " (with expiry)" } else { "" };
|
||||
ctx.notice(me, from.uid, format!("\x02{chan}\x02 is now suspended{expiry}."));
|
||||
ctx.notice(me, from.uid, t!(ctx, "\x02{chan}\x02 is now suspended{expiry}.", chan = chan, expiry = expiry));
|
||||
}
|
||||
Err(_) => ctx.notice(me, from.uid, "Sorry, that didn't work. Please try again in a moment."),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use echo_api::Store;
|
||||
use echo_api::{Sender, ServiceCtx};
|
||||
use echo_api::t;
|
||||
|
||||
// TOPIC <#channel> <text>: set the channel topic (empty clears it).
|
||||
pub fn handle(me: &str, from: &Sender, args: &[&str], ctx: &mut ServiceCtx, db: &mut dyn Store) {
|
||||
|
|
@ -16,5 +17,5 @@ pub fn handle(me: &str, from: &Sender, args: &[&str], ctx: &mut ServiceCtx, db:
|
|||
// stored topic stays stale and KEEPTOPIC/TOPICLOCK restore the old one on
|
||||
// recreation/restart. Ignore NoChannel (require_op already proved it exists).
|
||||
let _ = db.set_channel_topic(chan, &text);
|
||||
ctx.notice(me, from.uid, format!("Topic for \x02{chan}\x02 updated."));
|
||||
ctx.notice(me, from.uid, t!(ctx, "Topic for \x02{chan}\x02 updated.", chan = chan));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use echo_api::Store;
|
||||
use echo_api::{Sender, ServiceCtx};
|
||||
use echo_api::NetView;
|
||||
use echo_api::t;
|
||||
|
||||
// UNBAN <#channel> [nick]: remove the *!*@host ban of a user (self if no nick).
|
||||
pub fn handle(me: &str, from: &Sender, args: &[&str], ctx: &mut ServiceCtx, net: &dyn NetView, db: &dyn Store) {
|
||||
|
|
@ -18,5 +19,5 @@ pub fn handle(me: &str, from: &Sender, args: &[&str], ctx: &mut ServiceCtx, net:
|
|||
.unwrap_or_else(|| from.uid.to_string());
|
||||
let host = net.host_of(&target).unwrap_or("*");
|
||||
ctx.channel_mode(me, chan, &format!("-b *!*@{host}"));
|
||||
ctx.notice(me, from.uid, format!("Cleared the *!*@{host} ban on \x02{chan}\x02."));
|
||||
ctx.notice(me, from.uid, t!(ctx, "Cleared the *!*@{host} ban on \x02{chan}\x02.", host = host, chan = chan));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
use echo_api::{status_mode, NetView, Sender, ServiceCtx, Store};
|
||||
use echo_api::t;
|
||||
|
||||
// UP <#channel>: (re)apply the status mode your access entitles you to.
|
||||
// DOWN <#channel>: drop your channel status modes. `up` selects which.
|
||||
|
|
@ -12,24 +13,24 @@ pub fn handle(me: &str, from: &Sender, up: bool, args: &[&str], ctx: &mut Servic
|
|||
return;
|
||||
};
|
||||
let Some(info) = db.channel(chan) else {
|
||||
ctx.notice(me, from.uid, format!("\x02{chan}\x02 isn't registered."));
|
||||
ctx.notice(me, from.uid, t!(ctx, "\x02{chan}\x02 isn't registered.", chan = chan));
|
||||
return;
|
||||
};
|
||||
if !net.channel_members(chan).iter().any(|u| u.as_str() == from.uid) {
|
||||
ctx.notice(me, from.uid, format!("You're not in \x02{chan}\x02."));
|
||||
ctx.notice(me, from.uid, t!(ctx, "You're not in \x02{chan}\x02.", chan = chan));
|
||||
return;
|
||||
}
|
||||
if up {
|
||||
match info.join_mode(account) {
|
||||
Some(mode) => {
|
||||
ctx.channel_mode(me, chan, &status_mode(mode, from.uid));
|
||||
ctx.notice(me, from.uid, format!("Your status in \x02{chan}\x02 has been applied."));
|
||||
ctx.notice(me, from.uid, t!(ctx, "Your status in \x02{chan}\x02 has been applied.", chan = chan));
|
||||
}
|
||||
None => ctx.notice(me, from.uid, format!("You have no status access in \x02{chan}\x02.")),
|
||||
None => ctx.notice(me, from.uid, t!(ctx, "You have no status access in \x02{chan}\x02.", chan = chan)),
|
||||
}
|
||||
} else {
|
||||
// Strip owner, admin, op, halfop and voice; the ircd ignores any you don't hold.
|
||||
ctx.channel_mode(me, chan, &status_mode("-qaohv", from.uid));
|
||||
ctx.notice(me, from.uid, format!("Your status in \x02{chan}\x02 has been removed."));
|
||||
ctx.notice(me, from.uid, t!(ctx, "Your status in \x02{chan}\x02 has been removed.", chan = chan));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,52 +1,53 @@
|
|||
use echo_api::{access_role, Sender, ServiceCtx, Store};
|
||||
use echo_api::t;
|
||||
|
||||
// SOP/AOP/HOP/VOP <#channel> ADD <account> | DEL <account> | LIST — tiered
|
||||
// shortcuts over the access list. `level` is the tier they map to ("sop", "op",
|
||||
// "halfop", "voice"); `word` is the tier the user typed ("SOP".."VOP").
|
||||
pub fn handle(me: &str, from: &Sender, word: &str, level: &str, args: &[&str], ctx: &mut ServiceCtx, db: &mut dyn Store) {
|
||||
let Some(&chan) = args.get(1) else {
|
||||
ctx.notice(me, from.uid, format!("Syntax: {word} <#channel> ADD <account> | DEL <account> | LIST"));
|
||||
ctx.notice(me, from.uid, t!(ctx, "Syntax: {word} <#channel> ADD <account> | DEL <account> | LIST", word = word));
|
||||
return;
|
||||
};
|
||||
match args.get(2).map(|s| s.to_ascii_uppercase()).as_deref() {
|
||||
None | Some("LIST") => match db.channel(chan) {
|
||||
None => ctx.notice(me, from.uid, format!("\x02{chan}\x02 isn't registered.")),
|
||||
None => ctx.notice(me, from.uid, t!(ctx, "\x02{chan}\x02 isn't registered.", chan = chan)),
|
||||
Some(info) => {
|
||||
ctx.notice(me, from.uid, format!("{word} list for \x02{}\x02:", info.name));
|
||||
ctx.notice(me, from.uid, t!(ctx, "{word} list for \x02{name}\x02:", word = word, name = info.name));
|
||||
// List by resolved tier, not the raw level string, so an entry set
|
||||
// via granular FLAGS appears under the same tier a XOP ADD would.
|
||||
for a in info.access.iter().filter(|a| access_role(&a.level).xop_word() == Some(word)) {
|
||||
ctx.notice(me, from.uid, format!(" \x02{}\x02", a.account));
|
||||
ctx.notice(me, from.uid, t!(ctx, " \x02{account}\x02", account = a.account));
|
||||
}
|
||||
}
|
||||
},
|
||||
Some("ADD") => {
|
||||
let Some(&account) = args.get(3) else {
|
||||
ctx.notice(me, from.uid, format!("Syntax: {word} <#channel> ADD <account>"));
|
||||
ctx.notice(me, from.uid, t!(ctx, "Syntax: {word} <#channel> ADD <account>", word = word));
|
||||
return;
|
||||
};
|
||||
if !super::require_founder(me, from, chan, ctx, db) {
|
||||
return;
|
||||
}
|
||||
match db.access_add(chan, account, level) {
|
||||
Ok(()) => ctx.notice(me, from.uid, format!("Added \x02{account}\x02 to \x02{chan}\x02's {word} list.")),
|
||||
Ok(()) => ctx.notice(me, from.uid, t!(ctx, "Added \x02{account}\x02 to \x02{chan}\x02's {word} list.", account = account, chan = chan, word = word)),
|
||||
Err(_) => ctx.notice(me, from.uid, "Sorry, that didn't work. Please try again in a moment."),
|
||||
}
|
||||
}
|
||||
Some("DEL") => {
|
||||
let Some(&account) = args.get(3) else {
|
||||
ctx.notice(me, from.uid, format!("Syntax: {word} <#channel> DEL <account>"));
|
||||
ctx.notice(me, from.uid, t!(ctx, "Syntax: {word} <#channel> DEL <account>", word = word));
|
||||
return;
|
||||
};
|
||||
if !super::require_founder(me, from, chan, ctx, db) {
|
||||
return;
|
||||
}
|
||||
match db.access_del(chan, account) {
|
||||
Ok(true) => ctx.notice(me, from.uid, format!("Removed \x02{account}\x02 from \x02{chan}\x02's {word} list.")),
|
||||
Ok(false) => ctx.notice(me, from.uid, format!("\x02{account}\x02 has no access to \x02{chan}\x02.")),
|
||||
Ok(true) => ctx.notice(me, from.uid, t!(ctx, "Removed \x02{account}\x02 from \x02{chan}\x02's {word} list.", account = account, chan = chan, word = word)),
|
||||
Ok(false) => ctx.notice(me, from.uid, t!(ctx, "\x02{account}\x02 has no access to \x02{chan}\x02.", account = account, chan = chan)),
|
||||
Err(_) => ctx.notice(me, from.uid, "Sorry, that didn't work. Please try again in a moment."),
|
||||
}
|
||||
}
|
||||
_ => ctx.notice(me, from.uid, format!("Syntax: {word} <#channel> ADD <account> | DEL <account> | LIST")),
|
||||
_ => ctx.notice(me, from.uid, t!(ctx, "Syntax: {word} <#channel> ADD <account> | DEL <account> | LIST", word = word)),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue