From 6ad9e22965b49c35a4e6ac32ce31723aaabff7ca Mon Sep 17 00:00:00 2001 From: xaralis <filip.varecha@fragaria.cz> Date: Wed, 23 Dec 2020 14:51:35 +0100 Subject: [PATCH] feat: properly handle unbanning --- src/actions/users.js | 2 +- src/components/posts/Post.jsx | 11 ++++++++++- src/components/posts/PostList.jsx | 3 +++ src/containers/PostsContainer.jsx | 33 ++++++++++++++++++++++++++++++- src/utils.js | 6 +++++- src/ws/connection.js | 8 -------- src/ws/handlers/global.js | 9 +++++++++ src/ws/handlers/index.js | 2 ++ src/ws/handlers/users.js | 18 ++++++++++++++++- typings/cf2021.d.ts | 1 + 10 files changed, 80 insertions(+), 13 deletions(-) create mode 100644 src/ws/handlers/global.js diff --git a/src/actions/users.js b/src/actions/users.js index 7fe04d8..49cf58b 100644 --- a/src/actions/users.js +++ b/src/actions/users.js @@ -51,7 +51,7 @@ export const ban = createAsyncAction( } ); -export const removeBan = createAsyncAction( +export const unban = createAsyncAction( /** * @param {number} userId */ diff --git a/src/components/posts/Post.jsx b/src/components/posts/Post.jsx index dc5fefb..207ed78 100644 --- a/src/components/posts/Post.jsx +++ b/src/components/posts/Post.jsx @@ -25,6 +25,7 @@ const Post = ({ onDislike, onHide, onBanUser, + onUnbanUser, onAnnounceProcedureProposal, onAcceptProcedureProposal, onRejectProcedureProposal, @@ -131,7 +132,8 @@ const Post = ({ const showRejectByChairmanAction = type === "procedure-proposal" && ["announced", "pending"].includes(state); const showEditAction = true; - const showBanAction = true; + const showBanAction = !author.isBanned; + const showUnbanAction = author.isBanned; const showHideAction = !archived; const showArchiveAction = !archived; @@ -225,6 +227,13 @@ const Post = ({ title="Zablokovat uĹľivatele" /> )} + {showUnbanAction && ( + <DropdownMenuItem + onClick={onUnbanUser} + icon="ico--lock-open" + title="Odblokovat uĹľivatele" + /> + )} {showHideAction && ( <DropdownMenuItem onClick={onHide} diff --git a/src/components/posts/PostList.jsx b/src/components/posts/PostList.jsx index da1ad33..23ba693 100644 --- a/src/components/posts/PostList.jsx +++ b/src/components/posts/PostList.jsx @@ -12,6 +12,7 @@ const PostList = ({ onDislike, onHide, onBanUser, + onUnbanUser, onAnnounceProcedureProposal, onAcceptProcedureProposal, onRejectProcedureProposal, @@ -31,6 +32,7 @@ const PostList = ({ const onPostEdit = buildHandler(onEdit); const onPostHide = buildHandler(onHide); const onPostBanUser = buildHandler(onBanUser); + const onPostUnbanUser = buildHandler(onUnbanUser); const onPostArchive = buildHandler(onArchive); const onPostAnnounceProcedureProposal = buildHandler( onAnnounceProcedureProposal @@ -69,6 +71,7 @@ const PostList = ({ onDislike={onPostDislike(item)} onHide={onPostHide(item)} onBanUser={onPostBanUser(item)} + onUnbanUser={onPostUnbanUser(item)} onAnnounceProcedureProposal={onPostAnnounceProcedureProposal(item)} onAcceptProcedureProposal={onPostAcceptProcedureProposal(item)} onRejectProcedureProposal={onPostRejectProcedureProposal(item)} diff --git a/src/containers/PostsContainer.jsx b/src/containers/PostsContainer.jsx index 486eafe..863c915 100644 --- a/src/containers/PostsContainer.jsx +++ b/src/containers/PostsContainer.jsx @@ -14,7 +14,7 @@ import { rejectProposal, rejectProposalByChairman, } from "actions/posts"; -import { ban } from "actions/users"; +import { ban, unban } from "actions/users"; import ErrorMessage from "components/ErrorMessage"; import ModalConfirm from "components/modals/ModalConfirm"; import PostEditModal from "components/posts/PostEditModal"; @@ -33,6 +33,12 @@ const PostsContainer = ({ className }) => { onBanUserConfirm, onBanUserCancel, ] = useItemActionConfirm(ban); + const [ + userToUnban, + setUserToUnban, + onUnbanUserConfirm, + onUnbanUserCancel, + ] = useItemActionConfirm(unban); const [ postToHide, setPostToHide, @@ -79,6 +85,10 @@ const PostsContainer = ({ className }) => { ); const [banningUser, banningUserError] = useActionState(ban, userToBan); + const [unbanningUser, unbanningUserError] = useActionState( + unban, + userToUnban + ); const [hidingPost, hidingPostError] = useActionState(hide, postToHide); const [archivingPost, archivingPostError] = useActionState( archive, @@ -134,6 +144,13 @@ const PostsContainer = ({ className }) => { const onBanUser = (post) => { setUserToBan(post.author); }; + /** + * Ban a post's author. + * @param {CF2021.Post} post + */ + const onUnbanUser = (post) => { + setUserToUnban(post.author); + }; const sliceStart = (window.page - 1) * window.perPage; const sliceEnd = window.page * window.perPage; @@ -157,6 +174,7 @@ const PostsContainer = ({ className }) => { dimArchived={!showingArchivedOnly} onHide={setPostToHide} onBanUser={onBanUser} + onUnbanUser={onUnbanUser} onEdit={setPostToEdit} onArchive={setPostToArchive} onAnnounceProcedureProposal={setPostToAnnounce} @@ -176,6 +194,19 @@ const PostsContainer = ({ className }) => { UĹľivatel <strong>{userToBan ? userToBan.name : null}</strong> bude zablokován a nebude dále moci vkládat novĂ© pĹ™ĂspÄ›vky. Opravdu to chcete? </ModalConfirm> + <ModalConfirm + isOpen={!!userToUnban} + onConfirm={onUnbanUserConfirm} + onCancel={onUnbanUserCancel} + confirming={unbanningUser} + error={unbanningUserError} + title={`Odblokovat uĹľivatele ${userToUnban ? userToUnban.name : null}?`} + yesActionLabel="Odblokovat" + > + UĹľivatel <strong>{userToUnban ? userToUnban.name : null}</strong> bude + odblokován a bude mu opÄ›t umoĹľnÄ›no pĹ™idávat novĂ© pĹ™ĂspÄ›vky. Opravdu to + chcete? + </ModalConfirm> <ModalConfirm isOpen={!!postToHide} onConfirm={onPostHideConfirm} diff --git a/src/utils.js b/src/utils.js index cc62eea..e21427d 100644 --- a/src/utils.js +++ b/src/utils.js @@ -126,7 +126,11 @@ export const announcementTypeMappingRev = { */ export const parseRawPost = (rawPost) => { const post = { - ...pick(rawPost, ["id", "content", "author"]), + ...pick(rawPost, ["id", "content"]), + author: { + ...pick(rawPost.author, ["id", "name", "username", "group"]), + isBanned: rawPost.author.is_banned === 1, + }, contentHtml: markdownConverter.makeHtml(rawPost.content), datetime: parse(rawPost.datetime, "yyyy-MM-dd HH:mm:ss", new Date()), historyLog: rawPost.history_log, diff --git a/src/ws/connection.js b/src/ws/connection.js index 17f9c2e..4882d1b 100644 --- a/src/ws/connection.js +++ b/src/ws/connection.js @@ -1,4 +1,3 @@ -import has from "lodash/has"; import WaitQueue from "wait-queue"; import { GlobalInfoStore } from "stores"; @@ -20,13 +19,6 @@ function Worker() { try { const data = JSON.parse(event.data); - // Special message, TODO: fix - if (has(data, "online_users")) { - return GlobalInfoStore.update((state) => { - state.onlineUsers = data["online_users"]; - }); - } - if (!data.event) { return console.error("[ws][worker] Missing `event` field"); } diff --git a/src/ws/handlers/global.js b/src/ws/handlers/global.js new file mode 100644 index 0000000..ba8a2e0 --- /dev/null +++ b/src/ws/handlers/global.js @@ -0,0 +1,9 @@ +import isNumber from "lodash/isNumber"; + +import { GlobalInfoStore } from "stores"; + +export const handleOnlineUsersUpdated = (onlineUserCount) => { + GlobalInfoStore.update((state) => { + state.onlineUsers = isNumber(onlineUserCount) ? onlineUserCount : 0; + }); +}; diff --git a/src/ws/handlers/index.js b/src/ws/handlers/index.js index fb4f300..fb68618 100644 --- a/src/ws/handlers/index.js +++ b/src/ws/handlers/index.js @@ -3,6 +3,7 @@ import { handleAnnouncementCreated, handleAnnouncementDeleted, } from "./announcements"; +import { handleOnlineUsersUpdated } from "./global"; import { handlePostChanged, handlePostCreated, @@ -23,4 +24,5 @@ export const handlers = { program_entry_changed: handleProgramEntryChanged, user_banned: handleUserBanned, user_unbanned: handleUserUnbanned, + online_users_updated: handleOnlineUsersUpdated, }; diff --git a/src/ws/handlers/users.js b/src/ws/handlers/users.js index bf9243f..85d8ca2 100644 --- a/src/ws/handlers/users.js +++ b/src/ws/handlers/users.js @@ -1,4 +1,4 @@ -import { AuthStore } from "stores"; +import { AuthStore, PostStore } from "stores"; export const handleUserBanned = (payload) => { AuthStore.update((state) => { @@ -6,6 +6,14 @@ export const handleUserBanned = (payload) => { state.user.isBanned = true; } }); + + PostStore.update((state) => { + Object.keys(state.items).forEach((key) => { + if (state.items[key].author.id === payload.id) { + state.items[key].author.isBanned = true; + } + }); + }); }; export const handleUserUnbanned = (payload) => { @@ -14,4 +22,12 @@ export const handleUserUnbanned = (payload) => { state.user.isBanned = false; } }); + + PostStore.update((state) => { + Object.keys(state.items).forEach((key) => { + if (state.items[key].author.id === payload.id) { + state.items[key].author.isBanned = false; + } + }); + }); }; diff --git a/typings/cf2021.d.ts b/typings/cf2021.d.ts index 5b31734..fa510f2 100644 --- a/typings/cf2021.d.ts +++ b/typings/cf2021.d.ts @@ -88,6 +88,7 @@ declare namespace CF2021 { name: string; username: string; group: string; + isBanned: boolean; }; type: PostType; content: string; -- GitLab