1use super::{PreparedSettingsUpdate, StorageSecret};
2use crate::client::{ClientError, WekanClient};
3use reqwest::{
4 Method,
5 header::{ACCEPT, CONTENT_TYPE},
6};
7use secrecy::{ExposeSecret, SecretString};
8use serde::{Deserialize, Serialize};
9
10pub const OAUTH_PROVIDER_KEYS: [&str; 7] = [
11 "google",
12 "github",
13 "facebook",
14 "twitter",
15 "meteor-developer",
16 "weibo",
17 "meetup",
18];
19
20#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
21#[serde(deny_unknown_fields)]
22pub struct ConfigSource<T> {
23 pub source: String,
24 pub value: Option<T>,
25}
26#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
27#[serde(untagged)]
28pub enum BooleanConfigValue {
29 Text(String),
30 Boolean(bool),
31}
32#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
33#[serde(
34 deny_unknown_fields,
35 rename_all(deserialize = "camelCase", serialize = "snake_case")
36)]
37pub struct SecretConfigSource {
38 pub source: String,
39 pub has_value: bool,
40}
41#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
42#[serde(deny_unknown_fields)]
43pub struct OauthProviderSource {
44 pub enabled: ConfigSource<BooleanConfigValue>,
45 pub id: ConfigSource<String>,
46 pub secret: SecretConfigSource,
47}
48#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
50#[serde(deny_unknown_fields)]
51pub struct OauthProviderSources {
52 pub google: OauthProviderSource,
53 pub github: OauthProviderSource,
54 pub facebook: OauthProviderSource,
55 pub twitter: OauthProviderSource,
56 #[serde(rename = "meteor-developer")]
57 pub meteor_developer: OauthProviderSource,
58 pub weibo: OauthProviderSource,
59 pub meetup: OauthProviderSource,
60}
61#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
62#[serde(
63 deny_unknown_fields,
64 rename_all(deserialize = "camelCase", serialize = "snake_case")
65)]
66pub struct OauthProviderSettings {
67 pub providers: OauthProviderSources,
68 pub login_style: ConfigSource<String>,
69 pub merge_existing_users: ConfigSource<BooleanConfigValue>,
70 pub allowed_email_domains: ConfigSource<String>,
71 pub passwordless: ConfigSource<BooleanConfigValue>,
72}
73#[derive(Clone, Debug, Serialize)]
74#[serde(rename_all = "camelCase")]
75pub struct UpdateOauthProviderRequest {
76 pub enabled: bool,
77 pub id: String,
78 #[serde(skip_serializing_if = "Option::is_none")]
79 pub secret: Option<StorageSecret>,
80 #[serde(skip_serializing_if = "Option::is_none")]
81 pub login_style: Option<String>,
82 #[serde(skip_serializing_if = "Option::is_none")]
83 pub global_login_style: Option<String>,
84 #[serde(skip_serializing_if = "Option::is_none")]
85 pub merge_existing_users: Option<bool>,
86}
87#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
88#[serde(deny_unknown_fields)]
89pub struct PasswordlessSettings {
90 pub passwordless: ConfigSource<BooleanConfigValue>,
91}
92#[derive(Serialize)]
93struct PasswordlessRequest {
94 enabled: bool,
95}
96
97impl WekanClient {
98 pub async fn oauth_provider_settings(
99 &self,
100 token: &SecretString,
101 ) -> Result<OauthProviderSettings, ClientError> {
102 self.admin_settings(
103 Method::GET,
104 "api/admin/oauth-providers",
105 None,
106 token,
107 "OAuth provider settings",
108 )
109 .await
110 }
111 pub async fn update_oauth_provider(
112 &self,
113 provider: &str,
114 request: PreparedSettingsUpdate<UpdateOauthProviderRequest>,
115 token: &SecretString,
116 ) -> Result<OauthProviderSettings, ClientError> {
117 let mut url = self
118 .server()
119 .join("api/admin/oauth-providers")
120 .map_err(|_| ClientError::Protocol {
121 message: "could not construct OAuth provider endpoint".into(),
122 diagnostic: None,
123 success_status_received: false,
124 })?;
125 url.path_segments_mut()
126 .expect("HTTP URL supports path segments")
127 .push(provider);
128 let body = self
129 .execute_success_request_with_limit(
130 self.http
131 .put(url)
132 .header(ACCEPT, "application/json")
133 .header(CONTENT_TYPE, "application/json")
134 .bearer_auth(token.expose_secret())
135 .body(request.body),
136 64 * 1024 * 1024,
137 )
138 .await?;
139 crate::client::transport::decode_success::<super::Object<OauthProviderSettings>>(
140 &body,
141 "OAuth provider settings update",
142 true,
143 )
144 .map(|value| value.0)
145 }
146 pub async fn update_passwordless_settings(
147 &self,
148 enabled: bool,
149 token: &SecretString,
150 ) -> Result<PasswordlessSettings, ClientError> {
151 let body = serde_json::to_vec(&PasswordlessRequest { enabled })
152 .expect("boolean request is serializable");
153 self.admin_settings(
154 Method::PUT,
155 "api/admin/passwordless",
156 Some(body),
157 token,
158 "passwordless settings update",
159 )
160 .await
161 }
162}