diff --git a/client/components/editor.vue b/client/components/editor.vue index 943bc6f3..a50d7251 100644 --- a/client/components/editor.vue +++ b/client/components/editor.vue @@ -267,7 +267,7 @@ export default { if (this.$store.get('editor/mode') === 'create') { window.location.assign(`/`) } else { - window.location.assign(`/${this.$store.get('page/path')}`) + window.location.assign(`/${this.$store.get('page/locale')}/${this.$store.get('page/path')}`) } }, 500) } diff --git a/client/static/svg/auth-icon-gitlab.svg b/client/static/svg/auth-icon-gitlab.svg new file mode 100644 index 00000000..3bf32d6e --- /dev/null +++ b/client/static/svg/auth-icon-gitlab.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/package.json b/package.json index 55620e59..699fa2c1 100644 --- a/package.json +++ b/package.json @@ -123,6 +123,7 @@ "passport-dropbox-oauth2": "1.1.0", "passport-facebook": "3.0.0", "passport-github2": "0.1.11", + "passport-gitlab2": "5.0.0", "passport-google-oauth20": "2.0.0", "passport-jwt": "4.0.0", "passport-ldapauth": "2.1.3", diff --git a/server/graph/resolvers/authentication.js b/server/graph/resolvers/authentication.js index cb1a38bb..e7ce61ec 100644 --- a/server/graph/resolvers/authentication.js +++ b/server/graph/resolvers/authentication.js @@ -21,14 +21,16 @@ module.exports = { ...strategyInfo, ...stg, config: _.sortBy(_.transform(stg.config, (res, value, key) => { - const configData = _.get(strategyInfo.props, key, {}) - res.push({ - key, - value: JSON.stringify({ - ...configData, - value + const configData = _.get(strategyInfo.props, key, false) + if (configData) { + res.push({ + key, + value: JSON.stringify({ + ...configData, + value + }) }) - }) + } }, []), 'key') } }) diff --git a/server/graph/resolvers/storage.js b/server/graph/resolvers/storage.js index 295fba1c..6fdab763 100644 --- a/server/graph/resolvers/storage.js +++ b/server/graph/resolvers/storage.js @@ -22,14 +22,16 @@ module.exports = { syncInterval: targetInfo.syncInterval || targetInfo.schedule || 'P0D', syncIntervalDefault: targetInfo.schedule, config: _.sortBy(_.transform(tgt.config, (res, value, key) => { - const configData = _.get(targetInfo.props, key, {}) - res.push({ - key, - value: JSON.stringify({ - ...configData, - value + const configData = _.get(targetInfo.props, key, false) + if (configData) { + res.push({ + key, + value: JSON.stringify({ + ...configData, + value + }) }) - }) + } }, []), 'key') } }) diff --git a/server/modules/authentication/gitlab/authentication.js b/server/modules/authentication/gitlab/authentication.js new file mode 100644 index 00000000..68c189fe --- /dev/null +++ b/server/modules/authentication/gitlab/authentication.js @@ -0,0 +1,34 @@ +/* global WIKI */ + +// ------------------------------------ +// GitLab Account +// ------------------------------------ + +const GitLabStrategy = require('passport-gitlab2').Strategy +const _ = require('lodash') + +module.exports = { + init (passport, conf) { + passport.use('gitlab', + new GitLabStrategy({ + clientID: conf.clientId, + clientSecret: conf.clientSecret, + callbackURL: conf.callbackURL, + scope: ['read_user'] + }, async (accessToken, refreshToken, profile, cb) => { + try { + const user = await WIKI.models.users.processProfile({ + profile: { + ...profile, + picture: _.get(profile, 'avatarUrl', '') + }, + providerKey: 'gitlab' + }) + cb(null, user) + } catch (err) { + cb(err, null) + } + } + )) + } +} diff --git a/server/modules/authentication/gitlab/definition.yml b/server/modules/authentication/gitlab/definition.yml new file mode 100644 index 00000000..e18dccb8 --- /dev/null +++ b/server/modules/authentication/gitlab/definition.yml @@ -0,0 +1,26 @@ +key: gitlab +title: GitLab +description: GitLab is a web-based DevOps lifecycle tool that provides a Git-repository manager providing wiki, issue-tracking and CI/CD pipeline features. +author: requarks.io +logo: https://static.requarks.io/logo/gitlab.svg +color: deep-orange +website: https://gitlab.com +isAvailable: true +useForm: false +props: + clientId: + type: String + title: Client ID + hint: Application Client ID + order: 1 + clientSecret: + type: String + title: Client Secret + hint: Application Client Secret + order: 2 + baseUrl: + type: String + title: Base URL + hint: For self-managed GitLab instances, define the base URL (e.g. https://gitlab.example.com). Leave default for GitLab.com SaaS (https://gitlab.com). + default: https://gitlab.com + order: 3 diff --git a/server/modules/storage/digitalocean/definition.yml b/server/modules/storage/digitalocean/definition.yml index 7a1a388d..7d77d5c5 100644 --- a/server/modules/storage/digitalocean/definition.yml +++ b/server/modules/storage/digitalocean/definition.yml @@ -4,10 +4,36 @@ description: DigitalOcean provides developers and businesses a reliable, easy-to author: requarks.io logo: https://static.requarks.io/logo/digitalocean.svg website: https://www.digitalocean.com/products/spaces/ +isAvailable: false +supportedModes: + - push +defaultMode: push +schedule: false props: - accessKeyId: String - accessSecret: String region: type: String + title: Region + hint: The DigitalOcean datacenter region where the Space will be created. default: nyc3 - bucket: String + enum: + - ams3 + - fra1 + - nyc3 + - sfo2 + - sgp1 + order: 1 + spaceId: + type: String + title: Space Unique Name + hint: The unique space name to create (e.g. wiki-johndoe) + order: 2 + accessKeyId: + type: String + title: Access Key ID + hint: The Access Key (Generated in API > Tokens/Keys > Spaces access keys). + order: 3 + secretAccessKey : + type: String + title: Access Key Secret + hint: The Access Key Secret for the Access Key ID you created above. + order: 4 diff --git a/server/modules/storage/disk/storage.js b/server/modules/storage/disk/storage.js index 1a2e9548..a6e6a90e 100644 --- a/server/modules/storage/disk/storage.js +++ b/server/modules/storage/disk/storage.js @@ -59,24 +59,41 @@ module.exports = { }, async created(page) { WIKI.logger.info(`(STORAGE/DISK) Creating file ${page.path}...`) - const filePath = path.join(this.config.path, `${page.path}.${getFileExtension(page.contentType)}`) + let fileName = `${page.path}.${getFileExtension(page.contentType)}` + if (WIKI.config.lang.namespacing && WIKI.config.lang.code !== page.localeCode) { + fileName = `${page.localeCode}/${fileName}` + } + const filePath = path.join(this.config.path, fileName) await fs.outputFile(filePath, page.injectMetadata(), 'utf8') }, async updated(page) { WIKI.logger.info(`(STORAGE/DISK) Updating file ${page.path}...`) - const filePath = path.join(this.config.path, `${page.path}.${getFileExtension(page.contentType)}`) + let fileName = `${page.path}.${getFileExtension(page.contentType)}` + if (WIKI.config.lang.namespacing && WIKI.config.lang.code !== page.localeCode) { + fileName = `${page.localeCode}/${fileName}` + } + const filePath = path.join(this.config.path, fileName) await fs.outputFile(filePath, page.injectMetadata(), 'utf8') }, async deleted(page) { WIKI.logger.info(`(STORAGE/DISK) Deleting file ${page.path}...`) - const filePath = path.join(this.config.path, `${page.path}.${getFileExtension(page.contentType)}`) + let fileName = `${page.path}.${getFileExtension(page.contentType)}` + if (WIKI.config.lang.namespacing && WIKI.config.lang.code !== page.localeCode) { + fileName = `${page.localeCode}/${fileName}` + } + const filePath = path.join(this.config.path, fileName) await fs.unlink(filePath) }, async renamed(page) { WIKI.logger.info(`(STORAGE/DISK) Renaming file ${page.sourcePath} to ${page.destinationPath}...`) - const sourceFilePath = path.join(this.config.path, `${page.sourcePath}.${getFileExtension(page.contentType)}`) - const destinationFilePath = path.join(this.config.path, `${page.destinationPath}.${getFileExtension(page.contentType)}`) - await fs.move(sourceFilePath, destinationFilePath, { overwrite: true }) + let sourceFilePath = `${page.sourcePath}.${getFileExtension(page.contentType)}` + let destinationFilePath = `${page.destinationPath}.${getFileExtension(page.contentType)}` + + if (WIKI.config.lang.namespacing && WIKI.config.lang.code !== page.localeCode) { + sourceFilePath = `${page.localeCode}/${sourceFilePath}` + destinationFilePath = `${page.localeCode}/${destinationFilePath}` + } + await fs.move(path.join(this.config.path, sourceFilePath), path.join(this.config.path, destinationFilePath), { overwrite: true }) }, /** @@ -91,7 +108,10 @@ module.exports = { new stream.Transform({ objectMode: true, transform: async (page, enc, cb) => { - const fileName = `${page.path}.${getFileExtension(page.contentType)}` + let fileName = `${page.path}.${getFileExtension(page.contentType)}` + if (WIKI.config.lang.namespacing && WIKI.config.lang.code !== page.localeCode) { + fileName = `${page.localeCode}/${fileName}` + } WIKI.logger.info(`(STORAGE/DISK) Dumping ${fileName}...`) const filePath = path.join(this.config.path, fileName) await fs.outputFile(filePath, pageHelper.injectPageMetadata(page), 'utf8') diff --git a/server/modules/storage/git/storage.js b/server/modules/storage/git/storage.js index e051f314..d5c9cca2 100644 --- a/server/modules/storage/git/storage.js +++ b/server/modules/storage/git/storage.js @@ -244,7 +244,10 @@ module.exports = { */ async created(page) { WIKI.logger.info(`(STORAGE/GIT) Committing new file ${page.path}...`) - const fileName = `${page.path}.${getFileExtension(page.contentType)}` + let fileName = `${page.path}.${getFileExtension(page.contentType)}` + if (WIKI.config.lang.namespacing && WIKI.config.lang.code !== page.localeCode) { + fileName = `${page.localeCode}/${fileName}` + } const filePath = path.join(this.repoPath, fileName) await fs.outputFile(filePath, page.injectMetadata(), 'utf8') @@ -260,7 +263,10 @@ module.exports = { */ async updated(page) { WIKI.logger.info(`(STORAGE/GIT) Committing updated file ${page.path}...`) - const fileName = `${page.path}.${getFileExtension(page.contentType)}` + let fileName = `${page.path}.${getFileExtension(page.contentType)}` + if (WIKI.config.lang.namespacing && WIKI.config.lang.code !== page.localeCode) { + fileName = `${page.localeCode}/${fileName}` + } const filePath = path.join(this.repoPath, fileName) await fs.outputFile(filePath, page.injectMetadata(), 'utf8') @@ -276,7 +282,10 @@ module.exports = { */ async deleted(page) { WIKI.logger.info(`(STORAGE/GIT) Committing removed file ${page.path}...`) - const fileName = `${page.path}.${getFileExtension(page.contentType)}` + let fileName = `${page.path}.${getFileExtension(page.contentType)}` + if (WIKI.config.lang.namespacing && WIKI.config.lang.code !== page.localeCode) { + fileName = `${page.localeCode}/${fileName}` + } await this.git.rm(`./${fileName}`) await this.git.commit(`docs: delete ${page.path}`, fileName, { @@ -290,8 +299,13 @@ module.exports = { */ async renamed(page) { WIKI.logger.info(`(STORAGE/GIT) Committing file move from ${page.sourcePath} to ${page.destinationPath}...`) - const sourceFilePath = `${page.sourcePath}.${getFileExtension(page.contentType)}` - const destinationFilePath = `${page.destinationPath}.${getFileExtension(page.contentType)}` + let sourceFilePath = `${page.sourcePath}.${getFileExtension(page.contentType)}` + let destinationFilePath = `${page.destinationPath}.${getFileExtension(page.contentType)}` + + if (WIKI.config.lang.namespacing && WIKI.config.lang.code !== page.localeCode) { + sourceFilePath = `${page.localeCode}/${sourceFilePath}` + destinationFilePath = `${page.localeCode}/${destinationFilePath}` + } await this.git.mv(`./${sourceFilePath}`, `./${destinationFilePath}`) await this.git.commit(`docs: rename ${page.sourcePath} to ${destinationFilePath}`, destinationFilePath, { @@ -338,6 +352,9 @@ module.exports = { objectMode: true, transform: async (page, enc, cb) => { const fileName = `${page.path}.${getFileExtension(page.contentType)}` + if (WIKI.config.lang.namespacing && WIKI.config.lang.code !== page.localeCode) { + fileName = `${page.localeCode}/${fileName}` + } WIKI.logger.info(`(STORAGE/GIT) Adding ${fileName}...`) const filePath = path.join(this.repoPath, fileName) await fs.outputFile(filePath, pageHelper.injectPageMetadata(page), 'utf8') diff --git a/yarn.lock b/yarn.lock index b3d05659..83917811 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3888,7 +3888,7 @@ consolidate@^0.15.1: dependencies: bluebird "^3.1.1" -constantinople@^3.0.1, constantinople@^3.1.2: +constantinople@^3.0.1, constantinople@^3.0.2, constantinople@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/constantinople/-/constantinople-3.1.2.tgz#d45ed724f57d3d10500017a7d3a889c1381ae647" integrity sha512-yePcBqEFhLOqSBtwYOGGS1exHo/s1xjekXiinh4itpNQGCu4KA1euPh1fg07N2wMITZXQkBz75Ntdt1ctGZouw== @@ -6690,10 +6690,15 @@ html-webpack-plugin@3.2.0: toposort "^1.0.0" util.promisify "1.0.0" -html-webpack-pug-plugin@0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/html-webpack-pug-plugin/-/html-webpack-pug-plugin-0.3.0.tgz#83e96e05c2b48b498d411a6a26f482508b52c885" - integrity sha512-84A4BCrgMdIaOwkhXbBqZOMwRnU937xI+cVE2GykQXi4CNg6AUp6AMet5ruhTfXJs7+xJ/b7jOSpc1/kF4ukMA== +html-webpack-pug-plugin@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/html-webpack-pug-plugin/-/html-webpack-pug-plugin-2.0.0.tgz#875773ded14f7857b60e81f6a393588ce3deb367" + integrity sha512-4RZIZGIuIJBb44jFpeNuXyQQ7degfyl70rIzgOyOhYAh6hWfvYHQCLXUL/u5V9HUtp8Ai4P4CGQp8VZdYQBXmg== + dependencies: + pug-lexer "^4.0.0" + pug-parser "^5.0.0" + pug-source-gen "0.0.2" + pug-walk "^1.1.7" htmlparser2@^3.9.1: version "3.10.0" @@ -9721,6 +9726,13 @@ passport-github2@0.1.11: dependencies: passport-oauth2 "1.x.x" +passport-gitlab2@5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/passport-gitlab2/-/passport-gitlab2-5.0.0.tgz#ea37e5285321c026a02671e87469cac28cce9b69" + integrity sha512-cXQMgM6JQx9wHVh7JLH30D8fplfwjsDwRz+zS0pqC8JS+4bNmc1J04NGp5g2M4yfwylH9kQRrMN98GxMw7q7cg== + dependencies: + passport-oauth2 "^1.4.0" + passport-google-oauth20@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/passport-google-oauth20/-/passport-google-oauth20-2.0.0.tgz#0d241b2d21ebd3dc7f2b60669ec4d587e3a674ef" @@ -9779,7 +9791,7 @@ passport-oauth2@1.2.0: passport-strategy "1.x.x" uid2 "0.0.x" -passport-oauth2@1.5.0, passport-oauth2@^1.3.0: +passport-oauth2@1.5.0, passport-oauth2@^1.3.0, passport-oauth2@^1.4.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== @@ -11496,7 +11508,7 @@ pug-lexer@^2.0.1: is-expression "^3.0.0" pug-error "^1.3.2" -pug-lexer@^4.1.0: +pug-lexer@^4.0.0, pug-lexer@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/pug-lexer/-/pug-lexer-4.1.0.tgz#531cde48c7c0b1fcbbc2b85485c8665e31489cfd" integrity sha512-i55yzEBtjm0mlplW4LoANq7k3S8gDdfC6+LThGEvsK4FuobcKfDAwt6V4jKPH9RtiE3a2Akfg5UpafZ1OksaPA== @@ -11549,7 +11561,7 @@ pug-loader@2.4.0: pug-walk "^1.0.0" resolve "^1.1.7" -pug-parser@^5.0.1: +pug-parser@^5.0.0, pug-parser@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/pug-parser/-/pug-parser-5.0.1.tgz#03e7ada48b6840bd3822f867d7d90f842d0ffdc9" integrity sha512-nGHqK+w07p5/PsPIyzkTQfzlYfuqoiGjaoqHv1LjOv2ZLXmGX1O+4Vcvps+P4LhxZ3drYSljjq4b+Naid126wA== @@ -11574,6 +11586,16 @@ pug-runtime@^2.0.5: resolved "https://registry.yarnpkg.com/pug-runtime/-/pug-runtime-2.0.5.tgz#6da7976c36bf22f68e733c359240d8ae7a32953a" integrity sha512-P+rXKn9un4fQY77wtpcuFyvFaBww7/91f3jHa154qU26qFAnOe6SW1CbIDcxiG5lLK9HazYrMCCuDvNgDQNptw== +pug-source-gen@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/pug-source-gen/-/pug-source-gen-0.0.2.tgz#76d7753d89693c6846578c80da1628b8c6fc6fdb" + integrity sha1-dtd1PYlpPGhGV4yA2hYouMb8b9s= + dependencies: + constantinople "^3.0.2" + object-assign "^4.0.1" + pug-walk "0.0.3" + repeat-string "^1.5.2" + pug-strip-comments@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/pug-strip-comments/-/pug-strip-comments-1.0.4.tgz#cc1b6de1f6e8f5931cf02ec66cdffd3f50eaf8a8" @@ -11581,12 +11603,17 @@ pug-strip-comments@^1.0.4: dependencies: pug-error "^1.3.3" +pug-walk@0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/pug-walk/-/pug-walk-0.0.3.tgz#c28be7bcc540f24b83d274472410827c84e31ac6" + integrity sha1-wovnvMVA8kuD0nRHJBCCfITjGsY= + pug-walk@^1.0.0: version "1.1.7" resolved "https://registry.yarnpkg.com/pug-walk/-/pug-walk-1.1.7.tgz#c00d5c5128bac5806bec15d2b7e7cdabe42531f3" integrity sha1-wA1cUSi6xYBr7BXSt+fNq+QlMfM= -pug-walk@^1.1.8: +pug-walk@^1.1.7, pug-walk@^1.1.8: version "1.1.8" resolved "https://registry.yarnpkg.com/pug-walk/-/pug-walk-1.1.8.tgz#b408f67f27912f8c21da2f45b7230c4bd2a5ea7a" integrity sha512-GMu3M5nUL3fju4/egXwZO0XLi6fW/K3T3VTgFQ14GxNi8btlxgT5qZL//JwZFm/2Fa64J/PNS8AZeys3wiMkVA==