google_wallet/
drive_api.rs

1use reqwest::Client;
2use serde::{Deserialize, Serialize};
3use std::error::Error;
4
5const BASE_URL: &str = "https://www.googleapis.com/drive/v3";
6
7#[derive(Debug, Clone)]
8pub struct DriveApi {
9    client: Client,
10    access_token: String,
11}
12
13impl DriveApi {
14    /// Creates a new DriveApi instance
15    pub fn new(access_token: String) -> Self {
16        DriveApi {
17            client: Client::new(),
18            access_token,
19        }
20    }
21
22    /// List files in the Google Drive
23    pub async fn list_files(&self) -> Result<Vec<File>, Box<dyn Error>> {
24        let url = format!("{}/files", BASE_URL);
25
26        let response = self
27            .client
28            .get(&url)
29            .bearer_auth(&self.access_token)
30            .query(&[("spaces", "appDataFolder")]) // List files from appDataFolder
31            .send()
32            .await?;
33
34        if response.status().is_success() {
35            let file_list: FileList = response.json().await?;
36            Ok(file_list.files)
37        } else {
38            let error_msg = response.text().await?;
39            Err(format!("Error listing files: {}", error_msg).into())
40        }
41    }
42
43    /// Upload a file to the appDataFolder
44    pub async fn upload_file(&self, content: &str) -> Result<File, Box<dyn Error>> {
45        tracing::debug!("Uploading file to Google Drive: {content}");
46        let metadata = serde_json::json!({
47            "name": option_env!("ENV").unwrap_or("local"),
48            "parents": ["appDataFolder"]
49        });
50
51        let url = format!("https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart");
52
53        let form = reqwest::multipart::Form::new()
54            .part(
55                "metadata",
56                reqwest::multipart::Part::text(metadata.to_string())
57                    .mime_str("application/json")?, // Correct Content-Type for metadata
58            )
59            .part(
60                "file",
61                reqwest::multipart::Part::text(content.to_string()).mime_str("text/plain")?,
62            );
63        let response = self
64            .client
65            .post(&url)
66            .bearer_auth(&self.access_token)
67            .multipart(form)
68            .send()
69            .await?;
70
71        if response.status().is_success() {
72            let uploaded_file: File = response.json().await?;
73            Ok(uploaded_file)
74        } else {
75            let error_msg = response.text().await?;
76            Err(format!("Error uploading file: {}", error_msg).into())
77        }
78    }
79
80    pub async fn get_file(&self, file_id: &str) -> Result<String, Box<dyn Error>> {
81        let url = format!("{}/files/{}?alt=media", BASE_URL, file_id);
82
83        let response = self
84            .client
85            .get(&url)
86            .bearer_auth(&self.access_token)
87            .send()
88            .await?;
89
90        if response.status().is_success() {
91            let contents = response.text().await?;
92            Ok(contents)
93        } else {
94            let error_msg = response.text().await?;
95            Err(format!("Error getting file: {}", error_msg).into())
96        }
97    }
98}
99
100#[derive(Debug, Deserialize)]
101pub struct FileList {
102    pub files: Vec<File>,
103}
104
105#[derive(Debug, Serialize, Deserialize)]
106pub struct File {
107    pub id: String,
108    pub name: String,
109}