Add stopIgnoringUser mutation and Embed uses it

This commit is contained in:
Benjamin Goering
2017-04-11 14:19:34 -07:00
parent c59ddb72a6
commit 2656141d59
13 changed files with 168 additions and 44 deletions
+2 -11
View File
@@ -15,7 +15,7 @@ import {NEW_COMMENT_COUNT_POLL_INTERVAL} from 'coral-framework/constants/comment
import {queryStream} from 'coral-framework/graphql/queries';
import {postComment, postFlag, postLike, postDontAgree, deleteAction, addCommentTag, removeCommentTag, ignoreUser} from 'coral-framework/graphql/mutations';
import {editName, ignoreUserSuccess} from 'coral-framework/actions/user';
import {editName} from 'coral-framework/actions/user';
import {updateCountCache, viewAllComments} from 'coral-framework/actions/asset';
import {notificationActions, authActions, assetActions, pym} from 'coral-framework';
@@ -117,15 +117,6 @@ class Embed extends Component {
}
}
ignoreUser = async ({id}) => {
const {ignoreUser, dispatch} = this.props;
await ignoreUser({id});
// dispatch ignoreUserSuccess so other reducers can know about the newly
// ignored user (e.g. to hide coments by that user)
dispatch(ignoreUserSuccess({id}));
}
render () {
const {activeTab} = this.state;
const {closedAt, countCache = {}} = this.props.asset;
@@ -264,7 +255,7 @@ class Embed extends Component {
postDontAgree={this.props.postDontAgree}
addCommentTag={this.props.addCommentTag}
removeCommentTag={this.props.removeCommentTag}
ignoreUser={this.ignoreUser}
ignoreUser={this.props.ignoreUser}
loadMore={this.props.loadMore}
deleteAction={this.props.deleteAction}
showSignInDialog={this.props.showSignInDialog}
-4
View File
@@ -1,7 +1,6 @@
import {addNotification} from '../actions/notification';
import coralApi from '../helpers/response';
import * as actions from '../constants/auth';
import {IGNORE_USER_SUCCESS} from '../constants/user';
import I18n from 'coral-framework/modules/i18n/i18n';
import translations from './../translations';
@@ -20,6 +19,3 @@ export const editName = (username) => (dispatch) => {
dispatch(editUsernameFailure(lang.t(`error.${error.translation_key}`)));
});
};
// a user was successfully ignored
export const ignoreUserSuccess = ({id}) => ({type: IGNORE_USER_SUCCESS, id});
+1
View File
@@ -7,3 +7,4 @@ export const COMMENTS_BY_USER_FAILURE = 'COMMENTS_BY_USER_FAILURE';
export const LOGOUT_SUCCESS = 'LOGOUT_SUCCESS';
export const UPDATE_USERNAME = 'UPDATE_USERNAME';
export const IGNORE_USER_SUCCESS = 'IGNORE_USER_SUCCESS';
export const STOP_IGNORING_USER_SUCCESS = 'STOP_IGNORING_USER_SUCCESS';
@@ -7,6 +7,9 @@ import DELETE_ACTION from './deleteAction.graphql';
import ADD_COMMENT_TAG from './addCommentTag.graphql';
import REMOVE_COMMENT_TAG from './removeCommentTag.graphql';
import IGNORE_USER from './ignoreUser.graphql';
import STOP_IGNORING_USER from './stopIgnoringUser.graphql';
import MY_IGNORED_USERS from '../queries/myIgnoredUsers.graphql';
import commentView from '../fragments/commentView.graphql';
@@ -156,7 +159,24 @@ export const ignoreUser = graphql(IGNORE_USER, {
return mutate({
variables: {
id,
}
},
refetchQueries: [{
query: MY_IGNORED_USERS,
}]
});
}}),
});
export const stopIgnoringUser = graphql(STOP_IGNORING_USER, {
props: ({mutate}) => ({
stopIgnoringUser: ({id}) => {
return mutate({
variables: {
id,
},
refetchQueries: [{
query: MY_IGNORED_USERS,
}]
});
}}),
});
@@ -0,0 +1,7 @@
mutation stopIgnoringUser ($id: ID!) {
stopIgnoringUser(id:$id) {
errors {
translation_key
}
}
}
+9 -4
View File
@@ -39,9 +39,14 @@ export default function user (state = initialState, action) {
return state.set('myAssets', action.assets);
case actions.LOGOUT_SUCCESS:
return initialState;
case actions.IGNORE_USER_SUCCESS:
return state.updateIn(['ignoredUsers'], i => i.add(action.id));
default :
return state;
case 'APOLLO_MUTATION_RESULT':
switch (action.operationName) {
case 'ignoreUser':
return state.updateIn(['ignoredUsers'], i => i.add(action.variables.id));
case 'stopIgnoringUser':
return state.updateIn(['ignoredUsers'], i => i.delete(action.variables.id));
}
break;
}
return state;
}
@@ -1,10 +1,19 @@
import React, {Component} from 'react';
import React, {Component, PropTypes} from 'react';
import styles from './IgnoredUsers.css';
export class IgnoredUsers extends Component {
static propTypes = {
users: PropTypes.arrayOf(PropTypes.shape({
username: PropTypes.string,
id: PropTypes.string,
})).isRequired,
// accepts { id }
stopIgnoring: PropTypes.func.isRequired,
}
render() {
const {users} = this.props;
const {users, stopIgnoring} = this.props;
return (
<div>
{
@@ -15,10 +24,12 @@ export class IgnoredUsers extends Component {
<dl className={styles.ignoredUserList}>
{
users.map(({username, id}) => (
<span className={styles.ignoredUser}>
<span className={styles.ignoredUser} key={id}>
<dt key={id}>{ username }</dt>
<dd className={styles.stopListening}>
<a className={styles.link}>Stop ignoring</a>
<a
onClick={() => stopIgnoring({id})}
className={styles.link}>Stop ignoring</a>
</dd>
</span>
))
@@ -4,6 +4,7 @@ import React, {Component} from 'react';
import I18n from 'coral-framework/modules/i18n/i18n';
import {myCommentHistory, myIgnoredUsers} from 'coral-framework/graphql/queries';
import {stopIgnoringUser} from 'coral-framework/graphql/mutations';
import {link} from 'coral-framework/services/PymConnection';
import NotLoggedIn from '../components/NotLoggedIn';
@@ -31,7 +32,7 @@ class ProfileContainer extends Component {
}
render() {
const {loggedIn, asset, showSignInDialog, data, myIgnoredUsersData} = this.props;
const {loggedIn, asset, showSignInDialog, data, myIgnoredUsersData, stopIgnoringUser} = this.props;
const {me} = this.props.data;
if (!loggedIn || !me) {
@@ -60,6 +61,7 @@ class ProfileContainer extends Component {
<h3>Ignored users</h3>
<IgnoredUsers
users={myIgnoredUsersData.myIgnoredUsers}
stopIgnoring={stopIgnoringUser}
/>
</div>
)
@@ -100,4 +102,5 @@ export default compose(
connect(mapStateToProps, mapDispatchToProps),
myCommentHistory,
myIgnoredUsers,
stopIgnoringUser,
)(ProfileContainer);
+6
View File
@@ -17,12 +17,18 @@ const ignoreUser = async ({user}, userToIgnore) => {
return await UsersService.ignoreUsers(user.id, [userToIgnore.id]);
};
const stopIgnoringUser = async ({user}, userToStopIgnoring) => {
console.log('stopIgnoringUser!!');
return await UsersService.stopIgnoringUsers(user.id, [userToStopIgnoring.id]);
};
module.exports = (context) => {
let mutators = {
User: {
setUserStatus: () => Promise.reject(errors.ErrNotAuthorized),
suspendUser: () => Promise.reject(errors.ErrNotAuthorized),
ignoreUser: (action) => ignoreUser(context, action),
stopIgnoringUser: (action) => stopIgnoringUser(context, action),
}
};
+3
View File
@@ -26,6 +26,9 @@ const RootMutation = {
ignoreUser(_, {id}, {mutators: {User}}) {
return wrapResponse(null)(User.ignoreUser({id}));
},
stopIgnoringUser(_, {id}, {mutators: {User}}) {
return wrapResponse(null)(User.stopIgnoringUser({id}));
},
setCommentStatus(_, {id, status}, {mutators: {Comment}}) {
return wrapResponse(null)(Comment.setCommentStatus({id, status}));
},
+8
View File
@@ -712,6 +712,11 @@ type IgnoreUserResponse implements Response {
errors: [UserError]
}
# Response to stopIgnoringUser mutation
type StopIgnoringUserResponse implements Response {
# An array of errors relating to the mutation that occured.
errors: [UserError]
}
# All mutations for the application are defined on this object.
type RootMutation {
@@ -748,6 +753,9 @@ type RootMutation {
# Ignore comments by another user
ignoreUser(id: ID!): IgnoreUserResponse
# Stop Ignoring comments by another user
stopIgnoringUser(id: ID!): StopIgnoringUserResponse
}
################################################################################
+16
View File
@@ -854,4 +854,20 @@ module.exports = class UsersService {
}
});
}
/**
* Stop ignoring other users
* @param {String} userId the id of the user that is ignoring another users
* @param {String[]} usersToStopIgnoring Array of user IDs to stop ignoring
*/
static async stopIgnoringUsers(userId, usersToStopIgnoring) {
assert(Array.isArray(usersToStopIgnoring), 'usersToStopIgnoring is an array');
assert(usersToStopIgnoring.every(u => typeof u === 'string'), 'usersToStopIgnoring is an array of string user IDs');
await UserModel.update({id: userId}, {
$pullAll: {
ignoresUsers: usersToStopIgnoring
}
});
console.log('Mongo wrote stopIgnoringUsers', usersToStopIgnoring);
}
};
+76 -19
View File
@@ -6,30 +6,30 @@ const Context = require('../../../graph/context');
const UsersService = require('../../../services/users');
const SettingsService = require('../../../services/settings');
const ignoreUserMutation = `
mutation ignoreUser ($id: ID!) {
ignoreUser(id:$id) {
errors {
translation_key
}
}
}
`;
const getMyIgnoredUsersQuery = `
query myIgnoredUsers {
myIgnoredUsers {
id,
username
}
}
`;
describe('graph.mutations.ignoreUser', () => {
beforeEach(async () => {
await SettingsService.init();
});
const ignoreUserMutation = `
mutation ignoreUser ($id: ID!) {
ignoreUser(id:$id) {
errors {
translation_key
}
}
}
`;
const getMyIgnoredUsersQuery = `
query myIgnoredUsers {
myIgnoredUsers {
id,
username
}
}
`;
// @TODO (bengo) - test a user can't ignore themselves
it('users can ignoreUser', async () => {
const user = await UsersService.createLocalUser('usernameA@example.com', 'password', 'usernameA');
@@ -54,3 +54,60 @@ describe('graph.mutations.ignoreUser', () => {
});
});
describe('graph.mutations.stopIgnoringUser', () => {
beforeEach(async () => {
await SettingsService.init();
});
it('users can stop ignoring another user they ignore', async () => {
// We're going to ignore 2 users,
// then stopIgnoring 1 of them
// then assert myIgnoredUsers only lists the one remaining
const user = await UsersService.createLocalUser('usernameA@example.com', 'password', 'usernameA');
const usersToIgnore = await Promise.all([
UsersService.createLocalUser('usernameB@example.com', 'password', 'usernameB'),
UsersService.createLocalUser('usernameC@example.com', 'password', 'usernameC'),
]);
const context = new Context({user});
// ignore two users
const ignoreUserResponses = await Promise.all(usersToIgnore.map(u => graphql(schema, ignoreUserMutation, {}, context, {id: u.id})));
ignoreUserResponses.forEach(response => {
if (response.errors && response.errors.length) {
console.error(response.errors);
}
expect(response.errors).to.be.empty;
});
const stopIgnoringUserMutation = `
mutation stopIgnoringUser ($id: ID!) {
stopIgnoringUser(id:$id) {
errors {
translation_key
}
}
}
`;
// stop ignoring one user
const stopIgnoringUserResponse = await graphql(schema, stopIgnoringUserMutation, {}, context, {id: usersToIgnore[0].id});
if (stopIgnoringUserResponse.errors && stopIgnoringUserResponse.errors.length) {
console.error(stopIgnoringUserResponse.errors);
}
expect(stopIgnoringUserResponse.errors).to.be.empty;
// now check my ignored users
const myIgnoredUsersResponse = await graphql(schema, getMyIgnoredUsersQuery, {}, context, {});
if (myIgnoredUsersResponse.errors && myIgnoredUsersResponse.errors.length) {
console.error(myIgnoredUsersResponse.errors);
}
expect(myIgnoredUsersResponse.errors).to.be.empty;
const myIgnoredUsers = myIgnoredUsersResponse.data.myIgnoredUsers;
expect(myIgnoredUsers.length).to.equal(1);
expect(myIgnoredUsers[0].id).to.equal(usersToIgnore[1].id);
expect(myIgnoredUsers[0].username).to.equal(usersToIgnore[1].username);
});
});