From 9793583ea956c42362e08d0c54a438c834f5b753 Mon Sep 17 00:00:00 2001 From: augustuswm Date: Sun, 17 Sep 2023 13:20:33 -0700 Subject: [PATCH] Work on listing rfds --- Cargo.toml | 1 + rfd-api-spec.json | 183 +- rfd-api/src/config.rs | 15 +- rfd-api/src/context.rs | 66 + rfd-api/src/endpoints/login/oauth/client.rs | 8 + rfd-api/src/endpoints/login/oauth/code.rs | 6 +- .../src/endpoints/login/oauth/device_token.rs | 8 +- rfd-api/src/endpoints/login/oauth/github.rs | 6 +- rfd-api/src/endpoints/login/oauth/google.rs | 48 +- rfd-api/src/endpoints/login/oauth/mod.rs | 27 +- rfd-api/src/endpoints/rfd.rs | 30 +- rfd-api/src/main.rs | 6 +- rfd-api/src/permissions.rs | 29 +- rfd-api/src/server.rs | 3 +- rfd-cli/src/auth/mod.rs | 159 +- rfd-cli/src/auth/oauth.rs | 4 +- rfd-cli/src/generated/cli.rs | 662 +++- rfd-cli/src/main.rs | 31 +- rfd-model/src/storage/mod.rs | 12 + rfd-model/src/storage/postgres.rs | 52 + rfd-processor/src/github/mod.rs | 2 +- rfd-sdk/src/generated/sdk.rs | 3392 +++++++++++------ 22 files changed, 3414 insertions(+), 1336 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d690740b..ba8ef89b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -64,6 +64,7 @@ serde_urlencoded = "0.7.1" similar = "2.2.1" slog = "2.7.0" slog-async = "2.7.0" +tabwriter = "1.3.0" tap = "1.0.1" thiserror = "1.0.38" tokio = "1.25.0" diff --git a/rfd-api-spec.json b/rfd-api-spec.json index 6c944e31..4af7224f 100644 --- a/rfd-api-spec.json +++ b/rfd-api-spec.json @@ -812,8 +812,37 @@ } } }, + "/rfd": { + "get": { + "summary": "List all available RFDs", + "operationId": "get_rfds", + "responses": { + "200": { + "description": "successful operation", + "content": { + "application/json": { + "schema": { + "title": "Array_of_ListRfd", + "type": "array", + "items": { + "$ref": "#/components/schemas/ListRfd" + } + } + } + } + }, + "4XX": { + "$ref": "#/components/responses/Error" + }, + "5XX": { + "$ref": "#/components/responses/Error" + } + } + } + }, "/rfd/{number}": { "get": { + "summary": "Get the latest representation of an RFD", "operationId": "get_rfd", "parameters": [ { @@ -970,8 +999,11 @@ "GetAllRfds", "GetAssignedRfds", "GetAllDiscussions", + "GetAssignedDiscussions", "CreateOAuthClient", - "GetOAuthClientAll" + "GetAssignedOAuthClients", + "UpdateAssignedOAuthClients", + "DeleteAssignedOAuthClients" ] }, { @@ -1043,6 +1075,19 @@ "type": "object", "properties": { "GetRfd": { + "type": "integer", + "format": "int32" + } + }, + "required": [ + "GetRfd" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "GetRfds": { "type": "array", "items": { "type": "integer", @@ -1052,7 +1097,37 @@ } }, "required": [ - "GetRfd" + "GetRfds" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "GetDiscussion": { + "type": "integer", + "format": "int32" + } + }, + "required": [ + "GetDiscussion" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "GetDiscussions": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "uniqueItems": true + } + }, + "required": [ + "GetDiscussions" ], "additionalProperties": false }, @@ -1069,6 +1144,23 @@ ], "additionalProperties": false }, + { + "type": "object", + "properties": { + "GetOAuthClients": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "uniqueItems": true + } + }, + "required": [ + "GetOAuthClients" + ], + "additionalProperties": false + }, { "type": "object", "properties": { @@ -1082,6 +1174,23 @@ ], "additionalProperties": false }, + { + "type": "object", + "properties": { + "UpdateOAuthClients": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "uniqueItems": true + } + }, + "required": [ + "UpdateOAuthClients" + ], + "additionalProperties": false + }, { "type": "object", "properties": { @@ -1094,6 +1203,23 @@ "DeleteOAuthClient" ], "additionalProperties": false + }, + { + "type": "object", + "properties": { + "DeleteOAuthClients": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "uniqueItems": true + } + }, + "required": [ + "DeleteOAuthClients" + ], + "additionalProperties": false } ] }, @@ -1412,6 +1538,56 @@ "permissions" ] }, + "ListRfd": { + "type": "object", + "properties": { + "authors": { + "nullable": true, + "type": "string" + }, + "commit": { + "type": "string" + }, + "committed_at": { + "type": "string", + "format": "date-time" + }, + "discussion": { + "nullable": true, + "type": "string" + }, + "id": { + "type": "string", + "format": "uuid" + }, + "link": { + "nullable": true, + "type": "string" + }, + "rfd_number": { + "type": "integer", + "format": "int32" + }, + "sha": { + "type": "string" + }, + "state": { + "nullable": true, + "type": "string" + }, + "title": { + "type": "string" + } + }, + "required": [ + "commit", + "committed_at", + "id", + "rfd_number", + "sha", + "title" + ] + }, "OAuthAuthzCodeExchangeBody": { "type": "object", "properties": { @@ -1607,7 +1783,8 @@ "type": "array", "items": { "$ref": "#/components/schemas/ApiPermission" - } + }, + "uniqueItems": true } } }, diff --git a/rfd-api/src/config.rs b/rfd-api/src/config.rs index 4d675592..e912a4f6 100644 --- a/rfd-api/src/config.rs +++ b/rfd-api/src/config.rs @@ -138,6 +138,18 @@ pub struct GitHubOAuthConfig { #[derive(Debug, Deserialize)] pub struct GoogleOAuthConfig { + pub device: GoogleOAuthDeviceConfig, + pub web: GoogleOAuthWebConfig, +} + +#[derive(Debug, Deserialize)] +pub struct GoogleOAuthDeviceConfig { + pub client_id: String, + pub client_secret: String, +} + +#[derive(Debug, Deserialize)] +pub struct GoogleOAuthWebConfig { pub client_id: String, pub client_secret: String, pub redirect_uri: String, @@ -146,7 +158,8 @@ pub struct GoogleOAuthConfig { impl AppConfig { pub fn new() -> Result { let config = Config::builder() - .add_source(File::with_name("config.toml")) + .add_source(File::with_name("config.toml").required(false)) + .add_source(File::with_name("rfd-api/config.toml").required(false)) .add_source(Environment::default()) .build()?; diff --git a/rfd-api/src/context.rs b/rfd-api/src/context.rs index 6a107008..756b2f26 100644 --- a/rfd-api/src/context.rs +++ b/rfd-api/src/context.rs @@ -5,6 +5,7 @@ use hyper::{client::HttpConnector, Body, Client}; use hyper_tls::HttpsConnector; use jsonwebtoken::jwk::JwkSet; use oauth2::CsrfToken; +use partial_struct::partial; use rfd_model::{ permissions::{Caller, Permissions}, schema_ext::LoginAttemptState, @@ -144,6 +145,7 @@ pub enum LoginAttemptError { Storage(#[from] StoreError), } +#[partial(ListRfd)] #[derive(Debug, Clone, Deserialize, Serialize, JsonSchema)] pub struct FullRfd { pub id: Uuid, @@ -153,10 +155,12 @@ pub struct FullRfd { pub title: String, pub state: Option, pub authors: Option, + #[partial(ListRfd(skip))] pub content: String, pub sha: String, pub commit: String, pub committed_at: DateTime, + #[partial(ListRfd(skip))] pub pdfs: Vec, } @@ -319,6 +323,56 @@ impl ApiContext { // RFD Operations + pub async fn list_rfds( + &self, + caller: &Caller, + ) -> Result, StoreError> { + let mut filter = RfdFilter::default(); + + if !caller.can(&ApiPermission::GetAllRfds) { + let numbers = caller.permissions.iter().filter_map(|p| { + match p { + ApiPermission::GetRfd(number) => Some(*number), + _ => None + } + }).collect::>(); + + filter = filter.rfd_number(Some(numbers)); + } + + let rfds = RfdStore::list( + &*self.storage, + filter, + &ListPagination::default().limit(1), + ) + .await.tap_err(|err| tracing::error!(?err, "Failed to lookup RFDs"))?; + + let rfd_revisions = RfdRevisionStore::list_unique_rfd( + &*self.storage, + RfdRevisionFilter::default() + .rfd(Some(rfds.iter().map(|rfd| rfd.id).collect())), + &ListPagination::default(), + ) + .await.tap_err(|err| tracing::error!(?err, "Failed to lookup RFD revisions"))?; + + let rfd_list = rfds.into_iter().zip(rfd_revisions).map(|(rfd, revision)| { + ListRfd { + id: rfd.id, + rfd_number: rfd.rfd_number, + link: rfd.link, + discussion: revision.discussion, + title: revision.title, + state: revision.state, + authors: revision.authors, + sha: revision.sha, + commit: revision.commit_sha, + committed_at: revision.committed_at, + } + }).collect::>(); + + Ok(rfd_list) + } + pub async fn get_rfd( &self, rfd_number: i32, @@ -888,6 +942,18 @@ pub(crate) mod tests { .await } + async fn list_unique_rfd( + &self, + filter: rfd_model::storage::RfdRevisionFilter, + pagination: &ListPagination, + ) -> Result, rfd_model::storage::StoreError> { + self.rfd_revision_store + .as_ref() + .unwrap() + .list(filter, pagination) + .await + } + async fn upsert( &self, new_revision: NewRfdRevision, diff --git a/rfd-api/src/endpoints/login/oauth/client.rs b/rfd-api/src/endpoints/login/oauth/client.rs index 721cabb8..1aca6521 100644 --- a/rfd-api/src/endpoints/login/oauth/client.rs +++ b/rfd-api/src/endpoints/login/oauth/client.rs @@ -3,6 +3,7 @@ use http::StatusCode; use rfd_model::{OAuthClient, OAuthClientRedirectUri, OAuthClientSecret}; use schemars::JsonSchema; use serde::Deserialize; +use trace_request::trace_request; use tracing::instrument; use uuid::Uuid; @@ -16,6 +17,7 @@ use crate::{ }; /// List OAuth clients +#[trace_request] #[endpoint { method = GET, path = "/oauth/client" @@ -41,6 +43,7 @@ async fn list_oauth_clients_op( } /// Create a new OAuth Client +#[trace_request] #[endpoint { method = POST, path = "/oauth/client" @@ -83,6 +86,7 @@ pub struct GetOAuthClientPath { } /// Get an new OAuth Client +#[trace_request] #[endpoint { method = GET, path = "/oauth/client/{client_id}" @@ -121,6 +125,7 @@ pub struct AddOAuthClientSecretPath { } /// Add an OAuth client secret +#[trace_request] #[endpoint { method = POST, path = "/oauth/client/{client_id}/secret" @@ -167,6 +172,7 @@ pub struct DeleteOAuthClientSecretPath { } /// Delete an OAuth client secret +#[trace_request] #[endpoint { method = DELETE, path = "/oauth/client/{client_id}/secret/{secret_id}" @@ -210,6 +216,7 @@ pub struct AddOAuthClientRedirectBody { } /// Add an OAuth client redirect uri +#[trace_request] #[endpoint { method = POST, path = "/oauth/client/{client_id}/redirect_uri" @@ -251,6 +258,7 @@ pub struct DeleteOAuthClientRedirectPath { } /// Delete an OAuth client redirect uri +#[trace_request] #[endpoint { method = DELETE, path = "/oauth/client/{client_id}/redirect_uri/{redirect_uri_id}" diff --git a/rfd-api/src/endpoints/login/oauth/code.rs b/rfd-api/src/endpoints/login/oauth/code.rs index e72c9f0e..21a5d0f7 100644 --- a/rfd-api/src/endpoints/login/oauth/code.rs +++ b/rfd-api/src/endpoints/login/oauth/code.rs @@ -25,7 +25,7 @@ use super::{OAuthProviderNameParam, UserInfoProvider}; use crate::{ authn::key::RawApiKey, context::ApiContext, - endpoints::login::LoginError, + endpoints::login::{LoginError, oauth::ClientType}, error::ApiError, util::{ request::RequestCookies, @@ -97,7 +97,7 @@ pub async fn authz_code_redirect( // TODO: This behavior should be changed so that clients are precomputed. We do not need to be // constructing a new client on every request. That said, we need to ensure the client does not // maintain state between requests - let client = provider.as_client().map_err(to_internal_error)?; + let client = provider.as_client(&ClientType::Web).map_err(to_internal_error)?; let (pkce_challenge, pkce_verifier) = PkceCodeChallenge::new_random_sha256(); // Construct a new login attempt with the minimum required values @@ -366,7 +366,7 @@ pub async fn authz_code_exchange( })?; // Exchange the stored authorization code with the remote provider for a remote access token - let client = provider.as_client().map_err(to_internal_error)?; + let client = provider.as_client(&ClientType::Web).map_err(to_internal_error)?; let mut request = client.exchange_code(AuthorizationCode::new( attempt.provider_authz_code.ok_or_else(|| { internal_error("Expected authorization code to exist due to attempt state") diff --git a/rfd-api/src/endpoints/login/oauth/device_token.rs b/rfd-api/src/endpoints/login/oauth/device_token.rs index b1d7baab..ab76afb1 100644 --- a/rfd-api/src/endpoints/login/oauth/device_token.rs +++ b/rfd-api/src/endpoints/login/oauth/device_token.rs @@ -10,7 +10,7 @@ use tap::TapFallible; use trace_request::trace_request; use tracing::instrument; -use super::{OAuthProvider, OAuthProviderInfo, OAuthProviderNameParam, UserInfoProvider}; +use super::{OAuthProvider, OAuthProviderInfo, OAuthProviderNameParam, UserInfoProvider, ClientType}; use crate::{ context::ApiContext, endpoints::login::LoginError, error::ApiError, util::response::bad_request, }; @@ -35,7 +35,7 @@ pub async fn get_device_provider( .map_err(ApiError::OAuth)?; Ok(HttpResponseOk( - provider.provider_info(&rqctx.context().public_url), + provider.provider_info(&rqctx.context().public_url, &ClientType::Device), )) } @@ -65,9 +65,9 @@ impl AccessTokenExchange { req: AccessTokenExchangeRequest, provider: &Box, ) -> Option { - provider.client_secret().map(|client_secret| Self { + provider.client_secret(&ClientType::Device).map(|client_secret| Self { provider: ProviderTokenExchange { - client_id: provider.client_id().to_string(), + client_id: provider.client_id(&ClientType::Device).to_string(), device_code: req.device_code, grant_type: req.grant_type, client_secret: client_secret.to_string(), diff --git a/rfd-api/src/endpoints/login/oauth/github.rs b/rfd-api/src/endpoints/login/oauth/github.rs index 8c1a6954..7828516b 100644 --- a/rfd-api/src/endpoints/login/oauth/github.rs +++ b/rfd-api/src/endpoints/login/oauth/github.rs @@ -5,7 +5,7 @@ use serde::{Deserialize, Serialize}; use crate::endpoints::login::{ExternalUserId, UserInfo, UserInfoError}; -use super::{ExtractUserInfo, OAuthProvider, OAuthProviderName}; +use super::{ExtractUserInfo, OAuthProvider, OAuthProviderName, ClientType}; pub struct GitHubOAuthProvider { public: GitHubPublicProvider, @@ -78,11 +78,11 @@ impl OAuthProvider for GitHubOAuthProvider { vec!["user:email"] } - fn client_id(&self) -> &str { + fn client_id(&self, _client_type: &ClientType) -> &str { &self.public.client_id } - fn client_secret(&self) -> Option<&str> { + fn client_secret(&self, _client_type: &ClientType) -> Option<&str> { self.private .as_ref() .map(|private| private.client_secret.as_str()) diff --git a/rfd-api/src/endpoints/login/oauth/google.rs b/rfd-api/src/endpoints/login/oauth/google.rs index 9917ff15..b5be1e4c 100644 --- a/rfd-api/src/endpoints/login/oauth/google.rs +++ b/rfd-api/src/endpoints/login/oauth/google.rs @@ -1,15 +1,17 @@ use std::fmt; use hyper::body::Bytes; -use serde::{Deserialize, Serialize}; +use serde::Deserialize; use crate::endpoints::login::{ExternalUserId, UserInfo, UserInfoError}; -use super::{ExtractUserInfo, OAuthProvider, OAuthProviderName}; +use super::{ExtractUserInfo, OAuthProvider, OAuthProviderName, ClientType, OAuthPublicCredentials, OAuthPrivateCredentials}; pub struct GoogleOAuthProvider { - public: GooglePublicProvider, - private: Option, + device_public: OAuthPublicCredentials, + device_private: Option, + web_public: OAuthPublicCredentials, + web_private: Option, } impl fmt::Debug for GoogleOAuthProvider { @@ -18,20 +20,18 @@ impl fmt::Debug for GoogleOAuthProvider { } } -#[derive(Debug, Deserialize, Serialize)] -pub struct GooglePublicProvider { - client_id: String, -} - -pub struct GooglePrivateProvider { - client_secret: String, -} - impl GoogleOAuthProvider { - pub fn new(client_id: String, client_secret: String) -> Self { + pub fn new( + device_client_id: String, + device_client_secret: String, + web_client_id: String, + web_client_secret: String, + ) -> Self { Self { - public: GooglePublicProvider { client_id }, - private: Some(GooglePrivateProvider { client_secret }), + device_public: OAuthPublicCredentials { client_id: device_client_id }, + device_private: Some(OAuthPrivateCredentials { client_secret: device_client_secret }), + web_public: OAuthPublicCredentials { client_id: web_client_id }, + web_private: Some(OAuthPrivateCredentials { client_secret: web_client_secret }), } } } @@ -70,14 +70,18 @@ impl OAuthProvider for GoogleOAuthProvider { vec!["https://www.googleapis.com/auth/userinfo.email", "openid"] } - fn client_id(&self) -> &str { - &self.public.client_id + fn client_id(&self, client_type: &ClientType) -> &str { + match client_type { + ClientType::Device => &self.device_public.client_id, + ClientType::Web => &self.web_public.client_id, + } } - fn client_secret(&self) -> Option<&str> { - self.private - .as_ref() - .map(|private| private.client_secret.as_str()) + fn client_secret(&self, client_type: &ClientType) -> Option<&str> { + match client_type { + ClientType::Device => self.device_private.as_ref().map(|private| private.client_secret.as_str()), + ClientType::Web => self.web_private.as_ref().map(|private| private.client_secret.as_str()), + } } fn user_info_endpoints(&self) -> Vec<&str> { diff --git a/rfd-api/src/endpoints/login/oauth/mod.rs b/rfd-api/src/endpoints/login/oauth/mod.rs index f2dbb850..63eb3377 100644 --- a/rfd-api/src/endpoints/login/oauth/mod.rs +++ b/rfd-api/src/endpoints/login/oauth/mod.rs @@ -27,11 +27,24 @@ pub enum OAuthProviderError { FailToCreateInvalidProvider, } +pub enum ClientType { + Device, + Web, +} + +pub struct OAuthPublicCredentials { + client_id: String, +} + +pub struct OAuthPrivateCredentials { + client_secret: String, +} + pub trait OAuthProvider: ExtractUserInfo + Debug { fn name(&self) -> OAuthProviderName; fn scopes(&self) -> Vec<&str>; - fn client_id(&self) -> &str; - fn client_secret(&self) -> Option<&str>; + fn client_id(&self, client_type: &ClientType) -> &str; + fn client_secret(&self, client_type: &ClientType) -> Option<&str>; // TODO: How can user info be change to something statically checked instead of a runtime check fn user_info_endpoints(&self) -> Vec<&str>; @@ -41,10 +54,10 @@ pub trait OAuthProvider: ExtractUserInfo + Debug { fn token_exchange_endpoint(&self) -> &str; fn supports_pkce(&self) -> bool; - fn provider_info(&self, public_url: &str) -> OAuthProviderInfo { + fn provider_info(&self, public_url: &str, client_type: &ClientType) -> OAuthProviderInfo { OAuthProviderInfo { provider: self.name(), - client_id: self.client_id().to_string(), + client_id: self.client_id(client_type).to_string(), auth_url_endpoint: self.auth_url_endpoint().to_string(), device_code_endpoint: self.device_code_endpoint().to_string(), token_endpoint: format!("{}/login/oauth/{}/device/exchange", public_url, self.name(),), @@ -56,10 +69,10 @@ pub trait OAuthProvider: ExtractUserInfo + Debug { } } - fn as_client(&self) -> Result { + fn as_client(&self, client_type: &ClientType) -> Result { Ok(BasicClient::new( - ClientId::new(self.client_id().to_string()), - self.client_secret() + ClientId::new(self.client_id(client_type).to_string()), + self.client_secret(client_type) .map(|s| ClientSecret::new(s.to_string())), AuthUrl::new(self.auth_url_endpoint().to_string())?, Some(TokenUrl::new(self.token_exchange_endpoint().to_string())?), diff --git a/rfd-api/src/endpoints/rfd.rs b/rfd-api/src/endpoints/rfd.rs index 3104a452..a660ef5c 100644 --- a/rfd-api/src/endpoints/rfd.rs +++ b/rfd-api/src/endpoints/rfd.rs @@ -6,10 +6,10 @@ use trace_request::trace_request; use tracing::instrument; use crate::{ - context::{ApiContext, FullRfd}, + context::{ApiContext, FullRfd, ListRfd}, permissions::ApiPermission, util::response::{client_error, internal_error, not_found}, - ApiCaller, + ApiCaller, error::ApiError, }; #[derive(Debug, Deserialize, JsonSchema)] @@ -17,7 +17,31 @@ pub struct RfdPathParams { number: String, } -// Get the latest known representation of an RFD +/// List all available RFDs +#[trace_request] +#[endpoint { + method = GET, + path = "/rfd", +}] +#[instrument(skip(rqctx), fields(request_id = rqctx.request_id), err(Debug))] +pub async fn get_rfds( + rqctx: RequestContext, +) -> Result>, HttpError> { + let ctx = rqctx.context(); + let auth = ctx.authn_token(&rqctx).await?; + get_rfds_op(ctx, &ctx.get_caller(&auth).await?).await +} + +#[instrument(skip(ctx, caller), fields(caller = ?caller.id), err(Debug))] +async fn get_rfds_op( + ctx: &ApiContext, + caller: &ApiCaller, +) -> Result>, HttpError> { + let rfds = ctx.list_rfds(caller).await.map_err(ApiError::Storage)?; + Ok(HttpResponseOk(rfds)) +} + +/// Get the latest representation of an RFD #[trace_request] #[endpoint { method = GET, diff --git a/rfd-api/src/main.rs b/rfd-api/src/main.rs index 0a146606..b04a57eb 100644 --- a/rfd-api/src/main.rs +++ b/rfd-api/src/main.rs @@ -87,8 +87,10 @@ async fn main() -> Result<(), Box> { OAuthProviderName::Google, Box::new(move || { Box::new(GoogleOAuthProvider::new( - google.client_id.clone(), - google.client_secret.clone(), + google.device.client_id.clone(), + google.device.client_secret.clone(), + google.web.client_id.clone(), + google.web.client_secret.clone(), )) }), ) diff --git a/rfd-api/src/permissions.rs b/rfd-api/src/permissions.rs index e4693e90..5b9516b7 100644 --- a/rfd-api/src/permissions.rs +++ b/rfd-api/src/permissions.rs @@ -133,6 +133,7 @@ impl PermissionStorage for Permissions { }, ApiPermission::GetAssignedRfds => { + expanded.push(p.clone()); for p in user.permissions().iter() { match p { ApiPermission::GetRfd(number) => expanded.push(ApiPermission::GetRfd(*number)), @@ -141,6 +142,7 @@ impl PermissionStorage for Permissions { } }, ApiPermission::GetAssignedOAuthClients => { + expanded.push(p.clone()); for p in user.permissions().iter() { match p { ApiPermission::GetOAuthClient(id) => expanded.push(ApiPermission::GetOAuthClient(*id)), @@ -149,6 +151,7 @@ impl PermissionStorage for Permissions { } }, ApiPermission::UpdateAssignedOAuthClients => { + expanded.push(p.clone()); for p in user.permissions().iter() { match p { ApiPermission::UpdateOAuthClient(id) => expanded.push(ApiPermission::UpdateOAuthClient(*id)), @@ -157,6 +160,7 @@ impl PermissionStorage for Permissions { } }, ApiPermission::DeleteAssignedOAuthClients => { + expanded.push(p.clone()); for p in user.permissions().iter() { match p { ApiPermission::DeleteOAuthClient(id) => expanded.push(ApiPermission::DeleteOAuthClient(*id)), @@ -165,11 +169,26 @@ impl PermissionStorage for Permissions { } }, - ApiPermission::GetApiUserSelf => expanded.push(ApiPermission::GetApiUser(*user.id())), - ApiPermission::CreateApiUserTokenSelf => expanded.push(ApiPermission::CreateApiUserToken(*user.id())), - ApiPermission::GetApiUserTokenSelf => expanded.push(ApiPermission::GetApiUserToken(*user.id())), - ApiPermission::DeleteApiUserTokenSelf => expanded.push(ApiPermission::DeleteApiUserToken(*user.id())), - ApiPermission::UpdateApiUserSelf => expanded.push(ApiPermission::UpdateApiUser(*user.id())), + ApiPermission::GetApiUserSelf => { + expanded.push(p.clone()); + expanded.push(ApiPermission::GetApiUser(*user.id())) + }, + ApiPermission::CreateApiUserTokenSelf => { + expanded.push(p.clone()); + expanded.push(ApiPermission::CreateApiUserToken(*user.id())) + }, + ApiPermission::GetApiUserTokenSelf => { + expanded.push(p.clone()); + expanded.push(ApiPermission::GetApiUserToken(*user.id())) + }, + ApiPermission::DeleteApiUserTokenSelf => { + expanded.push(p.clone()); + expanded.push(ApiPermission::DeleteApiUserToken(*user.id())) + }, + ApiPermission::UpdateApiUserSelf => { + expanded.push(p.clone()); + expanded.push(ApiPermission::UpdateApiUser(*user.id())) + }, other => expanded.push(other.clone()), } diff --git a/rfd-api/src/server.rs b/rfd-api/src/server.rs index 0845655d..d5a37d77 100644 --- a/rfd-api/src/server.rs +++ b/rfd-api/src/server.rs @@ -22,7 +22,7 @@ use crate::{ code::{authz_code_callback, authz_code_exchange, authz_code_redirect}, device_token::{exchange_device_token, get_device_provider}, }, - rfd::get_rfd, + rfd::{get_rfd, get_rfds}, webhook::github_webhook, }, }; @@ -71,6 +71,7 @@ pub fn server( }); // RFDs + api.register(get_rfds).unwrap(); api.register(get_rfd).unwrap(); // Webhooks diff --git a/rfd-cli/src/auth/mod.rs b/rfd-cli/src/auth/mod.rs index f5506aa0..e75e6553 100644 --- a/rfd-cli/src/auth/mod.rs +++ b/rfd-cli/src/auth/mod.rs @@ -2,72 +2,28 @@ use anyhow::Result; use chrono::{DateTime, Duration, Utc}; use clap::{Parser, Subcommand}; use oauth2::TokenResponse; -use rfd_sdk::types::{ - AccessTokenProviderLogin, AccessTokenProviderName, JwtProviderLogin, JwtProviderName, - LoginPermissions, OAuthProviderName, -}; +use rfd_sdk::types::OAuthProviderName; use std::ops::Add; use crate::{err::format_api_err, Context}; mod oauth; -/// Authenticates and generates an access token for interacting with the api +// Authenticates and generates an access token for interacting with the api #[derive(Parser, Debug)] #[clap(name = "login")] pub struct Login { - #[clap(subcommand)] + #[command(subcommand)] provider: LoginProvider, } -#[derive(Subcommand, Debug)] -pub enum LoginProvider { - /// Login via GitHub - #[clap(subcommand, name = "github")] - GitHub(GitHubLoginMethod), - /// Login via Google - #[clap(subcommand)] - Google(GoogleLoginMethod), -} - -#[derive(Subcommand, Debug)] -pub enum GitHubLoginMethod { - /// Authenticate against a GitHub account with an access, personal, or fine-grained token - Token { - /// An access, personal, or fine-grained token - #[clap(short = 't', long, env = "RFD_GITHUB_TOKEN")] - token: String, - /// An expiration date for generated RFD API access token. If none is specified the - /// generated token will last for one week - #[clap(short = 'e', long)] - expiration: Option>, - }, -} - -#[derive(Subcommand, Debug)] -pub enum GoogleLoginMethod { - /// Authenticate against a Google account with an id token - Id { - /// An id token signed by Google. The token must have the openid and email scopes - #[clap(short = 't', long, env = "RFD_GOOGLE_ID_TOKEN")] - token: String, - - /// An expiration date for generated RFD API access token. If none is specified the - /// generated token will last for one week - #[clap(short = 'e', long)] - expiration: Option>, - }, - #[clap(name = "oauth")] - /// Authenticate against a Google account via an OAuth flow - OAuth, -} - impl Login { pub async fn run(&self, ctx: &mut Context) -> Result<()> { - let access_token = match &self.provider { - LoginProvider::GitHub(github) => github.run(ctx).await, - LoginProvider::Google(google) => google.run(ctx).await, - }?; + let access_token = self.provider.run(ctx).await?; + // let access_token = match &self.provider { + // LoginProvider::GitHub(github) => github.run(ctx).await, + // LoginProvider::Google(google) => google.run(ctx).await, + // }?; ctx.config.set_token(access_token); ctx.config.save()?; @@ -76,77 +32,40 @@ impl Login { } } -impl GitHubLoginMethod { - async fn run(&self, ctx: &mut Context) -> Result { - match self { - GitHubLoginMethod::Token { token, expiration } => { - let response = ctx - .client()? - .access_token_login() - .provider(AccessTokenProviderName::Github) - .body(AccessTokenProviderLogin { - token: token.to_string(), - expiration: expiration.or_else(|| Some(Utc::now().add(Duration::weeks(1)))), - permissions: LoginPermissions::All, - }) - .send() - .await; - - match response { - Ok(response) => Ok(response.into_inner().token), - Err(err) => Err(format_api_err(&ctx, err)), - } - } - } - } +#[derive(Subcommand, Debug)] +pub enum LoginProvider { + /// Login via GitHub + // #[command(subcommand, name = "github")] + // GitHub, + /// Login via Google + Google, } -impl GoogleLoginMethod { +impl LoginProvider { async fn run(&self, ctx: &mut Context) -> Result { - match self { - GoogleLoginMethod::Id { token, expiration } => { - let response = ctx - .client()? - .jwt_login() - .provider(JwtProviderName::Google) - .body(JwtProviderLogin { - token: token.to_string(), - expiration: expiration.or_else(|| Some(Utc::now().add(Duration::weeks(1)))), - permissions: LoginPermissions::All, - }) - .send() - .await; - - match response { - Ok(response) => Ok(response.into_inner().token), - Err(err) => Err(format_api_err(&ctx, err)), - } - } - GoogleLoginMethod::OAuth => { - let provider = ctx - .client()? - .get_device_provider() - .provider(OAuthProviderName::Google) - .send() - .await?; - let oauth_client = oauth::GoogleDeviceAuth::new(provider.into_inner())?; - let details = oauth_client.get_device_authorization().await?; - - println!( - "To complete login visit: {} and enter {}", - details.verification_uri().as_str(), - details.user_code().secret() - ); - - let token_response = oauth_client.login(&details).await; - - let token = match token_response { - Ok(token) => Ok(token.access_token().to_owned()), - Err(err) => Err(anyhow::anyhow!("Authentication failed: {}", err)), - }?; + let provider = ctx + .client()? + .get_device_provider() + .provider(OAuthProviderName::Google) + .send() + .await?; + + let oauth_client = oauth::GoogleDeviceAuth::new(provider.into_inner())?; + let details = oauth_client.get_device_authorization().await?; + + println!( + "To complete login visit: {} and enter {}", + details.verification_uri().as_str(), + details.user_code().secret() + ); + + let token_response = oauth_client.login(&details).await; + + let token = match token_response { + Ok(token) => Ok(token.access_token().to_owned()), + Err(err) => Err(anyhow::anyhow!("Authentication failed: {}", err)), + }?; - Ok(token.secret().to_string()) - } - } + Ok(token.secret().to_string()) } } diff --git a/rfd-cli/src/auth/oauth.rs b/rfd-cli/src/auth/oauth.rs index af8346bb..e2b8af8a 100644 --- a/rfd-cli/src/auth/oauth.rs +++ b/rfd-cli/src/auth/oauth.rs @@ -76,6 +76,8 @@ impl GoogleDeviceAuth { req = req.add_scope(Scope::new(scope.to_string())); } - req.request_async(async_http_client).await + let res = req.request_async(async_http_client).await; + + res } } diff --git a/rfd-cli/src/generated/cli.rs b/rfd-cli/src/generated/cli.rs index 0fb58757..f7b65bbc 100644 --- a/rfd-cli/src/generated/cli.rs +++ b/rfd-cli/src/generated/cli.rs @@ -22,10 +22,23 @@ impl Cli { CliCommand::GetApiUserToken => Self::cli_get_api_user_token(), CliCommand::DeleteApiUserToken => Self::cli_delete_api_user_token(), CliCommand::GithubWebhook => Self::cli_github_webhook(), - CliCommand::AccessTokenLogin => Self::cli_access_token_login(), - CliCommand::JwtLogin => Self::cli_jwt_login(), + CliCommand::AuthzCodeRedirect => Self::cli_authz_code_redirect(), + CliCommand::AuthzCodeCallback => Self::cli_authz_code_callback(), + CliCommand::AuthzCodeExchange => Self::cli_authz_code_exchange(), CliCommand::GetDeviceProvider => Self::cli_get_device_provider(), CliCommand::ExchangeDeviceToken => Self::cli_exchange_device_token(), + CliCommand::ListOauthClients => Self::cli_list_oauth_clients(), + CliCommand::CreateOauthClient => Self::cli_create_oauth_client(), + CliCommand::GetOauthClient => Self::cli_get_oauth_client(), + CliCommand::CreateOauthClientRedirectUri => { + Self::cli_create_oauth_client_redirect_uri() + } + CliCommand::DeleteOauthClientRedirectUri => { + Self::cli_delete_oauth_client_redirect_uri() + } + CliCommand::CreateOauthClientSecret => Self::cli_create_oauth_client_secret(), + CliCommand::DeleteOauthClientSecret => Self::cli_delete_oauth_client_secret(), + CliCommand::GetRfds => Self::cli_get_rfds(), CliCommand::GetRfd => Self::cli_get_rfd(), CliCommand::GetSelf => Self::cli_get_self(), } @@ -183,53 +196,59 @@ impl Cli { ) } - pub fn cli_access_token_login() -> clap::Command { + pub fn cli_authz_code_redirect() -> clap::Command { clap::Command::new("") .arg( - clap::Arg::new("expiration") - .long("expiration") - .value_parser(clap::value_parser!(chrono::DateTime)) - .required(false), + clap::Arg::new("client-id") + .long("client-id") + .value_parser(clap::value_parser!(uuid::Uuid)) + .required(true), ) .arg( clap::Arg::new("provider") .long("provider") .value_parser(clap::builder::TypedValueParser::map( clap::builder::PossibleValuesParser::new([ - types::AccessTokenProviderName::Github.to_string(), + types::OAuthProviderName::GitHub.to_string(), + types::OAuthProviderName::Google.to_string(), ]), - |s| types::AccessTokenProviderName::try_from(s).unwrap(), + |s| types::OAuthProviderName::try_from(s).unwrap(), )) .required(true), ) .arg( - clap::Arg::new("token") - .long("token") + clap::Arg::new("redirect-uri") + .long("redirect-uri") .value_parser(clap::value_parser!(String)) - .required_unless_present("json-body"), + .required(true), ) .arg( - clap::Arg::new("json-body") - .long("json-body") - .value_name("JSON-FILE") - .required(true) - .value_parser(clap::value_parser!(std::path::PathBuf)) - .help("Path to a file that contains the full json body."), + clap::Arg::new("response-type") + .long("response-type") + .value_parser(clap::value_parser!(String)) + .required(true), ) .arg( - clap::Arg::new("json-body-template") - .long("json-body-template") - .action(clap::ArgAction::SetTrue) - .help("XXX"), + clap::Arg::new("state") + .long("state") + .value_parser(clap::value_parser!(String)) + .required(true), ) + .about("Generate the remote provider login url and redirect the user") } - pub fn cli_jwt_login() -> clap::Command { + pub fn cli_authz_code_callback() -> clap::Command { clap::Command::new("") .arg( - clap::Arg::new("expiration") - .long("expiration") - .value_parser(clap::value_parser!(chrono::DateTime)) + clap::Arg::new("code") + .long("code") + .value_parser(clap::value_parser!(String)) + .required(false), + ) + .arg( + clap::Arg::new("error") + .long("error") + .value_parser(clap::value_parser!(String)) .required(false), ) .arg( @@ -237,15 +256,69 @@ impl Cli { .long("provider") .value_parser(clap::builder::TypedValueParser::map( clap::builder::PossibleValuesParser::new([ - types::JwtProviderName::Google.to_string() + types::OAuthProviderName::GitHub.to_string(), + types::OAuthProviderName::Google.to_string(), ]), - |s| types::JwtProviderName::try_from(s).unwrap(), + |s| types::OAuthProviderName::try_from(s).unwrap(), )) .required(true), ) .arg( - clap::Arg::new("token") - .long("token") + clap::Arg::new("state") + .long("state") + .value_parser(clap::value_parser!(String)) + .required(false), + ) + .about("Handle return calls from a remote OAuth provider") + } + + pub fn cli_authz_code_exchange() -> clap::Command { + clap::Command::new("") + .arg( + clap::Arg::new("client-id") + .long("client-id") + .value_parser(clap::value_parser!(uuid::Uuid)) + .required_unless_present("json-body"), + ) + .arg( + clap::Arg::new("client-secret") + .long("client-secret") + .value_parser(clap::value_parser!(String)) + .required_unless_present("json-body"), + ) + .arg( + clap::Arg::new("code") + .long("code") + .value_parser(clap::value_parser!(String)) + .required_unless_present("json-body"), + ) + .arg( + clap::Arg::new("grant-type") + .long("grant-type") + .value_parser(clap::value_parser!(String)) + .required_unless_present("json-body"), + ) + .arg( + clap::Arg::new("pkce-verifier") + .long("pkce-verifier") + .value_parser(clap::value_parser!(String)) + .required(false), + ) + .arg( + clap::Arg::new("provider") + .long("provider") + .value_parser(clap::builder::TypedValueParser::map( + clap::builder::PossibleValuesParser::new([ + types::OAuthProviderName::GitHub.to_string(), + types::OAuthProviderName::Google.to_string(), + ]), + |s| types::OAuthProviderName::try_from(s).unwrap(), + )) + .required(true), + ) + .arg( + clap::Arg::new("redirect-uri") + .long("redirect-uri") .value_parser(clap::value_parser!(String)) .required_unless_present("json-body"), ) @@ -253,7 +326,7 @@ impl Cli { clap::Arg::new("json-body") .long("json-body") .value_name("JSON-FILE") - .required(true) + .required(false) .value_parser(clap::value_parser!(std::path::PathBuf)) .help("Path to a file that contains the full json body."), ) @@ -263,6 +336,7 @@ impl Cli { .action(clap::ArgAction::SetTrue) .help("XXX"), ) + .about("Exchange an authorization code for an access token") } pub fn cli_get_device_provider() -> clap::Command { @@ -271,7 +345,8 @@ impl Cli { .long("provider") .value_parser(clap::builder::TypedValueParser::map( clap::builder::PossibleValuesParser::new([ - types::OAuthProviderName::Google.to_string() + types::OAuthProviderName::GitHub.to_string(), + types::OAuthProviderName::Google.to_string(), ]), |s| types::OAuthProviderName::try_from(s).unwrap(), )) @@ -304,6 +379,7 @@ impl Cli { .long("provider") .value_parser(clap::builder::TypedValueParser::map( clap::builder::PossibleValuesParser::new([ + types::OAuthProviderName::GitHub.to_string(), types::OAuthProviderName::Google.to_string(), ]), |s| types::OAuthProviderName::try_from(s).unwrap(), @@ -326,13 +402,114 @@ impl Cli { ) } + pub fn cli_list_oauth_clients() -> clap::Command { + clap::Command::new("").about("List OAuth clients") + } + + pub fn cli_create_oauth_client() -> clap::Command { + clap::Command::new("").about("Create a new OAuth Client") + } + + pub fn cli_get_oauth_client() -> clap::Command { + clap::Command::new("") + .arg( + clap::Arg::new("client-id") + .long("client-id") + .value_parser(clap::value_parser!(uuid::Uuid)) + .required(true), + ) + .about("Get an new OAuth Client") + } + + pub fn cli_create_oauth_client_redirect_uri() -> clap::Command { + clap::Command::new("") + .arg( + clap::Arg::new("client-id") + .long("client-id") + .value_parser(clap::value_parser!(uuid::Uuid)) + .required(true), + ) + .arg( + clap::Arg::new("redirect-uri") + .long("redirect-uri") + .value_parser(clap::value_parser!(String)) + .required_unless_present("json-body"), + ) + .arg( + clap::Arg::new("json-body") + .long("json-body") + .value_name("JSON-FILE") + .required(false) + .value_parser(clap::value_parser!(std::path::PathBuf)) + .help("Path to a file that contains the full json body."), + ) + .arg( + clap::Arg::new("json-body-template") + .long("json-body-template") + .action(clap::ArgAction::SetTrue) + .help("XXX"), + ) + .about("Add an OAuth client redirect uri") + } + + pub fn cli_delete_oauth_client_redirect_uri() -> clap::Command { + clap::Command::new("") + .arg( + clap::Arg::new("client-id") + .long("client-id") + .value_parser(clap::value_parser!(uuid::Uuid)) + .required(true), + ) + .arg( + clap::Arg::new("redirect-uri-id") + .long("redirect-uri-id") + .value_parser(clap::value_parser!(uuid::Uuid)) + .required(true), + ) + .about("Delete an OAuth client redirect uri") + } + + pub fn cli_create_oauth_client_secret() -> clap::Command { + clap::Command::new("") + .arg( + clap::Arg::new("client-id") + .long("client-id") + .value_parser(clap::value_parser!(uuid::Uuid)) + .required(true), + ) + .about("Add an OAuth client secret") + } + + pub fn cli_delete_oauth_client_secret() -> clap::Command { + clap::Command::new("") + .arg( + clap::Arg::new("client-id") + .long("client-id") + .value_parser(clap::value_parser!(uuid::Uuid)) + .required(true), + ) + .arg( + clap::Arg::new("secret-id") + .long("secret-id") + .value_parser(clap::value_parser!(uuid::Uuid)) + .required(true), + ) + .about("Delete an OAuth client secret") + } + + pub fn cli_get_rfds() -> clap::Command { + clap::Command::new("").about("List all available RFDs") + } + pub fn cli_get_rfd() -> clap::Command { - clap::Command::new("").arg( - clap::Arg::new("number") - .long("number") - .value_parser(clap::value_parser!(String)) - .required(true), - ) + clap::Command::new("") + .arg( + clap::Arg::new("number") + .long("number") + .value_parser(clap::value_parser!(String)) + .required(true), + ) + .about("Get the latest representation of an RFD") } pub fn cli_get_self() -> clap::Command { @@ -371,11 +548,14 @@ impl Cli { CliCommand::GithubWebhook => { self.execute_github_webhook(matches).await; } - CliCommand::AccessTokenLogin => { - self.execute_access_token_login(matches).await; + CliCommand::AuthzCodeRedirect => { + self.execute_authz_code_redirect(matches).await; + } + CliCommand::AuthzCodeCallback => { + self.execute_authz_code_callback(matches).await; } - CliCommand::JwtLogin => { - self.execute_jwt_login(matches).await; + CliCommand::AuthzCodeExchange => { + self.execute_authz_code_exchange(matches).await; } CliCommand::GetDeviceProvider => { self.execute_get_device_provider(matches).await; @@ -383,6 +563,30 @@ impl Cli { CliCommand::ExchangeDeviceToken => { self.execute_exchange_device_token(matches).await; } + CliCommand::ListOauthClients => { + self.execute_list_oauth_clients(matches).await; + } + CliCommand::CreateOauthClient => { + self.execute_create_oauth_client(matches).await; + } + CliCommand::GetOauthClient => { + self.execute_get_oauth_client(matches).await; + } + CliCommand::CreateOauthClientRedirectUri => { + self.execute_create_oauth_client_redirect_uri(matches).await; + } + CliCommand::DeleteOauthClientRedirectUri => { + self.execute_delete_oauth_client_redirect_uri(matches).await; + } + CliCommand::CreateOauthClientSecret => { + self.execute_create_oauth_client_secret(matches).await; + } + CliCommand::DeleteOauthClientSecret => { + self.execute_delete_oauth_client_secret(matches).await; + } + CliCommand::GetRfds => { + self.execute_get_rfds(matches).await; + } CliCommand::GetRfd => { self.execute_get_rfd(matches).await; } @@ -493,8 +697,7 @@ impl Cli { if let Some(value) = matches.get_one::("json-body") { let body_txt = std::fs::read_to_string(value).unwrap(); - let body_value = - serde_json::from_str::(&body_txt).unwrap(); + let body_value = serde_json::from_str::(&body_txt).unwrap(); request = request.body(body_value); } @@ -586,35 +789,67 @@ impl Cli { } } - pub async fn execute_access_token_login(&self, matches: &clap::ArgMatches) { - let mut request = self.client.access_token_login(); - if let Some(value) = matches.get_one::>("expiration") - { - request = request.body_map(|body| body.expiration(value.clone())) + pub async fn execute_authz_code_redirect(&self, matches: &clap::ArgMatches) { + let mut request = self.client.authz_code_redirect(); + if let Some(value) = matches.get_one::("client-id") { + request = request.client_id(value.clone()); } - if let Some(value) = matches.get_one::("provider") { + if let Some(value) = matches.get_one::("provider") { request = request.provider(value.clone()); } - if let Some(value) = matches.get_one::("token") { - request = request.body_map(|body| body.token(value.clone())) + if let Some(value) = matches.get_one::("redirect-uri") { + request = request.redirect_uri(value.clone()); } - if let Some(value) = matches.get_one::("json-body") { - let body_txt = std::fs::read_to_string(value).unwrap(); - let body_value = - serde_json::from_str::(&body_txt).unwrap(); - request = request.body(body_value); + if let Some(value) = matches.get_one::("response-type") { + request = request.response_type(value.clone()); + } + + if let Some(value) = matches.get_one::("state") { + request = request.state(value.clone()); } self.over - .execute_access_token_login(matches, &mut request) + .execute_authz_code_redirect(matches, &mut request) .unwrap(); let result = request.send().await; match result { Ok(r) => { - println!("success\n{:#?}", r) + todo!() + } + Err(r) => { + todo!() + } + } + } + + pub async fn execute_authz_code_callback(&self, matches: &clap::ArgMatches) { + let mut request = self.client.authz_code_callback(); + if let Some(value) = matches.get_one::("code") { + request = request.code(value.clone()); + } + + if let Some(value) = matches.get_one::("error") { + request = request.error(value.clone()); + } + + if let Some(value) = matches.get_one::("provider") { + request = request.provider(value.clone()); + } + + if let Some(value) = matches.get_one::("state") { + request = request.state(value.clone()); + } + + self.over + .execute_authz_code_callback(matches, &mut request) + .unwrap(); + let result = request.send().await; + match result { + Ok(r) => { + todo!() } Err(r) => { println!("error\n{:#?}", r) @@ -622,28 +857,46 @@ impl Cli { } } - pub async fn execute_jwt_login(&self, matches: &clap::ArgMatches) { - let mut request = self.client.jwt_login(); - if let Some(value) = matches.get_one::>("expiration") - { - request = request.body_map(|body| body.expiration(value.clone())) + pub async fn execute_authz_code_exchange(&self, matches: &clap::ArgMatches) { + let mut request = self.client.authz_code_exchange(); + if let Some(value) = matches.get_one::("client-id") { + request = request.body_map(|body| body.client_id(value.clone())) } - if let Some(value) = matches.get_one::("provider") { + if let Some(value) = matches.get_one::("client-secret") { + request = request.body_map(|body| body.client_secret(value.clone())) + } + + if let Some(value) = matches.get_one::("code") { + request = request.body_map(|body| body.code(value.clone())) + } + + if let Some(value) = matches.get_one::("grant-type") { + request = request.body_map(|body| body.grant_type(value.clone())) + } + + if let Some(value) = matches.get_one::("pkce-verifier") { + request = request.body_map(|body| body.pkce_verifier(value.clone())) + } + + if let Some(value) = matches.get_one::("provider") { request = request.provider(value.clone()); } - if let Some(value) = matches.get_one::("token") { - request = request.body_map(|body| body.token(value.clone())) + if let Some(value) = matches.get_one::("redirect-uri") { + request = request.body_map(|body| body.redirect_uri(value.clone())) } if let Some(value) = matches.get_one::("json-body") { let body_txt = std::fs::read_to_string(value).unwrap(); - let body_value = serde_json::from_str::(&body_txt).unwrap(); + let body_value = + serde_json::from_str::(&body_txt).unwrap(); request = request.body(body_value); } - self.over.execute_jwt_login(matches, &mut request).unwrap(); + self.over + .execute_authz_code_exchange(matches, &mut request) + .unwrap(); let result = request.send().await; match result { Ok(r) => { @@ -715,6 +968,171 @@ impl Cli { } } + pub async fn execute_list_oauth_clients(&self, matches: &clap::ArgMatches) { + let mut request = self.client.list_oauth_clients(); + self.over + .execute_list_oauth_clients(matches, &mut request) + .unwrap(); + let result = request.send().await; + match result { + Ok(r) => { + println!("success\n{:#?}", r) + } + Err(r) => { + println!("error\n{:#?}", r) + } + } + } + + pub async fn execute_create_oauth_client(&self, matches: &clap::ArgMatches) { + let mut request = self.client.create_oauth_client(); + self.over + .execute_create_oauth_client(matches, &mut request) + .unwrap(); + let result = request.send().await; + match result { + Ok(r) => { + println!("success\n{:#?}", r) + } + Err(r) => { + println!("error\n{:#?}", r) + } + } + } + + pub async fn execute_get_oauth_client(&self, matches: &clap::ArgMatches) { + let mut request = self.client.get_oauth_client(); + if let Some(value) = matches.get_one::("client-id") { + request = request.client_id(value.clone()); + } + + self.over + .execute_get_oauth_client(matches, &mut request) + .unwrap(); + let result = request.send().await; + match result { + Ok(r) => { + println!("success\n{:#?}", r) + } + Err(r) => { + println!("error\n{:#?}", r) + } + } + } + + pub async fn execute_create_oauth_client_redirect_uri(&self, matches: &clap::ArgMatches) { + let mut request = self.client.create_oauth_client_redirect_uri(); + if let Some(value) = matches.get_one::("client-id") { + request = request.client_id(value.clone()); + } + + if let Some(value) = matches.get_one::("redirect-uri") { + request = request.body_map(|body| body.redirect_uri(value.clone())) + } + + if let Some(value) = matches.get_one::("json-body") { + let body_txt = std::fs::read_to_string(value).unwrap(); + let body_value = + serde_json::from_str::(&body_txt).unwrap(); + request = request.body(body_value); + } + + self.over + .execute_create_oauth_client_redirect_uri(matches, &mut request) + .unwrap(); + let result = request.send().await; + match result { + Ok(r) => { + println!("success\n{:#?}", r) + } + Err(r) => { + println!("error\n{:#?}", r) + } + } + } + + pub async fn execute_delete_oauth_client_redirect_uri(&self, matches: &clap::ArgMatches) { + let mut request = self.client.delete_oauth_client_redirect_uri(); + if let Some(value) = matches.get_one::("client-id") { + request = request.client_id(value.clone()); + } + + if let Some(value) = matches.get_one::("redirect-uri-id") { + request = request.redirect_uri_id(value.clone()); + } + + self.over + .execute_delete_oauth_client_redirect_uri(matches, &mut request) + .unwrap(); + let result = request.send().await; + match result { + Ok(r) => { + println!("success\n{:#?}", r) + } + Err(r) => { + println!("error\n{:#?}", r) + } + } + } + + pub async fn execute_create_oauth_client_secret(&self, matches: &clap::ArgMatches) { + let mut request = self.client.create_oauth_client_secret(); + if let Some(value) = matches.get_one::("client-id") { + request = request.client_id(value.clone()); + } + + self.over + .execute_create_oauth_client_secret(matches, &mut request) + .unwrap(); + let result = request.send().await; + match result { + Ok(r) => { + println!("success\n{:#?}", r) + } + Err(r) => { + println!("error\n{:#?}", r) + } + } + } + + pub async fn execute_delete_oauth_client_secret(&self, matches: &clap::ArgMatches) { + let mut request = self.client.delete_oauth_client_secret(); + if let Some(value) = matches.get_one::("client-id") { + request = request.client_id(value.clone()); + } + + if let Some(value) = matches.get_one::("secret-id") { + request = request.secret_id(value.clone()); + } + + self.over + .execute_delete_oauth_client_secret(matches, &mut request) + .unwrap(); + let result = request.send().await; + match result { + Ok(r) => { + println!("success\n{:#?}", r) + } + Err(r) => { + println!("error\n{:#?}", r) + } + } + } + + pub async fn execute_get_rfds(&self, matches: &clap::ArgMatches) { + let mut request = self.client.get_rfds(); + self.over.execute_get_rfds(matches, &mut request).unwrap(); + let result = request.send().await; + match result { + Ok(r) => { + println!("success\n{:#?}", r) + } + Err(r) => { + println!("error\n{:#?}", r) + } + } + } + pub async fn execute_get_rfd(&self, matches: &clap::ArgMatches) { let mut request = self.client.get_rfd(); if let Some(value) = matches.get_one::("number") { @@ -813,18 +1231,26 @@ pub trait CliOverride { Ok(()) } - fn execute_access_token_login( + fn execute_authz_code_redirect( + &self, + matches: &clap::ArgMatches, + request: &mut builder::AuthzCodeRedirect, + ) -> Result<(), String> { + Ok(()) + } + + fn execute_authz_code_callback( &self, matches: &clap::ArgMatches, - request: &mut builder::AccessTokenLogin, + request: &mut builder::AuthzCodeCallback, ) -> Result<(), String> { Ok(()) } - fn execute_jwt_login( + fn execute_authz_code_exchange( &self, matches: &clap::ArgMatches, - request: &mut builder::JwtLogin, + request: &mut builder::AuthzCodeExchange, ) -> Result<(), String> { Ok(()) } @@ -845,6 +1271,70 @@ pub trait CliOverride { Ok(()) } + fn execute_list_oauth_clients( + &self, + matches: &clap::ArgMatches, + request: &mut builder::ListOauthClients, + ) -> Result<(), String> { + Ok(()) + } + + fn execute_create_oauth_client( + &self, + matches: &clap::ArgMatches, + request: &mut builder::CreateOauthClient, + ) -> Result<(), String> { + Ok(()) + } + + fn execute_get_oauth_client( + &self, + matches: &clap::ArgMatches, + request: &mut builder::GetOauthClient, + ) -> Result<(), String> { + Ok(()) + } + + fn execute_create_oauth_client_redirect_uri( + &self, + matches: &clap::ArgMatches, + request: &mut builder::CreateOauthClientRedirectUri, + ) -> Result<(), String> { + Ok(()) + } + + fn execute_delete_oauth_client_redirect_uri( + &self, + matches: &clap::ArgMatches, + request: &mut builder::DeleteOauthClientRedirectUri, + ) -> Result<(), String> { + Ok(()) + } + + fn execute_create_oauth_client_secret( + &self, + matches: &clap::ArgMatches, + request: &mut builder::CreateOauthClientSecret, + ) -> Result<(), String> { + Ok(()) + } + + fn execute_delete_oauth_client_secret( + &self, + matches: &clap::ArgMatches, + request: &mut builder::DeleteOauthClientSecret, + ) -> Result<(), String> { + Ok(()) + } + + fn execute_get_rfds( + &self, + matches: &clap::ArgMatches, + request: &mut builder::GetRfds, + ) -> Result<(), String> { + Ok(()) + } + fn execute_get_rfd( &self, matches: &clap::ArgMatches, @@ -874,10 +1364,19 @@ pub enum CliCommand { GetApiUserToken, DeleteApiUserToken, GithubWebhook, - AccessTokenLogin, - JwtLogin, + AuthzCodeRedirect, + AuthzCodeCallback, + AuthzCodeExchange, GetDeviceProvider, ExchangeDeviceToken, + ListOauthClients, + CreateOauthClient, + GetOauthClient, + CreateOauthClientRedirectUri, + DeleteOauthClientRedirectUri, + CreateOauthClientSecret, + DeleteOauthClientSecret, + GetRfds, GetRfd, GetSelf, } @@ -893,10 +1392,19 @@ impl CliCommand { CliCommand::GetApiUserToken, CliCommand::DeleteApiUserToken, CliCommand::GithubWebhook, - CliCommand::AccessTokenLogin, - CliCommand::JwtLogin, + CliCommand::AuthzCodeRedirect, + CliCommand::AuthzCodeCallback, + CliCommand::AuthzCodeExchange, CliCommand::GetDeviceProvider, CliCommand::ExchangeDeviceToken, + CliCommand::ListOauthClients, + CliCommand::CreateOauthClient, + CliCommand::GetOauthClient, + CliCommand::CreateOauthClientRedirectUri, + CliCommand::DeleteOauthClientRedirectUri, + CliCommand::CreateOauthClientSecret, + CliCommand::DeleteOauthClientSecret, + CliCommand::GetRfds, CliCommand::GetRfd, CliCommand::GetSelf, ] diff --git a/rfd-cli/src/main.rs b/rfd-cli/src/main.rs index 77749ba4..1bd8a25e 100644 --- a/rfd-cli/src/main.rs +++ b/rfd-cli/src/main.rs @@ -41,12 +41,15 @@ impl Context { pub fn client(&mut self) -> Result<&Client> { if self.client.is_none() { - let mut auth_header = - HeaderValue::from_str(&format!("Bearer {}", self.config.token()?))?; - auth_header.set_sensitive(true); let mut default_headers = HeaderMap::new(); - default_headers.insert(AUTHORIZATION, auth_header); + + if let Ok(token) = self.config.token() { + let mut auth_header = + HeaderValue::from_str(&format!("Bearer {}", self.config.token()?))?; + auth_header.set_sensitive(true); + default_headers.insert(AUTHORIZATION, auth_header); + } let http_client = reqwest::Client::builder() .default_headers(default_headers) @@ -94,18 +97,30 @@ fn cmd_path<'a>(cmd: &CliCommand) -> Option<&'a str> { CliCommand::DeleteApiUserToken => Some("user token delete"), CliCommand::GetApiUser => Some("user get"), CliCommand::GetApiUserToken => Some("user token get"), - CliCommand::GetRfd => Some("rfd"), + CliCommand::GetRfd => Some("rfd get"), + CliCommand::GetRfds => Some("rfd list"), CliCommand::GetSelf => Some("self"), CliCommand::ListApiUserTokens => Some("user token list"), CliCommand::UpdateApiUser => Some("user update"), + // OAuth client commands + CliCommand::ListOauthClients => None, + CliCommand::CreateOauthClient => None, + CliCommand::GetOauthClient => None, + CliCommand::CreateOauthClientRedirectUri => None, + CliCommand::DeleteOauthClientRedirectUri => None, + CliCommand::CreateOauthClientSecret => None, + CliCommand::DeleteOauthClientSecret => None, + // Authentication is handled separately - CliCommand::AccessTokenLogin => None, - CliCommand::JwtLogin => None, CliCommand::ExchangeDeviceToken => None, CliCommand::GetDeviceProvider => None, - CliCommand::GithubWebhook => unimplemented!(), + // Unsupported commands + CliCommand::AuthzCodeRedirect => None, + CliCommand::AuthzCodeCallback => None, + CliCommand::AuthzCodeExchange => None, + CliCommand::GithubWebhook => None, } } diff --git a/rfd-model/src/storage/mod.rs b/rfd-model/src/storage/mod.rs index e30e81bf..6dbec2e8 100644 --- a/rfd-model/src/storage/mod.rs +++ b/rfd-model/src/storage/mod.rs @@ -131,6 +131,13 @@ impl RfdRevisionFilter { } } +#[derive(Debug, Default)] +pub enum RfdRevisionGroupBy { + Id, + #[default] + None, +} + #[cfg_attr(feature = "mock", automock)] #[async_trait] pub trait RfdRevisionStore { @@ -140,6 +147,11 @@ pub trait RfdRevisionStore { filter: RfdRevisionFilter, pagination: &ListPagination, ) -> Result, StoreError>; + async fn list_unique_rfd( + &self, + filter: RfdRevisionFilter, + pagination: &ListPagination, + ) -> Result, StoreError>; async fn upsert(&self, new_revision: NewRfdRevision) -> Result; async fn delete(&self, id: &Uuid) -> Result, StoreError>; } diff --git a/rfd-model/src/storage/postgres.rs b/rfd-model/src/storage/postgres.rs index 606c66a0..02744c1d 100644 --- a/rfd-model/src/storage/postgres.rs +++ b/rfd-model/src/storage/postgres.rs @@ -97,6 +97,8 @@ impl RfdStore for PostgresStore { ) -> Result, StoreError> { let mut query = rfd::dsl::rfd.into_boxed(); + tracing::trace!(?filter, "Lookup RFDs"); + let RfdFilter { id, rfd_number, @@ -181,6 +183,8 @@ impl RfdRevisionStore for PostgresStore { ) -> Result, StoreError> { let mut query = rfd_revision::dsl::rfd_revision.into_boxed(); + tracing::trace!(?filter, "Lookup RFD revisions"); + let RfdRevisionFilter { id, rfd, @@ -217,6 +221,52 @@ impl RfdRevisionStore for PostgresStore { .collect()) } + // TODO: Refactor into a group by arg in list. Diesel types here are a pain + async fn list_unique_rfd( + &self, + filter: RfdRevisionFilter, + pagination: &ListPagination, + ) -> Result, StoreError> { + let mut query = rfd_revision::dsl::rfd_revision.distinct_on(rfd_revision::rfd_id).into_boxed(); + + tracing::trace!(?filter, "Lookup unique RFD revisions"); + + let RfdRevisionFilter { + id, + rfd, + sha, + deleted, + } = filter; + + if let Some(id) = id { + query = query.filter(rfd_revision::id.eq_any(id)); + } + + if let Some(rfd) = rfd { + query = query.filter(rfd_revision::rfd_id.eq_any(rfd)); + } + + if let Some(sha) = sha { + query = query.filter(rfd_revision::sha.eq_any(sha)); + } + + if !deleted { + query = query.filter(rfd_revision::deleted_at.is_null()); + } + + let results = query + .offset(pagination.offset) + .limit(pagination.limit) + .order(rfd_revision::rfd_id.asc()) + .get_results_async::(&self.conn) + .await?; + + Ok(results + .into_iter() + .map(|revision| revision.into()) + .collect()) + } + async fn upsert(&self, new_revision: NewRfdRevision) -> Result { let rfd: RfdRevisionModel = insert_into(rfd_revision::dsl::rfd_revision) .values(( @@ -283,6 +333,8 @@ impl RfdPdfStore for PostgresStore { ) -> Result, StoreError> { let mut query = rfd_pdf::dsl::rfd_pdf.into_boxed(); + tracing::trace!(?filter, "Lookup RFD pdfs"); + let RfdPdfFilter { id, rfd_revision, diff --git a/rfd-processor/src/github/mod.rs b/rfd-processor/src/github/mod.rs index eb7fff4f..a035211f 100644 --- a/rfd-processor/src/github/mod.rs +++ b/rfd-processor/src/github/mod.rs @@ -193,7 +193,7 @@ impl GitHubRfdRepo { let rfd_number = RfdNumber::from(number); - // Only interesting in exactly the RFD file that matches the branch name + // Only interested in exactly the RFD file that matches the branch name let response = client.repos().get_content_file(&self.owner, &self.repo, &format!("rfd/{}/README.adoc", rfd_number.as_number_string()), &branch.commit.sha).await; // 404s are returned as errors, but that should not stop processing. This only diff --git a/rfd-sdk/src/generated/sdk.rs b/rfd-sdk/src/generated/sdk.rs index 9649e1ce..cc1cf728 100644 --- a/rfd-sdk/src/generated/sdk.rs +++ b/rfd-sdk/src/generated/sdk.rs @@ -30,85 +30,56 @@ pub mod types { } #[derive(Clone, Debug, Deserialize, Serialize, schemars :: JsonSchema)] - pub struct AccessTokenProviderLogin { - #[serde(default, skip_serializing_if = "Option::is_none")] - pub expiration: Option>, - pub permissions: LoginPermissions, - pub token: String, + pub struct AddOAuthClientRedirectBody { + pub redirect_uri: String, } - impl From<&AccessTokenProviderLogin> for AccessTokenProviderLogin { - fn from(value: &AccessTokenProviderLogin) -> Self { + impl From<&AddOAuthClientRedirectBody> for AddOAuthClientRedirectBody { + fn from(value: &AddOAuthClientRedirectBody) -> Self { value.clone() } } - impl AccessTokenProviderLogin { - pub fn builder() -> builder::AccessTokenProviderLogin { - builder::AccessTokenProviderLogin::default() + impl AddOAuthClientRedirectBody { + pub fn builder() -> builder::AddOAuthClientRedirectBody { + builder::AddOAuthClientRedirectBody::default() } } - #[derive( - Clone, - Copy, - Debug, - Deserialize, - Eq, - Hash, - Ord, - PartialEq, - PartialOrd, - Serialize, - schemars :: JsonSchema, - )] - pub enum AccessTokenProviderName { - #[serde(rename = "github")] - Github, + #[derive(Clone, Debug, Deserialize, Serialize, schemars :: JsonSchema)] + pub struct ApiKeyCreateParams { + pub expires_at: chrono::DateTime, + pub permissions: PermissionsForApiPermission, } - impl From<&AccessTokenProviderName> for AccessTokenProviderName { - fn from(value: &AccessTokenProviderName) -> Self { + impl From<&ApiKeyCreateParams> for ApiKeyCreateParams { + fn from(value: &ApiKeyCreateParams) -> Self { value.clone() } } - impl ToString for AccessTokenProviderName { - fn to_string(&self) -> String { - match *self { - Self::Github => "github".to_string(), - } - } - } - - impl std::str::FromStr for AccessTokenProviderName { - type Err = &'static str; - fn from_str(value: &str) -> Result { - match value { - "github" => Ok(Self::Github), - _ => Err("invalid value"), - } + impl ApiKeyCreateParams { + pub fn builder() -> builder::ApiKeyCreateParams { + builder::ApiKeyCreateParams::default() } } - impl std::convert::TryFrom<&str> for AccessTokenProviderName { - type Error = &'static str; - fn try_from(value: &str) -> Result { - value.parse() - } + #[derive(Clone, Debug, Deserialize, Serialize, schemars :: JsonSchema)] + pub struct ApiKeyResponse { + pub created_at: chrono::DateTime, + pub id: uuid::Uuid, + pub permissions: PermissionsForApiPermission, } - impl std::convert::TryFrom<&String> for AccessTokenProviderName { - type Error = &'static str; - fn try_from(value: &String) -> Result { - value.parse() + impl From<&ApiKeyResponse> for ApiKeyResponse { + fn from(value: &ApiKeyResponse) -> Self { + value.clone() } } - impl std::convert::TryFrom for AccessTokenProviderName { - type Error = &'static str; - fn try_from(value: String) -> Result { - value.parse() + impl ApiKeyResponse { + pub fn builder() -> builder::ApiKeyResponse { + builder::ApiKeyResponse::default() } } @@ -126,12 +97,27 @@ pub mod types { UpdateApiUserAll, GetAllRfds, GetAssignedRfds, + GetAllDiscussions, + GetAssignedDiscussions, + CreateOAuthClient, + GetAssignedOAuthClients, + UpdateAssignedOAuthClients, + DeleteAssignedOAuthClients, CreateApiUserToken(uuid::Uuid), GetApiUser(uuid::Uuid), GetApiUserToken(uuid::Uuid), DeleteApiUserToken(uuid::Uuid), UpdateApiUser(uuid::Uuid), - GetRfd(Vec), + GetRfd(i32), + GetRfds(Vec), + GetDiscussion(i32), + GetDiscussions(Vec), + GetOAuthClient(uuid::Uuid), + GetOAuthClients(Vec), + UpdateOAuthClient(uuid::Uuid), + UpdateOAuthClients(Vec), + DeleteOAuthClient(uuid::Uuid), + DeleteOAuthClients(Vec), } impl From<&ApiPermission> for ApiPermission { @@ -140,12 +126,6 @@ pub mod types { } } - impl From> for ApiPermission { - fn from(value: Vec) -> Self { - Self::GetRfd(value) - } - } - #[derive(Clone, Debug, Deserialize, Serialize, schemars :: JsonSchema)] pub struct ApiUserForApiPermission { pub created_at: chrono::DateTime, @@ -168,43 +148,6 @@ pub mod types { } } - #[derive(Clone, Debug, Deserialize, Serialize, schemars :: JsonSchema)] - pub struct ApiUserTokenCreateParams { - pub expires_at: chrono::DateTime, - pub permissions: PermissionsForApiPermission, - } - - impl From<&ApiUserTokenCreateParams> for ApiUserTokenCreateParams { - fn from(value: &ApiUserTokenCreateParams) -> Self { - value.clone() - } - } - - impl ApiUserTokenCreateParams { - pub fn builder() -> builder::ApiUserTokenCreateParams { - builder::ApiUserTokenCreateParams::default() - } - } - - #[derive(Clone, Debug, Deserialize, Serialize, schemars :: JsonSchema)] - pub struct ApiUserTokenResponse { - pub created_at: chrono::DateTime, - pub id: uuid::Uuid, - pub permissions: PermissionsForApiPermission, - } - - impl From<&ApiUserTokenResponse> for ApiUserTokenResponse { - fn from(value: &ApiUserTokenResponse) -> Self { - value.clone() - } - } - - impl ApiUserTokenResponse { - pub fn builder() -> builder::ApiUserTokenResponse { - builder::ApiUserTokenResponse::default() - } - } - #[derive(Clone, Debug, Deserialize, Serialize, schemars :: JsonSchema)] pub struct ApiUserUpdateParams { pub permissions: PermissionsForApiPermission, @@ -414,140 +357,160 @@ pub mod types { } #[derive(Clone, Debug, Deserialize, Serialize, schemars :: JsonSchema)] - pub struct InitialApiUserTokenResponse { + pub struct InitialApiKeyResponse { pub created_at: chrono::DateTime, pub id: uuid::Uuid, + pub key: String, pub permissions: PermissionsForApiPermission, - pub token: String, } - impl From<&InitialApiUserTokenResponse> for InitialApiUserTokenResponse { - fn from(value: &InitialApiUserTokenResponse) -> Self { + impl From<&InitialApiKeyResponse> for InitialApiKeyResponse { + fn from(value: &InitialApiKeyResponse) -> Self { value.clone() } } - impl InitialApiUserTokenResponse { - pub fn builder() -> builder::InitialApiUserTokenResponse { - builder::InitialApiUserTokenResponse::default() + impl InitialApiKeyResponse { + pub fn builder() -> builder::InitialApiKeyResponse { + builder::InitialApiKeyResponse::default() } } #[derive(Clone, Debug, Deserialize, Serialize, schemars :: JsonSchema)] - pub struct JwtProviderLogin { + pub struct ListRfd { + #[serde(default, skip_serializing_if = "Option::is_none")] + pub authors: Option, + pub commit: String, + pub committed_at: chrono::DateTime, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub discussion: Option, + pub id: uuid::Uuid, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub link: Option, + pub rfd_number: i32, + pub sha: String, #[serde(default, skip_serializing_if = "Option::is_none")] - pub expiration: Option>, - pub permissions: LoginPermissions, - pub token: String, + pub state: Option, + pub title: String, } - impl From<&JwtProviderLogin> for JwtProviderLogin { - fn from(value: &JwtProviderLogin) -> Self { + impl From<&ListRfd> for ListRfd { + fn from(value: &ListRfd) -> Self { value.clone() } } - impl JwtProviderLogin { - pub fn builder() -> builder::JwtProviderLogin { - builder::JwtProviderLogin::default() + impl ListRfd { + pub fn builder() -> builder::ListRfd { + builder::ListRfd::default() } } - #[derive( - Clone, - Copy, - Debug, - Deserialize, - Eq, - Hash, - Ord, - PartialEq, - PartialOrd, - Serialize, - schemars :: JsonSchema, - )] - pub enum JwtProviderName { - #[serde(rename = "google")] - Google, + #[derive(Clone, Debug, Deserialize, Serialize, schemars :: JsonSchema)] + pub struct OAuthAuthzCodeExchangeBody { + pub client_id: uuid::Uuid, + pub client_secret: String, + pub code: String, + pub grant_type: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub pkce_verifier: Option, + pub redirect_uri: String, } - impl From<&JwtProviderName> for JwtProviderName { - fn from(value: &JwtProviderName) -> Self { + impl From<&OAuthAuthzCodeExchangeBody> for OAuthAuthzCodeExchangeBody { + fn from(value: &OAuthAuthzCodeExchangeBody) -> Self { value.clone() } } - impl ToString for JwtProviderName { - fn to_string(&self) -> String { - match *self { - Self::Google => "google".to_string(), - } + impl OAuthAuthzCodeExchangeBody { + pub fn builder() -> builder::OAuthAuthzCodeExchangeBody { + builder::OAuthAuthzCodeExchangeBody::default() } } - impl std::str::FromStr for JwtProviderName { - type Err = &'static str; - fn from_str(value: &str) -> Result { - match value { - "google" => Ok(Self::Google), - _ => Err("invalid value"), - } + #[derive(Clone, Debug, Deserialize, Serialize, schemars :: JsonSchema)] + pub struct OAuthAuthzCodeExchangeResponse { + pub access_token: String, + pub expires_in: i64, + pub token_type: String, + } + + impl From<&OAuthAuthzCodeExchangeResponse> for OAuthAuthzCodeExchangeResponse { + fn from(value: &OAuthAuthzCodeExchangeResponse) -> Self { + value.clone() } } - impl std::convert::TryFrom<&str> for JwtProviderName { - type Error = &'static str; - fn try_from(value: &str) -> Result { - value.parse() + impl OAuthAuthzCodeExchangeResponse { + pub fn builder() -> builder::OAuthAuthzCodeExchangeResponse { + builder::OAuthAuthzCodeExchangeResponse::default() } } - impl std::convert::TryFrom<&String> for JwtProviderName { - type Error = &'static str; - fn try_from(value: &String) -> Result { - value.parse() + #[derive(Clone, Debug, Deserialize, Serialize, schemars :: JsonSchema)] + pub struct OAuthClient { + pub created_at: chrono::DateTime, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub deleted_at: Option>, + pub id: uuid::Uuid, + pub redirect_uris: Vec, + pub secrets: Vec, + } + + impl From<&OAuthClient> for OAuthClient { + fn from(value: &OAuthClient) -> Self { + value.clone() } } - impl std::convert::TryFrom for JwtProviderName { - type Error = &'static str; - fn try_from(value: String) -> Result { - value.parse() + impl OAuthClient { + pub fn builder() -> builder::OAuthClient { + builder::OAuthClient::default() } } #[derive(Clone, Debug, Deserialize, Serialize, schemars :: JsonSchema)] - pub enum LoginPermissions { - All, - Specific(Vec), + pub struct OAuthClientRedirectUri { + pub created_at: chrono::DateTime, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub deleted_at: Option>, + pub id: uuid::Uuid, + pub oauth_client_id: uuid::Uuid, + pub redirect_uri: String, } - impl From<&LoginPermissions> for LoginPermissions { - fn from(value: &LoginPermissions) -> Self { + impl From<&OAuthClientRedirectUri> for OAuthClientRedirectUri { + fn from(value: &OAuthClientRedirectUri) -> Self { value.clone() } } - impl From> for LoginPermissions { - fn from(value: Vec) -> Self { - Self::Specific(value) + impl OAuthClientRedirectUri { + pub fn builder() -> builder::OAuthClientRedirectUri { + builder::OAuthClientRedirectUri::default() } } #[derive(Clone, Debug, Deserialize, Serialize, schemars :: JsonSchema)] - pub struct LoginTokenResponse { - pub token: String, + pub struct OAuthClientSecret { + pub created_at: chrono::DateTime, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub deleted_at: Option>, + pub id: uuid::Uuid, + pub oauth_client_id: uuid::Uuid, + pub secret_signature: String, } - impl From<&LoginTokenResponse> for LoginTokenResponse { - fn from(value: &LoginTokenResponse) -> Self { + impl From<&OAuthClientSecret> for OAuthClientSecret { + fn from(value: &OAuthClientSecret) -> Self { value.clone() } } - impl LoginTokenResponse { - pub fn builder() -> builder::LoginTokenResponse { - builder::LoginTokenResponse::default() + impl OAuthClientSecret { + pub fn builder() -> builder::OAuthClientSecret { + builder::OAuthClientSecret::default() } } @@ -587,6 +550,8 @@ pub mod types { schemars :: JsonSchema, )] pub enum OAuthProviderName { + #[serde(rename = "git-hub")] + GitHub, #[serde(rename = "google")] Google, } @@ -600,6 +565,7 @@ pub mod types { impl ToString for OAuthProviderName { fn to_string(&self) -> String { match *self { + Self::GitHub => "git-hub".to_string(), Self::Google => "google".to_string(), } } @@ -609,6 +575,7 @@ pub mod types { type Err = &'static str; fn from_str(value: &str) -> Result { match value { + "git-hub" => Ok(Self::GitHub), "google" => Ok(Self::Google), _ => Err("invalid value"), } @@ -736,36 +703,77 @@ pub mod types { } #[derive(Clone, Debug)] - pub struct AccessTokenProviderLogin { - expiration: Result>, String>, - permissions: Result, - token: Result, + pub struct AddOAuthClientRedirectBody { + redirect_uri: Result, + } + + impl Default for AddOAuthClientRedirectBody { + fn default() -> Self { + Self { + redirect_uri: Err("no value supplied for redirect_uri".to_string()), + } + } + } + + impl AddOAuthClientRedirectBody { + pub fn redirect_uri(mut self, value: T) -> Self + where + T: std::convert::TryInto, + T::Error: std::fmt::Display, + { + self.redirect_uri = value.try_into().map_err(|e| { + format!("error converting supplied value for redirect_uri: {}", e) + }); + self + } + } + + impl std::convert::TryFrom for super::AddOAuthClientRedirectBody { + type Error = String; + fn try_from(value: AddOAuthClientRedirectBody) -> Result { + Ok(Self { + redirect_uri: value.redirect_uri?, + }) + } + } + + impl From for AddOAuthClientRedirectBody { + fn from(value: super::AddOAuthClientRedirectBody) -> Self { + Self { + redirect_uri: Ok(value.redirect_uri), + } + } + } + + #[derive(Clone, Debug)] + pub struct ApiKeyCreateParams { + expires_at: Result, String>, + permissions: Result, } - impl Default for AccessTokenProviderLogin { + impl Default for ApiKeyCreateParams { fn default() -> Self { Self { - expiration: Ok(Default::default()), + expires_at: Err("no value supplied for expires_at".to_string()), permissions: Err("no value supplied for permissions".to_string()), - token: Err("no value supplied for token".to_string()), } } } - impl AccessTokenProviderLogin { - pub fn expiration(mut self, value: T) -> Self + impl ApiKeyCreateParams { + pub fn expires_at(mut self, value: T) -> Self where - T: std::convert::TryInto>>, + T: std::convert::TryInto>, T::Error: std::fmt::Display, { - self.expiration = value + self.expires_at = value .try_into() - .map_err(|e| format!("error converting supplied value for expiration: {}", e)); + .map_err(|e| format!("error converting supplied value for expires_at: {}", e)); self } pub fn permissions(mut self, value: T) -> Self where - T: std::convert::TryInto, + T: std::convert::TryInto, T::Error: std::fmt::Display, { self.permissions = value @@ -773,35 +781,94 @@ pub mod types { .map_err(|e| format!("error converting supplied value for permissions: {}", e)); self } - pub fn token(mut self, value: T) -> Self + } + + impl std::convert::TryFrom for super::ApiKeyCreateParams { + type Error = String; + fn try_from(value: ApiKeyCreateParams) -> Result { + Ok(Self { + expires_at: value.expires_at?, + permissions: value.permissions?, + }) + } + } + + impl From for ApiKeyCreateParams { + fn from(value: super::ApiKeyCreateParams) -> Self { + Self { + expires_at: Ok(value.expires_at), + permissions: Ok(value.permissions), + } + } + } + + #[derive(Clone, Debug)] + pub struct ApiKeyResponse { + created_at: Result, String>, + id: Result, + permissions: Result, + } + + impl Default for ApiKeyResponse { + fn default() -> Self { + Self { + created_at: Err("no value supplied for created_at".to_string()), + id: Err("no value supplied for id".to_string()), + permissions: Err("no value supplied for permissions".to_string()), + } + } + } + + impl ApiKeyResponse { + pub fn created_at(mut self, value: T) -> Self + where + T: std::convert::TryInto>, + T::Error: std::fmt::Display, + { + self.created_at = value + .try_into() + .map_err(|e| format!("error converting supplied value for created_at: {}", e)); + self + } + pub fn id(mut self, value: T) -> Self where - T: std::convert::TryInto, + T: std::convert::TryInto, + T::Error: std::fmt::Display, + { + self.id = value + .try_into() + .map_err(|e| format!("error converting supplied value for id: {}", e)); + self + } + pub fn permissions(mut self, value: T) -> Self + where + T: std::convert::TryInto, T::Error: std::fmt::Display, { - self.token = value + self.permissions = value .try_into() - .map_err(|e| format!("error converting supplied value for token: {}", e)); + .map_err(|e| format!("error converting supplied value for permissions: {}", e)); self } } - impl std::convert::TryFrom for super::AccessTokenProviderLogin { + impl std::convert::TryFrom for super::ApiKeyResponse { type Error = String; - fn try_from(value: AccessTokenProviderLogin) -> Result { + fn try_from(value: ApiKeyResponse) -> Result { Ok(Self { - expiration: value.expiration?, + created_at: value.created_at?, + id: value.id?, permissions: value.permissions?, - token: value.token?, }) } } - impl From for AccessTokenProviderLogin { - fn from(value: super::AccessTokenProviderLogin) -> Self { + impl From for ApiKeyResponse { + fn from(value: super::ApiKeyResponse) -> Self { Self { - expiration: Ok(value.expiration), + created_at: Ok(value.created_at), + id: Ok(value.id), permissions: Ok(value.permissions), - token: Ok(value.token), } } } @@ -906,147 +973,19 @@ pub mod types { } #[derive(Clone, Debug)] - pub struct ApiUserTokenCreateParams { - expires_at: Result, String>, + pub struct ApiUserUpdateParams { permissions: Result, } - impl Default for ApiUserTokenCreateParams { + impl Default for ApiUserUpdateParams { fn default() -> Self { Self { - expires_at: Err("no value supplied for expires_at".to_string()), permissions: Err("no value supplied for permissions".to_string()), } } } - impl ApiUserTokenCreateParams { - pub fn expires_at(mut self, value: T) -> Self - where - T: std::convert::TryInto>, - T::Error: std::fmt::Display, - { - self.expires_at = value - .try_into() - .map_err(|e| format!("error converting supplied value for expires_at: {}", e)); - self - } - pub fn permissions(mut self, value: T) -> Self - where - T: std::convert::TryInto, - T::Error: std::fmt::Display, - { - self.permissions = value - .try_into() - .map_err(|e| format!("error converting supplied value for permissions: {}", e)); - self - } - } - - impl std::convert::TryFrom for super::ApiUserTokenCreateParams { - type Error = String; - fn try_from(value: ApiUserTokenCreateParams) -> Result { - Ok(Self { - expires_at: value.expires_at?, - permissions: value.permissions?, - }) - } - } - - impl From for ApiUserTokenCreateParams { - fn from(value: super::ApiUserTokenCreateParams) -> Self { - Self { - expires_at: Ok(value.expires_at), - permissions: Ok(value.permissions), - } - } - } - - #[derive(Clone, Debug)] - pub struct ApiUserTokenResponse { - created_at: Result, String>, - id: Result, - permissions: Result, - } - - impl Default for ApiUserTokenResponse { - fn default() -> Self { - Self { - created_at: Err("no value supplied for created_at".to_string()), - id: Err("no value supplied for id".to_string()), - permissions: Err("no value supplied for permissions".to_string()), - } - } - } - - impl ApiUserTokenResponse { - pub fn created_at(mut self, value: T) -> Self - where - T: std::convert::TryInto>, - T::Error: std::fmt::Display, - { - self.created_at = value - .try_into() - .map_err(|e| format!("error converting supplied value for created_at: {}", e)); - self - } - pub fn id(mut self, value: T) -> Self - where - T: std::convert::TryInto, - T::Error: std::fmt::Display, - { - self.id = value - .try_into() - .map_err(|e| format!("error converting supplied value for id: {}", e)); - self - } - pub fn permissions(mut self, value: T) -> Self - where - T: std::convert::TryInto, - T::Error: std::fmt::Display, - { - self.permissions = value - .try_into() - .map_err(|e| format!("error converting supplied value for permissions: {}", e)); - self - } - } - - impl std::convert::TryFrom for super::ApiUserTokenResponse { - type Error = String; - fn try_from(value: ApiUserTokenResponse) -> Result { - Ok(Self { - created_at: value.created_at?, - id: value.id?, - permissions: value.permissions?, - }) - } - } - - impl From for ApiUserTokenResponse { - fn from(value: super::ApiUserTokenResponse) -> Self { - Self { - created_at: Ok(value.created_at), - id: Ok(value.id), - permissions: Ok(value.permissions), - } - } - } - - #[derive(Clone, Debug)] - pub struct ApiUserUpdateParams { - permissions: Result, - } - - impl Default for ApiUserUpdateParams { - fn default() -> Self { - Self { - permissions: Err("no value supplied for permissions".to_string()), - } - } - } - - impl ApiUserUpdateParams { + impl ApiUserUpdateParams { pub fn permissions(mut self, value: T) -> Self where T: std::convert::TryInto, @@ -1898,25 +1837,25 @@ pub mod types { } #[derive(Clone, Debug)] - pub struct InitialApiUserTokenResponse { + pub struct InitialApiKeyResponse { created_at: Result, String>, id: Result, + key: Result, permissions: Result, - token: Result, } - impl Default for InitialApiUserTokenResponse { + impl Default for InitialApiKeyResponse { fn default() -> Self { Self { created_at: Err("no value supplied for created_at".to_string()), id: Err("no value supplied for id".to_string()), + key: Err("no value supplied for key".to_string()), permissions: Err("no value supplied for permissions".to_string()), - token: Err("no value supplied for token".to_string()), } } } - impl InitialApiUserTokenResponse { + impl InitialApiKeyResponse { pub fn created_at(mut self, value: T) -> Self where T: std::convert::TryInto>, @@ -1937,597 +1876,1813 @@ pub mod types { .map_err(|e| format!("error converting supplied value for id: {}", e)); self } - pub fn permissions(mut self, value: T) -> Self + pub fn key(mut self, value: T) -> Self where - T: std::convert::TryInto, + T: std::convert::TryInto, T::Error: std::fmt::Display, { - self.permissions = value + self.key = value .try_into() - .map_err(|e| format!("error converting supplied value for permissions: {}", e)); + .map_err(|e| format!("error converting supplied value for key: {}", e)); self } - pub fn token(mut self, value: T) -> Self + pub fn permissions(mut self, value: T) -> Self where - T: std::convert::TryInto, + T: std::convert::TryInto, T::Error: std::fmt::Display, { - self.token = value + self.permissions = value .try_into() - .map_err(|e| format!("error converting supplied value for token: {}", e)); + .map_err(|e| format!("error converting supplied value for permissions: {}", e)); self } } - impl std::convert::TryFrom for super::InitialApiUserTokenResponse { + impl std::convert::TryFrom for super::InitialApiKeyResponse { type Error = String; - fn try_from(value: InitialApiUserTokenResponse) -> Result { + fn try_from(value: InitialApiKeyResponse) -> Result { Ok(Self { created_at: value.created_at?, id: value.id?, + key: value.key?, permissions: value.permissions?, - token: value.token?, }) } } - impl From for InitialApiUserTokenResponse { - fn from(value: super::InitialApiUserTokenResponse) -> Self { + impl From for InitialApiKeyResponse { + fn from(value: super::InitialApiKeyResponse) -> Self { Self { created_at: Ok(value.created_at), id: Ok(value.id), + key: Ok(value.key), permissions: Ok(value.permissions), - token: Ok(value.token), } } } #[derive(Clone, Debug)] - pub struct JwtProviderLogin { - expiration: Result>, String>, - permissions: Result, - token: Result, + pub struct ListRfd { + authors: Result, String>, + commit: Result, + committed_at: Result, String>, + discussion: Result, String>, + id: Result, + link: Result, String>, + rfd_number: Result, + sha: Result, + state: Result, String>, + title: Result, } - impl Default for JwtProviderLogin { + impl Default for ListRfd { fn default() -> Self { Self { - expiration: Ok(Default::default()), - permissions: Err("no value supplied for permissions".to_string()), - token: Err("no value supplied for token".to_string()), + authors: Ok(Default::default()), + commit: Err("no value supplied for commit".to_string()), + committed_at: Err("no value supplied for committed_at".to_string()), + discussion: Ok(Default::default()), + id: Err("no value supplied for id".to_string()), + link: Ok(Default::default()), + rfd_number: Err("no value supplied for rfd_number".to_string()), + sha: Err("no value supplied for sha".to_string()), + state: Ok(Default::default()), + title: Err("no value supplied for title".to_string()), } } } - impl JwtProviderLogin { - pub fn expiration(mut self, value: T) -> Self + impl ListRfd { + pub fn authors(mut self, value: T) -> Self where - T: std::convert::TryInto>>, + T: std::convert::TryInto>, T::Error: std::fmt::Display, { - self.expiration = value + self.authors = value .try_into() - .map_err(|e| format!("error converting supplied value for expiration: {}", e)); + .map_err(|e| format!("error converting supplied value for authors: {}", e)); self } - pub fn permissions(mut self, value: T) -> Self + pub fn commit(mut self, value: T) -> Self where - T: std::convert::TryInto, + T: std::convert::TryInto, T::Error: std::fmt::Display, { - self.permissions = value + self.commit = value .try_into() - .map_err(|e| format!("error converting supplied value for permissions: {}", e)); + .map_err(|e| format!("error converting supplied value for commit: {}", e)); + self + } + pub fn committed_at(mut self, value: T) -> Self + where + T: std::convert::TryInto>, + T::Error: std::fmt::Display, + { + self.committed_at = value.try_into().map_err(|e| { + format!("error converting supplied value for committed_at: {}", e) + }); + self + } + pub fn discussion(mut self, value: T) -> Self + where + T: std::convert::TryInto>, + T::Error: std::fmt::Display, + { + self.discussion = value + .try_into() + .map_err(|e| format!("error converting supplied value for discussion: {}", e)); + self + } + pub fn id(mut self, value: T) -> Self + where + T: std::convert::TryInto, + T::Error: std::fmt::Display, + { + self.id = value + .try_into() + .map_err(|e| format!("error converting supplied value for id: {}", e)); + self + } + pub fn link(mut self, value: T) -> Self + where + T: std::convert::TryInto>, + T::Error: std::fmt::Display, + { + self.link = value + .try_into() + .map_err(|e| format!("error converting supplied value for link: {}", e)); + self + } + pub fn rfd_number(mut self, value: T) -> Self + where + T: std::convert::TryInto, + T::Error: std::fmt::Display, + { + self.rfd_number = value + .try_into() + .map_err(|e| format!("error converting supplied value for rfd_number: {}", e)); + self + } + pub fn sha(mut self, value: T) -> Self + where + T: std::convert::TryInto, + T::Error: std::fmt::Display, + { + self.sha = value + .try_into() + .map_err(|e| format!("error converting supplied value for sha: {}", e)); self } - pub fn token(mut self, value: T) -> Self + pub fn state(mut self, value: T) -> Self + where + T: std::convert::TryInto>, + T::Error: std::fmt::Display, + { + self.state = value + .try_into() + .map_err(|e| format!("error converting supplied value for state: {}", e)); + self + } + pub fn title(mut self, value: T) -> Self where T: std::convert::TryInto, T::Error: std::fmt::Display, { - self.token = value + self.title = value .try_into() - .map_err(|e| format!("error converting supplied value for token: {}", e)); + .map_err(|e| format!("error converting supplied value for title: {}", e)); self } } - impl std::convert::TryFrom for super::JwtProviderLogin { + impl std::convert::TryFrom for super::ListRfd { type Error = String; - fn try_from(value: JwtProviderLogin) -> Result { + fn try_from(value: ListRfd) -> Result { Ok(Self { - expiration: value.expiration?, - permissions: value.permissions?, - token: value.token?, + authors: value.authors?, + commit: value.commit?, + committed_at: value.committed_at?, + discussion: value.discussion?, + id: value.id?, + link: value.link?, + rfd_number: value.rfd_number?, + sha: value.sha?, + state: value.state?, + title: value.title?, }) } } - impl From for JwtProviderLogin { - fn from(value: super::JwtProviderLogin) -> Self { + impl From for ListRfd { + fn from(value: super::ListRfd) -> Self { Self { - expiration: Ok(value.expiration), - permissions: Ok(value.permissions), - token: Ok(value.token), + authors: Ok(value.authors), + commit: Ok(value.commit), + committed_at: Ok(value.committed_at), + discussion: Ok(value.discussion), + id: Ok(value.id), + link: Ok(value.link), + rfd_number: Ok(value.rfd_number), + sha: Ok(value.sha), + state: Ok(value.state), + title: Ok(value.title), } } } #[derive(Clone, Debug)] - pub struct LoginTokenResponse { - token: Result, + pub struct OAuthAuthzCodeExchangeBody { + client_id: Result, + client_secret: Result, + code: Result, + grant_type: Result, + pkce_verifier: Result, String>, + redirect_uri: Result, } - impl Default for LoginTokenResponse { + impl Default for OAuthAuthzCodeExchangeBody { fn default() -> Self { Self { - token: Err("no value supplied for token".to_string()), + client_id: Err("no value supplied for client_id".to_string()), + client_secret: Err("no value supplied for client_secret".to_string()), + code: Err("no value supplied for code".to_string()), + grant_type: Err("no value supplied for grant_type".to_string()), + pkce_verifier: Ok(Default::default()), + redirect_uri: Err("no value supplied for redirect_uri".to_string()), } } } - impl LoginTokenResponse { - pub fn token(mut self, value: T) -> Self + impl OAuthAuthzCodeExchangeBody { + pub fn client_id(mut self, value: T) -> Self where - T: std::convert::TryInto, + T: std::convert::TryInto, T::Error: std::fmt::Display, { - self.token = value + self.client_id = value .try_into() - .map_err(|e| format!("error converting supplied value for token: {}", e)); + .map_err(|e| format!("error converting supplied value for client_id: {}", e)); self } - } - - impl std::convert::TryFrom for super::LoginTokenResponse { - type Error = String; - fn try_from(value: LoginTokenResponse) -> Result { - Ok(Self { - token: value.token?, - }) + pub fn client_secret(mut self, value: T) -> Self + where + T: std::convert::TryInto, + T::Error: std::fmt::Display, + { + self.client_secret = value.try_into().map_err(|e| { + format!("error converting supplied value for client_secret: {}", e) + }); + self + } + pub fn code(mut self, value: T) -> Self + where + T: std::convert::TryInto, + T::Error: std::fmt::Display, + { + self.code = value + .try_into() + .map_err(|e| format!("error converting supplied value for code: {}", e)); + self + } + pub fn grant_type(mut self, value: T) -> Self + where + T: std::convert::TryInto, + T::Error: std::fmt::Display, + { + self.grant_type = value + .try_into() + .map_err(|e| format!("error converting supplied value for grant_type: {}", e)); + self + } + pub fn pkce_verifier(mut self, value: T) -> Self + where + T: std::convert::TryInto>, + T::Error: std::fmt::Display, + { + self.pkce_verifier = value.try_into().map_err(|e| { + format!("error converting supplied value for pkce_verifier: {}", e) + }); + self + } + pub fn redirect_uri(mut self, value: T) -> Self + where + T: std::convert::TryInto, + T::Error: std::fmt::Display, + { + self.redirect_uri = value.try_into().map_err(|e| { + format!("error converting supplied value for redirect_uri: {}", e) + }); + self + } + } + + impl std::convert::TryFrom for super::OAuthAuthzCodeExchangeBody { + type Error = String; + fn try_from(value: OAuthAuthzCodeExchangeBody) -> Result { + Ok(Self { + client_id: value.client_id?, + client_secret: value.client_secret?, + code: value.code?, + grant_type: value.grant_type?, + pkce_verifier: value.pkce_verifier?, + redirect_uri: value.redirect_uri?, + }) } } - impl From for LoginTokenResponse { - fn from(value: super::LoginTokenResponse) -> Self { + impl From for OAuthAuthzCodeExchangeBody { + fn from(value: super::OAuthAuthzCodeExchangeBody) -> Self { Self { - token: Ok(value.token), + client_id: Ok(value.client_id), + client_secret: Ok(value.client_secret), + code: Ok(value.code), + grant_type: Ok(value.grant_type), + pkce_verifier: Ok(value.pkce_verifier), + redirect_uri: Ok(value.redirect_uri), } } } #[derive(Clone, Debug)] - pub struct OAuthProviderInfo { - auth_url_endpoint: Result, - client_id: Result, - device_code_endpoint: Result, - provider: Result, - scopes: Result, String>, - token_endpoint: Result, + pub struct OAuthAuthzCodeExchangeResponse { + access_token: Result, + expires_in: Result, + token_type: Result, } - impl Default for OAuthProviderInfo { + impl Default for OAuthAuthzCodeExchangeResponse { fn default() -> Self { Self { - auth_url_endpoint: Err("no value supplied for auth_url_endpoint".to_string()), - client_id: Err("no value supplied for client_id".to_string()), - device_code_endpoint: Err( - "no value supplied for device_code_endpoint".to_string() - ), - provider: Err("no value supplied for provider".to_string()), - scopes: Err("no value supplied for scopes".to_string()), - token_endpoint: Err("no value supplied for token_endpoint".to_string()), + access_token: Err("no value supplied for access_token".to_string()), + expires_in: Err("no value supplied for expires_in".to_string()), + token_type: Err("no value supplied for token_type".to_string()), } } } - impl OAuthProviderInfo { - pub fn auth_url_endpoint(mut self, value: T) -> Self + impl OAuthAuthzCodeExchangeResponse { + pub fn access_token(mut self, value: T) -> Self where T: std::convert::TryInto, T::Error: std::fmt::Display, { - self.auth_url_endpoint = value.try_into().map_err(|e| { - format!( - "error converting supplied value for auth_url_endpoint: {}", - e - ) + self.access_token = value.try_into().map_err(|e| { + format!("error converting supplied value for access_token: {}", e) }); self } - pub fn client_id(mut self, value: T) -> Self + pub fn expires_in(mut self, value: T) -> Self where - T: std::convert::TryInto, + T: std::convert::TryInto, T::Error: std::fmt::Display, { - self.client_id = value + self.expires_in = value .try_into() - .map_err(|e| format!("error converting supplied value for client_id: {}", e)); + .map_err(|e| format!("error converting supplied value for expires_in: {}", e)); self } - pub fn device_code_endpoint(mut self, value: T) -> Self + pub fn token_type(mut self, value: T) -> Self where T: std::convert::TryInto, T::Error: std::fmt::Display, { - self.device_code_endpoint = value.try_into().map_err(|e| { - format!( - "error converting supplied value for device_code_endpoint: {}", - e - ) - }); + self.token_type = value + .try_into() + .map_err(|e| format!("error converting supplied value for token_type: {}", e)); self } - pub fn provider(mut self, value: T) -> Self + } + + impl std::convert::TryFrom + for super::OAuthAuthzCodeExchangeResponse + { + type Error = String; + fn try_from(value: OAuthAuthzCodeExchangeResponse) -> Result { + Ok(Self { + access_token: value.access_token?, + expires_in: value.expires_in?, + token_type: value.token_type?, + }) + } + } + + impl From for OAuthAuthzCodeExchangeResponse { + fn from(value: super::OAuthAuthzCodeExchangeResponse) -> Self { + Self { + access_token: Ok(value.access_token), + expires_in: Ok(value.expires_in), + token_type: Ok(value.token_type), + } + } + } + + #[derive(Clone, Debug)] + pub struct OAuthClient { + created_at: Result, String>, + deleted_at: Result>, String>, + id: Result, + redirect_uris: Result, String>, + secrets: Result, String>, + } + + impl Default for OAuthClient { + fn default() -> Self { + Self { + created_at: Err("no value supplied for created_at".to_string()), + deleted_at: Ok(Default::default()), + id: Err("no value supplied for id".to_string()), + redirect_uris: Err("no value supplied for redirect_uris".to_string()), + secrets: Err("no value supplied for secrets".to_string()), + } + } + } + + impl OAuthClient { + pub fn created_at(mut self, value: T) -> Self where - T: std::convert::TryInto, + T: std::convert::TryInto>, T::Error: std::fmt::Display, { - self.provider = value + self.created_at = value .try_into() - .map_err(|e| format!("error converting supplied value for provider: {}", e)); + .map_err(|e| format!("error converting supplied value for created_at: {}", e)); self } - pub fn scopes(mut self, value: T) -> Self + pub fn deleted_at(mut self, value: T) -> Self where - T: std::convert::TryInto>, + T: std::convert::TryInto>>, T::Error: std::fmt::Display, { - self.scopes = value + self.deleted_at = value .try_into() - .map_err(|e| format!("error converting supplied value for scopes: {}", e)); + .map_err(|e| format!("error converting supplied value for deleted_at: {}", e)); self } - pub fn token_endpoint(mut self, value: T) -> Self + pub fn id(mut self, value: T) -> Self where - T: std::convert::TryInto, + T: std::convert::TryInto, T::Error: std::fmt::Display, { - self.token_endpoint = value.try_into().map_err(|e| { - format!("error converting supplied value for token_endpoint: {}", e) + self.id = value + .try_into() + .map_err(|e| format!("error converting supplied value for id: {}", e)); + self + } + pub fn redirect_uris(mut self, value: T) -> Self + where + T: std::convert::TryInto>, + T::Error: std::fmt::Display, + { + self.redirect_uris = value.try_into().map_err(|e| { + format!("error converting supplied value for redirect_uris: {}", e) }); self } + pub fn secrets(mut self, value: T) -> Self + where + T: std::convert::TryInto>, + T::Error: std::fmt::Display, + { + self.secrets = value + .try_into() + .map_err(|e| format!("error converting supplied value for secrets: {}", e)); + self + } } - impl std::convert::TryFrom for super::OAuthProviderInfo { + impl std::convert::TryFrom for super::OAuthClient { type Error = String; - fn try_from(value: OAuthProviderInfo) -> Result { + fn try_from(value: OAuthClient) -> Result { Ok(Self { - auth_url_endpoint: value.auth_url_endpoint?, - client_id: value.client_id?, - device_code_endpoint: value.device_code_endpoint?, - provider: value.provider?, - scopes: value.scopes?, - token_endpoint: value.token_endpoint?, + created_at: value.created_at?, + deleted_at: value.deleted_at?, + id: value.id?, + redirect_uris: value.redirect_uris?, + secrets: value.secrets?, }) } } - impl From for OAuthProviderInfo { - fn from(value: super::OAuthProviderInfo) -> Self { + impl From for OAuthClient { + fn from(value: super::OAuthClient) -> Self { Self { - auth_url_endpoint: Ok(value.auth_url_endpoint), - client_id: Ok(value.client_id), - device_code_endpoint: Ok(value.device_code_endpoint), - provider: Ok(value.provider), - scopes: Ok(value.scopes), - token_endpoint: Ok(value.token_endpoint), + created_at: Ok(value.created_at), + deleted_at: Ok(value.deleted_at), + id: Ok(value.id), + redirect_uris: Ok(value.redirect_uris), + secrets: Ok(value.secrets), } } } - } -} - -#[derive(Clone, Debug)] -/// Client for RFD API -/// -/// Programmatic access to RFDs -/// -/// Version: -pub struct Client { - pub(crate) baseurl: String, - pub(crate) client: reqwest::Client, -} - -impl Client { - /// Create a new client. - /// - /// `baseurl` is the base URL provided to the internal - /// `reqwest::Client`, and should include a scheme and hostname, - /// as well as port and a path stem if applicable. - pub fn new(baseurl: &str) -> Self { - #[cfg(not(target_arch = "wasm32"))] - let client = { - let dur = std::time::Duration::from_secs(15); - reqwest::ClientBuilder::new() - .connect_timeout(dur) - .timeout(dur) - }; - #[cfg(target_arch = "wasm32")] - let client = reqwest::ClientBuilder::new(); - Self::new_with_client(baseurl, client.build().unwrap()) - } - /// Construct a new client with an existing `reqwest::Client`, - /// allowing more control over its configuration. - /// - /// `baseurl` is the base URL provided to the internal - /// `reqwest::Client`, and should include a scheme and hostname, - /// as well as port and a path stem if applicable. - pub fn new_with_client(baseurl: &str, client: reqwest::Client) -> Self { - Self { - baseurl: baseurl.to_string(), - client, + #[derive(Clone, Debug)] + pub struct OAuthClientRedirectUri { + created_at: Result, String>, + deleted_at: Result>, String>, + id: Result, + oauth_client_id: Result, + redirect_uri: Result, } - } - - /// Get the base URL to which requests are made. - pub fn baseurl(&self) -> &String { - &self.baseurl - } - - /// Get the internal `reqwest::Client` used to make requests. - pub fn client(&self) -> &reqwest::Client { - &self.client - } - /// Get the version of this API. - /// - /// This string is pulled directly from the source OpenAPI - /// document and may be in any format the API selects. - pub fn api_version(&self) -> &'static str { - "" - } -} + impl Default for OAuthClientRedirectUri { + fn default() -> Self { + Self { + created_at: Err("no value supplied for created_at".to_string()), + deleted_at: Ok(Default::default()), + id: Err("no value supplied for id".to_string()), + oauth_client_id: Err("no value supplied for oauth_client_id".to_string()), + redirect_uri: Err("no value supplied for redirect_uri".to_string()), + } + } + } -impl Client { - /// Create a new user with a given set of permissions - /// - /// Sends a `POST` request to `/api-user` - /// - /// ```ignore - /// let response = client.create_api_user() - /// .body(body) - /// .send() - /// .await; - /// ``` - pub fn create_api_user(&self) -> builder::CreateApiUser { - builder::CreateApiUser::new(self) - } + impl OAuthClientRedirectUri { + pub fn created_at(mut self, value: T) -> Self + where + T: std::convert::TryInto>, + T::Error: std::fmt::Display, + { + self.created_at = value + .try_into() + .map_err(|e| format!("error converting supplied value for created_at: {}", e)); + self + } + pub fn deleted_at(mut self, value: T) -> Self + where + T: std::convert::TryInto>>, + T::Error: std::fmt::Display, + { + self.deleted_at = value + .try_into() + .map_err(|e| format!("error converting supplied value for deleted_at: {}", e)); + self + } + pub fn id(mut self, value: T) -> Self + where + T: std::convert::TryInto, + T::Error: std::fmt::Display, + { + self.id = value + .try_into() + .map_err(|e| format!("error converting supplied value for id: {}", e)); + self + } + pub fn oauth_client_id(mut self, value: T) -> Self + where + T: std::convert::TryInto, + T::Error: std::fmt::Display, + { + self.oauth_client_id = value.try_into().map_err(|e| { + format!("error converting supplied value for oauth_client_id: {}", e) + }); + self + } + pub fn redirect_uri(mut self, value: T) -> Self + where + T: std::convert::TryInto, + T::Error: std::fmt::Display, + { + self.redirect_uri = value.try_into().map_err(|e| { + format!("error converting supplied value for redirect_uri: {}", e) + }); + self + } + } + + impl std::convert::TryFrom for super::OAuthClientRedirectUri { + type Error = String; + fn try_from(value: OAuthClientRedirectUri) -> Result { + Ok(Self { + created_at: value.created_at?, + deleted_at: value.deleted_at?, + id: value.id?, + oauth_client_id: value.oauth_client_id?, + redirect_uri: value.redirect_uri?, + }) + } + } + + impl From for OAuthClientRedirectUri { + fn from(value: super::OAuthClientRedirectUri) -> Self { + Self { + created_at: Ok(value.created_at), + deleted_at: Ok(value.deleted_at), + id: Ok(value.id), + oauth_client_id: Ok(value.oauth_client_id), + redirect_uri: Ok(value.redirect_uri), + } + } + } + + #[derive(Clone, Debug)] + pub struct OAuthClientSecret { + created_at: Result, String>, + deleted_at: Result>, String>, + id: Result, + oauth_client_id: Result, + secret_signature: Result, + } + + impl Default for OAuthClientSecret { + fn default() -> Self { + Self { + created_at: Err("no value supplied for created_at".to_string()), + deleted_at: Ok(Default::default()), + id: Err("no value supplied for id".to_string()), + oauth_client_id: Err("no value supplied for oauth_client_id".to_string()), + secret_signature: Err("no value supplied for secret_signature".to_string()), + } + } + } + + impl OAuthClientSecret { + pub fn created_at(mut self, value: T) -> Self + where + T: std::convert::TryInto>, + T::Error: std::fmt::Display, + { + self.created_at = value + .try_into() + .map_err(|e| format!("error converting supplied value for created_at: {}", e)); + self + } + pub fn deleted_at(mut self, value: T) -> Self + where + T: std::convert::TryInto>>, + T::Error: std::fmt::Display, + { + self.deleted_at = value + .try_into() + .map_err(|e| format!("error converting supplied value for deleted_at: {}", e)); + self + } + pub fn id(mut self, value: T) -> Self + where + T: std::convert::TryInto, + T::Error: std::fmt::Display, + { + self.id = value + .try_into() + .map_err(|e| format!("error converting supplied value for id: {}", e)); + self + } + pub fn oauth_client_id(mut self, value: T) -> Self + where + T: std::convert::TryInto, + T::Error: std::fmt::Display, + { + self.oauth_client_id = value.try_into().map_err(|e| { + format!("error converting supplied value for oauth_client_id: {}", e) + }); + self + } + pub fn secret_signature(mut self, value: T) -> Self + where + T: std::convert::TryInto, + T::Error: std::fmt::Display, + { + self.secret_signature = value.try_into().map_err(|e| { + format!( + "error converting supplied value for secret_signature: {}", + e + ) + }); + self + } + } + + impl std::convert::TryFrom for super::OAuthClientSecret { + type Error = String; + fn try_from(value: OAuthClientSecret) -> Result { + Ok(Self { + created_at: value.created_at?, + deleted_at: value.deleted_at?, + id: value.id?, + oauth_client_id: value.oauth_client_id?, + secret_signature: value.secret_signature?, + }) + } + } + + impl From for OAuthClientSecret { + fn from(value: super::OAuthClientSecret) -> Self { + Self { + created_at: Ok(value.created_at), + deleted_at: Ok(value.deleted_at), + id: Ok(value.id), + oauth_client_id: Ok(value.oauth_client_id), + secret_signature: Ok(value.secret_signature), + } + } + } + + #[derive(Clone, Debug)] + pub struct OAuthProviderInfo { + auth_url_endpoint: Result, + client_id: Result, + device_code_endpoint: Result, + provider: Result, + scopes: Result, String>, + token_endpoint: Result, + } + + impl Default for OAuthProviderInfo { + fn default() -> Self { + Self { + auth_url_endpoint: Err("no value supplied for auth_url_endpoint".to_string()), + client_id: Err("no value supplied for client_id".to_string()), + device_code_endpoint: Err( + "no value supplied for device_code_endpoint".to_string() + ), + provider: Err("no value supplied for provider".to_string()), + scopes: Err("no value supplied for scopes".to_string()), + token_endpoint: Err("no value supplied for token_endpoint".to_string()), + } + } + } + + impl OAuthProviderInfo { + pub fn auth_url_endpoint(mut self, value: T) -> Self + where + T: std::convert::TryInto, + T::Error: std::fmt::Display, + { + self.auth_url_endpoint = value.try_into().map_err(|e| { + format!( + "error converting supplied value for auth_url_endpoint: {}", + e + ) + }); + self + } + pub fn client_id(mut self, value: T) -> Self + where + T: std::convert::TryInto, + T::Error: std::fmt::Display, + { + self.client_id = value + .try_into() + .map_err(|e| format!("error converting supplied value for client_id: {}", e)); + self + } + pub fn device_code_endpoint(mut self, value: T) -> Self + where + T: std::convert::TryInto, + T::Error: std::fmt::Display, + { + self.device_code_endpoint = value.try_into().map_err(|e| { + format!( + "error converting supplied value for device_code_endpoint: {}", + e + ) + }); + self + } + pub fn provider(mut self, value: T) -> Self + where + T: std::convert::TryInto, + T::Error: std::fmt::Display, + { + self.provider = value + .try_into() + .map_err(|e| format!("error converting supplied value for provider: {}", e)); + self + } + pub fn scopes(mut self, value: T) -> Self + where + T: std::convert::TryInto>, + T::Error: std::fmt::Display, + { + self.scopes = value + .try_into() + .map_err(|e| format!("error converting supplied value for scopes: {}", e)); + self + } + pub fn token_endpoint(mut self, value: T) -> Self + where + T: std::convert::TryInto, + T::Error: std::fmt::Display, + { + self.token_endpoint = value.try_into().map_err(|e| { + format!("error converting supplied value for token_endpoint: {}", e) + }); + self + } + } + + impl std::convert::TryFrom for super::OAuthProviderInfo { + type Error = String; + fn try_from(value: OAuthProviderInfo) -> Result { + Ok(Self { + auth_url_endpoint: value.auth_url_endpoint?, + client_id: value.client_id?, + device_code_endpoint: value.device_code_endpoint?, + provider: value.provider?, + scopes: value.scopes?, + token_endpoint: value.token_endpoint?, + }) + } + } + + impl From for OAuthProviderInfo { + fn from(value: super::OAuthProviderInfo) -> Self { + Self { + auth_url_endpoint: Ok(value.auth_url_endpoint), + client_id: Ok(value.client_id), + device_code_endpoint: Ok(value.device_code_endpoint), + provider: Ok(value.provider), + scopes: Ok(value.scopes), + token_endpoint: Ok(value.token_endpoint), + } + } + } + } +} + +#[derive(Clone, Debug)] +/// Client for RFD API +/// +/// Programmatic access to RFDs +/// +/// Version: +pub struct Client { + pub(crate) baseurl: String, + pub(crate) client: reqwest::Client, +} + +impl Client { + /// Create a new client. + /// + /// `baseurl` is the base URL provided to the internal + /// `reqwest::Client`, and should include a scheme and hostname, + /// as well as port and a path stem if applicable. + pub fn new(baseurl: &str) -> Self { + #[cfg(not(target_arch = "wasm32"))] + let client = { + let dur = std::time::Duration::from_secs(15); + reqwest::ClientBuilder::new() + .connect_timeout(dur) + .timeout(dur) + }; + #[cfg(target_arch = "wasm32")] + let client = reqwest::ClientBuilder::new(); + Self::new_with_client(baseurl, client.build().unwrap()) + } + + /// Construct a new client with an existing `reqwest::Client`, + /// allowing more control over its configuration. + /// + /// `baseurl` is the base URL provided to the internal + /// `reqwest::Client`, and should include a scheme and hostname, + /// as well as port and a path stem if applicable. + pub fn new_with_client(baseurl: &str, client: reqwest::Client) -> Self { + Self { + baseurl: baseurl.to_string(), + client, + } + } + + /// Get the base URL to which requests are made. + pub fn baseurl(&self) -> &String { + &self.baseurl + } + + /// Get the internal `reqwest::Client` used to make requests. + pub fn client(&self) -> &reqwest::Client { + &self.client + } + + /// Get the version of this API. + /// + /// This string is pulled directly from the source OpenAPI + /// document and may be in any format the API selects. + pub fn api_version(&self) -> &'static str { + "" + } +} + +impl Client { + /// Create a new user with a given set of permissions + /// + /// Sends a `POST` request to `/api-user` + /// + /// ```ignore + /// let response = client.create_api_user() + /// .body(body) + /// .send() + /// .await; + /// ``` + pub fn create_api_user(&self) -> builder::CreateApiUser { + builder::CreateApiUser::new(self) + } + + /// Get user information for a given user id + /// + /// Sends a `GET` request to `/api-user/{identifier}` + /// + /// ```ignore + /// let response = client.get_api_user() + /// .identifier(identifier) + /// .send() + /// .await; + /// ``` + pub fn get_api_user(&self) -> builder::GetApiUser { + builder::GetApiUser::new(self) + } + + /// Update the permissions assigned to a given user + /// + /// Sends a `POST` request to `/api-user/{identifier}` + /// + /// ```ignore + /// let response = client.update_api_user() + /// .identifier(identifier) + /// .body(body) + /// .send() + /// .await; + /// ``` + pub fn update_api_user(&self) -> builder::UpdateApiUser { + builder::UpdateApiUser::new(self) + } + + /// List the active and expired API tokens for a given user + /// + /// Sends a `GET` request to `/api-user/{identifier}/token` + /// + /// ```ignore + /// let response = client.list_api_user_tokens() + /// .identifier(identifier) + /// .send() + /// .await; + /// ``` + pub fn list_api_user_tokens(&self) -> builder::ListApiUserTokens { + builder::ListApiUserTokens::new(self) + } + + /// Sends a `POST` request to `/api-user/{identifier}/token` + /// + /// ```ignore + /// let response = client.create_api_user_token() + /// .identifier(identifier) + /// .body(body) + /// .send() + /// .await; + /// ``` + pub fn create_api_user_token(&self) -> builder::CreateApiUserToken { + builder::CreateApiUserToken::new(self) + } + + /// Sends a `GET` request to + /// `/api-user/{identifier}/token/{token_identifier}` + /// + /// ```ignore + /// let response = client.get_api_user_token() + /// .identifier(identifier) + /// .token_identifier(token_identifier) + /// .send() + /// .await; + /// ``` + pub fn get_api_user_token(&self) -> builder::GetApiUserToken { + builder::GetApiUserToken::new(self) + } + + /// Sends a `DELETE` request to + /// `/api-user/{identifier}/token/{token_identifier}` + /// + /// ```ignore + /// let response = client.delete_api_user_token() + /// .identifier(identifier) + /// .token_identifier(token_identifier) + /// .send() + /// .await; + /// ``` + pub fn delete_api_user_token(&self) -> builder::DeleteApiUserToken { + builder::DeleteApiUserToken::new(self) + } + + /// Generate the remote provider login url and redirect the user + /// + /// Sends a `GET` request to `/login/oauth/{provider}/code/authorize` + /// + /// ```ignore + /// let response = client.authz_code_redirect() + /// .provider(provider) + /// .client_id(client_id) + /// .redirect_uri(redirect_uri) + /// .response_type(response_type) + /// .state(state) + /// .send() + /// .await; + /// ``` + pub fn authz_code_redirect(&self) -> builder::AuthzCodeRedirect { + builder::AuthzCodeRedirect::new(self) + } + + /// Handle return calls from a remote OAuth provider + /// + /// Sends a `GET` request to `/login/oauth/{provider}/code/callback` + /// + /// ```ignore + /// let response = client.authz_code_callback() + /// .provider(provider) + /// .code(code) + /// .error(error) + /// .state(state) + /// .send() + /// .await; + /// ``` + pub fn authz_code_callback(&self) -> builder::AuthzCodeCallback { + builder::AuthzCodeCallback::new(self) + } + + /// Exchange an authorization code for an access token + /// + /// Sends a `POST` request to `/login/oauth/{provider}/code/token` + /// + /// ```ignore + /// let response = client.authz_code_exchange() + /// .provider(provider) + /// .body(body) + /// .send() + /// .await; + /// ``` + pub fn authz_code_exchange(&self) -> builder::AuthzCodeExchange { + builder::AuthzCodeExchange::new(self) + } + + /// Sends a `GET` request to `/login/oauth/{provider}/device` + /// + /// ```ignore + /// let response = client.get_device_provider() + /// .provider(provider) + /// .send() + /// .await; + /// ``` + pub fn get_device_provider(&self) -> builder::GetDeviceProvider { + builder::GetDeviceProvider::new(self) + } + + /// Sends a `POST` request to `/login/oauth/{provider}/device/exchange` + /// + /// ```ignore + /// let response = client.exchange_device_token() + /// .provider(provider) + /// .body(body) + /// .send() + /// .await; + /// ``` + pub fn exchange_device_token(&self) -> builder::ExchangeDeviceToken { + builder::ExchangeDeviceToken::new(self) + } + + /// List OAuth clients + /// + /// Sends a `GET` request to `/oauth/client` + /// + /// ```ignore + /// let response = client.list_oauth_clients() + /// .send() + /// .await; + /// ``` + pub fn list_oauth_clients(&self) -> builder::ListOauthClients { + builder::ListOauthClients::new(self) + } + + /// Create a new OAuth Client + /// + /// Sends a `POST` request to `/oauth/client` + /// + /// ```ignore + /// let response = client.create_oauth_client() + /// .send() + /// .await; + /// ``` + pub fn create_oauth_client(&self) -> builder::CreateOauthClient { + builder::CreateOauthClient::new(self) + } + + /// Get an new OAuth Client + /// + /// Sends a `GET` request to `/oauth/client/{client_id}` + /// + /// ```ignore + /// let response = client.get_oauth_client() + /// .client_id(client_id) + /// .send() + /// .await; + /// ``` + pub fn get_oauth_client(&self) -> builder::GetOauthClient { + builder::GetOauthClient::new(self) + } + + /// Add an OAuth client redirect uri + /// + /// Sends a `POST` request to `/oauth/client/{client_id}/redirect_uri` + /// + /// ```ignore + /// let response = client.create_oauth_client_redirect_uri() + /// .client_id(client_id) + /// .body(body) + /// .send() + /// .await; + /// ``` + pub fn create_oauth_client_redirect_uri(&self) -> builder::CreateOauthClientRedirectUri { + builder::CreateOauthClientRedirectUri::new(self) + } + + /// Delete an OAuth client redirect uri + /// + /// Sends a `DELETE` request to + /// `/oauth/client/{client_id}/redirect_uri/{redirect_uri_id}` + /// + /// ```ignore + /// let response = client.delete_oauth_client_redirect_uri() + /// .client_id(client_id) + /// .redirect_uri_id(redirect_uri_id) + /// .send() + /// .await; + /// ``` + pub fn delete_oauth_client_redirect_uri(&self) -> builder::DeleteOauthClientRedirectUri { + builder::DeleteOauthClientRedirectUri::new(self) + } + + /// Add an OAuth client secret + /// + /// Sends a `POST` request to `/oauth/client/{client_id}/secret` + /// + /// ```ignore + /// let response = client.create_oauth_client_secret() + /// .client_id(client_id) + /// .send() + /// .await; + /// ``` + pub fn create_oauth_client_secret(&self) -> builder::CreateOauthClientSecret { + builder::CreateOauthClientSecret::new(self) + } + + /// Delete an OAuth client secret + /// + /// Sends a `DELETE` request to + /// `/oauth/client/{client_id}/secret/{secret_id}` + /// + /// ```ignore + /// let response = client.delete_oauth_client_secret() + /// .client_id(client_id) + /// .secret_id(secret_id) + /// .send() + /// .await; + /// ``` + pub fn delete_oauth_client_secret(&self) -> builder::DeleteOauthClientSecret { + builder::DeleteOauthClientSecret::new(self) + } + + /// List all available RFDs + /// + /// Sends a `GET` request to `/rfd` + /// + /// ```ignore + /// let response = client.get_rfds() + /// .send() + /// .await; + /// ``` + pub fn get_rfds(&self) -> builder::GetRfds { + builder::GetRfds::new(self) + } + + /// Get the latest representation of an RFD + /// + /// Sends a `GET` request to `/rfd/{number}` + /// + /// ```ignore + /// let response = client.get_rfd() + /// .number(number) + /// .send() + /// .await; + /// ``` + pub fn get_rfd(&self) -> builder::GetRfd { + builder::GetRfd::new(self) + } - /// Get user information for a given user id + /// Retrieve the user information of the calling user /// - /// Sends a `GET` request to `/api-user/{identifier}` + /// Sends a `GET` request to `/self` /// /// ```ignore - /// let response = client.get_api_user() - /// .identifier(identifier) + /// let response = client.get_self() /// .send() /// .await; /// ``` - pub fn get_api_user(&self) -> builder::GetApiUser { - builder::GetApiUser::new(self) + pub fn get_self(&self) -> builder::GetSelf { + builder::GetSelf::new(self) + } +} + +pub trait ClientHiddenExt { + /// Sends a `POST` request to `/github` + /// + /// ```ignore + /// let response = client.github_webhook() + /// .body(body) + /// .send() + /// .await; + /// ``` + fn github_webhook(&self) -> builder::GithubWebhook; +} + +impl ClientHiddenExt for Client { + fn github_webhook(&self) -> builder::GithubWebhook { + builder::GithubWebhook::new(self) + } +} + +pub mod builder { + use super::types; + #[allow(unused_imports)] + use super::{ + encode_path, ByteStream, Error, HeaderMap, HeaderValue, RequestBuilderExt, ResponseValue, + }; + /// Builder for [`Client::create_api_user`] + /// + /// [`Client::create_api_user`]: super::Client::create_api_user + #[derive(Debug, Clone)] + pub struct CreateApiUser<'a> { + client: &'a super::Client, + body: Result, + } + + impl<'a> CreateApiUser<'a> { + pub fn new(client: &'a super::Client) -> Self { + Self { + client, + body: Ok(types::builder::ApiUserUpdateParams::default()), + } + } + + pub fn body(mut self, value: V) -> Self + where + V: std::convert::TryInto, + { + self.body = value + .try_into() + .map(From::from) + .map_err(|_| "conversion to `ApiUserUpdateParams` for body failed".to_string()); + self + } + + pub fn body_map(mut self, f: F) -> Self + where + F: std::ops::FnOnce( + types::builder::ApiUserUpdateParams, + ) -> types::builder::ApiUserUpdateParams, + { + self.body = self.body.map(f); + self + } + + /// Sends a `POST` request to `/api-user` + pub async fn send( + self, + ) -> Result, Error> { + let Self { client, body } = self; + let body = body + .and_then(std::convert::TryInto::::try_into) + .map_err(Error::InvalidRequest)?; + let url = format!("{}/api-user", client.baseurl,); + let request = client + .client + .post(url) + .header( + reqwest::header::ACCEPT, + reqwest::header::HeaderValue::from_static("application/json"), + ) + .json(&body) + .build()?; + let result = client.client.execute(request).await; + let response = result?; + match response.status().as_u16() { + 201u16 => ResponseValue::from_response(response).await, + 400u16..=499u16 => Err(Error::ErrorResponse( + ResponseValue::from_response(response).await?, + )), + 500u16..=599u16 => Err(Error::ErrorResponse( + ResponseValue::from_response(response).await?, + )), + _ => Err(Error::UnexpectedResponse(response)), + } + } + } + + /// Builder for [`Client::get_api_user`] + /// + /// [`Client::get_api_user`]: super::Client::get_api_user + #[derive(Debug, Clone)] + pub struct GetApiUser<'a> { + client: &'a super::Client, + identifier: Result, + } + + impl<'a> GetApiUser<'a> { + pub fn new(client: &'a super::Client) -> Self { + Self { + client, + identifier: Err("identifier was not initialized".to_string()), + } + } + + pub fn identifier(mut self, value: V) -> Self + where + V: std::convert::TryInto, + { + self.identifier = value + .try_into() + .map_err(|_| "conversion to `uuid :: Uuid` for identifier failed".to_string()); + self + } + + /// Sends a `GET` request to `/api-user/{identifier}` + pub async fn send( + self, + ) -> Result, Error> { + let Self { client, identifier } = self; + let identifier = identifier.map_err(Error::InvalidRequest)?; + let url = format!( + "{}/api-user/{}", + client.baseurl, + encode_path(&identifier.to_string()), + ); + let request = client + .client + .get(url) + .header( + reqwest::header::ACCEPT, + reqwest::header::HeaderValue::from_static("application/json"), + ) + .build()?; + let result = client.client.execute(request).await; + let response = result?; + match response.status().as_u16() { + 200u16 => ResponseValue::from_response(response).await, + 400u16..=499u16 => Err(Error::ErrorResponse( + ResponseValue::from_response(response).await?, + )), + 500u16..=599u16 => Err(Error::ErrorResponse( + ResponseValue::from_response(response).await?, + )), + _ => Err(Error::UnexpectedResponse(response)), + } + } + } + + /// Builder for [`Client::update_api_user`] + /// + /// [`Client::update_api_user`]: super::Client::update_api_user + #[derive(Debug, Clone)] + pub struct UpdateApiUser<'a> { + client: &'a super::Client, + identifier: Result, + body: Result, + } + + impl<'a> UpdateApiUser<'a> { + pub fn new(client: &'a super::Client) -> Self { + Self { + client, + identifier: Err("identifier was not initialized".to_string()), + body: Ok(types::builder::ApiUserUpdateParams::default()), + } + } + + pub fn identifier(mut self, value: V) -> Self + where + V: std::convert::TryInto, + { + self.identifier = value + .try_into() + .map_err(|_| "conversion to `uuid :: Uuid` for identifier failed".to_string()); + self + } + + pub fn body(mut self, value: V) -> Self + where + V: std::convert::TryInto, + { + self.body = value + .try_into() + .map(From::from) + .map_err(|_| "conversion to `ApiUserUpdateParams` for body failed".to_string()); + self + } + + pub fn body_map(mut self, f: F) -> Self + where + F: std::ops::FnOnce( + types::builder::ApiUserUpdateParams, + ) -> types::builder::ApiUserUpdateParams, + { + self.body = self.body.map(f); + self + } + + /// Sends a `POST` request to `/api-user/{identifier}` + pub async fn send( + self, + ) -> Result, Error> { + let Self { + client, + identifier, + body, + } = self; + let identifier = identifier.map_err(Error::InvalidRequest)?; + let body = body + .and_then(std::convert::TryInto::::try_into) + .map_err(Error::InvalidRequest)?; + let url = format!( + "{}/api-user/{}", + client.baseurl, + encode_path(&identifier.to_string()), + ); + let request = client + .client + .post(url) + .header( + reqwest::header::ACCEPT, + reqwest::header::HeaderValue::from_static("application/json"), + ) + .json(&body) + .build()?; + let result = client.client.execute(request).await; + let response = result?; + match response.status().as_u16() { + 200u16 => ResponseValue::from_response(response).await, + 400u16..=499u16 => Err(Error::ErrorResponse( + ResponseValue::from_response(response).await?, + )), + 500u16..=599u16 => Err(Error::ErrorResponse( + ResponseValue::from_response(response).await?, + )), + _ => Err(Error::UnexpectedResponse(response)), + } + } } - /// Update the permissions assigned to a given user - /// - /// Sends a `POST` request to `/api-user/{identifier}` + /// Builder for [`Client::list_api_user_tokens`] /// - /// ```ignore - /// let response = client.update_api_user() - /// .identifier(identifier) - /// .body(body) - /// .send() - /// .await; - /// ``` - pub fn update_api_user(&self) -> builder::UpdateApiUser { - builder::UpdateApiUser::new(self) + /// [`Client::list_api_user_tokens`]: super::Client::list_api_user_tokens + #[derive(Debug, Clone)] + pub struct ListApiUserTokens<'a> { + client: &'a super::Client, + identifier: Result, } - /// List the active and expired API tokens for a given user - /// - /// Sends a `GET` request to `/api-user/{identifier}/token` - /// - /// ```ignore - /// let response = client.list_api_user_tokens() - /// .identifier(identifier) - /// .send() - /// .await; - /// ``` - pub fn list_api_user_tokens(&self) -> builder::ListApiUserTokens { - builder::ListApiUserTokens::new(self) - } + impl<'a> ListApiUserTokens<'a> { + pub fn new(client: &'a super::Client) -> Self { + Self { + client, + identifier: Err("identifier was not initialized".to_string()), + } + } - /// Sends a `POST` request to `/api-user/{identifier}/token` - /// - /// ```ignore - /// let response = client.create_api_user_token() - /// .identifier(identifier) - /// .body(body) - /// .send() - /// .await; - /// ``` - pub fn create_api_user_token(&self) -> builder::CreateApiUserToken { - builder::CreateApiUserToken::new(self) - } + pub fn identifier(mut self, value: V) -> Self + where + V: std::convert::TryInto, + { + self.identifier = value + .try_into() + .map_err(|_| "conversion to `uuid :: Uuid` for identifier failed".to_string()); + self + } - /// Sends a `GET` request to - /// `/api-user/{identifier}/token/{token_identifier}` - /// - /// ```ignore - /// let response = client.get_api_user_token() - /// .identifier(identifier) - /// .token_identifier(token_identifier) - /// .send() - /// .await; - /// ``` - pub fn get_api_user_token(&self) -> builder::GetApiUserToken { - builder::GetApiUserToken::new(self) + /// Sends a `GET` request to `/api-user/{identifier}/token` + pub async fn send( + self, + ) -> Result>, Error> { + let Self { client, identifier } = self; + let identifier = identifier.map_err(Error::InvalidRequest)?; + let url = format!( + "{}/api-user/{}/token", + client.baseurl, + encode_path(&identifier.to_string()), + ); + let request = client + .client + .get(url) + .header( + reqwest::header::ACCEPT, + reqwest::header::HeaderValue::from_static("application/json"), + ) + .build()?; + let result = client.client.execute(request).await; + let response = result?; + match response.status().as_u16() { + 200u16 => ResponseValue::from_response(response).await, + 400u16..=499u16 => Err(Error::ErrorResponse( + ResponseValue::from_response(response).await?, + )), + 500u16..=599u16 => Err(Error::ErrorResponse( + ResponseValue::from_response(response).await?, + )), + _ => Err(Error::UnexpectedResponse(response)), + } + } } - /// Sends a `DELETE` request to - /// `/api-user/{identifier}/token/{token_identifier}` + /// Builder for [`Client::create_api_user_token`] /// - /// ```ignore - /// let response = client.delete_api_user_token() - /// .identifier(identifier) - /// .token_identifier(token_identifier) - /// .send() - /// .await; - /// ``` - pub fn delete_api_user_token(&self) -> builder::DeleteApiUserToken { - builder::DeleteApiUserToken::new(self) + /// [`Client::create_api_user_token`]: super::Client::create_api_user_token + #[derive(Debug, Clone)] + pub struct CreateApiUserToken<'a> { + client: &'a super::Client, + identifier: Result, + body: Result, } - /// Sends a `POST` request to `/login/access-token/{provider}` - /// - /// ```ignore - /// let response = client.access_token_login() - /// .provider(provider) - /// .body(body) - /// .send() - /// .await; - /// ``` - pub fn access_token_login(&self) -> builder::AccessTokenLogin { - builder::AccessTokenLogin::new(self) - } + impl<'a> CreateApiUserToken<'a> { + pub fn new(client: &'a super::Client) -> Self { + Self { + client, + identifier: Err("identifier was not initialized".to_string()), + body: Ok(types::builder::ApiKeyCreateParams::default()), + } + } - /// Sends a `POST` request to `/login/jwt/{provider}` - /// - /// ```ignore - /// let response = client.jwt_login() - /// .provider(provider) - /// .body(body) - /// .send() - /// .await; - /// ``` - pub fn jwt_login(&self) -> builder::JwtLogin { - builder::JwtLogin::new(self) + pub fn identifier(mut self, value: V) -> Self + where + V: std::convert::TryInto, + { + self.identifier = value + .try_into() + .map_err(|_| "conversion to `uuid :: Uuid` for identifier failed".to_string()); + self + } + + pub fn body(mut self, value: V) -> Self + where + V: std::convert::TryInto, + { + self.body = value + .try_into() + .map(From::from) + .map_err(|_| "conversion to `ApiKeyCreateParams` for body failed".to_string()); + self + } + + pub fn body_map(mut self, f: F) -> Self + where + F: std::ops::FnOnce( + types::builder::ApiKeyCreateParams, + ) -> types::builder::ApiKeyCreateParams, + { + self.body = self.body.map(f); + self + } + + /// Sends a `POST` request to `/api-user/{identifier}/token` + pub async fn send( + self, + ) -> Result, Error> { + let Self { + client, + identifier, + body, + } = self; + let identifier = identifier.map_err(Error::InvalidRequest)?; + let body = body + .and_then(std::convert::TryInto::::try_into) + .map_err(Error::InvalidRequest)?; + let url = format!( + "{}/api-user/{}/token", + client.baseurl, + encode_path(&identifier.to_string()), + ); + let request = client + .client + .post(url) + .header( + reqwest::header::ACCEPT, + reqwest::header::HeaderValue::from_static("application/json"), + ) + .json(&body) + .build()?; + let result = client.client.execute(request).await; + let response = result?; + match response.status().as_u16() { + 201u16 => ResponseValue::from_response(response).await, + 400u16..=499u16 => Err(Error::ErrorResponse( + ResponseValue::from_response(response).await?, + )), + 500u16..=599u16 => Err(Error::ErrorResponse( + ResponseValue::from_response(response).await?, + )), + _ => Err(Error::UnexpectedResponse(response)), + } + } } - /// Sends a `GET` request to `/login/oauth/{provider}/device` + /// Builder for [`Client::get_api_user_token`] /// - /// ```ignore - /// let response = client.get_device_provider() - /// .provider(provider) - /// .send() - /// .await; - /// ``` - pub fn get_device_provider(&self) -> builder::GetDeviceProvider { - builder::GetDeviceProvider::new(self) + /// [`Client::get_api_user_token`]: super::Client::get_api_user_token + #[derive(Debug, Clone)] + pub struct GetApiUserToken<'a> { + client: &'a super::Client, + identifier: Result, + token_identifier: Result, } - /// Sends a `POST` request to `/login/oauth/{provider}/device/exchange` - /// - /// ```ignore - /// let response = client.exchange_device_token() - /// .provider(provider) - /// .body(body) - /// .send() - /// .await; - /// ``` - pub fn exchange_device_token(&self) -> builder::ExchangeDeviceToken { - builder::ExchangeDeviceToken::new(self) + impl<'a> GetApiUserToken<'a> { + pub fn new(client: &'a super::Client) -> Self { + Self { + client, + identifier: Err("identifier was not initialized".to_string()), + token_identifier: Err("token_identifier was not initialized".to_string()), + } + } + + pub fn identifier(mut self, value: V) -> Self + where + V: std::convert::TryInto, + { + self.identifier = value + .try_into() + .map_err(|_| "conversion to `uuid :: Uuid` for identifier failed".to_string()); + self + } + + pub fn token_identifier(mut self, value: V) -> Self + where + V: std::convert::TryInto, + { + self.token_identifier = value.try_into().map_err(|_| { + "conversion to `uuid :: Uuid` for token_identifier failed".to_string() + }); + self + } + + /// Sends a `GET` request to + /// `/api-user/{identifier}/token/{token_identifier}` + pub async fn send( + self, + ) -> Result, Error> { + let Self { + client, + identifier, + token_identifier, + } = self; + let identifier = identifier.map_err(Error::InvalidRequest)?; + let token_identifier = token_identifier.map_err(Error::InvalidRequest)?; + let url = format!( + "{}/api-user/{}/token/{}", + client.baseurl, + encode_path(&identifier.to_string()), + encode_path(&token_identifier.to_string()), + ); + let request = client + .client + .get(url) + .header( + reqwest::header::ACCEPT, + reqwest::header::HeaderValue::from_static("application/json"), + ) + .build()?; + let result = client.client.execute(request).await; + let response = result?; + match response.status().as_u16() { + 200u16 => ResponseValue::from_response(response).await, + 400u16..=499u16 => Err(Error::ErrorResponse( + ResponseValue::from_response(response).await?, + )), + 500u16..=599u16 => Err(Error::ErrorResponse( + ResponseValue::from_response(response).await?, + )), + _ => Err(Error::UnexpectedResponse(response)), + } + } } - /// Sends a `GET` request to `/rfd/{number}` + /// Builder for [`Client::delete_api_user_token`] /// - /// ```ignore - /// let response = client.get_rfd() - /// .number(number) - /// .send() - /// .await; - /// ``` - pub fn get_rfd(&self) -> builder::GetRfd { - builder::GetRfd::new(self) + /// [`Client::delete_api_user_token`]: super::Client::delete_api_user_token + #[derive(Debug, Clone)] + pub struct DeleteApiUserToken<'a> { + client: &'a super::Client, + identifier: Result, + token_identifier: Result, } - /// Retrieve the user information of the calling user - /// - /// Sends a `GET` request to `/self` - /// - /// ```ignore - /// let response = client.get_self() - /// .send() - /// .await; - /// ``` - pub fn get_self(&self) -> builder::GetSelf { - builder::GetSelf::new(self) - } -} + impl<'a> DeleteApiUserToken<'a> { + pub fn new(client: &'a super::Client) -> Self { + Self { + client, + identifier: Err("identifier was not initialized".to_string()), + token_identifier: Err("token_identifier was not initialized".to_string()), + } + } -pub trait ClientHiddenExt { - /// Sends a `POST` request to `/github` - /// - /// ```ignore - /// let response = client.github_webhook() - /// .body(body) - /// .send() - /// .await; - /// ``` - fn github_webhook(&self) -> builder::GithubWebhook; -} + pub fn identifier(mut self, value: V) -> Self + where + V: std::convert::TryInto, + { + self.identifier = value + .try_into() + .map_err(|_| "conversion to `uuid :: Uuid` for identifier failed".to_string()); + self + } -impl ClientHiddenExt for Client { - fn github_webhook(&self) -> builder::GithubWebhook { - builder::GithubWebhook::new(self) + pub fn token_identifier(mut self, value: V) -> Self + where + V: std::convert::TryInto, + { + self.token_identifier = value.try_into().map_err(|_| { + "conversion to `uuid :: Uuid` for token_identifier failed".to_string() + }); + self + } + + /// Sends a `DELETE` request to + /// `/api-user/{identifier}/token/{token_identifier}` + pub async fn send( + self, + ) -> Result, Error> { + let Self { + client, + identifier, + token_identifier, + } = self; + let identifier = identifier.map_err(Error::InvalidRequest)?; + let token_identifier = token_identifier.map_err(Error::InvalidRequest)?; + let url = format!( + "{}/api-user/{}/token/{}", + client.baseurl, + encode_path(&identifier.to_string()), + encode_path(&token_identifier.to_string()), + ); + let request = client + .client + .delete(url) + .header( + reqwest::header::ACCEPT, + reqwest::header::HeaderValue::from_static("application/json"), + ) + .build()?; + let result = client.client.execute(request).await; + let response = result?; + match response.status().as_u16() { + 200u16 => ResponseValue::from_response(response).await, + 400u16..=499u16 => Err(Error::ErrorResponse( + ResponseValue::from_response(response).await?, + )), + 500u16..=599u16 => Err(Error::ErrorResponse( + ResponseValue::from_response(response).await?, + )), + _ => Err(Error::UnexpectedResponse(response)), + } + } } -} -pub mod builder { - use super::types; - #[allow(unused_imports)] - use super::{ - encode_path, ByteStream, Error, HeaderMap, HeaderValue, RequestBuilderExt, ResponseValue, - }; - /// Builder for [`Client::create_api_user`] + /// Builder for [`ClientHiddenExt::github_webhook`] /// - /// [`Client::create_api_user`]: super::Client::create_api_user + /// [`ClientHiddenExt::github_webhook`]: super::ClientHiddenExt::github_webhook #[derive(Debug, Clone)] - pub struct CreateApiUser<'a> { + pub struct GithubWebhook<'a> { client: &'a super::Client, - body: Result, + body: Result, } - impl<'a> CreateApiUser<'a> { + impl<'a> GithubWebhook<'a> { pub fn new(client: &'a super::Client) -> Self { Self { client, - body: Ok(types::builder::ApiUserUpdateParams::default()), + body: Ok(types::builder::GitHubCommitPayload::default()), } } pub fn body(mut self, value: V) -> Self where - V: std::convert::TryInto, + V: std::convert::TryInto, { self.body = value .try_into() .map(From::from) - .map_err(|_| "conversion to `ApiUserUpdateParams` for body failed".to_string()); + .map_err(|_| "conversion to `GitHubCommitPayload` for body failed".to_string()); self } pub fn body_map(mut self, f: F) -> Self where F: std::ops::FnOnce( - types::builder::ApiUserUpdateParams, - ) -> types::builder::ApiUserUpdateParams, + types::builder::GitHubCommitPayload, + ) -> types::builder::GitHubCommitPayload, { self.body = self.body.map(f); self } - /// Sends a `POST` request to `/api-user` - pub async fn send( - self, - ) -> Result, Error> { + /// Sends a `POST` request to `/github` + pub async fn send(self) -> Result, Error> { let Self { client, body } = self; let body = body - .and_then(std::convert::TryInto::::try_into) + .and_then(std::convert::TryInto::::try_into) .map_err(Error::InvalidRequest)?; - let url = format!("{}/api-user", client.baseurl,); + let url = format!("{}/github", client.baseurl,); let request = client .client .post(url) @@ -2540,68 +3695,227 @@ pub mod builder { let result = client.client.execute(request).await; let response = result?; match response.status().as_u16() { - 201u16 => ResponseValue::from_response(response).await, - 400u16..=499u16 => Err(Error::ErrorResponse( - ResponseValue::from_response(response).await?, - )), - 500u16..=599u16 => Err(Error::ErrorResponse( - ResponseValue::from_response(response).await?, - )), - _ => Err(Error::UnexpectedResponse(response)), + 202u16 => ResponseValue::from_response(response).await, + 400u16..=499u16 => Err(Error::ErrorResponse( + ResponseValue::from_response(response).await?, + )), + 500u16..=599u16 => Err(Error::ErrorResponse( + ResponseValue::from_response(response).await?, + )), + _ => Err(Error::UnexpectedResponse(response)), + } + } + } + + /// Builder for [`Client::authz_code_redirect`] + /// + /// [`Client::authz_code_redirect`]: super::Client::authz_code_redirect + #[derive(Debug, Clone)] + pub struct AuthzCodeRedirect<'a> { + client: &'a super::Client, + provider: Result, + client_id: Result, + redirect_uri: Result, + response_type: Result, + state: Result, + } + + impl<'a> AuthzCodeRedirect<'a> { + pub fn new(client: &'a super::Client) -> Self { + Self { + client, + provider: Err("provider was not initialized".to_string()), + client_id: Err("client_id was not initialized".to_string()), + redirect_uri: Err("redirect_uri was not initialized".to_string()), + response_type: Err("response_type was not initialized".to_string()), + state: Err("state was not initialized".to_string()), + } + } + + pub fn provider(mut self, value: V) -> Self + where + V: std::convert::TryInto, + { + self.provider = value + .try_into() + .map_err(|_| "conversion to `OAuthProviderName` for provider failed".to_string()); + self + } + + pub fn client_id(mut self, value: V) -> Self + where + V: std::convert::TryInto, + { + self.client_id = value + .try_into() + .map_err(|_| "conversion to `uuid :: Uuid` for client_id failed".to_string()); + self + } + + pub fn redirect_uri(mut self, value: V) -> Self + where + V: std::convert::TryInto, + { + self.redirect_uri = value + .try_into() + .map_err(|_| "conversion to `String` for redirect_uri failed".to_string()); + self + } + + pub fn response_type(mut self, value: V) -> Self + where + V: std::convert::TryInto, + { + self.response_type = value + .try_into() + .map_err(|_| "conversion to `String` for response_type failed".to_string()); + self + } + + pub fn state(mut self, value: V) -> Self + where + V: std::convert::TryInto, + { + self.state = value + .try_into() + .map_err(|_| "conversion to `String` for state failed".to_string()); + self + } + + /// Sends a `GET` request to `/login/oauth/{provider}/code/authorize` + pub async fn send(self) -> Result, Error> { + let Self { + client, + provider, + client_id, + redirect_uri, + response_type, + state, + } = self; + let provider = provider.map_err(Error::InvalidRequest)?; + let client_id = client_id.map_err(Error::InvalidRequest)?; + let redirect_uri = redirect_uri.map_err(Error::InvalidRequest)?; + let response_type = response_type.map_err(Error::InvalidRequest)?; + let state = state.map_err(Error::InvalidRequest)?; + let url = format!( + "{}/login/oauth/{}/code/authorize", + client.baseurl, + encode_path(&provider.to_string()), + ); + let mut query = Vec::with_capacity(4usize); + query.push(("client_id", client_id.to_string())); + query.push(("redirect_uri", redirect_uri.to_string())); + query.push(("response_type", response_type.to_string())); + query.push(("state", state.to_string())); + let request = client.client.get(url).query(&query).build()?; + let result = client.client.execute(request).await; + let response = result?; + match response.status().as_u16() { + 200..=299 => Ok(ResponseValue::stream(response)), + _ => Err(Error::ErrorResponse(ResponseValue::stream(response))), } } } - /// Builder for [`Client::get_api_user`] + /// Builder for [`Client::authz_code_callback`] /// - /// [`Client::get_api_user`]: super::Client::get_api_user + /// [`Client::authz_code_callback`]: super::Client::authz_code_callback #[derive(Debug, Clone)] - pub struct GetApiUser<'a> { + pub struct AuthzCodeCallback<'a> { client: &'a super::Client, - identifier: Result, + provider: Result, + code: Result, String>, + error: Result, String>, + state: Result, String>, } - impl<'a> GetApiUser<'a> { + impl<'a> AuthzCodeCallback<'a> { pub fn new(client: &'a super::Client) -> Self { Self { client, - identifier: Err("identifier was not initialized".to_string()), + provider: Err("provider was not initialized".to_string()), + code: Ok(None), + error: Ok(None), + state: Ok(None), } } - pub fn identifier(mut self, value: V) -> Self + pub fn provider(mut self, value: V) -> Self where - V: std::convert::TryInto, + V: std::convert::TryInto, { - self.identifier = value + self.provider = value .try_into() - .map_err(|_| "conversion to `uuid :: Uuid` for identifier failed".to_string()); + .map_err(|_| "conversion to `OAuthProviderName` for provider failed".to_string()); self } - /// Sends a `GET` request to `/api-user/{identifier}` - pub async fn send( - self, - ) -> Result, Error> { - let Self { client, identifier } = self; - let identifier = identifier.map_err(Error::InvalidRequest)?; + pub fn code(mut self, value: V) -> Self + where + V: std::convert::TryInto, + { + self.code = value + .try_into() + .map(Some) + .map_err(|_| "conversion to `String` for code failed".to_string()); + self + } + + pub fn error(mut self, value: V) -> Self + where + V: std::convert::TryInto, + { + self.error = value + .try_into() + .map(Some) + .map_err(|_| "conversion to `String` for error failed".to_string()); + self + } + + pub fn state(mut self, value: V) -> Self + where + V: std::convert::TryInto, + { + self.state = value + .try_into() + .map(Some) + .map_err(|_| "conversion to `String` for state failed".to_string()); + self + } + + /// Sends a `GET` request to `/login/oauth/{provider}/code/callback` + pub async fn send(self) -> Result, Error> { + let Self { + client, + provider, + code, + error, + state, + } = self; + let provider = provider.map_err(Error::InvalidRequest)?; + let code = code.map_err(Error::InvalidRequest)?; + let error = error.map_err(Error::InvalidRequest)?; + let state = state.map_err(Error::InvalidRequest)?; let url = format!( - "{}/api-user/{}", + "{}/login/oauth/{}/code/callback", client.baseurl, - encode_path(&identifier.to_string()), + encode_path(&provider.to_string()), ); - let request = client - .client - .get(url) - .header( - reqwest::header::ACCEPT, - reqwest::header::HeaderValue::from_static("application/json"), - ) - .build()?; + let mut query = Vec::with_capacity(3usize); + if let Some(v) = &code { + query.push(("code", v.to_string())); + } + if let Some(v) = &error { + query.push(("error", v.to_string())); + } + if let Some(v) = &state { + query.push(("state", v.to_string())); + } + let request = client.client.get(url).query(&query).build()?; let result = client.client.execute(request).await; let response = result?; match response.status().as_u16() { - 200u16 => ResponseValue::from_response(response).await, + 200..=299 => Ok(ResponseValue::stream(response)), 400u16..=499u16 => Err(Error::ErrorResponse( ResponseValue::from_response(response).await?, )), @@ -2613,73 +3927,73 @@ pub mod builder { } } - /// Builder for [`Client::update_api_user`] + /// Builder for [`Client::authz_code_exchange`] /// - /// [`Client::update_api_user`]: super::Client::update_api_user + /// [`Client::authz_code_exchange`]: super::Client::authz_code_exchange #[derive(Debug, Clone)] - pub struct UpdateApiUser<'a> { + pub struct AuthzCodeExchange<'a> { client: &'a super::Client, - identifier: Result, - body: Result, + provider: Result, + body: Result, } - impl<'a> UpdateApiUser<'a> { + impl<'a> AuthzCodeExchange<'a> { pub fn new(client: &'a super::Client) -> Self { Self { client, - identifier: Err("identifier was not initialized".to_string()), - body: Ok(types::builder::ApiUserUpdateParams::default()), + provider: Err("provider was not initialized".to_string()), + body: Ok(types::builder::OAuthAuthzCodeExchangeBody::default()), } } - pub fn identifier(mut self, value: V) -> Self + pub fn provider(mut self, value: V) -> Self where - V: std::convert::TryInto, + V: std::convert::TryInto, { - self.identifier = value + self.provider = value .try_into() - .map_err(|_| "conversion to `uuid :: Uuid` for identifier failed".to_string()); + .map_err(|_| "conversion to `OAuthProviderName` for provider failed".to_string()); self } pub fn body(mut self, value: V) -> Self where - V: std::convert::TryInto, + V: std::convert::TryInto, { - self.body = value - .try_into() - .map(From::from) - .map_err(|_| "conversion to `ApiUserUpdateParams` for body failed".to_string()); + self.body = value.try_into().map(From::from).map_err(|_| { + "conversion to `OAuthAuthzCodeExchangeBody` for body failed".to_string() + }); self } pub fn body_map(mut self, f: F) -> Self where F: std::ops::FnOnce( - types::builder::ApiUserUpdateParams, - ) -> types::builder::ApiUserUpdateParams, + types::builder::OAuthAuthzCodeExchangeBody, + ) -> types::builder::OAuthAuthzCodeExchangeBody, { self.body = self.body.map(f); self } - /// Sends a `POST` request to `/api-user/{identifier}` + /// Sends a `POST` request to `/login/oauth/{provider}/code/token` pub async fn send( self, - ) -> Result, Error> { + ) -> Result, Error> + { let Self { client, - identifier, + provider, body, } = self; - let identifier = identifier.map_err(Error::InvalidRequest)?; + let provider = provider.map_err(Error::InvalidRequest)?; let body = body - .and_then(std::convert::TryInto::::try_into) + .and_then(std::convert::TryInto::::try_into) .map_err(Error::InvalidRequest)?; let url = format!( - "{}/api-user/{}", + "{}/login/oauth/{}/code/token", client.baseurl, - encode_path(&identifier.to_string()), + encode_path(&provider.to_string()), ); let request = client .client @@ -2688,7 +4002,7 @@ pub mod builder { reqwest::header::ACCEPT, reqwest::header::HeaderValue::from_static("application/json"), ) - .json(&body) + .form_urlencoded(&body)? .build()?; let result = client.client.execute(request).await; let response = result?; @@ -2705,43 +4019,43 @@ pub mod builder { } } - /// Builder for [`Client::list_api_user_tokens`] + /// Builder for [`Client::get_device_provider`] /// - /// [`Client::list_api_user_tokens`]: super::Client::list_api_user_tokens + /// [`Client::get_device_provider`]: super::Client::get_device_provider #[derive(Debug, Clone)] - pub struct ListApiUserTokens<'a> { + pub struct GetDeviceProvider<'a> { client: &'a super::Client, - identifier: Result, + provider: Result, } - impl<'a> ListApiUserTokens<'a> { + impl<'a> GetDeviceProvider<'a> { pub fn new(client: &'a super::Client) -> Self { Self { client, - identifier: Err("identifier was not initialized".to_string()), + provider: Err("provider was not initialized".to_string()), } } - pub fn identifier(mut self, value: V) -> Self + pub fn provider(mut self, value: V) -> Self where - V: std::convert::TryInto, + V: std::convert::TryInto, { - self.identifier = value + self.provider = value .try_into() - .map_err(|_| "conversion to `uuid :: Uuid` for identifier failed".to_string()); + .map_err(|_| "conversion to `OAuthProviderName` for provider failed".to_string()); self } - /// Sends a `GET` request to `/api-user/{identifier}/token` + /// Sends a `GET` request to `/login/oauth/{provider}/device` pub async fn send( self, - ) -> Result>, Error> { - let Self { client, identifier } = self; - let identifier = identifier.map_err(Error::InvalidRequest)?; + ) -> Result, Error> { + let Self { client, provider } = self; + let provider = provider.map_err(Error::InvalidRequest)?; let url = format!( - "{}/api-user/{}/token", + "{}/login/oauth/{}/device", client.baseurl, - encode_path(&identifier.to_string()), + encode_path(&provider.to_string()), ); let request = client .client @@ -2766,41 +4080,41 @@ pub mod builder { } } - /// Builder for [`Client::create_api_user_token`] + /// Builder for [`Client::exchange_device_token`] /// - /// [`Client::create_api_user_token`]: super::Client::create_api_user_token + /// [`Client::exchange_device_token`]: super::Client::exchange_device_token #[derive(Debug, Clone)] - pub struct CreateApiUserToken<'a> { + pub struct ExchangeDeviceToken<'a> { client: &'a super::Client, - identifier: Result, - body: Result, + provider: Result, + body: Result, } - impl<'a> CreateApiUserToken<'a> { + impl<'a> ExchangeDeviceToken<'a> { pub fn new(client: &'a super::Client) -> Self { Self { client, - identifier: Err("identifier was not initialized".to_string()), - body: Ok(types::builder::ApiUserTokenCreateParams::default()), + provider: Err("provider was not initialized".to_string()), + body: Ok(types::builder::AccessTokenExchangeRequest::default()), } } - pub fn identifier(mut self, value: V) -> Self + pub fn provider(mut self, value: V) -> Self where - V: std::convert::TryInto, + V: std::convert::TryInto, { - self.identifier = value + self.provider = value .try_into() - .map_err(|_| "conversion to `uuid :: Uuid` for identifier failed".to_string()); + .map_err(|_| "conversion to `OAuthProviderName` for provider failed".to_string()); self } pub fn body(mut self, value: V) -> Self where - V: std::convert::TryInto, + V: std::convert::TryInto, { self.body = value.try_into().map(From::from).map_err(|_| { - "conversion to `ApiUserTokenCreateParams` for body failed".to_string() + "conversion to `AccessTokenExchangeRequest` for body failed".to_string() }); self } @@ -2808,113 +4122,58 @@ pub mod builder { pub fn body_map(mut self, f: F) -> Self where F: std::ops::FnOnce( - types::builder::ApiUserTokenCreateParams, - ) -> types::builder::ApiUserTokenCreateParams, + types::builder::AccessTokenExchangeRequest, + ) -> types::builder::AccessTokenExchangeRequest, { self.body = self.body.map(f); self } - /// Sends a `POST` request to `/api-user/{identifier}/token` - pub async fn send( - self, - ) -> Result, Error> - { + /// Sends a `POST` request to `/login/oauth/{provider}/device/exchange` + pub async fn send(self) -> Result, Error> { let Self { client, - identifier, + provider, body, } = self; - let identifier = identifier.map_err(Error::InvalidRequest)?; + let provider = provider.map_err(Error::InvalidRequest)?; let body = body - .and_then(std::convert::TryInto::::try_into) + .and_then(std::convert::TryInto::::try_into) .map_err(Error::InvalidRequest)?; let url = format!( - "{}/api-user/{}/token", + "{}/login/oauth/{}/device/exchange", client.baseurl, - encode_path(&identifier.to_string()), + encode_path(&provider.to_string()), ); - let request = client - .client - .post(url) - .header( - reqwest::header::ACCEPT, - reqwest::header::HeaderValue::from_static("application/json"), - ) - .json(&body) - .build()?; + let request = client.client.post(url).form_urlencoded(&body)?.build()?; let result = client.client.execute(request).await; let response = result?; match response.status().as_u16() { - 201u16 => ResponseValue::from_response(response).await, - 400u16..=499u16 => Err(Error::ErrorResponse( - ResponseValue::from_response(response).await?, - )), - 500u16..=599u16 => Err(Error::ErrorResponse( - ResponseValue::from_response(response).await?, - )), - _ => Err(Error::UnexpectedResponse(response)), + 200..=299 => Ok(ResponseValue::stream(response)), + _ => Err(Error::ErrorResponse(ResponseValue::stream(response))), } } } - /// Builder for [`Client::get_api_user_token`] + /// Builder for [`Client::list_oauth_clients`] /// - /// [`Client::get_api_user_token`]: super::Client::get_api_user_token + /// [`Client::list_oauth_clients`]: super::Client::list_oauth_clients #[derive(Debug, Clone)] - pub struct GetApiUserToken<'a> { + pub struct ListOauthClients<'a> { client: &'a super::Client, - identifier: Result, - token_identifier: Result, } - impl<'a> GetApiUserToken<'a> { + impl<'a> ListOauthClients<'a> { pub fn new(client: &'a super::Client) -> Self { - Self { - client, - identifier: Err("identifier was not initialized".to_string()), - token_identifier: Err("token_identifier was not initialized".to_string()), - } - } - - pub fn identifier(mut self, value: V) -> Self - where - V: std::convert::TryInto, - { - self.identifier = value - .try_into() - .map_err(|_| "conversion to `uuid :: Uuid` for identifier failed".to_string()); - self - } - - pub fn token_identifier(mut self, value: V) -> Self - where - V: std::convert::TryInto, - { - self.token_identifier = value.try_into().map_err(|_| { - "conversion to `uuid :: Uuid` for token_identifier failed".to_string() - }); - self + Self { client } } - - /// Sends a `GET` request to - /// `/api-user/{identifier}/token/{token_identifier}` + + /// Sends a `GET` request to `/oauth/client` pub async fn send( self, - ) -> Result, Error> { - let Self { - client, - identifier, - token_identifier, - } = self; - let identifier = identifier.map_err(Error::InvalidRequest)?; - let token_identifier = token_identifier.map_err(Error::InvalidRequest)?; - let url = format!( - "{}/api-user/{}/token/{}", - client.baseurl, - encode_path(&identifier.to_string()), - encode_path(&token_identifier.to_string()), - ); + ) -> Result>, Error> { + let Self { client } = self; + let url = format!("{}/oauth/client", client.baseurl,); let request = client .client .get(url) @@ -2938,66 +4197,26 @@ pub mod builder { } } - /// Builder for [`Client::delete_api_user_token`] + /// Builder for [`Client::create_oauth_client`] /// - /// [`Client::delete_api_user_token`]: super::Client::delete_api_user_token + /// [`Client::create_oauth_client`]: super::Client::create_oauth_client #[derive(Debug, Clone)] - pub struct DeleteApiUserToken<'a> { + pub struct CreateOauthClient<'a> { client: &'a super::Client, - identifier: Result, - token_identifier: Result, } - impl<'a> DeleteApiUserToken<'a> { + impl<'a> CreateOauthClient<'a> { pub fn new(client: &'a super::Client) -> Self { - Self { - client, - identifier: Err("identifier was not initialized".to_string()), - token_identifier: Err("token_identifier was not initialized".to_string()), - } - } - - pub fn identifier(mut self, value: V) -> Self - where - V: std::convert::TryInto, - { - self.identifier = value - .try_into() - .map_err(|_| "conversion to `uuid :: Uuid` for identifier failed".to_string()); - self - } - - pub fn token_identifier(mut self, value: V) -> Self - where - V: std::convert::TryInto, - { - self.token_identifier = value.try_into().map_err(|_| { - "conversion to `uuid :: Uuid` for token_identifier failed".to_string() - }); - self + Self { client } } - /// Sends a `DELETE` request to - /// `/api-user/{identifier}/token/{token_identifier}` - pub async fn send( - self, - ) -> Result, Error> { - let Self { - client, - identifier, - token_identifier, - } = self; - let identifier = identifier.map_err(Error::InvalidRequest)?; - let token_identifier = token_identifier.map_err(Error::InvalidRequest)?; - let url = format!( - "{}/api-user/{}/token/{}", - client.baseurl, - encode_path(&identifier.to_string()), - encode_path(&token_identifier.to_string()), - ); + /// Sends a `POST` request to `/oauth/client` + pub async fn send(self) -> Result, Error> { + let Self { client } = self; + let url = format!("{}/oauth/client", client.baseurl,); let request = client .client - .delete(url) + .post(url) .header( reqwest::header::ACCEPT, reqwest::header::HeaderValue::from_static("application/json"), @@ -3018,64 +4237,54 @@ pub mod builder { } } - /// Builder for [`ClientHiddenExt::github_webhook`] + /// Builder for [`Client::get_oauth_client`] /// - /// [`ClientHiddenExt::github_webhook`]: super::ClientHiddenExt::github_webhook + /// [`Client::get_oauth_client`]: super::Client::get_oauth_client #[derive(Debug, Clone)] - pub struct GithubWebhook<'a> { + pub struct GetOauthClient<'a> { client: &'a super::Client, - body: Result, + client_id: Result, } - impl<'a> GithubWebhook<'a> { + impl<'a> GetOauthClient<'a> { pub fn new(client: &'a super::Client) -> Self { Self { client, - body: Ok(types::builder::GitHubCommitPayload::default()), + client_id: Err("client_id was not initialized".to_string()), } } - pub fn body(mut self, value: V) -> Self + pub fn client_id(mut self, value: V) -> Self where - V: std::convert::TryInto, + V: std::convert::TryInto, { - self.body = value + self.client_id = value .try_into() - .map(From::from) - .map_err(|_| "conversion to `GitHubCommitPayload` for body failed".to_string()); - self - } - - pub fn body_map(mut self, f: F) -> Self - where - F: std::ops::FnOnce( - types::builder::GitHubCommitPayload, - ) -> types::builder::GitHubCommitPayload, - { - self.body = self.body.map(f); + .map_err(|_| "conversion to `uuid :: Uuid` for client_id failed".to_string()); self } - /// Sends a `POST` request to `/github` - pub async fn send(self) -> Result, Error> { - let Self { client, body } = self; - let body = body - .and_then(std::convert::TryInto::::try_into) - .map_err(Error::InvalidRequest)?; - let url = format!("{}/github", client.baseurl,); + /// Sends a `GET` request to `/oauth/client/{client_id}` + pub async fn send(self) -> Result, Error> { + let Self { client, client_id } = self; + let client_id = client_id.map_err(Error::InvalidRequest)?; + let url = format!( + "{}/oauth/client/{}", + client.baseurl, + encode_path(&client_id.to_string()), + ); let request = client .client - .post(url) + .get(url) .header( reqwest::header::ACCEPT, reqwest::header::HeaderValue::from_static("application/json"), ) - .json(&body) .build()?; let result = client.client.execute(request).await; let response = result?; match response.status().as_u16() { - 202u16 => ResponseValue::from_response(response).await, + 200u16 => ResponseValue::from_response(response).await, 400u16..=499u16 => Err(Error::ErrorResponse( ResponseValue::from_response(response).await?, )), @@ -3087,41 +4296,41 @@ pub mod builder { } } - /// Builder for [`Client::access_token_login`] + /// Builder for [`Client::create_oauth_client_redirect_uri`] /// - /// [`Client::access_token_login`]: super::Client::access_token_login + /// [`Client::create_oauth_client_redirect_uri`]: super::Client::create_oauth_client_redirect_uri #[derive(Debug, Clone)] - pub struct AccessTokenLogin<'a> { + pub struct CreateOauthClientRedirectUri<'a> { client: &'a super::Client, - provider: Result, - body: Result, + client_id: Result, + body: Result, } - impl<'a> AccessTokenLogin<'a> { + impl<'a> CreateOauthClientRedirectUri<'a> { pub fn new(client: &'a super::Client) -> Self { Self { client, - provider: Err("provider was not initialized".to_string()), - body: Ok(types::builder::AccessTokenProviderLogin::default()), + client_id: Err("client_id was not initialized".to_string()), + body: Ok(types::builder::AddOAuthClientRedirectBody::default()), } } - pub fn provider(mut self, value: V) -> Self + pub fn client_id(mut self, value: V) -> Self where - V: std::convert::TryInto, + V: std::convert::TryInto, { - self.provider = value.try_into().map_err(|_| { - "conversion to `AccessTokenProviderName` for provider failed".to_string() - }); + self.client_id = value + .try_into() + .map_err(|_| "conversion to `uuid :: Uuid` for client_id failed".to_string()); self } pub fn body(mut self, value: V) -> Self where - V: std::convert::TryInto, + V: std::convert::TryInto, { self.body = value.try_into().map(From::from).map_err(|_| { - "conversion to `AccessTokenProviderLogin` for body failed".to_string() + "conversion to `AddOAuthClientRedirectBody` for body failed".to_string() }); self } @@ -3129,30 +4338,30 @@ pub mod builder { pub fn body_map(mut self, f: F) -> Self where F: std::ops::FnOnce( - types::builder::AccessTokenProviderLogin, - ) -> types::builder::AccessTokenProviderLogin, + types::builder::AddOAuthClientRedirectBody, + ) -> types::builder::AddOAuthClientRedirectBody, { self.body = self.body.map(f); self } - /// Sends a `POST` request to `/login/access-token/{provider}` + /// Sends a `POST` request to `/oauth/client/{client_id}/redirect_uri` pub async fn send( self, - ) -> Result, Error> { + ) -> Result, Error> { let Self { client, - provider, + client_id, body, } = self; - let provider = provider.map_err(Error::InvalidRequest)?; + let client_id = client_id.map_err(Error::InvalidRequest)?; let body = body - .and_then(std::convert::TryInto::::try_into) + .and_then(std::convert::TryInto::::try_into) .map_err(Error::InvalidRequest)?; let url = format!( - "{}/login/access-token/{}", + "{}/oauth/client/{}/redirect_uri", client.baseurl, - encode_path(&provider.to_string()), + encode_path(&client_id.to_string()), ); let request = client .client @@ -3166,7 +4375,7 @@ pub mod builder { let result = client.client.execute(request).await; let response = result?; match response.status().as_u16() { - 201u16 => ResponseValue::from_response(response).await, + 200u16 => ResponseValue::from_response(response).await, 400u16..=499u16 => Err(Error::ErrorResponse( ResponseValue::from_response(response).await?, )), @@ -3178,87 +4387,75 @@ pub mod builder { } } - /// Builder for [`Client::jwt_login`] + /// Builder for [`Client::delete_oauth_client_redirect_uri`] /// - /// [`Client::jwt_login`]: super::Client::jwt_login + /// [`Client::delete_oauth_client_redirect_uri`]: super::Client::delete_oauth_client_redirect_uri #[derive(Debug, Clone)] - pub struct JwtLogin<'a> { + pub struct DeleteOauthClientRedirectUri<'a> { client: &'a super::Client, - provider: Result, - body: Result, + client_id: Result, + redirect_uri_id: Result, } - impl<'a> JwtLogin<'a> { + impl<'a> DeleteOauthClientRedirectUri<'a> { pub fn new(client: &'a super::Client) -> Self { Self { client, - provider: Err("provider was not initialized".to_string()), - body: Ok(types::builder::JwtProviderLogin::default()), + client_id: Err("client_id was not initialized".to_string()), + redirect_uri_id: Err("redirect_uri_id was not initialized".to_string()), } } - pub fn provider(mut self, value: V) -> Self + pub fn client_id(mut self, value: V) -> Self where - V: std::convert::TryInto, + V: std::convert::TryInto, { - self.provider = value + self.client_id = value .try_into() - .map_err(|_| "conversion to `JwtProviderName` for provider failed".to_string()); + .map_err(|_| "conversion to `uuid :: Uuid` for client_id failed".to_string()); self } - pub fn body(mut self, value: V) -> Self + pub fn redirect_uri_id(mut self, value: V) -> Self where - V: std::convert::TryInto, + V: std::convert::TryInto, { - self.body = value + self.redirect_uri_id = value .try_into() - .map(From::from) - .map_err(|_| "conversion to `JwtProviderLogin` for body failed".to_string()); - self - } - - pub fn body_map(mut self, f: F) -> Self - where - F: std::ops::FnOnce( - types::builder::JwtProviderLogin, - ) -> types::builder::JwtProviderLogin, - { - self.body = self.body.map(f); + .map_err(|_| "conversion to `uuid :: Uuid` for redirect_uri_id failed".to_string()); self } - /// Sends a `POST` request to `/login/jwt/{provider}` + /// Sends a `DELETE` request to + /// `/oauth/client/{client_id}/redirect_uri/{redirect_uri_id}` pub async fn send( self, - ) -> Result, Error> { + ) -> Result, Error> { let Self { client, - provider, - body, + client_id, + redirect_uri_id, } = self; - let provider = provider.map_err(Error::InvalidRequest)?; - let body = body - .and_then(std::convert::TryInto::::try_into) - .map_err(Error::InvalidRequest)?; + let client_id = client_id.map_err(Error::InvalidRequest)?; + let redirect_uri_id = redirect_uri_id.map_err(Error::InvalidRequest)?; let url = format!( - "{}/login/jwt/{}", + "{}/oauth/client/{}/redirect_uri/{}", client.baseurl, - encode_path(&provider.to_string()), + encode_path(&client_id.to_string()), + encode_path(&redirect_uri_id.to_string()), ); let request = client .client - .post(url) + .delete(url) .header( reqwest::header::ACCEPT, reqwest::header::HeaderValue::from_static("application/json"), ) - .json(&body) .build()?; let result = client.client.execute(request).await; let response = result?; match response.status().as_u16() { - 201u16 => ResponseValue::from_response(response).await, + 200u16 => ResponseValue::from_response(response).await, 400u16..=499u16 => Err(Error::ErrorResponse( ResponseValue::from_response(response).await?, )), @@ -3270,47 +4467,47 @@ pub mod builder { } } - /// Builder for [`Client::get_device_provider`] + /// Builder for [`Client::create_oauth_client_secret`] /// - /// [`Client::get_device_provider`]: super::Client::get_device_provider + /// [`Client::create_oauth_client_secret`]: super::Client::create_oauth_client_secret #[derive(Debug, Clone)] - pub struct GetDeviceProvider<'a> { + pub struct CreateOauthClientSecret<'a> { client: &'a super::Client, - provider: Result, + client_id: Result, } - impl<'a> GetDeviceProvider<'a> { + impl<'a> CreateOauthClientSecret<'a> { pub fn new(client: &'a super::Client) -> Self { Self { client, - provider: Err("provider was not initialized".to_string()), + client_id: Err("client_id was not initialized".to_string()), } } - pub fn provider(mut self, value: V) -> Self + pub fn client_id(mut self, value: V) -> Self where - V: std::convert::TryInto, + V: std::convert::TryInto, { - self.provider = value + self.client_id = value .try_into() - .map_err(|_| "conversion to `OAuthProviderName` for provider failed".to_string()); + .map_err(|_| "conversion to `uuid :: Uuid` for client_id failed".to_string()); self } - /// Sends a `GET` request to `/login/oauth/{provider}/device` + /// Sends a `POST` request to `/oauth/client/{client_id}/secret` pub async fn send( self, - ) -> Result, Error> { - let Self { client, provider } = self; - let provider = provider.map_err(Error::InvalidRequest)?; + ) -> Result, Error> { + let Self { client, client_id } = self; + let client_id = client_id.map_err(Error::InvalidRequest)?; let url = format!( - "{}/login/oauth/{}/device", + "{}/oauth/client/{}/secret", client.baseurl, - encode_path(&provider.to_string()), + encode_path(&client_id.to_string()), ); let request = client .client - .get(url) + .post(url) .header( reqwest::header::ACCEPT, reqwest::header::HeaderValue::from_static("application/json"), @@ -3331,77 +4528,122 @@ pub mod builder { } } - /// Builder for [`Client::exchange_device_token`] + /// Builder for [`Client::delete_oauth_client_secret`] /// - /// [`Client::exchange_device_token`]: super::Client::exchange_device_token + /// [`Client::delete_oauth_client_secret`]: super::Client::delete_oauth_client_secret #[derive(Debug, Clone)] - pub struct ExchangeDeviceToken<'a> { + pub struct DeleteOauthClientSecret<'a> { client: &'a super::Client, - provider: Result, - body: Result, + client_id: Result, + secret_id: Result, } - impl<'a> ExchangeDeviceToken<'a> { + impl<'a> DeleteOauthClientSecret<'a> { pub fn new(client: &'a super::Client) -> Self { Self { client, - provider: Err("provider was not initialized".to_string()), - body: Ok(types::builder::AccessTokenExchangeRequest::default()), + client_id: Err("client_id was not initialized".to_string()), + secret_id: Err("secret_id was not initialized".to_string()), } } - pub fn provider(mut self, value: V) -> Self + pub fn client_id(mut self, value: V) -> Self where - V: std::convert::TryInto, + V: std::convert::TryInto, { - self.provider = value + self.client_id = value .try_into() - .map_err(|_| "conversion to `OAuthProviderName` for provider failed".to_string()); - self - } - - pub fn body(mut self, value: V) -> Self - where - V: std::convert::TryInto, - { - self.body = value.try_into().map(From::from).map_err(|_| { - "conversion to `AccessTokenExchangeRequest` for body failed".to_string() - }); + .map_err(|_| "conversion to `uuid :: Uuid` for client_id failed".to_string()); self } - pub fn body_map(mut self, f: F) -> Self + pub fn secret_id(mut self, value: V) -> Self where - F: std::ops::FnOnce( - types::builder::AccessTokenExchangeRequest, - ) -> types::builder::AccessTokenExchangeRequest, + V: std::convert::TryInto, { - self.body = self.body.map(f); + self.secret_id = value + .try_into() + .map_err(|_| "conversion to `uuid :: Uuid` for secret_id failed".to_string()); self } - /// Sends a `POST` request to `/login/oauth/{provider}/device/exchange` - pub async fn send(self) -> Result, Error> { + /// Sends a `DELETE` request to + /// `/oauth/client/{client_id}/secret/{secret_id}` + pub async fn send( + self, + ) -> Result, Error> { let Self { client, - provider, - body, + client_id, + secret_id, } = self; - let provider = provider.map_err(Error::InvalidRequest)?; - let body = body - .and_then(std::convert::TryInto::::try_into) - .map_err(Error::InvalidRequest)?; + let client_id = client_id.map_err(Error::InvalidRequest)?; + let secret_id = secret_id.map_err(Error::InvalidRequest)?; let url = format!( - "{}/login/oauth/{}/device/exchange", + "{}/oauth/client/{}/secret/{}", client.baseurl, - encode_path(&provider.to_string()), + encode_path(&client_id.to_string()), + encode_path(&secret_id.to_string()), ); - let request = client.client.post(url).form_urlencoded(&body)?.build()?; + let request = client + .client + .delete(url) + .header( + reqwest::header::ACCEPT, + reqwest::header::HeaderValue::from_static("application/json"), + ) + .build()?; let result = client.client.execute(request).await; let response = result?; match response.status().as_u16() { - 200..=299 => Ok(ResponseValue::stream(response)), - _ => Err(Error::ErrorResponse(ResponseValue::stream(response))), + 200u16 => ResponseValue::from_response(response).await, + 400u16..=499u16 => Err(Error::ErrorResponse( + ResponseValue::from_response(response).await?, + )), + 500u16..=599u16 => Err(Error::ErrorResponse( + ResponseValue::from_response(response).await?, + )), + _ => Err(Error::UnexpectedResponse(response)), + } + } + } + + /// Builder for [`Client::get_rfds`] + /// + /// [`Client::get_rfds`]: super::Client::get_rfds + #[derive(Debug, Clone)] + pub struct GetRfds<'a> { + client: &'a super::Client, + } + + impl<'a> GetRfds<'a> { + pub fn new(client: &'a super::Client) -> Self { + Self { client } + } + + /// Sends a `GET` request to `/rfd` + pub async fn send(self) -> Result>, Error> { + let Self { client } = self; + let url = format!("{}/rfd", client.baseurl,); + let request = client + .client + .get(url) + .header( + reqwest::header::ACCEPT, + reqwest::header::HeaderValue::from_static("application/json"), + ) + .build()?; + let result = client.client.execute(request).await; + let response = result?; + match response.status().as_u16() { + 200u16 => ResponseValue::from_response(response).await, + 400u16..=499u16 => Err(Error::ErrorResponse( + ResponseValue::from_response(response).await?, + )), + 500u16..=599u16 => Err(Error::ErrorResponse( + ResponseValue::from_response(response).await?, + )), + _ => Err(Error::UnexpectedResponse(response)), } } }