Merge branch 'latest' of github.com:Requarks/wiki into tyclipso

pull/7734/head
Carl Richter 4 years ago
commit 672fd84e96

@ -14,13 +14,14 @@
[![Standard - JavaScript Style Guide](https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat)](http://standardjs.com/)
[![Chat on Slack](https://img.shields.io/badge/slack-requarks-CC2B5E.svg?style=flat&logo=slack)](https://wiki.requarks.io/slack)
[![Twitter Follow](https://img.shields.io/badge/follow-%40requarks-blue.svg?style=flat&logo=twitter)](https://twitter.com/requarks)
[![Reddit](https://img.shields.io/badge/reddit-%2Fr%2Fwikijs-orange?logo=reddit&logoColor=white)](https://www.reddit.com/r/wikijs/)
[![Subscribe to Newsletter](https://img.shields.io/badge/newsletter-subscribe-yellow.svg?style=flat&logo=mailchimp)](https://blog.js.wiki/subscribe)
##### A modern, lightweight and powerful wiki app built on NodeJS
</div>
- **[Official Website](https://wiki.js.org/)**
- **[Official Website](https://js.wiki/)**
- **[Documentation](https://docs.requarks.io/)**
- [Requirements](https://docs.requarks.io/install/requirements)
- [Installation](https://docs.requarks.io/install)
@ -74,6 +75,11 @@ Support this project by becoming a sponsor. Your name will show up in the Contri
<img src="https://static.requarks.io/sponsors/gigabitelabs-148x129.png">
</a>
</td>
<td align="center" valign="middle" width="148">
<a href="https://github.com/JayDaley" target="_blank">
Jay Daley<br />(@JayDaley)
</a>
</td>
<td align="center" valign="middle" width="148">
<a href="https://github.com/idokka" target="_blank">
Oleksii<br />(@idokka)
@ -84,18 +90,20 @@ Support this project by becoming a sponsor. Your name will show up in the Contri
Theodore Chu<br />(@TheodoreChu)
</a>
</td>
<td align="center" valign="middle" width="148">
<!--<td align="center" valign="middle" width="148">
<a href="https://github.com/sponsors/NGPixel" target="_blank">
<img src="https://static.requarks.io/sponsors/become-148x72.png">
</a>
</td>
</td>-->
</tr>
</tbody>
</table>
</div>
- Akira Suenami ([@a-suenami](https://github.com/a-suenami))
- Arnaud Marchand ([@snuids](https://github.com/snuids))
- Bryon Vandiver ([@asterick](https://github.com/asterick))
- Cameron Steele ([@ATechAdventurer](https://github.com/ATechAdventurer))
- Cloud Data Hosting LLC ([@CloudDataHostingLLC](https://github.com/CloudDataHostingLLC))
- CrazyMarvin ([@CrazyMarvin](https://github.com/CrazyMarvin))
- David Christian Holin ([@SirGibihm](https://github.com/SirGibihm))
@ -104,9 +112,11 @@ Support this project by becoming a sponsor. Your name will show up in the Contri
- Ernie ([@iamernie](https://github.com/iamernie))
- Florian Moss ([@florianmoss](https://github.com/florianmoss))
- HeavenBay ([@HeavenBay](https://github.com/heavenbay))
- Jaimyn Mayer ([@jabelone](https://github.com/jabelone))
- Jay Lee ([@polyglotm](https://github.com/polyglotm))
- Kelly Wardrop ([@dropcoded](https://github.com/dropcoded))
- Loki ([@binaryloki](https://github.com/binaryloki))
- Marcilio Leite Neto ([@marclneto](https://github.com/marclneto))
- Mattias Johnson ([@mattiasJohnson](https://github.com/mattiasJohnson))
- Mitchell Rowton ([@mrowton](https://github.com/mrowton))
- M. Scott Ford ([@mscottford](https://github.com/mscottford))
@ -122,6 +132,7 @@ Support this project by becoming a sponsor. Your name will show up in the Contri
- aniketpanjwani ([@aniketpanjwani](https://github.com/aniketpanjwani))
- aytaa ([@aytaa](https://github.com/aytaa))
- magicpotato ([@fortheday](https://github.com/fortheday))
- motoacs ([@motoacs](https://github.com/motoacs))
- scorpion ([@scorpion](https://github.com/scorpion))
- valantien ([@valantien](https://github.com/valantien))
@ -230,6 +241,7 @@ Thank you to all our patrons! 🙏 [[Become a patron](https://www.patreon.com/re
- Alex Zen
- Arti Zirk
- Brandon Curtis
- Dave 'Sri' Seah
- djagoo
- Douglas Lassance
- Ernie Reid
@ -238,6 +250,7 @@ Thank you to all our patrons! 🙏 [[Become a patron](https://www.patreon.com/re
- Florent
- Günter Pavlas
- hong
- Hope
- Ian
- Iskander Callos
- Josh Stewart
@ -245,9 +258,11 @@ Thank you to all our patrons! 🙏 [[Become a patron](https://www.patreon.com/re
- Keir
- Loïc CRAMPON
- Ludgeir Ibanez
- Mark Mansur
- Matt Gedigian
- Patryk
- Philipp Schürch
- Tracey Duffy
- Richeir
- SmartNET.works
- Stepan Sokolovskyi

@ -61,6 +61,7 @@
sort-by='updatedAt',
sort-desc,
hide-default-footer
@page-count="pageTotal = $event"
)
template(slot='item', slot-scope='props')
tr.is-clickable(:active='props.selected', @click='$router.push(`/pages/` + props.item.id)')
@ -89,6 +90,7 @@ export default {
selectedPage: {},
pagination: 1,
pages: [],
pageTotal: 0,
headers: [
{ text: 'ID', value: 'id', width: 80, sortable: true },
{ text: 'Title', value: 'title' },
@ -108,9 +110,6 @@ export default {
}
},
computed: {
pageTotal () {
return Math.ceil(this.filteredPages.length / 15)
},
filteredPages () {
return _.filter(this.pages, pg => {
if (this.selectedLang !== null && this.selectedLang !== pg.locale) {

@ -564,11 +564,11 @@ export default {
if (window.location.hash && window.location.hash.length > 1) {
if (document.readyState === 'complete') {
this.$nextTick(() => {
this.$vuetify.goTo(window.location.hash, this.scrollOpts)
this.$vuetify.goTo(decodeURIComponent(window.location.hash), this.scrollOpts)
})
} else {
window.addEventListener('load', () => {
this.$vuetify.goTo(window.location.hash, this.scrollOpts)
this.$vuetify.goTo(decodeURIComponent(window.location.hash), this.scrollOpts)
})
}
}
@ -579,7 +579,7 @@ export default {
el.onclick = ev => {
ev.preventDefault()
ev.stopPropagation()
this.$vuetify.goTo(decodeURIComponent(ev.target.hash), this.scrollOpts)
this.$vuetify.goTo(decodeURIComponent(ev.currentTarget.hash), this.scrollOpts)
}
})
})

@ -43,6 +43,9 @@ db:
# pfx: path/to/cert.pfx
# passphrase: xyz123
# Optional - PostgreSQL only:
schema: public
# SQLite only:
storage: path/to/database.sqlite

@ -2,7 +2,7 @@ apiVersion: v2
name: wiki
# This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version.
version: 2.1.0
version: 2.2.0
# This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application.
AppVersion: latest

@ -107,6 +107,8 @@ The following table lists the configurable parameters of the Wiki.js chart and t
| `postgresql.postgresqlUser` | Postgres username | `postgres` |
| `postgresql.postgresqlHost` | External postgres host | `nil` |
| `postgresql.postgresqlPassword` | External postgres password | `nil` |
| `postgresql.existingSecret` | Provide an existing `Secret` for postgres | `nil` |
| `postgresql.existingSecretKey` | The postgres password key in the existing `Secret` | `postgresql-password` |
| `postgresql.postgresqlPort` | External postgres port | `5432` |
| `postgresql.ssl` | Enable external postgres SSL connection | `false` |
| `postgresql.ca` | Certificate of Authority path for postgres | `nil` |
@ -137,11 +139,11 @@ By default, PostgreSQL is installed as part of the chart.
### Using an external PostgreSQL server
To use an external PostgreSQL server, set `postgresql.enabled` to `false` and then set `postgresql.postgresqlHost` and `postgresql.postgresqlPassword`. The other options (`postgresql.postgresqlDatabase`, `postgresql.postgresqlUser` and `postgresql.postgresqlPort`) may also want changing from their default values.
To use an external PostgreSQL server, set `postgresql.enabled` to `false` and then set `postgresql.postgresqlHost` and `postgresql.postgresqlPassword`. To use an existing `Secret`, set `postgresql.existingSecret`. The other options (`postgresql.postgresqlDatabase`, `postgresql.postgresqlUser`, `postgresql.postgresqlPort` and `postgresql.existingSecretKey`) may also want changing from their default values.
To use an SSL connection you can set `postgresql.ssl` to `true` and if needed the path to a Certificate of Authority can be set using `postgresql.ca` to `/path/to/ca`. Default `postgresql.ssl` value is `false`.
You also need to add the follow Helm template to your deployment:
If `postgresql.existingSecret` is not specified, you also need to add the following Helm template to your deployment in order to create the postgresql `Secret`:
```yaml
kind: Secret
@ -159,4 +161,4 @@ See the [Configuration](#configuration) section to configure the PVC or to disab
## Ingress
This chart provides support for Ingress resource. If you have an available Ingress Controller such as Nginx or Traefik you maybe want to set `ingress.enabled` to true and choose an `ingress.hostname` for the URL. Then, you should be able to access the installation using that address.
This chart provides support for Ingress resource. If you have an available Ingress Controller such as Nginx or Traefik you maybe want to set `ingress.enabled` to true and add `ingress.hosts` for the URL. Then, you should be able to access the installation using that address.

@ -51,18 +51,16 @@ spec:
name: {{ template "wiki.postgresql.secret" . }}
{{- end }}
key: {{ template "wiki.postgresql.secretKey" . }}
- name: HA
value: {{ .Values.replicaCount | int | le 2 | quote }}
ports:
- name: http
containerPort: 3000
protocol: TCP
livenessProbe:
httpGet:
path: /healthz
port: http
{{- toYaml .Values.livenessProbe | nindent 12 }}
readinessProbe:
httpGet:
path: /healthz
port: http
{{- toYaml .Values.readinessProbe | nindent 12 }}
resources:
{{- toYaml .Values.resources | nindent 12 }}
{{- with .Values.nodeSelector }}

@ -1,11 +1,18 @@
{{- if .Values.ingress.enabled -}}
{{- $fullName := include "wiki.fullname" . -}}
{{- $svcPort := .Values.service.port -}}
{{- if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}}
{{- $fullName := include "wiki.fullname" . -}}
{{- $svcPort := .Values.service.port -}}
{{- if and .Values.ingress.className (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) }}
{{- if not (hasKey .Values.ingress.annotations "kubernetes.io/ingress.class") }}
{{- $_ := set .Values.ingress.annotations "kubernetes.io/ingress.class" .Values.ingress.className}}
{{- end }}
{{- end }}
{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}}
apiVersion: networking.k8s.io/v1
{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}}
apiVersion: networking.k8s.io/v1beta1
{{- else -}}
{{- else -}}
apiVersion: extensions/v1beta1
{{- end }}
{{- end }}
kind: Ingress
metadata:
name: {{ $fullName }}
@ -31,11 +38,21 @@ spec:
- host: {{ .host | quote }}
http:
paths:
{{- range .paths }}
- path: {{ . }}
{{- range .paths }}
- path: {{ .path }}
{{- if and .pathType (semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion) }}
pathType: {{ .pathType }}
{{- end }}
backend:
{{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }}
service:
name: {{ $fullName }}
port:
number: {{ $svcPort }}
{{- else }}
serviceName: {{ $fullName }}
servicePort: {{ $svcPort }}
{{- end }}
{{- end }}
{{- end }}
{{- end }}
{{- end }}
{{- end }}

@ -21,6 +21,16 @@ serviceAccount:
# If not set and create is true, a name is generated using the fullname template
name:
livenessProbe:
httpGet:
path: /healthz
port: http
readinessProbe:
httpGet:
path: /healthz
port: http
podSecurityContext: {}
# fsGroup: 2000
@ -42,13 +52,16 @@ service:
# annotations: {}
ingress:
enabled: false
enabled: true
annotations: {}
# kubernetes.io/ingress.class: nginx
# kubernetes.io/tls-acme: "true"
hosts:
- host: wiki.local
paths: ["/"]
- host: wiki.minikube.local
paths:
- path: "/"
pathType: Prefix
tls: []
# - secretName: chart-example-tls
# hosts:

@ -36,7 +36,6 @@
"node": ">=10.12"
},
"dependencies": {
"@aoberoi/passport-slack": "1.0.5",
"@azure/storage-blob": "12.2.1",
"@exlinc/keycloak-passport": "1.0.2",
"@joplin/turndown-plugin-gfm": "1.0.27",
@ -151,6 +150,7 @@
"passport-okta-oauth": "0.0.1",
"passport-openidconnect": "0.0.2",
"passport-saml": "1.3.5",
"passport-slack-oauth2": "1.1.1",
"passport-twitch-oauth": "1.0.0",
"pem-jwk": "2.0.0",
"pg": "8.4.1",

@ -76,7 +76,7 @@ router.post('/u', (req, res, next) => {
}
// Sanitize filename
fileMeta.originalname = sanitize(fileMeta.originalname.toLowerCase().replace(/[\s,;]+/g, '_'))
fileMeta.originalname = sanitize(fileMeta.originalname.toLowerCase().replace(/[\s,;#]+/g, '_'))
// Check if user can upload at path
const assetPath = (folderId) ? hierarchy.map(h => h.slug).join('/') + `/${fileMeta.originalname}` : fileMeta.originalname

@ -40,11 +40,11 @@ module.exports = {
}
},
async unload () {
if (this.fdCache) {
const fds = Object.values(this.fdCache)
if (fds.length > 0) {
WIKI.logger.info('Closing ASAR file descriptors...')
for (const fdItem in this.fdCache) {
fs.closeSync(this.fdCache[fdItem].fd)
}
const closeAsync = require('util').promisify(fs.close)
await Promise.all(fds.map(x => closeAsync(x.fd)))
this.fdCache = {}
}
},

@ -138,6 +138,10 @@ module.exports = {
switch (WIKI.config.db.type) {
case 'postgres':
await conn.query(`set application_name = 'Wiki.js'`)
// -> Set schema if it's not public
if (WIKI.config.db.schema && WIKI.config.db.schema !== 'public') {
await conn.query(`set search_path TO ${WIKI.config.db.schema}, public;`)
}
done()
break
case 'mysql':

@ -107,19 +107,21 @@ module.exports = {
* Graceful shutdown
*/
async shutdown () {
if (WIKI.models) {
await WIKI.models.unsubscribeToNotifications()
await WIKI.models.knex.client.pool.destroy()
await WIKI.models.knex.destroy()
if (WIKI.servers) {
await WIKI.servers.stopServers()
}
if (WIKI.scheduler) {
WIKI.scheduler.stop()
await WIKI.scheduler.stop()
}
if (WIKI.models) {
await WIKI.models.unsubscribeToNotifications()
if (WIKI.models.knex) {
await WIKI.models.knex.destroy()
}
}
if (WIKI.asar) {
await WIKI.asar.unload()
}
if (WIKI.servers) {
await WIKI.servers.stopServers()
}
process.exit(0)
}
}

@ -12,7 +12,8 @@ class Job {
schedule = 'P1D',
repeat = false,
worker = false
}) {
}, queue) {
this.queue = queue
this.finished = Promise.resolve()
this.name = name
this.immediate = immediate
@ -27,10 +28,11 @@ class Job {
* @param {Object} data Job Data
*/
start(data) {
this.queue.jobs.push(this)
if (this.immediate) {
this.invoke(data)
} else {
this.queue(data)
this.enqueue(data)
}
}
@ -39,7 +41,7 @@ class Job {
*
* @param {Object} data Job Data
*/
queue(data) {
enqueue(data) {
this.timeout = setTimeout(this.invoke.bind(this), this.schedule.asMilliseconds(), data)
}
@ -55,14 +57,22 @@ class Job {
`--job=${this.name}`,
`--data=${data}`
], {
cwd: WIKI.ROOTPATH
cwd: WIKI.ROOTPATH,
stdio: ['inherit', 'inherit', 'pipe', 'ipc']
})
const stderr = [];
proc.stderr.on('data', chunk => stderr.push(chunk))
this.finished = new Promise((resolve, reject) => {
proc.on('exit', (code, signal) => {
const data = Buffer.concat(stderr).toString()
if (code === 0) {
resolve()
resolve(data)
} else {
reject(signal)
const err = new Error(`Error when running job ${this.name}: ${data}`)
err.exitSignal = signal
err.exitCode = code
err.stderr = data
reject(err)
}
proc.kill()
})
@ -74,16 +84,20 @@ class Job {
} catch (err) {
WIKI.logger.warn(err)
}
if (this.repeat) {
this.queue(data)
if (this.repeat && this.queue.jobs.includes(this)) {
this.enqueue(data)
} else {
this.stop().catch(() => {})
}
}
/**
* Stop any future job invocation from occuring
*/
stop() {
async stop() {
clearTimeout(this.timeout)
this.queue.jobs = this.queue.jobs.filter(x => x !== this)
return this.finished
}
}
@ -110,16 +124,11 @@ module.exports = {
})
},
registerJob(opts, data) {
const job = new Job(opts)
const job = new Job(opts, this)
job.start(data)
if (job.repeat) {
this.jobs.push(job)
}
return job
},
stop() {
this.jobs.forEach(job => {
job.stop()
})
async stop() {
return Promise.all(this.jobs.map(job => job.stop()))
}
}

@ -14,6 +14,11 @@ WIKI.logger = require('./logger').init('JOB')
const args = require('yargs').argv
;(async () => {
await require(`../jobs/${args.job}`)(args.data)
process.exit(0)
try {
await require(`../jobs/${args.job}`)(args.data)
process.exit(0)
} catch (e) {
await new Promise(resolve => process.stderr.write(e.message, resolve))
process.exit(1)
}
})()

@ -33,3 +33,16 @@ WIKI.logger = require('./core/logger').init('MASTER')
// ----------------------------------------
WIKI.kernel.init()
// ----------------------------------------
// Register exit handler
// ----------------------------------------
process.on('SIGINT', () => {
WIKI.kernel.shutdown()
})
process.on('message', (msg) => {
if (msg === 'shutdown') {
WIKI.kernel.shutdown()
}
})

@ -74,5 +74,7 @@ module.exports = async (pageId) => {
} catch (err) {
WIKI.logger.error(`Rebuilding page tree: [ FAILED ]`)
WIKI.logger.error(err.message)
// exit process with error code
throw err
}
}

@ -90,5 +90,7 @@ module.exports = async (pageId) => {
} catch (err) {
WIKI.logger.error(`Rendering page ID ${pageId}: [ FAILED ]`)
WIKI.logger.error(err.message)
// exit process with error code
throw err
}
}

@ -1,6 +0,0 @@
const { graphqlUploadExpress } = require('graphql-upload')
/**
* GraphQL File Upload Middleware
*/
module.exports = graphqlUploadExpress({ maxFileSize: 5000000, maxFiles: 20 })

@ -650,7 +650,15 @@ module.exports = class Page extends Model {
* @returns {Promise} Promise with no value
*/
static async movePage(opts) {
const page = await WIKI.models.pages.query().findById(opts.id)
let page
if (_.has(opts, 'id')) {
page = await WIKI.models.pages.query().findById(opts.id)
} else {
page = await WIKI.models.pages.query().findOne({
path: opts.path,
localeCode: opts.locale
})
}
if (!page) {
throw new WIKI.Error.PageNotFound()
}
@ -704,9 +712,11 @@ module.exports = class Page extends Model {
const destinationHash = pageHelper.generateHash({ path: opts.destinationPath, locale: opts.destinationLocale, privateNS: opts.isPrivate ? 'TODO' : '' })
// -> Move page
const destinationTitle = (page.title === page.path ? opts.destinationPath : page.title)
await WIKI.models.pages.query().patch({
path: opts.destinationPath,
localeCode: opts.destinationLocale,
title: destinationTitle,
hash: destinationHash
}).findById(page.id)
await WIKI.models.pages.deletePageFromCache(page.hash)
@ -775,7 +785,7 @@ module.exports = class Page extends Model {
})
}
if (!page) {
throw new Error('Invalid Page Id')
throw new WIKI.Error.PageNotFound()
}
// -> Check for page access

File diff suppressed because one or more lines are too long

@ -16,3 +16,15 @@ props:
title: Application ID
hint: Found at the very end of the code snippet provided by New Relic Browser
order: 2
beacon:
type: String
title: Beacon
default: bam.nr-data.net
hint: Found at the very end of the code snippet provided by New Relic Browser. Differs for US and EU servers.
order: 3
errorBeacon:
type: String
title: Error Beacon
default: bam.nr-data.net
hint: Found at the very end of the code snippet provided by New Relic Browser. Differs for US and EU servers.
order: 4

@ -9,27 +9,38 @@ const _ = require('lodash')
module.exports = {
init (passport, conf) {
passport.use('google',
new GoogleStrategy({
clientID: conf.clientId,
clientSecret: conf.clientSecret,
callbackURL: conf.callbackURL,
passReqToCallback: true
}, async (req, accessToken, refreshToken, profile, cb) => {
try {
const user = await WIKI.models.users.processProfile({
providerKey: req.params.strategy,
profile: {
...profile,
picture: _.get(profile, 'photos[0].value', '')
}
})
cb(null, user)
} catch (err) {
cb(err, null)
const strategy = new GoogleStrategy({
clientID: conf.clientId,
clientSecret: conf.clientSecret,
callbackURL: conf.callbackURL,
passReqToCallback: true
}, async (req, accessToken, refreshToken, profile, cb) => {
try {
if (conf.hostedDomain && conf.hostedDomain != profile._json.hd) {
throw new Error('Google authentication should have been performed with domain ' + conf.hostedDomain)
}
})
)
const user = await WIKI.models.users.processProfile({
providerKey: req.params.strategy,
profile: {
...profile,
picture: _.get(profile, 'photos[0].value', '')
}
})
cb(null, user)
} catch (err) {
cb(err, null)
}
})
if (conf.hostedDomain) {
strategy.authorizationParams = function(options) {
return {
hd: conf.hostedDomain
}
}
}
passport.use('google', strategy)
},
logout (conf) {
return '/'

@ -22,3 +22,8 @@ props:
title: Client Secret
hint: Application Client Secret
order: 2
hostedDomain:
type: String
title: Hosted Domain
hint: (optional) Only for G Suite hosted domain. Leave empty otherwise.
order: 3

@ -4,7 +4,7 @@
// Slack Account
// ------------------------------------
const SlackStrategy = require('@aoberoi/passport-slack').default.Strategy
const SlackStrategy = require('passport-slack-oauth2').Strategy
const _ = require('lodash')
module.exports = {
@ -15,8 +15,9 @@ module.exports = {
clientSecret: conf.clientSecret,
callbackURL: conf.callbackURL,
team: conf.team,
scope: ['identity.basic', 'identity.email', 'identity.avatar'],
passReqToCallback: true
}, async (req, accessToken, scopes, team, extra, { user: userProfile }, cb) => {
}, async (req, accessToken, refreshToken, { user: userProfile }, cb) => {
try {
const user = await WIKI.models.users.processProfile({
providerKey: req.params.strategy,

@ -237,7 +237,7 @@ module.exports = {
// --------------------------------
$('body').contents().toArray().forEach(item => {
if (item.type === 'text' && item.parent.name === 'body') {
if (item && item.type === 'text' && item.parent.name === 'body') {
$(item).wrap('<div></div>')
}
})
@ -249,7 +249,7 @@ module.exports = {
function iterateMustacheNode (node) {
const list = $(node).contents().toArray()
list.forEach(item => {
if (item.type === 'text') {
if (item && item.type === 'text') {
const rawText = $(item).text().replace(/\r?\n|\r/g, '')
if (mustacheRegExp.test(rawText)) {
$(item).parent().attr('v-pre', true)

@ -142,7 +142,9 @@ module.exports = {
if (_.get(diff, 'files', []).length > 0) {
let filesToProcess = []
for (const f of diff.files) {
const fPath = path.join(this.repoPath, f.file)
const fMoved = f.file.split(' => ')
const fName = fMoved.length === 2 ? fMoved[1] : fMoved[0]
const fPath = path.join(this.repoPath, fName)
let fStats = { size: 0 }
try {
fStats = await fs.stat(fPath)
@ -159,7 +161,8 @@ module.exports = {
path: fPath,
stats: fStats
},
relPath: f.file
oldPath: fMoved[0],
relPath: fName
})
}
await this.processFiles(filesToProcess, rootUser)
@ -174,11 +177,25 @@ module.exports = {
async processFiles(files, user) {
for (const item of files) {
const contentType = pageHelper.getContentType(item.relPath)
const fileExists = await fs.pathExists(item.file)
const fileExists = await fs.pathExists(item.file.path)
if (!item.binary && contentType) {
// -> Page
if (!fileExists && item.deletions > 0 && item.insertions === 0) {
if (fileExists && item.relPath !== item.oldPath) {
// Page was renamed by git, so rename in DB
WIKI.logger.info(`(STORAGE/GIT) Page marked as renamed: from ${item.oldPath} to ${item.relPath}`)
const contentPath = pageHelper.getPagePath(item.oldPath)
const contentDestinationPath = pageHelper.getPagePath(item.relPath)
await WIKI.models.pages.movePage({
user: user,
path: contentPath.path,
destinationPath: contentDestinationPath.path,
locale: contentPath.locale,
destinationLocale: contentPath.locale,
skipStorage: true
})
} else if (!fileExists && item.deletions > 0 && item.insertions === 0) {
// Page was deleted by git, can safely mark as deleted in DB
WIKI.logger.info(`(STORAGE/GIT) Page marked as deleted: ${item.relPath}`)
@ -207,7 +224,23 @@ module.exports = {
} else {
// -> Asset
if (!fileExists && ((item.before > 0 && item.after === 0) || (item.deletions > 0 && item.insertions === 0))) {
if (fileExists && ((item.before === item.after) || (item.deletions === 0 && item.insertions === 0))) {
// Asset was renamed by git, so rename in DB
WIKI.logger.info(`(STORAGE/GIT) Asset marked as renamed: from ${item.oldPath} to ${item.relPath}`)
const fileHash = assetHelper.generateHash(item.relPath)
const assetToRename = await WIKI.models.assets.query().findOne({ hash: fileHash })
if (assetToRename) {
await WIKI.models.assets.query().patch({
filename: item.relPath,
hash: fileHash
}).findById(assetToRename.id)
await assetToRename.deleteAssetCache()
} else {
WIKI.logger.info(`(STORAGE/GIT) Asset was not found in the DB, nothing to rename: ${item.relPath}`)
}
continue
} else if (!fileExists && ((item.before > 0 && item.after === 0) || (item.deletions > 0 && item.insertions === 0))) {
// Asset was deleted by git, can safely mark as deleted in DB
WIKI.logger.info(`(STORAGE/GIT) Asset marked as deleted: ${item.relPath}`)

@ -155,7 +155,12 @@ module.exports = {
const folderPaths = _.dropRight(filePath.split('/'))
for (let i = 1; i <= folderPaths.length; i++) {
const folderSection = _.take(folderPaths, i).join('/')
await this.sftp.mkdir(path.posix.join(this.config.basePath, folderSection))
const folderDir = path.posix.join(this.config.basePath, folderSection)
try {
await this.sftp.readdir(folderDir)
} catch (err) {
await this.sftp.mkdir(folderDir)
}
}
} catch (err) {}
}

@ -106,18 +106,6 @@
"@algolia/logger-common" "4.5.1"
"@algolia/requester-common" "4.5.1"
"@aoberoi/passport-slack@1.0.5":
version "1.0.5"
resolved "https://registry.yarnpkg.com/@aoberoi/passport-slack/-/passport-slack-1.0.5.tgz#08dcd2d951e94d8e2934bd567c01410a0cc42bec"
integrity sha1-CNzS2VHpTY4pNL1WfAFBCgzEK+w=
dependencies:
babel-polyfill "^6.16.0"
lodash.defaults "^4.2.0"
lodash.isfunction "^3.0.8"
lodash.pickby "^4.6.0"
needle "^1.4.2"
passport-oauth2 "^1.3.0"
"@apollo/client@^3.1.5":
version "3.2.2"
resolved "https://registry.yarnpkg.com/@apollo/client/-/client-3.2.2.tgz#fe5cad4d53373979f13a925e9da02d8743e798a5"
@ -5415,15 +5403,6 @@ babel-plugin-transform-imports@2.0.0:
"@babel/types" "^7.4"
is-valid-path "^0.1.1"
babel-polyfill@^6.16.0:
version "6.26.0"
resolved "https://registry.yarnpkg.com/babel-polyfill/-/babel-polyfill-6.26.0.tgz#379937abc67d7895970adc621f284cd966cf2153"
integrity sha1-N5k3q8Z9eJWXCtxiHyhM2WbPIVM=
dependencies:
babel-runtime "^6.26.0"
core-js "^2.5.0"
regenerator-runtime "^0.10.5"
babel-preset-current-node-syntax@^0.1.3:
version "0.1.3"
resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-0.1.3.tgz#b4b547acddbf963cba555ba9f9cbbb70bfd044da"
@ -6989,7 +6968,7 @@ core-js@3.6.5, core-js@^3.6.5:
resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.6.5.tgz#7395dc273af37fb2e50e9bd3d9fe841285231d1a"
integrity sha512-vZVEEwZoIsI+vPEuoF9Iqf5H7/M3eeQqWlQnYa8FSKKePuYTf5MWnxb5SDAzCa60b3JBRS5g9b+Dq7b1y/RCrA==
core-js@^2.4.0, core-js@^2.5.0, core-js@^2.6.5:
core-js@^2.4.0, core-js@^2.6.5:
version "2.6.9"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.9.tgz#6b4b214620c834152e179323727fc19741b084f2"
integrity sha512-HOpZf6eXmnl7la+cUdMnLvUxKNqLUzJvgIziQ0DiF3JwSImNphIqdGqzj6hIKyX04MmV0poclQ7+wjWvxQyR2A==
@ -8012,7 +7991,7 @@ de-indent@^1.0.2:
resolved "https://registry.yarnpkg.com/de-indent/-/de-indent-1.0.2.tgz#b2038e846dc33baa5796128d0804b455b8c1e21d"
integrity sha1-sgOOhG3DO6pXlhKNCAS0VbjB4h0=
debug@2.6.9, debug@^2.1.2, debug@^2.2.0, debug@^2.3.3, debug@^2.6.9:
debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.9:
version "2.6.9"
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
@ -12364,11 +12343,6 @@ lodash.clonedeep@4.5.0:
resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef"
integrity sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=
lodash.defaults@^4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c"
integrity sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw=
lodash.includes@^4.3.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/lodash.includes/-/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f"
@ -12379,11 +12353,6 @@ lodash.isboolean@^3.0.3:
resolved "https://registry.yarnpkg.com/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz#6c2e171db2a257cd96802fd43b01b20d5f5870f6"
integrity sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY=
lodash.isfunction@^3.0.8:
version "3.0.9"
resolved "https://registry.yarnpkg.com/lodash.isfunction/-/lodash.isfunction-3.0.9.tgz#06de25df4db327ac931981d1bdb067e5af68d051"
integrity sha512-AirXNj15uRIMMPihnkInB4i3NHeb4iBtNg9WRWuK2o31S+ePwwNmDPaTL3o7dTJ+VXNZim7rFs4rxN4YU1oUJw==
lodash.isinteger@^4.0.4:
version "4.0.4"
resolved "https://registry.yarnpkg.com/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz#619c0af3d03f8b04c31f5882840b77b11cd68343"
@ -12419,11 +12388,6 @@ lodash.once@^4.0.0, lodash.once@^4.1.1:
resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac"
integrity sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=
lodash.pickby@^4.6.0:
version "4.6.0"
resolved "https://registry.yarnpkg.com/lodash.pickby/-/lodash.pickby-4.6.0.tgz#7dea21d8c18d7703a27c704c15d3b84a67e33aff"
integrity sha1-feoh2MGNdwOifHBMFdO4SmfjOv8=
lodash.repeat@^4.0.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/lodash.repeat/-/lodash.repeat-4.1.0.tgz#fc7de8131d8c8ac07e4b49f74ffe829d1f2bec44"
@ -13299,14 +13263,6 @@ ncp@~2.0.0:
resolved "https://registry.yarnpkg.com/ncp/-/ncp-2.0.0.tgz#195a21d6c46e361d2fb1281ba38b91e9df7bdbb3"
integrity sha1-GVoh1sRuNh0vsSgbo4uR6d9727M=
needle@^1.4.2:
version "1.6.0"
resolved "https://registry.yarnpkg.com/needle/-/needle-1.6.0.tgz#f52a5858972121618e002f8e6384cadac22d624f"
integrity sha1-9SpYWJchIWGOAC+OY4TK2sItYk8=
dependencies:
debug "^2.1.2"
iconv-lite "^0.4.4"
needle@^2.2.1:
version "2.4.0"
resolved "https://registry.yarnpkg.com/needle/-/needle-2.4.0.tgz#6833e74975c444642590e15a750288c5f939b57c"
@ -14298,7 +14254,7 @@ passport-oauth2@1.2.0:
passport-strategy "1.x.x"
uid2 "0.0.x"
passport-oauth2@1.5.0, passport-oauth2@1.x.x, passport-oauth2@^1.2.0, passport-oauth2@^1.3.0, passport-oauth2@^1.4.0, passport-oauth2@^1.5.0:
passport-oauth2@1.5.0, passport-oauth2@1.x.x, passport-oauth2@^1.2.0, passport-oauth2@^1.4.0, passport-oauth2@^1.5.0:
version "1.5.0"
resolved "https://registry.yarnpkg.com/passport-oauth2/-/passport-oauth2-1.5.0.tgz#64babbb54ac46a4dcab35e7f266ed5294e3c4108"
integrity sha512-kqBt6vR/5VlCK8iCx1/KpY42kQ+NEHZwsSyt4Y6STiNjU+wWICG1i8ucc1FapXDGO15C5O5VZz7+7vRzrDPXXQ==
@ -14350,6 +14306,14 @@ passport-saml@1.3.5:
xmlbuilder "^11.0.0"
xmldom "0.1.x"
passport-slack-oauth2@1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/passport-slack-oauth2/-/passport-slack-oauth2-1.1.1.tgz#d831ffc3f1e968fcc3622e6ecf41643c8d8f9cbc"
integrity sha512-xC+yMKFXximP5TzSNt4lr9TP78MMos5B+acC7bJNCxBAVNyL9e02AEpVpVtyMIqHv4nNZnv1vyoOb50J8VCcZQ==
dependencies:
passport-oauth2 "^1.5.0"
pkginfo "^0.4.1"
passport-strategy@*, passport-strategy@1.x.x, passport-strategy@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/passport-strategy/-/passport-strategy-1.0.0.tgz#b5539aa8fc225a3d1ad179476ddf236b440f52e4"
@ -14732,6 +14696,11 @@ pkginfo@0.2.x, pkginfo@^0.2.3:
resolved "https://registry.yarnpkg.com/pkginfo/-/pkginfo-0.2.3.tgz#7239c42a5ef6c30b8f328439d9b9ff71042490f8"
integrity sha1-cjnEKl72wwuPMoQ52bn/cQQkkPg=
pkginfo@^0.4.1:
version "0.4.1"
resolved "https://registry.yarnpkg.com/pkginfo/-/pkginfo-0.4.1.tgz#b5418ef0439de5425fc4995042dced14fb2a84ff"
integrity sha1-tUGO8EOd5UJfxJlQQtztFPsqhP8=
pleeease-filters@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/pleeease-filters/-/pleeease-filters-4.0.0.tgz#6632b2fb05648d2758d865384fbced79e1ccaec7"
@ -16479,11 +16448,6 @@ regenerate@^1.4.0:
resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.0.tgz#4a856ec4b56e4077c557589cae85e7a4c8869a11"
integrity sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==
regenerator-runtime@^0.10.5:
version "0.10.5"
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz#336c3efc1220adcedda2c9fab67b5a7955a33658"
integrity sha1-M2w+/BIgrc7dosn6tntaeVWjNlg=
regenerator-runtime@^0.11.0:
version "0.11.1"
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9"

Loading…
Cancel
Save