Create / Authorize User feature

This commit is contained in:
NGPixel 2017-02-10 01:43:26 -05:00
parent 15e4341fed
commit 85bd64ea8b
7 changed files with 100 additions and 14 deletions

View File

@ -6,6 +6,8 @@ This project adheres to [Semantic Versioning](http://semver.org/).
### Added
- Change log
- Added .editorconfig, .eslintrc.json and .pug-lintrc.json for code linting
- Added Create / Authorize User feature
- Added Login as... button to Forbidden page
### Fixed
- Fixed issue with social accounts with empty name

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,4 +1,4 @@
/* global $, Vue */
/* global $, Vue, alerts */
// Vue Create User instance
@ -8,7 +8,8 @@ let vueCreateUser = new Vue({
email: '',
provider: 'local',
password: '',
name: ''
name: '',
loading: false
},
methods: {
open: (ev) => {
@ -21,7 +22,28 @@ let vueCreateUser = new Vue({
vueCreateUser.provider = 'local'
},
create: (ev) => {
vueCreateUser.cancel()
vueCreateUser.loading = true
$.ajax('/admin/users/create', {
data: {
email: vueCreateUser.email,
provider: vueCreateUser.provider,
password: vueCreateUser.password,
name: vueCreateUser.name
},
dataType: 'json',
method: 'POST'
}).then((rData, rStatus, rXHR) => {
vueCreateUser.loading = false
if (rData.ok) {
vueCreateUser.cancel()
window.location.reload(true)
} else {
alerts.pushError('Something went wrong', rData.msg)
}
}, (rXHR, rStatus, err) => {
vueCreateUser.loading = false
alerts.pushError('Error', rXHR.responseJSON.msg)
})
}
}
})

View File

@ -103,6 +103,65 @@ router.get('/users/:id', (req, res) => {
})
})
/**
* Create / Authorize a new user
*/
router.post('/users/create', (req, res) => {
if (!res.locals.rights.manage) {
return res.status(401).json({ msg: 'Unauthorized' })
}
let nUsr = {
email: _.trim(req.body.email),
provider: _.trim(req.body.provider),
password: req.body.password,
name: _.trim(req.body.name)
}
if (!validator.isEmail(nUsr.email)) {
return res.status(400).json({ msg: 'Invalid email address' })
} else if (!validator.isIn(nUsr.provider, ['local', 'google', 'windowslive', 'facebook'])) {
return res.status(400).json({ msg: 'Invalid provider' })
} else if (nUsr.provider === 'local' && !validator.isLength(nUsr.password, { min: 6 })) {
return res.status(400).json({ msg: 'Password too short or missing' })
} else if (nUsr.provider === 'local' && !validator.isLength(nUsr.name, { min: 2 })) {
return res.status(400).json({ msg: 'Name is missing' })
}
db.User.findOne({ email: nUsr.email, provider: nUsr.provider }).then(exUsr => {
if (exUsr) {
return res.status(400).json({ msg: 'User already exists!' }) || true
}
let pwdGen = (nUsr.provider === 'local') ? db.User.hashPassword(nUsr.password) : Promise.resolve(true)
return pwdGen.then(nPwd => {
if (nUsr.provider !== 'local') {
nUsr.password = ''
nUsr.name = '-- pending --'
} else {
nUsr.password = nPwd
}
nUsr.rights = [{
role: 'read',
path: '/',
exact: false,
deny: false
}]
return db.User.create(nUsr).then(() => {
return res.json({ ok: true })
})
}).catch(err => {
winston.warn(err)
return res.status(500).json({ msg: err })
})
}).catch(err => {
winston.warn(err)
return res.status(500).json({ msg: err })
})
})
router.post('/users/:id', (req, res) => {
if (!res.locals.rights.manage) {
return res.status(401).json({ msg: 'Unauthorized' })

View File

@ -27,3 +27,4 @@ html
h1 Forbidden
h2 Sorry, you don't have the necessary permissions to access this page.
a.button.is-amber.is-inverted(href='/') Go Home
a.button.is-amber.is-inverted(href='/login') Login as...

View File

@ -3,31 +3,33 @@
.modal-background
.modal-container
.modal-content
header.is-blue Create / Authorize User
header.is-blue
span Create / Authorize User
p.modal-notify(v-bind:class='{ "is-active": loading }'): i
section
label.label Email address:
p.control.is-fullwidth
input.input(type='text', placeholder='e.g. john.doe@company.com', v-model='email')
span.help.is-red.is-hidden This email is invalid!
section
label.label Provider:
p.control.is-fullwidth
select(v-model='provider')
option(value='local') Local Database
option(value='windowslive') Microsoft Account
option(value='google') Google ID
option(value='facebook') Facebook
if appconfig.auth.microsoft.enabled
option(value='windowslive') Microsoft Account
if appconfig.auth.google.enabled
option(value='google') Google ID
if appconfig.auth.facebook.enabled
option(value='facebook') Facebook
section(v-if='provider=="local"')
label.label Password:
p.control.is-fullwidth
input.input(type='password', placeholder='', v-model='password')
span.help.is-red.is-hidden This password is invalid!
section(v-if='provider=="local"')
label.label Full Name:
p.control.is-fullwidth
input.input(type='text', placeholder='e.g. John Doe', v-model='name')
span.help.is-red.is-hidden This name is invalid!
footer
a.button.is-grey.is-outlined(v-on:click='cancel') Discard
a.button.is-blue(v-on:click='create', v-if='provider=="local"') Create User
a.button.is-blue(v-on:click='create', v-if='provider!="local"') Authorize User
a.button(v-on:click='create', v-if='provider=="local"', v-bind:disabled='loading', v-bind:class='{ "is-disabled": loading, "is-blue": !loading }') Create User
a.button(v-on:click='create', v-if='provider!="local"', v-bind:disabled='loading', v-bind:class='{ "is-disabled": loading, "is-blue": !loading }') Authorize User