diff --git a/backend/src/controller/person/mod.rs b/backend/src/controller/person/mod.rs index 4ffe230..12718cb 100644 --- a/backend/src/controller/person/mod.rs +++ b/backend/src/controller/person/mod.rs @@ -6,11 +6,18 @@ use rocket::serde::json::Json; use crate::json_result::JsonResult; use crate::model::person::{PersonCreate, PersonLink}; use crate::model::reniec_person::ReniecPerson; +use crate::model::DBError; use crate::{db, model::person::Person}; #[get("/person/")] pub async fn get_by_dni(dni: i32) -> (Status, Json>) { - let db = db().await; + let db = match db().await { + Ok(db) => db, + Err(reason) => { + return (Status::InternalServerError, JsonResult::err(reason)); + } + }; + info!("get person with dni {}", dni); /* @@ -23,15 +30,22 @@ pub async fn get_by_dni(dni: i32) -> (Status, Json>) { Err(error) => { match error { // Only if the person is not found in DB, continue - sqlx::Error::RowNotFound => (), + DBError::Sqlx(sqlx::Error::RowNotFound) => (), // Otherwise, throw an error - _ => { + DBError::Sqlx(error) => { error!("Error searching person with dni {}: {:?}", dni, error); return ( Status::InternalServerError, JsonResult::err(format!("Error buscando persona en DB.")), ); } + DBError::Str(reason) => { + error!("Error searching person with dni {}: {}", dni, reason); + return ( + Status::InternalServerError, + JsonResult::err(format!("Error buscando persona en DB.")), + ); + } } } }; diff --git a/backend/src/controller/scans/mod.rs b/backend/src/controller/scans/mod.rs index 2daafc8..58f7d09 100644 --- a/backend/src/controller/scans/mod.rs +++ b/backend/src/controller/scans/mod.rs @@ -224,7 +224,7 @@ fn get_image_info(path: PathBuf) -> ScanInfo { ScanInfo::Error("Error renombrando archivo.".into()) } - } + }; } }; diff --git a/backend/src/main.rs b/backend/src/main.rs index 7c2130e..53580e1 100644 --- a/backend/src/main.rs +++ b/backend/src/main.rs @@ -1,6 +1,7 @@ +#![feature(lazy_cell)] + use cors::Cors; use once_cell::sync::OnceCell; -use rocket::tokio; use sqlx::mysql::MySqlPoolOptions; use sqlx::{MySql, Pool}; use std::env; @@ -18,41 +19,54 @@ pub mod json_result; static DB: OnceCell> = OnceCell::new(); /// Returns a global reference to the database pool -/// +/// /// If the database pool has not been initialized, this function will attempt to initialize it /// up to 3 times -/// +/// /// If the database pool fails to initialize, this function will panic. -pub async fn db() -> &'static Pool { +pub async fn db() -> Result<&'static Pool, String> { let attempts = 3; for _ in 0..attempts { match DB.get() { - Some(db) => return db, + Some(db) => return Ok(db), None => { log::info!("DB not initialized, initializing from db()"); - init_db().await; + let _ = init_db().await; } } - }; + } log::error!("Failed to initialize DB after {} attempts", attempts); - panic!("DB not initialized"); + Err("Failed to initialize DB".to_string()) } -pub async fn init_db() { +pub async fn init_db() -> Result<(), String> { /* Init DB and set it as a global variable */ - let db_url = env::var("DATABASE_URL").expect("DATABASE_URL is not set in .env file"); + let db_url = match env::var("DATABASE_URL") { + Ok(url) => url, + Err(_) => return Err("env DATABASE_URL not found".to_string()), + }; + let pool = MySqlPoolOptions::new() .max_connections(5) .connect(db_url.as_str()) .await; match pool { - Ok(pool) => DB.set(pool).expect("Failed to set DB pool"), - Err(e) => log::error!("Error connecting to DB: {}", e), + Ok(pool) => match DB.set(pool) { + Ok(_) => Ok(()), + Err(_) => { + log::error!("Failed to set DB global variable"); + Err("Failed to set DB".to_string()) + } + }, + Err(e) => { + log::error!("Error connecting to DB: {}", e); + Err("Error connecting to DB".to_string()) + } } } diff --git a/backend/src/model/course.rs b/backend/src/model/course.rs index eaa2df0..6a29653 100644 --- a/backend/src/model/course.rs +++ b/backend/src/model/course.rs @@ -27,12 +27,25 @@ pub struct Course { } impl Course { - pub async fn get_all() -> Result, sqlx::Error> { - let db = db().await; + pub async fn get_all() -> Result, String> { + let db = match db().await { + Ok(db) => db, + Err(reason) => { + return Err(reason); + } + }; - let results = sqlx::query!("SELECT * FROM course") - .fetch_all(db) - .await? + let results = sqlx::query!("SELECT * FROM course").fetch_all(db).await; + + let results = match results { + Ok(res) => res, + Err(error) => { + error!("Error getting courses: {:?}", error); + return Err(format!("Error getting courses")); + } + }; + + let results = results .iter() .map(|d| Course { course_id: d.course_id, @@ -46,8 +59,13 @@ impl Course { Ok(results) } - pub async fn get_course_name(course_id: i32) -> Option { - let db = db().await; + pub async fn get_course_name(course_id: i32) -> Result { + let db = match db().await { + Ok(db) => db, + Err(reason) => { + return Err(reason); + } + }; let res = sqlx::query!( "SELECT course_name FROM course WHERE course_id = ?", @@ -57,8 +75,12 @@ impl Course { .await; match res { - Ok(data) => Some(data.course_name), - Err(_) => None, + Ok(data) => Ok(data.course_name), + Err(sqlx::Error::RowNotFound) => Ok("".into()), + Err(err) => { + log::error!("Error fetching course name: {:?}", err); + return Err("Error fetching course name".into()); + } } } } diff --git a/backend/src/model/custom_label.rs b/backend/src/model/custom_label.rs index eb4aec5..1776173 100644 --- a/backend/src/model/custom_label.rs +++ b/backend/src/model/custom_label.rs @@ -8,8 +8,11 @@ pub struct CustomLabel { } impl CustomLabel { - pub async fn get_all() -> Result, sqlx::Error> { - let db = db().await; + pub async fn get_all() -> Result, String> { + let db = match db().await { + Ok(db) => db, + Err(reason) => return Err(reason), + }; let result = sqlx::query_as::<_, CustomLabel>( r#" @@ -18,20 +21,37 @@ impl CustomLabel { "#, ) .fetch_all(db) - .await?; + .await; - Ok(result) + match result { + Ok(res) => Ok(res), + Err(err) => { + log::error!("Error fetching custom labels: {:?}", err); + Err("Error fetching custom labels".into()) + } + } } - pub async fn get_id_by_value(value: &String) -> Result { - let db = db().await; + pub async fn get_id_by_value(value: &String) -> Result { + let db = match db().await { + Ok(db) => db, + Err(reason) => return Err(reason), + }; let result = sqlx::query!( "SELECT custom_label_id FROM custom_label WHERE custom_label_value = ?", value ) .fetch_all(db) - .await?; + .await; + + let result = match result { + Ok(r) => r, + Err(err) => { + log::error!("Error fetching label by value: {:?}", err); + return Err("Error fetching label by value".into()); + } + }; if result.is_empty() { Ok(-1) @@ -42,15 +62,24 @@ impl CustomLabel { } } - pub async fn create(value: &String) -> Result { - let db = db().await; + pub async fn create(value: &String) -> Result { + let db = match db().await { + Ok(db) => db, + Err(reason) => return Err(reason), + }; - sqlx::query!( + let result = sqlx::query!( "INSERT INTO custom_label (custom_label_value) VALUES (?)", value ) .execute(db) - .await?; + .await; + + if let Err(err) = result { + log::error!("Error inserting custom label: {:?}", err); + return Err("Error inserting custom label".into()); + } + let result = Self::get_id_by_value(value).await?; Ok(result) diff --git a/backend/src/model/mod.rs b/backend/src/model/mod.rs index c96c4da..b340071 100644 --- a/backend/src/model/mod.rs +++ b/backend/src/model/mod.rs @@ -4,3 +4,8 @@ pub mod custom_label; pub mod person; pub mod register; pub mod reniec_person; + +pub enum DBError { + Str(String), + Sqlx(sqlx::Error), +} diff --git a/backend/src/model/person.rs b/backend/src/model/person.rs index aea54f9..1ae0bed 100644 --- a/backend/src/model/person.rs +++ b/backend/src/model/person.rs @@ -3,6 +3,8 @@ use serde::{Deserialize, Serialize}; use crate::db; +use super::DBError; + /// Information about a person registered in DB #[derive(Serialize, Clone)] pub struct Person { @@ -31,8 +33,11 @@ pub struct Person { } impl Person { - pub async fn get_by_dni(dni: i32) -> Result { - let db = db().await; + pub async fn get_by_dni(dni: i32) -> Result { + let db = match db().await { + Ok(db) => db, + Err(reason) => return Err(DBError::Str(reason)), + }; let result = sqlx::query_as!(Person, "SELECT * FROM person WHERE person_dni = ?", dni) .fetch_one(db) @@ -42,7 +47,7 @@ impl Person { Ok(v) => Ok(v), Err(e) => { error!("Error searching person with dni {}: {:?}", dni, e); - Err(e) + Err(DBError::Sqlx(e)) } } } @@ -57,10 +62,13 @@ pub struct PersonCreate { } impl PersonCreate { - pub async fn create(&self) -> Result<(), sqlx::Error> { - let db = db().await; + pub async fn create(&self) -> Result<(), String> { + let db = match db().await { + Ok(db) => db, + Err(err) => return Err(err), + }; - sqlx::query!( + let result = sqlx::query!( "INSERT INTO person (person_dni, person_names, person_paternal_surname, person_maternal_surname) VALUES (?, ?, ?, ?)", self.person_dni, self.person_names, @@ -68,9 +76,15 @@ impl PersonCreate { self.person_maternal_surname, ) .execute(db) - .await?; + .await; - Ok(()) + match result { + Ok(_) => Ok(()), + Err(err) => { + log::error!("Error creating person: {:?}", err); + Err("Error creating person".into()) + } + } } } @@ -84,7 +98,10 @@ pub struct PersonLink { impl PersonLink { /// Links a person to a user in the online classroom pub async fn insert(&self) -> Result<(), String> { - let db = db().await; + let db = match db().await { + Ok(db) => db, + Err(reason) => return Err(reason), + }; let res = sqlx::query!( "UPDATE person SET person_classroom_id = ?, person_classroom_username = ? WHERE person_id = ?", diff --git a/backend/src/model/register.rs b/backend/src/model/register.rs index b528043..4ae22b0 100644 --- a/backend/src/model/register.rs +++ b/backend/src/model/register.rs @@ -31,8 +31,11 @@ pub struct RegisterCreate { impl RegisterCreate { /// Registers a new certificate - pub async fn create(&self) -> Result<(), sqlx::Error> { - let db = db().await; + pub async fn create(&self) -> Result<(), String> { + let db = match db().await { + Ok(db) => db, + Err(reason) => return Err(reason), + }; // Get custom_label_id from db based of self.custom_label let custom_label_id = { @@ -57,7 +60,7 @@ impl RegisterCreate { // Current date in YYYY-MM-DD format let current_date = chrono::Local::now().format("%Y-%m-%d").to_string(); - let _ = sqlx::query!( + let result = sqlx::query!( "INSERT INTO register ( register_code, register_creation_date, @@ -76,15 +79,21 @@ impl RegisterCreate { self.course_id ) .execute(db) - .await?; + .await; - Ok(()) + match result { + Ok(_) => Ok(()), + Err(err) => { + log::error!("Error inserting person: {:?}", err); + Err("Error inserting person".into()) + } + } } - async fn get_next_register_code(course_id: i32) -> Result { - let db = db().await; + async fn get_next_register_code(course_id: i32) -> Result { + let db = db().await?; - let course_name = Course::get_course_name(course_id).await; + let course_name = Course::get_course_name(course_id).await?; // All matpel certs share codes let new_max = if course_name.contains("Matpel") { @@ -94,10 +103,18 @@ impl RegisterCreate { (SELECT course_id FROM course WHERE course_name LIKE 'Matpel%')", ) .fetch_one(db) - .await?; + .await; - // If there are no registers, the new code will start from 50, as per the requirements - res.max.unwrap_or(50) + 1 + match res { + Ok(res) => { + // If there are no registers, the new code will start from 50, as per the requirements + res.max.unwrap_or(50) + 1 + } + Err(err) => { + log::error!("Error fetching matpel code: {:?}", err); + return Err("Error fetching matpel code".into()); + } + } } else { let res = sqlx::query!( "SELECT MAX(register_code) AS max FROM register @@ -105,10 +122,18 @@ impl RegisterCreate { course_id ) .fetch_one(db) - .await?; + .await; - // If there are no registers, the new code will start from 50, as per the requirements - res.max.unwrap_or(50) + 1 + match res { + Ok(res) => { + // If there are no registers, the new code will start from 50, as per the requirements + res.max.unwrap_or(50) + 1 + } + Err(err) => { + log::error!("Error fetching cert code: {:?}", err); + return Err("Error fetching cert code".into()); + } + } }; Ok(new_max) @@ -139,8 +164,8 @@ pub struct Register { } impl Register { - pub async fn get_by_dni(dni: String) -> Result, sqlx::Error> { - let db = db().await; + pub async fn get_by_dni(dni: String) -> Result, String> { + let db = db().await?; let res = sqlx::query!( "SELECT * FROM register @@ -148,38 +173,54 @@ impl Register { dni ) .fetch_all(db) - .await? - .into_iter() - .map(|r| Register { - register_id: r.register_id, - register_code: r.register_code, - register_creation_date: r.register_creation_date.format("%Y-%m-%d").to_string(), - register_display_date: r.register_display_date.format("%Y-%m-%d").to_string(), - register_custom_label: r.register_custom_label, - register_is_preview: r.register_is_preview == 1, - register_person_id: r.register_person_id, - register_course_id: r.register_course_id, - }) - .collect(); + .await; + + let res = match res { + Ok(res) => res, + Err(err) => { + log::error!("Error fetching register for DNI: {:?}", err); + return Err("Error fetching register for DNI".into()); + } + }; + + let res = res + .into_iter() + .map(|r| Register { + register_id: r.register_id, + register_code: r.register_code, + register_creation_date: r.register_creation_date.format("%Y-%m-%d").to_string(), + register_display_date: r.register_display_date.format("%Y-%m-%d").to_string(), + register_custom_label: r.register_custom_label, + register_is_preview: r.register_is_preview == 1, + register_person_id: r.register_person_id, + register_course_id: r.register_course_id, + }) + .collect(); Ok(res) } - pub async fn delete(register_id: i32) -> Result<(), sqlx::Error> { - let db = db().await; + pub async fn delete(register_id: i32) -> Result<(), String> { + let db = db().await?; - let _ = sqlx::query!("DELETE FROM register WHERE register_id = ?", register_id) + let res = sqlx::query!("DELETE FROM register WHERE register_id = ?", register_id) .execute(db) - .await?; + .await; - Ok(()) + match res { + Ok(_) => Ok(()), + Err(err) => { + log::error!("Error deleting register: {:?}", err); + Err("Error deleting register".into()) + } + } } pub async fn get_course_and_person( register_id_list: String, person_dni_list: String, - ) -> Result, sqlx::Error> { - let db = db().await; + ) -> Result, String> { + let db = db().await?; let sql = format!( " @@ -209,7 +250,13 @@ impl Register { log::info!("sql: {}", sql); - let result = db.fetch_all(sql.as_str()).await?; + let result = match db.fetch_all(sql.as_str()).await { + Ok(res) => res, + Err(err) => { + log::error!("Error fetching course & person: {:?}", err); + return Err("Error fetching course & person".into()); + } + }; log::info!("rows: {}", result.len()); diff --git a/backend/src/online_classroom/create_user.rs b/backend/src/online_classroom/create_user.rs index c8b4de4..be21bee 100644 --- a/backend/src/online_classroom/create_user.rs +++ b/backend/src/online_classroom/create_user.rs @@ -61,10 +61,9 @@ pub async fn create(data: &ClassroomPersonCreate) -> Result Err("Expected empty body, found something else".into()) } - /// Makes a request to the user creation form, and gets the /// security token. -/// +/// /// This security token must be present for CSRF reasons async fn get_form_sec_token() -> Result { let creation_form = request("/main/admin/user_add.php".into()).await?; @@ -91,7 +90,6 @@ async fn get_form_sec_token() -> Result { Ok(sec_token_value.into()) } - /// Creates a request body data to send to the classroom fn get_request_body( surnames: &String, diff --git a/backend/src/online_classroom/mod.rs b/backend/src/online_classroom/mod.rs index 75ba722..9906fb3 100644 --- a/backend/src/online_classroom/mod.rs +++ b/backend/src/online_classroom/mod.rs @@ -12,12 +12,11 @@ mod session; pub mod update_expiration_date; pub mod user; - /// Tries to connect to the online classroom, and gets a session cookie /// if neccesary. -/// +/// /// Mantains a global session cookie for ~20 minutes. -/// +/// /// Every time a request is made the session cookie is checked. If more than /// 20 minutes have passed, a new session cookie is requested. #[get("/classroom/connect")] diff --git a/backend/src/online_classroom/session.rs b/backend/src/online_classroom/session.rs index ec89379..62daa97 100644 --- a/backend/src/online_classroom/session.rs +++ b/backend/src/online_classroom/session.rs @@ -166,7 +166,7 @@ pub async fn register_courses_request(url: String, body: String) -> Result Result<(), String> { let last_usage_time = SESSION_TIME.read().unwrap().clone(); @@ -238,7 +238,6 @@ async fn login() -> Result<(), String> { } } - /// Helper function to log the responses recieved from the online classroom, /// for debugging purposes pub fn log_html(html: &String) {