drive_v3/resources/changes.rs
1use reqwest::Method;
2use std::collections::HashMap;
3use drive_v3_macros::{DriveRequestBuilder, request};
4
5use super::DriveRequestBuilder;
6use crate::{objects, Credentials, Error, ErrorKind};
7
8#[request(
9 method=Method::GET,
10 url="https://www.googleapis.com/drive/v3/changes/startPageToken",
11)]
12#[derive(DriveRequestBuilder)]
13/// A request builder to get the starting `pageToken` for listing future
14/// changes.
15pub struct GetStartPageTokenRequest {
16 /// The ID of the shared drive for which the starting pageToken for
17 /// listing future changes from that shared drive will be returned.
18 #[drive_v3(parameter)]
19 drive_id: Option<String>,
20
21 /// Whether the requesting application supports both My Drives and
22 /// shared drives.
23 #[drive_v3(parameter)]
24 supports_all_drives: Option<bool>,
25}
26
27impl GetStartPageTokenRequest {
28 /// Executes this request.
29 ///
30 /// # Errors:
31 ///
32 /// - a [`UrlParsing`](crate::ErrorKind::UrlParsing) error, if the creation
33 /// of the request's URL failed.
34 /// - a [`Request`](crate::ErrorKind::Request) error, if unable to send the
35 /// request or get a body from the response.
36 /// - a [`Response`](crate::ErrorKind::Response) error, if the request
37 /// returned an error response.
38 /// - a [`Json`](crate::ErrorKind::Json) error, if unable to parse the
39 /// response's body.
40 pub fn execute( &self ) -> crate::Result<String> {
41 let response = self.send()?;
42 let response_text = response.text()?;
43 let parsed_json = serde_json::from_str::<HashMap<&str, String>> (&response_text)?;
44
45 match parsed_json.get("startPageToken") {
46 Some(token) => Ok( token.clone() ),
47 #[cfg(not(tarpaulin_include))]
48 None => Err( Error::new(
49 ErrorKind::Json,
50 "the response did not contain the 'startPageToken' field",
51 ) )
52 }
53 }
54}
55
56#[request(
57 method=Method::GET,
58 url="https://www.googleapis.com/drive/v3/changes",
59 returns=objects::ChangeList,
60)]
61#[derive(DriveRequestBuilder)]
62/// A request builder to list the changes for a user or drive.
63pub struct ListRequest {
64 /// The shared drive from which changes will be returned.
65 ///
66 /// If specified the change IDs will be reflective of the shared drive;
67 /// use the combined drive ID and change ID as an identifier.
68 #[drive_v3(parameter)]
69 drive_id: Option<String>,
70
71 /// Whether changes should include the file resource if the file is
72 /// still accessible by the user at the time of the request, even when
73 /// a file was removed from the list of changes and there will be no
74 /// further change entries for this file.
75 #[drive_v3(parameter)]
76 include_corpus_removals: Option<bool>,
77
78 /// Whether both My Drive and shared drive items should be included in
79 /// results.
80 #[drive_v3(parameter)]
81 include_items_from_all_drives: Option<bool>,
82
83 /// Whether to include changes indicating that items have been removed
84 /// from the list of changes, for example by deletion or loss of access.
85 #[drive_v3(parameter)]
86 include_removed: Option<bool>,
87
88 /// The maximum number of changes to return per page.
89 #[drive_v3(parameter)]
90 page_size: Option<i64>,
91
92 /// The token for continuing a previous list request on the next page.
93 ///
94 /// This should be set to the value of
95 /// [`next_page_token`](objects::ChangeList::next_page_token) from the
96 /// previous response or to the response from the
97 /// [`get_start_page_token`](Changes::get_start_page_token) method.
98 #[drive_v3(parameter)]
99 page_token: Option<String>,
100
101 /// Whether to restrict the results to changes inside the My Drive
102 /// hierarchy.
103 ///
104 /// This omits changes to files such as those in the Application Data
105 /// folder or shared files which have not been added to My Drive.
106 #[drive_v3(parameter)]
107 restrict_to_my_drive: Option<bool>,
108
109 /// A comma-separated list of spaces to query within the corpora.
110 ///
111 /// Supported values are `drive` and `appDataFolder`.
112 #[drive_v3(parameter)]
113 spaces: Option<String>,
114
115 /// Whether the requesting application supports both My Drives and
116 /// shared drives.
117 #[drive_v3(parameter)]
118 supports_all_drives: Option<bool>,
119
120 /// Specifies which additional view's permissions to include in the
121 /// response.
122 ///
123 /// Only `published` is supported.
124 #[drive_v3(parameter)]
125 include_permissions_for_view: Option<String>,
126
127 /// A comma-separated list of IDs of labels to include in the
128 /// [`label_info`](objects::File::label_info) part of the response.
129 #[drive_v3(parameter)]
130 include_labels: Option<String>,
131}
132
133#[request(
134 method=Method::POST,
135 url="https://www.googleapis.com/drive/v3/changes/watch",
136 returns=objects::Channel,
137)]
138#[derive(DriveRequestBuilder)]
139/// A request builder for subscribing to changes for a user.
140pub struct WatchRequest {
141 /// The shared drive from which changes will be returned.
142 ///
143 /// If specified the change IDs will be reflective of the shared drive;
144 /// use the combined drive ID and change ID as an identifier.
145 #[drive_v3(parameter)]
146 drive_id: Option<String>,
147
148 /// Whether changes should include the file resource if the file is
149 /// still accessible by the user at the time of the request, even when
150 /// a file was removed from the list of changes and there will be no
151 /// further change entries for this file.
152 #[drive_v3(parameter)]
153 include_corpus_removals: Option<bool>,
154
155 /// Whether both My Drive and shared drive items should be included in
156 /// results.
157 #[drive_v3(parameter)]
158 include_items_from_all_drives: Option<bool>,
159
160 /// Whether to include changes indicating that items have been removed
161 /// from the list of changes, for example by deletion or loss of access.
162 #[drive_v3(parameter)]
163 include_removed: Option<bool>,
164
165 /// The maximum number of changes to return per page.
166 #[drive_v3(parameter)]
167 page_size: Option<i64>,
168
169 /// The token for continuing a previous list request on the next page.
170 ///
171 /// This should be set to the value of
172 /// [`next_page_token`](objects::ChangeList::next_page_token) from the
173 /// previous response or to the response from the
174 /// [`get_start_page_token`](Changes::get_start_page_token) method.
175 #[drive_v3(parameter)]
176 page_token: Option<String>,
177
178 /// Whether to restrict the results to changes inside the My Drive
179 /// hierarchy.
180 ///
181 /// This omits changes to files such as those in the Application Data
182 /// folder or shared files which have not been added to My Drive.
183 #[drive_v3(parameter)]
184 restrict_to_my_drive: Option<bool>,
185
186 /// A comma-separated list of spaces to query within the corpora.
187 ///
188 /// Supported values are `drive` and `appDataFolder`.
189 #[drive_v3(parameter)]
190 spaces: Option<String>,
191
192 /// Whether the requesting application supports both My Drives and
193 /// shared drives.
194 #[drive_v3(parameter)]
195 supports_all_drives: Option<bool>,
196
197 /// Specifies which additional view's permissions to include in the
198 /// response.
199 ///
200 /// Only `published` is supported.
201 #[drive_v3(parameter)]
202 include_permissions_for_view: Option<String>,
203
204 /// A comma-separated list of IDs of labels to include in the
205 /// [`label_info`](objects::File::label_info) part of the response.
206 #[drive_v3(parameter)]
207 include_labels: Option<String>,
208
209 /// Sets the metadata that the channel will have.
210 #[drive_v3(body)]
211 channel: Option<objects::Channel>
212}
213
214/// A change to a file or shared drive.
215///
216/// # Examples:
217///
218/// List changes in a drive
219///
220/// ```no_run
221/// # use drive_v3::{Error, Credentials, Drive};
222/// #
223/// # let drive = Drive::new( &Credentials::from_file(
224/// # "../.secure-files/google_drive_credentials.json",
225/// # &["https://www.googleapis.com/auth/drive.file"],
226/// # )? );
227/// #
228/// let drive_id = "some-drive-id";
229/// let page_token = "some-page-token";
230///
231/// let change_list = drive.changes.list()
232/// .page_size(10)
233/// .drive_id(drive_id)
234/// .page_token(page_token)
235/// .execute()?;
236///
237/// if let Some(changes) = change_list.changes {
238/// for change in changes {
239/// println!("{}", change);
240/// }
241/// }
242/// # Ok::<(), Error>(())
243/// ```
244#[derive(Debug, Clone, PartialEq, Eq)]
245pub struct Changes {
246 /// Credentials used to authenticate a user's access to this resource.
247 credentials: Credentials,
248}
249
250impl Changes {
251 /// Creates a new [`Changes`] resource with the given [`Credentials`].
252 pub fn new( credentials: &Credentials ) -> Self {
253 Self { credentials: credentials.clone() }
254 }
255
256 /// Gets the starting `pageToken` for listing future changes.
257 ///
258 /// The starting page token is used for listing future changes. The page
259 /// token doesn't expire.
260 ///
261 /// See Google's
262 /// [documentation](https://developers.google.com/drive/api/reference/rest/v3/changes/getStartPageToken)
263 /// for more information.
264 ///
265 /// # Note:
266 ///
267 /// This request requires you to set the
268 /// [`drive_id`](GetStartPageTokenRequest::drive_id) and
269 /// [`supports_all_drives`](GetStartPageTokenRequest::supports_all_drives)
270 /// parameters.
271 ///
272 /// # Requires one of the following OAuth scopes:
273 ///
274 /// - `https://www.googleapis.com/auth/drive`
275 /// - `https://www.googleapis.com/auth/drive.appdata`
276 /// - `https://www.googleapis.com/auth/drive.file`
277 /// - `https://www.googleapis.com/auth/drive.metadata`
278 /// - `https://www.googleapis.com/auth/drive.metadata.readonly`
279 /// - `https://www.googleapis.com/auth/drive.photos.readonly`
280 /// - `https://www.googleapis.com/auth/drive.readonly`
281 ///
282 /// # Examples:
283 ///
284 /// ```no_run
285 /// # use drive_v3::{Error, Credentials, Drive};
286 /// #
287 /// # let drive = Drive::new( &Credentials::from_file(
288 /// # "../.secure-files/google_drive_credentials.json",
289 /// # &["https://www.googleapis.com/auth/drive.file"],
290 /// # )? );
291 /// #
292 /// let drive_id = "some-drive-id";
293 ///
294 /// let start_page_token = drive.changes.get_start_page_token()
295 /// .drive_id(drive_id)
296 /// .supports_all_drives(true)
297 /// .execute()?;
298 ///
299 /// println!("Your start page token is: {}", start_page_token);
300 /// # Ok::<(), Error>(())
301 /// ```
302 pub fn get_start_page_token( &self ) -> GetStartPageTokenRequest {
303 GetStartPageTokenRequest::new(&self.credentials)
304 }
305
306 /// Lists the changes for a user or shared drive.
307 ///
308 /// See Google's
309 /// [documentation](https://developers.google.com/drive/api/reference/rest/v3/changes/list)
310 /// for more information.
311 ///
312 /// # Note:
313 ///
314 /// This request requires you to set the
315 /// [`drive_id`](ListRequest::drive_id) and
316 /// [`page_token`](ListRequest::page_token)
317 /// parameters.
318 ///
319 /// # Requires one of the following OAuth scopes:
320 ///
321 /// - `https://www.googleapis.com/auth/drive`
322 /// - `https://www.googleapis.com/auth/drive.appdata`
323 /// - `https://www.googleapis.com/auth/drive.file`
324 /// - `https://www.googleapis.com/auth/drive.metadata`
325 /// - `https://www.googleapis.com/auth/drive.metadata.readonly`
326 /// - `https://www.googleapis.com/auth/drive.photos.readonly`
327 /// - `https://www.googleapis.com/auth/drive.readonly`
328 ///
329 /// # Examples:
330 ///
331 /// ```no_run
332 /// # use drive_v3::{Error, Credentials, Drive};
333 /// #
334 /// # let drive = Drive::new( &Credentials::from_file(
335 /// # "../.secure-files/google_drive_credentials.json",
336 /// # &["https://www.googleapis.com/auth/drive.file"],
337 /// # )? );
338 /// #
339 /// let drive_id = "some-drive-id";
340 /// let page_token = "some-page-token";
341 ///
342 /// let change_list = drive.changes.list()
343 /// .page_size(10)
344 /// .drive_id(drive_id)
345 /// .page_token(page_token)
346 /// .execute()?;
347 ///
348 /// if let Some(changes) = change_list.changes {
349 /// for change in changes {
350 /// println!("{}", change);
351 /// }
352 /// }
353 /// # Ok::<(), Error>(())
354 /// ```
355 pub fn list( &self ) -> ListRequest {
356 ListRequest::new(&self.credentials)
357 }
358
359 /// Subscribes to changes for a user.
360 ///
361 /// See Google's
362 /// [documentation](https://developers.google.com/drive/api/reference/rest/v3/changes/watch)
363 /// for more information.
364 ///
365 /// # Note:
366 ///
367 /// This request requires you to set the
368 /// [`drive_id`](ListRequest::drive_id) and
369 /// [`page_token`](ListRequest::page_token)
370 /// parameters.
371 ///
372 /// # Note
373 ///
374 /// In order to subscribe to changes, you must provide a
375 /// [`Channel`](objects::Channel) with an `id` and an `address` which is the
376 /// one that will receive the notifications. This can be done by creating a
377 /// channel using [`from`](objects::Channel::from).
378 ///
379 /// For more informChangesation on channels, see Google's
380 /// [documentation](https://developers.google.com/drive/api/guides/push).
381 ///
382 /// # Requires one of the following OAuth scopes:
383 ///
384 /// - `https://www.googleapis.com/auth/drive`
385 /// - `https://www.googleapis.com/auth/drive.appdata`
386 /// - `https://www.googleapis.com/auth/drive.file`
387 /// - `https://www.googleapis.com/auth/drive.metadata`
388 /// - `https://www.googleapis.com/auth/drive.metadata.readonly`
389 /// - `https://www.googleapis.com/auth/drive.photos.readonly`
390 /// - `https://www.googleapis.com/auth/drive.readonly`
391 ///
392 /// # Examples:
393 ///
394 /// ```no_run
395 /// use drive_v3::objects::Channel;
396 /// # use drive_v3::{Error, Credentials, Drive};
397 /// #
398 /// # let drive = Drive::new( &Credentials::from_file(
399 /// # "../.secure-files/google_drive_credentials.json",
400 /// # &["https://www.googleapis.com/auth/drive.file"],
401 /// # )? );
402 ///
403 /// let channel_id = "my-channel-id";
404 /// let channel_address = "https://mydomain.com/channel-notifications";
405 /// let channel = Channel::from(&channel_id, &channel_address);
406 ///
407 /// let drive_id = "some-drive-id";
408 /// let page_token = "some-page-token";
409 ///
410 /// let created_channel = drive.changes.watch()
411 /// .drive_id(drive_id)
412 /// .page_token(page_token)
413 /// .channel(&channel)
414 /// .execute()?;
415 ///
416 /// println!("this is the created channel:\n{}", created_channel);
417 /// # Ok::<(), Error>(())
418 /// ```
419 pub fn watch( &self ) -> WatchRequest {
420 WatchRequest::new(&self.credentials)
421 }
422}
423
424#[cfg(test)]
425mod tests {
426 use super::Changes;
427 use crate::{objects, ErrorKind};
428 use crate::utils::test::{INVALID_CREDENTIALS, VALID_CREDENTIALS};
429
430 fn get_resource() -> Changes {
431 Changes::new(&VALID_CREDENTIALS)
432 }
433
434 fn get_invalid_resource() -> Changes {
435 Changes::new(&INVALID_CREDENTIALS)
436 }
437
438 #[test]
439 fn new_test() {
440 let valid_resource = get_resource();
441 let invalid_resource = get_invalid_resource();
442
443 assert_eq!( valid_resource.credentials, VALID_CREDENTIALS.clone() );
444 assert_eq!( invalid_resource.credentials, INVALID_CREDENTIALS.clone() );
445 }
446
447 #[test]
448 fn get_start_page_token_invalid_response_test() {
449 let response = get_invalid_resource().get_start_page_token()
450 .drive_id("test-drive-id")
451 .supports_all_drives(true)
452 .execute();
453
454 assert!( response.is_err() );
455 assert_eq!( response.unwrap_err().kind, ErrorKind::Response );
456 }
457
458 #[test]
459 fn list_invalid_response_test() {
460 let response = get_invalid_resource().list()
461 .drive_id("test-drive-id")
462 .page_token("test-page-token")
463 .execute();
464
465 assert!( response.is_err() );
466 assert_eq!( response.unwrap_err().kind, ErrorKind::Response );
467 }
468
469 #[test]
470 fn watch_invalid_response_test() {
471 let channel = objects::Channel::from("test-channel-id", "test-address");
472
473 let response = get_invalid_resource().watch()
474 .drive_id("test-drive-id")
475 .page_token("test-page-token")
476 .channel(&channel)
477 .execute();
478
479 assert!( response.is_err() );
480 assert_eq!( response.unwrap_err().kind, ErrorKind::Response );
481 }
482}