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