use db::conn::sea_orm::{ ActiveModelTrait, EntityTrait, QueryFilter, QueryOrder, Set, }; use uuid::Uuid; use crate::error::{UserError, UserResult}; use crate::features::UserService; use super::types::{DeviceView, UpdateDeviceCmd}; const MAX_DEVICE_NAME: usize = 128; pub async fn list(svc: &UserService, caller: Uuid) -> UserResult> { let db = svc.db.reader(); let rows = db::user::user_devices::Entity::find() .filter(db::user::user_devices::COLUMN.user_id.eq(caller)) .order_by_desc(db::user::user_devices::COLUMN.last_seen_at) .all(&db) .await?; Ok(rows.into_iter().map(DeviceView::from).collect()) } pub async fn update( svc: &UserService, caller: Uuid, device_id: Uuid, cmd: UpdateDeviceCmd, ) -> UserResult { if let Some(Some(ref name)) = cmd.device_name && (name.is_empty() || name.len() > MAX_DEVICE_NAME) { return Err(UserError::BadRequest(format!( "device_name length must be 1..={MAX_DEVICE_NAME}" ))); } let writer = svc.db.writer(); let row = db::user::user_devices::Entity::find_by_id(device_id) .one(&writer) .await? .ok_or_else(|| UserError::NotFound(format!("device {device_id}")))?; if row.user_id != caller { return Err(UserError::Forbidden("cannot modify other user's device".into())); } let mut active: db::user::user_devices::ActiveModel = row.into(); if let Some(v) = cmd.device_name { active.device_name = Set(v); } if let Some(v) = cmd.is_trusted { active.is_trusted = Set(v); } active.updated_at = Set(time::OffsetDateTime::now_utc()); let saved = active.update(&writer).await?; Ok(DeviceView::from(saved)) } pub async fn delete(svc: &UserService, caller: Uuid, device_id: Uuid) -> UserResult<()> { let writer = svc.db.writer(); let row = db::user::user_devices::Entity::find_by_id(device_id) .one(&writer) .await? .ok_or_else(|| UserError::NotFound(format!("device {device_id}")))?; if row.user_id != caller { return Err(UserError::Forbidden("cannot delete other user's device".into())); } db::user::user_devices::Entity::delete_by_id(device_id) .exec(&writer) .await?; Ok(()) } #[allow(dead_code)] fn _now_utc() -> time::OffsetDateTime { time::OffsetDateTime::now_utc() }