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/) [![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) [![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) [![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) [![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 ##### A modern, lightweight and powerful wiki app built on NodeJS
</div> </div>
- **[Official Website](https://wiki.js.org/)** - **[Official Website](https://js.wiki/)**
- **[Documentation](https://docs.requarks.io/)** - **[Documentation](https://docs.requarks.io/)**
- [Requirements](https://docs.requarks.io/install/requirements) - [Requirements](https://docs.requarks.io/install/requirements)
- [Installation](https://docs.requarks.io/install) - [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"> <img src="https://static.requarks.io/sponsors/gigabitelabs-148x129.png">
</a> </a>
</td> </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"> <td align="center" valign="middle" width="148">
<a href="https://github.com/idokka" target="_blank"> <a href="https://github.com/idokka" target="_blank">
Oleksii<br />(@idokka) 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) Theodore Chu<br />(@TheodoreChu)
</a> </a>
</td> </td>
<td align="center" valign="middle" width="148"> <!--<td align="center" valign="middle" width="148">
<a href="https://github.com/sponsors/NGPixel" target="_blank"> <a href="https://github.com/sponsors/NGPixel" target="_blank">
<img src="https://static.requarks.io/sponsors/become-148x72.png"> <img src="https://static.requarks.io/sponsors/become-148x72.png">
</a> </a>
</td> </td>-->
</tr> </tr>
</tbody> </tbody>
</table> </table>
</div> </div>
- Akira Suenami ([@a-suenami](https://github.com/a-suenami)) - Akira Suenami ([@a-suenami](https://github.com/a-suenami))
- Arnaud Marchand ([@snuids](https://github.com/snuids))
- Bryon Vandiver ([@asterick](https://github.com/asterick)) - Bryon Vandiver ([@asterick](https://github.com/asterick))
- Cameron Steele ([@ATechAdventurer](https://github.com/ATechAdventurer))
- Cloud Data Hosting LLC ([@CloudDataHostingLLC](https://github.com/CloudDataHostingLLC)) - Cloud Data Hosting LLC ([@CloudDataHostingLLC](https://github.com/CloudDataHostingLLC))
- CrazyMarvin ([@CrazyMarvin](https://github.com/CrazyMarvin)) - CrazyMarvin ([@CrazyMarvin](https://github.com/CrazyMarvin))
- David Christian Holin ([@SirGibihm](https://github.com/SirGibihm)) - 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)) - Ernie ([@iamernie](https://github.com/iamernie))
- Florian Moss ([@florianmoss](https://github.com/florianmoss)) - Florian Moss ([@florianmoss](https://github.com/florianmoss))
- HeavenBay ([@HeavenBay](https://github.com/heavenbay)) - HeavenBay ([@HeavenBay](https://github.com/heavenbay))
- Jaimyn Mayer ([@jabelone](https://github.com/jabelone))
- Jay Lee ([@polyglotm](https://github.com/polyglotm)) - Jay Lee ([@polyglotm](https://github.com/polyglotm))
- Kelly Wardrop ([@dropcoded](https://github.com/dropcoded)) - Kelly Wardrop ([@dropcoded](https://github.com/dropcoded))
- Loki ([@binaryloki](https://github.com/binaryloki)) - Loki ([@binaryloki](https://github.com/binaryloki))
- Marcilio Leite Neto ([@marclneto](https://github.com/marclneto))
- Mattias Johnson ([@mattiasJohnson](https://github.com/mattiasJohnson)) - Mattias Johnson ([@mattiasJohnson](https://github.com/mattiasJohnson))
- Mitchell Rowton ([@mrowton](https://github.com/mrowton)) - Mitchell Rowton ([@mrowton](https://github.com/mrowton))
- M. Scott Ford ([@mscottford](https://github.com/mscottford)) - 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)) - aniketpanjwani ([@aniketpanjwani](https://github.com/aniketpanjwani))
- aytaa ([@aytaa](https://github.com/aytaa)) - aytaa ([@aytaa](https://github.com/aytaa))
- magicpotato ([@fortheday](https://github.com/fortheday)) - magicpotato ([@fortheday](https://github.com/fortheday))
- motoacs ([@motoacs](https://github.com/motoacs))
- scorpion ([@scorpion](https://github.com/scorpion)) - scorpion ([@scorpion](https://github.com/scorpion))
- valantien ([@valantien](https://github.com/valantien)) - 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 - Alex Zen
- Arti Zirk - Arti Zirk
- Brandon Curtis - Brandon Curtis
- Dave 'Sri' Seah
- djagoo - djagoo
- Douglas Lassance - Douglas Lassance
- Ernie Reid - Ernie Reid
@ -238,6 +250,7 @@ Thank you to all our patrons! 🙏 [[Become a patron](https://www.patreon.com/re
- Florent - Florent
- Günter Pavlas - Günter Pavlas
- hong - hong
- Hope
- Ian - Ian
- Iskander Callos - Iskander Callos
- Josh Stewart - Josh Stewart
@ -245,9 +258,11 @@ Thank you to all our patrons! 🙏 [[Become a patron](https://www.patreon.com/re
- Keir - Keir
- Loïc CRAMPON - Loïc CRAMPON
- Ludgeir Ibanez - Ludgeir Ibanez
- Mark Mansur
- Matt Gedigian - Matt Gedigian
- Patryk - Patryk
- Philipp Schürch - Philipp Schürch
- Tracey Duffy
- Richeir - Richeir
- SmartNET.works - SmartNET.works
- Stepan Sokolovskyi - Stepan Sokolovskyi

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

@ -564,11 +564,11 @@ export default {
if (window.location.hash && window.location.hash.length > 1) { if (window.location.hash && window.location.hash.length > 1) {
if (document.readyState === 'complete') { if (document.readyState === 'complete') {
this.$nextTick(() => { this.$nextTick(() => {
this.$vuetify.goTo(window.location.hash, this.scrollOpts) this.$vuetify.goTo(decodeURIComponent(window.location.hash), this.scrollOpts)
}) })
} else { } else {
window.addEventListener('load', () => { 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 => { el.onclick = ev => {
ev.preventDefault() ev.preventDefault()
ev.stopPropagation() 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 # pfx: path/to/cert.pfx
# passphrase: xyz123 # passphrase: xyz123
# Optional - PostgreSQL only:
schema: public
# SQLite only: # SQLite only:
storage: path/to/database.sqlite storage: path/to/database.sqlite

@ -2,7 +2,7 @@ apiVersion: v2
name: wiki name: wiki
# This is the chart version. This version number should be incremented each time you make changes # 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. # 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 # This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application. # incremented each time you make changes to the application.
AppVersion: latest 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.postgresqlUser` | Postgres username | `postgres` |
| `postgresql.postgresqlHost` | External postgres host | `nil` | | `postgresql.postgresqlHost` | External postgres host | `nil` |
| `postgresql.postgresqlPassword` | External postgres password | `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.postgresqlPort` | External postgres port | `5432` |
| `postgresql.ssl` | Enable external postgres SSL connection | `false` | | `postgresql.ssl` | Enable external postgres SSL connection | `false` |
| `postgresql.ca` | Certificate of Authority path for postgres | `nil` | | `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 ### 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`. 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 ```yaml
kind: Secret kind: Secret
@ -159,4 +161,4 @@ See the [Configuration](#configuration) section to configure the PVC or to disab
## Ingress ## 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.

@ -39,9 +39,9 @@ spec:
- name: DB_USER - name: DB_USER
value: {{ default "wiki" .Values.postgresql.postgresqlUser }} value: {{ default "wiki" .Values.postgresql.postgresqlUser }}
- name: DB_SSL - name: DB_SSL
value: "{{ default "false" .Values.postgresql.ssl }}" value: "{{ default "false" .Values.postgresql.ssl }}"
- name: DB_SSL_CA - name: DB_SSL_CA
value: "{{ default "" .Values.postgresql.ca }}" value: "{{ default "" .Values.postgresql.ca }}"
- name: DB_PASS - name: DB_PASS
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
@ -51,18 +51,16 @@ spec:
name: {{ template "wiki.postgresql.secret" . }} name: {{ template "wiki.postgresql.secret" . }}
{{- end }} {{- end }}
key: {{ template "wiki.postgresql.secretKey" . }} key: {{ template "wiki.postgresql.secretKey" . }}
- name: HA
value: {{ .Values.replicaCount | int | le 2 | quote }}
ports: ports:
- name: http - name: http
containerPort: 3000 containerPort: 3000
protocol: TCP protocol: TCP
livenessProbe: livenessProbe:
httpGet: {{- toYaml .Values.livenessProbe | nindent 12 }}
path: /healthz
port: http
readinessProbe: readinessProbe:
httpGet: {{- toYaml .Values.readinessProbe | nindent 12 }}
path: /healthz
port: http
resources: resources:
{{- toYaml .Values.resources | nindent 12 }} {{- toYaml .Values.resources | nindent 12 }}
{{- with .Values.nodeSelector }} {{- with .Values.nodeSelector }}

@ -1,11 +1,18 @@
{{- if .Values.ingress.enabled -}} {{- if .Values.ingress.enabled -}}
{{- $fullName := include "wiki.fullname" . -}} {{- $fullName := include "wiki.fullname" . -}}
{{- $svcPort := .Values.service.port -}} {{- $svcPort := .Values.service.port -}}
{{- if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}} {{- 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 apiVersion: networking.k8s.io/v1beta1
{{- else -}} {{- else -}}
apiVersion: extensions/v1beta1 apiVersion: extensions/v1beta1
{{- end }} {{- end }}
kind: Ingress kind: Ingress
metadata: metadata:
name: {{ $fullName }} name: {{ $fullName }}
@ -31,11 +38,21 @@ spec:
- host: {{ .host | quote }} - host: {{ .host | quote }}
http: http:
paths: paths:
{{- range .paths }} {{- range .paths }}
- path: {{ . }} - path: {{ .path }}
{{- if and .pathType (semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion) }}
pathType: {{ .pathType }}
{{- end }}
backend: backend:
{{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }}
service:
name: {{ $fullName }}
port:
number: {{ $svcPort }}
{{- else }}
serviceName: {{ $fullName }} serviceName: {{ $fullName }}
servicePort: {{ $svcPort }} servicePort: {{ $svcPort }}
{{- end }} {{- 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 # If not set and create is true, a name is generated using the fullname template
name: name:
livenessProbe:
httpGet:
path: /healthz
port: http
readinessProbe:
httpGet:
path: /healthz
port: http
podSecurityContext: {} podSecurityContext: {}
# fsGroup: 2000 # fsGroup: 2000
@ -42,13 +52,16 @@ service:
# annotations: {} # annotations: {}
ingress: ingress:
enabled: false enabled: true
annotations: {} annotations: {}
# kubernetes.io/ingress.class: nginx # kubernetes.io/ingress.class: nginx
# kubernetes.io/tls-acme: "true" # kubernetes.io/tls-acme: "true"
hosts: hosts:
- host: wiki.local - host: wiki.minikube.local
paths: ["/"] paths:
- path: "/"
pathType: Prefix
tls: [] tls: []
# - secretName: chart-example-tls # - secretName: chart-example-tls
# hosts: # hosts:
@ -82,7 +95,7 @@ postgresql:
enabled: true enabled: true
## ssl enforce SSL communication with PostgresSQL ## ssl enforce SSL communication with PostgresSQL
## Default to false ## Default to false
## ##
# ssl: false # ssl: false
## ca Certificate of Authority ## ca Certificate of Authority
## Default to empty, point to location of CA ## Default to empty, point to location of CA
@ -92,7 +105,7 @@ postgresql:
## Default to postgres ## Default to postgres
## ##
# postgresqlHost: postgres # postgresqlHost: postgres
## postgresqlPort port for postgres ## postgresqlPort port for postgres
## Default to 5432 ## Default to 5432
## ##
# postgresqlPort: 5432 # postgresqlPort: 5432

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

@ -76,7 +76,7 @@ router.post('/u', (req, res, next) => {
} }
// Sanitize filename // 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 // Check if user can upload at path
const assetPath = (folderId) ? hierarchy.map(h => h.slug).join('/') + `/${fileMeta.originalname}` : fileMeta.originalname const assetPath = (folderId) ? hierarchy.map(h => h.slug).join('/') + `/${fileMeta.originalname}` : fileMeta.originalname

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

@ -138,6 +138,10 @@ module.exports = {
switch (WIKI.config.db.type) { switch (WIKI.config.db.type) {
case 'postgres': case 'postgres':
await conn.query(`set application_name = 'Wiki.js'`) 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() done()
break break
case 'mysql': case 'mysql':

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

@ -12,7 +12,8 @@ class Job {
schedule = 'P1D', schedule = 'P1D',
repeat = false, repeat = false,
worker = false worker = false
}) { }, queue) {
this.queue = queue
this.finished = Promise.resolve() this.finished = Promise.resolve()
this.name = name this.name = name
this.immediate = immediate this.immediate = immediate
@ -27,10 +28,11 @@ class Job {
* @param {Object} data Job Data * @param {Object} data Job Data
*/ */
start(data) { start(data) {
this.queue.jobs.push(this)
if (this.immediate) { if (this.immediate) {
this.invoke(data) this.invoke(data)
} else { } else {
this.queue(data) this.enqueue(data)
} }
} }
@ -39,7 +41,7 @@ class Job {
* *
* @param {Object} data Job Data * @param {Object} data Job Data
*/ */
queue(data) { enqueue(data) {
this.timeout = setTimeout(this.invoke.bind(this), this.schedule.asMilliseconds(), data) this.timeout = setTimeout(this.invoke.bind(this), this.schedule.asMilliseconds(), data)
} }
@ -55,14 +57,22 @@ class Job {
`--job=${this.name}`, `--job=${this.name}`,
`--data=${data}` `--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) => { this.finished = new Promise((resolve, reject) => {
proc.on('exit', (code, signal) => { proc.on('exit', (code, signal) => {
const data = Buffer.concat(stderr).toString()
if (code === 0) { if (code === 0) {
resolve() resolve(data)
} else { } 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() proc.kill()
}) })
@ -74,16 +84,20 @@ class Job {
} catch (err) { } catch (err) {
WIKI.logger.warn(err) WIKI.logger.warn(err)
} }
if (this.repeat) { if (this.repeat && this.queue.jobs.includes(this)) {
this.queue(data) this.enqueue(data)
} else {
this.stop().catch(() => {})
} }
} }
/** /**
* Stop any future job invocation from occuring * Stop any future job invocation from occuring
*/ */
stop() { async stop() {
clearTimeout(this.timeout) 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) { registerJob(opts, data) {
const job = new Job(opts) const job = new Job(opts, this)
job.start(data) job.start(data)
if (job.repeat) {
this.jobs.push(job)
}
return job return job
}, },
stop() { async stop() {
this.jobs.forEach(job => { return Promise.all(this.jobs.map(job => job.stop()))
job.stop()
})
} }
} }

@ -14,6 +14,11 @@ WIKI.logger = require('./logger').init('JOB')
const args = require('yargs').argv const args = require('yargs').argv
;(async () => { ;(async () => {
await require(`../jobs/${args.job}`)(args.data) try {
process.exit(0) 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() 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) { } catch (err) {
WIKI.logger.error(`Rebuilding page tree: [ FAILED ]`) WIKI.logger.error(`Rebuilding page tree: [ FAILED ]`)
WIKI.logger.error(err.message) WIKI.logger.error(err.message)
// exit process with error code
throw err
} }
} }

@ -90,5 +90,7 @@ module.exports = async (pageId) => {
} catch (err) { } catch (err) {
WIKI.logger.error(`Rendering page ID ${pageId}: [ FAILED ]`) WIKI.logger.error(`Rendering page ID ${pageId}: [ FAILED ]`)
WIKI.logger.error(err.message) 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 * @returns {Promise} Promise with no value
*/ */
static async movePage(opts) { 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) { if (!page) {
throw new WIKI.Error.PageNotFound() 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' : '' }) const destinationHash = pageHelper.generateHash({ path: opts.destinationPath, locale: opts.destinationLocale, privateNS: opts.isPrivate ? 'TODO' : '' })
// -> Move page // -> Move page
const destinationTitle = (page.title === page.path ? opts.destinationPath : page.title)
await WIKI.models.pages.query().patch({ await WIKI.models.pages.query().patch({
path: opts.destinationPath, path: opts.destinationPath,
localeCode: opts.destinationLocale, localeCode: opts.destinationLocale,
title: destinationTitle,
hash: destinationHash hash: destinationHash
}).findById(page.id) }).findById(page.id)
await WIKI.models.pages.deletePageFromCache(page.hash) await WIKI.models.pages.deletePageFromCache(page.hash)
@ -775,7 +785,7 @@ module.exports = class Page extends Model {
}) })
} }
if (!page) { if (!page) {
throw new Error('Invalid Page Id') throw new WIKI.Error.PageNotFound()
} }
// -> Check for page access // -> Check for page access

File diff suppressed because one or more lines are too long

@ -16,3 +16,15 @@ props:
title: Application ID title: Application ID
hint: Found at the very end of the code snippet provided by New Relic Browser hint: Found at the very end of the code snippet provided by New Relic Browser
order: 2 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 = { module.exports = {
init (passport, conf) { init (passport, conf) {
passport.use('google', const strategy = new GoogleStrategy({
new GoogleStrategy({ clientID: conf.clientId,
clientID: conf.clientId, clientSecret: conf.clientSecret,
clientSecret: conf.clientSecret, callbackURL: conf.callbackURL,
callbackURL: conf.callbackURL, passReqToCallback: true
passReqToCallback: true }, async (req, accessToken, refreshToken, profile, cb) => {
}, async (req, accessToken, refreshToken, profile, cb) => { try {
try { if (conf.hostedDomain && conf.hostedDomain != profile._json.hd) {
const user = await WIKI.models.users.processProfile({ throw new Error('Google authentication should have been performed with domain ' + conf.hostedDomain)
providerKey: req.params.strategy,
profile: {
...profile,
picture: _.get(profile, 'photos[0].value', '')
}
})
cb(null, user)
} catch (err) {
cb(err, null)
} }
}) 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) { logout (conf) {
return '/' return '/'

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

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

@ -142,7 +142,9 @@ module.exports = {
if (_.get(diff, 'files', []).length > 0) { if (_.get(diff, 'files', []).length > 0) {
let filesToProcess = [] let filesToProcess = []
for (const f of diff.files) { 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 } let fStats = { size: 0 }
try { try {
fStats = await fs.stat(fPath) fStats = await fs.stat(fPath)
@ -159,7 +161,8 @@ module.exports = {
path: fPath, path: fPath,
stats: fStats stats: fStats
}, },
relPath: f.file oldPath: fMoved[0],
relPath: fName
}) })
} }
await this.processFiles(filesToProcess, rootUser) await this.processFiles(filesToProcess, rootUser)
@ -174,11 +177,25 @@ module.exports = {
async processFiles(files, user) { async processFiles(files, user) {
for (const item of files) { for (const item of files) {
const contentType = pageHelper.getContentType(item.relPath) 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) { if (!item.binary && contentType) {
// -> Page // -> 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 // Page was deleted by git, can safely mark as deleted in DB
WIKI.logger.info(`(STORAGE/GIT) Page marked as deleted: ${item.relPath}`) WIKI.logger.info(`(STORAGE/GIT) Page marked as deleted: ${item.relPath}`)
@ -207,7 +224,23 @@ module.exports = {
} else { } else {
// -> Asset // -> 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 // Asset was deleted by git, can safely mark as deleted in DB
WIKI.logger.info(`(STORAGE/GIT) Asset marked as deleted: ${item.relPath}`) WIKI.logger.info(`(STORAGE/GIT) Asset marked as deleted: ${item.relPath}`)
@ -419,7 +452,7 @@ module.exports = {
transform: async (page, enc, cb) => { transform: async (page, enc, cb) => {
const pageObject = await WIKI.models.pages.query().findById(page.id) const pageObject = await WIKI.models.pages.query().findById(page.id)
page.tags = await pageObject.$relatedQuery('tags') page.tags = await pageObject.$relatedQuery('tags')
let fileName = `${page.path}.${pageHelper.getFileExtension(page.contentType)}` let fileName = `${page.path}.${pageHelper.getFileExtension(page.contentType)}`
if (WIKI.config.lang.namespacing && WIKI.config.lang.code !== page.localeCode) { if (WIKI.config.lang.namespacing && WIKI.config.lang.code !== page.localeCode) {
fileName = `${page.localeCode}/${fileName}` fileName = `${page.localeCode}/${fileName}`

@ -155,7 +155,12 @@ module.exports = {
const folderPaths = _.dropRight(filePath.split('/')) const folderPaths = _.dropRight(filePath.split('/'))
for (let i = 1; i <= folderPaths.length; i++) { for (let i = 1; i <= folderPaths.length; i++) {
const folderSection = _.take(folderPaths, i).join('/') 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) {} } catch (err) {}
} }

@ -106,18 +106,6 @@
"@algolia/logger-common" "4.5.1" "@algolia/logger-common" "4.5.1"
"@algolia/requester-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": "@apollo/client@^3.1.5":
version "3.2.2" version "3.2.2"
resolved "https://registry.yarnpkg.com/@apollo/client/-/client-3.2.2.tgz#fe5cad4d53373979f13a925e9da02d8743e798a5" 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" "@babel/types" "^7.4"
is-valid-path "^0.1.1" 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: babel-preset-current-node-syntax@^0.1.3:
version "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" 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" resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.6.5.tgz#7395dc273af37fb2e50e9bd3d9fe841285231d1a"
integrity sha512-vZVEEwZoIsI+vPEuoF9Iqf5H7/M3eeQqWlQnYa8FSKKePuYTf5MWnxb5SDAzCa60b3JBRS5g9b+Dq7b1y/RCrA== 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" version "2.6.9"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.9.tgz#6b4b214620c834152e179323727fc19741b084f2" resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.9.tgz#6b4b214620c834152e179323727fc19741b084f2"
integrity sha512-HOpZf6eXmnl7la+cUdMnLvUxKNqLUzJvgIziQ0DiF3JwSImNphIqdGqzj6hIKyX04MmV0poclQ7+wjWvxQyR2A== 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" resolved "https://registry.yarnpkg.com/de-indent/-/de-indent-1.0.2.tgz#b2038e846dc33baa5796128d0804b455b8c1e21d"
integrity sha1-sgOOhG3DO6pXlhKNCAS0VbjB4h0= 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" version "2.6.9"
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== 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" resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef"
integrity sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8= 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: lodash.includes@^4.3.0:
version "4.3.0" version "4.3.0"
resolved "https://registry.yarnpkg.com/lodash.includes/-/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f" 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" resolved "https://registry.yarnpkg.com/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz#6c2e171db2a257cd96802fd43b01b20d5f5870f6"
integrity sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY= 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: lodash.isinteger@^4.0.4:
version "4.0.4" version "4.0.4"
resolved "https://registry.yarnpkg.com/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz#619c0af3d03f8b04c31f5882840b77b11cd68343" 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" resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac"
integrity sha1-DdOXEhPHxW34gJd9UEyI+0cal6w= 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: lodash.repeat@^4.0.0:
version "4.1.0" version "4.1.0"
resolved "https://registry.yarnpkg.com/lodash.repeat/-/lodash.repeat-4.1.0.tgz#fc7de8131d8c8ac07e4b49f74ffe829d1f2bec44" 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" resolved "https://registry.yarnpkg.com/ncp/-/ncp-2.0.0.tgz#195a21d6c46e361d2fb1281ba38b91e9df7bdbb3"
integrity sha1-GVoh1sRuNh0vsSgbo4uR6d9727M= 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: needle@^2.2.1:
version "2.4.0" version "2.4.0"
resolved "https://registry.yarnpkg.com/needle/-/needle-2.4.0.tgz#6833e74975c444642590e15a750288c5f939b57c" 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" passport-strategy "1.x.x"
uid2 "0.0.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" version "1.5.0"
resolved "https://registry.yarnpkg.com/passport-oauth2/-/passport-oauth2-1.5.0.tgz#64babbb54ac46a4dcab35e7f266ed5294e3c4108" resolved "https://registry.yarnpkg.com/passport-oauth2/-/passport-oauth2-1.5.0.tgz#64babbb54ac46a4dcab35e7f266ed5294e3c4108"
integrity sha512-kqBt6vR/5VlCK8iCx1/KpY42kQ+NEHZwsSyt4Y6STiNjU+wWICG1i8ucc1FapXDGO15C5O5VZz7+7vRzrDPXXQ== integrity sha512-kqBt6vR/5VlCK8iCx1/KpY42kQ+NEHZwsSyt4Y6STiNjU+wWICG1i8ucc1FapXDGO15C5O5VZz7+7vRzrDPXXQ==
@ -14350,6 +14306,14 @@ passport-saml@1.3.5:
xmlbuilder "^11.0.0" xmlbuilder "^11.0.0"
xmldom "0.1.x" 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: passport-strategy@*, passport-strategy@1.x.x, passport-strategy@^1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/passport-strategy/-/passport-strategy-1.0.0.tgz#b5539aa8fc225a3d1ad179476ddf236b440f52e4" 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" resolved "https://registry.yarnpkg.com/pkginfo/-/pkginfo-0.2.3.tgz#7239c42a5ef6c30b8f328439d9b9ff71042490f8"
integrity sha1-cjnEKl72wwuPMoQ52bn/cQQkkPg= 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: pleeease-filters@^4.0.0:
version "4.0.0" version "4.0.0"
resolved "https://registry.yarnpkg.com/pleeease-filters/-/pleeease-filters-4.0.0.tgz#6632b2fb05648d2758d865384fbced79e1ccaec7" 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" resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.0.tgz#4a856ec4b56e4077c557589cae85e7a4c8869a11"
integrity sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg== 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: regenerator-runtime@^0.11.0:
version "0.11.1" version "0.11.1"
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9"

Loading…
Cancel
Save