backend/controller/
drawings.rs

1//! `Drawings` endpoints.
2
3use actix_web::{
4    delete, get, patch, post,
5    web::{Json, Path},
6    HttpResponse, Result,
7};
8use uuid::Uuid;
9
10use crate::{
11    config::{
12        auth::user_info::UserInfo,
13        data::{SharedBroadcaster, SharedPool},
14    },
15    model::dto::{
16        actions::{Action, ActionType, UpdateDrawingNotesActionPayload},
17        core::ActionDtoWrapper,
18        drawings::{DrawingDto, UpdateDrawingsDto},
19    },
20    service,
21};
22
23/// Endpoint for listing and filtering `Drawing`s.
24///
25/// # Errors
26/// * If the connection to the database could not be established.
27#[utoipa::path(
28    context_path = "/api/maps/{map_id}/drawings",
29    params(
30        ("map_id" = i32, Path, description = "The id of the map the layer is on"),
31    ),
32    responses(
33        (status = 200, description = "Find drawings", body = Vec<DrawingDto>)
34    ),
35    security(
36        ("oauth2" = [])
37    )
38)]
39#[get("")]
40pub async fn find(map_id: Path<i32>, pool: SharedPool) -> Result<HttpResponse> {
41    let response = service::drawings::find(map_id.into_inner(), &pool).await?;
42    Ok(HttpResponse::Ok().json(response))
43}
44
45/// Endpoint for creating new `Drawings`s.
46///
47/// # Errors
48/// * If the connection to the database could not be established.
49#[utoipa::path(
50    context_path = "/api/maps/{map_id}/drawings",
51    params(
52        ("map_id" = i32, Path, description = "The id of the map"),
53    ),
54    request_body = ActionDtoWrapperNewPlantings,
55    responses(
56        (status = 201, description = "Create plantings", body = Vec<DrawingDto>)
57    ),
58    security(
59        ("oauth2" = [])
60    )
61)]
62#[post("")]
63pub async fn create(
64    path: Path<i32>,
65    new_drawings: Json<ActionDtoWrapper<Vec<DrawingDto>>>,
66    pool: SharedPool,
67    broadcaster: SharedBroadcaster,
68    user_info: UserInfo,
69) -> Result<HttpResponse> {
70    let map_id = path.into_inner();
71
72    let ActionDtoWrapper { action_id, dto } = new_drawings.into_inner();
73
74    let created_drawings = service::drawings::create(dto, &pool).await?;
75
76    broadcaster
77        .broadcast(
78            map_id,
79            Action {
80                action_id,
81                user_id: user_info.id,
82                action: ActionType::CreateDrawing(created_drawings.clone()),
83            },
84        )
85        .await;
86
87    Ok(HttpResponse::Created().json(created_drawings))
88}
89
90/// Endpoint for updating `Drawings`s.
91///
92/// # Errors
93/// * If the connection to the database could not be established.
94#[utoipa::path(
95    context_path = "/api/maps/{map_id}/drawings",
96    params(
97        ("map_id" = i32, Path, description = "The id of the map the layer is on"),
98    ),
99    request_body = ActionDtoWrapperUpdatePlantings,
100    responses(
101        (status = 200, description = "Update plantings", body = Vec<DrawingDto>)
102    ),
103    security(
104        ("oauth2" = [])
105    )
106)]
107#[patch("")]
108pub async fn update(
109    path: Path<i32>,
110    update_drawings: Json<ActionDtoWrapper<UpdateDrawingsDto>>,
111    pool: SharedPool,
112    broadcaster: SharedBroadcaster,
113    user_info: UserInfo,
114) -> Result<HttpResponse> {
115    let map_id = path.into_inner();
116
117    let ActionDtoWrapper { action_id, dto } = update_drawings.into_inner();
118
119    let updated = service::drawings::update(dto.clone(), &pool).await?;
120
121    let action = match &dto {
122        UpdateDrawingsDto::Update(_) => ActionType::UpdateDrawing(updated.clone()),
123        UpdateDrawingsDto::UpdateAddDate(_) => ActionType::UpdateDrawingAddDate(updated.clone()),
124        UpdateDrawingsDto::UpdateRemoveDate(_) => {
125            ActionType::UpdateDrawingRemoveDate(updated.clone())
126        }
127        UpdateDrawingsDto::UpdateNotes(_) => ActionType::UpdateDrawingNotes(
128            updated
129                .clone()
130                .into_iter()
131                .map(UpdateDrawingNotesActionPayload::new)
132                .collect(),
133        ),
134    };
135
136    broadcaster
137        .broadcast(
138            map_id,
139            Action {
140                action_id,
141                user_id: user_info.id,
142                action,
143            },
144        )
145        .await;
146
147    Ok(HttpResponse::Ok().json(updated))
148}
149
150/// Endpoint for deleting `Drawings`s.
151///
152/// # Errors
153/// * If the connection to the database could not be established.
154#[utoipa::path(
155    context_path = "/api/maps/{map_id}/drawings",
156    params(
157        ("map_id" = i32, Path, description = "The id of the map"),
158    ),
159    request_body = ActionDtoWrapperDeleteDrawings,
160    responses(
161        (status = 200, description = "Drawings have been deleted")
162    ),
163    security(
164        ("oauth2" = [])
165    )
166)]
167#[delete("")]
168pub async fn delete(
169    path: Path<i32>,
170    delete_drawings: Json<ActionDtoWrapper<Vec<Uuid>>>,
171    pool: SharedPool,
172    broadcaster: SharedBroadcaster,
173    user_info: UserInfo,
174) -> Result<HttpResponse> {
175    let map_id = path.into_inner();
176
177    let ActionDtoWrapper { action_id, dto } = delete_drawings.into_inner();
178
179    service::drawings::delete_by_ids(dto.clone(), &pool).await?;
180
181    broadcaster
182        .broadcast(
183            map_id,
184            Action {
185                action_id,
186                user_id: user_info.id,
187                action: ActionType::DeleteDrawing(dto),
188            },
189        )
190        .await;
191
192    Ok(HttpResponse::Ok().finish())
193}