mirror of
https://github.com/wassname/talk.git
synced 2026-07-14 11:18:50 +08:00
Prompting user to update name when banned.
This commit is contained in:
@@ -11,6 +11,7 @@ const {fetchAssetSuccess} = assetActions;
|
||||
|
||||
import {queryStream} from 'coral-framework/graphql/queries';
|
||||
import {postComment, postAction, deleteAction} from 'coral-framework/graphql/mutations';
|
||||
import {editName} from 'coral-framework/actions/user';
|
||||
import {Notification, notificationActions, authActions, assetActions, pym} from 'coral-framework';
|
||||
|
||||
import Stream from './Stream';
|
||||
@@ -123,6 +124,7 @@ class Embed extends Component {
|
||||
<RestrictedContent restricted={banned} restrictedComp={
|
||||
<SuspendedAccount
|
||||
canEditName={user && user.canEditName}
|
||||
editName={this.props.editName}
|
||||
/>
|
||||
}>
|
||||
{
|
||||
@@ -200,6 +202,7 @@ const mapDispatchToProps = dispatch => ({
|
||||
loadAsset: (asset) => dispatch(fetchAssetSuccess(asset)),
|
||||
addNotification: (type, text) => dispatch(addNotification(type, text)),
|
||||
clearNotification: () => dispatch(clearNotification()),
|
||||
editName: (displayName) => dispatch(editName(displayName)),
|
||||
showSignInDialog: (offset) => dispatch(showSignInDialog(offset)),
|
||||
logout: () => dispatch(logout()),
|
||||
dispatch: d => dispatch(d)
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import * as actions from '../constants/user';
|
||||
import {addNotification} from '../actions/notification';
|
||||
import coralApi from '../helpers/response';
|
||||
|
||||
@@ -6,16 +5,9 @@ import I18n from 'coral-framework/modules/i18n/i18n';
|
||||
import translations from './../translations';
|
||||
const lang = new I18n(translations);
|
||||
|
||||
const saveBioRequest = () => ({type: actions.SAVE_BIO_REQUEST});
|
||||
const saveBioSuccess = settings => ({type: actions.SAVE_BIO_SUCCESS, settings});
|
||||
const saveBioFailure = error => ({type: actions.SAVE_BIO_FAILURE, error});
|
||||
|
||||
export const saveBio = (user_id, formData) => dispatch => {
|
||||
dispatch(saveBioRequest());
|
||||
coralApi('/account/settings', {method: 'PUT', body: formData})
|
||||
export const editName = (displayName) => (dispatch) => {
|
||||
return coralApi('/account/displayname', {method: 'PUT', body: {displayName}})
|
||||
.then(() => {
|
||||
dispatch(addNotification('success', lang.t('successBioUpdate')));
|
||||
dispatch(saveBioSuccess(formData));
|
||||
})
|
||||
.catch(error => dispatch(saveBioFailure(error)));
|
||||
dispatch(addNotification('success', lang.t('successNameUpdate')));
|
||||
});
|
||||
};
|
||||
|
||||
@@ -2,3 +2,13 @@
|
||||
background: #D8D8D8;
|
||||
padding: 25px;
|
||||
}
|
||||
|
||||
.editNameInput {
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.alert {
|
||||
margin-top: 10px;
|
||||
color: #B71C1C;
|
||||
}
|
||||
|
||||
@@ -1,15 +1,79 @@
|
||||
import React from 'react';
|
||||
import React, {Component, PropTypes} from 'react';
|
||||
import I18n from 'coral-framework/modules/i18n/i18n';
|
||||
import translations from 'coral-framework/translations.json';
|
||||
const lang = new I18n(translations);
|
||||
import styles from './RestrictedContent.css';
|
||||
import {Button} from 'coral-ui';
|
||||
import validate from '../helpers/validate';
|
||||
|
||||
export default ({canEditName}) => (
|
||||
<div className={styles.message}>
|
||||
<span>{
|
||||
class SuspendedAccount extends Component {
|
||||
|
||||
static propTypes = {
|
||||
canEditName: PropTypes.bool,
|
||||
editName: PropTypes.func.isRequired
|
||||
}
|
||||
|
||||
state = {
|
||||
displayName: '',
|
||||
alert: ''
|
||||
}
|
||||
|
||||
onSubmitClick = (e) => {
|
||||
const {editName} = this.props;
|
||||
const {displayName} = this.state;
|
||||
e.preventDefault();
|
||||
if (validate.displayName(displayName)) {
|
||||
editName(displayName)
|
||||
.then(() => window.reload())
|
||||
.catch((error) => {
|
||||
this.setState({alert: lang.t(`error.${error.message}`)});
|
||||
});
|
||||
} else {
|
||||
this.setState({alert: lang.t('editName.error')});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
render () {
|
||||
const {canEditName} = this.props;
|
||||
const {displayName, alert} = this.state;
|
||||
|
||||
return <div className={styles.message}>
|
||||
<span>{
|
||||
canEditName ?
|
||||
lang.t('editName.msg')
|
||||
: lang.t('bannedAccountMsg')
|
||||
}</span>
|
||||
{
|
||||
canEditName ?
|
||||
lang.t('editNameMsg')
|
||||
: lang.t('bannedAccountMsg')
|
||||
}</span>
|
||||
</div>
|
||||
);
|
||||
<div>
|
||||
<div className={styles.alert}>
|
||||
{alert}
|
||||
</div>
|
||||
<label
|
||||
htmlFor='displayName'
|
||||
className="screen-reader-text"
|
||||
aria-hidden={true}>
|
||||
{lang.t('editName.label')}
|
||||
</label>
|
||||
<input
|
||||
type='text'
|
||||
className={styles.editNameInput}
|
||||
value={displayName}
|
||||
placeholder={lang.t('editName.label')}
|
||||
id='displayName'
|
||||
onChange={(e) => this.setState({displayName: e.target.value})}
|
||||
rows={3}/><br/>
|
||||
<Button
|
||||
onClick={this.onSubmitClick}>
|
||||
{
|
||||
lang.t('editName.button')
|
||||
}
|
||||
</Button>
|
||||
</div> : null
|
||||
}
|
||||
</div>;
|
||||
}
|
||||
}
|
||||
|
||||
export default SuspendedAccount;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
export const SAVE_BIO_REQUEST = 'SAVE_BIO_REQUEST';
|
||||
export const SAVE_BIO_SUCCESS = 'SAVE_BIO_SUCCESS';
|
||||
export const SAVE_BIO_FAILURE = 'SAVE_BIO_FAILURE';
|
||||
export const EDIT_NAME_REQUEST = 'EDIT_NAME_REQUEST';
|
||||
export const EDIT_NAME_SUCCESS = 'EDIT_NAME_SUCCESS';
|
||||
export const EDIT_NAME_FAILURE = 'EDIT_NAME_FAILURE';
|
||||
export const COMMENTS_BY_USER_REQUEST = 'COMMENTS_BY_USER_REQUEST';
|
||||
export const COMMENTS_BY_USER_SUCCESS = 'COMMENTS_BY_USER_SUCCESS';
|
||||
export const COMMENTS_BY_USER_FAILURE = 'COMMENTS_BY_USER_FAILURE';
|
||||
|
||||
@@ -1,10 +1,15 @@
|
||||
{
|
||||
"en": {
|
||||
"successUpdateSettings": "The changes you have made have been applied to the comment stream on this article",
|
||||
"successBioUpdate": "Your Bio has been updated",
|
||||
"successNameUpdate": "Your display name has been updated",
|
||||
"contentNotAvailable": "This content is not available",
|
||||
"bannedAccountMsg": "Your account is currently suspended. This means that you cannot Like, Flag, or write comments. Please contact moderator@fakeurl.com for more information",
|
||||
"editNameMsg": "Your account is currently suspended because your username has been deemed inappropriate. To restore your account, please enter a new username. You may contact moderator@fakeurl.com for more information.",
|
||||
"editName": {
|
||||
"msg": "Your account is currently suspended because your display name has been deemed inappropriate. To restore your account, please enter a new username. You may contact moderator@fakeurl.com for more information.",
|
||||
"label": "New Display Name",
|
||||
"button": "Submit",
|
||||
"error": "Display names can contain letters, numbers and _ only"
|
||||
},
|
||||
"error": {
|
||||
"email": "Not a valid E-Mail",
|
||||
"password": "Password must be at least 8 characters",
|
||||
|
||||
@@ -2,7 +2,6 @@ const _ = require('lodash');
|
||||
|
||||
const Comment = require('./comment');
|
||||
const Action = require('./action');
|
||||
const User = require('./user');
|
||||
|
||||
module.exports = (context) => {
|
||||
|
||||
@@ -10,7 +9,6 @@ module.exports = (context) => {
|
||||
return _.merge(...[
|
||||
Comment,
|
||||
Action,
|
||||
User,
|
||||
].map((mutators) => {
|
||||
|
||||
// Each set of mutators is a function which takes the context.
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
const UsersService = require('../../services/users');
|
||||
|
||||
/**
|
||||
* Updates a users settings.
|
||||
* @param {Object} user the user performing the request
|
||||
* @param {String} bio the new user bio
|
||||
* @return {Promise}
|
||||
*/
|
||||
const updateUserSettings = ({user}, {bio}) => {
|
||||
return UsersService.updateSettings(user.id, {bio});
|
||||
};
|
||||
|
||||
module.exports = (context) => {
|
||||
|
||||
// TODO: refactor to something that'll return an error in the event an attempt
|
||||
// is made to mutate state while not logged in. There's got to be a better way
|
||||
// to do this.
|
||||
if (context.user && context.user.can('mutation:updateUserSettings')) {
|
||||
return {
|
||||
User: {
|
||||
updateSettings: (settings) => updateUserSettings(context, settings)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
User: {
|
||||
updateSettings: () => {}
|
||||
}
|
||||
};
|
||||
};
|
||||
@@ -145,7 +145,7 @@ type Asset {
|
||||
# The scraped title of the asset.
|
||||
title: String
|
||||
|
||||
# The URL that the asset is locaed on.
|
||||
# The URL that the asset is located on.
|
||||
url: String
|
||||
|
||||
# The top level comments that are attached to the asset.
|
||||
|
||||
+1
-1
@@ -146,7 +146,7 @@ const USER_GRAPH_OPERATIONS = [
|
||||
'mutation:createComment',
|
||||
'mutation:createAction',
|
||||
'mutation:deleteAction',
|
||||
'mutation:updateUserSettings'
|
||||
'mutation:editName'
|
||||
];
|
||||
|
||||
/**
|
||||
|
||||
@@ -117,11 +117,17 @@ router.put('/password/reset', (req, res, next) => {
|
||||
|
||||
router.put('/displayname', authorization.needed(), (req, res, next) => {
|
||||
UsersService
|
||||
.editUsername(req.user.id, req.body.displayName)
|
||||
.editName(req.user.id, req.body.displayName)
|
||||
.then(() => {
|
||||
res.status(204).end();
|
||||
})
|
||||
.catch(next);
|
||||
.catch(error => {
|
||||
if (error.code === 11000) {
|
||||
next(errors.ErrDisplayTaken);
|
||||
} else {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
|
||||
@@ -59,7 +59,7 @@ router.post('/:user_id/status', authorization.needed('ADMIN'), (req, res, next)
|
||||
|
||||
router.post('/:user_id/username-enable', authorization.needed('ADMIN'), (req, res, next) => {
|
||||
UsersService
|
||||
.toggleUsernameEdit(req.params.user_id, true)
|
||||
.toggleNameEdit(req.params.user_id, true)
|
||||
.then(() => {
|
||||
res.status(204).end();
|
||||
})
|
||||
|
||||
+4
-3
@@ -619,7 +619,7 @@ module.exports = class UsersService {
|
||||
* @param {Boolean} canEditName sets whether the user can edit their name.
|
||||
* @return {Promise}
|
||||
*/
|
||||
static toggleUsernameEdit(id, canEditName) {
|
||||
static toggleNameEdit(id, canEditName) {
|
||||
return UserModel.update({id}, {
|
||||
$set: {canEditName}
|
||||
});
|
||||
@@ -631,14 +631,15 @@ module.exports = class UsersService {
|
||||
* @param {String} displayName The new displayname for the user.
|
||||
* @return {Promise}
|
||||
*/
|
||||
static editUsername(id, displayName) {
|
||||
static editName(id, displayName) {
|
||||
return UserModel.findOne({id})
|
||||
.then((user) => {
|
||||
return user.canEditName ?
|
||||
UserModel.update({id}, {
|
||||
$set: {
|
||||
displayName: displayName.toLowerCase(),
|
||||
canEditName: false
|
||||
canEditName: false,
|
||||
status: 'PENDING'
|
||||
}
|
||||
})
|
||||
: Promise.reject(new Error('Display name editing disabled for this account.'));
|
||||
|
||||
@@ -209,10 +209,10 @@ describe('services.UsersService', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('#toggleUsernameEdit', () => {
|
||||
describe('#toggleNameEdit', () => {
|
||||
it('should toggle the canEditName field', () => {
|
||||
return UsersService
|
||||
.toggleUsernameEdit(mockUsers[0].id, true)
|
||||
.toggleNameEdit(mockUsers[0].id, true)
|
||||
.then(() => UsersService.findById(mockUsers[0].id))
|
||||
.then((user) => {
|
||||
expect(user).to.have.property('canEditName', true);
|
||||
@@ -220,11 +220,11 @@ describe('services.UsersService', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('#editUsername', () => {
|
||||
describe('#editName', () => {
|
||||
it('should let the user edit their username if the proper toggle is set', () => {
|
||||
return UsersService
|
||||
.toggleUsernameEdit(mockUsers[0].id, true)
|
||||
.then(() => UsersService.editUsername(mockUsers[0].id, 'Jojo'))
|
||||
.toggleNameEdit(mockUsers[0].id, true)
|
||||
.then(() => UsersService.editName(mockUsers[0].id, 'Jojo'))
|
||||
.then(() => UsersService.findById(mockUsers[0].id))
|
||||
.then((user) => {
|
||||
expect(user).to.have.property('displayName', 'jojo');
|
||||
@@ -234,7 +234,7 @@ describe('services.UsersService', () => {
|
||||
|
||||
it('should return an error if canEditName is false', (done) => {
|
||||
UsersService
|
||||
.editUsername(mockUsers[0].id, 'Jojo')
|
||||
.editName(mockUsers[0].id, 'Jojo')
|
||||
.then(() => UsersService.findById(mockUsers[0].id))
|
||||
.then(() => {
|
||||
done(new Error('Error expected'));
|
||||
@@ -247,8 +247,8 @@ describe('services.UsersService', () => {
|
||||
|
||||
it('should return an error if the username is already taken', (done) => {
|
||||
UsersService
|
||||
.toggleUsernameEdit(mockUsers[0].id, true)
|
||||
.then(() => UsersService.editUsername(mockUsers[0].id, 'Marvel'))
|
||||
.toggleNameEdit(mockUsers[0].id, true)
|
||||
.then(() => UsersService.editName(mockUsers[0].id, 'Marvel'))
|
||||
.then(() => UsersService.findById(mockUsers[0].id))
|
||||
.then(() => {
|
||||
done(new Error('Error expected'));
|
||||
|
||||
Reference in New Issue
Block a user