Prevent duplicate challenge tasks (#11502)

* Implement atomic user challenges update

Prevents multiple concurrent requests from passing through
Fixes #11295

* Move user challenges update to separate method

* Rename challenge syncToUser to syncTasksToUser

Now that adding the challenge to user is separated, this methods main purpose is to sync the tasks

* Fix lint errors
This commit is contained in:
Carl Vuorinen
2019-12-13 15:14:57 +02:00
committed by Matteo Pagliazzi
parent bdb3cf25c1
commit cd90a281c2
4 changed files with 60 additions and 17 deletions

View File

@@ -254,19 +254,23 @@ api.joinChallenge = {
const challenge = await Challenge.findOne({ _id: req.params.challengeId }).exec();
if (!challenge) throw new NotFound(res.t('challengeNotFound'));
if (challenge.isMember(user)) throw new NotAuthorized(res.t('userAlreadyInChallenge'));
const group = await Group.getGroup({
user, groupId: challenge.group, fields: basicGroupFields, optionalMembership: true,
});
if (!group || !challenge.canJoin(user, group)) throw new NotFound(res.t('challengeNotFound'));
const addedSuccessfully = await challenge.addToUser(user);
if (!addedSuccessfully) {
throw new NotAuthorized(res.t('userAlreadyInChallenge'));
}
challenge.memberCount += 1;
addUserJoinChallengeNotification(user);
// Add all challenge's tasks to user's tasks and save the challenge
const results = await Promise.all([challenge.syncToUser(user), challenge.save()]);
const results = await Promise.all([challenge.syncTasksToUser(user), challenge.save()]);
const response = results[1].toJSON();
response.group = getChallengeGroupResponse(group);