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