1use oiseau::cache::Cache;
2use crate::model::socket::{CrudMessageType, PacketType, SocketMessage, SocketMethod};
3use crate::model::{Error, Result, auth::Notification, auth::User, permissions::FinePermission};
4use crate::{auto_method, DataManager};
5
6use oiseau::{PostgresRow, cache::redis::Commands};
7use oiseau::{execute, get, query_rows, params};
8
9impl DataManager {
10 pub(crate) fn get_notification_from_row(x: &PostgresRow) -> Notification {
12 Notification {
13 id: get!(x->0(i64)) as usize,
14 created: get!(x->1(i64)) as usize,
15 title: get!(x->2(String)),
16 content: get!(x->3(String)),
17 owner: get!(x->4(i64)) as usize,
18 read: get!(x->5(i32)) as i8 == 1,
19 tag: get!(x->6(String)),
20 }
21 }
22
23 auto_method!(get_notification_by_id()@get_notification_from_row -> "SELECT * FROM notifications WHERE id = $1" --name="notification" --returns=Notification --cache-key-tmpl="atto.notification:{}");
24
25 pub async fn get_notifications_by_owner(&self, owner: usize) -> Result<Vec<Notification>> {
27 let conn = match self.0.connect().await {
28 Ok(c) => c,
29 Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
30 };
31
32 let res = query_rows!(
33 &conn,
34 "SELECT * FROM notifications WHERE owner = $1 ORDER BY created DESC",
35 &[&(owner as i64)],
36 |x| { Self::get_notification_from_row(x) }
37 );
38
39 if res.is_err() {
40 return Err(Error::GeneralNotFound("notification".to_string()));
41 }
42
43 Ok(res.unwrap())
44 }
45
46 pub async fn get_notifications_by_owner_paginated(
48 &self,
49 owner: usize,
50 batch: usize,
51 page: usize,
52 ) -> Result<Vec<Notification>> {
53 let conn = match self.0.connect().await {
54 Ok(c) => c,
55 Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
56 };
57
58 let res = query_rows!(
59 &conn,
60 "SELECT * FROM notifications WHERE owner = $1 ORDER BY created DESC LIMIT $2 OFFSET $3",
61 &[&(owner as i64), &(batch as i64), &((page * batch) as i64)],
62 |x| { Self::get_notification_from_row(x) }
63 );
64
65 if res.is_err() {
66 return Err(Error::GeneralNotFound("notification".to_string()));
67 }
68
69 Ok(res.unwrap())
70 }
71
72 pub async fn get_notifications_by_tag(&self, tag: &str) -> Result<Vec<Notification>> {
74 let conn = match self.0.connect().await {
75 Ok(c) => c,
76 Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
77 };
78
79 let res = query_rows!(
80 &conn,
81 "SELECT * FROM notifications WHERE tag = $1 ORDER BY created DESC",
82 &[&tag],
83 |x| { Self::get_notification_from_row(x) }
84 );
85
86 if res.is_err() {
87 return Err(Error::GeneralNotFound("notification".to_string()));
88 }
89
90 Ok(res.unwrap())
91 }
92
93 pub async fn create_notification(&self, data: Notification) -> Result<()> {
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 = execute!(
104 &conn,
105 "INSERT INTO notifications VALUES ($1, $2, $3, $4, $5, $6, $7)",
106 params![
107 &(data.id as i64),
108 &(data.created as i64),
109 &data.title,
110 &data.content,
111 &(data.owner as i64),
112 &{ if data.read { 1 } else { 0 } },
113 &data.tag
114 ]
115 );
116
117 if let Err(e) = res {
118 return Err(Error::DatabaseError(e.to_string()));
119 }
120
121 self.incr_user_notifications(data.owner).await?;
123
124 let mut con = self.0.1.get_con().await;
126
127 if let Err(e) = con.publish::<String, String, ()>(
128 format!("{}/notifs", data.owner),
129 serde_json::to_string(&SocketMessage {
130 method: SocketMethod::Packet(PacketType::Crud(CrudMessageType::Create)),
131 data: serde_json::to_string(&data).unwrap(),
132 })
133 .unwrap(),
134 ) {
135 return Err(Error::MiscError(e.to_string()));
136 }
137
138 Ok(())
140 }
141
142 pub async fn delete_notification(&self, id: usize, user: &User) -> Result<()> {
143 let notification = self.get_notification_by_id(id).await?;
144
145 if user.id != notification.owner
146 && !user.permissions.check(FinePermission::MANAGE_NOTIFICATIONS)
147 {
148 return Err(Error::NotAllowed);
149 }
150
151 let conn = match self.0.connect().await {
152 Ok(c) => c,
153 Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
154 };
155
156 let res = execute!(
157 &conn,
158 "DELETE FROM notifications WHERE id = $1",
159 &[&(id as i64)]
160 );
161
162 if let Err(e) = res {
163 return Err(Error::DatabaseError(e.to_string()));
164 }
165
166 self.0.1.remove(format!("atto.notification:{}", id)).await;
167
168 if !notification.read {
170 self.decr_user_notifications(notification.owner)
171 .await
172 .unwrap();
173 }
174
175 let mut con = self.0.1.get_con().await;
177
178 if let Err(e) = con.publish::<String, String, ()>(
179 format!("{}/notifs", notification.owner),
180 serde_json::to_string(&SocketMessage {
181 method: SocketMethod::Packet(PacketType::Crud(CrudMessageType::Delete)),
182 data: notification.id.to_string(),
183 })
184 .unwrap(),
185 ) {
186 return Err(Error::MiscError(e.to_string()));
187 }
188
189 Ok(())
191 }
192
193 pub async fn delete_all_notifications(&self, user: &User) -> Result<()> {
194 let conn = match self.0.connect().await {
195 Ok(c) => c,
196 Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
197 };
198
199 let res = execute!(
200 &conn,
201 "DELETE FROM notifications WHERE owner = $1",
202 &[&(user.id as i64)]
203 );
204
205 if let Err(e) = res {
206 return Err(Error::DatabaseError(e.to_string()));
207 }
208
209 self.update_user_notification_count(user.id, 0).await?;
210 Ok(())
211 }
212
213 pub async fn delete_all_notifications_by_tag(&self, user: &User, tag: &str) -> Result<()> {
214 let conn = match self.0.connect().await {
215 Ok(c) => c,
216 Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
217 };
218
219 let res = execute!(
220 &conn,
221 "DELETE FROM notifications WHERE owner = $1 AND tag = $2",
222 params![&(user.id as i64), tag]
223 );
224
225 if let Err(e) = res {
226 return Err(Error::DatabaseError(e.to_string()));
227 }
228
229 Ok(())
230 }
231
232 pub async fn update_notification_read(
233 &self,
234 id: usize,
235 new_read: bool,
236 user: &User,
237 ) -> Result<()> {
238 let y = self.get_notification_by_id(id).await?;
239
240 if y.owner != user.id && !user.permissions.check(FinePermission::MANAGE_NOTIFICATIONS) {
241 return Err(Error::NotAllowed);
242 }
243
244 let conn = match self.0.connect().await {
246 Ok(c) => c,
247 Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
248 };
249
250 let res = execute!(
251 &conn,
252 "UPDATE notifications SET read = $1 WHERE id = $2",
253 params![&{ if new_read { 1 } else { 0 } }, &(id as i64)]
254 );
255
256 if let Err(e) = res {
257 return Err(Error::DatabaseError(e.to_string()));
258 }
259
260 self.0.1.remove(format!("atto.notification:{}", id)).await;
261
262 if (y.read) && (!new_read) {
263 self.incr_user_notifications(user.id).await?;
264 } else if (!y.read) && (new_read) {
265 self.decr_user_notifications(user.id).await?;
266 }
267
268 Ok(())
269 }
270
271 pub async fn update_all_notifications_read(&self, user: &User, read: bool) -> Result<()> {
272 let notifications = self.get_notifications_by_owner(user.id).await?;
273
274 let mut changed_count: i32 = 0;
275 for notification in notifications {
276 if notification.read == read {
277 continue;
279 }
280
281 changed_count += 1;
282
283 self.0
284 .1
285 .remove(format!("atto.notification:{}", notification.id))
286 .await;
287 }
288
289 let conn = match self.0.connect().await {
291 Ok(c) => c,
292 Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
293 };
294
295 let res = execute!(
296 &conn,
297 "UPDATE notifications SET read = $1 WHERE owner = $2",
298 params![&{ if read { 1 } else { 0 } }, &(user.id as i64)]
299 );
300
301 if let Err(e) = res {
302 return Err(Error::DatabaseError(e.to_string()));
303 }
304
305 if !read {
307 self.update_user_notification_count(user.id, changed_count)
309 .await?;
310 } else {
311 self.update_user_notification_count(user.id, 0).await?;
312 }
313
314 Ok(())
316 }
317}