1use oiseau::cache::Cache;
2use crate::model::{
3 Error, Result,
4 requests::{ActionRequest, ActionType},
5 auth::{Notification, User},
6 guest_logs::GuestLog,
7 permissions::{SecondaryPermission, FinePermission},
8};
9use crate::{auto_method, DataManager};
10use oiseau::{execute, get, query_rows, params, PostgresRow};
11
12impl DataManager {
13 pub(crate) fn get_guest_log_from_row(x: &PostgresRow) -> GuestLog {
15 GuestLog {
16 id: get!(x->0(i64)) as usize,
17 created: get!(x->1(i64)) as usize,
18 owner: get!(x->2(i64)) as usize,
19 name: get!(x->3(String)),
20 content: get!(x->4(String)),
21 waiting_for_review: get!(x->5(i32)) as i8 == 1,
22 ip: get!(x->6(String)),
23 }
24 }
25
26 auto_method!(get_guest_log_by_id()@get_guest_log_from_row -> "SELECT * FROM guest_logs WHERE id = $1" --name="guest_log" --returns=GuestLog --cache-key-tmpl="atto.guest_log:{}");
27
28 pub async fn get_guest_logs_by_owner(
30 &self,
31 owner: usize,
32 batch: usize,
33 page: usize,
34 ) -> Result<Vec<GuestLog>> {
35 let conn = match self.0.connect().await {
36 Ok(c) => c,
37 Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
38 };
39
40 let res = query_rows!(
41 &conn,
42 "SELECT * FROM guest_logs WHERE owner = $1 AND waiting_for_review = 0 ORDER BY created DESC LIMIT $2 OFFSET $3",
43 &[&(owner as i64), &(batch as i64), &((page * batch) as i64)],
44 |x| { Self::get_guest_log_from_row(x) }
45 );
46
47 if res.is_err() {
48 return Err(Error::GeneralNotFound("guest_log".to_string()));
49 }
50
51 Ok(res.unwrap())
52 }
53
54 pub async fn get_guest_logs_by_owner_wfr(
56 &self,
57 owner: usize,
58 batch: usize,
59 page: usize,
60 ) -> Result<Vec<GuestLog>> {
61 let conn = match self.0.connect().await {
62 Ok(c) => c,
63 Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
64 };
65
66 let res = query_rows!(
67 &conn,
68 "SELECT * FROM guest_logs WHERE owner = $1 AND waiting_for_review = 1 ORDER BY created DESC LIMIT $2 OFFSET $3",
69 &[&(owner as i64), &(batch as i64), &((page * batch) as i64)],
70 |x| { Self::get_guest_log_from_row(x) }
71 );
72
73 if res.is_err() {
74 return Err(Error::GeneralNotFound("guest_log".to_string()));
75 }
76
77 Ok(res.unwrap())
78 }
79
80 pub async fn create_guest_log(&self, data: GuestLog) -> Result<usize> {
85 if data.name.len() < 2 {
87 return Err(Error::DataTooShort("name".to_string()));
88 }
89
90 if data.name.len() > 32 {
91 return Err(Error::DataTooLong("name".to_string()));
92 }
93
94 if data.content.len() < 2 {
95 return Err(Error::DataTooShort("content".to_string()));
96 }
97
98 if data.content.len() > 2048 {
99 return Err(Error::DataTooLong("content".to_string()));
100 }
101
102 let owner = self.get_user_by_id(data.owner).await?;
104
105 let conn = match self.0.connect().await {
106 Ok(c) => c,
107 Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
108 };
109
110 let res = execute!(
111 &conn,
112 "INSERT INTO guest_logs VALUES ($1, $2, $3, $4, $5, $6, $7)",
113 params![
114 &(data.id as i64),
115 &(data.created as i64),
116 &(data.owner as i64),
117 &data.name,
118 &data.content,
119 &{ if data.waiting_for_review { 1 } else { 0 } },
120 &data.ip,
121 ]
122 );
123
124 if let Err(e) = res {
125 return Err(Error::DatabaseError(e.to_string()));
126 }
127
128 if data.waiting_for_review {
130 self.create_request(ActionRequest::with_id(
131 data.owner,
132 data.owner,
133 ActionType::GuestLog,
134 data.id,
135 None,
136 ))
137 .await?;
138 } else {
139 self.create_notification(Notification::new(
141 "New message on your guestbook!".to_string(),
142 format!(
143 "You've received a new message in your [guestbook](/@{}/guestbook).",
144 owner.username
145 ),
146 data.owner,
147 ))
148 .await?;
149 }
150
151 Ok(data.id)
153 }
154
155 pub async fn delete_guest_log(&self, id: usize, user: &User) -> Result<()> {
156 let y = self.get_guest_log_by_id(id).await?;
157
158 if user.id != y.owner
159 && !user
160 .secondary_permissions
161 .check(SecondaryPermission::MANAGE_GUEST_LOGS)
162 {
163 return Err(Error::NotAllowed);
164 }
165
166 let conn = match self.0.connect().await {
167 Ok(c) => c,
168 Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
169 };
170
171 let res = execute!(
172 &conn,
173 "DELETE FROM guest_logs WHERE id = $1",
174 &[&(id as i64)]
175 );
176
177 if let Err(e) = res {
178 return Err(Error::DatabaseError(e.to_string()));
179 }
180
181 self.0.1.remove(format!("atto.guest_log:{}", id)).await;
182
183 if y.waiting_for_review
185 && self
186 .get_request_by_id_linked_asset(y.owner, y.id)
187 .await
188 .is_ok()
189 {
190 self.delete_request(y.owner, y.id, user, false).await?;
191 }
192
193 Ok(())
195 }
196
197 pub async fn update_guest_log_waiting_for_review(
198 &self,
199 id: usize,
200 new_wfr: bool,
201 user: &User,
202 ) -> Result<()> {
203 let y = self.get_guest_log_by_id(id).await?;
204
205 if y.owner != user.id && !user.permissions.check(FinePermission::MANAGE_REQUESTS) {
206 return Err(Error::NotAllowed);
207 }
208
209 let conn = match self.0.connect().await {
211 Ok(c) => c,
212 Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
213 };
214
215 let res = execute!(
216 &conn,
217 "UPDATE guest_logs SET waiting_for_review = $1 WHERE id = $2",
218 params![&{ if new_wfr { 1 } else { 0 } }, &(id as i64)]
219 );
220
221 if let Err(e) = res {
222 return Err(Error::DatabaseError(e.to_string()));
223 }
224
225 self.0.1.remove(format!("atto.guest_log:{}", id)).await;
226 Ok(())
227 }
228}