use axum::extract::State; use chrono::{DateTime, Utc}; use entity::invite_tokens; use sea_orm::{ActiveModelTrait, ActiveValue::Set, IntoActiveModel, ModelTrait}; use serde::Deserialize; use utoipa::{IntoParams, ToSchema}; use utoipa_axum::{router::OpenApiRouter, routes}; use crate::{ ApiResult, AppState, GlobalResponses, SuccessResponse, extract::{ApiJson, ApiQuery, Auth}, models::InviteToken, tags::INVITE_TOKEN, util::{get_owned_invite_token, get_owned_queue}, }; #[derive(Deserialize, IntoParams)] #[into_params(parameter_in = Query)] struct GetInviteTokenByIdQuery { #[param(example = 1)] id: i64, } #[derive(Deserialize, IntoParams)] #[into_params(parameter_in = Query)] struct GetInviteTokenByQueueIdQuery { #[param(example = 1)] queue_id: i64, } #[derive(Deserialize, ToSchema)] #[schema(description = "Body of the create invite token request")] struct CreateInviteTokenRequest { #[schema(examples(1))] queue_id: i64, #[schema(examples("For classmates", "Для однокурсников"))] name: String, expiration_date: Option>, } #[derive(Deserialize, ToSchema)] #[schema(description = "Body of the expire invite token request")] struct ExpireInviteTokenRequest { #[schema(examples(1))] id: i64, } #[derive(Deserialize, ToSchema)] #[schema(description = "Body of the change invite token expiration date request")] struct ChangeInviteTokenExpirationDateRequest { #[schema(examples(1))] id: i64, #[schema(examples("2000-01-01 00:00:00Z", "2000-01-01 03:00:00+03:00", json!(null)))] expiration_date: Option>, } #[derive(Deserialize, ToSchema)] #[schema(description = "Body of the delete invite token request")] struct DeleteInviteTokenRequest { #[schema(examples(1))] id: i64, } #[utoipa::path( get, path = "/get/by_id", tag = INVITE_TOKEN, summary = "Get by id", description = "Get the invite token by id", params(GetInviteTokenByIdQuery), responses( ( status = 200, body = SuccessResponse, description = "Success response with the requested invite token" ), GlobalResponses ), security(("auth" = [])), )] async fn get_by_id( State(state): State, Auth(user): Auth, ApiQuery(req): ApiQuery, ) -> ApiResult { Ok(SuccessResponse::ok( get_owned_invite_token(req.id, user.id, &state.db) .await? .into(), )) } #[utoipa::path( get, path = "/get/by_queue_id", tag = INVITE_TOKEN, summary = "Get by queue id", description = "Get the invite token by the queue id", params(GetInviteTokenByQueueIdQuery), responses( ( status = 200, body = SuccessResponse>, description = "Success response with the requested invite tokens" ), GlobalResponses ), security(("auth" = [])), )] async fn get_by_queue_id( State(state): State, Auth(user): Auth, ApiQuery(req): ApiQuery, ) -> ApiResult> { let queue = get_owned_queue(req.queue_id, user.id, &state.db).await?; Ok(SuccessResponse::ok( queue .find_related(invite_tokens::Entity) .all(&state.db) .await? .into_iter() .map(Into::into) .collect(), )) } #[utoipa::path( post, path = "/create", tag = INVITE_TOKEN, summary = "Create", description = "Create a new invite token", request_body = CreateInviteTokenRequest, responses( ( status = 200, body = SuccessResponse, description = "Success response with the created invite token" ), GlobalResponses ), security(("auth" = [])), )] async fn create( State(state): State, Auth(user): Auth, ApiJson(req): ApiJson, ) -> ApiResult { let queue = get_owned_queue(req.queue_id, user.id, &state.db).await?; Ok(SuccessResponse::ok( invite_tokens::ActiveModel { token: Set(uuid::Uuid::new_v4()), queue_id: Set(queue.id), name: Set(req.name), expiration_date: Set(req.expiration_date.as_ref().map(DateTime::naive_utc)), ..Default::default() } .insert(&state.db) .await? .into(), )) } #[utoipa::path( patch, path = "/expire", tag = INVITE_TOKEN, summary = "Expire", description = "Expire the invite token", request_body = ExpireInviteTokenRequest, responses( ( status = 200, body = SuccessResponse, description = "Success response with the changed invite token data" ), GlobalResponses ), security(("auth" = [])), )] async fn expire( State(state): State, Auth(user): Auth, ApiJson(req): ApiJson, ) -> ApiResult { let mut active_invite_token = get_owned_invite_token(req.id, user.id, &state.db) .await? .into_active_model(); active_invite_token.expiration_date = Set(Some(Utc::now().naive_utc())); let invite_token = active_invite_token.update(&state.db).await?; Ok(SuccessResponse::ok(invite_token.into())) } #[utoipa::path( patch, path = "/update/expiration_date", tag = INVITE_TOKEN, summary = "Change expiration date", description = "Change invite token expiration date", request_body = ChangeInviteTokenExpirationDateRequest, responses( ( status = 200, body = SuccessResponse, description = "Success response with the changed invite token data" ), GlobalResponses ), security(("auth" = [])), )] async fn update_expiration_date( State(state): State, Auth(user): Auth, ApiJson(req): ApiJson, ) -> ApiResult { let mut active_invite_token = get_owned_invite_token(req.id, user.id, &state.db) .await? .into_active_model(); active_invite_token.expiration_date = Set(req.expiration_date.as_ref().map(DateTime::naive_utc)); let invite_token = active_invite_token.update(&state.db).await?; Ok(SuccessResponse::ok(invite_token.into())) } #[utoipa::path( delete, path = "/delete", tag = INVITE_TOKEN, summary = "Delete", description = "Delete the invite token", request_body = DeleteInviteTokenRequest, responses( ( status = 200, body = SuccessResponse, description = "Success response with the deleted invite token data" ), GlobalResponses ), security(("auth" = [])), )] async fn delete( State(state): State, Auth(user): Auth, ApiJson(req): ApiJson, ) -> ApiResult { let invite_token = get_owned_invite_token(req.id, user.id, &state.db).await?; invite_token.clone().delete(&state.db).await?; Ok(SuccessResponse::ok(invite_token.into())) } pub fn router() -> OpenApiRouter { OpenApiRouter::new() .routes(routes!(get_by_id)) .routes(routes!(get_by_queue_id)) .routes(routes!(create)) .routes(routes!(expire)) .routes(routes!(update_expiration_date)) .routes(routes!(delete)) }