Adding displayname editing and appropriate toggle.

This commit is contained in:
David Jay
2017-02-01 15:55:33 -05:00
parent 37975574ea
commit b2430eaf60
9 changed files with 185 additions and 30 deletions
@@ -36,7 +36,7 @@ class SuspendUserModal extends Component {
}
componentDidMount() {
const about = this.props.actionType === 'flag_bio' ? lang.t('suspenduser.bio') : lang.t('suspenduser.username');
const about = lang.t('suspenduser.username');
this.setState({email: lang.t('suspenduser.email', about)});
}
-3
View File
@@ -8,9 +8,6 @@ const RootMutation = {
deleteAction(_, {id}, {mutators: {Action}}) {
return Action.delete({id});
},
updateUserSettings(_, {settings}, {mutators: {User}}) {
return User.updateSettings(settings);
}
};
module.exports = RootMutation;
+3 -15
View File
@@ -10,11 +10,6 @@ enum SORT_ORDER {
# Date represented as an ISO8601 string.
scalar Date
type UserSettings {
# bio of the user.
bio: String
}
input CommentsQuery {
# current status of a comment.
statuses: [COMMENT_STATUS]
@@ -22,7 +17,7 @@ input CommentsQuery {
# asset that a comment is on.
asset_id: ID
# the parent of the comment that we want to retrive.
# the parent of the comment that we want to retrieve.
parent_id: ID
# comments returned will only be ones which have at least one action of this
@@ -61,8 +56,8 @@ type User {
# the current roles of the user.
roles: [USER_ROLES]
# settings for a user.
settings: UserSettings
# determines whether the user can edit their username
canEditName: Boolean
# returns all comments based on a query.
comments(query: CommentsQuery): [Comment]
@@ -205,11 +200,6 @@ input CreateActionInput {
item_id: ID!
}
input UpdateUserSettingsInput {
# user bio
bio: String!
}
type RootMutation {
# creates a comment on the asset.
createComment(asset_id: ID!, parent_id: ID, body: String!): Comment
@@ -220,8 +210,6 @@ type RootMutation {
# delete an action based on the action id.
deleteAction(id: ID!): Boolean
# updates a user's settings, it will return if the query was successful.
updateUserSettings(settings: UpdateUserSettingsInput!): Boolean
}
schema {
+6
View File
@@ -96,6 +96,12 @@ const UserSchema = new mongoose.Schema({
default: 'ACTIVE'
},
// Determines whether the user can edit their username.
canEditName: {
type: Boolean,
default: false
},
// User's settings
settings: {
bio: {
+3 -10
View File
@@ -115,20 +115,13 @@ router.put('/password/reset', (req, res, next) => {
});
});
router.put('/settings', authorization.needed(), (req, res, next) => {
const {
bio
} = req.body;
router.put('/displayname', authorization.needed(), (req, res, next) => {
UsersService
.updateSettings(req.user.id, {bio})
.editUsername(req.user.id, req.body.displayName)
.then(() => {
res.status(204).end();
})
.catch((err) => {
next(err);
});
.catch(next);
});
module.exports = router;
+10 -1
View File
@@ -57,7 +57,16 @@ router.post('/:user_id/status', authorization.needed('ADMIN'), (req, res, next)
.catch(next);
});
router.post('/:user_id/email', 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)
.then(() => {
res.status(204).end();
})
.catch(next);
});
router.post('/:user_id/email', authorization.needed('ADMIN'), (req, res, next) => {
UsersService.findById(req.params.user_id)
.then(user => {
let localProfile = user.profiles.find((profile) => profile.provider === 'local');
+31
View File
@@ -613,4 +613,35 @@ module.exports = class UsersService {
return UserModel.find({status: 'PENDING'});
}
/**
* Gives the user the ability to edit their username.
* @param {String} id the id of the user to be toggled.
* @param {Boolean} canEditName sets whether the user can edit their name.
* @return {Promise}
*/
static toggleUsernameEdit(id, canEditName) {
return UserModel.update({id}, {
$set: {canEditName}
});
}
/**
* Gives the user the ability to edit their username.
* @param {String} id the id of the user to be enabled.
* @param {String} displayName The new displayname for the user.
* @return {Promise}
*/
static editUsername(id, displayName) {
return UserModel.findOne({id})
.then((user) => {
return user.canEditName ?
UserModel.update({id}, {
$set: {
displayName: displayName.toLowerCase(),
canEditName: false
}
})
: Promise.reject(new Error('Display name editing disabled for this account.'));
});
}
};
+79
View File
@@ -83,3 +83,82 @@ describe('/api/v1/users/:user_id/actions', () => {
});
});
});
describe('/api/v1/users/:user_id/username-enable', () => {
let mockUser;
beforeEach(() => SettingsService.init(settings).then(() => {
return UsersService.createLocalUser('ana@gmail.com', '123321123', 'Ana');
})
.then((user) => {
mockUser = user;
}));
describe('#post', () => {
it('it should enable a user to edit their username', () => {
return chai.request(app)
.post(`/api/v1/users/${mockUser.id}/username-enable`)
.set(passport.inject({id: '456', roles: ['ADMIN']}))
.then((res) => {
expect(res).to.have.status(204);
});
});
});
});
describe('/api/v1/account/displayname', () => {
let mockUser;
beforeEach(() => SettingsService.init(settings).then(() => {
return UsersService.createLocalUser('ana@gmail.com', '123321123', 'Ana');
})
.then((user) => {
mockUser = user;
}));
describe('#post', () => {
it('it should enable a user to edit their username if canEditName is enabled', () => {
return chai.request(app)
.post(`/api/v1/users/${mockUser.id}/username-enable`)
.set(passport.inject({id: '456', roles: ['ADMIN']}))
.then(() => chai.request(app)
.put('/api/v1/account/displayname')
.set(passport.inject({id: mockUser.id, roles: []}))
.send({displayName: 'MojoJojo'}))
.then((res) => {
expect(res).to.have.status(204);
});
});
it('it should return an error if the wrong user tries to edit a username', (done) => {
chai.request(app)
.post(`/api/v1/users/${mockUser.id}/username-enable`)
.set(passport.inject({id: '456', roles: ['ADMIN']}))
.then(() => chai.request(app)
.put('/api/v1/account/displayname')
.set(passport.inject({id: 'wrongid', roles: []}))
.send({displayName: 'MojoJojo'}))
.then(() => {
done(new Error('Exected Error'));
})
.catch((err) => {
expect(err).to.be.truthy;
done();
});
});
it('it should return an error when the user tries to edit their username if canEditName is disabled', (done) => {
chai.request(app)
.put('/api/v1/account/displayname')
.set(passport.inject({id: mockUser.id, roles: []}))
.send({username: 'MojoJojo'})
.then(() => {
done(new Error('Exected Error'));
})
.catch((err) => {
expect(err).to.be.truthy;
done();
});
});
});
});
+52
View File
@@ -208,4 +208,56 @@ describe('services.UsersService', () => {
});
});
});
describe('#toggleUsernameEdit', () => {
it('should toggle the canEditName field', () => {
return UsersService
.toggleUsernameEdit(mockUsers[0].id, true)
.then(() => UsersService.findById(mockUsers[0].id))
.then((user) => {
expect(user).to.have.property('canEditName', true);
});
});
});
describe('#editUsername', () => {
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'))
.then(() => UsersService.findById(mockUsers[0].id))
.then((user) => {
expect(user).to.have.property('displayName', 'jojo');
expect(user).to.have.property('canEditName', false);
});
});
it('should return an error if canEditName is false', (done) => {
UsersService
.editUsername(mockUsers[0].id, 'Jojo')
.then(() => UsersService.findById(mockUsers[0].id))
.then(() => {
done(new Error('Error expected'));
})
.catch((err) => {
expect(err).to.be.truthy;
done();
});
});
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'))
.then(() => UsersService.findById(mockUsers[0].id))
.then(() => {
done(new Error('Error expected'));
})
.catch((err) => {
expect(err).to.be.truthy;
done();
});
});
});
});