use axum::extract::State; use entity::{queues, users}; use sea_orm::{ ActiveModelTrait, ActiveValue::Set, ColumnTrait, DatabaseConnection, EntityTrait, IntoActiveModel, ModelTrait, QueryFilter, }; use serde::Deserialize; use utoipa::ToSchema; use utoipa_axum::{router::OpenApiRouter, routes}; use crate::{ ApiError, ApiResult, AppState, ClientError, GlobalResponses, SuccessResponse, extract::{ApiJson, Auth}, models::Queue, tags::QUEUE, }; async fn user_exists(id: i64, db: &DatabaseConnection) -> Result { Ok(users::Entity::find_by_id(id).one(db).await?.is_some()) } async fn get_owned_queue( id: i64, owner_id: i64, db: &DatabaseConnection, ) -> Result { let queue = queues::Entity::find_by_id(id) .one(db) .await? .ok_or(ClientError::QueueNotFound { id })?; if queue.owner_id != owner_id { return Err(ClientError::NotQueueOwner { id: queue.id }.into()); } Ok(queue) } #[derive(Deserialize, ToSchema)] #[schema(description = "Body of the create queue request")] struct CreateQueueRequest { #[schema(examples("John's queue", "Очередь Ивана"))] name: String, } #[derive(Deserialize, ToSchema)] #[schema(description = "Body of the change queue name request")] struct ChangeQueueNameRequest { #[schema(examples(1))] id: i64, #[schema(examples("John's queue", "Очередь Ивана"))] new_name: String, } #[derive(Deserialize, ToSchema)] #[schema(description = "Body of the change queue ownership request")] struct ChangeQueueOwnershipRequest { #[schema(examples(1))] id: i64, #[schema(examples(1))] new_owner_id: i64, } #[derive(Deserialize, ToSchema)] #[schema(description = "Body of the delete queue request")] struct DeleteQueueRequest { #[schema(examples(1))] id: i64, } #[utoipa::path( get, path = "/owned", tag = QUEUE, summary = "Get owned", description = "Get your queues", responses( ( status = 200, body = SuccessResponse>, description = "Success response with your queues" ), GlobalResponses ), security(("auth" = [])), )] async fn owned(State(state): State, Auth(user): Auth) -> ApiResult> { return Ok(SuccessResponse::ok( queues::Entity::find() .filter(queues::Column::OwnerId.eq(user.id)) .all(&state.db) .await? .into_iter() .map(Into::into) .collect(), )); } #[utoipa::path( post, path = "/create", tag = QUEUE, summary = "Create", description = "Create a new queue", request_body = CreateQueueRequest, responses( ( status = 200, body = SuccessResponse, description = "Success response with the created queue" ), GlobalResponses ), security(("auth" = [])), )] async fn create( State(state): State, Auth(user): Auth, ApiJson(req): ApiJson, ) -> ApiResult { Ok(SuccessResponse::ok( queues::ActiveModel { owner_id: Set(user.id), name: Set(req.name), ..Default::default() } .insert(&state.db) .await? .into(), )) } #[utoipa::path( put, path = "/update/name", tag = QUEUE, summary = "Change name", description = "Change queue name", request_body = ChangeQueueNameRequest, responses( ( status = 200, body = SuccessResponse, description = "Success response with the changed queue data" ), GlobalResponses ), security(("auth" = [])), )] async fn update_name( State(state): State, Auth(user): Auth, ApiJson(req): ApiJson, ) -> ApiResult { let mut active_queue = get_owned_queue(req.id, user.id, &state.db) .await? .into_active_model(); active_queue.name = Set(req.new_name); let queue = active_queue.update(&state.db).await?; Ok(SuccessResponse::ok(queue.into())) } #[utoipa::path( put, path = "/update/owner", tag = QUEUE, summary = "Change owner", description = "Reassign queue ownership", request_body = ChangeQueueOwnershipRequest, responses( ( status = 200, body = SuccessResponse, description = "Success response with the changed queue data" ), GlobalResponses ), security(("auth" = [])), )] async fn update_owner( State(state): State, Auth(user): Auth, ApiJson(req): ApiJson, ) -> ApiResult { if !user_exists(req.new_owner_id, &state.db).await? { return Err(ClientError::UserNotFound { id: req.new_owner_id, } .into()); } let mut active_queue = get_owned_queue(req.id, user.id, &state.db) .await? .into_active_model(); active_queue.owner_id = Set(req.new_owner_id); let queue = active_queue.update(&state.db).await?; Ok(SuccessResponse::ok(queue.into())) } #[utoipa::path( delete, path = "/delete", tag = QUEUE, summary = "Delete", description = "Delete the queue", request_body = DeleteQueueRequest, responses( ( status = 200, body = SuccessResponse, description = "Success response with the deleted queue data" ), GlobalResponses ), security(("auth" = [])), )] async fn delete( State(state): State, Auth(user): Auth, ApiJson(req): ApiJson, ) -> ApiResult { let queue = get_owned_queue(req.id, user.id, &state.db).await?; queue.clone().delete(&state.db).await?; Ok(SuccessResponse::ok(queue.into())) } pub fn router() -> OpenApiRouter { OpenApiRouter::new() .routes(routes!(owned)) .routes(routes!(create)) .routes(routes!(update_name)) .routes(routes!(update_owner)) .routes(routes!(delete)) }