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}; use urlencoding::encode; #[derive(Debug, Serialize, Deserialize)] pub struct ClassroomPerson { name: String, surname: String, username: String, user_id: String, } // 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/")] pub async fn get_users(full_name: String) -> (Status, Json>>) { 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, 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) -> Result { // 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 userid 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, }) }