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