drive_v3/resources/
files.rs

1use std::fs;
2use std::io::Read;
3use std::path::PathBuf;
4use std::collections::HashMap;
5use reqwest::{Url, Method, header};
6use reqwest::blocking::{Client, multipart, RequestBuilder};
7use drive_v3_macros::{DriveRequestBuilder, request};
8
9use super::DriveRequestBuilder;
10use crate::utils::upload::FileUploader;
11use crate::{Credentials, Error, ErrorKind, objects};
12
13#[request(
14    method=Method::POST,
15    url="https://www.googleapis.com/drive/v3/files/{file_id}/copy",
16    returns=objects::File,
17)]
18#[derive(DriveRequestBuilder)]
19/// A request builder to create a copy of a file and apply any requested
20/// updates with patch semantics.
21pub struct CopyRequest {
22    /// Whether to ignore the domain's default visibility settings for the
23    /// created file.
24    ///
25    /// Domain administrators can choose to make all uploaded files visible
26    /// to the domain by default; this parameter bypasses that behavior for
27    /// the request. Permissions are still inherited from parent folders.
28    #[drive_v3(parameter)]
29    ignore_default_visibility: Option<bool>,
30
31    /// Whether to set the `keepForever` field in the new head revision.
32    ///
33    /// This is only applicable to files with binary content in a Drive.
34    ///
35    /// Only 200 revisions for the file can be kept forever, if the limit is
36    /// reached, try deleting pinned revisions.
37    #[drive_v3(parameter)]
38    keep_revision_forever: Option<bool>,
39
40    /// A language hint for OCR processing during image import
41    /// (ISO 639-1 code).
42    #[drive_v3(parameter)]
43    ocr_language: Option<String>,
44
45    /// Whether the requesting application supports both My Drives and
46    /// shared drives.
47    #[drive_v3(parameter)]
48    supports_all_drives: Option<bool>,
49
50    /// Specifies which additional view's permissions to include in the
51    /// response.
52    ///
53    /// Only `published` is supported.
54    #[drive_v3(parameter)]
55    include_permissions_for_view: Option<String>,
56
57    /// A comma-separated list of IDs of labels to include in the
58    /// [`label_info`](objects::File::label_info) part of the response.
59    #[drive_v3(parameter)]
60    include_labels: Option<String>,
61
62    /// Sets the metadata that the copied file will have.
63    #[drive_v3(body)]
64    metadata: Option<objects::File>,
65}
66
67#[request(
68    method=Method::POST,
69    url="https://www.googleapis.com/upload/drive/v3/files",
70)]
71#[derive(DriveRequestBuilder)]
72/// A request builder to create a new file in a Drive.
73pub struct CreateRequest {
74    /// The type of upload request to the /upload URI.
75    #[drive_v3(parameter)]
76    upload_type: Option<objects::UploadType>,
77
78    /// Whether to ignore the domain's default visibility settings for the
79    /// created file.
80    ///
81    /// Domain administrators can choose to make all uploaded files visible
82    /// to the domain by default; this parameter bypasses that behavior for
83    /// the request. Permissions are still inherited from parent folders.
84    #[drive_v3(parameter)]
85    ignore_default_visibility: Option<bool>,
86
87    /// Whether to set the `keepForever` field in the new head revision.
88    ///
89    /// This is only applicable to files with binary content in a Drive.
90    ///
91    /// Only 200 revisions for the file can be kept forever, if the limit is
92    /// reached, try deleting pinned revisions.
93    #[drive_v3(parameter)]
94    keep_revision_forever: Option<bool>,
95
96    /// A language hint for OCR processing during image import
97    /// (ISO 639-1 code).
98    #[drive_v3(parameter)]
99    ocr_language: Option<String>,
100
101    /// Whether the requesting application supports both My Drives and
102    /// shared drives.
103    #[drive_v3(parameter)]
104    supports_all_drives: Option<bool>,
105
106    /// Whether to use the uploaded content as indexable text.
107    #[drive_v3(parameter)]
108    use_content_as_indexable_text: Option<bool>,
109
110    /// Specifies which additional view's permissions to include in the
111    /// response.
112    ///
113    /// Only `published` is supported.
114    #[drive_v3(parameter)]
115    include_permissions_for_view: Option<String>,
116
117    /// A comma-separated list of IDs of labels to include in the
118    /// [`label_info`](objects::File::label_info) part of the response.
119    #[drive_v3(parameter)]
120    include_labels: Option<String>,
121
122    /// Sets the metadata that the created file will have in Google Drive.
123    #[drive_v3(body)]
124    metadata: Option<objects::File>,
125
126    /// The path of the source file to be uploaded.
127    content_source: Option<PathBuf>,
128
129    /// Use this string as the content of the created file.
130    content_string: Option<String>,
131
132    /// A callback to receive updates on a resumable upload.
133    #[drive_v3(callback)]
134    callback: Option<fn(usize, usize)>,
135}
136
137impl CreateRequest {
138    /// Gets a media request.
139    fn get_media_request( &self ) -> crate::Result<RequestBuilder> {
140        let mut content_bytes = Vec::new();
141
142        if self.content_source.is_some() && self.content_string.is_some() {
143            return Err( Error::new(
144                ErrorKind::Request,
145                "a create request can only use one of 'content_source' or 'content_string'"
146            ) )
147        }
148
149        if let Some(source) = &self.content_source {
150            let mut file = fs::File::open(source)?;
151            file.read_to_end(&mut content_bytes)?;
152        }
153
154        if let Some(string) = &self.content_string {
155            content_bytes = string.as_bytes().to_vec();
156        }
157
158        let mut request = self.build()?    
159            .header( "Content-Length", content_bytes.len().to_string() )
160            .body(content_bytes);
161
162        let metadata = self.metadata.clone().unwrap_or_default();
163        if let Some(mime_type) = metadata.mime_type {
164            request = request.header("Content-Type", mime_type);
165        }
166
167        Ok(request)
168    }
169
170    fn get_metadata_form_part( &self ) -> crate::Result<multipart::Part> {
171        let metadata_string = serde_json::to_string(&self.metadata)?;
172
173        let mut metadata_headers = header::HeaderMap::new();
174
175        metadata_headers.insert(
176            header::CONTENT_TYPE, "application/json; charset=UTF-8".parse()? 
177        );
178
179        metadata_headers.insert(
180            header::CONTENT_DISPOSITION, "form-data; name=\"metadata\"".parse()?
181        );
182
183        Ok( multipart::Part::text(metadata_string)
184            .headers(metadata_headers) )
185    }
186
187    fn get_file_form_part( &self ) -> crate::Result<multipart::Part> {
188        let metadata = self.metadata.clone().unwrap_or_default();
189        let content_mime_type = metadata.mime_type.unwrap_or( "*/*".into() );
190
191        let mut file_headers = reqwest::header::HeaderMap::new();
192
193        file_headers.insert(
194            header::CONTENT_TYPE, content_mime_type.parse()?
195        );
196
197        file_headers.insert(
198            header::CONTENT_DISPOSITION, "form-data; name=\"file\"".parse()?
199        );
200
201        let mut file_part = multipart::Part::text("");
202
203        if let Some(source) = &self.content_source {
204            file_part = multipart::Part::file(source)?;
205        }
206
207        if let Some(string) = &self.content_string {
208            file_part = multipart::Part::text(string.clone());
209        }
210
211        Ok( file_part.headers(file_headers) )
212    }
213
214    /// Gets a multipart request.
215    fn get_multipart_request( &self ) -> crate::Result<RequestBuilder> {
216        let metadata_part = self.get_metadata_form_part()?;
217        let file_part = self.get_file_form_part()?;
218
219        let form = multipart::Form::new()
220            .part("metadata", metadata_part)
221            .part("file", file_part);
222
223        Ok( self.build()?
224            .multipart(form) )
225    }
226
227    /// Performs a resumable upload.
228    fn perform_resumable_upload( &self ) -> crate::Result<objects::File> {
229        let metadata = self.metadata.clone().unwrap_or_default();
230        let metadata_string = serde_json::to_string(&metadata)?;
231        let metadata_size = metadata_string.as_bytes().len();
232        let content_mime_type = metadata.mime_type.unwrap_or( "*/*".into() );
233
234        if self.content_string.is_some() {
235            return Err( Error::new(
236                ErrorKind::Request,
237                "A resumable upload cannot be created from a string, it must be a file",
238            ) )
239        }
240
241        let mut file = match &self.content_source {
242            Some(source) => fs::File::open(source)?,
243            None => {
244                return Err( Error::new(
245                    ErrorKind::Request,
246                    "A resumable request must include a source file"
247                ) )
248            }
249        };
250
251        let file_size = file.metadata()?.len();
252
253        let request = self.build()?
254            .header( "X-Upload-Content-Type", &content_mime_type )
255            .header( "X-Upload-Content-Length", &file_size.to_string() )
256            .header( "Content-Type", "application/json; charset=UTF-8" )
257            .header( "Content-Length", &metadata_size.to_string() )
258            .body(metadata_string);
259
260        let response = request.send()?;
261
262        if !response.status().is_success() {
263            return Err( response.into() );
264        }
265
266        let upload_uri = match response.headers().get("location") {
267            Some(header) => header.to_str()?,
268            #[cfg(not(tarpaulin_include))]
269            None => {
270                return Err( Error::new(
271                    ErrorKind::Request,
272                    "unable to get the resumable upload location",
273                ) )
274            }
275        };
276
277        let mut file_uploader = FileUploader::from_uri(upload_uri);
278
279        if let Some(callback) = self.callback {
280            file_uploader = file_uploader.with_callback(callback);
281        }
282
283        file_uploader.upload_file(&mut file)
284    }
285
286    /// Executes this request.
287    ///
288    /// # Errors
289    ///
290    /// - an [`IO`](crate::ErrorKind::IO) error, if the source file does not exist.
291    /// - a [`UrlParsing`](crate::ErrorKind::UrlParsing) error, if the creation of the request URL failed.
292    /// - a [`Json`](crate::ErrorKind::Json) error, if unable to parse the destination file to JSON.
293    /// - a [`Request`](crate::ErrorKind::Request) error, if unable to send the request or get a body from the response.
294    /// - a [`Response`](crate::ErrorKind::Response) error, if the request returned an error response.
295    pub fn execute( &self ) -> crate::Result<objects::File> {
296        let upload_type = self.upload_type.unwrap_or_default();
297
298        let request = match upload_type {
299            objects::UploadType::Media => self.get_media_request()?,
300            objects::UploadType::Multipart => self.get_multipart_request()?,
301            objects::UploadType::Resumable => {
302                return self.perform_resumable_upload()
303            },
304        };
305
306        let response = request.send()?;
307
308        if !response.status().is_success() {
309            return Err( response.into() );
310        }
311
312        Ok( serde_json::from_str( &response.text()? )? )
313    }
314}
315
316#[request(
317    method=Method::DELETE,
318    url="https://www.googleapis.com/drive/v3/files/{file_id}",
319    returns=(),
320)]
321#[derive(DriveRequestBuilder)]
322/// A request builder to permanently delete a file without moving it into
323/// the trash.
324pub struct DeleteRequest {
325    /// Whether the requesting application supports both My Drives and
326    /// shared drives.
327    #[drive_v3(parameter)]
328    supports_all_drives: Option<bool>,
329}
330
331#[request(
332    method=Method::DELETE,
333    url="https://www.googleapis.com/drive/v3/files/trash",
334    returns=(),
335)]
336#[derive(DriveRequestBuilder)]
337/// A request builder to permanently delete all of the user's trashed files.
338pub struct EmptyTrashRequest {
339    /// If set, empties the trash of the provided shared drive.
340    drive_id: Option<String>,
341}
342
343#[request(
344    method=Method::GET,
345    url="https://www.googleapis.com/drive/v3/files/{file_id}/export",
346    returns=Vec::<u8>,
347    returns_bytes=true,
348)]
349#[derive(DriveRequestBuilder)]
350/// A request builder to export a Google Workspace document.
351pub struct ExportRequest {
352    /// The MIME type of the format requested for this export.
353    #[drive_v3(parameter)]
354    mime_type: Option<String>,
355}
356
357#[request(
358    method=Method::GET,
359    url="https://www.googleapis.com/drive/v3/files/generateIds",
360    returns=objects::GeneratedIDs,
361)]
362#[derive(DriveRequestBuilder)]
363/// A request builder to generate IDs.
364pub struct GenerateIDsRequest {
365    /// The number of IDs to return.
366    #[drive_v3(parameter)]
367    count: Option<i64>,
368
369    /// The space in which the IDs can be used to create new files.
370    #[drive_v3(parameter)]
371    space: Option<objects::Space>,
372
373    /// The type of items which the IDs can be used for.
374    #[drive_v3(parameter)]
375    kind: Option<objects::IDKind>,
376}
377
378#[request(
379    method=Method::GET,
380    url="https://www.googleapis.com/drive/v3/files/{file_id}",
381    returns=objects::File,
382)]
383#[derive(DriveRequestBuilder)]
384/// A request builder to get a file’s metadata by ID.
385pub struct GetRequest {
386    /// Whether the requesting application supports both My Drives and
387    /// shared drives.
388    #[drive_v3(parameter)]
389    supports_all_drives: Option<bool>,
390
391    /// Specifies which additional view's permissions to include in the
392    /// response.
393    ///
394    /// Only `published` is supported.
395    #[drive_v3(parameter)]
396    include_permissions_for_view: Option<String>,
397
398    /// A comma-separated list of IDs of labels to include in the
399    /// [`label_info`](objects::File::label_info) part of the response.
400    #[drive_v3(parameter)]
401    include_labels: Option<String>,
402}
403
404#[request(
405    method=Method::GET,
406    url="https://www.googleapis.com/drive/v3/files/{file_id}",
407)]
408#[derive(DriveRequestBuilder)]
409/// A request builder to get a file’s content by ID.
410pub struct GetMediaRequest {
411    /// Whether the user is acknowledging the risk of downloading known
412    /// malware or other abusive files.
413    #[drive_v3(parameter)]
414    acknowledge_abuse: Option<bool>,
415
416    /// Whether the requesting application supports both My Drives and
417    /// shared drives.
418    #[drive_v3(parameter)]
419    supports_all_drives: Option<bool>,
420
421    /// Specifies which additional view's permissions to include in the
422    /// response.
423    ///
424    /// Only `published` is supported.
425    #[drive_v3(parameter)]
426    include_permissions_for_view: Option<String>,
427
428    /// A comma-separated list of IDs of labels to include in the
429    /// [`label_info`](objects::File::label_info) part of the response.
430    #[drive_v3(parameter)]
431    include_labels: Option<String>,
432
433    /// Path to save the contents to.
434    save_to: Option<PathBuf>,
435}
436
437impl GetMediaRequest {
438    /// Executes this request.
439    ///
440    /// # Errors
441    ///
442    /// - a [`UrlParsing`](ErrorKind::UrlParsing) error, if the creation of the request URL failed.
443    /// - a [`Json`](ErrorKind::Json) error, if unable to parse the destination file to JSON.
444    /// - a [`Request`](ErrorKind::Request) error, if unable to send the request or get a body from the response.
445    /// - a [`Response`](ErrorKind::Response) error, if the request returned an error response.
446    pub fn execute( &self ) -> crate::Result< Vec<u8> > {
447        let mut parameters = self.get_parameters();
448        parameters.push(( "alt".into(), objects::Alt::Media.to_string() ));
449
450        let url = Url::parse_with_params(&self.url, parameters)?;
451        let request = Client::new()
452            .request( self.method.clone(), url )
453            .bearer_auth( self.credentials.get_access_token() );
454
455        let response = request.send()?;
456
457        if !response.status().is_success() {
458            return Err( response.into() );
459        }
460
461        let file_bytes: Vec<u8> = response.bytes()?.into();
462
463        if let Some(path) = &self.save_to {
464            use std::io::Write;
465
466            let mut file = fs::File::create(path)?;
467            file.write_all(&file_bytes)?;
468        }
469
470        Ok(file_bytes)
471    }
472}
473
474#[request(
475    method=Method::GET,
476    url="https://www.googleapis.com/drive/v3/files",
477    returns=objects::FileList,
478)]
479#[derive(DriveRequestBuilder)]
480/// A request builder to list the user's files.
481pub struct ListRequest {
482    /// Bodies of items (files/documents) to which the query applies.
483    ///
484    /// Supported bodies are `user`, `domain`, `drive`, and `allDrives`.
485    ///
486    /// Prefer `user` or `drive` to `allDrives` for efficiency. By default,
487    /// corpora is set to `user`. However, this can change depending on the
488    /// filter set through the [`q`](ListRequest::q) parameter.
489    #[drive_v3(parameter)]
490    corpora: Option<String>,
491
492    /// ID of the shared drive to search.
493    #[drive_v3(parameter)]
494    drive_id: Option<String>,
495
496    /// Whether both My Drive and shared drive items should be included in
497    /// results.
498    #[drive_v3(parameter)]
499    include_items_from_all_drives: Option<bool>,
500
501    /// A comma-separated list of sort keys.
502    ///
503    /// Valid keys are `createdTime`, `folder`, `modifiedByMeTime`,
504    /// `modifiedTime`, `name`, `name_natural`, `quotaBytesUsed`,
505    /// `recency`, `sharedWithMeTime`, `starred`, and `viewedByMeTime`.
506    ///
507    /// Each key sorts ascending by default, but can be reversed by adding
508    /// the `desc` to the end of the key.
509    #[drive_v3(parameter)]
510    order_by: Option<String>,
511
512    /// The maximum number of files to return per page.
513    ///
514    /// Partial or empty result pages are possible even before the end of
515    /// the files list has been reached.
516    #[drive_v3(parameter)]
517    page_size: Option<i64>,
518
519    /// The token for continuing a previous list request on the next page.
520    ///
521    /// This should be set to the value of
522    /// [`nest_page_token`](objects::FileList::next_page_token) from the
523    /// previous response.
524    #[drive_v3(parameter)]
525    page_token: Option<String>,
526
527    /// A query for filtering the file results.
528    ///
529    /// For more information, see Google's
530    /// [Search for files & folders](https://developers.google.com/drive/api/guides/search-files)
531    /// guide.
532    #[drive_v3(parameter)]
533    q: Option<String>,
534
535    /// A comma-separated list of spaces to query within the corpora.
536    ///
537    /// Supported values are `drive` and `appDataFolder`.
538    #[drive_v3(parameter)]
539    spaces: Option<String>,
540
541    /// Whether the requesting application supports both My Drives and
542    /// shared drives.
543    #[drive_v3(parameter)]
544    supports_all_drives: Option<bool>,
545
546    /// Specifies which additional view's permissions to include in the
547    /// response.
548    ///
549    /// Only `published` is supported.
550    #[drive_v3(parameter)]
551    include_permissions_for_view: Option<String>,
552
553    /// A comma-separated list of IDs of labels to include in the
554    /// [`label_info`](objects::File::label_info) part of the response.
555    #[drive_v3(parameter)]
556    include_labels: Option<String>,
557}
558
559#[request(
560    method=Method::GET,
561    url="https://www.googleapis.com/drive/v3/files/{file_id}/listLabels",
562    returns=objects::LabelList,
563)]
564#[derive(DriveRequestBuilder)]
565/// A request builder to list the labels in a file.
566pub struct ListLabelsRequest {
567    /// The maximum number of labels to return per page.
568    ///
569    /// When not set, defaults to 100.
570    #[drive_v3(parameter)]
571    max_results: Option<i64>,
572
573    /// The token for continuing a previous list request on the next page.
574    ///
575    /// This should be set to the value of
576    /// [`next_page_token`](objects::LabelList::next_page_token) from the
577    /// previous response.
578    #[drive_v3(parameter)]
579    page_token: Option<String>,
580}
581
582#[request(
583    method=Method::POST,
584    url="https://www.googleapis.com/drive/v3/files/{file_id}/modifyLabels",
585)]
586#[derive(DriveRequestBuilder)]
587/// A request builder to modify the labels in a file.
588pub struct ModifyLabelsRequest {
589    /// Sets the metadata that the updated file will have in Google Drive.
590    #[drive_v3(body)]
591    modifications: Option< Vec<objects::LabelModification> >,
592}
593
594#[cfg(not(tarpaulin_include))] // Requires a business account
595impl ModifyLabelsRequest {
596    /// Executes this request.
597    ///
598    /// # Errors
599    ///
600    /// - a [`UrlParsing`](ErrorKind::UrlParsing) error, if the creation of the
601    /// request URL failed.
602    /// - a [`Json`](ErrorKind::Json) error, if unable to parse the destination
603    /// file to JSON.
604    /// - a [`Request`](ErrorKind::Request) error, if unable to send the request
605    /// or get a body from the response.
606    /// - a [`Response`](ErrorKind::Response) error, if the request returned an
607    /// error response.
608    pub fn execute( &self ) -> crate::Result< Vec<objects::Label> > {
609        let mut modify_request = objects::ModifyLabelsRequest::new();
610
611        if let Some(modifications) = &self.modifications {
612            modify_request.label_modifications = Some( modifications.to_vec() );
613        }
614
615        let request = self.build()?
616            .body( serde_json::to_string(&modify_request)? );
617
618        let response = request.send()?;
619
620        if !response.status().is_success() {
621            return Err( response.into() )
622        }
623
624        let response_text = response.text()?;
625        let parsed_json = serde_json::from_str::<HashMap<&str, serde_json::Value>> (&response_text)?;
626
627        match parsed_json.get("modifiedLabels") {
628            Some(labels) => Ok( serde_json::from_value(labels.clone())? ),
629            None => Err( Error::new(
630                ErrorKind::Json,
631                "the response did not contain the modified labels",
632            ) )
633        }
634    }
635}
636
637#[request(
638    method=Method::PATCH,
639    url="https://www.googleapis.com/upload/drive/v3/files/{file_id}",
640)]
641#[derive(DriveRequestBuilder)]
642/// A request builder to list the labels in a file.
643pub struct UpdateRequest {
644    /// The type of upload request to the /upload URI.
645    #[drive_v3(parameter)]
646    upload_type: Option<objects::UploadType>,
647
648    /// A comma-separated list of parent IDs to add.
649    #[drive_v3(parameter)]
650    add_parents: Option<String>,
651
652    /// Whether to set the `keepForever` field in the new head revision.
653    ///
654    /// This is only applicable to files with binary content in a Drive.
655    ///
656    /// Only 200 revisions for the file can be kept forever, if the limit is
657    /// reached, try deleting pinned revisions.
658    #[drive_v3(parameter)]
659    keep_revision_forever: Option<bool>,
660
661    /// A language hint for OCR processing during image import
662    /// (ISO 639-1 code).
663    #[drive_v3(parameter)]
664    ocr_language: Option<String>,
665
666    /// Whether the requesting application supports both My Drives and
667    /// shared drives.
668    #[drive_v3(parameter)]
669    supports_all_drives: Option<bool>,
670
671    /// Whether to use the uploaded content as indexable text.
672    #[drive_v3(parameter)]
673    use_content_as_indexable_text: Option<bool>,
674
675    /// Specifies which additional view's permissions to include in the
676    /// response.
677    ///
678    /// Only 'published' is supported.
679    #[drive_v3(parameter)]
680    include_permissions_for_view: Option<String>,
681
682    /// A comma-separated list of IDs of labels to include in the
683    /// [`label_info`](objects::File::label_info) part of the response.
684    #[drive_v3(parameter)]
685    include_labels: Option<String>,
686
687    /// Sets the metadata that the updated file will have in Google Drive.
688    #[drive_v3(body)]
689    metadata: Option<objects::File>,
690
691    /// The path of the source file to be uploaded.
692    content_source: Option<PathBuf>,
693
694    /// Use this string as the content of the created file.
695    content_string: Option<String>,
696
697    /// A callback to receive updates on a resumable upload.
698    #[drive_v3(callback)]
699    callback: Option<fn(usize, usize)>,
700}
701
702impl UpdateRequest {
703    /// Gets a media request.
704    fn get_media_request( &self ) -> crate::Result<RequestBuilder> {
705        let mut content_bytes = Vec::new();
706
707        if self.content_source.is_some() && self.content_string.is_some() {
708            return Err( Error::new(
709                ErrorKind::Request,
710                "an update request can only use one of 'content_source' or 'content_string'"
711            ) )
712        }
713
714        if let Some(source) = &self.content_source {
715            let mut file = fs::File::open(source)?;
716            file.read_to_end(&mut content_bytes)?;
717        }
718
719        if let Some(string) = &self.content_string {
720            content_bytes = string.as_bytes().to_vec();
721        }
722
723        let mut request = self.build()?
724            .header( "Content-Length", content_bytes.len().to_string() )
725            .body(content_bytes);
726
727        let metadata = self.metadata.clone().unwrap_or_default();
728        if let Some(mime_type) = metadata.mime_type {
729            request = request.header("Content-Type", mime_type);
730        }
731
732        Ok(request)
733    }
734
735    fn get_metadata_form_part( &self ) -> crate::Result<multipart::Part> {
736        let metadata_string = serde_json::to_string(&self.metadata)?;
737
738        let mut metadata_headers = header::HeaderMap::new();
739
740        metadata_headers.insert(
741            header::CONTENT_TYPE, "application/json; charset=UTF-8".parse()? 
742        );
743
744        metadata_headers.insert(
745            header::CONTENT_DISPOSITION, "form-data; name=\"metadata\"".parse()?
746        );
747
748        Ok( multipart::Part::text(metadata_string)
749            .headers(metadata_headers) )
750    }
751
752    fn get_file_form_part( &self ) -> crate::Result<multipart::Part> {
753        let metadata = self.metadata.clone().unwrap_or_default();
754        let content_mime_type = metadata.mime_type.unwrap_or( "*/*".into() );
755
756        let mut file_headers = reqwest::header::HeaderMap::new();
757
758        file_headers.insert(
759            header::CONTENT_TYPE, content_mime_type.parse()?
760        );
761
762        file_headers.insert(
763            header::CONTENT_DISPOSITION, "form-data; name=\"file\"".parse()?
764        );
765
766        let mut file_part = multipart::Part::text("");
767
768        if let Some(source) = &self.content_source {
769            file_part = multipart::Part::file(source)?;
770        }
771
772        if let Some(string) = &self.content_string {
773            file_part = multipart::Part::text(string.clone());
774        }
775
776        Ok( file_part.headers(file_headers) )
777    }
778
779    /// Gets a multipart request.
780    fn get_multipart_request( &self ) -> crate::Result<RequestBuilder> {
781        let metadata_part = self.get_metadata_form_part()?;
782        let file_part = self.get_file_form_part()?;
783
784        let form = multipart::Form::new()
785            .part("metadata", metadata_part)
786            .part("file", file_part);
787
788        Ok( self.build()?
789            .multipart(form) )
790    }
791
792    /// Performs a resumable upload.
793    fn perform_resumable_upload( &self ) -> crate::Result<objects::File> {
794        let metadata = self.metadata.clone().unwrap_or_default();
795        let metadata_string = serde_json::to_string(&metadata)?;
796        let metadata_size = metadata_string.as_bytes().len();
797        let content_mime_type = metadata.mime_type.unwrap_or( "*/*".into() );
798
799        if self.content_string.is_some() {
800            return Err( Error::new(
801                ErrorKind::Request,
802                "A resumable upload cannot be created from a string, it must be a file",
803            ) )
804        }
805
806        let mut file = match &self.content_source {
807            Some(source) => fs::File::open(source)?,
808            None => {
809                return Err( Error::new(
810                    ErrorKind::Request,
811                    "A resumable request must include a source file",
812                ) )
813            }
814        };
815
816        let file_size = file.metadata()?.len();
817
818        let request = self.build()?
819            .header( "X-Upload-Content-Type", &content_mime_type )
820            .header( "X-Upload-Content-Length", &file_size.to_string() )
821            .header( "Content-Type", "application/json; charset=UTF-8" )
822            .header( "Content-Length", &metadata_size.to_string() )
823            .body(metadata_string);
824
825        let response = request.send()?;
826
827        if !response.status().is_success() {
828            return Err( response.into() );
829        }
830
831        let upload_uri = match response.headers().get("location") {
832            Some(header) => header.to_str()?,
833            #[cfg(not(tarpaulin_include))]
834            None => {
835                return Err( Error::new(
836                    ErrorKind::Request,
837                    "unable to get the resumable upload location",
838                ) )
839            }
840        };
841
842        let mut file_uploader = FileUploader::from_uri(upload_uri);
843
844        if let Some(callback) = self.callback {
845            file_uploader = file_uploader.with_callback(callback);
846        }
847
848        file_uploader.upload_file(&mut file)
849    }
850
851    /// Executes this request.
852    ///
853    /// # Errors
854    ///
855    /// - an [`IO`](crate::ErrorKind::IO) error, if the source file does not exist.
856    /// - a [`UrlParsing`](crate::ErrorKind::UrlParsing) error, if the creation of the request URL failed.
857    /// - a [`Json`](crate::ErrorKind::Json) error, if unable to parse the destination file to JSON.
858    /// - a [`Request`](crate::ErrorKind::Request) error, if unable to send the request or get a body from the response.
859    /// - a [`Response`](crate::ErrorKind::Response) error, if the request returned an error response.
860    pub fn execute( &self ) -> crate::Result<objects::File> {
861        let upload_type = self.upload_type.unwrap_or_default();
862
863        let request = match upload_type {
864            objects::UploadType::Media => self.get_media_request()?,
865            objects::UploadType::Multipart => self.get_multipart_request()?,
866            objects::UploadType::Resumable => {
867                return self.perform_resumable_upload()
868            },
869        };
870
871        let response = request.send()?;
872
873        if !response.status().is_success() {
874            return Err( response.into() );
875        }
876
877        Ok( serde_json::from_str( &response.text()? )? )
878    }
879}
880
881#[request(
882    method=Method::POST,
883    url="https://www.googleapis.com/drive/v3/files/{file_id}/watch",
884    returns=objects::Channel,
885)]
886#[derive(DriveRequestBuilder)]
887/// A request builder to modify the labels in a file.
888pub struct WatchRequest {
889    /// Whether the requesting application supports both My Drives and
890    /// shared drives.
891    #[drive_v3(parameter)]
892    supports_all_drives: Option<bool>,
893
894    /// Whether the user is acknowledging the risk of downloading known
895    /// malware or other abusive files.
896    #[drive_v3(parameter)]
897    acknowledge_abuse: Option<bool>,
898
899    /// Specifies which additional view's permissions to include in the
900    /// response.
901    ///
902    /// Only `published` is supported.
903    #[drive_v3(parameter)]
904    include_permissions_for_view: Option<String>,
905
906    /// A comma-separated list of IDs of labels to include in the
907    /// [`label_info`](objects::File::label_info) part of the response.
908    #[drive_v3(parameter)]
909    include_labels: Option<String>,
910
911    /// Sets the metadata that the channel will have.
912    #[drive_v3(body)]
913    channel: Option<objects::Channel>,
914}
915
916/// Information related to a user's files.
917///
918/// # Examples:
919///
920/// List the files in a drive
921///
922/// ```no_run
923/// # use drive_v3::Error;
924/// use drive_v3::{Credentials, Drive};
925///
926/// let credentials_path = "my_credentials.json";
927/// let scopes = ["https://www.googleapis.com/auth/drive.metadata.readonly"];
928///
929/// let credentials = Credentials::from_file(&credentials_path, &scopes)?;
930/// let drive = Drive::new(&credentials);
931///
932/// let file_list = drive.files.list()
933///     .fields("files(name, id, mimeType)") // Set what fields will be returned
934///     .q("name = 'file_im_looking_for' and not trashed") // search for specific files
935///     .execute()?;
936///
937/// if let Some(files) = file_list.files {
938///     for file in &files {
939///         println!("{}", file);
940///     }
941/// }
942/// # Ok::<(), Error>(())
943/// ```
944#[derive(Debug, Clone, PartialEq, Eq)]
945pub struct Files {
946    /// Credentials used to authenticate a user's access to this resource.
947    credentials: Credentials,
948}
949
950impl Files {
951    /// Creates a new [`Files`] resource with the given [`Credentials`].
952    pub fn new( credentials: &Credentials ) -> Self {
953        Self {
954            credentials: credentials.clone(),
955        }
956    }
957
958    /// Creates a copy of a file and applies any requested updates with patch
959    /// semantics.
960    ///
961    /// See Google's
962    /// [documentation](https://developers.google.com/drive/api/reference/rest/v3/files/copy)
963    /// for more information.
964    ///
965    /// # Requires one of the following OAuth scopes:
966    ///
967    /// - `https://www.googleapis.com/auth/drive`
968    /// - `https://www.googleapis.com/auth/drive.appdata`
969    /// - `https://www.googleapis.com/auth/drive.file`
970    /// - `https://www.googleapis.com/auth/drive.photos.readonly`
971    ///
972    /// # Examples:
973    ///
974    /// ```no_run
975    /// use drive_v3::objects::File;
976    /// # use drive_v3::{Error, Credentials, Drive};
977    /// #
978    /// # let drive = Drive::new( &Credentials::from_file(
979    /// #     "../.secure-files/google_drive_credentials.json",
980    /// #     &["https://www.googleapis.com/auth/drive.file"],
981    /// # )? );
982    ///
983    /// // Set the metadata that the copied file will have
984    /// let metadata = File {
985    ///     name: Some( "my-copy.txt".to_string() ),
986    ///     description: Some( "I copied this using drive_v3!".to_string() ),
987    ///     ..Default::default()
988    /// };
989    ///
990    /// // Set the ID of the file you want to copy,
991    /// // you can get this using files.list()
992    /// let source_file_id = "some-file-id";
993    ///
994    /// let copied_file = drive.files.copy(&source_file_id)
995    ///     .metadata(&metadata)
996    ///     .execute()?;
997    ///
998    /// assert_eq!(copied_file.name, metadata.name);
999    /// assert_eq!(copied_file.description, metadata.description);
1000    /// # Ok::<(), Error>(())
1001    /// ```
1002    pub fn copy<T: AsRef<str>> ( &self, file_id: T ) -> CopyRequest {
1003        CopyRequest::new(&self.credentials, &file_id)
1004    }
1005
1006    /// Creates a new file.
1007    ///
1008    /// See Google's
1009    /// [documentation](https://developers.google.com/drive/api/reference/rest/v3/files/create)
1010    /// for more information.
1011    ///
1012    /// # Note:
1013    ///
1014    /// You can use any of the [`UploadTypes`](objects::UploadType), but for
1015    /// most uploads I recommend using the
1016    /// [`Resumable`](objects::UploadType::Resumable) type, which will allow you
1017    /// to set a callback to monitor the upload progress.
1018    ///
1019    /// # Requires one of the following OAuth scopes:
1020    ///
1021    /// - `https://www.googleapis.com/auth/drive`
1022    /// - `https://www.googleapis.com/auth/drive.appdata`
1023    /// - `https://www.googleapis.com/auth/drive.file`
1024    ///
1025    /// # Examples:
1026    ///
1027    /// Perform a simple upload to create a small media file (5 MB or less)
1028    /// without supplying metadata:
1029    ///
1030    /// ```no_run
1031    /// use drive_v3::objects::{File, UploadType};
1032    /// # use drive_v3::{Error, Credentials, Drive};
1033    /// #
1034    /// # let drive = Drive::new( &Credentials::from_file(
1035    /// #     "../.secure-files/google_drive_credentials.json",
1036    /// #     &["https://www.googleapis.com/auth/drive.file"],
1037    /// # )? );
1038    ///
1039    /// // A simple upload does not support metadata, however you can use it in
1040    /// // this request to set the MIME type of your new file, any other fields
1041    /// // you set will be ignored.
1042    /// let metadata = File {
1043    ///     mime_type: Some( "text/plain".to_string() ),
1044    ///     ..Default::default()
1045    /// };
1046    ///
1047    /// let my_new_file = drive.files.create()
1048    ///     .upload_type(UploadType::Media)
1049    ///     .metadata(&metadata)
1050    ///     .content_string("This is the content of my new file!")
1051    ///     // .content_source("path/to/file.txt") // You can also load a file from the system
1052    ///     .execute()?;
1053    ///
1054    /// assert_eq!(my_new_file.mime_type, metadata.mime_type);
1055    /// # Ok::<(), Error>(())
1056    /// ```
1057    ///
1058    /// Perform a multipart upload to create a small media file (5 MB or less)
1059    /// along with metadata that describes the file, in a single request:
1060    ///
1061    /// ```no_run
1062    /// use drive_v3::objects::{File, UploadType};
1063    /// # use drive_v3::{Error, Credentials, Drive};
1064    /// #
1065    /// # let drive = Drive::new( &Credentials::from_file(
1066    /// #     "../.secure-files/google_drive_credentials.json",
1067    /// #     &["https://www.googleapis.com/auth/drive.file"],
1068    /// # )? );
1069    ///
1070    /// // Set what information the uploaded file wil have
1071    /// let metadata = File {
1072    ///     name: Some( "my-new-file.txt".to_string() ),
1073    ///     mime_type: Some( "text/plain".to_string() ),
1074    ///     ..Default::default()
1075    /// };
1076    ///
1077    /// let my_new_file = drive.files.create()
1078    ///     .upload_type(UploadType::Multipart)
1079    ///     .metadata(&metadata)
1080    ///     .content_source("path/to/file.txt")
1081    ///     // .content_string("This is the content of my new file!")  // You can use a string
1082    ///     .execute()?;
1083    ///
1084    /// assert_eq!(my_new_file.name, metadata.name);
1085    /// assert_eq!(my_new_file.mime_type, metadata.mime_type);
1086    /// # Ok::<(), Error>(())
1087    /// ```
1088    ///
1089    /// Perform a resumable upload to create a large file (greater than 5 MB):
1090    ///
1091    /// ```no_run
1092    /// use drive_v3::objects::{File, UploadType};
1093    /// # use drive_v3::{Error, Credentials, Drive};
1094    /// #
1095    /// # let drive = Drive::new( &Credentials::from_file(
1096    /// #     "../.secure-files/google_drive_credentials.json",
1097    /// #     &["https://www.googleapis.com/auth/drive.file"],
1098    /// # )? );
1099    ///
1100    /// // Set what information the uploaded file wil have
1101    /// let metadata = File {
1102    ///     name: Some( "my-new-file.txt".to_string() ),
1103    ///     mime_type: Some( "text/plain".to_string() ),
1104    ///     ..Default::default()
1105    /// };
1106    ///
1107    /// // You can set a callback that will be called when a resumable upload
1108    /// // progresses
1109    /// fn progress_callback( total_bytes: usize, uploaded_bytes: usize ) {
1110    ///     println!("Uploaded {} bytes, out of a total of {}.", uploaded_bytes, total_bytes);
1111    /// }
1112    ///
1113    /// let my_new_file = drive.files.create()
1114    ///     .upload_type(UploadType::Resumable)
1115    ///     .callback(progress_callback)
1116    ///     .metadata(&metadata)
1117    ///     .content_source("path/to/file.txt")
1118    ///     .execute()?;
1119    ///
1120    /// assert_eq!(my_new_file.name, metadata.name);
1121    /// assert_eq!(my_new_file.mime_type, metadata.mime_type);
1122    /// # Ok::<(), Error>(())
1123    /// ```
1124    pub fn create( &self ) -> CreateRequest {
1125        CreateRequest::new(&self.credentials)
1126    }
1127
1128    /// Permanently deletes a file owned by the user without moving it to the
1129    /// trash.
1130    ///
1131    /// If the file belongs to a shared drive, the user must be an organizer on
1132    /// the parent folder. If the target is a folder, all descendants owned by
1133    /// the user are also deleted.
1134    ///
1135    /// # Requires one of the following OAuth scopes:
1136    ///
1137    /// - `https://www.googleapis.com/auth/drive`
1138    /// - `https://www.googleapis.com/auth/drive.appdata`
1139    /// - `https://www.googleapis.com/auth/drive.file`
1140    ///
1141    /// # Examples:
1142    ///
1143    /// ```no_run
1144    /// # use drive_v3::{Error, Credentials, Drive};
1145    /// #
1146    /// # let drive = Drive::new( &Credentials::from_file(
1147    /// #     "../.secure-files/google_drive_credentials.json",
1148    /// #     &["https://www.googleapis.com/auth/drive.file"],
1149    /// # )? );
1150    /// #
1151    /// let my_file_id = "example-id";
1152    ///
1153    /// drive.files.delete(&my_file_id).execute()?;
1154    ///
1155    /// # Ok::<(), Error>(())
1156    /// ```
1157    pub fn delete<T: AsRef<str>> ( &self, file_id: T ) -> DeleteRequest {
1158        DeleteRequest::new(&self.credentials, &file_id)
1159    }
1160
1161    /// Permanently deletes all of the user's trashed files.
1162    ///
1163    /// # Note:
1164    ///
1165    /// The emptying of the trash may take some time to be reflected in a user's
1166    /// Drive.
1167    ///
1168    /// # Requires the following OAuth scope:
1169    ///
1170    /// - `https://www.googleapis.com/auth/drive`
1171    ///
1172    /// # Examples:
1173    ///
1174    /// ```no_run
1175    /// # use drive_v3::{Error, Credentials, Drive};
1176    /// #
1177    /// # let drive = Drive::new( &Credentials::from_file(
1178    /// #     "../.secure-files/google_drive_credentials.json",
1179    /// #     &["https://www.googleapis.com/auth/drive"],
1180    /// # )? );
1181    /// #
1182    /// drive.files.empty_trash()
1183    ///     // .drive_id("my-drive-id") // You can specify which drive to empty the trash from
1184    ///     .execute()?;
1185    ///
1186    /// # Ok::<(), Error>(())
1187    /// ```
1188    #[cfg(not(tarpaulin_include))] // Requires higher permissions
1189    pub fn empty_trash( &self ) -> EmptyTrashRequest {
1190        EmptyTrashRequest::new(&self.credentials)
1191    }
1192
1193    /// Exports a Google Workspace document to the requested MIME type and
1194    /// returns exported byte content (limited to 10MB).
1195    ///
1196    /// For more information on the supported export MIME types, check Google's
1197    /// [documentation](https://developers.google.com/drive/api/guides/ref-export-formats).
1198    ///
1199    /// # Note:
1200    ///
1201    /// This request requires you to set the
1202    /// [`mime_type`](ExportRequest::mime_type) of the file to export.
1203    ///
1204    /// # Requires one of the following OAuth scopes:
1205    ///
1206    /// - `https://www.googleapis.com/auth/drive`
1207    /// - `https://www.googleapis.com/auth/drive.file`
1208    /// - `https://www.googleapis.com/auth/drive.readonly`
1209    ///
1210    /// # Examples:
1211    ///
1212    /// ```no_run
1213    /// use std::fs;
1214    /// use std::io::Write;
1215    /// # use drive_v3::{Error, Credentials, Drive};
1216    /// #
1217    /// # let drive = Drive::new( &Credentials::from_file(
1218    /// #     "../.secure-files/google_drive_credentials.json",
1219    /// #     &["https://www.googleapis.com/auth/drive.file"],
1220    /// # )? );
1221    /// #
1222    /// let my_file_id = "file-id";
1223    /// let my_exported_mime_type = "application/pdf";
1224    ///
1225    /// let exported_bytes = drive.files.export(&my_file_id)
1226    ///     .mime_type(my_exported_mime_type)
1227    ///     .execute()?;
1228    ///
1229    /// // Write the bytes to a file
1230    /// let mut file = fs::File::create("exported-file.pdf")?;
1231    /// file.write_all(&exported_bytes)?;
1232    ///
1233    /// # Ok::<(), Error>(())
1234    /// ```
1235    #[cfg(not(tarpaulin_include))] // Requires higher permissions
1236    pub fn export<T: AsRef<str>> ( &self, file_id: T ) -> ExportRequest {
1237        ExportRequest::new(&self.credentials, &file_id)
1238    }
1239
1240    /// Generates a set of file IDs which can be provided in create or copy
1241    /// requests.
1242    ///
1243    /// # Requires one of the following OAuth scopes:
1244    ///
1245    /// - `https://www.googleapis.com/auth/drive`
1246    /// - `https://www.googleapis.com/auth/drive.appdata`
1247    /// - `https://www.googleapis.com/auth/drive.file`
1248    ///
1249    /// # Examples:
1250    ///
1251    /// ```no_run
1252    /// use drive_v3::objects::{Space, IDKind};
1253    /// # use drive_v3::{Error, Credentials, Drive};
1254    /// #
1255    /// # let drive = Drive::new( &Credentials::from_file(
1256    /// #     "../.secure-files/google_drive_credentials.json",
1257    /// #     &["https://www.googleapis.com/auth/drive.file"],
1258    /// # )? );
1259    ///
1260    /// let my_generated_ids = drive.files.generate_ids()
1261    ///     .count(5) // How many IDs to generate
1262    ///     .space(Space::Drive) // Set the space in which the IDs can be used
1263    ///     .kind(IDKind::Files) // Set the type of the IDs
1264    ///     .execute()?;
1265    ///
1266    /// for id in &my_generated_ids.ids {
1267    ///     println!("Generated this ID: {}", id);
1268    /// }
1269    /// # Ok::<(), Error>(())
1270    /// ```
1271    pub fn generate_ids( &self ) -> GenerateIDsRequest {
1272        GenerateIDsRequest::new(&self.credentials)
1273    }
1274
1275    /// Gets a file's metadata by ID.
1276    ///
1277    /// # Note:
1278    ///
1279    /// To get the content of a file you can use [`get_media`](Files::get_media)
1280    /// (only works if the file is stored in Drive).
1281    ///
1282    /// To download Google Docs, Sheets, and Slides use
1283    /// [`export`](Files::export) instead.
1284    ///
1285    /// # Requires one of the following OAuth scopes:
1286    ///
1287    /// - `https://www.googleapis.com/auth/drive`
1288    /// - `https://www.googleapis.com/auth/drive.appdata`
1289    /// - `https://www.googleapis.com/auth/drive.file`
1290    /// - `https://www.googleapis.com/auth/drive.metadata`
1291    /// - `https://www.googleapis.com/auth/drive.metadata.readonly`
1292    /// - `https://www.googleapis.com/auth/drive.photos.readonly`
1293    /// - `https://www.googleapis.com/auth/drive.readonly`
1294    ///
1295    /// # Examples:
1296    ///
1297    /// ```no_run
1298    /// # use drive_v3::{Error, Credentials, Drive};
1299    /// #
1300    /// # let drive = Drive::new( &Credentials::from_file(
1301    /// #     "../.secure-files/google_drive_credentials.json",
1302    /// #     &["https://www.googleapis.com/auth/drive.file"],
1303    /// # )? );
1304    /// #
1305    /// let my_file_id = "file-id";
1306    ///
1307    /// let file_metadata = drive.files.get(&my_file_id).execute()?;
1308    ///
1309    /// println!("Look at this metadata:\n{}", file_metadata);
1310    /// # Ok::<(), Error>(())
1311    /// ```
1312    pub fn get<T: AsRef<str>> ( &self, file_id: T ) -> GetRequest {
1313        GetRequest::new(&self.credentials, &file_id)
1314    }
1315
1316    /// Gets a file's content by ID.
1317    ///
1318    /// # Requires one of the following OAuth scopes:
1319    ///
1320    /// - `https://www.googleapis.com/auth/drive`
1321    /// - `https://www.googleapis.com/auth/drive.appdata`
1322    /// - `https://www.googleapis.com/auth/drive.file`
1323    /// - `https://www.googleapis.com/auth/drive.metadata`
1324    /// - `https://www.googleapis.com/auth/drive.metadata.readonly`
1325    /// - `https://www.googleapis.com/auth/drive.photos.readonly`
1326    /// - `https://www.googleapis.com/auth/drive.readonly`
1327    ///
1328    /// # Examples:
1329    ///
1330    /// ```no_run
1331    /// # use drive_v3::{Error, Credentials, Drive};
1332    /// #
1333    /// # let drive = Drive::new( &Credentials::from_file(
1334    /// #     "../.secure-files/google_drive_credentials.json",
1335    /// #     &["https://www.googleapis.com/auth/drive.file"],
1336    /// # )? );
1337    /// #
1338    /// let my_text_file_id = "file-id";
1339    ///
1340    /// let file_bytes = drive.files.get_media(&my_text_file_id)
1341    ///     // .save_to("my_downloaded_file.txt") // Save the contents to a path
1342    ///     .execute()?;
1343    ///
1344    /// let content = String::from_utf8_lossy(&file_bytes);
1345    ///
1346    /// println!("content: {}", content);
1347    /// # Ok::<(), Error>(())
1348    /// ```
1349    pub fn get_media<T: AsRef<str>> ( &self, file_id: T ) -> GetMediaRequest {
1350        GetMediaRequest::new(&self.credentials, &file_id)
1351    }
1352
1353    /// Lists the user's files.
1354    ///
1355    /// This method accepts the [`q`](ListRequest::q) parameter, which is a
1356    /// search query combining one or more search terms.
1357    ///
1358    /// For more information, see Google's
1359    /// [Search for files & folders](https://developers.google.com/drive/api/guides/search-files)
1360    /// guide.
1361    ///
1362    /// # Note
1363    ///
1364    /// This method returns all files by default, including trashed files. If
1365    /// you don't want trashed files to appear in the list, use the
1366    /// `trashed=false` or `not trashed` in the [`q`](ListRequest::q) parameter
1367    /// to remove trashed files from the results.
1368    ///
1369    /// # Requires one of the following OAuth scopes:
1370    ///
1371    /// - `https://www.googleapis.com/auth/drive`
1372    /// - `https://www.googleapis.com/auth/drive.appdata`
1373    /// - `https://www.googleapis.com/auth/drive.file`
1374    /// - `https://www.googleapis.com/auth/drive.metadata`
1375    /// - `https://www.googleapis.com/auth/drive.metadata.readonly`
1376    /// - `https://www.googleapis.com/auth/drive.photos.readonly`
1377    /// - `https://www.googleapis.com/auth/drive.readonly`
1378    ///
1379    /// # Examples:
1380    ///
1381    /// ```no_run
1382    /// # use drive_v3::{Error, Credentials, Drive};
1383    /// #
1384    /// # let drive = Drive::new( &Credentials::from_file(
1385    /// #     "../.secure-files/google_drive_credentials.json",
1386    /// #     &["https://www.googleapis.com/auth/drive.file"],
1387    /// # )? );
1388    /// #
1389    /// let file_list = drive.files.list()
1390    ///     .fields("files(name, id, mimeType)") // Set what fields will be returned
1391    ///     .q("name = 'file_im_looking_for' and not trashed") // search for specific files
1392    ///     .execute()?;
1393    ///
1394    /// if let Some(files) = file_list.files {
1395    ///     for file in &files {
1396    ///         println!("{}", file);
1397    ///     }
1398    /// }
1399    /// # Ok::<(), Error>(())
1400    /// ```
1401    pub fn list( &self ) -> ListRequest {
1402        ListRequest::new(&self.credentials)
1403    }
1404
1405    /// Lists the labels on a file.
1406    ///
1407    /// # Requires one of the following OAuth scopes:
1408    ///
1409    /// - `https://www.googleapis.com/auth/drive`
1410    /// - `https://www.googleapis.com/auth/drive.file`
1411    /// - `https://www.googleapis.com/auth/drive.metadata`
1412    /// - `https://www.googleapis.com/auth/drive.metadata.readonly`
1413    /// - `https://www.googleapis.com/auth/drive.readonly`
1414    ///
1415    /// # Examples:
1416    ///
1417    /// ```no_run
1418    /// # use drive_v3::{Error, Credentials, Drive};
1419    /// #
1420    /// # let drive = Drive::new( &Credentials::from_file(
1421    /// #     "../.secure-files/google_drive_credentials.json",
1422    /// #     &["https://www.googleapis.com/auth/drive.file"],
1423    /// # )? );
1424    /// #
1425    /// let my_file_id = "file-id";
1426    ///
1427    /// let label_list = drive.files.list_labels(&my_file_id)
1428    ///     .max_results(10)
1429    ///     .execute()?;
1430    ///
1431    /// if let Some(labels) = label_list.labels {
1432    ///     for label in &labels {
1433    ///         println!("{}", label);
1434    ///     }
1435    /// }
1436    /// # Ok::<(), Error>(())
1437    /// ```
1438    pub fn list_labels<T: AsRef<str>> ( &self, file_id: T ) -> ListLabelsRequest {
1439        ListLabelsRequest::new(&self.credentials, &file_id)
1440    }
1441
1442    /// Modifies the set of labels applied to a file.
1443    ///
1444    /// Returns a list of the labels that were added or modified.
1445    ///
1446    /// # Note
1447    ///
1448    /// As of now, labels on files are not supported on personal (free) Google
1449    /// Drive accounts.
1450    ///
1451    /// # Requires one of the following OAuth scopes:
1452    ///
1453    /// - `https://www.googleapis.com/auth/drive`
1454    /// - `https://www.googleapis.com/auth/drive.file`
1455    /// - `https://www.googleapis.com/auth/drive.metadata`
1456    ///
1457    /// # Examples:
1458    ///
1459    /// ```no_run
1460    /// use drive_v3::objects::{LabelModification, FieldModification};
1461    /// # use drive_v3::{Error, Credentials, Drive};
1462    /// #
1463    /// # let drive = Drive::new( &Credentials::from_file(
1464    /// #     "../.secure-files/google_drive_credentials.json",
1465    /// #     &["https://www.googleapis.com/auth/drive.file"],
1466    /// # )? );
1467    ///
1468    /// let label_modifications = vec![
1469    ///     LabelModification::from(
1470    ///         "label-id",
1471    ///         &vec![
1472    ///             FieldModification {
1473    ///                 set_text_values: Some( vec!["text".into(), "other_text".into()] ),
1474    ///                 ..Default::default()
1475    ///             }
1476    ///         ]
1477    ///     )
1478    /// ];
1479    ///
1480    /// let my_file_id = "file-id";
1481    ///
1482    /// let modified_labels = drive.files.modify_labels(&my_file_id)
1483    ///     .modifications(label_modifications)
1484    ///     .execute()?;
1485    ///
1486    /// for label in &modified_labels {
1487    ///     println!("this label was modified:\n{}", label);
1488    /// }
1489    /// # Ok::<(), Error>(())
1490    /// ```
1491    #[cfg(not(tarpaulin_include))] // Requires a business account
1492    pub fn modify_labels<T: AsRef<str>> ( &self, file_id: T ) -> ModifyLabelsRequest {
1493        ModifyLabelsRequest::new(&self.credentials, &file_id)
1494    }
1495
1496    /// Updates a file's metadata and/or content.
1497    ///
1498    /// When calling this method, only populate fields in the request that you
1499    /// want to modify. When updating fields, some fields might be changed
1500    /// automatically, such as [`modified_time`](objects::File::modified_time).
1501    ///
1502    /// This method supports patch semantics.
1503    ///
1504    /// # Requires one of the following OAuth scopes:
1505    ///
1506    /// - `https://www.googleapis.com/auth/drive`
1507    /// - `https://www.googleapis.com/auth/drive.appdata`
1508    /// - `https://www.googleapis.com/auth/drive.file`
1509    ///
1510    /// # Examples:
1511    ///
1512    /// Perform a simple upload to create a small media file (5 MB or less)
1513    /// without supplying metadata:
1514    ///
1515    /// ```no_run
1516    /// use drive_v3::objects::{File, UploadType};
1517    /// # use drive_v3::{Error, Credentials, Drive};
1518    /// #
1519    /// # let drive = Drive::new( &Credentials::from_file(
1520    /// #     "../.secure-files/google_drive_credentials.json",
1521    /// #     &["https://www.googleapis.com/auth/drive.file"],
1522    /// # )? );
1523    /// #
1524    /// // A simple upload does not support metadata, however you can use it in
1525    /// // this request to set the MIME type of your new file, any other fields
1526    /// // you set will be ignored.
1527    /// let metadata = File {
1528    ///     mime_type: Some( "text/plain".to_string() ),
1529    ///     ..Default::default()
1530    /// };
1531    ///
1532    /// let my_file_id = "file-id";
1533    ///
1534    /// let my_new_file = drive.files.update(&my_file_id)
1535    ///     .upload_type(UploadType::Media)
1536    ///     .metadata(&metadata)
1537    ///     .content_string("This is the content of my new file!")
1538    ///     // .content_source("path/to/file.txt") // You can also load a file from the system
1539    ///     .execute()?;
1540    ///
1541    /// # Ok::<(), Error>(())
1542    /// ```
1543    ///
1544    /// Perform a multipart upload to create a small media file (5 MB or less)
1545    /// along with metadata that describes the file, in a single request:
1546    ///
1547    /// ```no_run
1548    /// use drive_v3::objects::{File, UploadType};
1549    /// # use drive_v3::{Error, Credentials, Drive};
1550    /// #
1551    /// # let drive = Drive::new( &Credentials::from_file(
1552    /// #     "../.secure-files/google_drive_credentials.json",
1553    /// #     &["https://www.googleapis.com/auth/drive.file"],
1554    /// # )? );
1555    /// #
1556    /// // Set what information the uploaded file wil have
1557    /// let metadata = File {
1558    ///     name: Some( "my-new-file.txt".to_string() ),
1559    ///     mime_type: Some( "text/plain".to_string() ),
1560    ///     ..Default::default()
1561    /// };
1562    ///
1563    /// let my_file_id = "file-id";
1564    ///
1565    /// let my_new_file = drive.files.update(&my_file_id)
1566    ///     .upload_type(UploadType::Multipart)
1567    ///     .metadata(&metadata)
1568    ///     .content_source("path/to/file.txt")
1569    ///     // .content_string("This is the content of my new file!")  // You can use a string
1570    ///     .execute()?;
1571    ///
1572    /// # Ok::<(), Error>(())
1573    /// ```
1574    ///
1575    /// Perform a resumable upload to create a large file (greater than 5 MB):
1576    ///
1577    /// ```no_run
1578    /// use drive_v3::objects::{File, UploadType};
1579    /// # use drive_v3::{Error, Credentials, Drive};
1580    /// #
1581    /// # let drive = Drive::new( &Credentials::from_file(
1582    /// #     "../.secure-files/google_drive_credentials.json",
1583    /// #     &["https://www.googleapis.com/auth/drive.file"],
1584    /// # )? );
1585    /// #
1586    /// // Set what information the uploaded file wil have
1587    /// let metadata = File {
1588    ///     name: Some( "my-new-file.txt".to_string() ),
1589    ///     mime_type: Some( "text/plain".to_string() ),
1590    ///     ..Default::default()
1591    /// };
1592    ///
1593    /// // You can set a callback that will be called when a resumable upload
1594    /// // progress, that way you can monitor and display how far along your
1595    /// // file upload is
1596    /// fn progress_callback( total_bytes: usize, uploaded_bytes: usize ) {
1597    ///     println!("Uploaded {} bytes, out of a total of {}.", uploaded_bytes, total_bytes);
1598    /// }
1599    ///
1600    /// let my_file_id = "file-id";
1601    ///
1602    /// let my_new_file = drive.files.update(&my_file_id)
1603    ///     .upload_type(UploadType::Resumable)
1604    ///     .callback(progress_callback)
1605    ///     .metadata(&metadata)
1606    ///     .content_source("path/to/file.txt")
1607    ///     .execute()?;
1608    ///
1609    /// # Ok::<(), Error>(())
1610    /// ```
1611    pub fn update<T: AsRef<str>> ( &self, file_id: T ) -> UpdateRequest {
1612        UpdateRequest::new(&self.credentials, &file_id)
1613    }
1614
1615    /// Subscribes to changes to a file.
1616    ///
1617    /// # Note
1618    ///
1619    /// In order to subscribe to a file's changes, you must provide a
1620    /// [`Channel`](objects::Channel) with an `id` and an `address` which is the
1621    /// one that will receive the notifications. This can be done by creating a
1622    /// channel using [`from`](objects::Channel::from).
1623    ///
1624    /// For more information on channels, see Google's
1625    /// [documentation](https://developers.google.com/drive/api/guides/push).
1626    ///
1627    /// # Requires one of the following OAuth scopes:
1628    ///
1629    /// - `https://www.googleapis.com/auth/drive`
1630    /// - `https://www.googleapis.com/auth/drive.appdata`
1631    /// - `https://www.googleapis.com/auth/drive.file`
1632    /// - `https://www.googleapis.com/auth/drive.metadata`
1633    /// - `https://www.googleapis.com/auth/drive.metadata.readonly`
1634    /// - `https://www.googleapis.com/auth/drive.photos.readonly`
1635    /// - `https://www.googleapis.com/auth/drive.readonly`
1636    ///
1637    /// # Examples:
1638    ///
1639    /// ```no_run
1640    /// use drive_v3::objects::Channel;
1641    /// # use drive_v3::{Error, Credentials, Drive};
1642    /// #
1643    /// # let drive = Drive::new( &Credentials::from_file(
1644    /// #     "../.secure-files/google_drive_credentials.json",
1645    /// #     &["https://www.googleapis.com/auth/drive.file"],
1646    /// # )? );
1647    ///
1648    /// let channel_id = "my-channel-id";
1649    /// let channel_address = "https://mydomain.com/channel-notifications";
1650    /// let channel = Channel::from(&channel_id, &channel_address);
1651    ///
1652    /// let my_file_id = "file-id";
1653    ///
1654    /// let created_channel = drive.files.watch(&my_file_id)
1655    ///     .channel(&channel)
1656    ///     .execute()?;
1657    ///
1658    /// println!("this is the created channel:\n{}", created_channel);
1659    /// # Ok::<(), Error>(())
1660    /// ```
1661    pub fn watch<T: AsRef<str>> ( &self, file_id: T ) -> WatchRequest {
1662        WatchRequest::new(&self.credentials, &file_id)
1663    }
1664}
1665
1666#[cfg(test)]
1667mod tests {
1668    use std::fs;
1669    use super::Files;
1670    use std::io::Write;
1671    use std::path::PathBuf;
1672    use crate::{objects, ErrorKind};
1673    use crate::utils::test::{INVALID_CREDENTIALS, LOCAL_STORAGE_IN_USE, VALID_CREDENTIALS};
1674
1675    fn get_resource() -> Files {
1676        Files::new(&VALID_CREDENTIALS)
1677    }
1678
1679    fn get_invalid_resource() -> Files {
1680        Files::new(&INVALID_CREDENTIALS)
1681    }
1682
1683    fn delete_file( file: &objects::File ) -> crate::Result<()> {
1684        get_resource().delete( file.clone().id.unwrap() ).execute()
1685    }
1686
1687    fn get_test_metadata() -> objects::File {
1688        objects::File {
1689            name: Some( "test.txt".to_string() ),
1690            description: Some( "a test file".to_string() ),
1691            mime_type: Some( "text/plain".to_string() ),
1692            ..Default::default()
1693        }
1694    }
1695
1696    fn get_test_file() -> (fs::File, PathBuf) {
1697        let path = PathBuf::from("test-file.txt");
1698
1699        let mut test_file = fs::File::create(&path).unwrap();
1700        test_file.write_all( "content".as_bytes() ).unwrap();
1701
1702        (test_file, path)
1703    }
1704
1705    fn get_test_drive_file() -> crate::Result<objects::File> {
1706        let metadata = get_test_metadata();
1707
1708        get_resource().create()
1709            .upload_type(objects::UploadType::Multipart)
1710            .metadata(&metadata)
1711            .content_string("content")
1712            .execute()
1713    }
1714
1715    #[test]
1716    fn new_test() {
1717        let valid_resource = get_resource();
1718        let invalid_resource = get_invalid_resource();
1719
1720        assert_eq!( valid_resource.credentials, VALID_CREDENTIALS.clone() );
1721        assert_eq!( invalid_resource.credentials, INVALID_CREDENTIALS.clone() );
1722    }
1723
1724    #[test]
1725    fn copy_test() {
1726        let metadata = get_test_metadata();
1727        let test_drive_file = get_test_drive_file().unwrap();
1728
1729        let response = get_resource().copy( &test_drive_file.clone().id.unwrap() )
1730            .fields("*")
1731            .metadata(&metadata)
1732            .execute().unwrap();
1733
1734        assert_eq!(response.name, metadata.name);
1735        assert_eq!(response.description, metadata.description);
1736        assert_eq!(response.mime_type, metadata.mime_type);
1737
1738        delete_file(&test_drive_file).expect("Failed to cleanup a created file");
1739        delete_file(&response).expect("Failed to cleanup a created file");
1740    }
1741
1742    #[test]
1743    fn copy_invalid_response_test() {
1744        let response = get_resource().copy("invalid-id")
1745            .execute();
1746
1747        assert!( response.is_err() );
1748        assert_eq!( response.unwrap_err().kind, ErrorKind::Response );
1749    }
1750
1751    #[test]
1752    fn create_media_test() {
1753        // Only run if no other tests are using the local storage
1754        let _unused = LOCAL_STORAGE_IN_USE.lock().unwrap();
1755
1756        let metadata = get_test_metadata();
1757        let (_, test_file_path) = get_test_file();
1758
1759        let response = get_resource().create()
1760            .upload_type(objects::UploadType::Media)
1761            .metadata(&metadata)
1762            .content_source(&test_file_path)
1763            .execute()
1764            .unwrap();
1765
1766        assert_eq!(response.mime_type, metadata.mime_type);
1767
1768        delete_file(&response).expect("Failed to cleanup a created file");
1769        fs::remove_file(&test_file_path).expect("Failed to cleanup a created file");
1770    }
1771
1772    #[test]
1773    fn create_multipart_test() {
1774        // Only run if no other tests are using the local storage
1775        let _unused = LOCAL_STORAGE_IN_USE.lock().unwrap();
1776
1777        let metadata = get_test_metadata();
1778        let (_, test_file_path) = get_test_file();
1779
1780        let response = get_resource().create()
1781            .fields("*")
1782            .upload_type(objects::UploadType::Multipart)
1783            .metadata(&metadata)
1784            .content_string("content")
1785            .execute()
1786            .unwrap();
1787
1788        assert_eq!(response.name, metadata.name);
1789        assert_eq!(response.description, metadata.description);
1790        assert_eq!(response.mime_type, metadata.mime_type);
1791
1792        delete_file(&response).expect("Failed to cleanup a created file");
1793
1794        let response = get_resource().create()
1795            .fields("*")
1796            .upload_type(objects::UploadType::Multipart)
1797            .metadata(&metadata)
1798            .content_source(&test_file_path)
1799            .execute()
1800            .unwrap();
1801
1802        assert_eq!(response.name, metadata.name);
1803        assert_eq!(response.description, metadata.description);
1804        assert_eq!(response.mime_type, metadata.mime_type);
1805
1806        delete_file(&response).expect("Failed to cleanup a created file");
1807        fs::remove_file(&test_file_path).expect("Failed to cleanup a created file");
1808    }
1809
1810    #[test]
1811    fn create_resumable_test() {
1812        // Only run if no other tests are using the local storage
1813        let _unused = LOCAL_STORAGE_IN_USE.lock().unwrap();
1814
1815        fn callback( _: usize, _: usize ) {}
1816
1817        let metadata = get_test_metadata();
1818        let (_, test_file_path) = get_test_file();
1819
1820        let response = get_resource().create()
1821            .fields("*")
1822            .upload_type(objects::UploadType::Resumable)
1823            .metadata(&metadata)
1824            .content_source(&test_file_path)
1825            .callback(callback)
1826            .execute()
1827            .unwrap();
1828
1829        assert_eq!(response.name, metadata.name);
1830        assert_eq!(response.description, metadata.description);
1831        assert_eq!(response.mime_type, metadata.mime_type);
1832
1833        delete_file(&response).expect("Failed to cleanup a created file");
1834        fs::remove_file(&test_file_path).expect("Failed to cleanup a created file");
1835    }
1836
1837    #[test]
1838    fn create_resumable_invalid_response_test() {
1839        // Only run if no other tests are using the local storage
1840        let _unused = LOCAL_STORAGE_IN_USE.lock().unwrap();
1841
1842        let (_, test_file_path) = get_test_file();
1843
1844        let response = get_invalid_resource().create()
1845            .upload_type(objects::UploadType::Resumable)
1846            .content_source(&test_file_path)
1847            .execute();
1848
1849        assert!( response.is_err() );
1850        assert_eq!( response.unwrap_err().kind, ErrorKind::Response );
1851
1852        fs::remove_file(&test_file_path).expect("Failed to cleanup a created file");
1853    }
1854
1855    #[test]
1856    fn create_multiple_sources_test() {
1857        // Only run if no other tests are using the local storage
1858        let _unused = LOCAL_STORAGE_IN_USE.lock().unwrap();
1859
1860        let (_, test_file_path) = get_test_file();
1861
1862        let response = get_resource().create()
1863            .upload_type(objects::UploadType::Media)
1864            .content_string("content")
1865            .content_source(&test_file_path)
1866            .execute();
1867
1868        assert!( response.is_err() );
1869        assert_eq!( response.unwrap_err().kind, ErrorKind::Request );
1870
1871        fs::remove_file(&test_file_path).expect("Failed to cleanup a created file");
1872    }
1873
1874    #[test]
1875    fn create_invalid_resumable_test() {
1876        let response = get_resource().create()
1877            .upload_type(objects::UploadType::Resumable)
1878            .content_string("content")
1879            .execute();
1880
1881        assert!( response.is_err() );
1882        assert_eq!( response.unwrap_err().kind, ErrorKind::Request );
1883    }
1884
1885    #[test]
1886    fn create_no_source_resumable_test() {
1887        let response = get_resource().create()
1888            .upload_type(objects::UploadType::Resumable)
1889            .execute();
1890
1891        assert!( response.is_err() );
1892        assert_eq!( response.unwrap_err().kind, ErrorKind::Request );
1893    }
1894
1895    #[test]
1896    fn create_invalid_response_test() {
1897        let response = get_invalid_resource().create()
1898            .content_string("content")
1899            .execute();
1900
1901        assert!( response.is_err() );
1902        assert_eq!( response.unwrap_err().kind, ErrorKind::Response );
1903    }
1904
1905    #[test]
1906    fn generate_ids_test() {
1907        let response = get_resource().generate_ids()
1908            .count(8)
1909            .space(objects::Space::Drive)
1910            .kind(objects::IDKind::Files)
1911            .execute().unwrap();
1912
1913        assert_eq!( response.ids.len(), 8 );
1914        assert_eq!( response.space, objects::Space::Drive );
1915    }
1916
1917    #[test]
1918    fn get_test() {
1919        let metadata = get_test_metadata();
1920        let test_drive_file = get_test_drive_file().unwrap();
1921
1922        let response = get_resource().get( test_drive_file.clone().id.unwrap() )
1923            .fields("*")
1924            .execute().unwrap();
1925
1926        assert_eq!(response.name, metadata.name);
1927        assert_eq!(response.description, metadata.description);
1928        assert_eq!(response.mime_type, metadata.mime_type);
1929
1930        delete_file(&test_drive_file).expect("Failed to cleanup a created file");
1931    }
1932
1933    #[test]
1934    fn get_media_test() {
1935        // Only run if no other tests are using the local storage
1936        let _unused = LOCAL_STORAGE_IN_USE.lock().unwrap();
1937
1938        let test_drive_file = get_test_drive_file().unwrap();
1939        let save_path = PathBuf::from("saved.txt");
1940
1941        let response = get_resource().get_media( test_drive_file.clone().id.unwrap() )
1942            .save_to(&save_path)
1943            .execute().unwrap();
1944
1945        let content = String::from_utf8(response).unwrap();
1946        let saved_content = fs::read_to_string(&save_path).unwrap();
1947
1948        assert_eq!(&content, "content");
1949        assert_eq!(&saved_content, "content");
1950
1951        delete_file(&test_drive_file).expect("Failed to cleanup a created file");
1952        fs::remove_file(&save_path).expect("Failed to cleanup a created file");
1953    }
1954
1955    #[test]
1956    fn get_media_invalid_response_test() {
1957        let response = get_invalid_resource().get_media("invalid-id")
1958            .execute();
1959
1960        assert!( response.is_err() );
1961        assert_eq!( response.unwrap_err().kind, ErrorKind::Response );
1962    }
1963
1964    #[test]
1965    fn list_test() {
1966        let response = get_resource().list()
1967            .execute();
1968
1969        assert!( response.is_ok() );
1970    }
1971
1972    #[test]
1973    fn list_labels_test() {
1974        let test_drive_file = get_test_drive_file().unwrap();
1975
1976        let response = get_resource().list_labels( test_drive_file.clone().id.unwrap() )
1977            .execute();
1978
1979        assert!( response.is_ok() );
1980
1981        delete_file(&test_drive_file).expect("Failed to cleanup a created file");
1982    }
1983
1984    #[test]
1985    fn update_test() {
1986        // Only run if no other tests are using the local storage
1987        let _unused = LOCAL_STORAGE_IN_USE.lock().unwrap();
1988
1989        let metadata = get_test_metadata();
1990        let test_drive_file = get_test_drive_file().unwrap();
1991        let (_, test_file_path) = get_test_file();
1992
1993        let response = get_resource().update( test_drive_file.clone().id.unwrap() )
1994            .upload_type(objects::UploadType::Media)
1995            .metadata(&metadata)
1996            .content_source(&test_file_path)
1997            .execute()
1998            .unwrap();
1999
2000        assert_eq!(response.id, test_drive_file.id);
2001        assert_eq!(response.mime_type, metadata.mime_type);
2002
2003        delete_file(&test_drive_file).expect("Failed to cleanup a created file");
2004        fs::remove_file(&test_file_path).expect("Failed to cleanup a created file");
2005    }
2006
2007    #[test]
2008    fn update_string_test() {
2009        // Only run if no other tests are using the local storage
2010        let _unused = LOCAL_STORAGE_IN_USE.lock().unwrap();
2011
2012        let metadata = get_test_metadata();
2013        let test_drive_file = get_test_drive_file().unwrap();
2014        let (_, test_file_path) = get_test_file();
2015
2016        let response = get_resource().update( test_drive_file.clone().id.unwrap() )
2017            .upload_type(objects::UploadType::Media)
2018            .metadata(&metadata)
2019            .content_string("new content")
2020            .execute()
2021            .unwrap();
2022
2023        assert_eq!(response.id, test_drive_file.id);
2024        assert_eq!(response.mime_type, metadata.mime_type);
2025
2026        delete_file(&test_drive_file).expect("Failed to cleanup a created file");
2027        fs::remove_file(&test_file_path).expect("Failed to cleanup a created file");
2028    }
2029
2030    #[test]
2031    fn update_multipart_test() {
2032        // Only run if no other tests are using the local storage
2033        let _unused = LOCAL_STORAGE_IN_USE.lock().unwrap();
2034
2035        let metadata = get_test_metadata();
2036        let test_drive_file = get_test_drive_file().unwrap();
2037        let (_, test_file_path) = get_test_file();
2038
2039        let response = get_resource().update( test_drive_file.clone().id.unwrap() )
2040            .fields("*")
2041            .upload_type(objects::UploadType::Multipart)
2042            .metadata(&metadata)
2043            .content_string("content")
2044            .execute()
2045            .unwrap();
2046
2047        assert_eq!(response.id, test_drive_file.id);
2048        assert_eq!(response.name, metadata.name);
2049        assert_eq!(response.description, metadata.description);
2050        assert_eq!(response.mime_type, metadata.mime_type);
2051
2052        let response = get_resource().update( test_drive_file.clone().id.unwrap() )
2053            .fields("*")
2054            .upload_type(objects::UploadType::Multipart)
2055            .metadata(&metadata)
2056            .content_source(&test_file_path)
2057            .execute()
2058            .unwrap();
2059
2060        assert_eq!(response.id, test_drive_file.id);
2061        assert_eq!(response.name, metadata.name);
2062        assert_eq!(response.description, metadata.description);
2063        assert_eq!(response.mime_type, metadata.mime_type);
2064
2065        delete_file(&test_drive_file).expect("Failed to cleanup a created file");
2066        fs::remove_file(&test_file_path).expect("Failed to cleanup a created file");
2067    }
2068
2069    #[test]
2070    fn update_resumable_test() {
2071        // Only run if no other tests are using the local storage
2072        let _unused = LOCAL_STORAGE_IN_USE.lock().unwrap();
2073
2074        fn callback( _: usize, _: usize ) {}
2075
2076        let metadata = get_test_metadata();
2077        let test_drive_file = get_test_drive_file().unwrap();
2078        let (_, test_file_path) = get_test_file();
2079
2080        let response = get_resource().update( test_drive_file.clone().id.unwrap() )
2081            .fields("*")
2082            .upload_type(objects::UploadType::Resumable)
2083            .metadata(&metadata)
2084            .content_source(&test_file_path)
2085            .callback(callback)
2086            .execute()
2087            .unwrap();
2088
2089        assert_eq!(response.id, test_drive_file.id);
2090        assert_eq!(response.name, metadata.name);
2091        assert_eq!(response.description, metadata.description);
2092        assert_eq!(response.mime_type, metadata.mime_type);
2093
2094        delete_file(&test_drive_file).expect("Failed to cleanup a created file");
2095        fs::remove_file(&test_file_path).expect("Failed to cleanup a created file");
2096    }
2097
2098    #[test]
2099    fn update_invalid_id_test() {
2100        let response = get_resource().update("invalid-id")
2101            .execute();
2102
2103        assert!( response.is_err() );
2104        assert_eq!( response.unwrap_err().kind, ErrorKind::Response );
2105    }
2106
2107    #[test]
2108    fn update_resumable_invalid_response_test() {
2109        // Only run if no other tests are using the local storage
2110        let _unused = LOCAL_STORAGE_IN_USE.lock().unwrap();
2111
2112        let (_, test_file_path) = get_test_file();
2113
2114        let response = get_invalid_resource().update("invalid-id")
2115            .upload_type(objects::UploadType::Resumable)
2116            .content_source(&test_file_path)
2117            .execute();
2118
2119        assert!( response.is_err() );
2120        assert_eq!( response.unwrap_err().kind, ErrorKind::Response );
2121
2122        fs::remove_file(&test_file_path).expect("Failed to cleanup a created file");
2123    }
2124
2125    #[test]
2126    fn update_invalid_response_test() {
2127        let response = get_invalid_resource().update("invalid-id")
2128            .content_string("content")
2129            .execute();
2130
2131        assert!( response.is_err() );
2132        assert_eq!( response.unwrap_err().kind, ErrorKind::Response );
2133    }
2134
2135    #[test]
2136    fn update_multiple_sources_test() {
2137        // Only run if no other tests are using the local storage
2138        let _unused = LOCAL_STORAGE_IN_USE.lock().unwrap();
2139
2140        let test_drive_file = get_test_drive_file().unwrap();
2141        let (_, test_file_path) = get_test_file();
2142
2143        let response = get_resource().update( test_drive_file.clone().id.unwrap() )
2144            .upload_type(objects::UploadType::Media)
2145            .content_string("content")
2146            .content_source(&test_file_path)
2147            .execute();
2148
2149        assert!( response.is_err() );
2150        assert_eq!( response.unwrap_err().kind, ErrorKind::Request );
2151
2152        delete_file(&test_drive_file).expect("Failed to cleanup a created file");
2153        fs::remove_file(&test_file_path).expect("Failed to cleanup a created file");
2154    }
2155
2156    #[test]
2157    fn update_invalid_resumable_test() {
2158        let test_drive_file = get_test_drive_file().unwrap();
2159
2160        let response = get_resource().update( test_drive_file.clone().id.unwrap() )
2161            .upload_type(objects::UploadType::Resumable)
2162            .content_string("content")
2163            .execute();
2164
2165        assert!( response.is_err() );
2166        assert_eq!( response.unwrap_err().kind, ErrorKind::Request );
2167
2168        delete_file(&test_drive_file).expect("Failed to cleanup a created file");
2169    }
2170
2171    #[test]
2172    fn update_no_source_resumable_test() {
2173        let test_drive_file = get_test_drive_file().unwrap();
2174
2175        let response = get_resource().update( test_drive_file.clone().id.unwrap() )
2176            .upload_type(objects::UploadType::Resumable)
2177            .execute();
2178
2179        assert!( response.is_err() );
2180        assert_eq!( response.unwrap_err().kind, ErrorKind::Request );
2181
2182        delete_file(&test_drive_file).expect("Failed to cleanup a created file");
2183    }
2184
2185    #[test]
2186    fn watch_test() {
2187        let test_drive_file = get_test_drive_file().unwrap();
2188
2189        let channel_id = "channel_id".to_string();
2190        let channel_address = "https://wwwgoogle.com".to_string();
2191
2192        let channel = objects::Channel::from(&channel_id, &channel_address);
2193
2194        let response = get_resource().watch( test_drive_file.clone().id.unwrap() )
2195            .channel(&channel)
2196            .execute();
2197
2198        assert!( response.is_ok() );
2199        assert_eq!( response.unwrap().id, Some(channel_id) );
2200
2201        delete_file(&test_drive_file).expect("Failed to cleanup a created file");
2202    }
2203
2204    #[test]
2205    fn watch_invalid_response_test() {
2206        let response = get_invalid_resource().watch("invalid-id")
2207            .execute();
2208
2209        assert!( response.is_err() );
2210        assert_eq!( response.unwrap_err().kind, ErrorKind::Response );
2211    }
2212}