@strapi/plugin-documentation 0.0.0-113ff29005

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +151 -0
  3. package/__mocks__/strapi.js +41 -0
  4. package/__tests__/build-component-schema.test.js +271 -0
  5. package/admin/src/components/FieldActionWrapper/index.js +14 -0
  6. package/admin/src/components/PluginIcon/index.js +12 -0
  7. package/admin/src/index.js +80 -0
  8. package/admin/src/pages/PluginPage/index.js +199 -0
  9. package/admin/src/pages/PluginPage/tests/index.test.js +873 -0
  10. package/admin/src/pages/PluginPage/tests/server.js +23 -0
  11. package/admin/src/pages/SettingsPage/index.js +181 -0
  12. package/admin/src/pages/SettingsPage/tests/index.test.js +612 -0
  13. package/admin/src/pages/SettingsPage/tests/server.js +18 -0
  14. package/admin/src/pages/utils/api.js +31 -0
  15. package/admin/src/pages/utils/schema.js +11 -0
  16. package/admin/src/pages/utils/useReactQuery.js +46 -0
  17. package/admin/src/permissions.js +19 -0
  18. package/admin/src/pluginId.js +5 -0
  19. package/admin/src/translations/ar.json +20 -0
  20. package/admin/src/translations/cs.json +21 -0
  21. package/admin/src/translations/de.json +26 -0
  22. package/admin/src/translations/dk.json +39 -0
  23. package/admin/src/translations/en.json +39 -0
  24. package/admin/src/translations/es.json +39 -0
  25. package/admin/src/translations/fr.json +26 -0
  26. package/admin/src/translations/id.json +24 -0
  27. package/admin/src/translations/it.json +26 -0
  28. package/admin/src/translations/ko.json +39 -0
  29. package/admin/src/translations/ms.json +23 -0
  30. package/admin/src/translations/nl.json +21 -0
  31. package/admin/src/translations/pl.json +39 -0
  32. package/admin/src/translations/pt-BR.json +21 -0
  33. package/admin/src/translations/pt.json +21 -0
  34. package/admin/src/translations/ru.json +28 -0
  35. package/admin/src/translations/sk.json +24 -0
  36. package/admin/src/translations/th.json +24 -0
  37. package/admin/src/translations/tr.json +20 -0
  38. package/admin/src/translations/uk.json +23 -0
  39. package/admin/src/translations/vi.json +24 -0
  40. package/admin/src/translations/zh-Hans.json +28 -0
  41. package/admin/src/translations/zh.json +24 -0
  42. package/admin/src/utils/getTrad.js +5 -0
  43. package/admin/src/utils/index.js +2 -0
  44. package/admin/src/utils/openWithNewTab.js +20 -0
  45. package/package.json +66 -0
  46. package/server/bootstrap.js +54 -0
  47. package/server/config/default-plugin-config.js +74 -0
  48. package/server/config/index.js +7 -0
  49. package/server/controllers/documentation.js +241 -0
  50. package/server/controllers/index.js +7 -0
  51. package/server/index.js +17 -0
  52. package/server/middlewares/documentation.js +25 -0
  53. package/server/middlewares/index.js +7 -0
  54. package/server/middlewares/restrict-access.js +24 -0
  55. package/server/public/index.html +70 -0
  56. package/server/public/login.html +145 -0
  57. package/server/register.js +11 -0
  58. package/server/routes/index.js +84 -0
  59. package/server/services/documentation.js +209 -0
  60. package/server/services/helpers/build-api-endpoint-path.js +185 -0
  61. package/server/services/helpers/build-component-schema.js +159 -0
  62. package/server/services/helpers/index.js +9 -0
  63. package/server/services/helpers/utils/clean-schema-attributes.js +212 -0
  64. package/server/services/helpers/utils/get-api-responses.js +105 -0
  65. package/server/services/helpers/utils/get-schema-data.js +32 -0
  66. package/server/services/helpers/utils/loop-content-type-names.js +53 -0
  67. package/server/services/helpers/utils/pascal-case.js +9 -0
  68. package/server/services/helpers/utils/query-params.js +84 -0
  69. package/server/services/helpers/utils/routes.js +10 -0
  70. package/server/services/index.js +7 -0
  71. package/strapi-admin.js +3 -0
  72. package/strapi-server.js +3 -0
@@ -0,0 +1,23 @@
1
+ {
2
+ "components.Row.open": "Відкрити",
3
+ "components.Row.regenerate": "Згенерувати",
4
+ "containers.HomePage.Block.title": "Версії",
5
+ "containers.HomePage.Button.update": "Оновити",
6
+ "containers.HomePage.PluginHeader.title": "Документація - Налаштування",
7
+ "containers.HomePage.PopUpWarning.confirm": "Я усвідомлюю",
8
+ "containers.HomePage.PopUpWarning.message": "Ви впевнені, що хочете видалити цю версію?",
9
+ "containers.HomePage.copied": "Токен скопійовано у буфер обміну",
10
+ "containers.HomePage.form.jwtToken": "Отримайте ваш JWT токен",
11
+ "containers.HomePage.form.jwtToken.description": "Скопіюйте цей токен та застосуйте його в swagger, щоб відправляти запити",
12
+ "containers.HomePage.form.password": "Пароль",
13
+ "containers.HomePage.form.password.inputDescription": "Встановіть пароль доступу до документації",
14
+ "containers.HomePage.form.restrictedAccess": "Обмежений доступ",
15
+ "containers.HomePage.form.restrictedAccess.inputDescription": "Зробіть документацію приватною. За замовченням, документація загальнодоступна",
16
+ "containers.HomePage.form.showGeneratedFiles": "Показати згенеровані файли",
17
+ "containers.HomePage.form.showGeneratedFiles.inputDescription": "Корисно, якщо ви хочете переписати згенеровані документи \nПлаґін згенерує файли окремо для моделі та плаґіну. \nУвімкнувши цю опцію, буде легше налаштувати вашу документацію",
18
+ "error.deleteDoc.versionMissing": "Версія, яку ви намагаєтесь видалити не існує.",
19
+ "error.noVersion": "Необхідна версія",
20
+ "error.regenerateDoc": "Під час генерування документації сталася помилка",
21
+ "error.regenerateDoc.versionMissing": "Версія, яку ви намагаєтесь згенерувати не існує.",
22
+ "notification.update.success": "Налаштування оновлено"
23
+ }
@@ -0,0 +1,24 @@
1
+ {
2
+ "components.Row.open": "Mở",
3
+ "components.Row.regenerate": "Sinh lại",
4
+ "containers.HomePage.Block.title": "Các Phiên Bản",
5
+ "containers.HomePage.Button.update": "Cập nhật",
6
+ "containers.HomePage.PluginHeader.title": "Tài liệu - Cài đặt",
7
+ "containers.HomePage.PopUpWarning.confirm": "Tôi hiểu",
8
+ "containers.HomePage.PopUpWarning.message": "Bạn có chắc là muốn xóa phiên bản này không?",
9
+ "containers.HomePage.copied": "Chuỗi khoá đã được sao chép vào bộ nhớ tạm",
10
+ "containers.HomePage.form.jwtToken": "Lấy lại chuỗi khóa jwt của bạn",
11
+ "containers.HomePage.form.jwtToken.description": "Sao chép chuỗi khóa và sử dụng nó trong swagger để truy vấn",
12
+ "containers.HomePage.form.password": "Mật khẩu",
13
+ "containers.HomePage.form.password.inputDescription": "Cài đặt mật khẩu để truy cập tài liệu",
14
+ "containers.HomePage.form.restrictedAccess": "Truy cập bị giới hạn",
15
+ "containers.HomePage.form.restrictedAccess.inputDescription": "Làm cho điểm truy cập tài liệu thành riêng tư. Mặc định, truy cập là công khai.",
16
+ "containers.HomePage.form.showGeneratedFiles": "Hiển thị tập tin đã sinh ra",
17
+ "containers.HomePage.form.showGeneratedFiles.inputDescription": "Hữu ích khi bạn muốn ghi đè lên tài liệu đã sinh ra. \nPlugin này sẽ tạo ra các tập tin phân chia bởi cấu hình và plugin. \nBằng việc kích hoạt tuỳ chọn này, sẽ dễ dàng hơn cho bạn tùy chỉnh tài liệu của bạn.",
18
+ "error.deleteDoc.versionMissing": "Phiên bản bạn đang cố xóa không tồn tại.",
19
+ "error.noVersion": "Bắt buộc phải có một phiên bản",
20
+ "error.regenerateDoc": "Một lỗi đã xảy ra trong khi sinh ra tài liệu",
21
+ "error.regenerateDoc.versionMissing": "Phiên bản bạn đang cố sinh ra không tồn tại",
22
+ "notification.update.success": "Các cài đặt đã được cập nhật thành công",
23
+ "plugin.name": "Tài liệu"
24
+ }
@@ -0,0 +1,28 @@
1
+ {
2
+ "components.Row.open": "打开",
3
+ "components.Row.regenerate": "重新生成",
4
+ "containers.HomePage.Block.title": "版本号",
5
+ "containers.HomePage.Button.update": "更新",
6
+ "containers.HomePage.PluginHeader.title": "文档 - 设置",
7
+ "containers.HomePage.PopUpWarning.confirm": "我确定",
8
+ "containers.HomePage.PopUpWarning.message": "您确定要删除此版本吗?",
9
+ "containers.HomePage.copied": "令牌已被复制到粘贴板",
10
+ "containers.HomePage.form.jwtToken": "检索您的 jwt 令牌",
11
+ "containers.HomePage.form.jwtToken.description": "复制此令牌,并用它在 Swagger 中发出请求",
12
+ "containers.HomePage.form.password": "密码",
13
+ "containers.HomePage.form.password.inputDescription": "设置密码以供访问文档",
14
+ "containers.HomePage.form.restrictedAccess": "禁止访问",
15
+ "containers.HomePage.form.restrictedAccess.inputDescription": "将文档端点设为私有。默认情况下,访问权限是公共的",
16
+ "containers.HomePage.form.showGeneratedFiles": "显示生成的文件",
17
+ "containers.HomePage.form.showGeneratedFiles.inputDescription": "当您想要覆盖生成的文档的时候很有用。 \n该插件将生成按型号和插件拆分的文件。 \n通过启用此选项,可以更轻松地自定义文档",
18
+ "error.deleteDoc.versionMissing": "您尝试删除的版本不存在。",
19
+ "error.noVersion": "需要一个版本",
20
+ "error.regenerateDoc": "重新生成文件时发生错误",
21
+ "error.regenerateDoc.versionMissing": "您尝试重新生成的版本不存在",
22
+ "notification.delete.success": "文档删除成功",
23
+ "notification.generate.success": "文档生成成功",
24
+ "notification.update.success": "设置更新成功",
25
+ "plugin.description.long": "创建OpenAPI文档并使用SwaggerUI可视化你的API",
26
+ "plugin.description.short": "创建OpenAPI文档并使用SwaggerUI可视化你的API",
27
+ "plugin.name": "文档"
28
+ }
@@ -0,0 +1,24 @@
1
+ {
2
+ "components.Row.open": "開啟",
3
+ "components.Row.regenerate": "重新產生",
4
+ "containers.HomePage.Block.title": "版本",
5
+ "containers.HomePage.Button.update": "更新",
6
+ "containers.HomePage.PluginHeader.title": "文件資料 - 設定",
7
+ "containers.HomePage.PopUpWarning.confirm": "我了解了",
8
+ "containers.HomePage.PopUpWarning.message": "你確定要刪除這個版本嗎?",
9
+ "containers.HomePage.copied": "Token 已經複製到剪貼簿",
10
+ "containers.HomePage.form.jwtToken": "存取你的 jwt token",
11
+ "containers.HomePage.form.jwtToken.description": "複製這個token並於swagger中使用於發出請求",
12
+ "containers.HomePage.form.password": "密碼",
13
+ "containers.HomePage.form.password.inputDescription": "設定密碼存取權限",
14
+ "containers.HomePage.form.restrictedAccess": "存取受到限制",
15
+ "containers.HomePage.form.restrictedAccess.inputDescription": "將endpoints設定為私密的. 預設是對外公開的",
16
+ "containers.HomePage.form.showGeneratedFiles": "顯示產生的檔案",
17
+ "containers.HomePage.form.showGeneratedFiles.inputDescription": "用於覆寫產生的文件檔案時. \n擴充套件會依照model及plugin分別產生檔案. \n啟用這個選項將會方便你客製化文件資料",
18
+ "error.deleteDoc.versionMissing": "你想刪除的版本不存在",
19
+ "error.noVersion": "版本是必填欄位",
20
+ "error.regenerateDoc": "重新產生文件資料時發生了錯誤",
21
+ "error.regenerateDoc.versionMissing": "你想產生的版本不存在",
22
+ "notification.update.success": "更新設定成功",
23
+ "plugin.name": "文件資料"
24
+ }
@@ -0,0 +1,5 @@
1
+ import pluginId from '../pluginId';
2
+
3
+ const getTrad = (id) => `${pluginId}.${id}`;
4
+
5
+ export default getTrad;
@@ -0,0 +1,2 @@
1
+ // eslint-disable-next-line import/prefer-default-export
2
+ export { default as getTrad } from './getTrad';
@@ -0,0 +1,20 @@
1
+ import { startsWith } from 'lodash';
2
+
3
+ const openWithNewTab = (path) => {
4
+ const url = (() => {
5
+ if (startsWith(path, '/')) {
6
+ return `${strapi.backendURL}${path}`;
7
+ }
8
+ if (startsWith(path, 'https') || startsWith(path, 'http')) {
9
+ return path;
10
+ }
11
+
12
+ return `${strapi.backendURL}/${path}`;
13
+ })();
14
+
15
+ window.open(url, '_blank');
16
+
17
+ return window.focus();
18
+ };
19
+
20
+ export default openWithNewTab;
package/package.json ADDED
@@ -0,0 +1,66 @@
1
+ {
2
+ "name": "@strapi/plugin-documentation",
3
+ "version": "0.0.0-113ff29005",
4
+ "description": "Create an OpenAPI Document and visualize your API with SWAGGER UI.",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "https://github.com/strapi/strapi.git",
8
+ "directory": "packages/plugins/documentation"
9
+ },
10
+ "license": "SEE LICENSE IN LICENSE",
11
+ "author": {
12
+ "name": "Strapi Solutions SAS",
13
+ "email": "hi@strapi.io",
14
+ "url": "https://strapi.io"
15
+ },
16
+ "maintainers": [
17
+ {
18
+ "name": "Strapi Solutions SAS",
19
+ "email": "hi@strapi.io",
20
+ "url": "https://strapi.io"
21
+ }
22
+ ],
23
+ "scripts": {
24
+ "test": "echo \"no tests yet\""
25
+ },
26
+ "dependencies": {
27
+ "@strapi/helper-plugin": "0.0.0-113ff29005",
28
+ "@strapi/utils": "0.0.0-113ff29005",
29
+ "bcryptjs": "2.4.3",
30
+ "cheerio": "^1.0.0-rc.12",
31
+ "fs-extra": "10.0.0",
32
+ "koa-static": "^5.0.0",
33
+ "lodash": "4.17.21",
34
+ "path-to-regexp": "6.2.1",
35
+ "pluralize": "8.0.0",
36
+ "react": "^17.0.2",
37
+ "react-copy-to-clipboard": "^5.1.0",
38
+ "react-dom": "^17.0.2",
39
+ "react-intl": "5.20.2",
40
+ "react-redux": "7.2.8",
41
+ "react-router": "^5.2.0",
42
+ "react-router-dom": "5.2.0",
43
+ "redux": "^4.0.1",
44
+ "reselect": "^4.0.0",
45
+ "swagger-ui-dist": "4.12.0",
46
+ "yaml": "1.10.2"
47
+ },
48
+ "peerDependencies": {
49
+ "@strapi/strapi": "^4.0.0"
50
+ },
51
+ "devDependencies": {
52
+ "@testing-library/react": "11.2.7",
53
+ "msw": "0.42.3"
54
+ },
55
+ "engines": {
56
+ "node": ">=14.19.1 <=16.x.x",
57
+ "npm": ">=6.0.0"
58
+ },
59
+ "strapi": {
60
+ "displayName": "Documentation",
61
+ "name": "documentation",
62
+ "description": "Create an OpenAPI Document and visualize your API with SWAGGER UI.",
63
+ "kind": "plugin"
64
+ },
65
+ "gitHead": "113ff2900569e2f7b1d25a382451031bea239ed2"
66
+ }
@@ -0,0 +1,54 @@
1
+ /* eslint-disable no-unreachable */
2
+
3
+ 'use strict';
4
+
5
+ // Add permissions
6
+ const RBAC_ACTIONS = [
7
+ {
8
+ section: 'plugins',
9
+ displayName: 'Access the Documentation',
10
+ uid: 'read',
11
+ pluginName: 'documentation',
12
+ },
13
+ {
14
+ section: 'plugins',
15
+ displayName: 'Update and delete',
16
+ uid: 'settings.update',
17
+ pluginName: 'documentation',
18
+ },
19
+ {
20
+ section: 'plugins',
21
+ displayName: 'Regenerate',
22
+ uid: 'settings.regenerate',
23
+ pluginName: 'documentation',
24
+ },
25
+ {
26
+ section: 'settings',
27
+ displayName: 'Access the documentation settings page',
28
+ uid: 'settings.read',
29
+ pluginName: 'documentation',
30
+ category: 'documentation',
31
+ },
32
+ ];
33
+
34
+ /**
35
+ *
36
+ * @param {{strapi: import("@strapi/strapi").Strapi}} args
37
+ */
38
+ module.exports = async ({ strapi }) => {
39
+ await strapi.admin.services.permission.actionProvider.registerMany(RBAC_ACTIONS);
40
+
41
+ const pluginStore = strapi.store({
42
+ environment: '',
43
+ type: 'plugin',
44
+ name: 'documentation',
45
+ });
46
+
47
+ const config = await pluginStore.get({ key: 'config' });
48
+
49
+ if (!config) {
50
+ pluginStore.set({ key: 'config', value: { restrictedAccess: false } });
51
+ }
52
+
53
+ await strapi.plugin('documentation').service('documentation').generateFullDoc();
54
+ };
@@ -0,0 +1,74 @@
1
+ 'use strict';
2
+
3
+ module.exports = {
4
+ openapi: '3.0.0',
5
+ info: {
6
+ version: '1.0.0',
7
+ title: 'DOCUMENTATION',
8
+ description: '',
9
+ termsOfService: 'YOUR_TERMS_OF_SERVICE_URL',
10
+ contact: {
11
+ name: 'TEAM',
12
+ email: 'contact-email@something.io',
13
+ url: 'mywebsite.io',
14
+ },
15
+ license: {
16
+ name: 'Apache 2.0',
17
+ url: 'https://www.apache.org/licenses/LICENSE-2.0.html',
18
+ },
19
+ },
20
+ 'x-strapi-config': {
21
+ path: '/documentation',
22
+ showGeneratedFiles: true,
23
+ generateDefaultResponse: true,
24
+ plugins: ['email', 'upload', 'users-permissions'],
25
+ },
26
+ servers: [],
27
+ externalDocs: {
28
+ description: 'Find out more',
29
+ url: 'https://docs.strapi.io/developer-docs/latest/getting-started/introduction.html',
30
+ },
31
+ security: [
32
+ {
33
+ bearerAuth: [],
34
+ },
35
+ ],
36
+ components: {
37
+ securitySchemes: {
38
+ bearerAuth: {
39
+ type: 'http',
40
+ scheme: 'bearer',
41
+ bearerFormat: 'JWT',
42
+ },
43
+ },
44
+ schemas: {
45
+ Error: {
46
+ type: 'object',
47
+ required: ['error'],
48
+ properties: {
49
+ data: {
50
+ nullable: true,
51
+ oneOf: [{ type: 'object' }, { type: 'array', items: [] }],
52
+ },
53
+ error: {
54
+ type: 'object',
55
+ properties: {
56
+ status: {
57
+ type: 'integer',
58
+ },
59
+ name: {
60
+ type: 'string',
61
+ },
62
+ message: {
63
+ type: 'string',
64
+ },
65
+ details: {
66
+ type: 'object',
67
+ },
68
+ },
69
+ },
70
+ },
71
+ },
72
+ },
73
+ },
74
+ };
@@ -0,0 +1,7 @@
1
+ 'use strict';
2
+
3
+ const defaultPluginConfig = require('./default-plugin-config');
4
+
5
+ module.exports = {
6
+ default: defaultPluginConfig,
7
+ };
@@ -0,0 +1,241 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Documentation.js controller
5
+ *
6
+ * @description: A set of functions called "actions" of the `documentation` plugin.
7
+ */
8
+
9
+ // Core dependencies.
10
+ const path = require('path');
11
+ const bcrypt = require('bcryptjs');
12
+
13
+ // Public dependencies.
14
+ const fs = require('fs-extra');
15
+ const _ = require('lodash');
16
+ const koaStatic = require('koa-static');
17
+
18
+ module.exports = {
19
+ async getInfos(ctx) {
20
+ try {
21
+ const docService = strapi.plugin('documentation').service('documentation');
22
+ const docVersions = docService.getDocumentationVersions();
23
+ const documentationAccess = await docService.getDocumentationAccess();
24
+
25
+ ctx.send({
26
+ docVersions,
27
+ currentVersion: docService.getDocumentationVersion(),
28
+ prefix: strapi.plugin('documentation').config('x-strapi-config').path,
29
+ documentationAccess,
30
+ });
31
+ } catch (err) {
32
+ ctx.badRequest(null, err.message);
33
+ }
34
+ },
35
+
36
+ async index(ctx, next) {
37
+ try {
38
+ /**
39
+ * We don't expose the specs using koa-static or something else due to security reasons.
40
+ * That's why, we need to read the file localy and send the specs through it when we serve the Swagger UI.
41
+ */
42
+ const { major, minor, patch } = ctx.params;
43
+ const version =
44
+ major && minor && patch
45
+ ? `${major}.${minor}.${patch}`
46
+ : strapi.plugin('documentation').service('documentation').getDocumentationVersion();
47
+
48
+ const openAPISpecsPath = path.join(
49
+ strapi.dirs.app.extensions,
50
+ 'documentation',
51
+ 'documentation',
52
+ version,
53
+ 'full_documentation.json'
54
+ );
55
+
56
+ try {
57
+ const documentation = fs.readFileSync(openAPISpecsPath, 'utf8');
58
+ const layout = fs.readFileSync(
59
+ path.resolve(__dirname, '..', 'public', 'index.html'),
60
+ 'utf8'
61
+ );
62
+ const filledLayout = _.template(layout)({
63
+ backendUrl: strapi.config.server.url,
64
+ spec: JSON.stringify(JSON.parse(documentation)),
65
+ });
66
+
67
+ try {
68
+ const layoutPath = path.resolve(
69
+ strapi.dirs.app.extensions,
70
+ 'documentation',
71
+ 'public',
72
+ 'index.html'
73
+ );
74
+ await fs.ensureFile(layoutPath);
75
+ await fs.writeFile(layoutPath, filledLayout);
76
+
77
+ // Serve the file.
78
+ ctx.url = path.basename(`${ctx.url}/index.html`);
79
+
80
+ try {
81
+ const staticFolder = path.resolve(
82
+ strapi.dirs.app.extensions,
83
+ 'documentation',
84
+ 'public'
85
+ );
86
+ return koaStatic(staticFolder)(ctx, next);
87
+ } catch (e) {
88
+ strapi.log.error(e);
89
+ }
90
+ } catch (e) {
91
+ strapi.log.error(e);
92
+ }
93
+ } catch (e) {
94
+ strapi.log.error(e);
95
+ }
96
+ } catch (e) {
97
+ strapi.log.error(e);
98
+ }
99
+ },
100
+
101
+ async loginView(ctx, next) {
102
+ // lazy require cheerio
103
+ const cheerio = require('cheerio');
104
+
105
+ const { error } = ctx.query;
106
+
107
+ try {
108
+ const layout = fs.readFileSync(path.join(__dirname, '..', 'public', 'login.html'));
109
+ const filledLayout = _.template(layout)({
110
+ actionUrl: `${strapi.config.server.url}${
111
+ strapi.config.get('plugin.documentation.x-strapi-config').path
112
+ }/login`,
113
+ });
114
+ const $ = cheerio.load(filledLayout);
115
+
116
+ $('.error').text(_.isEmpty(error) ? '' : 'Wrong password...');
117
+
118
+ try {
119
+ const layoutPath = path.resolve(
120
+ strapi.dirs.app.extensions,
121
+ 'documentation',
122
+ 'public',
123
+ 'login.html'
124
+ );
125
+ await fs.ensureFile(layoutPath);
126
+ await fs.writeFile(layoutPath, $.html());
127
+
128
+ ctx.url = path.basename(`${ctx.url}/login.html`);
129
+
130
+ try {
131
+ const staticFolder = path.resolve(strapi.dirs.app.extensions, 'documentation', 'public');
132
+ return koaStatic(staticFolder)(ctx, next);
133
+ } catch (e) {
134
+ strapi.log.error(e);
135
+ }
136
+ } catch (e) {
137
+ strapi.log.error(e);
138
+ }
139
+ } catch (e) {
140
+ strapi.log.error(e);
141
+ }
142
+ },
143
+
144
+ async login(ctx) {
145
+ const {
146
+ body: { password },
147
+ } = ctx.request;
148
+
149
+ const { password: hash } = await strapi
150
+ .store({ type: 'plugin', name: 'documentation', key: 'config' })
151
+ .get();
152
+
153
+ const isValid = await bcrypt.compare(password, hash);
154
+
155
+ let querystring = '?error=password';
156
+
157
+ if (isValid) {
158
+ ctx.session.documentation = {
159
+ logged: true,
160
+ };
161
+
162
+ querystring = '';
163
+ }
164
+
165
+ ctx.redirect(
166
+ `${strapi.config.server.url}${
167
+ strapi.config.get('plugin.documentation.x-strapi-config').path
168
+ }${querystring}`
169
+ );
170
+ },
171
+
172
+ async regenerateDoc(ctx) {
173
+ const { version } = ctx.request.body;
174
+
175
+ const service = strapi.service('plugin::documentation.documentation');
176
+
177
+ const documentationVersions = service.getDocumentationVersions().map((el) => el.version);
178
+
179
+ if (_.isEmpty(version)) {
180
+ return ctx.badRequest('Please provide a version.');
181
+ }
182
+
183
+ if (!documentationVersions.includes(version)) {
184
+ return ctx.badRequest('The version you are trying to generate does not exist.');
185
+ }
186
+
187
+ try {
188
+ strapi.reload.isWatching = false;
189
+ await service.generateFullDoc(version);
190
+ ctx.send({ ok: true });
191
+ } finally {
192
+ strapi.reload.isWatching = true;
193
+ }
194
+ },
195
+
196
+ async deleteDoc(ctx) {
197
+ const { version } = ctx.params;
198
+
199
+ const service = strapi.service('plugin::documentation.documentation');
200
+
201
+ const documentationVersions = service.getDocumentationVersions().map((el) => el.version);
202
+
203
+ if (_.isEmpty(version)) {
204
+ return ctx.badRequest('Please provide a version.');
205
+ }
206
+
207
+ if (!documentationVersions.includes(version)) {
208
+ return ctx.badRequest('The version you are trying to delete does not exist.');
209
+ }
210
+
211
+ try {
212
+ strapi.reload.isWatching = false;
213
+ await service.deleteDocumentation(version);
214
+ ctx.send({ ok: true });
215
+ } finally {
216
+ strapi.reload.isWatching = true;
217
+ }
218
+ },
219
+
220
+ async updateSettings(ctx) {
221
+ const { restrictedAccess, password } = ctx.request.body;
222
+
223
+ const pluginStore = strapi.store({ type: 'plugin', name: 'documentation' });
224
+
225
+ const config = {
226
+ restrictedAccess: Boolean(restrictedAccess),
227
+ };
228
+
229
+ if (restrictedAccess) {
230
+ if (_.isEmpty(password)) {
231
+ return ctx.badRequest('Please provide a password');
232
+ }
233
+
234
+ config.password = await bcrypt.hash(password, 10);
235
+ }
236
+
237
+ await pluginStore.set({ key: 'config', value: config });
238
+
239
+ return ctx.send({ ok: true });
240
+ },
241
+ };
@@ -0,0 +1,7 @@
1
+ 'use strict';
2
+
3
+ const documentation = require('./documentation');
4
+
5
+ module.exports = {
6
+ documentation,
7
+ };
@@ -0,0 +1,17 @@
1
+ 'use strict';
2
+
3
+ const bootstrap = require('./bootstrap');
4
+ const services = require('./services');
5
+ const routes = require('./routes');
6
+ const controllers = require('./controllers');
7
+ const register = require('./register');
8
+ const config = require('./config');
9
+
10
+ module.exports = () => ({
11
+ bootstrap,
12
+ config,
13
+ routes,
14
+ controllers,
15
+ register,
16
+ services,
17
+ });
@@ -0,0 +1,25 @@
1
+ 'use strict';
2
+
3
+ const path = require('path');
4
+ const koaStatic = require('koa-static');
5
+ const swaggerUi = require('swagger-ui-dist');
6
+
7
+ module.exports = async ({ strapi }) => {
8
+ strapi.server.routes([
9
+ {
10
+ method: 'GET',
11
+ path: '/plugins/documentation/(.*)',
12
+ async handler(ctx, next) {
13
+ ctx.url = path.basename(ctx.url);
14
+
15
+ return koaStatic(swaggerUi.getAbsoluteFSPath(), {
16
+ maxage: 86400000,
17
+ defer: true,
18
+ })(ctx, next);
19
+ },
20
+ config: {
21
+ auth: false,
22
+ },
23
+ },
24
+ ]);
25
+ };
@@ -0,0 +1,7 @@
1
+ 'use strict';
2
+
3
+ const documentation = require('./documentation');
4
+
5
+ module.exports = {
6
+ documentation,
7
+ };
@@ -0,0 +1,24 @@
1
+ 'use strict';
2
+
3
+ module.exports = async (ctx, next) => {
4
+ const pluginStore = strapi.store({ type: 'plugin', name: 'documentation' });
5
+
6
+ const config = await pluginStore.get({ key: 'config' });
7
+
8
+ if (!config.restrictedAccess) {
9
+ return next();
10
+ }
11
+
12
+ if (!ctx.session.documentation || !ctx.session.documentation.logged) {
13
+ const querystring = ctx.querystring ? `?${ctx.querystring}` : '';
14
+
15
+ return ctx.redirect(
16
+ `${strapi.config.server.url}${
17
+ strapi.config.get('plugin.documentation.x-strapi-config').path
18
+ }/login${querystring}`
19
+ );
20
+ }
21
+
22
+ // Execute the action.
23
+ return next();
24
+ };