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 = true;
|
||||||
u.flags.snomask_cats = "x".to_string();
|
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");
|
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"));
|
||||||
assert!(!s.remove_xline(crate::xline::XKind::Gline, "*@bad.example", "op")); // gone: no re-announce
|
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
|
// 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() {
|
for x in s.xlines.iter_mut() {
|
||||||
if x.mask == "192.0.2.5" {
|
if x.mask == "192.0.2.5" {
|
||||||
x.expires = 1;
|
x.expires = 1;
|
||||||
|
|
@ -1644,7 +1647,11 @@ mod tests {
|
||||||
let joined: String =
|
let joined: String =
|
||||||
std::iter::from_fn(|| orx.try_recv().ok()).collect::<Vec<_>>().join("\n");
|
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 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}");
|
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();
|
self.enforce_xlines();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Remove an x-line by kind + mask; announces it (snomask +x, like the add) and
|
/// Remove an x-line by kind + mask; announces it (snomask +x, like the add) —
|
||||||
/// returns whether one was found. `remover` is who took it off.
|
/// 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 {
|
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();
|
let before = self.xlines.len();
|
||||||
// case-insensitive: nick/host/channel masks match case-insensitively when
|
// case-insensitive: nick/host/channel masks match case-insensitively when
|
||||||
// enforced, so removal must too (e.g. remove `CBAN #foo` for a `#Foo` ban).
|
// 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)));
|
.retain(|x| !(x.kind == kind && x.mask.eq_ignore_ascii_case(mask)));
|
||||||
let removed = self.xlines.len() < before;
|
let removed = self.xlines.len() < before;
|
||||||
if removed {
|
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();
|
self.save_xlines();
|
||||||
}
|
}
|
||||||
removed
|
removed
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue