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`.
6 use rand::{rngs::ThreadRng, Rng};
7 use std::collections::{HashMap, HashSet};
8 use serde::{Deserialize, Serialize};
9 use serde_json::{Value};
11 use std::str::FromStr;
12 use diesel::PgConnection;
14 use std::time::{SystemTime};
16 use {Crud, Joinable, Likeable, Followable, Bannable, Saveable, establish_connection, naive_now, naive_from_unix, SortType, SearchType, has_slurs, remove_slurs, Settings};
22 use db::comment_view::*;
24 use db::community_view::*;
26 use db::moderator_views::*;
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;
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
39 #[derive(Fail, Debug)]
40 #[fail(display = "{{\"op\":\"{}\", \"error\":\"{}\"}}", op, message)]
41 pub struct ErrorMessage {
46 /// Chat server sends this messages to session
48 pub struct WSMessage(pub String);
50 /// Message for chat server communications
52 /// New chat session is created
56 pub addr: Recipient<WSMessage>,
60 /// Session is disconnected
62 pub struct Disconnect {
67 /// Send message to specific room
69 pub struct ClientMessage {
70 /// Id of the client session
78 #[derive(Serialize, Deserialize)]
79 pub struct StandardMessage {
80 /// Id of the client session
86 impl actix::Message for StandardMessage {
90 #[derive(Serialize, Deserialize)]
92 pub username_or_email: String,
96 #[derive(Serialize, Deserialize)]
99 email: Option<String>,
101 password_verify: String,
106 #[derive(Serialize, Deserialize)]
107 pub struct LoginResponse {
112 #[derive(Serialize, Deserialize)]
113 pub struct CreateCommunity {
116 description: Option<String>,
121 #[derive(Serialize, Deserialize)]
122 pub struct CommunityResponse {
124 community: CommunityView
127 #[derive(Serialize, Deserialize)]
128 pub struct ListCommunities {
135 #[derive(Serialize, Deserialize)]
136 pub struct ListCommunitiesResponse {
138 communities: Vec<CommunityView>
141 #[derive(Serialize, Deserialize)]
142 pub struct ListCategories;
144 #[derive(Serialize, Deserialize)]
145 pub struct ListCategoriesResponse {
147 categories: Vec<Category>
150 #[derive(Serialize, Deserialize)]
151 pub struct CreatePost {
154 body: Option<String>,
159 #[derive(Serialize, Deserialize)]
160 pub struct PostResponse {
166 #[derive(Serialize, Deserialize)]
172 #[derive(Serialize, Deserialize)]
173 pub struct GetPostResponse {
176 comments: Vec<CommentView>,
177 community: CommunityView,
178 moderators: Vec<CommunityModeratorView>,
179 admins: Vec<UserView>,
182 #[derive(Serialize, Deserialize)]
183 pub struct GetPosts {
188 community_id: Option<i32>,
192 #[derive(Serialize, Deserialize)]
193 pub struct GetPostsResponse {
195 posts: Vec<PostView>,
198 #[derive(Serialize, Deserialize)]
199 pub struct GetCommunity {
201 name: Option<String>,
205 #[derive(Serialize, Deserialize)]
206 pub struct GetCommunityResponse {
208 community: CommunityView,
209 moderators: Vec<CommunityModeratorView>,
210 admins: Vec<UserView>,
213 #[derive(Serialize, Deserialize)]
214 pub struct CreateComment {
216 parent_id: Option<i32>,
217 edit_id: Option<i32>,
222 #[derive(Serialize, Deserialize)]
223 pub struct EditComment {
225 parent_id: Option<i32>,
229 removed: Option<bool>,
230 deleted: Option<bool>,
231 reason: Option<String>,
236 #[derive(Serialize, Deserialize)]
237 pub struct SaveComment {
243 #[derive(Serialize, Deserialize)]
244 pub struct CommentResponse {
249 #[derive(Serialize, Deserialize)]
250 pub struct CreateCommentLike {
257 #[derive(Serialize, Deserialize)]
258 pub struct CreatePostLike {
264 #[derive(Serialize, Deserialize)]
265 pub struct CreatePostLikeResponse {
271 #[derive(Serialize, Deserialize)]
272 pub struct EditPost {
278 body: Option<String>,
279 removed: Option<bool>,
280 deleted: Option<bool>,
281 locked: Option<bool>,
282 reason: Option<String>,
286 #[derive(Serialize, Deserialize)]
287 pub struct SavePost {
293 #[derive(Serialize, Deserialize)]
294 pub struct EditCommunity {
298 description: Option<String>,
300 removed: Option<bool>,
301 deleted: Option<bool>,
302 reason: Option<String>,
303 expires: Option<i64>,
307 #[derive(Serialize, Deserialize)]
308 pub struct FollowCommunity {
314 #[derive(Serialize, Deserialize)]
315 pub struct GetFollowedCommunities {
319 #[derive(Serialize, Deserialize)]
320 pub struct GetFollowedCommunitiesResponse {
322 communities: Vec<CommunityFollowerView>
325 #[derive(Serialize, Deserialize)]
326 pub struct GetUserDetails {
327 user_id: Option<i32>,
328 username: Option<String>,
332 community_id: Option<i32>,
334 auth: Option<String>,
337 #[derive(Serialize, Deserialize)]
338 pub struct GetUserDetailsResponse {
341 follows: Vec<CommunityFollowerView>,
342 moderates: Vec<CommunityModeratorView>,
343 comments: Vec<CommentView>,
344 posts: Vec<PostView>,
347 #[derive(Serialize, Deserialize)]
348 pub struct GetModlog {
349 mod_user_id: Option<i32>,
350 community_id: Option<i32>,
355 #[derive(Serialize, Deserialize)]
356 pub struct GetModlogResponse {
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>,
368 #[derive(Serialize, Deserialize)]
369 pub struct BanFromCommunity {
373 reason: Option<String>,
374 expires: Option<i64>,
378 #[derive(Serialize, Deserialize)]
379 pub struct BanFromCommunityResponse {
386 #[derive(Serialize, Deserialize)]
387 pub struct AddModToCommunity {
394 #[derive(Serialize, Deserialize)]
395 pub struct AddModToCommunityResponse {
397 moderators: Vec<CommunityModeratorView>,
400 #[derive(Serialize, Deserialize)]
401 pub struct CreateSite {
403 description: Option<String>,
407 #[derive(Serialize, Deserialize)]
408 pub struct EditSite {
410 description: Option<String>,
414 #[derive(Serialize, Deserialize)]
418 #[derive(Serialize, Deserialize)]
419 pub struct SiteResponse {
424 #[derive(Serialize, Deserialize)]
425 pub struct GetSiteResponse {
427 site: Option<SiteView>,
428 admins: Vec<UserView>,
429 banned: Vec<UserView>,
432 #[derive(Serialize, Deserialize)]
433 pub struct AddAdmin {
439 #[derive(Serialize, Deserialize)]
440 pub struct AddAdminResponse {
442 admins: Vec<UserView>,
445 #[derive(Serialize, Deserialize)]
449 reason: Option<String>,
450 expires: Option<i64>,
454 #[derive(Serialize, Deserialize)]
455 pub struct BanUserResponse {
461 #[derive(Serialize, Deserialize)]
462 pub struct GetReplies {
470 #[derive(Serialize, Deserialize)]
471 pub struct GetRepliesResponse {
473 replies: Vec<ReplyView>,
476 #[derive(Serialize, Deserialize)]
480 community_id: Option<i32>,
486 #[derive(Serialize, Deserialize)]
487 pub struct SearchResponse {
489 comments: Vec<CommentView>,
490 posts: Vec<PostView>,
493 #[derive(Serialize, Deserialize)]
494 pub struct MarkAllAsRead {
499 pub struct RateLimitBucket {
500 last_checked: SystemTime,
504 pub struct SessionInfo {
505 pub addr: Recipient<WSMessage>,
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
518 impl Default for ChatServer {
519 fn default() -> ChatServer {
521 let rooms = HashMap::new();
524 sessions: HashMap::new(),
525 rate_limits: HashMap::new(),
527 rng: rand::thread_rng(),
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) {
538 if let Some(info) = self.sessions.get(id) {
539 let _ = info.addr.do_send(WSMessage(message.to_owned()));
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,
559 self.send_room_message(post.id, message, skip_id);
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)
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)
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) {
577 if rate_limit.allowance == -2f64 {
578 rate_limit.allowance = rate as f64;
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;
589 if rate_limit.allowance < 1.0 {
590 println!("Rate limited IP: {}, time_passed: {}, allowance: {}", &info.ip, time_passed, rate_limit.allowance);
592 op: "Rate Limit".to_string(),
593 message: format!("Too many requests. {} per {} seconds", rate, per),
596 rate_limit.allowance -= 1.0;
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>;
616 /// Handler for Connect message.
618 /// Register new session and assign unique id to this session
619 impl Handler<Connect> for ChatServer {
622 fn handle(&mut self, msg: Connect, _ctx: &mut Context<Self>) -> Self::Result {
624 // notify all users in same room
625 // self.send_room_message(&"Main".to_owned(), "Someone joined", 0);
627 // register session with random id
628 let id = self.rng.gen::<usize>();
629 println!("{} joined", &msg.ip);
631 self.sessions.insert(id, SessionInfo {
633 ip: msg.ip.to_owned(),
636 if self.rate_limits.get(&msg.ip).is_none() {
637 self.rate_limits.insert(msg.ip, RateLimitBucket {
638 last_checked: SystemTime::now(),
643 // for (k,v) in &self.rate_limits {
644 // println!("{}: {:?}", k,v);
647 // auto join session to Main room
648 // self.rooms.get_mut(&"Main".to_owned()).unwrap().insert(id);
656 /// Handler for Disconnect message.
657 impl Handler<Disconnect> for ChatServer {
660 fn handle(&mut self, msg: Disconnect, _: &mut Context<Self>) {
662 // let mut rooms: Vec<i32> = Vec::new();
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) {
676 /// Handler for Message message.
677 impl Handler<StandardMessage> for ChatServer {
678 type Result = MessageResult<StandardMessage>;
681 fn handle(&mut self, msg: StandardMessage, _: &mut Context<Self>) -> Self::Result {
683 let msg_out = match parse_json_message(self, msg) {
685 Err(e) => e.to_string()
688 MessageResult(msg_out)
692 fn parse_json_message(chat: &mut ChatServer, msg: StandardMessage) -> Result<String, Error> {
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();
698 let user_operation: UserOperation = UserOperation::from_str(&op)?;
700 match user_operation {
701 UserOperation::Login => {
702 let login: Login = serde_json::from_str(data)?;
703 login.perform(chat, msg.id)
705 UserOperation::Register => {
706 let register: Register = serde_json::from_str(data)?;
707 register.perform(chat, msg.id)
709 UserOperation::CreateCommunity => {
710 let create_community: CreateCommunity = serde_json::from_str(data)?;
711 create_community.perform(chat, msg.id)
713 UserOperation::ListCommunities => {
714 let list_communities: ListCommunities = serde_json::from_str(data)?;
715 list_communities.perform(chat, msg.id)
717 UserOperation::ListCategories => {
718 let list_categories: ListCategories = ListCategories;
719 list_categories.perform(chat, msg.id)
721 UserOperation::CreatePost => {
722 let create_post: CreatePost = serde_json::from_str(data)?;
723 create_post.perform(chat, msg.id)
725 UserOperation::GetPost => {
726 let get_post: GetPost = serde_json::from_str(data)?;
727 get_post.perform(chat, msg.id)
729 UserOperation::GetCommunity => {
730 let get_community: GetCommunity = serde_json::from_str(data)?;
731 get_community.perform(chat, msg.id)
733 UserOperation::CreateComment => {
734 let create_comment: CreateComment = serde_json::from_str(data)?;
735 create_comment.perform(chat, msg.id)
737 UserOperation::EditComment => {
738 let edit_comment: EditComment = serde_json::from_str(data)?;
739 edit_comment.perform(chat, msg.id)
741 UserOperation::SaveComment => {
742 let save_post: SaveComment = serde_json::from_str(data)?;
743 save_post.perform(chat, msg.id)
745 UserOperation::CreateCommentLike => {
746 let create_comment_like: CreateCommentLike = serde_json::from_str(data)?;
747 create_comment_like.perform(chat, msg.id)
749 UserOperation::GetPosts => {
750 let get_posts: GetPosts = serde_json::from_str(data)?;
751 get_posts.perform(chat, msg.id)
753 UserOperation::CreatePostLike => {
754 let create_post_like: CreatePostLike = serde_json::from_str(data)?;
755 create_post_like.perform(chat, msg.id)
757 UserOperation::EditPost => {
758 let edit_post: EditPost = serde_json::from_str(data)?;
759 edit_post.perform(chat, msg.id)
761 UserOperation::SavePost => {
762 let save_post: SavePost = serde_json::from_str(data)?;
763 save_post.perform(chat, msg.id)
765 UserOperation::EditCommunity => {
766 let edit_community: EditCommunity = serde_json::from_str(data)?;
767 edit_community.perform(chat, msg.id)
769 UserOperation::FollowCommunity => {
770 let follow_community: FollowCommunity = serde_json::from_str(data)?;
771 follow_community.perform(chat, msg.id)
773 UserOperation::GetFollowedCommunities => {
774 let followed_communities: GetFollowedCommunities = serde_json::from_str(data)?;
775 followed_communities.perform(chat, msg.id)
777 UserOperation::GetUserDetails => {
778 let get_user_details: GetUserDetails = serde_json::from_str(data)?;
779 get_user_details.perform(chat, msg.id)
781 UserOperation::GetModlog => {
782 let get_modlog: GetModlog = serde_json::from_str(data)?;
783 get_modlog.perform(chat, msg.id)
785 UserOperation::BanFromCommunity => {
786 let ban_from_community: BanFromCommunity = serde_json::from_str(data)?;
787 ban_from_community.perform(chat, msg.id)
789 UserOperation::AddModToCommunity => {
790 let mod_add_to_community: AddModToCommunity = serde_json::from_str(data)?;
791 mod_add_to_community.perform(chat, msg.id)
793 UserOperation::CreateSite => {
794 let create_site: CreateSite = serde_json::from_str(data)?;
795 create_site.perform(chat, msg.id)
797 UserOperation::EditSite => {
798 let edit_site: EditSite = serde_json::from_str(data)?;
799 edit_site.perform(chat, msg.id)
801 UserOperation::GetSite => {
802 let get_site: GetSite = serde_json::from_str(data)?;
803 get_site.perform(chat, msg.id)
805 UserOperation::AddAdmin => {
806 let add_admin: AddAdmin = serde_json::from_str(data)?;
807 add_admin.perform(chat, msg.id)
809 UserOperation::BanUser => {
810 let ban_user: BanUser = serde_json::from_str(data)?;
811 ban_user.perform(chat, msg.id)
813 UserOperation::GetReplies => {
814 let get_replies: GetReplies = serde_json::from_str(data)?;
815 get_replies.perform(chat, msg.id)
817 UserOperation::Search => {
818 let search: Search = serde_json::from_str(data)?;
819 search.perform(chat, msg.id)
821 UserOperation::MarkAllAsRead => {
822 let mark_all_as_read: MarkAllAsRead = serde_json::from_str(data)?;
823 mark_all_as_read.perform(chat, msg.id)
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 {
833 op: self.op_type().to_string(),
834 message: error_msg.to_string()
839 impl Perform for Login {
841 fn op_type(&self) -> UserOperation {
845 fn perform(&self, _chat: &mut ChatServer, _addr: usize) -> Result<String, Error> {
847 let conn = establish_connection();
849 // Fetch that username / email
850 let user: User_ = match User_::find_by_email_or_username(&conn, &self.username_or_email) {
852 Err(_e) => return Err(self.error("Couldn't find that username or email"))?
855 // Verify the password
856 let valid: bool = verify(&self.password, &user.password_encrypted).unwrap_or(false);
858 return Err(self.error("Password incorrect"))?
863 serde_json::to_string(
865 op: self.op_type().to_string(),
874 impl Perform for Register {
875 fn op_type(&self) -> UserOperation {
876 UserOperation::Register
878 fn perform(&self, chat: &mut ChatServer, addr: usize) -> Result<String, Error> {
880 let conn = establish_connection();
882 chat.check_rate_limit_register(addr)?;
884 // Make sure passwords match
885 if &self.password != &self.password_verify {
886 return Err(self.error("Passwords do not match."))?
889 if self.spam_timeri < 1142 {
890 return Err(self.error("Too fast"))?
893 if has_slurs(&self.username) {
894 return Err(self.error("No slurs"))?
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."))?
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,
915 let inserted_user = match User_::register(&conn, &user_form) {
918 return Err(self.error("User already exists."))?
922 // Sign them up for main community no matter what
923 let community_follower_form = CommunityFollowerForm {
925 user_id: inserted_user.id,
928 let _inserted_community_follower = match CommunityFollower::follow(&conn, &community_follower_form) {
931 return Err(self.error("Community follower already exists."))?
935 // If its an admin, add them as a mod and follower to main
937 let community_moderator_form = CommunityModeratorForm {
939 user_id: inserted_user.id,
942 let _inserted_community_moderator = match CommunityModerator::join(&conn, &community_moderator_form) {
945 return Err(self.error("Community moderator already exists."))?
954 serde_json::to_string(
956 op: self.op_type().to_string(),
957 jwt: inserted_user.jwt()
965 impl Perform for CreateCommunity {
966 fn op_type(&self) -> UserOperation {
967 UserOperation::CreateCommunity
970 fn perform(&self, chat: &mut ChatServer, addr: usize) -> Result<String, Error> {
972 let conn = establish_connection();
974 chat.check_rate_limit_register(addr)?;
976 let claims = match Claims::decode(&self.auth) {
977 Ok(claims) => claims.claims,
979 return Err(self.error("Not logged in."))?
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"))?
989 let user_id = claims.id;
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"))?
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,
1008 let inserted_community = match Community::create(&conn, &community_form) {
1009 Ok(community) => community,
1011 return Err(self.error("Community already exists."))?
1015 let community_moderator_form = CommunityModeratorForm {
1016 community_id: inserted_community.id,
1020 let _inserted_community_moderator = match CommunityModerator::join(&conn, &community_moderator_form) {
1023 return Err(self.error("Community moderator already exists."))?
1027 let community_follower_form = CommunityFollowerForm {
1028 community_id: inserted_community.id,
1032 let _inserted_community_follower = match CommunityFollower::follow(&conn, &community_follower_form) {
1035 return Err(self.error("Community follower already exists."))?
1039 let community_view = CommunityView::read(&conn, inserted_community.id, Some(user_id))?;
1042 serde_json::to_string(
1043 &CommunityResponse {
1044 op: self.op_type().to_string(),
1045 community: community_view
1052 impl Perform for ListCommunities {
1053 fn op_type(&self) -> UserOperation {
1054 UserOperation::ListCommunities
1057 fn perform(&self, _chat: &mut ChatServer, _addr: usize) -> Result<String, Error> {
1059 let conn = establish_connection();
1061 let user_id: Option<i32> = match &self.auth {
1063 match Claims::decode(&auth) {
1065 let user_id = claims.claims.id;
1074 let sort = SortType::from_str(&self.sort)?;
1076 let communities: Vec<CommunityView> = CommunityView::list(&conn, user_id, sort, self.page, self.limit)?;
1080 serde_json::to_string(
1081 &ListCommunitiesResponse {
1082 op: self.op_type().to_string(),
1083 communities: communities
1090 impl Perform for ListCategories {
1091 fn op_type(&self) -> UserOperation {
1092 UserOperation::ListCategories
1095 fn perform(&self, _chat: &mut ChatServer, _addr: usize) -> Result<String, Error> {
1097 let conn = establish_connection();
1099 let categories: Vec<Category> = Category::list_all(&conn)?;
1103 serde_json::to_string(
1104 &ListCategoriesResponse {
1105 op: self.op_type().to_string(),
1106 categories: categories
1113 impl Perform for CreatePost {
1114 fn op_type(&self) -> UserOperation {
1115 UserOperation::CreatePost
1118 fn perform(&self, chat: &mut ChatServer, addr: usize) -> Result<String, Error> {
1120 let conn = establish_connection();
1122 chat.check_rate_limit_register(addr)?;
1124 let claims = match Claims::decode(&self.auth) {
1125 Ok(claims) => claims.claims,
1127 return Err(self.error("Not logged in."))?
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"))?
1136 let user_id = claims.id;
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"))?
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"))?
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,
1160 let inserted_post = match Post::create(&conn, &post_form) {
1163 return Err(self.error("Couldn't create Post"))?
1167 // They like their own post by default
1168 let like_form = PostLikeForm {
1169 post_id: inserted_post.id,
1174 // Only add the like if the score isnt 0
1175 let _inserted_like = match PostLike::like(&conn, &like_form) {
1178 return Err(self.error("Couldn't like post."))?
1183 let post_view = match PostView::read(&conn, inserted_post.id, Some(user_id)) {
1186 return Err(self.error("Couldn't find Post"))?
1191 serde_json::to_string(
1193 op: self.op_type().to_string(),
1202 impl Perform for GetPost {
1203 fn op_type(&self) -> UserOperation {
1204 UserOperation::GetPost
1207 fn perform(&self, chat: &mut ChatServer, addr: usize) -> Result<String, Error> {
1209 let conn = establish_connection();
1211 let user_id: Option<i32> = match &self.auth {
1213 match Claims::decode(&auth) {
1215 let user_id = claims.claims.id;
1224 let post_view = match PostView::read(&conn, self.id, user_id) {
1227 return Err(self.error("Couldn't find Post"))?
1231 // remove session from all rooms
1232 for (_n, sessions) in &mut chat.rooms {
1233 sessions.remove(&addr);
1236 if chat.rooms.get_mut(&self.id).is_none() {
1237 chat.rooms.insert(self.id, HashSet::new());
1240 chat.rooms.get_mut(&self.id).unwrap().insert(addr);
1242 let comments = CommentView::list(&conn, &SortType::New, Some(self.id), None, None, user_id, false, None, Some(9999))?;
1244 let community = CommunityView::read(&conn, post_view.community_id, user_id)?;
1246 let moderators = CommunityModeratorView::for_community(&conn, post_view.community_id)?;
1248 let admins = UserView::admins(&conn)?;
1252 serde_json::to_string(
1254 op: self.op_type().to_string(),
1257 community: community,
1258 moderators: moderators,
1266 impl Perform for GetCommunity {
1267 fn op_type(&self) -> UserOperation {
1268 UserOperation::GetCommunity
1271 fn perform(&self, _chat: &mut ChatServer, _addr: usize) -> Result<String, Error> {
1273 let conn = establish_connection();
1275 let user_id: Option<i32> = match &self.auth {
1277 match Claims::decode(&auth) {
1279 let user_id = claims.claims.id;
1288 let community_id = match self.id {
1290 None => Community::read_from_name(&conn, self.name.to_owned().unwrap_or("main".to_string()))?.id
1293 let community_view = match CommunityView::read(&conn, community_id, user_id) {
1294 Ok(community) => community,
1296 return Err(self.error("Couldn't find Community"))?
1300 let moderators = match CommunityModeratorView::for_community(&conn, community_id) {
1301 Ok(moderators) => moderators,
1303 return Err(self.error("Couldn't find Community"))?
1307 let admins = UserView::admins(&conn)?;
1311 serde_json::to_string(
1312 &GetCommunityResponse {
1313 op: self.op_type().to_string(),
1314 community: community_view,
1315 moderators: moderators,
1323 impl Perform for CreateComment {
1324 fn op_type(&self) -> UserOperation {
1325 UserOperation::CreateComment
1328 fn perform(&self, chat: &mut ChatServer, addr: usize) -> Result<String, Error> {
1330 let conn = establish_connection();
1332 chat.check_rate_limit(addr)?;
1334 let claims = match Claims::decode(&self.auth) {
1335 Ok(claims) => claims.claims,
1337 return Err(self.error("Not logged in."))?
1341 let user_id = claims.id;
1343 // Check for a community ban
1344 let post = Post::read(&conn, self.post_id)?;
1345 if CommunityUserBanView::get(&conn, user_id, post.community_id).is_ok() {
1346 return Err(self.error("You have been banned from this community"))?
1349 // Check for a site ban
1350 if UserView::read(&conn, user_id)?.banned {
1351 return Err(self.error("You have been banned from the site"))?
1354 let content_slurs_removed = remove_slurs(&self.content.to_owned());
1356 let comment_form = CommentForm {
1357 content: content_slurs_removed,
1358 parent_id: self.parent_id.to_owned(),
1359 post_id: self.post_id,
1360 creator_id: user_id,
1367 let inserted_comment = match Comment::create(&conn, &comment_form) {
1368 Ok(comment) => comment,
1370 return Err(self.error("Couldn't create Comment"))?
1374 // You like your own comment by default
1375 let like_form = CommentLikeForm {
1376 comment_id: inserted_comment.id,
1377 post_id: self.post_id,
1382 let _inserted_like = match CommentLike::like(&conn, &like_form) {
1385 return Err(self.error("Couldn't like comment."))?
1389 let comment_view = CommentView::read(&conn, inserted_comment.id, Some(user_id))?;
1391 let mut comment_sent = comment_view.clone();
1392 comment_sent.my_vote = None;
1393 comment_sent.user_id = None;
1395 let comment_out = serde_json::to_string(
1397 op: self.op_type().to_string(),
1398 comment: comment_view
1402 let comment_sent_out = serde_json::to_string(
1404 op: self.op_type().to_string(),
1405 comment: comment_sent
1409 chat.send_room_message(self.post_id, &comment_sent_out, addr);
1415 impl Perform for EditComment {
1416 fn op_type(&self) -> UserOperation {
1417 UserOperation::EditComment
1420 fn perform(&self, chat: &mut ChatServer, addr: usize) -> Result<String, Error> {
1422 let conn = establish_connection();
1424 let claims = match Claims::decode(&self.auth) {
1425 Ok(claims) => claims.claims,
1427 return Err(self.error("Not logged in."))?
1431 let user_id = claims.id;
1433 let orig_comment = CommentView::read(&conn, self.edit_id, None)?;
1435 // You are allowed to mark the comment as read even if you're banned.
1436 if self.read.is_none() {
1438 // Verify its the creator or a mod, or an admin
1439 let mut editors: Vec<i32> = vec![self.creator_id];
1441 &mut CommunityModeratorView::for_community(&conn, orig_comment.community_id)
1448 &mut UserView::admins(&conn)
1455 if !editors.contains(&user_id) {
1456 return Err(self.error("Not allowed to edit comment."))?
1459 // Check for a community ban
1460 if CommunityUserBanView::get(&conn, user_id, orig_comment.community_id).is_ok() {
1461 return Err(self.error("You have been banned from this community"))?
1464 // Check for a site ban
1465 if UserView::read(&conn, user_id)?.banned {
1466 return Err(self.error("You have been banned from the site"))?
1471 let content_slurs_removed = remove_slurs(&self.content.to_owned());
1473 let comment_form = CommentForm {
1474 content: content_slurs_removed,
1475 parent_id: self.parent_id,
1476 post_id: self.post_id,
1477 creator_id: self.creator_id,
1478 removed: self.removed.to_owned(),
1479 deleted: self.deleted.to_owned(),
1480 read: self.read.to_owned(),
1481 updated: if self.read.is_some() { orig_comment.updated } else {Some(naive_now())}
1484 let _updated_comment = match Comment::update(&conn, self.edit_id, &comment_form) {
1485 Ok(comment) => comment,
1487 return Err(self.error("Couldn't update Comment"))?
1492 if let Some(removed) = self.removed.to_owned() {
1493 let form = ModRemoveCommentForm {
1494 mod_user_id: user_id,
1495 comment_id: self.edit_id,
1496 removed: Some(removed),
1497 reason: self.reason.to_owned(),
1499 ModRemoveComment::create(&conn, &form)?;
1503 let comment_view = CommentView::read(&conn, self.edit_id, Some(user_id))?;
1505 let mut comment_sent = comment_view.clone();
1506 comment_sent.my_vote = None;
1507 comment_sent.user_id = None;
1509 let comment_out = serde_json::to_string(
1511 op: self.op_type().to_string(),
1512 comment: comment_view
1516 let comment_sent_out = serde_json::to_string(
1518 op: self.op_type().to_string(),
1519 comment: comment_sent
1523 chat.send_room_message(self.post_id, &comment_sent_out, addr);
1529 impl Perform for SaveComment {
1530 fn op_type(&self) -> UserOperation {
1531 UserOperation::SaveComment
1534 fn perform(&self, _chat: &mut ChatServer, _addr: usize) -> Result<String, Error> {
1536 let conn = establish_connection();
1538 let claims = match Claims::decode(&self.auth) {
1539 Ok(claims) => claims.claims,
1541 return Err(self.error("Not logged in."))?
1545 let user_id = claims.id;
1547 let comment_saved_form = CommentSavedForm {
1548 comment_id: self.comment_id,
1553 match CommentSaved::save(&conn, &comment_saved_form) {
1554 Ok(comment) => comment,
1556 return Err(self.error("Couldnt do comment save"))?
1560 match CommentSaved::unsave(&conn, &comment_saved_form) {
1561 Ok(comment) => comment,
1563 return Err(self.error("Couldnt do comment save"))?
1568 let comment_view = CommentView::read(&conn, self.comment_id, Some(user_id))?;
1570 let comment_out = serde_json::to_string(
1572 op: self.op_type().to_string(),
1573 comment: comment_view
1583 impl Perform for CreateCommentLike {
1584 fn op_type(&self) -> UserOperation {
1585 UserOperation::CreateCommentLike
1588 fn perform(&self, chat: &mut ChatServer, addr: usize) -> Result<String, Error> {
1590 let conn = establish_connection();
1592 chat.check_rate_limit(addr)?;
1594 let claims = match Claims::decode(&self.auth) {
1595 Ok(claims) => claims.claims,
1597 return Err(self.error("Not logged in."))?
1601 let user_id = claims.id;
1603 // Check for a community ban
1604 let post = Post::read(&conn, self.post_id)?;
1605 if CommunityUserBanView::get(&conn, user_id, post.community_id).is_ok() {
1606 return Err(self.error("You have been banned from this community"))?
1609 // Check for a site ban
1610 if UserView::read(&conn, user_id)?.banned {
1611 return Err(self.error("You have been banned from the site"))?
1614 let like_form = CommentLikeForm {
1615 comment_id: self.comment_id,
1616 post_id: self.post_id,
1621 // Remove any likes first
1622 CommentLike::remove(&conn, &like_form)?;
1624 // Only add the like if the score isnt 0
1625 if &like_form.score != &0 {
1626 let _inserted_like = match CommentLike::like(&conn, &like_form) {
1629 return Err(self.error("Couldn't like comment."))?
1634 // Have to refetch the comment to get the current state
1635 let liked_comment = CommentView::read(&conn, self.comment_id, Some(user_id))?;
1637 let mut liked_comment_sent = liked_comment.clone();
1638 liked_comment_sent.my_vote = None;
1639 liked_comment_sent.user_id = None;
1641 let like_out = serde_json::to_string(
1643 op: self.op_type().to_string(),
1644 comment: liked_comment
1648 let like_sent_out = serde_json::to_string(
1650 op: self.op_type().to_string(),
1651 comment: liked_comment_sent
1655 chat.send_room_message(self.post_id, &like_sent_out, addr);
1662 impl Perform for GetPosts {
1663 fn op_type(&self) -> UserOperation {
1664 UserOperation::GetPosts
1667 fn perform(&self, _chat: &mut ChatServer, _addr: usize) -> Result<String, Error> {
1669 let conn = establish_connection();
1671 let user_id: Option<i32> = match &self.auth {
1673 match Claims::decode(&auth) {
1675 let user_id = claims.claims.id;
1684 let type_ = PostListingType::from_str(&self.type_)?;
1685 let sort = SortType::from_str(&self.sort)?;
1687 let posts = match PostView::list(&conn,
1700 return Err(self.error("Couldn't get posts"))?
1706 serde_json::to_string(
1708 op: self.op_type().to_string(),
1717 impl Perform for CreatePostLike {
1718 fn op_type(&self) -> UserOperation {
1719 UserOperation::CreatePostLike
1722 fn perform(&self, chat: &mut ChatServer, addr: usize) -> Result<String, Error> {
1724 let conn = establish_connection();
1726 chat.check_rate_limit(addr)?;
1728 let claims = match Claims::decode(&self.auth) {
1729 Ok(claims) => claims.claims,
1731 return Err(self.error("Not logged in."))?
1735 let user_id = claims.id;
1737 // Check for a community ban
1738 let post = Post::read(&conn, self.post_id)?;
1739 if CommunityUserBanView::get(&conn, user_id, post.community_id).is_ok() {
1740 return Err(self.error("You have been banned from this community"))?
1743 // Check for a site ban
1744 if UserView::read(&conn, user_id)?.banned {
1745 return Err(self.error("You have been banned from the site"))?
1748 let like_form = PostLikeForm {
1749 post_id: self.post_id,
1754 // Remove any likes first
1755 PostLike::remove(&conn, &like_form)?;
1757 // Only add the like if the score isnt 0
1758 if &like_form.score != &0 {
1759 let _inserted_like = match PostLike::like(&conn, &like_form) {
1762 return Err(self.error("Couldn't like post."))?
1767 let post_view = match PostView::read(&conn, self.post_id, Some(user_id)) {
1770 return Err(self.error("Couldn't find Post"))?
1774 // just output the score
1776 let like_out = serde_json::to_string(
1777 &CreatePostLikeResponse {
1778 op: self.op_type().to_string(),
1787 impl Perform for EditPost {
1788 fn op_type(&self) -> UserOperation {
1789 UserOperation::EditPost
1792 fn perform(&self, chat: &mut ChatServer, addr: usize) -> Result<String, Error> {
1794 if has_slurs(&self.name) ||
1795 (self.body.is_some() && has_slurs(&self.body.to_owned().unwrap())) {
1796 return Err(self.error("No slurs"))?
1799 let conn = establish_connection();
1801 let claims = match Claims::decode(&self.auth) {
1802 Ok(claims) => claims.claims,
1804 return Err(self.error("Not logged in."))?
1808 let user_id = claims.id;
1810 // Verify its the creator or a mod or admin
1811 let mut editors: Vec<i32> = vec![self.creator_id];
1813 &mut CommunityModeratorView::for_community(&conn, self.community_id)
1820 &mut UserView::admins(&conn)
1826 if !editors.contains(&user_id) {
1827 return Err(self.error("Not allowed to edit post."))?
1830 // Check for a community ban
1831 if CommunityUserBanView::get(&conn, user_id, self.community_id).is_ok() {
1832 return Err(self.error("You have been banned from this community"))?
1835 // Check for a site ban
1836 if UserView::read(&conn, user_id)?.banned {
1837 return Err(self.error("You have been banned from the site"))?
1840 let post_form = PostForm {
1841 name: self.name.to_owned(),
1842 url: self.url.to_owned(),
1843 body: self.body.to_owned(),
1844 creator_id: self.creator_id.to_owned(),
1845 community_id: self.community_id,
1846 removed: self.removed.to_owned(),
1847 deleted: self.deleted.to_owned(),
1848 locked: self.locked.to_owned(),
1849 updated: Some(naive_now())
1852 let _updated_post = match Post::update(&conn, self.edit_id, &post_form) {
1855 return Err(self.error("Couldn't update Post"))?
1860 if let Some(removed) = self.removed.to_owned() {
1861 let form = ModRemovePostForm {
1862 mod_user_id: user_id,
1863 post_id: self.edit_id,
1864 removed: Some(removed),
1865 reason: self.reason.to_owned(),
1867 ModRemovePost::create(&conn, &form)?;
1870 if let Some(locked) = self.locked.to_owned() {
1871 let form = ModLockPostForm {
1872 mod_user_id: user_id,
1873 post_id: self.edit_id,
1874 locked: Some(locked),
1876 ModLockPost::create(&conn, &form)?;
1879 let post_view = PostView::read(&conn, self.edit_id, Some(user_id))?;
1881 let mut post_sent = post_view.clone();
1882 post_sent.my_vote = None;
1884 let post_out = serde_json::to_string(
1886 op: self.op_type().to_string(),
1892 let post_sent_out = serde_json::to_string(
1894 op: self.op_type().to_string(),
1900 chat.send_room_message(self.edit_id, &post_sent_out, addr);
1906 impl Perform for SavePost {
1907 fn op_type(&self) -> UserOperation {
1908 UserOperation::SavePost
1911 fn perform(&self, _chat: &mut ChatServer, _addr: usize) -> Result<String, Error> {
1913 let conn = establish_connection();
1915 let claims = match Claims::decode(&self.auth) {
1916 Ok(claims) => claims.claims,
1918 return Err(self.error("Not logged in."))?
1922 let user_id = claims.id;
1924 let post_saved_form = PostSavedForm {
1925 post_id: self.post_id,
1930 match PostSaved::save(&conn, &post_saved_form) {
1933 return Err(self.error("Couldnt do post save"))?
1937 match PostSaved::unsave(&conn, &post_saved_form) {
1940 return Err(self.error("Couldnt do post save"))?
1945 let post_view = PostView::read(&conn, self.post_id, Some(user_id))?;
1947 let post_out = serde_json::to_string(
1949 op: self.op_type().to_string(),
1959 impl Perform for EditCommunity {
1960 fn op_type(&self) -> UserOperation {
1961 UserOperation::EditCommunity
1964 fn perform(&self, chat: &mut ChatServer, addr: usize) -> Result<String, Error> {
1966 if has_slurs(&self.name) || has_slurs(&self.title) {
1967 return Err(self.error("No slurs"))?
1970 let conn = establish_connection();
1972 let claims = match Claims::decode(&self.auth) {
1973 Ok(claims) => claims.claims,
1975 return Err(self.error("Not logged in."))?
1979 let user_id = claims.id;
1981 // Check for a site ban
1982 if UserView::read(&conn, user_id)?.banned {
1983 return Err(self.error("You have been banned from the site"))?
1987 let mut editors: Vec<i32> = Vec::new();
1989 &mut CommunityModeratorView::for_community(&conn, self.edit_id)
1996 &mut UserView::admins(&conn)
2002 if !editors.contains(&user_id) {
2003 return Err(self.error("Not allowed to edit community"))?
2006 let community_form = CommunityForm {
2007 name: self.name.to_owned(),
2008 title: self.title.to_owned(),
2009 description: self.description.to_owned(),
2010 category_id: self.category_id.to_owned(),
2011 creator_id: user_id,
2012 removed: self.removed.to_owned(),
2013 deleted: self.deleted.to_owned(),
2014 updated: Some(naive_now())
2017 let _updated_community = match Community::update(&conn, self.edit_id, &community_form) {
2018 Ok(community) => community,
2020 return Err(self.error("Couldn't update Community"))?
2025 if let Some(removed) = self.removed.to_owned() {
2026 let expires = match self.expires {
2027 Some(time) => Some(naive_from_unix(time)),
2030 let form = ModRemoveCommunityForm {
2031 mod_user_id: user_id,
2032 community_id: self.edit_id,
2033 removed: Some(removed),
2034 reason: self.reason.to_owned(),
2037 ModRemoveCommunity::create(&conn, &form)?;
2040 let community_view = CommunityView::read(&conn, self.edit_id, Some(user_id))?;
2042 let community_out = serde_json::to_string(
2043 &CommunityResponse {
2044 op: self.op_type().to_string(),
2045 community: community_view
2050 let community_view_sent = CommunityView::read(&conn, self.edit_id, None)?;
2052 let community_sent = serde_json::to_string(
2053 &CommunityResponse {
2054 op: self.op_type().to_string(),
2055 community: community_view_sent
2060 chat.send_community_message(&conn, self.edit_id, &community_sent, addr)?;
2067 impl Perform for FollowCommunity {
2068 fn op_type(&self) -> UserOperation {
2069 UserOperation::FollowCommunity
2072 fn perform(&self, _chat: &mut ChatServer, _addr: usize) -> Result<String, Error> {
2074 let conn = establish_connection();
2076 let claims = match Claims::decode(&self.auth) {
2077 Ok(claims) => claims.claims,
2079 return Err(self.error("Not logged in."))?
2083 let user_id = claims.id;
2085 let community_follower_form = CommunityFollowerForm {
2086 community_id: self.community_id,
2092 match CommunityFollower::follow(&conn, &community_follower_form) {
2095 return Err(self.error("Community follower already exists."))?
2099 match CommunityFollower::ignore(&conn, &community_follower_form) {
2102 return Err(self.error("Community follower already exists."))?
2107 let community_view = CommunityView::read(&conn, self.community_id, Some(user_id))?;
2110 serde_json::to_string(
2111 &CommunityResponse {
2112 op: self.op_type().to_string(),
2113 community: community_view
2120 impl Perform for GetFollowedCommunities {
2121 fn op_type(&self) -> UserOperation {
2122 UserOperation::GetFollowedCommunities
2125 fn perform(&self, _chat: &mut ChatServer, _addr: usize) -> Result<String, Error> {
2127 let conn = establish_connection();
2129 let claims = match Claims::decode(&self.auth) {
2130 Ok(claims) => claims.claims,
2132 return Err(self.error("Not logged in."))?
2136 let user_id = claims.id;
2138 let communities: Vec<CommunityFollowerView> = match CommunityFollowerView::for_user(&conn, user_id) {
2139 Ok(communities) => communities,
2141 return Err(self.error("System error, try logging out and back in."))?
2147 serde_json::to_string(
2148 &GetFollowedCommunitiesResponse {
2149 op: self.op_type().to_string(),
2150 communities: communities
2157 impl Perform for GetUserDetails {
2158 fn op_type(&self) -> UserOperation {
2159 UserOperation::GetUserDetails
2162 fn perform(&self, _chat: &mut ChatServer, _addr: usize) -> Result<String, Error> {
2164 let conn = establish_connection();
2166 let user_id: Option<i32> = match &self.auth {
2168 match Claims::decode(&auth) {
2170 let user_id = claims.claims.id;
2180 let sort = SortType::from_str(&self.sort)?;
2182 let user_details_id = match self.user_id {
2184 None => User_::read_from_name(&conn, self.username.to_owned().unwrap_or("admin".to_string()))?.id
2187 let user_view = UserView::read(&conn, user_details_id)?;
2189 // If its saved only, you don't care what creator it was
2190 let posts = if self.saved_only {
2191 PostView::list(&conn,
2192 PostListingType::All,
2197 Some(user_details_id),
2203 PostView::list(&conn,
2204 PostListingType::All,
2207 Some(user_details_id),
2215 let comments = if self.saved_only {
2216 CommentView::list(&conn,
2221 Some(user_details_id),
2226 CommentView::list(&conn,
2229 Some(user_details_id),
2237 let follows = CommunityFollowerView::for_user(&conn, user_details_id)?;
2238 let moderates = CommunityModeratorView::for_user(&conn, user_details_id)?;
2242 serde_json::to_string(
2243 &GetUserDetailsResponse {
2244 op: self.op_type().to_string(),
2247 moderates: moderates,
2256 impl Perform for GetModlog {
2257 fn op_type(&self) -> UserOperation {
2258 UserOperation::GetModlog
2261 fn perform(&self, _chat: &mut ChatServer, _addr: usize) -> Result<String, Error> {
2263 let conn = establish_connection();
2265 let removed_posts = ModRemovePostView::list(&conn, self.community_id, self.mod_user_id, self.page, self.limit)?;
2266 let locked_posts = ModLockPostView::list(&conn, self.community_id, self.mod_user_id, self.page, self.limit)?;
2267 let removed_comments = ModRemoveCommentView::list(&conn, self.community_id, self.mod_user_id, self.page, self.limit)?;
2268 let banned_from_community = ModBanFromCommunityView::list(&conn, self.community_id, self.mod_user_id, self.page, self.limit)?;
2269 let added_to_community = ModAddCommunityView::list(&conn, self.community_id, self.mod_user_id, self.page, self.limit)?;
2271 // These arrays are only for the full modlog, when a community isn't given
2272 let mut removed_communities = Vec::new();
2273 let mut banned = Vec::new();
2274 let mut added = Vec::new();
2276 if self.community_id.is_none() {
2277 removed_communities = ModRemoveCommunityView::list(&conn, self.mod_user_id, self.page, self.limit)?;
2278 banned = ModBanView::list(&conn, self.mod_user_id, self.page, self.limit)?;
2279 added = ModAddView::list(&conn, self.mod_user_id, self.page, self.limit)?;
2284 serde_json::to_string(
2285 &GetModlogResponse {
2286 op: self.op_type().to_string(),
2287 removed_posts: removed_posts,
2288 locked_posts: locked_posts,
2289 removed_comments: removed_comments,
2290 removed_communities: removed_communities,
2291 banned_from_community: banned_from_community,
2293 added_to_community: added_to_community,
2301 impl Perform for GetReplies {
2302 fn op_type(&self) -> UserOperation {
2303 UserOperation::GetReplies
2306 fn perform(&self, _chat: &mut ChatServer, _addr: usize) -> Result<String, Error> {
2308 let conn = establish_connection();
2310 let claims = match Claims::decode(&self.auth) {
2311 Ok(claims) => claims.claims,
2313 return Err(self.error("Not logged in."))?
2317 let user_id = claims.id;
2319 let sort = SortType::from_str(&self.sort)?;
2321 let replies = ReplyView::get_replies(&conn, user_id, &sort, self.unread_only, self.page, self.limit)?;
2325 serde_json::to_string(
2326 &GetRepliesResponse {
2327 op: self.op_type().to_string(),
2335 impl Perform for BanFromCommunity {
2336 fn op_type(&self) -> UserOperation {
2337 UserOperation::BanFromCommunity
2340 fn perform(&self, chat: &mut ChatServer, addr: usize) -> Result<String, Error> {
2342 let conn = establish_connection();
2344 let claims = match Claims::decode(&self.auth) {
2345 Ok(claims) => claims.claims,
2347 return Err(self.error("Not logged in."))?
2351 let user_id = claims.id;
2353 let community_user_ban_form = CommunityUserBanForm {
2354 community_id: self.community_id,
2355 user_id: self.user_id,
2359 match CommunityUserBan::ban(&conn, &community_user_ban_form) {
2362 return Err(self.error("Community user ban already exists"))?
2366 match CommunityUserBan::unban(&conn, &community_user_ban_form) {
2369 return Err(self.error("Community user ban already exists"))?
2375 let expires = match self.expires {
2376 Some(time) => Some(naive_from_unix(time)),
2380 let form = ModBanFromCommunityForm {
2381 mod_user_id: user_id,
2382 other_user_id: self.user_id,
2383 community_id: self.community_id,
2384 reason: self.reason.to_owned(),
2385 banned: Some(self.ban),
2388 ModBanFromCommunity::create(&conn, &form)?;
2390 let user_view = UserView::read(&conn, self.user_id)?;
2392 let res = serde_json::to_string(
2393 &BanFromCommunityResponse {
2394 op: self.op_type().to_string(),
2402 chat.send_community_message(&conn, self.community_id, &res, addr)?;
2408 impl Perform for AddModToCommunity {
2409 fn op_type(&self) -> UserOperation {
2410 UserOperation::AddModToCommunity
2413 fn perform(&self, chat: &mut ChatServer, addr: usize) -> Result<String, Error> {
2415 let conn = establish_connection();
2417 let claims = match Claims::decode(&self.auth) {
2418 Ok(claims) => claims.claims,
2420 return Err(self.error("Not logged in."))?
2424 let user_id = claims.id;
2426 let community_moderator_form = CommunityModeratorForm {
2427 community_id: self.community_id,
2428 user_id: self.user_id
2432 match CommunityModerator::join(&conn, &community_moderator_form) {
2435 return Err(self.error("Community moderator already exists."))?
2439 match CommunityModerator::leave(&conn, &community_moderator_form) {
2442 return Err(self.error("Community moderator already exists."))?
2448 let form = ModAddCommunityForm {
2449 mod_user_id: user_id,
2450 other_user_id: self.user_id,
2451 community_id: self.community_id,
2452 removed: Some(!self.added),
2454 ModAddCommunity::create(&conn, &form)?;
2456 let moderators = CommunityModeratorView::for_community(&conn, self.community_id)?;
2458 let res = serde_json::to_string(
2459 &AddModToCommunityResponse {
2460 op: self.op_type().to_string(),
2461 moderators: moderators,
2467 chat.send_community_message(&conn, self.community_id, &res, addr)?;
2474 impl Perform for CreateSite {
2475 fn op_type(&self) -> UserOperation {
2476 UserOperation::CreateSite
2479 fn perform(&self, _chat: &mut ChatServer, _addr: usize) -> Result<String, Error> {
2481 let conn = establish_connection();
2483 let claims = match Claims::decode(&self.auth) {
2484 Ok(claims) => claims.claims,
2486 return Err(self.error("Not logged in."))?
2490 if has_slurs(&self.name) ||
2491 (self.description.is_some() && has_slurs(&self.description.to_owned().unwrap())) {
2492 return Err(self.error("No slurs"))?
2495 let user_id = claims.id;
2497 // Make sure user is an admin
2498 if !UserView::read(&conn, user_id)?.admin {
2499 return Err(self.error("Not an admin."))?
2502 let site_form = SiteForm {
2503 name: self.name.to_owned(),
2504 description: self.description.to_owned(),
2505 creator_id: user_id,
2509 match Site::create(&conn, &site_form) {
2512 return Err(self.error("Site exists already"))?
2516 let site_view = SiteView::read(&conn)?;
2519 serde_json::to_string(
2521 op: self.op_type().to_string(),
2529 impl Perform for EditSite {
2530 fn op_type(&self) -> UserOperation {
2531 UserOperation::EditSite
2534 fn perform(&self, _chat: &mut ChatServer, _addr: usize) -> Result<String, Error> {
2536 let conn = establish_connection();
2538 let claims = match Claims::decode(&self.auth) {
2539 Ok(claims) => claims.claims,
2541 return Err(self.error("Not logged in."))?
2545 if has_slurs(&self.name) ||
2546 (self.description.is_some() && has_slurs(&self.description.to_owned().unwrap())) {
2547 return Err(self.error("No slurs"))?
2550 let user_id = claims.id;
2552 // Make sure user is an admin
2553 if UserView::read(&conn, user_id)?.admin == false {
2554 return Err(self.error("Not an admin."))?
2557 let found_site = Site::read(&conn, 1)?;
2559 let site_form = SiteForm {
2560 name: self.name.to_owned(),
2561 description: self.description.to_owned(),
2562 creator_id: found_site.creator_id,
2563 updated: Some(naive_now()),
2566 match Site::update(&conn, 1, &site_form) {
2569 return Err(self.error("Couldn't update site."))?
2573 let site_view = SiteView::read(&conn)?;
2576 serde_json::to_string(
2578 op: self.op_type().to_string(),
2586 impl Perform for GetSite {
2587 fn op_type(&self) -> UserOperation {
2588 UserOperation::GetSite
2591 fn perform(&self, _chat: &mut ChatServer, _addr: usize) -> Result<String, Error> {
2593 let conn = establish_connection();
2595 // It can return a null site in order to redirect
2596 let site_view = match Site::read(&conn, 1) {
2597 Ok(_site) => Some(SiteView::read(&conn)?),
2601 let admins = UserView::admins(&conn)?;
2602 let banned = UserView::banned(&conn)?;
2605 serde_json::to_string(
2607 op: self.op_type().to_string(),
2617 impl Perform for AddAdmin {
2618 fn op_type(&self) -> UserOperation {
2619 UserOperation::AddAdmin
2622 fn perform(&self, _chat: &mut ChatServer, _addr: usize) -> Result<String, Error> {
2624 let conn = establish_connection();
2626 let claims = match Claims::decode(&self.auth) {
2627 Ok(claims) => claims.claims,
2629 return Err(self.error("Not logged in."))?
2633 let user_id = claims.id;
2635 // Make sure user is an admin
2636 if UserView::read(&conn, user_id)?.admin == false {
2637 return Err(self.error("Not an admin."))?
2640 let read_user = User_::read(&conn, self.user_id)?;
2642 let user_form = UserForm {
2643 name: read_user.name,
2644 fedi_name: read_user.fedi_name,
2645 email: read_user.email,
2646 password_encrypted: read_user.password_encrypted,
2647 preferred_username: read_user.preferred_username,
2648 updated: Some(naive_now()),
2650 banned: read_user.banned,
2653 match User_::update(&conn, self.user_id, &user_form) {
2656 return Err(self.error("Couldn't update user"))?
2661 let form = ModAddForm {
2662 mod_user_id: user_id,
2663 other_user_id: self.user_id,
2664 removed: Some(!self.added),
2667 ModAdd::create(&conn, &form)?;
2669 let admins = UserView::admins(&conn)?;
2671 let res = serde_json::to_string(
2673 op: self.op_type().to_string(),
2685 impl Perform for BanUser {
2686 fn op_type(&self) -> UserOperation {
2687 UserOperation::BanUser
2690 fn perform(&self, _chat: &mut ChatServer, _addr: usize) -> Result<String, Error> {
2692 let conn = establish_connection();
2694 let claims = match Claims::decode(&self.auth) {
2695 Ok(claims) => claims.claims,
2697 return Err(self.error("Not logged in."))?
2701 let user_id = claims.id;
2703 // Make sure user is an admin
2704 if UserView::read(&conn, user_id)?.admin == false {
2705 return Err(self.error("Not an admin."))?
2708 let read_user = User_::read(&conn, self.user_id)?;
2710 let user_form = UserForm {
2711 name: read_user.name,
2712 fedi_name: read_user.fedi_name,
2713 email: read_user.email,
2714 password_encrypted: read_user.password_encrypted,
2715 preferred_username: read_user.preferred_username,
2716 updated: Some(naive_now()),
2717 admin: read_user.admin,
2721 match User_::update(&conn, self.user_id, &user_form) {
2724 return Err(self.error("Couldn't update user"))?
2729 let expires = match self.expires {
2730 Some(time) => Some(naive_from_unix(time)),
2734 let form = ModBanForm {
2735 mod_user_id: user_id,
2736 other_user_id: self.user_id,
2737 reason: self.reason.to_owned(),
2738 banned: Some(self.ban),
2742 ModBan::create(&conn, &form)?;
2744 let user_view = UserView::read(&conn, self.user_id)?;
2746 let res = serde_json::to_string(
2748 op: self.op_type().to_string(),
2760 impl Perform for Search {
2761 fn op_type(&self) -> UserOperation {
2762 UserOperation::Search
2765 fn perform(&self, _chat: &mut ChatServer, _addr: usize) -> Result<String, Error> {
2767 let conn = establish_connection();
2769 let sort = SortType::from_str(&self.sort)?;
2770 let type_ = SearchType::from_str(&self.type_)?;
2772 let mut posts = Vec::new();
2773 let mut comments = Vec::new();
2776 SearchType::Posts => {
2777 posts = PostView::list(&conn,
2778 PostListingType::All,
2782 Some(self.q.to_owned()),
2789 SearchType::Comments => {
2790 comments = CommentView::list(&conn,
2794 Some(self.q.to_owned()),
2800 SearchType::Both => {
2801 posts = PostView::list(&conn,
2802 PostListingType::All,
2806 Some(self.q.to_owned()),
2812 comments = CommentView::list(&conn,
2816 Some(self.q.to_owned()),
2827 serde_json::to_string(
2829 op: self.op_type().to_string(),
2839 impl Perform for MarkAllAsRead {
2840 fn op_type(&self) -> UserOperation {
2841 UserOperation::MarkAllAsRead
2844 fn perform(&self, _chat: &mut ChatServer, _addr: usize) -> Result<String, Error> {
2846 let conn = establish_connection();
2848 let claims = match Claims::decode(&self.auth) {
2849 Ok(claims) => claims.claims,
2851 return Err(self.error("Not logged in."))?
2855 let user_id = claims.id;
2857 let replies = ReplyView::get_replies(&conn, user_id, &SortType::New, true, Some(1), Some(999))?;
2859 for reply in &replies {
2860 let comment_form = CommentForm {
2861 content: reply.to_owned().content,
2862 parent_id: reply.to_owned().parent_id,
2863 post_id: reply.to_owned().post_id,
2864 creator_id: reply.to_owned().creator_id,
2868 updated: reply.to_owned().updated
2871 let _updated_comment = match Comment::update(&conn, reply.id, &comment_form) {
2872 Ok(comment) => comment,
2874 return Err(self.error("Couldn't update Comment"))?
2879 let replies = ReplyView::get_replies(&conn, user_id, &SortType::New, true, Some(1), Some(999))?;
2882 serde_json::to_string(
2883 &GetRepliesResponse {
2884 op: self.op_type().to_string(),