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::{self, map_access_control::check_permissions},
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(
41    map_id: Path<i32>,
42    pool: SharedPool,
43    user_info: UserInfo,
44) -> Result<HttpResponse> {
45    let id = map_id.into_inner();
46    check_permissions(id, &pool, user_info).await?;
47    let response = service::drawings::find(id, &pool).await?;
48    Ok(HttpResponse::Ok().json(response))
49}
50
51/// Endpoint for creating new `Drawings`s.
52///
53/// # Errors
54/// * If the connection to the database could not be established.
55#[utoipa::path(
56    context_path = "/api/maps/{map_id}/drawings",
57    params(
58        ("map_id" = i32, Path, description = "The id of the map"),
59    ),
60    request_body = ActionDtoWrapperNewPlantings,
61    responses(
62        (status = 201, description = "Create plantings", body = Vec<DrawingDto>)
63    ),
64    security(
65        ("oauth2" = [])
66    )
67)]
68#[post("")]
69pub async fn create(
70    path: Path<i32>,
71    new_drawings: Json<ActionDtoWrapper<Vec<DrawingDto>>>,
72    pool: SharedPool,
73    broadcaster: SharedBroadcaster,
74    user_info: UserInfo,
75) -> Result<HttpResponse> {
76    let map_id = path.into_inner();
77    let id = user_info.id;
78    check_permissions(map_id, &pool, user_info).await?;
79
80    let ActionDtoWrapper { action_id, dto } = new_drawings.into_inner();
81
82    let created_drawings = service::drawings::create(dto, &pool).await?;
83
84    broadcaster
85        .broadcast(
86            map_id,
87            Action {
88                action_id,
89                user_id: id,
90                action: ActionType::CreateDrawing(created_drawings.clone()),
91            },
92        )
93        .await;
94
95    Ok(HttpResponse::Created().json(created_drawings))
96}
97
98/// Endpoint for updating `Drawings`s.
99///
100/// # Errors
101/// * If the connection to the database could not be established.
102#[utoipa::path(
103    context_path = "/api/maps/{map_id}/drawings",
104    params(
105        ("map_id" = i32, Path, description = "The id of the map the layer is on"),
106    ),
107    request_body = ActionDtoWrapperUpdatePlantings,
108    responses(
109        (status = 200, description = "Update plantings", body = Vec<DrawingDto>)
110    ),
111    security(
112        ("oauth2" = [])
113    )
114)]
115#[patch("")]
116pub async fn update(
117    path: Path<i32>,
118    update_drawings: Json<ActionDtoWrapper<UpdateDrawingsDto>>,
119    pool: SharedPool,
120    broadcaster: SharedBroadcaster,
121    user_info: UserInfo,
122) -> Result<HttpResponse> {
123    let map_id = path.into_inner();
124    let id = user_info.id;
125    check_permissions(map_id, &pool, user_info).await?;
126    let ActionDtoWrapper { action_id, dto } = update_drawings.into_inner();
127
128    let updated = service::drawings::update(dto.clone(), &pool).await?;
129
130    let action = match &dto {
131        UpdateDrawingsDto::Update(_) => ActionType::UpdateDrawing(updated.clone()),
132        UpdateDrawingsDto::UpdateAddDate(_) => ActionType::UpdateDrawingAddDate(updated.clone()),
133        UpdateDrawingsDto::UpdateRemoveDate(_) => {
134            ActionType::UpdateDrawingRemoveDate(updated.clone())
135        }
136        UpdateDrawingsDto::UpdateNotes(_) => ActionType::UpdateDrawingNotes(
137            updated
138                .clone()
139                .into_iter()
140                .map(UpdateDrawingNotesActionPayload::new)
141                .collect(),
142        ),
143    };
144
145    broadcaster
146        .broadcast(
147            map_id,
148            Action {
149                action_id,
150                user_id: id,
151                action,
152            },
153        )
154        .await;
155
156    Ok(HttpResponse::Ok().json(updated))
157}
158
159/// Endpoint for deleting `Drawings`s.
160///
161/// # Errors
162/// * If the connection to the database could not be established.
163#[utoipa::path(
164    context_path = "/api/maps/{map_id}/drawings",
165    params(
166        ("map_id" = i32, Path, description = "The id of the map"),
167    ),
168    request_body = ActionDtoWrapperDeleteDrawings,
169    responses(
170        (status = 200, description = "Drawings have been deleted")
171    ),
172    security(
173        ("oauth2" = [])
174    )
175)]
176#[delete("")]
177pub async fn delete(
178    path: Path<i32>,
179    delete_drawings: Json<ActionDtoWrapper<Vec<Uuid>>>,
180    pool: SharedPool,
181    broadcaster: SharedBroadcaster,
182    user_info: UserInfo,
183) -> Result<HttpResponse> {
184    let map_id = path.into_inner();
185    let id = user_info.id;
186    check_permissions(map_id, &pool, user_info).await?;
187    let ActionDtoWrapper { action_id, dto } = delete_drawings.into_inner();
188
189    service::drawings::delete_by_ids(dto.clone(), &pool).await?;
190
191    broadcaster
192        .broadcast(
193            map_id,
194            Action {
195                action_id,
196                user_id: id,
197                action: ActionType::DeleteDrawing(dto),
198            },
199        )
200        .await;
201
202    Ok(HttpResponse::Ok().finish())
203}