use actix_web::{HttpResponse, web}; use actix_web::post; use actix_web::web::{Data, Json}; use log::error; use serde::{Serialize, Deserialize}; use crate::config::CONFIG; use crate::error::{APIError, APIErrorResponse}; use crate::models::{NewUser, User}; use crate::PgPool; use diesel::prelude::*; use crate::tokens::{Scope, token_has_scope}; #[derive(Serialize, Deserialize, Clone)] pub struct UserAddRequest { pub token: String, pub name: String, pub discord_id: i64, pub password_hash: String } #[derive(Serialize, Deserialize, Clone)] pub struct UserResponse { pub id: i32, pub name: String, pub discord_id: i64, pub password_hash: String } #[post("/v1/user/add")] pub async fn add_user_request(pool: Data, req: Json) -> HttpResponse { use crate::schema::users; if !token_has_scope(&req.token, &Scope::UserAdd) { return HttpResponse::Unauthorized().json(APIErrorResponse { errors: vec![ APIError { code: "ERR_MISSING_SCOPE".to_string(), message: "This endpoint requires the user:add scope".to_string(), } ], }) } let req_clone = req.clone(); let pool_clone = pool.clone(); let results = match web::block(move || { let mut conn = pool_clone.get().expect("Unable to get db pool"); users::table.filter(users::name.eq(&req_clone.name)).load::(&mut conn) }).await { Ok(r) => r, Err(e) => { error!("Database error: {}", e); return HttpResponse::InternalServerError().json(APIErrorResponse { errors: vec![ APIError { code: "ERR_BLOCKING_ERROR".to_string(), message: "There was an error running the database request. Please try again later.".to_string() } ] }) } }; let user_list = match results { Ok(r) => r, Err(e) => { error!("Database error: {}", e); return HttpResponse::InternalServerError().json(APIErrorResponse { errors: vec![ APIError { code: "ERR_DB_ERROR".to_string(), message: "There was an error fetching the user. Please try again later.".to_string() } ] }) } }; if !user_list.is_empty() { return HttpResponse::Unauthorized().json(APIErrorResponse { errors: vec![ APIError { code: "ERR_USER_EXISTS".to_string(), message: "Cannot create user that already exists".to_string() } ] }) } let new_user = NewUser { name: req.name.clone(), discord_id: req.discord_id, password_hash: req.password_hash.clone(), }; let insert_result: QueryResult = match web::block(move || { let mut conn = pool.get().expect("Unable to get db pool"); diesel::insert_into(users::table).values(new_user).get_result(&mut conn) }).await { Ok(r) => r, Err(e) => { error!("Database error: {}", e); return HttpResponse::InternalServerError().json(APIErrorResponse { errors: vec![ APIError { code: "ERR_BLOCKING_ERROR".to_string(), message: "There was an error running the insert database request. Please try again later.".to_string() } ] }) } }; let user = match insert_result { Ok(r) => r, Err(e) => { error!("Database error: {}", e); return HttpResponse::InternalServerError().json(APIErrorResponse { errors: vec![ APIError { code: "ERR_DB_ERROR".to_string(), message: "There was an error creating the codereq. Please try again later.".to_string() } ] }) } }; HttpResponse::Ok().json(UserResponse { id: user.id, name: user.name, discord_id: user.discord_id, password_hash: user.password_hash, }) }