2019-06-11 18:22:07 +02:00

354 lines
9.3 KiB
JavaScript
Executable File

'use strict';
/**
* Documentation.js controller
*
* @description: A set of functions called "actions" of the `documentation` plugin.
*/
// Core dependencies.
const path = require('path');
// Public dependencies.
const fs = require('fs-extra');
const cheerio = require('cheerio');
const _ = require('lodash');
const koaStatic = require('koa-static');
module.exports = {
getInfos: async ctx => {
try {
const prefix = _.get(
strapi.plugins,
['documentation', 'config', 'x-strapi-config', 'path'],
'/documentation'
);
const service = strapi.plugins.documentation.services.documentation;
const docVersions = service.retrieveDocumentationVersions();
const form = await service.retrieveFrontForm();
ctx.send({
docVersions,
currentVersion: service.getDocumentationVersion(),
prefix: `/${prefix}`.replace('//', '/'),
form,
});
} catch (err) {
ctx.badRequest(null, err.message);
}
},
async index(ctx, next) {
// Read layout file.
try {
const layout = fs.readFileSync(
path.resolve(__dirname, '..', 'public', 'index.html'),
'utf8'
);
const $ = cheerio.load(layout);
/**
* We don't expose the specs using koa-static or something else due to security reasons.
* That's why, we need to read the file localy and send the specs through it when we serve the Swagger UI.
*/
const { major, minor, patch } = ctx.params;
const version =
major && minor && patch
? `${major}.${minor}.${patch}`
: strapi.plugins.documentation.config.info.version;
const openAPISpecsPath = path.join(
strapi.config.appPath,
'extensions',
'documentation',
'documentation',
version,
'full_documentation.json'
);
try {
const documentation = fs.readFileSync(openAPISpecsPath, 'utf8');
// Remove previous Swagger configuration.
$('.custom-swagger-ui').remove();
// Set new Swagger configuration
$('body').append(`
<script class="custom-swagger-ui">
window.onload = function() {
// Build a system
const ui = SwaggerUIBundle({
url: "https://petstore.swagger.io/v2/swagger.json",
spec: ${JSON.stringify(JSON.parse(documentation))},
dom_id: '#swagger-ui',
docExpansion: "none",
deepLinking: true,
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIStandalonePreset
],
plugins: [
SwaggerUIBundle.plugins.DownloadUrl
],
layout: "StandaloneLayout"
})
window.ui = ui
}
</script>
`);
try {
// Write the layout with the new Swagger configuration.
// fs.writeFileSync(layoutPath, $.html());
const layoutPath = path.resolve(
strapi.config.appPath,
'extensions',
'documentation',
'public',
'index.html'
);
await fs.ensureFile(layoutPath);
await fs.writeFile(layoutPath, $.html());
// Serve the file.
ctx.url = path.basename(`${ctx.url}/index.html`);
try {
const staticFolder = path.resolve(
strapi.config.appPath,
'extensions',
'documentation',
'public'
);
return await koaStatic(staticFolder)(ctx, next);
} catch (e) {
strapi.log.error(e);
}
} catch (e) {
strapi.log.error(e);
}
} catch (e) {
strapi.log.error(e);
}
} catch (e) {
strapi.log.error(e);
}
},
async loginView(ctx, next) {
const { error } = ctx.query;
try {
const layout = fs.readFileSync(
path.join(__dirname, '..', 'public', 'login.html')
);
const $ = cheerio.load(layout);
$('form').attr(
'action',
`${strapi.plugins.documentation.config['x-strapi-config'].path}/login`
);
$('.error').text(_.isEmpty(error) ? '' : 'Wrong password...');
try {
const layoutPath = path.resolve(
strapi.config.appPath,
'extensions',
'documentation',
'public',
'login.html'
);
await fs.ensureFile(layoutPath);
await fs.writeFile(layoutPath, $.html());
ctx.url = path.basename(`${ctx.url}/login.html`);
try {
const staticFolder = path.resolve(
strapi.config.appPath,
'extensions',
'documentation',
'public'
);
return await koaStatic(staticFolder)(ctx, next);
} catch (e) {
strapi.log.error(e);
}
} catch (e) {
strapi.log.error(e);
}
} catch (e) {
strapi.log.error(e);
}
},
async login(ctx) {
const {
body: { password },
} = ctx.request;
const { password: storedPassword } = await strapi
.store({
environment: '',
type: 'plugin',
name: 'documentation',
key: 'config',
})
.get();
const isValid = strapi.plugins[
'users-permissions'
].services.user.validatePassword(password, storedPassword);
let querystring = '?error=password';
if (isValid) {
ctx.session.documentation = password;
querystring = '';
}
ctx.redirect(
`${
strapi.plugins.documentation.config['x-strapi-config'].path
}${querystring}`
);
},
regenerateDoc: async ctx => {
const service = strapi.plugins.documentation.services.documentation;
const documentationVersions = service
.retrieveDocumentationVersions()
.map(el => el.version);
const {
request: {
body: { version },
admin,
},
} = ctx;
if (_.isEmpty(version)) {
return ctx.badRequest(
null,
admin ? 'documentation.error.noVersion' : 'Please provide a version.'
);
}
if (!documentationVersions.includes(version)) {
return ctx.badRequest(
null,
admin
? 'documentation.error.regenerateDoc.versionMissing'
: 'The version you are trying to generate does not exist.'
);
}
try {
strapi.reload.isWatching = false;
const fullDoc = service.generateFullDoc(version);
const documentationPath = service.getMergedDocumentationPath(version);
// Write the file
fs.writeFileSync(
path.resolve(documentationPath, 'full_documentation.json'),
JSON.stringify(fullDoc, null, 2),
'utf8'
);
ctx.send({ ok: true });
} catch (err) {
ctx.badRequest(
null,
admin ? 'documentation.error.regenerateDoc' : 'An error occured'
);
} finally {
strapi.reload.isWatching = true;
}
},
deleteDoc: async ctx => {
strapi.reload.isWatching = false;
const service = strapi.plugins.documentation.services.documentation;
const documentationVersions = service
.retrieveDocumentationVersions()
.map(el => el.version);
const {
request: {
params: { version },
admin,
},
} = ctx;
if (_.isEmpty(version)) {
return ctx.badRequest(
null,
admin ? 'documentation.error.noVersion' : 'Please provide a version.'
);
}
if (!documentationVersions.includes(version)) {
return ctx.badRequest(
null,
admin
? 'documentation.error.deleteDoc.versionMissing'
: 'The version you are trying to delete does not exist.'
);
}
try {
await service.deleteDocumentation(version);
ctx.send({ ok: true });
} catch (err) {
ctx.badRequest(null, admin ? 'notification.error' : err.message);
} finally {
strapi.reload.isWatching = true;
}
},
updateSettings: async ctx => {
const {
admin,
body: { restrictedAccess, password },
} = ctx.request;
const usersPermService = strapi.plugins['users-permissions'].services;
const pluginStore = strapi.store({
environment: '',
type: 'plugin',
name: 'documentation',
});
const prevConfig = await pluginStore.get({ key: 'config' });
if (restrictedAccess && _.isEmpty(password)) {
return ctx.badRequest(
null,
admin
? 'users-permissions.Auth.form.error.password.provide'
: 'Please provide a password'
);
}
const isNewPassword =
!_.isEmpty(password) && password !== prevConfig.password;
if (isNewPassword && usersPermService.user.isHashed(password)) {
// Throw an error if the password selected by the user
// contains more than two times the symbol '$'.
return ctx.badRequest(
null,
admin
? 'users-permissions.Auth.form.error.password.format'
: 'our password cannot contain more than three times the symbol `$`.'
);
}
if (isNewPassword) {
prevConfig.password = await usersPermService.user.hashPassword({
password,
});
}
_.set(prevConfig, 'restrictedAccess', restrictedAccess);
await pluginStore.set({ key: 'config', value: prevConfig });
return ctx.send({ ok: true });
},
};