diff --git a/Cargo.toml b/Cargo.toml
index 80e2e9b..e9f910e 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -18,10 +18,13 @@ strip = "symbols"
tokio = { version = "1.43.0", default-features = false,features = ["macros", "rt-multi-thread", "time"] }
serde = { version = "1.0.217", default-features = false, features = ["derive"] }
serde_json = { version = "1.0.135" , default-features = false}
-axum = { version = "0.8.1", default-features = false, features = ["http2", "json", "tokio"]}
+axum = { version = "0.8.1", default-features = false, features = ["http1", "json", "tokio"]}
chrono = { version = "0.4.39", default-features = false, features = ["serde"] }
jwt-simple = { version = "0.12.11", default-features = false, features = ["pure-rust"] }
lettre = { version = "0.11.11", default-features = false, features = ["builder", "serde", "smtp-transport", "tokio1-rustls-tls"] }
sqlx = { version = "0.8.3", default-features = false, features = ["chrono", "macros", "migrate", "postgres", "runtime-tokio-rustls"] }
tower = { version = "0.5.2", default-features = false, features = ["limit"] }
-tower-http = { version = "0.6.2", default-features = false, features = ["cors"] }
+tower-http = { version = "0.6.2", default-features = false, features = ["cors", "trace"] }
+axum-macros = "0.5.0"
+tracing-subscriber = "0.3.19"
+tracing = "0.1.41"
diff --git a/configs/database_config.toml b/configs/database_config.toml
index 88aab43..9fdcb5a 100644
--- a/configs/database_config.toml
+++ b/configs/database_config.toml
@@ -4,4 +4,5 @@ username = "root"
password = "root"
database = "rust_forum"
backend = "postgres"
-connection_pool_size = "100"
\ No newline at end of file
+connection_pool_size = 100
+default_user_role_id = 10
diff --git a/mail_templates/one_time_password.toml b/mail_templates/one_time_password.toml
index 6cdadf6..a52031c 100644
--- a/mail_templates/one_time_password.toml
+++ b/mail_templates/one_time_password.toml
@@ -1,3 +1,3 @@
[one_time_password]
subject = "Your One Time Password"
-body = "Dear *, \nHere is your One Time Password = * \n Best Wishes"
\ No newline at end of file
+body = "Dear *,
Here is your One Time Password = *
Best Wishes"
diff --git a/migrations/20241204225135_create_user_table.up.sql b/migrations/20241204225135_create_user_table.up.sql
index e1bee62..a57a049 100644
--- a/migrations/20241204225135_create_user_table.up.sql
+++ b/migrations/20241204225135_create_user_table.up.sql
@@ -3,8 +3,8 @@ CREATE TABLE IF NOT EXISTS "user"(
user_id BIGSERIAL PRIMARY KEY NOT NULL UNIQUE,
name VARCHAR(256) NOT NULL,
surname VARCHAR(256) NOT NULL,
- gender boolean NOT NULL,
+ gender BOOLEAN NOT NULL,
birth_date DATE NOT NULL,
- role_id BIGSERIAL NOT NULL REFERENCES "role"(id),
+ role_id BIGINT NOT NULL REFERENCES "role" DEFAULT 10,
creation_time TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
diff --git a/migrations/20241213232937_contact.up.sql b/migrations/20241213232937_contact.up.sql
index cca60e8..cfc4961 100644
--- a/migrations/20241213232937_contact.up.sql
+++ b/migrations/20241213232937_contact.up.sql
@@ -2,4 +2,6 @@
CREATE TABLE IF NOT EXISTS "contact"(
id BIGSERIAL PRIMARY KEY NOT NULL UNIQUE,
name VARCHAR(32) NOT NULL UNIQUE
-);
\ No newline at end of file
+);
+
+INSERT INTO "contact"(id, name) VALUES (0, 'Email') ON CONFLICT(id) DO UPDATE SET "name" = 'Email';
diff --git a/migrations/20241215002127_user_contact.up.sql b/migrations/20241215002127_user_contact.up.sql
index 67440c1..f0f7f52 100644
--- a/migrations/20241215002127_user_contact.up.sql
+++ b/migrations/20241215002127_user_contact.up.sql
@@ -2,5 +2,6 @@
CREATE TABLE IF NOT EXISTS "user_contact"(
user_id BIGSERIAL NOT NULL REFERENCES "user"(user_id),
contact_id BIGSERIAL NOT NULL REFERENCES "contact"(id),
+ contact_value VARCHAR(256) NOT NULL,
PRIMARY KEY (user_id, contact_id)
);
diff --git a/src/database/user.rs b/src/database/user.rs
index 0b95b9d..fb03f3d 100644
--- a/src/database/user.rs
+++ b/src/database/user.rs
@@ -13,15 +13,14 @@ pub async fn create(
sqlx::query_as!(
User,
r#"
- INSERT INTO "user"(name, surname, gender, birth_date, role_id)
- VALUES ($1, $2, $3, $4, $5)
+ INSERT INTO "user"(name, surname, gender, birth_date)
+ VALUES ($1, $2, $3, $4)
RETURNING *
"#,
name,
surname,
gender,
birth_date,
- 2
)
.fetch_one(&*DATABASE_CONNECTIONS)
.await
diff --git a/src/database/user_contact.rs b/src/database/user_contact.rs
index e6d908f..4b09ddd 100644
--- a/src/database/user_contact.rs
+++ b/src/database/user_contact.rs
@@ -2,16 +2,21 @@ use crate::feature::user_contact::UserContact;
use super::DATABASE_CONNECTIONS;
-pub async fn create(user_id: &i64, contact_id: &i64) -> Result {
+pub async fn create(
+ user_id: &i64,
+ contact_id: &i64,
+ contact_value: &String,
+) -> Result {
sqlx::query_as!(
UserContact,
r#"
- INSERT INTO "user_contact"(user_id, contact_id)
- VALUES ($1, $2)
+ INSERT INTO "user_contact"(user_id, contact_id, contact_value)
+ VALUES ($1, $2, $3)
RETURNING *
"#,
user_id,
contact_id,
+ contact_value,
)
.fetch_one(&*DATABASE_CONNECTIONS)
.await
@@ -24,21 +29,25 @@ pub async fn read(user_id: &i64, contact_id: &i64) -> Result Result {
+pub async fn update(
+ user_id: &i64,
+ contact_id: &i64,
+ contact_value: &String,
+) -> Result {
sqlx::query_as!(
UserContact,
r#"
- UPDATE "user_contact" SET "contact_id" = $2 WHERE "user_id" = $1
- RETURNING *
+ UPDATE "user_contact" SET "contact_value" = $3 WHERE "user_id" = $1 AND "contact_id" = $2 RETURNING *
"#,
user_id,
contact_id,
+ contact_value,
)
.fetch_one(&*DATABASE_CONNECTIONS)
.await
diff --git a/src/feature/login.rs b/src/feature/login.rs
index 069c930..9781a84 100644
--- a/src/feature/login.rs
+++ b/src/feature/login.rs
@@ -14,6 +14,11 @@ use super::user::User;
static TOKEN_META: LazyLock = LazyLock::new(TokenMeta::init);
+#[derive(Debug, Serialize, Deserialize)]
+pub struct CustomClaim {
+ pub user_id: i64,
+}
+
pub struct TokenMeta {
token_key: HS256Key,
token_verification_options: Option,
@@ -33,9 +38,9 @@ impl TokenMeta {
async fn create_token(user_id: &i64) -> Option {
let key = &TOKEN_META.token_key;
-
+ let custom_claim = CustomClaim { user_id: *user_id };
let claims = Claims::with_custom_claims(
- *user_id,
+ custom_claim,
jwt_simple::prelude::Duration::from_mins(
SERVER_CONFIG.login_token_expiration_time_limit as u64,
),
@@ -48,11 +53,10 @@ impl TokenMeta {
}
}
- pub async fn verify_token(token: &String) -> Result, jwt_simple::Error> {
- let token_meta = &TOKEN_META;
- token_meta
+ pub async fn verify_token(token: &String) -> Result, jwt_simple::Error> {
+ TOKEN_META
.token_key
- .verify_token::(token, token_meta.token_verification_options.clone())
+ .verify_token::(token, TOKEN_META.token_verification_options.clone())
}
}
diff --git a/src/feature/user_contact.rs b/src/feature/user_contact.rs
index 13dcdc2..1b00f2a 100644
--- a/src/feature/user_contact.rs
+++ b/src/feature/user_contact.rs
@@ -6,19 +6,28 @@ use crate::database::user_contact;
pub struct UserContact {
pub user_id: i64,
pub contact_id: i64,
+ pub contact_value: String,
}
impl UserContact {
- pub async fn create(user_id: &i64, contact_id: &i64) -> Result {
- user_contact::create(user_id, contact_id).await
+ pub async fn create(
+ user_id: &i64,
+ contact_id: &i64,
+ contact_value: &String,
+ ) -> Result {
+ user_contact::create(user_id, contact_id, contact_value).await
}
pub async fn read(user_id: &i64, contact_id: &i64) -> Result {
user_contact::read(user_id, contact_id).await
}
- pub async fn update(user_id: &i64, contact_id: &i64) -> Result {
- user_contact::update(user_id, contact_id).await
+ pub async fn update(
+ user_id: &i64,
+ contact_id: &i64,
+ contact_value: &String,
+ ) -> Result {
+ user_contact::update(user_id, contact_id, contact_value).await
}
pub async fn delete(user_id: &i64, contact_id: &i64) -> Result {
diff --git a/src/lib.rs b/src/lib.rs
index 296bdd0..72f208a 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -57,6 +57,11 @@ impl Default for ServerConfig {
fn default() -> Self {
let (header, mut server_configs) = naive_toml_parser(SERVER_CONFIG_FILE_LOCATION);
let value_or_max = |value: String| value.parse().map_or(usize::MAX, |value| value);
+ let value_or_semaphore_max = |value: String| {
+ value
+ .parse()
+ .map_or(tokio::sync::Semaphore::MAX_PERMITS, |value| value)
+ };
if header == "[server_config]" {
Self {
@@ -66,7 +71,7 @@ impl Default for ServerConfig {
server_configs.pop_front().unwrap(),
),
login_token_refresh_time_limit: value_or_max(server_configs.pop_front().unwrap()),
- concurrency_limit: value_or_max(server_configs.pop_front().unwrap()),
+ concurrency_limit: value_or_semaphore_max(server_configs.pop_front().unwrap()),
}
} else {
panic!("Server Config File Must Include [server_config] at the First Line")
diff --git a/src/mail.rs b/src/mail.rs
index 69f9980..1887180 100644
--- a/src/mail.rs
+++ b/src/mail.rs
@@ -66,7 +66,7 @@ impl MailTemplate {
MailTemplate::OneTimePassword(mail_fields) => {
let mut mail_template_from_file =
naive_toml_parser(ONE_TIME_PASSWORD_MAIL_TEMPLATE_FILE_LOCATION);
- if mail_template_from_file.0 == "one_time_password" {
+ if mail_template_from_file.0 == "[one_time_password]" {
let subject = match mail_template_from_file.1.pop_front() {
Some(subject) => subject,
None => return Err(ForumMailError::TemplateLackOfParameter),
@@ -106,7 +106,7 @@ async fn send_mail(
)
.to(format!("<{}>", receiver).parse().unwrap())
.subject(subject)
- .header(ContentType::TEXT_PLAIN)
+ .header(ContentType::TEXT_HTML)
.body(body.to_owned())
.unwrap();
diff --git a/src/main.rs b/src/main.rs
index d093ffb..ae033f2 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,8 +1,11 @@
use rust_forum::server::start_server;
+use tracing::Level;
#[tokio::main]
async fn main() {
println!("Hello, world!");
-
+ tracing_subscriber::fmt()
+ .with_max_level(Level::TRACE)
+ .init();
start_server().await;
}
diff --git a/src/routing.rs b/src/routing.rs
index c0fb739..8065596 100644
--- a/src/routing.rs
+++ b/src/routing.rs
@@ -12,13 +12,14 @@ pub mod user_contact;
use axum::{http::StatusCode, response::IntoResponse, routing::get, Router};
use tower::limit::ConcurrencyLimitLayer;
-use tower_http::cors::CorsLayer;
+use tower_http::{cors::CorsLayer, trace::TraceLayer};
use crate::database;
pub async fn route(concurrency_limit: &usize) -> Router {
Router::new()
.route("/", get(alive))
+ .nest("/logins", login::route())
.nest("/roles", role::route())
.nest("/users", user::route())
.nest("/posts", post::route())
@@ -30,6 +31,7 @@ pub async fn route(concurrency_limit: &usize) -> Router {
.nest("/user_contacts", user_contact::route())
.layer(CorsLayer::permissive())
.layer(ConcurrencyLimitLayer::new(*concurrency_limit))
+ .layer(TraceLayer::new_for_http())
}
pub async fn alive() -> impl IntoResponse {
diff --git a/src/routing/comment.rs b/src/routing/comment.rs
index 5bbb1b9..9ee9649 100644
--- a/src/routing/comment.rs
+++ b/src/routing/comment.rs
@@ -26,10 +26,10 @@ struct UpdateComment {
pub fn route() -> Router {
Router::new()
.route("/", post(create))
- .route("/:creation_time", get(read))
+ .route("/{creation_time}", get(read))
.route("/", patch(update))
- .route("/:creation_time", delete(delete_))
- .route("/posts/:post_creation_time", get(read_all_for_post))
+ .route("/{creation_time}", delete(delete_))
+ .route("/posts/{post_creation_time}", get(read_all_for_post))
}
async fn create(Json(create_comment): Json) -> impl IntoResponse {
diff --git a/src/routing/comment_interaction.rs b/src/routing/comment_interaction.rs
index b17eaf8..8fcbe3a 100644
--- a/src/routing/comment_interaction.rs
+++ b/src/routing/comment_interaction.rs
@@ -28,11 +28,11 @@ struct UpdateCommentInteraction {
pub fn route() -> Router {
Router::new()
.route("/", post(create))
- .route("/:interaction_time", get(read))
+ .route("/{interaction_time}", get(read))
.route("/", patch(update))
- .route("/:interaction_time", delete(delete_))
+ .route("/{interaction_time}", delete(delete_))
.route(
- "/comments/:comment_creation_time",
+ "/comments/{comment_creation_time}",
get(read_all_for_comment),
)
}
diff --git a/src/routing/contact.rs b/src/routing/contact.rs
index d4d1f27..32b7fbe 100644
--- a/src/routing/contact.rs
+++ b/src/routing/contact.rs
@@ -23,9 +23,9 @@ struct UpdateContact {
pub fn route() -> Router {
Router::new()
.route("/", post(create))
- .route("/:id", get(read))
+ .route("/{id}", get(read))
.route("/", patch(update))
- .route("/:id", delete(delete_))
+ .route("/{id}", delete(delete_))
.route("/", get(read_all))
}
diff --git a/src/routing/interaction.rs b/src/routing/interaction.rs
index e098688..63e6b60 100644
--- a/src/routing/interaction.rs
+++ b/src/routing/interaction.rs
@@ -23,9 +23,9 @@ struct UpdateInteraction {
pub fn route() -> Router {
Router::new()
.route("/", post(create))
- .route("/:id", get(read))
+ .route("/{id}", get(read))
.route("/", patch(update))
- .route("/:id", delete(delete_))
+ .route("/{id}", delete(delete_))
.route("/", get(read_all))
}
diff --git a/src/routing/login.rs b/src/routing/login.rs
index c6d8aa3..6fd5e90 100644
--- a/src/routing/login.rs
+++ b/src/routing/login.rs
@@ -7,7 +7,14 @@ use axum::{
};
use serde::{Deserialize, Serialize};
-use crate::feature::{auth::OneTimePassword, login::Login};
+use crate::feature::{auth::OneTimePassword, login::Login, user::User, user_contact::UserContact};
+
+const CONTACT_EMAIL_DEFAULT_ID: i64 = 0;
+
+#[derive(Debug, Serialize, Deserialize)]
+struct CreateOneTimePassword {
+ pub user_id: i64,
+}
#[derive(Debug, Serialize, Deserialize)]
struct CreateLogin {
@@ -22,15 +29,34 @@ struct UpdateLogin {
pub fn route() -> Router {
Router::new()
+ .route("/one_time_password", post(create_one_time_password))
.route("/", post(create))
- .route("/users/:user_id/token/:token", get(read))
+ .route("/users/{user_id}/tokens/{token}", get(read))
.route("/", patch(update))
- .route("/users/:user_id/token/:token", delete(delete_))
- .route("/users/:user_id", get(read_all_for_user))
- .route("/users/:user_id", delete(delete_all_for_user))
- .route("/count/users/:user_id", get(count_all_for_user))
+ .route("/users/{user_id}/tokens/{token}", delete(delete_))
+ .route("/users/{user_id}", get(read_all_for_user))
+ .route("/users/{user_id}", delete(delete_all_for_user))
+ .route("/count/users/{user_id}", get(count_all_for_user))
+}
+async fn create_one_time_password(
+ Json(create_one_time_password): Json,
+) -> impl IntoResponse {
+ //todo get user from middleware or something
+ let user = User::read(&create_one_time_password.user_id).await.unwrap();
+ match UserContact::read(&user.user_id, &CONTACT_EMAIL_DEFAULT_ID).await {
+ Ok(user_email) => match OneTimePassword::new(&user, &user_email.contact_value).await {
+ Ok(_) => (StatusCode::CREATED, Json(serde_json::json!(""))),
+ Err(err_val) => (
+ StatusCode::BAD_REQUEST,
+ Json(serde_json::json!(err_val.to_string())),
+ ),
+ },
+ Err(err_val) => (
+ StatusCode::BAD_REQUEST,
+ Json(serde_json::json!(err_val.to_string())),
+ ),
+ }
}
-
async fn create(Json(create_login): Json) -> impl IntoResponse {
match OneTimePassword::verify(&create_login.one_time_password).await {
true => match Login::create(&create_login.one_time_password.user_id).await {
@@ -59,8 +85,8 @@ async fn read(Path((user_id, token)): Path<(i64, String)>) -> impl IntoResponse
}
}
-async fn update(Json(update_role): Json) -> impl IntoResponse {
- match Login::update(&update_role.user_id, &update_role.token).await {
+async fn update(Json(update_login): Json) -> impl IntoResponse {
+ match Login::update(&update_login.user_id, &update_login.token).await {
Ok(login) => (StatusCode::ACCEPTED, Json(serde_json::json!(login))),
Err(err_val) => (
StatusCode::BAD_REQUEST,
diff --git a/src/routing/middleware.rs b/src/routing/middleware.rs
index 3bf9546..d55a5fa 100644
--- a/src/routing/middleware.rs
+++ b/src/routing/middleware.rs
@@ -33,14 +33,17 @@ async fn user_extraction(request: Request) -> Option {
if let Some(authorization_header) = request.headers().get(http::header::AUTHORIZATION) {
if let Ok(authorization_header) = authorization_header.to_str() {
if let Some((bearer, authorization_header)) = authorization_header.split_once(' ') {
- if bearer == "bearer" {
- if let Ok(claims) =
- TokenMeta::verify_token(&authorization_header.to_string()).await
- {
- return Some(UserAndRequest {
- user: User::read(&claims.custom).await.ok()?,
- request,
- });
+ if bearer.to_lowercase() == "bearer" {
+ match TokenMeta::verify_token(&authorization_header.to_string()).await {
+ Ok(claims) => {
+ return Some(UserAndRequest {
+ user: User::read(&claims.custom.user_id).await.ok()?,
+ request,
+ });
+ }
+ Err(err_val) => {
+ eprintln!("Verify Token | {}", err_val);
+ }
}
}
}
diff --git a/src/routing/post.rs b/src/routing/post.rs
index 486df47..85e15e9 100644
--- a/src/routing/post.rs
+++ b/src/routing/post.rs
@@ -26,9 +26,9 @@ struct UpdatePost {
pub fn route() -> Router {
Router::new()
.route("/", post(create))
- .route("/:creation_time", get(read))
+ .route("/{creation_time}", get(read))
.route("/", patch(update))
- .route("/:creation_time", delete(delete_))
+ .route("/{creation_time}", delete(delete_))
.route("/", get(read_all))
}
diff --git a/src/routing/post_interaction.rs b/src/routing/post_interaction.rs
index 5c7c581..a81d3ea 100644
--- a/src/routing/post_interaction.rs
+++ b/src/routing/post_interaction.rs
@@ -28,10 +28,10 @@ struct UpdatePostInteraction {
pub fn route() -> Router {
Router::new()
.route("/", post(create))
- .route("/:interaction_time", get(read))
+ .route("/{interaction_time}", get(read))
.route("/", patch(update))
- .route("/:interaction_time", delete(delete_))
- .route("/posts/:post_creation_time", get(read_all_for_post))
+ .route("/{interaction_time}", delete(delete_))
+ .route("/posts/{post_creation_time}", get(read_all_for_post))
}
async fn create(Json(create_post_interaction): Json) -> impl IntoResponse {
diff --git a/src/routing/role.rs b/src/routing/role.rs
index 840d158..6f8bf1f 100644
--- a/src/routing/role.rs
+++ b/src/routing/role.rs
@@ -9,8 +9,6 @@ use serde::{Deserialize, Serialize};
use crate::feature::role::Role;
-use super::middleware;
-
#[derive(Debug, Serialize, Deserialize)]
struct CreateRole {
name: String,
@@ -25,15 +23,10 @@ struct UpdateRole {
pub fn route() -> Router {
Router::new()
.route("/", post(create))
- .route_layer(axum::middleware::from_fn(middleware::pass_builder_or_admin))
- .route("/:id", get(read))
- .route_layer(axum::middleware::from_fn(middleware::pass))
+ .route("/{id}", get(read))
.route("/", patch(update))
- .route_layer(axum::middleware::from_fn(middleware::pass_builder_or_admin))
- .route("/:id", delete(delete_))
- .route_layer(axum::middleware::from_fn(middleware::pass_builder_or_admin))
+ .route("/{id}", delete(delete_))
.route("/", get(read_all))
- .route_layer(axum::middleware::from_fn(middleware::pass))
}
async fn create(Json(create_role): Json) -> impl IntoResponse {
diff --git a/src/routing/user.rs b/src/routing/user.rs
index 765d25b..f197914 100644
--- a/src/routing/user.rs
+++ b/src/routing/user.rs
@@ -10,6 +10,8 @@ use serde::{Deserialize, Serialize};
use crate::feature::user::User;
+use super::middleware;
+
#[derive(Debug, Serialize, Deserialize)]
struct CreateUser {
name: String,
@@ -31,33 +33,45 @@ struct UpdateUser {
pub fn route() -> Router {
Router::new()
.route("/", post(create))
- .route("/:id", get(read))
- .route("/", patch(update))
- .route("/:id", delete(delete_))
- .route("/", get(read_all))
- .route("/names/:name", get(read_all_for_name))
- .route("/surnames/:surname", get(read_all_for_surname))
- .route("/birth_dates/:birth_date", get(read_all_for_birth_date))
- .route("/roles/:role", get(read_all_for_role))
- .route("/genders/:gender", get(read_all_for_gender))
- .route("/ids", get(read_all_id))
- .route("/ids/names/:name", get(read_all_id_for_name))
- .route("/ids/surnames/:surname", get(read_all_id_for_surname))
.route(
- "/ids/birth_dates/:birth_date",
+ "/{id}",
+ get(read).route_layer(axum::middleware::from_fn(middleware::pass)),
+ )
+ .route(
+ "/",
+ patch(update).route_layer(axum::middleware::from_fn(middleware::pass_higher_or_self)),
+ )
+ .route(
+ "/{id}",
+ delete(delete_).route_layer(axum::middleware::from_fn(middleware::pass_higher_or_self)),
+ )
+ .route(
+ "/",
+ get(read_all).route_layer(axum::middleware::from_fn(middleware::pass_builder_or_admin)),
+ )
+ .route("/names/{name}", get(read_all_for_name))
+ .route("/surnames/{surname}", get(read_all_for_surname))
+ .route("/birth_dates/{birth_date}", get(read_all_for_birth_date))
+ .route("/roles/{role}", get(read_all_for_role))
+ .route("/genders/{gender}", get(read_all_for_gender))
+ .route("/ids", get(read_all_id))
+ .route("/ids/names/{name}", get(read_all_id_for_name))
+ .route("/ids/surnames/{surname}", get(read_all_id_for_surname))
+ .route(
+ "/ids/birth_dates/{birth_date}",
get(read_all_id_for_birth_date),
)
- .route("/ids/roles/:role", get(read_all_id_for_role))
- .route("/ids/genders/:gender", get(read_all_id_for_gender))
+ .route("/ids/roles/{role}", get(read_all_id_for_role))
+ .route("/ids/genders/{gender}", get(read_all_id_for_gender))
.route("/count", get(count_all))
- .route("/count/names/:name", get(count_all_for_name))
- .route("/count/surnames/:surname", get(count_all_for_surname))
+ .route("/count/names/{name}", get(count_all_for_name))
+ .route("/count/surnames/{surname}", get(count_all_for_surname))
.route(
- "/count/birth_dates/:birth_date",
+ "/count/birth_dates/{birth_date}",
get(count_all_for_birth_date),
)
- .route("/count/roles/:role", get(count_all_for_role))
- .route("/count/genders/:gender", get(count_all_for_gender))
+ .route("/count/roles/{role}", get(count_all_for_role))
+ .route("/count/genders/{gender}", get(count_all_for_gender))
}
async fn create(Json(create_user): Json) -> impl IntoResponse {
diff --git a/src/routing/user_contact.rs b/src/routing/user_contact.rs
index 4478c27..046aef6 100644
--- a/src/routing/user_contact.rs
+++ b/src/routing/user_contact.rs
@@ -13,28 +13,31 @@ use crate::feature::user_contact::UserContact;
struct CreateUserContact {
pub user_id: i64,
pub contact_id: i64,
+ pub contact_value: String,
}
#[derive(Debug, Serialize, Deserialize)]
struct UpdateUserContact {
pub user_id: i64,
pub contact_id: i64,
+ pub contact_value: String,
}
pub fn route() -> Router {
Router::new()
.route("/", post(create))
- .route("/roles/:user_id/contacts/:contact_id", get(read))
+ .route("/roles/{user_id}/contacts/{contact_id}", get(read))
.route("/", patch(update))
- .route("/roles/:user_id/contacts/:contact_id", delete(delete_))
- .route("/users/:user_id", get(read_all_for_user))
- .route("/users/:user_id", delete(delete_all_for_user))
+ .route("/roles/{user_id}/contacts/{contact_id}", delete(delete_))
+ .route("/users/{user_id}", get(read_all_for_user))
+ .route("/users/{user_id}", delete(delete_all_for_user))
}
async fn create(Json(create_user_contact): Json) -> impl IntoResponse {
match UserContact::create(
&create_user_contact.user_id,
&create_user_contact.contact_id,
+ &create_user_contact.contact_value,
)
.await
{
@@ -56,8 +59,14 @@ async fn read(Path((user_id, contact_id)): Path<(i64, i64)>) -> impl IntoRespons
}
}
-async fn update(Json(update_role): Json) -> impl IntoResponse {
- match UserContact::update(&update_role.user_id, &update_role.contact_id).await {
+async fn update(Json(update_user_contact): Json) -> impl IntoResponse {
+ match UserContact::update(
+ &update_user_contact.user_id,
+ &update_user_contact.contact_id,
+ &update_user_contact.contact_value,
+ )
+ .await
+ {
Ok(user_contact) => (StatusCode::ACCEPTED, Json(serde_json::json!(user_contact))),
Err(err_val) => (
StatusCode::BAD_REQUEST,