rouchdb_adapter_http/
auth.rs1use reqwest::Client;
6use serde::{Deserialize, Serialize};
7
8use rouchdb_core::error::{Result, RouchError};
9
10#[derive(Debug, Clone, Serialize, Deserialize)]
12pub struct Session {
13 pub ok: bool,
14 #[serde(rename = "userCtx")]
15 pub user_ctx: UserContext,
16}
17
18#[derive(Debug, Clone, Serialize, Deserialize)]
20pub struct UserContext {
21 pub name: Option<String>,
22 pub roles: Vec<String>,
23}
24
25pub struct AuthClient {
31 client: Client,
32 server_url: String,
33}
34
35impl AuthClient {
36 pub fn new(server_url: &str) -> Self {
38 let client = Client::builder()
39 .cookie_store(true)
40 .build()
41 .unwrap_or_default();
42 Self {
43 client,
44 server_url: server_url.trim_end_matches('/').to_string(),
45 }
46 }
47
48 pub fn client(&self) -> &Client {
50 &self.client
51 }
52
53 pub fn server_url(&self) -> &str {
55 &self.server_url
56 }
57
58 pub async fn login(&self, username: &str, password: &str) -> Result<Session> {
60 let resp = self
61 .client
62 .post(format!("{}/_session", self.server_url))
63 .json(&serde_json::json!({"name": username, "password": password}))
64 .send()
65 .await
66 .map_err(|e| RouchError::DatabaseError(e.to_string()))?;
67
68 if !resp.status().is_success() {
69 let status = resp.status();
70 let body = resp.text().await.unwrap_or_default();
71 return Err(RouchError::DatabaseError(format!(
72 "login failed ({}): {}",
73 status, body
74 )));
75 }
76
77 resp.json::<Session>()
78 .await
79 .map_err(|e| RouchError::DatabaseError(e.to_string()))
80 }
81
82 pub async fn logout(&self) -> Result<()> {
84 self.client
85 .delete(format!("{}/_session", self.server_url))
86 .send()
87 .await
88 .map_err(|e| RouchError::DatabaseError(e.to_string()))?;
89 Ok(())
90 }
91
92 pub async fn get_session(&self) -> Result<Session> {
94 let resp = self
95 .client
96 .get(format!("{}/_session", self.server_url))
97 .send()
98 .await
99 .map_err(|e| RouchError::DatabaseError(e.to_string()))?;
100
101 resp.json::<Session>()
102 .await
103 .map_err(|e| RouchError::DatabaseError(e.to_string()))
104 }
105
106 pub async fn sign_up(&self, username: &str, password: &str, roles: Vec<String>) -> Result<()> {
108 let user_doc = serde_json::json!({
109 "_id": format!("org.couchdb.user:{}", username),
110 "name": username,
111 "password": password,
112 "roles": roles,
113 "type": "user"
114 });
115
116 let resp = self
117 .client
118 .put(format!(
119 "{}/_users/org.couchdb.user:{}",
120 self.server_url, username
121 ))
122 .json(&user_doc)
123 .send()
124 .await
125 .map_err(|e| RouchError::DatabaseError(e.to_string()))?;
126
127 if !resp.status().is_success() {
128 let status = resp.status();
129 let body = resp.text().await.unwrap_or_default();
130 return Err(RouchError::DatabaseError(format!(
131 "signup failed ({}): {}",
132 status, body
133 )));
134 }
135
136 Ok(())
137 }
138}