1use actix_http::StatusCode;
4use postgis_diesel::types::{Point, Polygon};
5use uuid::Uuid;
6
7use crate::{
8 config::{auth::user_info::UserInfo, data::SharedPool},
9 error::ServiceError,
10 model::{
11 dto::{
12 base_layer_images::BaseLayerImageDto, layers::LayerDto, MapDto, MapSearchParameters,
13 NewMapDto, Page, PageParameters, UpdateMapDto, UpdateMapGeometryDto,
14 },
15 entity::{base_layer_images::BaseLayerImages, layers::Layer, Map, MapCollaborator},
16 r#enum::layer_type::LayerType,
17 },
18};
19
20const LAYER_TYPES: [LayerType; 6] = [
22 LayerType::Base,
23 LayerType::Drawing,
24 LayerType::Soiltexture,
25 LayerType::Hydrology,
26 LayerType::Shade,
27 LayerType::Plants,
28];
29
30pub async fn find(
35 search_parameters: MapSearchParameters,
36 page_parameters: PageParameters,
37 pool: &SharedPool,
38 user_info: UserInfo,
39) -> Result<Page<MapDto>, ServiceError> {
40 let mut conn = pool.get().await?;
41 let collaborating_in = MapCollaborator::find_by_user_id(user_info.id, &mut conn).await?;
42 let result = Map::find(
43 search_parameters,
44 page_parameters,
45 &mut conn,
46 user_info,
47 collaborating_in,
48 )
49 .await?;
50 Ok(result)
51}
52
53pub async fn find_by_id(id: i32, pool: &SharedPool) -> Result<MapDto, ServiceError> {
58 let mut conn = pool.get().await?;
59 let result = Map::find_by_id(id, &mut conn).await?;
60 Ok(result)
61}
62
63pub async fn create(
68 new_map: NewMapDto,
69 user_id: Uuid,
70 pool: &SharedPool,
71) -> Result<MapDto, ServiceError> {
72 let mut conn = pool.get().await?;
73
74 if Map::is_name_taken(&new_map.name, &mut conn).await? {
75 return Err(ServiceError::new(
76 StatusCode::CONFLICT,
77 "Map name already taken",
78 ));
79 }
80
81 let geometry_validation_result = is_valid_map_geometry(&new_map.geometry);
82 if let Some(error) = geometry_validation_result {
83 return Err(error);
84 }
85
86 let result = Map::create(new_map, user_id, &mut conn).await?;
87 for (layer_type, order_index) in LAYER_TYPES.iter().zip(0..) {
88 let new_layer = LayerDto {
89 id: Uuid::new_v4(),
90 type_: *layer_type,
91 name: format!("{layer_type} Layer"),
92 is_alternative: false,
93 map_id: result.id,
94 order_index,
95 marked_deleted: false,
96 };
97 let layer = Layer::create(result.id, new_layer, &mut conn).await?;
98
99 if layer.type_ == LayerType::Base {
103 BaseLayerImages::create(
104 BaseLayerImageDto {
105 id: Uuid::new_v4(),
106 layer_id: layer.id,
107 path: String::new(),
108 rotation: 0.0,
109 scale: 100.0,
110 x: 0,
111 y: 0,
112 },
113 &mut conn,
114 )
115 .await?;
116 }
117 }
118
119 Ok(result)
120}
121
122pub async fn update(
129 map_update: UpdateMapDto,
130 id: i32,
131 pool: &SharedPool,
132) -> Result<MapDto, ServiceError> {
133 let mut conn = pool.get().await?;
134
135 let result = Map::update(map_update, id, &mut conn).await?;
136 Ok(result)
137}
138
139pub async fn update_geometry(
146 map_update_geometry: UpdateMapGeometryDto,
147 id: i32,
148 pool: &SharedPool,
149) -> Result<MapDto, ServiceError> {
150 let mut conn = pool.get().await?;
151
152 let geometry_validation_result = is_valid_map_geometry(&map_update_geometry.geometry);
153 if let Some(error) = geometry_validation_result {
154 return Err(error);
155 }
156
157 let result = Map::update_geometry(map_update_geometry, id, &mut conn).await?;
158 Ok(result)
159}
160
161pub async fn delete_by_id(id: i32, pool: &SharedPool) -> Result<MapDto, ServiceError> {
168 let mut conn = pool.get().await?;
169
170 let result = Map::mark_for_deletion(id, &mut conn).await?;
171
172 Ok(result)
173}
174
175fn is_valid_map_geometry(geometry: &Polygon<Point>) -> Option<ServiceError> {
177 if geometry.rings.len() != 1 {
178 return Some(ServiceError {
179 status_code: StatusCode::BAD_REQUEST,
180 reason: "Map geometry must have exactly one ring".to_owned(),
181 });
182 }
183
184 let geometry_points_length = geometry.rings.get(0).unwrap_or(&Vec::new()).len();
185
186 if geometry_points_length < 3 + 1 {
187 return Some(ServiceError {
188 status_code: StatusCode::BAD_REQUEST,
189 reason: "Map geometry must be a polygon of at least three points.".to_owned(),
190 });
191 }
192
193 None
194}