use axum::extract::State; use entity::queues; use sea_orm::{ ActiveModelTrait, ActiveValue::Set, ColumnTrait, EntityTrait, IntoActiveModel, ModelTrait, QueryFilter, }; use serde::Deserialize; use utoipa::{IntoParams, ToSchema}; use utoipa_axum::{router::OpenApiRouter, routes}; use crate::{ ApiResult, AppState, ClientError, GlobalResponses, SuccessResponse, extract::{ApiJson, ApiQuery, Auth}, models::Queue, tags::QUEUE, util::{get_owned_queue, user_exists}, }; #[derive(Deserialize, IntoParams)] #[into_params(parameter_in = Query)] struct GetQueueByIdQuery { #[param(example = 1)] id: i64, } #[derive(Deserialize, IntoParams)] #[into_params(parameter_in = Query)] struct GetByOwnerIdQuery { #[param(example = 1)] owner_id: i64, } #[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 = "/get/by_id", tag = QUEUE, summary = "Get by id", description = "Get the queue by id", params(GetQueueByIdQuery), responses( ( status = 200, body = SuccessResponse>, description = "Success response with the requested queue" ), GlobalResponses ), )] async fn get_by_id( State(state): State, ApiQuery(req): ApiQuery, ) -> ApiResult> { Ok(SuccessResponse::ok( queues::Entity::find_by_id(req.id) .one(&state.db) .await? .map(Into::into), )) } #[utoipa::path( get, path = "/get/by_owner", tag = QUEUE, summary = "Get by owner", description = "Get queues by the owner id", params(GetByOwnerIdQuery), responses( ( status = 200, body = SuccessResponse>, description = "Success response with queues owned by the given user" ), GlobalResponses ), )] async fn get_by_owner( State(state): State, ApiQuery(req): ApiQuery, ) -> ApiResult> { Ok(SuccessResponse::ok( queues::Entity::find() .filter(queues::Column::OwnerId.eq(req.owner_id)) .all(&state.db) .await? .into_iter() .map(Into::into) .collect(), )) } #[utoipa::path( get, path = "/get/owned", tag = QUEUE, summary = "Get owned", description = "Get your queues", responses( ( status = 200, body = SuccessResponse>, description = "Success response with queues owned by you" ), GlobalResponses ), )] async fn get_owned(State(state): State, Auth(user): Auth) -> ApiResult> { Ok(SuccessResponse::ok( user.find_related(queues::Entity) .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( patch, 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( patch, 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!(get_by_id)) .routes(routes!(get_by_owner)) .routes(routes!(get_owned)) .routes(routes!(create)) .routes(routes!(update_name)) .routes(routes!(update_owner)) .routes(routes!(delete)) }