shift_client/types/
account_page.rs1use crate::util::extract_csrf_token;
2use scraper::{Html, Selector};
3
4#[derive(Debug, thiserror::Error)]
6pub enum FromHtmlError {
7 #[error("missing csrf token")]
9 MissingCsrfToken,
10 #[error("missing email")]
12 MissingEmail,
13 #[error("missing display name")]
15 MissingDisplayName,
16 #[error("missing first name")]
18 MissingFirstName,
19}
20
21#[derive(Debug)]
23pub struct AccountPage {
24 pub csrf_token: String,
26 pub email: String,
28 pub display_name: String,
30 pub first_name: String,
32}
33
34impl AccountPage {
35 pub(crate) fn from_html(html: &Html) -> Result<Self, FromHtmlError> {
37 let csrf_token = extract_csrf_token(html)
38 .ok_or(FromHtmlError::MissingCsrfToken)?
39 .to_string();
40
41 let email = get_text_by_id(html, "current_email")
42 .ok_or(FromHtmlError::MissingEmail)?
43 .to_string();
44
45 let display_name = get_text_by_id(html, "current_display_name")
46 .ok_or(FromHtmlError::MissingDisplayName)?
47 .to_string();
48
49 let first_name = get_text_by_id(html, "current_first_name")
50 .ok_or(FromHtmlError::MissingFirstName)?
51 .to_string();
52
53 Ok(Self {
54 csrf_token,
55 email,
56 display_name,
57 first_name,
58 })
59 }
60}
61
62fn get_text_by_id<'a>(html: &'a Html, id: &str) -> Option<&'a str> {
63 let selector = Selector::parse(&format!("#{id}")).ok()?;
64 let element = html.select(&selector).next()?;
65 element.text().next()
66}
67
68#[cfg(test)]
69mod test {
70 use super::*;
71
72 const SAMPLE_1: &str = include_str!("../../test_data/account.html");
73
74 #[test]
75 fn sample_1() {
76 let html = Html::parse_document(SAMPLE_1);
77 let page = AccountPage::from_html(&html).expect("invalid account page");
78 dbg!(page);
79 }
80}