aboutsummaryrefslogtreecommitdiff
path: root/src/routers
diff options
context:
space:
mode:
authorTolmachev Igor <me@igorek.dev>2025-09-25 01:20:24 +0300
committerTolmachev Igor <me@igorek.dev>2025-09-25 01:20:24 +0300
commit15c744e995805a30700cb04c488cddbb3015316b (patch)
tree4f53cff607933cea64c60a59163113893b8e5362 /src/routers
parent5c63c56ba7104fe6b1d6d2fb520098019bb9b7fc (diff)
downloadqueue_server-15c744e995805a30700cb04c488cddbb3015316b.tar.gz
queue_server-15c744e995805a30700cb04c488cddbb3015316b.zip
Add basic queue CRUD
Diffstat (limited to 'src/routers')
-rw-r--r--src/routers/mod.rs5
-rw-r--r--src/routers/queue.rs224
2 files changed, 228 insertions, 1 deletions
diff --git a/src/routers/mod.rs b/src/routers/mod.rs
index 80f9e74..c73e1f8 100644
--- a/src/routers/mod.rs
+++ b/src/routers/mod.rs
@@ -1,4 +1,5 @@
1mod account; 1mod account;
2mod queue;
2 3
3use utoipa::OpenApi; 4use utoipa::OpenApi;
4use utoipa_axum::router::OpenApiRouter; 5use utoipa_axum::router::OpenApiRouter;
@@ -6,5 +7,7 @@ use utoipa_axum::router::OpenApiRouter;
6use crate::{AppOpenApi, AppState}; 7use crate::{AppOpenApi, AppState};
7 8
8pub fn router() -> OpenApiRouter<AppState> { 9pub fn router() -> OpenApiRouter<AppState> {
9 OpenApiRouter::with_openapi(AppOpenApi::openapi()).nest("/account", account::router()) 10 OpenApiRouter::with_openapi(AppOpenApi::openapi())
11 .nest("/account", account::router())
12 .nest("/queue", queue::routes())
10} 13}
diff --git a/src/routers/queue.rs b/src/routers/queue.rs
new file mode 100644
index 0000000..1e93b2a
--- /dev/null
+++ b/src/routers/queue.rs
@@ -0,0 +1,224 @@
1use axum::extract::State;
2use entity::{queues, users};
3use sea_orm::{
4 ActiveModelTrait, ActiveValue::Set, ColumnTrait, DatabaseConnection, EntityTrait,
5 IntoActiveModel, ModelTrait, QueryFilter,
6};
7use serde::Deserialize;
8use utoipa::ToSchema;
9use utoipa_axum::{router::OpenApiRouter, routes};
10
11use crate::{
12 ApiError, ApiResult, AppState, ClientError, GlobalResponses, SuccessResponse,
13 extract::{ApiJson, Auth},
14 models::Queue,
15 tags::QUEUE,
16};
17
18async fn user_exists(id: i64, db: &DatabaseConnection) -> Result<bool, ApiError> {
19 Ok(users::Entity::find_by_id(id).one(db).await?.is_some())
20}
21
22async fn get_owned_queue(
23 id: i64,
24 owner_id: i64,
25 db: &DatabaseConnection,
26) -> Result<queues::Model, ApiError> {
27 Ok(queues::Entity::find_by_id(id)
28 .filter(queues::Column::OwnerId.eq(owner_id))
29 .one(db)
30 .await?
31 .ok_or(ClientError::QueueNotFound { id })?)
32}
33
34#[derive(Deserialize, ToSchema)]
35struct CreateQueueRequest {
36 #[schema(examples("John's queue", "Очередь Ивана"))]
37 name: String,
38}
39
40#[derive(Deserialize, ToSchema)]
41struct ChangeQueueNameRequest {
42 #[schema(examples(1))]
43 id: i64,
44 #[schema(examples("John's queue", "Очередь Ивана"))]
45 new_name: String,
46}
47
48#[derive(Deserialize, ToSchema)]
49struct ChangeQueueOwnerRequest {
50 #[schema(examples(1))]
51 id: i64,
52 #[schema(examples(1))]
53 new_owner_id: i64,
54}
55
56#[derive(Deserialize, ToSchema)]
57struct DeleteQueueRequest {
58 #[schema(examples(1))]
59 id: i64,
60}
61
62#[utoipa::path(
63 get,
64 path = "/owned",
65 tag = QUEUE,
66 summary = "Get owned",
67 description = "Get your own queues",
68 responses(
69 (
70 status = 200, body = SuccessResponse<Vec<Queue>>,
71 description = "Success response with your queues"
72 ),
73 GlobalResponses
74 ),
75 security(("auth" = [])),
76)]
77async fn owned(State(state): State<AppState>, Auth(user): Auth) -> ApiResult<Vec<Queue>> {
78 return Ok(SuccessResponse::ok(
79 queues::Entity::find()
80 .filter(queues::Column::OwnerId.eq(user.id))
81 .all(&state.db)
82 .await?
83 .into_iter()
84 .map(Into::into)
85 .collect(),
86 ));
87}
88
89#[utoipa::path(
90 post,
91 path = "/create",
92 tag = QUEUE,
93 summary = "Create",
94 description = "Create a new queue",
95 request_body = CreateQueueRequest,
96 responses(
97 (
98 status = 200, body = SuccessResponse<Queue>,
99 description = "Success response with created queue"
100 ),
101 GlobalResponses
102 ),
103 security(("auth" = [])),
104)]
105async fn create(
106 State(state): State<AppState>,
107 Auth(user): Auth,
108 ApiJson(req): ApiJson<CreateQueueRequest>,
109) -> ApiResult<Queue> {
110 Ok(SuccessResponse::ok(
111 queues::ActiveModel {
112 owner_id: Set(user.id),
113 name: Set(req.name),
114 ..Default::default()
115 }
116 .insert(&state.db)
117 .await?
118 .into(),
119 ))
120}
121
122#[utoipa::path(
123 put,
124 path = "/change/name",
125 tag = QUEUE,
126 summary = "Change name",
127 description = "Change queue name",
128 request_body = ChangeQueueNameRequest,
129 responses(
130 (
131 status = 200, body = SuccessResponse<Queue>,
132 description = "Success response with changed queue data"
133 ),
134 GlobalResponses
135 ),
136 security(("auth" = [])),
137)]
138async fn change_name(
139 State(state): State<AppState>,
140 Auth(user): Auth,
141 ApiJson(req): ApiJson<ChangeQueueNameRequest>,
142) -> ApiResult<Queue> {
143 let mut active_queue = get_owned_queue(req.id, user.id, &state.db)
144 .await?
145 .into_active_model();
146
147 active_queue.name = Set(req.new_name);
148
149 let queue = active_queue.update(&state.db).await?;
150 Ok(SuccessResponse::ok(queue.into()))
151}
152
153#[utoipa::path(
154 put,
155 path = "/change/owner",
156 tag = QUEUE,
157 summary = "Change owner",
158 description = "Transfer ownership of the queue",
159 request_body = ChangeQueueOwnerRequest,
160 responses(
161 (
162 status = 200, body = SuccessResponse<Queue>,
163 description = "Success response with changed queue data"
164 ),
165 GlobalResponses
166 ),
167 security(("auth" = [])),
168)]
169async fn change_owner(
170 State(state): State<AppState>,
171 Auth(user): Auth,
172 ApiJson(req): ApiJson<ChangeQueueOwnerRequest>,
173) -> ApiResult<Queue> {
174 if !user_exists(req.new_owner_id, &state.db).await? {
175 return Err(ClientError::UserNotFound {
176 id: req.new_owner_id,
177 }
178 .into());
179 }
180
181 let mut active_queue = get_owned_queue(req.id, user.id, &state.db)
182 .await?
183 .into_active_model();
184
185 active_queue.owner_id = Set(req.new_owner_id);
186
187 let queue = active_queue.update(&state.db).await?;
188 Ok(SuccessResponse::ok(queue.into()))
189}
190
191#[utoipa::path(
192 delete,
193 path = "/delete",
194 tag = QUEUE,
195 summary = "Delete",
196 description = "Delete queue",
197 request_body = DeleteQueueRequest,
198 responses(
199 (
200 status = 200, body = SuccessResponse<Queue>,
201 description = "Success response with deleted queue data"
202 ),
203 GlobalResponses
204 ),
205 security(("auth" = [])),
206)]
207async fn delete(
208 State(state): State<AppState>,
209 Auth(user): Auth,
210 ApiJson(req): ApiJson<DeleteQueueRequest>,
211) -> ApiResult<Queue> {
212 let queue = get_owned_queue(req.id, user.id, &state.db).await?;
213 queue.clone().delete(&state.db).await?;
214 Ok(SuccessResponse::ok(queue.into()))
215}
216
217pub fn routes() -> OpenApiRouter<AppState> {
218 OpenApiRouter::new()
219 .routes(routes!(owned))
220 .routes(routes!(create))
221 .routes(routes!(change_name))
222 .routes(routes!(change_owner))
223 .routes(routes!(delete))
224}