supabase_storage/build/object/
sign.rs

1use reqwest::{header::HeaderValue, Method};
2
3use crate::build::{
4    builder::{BodyType, Builder},
5    executor::Executor,
6};
7
8impl Builder {
9    /// generate presigned url to retrieve an object
10    ///
11    /// # Arguments
12    ///
13    /// * `bucket_name` - bucket name
14    /// * `object` - object name
15    ///
16    /// # Returns
17    ///
18    /// * `Executor` - The constructed `Executor` instance for executing the request.
19    ///
20    /// # Example
21    /// ```
22    /// use supabase_storage::{
23    ///     Storage,
24    ///     config::SupabaseConfig,
25    ///     model::bucket::NewBucket,
26    /// };
27    /// use dotenv::dotenv;
28    ///
29    /// #[tokio::main]
30    /// async fn main() {
31    ///     dotenv().ok();
32    ///     let config = SupabaseConfig::default();
33    ///     let response = Storage::new_with_config(config)
34    ///         .from()
35    ///         .create_signed_url("thefux", "bitcoin.pdf", r#"
36    ///             {
37    ///                 "expiresIn": 3600,
38    ///                 "transform": {
39    ///                     "height": 0,
40    ///                     "width": 0,
41    ///                     "resize": "cover",
42    ///                     "format": "origin",
43    ///                     "quality": 100
44    ///                 }
45    ///             }"#)
46    ///         .execute()
47    ///         .await
48    ///         .unwrap();
49    /// }
50    /// ```
51    pub fn create_signed_url(mut self, bucket_name: &str, object: &str, body: &str) -> Executor {
52        self.headers
53            .insert("Content-Type", HeaderValue::from_static("application/json"));
54        self.method = Method::POST;
55        self.url
56            .path_segments_mut()
57            .unwrap()
58            .push("object")
59            .push("sign")
60            .push(bucket_name)
61            .push(object);
62
63        self.body = Some(BodyType::StringBody(body.to_string()));
64        self.create_executor()
65    }
66
67    /// generate presigned urls to retrieve objects
68    ///
69    /// # Arguments
70    ///
71    /// * `bucket_name` - bucket name
72    /// * `object` - object name
73    ///
74    /// # Returns
75    ///
76    /// * `Executor` - The constructed `Executor` instance for executing the request.
77    ///
78    /// # Example
79    /// ```
80    /// use supabase_storage::{
81    ///     Storage,
82    ///     config::SupabaseConfig,
83    ///     model::bucket::NewBucket,
84    /// };
85    /// use dotenv::dotenv;
86    ///
87    /// #[tokio::main]
88    /// async fn main() {
89    ///     dotenv().ok();
90    ///     let config = SupabaseConfig::default();
91    ///     let response = Storage::new_with_config(config)
92    ///         .from()
93    ///         .create_signed_urls("thefux", r#"{"expiresIn": 3600, "paths": ["hello.pdf", "test.pdf"]}"#)
94    ///         .execute()
95    ///         .await
96    ///         .unwrap();
97    /// }
98    /// ```
99    pub fn create_signed_urls(mut self, bucket_name: &str, body: &str) -> Executor {
100        self.headers
101            .insert("Content-Type", HeaderValue::from_static("application/json"));
102        self.method = Method::POST;
103        self.url
104            .path_segments_mut()
105            .unwrap()
106            .push("object")
107            .push("sign")
108            .push(bucket_name);
109
110        self.body = Some(BodyType::StringBody(body.to_string()));
111        self.create_executor()
112    }
113
114    /// get object via pre-signed url
115    ///
116    /// # Arguments
117    ///
118    /// * `bucket_name` - bucket name
119    /// * `object` - object name
120    /// * `token` - sign token
121    /// * `file` - file object
122    ///
123    /// # Returns
124    ///
125    /// * `Executor` - The constructed `Executor` instance for executing the request.
126    ///
127    /// # Example
128    /// ```
129    /// use supabase_storage::{
130    ///     Storage,
131    ///     config::SupabaseConfig,
132    ///     model::bucket::NewBucket,
133    /// };
134    /// use dotenv::dotenv;
135    /// use tokio::fs::File;
136    ///
137    /// #[tokio::main]
138    /// async fn main() {
139    ///     dotenv().ok();
140    ///     let config = SupabaseConfig::default();
141    ///     let response = Storage::new_with_config(config)
142    ///         .from()
143    ///         .get_object_with_pre_assigned_url("thefux", "btc.pdf", "<token>")
144    ///         .execute()
145    ///         .await
146    ///         .unwrap();
147    /// }
148    /// ```
149    pub fn get_object_with_pre_assigned_url(
150        mut self,
151        bucket_name: &str,
152        object: &str,
153        token: &str,
154    ) -> Executor {
155        self.url
156            .path_segments_mut()
157            .unwrap()
158            .push("object")
159            .push("sign")
160            .push(bucket_name)
161            .push(object);
162
163        self.url.query_pairs_mut().append_pair("token", token);
164
165        self.create_executor()
166    }
167}
168
169#[cfg(test)]
170mod test {
171    use reqwest::{header::HeaderMap, Client, Method};
172    use url::{Host, Origin};
173
174    use crate::build::builder::{BodyType, Builder};
175
176    #[test]
177    fn test_get_object_with_signed_url() {
178        let executor = Builder::new(
179            url::Url::parse("http://localhost").unwrap(),
180            HeaderMap::new(),
181            Client::new(),
182        )
183        .get_object_with_pre_assigned_url("thefux", "btc.pdf", "token");
184
185        assert_eq!(executor.builder.method, Method::GET);
186        assert_eq!(
187            executor.builder.url.origin(),
188            Origin::Tuple("http".into(), Host::Domain("localhost".into()), 80)
189        );
190        assert_eq!(executor.builder.url.path(), "/object/sign/thefux/btc.pdf");
191        assert_eq!(executor.builder.url.query(), Some("token=token"));
192    }
193
194    #[test]
195    fn test_create_signed_url() {
196        let executor = Builder::new(
197            url::Url::parse("http://localhost").unwrap(),
198            HeaderMap::new(),
199            Client::new(),
200        )
201        .create_signed_url(
202            "thefux",
203            "btc.pdf",
204            r#"
205                    {
206                        "expiresIn": 3600,
207                        "transform": {
208                            "height": 0,
209                            "width": 0,
210                            "resize": "cover",
211                            "format": "origin",
212                            "quality": 100
213                        }
214                    }"#,
215        );
216
217        if let Some(typ) = executor.builder.body {
218            match typ {
219                BodyType::StringBody(val) => assert_eq!(
220                    val,
221                    r#"
222                    {
223                        "expiresIn": 3600,
224                        "transform": {
225                            "height": 0,
226                            "width": 0,
227                            "resize": "cover",
228                            "format": "origin",
229                            "quality": 100
230                        }
231                    }"#
232                ),
233                _ => panic!("nop"),
234            }
235        }
236        assert_eq!(executor.builder.method, Method::POST);
237        assert_eq!(
238            executor.builder.url.origin(),
239            Origin::Tuple("http".into(), Host::Domain("localhost".into()), 80)
240        );
241        assert_eq!(executor.builder.url.path(), "/object/sign/thefux/btc.pdf");
242    }
243
244    #[test]
245    fn test_create_signed_urls() {
246        let executor = Builder::new(
247            url::Url::parse("http://localhost").unwrap(),
248            HeaderMap::new(),
249            Client::new(),
250        )
251        .create_signed_urls("thefux", r#"{"paths":["btc.pdf","test.pdf"]}"#);
252
253        if let Some(typ) = executor.builder.body {
254            match typ {
255                BodyType::StringBody(val) => assert_eq!(val, r#"{"paths":["btc.pdf","test.pdf"]}"#),
256                _ => panic!("nop"),
257            }
258        }
259        assert_eq!(executor.builder.method, Method::POST);
260        assert_eq!(
261            executor.builder.url.origin(),
262            Origin::Tuple("http".into(), Host::Domain("localhost".into()), 80)
263        );
264        assert_eq!(executor.builder.url.path(), "/object/sign/thefux");
265    }
266}