diff --git a/migrations/20241204225135_create_user_table.up.sql b/migrations/20241204225135_create_user_table.up.sql index 5402bd4..bde9aa3 100644 --- a/migrations/20241204225135_create_user_table.up.sql +++ b/migrations/20241204225135_create_user_table.up.sql @@ -5,7 +5,6 @@ CREATE TABLE IF NOT EXISTS "user"( surname VARCHAR(255) NOT NULL, gender boolean NOT NULL, birth_date DATE NOT NULL, - email VARCHAR(255) NOT NULL UNIQUE, role_id BIGSERIAL NOT NULL REFERENCES "role"(id), creation_time TIMESTAMPTZ NOT NULL DEFAULT NOW() ); \ No newline at end of file diff --git a/migrations/20241213232937_contact.down.sql b/migrations/20241213232937_contact.down.sql new file mode 100644 index 0000000..db88a01 --- /dev/null +++ b/migrations/20241213232937_contact.down.sql @@ -0,0 +1,2 @@ +-- Add down migration script here +DROP TABLE IF EXISTS "contact"; \ No newline at end of file diff --git a/migrations/20241213232937_contact.up.sql b/migrations/20241213232937_contact.up.sql new file mode 100644 index 0000000..ec0567d --- /dev/null +++ b/migrations/20241213232937_contact.up.sql @@ -0,0 +1,5 @@ +-- Add up migration script here +CREATE TABLE IF NOT EXISTS "contact"( + user_id BIGSERIAL PRIMARY KEY NOT NULL UNIQUE, + email VARCHAR(255) NOT NULL UNIQUE +); \ No newline at end of file diff --git a/src/database.rs b/src/database.rs index 76e69cf..041977d 100644 --- a/src/database.rs +++ b/src/database.rs @@ -1,5 +1,6 @@ pub mod comment; pub mod comment_interaction; +pub mod contact; pub mod interaction; pub mod permission; pub mod post; diff --git a/src/database/comment.rs b/src/database/comment.rs index 085172d..53fe03e 100644 --- a/src/database/comment.rs +++ b/src/database/comment.rs @@ -47,11 +47,11 @@ pub async fn update( sqlx::query_as!( Comment, r#" - UPDATE "comment" SET "comment" = $1 WHERE "creation_time" = $2 + UPDATE "comment" SET "comment" = $2 WHERE "creation_time" = $1 RETURNING * "#, - comment, - creation_time + creation_time, + comment ) .fetch_one(database_connection) .await diff --git a/src/database/comment_interaction.rs b/src/database/comment_interaction.rs index 8280c00..1a21908 100644 --- a/src/database/comment_interaction.rs +++ b/src/database/comment_interaction.rs @@ -47,11 +47,11 @@ pub async fn update( sqlx::query_as!( CommentInteraction, r#" - UPDATE "comment_interaction" SET "interaction_id" = $1 WHERE "interaction_time" = $2 + UPDATE "comment_interaction" SET "interaction_id" = $2 WHERE "interaction_time" = $1 RETURNING * "#, - interaction_id, - interaction_time + interaction_time, + interaction_id ) .fetch_one(database_connection) .await diff --git a/src/database/contact.rs b/src/database/contact.rs new file mode 100644 index 0000000..e39fafb --- /dev/null +++ b/src/database/contact.rs @@ -0,0 +1,69 @@ +use sqlx::{Pool, Postgres}; + +use crate::feature::contact::Contact; + +pub async fn create( + email: &String, + database_connection: &Pool, +) -> Result { + sqlx::query_as!( + Contact, + r#" + INSERT INTO "contact"(email) + VALUES ($1) + RETURNING * + "#, + email, + ) + .fetch_one(database_connection) + .await +} + +pub async fn read( + user_id: &i64, + database_connection: &Pool, +) -> Result { + sqlx::query_as!( + Contact, + r#" + SELECT * FROM "contact" WHERE "user_id" = $1 + "#, + user_id + ) + .fetch_one(database_connection) + .await +} + +pub async fn update( + user_id: &i64, + email: &String, + database_connection: &Pool, +) -> Result { + sqlx::query_as!( + Contact, + r#" + UPDATE "contact" SET "email" = $2 WHERE "user_id" = $1 + RETURNING * + "#, + user_id, + email, + ) + .fetch_one(database_connection) + .await +} + +pub async fn delete( + user_id: &i64, + database_connection: &Pool, +) -> Result { + sqlx::query_as!( + Contact, + r#" + DELETE FROM "contact" where "user_id" = $1 + RETURNING * + "#, + user_id + ) + .fetch_one(database_connection) + .await +} diff --git a/src/database/interaction.rs b/src/database/interaction.rs index c69860a..9300764 100644 --- a/src/database/interaction.rs +++ b/src/database/interaction.rs @@ -42,11 +42,11 @@ pub async fn update( sqlx::query_as!( Interaction, r#" - UPDATE "interaction" SET "name" = $1 WHERE "id" = $2 + UPDATE "interaction" SET "name" = $2 WHERE "id" = $1 RETURNING * "#, - name, - id + id, + name ) .fetch_one(database_connection) .await diff --git a/src/database/post.rs b/src/database/post.rs index 079203d..9b3f0bf 100644 --- a/src/database/post.rs +++ b/src/database/post.rs @@ -46,12 +46,12 @@ pub async fn update( sqlx::query_as!( Post, r#" - UPDATE "post" SET poster_id = $1, post = $2 WHERE "creation_time" = $3 + UPDATE "post" SET poster_id = $2, post = $3 WHERE "creation_time" = $1 RETURNING * "#, + creation_time, poster_id, - post, - creation_time + post ) .fetch_one(database_connection) .await diff --git a/src/database/post_interaction.rs b/src/database/post_interaction.rs index aea0fe8..bffd1e4 100644 --- a/src/database/post_interaction.rs +++ b/src/database/post_interaction.rs @@ -47,11 +47,11 @@ pub async fn update( sqlx::query_as!( PostInteraction, r#" - UPDATE "post_interaction" SET "interaction_id" = $1 WHERE "interaction_time" = $2 + UPDATE "post_interaction" SET "interaction_id" = $2 WHERE "interaction_time" = $1 RETURNING * "#, + interaction_time, interaction_id, - interaction_time ) .fetch_one(database_connection) .await diff --git a/src/database/role.rs b/src/database/role.rs index 01096de..cbbd62e 100644 --- a/src/database/role.rs +++ b/src/database/role.rs @@ -39,11 +39,11 @@ pub async fn update( sqlx::query_as!( Role, r#" - UPDATE "role" SET "name" = $1 WHERE "id" = $2 + UPDATE "role" SET "name" = $2 WHERE "id" = $1 RETURNING * "#, + id, name, - id ) .fetch_one(database_connection) .await diff --git a/src/database/user.rs b/src/database/user.rs index 553015d..9a03bf5 100644 --- a/src/database/user.rs +++ b/src/database/user.rs @@ -8,21 +8,19 @@ pub async fn create( surname: &String, gender: &bool, birth_date: &NaiveDate, - email: &String, database_connection: &Pool, ) -> Result { sqlx::query_as!( User, r#" - INSERT INTO "user"(name, surname, gender, birth_date, email, role_id) - VALUES ($1, $2, $3, $4, $5, $6) + INSERT INTO "user"(name, surname, gender, birth_date, role_id) + VALUES ($1, $2, $3, $4, $5) RETURNING * "#, name, surname, gender, birth_date, - email, 2 ) .fetch_one(database_connection) @@ -47,15 +45,14 @@ pub async fn update( surname: &String, gender: &bool, birth_date: &NaiveDate, - email: &String, role_id: &i64, database_connection: &Pool, ) -> Result { sqlx::query_as!(User, r#" - UPDATE "user" SET "name" = $1, "surname" = $2, "gender" = $3, "birth_date" = $4, "email" = $5, "role_id" = $6 WHERE "id" = $7 + UPDATE "user" SET "name" = $2, "surname" = $3, "gender" = $4, "birth_date" = $5, "role_id" = $6 WHERE "id" = $1 RETURNING * - "#, name, surname, gender, birth_date, email, role_id, id).fetch_one(database_connection).await + "#, id, name, surname, gender, birth_date, role_id).fetch_one(database_connection).await } pub async fn delete(id: &i64, database_connection: &Pool) -> Result { @@ -82,21 +79,6 @@ pub async fn read_all(database_connection: &Pool) -> Result, .await } -pub async fn read_with_email( - email: &String, - database_connection: &Pool, -) -> Result { - sqlx::query_as!( - User, - r#" - SELECT * FROM "user" WHERE "email" = $1 - "#, - email - ) - .fetch_one(database_connection) - .await -} - pub async fn read_all_for_name( name: &String, database_connection: &Pool, @@ -172,21 +154,6 @@ pub async fn read_all_for_gender( .await } -pub async fn read_id_with_email( - email: &String, - database_connection: &Pool, -) -> Result { - Ok(sqlx::query!( - r#" - SELECT "id" FROM "user" WHERE "email" = $1 - "#, - email - ) - .fetch_one(database_connection) - .await? - .id) -} - pub async fn read_all_id(database_connection: &Pool) -> Result, sqlx::Error> { Ok(sqlx::query!( r#" diff --git a/src/feature.rs b/src/feature.rs index 5b8ba5b..58ee13e 100644 --- a/src/feature.rs +++ b/src/feature.rs @@ -1,5 +1,6 @@ pub mod comment; pub mod comment_interaction; +pub mod contact; pub mod interaction; pub mod permission; pub mod post; diff --git a/src/feature/contact.rs b/src/feature/contact.rs new file mode 100644 index 0000000..cd9544b --- /dev/null +++ b/src/feature/contact.rs @@ -0,0 +1,7 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize)] +pub struct Contact { + pub user_id: i64, + pub email: String, +} diff --git a/src/feature/user.rs b/src/feature/user.rs index 969b087..1083088 100644 --- a/src/feature/user.rs +++ b/src/feature/user.rs @@ -1,5 +1,8 @@ use chrono::{DateTime, NaiveDate, Utc}; use serde::{Deserialize, Serialize}; +use sqlx::{Pool, Postgres}; + +use crate::database::user; #[derive(Debug, Serialize, Deserialize)] pub struct Contact { @@ -15,7 +18,54 @@ pub struct User { pub surname: String, pub gender: bool, pub birth_date: NaiveDate, - pub email: String, pub role_id: i64, pub creation_time: DateTime, } + +impl User { + pub async fn create( + name: &String, + surname: &String, + gender: &bool, + birth_date: &NaiveDate, + database_connection: &Pool, + ) -> Result { + user::create(name, surname, gender, birth_date, database_connection).await + } + + pub async fn read(id: &i64, database_connection: &Pool) -> Result { + user::read(id, database_connection).await + } + + pub async fn update( + id: &i64, + name: &String, + surname: &String, + gender: &bool, + birth_date: &NaiveDate, + role_id: &i64, + database_connection: &Pool, + ) -> Result { + user::update( + id, + name, + surname, + gender, + birth_date, + role_id, + database_connection, + ) + .await + } + + pub async fn delete( + id: &i64, + database_connection: &Pool, + ) -> Result { + user::delete(id, database_connection).await + } + + pub async fn read_all(database_connection: &Pool) -> Result, sqlx::Error> { + user::read_all(database_connection).await + } +} diff --git a/src/routing.rs b/src/routing.rs index 362f6d2..5b7c0a6 100644 --- a/src/routing.rs +++ b/src/routing.rs @@ -1,4 +1,5 @@ pub mod role; +pub mod user; use axum::{extract::State, http::StatusCode, response::IntoResponse, routing::get, Router}; use tower_http::cors::CorsLayer; @@ -12,6 +13,10 @@ pub async fn route(State(app_state): State) -> Router { "/role", role::route(axum::extract::State(app_state.clone())), ) + .nest( + "/user", + user::route(axum::extract::State(app_state.clone())), + ) .layer(CorsLayer::permissive()) .with_state(app_state) } diff --git a/src/routing/role.rs b/src/routing/role.rs index f921079..57ebbac 100644 --- a/src/routing/role.rs +++ b/src/routing/role.rs @@ -5,21 +5,36 @@ use axum::{ routing::{delete, get, patch, post}, Json, Router, }; +use serde::{Deserialize, Serialize}; use crate::{feature::role::Role, AppState}; +#[derive(Debug, Serialize, Deserialize)] +struct CreateRole { + name: String, +} + +#[derive(Debug, Serialize, Deserialize)] +struct UpdateRole { + id: i64, + name: String, +} + pub fn route(State(app_state): State) -> Router { Router::new() - .route("/:name", post(create)) + .route("/", post(create)) .route("/:id", get(read)) - .route("/:id/:name", patch(update)) - .route("/:id", delete(_delete)) + .route("/", patch(update)) + .route("/:id", delete(delete_)) .route("/", get(read_all)) .with_state(app_state) } -async fn create(Path(name): Path, State(app_state): State) -> impl IntoResponse { - match Role::create(&name, &app_state.database_connection).await { +async fn create( + State(app_state): State, + Json(create_role): Json, +) -> impl IntoResponse { + match Role::create(&create_role.name, &app_state.database_connection).await { Ok(role) => (StatusCode::CREATED, Json(serde_json::json!(role))), Err(err_val) => ( StatusCode::BAD_REQUEST, @@ -28,7 +43,7 @@ async fn create(Path(name): Path, State(app_state): State) -> } } -async fn read(Path(id): Path, State(app_state): State) -> impl IntoResponse { +async fn read(State(app_state): State, Path(id): Path) -> impl IntoResponse { match Role::read(&id, &app_state.database_connection).await { Ok(role) => (StatusCode::OK, Json(serde_json::json!(role))), Err(err_val) => ( @@ -39,10 +54,16 @@ async fn read(Path(id): Path, State(app_state): State) -> impl In } async fn update( - Path((id, name)): Path<(i64, String)>, State(app_state): State, + Json(update_role): Json, ) -> impl IntoResponse { - match Role::update(&id, &name, &app_state.database_connection).await { + match Role::update( + &update_role.id, + &update_role.name, + &app_state.database_connection, + ) + .await + { Ok(role) => (StatusCode::ACCEPTED, Json(serde_json::json!(role))), Err(err_val) => ( StatusCode::BAD_REQUEST, @@ -51,7 +72,7 @@ async fn update( } } -async fn _delete(Path(id): Path, State(app_state): State) -> impl IntoResponse { +async fn delete_(State(app_state): State, Path(id): Path) -> impl IntoResponse { match Role::delete(&id, &app_state.database_connection).await { Ok(role) => (StatusCode::NO_CONTENT, Json(serde_json::json!(role))), Err(err_val) => ( diff --git a/src/routing/user.rs b/src/routing/user.rs new file mode 100644 index 0000000..58a0b14 --- /dev/null +++ b/src/routing/user.rs @@ -0,0 +1,113 @@ +use axum::{ + extract::{Path, State}, + http::StatusCode, + response::IntoResponse, + routing::{delete, get, patch, post}, + Json, Router, +}; +use chrono::NaiveDate; +use serde::{Deserialize, Serialize}; + +use crate::{feature::user::User, AppState}; + +#[derive(Debug, Serialize, Deserialize)] +struct CreateUser { + name: String, + surname: String, + gender: bool, + birth_date: NaiveDate, +} + +#[derive(Debug, Serialize, Deserialize)] +struct UpdateUser { + id: i64, + name: String, + surname: String, + gender: bool, + birth_date: NaiveDate, + role_id: i64, +} + +pub fn route(State(app_state): State) -> Router { + Router::new() + .route("/", post(create)) + .route("/:id", get(read)) + .route("/", patch(update)) + .route("/:id", delete(delete_)) + .route("/", get(read_all)) + .with_state(app_state) +} + +async fn create( + State(app_state): State, + Json(create_user): Json, +) -> impl IntoResponse { + match User::create( + &create_user.name, + &create_user.surname, + &create_user.gender, + &create_user.birth_date, + &app_state.database_connection, + ) + .await + { + Ok(user) => (StatusCode::CREATED, Json(serde_json::json!(user))), + Err(err_val) => ( + StatusCode::BAD_REQUEST, + Json(serde_json::json!(err_val.to_string())), + ), + } +} + +async fn read(State(app_state): State, Path(id): Path) -> impl IntoResponse { + match User::read(&id, &app_state.database_connection).await { + Ok(user) => (StatusCode::OK, Json(serde_json::json!(user))), + Err(err_val) => ( + StatusCode::BAD_REQUEST, + Json(serde_json::json!(err_val.to_string())), + ), + } +} + +async fn update( + State(app_state): State, + Json(update_user): Json, +) -> impl IntoResponse { + match User::update( + &update_user.id, + &update_user.name, + &update_user.surname, + &update_user.gender, + &update_user.birth_date, + &update_user.role_id, + &app_state.database_connection, + ) + .await + { + Ok(user) => (StatusCode::ACCEPTED, Json(serde_json::json!(user))), + Err(err_val) => ( + StatusCode::BAD_REQUEST, + Json(serde_json::json!(err_val.to_string())), + ), + } +} + +async fn delete_(State(app_state): State, Path(id): Path) -> impl IntoResponse { + match User::delete(&id, &app_state.database_connection).await { + Ok(user) => (StatusCode::NO_CONTENT, Json(serde_json::json!(user))), + Err(err_val) => ( + StatusCode::BAD_REQUEST, + Json(serde_json::json!(err_val.to_string())), + ), + } +} + +async fn read_all(State(app_state): State) -> impl IntoResponse { + match User::read_all(&app_state.database_connection).await { + Ok(users) => (StatusCode::OK, Json(serde_json::json!(users))), + Err(err_val) => ( + StatusCode::BAD_REQUEST, + Json(serde_json::json!(err_val.to_string())), + ), + } +}