eeg_certs/backend/src/online_classroom/user.rs
2023-10-03 17:55:58 -05:00

136 lines
4.4 KiB
Rust

use crate::{json_result::JsonResult, model::classroom_user::ClassroomPerson};
use super::session::request;
use rocket::{http::Status, serde::json::Json};
use scraper::{ElementRef, Html, Selector};
use urlencoding::encode;
// Instead of requesting pages and managing session & cookies manually,
// create a wrapper that:
// - Checks if the session cookie is valid
// - If not, tries to login
// - Makes the request
// - Returns the html string, or an error
#[get("/classroom/users/<full_name>")]
pub async fn get_users(full_name: String) -> (Status, Json<JsonResult<Vec<ClassroomPerson>>>) {
let html = request(format!(
"/main/admin/user_list.php?keyword={}&submit=&_qf__search_simple=",
encode(full_name.as_str())
))
.await;
match html {
Ok(html) => match parse_users(&html) {
Ok(users) => (Status::Ok, JsonResult::ok(users)),
Err(reason) => {
// println!("{}", html);
(Status::InternalServerError, JsonResult::err(reason))
}
},
Err(reason) => (Status::InternalServerError, JsonResult::err(reason)),
}
}
fn parse_users(file: &str) -> Result<Vec<ClassroomPerson>, String> {
// Selectors
let Ok(form_selector) = Selector::parse("form#form_users_id") else {
return Err("Error parsing form#form_users_id selector".into());
};
let Ok(tr_selector) = Selector::parse("tr:not(:first-child)") else {
return Err("Error parsing tr:not(:first-child) selector".into());
};
let Ok(td_selector) = Selector::parse("td") else {
return Err("Error parsing td selector".into());
};
let fragment = Html::parse_document(file);
let form_element = match fragment.select(&form_selector).next() {
Some(el) => el,
// If the form is not found, it may mean that no users were found
None => {
let Ok(secondary_button) = Selector::parse("#img_plus_and_minus") else {
return Err("Error parsing secondary button selector".into());
};
match fragment.select(&secondary_button).next() {
Some(_) => return Ok(Vec::new()),
None => return Err("Error parsing html: no form or empty form found.".into()),
}
}
};
let mut result_vec = Vec::new();
for element in form_element.select(&tr_selector) {
let td_vec: Vec<_> = element.select(&td_selector).collect();
if td_vec.len() != 12 {
return Err(format!(
"Error parsing tr: td elements count is not 12, but {}",
td_vec.len()
));
}
result_vec.push(get_person_data(&td_vec)?);
}
Ok(result_vec)
}
fn get_person_data(td_vec: &Vec<ElementRef>) -> Result<ClassroomPerson, String> {
// Surnames
let surname_ref = td_vec[3];
let name_ref = td_vec[4];
let username_ref = td_vec[5];
// Selectors
let a_selector = Selector::parse("a").expect("Error parsing `a` selector");
//
// Get the href of the surname link
//
let surnames_a_node = surname_ref
.first_child()
.ok_or("Expected the 3rd td element to have a children")?;
let surnames_a_element = surnames_a_node
.value()
.as_element()
.ok_or("Expected the 3rd td element to have an html children")?;
let href_value = surnames_a_element
.attr("href")
.ok_or("Expected the 3rd td element's children to have an href attribute")?;
// Get the surname
let Some(surname_a_element) = surname_ref.select(&a_selector).next() else {
return Err("Expected the 3rd td element to have an `a` element".into());
};
let surname = surname_a_element.inner_html();
// Get the name
let Some(surnames_a_element) = name_ref.select(&a_selector).next() else {
return Err("Expected the 4th td element to have an `a` element".into());
};
let name = surnames_a_element.inner_html();
// Get the username
let username = username_ref.inner_html();
// Parse user_id from href
// format: https://testing.aulavirtual.eegsac.com/main/admin/user_information.php?user_id=1087
// Get the position of 'user_id='
let user_id_start = href_value.find("user_id=").ok_or("Error parsing user_id")? + 8;
let user_id = href_value[user_id_start..].to_string();
Ok(ClassroomPerson {
name,
surname,
username,
user_id,
})
}