feat: implement device update POST route

episode-actions
Jef Roosens 2025-02-23 21:54:34 +01:00
parent d6fb4573d0
commit 4d37ddb780
No known key found for this signature in database
GPG Key ID: 21FD3D77D56BAF49
4 changed files with 133 additions and 8 deletions

View File

@ -18,8 +18,8 @@ on later, no guarantees.
* Suggestions API
- [ ] Retrieve Suggested Podcasts
* Device API
- [ ] Update Device Data
- [ ] List Devices
- [x] Update Device Data
- [-] List Devices
- [ ] Get Device Updates
* Subscriptions API
- [ ] Get Subscriptions of Device

View File

@ -1,7 +1,7 @@
pub mod models;
mod schema;
pub use models::device::{Device, NewDevice};
pub use models::device::{Device, DeviceType, NewDevice};
pub use models::session::Session;
pub use models::user::{NewUser, User};

View File

@ -51,6 +51,52 @@ impl Device {
.filter(devices::user_id.eq(user_id))
.get_results(&mut pool.get()?)?)
}
pub fn by_device_id(pool: &DbPool, user_id: i64, device_id: &str) -> DbResult<Option<Self>> {
Ok(devices::dsl::devices
.select(Self::as_select())
.filter(
devices::user_id
.eq(user_id)
.and(devices::device_id.eq(device_id)),
)
.get_result(&mut pool.get()?)
.optional()?)
}
pub fn update(&self, pool: &DbPool) -> DbResult<()> {
Ok(diesel::update(
devices::table.filter(
devices::user_id
.eq(self.user_id)
.and(devices::device_id.eq(&self.device_id)),
),
)
.set((
devices::caption.eq(&self.caption),
devices::type_.eq(&self.type_),
))
.execute(&mut pool.get()?)
.map(|_| ())?)
}
}
impl NewDevice {
pub fn new(user_id: i64, device_id: String, caption: String, type_: DeviceType) -> Self {
Self {
device_id,
user_id,
caption,
type_,
}
}
pub fn insert(self, pool: &DbPool) -> DbResult<Device> {
Ok(diesel::insert_into(devices::table)
.values(&self)
.returning(Device::as_returning())
.get_result(&mut pool.get()?)?)
}
}
impl fmt::Display for DeviceType {

View File

@ -1,10 +1,10 @@
use axum::{
extract::{Path, State},
middleware,
routing::get,
routing::{get, post},
Extension, Json, Router,
};
use serde::Serialize;
use serde::{Deserialize, Serialize};
use crate::{
db::{self, User},
@ -19,14 +19,49 @@ use super::auth::auth_middleware;
pub fn router(ctx: Context) -> Router<Context> {
Router::new()
.route("/{username}", get(get_devices))
.route("/{username}/{id}", post(post_device))
.layer(middleware::from_fn_with_state(ctx.clone(), auth_middleware))
}
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum DeviceType {
Desktop,
Laptop,
Mobile,
Server,
Other,
}
impl From<DeviceType> for db::DeviceType {
fn from(value: DeviceType) -> Self {
match value {
DeviceType::Desktop => Self::Desktop,
DeviceType::Laptop => Self::Laptop,
DeviceType::Mobile => Self::Mobile,
DeviceType::Server => Self::Server,
DeviceType::Other => Self::Other,
}
}
}
impl From<db::DeviceType> for DeviceType {
fn from(value: db::DeviceType) -> Self {
match value {
db::DeviceType::Desktop => Self::Desktop,
db::DeviceType::Laptop => Self::Laptop,
db::DeviceType::Mobile => Self::Mobile,
db::DeviceType::Server => Self::Server,
db::DeviceType::Other => Self::Other,
}
}
}
#[derive(Serialize)]
pub struct Device {
id: String,
caption: String,
r#type: String,
r#type: DeviceType,
subscriptions: i64,
}
@ -50,12 +85,56 @@ async fn get_devices(
.map(|d| Device {
id: d.device_id,
caption: d.caption,
r#type: d.type_.to_string(),
r#type: d.type_.into(),
// TODO implement subscription count
subscriptions: 0,
})
.collect();
Ok(Json(devices))
// let devices: Vec<Device> = devices.iter
}
#[derive(Deserialize)]
pub struct DevicePatch {
caption: Option<String>,
r#type: Option<DeviceType>,
}
async fn post_device(
State(ctx): State<Context>,
Path((_username, id)): Path<(String, String)>,
Extension(user): Extension<User>,
Json(patch): Json<DevicePatch>,
) -> AppResult<()> {
let id = id
.strip_suffix(".json")
.ok_or(AppError::NotFound)?
.to_string();
tokio::task::spawn_blocking(move || {
if let Some(mut device) = db::Device::by_device_id(&ctx.pool, user.id, &id)? {
if let Some(caption) = patch.caption {
device.caption = caption;
}
if let Some(type_) = patch.r#type {
device.type_ = type_.into();
}
device.update(&ctx.pool)
} else {
db::NewDevice::new(
user.id,
id.to_string(),
patch.caption.unwrap_or(String::new()),
patch.r#type.unwrap_or(DeviceType::Other).into(),
)
.insert(&ctx.pool)
.map(|_| ())
}
})
.await
.unwrap()?;
Ok(())
}