| @ -0,0 +1,86 @@ | |||||
| <app-users> | |||||
| <div class="buckets"> | |||||
| <table class="table"> | |||||
| <div class="table__row" each={ user in state.users }> | |||||
| <div class="table__column"> | |||||
| { user.username } | |||||
| </div> | |||||
| <div class="table__column"> | |||||
| { user.email } | |||||
| </div> | |||||
| <div class="table__column"> | |||||
| </div> | |||||
| </div> | |||||
| </table> | |||||
| <div class="grid" if={ state.maxLength > state.users.length }> | |||||
| <div class="col-12"> | |||||
| <div class="buckets__more"> | |||||
| <button type="button" class="button" onclick={ handleClick }> | |||||
| More | |||||
| <svg class="icon" aria-hidden="true"> | |||||
| <use xlink:href="/symbol-defs.svg#icon-arrow-down"></use> | |||||
| </svg> | |||||
| </button> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| <script> | |||||
| import axios from 'axios' | |||||
| import remove from 'lodash.remove' | |||||
| /** | |||||
| * | |||||
| * | |||||
| * | |||||
| * @author Björn Hase | |||||
| * | |||||
| */ | |||||
| export default { | |||||
| state: { | |||||
| users: [], | |||||
| maxLength: 0 | |||||
| }, | |||||
| onBeforeMount() { | |||||
| this.fetch() | |||||
| }, | |||||
| handleClick() { | |||||
| }, | |||||
| handleDelete(event, bucket) { | |||||
| event.preventDefault() | |||||
| axios.delete('/api/bucket/' + bucket._id) | |||||
| .then((response) => { | |||||
| // removing from buckets | |||||
| remove(this.state.buckets, function(b) { | |||||
| return b._id === bucket._id | |||||
| }) | |||||
| this.update() | |||||
| }) | |||||
| }, | |||||
| /** | |||||
| * getting all buckets | |||||
| * | |||||
| * | |||||
| */ | |||||
| fetch() { | |||||
| axios.get('/api/users').then((response) => { | |||||
| this.state.users = response.data.data | |||||
| this.update() | |||||
| }) | |||||
| } | |||||
| } | |||||
| </script> | |||||
| </app-users> | |||||
| @ -0,0 +1,128 @@ | |||||
| <app-users-form> | |||||
| <div class="sidebar sidebar--open"> | |||||
| <div class="sidebar__inner"> | |||||
| <div class="bar"> | |||||
| <div class="bar__main"> | |||||
| Create User | |||||
| </div> | |||||
| <div class="bar__end"> | |||||
| <button class="button button--transparent" type="button" onclick={ (event) => { handleClose(event) } }> | |||||
| <svg class="icon fill-text-contrast" aria-hidden="true"> | |||||
| <use xlink:href="/symbol-defs.svg#icon-close"></use> | |||||
| </svg> | |||||
| </button> | |||||
| </div> | |||||
| </div> | |||||
| <div class="sidebar__body"> | |||||
| <form id="app-users-form"> | |||||
| <div class="field-group"> | |||||
| <label class="field-label"> | |||||
| <input name="email" type="text" class="field-text" /> | |||||
| </label> | |||||
| <field-error name="email"></field-error> | |||||
| </div> | |||||
| <div class="field-group"> | |||||
| <label class="field-label"> | |||||
| Password | |||||
| <input name="password" type="password" class="field-text" /> | |||||
| </label> | |||||
| <field-error name="password"></field-error> | |||||
| </div> | |||||
| </form> | |||||
| </div> | |||||
| <div class="sidebar__footer"> | |||||
| <button class="button m-bottom-0" type="submit" form="app-users-form"> | |||||
| Save | |||||
| <svg class="icon fill-success p-left-3" aria-hidden="true"> | |||||
| <use xlink:href="/symbol-defs.svg#icon-check"></use> | |||||
| </svg> | |||||
| </button> | |||||
| <button class="button m-bottom-0" type="submit" form="app-users-form"> | |||||
| Save and Close | |||||
| <svg class="icon fill-success p-left-3" aria-hidden="true"> | |||||
| <use xlink:href="/symbol-defs.svg#icon-arrow-right"></use> | |||||
| </svg> | |||||
| </button> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| <script> | |||||
| import axios from 'axios' | |||||
| import * as riot from 'riot' | |||||
| import FormValidator from './../../FormValidator' | |||||
| import FieldError from './../field-error.riot' | |||||
| riot.register('field-error', FieldError) | |||||
| riot.mount('field-error') | |||||
| export default { | |||||
| state: { | |||||
| user: { } | |||||
| }, | |||||
| /** | |||||
| * | |||||
| * | |||||
| */ | |||||
| onMounted(props, state) { | |||||
| // create form validation | |||||
| const formValidation = new FormValidator('app-users-form', { | |||||
| 'email': { | |||||
| 'length': { | |||||
| 'maximum': 255 | |||||
| }, | |||||
| 'email': true, | |||||
| 'presence': true | |||||
| }, | |||||
| 'password': { | |||||
| 'length': { | |||||
| 'maximum': 64 | |||||
| }, | |||||
| 'presence': true | |||||
| } | |||||
| }, (event, data) => { | |||||
| this.handleSubmit(event, data) | |||||
| }) | |||||
| }, | |||||
| handleClose(event) | |||||
| { | |||||
| event.preventDefault() | |||||
| this.$('.sidebar').classList.remove('sidebar--open') | |||||
| }, | |||||
| /** | |||||
| * | |||||
| * | |||||
| */ | |||||
| handleSubmit(event, data) { | |||||
| let method = 'post' | |||||
| if (this.state.user && this.state.user._id) { | |||||
| method = 'put' | |||||
| } | |||||
| axios({ | |||||
| method: method, | |||||
| url: '/api/users', | |||||
| data: data | |||||
| }).then((response) => { | |||||
| this.state.user = response.data.data | |||||
| this.update() | |||||
| }) | |||||
| } | |||||
| } | |||||
| </script> | |||||
| </app-users-form> | |||||
| @ -0,0 +1,11 @@ | |||||
| import * as riot from 'riot' | |||||
| import AppUsers from './components/users.riot' | |||||
| import AppUsersForm from './components/users/form.riot' | |||||
| // register components for buckets | |||||
| riot.register('app-users', AppUsers) | |||||
| riot.mount('app-users') | |||||
| riot.register('app-users-form', AppUsersForm) | |||||
| riot.mount('app-users-form') | |||||
| @ -0,0 +1,68 @@ | |||||
| .sidebar { | |||||
| position: fixed; | |||||
| top: 0; | |||||
| left: 0; | |||||
| width: 100%; | |||||
| height: 100%; | |||||
| max-width: 33%; | |||||
| z-index: 1; | |||||
| visibility: hidden; | |||||
| transition: visibility 0s linear 0.5s; | |||||
| &__body { | |||||
| @extend .panel__body; | |||||
| } | |||||
| &__inner { | |||||
| @extend .panel; | |||||
| position: relative; | |||||
| height: 100%; | |||||
| transition: transform 0.2s; | |||||
| transform: translateX(-100%); | |||||
| } | |||||
| &__footer { | |||||
| position: fixed; | |||||
| left: 0; | |||||
| bottom: 0; | |||||
| display: flex; | |||||
| justify-content: space-between; | |||||
| background: var(--background); | |||||
| width: 100%; | |||||
| padding: 1rem; | |||||
| } | |||||
| &:before { | |||||
| position: fixed; | |||||
| top: 0; | |||||
| left: 0; | |||||
| width: 100%; | |||||
| height: 100%; | |||||
| background-color: transparent; | |||||
| transition: background-color 0.5s; | |||||
| z-index: 0; | |||||
| content: ""; | |||||
| } | |||||
| &--open { | |||||
| visibility: visible; | |||||
| transition: visibility 0s linear 0s; | |||||
| .sidebar__inner { | |||||
| transform: translateX(0); | |||||
| } | |||||
| &:before { | |||||
| background: rgba(0,0,0,.7); | |||||
| } | |||||
| } | |||||
| } | |||||
| @ -0,0 +1,15 @@ | |||||
| <% layout('./layout.html') %> | |||||
| <div class="container container--app"> | |||||
| <div class="grid"> | |||||
| <div class="col-12"> | |||||
| <h1 class="highlight"> | |||||
| Users | |||||
| </h1> | |||||
| <app-users></app-users> | |||||
| <app-users-form></app-users-form> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| <script type="text/javascript" src="/js/users.js" defer></script> | |||||
| @ -0,0 +1,57 @@ | |||||
| import 'https://deno.land/x/dotenv@v2.0.0/load.ts' | |||||
| import { | |||||
| opine, | |||||
| serveStatic, | |||||
| json, | |||||
| urlencoded | |||||
| } from 'https://deno.land/x/opine@1.5.3/mod.ts' | |||||
| import { dirname, join, createError } from "https://deno.land/x/opine@1.5.3/deps.ts"; | |||||
| import { renderFile } from 'https://deno.land/x/eta@v1.12.2/mod.ts' | |||||
| // middleware | |||||
| import session from './src/middleware/session.ts' | |||||
| // getting routes | |||||
| import index from './src/http/index.ts' | |||||
| //import bucket from './src/http/bucket.ts' | |||||
| //import settings from './src/http/settings.ts' | |||||
| import users from './src/http/users.ts' | |||||
| //import bucketApi from './src/http/api/bucket.ts' | |||||
| //import noteApi from './src/http/api/note.ts' | |||||
| const app = opine() | |||||
| const __dirname = dirname(import.meta.url) | |||||
| // for parsing application/json | |||||
| app.use(json()) | |||||
| // for parsing application/x-www-form-urlencoded | |||||
| app.use(urlencoded()) | |||||
| // adding static files | |||||
| app.use(serveStatic(join(__dirname, 'public'))) | |||||
| // adding eta as view engine | |||||
| app.engine('.html', renderFile) | |||||
| app.set('views', join(__dirname, 'resources/views')) | |||||
| app.set('view engine', 'html') | |||||
| // adding http classes for routes | |||||
| app.use('*', session) | |||||
| app.use('/', index) | |||||
| //app.use('/bucket', bucket) | |||||
| //app.use('/settings', settings) | |||||
| app.use('/users', users) | |||||
| //app.use('/api/bucket', bucketApi) | |||||
| //app.use('/api/note', noteApi) | |||||
| app.use((request, response, next) => { | |||||
| response.setStatus(404) | |||||
| response.render('errors/404') | |||||
| }) | |||||
| // let it rain | |||||
| app.listen(Number(Deno.env.get('SERVER_PORT'))) | |||||
| console.log('running on ' + Deno.env.get('SERVER_PORT')) | |||||
| @ -0,0 +1,93 @@ | |||||
| 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 { BucketSchema } from './../../stores/bucket.ts' | |||||
| import { NoteSchema } from './../../stores/note.ts' | |||||
| import { Router } from 'https://deno.land/x/opine@1.5.3/mod.ts' | |||||
| const router = Router() | |||||
| /** | |||||
| * | |||||
| * | |||||
| * @param request | |||||
| * @param response | |||||
| * @return | |||||
| */ | |||||
| router.post('/:bucket_id', async function(request, response) | |||||
| { | |||||
| const body = request.body | |||||
| const [ valid, errors ] = await validate(body, { | |||||
| title: [ maxLength(255) ], | |||||
| content: [ maxLength(10922) ] | |||||
| }) | |||||
| if (valid) { | |||||
| const noteRepository = new NoteRepository(request.bucket._id) | |||||
| note = await db.insertOne(body) | |||||
| } | |||||
| response.json({ | |||||
| data: note | |||||
| }) | |||||
| }) | |||||
| /** | |||||
| * | |||||
| * | |||||
| * @param request | |||||
| * @param response | |||||
| * @return | |||||
| */ | |||||
| router.put('/:bucket_id', async function(request, response, next) | |||||
| { | |||||
| const body = request.body | |||||
| let note | |||||
| // check if uuid is valid | |||||
| if (!v4.validate(request.params.bucket_id)) { | |||||
| response.setStatus(404) | |||||
| } | |||||
| // check if bucket exists | |||||
| const bucketDb = new Database<BucketSchema>('./storage/database/buckets.json') | |||||
| const bucket = await bucketDb.findOne({ _id: request.params.bucket_id }) | |||||
| if (!bucket) { | |||||
| response.setStatus(404) | |||||
| } | |||||
| const [ valid, errors ] = await validate(body, { | |||||
| title: [ maxLength(255) ], | |||||
| content: [ maxLength(10922) ] | |||||
| }) | |||||
| if (valid && bucket) { | |||||
| // getting database and search by uuid | |||||
| const db = new Database<NoteSchema>('./storage/database/' + bucket._id + '.json') | |||||
| note = await db.updateOne({ _id: body._id }, body) | |||||
| } | |||||
| response.json({ | |||||
| data: note | |||||
| }) | |||||
| }) | |||||
| /** | |||||
| * | |||||
| * | |||||
| * @param request | |||||
| * @param response | |||||
| * @return | |||||
| */ | |||||
| router.delete('/:bucket_id/:id', function(request, response, next) | |||||
| { | |||||
| }) | |||||
| export default router | |||||
| @ -0,0 +1,149 @@ | |||||
| 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 | |||||
| @ -0,0 +1,60 @@ | |||||
| 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' | |||||
| 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.findMany() | |||||
| response.json({ | |||||
| data: users | |||||
| }) | |||||
| }) | |||||
| /** | |||||
| * create user | |||||
| * | |||||
| * @param request | |||||
| * @param response | |||||
| * @return | |||||
| * | |||||
| */ | |||||
| router.post('/', async function(request, response) | |||||
| { | |||||
| const body = request.body | |||||
| const userRepository = new UserRepository() | |||||
| let user = [] | |||||
| const [ valid, errors ] = await validate(body, { | |||||
| email: [ isEmail, maxLength(255), required ], | |||||
| password: [ required, maxLength(64) ] | |||||
| }) | |||||
| if (valid) { | |||||
| user = await userRepository.create(body) | |||||
| // remove password | |||||
| // @TODO make sure repository can hide variables | |||||
| delete user.password | |||||
| } | |||||
| response.json({ | |||||
| data: user | |||||
| }) | |||||
| }) | |||||
| export default router | |||||
| @ -0,0 +1,43 @@ | |||||
| import { validate, required, email } from 'https://deno.land/x/validasaur@v0.15.0/mod.ts' | |||||
| import { Router } from 'https://deno.land/x/opine@1.5.3/mod.ts' | |||||
| const router = Router() | |||||
| /** | |||||
| * auth user, check for password in db | |||||
| * and create jwt | |||||
| * | |||||
| * @param request | |||||
| * @param response | |||||
| * @return | |||||
| */ | |||||
| router.post('/', async function(request, response) | |||||
| { | |||||
| if (body.password) { | |||||
| body.password = escapeHtml(body.password) | |||||
| } | |||||
| const [ valid, errors ] = await validate(body, { | |||||
| email: [ required, email ], | |||||
| password: [ required, maxLength(64) ] | |||||
| }); | |||||
| if (valid) { | |||||
| // check if user exists | |||||
| user = await userRepository.db.findOne({ | |||||
| 'email': body.email | |||||
| }) | |||||
| if (user) { | |||||
| result = userRepository.verifyPassword(user, body.password) | |||||
| if (result) { | |||||
| response.cookie('auth-token', jwt) | |||||
| } | |||||
| } | |||||
| } | |||||
| response.redirect('/') | |||||
| } | |||||
| @ -0,0 +1,23 @@ | |||||
| import { Router } from 'https://deno.land/x/opine@1.5.3/mod.ts' | |||||
| import bucketMiddleware from '../middleware/bucket.ts' | |||||
| const router = Router() | |||||
| // check for id and try load bucket | |||||
| router.param('bucket_id', bucketMiddleware) | |||||
| /** | |||||
| * render single bucket | |||||
| * | |||||
| * @param request | |||||
| * @param response | |||||
| * @return | |||||
| */ | |||||
| router.get('/:bucket_id', async function(request, response) | |||||
| { | |||||
| response.render('bucket/single', { | |||||
| bucket: response.locals.bucket | |||||
| }) | |||||
| }) | |||||
| export default router | |||||
| @ -0,0 +1,17 @@ | |||||
| import { Router } from 'https://deno.land/x/opine@1.5.3/mod.ts' | |||||
| const router = Router() | |||||
| /** | |||||
| * render template for settings | |||||
| * | |||||
| * @param request | |||||
| * @param response | |||||
| * @return | |||||
| */ | |||||
| router.get('/', function(request, response, next) | |||||
| { | |||||
| response.render('users') | |||||
| }) | |||||
| export default router | |||||
| @ -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 BucketRepository from '../repositories/bucket.ts' | |||||
| const router = Router() | |||||
| /** | |||||
| * check every route for single bucket | |||||
| * | |||||
| * @param request | |||||
| * @param response | |||||
| * @param next | |||||
| * @return | |||||
| */ | |||||
| async function bucketMiddleware(request: any, response: any, next: any) | |||||
| { | |||||
| // max for id | |||||
| request.params.bucket_id = request.params.bucket_id.slice(0, 128) | |||||
| // only dash, numbers & letters are allowed | |||||
| request.params.bucket_id = request.params.bucket_id.replace(/[^a-z0-9-]/gi, '') | |||||
| const [ valid, errors ] = await validate(request.params, { | |||||
| bucket_id: [ uuid ] | |||||
| }) | |||||
| // if invalid send 404 | |||||
| if (!valid) { | |||||
| response | |||||
| .setStatus(404) | |||||
| .send() | |||||
| } | |||||
| // getting | |||||
| const bucketRepository = new BucketRepository() | |||||
| const bucket = await bucketRepository.db.findOne({ '_id': request.params.bucket_id }) | |||||
| // if not exists send 404 | |||||
| if (!bucket) { | |||||
| response | |||||
| .setStatus(404) | |||||
| .send() | |||||
| } | |||||
| response.locals.bucket = bucket | |||||
| next() | |||||
| } | |||||
| export default bucketMiddleware | |||||
| @ -0,0 +1,32 @@ | |||||
| import { Router } from 'https://deno.land/x/opine@1.5.3/mod.ts' | |||||
| import { v4 } from 'https://deno.land/std@0.99.0/uuid/mod.ts' | |||||
| import UserRepository from './../repositories/user.ts' | |||||
| export default async function(request: any, response: any, next: any) | |||||
| { | |||||
| request.user = false | |||||
| try { | |||||
| const token = request.headers.authorization.split(' ')[1]; | |||||
| // if v4 is not validate next | |||||
| if (!v4.validate(token)) { | |||||
| next() | |||||
| } | |||||
| // search for user with session id | |||||
| const userRepository = new UserRepository() | |||||
| const user = await userRepository.db.findOne({ | |||||
| 'session_id': token | |||||
| }) | |||||
| if (user) { | |||||
| response.locals.user = user | |||||
| } | |||||
| } catch(error) { | |||||
| } | |||||
| next() | |||||
| } | |||||
| @ -0,0 +1,36 @@ | |||||
| import { v4 } from 'https://deno.land/std@0.99.0/uuid/mod.ts' | |||||
| import { Database } from 'https://deno.land/x/aloedb@0.9.0/mod.ts' | |||||
| import { BucketSchema } from '../stores/bucket.ts' | |||||
| /** | |||||
| * | |||||
| * | |||||
| */ | |||||
| class BucketRepository | |||||
| { | |||||
| db: any | |||||
| constructor() | |||||
| { | |||||
| this.db = new Database<BucketSchema>('./storage/database/buckets.json') | |||||
| } | |||||
| /** | |||||
| * | |||||
| */ | |||||
| async create(data: any) | |||||
| { | |||||
| data._id = v4.generate() | |||||
| return await this.db.insertOne(data) | |||||
| } | |||||
| /** | |||||
| * | |||||
| */ | |||||
| async update(data: any) | |||||
| { | |||||
| return await this.db.updateOne({ '_id': data._id }, data) | |||||
| } | |||||
| } | |||||
| export default BucketRepository | |||||
| @ -0,0 +1,47 @@ | |||||
| import * as bcrypt from 'https://deno.land/x/bcrypt@v0.2.4/mod.ts' | |||||
| import { v4 } from 'https://deno.land/std@0.99.0/uuid/mod.ts' | |||||
| import { Database } from 'https://deno.land/x/aloedb@0.9.0/mod.ts' | |||||
| import { UserSchema } from './../stores/user.ts' | |||||
| /** | |||||
| * | |||||
| * | |||||
| */ | |||||
| class UserRepository | |||||
| { | |||||
| db: any; | |||||
| constructor() | |||||
| { | |||||
| this.db = new Database<UserSchema>('./../../storage/database/users.json') | |||||
| } | |||||
| /** | |||||
| * | |||||
| */ | |||||
| async create(data: any) | |||||
| { | |||||
| data._id = v4.generate() | |||||
| data.password = await bcrypt.hash(data.password) | |||||
| return await this.db.insertOne(data) | |||||
| } | |||||
| /** | |||||
| * | |||||
| */ | |||||
| async update(data: any) | |||||
| { | |||||
| const user = await this.db.findOne({ '_id': data._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) | |||||
| } | |||||
| } | |||||
| export default UserRepository | |||||
| @ -0,0 +1,23 @@ | |||||
| import { invalid, Validity, Rule } from "https://deno.land/x/validasaur/mod.ts"; | |||||
| /** | |||||
| * | |||||
| * @param id | |||||
| * @return | |||||
| */ | |||||
| export function exists(id: string): Rule { | |||||
| return async function existsRule(value: any): Promise<Validity> { | |||||
| if (typeof value !== 'string' && typeof value !== 'number') { | |||||
| return invalid('exists', { value, table, column }); | |||||
| } | |||||
| const data = await db.findOne({ | |||||
| key: value | |||||
| }) | |||||
| if (data !== null) { | |||||
| return invalid('unique', { value, table, column }); | |||||
| } | |||||
| } | |||||
| } | |||||
| @ -0,0 +1,25 @@ | |||||
| import { invalid, Validity, Rule } from "https://deno.land/x/validasaur/mod.ts"; | |||||
| /** | |||||
| * search for key | |||||
| * | |||||
| * @param key | |||||
| * @param value | |||||
| * @return | |||||
| */ | |||||
| export function unique(key: string, value: string): Rule { | |||||
| return async function uniqueRule(value: any): Promise<Validity> { | |||||
| if (typeof value !== 'string' && typeof value !== 'number') { | |||||
| return invalid('unique', { value, table, column }); | |||||
| } | |||||
| const data = await db.findOne({ | |||||
| key: value | |||||
| }) | |||||
| if (data !== null) { | |||||
| return invalid('unique', { value, table, column }); | |||||
| } | |||||
| } | |||||
| } | |||||
| @ -0,0 +1,19 @@ | |||||
| import { invalid, Validity } from 'https://deno.land/x/validasaur@v0.15.0/mod.ts' | |||||
| import { v4 } from 'https://deno.land/std@0.99.0/uuid/mod.ts' | |||||
| /** | |||||
| * validate uuid v4 | |||||
| * | |||||
| * @param value | |||||
| * @return <Promise> | |||||
| * | |||||
| */ | |||||
| export async function uuid(value: any): Promise<Validity> { | |||||
| if (typeof value !== 'string') { | |||||
| return invalid('uuid', { value: value }) | |||||
| } | |||||
| if (!v4.validate(value)) { | |||||
| return invalid('uuid', { value: value }) | |||||
| } | |||||
| } | |||||
| @ -1,13 +0,0 @@ | |||||
| import { validate, required, isNumber } from 'https://deno.land/x/validasaur@0.15.0/mod.ts' | |||||
| // create shema for validation | |||||
| const BucketSchema = Schema({ | |||||
| title: string.trim().normalize(), | |||||
| description: string.trim().normalize().optional(), | |||||
| type: Schema.either('a', 'b', 'c'), | |||||
| visiblity: Schema.either('a', 'b', 'c') | |||||
| }) | |||||
| // create type and get validator from schema | |||||
| export type bucketType = Type<typeof BucketSchema> | |||||
| export const bucketValidator = BucketSchema.destruct() | |||||
| @ -1,15 +0,0 @@ | |||||
| import Schema, { Type, string, number, array } from 'https://denoporter.sirjosh.workers.dev/v1/deno.land/x/computed_types/src/index.ts' | |||||
| // create shema for validation | |||||
| const NoteSchema = Schema({ | |||||
| title: string.trim().normalize(), | |||||
| description: string.trim().normalize().optional(), | |||||
| type: Schema.either('a', 'b', 'c'), | |||||
| visiblity: Schema.either('a', 'b', 'c') | |||||
| }) | |||||
| // create type and get validator from schema | |||||
| type Note = Type<typeof NoteSchema> | |||||
| const validator = NoteSchema.destruct() | |||||
| export default validator | |||||
| @ -1,14 +0,0 @@ | |||||
| import Schema, { Type, string, number, array } from 'https://denoporter.sirjosh.workers.dev/v1/deno.land/x/computed_types/src/index.ts' | |||||
| // create shema for validation | |||||
| const UserSchema = Schema({ | |||||
| username: string.trim().normalize(), | |||||
| password: string.normalize(), | |||||
| email: Schema.email() | |||||
| }) | |||||
| // create type and get validator from schema | |||||
| type User = Type<typeof UserSchema> | |||||
| const validator = UserSchema.destruct() | |||||
| export default validator | |||||