1use actix_web::{
4 delete, get, patch, post,
5 web::{Json, Path, Query},
6 HttpResponse, Result,
7};
8
9use crate::{
10 config::{
11 auth::user_info::UserInfo,
12 data::{SharedBroadcaster, SharedPool},
13 },
14 model::dto::{
15 actions::Action,
16 core::ActionDtoWrapper,
17 plantings::{DeletePlantingDto, PlantingDto, PlantingSearchParameters, UpdatePlantingDto},
18 },
19 service::{
20 map_access_control::{check_permissions, AccessRights},
21 plantings,
22 },
23};
24#[utoipa::path(
29 context_path = "/api/maps/{map_id}/layers/plants/plantings",
30 params(
31 ("map_id" = i32, Path, description = "The id of the map the layer is on"),
32 PlantingSearchParameters
33 ),
34 responses(
35 (status = 200, description = "Find plantings", body = TimelinePagePlantingsDto)
36 ),
37 security(
38 ("oauth2" = [])
39 )
40)]
41#[get("")]
42pub async fn find(
43 map_id: Path<i32>,
46 search_params: Query<PlantingSearchParameters>,
47 pool: SharedPool,
48 user_info: UserInfo,
49) -> Result<HttpResponse> {
50 check_permissions(
51 map_id.into_inner(),
52 &pool,
53 user_info.clone(),
54 AccessRights::Read,
55 )
56 .await?;
57 let response = plantings::find(search_params.into_inner(), &pool).await?;
58 Ok(HttpResponse::Ok().json(response))
59}
60
61#[utoipa::path(
66 context_path = "/api/maps/{map_id}/layers/plants/plantings",
67 params(
68 ("map_id" = i32, Path, description = "The id of the map the layer is on"),
69 ),
70 request_body = ActionDtoWrapperNewPlantings,
71 responses(
72 (status = 201, description = "Create plantings", body = Vec<PlantingDto>)
73 ),
74 security(
75 ("oauth2" = [])
76 )
77)]
78#[post("")]
79pub async fn create(
80 path: Path<i32>,
81 new_plantings: Json<ActionDtoWrapper<Vec<PlantingDto>>>,
82 user_info: UserInfo,
83 pool: SharedPool,
84 broadcaster: SharedBroadcaster,
85) -> Result<HttpResponse> {
86 let map_id = path.into_inner();
87
88 check_permissions(map_id, &pool, user_info.clone(), AccessRights::Write).await?;
89
90 let ActionDtoWrapper { action_id, dto } = new_plantings.into_inner();
91
92 let created_plantings = plantings::create(dto, map_id.into(), user_info.id, &pool).await?;
93
94 broadcaster
95 .broadcast(
96 map_id,
97 Action::new_create_planting_action(created_plantings.clone(), user_info.id, action_id),
98 )
99 .await;
100
101 Ok(HttpResponse::Created().json(created_plantings))
102}
103
104#[utoipa::path(
109 context_path = "/api/maps/{map_id}/layers/plants/plantings",
110 params(
111 ("map_id" = i32, Path, description = "The id of the map the layer is on"),
112 ),
113 request_body = ActionDtoWrapperUpdatePlantings,
114 responses(
115 (status = 200, description = "Update plantings", body = Vec<PlantingDto>)
116 ),
117 security(
118 ("oauth2" = [])
119 )
120)]
121#[patch("")]
122pub async fn update(
123 path: Path<i32>,
124 update_planting: Json<ActionDtoWrapper<UpdatePlantingDto>>,
125 user_info: UserInfo,
126 pool: SharedPool,
127 broadcaster: SharedBroadcaster,
128) -> Result<HttpResponse> {
129 let map_id = path.into_inner();
130
131 check_permissions(map_id, &pool, user_info.clone(), AccessRights::Write).await?;
132
133 let ActionDtoWrapper { action_id, dto } = update_planting.into_inner();
134
135 let updated_plantings =
136 plantings::update(dto.clone(), map_id.into(), user_info.id, &pool).await?;
137
138 let action = match &dto {
139 UpdatePlantingDto::Transform(dto) => {
140 Action::new_transform_planting_action(dto, user_info.id, action_id)
141 }
142 UpdatePlantingDto::Move(dto) => {
143 Action::new_move_planting_action(dto, user_info.id, action_id)
144 }
145 UpdatePlantingDto::UpdateAddDate(dto) => {
146 Action::new_update_planting_add_date_action(dto, user_info.id, action_id)
147 }
148 UpdatePlantingDto::UpdateRemoveDate(dto) => {
149 Action::new_update_planting_remove_date_action(dto, user_info.id, action_id)
150 }
151 UpdatePlantingDto::UpdateNote(dto) => {
152 Action::new_update_planting_note_action(dto, user_info.id, action_id)
153 }
154 };
155
156 broadcaster.broadcast(map_id, action).await;
157
158 Ok(HttpResponse::Ok().json(updated_plantings))
159}
160
161#[utoipa::path(
166 context_path = "/api/maps/{map_id}/layers/plants/plantings",
167 params(
168 ("map_id" = i32, Path, description = "The id of the map the layer is on"),
169 ),
170 request_body = ActionDtoWrapperDeletePlantings,
171 responses(
172 (status = 200, description = "Delete plantings")
173 ),
174 security(
175 ("oauth2" = [])
176 )
177)]
178#[delete("")]
179pub async fn delete(
180 path: Path<i32>,
181 delete_planting: Json<ActionDtoWrapper<Vec<DeletePlantingDto>>>,
182 user_info: UserInfo,
183 pool: SharedPool,
184 broadcaster: SharedBroadcaster,
185) -> Result<HttpResponse> {
186 let map_id = path.into_inner();
187
188 check_permissions(map_id, &pool, user_info.clone(), AccessRights::Write).await?;
189
190 let ActionDtoWrapper { action_id, dto } = delete_planting.into_inner();
191
192 plantings::delete_by_ids(dto.clone(), map_id.into(), user_info.id, &pool).await?;
193
194 broadcaster
195 .broadcast(
196 map_id,
197 Action::new_delete_planting_action(&dto, user_info.id, action_id),
198 )
199 .await;
200
201 Ok(HttpResponse::Ok().finish())
202}