1use serde::{Deserialize, Serialize};
16
17use crate::client::{get_owner, Client, PostBody};
18use crate::error::{CasdoorError, Result};
19
20#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
23#[serde(rename_all = "camelCase", default)]
24pub struct Resource {
25 pub owner: String,
26 pub name: String,
27 pub created_time: String,
28
29 pub user: String,
30 pub provider: String,
31 pub application: String,
32 pub tag: String,
33 pub parent: String,
34 pub file_name: String,
35 pub file_type: String,
36 pub file_format: String,
37 pub file_size: i32,
38 pub url: String,
39 pub description: String,
40}
41
42impl Client {
43 pub async fn get_resource(&self, id: &str) -> Result<Option<Resource>> {
45 self.get_object(
46 "get-resource",
47 &[("owner", &self.config.organization_name), ("id", id)],
48 )
49 .await
50 }
51
52 pub async fn get_resource_ex(&self, owner: &str, name: &str) -> Result<Option<Resource>> {
54 self.get_resource(&format!("{owner}/{name}")).await
55 }
56
57 pub async fn get_resources(
59 &self,
60 owner: &str,
61 user: &str,
62 field: &str,
63 value: &str,
64 sort_field: &str,
65 sort_order: &str,
66 ) -> Result<Vec<Resource>> {
67 self.get_list(
68 "get-resources",
69 &[
70 ("owner", owner),
71 ("user", user),
72 ("field", field),
73 ("value", value),
74 ("sortField", sort_field),
75 ("sortOrder", sort_order),
76 ],
77 )
78 .await
79 }
80
81 #[allow(clippy::too_many_arguments)]
83 pub async fn get_pagination_resources(
84 &self,
85 owner: &str,
86 user: &str,
87 field: &str,
88 value: &str,
89 page_size: i32,
90 page: i32,
91 sort_field: &str,
92 sort_order: &str,
93 ) -> Result<Vec<Resource>> {
94 self.get_list(
95 "get-resources",
96 &[
97 ("owner", owner),
98 ("user", user),
99 ("field", field),
100 ("value", value),
101 ("p", &page.to_string()),
102 ("pageSize", &page_size.to_string()),
103 ("sortField", sort_field),
104 ("sortOrder", sort_order),
105 ],
106 )
107 .await
108 }
109
110 pub async fn upload_resource(
113 &self,
114 user: &str,
115 tag: &str,
116 parent: &str,
117 full_file_path: &str,
118 file_bytes: &[u8],
119 ) -> Result<(String, String)> {
120 self.do_upload_resource(
121 &[
122 ("owner", &self.config.organization_name),
123 ("user", user),
124 ("application", &self.config.application_name),
125 ("tag", tag),
126 ("parent", parent),
127 ("fullFilePath", full_file_path),
128 ],
129 file_bytes,
130 )
131 .await
132 }
133
134 #[allow(clippy::too_many_arguments)]
137 pub async fn upload_resource_ex(
138 &self,
139 user: &str,
140 tag: &str,
141 parent: &str,
142 full_file_path: &str,
143 file_bytes: &[u8],
144 created_time: &str,
145 description: &str,
146 ) -> Result<(String, String)> {
147 self.do_upload_resource(
148 &[
149 ("owner", &self.config.organization_name),
150 ("user", user),
151 ("application", &self.config.application_name),
152 ("tag", tag),
153 ("parent", parent),
154 ("fullFilePath", full_file_path),
155 ("createdTime", created_time),
156 ("description", description),
157 ],
158 file_bytes,
159 )
160 .await
161 }
162
163 pub async fn add_resource(&self, resource: &Resource) -> Result<bool> {
165 self.modify_resource("add-resource", resource).await
166 }
167
168 pub async fn update_resource(&self, resource: &Resource) -> Result<bool> {
170 self.modify_resource("update-resource", resource).await
171 }
172
173 async fn modify_resource(&self, action: &str, resource: &Resource) -> Result<bool> {
174 let mut resource = resource.clone();
175 resource.owner = get_owner(&resource.owner, &self.config.organization_name);
176
177 let id = format!("{}/{}", resource.owner, resource.name);
178 Ok(self.modify_object(action, &id, &resource, &[]).await?.1)
179 }
180
181 pub async fn delete_resource(&self, resource: &Resource) -> Result<bool> {
183 self.delete_resource_with_tag(resource, "").await
184 }
185
186 pub async fn delete_resource_with_tag(&self, resource: &Resource, tag: &str) -> Result<bool> {
188 let mut resource = resource.clone();
189 if resource.owner.is_empty() {
190 resource.owner = self.config.organization_name.clone();
191 }
192
193 let post_bytes = serde_json::to_vec(&resource)?;
194 let response = self
195 .do_post(
196 "delete-resource",
197 &[("tag", tag)],
198 PostBody::Raw(post_bytes),
199 )
200 .await?;
201
202 Ok(response.data.as_str() == Some("Affected"))
203 }
204
205 async fn do_upload_resource(
206 &self,
207 query: &[(&str, &str)],
208 file_bytes: &[u8],
209 ) -> Result<(String, String)> {
210 let response = self
211 .do_post("upload-resource", query, PostBody::File(file_bytes))
212 .await?;
213
214 let file_url = response
215 .data
216 .as_str()
217 .ok_or(CasdoorError::InvalidData)?
218 .to_string();
219 let name = response
220 .data2
221 .as_str()
222 .ok_or(CasdoorError::InvalidData)?
223 .to_string();
224
225 Ok((file_url, name))
226 }
227}