feat: define and implement RequestAccessToken for Forgejo

This commit is contained in:
Aravinth Manivannan 2024-05-10 20:31:01 +05:30
parent 6a40fcdf50
commit e1ae648c8b
Signed by: realaravinth
GPG key ID: F8F50389936984FF
2 changed files with 88 additions and 3 deletions

View file

@ -0,0 +1,80 @@
use std::time::Duration;
use serde::{Deserialize, Serialize};
use url::Url;
use super::Forgejo;
use crate::auth::application::port::out::forge::{
errors::OutForgePortResult, request_access_token::RequestAccessToken,
};
use crate::auth::domain::OAuthAccessToken;
#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
struct ForgejoAccessTokenResponse {
refresh_token: String,
access_token: String,
token_type: String,
expires_in: u64,
}
impl From<ForgejoAccessTokenResponse> for OAuthAccessToken {
fn from(v: ForgejoAccessTokenResponse) -> Self {
let expires_at = Duration::from_secs(v.expires_in);
Self {
refresh_token: v.refresh_token,
access_token: v.access_token,
token_type: v.token_type,
expires_at, // unix epoch of the instant
expires_in: v.expires_in,
}
}
}
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
struct ForgejoAccessTokenRequest {
code: String,
client_id: String,
client_secret: String,
grant_type: String,
redirect_uri: Url,
}
impl ForgejoAccessTokenRequest {
pub fn new(code: String, redirect_uri: Url, forgejo: &Forgejo) -> Self {
Self {
code,
client_id: forgejo.client_id.clone(),
client_secret: forgejo.client_secret.clone(),
grant_type: "authorization_code".into(),
redirect_uri,
}
}
}
#[async_trait::async_trait]
impl RequestAccessToken for Forgejo {
async fn request_access_token(
&self,
code: String,
redirect_uri: Url,
) -> OutForgePortResult<OAuthAccessToken> {
let u = {
let mut u = self.url().to_owned();
u.set_path("/login/oauth/access_token");
u
};
let payload = ForgejoAccessTokenRequest::new(code, redirect_uri, self);
let res: ForgejoAccessTokenResponse = self
.http_client
.post(u)
.json(&payload)
.send()
.await
.unwrap()
.json()
.await
.unwrap();
Ok(res.into())
}
}

View file

@ -1,5 +1,6 @@
use mockall::predicate::*;
use mockall::*;
use url::Url;
use super::errors::*;
use crate::auth::domain::OAuthAccessToken;
@ -7,7 +8,11 @@ use crate::auth::domain::OAuthAccessToken;
#[automock]
#[async_trait::async_trait]
pub trait RequestAccessToken: Send + Sync {
async fn request_access_token(&self, code: &str) -> OutForgePortResult<OAuthAccessToken>;
async fn request_access_token(
&self,
code: String,
redirect_uri: Url,
) -> OutForgePortResult<OAuthAccessToken>;
}
#[cfg(test)]
@ -21,10 +26,10 @@ pub mod tests {
if let Some(times) = times {
m.expect_request_access_token()
.times(times)
.returning(|_| Ok(OAuthAccessToken::default()));
.returning(|_, _| Ok(OAuthAccessToken::default()));
} else {
m.expect_request_access_token()
.returning(|_| Ok(OAuthAccessToken::default()));
.returning(|_, _| Ok(OAuthAccessToken::default()));
}
Arc::new(m)