refactor: knex remaining models
This commit is contained in:
parent
c9b643fbf0
commit
17b2117b39
@ -3,7 +3,7 @@
|
|||||||
nav-header
|
nav-header
|
||||||
template(slot='actions')
|
template(slot='actions')
|
||||||
v-btn(outline, color='green', @click.native.stop='save')
|
v-btn(outline, color='green', @click.native.stop='save')
|
||||||
v-icon(color='green', left) save
|
v-icon(color='green', left) check
|
||||||
span.white--text Save
|
span.white--text Save
|
||||||
v-btn(icon): v-icon(color='red') close
|
v-btn(icon): v-icon(color='red') close
|
||||||
v-btn(icon, @click.native.stop='openModal(`properties`)'): v-icon(color='white') sort_by_alpha
|
v-btn(icon, @click.native.stop='openModal(`properties`)'): v-icon(color='white') sort_by_alpha
|
||||||
@ -11,12 +11,12 @@
|
|||||||
v-content
|
v-content
|
||||||
editor-code
|
editor-code
|
||||||
component(:is='currentModal')
|
component(:is='currentModal')
|
||||||
v-dialog(v-model='dialogProgress', persistent, max-width='300')
|
v-dialog(v-model='dialogProgress', persistent, max-width='350')
|
||||||
v-card
|
v-card(color='blue darken-3', dark)
|
||||||
v-progress-linear.my-0(indeterminate, color='primary', height='5')
|
v-card-text.text-xs-center.py-4
|
||||||
v-card-text.text-xs-center
|
v-progress-circular(indeterminate, color='white', width='1')
|
||||||
.headline Saving
|
.subheading Processing
|
||||||
.caption Please wait...
|
.caption.blue--text.text--lighten-3 Please wait...
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
@ -1,73 +1,70 @@
|
|||||||
<template lang='pug'>
|
<template lang='pug'>
|
||||||
.editor-code
|
.editor-code
|
||||||
.editor-code-toolbar
|
v-toolbar.editor-code-toolbar.px-3(dense, color='primary', dark)
|
||||||
.editor-code-toolbar-group
|
v-btn(icon).mx-0
|
||||||
.editor-code-toolbar-item(@click='toggleAround("**", "**")')
|
svg.icons.is-18(role='img')
|
||||||
|
title Bold
|
||||||
|
use(xlink:href='#fa-bold')
|
||||||
|
v-btn(icon).mx-0
|
||||||
|
svg.icons.is-18(role='img')
|
||||||
|
title Italic
|
||||||
|
use(xlink:href='#fa-italic')
|
||||||
|
v-btn(icon).mx-0
|
||||||
|
svg.icons.is-18(role='img')
|
||||||
|
title Strikethrough
|
||||||
|
use(xlink:href='#fa-strikethrough')
|
||||||
|
v-menu(offset-y, open-on-hover)
|
||||||
|
v-btn(icon, slot='activator').mx-0
|
||||||
svg.icons.is-18(role='img')
|
svg.icons.is-18(role='img')
|
||||||
title Bold
|
title Heading
|
||||||
use(xlink:href='#fa-bold')
|
use(xlink:href='#fa-heading')
|
||||||
.editor-code-toolbar-item
|
v-list
|
||||||
svg.icons.is-18(role='img')
|
v-list-tile(v-for='(n, idx) in 6', @click='', :key='idx')
|
||||||
title Italic
|
v-list-tile-action
|
||||||
use(xlink:href='#fa-italic')
|
svg.icons.is-18(role='img')
|
||||||
.editor-code-toolbar-item
|
title Heading {{n}}
|
||||||
svg.icons.is-18(role='img')
|
use(xlink:href='#fa-heading')
|
||||||
title Strikethrough
|
v-list-tile-title Heading {{n}}
|
||||||
use(xlink:href='#fa-strikethrough')
|
v-btn(icon).mx-0
|
||||||
.editor-code-toolbar-group
|
svg.icons.is-18(role='img')
|
||||||
v-menu(offset-y, open-on-hover)
|
title Blockquote
|
||||||
.editor-code-toolbar-item.is-dropdown(slot='activator')
|
use(xlink:href='#fa-quote-left')
|
||||||
svg.icons.is-18(role='img')
|
v-btn(icon).mx-0
|
||||||
title Heading
|
svg.icons.is-18(role='img')
|
||||||
use(xlink:href='#fa-heading')
|
title Unordered List
|
||||||
v-list
|
use(xlink:href='#fa-list-ul')
|
||||||
v-list-tile(v-for='(n, idx) in 6', @click='', :key='idx')
|
v-btn(icon).mx-0
|
||||||
v-list-tile-action: v-icon format_size
|
svg.icons.is-18(role='img')
|
||||||
v-list-tile-title Heading {{n}}
|
title Ordered List
|
||||||
.editor-code-toolbar-item
|
use(xlink:href='#fa-list-ol')
|
||||||
svg.icons.is-18(role='img')
|
v-btn(icon).mx-0
|
||||||
title Blockquote
|
svg.icons.is-18(role='img')
|
||||||
use(xlink:href='#fa-quote-left')
|
title Link
|
||||||
.editor-code-toolbar-group
|
use(xlink:href='#fa-link')
|
||||||
.editor-code-toolbar-item
|
v-btn(icon).mx-0
|
||||||
svg.icons.is-18(role='img')
|
svg.icons.is-18(role='img')
|
||||||
title Unordered List
|
title Inline Code
|
||||||
use(xlink:href='#fa-list-ul')
|
use(xlink:href='#fa-terminal')
|
||||||
.editor-code-toolbar-item
|
v-btn(icon).mx-0
|
||||||
svg.icons.is-18(role='img')
|
svg.icons.is-18(role='img')
|
||||||
title Ordered List
|
title Code Block
|
||||||
use(xlink:href='#fa-list-ol')
|
use(xlink:href='#fa-code')
|
||||||
.editor-code-toolbar-group
|
v-btn(icon).mx-0
|
||||||
.editor-code-toolbar-item
|
svg.icons.is-18(role='img')
|
||||||
svg.icons.is-18(role='img')
|
title Horizontal Bar
|
||||||
title Link
|
use(xlink:href='#fa-minus')
|
||||||
use(xlink:href='#fa-link')
|
|
||||||
.editor-code-toolbar-group
|
|
||||||
.editor-code-toolbar-item
|
|
||||||
svg.icons.is-18(role='img')
|
|
||||||
title Inline Code
|
|
||||||
use(xlink:href='#fa-terminal')
|
|
||||||
.editor-code-toolbar-item
|
|
||||||
svg.icons.is-18(role='img')
|
|
||||||
title Code Block
|
|
||||||
use(xlink:href='#fa-code')
|
|
||||||
.editor-code-toolbar-group
|
|
||||||
.editor-code-toolbar-item
|
|
||||||
svg.icons.is-18(role='img')
|
|
||||||
title Horizontal Bar
|
|
||||||
use(xlink:href='#fa-minus')
|
|
||||||
|
|
||||||
.editor-code-main
|
.editor-code-main
|
||||||
.editor-code-editor
|
.editor-code-editor
|
||||||
.editor-code-editor-title(v-if='previewShown', @click='previewShown = false') Editor
|
.editor-code-editor-title(v-if='previewShown', @click='previewShown = false') Editor
|
||||||
.editor-code-editor-title(v-else='previewShown', @click='previewShown = true'): v-icon(dark) search
|
.editor-code-editor-title(v-else='previewShown', @click='previewShown = true'): v-icon(dark) drag_indicator
|
||||||
codemirror(ref='cm', v-model='code', :options='cmOptions', @ready='onCmReady', @input='onCmInput')
|
codemirror(ref='cm', v-model='code', :options='cmOptions', @ready='onCmReady', @input='onCmInput')
|
||||||
transition(name='editor-code-preview')
|
transition(name='editor-code-preview')
|
||||||
.editor-code-preview(v-if='previewShown')
|
.editor-code-preview(v-if='previewShown')
|
||||||
.editor-code-preview-title(@click='previewShown = false') Preview
|
.editor-code-preview-title(@click='previewShown = false') Preview
|
||||||
.editor-code-preview-content.markdown-content(ref='editorPreview', v-html='previewHTML')
|
.editor-code-preview-content.markdown-content(ref='editorPreview', v-html='previewHTML')
|
||||||
|
|
||||||
v-speed-dial(v-model='fabInsertMenu', :open-on-hover='true', direction='top', transition='slide-y-reverse-transition', fixed, right, bottom)
|
v-speed-dial(v-model='fabInsertMenu', :open-on-hover='true', direction='top', transition='slide-y-reverse-transition', fixed, left, bottom)
|
||||||
v-btn(color='blue', fab, dark, v-model='fabInsertMenu', slot='activator')
|
v-btn(color='blue', fab, dark, v-model='fabInsertMenu', slot='activator')
|
||||||
v-icon add_circle
|
v-icon add_circle
|
||||||
v-icon close
|
v-icon close
|
||||||
@ -276,7 +273,7 @@ export default {
|
|||||||
background-color: darken(mc('grey', '900'), 4.5%);
|
background-color: darken(mc('grey', '900'), 4.5%);
|
||||||
flex: 1 1 50%;
|
flex: 1 1 50%;
|
||||||
display: block;
|
display: block;
|
||||||
height: calc(100vh - 100px);
|
height: calc(100vh - 96px);
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
&-title {
|
&-title {
|
||||||
@ -361,48 +358,12 @@ export default {
|
|||||||
&-toolbar {
|
&-toolbar {
|
||||||
background-color: mc('blue', '700');
|
background-color: mc('blue', '700');
|
||||||
background-image: linear-gradient(to bottom, mc('blue', '700') 0%, mc('blue','800') 100%);
|
background-image: linear-gradient(to bottom, mc('blue', '700') 0%, mc('blue','800') 100%);
|
||||||
height: 50px;
|
|
||||||
color: #FFF;
|
color: #FFF;
|
||||||
display: flex;
|
|
||||||
|
|
||||||
@include until($tablet) {
|
@include until($tablet) {
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
&-group {
|
|
||||||
display: flex;
|
|
||||||
|
|
||||||
+ .editor-code-toolbar-group {
|
|
||||||
border-left: 1px solid rgba(mc('blue', '600'), .5);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&-item {
|
|
||||||
width: 40px;
|
|
||||||
height: 50px;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
transition: all .4s ease;
|
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
&:first-child {
|
|
||||||
padding-left: .5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:last-child {
|
|
||||||
padding-right: .5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background-color: mc('blue', '600');
|
|
||||||
}
|
|
||||||
|
|
||||||
@include until($tablet) {
|
|
||||||
width: 35px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
svg {
|
svg {
|
||||||
use {
|
use {
|
||||||
color: #FFF;
|
color: #FFF;
|
||||||
|
@ -31,10 +31,7 @@
|
|||||||
v-subheader Assets
|
v-subheader Assets
|
||||||
v-list-tile(avatar, @click='')
|
v-list-tile(avatar, @click='')
|
||||||
v-list-tile-avatar: v-icon(color='blue-grey') burst_mode
|
v-list-tile-avatar: v-icon(color='blue-grey') burst_mode
|
||||||
v-list-tile-content Images
|
v-list-tile-content Images & Files
|
||||||
v-list-tile(avatar, @click='')
|
|
||||||
v-list-tile-avatar: v-icon(color='blue-grey') description
|
|
||||||
v-list-tile-content Files
|
|
||||||
v-toolbar-title
|
v-toolbar-title
|
||||||
span.subheading Wiki.js
|
span.subheading Wiki.js
|
||||||
v-spacer
|
v-spacer
|
||||||
|
@ -1,46 +1,85 @@
|
|||||||
exports.up = knex => {
|
exports.up = knex => {
|
||||||
return knex.schema
|
return knex.schema
|
||||||
// -------------------------------------
|
// =====================================
|
||||||
// GROUPS
|
// MODEL TABLES
|
||||||
// -------------------------------------
|
// =====================================
|
||||||
|
// ASSETS ------------------------------
|
||||||
|
.createTable('assets', table => {
|
||||||
|
table.increments('id').primary()
|
||||||
|
table.string('filename').notNullable()
|
||||||
|
table.string('basename').notNullable()
|
||||||
|
table.string('ext').notNullable()
|
||||||
|
table.enum('kind', ['binary', 'image']).notNullable().defaultTo('binary')
|
||||||
|
table.string('mime').notNullable().defaultTo('application/octet-stream')
|
||||||
|
table.integer('fileSize').unsigned().comment('In kilobytes')
|
||||||
|
table.jsonb('metadata')
|
||||||
|
table.string('createdAt').notNullable()
|
||||||
|
table.string('updatedAt').notNullable()
|
||||||
|
})
|
||||||
|
// ASSET FOLDERS -----------------------
|
||||||
|
.createTable('assetFolders', table => {
|
||||||
|
table.increments('id').primary()
|
||||||
|
table.string('name').notNullable()
|
||||||
|
table.string('slug').notNullable()
|
||||||
|
table.integer('parentId').unsigned().references('id').inTable('assetFolders')
|
||||||
|
})
|
||||||
|
// COMMENTS ----------------------------
|
||||||
|
.createTable('comments', table => {
|
||||||
|
table.increments('id').primary()
|
||||||
|
table.text('content').notNullable()
|
||||||
|
table.string('createdAt').notNullable()
|
||||||
|
table.string('updatedAt').notNullable()
|
||||||
|
})
|
||||||
|
// GROUPS ------------------------------
|
||||||
.createTable('groups', table => {
|
.createTable('groups', table => {
|
||||||
table.increments('id').primary()
|
table.increments('id').primary()
|
||||||
|
|
||||||
table.string('name').notNullable()
|
table.string('name').notNullable()
|
||||||
table.string('createdAt').notNullable()
|
table.string('createdAt').notNullable()
|
||||||
table.string('updatedAt').notNullable()
|
table.string('updatedAt').notNullable()
|
||||||
})
|
})
|
||||||
// -------------------------------------
|
// LOCALES -----------------------------
|
||||||
// LOCALES
|
|
||||||
// -------------------------------------
|
|
||||||
.createTable('locales', table => {
|
.createTable('locales', table => {
|
||||||
table.increments('id').primary()
|
table.increments('id').primary()
|
||||||
|
|
||||||
table.string('code', 2).notNullable().unique()
|
table.string('code', 2).notNullable().unique()
|
||||||
table.json('strings')
|
table.jsonb('strings')
|
||||||
table.boolean('isRTL').notNullable().defaultTo(false)
|
table.boolean('isRTL').notNullable().defaultTo(false)
|
||||||
table.string('name').notNullable()
|
table.string('name').notNullable()
|
||||||
table.string('nativeName').notNullable()
|
table.string('nativeName').notNullable()
|
||||||
table.string('createdAt').notNullable()
|
table.string('createdAt').notNullable()
|
||||||
table.string('updatedAt').notNullable()
|
table.string('updatedAt').notNullable()
|
||||||
})
|
})
|
||||||
// -------------------------------------
|
// PAGES -------------------------------
|
||||||
// SETTINGS
|
.createTable('pages', table => {
|
||||||
// -------------------------------------
|
|
||||||
.createTable('settings', table => {
|
|
||||||
table.increments('id').primary()
|
table.increments('id').primary()
|
||||||
|
table.string('path').notNullable()
|
||||||
table.string('key').notNullable().unique()
|
table.string('title').notNullable()
|
||||||
table.json('value')
|
table.string('description')
|
||||||
|
table.boolean('isPublished').notNullable().defaultTo(false)
|
||||||
|
table.string('publishStartDate')
|
||||||
|
table.string('publishEndDate')
|
||||||
|
table.text('content')
|
||||||
table.string('createdAt').notNullable()
|
table.string('createdAt').notNullable()
|
||||||
table.string('updatedAt').notNullable()
|
table.string('updatedAt').notNullable()
|
||||||
})
|
})
|
||||||
// -------------------------------------
|
// SETTINGS ----------------------------
|
||||||
// USERS
|
.createTable('settings', table => {
|
||||||
// -------------------------------------
|
table.increments('id').primary()
|
||||||
|
table.string('key').notNullable().unique()
|
||||||
|
table.jsonb('value')
|
||||||
|
table.string('createdAt').notNullable()
|
||||||
|
table.string('updatedAt').notNullable()
|
||||||
|
})
|
||||||
|
// TAGS --------------------------------
|
||||||
|
.createTable('tags', table => {
|
||||||
|
table.increments('id').primary()
|
||||||
|
table.string('tag').notNullable().unique()
|
||||||
|
table.string('title')
|
||||||
|
table.string('createdAt').notNullable()
|
||||||
|
table.string('updatedAt').notNullable()
|
||||||
|
})
|
||||||
|
// USERS -------------------------------
|
||||||
.createTable('users', table => {
|
.createTable('users', table => {
|
||||||
table.increments('id').primary()
|
table.increments('id').primary()
|
||||||
|
|
||||||
table.string('email').notNullable()
|
table.string('email').notNullable()
|
||||||
table.string('name').notNullable()
|
table.string('name').notNullable()
|
||||||
table.string('provider').notNullable().defaultTo('local')
|
table.string('provider').notNullable().defaultTo('local')
|
||||||
@ -54,22 +93,52 @@ exports.up = knex => {
|
|||||||
|
|
||||||
table.unique(['provider', 'email'])
|
table.unique(['provider', 'email'])
|
||||||
})
|
})
|
||||||
// -------------------------------------
|
// =====================================
|
||||||
// USER GROUPS
|
// RELATION TABLES
|
||||||
// -------------------------------------
|
// =====================================
|
||||||
|
// PAGE TAGS ---------------------------
|
||||||
|
.createTable('pageTags', table => {
|
||||||
|
table.increments('id').primary()
|
||||||
|
table.integer('pageId').unsigned().references('id').inTable('pages')
|
||||||
|
table.integer('tagId').unsigned().references('id').inTable('tags')
|
||||||
|
})
|
||||||
|
// USER GROUPS -------------------------
|
||||||
.createTable('userGroups', table => {
|
.createTable('userGroups', table => {
|
||||||
table.increments('id').primary()
|
table.increments('id').primary()
|
||||||
|
|
||||||
table.integer('userId').unsigned().references('id').inTable('users')
|
table.integer('userId').unsigned().references('id').inTable('users')
|
||||||
table.integer('groupId').unsigned().references('id').inTable('groups')
|
table.integer('groupId').unsigned().references('id').inTable('groups')
|
||||||
})
|
})
|
||||||
|
// =====================================
|
||||||
|
// REFERENCES
|
||||||
|
// =====================================
|
||||||
|
.table('assets', table => {
|
||||||
|
table.integer('folderId').unsigned().references('id').inTable('assetFolders')
|
||||||
|
table.integer('authorId').unsigned().references('id').inTable('users')
|
||||||
|
})
|
||||||
|
.table('comments', table => {
|
||||||
|
table.integer('pageId').unsigned().references('id').inTable('pages')
|
||||||
|
table.integer('authorId').unsigned().references('id').inTable('users')
|
||||||
|
})
|
||||||
|
.table('pages', table => {
|
||||||
|
table.string('locale', 2).references('code').inTable('locales')
|
||||||
|
table.integer('authorId').unsigned().references('id').inTable('users')
|
||||||
|
})
|
||||||
|
.table('users', table => {
|
||||||
|
table.string('locale', 2).references('code').inTable('locales')
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.down = knex => {
|
exports.down = knex => {
|
||||||
return knex.schema
|
return knex.schema
|
||||||
.dropTableIfExists('userGroups')
|
.dropTableIfExists('userGroups')
|
||||||
|
.dropTableIfExists('pageTags')
|
||||||
|
.dropTableIfExists('assets')
|
||||||
|
.dropTableIfExists('assetFolders')
|
||||||
|
.dropTableIfExists('comments')
|
||||||
.dropTableIfExists('groups')
|
.dropTableIfExists('groups')
|
||||||
.dropTableIfExists('locales')
|
.dropTableIfExists('locales')
|
||||||
|
.dropTableIfExists('pages')
|
||||||
.dropTableIfExists('settings')
|
.dropTableIfExists('settings')
|
||||||
|
.dropTableIfExists('tags')
|
||||||
.dropTableIfExists('users')
|
.dropTableIfExists('users')
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
const Model = require('objection').Model
|
const Model = require('objection').Model
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Settings model
|
* Groups model
|
||||||
*/
|
*/
|
||||||
module.exports = class Group extends Model {
|
module.exports = class Group extends Model {
|
||||||
static get tableName() { return 'groups' }
|
static get tableName() { return 'groups' }
|
||||||
@ -21,11 +21,10 @@ module.exports = class Group extends Model {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static get relationMappings() {
|
static get relationMappings() {
|
||||||
const User = require('./users')
|
|
||||||
return {
|
return {
|
||||||
users: {
|
users: {
|
||||||
relation: Model.ManyToManyRelation,
|
relation: Model.ManyToManyRelation,
|
||||||
modelClass: User,
|
modelClass: require('./users'),
|
||||||
join: {
|
join: {
|
||||||
from: 'groups.id',
|
from: 'groups.id',
|
||||||
through: {
|
through: {
|
||||||
|
70
server/db/models/pages.js
Normal file
70
server/db/models/pages.js
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
const Model = require('objection').Model
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pages model
|
||||||
|
*/
|
||||||
|
module.exports = class Page extends Model {
|
||||||
|
static get tableName() { return 'pages' }
|
||||||
|
|
||||||
|
static get jsonSchema () {
|
||||||
|
return {
|
||||||
|
type: 'object',
|
||||||
|
required: ['path', 'title'],
|
||||||
|
|
||||||
|
properties: {
|
||||||
|
id: {type: 'integer'},
|
||||||
|
path: {type: 'string'},
|
||||||
|
title: {type: 'string'},
|
||||||
|
description: {type: 'string'},
|
||||||
|
isPublished: {type: 'boolean'},
|
||||||
|
publishStartDate: {type: 'string'},
|
||||||
|
publishEndDate: {type: 'string'},
|
||||||
|
content: {type: 'string'},
|
||||||
|
|
||||||
|
createdAt: {type: 'string'},
|
||||||
|
updatedAt: {type: 'string'}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static get relationMappings() {
|
||||||
|
return {
|
||||||
|
tags: {
|
||||||
|
relation: Model.ManyToManyRelation,
|
||||||
|
modelClass: require('./tags'),
|
||||||
|
join: {
|
||||||
|
from: 'pages.id',
|
||||||
|
through: {
|
||||||
|
from: 'pageTags.pageId',
|
||||||
|
to: 'pageTags.tagId'
|
||||||
|
},
|
||||||
|
to: 'tags.id'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
author: {
|
||||||
|
relation: Model.BelongsToOneRelation,
|
||||||
|
modelClass: require('./users'),
|
||||||
|
join: {
|
||||||
|
from: 'pages.authorId',
|
||||||
|
to: 'users.id'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
locale: {
|
||||||
|
relation: Model.BelongsToOneRelation,
|
||||||
|
modelClass: require('./locales'),
|
||||||
|
join: {
|
||||||
|
from: 'users.locale',
|
||||||
|
to: 'locales.code'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$beforeUpdate() {
|
||||||
|
this.updatedAt = new Date().toISOString()
|
||||||
|
}
|
||||||
|
$beforeInsert() {
|
||||||
|
this.createdAt = new Date().toISOString()
|
||||||
|
this.updatedAt = new Date().toISOString()
|
||||||
|
}
|
||||||
|
}
|
49
server/db/models/tags.js
Normal file
49
server/db/models/tags.js
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
const Model = require('objection').Model
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tags model
|
||||||
|
*/
|
||||||
|
module.exports = class Tag extends Model {
|
||||||
|
static get tableName() { return 'tags' }
|
||||||
|
|
||||||
|
static get jsonSchema () {
|
||||||
|
return {
|
||||||
|
type: 'object',
|
||||||
|
required: ['tag'],
|
||||||
|
|
||||||
|
properties: {
|
||||||
|
id: {type: 'integer'},
|
||||||
|
tag: {type: 'string'},
|
||||||
|
title: {type: 'string'},
|
||||||
|
|
||||||
|
createdAt: {type: 'string'},
|
||||||
|
updatedAt: {type: 'string'}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static get relationMappings() {
|
||||||
|
return {
|
||||||
|
pages: {
|
||||||
|
relation: Model.ManyToManyRelation,
|
||||||
|
modelClass: require('./pages'),
|
||||||
|
join: {
|
||||||
|
from: 'tags.id',
|
||||||
|
through: {
|
||||||
|
from: 'pageTags.tagId',
|
||||||
|
to: 'pageTags.pageId'
|
||||||
|
},
|
||||||
|
to: 'pages.id'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$beforeUpdate() {
|
||||||
|
this.updatedAt = new Date().toISOString()
|
||||||
|
}
|
||||||
|
$beforeInsert() {
|
||||||
|
this.createdAt = new Date().toISOString()
|
||||||
|
this.updatedAt = new Date().toISOString()
|
||||||
|
}
|
||||||
|
}
|
@ -29,6 +29,7 @@ module.exports = class User extends Model {
|
|||||||
role: {type: 'string', enum: ['admin', 'guest', 'user']},
|
role: {type: 'string', enum: ['admin', 'guest', 'user']},
|
||||||
tfaIsActive: {type: 'boolean', default: false},
|
tfaIsActive: {type: 'boolean', default: false},
|
||||||
tfaSecret: {type: 'string'},
|
tfaSecret: {type: 'string'},
|
||||||
|
locale: {type: 'string'},
|
||||||
createdAt: {type: 'string'},
|
createdAt: {type: 'string'},
|
||||||
updatedAt: {type: 'string'}
|
updatedAt: {type: 'string'}
|
||||||
}
|
}
|
||||||
@ -36,11 +37,10 @@ module.exports = class User extends Model {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static get relationMappings() {
|
static get relationMappings() {
|
||||||
const Group = require('./groups')
|
|
||||||
return {
|
return {
|
||||||
groups: {
|
groups: {
|
||||||
relation: Model.ManyToManyRelation,
|
relation: Model.ManyToManyRelation,
|
||||||
modelClass: Group,
|
modelClass: require('./groups'),
|
||||||
join: {
|
join: {
|
||||||
from: 'users.id',
|
from: 'users.id',
|
||||||
through: {
|
through: {
|
||||||
@ -79,7 +79,7 @@ module.exports = class User extends Model {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async verifyPassword(pwd) {
|
async verifyPassword(pwd) {
|
||||||
if (await bcrypt.compare(this.password, pwd) === true) {
|
if (await bcrypt.compare(pwd, this.password) === true) {
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
throw new WIKI.Error.AuthLoginFailed()
|
throw new WIKI.Error.AuthLoginFailed()
|
||||||
|
51
server/graph/resolvers/page.js
Normal file
51
server/graph/resolvers/page.js
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
const graphHelper = require('../../helpers/graph')
|
||||||
|
|
||||||
|
/* global WIKI */
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
Query: {
|
||||||
|
async pages() { return {} }
|
||||||
|
},
|
||||||
|
Mutation: {
|
||||||
|
async pages() { return {} }
|
||||||
|
},
|
||||||
|
PageQuery: {
|
||||||
|
async list(obj, args, context, info) {
|
||||||
|
return WIKI.db.groups.query().select(
|
||||||
|
'groups.*',
|
||||||
|
WIKI.db.groups.relatedQuery('users').count().as('userCount')
|
||||||
|
)
|
||||||
|
},
|
||||||
|
async single(obj, args, context, info) {
|
||||||
|
return WIKI.db.groups.query().findById(args.id)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
PageMutation: {
|
||||||
|
async create(obj, args) {
|
||||||
|
const group = await WIKI.db.pages.query().insertAndFetch({
|
||||||
|
name: args.name
|
||||||
|
})
|
||||||
|
return {
|
||||||
|
responseResult: graphHelper.generateSuccess('Group created successfully.'),
|
||||||
|
group
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async delete(obj, args) {
|
||||||
|
await WIKI.db.groups.query().deleteById(args.id)
|
||||||
|
return {
|
||||||
|
responseResult: graphHelper.generateSuccess('Group has been deleted.')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async update(obj, args) {
|
||||||
|
await WIKI.db.groups.query().patch({ name: args.name }).where('id', args.id)
|
||||||
|
return {
|
||||||
|
responseResult: graphHelper.generateSuccess('Group has been updated.')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Page: {
|
||||||
|
// comments(pg) {
|
||||||
|
// return pg.$relatedQuery('comments')
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
78
server/graph/schemas/page.graphql
Normal file
78
server/graph/schemas/page.graphql
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
# ===============================================
|
||||||
|
# PAGES
|
||||||
|
# ===============================================
|
||||||
|
|
||||||
|
extend type Query {
|
||||||
|
pages: PageQuery
|
||||||
|
}
|
||||||
|
|
||||||
|
extend type Mutation {
|
||||||
|
pages: PageMutation
|
||||||
|
}
|
||||||
|
|
||||||
|
# -----------------------------------------------
|
||||||
|
# QUERIES
|
||||||
|
# -----------------------------------------------
|
||||||
|
|
||||||
|
type PageQuery {
|
||||||
|
list(
|
||||||
|
filter: String
|
||||||
|
orderBy: String
|
||||||
|
): [PageMinimal]
|
||||||
|
|
||||||
|
single(
|
||||||
|
id: Int!
|
||||||
|
): Page
|
||||||
|
}
|
||||||
|
|
||||||
|
# -----------------------------------------------
|
||||||
|
# MUTATIONS
|
||||||
|
# -----------------------------------------------
|
||||||
|
|
||||||
|
type PageMutation {
|
||||||
|
create(
|
||||||
|
description: String
|
||||||
|
isPublished: Boolean
|
||||||
|
locale: String
|
||||||
|
path: String!
|
||||||
|
publishEndDate: Date
|
||||||
|
publishStartDate: Date
|
||||||
|
tags: [String]
|
||||||
|
title: String!
|
||||||
|
): PageResponse
|
||||||
|
|
||||||
|
update(
|
||||||
|
id: Int!
|
||||||
|
name: String!
|
||||||
|
): DefaultResponse
|
||||||
|
|
||||||
|
delete(
|
||||||
|
id: Int!
|
||||||
|
): DefaultResponse
|
||||||
|
}
|
||||||
|
|
||||||
|
# -----------------------------------------------
|
||||||
|
# TYPES
|
||||||
|
# -----------------------------------------------
|
||||||
|
|
||||||
|
type PageResponse {
|
||||||
|
responseResult: ResponseStatus!
|
||||||
|
page: Page
|
||||||
|
}
|
||||||
|
|
||||||
|
type PageMinimal {
|
||||||
|
id: Int!
|
||||||
|
name: String!
|
||||||
|
userCount: Int
|
||||||
|
createdAt: Date!
|
||||||
|
updatedAt: Date!
|
||||||
|
}
|
||||||
|
|
||||||
|
type Page {
|
||||||
|
id: Int!
|
||||||
|
name: String!
|
||||||
|
rights: [Right]
|
||||||
|
users: [User]
|
||||||
|
createdAt: Date!
|
||||||
|
updatedAt: Date!
|
||||||
|
}
|
@ -1,16 +0,0 @@
|
|||||||
/**
|
|
||||||
* Associate DB Model relations
|
|
||||||
*/
|
|
||||||
module.exports = db => {
|
|
||||||
db.User.belongsToMany(db.Group, { through: 'userGroups' })
|
|
||||||
db.Group.belongsToMany(db.User, { through: 'userGroups' })
|
|
||||||
db.Group.hasMany(db.Right)
|
|
||||||
db.Right.belongsTo(db.Group)
|
|
||||||
db.Document.belongsToMany(db.Tag, { through: 'documentTags' })
|
|
||||||
db.Document.hasMany(db.Comment)
|
|
||||||
db.Tag.belongsToMany(db.Document, { through: 'documentTags' })
|
|
||||||
db.File.belongsTo(db.Folder)
|
|
||||||
db.Folder.hasMany(db.File)
|
|
||||||
db.Comment.belongsTo(db.Document)
|
|
||||||
db.Comment.belongsTo(db.User, { as: 'author' })
|
|
||||||
}
|
|
@ -1,16 +0,0 @@
|
|||||||
/**
|
|
||||||
* Comment schema
|
|
||||||
*/
|
|
||||||
module.exports = (sequelize, DataTypes) => {
|
|
||||||
let commentSchema = sequelize.define('comment', {
|
|
||||||
content: {
|
|
||||||
type: DataTypes.STRING,
|
|
||||||
allowNull: false
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
timestamps: true,
|
|
||||||
version: true
|
|
||||||
})
|
|
||||||
|
|
||||||
return commentSchema
|
|
||||||
}
|
|
@ -1,64 +0,0 @@
|
|||||||
/**
|
|
||||||
* Document schema
|
|
||||||
*/
|
|
||||||
module.exports = (sequelize, DataTypes) => {
|
|
||||||
let documentSchema = sequelize.define('setting', {
|
|
||||||
path: {
|
|
||||||
type: DataTypes.STRING,
|
|
||||||
allowNull: false
|
|
||||||
},
|
|
||||||
title: {
|
|
||||||
type: DataTypes.STRING,
|
|
||||||
allowNull: false,
|
|
||||||
validate: {
|
|
||||||
len: [2, 255]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
subtitle: {
|
|
||||||
type: DataTypes.STRING,
|
|
||||||
allowNull: true,
|
|
||||||
defaultValue: ''
|
|
||||||
},
|
|
||||||
parentPath: {
|
|
||||||
type: DataTypes.STRING,
|
|
||||||
allowNull: true,
|
|
||||||
defaultValue: ''
|
|
||||||
},
|
|
||||||
parentTitle: {
|
|
||||||
type: DataTypes.STRING,
|
|
||||||
allowNull: true,
|
|
||||||
defaultValue: ''
|
|
||||||
},
|
|
||||||
isDirectory: {
|
|
||||||
type: DataTypes.BOOLEAN,
|
|
||||||
allowNull: false,
|
|
||||||
defaultValue: false
|
|
||||||
},
|
|
||||||
isEntry: {
|
|
||||||
type: DataTypes.BOOLEAN,
|
|
||||||
allowNull: false,
|
|
||||||
defaultValue: false
|
|
||||||
},
|
|
||||||
isDraft: {
|
|
||||||
type: DataTypes.BOOLEAN,
|
|
||||||
allowNull: false,
|
|
||||||
defaultValue: false
|
|
||||||
},
|
|
||||||
searchContent: {
|
|
||||||
type: DataTypes.TEXT,
|
|
||||||
allowNull: true,
|
|
||||||
defaultValue: ''
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
timestamps: true,
|
|
||||||
version: true,
|
|
||||||
indexes: [
|
|
||||||
{
|
|
||||||
unique: true,
|
|
||||||
fields: ['path']
|
|
||||||
}
|
|
||||||
]
|
|
||||||
})
|
|
||||||
|
|
||||||
return documentSchema
|
|
||||||
}
|
|
@ -1,42 +0,0 @@
|
|||||||
/**
|
|
||||||
* File schema
|
|
||||||
*/
|
|
||||||
module.exports = (sequelize, DataTypes) => {
|
|
||||||
let fileSchema = sequelize.define('file', {
|
|
||||||
category: {
|
|
||||||
type: DataTypes.ENUM('binary', 'image'),
|
|
||||||
allowNull: false,
|
|
||||||
defaultValue: 'binary'
|
|
||||||
},
|
|
||||||
mime: {
|
|
||||||
type: DataTypes.STRING,
|
|
||||||
allowNull: false,
|
|
||||||
defaultValue: 'application/octet-stream'
|
|
||||||
},
|
|
||||||
extra: {
|
|
||||||
type: DataTypes.JSON,
|
|
||||||
allowNull: true
|
|
||||||
},
|
|
||||||
filename: {
|
|
||||||
type: DataTypes.STRING,
|
|
||||||
allowNull: false
|
|
||||||
},
|
|
||||||
basename: {
|
|
||||||
type: DataTypes.STRING,
|
|
||||||
allowNull: false
|
|
||||||
},
|
|
||||||
filesize: {
|
|
||||||
type: DataTypes.INTEGER,
|
|
||||||
allowNull: false,
|
|
||||||
validate: {
|
|
||||||
isInt: true,
|
|
||||||
min: 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
timestamps: true,
|
|
||||||
version: true
|
|
||||||
})
|
|
||||||
|
|
||||||
return fileSchema
|
|
||||||
}
|
|
@ -1,22 +0,0 @@
|
|||||||
/**
|
|
||||||
* Folder schema
|
|
||||||
*/
|
|
||||||
module.exports = (sequelize, DataTypes) => {
|
|
||||||
let folderSchema = sequelize.define('folder', {
|
|
||||||
name: {
|
|
||||||
type: DataTypes.STRING,
|
|
||||||
allowNull: false
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
timestamps: true,
|
|
||||||
version: true,
|
|
||||||
indexes: [
|
|
||||||
{
|
|
||||||
unique: true,
|
|
||||||
fields: ['name']
|
|
||||||
}
|
|
||||||
]
|
|
||||||
})
|
|
||||||
|
|
||||||
return folderSchema
|
|
||||||
}
|
|
@ -1,16 +0,0 @@
|
|||||||
/**
|
|
||||||
* Group schema
|
|
||||||
*/
|
|
||||||
module.exports = (sequelize, DataTypes) => {
|
|
||||||
let groupSchema = sequelize.define('group', {
|
|
||||||
name: {
|
|
||||||
type: DataTypes.STRING,
|
|
||||||
allowNull: false
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
timestamps: true,
|
|
||||||
version: true
|
|
||||||
})
|
|
||||||
|
|
||||||
return groupSchema
|
|
||||||
}
|
|
@ -1,39 +0,0 @@
|
|||||||
/**
|
|
||||||
* Locale schema
|
|
||||||
*/
|
|
||||||
module.exports = (sequelize, DataTypes) => {
|
|
||||||
let localeSchema = sequelize.define('locale', {
|
|
||||||
code: {
|
|
||||||
type: DataTypes.STRING,
|
|
||||||
allowNull: false
|
|
||||||
},
|
|
||||||
strings: {
|
|
||||||
type: DataTypes.JSON,
|
|
||||||
allowNull: true
|
|
||||||
},
|
|
||||||
isRTL: {
|
|
||||||
type: DataTypes.BOOLEAN,
|
|
||||||
allowNull: false,
|
|
||||||
defaultValue: false
|
|
||||||
},
|
|
||||||
name: {
|
|
||||||
type: DataTypes.STRING,
|
|
||||||
allowNull: false
|
|
||||||
},
|
|
||||||
nativeName: {
|
|
||||||
type: DataTypes.STRING,
|
|
||||||
allowNull: false
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
timestamps: true,
|
|
||||||
version: true,
|
|
||||||
indexes: [
|
|
||||||
{
|
|
||||||
unique: true,
|
|
||||||
fields: ['code']
|
|
||||||
}
|
|
||||||
]
|
|
||||||
})
|
|
||||||
|
|
||||||
return localeSchema
|
|
||||||
}
|
|
@ -1,36 +0,0 @@
|
|||||||
/**
|
|
||||||
* Right schema
|
|
||||||
*/
|
|
||||||
module.exports = (sequelize, DataTypes) => {
|
|
||||||
let rightSchema = sequelize.define('right', {
|
|
||||||
path: {
|
|
||||||
type: DataTypes.STRING,
|
|
||||||
allowNull: false
|
|
||||||
},
|
|
||||||
role: {
|
|
||||||
type: DataTypes.ENUM('read', 'write', 'manage'),
|
|
||||||
allowNull: false,
|
|
||||||
defaultValue: 'read'
|
|
||||||
},
|
|
||||||
exact: {
|
|
||||||
type: DataTypes.BOOLEAN,
|
|
||||||
allowNull: false,
|
|
||||||
defaultValue: false
|
|
||||||
},
|
|
||||||
allow: {
|
|
||||||
type: DataTypes.BOOLEAN,
|
|
||||||
allowNull: false,
|
|
||||||
defaultValue: false
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
timestamps: true,
|
|
||||||
version: true,
|
|
||||||
indexes: [
|
|
||||||
{
|
|
||||||
fields: ['path']
|
|
||||||
}
|
|
||||||
]
|
|
||||||
})
|
|
||||||
|
|
||||||
return rightSchema
|
|
||||||
}
|
|
@ -1,26 +0,0 @@
|
|||||||
/**
|
|
||||||
* Settings schema
|
|
||||||
*/
|
|
||||||
module.exports = (sequelize, DataTypes) => {
|
|
||||||
let settingSchema = sequelize.define('setting', {
|
|
||||||
key: {
|
|
||||||
type: DataTypes.STRING,
|
|
||||||
allowNull: false
|
|
||||||
},
|
|
||||||
config: {
|
|
||||||
type: DataTypes.JSON,
|
|
||||||
allowNull: false
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
timestamps: true,
|
|
||||||
version: true,
|
|
||||||
indexes: [
|
|
||||||
{
|
|
||||||
unique: true,
|
|
||||||
fields: ['key']
|
|
||||||
}
|
|
||||||
]
|
|
||||||
})
|
|
||||||
|
|
||||||
return settingSchema
|
|
||||||
}
|
|
@ -1,22 +0,0 @@
|
|||||||
/**
|
|
||||||
* Tags schema
|
|
||||||
*/
|
|
||||||
module.exports = (sequelize, DataTypes) => {
|
|
||||||
let tagSchema = sequelize.define('tag', {
|
|
||||||
key: {
|
|
||||||
type: DataTypes.STRING,
|
|
||||||
allowNull: false
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
timestamps: true,
|
|
||||||
version: true,
|
|
||||||
indexes: [
|
|
||||||
{
|
|
||||||
unique: true,
|
|
||||||
fields: ['key']
|
|
||||||
}
|
|
||||||
]
|
|
||||||
})
|
|
||||||
|
|
||||||
return tagSchema
|
|
||||||
}
|
|
@ -23,12 +23,12 @@ module.exports = {
|
|||||||
}).then((user) => {
|
}).then((user) => {
|
||||||
if (user) {
|
if (user) {
|
||||||
return user.verifyPassword(uPassword).then(() => {
|
return user.verifyPassword(uPassword).then(() => {
|
||||||
return done(null, user) || true
|
done(null, user)
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
return done(err, null)
|
done(err, null)
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
return done(new WIKI.Error.AuthLoginFailed(), null)
|
done(new WIKI.Error.AuthLoginFailed(), null)
|
||||||
}
|
}
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
done(err, null)
|
done(err, null)
|
||||||
|
@ -250,6 +250,8 @@ module.exports = () => {
|
|||||||
app.post('/finalize', async (req, res) => {
|
app.post('/finalize', async (req, res) => {
|
||||||
WIKI.telemetry.sendEvent('setup', 'finalize')
|
WIKI.telemetry.sendEvent('setup', 'finalize')
|
||||||
|
|
||||||
|
console.error('DUDE')
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Upgrade from WIKI.js 1.x?
|
// Upgrade from WIKI.js 1.x?
|
||||||
if (req.body.upgrade) {
|
if (req.body.upgrade) {
|
||||||
@ -307,6 +309,16 @@ module.exports = () => {
|
|||||||
{ key: 'uploads', value: WIKI.config.uploads }
|
{ key: 'uploads', value: WIKI.config.uploads }
|
||||||
])
|
])
|
||||||
|
|
||||||
|
// Create default locale
|
||||||
|
WIKI.logger.info('Installing default locale...')
|
||||||
|
await WIKI.db.locales.query().insert({
|
||||||
|
code: 'en',
|
||||||
|
strings: require('./locales/default.json'),
|
||||||
|
isRTL: false,
|
||||||
|
name: 'English',
|
||||||
|
nativeName: 'English'
|
||||||
|
})
|
||||||
|
|
||||||
// Create root administrator
|
// Create root administrator
|
||||||
WIKI.logger.info('Creating root administrator...')
|
WIKI.logger.info('Creating root administrator...')
|
||||||
await WIKI.db.users.query().insert({
|
await WIKI.db.users.query().insert({
|
||||||
@ -315,6 +327,7 @@ module.exports = () => {
|
|||||||
password: req.body.adminPassword,
|
password: req.body.adminPassword,
|
||||||
name: 'Administrator',
|
name: 'Administrator',
|
||||||
role: 'admin',
|
role: 'admin',
|
||||||
|
locale: 'en',
|
||||||
tfaIsActive: false
|
tfaIsActive: false
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -331,20 +344,11 @@ module.exports = () => {
|
|||||||
name: 'Guest',
|
name: 'Guest',
|
||||||
password: '',
|
password: '',
|
||||||
role: 'guest',
|
role: 'guest',
|
||||||
|
locale: 'en',
|
||||||
tfaIsActive: false
|
tfaIsActive: false
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create default locale
|
|
||||||
WIKI.logger.info('Installing default locale...')
|
|
||||||
await WIKI.db.locales.query().insert({
|
|
||||||
code: 'en',
|
|
||||||
strings: require('./locales/default.json'),
|
|
||||||
isRTL: false,
|
|
||||||
name: 'English',
|
|
||||||
nativeName: 'English'
|
|
||||||
})
|
|
||||||
|
|
||||||
WIKI.logger.info('Setup is complete!')
|
WIKI.logger.info('Setup is complete!')
|
||||||
res.json({
|
res.json({
|
||||||
ok: true,
|
ok: true,
|
||||||
|
Loading…
Reference in New Issue
Block a user