Skip to main content

resourcespace_client/api/
collection.rs

1use serde::Serialize;
2use serde_with::json::JsonString;
3use serde_with::{serde_as, skip_serializing_none};
4use validator::Validate;
5
6use crate::client::Client;
7use crate::error::RsError;
8
9use super::{List, SortOrder};
10
11/// Sub-API for collection endpoints.
12#[derive(Debug)]
13pub struct CollectionApi<'a> {
14    client: &'a Client,
15}
16
17impl<'a> CollectionApi<'a> {
18    pub(crate) fn new(client: &'a Client) -> Self {
19        Self { client }
20    }
21
22    /// Returns a list of the user's collections.
23    ///
24    /// ## Arguments
25    /// `None`
26    ///
27    /// ## Examples
28    /// ```no_run
29    /// # use resourcespace_client::Client;
30    /// # async fn example(client: Client) -> Result<(), Box<dyn std::error::Error>> {
31    /// let status = client.collection().get_user_collections().await?;
32    /// # Ok(())
33    /// # }
34    /// ```
35    pub async fn get_user_collections(&self) -> Result<serde_json::Value, RsError> {
36        self.client
37            .send_request("get_user_collections", reqwest::Method::GET, ())
38            .await
39    }
40
41    /// Add a resource to a collection.
42    ///
43    /// ## Arguments
44    /// * `request` - Parameters built via [`AddResourceToCollectionRequest`]
45    ///
46    /// ## Returns
47    /// True or false depending on operation success.
48    ///
49    /// ## TODO: Errors
50    ///
51    /// ## TODO: Examples
52    pub async fn add_resource_to_collection(
53        &self,
54        request: AddResourceToCollectionRequest,
55    ) -> Result<serde_json::Value, RsError> {
56        self.client
57            .send_request("add_resource_to_collection", reqwest::Method::POST, request)
58            .await
59    }
60
61    /// Remove a resource from a collection.
62    ///
63    /// ## Arguments
64    /// * `request` - Parameters built via [`RemoveResourceFromCollectionRequest`]
65    ///
66    /// ## Returns
67    /// True or false depending on operation success.
68    ///
69    /// ## TODO: Errors
70    ///
71    /// ## TODO: Examples
72    pub async fn remove_resource_from_collection(
73        &self,
74        request: RemoveResourceFromCollectionRequest,
75    ) -> Result<serde_json::Value, RsError> {
76        self.client
77            .send_request(
78                "remove_resource_from_collection",
79                reqwest::Method::POST,
80                request,
81            )
82            .await
83    }
84
85    /// Create a new collection for the user.
86    ///
87    /// ## Arguments
88    /// * `request` - Parameters built via [`CreateCollectionRequest`]
89    ///
90    /// ## Returns
91    /// Integer|bool - ID of the collection created, false if collection creation is not permitted
92    ///
93    /// ## TODO: Errors
94    ///
95    /// ## TODO: Examples
96    pub async fn create_collection(
97        &self,
98        request: CreateCollectionRequest,
99    ) -> Result<serde_json::Value, RsError> {
100        self.client
101            .send_request("create_collection", reqwest::Method::POST, request)
102            .await
103    }
104
105    /// Deletes a collection. The user must have write access to this collection.
106    ///
107    /// ## Arguments
108    /// * `request` - Parameters built via [`DeleteCollectionRequest`]
109    ///
110    /// ## Returns
111    /// True or false depending on operation success.
112    ///
113    /// ## TODO: Errors
114    ///
115    /// ## TODO: Examples
116    pub async fn delete_collection(
117        &self,
118        request: DeleteCollectionRequest,
119    ) -> Result<serde_json::Value, RsError> {
120        self.client
121            .send_request("delete_collection", reqwest::Method::POST, request)
122            .await
123    }
124
125    /// Search public and featured collections.
126    ///
127    /// ## Arguments
128    /// * `request` - Parameters built via [`SearchPublicCollectionsRequest`]
129    ///
130    /// ## Returns
131    /// A list of matching public or featured collections.
132    ///
133    /// ## TODO: Errors
134    ///
135    /// ## TODO: Examples
136    pub async fn search_public_collections(
137        &self,
138        request: SearchPublicCollectionsRequest,
139    ) -> Result<serde_json::Value, RsError> {
140        self.client
141            .send_request("search_public_collections", reqwest::Method::GET, request)
142            .await
143    }
144
145    /// Get collection details.
146    ///
147    /// This requires administrator access ("a" permission).
148    ///
149    /// ## Arguments
150    /// * `request` - Parameters built via [`GetCollectionRequest`]
151    ///
152    /// ## Returns
153    /// The collection details including owner name, description, public/private status, thumbnail image reference. All available columns are returned.
154    ///
155    /// ## TODO: Errors
156    ///
157    /// ## TODO: Examples
158    pub async fn get_collection(
159        &self,
160        request: GetCollectionRequest,
161    ) -> Result<serde_json::Value, RsError> {
162        self.client
163            .send_request("get_collection", reqwest::Method::GET, request)
164            .await
165    }
166
167    /// Save collection data.
168    ///
169    /// ## Arguments
170    /// * `request` - Parameters built via [`SaveCollectionRequest`]
171    ///
172    /// ## Returns
173    /// Returns false if access control fails or invalid arguments have been received (e.g ref not a number), true otherwise.
174    ///
175    /// ## TODO: Errors
176    ///
177    /// ## TODO: Examples
178    pub async fn save_collection(
179        &self,
180        request: SaveCollectionRequest,
181    ) -> Result<serde_json::Value, RsError> {
182        self.client
183            .send_request("save_collection", reqwest::Method::POST, request)
184            .await
185    }
186
187    /// Shows or hides a collection from the user's drop-down list.
188    ///
189    /// ## Arguments
190    /// * `request` - Parameters built via [`ShowHideCollectionRequest`]
191    ///
192    /// ## Returns
193    /// True or false depending on operation success.
194    ///
195    /// ## TODO: Errors
196    ///
197    /// ## TODO: Examples
198    pub async fn show_hide_collection(
199        &self,
200        request: ShowHideCollectionRequest,
201    ) -> Result<serde_json::Value, RsError> {
202        self.client
203            .send_request("show_hide_collection", reqwest::Method::POST, request)
204            .await
205    }
206
207    /// Sends a copy of the collection for admin review.
208    ///
209    /// ## Arguments
210    /// * `request` - Parameters built via [`SendCollectionToAdminRequest`]
211    ///
212    /// ## Returns
213    /// True or false depending on operation success.
214    ///
215    /// ## TODO: Errors
216    ///
217    /// ## TODO: Examples
218    pub async fn send_collection_to_admin(
219        &self,
220        request: SendCollectionToAdminRequest,
221    ) -> Result<serde_json::Value, RsError> {
222        self.client
223            .send_request("send_collection_to_admin", reqwest::Method::POST, request)
224            .await
225    }
226
227    /// Get ResourceSpace featured collections (category).
228    ///
229    /// ## Arguments
230    /// * `request` - Parameters built via [`GetFeaturedCollectionsRequest`]
231    ///
232    /// ## Returns
233    /// If successful, a 200 HTTP status will be returned with the body containing an array. If the parent is invalid an empty array will be returned instead.
234    ///
235    /// ## TODO: Errors
236    ///
237    /// ## TODO: Examples
238    pub async fn get_featured_collections(
239        &self,
240        request: GetFeaturedCollectionsRequest,
241    ) -> Result<serde_json::Value, RsError> {
242        self.client
243            .send_request("get_featured_collections", reqwest::Method::GET, request)
244            .await
245    }
246
247    /// Deletes all resources in a collection.
248    ///
249    /// The user must have edit access to the resources, permission to delete resources and the collection must be writable.
250    ///
251    /// ## Arguments
252    /// * `request` - Parameters built via [`DeleteResourcesInCollectionRequest`]
253    ///
254    /// ## Returns
255    /// True or false depending on operation success.
256    ///
257    /// ## TODO: Errors
258    ///
259    /// ## TODO: Examples
260    pub async fn delete_resources_in_collection(
261        &self,
262        request: DeleteResourcesInCollectionRequest,
263    ) -> Result<serde_json::Value, RsError> {
264        self.client
265            .send_request(
266                "delete_resources_in_collection",
267                reqwest::Method::POST,
268                request,
269            )
270            .await
271    }
272
273    /// Get the total resource count for a list of collections.
274    ///
275    /// Requires permission `b` and the collections must be readable by the user.
276    ///
277    /// ## Arguments
278    /// * `request` - Parameters built via [`GetCollectionsResourceCountRequest`]
279    ///
280    /// ## Returns
281    /// Array of collections and their total resource count. Note the returned array may
282    /// not contain keys for all input IDs if validation fails for some.
283    ///
284    /// ## TODO: Errors
285    ///
286    /// ## TODO: Examples
287    pub async fn get_collections_resource_count(
288        &self,
289        request: GetCollectionsResourceCountRequest,
290    ) -> Result<serde_json::Value, RsError> {
291        self.client
292            .send_request(
293                "get_collections_resource_count",
294                reqwest::Method::GET,
295                request,
296            )
297            .await
298    }
299}
300
301#[derive(Clone, Debug, PartialEq, Serialize)]
302pub struct AddResourceToCollectionRequest {
303    /// The ID of the resource to add.
304    pub resource: u32,
305    /// The ID of the collection to add the resource to.
306    pub collection: u32,
307}
308
309impl AddResourceToCollectionRequest {
310    pub fn new(resource: u32, collection: u32) -> Self {
311        Self {
312            resource,
313            collection,
314        }
315    }
316}
317
318#[derive(Clone, Debug, PartialEq, Serialize)]
319pub struct RemoveResourceFromCollectionRequest {
320    /// The ID of the resource to remove.
321    pub resource: u32,
322    /// The ID of the collection to remove the resource from.
323    pub collection: u32,
324}
325
326impl RemoveResourceFromCollectionRequest {
327    pub fn new(resource: u32, collection: u32) -> Self {
328        Self {
329            resource,
330            collection,
331        }
332    }
333}
334
335#[skip_serializing_none]
336#[derive(Clone, Debug, PartialEq, Serialize)]
337pub struct CreateCollectionRequest {
338    /// The name of the new collection.
339    pub name: String,
340    /// If set, marks this collection as an upload collection.
341    pub forupload: Option<u8>,
342}
343
344impl CreateCollectionRequest {
345    pub fn new(name: impl Into<String>) -> Self {
346        Self {
347            name: name.into(),
348            forupload: None,
349        }
350    }
351
352    pub fn forupload(mut self, forupload: bool) -> Self {
353        self.forupload = Some(forupload as u8);
354        self
355    }
356}
357
358#[derive(Clone, Debug, PartialEq, Serialize)]
359pub struct DeleteCollectionRequest {
360    /// The ID of the collection to delete.
361    pub collection: u32,
362}
363
364impl DeleteCollectionRequest {
365    pub fn new(collection: u32) -> Self {
366        Self { collection }
367    }
368}
369
370#[skip_serializing_none]
371#[derive(Clone, Debug, Default, PartialEq, Serialize)]
372pub struct SearchPublicCollectionsRequest {
373    /// Optional search string to filter collections by name.
374    pub search: Option<String>,
375    /// Field name to order results by.
376    pub order_by: Option<String>,
377    /// Sort direction for the results.
378    pub sort: Option<SortOrder>,
379    /// If set, excludes theme/featured collections from results.
380    pub exclude_themes: Option<u8>,
381}
382
383impl SearchPublicCollectionsRequest {
384    pub fn new() -> Self {
385        Self::default()
386    }
387
388    pub fn search(mut self, search: impl Into<String>) -> Self {
389        self.search = Some(search.into());
390        self
391    }
392
393    pub fn order_by(mut self, order_by: impl Into<String>) -> Self {
394        self.order_by = Some(order_by.into());
395        self
396    }
397
398    pub fn sort(mut self, sort: SortOrder) -> Self {
399        self.sort = Some(sort);
400        self
401    }
402
403    pub fn exclude_themes(mut self, exclude_themes: bool) -> Self {
404        self.exclude_themes = Some(exclude_themes as u8);
405        self
406    }
407}
408
409#[derive(Clone, Debug, PartialEq, Serialize)]
410pub struct GetCollectionRequest {
411    /// The ID of the collection to retrieve.
412    #[serde(rename = "ref")]
413    pub r#ref: u32,
414}
415
416impl GetCollectionRequest {
417    pub fn new(r#ref: u32) -> Self {
418        Self { r#ref }
419    }
420}
421
422#[serde_as]
423#[derive(Clone, Debug, PartialEq, Serialize)]
424pub struct SaveCollectionRequest {
425    /// The ID of the collection to save.
426    #[serde(rename = "ref")]
427    pub r#ref: u32,
428    /// JSON object containing the collection fields to update (e.g. name, description, public).
429    #[serde_as(as = "JsonString")]
430    pub coldata: SaveCollectionColdata,
431}
432
433impl SaveCollectionRequest {
434    pub fn new(r#ref: u32, coldata: SaveCollectionColdata) -> Self {
435        Self { r#ref, coldata }
436    }
437}
438
439#[derive(Clone, Debug, PartialEq, Serialize, Validate)]
440pub struct SaveCollectionColdata {
441    /// Comma-separated value of keywords to be associated with this collection.
442    pub keywords: Option<List<String>>,
443    /// To set whether other users are allowed to add/remove resources when collection is shared or is public. The allowed value is 0 or 1.
444    #[validate(range(min = 0, max = 1))]
445    pub allow_changes: Option<u8>,
446    /// Comma-separated value of users to attach to the collection.
447    pub users: Option<List<String>>,
448    /// Collection name.
449    pub name: Option<String>,
450    /// 0 for private, 1 for public (legacy).
451    #[validate(range(min = 0, max = 1))]
452    pub public: Option<u8>,
453    /// 0 = standard, 3 = Featured collection, 4 = public. If 3 or 4 then public should be set to 1.
454    #[serde(rename = "type")]
455    pub r#type: Option<u8>,
456    /// ID of parent featured collection. Set to 0 to create a new root level collection (see below). Applies to Featured collections only.
457    pub parent: Option<u32>,
458    /// Required to be set to 1 if creating a root level featured collection (parent=0). Applies to Featured collections only.
459    #[validate(range(min = 0, max = 1))]
460    pub force_featured_collection_type: Option<u8>,
461    /// 0 = no image, 1 = most popular image, 10 - most popular images, 100 - manually select image. Applies to Featured collections only.
462    pub thumbnail_selection_method: Option<u32>,
463    /// Resource ID to use as thumbnail. Only if thumbnail_selection_method =100. Applies to Featured collections only.
464    pub bg_img_resource_ref: Option<u32>,
465}
466
467#[derive(Clone, Debug, PartialEq, Serialize)]
468pub struct ShowHideCollectionRequest {
469    /// The ID of the collection to show or hide.
470    pub collection: u32,
471    /// If set, shows the collection in the drop-down list.
472    pub show: u8,
473    /// The ID of the user whose drop-down list is being updated.
474    pub user: u32,
475}
476
477impl ShowHideCollectionRequest {
478    pub fn new(collection: u32, show: bool, user: u32) -> Self {
479        Self {
480            collection,
481            show: show as u8,
482            user,
483        }
484    }
485}
486
487#[derive(Clone, Debug, PartialEq, Serialize)]
488pub struct SendCollectionToAdminRequest {
489    /// The ID of the collection to send to the administrator for review.
490    pub collection: u32,
491}
492
493impl SendCollectionToAdminRequest {
494    pub fn new(collection: u32) -> Self {
495        Self { collection }
496    }
497}
498
499#[derive(Clone, Debug, PartialEq, Serialize)]
500pub struct GetFeaturedCollectionsRequest {
501    /// The ID of the parent featured collection (category) to retrieve children for. Use 0 for top-level.
502    pub parent: u32,
503}
504
505impl GetFeaturedCollectionsRequest {
506    pub fn new(parent: u32) -> Self {
507        Self { parent }
508    }
509}
510
511#[derive(Clone, Debug, PartialEq, Serialize)]
512pub struct DeleteResourcesInCollectionRequest {
513    /// The ID of the collection whose resources should all be deleted.
514    pub collection: u32,
515}
516
517impl DeleteResourcesInCollectionRequest {
518    pub fn new(collection: u32) -> Self {
519        Self { collection }
520    }
521}
522
523#[derive(Clone, Debug, PartialEq, Serialize)]
524pub struct GetCollectionsResourceCountRequest {
525    /// Comma-separated list of collection IDs to retrieve resource counts for.
526    pub refs: List<u32>,
527}
528
529impl GetCollectionsResourceCountRequest {
530    pub fn new(refs: impl Into<List<u32>>) -> Self {
531        Self { refs: refs.into() }
532    }
533}