port create challenge

This commit is contained in:
Matteo Pagliazzi
2015-12-28 12:14:56 +01:00
parent 01e2bb56df
commit ba0fb884dd
3 changed files with 97 additions and 9 deletions

View File

@@ -38,5 +38,8 @@
"groupMemberNotFound": "User not found among group's members",
"keepOrRemoveAll": "req.query.keep must be either \"keep-all\" or \"remove-all\"",
"canOnlyInviteEmailUuid": "Can only invite using uuids or emails but not both at the same time.",
"inviteMissingEmail": "Missing email address in invite."
"inviteMissingEmail": "Missing email address in invite.",
"onlyGroupLeaderChal": "Only the group leader can create challenges",
"pubChalsMinPrize": "Prize must be at least 1 Gem for public challenges.",
"cantAfford": "You can't afford this prize. Purchase more gems or lower the prize amount."
}

View File

@@ -1,9 +1,101 @@
import { authWithHeaders } from '../../middlewares/api-v3/auth';
import cron from '../../middlewares/api-v3/cron';
import { model as Challenge } from '../../models/challenge';
import { model as Group } from '../../models/group';
import {
NotFound,
NotAuthorized,
} from '../../libs/api-v3/errors';
import * as Tasks from './task';
import Q from 'q';
let api = {};
/**
* @api {post} /challenges Create a new challenge
* @apiVersion 3.0.0
* @apiName CreateChallenge
* @apiGroup Challenge
*
* @apiSuccess {object} challenge The newly created challenge
*/
api.getChallenges = {
method: 'POST',
url: '/challenges',
middlewares: [authWithHeaders(), cron],
handler (req, res, next) {
let user = res.locals.user;
req.checkBody('group', res.t('groupIdRequired')).notEmpty();
let validationErrors = req.validationErrors();
if (validationErrors) return next(validationErrors);
let groupId = req.body.group;
let prize = req.body.prize;
Group.getGroup(user, groupId, '-chat')
.then(group => {
if (!group) throw new NotFound(res.t('groupNotFound'));
if (group.leaderOnly && group.leaderOnly.challenges && group.leader !== user._id) {
throw new NotAuthorized(res.t('onlyGroupLeaderChal'));
}
if (groupId === 'habitrpg' && prize < 1) {
throw new NotAuthorized(res.t('pubChalsMinPrize'));
}
if (prize > 0) {
let groupBalance = group.balance && group.leader === user._id ? group.balance : 0;
let prizeCost = prize / 4;
if (prizeCost > user.balance + groupBalance) {
throw new NotAuthorized(res.t('cantAfford'));
}
if (groupBalance >= prizeCost) {
// Group pays for all of prize
group.balance -= prizeCost;
} else if (groupBalance > 0) {
// User pays remainder of prize cost after group
let remainder = prizeCost - group.balance;
group.balance = 0;
user.balance -= remainder;
} else {
// User pays for all of prize
user.balance -= prizeCost;
}
}
let tasks = req.body.tasks || []; // TODO validate
req.body.leader = user._id;
req.body.official = user.contributor.admin && req.body.official;
let challenge = new Challenge(Challenge.sanitize(req.body));
let toSave = tasks.map(tasks, taskToCreate => {
// TODO validate type
let task = new Tasks[taskToCreate.type](Tasks.Task.sanitizeCreate(taskToCreate));
task.challenge.id = challenge._id;
challenge.tasksOrder[`${task.type}s`].push(task._id);
return task.save();
});
toSave.unshift(challenge, group);
return Q.all(toSave);
})
.then(results => {
let savedChal = results[0];
user.challenges.push(savedChal._id); // TODO save user only after group created, so that we can account for failed validation. Revisit in other places
return savedChal.syncToUser(user) // (it also saves the user)
.then(() => res.respond(201, savedChal));
})
.catch(next);
},
};
/**
* @api {get} /challenges Get challenges for a user
* @apiVersion 3.0.0

View File

@@ -22,18 +22,11 @@ let schema = new Schema({
group: {type: String, ref: 'Group', validate: [validator.isUUID, 'Invalid uuid.'], required: true},
timestamp: {type: Date, default: Date.now, required: true}, // TODO what is this? use timestamps from plugin?
memberCount: {type: Number, default: 0},
prize: {type: Number, default: 0, required: true},
prize: {type: Number, default: 0, min: 0},
});
schema.plugin(baseModel, {
noSet: ['_id', 'memberCount', 'tasksOrder'],
toJSONTransform: function userToJSON (doc) {
// TODO fixme
// TODO this works?
doc._isMember = this._isMember;
return doc;
},
});