safe-vk 1.2.2

A simple library to create your own vk bot for conversations
Documentation
use crate::{
    extract::{Ctx, Update},
    parse_response,
    responses::{ButtonPressCallback, EventAnswer, Members, Message},
    util::NdArray,
    Error, Result, VK,
};
use serde_json::json;

impl Ctx<Message> {
    pub async fn send_message(&self, message: impl Into<String>) -> Result<()> {
        self.request()
            .post(
                VK,
                "messages.send",
                &[
                    ("message", message.into()),
                    ("peer_id", self.message.peer_id.to_string()),
                    ("random_id", String::from("0")),
                ],
                {},
            )
            .await?;
        Ok(())
    }

    /// Send message using random id
    pub async fn send_message_rnd(
        &self,
        message: impl Into<String>,
        random_id: String,
    ) -> Result<()> {
        self.request()
            .post(
                VK,
                "messages.send",
                &[
                    ("message", message.into()),
                    ("peer_id", self.message.peer_id.to_string()),
                    ("random_id", random_id),
                ],
                {},
            )
            .await?;
        Ok(())
    }

    pub async fn get_members(
        &self,
        offset: Option<u16>,
        count: Option<u16>,
        extended: bool,
    ) -> Result<Members> {
        let mut params = vec![("peer_id", self.message.peer_id.to_string())];

        if extended {
            params.push(("extended", String::from("1")));
        } else {
            params.push(("extended", String::from("0")));
        }

        if let Some(offset_val) = offset {
            params.push(("offset", offset_val.to_string()));
        }
        if let Some(count_val) = count {
            params.push(("count", count_val.to_string()));
        }

        let res = self
            .request()
            .post(VK, "messages.getConversationMembers", &params, {})
            .await?;

        return Ok(parse_response!(res, Members)?);
    }

    pub async fn keyboard<T: serde::Serialize, N: NdArray<T>>(
        &self,
        message: impl Into<String>,
        one_time: bool,
        inline: bool,
        buttons: N,
    ) -> crate::Result<()> {
        let dim_1 = buttons.shape().dims()[1];
        let dim_2 = buttons.shape().dims()[0];

        // Ensure that the first dimension (dim_1) is not greater than 5
        // This is to enforce a maximum shape of 5x1 for the array
        // Fore more info: https://dev.vk.com/ru/api/bots/development/keyboard
        if dim_1 > 5 {
            return Err(Error::DimOutOfRange {
                shape: buttons.shape(),
                dim: dim_1 as i32,
            });
        } else if dim_2 > 10 {
            return Err(Error::DimOutOfRange {
                shape: buttons.shape(),
                dim: dim_2 as i32,
            });
        }

        let keyboard = json!({
            "one_time": one_time,
            "inline": inline,
            "buttons": json!(buttons.slice()),
        });

        let keyboard = serde_json::to_string(&keyboard)?;

        self.request()
            .post(
                VK,
                "messages.send",
                &[
                    ("message", message.into()),
                    ("peer_id", self.message.peer_id.to_string()),
                    ("keyboard", keyboard),
                    ("random_id", String::from("0")),
                ],
                {},
            )
            .await?;

        Ok(())
    }
}

impl Ctx<Update> {
    pub async fn send_message(&self, message: impl Into<String>, peer_id: i32) -> Result<()> {
        self.request()
            .post(
                VK,
                "messages.send",
                &[
                    ("message", message.into()),
                    ("peer_id", peer_id.to_string()),
                    ("random_id", String::from("0")),
                ],
                {},
            )
            .await?;
        Ok(())
    }

    pub async fn keyboard_callback<
        'de,
        T: serde::Serialize,
        A: serde::de::DeserializeOwned + PartialEq + serde::Serialize,
    >(
        &self,
        callback: T,
        _payload: A,
    ) -> crate::Result<Option<ButtonPressCallback<A>>> {
        for update in self.updates.as_ref().unwrap() {
            if let Ok(valid_data) =
                serde_json::from_value::<ButtonPressCallback<A>>(update.object.clone())
            {
                let event_data = serde_json::to_string(&callback).unwrap();
                // Safe unwraps here, because if response has object `payload` then VK api
                // guarantee that it will contain `user_id` field and `peer_id`
                let res = self
                    .request()
                    .post(
                        VK,
                        "messages.sendMessageEventAnswer",
                        &[
                            ("event_data", event_data),
                            ("user_id", valid_data.user_id.to_string()),
                            ("event_id", valid_data.event_id.to_string()),
                            ("peer_id", valid_data.peer_id.to_string()),
                        ],
                        {},
                    )
                    .await?;

                if let Ok(response) = parse_response!(res, EventAnswer) {
                    if response.get_status().is_ok() {
                        return Ok(Some(valid_data));
                    }
                }
            }
        }
        Ok(None)
    }
}