Skip to content

Commit 8357fbe

Browse files
docs & roles in questions
1 parent 6b18074 commit 8357fbe

File tree

18 files changed

+3171
-680
lines changed

18 files changed

+3171
-680
lines changed

backend/api.yaml

Lines changed: 1686 additions & 578 deletions
Large diffs are not rendered by default.

backend/server/src/models/answer.rs

Lines changed: 158 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
//! Answer management module for the Chaos application.
2+
//!
3+
//! This module provides functionality for managing answers to application questions,
4+
//! including creation, retrieval, updating, and deletion of answers. It supports
5+
//! various question types such as short answer, multiple choice, and ranking questions.
6+
17
use crate::models::error::ChaosError;
28
use crate::models::question::QuestionType;
39
use chrono::{DateTime, Utc};
@@ -6,9 +12,11 @@ use snowflake::SnowflakeIdGenerator;
612
use sqlx::{Postgres, Transaction};
713
use std::ops::DerefMut;
814

9-
/// The `Answer` type that will be sent in API responses.
10-
///
11-
///
15+
/// Represents an answer in the system.
16+
///
17+
/// An answer is a response to a question in an application. The answer data is
18+
/// stored in a type-specific format based on the question type.
19+
///
1220
/// With the chosen `serde` representation and the use of `#[serde(flatten)]`, the JSON for a
1321
/// `Answer` will look like this:
1422
/// ```json
@@ -23,43 +31,81 @@ use std::ops::DerefMut;
2331
/// ```
2432
#[derive(Deserialize, Serialize)]
2533
pub struct Answer {
34+
/// Unique identifier for the answer
2635
id: i64,
36+
/// ID of the question this answer is for
2737
question_id: i64,
2838

39+
/// The actual answer data, flattened in serialization
2940
#[serde(flatten)]
3041
answer_data: AnswerData,
3142

43+
/// When the answer was created
3244
created_at: DateTime<Utc>,
45+
/// When the answer was last updated
3346
updated_at: DateTime<Utc>,
3447
}
3548

49+
/// Data structure for creating a new answer.
50+
///
51+
/// Contains the question ID and the answer data.
3652
#[derive(Deserialize)]
3753
pub struct NewAnswer {
54+
/// ID of the question this answer is for
3855
pub question_id: i64,
3956

57+
/// The actual answer data, flattened in serialization
4058
#[serde(flatten)]
4159
pub answer_data: AnswerData,
4260
}
4361

62+
/// Raw answer data from the database.
63+
///
64+
/// Contains all fields needed to construct an Answer structure,
65+
/// including the question type and various answer formats.
4466
#[derive(Deserialize, sqlx::FromRow)]
4567
pub struct AnswerRawData {
68+
/// Unique identifier for the answer
4669
id: i64,
70+
/// ID of the question this answer is for
4771
question_id: i64,
72+
/// Type of the question
4873
question_type: QuestionType,
74+
/// Text answer for short answer questions
4975
short_answer_answer: Option<String>,
76+
/// Selected options for multiple choice/select questions
5077
multi_option_answers: Option<Vec<i64>>,
78+
/// Ranked options for ranking questions
5179
ranking_answers: Option<Vec<i64>>,
80+
/// When the answer was created
5281
created_at: DateTime<Utc>,
82+
/// When the answer was last updated
5383
updated_at: DateTime<Utc>,
5484
}
5585

86+
/// Data structure for identifying an answer by type and application.
5687
#[derive(Deserialize)]
5788
pub struct AnswerTypeApplicationId {
89+
/// Type of the question
5890
question_type: QuestionType,
91+
/// ID of the application this answer belongs to
5992
application_id: i64,
6093
}
6194

6295
impl Answer {
96+
/// Creates a new answer.
97+
///
98+
/// # Arguments
99+
///
100+
/// * `application_id` - ID of the application this answer belongs to
101+
/// * `question_id` - ID of the question being answered
102+
/// * `answer_data` - The answer data
103+
/// * `snowflake_generator` - Generator for creating unique IDs
104+
/// * `transaction` - Database transaction to use
105+
///
106+
/// # Returns
107+
///
108+
/// * `Result<i64, ChaosError>` - ID of the created answer or error
63109
pub async fn create(
64110
application_id: i64,
65111
question_id: i64,
@@ -88,6 +134,16 @@ impl Answer {
88134
Ok(id)
89135
}
90136

137+
/// Retrieves an answer by its ID.
138+
///
139+
/// # Arguments
140+
///
141+
/// * `id` - ID of the answer to retrieve
142+
/// * `transaction` - Database transaction to use
143+
///
144+
/// # Returns
145+
///
146+
/// * `Result<Answer, ChaosError>` - Answer details or error
91147
pub async fn get(
92148
id: i64,
93149
transaction: &mut Transaction<'_, Postgres>,
@@ -146,6 +202,18 @@ impl Answer {
146202
})
147203
}
148204

205+
/// Retrieves all common answers for an application.
206+
///
207+
/// Common answers are those that apply to all roles in the application.
208+
///
209+
/// # Arguments
210+
///
211+
/// * `application_id` - ID of the application to get answers for
212+
/// * `transaction` - Database transaction to use
213+
///
214+
/// # Returns
215+
///
216+
/// * `Result<Vec<Answer>, ChaosError>` - List of answers or error
149217
pub async fn get_all_common_by_application(
150218
application_id: i64,
151219
transaction: &mut Transaction<'_, Postgres>,
@@ -211,6 +279,17 @@ impl Answer {
211279
Ok(answers)
212280
}
213281

282+
/// Retrieves all answers for an application and role.
283+
///
284+
/// # Arguments
285+
///
286+
/// * `application_id` - ID of the application to get answers for
287+
/// * `role_id` - ID of the role to get answers for
288+
/// * `transaction` - Database transaction to use
289+
///
290+
/// # Returns
291+
///
292+
/// * `Result<Vec<Answer>, ChaosError>` - List of answers or error
214293
pub async fn get_all_by_application_and_role(
215294
application_id: i64,
216295
role_id: i64,
@@ -279,6 +358,17 @@ impl Answer {
279358
Ok(answers)
280359
}
281360

361+
/// Updates an existing answer.
362+
///
363+
/// # Arguments
364+
///
365+
/// * `id` - ID of the answer to update
366+
/// * `answer_data` - New answer data
367+
/// * `transaction` - Database transaction to use
368+
///
369+
/// # Returns
370+
///
371+
/// * `Result<(), ChaosError>` - Success or error
282372
pub async fn update(
283373
id: i64,
284374
answer_data: AnswerData,
@@ -315,6 +405,16 @@ impl Answer {
315405
Ok(())
316406
}
317407

408+
/// Deletes an answer.
409+
///
410+
/// # Arguments
411+
///
412+
/// * `id` - ID of the answer to delete
413+
/// * `transaction` - Database transaction to use
414+
///
415+
/// # Returns
416+
///
417+
/// * `Result<(), ChaosError>` - Success or error
318418
pub async fn delete(
319419
id: i64,
320420
transaction: &mut Transaction<'_, Postgres>,
@@ -327,17 +427,34 @@ impl Answer {
327427
}
328428
}
329429

430+
/// Represents the different types of answer data.
431+
///
432+
/// Each variant corresponds to a different question type and contains
433+
/// the appropriate data format for that type.
330434
#[derive(Deserialize, Serialize)]
331-
#[serde(tag = "answer_type", content = "data")]
332435
pub enum AnswerData {
436+
/// Text answer for short answer questions
333437
ShortAnswer(String),
438+
/// Single selected option for multiple choice questions
334439
MultiChoice(i64),
440+
/// Multiple selected options for multi-select questions
335441
MultiSelect(Vec<i64>),
442+
/// Single selected option for dropdown questions
336443
DropDown(i64),
444+
/// Ranked list of options for ranking questions
337445
Ranking(Vec<i64>),
338446
}
339447

340448
impl AnswerData {
449+
/// Creates a new AnswerData instance based on a question type.
450+
///
451+
/// # Arguments
452+
///
453+
/// * `question_type` - Type of the question
454+
///
455+
/// # Returns
456+
///
457+
/// * `AnswerData` - New answer data instance
341458
fn from_question_type(question_type: &QuestionType) -> Self {
342459
match question_type {
343460
QuestionType::ShortAnswer => AnswerData::ShortAnswer("".to_string()),
@@ -348,6 +465,18 @@ impl AnswerData {
348465
}
349466
}
350467

468+
/// Creates an AnswerData instance from raw database data.
469+
///
470+
/// # Arguments
471+
///
472+
/// * `question_type` - Type of the question
473+
/// * `short_answer_answer` - Text answer for short answer questions
474+
/// * `multi_option_answers` - Selected options for multiple choice/select questions
475+
/// * `ranking_answers` - Ranked options for ranking questions
476+
///
477+
/// # Returns
478+
///
479+
/// * `AnswerData` - New answer data instance
351480
fn from_answer_raw_data(
352481
question_type: QuestionType,
353482
short_answer_answer: Option<String>,
@@ -378,6 +507,11 @@ impl AnswerData {
378507
}
379508
}
380509

510+
/// Validates the answer data.
511+
///
512+
/// # Returns
513+
///
514+
/// * `Result<(), ChaosError>` - Success if valid, error if not
381515
pub fn validate(&self) -> Result<(), ChaosError> {
382516
match self {
383517
Self::ShortAnswer(text) => {
@@ -396,6 +530,16 @@ impl AnswerData {
396530
Ok(())
397531
}
398532

533+
/// Inserts the answer data into the database.
534+
///
535+
/// # Arguments
536+
///
537+
/// * `answer_id` - ID of the answer to insert data for
538+
/// * `transaction` - Database transaction to use
539+
///
540+
/// # Returns
541+
///
542+
/// * `Result<(), ChaosError>` - Success or error
399543
pub async fn insert_into_db(
400544
self,
401545
answer_id: i64,
@@ -457,6 +601,16 @@ impl AnswerData {
457601
}
458602
}
459603

604+
/// Deletes the answer data from the database.
605+
///
606+
/// # Arguments
607+
///
608+
/// * `answer_id` - ID of the answer to delete data for
609+
/// * `transaction` - Database transaction to use
610+
///
611+
/// # Returns
612+
///
613+
/// * `Result<(), ChaosError>` - Success or error
460614
pub async fn delete_from_db(
461615
self,
462616
answer_id: i64,

backend/server/src/models/app.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ pub async fn app() -> Result<Router, ChaosError> {
158158
.put(RatingHandler::update),
159159
)
160160
.route(
161-
"/api/v1/:application_id/rating",
161+
"/api/v1/application/:application_id/rating",
162162
post(ApplicationHandler::create_rating),
163163
)
164164
.route(

0 commit comments

Comments
 (0)