ucare/
group.rs

1//! Holds all primitives and logic related file entity.
2//!
3//! Individual files on Uploadcare can be joined into groups. Those can be used
4//! to better organize your workflow. Technically, groups are ordered lists of
5//! files and can hold files together with Image Transformations in their URLs.
6//! The most common case with creating groups is when users upload multiple files at once.
7//!
8//! NOTE: a group itself and files within that group MUST belong to the same project.
9//! Groups are immutable and the only way to add/remove a file is creating a new group.
10//!
11//! Groups are identified in a way similar to individual files.
12//! A group ID consists of a UUID followed by a “~” tilde character and a group size:
13//! integer number of files in group.
14//! For example, here is an identifier for a group holding 12 files:
15//!   badfc9f7-f88f-4921-9cc0-22e2c08aa2da~12
16
17use std::fmt::{self, Debug, Display};
18
19use reqwest::{Method, Url};
20use serde::Deserialize;
21
22use crate::ucare::{rest::Client, IntoUrlQuery, Result};
23
24/// Service is used to make calls to group API.
25pub struct Service<'a> {
26    client: &'a Client,
27}
28
29/// creates an instance of the group service
30pub fn new_svc(client: &Client) -> Service {
31    Service { client }
32}
33
34impl Service<'_> {
35    /// Acquires some file specific info
36    pub fn info(&self, group_id: &str) -> Result<Info> {
37        self.client.call::<String, String, Info>(
38            Method::GET,
39            format!("/groups/{}/", group_id),
40            None,
41            None,
42        )
43    }
44
45    /// Returns a list of groups
46    ///
47    /// ```rust,ignore
48    /// # use ucare::group;
49    ///
50    /// let params = group::ListParams{
51    ///     limit: Some(10),
52    ///     ordering: Some(group::Ordering::CreatedAtDesc),
53    ///     from: None,
54    /// };
55    /// let list = group_svc.list(params)?;
56    /// let mut next_page = list.next;
57    ///
58    /// let mut groups = list.results.unwrap();
59    /// while let Some(next) = next_page {
60    ///     let new_page = group_svc.get_page(&next).unwrap();
61    ///     next_page = new_page.next;
62    ///     groups.extend(new_page.results.unwrap());
63    /// }
64    ///
65    /// for group in groups.iter() {
66    ///     println!("group: {}", group);
67    /// }
68    /// ```
69    pub fn list(&self, params: ListParams) -> Result<List> {
70        self.client.call::<ListParams, String, List>(
71            Method::GET,
72            format!("/groups/"),
73            Some(params),
74            None,
75        )
76    }
77
78    /// Gets next page by its url
79    pub fn get_page(&self, url: &str) -> Result<List> {
80        let url = Url::parse(url)?;
81        self.client.call_url::<String, List>(Method::GET, url, None)
82    }
83
84    /// Marks all files in group as stored
85    pub fn store(&self, group_id: &str) -> Result<Info> {
86        self.client.call::<String, String, Info>(
87            Method::PUT,
88            format!("/groups/{}/storage/", group_id),
89            None,
90            None,
91        )
92    }
93}
94
95/// Info holds group specific information
96#[derive(Debug, Deserialize)]
97pub struct Info {
98    /// group identifier
99    pub id: String,
100    /// date and time when a group was created
101    pub datetime_created: Option<String>,
102    /// date and time when a group was stored
103    pub datetime_stored: Option<String>,
104    /// number of files in a group
105    pub files_count: i32,
106    /// public CDN URL for a group
107    pub cdn_url: String,
108}
109
110/// Holds all possible params for for the list method
111pub struct ListParams {
112    /// Specifies preferred amount of groups in a list for a single
113    /// response. Defaults to 100, while the maximum is 1000
114    pub limit: Option<i32>,
115    /// Specifies the way groups are sorted in a returned list.
116    /// By default is set to datetime_created.
117    pub ordering: Option<Ordering>,
118    /// A starting point for filtering group lists. MUST be a datetime value with T used as a
119    /// separator. Example: "2015-01-02T10:00:00"
120    pub from: Option<String>,
121}
122
123/// Specifies the way groups are sorted in a returned list.
124/// By default is set to datetime_created.
125pub enum Ordering {
126    /// datetime_created
127    CreatedAtAsc,
128    /// -datetime_created
129    CreatedAtDesc,
130}
131
132impl Display for Ordering {
133    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
134        let val = match *self {
135            Ordering::CreatedAtAsc => "datetime_created",
136            Ordering::CreatedAtDesc => "-datetime_created",
137        };
138
139        write!(f, "{}", val)
140    }
141}
142
143impl IntoUrlQuery for ListParams {
144    fn into_query(self) -> String {
145        let mut q = String::new();
146
147        q.push_str("limit=");
148        if let Some(val) = self.limit {
149            q.push_str(val.to_string().as_str());
150        } else {
151            q.push_str("100");
152        }
153        q.push('&');
154
155        q.push_str("ordering=");
156        if let Some(val) = self.ordering {
157            q.push_str(val.to_string().as_str());
158        } else {
159            q.push_str(Ordering::CreatedAtAsc.to_string().as_str());
160        }
161
162        if let Some(val) = self.from {
163            q.push('&');
164            q.push_str("from=");
165            q.push_str(val.as_str());
166        }
167
168        q
169    }
170}
171
172/// Holds a list of groups
173#[derive(Debug, Deserialize)]
174pub struct List {
175    /// Actual results
176    pub results: Option<Vec<Info>>,
177    /// Next page URL.
178    pub next: Option<String>,
179    /// Previous page URL.
180    pub previous: Option<String>,
181    /// A total number of objects of the queried type.
182    pub total: Option<f32>,
183    /// Number of objects per page.
184    pub per_page: Option<f32>,
185}