backend/controller/
seed.rs

1//! `Seed` endpoints.
2
3use actix_web::web::Query;
4use actix_web::{
5    delete, get, patch, post, put,
6    web::{Json, Path},
7    HttpResponse, Result,
8};
9use uuid::Uuid;
10
11use crate::{
12    config::{
13        auth::user_info::UserInfo,
14        data::{SharedBroadcaster, SharedPool},
15    },
16    model::dto::{
17        actions::{Action, ActionType, UpdatePlantingAdditionalNamePayload},
18        ArchiveSeedDto, NewSeedDto, PageParameters, SeedSearchParameters,
19    },
20    service,
21};
22
23/// Endpoint for fetching all [`SeedDto`](crate::model::dto::SeedDto).
24/// If no page parameters are provided, the first page is returned.
25/// Seeds are ordered using their `use_by` date in an ascending fashion.
26///
27/// By default, archived seeds will not be returned.
28/// This behaviour can be changed using `search_parameters`.
29///
30/// # Errors
31/// * If the connection to the database could not be established.
32#[utoipa::path(
33    context_path = "/api/seeds",
34    params(
35        SeedSearchParameters,
36        PageParameters
37    ),
38    responses(
39        (status = 200, description = "Fetch all seeds", body = PageSeedDto)
40    ),
41    security(
42        ("oauth2" = [])
43    )
44)]
45#[get("")]
46pub async fn find(
47    search_query: Query<SeedSearchParameters>,
48    page_query: Query<PageParameters>,
49    user_info: UserInfo,
50    pool: SharedPool,
51) -> Result<HttpResponse> {
52    let response = service::seed::find(
53        search_query.into_inner(),
54        page_query.into_inner(),
55        user_info.id,
56        &pool,
57    )
58    .await?;
59    Ok(HttpResponse::Ok().json(response))
60}
61
62/// Endpoint for fetching a [`Seed`](crate::model::entity::Seed).
63///
64/// # Errors
65/// * If the connection to the database could not be established.
66#[utoipa::path(
67    context_path = "/api/seeds",
68    responses(
69        (status = 200, description = "Fetch seed by id", body = SeedDto)
70    ),
71    security(
72        ("oauth2" = [])
73    )
74)]
75#[get("/{id}")]
76pub async fn find_by_id(
77    id: Path<i32>,
78    user_info: UserInfo,
79    pool: SharedPool,
80) -> Result<HttpResponse> {
81    let response = service::seed::find_by_id(*id, user_info.id, &pool).await?;
82    Ok(HttpResponse::Ok().json(response))
83}
84
85/// Endpoint for creating a new [`Seed`](crate::model::entity::Seed).
86///
87/// # Errors
88/// * If the connection to the database could not be established.
89#[utoipa::path(
90    context_path = "/api/seeds",
91    request_body = NewSeedDto,
92    responses(
93        (status = 201, description = "Create a seed", body = SeedDto)
94    ),
95    security(
96        ("oauth2" = [])
97    )
98)]
99#[post("")]
100pub async fn create(
101    new_seed_json: Json<NewSeedDto>,
102    user_info: UserInfo,
103    pool: SharedPool,
104) -> Result<HttpResponse> {
105    let response = service::seed::create(new_seed_json.0, user_info.id, &pool).await?;
106    Ok(HttpResponse::Created().json(response))
107}
108
109/// Endpoint for deleting a [`Seed`](crate::model::entity::Seed).
110///
111/// # Errors
112/// * If the connection to the database could not be established.
113#[utoipa::path(
114    context_path = "/api/seeds",
115    responses(
116        (status = 200, description = "Delete a seed", body = String)
117    ),
118    security(
119        ("oauth2" = [])
120    )
121)]
122#[delete("/{id}")]
123pub async fn delete_by_id(
124    path: Path<i32>,
125    user_info: UserInfo,
126    pool: SharedPool,
127) -> Result<HttpResponse> {
128    service::seed::delete_by_id(*path, user_info.id, &pool).await?;
129    Ok(HttpResponse::Ok().json(""))
130}
131
132/// Endpoint for editing a [`Seed`](crate::model::entity::Seed).
133///
134/// # Errors
135/// * If the connection to the database could not be established.
136#[put("/{id}")]
137pub async fn edit_by_id(
138    id: Path<i32>,
139    edit_seed_json: Json<NewSeedDto>,
140    user_info: UserInfo,
141    pool: SharedPool,
142    broadcaster: SharedBroadcaster,
143) -> Result<HttpResponse> {
144    let response = service::seed::edit(*id, user_info.id, edit_seed_json.0, &pool).await?;
145    let affected_plantings = service::plantings::find_by_seed_id(*id, &pool);
146
147    for planting in affected_plantings.await? {
148        broadcaster
149            .broadcast_all_maps(Action {
150                action_id: Uuid::new_v4(),
151                user_id: user_info.id,
152                action: ActionType::UpdatePlantingAdditionalName(
153                    UpdatePlantingAdditionalNamePayload::new(
154                        &planting,
155                        Some(response.name.clone()),
156                    ),
157                ),
158            })
159            .await;
160    }
161
162    Ok(HttpResponse::Accepted().json(response))
163}
164
165/// Endpoint archiving/unarchiving a [`Seed`](crate::model::entity::Seed).
166/// A timestamp will be recorded when the seed is first archived.
167///
168/// # Errors
169/// * If the connection to the database could not be established.
170#[patch("/{id}/archive")]
171pub async fn archive(
172    id: Path<i32>,
173    archive_seed_json: Json<ArchiveSeedDto>,
174    user_info: UserInfo,
175    pool: SharedPool,
176) -> Result<HttpResponse> {
177    let response = service::seed::archive(*id, user_info.id, archive_seed_json.0, &pool).await?;
178    Ok(HttpResponse::Accepted().json(response))
179}