typespec-rust-emitter 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,712 @@
1
+ use super::types::*;
2
+ use async_trait::async_trait;
3
+ use axum::{http::StatusCode, Json};
4
+ use eyre::Result;
5
+
6
+ #[async_trait]
7
+ pub trait Server: Send + Sync {
8
+ type Claims: Send + Sync + 'static;
9
+
10
+
11
+ /// Retrieve a list of all groups for the current account (from view_learning_group).
12
+ async fn groups_list(&self, request: GroupsListRequest) -> Result<GroupsListResponse>;
13
+ /// Create a new group.
14
+ async fn groups_create(&self, claims: Self::Claims, request: GroupsCreateRequest) -> Result<GroupsCreateResponse>;
15
+ /// Get the details of a group by its ID.
16
+ async fn groups_get_by_id(&self, request: GroupsGetByIdRequest) -> Result<GroupsGetByIdResponse>;
17
+ /// Update a group. Only provide the fields that need to be changed.
18
+ async fn groups_update(&self, claims: Self::Claims, request: GroupsUpdateRequest) -> Result<GroupsUpdateResponse>;
19
+ /// Soft delete a group. All subjects within the group will also be soft deleted.
20
+ async fn groups_delete(&self, claims: Self::Claims, request: GroupsDeleteRequest) -> Result<GroupsDeleteResponse>;
21
+ /// Retrieve a list of subjects for a group (from view_subject_statistics).
22
+ async fn subjects_list(&self, request: SubjectsListRequest) -> Result<SubjectsListResponse>;
23
+ /// Create a new subject within the specified group.
24
+ async fn subjects_create(&self, claims: Self::Claims, request: SubjectsCreateRequest) -> Result<SubjectsCreateResponse>;
25
+ /// Get the details of a subject by its ID.
26
+ async fn subjects_get_by_id(&self, request: SubjectsGetByIdRequest) -> Result<SubjectsGetByIdResponse>;
27
+ /// Update a subject. Only provide the fields that need to be changed.
28
+ async fn subjects_update(&self, claims: Self::Claims, request: SubjectsUpdateRequest) -> Result<SubjectsUpdateResponse>;
29
+ /// Soft delete a subject.
30
+ async fn subjects_delete(&self, claims: Self::Claims, request: SubjectsDeleteRequest) -> Result<SubjectsDeleteResponse>;
31
+ /// Start a new study session for the subject.
32
+ /// The server creates a Log (status=Starting) and the first Timelog.
33
+ /// Returns 409 if the subject already has a session in Starting or Paused status.
34
+ async fn sessions_start(&self, claims: Self::Claims, request: SessionsStartRequest) -> Result<SessionsStartResponse>;
35
+ /// Pause the currently running session (transition from Starting to Paused).
36
+ /// The server closes the current Timelog (sets stoppedAt and calculates durationInSeconds).
37
+ /// Returns 409 if the session is not in the Starting state.
38
+ async fn sessions_pause(&self, claims: Self::Claims, request: SessionsPauseRequest) -> Result<SessionsPauseResponse>;
39
+ /// Resume a paused session (transition from Paused to Starting).
40
+ /// The server creates a new Timelog.
41
+ /// Returns 409 if the session is not in the Paused state.
42
+ async fn sessions_resume(&self, claims: Self::Claims, request: SessionsResumeRequest) -> Result<SessionsResumeResponse>;
43
+ /// End the session (transition from Starting or Paused to Stopped).
44
+ /// The server closes the current Timelog if it is running, and updates Log.stoppedAt.
45
+ /// Returns 409 if the session is already Stopped.
46
+ async fn sessions_stop(&self, claims: Self::Claims, request: SessionsStopRequest) -> Result<SessionsStopResponse>;
47
+ }
48
+ #[derive(Debug, Clone, serde::Deserialize)]
49
+ pub struct GroupsListRequest {
50
+
51
+ }
52
+
53
+ #[derive(Debug, Clone, serde::Deserialize)]
54
+ pub struct GroupsCreateRequest {
55
+ #[serde(rename = "body", flatten)]
56
+ pub body: CreateGroupBody,
57
+ }
58
+
59
+ #[derive(Debug, Clone, serde::Deserialize)]
60
+ pub struct GroupsGetByIdRequest {
61
+ #[serde(rename = "id", flatten)]
62
+ pub id: i64,
63
+ }
64
+
65
+ #[derive(Debug, Clone, serde::Deserialize)]
66
+ pub struct GroupsUpdateRequest {
67
+ #[serde(rename = "id", flatten)]
68
+ pub id: i64,
69
+ #[serde(rename = "body", flatten)]
70
+ pub body: UpdateGroupBody,
71
+ }
72
+
73
+ #[derive(Debug, Clone, serde::Deserialize)]
74
+ pub struct GroupsDeleteRequest {
75
+ #[serde(rename = "id", flatten)]
76
+ pub id: i64,
77
+ }
78
+
79
+ #[derive(Debug, Clone, serde::Deserialize)]
80
+ pub struct SubjectsListRequest {
81
+ #[serde(rename = "groupId", flatten)]
82
+ pub group_id: i64,
83
+ }
84
+
85
+ #[derive(Debug, Clone, serde::Deserialize)]
86
+ pub struct SubjectsCreateRequest {
87
+ #[serde(rename = "groupId", flatten)]
88
+ pub group_id: i64,
89
+ #[serde(rename = "body", flatten)]
90
+ pub body: CreateSubjectBody,
91
+ }
92
+
93
+ #[derive(Debug, Clone, serde::Deserialize)]
94
+ pub struct SubjectsGetByIdRequest {
95
+ #[serde(rename = "groupId", flatten)]
96
+ pub group_id: i64,
97
+ #[serde(rename = "id", flatten)]
98
+ pub id: i64,
99
+ }
100
+
101
+ #[derive(Debug, Clone, serde::Deserialize)]
102
+ pub struct SubjectsUpdateRequest {
103
+ #[serde(rename = "groupId", flatten)]
104
+ pub group_id: i64,
105
+ #[serde(rename = "id", flatten)]
106
+ pub id: i64,
107
+ #[serde(rename = "body", flatten)]
108
+ pub body: UpdateSubjectBody,
109
+ }
110
+
111
+ #[derive(Debug, Clone, serde::Deserialize)]
112
+ pub struct SubjectsDeleteRequest {
113
+ #[serde(rename = "groupId", flatten)]
114
+ pub group_id: i64,
115
+ #[serde(rename = "id", flatten)]
116
+ pub id: i64,
117
+ }
118
+
119
+ #[derive(Debug, Clone, serde::Deserialize)]
120
+ pub struct SessionsStartRequest {
121
+ #[serde(rename = "subjectId", flatten)]
122
+ pub subject_id: i64,
123
+ #[serde(rename = "body", flatten)]
124
+ pub body: SessionNoteBody,
125
+ }
126
+
127
+ #[derive(Debug, Clone, serde::Deserialize)]
128
+ pub struct SessionsPauseRequest {
129
+ #[serde(rename = "subjectId", flatten)]
130
+ pub subject_id: i64,
131
+ #[serde(rename = "logId", flatten)]
132
+ pub log_id: i64,
133
+ }
134
+
135
+ #[derive(Debug, Clone, serde::Deserialize)]
136
+ pub struct SessionsResumeRequest {
137
+ #[serde(rename = "subjectId", flatten)]
138
+ pub subject_id: i64,
139
+ #[serde(rename = "logId", flatten)]
140
+ pub log_id: i64,
141
+ }
142
+
143
+ #[derive(Debug, Clone, serde::Deserialize)]
144
+ pub struct SessionsStopRequest {
145
+ #[serde(rename = "subjectId", flatten)]
146
+ pub subject_id: i64,
147
+ #[serde(rename = "logId", flatten)]
148
+ pub log_id: i64,
149
+ #[serde(rename = "body", flatten)]
150
+ pub body: SessionNoteBody,
151
+ }
152
+
153
+ pub enum GroupsListResponse {
154
+ Ok(Json<Vec<GroupStatistics>>),
155
+ Unauthorized,
156
+ }
157
+
158
+ impl IntoResponse for GroupsListResponse {
159
+ fn into_response(self) -> axum::response::Response {
160
+ match self {
161
+
162
+ GroupsListResponse::Ok(body) => (StatusCode::OK, body).into_response(),
163
+ GroupsListResponse::Unauthorized => StatusCode::UNAUTHORIZED.into_response(),
164
+ }
165
+ }
166
+ }
167
+
168
+ pub enum GroupsCreateResponse {
169
+ Created(Json<Group>),
170
+ BadRequest,
171
+ Unauthorized,
172
+ }
173
+
174
+ impl IntoResponse for GroupsCreateResponse {
175
+ fn into_response(self) -> axum::response::Response {
176
+ match self {
177
+
178
+ GroupsCreateResponse::Created(body) => (StatusCode::CREATED, body).into_response(),
179
+ GroupsCreateResponse::BadRequest => StatusCode::BAD_REQUEST.into_response(),
180
+ GroupsCreateResponse::Unauthorized => StatusCode::UNAUTHORIZED.into_response(),
181
+ }
182
+ }
183
+ }
184
+
185
+ pub enum GroupsGetByIdResponse {
186
+ Ok(Json<GroupStatistics>),
187
+ Unauthorized,
188
+ NotFound,
189
+ }
190
+
191
+ impl IntoResponse for GroupsGetByIdResponse {
192
+ fn into_response(self) -> axum::response::Response {
193
+ match self {
194
+
195
+ GroupsGetByIdResponse::Ok(body) => (StatusCode::OK, body).into_response(),
196
+ GroupsGetByIdResponse::Unauthorized => StatusCode::UNAUTHORIZED.into_response(),
197
+ GroupsGetByIdResponse::NotFound => StatusCode::NOT_FOUND.into_response(),
198
+ }
199
+ }
200
+ }
201
+
202
+ pub enum GroupsUpdateResponse {
203
+ Ok(Json<Group>),
204
+ BadRequest,
205
+ Unauthorized,
206
+ NotFound,
207
+ }
208
+
209
+ impl IntoResponse for GroupsUpdateResponse {
210
+ fn into_response(self) -> axum::response::Response {
211
+ match self {
212
+
213
+ GroupsUpdateResponse::Ok(body) => (StatusCode::OK, body).into_response(),
214
+ GroupsUpdateResponse::BadRequest => StatusCode::BAD_REQUEST.into_response(),
215
+ GroupsUpdateResponse::Unauthorized => StatusCode::UNAUTHORIZED.into_response(),
216
+ GroupsUpdateResponse::NotFound => StatusCode::NOT_FOUND.into_response(),
217
+ }
218
+ }
219
+ }
220
+
221
+ pub enum GroupsDeleteResponse {
222
+ NoContent,
223
+ Unauthorized,
224
+ NotFound,
225
+ }
226
+
227
+ impl IntoResponse for GroupsDeleteResponse {
228
+ fn into_response(self) -> axum::response::Response {
229
+ match self {
230
+
231
+ GroupsDeleteResponse::NoContent => StatusCode::NO_CONTENT.into_response(),
232
+ GroupsDeleteResponse::Unauthorized => StatusCode::UNAUTHORIZED.into_response(),
233
+ GroupsDeleteResponse::NotFound => StatusCode::NOT_FOUND.into_response(),
234
+ }
235
+ }
236
+ }
237
+
238
+ pub enum SubjectsListResponse {
239
+ Ok(Json<Vec<SubjectStatistics>>),
240
+ Unauthorized,
241
+ NotFound,
242
+ }
243
+
244
+ impl IntoResponse for SubjectsListResponse {
245
+ fn into_response(self) -> axum::response::Response {
246
+ match self {
247
+
248
+ SubjectsListResponse::Ok(body) => (StatusCode::OK, body).into_response(),
249
+ SubjectsListResponse::Unauthorized => StatusCode::UNAUTHORIZED.into_response(),
250
+ SubjectsListResponse::NotFound => StatusCode::NOT_FOUND.into_response(),
251
+ }
252
+ }
253
+ }
254
+
255
+ pub enum SubjectsCreateResponse {
256
+ Created(Json<Subject>),
257
+ BadRequest,
258
+ Unauthorized,
259
+ NotFound,
260
+ }
261
+
262
+ impl IntoResponse for SubjectsCreateResponse {
263
+ fn into_response(self) -> axum::response::Response {
264
+ match self {
265
+
266
+ SubjectsCreateResponse::Created(body) => (StatusCode::CREATED, body).into_response(),
267
+ SubjectsCreateResponse::BadRequest => StatusCode::BAD_REQUEST.into_response(),
268
+ SubjectsCreateResponse::Unauthorized => StatusCode::UNAUTHORIZED.into_response(),
269
+ SubjectsCreateResponse::NotFound => StatusCode::NOT_FOUND.into_response(),
270
+ }
271
+ }
272
+ }
273
+
274
+ pub enum SubjectsGetByIdResponse {
275
+ Ok(Json<SubjectStatistics>),
276
+ Unauthorized,
277
+ NotFound,
278
+ }
279
+
280
+ impl IntoResponse for SubjectsGetByIdResponse {
281
+ fn into_response(self) -> axum::response::Response {
282
+ match self {
283
+
284
+ SubjectsGetByIdResponse::Ok(body) => (StatusCode::OK, body).into_response(),
285
+ SubjectsGetByIdResponse::Unauthorized => StatusCode::UNAUTHORIZED.into_response(),
286
+ SubjectsGetByIdResponse::NotFound => StatusCode::NOT_FOUND.into_response(),
287
+ }
288
+ }
289
+ }
290
+
291
+ pub enum SubjectsUpdateResponse {
292
+ Ok(Json<Subject>),
293
+ BadRequest,
294
+ Unauthorized,
295
+ NotFound,
296
+ }
297
+
298
+ impl IntoResponse for SubjectsUpdateResponse {
299
+ fn into_response(self) -> axum::response::Response {
300
+ match self {
301
+
302
+ SubjectsUpdateResponse::Ok(body) => (StatusCode::OK, body).into_response(),
303
+ SubjectsUpdateResponse::BadRequest => StatusCode::BAD_REQUEST.into_response(),
304
+ SubjectsUpdateResponse::Unauthorized => StatusCode::UNAUTHORIZED.into_response(),
305
+ SubjectsUpdateResponse::NotFound => StatusCode::NOT_FOUND.into_response(),
306
+ }
307
+ }
308
+ }
309
+
310
+ pub enum SubjectsDeleteResponse {
311
+ NoContent,
312
+ Unauthorized,
313
+ NotFound,
314
+ }
315
+
316
+ impl IntoResponse for SubjectsDeleteResponse {
317
+ fn into_response(self) -> axum::response::Response {
318
+ match self {
319
+
320
+ SubjectsDeleteResponse::NoContent => StatusCode::NO_CONTENT.into_response(),
321
+ SubjectsDeleteResponse::Unauthorized => StatusCode::UNAUTHORIZED.into_response(),
322
+ SubjectsDeleteResponse::NotFound => StatusCode::NOT_FOUND.into_response(),
323
+ }
324
+ }
325
+ }
326
+
327
+ pub enum SessionsStartResponse {
328
+ Created(Json<SessionOpenedResponse>),
329
+ Unauthorized,
330
+ NotFound,
331
+ Conflict,
332
+ }
333
+
334
+ impl IntoResponse for SessionsStartResponse {
335
+ fn into_response(self) -> axum::response::Response {
336
+ match self {
337
+
338
+ SessionsStartResponse::Created(body) => (StatusCode::CREATED, body).into_response(),
339
+ SessionsStartResponse::Unauthorized => StatusCode::UNAUTHORIZED.into_response(),
340
+ SessionsStartResponse::NotFound => StatusCode::NOT_FOUND.into_response(),
341
+ SessionsStartResponse::Conflict => StatusCode::CONFLICT.into_response(),
342
+ }
343
+ }
344
+ }
345
+
346
+ pub enum SessionsPauseResponse {
347
+ Ok(Json<SessionClosedResponse>),
348
+ Unauthorized,
349
+ NotFound,
350
+ Conflict,
351
+ }
352
+
353
+ impl IntoResponse for SessionsPauseResponse {
354
+ fn into_response(self) -> axum::response::Response {
355
+ match self {
356
+
357
+ SessionsPauseResponse::Ok(body) => (StatusCode::OK, body).into_response(),
358
+ SessionsPauseResponse::Unauthorized => StatusCode::UNAUTHORIZED.into_response(),
359
+ SessionsPauseResponse::NotFound => StatusCode::NOT_FOUND.into_response(),
360
+ SessionsPauseResponse::Conflict => StatusCode::CONFLICT.into_response(),
361
+ }
362
+ }
363
+ }
364
+
365
+ pub enum SessionsResumeResponse {
366
+ Ok(Json<SessionOpenedResponse>),
367
+ Unauthorized,
368
+ NotFound,
369
+ Conflict,
370
+ }
371
+
372
+ impl IntoResponse for SessionsResumeResponse {
373
+ fn into_response(self) -> axum::response::Response {
374
+ match self {
375
+
376
+ SessionsResumeResponse::Ok(body) => (StatusCode::OK, body).into_response(),
377
+ SessionsResumeResponse::Unauthorized => StatusCode::UNAUTHORIZED.into_response(),
378
+ SessionsResumeResponse::NotFound => StatusCode::NOT_FOUND.into_response(),
379
+ SessionsResumeResponse::Conflict => StatusCode::CONFLICT.into_response(),
380
+ }
381
+ }
382
+ }
383
+
384
+ pub enum SessionsStopResponse {
385
+ Ok(Json<SessionClosedResponse>),
386
+ Unauthorized,
387
+ NotFound,
388
+ Conflict,
389
+ }
390
+
391
+ impl IntoResponse for SessionsStopResponse {
392
+ fn into_response(self) -> axum::response::Response {
393
+ match self {
394
+
395
+ SessionsStopResponse::Ok(body) => (StatusCode::OK, body).into_response(),
396
+ SessionsStopResponse::Unauthorized => StatusCode::UNAUTHORIZED.into_response(),
397
+ SessionsStopResponse::NotFound => StatusCode::NOT_FOUND.into_response(),
398
+ SessionsStopResponse::Conflict => StatusCode::CONFLICT.into_response(),
399
+ }
400
+ }
401
+ }
402
+
403
+ use axum::response::IntoResponse;
404
+ use axum::routing::{delete, get, patch, post};
405
+ use axum::Router;
406
+
407
+
408
+ pub async fn groups_list_handler<S>(
409
+ axum::extract::State(service): axum::extract::State<S>,
410
+
411
+ ) -> impl axum::response::IntoResponse
412
+ where
413
+ S: Server + Clone + Send + Sync + 'static,
414
+ S::Claims: Send + Sync + Clone + 'static,
415
+ {
416
+ let result = service.groups_list(GroupsListRequest {}).await;
417
+ match result {
418
+ Ok(response) => response.into_response(),
419
+ Err(e) => (
420
+ axum::http::StatusCode::INTERNAL_SERVER_ERROR,
421
+ format!("Internal error: {e}"),
422
+ )
423
+ .into_response(),
424
+ }
425
+ }
426
+
427
+ pub async fn groups_create_handler<S>(
428
+ axum::extract::State(service): axum::extract::State<S>,
429
+ axum::extract::Query(query): axum::extract::Query<GroupsCreateRequest>,
430
+ axum::Extension(claims): axum::Extension<S::Claims>,
431
+ ) -> impl axum::response::IntoResponse
432
+ where
433
+ S: Server + Clone + Send + Sync + 'static,
434
+ S::Claims: Send + Sync + Clone + 'static,
435
+ {
436
+ let result = service.groups_create(claims, query).await;
437
+ match result {
438
+ Ok(response) => response.into_response(),
439
+ Err(e) => (
440
+ axum::http::StatusCode::INTERNAL_SERVER_ERROR,
441
+ format!("Internal error: {e}"),
442
+ )
443
+ .into_response(),
444
+ }
445
+ }
446
+
447
+ pub async fn groups_get_by_id_handler<S>(
448
+ axum::extract::State(service): axum::extract::State<S>,
449
+ axum::extract::Query(query): axum::extract::Query<GroupsGetByIdRequest>,
450
+ ) -> impl axum::response::IntoResponse
451
+ where
452
+ S: Server + Clone + Send + Sync + 'static,
453
+ S::Claims: Send + Sync + Clone + 'static,
454
+ {
455
+ let result = service.groups_get_by_id(query).await;
456
+ match result {
457
+ Ok(response) => response.into_response(),
458
+ Err(e) => (
459
+ axum::http::StatusCode::INTERNAL_SERVER_ERROR,
460
+ format!("Internal error: {e}"),
461
+ )
462
+ .into_response(),
463
+ }
464
+ }
465
+
466
+ pub async fn groups_update_handler<S>(
467
+ axum::extract::State(service): axum::extract::State<S>,
468
+ axum::extract::Query(query): axum::extract::Query<GroupsUpdateRequest>,
469
+ axum::Extension(claims): axum::Extension<S::Claims>,
470
+ ) -> impl axum::response::IntoResponse
471
+ where
472
+ S: Server + Clone + Send + Sync + 'static,
473
+ S::Claims: Send + Sync + Clone + 'static,
474
+ {
475
+ let result = service.groups_update(claims, query).await;
476
+ match result {
477
+ Ok(response) => response.into_response(),
478
+ Err(e) => (
479
+ axum::http::StatusCode::INTERNAL_SERVER_ERROR,
480
+ format!("Internal error: {e}"),
481
+ )
482
+ .into_response(),
483
+ }
484
+ }
485
+
486
+ pub async fn groups_delete_handler<S>(
487
+ axum::extract::State(service): axum::extract::State<S>,
488
+ axum::extract::Query(query): axum::extract::Query<GroupsDeleteRequest>,
489
+ axum::Extension(claims): axum::Extension<S::Claims>,
490
+ ) -> impl axum::response::IntoResponse
491
+ where
492
+ S: Server + Clone + Send + Sync + 'static,
493
+ S::Claims: Send + Sync + Clone + 'static,
494
+ {
495
+ let result = service.groups_delete(claims, query).await;
496
+ match result {
497
+ Ok(response) => response.into_response(),
498
+ Err(e) => (
499
+ axum::http::StatusCode::INTERNAL_SERVER_ERROR,
500
+ format!("Internal error: {e}"),
501
+ )
502
+ .into_response(),
503
+ }
504
+ }
505
+
506
+ pub async fn subjects_list_handler<S>(
507
+ axum::extract::State(service): axum::extract::State<S>,
508
+ axum::extract::Query(query): axum::extract::Query<SubjectsListRequest>,
509
+ ) -> impl axum::response::IntoResponse
510
+ where
511
+ S: Server + Clone + Send + Sync + 'static,
512
+ S::Claims: Send + Sync + Clone + 'static,
513
+ {
514
+ let result = service.subjects_list(query).await;
515
+ match result {
516
+ Ok(response) => response.into_response(),
517
+ Err(e) => (
518
+ axum::http::StatusCode::INTERNAL_SERVER_ERROR,
519
+ format!("Internal error: {e}"),
520
+ )
521
+ .into_response(),
522
+ }
523
+ }
524
+
525
+ pub async fn subjects_create_handler<S>(
526
+ axum::extract::State(service): axum::extract::State<S>,
527
+ axum::extract::Query(query): axum::extract::Query<SubjectsCreateRequest>,
528
+ axum::Extension(claims): axum::Extension<S::Claims>,
529
+ ) -> impl axum::response::IntoResponse
530
+ where
531
+ S: Server + Clone + Send + Sync + 'static,
532
+ S::Claims: Send + Sync + Clone + 'static,
533
+ {
534
+ let result = service.subjects_create(claims, query).await;
535
+ match result {
536
+ Ok(response) => response.into_response(),
537
+ Err(e) => (
538
+ axum::http::StatusCode::INTERNAL_SERVER_ERROR,
539
+ format!("Internal error: {e}"),
540
+ )
541
+ .into_response(),
542
+ }
543
+ }
544
+
545
+ pub async fn subjects_get_by_id_handler<S>(
546
+ axum::extract::State(service): axum::extract::State<S>,
547
+ axum::extract::Query(query): axum::extract::Query<SubjectsGetByIdRequest>,
548
+ ) -> impl axum::response::IntoResponse
549
+ where
550
+ S: Server + Clone + Send + Sync + 'static,
551
+ S::Claims: Send + Sync + Clone + 'static,
552
+ {
553
+ let result = service.subjects_get_by_id(query).await;
554
+ match result {
555
+ Ok(response) => response.into_response(),
556
+ Err(e) => (
557
+ axum::http::StatusCode::INTERNAL_SERVER_ERROR,
558
+ format!("Internal error: {e}"),
559
+ )
560
+ .into_response(),
561
+ }
562
+ }
563
+
564
+ pub async fn subjects_update_handler<S>(
565
+ axum::extract::State(service): axum::extract::State<S>,
566
+ axum::extract::Query(query): axum::extract::Query<SubjectsUpdateRequest>,
567
+ axum::Extension(claims): axum::Extension<S::Claims>,
568
+ ) -> impl axum::response::IntoResponse
569
+ where
570
+ S: Server + Clone + Send + Sync + 'static,
571
+ S::Claims: Send + Sync + Clone + 'static,
572
+ {
573
+ let result = service.subjects_update(claims, query).await;
574
+ match result {
575
+ Ok(response) => response.into_response(),
576
+ Err(e) => (
577
+ axum::http::StatusCode::INTERNAL_SERVER_ERROR,
578
+ format!("Internal error: {e}"),
579
+ )
580
+ .into_response(),
581
+ }
582
+ }
583
+
584
+ pub async fn subjects_delete_handler<S>(
585
+ axum::extract::State(service): axum::extract::State<S>,
586
+ axum::extract::Query(query): axum::extract::Query<SubjectsDeleteRequest>,
587
+ axum::Extension(claims): axum::Extension<S::Claims>,
588
+ ) -> impl axum::response::IntoResponse
589
+ where
590
+ S: Server + Clone + Send + Sync + 'static,
591
+ S::Claims: Send + Sync + Clone + 'static,
592
+ {
593
+ let result = service.subjects_delete(claims, query).await;
594
+ match result {
595
+ Ok(response) => response.into_response(),
596
+ Err(e) => (
597
+ axum::http::StatusCode::INTERNAL_SERVER_ERROR,
598
+ format!("Internal error: {e}"),
599
+ )
600
+ .into_response(),
601
+ }
602
+ }
603
+
604
+ pub async fn sessions_start_handler<S>(
605
+ axum::extract::State(service): axum::extract::State<S>,
606
+ axum::extract::Query(query): axum::extract::Query<SessionsStartRequest>,
607
+ axum::Extension(claims): axum::Extension<S::Claims>,
608
+ ) -> impl axum::response::IntoResponse
609
+ where
610
+ S: Server + Clone + Send + Sync + 'static,
611
+ S::Claims: Send + Sync + Clone + 'static,
612
+ {
613
+ let result = service.sessions_start(claims, query).await;
614
+ match result {
615
+ Ok(response) => response.into_response(),
616
+ Err(e) => (
617
+ axum::http::StatusCode::INTERNAL_SERVER_ERROR,
618
+ format!("Internal error: {e}"),
619
+ )
620
+ .into_response(),
621
+ }
622
+ }
623
+
624
+ pub async fn sessions_pause_handler<S>(
625
+ axum::extract::State(service): axum::extract::State<S>,
626
+ axum::extract::Query(query): axum::extract::Query<SessionsPauseRequest>,
627
+ axum::Extension(claims): axum::Extension<S::Claims>,
628
+ ) -> impl axum::response::IntoResponse
629
+ where
630
+ S: Server + Clone + Send + Sync + 'static,
631
+ S::Claims: Send + Sync + Clone + 'static,
632
+ {
633
+ let result = service.sessions_pause(claims, query).await;
634
+ match result {
635
+ Ok(response) => response.into_response(),
636
+ Err(e) => (
637
+ axum::http::StatusCode::INTERNAL_SERVER_ERROR,
638
+ format!("Internal error: {e}"),
639
+ )
640
+ .into_response(),
641
+ }
642
+ }
643
+
644
+ pub async fn sessions_resume_handler<S>(
645
+ axum::extract::State(service): axum::extract::State<S>,
646
+ axum::extract::Query(query): axum::extract::Query<SessionsResumeRequest>,
647
+ axum::Extension(claims): axum::Extension<S::Claims>,
648
+ ) -> impl axum::response::IntoResponse
649
+ where
650
+ S: Server + Clone + Send + Sync + 'static,
651
+ S::Claims: Send + Sync + Clone + 'static,
652
+ {
653
+ let result = service.sessions_resume(claims, query).await;
654
+ match result {
655
+ Ok(response) => response.into_response(),
656
+ Err(e) => (
657
+ axum::http::StatusCode::INTERNAL_SERVER_ERROR,
658
+ format!("Internal error: {e}"),
659
+ )
660
+ .into_response(),
661
+ }
662
+ }
663
+
664
+ pub async fn sessions_stop_handler<S>(
665
+ axum::extract::State(service): axum::extract::State<S>,
666
+ axum::extract::Query(query): axum::extract::Query<SessionsStopRequest>,
667
+ axum::Extension(claims): axum::Extension<S::Claims>,
668
+ ) -> impl axum::response::IntoResponse
669
+ where
670
+ S: Server + Clone + Send + Sync + 'static,
671
+ S::Claims: Send + Sync + Clone + 'static,
672
+ {
673
+ let result = service.sessions_stop(claims, query).await;
674
+ match result {
675
+ Ok(response) => response.into_response(),
676
+ Err(e) => (
677
+ axum::http::StatusCode::INTERNAL_SERVER_ERROR,
678
+ format!("Internal error: {e}"),
679
+ )
680
+ .into_response(),
681
+ }
682
+ }
683
+
684
+ pub fn create_router<S, M>(service: S, middleware: M) -> Router
685
+ where
686
+ S: Server + Clone + Send + Sync + 'static,
687
+ S::Claims: Send + Sync + Clone + 'static,
688
+ M: FnOnce(Router<S>) -> Router<S> + Clone + Send + Sync + 'static,
689
+ {
690
+ let mut router = Router::new();
691
+ let public = Router::new()
692
+ .route("/groups", get(groups_list_handler::<S>))
693
+ .route("/groups/{id}", get(groups_get_by_id_handler::<S>))
694
+ .route("/groups/{groupId}/subjects", get(subjects_list_handler::<S>))
695
+ .route("/groups/{groupId}/subjects/{id}", get(subjects_get_by_id_handler::<S>))
696
+ ;
697
+ router = router.merge(public);
698
+ let protected = Router::new()
699
+ .route("/groups", post(groups_create_handler::<S>))
700
+ .route("/groups/{id}", patch(groups_update_handler::<S>))
701
+ .route("/groups/{id}", delete(groups_delete_handler::<S>))
702
+ .route("/groups/{groupId}/subjects", post(subjects_create_handler::<S>))
703
+ .route("/groups/{groupId}/subjects/{id}", patch(subjects_update_handler::<S>))
704
+ .route("/groups/{groupId}/subjects/{id}", delete(subjects_delete_handler::<S>))
705
+ .route("/subjects/{subjectId}/sessions", post(sessions_start_handler::<S>))
706
+ .route("/subjects/{subjectId}/sessions/{logId}/pause", post(sessions_pause_handler::<S>))
707
+ .route("/subjects/{subjectId}/sessions/{logId}/resume", post(sessions_resume_handler::<S>))
708
+ .route("/subjects/{subjectId}/sessions/{logId}/stop", post(sessions_stop_handler::<S>))
709
+ ;
710
+ router = router.merge(middleware(protected));
711
+ router.with_state(service)
712
+ }