Merge branch 'api-v3' into api-v3-client

This commit is contained in:
Matteo Pagliazzi
2016-04-30 16:51:15 +02:00
3261 changed files with 5070 additions and 4577 deletions
+5 -2
View File
@@ -52,7 +52,9 @@ api.list = async function(req, res, next) {
let obj = challenge.toJSON();
obj._isMember = user.challenges.indexOf(challenge._id) !== -1;
return obj;
});
// TODO Instead of populate we make a find call manually because of https://github.com/Automattic/mongoose/issues/3833
await Q.all(resChals.map((chal, index) => {
return Q.all([
@@ -195,7 +197,8 @@ api.create = async function(req, res, next){
req.body.rewards = req.body.rewards || [];
var chalTasks = req.body.habits.concat(req.body.rewards)
.concat(req.body.dailys).concat(req.body.todos);
.concat(req.body.dailys).concat(req.body.todos)
.map(v2Task => Tasks.Task.fromJSONV2(v2Task));
chalTasks = chalTasks.map(function(task) {
var newTask = new Tasks[task.type](Tasks.Task.sanitize(task));
@@ -318,7 +321,7 @@ api.selectWinner = async function(req, res, next) {
if (!challenge) return next('Challenge ' + req.params.cid + ' not found');
if (!challenge.canModify(res.locals.user)) return next(shared.i18n.t('noPermissionCloseChallenge'));
let winner = await User.findOne({_id: req.params.uid}).exec();
let winner = await User.findOne({_id: req.query.uid}).exec();
if (!winner || winner.challenges.indexOf(challenge._id) === -1) return next('Winner ' + req.query.uid + ' not found.');
// Close channel in background, some ops are run in the background without `await`ing
+8 -1
View File
@@ -676,7 +676,14 @@ api.cast = async function(req, res, next) {
if (!partyMembers) throw new NotFound(res.t('userWithIDNotFound', {userId: targetId}));
spell.cast(user, partyMembers, req);
await partyMembers.save();
if (partyMembers === user) {
await partyMembers.save();
} else {
await Q.all([
await partyMembers.save(),
await user.save(),
]);
}
}
if (party && !spell.silent) {
+2 -1
View File
@@ -83,7 +83,7 @@ api.createChallenge = {
group.challengeCount += 1;
req.body.leader = user._id;
req.body.official = user.contributor.admin && req.body.official;
req.body.official = user.contributor.admin && req.body.official ? true : false;
let challenge = new Challenge(Challenge.sanitize(req.body));
// First validate challenge so we don't save group if it's invalid (only runs sync validators)
@@ -108,6 +108,7 @@ api.createChallenge = {
type: group.type,
privacy: group.privacy,
};
res.respond(201, response);
},
};
+19 -3
View File
@@ -350,7 +350,15 @@ api.castSpell = {
if (task.challenge.id) throw new BadRequest(res.t('challengeTasksNoCast'));
spell.cast(user, task, req);
await task.save();
if (user.isModified()) {
await Q.all([
user.save(),
task.save(),
]);
} else {
await task.save();
}
res.respond(200, task);
} else if (targetType === 'self') {
spell.cast(user, null, req);
@@ -370,7 +378,8 @@ api.castSpell = {
let toSave = tasks.filter(t => t.isModified());
let isUserModified = user.isModified();
toSave.unshift(user.save());
if (isUserModified) toSave.unshift(user.save());
let saved = await Q.all(toSave);
let response = {
@@ -403,7 +412,14 @@ api.castSpell = {
if (!partyMembers) throw new NotFound(res.t('userWithIDNotFound', {userId: targetId}));
spell.cast(user, partyMembers, req);
await partyMembers.save();
if (user.isModified()) {
await Q.all([
user.save(),
partyMembers.save(),
]);
} else {
await partyMembers.save();
}
}
res.respond(200, partyMembers);
+5 -1
View File
@@ -23,7 +23,10 @@ let schema = new Schema({
leader: {type: String, ref: 'User', validate: [validator.isUUID, 'Invalid uuid.'], required: true},
group: {type: String, ref: 'Group', validate: [validator.isUUID, 'Invalid uuid.'], required: true},
memberCount: {type: Number, default: 1},
prize: {type: Number, default: 0, min: 0}, // TODO no update?
prize: {type: Number, default: 0, min: 0},
}, {
strict: true,
minimize: false, // So empty objects are returned
});
schema.plugin(baseModel, {
@@ -153,6 +156,7 @@ schema.methods.addTasks = async function challengeAddTasks (tasks) {
// Sync each user sequentially
// TODO are we sure it's the best solution?
// use bulk ops? http://stackoverflow.com/questions/16726330/mongoose-mongodb-batch-insert
for (let memberId of membersIds) {
let updateTasksOrderQ = {$push: {}};
let toSave = [];
+3
View File
@@ -13,6 +13,9 @@ import {
export let schema = new mongoose.Schema({
event: {type: String, enum: ['wondercon', 'google_6mo']},
user: {type: String, ref: 'User'},
}, {
strict: true,
minimize: false, // So empty objects are returned
});
schema.plugin(baseModel, {
@@ -15,6 +15,9 @@ export let schema = new mongoose.Schema({
lowercase: true, // TODO migrate existing to lowerCase
validator: [validator.isEmail, 'Invalid email.'],
},
}, {
strict: true,
minimize: false, // So empty objects are returned
});
export let model = mongoose.model('EmailUnsubscription', schema);
+18 -33
View File
@@ -91,21 +91,6 @@ schema.statics.sanitizeUpdate = function sanitizeUpdate (updateObj) {
// Basic fields to fetch for populating a group info
export let basicFields = 'name type privacy';
// TODO migration
/**
* Derby duplicated stuff. This is a temporary solution, once we're completely off derby we'll run an mongo migration
* to remove duplicates, then take these fucntions out
*/
/* function removeDuplicates(doc){
// Remove duplicate members
if (doc.members) {
var uniqMembers = _.uniq(doc.members);
if (uniqMembers.length != doc.members.length) {
doc.members = uniqMembers;
}
}
}*/
// TODO test
schema.pre('remove', true, async function preRemoveGroup (next, done) {
next();
@@ -646,32 +631,32 @@ schema.methods.leave = async function leaveGroup (user, keep = 'keep-all') {
let promises = [];
// If user is the last one in group and group is private, delete it
if (group.memberCount <= 1 && group.privacy === 'private') {
return await group.remove();
}
// otherwise just remove a member TODO create User.methods.removeFromGroup?
// remove the group from the user's groups
if (group.type === 'guild') {
promises.push(User.update({_id: user._id}, {$pull: {guilds: group._id}}).exec());
} else {
promises.push(User.update({_id: user._id}, {$set: {party: {}}}).exec());
}
// If the leader is leaving (or if the leader previously left, and this wasn't accounted for)
let update = {
$inc: {memberCount: -1},
};
// If user is the last one in group and group is private, delete it
if (group.memberCount <= 1 && group.privacy === 'private') {
return await group.remove();
} else { // otherwise If the leader is leaving (or if the leader previously left, and this wasn't accounted for)
let update = {
$inc: {memberCount: -1},
};
if (group.leader === user._id) {
let query = group.type === 'party' ? {'party._id': group._id} : {guilds: group._id};
query._id = {$ne: user._id};
let seniorMember = await User.findOne(query).select('_id').exec();
if (group.leader === user._id) {
let query = group.type === 'party' ? {'party._id': group._id} : {guilds: group._id};
query._id = {$ne: user._id};
let seniorMember = await User.findOne(query).select('_id').exec();
// could be missing in case of public guild (that can have 0 members) with 1 member who is leaving
if (seniorMember) update.$set = {leader: seniorMember._id};
// could be missing in case of public guild (that can have 0 members) with 1 member who is leaving
if (seniorMember) update.$set = {leader: seniorMember._id};
}
promises.push(group.update(update).exec());
}
promises.push(group.update(update).exec());
firebase.removeUserFromGroup(group._id, user._id);
return Q.all(promises);
@@ -745,7 +730,7 @@ if (!nconf.get('IS_TEST')) {
new model({ // eslint-disable-line babel/new-cap
_id: TAVERN_ID,
leader: '7bde7864-ebc5-4ee2-a4b7-1070d464cdb0', // Siena Leslie
name: 'HabitRPG',
name: 'Tavern',
type: 'guild',
privacy: 'public',
}).save();
+1 -1
View File
@@ -7,8 +7,8 @@ export let schema = new Schema({
name: {type: String, required: true},
challenge: {type: String},
}, {
minimize: true, // So empty objects are returned
strict: true,
minimize: false, // So empty objects are returned
});
schema.plugin(baseModel, {
+4 -4
View File
@@ -115,10 +115,10 @@ export let schema = new Schema({
},
balance: {type: Number, default: 0},
// Not saved on the user TODO remove with migration
/* filters: {type: Schema.Types.Mixed, default: () => {
// Not saved on the user right now
filters: {type: Schema.Types.Mixed, default: () => {
return {};
}}, */
}},
purchased: {
ads: {type: Boolean, default: false},
@@ -524,7 +524,7 @@ export let schema = new Schema({
},
}, {
strict: true,
minimize: false, // So empty objects are returned TODO make sure it's in every model
minimize: false, // So empty objects are returned
});
schema.plugin(baseModel, {
+1 -2
View File
@@ -4,8 +4,7 @@ var router = express.Router();
var _ = require('lodash');
var locals = require('../middlewares/api-v2/locals');
var i18n = require('../libs/api-v2/i18n');
var Remarkable = require('remarkable');
var md = new Remarkable({
var md = require('markdown-it')({
html: true,
});