oauth1_twitter/endpoints/
authorize.rs

1//! https://developer.twitter.com/en/docs/authentication/api-reference/authorize
2
3use http_api_client_endpoint::{
4    http::{Error as HttpError, Method},
5    Body, Endpoint, Request, Response,
6};
7use serde::{Deserialize, Serialize};
8use serde_qs::Error as SerdeQsError;
9use url::{ParseError as UrlParseError, Url};
10
11pub const URL: &str = "https://api.twitter.com/oauth/authorize";
12
13//
14#[derive(Debug, Clone)]
15pub struct AuthorizeEndpoint {
16    pub oauth_token: String,
17    pub force_login: Option<bool>,
18    pub screen_name: Option<String>,
19}
20impl AuthorizeEndpoint {
21    pub fn new(oauth_token: impl AsRef<str>) -> Self {
22        Self {
23            oauth_token: oauth_token.as_ref().into(),
24            force_login: None,
25            screen_name: None,
26        }
27    }
28
29    pub fn with_force_login(mut self, force_login: bool) -> Self {
30        self.force_login = Some(force_login);
31        self
32    }
33
34    pub fn with_screen_name(mut self, screen_name: impl AsRef<str>) -> Self {
35        self.screen_name = Some(screen_name.as_ref().into());
36        self
37    }
38
39    pub fn authorization_url(&self) -> Result<String, AuthorizeEndpointError> {
40        let request = self.render_request()?;
41        Ok(request.uri().to_string())
42    }
43}
44
45impl Endpoint for AuthorizeEndpoint {
46    type RenderRequestError = AuthorizeEndpointError;
47
48    type ParseResponseOutput = ();
49    type ParseResponseError = AuthorizeEndpointError;
50
51    fn render_request(&self) -> Result<Request<Body>, Self::RenderRequestError> {
52        let mut url = Url::parse(URL).map_err(AuthorizeEndpointError::MakeRequestUrlFailed)?;
53
54        let query = AuthorizeRequestQuery {
55            oauth_token: self.oauth_token.to_owned(),
56            force_login: self.force_login,
57            screen_name: self.screen_name.to_owned(),
58        };
59
60        let query = serde_qs::to_string(&query)
61            .map_err(AuthorizeEndpointError::SerRequestUrlQueryFailed)?;
62
63        url.set_query(Some(query.as_str()));
64
65        let request = Request::builder()
66            .method(Method::GET)
67            .uri(url.as_str())
68            .body(vec![])
69            .map_err(AuthorizeEndpointError::MakeRequestFailed)?;
70
71        Ok(request)
72    }
73
74    fn parse_response(
75        &self,
76        _response: Response<Body>,
77    ) -> Result<Self::ParseResponseOutput, Self::ParseResponseError> {
78        unreachable!()
79    }
80}
81
82//
83#[derive(Deserialize, Serialize, Debug, Clone)]
84pub struct AuthorizeRequestQuery {
85    pub oauth_token: String,
86    pub force_login: Option<bool>,
87    pub screen_name: Option<String>,
88}
89
90//
91//
92//
93#[derive(Debug)]
94pub enum AuthorizeEndpointError {
95    MakeRequestUrlFailed(UrlParseError),
96    SerRequestUrlQueryFailed(SerdeQsError),
97    MakeRequestFailed(HttpError),
98}
99
100impl core::fmt::Display for AuthorizeEndpointError {
101    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
102        write!(f, "{self:?}")
103    }
104}
105
106impl std::error::Error for AuthorizeEndpointError {}
107
108#[cfg(test)]
109mod tests {
110    use super::*;
111
112    #[test]
113    fn test_render_request() {
114        //
115        let req = AuthorizeEndpoint::new("Z6eEdO8MOmk394WozF5oKyuAv855l4Mlqo7hxxxxxx")
116            .render_request()
117            .unwrap();
118        assert_eq!(req.method(), Method::GET);
119        assert_eq!(req.uri(), "https://api.twitter.com/oauth/authorize?oauth_token=Z6eEdO8MOmk394WozF5oKyuAv855l4Mlqo7hxxxxxx");
120
121        //
122        let req = AuthorizeEndpoint::new("Z6eEdO8MOmk394WozF5oKyuAv855l4Mlqo7hxxxxxx")
123            .with_force_login(true)
124            .with_screen_name("xxx")
125            .render_request()
126            .unwrap();
127        assert_eq!(req.method(), Method::GET);
128        assert_eq!(req.uri(), "https://api.twitter.com/oauth/authorize?oauth_token=Z6eEdO8MOmk394WozF5oKyuAv855l4Mlqo7hxxxxxx&force_login=true&screen_name=xxx");
129    }
130}