Skip to main content

canvas_lms_api/resources/
folder.rs

1use crate::{error::Result, http::Requester, pagination::PageStream, params::flatten_params};
2use chrono::{DateTime, Utc};
3use serde::{Deserialize, Serialize};
4use std::sync::Arc;
5
6use crate::resources::file::File;
7
8/// Parameters for updating a Canvas folder.
9#[derive(Debug, Default, Clone, Serialize)]
10pub struct UpdateFolderParams {
11    #[serde(skip_serializing_if = "Option::is_none")]
12    pub name: Option<String>,
13    #[serde(skip_serializing_if = "Option::is_none")]
14    pub parent_folder_id: Option<u64>,
15    #[serde(skip_serializing_if = "Option::is_none")]
16    pub locked: Option<bool>,
17    #[serde(skip_serializing_if = "Option::is_none")]
18    pub hidden: Option<bool>,
19    #[serde(skip_serializing_if = "Option::is_none")]
20    pub position: Option<u64>,
21}
22
23/// A folder in the Canvas file storage system.
24#[derive(Debug, Clone, Deserialize, Serialize, canvas_lms_api_derive::CanvasResource)]
25pub struct Folder {
26    pub id: u64,
27    pub name: Option<String>,
28    pub full_name: Option<String>,
29    pub context_id: Option<u64>,
30    pub context_type: Option<String>,
31    pub parent_folder_id: Option<u64>,
32    pub created_at: Option<DateTime<Utc>>,
33    pub updated_at: Option<DateTime<Utc>>,
34    pub lock_at: Option<DateTime<Utc>>,
35    pub unlock_at: Option<DateTime<Utc>>,
36    pub position: Option<u64>,
37    pub locked: Option<bool>,
38    pub folders_url: Option<String>,
39    pub files_url: Option<String>,
40    pub files_count: Option<u64>,
41    pub folders_count: Option<u64>,
42    pub hidden: Option<bool>,
43    pub locked_for_user: Option<bool>,
44    pub hidden_for_user: Option<bool>,
45    pub for_submissions: Option<bool>,
46    pub can_upload: Option<bool>,
47
48    #[serde(skip)]
49    pub(crate) requester: Option<Arc<Requester>>,
50}
51
52impl Folder {
53    /// Update this folder's name, parent, or lock state.
54    ///
55    /// # Canvas API
56    /// `PUT /api/v1/folders/:id`
57    pub async fn update(&self, params: UpdateFolderParams) -> Result<Folder> {
58        let form = flatten_params(&serde_json::to_value(&params).unwrap());
59        let mut f: Folder = self
60            .req()
61            .put(&format!("folders/{}", self.id), &form)
62            .await?;
63        f.requester = self.requester.clone();
64        Ok(f)
65    }
66
67    /// Delete this folder.
68    ///
69    /// # Canvas API
70    /// `DELETE /api/v1/folders/:id`
71    pub async fn delete(&self) -> Result<Folder> {
72        let mut f: Folder = self
73            .req()
74            .delete(&format!("folders/{}", self.id), &[])
75            .await?;
76        f.requester = self.requester.clone();
77        Ok(f)
78    }
79
80    /// Stream all files in this folder.
81    ///
82    /// # Canvas API
83    /// `GET /api/v1/folders/:id/files`
84    pub fn get_files(&self) -> PageStream<File> {
85        PageStream::new_with_injector(
86            Arc::clone(self.req()),
87            &format!("folders/{}/files", self.id),
88            vec![],
89            |mut f: File, req| {
90                f.requester = Some(Arc::clone(&req));
91                f
92            },
93        )
94    }
95
96    /// Stream all subfolders in this folder.
97    ///
98    /// # Canvas API
99    /// `GET /api/v1/folders/:id/folders`
100    pub fn get_folders(&self) -> PageStream<Folder> {
101        PageStream::new_with_injector(
102            Arc::clone(self.req()),
103            &format!("folders/{}/folders", self.id),
104            vec![],
105            |mut f: Folder, req| {
106                f.requester = Some(Arc::clone(&req));
107                f
108            },
109        )
110    }
111
112    /// Create a subfolder inside this folder.
113    ///
114    /// # Canvas API
115    /// `POST /api/v1/folders/:id/folders`
116    pub async fn create_folder(&self, name: &str) -> Result<Folder> {
117        let params = vec![("name".to_string(), name.to_string())];
118        let mut f: Folder = self
119            .req()
120            .post(&format!("folders/{}/folders", self.id), &params)
121            .await?;
122        f.requester = self.requester.clone();
123        Ok(f)
124    }
125
126    /// Copy a file into this folder.
127    ///
128    /// # Canvas API
129    /// `POST /api/v1/folders/:dest_folder_id/copy_file`
130    pub async fn copy_file(&self, source_file_id: u64) -> Result<File> {
131        let params = vec![("source_file_id".to_string(), source_file_id.to_string())];
132        let mut f: File = self
133            .req()
134            .post(&format!("folders/{}/copy_file", self.id), &params)
135            .await?;
136        f.requester = self.requester.clone();
137        Ok(f)
138    }
139
140    /// Upload a file to this folder.
141    ///
142    /// Canvas uses a two-step upload: first POSTing metadata to obtain an upload URL,
143    /// then POSTing the file as multipart form data to that URL.
144    ///
145    /// # Canvas API
146    /// `POST /api/v1/folders/:id/files`
147    pub async fn upload_file(
148        &self,
149        request: crate::upload::UploadRequest,
150        data: Vec<u8>,
151    ) -> Result<File> {
152        crate::upload::initiate_and_upload(
153            self.req(),
154            &format!("folders/{}/files", self.id),
155            request,
156            data,
157        )
158        .await
159    }
160}