drive-v3 0.5.1

A library for interacting the Google Drive API
Documentation
use reqwest::Method;

use crate::{objects, request_builder, Credentials, Error};

request_builder!(
    /// A request builder to stop watching resources through a channel.
    pub StopRequest {},

    // HTTP Method
    Method::POST,

    // API endpoint
    ("https://www.googleapis.com/drive/v3/channels/stop"),

    // Other fields

    /// The channel which will be stopped.
    channel: Option<objects::Channel>
);

impl StopRequest {
    /// Executes this request.
    ///
    /// # Errors:
    ///
    /// - a [`UrlParsing`](crate::ErrorKind::UrlParsing) error, if the creation
    /// of the request's URL failed.
    /// - a [`Request`](crate::ErrorKind::Request) error, if unable to send the
    /// request or get a body from the response.
    /// - a [`Response`](crate::ErrorKind::Response) error, if the request
    /// returned an error response.
    /// - a [`Json`](crate::ErrorKind::Json) error, if unable to parse the
    /// response's body.
    pub fn execute( &self ) -> Result<(), Error> {
        let channel = self.channel.clone().unwrap_or_default();
        let channel_string = serde_json::to_string(&channel)?;
        let content_length = channel_string.as_bytes().len();

        let request = self.build()?
            .header( "Content-Length", content_length.to_string() )
            .body(channel_string);

        let response = request.send()?;

        if !response.status().is_success() {
            return Err( response.into() )
        }

        Ok(())
    }
}

/// A notification channel used to watch for resource changes.
///
/// # Examples:
///
/// ```no_run
/// use drive_v3::objects::Channel;
/// # use drive_v3::{Error, Credentials, Drive};
/// #
/// # let drive = Drive::new( &Credentials::from_file(
/// #     ".secure-files/google_drive_credentials.json",
/// #     &["https://www.googleapis.com/auth/drive.file"],
/// # )? );
///
/// // You should use the channel return by requests like files.watch or
/// // changes.watch
/// let channel = Channel::new();
///
/// let response = drive.channels.stop()
///     .channel(&channel)
///     .execute();
///
/// assert!( response.is_ok() );
/// # Ok::<(), Error>(())
/// ```
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Channels {
    /// Credentials used to authenticate a user's access to this resource.
    credentials: Credentials,
}

impl Channels {
    /// Creates a new [`Channels`] resource with the given [`Credentials`].
    pub fn new( credentials: &Credentials ) -> Self {
        Self { credentials: credentials.clone() }
    }

    /// Stops watching resources through this channel.
    ///
    /// See Google's
    /// [documentation](https://developers.google.com/drive/api/reference/rest/v3/channels/stop)
    /// for more information.
    ///
    /// # Requires one of the following OAuth scopes:
    ///
    /// - `https://www.googleapis.com/auth/docs`
    /// - `https://www.googleapis.com/auth/drive`
    /// - `https://www.googleapis.com/auth/drive.appdata`
    /// - `https://www.googleapis.com/auth/drive.apps`
    /// - `https://www.googleapis.com/auth/drive.file`
    /// - `https://www.googleapis.com/auth/drive.metadata`
    /// - `https://www.googleapis.com/auth/drive.metadata.readonly`
    /// - `https://www.googleapis.com/auth/drive.photos.readonly`
    /// - `https://www.googleapis.com/auth/drive.readonly`
    ///
    /// # Examples:
    ///
    /// ```no_run
    /// use drive_v3::objects::Channel;
    /// # use drive_v3::{Error, Credentials, Drive};
    /// #
    /// # let drive = Drive::new( &Credentials::from_file(
    /// #     ".secure-files/google_drive_credentials.json",
    /// #     &["https://www.googleapis.com/auth/drive.file"],
    /// # )? );
    ///
    /// // You should use the channel return by requests like files.watch or
    /// // changes.watch
    /// let channel = Channel::new();
    ///
    /// let response = drive.channels.stop()
    ///     .channel(&channel)
    ///     .execute();
    ///
    /// assert!( response.is_ok() );
    /// # Ok::<(), Error>(())
    /// ```
    pub fn stop( &self ) -> StopRequest {
        StopRequest::new(&self.credentials)
    }
}

#[cfg(test)]
mod tests {
    use super::Channels;
    use crate::{Error, ErrorKind, objects, resources};
    use crate::utils::test::{INVALID_CREDENTIALS, VALID_CREDENTIALS};

    fn get_resource() -> Channels {
        Channels::new(&VALID_CREDENTIALS)
    }

    fn get_invalid_resource() -> Channels {
        Channels::new(&INVALID_CREDENTIALS)
    }

    fn get_files_resource() -> resources::Files {
        resources::Files::new(&VALID_CREDENTIALS)
    }

    fn delete_file( file: &objects::File ) -> Result<(), Error> {
        get_files_resource().delete( file.clone().id.unwrap() ).execute()
    }

    fn get_test_file_metadata() -> objects::File {
        objects::File {
            name: Some( "test.txt".to_string() ),
            description: Some( "a test file".to_string() ),
            mime_type: Some( "text/plain".to_string() ),
            ..Default::default()
        }
    }

    fn get_test_drive_file() -> Result<objects::File, Error> {
        let metadata = get_test_file_metadata();

        get_files_resource().create()
            .upload_type(objects::UploadType::Multipart)
            .metadata(&metadata)
            .content_string("content")
            .execute()
    }

    fn get_test_channel( file: &objects::File ) -> Result<objects::Channel, Error> {
        let channel_id = "test-channel-id";
        let channel_address = "https://gitlab.com/mderr/drive-v3";
        let channel = objects::Channel::from(&channel_id, &channel_address);

        get_files_resource().watch( file.clone().id.unwrap() )
            .channel(&channel)
            .execute()
    }

    #[test]
    fn new_test() {
        let valid_resource = get_resource();
        let invalid_resource = get_invalid_resource();

        assert_eq!( valid_resource.credentials, VALID_CREDENTIALS.clone() );
        assert_eq!( invalid_resource.credentials, INVALID_CREDENTIALS.clone() );
    }

    #[test]
    fn stop_test() {
        let test_drive_file = get_test_drive_file().unwrap();
        let test_channel = get_test_channel(&test_drive_file).unwrap();

        let response = get_resource().stop()
            .channel(&test_channel)
            .execute();

        assert!( response.is_ok() );

        delete_file(&test_drive_file).expect("Failed to cleanup created file");
    }

    #[test]
    fn stop_invalid_test() {
        let response = get_invalid_resource().stop()
            .execute();

        assert!( response.is_err() );
        assert_eq!( response.unwrap_err().kind, ErrorKind::Response );
    }
}