feat: delete page

This commit is contained in:
Nicolas Giard 2019-01-26 18:35:56 -05:00 committed by Nick
parent faa1f389d9
commit 658c105ab5
24 changed files with 2126 additions and 2955 deletions

1
.gitignore vendored
View File

@ -29,6 +29,7 @@ npm-debug.log*
/repo /repo
/data /data
/uploads /uploads
/content
*.sqlite *.sqlite
# IDE exclude # IDE exclude

View File

@ -5,8 +5,9 @@ This project adheres to [Semantic Versioning](http://semver.org/).
## [2.0.0-beta.12] - 2018-01-27 ## [2.0.0-beta.12] - 2018-01-27
### Added ### Added
- Added Patreon link in Contribute admin page - Added Patreon link in Contribute admin page
- Added Theme Code Injection feature - Added Theme Code Injection functionality
- Added Theme CSS Injection code minification - Added Theme CSS Injection code minification
- Added Page Delete functionality
### Fixed ### Fixed
- Fixed root admin refresh token fail - Fixed root admin refresh token fail
@ -14,6 +15,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
### Changed ### Changed
- Moved Insert Media button in Markdown editor - Moved Insert Media button in Markdown editor
- Use semver for DB migrations ordering
## [2.0.0-beta.11] - 2018-01-20 ## [2.0.0-beta.11] - 2018-01-20
- First beta release - First beta release

View File

@ -35,9 +35,12 @@ docker-dev-rebuild: ## Rebuild dockerized dev image
docker-dev-clean: ## Clean DB, redis and data folders docker-dev-clean: ## Clean DB, redis and data folders
rm -rf ./data rm -rf ./data
docker-compose -f ./dev/docker/docker-compose.yml -p wiki --project-directory . exec db psql --dbname=wiki --username=postgres --command='DROP SCHEMA IF EXISTS public CASCADE; CREATE SCHEMA public' docker-compose -f ./dev/docker/docker-compose.yml -p wiki --project-directory . exec db psql --dbname=wiki --username=wikijs --command='DROP SCHEMA IF EXISTS public CASCADE; CREATE SCHEMA public'
docker-compose -f ./dev/docker/docker-compose.yml -p wiki --project-directory . exec redis redis-cli flushall docker-compose -f ./dev/docker/docker-compose.yml -p wiki --project-directory . exec redis redis-cli flushall
docker-dev-bash: ## Rebuild dockerized dev image
docker-compose -f ./dev/docker/docker-compose.yml -p wiki --project-directory . exec wiki bash
docker-build: ## Run assets generation build in docker docker-build: ## Run assets generation build in docker
docker-compose -f ./dev/docker/docker-compose.yml -p wiki --project-directory . run wiki yarn build docker-compose -f ./dev/docker/docker-compose.yml -p wiki --project-directory . run wiki yarn build
docker-compose -f ./dev/docker/docker-compose.yml -p wiki --project-directory . down docker-compose -f ./dev/docker/docker-compose.yml -p wiki --project-directory . down

View File

@ -203,7 +203,7 @@ export default {
<style lang='scss'> <style lang='scss'>
.admin { .admin {
&.theme--light { &.theme--light .application--wrap {
background-color: lighten(mc('grey', '200'), 2%); background-color: lighten(mc('grey', '200'), 2%);
} }
} }

View File

@ -79,6 +79,20 @@ export default {
restrictedForSystem: false, restrictedForSystem: false,
disabled: false disabled: false
}, },
{
permission: 'read:source',
hint: 'Can view pages source, as specified in the Page Rules',
warning: false,
restrictedForSystem: false,
disabled: false
},
{
permission: 'read:history',
hint: 'Can view pages history, as specified in the Page Rules',
warning: false,
restrictedForSystem: false,
disabled: false
},
{ {
permission: 'read:assets', permission: 'read:assets',
hint: 'Can view / use assets (such as images and files), as specified in the Page Rules', hint: 'Can view / use assets (such as images and files), as specified in the Page Rules',

View File

@ -206,6 +206,8 @@ export default {
{ text: 'Create Pages', value: 'write:pages', icon: 'insert_drive_file' }, { text: 'Create Pages', value: 'write:pages', icon: 'insert_drive_file' },
{ text: 'Edit + Move Pages', value: 'manage:pages', icon: 'insert_drive_file' }, { text: 'Edit + Move Pages', value: 'manage:pages', icon: 'insert_drive_file' },
{ text: 'Delete Pages', value: 'delete:pages', icon: 'insert_drive_file' }, { text: 'Delete Pages', value: 'delete:pages', icon: 'insert_drive_file' },
{ text: 'View Pages Source', value: 'read:source', icon: 'code' },
{ text: 'View Pages History', value: 'read:history', icon: 'restore' },
{ text: 'Read / Use Assets', value: 'read:assets', icon: 'camera' }, { text: 'Read / Use Assets', value: 'read:assets', icon: 'camera' },
{ text: 'Upload Assets', value: 'write:assets', icon: 'camera' }, { text: 'Upload Assets', value: 'write:assets', icon: 'camera' },
{ text: 'Edit + Delete Assets', value: 'manage:assets', icon: 'camera' }, { text: 'Edit + Delete Assets', value: 'manage:assets', icon: 'camera' },

View File

@ -131,6 +131,7 @@
span Login span Login
page-selector(mode='create', v-model='newPageModal', :open-handler='pageNewCreate') page-selector(mode='create', v-model='newPageModal', :open-handler='pageNewCreate')
page-delete(v-model='deletePageModal', v-if='path && path.length')
</template> </template>
<script> <script>
@ -139,6 +140,9 @@ import _ from 'lodash'
import Cookies from 'js-cookie' import Cookies from 'js-cookie'
export default { export default {
components: {
PageDelete: () => import('./page-delete.vue')
},
props: { props: {
dense: { dense: {
type: Boolean, type: Boolean,
@ -155,7 +159,8 @@ export default {
searchIsLoading: false, searchIsLoading: false,
searchIsShown: true, searchIsShown: true,
search: '', search: '',
newPageModal: false newPageModal: false,
deletePageModal: false
} }
}, },
computed: { computed: {
@ -233,11 +238,7 @@ export default {
}) })
}, },
pageDelete () { pageDelete () {
this.$store.commit('showNotification', { this.deletePageModal = true
style: 'indigo',
message: `Coming soon...`,
icon: 'directions_boat'
})
}, },
assets () { assets () {
this.$store.commit('showNotification', { this.$store.commit('showNotification', {

View File

@ -0,0 +1,110 @@
<template lang='pug'>
v-dialog(v-model='isShown', max-width='550', persistent)
v-card.wiki-form
.dialog-header.is-short.is-red
v-icon.mr-2(color='white') highlight_off
span Delete Page
v-card-text
.body-2 Are you sure you want to delete page #[span.red--text.text--darken-2 {{pageTitle}}]?
.caption The page can be restored from the administration area.
v-chip.mt-3.ml-0.mr-1(label, color='red lighten-4', disabled, small)
.caption.red--text.text--darken-2 {{pageLocale.toUpperCase()}}
v-chip.mt-3.mx-0(label, color='red lighten-5', disabled, small)
span.red--text.text--darken-2 /{{pagePath}}
v-card-chin
v-spacer
v-btn(flat, @click='discard', :disabled='loading') Cancel
v-btn(color='red darken-2', @click='deletePage', :loading='loading').white--text Delete
</template>
<script>
import _ from 'lodash'
import { get } from 'vuex-pathify'
import deletePageMutation from 'gql/common/common-pages-mutation-delete.gql'
export default {
props: {
value: {
type: Boolean,
default: false
}
},
data() {
return {
loading: false
}
},
computed: {
isShown: {
get() { return this.value },
set(val) { this.$emit('input', val) }
},
pageTitle: get('page/title'),
pagePath: get('page/path'),
pageLocale: get('page/locale'),
pageId: get('page/id')
},
watch: {
isShown(newValue, oldValue) {
if (newValue) {
document.body.classList.add('page-deleted-pending')
}
}
},
methods: {
discard() {
document.body.classList.remove('page-deleted-pending')
this.isShown = false
},
async deletePage() {
this.loading = true
this.$store.commit(`loadingStart`, 'page-delete')
this.$nextTick(async () => {
try {
const resp = await this.$apollo.mutate({
mutation: deletePageMutation,
variables: {
id: this.pageId
}
})
if (_.get(resp, 'data.pages.delete.responseResult.succeeded', false)) {
this.isShown = false
_.delay(() => {
document.body.classList.add('page-deleted')
_.delay(() => {
window.location.assign('/')
}, 1200)
}, 400)
} else {
throw new Error(_.get(resp, 'data.pages.delete.responseResult.message', 'An unexpected error occured.'))
}
} catch (err) {
this.$store.commit('pushGraphError', err)
}
this.$store.commit(`loadingStop`, 'page-delete')
this.loading = false
})
}
}
}
</script>
<style lang='scss'>
body.page-deleted-pending {
.application {
background-color: mc('grey', '900');
}
.application--wrap {
transform: translateZ(-5vw) rotateX(2deg);
border-radius: 7px;
overflow: hidden;
}
}
body.page-deleted {
.application--wrap {
transform: translateZ(-1000vw) rotateX(60deg);
opacity: 0;
}
}
</style>

View File

@ -14,7 +14,7 @@
outline outline
color='blue' color='blue'
@click.native.stop='openPropsModal' @click.native.stop='openPropsModal'
:class='{ "is-icon": $vuetify.breakpoint.mdAndDown, "mx-0": !welcomeMode, "ml-0": !welcomeMode }' :class='{ "is-icon": $vuetify.breakpoint.mdAndDown, "mx-0": !welcomeMode, "ml-0": welcomeMode }'
) )
v-icon(color='blue', :left='$vuetify.breakpoint.lgAndUp') sort_by_alpha v-icon(color='blue', :left='$vuetify.breakpoint.lgAndUp') sort_by_alpha
span.white--text(v-if='$vuetify.breakpoint.lgAndUp') {{ $t('editor:page') }} span.white--text(v-if='$vuetify.breakpoint.lgAndUp') {{ $t('editor:page') }}
@ -282,6 +282,10 @@ export default {
.editor { .editor {
background-color: mc('grey', '900') !important; background-color: mc('grey', '900') !important;
min-height: 100vh; min-height: 100vh;
.application--wrap {
background-color: mc('grey', '900');
}
} }
.atom-spinner.is-inline { .atom-spinner.is-inline {

View File

@ -0,0 +1,12 @@
mutation($id: Int!) {
pages {
delete(id: $id) {
responseResult {
succeeded
errorCode
slug
message
}
}
}
}

View File

@ -1,6 +1,8 @@
html { html {
box-sizing: border-box; box-sizing: border-box;
height: 100%; height: 100%;
perspective: 50vw;
background-color: mc('grey', '900');
} }
*, *:before, *:after { *, *:before, *:after {
box-sizing: inherit; box-sizing: inherit;
@ -19,6 +21,17 @@ html {
} }
} }
.application--wrap {
transition: all 1.2s ease;
transform-style: preserve-3d;
transform-origin: 50% 50%;
background-color: #FFF;
@at-root .theme--dark & {
background-color: mc('grey', '900');
}
}
@for $i from 0 through 25 { @for $i from 0 through 25 {
.radius-#{$i} { .radius-#{$i} {

View File

@ -132,6 +132,10 @@ export default {
StatusIndicator StatusIndicator
}, },
props: { props: {
pageId: {
type: Number,
default: 0
},
locale: { locale: {
type: String, type: String,
default: 'en' default: 'en'
@ -229,6 +233,7 @@ export default {
this.$store.commit('page/SET_CREATED_AT', this.createdAt) this.$store.commit('page/SET_CREATED_AT', this.createdAt)
this.$store.commit('page/SET_DESCRIPTION', this.description) this.$store.commit('page/SET_DESCRIPTION', this.description)
this.$store.commit('page/SET_IS_PUBLISHED', this.isPublished) this.$store.commit('page/SET_IS_PUBLISHED', this.isPublished)
this.$store.commit('page/SET_ID', this.pageId)
this.$store.commit('page/SET_LOCALE', this.locale) this.$store.commit('page/SET_LOCALE', this.locale)
this.$store.commit('page/SET_PATH', this.path) this.$store.commit('page/SET_PATH', this.path)
this.$store.commit('page/SET_TAGS', this.tags) this.$store.commit('page/SET_TAGS', this.tags)

View File

@ -5,7 +5,7 @@ FROM node:10-alpine
LABEL maintainer "requarks.io" LABEL maintainer "requarks.io"
RUN apk update && \ RUN apk update && \
apk add bash curl git python make g++ --no-cache && \ apk add bash curl git python make g++ nano --no-cache && \
mkdir -p /wiki mkdir -p /wiki
WORKDIR /wiki WORKDIR /wiki

View File

@ -1,6 +1,3 @@
# -- DEV DOCKER-COMPOSE --
# -- DO NOT USE IN PRODUCTION! --
version: "3" version: "3"
services: services:

View File

@ -40,17 +40,16 @@
}, },
"dependencies": { "dependencies": {
"apollo-fetch": "0.7.0", "apollo-fetch": "0.7.0",
"apollo-server": "2.2.2", "apollo-server": "2.3.2",
"apollo-server-express": "2.2.2", "apollo-server-express": "2.3.2",
"auto-load": "3.0.4", "auto-load": "3.0.4",
"axios": "0.18.0", "axios": "0.18.0",
"js-base64": "2.5.0",
"bcryptjs-then": "1.0.1", "bcryptjs-then": "1.0.1",
"bluebird": "3.5.3", "bluebird": "3.5.3",
"body-parser": "1.18.3", "body-parser": "1.18.3",
"bugsnag": "2.4.3", "bugsnag": "2.4.3",
"bull": "3.5.2", "bull": "3.6.0",
"chalk": "2.4.1", "chalk": "2.4.2",
"cheerio": "1.0.0-rc.2", "cheerio": "1.0.0-rc.2",
"child-process-promise": "2.2.1", "child-process-promise": "2.2.1",
"chokidar": "2.0.4", "chokidar": "2.0.4",
@ -60,36 +59,37 @@
"cookie-parser": "1.4.3", "cookie-parser": "1.4.3",
"cors": "2.8.5", "cors": "2.8.5",
"custom-error-instance": "2.1.1", "custom-error-instance": "2.1.1",
"dependency-graph": "0.7.2", "dependency-graph": "0.8.0",
"diff": "3.5.0", "diff": "4.0.1",
"diff2html": "2.5.0", "diff2html": "2.7.0",
"dotize": "^0.2.0", "dotize": "^0.2.0",
"execa": "1.0.0", "execa": "1.0.0",
"express": "4.16.4", "express": "4.16.4",
"express-brute": "1.0.1", "express-brute": "1.0.1",
"express-brute-redis": "0.0.1", "express-brute-redis": "0.0.1",
"express-session": "1.15.6", "express-session": "1.15.6",
"file-type": "10.4.0", "file-type": "10.7.1",
"filesize": "3.6.1", "filesize": "4.0.0",
"follow-redirects": "1.5.9", "follow-redirects": "1.6.1",
"fs-extra": "7.0.1", "fs-extra": "7.0.1",
"getos": "3.1.0", "getos": "3.1.1",
"graphql": "14.0.2", "graphql": "14.1.1",
"graphql-list-fields": "2.0.2", "graphql-list-fields": "2.0.2",
"graphql-subscriptions": "1.0.0", "graphql-subscriptions": "1.0.0",
"graphql-tools": "4.0.3", "graphql-tools": "4.0.4",
"highlight.js": "9.13.1", "highlight.js": "9.13.1",
"i18next": "12.0.0", "i18next": "14.0.1",
"i18next-express-middleware": "1.5.0", "i18next-express-middleware": "1.7.1",
"i18next-localstorage-cache": "1.1.1", "i18next-localstorage-cache": "1.1.1",
"i18next-node-fs-backend": "2.1.0", "i18next-node-fs-backend": "2.1.1",
"image-size": "0.6.3", "image-size": "0.7.1",
"ioredis": "4.2.0", "ioredis": "4.5.1",
"js-base64": "2.5.1",
"js-binary": "1.2.0", "js-binary": "1.2.0",
"js-yaml": "3.12.0", "js-yaml": "3.12.1",
"jsonwebtoken": "8.4.0", "jsonwebtoken": "8.4.0",
"klaw": "3.0.0", "klaw": "3.0.0",
"knex": "0.15.2", "knex": "0.16.3",
"lodash": "4.17.11", "lodash": "4.17.11",
"markdown-it": "8.4.2", "markdown-it": "8.4.2",
"markdown-it-abbr": "1.0.4", "markdown-it-abbr": "1.0.4",
@ -107,18 +107,18 @@
"markdown-it-task-lists": "2.1.1", "markdown-it-task-lists": "2.1.1",
"mathjax-node": "2.1.1", "mathjax-node": "2.1.1",
"mime-types": "2.1.21", "mime-types": "2.1.21",
"moment": "2.22.2", "moment": "2.24.0",
"moment-timezone": "0.5.23", "moment-timezone": "0.5.23",
"mongodb": "3.1.10", "mongodb": "3.1.13",
"mssql": "4.2.3", "mssql": "4.3.0",
"multer": "1.4.1", "multer": "1.4.1",
"mysql2": "1.6.4", "mysql2": "1.6.4",
"nanoid": "2.0.0", "nanoid": "2.0.1",
"node-2fa": "1.1.2", "node-2fa": "1.1.2",
"node-cache": "4.2.0", "node-cache": "4.2.0",
"nodemailer": "4.7.0", "nodemailer": "5.1.1",
"oauth2orize": "1.11.0", "oauth2orize": "1.11.0",
"objection": "1.4.0", "objection": "1.5.3",
"ora": "3.0.0", "ora": "3.0.0",
"passport": "0.4.0", "passport": "0.4.0",
"passport-auth0": "1.1.0", "passport-auth0": "1.1.0",
@ -126,23 +126,23 @@
"passport-cas": "0.1.1", "passport-cas": "0.1.1",
"passport-discord": "0.1.3", "passport-discord": "0.1.3",
"passport-dropbox-oauth2": "1.1.0", "passport-dropbox-oauth2": "1.1.0",
"passport-facebook": "2.1.1", "passport-facebook": "3.0.0",
"passport-github2": "0.1.11", "passport-github2": "0.1.11",
"passport-google-oauth20": "1.0.0", "passport-google-oauth20": "1.0.0",
"passport-jwt": "4.0.0", "passport-jwt": "4.0.0",
"passport-ldapauth": "2.1.0", "passport-ldapauth": "2.1.1",
"passport-local": "1.0.0", "passport-local": "1.0.0",
"passport-oauth2": "1.4.0", "passport-oauth2": "1.4.0",
"passport-okta-oauth": "0.0.1", "passport-okta-oauth": "0.0.1",
"passport-openidconnect": "0.0.2", "passport-openidconnect": "0.0.2",
"passport-saml": "0.35.0", "passport-saml": "1.0.0",
"passport-slack": "0.0.7", "passport-slack": "0.0.7",
"passport-twitch": "1.0.3", "passport-twitch": "1.0.3",
"passport-windowslive": "1.0.2", "passport-windowslive": "1.0.2",
"pem-jwk": "1.5.1", "pem-jwk": "2.0.0",
"pg": "7.6.1", "pg": "7.8.0",
"pg-hstore": "2.3.2", "pg-hstore": "2.3.2",
"pm2": "3.2.2", "pm2": "3.2.9",
"pug": "2.0.3", "pug": "2.0.3",
"qr-image": "3.2.0", "qr-image": "3.2.0",
"raven": "2.6.4", "raven": "2.6.4",
@ -154,73 +154,73 @@
"scim-query-filter-parser": "1.1.0", "scim-query-filter-parser": "1.1.0",
"semver": "5.6.0", "semver": "5.6.0",
"serve-favicon": "2.5.0", "serve-favicon": "2.5.0",
"sqlite3": "4.0.4", "sqlite3": "4.0.6",
"subscriptions-transport-ws": "0.9.15", "subscriptions-transport-ws": "0.9.15",
"twemoji": "11.2.0", "twemoji": "11.2.0",
"uslug": "1.0.4", "uslug": "1.0.4",
"uuid": "3.3.2", "uuid": "3.3.2",
"validate.js": "0.12.0", "validate.js": "0.12.0",
"validator": "10.9.0", "validator": "10.11.0",
"validator-as-promised": "1.0.2", "validator-as-promised": "1.0.2",
"winston": "3.1.0", "winston": "3.1.0",
"yargs": "12.0.4" "yargs": "12.0.5"
}, },
"devDependencies": { "devDependencies": {
"@babel/cli": "^7.1.5", "@babel/cli": "^7.2.3",
"@babel/core": "^7.1.6", "@babel/core": "^7.2.2",
"@babel/plugin-proposal-class-properties": "^7.1.0", "@babel/plugin-proposal-class-properties": "^7.3.0",
"@babel/plugin-proposal-decorators": "^7.1.6", "@babel/plugin-proposal-decorators": "^7.3.0",
"@babel/plugin-proposal-export-namespace-from": "^7.0.0", "@babel/plugin-proposal-export-namespace-from": "^7.2.0",
"@babel/plugin-proposal-function-sent": "^7.1.0", "@babel/plugin-proposal-function-sent": "^7.2.0",
"@babel/plugin-proposal-json-strings": "^7.0.0", "@babel/plugin-proposal-json-strings": "^7.2.0",
"@babel/plugin-proposal-numeric-separator": "^7.0.0", "@babel/plugin-proposal-numeric-separator": "^7.2.0",
"@babel/plugin-proposal-throw-expressions": "^7.0.0", "@babel/plugin-proposal-throw-expressions": "^7.2.0",
"@babel/plugin-syntax-dynamic-import": "^7.0.0", "@babel/plugin-syntax-dynamic-import": "^7.2.0",
"@babel/plugin-syntax-import-meta": "^7.0.0", "@babel/plugin-syntax-import-meta": "^7.2.0",
"@babel/polyfill": "^7.0.0", "@babel/polyfill": "^7.2.5",
"@babel/preset-env": "^7.1.6", "@babel/preset-env": "^7.3.1",
"@panter/vue-i18next": "0.13.0", "@panter/vue-i18next": "0.15.0",
"animated-number-vue": "0.1.3", "animated-number-vue": "0.1.4",
"apollo-cache-inmemory": "1.3.10", "apollo-cache-inmemory": "1.4.2",
"apollo-client": "2.4.6", "apollo-client": "2.4.12",
"apollo-link": "1.2.3", "apollo-link": "1.2.6",
"apollo-link-batch-http": "1.2.3", "apollo-link-batch-http": "1.2.6",
"apollo-link-error": "1.1.1", "apollo-link-error": "1.1.5",
"apollo-link-http": "1.5.5", "apollo-link-http": "1.5.9",
"apollo-link-persisted-queries": "0.2.2", "apollo-link-persisted-queries": "0.2.2",
"apollo-link-ws": "1.0.9", "apollo-link-ws": "1.0.12",
"apollo-utilities": "1.0.25", "apollo-utilities": "1.1.2",
"autoprefixer": "9.3.1", "autoprefixer": "9.4.6",
"babel-eslint": "10.0.1", "babel-eslint": "10.0.1",
"babel-jest": "23.6.0", "babel-jest": "24.0.0",
"babel-loader": "^8.0.4", "babel-loader": "^8.0.5",
"babel-plugin-graphql-tag": "1.6.0", "babel-plugin-graphql-tag": "1.6.0",
"babel-plugin-lodash": "3.3.4", "babel-plugin-lodash": "3.3.4",
"babel-plugin-transform-imports": "1.5.1", "babel-plugin-transform-imports": "1.5.1",
"brace": "0.11.1", "brace": "0.11.1",
"cache-loader": "1.2.5", "cache-loader": "2.0.1",
"chart.js": "2.7.3", "chart.js": "2.7.3",
"clean-webpack-plugin": "1.0.0", "clean-webpack-plugin": "1.0.1",
"copy-webpack-plugin": "4.6.0", "copy-webpack-plugin": "4.6.0",
"core-js": "2.5.7", "core-js": "2.6.3",
"css-loader": "1.0.1", "css-loader": "2.1.0",
"cssnano": "4.1.7", "cssnano": "4.1.8",
"duplicate-package-checker-webpack-plugin": "3.0.0", "duplicate-package-checker-webpack-plugin": "3.0.0",
"epic-spinners": "1.0.4", "epic-spinners": "1.0.4",
"eslint": "5.9.0", "eslint": "5.12.1",
"eslint-config-requarks": "1.0.7", "eslint-config-requarks": "1.0.7",
"eslint-config-standard": "12.0.0", "eslint-config-standard": "12.0.0",
"eslint-plugin-import": "2.14.0", "eslint-plugin-import": "2.15.0",
"eslint-plugin-node": "8.0.0", "eslint-plugin-node": "8.0.1",
"eslint-plugin-promise": "4.0.1", "eslint-plugin-promise": "4.0.1",
"eslint-plugin-standard": "4.0.0", "eslint-plugin-standard": "4.0.0",
"eslint-plugin-vue": "4.7.1", "eslint-plugin-vue": "5.1.0",
"file-loader": "2.0.0", "file-loader": "3.0.1",
"filesize.js": "1.0.2", "filesize.js": "1.0.2",
"grapesjs": "0.14.40", "grapesjs": "0.14.50",
"graphiql": "0.12.0", "graphiql": "0.12.0",
"graphql-persisted-document-loader": "1.0.1", "graphql-persisted-document-loader": "1.0.1",
"graphql-tag": "^2.10.0", "graphql-tag": "^2.10.1",
"graphql-voyager": "1.0.0-rc.26", "graphql-voyager": "1.0.0-rc.26",
"hammerjs": "2.0.8", "hammerjs": "2.0.8",
"html-webpack-plugin": "3.2.0", "html-webpack-plugin": "3.2.0",
@ -228,8 +228,8 @@
"i18next-xhr-backend": "1.5.1", "i18next-xhr-backend": "1.5.1",
"ignore-loader": "0.1.2", "ignore-loader": "0.1.2",
"js-cookie": "2.2.0", "js-cookie": "2.2.0",
"mini-css-extract-plugin": "0.4.4", "mini-css-extract-plugin": "0.5.0",
"node-sass": "4.9.4", "node-sass": "4.11.0",
"offline-plugin": "5.0.6", "offline-plugin": "5.0.6",
"optimize-css-assets-webpack-plugin": "5.0.1", "optimize-css-assets-webpack-plugin": "5.0.1",
"postcss-cssnext": "3.1.0", "postcss-cssnext": "3.1.0",
@ -237,14 +237,14 @@
"postcss-flexibility": "2.0.0", "postcss-flexibility": "2.0.0",
"postcss-import": "12.0.1", "postcss-import": "12.0.1",
"postcss-loader": "3.0.0", "postcss-loader": "3.0.0",
"postcss-preset-env": "6.4.0", "postcss-preset-env": "6.5.0",
"postcss-selector-parser": "5.0.0-rc.4", "postcss-selector-parser": "5.0.0",
"pug-lint": "2.5.0", "pug-lint": "2.5.0",
"pug-loader": "2.4.0", "pug-loader": "2.4.0",
"pug-plain-loader": "1.0.0", "pug-plain-loader": "1.0.0",
"raw-loader": "0.5.1", "raw-loader": "1.0.0",
"react": "16.6.3", "react": "16.7.0",
"react-dom": "16.6.3", "react-dom": "16.7.0",
"resolve-url-loader": "3.0.0", "resolve-url-loader": "3.0.0",
"sass-loader": "7.1.0", "sass-loader": "7.1.0",
"sass-resources-loader": "2.0.0", "sass-resources-loader": "2.0.0",
@ -255,40 +255,40 @@
"stylus-loader": "3.0.2", "stylus-loader": "3.0.2",
"twemoji-awesome": "1.0.6", "twemoji-awesome": "1.0.6",
"url-loader": "1.1.2", "url-loader": "1.1.2",
"vee-validate": "2.1.3", "vee-validate": "2.1.5",
"velocity-animate": "1.5.2", "velocity-animate": "1.5.2",
"viz.js": "2.1.1", "viz.js": "2.1.2",
"vue": "2.5.17", "vue": "2.5.22",
"vue-apollo": "3.0.0-beta.26", "vue-apollo": "3.0.0-beta.27",
"vue-chartjs": "3.4.0", "vue-chartjs": "3.4.0",
"vue-clipboards": "1.2.4", "vue-clipboards": "1.2.4",
"vue-codemirror": "4.0.6", "vue-codemirror": "4.0.6",
"vue-hot-reload-api": "2.3.1", "vue-hot-reload-api": "2.3.1",
"vue-loader": "15.4.2", "vue-loader": "15.6.1",
"vue-material-design-icons": "2.4.0", "vue-material-design-icons": "2.6.0",
"vue-moment": "4.0.0", "vue-moment": "4.0.0",
"vue-router": "3.0.1", "vue-router": "3.0.2",
"vue-simple-breakpoints": "1.0.3", "vue-simple-breakpoints": "1.0.3",
"vue-status-indicator": "1.1.1", "vue-status-indicator": "1.1.1",
"vue-template-compiler": "2.5.17", "vue-template-compiler": "2.5.22",
"vue-tour": "1.1.0", "vue-tour": "1.1.0",
"vue2-animate": "2.1.0", "vue2-animate": "2.1.0",
"vuedraggable": "2.16.0", "vuedraggable": "2.17.0",
"vuescroll": "4.9.0-beta.14", "vuescroll": "4.9.6",
"vuetify": "1.3.8", "vuetify": "1.4.3",
"vuex": "3.0.1", "vuex": "3.1.0",
"vuex-pathify": "1.1.3", "vuex-pathify": "1.1.3",
"vuex-persistedstate": "2.5.4", "vuex-persistedstate": "2.5.4",
"webpack": "4.25.1", "webpack": "4.29.0",
"webpack-bundle-analyzer": "3.0.3", "webpack-bundle-analyzer": "3.0.3",
"webpack-cli": "3.1.2", "webpack-cli": "3.2.1",
"webpack-dev-middleware": "3.4.0", "webpack-dev-middleware": "3.5.1",
"webpack-hot-middleware": "2.24.3", "webpack-hot-middleware": "2.24.3",
"webpack-merge": "4.1.4", "webpack-merge": "4.2.1",
"webpack-subresource-integrity": "1.3.0", "webpack-subresource-integrity": "1.3.1",
"whatwg-fetch": "3.0.0", "whatwg-fetch": "3.0.0",
"write-file-webpack-plugin": "4.4.1", "write-file-webpack-plugin": "4.5.0",
"xterm": "3.8.0", "xterm": "3.10.1",
"zxcvbn": "4.4.2" "zxcvbn": "4.4.2"
}, },
"browserslist": [ "browserslist": [

View File

@ -5,6 +5,8 @@ const Promise = require('bluebird')
const Knex = require('knex') const Knex = require('knex')
const Objection = require('objection') const Objection = require('objection')
const migrationSource = require('../db/migrator-source')
/* global WIKI */ /* global WIKI */
/** /**
@ -89,12 +91,14 @@ module.exports = {
// Set init tasks // Set init tasks
console.info(migrationSource)
let initTasks = { let initTasks = {
// -> Migrate DB Schemas // -> Migrate DB Schemas
async syncSchemas() { async syncSchemas() {
return self.knex.migrate.latest({ return self.knex.migrate.latest({
directory: path.join(WIKI.SERVERPATH, 'db/migrations'), tableName: 'migrations',
tableName: 'migrations' migrationSource
}) })
} }
} }

View File

@ -1,6 +1,8 @@
const _ = require('lodash') const _ = require('lodash')
const cfgHelper = require('../helpers/config') const cfgHelper = require('../helpers/config')
const Promise = require('bluebird') const Promise = require('bluebird')
const fs = require('fs-extra')
const path = require('path')
/* global WIKI */ /* global WIKI */
@ -22,6 +24,9 @@ module.exports = {
} }
}) })
// Clear content cache
fs.emptyDir(path.join(WIKI.ROOTPATH, 'data/cache'))
return this return this
}, },
/** /**

View File

@ -0,0 +1,15 @@
exports.up = knex => {
return knex.schema
.table('pageHistory', table => {
table.string('action').defaultTo('updated')
table.dropForeign('pageId')
})
}
exports.down = knex => {
return knex.schema
.table('pageHistory', table => {
table.dropColumn('action')
table.integer('pageId').unsigned().references('id').inTable('pages')
})
}

View File

@ -0,0 +1,28 @@
const path = require('path')
const fs = require('fs-extra')
const semver = require('semver')
/* global WIKI */
module.exports = {
/**
* Gets the migration names
* @returns Promise<string[]>
*/
async getMigrations() {
const absoluteDir = path.join(WIKI.SERVERPATH, 'db/migrations')
const migrationFiles = await fs.readdirAsync(absoluteDir)
return migrationFiles.sort(semver.compare).map(m => ({
file: m,
directory: absoluteDir
}))
},
getMigrationName(migration) {
return migration.file;
},
getMigration(migration) {
return require(path.join(WIKI.SERVERPATH, 'db/migrations', migration.file));
}
}

View File

@ -29,8 +29,11 @@ module.exports = {
page page
} }
}, },
async delete(obj, args) { async delete(obj, args, context) {
await WIKI.models.groups.query().deleteById(args.id) await WIKI.models.pages.deletePage({
...args,
authorId: context.req.user.id
})
return { return {
responseResult: graphHelper.generateSuccess('Page has been deleted.') responseResult: graphHelper.generateSuccess('Page has been deleted.')
} }

View File

@ -99,7 +99,8 @@ module.exports = class PageHistory extends Model {
path: opts.path, path: opts.path,
publishEndDate: opts.publishEndDate || '', publishEndDate: opts.publishEndDate || '',
publishStartDate: opts.publishStartDate || '', publishStartDate: opts.publishStartDate || '',
title: opts.title title: opts.title,
action: opts.action || 'updated'
}) })
} }
@ -109,6 +110,7 @@ module.exports = class PageHistory extends Model {
'pageHistory.id', 'pageHistory.id',
'pageHistory.path', 'pageHistory.path',
'pageHistory.authorId', 'pageHistory.authorId',
'pageHistory.action',
'pageHistory.createdAt', 'pageHistory.createdAt',
{ {
authorName: 'author.name' authorName: 'author.name'
@ -130,6 +132,7 @@ module.exports = class PageHistory extends Model {
'pageHistory.id', 'pageHistory.id',
'pageHistory.path', 'pageHistory.path',
'pageHistory.authorId', 'pageHistory.authorId',
'pageHistory.action',
'pageHistory.createdAt', 'pageHistory.createdAt',
{ {
authorName: 'author.name' authorName: 'author.name'

View File

@ -96,6 +96,7 @@ module.exports = class Page extends Model {
static get cacheSchema() { static get cacheSchema() {
return new JSBinType({ return new JSBinType({
id: 'uint',
authorId: 'uint', authorId: 'uint',
authorName: 'string', authorName: 'string',
createdAt: 'string', createdAt: 'string',
@ -150,7 +151,10 @@ module.exports = class Page extends Model {
if (!ogPage) { if (!ogPage) {
throw new Error('Invalid Page Id') throw new Error('Invalid Page Id')
} }
await WIKI.models.pageHistory.addVersion(ogPage) await WIKI.models.pageHistory.addVersion({
...ogPage,
action: 'updated'
})
await WIKI.models.pages.query().patch({ await WIKI.models.pages.query().patch({
authorId: opts.authorId, authorId: opts.authorId,
content: opts.content, content: opts.content,
@ -174,6 +178,23 @@ module.exports = class Page extends Model {
return page return page
} }
static async deletePage(opts) {
const page = await WIKI.models.pages.query().findById(opts.id)
if (!page) {
throw new Error('Invalid Page Id')
}
await WIKI.models.pageHistory.addVersion({
...page,
action: 'deleted'
})
await WIKI.models.pages.query().delete().where('id', page.id)
await WIKI.models.pages.deletePageFromCache(page)
await WIKI.models.storage.pageEvent({
event: 'deleted',
page
})
}
static async renderPage(page) { static async renderPage(page) {
const pipeline = await WIKI.models.renderers.getRenderingPipeline(page.contentType) const pipeline = await WIKI.models.renderers.getRenderingPipeline(page.contentType)
WIKI.queue.job.renderPage.add({ WIKI.queue.job.renderPage.add({
@ -232,6 +253,7 @@ module.exports = class Page extends Model {
static async savePageToCache(page) { static async savePageToCache(page) {
const cachePath = path.join(process.cwd(), `data/cache/${page.hash}.bin`) const cachePath = path.join(process.cwd(), `data/cache/${page.hash}.bin`)
await fs.outputFile(cachePath, WIKI.models.pages.cacheSchema.encode({ await fs.outputFile(cachePath, WIKI.models.pages.cacheSchema.encode({
id: page.id,
authorId: page.authorId, authorId: page.authorId,
authorName: page.authorName, authorName: page.authorName,
createdAt: page.createdAt, createdAt: page.createdAt,
@ -270,4 +292,8 @@ module.exports = class Page extends Model {
throw err throw err
} }
} }
static async deletePageFromCache(page) {
return fs.remove(path.join(process.cwd(), `data/cache/${page.hash}.bin`))
}
} }

View File

@ -20,6 +20,7 @@ block body
:author-id=page.authorId :author-id=page.authorId
:is-published=page.isPublished.toString() :is-published=page.isPublished.toString()
:toc=page.toc :toc=page.toc
:page-id=page.id
) )
template(slot='sidebar') template(slot='sidebar')
each navItem in sidebar each navItem in sidebar

4592
yarn.lock

File diff suppressed because it is too large Load Diff