lacoctelera/routes/author/
post.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
// Copyright 2024 Felipe Torres González
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

use crate::{
    authentication::{check_access, AuthData},
    domain::Author,
    routes::author::utils::register_new_author,
};
use actix_web::{
    post,
    web::{Data, Json, Query},
    HttpResponse,
};
use serde_json::json;
use sqlx::MySqlPool;
use std::error::Error;
use tracing::{debug, info, instrument};

/// Resource that allows the inclusion of a new recipe's author in the DB.
///
/// # Description
///
/// This method creates a new author entry in the DB, which is described by the **Author** schema. When a new author
/// is aimed to be registered in the DB, only providing a valid email address is mandatory. A confirmation email will
/// be sent to that email, so unvalidated authors won't be able to register content in the DB. This is a measure to
/// avoid spamming content in the DB.
///
/// When an author registers without providing a name, a *funny name* will be assigned by the backend logic.
///
/// Authors are identified by an unique ID, thus there's no issue when the same names are registered multiple times.
///
/// This resource requires clients of the API to provide an API token.
#[utoipa::path(
    post,
    path = "/author",
    tag = "Author",
    security(
        ("api_key" = [])
    ),
    responses(
        (
            status = 200,
            description = "The Author descriptor was inserted in the DB.",
            content_type = "application/json",
            example = json!({"id": "0192e8d9-36cf-7ce3-82ef-0a7c9b2deefe"}),
            headers(
                ("Content-Length"),
                ("Content-Type"),
                ("Date"),
                ("Vary", description = "Origin,Access-Control-Request-Method,Access-Control-Request-Headers")
            ),
        ),
        (
            status = 404,
            description = "The given author's ID was not found in the DB.",
            headers(
                ("Content-Length"),
                ("Date"),
                ("Vary", description = "Origin,Access-Control-Request-Method,Access-Control-Request-Headers")
            ),
        ),
        (
            status = 429, description = "**Too many requests.**",
            headers(
                ("Cache-Control", description = "Cache control is set to *no-cache*."),
                ("Access-Control-Allow-Origin"),
                ("Retry-After", description = "Amount of time between requests (seconds).")
            )
        )
    )
)]
#[instrument(skip(pool, token))]
#[post("")]
pub async fn post_author(
    req: Json<Author>,
    pool: Data<MySqlPool>,
    token: Query<AuthData>,
) -> Result<HttpResponse, Box<dyn Error>> {
    // Access control
    check_access(&pool, &token.api_key).await?;
    debug!("Access granted");

    // Log the received payload
    debug!("Author entry: {:?}", req);

    // Store the received entry in the DB.
    let id = register_new_author(&pool, &req).await?;
    info!("New Author entry registered with id: {id}");

    Ok(HttpResponse::Ok().json(json!({
        "id": id.to_string()
    })))
}