diff --git a/app/templates/admin/administer-user-modal.jade b/app/templates/admin/administer-user-modal.jade new file mode 100644 index 000000000..75a6991b2 --- /dev/null +++ b/app/templates/admin/administer-user-modal.jade @@ -0,0 +1,37 @@ +extends /templates/core/modal-base + +block modal-header-content + h3 Administer User + h4 #{user.get('name') || 'Unnamed'} / #{user.get('email')} + span= user.id + + +block modal-body-content + + h3 Stripe Benefit + .form + .form-group + .radio + label + input(type="radio" name="stripe-benefit" value="" checked=none) + | None + .radio + label + input(type="radio" name="stripe-benefit" value="free" checked=free) + | Free + .radio + label + input(type="radio" name="stripe-benefit" value="free-until" checked=FreeUntil) + | Free Until + input.form-control.spl(type="date" name="stripe-free-until" value=freeUntilDate)#free-until-date + .radio + label + input(type="radio" name="stripe-benefit" value="coupon" checked=coupon) + | Coupon + select.form-control#coupon-select + for couponOption in coupons + option(value=couponOption.id selected=coupon===couponOption.id)= couponOption.format + +block modal-footer-content + button#save-changes.btn.btn-primary Save Changes + diff --git a/app/views/admin/AdministerUserModal.coffee b/app/views/admin/AdministerUserModal.coffee new file mode 100644 index 000000000..4828b7967 --- /dev/null +++ b/app/views/admin/AdministerUserModal.coffee @@ -0,0 +1,62 @@ +ModalView = require 'views/core/ModalView' +template = require 'templates/admin/administer-user-modal' +User = require 'models/User' + +module.exports = class AdministerUserModal extends ModalView + id: "administer-user-modal" + template: template + plain: true + + events: + 'click #save-changes': 'onSaveChanges' + + constructor: (options, @userHandle) -> + super(options) + @user = @supermodel.loadModel(new User({_id:@userHandle}), 'user').model + options = {url: '/stripe/coupons'} + options.success = (@coupons) => + @couponsResource = @supermodel.addRequestResource('coupon', options) + @couponsResource.load() + + getRenderData: -> + c = super() + stripe = @user.get('stripe') or {} + c.free = stripe.free is true + c.freeUntil = _.isString(stripe.free) + c.freeUntilDate = if c.freeUntil then stripe.free else new Date().toISOString()[...10] + c.coupon = stripe.couponID + c.coupons = @coupons or [] + for coupon in c.coupons + bits = [coupon.id] + if coupon.percent_off + bits.push "(#{coupon.percent_off}% off)" + else if coupon.amount_off + bits.push "($#{coupon.amount_off} off)" + if coupon.duration + bits.push "(duration: #{coupon.duration})" + if coupon.redeem_by + bits.push "(redeem by: #{moment(coupon.redeem_by).format('lll')}" + coupon.format = bits.join(' ') + c.none = not (c.free or c.freeUntil or c.coupon) + c.user = @user + c + + onSaveChanges: -> + stripe = _.clone(@user.get('stripe') or {}) + delete stripe.free + delete stripe.couponID + + selection = @$el.find('input[name="stripe-benefit"]:checked').val() + dateVal = @$el.find('#free-until-date').val() + couponVal = @$el.find('#coupon-select').val() + switch selection + when 'free' then stripe.free = true + when 'free-until' then stripe.free = dateVal + when 'coupon' then stripe.couponID = couponVal + + @user.set('stripe', stripe) + options = {} + options.success = => @hide() + @user.patch(options) + + \ No newline at end of file diff --git a/app/views/admin/MainAdminView.coffee b/app/views/admin/MainAdminView.coffee index f35bfe1eb..e05dd20a9 100644 --- a/app/views/admin/MainAdminView.coffee +++ b/app/views/admin/MainAdminView.coffee @@ -1,6 +1,7 @@ {backboneFailure, genericFailure} = require 'core/errors' RootView = require 'views/core/RootView' template = require 'templates/admin' +AdministerUserModal = require 'views/admin/AdministerUserModal' module.exports = class MainAdminView extends RootView id: 'admin-view' @@ -12,6 +13,7 @@ module.exports = class MainAdminView extends RootView 'click #enter-espionage-mode': 'enterEspionageMode' 'click #user-search-button': 'searchForUser' 'click #increment-button': 'incrementUserAttribute' + 'click #user-search-result': 'onClickUserSearchResult' checkForFormSubmissionEnterPress: (e) -> if e.which is 13 and @$el.find('#espionage-name-or-email').val() isnt '' @@ -47,7 +49,7 @@ module.exports = class MainAdminView extends RootView onSearchRequestSuccess: (users) => result = '' if users.length - result = ("#{user._id}#{_.escape(user.name or 'Anoner')}#{_.escape(user.email)}" for user in users) + result = ("#{user._id}#{_.escape(user.name or 'Anoner')}#{_.escape(user.email)}" for user in users) result = "#{result.join('\n')}
" @$el.find('#user-search-result').html(result) @@ -59,3 +61,7 @@ module.exports = class MainAdminView extends RootView val = $('#increment-field').val() me.set(val, me.get(val) + 1) me.save() + + onClickUserSearchResult: (e) -> + userID = $(e.target).closest('tr').data('user-id') + @openModalView new AdministerUserModal({}, userID) if userID diff --git a/server/routes/stripe.coffee b/server/routes/stripe.coffee index 2a9951065..8559ea3a8 100644 --- a/server/routes/stripe.coffee +++ b/server/routes/stripe.coffee @@ -2,9 +2,10 @@ config = require '../../server_config' stripe = require('stripe')(config.stripe.secretKey) User = require '../users/User' Payment = require '../payments/Payment' +errors = require '../commons/errors' module.exports.setup = (app) -> - app.post '/stripe/webhook', (req, res, next) -> + app.post '/stripe/webhook', (req, res) -> if req.body.type is 'invoice.payment_succeeded' # if they actually paid, give em some gems invoiceID = req.body.data.object.id @@ -61,4 +62,13 @@ module.exports.setup = (app) -> return res.send(200, '') else # ignore all other notifications - return res.send(200, '') \ No newline at end of file + return res.send(200, '') + + app.get '/stripe/coupons', (req, res) -> + return errors.forbidden(res) unless req.user?.isAdmin() + stripe.coupons.list {limit: 100}, (err, coupons) -> + return errors.serverError(res) if err + res.send(200, coupons.data) + return res.end() + + \ No newline at end of file