password_verify: String,
}
- op: String,
+#[derive(Serialize, Deserialize)]
+pub struct CreatePrivateMessage {
+ content: String,
+ recipient_id: i32,
+ auth: String,
+}
+
+#[derive(Serialize, Deserialize)]
+pub struct EditPrivateMessage {
+ edit_id: i32,
+ content: Option<String>,
+ deleted: Option<bool>,
+ read: Option<bool>,
+ auth: String,
+}
+
+#[derive(Serialize, Deserialize)]
+pub struct GetPrivateMessages {
+ unread_only: bool,
+ page: Option<i64>,
+ limit: Option<i64>,
+ auth: String,
+}
+
+#[derive(Serialize, Deserialize, Clone)]
+pub struct PrivateMessagesResponse {
- op: String,
+ messages: Vec<PrivateMessageView>,
+}
+
+#[derive(Serialize, Deserialize, Clone)]
+pub struct PrivateMessageResponse {
+ message: PrivateMessageView,
+}
+
impl Perform<LoginResponse> for Oper<Login> {
fn perform(&self, conn: &PgConnection) -> Result<LoginResponse, Error> {
let data: &Login = &self.data;
};
}
- Err(_e) => return Err(APIError::err(&self.op, "couldnt_update_private_message").into()),
+ // messages
+ let messages = PrivateMessageQueryBuilder::create(&conn, user_id)
+ .page(1)
+ .limit(999)
+ .unread_only(true)
+ .list()?;
+
+ for message in &messages {
+ let private_message_form = PrivateMessageForm {
+ content: None,
+ creator_id: message.to_owned().creator_id,
+ recipient_id: message.to_owned().recipient_id,
+ deleted: None,
+ read: Some(true),
+ updated: None,
+ };
+
+ let _updated_message = match PrivateMessage::update(&conn, message.id, &private_message_form)
+ {
+ Ok(message) => message,
- Ok(GetRepliesResponse {
- op: self.op.to_string(),
- replies: vec![],
- })
++ Err(_e) => return Err(APIError::err("couldnt_update_private_message").into()),
+ };
+ }
+
+ Ok(GetRepliesResponse { replies: vec![] })
}
}
})
}
}
- Err(_e) => return Err(APIError::err(&self.op, "not_logged_in").into()),
+
+impl Perform<PrivateMessageResponse> for Oper<CreatePrivateMessage> {
+ fn perform(&self, conn: &PgConnection) -> Result<PrivateMessageResponse, Error> {
+ let data: &CreatePrivateMessage = &self.data;
+
+ let claims = match Claims::decode(&data.auth) {
+ Ok(claims) => claims.claims,
- return Err(APIError::err(&self.op, "site_ban").into());
++ Err(_e) => return Err(APIError::err("not_logged_in").into()),
+ };
+
+ let user_id = claims.id;
+
+ let hostname = &format!("https://{}", Settings::get().hostname);
+
+ // Check for a site ban
+ if UserView::read(&conn, user_id)?.banned {
- return Err(APIError::err(&self.op, "couldnt_create_private_message").into());
++ return Err(APIError::err("site_ban").into());
+ }
+
+ let content_slurs_removed = remove_slurs(&data.content.to_owned());
+
+ let private_message_form = PrivateMessageForm {
+ content: Some(content_slurs_removed.to_owned()),
+ creator_id: user_id,
+ recipient_id: data.recipient_id,
+ deleted: None,
+ read: None,
+ updated: None,
+ };
+
+ let inserted_private_message = match PrivateMessage::create(&conn, &private_message_form) {
+ Ok(private_message) => private_message,
+ Err(_e) => {
- let private_message_view = PrivateMessageView::read(&conn, inserted_private_message.id)?;
++ return Err(APIError::err("couldnt_create_private_message").into());
+ }
+ };
+
+ // Send notifications to the recipient
+ let recipient_user = User_::read(&conn, data.recipient_id)?;
+ if recipient_user.send_notifications_to_email {
+ if let Some(email) = recipient_user.email {
+ let subject = &format!(
+ "{} - Private Message from {}",
+ Settings::get().hostname,
+ claims.username
+ );
+ let html = &format!(
+ "<h1>Private Message</h1><br><div>{} - {}</div><br><a href={}/inbox>inbox</a>",
+ claims.username, &content_slurs_removed, hostname
+ );
+ match send_email(subject, &email, &recipient_user.name, html) {
+ Ok(_o) => _o,
+ Err(e) => eprintln!("{}", e),
+ };
+ }
+ }
+
- Ok(PrivateMessageResponse {
- op: self.op.to_string(),
- message: private_message_view,
- })
++ let message = PrivateMessageView::read(&conn, inserted_private_message.id)?;
+
- Err(_e) => return Err(APIError::err(&self.op, "not_logged_in").into()),
++ Ok(PrivateMessageResponse { message })
+ }
+}
+
+impl Perform<PrivateMessageResponse> for Oper<EditPrivateMessage> {
+ fn perform(&self, conn: &PgConnection) -> Result<PrivateMessageResponse, Error> {
+ let data: &EditPrivateMessage = &self.data;
+
+ let claims = match Claims::decode(&data.auth) {
+ Ok(claims) => claims.claims,
- return Err(APIError::err(&self.op, "site_ban").into());
++ Err(_e) => return Err(APIError::err("not_logged_in").into()),
+ };
+
+ let user_id = claims.id;
+
+ let orig_private_message = PrivateMessage::read(&conn, data.edit_id)?;
+
+ // Check for a site ban
+ if UserView::read(&conn, user_id)?.banned {
- return Err(APIError::err(&self.op, "no_private_message_edit_allowed").into());
++ return Err(APIError::err("site_ban").into());
+ }
+
+ // Check to make sure they are the creator (or the recipient marking as read
+ if !(data.read.is_some() && orig_private_message.recipient_id.eq(&user_id)
+ || orig_private_message.creator_id.eq(&user_id))
+ {
- Err(_e) => return Err(APIError::err(&self.op, "couldnt_update_private_message").into()),
++ return Err(APIError::err("no_private_message_edit_allowed").into());
+ }
+
+ let content_slurs_removed = match &data.content {
+ Some(content) => Some(remove_slurs(content)),
+ None => None,
+ };
+
+ let private_message_form = PrivateMessageForm {
+ content: content_slurs_removed,
+ creator_id: orig_private_message.creator_id,
+ recipient_id: orig_private_message.recipient_id,
+ deleted: data.deleted.to_owned(),
+ read: data.read.to_owned(),
+ updated: if data.read.is_some() {
+ orig_private_message.updated
+ } else {
+ Some(naive_now())
+ },
+ };
+
+ let _updated_private_message =
+ match PrivateMessage::update(&conn, data.edit_id, &private_message_form) {
+ Ok(private_message) => private_message,
- let private_message_view = PrivateMessageView::read(&conn, data.edit_id)?;
++ Err(_e) => return Err(APIError::err("couldnt_update_private_message").into()),
+ };
+
- Ok(PrivateMessageResponse {
- op: self.op.to_string(),
- message: private_message_view,
- })
++ let message = PrivateMessageView::read(&conn, data.edit_id)?;
+
- Err(_e) => return Err(APIError::err(&self.op, "not_logged_in").into()),
++ Ok(PrivateMessageResponse { message })
+ }
+}
+
+impl Perform<PrivateMessagesResponse> for Oper<GetPrivateMessages> {
+ fn perform(&self, conn: &PgConnection) -> Result<PrivateMessagesResponse, Error> {
+ let data: &GetPrivateMessages = &self.data;
+
+ let claims = match Claims::decode(&data.auth) {
+ Ok(claims) => claims.claims,
- Ok(PrivateMessagesResponse {
- op: self.op.to_string(),
- messages,
- })
++ Err(_e) => return Err(APIError::err("not_logged_in").into()),
+ };
+
+ let user_id = claims.id;
+
+ let messages = PrivateMessageQueryBuilder::create(&conn, user_id)
+ .page(data.page)
+ .limit(data.limit)
+ .unread_only(data.unread_only)
+ .list()?;
+
++ Ok(PrivateMessagesResponse { messages })
+ }
+}
pub mod server;
+
+ #[derive(EnumString, ToString, Debug)]
+ pub enum UserOperation {
+ Login,
+ Register,
+ CreateCommunity,
+ CreatePost,
+ ListCommunities,
+ ListCategories,
+ GetPost,
+ GetCommunity,
+ CreateComment,
+ EditComment,
+ SaveComment,
+ CreateCommentLike,
+ GetPosts,
+ CreatePostLike,
+ EditPost,
+ SavePost,
+ EditCommunity,
+ FollowCommunity,
+ GetFollowedCommunities,
+ GetUserDetails,
+ GetReplies,
+ GetUserMentions,
+ EditUserMention,
+ GetModlog,
+ BanFromCommunity,
+ AddModToCommunity,
+ CreateSite,
+ EditSite,
+ GetSite,
+ AddAdmin,
+ BanUser,
+ Search,
+ MarkAllAsRead,
+ SaveUserSettings,
+ TransferCommunity,
+ TransferSite,
+ DeleteAccount,
+ PasswordReset,
+ PasswordChange,
++ CreatePrivateMessage,
++ EditPrivateMessage,
++ GetPrivateMessages,
+ }
UserOperation::GetSite => {
let online: usize = chat.sessions.len();
let get_site: GetSite = serde_json::from_str(data)?;
- let mut res = Oper::new(user_operation, get_site).perform(&conn)?;
+ let mut res = Oper::new(get_site).perform(&conn)?;
res.online = online;
- Ok(serde_json::to_string(&res)?)
+ to_json_string(&user_operation, &res)
}
UserOperation::Search => {
- let search: Search = serde_json::from_str(data)?;
- let res = Oper::new(user_operation, search).perform(&conn)?;
- Ok(serde_json::to_string(&res)?)
+ do_user_operation::<Search, SearchResponse>(user_operation, data, &conn)
}
UserOperation::TransferCommunity => {
- let transfer_community: TransferCommunity = serde_json::from_str(data)?;
- let res = Oper::new(user_operation, transfer_community).perform(&conn)?;
- Ok(serde_json::to_string(&res)?)
+ do_user_operation::<TransferCommunity, GetCommunityResponse>(user_operation, data, &conn)
}
UserOperation::TransferSite => {
- let transfer_site: TransferSite = serde_json::from_str(data)?;
- let res = Oper::new(user_operation, transfer_site).perform(&conn)?;
- Ok(serde_json::to_string(&res)?)
+ do_user_operation::<TransferSite, GetSiteResponse>(user_operation, data, &conn)
}
UserOperation::DeleteAccount => {
- let delete_account: DeleteAccount = serde_json::from_str(data)?;
- let res = Oper::new(user_operation, delete_account).perform(&conn)?;
- Ok(serde_json::to_string(&res)?)
+ do_user_operation::<DeleteAccount, LoginResponse>(user_operation, data, &conn)
}
UserOperation::PasswordReset => {
- let password_reset: PasswordReset = serde_json::from_str(data)?;
- let res = Oper::new(user_operation, password_reset).perform(&conn)?;
- Ok(serde_json::to_string(&res)?)
+ do_user_operation::<PasswordReset, PasswordResetResponse>(user_operation, data, &conn)
}
UserOperation::PasswordChange => {
- let password_change: PasswordChange = serde_json::from_str(data)?;
- let res = Oper::new(user_operation, password_change).perform(&conn)?;
- Ok(serde_json::to_string(&res)?)
+ do_user_operation::<PasswordChange, LoginResponse>(user_operation, data, &conn)
}
- let create_private_message: CreatePrivateMessage = serde_json::from_str(data)?;
- let res = Oper::new(user_operation, create_private_message).perform(&conn)?;
- Ok(serde_json::to_string(&res)?)
+ UserOperation::CreatePrivateMessage => {
+ chat.check_rate_limit_message(msg.id)?;
- let edit_private_message: EditPrivateMessage = serde_json::from_str(data)?;
- let res = Oper::new(user_operation, edit_private_message).perform(&conn)?;
- Ok(serde_json::to_string(&res)?)
++ do_user_operation::<CreatePrivateMessage, PrivateMessageResponse>(user_operation, data, &conn)
+ }
+ UserOperation::EditPrivateMessage => {
- let messages: GetPrivateMessages = serde_json::from_str(data)?;
- let res = Oper::new(user_operation, messages).perform(&conn)?;
- Ok(serde_json::to_string(&res)?)
++ do_user_operation::<EditPrivateMessage, PrivateMessageResponse>(user_operation, data, &conn)
+ }
+ UserOperation::GetPrivateMessages => {
++ do_user_operation::<GetPrivateMessages, PrivateMessagesResponse>(user_operation, data, &conn)
+ }
}
}
FollowCommunityForm,
ListCommunitiesForm,
SortType,
+ WebSocketJsonResponse,
} from '../interfaces';
import { WebSocketService } from '../services';
- import { msgOp, toast } from '../utils';
-import { wsJsonToRes } from '../utils';
++import { wsJsonToRes, toast } from '../utils';
import { i18n } from '../i18next';
import { T } from 'inferno-i18next';
WebSocketService.Instance.listCommunities(listCommunitiesForm);
}
- parseMessage(msg: any) {
+ parseMessage(msg: WebSocketJsonResponse) {
console.log(msg);
- let op: UserOperation = msgOp(msg);
- if (msg.error) {
+ let res = wsJsonToRes(msg);
+ if (res.error) {
- alert(i18n.t(res.error));
+ toast(i18n.t(msg.error), 'danger');
return;
- } else if (op == UserOperation.ListCommunities) {
- let res: ListCommunitiesResponse = msg;
- this.state.communities = res.communities;
+ } else if (res.op == UserOperation.ListCommunities) {
+ let data = res.data as ListCommunitiesResponse;
+ this.state.communities = data.communities;
this.state.communities.sort(
(a, b) => b.number_of_subscribers - a.number_of_subscribers
);
ListCategoriesResponse,
CommunityResponse,
GetSiteResponse,
++ WebSocketJsonResponse,
} from '../interfaces';
import { WebSocketService } from '../services';
- import { msgOp, capitalizeFirstLetter, toast } from '../utils';
-import { wsJsonToRes, capitalizeFirstLetter } from '../utils';
++import { wsJsonToRes, capitalizeFirstLetter, toast } from '../utils';
import autosize from 'autosize';
import { i18n } from '../i18next';
import { T } from 'inferno-i18next';
i.props.onCancel();
}
- parseMessage(msg: any) {
- let op: UserOperation = msgOp(msg);
+ parseMessage(msg: WebSocketJsonResponse) {
+ let res = wsJsonToRes(msg);
console.log(msg);
- if (msg.error) {
+ if (res.error) {
- alert(i18n.t(res.error));
+ toast(i18n.t(msg.error), 'danger');
this.state.loading = false;
this.setState(this.state);
return;
WebSocketService.Instance.getPosts(getPostsForm);
}
- parseMessage(msg: any) {
+ parseMessage(msg: WebSocketJsonResponse) {
console.log(msg);
- let op: UserOperation = msgOp(msg);
- if (msg.error) {
+ let res = wsJsonToRes(msg);
+ if (res.error) {
- alert(i18n.t(res.error));
+ toast(i18n.t(msg.error), 'danger');
this.context.router.history.push('/');
return;
- } else if (op == UserOperation.GetCommunity) {
- let res: GetCommunityResponse = msg;
- this.state.community = res.community;
- this.state.moderators = res.moderators;
- this.state.admins = res.admins;
+ } else if (res.op == UserOperation.GetCommunity) {
+ let data = res.data as GetCommunityResponse;
+ this.state.community = data.community;
+ this.state.moderators = data.moderators;
+ this.state.admins = data.admins;
document.title = `/c/${this.state.community.name} - ${WebSocketService.Instance.site.name}`;
this.setState(this.state);
this.keepFetchingPosts();
- } else if (op == UserOperation.EditCommunity) {
- let res: CommunityResponse = msg;
- this.state.community = res.community;
+ } else if (res.op == UserOperation.EditCommunity) {
+ let data = res.data as CommunityResponse;
+ this.state.community = data.community;
this.setState(this.state);
- } else if (op == UserOperation.FollowCommunity) {
- let res: CommunityResponse = msg;
- this.state.community.subscribed = res.community.subscribed;
+ } else if (res.op == UserOperation.FollowCommunity) {
+ let data = res.data as CommunityResponse;
+ this.state.community.subscribed = data.community.subscribed;
this.state.community.number_of_subscribers =
- res.community.number_of_subscribers;
+ data.community.number_of_subscribers;
this.setState(this.state);
- } else if (op == UserOperation.GetPosts) {
- let res: GetPostsResponse = msg;
- this.state.posts = res.posts;
+ } else if (res.op == UserOperation.GetPosts) {
+ let data = res.data as GetPostsResponse;
-
- // TODO rework this
- // This is needed to refresh the view
- this.state.posts = undefined;
- this.setState(this.state);
-
+ this.state.posts = data.posts;
this.state.loading = false;
this.setState(this.state);
- } else if (op == UserOperation.CreatePostLike) {
- let res: CreatePostLikeResponse = msg;
- let found = this.state.posts.find(c => c.id == res.post.id);
- found.my_vote = res.post.my_vote;
- found.score = res.post.score;
- found.upvotes = res.post.upvotes;
- found.downvotes = res.post.downvotes;
+ } else if (res.op == UserOperation.CreatePostLike) {
+ let data = res.data as CreatePostLikeResponse;
+ let found = this.state.posts.find(c => c.id == data.post.id);
+ found.my_vote = data.post.my_vote;
+ found.score = data.post.score;
+ found.upvotes = data.post.upvotes;
+ found.downvotes = data.post.downvotes;
this.setState(this.state);
}
}
GetUserMentionsResponse,
UserMentionResponse,
CommentResponse,
+ WebSocketJsonResponse,
+ PrivateMessage as PrivateMessageI,
+ GetPrivateMessagesForm,
+ PrivateMessagesResponse,
+ PrivateMessageResponse,
} from '../interfaces';
import { WebSocketService, UserService } from '../services';
- import { msgOp, fetchLimit, isCommentType, toast } from '../utils';
-import { wsJsonToRes, fetchLimit } from '../utils';
++import { wsJsonToRes, fetchLimit, isCommentType, toast } from '../utils';
import { CommentNodes } from './comment-nodes';
+import { PrivateMessage } from './private-message';
import { SortSelect } from './sort-select';
import { i18n } from '../i18next';
import { T } from 'inferno-i18next';
WebSocketService.Instance.markAllAsRead();
}
- parseMessage(msg: any) {
+ parseMessage(msg: WebSocketJsonResponse) {
console.log(msg);
- let op: UserOperation = msgOp(msg);
- if (msg.error) {
+ let res = wsJsonToRes(msg);
+ if (res.error) {
- alert(i18n.t(res.error));
+ toast(i18n.t(msg.error), 'danger');
return;
- } else if (op == UserOperation.GetReplies) {
- let res: GetRepliesResponse = msg;
- this.state.replies = res.replies;
+ } else if (res.op == UserOperation.GetReplies) {
+ let data = res.data as GetRepliesResponse;
+ this.state.replies = data.replies;
this.sendUnreadCount();
window.scrollTo(0, 0);
this.setState(this.state);
this.sendUnreadCount();
window.scrollTo(0, 0);
this.setState(this.state);
- } else if (op == UserOperation.GetPrivateMessages) {
- let res: PrivateMessagesResponse = msg;
- this.state.messages = res.messages;
++ } else if (res.op == UserOperation.GetPrivateMessages) {
++ let data = res.data as PrivateMessagesResponse;
++ this.state.messages = data.messages;
+ this.sendUnreadCount();
+ window.scrollTo(0, 0);
+ this.setState(this.state);
- } else if (op == UserOperation.EditPrivateMessage) {
- let res: PrivateMessageResponse = msg;
++ } else if (res.op == UserOperation.EditPrivateMessage) {
++ let data = res.data as PrivateMessageResponse;
+ let found: PrivateMessageI = this.state.messages.find(
- m => m.id === res.message.id
++ m => m.id === data.message.id
+ );
- found.content = res.message.content;
- found.updated = res.message.updated;
- found.deleted = res.message.deleted;
++ found.content = data.message.content;
++ found.updated = data.message.updated;
++ found.deleted = data.message.deleted;
+ // If youre in the unread view, just remove it from the list
- if (this.state.unreadOrAll == UnreadOrAll.Unread && res.message.read) {
++ if (this.state.unreadOrAll == UnreadOrAll.Unread && data.message.read) {
+ this.state.messages = this.state.messages.filter(
- r => r.id !== res.message.id
++ r => r.id !== data.message.id
+ );
+ } else {
- let found = this.state.messages.find(c => c.id == res.message.id);
- found.read = res.message.read;
++ let found = this.state.messages.find(c => c.id == data.message.id);
++ found.read = data.message.read;
+ }
+ this.sendUnreadCount();
+ window.scrollTo(0, 0);
+ this.setState(this.state);
- } else if (op == UserOperation.MarkAllAsRead) {
+ } else if (res.op == UserOperation.MarkAllAsRead) {
this.state.replies = [];
this.state.mentions = [];
+ this.state.messages = [];
+ this.sendUnreadCount();
window.scrollTo(0, 0);
this.setState(this.state);
- } else if (op == UserOperation.EditComment) {
- let res: CommentResponse = msg;
-
- let found = this.state.replies.find(c => c.id == res.comment.id);
- found.content = res.comment.content;
- found.updated = res.comment.updated;
- found.removed = res.comment.removed;
- found.deleted = res.comment.deleted;
- found.upvotes = res.comment.upvotes;
- found.downvotes = res.comment.downvotes;
- found.score = res.comment.score;
+ } else if (res.op == UserOperation.EditComment) {
+ let data = res.data as CommentResponse;
+
+ let found = this.state.replies.find(c => c.id == data.comment.id);
+ found.content = data.comment.content;
+ found.updated = data.comment.updated;
+ found.removed = data.comment.removed;
+ found.deleted = data.comment.deleted;
+ found.upvotes = data.comment.upvotes;
+ found.downvotes = data.comment.downvotes;
+ found.score = data.comment.score;
// If youre in the unread view, just remove it from the list
- if (this.state.unreadOrAll == UnreadOrAll.Unread && res.comment.read) {
+ if (this.state.unreadOrAll == UnreadOrAll.Unread && data.comment.read) {
this.state.replies = this.state.replies.filter(
- r => r.id !== res.comment.id
+ r => r.id !== data.comment.id
);
} else {
- let found = this.state.replies.find(c => c.id == res.comment.id);
- found.read = res.comment.read;
+ let found = this.state.replies.find(c => c.id == data.comment.id);
+ found.read = data.comment.read;
}
this.sendUnreadCount();
this.setState(this.state);
}
this.sendUnreadCount();
this.setState(this.state);
- } else if (op == UserOperation.CreateComment) {
+ } else if (res.op == UserOperation.CreateComment) {
// let res: CommentResponse = msg;
- alert(i18n.t('reply_sent'));
+ toast(i18n.t('reply_sent'));
// this.state.replies.unshift(res.comment); // TODO do this right
// this.setState(this.state);
- } else if (op == UserOperation.SaveComment) {
- let res: CommentResponse = msg;
- let found = this.state.replies.find(c => c.id == res.comment.id);
- found.saved = res.comment.saved;
+ } else if (res.op == UserOperation.SaveComment) {
+ let data = res.data as CommentResponse;
+ let found = this.state.replies.find(c => c.id == data.comment.id);
+ found.saved = data.comment.saved;
this.setState(this.state);
- } else if (op == UserOperation.CreateCommentLike) {
- let res: CommentResponse = msg;
+ } else if (res.op == UserOperation.CreateCommentLike) {
+ let data = res.data as CommentResponse;
let found: Comment = this.state.replies.find(
- c => c.id === res.comment.id
+ c => c.id === data.comment.id
);
- found.score = res.comment.score;
- found.upvotes = res.comment.upvotes;
- found.downvotes = res.comment.downvotes;
- if (res.comment.my_vote !== null) found.my_vote = res.comment.my_vote;
+ found.score = data.comment.score;
+ found.upvotes = data.comment.upvotes;
+ found.downvotes = data.comment.downvotes;
+ if (data.comment.my_vote !== null) found.my_vote = data.comment.my_vote;
this.setState(this.state);
}
}
UserOperation,
PasswordResetForm,
GetSiteResponse,
+ WebSocketJsonResponse,
} from '../interfaces';
import { WebSocketService, UserService } from '../services';
- import { msgOp, validEmail, toast } from '../utils';
-import { wsJsonToRes, validEmail } from '../utils';
++import { wsJsonToRes, validEmail, toast } from '../utils';
import { i18n } from '../i18next';
import { T } from 'inferno-i18next';
WebSocketService.Instance.passwordReset(resetForm);
}
- parseMessage(msg: any) {
- let op: UserOperation = msgOp(msg);
- if (msg.error) {
+ parseMessage(msg: WebSocketJsonResponse) {
+ let res = wsJsonToRes(msg);
+ if (res.error) {
- alert(i18n.t(res.error));
+ toast(i18n.t(msg.error), 'danger');
this.state = this.emptyState;
this.setState(this.state);
return;
} else {
- if (op == UserOperation.Login) {
+ if (res.op == UserOperation.Login) {
+ let data = res.data as LoginResponse;
this.state = this.emptyState;
this.setState(this.state);
- let res: LoginResponse = msg;
- UserService.Instance.login(res);
+ UserService.Instance.login(data);
+ toast(i18n.t('logged_in'));
this.props.history.push('/');
- } else if (op == UserOperation.Register) {
+ } else if (res.op == UserOperation.Register) {
+ let data = res.data as LoginResponse;
this.state = this.emptyState;
this.setState(this.state);
- let res: LoginResponse = msg;
- UserService.Instance.login(res);
+ UserService.Instance.login(data);
this.props.history.push('/communities');
- } else if (op == UserOperation.PasswordReset) {
+ } else if (res.op == UserOperation.PasswordReset) {
- alert(i18n.t('reset_password_mail_sent'));
+ toast(i18n.t('reset_password_mail_sent'));
- } else if (op == UserOperation.GetSite) {
- let res: GetSiteResponse = msg;
- this.state.enable_nsfw = res.site.enable_nsfw;
+ } else if (res.op == UserOperation.GetSite) {
+ let data = res.data as GetSiteResponse;
+ this.state.enable_nsfw = data.site.enable_nsfw;
this.setState(this.state);
document.title = `${i18n.t('login')} - ${
WebSocketService.Instance.site.name
WebSocketService.Instance.getPosts(getPostsForm);
}
- parseMessage(msg: any) {
+ parseMessage(msg: WebSocketJsonResponse) {
console.log(msg);
- let op: UserOperation = msgOp(msg);
- if (msg.error) {
+ let res = wsJsonToRes(msg);
+ if (res.error) {
- alert(i18n.t(res.error));
+ toast(i18n.t(msg.error), 'danger');
return;
- } else if (op == UserOperation.GetFollowedCommunities) {
- let res: GetFollowedCommunitiesResponse = msg;
- this.state.subscribedCommunities = res.communities;
+ } else if (res.op == UserOperation.GetFollowedCommunities) {
+ let data = res.data as GetFollowedCommunitiesResponse;
+ this.state.subscribedCommunities = data.communities;
this.setState(this.state);
- } else if (op == UserOperation.ListCommunities) {
- let res: ListCommunitiesResponse = msg;
- this.state.trendingCommunities = res.communities;
+ } else if (res.op == UserOperation.ListCommunities) {
+ let data = res.data as ListCommunitiesResponse;
+ this.state.trendingCommunities = data.communities;
this.setState(this.state);
- } else if (op == UserOperation.GetSite) {
- let res: GetSiteResponse = msg;
+ } else if (res.op == UserOperation.GetSite) {
+ let data = res.data as GetSiteResponse;
// This means it hasn't been set up yet
- if (!res.site) {
+ if (!data.site) {
this.context.router.history.push('/setup');
}
- this.state.site.admins = res.admins;
- this.state.site.site = res.site;
- this.state.site.banned = res.banned;
- this.state.site.online = res.online;
+ this.state.site.admins = data.admins;
+ this.state.site.site = data.site;
+ this.state.site.banned = data.banned;
+ this.state.site.online = data.online;
this.setState(this.state);
document.title = `${WebSocketService.Instance.site.name}`;
- } else if (op == UserOperation.EditSite) {
- let res: SiteResponse = msg;
- this.state.site.site = res.site;
+ } else if (res.op == UserOperation.EditSite) {
+ let data = res.data as SiteResponse;
+ this.state.site.site = data.site;
this.state.showEditSite = false;
this.setState(this.state);
- } else if (op == UserOperation.GetPosts) {
- let res: GetPostsResponse = msg;
- this.state.posts = res.posts;
+ } else if (res.op == UserOperation.GetPosts) {
+ let data = res.data as GetPostsResponse;
-
- // This is needed to refresh the view
- // TODO mess with this
- this.state.posts = undefined;
- this.setState(this.state);
-
+ this.state.posts = data.posts;
this.state.loading = false;
this.setState(this.state);
- } else if (op == UserOperation.CreatePostLike) {
- let res: CreatePostLikeResponse = msg;
- let found = this.state.posts.find(c => c.id == res.post.id);
- found.my_vote = res.post.my_vote;
- found.score = res.post.score;
- found.upvotes = res.post.upvotes;
- found.downvotes = res.post.downvotes;
+ } else if (res.op == UserOperation.CreatePostLike) {
+ let data = res.data as CreatePostLikeResponse;
+ let found = this.state.posts.find(c => c.id == data.post.id);
+ found.my_vote = data.post.my_vote;
+ found.score = data.post.score;
+ found.upvotes = data.post.upvotes;
+ found.downvotes = data.post.downvotes;
this.setState(this.state);
}
}
ModAdd,
} from '../interfaces';
import { WebSocketService } from '../services';
- import { msgOp, addTypeInfo, fetchLimit, toast } from '../utils';
-import { wsJsonToRes, addTypeInfo, fetchLimit } from '../utils';
++import { wsJsonToRes, addTypeInfo, fetchLimit, toast } from '../utils';
import { MomentTime } from './moment-time';
import moment from 'moment';
import { i18n } from '../i18next';
WebSocketService.Instance.getModlog(modlogForm);
}
- parseMessage(msg: any) {
+ parseMessage(msg: WebSocketJsonResponse) {
console.log(msg);
- let op: UserOperation = msgOp(msg);
- if (msg.error) {
+ let res = wsJsonToRes(msg);
+ if (res.error) {
- alert(i18n.t(res.error));
+ toast(i18n.t(msg.error), 'danger');
return;
- } else if (op == UserOperation.GetModlog) {
- let res: GetModlogResponse = msg;
+ } else if (res.op == UserOperation.GetModlog) {
+ let data = res.data as GetModlogResponse;
this.state.loading = false;
window.scrollTo(0, 0);
- this.setCombined(res);
+ this.setCombined(data);
}
}
}
SortType,
GetSiteResponse,
Comment,
+ PrivateMessage,
+ WebSocketJsonResponse,
} from '../interfaces';
import {
- msgOp,
+ wsJsonToRes,
pictshareAvatarThumbnail,
showAvatars,
fetchLimit,
this.state.mentions = unreadMentions;
this.setState(this.state);
this.sendUnreadCount();
- } else if (op == UserOperation.GetPrivateMessages) {
- let res: PrivateMessagesResponse = msg;
- let unreadMessages = res.messages.filter(r => !r.read);
++ } else if (res.op == UserOperation.GetPrivateMessages) {
++ let data = res.data as PrivateMessagesResponse;
++ let unreadMessages = data.messages.filter(r => !r.read);
+ if (
+ unreadMessages.length > 0 &&
+ this.state.fetchCount > 1 &&
+ JSON.stringify(this.state.messages) !== JSON.stringify(unreadMessages)
+ ) {
+ this.notify(unreadMessages);
+ }
+
+ this.state.messages = unreadMessages;
+ this.setState(this.state);
+ this.sendUnreadCount();
- } else if (op == UserOperation.GetSite) {
- let res: GetSiteResponse = msg;
+ } else if (res.op == UserOperation.GetSite) {
+ let data = res.data as GetSiteResponse;
- if (res.site) {
- this.state.siteName = res.site.name;
- WebSocketService.Instance.site = res.site;
+ if (data.site) {
+ this.state.siteName = data.site.name;
+ WebSocketService.Instance.site = data.site;
this.setState(this.state);
}
}
UserOperation,
LoginResponse,
PasswordChangeForm,
+ WebSocketJsonResponse,
} from '../interfaces';
import { WebSocketService, UserService } from '../services';
- import { msgOp, capitalizeFirstLetter, toast } from '../utils';
-import { wsJsonToRes, capitalizeFirstLetter } from '../utils';
++import { wsJsonToRes, capitalizeFirstLetter, toast } from '../utils';
import { i18n } from '../i18next';
import { T } from 'inferno-i18next';
WebSocketService.Instance.passwordChange(i.state.passwordChangeForm);
}
- parseMessage(msg: any) {
- let op: UserOperation = msgOp(msg);
+ parseMessage(msg: WebSocketJsonResponse) {
+ let res = wsJsonToRes(msg);
if (msg.error) {
- alert(i18n.t(msg.error));
+ toast(i18n.t(msg.error), 'danger');
this.state.loading = false;
this.setState(this.state);
return;
});
}
- parseMessage(msg: any) {
- let op: UserOperation = msgOp(msg);
- if (msg.error) {
+ parseMessage(msg: WebSocketJsonResponse) {
+ let res = wsJsonToRes(msg);
+ if (res.error) {
- alert(i18n.t(res.error));
+ toast(i18n.t(msg.error), 'danger');
this.state.loading = false;
this.setState(this.state);
return;
SearchResponse,
GetSiteResponse,
GetCommunityResponse,
+ WebSocketJsonResponse,
} from '../interfaces';
import { WebSocketService, UserService } from '../services';
- import { msgOp, hotRank, toast } from '../utils';
-import { wsJsonToRes, hotRank } from '../utils';
++import { wsJsonToRes, hotRank, toast } from '../utils';
import { PostListing } from './post-listing';
import { PostListings } from './post-listings';
import { Sidebar } from './sidebar';
);
}
- parseMessage(msg: any) {
+ parseMessage(msg: WebSocketJsonResponse) {
console.log(msg);
- let op: UserOperation = msgOp(msg);
- if (msg.error) {
+ let res = wsJsonToRes(msg);
+ if (res.error) {
- alert(i18n.t(res.error));
+ toast(i18n.t(msg.error), 'danger');
return;
- } else if (op == UserOperation.GetPost) {
- let res: GetPostResponse = msg;
- this.state.post = res.post;
- this.state.comments = res.comments;
- this.state.community = res.community;
- this.state.moderators = res.moderators;
- this.state.admins = res.admins;
+ } else if (res.op == UserOperation.GetPost) {
+ let data = res.data as GetPostResponse;
+ this.state.post = data.post;
+ this.state.comments = data.comments;
+ this.state.community = data.community;
+ this.state.moderators = data.moderators;
+ this.state.admins = data.admins;
this.state.loading = false;
document.title = `${this.state.post.name} - ${WebSocketService.Instance.site.name}`;
}
this.setState(this.state);
- } else if (op == UserOperation.CreateComment) {
- let res: CommentResponse = msg;
- this.state.comments.unshift(res.comment);
+ } else if (res.op == UserOperation.CreateComment) {
+ let data = res.data as CommentResponse;
+ this.state.comments.unshift(data.comment);
this.setState(this.state);
- } else if (op == UserOperation.EditComment) {
- let res: CommentResponse = msg;
- let found = this.state.comments.find(c => c.id == res.comment.id);
- found.content = res.comment.content;
- found.updated = res.comment.updated;
- found.removed = res.comment.removed;
- found.deleted = res.comment.deleted;
- found.upvotes = res.comment.upvotes;
- found.downvotes = res.comment.downvotes;
- found.score = res.comment.score;
- found.read = res.comment.read;
+ } else if (res.op == UserOperation.EditComment) {
+ let data = res.data as CommentResponse;
+ let found = this.state.comments.find(c => c.id == data.comment.id);
+ found.content = data.comment.content;
+ found.updated = data.comment.updated;
+ found.removed = data.comment.removed;
+ found.deleted = data.comment.deleted;
+ found.upvotes = data.comment.upvotes;
+ found.downvotes = data.comment.downvotes;
+ found.score = data.comment.score;
+ found.read = data.comment.read;
this.setState(this.state);
- } else if (op == UserOperation.SaveComment) {
- let res: CommentResponse = msg;
- let found = this.state.comments.find(c => c.id == res.comment.id);
- found.saved = res.comment.saved;
+ } else if (res.op == UserOperation.SaveComment) {
+ let data = res.data as CommentResponse;
+ let found = this.state.comments.find(c => c.id == data.comment.id);
+ found.saved = data.comment.saved;
this.setState(this.state);
- } else if (op == UserOperation.CreateCommentLike) {
- let res: CommentResponse = msg;
+ } else if (res.op == UserOperation.CreateCommentLike) {
+ let data = res.data as CommentResponse;
let found: Comment = this.state.comments.find(
- c => c.id === res.comment.id
+ c => c.id === data.comment.id
);
- found.score = res.comment.score;
- found.upvotes = res.comment.upvotes;
- found.downvotes = res.comment.downvotes;
- if (res.comment.my_vote !== null) {
- found.my_vote = res.comment.my_vote;
+ found.score = data.comment.score;
+ found.upvotes = data.comment.upvotes;
+ found.downvotes = data.comment.downvotes;
- if (data.comment.my_vote !== null) found.my_vote = data.comment.my_vote;
++ if (data.comment.my_vote !== null) {
++ found.my_vote = data.comment.my_vote;
+ found.upvoteLoading = false;
+ found.downvoteLoading = false;
+ }
this.setState(this.state);
- } else if (op == UserOperation.CreatePostLike) {
- let res: CreatePostLikeResponse = msg;
- this.state.post.my_vote = res.post.my_vote;
- this.state.post.score = res.post.score;
- this.state.post.upvotes = res.post.upvotes;
- this.state.post.downvotes = res.post.downvotes;
- this.state.post.upvoteLoading = false;
- this.state.post.downvoteLoading = false;
+ } else if (res.op == UserOperation.CreatePostLike) {
+ let data = res.data as CreatePostLikeResponse;
+ this.state.post.my_vote = data.post.my_vote;
+ this.state.post.score = data.post.score;
+ this.state.post.upvotes = data.post.upvotes;
+ this.state.post.downvotes = data.post.downvotes;
this.setState(this.state);
- } else if (op == UserOperation.EditPost) {
- let res: PostResponse = msg;
- this.state.post = res.post;
+ } else if (res.op == UserOperation.EditPost) {
+ let data = res.data as PostResponse;
+ this.state.post = data.post;
this.setState(this.state);
- } else if (op == UserOperation.SavePost) {
- let res: PostResponse = msg;
- this.state.post = res.post;
+ } else if (res.op == UserOperation.SavePost) {
+ let data = res.data as PostResponse;
+ this.state.post = data.post;
this.setState(this.state);
- } else if (op == UserOperation.EditCommunity) {
- let res: CommunityResponse = msg;
- this.state.community = res.community;
- this.state.post.community_id = res.community.id;
- this.state.post.community_name = res.community.name;
+ } else if (res.op == UserOperation.EditCommunity) {
+ let data = res.data as CommunityResponse;
+ this.state.community = data.community;
+ this.state.post.community_id = data.community.id;
+ this.state.post.community_name = data.community.name;
this.setState(this.state);
- } else if (op == UserOperation.FollowCommunity) {
- let res: CommunityResponse = msg;
- this.state.community.subscribed = res.community.subscribed;
+ } else if (res.op == UserOperation.FollowCommunity) {
+ let data = res.data as CommunityResponse;
+ this.state.community.subscribed = data.community.subscribed;
this.state.community.number_of_subscribers =
- res.community.number_of_subscribers;
+ data.community.number_of_subscribers;
this.setState(this.state);
- } else if (op == UserOperation.BanFromCommunity) {
- let res: BanFromCommunityResponse = msg;
+ } else if (res.op == UserOperation.BanFromCommunity) {
+ let data = res.data as BanFromCommunityResponse;
this.state.comments
- .filter(c => c.creator_id == res.user.id)
- .forEach(c => (c.banned_from_community = res.banned));
- if (this.state.post.creator_id == res.user.id) {
- this.state.post.banned_from_community = res.banned;
+ .filter(c => c.creator_id == data.user.id)
+ .forEach(c => (c.banned_from_community = data.banned));
+ if (this.state.post.creator_id == data.user.id) {
+ this.state.post.banned_from_community = data.banned;
}
this.setState(this.state);
- } else if (op == UserOperation.AddModToCommunity) {
- let res: AddModToCommunityResponse = msg;
- this.state.moderators = res.moderators;
+ } else if (res.op == UserOperation.AddModToCommunity) {
+ let data = res.data as AddModToCommunityResponse;
+ this.state.moderators = data.moderators;
this.setState(this.state);
- } else if (op == UserOperation.BanUser) {
- let res: BanUserResponse = msg;
+ } else if (res.op == UserOperation.BanUser) {
+ let data = res.data as BanUserResponse;
this.state.comments
- .filter(c => c.creator_id == res.user.id)
- .forEach(c => (c.banned = res.banned));
- if (this.state.post.creator_id == res.user.id) {
- this.state.post.banned = res.banned;
+ .filter(c => c.creator_id == data.user.id)
+ .forEach(c => (c.banned = data.banned));
+ if (this.state.post.creator_id == data.user.id) {
+ this.state.post.banned = data.banned;
}
this.setState(this.state);
- } else if (op == UserOperation.AddAdmin) {
- let res: AddAdminResponse = msg;
- this.state.admins = res.admins;
+ } else if (res.op == UserOperation.AddAdmin) {
+ let data = res.data as AddAdminResponse;
+ this.state.admins = data.admins;
this.setState(this.state);
- } else if (op == UserOperation.Search) {
- let res: SearchResponse = msg;
- this.state.crossPosts = res.posts.filter(p => p.id != this.state.post.id);
+ } else if (res.op == UserOperation.Search) {
+ let data = res.data as SearchResponse;
+ this.state.crossPosts = data.posts.filter(
+ p => p.id != this.state.post.id
+ );
this.setState(this.state);
- } else if (op == UserOperation.TransferSite) {
- let res: GetSiteResponse = msg;
+ } else if (res.op == UserOperation.TransferSite) {
+ let data = res.data as GetSiteResponse;
- this.state.admins = res.admins;
+ this.state.admins = data.admins;
this.setState(this.state);
- } else if (op == UserOperation.TransferCommunity) {
- let res: GetCommunityResponse = msg;
- this.state.community = res.community;
- this.state.moderators = res.moderators;
- this.state.admins = res.admins;
+ } else if (res.op == UserOperation.TransferCommunity) {
+ let data = res.data as GetCommunityResponse;
+ this.state.community = data.community;
+ this.state.moderators = data.moderators;
+ this.state.admins = data.admins;
this.setState(this.state);
}
}
--- /dev/null
- msgOp,
+import { Component, linkEvent } from 'inferno';
+import { Link } from 'inferno-router';
+import { Subscription } from 'rxjs';
+import { retryWhen, delay, take } from 'rxjs/operators';
+import {
+ PrivateMessageForm as PrivateMessageFormI,
+ EditPrivateMessageForm,
+ PrivateMessageFormParams,
+ PrivateMessage,
+ PrivateMessageResponse,
+ UserView,
+ UserOperation,
+ UserDetailsResponse,
+ GetUserDetailsForm,
+ SortType,
++ WebSocketJsonResponse,
+} from '../interfaces';
+import { WebSocketService } from '../services';
+import {
- parseMessage(msg: any) {
- let op: UserOperation = msgOp(msg);
- if (msg.error) {
+ capitalizeFirstLetter,
+ markdownHelpUrl,
+ mdToHtml,
+ showAvatars,
+ pictshareAvatarThumbnail,
++ wsJsonToRes,
+ toast,
+} from '../utils';
+import autosize from 'autosize';
+import { i18n } from '../i18next';
+import { T } from 'inferno-i18next';
+
+interface PrivateMessageFormProps {
+ privateMessage?: PrivateMessage; // If a pm is given, that means this is an edit
+ params?: PrivateMessageFormParams;
+ onCancel?(): any;
+ onCreate?(message: PrivateMessage): any;
+ onEdit?(message: PrivateMessage): any;
+}
+
+interface PrivateMessageFormState {
+ privateMessageForm: PrivateMessageFormI;
+ recipient: UserView;
+ loading: boolean;
+ previewMode: boolean;
+ showDisclaimer: boolean;
+}
+
+export class PrivateMessageForm extends Component<
+ PrivateMessageFormProps,
+ PrivateMessageFormState
+> {
+ private subscription: Subscription;
+ private emptyState: PrivateMessageFormState = {
+ privateMessageForm: {
+ content: null,
+ recipient_id: null,
+ },
+ recipient: null,
+ loading: false,
+ previewMode: false,
+ showDisclaimer: false,
+ };
+
+ constructor(props: any, context: any) {
+ super(props, context);
+
+ this.state = this.emptyState;
+
+ if (this.props.privateMessage) {
+ this.state.privateMessageForm = {
+ content: this.props.privateMessage.content,
+ recipient_id: this.props.privateMessage.recipient_id,
+ };
+ }
+
+ if (this.props.params) {
+ this.state.privateMessageForm.recipient_id = this.props.params.recipient_id;
+ let form: GetUserDetailsForm = {
+ user_id: this.state.privateMessageForm.recipient_id,
+ sort: SortType[SortType.New],
+ saved_only: false,
+ };
+ WebSocketService.Instance.getUserDetails(form);
+ }
+
+ this.subscription = WebSocketService.Instance.subject
+ .pipe(retryWhen(errors => errors.pipe(delay(3000), take(10))))
+ .subscribe(
+ msg => this.parseMessage(msg),
+ err => console.error(err),
+ () => console.log('complete')
+ );
+ }
+
+ componentDidMount() {
+ autosize(document.querySelectorAll('textarea'));
+ }
+
+ componentWillUnmount() {
+ this.subscription.unsubscribe();
+ }
+
+ render() {
+ return (
+ <div>
+ <form onSubmit={linkEvent(this, this.handlePrivateMessageSubmit)}>
+ {!this.props.privateMessage && (
+ <div class="form-group row">
+ <label class="col-sm-2 col-form-label">
+ {capitalizeFirstLetter(i18n.t('to'))}
+ </label>
+
+ {this.state.recipient && (
+ <div class="col-sm-10 form-control-plaintext">
+ <Link
+ className="text-info"
+ to={`/u/${this.state.recipient.name}`}
+ >
+ {this.state.recipient.avatar && showAvatars() && (
+ <img
+ height="32"
+ width="32"
+ src={pictshareAvatarThumbnail(
+ this.state.recipient.avatar
+ )}
+ class="rounded-circle mr-1"
+ />
+ )}
+ <span>{this.state.recipient.name}</span>
+ </Link>
+ </div>
+ )}
+ </div>
+ )}
+ <div class="form-group row">
+ <label class="col-sm-2 col-form-label">{i18n.t('message')}</label>
+ <div class="col-sm-10">
+ <textarea
+ value={this.state.privateMessageForm.content}
+ onInput={linkEvent(this, this.handleContentChange)}
+ className={`form-control ${this.state.previewMode && 'd-none'}`}
+ rows={4}
+ maxLength={10000}
+ />
+ {this.state.previewMode && (
+ <div
+ className="md-div"
+ dangerouslySetInnerHTML={mdToHtml(
+ this.state.privateMessageForm.content
+ )}
+ />
+ )}
+
+ {this.state.privateMessageForm.content && (
+ <button
+ className={`mt-1 mr-2 btn btn-sm btn-secondary ${this.state
+ .previewMode && 'active'}`}
+ onClick={linkEvent(this, this.handlePreviewToggle)}
+ >
+ {i18n.t('preview')}
+ </button>
+ )}
+ <ul class="float-right list-inline mb-1 text-muted small font-weight-bold">
+ <li class="list-inline-item">
+ <span
+ onClick={linkEvent(this, this.handleShowDisclaimer)}
+ class="pointer"
+ >
+ {i18n.t('disclaimer')}
+ </span>
+ </li>
+ <li class="list-inline-item">
+ <a href={markdownHelpUrl} target="_blank" class="text-muted">
+ {i18n.t('formatting_help')}
+ </a>
+ </li>
+ </ul>
+ </div>
+ </div>
+
+ {this.state.showDisclaimer && (
+ <div class="form-group row">
+ <div class="col-sm-10">
+ <div class="alert alert-danger" role="alert">
+ <T i18nKey="private_message_disclaimer">
+ #
+ <a
+ class="alert-link"
+ target="_blank"
+ href="https://about.riot.im/"
+ >
+ #
+ </a>
+ </T>
+ </div>
+ </div>
+ </div>
+ )}
+ <div class="form-group row">
+ <div class="col-sm-10">
+ <button type="submit" class="btn btn-secondary mr-2">
+ {this.state.loading ? (
+ <svg class="icon icon-spinner spin">
+ <use xlinkHref="#icon-spinner"></use>
+ </svg>
+ ) : this.props.privateMessage ? (
+ capitalizeFirstLetter(i18n.t('save'))
+ ) : (
+ capitalizeFirstLetter(i18n.t('send_message'))
+ )}
+ </button>
+ {this.props.privateMessage && (
+ <button
+ type="button"
+ class="btn btn-secondary"
+ onClick={linkEvent(this, this.handleCancel)}
+ >
+ {i18n.t('cancel')}
+ </button>
+ )}
+ </div>
+ </div>
+ </form>
+ </div>
+ );
+ }
+
+ handlePrivateMessageSubmit(i: PrivateMessageForm, event: any) {
+ event.preventDefault();
+ if (i.props.privateMessage) {
+ let editForm: EditPrivateMessageForm = {
+ edit_id: i.props.privateMessage.id,
+ content: i.state.privateMessageForm.content,
+ };
+ WebSocketService.Instance.editPrivateMessage(editForm);
+ } else {
+ WebSocketService.Instance.createPrivateMessage(
+ i.state.privateMessageForm
+ );
+ }
+ i.state.loading = true;
+ i.setState(i.state);
+ }
+
+ handleRecipientChange(i: PrivateMessageForm, event: any) {
+ i.state.recipient = event.target.value;
+ i.setState(i.state);
+ }
+
+ handleContentChange(i: PrivateMessageForm, event: any) {
+ i.state.privateMessageForm.content = event.target.value;
+ i.setState(i.state);
+ }
+
+ handleCancel(i: PrivateMessageForm) {
+ i.props.onCancel();
+ }
+
+ handlePreviewToggle(i: PrivateMessageForm, event: any) {
+ event.preventDefault();
+ i.state.previewMode = !i.state.previewMode;
+ i.setState(i.state);
+ }
+
+ handleShowDisclaimer(i: PrivateMessageForm) {
+ i.state.showDisclaimer = !i.state.showDisclaimer;
+ i.setState(i.state);
+ }
+
- } else if (op == UserOperation.EditPrivateMessage) {
++ parseMessage(msg: WebSocketJsonResponse) {
++ let res = wsJsonToRes(msg);
++ if (res.error) {
+ toast(i18n.t(msg.error), 'danger');
+ this.state.loading = false;
+ this.setState(this.state);
+ return;
- let res: PrivateMessageResponse = msg;
- this.props.onEdit(res.message);
- } else if (op == UserOperation.GetUserDetails) {
- let res: UserDetailsResponse = msg;
- this.state.recipient = res.user;
- this.state.privateMessageForm.recipient_id = res.user.id;
++ } else if (res.op == UserOperation.EditPrivateMessage) {
++ let data = res.data as PrivateMessageResponse;
+ this.state.loading = false;
- } else if (op == UserOperation.CreatePrivateMessage) {
++ this.props.onEdit(data.message);
++ } else if (res.op == UserOperation.GetUserDetails) {
++ let data = res.data as UserDetailsResponse;
++ this.state.recipient = data.user;
++ this.state.privateMessageForm.recipient_id = data.user.id;
+ this.setState(this.state);
- let res: PrivateMessageResponse = msg;
- this.props.onCreate(res.message);
++ } else if (res.op == UserOperation.CreatePrivateMessage) {
++ let data = res.data as PrivateMessageResponse;
+ this.state.loading = false;
++ this.props.onCreate(data.message);
+ this.setState(this.state);
+ }
+ }
+}
SearchForm,
SearchResponse,
SearchType,
+ CreatePostLikeResponse,
+ CommentResponse,
+ WebSocketJsonResponse,
} from '../interfaces';
import { WebSocketService } from '../services';
import {
);
}
- parseMessage(msg: any) {
+ parseMessage(msg: WebSocketJsonResponse) {
console.log(msg);
- let op: UserOperation = msgOp(msg);
- if (msg.error) {
+ let res = wsJsonToRes(msg);
+ if (res.error) {
- alert(i18n.t(res.error));
+ toast(i18n.t(msg.error), 'danger');
return;
- } else if (op == UserOperation.Search) {
- let res: SearchResponse = msg;
- this.state.searchResponse = res;
+ } else if (res.op == UserOperation.Search) {
+ let data = res.data as SearchResponse;
+ this.state.searchResponse = data;
this.state.loading = false;
document.title = `${i18n.t('search')} - ${this.state.q} - ${
WebSocketService.Instance.site.name
}`;
window.scrollTo(0, 0);
this.setState(this.state);
- } else if (op == UserOperation.CreateCommentLike) {
- let res: CommentResponse = msg;
++ } else if (res.op == UserOperation.CreateCommentLike) {
++ let data = res.data as CommentResponse;
+ let found: Comment = this.state.searchResponse.comments.find(
- c => c.id === res.comment.id
++ c => c.id === data.comment.id
+ );
- found.score = res.comment.score;
- found.upvotes = res.comment.upvotes;
- found.downvotes = res.comment.downvotes;
- if (res.comment.my_vote !== null) {
- found.my_vote = res.comment.my_vote;
++ found.score = data.comment.score;
++ found.upvotes = data.comment.upvotes;
++ found.downvotes = data.comment.downvotes;
++ if (data.comment.my_vote !== null) {
++ found.my_vote = data.comment.my_vote;
+ found.upvoteLoading = false;
+ found.downvoteLoading = false;
+ }
+ this.setState(this.state);
- } else if (op == UserOperation.CreatePostLike) {
- let res: CreatePostLikeResponse = msg;
++ } else if (res.op == UserOperation.CreatePostLike) {
++ let data = res.data as CreatePostLikeResponse;
+ let found = this.state.searchResponse.posts.find(
- c => c.id == res.post.id
++ c => c.id == data.post.id
+ );
- found.my_vote = res.post.my_vote;
- found.score = res.post.score;
- found.upvotes = res.post.upvotes;
- found.downvotes = res.post.downvotes;
++ found.my_vote = data.post.my_vote;
++ found.score = data.post.score;
++ found.upvotes = data.post.upvotes;
++ found.downvotes = data.post.downvotes;
+ this.setState(this.state);
}
}
}
import { Component, linkEvent } from 'inferno';
import { Subscription } from 'rxjs';
import { retryWhen, delay, take } from 'rxjs/operators';
- import { RegisterForm, LoginResponse, UserOperation } from '../interfaces';
+ import {
+ RegisterForm,
+ LoginResponse,
+ UserOperation,
+ WebSocketJsonResponse,
+ } from '../interfaces';
import { WebSocketService, UserService } from '../services';
- import { msgOp, toast } from '../utils';
-import { wsJsonToRes } from '../utils';
++import { wsJsonToRes, toast } from '../utils';
import { SiteForm } from './site-form';
import { i18n } from '../i18next';
import { T } from 'inferno-i18next';
i.setState(i.state);
}
- parseMessage(msg: any) {
- let op: UserOperation = msgOp(msg);
- if (msg.error) {
+ parseMessage(msg: WebSocketJsonResponse) {
+ let res = wsJsonToRes(msg);
+ if (res.error) {
- alert(i18n.t(res.error));
+ toast(i18n.t(msg.error), 'danger');
this.state.userLoading = false;
this.setState(this.state);
return;
BanUserResponse,
AddAdminResponse,
DeleteAccountForm,
+ CreatePostLikeResponse,
+ WebSocketJsonResponse,
} from '../interfaces';
import { WebSocketService, UserService } from '../services';
import {
WebSocketService.Instance.deleteAccount(i.state.deleteAccountForm);
}
- parseMessage(msg: any) {
+ parseMessage(msg: WebSocketJsonResponse) {
console.log(msg);
- let op: UserOperation = msgOp(msg);
- if (msg.error) {
+ let res = wsJsonToRes(msg);
+ if (res.error) {
- alert(i18n.t(res.error));
+ toast(i18n.t(msg.error), 'danger');
this.state.deleteAccountLoading = false;
this.state.avatarLoading = false;
this.state.userSettingsLoading = false;
document.title = `/u/${this.state.user.name} - ${WebSocketService.Instance.site.name}`;
window.scrollTo(0, 0);
this.setState(this.state);
- } else if (op == UserOperation.EditComment) {
- let res: CommentResponse = msg;
+ } else if (res.op == UserOperation.EditComment) {
+ let data = res.data as CommentResponse;
- let found = this.state.comments.find(c => c.id == res.comment.id);
- found.content = res.comment.content;
- found.updated = res.comment.updated;
- found.removed = res.comment.removed;
- found.deleted = res.comment.deleted;
- found.upvotes = res.comment.upvotes;
- found.downvotes = res.comment.downvotes;
- found.score = res.comment.score;
+ let found = this.state.comments.find(c => c.id == data.comment.id);
+ found.content = data.comment.content;
+ found.updated = data.comment.updated;
+ found.removed = data.comment.removed;
+ found.deleted = data.comment.deleted;
+ found.upvotes = data.comment.upvotes;
+ found.downvotes = data.comment.downvotes;
+ found.score = data.comment.score;
this.setState(this.state);
- } else if (op == UserOperation.CreateComment) {
+ } else if (res.op == UserOperation.CreateComment) {
// let res: CommentResponse = msg;
- alert(i18n.t('reply_sent'));
+ toast(i18n.t('reply_sent'));
// this.state.comments.unshift(res.comment); // TODO do this right
// this.setState(this.state);
- } else if (op == UserOperation.SaveComment) {
- let res: CommentResponse = msg;
- let found = this.state.comments.find(c => c.id == res.comment.id);
- found.saved = res.comment.saved;
+ } else if (res.op == UserOperation.SaveComment) {
+ let data = res.data as CommentResponse;
+ let found = this.state.comments.find(c => c.id == data.comment.id);
+ found.saved = data.comment.saved;
this.setState(this.state);
- } else if (op == UserOperation.CreateCommentLike) {
- let res: CommentResponse = msg;
+ } else if (res.op == UserOperation.CreateCommentLike) {
+ let data = res.data as CommentResponse;
let found: Comment = this.state.comments.find(
- c => c.id === res.comment.id
+ c => c.id === data.comment.id
);
- found.score = res.comment.score;
- found.upvotes = res.comment.upvotes;
- found.downvotes = res.comment.downvotes;
- if (res.comment.my_vote !== null) found.my_vote = res.comment.my_vote;
+ found.score = data.comment.score;
+ found.upvotes = data.comment.upvotes;
+ found.downvotes = data.comment.downvotes;
+ if (data.comment.my_vote !== null) found.my_vote = data.comment.my_vote;
this.setState(this.state);
- } else if (op == UserOperation.CreatePostLike) {
- let res: CreatePostLikeResponse = msg;
- let found = this.state.posts.find(c => c.id == res.post.id);
- found.my_vote = res.post.my_vote;
- found.score = res.post.score;
- found.upvotes = res.post.upvotes;
- found.downvotes = res.post.downvotes;
++ } else if (res.op == UserOperation.CreatePostLike) {
++ let data = res.data as CreatePostLikeResponse;
++ let found = this.state.posts.find(c => c.id == data.post.id);
++ found.my_vote = data.post.my_vote;
++ found.score = data.post.score;
++ found.upvotes = data.post.upvotes;
++ found.downvotes = data.post.downvotes;
+ this.setState(this.state);
- } else if (op == UserOperation.BanUser) {
- let res: BanUserResponse = msg;
+ } else if (res.op == UserOperation.BanUser) {
+ let data = res.data as BanUserResponse;
this.state.comments
- .filter(c => c.creator_id == res.user.id)
- .forEach(c => (c.banned = res.banned));
+ .filter(c => c.creator_id == data.user.id)
+ .forEach(c => (c.banned = data.banned));
this.state.posts
- .filter(c => c.creator_id == res.user.id)
- .forEach(c => (c.banned = res.banned));
+ .filter(c => c.creator_id == data.user.id)
+ .forEach(c => (c.banned = data.banned));
this.setState(this.state);
- } else if (op == UserOperation.AddAdmin) {
- let res: AddAdminResponse = msg;
- this.state.admins = res.admins;
+ } else if (res.op == UserOperation.AddAdmin) {
+ let data = res.data as AddAdminResponse;
+ this.state.admins = data.admins;
this.setState(this.state);
- } else if (op == UserOperation.SaveUserSettings) {
+ } else if (res.op == UserOperation.SaveUserSettings) {
+ let data = res.data as LoginResponse;
this.state = this.emptyState;
this.state.userSettingsLoading = false;
this.setState(this.state);
password_verify: string;
}
- op: string;
+export interface PrivateMessageForm {
+ content: string;
+ recipient_id: number;
+ auth?: string;
+}
+
+export interface PrivateMessageFormParams {
+ recipient_id: number;
+}
+
+export interface EditPrivateMessageForm {
+ edit_id: number;
+ content?: string;
+ deleted?: boolean;
+ read?: boolean;
+ auth?: string;
+}
+
+export interface GetPrivateMessagesForm {
+ unread_only: boolean;
+ page?: number;
+ limit?: number;
+ auth?: string;
+}
+
+export interface PrivateMessagesResponse {
- op: string;
+ messages: Array<PrivateMessage>;
+}
+
+export interface PrivateMessageResponse {
- | AddAdminResponse;
+ message: PrivateMessage;
+}
++
+ type ResponseType =
+ | SiteResponse
+ | GetFollowedCommunitiesResponse
+ | ListCommunitiesResponse
+ | GetPostsResponse
+ | CreatePostLikeResponse
+ | GetRepliesResponse
+ | GetUserMentionsResponse
+ | ListCategoriesResponse
+ | CommunityResponse
+ | CommentResponse
+ | UserMentionResponse
+ | LoginResponse
+ | GetModlogResponse
+ | SearchResponse
+ | BanFromCommunityResponse
+ | AddModToCommunityResponse
+ | BanUserResponse
++ | AddAdminResponse
++ | PrivateMessageResponse
++ | PrivateMessagesResponse;
+
+ export interface WebSocketResponse {
+ op: UserOperation;
+ data: ResponseType;
+ error?: string;
+ }
+
+ export interface WebSocketJsonResponse {
+ op: string;
+ data: ResponseType;
+ error?: string;
+ }