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