mirror of
https://github.com/HackPlan/RootPanel.git
synced 2026-01-12 22:27:09 +08:00
Router: account
This commit is contained in:
@@ -38,10 +38,6 @@
|
||||
"level": "error",
|
||||
"limitComments": true
|
||||
},
|
||||
"missing_fat_arrows": {
|
||||
"name": "missing_fat_arrows",
|
||||
"level": "warn"
|
||||
},
|
||||
"newlines_after_classes": {
|
||||
"name": "newlines_after_classes",
|
||||
"value": 1,
|
||||
|
||||
@@ -64,7 +64,7 @@ class BillingPlan
|
||||
setupDefaultComponents: (account) ->
|
||||
Q.all _.values(@components).map ({type, defaults}) ->
|
||||
Q.all defaults.map (defaultOptions) ->
|
||||
rp.components.byName(type).createComponent account, defaultOptions(account)
|
||||
root.components.byName(type).createComponent account, defaultOptions(account)
|
||||
|
||||
triggerTimeBilling: (account) ->
|
||||
unless @billing.time
|
||||
|
||||
@@ -79,8 +79,8 @@ module.exports = class I18nManager
|
||||
|
||||
Return {Object}.
|
||||
###
|
||||
packClientLocale: (language) ->
|
||||
return @packLocale @alternativeLanguages language
|
||||
packTranslations: (language) ->
|
||||
return @packTranslationsByLanguages @alternativeLanguages language
|
||||
|
||||
###
|
||||
Public: Get hash of packaged translations by language or request.
|
||||
@@ -89,8 +89,8 @@ module.exports = class I18nManager
|
||||
|
||||
Return {Object}.
|
||||
###
|
||||
localeHash: (language) ->
|
||||
utils.sha256 jsonStableStringify @pickClientLocale language
|
||||
translationsHash: (language) ->
|
||||
utils.sha256 jsonStableStringify @packTranslations language
|
||||
|
||||
###
|
||||
Public: Translate name by languages.
|
||||
@@ -135,9 +135,11 @@ module.exports = class I18nManager
|
||||
|
||||
* `languages` {Array} of {String}
|
||||
|
||||
TODO: Cache.
|
||||
|
||||
Return {Object}.
|
||||
###
|
||||
packLocale: (languages) ->
|
||||
packTranslationsByLanguages: (languages) ->
|
||||
result = {}
|
||||
|
||||
for language in languages
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
expressBunyanLogger = require 'express-bunyan-logger'
|
||||
expressSession = require 'express-session'
|
||||
redisStore = require 'connect-redis'
|
||||
moment = require 'moment-timezone'
|
||||
crypto = require 'crypto'
|
||||
csrf = require 'csrf'
|
||||
path = require 'path'
|
||||
fs = require 'fs'
|
||||
_ = require 'lodash'
|
||||
|
||||
{config} = app
|
||||
{_, path, fs, moment, crypto} = app.libs
|
||||
{Account, SecurityLog} = app.models
|
||||
{Account, SecurityLog, config} = root
|
||||
|
||||
exports.reqHelpers = (req, res, next) ->
|
||||
req.getCsrfToken = ->
|
||||
@@ -36,10 +39,10 @@ exports.reqHelpers = (req, res, next) ->
|
||||
return req.cookies?.timezone ? config.i18n.default_timezone
|
||||
|
||||
req.getTranslator = ->
|
||||
return rp.translatorByReq req
|
||||
return root.i18n.translator req
|
||||
|
||||
req.getMoment = ->
|
||||
return moment.apply(@, arguments).locale(req.getLanguage()).tz(req.getTimezone())
|
||||
return moment.apply(arguments...).locale(req.getLanguage()).tz(req.getTimezone())
|
||||
|
||||
req.createSecurityLog = (type, options, {account, token} = {}) ->
|
||||
SecurityLog.createLog (account ? req.account),
|
||||
@@ -87,6 +90,7 @@ exports.renderHelpers = (req, res, next) ->
|
||||
next()
|
||||
|
||||
exports.logger = ->
|
||||
# TODO: refactor
|
||||
return expressBunyanLogger
|
||||
genReqId: (req) -> req.sessionID
|
||||
parseUA: false
|
||||
@@ -122,7 +126,7 @@ exports.csrf = ->
|
||||
if req.path in app.getHooks('app.ignore_csrf', null, pluck: 'path')
|
||||
return next()
|
||||
|
||||
if req.method in ['GET', 'HEAD', 'OPTIONS']
|
||||
if req.method in ['HEAD', 'OPTIONS']
|
||||
return next()
|
||||
|
||||
unless provider.verify req.session.csrf_secret, req.getCsrfToken()
|
||||
@@ -145,17 +149,15 @@ exports.authenticate = (req, res, next) ->
|
||||
_.extend req,
|
||||
token: token
|
||||
account: account
|
||||
|
||||
.finally next
|
||||
|
||||
exports.requireAuthenticate = (req, res, next) ->
|
||||
if req.account
|
||||
next()
|
||||
else if req.method == 'GET'
|
||||
res.redirect '/account/login/'
|
||||
else
|
||||
if req.method == 'GET'
|
||||
res.redirect '/account/login/'
|
||||
else
|
||||
res.error 403, 'auth_failed'
|
||||
res.error 403, 'auth_failed'
|
||||
|
||||
exports.requireAdminAuthenticate = (req, res, next) ->
|
||||
if req.account?.isAdmin()
|
||||
|
||||
@@ -53,6 +53,14 @@ CouponCode = mabolo.model 'CouponCode',
|
||||
# Public: Apply log of coupon
|
||||
apply_log: [ApplyLog]
|
||||
|
||||
CouponCode.ensureIndex
|
||||
code: 1
|
||||
,
|
||||
unique: true
|
||||
|
||||
CouponCode.findByCode = (code, options...) ->
|
||||
@findOne code: code, options...
|
||||
|
||||
###
|
||||
Public: Create coupons.
|
||||
|
||||
@@ -76,6 +84,9 @@ CouponCode.createCoupons = ({type, options, expired_at, available_times}, count)
|
||||
expired_at: expired_at
|
||||
available_times: available_times
|
||||
|
||||
CouponCode::pick = ->
|
||||
return _.omit @, 'apply_log'
|
||||
|
||||
###
|
||||
Public: Check availability for specified account.
|
||||
|
||||
@@ -84,10 +95,13 @@ CouponCode.createCoupons = ({type, options, expired_at, available_times}, count)
|
||||
Return {Promise} resolve with {Boolean}.
|
||||
###
|
||||
CouponCode::validate = (account) ->
|
||||
if @available_times <= 0
|
||||
return Q false
|
||||
|
||||
@populate().then ->
|
||||
if @available_times != undefined and @available_times <= 0
|
||||
return false
|
||||
|
||||
if @expired and new Date() > @expired
|
||||
return false
|
||||
|
||||
@provider.validate account, @
|
||||
|
||||
###
|
||||
@@ -98,18 +112,19 @@ CouponCode::validate = (account) ->
|
||||
Return {Promise}.
|
||||
###
|
||||
CouponCode::apply = (account) ->
|
||||
if @available_times <= 0
|
||||
throw new Error 'coupon_unavailable'
|
||||
|
||||
@populate().then ->
|
||||
@provider.apply(account, @).then =>
|
||||
@update
|
||||
$inc:
|
||||
available_times: -1
|
||||
$push:
|
||||
apply_log:
|
||||
account_id: account._id
|
||||
created_at: new Date()
|
||||
@validate(account).then (available) ->
|
||||
unless available
|
||||
throw new Error 'coupon_unavailable'
|
||||
.then =>
|
||||
@provider.apply account, @
|
||||
.then =>
|
||||
@update
|
||||
$inc:
|
||||
available_times: -1
|
||||
$push:
|
||||
apply_log:
|
||||
account_id: account._id
|
||||
created_at: new Date()
|
||||
|
||||
###
|
||||
Public: Populate.
|
||||
|
||||
@@ -58,9 +58,9 @@ module.exports = class ViewRegistry
|
||||
|
||||
async.detect([
|
||||
view
|
||||
rp.resolve view
|
||||
rp.resolve 'core', view
|
||||
rp.resolve 'core/view', view
|
||||
root.resolve view
|
||||
root.resolve 'core', view
|
||||
root.resolve 'core/view', view
|
||||
], fs.exists).then (filename) ->
|
||||
fs.read(filename).then (source) ->
|
||||
return jade.compile extendSource(source),
|
||||
|
||||
@@ -1,38 +1,69 @@
|
||||
{_, express} = app.libs
|
||||
{requireAuthenticate} = app.middleware
|
||||
{Account, SecurityLog, CouponCode} = app.models
|
||||
{config, utils, logger, i18n} = app
|
||||
express = require 'express'
|
||||
_ = require 'lodash'
|
||||
|
||||
module.exports = exports = express.Router()
|
||||
utils = require '../utils'
|
||||
|
||||
exports.get '/register', (req, res) ->
|
||||
{i18n, Account, CouponCode} = root
|
||||
{requireAuthenticate} = root.middleware
|
||||
|
||||
module.router = router = express.Router()
|
||||
|
||||
###
|
||||
Router: GET /account/register
|
||||
|
||||
Response HTML.
|
||||
###
|
||||
router.get '/register', (req, res) ->
|
||||
res.render 'account/register'
|
||||
|
||||
exports.get '/login', (req, res) ->
|
||||
###
|
||||
Router: GET /account/login
|
||||
|
||||
Response HTML.
|
||||
###
|
||||
router.get '/login', (req, res) ->
|
||||
res.render 'account/login'
|
||||
|
||||
exports.get '/locale/:language?', (req, res) ->
|
||||
if req.params['language']
|
||||
req.cookies['language'] = req.params['language']
|
||||
###
|
||||
Router: GET /account/translations/:language?
|
||||
|
||||
res.json i18n.pickClientLocale i18n.getLanguagesByReq req
|
||||
Response {Object}.
|
||||
###
|
||||
router.get '/translations/:language?', (req, res) ->
|
||||
if req.params.language
|
||||
res.json i18n.packTranslations req.params.language
|
||||
else
|
||||
res.json i18n.packTranslations req
|
||||
|
||||
exports.get '/preferences', requireAuthenticate, (req, res) ->
|
||||
###
|
||||
Router: GET /account/preferences/edit
|
||||
|
||||
Response HTML.
|
||||
###
|
||||
router.get '/preferences/edit', requireAuthenticate, (req, res) ->
|
||||
res.render 'account/preferences'
|
||||
|
||||
exports.get '/session_info/', (req, res) ->
|
||||
response =
|
||||
csrf_token: req.session.csrf_token
|
||||
###
|
||||
Router: GET /account/self
|
||||
|
||||
if req.account
|
||||
_.extend response,
|
||||
account_id: req.account._id
|
||||
username: req.account.username
|
||||
preferences: req.account.preferences
|
||||
Response {Account} from {Account::pick}
|
||||
###
|
||||
router.get '/self', requireAuthenticate, (req, res) ->
|
||||
res.json req.account.pick 'self'
|
||||
|
||||
res.json response
|
||||
###
|
||||
Router: POST /account/register
|
||||
|
||||
exports.post '/register', (req, res) ->
|
||||
Request {Object}
|
||||
|
||||
* `username` {String}
|
||||
* `email` {String}
|
||||
* `password` {String}
|
||||
|
||||
Response {Token}.
|
||||
Set-Cookie: token.
|
||||
###
|
||||
router.post '/register', (req, res) ->
|
||||
Account.register(req.body).then (account) ->
|
||||
res.createToken account
|
||||
.catch (err) ->
|
||||
@@ -43,7 +74,18 @@ exports.post '/register', (req, res) ->
|
||||
else
|
||||
res.error err
|
||||
|
||||
exports.post '/login', (req, res) ->
|
||||
###
|
||||
Router: POST /account/login
|
||||
|
||||
Request {Object}
|
||||
|
||||
* `username` {String} Username, email or account_id.
|
||||
* `password` {String}
|
||||
|
||||
Response {Token}.
|
||||
Set-Cookie: token, language.
|
||||
###
|
||||
router.post '/login', (req, res) ->
|
||||
Account.search(req.body.username).then (account) ->
|
||||
unless account?.matchPassword req.body.password
|
||||
throw new Error 'wrong_password'
|
||||
@@ -61,14 +103,28 @@ exports.post '/login', (req, res) ->
|
||||
else
|
||||
res.error err
|
||||
|
||||
exports.post '/logout', requireAuthenticate, (req, res) ->
|
||||
req.token.revoke().then ->
|
||||
###
|
||||
Router: POST /account/logout
|
||||
|
||||
Set-Cookie: token.
|
||||
###
|
||||
router.post '/logout', requireAuthenticate, (req, res) ->
|
||||
req.token.revoke().done ->
|
||||
req.createSecurityLog('revoke_token').then ->
|
||||
res.clearCookie('token').sendStatus 204
|
||||
.catch res.error
|
||||
, res.error
|
||||
|
||||
exports.post '/update_password', requireAuthenticate, (req, res) ->
|
||||
Q().then ->
|
||||
###
|
||||
Router: PUT /account/password
|
||||
|
||||
Request {Object}
|
||||
|
||||
* `original_password` {String}
|
||||
* `password` {String}
|
||||
|
||||
###
|
||||
router.put '/password', requireAuthenticate, (req, res) ->
|
||||
Q().done ->
|
||||
unless req.account.matchPassword req.body.original_password
|
||||
throw new Error 'wrong_password'
|
||||
|
||||
@@ -77,10 +133,20 @@ exports.post '/update_password', requireAuthenticate, (req, res) ->
|
||||
|
||||
req.account.setPassword(req.body.password).then ->
|
||||
req.createSecurityLog 'update_password'
|
||||
res.sendStatus 204
|
||||
|
||||
.catch res.error
|
||||
, res.error
|
||||
|
||||
exports.post '/update_email', requireAuthenticate, (req, res) ->
|
||||
###
|
||||
Router: PUT /email
|
||||
|
||||
Request {Object}
|
||||
|
||||
* `email` {String}
|
||||
* `password` {String}
|
||||
|
||||
###
|
||||
router.post '/update_email', requireAuthenticate, (req, res) ->
|
||||
Q().done ->
|
||||
unless req.account.matchPassword req.body.password
|
||||
throw new Error 'wrong_password'
|
||||
@@ -95,46 +161,47 @@ exports.post '/update_email', requireAuthenticate, (req, res) ->
|
||||
original_email: original_email
|
||||
current_email: req.account.email
|
||||
|
||||
res.sendStatus 204
|
||||
|
||||
, req.error
|
||||
|
||||
exports.post '/update_preferences', requireAuthenticate, (req, res) ->
|
||||
###
|
||||
Router: PATCH /account/preferences
|
||||
|
||||
exports.use do ->
|
||||
router = new express.Router()
|
||||
Request {Preferences}.
|
||||
|
||||
router.use requireAuthenticate
|
||||
Response {Preferences}.
|
||||
###
|
||||
router.patch '/preferences', requireAuthenticate, (req, res) ->
|
||||
req.account.updatePreferences(req.body).done (preferences) ->
|
||||
res.json preferences
|
||||
, res.error
|
||||
|
||||
router.get '/info', (req, res) ->
|
||||
CouponCode.findOne
|
||||
code: req.query.code
|
||||
, (err, coupon) ->
|
||||
unless coupon
|
||||
return res.error 'code_not_exist'
|
||||
router.use '/coupons', do (router = express.Router()) ->
|
||||
###
|
||||
Router: GET /account/coupons/:code
|
||||
|
||||
coupon.validateCode req.account, (is_available) ->
|
||||
unless is_available
|
||||
return res.error 'code_not_available'
|
||||
Response {CouponCode}.
|
||||
###
|
||||
router.get '/:code', (req, res) ->
|
||||
CouponCode.findByCode(req.params.code).done (coupon) ->
|
||||
if coupon
|
||||
coupon.populate(req: req).then ->
|
||||
coupon.validate(req.account).then (available) ->
|
||||
res.json _.extend coupon.pick(),
|
||||
available: available
|
||||
else
|
||||
throw new Error 'coupon_not_found'
|
||||
, res.error
|
||||
|
||||
coupon.getMessage req, (message) ->
|
||||
res.json
|
||||
message: message
|
||||
|
||||
router.post '/apply', (req, res) ->
|
||||
CouponCode.findOne
|
||||
code: req.body.code
|
||||
, (err, coupon) ->
|
||||
unless coupon
|
||||
return res.error 'code_not_exist'
|
||||
|
||||
if coupon.expired and Date.now() > coupon.expired.getTime()
|
||||
return res.error 'code_expired'
|
||||
|
||||
if coupon.available_times and coupon.available_times < 0
|
||||
return res.error 'code_not_available'
|
||||
|
||||
coupon.validateCode req.account, (is_available) ->
|
||||
unless is_available
|
||||
return res.error 'code_not_available'
|
||||
|
||||
coupon.applyCode req.account, ->
|
||||
res.json {}
|
||||
###
|
||||
Router: POST /account/coupons/:code/apply
|
||||
###
|
||||
router.post '/:code/apply', requireAuthenticate, (req, res) ->
|
||||
CouponCode.findByCode(req.params.code).done (coupon) ->
|
||||
if coupon
|
||||
coupon.apply(account).then ->
|
||||
res.sendStatus 204
|
||||
else
|
||||
throw new Error 'coupon_not_found'
|
||||
, res.error
|
||||
|
||||
Reference in New Issue
Block a user