diff --git a/.sqlx/query-5027790ff6e3cd978eaec2c399b171e765515747a4052d0ad59c2fd64ec81251.json b/.sqlx/query-00030e21560ce62548eabf89124a90e28fc6bf4651a85c7a52d6468c44e36852.json similarity index 72% rename from .sqlx/query-5027790ff6e3cd978eaec2c399b171e765515747a4052d0ad59c2fd64ec81251.json rename to .sqlx/query-00030e21560ce62548eabf89124a90e28fc6bf4651a85c7a52d6468c44e36852.json index fa3e05c..e4aa1d3 100644 --- a/.sqlx/query-5027790ff6e3cd978eaec2c399b171e765515747a4052d0ad59c2fd64ec81251.json +++ b/.sqlx/query-00030e21560ce62548eabf89124a90e28fc6bf4651a85c7a52d6468c44e36852.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n UPDATE event SET\n name = COALESCE($1, name),\n location = COALESCE($2, location),\n start_time = COALESCE($3, start_time),\n end_time = COALESCE($4, end_time)\n WHERE id = $5 RETURNING id\n ", + "query": "\n UPDATE event SET\n name = COALESCE($1, name),\n location = COALESCE($2, location),\n start_time = COALESCE($3, start_time),\n end_time = COALESCE($4, end_time)\n WHERE id = $5 AND creator = $6\n RETURNING id\n ", "describe": { "columns": [ { @@ -15,12 +15,13 @@ "Varchar", "Timestamptz", "Timestamptz", - "Int4" + "Int4", + "Text" ] }, "nullable": [ false ] }, - "hash": "5027790ff6e3cd978eaec2c399b171e765515747a4052d0ad59c2fd64ec81251" + "hash": "00030e21560ce62548eabf89124a90e28fc6bf4651a85c7a52d6468c44e36852" } diff --git a/.sqlx/query-f75b9810062cfc9509c96fc289f0f039194865d02f6abc03662c16fcf147b3e6.json b/.sqlx/query-47d04e0acd95c6675cd4d5415321ac476243289d42ccb2c6ba5c35b32bf63986.json similarity index 61% rename from .sqlx/query-f75b9810062cfc9509c96fc289f0f039194865d02f6abc03662c16fcf147b3e6.json rename to .sqlx/query-47d04e0acd95c6675cd4d5415321ac476243289d42ccb2c6ba5c35b32bf63986.json index 0504fee..e721e82 100644 --- a/.sqlx/query-f75b9810062cfc9509c96fc289f0f039194865d02f6abc03662c16fcf147b3e6.json +++ b/.sqlx/query-47d04e0acd95c6675cd4d5415321ac476243289d42ccb2c6ba5c35b32bf63986.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "DELETE FROM car WHERE event_id = $1 AND id = $2 RETURNING id", + "query": "DELETE FROM event WHERE id = $1 AND creator = $2 RETURNING id", "describe": { "columns": [ { @@ -12,12 +12,12 @@ "parameters": { "Left": [ "Int4", - "Int4" + "Text" ] }, "nullable": [ false ] }, - "hash": "f75b9810062cfc9509c96fc289f0f039194865d02f6abc03662c16fcf147b3e6" + "hash": "47d04e0acd95c6675cd4d5415321ac476243289d42ccb2c6ba5c35b32bf63986" } diff --git a/.sqlx/query-40901d716c75136d6fb2bf60c6dc19c67dd744ab3b8225005afe36ccb74bd491.json b/.sqlx/query-4e674fb9370edd9c1b50f774406e8bcb575747135c9adccb9a2e1ea881e14963.json similarity index 53% rename from .sqlx/query-40901d716c75136d6fb2bf60c6dc19c67dd744ab3b8225005afe36ccb74bd491.json rename to .sqlx/query-4e674fb9370edd9c1b50f774406e8bcb575747135c9adccb9a2e1ea881e14963.json index 52534d8..ab16479 100644 --- a/.sqlx/query-40901d716c75136d6fb2bf60c6dc19c67dd744ab3b8225005afe36ccb74bd491.json +++ b/.sqlx/query-4e674fb9370edd9c1b50f774406e8bcb575747135c9adccb9a2e1ea881e14963.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "DELETE FROM event WHERE id = $1 RETURNING id", + "query": "DELETE FROM car WHERE event_id = $1 AND id = $2 AND driver = $3 RETURNING id", "describe": { "columns": [ { @@ -11,12 +11,14 @@ ], "parameters": { "Left": [ - "Int4" + "Int4", + "Int4", + "Text" ] }, "nullable": [ false ] }, - "hash": "40901d716c75136d6fb2bf60c6dc19c67dd744ab3b8225005afe36ccb74bd491" + "hash": "4e674fb9370edd9c1b50f774406e8bcb575747135c9adccb9a2e1ea881e14963" } diff --git a/.sqlx/query-265aeab895a5d3ce441ebba42bd83c61c1a2147289e4b58d0c70680b83a30585.json b/.sqlx/query-8973026fd1f6a28d695834021c538cad2ce6b5c7bc1ae2d561c8219967810ee2.json similarity index 78% rename from .sqlx/query-265aeab895a5d3ce441ebba42bd83c61c1a2147289e4b58d0c70680b83a30585.json rename to .sqlx/query-8973026fd1f6a28d695834021c538cad2ce6b5c7bc1ae2d561c8219967810ee2.json index cf0f97a..c946eab 100644 --- a/.sqlx/query-265aeab895a5d3ce441ebba42bd83c61c1a2147289e4b58d0c70680b83a30585.json +++ b/.sqlx/query-8973026fd1f6a28d695834021c538cad2ce6b5c7bc1ae2d561c8219967810ee2.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n UPDATE car SET\n max_capacity = COALESCE($1, max_capacity),\n departure_time = COALESCE($2, departure_time),\n return_time = COALESCE($3, return_time),\n comment = COALESCE($4, comment)\n WHERE event_id = $5 AND id = $6 RETURNING id\n ", + "query": "\n UPDATE car SET\n max_capacity = COALESCE($1, max_capacity),\n departure_time = COALESCE($2, departure_time),\n return_time = COALESCE($3, return_time),\n comment = COALESCE($4, comment)\n WHERE event_id = $5 AND id = $6 AND driver = $7 RETURNING id\n ", "describe": { "columns": [ { @@ -16,12 +16,13 @@ "Timestamptz", "Varchar", "Int4", - "Int4" + "Int4", + "Text" ] }, "nullable": [ false ] }, - "hash": "265aeab895a5d3ce441ebba42bd83c61c1a2147289e4b58d0c70680b83a30585" + "hash": "8973026fd1f6a28d695834021c538cad2ce6b5c7bc1ae2d561c8219967810ee2" } diff --git a/.sqlx/query-dfb486af0f1ea3f1faa1b68b5a25515cdf802a50dece2d3869b6be8dc30c497c.json b/.sqlx/query-dfb486af0f1ea3f1faa1b68b5a25515cdf802a50dece2d3869b6be8dc30c497c.json new file mode 100644 index 0000000..c33e687 --- /dev/null +++ b/.sqlx/query-dfb486af0f1ea3f1faa1b68b5a25515cdf802a50dece2d3869b6be8dc30c497c.json @@ -0,0 +1,23 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT COUNT(*) as count FROM (SELECT id FROM car WHERE event_id = $1 AND driver = $2 UNION SELECT rider.car_id FROM rider JOIN car ON rider.car_id = car.id WHERE car.event_id = $1 AND rider.rider = $2)", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "count", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [ + "Int4", + "Text" + ] + }, + "nullable": [ + null + ] + }, + "hash": "dfb486af0f1ea3f1faa1b68b5a25515cdf802a50dece2d3869b6be8dc30c497c" +} diff --git a/src/api/v1/auth/csh.rs b/src/api/v1/auth/csh.rs index 8945eab..081cf55 100644 --- a/src/api/v1/auth/csh.rs +++ b/src/api/v1/auth/csh.rs @@ -1,15 +1,15 @@ +use crate::api::v1::auth::models::UserRealm; +use crate::api::v1::auth::models::{CSHUserInfo, UserInfo}; +use crate::AppState; use actix_session::Session; use actix_web::http::header; +use actix_web::{get, Scope}; use actix_web::{web, HttpResponse, Responder}; use oauth2::reqwest::async_http_client; use oauth2::{AuthorizationCode, TokenResponse}; use reqwest::Client; -use utoipa::{OpenApi, ToSchema}; - -use crate::api::v1::auth::models::{CSHUserInfo, UserInfo, UserRealm}; -use crate::AppState; -use actix_web::{get, Scope}; use serde::Deserialize; +use utoipa::{OpenApi, ToSchema}; use crate::api::v1::auth::common; @@ -34,7 +34,7 @@ async fn login(data: web::Data) -> impl Responder { #[derive(Deserialize, ToSchema)] pub struct AuthRequest { code: String, - state: String, + _state: String, } #[utoipa::path( @@ -72,11 +72,11 @@ async fn auth( sqlx::query!( "INSERT INTO users (id, realm, name) VALUES ($1, $2, $3) ON CONFLICT (id) DO UPDATE SET realm = EXCLUDED.realm, name = EXCLUDED.name;", user_info.ldap_id, - UserRealm::CSH as _, + UserRealm::Csh as _, format!("{} {}", user_info.given_name, user_info.family_name) ) .execute(&data.db) - .await; + .await.unwrap(); session.insert("login", true).unwrap(); session diff --git a/src/api/v1/auth/google.rs b/src/api/v1/auth/google.rs index 1b25482..6cb1880 100644 --- a/src/api/v1/auth/google.rs +++ b/src/api/v1/auth/google.rs @@ -1,16 +1,16 @@ +use crate::api::v1::auth::common; +use crate::api::v1::auth::models::UserRealm; +use crate::api::v1::auth::models::{GoogleUserInfo, UserInfo}; +use crate::AppState; use actix_session::Session; use actix_web::http::header; +use actix_web::{get, web, Scope}; use actix_web::{HttpResponse, Responder}; use oauth2::reqwest::async_http_client; use oauth2::{AuthorizationCode, TokenResponse}; use reqwest::Client; -use utoipa::{OpenApi, ToSchema}; - -use crate::api::v1::auth::common; -use crate::api::v1::auth::models::{GoogleUserInfo, UserInfo, UserRealm}; -use crate::AppState; -use actix_web::{get, web, Scope}; use serde::Deserialize; +use utoipa::{OpenApi, ToSchema}; #[derive(OpenApi)] #[openapi(paths(login, auth,), components(schemas(AuthRequest)))] @@ -37,7 +37,7 @@ async fn login(data: web::Data) -> impl Responder { #[derive(Deserialize, ToSchema)] pub struct AuthRequest { code: String, - state: String, + _state: String, } #[utoipa::path( @@ -81,7 +81,7 @@ async fn auth( format!("{} {}", user_info.given_name, user_info.family_name) ) .execute(&data.db) - .await; + .await.unwrap(); session.insert("login", true).unwrap(); session diff --git a/src/api/v1/auth/models.rs b/src/api/v1/auth/models.rs index bbe01f6..55c6d4a 100644 --- a/src/api/v1/auth/models.rs +++ b/src/api/v1/auth/models.rs @@ -4,7 +4,7 @@ use utoipa::ToSchema; #[derive(sqlx::Type)] #[sqlx(type_name = "user_realm", rename_all = "lowercase")] pub enum UserRealm { - CSH, + Csh, Google, } diff --git a/src/api/v1/event/car/mod.rs b/src/api/v1/event/car/mod.rs index e7e4923..5103b3b 100644 --- a/src/api/v1/event/car/mod.rs +++ b/src/api/v1/event/car/mod.rs @@ -9,10 +9,10 @@ use actix_web::{ }; use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; -use sqlx::query_as; +use sqlx::{query, query_as}; use utoipa::{OpenApi, ToSchema}; -use log::{debug, error}; +use log::error; mod rider; @@ -89,15 +89,25 @@ async fn create_car( path: web::Path, ) -> impl Responder { let event_id: i32 = path.into_inner(); + let user_id = session.get::("userinfo").unwrap().unwrap().id; if car.max_capacity < 0 { return HttpResponse::BadRequest() .body("Sorry @cinnamon, you can't have negative people in your car :)"); } + let check = query!( + r#"SELECT COUNT(*) as count FROM (SELECT id FROM car WHERE event_id = $1 AND driver = $2 UNION SELECT rider.car_id FROM rider JOIN car ON rider.car_id = car.id WHERE car.event_id = $1 AND rider.rider = $2)"#, + event_id, user_id + ).fetch_one(&data.db).await.unwrap(); + + if check.count.unwrap() > 0 { + return HttpResponse::BadRequest().body("User is already in a car."); + } + let result = sqlx::query!( r#" INSERT INTO car (event_id, driver, max_capacity, departure_time, return_time, comment) VALUES ($1, $2, $3, $4, $5, $6) RETURNING id "#, - event_id, session.get::("userinfo").unwrap().unwrap().id, car.max_capacity, car.departure_time, car.return_time, car.comment + event_id, user_id, car.max_capacity, car.departure_time, car.return_time, car.comment ) .fetch_one(&data.db) .await; @@ -117,11 +127,7 @@ async fn create_car( ) )] #[get("/{car_id}", wrap = "SessionAuth")] -async fn get_car( - data: web::Data, - session: Session, - path: web::Path<(i32, i32)>, -) -> impl Responder { +async fn get_car(data: web::Data, path: web::Path<(i32, i32)>) -> impl Responder { let (event_id, car_id) = path.into_inner(); let result: Option = query_as!( CarData, @@ -155,11 +161,7 @@ async fn get_car( ) )] #[get("/", wrap = "SessionAuth")] -async fn get_all_cars( - data: web::Data, - session: Session, - path: web::Path, -) -> impl Responder { +async fn get_all_cars(data: web::Data, path: web::Path) -> impl Responder { let event_id: i32 = path.into_inner(); let result = query_as!( CarData, @@ -213,21 +215,22 @@ async fn update_car( departure_time = COALESCE($2, departure_time), return_time = COALESCE($3, return_time), comment = COALESCE($4, comment) - WHERE event_id = $5 AND id = $6 RETURNING id + WHERE event_id = $5 AND id = $6 AND driver = $7 RETURNING id "#, car.max_capacity, car.departure_time, car.return_time, car.comment, event_id, - car_id + car_id, + session.get::("userinfo").unwrap().unwrap().id ) .fetch_optional(&data.db) .await; match updated { Ok(Some(_)) => HttpResponse::Ok().body("Car updated successfully"), - Ok(None) => HttpResponse::NotFound().body("Car not found"), + Ok(None) => HttpResponse::NotFound().body("Car not found or you are not the driver."), Err(_) => HttpResponse::InternalServerError().body("Failed to update car"), } } @@ -249,16 +252,17 @@ async fn delete_car( let (event_id, car_id) = path.into_inner(); let deleted = sqlx::query!( - "DELETE FROM car WHERE event_id = $1 AND id = $2 RETURNING id", + "DELETE FROM car WHERE event_id = $1 AND id = $2 AND driver = $3 RETURNING id", event_id, - car_id + car_id, + session.get::("userinfo").unwrap().unwrap().id ) .fetch_optional(&data.db) .await; match deleted { Ok(Some(_)) => HttpResponse::Ok().body("Car deleted"), - Ok(None) => HttpResponse::NotFound().body("Car not found"), + Ok(None) => HttpResponse::NotFound().body("Car not found or you are not the driver."), Err(_) => HttpResponse::InternalServerError().body("Failed to delete car"), } } diff --git a/src/api/v1/event/car/rider/mod.rs b/src/api/v1/event/car/rider/mod.rs index 5072d75..dfd1802 100644 --- a/src/api/v1/event/car/rider/mod.rs +++ b/src/api/v1/event/car/rider/mod.rs @@ -8,8 +8,8 @@ use actix_web::{ HttpResponse, Responder, Scope, }; use log::error; -use serde::{Deserialize, Serialize}; -use utoipa::{OpenApi, ToSchema}; +use sqlx::query; +use utoipa::OpenApi; #[derive(OpenApi)] #[openapi(paths(create_rider, delete_rider))] @@ -30,13 +30,24 @@ async fn create_rider( session: Session, path: web::Path<(i32, i32)>, ) -> impl Responder { - let (_event_id, car_id) = path.into_inner(); + let (event_id, car_id) = path.into_inner(); + let user_id = session.get::("userinfo").unwrap().unwrap().id; + + let check = query!( + r#"SELECT COUNT(*) as count FROM (SELECT id FROM car WHERE event_id = $1 AND driver = $2 UNION SELECT rider.car_id FROM rider JOIN car ON rider.car_id = car.id WHERE car.event_id = $1 AND rider.rider = $2)"#, + event_id, user_id + ).fetch_one(&data.db).await.unwrap(); + + if check.count.unwrap() > 0 { + return HttpResponse::BadRequest().body("User is already in a car."); + } + let result = sqlx::query!( r#" INSERT INTO rider (car_id, rider) VALUES ($1, $2) "#, car_id, - session.get::("userinfo").unwrap().unwrap().id + user_id ) .execute(&data.db) .await; diff --git a/src/api/v1/event/mod.rs b/src/api/v1/event/mod.rs index 71039b8..5eedd59 100644 --- a/src/api/v1/event/mod.rs +++ b/src/api/v1/event/mod.rs @@ -1,3 +1,4 @@ +use crate::api::v1::auth::models::UserInfo; use actix_session::Session; use actix_web::{ delete, get, post, put, @@ -8,8 +9,8 @@ use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use sqlx::query_as; +use crate::auth::SessionAuth; use crate::AppState; -use crate::{api::v1::auth::models::UserInfo, auth::SessionAuth}; use utoipa::{OpenApi, ToSchema}; @@ -94,11 +95,7 @@ async fn create_event( ) )] #[get("/{event_id}", wrap = "SessionAuth")] -async fn get_event( - data: web::Data, - session: Session, - path: web::Path, -) -> impl Responder { +async fn get_event(data: web::Data, path: web::Path) -> impl Responder { let event_id = path.into_inner(); let result: Option = query_as!( Event, @@ -128,7 +125,6 @@ struct EventQueryParams { #[get("/", wrap = "SessionAuth")] async fn get_all_events( data: web::Data, - session: Session, params: web::Query, ) -> impl Responder { let past: bool = params.past.unwrap_or(false); @@ -164,20 +160,22 @@ async fn update_event( location = COALESCE($2, location), start_time = COALESCE($3, start_time), end_time = COALESCE($4, end_time) - WHERE id = $5 RETURNING id + WHERE id = $5 AND creator = $6 + RETURNING id "#, event.name, event.location, event.start_time, event.end_time, - event_id + event_id, + session.get::("userinfo").unwrap().unwrap().id ) .fetch_optional(&data.db) .await; match updated { Ok(Some(_)) => HttpResponse::Ok().body("Event updated successfully"), - Ok(None) => HttpResponse::NotFound().body("Event not found"), + Ok(None) => HttpResponse::NotFound().body("Event not found or you are not the creator."), Err(_) => HttpResponse::InternalServerError().body("Failed to update event"), } } @@ -195,13 +193,17 @@ async fn delete_event( ) -> impl Responder { let event_id = path.into_inner(); - let deleted = sqlx::query!("DELETE FROM event WHERE id = $1 RETURNING id", event_id) - .fetch_optional(&data.db) - .await; + let deleted = sqlx::query!( + "DELETE FROM event WHERE id = $1 AND creator = $2 RETURNING id", + event_id, + session.get::("userinfo").unwrap().unwrap().id + ) + .fetch_optional(&data.db) + .await; match deleted { Ok(Some(_)) => HttpResponse::Ok().body("Event deleted"), - Ok(None) => HttpResponse::NotFound().body("Event not found"), + Ok(None) => HttpResponse::NotFound().body("Event not found or you are not the creator."), Err(_) => HttpResponse::InternalServerError().body("Failed to delete event"), } } diff --git a/src/main.rs b/src/main.rs index e9cc151..e440297 100644 --- a/src/main.rs +++ b/src/main.rs @@ -12,7 +12,7 @@ use std::env; mod api; mod auth; -mod pings; +//mod pings; // Undo this when developing it #[derive(Clone)] struct AppState {