]> Untitled Git - lemmy.git/blob - server/src/api/site.rs
Adding emoji support.
[lemmy.git] / server / src / api / site.rs
1 use super::*;
2 use std::str::FromStr;
3
4 #[derive(Serialize, Deserialize)]
5 pub struct ListCategories;
6
7 #[derive(Serialize, Deserialize)]
8 pub struct ListCategoriesResponse {
9   op: String,
10   categories: Vec<Category>
11 }
12
13 #[derive(Serialize, Deserialize)]
14 pub struct Search {
15   q: String,
16   type_: String,
17   community_id: Option<i32>,
18   sort: String,
19   page: Option<i64>,
20   limit: Option<i64>,
21 }
22
23 #[derive(Serialize, Deserialize)]
24 pub struct SearchResponse {
25   op: String,
26   type_: String,
27   comments: Vec<CommentView>,
28   posts: Vec<PostView>,
29   communities: Vec<CommunityView>,
30   users: Vec<UserView>,
31 }
32
33 #[derive(Serialize, Deserialize)]
34 pub struct GetModlog {
35   mod_user_id: Option<i32>,
36   community_id: Option<i32>,
37   page: Option<i64>,
38   limit: Option<i64>,
39 }
40
41 #[derive(Serialize, Deserialize)]
42 pub struct GetModlogResponse {
43   op: String,
44   removed_posts: Vec<ModRemovePostView>,
45   locked_posts: Vec<ModLockPostView>,
46   removed_comments: Vec<ModRemoveCommentView>,
47   removed_communities: Vec<ModRemoveCommunityView>,
48   banned_from_community: Vec<ModBanFromCommunityView>,
49   banned: Vec<ModBanView>,
50   added_to_community: Vec<ModAddCommunityView>,
51   added: Vec<ModAddView>,
52 }
53
54
55 #[derive(Serialize, Deserialize)]
56 pub struct CreateSite {
57   name: String,
58   description: Option<String>,
59   auth: String
60 }
61
62 #[derive(Serialize, Deserialize)]
63 pub struct EditSite {
64   name: String,
65   description: Option<String>,
66   auth: String
67 }
68
69 #[derive(Serialize, Deserialize)]
70 pub struct GetSite;
71
72 #[derive(Serialize, Deserialize)]
73 pub struct SiteResponse {
74   op: String,
75   site: SiteView,
76 }
77
78 #[derive(Serialize, Deserialize)]
79 pub struct GetSiteResponse {
80   op: String,
81   site: Option<SiteView>,
82   admins: Vec<UserView>,
83   banned: Vec<UserView>,
84 }
85
86 #[derive(Serialize, Deserialize)]
87 pub struct TransferSite {
88   user_id: i32,
89   auth: String
90 }
91
92 impl Perform<ListCategoriesResponse> for Oper<ListCategories> {
93   fn perform(&self) -> Result<ListCategoriesResponse, Error> {
94     let _data: &ListCategories = &self.data;
95     let conn = establish_connection();
96
97     let categories: Vec<Category> = Category::list_all(&conn)?;
98
99     // Return the jwt
100     Ok(
101       ListCategoriesResponse {
102         op: self.op.to_string(),
103         categories: categories
104       }
105       )
106   }
107 }
108
109 impl Perform<GetModlogResponse> for Oper<GetModlog> {
110   fn perform(&self) -> Result<GetModlogResponse, Error> {
111     let data: &GetModlog = &self.data;
112     let conn = establish_connection();
113
114     let removed_posts = ModRemovePostView::list(&conn, data.community_id, data.mod_user_id, data.page, data.limit)?;
115     let locked_posts = ModLockPostView::list(&conn, data.community_id, data.mod_user_id, data.page, data.limit)?;
116     let removed_comments = ModRemoveCommentView::list(&conn, data.community_id, data.mod_user_id, data.page, data.limit)?;
117     let banned_from_community = ModBanFromCommunityView::list(&conn, data.community_id, data.mod_user_id, data.page, data.limit)?;
118     let added_to_community = ModAddCommunityView::list(&conn, data.community_id, data.mod_user_id, data.page, data.limit)?;
119
120     // These arrays are only for the full modlog, when a community isn't given
121     let mut removed_communities = Vec::new();
122     let mut banned = Vec::new();
123     let mut added = Vec::new();
124
125     if data.community_id.is_none() {
126       removed_communities = ModRemoveCommunityView::list(&conn, data.mod_user_id, data.page, data.limit)?;
127       banned = ModBanView::list(&conn, data.mod_user_id, data.page, data.limit)?;
128       added = ModAddView::list(&conn, data.mod_user_id, data.page, data.limit)?;
129     }
130
131     // Return the jwt
132     Ok(
133       GetModlogResponse {
134         op: self.op.to_string(),
135         removed_posts: removed_posts,
136         locked_posts: locked_posts,
137         removed_comments: removed_comments,
138         removed_communities: removed_communities,
139         banned_from_community: banned_from_community,
140         banned: banned,
141         added_to_community: added_to_community,
142         added: added,
143       }
144       )
145   }
146 }
147
148 impl Perform<SiteResponse> for Oper<CreateSite> {
149   fn perform(&self) -> Result<SiteResponse, Error> {
150     let data: &CreateSite = &self.data;
151     let conn = establish_connection();
152
153     let claims = match Claims::decode(&data.auth) {
154       Ok(claims) => claims.claims,
155       Err(_e) => {
156         return Err(APIError::err(&self.op, "not_logged_in"))?
157       }
158     };
159
160     if has_slurs(&data.name) || 
161       (data.description.is_some() && has_slurs(&data.description.to_owned().unwrap())) {
162         return Err(APIError::err(&self.op, "no_slurs"))?
163       }
164
165     let user_id = claims.id;
166
167     // Make sure user is an admin
168     if !UserView::read(&conn, user_id)?.admin {
169       return Err(APIError::err(&self.op, "not_an_admin"))?
170     }
171
172     let site_form = SiteForm {
173       name: data.name.to_owned(),
174       description: data.description.to_owned(),
175       creator_id: user_id,
176       updated: None,
177     };
178
179     match Site::create(&conn, &site_form) {
180       Ok(site) => site,
181       Err(_e) => {
182         return Err(APIError::err(&self.op, "site_already_exists"))?
183       }
184     };
185
186     let site_view = SiteView::read(&conn)?;
187
188     Ok(
189       SiteResponse {
190         op: self.op.to_string(), 
191         site: site_view,
192       }
193       )
194   }
195 }
196
197
198 impl Perform<SiteResponse> for Oper<EditSite> {
199   fn perform(&self) -> Result<SiteResponse, Error> {
200     let data: &EditSite = &self.data;
201     let conn = establish_connection();
202
203     let claims = match Claims::decode(&data.auth) {
204       Ok(claims) => claims.claims,
205       Err(_e) => {
206         return Err(APIError::err(&self.op, "not_logged_in"))?
207       }
208     };
209
210     if has_slurs(&data.name) || 
211       (data.description.is_some() && has_slurs(&data.description.to_owned().unwrap())) {
212         return Err(APIError::err(&self.op, "no_slurs"))?
213       }
214
215     let user_id = claims.id;
216
217     // Make sure user is an admin
218     if UserView::read(&conn, user_id)?.admin == false {
219       return Err(APIError::err(&self.op, "not_an_admin"))?
220     }
221
222     let found_site = Site::read(&conn, 1)?;
223
224     let site_form = SiteForm {
225       name: data.name.to_owned(),
226       description: data.description.to_owned(),
227       creator_id: found_site.creator_id,
228       updated: Some(naive_now()),
229     };
230
231     match Site::update(&conn, 1, &site_form) {
232       Ok(site) => site,
233       Err(_e) => {
234         return Err(APIError::err(&self.op, "couldnt_update_site"))?
235       }
236     };
237
238     let site_view = SiteView::read(&conn)?;
239
240     Ok(
241       SiteResponse {
242         op: self.op.to_string(), 
243         site: site_view,
244       }
245       )
246   }
247 }
248
249 impl Perform<GetSiteResponse> for Oper<GetSite> {
250   fn perform(&self) -> Result<GetSiteResponse, Error> {
251     let _data: &GetSite = &self.data;
252     let conn = establish_connection();
253
254     // It can return a null site in order to redirect
255     let site_view = match Site::read(&conn, 1) {
256       Ok(_site) => Some(SiteView::read(&conn)?),
257       Err(_e) => None
258     };
259
260     let mut admins = UserView::admins(&conn)?;
261     if site_view.is_some() {
262       let site_creator_id = site_view.to_owned().unwrap().creator_id;
263       let creator_index = admins.iter().position(|r| r.id == site_creator_id).unwrap();
264       let creator_user = admins.remove(creator_index);
265       admins.insert(0, creator_user);
266     }
267
268     let banned = UserView::banned(&conn)?;
269
270     Ok(
271       GetSiteResponse {
272         op: self.op.to_string(), 
273         site: site_view,
274         admins: admins,
275         banned: banned,
276       }
277       )
278   }
279 }
280
281 impl Perform<SearchResponse> for Oper<Search> {
282   fn perform(&self) -> Result<SearchResponse, Error> {
283     let data: &Search = &self.data;
284     let conn = establish_connection();
285
286     let sort = SortType::from_str(&data.sort)?;
287     let type_ = SearchType::from_str(&data.type_)?;
288
289     let mut posts = Vec::new();
290     let mut comments = Vec::new();
291     let mut communities = Vec::new();
292     let mut users = Vec::new();
293
294     // TODO no clean / non-nsfw searching rn
295
296     match type_ {
297       SearchType::Posts => {
298         posts = PostView::list(
299           &conn, 
300           PostListingType::All, 
301           &sort, 
302           data.community_id, 
303           None,
304           Some(data.q.to_owned()),
305           None,
306           None, 
307           true,
308           false, 
309           false, 
310           data.page, 
311           data.limit)?;
312       },
313       SearchType::Comments => {
314         comments = CommentView::list(
315           &conn, 
316           &sort, 
317           None, 
318           None, 
319           Some(data.q.to_owned()),
320           None,
321           false, 
322           data.page,
323           data.limit)?;
324       },
325       SearchType::Communities => {
326         communities = CommunityView::list(
327           &conn, 
328           &sort, 
329           None, 
330           true,
331           Some(data.q.to_owned()),
332           data.page, 
333           data.limit)?;
334       }, 
335       SearchType::Users => {
336         users = UserView::list(
337           &conn, 
338           &sort, 
339           Some(data.q.to_owned()), 
340           data.page, 
341           data.limit)?;
342       }, 
343       SearchType::All => {
344         posts = PostView::list(
345           &conn, 
346           PostListingType::All, 
347           &sort, 
348           data.community_id, 
349           None,
350           Some(data.q.to_owned()),
351           None,
352           None, 
353           true,
354           false, 
355           false, 
356           data.page, 
357           data.limit)?;
358         comments = CommentView::list(
359           &conn, 
360           &sort, 
361           None, 
362           None, 
363           Some(data.q.to_owned()),
364           None,
365           false, 
366           data.page,
367           data.limit)?;
368         communities = CommunityView::list(
369           &conn, 
370           &sort, 
371           None, 
372           true,
373           Some(data.q.to_owned()),
374           data.page, 
375           data.limit)?;
376         users = UserView::list(
377           &conn, 
378           &sort, 
379           Some(data.q.to_owned()), 
380           data.page, 
381           data.limit)?;
382       },
383       SearchType::Url => {
384         posts = PostView::list(
385           &conn, 
386           PostListingType::All, 
387           &sort, 
388           data.community_id, 
389           None,
390           None,
391           Some(data.q.to_owned()),
392           None, 
393           true,
394           false, 
395           false, 
396           data.page, 
397           data.limit)?;
398       }
399     };
400
401
402     // Return the jwt
403     Ok(
404       SearchResponse {
405         op: self.op.to_string(),
406         type_: data.type_.to_owned(),
407         comments: comments,
408         posts: posts,
409         communities: communities,
410         users: users,
411       }
412       )
413   }
414 }
415
416 impl Perform<GetSiteResponse> for Oper<TransferSite> {
417   fn perform(&self) -> Result<GetSiteResponse, Error> {
418     let data: &TransferSite = &self.data;
419     let conn = establish_connection();
420
421     let claims = match Claims::decode(&data.auth) {
422       Ok(claims) => claims.claims,
423       Err(_e) => {
424         return Err(APIError::err(&self.op, "not_logged_in"))?
425       }
426     };
427
428     let user_id = claims.id;
429
430     let read_site = Site::read(&conn, 1)?;
431
432     // Make sure user is the creator
433     if read_site.creator_id != user_id {
434       return Err(APIError::err(&self.op, "not_an_admin"))?
435     }
436
437     let site_form = SiteForm {
438       name: read_site.name,
439       description: read_site.description,
440       creator_id: data.user_id,
441       updated: Some(naive_now()),
442     };
443
444     match Site::update(&conn, 1, &site_form) {
445       Ok(site) => site,
446       Err(_e) => {
447         return Err(APIError::err(&self.op, "couldnt_update_site"))?
448       }
449     };
450
451     // Mod tables
452     let form = ModAddForm {
453       mod_user_id: user_id,
454       other_user_id: data.user_id,
455       removed: Some(false),
456     };
457
458     ModAdd::create(&conn, &form)?;
459
460     let site_view = SiteView::read(&conn)?;
461
462     let mut admins = UserView::admins(&conn)?;
463     let creator_index = admins.iter().position(|r| r.id == site_view.creator_id).unwrap();
464     let creator_user = admins.remove(creator_index);
465     admins.insert(0, creator_user);
466
467     let banned = UserView::banned(&conn)?;
468
469     Ok(
470       GetSiteResponse {
471         op: self.op.to_string(), 
472         site: Some(site_view),
473         admins: admins,
474         banned: banned,
475       }
476       )
477   }
478 }
479