use serde::{Deserialize, Serialize}; use thiserror::Error; use chrono::prelude::*; pub type Campaigns = Vec>; pub type Pledges = Vec>; pub type Users = Vec>; #[derive(Debug, Serialize, Deserialize, Clone)] pub struct Campaign { pub summary: String, pub creation_name: String, pub display_patron_goals: bool, pub pay_per_name: String, pub one_liner: Option, pub main_video_embed: Option, pub main_video_url: Option, pub image_small_url: String, pub image_url: String, pub thanks_video_url: Option, pub thanks_embed: Option, pub thanks_msg: String, pub is_charged_immediately: bool, pub is_monthly: bool, pub is_nsfw: bool, pub is_plural: bool, pub created_at: DateTime, pub published_at: DateTime, pub pledge_url: String, pub pledge_sum: i32, pub patron_count: u32, pub creation_count: u32, pub outstanding_payment_amount_cents: u64, } #[derive(Debug, Serialize, Deserialize, Clone)] pub struct Pledge { pub amount_cents: u32, pub created_at: String, pub declined_since: Option, pub pledge_cap_cents: u32, pub patron_pays_fees: bool, pub total_historical_amount_cents: Option, pub is_paused: Option, pub has_shipping_address: Option, pub outstanding_payment_amount_cents: Option, } #[derive(Debug, Serialize, Deserialize, Clone)] pub struct User { pub first_name: String, pub last_name: String, pub full_name: String, pub vanity: Option, pub about: Option, pub gender: i32, pub image_url: String, pub thumb_url: String, pub created: DateTime, pub url: String, } pub type Result = std::result::Result; #[derive(Error, Debug)] pub enum Error { #[error("json error: {0:?}")] Json(#[from] serde_json::Error), #[error("request error: {0:?}")] Request(#[from] reqwest::Error), } #[derive(Debug, Serialize, Deserialize, Clone)] pub struct Credentials { pub client_id: String, pub client_secret: String, pub access_token: String, pub refresh_token: String, } pub struct Client { cli: reqwest::Client, base_url: String, creds: Credentials, } #[derive(Debug, Serialize, Deserialize, Clone)] pub struct Data { pub data: T, pub included: Option>, } #[derive(Debug, Serialize, Deserialize, Clone)] pub struct Object { pub id: String, pub attributes: T, pub r#type: String, pub links: Option, } #[derive(Debug, Serialize, Deserialize, Clone)] pub struct Links { related: String, } impl Client { pub fn new(creds: Credentials) -> Self { Self { cli: reqwest::Client::new(), base_url: "https://api.patreon.com".into(), creds: creds, } } pub async fn campaign(&self) -> Result>, ()>> { let data = self .cli .get(&format!( "{}/oauth2/api/current_user/campaigns", self.base_url )) .query(&[("include", "patron.null"), ("includes", "")]) .header( "Authorization", format!("Bearer {}", self.creds.access_token), ) .send() .await? .error_for_status()?.text().await?; log::debug!("campaign response: {}", data); Ok(serde_json::from_str(&data)?) } pub async fn pledges(&self, camp_id: String) -> Result>> { let data = self .cli .get(&format!( "{}/oauth2/api/campaigns/{}/pledges", self.base_url, camp_id )) .query(&[("include", "patron.null")]) .header( "Authorization", format!("Bearer {}", self.creds.access_token), ) .send() .await? .error_for_status()? .text() .await?; log::debug!("pledges for {}: {}", camp_id, data); let data : Data>, Object> = serde_json::from_str(&data)?; Ok(data.included.unwrap()) } }