drive_v3/resources/
comments.rs

1use reqwest::Method;
2use drive_v3_macros::{DriveRequestBuilder, request};
3
4use super::DriveRequestBuilder;
5use crate::{objects, Credentials};
6
7#[request(
8    method=Method::POST,
9    url="https://www.googleapis.com/drive/v3/files/{file_id}/comments",
10    returns=objects::Comment,
11)]
12#[derive(DriveRequestBuilder)]
13/// A request builder to create a comment on a file.
14pub struct CreateRequest {
15    /// The comment to be created
16    #[drive_v3(body)]
17    comment: Option<objects::Comment>
18}
19
20#[request(
21    method=Method::DELETE,
22    url="https://www.googleapis.com/drive/v3/files/{file_id}/comments/{comment_id}",
23    returns=(),
24)]
25#[derive(DriveRequestBuilder)]
26/// A request builder to delete a comment on a file.
27pub struct DeleteRequest {}
28
29#[request(
30    method=Method::GET,
31    url="https://www.googleapis.com/drive/v3/files/{file_id}/comments/{comment_id}",
32    returns=objects::Comment,
33)]
34#[derive(DriveRequestBuilder)]
35/// A request builder to get a comment on a file.
36pub struct GetRequest {
37    /// Whether to return deleted comments.
38    ///
39    /// Deleted comments will not include their original content.
40    #[drive_v3(parameter)]
41    include_deleted: Option<bool>
42}
43
44#[request(
45    method=Method::GET,
46    url="https://www.googleapis.com/drive/v3/files/{file_id}/comments",
47    returns=objects::CommentList,
48)]
49#[derive(DriveRequestBuilder)]
50/// A request builder to list the comments on a file.
51pub struct ListRequest {
52    /// Whether to return deleted comments.
53    ///
54    /// Deleted comments will not include their original content.
55    #[drive_v3(parameter)]
56    include_deleted: Option<bool>,
57
58    /// The maximum number of comments to return per page.
59    #[drive_v3(parameter)]
60    page_size: Option<i64>,
61
62    /// The token for continuing a previous list request on the next page.
63    ///
64    /// This should be set to the value of
65    /// [`next_page_token`](objects::CommentList::next_page_token) from the
66    /// previous response.
67    #[drive_v3(parameter)]
68    page_token: Option<String>,
69
70    /// The minimum value of `modifiedTime` for the result comments
71    /// (RFC 3339 date-time).
72    #[drive_v3(parameter)]
73    start_modified_time: Option<String>,
74}
75
76#[request(
77    method=Method::PATCH,
78    url="https://www.googleapis.com/drive/v3/files/{file_id}/comments/{comment_id}",
79    returns=objects::Comment,
80)]
81#[derive(DriveRequestBuilder)]
82/// A request builder to update a comment on a file.
83pub struct UpdateRequest {
84    /// The updated comment
85    #[drive_v3(body)]
86    comment: Option<objects::Comment>
87}
88
89/// Comments on a file.
90///
91/// Some resource methods (such as [`comments.update`](Comments::update))
92/// require a `comment_id`. Use the [`comments.list`](Comments::list) method
93/// to retrieve the ID for a comment in a file.
94///
95/// # Examples:
96///
97/// List the comments in a file
98///
99/// ```no_run
100/// # use drive_v3::{Error, Credentials, Drive};
101/// #
102/// # let drive = Drive::new( &Credentials::from_file(
103/// #     "../.secure-files/google_drive_credentials.json",
104/// #     &["https://www.googleapis.com/auth/drive.file"],
105/// # )? );
106/// #
107/// let file_id = "some-file-id";
108///
109/// let comment_list = drive.comments.list(&file_id)
110///     .fields("*") // You must set the fields
111///     .page_size(10)
112///     .execute()?;
113///
114/// if let Some(comments) = comment_list.comments {
115///     for comment in comments {
116///         println!("{}", comment);
117///     }
118/// }
119/// # Ok::<(), Error>(())
120/// ```
121#[derive(Debug, Clone, PartialEq, Eq)]
122pub struct Comments {
123    /// Credentials used to authenticate a user's access to this resource.
124    credentials: Credentials,
125}
126
127impl Comments {
128    /// Creates a new [`Comments`] resource with the given [`Credentials`].
129    pub fn new( credentials: &Credentials ) -> Self {
130        Self { credentials: credentials.clone() }
131    }
132
133    /// Creates a comment on a file.
134    ///
135    /// See Google's
136    /// [documentation](https://developers.google.com/drive/api/reference/rest/v3/comments/create)
137    /// for more information.
138    ///
139    /// # Requires one of the following OAuth scopes:
140    ///
141    /// - `https://www.googleapis.com/auth/drive`
142    /// - `https://www.googleapis.com/auth/drive.file`
143    ///
144    /// # Examples:
145    ///
146    /// ```no_run
147    /// use drive_v3::objects::Comment;
148    /// # use drive_v3::{Error, Credentials, Drive};
149    /// #
150    /// # let drive = Drive::new( &Credentials::from_file(
151    /// #     "../.secure-files/google_drive_credentials.json",
152    /// #     &["https://www.googleapis.com/auth/drive.file"],
153    /// # )? );
154    ///
155    /// let comment = Comment {
156    ///     content: Some( "this is my comment".to_string() ),
157    ///     ..Default::default()
158    /// };
159    ///
160    /// let file_id = "some-file-id";
161    ///
162    /// let created_comment = drive.comments.create(&file_id)
163    ///     .fields("*")
164    ///     .comment(&comment)
165    ///     .execute()?;
166    ///
167    /// assert_eq!(created_comment.content, comment.content);
168    /// # Ok::<(), Error>(())
169    /// ```
170    pub fn create<T: AsRef<str>> ( &self, file_id: T ) -> CreateRequest {
171        CreateRequest::new(&self.credentials, file_id)
172    }
173
174    /// Deletes a comment.
175    ///
176    /// See Google's
177    /// [documentation](https://developers.google.com/drive/api/reference/rest/v3/comments/delete)
178    /// for more information.
179    ///
180    /// # Requires one of the following OAuth scopes:
181    ///
182    /// - `https://www.googleapis.com/auth/drive`
183    /// - `https://www.googleapis.com/auth/drive.file`
184    ///
185    /// # Examples:
186    ///
187    /// ```no_run
188    /// # use drive_v3::{Error, Credentials, Drive};
189    /// #
190    /// # let drive = Drive::new( &Credentials::from_file(
191    /// #     "../.secure-files/google_drive_credentials.json",
192    /// #     &["https://www.googleapis.com/auth/drive.file"],
193    /// # )? );
194    /// #
195    /// let file_id = "some-file-id";
196    /// let comment_id = "some-comment-id";
197    ///
198    /// let response = drive.comments.delete(&file_id, &comment_id).execute();
199    ///
200    /// assert!( response.is_ok() );
201    /// # Ok::<(), Error>(())
202    /// ```
203    pub fn delete<T, U> ( &self, file_id: T, comment_id: U ) -> DeleteRequest
204        where
205            T: AsRef<str>,
206            U: AsRef<str>
207    {
208        DeleteRequest::new(&self.credentials, file_id, comment_id)
209    }
210
211    /// Gets a comment by ID.
212    ///
213    /// See Google's
214    /// [documentation](https://developers.google.com/drive/api/reference/rest/v3/comments/get)
215    /// for more information.
216    ///
217    /// # Note:
218    ///
219    /// This request requires you to set the [`fields`](GetRequest::fields)
220    /// parameter.
221    ///
222    /// # Requires one of the following OAuth scopes:
223    ///
224    /// - `https://www.googleapis.com/auth/drive`
225    /// - `https://www.googleapis.com/auth/drive.file`
226    /// - `https://www.googleapis.com/auth/drive.readonly`
227    ///
228    /// # Examples:
229    ///
230    /// ```no_run
231    /// # use drive_v3::{Error, Credentials, Drive};
232    /// #
233    /// # let drive = Drive::new( &Credentials::from_file(
234    /// #     "../.secure-files/google_drive_credentials.json",
235    /// #     &["https://www.googleapis.com/auth/drive.file"],
236    /// # )? );
237    /// #
238    /// let file_id = "some-file-id";
239    /// let comment_id = "some-comment-id";
240    ///
241    /// let created_comment = drive.comments.get(&file_id, &comment_id)
242    ///     .fields("id, author, createdTime, content") // You must set the fields
243    ///     .execute()?;
244    ///
245    /// println!("This is the comment:\n{}", created_comment);
246    /// # Ok::<(), Error>(())
247    /// ```
248    pub fn get<T, U> ( &self, file_id: T, comment_id: U ) -> GetRequest
249        where
250            T: AsRef<str>,
251            U: AsRef<str>
252    {
253        GetRequest::new(&self.credentials, file_id, comment_id)
254    }
255
256    /// Lists a file's comments.
257    ///
258    /// See Google's
259    /// [documentation](https://developers.google.com/drive/api/reference/rest/v3/comments/list)
260    /// for more information.
261    ///
262    /// # Note:
263    ///
264    /// This request requires you to set the [`fields`](ListRequest::fields)
265    /// parameter.
266    ///
267    /// # Requires one of the following OAuth scopes:
268    ///
269    /// - `https://www.googleapis.com/auth/drive`
270    /// - `https://www.googleapis.com/auth/drive.file`
271    /// - `https://www.googleapis.com/auth/drive.readonly`
272    ///
273    /// # Examples:
274    ///
275    /// ```no_run
276    /// # use drive_v3::{Error, Credentials, Drive};
277    /// #
278    /// # let drive = Drive::new( &Credentials::from_file(
279    /// #     "../.secure-files/google_drive_credentials.json",
280    /// #     &["https://www.googleapis.com/auth/drive.file"],
281    /// # )? );
282    /// #
283    /// let file_id = "some-file-id";
284    ///
285    /// let comment_list = drive.comments.list(&file_id)
286    ///     .fields("*") // You must set the fields
287    ///     .page_size(10)
288    ///     .execute()?;
289    ///
290    /// if let Some(comments) = comment_list.comments {
291    ///     for comment in comments {
292    ///         println!("{}", comment);
293    ///     }
294    /// }
295    /// # Ok::<(), Error>(())
296    /// ```
297    pub fn list<T: AsRef<str>> ( &self, file_id: T ) -> ListRequest {
298        ListRequest::new(&self.credentials, file_id)
299    }
300
301    /// Updates a comment with patch semantics.
302    ///
303    /// See Google's
304    /// [documentation](https://developers.google.com/drive/api/reference/rest/v3/comments/update)
305    /// for more information.
306    ///
307    /// # Requires one of the following OAuth scopes:
308    ///
309    /// - `https://www.googleapis.com/auth/drive`
310    /// - `https://www.googleapis.com/auth/drive.file`
311    ///
312    /// # Examples:
313    ///
314    /// ```no_run
315    /// use drive_v3::objects::Comment;
316    /// # use drive_v3::{Error, Credentials, Drive};
317    /// #
318    /// # let drive = Drive::new( &Credentials::from_file(
319    /// #     "../.secure-files/google_drive_credentials.json",
320    /// #     &["https://www.googleapis.com/auth/drive.file"],
321    /// # )? );
322    ///
323    /// let updated_comment = Comment {
324    ///     content: Some( "this is the updated content of my comment".to_string() ),
325    ///     ..Default::default()
326    /// };
327    ///
328    /// let file_id = "some-file-id";
329    /// let comment_id = "some-comment-id";
330    ///
331    /// let modified_comment = drive.comments.update(&file_id, &comment_id)
332    ///     .fields("*")
333    ///     .comment(&updated_comment)
334    ///     .execute()?;
335    ///
336    /// assert_eq!(modified_comment.content, updated_comment.content);
337    /// # Ok::<(), Error>(())
338    /// ```
339    pub fn update<T, U> ( &self, file_id: T, comment_id: U ) -> UpdateRequest
340        where
341            T: AsRef<str>,
342            U: AsRef<str>
343    {
344        UpdateRequest::new(&self.credentials, file_id, comment_id)
345    }
346}
347
348#[cfg(test)]
349mod tests {
350    use super::Comments;
351    use crate::{ErrorKind, objects, resources};
352    use crate::utils::test::{INVALID_CREDENTIALS, VALID_CREDENTIALS};
353
354    fn get_resource() -> Comments {
355        Comments::new(&VALID_CREDENTIALS)
356    }
357
358    fn get_invalid_resource() -> Comments {
359        Comments::new(&INVALID_CREDENTIALS)
360    }
361
362    fn get_files_resource() -> resources::Files {
363        resources::Files::new(&VALID_CREDENTIALS)
364    }
365
366    fn delete_file( file: &objects::File ) -> crate::Result<()> {
367        get_files_resource().delete( file.clone().id.unwrap() ).execute()
368    }
369
370    fn get_test_file_metadata() -> objects::File {
371        objects::File {
372            name: Some( "test.txt".to_string() ),
373            description: Some( "a test file".to_string() ),
374            mime_type: Some( "text/plain".to_string() ),
375            ..Default::default()
376        }
377    }
378
379    fn get_test_drive_file() -> crate::Result<objects::File> {
380        let metadata = get_test_file_metadata();
381
382        get_files_resource().create()
383            .fields("*")
384            .upload_type(objects::UploadType::Multipart)
385            .metadata(&metadata)
386            .content_string("content")
387            .execute()
388    }
389
390    fn get_test_comment() -> objects::Comment {
391        objects::Comment {
392            content: Some( "test comment".to_string() ),
393            ..Default::default()
394        }
395    }
396
397    fn get_test_drive_comment( file: &objects::File ) -> crate::Result<objects::Comment> {
398        let test_comment = get_test_comment();
399
400        get_resource().create( &file.clone().id.unwrap() )
401            .fields("*")
402            .comment(&test_comment)
403            .execute()
404    }
405
406    #[test]
407    fn new_test() {
408        let valid_resource = get_resource();
409        let invalid_resource = get_invalid_resource();
410
411        assert_eq!( valid_resource.credentials, VALID_CREDENTIALS.clone() );
412        assert_eq!( invalid_resource.credentials, INVALID_CREDENTIALS.clone() );
413    }
414
415    #[test]
416    fn create_test() {
417        let test_drive_file = get_test_drive_file().unwrap();
418        let test_comment = get_test_comment();
419
420        let response = get_resource().create( &test_drive_file.clone().id.unwrap() )
421            .fields("*")
422            .comment(&test_comment)
423            .execute();
424
425        assert!( response.is_ok() );
426
427        let comment = response.unwrap();
428        assert_eq!(comment.content, test_comment.content);
429
430        delete_file(&test_drive_file).expect("Failed to cleanup created file");
431    }
432
433    #[test]
434    fn create_invalid_test() {
435        let response = get_invalid_resource().create("invalid-id")
436            .execute();
437
438        assert!( response.is_err() );
439        assert_eq!( response.unwrap_err().kind, ErrorKind::Response );
440    }
441
442    #[test]
443    fn delete_test() {
444        let test_drive_file = get_test_drive_file().unwrap();
445        let test_drive_comment = get_test_drive_comment(&test_drive_file).unwrap();
446
447        let response = get_resource().delete(
448                &test_drive_file.clone().id.unwrap(),
449                &test_drive_comment.clone().id.unwrap(),
450            )
451            .execute();
452
453        assert!( response.is_ok() );
454
455        delete_file(&test_drive_file).expect("Failed to cleanup created file");
456    }
457
458    #[test]
459    fn delete_invalid_test() {
460        let response = get_invalid_resource().delete("invalid-id", "invalid-id")
461            .execute();
462
463        assert!( response.is_err() );
464        assert_eq!( response.unwrap_err().kind, ErrorKind::Response );
465    }
466
467    #[test]
468    fn get_test() {
469        let test_drive_file = get_test_drive_file().unwrap();
470        let test_drive_comment = get_test_drive_comment(&test_drive_file).unwrap();
471
472        let response = get_resource().get(
473                &test_drive_file.clone().id.unwrap(),
474                &test_drive_comment.clone().id.unwrap(),
475            )
476            .fields("*")
477            .execute();
478
479        assert!( response.is_ok() );
480
481        let comment = response.unwrap();
482        assert_eq!(comment, test_drive_comment);
483
484        delete_file(&test_drive_file).expect("Failed to cleanup created file");
485    }
486
487    #[test]
488    fn get_invalid_test() {
489        let response = get_invalid_resource().get("invalid-id", "invalid-id")
490            .execute();
491
492        assert!( response.is_err() );
493        assert_eq!( response.unwrap_err().kind, ErrorKind::Response );
494    }
495
496    #[test]
497    fn list_test() {
498        let test_drive_file = get_test_drive_file().unwrap();
499        let test_drive_comment = get_test_drive_comment(&test_drive_file).unwrap();
500
501        let response = get_resource().list( &test_drive_file.clone().id.unwrap() )
502            .fields("*")
503            .execute();
504
505        assert!( response.is_ok() );
506
507        let comment_list = response.unwrap();
508        assert_eq!( comment_list.comments, Some(vec![test_drive_comment]) );
509
510        delete_file(&test_drive_file).expect("Failed to cleanup created file");
511    }
512
513    #[test]
514    fn list_invalid_test() {
515        let response = get_invalid_resource().list("invalid-id")
516            .execute();
517
518        assert!( response.is_err() );
519        assert_eq!( response.unwrap_err().kind, ErrorKind::Response );
520    }
521
522    #[test]
523    fn update_test() {
524        let test_drive_file = get_test_drive_file().unwrap();
525        let test_drive_comment = get_test_drive_comment(&test_drive_file).unwrap();
526
527        let mut updated_comment = test_drive_comment.clone();
528        updated_comment.content = Some( "updated comment".to_string() );
529
530        let response = get_resource().update(
531                &test_drive_file.clone().id.unwrap(),
532                &test_drive_comment.clone().id.unwrap(),
533            )
534            .fields("*")
535            .comment(&updated_comment)
536            .execute();
537
538        assert!( response.is_ok() );
539
540        let comment = response.unwrap();
541        assert_eq!(comment.content, updated_comment.content);
542
543        delete_file(&test_drive_file).expect("Failed to cleanup created file");
544    }
545
546    #[test]
547    fn update_invalid_test() {
548        let response = get_invalid_resource().update("invalid-id", "invalid-id")
549            .execute();
550
551        assert!( response.is_err() );
552        assert_eq!( response.unwrap_err().kind, ErrorKind::Response );
553    }
554}