@strapi/plugin-documentation 5.0.0-beta.0 → 5.0.0-beta.1

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 (184) hide show
  1. package/README.md +0 -1
  2. package/dist/_chunks/{index-7xstUX8_.mjs → App-ig-uE4do.mjs} +48 -14
  3. package/dist/_chunks/App-ig-uE4do.mjs.map +1 -0
  4. package/dist/_chunks/{index-D1KkfApT.js → App-o4uH8gaQ.js} +73 -20
  5. package/dist/_chunks/App-o4uH8gaQ.js.map +1 -0
  6. package/dist/_chunks/{index-VpLAJXMs.mjs → Settings-3hsPOP_b.mjs} +64 -33
  7. package/dist/_chunks/Settings-3hsPOP_b.mjs.map +1 -0
  8. package/dist/_chunks/{index-NbPCucJl.js → Settings-XmOzLTUn.js} +69 -37
  9. package/dist/_chunks/Settings-XmOzLTUn.js.map +1 -0
  10. package/dist/_chunks/getTrad-bnElvR8_.js +5 -0
  11. package/dist/_chunks/getTrad-bnElvR8_.js.map +1 -0
  12. package/dist/_chunks/getTrad-md7Tjpcv.mjs +6 -0
  13. package/dist/_chunks/getTrad-md7Tjpcv.mjs.map +1 -0
  14. package/{server/public/index.html → dist/_chunks/index-MKWIGajW.mjs} +9 -4
  15. package/dist/_chunks/index-MKWIGajW.mjs.map +1 -0
  16. package/dist/_chunks/index-WbbYm9_u.js +75 -0
  17. package/dist/_chunks/index-WbbYm9_u.js.map +1 -0
  18. package/dist/_chunks/{index-NvJ4m2q5.mjs → index-jpDwTC-Q.mjs} +121 -117
  19. package/dist/_chunks/index-jpDwTC-Q.mjs.map +1 -0
  20. package/dist/_chunks/{index-r7HsQTou.js → index-vNbIS1u2.js} +119 -115
  21. package/dist/_chunks/index-vNbIS1u2.js.map +1 -0
  22. package/dist/_chunks/login-HAajOKpu.js +150 -0
  23. package/dist/_chunks/login-HAajOKpu.js.map +1 -0
  24. package/{server/public/login.html → dist/_chunks/login-slUa679p.mjs} +6 -1
  25. package/dist/_chunks/login-slUa679p.mjs.map +1 -0
  26. package/dist/admin/index.js +1 -1
  27. package/dist/admin/index.mjs +2 -2
  28. package/dist/admin/src/components/SettingsForm.d.ts +8 -0
  29. package/dist/admin/src/constants.d.ts +18 -0
  30. package/dist/admin/src/index.d.ts +14 -0
  31. package/dist/admin/src/pages/App.d.ts +2 -0
  32. package/dist/admin/src/pages/Settings.d.ts +2 -0
  33. package/dist/admin/src/pluginId.d.ts +1 -0
  34. package/dist/admin/src/services/api.d.ts +25 -0
  35. package/dist/admin/src/types.d.ts +16 -0
  36. package/dist/admin/src/utils/baseQuery.d.ts +20 -0
  37. package/dist/admin/src/utils/getTrad.d.ts +1 -0
  38. package/dist/admin/src/utils/index.d.ts +2 -0
  39. package/dist/admin/src/utils/prefixPluginTranslations.d.ts +2 -0
  40. package/dist/server/index.js +1263 -0
  41. package/dist/server/index.js.map +1 -0
  42. package/dist/server/index.mjs +1238 -0
  43. package/dist/server/index.mjs.map +1 -0
  44. package/dist/server/src/bootstrap.d.ts +5 -0
  45. package/dist/server/src/bootstrap.d.ts.map +1 -0
  46. package/dist/server/src/config/default-plugin-config.d.ts +3 -0
  47. package/dist/server/src/config/default-plugin-config.d.ts.map +1 -0
  48. package/dist/server/src/config/index.d.ts +4 -0
  49. package/dist/server/src/config/index.d.ts.map +1 -0
  50. package/dist/server/src/controllers/documentation.d.ts +12 -0
  51. package/dist/server/src/controllers/documentation.d.ts.map +1 -0
  52. package/dist/server/src/controllers/index.d.ts +14 -0
  53. package/dist/server/src/controllers/index.d.ts.map +1 -0
  54. package/dist/server/src/index.d.ts +91 -0
  55. package/dist/server/src/index.d.ts.map +1 -0
  56. package/dist/server/src/middlewares/documentation.d.ts +5 -0
  57. package/dist/server/src/middlewares/documentation.d.ts.map +1 -0
  58. package/dist/server/src/middlewares/restrict-access.d.ts +4 -0
  59. package/dist/server/src/middlewares/restrict-access.d.ts.map +1 -0
  60. package/dist/server/src/register.d.ts +5 -0
  61. package/dist/server/src/register.d.ts.map +1 -0
  62. package/dist/server/src/routes/index.d.ts +36 -0
  63. package/dist/server/src/routes/index.d.ts.map +1 -0
  64. package/dist/server/src/services/__mocks__/mock-content-types.d.ts +449 -0
  65. package/dist/server/src/services/__mocks__/mock-content-types.d.ts.map +1 -0
  66. package/dist/server/src/services/__mocks__/mock-strapi-data.d.ts +592 -0
  67. package/dist/server/src/services/__mocks__/mock-strapi-data.d.ts.map +1 -0
  68. package/dist/server/src/services/documentation.d.ts +36 -0
  69. package/dist/server/src/services/documentation.d.ts.map +1 -0
  70. package/dist/server/src/services/helpers/build-api-endpoint-path.d.ts +7 -0
  71. package/dist/server/src/services/helpers/build-api-endpoint-path.d.ts.map +1 -0
  72. package/dist/server/src/services/helpers/build-component-schema.d.ts +4 -0
  73. package/dist/server/src/services/helpers/build-component-schema.d.ts.map +1 -0
  74. package/dist/server/src/services/helpers/index.d.ts +4 -0
  75. package/dist/server/src/services/helpers/index.d.ts.map +1 -0
  76. package/dist/server/src/services/helpers/utils/clean-schema-attributes.d.ts +15 -0
  77. package/dist/server/src/services/helpers/utils/clean-schema-attributes.d.ts.map +1 -0
  78. package/dist/server/src/services/helpers/utils/get-api-responses.d.ts +15 -0
  79. package/dist/server/src/services/helpers/utils/get-api-responses.d.ts.map +1 -0
  80. package/dist/server/src/services/helpers/utils/get-schema-data.d.ts +12 -0
  81. package/dist/server/src/services/helpers/utils/get-schema-data.d.ts.map +1 -0
  82. package/dist/server/src/services/helpers/utils/loop-content-type-names.d.ts +7 -0
  83. package/dist/server/src/services/helpers/utils/loop-content-type-names.d.ts.map +1 -0
  84. package/dist/server/src/services/helpers/utils/pascal-case.d.ts +3 -0
  85. package/dist/server/src/services/helpers/utils/pascal-case.d.ts.map +1 -0
  86. package/dist/server/src/services/helpers/utils/query-params.d.ts +4 -0
  87. package/dist/server/src/services/helpers/utils/query-params.d.ts.map +1 -0
  88. package/dist/server/src/services/helpers/utils/routes.d.ts +3 -0
  89. package/dist/server/src/services/helpers/utils/routes.d.ts.map +1 -0
  90. package/dist/server/src/services/index.d.ts +43 -0
  91. package/dist/server/src/services/index.d.ts.map +1 -0
  92. package/dist/server/src/services/override.d.ts +21 -0
  93. package/dist/server/src/services/override.d.ts.map +1 -0
  94. package/dist/server/src/services/utils/get-plugins-that-need-documentation.d.ts +4 -0
  95. package/dist/server/src/services/utils/get-plugins-that-need-documentation.d.ts.map +1 -0
  96. package/dist/server/src/types.d.ts +28 -0
  97. package/dist/server/src/types.d.ts.map +1 -0
  98. package/dist/server/src/utils.d.ts +12 -0
  99. package/dist/server/src/utils.d.ts.map +1 -0
  100. package/package.json +33 -15
  101. package/strapi-server.js +1 -1
  102. package/.eslintignore +0 -1
  103. package/.eslintrc +0 -17
  104. package/admin/src/constants.js +0 -17
  105. package/admin/src/hooks/useDocumentation.js +0 -81
  106. package/admin/src/index.js +0 -62
  107. package/admin/src/pages/PluginPage/index.jsx +0 -212
  108. package/admin/src/pages/PluginPage/tests/index.test.jsx +0 -160
  109. package/admin/src/pages/SettingsPage/index.jsx +0 -202
  110. package/admin/src/pages/SettingsPage/tests/index.test.jsx +0 -72
  111. package/admin/src/pluginId.js +0 -5
  112. package/admin/src/translations/ar.json +0 -20
  113. package/admin/src/translations/cs.json +0 -21
  114. package/admin/src/translations/de.json +0 -26
  115. package/admin/src/translations/dk.json +0 -39
  116. package/admin/src/translations/en.json +0 -39
  117. package/admin/src/translations/es.json +0 -39
  118. package/admin/src/translations/fr.json +0 -26
  119. package/admin/src/translations/id.json +0 -24
  120. package/admin/src/translations/it.json +0 -26
  121. package/admin/src/translations/ko.json +0 -39
  122. package/admin/src/translations/ms.json +0 -23
  123. package/admin/src/translations/nl.json +0 -21
  124. package/admin/src/translations/pl.json +0 -39
  125. package/admin/src/translations/pt-BR.json +0 -21
  126. package/admin/src/translations/pt.json +0 -21
  127. package/admin/src/translations/ru.json +0 -39
  128. package/admin/src/translations/sk.json +0 -24
  129. package/admin/src/translations/sv.json +0 -39
  130. package/admin/src/translations/th.json +0 -24
  131. package/admin/src/translations/tr.json +0 -39
  132. package/admin/src/translations/uk.json +0 -23
  133. package/admin/src/translations/vi.json +0 -24
  134. package/admin/src/translations/zh-Hans.json +0 -28
  135. package/admin/src/translations/zh.json +0 -39
  136. package/admin/src/utils/getTrad.js +0 -5
  137. package/admin/src/utils/index.js +0 -2
  138. package/admin/src/utils/prefixPluginTranslations.js +0 -13
  139. package/dist/_chunks/index-7xstUX8_.mjs.map +0 -1
  140. package/dist/_chunks/index-D1KkfApT.js.map +0 -1
  141. package/dist/_chunks/index-NbPCucJl.js.map +0 -1
  142. package/dist/_chunks/index-NvJ4m2q5.mjs.map +0 -1
  143. package/dist/_chunks/index-VpLAJXMs.mjs.map +0 -1
  144. package/dist/_chunks/index-r7HsQTou.js.map +0 -1
  145. package/dist/_chunks/useDocumentation-6Ks-_Ms6.mjs +0 -68
  146. package/dist/_chunks/useDocumentation-6Ks-_Ms6.mjs.map +0 -1
  147. package/dist/_chunks/useDocumentation-S0e4mU-U.js +0 -67
  148. package/dist/_chunks/useDocumentation-S0e4mU-U.js.map +0 -1
  149. package/jest.config.front.js +0 -7
  150. package/jest.config.js +0 -6
  151. package/packup.config.ts +0 -22
  152. package/server/bootstrap.js +0 -54
  153. package/server/config/default-plugin-config.js +0 -35
  154. package/server/config/index.js +0 -7
  155. package/server/controllers/documentation.js +0 -241
  156. package/server/controllers/index.js +0 -7
  157. package/server/index.js +0 -17
  158. package/server/middlewares/documentation.js +0 -25
  159. package/server/middlewares/index.js +0 -7
  160. package/server/middlewares/restrict-access.js +0 -24
  161. package/server/register.js +0 -11
  162. package/server/routes/index.js +0 -84
  163. package/server/services/__mocks__/mock-content-types.js +0 -264
  164. package/server/services/__mocks__/mock-strapi-data.js +0 -183
  165. package/server/services/__tests__/build-component-schema.test.js +0 -761
  166. package/server/services/__tests__/documentation.test.js +0 -481
  167. package/server/services/__tests__/override.test.js +0 -85
  168. package/server/services/documentation.js +0 -246
  169. package/server/services/helpers/build-api-endpoint-path.js +0 -186
  170. package/server/services/helpers/build-component-schema.js +0 -254
  171. package/server/services/helpers/index.js +0 -9
  172. package/server/services/helpers/utils/clean-schema-attributes.js +0 -246
  173. package/server/services/helpers/utils/get-api-responses.js +0 -105
  174. package/server/services/helpers/utils/get-schema-data.js +0 -32
  175. package/server/services/helpers/utils/loop-content-type-names.js +0 -55
  176. package/server/services/helpers/utils/pascal-case.js +0 -9
  177. package/server/services/helpers/utils/query-params.js +0 -105
  178. package/server/services/helpers/utils/routes.js +0 -10
  179. package/server/services/index.js +0 -9
  180. package/server/services/override.js +0 -52
  181. package/server/services/utils/default-openapi-components.js +0 -40
  182. package/server/services/utils/get-plugins-that-need-documentation.js +0 -24
  183. package/tests/server.js +0 -37
  184. package/tests/setup.js +0 -15
@@ -0,0 +1,1238 @@
1
+ import path from "path";
2
+ import koaStatic from "koa-static";
3
+ import swaggerUi from "swagger-ui-dist";
4
+ import fs from "fs-extra";
5
+ import { produce } from "immer";
6
+ import _ from "lodash";
7
+ import * as pathToRegexp from "path-to-regexp";
8
+ import bcrypt from "bcryptjs";
9
+ import { validateYupSchema, yup } from "@strapi/utils";
10
+ const getService = (name, { strapi: strapi2 } = { strapi: global.strapi }) => {
11
+ return strapi2.plugin("documentation").service(name);
12
+ };
13
+ const RBAC_ACTIONS = [
14
+ {
15
+ section: "plugins",
16
+ displayName: "Access the Documentation",
17
+ uid: "read",
18
+ pluginName: "documentation"
19
+ },
20
+ {
21
+ section: "plugins",
22
+ displayName: "Update and delete",
23
+ uid: "settings.update",
24
+ pluginName: "documentation"
25
+ },
26
+ {
27
+ section: "plugins",
28
+ displayName: "Regenerate",
29
+ uid: "settings.regenerate",
30
+ pluginName: "documentation"
31
+ },
32
+ {
33
+ section: "settings",
34
+ displayName: "Access the documentation settings page",
35
+ uid: "settings.read",
36
+ pluginName: "documentation",
37
+ category: "documentation"
38
+ }
39
+ ];
40
+ async function bootstrap({ strapi: strapi2 }) {
41
+ await strapi2.admin?.services.permission.actionProvider.registerMany(RBAC_ACTIONS);
42
+ const pluginStore = strapi2.store({
43
+ environment: "",
44
+ type: "plugin",
45
+ name: "documentation"
46
+ });
47
+ const config2 = await pluginStore.get({ key: "config" });
48
+ if (!config2) {
49
+ pluginStore.set({ key: "config", value: { restrictedAccess: false } });
50
+ }
51
+ await getService("documentation").generateFullDoc();
52
+ }
53
+ const addDocumentMiddlewares = async ({ strapi: strapi2 }) => {
54
+ strapi2.server.routes([
55
+ {
56
+ method: "GET",
57
+ path: "/plugins/documentation/(.*)",
58
+ async handler(ctx, next) {
59
+ ctx.url = path.basename(ctx.url);
60
+ return koaStatic(swaggerUi.getAbsoluteFSPath(), {
61
+ maxage: 864e5,
62
+ defer: true
63
+ })(ctx, next);
64
+ },
65
+ config: {
66
+ auth: false
67
+ }
68
+ }
69
+ ]);
70
+ };
71
+ async function register({ strapi: strapi2 }) {
72
+ await addDocumentMiddlewares({ strapi: strapi2 });
73
+ }
74
+ const pascalCase = (string) => {
75
+ return _.upperFirst(_.camelCase(string));
76
+ };
77
+ const params = [
78
+ {
79
+ name: "sort",
80
+ in: "query",
81
+ description: "Sort by attributes ascending (asc) or descending (desc)",
82
+ deprecated: false,
83
+ required: false,
84
+ schema: {
85
+ type: "string"
86
+ }
87
+ },
88
+ {
89
+ name: "pagination[withCount]",
90
+ in: "query",
91
+ description: "Return page/pageSize (default: true)",
92
+ deprecated: false,
93
+ required: false,
94
+ schema: {
95
+ type: "boolean"
96
+ }
97
+ },
98
+ {
99
+ name: "pagination[page]",
100
+ in: "query",
101
+ description: "Page number (default: 0)",
102
+ deprecated: false,
103
+ required: false,
104
+ schema: {
105
+ type: "integer"
106
+ }
107
+ },
108
+ {
109
+ name: "pagination[pageSize]",
110
+ in: "query",
111
+ description: "Page size (default: 25)",
112
+ deprecated: false,
113
+ required: false,
114
+ schema: {
115
+ type: "integer"
116
+ }
117
+ },
118
+ {
119
+ name: "pagination[start]",
120
+ in: "query",
121
+ description: "Offset value (default: 0)",
122
+ deprecated: false,
123
+ required: false,
124
+ schema: {
125
+ type: "integer"
126
+ }
127
+ },
128
+ {
129
+ name: "pagination[limit]",
130
+ in: "query",
131
+ description: "Number of entities to return (default: 25)",
132
+ deprecated: false,
133
+ required: false,
134
+ schema: {
135
+ type: "integer"
136
+ }
137
+ },
138
+ {
139
+ name: "fields",
140
+ in: "query",
141
+ description: "Fields to return (ex: title,author)",
142
+ deprecated: false,
143
+ required: false,
144
+ schema: {
145
+ type: "string"
146
+ }
147
+ },
148
+ {
149
+ name: "populate",
150
+ in: "query",
151
+ description: "Relations to return",
152
+ deprecated: false,
153
+ required: false,
154
+ schema: {
155
+ type: "string"
156
+ }
157
+ },
158
+ {
159
+ name: "filters",
160
+ in: "query",
161
+ description: "Filters to apply",
162
+ deprecated: false,
163
+ required: false,
164
+ schema: {
165
+ type: "object"
166
+ },
167
+ style: "deepObject"
168
+ },
169
+ {
170
+ name: "locale",
171
+ in: "query",
172
+ description: "Locale to apply",
173
+ deprecated: false,
174
+ required: false,
175
+ schema: {
176
+ type: "string"
177
+ }
178
+ }
179
+ ];
180
+ const loopContentTypeNames = (api, callback) => {
181
+ let result = {};
182
+ for (const contentTypeName of api.ctNames) {
183
+ const uid = `${api.getter}::${api.name}.${contentTypeName}`;
184
+ const { attributes, info: contentTypeInfo, kind } = strapi.contentType(uid);
185
+ const routeInfo = api.getter === "plugin" ? (
186
+ // @ts-expect-error - This is a valid check
187
+ strapi.plugin(api.name).routes["content-api"]
188
+ ) : strapi.api[api.name].routes[contentTypeName];
189
+ if (!routeInfo) {
190
+ continue;
191
+ }
192
+ const apiName = _.upperFirst(api.name);
193
+ const uniqueName = api.name === contentTypeName ? apiName : `${apiName} - ${_.upperFirst(contentTypeName)}`;
194
+ const apiInfo = {
195
+ ...api,
196
+ routeInfo,
197
+ attributes,
198
+ uniqueName,
199
+ contentTypeInfo,
200
+ kind
201
+ };
202
+ result = {
203
+ ...result,
204
+ ...callback(apiInfo)
205
+ };
206
+ }
207
+ return result;
208
+ };
209
+ const getApiResponse = ({
210
+ uniqueName,
211
+ route,
212
+ isListOfEntities = false
213
+ }) => {
214
+ const getSchema = () => {
215
+ if (route.method === "DELETE") {
216
+ return {
217
+ type: "integer",
218
+ format: "int64"
219
+ };
220
+ }
221
+ if (isListOfEntities) {
222
+ return { $ref: `#/components/schemas/${pascalCase(uniqueName)}ListResponse` };
223
+ }
224
+ return { $ref: `#/components/schemas/${pascalCase(uniqueName)}Response` };
225
+ };
226
+ const schema = getSchema();
227
+ return {
228
+ 200: {
229
+ description: "OK",
230
+ content: {
231
+ "application/json": {
232
+ schema
233
+ }
234
+ }
235
+ },
236
+ 400: {
237
+ description: "Bad Request",
238
+ content: {
239
+ "application/json": {
240
+ schema: {
241
+ $ref: "#/components/schemas/Error"
242
+ }
243
+ }
244
+ }
245
+ },
246
+ 401: {
247
+ description: "Unauthorized",
248
+ content: {
249
+ "application/json": {
250
+ schema: {
251
+ $ref: "#/components/schemas/Error"
252
+ }
253
+ }
254
+ }
255
+ },
256
+ 403: {
257
+ description: "Forbidden",
258
+ content: {
259
+ "application/json": {
260
+ schema: {
261
+ $ref: "#/components/schemas/Error"
262
+ }
263
+ }
264
+ }
265
+ },
266
+ 404: {
267
+ description: "Not Found",
268
+ content: {
269
+ "application/json": {
270
+ schema: {
271
+ $ref: "#/components/schemas/Error"
272
+ }
273
+ }
274
+ }
275
+ },
276
+ 500: {
277
+ description: "Internal Server Error",
278
+ content: {
279
+ "application/json": {
280
+ schema: {
281
+ $ref: "#/components/schemas/Error"
282
+ }
283
+ }
284
+ }
285
+ }
286
+ };
287
+ };
288
+ const hasFindMethod = (handler) => {
289
+ if (typeof handler === "string") {
290
+ return handler.split(".").pop() === "find";
291
+ }
292
+ return false;
293
+ };
294
+ const parsePathWithVariables = (routePath) => {
295
+ return pathToRegexp.parse(routePath).map((token) => {
296
+ if (_.isObject(token)) {
297
+ return `${token.prefix}{${token.name}}`;
298
+ }
299
+ return token;
300
+ }).join("");
301
+ };
302
+ const getPathParams = (routePath) => {
303
+ return pathToRegexp.parse(routePath).reduce((acc, param) => {
304
+ if (!(typeof param === "object")) {
305
+ return acc;
306
+ }
307
+ acc.push({
308
+ name: `${param.name}`,
309
+ in: "path",
310
+ description: "",
311
+ deprecated: false,
312
+ required: true,
313
+ schema: { type: "number" }
314
+ });
315
+ return acc;
316
+ }, []);
317
+ };
318
+ const getPathWithPrefix = (prefix, route) => {
319
+ if (prefix && !_.has(route.config, "prefix")) {
320
+ return prefix.concat(route.path);
321
+ }
322
+ return route.path;
323
+ };
324
+ const getPaths = ({ routeInfo, uniqueName, contentTypeInfo, kind }) => {
325
+ const contentTypeRoutes = routeInfo.routes.filter((route) => {
326
+ return route.path.includes(contentTypeInfo.pluralName) || route.path.includes(contentTypeInfo.singularName);
327
+ });
328
+ const paths = contentTypeRoutes.reduce((acc, route) => {
329
+ const isListOfEntities = hasFindMethod(route.handler);
330
+ const methodVerb = route.method.toLowerCase();
331
+ const hasPathParams = route.path.includes("/:");
332
+ const pathWithPrefix = getPathWithPrefix(routeInfo.prefix, route);
333
+ const routePath = hasPathParams ? parsePathWithVariables(pathWithPrefix) : pathWithPrefix;
334
+ const responses = getApiResponse({
335
+ uniqueName,
336
+ route,
337
+ isListOfEntities: kind !== "singleType" && isListOfEntities
338
+ });
339
+ const swaggerConfig = {
340
+ responses,
341
+ tags: [_.upperFirst(uniqueName)],
342
+ parameters: [],
343
+ operationId: `${methodVerb}${routePath}`
344
+ };
345
+ if (isListOfEntities) {
346
+ swaggerConfig.parameters?.push(...params);
347
+ }
348
+ if (hasPathParams) {
349
+ const pathParams = getPathParams(route.path);
350
+ swaggerConfig.parameters?.push(...pathParams);
351
+ }
352
+ if (["post", "put"].includes(methodVerb)) {
353
+ const refName = "Request";
354
+ const requestBody = {
355
+ required: true,
356
+ content: {
357
+ "application/json": {
358
+ schema: {
359
+ $ref: `#/components/schemas/${pascalCase(uniqueName)}${refName}`
360
+ }
361
+ }
362
+ }
363
+ };
364
+ swaggerConfig.requestBody = requestBody;
365
+ }
366
+ _.set(acc, `${routePath}.${methodVerb}`, swaggerConfig);
367
+ return acc;
368
+ }, {});
369
+ return paths;
370
+ };
371
+ const buildApiEndpointPath = (api) => {
372
+ return loopContentTypeNames(api, getPaths);
373
+ };
374
+ const getSchemaData = (isListOfEntities, attributes) => {
375
+ if (isListOfEntities) {
376
+ return {
377
+ type: "array",
378
+ items: {
379
+ type: "object",
380
+ properties: {
381
+ id: { type: "number" },
382
+ documentId: { type: "string" },
383
+ ...attributes
384
+ }
385
+ }
386
+ };
387
+ }
388
+ return {
389
+ type: "object",
390
+ properties: {
391
+ id: { type: "number" },
392
+ documentId: { type: "string" },
393
+ ...attributes
394
+ }
395
+ };
396
+ };
397
+ const cleanSchemaAttributes = (attributes, { typeMap = /* @__PURE__ */ new Map(), isRequest = false, didAddStrapiComponentsToSchemas }) => {
398
+ const schemaAttributes = {};
399
+ for (const prop of Object.keys(attributes)) {
400
+ const attribute = attributes[prop];
401
+ switch (attribute.type) {
402
+ case "password": {
403
+ if (!isRequest) {
404
+ break;
405
+ }
406
+ schemaAttributes[prop] = { type: "string", format: "password", example: "*******" };
407
+ break;
408
+ }
409
+ case "email": {
410
+ schemaAttributes[prop] = { type: "string", format: "email" };
411
+ break;
412
+ }
413
+ case "string":
414
+ case "text":
415
+ case "richtext": {
416
+ schemaAttributes[prop] = { type: "string" };
417
+ break;
418
+ }
419
+ case "timestamp": {
420
+ schemaAttributes[prop] = { type: "string", format: "timestamp", example: Date.now() };
421
+ break;
422
+ }
423
+ case "time": {
424
+ schemaAttributes[prop] = { type: "string", format: "time", example: "12:54.000" };
425
+ break;
426
+ }
427
+ case "date": {
428
+ schemaAttributes[prop] = { type: "string", format: "date" };
429
+ break;
430
+ }
431
+ case "datetime": {
432
+ schemaAttributes[prop] = { type: "string", format: "date-time" };
433
+ break;
434
+ }
435
+ case "boolean": {
436
+ schemaAttributes[prop] = { type: "boolean" };
437
+ break;
438
+ }
439
+ case "enumeration": {
440
+ schemaAttributes[prop] = { type: "string", enum: [...attribute.enum] };
441
+ break;
442
+ }
443
+ case "decimal":
444
+ case "float": {
445
+ schemaAttributes[prop] = { type: "number", format: "float" };
446
+ break;
447
+ }
448
+ case "integer": {
449
+ schemaAttributes[prop] = { type: "integer" };
450
+ break;
451
+ }
452
+ case "biginteger": {
453
+ schemaAttributes[prop] = { type: "string", pattern: "^\\d*$", example: "123456789" };
454
+ break;
455
+ }
456
+ case "json":
457
+ case "blocks": {
458
+ schemaAttributes[prop] = {};
459
+ break;
460
+ }
461
+ case "uid": {
462
+ schemaAttributes[prop] = { type: "string" };
463
+ break;
464
+ }
465
+ case "component": {
466
+ const componentAttributes = strapi.components[attribute.component].attributes;
467
+ const rawComponentSchema = {
468
+ type: "object",
469
+ properties: {
470
+ ...isRequest ? {} : { id: { type: "number" } },
471
+ ...cleanSchemaAttributes(componentAttributes, {
472
+ typeMap,
473
+ isRequest,
474
+ didAddStrapiComponentsToSchemas
475
+ })
476
+ }
477
+ };
478
+ const refComponentSchema = {
479
+ $ref: `#/components/schemas/${pascalCase(attribute.component)}Component`
480
+ };
481
+ const componentExists = didAddStrapiComponentsToSchemas(
482
+ `${pascalCase(attribute.component)}Component`,
483
+ rawComponentSchema
484
+ );
485
+ const finalComponentSchema = componentExists ? refComponentSchema : rawComponentSchema;
486
+ if (attribute.repeatable) {
487
+ schemaAttributes[prop] = {
488
+ type: "array",
489
+ items: finalComponentSchema
490
+ };
491
+ } else {
492
+ schemaAttributes[prop] = finalComponentSchema;
493
+ }
494
+ break;
495
+ }
496
+ case "dynamiczone": {
497
+ const components = attribute.components.map((component) => {
498
+ const componentAttributes = strapi.components[component].attributes;
499
+ const rawComponentSchema = {
500
+ type: "object",
501
+ properties: {
502
+ ...isRequest ? {} : { id: { type: "number" } },
503
+ __component: { type: "string" },
504
+ ...cleanSchemaAttributes(componentAttributes, {
505
+ typeMap,
506
+ isRequest,
507
+ didAddStrapiComponentsToSchemas
508
+ })
509
+ }
510
+ };
511
+ const refComponentSchema = {
512
+ $ref: `#/components/schemas/${pascalCase(component)}Component`
513
+ };
514
+ const componentExists = didAddStrapiComponentsToSchemas(
515
+ `${pascalCase(component)}Component`,
516
+ rawComponentSchema
517
+ );
518
+ const finalComponentSchema = componentExists ? refComponentSchema : rawComponentSchema;
519
+ return finalComponentSchema;
520
+ });
521
+ schemaAttributes[prop] = {
522
+ type: "array",
523
+ items: {
524
+ anyOf: components
525
+ }
526
+ };
527
+ break;
528
+ }
529
+ case "media": {
530
+ const imageAttributes = strapi.contentType("plugin::upload.file").attributes;
531
+ const isListOfEntities = attribute.multiple ?? false;
532
+ if (isRequest) {
533
+ const oneOfType = {
534
+ oneOf: [{ type: "integer" }, { type: "string" }],
535
+ example: "string or id"
536
+ };
537
+ schemaAttributes[prop] = isListOfEntities ? { type: "array", items: oneOfType } : oneOfType;
538
+ break;
539
+ }
540
+ schemaAttributes[prop] = getSchemaData(
541
+ isListOfEntities,
542
+ cleanSchemaAttributes(imageAttributes, { typeMap, didAddStrapiComponentsToSchemas })
543
+ );
544
+ break;
545
+ }
546
+ case "relation": {
547
+ const isListOfEntities = attribute.relation.includes("ToMany");
548
+ if (isRequest) {
549
+ const oneOfType = {
550
+ oneOf: [{ type: "integer" }, { type: "string" }],
551
+ example: "string or id"
552
+ };
553
+ schemaAttributes[prop] = isListOfEntities ? { type: "array", items: oneOfType } : oneOfType;
554
+ break;
555
+ }
556
+ if (!("target" in attribute) || !attribute.target || typeMap.has(attribute.target)) {
557
+ schemaAttributes[prop] = getSchemaData(isListOfEntities, {});
558
+ break;
559
+ }
560
+ typeMap.set(attribute.target, true);
561
+ const targetAttributes = strapi.contentType(attribute.target).attributes;
562
+ schemaAttributes[prop] = getSchemaData(
563
+ isListOfEntities,
564
+ cleanSchemaAttributes(targetAttributes, {
565
+ typeMap,
566
+ isRequest,
567
+ didAddStrapiComponentsToSchemas
568
+ })
569
+ );
570
+ break;
571
+ }
572
+ default: {
573
+ throw new Error(`Invalid type ${attribute.type} while generating open api schema.`);
574
+ }
575
+ }
576
+ }
577
+ return schemaAttributes;
578
+ };
579
+ const getRequiredAttributes = (allAttributes) => {
580
+ const requiredAttributes = [];
581
+ for (const key in allAttributes) {
582
+ if (allAttributes[key].required) {
583
+ requiredAttributes.push(key);
584
+ }
585
+ }
586
+ return requiredAttributes;
587
+ };
588
+ const getAllSchemasForContentType = ({ routeInfo, attributes, uniqueName }) => {
589
+ let strapiComponentSchemas = {};
590
+ const schemas = {};
591
+ const typeName = pascalCase(uniqueName);
592
+ const didAddStrapiComponentsToSchemas = (schemaName, schema) => {
593
+ if (!Object.keys(schema) || !Object.keys(schema.properties))
594
+ return false;
595
+ strapiComponentSchemas = {
596
+ ...strapiComponentSchemas,
597
+ [schemaName]: schema
598
+ };
599
+ return true;
600
+ };
601
+ const routeMethods = routeInfo.routes.map((route) => route.method);
602
+ const attributesToOmit = [
603
+ "createdAt",
604
+ "updatedAt",
605
+ "publishedAt",
606
+ "publishedBy",
607
+ "updatedBy",
608
+ "createdBy"
609
+ ];
610
+ const attributesForRequest = _.omit(attributes, attributesToOmit);
611
+ const requiredRequestAttributes = getRequiredAttributes(attributesForRequest);
612
+ if (routeMethods.includes("POST") || routeMethods.includes("PUT")) {
613
+ Object.assign(schemas, {
614
+ [`${typeName}Request`]: {
615
+ type: "object",
616
+ required: ["data"],
617
+ properties: {
618
+ data: {
619
+ ...requiredRequestAttributes.length && { required: requiredRequestAttributes },
620
+ type: "object",
621
+ properties: cleanSchemaAttributes(attributesForRequest, {
622
+ isRequest: true,
623
+ didAddStrapiComponentsToSchemas
624
+ })
625
+ }
626
+ }
627
+ }
628
+ });
629
+ }
630
+ const hasListOfEntities = routeInfo.routes.filter(
631
+ (route) => hasFindMethod(route.handler)
632
+ ).length;
633
+ if (hasListOfEntities) {
634
+ Object.assign(schemas, {
635
+ [`${typeName}ListResponse`]: {
636
+ type: "object",
637
+ properties: {
638
+ data: {
639
+ type: "array",
640
+ items: {
641
+ $ref: `#/components/schemas/${typeName}`
642
+ }
643
+ },
644
+ meta: {
645
+ type: "object",
646
+ properties: {
647
+ pagination: {
648
+ type: "object",
649
+ properties: {
650
+ page: { type: "integer" },
651
+ pageSize: { type: "integer", minimum: 25 },
652
+ pageCount: { type: "integer", maximum: 1 },
653
+ total: { type: "integer" }
654
+ }
655
+ }
656
+ }
657
+ }
658
+ }
659
+ }
660
+ });
661
+ }
662
+ const requiredAttributes = getRequiredAttributes(attributes);
663
+ Object.assign(schemas, {
664
+ [`${typeName}`]: {
665
+ type: "object",
666
+ ...requiredAttributes.length && { required: requiredAttributes },
667
+ properties: {
668
+ id: { type: "number" },
669
+ documentId: { type: "string" },
670
+ ...cleanSchemaAttributes(attributes, { didAddStrapiComponentsToSchemas })
671
+ }
672
+ },
673
+ [`${typeName}Response`]: {
674
+ type: "object",
675
+ properties: {
676
+ data: {
677
+ $ref: `#/components/schemas/${typeName}`
678
+ },
679
+ meta: { type: "object" }
680
+ }
681
+ }
682
+ });
683
+ return { ...schemas, ...strapiComponentSchemas };
684
+ };
685
+ const buildComponentSchema = (api) => {
686
+ return loopContentTypeNames(api, getAllSchemasForContentType);
687
+ };
688
+ const getPluginsThatNeedDocumentation = (config2) => {
689
+ const defaultPlugins = ["upload", "users-permissions"];
690
+ const userPluginsConfig = config2["x-strapi-config"].plugins;
691
+ if (userPluginsConfig === null) {
692
+ return defaultPlugins;
693
+ }
694
+ if (userPluginsConfig.length) {
695
+ return userPluginsConfig;
696
+ }
697
+ return [];
698
+ };
699
+ const createService$1 = ({ strapi: strapi2 }) => {
700
+ const config2 = strapi2.config.get("plugin::documentation");
701
+ const pluginsThatNeedDocumentation = getPluginsThatNeedDocumentation(config2);
702
+ const overrideService = getService("override");
703
+ return {
704
+ getDocumentationVersion() {
705
+ return config2.info.version;
706
+ },
707
+ getFullDocumentationPath() {
708
+ return path.join(strapi2.dirs.app.extensions, "documentation", "documentation");
709
+ },
710
+ getDocumentationVersions() {
711
+ return fs.readdirSync(this.getFullDocumentationPath()).map((version) => {
712
+ try {
713
+ const filePath = path.resolve(
714
+ this.getFullDocumentationPath(),
715
+ version,
716
+ "full_documentation.json"
717
+ );
718
+ const doc = JSON.parse(fs.readFileSync(filePath).toString());
719
+ const generatedDate = doc.info["x-generation-date"];
720
+ return { version, generatedDate, url: "" };
721
+ } catch (err) {
722
+ return null;
723
+ }
724
+ }).filter((x) => x);
725
+ },
726
+ /**
727
+ * Returns settings stored in core-store
728
+ */
729
+ async getDocumentationAccess() {
730
+ const { restrictedAccess } = await strapi2.store({
731
+ environment: "",
732
+ type: "plugin",
733
+ name: "documentation",
734
+ key: "config"
735
+ }).get();
736
+ return { restrictedAccess };
737
+ },
738
+ getApiDocumentationPath(api) {
739
+ if (api.getter === "plugin") {
740
+ return path.join(strapi2.dirs.app.extensions, api.name, "documentation");
741
+ }
742
+ return path.join(strapi2.dirs.app.api, api.name, "documentation");
743
+ },
744
+ async deleteDocumentation(version) {
745
+ const apis = this.getPluginAndApiInfo();
746
+ for (const api of apis) {
747
+ await fs.remove(path.join(this.getApiDocumentationPath(api), version));
748
+ }
749
+ await fs.remove(path.join(this.getFullDocumentationPath(), version));
750
+ },
751
+ getPluginAndApiInfo() {
752
+ const pluginsToDocument = pluginsThatNeedDocumentation.map((plugin) => {
753
+ return {
754
+ name: plugin,
755
+ getter: "plugin",
756
+ ctNames: Object.keys(strapi2.plugin(plugin).contentTypes)
757
+ };
758
+ });
759
+ const apisToDocument = Object.keys(strapi2.api).map((api) => {
760
+ return {
761
+ name: api,
762
+ getter: "api",
763
+ ctNames: Object.keys(strapi2.api[api].contentTypes)
764
+ };
765
+ });
766
+ return [...apisToDocument, ...pluginsToDocument];
767
+ },
768
+ /**
769
+ * @description - Creates the Swagger json files
770
+ */
771
+ async generateFullDoc(versionOpt) {
772
+ const version = versionOpt ?? this.getDocumentationVersion();
773
+ const apis = this.getPluginAndApiInfo();
774
+ const apisThatNeedGeneratedDocumentation = apis.filter(
775
+ ({ name }) => !overrideService.isEnabled(name)
776
+ );
777
+ const generatedDocumentation = await produce(config2, async (draft) => {
778
+ if (draft.servers?.length === 0) {
779
+ const serverUrl = strapi2.config.get("server.absoluteUrl");
780
+ const apiPath = strapi2.config.get("api.rest.prefix");
781
+ draft.servers = [
782
+ {
783
+ url: `${serverUrl}${apiPath}`,
784
+ description: "Development server"
785
+ }
786
+ ];
787
+ }
788
+ if (!draft.components) {
789
+ draft.components = {};
790
+ }
791
+ draft.info["x-generation-date"] = (/* @__PURE__ */ new Date()).toISOString();
792
+ draft["x-strapi-config"].plugins = pluginsThatNeedDocumentation;
793
+ delete draft["x-strapi-config"].mutateDocumentation;
794
+ for (const api of apisThatNeedGeneratedDocumentation) {
795
+ const newApiPath = buildApiEndpointPath(api);
796
+ const generatedSchemas = buildComponentSchema(api);
797
+ if (generatedSchemas) {
798
+ draft.components.schemas = { ...draft.components.schemas, ...generatedSchemas };
799
+ }
800
+ if (newApiPath) {
801
+ draft.paths = { ...draft.paths, ...newApiPath };
802
+ }
803
+ }
804
+ if (overrideService.registeredOverrides.length > 0) {
805
+ overrideService.registeredOverrides.forEach((override) => {
806
+ if (!override?.info?.version || override.info.version === version) {
807
+ if (override.tags) {
808
+ draft.tags = draft.tags || [];
809
+ draft.tags.push(...override.tags);
810
+ }
811
+ if (override.paths) {
812
+ draft.paths = { ...draft.paths, ...override.paths };
813
+ }
814
+ if (override.components) {
815
+ const keys = Object.keys(override.components);
816
+ keys.forEach((overrideKey) => {
817
+ draft.components = draft.components || {};
818
+ const overrideValue = override.components?.[overrideKey];
819
+ const originalValue = draft.components?.[overrideKey];
820
+ Object.assign(draft.components, {
821
+ [overrideKey]: {
822
+ ...originalValue,
823
+ ...overrideValue
824
+ }
825
+ });
826
+ });
827
+ }
828
+ }
829
+ });
830
+ }
831
+ });
832
+ const userMutatesDocumentation = config2["x-strapi-config"].mutateDocumentation;
833
+ const finalDocumentation = userMutatesDocumentation ? produce(generatedDocumentation, userMutatesDocumentation) : generatedDocumentation;
834
+ const fullDocJsonPath = path.join(
835
+ this.getFullDocumentationPath(),
836
+ version,
837
+ "full_documentation.json"
838
+ );
839
+ await fs.ensureFile(fullDocJsonPath);
840
+ await fs.writeJson(fullDocJsonPath, finalDocumentation, { spaces: 2 });
841
+ }
842
+ };
843
+ };
844
+ const createService = ({ strapi: strapi2 }) => {
845
+ const registeredOverrides = [];
846
+ const excludedFromGeneration = [];
847
+ return {
848
+ registeredOverrides,
849
+ excludedFromGeneration,
850
+ /**
851
+ *
852
+ * @param {(string | string[])} api - The name of the api or and array of apis to exclude from generation
853
+ */
854
+ excludeFromGeneration(api) {
855
+ if (Array.isArray(api)) {
856
+ excludedFromGeneration.push(...api);
857
+ return;
858
+ }
859
+ excludedFromGeneration.push(api);
860
+ },
861
+ isEnabled(name) {
862
+ return excludedFromGeneration.includes(name);
863
+ },
864
+ registerOverride(override, opts) {
865
+ const { pluginOrigin, excludeFromGeneration = [] } = opts ?? {};
866
+ const pluginsThatNeedDocumentation = getPluginsThatNeedDocumentation(
867
+ strapi2.config.get("plugin::documentation")
868
+ );
869
+ if (pluginOrigin && !pluginsThatNeedDocumentation.includes(pluginOrigin))
870
+ return;
871
+ if (excludeFromGeneration.length) {
872
+ this.excludeFromGeneration(excludeFromGeneration);
873
+ }
874
+ let overrideToRegister = override;
875
+ if (typeof override === "string") {
876
+ overrideToRegister = require("yaml").parse(overrideToRegister);
877
+ }
878
+ registeredOverrides.push(overrideToRegister);
879
+ }
880
+ };
881
+ };
882
+ const services = {
883
+ documentation: createService$1,
884
+ override: createService
885
+ };
886
+ const restrictAccess = async (ctx, next) => {
887
+ const pluginStore = strapi.store({ type: "plugin", name: "documentation" });
888
+ const config2 = await pluginStore.get({ key: "config" });
889
+ if (!config2.restrictedAccess) {
890
+ return next();
891
+ }
892
+ if (!ctx.session || !ctx.session.documentation || !ctx.session.documentation.logged) {
893
+ const querystring = ctx.querystring ? `?${ctx.querystring}` : "";
894
+ return ctx.redirect(`${strapi.config.server.url}/documentation/login${querystring}`);
895
+ }
896
+ return next();
897
+ };
898
+ const routes = [
899
+ {
900
+ method: "GET",
901
+ path: "/",
902
+ handler: "documentation.index",
903
+ config: {
904
+ auth: false,
905
+ middlewares: [restrictAccess]
906
+ }
907
+ },
908
+ {
909
+ method: "GET",
910
+ path: "/v:major(\\d+).:minor(\\d+).:patch(\\d+)",
911
+ handler: "documentation.index",
912
+ config: {
913
+ auth: false,
914
+ middlewares: [restrictAccess]
915
+ }
916
+ },
917
+ {
918
+ method: "GET",
919
+ path: "/login",
920
+ handler: "documentation.loginView",
921
+ config: {
922
+ auth: false
923
+ }
924
+ },
925
+ {
926
+ method: "POST",
927
+ path: "/login",
928
+ handler: "documentation.login",
929
+ config: {
930
+ auth: false
931
+ }
932
+ },
933
+ {
934
+ method: "GET",
935
+ path: "/getInfos",
936
+ handler: "documentation.getInfos",
937
+ config: {
938
+ policies: [
939
+ { name: "admin::hasPermissions", config: { actions: ["plugin::documentation.read"] } }
940
+ ]
941
+ }
942
+ },
943
+ {
944
+ method: "POST",
945
+ path: "/regenerateDoc",
946
+ handler: "documentation.regenerateDoc",
947
+ config: {
948
+ policies: [
949
+ {
950
+ name: "admin::hasPermissions",
951
+ config: { actions: ["plugin::documentation.settings.regenerate"] }
952
+ }
953
+ ]
954
+ }
955
+ },
956
+ {
957
+ method: "PUT",
958
+ path: "/updateSettings",
959
+ handler: "documentation.updateSettings",
960
+ config: {
961
+ policies: [
962
+ {
963
+ name: "admin::hasPermissions",
964
+ config: { actions: ["plugin::documentation.settings.update"] }
965
+ }
966
+ ]
967
+ }
968
+ },
969
+ {
970
+ method: "DELETE",
971
+ path: "/deleteDoc/:version",
972
+ handler: "documentation.deleteDoc",
973
+ config: {
974
+ policies: []
975
+ }
976
+ }
977
+ ];
978
+ const validation = {
979
+ validatSettings: validateYupSchema(
980
+ yup.object().shape({
981
+ restrictedAccess: yup.boolean(),
982
+ password: yup.string().min(8).matches(/[a-z]/, "${path} must contain at least one lowercase character").matches(/[A-Z]/, "${path} must contain at least one uppercase character").matches(/\d/, "${path} must contain at least one number").when("restrictedAccess", (value, initSchema) => {
983
+ return value ? initSchema.required("password is required") : initSchema;
984
+ })
985
+ })
986
+ )
987
+ };
988
+ const documentation = {
989
+ async getInfos(ctx) {
990
+ try {
991
+ const docService = getService("documentation");
992
+ const docVersions = docService.getDocumentationVersions();
993
+ const documentationAccess = await docService.getDocumentationAccess();
994
+ ctx.send({
995
+ docVersions,
996
+ currentVersion: docService.getDocumentationVersion(),
997
+ prefix: "/documentation",
998
+ documentationAccess
999
+ });
1000
+ } catch (err) {
1001
+ strapi.log.error(err);
1002
+ ctx.badRequest();
1003
+ }
1004
+ },
1005
+ async index(ctx, next) {
1006
+ try {
1007
+ const { major, minor, patch } = ctx.params;
1008
+ const version = major && minor && patch ? `${major}.${minor}.${patch}` : getService("documentation").getDocumentationVersion();
1009
+ const openAPISpecsPath = path.join(
1010
+ strapi.dirs.app.extensions,
1011
+ "documentation",
1012
+ "documentation",
1013
+ version,
1014
+ "full_documentation.json"
1015
+ );
1016
+ try {
1017
+ const documentation2 = fs.readFileSync(openAPISpecsPath, "utf8");
1018
+ const layout = (await import("../_chunks/index-MKWIGajW.mjs")).default;
1019
+ const filledLayout = _.template(layout)({
1020
+ backendUrl: strapi.config.server.url,
1021
+ spec: JSON.stringify(JSON.parse(documentation2))
1022
+ });
1023
+ try {
1024
+ const layoutPath = path.resolve(
1025
+ strapi.dirs.app.extensions,
1026
+ "documentation",
1027
+ "public",
1028
+ "index.html"
1029
+ );
1030
+ await fs.ensureFile(layoutPath);
1031
+ await fs.writeFile(layoutPath, filledLayout);
1032
+ ctx.url = path.basename(`${ctx.url}/index.html`);
1033
+ try {
1034
+ const staticFolder = path.resolve(
1035
+ strapi.dirs.app.extensions,
1036
+ "documentation",
1037
+ "public"
1038
+ );
1039
+ return koaStatic(staticFolder)(ctx, next);
1040
+ } catch (e) {
1041
+ strapi.log.error(e);
1042
+ }
1043
+ } catch (e) {
1044
+ strapi.log.error(e);
1045
+ }
1046
+ } catch (e) {
1047
+ strapi.log.error(e);
1048
+ }
1049
+ } catch (e) {
1050
+ strapi.log.error(e);
1051
+ }
1052
+ },
1053
+ async loginView(ctx, next) {
1054
+ const cheerio = require("cheerio");
1055
+ const { error } = ctx.query;
1056
+ try {
1057
+ const layout = (await import("../_chunks/login-slUa679p.mjs")).default;
1058
+ const filledLayout = _.template(layout.toString())({
1059
+ actionUrl: `${strapi.config.server.url}/documentation/login`
1060
+ });
1061
+ const $ = cheerio.load(filledLayout);
1062
+ $(".error").text(_.isEmpty(error) ? "" : "Wrong password...");
1063
+ try {
1064
+ const layoutPath = path.resolve(
1065
+ strapi.dirs.app.extensions,
1066
+ "documentation",
1067
+ "public",
1068
+ "login.html"
1069
+ );
1070
+ await fs.ensureFile(layoutPath);
1071
+ await fs.writeFile(layoutPath, $.html());
1072
+ ctx.url = path.basename(`${ctx.url}/login.html`);
1073
+ try {
1074
+ const staticFolder = path.resolve(strapi.dirs.app.extensions, "documentation", "public");
1075
+ return koaStatic(staticFolder)(ctx, next);
1076
+ } catch (e) {
1077
+ strapi.log.error(e);
1078
+ }
1079
+ } catch (e) {
1080
+ strapi.log.error(e);
1081
+ }
1082
+ } catch (e) {
1083
+ strapi.log.error(e);
1084
+ }
1085
+ },
1086
+ async login(ctx) {
1087
+ const {
1088
+ body: { password }
1089
+ } = ctx.request;
1090
+ const { password: hash } = await strapi.store({ type: "plugin", name: "documentation", key: "config" }).get();
1091
+ const isValid = await bcrypt.compare(password, hash);
1092
+ let querystring = "?error=password";
1093
+ if (isValid && ctx.session) {
1094
+ ctx.session.documentation = {
1095
+ logged: true
1096
+ };
1097
+ querystring = "";
1098
+ }
1099
+ ctx.redirect(`${strapi.config.server.url}/documentation${querystring}`);
1100
+ },
1101
+ async regenerateDoc(ctx) {
1102
+ const { version } = ctx.request.body;
1103
+ const service = getService("documentation");
1104
+ const documentationVersions = service.getDocumentationVersions().map((el) => el.version);
1105
+ if (_.isEmpty(version)) {
1106
+ return ctx.badRequest("Please provide a version.");
1107
+ }
1108
+ if (!documentationVersions.includes(version)) {
1109
+ return ctx.badRequest("The version you are trying to generate does not exist.");
1110
+ }
1111
+ try {
1112
+ strapi.reload.isWatching = false;
1113
+ await service.generateFullDoc(version);
1114
+ ctx.send({ ok: true });
1115
+ } finally {
1116
+ strapi.reload.isWatching = true;
1117
+ }
1118
+ },
1119
+ async deleteDoc(ctx) {
1120
+ const { version } = ctx.params;
1121
+ const service = getService("documentation");
1122
+ const documentationVersions = service.getDocumentationVersions().map((el) => el.version);
1123
+ if (_.isEmpty(version)) {
1124
+ return ctx.badRequest("Please provide a version.");
1125
+ }
1126
+ if (!documentationVersions.includes(version)) {
1127
+ return ctx.badRequest("The version you are trying to delete does not exist.");
1128
+ }
1129
+ try {
1130
+ strapi.reload.isWatching = false;
1131
+ await service.deleteDocumentation(version);
1132
+ ctx.send({ ok: true });
1133
+ } finally {
1134
+ strapi.reload.isWatching = true;
1135
+ }
1136
+ },
1137
+ async updateSettings(ctx) {
1138
+ const pluginStore = strapi.store({ type: "plugin", name: "documentation" });
1139
+ const data = await validation.validatSettings(ctx.request.body);
1140
+ const config2 = {
1141
+ restrictedAccess: Boolean(data.restrictedAccess)
1142
+ };
1143
+ if (data.password) {
1144
+ config2.password = await bcrypt.hash(data.password, 10);
1145
+ }
1146
+ await pluginStore.set({ key: "config", value: config2 });
1147
+ return ctx.send({ ok: true });
1148
+ }
1149
+ };
1150
+ const controllers = {
1151
+ documentation
1152
+ };
1153
+ const defaultConfig = {
1154
+ openapi: "3.0.0",
1155
+ info: {
1156
+ version: "1.0.0",
1157
+ title: "DOCUMENTATION",
1158
+ description: "",
1159
+ termsOfService: "YOUR_TERMS_OF_SERVICE_URL",
1160
+ contact: {
1161
+ name: "TEAM",
1162
+ email: "contact-email@something.io",
1163
+ url: "mywebsite.io"
1164
+ },
1165
+ license: {
1166
+ name: "Apache 2.0",
1167
+ url: "https://www.apache.org/licenses/LICENSE-2.0.html"
1168
+ }
1169
+ },
1170
+ "x-strapi-config": {
1171
+ plugins: null,
1172
+ mutateDocumentation: null
1173
+ },
1174
+ servers: [],
1175
+ externalDocs: {
1176
+ description: "Find out more",
1177
+ url: "https://docs.strapi.io/developer-docs/latest/getting-started/introduction.html"
1178
+ },
1179
+ security: [
1180
+ {
1181
+ bearerAuth: []
1182
+ }
1183
+ ],
1184
+ paths: {},
1185
+ components: {
1186
+ securitySchemes: {
1187
+ bearerAuth: {
1188
+ type: "http",
1189
+ scheme: "bearer",
1190
+ bearerFormat: "JWT"
1191
+ }
1192
+ },
1193
+ schemas: {
1194
+ Error: {
1195
+ type: "object",
1196
+ required: ["error"],
1197
+ properties: {
1198
+ data: {
1199
+ nullable: true,
1200
+ oneOf: [{ type: "object" }, { type: "array", items: { type: "object" } }]
1201
+ },
1202
+ error: {
1203
+ type: "object",
1204
+ properties: {
1205
+ status: {
1206
+ type: "integer"
1207
+ },
1208
+ name: {
1209
+ type: "string"
1210
+ },
1211
+ message: {
1212
+ type: "string"
1213
+ },
1214
+ details: {
1215
+ type: "object"
1216
+ }
1217
+ }
1218
+ }
1219
+ }
1220
+ }
1221
+ }
1222
+ }
1223
+ };
1224
+ const config = {
1225
+ default: defaultConfig
1226
+ };
1227
+ const index = {
1228
+ bootstrap,
1229
+ config,
1230
+ routes,
1231
+ controllers,
1232
+ register,
1233
+ services
1234
+ };
1235
+ export {
1236
+ index as default
1237
+ };
1238
+ //# sourceMappingURL=index.mjs.map