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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
extern crate serde;
extern crate reqwest;
extern crate uuid;
extern crate chrono;
extern crate serde_json;
extern crate erased_serde;

pub mod command;
pub mod resource;

mod types;
mod tests;

pub use types::*;

#[macro_use] extern crate serde_derive;

#[derive(Serialize, Deserialize, Debug)]
pub enum Resource {
    Label(resource::Label),
    Project(resource::Project),
    Item(resource::Item),
    Note(resource::Note),
    Filter(resource::Filter),
    User(resource::User),
    Collaborator(resource::Collaborator),
    LiveNotification(resource::LiveNotification),
}

#[derive(Serialize, Deserialize, Debug)]
pub enum ResourceType {
    #[serde(rename = "all")]
    All,

    #[serde(rename = "labels")]
    Labels,

    #[serde(rename = "projects")]
    Projects,

    #[serde(rename = "items")]
    Items,

    #[serde(rename = "notes")]
    Notes,

    #[serde(rename = "filters")]
    Filters,

    #[serde(rename = "reminders")]
    Reminders,

    #[serde(rename = "location")]
    Locations, // TODO

    #[serde(rename = "user")]
    User,

    #[serde(rename = "live_notifications")]
    LiveNotifications,

    #[serde(rename = "collaborators")]
    Collaborators,

    #[serde(rename = "notification_settings")]
    NotificationSettings, // TODO
}




#[derive(Serialize, Deserialize, Default, Debug)]
#[serde(default)]
pub struct CommandResponse {

}



#[derive(Serialize, Deserialize, Default, Debug)]
#[serde(default)]
pub struct SyncResponse {
    pub sync_token : String,
    pub full_sync : bool,
    pub items : Option<Vec<resource::Item>>,
    pub labels : Option<Vec<resource::Label>>,
    pub projects : Option<Vec<resource::Project>>,
    pub collaborators : Option<Vec<resource::Collaborator>>,
    pub notes : Option<Vec<resource::Note>>,
    pub filters : Option<Vec<resource::Filter>>,
    pub live_notifications : Option<Vec<resource::LiveNotification>>,
    pub reminders : Option<Vec<resource::Reminder>>,
    pub user : Option<resource::User>,
}

/// Client to make request to the todoist API
pub struct Client {
    token: String,
    client: reqwest::Client,
    last_sync: String,
}

impl Client {

    /// Create a new with todoist API client with auth token `tok`
    pub fn new(tok: &str) -> Client {
        Client::new_with_sync(tok, "*")
    }
    
    /// create a new client with a sync token
    pub fn new_with_sync(tok: &str, sync_tok: &str) -> Client {
        Client {
            client: reqwest::Client::new(),
            token: String::from(tok),
            last_sync: String::from(sync_tok),

        }
    }

    /// Request resources from todoist
    pub fn sync(&mut self, what: &[ResourceType]) -> Result<SyncResponse, types::Error> {
        let res : SyncResponse = self.client.post("http://todoist.com/api/v7/sync")
            .form(&[("token", self.token.clone()), 
                    ("sync_token", self.last_sync.clone()),
                    ("resource_types", serde_json::to_string(what)?)])
            .send()?
            .json()?;

        self.last_sync = res.sync_token.clone();
        Ok(res)
    }

    /// Update a user's resources
    pub fn send(&mut self, cmd: &[&command::Command]) -> Result<CommandResponse, types::Error> {
        let res : CommandResponse = self.client.post("http://todoist.com/api/v7/sync")
            .form(&[("token", self.token.clone()), 
                    ("resource_types", serde_json::to_string(cmd)?)])
            .send()?
            .json()?;

        Ok(res)
    }
}