diff --git a/backend/Cargo.lock b/backend/Cargo.lock index d9c15a2..3ebe749 100644 --- a/backend/Cargo.lock +++ b/backend/Cargo.lock @@ -132,6 +132,7 @@ dependencies = [ "dotenvy", "isahc", "lazy_static", + "once_cell", "reqwest", "rocket", "scraper", diff --git a/backend/Cargo.toml b/backend/Cargo.toml index 47a5c74..4a1e412 100644 --- a/backend/Cargo.toml +++ b/backend/Cargo.toml @@ -16,5 +16,6 @@ scraper = "0.17.1" isahc = { version = "1.7.2", features = ["cookies"] } urlencoding = "2.1.3" lazy_static = "1.4.0" +once_cell = "1.18.0" diff --git a/backend/src/controller/person/mod.rs b/backend/src/controller/person/mod.rs index f0f4da8..e5a96d7 100644 --- a/backend/src/controller/person/mod.rs +++ b/backend/src/controller/person/mod.rs @@ -1,13 +1,16 @@ +use std::fmt::format; + use reqwest::Client; use rocket::http::Status; use rocket::serde::json::Json; +use crate::json_result::JsonResult; use crate::model::person::PersonCreate; use crate::model::reniec_person::ReniecPerson; use crate::{db, model::person::Person}; #[get("/person/")] -pub async fn get_by_dni(dni: i32) -> (Status, Json) { +pub async fn get_by_dni(dni: i32) -> (Status, Json>) { let db = db(); // TODO: move db logic to model @@ -29,7 +32,7 @@ pub async fn get_by_dni(dni: i32) -> (Status, Json) { person_classroom_id: None, }; - return (Status::Ok, Json(person)); + return (Status::Ok, JsonResult::ok(person)); } /* @@ -67,33 +70,80 @@ pub async fn get_by_dni(dni: i32) -> (Status, Json) { // If person is found in fake RENIEC API, insert to DB and return if let Some(p) = reniec_person { - let query = sqlx::query!( + // Insert person into DB and get last inserted id + let mut tx = match db.begin().await { + Ok(t) => t, + Err(err) => { + eprintln!("Error starting transaction: {:?}", err); + return ( + Status::InternalServerError, + JsonResult::err(format!("Error iniciando transaccion.")), + ); + } + }; + + let query_1 = sqlx::query!( "INSERT INTO person (person_dni, person_names, person_paternal_surname, person_maternal_surname) VALUES (?, ?, ?, ?)", dni, p.nombres, p.apellidoPaterno, p.apellidoMaterno, ) - .execute(db) + .execute(&mut *tx) .await; - if let Err(reason) = query { - eprintln!("Error inserting person into DB: {:?}", reason); - return (Status::InternalServerError, Json(Person::default())); - } + let query_2 = sqlx::query!("SELECT LAST_INSERT_ID() AS person_id") + .fetch_one(&mut *tx) + .await; - match Person::get_by_dni(dni).await { - Ok(p) => return (Status::Ok, Json(p)), - Err(error) => { - eprintln!("Error fetching person from DB: {:?}", error); - - return (Status::InternalServerError, Json(Person::default())); + match tx.commit().await { + Ok(_) => (), + Err(err) => { + eprintln!("Error commiting transaction: {:?}", err); + return ( + Status::InternalServerError, + JsonResult::err(format!("Error confirmando transaccion.")), + ); } } + + if let Err(reason) = query_1 { + eprintln!("Error inserting person into DB: {:?}", reason); + return ( + Status::InternalServerError, + JsonResult::err(format!("Error insertando a DB.")), + ); + } + + let inserted_id = match query_2 { + Ok(value) => value.person_id, + Err(error) => { + println!("Error getting last inserted id: {:?}", error); + return ( + Status::InternalServerError, + JsonResult::err(format!("Error recuperando ID insertado.")), + ); + } + }; + + return ( + Status::Ok, + JsonResult::ok(Person { + person_id: inserted_id as i32, + person_dni: format!("{}", dni), + person_names: p.nombres, + person_paternal_surname: p.apellidoPaterno, + person_maternal_surname: p.apellidoMaterno, + person_classroom_id: None, + }), + ); } // Return error - (Status::NotFound, Json(Person::default())) + ( + Status::NotFound, + JsonResult::err(format!("Persona no encontrada.")), + ) } #[options("/person")] diff --git a/backend/src/online_classroom/json_result.rs b/backend/src/json_result.rs similarity index 100% rename from backend/src/online_classroom/json_result.rs rename to backend/src/json_result.rs diff --git a/backend/src/main.rs b/backend/src/main.rs index d314a50..4de6274 100644 --- a/backend/src/main.rs +++ b/backend/src/main.rs @@ -12,6 +12,8 @@ mod cors; mod model; mod online_classroom; +pub mod json_result; + static DB: OnceCell> = OnceCell::new(); pub fn db() -> &'static Pool { diff --git a/backend/src/online_classroom/mod.rs b/backend/src/online_classroom/mod.rs index a5baec2..2283e96 100644 --- a/backend/src/online_classroom/mod.rs +++ b/backend/src/online_classroom/mod.rs @@ -1,8 +1,9 @@ use rocket::{http::Status, serde::json::Json}; -use self::{json_result::JsonResult, session::ensure_session}; +use crate::json_result::JsonResult; + +use self::session::ensure_session; -pub mod json_result; mod session; pub mod users; diff --git a/backend/src/online_classroom/session.rs b/backend/src/online_classroom/session.rs index 7d813dd..efb6ff0 100644 --- a/backend/src/online_classroom/session.rs +++ b/backend/src/online_classroom/session.rs @@ -8,7 +8,6 @@ struct CookieHold { pub jar: CookieJar, } - lazy_static! { /// Stores a client with a persistent cookie store static ref SESSION_COOKIE: RwLock = RwLock::new(CookieHold { jar: CookieJar::new()}); @@ -16,7 +15,6 @@ lazy_static! { static ref SESSION_TIME: RwLock = RwLock::new(0); } - /// Makes a request to the online classroom, and returns the html string pub async fn request(url: String) -> Result { let classroom_url = std::env::var("CLASSROOM_URL").expect("CLASSROOM_URL env var is not set!"); diff --git a/backend/src/online_classroom/users.rs b/backend/src/online_classroom/users.rs index b84845d..b158a3e 100644 --- a/backend/src/online_classroom/users.rs +++ b/backend/src/online_classroom/users.rs @@ -1,4 +1,6 @@ -use super::{json_result::JsonResult, session::request}; +use crate::json_result::JsonResult; + +use super::session::request; use rocket::{http::Status, serde::json::Json}; use scraper::{ElementRef, Html, Selector}; use serde::{Deserialize, Serialize}; diff --git a/frontend/package.json b/frontend/package.json index ed6694d..55f6bf4 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -27,6 +27,7 @@ "@solidjs/router": "^0.8.3", "@types/file-saver": "^2.0.5", "@types/qrcode": "^1.5.1", + "axios": "^1.5.1", "file-saver": "^2.0.5", "qrcode": "^1.5.3", "solid-js": "^1.7.6" diff --git a/frontend/src/certs/Search/index.tsx b/frontend/src/certs/Search/index.tsx index 31dbf27..666e421 100644 --- a/frontend/src/certs/Search/index.tsx +++ b/frontend/src/certs/Search/index.tsx @@ -6,6 +6,8 @@ import { XIcon } from "../../icons/XIcon"; import { Person } from "../../types/Person"; import { PersonDisplay } from "./PersonDisplay"; import { PersonRegister } from "./PersonRegister"; +import { backend } from "../../utils/functions"; +import { JsonResult } from "../../types/JsonResult"; type HTMLButtonEvent = JSX.EventHandlerUnion; @@ -44,37 +46,38 @@ export function Search(props: {setPerson: (p: Person | null) => void}) { /* Get the user data from the DB */ - const search = async() => { + const search = () => { setLoading(true); setError(""); - try { - const response = await fetch(`${import.meta.env.VITE_BACKEND_URL}/api/person/${dni()}`); - const body = await response.json(); + backend.get>(`/api/person/${dni()}`) + .then((response) => { + if (response.status === 200) { + setPerson(response.data.Ok); + props.setPerson(response.data.Ok); + setManualCreate(false); + } else if (response.status === 404) { + console.error(response.data); - if (response.ok) { - setPerson(body); - props.setPerson(body); - setManualCreate(false); - } else if (response.status === 404) { - console.error(body); - - setError("No encontrado. Ingresar datos manualmente."); - setManualCreate(true); - props.setPerson(null); - } else { - setError(body); - setManualCreate(false); - } - } catch (e) { - setError(JSON.stringify(e)); - } - - setLoading(false); + setError("No encontrado. Ingresar datos manualmente."); + setManualCreate(true); + props.setPerson(null); + } else { + setError(response.data.Err.reason); + setManualCreate(false); + } + }) + .catch((err) => { + setError(`Error inesperado: ${err.message}`); + console.error(err); + }) + .finally(() => { + setLoading(false); + }) + ; }; - return (
diff --git a/frontend/src/utils/functions.ts b/frontend/src/utils/functions.ts index e7df087..dd5bb8f 100644 --- a/frontend/src/utils/functions.ts +++ b/frontend/src/utils/functions.ts @@ -1,3 +1,4 @@ +import axios from "axios"; // YYYY-MM-DD to DD/MM/YYYY @@ -5,3 +6,7 @@ export function formatDate(date: string): string { const [year, month, day] = date.split("-"); return `${day}/${month}/${year}`; } + +export const backend = axios.create({ + baseURL: import.meta.env.VITE_BACKEND_URL, +});