backend/controller/
guided_tour.rs

1//! `GuidedTour` endpoints.
2
3use actix_web::{get, post, web::Json, HttpResponse, Result};
4
5use crate::{
6    config::{auth::user_info::UserInfo, data::SharedPool},
7    model::dto::{CompleteGuidedTourStepDto, CompleteGuidedTourStepsDto},
8    service,
9};
10
11/// Endpoint for fetching the guided tour info of the requesting user.
12///
13/// Returns:
14/// - completed steps
15/// - paused boolean (computed from `paused_at` + `pause_count`)
16///
17/// # Errors
18/// * If the connection to the database could not be established.
19#[utoipa::path(
20    context_path = "/api/tour",
21    responses(
22        (status = 200, description = "Fetch guided tour info for the requesting user", body = GuidedTourDto)
23    ),
24    security(
25        ("oauth2" = [])
26    )
27)]
28#[get("")]
29pub async fn find_by_user(user_info: UserInfo, pool: SharedPool) -> Result<HttpResponse> {
30    let response = service::guided_tour::find_by_user(user_info.id, &pool).await?;
31    Ok(HttpResponse::Ok().json(response))
32}
33
34/// Pause the guided tour for the requesting user.
35///
36/// Backend will:
37/// - set `paused_at` = `now()`
38/// - increment `pause_count` (or insert `pause_count=1` if row doesn't exist)
39///
40/// # Errors
41/// * If the connection to the database could not be established.
42#[utoipa::path(
43    context_path = "/api/tour",
44    responses(
45        (status = 204, description = "Pause the guided tour for the requesting user")
46    ),
47    security(
48        ("oauth2" = [])
49    )
50)]
51#[post("/pause")]
52pub async fn pause(user_info: UserInfo, pool: SharedPool) -> Result<HttpResponse> {
53    service::guided_tour::pause(user_info.id, &pool).await?;
54    Ok(HttpResponse::NoContent().finish())
55}
56
57/// Mark a single guided tour step as completed (idempotent).
58///
59/// # Errors
60/// * If the connection to the database could not be established.
61#[utoipa::path(
62    context_path = "/api/tour",
63    request_body = CompleteGuidedTourStepDto,
64    responses(
65        (status = 204, description = "Mark a guided tour step as completed")
66    ),
67    security(
68        ("oauth2" = [])
69    )
70)]
71#[post("/steps/complete")]
72pub async fn complete_step(
73    body: Json<CompleteGuidedTourStepDto>,
74    user_info: UserInfo,
75    pool: SharedPool,
76) -> Result<HttpResponse> {
77    service::guided_tour::complete_step(user_info.id, body.0, &pool).await?;
78    Ok(HttpResponse::NoContent().finish())
79}
80
81/// Mark multiple guided tour steps as completed (idempotent).
82///
83/// # Errors
84/// * If the connection to the database could not be established.
85#[utoipa::path(
86    context_path = "/api/tour",
87    request_body = CompleteGuidedTourStepsDto,
88    responses(
89        (status = 204, description = "Mark multiple guided tour steps as completed")
90    ),
91    security(
92        ("oauth2" = [])
93    )
94)]
95#[post("/steps/complete-bulk")]
96pub async fn complete_steps_bulk(
97    body: Json<CompleteGuidedTourStepsDto>,
98    user_info: UserInfo,
99    pool: SharedPool,
100) -> Result<HttpResponse> {
101    service::guided_tour::complete_steps(user_info.id, body.0.step_keys, &pool).await?;
102    Ok(HttpResponse::NoContent().finish())
103}