maxbot 0.1.0

Автоматизация работы с чат-ботами MAX
Documentation
//! Методы для работы с чатами (групповыми и диалогами).

use crate::client::MaxClient;
use crate::error::Result;
use crate::types::{Chat, ChatMember, Message, UpdateChatInfo};

impl MaxClient {
    // -------------------------------------------------------------------------
    // Базовые операции с чатами
    // -------------------------------------------------------------------------

    /// Получить информацию о чате по его ID.
    pub async fn get_chat(&self, chat_id: i64) -> Result<Chat> {
        self.request_with_rate_limit(
            reqwest::Method::GET,
            &format!("/chats/{}", chat_id),
            &[],
            None,
        )
        .await
    }

    /// Получить список групповых чатов, в которых участвовал бот.
    /// Поддерживает пагинацию через `count` (1-100) и `marker`.
    pub async fn get_chats(
        &self,
        count: Option<u32>,
        marker: Option<i64>,
    ) -> Result<(Vec<Chat>, Option<i64>)> {
        let mut query = Vec::new();
        if let Some(c) = count {
            query.push(("count", c.to_string()));
        }
        if let Some(m) = marker {
            query.push(("marker", m.to_string()));
        }
        let resp: serde_json::Value = self
            .request_with_rate_limit(reqwest::Method::GET, "/chats", &query, None)
            .await?;
        let chats = serde_json::from_value(resp["chats"].clone())?;
        let next_marker = resp.get("marker").and_then(|v| v.as_i64());
        Ok((chats, next_marker))
    }

    /// Обновить информацию о чате (название, описание, иконка, ссылка, публичность).
    pub async fn update_chat(&self, chat_id: i64, info: UpdateChatInfo) -> Result<Chat> {
        let mut body = serde_json::Map::new();
        if let Some(title) = info.title {
            body.insert("title".into(), title.into());
        }
        if let Some(desc) = info.description {
            body.insert("description".into(), desc.into());
        }
        if let Some(icon_token) = info.icon_token {
            body.insert("icon".into(), icon_token.into());
        }
        if let Some(link) = info.link {
            body.insert("link".into(), link.into());
        }
        if let Some(is_public) = info.is_public {
            body.insert("is_public".into(), is_public.into());
        }
        self.request_with_rate_limit(
            reqwest::Method::PATCH,
            &format!("/chats/{}", chat_id),
            &[],
            Some(serde_json::Value::Object(body)),
        )
        .await
    }

    /// Удалить групповой чат (только для владельца).
    pub async fn delete_chat(&self, chat_id: i64) -> Result<()> {
        self.request_with_rate_limit::<serde_json::Value>(
            reqwest::Method::DELETE,
            &format!("/chats/{}", chat_id),
            &[],
            None,
        )
        .await?;
        Ok(())
    }

    /// Выход бота из чата.
    pub async fn leave_chat(&self, chat_id: i64) -> Result<()> {
        self.request_with_rate_limit::<serde_json::Value>(
            reqwest::Method::DELETE,
            &format!("/chats/{}/members/me", chat_id),
            &[],
            None,
        )
        .await?;
        Ok(())
    }

    // -------------------------------------------------------------------------
    // Участники и администраторы
    // -------------------------------------------------------------------------

    /// Получить список участников чата (с пагинацией).
    pub async fn get_chat_members(
        &self,
        chat_id: i64,
        marker: Option<i64>,
        count: Option<u32>,
    ) -> Result<(Vec<ChatMember>, Option<i64>)> {
        let mut query = Vec::new();
        if let Some(m) = marker {
            query.push(("marker", m.to_string()));
        }
        if let Some(c) = count {
            query.push(("count", c.to_string()));
        }
        let resp: serde_json::Value = self
            .request_with_rate_limit(
                reqwest::Method::GET,
                &format!("/chats/{}/members", chat_id),
                &query,
                None,
            )
            .await?;
        let members = serde_json::from_value(resp["members"].clone())?;
        let next_marker = resp.get("marker").and_then(|v| v.as_i64());
        Ok((members, next_marker))
    }

    /// Получить список администраторов чата.
    pub async fn get_chat_admins(&self, chat_id: i64) -> Result<Vec<ChatMember>> {
        let resp: serde_json::Value = self
            .request_with_rate_limit(
                reqwest::Method::GET,
                &format!("/chats/{}/members/admins", chat_id),
                &[],
                None,
            )
            .await?;
        Ok(serde_json::from_value(resp["admins"].clone())?)
    }

    /// Назначить пользователя администратором с указанными правами.
    pub async fn add_chat_admin(
        &self,
        chat_id: i64,
        user_id: i64,
        permissions: Vec<String>,
    ) -> Result<()> {
        let body = serde_json::json!({
            "user_id": user_id,
            "permissions": permissions,
        });
        self.request_with_rate_limit::<serde_json::Value>(
            reqwest::Method::POST,
            &format!("/chats/{}/members/admins", chat_id),
            &[],
            Some(body),
        )
        .await?;
        Ok(())
    }

    /// Снять права администратора с пользователя.
    pub async fn remove_chat_admin(&self, chat_id: i64, user_id: i64) -> Result<()> {
        self.request_with_rate_limit::<serde_json::Value>(
            reqwest::Method::DELETE,
            &format!("/chats/{}/members/admins/{}", chat_id, user_id),
            &[],
            None,
        )
        .await?;
        Ok(())
    }

    /// Добавить участников в чат.
    pub async fn add_chat_members(&self, chat_id: i64, user_ids: Vec<i64>) -> Result<()> {
        let body = serde_json::json!({ "user_ids": user_ids });
        self.request_with_rate_limit::<serde_json::Value>(
            reqwest::Method::POST,
            &format!("/chats/{}/members", chat_id),
            &[],
            Some(body),
        )
        .await?;
        Ok(())
    }

    /// Удалить участника из чата.
    pub async fn remove_chat_member(&self, chat_id: i64, user_id: i64) -> Result<()> {
        self.request_with_rate_limit::<serde_json::Value>(
            reqwest::Method::DELETE,
            &format!("/chats/{}/members", chat_id),
            &[("user_id", user_id.to_string())],
            None,
        )
        .await?;
        Ok(())
    }

    /// Получить информацию о боте как об участнике чата.
    pub async fn get_bot_member(&self, chat_id: i64) -> Result<ChatMember> {
        self.request_with_rate_limit(
            reqwest::Method::GET,
            &format!("/chats/{}/members/me", chat_id),
            &[],
            None,
        )
        .await
    }

    // -------------------------------------------------------------------------
    // Действия в чате (печать, загрузка и т.п.)
    // -------------------------------------------------------------------------

    /// Отправить действие бота (typing, upload_photo, ...).
    pub async fn send_chat_action(&self, chat_id: i64, action: &str) -> Result<()> {
        let body = serde_json::json!({ "action": action });
        self.request_with_rate_limit::<serde_json::Value>(
            reqwest::Method::POST,
            &format!("/chats/{}/actions", chat_id),
            &[],
            Some(body),
        )
        .await?;
        Ok(())
    }

    // -------------------------------------------------------------------------
    // Закреплённые сообщения
    // -------------------------------------------------------------------------

    /// Получить закреплённое сообщение в чате.
    pub async fn get_pinned_message(&self, chat_id: i64) -> Result<Message> {
        self.request_with_rate_limit(
            reqwest::Method::GET,
            &format!("/chats/{}/pin", chat_id),
            &[],
            None,
        )
        .await
    }

    /// Закрепить сообщение в чате.
    pub async fn pin_message(&self, chat_id: i64, message_mid: &str) -> Result<()> {
        let body = serde_json::json!({ "mid": message_mid });
        self.request_with_rate_limit::<serde_json::Value>(
            reqwest::Method::PUT,
            &format!("/chats/{}/pin", chat_id),
            &[],
            Some(body),
        )
        .await?;
        Ok(())
    }

    /// Открепить сообщение в чате.
    pub async fn unpin_message(&self, chat_id: i64) -> Result<()> {
        self.request_with_rate_limit::<serde_json::Value>(
            reqwest::Method::DELETE,
            &format!("/chats/{}/pin", chat_id),
            &[],
            None,
        )
        .await?;
        Ok(())
    }
}