@strapi/upload 5.33.4 → 5.35.0

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 (183) hide show
  1. package/dist/admin/components/EditAssetDialog/EditAssetContent.js +32 -3
  2. package/dist/admin/components/EditAssetDialog/EditAssetContent.js.map +1 -1
  3. package/dist/admin/components/EditAssetDialog/EditAssetContent.mjs +32 -3
  4. package/dist/admin/components/EditAssetDialog/EditAssetContent.mjs.map +1 -1
  5. package/dist/admin/components/EditAssetDialog/PreviewBox/AssetPreview.js.map +1 -1
  6. package/dist/admin/components/EditAssetDialog/PreviewBox/AssetPreview.mjs.map +1 -1
  7. package/dist/admin/components/EditAssetDialog/PreviewBox/FocalPointActions.js +57 -0
  8. package/dist/admin/components/EditAssetDialog/PreviewBox/FocalPointActions.js.map +1 -0
  9. package/dist/admin/components/EditAssetDialog/PreviewBox/FocalPointActions.mjs +55 -0
  10. package/dist/admin/components/EditAssetDialog/PreviewBox/FocalPointActions.mjs.map +1 -0
  11. package/dist/admin/components/EditAssetDialog/PreviewBox/PreviewBox.js +96 -20
  12. package/dist/admin/components/EditAssetDialog/PreviewBox/PreviewBox.js.map +1 -1
  13. package/dist/admin/components/EditAssetDialog/PreviewBox/PreviewBox.mjs +98 -22
  14. package/dist/admin/components/EditAssetDialog/PreviewBox/PreviewBox.mjs.map +1 -1
  15. package/dist/admin/components/EditAssetDialog/PreviewBox/PreviewComponents.js +47 -0
  16. package/dist/admin/components/EditAssetDialog/PreviewBox/PreviewComponents.js.map +1 -1
  17. package/dist/admin/components/EditAssetDialog/PreviewBox/PreviewComponents.mjs +44 -1
  18. package/dist/admin/components/EditAssetDialog/PreviewBox/PreviewComponents.mjs.map +1 -1
  19. package/dist/admin/future/App.js +45 -0
  20. package/dist/admin/future/App.js.map +1 -0
  21. package/dist/admin/future/App.mjs +43 -0
  22. package/dist/admin/future/App.mjs.map +1 -0
  23. package/dist/admin/future/pages/AIGenerationPage.js +24 -0
  24. package/dist/admin/future/pages/AIGenerationPage.js.map +1 -0
  25. package/dist/admin/future/pages/AIGenerationPage.mjs +22 -0
  26. package/dist/admin/future/pages/AIGenerationPage.mjs.map +1 -0
  27. package/dist/admin/future/pages/MediaLibraryPage.js +119 -0
  28. package/dist/admin/future/pages/MediaLibraryPage.js.map +1 -0
  29. package/dist/admin/future/pages/MediaLibraryPage.mjs +98 -0
  30. package/dist/admin/future/pages/MediaLibraryPage.mjs.map +1 -0
  31. package/dist/admin/future/services/api.js +28 -0
  32. package/dist/admin/future/services/api.js.map +1 -0
  33. package/dist/admin/future/services/api.mjs +25 -0
  34. package/dist/admin/future/services/api.mjs.map +1 -0
  35. package/dist/admin/future/utils/translations.js +8 -0
  36. package/dist/admin/future/utils/translations.js.map +1 -0
  37. package/dist/admin/future/utils/translations.mjs +6 -0
  38. package/dist/admin/future/utils/translations.mjs.map +1 -0
  39. package/dist/admin/hooks/useAIMetadataJob.js +114 -0
  40. package/dist/admin/hooks/useAIMetadataJob.js.map +1 -0
  41. package/dist/admin/hooks/useAIMetadataJob.mjs +93 -0
  42. package/dist/admin/hooks/useAIMetadataJob.mjs.map +1 -0
  43. package/dist/admin/hooks/useEditAsset.js +1 -0
  44. package/dist/admin/hooks/useEditAsset.js.map +1 -1
  45. package/dist/admin/hooks/useEditAsset.mjs +1 -0
  46. package/dist/admin/hooks/useEditAsset.mjs.map +1 -1
  47. package/dist/admin/index.js +23 -4
  48. package/dist/admin/index.js.map +1 -1
  49. package/dist/admin/index.mjs +24 -5
  50. package/dist/admin/index.mjs.map +1 -1
  51. package/dist/admin/package.json.js +6 -5
  52. package/dist/admin/package.json.js.map +1 -1
  53. package/dist/admin/package.json.mjs +6 -5
  54. package/dist/admin/package.json.mjs.map +1 -1
  55. package/dist/admin/pages/App/ConfigureTheView/ConfigureTheView.js +1 -0
  56. package/dist/admin/pages/App/ConfigureTheView/ConfigureTheView.js.map +1 -1
  57. package/dist/admin/pages/App/ConfigureTheView/ConfigureTheView.mjs +1 -0
  58. package/dist/admin/pages/App/ConfigureTheView/ConfigureTheView.mjs.map +1 -1
  59. package/dist/admin/pages/App/components/Header.js +3 -0
  60. package/dist/admin/pages/App/components/Header.js.map +1 -1
  61. package/dist/admin/pages/App/components/Header.mjs +3 -0
  62. package/dist/admin/pages/App/components/Header.mjs.map +1 -1
  63. package/dist/admin/pages/SettingsPage/SettingsPage.js +252 -67
  64. package/dist/admin/pages/SettingsPage/SettingsPage.js.map +1 -1
  65. package/dist/admin/pages/SettingsPage/SettingsPage.mjs +256 -71
  66. package/dist/admin/pages/SettingsPage/SettingsPage.mjs.map +1 -1
  67. package/dist/admin/src/components/EditAssetDialog/PreviewBox/AssetPreview.d.ts +1 -2
  68. package/dist/admin/src/components/EditAssetDialog/PreviewBox/FocalPointActions.d.ts +7 -0
  69. package/dist/admin/src/components/EditAssetDialog/PreviewBox/PreviewBox.d.ts +6 -2
  70. package/dist/admin/src/components/EditAssetDialog/PreviewBox/PreviewComponents.d.ts +13 -0
  71. package/dist/admin/src/future/App.d.ts +1 -0
  72. package/dist/admin/src/future/pages/AIGenerationPage.d.ts +1 -0
  73. package/dist/admin/src/future/pages/MediaLibraryPage.d.ts +1 -0
  74. package/dist/admin/src/future/services/api.d.ts +6 -0
  75. package/dist/admin/src/future/services/settings.d.ts +2 -0
  76. package/dist/admin/src/future/utils/translations.d.ts +1 -0
  77. package/dist/admin/src/hooks/useAIMetadataJob.d.ts +9 -0
  78. package/dist/admin/translations/de.json.js +44 -1
  79. package/dist/admin/translations/de.json.js.map +1 -1
  80. package/dist/admin/translations/de.json.mjs +44 -1
  81. package/dist/admin/translations/de.json.mjs.map +1 -1
  82. package/dist/admin/translations/en.json.js +17 -0
  83. package/dist/admin/translations/en.json.js.map +1 -1
  84. package/dist/admin/translations/en.json.mjs +17 -0
  85. package/dist/admin/translations/en.json.mjs.map +1 -1
  86. package/dist/server/bootstrap.js +1 -0
  87. package/dist/server/bootstrap.js.map +1 -1
  88. package/dist/server/bootstrap.mjs +1 -0
  89. package/dist/server/bootstrap.mjs.map +1 -1
  90. package/dist/server/content-types/file.js +4 -0
  91. package/dist/server/content-types/file.js.map +1 -1
  92. package/dist/server/content-types/file.mjs +4 -0
  93. package/dist/server/content-types/file.mjs.map +1 -1
  94. package/dist/server/controllers/admin-file.js +86 -0
  95. package/dist/server/controllers/admin-file.js.map +1 -1
  96. package/dist/server/controllers/admin-file.mjs +86 -0
  97. package/dist/server/controllers/admin-file.mjs.map +1 -1
  98. package/dist/server/controllers/admin-upload.js +3 -23
  99. package/dist/server/controllers/admin-upload.js.map +1 -1
  100. package/dist/server/controllers/admin-upload.mjs +3 -23
  101. package/dist/server/controllers/admin-upload.mjs.map +1 -1
  102. package/dist/server/controllers/validation/admin/upload.js +5 -0
  103. package/dist/server/controllers/validation/admin/upload.js.map +1 -1
  104. package/dist/server/controllers/validation/admin/upload.mjs +5 -0
  105. package/dist/server/controllers/validation/admin/upload.mjs.map +1 -1
  106. package/dist/server/controllers/validation/content-api/upload.js +6 -1
  107. package/dist/server/controllers/validation/content-api/upload.js.map +1 -1
  108. package/dist/server/controllers/validation/content-api/upload.mjs +6 -1
  109. package/dist/server/controllers/validation/content-api/upload.mjs.map +1 -1
  110. package/dist/server/models/ai-metadata-job.js +36 -0
  111. package/dist/server/models/ai-metadata-job.js.map +1 -0
  112. package/dist/server/models/ai-metadata-job.mjs +33 -0
  113. package/dist/server/models/ai-metadata-job.mjs.map +1 -0
  114. package/dist/server/register.js +3 -0
  115. package/dist/server/register.js.map +1 -1
  116. package/dist/server/register.mjs +3 -0
  117. package/dist/server/register.mjs.map +1 -1
  118. package/dist/server/routes/admin.js +46 -0
  119. package/dist/server/routes/admin.js.map +1 -1
  120. package/dist/server/routes/admin.mjs +46 -0
  121. package/dist/server/routes/admin.mjs.map +1 -1
  122. package/dist/server/services/ai-metadata-jobs.js +72 -0
  123. package/dist/server/services/ai-metadata-jobs.js.map +1 -0
  124. package/dist/server/services/ai-metadata-jobs.mjs +70 -0
  125. package/dist/server/services/ai-metadata-jobs.mjs.map +1 -0
  126. package/dist/server/services/ai-metadata.js +170 -20
  127. package/dist/server/services/ai-metadata.js.map +1 -1
  128. package/dist/server/services/ai-metadata.mjs +170 -20
  129. package/dist/server/services/ai-metadata.mjs.map +1 -1
  130. package/dist/server/services/index.js +3 -1
  131. package/dist/server/services/index.js.map +1 -1
  132. package/dist/server/services/index.mjs +3 -1
  133. package/dist/server/services/index.mjs.map +1 -1
  134. package/dist/server/services/upload.js +3 -1
  135. package/dist/server/services/upload.js.map +1 -1
  136. package/dist/server/services/upload.mjs +3 -1
  137. package/dist/server/services/upload.mjs.map +1 -1
  138. package/dist/server/src/bootstrap.d.ts.map +1 -1
  139. package/dist/server/src/content-types/file.d.ts +4 -0
  140. package/dist/server/src/content-types/file.d.ts.map +1 -1
  141. package/dist/server/src/content-types/index.d.ts +4 -0
  142. package/dist/server/src/content-types/index.d.ts.map +1 -1
  143. package/dist/server/src/controllers/admin-file.d.ts +3 -0
  144. package/dist/server/src/controllers/admin-file.d.ts.map +1 -1
  145. package/dist/server/src/controllers/admin-upload.d.ts.map +1 -1
  146. package/dist/server/src/controllers/index.d.ts +3 -0
  147. package/dist/server/src/controllers/index.d.ts.map +1 -1
  148. package/dist/server/src/controllers/validation/admin/upload.d.ts +240 -0
  149. package/dist/server/src/controllers/validation/admin/upload.d.ts.map +1 -1
  150. package/dist/server/src/controllers/validation/content-api/upload.d.ts +180 -0
  151. package/dist/server/src/controllers/validation/content-api/upload.d.ts.map +1 -1
  152. package/dist/server/src/index.d.ts +32 -2
  153. package/dist/server/src/index.d.ts.map +1 -1
  154. package/dist/server/src/models/ai-metadata-job.d.ts +5 -0
  155. package/dist/server/src/models/ai-metadata-job.d.ts.map +1 -0
  156. package/dist/server/src/models/index.d.ts +5 -0
  157. package/dist/server/src/models/index.d.ts.map +1 -0
  158. package/dist/server/src/register.d.ts.map +1 -1
  159. package/dist/server/src/routes/admin.d.ts.map +1 -1
  160. package/dist/server/src/services/ai-metadata-jobs.d.ts +14 -0
  161. package/dist/server/src/services/ai-metadata-jobs.d.ts.map +1 -0
  162. package/dist/server/src/services/ai-metadata.d.ts +25 -2
  163. package/dist/server/src/services/ai-metadata.d.ts.map +1 -1
  164. package/dist/server/src/services/index.d.ts +25 -2
  165. package/dist/server/src/services/index.d.ts.map +1 -1
  166. package/dist/server/src/services/upload.d.ts +1 -1
  167. package/dist/server/src/services/upload.d.ts.map +1 -1
  168. package/dist/server/src/types.d.ts +6 -0
  169. package/dist/server/src/types.d.ts.map +1 -1
  170. package/dist/server/src/utils/images.d.ts +7 -0
  171. package/dist/server/src/utils/images.d.ts.map +1 -0
  172. package/dist/server/src/utils/index.d.ts +2 -0
  173. package/dist/server/src/utils/index.d.ts.map +1 -1
  174. package/dist/server/utils/images.js +35 -0
  175. package/dist/server/utils/images.js.map +1 -0
  176. package/dist/server/utils/images.mjs +33 -0
  177. package/dist/server/utils/images.mjs.map +1 -0
  178. package/dist/server/utils/index.js.map +1 -1
  179. package/dist/server/utils/index.mjs.map +1 -1
  180. package/dist/shared/contracts/ai-metadata-jobs.d.ts +53 -0
  181. package/dist/shared/contracts/ai-metadata-jobs.d.ts.map +1 -0
  182. package/dist/shared/contracts/files.d.ts +39 -0
  183. package/package.json +6 -5
@@ -54,6 +54,92 @@ var adminFile = {
54
54
  index.getService('upload').remove(file)
55
55
  ]);
56
56
  ctx.body = body;
57
+ },
58
+ async getAIMetadataCount (ctx) {
59
+ const { userAbility } = ctx.state;
60
+ const pm = strapi.service('admin::permission').createPermissionsManager({
61
+ ability: userAbility,
62
+ action: constants.ACTIONS.read,
63
+ model: constants.FILE_MODEL_UID
64
+ });
65
+ if (!pm.isAllowed) {
66
+ return ctx.forbidden();
67
+ }
68
+ const aiMetadataService = index.getService('aiMetadata');
69
+ // Check if AI service is enabled
70
+ if (!await aiMetadataService.isEnabled()) {
71
+ return ctx.badRequest('AI Metadata service is not enabled');
72
+ }
73
+ try {
74
+ const { imagesWithoutMetadataCount, totalImages } = await aiMetadataService.countImagesWithoutMetadata();
75
+ ctx.body = {
76
+ imagesWithoutMetadataCount,
77
+ totalImages
78
+ };
79
+ } catch (error) {
80
+ const message = error instanceof Error ? error.message : 'Failed to get AI metadata count';
81
+ strapi.log.error('Failed to get AI metadata count', {
82
+ message,
83
+ error
84
+ });
85
+ ctx.badRequest(message);
86
+ }
87
+ },
88
+ async generateAIMetadata (ctx) {
89
+ const { userAbility } = ctx.state;
90
+ const pm = strapi.service('admin::permission').createPermissionsManager({
91
+ ability: userAbility,
92
+ action: constants.ACTIONS.update,
93
+ model: constants.FILE_MODEL_UID
94
+ });
95
+ if (!pm.isAllowed) {
96
+ return ctx.forbidden();
97
+ }
98
+ const aiMetadataService = index.getService('aiMetadata');
99
+ // Check if AI service is enabled
100
+ if (!await aiMetadataService.isEnabled()) {
101
+ return ctx.badRequest('AI Metadata service is not enabled');
102
+ }
103
+ try {
104
+ // Get count first to check if there are images to process
105
+ const result = await aiMetadataService.countImagesWithoutMetadata();
106
+ if (result.imagesWithoutMetadataCount === 0) {
107
+ ctx.body = {
108
+ count: 0,
109
+ message: 'No images without metadata found'
110
+ };
111
+ return;
112
+ }
113
+ // Create job
114
+ const jobService = index.getService('aiMetadataJobs');
115
+ const jobId = await jobService.createJob();
116
+ // Start async processing (fire and forget)
117
+ aiMetadataService.processExistingFiles(jobId, ctx.state.user).catch((err)=>{
118
+ strapi.log.error('AI metadata job failed:', err);
119
+ });
120
+ // Return immediately with job ID
121
+ ctx.body = {
122
+ jobId,
123
+ status: 'pending'
124
+ };
125
+ } catch (error) {
126
+ const message = error instanceof Error ? error.message : 'Failed to generate AI metadata';
127
+ const cause = error instanceof Error && error.cause ? String(error.cause) : undefined;
128
+ strapi.log.error('AI metadata generation failed in controller', {
129
+ message,
130
+ cause,
131
+ error
132
+ });
133
+ ctx.badRequest(cause ? `${message}: ${cause}` : message);
134
+ }
135
+ },
136
+ async getLatestAIMetadataJob (ctx) {
137
+ const jobService = index.getService('aiMetadataJobs');
138
+ const job = await jobService.getLatestActiveJob();
139
+ if (!job) {
140
+ return ctx.notFound('No active job found');
141
+ }
142
+ ctx.body = job;
57
143
  }
58
144
  };
59
145
 
@@ -1 +1 @@
1
- {"version":3,"file":"admin-file.js","sources":["../../../server/src/controllers/admin-file.ts"],"sourcesContent":["import { merge } from 'lodash/fp';\nimport { async } from '@strapi/utils';\n\nimport type { Context } from 'koa';\n\nimport { getService } from '../utils';\nimport { ACTIONS, FILE_MODEL_UID } from '../constants';\nimport { findEntityAndCheckPermissions } from './utils/find-entity-and-check-permissions';\n\nexport default {\n async find(ctx: Context) {\n const {\n state: { userAbility },\n } = ctx;\n\n const defaultQuery = { populate: { folder: true } };\n\n const pm = strapi.service('admin::permission').createPermissionsManager({\n ability: userAbility,\n action: ACTIONS.read,\n model: FILE_MODEL_UID,\n });\n\n if (!pm.isAllowed) {\n return ctx.forbidden();\n }\n\n // validate the incoming user query params\n await pm.validateQuery(ctx.query);\n\n const query = await async.pipe(\n // Start by sanitizing the incoming query\n (q) => pm.sanitizeQuery(q),\n // Add the default query which should not be validated or sanitized\n (q) => merge(defaultQuery, q),\n // Add the dynamic filters based on permissions' conditions\n (q) => pm.addPermissionsQueryTo(q)\n )(ctx.query);\n\n const { results: files, pagination } = await getService('upload').findPage(query);\n\n // Sign file urls for private providers\n const signedFiles = await async.map(files, getService('file').signFileUrls);\n\n const sanitizedFiles = await pm.sanitizeOutput(signedFiles);\n\n return { results: sanitizedFiles, pagination };\n },\n\n async findOne(ctx: Context) {\n const {\n state: { userAbility },\n params: { id },\n } = ctx;\n\n const { pm, file } = await findEntityAndCheckPermissions(\n userAbility,\n ACTIONS.read,\n FILE_MODEL_UID,\n id\n );\n\n const signedFile = await getService('file').signFileUrls(file);\n ctx.body = await pm.sanitizeOutput(signedFile);\n },\n\n async destroy(ctx: Context) {\n const { id } = ctx.params;\n const { userAbility } = ctx.state;\n\n const { pm, file } = await findEntityAndCheckPermissions(\n userAbility,\n ACTIONS.update,\n FILE_MODEL_UID,\n id\n );\n\n const [body] = await Promise.all([\n pm.sanitizeOutput(file, { action: ACTIONS.read }),\n getService('upload').remove(file),\n ]);\n\n ctx.body = body;\n },\n};\n"],"names":["find","ctx","state","userAbility","defaultQuery","populate","folder","pm","strapi","service","createPermissionsManager","ability","action","ACTIONS","read","model","FILE_MODEL_UID","isAllowed","forbidden","validateQuery","query","async","pipe","q","sanitizeQuery","merge","addPermissionsQueryTo","results","files","pagination","getService","findPage","signedFiles","map","signFileUrls","sanitizedFiles","sanitizeOutput","findOne","params","id","file","findEntityAndCheckPermissions","signedFile","body","destroy","update","Promise","all","remove"],"mappings":"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"}
1
+ {"version":3,"file":"admin-file.js","sources":["../../../server/src/controllers/admin-file.ts"],"sourcesContent":["import { merge } from 'lodash/fp';\nimport { async } from '@strapi/utils';\n\nimport type { Context } from 'koa';\n\nimport { getService } from '../utils';\nimport { ACTIONS, FILE_MODEL_UID } from '../constants';\nimport { findEntityAndCheckPermissions } from './utils/find-entity-and-check-permissions';\n\nexport default {\n async find(ctx: Context) {\n const {\n state: { userAbility },\n } = ctx;\n\n const defaultQuery = { populate: { folder: true } };\n\n const pm = strapi.service('admin::permission').createPermissionsManager({\n ability: userAbility,\n action: ACTIONS.read,\n model: FILE_MODEL_UID,\n });\n\n if (!pm.isAllowed) {\n return ctx.forbidden();\n }\n\n // validate the incoming user query params\n await pm.validateQuery(ctx.query);\n\n const query = await async.pipe(\n // Start by sanitizing the incoming query\n (q) => pm.sanitizeQuery(q),\n // Add the default query which should not be validated or sanitized\n (q) => merge(defaultQuery, q),\n // Add the dynamic filters based on permissions' conditions\n (q) => pm.addPermissionsQueryTo(q)\n )(ctx.query);\n\n const { results: files, pagination } = await getService('upload').findPage(query);\n\n // Sign file urls for private providers\n const signedFiles = await async.map(files, getService('file').signFileUrls);\n\n const sanitizedFiles = await pm.sanitizeOutput(signedFiles);\n\n return { results: sanitizedFiles, pagination };\n },\n\n async findOne(ctx: Context) {\n const {\n state: { userAbility },\n params: { id },\n } = ctx;\n\n const { pm, file } = await findEntityAndCheckPermissions(\n userAbility,\n ACTIONS.read,\n FILE_MODEL_UID,\n id\n );\n\n const signedFile = await getService('file').signFileUrls(file);\n ctx.body = await pm.sanitizeOutput(signedFile);\n },\n\n async destroy(ctx: Context) {\n const { id } = ctx.params;\n const { userAbility } = ctx.state;\n\n const { pm, file } = await findEntityAndCheckPermissions(\n userAbility,\n ACTIONS.update,\n FILE_MODEL_UID,\n id\n );\n\n const [body] = await Promise.all([\n pm.sanitizeOutput(file, { action: ACTIONS.read }),\n getService('upload').remove(file),\n ]);\n\n ctx.body = body;\n },\n\n async getAIMetadataCount(ctx: Context) {\n const { userAbility } = ctx.state;\n\n const pm = strapi.service('admin::permission').createPermissionsManager({\n ability: userAbility,\n action: ACTIONS.read,\n model: FILE_MODEL_UID,\n });\n\n if (!pm.isAllowed) {\n return ctx.forbidden();\n }\n\n const aiMetadataService = getService('aiMetadata');\n\n // Check if AI service is enabled\n if (!(await aiMetadataService.isEnabled())) {\n return ctx.badRequest('AI Metadata service is not enabled');\n }\n\n try {\n const { imagesWithoutMetadataCount, totalImages } =\n await aiMetadataService.countImagesWithoutMetadata();\n\n ctx.body = {\n imagesWithoutMetadataCount,\n totalImages,\n };\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Failed to get AI metadata count';\n\n strapi.log.error('Failed to get AI metadata count', {\n message,\n error,\n });\n\n ctx.badRequest(message);\n }\n },\n\n async generateAIMetadata(ctx: Context) {\n const { userAbility } = ctx.state;\n\n const pm = strapi.service('admin::permission').createPermissionsManager({\n ability: userAbility,\n action: ACTIONS.update,\n model: FILE_MODEL_UID,\n });\n\n if (!pm.isAllowed) {\n return ctx.forbidden();\n }\n\n const aiMetadataService = getService('aiMetadata');\n\n // Check if AI service is enabled\n if (!(await aiMetadataService.isEnabled())) {\n return ctx.badRequest('AI Metadata service is not enabled');\n }\n\n try {\n // Get count first to check if there are images to process\n const result = await aiMetadataService.countImagesWithoutMetadata();\n\n if (result.imagesWithoutMetadataCount === 0) {\n ctx.body = {\n count: 0,\n message: 'No images without metadata found',\n };\n return;\n }\n\n // Create job\n const jobService = getService('aiMetadataJobs');\n const jobId = await jobService.createJob();\n\n // Start async processing (fire and forget)\n aiMetadataService.processExistingFiles(jobId, ctx.state.user).catch((err: Error) => {\n strapi.log.error('AI metadata job failed:', err);\n });\n\n // Return immediately with job ID\n ctx.body = {\n jobId,\n status: 'pending',\n };\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Failed to generate AI metadata';\n const cause = error instanceof Error && error.cause ? String(error.cause) : undefined;\n\n strapi.log.error('AI metadata generation failed in controller', {\n message,\n cause,\n error,\n });\n\n ctx.badRequest(cause ? `${message}: ${cause}` : message);\n }\n },\n\n async getLatestAIMetadataJob(ctx: Context) {\n const jobService = getService('aiMetadataJobs');\n const job = await jobService.getLatestActiveJob();\n\n if (!job) {\n return ctx.notFound('No active job found');\n }\n\n ctx.body = job;\n },\n};\n"],"names":["find","ctx","state","userAbility","defaultQuery","populate","folder","pm","strapi","service","createPermissionsManager","ability","action","ACTIONS","read","model","FILE_MODEL_UID","isAllowed","forbidden","validateQuery","query","async","pipe","q","sanitizeQuery","merge","addPermissionsQueryTo","results","files","pagination","getService","findPage","signedFiles","map","signFileUrls","sanitizedFiles","sanitizeOutput","findOne","params","id","file","findEntityAndCheckPermissions","signedFile","body","destroy","update","Promise","all","remove","getAIMetadataCount","aiMetadataService","isEnabled","badRequest","imagesWithoutMetadataCount","totalImages","countImagesWithoutMetadata","error","message","Error","log","generateAIMetadata","result","count","jobService","jobId","createJob","processExistingFiles","user","catch","err","status","cause","String","undefined","getLatestAIMetadataJob","job","getLatestActiveJob","notFound"],"mappings":"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"}
@@ -52,6 +52,92 @@ var adminFile = {
52
52
  getService('upload').remove(file)
53
53
  ]);
54
54
  ctx.body = body;
55
+ },
56
+ async getAIMetadataCount (ctx) {
57
+ const { userAbility } = ctx.state;
58
+ const pm = strapi.service('admin::permission').createPermissionsManager({
59
+ ability: userAbility,
60
+ action: ACTIONS.read,
61
+ model: FILE_MODEL_UID
62
+ });
63
+ if (!pm.isAllowed) {
64
+ return ctx.forbidden();
65
+ }
66
+ const aiMetadataService = getService('aiMetadata');
67
+ // Check if AI service is enabled
68
+ if (!await aiMetadataService.isEnabled()) {
69
+ return ctx.badRequest('AI Metadata service is not enabled');
70
+ }
71
+ try {
72
+ const { imagesWithoutMetadataCount, totalImages } = await aiMetadataService.countImagesWithoutMetadata();
73
+ ctx.body = {
74
+ imagesWithoutMetadataCount,
75
+ totalImages
76
+ };
77
+ } catch (error) {
78
+ const message = error instanceof Error ? error.message : 'Failed to get AI metadata count';
79
+ strapi.log.error('Failed to get AI metadata count', {
80
+ message,
81
+ error
82
+ });
83
+ ctx.badRequest(message);
84
+ }
85
+ },
86
+ async generateAIMetadata (ctx) {
87
+ const { userAbility } = ctx.state;
88
+ const pm = strapi.service('admin::permission').createPermissionsManager({
89
+ ability: userAbility,
90
+ action: ACTIONS.update,
91
+ model: FILE_MODEL_UID
92
+ });
93
+ if (!pm.isAllowed) {
94
+ return ctx.forbidden();
95
+ }
96
+ const aiMetadataService = getService('aiMetadata');
97
+ // Check if AI service is enabled
98
+ if (!await aiMetadataService.isEnabled()) {
99
+ return ctx.badRequest('AI Metadata service is not enabled');
100
+ }
101
+ try {
102
+ // Get count first to check if there are images to process
103
+ const result = await aiMetadataService.countImagesWithoutMetadata();
104
+ if (result.imagesWithoutMetadataCount === 0) {
105
+ ctx.body = {
106
+ count: 0,
107
+ message: 'No images without metadata found'
108
+ };
109
+ return;
110
+ }
111
+ // Create job
112
+ const jobService = getService('aiMetadataJobs');
113
+ const jobId = await jobService.createJob();
114
+ // Start async processing (fire and forget)
115
+ aiMetadataService.processExistingFiles(jobId, ctx.state.user).catch((err)=>{
116
+ strapi.log.error('AI metadata job failed:', err);
117
+ });
118
+ // Return immediately with job ID
119
+ ctx.body = {
120
+ jobId,
121
+ status: 'pending'
122
+ };
123
+ } catch (error) {
124
+ const message = error instanceof Error ? error.message : 'Failed to generate AI metadata';
125
+ const cause = error instanceof Error && error.cause ? String(error.cause) : undefined;
126
+ strapi.log.error('AI metadata generation failed in controller', {
127
+ message,
128
+ cause,
129
+ error
130
+ });
131
+ ctx.badRequest(cause ? `${message}: ${cause}` : message);
132
+ }
133
+ },
134
+ async getLatestAIMetadataJob (ctx) {
135
+ const jobService = getService('aiMetadataJobs');
136
+ const job = await jobService.getLatestActiveJob();
137
+ if (!job) {
138
+ return ctx.notFound('No active job found');
139
+ }
140
+ ctx.body = job;
55
141
  }
56
142
  };
57
143
 
@@ -1 +1 @@
1
- {"version":3,"file":"admin-file.mjs","sources":["../../../server/src/controllers/admin-file.ts"],"sourcesContent":["import { merge } from 'lodash/fp';\nimport { async } from '@strapi/utils';\n\nimport type { Context } from 'koa';\n\nimport { getService } from '../utils';\nimport { ACTIONS, FILE_MODEL_UID } from '../constants';\nimport { findEntityAndCheckPermissions } from './utils/find-entity-and-check-permissions';\n\nexport default {\n async find(ctx: Context) {\n const {\n state: { userAbility },\n } = ctx;\n\n const defaultQuery = { populate: { folder: true } };\n\n const pm = strapi.service('admin::permission').createPermissionsManager({\n ability: userAbility,\n action: ACTIONS.read,\n model: FILE_MODEL_UID,\n });\n\n if (!pm.isAllowed) {\n return ctx.forbidden();\n }\n\n // validate the incoming user query params\n await pm.validateQuery(ctx.query);\n\n const query = await async.pipe(\n // Start by sanitizing the incoming query\n (q) => pm.sanitizeQuery(q),\n // Add the default query which should not be validated or sanitized\n (q) => merge(defaultQuery, q),\n // Add the dynamic filters based on permissions' conditions\n (q) => pm.addPermissionsQueryTo(q)\n )(ctx.query);\n\n const { results: files, pagination } = await getService('upload').findPage(query);\n\n // Sign file urls for private providers\n const signedFiles = await async.map(files, getService('file').signFileUrls);\n\n const sanitizedFiles = await pm.sanitizeOutput(signedFiles);\n\n return { results: sanitizedFiles, pagination };\n },\n\n async findOne(ctx: Context) {\n const {\n state: { userAbility },\n params: { id },\n } = ctx;\n\n const { pm, file } = await findEntityAndCheckPermissions(\n userAbility,\n ACTIONS.read,\n FILE_MODEL_UID,\n id\n );\n\n const signedFile = await getService('file').signFileUrls(file);\n ctx.body = await pm.sanitizeOutput(signedFile);\n },\n\n async destroy(ctx: Context) {\n const { id } = ctx.params;\n const { userAbility } = ctx.state;\n\n const { pm, file } = await findEntityAndCheckPermissions(\n userAbility,\n ACTIONS.update,\n FILE_MODEL_UID,\n id\n );\n\n const [body] = await Promise.all([\n pm.sanitizeOutput(file, { action: ACTIONS.read }),\n getService('upload').remove(file),\n ]);\n\n ctx.body = body;\n },\n};\n"],"names":["find","ctx","state","userAbility","defaultQuery","populate","folder","pm","strapi","service","createPermissionsManager","ability","action","ACTIONS","read","model","FILE_MODEL_UID","isAllowed","forbidden","validateQuery","query","async","pipe","q","sanitizeQuery","merge","addPermissionsQueryTo","results","files","pagination","getService","findPage","signedFiles","map","signFileUrls","sanitizedFiles","sanitizeOutput","findOne","params","id","file","findEntityAndCheckPermissions","signedFile","body","destroy","update","Promise","all","remove"],"mappings":"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"}
1
+ {"version":3,"file":"admin-file.mjs","sources":["../../../server/src/controllers/admin-file.ts"],"sourcesContent":["import { merge } from 'lodash/fp';\nimport { async } from '@strapi/utils';\n\nimport type { Context } from 'koa';\n\nimport { getService } from '../utils';\nimport { ACTIONS, FILE_MODEL_UID } from '../constants';\nimport { findEntityAndCheckPermissions } from './utils/find-entity-and-check-permissions';\n\nexport default {\n async find(ctx: Context) {\n const {\n state: { userAbility },\n } = ctx;\n\n const defaultQuery = { populate: { folder: true } };\n\n const pm = strapi.service('admin::permission').createPermissionsManager({\n ability: userAbility,\n action: ACTIONS.read,\n model: FILE_MODEL_UID,\n });\n\n if (!pm.isAllowed) {\n return ctx.forbidden();\n }\n\n // validate the incoming user query params\n await pm.validateQuery(ctx.query);\n\n const query = await async.pipe(\n // Start by sanitizing the incoming query\n (q) => pm.sanitizeQuery(q),\n // Add the default query which should not be validated or sanitized\n (q) => merge(defaultQuery, q),\n // Add the dynamic filters based on permissions' conditions\n (q) => pm.addPermissionsQueryTo(q)\n )(ctx.query);\n\n const { results: files, pagination } = await getService('upload').findPage(query);\n\n // Sign file urls for private providers\n const signedFiles = await async.map(files, getService('file').signFileUrls);\n\n const sanitizedFiles = await pm.sanitizeOutput(signedFiles);\n\n return { results: sanitizedFiles, pagination };\n },\n\n async findOne(ctx: Context) {\n const {\n state: { userAbility },\n params: { id },\n } = ctx;\n\n const { pm, file } = await findEntityAndCheckPermissions(\n userAbility,\n ACTIONS.read,\n FILE_MODEL_UID,\n id\n );\n\n const signedFile = await getService('file').signFileUrls(file);\n ctx.body = await pm.sanitizeOutput(signedFile);\n },\n\n async destroy(ctx: Context) {\n const { id } = ctx.params;\n const { userAbility } = ctx.state;\n\n const { pm, file } = await findEntityAndCheckPermissions(\n userAbility,\n ACTIONS.update,\n FILE_MODEL_UID,\n id\n );\n\n const [body] = await Promise.all([\n pm.sanitizeOutput(file, { action: ACTIONS.read }),\n getService('upload').remove(file),\n ]);\n\n ctx.body = body;\n },\n\n async getAIMetadataCount(ctx: Context) {\n const { userAbility } = ctx.state;\n\n const pm = strapi.service('admin::permission').createPermissionsManager({\n ability: userAbility,\n action: ACTIONS.read,\n model: FILE_MODEL_UID,\n });\n\n if (!pm.isAllowed) {\n return ctx.forbidden();\n }\n\n const aiMetadataService = getService('aiMetadata');\n\n // Check if AI service is enabled\n if (!(await aiMetadataService.isEnabled())) {\n return ctx.badRequest('AI Metadata service is not enabled');\n }\n\n try {\n const { imagesWithoutMetadataCount, totalImages } =\n await aiMetadataService.countImagesWithoutMetadata();\n\n ctx.body = {\n imagesWithoutMetadataCount,\n totalImages,\n };\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Failed to get AI metadata count';\n\n strapi.log.error('Failed to get AI metadata count', {\n message,\n error,\n });\n\n ctx.badRequest(message);\n }\n },\n\n async generateAIMetadata(ctx: Context) {\n const { userAbility } = ctx.state;\n\n const pm = strapi.service('admin::permission').createPermissionsManager({\n ability: userAbility,\n action: ACTIONS.update,\n model: FILE_MODEL_UID,\n });\n\n if (!pm.isAllowed) {\n return ctx.forbidden();\n }\n\n const aiMetadataService = getService('aiMetadata');\n\n // Check if AI service is enabled\n if (!(await aiMetadataService.isEnabled())) {\n return ctx.badRequest('AI Metadata service is not enabled');\n }\n\n try {\n // Get count first to check if there are images to process\n const result = await aiMetadataService.countImagesWithoutMetadata();\n\n if (result.imagesWithoutMetadataCount === 0) {\n ctx.body = {\n count: 0,\n message: 'No images without metadata found',\n };\n return;\n }\n\n // Create job\n const jobService = getService('aiMetadataJobs');\n const jobId = await jobService.createJob();\n\n // Start async processing (fire and forget)\n aiMetadataService.processExistingFiles(jobId, ctx.state.user).catch((err: Error) => {\n strapi.log.error('AI metadata job failed:', err);\n });\n\n // Return immediately with job ID\n ctx.body = {\n jobId,\n status: 'pending',\n };\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Failed to generate AI metadata';\n const cause = error instanceof Error && error.cause ? String(error.cause) : undefined;\n\n strapi.log.error('AI metadata generation failed in controller', {\n message,\n cause,\n error,\n });\n\n ctx.badRequest(cause ? `${message}: ${cause}` : message);\n }\n },\n\n async getLatestAIMetadataJob(ctx: Context) {\n const jobService = getService('aiMetadataJobs');\n const job = await jobService.getLatestActiveJob();\n\n if (!job) {\n return ctx.notFound('No active job found');\n }\n\n ctx.body = job;\n },\n};\n"],"names":["find","ctx","state","userAbility","defaultQuery","populate","folder","pm","strapi","service","createPermissionsManager","ability","action","ACTIONS","read","model","FILE_MODEL_UID","isAllowed","forbidden","validateQuery","query","async","pipe","q","sanitizeQuery","merge","addPermissionsQueryTo","results","files","pagination","getService","findPage","signedFiles","map","signFileUrls","sanitizedFiles","sanitizeOutput","findOne","params","id","file","findEntityAndCheckPermissions","signedFile","body","destroy","update","Promise","all","remove","getAIMetadataCount","aiMetadataService","isEnabled","badRequest","imagesWithoutMetadataCount","totalImages","countImagesWithoutMetadata","error","message","Error","log","generateAIMetadata","result","count","jobService","jobId","createJob","processExistingFiles","user","catch","err","status","cause","String","undefined","getLatestAIMetadataJob","job","getLatestActiveJob","notFound"],"mappings":"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"}
@@ -96,32 +96,12 @@ var adminUpload = {
96
96
  await index.getService('metrics').trackUsage('didUploadImage');
97
97
  }
98
98
  const aiMetadataService = index.getService('aiMetadata');
99
- // AFTER upload - use thumbnail versions for AI processing
99
+ // AFTER upload - generate AI metadata for images
100
100
  if (await aiMetadataService.isEnabled()) {
101
101
  try {
102
- // Use thumbnail URLs instead of original files
103
- const thumbnailFiles = uploadedFiles.map((file)=>({
104
- filepath: file.formats?.thumbnail?.url || file.url,
105
- mimetype: file.mime,
106
- originalFilename: file.name,
107
- size: file.formats?.thumbnail?.size || file.size,
108
- provider: file.provider
109
- }));
110
- const metadataResults = await aiMetadataService.processFiles(thumbnailFiles);
102
+ const metadataResults = await aiMetadataService.processFiles(uploadedFiles);
111
103
  // Update the uploaded files with AI metadata
112
- await Promise.all(uploadedFiles.map(async (uploadedFile, index)=>{
113
- const aiMetadata = metadataResults[index];
114
- if (aiMetadata) {
115
- await uploadService.updateFileInfo(uploadedFile.id, {
116
- alternativeText: aiMetadata.altText,
117
- caption: aiMetadata.caption
118
- }, {
119
- user
120
- });
121
- uploadedFiles[index].alternativeText = aiMetadata.altText;
122
- uploadedFiles[index].caption = aiMetadata.caption;
123
- }
124
- }));
104
+ await aiMetadataService.updateFilesWithAIMetadata(uploadedFiles, metadataResults, user);
125
105
  } catch (error) {
126
106
  strapi.log.warn('AI metadata generation failed, proceeding without AI enhancements', {
127
107
  error: error instanceof Error ? error.message : String(error)
@@ -1 +1 @@
1
- {"version":3,"file":"admin-upload.js","sources":["../../../server/src/controllers/admin-upload.ts"],"sourcesContent":["import _ from 'lodash';\nimport { errors, async } from '@strapi/utils';\n\nimport type { Context } from 'koa';\n\nimport { getService } from '../utils';\nimport { ACTIONS, FILE_MODEL_UID } from '../constants';\nimport { validateBulkUpdateBody, validateUploadBody } from './validation/admin/upload';\nimport { findEntityAndCheckPermissions } from './utils/find-entity-and-check-permissions';\nimport { FileInfo } from '../types';\nimport { prepareUploadRequest } from '../utils/mime-validation';\n\nexport default {\n async bulkUpdateFileInfo(ctx: Context) {\n const {\n state: { userAbility, user },\n request: { body },\n } = ctx;\n\n const { updates } = await validateBulkUpdateBody(body);\n const uploadService = getService('upload');\n\n const results = await async.map(\n updates,\n async ({ id, fileInfo }: { id: number; fileInfo: FileInfo }) => {\n const { pm } = await findEntityAndCheckPermissions(\n userAbility,\n ACTIONS.update,\n FILE_MODEL_UID,\n id\n );\n\n const updated = await uploadService.updateFileInfo(id, fileInfo as any, { user });\n return pm.sanitizeOutput(updated, { action: ACTIONS.read });\n }\n );\n\n ctx.body = results;\n },\n\n async updateFileInfo(ctx: Context) {\n const {\n state: { userAbility, user },\n query: { id },\n request: { body },\n } = ctx;\n\n if (typeof id !== 'string') {\n throw new errors.ValidationError('File id is required');\n }\n\n const uploadService = getService('upload');\n const { pm } = await findEntityAndCheckPermissions(\n userAbility,\n ACTIONS.update,\n FILE_MODEL_UID,\n id\n );\n\n const data = await validateUploadBody(body);\n\n const file = await uploadService.updateFileInfo(id, data.fileInfo as any, { user });\n\n ctx.body = await pm.sanitizeOutput(file, { action: ACTIONS.read });\n },\n\n async replaceFile(ctx: Context) {\n const {\n state: { userAbility, user },\n query: { id },\n request: { body, files: { files } = {} },\n } = ctx;\n\n if (typeof id !== 'string') {\n throw new errors.ValidationError('File id is required');\n }\n\n const uploadService = getService('upload');\n const { pm } = await findEntityAndCheckPermissions(\n userAbility,\n ACTIONS.update,\n FILE_MODEL_UID,\n id\n );\n\n if (Array.isArray(files)) {\n throw new errors.ApplicationError('Cannot replace a file with multiple ones');\n }\n\n const { validFiles, filteredBody } = await prepareUploadRequest(files, body, strapi);\n\n const data = (await validateUploadBody(filteredBody)) as { fileInfo: FileInfo };\n const replacedFile = await uploadService.replace(id, { data, file: validFiles[0] }, { user });\n\n // Sign file urls for private providers\n const signedFile = await getService('file').signFileUrls(replacedFile);\n\n ctx.body = await pm.sanitizeOutput(signedFile, { action: ACTIONS.read });\n },\n\n async uploadFiles(ctx: Context) {\n const {\n state: { userAbility, user },\n request: { body, files: { files } = {} },\n } = ctx;\n\n const uploadService = getService('upload');\n const pm = strapi.service('admin::permission').createPermissionsManager({\n ability: userAbility,\n action: ACTIONS.create,\n model: FILE_MODEL_UID,\n });\n\n if (!pm.isAllowed) {\n return ctx.forbidden();\n }\n\n const { validFiles, filteredBody } = await prepareUploadRequest(files, body, strapi);\n\n const isMultipleFiles = validFiles.length > 1;\n const data = await validateUploadBody(filteredBody, isMultipleFiles);\n\n let filesArray = validFiles;\n\n if (\n data.fileInfo &&\n Array.isArray(data.fileInfo) &&\n filesArray.length === data.fileInfo.length\n ) {\n // Reorder filesArray to match data.fileInfo order\n const alignedFilesArray = data.fileInfo\n .map((info) => {\n return filesArray.find((file) => file.originalFilename === info.name);\n })\n .filter(Boolean) as any[];\n\n filesArray = alignedFilesArray;\n }\n\n // Upload files first to get thumbnails\n const uploadedFiles = await uploadService.upload({ data, files: filesArray }, { user });\n if (uploadedFiles.some((file) => file.mime?.startsWith('image/'))) {\n await getService('metrics').trackUsage('didUploadImage');\n }\n\n const aiMetadataService = getService('aiMetadata');\n\n // AFTER upload - use thumbnail versions for AI processing\n if (await aiMetadataService.isEnabled()) {\n try {\n // Use thumbnail URLs instead of original files\n const thumbnailFiles = uploadedFiles.map(\n (file) =>\n ({\n filepath: file.formats?.thumbnail?.url || file.url, // Use thumbnail if available\n mimetype: file.mime,\n originalFilename: file.name,\n size: file.formats?.thumbnail?.size || file.size,\n provider: file.provider,\n }) as unknown as any\n );\n\n const metadataResults = await aiMetadataService.processFiles(thumbnailFiles);\n\n // Update the uploaded files with AI metadata\n await Promise.all(\n uploadedFiles.map(async (uploadedFile, index) => {\n const aiMetadata = metadataResults[index];\n if (aiMetadata) {\n await uploadService.updateFileInfo(\n uploadedFile.id,\n {\n alternativeText: aiMetadata.altText,\n caption: aiMetadata.caption,\n },\n { user }\n );\n\n uploadedFiles[index].alternativeText = aiMetadata.altText;\n uploadedFiles[index].caption = aiMetadata.caption;\n }\n })\n );\n } catch (error) {\n strapi.log.warn('AI metadata generation failed, proceeding without AI enhancements', {\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n // Sign file urls for private providers\n const signedFiles = await async.map(uploadedFiles, getService('file').signFileUrls);\n\n ctx.body = await pm.sanitizeOutput(signedFiles, { action: ACTIONS.read });\n ctx.status = 201;\n },\n\n // TODO: split into multiple endpoints\n async upload(ctx: Context) {\n const {\n query: { id },\n request: { files: { files } = {} },\n } = ctx;\n\n if (_.isEmpty(files) || (!Array.isArray(files) && files.size === 0)) {\n if (id) {\n return this.updateFileInfo(ctx);\n }\n\n throw new errors.ApplicationError('Files are empty');\n }\n\n await (id ? this.replaceFile : this.uploadFiles)(ctx);\n },\n};\n"],"names":["bulkUpdateFileInfo","ctx","state","userAbility","user","request","body","updates","validateBulkUpdateBody","uploadService","getService","results","async","map","id","fileInfo","pm","findEntityAndCheckPermissions","ACTIONS","update","FILE_MODEL_UID","updated","updateFileInfo","sanitizeOutput","action","read","query","errors","ValidationError","data","validateUploadBody","file","replaceFile","files","Array","isArray","ApplicationError","validFiles","filteredBody","prepareUploadRequest","strapi","replacedFile","replace","signedFile","signFileUrls","uploadFiles","service","createPermissionsManager","ability","create","model","isAllowed","forbidden","isMultipleFiles","length","filesArray","alignedFilesArray","info","find","originalFilename","name","filter","Boolean","uploadedFiles","upload","some","mime","startsWith","trackUsage","aiMetadataService","isEnabled","thumbnailFiles","filepath","formats","thumbnail","url","mimetype","size","provider","metadataResults","processFiles","Promise","all","uploadedFile","index","aiMetadata","alternativeText","altText","caption","error","log","warn","Error","message","String","signedFiles","status","_","isEmpty"],"mappings":"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"}
1
+ {"version":3,"file":"admin-upload.js","sources":["../../../server/src/controllers/admin-upload.ts"],"sourcesContent":["import _ from 'lodash';\nimport { errors, async } from '@strapi/utils';\n\nimport type { Context } from 'koa';\n\nimport { getService } from '../utils';\nimport { ACTIONS, FILE_MODEL_UID } from '../constants';\nimport { validateBulkUpdateBody, validateUploadBody } from './validation/admin/upload';\nimport { findEntityAndCheckPermissions } from './utils/find-entity-and-check-permissions';\nimport { FileInfo } from '../types';\nimport { prepareUploadRequest } from '../utils/mime-validation';\n\nexport default {\n async bulkUpdateFileInfo(ctx: Context) {\n const {\n state: { userAbility, user },\n request: { body },\n } = ctx;\n\n const { updates } = await validateBulkUpdateBody(body);\n const uploadService = getService('upload');\n\n const results = await async.map(\n updates,\n async ({ id, fileInfo }: { id: number; fileInfo: FileInfo }) => {\n const { pm } = await findEntityAndCheckPermissions(\n userAbility,\n ACTIONS.update,\n FILE_MODEL_UID,\n id\n );\n\n const updated = await uploadService.updateFileInfo(id, fileInfo as any, { user });\n return pm.sanitizeOutput(updated, { action: ACTIONS.read });\n }\n );\n\n ctx.body = results;\n },\n\n async updateFileInfo(ctx: Context) {\n const {\n state: { userAbility, user },\n query: { id },\n request: { body },\n } = ctx;\n\n if (typeof id !== 'string') {\n throw new errors.ValidationError('File id is required');\n }\n\n const uploadService = getService('upload');\n const { pm } = await findEntityAndCheckPermissions(\n userAbility,\n ACTIONS.update,\n FILE_MODEL_UID,\n id\n );\n\n const data = await validateUploadBody(body);\n\n const file = await uploadService.updateFileInfo(id, data.fileInfo as any, { user });\n\n ctx.body = await pm.sanitizeOutput(file, { action: ACTIONS.read });\n },\n\n async replaceFile(ctx: Context) {\n const {\n state: { userAbility, user },\n query: { id },\n request: { body, files: { files } = {} },\n } = ctx;\n\n if (typeof id !== 'string') {\n throw new errors.ValidationError('File id is required');\n }\n\n const uploadService = getService('upload');\n const { pm } = await findEntityAndCheckPermissions(\n userAbility,\n ACTIONS.update,\n FILE_MODEL_UID,\n id\n );\n\n if (Array.isArray(files)) {\n throw new errors.ApplicationError('Cannot replace a file with multiple ones');\n }\n\n const { validFiles, filteredBody } = await prepareUploadRequest(files, body, strapi);\n\n const data = (await validateUploadBody(filteredBody)) as { fileInfo: FileInfo };\n const replacedFile = await uploadService.replace(id, { data, file: validFiles[0] }, { user });\n\n // Sign file urls for private providers\n const signedFile = await getService('file').signFileUrls(replacedFile);\n\n ctx.body = await pm.sanitizeOutput(signedFile, { action: ACTIONS.read });\n },\n\n async uploadFiles(ctx: Context) {\n const {\n state: { userAbility, user },\n request: { body, files: { files } = {} },\n } = ctx;\n\n const uploadService = getService('upload');\n const pm = strapi.service('admin::permission').createPermissionsManager({\n ability: userAbility,\n action: ACTIONS.create,\n model: FILE_MODEL_UID,\n });\n\n if (!pm.isAllowed) {\n return ctx.forbidden();\n }\n\n const { validFiles, filteredBody } = await prepareUploadRequest(files, body, strapi);\n\n const isMultipleFiles = validFiles.length > 1;\n const data = await validateUploadBody(filteredBody, isMultipleFiles);\n\n let filesArray = validFiles;\n\n if (\n data.fileInfo &&\n Array.isArray(data.fileInfo) &&\n filesArray.length === data.fileInfo.length\n ) {\n // Reorder filesArray to match data.fileInfo order\n const alignedFilesArray = data.fileInfo\n .map((info) => {\n return filesArray.find((file) => file.originalFilename === info.name);\n })\n .filter(Boolean) as any[];\n\n filesArray = alignedFilesArray;\n }\n\n // Upload files first to get thumbnails\n const uploadedFiles = await uploadService.upload({ data, files: filesArray }, { user });\n if (uploadedFiles.some((file) => file.mime?.startsWith('image/'))) {\n await getService('metrics').trackUsage('didUploadImage');\n }\n\n const aiMetadataService = getService('aiMetadata');\n\n // AFTER upload - generate AI metadata for images\n if (await aiMetadataService.isEnabled()) {\n try {\n const metadataResults = await aiMetadataService.processFiles(uploadedFiles);\n // Update the uploaded files with AI metadata\n await aiMetadataService.updateFilesWithAIMetadata(uploadedFiles, metadataResults, user);\n } catch (error) {\n strapi.log.warn('AI metadata generation failed, proceeding without AI enhancements', {\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n // Sign file urls for private providers\n const signedFiles = await async.map(uploadedFiles, getService('file').signFileUrls);\n\n ctx.body = await pm.sanitizeOutput(signedFiles, { action: ACTIONS.read });\n ctx.status = 201;\n },\n\n // TODO: split into multiple endpoints\n async upload(ctx: Context) {\n const {\n query: { id },\n request: { files: { files } = {} },\n } = ctx;\n\n if (_.isEmpty(files) || (!Array.isArray(files) && files.size === 0)) {\n if (id) {\n return this.updateFileInfo(ctx);\n }\n\n throw new errors.ApplicationError('Files are empty');\n }\n\n await (id ? this.replaceFile : this.uploadFiles)(ctx);\n },\n};\n"],"names":["bulkUpdateFileInfo","ctx","state","userAbility","user","request","body","updates","validateBulkUpdateBody","uploadService","getService","results","async","map","id","fileInfo","pm","findEntityAndCheckPermissions","ACTIONS","update","FILE_MODEL_UID","updated","updateFileInfo","sanitizeOutput","action","read","query","errors","ValidationError","data","validateUploadBody","file","replaceFile","files","Array","isArray","ApplicationError","validFiles","filteredBody","prepareUploadRequest","strapi","replacedFile","replace","signedFile","signFileUrls","uploadFiles","service","createPermissionsManager","ability","create","model","isAllowed","forbidden","isMultipleFiles","length","filesArray","alignedFilesArray","info","find","originalFilename","name","filter","Boolean","uploadedFiles","upload","some","mime","startsWith","trackUsage","aiMetadataService","isEnabled","metadataResults","processFiles","updateFilesWithAIMetadata","error","log","warn","Error","message","String","signedFiles","status","_","isEmpty","size"],"mappings":"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"}
@@ -94,32 +94,12 @@ var adminUpload = {
94
94
  await getService('metrics').trackUsage('didUploadImage');
95
95
  }
96
96
  const aiMetadataService = getService('aiMetadata');
97
- // AFTER upload - use thumbnail versions for AI processing
97
+ // AFTER upload - generate AI metadata for images
98
98
  if (await aiMetadataService.isEnabled()) {
99
99
  try {
100
- // Use thumbnail URLs instead of original files
101
- const thumbnailFiles = uploadedFiles.map((file)=>({
102
- filepath: file.formats?.thumbnail?.url || file.url,
103
- mimetype: file.mime,
104
- originalFilename: file.name,
105
- size: file.formats?.thumbnail?.size || file.size,
106
- provider: file.provider
107
- }));
108
- const metadataResults = await aiMetadataService.processFiles(thumbnailFiles);
100
+ const metadataResults = await aiMetadataService.processFiles(uploadedFiles);
109
101
  // Update the uploaded files with AI metadata
110
- await Promise.all(uploadedFiles.map(async (uploadedFile, index)=>{
111
- const aiMetadata = metadataResults[index];
112
- if (aiMetadata) {
113
- await uploadService.updateFileInfo(uploadedFile.id, {
114
- alternativeText: aiMetadata.altText,
115
- caption: aiMetadata.caption
116
- }, {
117
- user
118
- });
119
- uploadedFiles[index].alternativeText = aiMetadata.altText;
120
- uploadedFiles[index].caption = aiMetadata.caption;
121
- }
122
- }));
102
+ await aiMetadataService.updateFilesWithAIMetadata(uploadedFiles, metadataResults, user);
123
103
  } catch (error) {
124
104
  strapi.log.warn('AI metadata generation failed, proceeding without AI enhancements', {
125
105
  error: error instanceof Error ? error.message : String(error)
@@ -1 +1 @@
1
- {"version":3,"file":"admin-upload.mjs","sources":["../../../server/src/controllers/admin-upload.ts"],"sourcesContent":["import _ from 'lodash';\nimport { errors, async } from '@strapi/utils';\n\nimport type { Context } from 'koa';\n\nimport { getService } from '../utils';\nimport { ACTIONS, FILE_MODEL_UID } from '../constants';\nimport { validateBulkUpdateBody, validateUploadBody } from './validation/admin/upload';\nimport { findEntityAndCheckPermissions } from './utils/find-entity-and-check-permissions';\nimport { FileInfo } from '../types';\nimport { prepareUploadRequest } from '../utils/mime-validation';\n\nexport default {\n async bulkUpdateFileInfo(ctx: Context) {\n const {\n state: { userAbility, user },\n request: { body },\n } = ctx;\n\n const { updates } = await validateBulkUpdateBody(body);\n const uploadService = getService('upload');\n\n const results = await async.map(\n updates,\n async ({ id, fileInfo }: { id: number; fileInfo: FileInfo }) => {\n const { pm } = await findEntityAndCheckPermissions(\n userAbility,\n ACTIONS.update,\n FILE_MODEL_UID,\n id\n );\n\n const updated = await uploadService.updateFileInfo(id, fileInfo as any, { user });\n return pm.sanitizeOutput(updated, { action: ACTIONS.read });\n }\n );\n\n ctx.body = results;\n },\n\n async updateFileInfo(ctx: Context) {\n const {\n state: { userAbility, user },\n query: { id },\n request: { body },\n } = ctx;\n\n if (typeof id !== 'string') {\n throw new errors.ValidationError('File id is required');\n }\n\n const uploadService = getService('upload');\n const { pm } = await findEntityAndCheckPermissions(\n userAbility,\n ACTIONS.update,\n FILE_MODEL_UID,\n id\n );\n\n const data = await validateUploadBody(body);\n\n const file = await uploadService.updateFileInfo(id, data.fileInfo as any, { user });\n\n ctx.body = await pm.sanitizeOutput(file, { action: ACTIONS.read });\n },\n\n async replaceFile(ctx: Context) {\n const {\n state: { userAbility, user },\n query: { id },\n request: { body, files: { files } = {} },\n } = ctx;\n\n if (typeof id !== 'string') {\n throw new errors.ValidationError('File id is required');\n }\n\n const uploadService = getService('upload');\n const { pm } = await findEntityAndCheckPermissions(\n userAbility,\n ACTIONS.update,\n FILE_MODEL_UID,\n id\n );\n\n if (Array.isArray(files)) {\n throw new errors.ApplicationError('Cannot replace a file with multiple ones');\n }\n\n const { validFiles, filteredBody } = await prepareUploadRequest(files, body, strapi);\n\n const data = (await validateUploadBody(filteredBody)) as { fileInfo: FileInfo };\n const replacedFile = await uploadService.replace(id, { data, file: validFiles[0] }, { user });\n\n // Sign file urls for private providers\n const signedFile = await getService('file').signFileUrls(replacedFile);\n\n ctx.body = await pm.sanitizeOutput(signedFile, { action: ACTIONS.read });\n },\n\n async uploadFiles(ctx: Context) {\n const {\n state: { userAbility, user },\n request: { body, files: { files } = {} },\n } = ctx;\n\n const uploadService = getService('upload');\n const pm = strapi.service('admin::permission').createPermissionsManager({\n ability: userAbility,\n action: ACTIONS.create,\n model: FILE_MODEL_UID,\n });\n\n if (!pm.isAllowed) {\n return ctx.forbidden();\n }\n\n const { validFiles, filteredBody } = await prepareUploadRequest(files, body, strapi);\n\n const isMultipleFiles = validFiles.length > 1;\n const data = await validateUploadBody(filteredBody, isMultipleFiles);\n\n let filesArray = validFiles;\n\n if (\n data.fileInfo &&\n Array.isArray(data.fileInfo) &&\n filesArray.length === data.fileInfo.length\n ) {\n // Reorder filesArray to match data.fileInfo order\n const alignedFilesArray = data.fileInfo\n .map((info) => {\n return filesArray.find((file) => file.originalFilename === info.name);\n })\n .filter(Boolean) as any[];\n\n filesArray = alignedFilesArray;\n }\n\n // Upload files first to get thumbnails\n const uploadedFiles = await uploadService.upload({ data, files: filesArray }, { user });\n if (uploadedFiles.some((file) => file.mime?.startsWith('image/'))) {\n await getService('metrics').trackUsage('didUploadImage');\n }\n\n const aiMetadataService = getService('aiMetadata');\n\n // AFTER upload - use thumbnail versions for AI processing\n if (await aiMetadataService.isEnabled()) {\n try {\n // Use thumbnail URLs instead of original files\n const thumbnailFiles = uploadedFiles.map(\n (file) =>\n ({\n filepath: file.formats?.thumbnail?.url || file.url, // Use thumbnail if available\n mimetype: file.mime,\n originalFilename: file.name,\n size: file.formats?.thumbnail?.size || file.size,\n provider: file.provider,\n }) as unknown as any\n );\n\n const metadataResults = await aiMetadataService.processFiles(thumbnailFiles);\n\n // Update the uploaded files with AI metadata\n await Promise.all(\n uploadedFiles.map(async (uploadedFile, index) => {\n const aiMetadata = metadataResults[index];\n if (aiMetadata) {\n await uploadService.updateFileInfo(\n uploadedFile.id,\n {\n alternativeText: aiMetadata.altText,\n caption: aiMetadata.caption,\n },\n { user }\n );\n\n uploadedFiles[index].alternativeText = aiMetadata.altText;\n uploadedFiles[index].caption = aiMetadata.caption;\n }\n })\n );\n } catch (error) {\n strapi.log.warn('AI metadata generation failed, proceeding without AI enhancements', {\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n // Sign file urls for private providers\n const signedFiles = await async.map(uploadedFiles, getService('file').signFileUrls);\n\n ctx.body = await pm.sanitizeOutput(signedFiles, { action: ACTIONS.read });\n ctx.status = 201;\n },\n\n // TODO: split into multiple endpoints\n async upload(ctx: Context) {\n const {\n query: { id },\n request: { files: { files } = {} },\n } = ctx;\n\n if (_.isEmpty(files) || (!Array.isArray(files) && files.size === 0)) {\n if (id) {\n return this.updateFileInfo(ctx);\n }\n\n throw new errors.ApplicationError('Files are empty');\n }\n\n await (id ? this.replaceFile : this.uploadFiles)(ctx);\n },\n};\n"],"names":["bulkUpdateFileInfo","ctx","state","userAbility","user","request","body","updates","validateBulkUpdateBody","uploadService","getService","results","async","map","id","fileInfo","pm","findEntityAndCheckPermissions","ACTIONS","update","FILE_MODEL_UID","updated","updateFileInfo","sanitizeOutput","action","read","query","errors","ValidationError","data","validateUploadBody","file","replaceFile","files","Array","isArray","ApplicationError","validFiles","filteredBody","prepareUploadRequest","strapi","replacedFile","replace","signedFile","signFileUrls","uploadFiles","service","createPermissionsManager","ability","create","model","isAllowed","forbidden","isMultipleFiles","length","filesArray","alignedFilesArray","info","find","originalFilename","name","filter","Boolean","uploadedFiles","upload","some","mime","startsWith","trackUsage","aiMetadataService","isEnabled","thumbnailFiles","filepath","formats","thumbnail","url","mimetype","size","provider","metadataResults","processFiles","Promise","all","uploadedFile","index","aiMetadata","alternativeText","altText","caption","error","log","warn","Error","message","String","signedFiles","status","_","isEmpty"],"mappings":"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"}
1
+ {"version":3,"file":"admin-upload.mjs","sources":["../../../server/src/controllers/admin-upload.ts"],"sourcesContent":["import _ from 'lodash';\nimport { errors, async } from '@strapi/utils';\n\nimport type { Context } from 'koa';\n\nimport { getService } from '../utils';\nimport { ACTIONS, FILE_MODEL_UID } from '../constants';\nimport { validateBulkUpdateBody, validateUploadBody } from './validation/admin/upload';\nimport { findEntityAndCheckPermissions } from './utils/find-entity-and-check-permissions';\nimport { FileInfo } from '../types';\nimport { prepareUploadRequest } from '../utils/mime-validation';\n\nexport default {\n async bulkUpdateFileInfo(ctx: Context) {\n const {\n state: { userAbility, user },\n request: { body },\n } = ctx;\n\n const { updates } = await validateBulkUpdateBody(body);\n const uploadService = getService('upload');\n\n const results = await async.map(\n updates,\n async ({ id, fileInfo }: { id: number; fileInfo: FileInfo }) => {\n const { pm } = await findEntityAndCheckPermissions(\n userAbility,\n ACTIONS.update,\n FILE_MODEL_UID,\n id\n );\n\n const updated = await uploadService.updateFileInfo(id, fileInfo as any, { user });\n return pm.sanitizeOutput(updated, { action: ACTIONS.read });\n }\n );\n\n ctx.body = results;\n },\n\n async updateFileInfo(ctx: Context) {\n const {\n state: { userAbility, user },\n query: { id },\n request: { body },\n } = ctx;\n\n if (typeof id !== 'string') {\n throw new errors.ValidationError('File id is required');\n }\n\n const uploadService = getService('upload');\n const { pm } = await findEntityAndCheckPermissions(\n userAbility,\n ACTIONS.update,\n FILE_MODEL_UID,\n id\n );\n\n const data = await validateUploadBody(body);\n\n const file = await uploadService.updateFileInfo(id, data.fileInfo as any, { user });\n\n ctx.body = await pm.sanitizeOutput(file, { action: ACTIONS.read });\n },\n\n async replaceFile(ctx: Context) {\n const {\n state: { userAbility, user },\n query: { id },\n request: { body, files: { files } = {} },\n } = ctx;\n\n if (typeof id !== 'string') {\n throw new errors.ValidationError('File id is required');\n }\n\n const uploadService = getService('upload');\n const { pm } = await findEntityAndCheckPermissions(\n userAbility,\n ACTIONS.update,\n FILE_MODEL_UID,\n id\n );\n\n if (Array.isArray(files)) {\n throw new errors.ApplicationError('Cannot replace a file with multiple ones');\n }\n\n const { validFiles, filteredBody } = await prepareUploadRequest(files, body, strapi);\n\n const data = (await validateUploadBody(filteredBody)) as { fileInfo: FileInfo };\n const replacedFile = await uploadService.replace(id, { data, file: validFiles[0] }, { user });\n\n // Sign file urls for private providers\n const signedFile = await getService('file').signFileUrls(replacedFile);\n\n ctx.body = await pm.sanitizeOutput(signedFile, { action: ACTIONS.read });\n },\n\n async uploadFiles(ctx: Context) {\n const {\n state: { userAbility, user },\n request: { body, files: { files } = {} },\n } = ctx;\n\n const uploadService = getService('upload');\n const pm = strapi.service('admin::permission').createPermissionsManager({\n ability: userAbility,\n action: ACTIONS.create,\n model: FILE_MODEL_UID,\n });\n\n if (!pm.isAllowed) {\n return ctx.forbidden();\n }\n\n const { validFiles, filteredBody } = await prepareUploadRequest(files, body, strapi);\n\n const isMultipleFiles = validFiles.length > 1;\n const data = await validateUploadBody(filteredBody, isMultipleFiles);\n\n let filesArray = validFiles;\n\n if (\n data.fileInfo &&\n Array.isArray(data.fileInfo) &&\n filesArray.length === data.fileInfo.length\n ) {\n // Reorder filesArray to match data.fileInfo order\n const alignedFilesArray = data.fileInfo\n .map((info) => {\n return filesArray.find((file) => file.originalFilename === info.name);\n })\n .filter(Boolean) as any[];\n\n filesArray = alignedFilesArray;\n }\n\n // Upload files first to get thumbnails\n const uploadedFiles = await uploadService.upload({ data, files: filesArray }, { user });\n if (uploadedFiles.some((file) => file.mime?.startsWith('image/'))) {\n await getService('metrics').trackUsage('didUploadImage');\n }\n\n const aiMetadataService = getService('aiMetadata');\n\n // AFTER upload - generate AI metadata for images\n if (await aiMetadataService.isEnabled()) {\n try {\n const metadataResults = await aiMetadataService.processFiles(uploadedFiles);\n // Update the uploaded files with AI metadata\n await aiMetadataService.updateFilesWithAIMetadata(uploadedFiles, metadataResults, user);\n } catch (error) {\n strapi.log.warn('AI metadata generation failed, proceeding without AI enhancements', {\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n // Sign file urls for private providers\n const signedFiles = await async.map(uploadedFiles, getService('file').signFileUrls);\n\n ctx.body = await pm.sanitizeOutput(signedFiles, { action: ACTIONS.read });\n ctx.status = 201;\n },\n\n // TODO: split into multiple endpoints\n async upload(ctx: Context) {\n const {\n query: { id },\n request: { files: { files } = {} },\n } = ctx;\n\n if (_.isEmpty(files) || (!Array.isArray(files) && files.size === 0)) {\n if (id) {\n return this.updateFileInfo(ctx);\n }\n\n throw new errors.ApplicationError('Files are empty');\n }\n\n await (id ? this.replaceFile : this.uploadFiles)(ctx);\n },\n};\n"],"names":["bulkUpdateFileInfo","ctx","state","userAbility","user","request","body","updates","validateBulkUpdateBody","uploadService","getService","results","async","map","id","fileInfo","pm","findEntityAndCheckPermissions","ACTIONS","update","FILE_MODEL_UID","updated","updateFileInfo","sanitizeOutput","action","read","query","errors","ValidationError","data","validateUploadBody","file","replaceFile","files","Array","isArray","ApplicationError","validFiles","filteredBody","prepareUploadRequest","strapi","replacedFile","replace","signedFile","signFileUrls","uploadFiles","service","createPermissionsManager","ability","create","model","isAllowed","forbidden","isMultipleFiles","length","filesArray","alignedFilesArray","info","find","originalFilename","name","filter","Boolean","uploadedFiles","upload","some","mime","startsWith","trackUsage","aiMetadataService","isEnabled","metadataResults","processFiles","updateFilesWithAIMetadata","error","log","warn","Error","message","String","signedFiles","status","_","isEmpty","size"],"mappings":"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"}
@@ -4,10 +4,15 @@ var utils = require('@strapi/utils');
4
4
  var fp = require('lodash/fp');
5
5
  var index = require('../../../utils/index.js');
6
6
 
7
+ const focalPointSchema = utils.yup.object({
8
+ x: utils.yup.number().min(0).max(100).required(),
9
+ y: utils.yup.number().min(0).max(100).required()
10
+ }).nullable().default(null);
7
11
  const fileInfoSchema = utils.yup.object({
8
12
  name: utils.yup.string().nullable(),
9
13
  alternativeText: utils.yup.string().nullable(),
10
14
  caption: utils.yup.string().nullable(),
15
+ focalPoint: focalPointSchema,
11
16
  folder: utils.yup.strapiID().nullable().test('folder-exists', 'the folder does not exist', async (folderId)=>{
12
17
  if (fp.isNil(folderId)) {
13
18
  return true;
@@ -1 +1 @@
1
- {"version":3,"file":"upload.js","sources":["../../../../../server/src/controllers/validation/admin/upload.ts"],"sourcesContent":["import { yup, validateYupSchema } from '@strapi/utils';\nimport { isNil } from 'lodash/fp';\nimport { getService } from '../../../utils';\n\nconst fileInfoSchema = yup.object({\n name: yup.string().nullable(),\n alternativeText: yup.string().nullable(),\n caption: yup.string().nullable(),\n folder: yup\n .strapiID()\n .nullable()\n .test('folder-exists', 'the folder does not exist', async (folderId) => {\n if (isNil(folderId)) {\n return true;\n }\n\n const exists = await getService('folder').exists({ id: folderId });\n\n return exists;\n }),\n});\n\nconst uploadSchema = yup.object({\n fileInfo: fileInfoSchema,\n});\n\nconst multiUploadSchema = yup.object({\n fileInfo: yup.array().of(fileInfoSchema),\n});\n\nconst validateUploadBody = (data = {}, isMulti = false) => {\n const schema = isMulti ? multiUploadSchema : uploadSchema;\n\n return validateYupSchema(schema, { strict: false })(data);\n};\n\nexport { validateUploadBody };\n\nexport type UploadBody =\n | yup.InferType<typeof uploadSchema>\n | yup.InferType<typeof multiUploadSchema>;\n\nconst bulkUpdatesSchema = yup.object({\n updates: yup\n .array()\n .of(\n yup.object({\n id: yup.number().required(),\n fileInfo: fileInfoSchema.required(),\n })\n )\n .min(1)\n .required(),\n});\n\nexport const validateBulkUpdateBody = validateYupSchema(bulkUpdatesSchema);\n"],"names":["fileInfoSchema","yup","object","name","string","nullable","alternativeText","caption","folder","strapiID","test","folderId","isNil","exists","getService","id","uploadSchema","fileInfo","multiUploadSchema","array","of","validateUploadBody","data","isMulti","schema","validateYupSchema","strict","bulkUpdatesSchema","updates","number","required","min","validateBulkUpdateBody"],"mappings":";;;;;;AAIA,MAAMA,cAAAA,GAAiBC,SAAIC,CAAAA,MAAM,CAAC;IAChCC,IAAMF,EAAAA,SAAAA,CAAIG,MAAM,EAAA,CAAGC,QAAQ,EAAA;IAC3BC,eAAiBL,EAAAA,SAAAA,CAAIG,MAAM,EAAA,CAAGC,QAAQ,EAAA;IACtCE,OAASN,EAAAA,SAAAA,CAAIG,MAAM,EAAA,CAAGC,QAAQ,EAAA;IAC9BG,MAAQP,EAAAA,SAAAA,CACLQ,QAAQ,EACRJ,CAAAA,QAAQ,GACRK,IAAI,CAAC,eAAiB,EAAA,2BAAA,EAA6B,OAAOC,QAAAA,GAAAA;AACzD,QAAA,IAAIC,SAAMD,QAAW,CAAA,EAAA;YACnB,OAAO,IAAA;AACT;AAEA,QAAA,MAAME,MAAS,GAAA,MAAMC,gBAAW,CAAA,QAAA,CAAA,CAAUD,MAAM,CAAC;YAAEE,EAAIJ,EAAAA;AAAS,SAAA,CAAA;QAEhE,OAAOE,MAAAA;AACT,KAAA;AACJ,CAAA,CAAA;AAEA,MAAMG,YAAAA,GAAef,SAAIC,CAAAA,MAAM,CAAC;IAC9Be,QAAUjB,EAAAA;AACZ,CAAA,CAAA;AAEA,MAAMkB,iBAAAA,GAAoBjB,SAAIC,CAAAA,MAAM,CAAC;AACnCe,IAAAA,QAAAA,EAAUhB,SAAIkB,CAAAA,KAAK,EAAGC,CAAAA,EAAE,CAACpB,cAAAA;AAC3B,CAAA,CAAA;AAEA,MAAMqB,qBAAqB,CAACC,IAAAA,GAAO,EAAE,EAAEC,UAAU,KAAK,GAAA;IACpD,MAAMC,MAAAA,GAASD,UAAUL,iBAAoBF,GAAAA,YAAAA;AAE7C,IAAA,OAAOS,wBAAkBD,MAAQ,EAAA;QAAEE,MAAQ,EAAA;KAASJ,CAAAA,CAAAA,IAAAA,CAAAA;AACtD;AAQA,MAAMK,iBAAAA,GAAoB1B,SAAIC,CAAAA,MAAM,CAAC;AACnC0B,IAAAA,OAAAA,EAAS3B,UACNkB,KAAK,EAAA,CACLC,EAAE,CACDnB,SAAAA,CAAIC,MAAM,CAAC;QACTa,EAAId,EAAAA,SAAAA,CAAI4B,MAAM,EAAA,CAAGC,QAAQ,EAAA;AACzBb,QAAAA,QAAAA,EAAUjB,eAAe8B,QAAQ;KAGpCC,CAAAA,CAAAA,CAAAA,GAAG,CAAC,CAAA,CAAA,CACJD,QAAQ;AACb,CAAA,CAAA;AAEO,MAAME,sBAAyBP,GAAAA,uBAAAA,CAAkBE,iBAAmB;;;;;"}
1
+ {"version":3,"file":"upload.js","sources":["../../../../../server/src/controllers/validation/admin/upload.ts"],"sourcesContent":["import { yup, validateYupSchema } from '@strapi/utils';\nimport { isNil } from 'lodash/fp';\nimport { getService } from '../../../utils';\n\nconst focalPointSchema = yup\n .object({\n x: yup.number().min(0).max(100).required(),\n y: yup.number().min(0).max(100).required(),\n })\n .nullable()\n .default(null);\n\nconst fileInfoSchema = yup.object({\n name: yup.string().nullable(),\n alternativeText: yup.string().nullable(),\n caption: yup.string().nullable(),\n focalPoint: focalPointSchema,\n folder: yup\n .strapiID()\n .nullable()\n .test('folder-exists', 'the folder does not exist', async (folderId) => {\n if (isNil(folderId)) {\n return true;\n }\n\n const exists = await getService('folder').exists({ id: folderId });\n\n return exists;\n }),\n});\n\nconst uploadSchema = yup.object({\n fileInfo: fileInfoSchema,\n});\n\nconst multiUploadSchema = yup.object({\n fileInfo: yup.array().of(fileInfoSchema),\n});\n\nconst validateUploadBody = (data = {}, isMulti = false) => {\n const schema = isMulti ? multiUploadSchema : uploadSchema;\n\n return validateYupSchema(schema, { strict: false })(data);\n};\n\nexport { validateUploadBody };\n\nexport type UploadBody =\n | yup.InferType<typeof uploadSchema>\n | yup.InferType<typeof multiUploadSchema>;\n\nconst bulkUpdatesSchema = yup.object({\n updates: yup\n .array()\n .of(\n yup.object({\n id: yup.number().required(),\n fileInfo: fileInfoSchema.required(),\n })\n )\n .min(1)\n .required(),\n});\n\nexport const validateBulkUpdateBody = validateYupSchema(bulkUpdatesSchema);\n"],"names":["focalPointSchema","yup","object","x","number","min","max","required","y","nullable","default","fileInfoSchema","name","string","alternativeText","caption","focalPoint","folder","strapiID","test","folderId","isNil","exists","getService","id","uploadSchema","fileInfo","multiUploadSchema","array","of","validateUploadBody","data","isMulti","schema","validateYupSchema","strict","bulkUpdatesSchema","updates","validateBulkUpdateBody"],"mappings":";;;;;;AAIA,MAAMA,gBAAAA,GAAmBC,SACtBC,CAAAA,MAAM,CAAC;IACNC,CAAGF,EAAAA,SAAAA,CAAIG,MAAM,EAAGC,CAAAA,GAAG,CAAC,CAAGC,CAAAA,CAAAA,GAAG,CAAC,GAAA,CAAA,CAAKC,QAAQ,EAAA;IACxCC,CAAGP,EAAAA,SAAAA,CAAIG,MAAM,EAAGC,CAAAA,GAAG,CAAC,CAAGC,CAAAA,CAAAA,GAAG,CAAC,GAAA,CAAA,CAAKC,QAAQ;AAC1C,CACCE,CAAAA,CAAAA,QAAQ,EACRC,CAAAA,OAAO,CAAC,IAAA,CAAA;AAEX,MAAMC,cAAAA,GAAiBV,SAAIC,CAAAA,MAAM,CAAC;IAChCU,IAAMX,EAAAA,SAAAA,CAAIY,MAAM,EAAA,CAAGJ,QAAQ,EAAA;IAC3BK,eAAiBb,EAAAA,SAAAA,CAAIY,MAAM,EAAA,CAAGJ,QAAQ,EAAA;IACtCM,OAASd,EAAAA,SAAAA,CAAIY,MAAM,EAAA,CAAGJ,QAAQ,EAAA;IAC9BO,UAAYhB,EAAAA,gBAAAA;IACZiB,MAAQhB,EAAAA,SAAAA,CACLiB,QAAQ,EACRT,CAAAA,QAAQ,GACRU,IAAI,CAAC,eAAiB,EAAA,2BAAA,EAA6B,OAAOC,QAAAA,GAAAA;AACzD,QAAA,IAAIC,SAAMD,QAAW,CAAA,EAAA;YACnB,OAAO,IAAA;AACT;AAEA,QAAA,MAAME,MAAS,GAAA,MAAMC,gBAAW,CAAA,QAAA,CAAA,CAAUD,MAAM,CAAC;YAAEE,EAAIJ,EAAAA;AAAS,SAAA,CAAA;QAEhE,OAAOE,MAAAA;AACT,KAAA;AACJ,CAAA,CAAA;AAEA,MAAMG,YAAAA,GAAexB,SAAIC,CAAAA,MAAM,CAAC;IAC9BwB,QAAUf,EAAAA;AACZ,CAAA,CAAA;AAEA,MAAMgB,iBAAAA,GAAoB1B,SAAIC,CAAAA,MAAM,CAAC;AACnCwB,IAAAA,QAAAA,EAAUzB,SAAI2B,CAAAA,KAAK,EAAGC,CAAAA,EAAE,CAAClB,cAAAA;AAC3B,CAAA,CAAA;AAEA,MAAMmB,qBAAqB,CAACC,IAAAA,GAAO,EAAE,EAAEC,UAAU,KAAK,GAAA;IACpD,MAAMC,MAAAA,GAASD,UAAUL,iBAAoBF,GAAAA,YAAAA;AAE7C,IAAA,OAAOS,wBAAkBD,MAAQ,EAAA;QAAEE,MAAQ,EAAA;KAASJ,CAAAA,CAAAA,IAAAA,CAAAA;AACtD;AAQA,MAAMK,iBAAAA,GAAoBnC,SAAIC,CAAAA,MAAM,CAAC;AACnCmC,IAAAA,OAAAA,EAASpC,UACN2B,KAAK,EAAA,CACLC,EAAE,CACD5B,SAAAA,CAAIC,MAAM,CAAC;QACTsB,EAAIvB,EAAAA,SAAAA,CAAIG,MAAM,EAAA,CAAGG,QAAQ,EAAA;AACzBmB,QAAAA,QAAAA,EAAUf,eAAeJ,QAAQ;KAGpCF,CAAAA,CAAAA,CAAAA,GAAG,CAAC,CAAA,CAAA,CACJE,QAAQ;AACb,CAAA,CAAA;AAEO,MAAM+B,sBAAyBJ,GAAAA,uBAAAA,CAAkBE,iBAAmB;;;;;"}
@@ -2,10 +2,15 @@ import { yup, validateYupSchema } from '@strapi/utils';
2
2
  import { isNil } from 'lodash/fp';
3
3
  import { getService } from '../../../utils/index.mjs';
4
4
 
5
+ const focalPointSchema = yup.object({
6
+ x: yup.number().min(0).max(100).required(),
7
+ y: yup.number().min(0).max(100).required()
8
+ }).nullable().default(null);
5
9
  const fileInfoSchema = yup.object({
6
10
  name: yup.string().nullable(),
7
11
  alternativeText: yup.string().nullable(),
8
12
  caption: yup.string().nullable(),
13
+ focalPoint: focalPointSchema,
9
14
  folder: yup.strapiID().nullable().test('folder-exists', 'the folder does not exist', async (folderId)=>{
10
15
  if (isNil(folderId)) {
11
16
  return true;
@@ -1 +1 @@
1
- {"version":3,"file":"upload.mjs","sources":["../../../../../server/src/controllers/validation/admin/upload.ts"],"sourcesContent":["import { yup, validateYupSchema } from '@strapi/utils';\nimport { isNil } from 'lodash/fp';\nimport { getService } from '../../../utils';\n\nconst fileInfoSchema = yup.object({\n name: yup.string().nullable(),\n alternativeText: yup.string().nullable(),\n caption: yup.string().nullable(),\n folder: yup\n .strapiID()\n .nullable()\n .test('folder-exists', 'the folder does not exist', async (folderId) => {\n if (isNil(folderId)) {\n return true;\n }\n\n const exists = await getService('folder').exists({ id: folderId });\n\n return exists;\n }),\n});\n\nconst uploadSchema = yup.object({\n fileInfo: fileInfoSchema,\n});\n\nconst multiUploadSchema = yup.object({\n fileInfo: yup.array().of(fileInfoSchema),\n});\n\nconst validateUploadBody = (data = {}, isMulti = false) => {\n const schema = isMulti ? multiUploadSchema : uploadSchema;\n\n return validateYupSchema(schema, { strict: false })(data);\n};\n\nexport { validateUploadBody };\n\nexport type UploadBody =\n | yup.InferType<typeof uploadSchema>\n | yup.InferType<typeof multiUploadSchema>;\n\nconst bulkUpdatesSchema = yup.object({\n updates: yup\n .array()\n .of(\n yup.object({\n id: yup.number().required(),\n fileInfo: fileInfoSchema.required(),\n })\n )\n .min(1)\n .required(),\n});\n\nexport const validateBulkUpdateBody = validateYupSchema(bulkUpdatesSchema);\n"],"names":["fileInfoSchema","yup","object","name","string","nullable","alternativeText","caption","folder","strapiID","test","folderId","isNil","exists","getService","id","uploadSchema","fileInfo","multiUploadSchema","array","of","validateUploadBody","data","isMulti","schema","validateYupSchema","strict","bulkUpdatesSchema","updates","number","required","min","validateBulkUpdateBody"],"mappings":";;;;AAIA,MAAMA,cAAAA,GAAiBC,GAAIC,CAAAA,MAAM,CAAC;IAChCC,IAAMF,EAAAA,GAAAA,CAAIG,MAAM,EAAA,CAAGC,QAAQ,EAAA;IAC3BC,eAAiBL,EAAAA,GAAAA,CAAIG,MAAM,EAAA,CAAGC,QAAQ,EAAA;IACtCE,OAASN,EAAAA,GAAAA,CAAIG,MAAM,EAAA,CAAGC,QAAQ,EAAA;IAC9BG,MAAQP,EAAAA,GAAAA,CACLQ,QAAQ,EACRJ,CAAAA,QAAQ,GACRK,IAAI,CAAC,eAAiB,EAAA,2BAAA,EAA6B,OAAOC,QAAAA,GAAAA;AACzD,QAAA,IAAIC,MAAMD,QAAW,CAAA,EAAA;YACnB,OAAO,IAAA;AACT;AAEA,QAAA,MAAME,MAAS,GAAA,MAAMC,UAAW,CAAA,QAAA,CAAA,CAAUD,MAAM,CAAC;YAAEE,EAAIJ,EAAAA;AAAS,SAAA,CAAA;QAEhE,OAAOE,MAAAA;AACT,KAAA;AACJ,CAAA,CAAA;AAEA,MAAMG,YAAAA,GAAef,GAAIC,CAAAA,MAAM,CAAC;IAC9Be,QAAUjB,EAAAA;AACZ,CAAA,CAAA;AAEA,MAAMkB,iBAAAA,GAAoBjB,GAAIC,CAAAA,MAAM,CAAC;AACnCe,IAAAA,QAAAA,EAAUhB,GAAIkB,CAAAA,KAAK,EAAGC,CAAAA,EAAE,CAACpB,cAAAA;AAC3B,CAAA,CAAA;AAEA,MAAMqB,qBAAqB,CAACC,IAAAA,GAAO,EAAE,EAAEC,UAAU,KAAK,GAAA;IACpD,MAAMC,MAAAA,GAASD,UAAUL,iBAAoBF,GAAAA,YAAAA;AAE7C,IAAA,OAAOS,kBAAkBD,MAAQ,EAAA;QAAEE,MAAQ,EAAA;KAASJ,CAAAA,CAAAA,IAAAA,CAAAA;AACtD;AAQA,MAAMK,iBAAAA,GAAoB1B,GAAIC,CAAAA,MAAM,CAAC;AACnC0B,IAAAA,OAAAA,EAAS3B,IACNkB,KAAK,EAAA,CACLC,EAAE,CACDnB,GAAAA,CAAIC,MAAM,CAAC;QACTa,EAAId,EAAAA,GAAAA,CAAI4B,MAAM,EAAA,CAAGC,QAAQ,EAAA;AACzBb,QAAAA,QAAAA,EAAUjB,eAAe8B,QAAQ;KAGpCC,CAAAA,CAAAA,CAAAA,GAAG,CAAC,CAAA,CAAA,CACJD,QAAQ;AACb,CAAA,CAAA;AAEO,MAAME,sBAAyBP,GAAAA,iBAAAA,CAAkBE,iBAAmB;;;;"}
1
+ {"version":3,"file":"upload.mjs","sources":["../../../../../server/src/controllers/validation/admin/upload.ts"],"sourcesContent":["import { yup, validateYupSchema } from '@strapi/utils';\nimport { isNil } from 'lodash/fp';\nimport { getService } from '../../../utils';\n\nconst focalPointSchema = yup\n .object({\n x: yup.number().min(0).max(100).required(),\n y: yup.number().min(0).max(100).required(),\n })\n .nullable()\n .default(null);\n\nconst fileInfoSchema = yup.object({\n name: yup.string().nullable(),\n alternativeText: yup.string().nullable(),\n caption: yup.string().nullable(),\n focalPoint: focalPointSchema,\n folder: yup\n .strapiID()\n .nullable()\n .test('folder-exists', 'the folder does not exist', async (folderId) => {\n if (isNil(folderId)) {\n return true;\n }\n\n const exists = await getService('folder').exists({ id: folderId });\n\n return exists;\n }),\n});\n\nconst uploadSchema = yup.object({\n fileInfo: fileInfoSchema,\n});\n\nconst multiUploadSchema = yup.object({\n fileInfo: yup.array().of(fileInfoSchema),\n});\n\nconst validateUploadBody = (data = {}, isMulti = false) => {\n const schema = isMulti ? multiUploadSchema : uploadSchema;\n\n return validateYupSchema(schema, { strict: false })(data);\n};\n\nexport { validateUploadBody };\n\nexport type UploadBody =\n | yup.InferType<typeof uploadSchema>\n | yup.InferType<typeof multiUploadSchema>;\n\nconst bulkUpdatesSchema = yup.object({\n updates: yup\n .array()\n .of(\n yup.object({\n id: yup.number().required(),\n fileInfo: fileInfoSchema.required(),\n })\n )\n .min(1)\n .required(),\n});\n\nexport const validateBulkUpdateBody = validateYupSchema(bulkUpdatesSchema);\n"],"names":["focalPointSchema","yup","object","x","number","min","max","required","y","nullable","default","fileInfoSchema","name","string","alternativeText","caption","focalPoint","folder","strapiID","test","folderId","isNil","exists","getService","id","uploadSchema","fileInfo","multiUploadSchema","array","of","validateUploadBody","data","isMulti","schema","validateYupSchema","strict","bulkUpdatesSchema","updates","validateBulkUpdateBody"],"mappings":";;;;AAIA,MAAMA,gBAAAA,GAAmBC,GACtBC,CAAAA,MAAM,CAAC;IACNC,CAAGF,EAAAA,GAAAA,CAAIG,MAAM,EAAGC,CAAAA,GAAG,CAAC,CAAGC,CAAAA,CAAAA,GAAG,CAAC,GAAA,CAAA,CAAKC,QAAQ,EAAA;IACxCC,CAAGP,EAAAA,GAAAA,CAAIG,MAAM,EAAGC,CAAAA,GAAG,CAAC,CAAGC,CAAAA,CAAAA,GAAG,CAAC,GAAA,CAAA,CAAKC,QAAQ;AAC1C,CACCE,CAAAA,CAAAA,QAAQ,EACRC,CAAAA,OAAO,CAAC,IAAA,CAAA;AAEX,MAAMC,cAAAA,GAAiBV,GAAIC,CAAAA,MAAM,CAAC;IAChCU,IAAMX,EAAAA,GAAAA,CAAIY,MAAM,EAAA,CAAGJ,QAAQ,EAAA;IAC3BK,eAAiBb,EAAAA,GAAAA,CAAIY,MAAM,EAAA,CAAGJ,QAAQ,EAAA;IACtCM,OAASd,EAAAA,GAAAA,CAAIY,MAAM,EAAA,CAAGJ,QAAQ,EAAA;IAC9BO,UAAYhB,EAAAA,gBAAAA;IACZiB,MAAQhB,EAAAA,GAAAA,CACLiB,QAAQ,EACRT,CAAAA,QAAQ,GACRU,IAAI,CAAC,eAAiB,EAAA,2BAAA,EAA6B,OAAOC,QAAAA,GAAAA;AACzD,QAAA,IAAIC,MAAMD,QAAW,CAAA,EAAA;YACnB,OAAO,IAAA;AACT;AAEA,QAAA,MAAME,MAAS,GAAA,MAAMC,UAAW,CAAA,QAAA,CAAA,CAAUD,MAAM,CAAC;YAAEE,EAAIJ,EAAAA;AAAS,SAAA,CAAA;QAEhE,OAAOE,MAAAA;AACT,KAAA;AACJ,CAAA,CAAA;AAEA,MAAMG,YAAAA,GAAexB,GAAIC,CAAAA,MAAM,CAAC;IAC9BwB,QAAUf,EAAAA;AACZ,CAAA,CAAA;AAEA,MAAMgB,iBAAAA,GAAoB1B,GAAIC,CAAAA,MAAM,CAAC;AACnCwB,IAAAA,QAAAA,EAAUzB,GAAI2B,CAAAA,KAAK,EAAGC,CAAAA,EAAE,CAAClB,cAAAA;AAC3B,CAAA,CAAA;AAEA,MAAMmB,qBAAqB,CAACC,IAAAA,GAAO,EAAE,EAAEC,UAAU,KAAK,GAAA;IACpD,MAAMC,MAAAA,GAASD,UAAUL,iBAAoBF,GAAAA,YAAAA;AAE7C,IAAA,OAAOS,kBAAkBD,MAAQ,EAAA;QAAEE,MAAQ,EAAA;KAASJ,CAAAA,CAAAA,IAAAA,CAAAA;AACtD;AAQA,MAAMK,iBAAAA,GAAoBnC,GAAIC,CAAAA,MAAM,CAAC;AACnCmC,IAAAA,OAAAA,EAASpC,IACN2B,KAAK,EAAA,CACLC,EAAE,CACD5B,GAAAA,CAAIC,MAAM,CAAC;QACTsB,EAAIvB,EAAAA,GAAAA,CAAIG,MAAM,EAAA,CAAGG,QAAQ,EAAA;AACzBmB,QAAAA,QAAAA,EAAUf,eAAeJ,QAAQ;KAGpCF,CAAAA,CAAAA,CAAAA,GAAG,CAAC,CAAA,CAAA,CACJE,QAAQ;AACb,CAAA,CAAA;AAEO,MAAM+B,sBAAyBJ,GAAAA,iBAAAA,CAAkBE,iBAAmB;;;;"}
@@ -2,10 +2,15 @@
2
2
 
3
3
  var utils = require('@strapi/utils');
4
4
 
5
+ const focalPointSchema = utils.yup.object({
6
+ x: utils.yup.number().min(0).max(100).required(),
7
+ y: utils.yup.number().min(0).max(100).required()
8
+ }).nullable().default(null);
5
9
  const fileInfoSchema = utils.yup.object({
6
10
  name: utils.yup.string().nullable(),
7
11
  alternativeText: utils.yup.string().nullable(),
8
- caption: utils.yup.string().nullable()
12
+ caption: utils.yup.string().nullable(),
13
+ focalPoint: focalPointSchema
9
14
  }).noUnknown();
10
15
  const uploadSchema = utils.yup.object({
11
16
  fileInfo: fileInfoSchema
@@ -1 +1 @@
1
- {"version":3,"file":"upload.js","sources":["../../../../../server/src/controllers/validation/content-api/upload.ts"],"sourcesContent":["import { yup, validateYupSchema } from '@strapi/utils';\n\nconst fileInfoSchema = yup\n .object({\n name: yup.string().nullable(),\n alternativeText: yup.string().nullable(),\n caption: yup.string().nullable(),\n })\n .noUnknown();\n\nconst uploadSchema = yup.object({\n fileInfo: fileInfoSchema,\n});\n\nconst multiUploadSchema = yup.object({\n fileInfo: yup.array().of(fileInfoSchema),\n});\n\nconst validateUploadBody = (data = {}, isMulti = false) => {\n const schema = isMulti ? multiUploadSchema : uploadSchema;\n\n return validateYupSchema(schema, { strict: false })(data);\n};\n\nexport { validateUploadBody };\n\nexport type UploadBody =\n | yup.InferType<typeof uploadSchema>\n | yup.InferType<typeof multiUploadSchema>;\n"],"names":["fileInfoSchema","yup","object","name","string","nullable","alternativeText","caption","noUnknown","uploadSchema","fileInfo","multiUploadSchema","array","of","validateUploadBody","data","isMulti","schema","validateYupSchema","strict"],"mappings":";;;;AAEA,MAAMA,cAAAA,GAAiBC,SACpBC,CAAAA,MAAM,CAAC;IACNC,IAAMF,EAAAA,SAAAA,CAAIG,MAAM,EAAA,CAAGC,QAAQ,EAAA;IAC3BC,eAAiBL,EAAAA,SAAAA,CAAIG,MAAM,EAAA,CAAGC,QAAQ,EAAA;IACtCE,OAASN,EAAAA,SAAAA,CAAIG,MAAM,EAAA,CAAGC,QAAQ;AAChC,CAAA,CAAA,CACCG,SAAS,EAAA;AAEZ,MAAMC,YAAAA,GAAeR,SAAIC,CAAAA,MAAM,CAAC;IAC9BQ,QAAUV,EAAAA;AACZ,CAAA,CAAA;AAEA,MAAMW,iBAAAA,GAAoBV,SAAIC,CAAAA,MAAM,CAAC;AACnCQ,IAAAA,QAAAA,EAAUT,SAAIW,CAAAA,KAAK,EAAGC,CAAAA,EAAE,CAACb,cAAAA;AAC3B,CAAA,CAAA;AAEA,MAAMc,qBAAqB,CAACC,IAAAA,GAAO,EAAE,EAAEC,UAAU,KAAK,GAAA;IACpD,MAAMC,MAAAA,GAASD,UAAUL,iBAAoBF,GAAAA,YAAAA;AAE7C,IAAA,OAAOS,wBAAkBD,MAAQ,EAAA;QAAEE,MAAQ,EAAA;KAASJ,CAAAA,CAAAA,IAAAA,CAAAA;AACtD;;;;"}
1
+ {"version":3,"file":"upload.js","sources":["../../../../../server/src/controllers/validation/content-api/upload.ts"],"sourcesContent":["import { yup, validateYupSchema } from '@strapi/utils';\n\nconst focalPointSchema = yup\n .object({\n x: yup.number().min(0).max(100).required(),\n y: yup.number().min(0).max(100).required(),\n })\n .nullable()\n .default(null);\n\nconst fileInfoSchema = yup\n .object({\n name: yup.string().nullable(),\n alternativeText: yup.string().nullable(),\n caption: yup.string().nullable(),\n focalPoint: focalPointSchema,\n })\n .noUnknown();\n\nconst uploadSchema = yup.object({\n fileInfo: fileInfoSchema,\n});\n\nconst multiUploadSchema = yup.object({\n fileInfo: yup.array().of(fileInfoSchema),\n});\n\nconst validateUploadBody = (data = {}, isMulti = false) => {\n const schema = isMulti ? multiUploadSchema : uploadSchema;\n\n return validateYupSchema(schema, { strict: false })(data);\n};\n\nexport { validateUploadBody };\n\nexport type UploadBody =\n | yup.InferType<typeof uploadSchema>\n | yup.InferType<typeof multiUploadSchema>;\n"],"names":["focalPointSchema","yup","object","x","number","min","max","required","y","nullable","default","fileInfoSchema","name","string","alternativeText","caption","focalPoint","noUnknown","uploadSchema","fileInfo","multiUploadSchema","array","of","validateUploadBody","data","isMulti","schema","validateYupSchema","strict"],"mappings":";;;;AAEA,MAAMA,gBAAAA,GAAmBC,SACtBC,CAAAA,MAAM,CAAC;IACNC,CAAGF,EAAAA,SAAAA,CAAIG,MAAM,EAAGC,CAAAA,GAAG,CAAC,CAAGC,CAAAA,CAAAA,GAAG,CAAC,GAAA,CAAA,CAAKC,QAAQ,EAAA;IACxCC,CAAGP,EAAAA,SAAAA,CAAIG,MAAM,EAAGC,CAAAA,GAAG,CAAC,CAAGC,CAAAA,CAAAA,GAAG,CAAC,GAAA,CAAA,CAAKC,QAAQ;AAC1C,CACCE,CAAAA,CAAAA,QAAQ,EACRC,CAAAA,OAAO,CAAC,IAAA,CAAA;AAEX,MAAMC,cAAAA,GAAiBV,SACpBC,CAAAA,MAAM,CAAC;IACNU,IAAMX,EAAAA,SAAAA,CAAIY,MAAM,EAAA,CAAGJ,QAAQ,EAAA;IAC3BK,eAAiBb,EAAAA,SAAAA,CAAIY,MAAM,EAAA,CAAGJ,QAAQ,EAAA;IACtCM,OAASd,EAAAA,SAAAA,CAAIY,MAAM,EAAA,CAAGJ,QAAQ,EAAA;IAC9BO,UAAYhB,EAAAA;AACd,CAAA,CAAA,CACCiB,SAAS,EAAA;AAEZ,MAAMC,YAAAA,GAAejB,SAAIC,CAAAA,MAAM,CAAC;IAC9BiB,QAAUR,EAAAA;AACZ,CAAA,CAAA;AAEA,MAAMS,iBAAAA,GAAoBnB,SAAIC,CAAAA,MAAM,CAAC;AACnCiB,IAAAA,QAAAA,EAAUlB,SAAIoB,CAAAA,KAAK,EAAGC,CAAAA,EAAE,CAACX,cAAAA;AAC3B,CAAA,CAAA;AAEA,MAAMY,qBAAqB,CAACC,IAAAA,GAAO,EAAE,EAAEC,UAAU,KAAK,GAAA;IACpD,MAAMC,MAAAA,GAASD,UAAUL,iBAAoBF,GAAAA,YAAAA;AAE7C,IAAA,OAAOS,wBAAkBD,MAAQ,EAAA;QAAEE,MAAQ,EAAA;KAASJ,CAAAA,CAAAA,IAAAA,CAAAA;AACtD;;;;"}