| @ -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 | |||