imgurs-model 0.2.0

A typed and safe model of the Imgur API
Documentation
//! Album specification

use std::fmt;

use crate::model::common::AccountID;
use serde::{Deserialize, Serialize};
use serde_json::Value;
use time::{serde::timestamp, OffsetDateTime};
use url::Url;

/// Album unique identifier
#[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Serialize, Deserialize)]
pub struct AlbumID(String);

impl<U> From<U> for AlbumID
where
    U: Into<String>,
{
    fn from(v: U) -> Self {
        AlbumID(v.into())
    }
}

impl fmt::Display for AlbumID {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.0.fmt(f)
    }
}

/// The base model for an album
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
#[serde(deny_unknown_fields)]
pub struct Album {
    /// The ID for the album
    pub id: AlbumID,
    /// The title of the album in the gallery
    pub title: String,
    /// The description of the album in the gallery
    pub description: Option<String>,
    /// Time inserted into the gallery, epoch time
    #[serde(with = "timestamp")]
    pub datetime: OffsetDateTime,
    /// The ID of the album cover image
    pub cover: Option<String>,
    /// TODO: missing from API model
    pub cover_edited: Option<Value>,
    /// The width, in pixels, of the album cover image
    pub cover_width: Option<u64>,
    /// The height, in pixels, of the album cover image
    pub cover_height: Option<u64>,
    /// The account username or null if it's anonymous.
    pub account_url: Option<String>,
    /// The account ID or null if it's anonymous.
    pub account_id: Option<AccountID>,
    /// The privacy level of the album, you can only view public if not logged in as album owner
    // TODO: Switch to enum
    pub privacy: String,
    /// The view layout of the album.
    // TODO: Switch to enum
    pub layout: String,
    /// The number of album views
    pub views: u64,
    /// The URL link to the album
    pub link: Url,
    /// Indicates if the current user favorited the image. Defaults to false if not signed in.
    pub favorite: bool,
    /// Indicates if the image has been marked as nsfw or not. Defaults to null if information is not available.
    pub nsfw: bool,
    /// If the image has been categorized by our backend then this will contain the section the image belongs in. (funny, cats, adviceanimals, wtf, etc)
    pub section: String,
    /// Order number of the album on the user's album page (defaults to 0 if their albums haven't been reordered)
    pub order: Option<u64>,
    /// OPTIONAL, the deletehash, if you're logged in as the album owner
    #[serde(rename = "deletehash")]
    pub delete_hash: Option<String>,
    /// The total number of images in the album
    pub images_count: u64,
    /// An array of all the images in the album (only available when requesting the direct album)
    ///
    /// TODO: switch to image object
    pub images: Vec<Value>,
    /// True if the image has been submitted to the gallery, false if otherwise.
    pub in_gallery: bool,
    /// True if the image is an ad
    pub is_ad: bool,
    /// TODO: missing from API model
    pub include_album_ads: bool,
    /// TODO: missing from API model
    pub is_album: bool,
    /// TODO: missing from API model, switch to an object
    pub ad_config: Value,
}

#[cfg(test)]
mod test {
    use std::error::Error;

    use crate::model::{album::Album, basic::Basic};

    #[test]
    fn test_deserialize_album_local() -> Result<(), Box<dyn Error>> {
        let res = r#"{"data":{"id":"z6B0j","title":"DOOGLE","description":null,"datetime":1515221993,"cover":null,"cover_edited":null,"cover_width":null,"cover_height":null,"account_url":null,"account_id":null,"privacy":"public","layout":"blog","views":84,"link":"https://imgur.com/a/z6B0j","favorite":false,"nsfw":false,"section":"ImgurAlbums","images_count":1,"in_gallery":false,"is_ad":false,"include_album_ads":false,"is_album":true,"images":[{"id":"1nneRbX","title":"DOOGLE","description":"Doogle","datetime":1515221708,"type":"image/png","animated":false,"width":1279,"height":717,"size":379024,"views":8705,"bandwidth":3299403920,"vote":null,"favorite":false,"nsfw":null,"section":null,"account_url":null,"account_id":null,"is_ad":false,"in_most_viral":false,"has_sound":false,"tags":[],"ad_type":0,"ad_url":"","edited":"0","in_gallery":false,"link":"https://i.imgur.com/1nneRbX.png"}],"ad_config":{"safeFlags":["not_in_gallery","subreddit","page_load"],"highRiskFlags":[],"unsafeFlags":["sixth_mod_unsafe"],"wallUnsafeFlags":[],"showsAds":false}},"success":true,"status":200}"#;

        let data = serde_json::from_str::<Basic<Album>>(res)?;

        println!("{:#?}", data);

        Ok(())
    }
}