backend/controller/
map.rs

1//! `Map` endpoints.
2
3use actix_web::web::Query;
4use actix_web::{
5    delete, get, patch, post,
6    web::{Json, Path},
7    HttpResponse, Result,
8};
9use uuid::Uuid;
10
11use crate::{
12    config::{
13        auth::user_info::UserInfo,
14        data::{SharedBroadcaster, SharedPool},
15    },
16    model::dto::{
17        actions::{Action, ActionType, UpdateMapGeometryActionPayload},
18        MapSearchParameters, NewMapDto, PageParameters, UpdateMapDto, UpdateMapGeometryDto,
19    },
20    service,
21    service::map_access_control::check_permissions,
22};
23
24/// Endpoint for fetching or searching all [`Map`](crate::model::entity::Map).
25/// Search parameters are taken from the URLs query string (e.g. .../`api/maps?is_inactive=false&per_page=5`).
26/// If no page parameters are provided, the first page is returned.
27///
28/// # Errors
29/// * If the connection to the database could not be established.
30#[utoipa::path(
31    context_path = "/api/maps",
32    params(
33        MapSearchParameters,
34        PageParameters
35    ),
36    responses(
37        (status = 200, description = "Fetch or search all maps", body = PageMapDto)
38    ),
39    security(
40        ("oauth2" = [])
41    )
42)]
43#[get("")]
44pub async fn find(
45    search_query: Query<MapSearchParameters>,
46    page_query: Query<PageParameters>,
47    pool: SharedPool,
48) -> Result<HttpResponse> {
49    let response =
50        service::map::find(search_query.into_inner(), page_query.into_inner(), &pool).await?;
51    Ok(HttpResponse::Ok().json(response))
52}
53
54/// Endpoint for fetching a [`Map`](crate::model::entity::Map).
55///
56/// # Errors
57/// * If the connection to the database could not be established.
58#[utoipa::path(
59    context_path = "/api/maps",
60    responses(
61        (status = 200, description = "Fetch a map by id", body = MapDto)
62    ),
63    security(
64        ("oauth2" = [])
65    )
66)]
67#[get("/{map_id}")]
68pub async fn find_by_id(
69    map_id: Path<i32>,
70    pool: SharedPool,
71    user_info: UserInfo,
72) -> Result<HttpResponse> {
73    let id = map_id.into_inner();
74    check_permissions(id, &pool, user_info).await?;
75    let response = service::map::find_by_id(id, &pool).await?;
76    Ok(HttpResponse::Ok().json(response))
77}
78
79/// Endpoint for creating a new [`Map`](crate::model::entity::Map).
80///
81/// # Errors
82/// * If the connection to the database could not be established.
83#[utoipa::path(
84    context_path = "/api/maps",
85    request_body = NewMapDto,
86    responses(
87        (status = 201, description = "Create a new map", body = MapDto)
88    ),
89    security(
90        ("oauth2" = [])
91    )
92)]
93#[post("")]
94pub async fn create(
95    new_map_json: Json<NewMapDto>,
96    user_info: UserInfo,
97    pool: SharedPool,
98) -> Result<HttpResponse> {
99    let response = service::map::create(new_map_json.0, user_info.id, &pool).await?;
100    Ok(HttpResponse::Created().json(response))
101}
102
103/// Endpoint for updating a [`Map`](crate::model::entity::Map).
104///
105/// # Errors
106/// * If the connection to the database could not be established.
107#[utoipa::path(
108    context_path = "/api/maps",
109    request_body = UpdateMapDto,
110    responses(
111        (status = 200, description = "Update a map", body = MapDto)
112    ),
113    security(
114        ("oauth2" = [])
115    )
116)]
117#[patch("/{map_id}")]
118pub async fn update(
119    map_update_json: Json<UpdateMapDto>,
120    map_id: Path<i32>,
121    user_info: UserInfo,
122    pool: SharedPool,
123) -> Result<HttpResponse> {
124    let id = map_id.into_inner();
125    let user_id = user_info.id;
126    check_permissions(id, &pool, user_info).await?;
127    let response = service::map::update(map_update_json.0, id, user_id, &pool).await?;
128    Ok(HttpResponse::Ok().json(response))
129}
130/// Endpoint for updating the [`Geometry`](postgis_diesel::sql_types::Geometry) of a [`Map`](crate::model::entity::Map).
131///
132/// # Errors
133/// * If the connection to the database could not be established.
134#[utoipa::path(
135context_path = "/api/maps",
136request_body = UpdateMapDto,
137responses(
138(status = 200, description = "Update a map", body = MapDto)
139),
140security(
141("oauth2" = [])
142)
143)]
144#[patch("/{map_id}/geometry")]
145pub async fn update_geometry(
146    map_update_geometry_json: Json<UpdateMapGeometryDto>,
147    map_id: Path<i32>,
148    user_info: UserInfo,
149    pool: SharedPool,
150    broadcaster: SharedBroadcaster,
151) -> Result<HttpResponse> {
152    let map_id_inner = map_id.into_inner();
153    let user_id = user_info.id;
154    check_permissions(map_id_inner, &pool, user_info).await?;
155
156    let response = service::map::update_geometry(
157        map_update_geometry_json.0.clone(),
158        map_id_inner,
159        user_id,
160        &pool,
161    )
162    .await?;
163
164    broadcaster
165        .broadcast(
166            map_id_inner,
167            Action {
168                action_id: Uuid::new_v4(),
169                user_id,
170                action: ActionType::UpdateMapGeometry(UpdateMapGeometryActionPayload::new(
171                    map_update_geometry_json.0,
172                    map_id_inner,
173                )),
174            },
175        )
176        .await;
177
178    Ok(HttpResponse::Ok().json(response))
179}
180
181/// Endpoint for soft-deleting a [`Map`](crate::model::entity::Map).
182///
183/// # Errors
184/// * If the connection to the database could not be established.
185#[utoipa::path(
186    context_path = "/api/maps",
187    responses(
188        (status = 200, description = "Delete a map by id")
189    ),
190    security(
191        ("oauth2" = [])
192    )
193)]
194#[delete("/{map_id}")]
195pub async fn delete_by_id(
196    map_id: Path<i32>,
197    user_info: UserInfo,
198    pool: SharedPool,
199) -> Result<HttpResponse> {
200    let m_id = map_id.into_inner();
201    let user_id = user_info.id;
202    check_permissions(m_id, &pool, user_info).await?;
203    service::map::delete_by_id(m_id, user_id, &pool).await?;
204    Ok(HttpResponse::Ok().finish())
205}