summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main.rs3
-rw-r--r--src/models/auth.rs2
-rw-r--r--src/models/mod.rs1
-rw-r--r--src/models/model.rs105
-rw-r--r--src/routes/mod.rs1
-rw-r--r--src/routes/model.rs39
6 files changed, 149 insertions, 2 deletions
diff --git a/src/main.rs b/src/main.rs
index 4a211fd..1c9d63a 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -35,7 +35,8 @@ async fn create_app() -> Router {
let api_routes = Router::new()
.nest("/users", routes::user::create_route())
- .nest("/auth", routes::auth::create_route());
+ .nest("/auth", routes::auth::create_route())
+ .nest("/models", routes::model::create_route());
Router::new()
// Map all routes to `/v1/*` namespace
diff --git a/src/models/auth.rs b/src/models/auth.rs
index 7f9ae00..4453bc7 100644
--- a/src/models/auth.rs
+++ b/src/models/auth.rs
@@ -18,7 +18,7 @@ struct Keys {
#[derive(Serialize, Deserialize)]
pub struct Claims {
/// ID from the user model
- user_id: i32,
+ pub user_id: i32,
/// Expiration timestamp
exp: usize,
}
diff --git a/src/models/mod.rs b/src/models/mod.rs
index f9bae3d..7e61662 100644
--- a/src/models/mod.rs
+++ b/src/models/mod.rs
@@ -1,2 +1,3 @@
pub mod auth;
+pub mod model;
pub mod user;
diff --git a/src/models/model.rs b/src/models/model.rs
new file mode 100644
index 0000000..1fe9b61
--- /dev/null
+++ b/src/models/model.rs
@@ -0,0 +1,105 @@
+use crate::db::get_client;
+use crate::errors::AppError;
+
+use chrono::{Local, NaiveDateTime};
+use serde::{Deserialize, Serialize};
+use validator::Validate;
+
+/// Model for models.
+#[derive(Deserialize, Serialize, Validate)]
+pub struct Model {
+ id: i32,
+ #[validate(length(min = 2, message = "Can not be empty"))]
+ name: String,
+ description: Option<String>,
+ duration: i32,
+ height: i32,
+ weight: i32,
+ printer: Option<String>,
+ material: Option<String>,
+ author_id: i32,
+ created: NaiveDateTime,
+ updated: NaiveDateTime,
+}
+
+/// Payload used for model creation
+#[derive(Deserialize)]
+pub struct ModelCreate {
+ pub name: String,
+ pub description: Option<String>,
+ pub duration: i32,
+ pub height: i32,
+ pub weight: i32,
+ pub printer: Option<String>,
+ pub material: Option<String>,
+}
+
+impl Model {
+ pub fn new(
+ name: String,
+ description: Option<String>,
+ duration: i32,
+ height: i32,
+ weight: i32,
+ printer: Option<String>,
+ material: Option<String>,
+ author_id: i32,
+ ) -> Self {
+ let now = Local::now().naive_utc();
+ Self {
+ id: 0,
+ name,
+ description,
+ duration,
+ height,
+ weight,
+ printer,
+ material,
+ author_id,
+ created: now,
+ updated: now,
+ }
+ }
+
+ /// Create a new model
+ pub async fn create(model: Model) -> Result<Model, AppError> {
+ let pool = unsafe { get_client() };
+
+ model
+ .validate()
+ .map_err(|error| AppError::BadRequest(error.to_string()))?;
+
+ let rec = sqlx::query_as!(
+ Model,
+ r#"
+ INSERT INTO models (name, description, duration, height, weight, printer, material, author_id, created, updated)
+ VALUES ( $1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
+ RETURNING *
+ "#,
+ model.name,
+ model.description,
+ model.duration,
+ model.height,
+ model.weight,
+ model.printer,
+ model.material,
+ model.author_id,
+ model.created,
+ model.updated,
+ )
+ .fetch_one(pool)
+ .await?;
+
+ Ok(rec)
+ }
+
+ /// List all models
+ pub async fn list() -> Result<Vec<Model>, AppError> {
+ let pool = unsafe { get_client() };
+ let rows = sqlx::query_as!(Model, r#"SELECT * FROM models"#)
+ .fetch_all(pool)
+ .await?;
+
+ Ok(rows)
+ }
+}
diff --git a/src/routes/mod.rs b/src/routes/mod.rs
index f9bae3d..7e61662 100644
--- a/src/routes/mod.rs
+++ b/src/routes/mod.rs
@@ -1,2 +1,3 @@
pub mod auth;
+pub mod model;
pub mod user;
diff --git a/src/routes/model.rs b/src/routes/model.rs
new file mode 100644
index 0000000..b1d4cc2
--- /dev/null
+++ b/src/routes/model.rs
@@ -0,0 +1,39 @@
+use crate::errors::AppError;
+use crate::models::{
+ auth::Claims,
+ model::{Model, ModelCreate},
+};
+use axum::{routing::get, Json, Router};
+
+/// Create routes for `/v1/models/` namespace
+pub fn create_route() -> Router {
+ Router::new().route("/", get(list_models).post(create_model))
+}
+
+/// List models.
+async fn list_models() -> Result<Json<Vec<Model>>, AppError> {
+ let models = Model::list().await?;
+
+ Ok(Json(models))
+}
+
+/// Create a model. Checks Authorization token
+async fn create_model(
+ Json(payload): Json<ModelCreate>,
+ claims: Claims,
+) -> Result<Json<Model>, AppError> {
+ let model = Model::new(
+ payload.name,
+ payload.description,
+ payload.duration,
+ payload.height,
+ payload.weight,
+ payload.printer,
+ payload.material,
+ claims.user_id,
+ );
+
+ let model_new = Model::create(model).await?;
+
+ Ok(Json(model_new))
+}