✨ Some basic rust code for new backend
This commit is contained in:
@@ -12,3 +12,4 @@ node_modules/
|
||||
survey.json
|
||||
.coverage
|
||||
export_deta.py
|
||||
target/
|
||||
|
||||
Generated
+2337
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,3 @@
|
||||
SPDX-FileCopyrightText: 2023 Marlon W (Mawoka)
|
||||
|
||||
SPDX-License-Identifier: MPL-2.0
|
||||
@@ -0,0 +1,27 @@
|
||||
# SPDX-FileCopyrightText: 2023 Marlon W (Mawoka)
|
||||
#
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
|
||||
[workspace]
|
||||
resolver = "2"
|
||||
|
||||
members = ["app", "live", "shared"]
|
||||
|
||||
[workspace.dependencies]
|
||||
sqlx = { version = "0.7", features = [
|
||||
"runtime-tokio",
|
||||
"postgres",
|
||||
"uuid",
|
||||
"chrono",
|
||||
"json",
|
||||
"macros",
|
||||
"migrate",
|
||||
] }
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = { version = "1", features = ["raw_value"] }
|
||||
tokio = { version = "1.36", features = ["full"] }
|
||||
chrono = { version = "0.4", features = ["clock", "serde"] }
|
||||
dotenvy = "0.15"
|
||||
uuid = { version = "1.7.0", features = ["serde", "v4", "fast-rng", "v7"] }
|
||||
anyhow = "1"
|
||||
@@ -0,0 +1,11 @@
|
||||
# SPDX-FileCopyrightText: 2023 Marlon W (Mawoka)
|
||||
#
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
|
||||
[package]
|
||||
name = "app"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
@@ -0,0 +1,7 @@
|
||||
// SPDX-FileCopyrightText: 2023 Marlon W (Mawoka)
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
fn main() {
|
||||
println!("Hello, world!");
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
# SPDX-FileCopyrightText: 2023 Marlon W (Mawoka)
|
||||
#
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
[package]
|
||||
name = "live"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
@@ -0,0 +1,7 @@
|
||||
// SPDX-FileCopyrightText: 2023 Marlon W (Mawoka)
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
fn main() {
|
||||
println!("Hello, world!");
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
# SPDX-FileCopyrightText: 2023 Marlon W (Mawoka)
|
||||
#
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
[package]
|
||||
name = "shared"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
strum = { version = "0.26", features = ["derive"] }
|
||||
sqlx = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
uuid = { workspace = true }
|
||||
chrono = { workspace = true }
|
||||
validator = { version = "0.18", features = ["derive"] }
|
||||
garde = { version = "0.20", features = ["full"] }
|
||||
@@ -0,0 +1,6 @@
|
||||
// SPDX-FileCopyrightText: 2023 Marlon W (Mawoka)
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
|
||||
pub mod models;
|
||||
@@ -0,0 +1,154 @@
|
||||
// SPDX-FileCopyrightText: 2023 Marlon W (Mawoka)
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid;
|
||||
use garde::{Validate, Valid};
|
||||
|
||||
#[derive(strum::Display)]
|
||||
#[strum(serialize_all = "UPPERCASE")]
|
||||
pub enum UserAuthTypes {
|
||||
Local,
|
||||
Google,
|
||||
Github,
|
||||
Custom,
|
||||
}
|
||||
|
||||
pub struct User {
|
||||
pub id: Uuid,
|
||||
pub email: String,
|
||||
pub password: Option<String>,
|
||||
pub verified: bool,
|
||||
pub verify_key: Option<String>,
|
||||
pub created_at: chrono::NaiveDateTime,
|
||||
pub auth_type: UserAuthTypes,
|
||||
pub google_uid: Option<String>,
|
||||
pub avatar: Vec<u8>,
|
||||
pub github_user_id: Option<i32>,
|
||||
pub require_password: bool,
|
||||
pub backup_code: String,
|
||||
pub totp_secret: String,
|
||||
pub storage_used: i64,
|
||||
}
|
||||
|
||||
pub struct FidoCredentials {
|
||||
pub pk: i32,
|
||||
pub id: Vec<u8>,
|
||||
pub public_key: Vec<u8>,
|
||||
pub sign_count: i32,
|
||||
pub user: Uuid,
|
||||
}
|
||||
|
||||
pub struct ApiKey {
|
||||
pub key: String,
|
||||
pub user: Option<Uuid>,
|
||||
}
|
||||
|
||||
pub struct UserSession {
|
||||
pub id: Uuid,
|
||||
pub user: Option<Uuid>,
|
||||
pub session_key: String,
|
||||
pub created_at: chrono::NaiveDateTime,
|
||||
pub ip_address: String,
|
||||
pub user_agent: String,
|
||||
pub last_seen: chrono::NaiveDateTime,
|
||||
}
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub struct ABCDQuizAnswer {
|
||||
right: bool,
|
||||
answer: String,
|
||||
color: Option<String>,
|
||||
}
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub struct RangeQuizAnswer {
|
||||
min: i32,
|
||||
max: i32,
|
||||
min_correct: i32,
|
||||
max_correct: i32,
|
||||
}
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub struct VotingQuizAnswer {
|
||||
answer: String,
|
||||
image: Option<String>,
|
||||
color: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(strum::Display, Debug, Serialize, Deserialize, Clone, PartialEq)]
|
||||
#[strum(serialize_all = "UPPERCASE")]
|
||||
pub enum QuizQuestionType {
|
||||
Abcd,
|
||||
Range,
|
||||
Voting,
|
||||
Slide,
|
||||
Text,
|
||||
Order,
|
||||
Check,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub struct TextQuizAnswer {
|
||||
answer: String,
|
||||
case_sensitive: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Validate)]
|
||||
pub struct QuizQuestion {
|
||||
#[garde(skip)]
|
||||
question: String,
|
||||
#[garde(skip)]
|
||||
time: i32,
|
||||
#[serde(default = "default_type")]
|
||||
#[serde(rename = "type")]
|
||||
#[garde(skip)]
|
||||
question_type: Option<QuizQuestionType>,
|
||||
#[garde(custom(validate_answers))]
|
||||
answers: QuizAnswers,
|
||||
#[garde(skip)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
image: Option<String>,
|
||||
#[garde(skip)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
hide_results: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
enum QuizAnswers {
|
||||
ABCD(Vec<ABCDQuizAnswer>),
|
||||
Range(RangeQuizAnswer),
|
||||
Text(Vec<TextQuizAnswer>),
|
||||
Voting(Vec<VotingQuizAnswer>),
|
||||
Slide(String),
|
||||
}
|
||||
|
||||
fn default_type() -> Option<QuizQuestionType> {
|
||||
Some(QuizQuestionType::Abcd)
|
||||
}
|
||||
|
||||
// impl Validate for QuizQuestion {
|
||||
// fn validate(&self) -> Result<(), ValidationErrors> {
|
||||
// match validate_answers(&self.answers, self) {
|
||||
// Ok(_) => Ok(()),
|
||||
// Err(e) => {
|
||||
// let mut error = ValidationErrors::new();
|
||||
// error.add("answers", e);
|
||||
// Err(error)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
fn validate_answers(answers: &QuizAnswers) -> garde::Result {
|
||||
match (&context.question_type, answers) {
|
||||
(Some(QuizQuestionType::Abcd), QuizAnswers::ABCD(_)) => Ok(()),
|
||||
(Some(QuizQuestionType::Range), QuizAnswers::Range(_)) => Ok(()),
|
||||
(Some(QuizQuestionType::Voting), QuizAnswers::Voting(_)) => Ok(()),
|
||||
(Some(QuizQuestionType::Text), QuizAnswers::Text(_)) => Ok(()),
|
||||
(Some(QuizQuestionType::Order), QuizAnswers::Voting(_)) => Ok(()),
|
||||
(Some(QuizQuestionType::Slide), QuizAnswers::Slide(_)) => Ok(()),
|
||||
(Some(QuizQuestionType::Check), QuizAnswers::ABCD(_)) => Ok(()),
|
||||
_ => Err(garde::Error::new("invalid_answers")),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
<!--
|
||||
SPDX-FileCopyrightText: 2023 Marlon W (Mawoka)
|
||||
|
||||
SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
-->
|
||||
|
||||
# Migration of the Backend to Rust (long term goal)
|
||||
Reference in New Issue
Block a user