diff --git a/web/.eslintrc.js b/web/.eslintrc.js
index bbd55376..2915f941 100644
--- a/web/.eslintrc.js
+++ b/web/.eslintrc.js
@@ -43,7 +43,7 @@ module.exports = {
'no-undef-init': 2,
'no-shadow-restricted-names': 2,
'handle-callback-err': 0,
- 'no-lonely-if': 2,
+ 'no-lonely-if': 0,
'constructor-super': 2,
'no-this-before-super': 2,
'no-dupe-class-members': 2,
diff --git a/web/app/common/api.js b/web/app/common/api.js
index 96ea41ef..d79faf2e 100644
--- a/web/app/common/api.js
+++ b/web/app/common/api.js
@@ -118,6 +118,18 @@ export const getBlocked = () =>
withCredentials: true,
});
+export const disableComments = () =>
+ fetcher.put({
+ url: `/admin/readonly?site=${siteId}&url=${url}&ro=1`,
+ withCredentials: true,
+ });
+
+export const enableComments = () =>
+ fetcher.put({
+ url: `/admin/readonly?site=${siteId}&url=${url}&ro=0`,
+ withCredentials: true,
+ });
+
export default {
logOut,
getConfig,
@@ -140,4 +152,6 @@ export default {
blockUser,
unblockUser,
getBlocked,
+ disableComments,
+ enableComments,
};
diff --git a/web/app/components/auth-panel/__tests__/auth-panel.test.js b/web/app/components/auth-panel/__tests__/auth-panel.test.js
index fa946807..ce8f1bb7 100644
--- a/web/app/components/auth-panel/__tests__/auth-panel.test.js
+++ b/web/app/components/auth-panel/__tests__/auth-panel.test.js
@@ -67,7 +67,7 @@ describe('', () => {
const adminAction = container.querySelector('.auth-panel__admin-action');
- expect(adminAction.textContent).toEqual('Show blocked');
+ expect(adminAction.textContent).toEqual('Show blocked users');
});
});
});
diff --git a/web/app/components/auth-panel/auth-panel.jsx b/web/app/components/auth-panel/auth-panel.jsx
index e0327b3b..a2560f8c 100644
--- a/web/app/components/auth-panel/auth-panel.jsx
+++ b/web/app/components/auth-panel/auth-panel.jsx
@@ -10,6 +10,7 @@ export default class AuthPanel extends Component {
this.toggleUserId = this.toggleUserId.bind(this);
this.toggleBlockedVisibility = this.toggleBlockedVisibility.bind(this);
+ this.toggleCommentsAvailability = this.toggleCommentsAvailability.bind(this);
this.onSortChange = this.onSortChange.bind(this);
}
@@ -31,8 +32,20 @@ export default class AuthPanel extends Component {
this.setState({ isBlockedVisible: !this.state.isBlockedVisible });
}
+ toggleCommentsAvailability() {
+ if (this.props.isCommentsDisabled) {
+ if (this.props.onCommentsEnable) {
+ this.props.onCommentsEnable();
+ }
+ } else {
+ if (this.props.onCommentsDisable) {
+ this.props.onCommentsDisable();
+ }
+ }
+ }
+
render(props, { isUserIdVisible, isBlockedVisible }) {
- const { user, providers = [], sort } = props;
+ const { user, providers = [], sort, isCommentsDisabled } = props;
const sortArray = getSortArray(sort);
@@ -82,7 +95,19 @@ export default class AuthPanel extends Component {
{...getHandleClickProps(this.toggleBlockedVisibility)}
role="link"
>
- {isBlockedVisible ? 'Hide' : 'Show'} blocked
+ {isBlockedVisible ? 'Hide' : 'Show'} blocked users
+
+ )}
+
+ {user.admin && ' • '}
+
+ {user.admin && (
+
+ {isCommentsDisabled ? 'Enable' : 'Disable'} comments
)}
diff --git a/web/app/components/comment/comment.jsx b/web/app/components/comment/comment.jsx
index 53c52c7d..74b139d5 100644
--- a/web/app/components/comment/comment.jsx
+++ b/web/app/components/comment/comment.jsx
@@ -320,7 +320,7 @@ export default class Comment extends Component {
editTimeLeft,
}
) {
- const { data, mods = {} } = props;
+ const { data, mods = {}, isCommentsDisabled } = props;
const isAdmin = !guest && store.get('user').admin;
const isGuest = guest || !Object.keys(store.get('user')).length;
const isCurrentUser = (data.user && data.user.id) === (store.get('user') && store.get('user').id);
@@ -500,6 +500,7 @@ export default class Comment extends Component {
{!deleted &&
+ !isCommentsDisabled &&
!mods.disabled &&
!isGuest &&
mods.view !== 'user' && (
diff --git a/web/app/components/root/root.jsx b/web/app/components/root/root.jsx
index 04713530..986a6d47 100644
--- a/web/app/components/root/root.jsx
+++ b/web/app/components/root/root.jsx
@@ -48,6 +48,8 @@ export default class Root extends Component {
this.onSignOut = this.onSignOut.bind(this);
this.onBlockedUsersShow = this.onBlockedUsersShow.bind(this);
this.onBlockedUsersHide = this.onBlockedUsersHide.bind(this);
+ this.onCommentsDisable = this.onCommentsDisable.bind(this);
+ this.onCommentsEnable = this.onCommentsEnable.bind(this);
this.onSortChange = this.onSortChange.bind(this);
this.onUnblockSomeone = this.onUnblockSomeone.bind(this);
this.checkUrlHash = this.checkUrlHash.bind(this);
@@ -56,6 +58,7 @@ export default class Root extends Component {
componentWillMount() {
store.onUpdate('comments', comments => this.setState({ comments }));
+ store.onUpdate('info', info => this.setState({ info }));
}
componentDidMount() {
@@ -73,7 +76,10 @@ export default class Root extends Component {
.catch(() => store.set('user', {})),
api
.getPostComments({ sort, url })
- .then(({ comments = [] } = {}) => store.set('comments', comments))
+ .then(({ comments = [], info = {} } = {}) => {
+ store.set('comments', comments);
+ store.set('info', info);
+ })
.catch(() => store.set('comments', [])),
]).finally(() => {
this.setState({
@@ -145,12 +151,31 @@ export default class Root extends Component {
});
}
+ onCommentsEnable() {
+ api.enableComments(siteId, url).then(() => {
+ const info = store.get('info');
+ info.read_only = false;
+ this.setState({ info });
+ });
+ }
+
+ onCommentsDisable() {
+ api.disableComments(siteId, url).then(() => {
+ const info = store.get('info');
+ info.read_only = true;
+ this.setState({ info });
+ });
+ }
+
onBlockedUsersHide() {
const { wasSomeoneUnblocked, sort } = this.state;
// if someone was unblocked let's reload comments
if (wasSomeoneUnblocked) {
- api.getPostComments({ sort, url }).then(({ comments } = {}) => store.set('comments', comments));
+ api.getPostComments({ sort, url }).then(({ comments, info } = {}) => {
+ store.set('comments', comments);
+ store.set('info', info);
+ });
}
this.setState({
@@ -172,7 +197,10 @@ export default class Root extends Component {
api
.getPostComments({ sort, url })
- .then(({ comments } = {}) => store.set('comments', comments))
+ .then(({ comments, info } = {}) => {
+ store.set('comments', comments);
+ store.set('info', info);
+ })
.finally(() => {
this.setState({ isCommentsListLoading: false });
});
@@ -201,6 +229,7 @@ export default class Root extends Component {
{
config = {},
comments = [],
+ info = {},
user,
sort,
isLoaded,
@@ -223,6 +252,7 @@ export default class Root extends Component {
// TODO: i think we should do it on backend
const pinnedComments = store.getPinnedComments();
const isGuest = !Object.keys(user).length;
+ const isCommentsDisabled = info != null && info.read_only === true;
return (
@@ -231,16 +261,20 @@ export default class Root extends Component {
user={user}
sort={sort}
providers={config.auth_providers}
+ isCommentsDisabled={isCommentsDisabled}
onSignIn={this.onSignIn}
onSignOut={this.onSignOut}
onBlockedUsersShow={this.onBlockedUsersShow}
onBlockedUsersHide={this.onBlockedUsersHide}
+ onCommentsEnable={this.onCommentsEnable}
+ onCommentsDisable={this.onCommentsDisable}
onSortChange={this.onSortChange}
/>
{!isBlockedVisible && (
- {!isGuest &&
}
+ {!isGuest &&
+ !isCommentsDisabled &&
}
{!!pinnedComments.length && (
@@ -259,6 +293,7 @@ export default class Root extends Component {
mix="root__thread"
mods={{ level: 0 }}
data={thread}
+ isCommentsDisabled={isCommentsDisabled}
onReply={this.addComment}
onEdit={this.replaceComment}
/>
diff --git a/web/app/components/thread/thread.jsx b/web/app/components/thread/thread.jsx
index 0f5b2b45..1b2342af 100644
--- a/web/app/components/thread/thread.jsx
+++ b/web/app/components/thread/thread.jsx
@@ -21,6 +21,7 @@ class Thread extends Component {
collapsed,
data: { comment, replies = [] },
mods = {},
+ isCommentsDisabled,
} = props;
return (
@@ -31,6 +32,7 @@ class Thread extends Component {
>