tetratto_core2/database/
requests.rs1use oiseau::cache::Cache;
2use crate::model::id::Id;
3use crate::model::requests::ActionType;
4use crate::model::{Error, Result, requests::ActionRequest, auth::User, permissions::FinePermission};
5use crate::DataManager;
6
7use oiseau::{PostgresRow, execute, get, query_row, query_rows, params};
8
9impl DataManager {
10 pub(crate) fn get_request_from_row(x: &PostgresRow) -> ActionRequest {
12 ActionRequest {
13 id: Id::deserialize(&get!(x->0(String))),
14 created: get!(x->1(i64)) as u128,
15 owner: Id::deserialize(&get!(x->2(String))),
16 action_type: serde_json::from_str(&get!(x->3(String))).unwrap(),
17 linked_asset: Id::deserialize(&get!(x->4(String))),
18 data: serde_json::from_str(&get!(x->5(String))).unwrap(),
19 }
20 }
21
22 pub async fn get_request_by_id_linked_asset(
23 &self,
24 id: &Id,
25 linked_asset: &Id,
26 ) -> Result<ActionRequest> {
27 if let Some(cached) = self
28 .0
29 .1
30 .get(format!("atto.request:{}:{}", id, linked_asset))
31 .await
32 {
33 if let Ok(x) = serde_json::from_str(&cached) {
34 return Ok(x);
35 } else {
36 self.0
37 .1
38 .remove(format!("atto.request:{}:{}", id, linked_asset))
39 .await;
40 }
41 }
42
43 let conn = match self.0.connect().await {
44 Ok(c) => c,
45 Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
46 };
47
48 let res = query_row!(
49 &conn,
50 "SELECT * FROM requests WHERE id = $1 AND linked_asset = $2",
51 &[&id.printable(), &linked_asset.printable()],
52 |x| { Ok(Self::get_request_from_row(x)) }
53 );
54
55 if res.is_err() {
56 return Err(Error::GeneralNotFound("request".to_string()));
57 }
58
59 let x = res.unwrap();
60 self.0
61 .1
62 .set(
63 format!("atto.request:{}:{}", id, linked_asset),
64 serde_json::to_string(&x).unwrap(),
65 )
66 .await;
67
68 Ok(x)
69 }
70
71 pub async fn get_requests_by_owner(&self, owner: &Id) -> Result<Vec<ActionRequest>> {
73 let conn = match self.0.connect().await {
74 Ok(c) => c,
75 Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
76 };
77
78 let res = query_rows!(
79 &conn,
80 "SELECT * FROM requests WHERE owner = $1 ORDER BY created DESC",
81 &[&owner.printable()],
82 |x| { Self::get_request_from_row(x) }
83 );
84
85 if res.is_err() {
86 return Err(Error::GeneralNotFound("request".to_string()));
87 }
88
89 Ok(res.unwrap())
90 }
91
92 pub async fn get_requests_by_owner_paginated(
94 &self,
95 owner: &Id,
96 batch: usize,
97 page: usize,
98 ) -> Result<Vec<ActionRequest>> {
99 let conn = match self.0.connect().await {
100 Ok(c) => c,
101 Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
102 };
103
104 let res = query_rows!(
105 &conn,
106 "SELECT * FROM requests WHERE owner = $1 ORDER BY created DESC LIMIT $2 OFFSET $3",
107 &[
108 &owner.printable(),
109 &(batch as i64),
110 &((page * batch) as i64)
111 ],
112 |x| { Self::get_request_from_row(x) }
113 );
114
115 if res.is_err() {
116 return Err(Error::GeneralNotFound("request".to_string()));
117 }
118
119 Ok(res.unwrap())
120 }
121
122 pub async fn create_request(&self, data: ActionRequest) -> Result<()> {
127 let conn = match self.0.connect().await {
128 Ok(c) => c,
129 Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
130 };
131
132 let res = execute!(
133 &conn,
134 "INSERT INTO requests VALUES ($1, $2, $3, $4, $5, $6)",
135 params![
136 &data.id.printable(),
137 &(data.created as i64),
138 &data.owner.printable(),
139 &serde_json::to_string(&data.action_type).unwrap().as_str(),
140 &data.linked_asset.printable(),
141 &serde_json::to_string(&data.data).unwrap().as_str(),
142 ]
143 );
144
145 if let Err(e) = res {
146 return Err(Error::DatabaseError(e.to_string()));
147 }
148
149 self.incr_user_request_count(&data.owner).await.unwrap();
151
152 Ok(())
154 }
155
156 pub async fn delete_request(
157 &self,
158 id: &Id,
159 linked_asset: &Id,
160 user: &User,
161 force: bool,
162 ) -> Result<()> {
163 let y = self
164 .get_request_by_id_linked_asset(id, linked_asset)
165 .await?;
166
167 if !force
168 && (user.id != y.owner && user.id != y.linked_asset)
169 && !user.permissions.check(FinePermission::ManageRequests)
170 {
171 return Err(Error::NotAllowed);
172 }
173
174 let conn = match self.0.connect().await {
175 Ok(c) => c,
176 Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
177 };
178
179 let res = execute!(
180 &conn,
181 "DELETE FROM requests WHERE id = $1",
182 &[&y.id.printable()]
183 );
184
185 if let Err(e) = res {
186 return Err(Error::DatabaseError(e.to_string()));
187 }
188
189 self.0.1.remove(format!("atto.request:{}", y.id)).await;
190
191 self.0
192 .1
193 .remove(format!("atto.request:{}:{}", id, linked_asset))
194 .await;
195
196 let owner = self.get_user_by_id(&y.owner).await?;
198 if owner.request_count > 0 {
199 self.decr_user_request_count(&y.owner).await.unwrap();
200 }
201
202 Ok(())
204 }
205
206 pub async fn delete_all_requests(&self, user: &User) -> Result<()> {
207 let y = self.get_requests_by_owner(&user.id).await?;
208
209 for x in y {
210 if user.id != x.owner && !user.permissions.check(FinePermission::ManageRequests) {
211 return Err(Error::NotAllowed);
212 }
213
214 self.delete_request(&x.id, &x.linked_asset, user, false)
215 .await?;
216
217 if x.action_type == ActionType::Answer {
219 self.delete_question(&x.linked_asset, user).await?;
220 }
221 }
222
223 self.update_user_request_count(&user.id, 0).await?;
224
225 Ok(())
226 }
227}