From c67cdd5b2a73f5d83d0b24453447a0215efa66b646bb6358135221adcb1041f3 Mon Sep 17 00:00:00 2001 From: raven <7156279+RavenX8@users.noreply.github.com> Date: Tue, 17 Dec 2024 04:06:56 -0500 Subject: [PATCH] - fix: issue where login failed to return the user if their role was null - add: register route for api-service - update: spawn a thread for the rest api in the api service --- api-service/src/axum_gateway.rs | 43 +++++++++++++++++++++-- api-service/src/main.rs | 2 +- auth-service/src/grpc.rs | 18 +++++++--- auth-service/src/users.rs | 1 - database-service/src/grpc/user_service.rs | 8 ++--- database-service/src/users.rs | 23 ++++++------ docker-compose.yml | 1 + proto/auth.proto | 1 + 8 files changed, 74 insertions(+), 23 deletions(-) diff --git a/api-service/src/axum_gateway.rs b/api-service/src/axum_gateway.rs index 30569fe..a8099a5 100644 --- a/api-service/src/axum_gateway.rs +++ b/api-service/src/axum_gateway.rs @@ -8,7 +8,7 @@ use tonic::transport::Channel; use tower_http::cors::{Any, CorsLayer}; use auth::auth_service_client::AuthServiceClient; -use auth::LoginRequest; +use auth::{LoginRequest, RegisterRequest}; use log::error; use tokio::sync::Mutex; @@ -27,6 +27,19 @@ struct RestLoginResponse { token: String, } +#[derive(Serialize, Deserialize)] +struct RestRegisterRequest { + username: String, + email: String, + password: String, +} + +#[derive(Serialize, Deserialize)] +struct RestRegisterResponse { + success: bool, + message: String, +} + async fn login_handler( State(grpc_client): State>>>, Json(payload): Json, @@ -49,9 +62,34 @@ async fn login_handler( } } +async fn register_handler( + State(grpc_client): State>>>, + Json(payload): Json, +) -> Result, axum::http::StatusCode> { + let mut client = grpc_client.lock().await; + + let request = tonic::Request::new(RegisterRequest { + username: payload.username, + email: payload.email, + password: payload.password, + }); + + match client.register(request).await { + Ok(response) => Ok(Json(RestRegisterResponse { + success: response.into_inner().user_id != 0, + message: "Registration successful".to_string(), + })), + Err(e) => { + error!("gRPC Login call failed: {}", e); + Err(axum::http::StatusCode::INTERNAL_SERVER_ERROR) + }, + } +} + + pub async fn serve_rest_api( grpc_client: Arc>>, -) -> Result<(), Box> { +) -> Result<(), Box> { let cors = CorsLayer::new() .allow_origin(Any) // Allow requests from any origin .allow_methods([Method::GET, Method::POST]) // Allow specific methods @@ -59,6 +97,7 @@ pub async fn serve_rest_api( let app = Router::new() .route("/api/login", post(login_handler)) + .route("/api/register", post(register_handler)) .with_state(grpc_client) .layer(cors); diff --git a/api-service/src/main.rs b/api-service/src/main.rs index 5489844..fa646ff 100644 --- a/api-service/src/main.rs +++ b/api-service/src/main.rs @@ -65,7 +65,7 @@ async fn main() -> Result<(), Box> { // Start the Axum REST API info!("Starting REST API on {}:{}", addr, port); - axum_gateway::serve_rest_api(grpc_client).await?; + tokio::spawn(axum_gateway::serve_rest_api(grpc_client)); select! { _ = signal::ctrl_c() => {}, diff --git a/auth-service/src/grpc.rs b/auth-service/src/grpc.rs index 764bf41..402ac88 100644 --- a/auth-service/src/grpc.rs +++ b/auth-service/src/grpc.rs @@ -6,7 +6,7 @@ use crate::users::{hash_password, verify_user}; use chrono::{Duration, Utc}; use rand::Rng; use tonic::{Request, Response, Status}; -use tracing::{info, warn}; +use tracing::{error, info, warn}; pub struct MyAuthService { pub db_client: T, @@ -62,11 +62,19 @@ impl AuthService for MyA let hashed_password = hash_password(&req.password); // Create user in the database - let user = self.db_client.clone().create_user(&req.username, &req.email, &hashed_password) - .await - .map_err(|e| Status::internal(format!("Database error: {}", e)))?; + let result = self.db_client.clone().create_user(&req.username, &req.email, &hashed_password) + .await; - Ok(Response::new(RegisterResponse { user_id: user.user_id })) + match result { + Ok(user) => Ok(Response::new(RegisterResponse { + user_id: user.user_id, + message: "User registered successfully".into(), + })), + Err(e) => { + error!("Failed to register user: {:?}", e); + Err(Status::internal("Failed to register user")) + } + } } async fn request_password_reset( diff --git a/auth-service/src/users.rs b/auth-service/src/users.rs index 067415e..0375f54 100644 --- a/auth-service/src/users.rs +++ b/auth-service/src/users.rs @@ -21,7 +21,6 @@ pub fn verify_password(password: &str, hash: &str) -> bool { pub async fn verify_user(mut db_client: T, username: &str, password: &str) -> Option { - // Placeholder: Replace with a gRPC call to the Database Service let user = db_client.get_user_by_username(username).await.ok()?; if verify_password(password, &user.hashed_password) { diff --git a/database-service/src/grpc/user_service.rs b/database-service/src/grpc/user_service.rs index 9243bd1..01ef0d9 100644 --- a/database-service/src/grpc/user_service.rs +++ b/database-service/src/grpc/user_service.rs @@ -20,7 +20,7 @@ impl UserService for MyDatabaseService { username: user.username, email: user.email, hashed_password: user.hashed_password, - roles: user.roles, + roles: user.roles.unwrap_or_else(Vec::new), })) } @@ -30,7 +30,7 @@ impl UserService for MyDatabaseService { ) -> Result, Status> { let req = request.into_inner(); - let user_id = self.db.user_repo.create_user(&req.username, &req.email, &req.hashed_password, &[]) + let user_id = self.db.user_repo.create_user(&req.username, &req.email, &req.hashed_password) .await .map_err(|_| Status::internal("Failed to create user"))?; @@ -53,7 +53,7 @@ impl UserService for MyDatabaseService { username: user.username, email: user.email, hashed_password: user.hashed_password, - roles: user.roles, + roles: user.roles.unwrap_or_else(Vec::new), })) } @@ -72,7 +72,7 @@ impl UserService for MyDatabaseService { username: user.username, email: user.email, hashed_password: user.hashed_password, - roles: user.roles, + roles: user.roles.unwrap_or_else(Vec::new), })) } } \ No newline at end of file diff --git a/database-service/src/users.rs b/database-service/src/users.rs index 0ea5ec9..4724ce3 100644 --- a/database-service/src/users.rs +++ b/database-service/src/users.rs @@ -3,6 +3,7 @@ use crate::redis_cache::{RedisCache, Cache}; // Import RedisCache and Cache Trai use serde::{Serialize, Deserialize}; use std::sync::Arc; use tokio::sync::Mutex; +use tracing::{debug}; #[derive(Debug, FromRow, Serialize, Deserialize)] pub struct User { @@ -10,7 +11,7 @@ pub struct User { pub username: String, pub email: String, pub hashed_password: String, - pub roles: Vec, + pub roles: Option>, pub created_at: chrono::NaiveDateTime, pub updated_at: chrono::NaiveDateTime, } @@ -79,19 +80,21 @@ impl UserRepository { Ok(user) } - pub async fn create_user(&self, username: &str, email: &str, hashed_password: &str, roles: &[String]) -> Result { - let row = sqlx::query( - "INSERT INTO users (username, email, hashed_password, roles, created_at, updated_at) \ - VALUES ($1, $2, $3, $4, NOW(), NOW()) RETURNING id", + pub async fn create_user(&self, username: &str, email: &str, hashed_password: &str) -> Result { + let result = sqlx::query!( + r#" + INSERT INTO users (username, email, hashed_password) + VALUES ($1, $2, $3) + RETURNING id + "#, + username, + email, + hashed_password ) - .bind(username) - .bind(email) - .bind(hashed_password) - .bind(roles) .fetch_one(&self.pool) .await?; - Ok(row.get("id")) + Ok(result.id) } pub async fn update_user_email(&self, user_id: i32, new_email: &str) -> Result<(), sqlx::Error> { diff --git a/docker-compose.yml b/docker-compose.yml index 61848ae..9f775a5 100755 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -20,6 +20,7 @@ dockerfile: ./api-service/Dockerfile ports: - "8080:8080" + - "8081:8081" env_file: - ./api-service/.env - .env diff --git a/proto/auth.proto b/proto/auth.proto index 70ed14c..de260ec 100644 --- a/proto/auth.proto +++ b/proto/auth.proto @@ -37,6 +37,7 @@ message RegisterRequest { message RegisterResponse { int32 user_id = 1; + string message = 2; } message PasswordResetRequest {