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 the room doesn't exist yet
1237 if chat.rooms.get_mut(&self.id).is_none() {
1238 chat.rooms.insert(self.id, HashSet::new());
1241 chat.rooms.get_mut(&self.id).unwrap().insert(addr);
1243 let comments = CommentView::list(&conn, &SortType::New, Some(self.id), None, None, user_id, false, None, Some(9999))?;
1245 let community = CommunityView::read(&conn, post_view.community_id, user_id)?;
1247 let moderators = CommunityModeratorView::for_community(&conn, post_view.community_id)?;
1249 let admins = UserView::admins(&conn)?;
1253 serde_json::to_string(
1255 op: self.op_type().to_string(),
1258 community: community,
1259 moderators: moderators,
1267 impl Perform for GetCommunity {
1268 fn op_type(&self) -> UserOperation {
1269 UserOperation::GetCommunity
1272 fn perform(&self, _chat: &mut ChatServer, _addr: usize) -> Result<String, Error> {
1274 let conn = establish_connection();
1276 let user_id: Option<i32> = match &self.auth {
1278 match Claims::decode(&auth) {
1280 let user_id = claims.claims.id;
1289 let community_id = match self.id {
1291 None => Community::read_from_name(&conn, self.name.to_owned().unwrap_or("main".to_string()))?.id
1294 let community_view = match CommunityView::read(&conn, community_id, user_id) {
1295 Ok(community) => community,
1297 return Err(self.error("Couldn't find Community"))?
1301 let moderators = match CommunityModeratorView::for_community(&conn, community_id) {
1302 Ok(moderators) => moderators,
1304 return Err(self.error("Couldn't find Community"))?
1308 let admins = UserView::admins(&conn)?;
1312 serde_json::to_string(
1313 &GetCommunityResponse {
1314 op: self.op_type().to_string(),
1315 community: community_view,
1316 moderators: moderators,
1324 impl Perform for CreateComment {
1325 fn op_type(&self) -> UserOperation {
1326 UserOperation::CreateComment
1329 fn perform(&self, chat: &mut ChatServer, addr: usize) -> Result<String, Error> {
1331 let conn = establish_connection();
1333 chat.check_rate_limit(addr)?;
1335 let claims = match Claims::decode(&self.auth) {
1336 Ok(claims) => claims.claims,
1338 return Err(self.error("Not logged in."))?
1342 let user_id = claims.id;
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"))?
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"))?
1355 let content_slurs_removed = remove_slurs(&self.content.to_owned());
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,
1368 let inserted_comment = match Comment::create(&conn, &comment_form) {
1369 Ok(comment) => comment,
1371 return Err(self.error("Couldn't create Comment"))?
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,
1383 let _inserted_like = match CommentLike::like(&conn, &like_form) {
1386 return Err(self.error("Couldn't like comment."))?
1390 let comment_view = CommentView::read(&conn, inserted_comment.id, Some(user_id))?;
1392 let mut comment_sent = comment_view.clone();
1393 comment_sent.my_vote = None;
1394 comment_sent.user_id = None;
1396 let comment_out = serde_json::to_string(
1398 op: self.op_type().to_string(),
1399 comment: comment_view
1403 let comment_sent_out = serde_json::to_string(
1405 op: self.op_type().to_string(),
1406 comment: comment_sent
1410 chat.send_room_message(self.post_id, &comment_sent_out, addr);
1416 impl Perform for EditComment {
1417 fn op_type(&self) -> UserOperation {
1418 UserOperation::EditComment
1421 fn perform(&self, chat: &mut ChatServer, addr: usize) -> Result<String, Error> {
1423 let conn = establish_connection();
1425 let claims = match Claims::decode(&self.auth) {
1426 Ok(claims) => claims.claims,
1428 return Err(self.error("Not logged in."))?
1432 let user_id = claims.id;
1434 let orig_comment = CommentView::read(&conn, self.edit_id, None)?;
1436 // You are allowed to mark the comment as read even if you're banned.
1437 if self.read.is_none() {
1439 // Verify its the creator or a mod, or an admin
1440 let mut editors: Vec<i32> = vec![self.creator_id];
1442 &mut CommunityModeratorView::for_community(&conn, orig_comment.community_id)
1449 &mut UserView::admins(&conn)
1456 if !editors.contains(&user_id) {
1457 return Err(self.error("Not allowed to edit comment."))?
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"))?
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"))?
1472 let content_slurs_removed = remove_slurs(&self.content.to_owned());
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())}
1485 let _updated_comment = match Comment::update(&conn, self.edit_id, &comment_form) {
1486 Ok(comment) => comment,
1488 return Err(self.error("Couldn't update Comment"))?
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(),
1500 ModRemoveComment::create(&conn, &form)?;
1504 let comment_view = CommentView::read(&conn, self.edit_id, Some(user_id))?;
1506 let mut comment_sent = comment_view.clone();
1507 comment_sent.my_vote = None;
1508 comment_sent.user_id = None;
1510 let comment_out = serde_json::to_string(
1512 op: self.op_type().to_string(),
1513 comment: comment_view
1517 let comment_sent_out = serde_json::to_string(
1519 op: self.op_type().to_string(),
1520 comment: comment_sent
1524 chat.send_room_message(self.post_id, &comment_sent_out, addr);
1530 impl Perform for SaveComment {
1531 fn op_type(&self) -> UserOperation {
1532 UserOperation::SaveComment
1535 fn perform(&self, _chat: &mut ChatServer, _addr: usize) -> Result<String, Error> {
1537 let conn = establish_connection();
1539 let claims = match Claims::decode(&self.auth) {
1540 Ok(claims) => claims.claims,
1542 return Err(self.error("Not logged in."))?
1546 let user_id = claims.id;
1548 let comment_saved_form = CommentSavedForm {
1549 comment_id: self.comment_id,
1554 match CommentSaved::save(&conn, &comment_saved_form) {
1555 Ok(comment) => comment,
1557 return Err(self.error("Couldnt do comment save"))?
1561 match CommentSaved::unsave(&conn, &comment_saved_form) {
1562 Ok(comment) => comment,
1564 return Err(self.error("Couldnt do comment save"))?
1569 let comment_view = CommentView::read(&conn, self.comment_id, Some(user_id))?;
1571 let comment_out = serde_json::to_string(
1573 op: self.op_type().to_string(),
1574 comment: comment_view
1584 impl Perform for CreateCommentLike {
1585 fn op_type(&self) -> UserOperation {
1586 UserOperation::CreateCommentLike
1589 fn perform(&self, chat: &mut ChatServer, addr: usize) -> Result<String, Error> {
1591 let conn = establish_connection();
1593 chat.check_rate_limit(addr)?;
1595 let claims = match Claims::decode(&self.auth) {
1596 Ok(claims) => claims.claims,
1598 return Err(self.error("Not logged in."))?
1602 let user_id = claims.id;
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"))?
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"))?
1615 let like_form = CommentLikeForm {
1616 comment_id: self.comment_id,
1617 post_id: self.post_id,
1622 // Remove any likes first
1623 CommentLike::remove(&conn, &like_form)?;
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) {
1630 return Err(self.error("Couldn't like comment."))?
1635 // Have to refetch the comment to get the current state
1636 let liked_comment = CommentView::read(&conn, self.comment_id, Some(user_id))?;
1638 let mut liked_comment_sent = liked_comment.clone();
1639 liked_comment_sent.my_vote = None;
1640 liked_comment_sent.user_id = None;
1642 let like_out = serde_json::to_string(
1644 op: self.op_type().to_string(),
1645 comment: liked_comment
1649 let like_sent_out = serde_json::to_string(
1651 op: self.op_type().to_string(),
1652 comment: liked_comment_sent
1656 chat.send_room_message(self.post_id, &like_sent_out, addr);
1663 impl Perform for GetPosts {
1664 fn op_type(&self) -> UserOperation {
1665 UserOperation::GetPosts
1668 fn perform(&self, _chat: &mut ChatServer, _addr: usize) -> Result<String, Error> {
1670 let conn = establish_connection();
1672 let user_id: Option<i32> = match &self.auth {
1674 match Claims::decode(&auth) {
1676 let user_id = claims.claims.id;
1685 let type_ = PostListingType::from_str(&self.type_)?;
1686 let sort = SortType::from_str(&self.sort)?;
1688 let posts = match PostView::list(&conn,
1701 return Err(self.error("Couldn't get posts"))?
1707 serde_json::to_string(
1709 op: self.op_type().to_string(),
1718 impl Perform for CreatePostLike {
1719 fn op_type(&self) -> UserOperation {
1720 UserOperation::CreatePostLike
1723 fn perform(&self, chat: &mut ChatServer, addr: usize) -> Result<String, Error> {
1725 let conn = establish_connection();
1727 chat.check_rate_limit(addr)?;
1729 let claims = match Claims::decode(&self.auth) {
1730 Ok(claims) => claims.claims,
1732 return Err(self.error("Not logged in."))?
1736 let user_id = claims.id;
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"))?
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"))?
1749 let like_form = PostLikeForm {
1750 post_id: self.post_id,
1755 // Remove any likes first
1756 PostLike::remove(&conn, &like_form)?;
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) {
1763 return Err(self.error("Couldn't like post."))?
1768 let post_view = match PostView::read(&conn, self.post_id, Some(user_id)) {
1771 return Err(self.error("Couldn't find Post"))?
1775 // just output the score
1777 let like_out = serde_json::to_string(
1778 &CreatePostLikeResponse {
1779 op: self.op_type().to_string(),
1788 impl Perform for EditPost {
1789 fn op_type(&self) -> UserOperation {
1790 UserOperation::EditPost
1793 fn perform(&self, chat: &mut ChatServer, addr: usize) -> Result<String, Error> {
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"))?
1800 let conn = establish_connection();
1802 let claims = match Claims::decode(&self.auth) {
1803 Ok(claims) => claims.claims,
1805 return Err(self.error("Not logged in."))?
1809 let user_id = claims.id;
1811 // Verify its the creator or a mod or admin
1812 let mut editors: Vec<i32> = vec![self.creator_id];
1814 &mut CommunityModeratorView::for_community(&conn, self.community_id)
1821 &mut UserView::admins(&conn)
1827 if !editors.contains(&user_id) {
1828 return Err(self.error("Not allowed to edit post."))?
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"))?
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"))?
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())
1853 let _updated_post = match Post::update(&conn, self.edit_id, &post_form) {
1856 return Err(self.error("Couldn't update Post"))?
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(),
1868 ModRemovePost::create(&conn, &form)?;
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),
1877 ModLockPost::create(&conn, &form)?;
1880 let post_view = PostView::read(&conn, self.edit_id, Some(user_id))?;
1882 let mut post_sent = post_view.clone();
1883 post_sent.my_vote = None;
1885 let post_out = serde_json::to_string(
1887 op: self.op_type().to_string(),
1893 let post_sent_out = serde_json::to_string(
1895 op: self.op_type().to_string(),
1901 chat.send_room_message(self.edit_id, &post_sent_out, addr);
1907 impl Perform for SavePost {
1908 fn op_type(&self) -> UserOperation {
1909 UserOperation::SavePost
1912 fn perform(&self, _chat: &mut ChatServer, _addr: usize) -> Result<String, Error> {
1914 let conn = establish_connection();
1916 let claims = match Claims::decode(&self.auth) {
1917 Ok(claims) => claims.claims,
1919 return Err(self.error("Not logged in."))?
1923 let user_id = claims.id;
1925 let post_saved_form = PostSavedForm {
1926 post_id: self.post_id,
1931 match PostSaved::save(&conn, &post_saved_form) {
1934 return Err(self.error("Couldnt do post save"))?
1938 match PostSaved::unsave(&conn, &post_saved_form) {
1941 return Err(self.error("Couldnt do post save"))?
1946 let post_view = PostView::read(&conn, self.post_id, Some(user_id))?;
1948 let post_out = serde_json::to_string(
1950 op: self.op_type().to_string(),
1960 impl Perform for EditCommunity {
1961 fn op_type(&self) -> UserOperation {
1962 UserOperation::EditCommunity
1965 fn perform(&self, chat: &mut ChatServer, addr: usize) -> Result<String, Error> {
1967 if has_slurs(&self.name) || has_slurs(&self.title) {
1968 return Err(self.error("No slurs"))?
1971 let conn = establish_connection();
1973 let claims = match Claims::decode(&self.auth) {
1974 Ok(claims) => claims.claims,
1976 return Err(self.error("Not logged in."))?
1980 let user_id = claims.id;
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"))?
1988 let mut editors: Vec<i32> = Vec::new();
1990 &mut CommunityModeratorView::for_community(&conn, self.edit_id)
1997 &mut UserView::admins(&conn)
2003 if !editors.contains(&user_id) {
2004 return Err(self.error("Not allowed to edit community"))?
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())
2018 let _updated_community = match Community::update(&conn, self.edit_id, &community_form) {
2019 Ok(community) => community,
2021 return Err(self.error("Couldn't update Community"))?
2026 if let Some(removed) = self.removed.to_owned() {
2027 let expires = match self.expires {
2028 Some(time) => Some(naive_from_unix(time)),
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(),
2038 ModRemoveCommunity::create(&conn, &form)?;
2041 let community_view = CommunityView::read(&conn, self.edit_id, Some(user_id))?;
2043 let community_out = serde_json::to_string(
2044 &CommunityResponse {
2045 op: self.op_type().to_string(),
2046 community: community_view
2051 let community_view_sent = CommunityView::read(&conn, self.edit_id, None)?;
2053 let community_sent = serde_json::to_string(
2054 &CommunityResponse {
2055 op: self.op_type().to_string(),
2056 community: community_view_sent
2061 chat.send_community_message(&conn, self.edit_id, &community_sent, addr)?;
2068 impl Perform for FollowCommunity {
2069 fn op_type(&self) -> UserOperation {
2070 UserOperation::FollowCommunity
2073 fn perform(&self, _chat: &mut ChatServer, _addr: usize) -> Result<String, Error> {
2075 let conn = establish_connection();
2077 let claims = match Claims::decode(&self.auth) {
2078 Ok(claims) => claims.claims,
2080 return Err(self.error("Not logged in."))?
2084 let user_id = claims.id;
2086 let community_follower_form = CommunityFollowerForm {
2087 community_id: self.community_id,
2093 match CommunityFollower::follow(&conn, &community_follower_form) {
2096 return Err(self.error("Community follower already exists."))?
2100 match CommunityFollower::ignore(&conn, &community_follower_form) {
2103 return Err(self.error("Community follower already exists."))?
2108 let community_view = CommunityView::read(&conn, self.community_id, Some(user_id))?;
2111 serde_json::to_string(
2112 &CommunityResponse {
2113 op: self.op_type().to_string(),
2114 community: community_view
2121 impl Perform for GetFollowedCommunities {
2122 fn op_type(&self) -> UserOperation {
2123 UserOperation::GetFollowedCommunities
2126 fn perform(&self, _chat: &mut ChatServer, _addr: usize) -> Result<String, Error> {
2128 let conn = establish_connection();
2130 let claims = match Claims::decode(&self.auth) {
2131 Ok(claims) => claims.claims,
2133 return Err(self.error("Not logged in."))?
2137 let user_id = claims.id;
2139 let communities: Vec<CommunityFollowerView> = match CommunityFollowerView::for_user(&conn, user_id) {
2140 Ok(communities) => communities,
2142 return Err(self.error("System error, try logging out and back in."))?
2148 serde_json::to_string(
2149 &GetFollowedCommunitiesResponse {
2150 op: self.op_type().to_string(),
2151 communities: communities
2158 impl Perform for GetUserDetails {
2159 fn op_type(&self) -> UserOperation {
2160 UserOperation::GetUserDetails
2163 fn perform(&self, _chat: &mut ChatServer, _addr: usize) -> Result<String, Error> {
2165 let conn = establish_connection();
2167 let user_id: Option<i32> = match &self.auth {
2169 match Claims::decode(&auth) {
2171 let user_id = claims.claims.id;
2181 let sort = SortType::from_str(&self.sort)?;
2183 let user_details_id = match self.user_id {
2185 None => User_::read_from_name(&conn, self.username.to_owned().unwrap_or("admin".to_string()))?.id
2188 let user_view = UserView::read(&conn, user_details_id)?;
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,
2198 Some(user_details_id),
2204 PostView::list(&conn,
2205 PostListingType::All,
2208 Some(user_details_id),
2216 let comments = if self.saved_only {
2217 CommentView::list(&conn,
2222 Some(user_details_id),
2227 CommentView::list(&conn,
2230 Some(user_details_id),
2238 let follows = CommunityFollowerView::for_user(&conn, user_details_id)?;
2239 let moderates = CommunityModeratorView::for_user(&conn, user_details_id)?;
2243 serde_json::to_string(
2244 &GetUserDetailsResponse {
2245 op: self.op_type().to_string(),
2248 moderates: moderates,
2257 impl Perform for GetModlog {
2258 fn op_type(&self) -> UserOperation {
2259 UserOperation::GetModlog
2262 fn perform(&self, _chat: &mut ChatServer, _addr: usize) -> Result<String, Error> {
2264 let conn = establish_connection();
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)?;
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();
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)?;
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,
2294 added_to_community: added_to_community,
2302 impl Perform for GetReplies {
2303 fn op_type(&self) -> UserOperation {
2304 UserOperation::GetReplies
2307 fn perform(&self, _chat: &mut ChatServer, _addr: usize) -> Result<String, Error> {
2309 let conn = establish_connection();
2311 let claims = match Claims::decode(&self.auth) {
2312 Ok(claims) => claims.claims,
2314 return Err(self.error("Not logged in."))?
2318 let user_id = claims.id;
2320 let sort = SortType::from_str(&self.sort)?;
2322 let replies = ReplyView::get_replies(&conn, user_id, &sort, self.unread_only, self.page, self.limit)?;
2326 serde_json::to_string(
2327 &GetRepliesResponse {
2328 op: self.op_type().to_string(),
2336 impl Perform for BanFromCommunity {
2337 fn op_type(&self) -> UserOperation {
2338 UserOperation::BanFromCommunity
2341 fn perform(&self, chat: &mut ChatServer, addr: usize) -> Result<String, Error> {
2343 let conn = establish_connection();
2345 let claims = match Claims::decode(&self.auth) {
2346 Ok(claims) => claims.claims,
2348 return Err(self.error("Not logged in."))?
2352 let user_id = claims.id;
2354 let community_user_ban_form = CommunityUserBanForm {
2355 community_id: self.community_id,
2356 user_id: self.user_id,
2360 match CommunityUserBan::ban(&conn, &community_user_ban_form) {
2363 return Err(self.error("Community user ban already exists"))?
2367 match CommunityUserBan::unban(&conn, &community_user_ban_form) {
2370 return Err(self.error("Community user ban already exists"))?
2376 let expires = match self.expires {
2377 Some(time) => Some(naive_from_unix(time)),
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),
2389 ModBanFromCommunity::create(&conn, &form)?;
2391 let user_view = UserView::read(&conn, self.user_id)?;
2393 let res = serde_json::to_string(
2394 &BanFromCommunityResponse {
2395 op: self.op_type().to_string(),
2403 chat.send_community_message(&conn, self.community_id, &res, addr)?;
2409 impl Perform for AddModToCommunity {
2410 fn op_type(&self) -> UserOperation {
2411 UserOperation::AddModToCommunity
2414 fn perform(&self, chat: &mut ChatServer, addr: usize) -> Result<String, Error> {
2416 let conn = establish_connection();
2418 let claims = match Claims::decode(&self.auth) {
2419 Ok(claims) => claims.claims,
2421 return Err(self.error("Not logged in."))?
2425 let user_id = claims.id;
2427 let community_moderator_form = CommunityModeratorForm {
2428 community_id: self.community_id,
2429 user_id: self.user_id
2433 match CommunityModerator::join(&conn, &community_moderator_form) {
2436 return Err(self.error("Community moderator already exists."))?
2440 match CommunityModerator::leave(&conn, &community_moderator_form) {
2443 return Err(self.error("Community moderator already exists."))?
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),
2455 ModAddCommunity::create(&conn, &form)?;
2457 let moderators = CommunityModeratorView::for_community(&conn, self.community_id)?;
2459 let res = serde_json::to_string(
2460 &AddModToCommunityResponse {
2461 op: self.op_type().to_string(),
2462 moderators: moderators,
2468 chat.send_community_message(&conn, self.community_id, &res, addr)?;
2475 impl Perform for CreateSite {
2476 fn op_type(&self) -> UserOperation {
2477 UserOperation::CreateSite
2480 fn perform(&self, _chat: &mut ChatServer, _addr: usize) -> Result<String, Error> {
2482 let conn = establish_connection();
2484 let claims = match Claims::decode(&self.auth) {
2485 Ok(claims) => claims.claims,
2487 return Err(self.error("Not logged in."))?
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"))?
2496 let user_id = claims.id;
2498 // Make sure user is an admin
2499 if !UserView::read(&conn, user_id)?.admin {
2500 return Err(self.error("Not an admin."))?
2503 let site_form = SiteForm {
2504 name: self.name.to_owned(),
2505 description: self.description.to_owned(),
2506 creator_id: user_id,
2510 match Site::create(&conn, &site_form) {
2513 return Err(self.error("Site exists already"))?
2517 let site_view = SiteView::read(&conn)?;
2520 serde_json::to_string(
2522 op: self.op_type().to_string(),
2530 impl Perform for EditSite {
2531 fn op_type(&self) -> UserOperation {
2532 UserOperation::EditSite
2535 fn perform(&self, _chat: &mut ChatServer, _addr: usize) -> Result<String, Error> {
2537 let conn = establish_connection();
2539 let claims = match Claims::decode(&self.auth) {
2540 Ok(claims) => claims.claims,
2542 return Err(self.error("Not logged in."))?
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"))?
2551 let user_id = claims.id;
2553 // Make sure user is an admin
2554 if UserView::read(&conn, user_id)?.admin == false {
2555 return Err(self.error("Not an admin."))?
2558 let found_site = Site::read(&conn, 1)?;
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()),
2567 match Site::update(&conn, 1, &site_form) {
2570 return Err(self.error("Couldn't update site."))?
2574 let site_view = SiteView::read(&conn)?;
2577 serde_json::to_string(
2579 op: self.op_type().to_string(),
2587 impl Perform for GetSite {
2588 fn op_type(&self) -> UserOperation {
2589 UserOperation::GetSite
2592 fn perform(&self, _chat: &mut ChatServer, _addr: usize) -> Result<String, Error> {
2594 let conn = establish_connection();
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)?),
2602 let admins = UserView::admins(&conn)?;
2603 let banned = UserView::banned(&conn)?;
2606 serde_json::to_string(
2608 op: self.op_type().to_string(),
2618 impl Perform for AddAdmin {
2619 fn op_type(&self) -> UserOperation {
2620 UserOperation::AddAdmin
2623 fn perform(&self, _chat: &mut ChatServer, _addr: usize) -> Result<String, Error> {
2625 let conn = establish_connection();
2627 let claims = match Claims::decode(&self.auth) {
2628 Ok(claims) => claims.claims,
2630 return Err(self.error("Not logged in."))?
2634 let user_id = claims.id;
2636 // Make sure user is an admin
2637 if UserView::read(&conn, user_id)?.admin == false {
2638 return Err(self.error("Not an admin."))?
2641 let read_user = User_::read(&conn, self.user_id)?;
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()),
2651 banned: read_user.banned,
2654 match User_::update(&conn, self.user_id, &user_form) {
2657 return Err(self.error("Couldn't update user"))?
2662 let form = ModAddForm {
2663 mod_user_id: user_id,
2664 other_user_id: self.user_id,
2665 removed: Some(!self.added),
2668 ModAdd::create(&conn, &form)?;
2670 let admins = UserView::admins(&conn)?;
2672 let res = serde_json::to_string(
2674 op: self.op_type().to_string(),
2686 impl Perform for BanUser {
2687 fn op_type(&self) -> UserOperation {
2688 UserOperation::BanUser
2691 fn perform(&self, _chat: &mut ChatServer, _addr: usize) -> Result<String, Error> {
2693 let conn = establish_connection();
2695 let claims = match Claims::decode(&self.auth) {
2696 Ok(claims) => claims.claims,
2698 return Err(self.error("Not logged in."))?
2702 let user_id = claims.id;
2704 // Make sure user is an admin
2705 if UserView::read(&conn, user_id)?.admin == false {
2706 return Err(self.error("Not an admin."))?
2709 let read_user = User_::read(&conn, self.user_id)?;
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,
2722 match User_::update(&conn, self.user_id, &user_form) {
2725 return Err(self.error("Couldn't update user"))?
2730 let expires = match self.expires {
2731 Some(time) => Some(naive_from_unix(time)),
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),
2743 ModBan::create(&conn, &form)?;
2745 let user_view = UserView::read(&conn, self.user_id)?;
2747 let res = serde_json::to_string(
2749 op: self.op_type().to_string(),
2761 impl Perform for Search {
2762 fn op_type(&self) -> UserOperation {
2763 UserOperation::Search
2766 fn perform(&self, _chat: &mut ChatServer, _addr: usize) -> Result<String, Error> {
2768 let conn = establish_connection();
2770 let sort = SortType::from_str(&self.sort)?;
2771 let type_ = SearchType::from_str(&self.type_)?;
2773 let mut posts = Vec::new();
2774 let mut comments = Vec::new();
2777 SearchType::Posts => {
2778 posts = PostView::list(&conn,
2779 PostListingType::All,
2783 Some(self.q.to_owned()),
2790 SearchType::Comments => {
2791 comments = CommentView::list(&conn,
2795 Some(self.q.to_owned()),
2801 SearchType::Both => {
2802 posts = PostView::list(&conn,
2803 PostListingType::All,
2807 Some(self.q.to_owned()),
2813 comments = CommentView::list(&conn,
2817 Some(self.q.to_owned()),
2828 serde_json::to_string(
2830 op: self.op_type().to_string(),
2840 impl Perform for MarkAllAsRead {
2841 fn op_type(&self) -> UserOperation {
2842 UserOperation::MarkAllAsRead
2845 fn perform(&self, _chat: &mut ChatServer, _addr: usize) -> Result<String, Error> {
2847 let conn = establish_connection();
2849 let claims = match Claims::decode(&self.auth) {
2850 Ok(claims) => claims.claims,
2852 return Err(self.error("Not logged in."))?
2856 let user_id = claims.id;
2858 let replies = ReplyView::get_replies(&conn, user_id, &SortType::New, true, Some(1), Some(999))?;
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,
2869 updated: reply.to_owned().updated
2872 let _updated_comment = match Comment::update(&conn, reply.id, &comment_form) {
2873 Ok(comment) => comment,
2875 return Err(self.error("Couldn't update Comment"))?
2880 let replies = ReplyView::get_replies(&conn, user_id, &SortType::New, true, Some(1), Some(999))?;
2883 serde_json::to_string(
2884 &GetRepliesResponse {
2885 op: self.op_type().to_string(),