xline: show a timed ban's remaining time in the removal notice
This commit is contained in:
parent
3ad67c6b52
commit
745ddd540e
2 changed files with 29 additions and 6 deletions
|
|
@ -1629,12 +1629,15 @@ mod tests {
|
|||
u.flags.snomask = true;
|
||||
u.flags.snomask_cats = "x".to_string();
|
||||
}
|
||||
// permanent G-line, then removed
|
||||
// permanent G-line, then removed → "permanent", no remaining clause
|
||||
s.add_xline(crate::xline::XKind::Gline, "*@bad.example", 0, "op", "spam");
|
||||
assert!(s.remove_xline(crate::xline::XKind::Gline, "*@bad.example", "op"));
|
||||
assert!(!s.remove_xline(crate::xline::XKind::Gline, "*@bad.example", "op")); // gone: no re-announce
|
||||
// timed K-line removed early → reports the time it had left
|
||||
s.add_xline(crate::xline::XKind::Kline, "*@foo.example", 604800, "op", "temp");
|
||||
assert!(s.remove_xline(crate::xline::XKind::Kline, "*@foo.example", "op"));
|
||||
// a timed Z-line whose expiry is forced into the past, then purged
|
||||
s.add_xline(crate::xline::XKind::Zline, "192.0.2.5", 3600, "op", "temp");
|
||||
s.add_xline(crate::xline::XKind::Zline, "192.0.2.5", 3600, "op", "temp2");
|
||||
for x in s.xlines.iter_mut() {
|
||||
if x.mask == "192.0.2.5" {
|
||||
x.expires = 1;
|
||||
|
|
@ -1644,7 +1647,11 @@ mod tests {
|
|||
let joined: String =
|
||||
std::iter::from_fn(|| orx.try_recv().ok()).collect::<Vec<_>>().join("\n");
|
||||
assert!(joined.contains("XLINE: op added a permanent G-line on *@bad.example: spam"), "add: {joined}");
|
||||
assert!(joined.contains("XLINE: op removed a G-line on *@bad.example"), "remove: {joined}");
|
||||
assert!(joined.contains("XLINE: op removed a permanent G-line on *@bad.example"), "remove permanent: {joined}");
|
||||
assert!(
|
||||
joined.contains("XLINE: op removed a timed K-line on *@foo.example (") && joined.contains("remaining)"),
|
||||
"remove timed shows remaining: {joined}"
|
||||
);
|
||||
assert!(joined.contains("XLINE: Z-line on 192.0.2.5 expired"), "expire: {joined}");
|
||||
}
|
||||
|
||||
|
|
|
|||
22
src/xline.rs
22
src/xline.rs
|
|
@ -294,9 +294,17 @@ impl Server {
|
|||
self.enforce_xlines();
|
||||
}
|
||||
|
||||
/// Remove an x-line by kind + mask; announces it (snomask +x, like the add) and
|
||||
/// returns whether one was found. `remover` is who took it off.
|
||||
/// Remove an x-line by kind + mask; announces it (snomask +x, like the add) —
|
||||
/// reporting how long a timed ban had left to run, so opers see what they cut
|
||||
/// short — and returns whether one was found. `remover` is who took it off.
|
||||
pub fn remove_xline(&mut self, kind: XKind, mask: &str, remover: &str) -> bool {
|
||||
let n = now();
|
||||
// capture the target's expiry before dropping it, to report the time left
|
||||
let expires = self
|
||||
.xlines
|
||||
.iter()
|
||||
.find(|x| x.kind == kind && x.mask.eq_ignore_ascii_case(mask))
|
||||
.map(|x| x.expires);
|
||||
let before = self.xlines.len();
|
||||
// case-insensitive: nick/host/channel masks match case-insensitively when
|
||||
// enforced, so removal must too (e.g. remove `CBAN #foo` for a `#Foo` ban).
|
||||
|
|
@ -304,7 +312,15 @@ impl Server {
|
|||
.retain(|x| !(x.kind == kind && x.mask.eq_ignore_ascii_case(mask)));
|
||||
let removed = self.xlines.len() < before;
|
||||
if removed {
|
||||
self.snotice_c('x', &format!("XLINE: {remover} removed a {}-line on {mask}", kind.tag()));
|
||||
let tag = kind.tag();
|
||||
let detail = match expires {
|
||||
Some(e) if e > n => {
|
||||
format!("timed {tag}-line on {mask} ({} remaining)", human_duration(e - n))
|
||||
}
|
||||
Some(e) if e != 0 => format!("timed {tag}-line on {mask} (already expired)"),
|
||||
_ => format!("permanent {tag}-line on {mask}"),
|
||||
};
|
||||
self.snotice_c('x', &format!("XLINE: {remover} removed a {detail}"));
|
||||
self.save_xlines();
|
||||
}
|
||||
removed
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue