123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295 |
- const graphHelper = require('../../helpers/graph')
- const _ = require('lodash')
- const CleanCSS = require('clean-css')
- const path = require('path')
- /* global WIKI */
- module.exports = {
- Query: {
- async sites () {
- const sites = await WIKI.models.sites.query()
- return sites.map(s => ({
- ...s.config,
- id: s.id,
- hostname: s.hostname,
- isEnabled: s.isEnabled
- }))
- },
- async siteById (obj, args) {
- const site = await WIKI.models.sites.query().findById(args.id)
- return site ? {
- ...site.config,
- id: site.id,
- hostname: site.hostname,
- isEnabled: site.isEnabled
- } : null
- },
- async siteByHostname (obj, args) {
- let site = await WIKI.models.sites.query().where({
- hostname: args.hostname
- }).first()
- if (!site && !args.exact) {
- site = await WIKI.models.sites.query().where({
- hostname: '*'
- }).first()
- }
- return site ? {
- ...site.config,
- id: site.id,
- hostname: site.hostname,
- isEnabled: site.isEnabled
- } : null
- },
- // LEGACY
- async site() { return {} }
- },
- Mutation: {
- /**
- * CREATE SITE
- */
- async createSite (obj, args) {
- try {
- // -> Validate inputs
- if (!args.hostname || args.hostname.length < 1 || !/^(\\*)|([a-z0-9\-.:]+)$/.test(args.hostname)) {
- throw WIKI.ERROR(new Error('Invalid Site Hostname'), 'SiteCreateInvalidHostname')
- }
- if (!args.title || args.title.length < 1 || !/^[^<>"]+$/.test(args.title)) {
- throw WIKI.ERROR(new Error('Invalid Site Title'), 'SiteCreateInvalidTitle')
- }
- // -> Check for duplicate catch-all
- if (args.hostname === '*') {
- const site = await WIKI.models.sites.query().where({
- hostname: args.hostname
- }).first()
- if (site) {
- throw WIKI.ERROR(new Error('A site with a catch-all hostname already exists! Cannot have 2 catch-all hostnames.'), 'SiteCreateDuplicateCatchAll')
- }
- }
- // -> Create site
- const newSite = await WIKI.models.sites.createSite(args.hostname, {
- title: args.title
- })
- return {
- status: graphHelper.generateSuccess('Site created successfully'),
- site: newSite
- }
- } catch (err) {
- return graphHelper.generateError(err)
- }
- },
- /**
- * UPDATE SITE
- */
- async updateSite (obj, args) {
- try {
- // -> Load site
- const site = await WIKI.models.sites.query().findById(args.id)
- if (!site) {
- throw WIKI.ERROR(new Error('Invalid Site ID'), 'SiteInvalidId')
- }
- // -> Check for bad input
- if (_.has(args.patch, 'hostname') && _.trim(args.patch.hostname).length < 1) {
- throw WIKI.ERROR(new Error('Hostname is invalid.'), 'SiteInvalidHostname')
- }
- // -> Check for duplicate catch-all
- if (args.patch.hostname === '*' && site.hostname !== '*') {
- const dupSite = await WIKI.models.sites.query().where({ hostname: '*' }).first()
- if (dupSite) {
- throw WIKI.ERROR(new Error(`Site ${dupSite.config.title} with a catch-all hostname already exists! Cannot have 2 catch-all hostnames.`), 'SiteUpdateDuplicateCatchAll')
- }
- }
- // -> Format Code
- if (args.patch?.theme?.injectCSS) {
- args.patch.theme.injectCSS = new CleanCSS({ inline: false }).minify(args.patch.theme.injectCSS).styles
- }
- // -> Update site
- await WIKI.models.sites.updateSite(args.id, {
- hostname: args.patch.hostname ?? site.hostname,
- isEnabled: args.patch.isEnabled ?? site.isEnabled,
- config: _.defaultsDeep(_.omit(args.patch, ['hostname', 'isEnabled']), site.config)
- })
- return {
- status: graphHelper.generateSuccess('Site updated successfully')
- }
- } catch (err) {
- WIKI.logger.warn(err)
- return graphHelper.generateError(err)
- }
- },
- /**
- * DELETE SITE
- */
- async deleteSite (obj, args) {
- try {
- // -> Ensure site isn't last one
- const sitesCount = await WIKI.models.sites.query().count('id').first()
- if (sitesCount?.count && _.toNumber(sitesCount?.count) <= 1) {
- throw WIKI.ERROR(new Error('Cannot delete the last site. At least 1 site must exists at all times.'), 'SiteDeleteLastSite')
- }
- // -> Delete site
- await WIKI.models.sites.deleteSite(args.id)
- return {
- status: graphHelper.generateSuccess('Site deleted successfully')
- }
- } catch (err) {
- WIKI.logger.warn(err)
- return graphHelper.generateError(err)
- }
- },
- /**
- * UPLOAD LOGO
- */
- async uploadSiteLogo (obj, args) {
- try {
- const { filename, mimetype, createReadStream } = await args.image
- WIKI.logger.info(`Processing site logo ${filename} of type ${mimetype}...`)
- if (!WIKI.extensions.ext.sharp.isInstalled) {
- throw new Error('This feature requires the Sharp extension but it is not installed.')
- }
- console.info(mimetype)
- const destFormat = mimetype.startsWith('image/svg') ? 'svg' : 'png'
- const destPath = path.resolve(
- process.cwd(),
- WIKI.config.dataPath,
- `assets/logo.${destFormat}`
- )
- await WIKI.extensions.ext.sharp.resize({
- format: destFormat,
- inputStream: createReadStream(),
- outputPath: destPath,
- width: 100
- })
- WIKI.logger.info('New site logo processed successfully.')
- return {
- status: graphHelper.generateSuccess('Site logo uploaded successfully')
- }
- } catch (err) {
- return graphHelper.generateError(err)
- }
- },
- /**
- * UPLOAD FAVICON
- */
- async uploadSiteFavicon (obj, args) {
- const { filename, mimetype, createReadStream } = await args.image
- console.info(filename, mimetype)
- return {
- status: graphHelper.generateSuccess('Site favicon uploaded successfully')
- }
- },
- // LEGACY
- async site() { return {} }
- },
- SiteQuery: {
- async config(obj, args, context, info) {
- return {
- host: WIKI.config.host,
- title: WIKI.config.title,
- company: WIKI.config.company,
- contentLicense: WIKI.config.contentLicense,
- logoUrl: WIKI.config.logoUrl,
- ...WIKI.config.seo,
- ...WIKI.config.features,
- ...WIKI.config.security,
- authAutoLogin: WIKI.config.auth.autoLogin,
- authEnforce2FA: WIKI.config.auth.enforce2FA,
- authHideLocal: WIKI.config.auth.hideLocal,
- authLoginBgUrl: WIKI.config.auth.loginBgUrl,
- authJwtAudience: WIKI.config.auth.audience,
- authJwtExpiration: WIKI.config.auth.tokenExpiration,
- authJwtRenewablePeriod: WIKI.config.auth.tokenRenewal,
- uploadMaxFileSize: WIKI.config.uploads.maxFileSize,
- uploadMaxFiles: WIKI.config.uploads.maxFiles,
- uploadScanSVG: WIKI.config.uploads.scanSVG,
- uploadForceDownload: WIKI.config.uploads.forceDownload
- }
- }
- },
- SiteMutation: {
- async updateConfig(obj, args, context) {
- try {
- if (args.host) {
- let siteHost = _.trim(args.host)
- if (siteHost.endsWith('/')) {
- siteHost = siteHost.slice(0, -1)
- }
- WIKI.config.host = siteHost
- }
- if (args.title) {
- WIKI.config.title = _.trim(args.title)
- }
- if (args.company) {
- WIKI.config.company = _.trim(args.company)
- }
- if (args.contentLicense) {
- WIKI.config.contentLicense = args.contentLicense
- }
- if (args.logoUrl) {
- WIKI.config.logoUrl = _.trim(args.logoUrl)
- }
- WIKI.config.seo = {
- description: _.get(args, 'description', WIKI.config.seo.description),
- robots: _.get(args, 'robots', WIKI.config.seo.robots),
- analyticsService: _.get(args, 'analyticsService', WIKI.config.seo.analyticsService),
- analyticsId: _.get(args, 'analyticsId', WIKI.config.seo.analyticsId)
- }
- WIKI.config.auth = {
- autoLogin: _.get(args, 'authAutoLogin', WIKI.config.auth.autoLogin),
- enforce2FA: _.get(args, 'authEnforce2FA', WIKI.config.auth.enforce2FA),
- hideLocal: _.get(args, 'authHideLocal', WIKI.config.auth.hideLocal),
- loginBgUrl: _.get(args, 'authLoginBgUrl', WIKI.config.auth.loginBgUrl),
- audience: _.get(args, 'authJwtAudience', WIKI.config.auth.audience),
- tokenExpiration: _.get(args, 'authJwtExpiration', WIKI.config.auth.tokenExpiration),
- tokenRenewal: _.get(args, 'authJwtRenewablePeriod', WIKI.config.auth.tokenRenewal)
- }
- WIKI.config.features = {
- featurePageRatings: _.get(args, 'featurePageRatings', WIKI.config.features.featurePageRatings),
- featurePageComments: _.get(args, 'featurePageComments', WIKI.config.features.featurePageComments),
- featurePersonalWikis: _.get(args, 'featurePersonalWikis', WIKI.config.features.featurePersonalWikis)
- }
- WIKI.config.security = {
- securityOpenRedirect: _.get(args, 'securityOpenRedirect', WIKI.config.security.securityOpenRedirect),
- securityIframe: _.get(args, 'securityIframe', WIKI.config.security.securityIframe),
- securityReferrerPolicy: _.get(args, 'securityReferrerPolicy', WIKI.config.security.securityReferrerPolicy),
- securityTrustProxy: _.get(args, 'securityTrustProxy', WIKI.config.security.securityTrustProxy),
- securitySRI: _.get(args, 'securitySRI', WIKI.config.security.securitySRI),
- securityHSTS: _.get(args, 'securityHSTS', WIKI.config.security.securityHSTS),
- securityHSTSDuration: _.get(args, 'securityHSTSDuration', WIKI.config.security.securityHSTSDuration),
- securityCSP: _.get(args, 'securityCSP', WIKI.config.security.securityCSP),
- securityCSPDirectives: _.get(args, 'securityCSPDirectives', WIKI.config.security.securityCSPDirectives)
- }
- WIKI.config.uploads = {
- maxFileSize: _.get(args, 'uploadMaxFileSize', WIKI.config.uploads.maxFileSize),
- maxFiles: _.get(args, 'uploadMaxFiles', WIKI.config.uploads.maxFiles),
- scanSVG: _.get(args, 'uploadScanSVG', WIKI.config.uploads.scanSVG),
- forceDownload: _.get(args, 'uploadForceDownload', WIKI.config.uploads.forceDownload)
- }
- await WIKI.configSvc.saveToDb(['host', 'title', 'company', 'contentLicense', 'seo', 'logoUrl', 'auth', 'features', 'security', 'uploads'])
- if (WIKI.config.security.securityTrustProxy) {
- WIKI.app.enable('trust proxy')
- } else {
- WIKI.app.disable('trust proxy')
- }
- return {
- responseResult: graphHelper.generateSuccess('Site configuration updated successfully')
- }
- } catch (err) {
- return graphHelper.generateError(err)
- }
- }
- }
- }
|