rsmycqu 0.4.4

A Rust library for interacting with Chonqing University services, including SSO authentication, campus card management, and more.
Documentation
use std::collections::HashMap;

use serde_json::Value;

use crate::{
    errors::mycqu::{MyCQUError, MyCQUResult},
    session::{Client, Session},
    utils::{
        consts::{MYCQU_AUTHORIZE_URL, MYCQU_TOKEN_INDEX_URL, MYCQU_TOKEN_URL},
        get_response_header,
    },
};

#[inline]
fn find_code(location: &(impl AsRef<str> + ?Sized)) -> MyCQUResult<&str> {
    Ok(regex!(r"\?code=([^&]+)&")
        .captures(location.as_ref())
        .and_then(|captures| captures.get(1))
        .ok_or(MyCQUError::AccessError)?
        .as_str())
}

pub(in crate::mycqu) async fn get_oauth_token(
    client: &Client,
    session: &mut Session,
) -> MyCQUResult<String> {
    let res = session.execute(client.get(MYCQU_AUTHORIZE_URL)).await?;
    let code = find_code(get_response_header(&res, "Location").ok_or(MyCQUError::AccessError)?)?;
    let token_data = [
        ("client_id", "enroll-prod"),
        ("client_secret", "app-a-1234"),
        ("code", code),
        ("redirect_uri", MYCQU_TOKEN_INDEX_URL),
        ("grant_type", "authorization_code"),
    ];

    let access_res = session
        .execute(client.post(MYCQU_TOKEN_URL).form(&token_data))
        .await?
        .json::<HashMap<String, Value>>()
        .await?;

    access_res
        .get("access_token")
        .ok_or(MyCQUError::AccessError)?
        .as_str()
        .map(ToString::to_string)
        .ok_or(MyCQUError::AccessError.into())
}

#[cfg(test)]
mod test {
    use rstest::*;

    use super::find_code;

    #[rstest]
    fn test_parse_code() {
        let location = "https://my.cqu.edu.cn/enroll/token-index?code=ZbfCVZ&state=";
        assert_eq!(find_code(location).unwrap(), "ZbfCVZ")
    }
}