From b4d799751603601caf471759e141128c452bc210 Mon Sep 17 00:00:00 2001 From: HerrHase Date: Mon, 6 Sep 2021 09:30:21 +0200 Subject: [PATCH] middleware for user --- public/js/bucket-single.js | 12 +- public/js/create-bucket.js | 12 +- public/js/users.js | 56 ++++----- resources/js/components/users.riot | 6 +- resources/js/components/users/form.riot | 9 +- server.ts | 6 +- src/http/api/user.ts | 149 ------------------------ src/http/api/users.ts | 98 ++++++++-------- src/middleware/users.ts | 51 ++++++++ src/repositories/user.ts | 6 +- 10 files changed, 156 insertions(+), 249 deletions(-) delete mode 100644 src/http/api/user.ts create mode 100644 src/middleware/users.ts diff --git a/public/js/bucket-single.js b/public/js/bucket-single.js index 6dfa499..6202e9e 100644 --- a/public/js/bucket-single.js +++ b/public/js/bucket-single.js @@ -124,7 +124,7 @@ __webpack_require__.r(__webpack_exports__); getComponent ) { return template( - '
', + '
', [ { 'type': bindingTypes.IF, @@ -135,11 +135,11 @@ __webpack_require__.r(__webpack_exports__); return _scope.state.errors.length > 0; }, - 'redundantAttribute': 'expr0', - 'selector': '[expr0]', + 'redundantAttribute': 'expr2', + 'selector': '[expr2]', 'template': template( - '', + '', [ { 'type': bindingTypes.EACH, @@ -170,8 +170,8 @@ __webpack_require__.r(__webpack_exports__); ] ), - 'redundantAttribute': 'expr1', - 'selector': '[expr1]', + 'redundantAttribute': 'expr3', + 'selector': '[expr3]', 'itemName': 'error', 'indexName': null, diff --git a/public/js/create-bucket.js b/public/js/create-bucket.js index f1c7276..240d618 100644 --- a/public/js/create-bucket.js +++ b/public/js/create-bucket.js @@ -124,7 +124,7 @@ __webpack_require__.r(__webpack_exports__); getComponent ) { return template( - '
', + '
', [ { 'type': bindingTypes.IF, @@ -135,11 +135,11 @@ __webpack_require__.r(__webpack_exports__); return _scope.state.errors.length > 0; }, - 'redundantAttribute': 'expr0', - 'selector': '[expr0]', + 'redundantAttribute': 'expr2', + 'selector': '[expr2]', 'template': template( - '', + '', [ { 'type': bindingTypes.EACH, @@ -170,8 +170,8 @@ __webpack_require__.r(__webpack_exports__); ] ), - 'redundantAttribute': 'expr1', - 'selector': '[expr1]', + 'redundantAttribute': 'expr3', + 'selector': '[expr3]', 'itemName': 'error', 'indexName': null, diff --git a/public/js/users.js b/public/js/users.js index 36584f5..1c850ce 100644 --- a/public/js/users.js +++ b/public/js/users.js @@ -124,7 +124,7 @@ __webpack_require__.r(__webpack_exports__); getComponent ) { return template( - '
', + '
', [ { 'type': bindingTypes.IF, @@ -135,11 +135,11 @@ __webpack_require__.r(__webpack_exports__); return _scope.state.errors.length > 0; }, - 'redundantAttribute': 'expr0', - 'selector': '[expr0]', + 'redundantAttribute': 'expr2', + 'selector': '[expr2]', 'template': template( - '', + '', [ { 'type': bindingTypes.EACH, @@ -170,8 +170,8 @@ __webpack_require__.r(__webpack_exports__); ] ), - 'redundantAttribute': 'expr1', - 'selector': '[expr1]', + 'redundantAttribute': 'expr3', + 'selector': '[expr3]', 'itemName': 'error', 'indexName': null, @@ -215,7 +215,7 @@ __webpack_require__.r(__webpack_exports__); getComponent ) { return template( - '
', + '
', [ { 'type': bindingTypes.IF, @@ -226,8 +226,8 @@ __webpack_require__.r(__webpack_exports__); return _scope.props.loading; }, - 'redundantAttribute': 'expr32', - 'selector': '[expr32]', + 'redundantAttribute': 'expr36', + 'selector': '[expr36]', 'template': template( '', @@ -316,18 +316,18 @@ __webpack_require__.r(__webpack_exports__); getComponent ) { return template( - '', + '', [ { 'type': bindingTypes.SLOT, 'attributes': [], 'name': 'title', - 'redundantAttribute': 'expr33', - 'selector': '[expr33]' + 'redundantAttribute': 'expr32', + 'selector': '[expr32]' }, { - 'redundantAttribute': 'expr34', - 'selector': '[expr34]', + 'redundantAttribute': 'expr33', + 'selector': '[expr33]', 'expressions': [ { @@ -347,8 +347,8 @@ __webpack_require__.r(__webpack_exports__); ] }, { - 'redundantAttribute': 'expr35', - 'selector': '[expr35]', + 'redundantAttribute': 'expr34', + 'selector': '[expr34]', 'expressions': [ { @@ -364,8 +364,8 @@ __webpack_require__.r(__webpack_exports__); ] }, { - 'redundantAttribute': 'expr36', - 'selector': '[expr36]', + 'redundantAttribute': 'expr35', + 'selector': '[expr35]', 'expressions': [ { @@ -471,11 +471,11 @@ __webpack_require__.r(__webpack_exports__); getComponent ) { return template( - '', + '', [ { - 'redundantAttribute': 'expr2', - 'selector': '[expr2]', + 'redundantAttribute': 'expr0', + 'selector': '[expr0]', 'expressions': [ { @@ -494,8 +494,8 @@ __webpack_require__.r(__webpack_exports__); 'type': bindingTypes.SLOT, 'attributes': [], 'name': 'default', - 'redundantAttribute': 'expr3', - 'selector': '[expr3]' + 'redundantAttribute': 'expr1', + 'selector': '[expr1]' } ] ); @@ -547,7 +547,7 @@ riot__WEBPACK_IMPORTED_MODULE_3__.mount('app-modal') /** * - * @param {[type]} event + * @param {[type]} event * @param {[type]} user * @return {[type]} * @@ -567,7 +567,7 @@ riot__WEBPACK_IMPORTED_MODULE_3__.mount('app-modal') const customEvent = new CustomEvent('open', { 'detail': { 'confirm': () => { - axios__WEBPACK_IMPORTED_MODULE_0___default().delete('/api/users/' + user._id) + axios__WEBPACK_IMPORTED_MODULE_0___default().delete('/api/users/v1/' + user._id) .then((response) => { // removing from buckets @@ -593,7 +593,7 @@ riot__WEBPACK_IMPORTED_MODULE_3__.mount('app-modal') * */ fetch() { - axios__WEBPACK_IMPORTED_MODULE_0___default().get('/api/users').then((response) => { + axios__WEBPACK_IMPORTED_MODULE_0___default().get('/api/users/v1').then((response) => { this.state.users = response.data.data this.update() }) @@ -917,7 +917,7 @@ riot__WEBPACK_IMPORTED_MODULE_4__.mount('app-loading') handleSubmit(event, data) { let method = 'post' - let url = '/api/users' + let url = '/api/users/v1' // user is set and has id, send as put with id if (this.state.user && this.state.user._id) { @@ -934,6 +934,8 @@ riot__WEBPACK_IMPORTED_MODULE_4__.mount('app-loading') data: data }).then((response) => { + console.log(response) + this.state.user = response.data.data // check if submit has close-attribute diff --git a/resources/js/components/users.riot b/resources/js/components/users.riot index 24ecc78..bacfdc6 100644 --- a/resources/js/components/users.riot +++ b/resources/js/components/users.riot @@ -106,7 +106,7 @@ /** * - * @param {[type]} event + * @param {[type]} event * @param {[type]} user * @return {[type]} * @@ -126,7 +126,7 @@ const customEvent = new CustomEvent('open', { 'detail': { 'confirm': () => { - axios.delete('/api/users/' + user._id) + axios.delete('/api/users/v1/' + user._id) .then((response) => { // removing from buckets @@ -152,7 +152,7 @@ * */ fetch() { - axios.get('/api/users').then((response) => { + axios.get('/api/users/v1').then((response) => { this.state.users = response.data.data this.update() }) diff --git a/resources/js/components/users/form.riot b/resources/js/components/users/form.riot index 678271f..1c25655 100644 --- a/resources/js/components/users/form.riot +++ b/resources/js/components/users/form.riot @@ -171,7 +171,7 @@ handleSubmit(event, data) { let method = 'post' - let url = '/api/users' + let url = '/api/users/v1' // user is set and has id, send as put with id if (this.state.user && this.state.user._id) { @@ -188,14 +188,17 @@ data: data }).then((response) => { - this.state.user = response.data.data + this.state.loading = false + + if (response.status === 201) { + this.state.user = response.data.data + } // check if submit has close-attribute if (event.submitter.attributes.close) { this.$('#sidebar-user-form-close').click() } - this.state.loading = false this.update() }) }, diff --git a/server.ts b/server.ts index be24fe2..ad17609 100644 --- a/server.ts +++ b/server.ts @@ -43,11 +43,11 @@ app.set('view engine', 'html') app.use('*', session) app.use('/', home) - app.use('/buckets', buckets) - app.use('/users', users) -app.use('/api/users', usersApi) + +// routes: api +app.use('/api/users/v1', usersApi) //app.use('/api/bucket', bucketApi) //app.use('/api/note', noteApi) diff --git a/src/http/api/user.ts b/src/http/api/user.ts deleted file mode 100644 index 3e8975e..0000000 --- a/src/http/api/user.ts +++ /dev/null @@ -1,149 +0,0 @@ -import { v4 } from "https://deno.land/std@0.99.0/uuid/mod.ts"; -import { validate, required, isIn, maxLength } from 'https://deno.land/x/validasaur@v0.15.0/mod.ts' - -import { Database } from 'https://deno.land/x/aloedb@0.9.0/mod.ts' -import { UserSchema } from './../../stores/user.ts' - -import { Router } from 'https://deno.land/x/opine@1.5.3/mod.ts' - -const router = Router() - - -/** - * get all users - * - * @param request - * @param response - * @return - * - */ -router.get('/', async function(request, response) -{ - const userRepository = new UserRepository() - const users = await userRepository.db.findAll() - - response.json({ - data: user - }) -}) - -/** - * create user - * - * @param request - * @param response - * @return - * - */ -router.get('/:id', async function(request, response) -{ - const userRepository = new UserRepository() - - const [ valid, errors ] = await validate(request.params, { - id: [ required, uuid ] - }) - - if (valid) { - const user = await userRepository.db.findOne({ - '_id': request.params.id - }) - - if (!user) { - response.setStatus(404) - } - - } else { - response.setStatus(405) - } - - response.json({ - data: user - }) -}) - -/** - * create user - * - * @param request - * @param response - * @return - * - */ -router.post('/', async function(request, response) -{ - const body = request.body - const userRepository = new UserRepository() - - const [ valid, errors ] = await validate(body, { - email: [ email, required ] - }) - - if (valid) { - user = await userRepository.create(body) - } - - response.json({ - data: user - }) -}) - -/** - * - * - * @param request - * @param response - * @return - */ -router.put('/:id', async function(request, response, next) -{ - const body = request.body - const userRepository = new UserRepository() - - let user = false - - const [ valid, errors ] = await validate(body, { - _id: [ required, uuid, exists ], - email: [ email, required, unique ], - password: [ maxLength(64) ], - displayname: [ maxLength(128) ], - role: [ array() ] - }) - - if (valid) { - user = userRepository.update(body) - } - - response.json({ - data: user - }) -}) - -/** - * - * - * @param request - * @param response - * @return - * - */ -router.delete('/:id', function(request, response) -{ - const userRepository = new UserRepository() - let user = false - - const [ valid, errors ] = await validate(request.params, { - '_id': [ required, uuid, exists ] - }) - - if (valid) { - user = userRepository.db.deleteOne({ - '_id': request.params._id - }) - } - - response.json({ - data: user - }) -}) - -export default router \ No newline at end of file diff --git a/src/http/api/users.ts b/src/http/api/users.ts index 521909a..d0ee128 100644 --- a/src/http/api/users.ts +++ b/src/http/api/users.ts @@ -1,11 +1,16 @@ +import { v4 } from "https://deno.land/std@0.99.0/uuid/mod.ts"; +import { validate, required, maxLength, isEmail } from 'https://deno.land/x/validasaur@v0.15.0/mod.ts' + import { Router } from 'https://deno.land/x/opine@1.5.3/mod.ts' -import UserRepository from '../../repositories/user.ts' -import { validate, required, maxLength, isEmail } from 'https://deno.land/x/validasaur@v0.15.0/mod.ts' -import { uuid } from '../../rules/uuid.ts' +import usersMiddleware from '../../middleware/users.ts' +import UserRepository from '../../repositories/user.ts' const router = Router() +// check for id and load user +router.param('id', usersMiddleware) + /** * get all users * @@ -26,6 +31,21 @@ router.get('/', async function(request, response) }) }) +/** + * get user + * + * @param request + * @param response + * @return + * + */ +router.get('/:id', async function(request, response) +{ + response.json({ + data: response.locals.user + }) +}) + /** * create user * @@ -39,23 +59,24 @@ router.post('/', async function(request, response) const body = request.body const userRepository = new UserRepository() - // @TODO check for permission of current user - let user const [ valid, errors ] = await validate(body, { - email: [ isEmail, maxLength(255), required ], - password: [ required, maxLength(64) ] + email: [ isEmail, required ], + password: [ maxLength(64) ], + displayname: [ maxLength(128) ] }) if (valid) { user = await userRepository.create(body) - - // remove password - // @TODO make sure repository can hide variables - delete user.password + } else { + response.setStatus(422) + response.json({ + 'errors': errors + }) } + response.setStatus(201) response.json({ data: user }) @@ -67,42 +88,30 @@ router.post('/', async function(request, response) * @param request * @param response * @return - * */ -router.put('/:id', async function(request, response) +router.put('/:id', async function(request, response, next) { const body = request.body const userRepository = new UserRepository() - // @TODO check for permission of current user - let user - const [ validUser, errorsUser ] = await validate(request.params, { - 'id': [ required, uuid ] - }) - - if (!validUser) { - response.json({ - data: user - }) - } - const [ valid, errors ] = await validate(body, { - email: [ isEmail, maxLength(255), required ], - password: [ maxLength(64) ] + email: [ isEmail, required ], + password: [ maxLength(64) ], + displayname: [ maxLength(128) ] }) if (valid) { - - body._id = request.params.id - user = await userRepository.update(body) - - // remove password - // @TODO make sure repository can hide variables - delete user.password + user = await userRepository.update(response.locals.user._id, body) + } else { + response.setStatus(422) + response.json({ + 'errors': errors + }) } + response.setStatus(201) response.json({ data: user }) @@ -116,26 +125,17 @@ router.put('/:id', async function(request, response) * @return * */ -router.delete('/:id', async function(request, response) +router.delete('/:id', function(request, response) { const userRepository = new UserRepository() - // @TODO check for permission of current user - let user = false - - const [ valid, errors ] = await validate(request.params, { - 'id': [ required, uuid ] + // delete user + const user = userRepository.db.deleteOne({ + '_id': response.locals.user._id }) - if (valid) { - user = userRepository.db.deleteOne({ - '_id': request.params.id - }) - } - - response.json({ - data: user - }) + // send status + response.send(204) }) export default router \ No newline at end of file diff --git a/src/middleware/users.ts b/src/middleware/users.ts new file mode 100644 index 0000000..01ac836 --- /dev/null +++ b/src/middleware/users.ts @@ -0,0 +1,51 @@ +import { Router } from 'https://deno.land/x/opine@1.5.3/mod.ts' +import { validate, required } from 'https://deno.land/x/validasaur@v0.15.0/mod.ts' +import { uuid } from '../rules/uuid.ts' + +import UserRepository from '../repositories/user.ts' + +const router = Router() + +/** + * check every route for single bucket + * + * @param request + * @param response + * @param next + * @return + */ +async function usersMiddleware(request: any, response: any, next: any) +{ + // max for id + request.params.id = request.params.id.slice(0, 128) + + // only dash, numbers & letters are allowed + request.params.id = request.params.id.replace(/[^a-z0-9-]/gi, '') + + const [ valid, errors ] = await validate(request.params, { + id: [ uuid ] + }) + + // if invalid send 404 + if (!valid) { + response + .setStatus(404) + .send() + } + + // getting + const userRepository = new UserRepository() + const user = await userRepository.db.findOne({ '_id': request.params.id }) + + // if not exists send 404 + if (!user) { + response + .setStatus(404) + .send() + } + + response.locals.user = user + next() +} + +export default usersMiddleware \ No newline at end of file diff --git a/src/repositories/user.ts b/src/repositories/user.ts index 3e8ffb9..c7225ad 100644 --- a/src/repositories/user.ts +++ b/src/repositories/user.ts @@ -33,16 +33,16 @@ class UserRepository /** * */ - async update(data: any) + async update(id: any, data: any) { - const user = await this.db.findOne({ '_id': data._id }) + const user = await this.db.findOne({ '_id': id }) // if password has changed hash password new if (user && user.password !== data.password) { data.password = await bcrypt.hash(data.password) } - return await this.db.updateOne({ '_id': data._id }, data) + return await this.db.updateOne({ '_id': id }, data) } }