backend/controller/
areas.rs

1//! `Areas` endpoints, handling shadings, hydrologies, and soil textures.
2
3use actix_web::{
4    delete, get, patch, post,
5    web::{Json, Path, Query},
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,
17        areas::{AreaKind, AreaSearchParameters, AreaUpdate, NewAreaDto, UpdateAreaDto},
18        core::ActionDtoWrapper,
19    },
20    service::{areas, map_access_control::check_permissions},
21};
22
23/// Endpoint for listing and filtering areas.
24///
25/// # Errors
26/// * If the connection to the database could not be established.
27#[utoipa::path(
28    context_path = "/api/maps/{map_id}/areas",
29    params(
30        ("map_id" = i32, Path, description = "The id of the map the layer is on"),
31        AreaSearchParameters
32    ),
33    responses(
34        (status = 200, description = "Find areas", body = Vec<AreaDto>),
35    ),
36    security(
37        ("oauth2" = [])
38    )
39)]
40#[get("")]
41pub async fn find(
42    search_params: Query<AreaSearchParameters>,
43    pool: SharedPool,
44    user_info: UserInfo,
45    path: Path<i32>,
46) -> Result<HttpResponse> {
47    check_permissions(path.into_inner(), &pool, user_info).await?;
48    let response = areas::find(search_params.into_inner(), &pool).await?;
49    Ok(HttpResponse::Ok().json(response))
50}
51
52/// Endpoint for creating a new area.
53///
54/// # Errors
55/// * If the connection to the database could not be established.
56#[utoipa::path(
57    context_path = "/api/maps/{map_id}/areas",
58    params(
59        ("map_id" = i32, Path, description = "The id of the map the layer is on"),
60        ("area_kind" = AreaKind, Path, description = "The type of area"),
61    ),
62    request_body = NewAreaDto,
63    responses(
64        (status = 201, description = "Create an areas", body = AreaDto)
65    ),
66    security(
67        ("oauth2" = [])
68    )
69)]
70#[post("/{area_kind}")]
71pub async fn create(
72    path: Path<(i32, AreaKind)>,
73    new_areas: Json<ActionDtoWrapper<Vec<NewAreaDto>>>,
74    pool: SharedPool,
75    broadcaster: SharedBroadcaster,
76    user_info: UserInfo,
77) -> Result<HttpResponse> {
78    let user_id = user_info.id;
79    let (map_id, area_kind) = path.into_inner();
80
81    check_permissions(map_id, &pool, user_info).await?;
82
83    let ActionDtoWrapper { action_id, dto } = new_areas.into_inner();
84
85    let created_areas = areas::create(area_kind, dto, &pool).await?;
86
87    broadcaster
88        .broadcast(
89            map_id,
90            Action::new_create_area_action(area_kind, created_areas.clone(), user_id, action_id),
91        )
92        .await;
93
94    Ok(HttpResponse::Created().json(created_areas))
95}
96
97/// Endpoint for updating an area.
98///
99/// # Errors
100/// * If the connection to the database could not be established.
101#[utoipa::path(
102    context_path = "/api/maps/{map_id}/areas",
103    params(
104        ("map_id" = i32, Path, description = "The id of the map the layer is on"),
105        ("area_kind" = AreaKind, Path, description = "The type of area"),
106    ),
107    request_body = ActionDtoWrapperUpdateAreas,
108    responses(
109        (status = 200, description = "Update multiple areas of the same kind", body = Vec<AreaDto>)
110    ),
111    security(
112        ("oauth2" = [])
113    )
114)]
115#[patch("/{area_kind}")]
116pub async fn update(
117    path: Path<(i32, AreaKind)>,
118    update_areas: Json<ActionDtoWrapper<UpdateAreaDto>>,
119    pool: SharedPool,
120    broadcaster: SharedBroadcaster,
121    user_info: UserInfo,
122) -> Result<HttpResponse> {
123    let (map_id, area_kind) = path.into_inner();
124
125    let user_id = user_info.id;
126
127    check_permissions(map_id, &pool, user_info).await?;
128
129    let ActionDtoWrapper { action_id, dto } = update_areas.into_inner();
130
131    let updated = areas::update(area_kind, dto.clone(), &pool).await?;
132
133    let action = match dto.update {
134        AreaUpdate::UpdateValue(_) => {
135            Action::new_update_area_action(area_kind, &updated, user_id, action_id)
136        }
137        AreaUpdate::UpdateAddDate(_) => {
138            Action::new_update_area_add_date_action(area_kind, &updated, user_id, action_id)
139        }
140        AreaUpdate::UpdateRemoveDate(_) => {
141            Action::new_update_area_remove_date_action(area_kind, &updated, user_id, action_id)
142        }
143        AreaUpdate::UpdateNotes(_) => {
144            Action::new_update_area_notes_action(area_kind, &updated, user_id, action_id)
145        }
146    };
147    broadcaster.broadcast(map_id, action).await;
148
149    Ok(HttpResponse::Ok().json(updated))
150}
151
152/// Endpoint for deleting an area.
153///
154/// # Errors
155/// * If the connection to the database could not be established.
156#[utoipa::path(
157    context_path = "/api/maps/{map_id}/areas",
158    params(
159        ("map_id" = i32, Path, description = "The id of the map the layer is on"),
160        ("area_kind" = AreaKind, Path, description = "The type of area"),
161    ),
162    request_body = ActionDtoWrapperDeleteAreas,
163    responses(
164        (status = 200, description = "Areas deleted")
165    ),
166    security(
167        ("oauth2" = [])
168    )
169)]
170#[delete("/{area_kind}")]
171pub async fn delete(
172    path: Path<(i32, AreaKind)>,
173    ids: Json<ActionDtoWrapper<Vec<Uuid>>>,
174    pool: SharedPool,
175    broadcaster: SharedBroadcaster,
176    user_info: UserInfo,
177) -> Result<HttpResponse> {
178    let (map_id, area_kind) = path.into_inner();
179
180    let user_id = user_info.id;
181
182    check_permissions(map_id, &pool, user_info).await?;
183
184    let ActionDtoWrapper { action_id, dto } = ids.into_inner();
185
186    areas::delete_by_ids(area_kind, dto.clone(), &pool).await?;
187
188    broadcaster
189        .broadcast(
190            map_id,
191            Action::new_delete_area_action(area_kind, dto, user_id, action_id),
192        )
193        .await;
194
195    Ok(HttpResponse::Ok().finish())
196}