pageseeder_api/
services.rs

1use std::collections::HashMap;
2
3use quick_xml::de;
4use reqwest::Response;
5use serde::de::DeserializeOwned;
6
7use crate::model::{LoadClear, PSError, PSResult, SearchResponse, VersionCreation};
8
9use super::{
10    model::{
11        DocumentFragment, Error, EventType, FragmentCreation, Group, LoadStart, LoadUnzip,
12        SearchResultPage, Service, Thread, Upload, Uri, UriHistory,
13    },
14    PSServer,
15};
16
17impl PSServer {
18    async fn handle_http<T: DeserializeOwned>(&self, op: &str, resp: Response) -> PSResult<T> {
19        if !(200..300).contains(&resp.status().as_u16()) {
20            let err: Error = de::from_str(&resp.text().await?)?;
21            Err(PSError::ApiError {
22                id: err.id,
23                req: op.to_string(),
24                msg: err.message,
25            })
26        } else {
27            Ok(de::from_str(&resp.text().await?)?)
28        }
29    }
30
31    /// Gets a group from the server.
32    pub async fn get_group(&self, name: &str) -> PSResult<Group> {
33        let resp = self
34            .checked_get(Service::GetGroup { group: name }, None, None)
35            .await?;
36
37        self.handle_http("get group", resp).await
38    }
39
40    /// Gets info about a single URI.
41    pub async fn get_uri(&self, member: &str, uri: &str) -> PSResult<Uri> {
42        let resp = self
43            .checked_get(Service::GetUri { member, uri }, None, None)
44            .await?;
45
46        self.handle_http("get uri", resp).await
47    }
48
49    /// Gets the history of a single URI.
50    pub async fn get_uri_history(&self, group: &str, uri: &str) -> PSResult<UriHistory> {
51        let resp = self
52            .checked_get(Service::GetUriHistory { group, uri }, None, None)
53            .await?;
54
55        self.handle_http("get uri history", resp).await
56    }
57
58    /// Gets the history of all URIs in a group.
59    /// TODO add auto pagination
60    pub async fn get_uris_history(
61        &self,
62        group: &str,
63        events: Vec<EventType>,
64        mut params: HashMap<&str, &str>,
65    ) -> PSResult<UriHistory> {
66        let events = events
67            .into_iter()
68            .map(|e| e.into())
69            .collect::<Vec<String>>()
70            .join(",");
71        params.insert("events", &events);
72
73        let resp = self
74            .checked_get(
75                Service::GetUrisHistory { group },
76                Some(params.into_iter().collect()),
77                None,
78            )
79            .await?;
80
81        self.handle_http("get uris history", resp).await
82    }
83
84    pub async fn get_uri_fragment(
85        &self,
86        member: &str,
87        group: &str,
88        uri: &str,
89        fragment: &str,
90        params: HashMap<&str, &str>,
91    ) -> PSResult<DocumentFragment> {
92        let resp = self
93            .checked_get(
94                Service::GetUriFragment {
95                    member,
96                    group,
97                    uri,
98                    fragment,
99                },
100                Some(params.into_iter().collect()),
101                None,
102            )
103            .await?;
104
105        self.handle_http("get uri fragment", resp).await
106    }
107
108    /// Returns the pageseeder thread that is exporting the URI(s).
109    pub async fn uri_export(
110        &self,
111        member: &str,
112        uri: &str,
113        params: Vec<(&str, &str)>,
114        // TODO find better solution for parameters (struct impl Default?)
115    ) -> PSResult<Thread> {
116        let resp = self
117            .checked_get(Service::UriExport { member, uri }, Some(params), None)
118            .await?;
119
120        self.handle_http("uri export", resp).await
121    }
122
123    /// Searches a group.
124    /// Fetches all pages for a search if no page number is specified in params.
125    /// This may result in multiple requests.
126    pub async fn group_search(
127        &self,
128        group: &str,
129        params: HashMap<&str, &str>,
130    ) -> PSResult<Vec<SearchResultPage>> {
131        let param_vec: Vec<(&str, &str)> = params.iter().map(|t| (*t.0, *t.1)).collect();
132
133        let service = Service::GroupSearch { group };
134        let resp = self
135            .checked_get(service.clone(), Some(param_vec), None)
136            .await?;
137
138        let results = self
139            .handle_http::<SearchResponse>("group search", resp)
140            .await?
141            .results;
142
143        let mut pages = vec![];
144        // Fetches all pages if pagenum not specified.
145        if !params.contains_key("page") {
146            for page in 2..=results.total_pages {
147                let page = page.to_string();
148                let mut params = params.clone();
149
150                params.insert("page", &page);
151                let resp = self
152                    .checked_get(
153                        service.clone(),
154                        Some(params.iter().map(|t| (*t.0, *t.1)).collect()),
155                        None,
156                    )
157                    .await?;
158                pages.push(de::from_str(&resp.text().await?)?);
159            }
160        }
161
162        pages.insert(0, results);
163        Ok(pages)
164    }
165
166    /// Gets the progress of a pageseeder thread.
167    pub async fn thread_progress(&self, thread_id: &str) -> PSResult<Thread> {
168        let resp = self
169            .checked_get(Service::ThreadProgress { id: thread_id }, None, None)
170            .await?;
171
172        self.handle_http("get thread progress", resp).await
173    }
174
175    pub async fn put_uri_fragment(
176        &self,
177        member: &str,
178        group: &str,
179        uri: &str,
180        fragment: &str,
181        content: String,
182        params: Option<Vec<(&str, &str)>>,
183    ) -> PSResult<FragmentCreation> {
184        let resp = self
185            .checked_put(
186                Service::PutUriFragment {
187                    member,
188                    group,
189                    uri,
190                    fragment,
191                },
192                params,
193                None,
194                Some(content),
195            )
196            .await?;
197
198        self.handle_http("put uri fragment", resp).await
199    }
200
201    pub async fn add_uri_fragment(
202        &self,
203        member: &str,
204        group: &str,
205        uri: &str,
206        content: &str,
207        mut params: HashMap<&str, &str>,
208    ) -> PSResult<FragmentCreation> {
209        params.insert("content", content);
210
211        let resp = self
212            .checked_post(
213                Service::AddUriFragment { member, group, uri },
214                Some(params.into_iter().collect()),
215                None,
216                Option::<&[u8]>::None,
217            )
218            .await?;
219
220        self.handle_http("add uri fragment", resp).await
221    }
222
223    pub async fn upload(
224        &self,
225        group: &str,
226        filename: &str,
227        file: Vec<u8>,
228        mut params: HashMap<&str, &str>,
229    ) -> PSResult<Upload> {
230        params.insert("group", group);
231        params.insert("filename", filename);
232
233        let resp = self
234            .checked_put(
235                Service::Upload,
236                Some(params.into_iter().collect()),
237                None,
238                Some(file),
239            )
240            .await?;
241
242        self.handle_http("upload", resp).await
243    }
244
245    pub async fn clear_loading_zone(&self, member: &str, group: &str) -> PSResult<LoadClear> {
246        let resp = self
247            .checked_post(
248                Service::ClearLoadingZone { member, group },
249                None,
250                None,
251                Option::<&[u8]>::None,
252            )
253            .await?;
254
255        self.handle_http("clear loading zone", resp).await
256    }
257
258    pub async fn unzip_loading_zone(
259        &self,
260        member: &str,
261        group: &str,
262        path: &str,
263        mut params: HashMap<&str, &str>,
264    ) -> PSResult<LoadUnzip> {
265        params.insert("path", path);
266
267        let resp = self
268            .checked_post(
269                Service::UnzipLoadingZone { member, group },
270                Some(params.into_iter().collect()),
271                None,
272                Option::<&[u8]>::None,
273            )
274            .await?;
275
276        self.handle_http("unzip loading zone content", resp).await
277    }
278
279    pub async fn start_loading(
280        &self,
281        member: &str,
282        group: &str,
283        params: HashMap<&str, &str>,
284    ) -> PSResult<LoadStart> {
285        let resp = self
286            .checked_post(
287                Service::StartLoading { member, group },
288                Some(params.into_iter().collect()),
289                None,
290                Option::<&[u8]>::None,
291            )
292            .await?;
293
294        self.handle_http("start loading the loading zone content", resp)
295            .await
296    }
297
298    /// Downloads a member resource like the result of an export thread.
299    pub async fn download_member_resource(&self, group: &str, filename: &str) -> PSResult<Vec<u8>> {
300        let resp = self
301            .checked_get(Service::DownloadMemberResource { group, filename }, None, None)
302            .await?;
303
304        Ok(resp.bytes().await?.to_vec())
305    }
306
307    /// Creates a version for a URI.
308    pub async fn create_uri_version(
309        &self,
310        member: &str,
311        group: &str,
312        uri: &str,
313        name: &str,
314        mut params: HashMap<&str, &str>,
315    ) -> PSResult<VersionCreation> {
316        params.insert("name", name);
317
318        let resp = self
319            .checked_post(
320                Service::CreateUriVersion { member, group, uri },
321                Some(params.into_iter().collect()),
322                None,
323                Option::<&[u8]>::None,
324            )
325            .await?;
326
327        self.handle_http("create version", resp).await
328    }
329}