v3: port coupons

This commit is contained in:
Matteo Pagliazzi
2016-04-02 16:37:55 +02:00
parent 731ac86244
commit de74fae0b4
12 changed files with 475 additions and 73 deletions
+125
View File
@@ -0,0 +1,125 @@
import csvStringify from '../../libs/api-v3/csvStringify';
import {
authWithHeaders,
authWithSession,
} from '../../middlewares/api-v3/auth';
import cron from '../../middlewares/api-v3/cron';
import { ensureSudo } from '../../middlewares/api-v3/ensureAccessRight';
import { model as Coupon } from '../../models/coupon';
import _ from 'lodash';
import couponCode from 'coupon-code';
let api = {};
/**
* @api {get} /coupons Get coupons (sudo users only)
* @apiVersion 3.0.0
* @apiName GetCoupons
* @apiGroup Coupon
*
* @apiSuccess string Coupons in CSV format
*/
api.getCoupons = {
method: 'GET',
url: '/coupons',
middlewares: [authWithSession, cron, ensureSudo],
async handler (req, res) {
let coupons = await Coupon.find().sort('createdAt').lean().exec();
let output = [['code', 'event', 'date', 'user']].concat(_.map(coupons, coupon => {
return [coupon._id, coupon.event, coupon.createdAt, coupon.user];
}));
let csv = await csvStringify(output);
res.set({
'Content-Type': 'text/csv',
'Content-disposition': `attachment; filename=habitica-coupons.csv`,
});
res.status(200).send(csv);
},
};
/**
* @api {post} /coupons/generate/:event Generate coupons for an event (sudo users only)
* @apiVersion 3.0.0
* @apiName GenerateCoupons
* @apiGroup Coupon
*
* @apiParam {string} event The event for which the coupon should be generated
* @apiParam {number} count Query parameter to specify the number of coupon codes to generate
*
* @apiSuccess array Generated coupons
*/
api.generateCoupons = {
method: 'POST',
url: '/coupons/generate/:event',
middlewares: [authWithHeaders(), cron, ensureSudo],
async handler (req, res) {
req.checkParams('event', res.t('eventRequired')).notEmpty();
req.checkQuery('count', res.t('countRequired')).notEmpty().isNumeric();
let validationErrors = req.validationErrors();
if (validationErrors) throw validationErrors;
let coupons = await Coupon.generate(req.params.event, req.query.count);
res.respond(200, coupons);
},
};
/**
* @api {post} /user/coupon/:code Enter coupon code
* @apiVersion 3.0.0
* @apiName EnterCouponCode
* @apiGroup Coupon
*
* @apiParam {string} code The coupon code to apply
*
* @apiSuccess object User object
*/
api.enterCouponCode = {
method: 'POST',
url: '/coupons/enter/:code',
middlewares: [authWithHeaders(), cron],
async handler (req, res) {
let user = res.locals.user;
req.checkParams('code', res.t('couponCodeRequired')).notEmpty();
let validationErrors = req.validationErrors();
if (validationErrors) throw validationErrors;
await Coupon.apply(user, req, req.params.code);
res.respond(200, user);
},
};
/**
* @api {post} /coupons/validate/:code Validate a coupon code
* @apiVersion 3.0.0
* @apiName ValidateCoupon
* @apiGroup Coupon
*
* @apiSuccess valid {boolean} true or false
*/
api.validateCoupon = {
method: 'POST',
url: '/coupons/validate/:code',
middlewares: [authWithHeaders(true)],
async handler (req, res) {
req.checkParams('code', res.t('couponCodeRequired')).notEmpty();
let validationErrors = req.validationErrors();
if (validationErrors) throw validationErrors;
let valid = false;
let code = couponCode.validate(req.params.code);
if (code) {
let coupon = await Coupon.findOne({_id: code}).exec();
valid = coupon ? true : false;
}
res.respond(200, {valid});
},
};
module.exports = api;
+3 -13
View File
@@ -1,9 +1,9 @@
import { authWithHeaders } from '../../middlewares/api-v3/auth';
import { ensureAdmin } from '../../middlewares/api-v3/ensureAccessRight';
import cron from '../../middlewares/api-v3/cron';
import { model as User } from '../../models/user';
import {
NotFound,
NotAuthorized,
} from '../../libs/api-v3/errors';
import _ from 'lodash';
@@ -90,9 +90,8 @@ const heroAdminFields = 'contributor balance profile.name purchased items auth';
api.getHero = {
method: 'GET',
url: '/hall/heroes/:heroId',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders(), cron, ensureAdmin],
async handler (req, res) {
let user = res.locals.user;
let heroId = req.params.heroId;
req.checkParams('heroId', res.t('heroIdRequired')).notEmpty().isUUID();
@@ -100,10 +99,6 @@ api.getHero = {
let validationErrors = req.validationErrors();
if (validationErrors) throw validationErrors;
if (!user.contributor.admin) {
throw new NotAuthorized(res.t('noAdminAccess'));
}
let hero = await User
.findById(heroId)
.select(heroAdminFields)
@@ -132,9 +127,8 @@ const gemsPerTier = {1: 3, 2: 3, 3: 3, 4: 4, 5: 4, 6: 4, 7: 4, 8: 0, 9: 0};
api.updateHero = {
method: 'PUT',
url: '/hall/heroes/:heroId',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders(), cron, ensureAdmin],
async handler (req, res) {
let user = res.locals.user;
let heroId = req.params.heroId;
let updateData = req.body;
@@ -143,10 +137,6 @@ api.updateHero = {
let validationErrors = req.validationErrors();
if (validationErrors) throw validationErrors;
if (!user.contributor.admin) {
throw new NotAuthorized(res.t('noAdminAccess'));
}
let hero = await User.findById(heroId).exec();
if (!hero) throw new NotFound(res.t('userWithIDNotFound', {userId: heroId}));