nadeo_api_rs/
oauth.rs

1use std::collections::HashMap;
2
3use log::warn;
4use serde_json::Value;
5
6use crate::{auth::OAuthToken, client::NadeoApiClient};
7
8pub trait OAuthApiClient: NadeoApiClient {
9    /// For adding API requests, use `get_oauth_permit_and_token`.
10    async fn get_oauth_token(&self) -> Result<OAuthToken, String>;
11
12    async fn get_oauth_permit_and_token(
13        &self,
14    ) -> Result<(OAuthToken, tokio::sync::SemaphorePermit), String> {
15        let permit = self.rate_limit().await;
16        // wait for permit before getting the token in case of refresh
17        let token = self.get_oauth_token().await?;
18        Ok((token, permit))
19    }
20
21    /// Get Display Names for a list of Uuids
22    ///
23    /// <https://webservices.openplanet.dev/oauth/reference/accounts/id-to-name>
24    ///
25    /// calls `GET 	https://api.trackmania.com/api/display-names?accountId[]={accountId}`
26    async fn get_display_names<T>(
27        &self,
28        account_ids: &[T],
29    ) -> Result<HashMap<String, String>, String>
30    where
31        T: Into<String> + Clone,
32    {
33        match account_ids.len() {
34            0 => return Ok(HashMap::new()),
35            x if x > 50 => return Err("Too many account ids (max 50)".to_string()),
36            _ => (),
37        };
38
39        let account_ids = account_ids
40            .iter()
41            .cloned()
42            .map(Into::into)
43            .collect::<Vec<String>>();
44        let mut account_ids_str = account_ids.join("&accountId[]=");
45        account_ids_str.insert_str(0, "accountId[]=");
46
47        let (token, permit) = self.get_oauth_permit_and_token().await?;
48
49        let rb = self
50            .oauth_get(
51                &format!("display-names?{}", account_ids_str),
52                &token,
53                &permit,
54            )
55            .await;
56
57        let resp = rb.send().await.map_err(|e| e.to_string())?;
58        drop(permit);
59
60        let status = resp.status().clone();
61        let headers = resp.headers().clone();
62        let url = resp.url().clone();
63        let body = resp.bytes().await.map_err(|e| e.to_string())?;
64        // let j: Value = resp.json().await.map_err(|e| e.to_string())?;
65        let j: Value = serde_json::from_slice(&body).map_err(|e| e.to_string())?;
66
67        if j.is_array() && j.as_array().unwrap().is_empty() {
68            // then no display names found, we need to return empty strings for all ids
69            return Ok(account_ids
70                .into_iter()
71                .map(|id| (id, "".to_string()))
72                .collect());
73        }
74
75        // map of WSID -> display name
76        let obj = j.as_object().ok_or_else(|| {
77            warn!(
78                "Bad response from get_display_names\nNames = {:?}\nResponse = {:?} {:?} {:?}",
79                &account_ids_str, &status, &url, &headers
80            );
81            format!("Not a json obj: {:?}", &j)
82        })?;
83        let mut hm: HashMap<_, _> = obj
84            .iter()
85            .map(|(k, v)| (k.clone(), v.as_str().unwrap_or(k).to_string()))
86            .collect();
87
88        // some user ids may not have display names, we add "" for them
89        for id in account_ids {
90            if !hm.contains_key(&id) {
91                hm.insert(id, "".to_string());
92            }
93        }
94
95        Ok(hm)
96    }
97
98    // todo: <https://webservices.openplanet.dev/oauth/reference/accounts/name-to-id>	https://api.trackmania.com/api/display-names/account-ids?displayName[]={accountName}
99}
100
101#[cfg(test)]
102mod tests {
103    use std::env;
104
105    use super::*;
106    use crate::{
107        auth::{NadeoClient, OAuthCredentials},
108        prelude::UserAgentDetails,
109        test_helpers::{get_test_creds, get_test_email},
110        user_agent_auto,
111    };
112
113    // works
114    #[ignore]
115    #[tokio::test]
116    async fn test_get_display_names() {
117        let creds = get_test_creds();
118        let client = NadeoClient::create(creds, user_agent_auto!(&get_test_email()), 10)
119            .await
120            .unwrap();
121        let client_id =
122            env::var("NADEO_API_TEST_OAUTH_ID").expect("NADEO_API_TEST_OAUTH_ID not set");
123        let client_secret =
124            env::var("NADEO_API_TEST_OAUTH_SECRET").expect("NADEO_API_TEST_OAUTH_SECRET not set");
125        let client = client
126            .with_oauth(OAuthCredentials::new(&client_id, &client_secret))
127            .unwrap();
128        let names_hm = client
129            .get_display_names(&vec![
130                "5b4d42f4-c2de-407d-b367-cbff3fe817bc",
131                "0a2d1bc0-4aaa-4374-b2db-3d561bdab1c9",
132            ])
133            .await
134            .unwrap();
135        println!("{:?}", names_hm);
136        assert_eq!(names_hm.len(), 2);
137        assert_eq!(
138            names_hm.get("5b4d42f4-c2de-407d-b367-cbff3fe817bc"),
139            Some(&"tooInfinite".to_string())
140        );
141        assert_eq!(
142            names_hm.get("0a2d1bc0-4aaa-4374-b2db-3d561bdab1c9"),
143            Some(&"XertroV".to_string())
144        );
145    }
146}