v3 adapt v2: port tags, cast, cron, deletUser and removeMember. Fix a few bugs in v3

This commit is contained in:
Matteo Pagliazzi
2016-04-06 19:28:43 +02:00
parent 08239345b5
commit b431b02012
25 changed files with 409 additions and 218 deletions

View File

@@ -1,5 +1,7 @@
import uuid from '../libs/uuid';
// TODO used only in client, move there?
module.exports = function(user, req, cb) {
if (user.tags == null) {
user.tags = [];

View File

@@ -1,6 +1,8 @@
import i18n from '../i18n';
import _ from 'lodash';
// TODO used only in client, move there?
module.exports = function(user, req, cb) {
var i, tag, tid;
tid = req.params.id;

View File

@@ -1,5 +1,7 @@
import i18n from '../i18n';
// TODO used only in client, move there?
module.exports = function(user, req, cb) {
var i, ref, task;
task = user.tasks[(ref = req.params) != null ? ref.id : void 0];

View File

@@ -1,6 +1,8 @@
import _ from 'lodash';
import i18n from '../i18n';
// TODO used only in client, move there?
module.exports = function(user, req, cb) {
var i, tid;
tid = req.params.id;

View File

@@ -1,3 +1,5 @@
// TODO used only in client, move there?
module.exports = function(user, req, cb) {
return typeof cb === "function" ? cb(null, user.tags) : void 0;
};

View File

@@ -1,3 +1,5 @@
// TODO used only in client, move there?
module.exports = function(user, req, cb) {
var from, ref, to;
ref = req.query, to = ref.to, from = ref.from;

View File

@@ -1,6 +1,8 @@
import i18n from '../i18n';
import preenTodos from '../libs/preenTodos';
// TODO used only in client, move there?
module.exports = function(user, req, cb) {
var from, id, movedTask, preenedTasks, ref, task, tasks, to;
id = req.params.id;

View File

@@ -1,6 +1,8 @@
import i18n from '../i18n';
import _ from 'lodash';
// TODO used only in client, move there?
module.exports = function(user, req, cb) {
var i, tid;
tid = req.params.id;

View File

@@ -3,7 +3,7 @@ import {
translate as t,
} from '../../../helpers/api-integration/v2';
xdescribe('POST /groups/:id/removeMember', () => {
describe('POST /groups/:id/removeMember', () => {
context('user is not member of the group', () => {
it('returns an error');
});

View File

@@ -10,7 +10,7 @@ import {
} from 'lodash';
import Q from 'q';
xdescribe('DELETE /user', () => {
describe('DELETE /user', () => {
let user;
beforeEach(async () => {

View File

@@ -2,7 +2,7 @@ import {
generateUser,
} from '../../../helpers/api-integration/v2';
xdescribe('GET /user/tags', () => {
describe('GET /user/tags', () => {
let user;
beforeEach(async () => {

View File

@@ -3,7 +3,7 @@ import {
translate as t,
} from '../../../helpers/api-integration/v2';
xdescribe('GET /user/tags/id', () => {
describe('GET /user/tags/id', () => {
let user;
beforeEach(async () => {

View File

@@ -5,7 +5,7 @@ import {
import { each } from 'lodash';
xdescribe('POST /user/batch-update', () => {
describe('POST /user/batch-update', () => {
let user;
beforeEach(async () => {

View File

@@ -12,6 +12,8 @@ var Q = require('q');
var utils = require('./../../libs/api-v2/utils');
var shared = require('../../../../common');
import { removeFromArray } from '../../libs/api-v3/collectionManipulators';
import {
model as User,
} from './../../models/user';
@@ -786,8 +788,13 @@ api.removeMember = function(req, res, next){
return res.status(401).json({err: "You cannot remove yourself!"});
}
if(_.contains(group.members, uuid)){
var update = {$pull:{members:uuid}};
User.findById(uuid, function(err, removedUser){
if (err) return next(err);
let isMember = group._id === removedUser.party._id || _.contains(removedUser.guilds, group._id);
let isInvited = group._id === removedUser.invitations.party._id || !!_.find(removedUser.invitations.guilds, {id: group._id});
if(isMember){
var update = {};
if (group.quest && group.quest.leader === uuid) {
update['$set'] = {
quest: { key: null, leader: null }
@@ -801,13 +808,15 @@ api.removeMember = function(req, res, next){
Group.update({_id:group._id},update, function(err, saved){
if (err) return next(err);
User.findById(uuid, function(err, removedUser){
if(err) return next(err);
sendMessage(removedUser);
//Mark removed users messages as seen
var update = {$unset:{}};
if (group.type === 'guild') {
update.$pull = {guilds: group._id};
} else {
update.$unset.party = true;
}
update.$unset['newMessages.' + group._id] = '';
if (group.quest && group.quest.active && group.quest.leader === uuid) {
update['$inc'] = {};
@@ -820,12 +829,8 @@ api.removeMember = function(req, res, next){
group = uuid = null;
return res.sendStatus(204);
});
});
}else if(_.contains(group.invites, uuid)){
User.findById(uuid, function(err,invited){
if(err) return next(err);
var invitations = invited.invitations;
}else if(isInvited){
var invitations = removedUser.invitations;
if(group.type === 'guild'){
invitations.guilds.splice(_.indexOf(invitations.guilds, group._id), 1);
}else{
@@ -834,11 +839,8 @@ api.removeMember = function(req, res, next){
async.series([
function(cb){
invited.save(cb);
removedUser.save(cb);
},
function(cb){
Group.update({_id:group._id},{$pull:{invites:uuid}}, cb);
}
], function(err, results){
if (err) return next(err);
@@ -848,12 +850,11 @@ api.removeMember = function(req, res, next){
group = uuid = null;
return res.sendStatus(204);
});
});
}else{
group = uuid = null;
return res.status(400).json({err: "User not found among group's members!"});
}
});
}
// ------------------------------------

View File

@@ -2,11 +2,12 @@ var url = require('url');
var ipn = require('paypal-ipn');
var _ = require('lodash');
var nconf = require('nconf');
var async = require('async');
var asyncM = require('async');
var shared = require('../../../../common');
import {
model as User,
} from '../../models/user';
import { model as Tag } from '../../models/tag';
import * as Tasks from '../../models/task';
import Q from 'q';
import {removeFromArray} from './../../libs/api-v3/collectionManipulators';
@@ -24,6 +25,8 @@ var logging = require('./../../libs/api-v2/logging');
var acceptablePUTPaths;
let restrictedPUTSubPaths;
let i18n = shared.i18n;
var api = module.exports;
var firebase = require('../../libs/api-v2/firebase');
var webhook = require('../../libs/api-v2/webhook');
@@ -121,7 +124,7 @@ api.score = function(req, res, next) {
direction,
}, req);
async.parallel({
asyncM.parallel({
task: task.save.bind(task),
user: user.save.bind(user)
}, function(err, results){
@@ -405,38 +408,7 @@ api.update = (req, res, next) => {
});
};
api.cron = function(req, res, next) {
var user = res.locals.user,
progress = user.fns.cron({analytics:utils.analytics, timezoneOffset:req.headers['x-user-timezoneoffset']}),
ranCron = user.isModified(),
quest = shared.content.quests[user.party.quest.key];
if (ranCron) res.locals.wasModified = true;
if (!ranCron) return next(null,user);
Group.tavernBoss(user,progress);
if (!quest) return user.save(next);
// If user is on a quest, roll for boss & player, or handle collections
// FIXME this saves user, runs db updates, loads user. Is there a better way to handle this?
async.waterfall([
function(cb){
user.save(cb); // make sure to save the cron effects
},
function(saved, count, cb){
var type = quest.boss ? 'boss' : 'collect';
Group[type+'Quest'](user,progress,cb);
},
function(){
var cb = arguments[arguments.length-1];
// User has been updated in boss-grapple, reload
User.findById(user._id, cb);
}
], function(err, saved) {
res.locals.user = saved;
next(err,saved);
user = progress = quest = null;
});
};
api.cron = require('../../middlewares/api-v3/cron');
// api.reroll // Shared.ops
// api.reset // Shared.ops
@@ -508,84 +480,210 @@ if (nconf.get('NODE_ENV') === 'development') {
Tags
------------------------------------------------------------------------
*/
// api.deleteTag // handled in Shared.ops
// api.addTag // handled in Shared.ops
// api.updateTag // handled in Shared.ops
// api.sortTag // handled in Shared.ops
api.getTags = function (req, res, next) {
res.json(res.locals.user.tags.toObject().map(tag => {
return {
name: tag.name,
id: tag._id,
challenge: tag.challenge,
}
}));
};
api.getTag = function (req, res, next) {
let tag = res.locals.user.tags.id(req.params.id);
if (!tag) {
return res.status(404).json({err: i18n.t('messageTagNotFound', req.language)});
}
res.json({
name: tag.name,
id: tag._id,
challenge: tag.challenge,
});
};
api.addTag = function (req, res, next) {
let user = res.locals.user;
user.tags.push(Tag.sanitize(req.body));
user.save(function (err, user) {
if (err) return next(err);
res.json(user.tags.toObject().map(tag => {
return {
name: tag.name,
id: tag._id,
challenge: tag.challenge,
}
}));
});
};
api.updateTag = function (req, res, next) {
let user = res.locals.user;
let tag = user.tags.id(req.params.id);
if (!tag) {
return res.status(404).json({err: i18n.t('messageTagNotFound', req.language)});
}
tag.name = req.body.tag;
user.save(function (err, user) {
if (err) return next(err);
res.json({
name: tag.name,
id: tag._id,
challenge: tag.challenge,
});
});
}
api.sortTag = function (req, res, next) {
var ref = req.query;
var to = ref.to;
var from = ref.from;
let user = res.locals.user;
if (!((to != null) && (from != null))) {
return res.statu(500).json('?to=__&from=__ are required');
}
user.tags.splice(to, 0, user.tags.splice(from, 1)[0]);
user.save(function (err, user) {
if (err) return next(err);
res.json(user.tags.toObject().map(tag => {
return {
name: tag.name,
id: tag._id,
challenge: tag.challenge,
}
}));
});
}
api.deleteTag = function (req, res, next) {
let user = res.locals.user;
let tag = user.tags.id(req.params.id);
if (!tag) {
return res.status(404).json({err: i18n.t('messageTagNotFound', req.language)});
}
tag.remove();
Tasks.Task.update({
userId: user._id,
}, {
$pull: {
tags: tag._id,
},
}, {multi: true}).exec();
user.save(function (err, user) {
if (err) return next(err);
res.json(user.tags.toObject().map(tag => {
return {
name: tag.name,
id: tag._id,
challenge: tag.challenge,
}
}));
});
}
/*
------------------------------------------------------------------------
Spells
------------------------------------------------------------------------
*/
api.cast = function(req, res, next) {
var user = res.locals.user,
targetType = req.query.targetType,
targetId = req.query.targetId,
klass = shared.content.spells.special[req.params.spell] ? 'special' : user.stats.class,
spell = shared.content.spells[klass][req.params.spell];
api.cast = async function(req, res, next) {
try {
let user = res.locals.user;
let spellId = req.params.spellId;
let targetId = req.query.targetId;
let klass = common.content.spells.special[spellId] ? 'special' : user.stats.class;
let spell = common.content.spells[klass][spellId];
if (!spell) return res.status(404).json({err: 'Spell "' + req.params.spell + '" not found.'});
if (spell.mana > user.stats.mp) return res.status(400).json({err: 'Not enough mana to cast spell'});
var done = function(){
var err = arguments[0];
var saved = _.size(arguments == 3) ? arguments[2] : arguments[1];
if (err) return next(err);
res.json(saved);
user = targetType = targetId = klass = spell = null;
let targetType = spell.target;
if (targetType === 'task') {
let task = await Tasks.Task.findOne({
_id: targetId,
userId: user._id,
}).exec();
if (!task) {
return res.status(404).json({err: 'Task "' + targetId + '" not found.'});
}
switch (targetType) {
case 'task':
if (!user.tasks[targetId]) return res.status(404).json({err: 'Task "' + targetId + '" not found.'});
spell.cast(user, user.tasks[targetId]);
user.save(done);
break;
spell.cast(user, task, req);
await task.save();
} else if (targetType === 'self') {
spell.cast(user, null, req);
await user.save();
} else if (targetType === 'tasks') { // new target type when all the user's tasks are necessary
let tasks = await Tasks.Task.find({
userId: user._id,
'challenge.id': {$exists: false}, // exclude challenge tasks
$or: [ // Exclude completed todos
{type: 'todo', completed: false},
{type: {$in: ['habit', 'daily', 'reward']}},
],
}).exec();
case 'self':
spell.cast(user);
user.save(done);
break;
spell.cast(user, tasks, req);
case 'party':
case 'user':
async.waterfall([
function(cb){
Group.findOne({type: 'party', members: {'$in': [user._id]}}).populate('members', 'profile.name stats achievements items.special').exec(cb);
},
function(group, cb) {
// Solo player? let's just create a faux group for simpler code
var g = group ? group : {members:[user]};
var series = [], found;
if (targetType == 'party') {
spell.cast(user, g.members);
series = _.transform(g.members, function(m,v,k){
m.push(function(cb2){v.save(cb2)});
});
let toSave = tasks.filter(t => t.isModified());
let isUserModified = user.isModified();
toSave.unshift(user.save());
let saved = await Q.all(toSave);
} else if (targetType === 'party' || targetType === 'user') {
let party = await Group.getGroup({groupId: 'party', user});
// arrays of users when targetType is 'party' otherwise single users
let partyMembers;
if (targetType === 'party') {
if (!party) {
partyMembers = [user]; // Act as solo party
} else {
found = _.find(g.members, {_id: targetId})
spell.cast(user, found);
series.push(function(cb2){found.save(cb2)});
partyMembers = await User.find({'party._id': party._id}).select(partyMembersFields).exec();
}
if (group && !spell.silent) {
series.push(function(cb2){
var message = '`'+user.profile.name+' casts '+spell.text() + (targetType=='user' ? ' on '+found.profile.name : ' for the party')+'.`';
group.sendChat(message);
group.save(cb2);
})
spell.cast(user, partyMembers, req);
await Q.all(partyMembers.map(m => m.save()));
} else {
if (!party && (!targetId || user._id === targetId)) {
partyMembers = user;
} else {
partyMembers = await User.findOne({_id: targetId, 'party._id': party._id}).select(partyMembersFields).exec();
}
series.push(function(cb2){g = group = series = found = null;cb2();})
async.series(series, cb);
},
function(whatever, cb){
user.save(cb);
if (!partyMembers) throw new NotFound(res.t('userWithIDNotFound', {userId: targetId}));
spell.cast(user, partyMembers, req);
await partyMembers.save();
}
], done);
break;
if (party && !spell.silent) {
let message = `\`${user.profile.name} casts ${spell.text()}${targetType === 'user' ? ` on ${partyMembers.profile.name}` : ' for the party'}.\``;
party.sendChat(message);
await party.save();
}
}
user.getTransformedData(function (err, transformedUser) {
if (err) next(err);
res.json(transformedUser);
});
} catch (e) {
return res.status(500).json({err: 'An error happened'});
}
}
@@ -594,7 +692,7 @@ api.sessionPartyInvite = function(req,res,next){
if (!req.session.partyInvite) return next();
var inv = res.locals.user.invitations;
if (inv.party && inv.party.id) return next(); // already invited to a party
async.waterfall([
asyncM.waterfall([
function(cb){
Group.findOne({_id:req.session.partyInvite.id, members:{$in:[req.session.partyInvite.inviter]}})
.select('invites members type').exec(cb);
@@ -646,6 +744,47 @@ api.clearCompleted = function(req, res, next) {
});
};
api.sortTask = async function (req, res, next) {
try {
let user = res.locals.user;
let to = Number(req.query.to);
let task = await Tasks.Task.findOne({
_id: req.params.id,
userId: user._id,
}).exec();
if (!task) return res.status(404).json(i18n.t('messageTaskNotFound', req.language));
if (task.type !== 'todo' || !task.completed) {
let order = user.tasksOrder[`${task.type}s`];
let currentIndex = order.indexOf(task._id);
// If for some reason the task isn't ordered (should never happen), push it in the new position
// if the task is moved to a non existing position
// or if the task is moved to position -1 (push to bottom)
// -> push task at end of list
if (!order[to] && to !== -1) {
order.push(task._id);
} else {
if (currentIndex !== -1) order.splice(currentIndex, 1);
if (to === -1) {
order.push(task._id);
} else {
order.splice(to, 0, task._id);
}
}
await user.save();
}
user.getTasks(function (err, userTasks) {
if(err) return next(err);
res.json(userTasks);
});
} catch (e) {
res.status(500).json({err: 'An error happened.'});
}
}
api.deleteTask = function(req, res, next) {
var user = res.locals.user;
if(!req.params || !req.params.id) return res.json(404, shared.i18n.t('messageTaskNotFound', req.language));
@@ -660,7 +799,7 @@ api.deleteTask = function(req, res, next) {
removeTaskFromOrder(user.tasksOrder[type])
});
async.parallel({
asyncM.parallel({
user: user.save.bind(user),
task: function(cb) {
Tasks.Task.remove({_id: id, userId: user._id}, cb);
@@ -789,31 +928,35 @@ api.batchUpdate = function(req, res, next) {
});
// call all the operations, then return the user object to the requester
async.waterfall(ops, function(err,_user) {
asyncM.waterfall(ops, function(err,_user) {
res.json = oldJson;
res.send = oldSend;
if (err) return next(err);
var response = _user.toJSON();
response.wasModified = res.locals.wasModified;
user.fns.nullify();
user = res.locals.user = oldSend = oldJson = oldSave = null;
var response;
// return only drops & streaks
if (response._tmp && response._tmp.drop){
if (_user._tmp && _user._tmp.drop){
response = _user.toJSON();
res.status(200).json({_tmp: {drop: response._tmp.drop}, _v: response._v});
// Fetch full user object
} else if (response.wasModified){
} else if (res.locals.wasModified){
// Preen 3-day past-completed To-Dos from Angular & mobile app
_user.getTransformedData(function(err, transformedData){
response = transformedData;
response.todos = shared.preenTodos(response.todos);
res.status(200).json(response);
});
// return only the version number
} else{
response = _user.toJSON();
res.status(200).json({_v: response._v});
}
user.fns.nullify();
user = res.locals.user = oldSend = oldJson = oldSave = null;
});
};

View File

@@ -1,6 +1,7 @@
import { authWithHeaders } from '../../middlewares/api-v3/auth';
import cron from '../../middlewares/api-v3/cron';
import { model as Tag } from '../../models/tag';
import { model as Tasks } from '../../models/task';
import {
NotFound,
} from '../../libs/api-v3/errors';
@@ -96,7 +97,6 @@ api.updateTag = {
let user = res.locals.user;
req.checkParams('tagId', res.t('tagIdRequired')).notEmpty().isUUID();
// TODO check that req.body isn't empty
let tagId = req.params.tagId;
@@ -139,6 +139,15 @@ api.deleteTag = {
if (!tag) throw new NotFound(res.t('tagNotFound'));
tag.remove();
// Remove from all the tasks TODO test
await Tasks.Task.update({
userId: user._id,
}, {
$pull: {
tags: tag._id,
},
}, {multi: true}).exec();
await user.save();
res.respond(200, {});
},

View File

@@ -373,7 +373,7 @@ api.castSpell = {
let response = {
tasks: isUserModified ? _.rest(saved) : saved,
};
if (isUserModified) res.user = user;
if (isUserModified) response.user = user;
res.respond(200, response);
} else if (targetType === 'party' || targetType === 'user') {
let party = await Group.getGroup({groupId: 'party', user});

View File

@@ -26,7 +26,7 @@ let clearBuffs = {
// For incomplete Dailys, deduct experience
// Make sure to run this function once in a while as server will not take care of overnight calculations.
// And you have to run it every time client connects.
export function cron (options = {}) {
function cron (options = {}) {
let {user, tasksByType, analytics, now = new Date(), daysMissed, timezoneOffsetFromUserPrefs} = options;
user.auth.timestamps.loggedin = now;
@@ -271,7 +271,7 @@ export function cron (options = {}) {
}
// TODO check that it's used everywhere
module.exports = async function cronMiddleware (req, res, next) {
module.exports = function cronMiddleware (req, res, next) {
let user = res.locals.user;
let analytics = res.analytics;

View File

@@ -112,6 +112,14 @@ TaskSchema.methods.scoreChallengeTask = async function scoreChallengeTask (delta
TaskSchema.methods.toJSONV2 = function toJSONV2 () {
let toJSON = this.toJSON();
toJSON.id = toJSON._id;
let v3Tags = this.tags;
toJSON.tags = {};
v3Tags.forEach(tag => {
toJSON.tags[tag] = true;
});
return toJSON;
};

View File

@@ -753,6 +753,15 @@ schema.methods.getTasks = function getUserTasks () {
// Given user and an array of tasks, return an API compatible user + tasks obj
schema.methods.addTasksToUser = function addTasksToUser (tasks) {
let obj = this.toJSON();
obj.tags = obj.tags.map(tag => {
return {
id: tag._id,
name: tag.name,
challenge: tag.challenge,
};
});
let tasksOrder = obj.tasksOrder; // Saving a reference because we won't return it
obj.habits = [];

View File

@@ -2,17 +2,18 @@ var auth = require('../../controllers/api-v2/auth');
var express = require('express');
var i18n = require('../../libs/api-v2/i18n');
var router = express.Router();
import getUserLanguage from '../../middlewares/api-v3/getUserLanguage';
/* auth.auth*/
// auth.setupPassport(router); //FIXME make this consistent with the others
router.post('/register', i18n.getUserLanguage, auth.registerUser);
router.post('/user/auth/local', i18n.getUserLanguage, auth.loginLocal);
router.post('/user/auth/social', i18n.getUserLanguage, auth.loginSocial);
router.delete('/user/auth/social', i18n.getUserLanguage, auth.auth, auth.deleteSocial);
router.post('/user/reset-password', i18n.getUserLanguage, auth.resetPassword);
router.post('/user/change-password', i18n.getUserLanguage, auth.auth, auth.changePassword);
router.post('/user/change-username', i18n.getUserLanguage, auth.auth, auth.changeUsername);
router.post('/user/change-email', i18n.getUserLanguage, auth.auth, auth.changeEmail);
router.post('/register', getUserLanguage, auth.registerUser);
router.post('/user/auth/local', getUserLanguage, auth.loginLocal);
router.post('/user/auth/social', getUserLanguage, auth.loginSocial);
router.delete('/user/auth/social', getUserLanguage, auth.auth, auth.deleteSocial);
router.post('/user/reset-password', getUserLanguage, auth.resetPassword);
router.post('/user/change-password', getUserLanguage, auth.auth, auth.changePassword);
router.post('/user/change-username', getUserLanguage, auth.auth, auth.changeUsername);
router.post('/user/change-email', getUserLanguage, auth.auth, auth.changeEmail);
// router.post('/user/auth/firebase', i18n.getUserLanguage, auth.auth, auth.getFirebaseToken);
module.exports = router;

View File

@@ -4,9 +4,10 @@ var router = express.Router();
var auth = require('../../controllers/api-v2/auth');
var coupon = require('../../controllers/api-v2/coupon');
var i18n = require('../../libs/api-v2/i18n');
import getUserLanguage from '../../middlewares/api-v3/getUserLanguage';
router.get('/coupons', auth.authWithUrl, i18n.getUserLanguage, coupon.ensureAdmin, coupon.getCoupons);
router.post('/coupons/generate/:event', auth.auth, i18n.getUserLanguage, coupon.ensureAdmin, coupon.generateCoupons);
router.post('/user/coupon/:code', auth.auth, i18n.getUserLanguage, coupon.enterCode);
router.get('/coupons', auth.authWithUrl, getUserLanguage, coupon.ensureAdmin, coupon.getCoupons);
router.post('/coupons/generate/:event', auth.auth, getUserLanguage, coupon.ensureAdmin, coupon.generateCoupons);
router.post('/user/coupon/:code', auth.auth, getUserLanguage, coupon.enterCode);
module.exports = router;

View File

@@ -19,6 +19,7 @@ var cron = user.cron;
var _ = require('lodash');
var content = require('../../../../common').content;
var i18n = require('../../libs/api-v2/i18n');
import getUserLanguage from '../../middlewares/api-v3/getUserLanguage';
var forceRefresh = require('../../middlewares/forceRefresh').middleware;
module.exports = function(swagger, v2) {
@@ -60,7 +61,7 @@ module.exports = function(swagger, v2) {
description: "Export user history",
method: 'GET'
},
middleware: [auth.auth, i18n.getUserLanguage],
middleware: [auth.auth, getUserLanguage],
action: dataexport.history
},
"/user/tasks/{id}/{direction}": {
@@ -134,7 +135,7 @@ module.exports = function(swagger, v2) {
description: 'Unlink a task from its challenge',
parameters: [path("id", "Task ID", "string"), query('keep', "When unlinking a challenge task, how to handle the orphans?", 'string', ['keep', 'keep-all', 'remove', 'remove-all'])]
},
middleware: [auth.auth, i18n.getUserLanguage],
middleware: [auth.auth, getUserLanguage],
action: challenges.unlink
},
"/user/inventory/buy": {
@@ -235,7 +236,7 @@ module.exports = function(swagger, v2) {
method: 'DELETE',
description: "Delete a user object entirely, USE WITH CAUTION!"
},
middleware: [auth.auth, i18n.getUserLanguage],
middleware: [auth.auth, getUserLanguage],
action: user["delete"]
},
"/user/revive": {
@@ -311,7 +312,7 @@ module.exports = function(swagger, v2) {
description: "This is an advanced route which is useful for apps which might for example need offline support. You can send a whole batch of user-based operations, which allows you to queue them up offline and send them all at once. The format is {op:'nameOfOperation',parameters:{},body:{},query:{}}",
parameters: [body('', 'The array of batch-operations to perform', 'object')]
},
middleware: [forceRefresh, auth.auth, i18n.getUserLanguage, cron, user.sessionPartyInvite],
middleware: [forceRefresh, auth.auth, getUserLanguage, cron, user.sessionPartyInvite],
action: user.batchUpdate
},
"/user/tags/{id}:GET": {
@@ -406,7 +407,7 @@ module.exports = function(swagger, v2) {
description: "Get a list of groups",
parameters: [query('type', "Comma-separated types of groups to return, eg 'party,guilds,public,tavern'", 'string')]
},
middleware: [auth.auth, i18n.getUserLanguage],
middleware: [auth.auth, getUserLanguage],
action: groups.list
},
"/groups:POST": {
@@ -416,7 +417,7 @@ module.exports = function(swagger, v2) {
description: 'Create a group',
parameters: [body('', 'Group object (see GroupSchema)', 'object')]
},
middleware: [auth.auth, i18n.getUserLanguage],
middleware: [auth.auth, getUserLanguage],
action: groups.create
},
"/groups/{gid}:GET": {
@@ -425,7 +426,7 @@ module.exports = function(swagger, v2) {
description: "Get a group. The party the user currently is in can be accessed with the gid 'party'.",
parameters: [path('gid', 'Group ID', 'string')]
},
middleware: [auth.auth, i18n.getUserLanguage],
middleware: [auth.auth, getUserLanguage],
action: groups.get
},
"/groups/{gid}:POST": {
@@ -435,7 +436,7 @@ module.exports = function(swagger, v2) {
description: "Edit a group",
parameters: [body('', 'Group object (see GroupSchema)', 'object')]
},
middleware: [auth.auth, i18n.getUserLanguage, groups.attachGroup],
middleware: [auth.auth, getUserLanguage, groups.attachGroup],
action: groups.update
},
"/groups/{gid}/join": {
@@ -444,7 +445,7 @@ module.exports = function(swagger, v2) {
description: 'Join a group',
parameters: [path('gid', 'Id of the group to join', 'string')]
},
middleware: [auth.auth, i18n.getUserLanguage, groups.attachGroup],
middleware: [auth.auth, getUserLanguage, groups.attachGroup],
action: groups.join
},
"/groups/{gid}/leave": {
@@ -453,7 +454,7 @@ module.exports = function(swagger, v2) {
description: 'Leave a group',
parameters: [path('gid', 'ID of the group to leave', 'string')]
},
middleware: [auth.auth, i18n.getUserLanguage, groups.attachGroup],
middleware: [auth.auth, getUserLanguage, groups.attachGroup],
action: groups.leave
},
"/groups/{gid}/invite": {
@@ -462,7 +463,7 @@ module.exports = function(swagger, v2) {
description: "Invite a user to a group",
parameters: [path('gid', 'Group id', 'string'), body('', 'a payload of invites either under body.uuids or body.emails, only one of them!', 'object')]
},
middleware: [auth.auth, i18n.getUserLanguage, groups.attachGroup],
middleware: [auth.auth, getUserLanguage, groups.attachGroup],
action: groups.invite
},
"/groups/{gid}/removeMember": {
@@ -471,7 +472,7 @@ module.exports = function(swagger, v2) {
description: "Remove / boot a member from a group",
parameters: [path('gid', 'Group id', 'string'), query('uuid', 'User id to boot', 'string')]
},
middleware: [auth.auth, i18n.getUserLanguage, groups.attachGroup],
middleware: [auth.auth, getUserLanguage, groups.attachGroup],
action: groups.removeMember
},
"/groups/{gid}/questAccept": {
@@ -480,7 +481,7 @@ module.exports = function(swagger, v2) {
description: "Accept a quest invitation",
parameters: [path('gid', "Group id", 'string'), query('key', "optional. if provided, trigger new invite, if not, accept existing invite", 'string')]
},
middleware: [auth.auth, i18n.getUserLanguage, groups.attachGroup],
middleware: [auth.auth, getUserLanguage, groups.attachGroup],
action: groups.questAccept
},
"/groups/{gid}/questReject": {
@@ -489,7 +490,7 @@ module.exports = function(swagger, v2) {
description: 'Reject quest invitation',
parameters: [path('gid', 'Group id', 'string')]
},
middleware: [auth.auth, i18n.getUserLanguage, groups.attachGroup],
middleware: [auth.auth, getUserLanguage, groups.attachGroup],
action: groups.questReject
},
"/groups/{gid}/questCancel": {
@@ -498,7 +499,7 @@ module.exports = function(swagger, v2) {
description: 'Cancel quest before it starts (in invitation stage)',
parameters: [path('gid', 'Group to cancel quest in', 'string')]
},
middleware: [auth.auth, i18n.getUserLanguage, groups.attachGroup],
middleware: [auth.auth, getUserLanguage, groups.attachGroup],
action: groups.questCancel
},
"/groups/{gid}/questAbort": {
@@ -507,7 +508,7 @@ module.exports = function(swagger, v2) {
description: 'Abort quest after it has started (all progress will be lost)',
parameters: [path('gid', 'Group to abort quest in', 'string')]
},
middleware: [auth.auth, i18n.getUserLanguage, groups.attachGroup],
middleware: [auth.auth, getUserLanguage, groups.attachGroup],
action: groups.questAbort
},
"/groups/{gid}/questLeave": {
@@ -516,7 +517,7 @@ module.exports = function(swagger, v2) {
description: 'Leave an active quest (Quest leaders cannot leave active quests. They must abort the quest to leave)',
parameters: [path('gid', 'Group to leave quest in', 'string')]
},
middleware: [auth.auth, i18n.getUserLanguage, groups.attachGroup],
middleware: [auth.auth, getUserLanguage, groups.attachGroup],
action: groups.questLeave
},
"/groups/{gid}/chat:GET": {
@@ -525,7 +526,7 @@ module.exports = function(swagger, v2) {
description: "Get all chat messages",
parameters: [path('gid', 'Group to return the chat from ', 'string')]
},
middleware: [auth.auth, i18n.getUserLanguage, groups.attachGroup],
middleware: [auth.auth, getUserLanguage, groups.attachGroup],
action: groups.getChat
},
"/groups/{gid}/chat:POST": {
@@ -535,7 +536,7 @@ module.exports = function(swagger, v2) {
description: "Send a chat message",
parameters: [query('message', 'Chat message', 'string'), path('gid', 'Group id', 'string')]
},
middleware: [auth.auth, i18n.getUserLanguage, groups.attachGroup],
middleware: [auth.auth, getUserLanguage, groups.attachGroup],
action: groups.postChat
},
"/groups/{gid}/chat/seen": {
@@ -552,7 +553,7 @@ module.exports = function(swagger, v2) {
description: 'Delete a chat message in a given group',
parameters: [path('gid', 'ID of the group containing the message to be deleted', 'string'), path('messageId', 'ID of message to be deleted', 'string')]
},
middleware: [auth.auth, i18n.getUserLanguage, groups.attachGroup],
middleware: [auth.auth, getUserLanguage, groups.attachGroup],
action: groups.deleteChatMessage
},
"/groups/{gid}/chat/{mid}/like": {
@@ -561,7 +562,7 @@ module.exports = function(swagger, v2) {
description: "Like a chat message",
parameters: [path('gid', 'Group id', 'string'), path('mid', 'Message id', 'string')]
},
middleware: [auth.auth, i18n.getUserLanguage, groups.attachGroup],
middleware: [auth.auth, getUserLanguage, groups.attachGroup],
action: groups.likeChatMessage
},
"/groups/{gid}/chat/{mid}/flag": {
@@ -570,7 +571,7 @@ module.exports = function(swagger, v2) {
description: "Flag a chat message",
parameters: [path('gid', 'Group id', 'string'), path('mid', 'Message id', 'string')]
},
middleware: [auth.auth, i18n.getUserLanguage, groups.attachGroup],
middleware: [auth.auth, getUserLanguage, groups.attachGroup],
action: groups.flagChatMessage
},
"/groups/{gid}/chat/{mid}/clearflags": {
@@ -579,7 +580,7 @@ module.exports = function(swagger, v2) {
description: "Clear flag count from message and unhide it",
parameters: [path('gid', 'Group id', 'string'), path('mid', 'Message id', 'string')]
},
middleware: [auth.auth, i18n.getUserLanguage, groups.attachGroup],
middleware: [auth.auth, getUserLanguage, groups.attachGroup],
action: groups.clearFlagCount
},
"/members/{uuid}:GET": {
@@ -588,7 +589,7 @@ module.exports = function(swagger, v2) {
description: "Get a member.",
parameters: [path('uuid', 'Member ID', 'string')]
},
middleware: [i18n.getUserLanguage],
middleware: [getUserLanguage],
action: members.getMember
},
"/members/{uuid}/message": {
@@ -620,14 +621,14 @@ module.exports = function(swagger, v2) {
},
"/hall/heroes": {
spec: {},
middleware: [auth.auth, i18n.getUserLanguage],
middleware: [auth.auth, getUserLanguage],
action: hall.getHeroes
},
"/hall/heroes/{uid}:GET": {
spec: {
path: "/hall/heroes/{uid}"
},
middleware: [auth.auth, i18n.getUserLanguage, hall.ensureAdmin],
middleware: [auth.auth, getUserLanguage, hall.ensureAdmin],
action: hall.getHero
},
"/hall/heroes/{uid}:POST": {
@@ -635,14 +636,14 @@ module.exports = function(swagger, v2) {
method: 'POST',
path: "/hall/heroes/{uid}"
},
middleware: [auth.auth, i18n.getUserLanguage, hall.ensureAdmin],
middleware: [auth.auth, getUserLanguage, hall.ensureAdmin],
action: hall.updateHero
},
"/hall/patrons": {
spec: {
parameters: [query('page', 'Page number to fetch (this list is long)', 'string')]
},
middleware: [auth.auth, i18n.getUserLanguage],
middleware: [auth.auth, getUserLanguage],
action: hall.getPatrons
},
"/challenges:GET": {
@@ -650,7 +651,7 @@ module.exports = function(swagger, v2) {
path: '/challenges',
description: "Get a list of challenges"
},
middleware: [auth.auth, i18n.getUserLanguage],
middleware: [auth.auth, getUserLanguage],
action: challenges.list
},
"/challenges:POST": {
@@ -660,7 +661,7 @@ module.exports = function(swagger, v2) {
description: "Create a challenge",
parameters: [body('', 'Challenge object (see ChallengeSchema)', 'object')]
},
middleware: [auth.auth, i18n.getUserLanguage],
middleware: [auth.auth, getUserLanguage],
action: challenges.create
},
"/challenges/{cid}:GET": {
@@ -669,7 +670,7 @@ module.exports = function(swagger, v2) {
description: 'Get a challenge',
parameters: [path('cid', 'Challenge id', 'string')]
},
middleware: [auth.auth, i18n.getUserLanguage],
middleware: [auth.auth, getUserLanguage],
action: challenges.get
},
"/challenges/{cid}/csv": {
@@ -686,7 +687,7 @@ module.exports = function(swagger, v2) {
description: "Update a challenge",
parameters: [path('cid', 'Challenge id', 'string'), body('', 'Challenge object (see ChallengeSchema)', 'object')]
},
middleware: [auth.auth, i18n.getUserLanguage],
middleware: [auth.auth, getUserLanguage],
action: challenges.update
},
"/challenges/{cid}:DELETE": {
@@ -696,7 +697,7 @@ module.exports = function(swagger, v2) {
description: "Delete a challenge",
parameters: [path('cid', 'Challenge id', 'string')]
},
middleware: [auth.auth, i18n.getUserLanguage],
middleware: [auth.auth, getUserLanguage],
action: challenges["delete"]
},
"/challenges/{cid}/close": {
@@ -705,7 +706,7 @@ module.exports = function(swagger, v2) {
description: 'Close a challenge',
parameters: [path('cid', 'Challenge id', 'string'), query('uid', 'User ID of the winner', 'string', true)]
},
middleware: [auth.auth, i18n.getUserLanguage],
middleware: [auth.auth, getUserLanguage],
action: challenges.selectWinner
},
"/challenges/{cid}/join": {
@@ -714,7 +715,7 @@ module.exports = function(swagger, v2) {
description: "Join a challenge",
parameters: [path('cid', 'Challenge id', 'string')]
},
middleware: [auth.auth, i18n.getUserLanguage],
middleware: [auth.auth, getUserLanguage],
action: challenges.join
},
"/challenges/{cid}/leave": {
@@ -723,7 +724,7 @@ module.exports = function(swagger, v2) {
description: 'Leave a challenge',
parameters: [path('cid', 'Challenge id', 'string')]
},
middleware: [auth.auth, i18n.getUserLanguage],
middleware: [auth.auth, getUserLanguage],
action: challenges.leave
},
"/challenges/{cid}/member/{uid}": {
@@ -731,7 +732,7 @@ module.exports = function(swagger, v2) {
description: "Get a member's progress in a particular challenge",
parameters: [path('cid', 'Challenge id', 'string'), path('uid', 'User id', 'string')]
},
middleware: [auth.auth, i18n.getUserLanguage],
middleware: [auth.auth, getUserLanguage],
action: challenges.getMember
}
};
@@ -765,7 +766,7 @@ module.exports = function(swagger, v2) {
method: 'GET'
});
if (route.middleware == null) {
route.middleware = path.indexOf('/user') === 0 ? [auth.auth, i18n.getUserLanguage, cron] : [i18n.getUserLanguage];
route.middleware = path.indexOf('/user') === 0 ? [auth.auth, getUserLanguage, cron] : [i18n.getUserLanguage];
}
swagger["add" + route.spec.method](route);
return true;

View File

@@ -2,7 +2,8 @@ var express = require('express');
var router = express.Router();
var i18n = require('../../libs/api-v2/i18n');
var unsubscription = require('../../controllers/api-v2/unsubscription');
import getUserLanguage from '../../middlewares/api-v3/getUserLanguage';
router.get('/unsubscribe', i18n.getUserLanguage, unsubscription.unsubscribe);
router.get('/unsubscribe', getUserLanguage, unsubscription.unsubscribe);
module.exports = router;

View File

@@ -4,28 +4,29 @@ var router = express.Router();
var auth = require('../controllers/api-v2/auth');
var payments = require('../controllers/payments');
var i18n = require('../libs/api-v2/i18n');
import getUserLanguage from '../../middlewares/api-v3/getUserLanguage';
router.get('/paypal/checkout', auth.authWithUrl, i18n.getUserLanguage, payments.paypalCheckout);
router.get('/paypal/checkout/success', i18n.getUserLanguage, payments.paypalCheckoutSuccess);
router.get('/paypal/subscribe', auth.authWithUrl, i18n.getUserLanguage, payments.paypalSubscribe);
router.get('/paypal/subscribe/success', i18n.getUserLanguage, payments.paypalSubscribeSuccess);
router.get('/paypal/subscribe/cancel', auth.authWithUrl, i18n.getUserLanguage, payments.paypalSubscribeCancel);
router.post('/paypal/ipn', i18n.getUserLanguage, payments.paypalIPN); // misc ipn handling
router.get('/paypal/checkout', auth.authWithUrl, getUserLanguage, payments.paypalCheckout);
router.get('/paypal/checkout/success', getUserLanguage, payments.paypalCheckoutSuccess);
router.get('/paypal/subscribe', auth.authWithUrl, getUserLanguage, payments.paypalSubscribe);
router.get('/paypal/subscribe/success', getUserLanguage, payments.paypalSubscribeSuccess);
router.get('/paypal/subscribe/cancel', auth.authWithUrl, getUserLanguage, payments.paypalSubscribeCancel);
router.post('/paypal/ipn', getUserLanguage, payments.paypalIPN); // misc ipn handling
router.post('/stripe/checkout', auth.auth, i18n.getUserLanguage, payments.stripeCheckout);
router.post('/stripe/subscribe/edit', auth.auth, i18n.getUserLanguage, payments.stripeSubscribeEdit);
//router.get('/stripe/subscribe', auth.authWithUrl, i18n.getUserLanguage, payments.stripeSubscribe); // checkout route is used (above) with ?plan= instead
router.get('/stripe/subscribe/cancel', auth.authWithUrl, i18n.getUserLanguage, payments.stripeSubscribeCancel);
router.post('/stripe/checkout', auth.auth, getUserLanguage, payments.stripeCheckout);
router.post('/stripe/subscribe/edit', auth.auth, getUserLanguage, payments.stripeSubscribeEdit);
//router.get('/stripe/subscribe', auth.authWithUrl, getUserLanguage, payments.stripeSubscribe); // checkout route is used (above) with ?plan= instead
router.get('/stripe/subscribe/cancel', auth.authWithUrl, getUserLanguage, payments.stripeSubscribeCancel);
router.post('/amazon/verifyAccessToken', auth.auth, i18n.getUserLanguage, payments.amazonVerifyAccessToken);
router.post('/amazon/createOrderReferenceId', auth.auth, i18n.getUserLanguage, payments.amazonCreateOrderReferenceId);
router.post('/amazon/checkout', auth.auth, i18n.getUserLanguage, payments.amazonCheckout);
router.post('/amazon/subscribe', auth.auth, i18n.getUserLanguage, payments.amazonSubscribe);
router.get('/amazon/subscribe/cancel', auth.authWithUrl, i18n.getUserLanguage, payments.amazonSubscribeCancel);
router.post('/amazon/verifyAccessToken', auth.auth, getUserLanguage, payments.amazonVerifyAccessToken);
router.post('/amazon/createOrderReferenceId', auth.auth, getUserLanguage, payments.amazonCreateOrderReferenceId);
router.post('/amazon/checkout', auth.auth, getUserLanguage, payments.amazonCheckout);
router.post('/amazon/subscribe', auth.auth, getUserLanguage, payments.amazonSubscribe);
router.get('/amazon/subscribe/cancel', auth.authWithUrl, getUserLanguage, payments.amazonSubscribeCancel);
router.post('/iap/android/verify', auth.authWithUrl, /*i18n.getUserLanguage, */payments.iapAndroidVerify);
router.post('/iap/ios/verify', auth.auth, /*i18n.getUserLanguage, */ payments.iapIosVerify);
router.post('/iap/android/verify', auth.authWithUrl, /*getUserLanguage, */payments.iapAndroidVerify);
router.post('/iap/ios/verify', auth.auth, /*getUserLanguage, */ payments.iapIosVerify);
router.get('/api/v2/coupons/valid-discount/:code', /*auth.authWithUrl, i18n.getUserLanguage, */ payments.validCoupon);
router.get('/api/v2/coupons/valid-discount/:code', /*auth.authWithUrl, getUserLanguage, */ payments.validCoupon);
module.exports = router;