Initial implementation
This commit is contained in:
133
src/devices.rs
Normal file
133
src/devices.rs
Normal file
@@ -0,0 +1,133 @@
|
||||
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]
|
||||
}
|
||||
Reference in New Issue
Block a user