mirror of
https://github.com/wassname/talk.git
synced 2026-07-11 06:57:24 +08:00
Implement activity tracking for flagged accounts
This commit is contained in:
@@ -11,6 +11,7 @@ import {
|
||||
HIDE_BANUSER_DIALOG,
|
||||
SHOW_REJECT_USERNAME_DIALOG,
|
||||
HIDE_REJECT_USERNAME_DIALOG,
|
||||
SET_INDICATOR_TRACK,
|
||||
} from '../constants/community';
|
||||
|
||||
import t from 'coral-framework/services/i18n';
|
||||
@@ -68,3 +69,8 @@ export const showRejectUsernameDialog = user => ({
|
||||
export const hideRejectUsernameDialog = () => ({
|
||||
type: HIDE_REJECT_USERNAME_DIALOG,
|
||||
});
|
||||
|
||||
export const setIndicatorTrack = track => ({
|
||||
type: SET_INDICATOR_TRACK,
|
||||
track,
|
||||
});
|
||||
|
||||
@@ -15,6 +15,7 @@ const CoralHeader = ({
|
||||
showShortcuts = () => {},
|
||||
auth,
|
||||
root,
|
||||
data,
|
||||
}) => {
|
||||
return (
|
||||
<div className={styles.headerWrapper}>
|
||||
@@ -31,7 +32,7 @@ const CoralHeader = ({
|
||||
activeClassName={styles.active}
|
||||
>
|
||||
{t('configure.moderate')}
|
||||
<ModerationIndicator root={root} />
|
||||
<ModerationIndicator root={root} data={data} />
|
||||
</IndexLink>
|
||||
)}
|
||||
<Link
|
||||
@@ -50,7 +51,7 @@ const CoralHeader = ({
|
||||
activeClassName={styles.active}
|
||||
>
|
||||
{t('configure.community')}
|
||||
<CommunityIndicator root={root} />
|
||||
<CommunityIndicator root={root} data={data} />
|
||||
</Link>
|
||||
|
||||
{can(auth.user, 'UPDATE_CONFIG') && (
|
||||
@@ -119,6 +120,7 @@ CoralHeader.propTypes = {
|
||||
showShortcuts: PropTypes.func,
|
||||
handleLogout: PropTypes.func.isRequired,
|
||||
root: PropTypes.object.isRequired,
|
||||
data: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
export default CoralHeader;
|
||||
|
||||
@@ -18,3 +18,5 @@ export const SHOW_REJECT_USERNAME_DIALOG = `${prefix}_SHOW_REJECT_USERNAME_DIALO
|
||||
export const HIDE_REJECT_USERNAME_DIALOG = `${prefix}_HIDE_REJECT_USERNAME_DIALOG`;
|
||||
|
||||
export const SET_SEARCH_VALUE = `${prefix}_SET_SEARCH_VALUE`;
|
||||
|
||||
export const SET_INDICATOR_TRACK = `${prefix}_SET_INDICATOR_TRACK`;
|
||||
|
||||
@@ -13,10 +13,5 @@ export default withQuery(
|
||||
}
|
||||
${ModerationIndicator.fragments.root}
|
||||
${CommunityIndicator.fragments.root}
|
||||
`,
|
||||
{
|
||||
options: {
|
||||
pollInterval: 10000,
|
||||
},
|
||||
}
|
||||
`
|
||||
)(Header);
|
||||
|
||||
@@ -173,13 +173,17 @@ export default {
|
||||
},
|
||||
updateQueries: {
|
||||
TalkAdmin_Community_FlaggedAccounts: (prev, { mutationResult }) => {
|
||||
const decrement = {
|
||||
flaggedUsernamesCount: { $apply: count => count - 1 },
|
||||
};
|
||||
|
||||
// Remove from list after the mutation was "really" completed.
|
||||
if (get(mutationResult, 'data.approveUsername.isOptimistic')) {
|
||||
return prev;
|
||||
return update(prev, decrement);
|
||||
}
|
||||
|
||||
const updated = update(prev, {
|
||||
flaggedUsernamesCount: { $apply: count => count - 1 },
|
||||
...decrement,
|
||||
flaggedUsers: {
|
||||
nodes: { $apply: nodes => nodes.filter(node => node.id !== id) },
|
||||
},
|
||||
@@ -227,13 +231,17 @@ export default {
|
||||
},
|
||||
updateQueries: {
|
||||
TalkAdmin_Community_FlaggedAccounts: (prev, { mutationResult }) => {
|
||||
const decrement = {
|
||||
flaggedUsernamesCount: { $apply: count => count - 1 },
|
||||
};
|
||||
|
||||
// Remove from list after the mutation was "really" completed.
|
||||
if (get(mutationResult, 'data.rejectUsername.isOptimistic')) {
|
||||
return prev;
|
||||
return update(prev, decrement);
|
||||
}
|
||||
|
||||
const updated = update(prev, {
|
||||
flaggedUsernamesCount: { $apply: count => count - 1 },
|
||||
...decrement,
|
||||
flaggedUsers: {
|
||||
nodes: {
|
||||
$apply: nodes => nodes.filter(node => node.id !== id),
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
HIDE_BANUSER_DIALOG,
|
||||
SHOW_REJECT_USERNAME_DIALOG,
|
||||
HIDE_REJECT_USERNAME_DIALOG,
|
||||
SET_INDICATOR_TRACK,
|
||||
} from '../constants/community';
|
||||
|
||||
const initialState = {
|
||||
@@ -24,6 +25,10 @@ const initialState = {
|
||||
user: {},
|
||||
banDialog: false,
|
||||
rejectUsernameDialog: false,
|
||||
// If true the activity indicator will track flagged account changes
|
||||
// in order to determine the current queue count. Set this to false
|
||||
// if the queue count is determined by other means.
|
||||
indicatorTrack: true,
|
||||
};
|
||||
|
||||
export default function community(state = initialState, action) {
|
||||
@@ -91,6 +96,11 @@ export default function community(state = initialState, action) {
|
||||
...state,
|
||||
searchValue: action.value,
|
||||
};
|
||||
case SET_INDICATOR_TRACK:
|
||||
return {
|
||||
...state,
|
||||
indicatorTrack: action.track,
|
||||
};
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
|
||||
@@ -6,12 +6,15 @@ import withQuery from 'coral-framework/hocs/withQuery';
|
||||
import { Spinner } from 'coral-ui';
|
||||
import PropTypes from 'prop-types';
|
||||
import { withApproveUsername } from 'coral-framework/graphql/mutations';
|
||||
import { showRejectUsernameDialog } from '../../../actions/community';
|
||||
import {
|
||||
showRejectUsernameDialog,
|
||||
setIndicatorTrack,
|
||||
} from '../../../actions/community';
|
||||
import { viewUserDetail } from '../../../actions/userDetail';
|
||||
import { getDefinitionName } from 'coral-framework/utils';
|
||||
import { appendNewNodes } from 'plugin-api/beta/client/utils';
|
||||
import update from 'immutability-helper';
|
||||
import { handleFlaggedUsernameChange } from '../graphql';
|
||||
import { handleFlaggedAccountsChange } from '../graphql';
|
||||
import { notify } from 'coral-framework/actions/notification';
|
||||
import { isFlaggedUserDangling } from '../utils';
|
||||
import t from 'coral-framework/services/i18n';
|
||||
@@ -50,7 +53,7 @@ class FlaggedAccountsContainer extends Component {
|
||||
prev,
|
||||
{ subscriptionData: { data: { usernameFlagged: user } } }
|
||||
) => {
|
||||
return handleFlaggedUsernameChange(prev, user, () => {
|
||||
return handleFlaggedAccountsChange(prev, user, () => {
|
||||
const msg = t(
|
||||
'flagged_usernames.notify_flagged',
|
||||
whoFlagged(user),
|
||||
@@ -66,7 +69,7 @@ class FlaggedAccountsContainer extends Component {
|
||||
prev,
|
||||
{ subscriptionData: { data: { usernameApproved: user } } }
|
||||
) => {
|
||||
return handleFlaggedUsernameChange(prev, user, () => {
|
||||
return handleFlaggedAccountsChange(prev, user, () => {
|
||||
const msg = t(
|
||||
'flagged_usernames.notify_approved',
|
||||
whoChangedTheStatus(user.state.status.username),
|
||||
@@ -82,7 +85,7 @@ class FlaggedAccountsContainer extends Component {
|
||||
prev,
|
||||
{ subscriptionData: { data: { usernameRejected: user } } }
|
||||
) => {
|
||||
return handleFlaggedUsernameChange(prev, user, () => {
|
||||
return handleFlaggedAccountsChange(prev, user, () => {
|
||||
const msg = t(
|
||||
'flagged_usernames.notify_rejected',
|
||||
whoChangedTheStatus(user.state.status.username),
|
||||
@@ -102,7 +105,7 @@ class FlaggedAccountsContainer extends Component {
|
||||
},
|
||||
}
|
||||
) => {
|
||||
return handleFlaggedUsernameChange(prev, user, () => {
|
||||
return handleFlaggedAccountsChange(prev, user, () => {
|
||||
const msg = t(
|
||||
'flagged_usernames.notify_changed',
|
||||
previousUsername,
|
||||
@@ -125,10 +128,14 @@ class FlaggedAccountsContainer extends Component {
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
// Stop activity indicator tracking, as we'll handle it here.
|
||||
this.props.setIndicatorTrack(false);
|
||||
this.subscribeToUpdates();
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
// Restart activity indicator tracking.
|
||||
this.props.setIndicatorTrack(true);
|
||||
this.unsubscribe();
|
||||
}
|
||||
|
||||
@@ -197,6 +204,7 @@ FlaggedAccountsContainer.propTypes = {
|
||||
approveUsername: PropTypes.func,
|
||||
data: PropTypes.object,
|
||||
root: PropTypes.object,
|
||||
setIndicatorTrack: PropTypes.func,
|
||||
};
|
||||
|
||||
const LOAD_MORE_QUERY = gql`
|
||||
@@ -288,6 +296,7 @@ const mapDispatchToProps = dispatch =>
|
||||
showRejectUsernameDialog,
|
||||
viewUserDetail,
|
||||
notify,
|
||||
setIndicatorTrack,
|
||||
},
|
||||
dispatch
|
||||
);
|
||||
|
||||
@@ -1,24 +1,164 @@
|
||||
import React, { Component } from 'react';
|
||||
import { compose, gql } from 'react-apollo';
|
||||
import Indicator from '../../../components/Indicator';
|
||||
import { withFragments } from 'plugin-api/beta/client/hocs';
|
||||
import { branch, renderNothing } from 'recompose';
|
||||
import { handleIndicatorChange } from '../graphql';
|
||||
import PropTypes from 'prop-types';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
const hideIfNoData = hasNoData => branch(hasNoData, renderNothing);
|
||||
class IndicatorContainer extends Component {
|
||||
subscriptions = [];
|
||||
|
||||
subscribeToUpdates() {
|
||||
const parameters = [
|
||||
{
|
||||
document: USERNAME_FLAGGED_SUBSCRIPTION,
|
||||
updateQuery: (
|
||||
prev,
|
||||
{ subscriptionData: { data: { usernameFlagged: user } } }
|
||||
) => {
|
||||
return handleIndicatorChange(prev, user);
|
||||
},
|
||||
},
|
||||
{
|
||||
document: USERNAME_APPROVED_SUBSCRIPTION,
|
||||
updateQuery: (
|
||||
prev,
|
||||
{ subscriptionData: { data: { usernameApproved: user } } }
|
||||
) => {
|
||||
return handleIndicatorChange(prev, user);
|
||||
},
|
||||
},
|
||||
{
|
||||
document: USERNAME_REJECTED_SUBSCRIPTION,
|
||||
updateQuery: (
|
||||
prev,
|
||||
{ subscriptionData: { data: { usernameRejected: user } } }
|
||||
) => {
|
||||
return handleIndicatorChange(prev, user);
|
||||
},
|
||||
},
|
||||
{
|
||||
document: USERNAME_CHANGED_SUBSCRIPTION,
|
||||
updateQuery: (
|
||||
prev,
|
||||
{ subscriptionData: { data: { usernameChanged: { user } } } }
|
||||
) => {
|
||||
return handleIndicatorChange(prev, user);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
this.subscriptions = parameters.map(param =>
|
||||
this.props.data.subscribeToMore(param)
|
||||
);
|
||||
}
|
||||
|
||||
unsubscribe() {
|
||||
this.subscriptions.forEach(unsubscribe => unsubscribe());
|
||||
this.subscriptions = [];
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
if (this.props.track) {
|
||||
this.subscribeToUpdates();
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.unsubscribe();
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
if (!this.props.track && nextProps.track) {
|
||||
this.subscribeToUpdates();
|
||||
}
|
||||
if (this.props.track && !nextProps.track) {
|
||||
this.unsubscribe();
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
if (!this.props.root || !this.props.root.flaggedUsernamesCount) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return <Indicator />;
|
||||
}
|
||||
}
|
||||
|
||||
IndicatorContainer.propTypes = {
|
||||
data: PropTypes.object,
|
||||
root: PropTypes.object,
|
||||
track: PropTypes.bool,
|
||||
};
|
||||
|
||||
const fields = `
|
||||
state {
|
||||
status {
|
||||
username {
|
||||
status
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const USERNAME_FLAGGED_SUBSCRIPTION = gql`
|
||||
subscription TalkAdmin_CommunityIndicator_UsernameFlagged {
|
||||
usernameFlagged {
|
||||
${fields}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const USERNAME_APPROVED_SUBSCRIPTION = gql`
|
||||
subscription TalkAdmin_ComunityIndicator_UsernameApproved {
|
||||
usernameApproved {
|
||||
${fields}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const USERNAME_REJECTED_SUBSCRIPTION = gql`
|
||||
subscription TalkAdmin_CommunityIndicator_UsernameRejected {
|
||||
usernameRejected {
|
||||
${fields}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const USERNAME_CHANGED_SUBSCRIPTION = gql`
|
||||
subscription TalkAdmin_ComunityIndicator_UsernameChanged {
|
||||
usernameChanged {
|
||||
previousUsername
|
||||
user {
|
||||
${fields}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
track: state.community.indicatorTrack,
|
||||
});
|
||||
|
||||
const enhance = compose(
|
||||
connect(mapStateToProps),
|
||||
withFragments({
|
||||
root: gql`
|
||||
fragment TalkAdmin_Community_Indicator_root on RootQuery {
|
||||
fragment TalkAdmin_CommunityIndicator_root on RootQuery {
|
||||
flaggedUsernamesCount: userCount(
|
||||
query: {
|
||||
action_type: FLAG
|
||||
state: { status: { username: [SET, CHANGED] } }
|
||||
}
|
||||
)
|
||||
me {
|
||||
id
|
||||
}
|
||||
}
|
||||
`,
|
||||
}),
|
||||
hideIfNoData(props => !props.root.flaggedUsernamesCount)
|
||||
})
|
||||
);
|
||||
|
||||
export default enhance(Indicator);
|
||||
export default enhance(IndicatorContainer);
|
||||
|
||||
@@ -49,13 +49,13 @@ function decrementFlaggedUserCount(root) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Assimilate flagged user changes into current store.
|
||||
* Assimilate flagged acount changes into current store.
|
||||
* @param {Object} root current state of the store
|
||||
* @param {Object} user user that was changed
|
||||
* @param {function} notify callback to show notification
|
||||
* @return {Object} next state of the store
|
||||
*/
|
||||
export function handleFlaggedUsernameChange(root, user, notify) {
|
||||
export function handleFlaggedAccountsChange(root, user, notify) {
|
||||
if (user.state.status.username.status !== 'SET') {
|
||||
// Check if change came from current user, if so ignore it.
|
||||
const lastChange =
|
||||
@@ -87,7 +87,7 @@ export function handleFlaggedUsernameChange(root, user, notify) {
|
||||
break;
|
||||
case 'APPROVED':
|
||||
case 'REJECTED':
|
||||
return root;
|
||||
return decrementFlaggedUserCount(root);
|
||||
default:
|
||||
}
|
||||
}
|
||||
@@ -105,3 +105,21 @@ export function handleFlaggedUsernameChange(root, user, notify) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Track indicator status
|
||||
* @param {Object} root current state of the store
|
||||
* @param {Object} user user that was changed
|
||||
* @return {Object} next state of the store
|
||||
*/
|
||||
export function handleIndicatorChange(root, user) {
|
||||
switch (user.state.status.username.status) {
|
||||
case 'SET':
|
||||
case 'CHANGED':
|
||||
return incrementFlaggedUserCount(root);
|
||||
case 'APPROVED':
|
||||
case 'REJECTED':
|
||||
return decrementFlaggedUserCount(root);
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user