drive-v3 0.6.0

A library for interacting the Google Drive API
Documentation
use reqwest::Method;
use drive_v3_macros::{DriveRequestBuilder, request};

use super::DriveRequestBuilder;
use crate::{objects, Credentials};

#[request(
    method=Method::POST,
    url="https://www.googleapis.com/drive/v3/channels/stop",
    returns=()
)]
#[derive(DriveRequestBuilder)]
/// A request builder to stop watching resources through a channel.
pub struct StopRequest {
    /// The channel which will be stopped.
    #[drive_v3(body)]
    channel: Option<objects::Channel>
}

/// 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::{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 ) -> crate::Result<()> {
        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() -> crate::Result<objects::File> {
        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 ) -> crate::Result<objects::Channel> {
        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 );
    }
}