Skip to main content

moderation_bot/
moderation_bot.rs

1//! A moderation bot for Communities. Welcomes new members and auto-bans anyone
2//! who posts a banned word — admins and the bot itself are never moderated.
3//!
4//! Demonstrates `on_event` (the full inbound stream) and the discord.js-style
5//! "actor in context" model: `msg.member()` is the sender as a [`Member`] you can
6//! act on directly.
7//!
8//! The bot must be a member of the community first — it builds `.public()` so you
9//! can invite it from the Vector app.
10//!
11//! Run with:
12//! ```sh
13//! VECTOR_NSEC=nsec1... cargo run -p vector-sdk --example moderation_bot
14//! ```
15//!
16//! [`Member`]: vector_sdk::Member
17
18use vector_sdk::{BotEvent, VectorBot};
19
20const BANNED_WORDS: &[&str] = &["spamword", "scamlink", "verboten"];
21
22#[tokio::main]
23async fn main() -> vector_sdk::Result<()> {
24    let nsec = std::env::var("VECTOR_NSEC").expect("set VECTOR_NSEC to your bot's nsec");
25
26    // `.public()` lets anyone invite the bot into their community to moderate it.
27    let bot = VectorBot::builder().nsec(nsec).public().build().await?;
28    println!("Moderation bot online as {}", bot.npub());
29
30    bot.on_event(|bot, event| async move {
31        match event {
32            // Greet new arrivals in the channel they joined.
33            BotEvent::MemberJoin { channel_id, npub } => {
34                let who = &npub[..npub.len().min(12)];
35                let _ = bot.channel(channel_id).send(&format!("👋 Welcome, {who}!")).await;
36            }
37
38            // Screen community messages; ban posters of banned words (never admins or ourselves).
39            BotEvent::Message(msg) if msg.is_group && !msg.is_mine() => {
40                let lower = msg.text().to_lowercase();
41                if !BANNED_WORDS.iter().any(|w| lower.contains(w)) {
42                    return;
43                }
44                if let Some(member) = msg.member() {
45                    if member.is_admin() {
46                        return; // never moderate admins or the owner
47                    }
48                    match member.ban().await {
49                        Ok(()) => println!("Banned {} for a banned word", member.npub()),
50                        Err(e) => eprintln!("Couldn't ban {}: {e}", member.npub()),
51                    }
52                }
53            }
54
55            _ => {}
56        }
57    })
58    .await?;
59
60    Ok(())
61}