backend/model/
dto.rs

1//! DTOs of `PermaplanT`.
2#![allow(clippy::module_name_repetitions)] // There needs to be a difference between DTOs and entities otherwise imports will be messy.
3
4use chrono::{NaiveDate, NaiveDateTime};
5use postgis_diesel::types::{Point, Polygon};
6use serde::{Deserialize, Serialize};
7use typeshare::typeshare;
8use utoipa::{IntoParams, ToSchema};
9use uuid::Uuid;
10
11use self::layers::LayerDto;
12
13use super::r#enum::{
14    herbaceous_or_woody::HerbaceousOrWoody, include_archived_seeds::IncludeArchivedSeeds,
15    life_cycle::LifeCycle, privacy_access_control::PrivacyAccessControl, quality::Quality,
16    quantity::Quantity, spatial_relation_type::SpatialRelationType,
17};
18
19pub mod actions;
20pub mod application_settings_impl;
21pub mod areas;
22pub mod areas_impl;
23pub mod base_layer_images;
24pub mod base_layer_images_impl;
25pub mod coordinates_impl;
26pub mod core;
27pub mod drawing_variant_impl;
28pub mod drawings;
29pub mod drawings_impl;
30pub mod guided_tour_impl;
31pub mod layer_impl;
32pub mod layers;
33pub mod map_collaborator_impl;
34pub mod map_impl;
35pub mod new_map_collaborator_impl;
36pub mod new_map_impl;
37pub mod new_seed_impl;
38pub mod page_impl;
39pub mod plantings;
40pub mod plantings_impl;
41pub mod plants_impl;
42pub mod seed_impl;
43pub mod timeline;
44pub mod update_map_geometry_impl;
45pub mod update_map_impl;
46
47/// Contains configuration the frontend needs to run.
48#[typeshare]
49#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, ToSchema)]
50pub struct ConfigDto {
51    /// The base URL of the authorization server
52    pub issuer_uri: String,
53    /// The `client_id` the frontend should use to log in
54    pub client_id: String,
55    /// The version must be an exact match between frontend and backend.
56    pub version: String,
57}
58
59/// Represents seeds of a user.
60#[typeshare]
61#[derive(Serialize, Deserialize, ToSchema)]
62pub struct SeedDto {
63    /// The record id of the seed.
64    pub id: i32,
65    /// An additional name for the seed.
66    pub name: String,
67    /// The id of the plant this seed belongs to.
68    #[serde(skip_serializing_if = "Option::is_none")]
69    pub plant_id: Option<i32>,
70    /// When the seeds were harvested.
71    pub harvest_year: i16,
72    /// How many seeds there are.
73    pub quantity: Quantity,
74    /// When the seeds should be used by.
75    #[serde(skip_serializing_if = "Option::is_none")]
76    pub use_by: Option<NaiveDate>,
77    /// Where the seeds came from.
78    #[serde(skip_serializing_if = "Option::is_none")]
79    pub origin: Option<String>,
80    /// What the seeds taste like.
81    #[serde(skip_serializing_if = "Option::is_none")]
82    pub taste: Option<String>,
83    /// The yield of the seeds.
84    #[serde(skip_serializing_if = "Option::is_none")]
85    pub yield_: Option<String>,
86    /// How many generations the seeds have been grown.
87    #[serde(skip_serializing_if = "Option::is_none")]
88    pub generation: Option<i16>,
89    /// The quality of the seeds.
90    #[serde(skip_serializing_if = "Option::is_none")]
91    pub quality: Option<Quality>,
92    /// How much the seeds cost.
93    #[serde(skip_serializing_if = "Option::is_none")]
94    pub price: Option<i16>,
95    /// Notes about the seeds.
96    #[serde(skip_serializing_if = "Option::is_none")]
97    pub notes: Option<String>,
98    /// The id of the creator of the seed.
99    pub created_by: Uuid,
100    /// Timestamp indicating when the seed was archived.
101    /// Empty if the seed was not archived.
102    #[serde(skip_serializing_if = "Option::is_none")]
103    pub archived_at: Option<String>,
104}
105
106#[allow(clippy::missing_docs_in_private_items)] // TODO: See #97.
107#[typeshare]
108#[derive(Serialize, Deserialize, ToSchema)]
109pub struct NewSeedDto {
110    pub name: String,
111    #[serde(skip_serializing_if = "Option::is_none")]
112    pub plant_id: Option<i32>,
113    pub harvest_year: i16,
114    pub quantity: Quantity,
115    #[serde(skip_serializing_if = "Option::is_none")]
116    pub use_by: Option<NaiveDate>,
117    #[serde(skip_serializing_if = "Option::is_none")]
118    pub origin: Option<String>,
119    #[serde(skip_serializing_if = "Option::is_none")]
120    pub taste: Option<String>,
121    #[serde(skip_serializing_if = "Option::is_none")]
122    pub yield_: Option<String>,
123    #[serde(skip_serializing_if = "Option::is_none")]
124    pub generation: Option<i16>,
125    #[serde(skip_serializing_if = "Option::is_none")]
126    pub quality: Option<Quality>,
127    #[serde(skip_serializing_if = "Option::is_none")]
128    pub price: Option<i16>,
129    #[serde(skip_serializing_if = "Option::is_none")]
130    pub notes: Option<String>,
131}
132
133/// Data that is required when archiving a seed.
134#[typeshare]
135#[derive(Serialize, Deserialize, ToSchema)]
136pub struct ArchiveSeedDto {
137    /// Whether the seed should be archived.
138    pub archived: bool,
139}
140
141/// The essential identifying information of a plant.
142#[typeshare]
143#[derive(Debug, Serialize, PartialEq, Eq, Deserialize, ToSchema)]
144pub struct PlantsSummaryDto {
145    /// The plants database id.
146    pub id: i32,
147    /// Biological name of this plant (E.g. "Triticum aestivum", "Prunus cerasus")
148    pub unique_name: String,
149    /// A list of common english names (E.g. "Bread wheat", "Sour cherry")
150    #[serde(skip_serializing_if = "Option::is_none")]
151    pub common_name_en: Option<Vec<Option<String>>>,
152    /// A list of common german names (E.g. "Brotweizen", "Sauerkirsche")
153    #[serde(skip_serializing_if = "Option::is_none")]
154    pub common_name_de: Option<Vec<Option<String>>>,
155    /// How far a plant spreads (The 'width' of a plant) in cm
156    #[serde(skip_serializing_if = "Option::is_none")]
157    pub spread: Option<i32>,
158    /// Indicates life span of the plant.
159    pub life_cycle: Vec<LifeCycle>,
160    /// Informs about the plants physiology.
161    #[serde(skip_serializing_if = "Option::is_none")]
162    pub herbaceous_or_woody: Option<HerbaceousOrWoody>,
163    #[serde(skip_serializing_if = "Option::is_none")]
164    pub has_drought_tolerance: Option<bool>,
165    #[serde(skip_serializing_if = "Option::is_none")]
166    pub hardiness_zone: Option<String>,
167    #[serde(skip_serializing_if = "Option::is_none")]
168    pub functions: Option<String>,
169    #[serde(skip_serializing_if = "Option::is_none")]
170    pub edible: Option<bool>,
171    pub edible_parts: Vec<Option<String>>,
172    #[serde(skip_serializing_if = "Option::is_none")]
173    pub warning: Option<String>,
174    pub sowing_outdoors: Vec<Option<i16>>,
175    pub harvest_time: Vec<Option<i16>>,
176    pub icon_path: Option<String>,
177}
178
179/// Query parameters for searching plants.
180#[typeshare]
181#[derive(Debug, Deserialize, IntoParams)]
182pub struct PlantsSearchParameters {
183    /// The system will check if this string occurs in the plants common name or unique name.
184    #[serde(skip_serializing_if = "Option::is_none")]
185    pub name: Option<String>,
186}
187
188/// Query parameters for searching spatial plant relations.
189#[typeshare]
190#[derive(Debug, Deserialize, IntoParams)]
191pub struct RelationSearchParameters {
192    /// The id of the plant to find relations for.
193    pub plant_id: i32,
194}
195
196/// Use to return spatial relations for the plant.
197#[typeshare]
198#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
199pub struct RelationsDto {
200    /// The id of the plant in the relation.
201    pub id: i32,
202    /// The type of relation.
203    pub relations: Vec<RelationDto>,
204}
205
206/// Use to return a spatial relation.
207#[typeshare]
208#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
209pub struct RelationDto {
210    /// The id of the plant in the relation.
211    pub id: i32,
212    /// The type of relation.
213    pub relation: SpatialRelationType,
214}
215
216/// Query parameters for searching seeds.
217#[typeshare]
218#[derive(Debug, Deserialize, IntoParams)]
219pub struct SeedSearchParameters {
220    /// Name of the seed to search for.
221    #[serde(skip_serializing_if = "Option::is_none")]
222    pub name: Option<String>,
223    /// The exact harvest year of the seed.
224    #[serde(skip_serializing_if = "Option::is_none")]
225    pub harvest_year: Option<i16>,
226    /// Whether archived, not archived or both kinds of seeds should be included.
227    /// If no value is provided, a default value of `NotArchived` is assumed.
228    #[serde(skip_serializing_if = "Option::is_none")]
229    pub archived: Option<IncludeArchivedSeeds>,
230}
231
232/// Query parameters paginating list endpoints.
233#[typeshare]
234#[derive(Debug, Deserialize, IntoParams)]
235pub struct PageParameters {
236    /// Number of results in per page.
237    #[serde(skip_serializing_if = "Option::is_none")]
238    pub per_page: Option<i32>,
239    /// Page number to be returned.
240    /// Note: pages start at one.
241    #[serde(skip_serializing_if = "Option::is_none")]
242    pub page: Option<i32>,
243}
244
245/// A page of results returned from a list endpoint.
246#[typeshare]
247#[derive(Debug, Serialize, PartialEq, Eq, Deserialize, ToSchema)]
248#[aliases(
249    PagePlantsSummaryDto = Page<PlantsSummaryDto>,
250    PageSeedDto = Page<SeedDto>,
251    PageMapDto = Page<MapDto>,
252    PageLayerDto = Page<LayerDto>
253)]
254pub struct Page<T> {
255    /// Resulting records.
256    pub results: Vec<T>,
257    /// Current page number.
258    pub page: i32,
259    /// Results per page.
260    pub per_page: i32,
261    /// Number of pages in total.
262    pub total_pages: i32,
263}
264
265/// The whole information of a map.
266#[typeshare]
267#[derive(Serialize, Deserialize, ToSchema)]
268pub struct MapDto {
269    /// The id of the map.
270    pub id: i32,
271    /// The name of the map.
272    pub name: String,
273    /// When the map was created.
274    pub created_at: NaiveDateTime,
275    /// When a map was last modified, e.g by modifying plantings.
276    pub modified_at: NaiveDateTime,
277    /// The id of the creator of the map.
278    pub created_by: Uuid,
279    /// By whom the map was last modified.
280    pub modified_by: Uuid,
281    /// The date the map is supposed to be deleted.
282    #[serde(skip_serializing_if = "Option::is_none")]
283    pub deletion_date: Option<NaiveDate>,
284    /// The date the last time the map view was opened by any user.
285    #[serde(skip_serializing_if = "Option::is_none")]
286    pub last_visit: Option<NaiveDate>,
287    /// A flag indicating if this map is marked for deletion.
288    pub is_inactive: bool,
289    /// The zoom factor of the map.
290    pub zoom_factor: i16,
291    /// An enum indicating if this map is private or not.
292    pub privacy: PrivacyAccessControl,
293    /// The description of the map.
294    #[serde(skip_serializing_if = "Option::is_none")]
295    pub description: Option<String>,
296    /// The location of the map as a latitude/longitude point.
297    #[serde(skip_serializing_if = "Option::is_none")]
298    pub location: Option<Coordinates>,
299    /// The geometry of the map.
300    ///
301    /// E.g. `{"rings": [[{"x": 0.0,"y": 0.0},{"x": 1000.0,"y": 0.0},{"x": 1000.0,"y": 1000.0},{"x": 0.0,"y": 1000.0},{"x": 0.0,"y": 0.0}]],"srid": 4326}`
302    #[typeshare(serialized_as = "object")]
303    #[schema(value_type = Object)]
304    pub geometry: Polygon<Point>,
305}
306
307/// The information of a map necessary for its creation.
308#[typeshare]
309#[derive(Serialize, Deserialize, ToSchema)]
310pub struct NewMapDto {
311    /// The name of the map.
312    pub name: String,
313    /// The date the map is supposed to be deleted.
314    #[serde(skip_serializing_if = "Option::is_none")]
315    pub deletion_date: Option<NaiveDate>,
316    /// The date the last time the map view was opened by any user.
317    #[serde(skip_serializing_if = "Option::is_none")]
318    pub last_visit: Option<NaiveDate>,
319    /// A flag indicating if this map is marked for deletion.
320    pub is_inactive: bool,
321    /// The zoom factor of the map.
322    pub zoom_factor: i16,
323    /// An enum indicating if this map is private or not.
324    pub privacy: PrivacyAccessControl,
325    /// The description of the map.
326    #[serde(skip_serializing_if = "Option::is_none")]
327    pub description: Option<String>,
328    /// The location of the map as a latitude/longitude point.
329    #[serde(skip_serializing_if = "Option::is_none")]
330    pub location: Option<Coordinates>,
331    /// The geometry of the map.
332    ///
333    /// E.g. `{"rings": [[{"x": 0.0,"y": 0.0},{"x": 1000.0,"y": 0.0},{"x": 1000.0,"y": 1000.0},{"x": 0.0,"y": 1000.0},{"x": 0.0,"y": 0.0}]],"srid": 4326}`
334    #[typeshare(serialized_as = "object")]
335    #[schema(value_type = Object)]
336    pub geometry: Polygon<Point>,
337}
338
339/// The information for updating a map.
340#[typeshare]
341#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
342pub struct UpdateMapDto {
343    /// The name of the map.
344    #[serde(skip_serializing_if = "Option::is_none")]
345    pub name: Option<String>,
346    /// An enum indicating if this map is private or not.
347    #[serde(skip_serializing_if = "Option::is_none")]
348    pub privacy: Option<PrivacyAccessControl>,
349    /// The description of the map.
350    #[serde(skip_serializing_if = "Option::is_none")]
351    pub description: Option<String>,
352    /// The location of the map as a latitude/longitude point.
353    #[serde(skip_serializing_if = "Option::is_none")]
354    pub location: Option<Coordinates>,
355}
356
357/// Data for updating a maps geometry.
358#[typeshare]
359#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
360pub struct UpdateMapGeometryDto {
361    /// The geometry of the map.
362    ///
363    /// E.g. `{"rings": [[{"x": 0.0,"y": 0.0},{"x": 1000.0,"y": 0.0},{"x": 1000.0,"y": 1000.0},{"x": 0.0,"y": 1000.0},{"x": 0.0,"y": 0.0}]],"srid": 4326}`
364    #[typeshare(serialized_as = "object")]
365    #[schema(value_type = Object)]
366    pub geometry: Polygon<Point>,
367}
368
369/// Query parameters for searching maps.
370#[typeshare]
371#[derive(Debug, Deserialize, IntoParams)]
372pub struct MapSearchParameters {
373    /// Name of the map to search for.
374    #[serde(skip_serializing_if = "Option::is_none")]
375    pub name: Option<String>,
376}
377
378/// Support struct for transmitting latitude/longitude coordinates.
379#[typeshare]
380#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
381pub struct Coordinates {
382    /// Latitude of the point.
383    pub latitude: f64,
384    /// Longitude of the point.
385    pub longitude: f64,
386}
387
388/// Query parameters for connecting to a map.
389#[typeshare]
390#[derive(Debug, Deserialize, IntoParams)]
391pub struct ConnectToMapQueryParams {
392    /// The id of the map to connect to.
393    pub map_id: i32,
394    /// The id of the user connecting to the map.
395    pub user_id: String,
396}
397
398/// Query parameters to configure the generation of the heatmap.
399#[typeshare]
400#[derive(Debug, Deserialize, IntoParams)]
401pub struct HeatMapQueryParams {
402    /// The id of the plant layer the planting will be planted on.
403    pub plant_layer_id: Uuid,
404    /// The id of the shade layer the planting will be planted on.
405    pub shade_layer_id: Uuid,
406    /// The id of the hydrology layer the planting will be planted on.
407    pub hydrology_layer_id: Uuid,
408    /// The id of the soil layer the planting will be planted on.
409    pub soil_layer_id: Uuid,
410    /// The id of the plant you want to plant.
411    pub plant_id: i32,
412    /// The date at which to generate the heatmap.
413    /// Will be set to the current date if `None`.
414    #[serde(skip_serializing_if = "Option::is_none")]
415    pub date: Option<NaiveDate>,
416}
417
418#[typeshare]
419#[derive(Serialize, Deserialize, ToSchema)]
420/// The information about a users tour sent to the frontend.
421pub struct GuidedTourDto {
422    /// IDs of the steps the user has already completed.
423    pub completed_steps: Vec<String>,
424    /// Boolean specifying if the tour is paused for this user.
425    pub paused: bool,
426}
427
428#[typeshare]
429#[derive(Serialize, Deserialize, ToSchema)]
430/// The information sent by the frontend to mark a tour step as completed for a user.
431pub struct CompleteGuidedTourStepDto {
432    /// ID of the step to mark as completed.
433    pub step_key: String,
434}
435
436#[typeshare]
437#[derive(Serialize, Deserialize, ToSchema)]
438/// The information sent by the frontend to mark multiple tour steps as completed for a user.
439pub struct CompleteGuidedTourStepsDto {
440    /// IDs of the steps to mark as completed.
441    pub step_keys: Vec<String>,
442}
443
444/// Application setting
445#[typeshare]
446#[derive(Serialize, Deserialize, ToSchema)]
447pub struct ApplicationSettingDto {
448    /// The id of the setting
449    pub id: i32,
450    /// The unique key of the setting
451    pub key: String,
452    /// The value of the setting
453    pub value: String,
454}
455
456#[typeshare]
457#[derive(Debug, Serialize, ToSchema)]
458#[serde(rename_all = "camelCase")]
459/// Information on user collaborating on a map.
460pub struct MapCollaboratorDto {
461    /// The id of the map.
462    pub map_id: i32,
463    /// The id of the collaborator.
464    pub user_id: Uuid,
465    /// The user name of the collaborator.
466    pub username: String,
467}
468
469#[typeshare]
470#[derive(Debug, Deserialize, ToSchema)]
471#[serde(rename_all = "camelCase")]
472/// The information of a map collaborator necessary for its creation.
473pub struct NewMapCollaboratorDto {
474    /// The id of the collaborator.
475    pub user_id: Uuid,
476}
477
478#[typeshare]
479#[derive(Debug, Serialize, Deserialize, ToSchema)]
480#[serde(rename_all = "camelCase")]
481pub struct DeleteMapCollaboratorDto {
482    /// The id of the collaborator.
483    pub user_id: Uuid,
484}
485
486#[typeshare]
487#[derive(Debug, Deserialize, IntoParams)]
488#[serde(rename_all = "camelCase")]
489/// Query params for searching map collaborators.
490pub struct MapCollaboratorSearchParameters {
491    /// The id of the map.
492    pub map_id: i32,
493}
494
495#[typeshare]
496#[derive(Debug, Deserialize, IntoParams)]
497#[serde(rename_all = "camelCase")]
498/// Query params for searching users.
499pub struct UserSearchParameters {
500    /// The name of the user to search for.
501    pub username: String,
502}