diff --git a/rest-server/migrations/08_notifications.sql b/rest-server/migrations/08_notifications.sql index d452dc8..de56431 100644 --- a/rest-server/migrations/08_notifications.sql +++ b/rest-server/migrations/08_notifications.sql @@ -1,8 +1,11 @@ CREATE TABLE IF NOT EXISTS "notifications" ( id SERIAL PRIMARY KEY, user_id INT REFERENCES "users"(id), + title VARCHAR(64) NOT NULL, + content VARCHAR(256) NOT NULL, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, "read" BOOLEAN NOT NULL DEFAULT FALSE, + status SMALLINT NOT NULL, type SMALLINT NOT NULL ); diff --git a/rest-server/src/api/v1/users/me/get.rs b/rest-server/src/api/v1/users/me/get.rs index 0268b85..ae16573 100644 --- a/rest-server/src/api/v1/users/me/get.rs +++ b/rest-server/src/api/v1/users/me/get.rs @@ -3,7 +3,7 @@ use axum::response::IntoResponse; use common::entities::UserRole; use crate::app::auth::AuthSession; use crate::app::web::AppState; -use crate::json::users::{UserMePayload, UserType}; +use crate::json::users::{UserMeResponse, UserType}; use crate::models::users::{CustomerUser, ProtectedUser, ViewerUser}; pub async fn me( @@ -59,5 +59,5 @@ pub async fn me( tx.commit().await; - Json(UserMePayload { user: protected_user, info: user_info }) + Json(UserMeResponse { user: protected_user, info: user_info }) } \ No newline at end of file diff --git a/rest-server/src/api/v1/users/me/notifications/get.rs b/rest-server/src/api/v1/users/me/notifications/get.rs index f88a2ce..8dbbde7 100644 --- a/rest-server/src/api/v1/users/me/notifications/get.rs +++ b/rest-server/src/api/v1/users/me/notifications/get.rs @@ -5,7 +5,7 @@ use crate::app::web::AppState; pub async fn notifications( Extension(state): Extension, - auth_session: AuthSession, + auth_session: AuthSession ) -> impl IntoResponse { - todo!() + } \ No newline at end of file diff --git a/rest-server/src/api/v1/users/me/notifications/mod.rs b/rest-server/src/api/v1/users/me/notifications/mod.rs index b89b513..cb10acc 100644 --- a/rest-server/src/api/v1/users/me/notifications/mod.rs +++ b/rest-server/src/api/v1/users/me/notifications/mod.rs @@ -7,5 +7,5 @@ mod patch; pub fn router() -> Router { Router::new() .route("/", get(get::notifications)) - .route("/:notification_id/read", patch(patch::mark_as_read)) + .route("/:notification_id", patch(patch::read)) } \ No newline at end of file diff --git a/rest-server/src/api/v1/users/me/notifications/patch.rs b/rest-server/src/api/v1/users/me/notifications/patch.rs index 5ad2f0b..e6e2c89 100644 --- a/rest-server/src/api/v1/users/me/notifications/patch.rs +++ b/rest-server/src/api/v1/users/me/notifications/patch.rs @@ -1,13 +1,42 @@ -use axum::Extension; +use axum::{Extension, Json}; use axum::extract::Path; +use axum::http::StatusCode; use axum::response::IntoResponse; use crate::app::auth::AuthSession; use crate::app::web::AppState; +use crate::json::error::error_message; +use crate::json::notifications::UpdateNotificationPayload; -pub async fn mark_as_read( +pub async fn read( Extension(state): Extension, auth_session: AuthSession, - Path(notification_id): Path, + Path(notification_id): Path, + Json(payload): Json, ) -> impl IntoResponse { - todo!() + let login_user = auth_session.user.unwrap(); + + let mut tx = state.pool.begin().await.unwrap(); + let query = sqlx::query(r#" + UPDATE notifications + SET read = $2 + WHERE id = $1 AND user_id = $3 + "#) + .bind(notification_id) + .bind(payload.read) + .bind(login_user.id) + .execute(&mut *tx) + .await + .unwrap(); + + if query.rows_affected() == 0 { + tx.rollback().await.unwrap(); + + return error_message( + StatusCode::UNAUTHORIZED, + "Você não é o dono da notificação ou a notificação não existe", + ); + } + + tx.commit().await.unwrap(); + StatusCode::OK.into_response() } \ No newline at end of file diff --git a/rest-server/src/json/mod.rs b/rest-server/src/json/mod.rs index 75e74cd..4d488f4 100644 --- a/rest-server/src/json/mod.rs +++ b/rest-server/src/json/mod.rs @@ -4,6 +4,7 @@ use sqlx::types::chrono::NaiveDateTime; pub mod auth; pub mod error; pub mod users; +pub mod notifications; pub fn serialize_timestamp(naive_datetime: &NaiveDateTime, serializer: S) -> Result where diff --git a/rest-server/src/json/notifications.rs b/rest-server/src/json/notifications.rs new file mode 100644 index 0000000..b2e2e2e --- /dev/null +++ b/rest-server/src/json/notifications.rs @@ -0,0 +1,6 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize)] +pub struct UpdateNotificationPayload { + pub read: bool +} \ No newline at end of file diff --git a/rest-server/src/json/users.rs b/rest-server/src/json/users.rs index 40927d1..51a8eae 100644 --- a/rest-server/src/json/users.rs +++ b/rest-server/src/json/users.rs @@ -2,7 +2,7 @@ use serde::{Serialize, Serializer}; use crate::models::users::{CustomerUser, ProtectedUser, SellerUser, ViewerUser}; #[derive(Serialize)] -pub struct UserMePayload { +pub struct UserMeResponse { pub user: ProtectedUser, pub info: Option } diff --git a/rest-server/tests/fixtures/notifications.sql b/rest-server/tests/fixtures/notifications.sql new file mode 100644 index 0000000..3655467 --- /dev/null +++ b/rest-server/tests/fixtures/notifications.sql @@ -0,0 +1,12 @@ +INSERT INTO notifications (user_id, title, content, status, type) +VALUES + (1, 'Notification 1', 'This is the content of notification 1', 1, 1), + (2, 'Notification 2', 'This is the content of notification 2', 1, 1), + (3, 'Notification 3', 'This is the content of notification 3', 1, 1), + (4, 'Notification 4', 'This is the content of notification 4', 1, 1), + (5, 'Notification 5', 'This is the content of notification 5', 1, 1), + (6, 'Notification 6', 'This is the content of notification 6', 1, 1), + (7, 'Notification 7', 'This is the content of notification 7', 1, 1), + (8, 'Notification 8', 'This is the content of notification 8', 1, 1), + (9, 'Notification 9', 'This is the content of notification 9', 1, 1), + (10, 'Notification 10', 'This is the content of notification 10', 1, 1); \ No newline at end of file diff --git a/rest-server/tests/notifications.rs b/rest-server/tests/notifications.rs new file mode 100644 index 0000000..d6865ab --- /dev/null +++ b/rest-server/tests/notifications.rs @@ -0,0 +1,37 @@ +use axum_test::TestServer; +use sqlx::{Pool, Postgres}; +use rest_server::json::auth::LoginCreds; +use rest_server::json::notifications::UpdateNotificationPayload; +use crate::common::{login, test_app}; + +mod common; + +#[sqlx::test(fixtures("users", "notifications"))] +async fn test_notifications(pool: Pool) { + let server = &mut test_app(pool); + + test_read_notifications(server) + .await; +} + +async fn test_read_notifications(server: &TestServer) { + login(server, LoginCreds { + email: "john.doe@gmail.com".to_string(), + password: "secured123456".to_string(), + }) + .await; + + server.patch("/api/v1/users/@me/notifications/1") + .json(&UpdateNotificationPayload { + read: true, + }) + .expect_success() + .await; + + server.patch("/api/v1/users/@me/notifications/2") + .json(&UpdateNotificationPayload { + read: true, + }) + .expect_failure() + .await; +} \ No newline at end of file