From 39b50e8fe19b84cf8232fd17db56b35e5f435846 Mon Sep 17 00:00:00 2001 From: Sean King Date: Mon, 18 Jan 2021 19:59:07 -0700 Subject: [PATCH] Add moderator button for marking posts sensitive or not sensitive --- app/soapbox/actions/admin.js | 17 +++++++++++ app/soapbox/actions/moderation.js | 28 ++++++++++++++++++- app/soapbox/components/status_action_bar.js | 8 ++++++ app/soapbox/containers/status_container.js | 6 +++- .../features/status/components/action_bar.js | 8 ++++++ .../containers/detailed_status_container.js | 6 +++- app/soapbox/features/status/index.js | 8 +++++- 7 files changed, 77 insertions(+), 4 deletions(-) diff --git a/app/soapbox/actions/admin.js b/app/soapbox/actions/admin.js index b16ef5a8b..1667c782e 100644 --- a/app/soapbox/actions/admin.js +++ b/app/soapbox/actions/admin.js @@ -37,6 +37,10 @@ export const ADMIN_STATUS_DELETE_REQUEST = 'ADMIN_STATUS_DELETE_REQUEST'; export const ADMIN_STATUS_DELETE_SUCCESS = 'ADMIN_STATUS_DELETE_SUCCESS'; export const ADMIN_STATUS_DELETE_FAIL = 'ADMIN_STATUS_DELETE_FAIL'; +export const ADMIN_STATUS_TOGGLE_SENSITIVITY_REQUEST = 'ADMIN_STATUS_TOGGLE_SENSITIVITY_REQUEST'; +export const ADMIN_STATUS_TOGGLE_SENSITIVITY_SUCCESS = 'ADMIN_STATUS_TOGGLE_SENSITIVITY_SUCCESS'; +export const ADMIN_STATUS_TOGGLE_SENSITIVITY_FAIL = 'ADMIN_STATUS_TOGGLE_SENSITIVITY_FAIL'; + export const ADMIN_LOG_FETCH_REQUEST = 'ADMIN_LOG_FETCH_REQUEST'; export const ADMIN_LOG_FETCH_SUCCESS = 'ADMIN_LOG_FETCH_SUCCESS'; export const ADMIN_LOG_FETCH_FAIL = 'ADMIN_LOG_FETCH_FAIL'; @@ -167,6 +171,19 @@ export function deleteStatus(id) { }; } +export function toggleStatusSensitivity(id, sensitive) { + return (dispatch, getState) => { + dispatch({ type: ADMIN_STATUS_TOGGLE_SENSITIVITY_REQUEST, id }); + return api(getState) + .put(`/api/pleroma/admin/statuses/${id}`, { sensitive: !sensitive }) + .then(() => { + dispatch({ type: ADMIN_STATUS_TOGGLE_SENSITIVITY_SUCCESS, id }); + }).catch(error => { + dispatch({ type: ADMIN_STATUS_TOGGLE_SENSITIVITY_FAIL, error, id }); + }); + }; +} + export function fetchModerationLog(params) { return (dispatch, getState) => { dispatch({ type: ADMIN_LOG_FETCH_REQUEST }); diff --git a/app/soapbox/actions/moderation.js b/app/soapbox/actions/moderation.js index 7edc3e775..f8b71aa25 100644 --- a/app/soapbox/actions/moderation.js +++ b/app/soapbox/actions/moderation.js @@ -1,6 +1,6 @@ import { defineMessages } from 'react-intl'; import { openModal } from 'soapbox/actions/modal'; -import { deactivateUsers, deleteUsers, deleteStatus } from 'soapbox/actions/admin'; +import { deactivateUsers, deleteUsers, deleteStatus, toggleStatusSensitivity } from 'soapbox/actions/admin'; import snackbar from 'soapbox/actions/snackbar'; const messages = defineMessages({ @@ -13,6 +13,12 @@ const messages = defineMessages({ deleteStatusPrompt: { id: 'confirmations.admin.delete_status.message', defaultMessage: 'You are about to delete a post by {acct}. This action cannot be undone.' }, deleteStatusConfirm: { id: 'confirmations.admin.delete_status.confirm', defaultMessage: 'Delete post' }, statusDeleted: { id: 'admin.statuses.status_deleted_message', defaultMessage: 'Post by {acct} was deleted' }, + markStatusSensitivePrompt: { id: 'confirmations.admin.mark_status_sensitive.message', defaultMessage: 'You are about to mark a post by {acct} sensitive.' }, + markStatusNotSensitivePrompt: { id: 'confirmations.admin.mark_status_not_sensitive.message', defaultMessage: 'You are about to mark a post by {acct} not sensitive.' }, + markStatusSensitiveConfirm: { id: 'confirmations.admin.mark_status_sensitive.confirm', defaultMessage: 'Mark post sensitive' }, + markStatusNotSensitiveConfirm: { id: 'confirmations.admin.mark_status_not_sensitive.confirm', defaultMessage: 'Mark post not sensitive' }, + statusMarkedSensitive: { id: 'admin.statuses.status_marked_message_sensitive', defaultMessage: 'Post by {acct} was marked sensitive' }, + statusMarkedNotSensitive: { id: 'admin.statuses.status_marked_message_not_sensitive', defaultMessage: 'Post by {acct} was marked not sensitive' }, }); export function deactivateUserModal(intl, accountId, afterConfirm = () => {}) { @@ -51,6 +57,26 @@ export function deleteUserModal(intl, accountId, afterConfirm = () => {}) { }; } +export function toggleStatusSensitivityModal(intl, statusId, sensitive, afterConfirm = () => {}) { + return function(dispatch, getState) { + const state = getState(); + const accountId = state.getIn(['statuses', statusId, 'account']); + const acct = state.getIn(['accounts', accountId, 'acct']); + + dispatch(openModal('CONFIRM', { + message: intl.formatMessage(sensitive === false ? messages.markStatusSensitivePrompt : messages.markStatusNotSensitivePrompt, { acct: `@${acct}` }), + confirm: intl.formatMessage(sensitive === false ? messages.markStatusSensitiveConfirm : messages.markStatusNotSensitiveConfirm), + onConfirm: () => { + dispatch(toggleStatusSensitivity(statusId, sensitive)).then(() => { + const message = intl.formatMessage(sensitive === false ? messages.statusMarkedSensitive : messages.statusMarkedNotSensitive, { acct: `@${acct}` }); + dispatch(snackbar.success(message)); + }).catch(() => {}); + afterConfirm(); + }, + })); + }; +} + export function deleteStatusModal(intl, statusId, afterConfirm = () => {}) { return function(dispatch, getState) { const state = getState(); diff --git a/app/soapbox/components/status_action_bar.js b/app/soapbox/components/status_action_bar.js index 5895dde9e..2e2934553 100644 --- a/app/soapbox/components/status_action_bar.js +++ b/app/soapbox/components/status_action_bar.js @@ -48,6 +48,8 @@ const messages = defineMessages({ deactivateUser: { id: 'admin.users.actions.deactivate_user', defaultMessage: 'Deactivate {acct}' }, deleteUser: { id: 'admin.users.actions.delete_user', defaultMessage: 'Delete {acct}' }, deleteStatus: { id: 'admin.statuses.actions.delete_status', defaultMessage: 'Delete post' }, + markStatusSensitive: { id: 'admin.statuses.actions.mark_status_sensitive', defaultMessage: 'Mark post sensitive' }, + markStatusNotSensitive: { id: 'admin.statuses.actions.mark_status_not_sensitive', defaultMessage: 'Mark post not sensitive' }, }); class StatusActionBar extends ImmutablePureComponent { @@ -72,6 +74,7 @@ class StatusActionBar extends ImmutablePureComponent { onEmbed: PropTypes.func, onDeactivateUser: PropTypes.func, onDeleteUser: PropTypes.func, + onToggleStatusSensitivity: PropTypes.func, onDeleteStatus: PropTypes.func, onMuteConversation: PropTypes.func, onPin: PropTypes.func, @@ -260,6 +263,10 @@ class StatusActionBar extends ImmutablePureComponent { this.props.onDeleteStatus(this.props.status); } + handleToggleStatusSensitivity = () => { + this.props.onToggleStatusSensitivity(this.props.status); + } + _makeMenu = (publicStatus) => { const { status, intl, withDismiss, withGroupAdmin, me, isStaff } = this.props; const mutingConversation = status.get('muted'); @@ -311,6 +318,7 @@ class StatusActionBar extends ImmutablePureComponent { // menu.push({ text: intl.formatMessage(messages.admin_status), href: `/admin/accounts/${status.getIn(['account', 'id'])}/statuses/${status.get('id')}` }); menu.push({ text: intl.formatMessage(messages.deactivateUser, { acct: `@${status.getIn(['account', 'acct'])}` }), action: this.handleDeactivateUser }); menu.push({ text: intl.formatMessage(messages.deleteUser, { acct: `@${status.getIn(['account', 'acct'])}` }), action: this.handleDeleteUser }); + menu.push({ text: intl.formatMessage(status.get('sensitive') === false ? messages.markStatusSensitive : messages.markStatusNotSensitive), action: this.handleToggleStatusSensitivity }); menu.push({ text: intl.formatMessage(messages.deleteStatus), action: this.handleDeleteStatus }); } diff --git a/app/soapbox/containers/status_container.js b/app/soapbox/containers/status_container.js index abb0da6c4..8c5206607 100644 --- a/app/soapbox/containers/status_container.js +++ b/app/soapbox/containers/status_container.js @@ -36,7 +36,7 @@ import { } from '../actions/groups'; import { getSettings } from '../actions/settings'; import { getSoapboxConfig } from 'soapbox/actions/soapbox'; -import { deactivateUserModal, deleteUserModal, deleteStatusModal } from 'soapbox/actions/moderation'; +import { deactivateUserModal, deleteUserModal, deleteStatusModal, toggleStatusSensitivityModal } from 'soapbox/actions/moderation'; const messages = defineMessages({ deleteConfirm: { id: 'confirmations.delete.confirm', defaultMessage: 'Delete' }, @@ -221,6 +221,10 @@ const mapDispatchToProps = (dispatch, { intl }) => ({ dispatch(deleteStatusModal(intl, status.get('id'))); }, + onToggleStatusSensitivity(status) { + dispatch(toggleStatusSensitivityModal(intl, status.get('id'), status.get('sensitive'))); + }, + }); export default injectIntl(connect(makeMapStateToProps, mapDispatchToProps)(Status)); diff --git a/app/soapbox/features/status/components/action_bar.js b/app/soapbox/features/status/components/action_bar.js index 2e8e6f375..759f58b3c 100644 --- a/app/soapbox/features/status/components/action_bar.js +++ b/app/soapbox/features/status/components/action_bar.js @@ -39,6 +39,8 @@ const messages = defineMessages({ deactivateUser: { id: 'admin.users.actions.deactivate_user', defaultMessage: 'Deactivate {acct}' }, deleteUser: { id: 'admin.users.actions.delete_user', defaultMessage: 'Delete {acct}' }, deleteStatus: { id: 'admin.statuses.actions.delete_status', defaultMessage: 'Delete post' }, + markStatusSensitive: { id: 'admin.statuses.actions.mark_status_sensitive', defaultMessage: 'Mark post sensitive' }, + markStatusNotSensitive: { id: 'admin.statuses.actions.mark_status_not_sensitive', defaultMessage: 'Mark post not sensitive' }, }); const mapStateToProps = state => { @@ -80,6 +82,7 @@ class ActionBar extends React.PureComponent { onDeactivateUser: PropTypes.func, onDeleteUser: PropTypes.func, onDeleteStatus: PropTypes.func, + onToggleStatusSensitivity: PropTypes.func, intl: PropTypes.object.isRequired, onOpenUnauthorizedModal: PropTypes.func.isRequired, me: SoapboxPropTypes.me, @@ -235,6 +238,10 @@ class ActionBar extends React.PureComponent { this.props.onDeleteUser(this.props.status); } + handleToggleStatusSensitivity = () => { + this.props.onToggleStatusSensitivity(this.props.status); + } + handleDeleteStatus = () => { this.props.onDeleteStatus(this.props.status); } @@ -296,6 +303,7 @@ class ActionBar extends React.PureComponent { // menu.push({ text: intl.formatMessage(messages.admin_status), href: `/admin/accounts/${status.getIn(['account', 'id'])}/statuses/${status.get('id')}` }); menu.push({ text: intl.formatMessage(messages.deactivateUser, { acct: `@${status.getIn(['account', 'acct'])}` }), action: this.handleDeactivateUser }); menu.push({ text: intl.formatMessage(messages.deleteUser, { acct: `@${status.getIn(['account', 'acct'])}` }), action: this.handleDeleteUser }); + menu.push({ text: intl.formatMessage(status.get('sensitive') === false ? messages.markStatusSensitive : messages.markStatusNotSensitive), action: this.handleToggleStatusSensitivity }); menu.push({ text: intl.formatMessage(messages.deleteStatus), action: this.handleDeleteStatus }); } } diff --git a/app/soapbox/features/status/containers/detailed_status_container.js b/app/soapbox/features/status/containers/detailed_status_container.js index e9c64e384..1c0a8cf64 100644 --- a/app/soapbox/features/status/containers/detailed_status_container.js +++ b/app/soapbox/features/status/containers/detailed_status_container.js @@ -31,7 +31,7 @@ import { openModal } from '../../../actions/modal'; import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; import { showAlertForError } from '../../../actions/alerts'; import { getSettings } from 'soapbox/actions/settings'; -import { deactivateUserModal, deleteUserModal, deleteStatusModal } from 'soapbox/actions/moderation'; +import { deactivateUserModal, deleteUserModal, deleteStatusModal, toggleStatusSensitivityModal } from 'soapbox/actions/moderation'; const messages = defineMessages({ deleteConfirm: { id: 'confirmations.delete.confirm', defaultMessage: 'Delete' }, @@ -199,6 +199,10 @@ const mapDispatchToProps = (dispatch, { intl }) => ({ dispatch(deleteUserModal(intl, status.getIn(['account', 'id']))); }, + onToggleStatusSensitivity(status) { + dispatch(toggleStatusSensitivityModal(intl, status.get('id'), status.get('sensitive'))); + }, + onDeleteStatus(status) { dispatch(deleteStatusModal(intl, status.get('id'))); }, diff --git a/app/soapbox/features/status/index.js b/app/soapbox/features/status/index.js index a48cedaa4..44992b426 100644 --- a/app/soapbox/features/status/index.js +++ b/app/soapbox/features/status/index.js @@ -47,7 +47,7 @@ import { textForScreenReader, defaultMediaVisibility } from '../../components/st import Icon from 'soapbox/components/icon'; import { getSettings } from 'soapbox/actions/settings'; import { getSoapboxConfig } from 'soapbox/actions/soapbox'; -import { deactivateUserModal, deleteUserModal, deleteStatusModal } from 'soapbox/actions/moderation'; +import { deactivateUserModal, deleteUserModal, deleteStatusModal, toggleStatusSensitivityModal } from 'soapbox/actions/moderation'; const messages = defineMessages({ deleteConfirm: { id: 'confirmations.delete.confirm', defaultMessage: 'Delete' }, @@ -313,6 +313,11 @@ class Status extends ImmutablePureComponent { dispatch(deleteUserModal(intl, status.getIn(['account', 'id']))); } + handleToggleStatusSensitivity = (status) => { + const { dispatch, intl } = this.props; + dispatch(toggleStatusSensitivityModal(intl, status.get('id'), status.get('sensitive'))); + } + handleDeleteStatus = (status) => { const { dispatch, intl } = this.props; dispatch(deleteStatusModal(intl, status.get('id'))); @@ -541,6 +546,7 @@ class Status extends ImmutablePureComponent { onEmbed={this.handleEmbed} onDeactivateUser={this.handleDeactivateUser} onDeleteUser={this.handleDeleteUser} + onToggleStatusSensitivity={this.handleToggleStatusSensitivity} onDeleteStatus={this.handleDeleteStatus} allowedEmoji={this.props.allowedEmoji} />