atlas_confluence/
lib.rs

1use base64::{engine::general_purpose, Engine};
2use reqwest::{
3    header::{HeaderMap, HeaderValue, AUTHORIZATION},
4    Client,
5};
6
7use log::{error, trace};
8
9use crate::models::{Page, PostPage, Space, SpaceContentResult, SpacesResult};
10
11pub mod models;
12
13pub struct Session {
14    base_url: String,
15    client: Client,
16}
17
18impl Session {
19    pub fn new(username: String, api_key: String, base_url: String) -> Session {
20        let auth_header_val = general_purpose::STANDARD.encode(format!("{}:{}", username, api_key));
21
22        let mut headers = HeaderMap::new();
23        headers.insert(
24            AUTHORIZATION,
25            HeaderValue::from_str(&format!("Basic {auth_header_val}")).unwrap(),
26        );
27
28        let client = reqwest::Client::builder()
29            .default_headers(headers)
30            .build()
31            .unwrap();
32
33        Session { base_url, client }
34    }
35
36    pub async fn get_page_by_id(&self, id: u64) -> Result<Page, ()> {
37        let url = format!("{}/rest/api/content/{}", self.base_url, id);
38        trace!("GET {}", url);
39        let response = self
40            .client
41            .get(url)
42            .query(&[("expand", "body.view,space,children.page,version")])
43            .send()
44            .await
45            .unwrap();
46        if response.status().is_client_error() || response.status().is_server_error() {
47            error!("Error getting page: {}", response.text().await.unwrap());
48            return Err(());
49        }
50        let page: Page = serde_json::from_str(&response.text().await.unwrap()).unwrap();
51        Ok(page)
52    }
53
54    pub async fn get_spaces(&self) -> Result<Vec<Space>, ()> {
55        let url = format!("{}/rest/api/space", self.base_url);
56        trace!("GET {}", url);
57        let response = self
58            .client
59            .get(url)
60            .query(&[("type", "global")])
61            .send()
62            .await
63            .unwrap();
64        if response.status().is_client_error() || response.status().is_server_error() {
65            error!("Error getting page: {}", response.text().await.unwrap());
66            return Err(());
67        }
68        let result: SpacesResult = serde_json::from_str(&response.text().await.unwrap()).unwrap();
69        Ok(result.results)
70    }
71
72    #[async_recursion::async_recursion]
73    pub async fn get_pages_for_space(
74        &self,
75        space_key: &str,
76        next: Option<String>,
77    ) -> Result<Vec<Page>, ()> {
78        let url = if next.is_some() {
79            format!("{}{}", self.base_url, next.unwrap().replace("/page", ""))
80        } else {
81            format!("{}/rest/api/space/{}/content", self.base_url, space_key)
82        };
83        trace!("GET {}", url);
84        let response = self
85            .client
86            .get(url)
87            .query(&[("expand", "body.view,space,children.page,version")])
88            .send()
89            .await
90            .unwrap();
91        if response.status().is_client_error() || response.status().is_server_error() {
92            error!("Error getting page: {}", response.text().await.unwrap());
93            return Err(());
94        }
95        let result: SpaceContentResult =
96            serde_json::from_str(&response.text().await.unwrap()).unwrap();
97        let mut pages = result.page.results;
98        if result.page.links.next.is_some() {
99            let mut next_pages = self
100                .get_pages_for_space(space_key, result.page.links.next)
101                .await
102                .unwrap();
103            pages.append(&mut next_pages);
104            return Ok(pages);
105        }
106        Ok(pages)
107    }
108
109    pub async fn add_new_page(
110        &self,
111        space_key: String,
112        ancestor: Option<u64>,
113        title: String,
114        body: Option<String>,
115    ) -> Result<Page, ()> {
116        let url = format!("{}/rest/api/content", self.base_url);
117        trace!("POST {}", url);
118        let response = self
119            .client
120            .post(url)
121            .query(&[("expand", "body.view,space,children.page,version")])
122            .json(&PostPage::new_new_page(title, ancestor, space_key, body))
123            .send()
124            .await
125            .unwrap();
126        if response.status().is_client_error() || response.status().is_server_error() {
127            error!("Error adding new page: {}", response.text().await.unwrap());
128            return Err(());
129        }
130        let page: Page = serde_json::from_str(&response.text().await.unwrap()).unwrap();
131        Ok(page)
132    }
133
134    pub async fn update_page(
135        &self,
136        space_key: String,
137        id: u64,
138        new_version: u64,
139        title: String,
140        body: Option<String>,
141    ) -> Result<Page, ()> {
142        let url = format!("{}/rest/api/content/{}", self.base_url, id);
143        trace!("PUT {}", url);
144        let response = self
145            .client
146            .put(url)
147            .query(&[("expand", "body.view,space,children.page,version")])
148            .json(&PostPage::new_update_page(
149                id,
150                title,
151                space_key,
152                body,
153                new_version,
154            ))
155            .send()
156            .await
157            .unwrap();
158        if response.status().is_client_error() || response.status().is_server_error() {
159            error!("Error updating page: {}", response.text().await.unwrap());
160            return Err(());
161        }
162        let page: Page = serde_json::from_str(&response.text().await.unwrap()).unwrap();
163        Ok(page)
164    }
165}
166
167#[cfg(test)]
168mod tests {
169    use super::*;
170
171    #[test]
172    fn test_session_creation() {
173        let _session = Session::new("".to_owned(), "".to_owned(), "".to_owned());
174    }
175}