Start refactor of ynab by splitting it up
This commit is contained in:
@@ -0,0 +1,134 @@
|
||||
use super::lookup::Lookup;
|
||||
use super::transform;
|
||||
use super::types;
|
||||
use crate::Transaction;
|
||||
|
||||
pub struct Ynab {
|
||||
token: String,
|
||||
webclient: reqwest::blocking::Client,
|
||||
}
|
||||
|
||||
impl Ynab {
|
||||
pub fn new(token: &str) -> Ynab {
|
||||
Ynab {
|
||||
token: token.to_owned(),
|
||||
webclient: reqwest::blocking::Client::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_plan(&self, plan: Lookup) -> Result<String, String> {
|
||||
match plan {
|
||||
Lookup::Id(id) => Ok(id),
|
||||
Lookup::Name(name) => {
|
||||
let url = "plans";
|
||||
let res: types::YnabResponse<types::YnabPlanList> = serde_json::from_str(
|
||||
&self.get(url).map_err(|e| format!("request error: {}", e))?,
|
||||
)
|
||||
.map_err(|e| format!("parse error: {}", e))?;
|
||||
let plans = res.data.plans;
|
||||
plans
|
||||
.into_iter()
|
||||
.find(|p| p.name == name)
|
||||
.map(|p| p.id)
|
||||
.ok_or_else(|| "no matching plan found".to_string())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_account(&self, plan_id: &str, account: Lookup) -> Result<String, String> {
|
||||
match account {
|
||||
Lookup::Id(id) => Ok(id),
|
||||
Lookup::Name(name) => {
|
||||
let url = format!("plans/{}/accounts", plan_id);
|
||||
let res: types::YnabResponse<types::YnabAccountList> = serde_json::from_str(
|
||||
&self
|
||||
.get(&url)
|
||||
.map_err(|e| format!("request error: {}", e))?,
|
||||
)
|
||||
.map_err(|e| format!("parse error: {}", e))?;
|
||||
let accounts = res.data.accounts;
|
||||
accounts
|
||||
.into_iter()
|
||||
.find(|a| a.name == name)
|
||||
.map(|a| a.id)
|
||||
.ok_or_else(|| "no matching account found".to_string())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn get(&self, request: &str) -> Result<String, reqwest::Error> {
|
||||
const URL: &str = "https://api.ynab.com/v1/";
|
||||
let request = format!("{}{}", URL, request);
|
||||
let res = self
|
||||
.webclient
|
||||
.get(request)
|
||||
.bearer_auth(&self.token)
|
||||
.send()?;
|
||||
let text = res.text()?;
|
||||
Ok(text)
|
||||
}
|
||||
|
||||
fn post(&self, request: &str, body: &str) -> Result<(), String> {
|
||||
const URL: &str = "https://api.ynab.com/v1/";
|
||||
let request = format!("{}{}", URL, request);
|
||||
let res = self
|
||||
.webclient
|
||||
.post(request)
|
||||
.body(body.to_owned())
|
||||
.bearer_auth(&self.token)
|
||||
.header("Content-Type", "application/json")
|
||||
.send()
|
||||
.map_err(|e| format!("post error: {}", e))?;
|
||||
if res.status().is_success() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(format!(
|
||||
"api error: {}: {}",
|
||||
res.status(),
|
||||
res.text()
|
||||
.map_err(|e| format!("error retrieving api error: {}", e))?
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn list_plans(&self) -> Result<Vec<String>, String> {
|
||||
let url = String::from("plans");
|
||||
let res: types::YnabResponse<types::YnabPlanList> = serde_json::from_str(
|
||||
&self
|
||||
.get(&url)
|
||||
.map_err(|e| format!("request error: {}", e))?,
|
||||
)
|
||||
.map_err(|e| format!("parse error: {}", e))?;
|
||||
Ok(res.data.plans.into_iter().map(|p| p.name).collect())
|
||||
}
|
||||
|
||||
pub fn list_accounts(&self, plan: Lookup) -> Result<Vec<String>, String> {
|
||||
let plan_id = self.resolve_plan(plan)?;
|
||||
let url = format!("plans/{}/accounts", plan_id);
|
||||
let res: types::YnabResponse<types::YnabAccountList> = serde_json::from_str(
|
||||
&self
|
||||
.get(&url)
|
||||
.map_err(|e| format!("request error: {}", e))?,
|
||||
)
|
||||
.map_err(|e| format!("parse error: {}", e))?;
|
||||
Ok(res.data.accounts.into_iter().map(|p| p.name).collect())
|
||||
}
|
||||
|
||||
pub fn upload(
|
||||
&self,
|
||||
transactions: &[Transaction],
|
||||
plan: Lookup,
|
||||
account: Lookup,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let plan_id = self.resolve_plan(plan)?;
|
||||
let account_id = self.resolve_account(&plan_id, account)?;
|
||||
let request = format!("plans/{}/transactions", plan_id);
|
||||
let body = serde_json::to_string(&types::YnabTransactionList {
|
||||
transactions: transform::ynab_transactions(transactions, &account_id),
|
||||
})
|
||||
.map_err(|e| format!("transaction format error: {}", e))?;
|
||||
println!("{}", body);
|
||||
self.post(&request, &body)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user