Skip to main content

rust_tg_bot_ext/handlers/
chat_join_request.rs

1//! [`ChatJoinRequestHandler`] -- handles chat join request updates.
2//!
3//! Ported from `python-telegram-bot`'s `ChatJoinRequestHandler`. Supports
4//! optional filtering by chat ID and/or username.
5
6use std::collections::HashSet;
7use std::future::Future;
8use std::pin::Pin;
9use std::sync::Arc;
10
11use rust_tg_bot_raw::types::update::Update;
12
13use super::base::{Handler, HandlerCallback, HandlerResult, MatchResult};
14
15/// Handler for `Update.chat_join_request`.
16///
17/// When neither `chat_ids` nor `usernames` is provided, every
18/// `chat_join_request` update matches.
19pub struct ChatJoinRequestHandler {
20    callback: HandlerCallback,
21    chat_ids: HashSet<i64>,
22    usernames: HashSet<String>,
23    block: bool,
24}
25
26impl ChatJoinRequestHandler {
27    /// Create a new `ChatJoinRequestHandler`.
28    ///
29    /// Both `chat_ids` and `usernames` may be empty.
30    pub fn new(
31        callback: HandlerCallback,
32        chat_ids: HashSet<i64>,
33        usernames: HashSet<String>,
34        block: bool,
35    ) -> Self {
36        // Normalize usernames to lowercase without leading `@`.
37        let usernames = usernames
38            .into_iter()
39            .map(|u| u.trim_start_matches('@').to_lowercase())
40            .collect();
41        Self {
42            callback,
43            chat_ids,
44            usernames,
45            block,
46        }
47    }
48}
49
50impl Handler for ChatJoinRequestHandler {
51    fn check_update(&self, update: &Update) -> Option<MatchResult> {
52        let cjr = update.chat_join_request()?;
53
54        // No filters -> accept all.
55        if self.chat_ids.is_empty() && self.usernames.is_empty() {
56            return Some(MatchResult::Empty);
57        }
58
59        // Check chat ID.
60        if self.chat_ids.contains(&cjr.chat.id) {
61            return Some(MatchResult::Empty);
62        }
63
64        // Check from_user username.
65        if let Some(username) = cjr.from_user.username.as_deref() {
66            if self.usernames.contains(&username.to_lowercase()) {
67                return Some(MatchResult::Empty);
68            }
69        }
70
71        None
72    }
73
74    fn handle_update(
75        &self,
76        update: Arc<Update>,
77        match_result: MatchResult,
78    ) -> Pin<Box<dyn Future<Output = HandlerResult> + Send>> {
79        (self.callback)(update, match_result)
80    }
81
82    fn block(&self) -> bool {
83        self.block
84    }
85}