134 lines
3.3 KiB
Rust
134 lines
3.3 KiB
Rust
use std::borrow::Cow;
|
|
|
|
use crate::{
|
|
Db, DotJson, SqlError, Timestamp,
|
|
auth::BasicAuth,
|
|
directory::{Episode, Podcast},
|
|
};
|
|
use rocket::{
|
|
Route, TypedError, get, post, routes,
|
|
serde::{Deserialize, Serialize, json::Json},
|
|
trace::debug,
|
|
};
|
|
use rocket_db_pools::{
|
|
Connection,
|
|
sqlx::{self, Connection as _},
|
|
};
|
|
|
|
#[derive(Debug, Serialize, Deserialize)]
|
|
#[serde(crate = "rocket::serde")]
|
|
pub struct Device {
|
|
id: String,
|
|
caption: String,
|
|
r#type: String,
|
|
// subscriptions: usize,
|
|
}
|
|
|
|
#[get("/devices/<_user>.json")]
|
|
pub async fn get(
|
|
_user: &str,
|
|
auth: BasicAuth,
|
|
mut db: Connection<Db>,
|
|
) -> Result<Json<Vec<Device>>, SqlError> {
|
|
let username = auth.username();
|
|
debug!("Attempting to get devices for {username}");
|
|
let res: Vec<Device> = sqlx::query_as!(
|
|
Device,
|
|
"SELECT id, caption, type FROM devices WHERE user = ?",
|
|
username
|
|
)
|
|
.fetch_all(&mut **db)
|
|
.await?;
|
|
Ok(Json(res))
|
|
// todo!()
|
|
}
|
|
|
|
#[derive(Debug, Serialize, Deserialize)]
|
|
#[serde(crate = "rocket::serde")]
|
|
pub struct DeviceUpdate<'a> {
|
|
caption: Option<&'a str>,
|
|
r#type: Option<&'a str>,
|
|
}
|
|
|
|
#[post("/devices/<_user>/<device>.json", data = "<dev>")]
|
|
pub async fn update(
|
|
_user: &str,
|
|
device: &str,
|
|
dev: Json<DeviceUpdate<'_>>,
|
|
mut db: Connection<Db>,
|
|
auth: BasicAuth,
|
|
) -> Result<Json<Device>, SqlError> {
|
|
let username = auth.username();
|
|
debug!("Attempting to update {device} for {username}");
|
|
let mut trans = db.begin().await?;
|
|
let existing = sqlx::query_as!(
|
|
Device,
|
|
"SELECT id, caption, type FROM devices WHERE user = ? AND id = ?",
|
|
username,
|
|
device
|
|
)
|
|
.fetch_optional(&mut *trans)
|
|
.await?;
|
|
|
|
// debug!("Users: {:?}", sqlx::query!("SELECT * FROM users").fetch_all(&mut **db).await);
|
|
let res = sqlx::query("INSERT INTO devices (id, user, caption, type) VALUES (?, ?, ?, ?)")
|
|
.bind(device)
|
|
.bind(username)
|
|
.bind(
|
|
dev.caption
|
|
.or(existing.as_ref().map(|d| d.caption.as_str()))
|
|
.unwrap_or(""),
|
|
)
|
|
.bind(
|
|
dev.r#type
|
|
.or(existing.as_ref().map(|d| d.r#type.as_str()))
|
|
.unwrap_or(""),
|
|
)
|
|
.execute(&mut *trans)
|
|
.await?;
|
|
debug!(
|
|
"Attempting to update {} for {username}, {dev:?}, {res:?}",
|
|
device
|
|
);
|
|
let res = sqlx::query_as!(
|
|
Device,
|
|
"SELECT id, caption, type FROM devices WHERE user = ? AND id = ?",
|
|
username,
|
|
device
|
|
)
|
|
.fetch_one(&mut *trans)
|
|
.await?;
|
|
trans.commit().await?;
|
|
Ok(Json(res))
|
|
}
|
|
|
|
#[derive(Debug, Serialize, Deserialize)]
|
|
#[serde(crate = "rocket::serde")]
|
|
pub struct DeviceUpdates<'a> {
|
|
add: Vec<Podcast<'a>>,
|
|
remove: Vec<Cow<'a, str>>,
|
|
updates: Vec<Episode<'a>>,
|
|
timestamp: Timestamp,
|
|
}
|
|
|
|
#[get("/updates/<username>/<device>?<since>&<include_actions>")]
|
|
pub fn updates(
|
|
username: &str,
|
|
device: DotJson<&str>,
|
|
since: Option<Timestamp>,
|
|
include_actions: Option<bool>,
|
|
_auth: BasicAuth,
|
|
) -> Json<DeviceUpdates<'static>> {
|
|
debug!("Attempting to update {} for {username}, {since:?}", *device);
|
|
Json(DeviceUpdates {
|
|
add: vec![],
|
|
remove: vec![],
|
|
updates: vec![],
|
|
timestamp: Timestamp::now(),
|
|
})
|
|
}
|
|
|
|
pub fn routes() -> Vec<Route> {
|
|
routes![get, update, updates]
|
|
}
|