Skip to main content

casdoor_rust_sdk/
application.rs

1// Copyright 2026 The Casdoor Authors. All Rights Reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//      http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use serde::{Deserialize, Serialize};
16
17use crate::cert::Cert;
18use crate::client::{get_admin_id, get_owner, Client, Response};
19use crate::error::Result;
20use crate::organization::{Organization, ThemeData};
21use crate::provider::Provider;
22use crate::serde_util::null_to_default;
23use crate::user::ScopeDescription;
24
25#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
26#[serde(rename_all = "camelCase", default)]
27pub struct ProviderItem {
28    pub owner: String,
29    pub name: String,
30
31    pub can_sign_up: bool,
32    pub can_sign_in: bool,
33    pub can_unlink: bool,
34    pub binding_rule: Option<Vec<String>>,
35    #[serde(deserialize_with = "null_to_default")]
36    pub country_codes: Vec<String>,
37    pub prompted: bool,
38    pub signup_group: String,
39    pub rule: String,
40    pub provider: Option<Provider>,
41}
42
43#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
44#[serde(rename_all = "camelCase", default)]
45pub struct ScopeItem {
46    pub name: String,
47    pub display_name: String,
48    pub description: String,
49    /// The MCP tools allowed by this scope.
50    #[serde(deserialize_with = "null_to_default")]
51    pub tools: Vec<String>,
52}
53
54#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
55#[serde(rename_all = "camelCase", default)]
56pub struct SignupItem {
57    pub name: String,
58    pub visible: bool,
59    pub required: bool,
60    pub prompted: bool,
61    pub r#type: String,
62    pub custom_css: String,
63    pub label: String,
64    pub placeholder: String,
65    #[serde(deserialize_with = "null_to_default")]
66    pub options: Vec<String>,
67    pub regex: String,
68    pub rule: String,
69}
70
71#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
72#[serde(rename_all = "camelCase", default)]
73pub struct SigninMethod {
74    pub name: String,
75    pub display_name: String,
76    pub rule: String,
77}
78
79#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
80#[serde(rename_all = "camelCase", default)]
81pub struct SigninItem {
82    pub name: String,
83    pub visible: bool,
84    pub label: String,
85    pub custom_css: String,
86    pub placeholder: String,
87    pub rule: String,
88    pub is_custom: bool,
89}
90
91#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
92#[serde(rename_all = "camelCase", default)]
93pub struct SamlItem {
94    pub name: String,
95    pub name_format: String,
96    pub value: String,
97}
98
99#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
100#[serde(rename_all = "camelCase", default)]
101pub struct JwtItem {
102    pub name: String,
103    pub category: String,
104    pub value: String,
105    pub r#type: String,
106}
107
108/// Application has the same definition as
109/// <https://github.com/casdoor/casdoor/blob/master/object/application.go>.
110#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
111#[serde(rename_all = "camelCase", default)]
112pub struct Application {
113    pub owner: String,
114    pub name: String,
115    pub created_time: String,
116
117    pub display_name: String,
118    pub category: String,
119    pub r#type: String,
120    #[serde(deserialize_with = "null_to_default")]
121    pub scopes: Vec<ScopeItem>,
122    pub logo: String,
123    pub title: String,
124    pub favicon: String,
125    pub order: i32,
126    pub homepage_url: String,
127    pub description: String,
128    pub organization: String,
129    pub cert: String,
130    pub default_group: String,
131    pub default_tag: String,
132    pub header_html: String,
133    pub page_html: String,
134    pub enable_password: bool,
135    pub enable_sign_up: bool,
136    pub enable_guest_signin: bool,
137    pub disable_signin: bool,
138    pub enable_signin_session: bool,
139    pub enable_auto_signin: bool,
140    pub enable_code_signin: bool,
141    pub enable_exclusive_signin: bool,
142    pub enable_saml_compress: bool,
143    pub enable_saml_c14n10: bool,
144    pub enable_saml_post_binding: bool,
145    pub disable_saml_attributes: bool,
146    pub enable_saml_assertion_signature: bool,
147    pub use_email_as_saml_name_id: bool,
148    pub enable_web_authn: bool,
149    pub enable_link_with_email: bool,
150    pub org_choice_mode: String,
151    pub saml_reply_url: String,
152    #[serde(deserialize_with = "null_to_default")]
153    pub providers: Vec<ProviderItem>,
154    #[serde(deserialize_with = "null_to_default")]
155    pub signin_methods: Vec<SigninMethod>,
156    #[serde(deserialize_with = "null_to_default")]
157    pub signup_items: Vec<SignupItem>,
158    #[serde(deserialize_with = "null_to_default")]
159    pub signin_items: Vec<SigninItem>,
160    #[serde(deserialize_with = "null_to_default")]
161    pub grant_types: Vec<String>,
162    pub organization_obj: Option<Organization>,
163    pub cert_public_key: String,
164    #[serde(deserialize_with = "null_to_default")]
165    pub tags: Vec<String>,
166    #[serde(deserialize_with = "null_to_default")]
167    pub saml_attributes: Vec<SamlItem>,
168    pub saml_hash_algorithm: String,
169    pub saml_c14n_prefix: String,
170    pub is_shared: bool,
171    pub ip_restriction: String,
172
173    pub client_id: String,
174    pub client_secret: String,
175    pub client_cert: String,
176    #[serde(deserialize_with = "null_to_default")]
177    pub redirect_uris: Vec<String>,
178    pub backchannel_logout_uri: String,
179    pub forced_redirect_origin: String,
180    pub token_format: String,
181    pub token_signing_method: String,
182    #[serde(deserialize_with = "null_to_default")]
183    pub token_fields: Vec<String>,
184    #[serde(deserialize_with = "null_to_default")]
185    pub token_attributes: Vec<JwtItem>,
186    pub expire_in_hours: f64,
187    pub refresh_expire_in_hours: f64,
188    pub cookie_expire_in_hours: i64,
189    pub signup_url: String,
190    pub signin_url: String,
191    pub forget_url: String,
192    pub affiliation_url: String,
193    pub ip_whitelist: String,
194    pub terms_of_use: String,
195    pub signup_html: String,
196    pub signin_html: String,
197    pub theme_data: Option<ThemeData>,
198    pub footer_html: String,
199    pub form_css: String,
200    pub form_css_mobile: String,
201    pub form_offset: i32,
202    pub form_side_html: String,
203    pub form_background_url: String,
204    pub form_background_url_mobile: String,
205
206    pub failed_signin_limit: i32,
207    pub failed_signin_frozen_time: i32,
208    pub code_resend_timeout: i32,
209
210    #[serde(deserialize_with = "null_to_default")]
211    pub custom_scopes: Vec<ScopeDescription>,
212
213    // Reverse proxy fields.
214    pub domain: String,
215    #[serde(deserialize_with = "null_to_default")]
216    pub other_domains: Vec<String>,
217    pub upstream_host: String,
218    pub ssl_mode: String,
219    pub ssl_cert: String,
220
221    #[serde(rename = "CertObj")]
222    pub cert_obj: Option<Cert>,
223
224    pub registration_access_token: String,
225}
226
227impl Client {
228    /// Get all the applications.
229    pub async fn get_applications(&self) -> Result<Vec<Application>> {
230        self.get_list("get-applications", &[("owner", "admin")])
231            .await
232    }
233
234    /// Get the applications of the client's organization.
235    pub async fn get_organization_applications(&self) -> Result<Vec<Application>> {
236        self.get_list(
237            "get-organization-applications",
238            &[
239                ("owner", "admin"),
240                ("organization", &self.config.organization_name),
241            ],
242        )
243        .await
244    }
245
246    /// Get one application by name.
247    pub async fn get_application(&self, name: &str) -> Result<Option<Application>> {
248        self.get_object("get-application", &[("id", &get_admin_id(name))])
249            .await
250    }
251
252    /// Add an application.
253    pub async fn add_application(&self, application: &Application) -> Result<bool> {
254        Ok(self
255            .modify_application("add-application", application, &[])
256            .await?
257            .1)
258    }
259
260    /// Update an application.
261    pub async fn update_application(&self, application: &Application) -> Result<bool> {
262        Ok(self
263            .modify_application("update-application", application, &[])
264            .await?
265            .1)
266    }
267
268    /// Delete an application.
269    pub async fn delete_application(&self, application: &Application) -> Result<bool> {
270        Ok(self
271            .modify_application("delete-application", application, &[])
272            .await?
273            .1)
274    }
275
276    async fn modify_application(
277        &self,
278        action: &str,
279        application: &Application,
280        columns: &[&str],
281    ) -> Result<(Response, bool)> {
282        let mut application = application.clone();
283        application.owner = get_owner(&application.owner, "admin");
284
285        let id = format!("{}/{}", application.owner, application.name);
286        self.modify_object(action, &id, &application, columns).await
287    }
288}