@strapi/i18n 5.42.0 → 5.43.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 (90) hide show
  1. package/dist/admin/components/CMHeaderActions.js +28 -25
  2. package/dist/admin/components/CMHeaderActions.js.map +1 -1
  3. package/dist/admin/components/CMHeaderActions.mjs +26 -23
  4. package/dist/admin/components/CMHeaderActions.mjs.map +1 -1
  5. package/dist/admin/index.js +1 -0
  6. package/dist/admin/index.js.map +1 -1
  7. package/dist/admin/index.mjs +1 -0
  8. package/dist/admin/index.mjs.map +1 -1
  9. package/dist/admin/services/fillFromLocale.js +21 -0
  10. package/dist/admin/services/fillFromLocale.js.map +1 -0
  11. package/dist/admin/services/fillFromLocale.mjs +18 -0
  12. package/dist/admin/services/fillFromLocale.mjs.map +1 -0
  13. package/dist/admin/services/settings.js +1 -1
  14. package/dist/admin/services/settings.js.map +1 -1
  15. package/dist/admin/services/settings.mjs +1 -1
  16. package/dist/admin/services/settings.mjs.map +1 -1
  17. package/dist/admin/src/services/aiLocalizationJobs.d.ts +1 -1
  18. package/dist/admin/src/services/api.d.ts +1 -1
  19. package/dist/admin/src/services/fillFromLocale.d.ts +2 -0
  20. package/dist/admin/src/services/locales.d.ts +1 -1
  21. package/dist/admin/src/services/relations.d.ts +1 -1
  22. package/dist/admin/src/services/settings.d.ts +2 -2
  23. package/dist/admin/translations/nl.json.js +91 -0
  24. package/dist/admin/translations/nl.json.js.map +1 -0
  25. package/dist/admin/translations/nl.json.mjs +89 -0
  26. package/dist/admin/translations/nl.json.mjs.map +1 -0
  27. package/dist/admin/translations/pl.json.js +48 -23
  28. package/dist/admin/translations/pl.json.js.map +1 -1
  29. package/dist/admin/translations/pl.json.mjs +48 -23
  30. package/dist/admin/translations/pl.json.mjs.map +1 -1
  31. package/dist/server/bootstrap.js +3 -1
  32. package/dist/server/bootstrap.js.map +1 -1
  33. package/dist/server/bootstrap.mjs +3 -1
  34. package/dist/server/bootstrap.mjs.map +1 -1
  35. package/dist/server/controllers/ai-localization-jobs.js +8 -0
  36. package/dist/server/controllers/ai-localization-jobs.js.map +1 -1
  37. package/dist/server/controllers/ai-localization-jobs.mjs +8 -0
  38. package/dist/server/controllers/ai-localization-jobs.mjs.map +1 -1
  39. package/dist/server/controllers/content-types.js +42 -2
  40. package/dist/server/controllers/content-types.js.map +1 -1
  41. package/dist/server/controllers/content-types.mjs +43 -3
  42. package/dist/server/controllers/content-types.mjs.map +1 -1
  43. package/dist/server/routes/admin.js +18 -0
  44. package/dist/server/routes/admin.js.map +1 -1
  45. package/dist/server/routes/admin.mjs +18 -0
  46. package/dist/server/routes/admin.mjs.map +1 -1
  47. package/dist/server/services/ai-localizations.js +3 -13
  48. package/dist/server/services/ai-localizations.js.map +1 -1
  49. package/dist/server/services/ai-localizations.mjs +3 -13
  50. package/dist/server/services/ai-localizations.mjs.map +1 -1
  51. package/dist/server/services/fill-from-locale.js +435 -0
  52. package/dist/server/services/fill-from-locale.js.map +1 -0
  53. package/dist/server/services/fill-from-locale.mjs +433 -0
  54. package/dist/server/services/fill-from-locale.mjs.map +1 -0
  55. package/dist/server/services/index.js +3 -1
  56. package/dist/server/services/index.js.map +1 -1
  57. package/dist/server/services/index.mjs +3 -1
  58. package/dist/server/services/index.mjs.map +1 -1
  59. package/dist/server/src/bootstrap.d.ts.map +1 -1
  60. package/dist/server/src/controllers/ai-localization-jobs.d.ts.map +1 -1
  61. package/dist/server/src/controllers/content-types.d.ts +1 -0
  62. package/dist/server/src/controllers/content-types.d.ts.map +1 -1
  63. package/dist/server/src/controllers/index.d.ts +1 -0
  64. package/dist/server/src/controllers/index.d.ts.map +1 -1
  65. package/dist/server/src/index.d.ts +7 -0
  66. package/dist/server/src/index.d.ts.map +1 -1
  67. package/dist/server/src/routes/admin.d.ts.map +1 -1
  68. package/dist/server/src/services/ai-localizations.d.ts.map +1 -1
  69. package/dist/server/src/services/fill-from-locale.d.ts +16 -0
  70. package/dist/server/src/services/fill-from-locale.d.ts.map +1 -0
  71. package/dist/server/src/services/index.d.ts +6 -0
  72. package/dist/server/src/services/index.d.ts.map +1 -1
  73. package/dist/server/src/utils/index.d.ts +2 -0
  74. package/dist/server/src/utils/index.d.ts.map +1 -1
  75. package/dist/server/src/validation/content-types.d.ts +2 -1
  76. package/dist/server/src/validation/content-types.d.ts.map +1 -1
  77. package/dist/server/utils/index.js.map +1 -1
  78. package/dist/server/utils/index.mjs.map +1 -1
  79. package/dist/server/validation/content-types.js +15 -0
  80. package/dist/server/validation/content-types.js.map +1 -1
  81. package/dist/server/validation/content-types.mjs +15 -1
  82. package/dist/server/validation/content-types.mjs.map +1 -1
  83. package/dist/shared/contracts/content-manager.d.ts +27 -0
  84. package/dist/shared/contracts/content-manager.d.ts.map +1 -0
  85. package/package.json +8 -8
  86. package/dist/admin/src/utils/clean.d.ts +0 -4
  87. package/dist/admin/utils/clean.js +0 -70
  88. package/dist/admin/utils/clean.js.map +0 -1
  89. package/dist/admin/utils/clean.mjs +0 -68
  90. package/dist/admin/utils/clean.mjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"bootstrap.mjs","sources":["../../server/src/bootstrap.ts"],"sourcesContent":["import type { Schema } from '@strapi/types';\nimport { isEqual } from 'lodash/fp';\nimport { getService } from './utils';\n\nconst registerModelsHooks = () => {\n strapi.db.lifecycles.subscribe({\n models: ['plugin::i18n.locale'],\n\n async afterCreate() {\n await getService('permissions').actions.syncSuperAdminPermissionsWithLocales();\n },\n\n async afterDelete() {\n await getService('permissions').actions.syncSuperAdminPermissionsWithLocales();\n },\n });\n\n strapi.documents.use(async (context, next) => {\n const schema: Schema.ContentType = context.contentType;\n\n if (!['create', 'update', 'discardDraft', 'publish'].includes(context.action)) {\n return next();\n }\n\n if (!getService('content-types').isLocalizedContentType(schema)) {\n return next();\n }\n\n // Build a populate array for all non localized fields within the schema\n const { getNestedPopulateOfNonLocalizedAttributes, copyNonLocalizedAttributes } =\n getService('content-types');\n const attributesToPopulate = getNestedPopulateOfNonLocalizedAttributes(schema.uid);\n\n // Get original data before the update to compare what actually changed\n const originalData =\n 'documentId' in context.params && context.params.documentId\n ? await strapi.db.query(schema.uid).findOne({\n where: { documentId: context.params.documentId },\n populate: attributesToPopulate,\n })\n : null;\n\n // Get the result of the document service action\n const result = (await next()) as any;\n\n // We may not have received a result with everything populated that we need\n // Use the id and populate built from non localized fields to get the full\n // result\n let resultID;\n // TODO: fix bug where an empty array can be returned\n if (Array.isArray(result?.entries) && result.entries[0]?.id) {\n resultID = result.entries[0].id;\n } else if (result?.id) {\n resultID = result.id;\n } else {\n return result;\n }\n\n const populatedResult = await strapi.db.query(schema.uid).findOne({\n where: { id: resultID },\n populate: attributesToPopulate,\n });\n\n const originalFields = copyNonLocalizedAttributes(schema, originalData);\n const currentFields = copyNonLocalizedAttributes(schema, populatedResult);\n\n // Only sync if there are actual changes to non-localized fields\n const shouldSync =\n !originalData ||\n Object.keys(currentFields).some((key) => {\n return !isEqual(currentFields[key], originalFields[key]);\n });\n\n if (shouldSync) {\n await getService('localizations').syncNonLocalizedAttributes(populatedResult, schema);\n }\n\n return result;\n });\n};\n\nexport default async () => {\n const { sendDidInitializeEvent } = getService('metrics');\n const { initDefaultLocale } = getService('locales');\n const { sectionsBuilder, actions, engine } = getService('permissions');\n\n // Data\n await initDefaultLocale();\n\n // Sections Builder\n sectionsBuilder.registerLocalesPropertyHandler();\n\n // Actions\n await actions.registerI18nActions();\n actions.registerI18nActionsHooks();\n actions.updateActionsProperties();\n\n // Engine/Permissions\n engine.registerI18nPermissionsHandlers();\n\n // Hooks & Models\n registerModelsHooks();\n\n // AI Localizations\n getService('ai-localizations').setupMiddleware();\n\n sendDidInitializeEvent();\n};\n"],"names":["registerModelsHooks","strapi","db","lifecycles","subscribe","models","afterCreate","getService","actions","syncSuperAdminPermissionsWithLocales","afterDelete","documents","use","context","next","schema","contentType","includes","action","isLocalizedContentType","getNestedPopulateOfNonLocalizedAttributes","copyNonLocalizedAttributes","attributesToPopulate","uid","originalData","params","documentId","query","findOne","where","populate","result","resultID","Array","isArray","entries","id","populatedResult","originalFields","currentFields","shouldSync","Object","keys","some","key","isEqual","syncNonLocalizedAttributes","sendDidInitializeEvent","initDefaultLocale","sectionsBuilder","engine","registerLocalesPropertyHandler","registerI18nActions","registerI18nActionsHooks","updateActionsProperties","registerI18nPermissionsHandlers","setupMiddleware"],"mappings":"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"}
1
+ {"version":3,"file":"bootstrap.mjs","sources":["../../server/src/bootstrap.ts"],"sourcesContent":["import type { Schema } from '@strapi/types';\nimport { isEqual } from 'lodash/fp';\nimport { getService } from './utils';\n\nconst registerModelsHooks = () => {\n strapi.db.lifecycles.subscribe({\n models: ['plugin::i18n.locale'],\n\n async afterCreate() {\n await getService('permissions').actions.syncSuperAdminPermissionsWithLocales();\n },\n\n async afterDelete() {\n await getService('permissions').actions.syncSuperAdminPermissionsWithLocales();\n },\n });\n\n strapi.documents.use(async (context, next) => {\n const schema: Schema.ContentType = context.contentType;\n\n if (!['create', 'update', 'discardDraft', 'publish'].includes(context.action)) {\n return next();\n }\n\n if (!getService('content-types').isLocalizedContentType(schema)) {\n return next();\n }\n\n // Build a populate array for all non localized fields within the schema\n const { getNestedPopulateOfNonLocalizedAttributes, copyNonLocalizedAttributes } =\n getService('content-types');\n const attributesToPopulate = getNestedPopulateOfNonLocalizedAttributes(schema.uid);\n\n // Get original data before the update to compare what actually changed\n const originalData =\n 'documentId' in context.params && context.params.documentId\n ? await strapi.db.query(schema.uid).findOne({\n where: { documentId: context.params.documentId },\n populate: attributesToPopulate,\n })\n : null;\n\n // Get the result of the document service action\n const result = (await next()) as any;\n\n // We may not have received a result with everything populated that we need\n // Use the id and populate built from non localized fields to get the full\n // result\n let resultID;\n // TODO: fix bug where an empty array can be returned\n if (Array.isArray(result?.entries) && result.entries[0]?.id) {\n resultID = result.entries[0].id;\n } else if (result?.id) {\n resultID = result.id;\n } else {\n return result;\n }\n\n const populatedResult = await strapi.db.query(schema.uid).findOne({\n where: { id: resultID },\n populate: attributesToPopulate,\n });\n\n const originalFields = copyNonLocalizedAttributes(schema, originalData);\n const currentFields = copyNonLocalizedAttributes(schema, populatedResult);\n\n // Only sync if there are actual changes to non-localized fields\n const shouldSync =\n !originalData ||\n Object.keys(currentFields).some((key) => {\n return !isEqual(currentFields[key], originalFields[key]);\n });\n\n if (shouldSync) {\n await getService('localizations').syncNonLocalizedAttributes(populatedResult, schema);\n }\n\n return result;\n });\n};\n\nexport default async () => {\n const { sendDidInitializeEvent } = getService('metrics');\n const { initDefaultLocale } = getService('locales');\n const { sectionsBuilder, actions, engine } = getService('permissions');\n\n // Data\n await initDefaultLocale();\n\n // Sections Builder\n sectionsBuilder.registerLocalesPropertyHandler();\n\n // Actions\n await actions.registerI18nActions();\n actions.registerI18nActionsHooks();\n actions.updateActionsProperties();\n\n // Engine/Permissions\n engine.registerI18nPermissionsHandlers();\n\n // Hooks & Models\n registerModelsHooks();\n\n // AI Localizations\n if (strapi.ai.admin.isEnabled() === true) {\n getService('ai-localizations').setupMiddleware();\n }\n\n sendDidInitializeEvent();\n};\n"],"names":["registerModelsHooks","strapi","db","lifecycles","subscribe","models","afterCreate","getService","actions","syncSuperAdminPermissionsWithLocales","afterDelete","documents","use","context","next","schema","contentType","includes","action","isLocalizedContentType","getNestedPopulateOfNonLocalizedAttributes","copyNonLocalizedAttributes","attributesToPopulate","uid","originalData","params","documentId","query","findOne","where","populate","result","resultID","Array","isArray","entries","id","populatedResult","originalFields","currentFields","shouldSync","Object","keys","some","key","isEqual","syncNonLocalizedAttributes","sendDidInitializeEvent","initDefaultLocale","sectionsBuilder","engine","registerLocalesPropertyHandler","registerI18nActions","registerI18nActionsHooks","updateActionsProperties","registerI18nPermissionsHandlers","ai","admin","isEnabled","setupMiddleware"],"mappings":"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"}
@@ -8,6 +8,10 @@ const createAILocalizationJobsController = ({ strapi })=>{
8
8
  * Get a job for a singleType using the contentType
9
9
  * There is only 1 job per contentType
10
10
  */ async getJobForSingleType (ctx) {
11
+ const aiLocalizationsService = getService('ai-localizations');
12
+ if (await aiLocalizationsService.isEnabled() === false) {
13
+ return ctx.notFound();
14
+ }
11
15
  const { contentType } = ctx.params;
12
16
  if (!contentType) {
13
17
  return ctx.badRequest('contentType is required');
@@ -26,6 +30,10 @@ const createAILocalizationJobsController = ({ strapi })=>{
26
30
  * Get a job for a collectionType using the documentId
27
31
  * There is only 1 job per documentId
28
32
  */ async getJobForCollectionType (ctx) {
33
+ const aiLocalizationsService = getService('ai-localizations');
34
+ if (await aiLocalizationsService.isEnabled() === false) {
35
+ return ctx.notFound();
36
+ }
29
37
  const { documentId, contentType } = ctx.params;
30
38
  if (!documentId || !contentType) {
31
39
  return ctx.badRequest('Document ID and contentType are required');
@@ -1 +1 @@
1
- {"version":3,"file":"ai-localization-jobs.js","sources":["../../../server/src/controllers/ai-localization-jobs.ts"],"sourcesContent":["import type { Core } from '@strapi/types';\n\nconst createAILocalizationJobsController = ({ strapi }: { strapi: Core.Strapi }) => {\n const getService = (name: string) => strapi.plugin('i18n').service(name);\n const aiLocalizationJobsService = getService('ai-localization-jobs');\n\n return {\n /**\n * Get a job for a singleType using the contentType\n * There is only 1 job per contentType\n */\n async getJobForSingleType(ctx: any) {\n const { contentType } = ctx.params;\n\n if (!contentType) {\n return ctx.badRequest('contentType is required');\n }\n\n try {\n const job = await aiLocalizationJobsService.getJobByContentType(contentType);\n\n ctx.body = {\n data: job,\n };\n } catch (error) {\n strapi.log.error('[AI Localizations Jobs] Error fetching job:', error);\n ctx.internalServerError('Failed to fetch AI localizations job');\n }\n },\n /**\n * Get a job for a collectionType using the documentId\n * There is only 1 job per documentId\n */\n async getJobForCollectionType(ctx: any) {\n const { documentId, contentType } = ctx.params;\n\n if (!documentId || !contentType) {\n return ctx.badRequest('Document ID and contentType are required');\n }\n\n try {\n const job = await aiLocalizationJobsService.getJobByDocument(contentType, documentId);\n\n ctx.body = {\n data: job,\n };\n } catch (error) {\n strapi.log.error('[AI Localizations Jobs] Error fetching job:', error);\n ctx.internalServerError('Failed to fetch AI localizations job');\n }\n },\n };\n};\n\nexport default createAILocalizationJobsController;\n"],"names":["createAILocalizationJobsController","strapi","getService","name","plugin","service","aiLocalizationJobsService","getJobForSingleType","ctx","contentType","params","badRequest","job","getJobByContentType","body","data","error","log","internalServerError","getJobForCollectionType","documentId","getJobByDocument"],"mappings":";;AAEA,MAAMA,kCAAAA,GAAqC,CAAC,EAAEC,MAAM,EAA2B,GAAA;IAC7E,MAAMC,UAAAA,GAAa,CAACC,IAAAA,GAAiBF,MAAAA,CAAOG,MAAM,CAAC,MAAA,CAAA,CAAQC,OAAO,CAACF,IAAAA,CAAAA;AACnE,IAAA,MAAMG,4BAA4BJ,UAAAA,CAAW,sBAAA,CAAA;IAE7C,OAAO;AACL;;;QAIA,MAAMK,qBAAoBC,GAAQ,EAAA;AAChC,YAAA,MAAM,EAAEC,WAAW,EAAE,GAAGD,IAAIE,MAAM;AAElC,YAAA,IAAI,CAACD,WAAAA,EAAa;gBAChB,OAAOD,GAAAA,CAAIG,UAAU,CAAC,yBAAA,CAAA;AACxB,YAAA;YAEA,IAAI;AACF,gBAAA,MAAMC,GAAAA,GAAM,MAAMN,yBAAAA,CAA0BO,mBAAmB,CAACJ,WAAAA,CAAAA;AAEhED,gBAAAA,GAAAA,CAAIM,IAAI,GAAG;oBACTC,IAAAA,EAAMH;AACR,iBAAA;AACF,YAAA,CAAA,CAAE,OAAOI,KAAAA,EAAO;AACdf,gBAAAA,MAAAA,CAAOgB,GAAG,CAACD,KAAK,CAAC,6CAAA,EAA+CA,KAAAA,CAAAA;AAChER,gBAAAA,GAAAA,CAAIU,mBAAmB,CAAC,sCAAA,CAAA;AAC1B,YAAA;AACF,QAAA,CAAA;AACA;;;QAIA,MAAMC,yBAAwBX,GAAQ,EAAA;AACpC,YAAA,MAAM,EAAEY,UAAU,EAAEX,WAAW,EAAE,GAAGD,IAAIE,MAAM;YAE9C,IAAI,CAACU,UAAAA,IAAc,CAACX,WAAAA,EAAa;gBAC/B,OAAOD,GAAAA,CAAIG,UAAU,CAAC,0CAAA,CAAA;AACxB,YAAA;YAEA,IAAI;AACF,gBAAA,MAAMC,GAAAA,GAAM,MAAMN,yBAAAA,CAA0Be,gBAAgB,CAACZ,WAAAA,EAAaW,UAAAA,CAAAA;AAE1EZ,gBAAAA,GAAAA,CAAIM,IAAI,GAAG;oBACTC,IAAAA,EAAMH;AACR,iBAAA;AACF,YAAA,CAAA,CAAE,OAAOI,KAAAA,EAAO;AACdf,gBAAAA,MAAAA,CAAOgB,GAAG,CAACD,KAAK,CAAC,6CAAA,EAA+CA,KAAAA,CAAAA;AAChER,gBAAAA,GAAAA,CAAIU,mBAAmB,CAAC,sCAAA,CAAA;AAC1B,YAAA;AACF,QAAA;AACF,KAAA;AACF;;;;"}
1
+ {"version":3,"file":"ai-localization-jobs.js","sources":["../../../server/src/controllers/ai-localization-jobs.ts"],"sourcesContent":["import type { Core } from '@strapi/types';\n\nconst createAILocalizationJobsController = ({ strapi }: { strapi: Core.Strapi }) => {\n const getService = (name: string) => strapi.plugin('i18n').service(name);\n const aiLocalizationJobsService = getService('ai-localization-jobs');\n\n return {\n /**\n * Get a job for a singleType using the contentType\n * There is only 1 job per contentType\n */\n async getJobForSingleType(ctx: any) {\n const aiLocalizationsService = getService('ai-localizations');\n if ((await aiLocalizationsService.isEnabled()) === false) {\n return ctx.notFound();\n }\n\n const { contentType } = ctx.params;\n\n if (!contentType) {\n return ctx.badRequest('contentType is required');\n }\n\n try {\n const job = await aiLocalizationJobsService.getJobByContentType(contentType);\n\n ctx.body = {\n data: job,\n };\n } catch (error) {\n strapi.log.error('[AI Localizations Jobs] Error fetching job:', error);\n ctx.internalServerError('Failed to fetch AI localizations job');\n }\n },\n /**\n * Get a job for a collectionType using the documentId\n * There is only 1 job per documentId\n */\n async getJobForCollectionType(ctx: any) {\n const aiLocalizationsService = getService('ai-localizations');\n if ((await aiLocalizationsService.isEnabled()) === false) {\n return ctx.notFound();\n }\n\n const { documentId, contentType } = ctx.params;\n\n if (!documentId || !contentType) {\n return ctx.badRequest('Document ID and contentType are required');\n }\n\n try {\n const job = await aiLocalizationJobsService.getJobByDocument(contentType, documentId);\n\n ctx.body = {\n data: job,\n };\n } catch (error) {\n strapi.log.error('[AI Localizations Jobs] Error fetching job:', error);\n ctx.internalServerError('Failed to fetch AI localizations job');\n }\n },\n };\n};\n\nexport default createAILocalizationJobsController;\n"],"names":["createAILocalizationJobsController","strapi","getService","name","plugin","service","aiLocalizationJobsService","getJobForSingleType","ctx","aiLocalizationsService","isEnabled","notFound","contentType","params","badRequest","job","getJobByContentType","body","data","error","log","internalServerError","getJobForCollectionType","documentId","getJobByDocument"],"mappings":";;AAEA,MAAMA,kCAAAA,GAAqC,CAAC,EAAEC,MAAM,EAA2B,GAAA;IAC7E,MAAMC,UAAAA,GAAa,CAACC,IAAAA,GAAiBF,MAAAA,CAAOG,MAAM,CAAC,MAAA,CAAA,CAAQC,OAAO,CAACF,IAAAA,CAAAA;AACnE,IAAA,MAAMG,4BAA4BJ,UAAAA,CAAW,sBAAA,CAAA;IAE7C,OAAO;AACL;;;QAIA,MAAMK,qBAAoBC,GAAQ,EAAA;AAChC,YAAA,MAAMC,yBAAyBP,UAAAA,CAAW,kBAAA,CAAA;AAC1C,YAAA,IAAI,MAAOO,sBAAAA,CAAuBC,SAAS,OAAQ,KAAA,EAAO;AACxD,gBAAA,OAAOF,IAAIG,QAAQ,EAAA;AACrB,YAAA;AAEA,YAAA,MAAM,EAAEC,WAAW,EAAE,GAAGJ,IAAIK,MAAM;AAElC,YAAA,IAAI,CAACD,WAAAA,EAAa;gBAChB,OAAOJ,GAAAA,CAAIM,UAAU,CAAC,yBAAA,CAAA;AACxB,YAAA;YAEA,IAAI;AACF,gBAAA,MAAMC,GAAAA,GAAM,MAAMT,yBAAAA,CAA0BU,mBAAmB,CAACJ,WAAAA,CAAAA;AAEhEJ,gBAAAA,GAAAA,CAAIS,IAAI,GAAG;oBACTC,IAAAA,EAAMH;AACR,iBAAA;AACF,YAAA,CAAA,CAAE,OAAOI,KAAAA,EAAO;AACdlB,gBAAAA,MAAAA,CAAOmB,GAAG,CAACD,KAAK,CAAC,6CAAA,EAA+CA,KAAAA,CAAAA;AAChEX,gBAAAA,GAAAA,CAAIa,mBAAmB,CAAC,sCAAA,CAAA;AAC1B,YAAA;AACF,QAAA,CAAA;AACA;;;QAIA,MAAMC,yBAAwBd,GAAQ,EAAA;AACpC,YAAA,MAAMC,yBAAyBP,UAAAA,CAAW,kBAAA,CAAA;AAC1C,YAAA,IAAI,MAAOO,sBAAAA,CAAuBC,SAAS,OAAQ,KAAA,EAAO;AACxD,gBAAA,OAAOF,IAAIG,QAAQ,EAAA;AACrB,YAAA;AAEA,YAAA,MAAM,EAAEY,UAAU,EAAEX,WAAW,EAAE,GAAGJ,IAAIK,MAAM;YAE9C,IAAI,CAACU,UAAAA,IAAc,CAACX,WAAAA,EAAa;gBAC/B,OAAOJ,GAAAA,CAAIM,UAAU,CAAC,0CAAA,CAAA;AACxB,YAAA;YAEA,IAAI;AACF,gBAAA,MAAMC,GAAAA,GAAM,MAAMT,yBAAAA,CAA0BkB,gBAAgB,CAACZ,WAAAA,EAAaW,UAAAA,CAAAA;AAE1Ef,gBAAAA,GAAAA,CAAIS,IAAI,GAAG;oBACTC,IAAAA,EAAMH;AACR,iBAAA;AACF,YAAA,CAAA,CAAE,OAAOI,KAAAA,EAAO;AACdlB,gBAAAA,MAAAA,CAAOmB,GAAG,CAACD,KAAK,CAAC,6CAAA,EAA+CA,KAAAA,CAAAA;AAChEX,gBAAAA,GAAAA,CAAIa,mBAAmB,CAAC,sCAAA,CAAA;AAC1B,YAAA;AACF,QAAA;AACF,KAAA;AACF;;;;"}
@@ -6,6 +6,10 @@ const createAILocalizationJobsController = ({ strapi })=>{
6
6
  * Get a job for a singleType using the contentType
7
7
  * There is only 1 job per contentType
8
8
  */ async getJobForSingleType (ctx) {
9
+ const aiLocalizationsService = getService('ai-localizations');
10
+ if (await aiLocalizationsService.isEnabled() === false) {
11
+ return ctx.notFound();
12
+ }
9
13
  const { contentType } = ctx.params;
10
14
  if (!contentType) {
11
15
  return ctx.badRequest('contentType is required');
@@ -24,6 +28,10 @@ const createAILocalizationJobsController = ({ strapi })=>{
24
28
  * Get a job for a collectionType using the documentId
25
29
  * There is only 1 job per documentId
26
30
  */ async getJobForCollectionType (ctx) {
31
+ const aiLocalizationsService = getService('ai-localizations');
32
+ if (await aiLocalizationsService.isEnabled() === false) {
33
+ return ctx.notFound();
34
+ }
27
35
  const { documentId, contentType } = ctx.params;
28
36
  if (!documentId || !contentType) {
29
37
  return ctx.badRequest('Document ID and contentType are required');
@@ -1 +1 @@
1
- {"version":3,"file":"ai-localization-jobs.mjs","sources":["../../../server/src/controllers/ai-localization-jobs.ts"],"sourcesContent":["import type { Core } from '@strapi/types';\n\nconst createAILocalizationJobsController = ({ strapi }: { strapi: Core.Strapi }) => {\n const getService = (name: string) => strapi.plugin('i18n').service(name);\n const aiLocalizationJobsService = getService('ai-localization-jobs');\n\n return {\n /**\n * Get a job for a singleType using the contentType\n * There is only 1 job per contentType\n */\n async getJobForSingleType(ctx: any) {\n const { contentType } = ctx.params;\n\n if (!contentType) {\n return ctx.badRequest('contentType is required');\n }\n\n try {\n const job = await aiLocalizationJobsService.getJobByContentType(contentType);\n\n ctx.body = {\n data: job,\n };\n } catch (error) {\n strapi.log.error('[AI Localizations Jobs] Error fetching job:', error);\n ctx.internalServerError('Failed to fetch AI localizations job');\n }\n },\n /**\n * Get a job for a collectionType using the documentId\n * There is only 1 job per documentId\n */\n async getJobForCollectionType(ctx: any) {\n const { documentId, contentType } = ctx.params;\n\n if (!documentId || !contentType) {\n return ctx.badRequest('Document ID and contentType are required');\n }\n\n try {\n const job = await aiLocalizationJobsService.getJobByDocument(contentType, documentId);\n\n ctx.body = {\n data: job,\n };\n } catch (error) {\n strapi.log.error('[AI Localizations Jobs] Error fetching job:', error);\n ctx.internalServerError('Failed to fetch AI localizations job');\n }\n },\n };\n};\n\nexport default createAILocalizationJobsController;\n"],"names":["createAILocalizationJobsController","strapi","getService","name","plugin","service","aiLocalizationJobsService","getJobForSingleType","ctx","contentType","params","badRequest","job","getJobByContentType","body","data","error","log","internalServerError","getJobForCollectionType","documentId","getJobByDocument"],"mappings":"AAEA,MAAMA,kCAAAA,GAAqC,CAAC,EAAEC,MAAM,EAA2B,GAAA;IAC7E,MAAMC,UAAAA,GAAa,CAACC,IAAAA,GAAiBF,MAAAA,CAAOG,MAAM,CAAC,MAAA,CAAA,CAAQC,OAAO,CAACF,IAAAA,CAAAA;AACnE,IAAA,MAAMG,4BAA4BJ,UAAAA,CAAW,sBAAA,CAAA;IAE7C,OAAO;AACL;;;QAIA,MAAMK,qBAAoBC,GAAQ,EAAA;AAChC,YAAA,MAAM,EAAEC,WAAW,EAAE,GAAGD,IAAIE,MAAM;AAElC,YAAA,IAAI,CAACD,WAAAA,EAAa;gBAChB,OAAOD,GAAAA,CAAIG,UAAU,CAAC,yBAAA,CAAA;AACxB,YAAA;YAEA,IAAI;AACF,gBAAA,MAAMC,GAAAA,GAAM,MAAMN,yBAAAA,CAA0BO,mBAAmB,CAACJ,WAAAA,CAAAA;AAEhED,gBAAAA,GAAAA,CAAIM,IAAI,GAAG;oBACTC,IAAAA,EAAMH;AACR,iBAAA;AACF,YAAA,CAAA,CAAE,OAAOI,KAAAA,EAAO;AACdf,gBAAAA,MAAAA,CAAOgB,GAAG,CAACD,KAAK,CAAC,6CAAA,EAA+CA,KAAAA,CAAAA;AAChER,gBAAAA,GAAAA,CAAIU,mBAAmB,CAAC,sCAAA,CAAA;AAC1B,YAAA;AACF,QAAA,CAAA;AACA;;;QAIA,MAAMC,yBAAwBX,GAAQ,EAAA;AACpC,YAAA,MAAM,EAAEY,UAAU,EAAEX,WAAW,EAAE,GAAGD,IAAIE,MAAM;YAE9C,IAAI,CAACU,UAAAA,IAAc,CAACX,WAAAA,EAAa;gBAC/B,OAAOD,GAAAA,CAAIG,UAAU,CAAC,0CAAA,CAAA;AACxB,YAAA;YAEA,IAAI;AACF,gBAAA,MAAMC,GAAAA,GAAM,MAAMN,yBAAAA,CAA0Be,gBAAgB,CAACZ,WAAAA,EAAaW,UAAAA,CAAAA;AAE1EZ,gBAAAA,GAAAA,CAAIM,IAAI,GAAG;oBACTC,IAAAA,EAAMH;AACR,iBAAA;AACF,YAAA,CAAA,CAAE,OAAOI,KAAAA,EAAO;AACdf,gBAAAA,MAAAA,CAAOgB,GAAG,CAACD,KAAK,CAAC,6CAAA,EAA+CA,KAAAA,CAAAA;AAChER,gBAAAA,GAAAA,CAAIU,mBAAmB,CAAC,sCAAA,CAAA;AAC1B,YAAA;AACF,QAAA;AACF,KAAA;AACF;;;;"}
1
+ {"version":3,"file":"ai-localization-jobs.mjs","sources":["../../../server/src/controllers/ai-localization-jobs.ts"],"sourcesContent":["import type { Core } from '@strapi/types';\n\nconst createAILocalizationJobsController = ({ strapi }: { strapi: Core.Strapi }) => {\n const getService = (name: string) => strapi.plugin('i18n').service(name);\n const aiLocalizationJobsService = getService('ai-localization-jobs');\n\n return {\n /**\n * Get a job for a singleType using the contentType\n * There is only 1 job per contentType\n */\n async getJobForSingleType(ctx: any) {\n const aiLocalizationsService = getService('ai-localizations');\n if ((await aiLocalizationsService.isEnabled()) === false) {\n return ctx.notFound();\n }\n\n const { contentType } = ctx.params;\n\n if (!contentType) {\n return ctx.badRequest('contentType is required');\n }\n\n try {\n const job = await aiLocalizationJobsService.getJobByContentType(contentType);\n\n ctx.body = {\n data: job,\n };\n } catch (error) {\n strapi.log.error('[AI Localizations Jobs] Error fetching job:', error);\n ctx.internalServerError('Failed to fetch AI localizations job');\n }\n },\n /**\n * Get a job for a collectionType using the documentId\n * There is only 1 job per documentId\n */\n async getJobForCollectionType(ctx: any) {\n const aiLocalizationsService = getService('ai-localizations');\n if ((await aiLocalizationsService.isEnabled()) === false) {\n return ctx.notFound();\n }\n\n const { documentId, contentType } = ctx.params;\n\n if (!documentId || !contentType) {\n return ctx.badRequest('Document ID and contentType are required');\n }\n\n try {\n const job = await aiLocalizationJobsService.getJobByDocument(contentType, documentId);\n\n ctx.body = {\n data: job,\n };\n } catch (error) {\n strapi.log.error('[AI Localizations Jobs] Error fetching job:', error);\n ctx.internalServerError('Failed to fetch AI localizations job');\n }\n },\n };\n};\n\nexport default createAILocalizationJobsController;\n"],"names":["createAILocalizationJobsController","strapi","getService","name","plugin","service","aiLocalizationJobsService","getJobForSingleType","ctx","aiLocalizationsService","isEnabled","notFound","contentType","params","badRequest","job","getJobByContentType","body","data","error","log","internalServerError","getJobForCollectionType","documentId","getJobByDocument"],"mappings":"AAEA,MAAMA,kCAAAA,GAAqC,CAAC,EAAEC,MAAM,EAA2B,GAAA;IAC7E,MAAMC,UAAAA,GAAa,CAACC,IAAAA,GAAiBF,MAAAA,CAAOG,MAAM,CAAC,MAAA,CAAA,CAAQC,OAAO,CAACF,IAAAA,CAAAA;AACnE,IAAA,MAAMG,4BAA4BJ,UAAAA,CAAW,sBAAA,CAAA;IAE7C,OAAO;AACL;;;QAIA,MAAMK,qBAAoBC,GAAQ,EAAA;AAChC,YAAA,MAAMC,yBAAyBP,UAAAA,CAAW,kBAAA,CAAA;AAC1C,YAAA,IAAI,MAAOO,sBAAAA,CAAuBC,SAAS,OAAQ,KAAA,EAAO;AACxD,gBAAA,OAAOF,IAAIG,QAAQ,EAAA;AACrB,YAAA;AAEA,YAAA,MAAM,EAAEC,WAAW,EAAE,GAAGJ,IAAIK,MAAM;AAElC,YAAA,IAAI,CAACD,WAAAA,EAAa;gBAChB,OAAOJ,GAAAA,CAAIM,UAAU,CAAC,yBAAA,CAAA;AACxB,YAAA;YAEA,IAAI;AACF,gBAAA,MAAMC,GAAAA,GAAM,MAAMT,yBAAAA,CAA0BU,mBAAmB,CAACJ,WAAAA,CAAAA;AAEhEJ,gBAAAA,GAAAA,CAAIS,IAAI,GAAG;oBACTC,IAAAA,EAAMH;AACR,iBAAA;AACF,YAAA,CAAA,CAAE,OAAOI,KAAAA,EAAO;AACdlB,gBAAAA,MAAAA,CAAOmB,GAAG,CAACD,KAAK,CAAC,6CAAA,EAA+CA,KAAAA,CAAAA;AAChEX,gBAAAA,GAAAA,CAAIa,mBAAmB,CAAC,sCAAA,CAAA;AAC1B,YAAA;AACF,QAAA,CAAA;AACA;;;QAIA,MAAMC,yBAAwBd,GAAQ,EAAA;AACpC,YAAA,MAAMC,yBAAyBP,UAAAA,CAAW,kBAAA,CAAA;AAC1C,YAAA,IAAI,MAAOO,sBAAAA,CAAuBC,SAAS,OAAQ,KAAA,EAAO;AACxD,gBAAA,OAAOF,IAAIG,QAAQ,EAAA;AACrB,YAAA;AAEA,YAAA,MAAM,EAAEY,UAAU,EAAEX,WAAW,EAAE,GAAGJ,IAAIK,MAAM;YAE9C,IAAI,CAACU,UAAAA,IAAc,CAACX,WAAAA,EAAa;gBAC/B,OAAOJ,GAAAA,CAAIM,UAAU,CAAC,0CAAA,CAAA;AACxB,YAAA;YAEA,IAAI;AACF,gBAAA,MAAMC,GAAAA,GAAM,MAAMT,yBAAAA,CAA0BkB,gBAAgB,CAACZ,WAAAA,EAAaW,UAAAA,CAAAA;AAE1Ef,gBAAAA,GAAAA,CAAIS,IAAI,GAAG;oBACTC,IAAAA,EAAMH;AACR,iBAAA;AACF,YAAA,CAAA,CAAE,OAAOI,KAAAA,EAAO;AACdlB,gBAAAA,MAAAA,CAAOmB,GAAG,CAACD,KAAK,CAAC,6CAAA,EAA+CA,KAAAA,CAAAA;AAChEX,gBAAAA,GAAAA,CAAIa,mBAAmB,CAAC,sCAAA,CAAA;AAC1B,YAAA;AACF,QAAA;AACF,KAAA;AACF;;;;"}
@@ -12,7 +12,7 @@ const getFieldsProperty = fp.prop('properties.fields');
12
12
  const getFirstLevelPath = fp.map((path)=>path.split('.')[0]);
13
13
  const controller = {
14
14
  async getNonLocalizedAttributes (ctx) {
15
- const { user } = ctx.state;
15
+ const { user, userAbility } = ctx.state;
16
16
  const body = ctx.request.body;
17
17
  const { model, id, locale } = body;
18
18
  await contentTypes.validateGetNonLocalizedAttributesInput({
@@ -20,6 +20,13 @@ const controller = {
20
20
  id,
21
21
  locale
22
22
  });
23
+ const permissionChecker = strapi.plugin('content-manager').service('permission-checker').create({
24
+ userAbility,
25
+ model
26
+ });
27
+ if (permissionChecker.cannot.read()) {
28
+ return ctx.forbidden();
29
+ }
23
30
  const { copyNonLocalizedAttributes, isLocalizedContentType, getNestedPopulateOfNonLocalizedAttributes } = index.getService('content-types');
24
31
  const { default: { READ_ACTION, CREATE_ACTION } } = strapi.service('admin::constants');
25
32
  const modelDef = strapi.contentType(model);
@@ -52,7 +59,15 @@ const controller = {
52
59
  const localePermissions = permissions.filter((perm)=>getLocalesProperty(perm).includes(locale)).map(getFieldsProperty);
53
60
  const permittedFields = fp.pipe(fp.flatten, getFirstLevelPath, fp.uniq)(localePermissions);
54
61
  const nonLocalizedFields = copyNonLocalizedAttributes(modelDef, entity);
55
- const sanitizedNonLocalizedFields = fp.pick(permittedFields, nonLocalizedFields);
62
+ const pickedFields = fp.pick(permittedFields, nonLocalizedFields);
63
+ // Guard relations: omit fields that point to content types the user cannot read
64
+ const sanitizedNonLocalizedFields = Object.fromEntries(Object.entries(pickedFields).filter(([key])=>{
65
+ const attribute = modelDef.attributes?.[key];
66
+ if (attribute?.type === 'relation' && attribute.target) {
67
+ return userAbility.can(READ_ACTION, attribute.target);
68
+ }
69
+ return true;
70
+ }));
56
71
  const availableLocalesResult = await strapi.plugins['content-manager'].service('document-metadata').getMetadata(model, entity, {
57
72
  availableLocales: true
58
73
  });
@@ -69,6 +84,31 @@ const controller = {
69
84
  PUBLISHED_AT_ATTRIBUTE
70
85
  ], entity))
71
86
  };
87
+ },
88
+ async getFillFromLocaleData (ctx) {
89
+ const { userAbility } = ctx.state;
90
+ const { model } = ctx.params;
91
+ await contentTypes.validateFillFromLocaleInput(ctx.query);
92
+ const { documentId, sourceLocale, targetLocale } = ctx.query;
93
+ const permissionChecker = strapi.plugin('content-manager').service('permission-checker').create({
94
+ userAbility,
95
+ model
96
+ });
97
+ if (permissionChecker.cannot.read()) {
98
+ return ctx.forbidden();
99
+ }
100
+ const fillFromLocaleService = index.getService('fill-from-locale');
101
+ const rawDocument = await fillFromLocaleService.fetchRawDocument(model, sourceLocale, documentId);
102
+ if (!rawDocument) {
103
+ return ctx.notFound();
104
+ }
105
+ // Field-level filtering: strip fields the user cannot read on this content type
106
+ const sanitizedDocument = await permissionChecker.sanitizeOutput(rawDocument);
107
+ // Transform relations to target locale, skipping those the user cannot read
108
+ const data = await fillFromLocaleService.transformDocument(sanitizedDocument, model, targetLocale, userAbility);
109
+ ctx.body = {
110
+ data
111
+ };
72
112
  }
73
113
  };
74
114
 
@@ -1 +1 @@
1
- {"version":3,"file":"content-types.js","sources":["../../../server/src/controllers/content-types.ts"],"sourcesContent":["import { pick, uniq, prop, getOr, flatten, pipe, map } from 'lodash/fp';\nimport { contentTypes as contentTypesUtils, errors } from '@strapi/utils';\nimport type { Core } from '@strapi/types';\nimport { getService } from '../utils';\nimport { validateGetNonLocalizedAttributesInput } from '../validation/content-types';\n\nconst { ApplicationError } = errors;\n\nconst { PUBLISHED_AT_ATTRIBUTE } = contentTypesUtils.constants;\n\nconst getLocalesProperty = getOr<string[]>([], 'properties.locales');\nconst getFieldsProperty = prop('properties.fields');\n\nconst getFirstLevelPath = map((path: string) => path.split('.')[0]);\n\nconst controller = {\n async getNonLocalizedAttributes(ctx) {\n const { user } = ctx.state;\n const body = ctx.request.body as any;\n const { model, id, locale } = body;\n\n await validateGetNonLocalizedAttributesInput({ model, id, locale });\n\n const {\n copyNonLocalizedAttributes,\n isLocalizedContentType,\n getNestedPopulateOfNonLocalizedAttributes,\n } = getService('content-types');\n\n const {\n default: { READ_ACTION, CREATE_ACTION },\n } = strapi.service('admin::constants');\n\n const modelDef = strapi.contentType(model);\n const attributesToPopulate = getNestedPopulateOfNonLocalizedAttributes(model);\n\n if (!isLocalizedContentType(modelDef)) {\n throw new ApplicationError(`Model ${model} is not localized`);\n }\n\n const params = modelDef.kind === 'singleType' ? {} : { id };\n\n const entity = await strapi.db\n .query(model)\n .findOne({ where: params, populate: attributesToPopulate });\n\n if (!entity) {\n return ctx.notFound();\n }\n\n const permissions = await strapi.admin.services.permission.findMany({\n where: {\n action: [READ_ACTION, CREATE_ACTION],\n subject: model,\n role: {\n id: user.roles.map(prop('id')),\n },\n },\n });\n\n const localePermissions = permissions\n .filter((perm: any) => getLocalesProperty(perm).includes(locale))\n .map(getFieldsProperty);\n\n const permittedFields = pipe(flatten, getFirstLevelPath, uniq)(localePermissions);\n\n const nonLocalizedFields = copyNonLocalizedAttributes(modelDef, entity);\n const sanitizedNonLocalizedFields = pick(permittedFields, nonLocalizedFields);\n\n const availableLocalesResult = await strapi.plugins['content-manager']\n .service('document-metadata')\n .getMetadata(model, entity, {\n availableLocales: true,\n });\n\n const availableLocales = availableLocalesResult.availableLocales.map((localeResult: any) =>\n pick(['id', 'locale', PUBLISHED_AT_ATTRIBUTE], localeResult)\n );\n\n ctx.body = {\n nonLocalizedFields: sanitizedNonLocalizedFields,\n localizations: availableLocales.concat(\n pick(['id', 'locale', PUBLISHED_AT_ATTRIBUTE], entity)\n ),\n };\n },\n} satisfies Core.Controller;\n\nexport default controller;\n"],"names":["ApplicationError","errors","PUBLISHED_AT_ATTRIBUTE","contentTypesUtils","constants","getLocalesProperty","getOr","getFieldsProperty","prop","getFirstLevelPath","map","path","split","controller","getNonLocalizedAttributes","ctx","user","state","body","request","model","id","locale","validateGetNonLocalizedAttributesInput","copyNonLocalizedAttributes","isLocalizedContentType","getNestedPopulateOfNonLocalizedAttributes","getService","default","READ_ACTION","CREATE_ACTION","strapi","service","modelDef","contentType","attributesToPopulate","params","kind","entity","db","query","findOne","where","populate","notFound","permissions","admin","services","permission","findMany","action","subject","role","roles","localePermissions","filter","perm","includes","permittedFields","pipe","flatten","uniq","nonLocalizedFields","sanitizedNonLocalizedFields","pick","availableLocalesResult","plugins","getMetadata","availableLocales","localeResult","localizations","concat"],"mappings":"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"}
1
+ {"version":3,"file":"content-types.js","sources":["../../../server/src/controllers/content-types.ts"],"sourcesContent":["import { pick, uniq, prop, getOr, flatten, pipe, map } from 'lodash/fp';\nimport { contentTypes as contentTypesUtils, errors } from '@strapi/utils';\nimport type { Core, UID } from '@strapi/types';\nimport type { FillFromLocale } from '../../../shared/contracts/content-manager';\nimport { getService } from '../utils';\nimport {\n validateGetNonLocalizedAttributesInput,\n validateFillFromLocaleInput,\n} from '../validation/content-types';\n\nconst { ApplicationError } = errors;\n\nconst { PUBLISHED_AT_ATTRIBUTE } = contentTypesUtils.constants;\n\nconst getLocalesProperty = getOr<string[]>([], 'properties.locales');\nconst getFieldsProperty = prop('properties.fields');\n\nconst getFirstLevelPath = map((path: string) => path.split('.')[0]);\n\nconst controller = {\n async getNonLocalizedAttributes(ctx) {\n const { user, userAbility } = ctx.state;\n const body = ctx.request.body as any;\n const { model, id, locale } = body;\n\n await validateGetNonLocalizedAttributesInput({ model, id, locale });\n\n const permissionChecker = strapi\n .plugin('content-manager')\n .service('permission-checker')\n .create({ userAbility, model });\n\n if (permissionChecker.cannot.read()) {\n return ctx.forbidden();\n }\n\n const {\n copyNonLocalizedAttributes,\n isLocalizedContentType,\n getNestedPopulateOfNonLocalizedAttributes,\n } = getService('content-types');\n\n const {\n default: { READ_ACTION, CREATE_ACTION },\n } = strapi.service('admin::constants');\n\n const modelDef = strapi.contentType(model);\n const attributesToPopulate = getNestedPopulateOfNonLocalizedAttributes(model);\n\n if (!isLocalizedContentType(modelDef)) {\n throw new ApplicationError(`Model ${model} is not localized`);\n }\n\n const params = modelDef.kind === 'singleType' ? {} : { id };\n\n const entity = await strapi.db\n .query(model)\n .findOne({ where: params, populate: attributesToPopulate });\n\n if (!entity) {\n return ctx.notFound();\n }\n\n const permissions = await strapi.admin.services.permission.findMany({\n where: {\n action: [READ_ACTION, CREATE_ACTION],\n subject: model,\n role: {\n id: user.roles.map(prop('id')),\n },\n },\n });\n\n const localePermissions = permissions\n .filter((perm: any) => getLocalesProperty(perm).includes(locale))\n .map(getFieldsProperty);\n\n const permittedFields = pipe(flatten, getFirstLevelPath, uniq)(localePermissions);\n\n const nonLocalizedFields = copyNonLocalizedAttributes(modelDef, entity);\n const pickedFields = pick(permittedFields, nonLocalizedFields);\n\n // Guard relations: omit fields that point to content types the user cannot read\n const sanitizedNonLocalizedFields = Object.fromEntries(\n Object.entries(pickedFields).filter(([key]) => {\n const attribute = modelDef.attributes?.[key] as any;\n if (attribute?.type === 'relation' && attribute.target) {\n return userAbility.can(READ_ACTION, attribute.target);\n }\n return true;\n })\n );\n\n const availableLocalesResult = await strapi.plugins['content-manager']\n .service('document-metadata')\n .getMetadata(model, entity, {\n availableLocales: true,\n });\n\n const availableLocales = availableLocalesResult.availableLocales.map((localeResult: any) =>\n pick(['id', 'locale', PUBLISHED_AT_ATTRIBUTE], localeResult)\n );\n\n ctx.body = {\n nonLocalizedFields: sanitizedNonLocalizedFields,\n localizations: availableLocales.concat(\n pick(['id', 'locale', PUBLISHED_AT_ATTRIBUTE], entity)\n ),\n };\n },\n\n async getFillFromLocaleData(ctx) {\n const { userAbility } = ctx.state;\n const { model } = ctx.params;\n\n await validateFillFromLocaleInput(ctx.query);\n\n const { documentId, sourceLocale, targetLocale } = ctx.query as unknown as Omit<\n FillFromLocale.Params,\n 'model'\n >;\n\n const permissionChecker = strapi\n .plugin('content-manager')\n .service('permission-checker')\n .create({ userAbility, model });\n\n if (permissionChecker.cannot.read()) {\n return ctx.forbidden();\n }\n\n const fillFromLocaleService = getService('fill-from-locale');\n\n const rawDocument = await fillFromLocaleService.fetchRawDocument(\n model as UID.ContentType,\n sourceLocale,\n documentId\n );\n\n if (!rawDocument) {\n return ctx.notFound();\n }\n\n // Field-level filtering: strip fields the user cannot read on this content type\n const sanitizedDocument = await permissionChecker.sanitizeOutput(rawDocument);\n\n // Transform relations to target locale, skipping those the user cannot read\n const data = await fillFromLocaleService.transformDocument(\n sanitizedDocument as Record<string, unknown>,\n model as UID.ContentType,\n targetLocale,\n userAbility\n );\n\n ctx.body = { data };\n },\n} satisfies Core.Controller;\n\nexport default controller;\n"],"names":["ApplicationError","errors","PUBLISHED_AT_ATTRIBUTE","contentTypesUtils","constants","getLocalesProperty","getOr","getFieldsProperty","prop","getFirstLevelPath","map","path","split","controller","getNonLocalizedAttributes","ctx","user","userAbility","state","body","request","model","id","locale","validateGetNonLocalizedAttributesInput","permissionChecker","strapi","plugin","service","create","cannot","read","forbidden","copyNonLocalizedAttributes","isLocalizedContentType","getNestedPopulateOfNonLocalizedAttributes","getService","default","READ_ACTION","CREATE_ACTION","modelDef","contentType","attributesToPopulate","params","kind","entity","db","query","findOne","where","populate","notFound","permissions","admin","services","permission","findMany","action","subject","role","roles","localePermissions","filter","perm","includes","permittedFields","pipe","flatten","uniq","nonLocalizedFields","pickedFields","pick","sanitizedNonLocalizedFields","Object","fromEntries","entries","key","attribute","attributes","type","target","can","availableLocalesResult","plugins","getMetadata","availableLocales","localeResult","localizations","concat","getFillFromLocaleData","validateFillFromLocaleInput","documentId","sourceLocale","targetLocale","fillFromLocaleService","rawDocument","fetchRawDocument","sanitizedDocument","sanitizeOutput","data","transformDocument"],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  import { getOr, prop, map, pipe, flatten, uniq, pick } from 'lodash/fp';
2
2
  import { errors, contentTypes } from '@strapi/utils';
3
3
  import { getService } from '../utils/index.mjs';
4
- import { validateGetNonLocalizedAttributesInput } from '../validation/content-types.mjs';
4
+ import { validateFillFromLocaleInput, validateGetNonLocalizedAttributesInput } from '../validation/content-types.mjs';
5
5
 
6
6
  const { ApplicationError } = errors;
7
7
  const { PUBLISHED_AT_ATTRIBUTE } = contentTypes.constants;
@@ -10,7 +10,7 @@ const getFieldsProperty = prop('properties.fields');
10
10
  const getFirstLevelPath = map((path)=>path.split('.')[0]);
11
11
  const controller = {
12
12
  async getNonLocalizedAttributes (ctx) {
13
- const { user } = ctx.state;
13
+ const { user, userAbility } = ctx.state;
14
14
  const body = ctx.request.body;
15
15
  const { model, id, locale } = body;
16
16
  await validateGetNonLocalizedAttributesInput({
@@ -18,6 +18,13 @@ const controller = {
18
18
  id,
19
19
  locale
20
20
  });
21
+ const permissionChecker = strapi.plugin('content-manager').service('permission-checker').create({
22
+ userAbility,
23
+ model
24
+ });
25
+ if (permissionChecker.cannot.read()) {
26
+ return ctx.forbidden();
27
+ }
21
28
  const { copyNonLocalizedAttributes, isLocalizedContentType, getNestedPopulateOfNonLocalizedAttributes } = getService('content-types');
22
29
  const { default: { READ_ACTION, CREATE_ACTION } } = strapi.service('admin::constants');
23
30
  const modelDef = strapi.contentType(model);
@@ -50,7 +57,15 @@ const controller = {
50
57
  const localePermissions = permissions.filter((perm)=>getLocalesProperty(perm).includes(locale)).map(getFieldsProperty);
51
58
  const permittedFields = pipe(flatten, getFirstLevelPath, uniq)(localePermissions);
52
59
  const nonLocalizedFields = copyNonLocalizedAttributes(modelDef, entity);
53
- const sanitizedNonLocalizedFields = pick(permittedFields, nonLocalizedFields);
60
+ const pickedFields = pick(permittedFields, nonLocalizedFields);
61
+ // Guard relations: omit fields that point to content types the user cannot read
62
+ const sanitizedNonLocalizedFields = Object.fromEntries(Object.entries(pickedFields).filter(([key])=>{
63
+ const attribute = modelDef.attributes?.[key];
64
+ if (attribute?.type === 'relation' && attribute.target) {
65
+ return userAbility.can(READ_ACTION, attribute.target);
66
+ }
67
+ return true;
68
+ }));
54
69
  const availableLocalesResult = await strapi.plugins['content-manager'].service('document-metadata').getMetadata(model, entity, {
55
70
  availableLocales: true
56
71
  });
@@ -67,6 +82,31 @@ const controller = {
67
82
  PUBLISHED_AT_ATTRIBUTE
68
83
  ], entity))
69
84
  };
85
+ },
86
+ async getFillFromLocaleData (ctx) {
87
+ const { userAbility } = ctx.state;
88
+ const { model } = ctx.params;
89
+ await validateFillFromLocaleInput(ctx.query);
90
+ const { documentId, sourceLocale, targetLocale } = ctx.query;
91
+ const permissionChecker = strapi.plugin('content-manager').service('permission-checker').create({
92
+ userAbility,
93
+ model
94
+ });
95
+ if (permissionChecker.cannot.read()) {
96
+ return ctx.forbidden();
97
+ }
98
+ const fillFromLocaleService = getService('fill-from-locale');
99
+ const rawDocument = await fillFromLocaleService.fetchRawDocument(model, sourceLocale, documentId);
100
+ if (!rawDocument) {
101
+ return ctx.notFound();
102
+ }
103
+ // Field-level filtering: strip fields the user cannot read on this content type
104
+ const sanitizedDocument = await permissionChecker.sanitizeOutput(rawDocument);
105
+ // Transform relations to target locale, skipping those the user cannot read
106
+ const data = await fillFromLocaleService.transformDocument(sanitizedDocument, model, targetLocale, userAbility);
107
+ ctx.body = {
108
+ data
109
+ };
70
110
  }
71
111
  };
72
112
 
@@ -1 +1 @@
1
- {"version":3,"file":"content-types.mjs","sources":["../../../server/src/controllers/content-types.ts"],"sourcesContent":["import { pick, uniq, prop, getOr, flatten, pipe, map } from 'lodash/fp';\nimport { contentTypes as contentTypesUtils, errors } from '@strapi/utils';\nimport type { Core } from '@strapi/types';\nimport { getService } from '../utils';\nimport { validateGetNonLocalizedAttributesInput } from '../validation/content-types';\n\nconst { ApplicationError } = errors;\n\nconst { PUBLISHED_AT_ATTRIBUTE } = contentTypesUtils.constants;\n\nconst getLocalesProperty = getOr<string[]>([], 'properties.locales');\nconst getFieldsProperty = prop('properties.fields');\n\nconst getFirstLevelPath = map((path: string) => path.split('.')[0]);\n\nconst controller = {\n async getNonLocalizedAttributes(ctx) {\n const { user } = ctx.state;\n const body = ctx.request.body as any;\n const { model, id, locale } = body;\n\n await validateGetNonLocalizedAttributesInput({ model, id, locale });\n\n const {\n copyNonLocalizedAttributes,\n isLocalizedContentType,\n getNestedPopulateOfNonLocalizedAttributes,\n } = getService('content-types');\n\n const {\n default: { READ_ACTION, CREATE_ACTION },\n } = strapi.service('admin::constants');\n\n const modelDef = strapi.contentType(model);\n const attributesToPopulate = getNestedPopulateOfNonLocalizedAttributes(model);\n\n if (!isLocalizedContentType(modelDef)) {\n throw new ApplicationError(`Model ${model} is not localized`);\n }\n\n const params = modelDef.kind === 'singleType' ? {} : { id };\n\n const entity = await strapi.db\n .query(model)\n .findOne({ where: params, populate: attributesToPopulate });\n\n if (!entity) {\n return ctx.notFound();\n }\n\n const permissions = await strapi.admin.services.permission.findMany({\n where: {\n action: [READ_ACTION, CREATE_ACTION],\n subject: model,\n role: {\n id: user.roles.map(prop('id')),\n },\n },\n });\n\n const localePermissions = permissions\n .filter((perm: any) => getLocalesProperty(perm).includes(locale))\n .map(getFieldsProperty);\n\n const permittedFields = pipe(flatten, getFirstLevelPath, uniq)(localePermissions);\n\n const nonLocalizedFields = copyNonLocalizedAttributes(modelDef, entity);\n const sanitizedNonLocalizedFields = pick(permittedFields, nonLocalizedFields);\n\n const availableLocalesResult = await strapi.plugins['content-manager']\n .service('document-metadata')\n .getMetadata(model, entity, {\n availableLocales: true,\n });\n\n const availableLocales = availableLocalesResult.availableLocales.map((localeResult: any) =>\n pick(['id', 'locale', PUBLISHED_AT_ATTRIBUTE], localeResult)\n );\n\n ctx.body = {\n nonLocalizedFields: sanitizedNonLocalizedFields,\n localizations: availableLocales.concat(\n pick(['id', 'locale', PUBLISHED_AT_ATTRIBUTE], entity)\n ),\n };\n },\n} satisfies Core.Controller;\n\nexport default controller;\n"],"names":["ApplicationError","errors","PUBLISHED_AT_ATTRIBUTE","contentTypesUtils","constants","getLocalesProperty","getOr","getFieldsProperty","prop","getFirstLevelPath","map","path","split","controller","getNonLocalizedAttributes","ctx","user","state","body","request","model","id","locale","validateGetNonLocalizedAttributesInput","copyNonLocalizedAttributes","isLocalizedContentType","getNestedPopulateOfNonLocalizedAttributes","getService","default","READ_ACTION","CREATE_ACTION","strapi","service","modelDef","contentType","attributesToPopulate","params","kind","entity","db","query","findOne","where","populate","notFound","permissions","admin","services","permission","findMany","action","subject","role","roles","localePermissions","filter","perm","includes","permittedFields","pipe","flatten","uniq","nonLocalizedFields","sanitizedNonLocalizedFields","pick","availableLocalesResult","plugins","getMetadata","availableLocales","localeResult","localizations","concat"],"mappings":"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"}
1
+ {"version":3,"file":"content-types.mjs","sources":["../../../server/src/controllers/content-types.ts"],"sourcesContent":["import { pick, uniq, prop, getOr, flatten, pipe, map } from 'lodash/fp';\nimport { contentTypes as contentTypesUtils, errors } from '@strapi/utils';\nimport type { Core, UID } from '@strapi/types';\nimport type { FillFromLocale } from '../../../shared/contracts/content-manager';\nimport { getService } from '../utils';\nimport {\n validateGetNonLocalizedAttributesInput,\n validateFillFromLocaleInput,\n} from '../validation/content-types';\n\nconst { ApplicationError } = errors;\n\nconst { PUBLISHED_AT_ATTRIBUTE } = contentTypesUtils.constants;\n\nconst getLocalesProperty = getOr<string[]>([], 'properties.locales');\nconst getFieldsProperty = prop('properties.fields');\n\nconst getFirstLevelPath = map((path: string) => path.split('.')[0]);\n\nconst controller = {\n async getNonLocalizedAttributes(ctx) {\n const { user, userAbility } = ctx.state;\n const body = ctx.request.body as any;\n const { model, id, locale } = body;\n\n await validateGetNonLocalizedAttributesInput({ model, id, locale });\n\n const permissionChecker = strapi\n .plugin('content-manager')\n .service('permission-checker')\n .create({ userAbility, model });\n\n if (permissionChecker.cannot.read()) {\n return ctx.forbidden();\n }\n\n const {\n copyNonLocalizedAttributes,\n isLocalizedContentType,\n getNestedPopulateOfNonLocalizedAttributes,\n } = getService('content-types');\n\n const {\n default: { READ_ACTION, CREATE_ACTION },\n } = strapi.service('admin::constants');\n\n const modelDef = strapi.contentType(model);\n const attributesToPopulate = getNestedPopulateOfNonLocalizedAttributes(model);\n\n if (!isLocalizedContentType(modelDef)) {\n throw new ApplicationError(`Model ${model} is not localized`);\n }\n\n const params = modelDef.kind === 'singleType' ? {} : { id };\n\n const entity = await strapi.db\n .query(model)\n .findOne({ where: params, populate: attributesToPopulate });\n\n if (!entity) {\n return ctx.notFound();\n }\n\n const permissions = await strapi.admin.services.permission.findMany({\n where: {\n action: [READ_ACTION, CREATE_ACTION],\n subject: model,\n role: {\n id: user.roles.map(prop('id')),\n },\n },\n });\n\n const localePermissions = permissions\n .filter((perm: any) => getLocalesProperty(perm).includes(locale))\n .map(getFieldsProperty);\n\n const permittedFields = pipe(flatten, getFirstLevelPath, uniq)(localePermissions);\n\n const nonLocalizedFields = copyNonLocalizedAttributes(modelDef, entity);\n const pickedFields = pick(permittedFields, nonLocalizedFields);\n\n // Guard relations: omit fields that point to content types the user cannot read\n const sanitizedNonLocalizedFields = Object.fromEntries(\n Object.entries(pickedFields).filter(([key]) => {\n const attribute = modelDef.attributes?.[key] as any;\n if (attribute?.type === 'relation' && attribute.target) {\n return userAbility.can(READ_ACTION, attribute.target);\n }\n return true;\n })\n );\n\n const availableLocalesResult = await strapi.plugins['content-manager']\n .service('document-metadata')\n .getMetadata(model, entity, {\n availableLocales: true,\n });\n\n const availableLocales = availableLocalesResult.availableLocales.map((localeResult: any) =>\n pick(['id', 'locale', PUBLISHED_AT_ATTRIBUTE], localeResult)\n );\n\n ctx.body = {\n nonLocalizedFields: sanitizedNonLocalizedFields,\n localizations: availableLocales.concat(\n pick(['id', 'locale', PUBLISHED_AT_ATTRIBUTE], entity)\n ),\n };\n },\n\n async getFillFromLocaleData(ctx) {\n const { userAbility } = ctx.state;\n const { model } = ctx.params;\n\n await validateFillFromLocaleInput(ctx.query);\n\n const { documentId, sourceLocale, targetLocale } = ctx.query as unknown as Omit<\n FillFromLocale.Params,\n 'model'\n >;\n\n const permissionChecker = strapi\n .plugin('content-manager')\n .service('permission-checker')\n .create({ userAbility, model });\n\n if (permissionChecker.cannot.read()) {\n return ctx.forbidden();\n }\n\n const fillFromLocaleService = getService('fill-from-locale');\n\n const rawDocument = await fillFromLocaleService.fetchRawDocument(\n model as UID.ContentType,\n sourceLocale,\n documentId\n );\n\n if (!rawDocument) {\n return ctx.notFound();\n }\n\n // Field-level filtering: strip fields the user cannot read on this content type\n const sanitizedDocument = await permissionChecker.sanitizeOutput(rawDocument);\n\n // Transform relations to target locale, skipping those the user cannot read\n const data = await fillFromLocaleService.transformDocument(\n sanitizedDocument as Record<string, unknown>,\n model as UID.ContentType,\n targetLocale,\n userAbility\n );\n\n ctx.body = { data };\n },\n} satisfies Core.Controller;\n\nexport default controller;\n"],"names":["ApplicationError","errors","PUBLISHED_AT_ATTRIBUTE","contentTypesUtils","constants","getLocalesProperty","getOr","getFieldsProperty","prop","getFirstLevelPath","map","path","split","controller","getNonLocalizedAttributes","ctx","user","userAbility","state","body","request","model","id","locale","validateGetNonLocalizedAttributesInput","permissionChecker","strapi","plugin","service","create","cannot","read","forbidden","copyNonLocalizedAttributes","isLocalizedContentType","getNestedPopulateOfNonLocalizedAttributes","getService","default","READ_ACTION","CREATE_ACTION","modelDef","contentType","attributesToPopulate","params","kind","entity","db","query","findOne","where","populate","notFound","permissions","admin","services","permission","findMany","action","subject","role","roles","localePermissions","filter","perm","includes","permittedFields","pipe","flatten","uniq","nonLocalizedFields","pickedFields","pick","sanitizedNonLocalizedFields","Object","fromEntries","entries","key","attribute","attributes","type","target","can","availableLocalesResult","plugins","getMetadata","availableLocales","localeResult","localizations","concat","getFillFromLocaleData","validateFillFromLocaleInput","documentId","sourceLocale","targetLocale","fillFromLocaleService","rawDocument","fetchRawDocument","sanitizedDocument","sanitizeOutput","data","transformDocument"],"mappings":"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"}
@@ -95,6 +95,24 @@ var admin = {
95
95
  ]
96
96
  }
97
97
  },
98
+ {
99
+ method: 'GET',
100
+ path: '/content-manager/get-fill-from-locale/:model',
101
+ handler: 'content-types.getFillFromLocaleData',
102
+ config: {
103
+ policies: [
104
+ 'admin::isAuthenticatedAdmin',
105
+ {
106
+ name: 'plugin::content-manager.hasPermissions',
107
+ config: {
108
+ actions: [
109
+ 'plugin::content-manager.explorer.read'
110
+ ]
111
+ }
112
+ }
113
+ ]
114
+ }
115
+ },
98
116
  {
99
117
  method: 'GET',
100
118
  path: '/settings',
@@ -1 +1 @@
1
- {"version":3,"file":"admin.js","sources":["../../../server/src/routes/admin.ts"],"sourcesContent":["export default {\n type: 'admin',\n routes: [\n {\n method: 'GET',\n path: '/iso-locales',\n handler: 'iso-locales.listIsoLocales',\n config: {\n policies: [\n 'admin::isAuthenticatedAdmin',\n {\n name: 'plugin::content-manager.hasPermissions',\n config: { actions: ['plugin::i18n.locale.read'] },\n },\n ],\n },\n },\n {\n method: 'GET',\n path: '/locales',\n handler: 'locales.listLocales',\n config: {\n policies: ['admin::isAuthenticatedAdmin'],\n },\n },\n {\n method: 'POST',\n path: '/locales',\n handler: 'locales.createLocale',\n config: {\n policies: [\n 'admin::isAuthenticatedAdmin',\n {\n name: 'plugin::content-manager.hasPermissions',\n config: { actions: ['plugin::i18n.locale.create'] },\n },\n ],\n },\n },\n {\n method: 'PUT',\n path: '/locales/:id',\n handler: 'locales.updateLocale',\n config: {\n policies: [\n 'admin::isAuthenticatedAdmin',\n {\n name: 'plugin::content-manager.hasPermissions',\n config: { actions: ['plugin::i18n.locale.update'] },\n },\n ],\n },\n },\n {\n method: 'DELETE',\n path: '/locales/:id',\n handler: 'locales.deleteLocale',\n config: {\n policies: [\n 'admin::isAuthenticatedAdmin',\n {\n name: 'plugin::content-manager.hasPermissions',\n config: { actions: ['plugin::i18n.locale.delete'] },\n },\n ],\n },\n },\n {\n method: 'POST',\n path: '/content-manager/actions/get-non-localized-fields',\n handler: 'content-types.getNonLocalizedAttributes',\n config: {\n policies: ['admin::isAuthenticatedAdmin'],\n },\n },\n {\n method: 'GET',\n path: '/settings',\n handler: 'settings.getSettings',\n config: {\n policies: ['admin::isAuthenticatedAdmin'],\n },\n },\n {\n method: 'PUT',\n path: '/settings',\n handler: 'settings.updateSettings',\n config: {\n policies: ['admin::isAuthenticatedAdmin'],\n },\n },\n {\n method: 'GET',\n path: '/ai-localization-jobs/collection-types/:contentType/:documentId',\n handler: 'ai-localization-jobs.getJobForCollectionType',\n config: {\n policies: ['admin::isAuthenticatedAdmin'],\n },\n },\n {\n method: 'GET',\n path: '/ai-localization-jobs/single-types/:contentType',\n handler: 'ai-localization-jobs.getJobForSingleType',\n config: {\n policies: ['admin::isAuthenticatedAdmin'],\n },\n },\n ],\n};\n"],"names":["type","routes","method","path","handler","config","policies","name","actions"],"mappings":";;AAAA,YAAe;IACbA,IAAAA,EAAM,OAAA;IACNC,MAAAA,EAAQ;AACN,QAAA;YACEC,MAAAA,EAAQ,KAAA;YACRC,IAAAA,EAAM,cAAA;YACNC,OAAAA,EAAS,4BAAA;YACTC,MAAAA,EAAQ;gBACNC,QAAAA,EAAU;AACR,oBAAA,6BAAA;AACA,oBAAA;wBACEC,IAAAA,EAAM,wCAAA;wBACNF,MAAAA,EAAQ;4BAAEG,OAAAA,EAAS;AAAC,gCAAA;AAA2B;AAAC;AAClD;AACD;AACH;AACF,SAAA;AACA,QAAA;YACEN,MAAAA,EAAQ,KAAA;YACRC,IAAAA,EAAM,UAAA;YACNC,OAAAA,EAAS,qBAAA;YACTC,MAAAA,EAAQ;gBACNC,QAAAA,EAAU;AAAC,oBAAA;AAA8B;AAC3C;AACF,SAAA;AACA,QAAA;YACEJ,MAAAA,EAAQ,MAAA;YACRC,IAAAA,EAAM,UAAA;YACNC,OAAAA,EAAS,sBAAA;YACTC,MAAAA,EAAQ;gBACNC,QAAAA,EAAU;AACR,oBAAA,6BAAA;AACA,oBAAA;wBACEC,IAAAA,EAAM,wCAAA;wBACNF,MAAAA,EAAQ;4BAAEG,OAAAA,EAAS;AAAC,gCAAA;AAA6B;AAAC;AACpD;AACD;AACH;AACF,SAAA;AACA,QAAA;YACEN,MAAAA,EAAQ,KAAA;YACRC,IAAAA,EAAM,cAAA;YACNC,OAAAA,EAAS,sBAAA;YACTC,MAAAA,EAAQ;gBACNC,QAAAA,EAAU;AACR,oBAAA,6BAAA;AACA,oBAAA;wBACEC,IAAAA,EAAM,wCAAA;wBACNF,MAAAA,EAAQ;4BAAEG,OAAAA,EAAS;AAAC,gCAAA;AAA6B;AAAC;AACpD;AACD;AACH;AACF,SAAA;AACA,QAAA;YACEN,MAAAA,EAAQ,QAAA;YACRC,IAAAA,EAAM,cAAA;YACNC,OAAAA,EAAS,sBAAA;YACTC,MAAAA,EAAQ;gBACNC,QAAAA,EAAU;AACR,oBAAA,6BAAA;AACA,oBAAA;wBACEC,IAAAA,EAAM,wCAAA;wBACNF,MAAAA,EAAQ;4BAAEG,OAAAA,EAAS;AAAC,gCAAA;AAA6B;AAAC;AACpD;AACD;AACH;AACF,SAAA;AACA,QAAA;YACEN,MAAAA,EAAQ,MAAA;YACRC,IAAAA,EAAM,mDAAA;YACNC,OAAAA,EAAS,yCAAA;YACTC,MAAAA,EAAQ;gBACNC,QAAAA,EAAU;AAAC,oBAAA;AAA8B;AAC3C;AACF,SAAA;AACA,QAAA;YACEJ,MAAAA,EAAQ,KAAA;YACRC,IAAAA,EAAM,WAAA;YACNC,OAAAA,EAAS,sBAAA;YACTC,MAAAA,EAAQ;gBACNC,QAAAA,EAAU;AAAC,oBAAA;AAA8B;AAC3C;AACF,SAAA;AACA,QAAA;YACEJ,MAAAA,EAAQ,KAAA;YACRC,IAAAA,EAAM,WAAA;YACNC,OAAAA,EAAS,yBAAA;YACTC,MAAAA,EAAQ;gBACNC,QAAAA,EAAU;AAAC,oBAAA;AAA8B;AAC3C;AACF,SAAA;AACA,QAAA;YACEJ,MAAAA,EAAQ,KAAA;YACRC,IAAAA,EAAM,iEAAA;YACNC,OAAAA,EAAS,8CAAA;YACTC,MAAAA,EAAQ;gBACNC,QAAAA,EAAU;AAAC,oBAAA;AAA8B;AAC3C;AACF,SAAA;AACA,QAAA;YACEJ,MAAAA,EAAQ,KAAA;YACRC,IAAAA,EAAM,iDAAA;YACNC,OAAAA,EAAS,0CAAA;YACTC,MAAAA,EAAQ;gBACNC,QAAAA,EAAU;AAAC,oBAAA;AAA8B;AAC3C;AACF;AACD;AACH,CAAA;;;;"}
1
+ {"version":3,"file":"admin.js","sources":["../../../server/src/routes/admin.ts"],"sourcesContent":["export default {\n type: 'admin',\n routes: [\n {\n method: 'GET',\n path: '/iso-locales',\n handler: 'iso-locales.listIsoLocales',\n config: {\n policies: [\n 'admin::isAuthenticatedAdmin',\n {\n name: 'plugin::content-manager.hasPermissions',\n config: { actions: ['plugin::i18n.locale.read'] },\n },\n ],\n },\n },\n {\n method: 'GET',\n path: '/locales',\n handler: 'locales.listLocales',\n config: {\n policies: ['admin::isAuthenticatedAdmin'],\n },\n },\n {\n method: 'POST',\n path: '/locales',\n handler: 'locales.createLocale',\n config: {\n policies: [\n 'admin::isAuthenticatedAdmin',\n {\n name: 'plugin::content-manager.hasPermissions',\n config: { actions: ['plugin::i18n.locale.create'] },\n },\n ],\n },\n },\n {\n method: 'PUT',\n path: '/locales/:id',\n handler: 'locales.updateLocale',\n config: {\n policies: [\n 'admin::isAuthenticatedAdmin',\n {\n name: 'plugin::content-manager.hasPermissions',\n config: { actions: ['plugin::i18n.locale.update'] },\n },\n ],\n },\n },\n {\n method: 'DELETE',\n path: '/locales/:id',\n handler: 'locales.deleteLocale',\n config: {\n policies: [\n 'admin::isAuthenticatedAdmin',\n {\n name: 'plugin::content-manager.hasPermissions',\n config: { actions: ['plugin::i18n.locale.delete'] },\n },\n ],\n },\n },\n {\n method: 'POST',\n path: '/content-manager/actions/get-non-localized-fields',\n handler: 'content-types.getNonLocalizedAttributes',\n config: {\n policies: ['admin::isAuthenticatedAdmin'],\n },\n },\n {\n method: 'GET',\n path: '/content-manager/get-fill-from-locale/:model',\n handler: 'content-types.getFillFromLocaleData',\n config: {\n policies: [\n 'admin::isAuthenticatedAdmin',\n {\n name: 'plugin::content-manager.hasPermissions',\n config: { actions: ['plugin::content-manager.explorer.read'] },\n },\n ],\n },\n },\n {\n method: 'GET',\n path: '/settings',\n handler: 'settings.getSettings',\n config: {\n policies: ['admin::isAuthenticatedAdmin'],\n },\n },\n {\n method: 'PUT',\n path: '/settings',\n handler: 'settings.updateSettings',\n config: {\n policies: ['admin::isAuthenticatedAdmin'],\n },\n },\n {\n method: 'GET',\n path: '/ai-localization-jobs/collection-types/:contentType/:documentId',\n handler: 'ai-localization-jobs.getJobForCollectionType',\n config: {\n policies: ['admin::isAuthenticatedAdmin'],\n },\n },\n {\n method: 'GET',\n path: '/ai-localization-jobs/single-types/:contentType',\n handler: 'ai-localization-jobs.getJobForSingleType',\n config: {\n policies: ['admin::isAuthenticatedAdmin'],\n },\n },\n ],\n};\n"],"names":["type","routes","method","path","handler","config","policies","name","actions"],"mappings":"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"}
@@ -93,6 +93,24 @@ var admin = {
93
93
  ]
94
94
  }
95
95
  },
96
+ {
97
+ method: 'GET',
98
+ path: '/content-manager/get-fill-from-locale/:model',
99
+ handler: 'content-types.getFillFromLocaleData',
100
+ config: {
101
+ policies: [
102
+ 'admin::isAuthenticatedAdmin',
103
+ {
104
+ name: 'plugin::content-manager.hasPermissions',
105
+ config: {
106
+ actions: [
107
+ 'plugin::content-manager.explorer.read'
108
+ ]
109
+ }
110
+ }
111
+ ]
112
+ }
113
+ },
96
114
  {
97
115
  method: 'GET',
98
116
  path: '/settings',
@@ -1 +1 @@
1
- {"version":3,"file":"admin.mjs","sources":["../../../server/src/routes/admin.ts"],"sourcesContent":["export default {\n type: 'admin',\n routes: [\n {\n method: 'GET',\n path: '/iso-locales',\n handler: 'iso-locales.listIsoLocales',\n config: {\n policies: [\n 'admin::isAuthenticatedAdmin',\n {\n name: 'plugin::content-manager.hasPermissions',\n config: { actions: ['plugin::i18n.locale.read'] },\n },\n ],\n },\n },\n {\n method: 'GET',\n path: '/locales',\n handler: 'locales.listLocales',\n config: {\n policies: ['admin::isAuthenticatedAdmin'],\n },\n },\n {\n method: 'POST',\n path: '/locales',\n handler: 'locales.createLocale',\n config: {\n policies: [\n 'admin::isAuthenticatedAdmin',\n {\n name: 'plugin::content-manager.hasPermissions',\n config: { actions: ['plugin::i18n.locale.create'] },\n },\n ],\n },\n },\n {\n method: 'PUT',\n path: '/locales/:id',\n handler: 'locales.updateLocale',\n config: {\n policies: [\n 'admin::isAuthenticatedAdmin',\n {\n name: 'plugin::content-manager.hasPermissions',\n config: { actions: ['plugin::i18n.locale.update'] },\n },\n ],\n },\n },\n {\n method: 'DELETE',\n path: '/locales/:id',\n handler: 'locales.deleteLocale',\n config: {\n policies: [\n 'admin::isAuthenticatedAdmin',\n {\n name: 'plugin::content-manager.hasPermissions',\n config: { actions: ['plugin::i18n.locale.delete'] },\n },\n ],\n },\n },\n {\n method: 'POST',\n path: '/content-manager/actions/get-non-localized-fields',\n handler: 'content-types.getNonLocalizedAttributes',\n config: {\n policies: ['admin::isAuthenticatedAdmin'],\n },\n },\n {\n method: 'GET',\n path: '/settings',\n handler: 'settings.getSettings',\n config: {\n policies: ['admin::isAuthenticatedAdmin'],\n },\n },\n {\n method: 'PUT',\n path: '/settings',\n handler: 'settings.updateSettings',\n config: {\n policies: ['admin::isAuthenticatedAdmin'],\n },\n },\n {\n method: 'GET',\n path: '/ai-localization-jobs/collection-types/:contentType/:documentId',\n handler: 'ai-localization-jobs.getJobForCollectionType',\n config: {\n policies: ['admin::isAuthenticatedAdmin'],\n },\n },\n {\n method: 'GET',\n path: '/ai-localization-jobs/single-types/:contentType',\n handler: 'ai-localization-jobs.getJobForSingleType',\n config: {\n policies: ['admin::isAuthenticatedAdmin'],\n },\n },\n ],\n};\n"],"names":["type","routes","method","path","handler","config","policies","name","actions"],"mappings":"AAAA,YAAe;IACbA,IAAAA,EAAM,OAAA;IACNC,MAAAA,EAAQ;AACN,QAAA;YACEC,MAAAA,EAAQ,KAAA;YACRC,IAAAA,EAAM,cAAA;YACNC,OAAAA,EAAS,4BAAA;YACTC,MAAAA,EAAQ;gBACNC,QAAAA,EAAU;AACR,oBAAA,6BAAA;AACA,oBAAA;wBACEC,IAAAA,EAAM,wCAAA;wBACNF,MAAAA,EAAQ;4BAAEG,OAAAA,EAAS;AAAC,gCAAA;AAA2B;AAAC;AAClD;AACD;AACH;AACF,SAAA;AACA,QAAA;YACEN,MAAAA,EAAQ,KAAA;YACRC,IAAAA,EAAM,UAAA;YACNC,OAAAA,EAAS,qBAAA;YACTC,MAAAA,EAAQ;gBACNC,QAAAA,EAAU;AAAC,oBAAA;AAA8B;AAC3C;AACF,SAAA;AACA,QAAA;YACEJ,MAAAA,EAAQ,MAAA;YACRC,IAAAA,EAAM,UAAA;YACNC,OAAAA,EAAS,sBAAA;YACTC,MAAAA,EAAQ;gBACNC,QAAAA,EAAU;AACR,oBAAA,6BAAA;AACA,oBAAA;wBACEC,IAAAA,EAAM,wCAAA;wBACNF,MAAAA,EAAQ;4BAAEG,OAAAA,EAAS;AAAC,gCAAA;AAA6B;AAAC;AACpD;AACD;AACH;AACF,SAAA;AACA,QAAA;YACEN,MAAAA,EAAQ,KAAA;YACRC,IAAAA,EAAM,cAAA;YACNC,OAAAA,EAAS,sBAAA;YACTC,MAAAA,EAAQ;gBACNC,QAAAA,EAAU;AACR,oBAAA,6BAAA;AACA,oBAAA;wBACEC,IAAAA,EAAM,wCAAA;wBACNF,MAAAA,EAAQ;4BAAEG,OAAAA,EAAS;AAAC,gCAAA;AAA6B;AAAC;AACpD;AACD;AACH;AACF,SAAA;AACA,QAAA;YACEN,MAAAA,EAAQ,QAAA;YACRC,IAAAA,EAAM,cAAA;YACNC,OAAAA,EAAS,sBAAA;YACTC,MAAAA,EAAQ;gBACNC,QAAAA,EAAU;AACR,oBAAA,6BAAA;AACA,oBAAA;wBACEC,IAAAA,EAAM,wCAAA;wBACNF,MAAAA,EAAQ;4BAAEG,OAAAA,EAAS;AAAC,gCAAA;AAA6B;AAAC;AACpD;AACD;AACH;AACF,SAAA;AACA,QAAA;YACEN,MAAAA,EAAQ,MAAA;YACRC,IAAAA,EAAM,mDAAA;YACNC,OAAAA,EAAS,yCAAA;YACTC,MAAAA,EAAQ;gBACNC,QAAAA,EAAU;AAAC,oBAAA;AAA8B;AAC3C;AACF,SAAA;AACA,QAAA;YACEJ,MAAAA,EAAQ,KAAA;YACRC,IAAAA,EAAM,WAAA;YACNC,OAAAA,EAAS,sBAAA;YACTC,MAAAA,EAAQ;gBACNC,QAAAA,EAAU;AAAC,oBAAA;AAA8B;AAC3C;AACF,SAAA;AACA,QAAA;YACEJ,MAAAA,EAAQ,KAAA;YACRC,IAAAA,EAAM,WAAA;YACNC,OAAAA,EAAS,yBAAA;YACTC,MAAAA,EAAQ;gBACNC,QAAAA,EAAU;AAAC,oBAAA;AAA8B;AAC3C;AACF,SAAA;AACA,QAAA;YACEJ,MAAAA,EAAQ,KAAA;YACRC,IAAAA,EAAM,iEAAA;YACNC,OAAAA,EAAS,8CAAA;YACTC,MAAAA,EAAQ;gBACNC,QAAAA,EAAU;AAAC,oBAAA;AAA8B;AAC3C;AACF,SAAA;AACA,QAAA;YACEJ,MAAAA,EAAQ,KAAA;YACRC,IAAAA,EAAM,iDAAA;YACNC,OAAAA,EAAS,0CAAA;YACTC,MAAAA,EAAQ;gBACNC,QAAAA,EAAU;AAAC,oBAAA;AAA8B;AAC3C;AACF;AACD;AACH,CAAA;;;;"}
1
+ {"version":3,"file":"admin.mjs","sources":["../../../server/src/routes/admin.ts"],"sourcesContent":["export default {\n type: 'admin',\n routes: [\n {\n method: 'GET',\n path: '/iso-locales',\n handler: 'iso-locales.listIsoLocales',\n config: {\n policies: [\n 'admin::isAuthenticatedAdmin',\n {\n name: 'plugin::content-manager.hasPermissions',\n config: { actions: ['plugin::i18n.locale.read'] },\n },\n ],\n },\n },\n {\n method: 'GET',\n path: '/locales',\n handler: 'locales.listLocales',\n config: {\n policies: ['admin::isAuthenticatedAdmin'],\n },\n },\n {\n method: 'POST',\n path: '/locales',\n handler: 'locales.createLocale',\n config: {\n policies: [\n 'admin::isAuthenticatedAdmin',\n {\n name: 'plugin::content-manager.hasPermissions',\n config: { actions: ['plugin::i18n.locale.create'] },\n },\n ],\n },\n },\n {\n method: 'PUT',\n path: '/locales/:id',\n handler: 'locales.updateLocale',\n config: {\n policies: [\n 'admin::isAuthenticatedAdmin',\n {\n name: 'plugin::content-manager.hasPermissions',\n config: { actions: ['plugin::i18n.locale.update'] },\n },\n ],\n },\n },\n {\n method: 'DELETE',\n path: '/locales/:id',\n handler: 'locales.deleteLocale',\n config: {\n policies: [\n 'admin::isAuthenticatedAdmin',\n {\n name: 'plugin::content-manager.hasPermissions',\n config: { actions: ['plugin::i18n.locale.delete'] },\n },\n ],\n },\n },\n {\n method: 'POST',\n path: '/content-manager/actions/get-non-localized-fields',\n handler: 'content-types.getNonLocalizedAttributes',\n config: {\n policies: ['admin::isAuthenticatedAdmin'],\n },\n },\n {\n method: 'GET',\n path: '/content-manager/get-fill-from-locale/:model',\n handler: 'content-types.getFillFromLocaleData',\n config: {\n policies: [\n 'admin::isAuthenticatedAdmin',\n {\n name: 'plugin::content-manager.hasPermissions',\n config: { actions: ['plugin::content-manager.explorer.read'] },\n },\n ],\n },\n },\n {\n method: 'GET',\n path: '/settings',\n handler: 'settings.getSettings',\n config: {\n policies: ['admin::isAuthenticatedAdmin'],\n },\n },\n {\n method: 'PUT',\n path: '/settings',\n handler: 'settings.updateSettings',\n config: {\n policies: ['admin::isAuthenticatedAdmin'],\n },\n },\n {\n method: 'GET',\n path: '/ai-localization-jobs/collection-types/:contentType/:documentId',\n handler: 'ai-localization-jobs.getJobForCollectionType',\n config: {\n policies: ['admin::isAuthenticatedAdmin'],\n },\n },\n {\n method: 'GET',\n path: '/ai-localization-jobs/single-types/:contentType',\n handler: 'ai-localization-jobs.getJobForSingleType',\n config: {\n policies: ['admin::isAuthenticatedAdmin'],\n },\n },\n ],\n};\n"],"names":["type","routes","method","path","handler","config","policies","name","actions"],"mappings":"AAAA,YAAe;IACbA,IAAAA,EAAM,OAAA;IACNC,MAAAA,EAAQ;AACN,QAAA;YACEC,MAAAA,EAAQ,KAAA;YACRC,IAAAA,EAAM,cAAA;YACNC,OAAAA,EAAS,4BAAA;YACTC,MAAAA,EAAQ;gBACNC,QAAAA,EAAU;AACR,oBAAA,6BAAA;AACA,oBAAA;wBACEC,IAAAA,EAAM,wCAAA;wBACNF,MAAAA,EAAQ;4BAAEG,OAAAA,EAAS;AAAC,gCAAA;AAA2B;AAAC;AAClD;AACD;AACH;AACF,SAAA;AACA,QAAA;YACEN,MAAAA,EAAQ,KAAA;YACRC,IAAAA,EAAM,UAAA;YACNC,OAAAA,EAAS,qBAAA;YACTC,MAAAA,EAAQ;gBACNC,QAAAA,EAAU;AAAC,oBAAA;AAA8B;AAC3C;AACF,SAAA;AACA,QAAA;YACEJ,MAAAA,EAAQ,MAAA;YACRC,IAAAA,EAAM,UAAA;YACNC,OAAAA,EAAS,sBAAA;YACTC,MAAAA,EAAQ;gBACNC,QAAAA,EAAU;AACR,oBAAA,6BAAA;AACA,oBAAA;wBACEC,IAAAA,EAAM,wCAAA;wBACNF,MAAAA,EAAQ;4BAAEG,OAAAA,EAAS;AAAC,gCAAA;AAA6B;AAAC;AACpD;AACD;AACH;AACF,SAAA;AACA,QAAA;YACEN,MAAAA,EAAQ,KAAA;YACRC,IAAAA,EAAM,cAAA;YACNC,OAAAA,EAAS,sBAAA;YACTC,MAAAA,EAAQ;gBACNC,QAAAA,EAAU;AACR,oBAAA,6BAAA;AACA,oBAAA;wBACEC,IAAAA,EAAM,wCAAA;wBACNF,MAAAA,EAAQ;4BAAEG,OAAAA,EAAS;AAAC,gCAAA;AAA6B;AAAC;AACpD;AACD;AACH;AACF,SAAA;AACA,QAAA;YACEN,MAAAA,EAAQ,QAAA;YACRC,IAAAA,EAAM,cAAA;YACNC,OAAAA,EAAS,sBAAA;YACTC,MAAAA,EAAQ;gBACNC,QAAAA,EAAU;AACR,oBAAA,6BAAA;AACA,oBAAA;wBACEC,IAAAA,EAAM,wCAAA;wBACNF,MAAAA,EAAQ;4BAAEG,OAAAA,EAAS;AAAC,gCAAA;AAA6B;AAAC;AACpD;AACD;AACH;AACF,SAAA;AACA,QAAA;YACEN,MAAAA,EAAQ,MAAA;YACRC,IAAAA,EAAM,mDAAA;YACNC,OAAAA,EAAS,yCAAA;YACTC,MAAAA,EAAQ;gBACNC,QAAAA,EAAU;AAAC,oBAAA;AAA8B;AAC3C;AACF,SAAA;AACA,QAAA;YACEJ,MAAAA,EAAQ,KAAA;YACRC,IAAAA,EAAM,8CAAA;YACNC,OAAAA,EAAS,qCAAA;YACTC,MAAAA,EAAQ;gBACNC,QAAAA,EAAU;AACR,oBAAA,6BAAA;AACA,oBAAA;wBACEC,IAAAA,EAAM,wCAAA;wBACNF,MAAAA,EAAQ;4BAAEG,OAAAA,EAAS;AAAC,gCAAA;AAAwC;AAAC;AAC/D;AACD;AACH;AACF,SAAA;AACA,QAAA;YACEN,MAAAA,EAAQ,KAAA;YACRC,IAAAA,EAAM,WAAA;YACNC,OAAAA,EAAS,sBAAA;YACTC,MAAAA,EAAQ;gBACNC,QAAAA,EAAU;AAAC,oBAAA;AAA8B;AAC3C;AACF,SAAA;AACA,QAAA;YACEJ,MAAAA,EAAQ,KAAA;YACRC,IAAAA,EAAM,WAAA;YACNC,OAAAA,EAAS,yBAAA;YACTC,MAAAA,EAAQ;gBACNC,QAAAA,EAAU;AAAC,oBAAA;AAA8B;AAC3C;AACF,SAAA;AACA,QAAA;YACEJ,MAAAA,EAAQ,KAAA;YACRC,IAAAA,EAAM,iEAAA;YACNC,OAAAA,EAAS,8CAAA;YACTC,MAAAA,EAAQ;gBACNC,QAAAA,EAAU;AAAC,oBAAA;AAA8B;AAC3C;AACF,SAAA;AACA,QAAA;YACEJ,MAAAA,EAAQ,KAAA;YACRC,IAAAA,EAAM,iDAAA;YACNC,OAAAA,EAAS,0CAAA;YACTC,MAAAA,EAAQ;gBACNC,QAAAA,EAAU;AAAC,oBAAA;AAA8B;AAC3C;AACF;AACD;AACH,CAAA;;;;"}
@@ -111,22 +111,12 @@ const createAILocalizationsService = ({ strapi })=>{
111
111
  return {
112
112
  // Async to avoid changing the signature later (there will be a db check in the future)
113
113
  async isEnabled () {
114
- // Check if user disabled AI features globally
115
- const isAIEnabled = strapi.config.get('admin.ai.enabled', true);
116
- if (!isAIEnabled) {
117
- return false;
118
- }
119
- // Check if the user's license grants access to AI features
120
- const hasAccess = strapi.ee.features.isEnabled('cms-ai');
121
- if (!hasAccess) {
114
+ if (strapi.ai.admin.isEnabled() === false) {
122
115
  return false;
123
116
  }
124
117
  const settings = index.getService('settings');
125
118
  const aiSettings = await settings.getSettings();
126
- if (!aiSettings?.aiLocalizations) {
127
- return false;
128
- }
129
- return true;
119
+ return aiSettings?.aiLocalizations === true;
130
120
  },
131
121
  /**
132
122
  * Checks if there are localizations that need to be generated for the given document,
@@ -212,7 +202,7 @@ const createAILocalizationsService = ({ strapi })=>{
212
202
  });
213
203
  let token;
214
204
  try {
215
- const tokenData = await strapi.get('ai').getAiToken();
205
+ const tokenData = await strapi.ai.admin.getAiToken();
216
206
  token = tokenData.token;
217
207
  } catch (error) {
218
208
  await aiLocalizationJobsService.upsertJobForDocument({