onedrive_api/
resource.rs

1//! Resource Objects defined in the OneDrive API.
2//!
3//! # Field descriptors
4//!
5//! Resource object `struct`s have field descriper `enum`s representing
6//! all controllable fields of it, which may be used
7//! in [`onedrive_api::option`][option] to [`select`][select] or [`expand`][expand] it using
8//! `with_option` version API of [`OneDrive`][one_drive].
9//!
10//! ## Example
11//! Here is an example to use [`resource::DriveItemField`][drive_item_field].
12//! ```
13//! use onedrive_api::{OneDrive, ItemLocation, option::ObjectOption};
14//! use onedrive_api::resource::*;
15//!
16//! # async fn run(drive: &OneDrive) -> onedrive_api::Result<()> {
17//! // let drive: OneDrive;
18//! let item: Option<DriveItem> = drive
19//!     .get_item_with_option(
20//!         ItemLocation::root(),
21//!         ObjectOption::new()
22//!             .if_none_match(&Tag("<abcdABCD1234>".to_owned()))
23//!             // Only response `id` and `e_tag` to reduce data transmission.
24//!             .select(&[DriveItemField::id, DriveItemField::e_tag]),
25//!     )
26//!     .await?;
27//! match item {
28//!     None => println!("Tag matched"),
29//!     Some(item) => {
30//!         println!("id: {:?}, e_tag: {:?}", item.id.unwrap(), item.e_tag.unwrap());
31//!     }
32//! }
33//! # Ok(())
34//! # }
35//! ```
36//!
37//! # See also
38//! [Microsoft Docs](https://docs.microsoft.com/en-us/onedrive/developer/rest-api/resources/?view=odsp-graph-online)
39//!
40//! [option]: ../option/index.html
41//! [select]: ../option/struct.ObjectOption.html#method.select
42//! [expand]: ../option/struct.ObjectOption.html#method.expand
43//! [one_drive]: ../struct.OneDrive.html
44//! [drive_item_field]: ./enum.DriveItemField.html
45use serde::{Deserialize, Serialize};
46
47/// A semantic alias for URL string in resource objects.
48pub type Url = String;
49
50/// Boxed raw json value.
51pub type JsonValue = Box<serde_json::Value>;
52
53/// Timestamp string with ISO 8601 format.
54pub type TimestampString = String;
55
56macro_rules! define_string_wrapper {
57    ($($(#[$meta:meta])* $vis:vis $name:ident;)*) => { $(
58        $(#[$meta])*
59        #[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
60        $vis struct $name(pub String);
61
62        impl $name {
63            /// View as str.
64            #[inline]
65            #[must_use]
66            pub fn as_str(&self) -> &str {
67                &self.0
68            }
69        }
70    )* };
71}
72
73define_string_wrapper! {
74    /// Wrapper for a unique identifier to a `Drive`.
75    ///
76    /// # See also
77    /// [Microsoft Docs: Drive resource type](https://docs.microsoft.com/en-us/graph/api/resources/drive?view=graph-rest-1.0)
78    pub DriveId;
79
80    /// Wrapper for a unique identifier for a `DriveItem`.
81    ///
82    /// # See also
83    /// [Microsoft Docs: driveItem resource type](https://docs.microsoft.com/en-us/graph/api/resources/driveitem?view=graph-rest-1.0)
84    pub ItemId;
85
86    /// Wrapper for a tag representing the state of an item.
87    ///
88    /// Used for avoid data transmission when a resource is not modified.
89    ///
90    /// The tag from [`DriveItem::c_tag`][c_tag] is for the content of the item,
91    /// while the one from [`DriveItem::e_tag`][e_tag] is for the entire item (metadata + content).
92    ///
93    /// # See also
94    /// [Microsoft Docs: driveItem resource type](https://docs.microsoft.com/en-us/graph/api/resources/driveitem?view=graph-rest-1.0)
95    ///
96    /// [e_tag]: ./struct.DriveItem.html#structfield.e_tag
97    /// [c_tag]: ./struct.DriveItem.html#structfield.c_tag
98    pub Tag;
99}
100
101// Used for generalization over any resource field enums in `option`.
102#[doc(hidden)]
103#[allow(clippy::module_name_repetitions)] // Internal trait.
104pub trait ResourceField: Copy {
105    fn __raw_name(self) -> &'static str;
106}
107
108macro_rules! define_resource_object {
109    ($(
110        $(#[$meta:meta])*
111        $vis:vis struct $struct_name:ident #$field_enum_name:ident {
112            $(
113                $(#[$field_meta:meta])*
114                pub $field_name:ident
115                    $(@$field_rename:literal)?
116                    : Option<$field_ty:ty>,
117            )*
118        }
119    )*) => {
120        $(
121            $(#[$meta])*
122            #[derive(Debug, Default, Clone, Deserialize, Serialize)]
123            #[serde(rename_all = "camelCase")]
124            #[non_exhaustive]
125            $vis struct $struct_name {
126                $(
127                    #[allow(missing_docs)]
128                    #[serde(skip_serializing_if="Option::is_none")]
129                    $(#[$field_meta])*
130                    $(#[serde(rename = $field_rename)])?
131                    pub $field_name: Option<$field_ty>,
132                )*
133            }
134
135            /// Fields descriptors.
136            ///
137            /// More details in [mod documentation][mod].
138            ///
139            /// [mod]: ./index.html
140            #[derive(Debug, Clone, Copy, Eq, PartialEq, strum::VariantNames)]
141            #[strum(serialize_all = "camelCase")]
142            #[non_exhaustive]
143            #[allow(missing_docs, non_camel_case_types)]
144            $vis enum $field_enum_name {
145                $(
146                    $(#[strum(serialize = $field_rename)])?
147                    $field_name,
148                )*
149            }
150
151            impl $field_enum_name {
152                /// Get the raw camelCase name of the field.
153                #[must_use]
154                pub fn raw_name(self) -> &'static str {
155                    <Self as strum::VariantNames>::VARIANTS[self as usize]
156                }
157            }
158
159            impl ResourceField for $field_enum_name {
160                #[inline]
161                fn __raw_name(self) -> &'static str {
162                    self.raw_name()
163                }
164            }
165
166        )*
167    };
168}
169
170define_resource_object! {
171    /// Drive resource type
172    ///
173    /// The drive resource is the top level object representing a user's OneDrive
174    /// or a document library in SharePoint.
175    ///
176    /// # See also
177    /// [Microsoft Docs](https://docs.microsoft.com/en-us/graph/api/resources/drive?view=graph-rest-1.0)
178    pub struct Drive #DriveField {
179        pub id: Option<DriveId>,
180        pub created_by: Option<JsonValue>,
181        pub created_date_time: Option<TimestampString>,
182        pub description: Option<String>,
183        pub drive_type: Option<JsonValue>,
184        pub items: Option<Vec<DriveItem>>,
185        pub last_modified_by: Option<JsonValue>,
186        pub last_modified_date_time: Option<TimestampString>,
187        pub name: Option<String>,
188        pub owner: Option<JsonValue>,
189        pub quota: Option<JsonValue>,
190        pub root: Option<DriveItem>,
191        pub sharepoint_ids: Option<JsonValue>,
192        pub special: Option<Vec<DriveItem>>,
193        pub system: Option<JsonValue>,
194        pub web_url: Option<Url>,
195    }
196
197    /// DriveItem resource type
198    ///
199    /// The `DriveItem` resource represents a file, folder, or other item stored in a drive.
200    /// All file system objects in OneDrive and SharePoint are returned as `DriveItem` resources.
201    ///
202    /// # See also
203    /// [Microsoft Docs](https://docs.microsoft.com/en-us/graph/api/resources/driveitem?view=graph-rest-1.0)
204    pub struct DriveItem #DriveItemField {
205
206        // Drive item
207
208        pub audio: Option<JsonValue>,
209        pub bundle: Option<JsonValue>,
210        pub content: Option<JsonValue>,
211        pub c_tag: Option<Tag>,
212        pub deleted: Option<JsonValue>,
213        pub description: Option<String>,
214        pub file: Option<JsonValue>,
215        pub file_system_info: Option<JsonValue>,
216        pub folder: Option<JsonValue>,
217        pub image: Option<JsonValue>,
218        pub location: Option<JsonValue>,
219        pub package: Option<JsonValue>,
220        pub photo: Option<JsonValue>,
221        pub publication: Option<JsonValue>,
222        pub remote_item: Option<JsonValue>,
223        pub root: Option<JsonValue>,
224        pub search_result: Option<JsonValue>,
225        pub shared: Option<JsonValue>,
226        pub sharepoint_ids: Option<JsonValue>,
227        pub size: Option<i64>,
228        pub special_folder: Option<JsonValue>,
229        pub video: Option<JsonValue>,
230        pub web_dav_url: Option<Url>,
231
232        // Relationships
233
234        pub children: Option<Vec<DriveItem>>,
235        pub created_by_user: Option<JsonValue>,
236        pub last_modified_by_user: Option<JsonValue>,
237        pub permissions: Option<JsonValue>,
238        pub thumbnails: Option<JsonValue>,
239        pub versions: Option<JsonValue>,
240
241        // Base item
242
243        pub id: Option<ItemId>,
244        pub created_by: Option<JsonValue>,
245        pub created_date_time: Option<TimestampString>,
246        pub e_tag: Option<Tag>,
247        pub last_modified_by: Option<JsonValue>,
248        pub last_modified_date_time: Option<TimestampString>,
249        pub name: Option<String>,
250        pub parent_reference: Option<JsonValue>,
251        pub web_url: Option<Url>,
252
253        // Instance annotations
254
255        // `@microsoft.graph.conflictBehavior` is write-only.
256
257        /// The pre-authorized url for downloading the content.
258        ///
259        /// It is **NOT** selectable through [`ObjectOption::select`][select] and
260        /// only provided in the result of [`OneDrive::get_item`][get_item]
261        /// (or [`OneDrive::get_item_with_option`][get_item_with_opt]).
262        ///
263        /// [select]: ../option/struct.ObjectOption.html#method.select
264        /// [get_item]: ../struct.OneDrive.html#method.get_item
265        /// [get_item_with_opt]: ../struct.OneDrive.html#method.get_item_with_option
266        pub download_url @"@microsoft.graph.downloadUrl": Option<Url>,
267
268        // `@microsoft.graph.sourceUrl` is write-only
269    }
270}
271
272/// The error resource type, returned whenever an error occurs in the processing of a request.
273///
274/// Error responses follow the definition in the OData v4 specification for error responses.
275///
276/// **This struct is independent with [`OAuth2ErrorResponse`][oauth2_error_response] from OAuth2 API.**
277///
278/// It may be contained in [`onedrive_api::Error`][error] returned by storage API
279/// (methods of [`OneDrive`][one_drive], [`ListChildrenFetcher`][list_children_fetcher], etc.).
280///
281/// # See also
282/// [Microsoft Docs](https://docs.microsoft.com/en-us/graph/errors#error-resource-type)
283///
284/// [oauth2_error_response]: ./struct.OAuth2ErrorResponse.html
285/// [error]: ../struct.Error.html
286/// [one_drive]: ../struct.OneDrive.html
287/// [list_children_fetcher]: ../struct.ListChildrenFetcher.html
288#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
289#[non_exhaustive]
290pub struct ErrorResponse {
291    /// OData `code`. Non-exhaustive.
292    ///
293    /// Some possible values of `code` field can be found in:
294    /// - [Error resource type: code property](https://docs.microsoft.com/en-us/graph/errors#code-property)
295    /// - [Error codes for authorization endpoint errors](https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-auth-code-flow#error-codes-for-authorization-endpoint-errors)
296    /// - And maybe more.
297    pub code: String,
298    /// OData `message`. Usually to be human-readable.
299    pub message: String,
300    /// OData `innererror`. An optional object with additional or more specific error codes.
301    #[serde(rename = "innererror")]
302    pub inner_error: Option<serde_json::Map<String, serde_json::Value>>,
303}
304
305/// OAuth2 error response.
306///
307/// **This struct is independent with [`ErrorResponse`][error_response] from storage API.**
308///
309/// It can only be contained in [`onedrive_api::Error`][error] returned by operations
310/// about OAuth2 (methods of [`Auth`][auth]).
311///
312/// # See also
313/// - [Microsoft Docs: Request an authorization code](https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-auth-code-flow#error-response)
314/// - [Microsoft Docs: Request an access token](https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-auth-code-flow#error-response-1)
315/// - [Microsoft Docs: Refresh the access token](https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-auth-code-flow#error-response-2)
316///
317/// [error_response]: ./struct.ErrorResponse.html
318/// [error]: ../struct.Error.html
319/// [auth]: ../struct.Auth.html
320#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
321#[allow(missing_docs)]
322#[non_exhaustive]
323pub struct OAuth2ErrorResponse {
324    pub error: String,
325    pub error_description: String,
326    pub error_codes: Option<Vec<u32>>,
327    pub timestamp: Option<String>,
328    pub trace_id: Option<String>,
329    pub correlation_id: Option<String>,
330}
331
332#[cfg(test)]
333mod tests {
334    use super::*;
335
336    #[test]
337    fn test_raw_name() {
338        assert_eq!(DriveField::id.raw_name(), "id");
339        assert_eq!(DriveField::drive_type.raw_name(), "driveType");
340        assert_eq!(DriveField::owner.raw_name(), "owner");
341        assert_eq!(DriveField::web_url.raw_name(), "webUrl");
342
343        assert_eq!(DriveItemField::id.raw_name(), "id");
344        assert_eq!(
345            DriveItemField::file_system_info.raw_name(),
346            "fileSystemInfo"
347        );
348        assert_eq!(DriveItemField::size.raw_name(), "size");
349        assert_eq!(DriveItemField::web_dav_url.raw_name(), "webDavUrl");
350        assert_eq!(DriveItemField::web_url.raw_name(), "webUrl");
351
352        assert_eq!(
353            DriveItemField::download_url.raw_name(),
354            "@microsoft.graph.downloadUrl",
355        );
356    }
357}