diff options
| author | Christine Dodrill <me@christine.website> | 2020-07-16 15:32:30 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-07-16 15:32:30 -0400 |
| commit | 385d25c9f96c0acd5d932488e3bd0ed36ceb4dd7 (patch) | |
| tree | af789f7250519b23038a7e5ea0ae7f4f4c1ffdfc /lib/patreon/src | |
| parent | 449e934246c82d90dd0aac2644d67f928befeeb4 (diff) | |
| download | xesite-385d25c9f96c0acd5d932488e3bd0ed36ceb4dd7.tar.xz xesite-385d25c9f96c0acd5d932488e3bd0ed36ceb4dd7.zip | |
Rewrite site backend in Rust (#178)
* add shell.nix changes for Rust #176
* set up base crate layout
* add first set of dependencies
* start adding basic app modules
* start html templates
* serve index page
* add contact and feeds pages
* add resume rendering support
* resume cleanups
* get signalboost page working
* rewrite config to be in dhall
* more work
* basic generic post loading
* more tests
* initial blog index support
* fix routing?
* render blogposts
* X-Clacks-Overhead
* split blog handlers into blog.rs
* gallery index
* gallery posts
* fix hashtags
* remove instantpage (it messes up the metrics)
* talk support + prometheus
* Create rust.yml
* Update rust.yml
* Update codeql-analysis.yml
* add jsonfeed library
* jsonfeed support
* rss/atom
* go mod tidy
* atom: add posted date
* rss: add publishing date
* nix: build rust program
* rip out go code
* rip out go templates
* prepare for serving in docker
* create kubernetes deployment
* create automagic deployment
* build docker images on non-master
* more fixes
* fix timestamps
* fix RSS/Atom/JSONFeed validation errors
* add go vanity import redirecting
* templates/header: remove this
* atom feed: fixes
* fix?
* fix??
* fix rust tests
* Update rust.yml
* automatically show snow during the winter
* fix dates
* show commit link in footer
* sitemap support
* fix compiler warning
* start basic patreon client
* integrate kankyo
* fix patreon client
* add patrons page
* remove this
* handle patron errors better
* fix build
* clean up deploy
* sort envvars for deploy
* remove deps.nix
* shell.nix: remove go
* update README
* fix envvars for tests
* nice
* blog: add rewrite in rust post
* blog/site-update: more words
Diffstat (limited to 'lib/patreon/src')
| -rw-r--r-- | lib/patreon/src/lib.rs | 158 |
1 files changed, 158 insertions, 0 deletions
diff --git a/lib/patreon/src/lib.rs b/lib/patreon/src/lib.rs new file mode 100644 index 0000000..07e6228 --- /dev/null +++ b/lib/patreon/src/lib.rs @@ -0,0 +1,158 @@ +#[macro_use] +extern crate log; + +use serde::{Deserialize, Serialize}; +use thiserror::Error; +use chrono::prelude::*; + +pub type Campaigns = Vec<Object<Campaign>>; +pub type Pledges = Vec<Object<Pledge>>; +pub type Users = Vec<Object<User>>; + +#[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<String>, + pub main_video_embed: Option<String>, + pub main_video_url: Option<String>, + pub image_small_url: String, + pub image_url: String, + pub thanks_video_url: Option<String>, + pub thanks_embed: Option<String>, + 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<Utc>, + pub published_at: DateTime<Utc>, + 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<String>, + pub pledge_cap_cents: u32, + pub patron_pays_fees: bool, + pub total_historical_amount_cents: Option<u32>, + pub is_paused: Option<bool>, + pub has_shipping_address: Option<bool>, + pub outstanding_payment_amount_cents: Option<u32>, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct User { + pub first_name: String, + pub last_name: String, + pub full_name: String, + pub vanity: Option<String>, + pub about: Option<String>, + pub gender: i32, + pub image_url: String, + pub thumb_url: String, + pub created: DateTime<Utc>, + pub url: String, +} + +pub type Result<T> = std::result::Result<T, Error>; + +#[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<T, U> { + pub data: T, + pub included: Option<Vec<U>>, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct Object<T> { + pub id: String, + pub attributes: T, + pub r#type: String, + pub links: Option<Links>, +} + +#[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<Data<Vec<Object<Campaign>>, ()>> { + 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<Vec<Object<User>>> { + 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<Vec<Object<Pledge>>, Object<User>> = serde_json::from_str(&data)?; + Ok(data.included.unwrap()) + } +} |
