1use serde::{Deserialize, Serialize};
16
17use crate::client::{get_owner, Client, PostBody, Response};
18use crate::error::{CasdoorError, Result};
19
20#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
23#[serde(rename_all = "camelCase", default)]
24pub struct Transaction {
25 pub owner: String,
26 pub name: String,
27 pub created_time: String,
28 pub display_name: String,
29
30 pub application: String,
31 pub domain: String,
32 pub category: String,
33 pub r#type: String,
34 pub subtype: String,
35 pub provider: String,
36 pub user: String,
37 pub tag: String,
38
39 pub amount: f64,
40 pub currency: String,
41
42 pub payment: String,
43
44 pub state: String,
45}
46
47impl Client {
48 pub async fn get_transactions(&self) -> Result<Vec<Transaction>> {
50 self.get_list(
51 "get-transactions",
52 &[("owner", &self.config.organization_name)],
53 )
54 .await
55 }
56
57 pub async fn get_pagination_transactions(
60 &self,
61 p: i32,
62 page_size: i32,
63 query: &[(&str, &str)],
64 ) -> Result<(Vec<Transaction>, i32)> {
65 self.get_pagination(
66 "get-transactions",
67 &self.config.organization_name,
68 p,
69 page_size,
70 query,
71 )
72 .await
73 }
74
75 pub async fn get_transaction(&self, name: &str) -> Result<Option<Transaction>> {
77 self.get_object("get-transaction", &[("id", &self.get_id(name))])
78 .await
79 }
80
81 pub async fn get_user_transactions(&self, user_name: &str) -> Result<Vec<Transaction>> {
83 self.get_list(
86 "get-transactions",
87 &[
88 ("owner", &self.config.organization_name),
89 ("field", "user"),
90 ("value", user_name),
91 ],
92 )
93 .await
94 }
95
96 pub async fn add_transaction(&self, transaction: &Transaction) -> Result<(bool, String)> {
98 self.add_transaction_with_dry_run(transaction, false).await
99 }
100
101 pub async fn add_transaction_with_dry_run(
103 &self,
104 transaction: &Transaction,
105 dry_run: bool,
106 ) -> Result<(bool, String)> {
107 let (response, affected) = self
108 .modify_transaction_with_dry_run("add-transaction", transaction, &[], dry_run)
109 .await?;
110
111 let transaction_id = response
112 .data
113 .as_str()
114 .ok_or(CasdoorError::Casdoor(
115 "failed to parse transaction id from response".to_string(),
116 ))?
117 .to_string();
118
119 Ok((affected, transaction_id))
120 }
121
122 pub async fn update_transaction(&self, transaction: &Transaction) -> Result<bool> {
124 Ok(self
125 .modify_transaction("update-transaction", transaction, &[])
126 .await?
127 .1)
128 }
129
130 pub async fn delete_transaction(&self, transaction: &Transaction) -> Result<bool> {
132 Ok(self
133 .modify_transaction("delete-transaction", transaction, &[])
134 .await?
135 .1)
136 }
137
138 async fn modify_transaction(
139 &self,
140 action: &str,
141 transaction: &Transaction,
142 columns: &[&str],
143 ) -> Result<(Response, bool)> {
144 self.modify_transaction_with_dry_run(action, transaction, columns, false)
145 .await
146 }
147
148 async fn modify_transaction_with_dry_run(
150 &self,
151 action: &str,
152 transaction: &Transaction,
153 columns: &[&str],
154 dry_run: bool,
155 ) -> Result<(Response, bool)> {
156 let mut transaction = transaction.clone();
157 transaction.owner = get_owner(&transaction.owner, &self.config.organization_name);
158
159 let id = format!("{}/{}", transaction.owner, transaction.name);
160 let columns = columns.join(",");
161
162 let mut query = vec![("id", id.as_str())];
163 if !columns.is_empty() {
164 query.push(("columns", columns.as_str()));
165 }
166 if dry_run && action == "add-transaction" {
167 query.push(("dryRun", "1"));
168 }
169
170 let post_bytes = serde_json::to_vec(&transaction)?;
171 let response = self
172 .do_post(action, &query, PostBody::Raw(post_bytes))
173 .await?;
174
175 let affected = response.data.as_str() == Some("Affected");
176 Ok((response, affected))
177 }
178}