1use 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#[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#[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#[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#[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}