mirror of
https://github.com/wassname/talk.git
synced 2026-07-30 12:40:41 +08:00
Adding displayname editing and appropriate toggle.
This commit is contained in:
@@ -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)});
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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 {
|
||||
|
||||
@@ -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: {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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.'));
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user