From c3156aeb416deb79a36e2db6b11c19d0e3f4b1e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ahmet=20Kaan=20G=C3=9CM=C3=9C=C5=9E?= <96421894+Tahinli@users.noreply.github.com> Date: Mon, 27 Jan 2025 17:54:57 +0300 Subject: [PATCH] feat: :sparkles: admin routing part 4 --- .../20241204225143_create_post_table.up.sql | 5 +- src/database/post.rs | 16 ++-- src/feature/post.rs | 12 +-- src/routing/admin.rs | 2 + src/routing/admin/post.rs | 32 ++++++++ src/routing/post.rs | 80 ++++++++++++++----- 6 files changed, 111 insertions(+), 36 deletions(-) create mode 100644 src/routing/admin/post.rs diff --git a/migrations/20241204225143_create_post_table.up.sql b/migrations/20241204225143_create_post_table.up.sql index 56bc47e..98b6f1a 100644 --- a/migrations/20241204225143_create_post_table.up.sql +++ b/migrations/20241204225143_create_post_table.up.sql @@ -1,6 +1,7 @@ -- Add up migration script here CREATE TABLE IF NOT EXISTS "post"( - creation_time TIMESTAMPTZ PRIMARY KEY UNIQUE NOT NULL DEFAULT NOW(), user_id BIGSERIAL NOT NULL REFERENCES "user"(user_id), - post VARCHAR(8192) NOT NULL UNIQUE + creation_time TIMESTAMPTZ UNIQUE NOT NULL DEFAULT NOW(), + post VARCHAR(8192) NOT NULL UNIQUE, + PRIMARY KEY(user_id, creation_time) ); diff --git a/src/database/post.rs b/src/database/post.rs index f6d1f35..0be9501 100644 --- a/src/database/post.rs +++ b/src/database/post.rs @@ -19,12 +19,13 @@ pub async fn create(user_id: &i64, post: &String) -> Result { .await } -pub async fn read(creation_time: &DateTime) -> Result { +pub async fn read(user_id: &i64, creation_time: &DateTime) -> Result { sqlx::query_as!( Post, r#" - SELECT * FROM "post" WHERE "creation_time" = $1 + SELECT * FROM "post" WHERE "user_id"= $1 AND "creation_time" = $2 "#, + user_id, creation_time ) .fetch_one(&*DATABASE_CONNECTIONS) @@ -32,31 +33,32 @@ pub async fn read(creation_time: &DateTime) -> Result { } pub async fn update( - creation_time: &DateTime, user_id: &i64, + creation_time: &DateTime, post: &String, ) -> Result { sqlx::query_as!( Post, r#" - UPDATE "post" SET user_id = $2, post = $3 WHERE "creation_time" = $1 + UPDATE "post" SET post = $3 WHERE "user_id" = $1 AND "creation_time" = $2 RETURNING * "#, - creation_time, user_id, + creation_time, post ) .fetch_one(&*DATABASE_CONNECTIONS) .await } -pub async fn delete(creation_time: &DateTime) -> Result { +pub async fn delete(user_id: &i64, creation_time: &DateTime) -> Result { sqlx::query_as!( Post, r#" - DELETE FROM "post" WHERE "creation_time" = $1 + DELETE FROM "post" WHERE "user_id" = $1 AND "creation_time" = $2 RETURNING * "#, + user_id, creation_time ) .fetch_one(&*DATABASE_CONNECTIONS) diff --git a/src/feature/post.rs b/src/feature/post.rs index 23e68c4..0253fd3 100644 --- a/src/feature/post.rs +++ b/src/feature/post.rs @@ -15,20 +15,20 @@ impl Post { post::create(user_id, post).await } - pub async fn read(creation_time: &DateTime) -> Result { - post::read(creation_time).await + pub async fn read(user_id: &i64, creation_time: &DateTime) -> Result { + post::read(user_id, creation_time).await } pub async fn update( - creation_time: &DateTime, user_id: &i64, + creation_time: &DateTime, post: &String, ) -> Result { - post::update(creation_time, user_id, post).await + post::update(user_id, creation_time, post).await } - pub async fn delete(creation_time: &DateTime) -> Result { - post::delete(creation_time).await + pub async fn delete(user_id: &i64, creation_time: &DateTime) -> Result { + post::delete(user_id, creation_time).await } pub async fn read_all() -> Result, sqlx::Error> { diff --git a/src/routing/admin.rs b/src/routing/admin.rs index b195d25..e2b533f 100644 --- a/src/routing/admin.rs +++ b/src/routing/admin.rs @@ -1,6 +1,7 @@ pub mod contact; pub mod interaction; pub mod login; +pub mod post; pub mod role; pub mod user; pub mod user_contact; @@ -17,6 +18,7 @@ pub fn route() -> Router { .nest("/contacts", contact::route()) .nest("/user_contacts", user_contact::route()) .nest("/interactions", interaction::route()) + .nest("/posts", post::route()) .route_layer(axum::middleware::from_fn( builder_or_admin_by_authorization_token, )) diff --git a/src/routing/admin/post.rs b/src/routing/admin/post.rs new file mode 100644 index 0000000..87b1f41 --- /dev/null +++ b/src/routing/admin/post.rs @@ -0,0 +1,32 @@ +use std::sync::Arc; + +use axum::{ + extract::Path, http::StatusCode, response::IntoResponse, routing::delete, Extension, Json, + Router, +}; +use chrono::{DateTime, Utc}; + +use crate::{ + feature::{post::Post, user::User}, + routing::middleware::by_uri_then_insert, +}; + +pub fn route() -> Router { + Router::new().route( + "/users/{user_id}/creation_times/{creation_time}", + delete(delete_).route_layer(axum::middleware::from_fn(by_uri_then_insert)), + ) +} + +async fn delete_( + Extension(user): Extension>, + Path(creation_time): Path>, +) -> impl IntoResponse { + match Post::delete(&user.user_id, &creation_time).await { + Ok(post) => (StatusCode::NO_CONTENT, Json(serde_json::json!(post))), + Err(err_val) => ( + StatusCode::BAD_REQUEST, + Json(serde_json::json!(err_val.to_string())), + ), + } +} diff --git a/src/routing/post.rs b/src/routing/post.rs index 85e15e9..001ee85 100644 --- a/src/routing/post.rs +++ b/src/routing/post.rs @@ -1,39 +1,64 @@ +use std::sync::Arc; + use axum::{ extract::Path, http::StatusCode, response::IntoResponse, routing::{delete, get, patch, post}, - Json, Router, + Extension, Json, Router, }; use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; -use crate::feature::post::Post; +use crate::feature::{post::Post, user::User}; + +use super::middleware::{by_authorization_token_then_insert, by_uri_then_insert}; #[derive(Debug, Serialize, Deserialize)] struct CreatePost { - user_id: i64, post: String, } #[derive(Debug, Serialize, Deserialize)] struct UpdatePost { creation_time: DateTime, - user_id: i64, post: String, } pub fn route() -> Router { Router::new() - .route("/", post(create)) - .route("/{creation_time}", get(read)) + .route( + "/", + post(create).route_layer(axum::middleware::from_fn( + by_authorization_token_then_insert, + )), + ) + .route( + "/users/{user_id}/creation_times/{creation_time}", + get(read).route_layer(axum::middleware::from_fn(by_uri_then_insert)), + ) .route("/", patch(update)) - .route("/{creation_time}", delete(delete_)) + .route_layer(axum::middleware::from_fn( + by_authorization_token_then_insert, + )) + .route( + "/creation_times/{creation_time}", + delete(delete_).route_layer(axum::middleware::from_fn( + by_authorization_token_then_insert, + )), + ) .route("/", get(read_all)) + .route( + "/users/{user_id}", + get(read_all_for_user).route_layer(axum::middleware::from_fn(by_uri_then_insert)), + ) } -async fn create(Json(create_post): Json) -> impl IntoResponse { - match Post::create(&create_post.user_id, &create_post.post).await { +async fn create( + Extension(user): Extension>, + Json(create_post): Json, +) -> impl IntoResponse { + match Post::create(&user.user_id, &create_post.post).await { Ok(post) => (StatusCode::CREATED, Json(serde_json::json!(post))), Err(err_val) => ( StatusCode::BAD_REQUEST, @@ -42,8 +67,11 @@ async fn create(Json(create_post): Json) -> impl IntoResponse { } } -async fn read(Path(creation_time): Path>) -> impl IntoResponse { - match Post::read(&creation_time).await { +async fn read( + Extension(user): Extension>, + Path(creation_time): Path>, +) -> impl IntoResponse { + match Post::read(&user.user_id, &creation_time).await { Ok(post) => (StatusCode::OK, Json(serde_json::json!(post))), Err(err_val) => ( StatusCode::BAD_REQUEST, @@ -52,14 +80,11 @@ async fn read(Path(creation_time): Path>) -> impl IntoResponse { } } -async fn update(Json(update_role): Json) -> impl IntoResponse { - match Post::update( - &update_role.creation_time, - &update_role.user_id, - &update_role.post, - ) - .await - { +async fn update( + Extension(user): Extension>, + Json(update_role): Json, +) -> impl IntoResponse { + match Post::update(&user.user_id, &update_role.creation_time, &update_role.post).await { Ok(post) => (StatusCode::ACCEPTED, Json(serde_json::json!(post))), Err(err_val) => ( StatusCode::BAD_REQUEST, @@ -68,8 +93,11 @@ async fn update(Json(update_role): Json) -> impl IntoResponse { } } -async fn delete_(Path(creation_time): Path>) -> impl IntoResponse { - match Post::delete(&creation_time).await { +async fn delete_( + Extension(user): Extension>, + Path(creation_time): Path>, +) -> impl IntoResponse { + match Post::delete(&user.user_id, &creation_time).await { Ok(post) => (StatusCode::NO_CONTENT, Json(serde_json::json!(post))), Err(err_val) => ( StatusCode::BAD_REQUEST, @@ -87,3 +115,13 @@ async fn read_all() -> impl IntoResponse { ), } } + +async fn read_all_for_user(Extension(user): Extension>) -> impl IntoResponse { + match Post::read_all_for_user(&user.user_id).await { + Ok(posts) => (StatusCode::OK, Json(serde_json::json!(posts))), + Err(err_val) => ( + StatusCode::BAD_REQUEST, + Json(serde_json::json!(err_val.to_string())), + ), + } +}