1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
use crate::models::Resource;
use crate::{OpenLibraryClient, OpenLibraryError, OpenLibraryErrorResponse};
use chrono::{DateTime, Utc};
use serde::de::Error;
use serde::{Deserialize, Deserializer, Serialize};

#[derive(Serialize)]
pub struct LoginRequest {
    pub username: String,
    pub password: String,
}

pub enum ReadingLogResponseWrapper {
    Success(ReadingLogResponse),
    Err(OpenLibraryErrorResponse),
}

impl<'de> Deserialize<'de> for ReadingLogResponseWrapper {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        let json: serde_json::Value = Deserialize::deserialize(deserializer)?;

        match json.get("error") {
            None => Ok(ReadingLogResponseWrapper::Success(
                serde_json::from_value(json).map_err(D::Error::custom)?,
            )),
            Some(_) => Ok(ReadingLogResponseWrapper::Err(
                serde_json::from_value(json).map_err(D::Error::custom)?,
            )),
        }
    }
}

#[derive(Clone, Debug, Deserialize, Eq, PartialEq)]
pub struct Session {
    cookie: String,
    username: String,
}

impl Session {
    pub fn from(cookie: String, username: String) -> Self {
        Session { cookie, username }
    }

    pub fn cookie(&self) -> &String {
        &self.cookie
    }

    pub fn username(&self) -> &String {
        &self.username
    }
}

#[derive(Clone)]
pub enum ReadingLog {
    AlreadyRead,
    CurrentlyReading,
    WantToRead,
}

impl ReadingLog {
    pub fn url(&self) -> &str {
        match self {
            ReadingLog::AlreadyRead => "already-read.json",
            ReadingLog::CurrentlyReading => "currently-reading.json",
            ReadingLog::WantToRead => "want-to-read.json",
        }
    }

    pub async fn retrieve_for(
        &self,
        client: &OpenLibraryClient,
        username: String,
    ) -> Result<Vec<ReadingLogEntry>, OpenLibraryError> {
        match self {
            ReadingLog::AlreadyRead => client.account.get_already_read(username).await,
            ReadingLog::CurrentlyReading => client.account.get_currently_reading(username).await,
            ReadingLog::WantToRead => client.account.get_want_to_read(username).await,
        }
    }
}

#[derive(Debug, Deserialize, Serialize)]
pub struct ReadingLogResponse {
    pub page: i16,
    pub reading_log_entries: Vec<ReadingLogEntry>,
}

#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct ReadingLogEntry {
    pub work: ReadingLogWork,
    pub logged_edition: Resource,
    #[serde(with = "crate::format::datetime")]
    pub logged_date: DateTime<Utc>,
}

#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct ReadingLogWork {
    pub title: String,
    pub key: Resource,
    pub author_keys: Vec<Resource>,
    pub author_names: Vec<String>,
    pub first_publish_year: Option<i32>,
    pub lending_edition_s: Option<String>,
    pub edition_key: Vec<String>,
    pub cover_id: Option<i32>,
    pub cover_edition_key: Option<String>,
}