]> Untitled Git - lemmy.git/blob - server/src/websocket/server.rs
Merge branch 'dev' into reorg
[lemmy.git] / server / src / websocket / server.rs
1 //! `ChatServer` is an actor. It maintains list of connection client session.
2 //! And manages available rooms. Peers send messages to other peers in same
3 //! room through `ChatServer`.
4
5 use actix::prelude::*;
6 use rand::{rngs::ThreadRng, Rng};
7 use std::collections::{HashMap, HashSet};
8 use serde::{Deserialize, Serialize};
9 use serde_json::{Value};
10 use bcrypt::{verify};
11 use std::str::FromStr;
12 use diesel::PgConnection;
13 use failure::Error;
14 use std::time::{SystemTime};
15
16 use {Crud, Joinable, Likeable, Followable, Bannable, Saveable, establish_connection, naive_now, naive_from_unix, SortType, SearchType, has_slurs, remove_slurs, Settings};
17 use db::community::*;
18 use db::user::*;
19 use db::post::*;
20 use db::comment::*;
21 use db::post_view::*;
22 use db::comment_view::*;
23 use db::category::*;
24 use db::community_view::*;
25 use db::user_view::*;
26 use db::moderator_views::*;
27 use db::moderator::*;
28
29 const RATE_LIMIT_MESSAGES: i32 = 30;
30 const RATE_LIMIT_PER_SECOND: i32 = 60;
31 const RATE_LIMIT_REGISTER_MESSAGES: i32 = 1;
32 const RATE_LIMIT_REGISTER_PER_SECOND: i32 = 60;
33
34 #[derive(EnumString,ToString,Debug)]
35 pub enum UserOperation {
36   Login, Register, CreateCommunity, CreatePost, ListCommunities, ListCategories, GetPost, GetCommunity, CreateComment, EditComment, SaveComment, CreateCommentLike, GetPosts, CreatePostLike, EditPost, SavePost, EditCommunity, FollowCommunity, GetFollowedCommunities, GetUserDetails, GetReplies, GetModlog, BanFromCommunity, AddModToCommunity, CreateSite, EditSite, GetSite, AddAdmin, BanUser, Search, MarkAllAsRead
37 }
38
39 #[derive(Fail, Debug)]
40 #[fail(display = "{{\"op\":\"{}\", \"error\":\"{}\"}}", op, message)]
41 pub struct ErrorMessage {
42   op: String,
43   message: String
44 }
45
46 /// Chat server sends this messages to session
47 #[derive(Message)]
48 pub struct WSMessage(pub String);
49
50 /// Message for chat server communications
51
52 /// New chat session is created
53 #[derive(Message)]
54 #[rtype(usize)]
55 pub struct Connect {
56   pub addr: Recipient<WSMessage>,
57   pub ip: String,
58 }
59
60 /// Session is disconnected
61 #[derive(Message)]
62 pub struct Disconnect {
63   pub id: usize,
64   pub ip: String,
65 }
66
67 /// Send message to specific room
68 #[derive(Message)]
69 pub struct ClientMessage {
70   /// Id of the client session
71   pub id: usize,
72   /// Peer message
73   pub msg: String,
74   /// Room name
75   pub room: String,
76 }
77
78 #[derive(Serialize, Deserialize)]
79 pub struct StandardMessage {
80   /// Id of the client session
81   pub id: usize,
82   /// Peer message
83   pub msg: String,
84 }
85
86 impl actix::Message for StandardMessage {
87   type Result = String;
88 }
89
90 #[derive(Serialize, Deserialize)]
91 pub struct Login {
92   pub username_or_email: String,
93   pub password: String
94 }
95
96 #[derive(Serialize, Deserialize)]
97 pub struct Register {
98   username: String,
99   email: Option<String>,
100   password: String,
101   password_verify: String,
102   admin: bool,
103   spam_timeri: i64,
104 }
105
106 #[derive(Serialize, Deserialize)]
107 pub struct LoginResponse {
108   op: String,
109   jwt: String
110 }
111
112 #[derive(Serialize, Deserialize)]
113 pub struct CreateCommunity {
114   name: String,
115   title: String,
116   description: Option<String>,
117   category_id: i32 ,
118   auth: String
119 }
120
121 #[derive(Serialize, Deserialize)]
122 pub struct CommunityResponse {
123   op: String,
124   community: CommunityView
125 }
126
127 #[derive(Serialize, Deserialize)]
128 pub struct ListCommunities {
129   sort: String,
130   page: Option<i64>,
131   limit: Option<i64>,
132   auth: Option<String>
133 }
134
135 #[derive(Serialize, Deserialize)]
136 pub struct ListCommunitiesResponse {
137   op: String,
138   communities: Vec<CommunityView>
139 }
140
141 #[derive(Serialize, Deserialize)]
142 pub struct ListCategories;
143
144 #[derive(Serialize, Deserialize)]
145 pub struct ListCategoriesResponse {
146   op: String,
147   categories: Vec<Category>
148 }
149
150 #[derive(Serialize, Deserialize)]
151 pub struct CreatePost {
152   name: String,
153   url: Option<String>,
154   body: Option<String>,
155   community_id: i32,
156   auth: String
157 }
158
159 #[derive(Serialize, Deserialize)]
160 pub struct PostResponse {
161   op: String,
162   post: PostView
163 }
164
165
166 #[derive(Serialize, Deserialize)]
167 pub struct GetPost {
168   id: i32,
169   auth: Option<String>
170 }
171
172 #[derive(Serialize, Deserialize)]
173 pub struct GetPostResponse {
174   op: String,
175   post: PostView,
176   comments: Vec<CommentView>,
177   community: CommunityView,
178   moderators: Vec<CommunityModeratorView>,
179   admins: Vec<UserView>,
180 }
181
182 #[derive(Serialize, Deserialize)]
183 pub struct GetPosts {
184   type_: String,
185   sort: String,
186   page: Option<i64>,
187   limit: Option<i64>,
188   community_id: Option<i32>,
189   auth: Option<String>
190 }
191
192 #[derive(Serialize, Deserialize)]
193 pub struct GetPostsResponse {
194   op: String,
195   posts: Vec<PostView>,
196 }
197
198 #[derive(Serialize, Deserialize)]
199 pub struct GetCommunity {
200   id: Option<i32>,
201   name: Option<String>,
202   auth: Option<String>
203 }
204
205 #[derive(Serialize, Deserialize)]
206 pub struct GetCommunityResponse {
207   op: String,
208   community: CommunityView,
209   moderators: Vec<CommunityModeratorView>,
210   admins: Vec<UserView>,
211 }
212
213 #[derive(Serialize, Deserialize)]
214 pub struct CreateComment {
215   content: String,
216   parent_id: Option<i32>,
217   edit_id: Option<i32>,
218   post_id: i32,
219   auth: String
220 }
221
222 #[derive(Serialize, Deserialize)]
223 pub struct EditComment {
224   content: String,
225   parent_id: Option<i32>,
226   edit_id: i32,
227   creator_id: i32,
228   post_id: i32,
229   removed: Option<bool>,
230   deleted: Option<bool>,
231   reason: Option<String>,
232   read: Option<bool>,
233   auth: String
234 }
235
236 #[derive(Serialize, Deserialize)]
237 pub struct SaveComment {
238   comment_id: i32,
239   save: bool,
240   auth: String
241 }
242
243 #[derive(Serialize, Deserialize)]
244 pub struct CommentResponse {
245   op: String,
246   comment: CommentView
247 }
248
249 #[derive(Serialize, Deserialize)]
250 pub struct CreateCommentLike {
251   comment_id: i32,
252   post_id: i32,
253   score: i16,
254   auth: String
255 }
256
257 #[derive(Serialize, Deserialize)]
258 pub struct CreatePostLike {
259   post_id: i32,
260   score: i16,
261   auth: String
262 }
263
264 #[derive(Serialize, Deserialize)]
265 pub struct CreatePostLikeResponse {
266   op: String,
267   post: PostView
268 }
269
270
271 #[derive(Serialize, Deserialize)]
272 pub struct EditPost {
273   edit_id: i32,
274   creator_id: i32,
275   community_id: i32,
276   name: String,
277   url: Option<String>,
278   body: Option<String>,
279   removed: Option<bool>,
280   deleted: Option<bool>,
281   locked: Option<bool>,
282   reason: Option<String>,
283   auth: String
284 }
285
286 #[derive(Serialize, Deserialize)]
287 pub struct SavePost {
288   post_id: i32,
289   save: bool,
290   auth: String
291 }
292
293 #[derive(Serialize, Deserialize)]
294 pub struct EditCommunity {
295   edit_id: i32,
296   name: String,
297   title: String,
298   description: Option<String>,
299   category_id: i32,
300   removed: Option<bool>,
301   deleted: Option<bool>,
302   reason: Option<String>,
303   expires: Option<i64>,
304   auth: String
305 }
306
307 #[derive(Serialize, Deserialize)]
308 pub struct FollowCommunity {
309   community_id: i32,
310   follow: bool,
311   auth: String
312 }
313
314 #[derive(Serialize, Deserialize)]
315 pub struct GetFollowedCommunities {
316   auth: String
317 }
318
319 #[derive(Serialize, Deserialize)]
320 pub struct GetFollowedCommunitiesResponse {
321   op: String,
322   communities: Vec<CommunityFollowerView>
323 }
324
325 #[derive(Serialize, Deserialize)]
326 pub struct GetUserDetails {
327   user_id: Option<i32>,
328   username: Option<String>,
329   sort: String,
330   page: Option<i64>,
331   limit: Option<i64>,
332   community_id: Option<i32>,
333   saved_only: bool,
334   auth: Option<String>,
335 }
336
337 #[derive(Serialize, Deserialize)]
338 pub struct GetUserDetailsResponse {
339   op: String,
340   user: UserView,
341   follows: Vec<CommunityFollowerView>,
342   moderates: Vec<CommunityModeratorView>,
343   comments: Vec<CommentView>,
344   posts: Vec<PostView>,
345 }
346
347 #[derive(Serialize, Deserialize)]
348 pub struct GetModlog {
349   mod_user_id: Option<i32>,
350   community_id: Option<i32>,
351   page: Option<i64>,
352   limit: Option<i64>,
353 }
354
355 #[derive(Serialize, Deserialize)]
356 pub struct GetModlogResponse {
357   op: String,
358   removed_posts: Vec<ModRemovePostView>,
359   locked_posts: Vec<ModLockPostView>,
360   removed_comments: Vec<ModRemoveCommentView>,
361   removed_communities: Vec<ModRemoveCommunityView>,
362   banned_from_community: Vec<ModBanFromCommunityView>,
363   banned: Vec<ModBanView>,
364   added_to_community: Vec<ModAddCommunityView>,
365   added: Vec<ModAddView>,
366 }
367
368 #[derive(Serialize, Deserialize)]
369 pub struct BanFromCommunity {
370   community_id: i32,
371   user_id: i32,
372   ban: bool,
373   reason: Option<String>,
374   expires: Option<i64>,
375   auth: String
376 }
377
378 #[derive(Serialize, Deserialize)]
379 pub struct BanFromCommunityResponse {
380   op: String,
381   user: UserView,
382   banned: bool,
383 }
384
385
386 #[derive(Serialize, Deserialize)]
387 pub struct AddModToCommunity {
388   community_id: i32,
389   user_id: i32,
390   added: bool,
391   auth: String
392 }
393
394 #[derive(Serialize, Deserialize)]
395 pub struct AddModToCommunityResponse {
396   op: String,
397   moderators: Vec<CommunityModeratorView>,
398 }
399
400 #[derive(Serialize, Deserialize)]
401 pub struct CreateSite {
402   name: String,
403   description: Option<String>,
404   auth: String
405 }
406
407 #[derive(Serialize, Deserialize)]
408 pub struct EditSite {
409   name: String,
410   description: Option<String>,
411   auth: String
412 }
413
414 #[derive(Serialize, Deserialize)]
415 pub struct GetSite {
416 }
417
418 #[derive(Serialize, Deserialize)]
419 pub struct SiteResponse {
420   op: String,
421   site: SiteView,
422 }
423
424 #[derive(Serialize, Deserialize)]
425 pub struct GetSiteResponse {
426   op: String,
427   site: Option<SiteView>,
428   admins: Vec<UserView>,
429   banned: Vec<UserView>,
430 }
431
432 #[derive(Serialize, Deserialize)]
433 pub struct AddAdmin {
434   user_id: i32,
435   added: bool,
436   auth: String
437 }
438
439 #[derive(Serialize, Deserialize)]
440 pub struct AddAdminResponse {
441   op: String,
442   admins: Vec<UserView>,
443 }
444
445 #[derive(Serialize, Deserialize)]
446 pub struct BanUser {
447   user_id: i32,
448   ban: bool,
449   reason: Option<String>,
450   expires: Option<i64>,
451   auth: String
452 }
453
454 #[derive(Serialize, Deserialize)]
455 pub struct BanUserResponse {
456   op: String,
457   user: UserView,
458   banned: bool,
459 }
460
461 #[derive(Serialize, Deserialize)]
462 pub struct GetReplies {
463   sort: String,
464   page: Option<i64>,
465   limit: Option<i64>,
466   unread_only: bool,
467   auth: String
468 }
469
470 #[derive(Serialize, Deserialize)]
471 pub struct GetRepliesResponse {
472   op: String,
473   replies: Vec<ReplyView>,
474 }
475
476 #[derive(Serialize, Deserialize)]
477 pub struct Search {
478   q: String,
479   type_: String,
480   community_id: Option<i32>,
481   sort: String,
482   page: Option<i64>,
483   limit: Option<i64>,
484 }
485
486 #[derive(Serialize, Deserialize)]
487 pub struct SearchResponse {
488   op: String,
489   comments: Vec<CommentView>,
490   posts: Vec<PostView>,
491 }
492
493 #[derive(Serialize, Deserialize)]
494 pub struct MarkAllAsRead {
495   auth: String
496 }
497
498 #[derive(Debug)]
499 pub struct RateLimitBucket {
500   last_checked: SystemTime,
501   allowance: f64
502 }
503
504 pub struct SessionInfo {
505   pub addr: Recipient<WSMessage>,
506   pub ip: String,
507 }
508
509 /// `ChatServer` manages chat rooms and responsible for coordinating chat
510 /// session. implementation is super primitive
511 pub struct ChatServer {
512   sessions: HashMap<usize, SessionInfo>, // A map from generated random ID to session addr
513   rate_limits: HashMap<String, RateLimitBucket>,
514   rooms: HashMap<i32, HashSet<usize>>, // A map from room / post name to set of connectionIDs
515   rng: ThreadRng,
516 }
517
518 impl Default for ChatServer {
519   fn default() -> ChatServer {
520     // default room
521     let rooms = HashMap::new();
522
523     ChatServer {
524       sessions: HashMap::new(),
525       rate_limits: HashMap::new(),
526       rooms: rooms,
527       rng: rand::thread_rng(),
528     }
529   }
530 }
531
532 impl ChatServer {
533   /// Send message to all users in the room
534   fn send_room_message(&self, room: i32, message: &str, skip_id: usize) {
535     if let Some(sessions) = self.rooms.get(&room) {
536       for id in sessions {
537         if *id != skip_id {
538           if let Some(info) = self.sessions.get(id) {
539             let _ = info.addr.do_send(WSMessage(message.to_owned()));
540           }
541         }
542       }
543     }
544   }
545
546   fn send_community_message(&self, conn: &PgConnection, community_id: i32, message: &str, skip_id: usize) -> Result<(), Error> {
547     let posts = PostView::list(conn,
548                                PostListingType::Community, 
549                                &SortType::New, 
550                                Some(community_id), 
551                                None,
552                                None, 
553                                None,
554                                false,
555                                false,
556                                None,
557                                Some(9999))?;
558     for post in posts {
559       self.send_room_message(post.id, message, skip_id);
560     }
561
562     Ok(())
563   }
564
565   fn check_rate_limit_register(&mut self, addr: usize) -> Result<(), Error> {
566     self.check_rate_limit_full(addr, RATE_LIMIT_REGISTER_MESSAGES, RATE_LIMIT_REGISTER_PER_SECOND)
567   }
568
569   fn check_rate_limit(&mut self, addr: usize) -> Result<(), Error> {
570     self.check_rate_limit_full(addr, RATE_LIMIT_MESSAGES, RATE_LIMIT_PER_SECOND)
571   }
572
573   fn check_rate_limit_full(&mut self, addr: usize, rate: i32, per: i32) -> Result<(), Error> {
574     if let Some(info) = self.sessions.get(&addr) {
575       if let Some(rate_limit) = self.rate_limits.get_mut(&info.ip) {
576         // The initial value
577         if rate_limit.allowance == -2f64 {
578           rate_limit.allowance = rate as f64;
579         };
580
581         let current = SystemTime::now();
582         let time_passed = current.duration_since(rate_limit.last_checked)?.as_secs() as f64;
583         rate_limit.last_checked = current;
584         rate_limit.allowance += time_passed * (rate as f64 / per as f64);
585         if rate_limit.allowance > rate as f64 {
586           rate_limit.allowance = rate as f64;
587         }
588
589         if rate_limit.allowance < 1.0 {
590           println!("Rate limited IP: {}, time_passed: {}, allowance: {}", &info.ip, time_passed, rate_limit.allowance);
591           Err(ErrorMessage {
592             op: "Rate Limit".to_string(), 
593             message: format!("Too many requests. {} per {} seconds", rate, per),
594           })?
595         } else {
596           rate_limit.allowance -= 1.0;
597           Ok(())
598         }
599       } else {
600         Ok(())
601       }
602     } else {
603       Ok(())
604     }
605   }
606 }
607
608
609 /// Make actor from `ChatServer`
610 impl Actor for ChatServer {
611   /// We are going to use simple Context, we just need ability to communicate
612   /// with other actors.
613   type Context = Context<Self>;
614 }
615
616 /// Handler for Connect message.
617 ///
618 /// Register new session and assign unique id to this session
619 impl Handler<Connect> for ChatServer {
620   type Result = usize;
621
622   fn handle(&mut self, msg: Connect, _ctx: &mut Context<Self>) -> Self::Result {
623
624     // notify all users in same room
625     // self.send_room_message(&"Main".to_owned(), "Someone joined", 0);
626
627     // register session with random id
628     let id = self.rng.gen::<usize>();
629     println!("{} joined", &msg.ip);
630
631     self.sessions.insert(id, SessionInfo {
632       addr: msg.addr,
633       ip: msg.ip.to_owned(),
634     });
635
636     if self.rate_limits.get(&msg.ip).is_none() {
637       self.rate_limits.insert(msg.ip, RateLimitBucket {
638         last_checked: SystemTime::now(),
639         allowance: -2f64,
640       });
641     }
642
643     // for (k,v) in &self.rate_limits {
644     //   println!("{}: {:?}", k,v);
645     // }
646
647     // auto join session to Main room
648     // self.rooms.get_mut(&"Main".to_owned()).unwrap().insert(id);
649
650     // send id back
651     id
652   }
653 }
654
655
656 /// Handler for Disconnect message.
657 impl Handler<Disconnect> for ChatServer {
658   type Result = ();
659
660   fn handle(&mut self, msg: Disconnect, _: &mut Context<Self>) {
661
662     // let mut rooms: Vec<i32> = Vec::new();
663
664     // remove address
665     if self.sessions.remove(&msg.id).is_some() {
666       // remove session from all rooms
667       for (_id, sessions) in &mut self.rooms {
668         if sessions.remove(&msg.id) {
669           // rooms.push(*id);
670         }
671       }
672     }
673   }
674 }
675
676 /// Handler for Message message.
677 impl Handler<StandardMessage> for ChatServer {
678   type Result = MessageResult<StandardMessage>;
679
680
681   fn handle(&mut self, msg: StandardMessage, _: &mut Context<Self>) -> Self::Result {
682
683     let msg_out = match parse_json_message(self, msg) {
684       Ok(m) => m,
685       Err(e) => e.to_string()
686     };
687
688     MessageResult(msg_out)
689   }
690 }
691
692 fn parse_json_message(chat: &mut ChatServer, msg: StandardMessage) -> Result<String, Error> {
693
694   let json: Value = serde_json::from_str(&msg.msg)?;
695   let data = &json["data"].to_string();
696   let op = &json["op"].as_str().unwrap();
697
698   let user_operation: UserOperation = UserOperation::from_str(&op)?;
699
700   match user_operation {
701     UserOperation::Login => {
702       let login: Login = serde_json::from_str(data)?;
703       login.perform(chat, msg.id)
704     },
705     UserOperation::Register => {
706       let register: Register = serde_json::from_str(data)?;
707       register.perform(chat, msg.id)
708     },
709     UserOperation::CreateCommunity => {
710       let create_community: CreateCommunity = serde_json::from_str(data)?;
711       create_community.perform(chat, msg.id)
712     },
713     UserOperation::ListCommunities => {
714       let list_communities: ListCommunities = serde_json::from_str(data)?;
715       list_communities.perform(chat, msg.id)
716     },
717     UserOperation::ListCategories => {
718       let list_categories: ListCategories = ListCategories;
719       list_categories.perform(chat, msg.id)
720     },
721     UserOperation::CreatePost => {
722       let create_post: CreatePost = serde_json::from_str(data)?;
723       create_post.perform(chat, msg.id)
724     },
725     UserOperation::GetPost => {
726       let get_post: GetPost = serde_json::from_str(data)?;
727       get_post.perform(chat, msg.id)
728     },
729     UserOperation::GetCommunity => {
730       let get_community: GetCommunity = serde_json::from_str(data)?;
731       get_community.perform(chat, msg.id)
732     },
733     UserOperation::CreateComment => {
734       let create_comment: CreateComment = serde_json::from_str(data)?;
735       create_comment.perform(chat, msg.id)
736     },
737     UserOperation::EditComment => {
738       let edit_comment: EditComment = serde_json::from_str(data)?;
739       edit_comment.perform(chat, msg.id)
740     },
741     UserOperation::SaveComment => {
742       let save_post: SaveComment = serde_json::from_str(data)?;
743       save_post.perform(chat, msg.id)
744     },
745     UserOperation::CreateCommentLike => {
746       let create_comment_like: CreateCommentLike = serde_json::from_str(data)?;
747       create_comment_like.perform(chat, msg.id)
748     },
749     UserOperation::GetPosts => {
750       let get_posts: GetPosts = serde_json::from_str(data)?;
751       get_posts.perform(chat, msg.id)
752     },
753     UserOperation::CreatePostLike => {
754       let create_post_like: CreatePostLike = serde_json::from_str(data)?;
755       create_post_like.perform(chat, msg.id)
756     },
757     UserOperation::EditPost => {
758       let edit_post: EditPost = serde_json::from_str(data)?;
759       edit_post.perform(chat, msg.id)
760     },
761     UserOperation::SavePost => {
762       let save_post: SavePost = serde_json::from_str(data)?;
763       save_post.perform(chat, msg.id)
764     },
765     UserOperation::EditCommunity => {
766       let edit_community: EditCommunity = serde_json::from_str(data)?;
767       edit_community.perform(chat, msg.id)
768     },
769     UserOperation::FollowCommunity => {
770       let follow_community: FollowCommunity = serde_json::from_str(data)?;
771       follow_community.perform(chat, msg.id)
772     },
773     UserOperation::GetFollowedCommunities => {
774       let followed_communities: GetFollowedCommunities = serde_json::from_str(data)?;
775       followed_communities.perform(chat, msg.id)
776     },
777     UserOperation::GetUserDetails => {
778       let get_user_details: GetUserDetails = serde_json::from_str(data)?;
779       get_user_details.perform(chat, msg.id)
780     },
781     UserOperation::GetModlog => {
782       let get_modlog: GetModlog = serde_json::from_str(data)?;
783       get_modlog.perform(chat, msg.id)
784     },
785     UserOperation::BanFromCommunity => {
786       let ban_from_community: BanFromCommunity = serde_json::from_str(data)?;
787       ban_from_community.perform(chat, msg.id)
788     },
789     UserOperation::AddModToCommunity => {
790       let mod_add_to_community: AddModToCommunity = serde_json::from_str(data)?;
791       mod_add_to_community.perform(chat, msg.id)
792     },
793     UserOperation::CreateSite => {
794       let create_site: CreateSite = serde_json::from_str(data)?;
795       create_site.perform(chat, msg.id)
796     },
797     UserOperation::EditSite => {
798       let edit_site: EditSite = serde_json::from_str(data)?;
799       edit_site.perform(chat, msg.id)
800     },
801     UserOperation::GetSite => {
802       let get_site: GetSite = serde_json::from_str(data)?;
803       get_site.perform(chat, msg.id)
804     },
805     UserOperation::AddAdmin => {
806       let add_admin: AddAdmin = serde_json::from_str(data)?;
807       add_admin.perform(chat, msg.id)
808     },
809     UserOperation::BanUser => {
810       let ban_user: BanUser = serde_json::from_str(data)?;
811       ban_user.perform(chat, msg.id)
812     },
813     UserOperation::GetReplies => {
814       let get_replies: GetReplies = serde_json::from_str(data)?;
815       get_replies.perform(chat, msg.id)
816     },
817     UserOperation::Search => {
818       let search: Search = serde_json::from_str(data)?;
819       search.perform(chat, msg.id)
820     },
821     UserOperation::MarkAllAsRead => {
822       let mark_all_as_read: MarkAllAsRead = serde_json::from_str(data)?;
823       mark_all_as_read.perform(chat, msg.id)
824     },
825   }
826 }
827
828 pub trait Perform {
829   fn perform(&self, _chat: &mut ChatServer, _addr: usize) -> Result<String, Error>;
830   fn op_type(&self) -> UserOperation;
831   fn error(&self, error_msg: &str) -> ErrorMessage {
832     ErrorMessage {
833       op: self.op_type().to_string(), 
834       message: error_msg.to_string()
835     }
836   }
837 }
838
839 impl Perform for Login {
840
841   fn op_type(&self) -> UserOperation {
842     UserOperation::Login
843   }
844
845   fn perform(&self, _chat: &mut ChatServer, _addr: usize) -> Result<String, Error> {
846
847     let conn = establish_connection();
848
849     // Fetch that username / email
850     let user: User_ = match User_::find_by_email_or_username(&conn, &self.username_or_email) {
851       Ok(user) => user,
852       Err(_e) => return Err(self.error("Couldn't find that username or email"))?
853     };
854
855     // Verify the password
856     let valid: bool = verify(&self.password, &user.password_encrypted).unwrap_or(false);
857     if !valid {
858       return Err(self.error("Password incorrect"))?
859     }
860
861     // Return the jwt
862     Ok(
863       serde_json::to_string(
864         &LoginResponse {
865           op: self.op_type().to_string(),
866           jwt: user.jwt()
867         }
868         )?
869       )
870   }
871
872 }
873
874 impl Perform for Register {
875   fn op_type(&self) -> UserOperation {
876     UserOperation::Register
877   }
878   fn perform(&self, chat: &mut ChatServer, addr: usize) -> Result<String, Error> {
879
880     let conn = establish_connection();
881
882     chat.check_rate_limit_register(addr)?;
883
884     // Make sure passwords match
885     if &self.password != &self.password_verify {
886       return Err(self.error("Passwords do not match."))?
887     }
888
889     if self.spam_timeri < 1142 {
890       return Err(self.error("Too fast"))?
891     }
892
893     if has_slurs(&self.username) {
894       return Err(self.error("No slurs"))?
895     }
896
897     // Make sure there are no admins
898     if self.admin && UserView::admins(&conn)?.len() > 0 {
899       return Err(self.error("Sorry, there's already an admin."))?
900     }
901
902     // Register the new user
903     let user_form = UserForm {
904       name: self.username.to_owned(),
905       fedi_name: Settings::get().hostname.into(),
906       email: self.email.to_owned(),
907       password_encrypted: self.password.to_owned(),
908       preferred_username: None,
909       updated: None,
910       admin: self.admin,
911       banned: false,
912     };
913
914     // Create the user
915     let inserted_user = match User_::register(&conn, &user_form) {
916       Ok(user) => user,
917       Err(_e) => {
918         return Err(self.error("User already exists."))?
919       }
920     };
921
922     // Sign them up for main community no matter what
923     let community_follower_form = CommunityFollowerForm {
924       community_id: 1,
925       user_id: inserted_user.id,
926     };
927
928     let _inserted_community_follower = match CommunityFollower::follow(&conn, &community_follower_form) {
929       Ok(user) => user,
930       Err(_e) => {
931         return Err(self.error("Community follower already exists."))?
932       }
933     };
934
935     // If its an admin, add them as a mod and follower to main
936     if self.admin {
937       let community_moderator_form = CommunityModeratorForm {
938         community_id: 1,
939         user_id: inserted_user.id,
940       };
941
942       let _inserted_community_moderator = match CommunityModerator::join(&conn, &community_moderator_form) {
943         Ok(user) => user,
944         Err(_e) => {
945           return Err(self.error("Community moderator already exists."))?
946         }
947       };
948
949     }
950
951
952     // Return the jwt
953     Ok(
954       serde_json::to_string(
955         &LoginResponse {
956           op: self.op_type().to_string(), 
957           jwt: inserted_user.jwt()
958         }
959         )?
960       )
961
962   }
963 }
964
965 impl Perform for CreateCommunity {
966   fn op_type(&self) -> UserOperation {
967     UserOperation::CreateCommunity
968   }
969
970   fn perform(&self, chat: &mut ChatServer, addr: usize) -> Result<String, Error> {
971
972     let conn = establish_connection();
973
974     chat.check_rate_limit_register(addr)?;
975
976     let claims = match Claims::decode(&self.auth) {
977       Ok(claims) => claims.claims,
978       Err(_e) => {
979         return Err(self.error("Not logged in."))?
980       }
981     };
982
983     if has_slurs(&self.name) || 
984       has_slurs(&self.title) || 
985         (self.description.is_some() && has_slurs(&self.description.to_owned().unwrap())) {
986           return Err(self.error("No slurs"))?
987         }
988
989     let user_id = claims.id;
990
991     // Check for a site ban
992     if UserView::read(&conn, user_id)?.banned {
993       return Err(self.error("You have been banned from the site"))?
994     }
995
996     // When you create a community, make sure the user becomes a moderator and a follower
997     let community_form = CommunityForm {
998       name: self.name.to_owned(),
999       title: self.title.to_owned(),
1000       description: self.description.to_owned(),
1001       category_id: self.category_id,
1002       creator_id: user_id,
1003       removed: None,
1004       deleted: None,
1005       updated: None,
1006     };
1007
1008     let inserted_community = match Community::create(&conn, &community_form) {
1009       Ok(community) => community,
1010       Err(_e) => {
1011         return Err(self.error("Community already exists."))?
1012       }
1013     };
1014
1015     let community_moderator_form = CommunityModeratorForm {
1016       community_id: inserted_community.id,
1017       user_id: user_id
1018     };
1019
1020     let _inserted_community_moderator = match CommunityModerator::join(&conn, &community_moderator_form) {
1021       Ok(user) => user,
1022       Err(_e) => {
1023         return Err(self.error("Community moderator already exists."))?
1024       }
1025     };
1026
1027     let community_follower_form = CommunityFollowerForm {
1028       community_id: inserted_community.id,
1029       user_id: user_id
1030     };
1031
1032     let _inserted_community_follower = match CommunityFollower::follow(&conn, &community_follower_form) {
1033       Ok(user) => user,
1034       Err(_e) => {
1035         return Err(self.error("Community follower already exists."))?
1036       }
1037     };
1038
1039     let community_view = CommunityView::read(&conn, inserted_community.id, Some(user_id))?;
1040
1041     Ok(
1042       serde_json::to_string(
1043         &CommunityResponse {
1044           op: self.op_type().to_string(), 
1045           community: community_view
1046         }
1047         )?
1048       )
1049   }
1050 }
1051
1052 impl Perform for ListCommunities {
1053   fn op_type(&self) -> UserOperation {
1054     UserOperation::ListCommunities
1055   }
1056
1057   fn perform(&self, _chat: &mut ChatServer, _addr: usize) -> Result<String, Error> {
1058
1059     let conn = establish_connection();
1060
1061     let user_id: Option<i32> = match &self.auth {
1062       Some(auth) => {
1063         match Claims::decode(&auth) {
1064           Ok(claims) => {
1065             let user_id = claims.claims.id;
1066             Some(user_id)
1067           }
1068           Err(_e) => None
1069         }
1070       }
1071       None => None
1072     };
1073
1074     let sort = SortType::from_str(&self.sort)?;
1075
1076     let communities: Vec<CommunityView> = CommunityView::list(&conn, user_id, sort, self.page, self.limit)?;
1077
1078     // Return the jwt
1079     Ok(
1080       serde_json::to_string(
1081         &ListCommunitiesResponse {
1082           op: self.op_type().to_string(),
1083           communities: communities
1084         }
1085         )?
1086       )
1087   }
1088 }
1089
1090 impl Perform for ListCategories {
1091   fn op_type(&self) -> UserOperation {
1092     UserOperation::ListCategories
1093   }
1094
1095   fn perform(&self, _chat: &mut ChatServer, _addr: usize) -> Result<String, Error> {
1096
1097     let conn = establish_connection();
1098
1099     let categories: Vec<Category> = Category::list_all(&conn)?;
1100
1101     // Return the jwt
1102     Ok(
1103       serde_json::to_string(
1104         &ListCategoriesResponse {
1105           op: self.op_type().to_string(),
1106           categories: categories
1107         }
1108         )?
1109       )
1110   }
1111 }
1112
1113 impl Perform for CreatePost {
1114   fn op_type(&self) -> UserOperation {
1115     UserOperation::CreatePost
1116   }
1117
1118   fn perform(&self, chat: &mut ChatServer, addr: usize) -> Result<String, Error> {
1119
1120     let conn = establish_connection();
1121
1122     chat.check_rate_limit_register(addr)?;
1123
1124     let claims = match Claims::decode(&self.auth) {
1125       Ok(claims) => claims.claims,
1126       Err(_e) => {
1127         return Err(self.error("Not logged in."))?
1128       }
1129     };
1130
1131     if has_slurs(&self.name) || 
1132       (self.body.is_some() && has_slurs(&self.body.to_owned().unwrap())) {
1133         return Err(self.error("No slurs"))?
1134       }
1135
1136     let user_id = claims.id;
1137
1138     // Check for a community ban
1139     if CommunityUserBanView::get(&conn, user_id, self.community_id).is_ok() {
1140       return Err(self.error("You have been banned from this community"))?
1141     }
1142
1143     // Check for a site ban
1144     if UserView::read(&conn, user_id)?.banned {
1145       return Err(self.error("You have been banned from the site"))?
1146     }
1147
1148     let post_form = PostForm {
1149       name: self.name.to_owned(),
1150       url: self.url.to_owned(),
1151       body: self.body.to_owned(),
1152       community_id: self.community_id,
1153       creator_id: user_id,
1154       removed: None,
1155       deleted: None,
1156       locked: None,
1157       updated: None
1158     };
1159
1160     let inserted_post = match Post::create(&conn, &post_form) {
1161       Ok(post) => post,
1162       Err(_e) => {
1163         return Err(self.error("Couldn't create Post"))?
1164       }
1165     };
1166
1167     // They like their own post by default
1168     let like_form = PostLikeForm {
1169       post_id: inserted_post.id,
1170       user_id: user_id,
1171       score: 1
1172     };
1173
1174     // Only add the like if the score isnt 0
1175     let _inserted_like = match PostLike::like(&conn, &like_form) {
1176       Ok(like) => like,
1177       Err(_e) => {
1178         return Err(self.error("Couldn't like post."))?
1179       }
1180     };
1181
1182     // Refetch the view
1183     let post_view = match PostView::read(&conn, inserted_post.id, Some(user_id)) {
1184       Ok(post) => post,
1185       Err(_e) => {
1186         return Err(self.error("Couldn't find Post"))?
1187       }
1188     };
1189
1190     Ok(
1191       serde_json::to_string(
1192         &PostResponse {
1193           op: self.op_type().to_string(), 
1194           post: post_view
1195         }
1196         )?
1197       )
1198   }
1199 }
1200
1201
1202 impl Perform for GetPost {
1203   fn op_type(&self) -> UserOperation {
1204     UserOperation::GetPost
1205   }
1206
1207   fn perform(&self, chat: &mut ChatServer, addr: usize) -> Result<String, Error> {
1208
1209     let conn = establish_connection();
1210
1211     let user_id: Option<i32> = match &self.auth {
1212       Some(auth) => {
1213         match Claims::decode(&auth) {
1214           Ok(claims) => {
1215             let user_id = claims.claims.id;
1216             Some(user_id)
1217           }
1218           Err(_e) => None
1219         }
1220       }
1221       None => None
1222     };
1223
1224     let post_view = match PostView::read(&conn, self.id, user_id) {
1225       Ok(post) => post,
1226       Err(_e) => {
1227         return Err(self.error("Couldn't find Post"))?
1228       }
1229     };
1230
1231     // remove session from all rooms
1232     for (_n, sessions) in &mut chat.rooms {
1233       sessions.remove(&addr);
1234     }
1235
1236     // If the room doesn't exist yet
1237     if chat.rooms.get_mut(&self.id).is_none() {
1238       chat.rooms.insert(self.id, HashSet::new());
1239     }
1240
1241     chat.rooms.get_mut(&self.id).unwrap().insert(addr);
1242
1243     let comments = CommentView::list(&conn, &SortType::New, Some(self.id), None, None, user_id, false, None, Some(9999))?;
1244
1245     let community = CommunityView::read(&conn, post_view.community_id, user_id)?;
1246
1247     let moderators = CommunityModeratorView::for_community(&conn, post_view.community_id)?;
1248
1249     let admins = UserView::admins(&conn)?;
1250
1251     // Return the jwt
1252     Ok(
1253       serde_json::to_string(
1254         &GetPostResponse {
1255           op: self.op_type().to_string(),
1256           post: post_view,
1257           comments: comments,
1258           community: community,
1259           moderators: moderators,
1260           admins: admins,
1261         }
1262         )?
1263       )
1264   }
1265 }
1266
1267 impl Perform for GetCommunity {
1268   fn op_type(&self) -> UserOperation {
1269     UserOperation::GetCommunity
1270   }
1271
1272   fn perform(&self, _chat: &mut ChatServer, _addr: usize) -> Result<String, Error> {
1273
1274     let conn = establish_connection();
1275
1276     let user_id: Option<i32> = match &self.auth {
1277       Some(auth) => {
1278         match Claims::decode(&auth) {
1279           Ok(claims) => {
1280             let user_id = claims.claims.id;
1281             Some(user_id)
1282           }
1283           Err(_e) => None
1284         }
1285       }
1286       None => None
1287     };
1288
1289     let community_id = match self.id {
1290       Some(id) => id,
1291       None => Community::read_from_name(&conn, self.name.to_owned().unwrap_or("main".to_string()))?.id
1292     };
1293
1294     let community_view = match CommunityView::read(&conn, community_id, user_id) {
1295       Ok(community) => community,
1296       Err(_e) => {
1297         return Err(self.error("Couldn't find Community"))?
1298       }
1299     };
1300
1301     let moderators = match CommunityModeratorView::for_community(&conn, community_id) {
1302       Ok(moderators) => moderators,
1303       Err(_e) => {
1304         return Err(self.error("Couldn't find Community"))?
1305       }
1306     };
1307
1308     let admins = UserView::admins(&conn)?;
1309
1310     // Return the jwt
1311     Ok(
1312       serde_json::to_string(
1313         &GetCommunityResponse {
1314           op: self.op_type().to_string(),
1315           community: community_view,
1316           moderators: moderators,
1317           admins: admins,
1318         }
1319         )?
1320       )
1321   }
1322 }
1323
1324 impl Perform for CreateComment {
1325   fn op_type(&self) -> UserOperation {
1326     UserOperation::CreateComment
1327   }
1328
1329   fn perform(&self, chat: &mut ChatServer, addr: usize) -> Result<String, Error> {
1330
1331     let conn = establish_connection();
1332
1333     chat.check_rate_limit(addr)?;
1334
1335     let claims = match Claims::decode(&self.auth) {
1336       Ok(claims) => claims.claims,
1337       Err(_e) => {
1338         return Err(self.error("Not logged in."))?
1339       }
1340     };
1341
1342     let user_id = claims.id;
1343
1344     // Check for a community ban
1345     let post = Post::read(&conn, self.post_id)?;
1346     if CommunityUserBanView::get(&conn, user_id, post.community_id).is_ok() {
1347       return Err(self.error("You have been banned from this community"))?
1348     }
1349
1350     // Check for a site ban
1351     if UserView::read(&conn, user_id)?.banned {
1352       return Err(self.error("You have been banned from the site"))?
1353     }
1354
1355     let content_slurs_removed = remove_slurs(&self.content.to_owned());
1356
1357     let comment_form = CommentForm {
1358       content: content_slurs_removed,
1359       parent_id: self.parent_id.to_owned(),
1360       post_id: self.post_id,
1361       creator_id: user_id,
1362       removed: None,
1363       deleted: None,
1364       read: None,
1365       updated: None
1366     };
1367
1368     let inserted_comment = match Comment::create(&conn, &comment_form) {
1369       Ok(comment) => comment,
1370       Err(_e) => {
1371         return Err(self.error("Couldn't create Comment"))?
1372       }
1373     };
1374
1375     // You like your own comment by default
1376     let like_form = CommentLikeForm {
1377       comment_id: inserted_comment.id,
1378       post_id: self.post_id,
1379       user_id: user_id,
1380       score: 1
1381     };
1382
1383     let _inserted_like = match CommentLike::like(&conn, &like_form) {
1384       Ok(like) => like,
1385       Err(_e) => {
1386         return Err(self.error("Couldn't like comment."))?
1387       }
1388     };
1389
1390     let comment_view = CommentView::read(&conn, inserted_comment.id, Some(user_id))?;
1391
1392     let mut comment_sent = comment_view.clone();
1393     comment_sent.my_vote = None;
1394     comment_sent.user_id = None;
1395
1396     let comment_out = serde_json::to_string(
1397       &CommentResponse {
1398         op: self.op_type().to_string(), 
1399         comment: comment_view
1400       }
1401       )?;
1402
1403     let comment_sent_out = serde_json::to_string(
1404       &CommentResponse {
1405         op: self.op_type().to_string(), 
1406         comment: comment_sent
1407       }
1408       )?;
1409
1410     chat.send_room_message(self.post_id, &comment_sent_out, addr);
1411
1412     Ok(comment_out)
1413   }
1414 }
1415
1416 impl Perform for EditComment {
1417   fn op_type(&self) -> UserOperation {
1418     UserOperation::EditComment
1419   }
1420
1421   fn perform(&self, chat: &mut ChatServer, addr: usize) -> Result<String, Error> {
1422
1423     let conn = establish_connection();
1424
1425     let claims = match Claims::decode(&self.auth) {
1426       Ok(claims) => claims.claims,
1427       Err(_e) => {
1428         return Err(self.error("Not logged in."))?
1429       }
1430     };
1431
1432     let user_id = claims.id;
1433
1434     let orig_comment = CommentView::read(&conn, self.edit_id, None)?;
1435
1436     // You are allowed to mark the comment as read even if you're banned.
1437     if self.read.is_none() {
1438
1439       // Verify its the creator or a mod, or an admin
1440       let mut editors: Vec<i32> = vec![self.creator_id];
1441       editors.append(
1442         &mut CommunityModeratorView::for_community(&conn, orig_comment.community_id)
1443         ?
1444         .into_iter()
1445         .map(|m| m.user_id)
1446         .collect()
1447         );
1448       editors.append(
1449         &mut UserView::admins(&conn)
1450         ?
1451         .into_iter()
1452         .map(|a| a.id)
1453         .collect()
1454         );
1455
1456       if !editors.contains(&user_id) {
1457         return Err(self.error("Not allowed to edit comment."))?
1458       }
1459
1460       // Check for a community ban
1461       if CommunityUserBanView::get(&conn, user_id, orig_comment.community_id).is_ok() {
1462         return Err(self.error("You have been banned from this community"))?
1463       }
1464
1465       // Check for a site ban
1466       if UserView::read(&conn, user_id)?.banned {
1467         return Err(self.error("You have been banned from the site"))?
1468       }
1469
1470     }
1471
1472     let content_slurs_removed = remove_slurs(&self.content.to_owned());
1473
1474     let comment_form = CommentForm {
1475       content: content_slurs_removed,
1476       parent_id: self.parent_id,
1477       post_id: self.post_id,
1478       creator_id: self.creator_id,
1479       removed: self.removed.to_owned(),
1480       deleted: self.deleted.to_owned(),
1481       read: self.read.to_owned(),
1482       updated: if self.read.is_some() { orig_comment.updated } else {Some(naive_now())}
1483     };
1484
1485     let _updated_comment = match Comment::update(&conn, self.edit_id, &comment_form) {
1486       Ok(comment) => comment,
1487       Err(_e) => {
1488         return Err(self.error("Couldn't update Comment"))?
1489       }
1490     };
1491
1492     // Mod tables
1493     if let Some(removed) = self.removed.to_owned() {
1494       let form = ModRemoveCommentForm {
1495         mod_user_id: user_id,
1496         comment_id: self.edit_id,
1497         removed: Some(removed),
1498         reason: self.reason.to_owned(),
1499       };
1500       ModRemoveComment::create(&conn, &form)?;
1501     }
1502
1503
1504     let comment_view = CommentView::read(&conn, self.edit_id, Some(user_id))?;
1505
1506     let mut comment_sent = comment_view.clone();
1507     comment_sent.my_vote = None;
1508     comment_sent.user_id = None;
1509
1510     let comment_out = serde_json::to_string(
1511       &CommentResponse {
1512         op: self.op_type().to_string(), 
1513         comment: comment_view
1514       }
1515       )?;
1516
1517     let comment_sent_out = serde_json::to_string(
1518       &CommentResponse {
1519         op: self.op_type().to_string(), 
1520         comment: comment_sent
1521       }
1522       )?;
1523
1524     chat.send_room_message(self.post_id, &comment_sent_out, addr);
1525
1526     Ok(comment_out)
1527   }
1528 }
1529
1530 impl Perform for SaveComment {
1531   fn op_type(&self) -> UserOperation {
1532     UserOperation::SaveComment
1533   }
1534
1535   fn perform(&self, _chat: &mut ChatServer, _addr: usize) -> Result<String, Error> {
1536
1537     let conn = establish_connection();
1538
1539     let claims = match Claims::decode(&self.auth) {
1540       Ok(claims) => claims.claims,
1541       Err(_e) => {
1542         return Err(self.error("Not logged in."))?
1543       }
1544     };
1545
1546     let user_id = claims.id;
1547
1548     let comment_saved_form = CommentSavedForm {
1549       comment_id: self.comment_id,
1550       user_id: user_id,
1551     };
1552
1553     if self.save {
1554       match CommentSaved::save(&conn, &comment_saved_form) {
1555         Ok(comment) => comment,
1556         Err(_e) => {
1557           return Err(self.error("Couldnt do comment save"))?
1558         }
1559       };
1560     } else {
1561       match CommentSaved::unsave(&conn, &comment_saved_form) {
1562         Ok(comment) => comment,
1563         Err(_e) => {
1564           return Err(self.error("Couldnt do comment save"))?
1565         }
1566       };
1567     }
1568
1569     let comment_view = CommentView::read(&conn, self.comment_id, Some(user_id))?;
1570
1571     let comment_out = serde_json::to_string(
1572       &CommentResponse {
1573         op: self.op_type().to_string(), 
1574         comment: comment_view
1575       }
1576       )
1577       ?;
1578
1579     Ok(comment_out)
1580   }
1581 }
1582
1583
1584 impl Perform for CreateCommentLike {
1585   fn op_type(&self) -> UserOperation {
1586     UserOperation::CreateCommentLike
1587   }
1588
1589   fn perform(&self, chat: &mut ChatServer, addr: usize) -> Result<String, Error> {
1590
1591     let conn = establish_connection();
1592
1593     chat.check_rate_limit(addr)?;
1594
1595     let claims = match Claims::decode(&self.auth) {
1596       Ok(claims) => claims.claims,
1597       Err(_e) => {
1598         return Err(self.error("Not logged in."))?
1599       }
1600     };
1601
1602     let user_id = claims.id;
1603
1604     // Check for a community ban
1605     let post = Post::read(&conn, self.post_id)?;
1606     if CommunityUserBanView::get(&conn, user_id, post.community_id).is_ok() {
1607       return Err(self.error("You have been banned from this community"))?
1608     }
1609
1610     // Check for a site ban
1611     if UserView::read(&conn, user_id)?.banned {
1612       return Err(self.error("You have been banned from the site"))?
1613     }
1614
1615     let like_form = CommentLikeForm {
1616       comment_id: self.comment_id,
1617       post_id: self.post_id,
1618       user_id: user_id,
1619       score: self.score
1620     };
1621
1622     // Remove any likes first
1623     CommentLike::remove(&conn, &like_form)?;
1624
1625     // Only add the like if the score isnt 0
1626     if &like_form.score != &0 {
1627       let _inserted_like = match CommentLike::like(&conn, &like_form) {
1628         Ok(like) => like,
1629         Err(_e) => {
1630           return Err(self.error("Couldn't like comment."))?
1631         }
1632       };
1633     }
1634
1635     // Have to refetch the comment to get the current state
1636     let liked_comment = CommentView::read(&conn, self.comment_id, Some(user_id))?;
1637
1638     let mut liked_comment_sent = liked_comment.clone();
1639     liked_comment_sent.my_vote = None;
1640     liked_comment_sent.user_id = None;
1641
1642     let like_out = serde_json::to_string(
1643       &CommentResponse {
1644         op: self.op_type().to_string(), 
1645         comment: liked_comment
1646       }
1647       )?;
1648
1649     let like_sent_out = serde_json::to_string(
1650       &CommentResponse {
1651         op: self.op_type().to_string(), 
1652         comment: liked_comment_sent
1653       }
1654       )?;
1655
1656     chat.send_room_message(self.post_id, &like_sent_out, addr);
1657
1658     Ok(like_out)
1659   }
1660 }
1661
1662
1663 impl Perform for GetPosts {
1664   fn op_type(&self) -> UserOperation {
1665     UserOperation::GetPosts
1666   }
1667
1668   fn perform(&self, _chat: &mut ChatServer, _addr: usize) -> Result<String, Error> {
1669
1670     let conn = establish_connection();
1671
1672     let user_id: Option<i32> = match &self.auth {
1673       Some(auth) => {
1674         match Claims::decode(&auth) {
1675           Ok(claims) => {
1676             let user_id = claims.claims.id;
1677             Some(user_id)
1678           }
1679           Err(_e) => None
1680         }
1681       }
1682       None => None
1683     };
1684
1685     let type_ = PostListingType::from_str(&self.type_)?;
1686     let sort = SortType::from_str(&self.sort)?;
1687
1688     let posts = match PostView::list(&conn, 
1689                                      type_, 
1690                                      &sort, 
1691                                      self.community_id, 
1692                                      None,
1693                                      None,
1694                                      user_id, 
1695                                      false, 
1696                                      false, 
1697                                      self.page, 
1698                                      self.limit) {
1699       Ok(posts) => posts,
1700       Err(_e) => {
1701         return Err(self.error("Couldn't get posts"))?
1702       }
1703     };
1704
1705     // Return the jwt
1706     Ok(
1707       serde_json::to_string(
1708         &GetPostsResponse {
1709           op: self.op_type().to_string(),
1710           posts: posts
1711         }
1712         )?
1713       )
1714   }
1715 }
1716
1717
1718 impl Perform for CreatePostLike {
1719   fn op_type(&self) -> UserOperation {
1720     UserOperation::CreatePostLike
1721   }
1722
1723   fn perform(&self, chat: &mut ChatServer, addr: usize) -> Result<String, Error> {
1724
1725     let conn = establish_connection();
1726
1727     chat.check_rate_limit(addr)?;
1728
1729     let claims = match Claims::decode(&self.auth) {
1730       Ok(claims) => claims.claims,
1731       Err(_e) => {
1732         return Err(self.error("Not logged in."))?
1733       }
1734     };
1735
1736     let user_id = claims.id;
1737
1738     // Check for a community ban
1739     let post = Post::read(&conn, self.post_id)?;
1740     if CommunityUserBanView::get(&conn, user_id, post.community_id).is_ok() {
1741       return Err(self.error("You have been banned from this community"))?
1742     }
1743
1744     // Check for a site ban
1745     if UserView::read(&conn, user_id)?.banned {
1746       return Err(self.error("You have been banned from the site"))?
1747     }
1748
1749     let like_form = PostLikeForm {
1750       post_id: self.post_id,
1751       user_id: user_id,
1752       score: self.score
1753     };
1754
1755     // Remove any likes first
1756     PostLike::remove(&conn, &like_form)?;
1757
1758     // Only add the like if the score isnt 0
1759     if &like_form.score != &0 {
1760       let _inserted_like = match PostLike::like(&conn, &like_form) {
1761         Ok(like) => like,
1762         Err(_e) => {
1763           return Err(self.error("Couldn't like post."))?
1764         }
1765       };
1766     }
1767
1768     let post_view = match PostView::read(&conn, self.post_id, Some(user_id)) {
1769       Ok(post) => post,
1770       Err(_e) => {
1771         return Err(self.error("Couldn't find Post"))?
1772       }
1773     };
1774
1775     // just output the score
1776
1777     let like_out = serde_json::to_string(
1778       &CreatePostLikeResponse {
1779         op: self.op_type().to_string(), 
1780         post: post_view
1781       }
1782       )?;
1783
1784     Ok(like_out)
1785   }
1786 }
1787
1788 impl Perform for EditPost {
1789   fn op_type(&self) -> UserOperation {
1790     UserOperation::EditPost
1791   }
1792
1793   fn perform(&self, chat: &mut ChatServer, addr: usize) -> Result<String, Error> {
1794
1795     if has_slurs(&self.name) || 
1796       (self.body.is_some() && has_slurs(&self.body.to_owned().unwrap())) {
1797         return Err(self.error("No slurs"))?
1798       }
1799
1800     let conn = establish_connection();
1801
1802     let claims = match Claims::decode(&self.auth) {
1803       Ok(claims) => claims.claims,
1804       Err(_e) => {
1805         return Err(self.error("Not logged in."))?
1806       }
1807     };
1808
1809     let user_id = claims.id;
1810
1811     // Verify its the creator or a mod or admin
1812     let mut editors: Vec<i32> = vec![self.creator_id];
1813     editors.append(
1814       &mut CommunityModeratorView::for_community(&conn, self.community_id)
1815       ?
1816       .into_iter()
1817       .map(|m| m.user_id)
1818       .collect()
1819       );
1820     editors.append(
1821       &mut UserView::admins(&conn)
1822       ?
1823       .into_iter()
1824       .map(|a| a.id)
1825       .collect()
1826       );
1827     if !editors.contains(&user_id) {
1828       return Err(self.error("Not allowed to edit post."))?
1829     }
1830
1831     // Check for a community ban
1832     if CommunityUserBanView::get(&conn, user_id, self.community_id).is_ok() {
1833       return Err(self.error("You have been banned from this community"))?
1834     }
1835
1836     // Check for a site ban
1837     if UserView::read(&conn, user_id)?.banned {
1838       return Err(self.error("You have been banned from the site"))?
1839     }
1840
1841     let post_form = PostForm {
1842       name: self.name.to_owned(),
1843       url: self.url.to_owned(),
1844       body: self.body.to_owned(),
1845       creator_id: self.creator_id.to_owned(),
1846       community_id: self.community_id,
1847       removed: self.removed.to_owned(),
1848       deleted: self.deleted.to_owned(),
1849       locked: self.locked.to_owned(),
1850       updated: Some(naive_now())
1851     };
1852
1853     let _updated_post = match Post::update(&conn, self.edit_id, &post_form) {
1854       Ok(post) => post,
1855       Err(_e) => {
1856         return Err(self.error("Couldn't update Post"))?
1857       }
1858     };
1859
1860     // Mod tables
1861     if let Some(removed) = self.removed.to_owned() {
1862       let form = ModRemovePostForm {
1863         mod_user_id: user_id,
1864         post_id: self.edit_id,
1865         removed: Some(removed),
1866         reason: self.reason.to_owned(),
1867       };
1868       ModRemovePost::create(&conn, &form)?;
1869     }
1870
1871     if let Some(locked) = self.locked.to_owned() {
1872       let form = ModLockPostForm {
1873         mod_user_id: user_id,
1874         post_id: self.edit_id,
1875         locked: Some(locked),
1876       };
1877       ModLockPost::create(&conn, &form)?;
1878     }
1879
1880     let post_view = PostView::read(&conn, self.edit_id, Some(user_id))?;
1881
1882     let mut post_sent = post_view.clone();
1883     post_sent.my_vote = None;
1884
1885     let post_out = serde_json::to_string(
1886       &PostResponse {
1887         op: self.op_type().to_string(), 
1888         post: post_view
1889       }
1890       )
1891       ?;
1892
1893     let post_sent_out = serde_json::to_string(
1894       &PostResponse {
1895         op: self.op_type().to_string(), 
1896         post: post_sent
1897       }
1898       )
1899       ?;
1900
1901     chat.send_room_message(self.edit_id, &post_sent_out, addr);
1902
1903     Ok(post_out)
1904   }
1905 }
1906
1907 impl Perform for SavePost {
1908   fn op_type(&self) -> UserOperation {
1909     UserOperation::SavePost
1910   }
1911
1912   fn perform(&self, _chat: &mut ChatServer, _addr: usize) -> Result<String, Error> {
1913
1914     let conn = establish_connection();
1915
1916     let claims = match Claims::decode(&self.auth) {
1917       Ok(claims) => claims.claims,
1918       Err(_e) => {
1919         return Err(self.error("Not logged in."))?
1920       }
1921     };
1922
1923     let user_id = claims.id;
1924
1925     let post_saved_form = PostSavedForm {
1926       post_id: self.post_id,
1927       user_id: user_id,
1928     };
1929
1930     if self.save {
1931       match PostSaved::save(&conn, &post_saved_form) {
1932         Ok(post) => post,
1933         Err(_e) => {
1934           return Err(self.error("Couldnt do post save"))?
1935         }
1936       };
1937     } else {
1938       match PostSaved::unsave(&conn, &post_saved_form) {
1939         Ok(post) => post,
1940         Err(_e) => {
1941           return Err(self.error("Couldnt do post save"))?
1942         }
1943       };
1944     }
1945
1946     let post_view = PostView::read(&conn, self.post_id, Some(user_id))?;
1947
1948     let post_out = serde_json::to_string(
1949       &PostResponse {
1950         op: self.op_type().to_string(), 
1951         post: post_view
1952       }
1953       )
1954       ?;
1955
1956     Ok(post_out)
1957   }
1958 }
1959
1960 impl Perform for EditCommunity {
1961   fn op_type(&self) -> UserOperation {
1962     UserOperation::EditCommunity
1963   }
1964
1965   fn perform(&self, chat: &mut ChatServer, addr: usize) -> Result<String, Error> {
1966
1967     if has_slurs(&self.name) || has_slurs(&self.title) {
1968       return Err(self.error("No slurs"))?
1969     }
1970
1971     let conn = establish_connection();
1972
1973     let claims = match Claims::decode(&self.auth) {
1974       Ok(claims) => claims.claims,
1975       Err(_e) => {
1976         return Err(self.error("Not logged in."))?
1977       }
1978     };
1979
1980     let user_id = claims.id;
1981
1982     // Check for a site ban
1983     if UserView::read(&conn, user_id)?.banned {
1984       return Err(self.error("You have been banned from the site"))?
1985     }
1986
1987     // Verify its a mod
1988     let mut editors: Vec<i32> = Vec::new();
1989     editors.append(
1990       &mut CommunityModeratorView::for_community(&conn, self.edit_id)
1991       ?
1992       .into_iter()
1993       .map(|m| m.user_id)
1994       .collect()
1995       );
1996     editors.append(
1997       &mut UserView::admins(&conn)
1998       ?
1999       .into_iter()
2000       .map(|a| a.id)
2001       .collect()
2002       );
2003     if !editors.contains(&user_id) {
2004       return Err(self.error("Not allowed to edit community"))?
2005     }
2006
2007     let community_form = CommunityForm {
2008       name: self.name.to_owned(),
2009       title: self.title.to_owned(),
2010       description: self.description.to_owned(),
2011       category_id: self.category_id.to_owned(),
2012       creator_id: user_id,
2013       removed: self.removed.to_owned(),
2014       deleted: self.deleted.to_owned(),
2015       updated: Some(naive_now())
2016     };
2017
2018     let _updated_community = match Community::update(&conn, self.edit_id, &community_form) {
2019       Ok(community) => community,
2020       Err(_e) => {
2021         return Err(self.error("Couldn't update Community"))?
2022       }
2023     };
2024
2025     // Mod tables
2026     if let Some(removed) = self.removed.to_owned() {
2027       let expires = match self.expires {
2028         Some(time) => Some(naive_from_unix(time)),
2029         None => None
2030       };
2031       let form = ModRemoveCommunityForm {
2032         mod_user_id: user_id,
2033         community_id: self.edit_id,
2034         removed: Some(removed),
2035         reason: self.reason.to_owned(),
2036         expires: expires
2037       };
2038       ModRemoveCommunity::create(&conn, &form)?;
2039     }
2040
2041     let community_view = CommunityView::read(&conn, self.edit_id, Some(user_id))?;
2042
2043     let community_out = serde_json::to_string(
2044       &CommunityResponse {
2045         op: self.op_type().to_string(), 
2046         community: community_view
2047       }
2048       )
2049       ?;
2050
2051     let community_view_sent = CommunityView::read(&conn, self.edit_id, None)?;
2052
2053     let community_sent = serde_json::to_string(
2054       &CommunityResponse {
2055         op: self.op_type().to_string(), 
2056         community: community_view_sent
2057       }
2058       )
2059       ?;
2060
2061     chat.send_community_message(&conn, self.edit_id, &community_sent, addr)?;
2062
2063     Ok(community_out)
2064   }
2065 }
2066
2067
2068 impl Perform for FollowCommunity {
2069   fn op_type(&self) -> UserOperation {
2070     UserOperation::FollowCommunity
2071   }
2072
2073   fn perform(&self, _chat: &mut ChatServer, _addr: usize) -> Result<String, Error> {
2074
2075     let conn = establish_connection();
2076
2077     let claims = match Claims::decode(&self.auth) {
2078       Ok(claims) => claims.claims,
2079       Err(_e) => {
2080         return Err(self.error("Not logged in."))?
2081       }
2082     };
2083
2084     let user_id = claims.id;
2085
2086     let community_follower_form = CommunityFollowerForm {
2087       community_id: self.community_id,
2088       user_id: user_id
2089     };
2090
2091     if self.follow {
2092
2093       match CommunityFollower::follow(&conn, &community_follower_form) {
2094         Ok(user) => user,
2095         Err(_e) => {
2096           return Err(self.error("Community follower already exists."))?
2097         }
2098       };
2099     } else {
2100       match CommunityFollower::ignore(&conn, &community_follower_form) {
2101         Ok(user) => user,
2102         Err(_e) => {
2103           return Err(self.error("Community follower already exists."))?
2104         }
2105       };
2106     }
2107
2108     let community_view = CommunityView::read(&conn, self.community_id, Some(user_id))?;
2109
2110     Ok(
2111       serde_json::to_string(
2112         &CommunityResponse {
2113           op: self.op_type().to_string(), 
2114           community: community_view
2115         }
2116         )?
2117       )
2118   }
2119 }
2120
2121 impl Perform for GetFollowedCommunities {
2122   fn op_type(&self) -> UserOperation {
2123     UserOperation::GetFollowedCommunities
2124   }
2125
2126   fn perform(&self, _chat: &mut ChatServer, _addr: usize) -> Result<String, Error> {
2127
2128     let conn = establish_connection();
2129
2130     let claims = match Claims::decode(&self.auth) {
2131       Ok(claims) => claims.claims,
2132       Err(_e) => {
2133         return Err(self.error("Not logged in."))?
2134       }
2135     };
2136
2137     let user_id = claims.id;
2138
2139     let communities: Vec<CommunityFollowerView> = match CommunityFollowerView::for_user(&conn, user_id) {
2140       Ok(communities) => communities,
2141       Err(_e) => {
2142         return Err(self.error("System error, try logging out and back in."))?
2143       }
2144     };
2145
2146     // Return the jwt
2147     Ok(
2148       serde_json::to_string(
2149         &GetFollowedCommunitiesResponse {
2150           op: self.op_type().to_string(),
2151           communities: communities
2152         }
2153         )?
2154       )
2155   }
2156 }
2157
2158 impl Perform for GetUserDetails {
2159   fn op_type(&self) -> UserOperation {
2160     UserOperation::GetUserDetails
2161   }
2162
2163   fn perform(&self, _chat: &mut ChatServer, _addr: usize) -> Result<String, Error> {
2164
2165     let conn = establish_connection();
2166
2167     let user_id: Option<i32> = match &self.auth {
2168       Some(auth) => {
2169         match Claims::decode(&auth) {
2170           Ok(claims) => {
2171             let user_id = claims.claims.id;
2172             Some(user_id)
2173           }
2174           Err(_e) => None
2175         }
2176       }
2177       None => None
2178     };
2179
2180     //TODO add save
2181     let sort = SortType::from_str(&self.sort)?;
2182
2183     let user_details_id = match self.user_id {
2184       Some(id) => id,
2185       None => User_::read_from_name(&conn, self.username.to_owned().unwrap_or("admin".to_string()))?.id
2186     };
2187
2188     let user_view = UserView::read(&conn, user_details_id)?;
2189
2190     // If its saved only, you don't care what creator it was
2191     let posts = if self.saved_only {
2192       PostView::list(&conn, 
2193                      PostListingType::All, 
2194                      &sort, 
2195                      self.community_id, 
2196                      None, 
2197                      None,
2198                      Some(user_details_id), 
2199                      self.saved_only, 
2200                      false, 
2201                      self.page, 
2202                      self.limit)?
2203     } else {
2204       PostView::list(&conn, 
2205                      PostListingType::All, 
2206                      &sort, 
2207                      self.community_id, 
2208                      Some(user_details_id), 
2209                      None, 
2210                      user_id, 
2211                      self.saved_only, 
2212                      false, 
2213                      self.page, 
2214                      self.limit)?
2215     };
2216     let comments = if self.saved_only {
2217       CommentView::list(&conn, 
2218                         &sort, 
2219                         None, 
2220                         None, 
2221                         None, 
2222                         Some(user_details_id), 
2223                         self.saved_only, 
2224                         self.page, 
2225                         self.limit)?
2226     } else {
2227       CommentView::list(&conn, 
2228                         &sort, 
2229                         None, 
2230                         Some(user_details_id), 
2231                         None, 
2232                         user_id, 
2233                         self.saved_only, 
2234                         self.page, 
2235                         self.limit)?
2236     };
2237
2238     let follows = CommunityFollowerView::for_user(&conn, user_details_id)?;
2239     let moderates = CommunityModeratorView::for_user(&conn, user_details_id)?;
2240
2241     // Return the jwt
2242     Ok(
2243       serde_json::to_string(
2244         &GetUserDetailsResponse {
2245           op: self.op_type().to_string(),
2246           user: user_view,
2247           follows: follows,
2248           moderates: moderates, 
2249           comments: comments,
2250           posts: posts,
2251         }
2252         )?
2253       )
2254   }
2255 }
2256
2257 impl Perform for GetModlog {
2258   fn op_type(&self) -> UserOperation {
2259     UserOperation::GetModlog
2260   }
2261
2262   fn perform(&self, _chat: &mut ChatServer, _addr: usize) -> Result<String, Error> {
2263
2264     let conn = establish_connection();
2265
2266     let removed_posts = ModRemovePostView::list(&conn, self.community_id, self.mod_user_id, self.page, self.limit)?;
2267     let locked_posts = ModLockPostView::list(&conn, self.community_id, self.mod_user_id, self.page, self.limit)?;
2268     let removed_comments = ModRemoveCommentView::list(&conn, self.community_id, self.mod_user_id, self.page, self.limit)?;
2269     let banned_from_community = ModBanFromCommunityView::list(&conn, self.community_id, self.mod_user_id, self.page, self.limit)?;
2270     let added_to_community = ModAddCommunityView::list(&conn, self.community_id, self.mod_user_id, self.page, self.limit)?;
2271
2272     // These arrays are only for the full modlog, when a community isn't given
2273     let mut removed_communities = Vec::new();
2274     let mut banned = Vec::new();
2275     let mut added = Vec::new();
2276
2277     if self.community_id.is_none() {
2278       removed_communities = ModRemoveCommunityView::list(&conn, self.mod_user_id, self.page, self.limit)?;
2279       banned = ModBanView::list(&conn, self.mod_user_id, self.page, self.limit)?;
2280       added = ModAddView::list(&conn, self.mod_user_id, self.page, self.limit)?;
2281     }
2282
2283     // Return the jwt
2284     Ok(
2285       serde_json::to_string(
2286         &GetModlogResponse {
2287           op: self.op_type().to_string(),
2288           removed_posts: removed_posts,
2289           locked_posts: locked_posts,
2290           removed_comments: removed_comments,
2291           removed_communities: removed_communities,
2292           banned_from_community: banned_from_community,
2293           banned: banned,
2294           added_to_community: added_to_community,
2295           added: added,
2296         }
2297         )?
2298       )
2299   }
2300 }
2301
2302 impl Perform for GetReplies {
2303   fn op_type(&self) -> UserOperation {
2304     UserOperation::GetReplies
2305   }
2306
2307   fn perform(&self, _chat: &mut ChatServer, _addr: usize) -> Result<String, Error> {
2308
2309     let conn = establish_connection();
2310
2311     let claims = match Claims::decode(&self.auth) {
2312       Ok(claims) => claims.claims,
2313       Err(_e) => {
2314         return Err(self.error("Not logged in."))?
2315       }
2316     };
2317
2318     let user_id = claims.id;
2319
2320     let sort = SortType::from_str(&self.sort)?;
2321
2322     let replies = ReplyView::get_replies(&conn, user_id, &sort, self.unread_only, self.page, self.limit)?;
2323
2324     // Return the jwt
2325     Ok(
2326       serde_json::to_string(
2327         &GetRepliesResponse {
2328           op: self.op_type().to_string(),
2329           replies: replies,
2330         }
2331         )?
2332       )
2333   }
2334 }
2335
2336 impl Perform for BanFromCommunity {
2337   fn op_type(&self) -> UserOperation {
2338     UserOperation::BanFromCommunity
2339   }
2340
2341   fn perform(&self, chat: &mut ChatServer, addr: usize) -> Result<String, Error> {
2342
2343     let conn = establish_connection();
2344
2345     let claims = match Claims::decode(&self.auth) {
2346       Ok(claims) => claims.claims,
2347       Err(_e) => {
2348         return Err(self.error("Not logged in."))?
2349       }
2350     };
2351
2352     let user_id = claims.id;
2353
2354     let community_user_ban_form = CommunityUserBanForm {
2355       community_id: self.community_id,
2356       user_id: self.user_id,
2357     };
2358
2359     if self.ban {
2360       match CommunityUserBan::ban(&conn, &community_user_ban_form) {
2361         Ok(user) => user,
2362         Err(_e) => {
2363           return Err(self.error("Community user ban already exists"))?
2364         }
2365       };
2366     } else {
2367       match CommunityUserBan::unban(&conn, &community_user_ban_form) {
2368         Ok(user) => user,
2369         Err(_e) => {
2370           return Err(self.error("Community user ban already exists"))?
2371         }
2372       };
2373     }
2374
2375     // Mod tables
2376     let expires = match self.expires {
2377       Some(time) => Some(naive_from_unix(time)),
2378       None => None
2379     };
2380
2381     let form = ModBanFromCommunityForm {
2382       mod_user_id: user_id,
2383       other_user_id: self.user_id,
2384       community_id: self.community_id,
2385       reason: self.reason.to_owned(),
2386       banned: Some(self.ban),
2387       expires: expires,
2388     };
2389     ModBanFromCommunity::create(&conn, &form)?;
2390
2391     let user_view = UserView::read(&conn, self.user_id)?;
2392
2393     let res = serde_json::to_string(
2394       &BanFromCommunityResponse {
2395         op: self.op_type().to_string(), 
2396         user: user_view,
2397         banned: self.ban
2398       }
2399       )
2400       ?;
2401
2402
2403     chat.send_community_message(&conn, self.community_id, &res, addr)?;
2404
2405     Ok(res)
2406   }
2407 }
2408
2409 impl Perform for AddModToCommunity {
2410   fn op_type(&self) -> UserOperation {
2411     UserOperation::AddModToCommunity
2412   }
2413
2414   fn perform(&self, chat: &mut ChatServer, addr: usize) -> Result<String, Error> {
2415
2416     let conn = establish_connection();
2417
2418     let claims = match Claims::decode(&self.auth) {
2419       Ok(claims) => claims.claims,
2420       Err(_e) => {
2421         return Err(self.error("Not logged in."))?
2422       }
2423     };
2424
2425     let user_id = claims.id;
2426
2427     let community_moderator_form = CommunityModeratorForm {
2428       community_id: self.community_id,
2429       user_id: self.user_id
2430     };
2431
2432     if self.added {
2433       match CommunityModerator::join(&conn, &community_moderator_form) {
2434         Ok(user) => user,
2435         Err(_e) => {
2436           return Err(self.error("Community moderator already exists."))?
2437         }
2438       };
2439     } else {
2440       match CommunityModerator::leave(&conn, &community_moderator_form) {
2441         Ok(user) => user,
2442         Err(_e) => {
2443           return Err(self.error("Community moderator already exists."))?
2444         }
2445       };
2446     }
2447
2448     // Mod tables
2449     let form = ModAddCommunityForm {
2450       mod_user_id: user_id,
2451       other_user_id: self.user_id,
2452       community_id: self.community_id,
2453       removed: Some(!self.added),
2454     };
2455     ModAddCommunity::create(&conn, &form)?;
2456
2457     let moderators = CommunityModeratorView::for_community(&conn, self.community_id)?;
2458
2459     let res = serde_json::to_string(
2460       &AddModToCommunityResponse {
2461         op: self.op_type().to_string(), 
2462         moderators: moderators,
2463       }
2464       )
2465       ?;
2466
2467
2468     chat.send_community_message(&conn, self.community_id, &res, addr)?;
2469
2470     Ok(res)
2471
2472   }
2473 }
2474
2475 impl Perform for CreateSite {
2476   fn op_type(&self) -> UserOperation {
2477     UserOperation::CreateSite
2478   }
2479
2480   fn perform(&self, _chat: &mut ChatServer, _addr: usize) -> Result<String, Error> {
2481
2482     let conn = establish_connection();
2483
2484     let claims = match Claims::decode(&self.auth) {
2485       Ok(claims) => claims.claims,
2486       Err(_e) => {
2487         return Err(self.error("Not logged in."))?
2488       }
2489     };
2490
2491     if has_slurs(&self.name) || 
2492       (self.description.is_some() && has_slurs(&self.description.to_owned().unwrap())) {
2493         return Err(self.error("No slurs"))?
2494       }
2495
2496     let user_id = claims.id;
2497
2498     // Make sure user is an admin
2499     if !UserView::read(&conn, user_id)?.admin {
2500       return Err(self.error("Not an admin."))?
2501     }
2502
2503     let site_form = SiteForm {
2504       name: self.name.to_owned(),
2505       description: self.description.to_owned(),
2506       creator_id: user_id,
2507       updated: None,
2508     };
2509
2510     match Site::create(&conn, &site_form) {
2511       Ok(site) => site,
2512       Err(_e) => {
2513         return Err(self.error("Site exists already"))?
2514       }
2515     };
2516
2517     let site_view = SiteView::read(&conn)?;
2518
2519     Ok(
2520       serde_json::to_string(
2521         &SiteResponse {
2522           op: self.op_type().to_string(), 
2523           site: site_view,
2524         }
2525         )?
2526       )
2527   }
2528 }
2529
2530 impl Perform for EditSite {
2531   fn op_type(&self) -> UserOperation {
2532     UserOperation::EditSite
2533   }
2534
2535   fn perform(&self, _chat: &mut ChatServer, _addr: usize) -> Result<String, Error> {
2536
2537     let conn = establish_connection();
2538
2539     let claims = match Claims::decode(&self.auth) {
2540       Ok(claims) => claims.claims,
2541       Err(_e) => {
2542         return Err(self.error("Not logged in."))?
2543       }
2544     };
2545
2546     if has_slurs(&self.name) || 
2547       (self.description.is_some() && has_slurs(&self.description.to_owned().unwrap())) {
2548         return Err(self.error("No slurs"))?
2549       }
2550
2551     let user_id = claims.id;
2552
2553     // Make sure user is an admin
2554     if UserView::read(&conn, user_id)?.admin == false {
2555       return Err(self.error("Not an admin."))?
2556     }
2557
2558     let found_site = Site::read(&conn, 1)?;
2559
2560     let site_form = SiteForm {
2561       name: self.name.to_owned(),
2562       description: self.description.to_owned(),
2563       creator_id: found_site.creator_id,
2564       updated: Some(naive_now()),
2565     };
2566
2567     match Site::update(&conn, 1, &site_form) {
2568       Ok(site) => site,
2569       Err(_e) => {
2570         return Err(self.error("Couldn't update site."))?
2571       }
2572     };
2573
2574     let site_view = SiteView::read(&conn)?;
2575
2576     Ok(
2577       serde_json::to_string(
2578         &SiteResponse {
2579           op: self.op_type().to_string(), 
2580           site: site_view,
2581         }
2582         )?
2583       )
2584   }
2585 }
2586
2587 impl Perform for GetSite {
2588   fn op_type(&self) -> UserOperation {
2589     UserOperation::GetSite
2590   }
2591
2592   fn perform(&self, _chat: &mut ChatServer, _addr: usize) -> Result<String, Error> {
2593
2594     let conn = establish_connection();
2595
2596     // It can return a null site in order to redirect
2597     let site_view = match Site::read(&conn, 1) {
2598       Ok(_site) => Some(SiteView::read(&conn)?),
2599       Err(_e) => None
2600     };
2601
2602     let admins = UserView::admins(&conn)?;
2603     let banned = UserView::banned(&conn)?;
2604
2605     Ok(
2606       serde_json::to_string(
2607         &GetSiteResponse {
2608           op: self.op_type().to_string(), 
2609           site: site_view,
2610           admins: admins,
2611           banned: banned,
2612         }
2613         )?    
2614       )
2615   }
2616 }
2617
2618 impl Perform for AddAdmin {
2619   fn op_type(&self) -> UserOperation {
2620     UserOperation::AddAdmin
2621   }
2622
2623   fn perform(&self, _chat: &mut ChatServer, _addr: usize) -> Result<String, Error> {
2624
2625     let conn = establish_connection();
2626
2627     let claims = match Claims::decode(&self.auth) {
2628       Ok(claims) => claims.claims,
2629       Err(_e) => {
2630         return Err(self.error("Not logged in."))?
2631       }
2632     };
2633
2634     let user_id = claims.id;
2635
2636     // Make sure user is an admin
2637     if UserView::read(&conn, user_id)?.admin == false {
2638       return Err(self.error("Not an admin."))?
2639     }
2640
2641     let read_user = User_::read(&conn, self.user_id)?;
2642
2643     let user_form = UserForm {
2644       name: read_user.name,
2645       fedi_name: read_user.fedi_name,
2646       email: read_user.email,
2647       password_encrypted: read_user.password_encrypted,
2648       preferred_username: read_user.preferred_username,
2649       updated: Some(naive_now()),
2650       admin: self.added,
2651       banned: read_user.banned,
2652     };
2653
2654     match User_::update(&conn, self.user_id, &user_form) {
2655       Ok(user) => user,
2656       Err(_e) => {
2657         return Err(self.error("Couldn't update user"))?
2658       }
2659     };
2660
2661     // Mod tables
2662     let form = ModAddForm {
2663       mod_user_id: user_id,
2664       other_user_id: self.user_id,
2665       removed: Some(!self.added),
2666     };
2667
2668     ModAdd::create(&conn, &form)?;
2669
2670     let admins = UserView::admins(&conn)?;
2671
2672     let res = serde_json::to_string(
2673       &AddAdminResponse {
2674         op: self.op_type().to_string(), 
2675         admins: admins,
2676       }
2677       )
2678       ?;
2679
2680
2681     Ok(res)
2682
2683   }
2684 }
2685
2686 impl Perform for BanUser {
2687   fn op_type(&self) -> UserOperation {
2688     UserOperation::BanUser
2689   }
2690
2691   fn perform(&self, _chat: &mut ChatServer, _addr: usize) -> Result<String, Error> {
2692
2693     let conn = establish_connection();
2694
2695     let claims = match Claims::decode(&self.auth) {
2696       Ok(claims) => claims.claims,
2697       Err(_e) => {
2698         return Err(self.error("Not logged in."))?
2699       }
2700     };
2701
2702     let user_id = claims.id;
2703
2704     // Make sure user is an admin
2705     if UserView::read(&conn, user_id)?.admin == false {
2706       return Err(self.error("Not an admin."))?
2707     }
2708
2709     let read_user = User_::read(&conn, self.user_id)?;
2710
2711     let user_form = UserForm {
2712       name: read_user.name,
2713       fedi_name: read_user.fedi_name,
2714       email: read_user.email,
2715       password_encrypted: read_user.password_encrypted,
2716       preferred_username: read_user.preferred_username,
2717       updated: Some(naive_now()),
2718       admin: read_user.admin,
2719       banned: self.ban,
2720     };
2721
2722     match User_::update(&conn, self.user_id, &user_form) {
2723       Ok(user) => user,
2724       Err(_e) => {
2725         return Err(self.error("Couldn't update user"))?
2726       }
2727     };
2728
2729     // Mod tables
2730     let expires = match self.expires {
2731       Some(time) => Some(naive_from_unix(time)),
2732       None => None
2733     };
2734
2735     let form = ModBanForm {
2736       mod_user_id: user_id,
2737       other_user_id: self.user_id,
2738       reason: self.reason.to_owned(),
2739       banned: Some(self.ban),
2740       expires: expires,
2741     };
2742
2743     ModBan::create(&conn, &form)?;
2744
2745     let user_view = UserView::read(&conn, self.user_id)?;
2746
2747     let res = serde_json::to_string(
2748       &BanUserResponse {
2749         op: self.op_type().to_string(), 
2750         user: user_view,
2751         banned: self.ban
2752       }
2753       )
2754       ?;
2755
2756     Ok(res)
2757
2758   }
2759 }
2760
2761 impl Perform for Search {
2762   fn op_type(&self) -> UserOperation {
2763     UserOperation::Search
2764   }
2765
2766   fn perform(&self, _chat: &mut ChatServer, _addr: usize) -> Result<String, Error> {
2767
2768     let conn = establish_connection();
2769
2770     let sort = SortType::from_str(&self.sort)?;
2771     let type_ = SearchType::from_str(&self.type_)?;
2772
2773     let mut posts = Vec::new();
2774     let mut comments = Vec::new();
2775
2776     match type_ {
2777       SearchType::Posts => {
2778         posts = PostView::list(&conn, 
2779                                PostListingType::All, 
2780                                &sort, 
2781                                self.community_id, 
2782                                None,
2783                                Some(self.q.to_owned()),
2784                                None, 
2785                                false, 
2786                                false, 
2787                                self.page, 
2788                                self.limit)?;
2789       },
2790       SearchType::Comments => {
2791         comments = CommentView::list(&conn, 
2792                                      &sort, 
2793                                      None, 
2794                                      None, 
2795                                      Some(self.q.to_owned()),
2796                                      None,
2797                                      false, 
2798                                      self.page,
2799                                      self.limit)?;
2800       }, 
2801       SearchType::Both => {
2802         posts = PostView::list(&conn, 
2803                                PostListingType::All, 
2804                                &sort, 
2805                                self.community_id, 
2806                                None,
2807                                Some(self.q.to_owned()),
2808                                None, 
2809                                false, 
2810                                false, 
2811                                self.page, 
2812                                self.limit)?;
2813         comments = CommentView::list(&conn, 
2814                                      &sort, 
2815                                      None, 
2816                                      None, 
2817                                      Some(self.q.to_owned()),
2818                                      None,
2819                                      false, 
2820                                      self.page,
2821                                      self.limit)?;
2822       }
2823     };
2824
2825
2826     // Return the jwt
2827     Ok(
2828       serde_json::to_string(
2829         &SearchResponse {
2830           op: self.op_type().to_string(),
2831           comments: comments,
2832           posts: posts,
2833         }
2834         )?
2835       )
2836   }
2837 }
2838
2839
2840 impl Perform for MarkAllAsRead {
2841   fn op_type(&self) -> UserOperation {
2842     UserOperation::MarkAllAsRead
2843   }
2844
2845   fn perform(&self, _chat: &mut ChatServer, _addr: usize) -> Result<String, Error> {
2846
2847     let conn = establish_connection();
2848
2849     let claims = match Claims::decode(&self.auth) {
2850       Ok(claims) => claims.claims,
2851       Err(_e) => {
2852         return Err(self.error("Not logged in."))?
2853       }
2854     };
2855
2856     let user_id = claims.id;
2857
2858     let replies = ReplyView::get_replies(&conn, user_id, &SortType::New, true, Some(1), Some(999))?;
2859
2860     for reply in &replies {
2861       let comment_form = CommentForm {
2862         content: reply.to_owned().content,
2863         parent_id: reply.to_owned().parent_id,
2864         post_id: reply.to_owned().post_id,
2865         creator_id: reply.to_owned().creator_id,
2866         removed: None,
2867         deleted: None,
2868         read: Some(true),
2869         updated: reply.to_owned().updated 
2870       };
2871
2872       let _updated_comment = match Comment::update(&conn, reply.id, &comment_form) {
2873         Ok(comment) => comment,
2874         Err(_e) => {
2875           return Err(self.error("Couldn't update Comment"))?
2876         }
2877       };
2878     }
2879
2880     let replies = ReplyView::get_replies(&conn, user_id, &SortType::New, true, Some(1), Some(999))?;
2881
2882     Ok(
2883       serde_json::to_string(
2884         &GetRepliesResponse {
2885           op: self.op_type().to_string(),
2886           replies: replies,
2887         }
2888         )?
2889       )
2890   }
2891 }