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        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, &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<DrawingDto>>>,
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).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
100    Ok(HttpResponse::Created().json(created_drawings))
101}
102
103/// Endpoint for updating `Drawings`s.
104///
105/// # Errors
106/// * If the connection to the database could not be established.
107/// * If the current user does not have the appropriate permissions.
108#[utoipa::path(
109    context_path = "/api/maps/{map_id}/drawings",
110    params(
111        ("map_id" = i32, Path, description = "The id of the map the layer is on"),
112    ),
113    request_body = ActionDtoWrapperUpdatePlantings,
114    responses(
115        (status = 200, description = "Update plantings", body = Vec<DrawingDto>)
116    ),
117    security(
118        ("oauth2" = [])
119    )
120)]
121#[patch("")]
122pub async fn update(
123    path: Path<i32>,
124    update_drawings: Json<ActionDtoWrapper<UpdateDrawingsDto>>,
125    pool: SharedPool,
126    broadcaster: SharedBroadcaster,
127    user_info: UserInfo,
128) -> Result<HttpResponse> {
129    let map_id = path.into_inner();
130    let id = user_info.id;
131    check_permissions(map_id, &pool, user_info, AccessRights::Write).await?;
132    let ActionDtoWrapper { action_id, dto } = update_drawings.into_inner();
133
134    let updated = service::drawings::update(dto.clone(), &pool).await?;
135
136    let action = match &dto {
137        UpdateDrawingsDto::Update(_) => ActionType::UpdateDrawing(updated.clone()),
138        UpdateDrawingsDto::UpdateAddDate(_) => ActionType::UpdateDrawingAddDate(updated.clone()),
139        UpdateDrawingsDto::UpdateRemoveDate(_) => {
140            ActionType::UpdateDrawingRemoveDate(updated.clone())
141        }
142        UpdateDrawingsDto::UpdateNotes(_) => ActionType::UpdateDrawingNotes(
143            updated
144                .clone()
145                .into_iter()
146                .map(UpdateDrawingNotesActionPayload::new)
147                .collect(),
148        ),
149    };
150
151    broadcaster
152        .broadcast(
153            map_id,
154            Action {
155                action_id,
156                user_id: id,
157                action,
158            },
159        )
160        .await;
161
162    Ok(HttpResponse::Ok().json(updated))
163}
164
165/// Endpoint for deleting `Drawings`s.
166///
167/// # Errors
168/// * If the connection to the database could not be established.
169/// * If the current user does not have the appropriate permissions.
170#[utoipa::path(
171    context_path = "/api/maps/{map_id}/drawings",
172    params(
173        ("map_id" = i32, Path, description = "The id of the map"),
174    ),
175    request_body = ActionDtoWrapperDeleteDrawings,
176    responses(
177        (status = 200, description = "Drawings have been deleted")
178    ),
179    security(
180        ("oauth2" = [])
181    )
182)]
183#[delete("")]
184pub async fn delete(
185    path: Path<i32>,
186    delete_drawings: Json<ActionDtoWrapper<Vec<Uuid>>>,
187    pool: SharedPool,
188    broadcaster: SharedBroadcaster,
189    user_info: UserInfo,
190) -> Result<HttpResponse> {
191    let map_id = path.into_inner();
192    let id = user_info.id;
193    check_permissions(map_id, &pool, user_info, AccessRights::Write).await?;
194    let ActionDtoWrapper { action_id, dto } = delete_drawings.into_inner();
195
196    service::drawings::delete_by_ids(dto.clone(), &pool).await?;
197
198    broadcaster
199        .broadcast(
200            map_id,
201            Action {
202                action_id,
203                user_id: id,
204                action: ActionType::DeleteDrawing(dto),
205            },
206        )
207        .await;
208
209    Ok(HttpResponse::Ok().finish())
210}