Files
gpodder-rs/src/subscriptions.rs

138 lines
3.8 KiB
Rust

use crate::{Db, SqlError, Timestamp, auth::BasicAuth};
use chrono::Utc;
use rocket::{
Route, get, post, put, routes,
serde::{Deserialize, Serialize, json::Json},
trace::debug,
};
use rocket_db_pools::Connection;
use sqlx::{Acquire, Execute};
#[put("/subscriptions/<_user>/<device>")]
pub fn set(_user: &str, device: &str, auth: BasicAuth) -> &'static str {
debug!("Attempting to set {}/{device}", auth.username());
""
}
#[get("/subscriptions/<_user>/<device>.opml")]
pub fn list_opml(_user: &str, device: &str, auth: BasicAuth) -> &'static str {
debug!("Attempting to list {}/{device}", auth.username());
""
}
#[derive(Debug, Serialize, Deserialize)]
#[serde(crate = "rocket::serde")]
pub struct Subscriptions {
add: Vec<String>,
remove: Vec<String>,
timestamp: i64,
}
#[get("/subscriptions/<_user>/<device>.json?<since>")]
pub async fn list_json(
_user: &str,
device: &str,
since: Option<i64>,
mut db: Connection<Db>,
auth: BasicAuth,
) -> Result<Json<Subscriptions>, SqlError> {
debug!(
"Attempting to list {}/{device}, since {since:?}",
auth.username()
);
let time = Utc::now().timestamp();
let username = auth.username();
let since = since.unwrap_or(0);
let results = sqlx::query!(
"SELECT * FROM subscriptions WHERE device = ? AND user = ? AND updated >= ?",
device,
username,
since,
)
.fetch_all(&mut **db)
.await?;
let mut res = Subscriptions {
add: vec![],
remove: vec![],
timestamp: time,
};
for record in results {
if record.current == 1 {
res.add.push(record.url);
} else if record.current == 0 {
res.remove.push(record.url);
} else {
debug!("Found current value of `{}`", record.current);
}
}
Ok(Json(res))
}
#[derive(Debug, Serialize, Deserialize)]
#[serde(crate = "rocket::serde")]
pub struct SubscriptionChanges {
add: Vec<String>,
remove: Vec<String>,
}
#[derive(Debug, Serialize, Deserialize)]
#[serde(crate = "rocket::serde")]
pub struct SubscriptionChangesResult {
pub update_urls: Vec<(String, String)>,
pub timestamp: i64,
}
#[post("/subscriptions/<_user>/<device>.json", data = "<updates>")]
pub async fn update_json(
_user: &str,
device: &str,
updates: Json<SubscriptionChanges>,
mut db: Connection<Db>,
auth: BasicAuth,
) -> Result<Json<SubscriptionChangesResult>, SqlError> {
let time = Utc::now().timestamp();
let updates = updates.into_inner();
debug!(
"Attempting to update {}/{device}, new: {:?}",
auth.username(),
updates
);
let mut trans = db.begin().await?;
for removed in &updates.remove {
sqlx::query("INSERT INTO subscriptions (url, device, user, current, updated) VALUES (?, ?, ?, ?, ?)")
.bind(removed)
.bind(device)
.bind(auth.username())
.bind(0)
.bind(time)
.execute(&mut *trans)
.await?;
}
for added in &updates.add {
sqlx::query("INSERT INTO subscriptions (url, device, user, current, updated) VALUES (?, ?, ?, ?, ?)")
.bind(added)
.bind(device)
.bind(auth.username())
.bind(1)
.bind(time)
.execute(&mut *trans)
.await?;
}
trans.commit().await?;
// sqlx::qu
Ok(Json(SubscriptionChangesResult {
update_urls: vec![],
timestamp: time,
}))
}
#[get("/subscriptions/<_user>.json")]
pub fn list_all_json(_user: &str, auth: BasicAuth) -> Json<Vec<String>> {
debug!("Attempting to list {}", auth.username());
Json(vec![])
}
pub fn routes() -> Vec<Route> {
routes![set, list_json, list_opml, list_all_json, update_json]
}