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