diff options
| author | Santo Cariotti <santo@dcariotti.me> | 2021-08-04 18:09:12 +0200 | 
|---|---|---|
| committer | Santo Cariotti <santo@dcariotti.me> | 2021-08-04 18:09:12 +0200 | 
| commit | 51ea2896cdcdf7b6027f96421a0ce2b454486e03 (patch) | |
| tree | 22eaae83fd2655cad9bc477bc59ce3fb92539788 /src | |
| parent | 7c445e6458b6b209ce59ed89dbb73daa96e2199f (diff) | |
docs: init adds
Diffstat (limited to 'src')
| -rw-r--r-- | src/browser/mod.rs | 5 | ||||
| -rw-r--r-- | src/browser/web_browser.rs | 11 | ||||
| -rw-r--r-- | src/commands.rs | 18 | ||||
| -rw-r--r-- | src/config.rs | 4 | ||||
| -rw-r--r-- | src/main.rs | 3 | 
5 files changed, 41 insertions, 0 deletions
| diff --git a/src/browser/mod.rs b/src/browser/mod.rs index d5ec337..7205f27 100644 --- a/src/browser/mod.rs +++ b/src/browser/mod.rs @@ -6,12 +6,16 @@ use thirtyfour::prelude::WebDriverResult;  mod web_browser; +/// Create a new instance of `Browser` and associate it with the static variable `WEB_BROWSER`. +/// This is an unsecure type of usage, so the block is inside the `unsafe` block  pub async fn init(driver_url: &String) {      unsafe {          WEB_BROWSER = Some(Browser::new(driver_url).await);      }  } +/// Login using the credentials from the `Config`. 'Cause its kind of nature +/// this is an `unsafe` block, so the function is defined like that  pub async unsafe fn login(credentials: &Config) -> WebDriverResult<()> {      if let Some(driver) = &WEB_BROWSER {          driver._login(credentials).await?; @@ -20,6 +24,7 @@ pub async unsafe fn login(credentials: &Config) -> WebDriverResult<()> {      Ok(())  } +/// Get the faculties available for booking a room  pub async unsafe fn get_faculties() -> WebDriverResult<Option<HashMap<String, String>>> {      if let Some(driver) = &WEB_BROWSER {          if let Some(faculties) = driver.faculties().await? { diff --git a/src/browser/web_browser.rs b/src/browser/web_browser.rs index d2ba6c4..c7497cf 100644 --- a/src/browser/web_browser.rs +++ b/src/browser/web_browser.rs @@ -6,14 +6,19 @@ use thirtyfour::error::{WebDriverError, WebDriverErrorInfo, WebDriverErrorValue}  use thirtyfour::prelude::{By, WebDriverResult};  use thirtyfour::{FirefoxCapabilities, WebDriver, WebDriverCommands}; +/// This url is used to make the login  const LOGIN_URL: &str = "https://studenti.smartedu.unict.it/WorkFlow2011/Logon/Logon.aspx?ReturnUrl=%2fStudenti%2fDefault.aspx"; +/// This url is used to go to the page where a student can book a room for study  const ROOMS_URL: &str = "https://studenti.smartedu.unict.it/StudentSpaceReserv?Type=unaTantum"; +/// Browser struct  pub struct Browser { +    /// The driver for Firefox, it could be `None`      driver: Option<WebDriver>,  }  impl Browser { +    /// Create a new `Browser` with a Firefox driver with a personalized User-Agent      pub async fn new(driver_url: &String) -> Self {          let user_agent =              "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:90.0) Gecko/20100101 Firefox/90.0"; @@ -34,6 +39,7 @@ impl Browser {      //     Ok(())      // } +    /// Login on `LOGIN_URL`      pub async unsafe fn _login(&self, credentials: &Config) -> WebDriverResult<()> {          if let Some(_d) = &self.driver {              _d.get(LOGIN_URL).await?; @@ -57,6 +63,8 @@ impl Browser {              thread::sleep(time::Duration::from_millis(2000)); +            // If the current url is the same as `LOGIN_URL` it means the login didn't work, so +            // returns a "login error"              if _d.current_url().await? == LOGIN_URL {                  return Err(WebDriverError::SessionNotCreated(WebDriverErrorInfo {                      status: 400, @@ -74,6 +82,8 @@ impl Browser {          Ok(())      } +    /// Get all faculties for booking and return an `HashMap<key, value>` when `key` is the +    /// key for that faculty inside the `select` tag and `value` is just the text of the option.      pub async fn faculties(&self) -> WebDriverResult<Option<HashMap<String, String>>> {          if let Some(_d) = &self.driver {              _d.get(ROOMS_URL).await?; @@ -106,4 +116,5 @@ impl Browser {      }  } +/// The static unsafe variable used to open a web browser  pub static mut WEB_BROWSER: Option<Browser> = None; diff --git a/src/commands.rs b/src/commands.rs index 2653600..7ee8d83 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -15,11 +15,18 @@ pub enum Command {      Room,  } +/// This is the handler for the commands. +/// It's called by `teloxide` every time someone write `/<text>`. +/// +/// First it checks if the author is authorized to do the commands. Then match that text thanks to +/// the `parse` method of `BotCommand`.  pub async fn handler(      cx: UpdateWithCx<AutoSend<Bot>, Message>,  ) -> Result<(), Box<dyn Error + Send + Sync>> { +    // In the config file there's a key for the Telegram username authorized to use this bot.      let username = Config::from_env().unwrap().username; +    // Compare the author of the message with the Telegram username from the config      if let Some(author) = &cx.update.from().unwrap().username {          if *author != username {              cx.reply_to("You are not allowed to do this action!") @@ -37,10 +44,16 @@ pub async fn handler(      if let Ok(command) = BotCommand::parse(txt.unwrap(), "unict-reservation") {          match command {              Command::Help => { +                // Just send the descriptions of all commands                  cx.answer(Command::descriptions()).await?;              }              Command::Room => {                  let faculties; + +                // This is an array of array because the `InlineKeyboardMarkup` +                // considers each array as a row. +                // So, using this format Vec<Vec<..>> will print a button +                // in `n` different rows in only 1 column.                  let mut faculties_array: Vec<Vec<InlineKeyboardButton>> = vec![];                  unsafe {                      faculties = browser::get_faculties().await.unwrap(); @@ -54,12 +67,17 @@ pub async fn handler(                          )]);                      }                  } else { +                    // If the response of the Option `faculties` is None, just answer +                    // an useless button with a text. +                    // I still don't know if it's a good idea to use a callback instead of +                    // a normal text button, but I could handle any such kind of callback                      faculties_array.push(vec![InlineKeyboardButton::callback(                          "No such element".to_string(),                          "".into(),                      )]);                  } +                // The `new` method accepts an interator                  let keyboard = InlineKeyboardMarkup::new(faculties_array);                  cx.answer("Where?").reply_markup(keyboard).await?;              } diff --git a/src/config.rs b/src/config.rs index 668dda7..f03a09b 100644 --- a/src/config.rs +++ b/src/config.rs @@ -3,9 +3,13 @@ use serde::Deserialize;  #[derive(Deserialize, Debug)]  pub struct Config { +    /// The ID for every italian person, it's used from Smartedu as username      pub cf: String, +    /// The password of Smartedu      pub password: String, +    /// Driver url, an example is `http://localhost:4444` for geckodriver      pub driver_url: String, +    /// Username of the Telegram user authorized to use the bot      pub username: String,  } diff --git a/src/main.rs b/src/main.rs index 270af8e..c038a9b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -17,13 +17,16 @@ async fn main() -> Result<(), Box<dyn Error>> {      let config = Config::from_env().unwrap();      unsafe { +        // Open the browser          browser::init(&config.driver_url).await; +        // Login using the credentials inside the `config`          match browser::login(&config).await {              Ok(_) => {                  log::info!("Logged in Smartedu");              }              Err(e) => { +                // Using the bot when the user is not logged in, is simply useless.                  panic!("You can't connect: `{}`, credentials are {:?}", e, config);              }          } | 
