safe-vk 0.3.0-alpha

A simple library to create your own vk bot for conversations
Documentation
use crate::{
    extract::{Ctx, Update},
    parse_response,
    responses::{
        attachment::Photo,
        events::{GetMessagesUploadServer, UploadImage},
        Message,
    },
    RequestBuilder, Result, VK,
};
use reqwest::{
    multipart::{Form, Part},
    Client,
};
use std::sync::Arc;

pub struct PhotosBuilder {
    request: Arc<RequestBuilder>,
    values: Vec<(&'static str, String)>,
}

impl PhotosBuilder {
    pub fn new(request: Arc<RequestBuilder>, peer_id: String) -> Self {
        let values = Vec::from([("peer_id", peer_id)]);
        PhotosBuilder { request, values }
    }

    pub async fn get_message_upload(&self) -> Result<GetMessagesUploadServer> {
        let response = self
            .request
            .post(VK, "photos.getMessagesUploadServer", (), &self.values)
            .await?;

        Ok(parse_response!(response, GetMessagesUploadServer)?)
    }

    pub async fn save_message_photo(
        &self,
        photo: String,
        server: i32,
        hash: String,
    ) -> Result<Vec<Photo>> {
        let response = self
            .request
            .post(
                VK,
                "photos.saveMessagesPhoto",
                &[
                    ("photo", photo),
                    ("server", server.to_string()),
                    ("hash", hash),
                ],
                {},
            )
            .await?;

        Ok(parse_response!(response, Vec<Photo>)?)
    }

    pub async fn upload(&self, image: Vec<u8>, filename: impl Into<String>) -> Result<Vec<Photo>> {
        let response = self.get_message_upload().await?;

        let filename = &filename.into();

        let file_type = filename.rsplit_once('.').map(|(_, ext)| ext).unwrap_or("");

        let image = Part::stream(image)
            .file_name(filename.clone())
            .mime_str(&format!("image/{file_type}"))?;

        let response = Client::new()
            .post(response.upload_url)
            .multipart(Form::new().part("photo", image))
            .send()
            .await
            .unwrap()
            .json::<serde_json::Value>()
            .await
            .unwrap();

        let response = parse_response!(response, UploadImage)?;

        let response = self
            .save_message_photo(response.photo, response.server, response.hash)
            .await?;

        Ok(response)
    }
}

impl Ctx<Message> {
    pub fn photos(&self) -> PhotosBuilder {
        let peer_id = self.message.peer_id.to_string();
        PhotosBuilder::new(self.request.clone(), peer_id)
    }
}

impl Ctx<Update> {
    pub fn photos(&self) -> Result<PhotosBuilder> {
        let object = self.object.get("message").unwrap();
        let peer_id = object.get("peer_id").unwrap().to_string();
        Ok(PhotosBuilder::new(self.request.clone(), peer_id))
    }
}