Skip to main content

casdoor_rust_sdk/
record.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::client::{Client, PostBody};
18use crate::error::Result;
19
20/// Record has the same definition as
21/// <https://github.com/casdoor/casdoor/blob/master/object/record.go>.
22#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
23#[serde(rename_all = "camelCase", default)]
24pub struct Record {
25    pub id: i32,
26
27    pub owner: String,
28    pub name: String,
29    pub created_time: String,
30
31    pub organization: String,
32    pub client_ip: String,
33    pub user: String,
34    pub method: String,
35    pub request_uri: String,
36    pub action: String,
37    pub language: String,
38
39    pub object: String,
40    pub response: String,
41    pub status_code: i32,
42
43    pub detail: String,
44
45    pub is_triggered: bool,
46}
47
48impl Client {
49    /// Get the records of the client's organization.
50    pub async fn get_records(&self) -> Result<Vec<Record>> {
51        self.get_list("get-records", &[("owner", &self.config.organization_name)])
52            .await
53    }
54
55    /// Get one page of the records of the client's organization, together with the total
56    /// number of the records.
57    pub async fn get_pagination_records(
58        &self,
59        p: i32,
60        page_size: i32,
61        query: &[(&str, &str)],
62    ) -> Result<(Vec<Record>, i32)> {
63        self.get_pagination(
64            "get-records",
65            &self.config.organization_name,
66            p,
67            page_size,
68            query,
69        )
70        .await
71    }
72
73    /// Get one record by name, `None` if it doesn't exist. Casdoor has no API to get a
74    /// single record, so it searches the records by name. Like the other APIs that read
75    /// records, it needs the access token of an admin user, see
76    /// [`Client::with_access_token()`].
77    pub async fn get_record(&self, name: &str) -> Result<Option<Record>> {
78        let name = name.rsplit('/').next().unwrap_or(name);
79
80        // The name filter matches the records whose names contain the given name.
81        let (records, _) = self
82            .get_pagination_records(1, 100, &[("field", "name"), ("value", name)])
83            .await?;
84
85        Ok(records.into_iter().find(|record| record.name == name))
86    }
87
88    /// Add a record.
89    pub async fn add_record(&self, record: &Record) -> Result<bool> {
90        let mut record = record.clone();
91        if record.owner.is_empty() {
92            record.owner = self.config.organization_name.clone();
93        }
94        if record.organization.is_empty() {
95            record.organization = self.config.organization_name.clone();
96        }
97
98        let post_bytes = serde_json::to_vec(&record)?;
99        let response = self
100            .do_post("add-record", &[], PostBody::Raw(post_bytes))
101            .await?;
102
103        Ok(response.data.as_str() == Some("Affected"))
104    }
105}