summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSanto Cariotti <santo@dcariotti.me>2022-09-06 17:58:35 +0000
committerSanto Cariotti <santo@dcariotti.me>2022-09-06 17:58:35 +0000
commitacc32ccc1650b99e03c390a87e71b0a85b073162 (patch)
tree0de545ee0eb8eba5961c57c0a73ff7031e97613d
parente6dbcbb42e7a4a973887acde633cc3ee233aad3e (diff)
Create a 3d model object
-rw-r--r--Cargo.lock2
-rw-r--r--Cargo.toml4
-rw-r--r--migrations/20220903093057_add-users-table.sql2
-rw-r--r--migrations/20220906164354_add-models-table.sql13
-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
10 files changed, 167 insertions, 5 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 18a84e2..e711a7c 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -231,6 +231,7 @@ dependencies = [
"js-sys",
"num-integer",
"num-traits",
+ "serde",
"time 0.1.44",
"wasm-bindgen",
"winapi",
@@ -1299,6 +1300,7 @@ dependencies = [
"bitflags",
"byteorder",
"bytes",
+ "chrono",
"crc",
"crossbeam-queue",
"dirs",
diff --git a/Cargo.toml b/Cargo.toml
index 40df836..13dee30 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -16,7 +16,7 @@ tokio = { version = "1.20", features = ["full"] }
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
tower-http = { version = "0.3.4", features = ["trace", "compression-br", "propagate-header", "sensitive-headers"] }
-sqlx = { version = "0.6", features = [ "runtime-tokio-rustls", "postgres" ] }
+sqlx = { version = "0.6", features = [ "runtime-tokio-rustls", "postgres", "chrono" ] }
sha256 = "1.0.3"
validator = { version = "0.16.0", features = ["derive"] }
-chrono = "0.4"
+chrono = { version = "0.4", features = ["serde"] }
diff --git a/migrations/20220903093057_add-users-table.sql b/migrations/20220903093057_add-users-table.sql
index b55eae6..73c2396 100644
--- a/migrations/20220903093057_add-users-table.sql
+++ b/migrations/20220903093057_add-users-table.sql
@@ -1,5 +1,5 @@
CREATE TABLE users (
- id SERIAL UNIQUE PRIMARY KEY,
+ id SERIAL PRIMARY KEY,
email VARCHAR(100) UNIQUE NOT NULL,
username VARCHAR(100) UNIQUE NOT NULL,
password VARCHAR(100) NOT NULL,
diff --git a/migrations/20220906164354_add-models-table.sql b/migrations/20220906164354_add-models-table.sql
new file mode 100644
index 0000000..84425ba
--- /dev/null
+++ b/migrations/20220906164354_add-models-table.sql
@@ -0,0 +1,13 @@
+CREATE TABLE models (
+ id SERIAL PRIMARY KEY,
+ name VARCHAR NOT NULL,
+ description TEXT,
+ duration INTEGER NOT NULL,
+ height INTEGER NOT NULL,
+ weight INTEGER NOT NULL,
+ printer VARCHAR,
+ material VARCHAR,
+ author_id INTEGER REFERENCES users(id) NOT NULL,
+ created TIMESTAMP NOT NULL,
+ updated TIMESTAMP NOT NULL
+);
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))
+}