From 67816b27ae76a5decf61893bbb1e6b1c3dd4862e Mon Sep 17 00:00:00 2001 From: Marc-Roig Date: Mon, 24 Apr 2023 08:58:30 +0200 Subject: [PATCH 01/84] feat: add wrapResult and wrapEntity methods to be decorated --- .../lib/services/entity-service/index.js | 56 ++++++++++++++----- 1 file changed, 43 insertions(+), 13 deletions(-) diff --git a/packages/core/strapi/lib/services/entity-service/index.js b/packages/core/strapi/lib/services/entity-service/index.js index 2cf70b83de..5b2f2bac1c 100644 --- a/packages/core/strapi/lib/services/entity-service/index.js +++ b/packages/core/strapi/lib/services/entity-service/index.js @@ -59,6 +59,22 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator }) return options; }, + async wrapEntity(entity) { + return entity; + }, + + async wrapResult(result) { + // If result is an array, wrap each entity + if (Array.isArray(result)) { + const wrappedEntities = Array(result.length); + for (const entity of result) { + wrappedEntities.push(this.wrapEntity(entity)); + } + return Promise.all(wrappedEntities); + } + return this.wrapEntity(result); + }, + async emitEvent(uid, event, entity) { // Ignore audit log events to prevent infinite loops if (uid === 'admin::audit-log') { @@ -86,7 +102,8 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator }) return db.query(uid).findOne(query); } - return db.query(uid).findMany(query); + const entities = await db.query(uid).findMany(query); + return this.wrapResult(entities); }, async findPage(uid, opts) { @@ -94,7 +111,8 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator }) const query = transformParamsToQuery(uid, wrappedParams); - return db.query(uid).findPage(query); + const page = await db.query(uid).findPage(query); + return this.wrapResult(page); }, // TODO: streamline the logic based on the populate option @@ -103,7 +121,8 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator }) const query = transformParamsToQuery(uid, wrappedParams); - return db.query(uid).findPage(query); + const entities = await db.query(uid).findPage(query); + return this.wrapResult(entities); }, async findWithRelationCounts(uid, opts) { @@ -111,7 +130,8 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator }) const query = transformParamsToQuery(uid, wrappedParams); - return db.query(uid).findMany(query); + const entities = db.query(uid).findMany(query); + return this.wrapResult(entities); }, async findOne(uid, entityId, opts) { @@ -119,7 +139,8 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator }) const query = transformParamsToQuery(uid, pickSelectionParams(wrappedParams)); - return db.query(uid).findOne({ ...query, where: { id: entityId } }); + const entity = db.query(uid).findOne({ ...query, where: { id: entityId } }); + return this.wrapResult(entity); }, async count(uid, opts) { @@ -164,7 +185,7 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator }) await this.emitEvent(uid, ENTRY_CREATE, entity); - return entity; + return this.wrapResult(entity); }, async update(uid, entityId, opts) { @@ -215,7 +236,7 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator }) await this.emitEvent(uid, ENTRY_UPDATE, entity); - return entity; + return this.wrapResult(entity); }, async delete(uid, entityId, opts) { @@ -240,7 +261,7 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator }) await this.emitEvent(uid, ENTRY_DELETE, entityToDelete); - return entityToDelete; + return this.wrapResult(entityToDelete); }, // FIXME: used only for the CM to be removed @@ -268,18 +289,22 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator }) // Trigger webhooks. One for each entity await Promise.all(entitiesToDelete.map((entity) => this.emitEvent(uid, ENTRY_DELETE, entity))); - return deletedEntities; + return this.wrapResult(deletedEntities); }, - load(uid, entity, field, params = {}) { + async load(uid, entity, field, params = {}) { if (!_.isString(field)) { throw new Error(`Invalid load. Expected "${field}" to be a string`); } - return db.query(uid).load(entity, field, transformLoadParamsToQuery(uid, field, params)); + const loadedEntity = await db + .query(uid) + .load(entity, field, transformLoadParamsToQuery(uid, field, params)); + + return this.wrapResult(loadedEntity); }, - loadPages(uid, entity, field, params = {}, pagination = {}) { + async loadPages(uid, entity, field, params = {}, pagination = {}) { if (!_.isString(field)) { throw new Error(`Invalid load. Expected "${field}" to be a string`); } @@ -293,7 +318,12 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator }) const query = transformLoadParamsToQuery(uid, field, params, pagination); - return db.query(uid).loadPages(entity, field, query); + const loadedPage = db.query(uid).loadPages(entity, field, query); + + return { + ...loadedPage, + results: await this.wrapResult(loadedPage.results), + }; }, }); From bf49cdb42af87846eae1a34df6263717c1f9847f Mon Sep 17 00:00:00 2001 From: Marc-Roig Date: Mon, 24 Apr 2023 10:20:01 +0200 Subject: [PATCH 02/84] fix: add missing await --- packages/core/strapi/lib/services/entity-service/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/strapi/lib/services/entity-service/index.js b/packages/core/strapi/lib/services/entity-service/index.js index 5b2f2bac1c..357fedc2a7 100644 --- a/packages/core/strapi/lib/services/entity-service/index.js +++ b/packages/core/strapi/lib/services/entity-service/index.js @@ -318,7 +318,7 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator }) const query = transformLoadParamsToQuery(uid, field, params, pagination); - const loadedPage = db.query(uid).loadPages(entity, field, query); + const loadedPage = await db.query(uid).loadPages(entity, field, query); return { ...loadedPage, From cd97074e335347c82b30225a2bd4a562ad6c6a8a Mon Sep 17 00:00:00 2001 From: Marc-Roig Date: Mon, 24 Apr 2023 10:44:24 +0200 Subject: [PATCH 03/84] fix: return attributes of findPage --- packages/core/strapi/lib/services/entity-service/index.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/core/strapi/lib/services/entity-service/index.js b/packages/core/strapi/lib/services/entity-service/index.js index 357fedc2a7..0aeb6940af 100644 --- a/packages/core/strapi/lib/services/entity-service/index.js +++ b/packages/core/strapi/lib/services/entity-service/index.js @@ -112,7 +112,10 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator }) const query = transformParamsToQuery(uid, wrappedParams); const page = await db.query(uid).findPage(query); - return this.wrapResult(page); + return { + ...page, + results: await this.wrapResult(page.results), + }; }, // TODO: streamline the logic based on the populate option From 05f29deee63ad006f798165517c3419dc54b7af8 Mon Sep 17 00:00:00 2001 From: Marc-Roig Date: Mon, 24 Apr 2023 10:44:46 +0200 Subject: [PATCH 04/84] fix: don't pre initialize array --- packages/core/strapi/lib/services/entity-service/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/strapi/lib/services/entity-service/index.js b/packages/core/strapi/lib/services/entity-service/index.js index 0aeb6940af..04fa0e47ab 100644 --- a/packages/core/strapi/lib/services/entity-service/index.js +++ b/packages/core/strapi/lib/services/entity-service/index.js @@ -66,7 +66,7 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator }) async wrapResult(result) { // If result is an array, wrap each entity if (Array.isArray(result)) { - const wrappedEntities = Array(result.length); + const wrappedEntities = []; for (const entity of result) { wrappedEntities.push(this.wrapEntity(entity)); } From 47376f0365ea69b037051f79e5556b5d41bb3e4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9Cmarwa-hodeib=E2=80=9D?= Date: Mon, 24 Apr 2023 12:22:32 +0300 Subject: [PATCH 05/84] Adding50ArabicTranslations --- .../core/admin/admin/src/translations/ar.json | 79 ++++++++++++++++++- 1 file changed, 78 insertions(+), 1 deletion(-) diff --git a/packages/core/admin/admin/src/translations/ar.json b/packages/core/admin/admin/src/translations/ar.json index 47a40a81a9..dab8a47c76 100644 --- a/packages/core/admin/admin/src/translations/ar.json +++ b/packages/core/admin/admin/src/translations/ar.json @@ -205,5 +205,82 @@ "content-manager.success.record.save": "حُفظ", "notification.error": "حدث خطأ", "notification.error.layout": "تعذّر استرداد التنسيق", - "request.error.model.unknown": "هذا النموذج غير موجود" + "request.error.model.unknown": "هذا النموذج غير موجود", + "admin.pages.MarketPlacePage.filters.categories": "فئات", + "admin.pages.MarketPlacePage.filters.collections": "المجموعات", + "admin.pages.MarketPlacePage.helmet": "السوق - الإضافات", + "admin.pages.MarketPlacePage.missingPlugin.description": "أخبرنا ما هو المكون الإضافي الذي تبحث عنه وسنعلم مطوري المكونات الإضافية في مجتمعنا في حال كانوا يبحثون عن الإلهام!", + "admin.pages.MarketPlacePage.missingPlugin.title": "هل فقدت مكونًا إضافيًا؟", + "admin.pages.MarketPlacePage.offline.subtitle": "يجب أن تكون متصلاً بالإنترنت للوصول إلى سوق سترابي", + "admin.pages.MarketPlacePage.offline.title": "انت غير متصل", + "admin.pages.MarketPlacePage.plugin.copy": "أمر نسخ التثبيت", + "admin.pages.MarketPlacePage.plugin.copy.success": "قم بتثبيت الأمر جاهزًا ليتم لصقه في الجهاز الطرفي", + "admin.pages.MarketPlacePage.plugin.downloads": "يتم تنزيل هذا المكون الإضافي {downloadsCount} أسبوعيًا", + "admin.pages.MarketPlacePage.plugin.githubStars": "تم تمييز هذا المكون الإضافي بنجمة على GitHub", + "admin.pages.MarketPlacePage.plugin.info": "يتعلم أكثر", + "admin.pages.MarketPlacePage.plugin.info.label": "تعرف على المزيد حول {pluginName}", + "admin.pages.MarketPlacePage.plugin.info.text": "أكثر", + "admin.pages.MarketPlacePage.plugin.installed": "المثبتة", + "admin.pages.MarketPlacePage.plugin.tooltip.madeByStrapi": "صنع بواسطة ستربي", + "admin.pages.MarketPlacePage.plugin.tooltip.verified": "Strapi تم التحقق من البرنامج المساعد من قبل ", + "admin.pages.MarketPlacePage.plugins": "الإضافات", + "admin.pages.MarketPlacePage.provider.downloads": "هذا الموفر لديه {downloadsCount} من التنزيلات الأسبوعية", + "admin.pages.MarketPlacePage.provider.githubStars": "{GitHub} على {starsCount} تم تميز هذا المزود ", + "admin.pages.MarketPlacePage.providers": "الموفرون", + "admin.pages.MarketPlacePage.search.clear": "مسح البحث", + "admin.pages.MarketPlacePage.search.empty": " \"{target}\" لا توجد نتيجة ل", + "admin.pages.MarketPlacePage.search.placeholder": "يبحث", + "admin.pages.MarketPlacePage.sort.alphabetical": "ترتيب ابجدي", + "admin.pages.MarketPlacePage.sort.alphabetical.selected": "فرز حسب الترتيب الأبجدي", + "admin.pages.MarketPlacePage.sort.githubStars": "GitHub عدد نجوم", + "admin.pages.MarketPlacePage.sort.githubStars.selected": "GitHub الترتيب حسب نجوم", + "admin.pages.MarketPlacePage.sort.newest": "الأحدث", + "admin.pages.MarketPlacePage.sort.newest.selected": "ترتيب حسب الأحدث", + "admin.pages.MarketPlacePage.sort.npmDownloads": "عدد التنزيلات", + "admin.pages.MarketPlacePage.sort.npmDownloads.selected": "npm فرز حسب التنزيلات ", + "admin.pages.MarketPlacePage.submit.plugin.link": "إرسال البرنامج المساعد", + "admin.pages.MarketPlacePage.submit.provider.link": "إرسال مزود", + "admin.pages.MarketPlacePage.subtitle": " Strapi احصل على المزيد من", + "admin.pages.MarketPlacePage.tab-group.label": "Strapi الإضافات ومقدمي ", + "Analytics": "تحليلات", + "anErrorOccurred": "عذرًا! هناك خطأ ما. حاول مرة اخرى.", + "app.component.CopyToClipboard.label": "نسخ إلى الحافظة", + "app.component.search.label": "{target} بحث عن", + "app.component.table.duplicate": "{target} ينسخ", + "app.component.table.edit": "{target} يحرر", + "app.component.table.read": "{target}يقرأ", + "app.component.table.select.one-entry": "{target}يختار", + "app.component.table.view": "{target} تفاصيل", + "app.components.BlockLink.blog": "مدونة", + "admin.pages.MarketPlacePage.filters.categoriesSelected": "{count, plural, =0 {No categories} واحد {# category} آخر{# categories}} المحدد", + "admin.pages.MarketPlacePage.plugin.version": " قم بتحديث إصدار الخاص بك : \"{strapiAppVersion}\" ل: \"{versionRange}\"", + "admin.pages.MarketPlacePage.plugin.version.null": "تعذر التحقق من التوافق مع إصدار Strapi الخاص بك: \"{strapiAppVersion}\"", + "app.components.BlockLink.blog.content": "اقرأ آخر الأخبار حول Strapi والنظام البيئي.", + "app.components.BlockLink.cloud": "Strapi سحاب", + "app.components.BlockLink.cloud.content": "نظام أساسي قابل للإنشاء والتعاون بشكل كامل لزيادة سرعة فريقك.", + "app.components.BlockLink.code.content": "تعلم من خلال اختبار المشاريع الحقيقية التي طورها المجتمع.", + "app.components.BlockLink.documentation.content": "اكتشف المفاهيم الأساسية والأدلة والتعليمات.", + "app.components.BlockLink.tutorial": "دروس", + "app.components.BlockLink.tutorial.content": "Strapi اتبع التعليمات خطوة بخطوة للاستخدام والتخصيص.", + "app.components.Button.confirm": "يتأكد", + "app.components.Button.reset": "إعادة ضبط", + "app.components.ConfirmDialog.title": "تأكيد", + "app.components.EmptyStateLayout.content-document": "لم يتم العثور على محتوى", + "app.components.EmptyStateLayout.content-permissions": "ليس لديك أذونات للوصول إلى هذا المحتوى", + "app.components.GuidedTour.apiTokens.create.content": "

قم بإنشاء رمز المصادقة هنا واسترجع المحتوى الذي أنشأته للتو.

", + "app.components.GuidedTour.apiTokens.create.cta.title": "API إنشاء رمز", + "app.components.GuidedTour.apiTokens.create.title": "🚀 مشاهدة المحتوى في العمل", + "app.components.GuidedTour.apiTokens.success.cta.title": "العودة الى الصفحة الرئيسية", + "app.components.GuidedTour.apiTokens.success.title": "✅ الخطوة 3: اكتمل", + "app.components.GuidedTour.CM.create.content": "

قم بإنشاء وإدارة كل المحتوى هنا في إدارة المحتوى.

مثال: أخذ مثال موقع المدونة إلى أبعد من ذلك ، يمكن للمرء كتابة مقال وحفظه ونشره كما يحلو له.

💡 نصيحة سريعة - لا تنس النقر على "نشر" على المحتوى الذي تنشئه.

", + "app.components.GuidedTour.CM.create.title": "⚡️ أنشئ محتوى", + "app.components.GuidedTour.CM.success.content": "

رائع ، خطوة أخيرة يجب أن تبدأ بها!

🚀 مشاهدة المحتوى في العمل", + "app.components.GuidedTour.CM.success.cta.title": "API اختبر ملف", + "app.components.GuidedTour.CM.success.title": "✅ الخطوة 2: اكتمل", + "app.components.GuidedTour.create-content": "أنشئ محتوى", + "app.components.GuidedTour.CTB.create.content": "

تساعدك أنواع المجموعات على إدارة عدة إدخالات ، والأنواع الفردية مناسبة لإدارة إدخال واحد فقط.

على سبيل المثال: بالنسبة إلى موقع مدونة ، ستكون المقالات من نوع المجموعة بينما تكون الصفحة الرئيسية من النوع الفردي.

", + "app.components.GuidedTour.CTB.create.cta.title": "بناء نوع المجموعة", + "app.components.GuidedTour.CTB.create.title": "🧠 قم بإنشاء أول نوع مجموعة", + "app.components.GuidedTour.CTB.success.content": "

جيد!

⚡️ ما الذي تود مشاركته مع العالم؟", + } From 4606c8a01e34c28456fb1c8f662aecdf3c1516bf Mon Sep 17 00:00:00 2001 From: Boegie19 Date: Mon, 24 Apr 2023 14:06:02 +0200 Subject: [PATCH 06/84] fix wrapParams ignoring lower services --- .../plugins/i18n/server/services/entity-service-decorator.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/plugins/i18n/server/services/entity-service-decorator.js b/packages/plugins/i18n/server/services/entity-service-decorator.js index 256e81f55f..dee836a49b 100644 --- a/packages/plugins/i18n/server/services/entity-service-decorator.js +++ b/packages/plugins/i18n/server/services/entity-service-decorator.js @@ -96,7 +96,7 @@ const decorator = (service) => ({ return wrappedParams; } - return wrapParams(params, ctx); + return wrapParams(wrappedParams, ctx); }, /** From 4a4a84926fd17a12e22870a8410a10287c7919b5 Mon Sep 17 00:00:00 2001 From: Boegie19 Date: Mon, 24 Apr 2023 16:34:47 +0200 Subject: [PATCH 07/84] i18n entity-service decorator findMany fix --- .../services/entity-service-decorator.js | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/packages/plugins/i18n/server/services/entity-service-decorator.js b/packages/plugins/i18n/server/services/entity-service-decorator.js index 256e81f55f..60227595fb 100644 --- a/packages/plugins/i18n/server/services/entity-service-decorator.js +++ b/packages/plugins/i18n/server/services/entity-service-decorator.js @@ -5,6 +5,7 @@ const { ApplicationError } = require('@strapi/utils').errors; const { transformParamsToQuery } = require('@strapi/utils').convertQueryParams; const { getService } = require('../utils'); +const { unformatLayout } = require('../../../../core/admin/admin/src/content-manager/pages/EditSettingsView/utils/layout'); const LOCALE_QUERY_FILTER = 'locale'; const SINGLE_ENTRY_ACTIONS = ['findOne', 'update', 'delete']; @@ -169,16 +170,24 @@ const decorator = (service) => ({ const wrappedParams = await this.wrapParams(opts, { uid, action: 'findMany' }); - const query = transformParamsToQuery(uid, wrappedParams); - if (kind === 'singleType') { - if (opts[LOCALE_QUERY_FILTER] === 'all') { - return strapi.db.query(uid).findMany(query); + if (kind === 'singleType' && opts[LOCALE_QUERY_FILTER] !== 'all') { + const query = { + ...transformParamsToQuery(uid, wrappedParams), + select: [], + populate: {} + + }; + + // Since we change from findMany to findOne we need to restart the process so we use the entityService + const result = strapi.db.query(uid).findOne(query); + if(result === null){ + return null } - return strapi.db.query(uid).findOne(query); + return strapi.entityService.findOne(uid, result.id) } - return strapi.db.query(uid).findMany(query); + return service.findMany.call(this, uid, wrappedParams); }, }); From f0a4d8e541fe0bfb6b1f3e2d7fefdec008deafbe Mon Sep 17 00:00:00 2001 From: Boegie19 Date: Mon, 24 Apr 2023 16:46:45 +0200 Subject: [PATCH 08/84] changed comment location --- .../plugins/i18n/server/services/entity-service-decorator.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/plugins/i18n/server/services/entity-service-decorator.js b/packages/plugins/i18n/server/services/entity-service-decorator.js index 60227595fb..e2bb0816a3 100644 --- a/packages/plugins/i18n/server/services/entity-service-decorator.js +++ b/packages/plugins/i18n/server/services/entity-service-decorator.js @@ -170,7 +170,6 @@ const decorator = (service) => ({ const wrappedParams = await this.wrapParams(opts, { uid, action: 'findMany' }); - if (kind === 'singleType' && opts[LOCALE_QUERY_FILTER] !== 'all') { const query = { ...transformParamsToQuery(uid, wrappedParams), @@ -179,11 +178,11 @@ const decorator = (service) => ({ }; - // Since we change from findMany to findOne we need to restart the process so we use the entityService const result = strapi.db.query(uid).findOne(query); if(result === null){ return null } + // Since we change from findMany to findOne we need to restart the process so we use the entityService return strapi.entityService.findOne(uid, result.id) } From c1541c42685e4419b1f62e6d01f1f94e8d56a4ad Mon Sep 17 00:00:00 2001 From: Boegie19 Date: Mon, 24 Apr 2023 16:48:27 +0200 Subject: [PATCH 09/84] add awaits --- .../i18n/server/services/entity-service-decorator.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/plugins/i18n/server/services/entity-service-decorator.js b/packages/plugins/i18n/server/services/entity-service-decorator.js index e2bb0816a3..424ecd7b99 100644 --- a/packages/plugins/i18n/server/services/entity-service-decorator.js +++ b/packages/plugins/i18n/server/services/entity-service-decorator.js @@ -178,15 +178,15 @@ const decorator = (service) => ({ }; - const result = strapi.db.query(uid).findOne(query); + const result = await strapi.db.query(uid).findOne(query); if(result === null){ return null } // Since we change from findMany to findOne we need to restart the process so we use the entityService - return strapi.entityService.findOne(uid, result.id) + return await strapi.entityService.findOne(uid, result.id) } - return service.findMany.call(this, uid, wrappedParams); + return await service.findMany.call(this, uid, wrappedParams); }, }); From 0915f36b6d48f272039b0816f011873d394bad7f Mon Sep 17 00:00:00 2001 From: Boegie19 Date: Mon, 24 Apr 2023 17:49:09 +0200 Subject: [PATCH 10/84] fix linting --- .../i18n/server/services/entity-service-decorator.js | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/packages/plugins/i18n/server/services/entity-service-decorator.js b/packages/plugins/i18n/server/services/entity-service-decorator.js index 424ecd7b99..e68d9bb19e 100644 --- a/packages/plugins/i18n/server/services/entity-service-decorator.js +++ b/packages/plugins/i18n/server/services/entity-service-decorator.js @@ -5,7 +5,6 @@ const { ApplicationError } = require('@strapi/utils').errors; const { transformParamsToQuery } = require('@strapi/utils').convertQueryParams; const { getService } = require('../utils'); -const { unformatLayout } = require('../../../../core/admin/admin/src/content-manager/pages/EditSettingsView/utils/layout'); const LOCALE_QUERY_FILTER = 'locale'; const SINGLE_ENTRY_ACTIONS = ['findOne', 'update', 'delete']; @@ -174,19 +173,18 @@ const decorator = (service) => ({ const query = { ...transformParamsToQuery(uid, wrappedParams), select: [], - populate: {} - + populate: {}, }; const result = await strapi.db.query(uid).findOne(query); - if(result === null){ - return null + if (result === null) { + return null; } // Since we change from findMany to findOne we need to restart the process so we use the entityService - return await strapi.entityService.findOne(uid, result.id) + return strapi.entityService.findOne(uid, result.id); } - return await service.findMany.call(this, uid, wrappedParams); + return service.findMany.call(this, uid, wrappedParams); }, }); From fbe8bad4f0d47d58af5f5c82bcb79190aa1e560f Mon Sep 17 00:00:00 2001 From: Boegie19 Date: Mon, 24 Apr 2023 19:57:43 +0200 Subject: [PATCH 11/84] fixed entity-service decorator tests --- .../services/__tests__/entity-service-decorator.test.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/plugins/i18n/server/services/__tests__/entity-service-decorator.test.js b/packages/plugins/i18n/server/services/__tests__/entity-service-decorator.test.js index 1a2fa3f016..882fb3425f 100644 --- a/packages/plugins/i18n/server/services/__tests__/entity-service-decorator.test.js +++ b/packages/plugins/i18n/server/services/__tests__/entity-service-decorator.test.js @@ -63,6 +63,9 @@ describe('Entity service decorator', () => { update() {}, }; }, + entityService: { + findOne() {}, + }, getModel(uid) { return models[uid || 'test-model']; }, @@ -321,6 +324,7 @@ describe('Entity service decorator', () => { const defaultService = { wrapParams: jest.fn(() => Promise.resolve(entry)), + findMany: jest.fn(() => Promise.resolve(entry)), }; const service = decorator(defaultService); @@ -329,7 +333,7 @@ describe('Entity service decorator', () => { await service.findMany('test-model', input); expect(global.strapi.getModel).toHaveBeenCalledWith('test-model'); - expect(global.strapi.db.query).toHaveBeenCalledWith('test-model'); + expect(defaultService.findMany).toBeCalled(); expect(findManySpy).toHaveBeenCalled(); }); @@ -341,6 +345,7 @@ describe('Entity service decorator', () => { const defaultService = { wrapParams: jest.fn(() => Promise.resolve(entry)), + findMany: jest.fn(() => Promise.resolve(entry)), }; const service = decorator(defaultService); @@ -361,7 +366,7 @@ describe('Entity service decorator', () => { await service.findMany('localized-single-type-model', input); expect(global.strapi.getModel).toHaveBeenCalledWith('localized-single-type-model'); - expect(global.strapi.db.query).toHaveBeenCalledWith('localized-single-type-model'); + expect(defaultService.findMany).toBeCalled(); expect(findManySpy).toHaveBeenCalled(); }); From 42bf6410ee957969ffe047aacfd566d18c7acf9a Mon Sep 17 00:00:00 2001 From: Boegie19 Date: Mon, 24 Apr 2023 20:28:09 +0200 Subject: [PATCH 12/84] fix even more tests --- .../services/__tests__/entity-service-decorator.test.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/plugins/i18n/server/services/__tests__/entity-service-decorator.test.js b/packages/plugins/i18n/server/services/__tests__/entity-service-decorator.test.js index 882fb3425f..b8e8df3764 100644 --- a/packages/plugins/i18n/server/services/__tests__/entity-service-decorator.test.js +++ b/packages/plugins/i18n/server/services/__tests__/entity-service-decorator.test.js @@ -360,6 +360,11 @@ describe('Entity service decorator', () => { global.strapi = { ...global.strapi, getModel: jest.fn((uid) => models[uid || 'test-model']), + entityService: { + findOne() { + return entry; + }, + }, db, }; const input = { data: { title: 'title ' }, locale: 'all' }; @@ -367,7 +372,6 @@ describe('Entity service decorator', () => { expect(global.strapi.getModel).toHaveBeenCalledWith('localized-single-type-model'); expect(defaultService.findMany).toBeCalled(); - expect(findManySpy).toHaveBeenCalled(); }); test('calls db.findMany for single type with no local param', async () => { @@ -386,8 +390,7 @@ describe('Entity service decorator', () => { await service.findMany('localized-single-type-model', input); expect(global.strapi.getModel).toHaveBeenCalledWith('localized-single-type-model'); - expect(global.strapi.db.query).toHaveBeenCalledWith('localized-single-type-model'); - expect(findOneSpy).toHaveBeenCalled(); + expect(defaultService.findMany).toHaveBeenCalledWith('localized-single-type-model'); }); }); }); From 527d9568959beced5b7ca548734660784f4b5cbd Mon Sep 17 00:00:00 2001 From: Boegie19 Date: Mon, 24 Apr 2023 20:45:48 +0200 Subject: [PATCH 13/84] fixed mistake --- .../services/__tests__/entity-service-decorator.test.js | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/packages/plugins/i18n/server/services/__tests__/entity-service-decorator.test.js b/packages/plugins/i18n/server/services/__tests__/entity-service-decorator.test.js index b8e8df3764..f97983bdb8 100644 --- a/packages/plugins/i18n/server/services/__tests__/entity-service-decorator.test.js +++ b/packages/plugins/i18n/server/services/__tests__/entity-service-decorator.test.js @@ -334,7 +334,6 @@ describe('Entity service decorator', () => { expect(global.strapi.getModel).toHaveBeenCalledWith('test-model'); expect(defaultService.findMany).toBeCalled(); - expect(findManySpy).toHaveBeenCalled(); }); describe('single types', () => { @@ -355,16 +354,14 @@ describe('Entity service decorator', () => { const db = { query: jest.fn(() => ({ findMany: findManySpy, + findOne() { + return entry; + }, })), }; global.strapi = { ...global.strapi, getModel: jest.fn((uid) => models[uid || 'test-model']), - entityService: { - findOne() { - return entry; - }, - }, db, }; const input = { data: { title: 'title ' }, locale: 'all' }; From 129197609eaad936efc35f43c8703a0952f97f6e Mon Sep 17 00:00:00 2001 From: Boegie19 Date: Mon, 24 Apr 2023 21:14:41 +0200 Subject: [PATCH 14/84] fix db.query.findOne --- .../services/__tests__/entity-service-decorator.test.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/plugins/i18n/server/services/__tests__/entity-service-decorator.test.js b/packages/plugins/i18n/server/services/__tests__/entity-service-decorator.test.js index f97983bdb8..6b6cf421cd 100644 --- a/packages/plugins/i18n/server/services/__tests__/entity-service-decorator.test.js +++ b/packages/plugins/i18n/server/services/__tests__/entity-service-decorator.test.js @@ -354,9 +354,7 @@ describe('Entity service decorator', () => { const db = { query: jest.fn(() => ({ findMany: findManySpy, - findOne() { - return entry; - }, + findOne: jest.fn(() => Promise.resolve(entry)), })), }; global.strapi = { From cf18d058615f9134b6dc59a59b3824f10ec33770 Mon Sep 17 00:00:00 2001 From: Boegie19 Date: Tue, 25 Apr 2023 11:06:54 +0200 Subject: [PATCH 15/84] fixed findOne --- .../server/services/__tests__/entity-service-decorator.test.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/plugins/i18n/server/services/__tests__/entity-service-decorator.test.js b/packages/plugins/i18n/server/services/__tests__/entity-service-decorator.test.js index 6b6cf421cd..11ef7fab93 100644 --- a/packages/plugins/i18n/server/services/__tests__/entity-service-decorator.test.js +++ b/packages/plugins/i18n/server/services/__tests__/entity-service-decorator.test.js @@ -354,7 +354,6 @@ describe('Entity service decorator', () => { const db = { query: jest.fn(() => ({ findMany: findManySpy, - findOne: jest.fn(() => Promise.resolve(entry)), })), }; global.strapi = { @@ -370,7 +369,7 @@ describe('Entity service decorator', () => { }); test('calls db.findMany for single type with no local param', async () => { - const findOneSpy = jest.fn(); + const findOneSpy = jest.fn(() => Promise.resolve(entry)); const db = { query: jest.fn(() => ({ findOne: findOneSpy, From 8e00ced3d276914e78454d4b6f78d4df8db6f79c Mon Sep 17 00:00:00 2001 From: Boegie19 Date: Tue, 25 Apr 2023 11:26:43 +0200 Subject: [PATCH 16/84] final fix --- .../services/__tests__/entity-service-decorator.test.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/plugins/i18n/server/services/__tests__/entity-service-decorator.test.js b/packages/plugins/i18n/server/services/__tests__/entity-service-decorator.test.js index 11ef7fab93..e5389804a5 100644 --- a/packages/plugins/i18n/server/services/__tests__/entity-service-decorator.test.js +++ b/packages/plugins/i18n/server/services/__tests__/entity-service-decorator.test.js @@ -384,7 +384,9 @@ describe('Entity service decorator', () => { await service.findMany('localized-single-type-model', input); expect(global.strapi.getModel).toHaveBeenCalledWith('localized-single-type-model'); - expect(defaultService.findMany).toHaveBeenCalledWith('localized-single-type-model'); + expect(defaultService.findMany).toHaveBeenCalledWith('localized-single-type-model', { + data: { title: 'title ' }, + }); }); }); }); From ec2328d11e59957bfe7bb6d63e2635b41329254a Mon Sep 17 00:00:00 2001 From: Boegie19 Date: Tue, 25 Apr 2023 13:06:30 +0200 Subject: [PATCH 17/84] init wrapParams output test --- .../__tests__/entity-service-decorator.test.js | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/packages/plugins/i18n/server/services/__tests__/entity-service-decorator.test.js b/packages/plugins/i18n/server/services/__tests__/entity-service-decorator.test.js index 1a2fa3f016..e14795c5a3 100644 --- a/packages/plugins/i18n/server/services/__tests__/entity-service-decorator.test.js +++ b/packages/plugins/i18n/server/services/__tests__/entity-service-decorator.test.js @@ -7,7 +7,7 @@ jest.mock('../localizations', () => { }); }); -const { decorator } = require('../entity-service-decorator')(); +const { decorator, wrapParams } = require('../entity-service-decorator')(); const localizations = require('../localizations')(); const locales = require('../locales')(); const contentTypes = require('../content-types')(); @@ -45,6 +45,8 @@ const models = { 'localized-single-type-model': singleTypeModel, }; +const testModels = [['test-model'], ['non-localized-model'], ['localized-single-type-model']]; + describe('Entity service decorator', () => { beforeAll(() => { global.strapi = { @@ -136,6 +138,16 @@ describe('Entity service decorator', () => { ['delete', { filters: [{ id: { $in: [1] } }] }], ]; + test.each(testModels)('Always uses original wrapParams in output - %s', async (modelName) => { + const defaultService = { + wrapParams: jest.fn(() => Promise.resolve('Test')), + }; + const service = decorator(defaultService); + + const output = await service.wrapParams({}, { uid: modelName, action: 'findMany' }); + + expect(output).toEqual('Test'); + }); test.each(testData)( "Doesn't add locale param when the params contain id or id_in - %s", async (action, params) => { From 6ce1665271ee3c716925c223c64701a598db6042 Mon Sep 17 00:00:00 2001 From: Boegie19 Date: Tue, 25 Apr 2023 13:25:58 +0200 Subject: [PATCH 18/84] removed function --- .../server/services/__tests__/entity-service-decorator.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/plugins/i18n/server/services/__tests__/entity-service-decorator.test.js b/packages/plugins/i18n/server/services/__tests__/entity-service-decorator.test.js index e14795c5a3..cd2e7143e4 100644 --- a/packages/plugins/i18n/server/services/__tests__/entity-service-decorator.test.js +++ b/packages/plugins/i18n/server/services/__tests__/entity-service-decorator.test.js @@ -7,7 +7,7 @@ jest.mock('../localizations', () => { }); }); -const { decorator, wrapParams } = require('../entity-service-decorator')(); +const { decorator } = require('../entity-service-decorator')(); const localizations = require('../localizations')(); const locales = require('../locales')(); const contentTypes = require('../content-types')(); From ec4cb1bfa5ea0cd9bf246b2693cabaa4173d9a8f Mon Sep 17 00:00:00 2001 From: Boegie19 Date: Tue, 25 Apr 2023 13:46:27 +0200 Subject: [PATCH 19/84] fix maby? --- .../plugins/i18n/server/services/entity-service-decorator.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/plugins/i18n/server/services/entity-service-decorator.js b/packages/plugins/i18n/server/services/entity-service-decorator.js index e68d9bb19e..974b8b6cf2 100644 --- a/packages/plugins/i18n/server/services/entity-service-decorator.js +++ b/packages/plugins/i18n/server/services/entity-service-decorator.js @@ -169,7 +169,10 @@ const decorator = (service) => ({ const wrappedParams = await this.wrapParams(opts, { uid, action: 'findMany' }); - if (kind === 'singleType' && opts[LOCALE_QUERY_FILTER] !== 'all') { + if (kind === 'singleType') { + if (opts[LOCALE_QUERY_FILTER] === 'all') { + return service.findMany.call(this, uid, wrappedParams); + } const query = { ...transformParamsToQuery(uid, wrappedParams), select: [], From 20cf36269b43233bf957de7b693944be55ac8d15 Mon Sep 17 00:00:00 2001 From: Boegie19 Date: Tue, 25 Apr 2023 13:51:19 +0200 Subject: [PATCH 20/84] fix output test --- .../services/__tests__/entity-service-decorator.test.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/plugins/i18n/server/services/__tests__/entity-service-decorator.test.js b/packages/plugins/i18n/server/services/__tests__/entity-service-decorator.test.js index cd2e7143e4..f65e58858c 100644 --- a/packages/plugins/i18n/server/services/__tests__/entity-service-decorator.test.js +++ b/packages/plugins/i18n/server/services/__tests__/entity-service-decorator.test.js @@ -140,13 +140,16 @@ describe('Entity service decorator', () => { test.each(testModels)('Always uses original wrapParams in output - %s', async (modelName) => { const defaultService = { - wrapParams: jest.fn(() => Promise.resolve('Test')), + wrapParams: jest.fn(() => Promise.resolve({ Test: 'Test' })), }; const service = decorator(defaultService); const output = await service.wrapParams({}, { uid: modelName, action: 'findMany' }); - expect(output).toEqual('Test'); + expect(output).toEqual({ + Test: 'Test', + filters: { $and: [{ locale: 'en' }] }, + }); }); test.each(testData)( "Doesn't add locale param when the params contain id or id_in - %s", From 78c5c76b8e2dbf787c4027dfe7cddceb77514325 Mon Sep 17 00:00:00 2001 From: Boegie19 Date: Tue, 25 Apr 2023 14:08:03 +0200 Subject: [PATCH 21/84] hopfully fixed test --- .../server/services/__tests__/entity-service-decorator.test.js | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/plugins/i18n/server/services/__tests__/entity-service-decorator.test.js b/packages/plugins/i18n/server/services/__tests__/entity-service-decorator.test.js index f65e58858c..185b4f1f61 100644 --- a/packages/plugins/i18n/server/services/__tests__/entity-service-decorator.test.js +++ b/packages/plugins/i18n/server/services/__tests__/entity-service-decorator.test.js @@ -148,7 +148,6 @@ describe('Entity service decorator', () => { expect(output).toEqual({ Test: 'Test', - filters: { $and: [{ locale: 'en' }] }, }); }); test.each(testData)( From 66b2c5ae74893681a42754badd14ddecca4e9c4e Mon Sep 17 00:00:00 2001 From: Marc-Roig Date: Tue, 25 Apr 2023 14:23:10 +0200 Subject: [PATCH 22/84] feat: just keep wrapResult --- .../strapi/lib/services/entity-service/index.js | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/packages/core/strapi/lib/services/entity-service/index.js b/packages/core/strapi/lib/services/entity-service/index.js index 04fa0e47ab..ce33854fc8 100644 --- a/packages/core/strapi/lib/services/entity-service/index.js +++ b/packages/core/strapi/lib/services/entity-service/index.js @@ -59,20 +59,8 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator }) return options; }, - async wrapEntity(entity) { - return entity; - }, - async wrapResult(result) { - // If result is an array, wrap each entity - if (Array.isArray(result)) { - const wrappedEntities = []; - for (const entity of result) { - wrappedEntities.push(this.wrapEntity(entity)); - } - return Promise.all(wrappedEntities); - } - return this.wrapEntity(result); + return result; }, async emitEvent(uid, event, entity) { From 0fb0bad21993f97746b1605bb9266e2abcbeb359 Mon Sep 17 00:00:00 2001 From: Boegie19 Date: Tue, 25 Apr 2023 14:24:46 +0200 Subject: [PATCH 23/84] fix? --- .../server/services/__tests__/entity-service-decorator.test.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/plugins/i18n/server/services/__tests__/entity-service-decorator.test.js b/packages/plugins/i18n/server/services/__tests__/entity-service-decorator.test.js index 185b4f1f61..f65e58858c 100644 --- a/packages/plugins/i18n/server/services/__tests__/entity-service-decorator.test.js +++ b/packages/plugins/i18n/server/services/__tests__/entity-service-decorator.test.js @@ -148,6 +148,7 @@ describe('Entity service decorator', () => { expect(output).toEqual({ Test: 'Test', + filters: { $and: [{ locale: 'en' }] }, }); }); test.each(testData)( From 0c84b254f7038211e8994e6823fdf8d6b1834de0 Mon Sep 17 00:00:00 2001 From: Marc-Roig Date: Tue, 25 Apr 2023 14:25:22 +0200 Subject: [PATCH 24/84] feat: wrapResult before emitting events --- .../lib/services/entity-service/index.js | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/packages/core/strapi/lib/services/entity-service/index.js b/packages/core/strapi/lib/services/entity-service/index.js index ce33854fc8..3dbe414000 100644 --- a/packages/core/strapi/lib/services/entity-service/index.js +++ b/packages/core/strapi/lib/services/entity-service/index.js @@ -174,9 +174,11 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator }) entity = await this.findOne(uid, entity.id, wrappedParams); } + entity = await this.wrapResult(entity); + await this.emitEvent(uid, ENTRY_CREATE, entity); - return this.wrapResult(entity); + return entity; }, async update(uid, entityId, opts) { @@ -225,9 +227,11 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator }) entity = await this.findOne(uid, entity.id, wrappedParams); } + entity = await this.wrapResult(entity); + await this.emitEvent(uid, ENTRY_UPDATE, entity); - return this.wrapResult(entity); + return entity; }, async delete(uid, entityId, opts) { @@ -236,7 +240,7 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator }) // select / populate const query = transformParamsToQuery(uid, pickSelectionParams(wrappedParams)); - const entityToDelete = await db.query(uid).findOne({ + let entityToDelete = await db.query(uid).findOne({ ...query, where: { id: entityId }, }); @@ -250,9 +254,11 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator }) await db.query(uid).delete({ where: { id: entityToDelete.id } }); await deleteComponents(uid, componentsToDelete, { loadComponents: false }); + entityToDelete = await this.wrapResult(entityToDelete); + await this.emitEvent(uid, ENTRY_DELETE, entityToDelete); - return this.wrapResult(entityToDelete); + return entityToDelete; }, // FIXME: used only for the CM to be removed @@ -262,7 +268,7 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator }) // select / populate const query = transformParamsToQuery(uid, wrappedParams); - const entitiesToDelete = await db.query(uid).findMany(query); + let entitiesToDelete = await db.query(uid).findMany(query); if (!entitiesToDelete.length) { return null; @@ -277,10 +283,12 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator }) componentsToDelete.map((compos) => deleteComponents(uid, compos, { loadComponents: false })) ); + entitiesToDelete = await this.wrapResult(entitiesToDelete); + // Trigger webhooks. One for each entity await Promise.all(entitiesToDelete.map((entity) => this.emitEvent(uid, ENTRY_DELETE, entity))); - return this.wrapResult(deletedEntities); + return deletedEntities; }, async load(uid, entity, field, params = {}) { From 4b1e60bad86073068d0603698b1d4f000810c049 Mon Sep 17 00:00:00 2001 From: Boegie19 Date: Wed, 26 Apr 2023 01:29:32 +0200 Subject: [PATCH 25/84] removed findMany since it is unneeded --- .../services/entity-service-decorator.js | 39 ------------------- 1 file changed, 39 deletions(-) diff --git a/packages/plugins/i18n/server/services/entity-service-decorator.js b/packages/plugins/i18n/server/services/entity-service-decorator.js index 974b8b6cf2..91a935f772 100644 --- a/packages/plugins/i18n/server/services/entity-service-decorator.js +++ b/packages/plugins/i18n/server/services/entity-service-decorator.js @@ -150,45 +150,6 @@ const decorator = (service) => ({ await syncNonLocalizedAttributes(entry, { model }); return entry; }, - - /** - * Find an entry or several if fetching all locales - * @param {string} uid - Model uid - * @param {object} opts - Query options object (params, data, files, populate) - */ - async findMany(uid, opts = {}) { - const model = strapi.getModel(uid); - - const { isLocalizedContentType } = getService('content-types'); - - if (!isLocalizedContentType(model)) { - return service.findMany.call(this, uid, opts); - } - - const { kind } = strapi.getModel(uid); - - const wrappedParams = await this.wrapParams(opts, { uid, action: 'findMany' }); - - if (kind === 'singleType') { - if (opts[LOCALE_QUERY_FILTER] === 'all') { - return service.findMany.call(this, uid, wrappedParams); - } - const query = { - ...transformParamsToQuery(uid, wrappedParams), - select: [], - populate: {}, - }; - - const result = await strapi.db.query(uid).findOne(query); - if (result === null) { - return null; - } - // Since we change from findMany to findOne we need to restart the process so we use the entityService - return strapi.entityService.findOne(uid, result.id); - } - - return service.findMany.call(this, uid, wrappedParams); - }, }); module.exports = () => ({ From c25a4dc6cccf47a0646c14986d79571451a1bff7 Mon Sep 17 00:00:00 2001 From: Boegie19 Date: Wed, 26 Apr 2023 01:31:48 +0200 Subject: [PATCH 26/84] used wrappedParams in wrapParms --- .../plugins/i18n/server/services/entity-service-decorator.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/plugins/i18n/server/services/entity-service-decorator.js b/packages/plugins/i18n/server/services/entity-service-decorator.js index 91a935f772..3a6620f010 100644 --- a/packages/plugins/i18n/server/services/entity-service-decorator.js +++ b/packages/plugins/i18n/server/services/entity-service-decorator.js @@ -96,7 +96,7 @@ const decorator = (service) => ({ return wrappedParams; } - return wrapParams(params, ctx); + return wrapParams(wrappedParams, ctx); }, /** From a5cd74a234d515e7406ab722045b1b88aeadbd92 Mon Sep 17 00:00:00 2001 From: Boegie19 Date: Wed, 26 Apr 2023 01:44:37 +0200 Subject: [PATCH 27/84] add findMany back for output[0] --- .../services/entity-service-decorator.js | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/packages/plugins/i18n/server/services/entity-service-decorator.js b/packages/plugins/i18n/server/services/entity-service-decorator.js index 3a6620f010..ca98fa8972 100644 --- a/packages/plugins/i18n/server/services/entity-service-decorator.js +++ b/packages/plugins/i18n/server/services/entity-service-decorator.js @@ -150,6 +150,45 @@ const decorator = (service) => ({ await syncNonLocalizedAttributes(entry, { model }); return entry; }, + + /** + * Find an entry or several if fetching all locales + * @param {string} uid - Model uid + * @param {object} opts - Query options object (params, data, files, populate) + */ + async findMany(uid, opts = {}) { + const model = strapi.getModel(uid); + + const { isLocalizedContentType } = getService('content-types'); + + if (!isLocalizedContentType(model)) { + return service.findMany.call(this, uid, opts); + } + + const { kind } = strapi.getModel(uid); + + const wrappedParams = await this.wrapParams(opts, { uid, action: 'findMany' }); + + if (kind === 'singleType') { + if (opts[LOCALE_QUERY_FILTER] === 'all') { + return service.findMany.call(this, uid, wrappedParams); + } + const query = { + ...transformParamsToQuery(uid, wrappedParams), + select: [], + populate: {}, + }; + + const result = await strapi.db.query(uid).findOne(query); + if (result === null) { + return null; + } + const output = service.findMany.call(this, uid, wrappedParams); + return output[0]; + } + + return service.findMany.call(this, uid, wrappedParams); + }, }); module.exports = () => ({ From 51df0ef83fb19b4f2f1720f34f56dd19d8f3e541 Mon Sep 17 00:00:00 2001 From: Boegie19 Date: Wed, 26 Apr 2023 01:46:35 +0200 Subject: [PATCH 28/84] fix return null --- .../i18n/server/services/entity-service-decorator.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/plugins/i18n/server/services/entity-service-decorator.js b/packages/plugins/i18n/server/services/entity-service-decorator.js index ca98fa8972..5d0533b02e 100644 --- a/packages/plugins/i18n/server/services/entity-service-decorator.js +++ b/packages/plugins/i18n/server/services/entity-service-decorator.js @@ -178,12 +178,10 @@ const decorator = (service) => ({ select: [], populate: {}, }; - - const result = await strapi.db.query(uid).findOne(query); - if (result === null) { + const output = service.findMany.call(this, uid, wrappedParams); + if (output == null || output.length == 0) { return null; } - const output = service.findMany.call(this, uid, wrappedParams); return output[0]; } From 468bf7e017a9acde008a927dcd7a5363b5f68734 Mon Sep 17 00:00:00 2001 From: Boegie19 Date: Wed, 26 Apr 2023 01:48:49 +0200 Subject: [PATCH 29/84] some more fixes --- .../server/services/entity-service-decorator.js | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/packages/plugins/i18n/server/services/entity-service-decorator.js b/packages/plugins/i18n/server/services/entity-service-decorator.js index 5d0533b02e..cab2c31208 100644 --- a/packages/plugins/i18n/server/services/entity-service-decorator.js +++ b/packages/plugins/i18n/server/services/entity-service-decorator.js @@ -167,25 +167,18 @@ const decorator = (service) => ({ const { kind } = strapi.getModel(uid); - const wrappedParams = await this.wrapParams(opts, { uid, action: 'findMany' }); - if (kind === 'singleType') { - if (opts[LOCALE_QUERY_FILTER] === 'all') { - return service.findMany.call(this, uid, wrappedParams); + if (opts[LOCALE_QUERY_FILTER] !== 'all') { + return service.findMany.call(this, uid, opts); } - const query = { - ...transformParamsToQuery(uid, wrappedParams), - select: [], - populate: {}, - }; - const output = service.findMany.call(this, uid, wrappedParams); + const output = service.findMany.call(this, uid, opts); if (output == null || output.length == 0) { return null; } return output[0]; } - return service.findMany.call(this, uid, wrappedParams); + return service.findMany.call(this, uid, opts); }, }); From aacd8e6a5049eaf418f55e967d215e4e37458bb5 Mon Sep 17 00:00:00 2001 From: Boegie19 Date: Wed, 26 Apr 2023 01:49:06 +0200 Subject: [PATCH 30/84] one last fix --- .../plugins/i18n/server/services/entity-service-decorator.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/plugins/i18n/server/services/entity-service-decorator.js b/packages/plugins/i18n/server/services/entity-service-decorator.js index cab2c31208..510053cdbb 100644 --- a/packages/plugins/i18n/server/services/entity-service-decorator.js +++ b/packages/plugins/i18n/server/services/entity-service-decorator.js @@ -168,7 +168,7 @@ const decorator = (service) => ({ const { kind } = strapi.getModel(uid); if (kind === 'singleType') { - if (opts[LOCALE_QUERY_FILTER] !== 'all') { + if (opts[LOCALE_QUERY_FILTER] === 'all') { return service.findMany.call(this, uid, opts); } const output = service.findMany.call(this, uid, opts); From a25ec71eb33794b127548f665130b68f86b7f89f Mon Sep 17 00:00:00 2001 From: Marc-Roig Date: Wed, 26 Apr 2023 09:21:05 +0200 Subject: [PATCH 31/84] fix: wrap findWithRelationCountPage --- packages/core/strapi/lib/services/entity-service/index.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/core/strapi/lib/services/entity-service/index.js b/packages/core/strapi/lib/services/entity-service/index.js index 3dbe414000..103c065c9a 100644 --- a/packages/core/strapi/lib/services/entity-service/index.js +++ b/packages/core/strapi/lib/services/entity-service/index.js @@ -113,7 +113,10 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator }) const query = transformParamsToQuery(uid, wrappedParams); const entities = await db.query(uid).findPage(query); - return this.wrapResult(entities); + return { + ...entities, + results: await this.wrapResult(entities.results), + }; }, async findWithRelationCounts(uid, opts) { From 79b5cacdbf76eff9544b3f4eeb20f87c17017e46 Mon Sep 17 00:00:00 2001 From: Marc-Roig Date: Wed, 26 Apr 2023 09:21:38 +0200 Subject: [PATCH 32/84] fix: await findWithRelationCounts --- packages/core/strapi/lib/services/entity-service/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/strapi/lib/services/entity-service/index.js b/packages/core/strapi/lib/services/entity-service/index.js index 103c065c9a..1907814348 100644 --- a/packages/core/strapi/lib/services/entity-service/index.js +++ b/packages/core/strapi/lib/services/entity-service/index.js @@ -124,7 +124,7 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator }) const query = transformParamsToQuery(uid, wrappedParams); - const entities = db.query(uid).findMany(query); + const entities = await db.query(uid).findMany(query); return this.wrapResult(entities); }, From f2e53a4613b9451ed8149a158cfea7138c5bcd97 Mon Sep 17 00:00:00 2001 From: Marc-Roig Date: Wed, 26 Apr 2023 09:28:22 +0200 Subject: [PATCH 33/84] feat: add uid and action options in wrapResult --- .../lib/services/entity-service/index.js | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/packages/core/strapi/lib/services/entity-service/index.js b/packages/core/strapi/lib/services/entity-service/index.js index 1907814348..c505fa5609 100644 --- a/packages/core/strapi/lib/services/entity-service/index.js +++ b/packages/core/strapi/lib/services/entity-service/index.js @@ -91,7 +91,7 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator }) } const entities = await db.query(uid).findMany(query); - return this.wrapResult(entities); + return this.wrapResult(entities, { uid, action: 'findMany' }); }, async findPage(uid, opts) { @@ -102,7 +102,7 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator }) const page = await db.query(uid).findPage(query); return { ...page, - results: await this.wrapResult(page.results), + results: await this.wrapResult(page.results, { uid, action: 'findPage' }), }; }, @@ -115,7 +115,7 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator }) const entities = await db.query(uid).findPage(query); return { ...entities, - results: await this.wrapResult(entities.results), + results: await this.wrapResult(entities.results, { uid, action: 'findWithRelationCounts' }), }; }, @@ -125,7 +125,7 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator }) const query = transformParamsToQuery(uid, wrappedParams); const entities = await db.query(uid).findMany(query); - return this.wrapResult(entities); + return this.wrapResult(entities, { uid, action: 'findWithRelationCounts' }); }, async findOne(uid, entityId, opts) { @@ -134,7 +134,7 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator }) const query = transformParamsToQuery(uid, pickSelectionParams(wrappedParams)); const entity = db.query(uid).findOne({ ...query, where: { id: entityId } }); - return this.wrapResult(entity); + return this.wrapResult(entity, { uid, action: 'findOne' }); }, async count(uid, opts) { @@ -177,7 +177,7 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator }) entity = await this.findOne(uid, entity.id, wrappedParams); } - entity = await this.wrapResult(entity); + entity = await this.wrapResult(entity, { uid, action: 'create' }); await this.emitEvent(uid, ENTRY_CREATE, entity); @@ -230,7 +230,7 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator }) entity = await this.findOne(uid, entity.id, wrappedParams); } - entity = await this.wrapResult(entity); + entity = await this.wrapResult(entity, { uid, action: 'update' }); await this.emitEvent(uid, ENTRY_UPDATE, entity); @@ -257,7 +257,7 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator }) await db.query(uid).delete({ where: { id: entityToDelete.id } }); await deleteComponents(uid, componentsToDelete, { loadComponents: false }); - entityToDelete = await this.wrapResult(entityToDelete); + entityToDelete = await this.wrapResult(entityToDelete, { uid, action: 'delete' }); await this.emitEvent(uid, ENTRY_DELETE, entityToDelete); @@ -286,7 +286,7 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator }) componentsToDelete.map((compos) => deleteComponents(uid, compos, { loadComponents: false })) ); - entitiesToDelete = await this.wrapResult(entitiesToDelete); + entitiesToDelete = await this.wrapResult(entitiesToDelete, { uid, action: 'delete' }); // Trigger webhooks. One for each entity await Promise.all(entitiesToDelete.map((entity) => this.emitEvent(uid, ENTRY_DELETE, entity))); @@ -303,7 +303,7 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator }) .query(uid) .load(entity, field, transformLoadParamsToQuery(uid, field, params)); - return this.wrapResult(loadedEntity); + return this.wrapResult(loadedEntity, { uid, action: 'load' }); }, async loadPages(uid, entity, field, params = {}, pagination = {}) { @@ -324,7 +324,7 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator }) return { ...loadedPage, - results: await this.wrapResult(loadedPage.results), + results: await this.wrapResult(loadedPage.results, { uid, action: 'load' }), }; }, }); From a24fc43526a92784ea92db7ade72cbc235fdbea9 Mon Sep 17 00:00:00 2001 From: Boegie19 Date: Wed, 26 Apr 2023 10:11:54 +0200 Subject: [PATCH 34/84] linting fixes --- .../plugins/i18n/server/services/entity-service-decorator.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/plugins/i18n/server/services/entity-service-decorator.js b/packages/plugins/i18n/server/services/entity-service-decorator.js index 510053cdbb..6511b33115 100644 --- a/packages/plugins/i18n/server/services/entity-service-decorator.js +++ b/packages/plugins/i18n/server/services/entity-service-decorator.js @@ -172,9 +172,10 @@ const decorator = (service) => ({ return service.findMany.call(this, uid, opts); } const output = service.findMany.call(this, uid, opts); - if (output == null || output.length == 0) { + if (output === null || output.length === 0) { return null; } + //This could break future decorators since they don't expect the value not to be an array return output[0]; } From 6b793c0d90bf6c440fc1382a06d4696ff7a2a48c Mon Sep 17 00:00:00 2001 From: Boegie19 Date: Wed, 26 Apr 2023 10:25:48 +0200 Subject: [PATCH 35/84] fix test --- .../server/services/__tests__/entity-service-decorator.test.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/plugins/i18n/server/services/__tests__/entity-service-decorator.test.js b/packages/plugins/i18n/server/services/__tests__/entity-service-decorator.test.js index f65e58858c..02ecfffa8b 100644 --- a/packages/plugins/i18n/server/services/__tests__/entity-service-decorator.test.js +++ b/packages/plugins/i18n/server/services/__tests__/entity-service-decorator.test.js @@ -146,9 +146,8 @@ describe('Entity service decorator', () => { const output = await service.wrapParams({}, { uid: modelName, action: 'findMany' }); - expect(output).toEqual({ + expect(output).toContain({ Test: 'Test', - filters: { $and: [{ locale: 'en' }] }, }); }); test.each(testData)( From bda72b7a0fc07f3f06a40ecd25562b193fa3922e Mon Sep 17 00:00:00 2001 From: Boegie19 Date: Wed, 26 Apr 2023 10:49:13 +0200 Subject: [PATCH 36/84] fix test again --- .../services/__tests__/entity-service-decorator.test.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/plugins/i18n/server/services/__tests__/entity-service-decorator.test.js b/packages/plugins/i18n/server/services/__tests__/entity-service-decorator.test.js index 02ecfffa8b..827a2aed6d 100644 --- a/packages/plugins/i18n/server/services/__tests__/entity-service-decorator.test.js +++ b/packages/plugins/i18n/server/services/__tests__/entity-service-decorator.test.js @@ -146,9 +146,7 @@ describe('Entity service decorator', () => { const output = await service.wrapParams({}, { uid: modelName, action: 'findMany' }); - expect(output).toContain({ - Test: 'Test', - }); + expect(output.Test).toEqual('Test'); }); test.each(testData)( "Doesn't add locale param when the params contain id or id_in - %s", From beb7d44517c601d307b541cda73cf5abb33c7760 Mon Sep 17 00:00:00 2001 From: Boegie19 Date: Wed, 26 Apr 2023 12:38:36 +0200 Subject: [PATCH 37/84] add ignoreKind --- packages/core/strapi/lib/services/entity-service/index.js | 2 +- packages/core/utils/lib/sanitize/index.js | 6 +++++- .../i18n/server/services/entity-service-decorator.js | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/packages/core/strapi/lib/services/entity-service/index.js b/packages/core/strapi/lib/services/entity-service/index.js index 2cf70b83de..5567ff60b9 100644 --- a/packages/core/strapi/lib/services/entity-service/index.js +++ b/packages/core/strapi/lib/services/entity-service/index.js @@ -82,7 +82,7 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator }) const query = transformParamsToQuery(uid, wrappedParams); - if (kind === 'singleType') { + if (kind === 'singleType' && !opts.ignoreKind) { return db.query(uid).findOne(query); } diff --git a/packages/core/utils/lib/sanitize/index.js b/packages/core/utils/lib/sanitize/index.js index babd4753eb..379ee36013 100644 --- a/packages/core/utils/lib/sanitize/index.js +++ b/packages/core/utils/lib/sanitize/index.js @@ -61,10 +61,14 @@ const createContentAPISanitizers = () => { }; const sanitizeQuery = async (query, schema, { auth } = {}) => { - const { filters, sort, fields, populate } = query; + const { filters, sort, fields, populate, ignoreKind } = query; const sanitizedQuery = cloneDeep(query); + if (ignoreKind) { + delete sanitizedQuery.ignoreKind; + } + if (filters) { Object.assign(sanitizedQuery, { filters: await sanitizeFilters(filters, schema, { auth }) }); } diff --git a/packages/plugins/i18n/server/services/entity-service-decorator.js b/packages/plugins/i18n/server/services/entity-service-decorator.js index 6511b33115..ba2fb19e53 100644 --- a/packages/plugins/i18n/server/services/entity-service-decorator.js +++ b/packages/plugins/i18n/server/services/entity-service-decorator.js @@ -169,7 +169,7 @@ const decorator = (service) => ({ if (kind === 'singleType') { if (opts[LOCALE_QUERY_FILTER] === 'all') { - return service.findMany.call(this, uid, opts); + return service.findMany.call(this, uid, opts, { ...opts, ignoreKind: true }); } const output = service.findMany.call(this, uid, opts); if (output === null || output.length === 0) { From cbb49465bdb820a25e4abf21f8fd3222fde4bd42 Mon Sep 17 00:00:00 2001 From: Marc-Roig Date: Wed, 26 Apr 2023 13:52:45 +0200 Subject: [PATCH 38/84] feat: move sign-media test to utils --- .../sign-media.test.js} | 7 ++--- .../extensions/core/entity-service.js | 29 +++++++++++++++++++ 2 files changed, 32 insertions(+), 4 deletions(-) rename packages/core/upload/server/services/extensions/{content-manager/__tests__/entity-manager.test.js => __tests__/sign-media.test.js} (96%) create mode 100644 packages/core/upload/server/services/extensions/core/entity-service.js diff --git a/packages/core/upload/server/services/extensions/content-manager/__tests__/entity-manager.test.js b/packages/core/upload/server/services/extensions/__tests__/sign-media.test.js similarity index 96% rename from packages/core/upload/server/services/extensions/content-manager/__tests__/entity-manager.test.js rename to packages/core/upload/server/services/extensions/__tests__/sign-media.test.js index 0ba03cd49e..d32c57acdc 100644 --- a/packages/core/upload/server/services/extensions/content-manager/__tests__/entity-manager.test.js +++ b/packages/core/upload/server/services/extensions/__tests__/sign-media.test.js @@ -1,10 +1,9 @@ 'use strict'; -const { signEntityMedia } = require('../entity-manager'); +const { signEntityMedia } = require('../utils'); +const { getService } = require('../../../utils'); -const { getService } = require('../../../../utils'); - -jest.mock('../../../../utils'); +jest.mock('../../../utils'); describe('Upload | extensions | entity-manager', () => { const modelUID = 'model'; diff --git a/packages/core/upload/server/services/extensions/core/entity-service.js b/packages/core/upload/server/services/extensions/core/entity-service.js new file mode 100644 index 0000000000..7c11d8168b --- /dev/null +++ b/packages/core/upload/server/services/extensions/core/entity-service.js @@ -0,0 +1,29 @@ +'use strict'; + +const { signEntityMedia } = require('../utils'); + +const addSignedFileUrlsToEntityService = async () => { + const { provider } = strapi.plugins.upload; + const isPrivate = await provider.isPrivate(); + + // We only need to sign the file urls if the provider is private + if (!isPrivate) { + return; + } + + const decorator = (service) => ({ + wrapResult(result) { + if (Array.isArray(result)) { + return Promise.all(result.map((entity) => signEntityMedia(entity, service.model.uid))); + } + return signEntityMedia(result, service.model.uid); + }, + }); + + strapi.entityService.decorate(decorator); +}; + +module.exports = { + addSignedFileUrlsToEntityService, + signEntityMedia, +}; From c921f6d05c0c1117fa3d31c2f3fdccb11dc02477 Mon Sep 17 00:00:00 2001 From: Marc-Roig Date: Wed, 26 Apr 2023 13:53:34 +0200 Subject: [PATCH 39/84] feat: create folders for entity service decorator --- .../core/upload/server/services/extensions/core/index.js | 7 +++++++ packages/core/upload/server/services/extensions/index.js | 2 ++ 2 files changed, 9 insertions(+) create mode 100644 packages/core/upload/server/services/extensions/core/index.js diff --git a/packages/core/upload/server/services/extensions/core/index.js b/packages/core/upload/server/services/extensions/core/index.js new file mode 100644 index 0000000000..26d169ab50 --- /dev/null +++ b/packages/core/upload/server/services/extensions/core/index.js @@ -0,0 +1,7 @@ +'use strict'; + +const { addSignedFileUrlsToEntityService } = require('./entity-service'); + +module.exports = { + entityService: { addSignedFileUrlsToEntityService }, +}; diff --git a/packages/core/upload/server/services/extensions/index.js b/packages/core/upload/server/services/extensions/index.js index 9c6dedf588..b0d8eff2b9 100644 --- a/packages/core/upload/server/services/extensions/index.js +++ b/packages/core/upload/server/services/extensions/index.js @@ -1,7 +1,9 @@ 'use strict'; const contentManagerExtensions = require('./content-manager'); +const coreExtensions = require('./core'); module.exports = { contentManager: contentManagerExtensions, + core: coreExtensions, }; From 1e545ae1e9aac7c4d2f75d49b537231db01feef6 Mon Sep 17 00:00:00 2001 From: Marc-Roig Date: Wed, 26 Apr 2023 13:54:18 +0200 Subject: [PATCH 40/84] feat: sign media util --- .../server/services/extensions/utils.js | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 packages/core/upload/server/services/extensions/utils.js diff --git a/packages/core/upload/server/services/extensions/utils.js b/packages/core/upload/server/services/extensions/utils.js new file mode 100644 index 0000000000..b175375fe7 --- /dev/null +++ b/packages/core/upload/server/services/extensions/utils.js @@ -0,0 +1,51 @@ +'use strict'; + +const { mapAsync, traverseEntity } = require('@strapi/utils'); +const { getService } = require('../../utils'); + +/** + * Visitor function to sign media URLs + * @param {Object} schema + * @param {string} schema.key - The key of the attribute + * @param {string} schema.value - The value of the attribute + * @param {Object} schema.attribute - The attribute definition + * @param {Object} entry + * @param {Function} entry.set - The set function to update the value + */ +const signEntityMediaVisitor = async ({ key, value, attribute }, { set }) => { + const { signFileUrls } = getService('file'); + + if (!value || attribute.type !== 'media') { + return; + } + + // If the attribute is repeatable sign each file + if (attribute.multiple) { + const signedFiles = await mapAsync(value, signFileUrls); + set(key, signedFiles); + return; + } + + // If the attribute is not repeatable only sign a single file + const signedFile = await signFileUrls(value); + set(key, signedFile); +}; + +/** + * + * Iterate through an entity manager result + * Check which modelAttributes are media and pre sign the image URLs + * if they are from the current upload provider + * + * @param {Object} entity + * @param {Object} modelAttributes + * @returns + */ +const signEntityMedia = async (entity, uid) => { + const model = strapi.getModel(uid); + return traverseEntity(signEntityMediaVisitor, { schema: model }, entity); +}; + +module.exports = { + signEntityMedia, +}; From 1e6f407cdab45542e17bfc6b6065aff862269b8c Mon Sep 17 00:00:00 2001 From: Marc-Roig Date: Wed, 26 Apr 2023 13:54:53 +0200 Subject: [PATCH 41/84] feat: move extensions to bootsrap instead of register --- packages/core/upload/server/bootstrap.js | 6 ++++++ packages/core/upload/server/register.js | 3 --- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/core/upload/server/bootstrap.js b/packages/core/upload/server/bootstrap.js index c45e6d5df6..af3e2dff3d 100644 --- a/packages/core/upload/server/bootstrap.js +++ b/packages/core/upload/server/bootstrap.js @@ -39,6 +39,12 @@ module.exports = async ({ strapi }) => { await getService('weeklyMetrics').registerCron(); getService('metrics').sendUploadPluginMetrics(); + + if (strapi.config.get('plugin.upload.onlySignUrlsAdmin', false)) { + getService('extensions').contentManager.entityManager.addSignedFileUrlsToAdmin(); + } else { + getService('extensions').core.entityService.addSignedFileUrlsToEntityService(); + } }; const registerPermissionActions = async () => { diff --git a/packages/core/upload/server/register.js b/packages/core/upload/server/register.js index 8ecc75301a..4a7143a670 100644 --- a/packages/core/upload/server/register.js +++ b/packages/core/upload/server/register.js @@ -6,7 +6,6 @@ const { } = require('@strapi/utils'); const _ = require('lodash'); const registerUploadMiddleware = require('./middlewares/upload'); -const { getService } = require('./utils'); /** * Register upload plugin @@ -17,8 +16,6 @@ module.exports = async ({ strapi }) => { await registerUploadMiddleware({ strapi }); - getService('extensions').contentManager.entityManager.addSignedFileUrlsToAdmin(); - if (strapi.plugin('graphql')) { require('./graphql')({ strapi }); } From 0c2e27ff8ca89868c1a2070b96a0b39e43fc4ee2 Mon Sep 17 00:00:00 2001 From: Boegie19 Date: Wed, 26 Apr 2023 14:19:04 +0200 Subject: [PATCH 42/84] add comment / lint fixes --- packages/core/utils/lib/sanitize/index.js | 4 ++++ .../plugins/i18n/server/services/entity-service-decorator.js | 1 - 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/core/utils/lib/sanitize/index.js b/packages/core/utils/lib/sanitize/index.js index 379ee36013..a3547e520c 100644 --- a/packages/core/utils/lib/sanitize/index.js +++ b/packages/core/utils/lib/sanitize/index.js @@ -65,6 +65,10 @@ const createContentAPISanitizers = () => { const sanitizedQuery = cloneDeep(query); + /*This is here since when you do a findMany on single types, it will become a findOne. + To keep it a findMany, you give it the ignoreKind flag. + This sensitization  is here since potentially, if a decorator like i18n makes a mistake and returns two values, findOne will only return the first value. + So this query.ignoreKind could return the second record, which is why we sanitize it .*/ if (ignoreKind) { delete sanitizedQuery.ignoreKind; } diff --git a/packages/plugins/i18n/server/services/entity-service-decorator.js b/packages/plugins/i18n/server/services/entity-service-decorator.js index ba2fb19e53..a2846b55a4 100644 --- a/packages/plugins/i18n/server/services/entity-service-decorator.js +++ b/packages/plugins/i18n/server/services/entity-service-decorator.js @@ -2,7 +2,6 @@ const { has, get, omit, isArray } = require('lodash/fp'); const { ApplicationError } = require('@strapi/utils').errors; -const { transformParamsToQuery } = require('@strapi/utils').convertQueryParams; const { getService } = require('../utils'); From dbff43cc7e2a7d5202fff7901979d446cb48e574 Mon Sep 17 00:00:00 2001 From: Boegie19 Date: Wed, 26 Apr 2023 16:09:37 +0200 Subject: [PATCH 43/84] fix lint --- .../i18n/server/services/entity-service-decorator.js | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/packages/plugins/i18n/server/services/entity-service-decorator.js b/packages/plugins/i18n/server/services/entity-service-decorator.js index a2846b55a4..4de2a9bd34 100644 --- a/packages/plugins/i18n/server/services/entity-service-decorator.js +++ b/packages/plugins/i18n/server/services/entity-service-decorator.js @@ -170,12 +170,7 @@ const decorator = (service) => ({ if (opts[LOCALE_QUERY_FILTER] === 'all') { return service.findMany.call(this, uid, opts, { ...opts, ignoreKind: true }); } - const output = service.findMany.call(this, uid, opts); - if (output === null || output.length === 0) { - return null; - } - //This could break future decorators since they don't expect the value not to be an array - return output[0]; + return service.findMany.call(this, uid, opts); } return service.findMany.call(this, uid, opts); From 3f931da2431683debced8f32f231edd95b36d1c8 Mon Sep 17 00:00:00 2001 From: Boegie19 Date: Wed, 26 Apr 2023 16:24:19 +0200 Subject: [PATCH 44/84] fix comment? --- packages/core/utils/lib/sanitize/index.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/core/utils/lib/sanitize/index.js b/packages/core/utils/lib/sanitize/index.js index a3547e520c..9be8116a64 100644 --- a/packages/core/utils/lib/sanitize/index.js +++ b/packages/core/utils/lib/sanitize/index.js @@ -65,10 +65,12 @@ const createContentAPISanitizers = () => { const sanitizedQuery = cloneDeep(query); - /*This is here since when you do a findMany on single types, it will become a findOne. + /* + This is here since when you do a findMany on single types, it will become a findOne. To keep it a findMany, you give it the ignoreKind flag. This sensitization  is here since potentially, if a decorator like i18n makes a mistake and returns two values, findOne will only return the first value. - So this query.ignoreKind could return the second record, which is why we sanitize it .*/ + So this query.ignoreKind could return the second record, which is why we sanitize it . + */ if (ignoreKind) { delete sanitizedQuery.ignoreKind; } From 238e82c1cf3a31c41210d981ddeedcad1e83e34d Mon Sep 17 00:00:00 2001 From: Boegie19 Date: Wed, 26 Apr 2023 16:37:32 +0200 Subject: [PATCH 45/84] fix mistake --- .../plugins/i18n/server/services/entity-service-decorator.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/plugins/i18n/server/services/entity-service-decorator.js b/packages/plugins/i18n/server/services/entity-service-decorator.js index 4de2a9bd34..3a9aa8db89 100644 --- a/packages/plugins/i18n/server/services/entity-service-decorator.js +++ b/packages/plugins/i18n/server/services/entity-service-decorator.js @@ -168,7 +168,7 @@ const decorator = (service) => ({ if (kind === 'singleType') { if (opts[LOCALE_QUERY_FILTER] === 'all') { - return service.findMany.call(this, uid, opts, { ...opts, ignoreKind: true }); + return service.findMany.call(this, uid, { ...opts, ignoreKind: true }); } return service.findMany.call(this, uid, opts); } From 03d43a6bf15e9e677402067d180f916e2326d960 Mon Sep 17 00:00:00 2001 From: Boegie19 Date: Wed, 26 Apr 2023 19:02:55 +0200 Subject: [PATCH 46/84] fix comment again --- packages/core/utils/lib/sanitize/index.js | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/packages/core/utils/lib/sanitize/index.js b/packages/core/utils/lib/sanitize/index.js index 9be8116a64..7f222aa813 100644 --- a/packages/core/utils/lib/sanitize/index.js +++ b/packages/core/utils/lib/sanitize/index.js @@ -65,12 +65,10 @@ const createContentAPISanitizers = () => { const sanitizedQuery = cloneDeep(query); - /* - This is here since when you do a findMany on single types, it will become a findOne. - To keep it a findMany, you give it the ignoreKind flag. - This sensitization  is here since potentially, if a decorator like i18n makes a mistake and returns two values, findOne will only return the first value. - So this query.ignoreKind could return the second record, which is why we sanitize it . - */ + // This is here since when you do a findMany on single types, it will become a findOne. + // To keep it a findMany, you give it the ignoreKind flag. + // This sensitization  is here since potentially, if a decorator like i18n makes a mistake and returns two values, findOne will only return the first value. + // So this query.ignoreKind could return the second record, which is why we sanitize it . if (ignoreKind) { delete sanitizedQuery.ignoreKind; } From 4a0803fb8e6071b58c53d18d747670ac87a49804 Mon Sep 17 00:00:00 2001 From: Boegie19 Date: Wed, 26 Apr 2023 19:03:19 +0200 Subject: [PATCH 47/84] removed 1 more space --- packages/core/utils/lib/sanitize/index.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/core/utils/lib/sanitize/index.js b/packages/core/utils/lib/sanitize/index.js index 7f222aa813..e0ab3b7600 100644 --- a/packages/core/utils/lib/sanitize/index.js +++ b/packages/core/utils/lib/sanitize/index.js @@ -65,10 +65,10 @@ const createContentAPISanitizers = () => { const sanitizedQuery = cloneDeep(query); - // This is here since when you do a findMany on single types, it will become a findOne. - // To keep it a findMany, you give it the ignoreKind flag. - // This sensitization  is here since potentially, if a decorator like i18n makes a mistake and returns two values, findOne will only return the first value. - // So this query.ignoreKind could return the second record, which is why we sanitize it . + // This is here since when you do a findMany on single types, it will become a findOne. + // To keep it a findMany, you give it the ignoreKind flag. + // This sensitization  is here since potentially, if a decorator like i18n makes a mistake and returns two values, findOne will only return the first value. + // So this query.ignoreKind could return the second record, which is why we sanitize it . if (ignoreKind) { delete sanitizedQuery.ignoreKind; } From 7fe9c3145d19b8d36af6e5b15f0d9b0a345739e9 Mon Sep 17 00:00:00 2001 From: Marc-Roig Date: Wed, 26 Apr 2023 20:26:58 +0200 Subject: [PATCH 48/84] fix: wrap result of findMany when it's a single type --- packages/core/strapi/lib/services/entity-service/index.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/core/strapi/lib/services/entity-service/index.js b/packages/core/strapi/lib/services/entity-service/index.js index c505fa5609..2d867e4f79 100644 --- a/packages/core/strapi/lib/services/entity-service/index.js +++ b/packages/core/strapi/lib/services/entity-service/index.js @@ -87,7 +87,8 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator }) const query = transformParamsToQuery(uid, wrappedParams); if (kind === 'singleType') { - return db.query(uid).findOne(query); + const entity = db.query(uid).findOne(query); + return this.wrapResult(entity, { uid, action: 'findOne' }); } const entities = await db.query(uid).findMany(query); From abeaef12e0da525aefc91fc571d4101bb095230a Mon Sep 17 00:00:00 2001 From: Marc-Roig Date: Wed, 26 Apr 2023 20:27:18 +0200 Subject: [PATCH 49/84] fix: await find one entity --- packages/core/strapi/lib/services/entity-service/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/strapi/lib/services/entity-service/index.js b/packages/core/strapi/lib/services/entity-service/index.js index 2d867e4f79..4e58ed094d 100644 --- a/packages/core/strapi/lib/services/entity-service/index.js +++ b/packages/core/strapi/lib/services/entity-service/index.js @@ -134,7 +134,7 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator }) const query = transformParamsToQuery(uid, pickSelectionParams(wrappedParams)); - const entity = db.query(uid).findOne({ ...query, where: { id: entityId } }); + const entity = await db.query(uid).findOne({ ...query, where: { id: entityId } }); return this.wrapResult(entity, { uid, action: 'findOne' }); }, From b776c76ada21f81d63e8443da20cab304f78b6a6 Mon Sep 17 00:00:00 2001 From: Marc-Roig Date: Wed, 26 Apr 2023 20:30:41 +0200 Subject: [PATCH 50/84] fix: pass uid in wrapResult --- .../server/services/extensions/core/entity-service.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/core/upload/server/services/extensions/core/entity-service.js b/packages/core/upload/server/services/extensions/core/entity-service.js index 7c11d8168b..0fd6904f1d 100644 --- a/packages/core/upload/server/services/extensions/core/entity-service.js +++ b/packages/core/upload/server/services/extensions/core/entity-service.js @@ -12,11 +12,11 @@ const addSignedFileUrlsToEntityService = async () => { } const decorator = (service) => ({ - wrapResult(result) { + wrapResult(result, { uid }) { if (Array.isArray(result)) { - return Promise.all(result.map((entity) => signEntityMedia(entity, service.model.uid))); + return Promise.all(result.map((entity) => signEntityMedia(entity, uid))); } - return signEntityMedia(result, service.model.uid); + return signEntityMedia(result, uid); }, }); From 869e2d15a8b7dd2f27cf10185b0b1183b7c5834b Mon Sep 17 00:00:00 2001 From: Marc-Roig Date: Wed, 26 Apr 2023 20:30:56 +0200 Subject: [PATCH 51/84] test: add private url sign api test --- .../private-file-signing.test.api.js | 203 ++++++++++++++++++ 1 file changed, 203 insertions(+) create mode 100644 api-tests/core/upload/content-api/private-file-signing.test.api.js diff --git a/api-tests/core/upload/content-api/private-file-signing.test.api.js b/api-tests/core/upload/content-api/private-file-signing.test.api.js new file mode 100644 index 0000000000..e5c1578ebd --- /dev/null +++ b/api-tests/core/upload/content-api/private-file-signing.test.api.js @@ -0,0 +1,203 @@ +'use strict'; + +const fs = require('fs'); +const path = require('path'); + +const { createTestBuilder } = require('api-tests/builder'); +const { createStrapiInstance } = require('api-tests/strapi'); +const { createContentAPIRequest } = require('api-tests/request'); + +const builder = createTestBuilder(); +let strapi; +let rq; + +const modelUID = 'api::model.model'; +const componentUID = 'default.component'; + +const models = { + [modelUID]: { + displayName: 'Model', + singularName: 'model', + pluralName: 'models', + kind: 'collectionType', + attributes: { + name: { + type: 'text', + }, + media: { + type: 'media', + }, + media_repeatable: { + type: 'media', + multiple: true, + }, + compo_media: { + type: 'component', + component: componentUID, + }, + compo_media_repeatable: { + type: 'component', + repeatable: true, + component: componentUID, + }, + dynamicZone: { + type: 'dynamiczone', + components: [componentUID], + }, + }, + }, + [componentUID]: { + displayName: 'component', + attributes: { + media_repeatable: { + type: 'media', + multiple: true, + }, + media: { + type: 'media', + multiple: false, + }, + }, + }, +}; + +const populate = { + media: true, + media_repeatable: true, + compo_media: { + populate: { + media: true, + media_repeatable: true, + }, + }, + compo_media_repeatable: { + populate: { + media: true, + media_repeatable: true, + }, + }, + dynamicZone: { + populate: { + media: true, + media_repeatable: true, + }, + }, +}; + +const mockProvider = (signUrl = true) => ({ + init() { + return { + isPrivate() { + return signUrl; + }, + getSignedUrl() { + return { url: 'signedUrl' }; + }, + uploadStream() {}, + upload() {}, + delete() {}, + checkFileSize() {}, + }; + }, +}); + +const uploadImg = (fileName) => { + return rq({ + method: 'POST', + url: '/upload', + formData: { + files: fs.createReadStream(path.join(__dirname, `../utils/${fileName}`)), + }, + }); +}; + +let repeatable; +let singleMedia; +let mediaEntry = {}; + +describe('Upload Plugin url signing', () => { + const responseExpectations = (result) => { + expect(result.media.url).toEqual('signedUrl'); + + for (const media of result.media_repeatable) { + expect(media.url).toEqual('signedUrl'); + } + + expect(result.compo_media.media.url).toEqual('signedUrl'); + for (const media of result.compo_media.media_repeatable) { + expect(media.url).toEqual('signedUrl'); + } + + for (const component of result.compo_media_repeatable) { + expect(component.media.url).toEqual('signedUrl'); + for (const media of component.media_repeatable) { + expect(media.url).toEqual('signedUrl'); + } + } + + for (const component of result.dynamicZone) { + expect(component.media.url).toEqual('signedUrl'); + for (const media of component.media_repeatable) { + expect(media.url).toEqual('signedUrl'); + } + } + }; + + let entity; + + beforeAll(async () => { + const localProviderPath = require.resolve('@strapi/provider-upload-local'); + jest.mock(localProviderPath, () => mockProvider(true)); + + // Create builder + await builder.addComponent(models[componentUID]).addContentType(models[modelUID]).build(); + + // Create api instance + strapi = await createStrapiInstance(); + + rq = await createContentAPIRequest({ strapi }); + + const imgRes = [await uploadImg('rec.jpg'), await uploadImg('strapi.jpg')]; + + repeatable = imgRes.map((img) => img.body[0].id); + singleMedia = imgRes[0].body[0].id; + mediaEntry = { + media: singleMedia, + media_repeatable: repeatable, + }; + }); + + afterAll(async () => { + await strapi.destroy(); + await builder.cleanup(); + }); + + test('returns signed media URLs on content creation', async () => { + entity = await strapi.entityService.create(modelUID, { + data: { + name: 'name', + media: singleMedia, + media_repeatable: repeatable, + compo_media: mediaEntry, + compo_media_repeatable: [mediaEntry, mediaEntry], + dynamicZone: [ + { + __component: componentUID, + ...mediaEntry, + }, + ], + }, + populate, + }); + + responseExpectations(entity); + }); + + test('returns signed media URLs when we GET content', async () => { + const en = await strapi.entityService.findOne(modelUID, entity.id, { + populate, + }); + + responseExpectations(en); + }); +}); From 2598bec7783b66da11733aa93049c0bec160c856 Mon Sep 17 00:00:00 2001 From: Boegie19 Date: Wed, 26 Apr 2023 21:25:37 +0200 Subject: [PATCH 52/84] fix comment for real --- packages/core/utils/lib/sanitize/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/core/utils/lib/sanitize/index.js b/packages/core/utils/lib/sanitize/index.js index e0ab3b7600..f54885ec5b 100644 --- a/packages/core/utils/lib/sanitize/index.js +++ b/packages/core/utils/lib/sanitize/index.js @@ -67,8 +67,8 @@ const createContentAPISanitizers = () => { // This is here since when you do a findMany on single types, it will become a findOne. // To keep it a findMany, you give it the ignoreKind flag. - // This sensitization  is here since potentially, if a decorator like i18n makes a mistake and returns two values, findOne will only return the first value. - // So this query.ignoreKind could return the second record, which is why we sanitize it . + // This sensitization is here since potentially, if a decorator like i18n makes a mistake and returns two values, findOne will only return the first value. + // So this query.ignoreKind could return the second record, which is why we sanitize it. if (ignoreKind) { delete sanitizedQuery.ignoreKind; } From d73059185f6bcc6e39c55e1f16632918cb5337b0 Mon Sep 17 00:00:00 2001 From: Boegie19 Date: Wed, 26 Apr 2023 23:29:58 +0200 Subject: [PATCH 53/84] fix opts being defiend --- packages/core/strapi/lib/services/entity-service/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/strapi/lib/services/entity-service/index.js b/packages/core/strapi/lib/services/entity-service/index.js index 5567ff60b9..c6997c1872 100644 --- a/packages/core/strapi/lib/services/entity-service/index.js +++ b/packages/core/strapi/lib/services/entity-service/index.js @@ -75,7 +75,7 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator }) }); }, - async findMany(uid, opts) { + async findMany(uid, opts = {}) { const { kind } = strapi.getModel(uid); const wrappedParams = await this.wrapParams(opts, { uid, action: 'findMany' }); From 4cf7d6284f731bfd61d091ecfb5567edbcdd17ca Mon Sep 17 00:00:00 2001 From: Marc-Roig Date: Thu, 27 Apr 2023 10:36:36 +0200 Subject: [PATCH 54/84] fix: call parent wrapResult --- .../server/services/extensions/core/entity-service.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/core/upload/server/services/extensions/core/entity-service.js b/packages/core/upload/server/services/extensions/core/entity-service.js index 0fd6904f1d..be647002b2 100644 --- a/packages/core/upload/server/services/extensions/core/entity-service.js +++ b/packages/core/upload/server/services/extensions/core/entity-service.js @@ -12,11 +12,12 @@ const addSignedFileUrlsToEntityService = async () => { } const decorator = (service) => ({ - wrapResult(result, { uid }) { - if (Array.isArray(result)) { - return Promise.all(result.map((entity) => signEntityMedia(entity, uid))); + async wrapResult(result, options) { + const wrappedResult = await service.wrapResult.call(this, result, options); + if (Array.isArray(wrappedResult)) { + return Promise.all(wrappedResult.map((entity) => signEntityMedia(entity, options.uid))); } - return signEntityMedia(result, uid); + return signEntityMedia(wrappedResult, options.uid); }, }); From 39fad95b72799fc9b94530765c74185f2a6c9b85 Mon Sep 17 00:00:00 2001 From: Marc-Roig Date: Thu, 27 Apr 2023 10:37:06 +0200 Subject: [PATCH 55/84] tests: test findMany --- .../private-file-signing.test.api.js | 64 ++++++++++++------- 1 file changed, 40 insertions(+), 24 deletions(-) diff --git a/api-tests/core/upload/content-api/private-file-signing.test.api.js b/api-tests/core/upload/content-api/private-file-signing.test.api.js index e5c1578ebd..d6928a718e 100644 --- a/api-tests/core/upload/content-api/private-file-signing.test.api.js +++ b/api-tests/core/upload/content-api/private-file-signing.test.api.js @@ -101,6 +101,25 @@ const mockProvider = (signUrl = true) => ({ }, }); +const createModel = async (name = 'name') => { + return strapi.entityService.create(modelUID, { + data: { + name, + media: singleMedia, + media_repeatable: repeatable, + compo_media: mediaEntry, + compo_media_repeatable: [mediaEntry, mediaEntry], + dynamicZone: [ + { + __component: componentUID, + ...mediaEntry, + }, + ], + }, + populate, + }); +}; + const uploadImg = (fileName) => { return rq({ method: 'POST', @@ -114,6 +133,7 @@ const uploadImg = (fileName) => { let repeatable; let singleMedia; let mediaEntry = {}; +let model; describe('Upload Plugin url signing', () => { const responseExpectations = (result) => { @@ -143,8 +163,6 @@ describe('Upload Plugin url signing', () => { } }; - let entity; - beforeAll(async () => { const localProviderPath = require.resolve('@strapi/provider-upload-local'); jest.mock(localProviderPath, () => mockProvider(true)); @@ -165,6 +183,8 @@ describe('Upload Plugin url signing', () => { media: singleMedia, media_repeatable: repeatable, }; + + model = await createModel('model1'); }); afterAll(async () => { @@ -172,32 +192,28 @@ describe('Upload Plugin url signing', () => { await builder.cleanup(); }); - test('returns signed media URLs on content creation', async () => { - entity = await strapi.entityService.create(modelUID, { - data: { - name: 'name', - media: singleMedia, - media_repeatable: repeatable, - compo_media: mediaEntry, - compo_media_repeatable: [mediaEntry, mediaEntry], - dynamicZone: [ - { - __component: componentUID, - ...mediaEntry, - }, - ], - }, - populate, + describe('Returns signed media URLs on', () => { + test('entityService.create', async () => { + let entity = await createModel(); + responseExpectations(entity); }); - responseExpectations(entity); - }); + test('entityService.findOne', async () => { + const entity = await strapi.entityService.findOne(modelUID, model.id, { + populate, + }); - test('returns signed media URLs when we GET content', async () => { - const en = await strapi.entityService.findOne(modelUID, entity.id, { - populate, + responseExpectations(entity); }); - responseExpectations(en); + test('entityService.findMany', async () => { + const entities = await strapi.entityService.findMany(modelUID, { + populate, + }); + + for (const entity of entities) { + responseExpectations(entity); + } + }); }); }); From 0921e9103403e0b4adca0e04a5994960dca76834 Mon Sep 17 00:00:00 2001 From: Marc-Roig Date: Thu, 27 Apr 2023 10:44:07 +0200 Subject: [PATCH 56/84] test: findPage --- .../private-file-signing.test.api.js | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/api-tests/core/upload/content-api/private-file-signing.test.api.js b/api-tests/core/upload/content-api/private-file-signing.test.api.js index d6928a718e..d24f522cf3 100644 --- a/api-tests/core/upload/content-api/private-file-signing.test.api.js +++ b/api-tests/core/upload/content-api/private-file-signing.test.api.js @@ -215,5 +215,46 @@ describe('Upload Plugin url signing', () => { responseExpectations(entity); } }); + + test('entityService.findPage', async () => { + const entities = await strapi.entityService.findPage(modelUID, { + populate, + }); + for (const entity of entities.results) { + responseExpectations(entity); + } + }); + + // test('entityService.update', async () => { + // const en = await strapi.entityService.findMany(modelUID, entity, { + // populate, + // }); + + // responseExpectations(en); + // }); + + // test('entityService.delete', async () => { + // const en = await strapi.entityService.findMany(modelUID, entity, { + // populate, + // }); + + // responseExpectations(en); + // }); + // }); + + // test('entityService.load', async () => { + // const en = await strapi.entityService.findMany(modelUID, entity, { + // populate, + // }); + + // responseExpectations(en); + // }); + + // test('entityService.loadPages', async () => { + // const en = await strapi.entityService.findMany(modelUID, entity, { + // populate, + // }); + + // responseExpectations(en); }); }); From 266ff0b5b1f5bf341a12397759175068e7c5cf07 Mon Sep 17 00:00:00 2001 From: Marc-Roig Date: Thu, 27 Apr 2023 11:06:04 +0200 Subject: [PATCH 57/84] test: update --- .../content-api/private-file-signing.test.api.js | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/api-tests/core/upload/content-api/private-file-signing.test.api.js b/api-tests/core/upload/content-api/private-file-signing.test.api.js index d24f522cf3..ccffdd2bc0 100644 --- a/api-tests/core/upload/content-api/private-file-signing.test.api.js +++ b/api-tests/core/upload/content-api/private-file-signing.test.api.js @@ -225,13 +225,17 @@ describe('Upload Plugin url signing', () => { } }); - // test('entityService.update', async () => { - // const en = await strapi.entityService.findMany(modelUID, entity, { - // populate, - // }); + test('entityService.update', async () => { + const model = await createModel(); + const en = await strapi.entityService.update(modelUID, model.id, { + data: { + name: 'model_updated', + }, + populate, + }); - // responseExpectations(en); - // }); + responseExpectations(en); + }); // test('entityService.delete', async () => { // const en = await strapi.entityService.findMany(modelUID, entity, { From fee4af7e16f584e144144cf7c0d9f51a01d3f19b Mon Sep 17 00:00:00 2001 From: Marc-Roig Date: Thu, 27 Apr 2023 11:39:01 +0200 Subject: [PATCH 58/84] test: delete --- .../private-file-signing.test.api.js | 39 +++++++------------ 1 file changed, 13 insertions(+), 26 deletions(-) diff --git a/api-tests/core/upload/content-api/private-file-signing.test.api.js b/api-tests/core/upload/content-api/private-file-signing.test.api.js index ccffdd2bc0..a97785d302 100644 --- a/api-tests/core/upload/content-api/private-file-signing.test.api.js +++ b/api-tests/core/upload/content-api/private-file-signing.test.api.js @@ -84,11 +84,13 @@ const populate = { }, }; -const mockProvider = (signUrl = true) => ({ +const isPrivate = true; + +const mockProvider = () => ({ init() { return { isPrivate() { - return signUrl; + return isPrivate; }, getSignedUrl() { return { url: 'signedUrl' }; @@ -227,38 +229,23 @@ describe('Upload Plugin url signing', () => { test('entityService.update', async () => { const model = await createModel(); - const en = await strapi.entityService.update(modelUID, model.id, { + const entity = await strapi.entityService.update(modelUID, model.id, { data: { name: 'model_updated', }, populate, }); - responseExpectations(en); + responseExpectations(entity); }); - // test('entityService.delete', async () => { - // const en = await strapi.entityService.findMany(modelUID, entity, { - // populate, - // }); + test('entityService.delete', async () => { + const model = await createModel(); + const entity = await strapi.entityService.delete(modelUID, model.id, { + populate, + }); - // responseExpectations(en); - // }); - // }); - - // test('entityService.load', async () => { - // const en = await strapi.entityService.findMany(modelUID, entity, { - // populate, - // }); - - // responseExpectations(en); - // }); - - // test('entityService.loadPages', async () => { - // const en = await strapi.entityService.findMany(modelUID, entity, { - // populate, - // }); - - // responseExpectations(en); + responseExpectations(entity); + }); }); }); From 491f56b0d635b3003f12a7e9965110dd059fc3f9 Mon Sep 17 00:00:00 2001 From: Marc-Roig Date: Thu, 27 Apr 2023 11:52:08 +0200 Subject: [PATCH 59/84] test do not sign if provider is not private --- .../private-file-signing.test.api.js | 101 ++++++++++++++---- 1 file changed, 82 insertions(+), 19 deletions(-) diff --git a/api-tests/core/upload/content-api/private-file-signing.test.api.js b/api-tests/core/upload/content-api/private-file-signing.test.api.js index a97785d302..8331acd625 100644 --- a/api-tests/core/upload/content-api/private-file-signing.test.api.js +++ b/api-tests/core/upload/content-api/private-file-signing.test.api.js @@ -84,7 +84,7 @@ const populate = { }, }; -const isPrivate = true; +let isPrivate = true; const mockProvider = () => ({ init() { @@ -95,8 +95,12 @@ const mockProvider = () => ({ getSignedUrl() { return { url: 'signedUrl' }; }, - uploadStream() {}, - upload() {}, + uploadStream(file) { + file.url = 'strapi.jpg'; + }, + upload(file) { + file.url = 'strapi.jpg'; + }, delete() {}, checkFileSize() {}, }; @@ -138,29 +142,29 @@ let mediaEntry = {}; let model; describe('Upload Plugin url signing', () => { - const responseExpectations = (result) => { - expect(result.media.url).toEqual('signedUrl'); + const responseExpectations = (result, expectedUrl) => { + expect(result.media.url).toEqual(expectedUrl); for (const media of result.media_repeatable) { - expect(media.url).toEqual('signedUrl'); + expect(media.url).toEqual(expectedUrl); } - expect(result.compo_media.media.url).toEqual('signedUrl'); + expect(result.compo_media.media.url).toEqual(expectedUrl); for (const media of result.compo_media.media_repeatable) { - expect(media.url).toEqual('signedUrl'); + expect(media.url).toEqual(expectedUrl); } for (const component of result.compo_media_repeatable) { - expect(component.media.url).toEqual('signedUrl'); + expect(component.media.url).toEqual(expectedUrl); for (const media of component.media_repeatable) { - expect(media.url).toEqual('signedUrl'); + expect(media.url).toEqual(expectedUrl); } } for (const component of result.dynamicZone) { - expect(component.media.url).toEqual('signedUrl'); + expect(component.media.url).toEqual(expectedUrl); for (const media of component.media_repeatable) { - expect(media.url).toEqual('signedUrl'); + expect(media.url).toEqual(expectedUrl); } } }; @@ -177,7 +181,7 @@ describe('Upload Plugin url signing', () => { rq = await createContentAPIRequest({ strapi }); - const imgRes = [await uploadImg('rec.jpg'), await uploadImg('strapi.jpg')]; + const imgRes = [await uploadImg('strapi.jpg'), await uploadImg('strapi.jpg')]; repeatable = imgRes.map((img) => img.body[0].id); singleMedia = imgRes[0].body[0].id; @@ -197,7 +201,7 @@ describe('Upload Plugin url signing', () => { describe('Returns signed media URLs on', () => { test('entityService.create', async () => { let entity = await createModel(); - responseExpectations(entity); + responseExpectations(entity, 'signedUrl'); }); test('entityService.findOne', async () => { @@ -205,7 +209,7 @@ describe('Upload Plugin url signing', () => { populate, }); - responseExpectations(entity); + responseExpectations(entity, 'signedUrl'); }); test('entityService.findMany', async () => { @@ -214,7 +218,7 @@ describe('Upload Plugin url signing', () => { }); for (const entity of entities) { - responseExpectations(entity); + responseExpectations(entity, 'signedUrl'); } }); @@ -223,7 +227,7 @@ describe('Upload Plugin url signing', () => { populate, }); for (const entity of entities.results) { - responseExpectations(entity); + responseExpectations(entity, 'signedUrl'); } }); @@ -236,7 +240,7 @@ describe('Upload Plugin url signing', () => { populate, }); - responseExpectations(entity); + responseExpectations(entity, 'signedUrl'); }); test('entityService.delete', async () => { @@ -245,7 +249,66 @@ describe('Upload Plugin url signing', () => { populate, }); - responseExpectations(entity); + responseExpectations(entity, 'signedUrl'); + }); + }); + + describe('Does not return signed media URLs on', () => { + beforeAll(async () => { + isPrivate = false; + }); + + test('entityService.create', async () => { + let entity = await createModel(); + responseExpectations(entity, 'strapi.jpg'); + }); + + test('entityService.findOne', async () => { + const entity = await strapi.entityService.findOne(modelUID, model.id, { + populate, + }); + + responseExpectations(entity, 'strapi.jpg'); + }); + + test('entityService.findMany', async () => { + const entities = await strapi.entityService.findMany(modelUID, { + populate, + }); + + for (const entity of entities) { + responseExpectations(entity, 'strapi.jpg'); + } + }); + + test('entityService.findPage', async () => { + const entities = await strapi.entityService.findPage(modelUID, { + populate, + }); + for (const entity of entities.results) { + responseExpectations(entity, 'strapi.jpg'); + } + }); + + test('entityService.update', async () => { + const model = await createModel(); + const entity = await strapi.entityService.update(modelUID, model.id, { + data: { + name: 'model_updated', + }, + populate, + }); + + responseExpectations(entity, 'strapi.jpg'); + }); + + test('entityService.delete', async () => { + const model = await createModel(); + const entity = await strapi.entityService.delete(modelUID, model.id, { + populate, + }); + + responseExpectations(entity, 'strapi.jpg'); }); }); }); From 7ea52e2b090ffacb7cb09f3371aeba6db2ca673c Mon Sep 17 00:00:00 2001 From: Marc-Roig Date: Thu, 27 Apr 2023 11:53:49 +0200 Subject: [PATCH 60/84] chore: change config variable name --- packages/core/upload/server/bootstrap.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/upload/server/bootstrap.js b/packages/core/upload/server/bootstrap.js index af3e2dff3d..aae54ab854 100644 --- a/packages/core/upload/server/bootstrap.js +++ b/packages/core/upload/server/bootstrap.js @@ -40,7 +40,7 @@ module.exports = async ({ strapi }) => { await getService('weeklyMetrics').registerCron(); getService('metrics').sendUploadPluginMetrics(); - if (strapi.config.get('plugin.upload.onlySignUrlsAdmin', false)) { + if (strapi.config.get('plugin.upload.signAdminURLsOnly', false)) { getService('extensions').contentManager.entityManager.addSignedFileUrlsToAdmin(); } else { getService('extensions').core.entityService.addSignedFileUrlsToEntityService(); From 6157598eb92843be931f00ee29d6f20f53aa0be5 Mon Sep 17 00:00:00 2001 From: Boegie19 <34578426+Boegie19@users.noreply.github.com> Date: Thu, 27 Apr 2023 12:04:50 +0200 Subject: [PATCH 61/84] Update packages/core/utils/lib/sanitize/index.js Co-authored-by: Marc --- packages/core/utils/lib/sanitize/index.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/core/utils/lib/sanitize/index.js b/packages/core/utils/lib/sanitize/index.js index f54885ec5b..0b8890aacd 100644 --- a/packages/core/utils/lib/sanitize/index.js +++ b/packages/core/utils/lib/sanitize/index.js @@ -65,10 +65,9 @@ const createContentAPISanitizers = () => { const sanitizedQuery = cloneDeep(query); - // This is here since when you do a findMany on single types, it will become a findOne. - // To keep it a findMany, you give it the ignoreKind flag. - // This sensitization is here since potentially, if a decorator like i18n makes a mistake and returns two values, findOne will only return the first value. - // So this query.ignoreKind could return the second record, which is why we sanitize it. + // Some methods behave different if requesting a Content Type or Single Type (entityService findMany) + // In some cases, we want to ignore such behaviour, and we do so by using `ignoreKind` flag. + // This sanitization is here to avoid potential security issues of using `ignoreKind`, specially using decorators & extensions. if (ignoreKind) { delete sanitizedQuery.ignoreKind; } From 00ec2c98a87459a72ff32ce3999f3ec408b481a5 Mon Sep 17 00:00:00 2001 From: Marc-Roig Date: Tue, 2 May 2023 10:51:27 +0200 Subject: [PATCH 62/84] fix: unit tests --- packages/core/upload/server/__tests__/bootstrap.test.js | 4 ++++ packages/core/upload/server/__tests__/register.test.js | 7 ------- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/packages/core/upload/server/__tests__/bootstrap.test.js b/packages/core/upload/server/__tests__/bootstrap.test.js index 3c1e5400c7..783d84024f 100644 --- a/packages/core/upload/server/__tests__/bootstrap.test.js +++ b/packages/core/upload/server/__tests__/bootstrap.test.js @@ -47,6 +47,10 @@ describe('Upload plugin bootstrap function', () => { weeklyMetrics: { registerCron() {}, }, + extensions: { + contentManager: { entityManager: { addSignedFileUrlsToAdmin: jest.fn() } }, + core: { entityService: { addSignedFileUrlsToEntityService: jest.fn() } }, + }, }, }, }, diff --git a/packages/core/upload/server/__tests__/register.test.js b/packages/core/upload/server/__tests__/register.test.js index 80fb134290..736d8b87d1 100644 --- a/packages/core/upload/server/__tests__/register.test.js +++ b/packages/core/upload/server/__tests__/register.test.js @@ -32,13 +32,6 @@ jest.mock('@strapi/provider-upload-local', () => ({ }, })); -jest.mock('../utils', () => ({ - ...jest.requireActual('../utils'), - getService: () => ({ - contentManager: { entityManager: { addSignedFileUrlsToAdmin: jest.fn() } }, - }), -})); - describe('Upload plugin register function', () => { test('The upload plugin registers the /upload route', async () => { const registerRoute = jest.fn(); From 2394ae2b9b9d1d53e1926b158280a48d7f50fb6f Mon Sep 17 00:00:00 2001 From: Marc-Roig Date: Mon, 8 May 2023 15:38:56 +0200 Subject: [PATCH 63/84] test entityService load --- .../private-file-signing.test.api.js | 37 +++++++++++++++++-- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/api-tests/core/upload/content-api/private-file-signing.test.api.js b/api-tests/core/upload/content-api/private-file-signing.test.api.js index 8331acd625..4a0604c665 100644 --- a/api-tests/core/upload/content-api/private-file-signing.test.api.js +++ b/api-tests/core/upload/content-api/private-file-signing.test.api.js @@ -142,12 +142,19 @@ let mediaEntry = {}; let model; describe('Upload Plugin url signing', () => { - const responseExpectations = (result, expectedUrl) => { - expect(result.media.url).toEqual(expectedUrl); + const expectMedia = (media, expectedUrl) => { + expect(media.url).toEqual(expectedUrl); + }; - for (const media of result.media_repeatable) { - expect(media.url).toEqual(expectedUrl); + const expectRepeatable = (repeatable, expectedUrl) => { + for (const media of repeatable) { + expectMedia(media, expectedUrl); } + }; + + const responseExpectations = (result, expectedUrl) => { + expectMedia(result.media, expectedUrl); + expectRepeatable(result.media_repeatable, expectedUrl); expect(result.compo_media.media.url).toEqual(expectedUrl); for (const media of result.compo_media.media_repeatable) { @@ -251,6 +258,17 @@ describe('Upload Plugin url signing', () => { responseExpectations(entity, 'signedUrl'); }); + + test('entityService.load', async () => { + const model = await createModel(); + const media_repeatable = await strapi.entityService.load( + modelUID, + { id: model.id }, + 'media_repeatable' + ); + + expectRepeatable(media_repeatable, 'signedUrl'); + }); }); describe('Does not return signed media URLs on', () => { @@ -310,5 +328,16 @@ describe('Upload Plugin url signing', () => { responseExpectations(entity, 'strapi.jpg'); }); + + test('entityService.load', async () => { + const model = await createModel(); + const media_repeatable = await strapi.entityService.load( + modelUID, + { id: model.id }, + 'media_repeatable' + ); + + expectRepeatable(media_repeatable, 'strapi.jpg'); + }); }); }); From 06f9367dc33aa69fe8e7efe6cd64b96161ee489f Mon Sep 17 00:00:00 2001 From: Marc-Roig Date: Mon, 8 May 2023 15:41:42 +0200 Subject: [PATCH 64/84] feat: sign load entities --- .../server/services/extensions/core/entity-service.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/packages/core/upload/server/services/extensions/core/entity-service.js b/packages/core/upload/server/services/extensions/core/entity-service.js index be647002b2..f4beb991bd 100644 --- a/packages/core/upload/server/services/extensions/core/entity-service.js +++ b/packages/core/upload/server/services/extensions/core/entity-service.js @@ -14,9 +14,18 @@ const addSignedFileUrlsToEntityService = async () => { const decorator = (service) => ({ async wrapResult(result, options) { const wrappedResult = await service.wrapResult.call(this, result, options); + + // Load returns only the attribute of the entity, not the entity itself, + if (options.action === 'load') { + const entity = { [options.field]: result }; + const signedEntity = await signEntityMedia(entity, options.uid); + return signedEntity[options.field]; + } + if (Array.isArray(wrappedResult)) { return Promise.all(wrappedResult.map((entity) => signEntityMedia(entity, options.uid))); } + return signEntityMedia(wrappedResult, options.uid); }, }); From 542cd7ff61994174909461e0d3d52de28678f355 Mon Sep 17 00:00:00 2001 From: Marc-Roig Date: Mon, 8 May 2023 15:42:23 +0200 Subject: [PATCH 65/84] feat: send field data in wrapResult options --- packages/core/strapi/lib/services/entity-service/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/core/strapi/lib/services/entity-service/index.js b/packages/core/strapi/lib/services/entity-service/index.js index 4e58ed094d..c2c135f814 100644 --- a/packages/core/strapi/lib/services/entity-service/index.js +++ b/packages/core/strapi/lib/services/entity-service/index.js @@ -304,7 +304,7 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator }) .query(uid) .load(entity, field, transformLoadParamsToQuery(uid, field, params)); - return this.wrapResult(loadedEntity, { uid, action: 'load' }); + return this.wrapResult(loadedEntity, { uid, field, action: 'load' }); }, async loadPages(uid, entity, field, params = {}, pagination = {}) { @@ -325,7 +325,7 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator }) return { ...loadedPage, - results: await this.wrapResult(loadedPage.results, { uid, action: 'load' }), + results: await this.wrapResult(loadedPage.results, { uid, field, action: 'load' }), }; }, }); From 8cf888ee66a40c0415406461436dc99571d28fb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9Cmarwa-hodeib=E2=80=9D?= Date: Tue, 9 May 2023 23:04:09 +0300 Subject: [PATCH 66/84] translate all to Arabic --- .../core/admin/admin/src/translations/ar.json | 359 +++++++++++++++++- 1 file changed, 358 insertions(+), 1 deletion(-) diff --git a/packages/core/admin/admin/src/translations/ar.json b/packages/core/admin/admin/src/translations/ar.json index dab8a47c76..25caa58dbb 100644 --- a/packages/core/admin/admin/src/translations/ar.json +++ b/packages/core/admin/admin/src/translations/ar.json @@ -282,5 +282,362 @@ "app.components.GuidedTour.CTB.create.cta.title": "بناء نوع المجموعة", "app.components.GuidedTour.CTB.create.title": "🧠 قم بإنشاء أول نوع مجموعة", "app.components.GuidedTour.CTB.success.content": "

جيد!

⚡️ ما الذي تود مشاركته مع العالم؟", - + "app.components.GuidedTour.CTB.success.title": "الخطوة 1: ✅ مكتمل", + "app.components.GuidedTour.home.apiTokens.cta.title": "API اختبار ", + "app.components.GuidedTour.home.CM.title": "⚡️ ما الذي تود مشاركته مع العالم؟", + "app.components.GuidedTour.home.CTB.cta.title": "Content type Builder انتقل إلى", + "app.components.GuidedTour.home.CTB.title": "🧠 بناء هيكل المحتوى", + "app.components.GuidedTour.skip": "تخطي الجولة", + "app.components.GuidedTour.title": "خطوات للبدء ٣", + "app.components.HomePage.create": "قم بإنشاء نوع المحتوى الأول الخاص بك", + "app.components.HomePage.roadmap": "انظر خارطة الطريق لدينا", + "app.components.InstallPluginPage.Download.description": "قد يستغرق تنزيل المكون الإضافي وتثبيته بضع ثوانٍ", + "app.components.InstallPluginPage.Download.title": "جارى التحميل...", + "app.components.LeftMenu.collapse": "تصغير شريط التنقل", + "app.components.LeftMenu.expand": "قم بتوسيع شريط التنقل", + "app.components.LeftMenu.general": "عام", + "app.components.LeftMenu.logo.alt": "شعار التطبيق", + "app.components.LeftMenu.logout": "تسجيل خروج", + "app.components.LeftMenu.navbrand.title": "Strapi لوحة القيادة", + "app.components.LeftMenu.navbrand.workplace": "مكان العمل", + "app.components.LeftMenu.plugins": "الإضافات", + "app.components.LeftMenuFooter.help": "يساعد", + "app.components.LeftMenuLinkContainer.collectionTypes": "أنواع المجموعات", + "app.components.LeftMenuLinkContainer.singleTypes": "أنواع مفردة", + "app.components.ListPluginsPage.deletePlugin.description": "قد يستغرق الأمر بضع ثوان لإلغاء تثبيت المكون الإضافي", + "app.components.ListPluginsPage.deletePlugin.title": "إلغاء التثبيت", + "app.components.MarketplaceBanner": "اكتشف المكونات الإضافية التي أنشأها المجتمع ، والعديد من الأشياء الرائعة لبدء مشروعك ، في سوق Strapi.", + "app.components.MarketplaceBanner.image.alt": "شعار صاروخ Strapi", + "app.components.MarketplaceBanner.link": "افحصه الآن", + "app.components.Onboarding.help.button": "زر المساعدة", + "app.components.Onboarding.label.completed": "% مكتمل", + "app.components.Onboarding.link.build-content": "بناء بنية المحتوى", + "app.components.Onboarding.link.manage-content": "إضافة وإدارة المحتوى", + "app.components.Onboarding.link.manage-media": "إدارة الوسائط", + "app.components.Onboarding.link.more-videos": "شاهد المزيد من مقاطع الفيديو", + "app.components.Onboarding.title": "ابدأ مقاطع الفيديو", + "app.components.PluginCard.PopUpWarning.install.impossible.autoReload.needed": "يجب تمكين ميزة AutoReload. `yarn develop` يرجى بدء تطبيقك بـ .", + "app.components.PluginCard.PopUpWarning.install.impossible.confirm": "أفهم!", + "app.components.PluginCard.PopUpWarning.install.impossible.environment": "لأسباب أمنية ، لا يمكن تنزيل المكون الإضافي إلا في بيئة التطوير.", + "app.components.PluginCard.PopUpWarning.install.impossible.title": "التنزيل مستحيل", + "app.components.ToggleCheckbox.off-label": "خطأ", + "app.components.ToggleCheckbox.on-label": "حقيقي", + "app.components.Users.MagicLink.connect": "انسخ هذا الرابط وشاركه لمنح حق الوصول لهذا المستخدم", + "app.components.Users.MagicLink.connect.sso": "أرسل هذا الرابط إلى المستخدم ، حيث يمكن إجراء أول تسجيل دخول عبر موفر خدمة الدخول الموحد", + "app.components.Users.ModalCreateBody.block-title.details": "بيانات المستخدم", + "app.components.Users.ModalCreateBody.block-title.roles": "أدوار المستخدم", + "app.components.Users.ModalCreateBody.block-title.roles.description": "يمكن للمستخدم أن يكون له دور واحد أو عدة أدوار", + "app.components.Users.SortPicker.button-label": "ترتيب حسب", + "app.components.Users.SortPicker.sortby.email_asc": "البريد الإلكتروني (من الألف إلى الياء)", + "app.components.Users.SortPicker.sortby.email_desc": "بريد إلكتروني (من ي إلى أ)", + "app.components.Users.SortPicker.sortby.firstname_asc": "الاسم الأول (من الألف إلى الياء)", + "app.components.Users.SortPicker.sortby.firstname_desc": "الاسم الأول (ي إلى أ)", + "app.components.Users.SortPicker.sortby.lastname_asc": "الاسم الأخير (من الألف إلى الياء)", + "app.components.Users.SortPicker.sortby.lastname_desc": "الاسم الأخير (ي إلى أ)", + "app.components.Users.SortPicker.sortby.username_asc": "اسم المستخدم (من الألف إلى الياء)", + "app.components.Users.SortPicker.sortby.username_desc": "اسم المستخدم (من ي إلى أ)", + "app.containers.App.notification.error.init": "API حدث خطأ أثناء الطلب", + "app.containers.AuthPage.ForgotPasswordSuccess.text.contact-admin": "إذا لم تستلم هذا الرابط ، فيرجى الاتصال بالمسؤول.", + "app.containers.AuthPage.ForgotPasswordSuccess.text.email": "قد يستغرق استلام رابط استعادة كلمة المرور بضع دقائق.", + "app.containers.AuthPage.ForgotPasswordSuccess.title": "أرسل البريد الإلكتروني", + "app.containers.Users.EditPage.form.active.label": "فعال", + "app.containers.Users.EditPage.header.label": "تعديل {الاسم}", + "app.containers.Users.EditPage.header.label-loading": "تحرير العضو", + "app.containers.Users.EditPage.roles-bloc-title": "الأدوار المنسوبة", + "app.containers.Users.ModalForm.footer.button-success": "قم بدعوة المستخدم", + "app.links.configure-view": "تكوين العرض", + "app.page.not.found": "أُووبس! يبدو أنه لا يمكننا العثور على الصفحة التي تبحث عنها ...", + "app.static.links.cheatsheet": "ورقة الغش", + "app.utils.add-filter": "أضف عامل تصفية", + "app.utils.close-label": "يغلق", + "app.utils.delete": "يمسح", + "app.utils.duplicate": "ينسخ", + "app.utils.edit": "يحرر", + "app.utils.errors.file-too-big.message": "الملف كبير جدًا", + "app.utils.filter-value": "قيمة التصفية", + "app.utils.filters": "المرشحات", + "app.utils.notify.data-loaded": "{الهدف} تم تحميل", + "app.utils.publish": "أصدر", + "app.utils.select-all": "اختر الكل", + "app.utils.select-field": "حدد المجال", + "app.utils.select-filter": "حدد عامل تصفية", + "app.utils.unpublish": "إلغاء النشر", + "Auth.components.Oops.text": "تم تعليق حسابك.", + "Auth.components.Oops.text.admin": "إذا كان هذا خطأ ، يرجى الاتصال بالمسؤول.", + "Auth.components.Oops.title": "أُووبس...", + "Auth.form.active.label": "فعال", + "Auth.form.button.go-home": "ارجع الى الصفحة الرئيسية", + "Auth.form.button.login.providers.error": "لا يمكننا توصيلك من خلال المزود المحدد.", + "Auth.form.button.login.strapi": "Strapi تسجيل الدخول عبر", + "Auth.form.button.password-recovery": "استعادة كلمة السر", + "Auth.form.confirmPassword.label": "تأكيد كلمة المرور", + "Auth.form.currentPassword.label": "كلمة السر الحالية", + "Auth.form.error.blocked": "تم حظر حسابك من قبل المسؤول.", + "Auth.form.error.confirmed": "لم يتم تأكيد البريد الإلكتروني لحسابك.", + "Auth.form.error.ratelimit": "محاولات كثيرة ، يرجى المحاولة مرة أخرى خلال دقيقة.", + "Auth.form.firstname.label": "الاسم الأول", + "Auth.form.firstname.placeholder": "على سبيل المثال سمر", + "Auth.form.lastname.label": "اسم العائلة", + "Auth.form.lastname.placeholder": "على سبيل المثال سامي", + "Auth.form.password.hide-password": "اخفاء كلمة المرور", + "Auth.form.password.hint": "يجب ألا يقل عدد الأحرف عن 8 أحرف ، وحرف كبير واحد ، ورقم واحد صغير ، ورقم واحد", + "Auth.form.password.show-password": "عرض كلمة المرور", + "Auth.form.register.news.label": "ابقني على اطلاع بالميزات الجديدة والتحسينات القادمة (من خلال القيام بذلك فأنت تقبل {شروط} و ال {بوليصة}).", + "Auth.form.register.subtitle": "تُستخدم بيانات الاعتماد فقط للمصادقة في Strapi. سيتم تخزين جميع البيانات المحفوظة في قاعدة البيانات الخاصة بك.", + "Auth.form.welcome.subtitle": "Strapi قم بتسجيل الدخول إلى حسابك على", + "Auth.form.welcome.title": "Strapi! مرحبا بك في", + "Auth.link.signin": "تسجيل الدخول", + "Auth.link.signin.account": "هل لديك حساب؟", + "Auth.login.sso.divider": "أو تسجيل الدخول باستخدام", + "Auth.login.sso.loading": "تحميل الموفرين ...", + "Auth.login.sso.subtitle": "SSO تسجيل الدخول إلى حسابك عبر", + "Auth.privacy-policy-agreement.policy": "سياسة الخصوصية", + "Auth.privacy-policy-agreement.terms": "شروط", + "Auth.reset-password.title": "إعادة تعيين كلمة المرور", + "clearLabel": "حذف", + "coming.soon": "هذا المحتوى قيد الإنشاء حاليًا وسيعود في غضون أسابيع قليلة!", + "component.Input.error.validation.integer": "يجب أن تكون القيمة عددًا صحيحًا", + "components.AutoReloadBlocker.description": "Strapi قم بتشغيل باستخدام أحد الأوامر التالية:", + "components.FilterOptions.FILTER_TYPES.$contains": "يحتوي على (حساس لحالة الأحرف)", + "components.FilterOptions.FILTER_TYPES.$endsWith": "ينتهي بـ", + "components.FilterOptions.FILTER_TYPES.$eq": "هو", + "components.FilterOptions.FILTER_TYPES.$gt": "أكبر من", + "components.FilterOptions.FILTER_TYPES.$gte": "أكبر من أو يساوي", + "components.FilterOptions.FILTER_TYPES.$lt": "أقل من", + "components.FilterOptions.FILTER_TYPES.$lte": "أقل من أو يساوي", + "components.FilterOptions.FILTER_TYPES.$ne": "ليس", + "components.FilterOptions.FILTER_TYPES.$notContains": "لا يحتوي على (حساس لحالة الأحرف)", + "components.FilterOptions.FILTER_TYPES.$notNull": "هو ليس لاشيء", + "components.FilterOptions.FILTER_TYPES.$null": "هو لاشيء", + "components.FilterOptions.FILTER_TYPES.$startsWith": "يبدا ب", + "components.Input.error.contain.lowercase": "يجب أن تحتوي كلمة المرور على حرف صغير واحد على الأقل", + "components.Input.error.contain.number": "يجب ان تحتوي كلمة المرور على الاقل رقما واحدا", + "components.Input.error.contain.uppercase": "يجب أن تحتوي كلمة المرور على حرف كبير واحد على الأقل", + "components.Input.error.validation.lowercase": "يجب أن تكون القيمة سلسلة أحرف صغيرة", + "components.Input.error.validation.unique": "هذه القيمة مستخدمة بالفعل.", + "components.InputSelect.option.placeholder": "اختر هنا", + "components.NotAllowedInput.text": "لا أذونات لرؤية هذا المجال", + "components.OverlayBlocker.description.serverError": "يجب إعادة تشغيل الخادم ، يرجى التحقق من سجلاتك في المحطة.", + "components.OverlayBlocker.title.serverError": "تستغرق إعادة التشغيل وقتًا أطول من المتوقع", + "components.pagination.go-to": "{page} انتقل إلى صفحة", + "components.pagination.go-to-next": "انتقل إلى الصفحة التالية", + "components.pagination.go-to-previous": "الانتقال إلى الصفحة السابقة", + "components.pagination.remaining-links": "روابط أخرى{number} و", + "components.popUpWarning.button.cancel": "لا ، إلغاء", + "components.popUpWarning.button.confirm": "نعم ، قم بالتأكيد", + "components.Search.placeholder": "بحث...", + "components.TableHeader.sort": "{label} الفرز على", + "components.Wysiwyg.ToggleMode.markdown-mode": "وضع Markdown", + "components.Wysiwyg.ToggleMode.preview-mode": "وضعية المعاينة", + "Content Type Builder": "منشئ أنواع المحتوى", + "content-manager.api.id": "معرف API", + "content-manager.apiError.This attribute must be unique": "{field} يجب أن يكون فريدًا", + "content-manager.App.schemas.data-loaded": "تم تحميل المخططات بنجاح", + "content-manager.components.DraggableCard.delete.field": "{item} حذف", + "content-manager.components.DraggableCard.edit.field": "{item} حرر", + "content-manager.components.DraggableCard.move.field": "{item} تحرك", + "content-manager.components.DragHandle-label": "جر", + "content-manager.components.DynamicTable.row-line": "{number} سطر البند", + "content-manager.components.DynamicZone.add-component": "{componentName} أضف مكونًا إلى", + "content-manager.components.DynamicZone.ComponentPicker-label": "اختر مكونًا واحدًا", + "content-manager.components.DynamicZone.delete-label": "{name} حذف", + "content-manager.components.DynamicZone.error-message": "يحتوي المكون على خطأ (أخطاء)", + "content-manager.components.DynamicZone.missing-components": "There {number, plural, =0 {are # missing components} one {is # missing component} other {are # missing components}}", + "content-manager.components.DynamicZone.move-down-label": "انقل المكون لأسفل", + "content-manager.components.DynamicZone.move-up-label": "انقل المكون لأعلى", + "content-manager.components.DynamicZone.pick-compo": "اختر مكونًا واحدًا", + "content-manager.components.DynamicZone.required": "المكون مطلوب", + "content-manager.components.empty-repeatable": "لا دخول حتى الان. انقر فوق الزر أدناه لإضافة واحد.", + "content-manager.components.FieldItem.linkToComponentLayout": "قم بتعيين تخطيط المكون", + "content-manager.components.FieldSelect.label": "أضف حقلاً", + "content-manager.components.LeftMenu.collection-types": "أنواع المجموعات", + "content-manager.components.LeftMenu.Search.label": "ابحث عن نوع المحتوى", + "content-manager.components.LeftMenu.single-types": "أنواع مفردة", + "content-manager.components.NotAllowedInput.text": "لا أذونات لرؤية هذا المجال", + "content-manager.components.notification.info.maximum-requirement": "لقد وصلت بالفعل إلى الحد الأقصى لعدد الحقول", + "content-manager.components.notification.info.minimum-requirement": "تمت إضافة حقل لمطابقة الحد الأدنى من المتطلبات", + "content-manager.components.RelationInput.icon-button-aria-label": "جر", + "content-manager.components.repeatable.reorder.error": "حدث خطأ أثناء إعادة ترتيب حقل المكون الخاص بك ، يرجى المحاولة مرة أخرى", + "content-manager.components.RepeatableComponent.error-message": "يحتوي المكون (المكونات) على خطأ (أخطاء)", + "content-manager.components.reset-entry": "إعادة الدخول", + "content-manager.components.Select.draft-info-title": "الحالة: مسودة", + "content-manager.components.Select.publish-info-title": "الحالة: منشور", + "content-manager.components.SettingsViewWrapper.pluginHeader.description.edit-settings": "تخصيص كيف سيبدو عرض التحرير.", + "content-manager.components.SettingsViewWrapper.pluginHeader.description.list-settings": "حدد إعدادات عرض القائمة.", + "content-manager.components.SettingsViewWrapper.pluginHeader.title": "{name} تكوين العرض -", + "content-manager.components.TableDelete.label": "{number, plural, one {# entry} other {# entries}} selected", + "content-manager.components.uid.apply": "طبق", + "content-manager.components.uid.available": "متاح", + "content-manager.components.uid.regenerate": "تجديد", + "content-manager.components.uid.suggested": "مقترح", + "content-manager.components.uid.unavailable": "غير متوفره", + "content-manager.containers.Edit.delete-entry": "احذف هذا الإدخال", + "content-manager.containers.Edit.information": "معلومة", + "content-manager.containers.Edit.information.by": "بواسطة", + "content-manager.containers.Edit.information.created": "أُنشء", + "content-manager.containers.Edit.information.draftVersion": "نسخة المسودة", + "content-manager.containers.Edit.information.editing": "التحرير", + "content-manager.containers.Edit.information.lastUpdate": "اخر تحديث", + "content-manager.containers.Edit.information.publishedVersion": "النسخة المنشورة", + "content-manager.containers.Edit.Link.Layout": "تكوين التخطيط", + "content-manager.containers.Edit.Link.Model": "تحرير نوع المجموعة", + "content-manager.containers.Edit.pluginHeader.title.new": "قم بإنشاء إدخال", + "content-manager.containers.EditSettingsView.modal-form.edit-field": "قم بتحرير الحقل", + "content-manager.containers.EditView.add.new-entry": "أضف إدخالاً", + "content-manager.containers.EditView.notification.errors": "النموذج يحتوي على بعض الأخطاء", + "content-manager.containers.List.draft": "مسودة", + "content-manager.containers.List.published": "نشرت", + "content-manager.containers.ListPage.items": "{number, plural, =0 {items} one {item} other {items}}", + "content-manager.containers.ListPage.table-headers.publishedAt": "State", + "content-manager.containers.ListSettingsView.modal-form.edit-label": "{fieldName} تعديل", + "content-manager.containers.SettingPage.add.field": "أدخل حقل آخر", + "content-manager.containers.SettingPage.add.relational-field": "أدخل حقل آخر ذي صلة", + "content-manager.containers.SettingPage.editSettings.entry.title": "عنوان الإدخال", + "content-manager.containers.SettingPage.editSettings.entry.title.description": "اضبط الحقل المعروض لإدخالك", + "content-manager.containers.SettingPage.editSettings.relation-field.description": "قم بتعيين الحقل المعروض في كل من طريقتي التحرير وعرض القائمة", + "content-manager.containers.SettingPage.layout": "تَخطِيط", + "content-manager.containers.SettingPage.listSettings.description": "تكوين الخيارات لنوع المجموعة هذا", + "content-manager.containers.SettingPage.pluginHeaderDescription": "تكوين الإعدادات المحددة لنوع المجموعة هذا", + "content-manager.containers.SettingPage.relations": "حقول ذات صله", + "content-manager.containers.SettingPage.settings": "إعدادات", + "content-manager.containers.SettingPage.view": "رؤية", + "content-manager.containers.SettingsPage.Block.contentType.title": "أنواع المجموعات", + "content-manager.containers.SettingsPage.Block.generalSettings.description": "تكوين الخيارات الافتراضية لأنواع المجموعة الخاصة بك", + "content-manager.containers.SettingsPage.pluginHeaderDescription": "قم بتكوين الإعدادات لجميع أنواع المجموعات والمجموعات الخاصة بك", + "content-manager.containers.SettingsView.list.subtitle": "تكوين تخطيط وعرض أنواع المجموعات والمجموعات الخاصة بك", + "content-manager.containers.SettingsView.list.title": "تكوينات العرض", + "content-manager.containers.SettingViewModel.pluginHeader.title": "{name} مدير محتوى -", + "content-manager.dnd.cancel-item": "{item}, dropped. Re-order cancelled.", + "content-manager.dnd.drop-item": "{item}, dropped. Final position in list: {position}.", + "content-manager.dnd.grab-item": "{item}, grabbed. Current position in list: {position}. Press up and down arrow to change position, Spacebar to drop, Escape to cancel.", + "content-manager.dnd.instructions": "اضغط على مفتاح المسافة للاستيلاء وإعادة الترتيب", + "content-manager.dnd.reorder": "{item}, انتقل. منصب جديد في القائمة: {position}.", + "content-manager.DynamicTable.relation-loaded": "تم تحميل العلاقات", + "content-manager.DynamicTable.relation-loading": "يتم تحميل العلاقات", + "content-manager.DynamicTable.relation-more": "تحتوي هذه العلاقة على كيانات أكثر من المعروضة", + "content-manager.edit-settings-view.link-to-ctb.components": "قم بتحرير المكون", + "content-manager.edit-settings-view.link-to-ctb.content-types": "قم بتحرير نوع المحتوى", + "content-manager.emptyAttributes.button": "انتقل إلى منشئ نوع المجموعة", + "content-manager.emptyAttributes.description": "أضف حقلك الأول إلى نوع المجموعة الخاصة بك", + "content-manager.form.Input.hint.character.unit": "{maxValue, plural, one { character} other { characters}}", + "content-manager.form.Input.hint.minMaxDivider": " / ", + "content-manager.form.Input.hint.text": "{min, select, undefined {} other {min. {min}}}{divider}{max, select, undefined {} other {max. {max}}}{unit}{br}{description}", + "content-manager.form.Input.pageEntries.inputDescription": "ملاحظة: يمكنك تجاوز هذه القيمة في صفحة إعدادات نوع المجموعة.", + "content-manager.form.Input.sort.order": "ترتيب الافتراضي", + "content-manager.form.Input.wysiwyg": "WYSIWYG عرض كـ", + "content-manager.global.displayedFields": "الحقول المعروضة", + "content-manager.groups": "مجموعات", + "content-manager.groups.numbered": "({number}) مجموعات", + "content-manager.header.name": "محتوى", + "content-manager.HeaderLayout.button.label-add-entry": "إنشاء إدخال جديد", + "content-manager.link-to-ctb": "قم بتحرير النموذج", + "content-manager.models": "أنواع المجموعات", + "content-manager.models.numbered": "({number}) أنواع المجموعات", + "content-manager.notification.info.minimumFields": "يجب أن يكون لديك حقل واحد على الأقل معروض", + "content-manager.notification.upload.error": "حدث خطأ أثناء تحميل ملفاتك", + "content-manager.pages.ListView.header-subtitle": "{number, plural, =0 {# entries} one {# entry} other {# entries}} found", + "content-manager.pages.NoContentType.button": "قم بإنشاء نوع المحتوى الأول الخاص بك", + "content-manager.pages.NoContentType.text": "ليس لديك أي محتوى حتى الآن ، نوصيك بإنشاء نوع المحتوى الأول الخاص بك.", + "content-manager.permissions.not-allowed.create": "لا يسمح لك لإنشاء وثيقة", + "content-manager.permissions.not-allowed.update": "لا يسمح لك أن ترى هذه الوثيقة", + "content-manager.popover.display-relations.label": "عرض العلاقات", + "content-manager.popUpwarning.warning.has-draft-relations.button-confirm": "نعم ، انشر", + "content-manager.popUpwarning.warning.has-draft-relations.message": "{count, plural, one { relation is } other { relations are } } not published yet and might lead to unexpected behavior.", + "content-manager.popUpWarning.warning.has-draft-relations.title": "تأكيد", + "content-manager.popUpWarning.warning.publish-question": "هل مازلت تريد النشر؟", + "content-manager.popUpWarning.warning.unpublish": "إذا لم تنشر هذا المحتوى ، فسيتحول تلقائيًا إلى مسودة.", + "content-manager.popUpWarning.warning.unpublish-question": "هل أنت متأكد أنك لا تريد نشره؟", + "content-manager.relation.add": "أضف العلاقة", + "content-manager.relation.disconnect": "نزع", + "content-manager.relation.isLoading": "يتم تحميل العلاقات", + "content-manager.relation.loadMore": "تحميل المزيد", + "content-manager.relation.notAvailable": "لا توجد علاقات متاحة", + "content-manager.relation.publicationState.draft": "مسودة", + "content-manager.relation.publicationState.published": "منشور", + "content-manager.select.currently.selected": "{count} المحدد حاليا", + "content-manager.success.record.publish": "منشور", + "content-manager.success.record.unpublish": "غير منشورة", + "content-manager.utils.data-loaded": "The {number, plural, =1 {entry has} other {entries have}} successfully been loaded", + "dark": "داكن", + "Documentation": "توثيق", + "form.button.continue": "واصل", + "form.button.done": "منتهي", + "global.actions": "أجراءات", + "global.auditLogs": "سجلات التدقيق", + "global.back": "الى الوراء", + "global.cancel": "إلغاء", + "global.change-password": "تغيير كلمة المرور", + "global.content-manager": "مدير محتوى", + "global.continue": "واصل", + "global.delete": "مسح", + "global.delete-target": "{target} مسح ", + "global.description": "وصف", + "global.details": "تفاصيل", + "global.disabled": "إبطال", + "global.documentation": "توثيق", + "global.enabled": "ممكن", + "global.finish": "نهاية", + "global.marketplace": "المتجر", + "global.name": "اسم", + "global.none": "لا أحد", + "global.password": "كلمة المرور", + "global.plugins": "الإضافات", + "global.plugins.content-manager": "مدير محتوى", + "global.plugins.content-manager.description": "طريقة سريعة لرؤية وتحرير وحذف البيانات في قاعدة البيانات الخاصة بك.", + "global.plugins.content-type-builder": "منشئ نوع المحتوى", + "global.plugins.content-type-builder.description": "قم بنمذجة بنية البيانات الخاصة بواجهة برمجة التطبيقات (API) الخاصة بك. إنشاء مجالات وعلاقات جديدة في دقيقة واحدة فقط. يتم إنشاء الملفات وتحديثها تلقائيًا في مشروعك.", + "global.plugins.documentation": "توثيق", + "global.plugins.documentation.description": "قم بإنشاء مستند OpenAPI وتصور API الخاص بك باستخدام SWAGGER UI.", + "global.plugins.email": "بريد إلكتروني", + "global.plugins.email.description": "تكوين التطبيق الخاص بك لإرسال رسائل البريد الإلكتروني.", + "global.plugins.graphql": "GraphQL", + "global.plugins.graphql.description": "يضيف نقطة نهاية GraphQL بأساليب واجهة برمجة التطبيقات الافتراضية.", + "global.plugins.i18n": "تدويل", + "global.plugins.i18n.description": "يمكّن هذا المكون الإضافي من إنشاء المحتوى وقراءته وتحديثه بلغات مختلفة ، سواء من لوحة الإدارة أو من واجهة برمجة التطبيقات.", + "global.plugins.sentry": "Sentry", + "global.plugins.sentry.description": "إرسال أحداث خطأ Strapi إلى Sentry.", + "global.plugins.upload": "مكتبة الوسائط", + "global.plugins.upload.description": "إدارة ملفات الوسائط.", + "global.plugins.users-permissions": "الأدوار والأذونات", + "global.plugins.users-permissions.description": "قم بحماية API الخاص بك من خلال عملية مصادقة كاملة تعتمد على JWT. يأتي هذا المكون الإضافي أيضًا مع إستراتيجية قائمة التحكم بالوصول (ACL) التي تتيح لك إدارة الأذونات بين مجموعات المستخدمين.", + "global.profile": "حساب تعريفي", + "global.prompt.unsaved": "هل أنت متأكد أنك تريد مغادرة هذه الصفحة؟ ستفقد كل تعديلاتك", + "global.reset-password": "إعادة تعيين كلمة المرور", + "global.roles": "الأدوار", + "global.save": "يحفظ", + "global.search": "يبحث", + "global.see-more": "شاهد المزيد", + "global.select": "اختار", + "global.select-all-entries": "حدد كل الإدخالات", + "global.settings": "إعدادات", + "global.type": "نوع", + "global.users": "المستخدمون", + "HomePage.helmet.title": "الصفحة الرئيسية", + "HomePage.roadmap": "انظر خارطة الطريق لدينا", + "HomePage.welcome.congrats": "تهاني!", + "HomePage.welcome.congrats.content": "Strapiلقد قمت بتسجيل الدخول باعتبارك المسؤول الأول. لاكتشاف الميزات القوية التي يوفرها", + "HomePage.welcome.congrats.content.bold": "نوصيك بإنشاء أول نوع مجموعة خاص بك.", + "light": "فاتح", + "Media Library": "مكتبة الوسائط", + "notification.contentType.relations.conflict": "Content type has conflicting relations", + "notification.default.title": "Information:", + "notification.ee.warning.at-seat-limit.title": "{licenseLimitStatus, select, OVER_LIMIT {Over} AT_LIMIT {At}} seat limit ({currentUserCount}/{permittedSeats})", + "notification.ee.warning.over-.message": "Add seats to {licenseLimitStatus, select, OVER_LIMIT {invite} AT_LIMIT {re-enable}} Users. If you already did it but it's not reflected in Strapi yet, make sure to restart your app.", + "notification.error.invalid.configuration": "You have an invalid configuration, check your server log for more information.", + "notification.error.tokennamenotunique": "Name already assigned to another token", + "notification.form.error.fields": "The form contains some errors", + "notification.form.success.fields": "Changes saved", + "notification.link-copied": "Link copied into the clipboard", + "notification.permission.not-allowed-read": "You are not allowed to see this document", + "notification.success.apitokencreated": "API Token successfully created", + "notification.success.apitokenedited": "API Token successfully edited", + "notification.success.delete": "The item has been deleted", + "notification.success.saved": "Saved", + "notification.success.title": "Success:", + "notification.success.transfertokencreated": "Transfer Token successfully created", + "notification.success.transfertokenedited": "Transfer Token successfully edited", + "notification.version.update.message": "A new version of Strapi is available!", + "notification.warning.404": "404 - Not found", + "notification.warning.title": "Warning:", + "or": "OR", } From 830421e8e5f661ba7f2679a72fa5b26979cbfe34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9Cmarwa-hodeib=E2=80=9D?= Date: Wed, 10 May 2023 16:12:21 +0300 Subject: [PATCH 67/84] fix error --- .../core/admin/admin/src/translations/ar.json | 293 ++++++++++++++++-- 1 file changed, 271 insertions(+), 22 deletions(-) diff --git a/packages/core/admin/admin/src/translations/ar.json b/packages/core/admin/admin/src/translations/ar.json index 25caa58dbb..6e66746ac9 100644 --- a/packages/core/admin/admin/src/translations/ar.json +++ b/packages/core/admin/admin/src/translations/ar.json @@ -272,7 +272,7 @@ "app.components.GuidedTour.apiTokens.create.title": "🚀 مشاهدة المحتوى في العمل", "app.components.GuidedTour.apiTokens.success.cta.title": "العودة الى الصفحة الرئيسية", "app.components.GuidedTour.apiTokens.success.title": "✅ الخطوة 3: اكتمل", - "app.components.GuidedTour.CM.create.content": "

قم بإنشاء وإدارة كل المحتوى هنا في إدارة المحتوى.

مثال: أخذ مثال موقع المدونة إلى أبعد من ذلك ، يمكن للمرء كتابة مقال وحفظه ونشره كما يحلو له.

💡 نصيحة سريعة - لا تنس النقر على "نشر" على المحتوى الذي تنشئه.

", + "app.components.GuidedTour.CM.create.content": "

قم بإنشاء وإدارة كل المحتوى هنا في إدارة المحتوى.

مثال: أخذ مثال موقع المدونة إلى أبعد من ذلك ، يمكن للمرء كتابة مقال وحفظه ونشره كما يحلو له.

💡 نصيحة سريعة - لا تنس النقر على ’نشر’ على المحتوى الذي تنشئه.

", "app.components.GuidedTour.CM.create.title": "⚡️ أنشئ محتوى", "app.components.GuidedTour.CM.success.content": "

رائع ، خطوة أخيرة يجب أن تبدأ بها!

🚀 مشاهدة المحتوى في العمل", "app.components.GuidedTour.CM.success.cta.title": "API اختبر ملف", @@ -619,25 +619,274 @@ "HomePage.welcome.congrats.content.bold": "نوصيك بإنشاء أول نوع مجموعة خاص بك.", "light": "فاتح", "Media Library": "مكتبة الوسائط", - "notification.contentType.relations.conflict": "Content type has conflicting relations", - "notification.default.title": "Information:", - "notification.ee.warning.at-seat-limit.title": "{licenseLimitStatus, select, OVER_LIMIT {Over} AT_LIMIT {At}} seat limit ({currentUserCount}/{permittedSeats})", - "notification.ee.warning.over-.message": "Add seats to {licenseLimitStatus, select, OVER_LIMIT {invite} AT_LIMIT {re-enable}} Users. If you already did it but it's not reflected in Strapi yet, make sure to restart your app.", - "notification.error.invalid.configuration": "You have an invalid configuration, check your server log for more information.", - "notification.error.tokennamenotunique": "Name already assigned to another token", - "notification.form.error.fields": "The form contains some errors", - "notification.form.success.fields": "Changes saved", - "notification.link-copied": "Link copied into the clipboard", - "notification.permission.not-allowed-read": "You are not allowed to see this document", - "notification.success.apitokencreated": "API Token successfully created", - "notification.success.apitokenedited": "API Token successfully edited", - "notification.success.delete": "The item has been deleted", - "notification.success.saved": "Saved", - "notification.success.title": "Success:", - "notification.success.transfertokencreated": "Transfer Token successfully created", - "notification.success.transfertokenedited": "Transfer Token successfully edited", - "notification.version.update.message": "A new version of Strapi is available!", - "notification.warning.404": "404 - Not found", - "notification.warning.title": "Warning:", - "or": "OR", + "notification.contentType.relations.conflict": "نوع المحتوى له علاقات متضاربة", + "notification.default.title": "معلومة:", + "notification.ee.warning.at-seat-limit.title": "{LicenseLimitStatus ، حدد ، OVER_LIMIT {Over} AT_LIMIT {At}} حد المقاعد ({currentUserCount} / {allowedSeats})", + "notification.ee.warning.over-.message": "أضف مقاعد إلى {LicenseLimitStatus ، حدد ، OVER_LIMIT {دعوة} AT_LIMIT {re-enable}} مستخدمين. إذا كنت قد فعلت ذلك بالفعل ولكن لم ينعكس في Strapi بعد ، فتأكد من إعادة تشغيل التطبيق الخاص بك.", + "notification.error.invalid.configuration": "لديك تكوين غير صالح ، تحقق من سجل الخادم لمزيد من المعلومات.", + "notification.error.tokennamenotunique": "تم تعيين الاسم بالفعل لرمز مميز آخر", + "notification.form.error.fields": "النموذج يحتوي على بعض الأخطاء", + "notification.form.success.fields": "تم حفظ التغييرات", + "notification.link-copied": "تم نسخ الرابط في الحافظة", + "notification.permission.not-allowed-read": "لا يسمح لك أن ترى هذه الوثيقة", + "notification.success.apitokencreated": "تم إنشاء رمز API بنجاح", + "notification.success.apitokenedited": "تم تحرير رمز API بنجاح", + "notification.success.delete": "تم حذف العنصر", + "notification.success.saved": "حفظ", + "notification.success.title": "نجاح:", + "notification.success.transfertokencreated": "تم إنشاء رمز النقل بنجاح", + "notification.success.transfertokenedited": "تم تحرير رمز النقل بنجاح", + "notification.version.update.message": "نسخة جديدة متاحة من ستربي!", + "notification.warning.404": "404 غير موجود", + "notification.warning.title": "تحذير:", + "or": "أو", + "Roles & Permissions": "الأدوار والأذونات", + "Roles.components.List.empty.withSearch": "لا يوجد دور مطابق للبحث ({بحث}) ...", + "Roles.ListPage.notification.delete-all-not-allowed": "تعذر حذف بعض الأدوار لأنها مرتبطة بالمستخدمين", + "Roles.ListPage.notification.delete-not-allowed": "لا يمكن حذف الدور إذا كان مرتبطًا بالمستخدمين", + "Roles.RoleRow.select-all": "حدد {name} للإجراءات المجمعة", + "Roles.RoleRow.user-count": "{number، plural، = 0 {# user} واحد {# user} آخر {# users}}", + "selectButtonTitle": "يختار", + "Settings.apiTokens.addFirstToken": "أضف رمز API الأول الخاص بك", + "Settings.apiTokens.addNewToken": "إضافة رمز API جديد", + "Settings.apiTokens.create": "إنشاء رمز API جديد", + "Settings.apiTokens.createPage.BoundRoute.title": "طريق منضم إلى", + "Settings.apiTokens.createPage.permissions.description": "يتم سرد الإجراءات المرتبطة بالمسار فقط أدناه.", + "Settings.apiTokens.createPage.permissions.header.hint": "حدد إجراءات التطبيق أو إجراءات البرنامج المساعد وانقر على أيقونة الترس لعرض المسار المنضم", + "Settings.apiTokens.createPage.permissions.header.title": "إعدادات متقدمة", + "Settings.apiTokens.createPage.permissions.title": "أذونات", + "Settings.apiTokens.createPage.title": "إنشاء رمز API", + "Settings.apiTokens.description": "قائمة الرموز التي تم إنشاؤها لاستهلاك API", + "Settings.apiTokens.emptyStateLayout": "ليس لديك أي محتوى حتى الآن ...", + "Settings.apiTokens.ListView.headers.createdAt": "أنشئت في", + "Settings.apiTokens.ListView.headers.description": "وصف", + "Settings.apiTokens.ListView.headers.lastUsedAt": "آخر أستخدام", + "Settings.apiTokens.ListView.headers.name": "اسم", + "Settings.apiTokens.ListView.headers.type": "نوع الرمز", + "Settings.apiTokens.regenerate": "تجديد", + "Settings.apiTokens.title": "رموز API", + "Settings.application.customization": "التخصيص", + "Settings.application.customization.auth-logo.carousel-hint": "استبدل الشعار في صفحات المصادقة", + "Settings.application.customization.carousel-hint": "تغيير شعار لوحة الإدارة (الحد الأقصى للبعد: {البعد} × {البعد} ، الحد الأقصى لحجم الملف: {الحجم} كيلوبايت)", + "Settings.application.customization.carousel-slide.label": "شريحة الشعار", + "Settings.application.customization.carousel.auth-logo.title": "شعار Auth", + "Settings.application.customization.carousel.change-action": "تغيير الشعار", + "Settings.application.customization.carousel.menu-logo.title": "شعار القائمة", + "Settings.application.customization.carousel.reset-action": "إعادة تعيين الشعار", + "Settings.application.customization.carousel.title": "شعار", + "Settings.application.customization.menu-logo.carousel-hint": "استبدل الشعار في شريط التنقل الرئيسي", + "Settings.application.customization.modal.cancel": "إلغاء", + "Settings.application.customization.modal.pending": "شعار معلق", + "Settings.application.customization.modal.pending.card-badge": "صورة", + "Settings.application.customization.modal.pending.choose-another": "اختر شعارًا آخر", + "Settings.application.customization.modal.pending.subtitle": "إدارة الشعار المختار قبل تحميله", + "Settings.application.customization.modal.pending.title": "الشعار جاهز للتحميل", + "Settings.application.customization.modal.pending.upload": "تحميل الشعار", + "Settings.application.customization.modal.tab.label": "كيف تريد تحميل الأصول الخاصة بك؟", + "Settings.application.customization.modal.upload": "تحميل الشعار", + "Settings.application.customization.modal.upload.cta.browse": "تصفح ملفات", + "Settings.application.customization.modal.upload.drag-drop": "قم بالسحب والإفلات هنا أو", + "Settings.application.customization.modal.upload.error-format": "تم تحميل تنسيق خاطئ (التنسيقات المقبولة فقط: jpeg ، jpg ، png ، svg).", + "Settings.application.customization.modal.upload.error-network": "خطأ في الشبكة", + "Settings.application.customization.modal.upload.error-size": "الملف الذي تم تحميله كبير جدًا (الحد الأقصى للبعد: {البعد} x {البعد} ، الحد الأقصى لحجم الملف: {الحجم} كيلوبايت)", + "Settings.application.customization.modal.upload.file-validation": "أقصى بُعد: {البعد} × {البعد} ، الحد الأقصى للحجم: {الحجم} كيلوبايت", + "Settings.application.customization.modal.upload.from-computer": "من الكمبيوتر", + "Settings.application.customization.modal.upload.from-url": "من URL", + "Settings.application.customization.modal.upload.from-url.input-label": "URL", + "Settings.application.customization.modal.upload.next": "التالي", + "Settings.application.customization.size-details": "أقصى بُعد: {البعد} x {البعد} ، الحد الأقصى لحجم الملف: {الحجم} كيلوبايت", + "Settings.application.description": "المعلومات العالمية للوحة الإدارة", + "Settings.application.edition-title": "الخطة الحالية", + "Settings.application.ee-or-ce": "{communityEdition، select، true {Community Edition} أخرى {Enterprise Edition}}", + "Settings.application.ee.admin-seats.add-seats": "{isHostedOnStrapiCloud، select، true {Add seat} other {Contact sales}}", + "Settings.application.ee.admin-seats.at-limit-tooltip": "عند الحد: أضف مقاعد لدعوة المزيد من المستخدمين", + "Settings.application.ee.admin-seats.count": "{enforcementUserCount}/{permittedSeats}", + "Settings.application.get-help": "احصل على مساعدة", + "Settings.application.link-pricing": "انظر جميع خطط التسعير", + "Settings.application.link-upgrade": "قم بترقية لوحة الإدارة الخاصة بك", + "Settings.application.node-version": "إصدار العقدة", + "Settings.application.strapi-version": "نسخة ستربي", + "Settings.application.strapiVersion": "Strapi نسخة", + "Settings.application.title": "ملخص", + "Settings.error": "خطأ", + "Settings.global": "الاعدادات العامة", + "Settings.PageTitle": "الإعدادات - {name}", + "Settings.permissions": "لوحة الإدارة", + "Settings.permissions.auditLogs.action": "فعل", + "Settings.permissions.auditLogs.admin.auth.success": "دخول المشرف", + "Settings.permissions.auditLogs.admin.logout": "خروج المسؤول", + "Settings.permissions.auditLogs.component.create": "تكوين المكون", + "Settings.permissions.auditLogs.component.delete": "حذف المكون", + "Settings.permissions.auditLogs.component.update": "مكون التحديث", + "Settings.permissions.auditLogs.content-type.create": "إنشاء نوع المحتوى", + "Settings.permissions.auditLogs.content-type.delete": "حذف نوع المحتوى", + "Settings.permissions.auditLogs.content-type.update": "تحديث نوع المحتوى", + "Settings.permissions.auditLogs.date": "تاريخ", + "Settings.permissions.auditLogs.details": "تفاصيل السجل", + "Settings.permissions.auditLogs.entry.create": "إنشاء إدخال {model، select، undefined {} other {({model})}}", + "Settings.permissions.auditLogs.entry.delete": "حذف الإدخال {model، select، undefined {} other {({model})}}", + "Settings.permissions.auditLogs.entry.publish": "نشر الإدخال {model، select، undefined {} other {({model})}}", + "Settings.permissions.auditLogs.entry.unpublish": "إلغاء نشر الإدخال {model، select، undefined {} other {({model})}}", + "Settings.permissions.auditLogs.entry.update": "تحديث الإدخال {model، select، undefined {} other {({model})}}", + "Settings.permissions.auditLogs.filters.combobox.aria-label": "ابحث وحدد خيارًا للتصفية", + "Settings.permissions.auditLogs.listview.header.subtitle": "سجلات لجميع الأنشطة التي حدثت في بيئتك", + "Settings.permissions.auditLogs.media.create": "قم بإنشاء وسائط", + "Settings.permissions.auditLogs.media.delete": "حذف الوسائط", + "Settings.permissions.auditLogs.media.update": "تحديث الوسائط", + "Settings.permissions.auditLogs.payload": "الحمولة", + "Settings.permissions.auditLogs.permission.create": "إنشاء إذن", + "Settings.permissions.auditLogs.permission.delete": "حذف إذن", + "Settings.permissions.auditLogs.permission.update": "إذن التحديث", + "Settings.permissions.auditLogs.role.create": "خلق دور", + "Settings.permissions.auditLogs.role.delete": "حذف الدور", + "Settings.permissions.auditLogs.role.update": "تحديث الدور", + "Settings.permissions.auditLogs.user": "مستخدم", + "Settings.permissions.auditLogs.user.create": "إنشاء مستخدم", + "Settings.permissions.auditLogs.user.delete": "مسح المستخدم", + "Settings.permissions.auditLogs.user.fullname": "{firstname} {lastname}", + "Settings.permissions.auditLogs.user.update": "تحديث المستخدم", + "Settings.permissions.auditLogs.userId": "معرف المستخدم", + "Settings.permissions.category": "إعدادات الأذونات لـ {category}", + "Settings.permissions.category.plugins": "إعدادات الأذونات للمكوِّن الإضافي {category}", + "Settings.permissions.conditions.anytime": "في أي وقت", + "Settings.permissions.conditions.apply": "يتقدم", + "Settings.permissions.conditions.can": "يستطيع", + "Settings.permissions.conditions.conditions": "شروط", + "Settings.permissions.conditions.define-conditions": "حدد الشروط", + "Settings.permissions.conditions.links": "الروابط", + "Settings.permissions.conditions.no-actions": "تحتاج أولاً إلى تحديد الإجراءات (إنشاء ، قراءة ، تحديث ، ...) قبل تحديد الشروط عليها.", + "Settings.permissions.conditions.none-selected": "في أي وقت", + "Settings.permissions.conditions.or": "أو", + "Settings.permissions.conditions.when": "متى", + "Settings.permissions.select-all-by-permission": "حدد كافة أذونات {label}", + "Settings.permissions.select-by-permission": "اختار {label} إذن", + "Settings.permissions.users.active": "نشيط", + "Settings.permissions.users.create": "قم بدعوة مستخدم جديد", + "Settings.permissions.users.email": "بريد إلكتروني", + "Settings.permissions.users.firstname": "الاسم الأول", + "Settings.permissions.users.form.sso": "تواصل مع SSO", + "Settings.permissions.users.form.sso.description": "عند التمكين (ON) ، يمكن للمستخدمين تسجيل الدخول عبر SSO", + "Settings.permissions.users.inactive": "غير نشط", + "Settings.permissions.users.lastname": "اسم العائلة", + "Settings.permissions.users.listview.header.subtitle": "جميع المستخدمين الذين لديهم حق الوصول إلى لوحة إدارة Strapi", + "Settings.permissions.users.roles": "الأدوار", + "Settings.permissions.users.strapi-author": "مؤلف", + "Settings.permissions.users.strapi-editor": "محرر", + "Settings.permissions.users.strapi-super-admin": "مشرف فائق", + "Settings.permissions.users.tabs.label": "أذونات علامات التبويب", + "Settings.permissions.users.user-status": "حالة المستخدم", + "Settings.permissions.users.username": "اسم المستخدم", + "Settings.profile.form.notify.data.loaded": "تم تحميل بيانات ملفك الشخصي", + "Settings.profile.form.section.experience.clear.select": "امسح لغة الواجهة المحددة", + "Settings.profile.form.section.experience.here": "هنا", + "Settings.profile.form.section.experience.interfaceLanguage": "لغة الواجهة", + "Settings.profile.form.section.experience.interfaceLanguage.hint": "سيعرض هذا فقط واجهتك الخاصة باللغة المختارة.", + "Settings.profile.form.section.experience.interfaceLanguageHelp": "سيتم تطبيق تغييرات التفضيلات عليك فقط. يتوفر مزيد من المعلومات{here}.", + "Settings.profile.form.section.experience.mode.hint": "يعرض واجهتك في الوضع المختار.", + "Settings.profile.form.section.experience.mode.label": "وضع الواجهة", + "Settings.profile.form.section.experience.mode.option-label": "{name} وضع", + "Settings.profile.form.section.experience.title": "خبرة", + "Settings.profile.form.section.helmet.title": "ملف تعريفي للمستخدم", + "Settings.profile.form.section.profile.page.title": "الصفحة الشخصية", + "Settings.roles.create.description": "تحديد الحقوق الممنوحة للدور", + "Settings.roles.create.title": "أنشئ دورًا", + "Settings.roles.created": "تم إنشاء الدور", + "Settings.roles.edit.title": "تحرير دور", + "Settings.roles.form.button.users-with-role": "{number, plural, =0 {# users} one {# user} other {# users}} with this role", + "Settings.roles.form.created": "مكون", + "Settings.roles.form.description": "اسم ووصف الدور", + "Settings.roles.form.permission.property-label": "{label} أذونات", + "Settings.roles.form.permissions.attributesPermissions": "أذونات الحقول", + "Settings.roles.form.permissions.create": "خلق", + "Settings.roles.form.permissions.delete": "شطب", + "Settings.roles.form.permissions.publish": "ينشر", + "Settings.roles.form.permissions.read": "يقرأ", + "Settings.roles.form.permissions.update": "تحديث", + "Settings.roles.list.button.add": "أضف دورًا جديدًا", + "Settings.roles.list.description": "قائمة الأدوار", + "Settings.roles.title.singular": "دور", + "Settings.sso.description": "قم بتكوين الإعدادات لميزة الدخول الموحد.", + "Settings.sso.form.defaultRole.description": "سيقوم بإرفاق المستخدم الجديد المصادق عليه بالدور المحدد", + "Settings.sso.form.defaultRole.description-not-allowed": "تحتاج إلى الحصول على إذن لقراءة أدوار المسؤول", + "Settings.sso.form.defaultRole.label": "الدور الافتراضي", + "Settings.sso.form.registration.description": "أنشئ مستخدمًا جديدًا على تسجيل الدخول الموحّد (SSO) في حالة عدم وجود حساب", + "Settings.sso.form.registration.label": "التسجيل التلقائي", + "Settings.sso.title": "علامة واحدة على", + "Settings.tokens.Button.cancel": "يلغي", + "Settings.tokens.Button.regenerate": "تجديد", + "Settings.tokens.copy.editMessage": "لأسباب تتعلق بالأمان ، لا يمكنك رؤية رمزك المميز إلا مرة واحدة.", + "Settings.tokens.copy.editTitle": "لم يعد هذا الرمز المميز يمكن الوصول إليه.", + "Settings.tokens.copy.lastWarning": "تأكد من نسخ هذا الرمز المميز ، فلن تتمكن من رؤيته مرة أخرى!", + "Settings.tokens.duration.30-days": "30 يوما", + "Settings.tokens.duration.7-days": "7 أيام", + "Settings.tokens.duration.90-days": "90 يومًا", + "Settings.tokens.duration.expiration-date": "تاريخ انتهاء الصلاحية", + "Settings.tokens.duration.unlimited": "غير محدود", + "Settings.tokens.form.description": "وصف", + "Settings.tokens.form.duration": "مدة الرمز", + "Settings.tokens.form.name": "اسم", + "Settings.tokens.form.type": "نوع الرمز", + "Settings.tokens.ListView.headers.createdAt": "أنشئت في", + "Settings.tokens.ListView.headers.description": "وصف", + "Settings.tokens.ListView.headers.lastUsedAt": "آخر أستخدام", + "Settings.tokens.ListView.headers.name": "اسم", + "Settings.tokens.notification.copied": "تم نسخ الرمز المميز إلى الحافظة.", + "Settings.tokens.popUpWarning.message": "هل أنت متأكد أنك تريد إعادة إنشاء هذا الرمز المميز؟", + "Settings.tokens.regenerate": "تجديد", + "Settings.tokens.RegenerateDialog.title": "إعادة إنشاء الرمز المميز", + "Settings.tokens.types.custom": "مخصص", + "Settings.tokens.types.full-access": "الوصول الكامل", + "Settings.tokens.types.read-only": "يقرأ فقط", + "Settings.transferTokens.addFirstToken": "أضف أول رمز تحويل خاص بك", + "Settings.transferTokens.addNewToken": "أضف رمز تحويل جديد", + "Settings.transferTokens.create": "إنشاء رمز تحويل جديد", + "Settings.transferTokens.createPage.title": "إنشاء رمز التحويل", + "Settings.transferTokens.description": "قائمة برموز التحويل المُنشأة", + "Settings.transferTokens.emptyStateLayout": "ليس لديك أي محتوى حتى الآن ...", + "Settings.transferTokens.ListView.headers.type": "نوع الرمز", + "Settings.transferTokens.title": "رموز التحويل", + "Settings.webhooks.create": "إنشاء خطاف ويب", + "Settings.webhooks.create.header": "إنشاء رأس جديد", + "Settings.webhooks.created": "تم إنشاء الرد التلقائي على الويب", + "Settings.webhooks.event.publish-tooltip": "هذا الحدث موجود فقط للمحتويات مع تمكين نظام المسودة / النشر", + "Settings.webhooks.events.create": "أخلق", + "Settings.webhooks.events.update": "تحديث", + "Settings.webhooks.form.events": "الأحداث", + "Settings.webhooks.form.headers": "الرؤوس", + "Settings.webhooks.form.url": "URL", + "Settings.webhooks.headers.remove": "{number} قم بإزالة صف الرأس", + "Settings.webhooks.key": "مفتاح", + "Settings.webhooks.list.button.add": "إنشاء خطاف ويب جديد", + "Settings.webhooks.list.description": "احصل على إخطارات التغييرات POST", + "Settings.webhooks.list.empty.description": "لم يتم العثور على خطافات الويب", + "Settings.webhooks.list.empty.link": "انظر وثائقنا", + "Settings.webhooks.list.empty.title": "لا توجد خطاطيف ويب حتى الان", + "Settings.webhooks.list.th.actions": "أجراءات", + "Settings.webhooks.list.th.status": "حالة", + "Settings.webhooks.singular": "الويب هوك", + "Settings.webhooks.title": "ويب هوك", + "Settings.webhooks.to.delete": "{webhooksToDeleteLength, plural, one {# asset} other {# assets}} selected", + "Settings.webhooks.trigger": "مشغل", + "Settings.webhooks.trigger.cancel": "إلغاء المشغل...", + "Settings.webhooks.trigger.pending": "قيد الانتظار…", + "Settings.webhooks.trigger.save": "يرجى الحفظ للتشغيل", + "Settings.webhooks.trigger.success": "نجاح!", + "Settings.webhooks.trigger.success.label": "نجح الزناد", + "Settings.webhooks.trigger.test": "اختبار الزناد", + "Settings.webhooks.trigger.title": "احفظ قبل تشغيل", + "Settings.webhooks.value": "قيمة", + "skipToContent": "تخطى الى المحتوى", + "submit": "يُقدِّم", + "Usecase.back-end": "المطور الخلفي", + "Usecase.button.skip": "تخطي هذا السؤال", + "Usecase.content-creator": "صانع المحتوى", + "Usecase.front-end": "مطور الواجهة الأمامية", + "Usecase.full-stack": "مطور كامل المكدس", + "Usecase.input.work-type": "ما نوع العمل الذي تفعله؟", + "Usecase.notification.success.project-created": "تم إنشاء المشروع بنجاح", + "Usecase.other": "آخر", + "Usecase.title": "تخبرنا أكثر قليلا عن نفسك", + "Users.components.List.empty": "لا يوجد مستخدمون ...", + "Users.components.List.empty.withFilters": "لا يوجد مستخدمون لديهم عوامل التصفية المطبقة ...", + "Users.components.List.empty.withSearch": "لا يوجد مستخدمون مطابقون للبحث({search})..." } From 524325fd303e7fbdd1d7405e84e516ad51605f6e Mon Sep 17 00:00:00 2001 From: Marc-Roig Date: Tue, 23 May 2023 12:16:55 +0200 Subject: [PATCH 68/84] doc: transactions --- .../_category_.json | 0 .../reordering.mdx | 0 .../docs/01-core/database/02-transactions.md | 102 ++++++++++++++++++ 3 files changed, 102 insertions(+) rename docs/docs/docs/01-core/database/{relations => 01-relations}/_category_.json (100%) rename docs/docs/docs/01-core/database/{relations => 01-relations}/reordering.mdx (100%) create mode 100644 docs/docs/docs/01-core/database/02-transactions.md diff --git a/docs/docs/docs/01-core/database/relations/_category_.json b/docs/docs/docs/01-core/database/01-relations/_category_.json similarity index 100% rename from docs/docs/docs/01-core/database/relations/_category_.json rename to docs/docs/docs/01-core/database/01-relations/_category_.json diff --git a/docs/docs/docs/01-core/database/relations/reordering.mdx b/docs/docs/docs/01-core/database/01-relations/reordering.mdx similarity index 100% rename from docs/docs/docs/01-core/database/relations/reordering.mdx rename to docs/docs/docs/01-core/database/01-relations/reordering.mdx diff --git a/docs/docs/docs/01-core/database/02-transactions.md b/docs/docs/docs/01-core/database/02-transactions.md new file mode 100644 index 0000000000..5a3bbbda2d --- /dev/null +++ b/docs/docs/docs/01-core/database/02-transactions.md @@ -0,0 +1,102 @@ +--- +title: Transactions +description: Conceptual guide to transactions in Strapi +tags: + - database +--- + +This provides an API to wrap a set of operations in a transaction that ensures the integrity of data. + +## What are transactions + +Transactions are a set of operations that are executed together as a single unit. If any of the operations fail, the entire transaction fails and the data is rolled back to its previous state. If all operations succeed, the transaction is committed and the data is permanently saved to the database. + +## Usage + +Transactions are handled by passing a handler function into `strapi.db.transaction`: + +```js +await strapi.db.transaction(async ({ trx, rollback, commit, onCommit, onRollback }) => { + // It will implicitly use the transaction + await strapi.entityService.create(); + await strapi.entityService.create(); +}); +``` + +After the transaction handler is executed, the transaction is committed if all operations succeed. If any of the operations throws, the transaction is rolled back and the data is restored to its previous state. + +:::note +Every `strapi.entityService` or `strapi.db.query` operation performed in a transaction block will implicitly use the transaction. +::: + +### Transaction handler properties + +The handler function receives an object with the following properties: + +| Property | Description | +| ------------ | ------------------------------------------------------------------------------------------- | +| `trx` | The transaction object. It can be used to perform knex queries within the transaction. | +| `commit` | Function to commit the transaction. | +| `rollback` | Function to rollback the transaction. | +| `onCommit` | Function to register a callback that will be executed after the transaction is committed. | +| `onRollback` | Function to register a callback that will be executed after the transaction is rolled back. | + +### Nested transactions + +Transactions can be nested. When a transaction is nested, the inner transaction is committed or rolled back when the outer transaction is committed or rolled back. + +```js +await strapi.db.transaction(async () => { + // It will implicitly use the transaction + await strapi.entityService.create(); + + // Nested transactions will implicitly use the outer transaction + await strapi.db.transaction(async ({}) => { + await strapi.entityService.create(); + }); +}); +``` + +### onCommit and onRollback + +The `onCommit` and `onRollback` hooks can be used to execute code after the transaction is committed or rolled back. + +```js +await strapi.db.transaction(async ({ onCommit, onRollback }) => { + // It will implicitly use the transaction + await strapi.entityService.create(); + await strapi.entityService.create(); + + onCommit(() => { + // This will be executed after the transaction is committed + }); + + onRollback(() => { + // This will be executed after the transaction is rolled back + }); +}); +``` + +### Using knex queries + +Transactions can also be used with knex queries. + +```js +await strapi.db.transaction(async ({ trx, rollback, commit }) => { + await knex('users').where('id', 1).update({ name: 'foo' }).transacting(trx); +}); +``` + +## When to use transactions + +Transactions should be used in cases where multiple operations should be executed together and their execution is dependent on each other. For example, when creating a user registration form, the transaction can be used to ensure that data is only committed to the database if all fields are properly filled out and validated. + +## When not to use transactions + +Transactions should not be used for small or simple sets of operations since it can result in performance penalties. + +## Potential problems of transactions + +Performing multiple operations within a transaction can lead to locking, which can block the execution of transactions from other processes until the original transaction is complete. + +Furthermore, transactions can stall if they are not committed or rolled back appropriately. From bff6d9a24a1c9fd9951b747f5fc410c249ab157c Mon Sep 17 00:00:00 2001 From: Marc-Roig Date: Tue, 23 May 2023 12:26:17 +0200 Subject: [PATCH 69/84] doc: rewording --- docs/docs/docs/01-core/database/02-transactions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/docs/01-core/database/02-transactions.md b/docs/docs/docs/01-core/database/02-transactions.md index 5a3bbbda2d..247390ae95 100644 --- a/docs/docs/docs/01-core/database/02-transactions.md +++ b/docs/docs/docs/01-core/database/02-transactions.md @@ -5,7 +5,7 @@ tags: - database --- -This provides an API to wrap a set of operations in a transaction that ensures the integrity of data. +An API to wrap a set of operations in a transaction that ensures the integrity of data. ## What are transactions From 39dae2b701d4f721a6f5f4d462bf241fc4c890e6 Mon Sep 17 00:00:00 2001 From: Marc-Roig Date: Tue, 23 May 2023 12:42:55 +0200 Subject: [PATCH 70/84] doc: update transaction example --- docs/docs/docs/01-core/database/02-transactions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/docs/01-core/database/02-transactions.md b/docs/docs/docs/01-core/database/02-transactions.md index 247390ae95..b5d45bfa16 100644 --- a/docs/docs/docs/01-core/database/02-transactions.md +++ b/docs/docs/docs/01-core/database/02-transactions.md @@ -89,7 +89,7 @@ await strapi.db.transaction(async ({ trx, rollback, commit }) => { ## When to use transactions -Transactions should be used in cases where multiple operations should be executed together and their execution is dependent on each other. For example, when creating a user registration form, the transaction can be used to ensure that data is only committed to the database if all fields are properly filled out and validated. +Transactions should be used in cases where multiple operations should be executed together and their execution is dependent on each other. For example, when creating a new user, the user should be created in the database and a welcome email should be sent to the user. If the email fails to send, the user should not be created in the database. ## When not to use transactions From 7821baed767a931c2e163438a0696fe6e1f27e95 Mon Sep 17 00:00:00 2001 From: Boegie19 Date: Tue, 23 May 2023 12:49:38 +0200 Subject: [PATCH 71/84] remove ignoreKind --- .../core/strapi/lib/services/entity-service/index.js | 2 +- packages/core/utils/lib/sanitize/index.js | 9 +-------- .../i18n/server/services/entity-service-decorator.js | 6 +++++- 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/packages/core/strapi/lib/services/entity-service/index.js b/packages/core/strapi/lib/services/entity-service/index.js index c6997c1872..5de99b7607 100644 --- a/packages/core/strapi/lib/services/entity-service/index.js +++ b/packages/core/strapi/lib/services/entity-service/index.js @@ -82,7 +82,7 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator }) const query = transformParamsToQuery(uid, wrappedParams); - if (kind === 'singleType' && !opts.ignoreKind) { + if (kind === 'singleType') { return db.query(uid).findOne(query); } diff --git a/packages/core/utils/lib/sanitize/index.js b/packages/core/utils/lib/sanitize/index.js index 0b8890aacd..babd4753eb 100644 --- a/packages/core/utils/lib/sanitize/index.js +++ b/packages/core/utils/lib/sanitize/index.js @@ -61,17 +61,10 @@ const createContentAPISanitizers = () => { }; const sanitizeQuery = async (query, schema, { auth } = {}) => { - const { filters, sort, fields, populate, ignoreKind } = query; + const { filters, sort, fields, populate } = query; const sanitizedQuery = cloneDeep(query); - // Some methods behave different if requesting a Content Type or Single Type (entityService findMany) - // In some cases, we want to ignore such behaviour, and we do so by using `ignoreKind` flag. - // This sanitization is here to avoid potential security issues of using `ignoreKind`, specially using decorators & extensions. - if (ignoreKind) { - delete sanitizedQuery.ignoreKind; - } - if (filters) { Object.assign(sanitizedQuery, { filters: await sanitizeFilters(filters, schema, { auth }) }); } diff --git a/packages/plugins/i18n/server/services/entity-service-decorator.js b/packages/plugins/i18n/server/services/entity-service-decorator.js index 3a9aa8db89..e36b2cae63 100644 --- a/packages/plugins/i18n/server/services/entity-service-decorator.js +++ b/packages/plugins/i18n/server/services/entity-service-decorator.js @@ -168,8 +168,12 @@ const decorator = (service) => ({ if (kind === 'singleType') { if (opts[LOCALE_QUERY_FILTER] === 'all') { - return service.findMany.call(this, uid, { ...opts, ignoreKind: true }); + // TODO Fix so this won't break lower lying find many wrappers + const wrappedParams = await this.wrapParams(opts, { uid, action: 'findMany' }); + return strapi.db.query(uid).findMany(wrappedParams); } + + // This one gets transformed into a findOne on a lower layer return service.findMany.call(this, uid, opts); } From 4ffaefcb1845977ab11bc7ac9457c24f157530d8 Mon Sep 17 00:00:00 2001 From: Marc Date: Tue, 23 May 2023 14:01:55 +0200 Subject: [PATCH 72/84] Update docs/docs/docs/01-core/database/02-transactions.md Co-authored-by: Ben Irvin --- docs/docs/docs/01-core/database/02-transactions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/docs/01-core/database/02-transactions.md b/docs/docs/docs/01-core/database/02-transactions.md index b5d45bfa16..2ce2218e4c 100644 --- a/docs/docs/docs/01-core/database/02-transactions.md +++ b/docs/docs/docs/01-core/database/02-transactions.md @@ -79,7 +79,7 @@ await strapi.db.transaction(async ({ onCommit, onRollback }) => { ### Using knex queries -Transactions can also be used with knex queries. +Transactions can also be used with knex queries, but in those cases `.transacting(trx)` must be explicitly called. ```js await strapi.db.transaction(async ({ trx, rollback, commit }) => { From 13c1d0db2c5967d442b5b8088f2a6286c74b4242 Mon Sep 17 00:00:00 2001 From: Marc Date: Tue, 23 May 2023 14:02:02 +0200 Subject: [PATCH 73/84] Update docs/docs/docs/01-core/database/02-transactions.md Co-authored-by: Ben Irvin --- docs/docs/docs/01-core/database/02-transactions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/docs/01-core/database/02-transactions.md b/docs/docs/docs/01-core/database/02-transactions.md index 2ce2218e4c..74d9d320fd 100644 --- a/docs/docs/docs/01-core/database/02-transactions.md +++ b/docs/docs/docs/01-core/database/02-transactions.md @@ -93,7 +93,7 @@ Transactions should be used in cases where multiple operations should be execute ## When not to use transactions -Transactions should not be used for small or simple sets of operations since it can result in performance penalties. +Transactions should not be used for operations that are not dependent on each other since it can result in performance penalties. ## Potential problems of transactions From abfcb0c194c9fcd5fbb059254aef277f4c3feba3 Mon Sep 17 00:00:00 2001 From: Marc Date: Tue, 23 May 2023 14:02:17 +0200 Subject: [PATCH 74/84] Update docs/docs/docs/01-core/database/02-transactions.md Co-authored-by: Ben Irvin --- docs/docs/docs/01-core/database/02-transactions.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/docs/docs/01-core/database/02-transactions.md b/docs/docs/docs/01-core/database/02-transactions.md index 74d9d320fd..c05c474d16 100644 --- a/docs/docs/docs/01-core/database/02-transactions.md +++ b/docs/docs/docs/01-core/database/02-transactions.md @@ -100,3 +100,5 @@ Transactions should not be used for operations that are not dependent on each ot Performing multiple operations within a transaction can lead to locking, which can block the execution of transactions from other processes until the original transaction is complete. Furthermore, transactions can stall if they are not committed or rolled back appropriately. + +For example, if a transaction is opened but there is a path in your code that does not close it, the transaction will be left open indefinitely and could cause instability until your server is restarted and the connection is forced to close. These issues can be difficult to debug, so use transactions with care in the cases they are necessary. From bd7df454c9894c090fb7f45d93b3fe45780d07a3 Mon Sep 17 00:00:00 2001 From: Boegie19 Date: Tue, 23 May 2023 17:57:41 +0200 Subject: [PATCH 75/84] removed default opts --- packages/core/strapi/lib/services/entity-service/index.js | 2 +- .../plugins/i18n/server/services/entity-service-decorator.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/core/strapi/lib/services/entity-service/index.js b/packages/core/strapi/lib/services/entity-service/index.js index 5de99b7607..2cf70b83de 100644 --- a/packages/core/strapi/lib/services/entity-service/index.js +++ b/packages/core/strapi/lib/services/entity-service/index.js @@ -75,7 +75,7 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator }) }); }, - async findMany(uid, opts = {}) { + async findMany(uid, opts) { const { kind } = strapi.getModel(uid); const wrappedParams = await this.wrapParams(opts, { uid, action: 'findMany' }); diff --git a/packages/plugins/i18n/server/services/entity-service-decorator.js b/packages/plugins/i18n/server/services/entity-service-decorator.js index e36b2cae63..8664e6b868 100644 --- a/packages/plugins/i18n/server/services/entity-service-decorator.js +++ b/packages/plugins/i18n/server/services/entity-service-decorator.js @@ -155,7 +155,7 @@ const decorator = (service) => ({ * @param {string} uid - Model uid * @param {object} opts - Query options object (params, data, files, populate) */ - async findMany(uid, opts = {}) { + async findMany(uid, opts) { const model = strapi.getModel(uid); const { isLocalizedContentType } = getService('content-types'); From 958b4cefcc70d7aad4118703d58cfa2ac150e523 Mon Sep 17 00:00:00 2001 From: Boegie19 Date: Thu, 25 May 2023 11:33:18 +0200 Subject: [PATCH 76/84] fix test --- .../server/services/__tests__/entity-service-decorator.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/plugins/i18n/server/services/__tests__/entity-service-decorator.test.js b/packages/plugins/i18n/server/services/__tests__/entity-service-decorator.test.js index 7678d39068..7c1a333187 100644 --- a/packages/plugins/i18n/server/services/__tests__/entity-service-decorator.test.js +++ b/packages/plugins/i18n/server/services/__tests__/entity-service-decorator.test.js @@ -377,7 +377,7 @@ describe('Entity service decorator', () => { await service.findMany('localized-single-type-model', input); expect(global.strapi.getModel).toHaveBeenCalledWith('localized-single-type-model'); - expect(defaultService.findMany).toBeCalled(); + expect(global.strapi.db.query).toBeCalled(); }); test('calls db.findMany for single type with no local param', async () => { From 619823e72f301cd28c51fa63774b765ff52a2d68 Mon Sep 17 00:00:00 2001 From: Marc-Roig Date: Fri, 26 May 2023 14:48:01 +0200 Subject: [PATCH 77/84] doc: transaction is an experimental feature --- docs/docs/docs/01-core/database/02-transactions.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/docs/docs/01-core/database/02-transactions.md b/docs/docs/docs/01-core/database/02-transactions.md index c05c474d16..3ecbd2d146 100644 --- a/docs/docs/docs/01-core/database/02-transactions.md +++ b/docs/docs/docs/01-core/database/02-transactions.md @@ -3,8 +3,13 @@ title: Transactions description: Conceptual guide to transactions in Strapi tags: - database + - experimental --- +:::caution +This is an experimental feature and is subject to change in future versions. +::: + An API to wrap a set of operations in a transaction that ensures the integrity of data. ## What are transactions From 48234303cc84f94e4a6800c81bd7107da1932391 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9Cmarwa-hodeib=E2=80=9D?= Date: Fri, 26 May 2023 21:26:32 +0300 Subject: [PATCH 78/84] fix variable translation --- .../core/admin/admin/src/translations/ar.json | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/core/admin/admin/src/translations/ar.json b/packages/core/admin/admin/src/translations/ar.json index 6e66746ac9..9b653f8325 100644 --- a/packages/core/admin/admin/src/translations/ar.json +++ b/packages/core/admin/admin/src/translations/ar.json @@ -356,7 +356,7 @@ "app.utils.errors.file-too-big.message": "الملف كبير جدًا", "app.utils.filter-value": "قيمة التصفية", "app.utils.filters": "المرشحات", - "app.utils.notify.data-loaded": "{الهدف} تم تحميل", + "app.utils.notify.data-loaded": "{target} تم تحميل", "app.utils.publish": "أصدر", "app.utils.select-all": "اختر الكل", "app.utils.select-field": "حدد المجال", @@ -382,7 +382,7 @@ "Auth.form.password.hide-password": "اخفاء كلمة المرور", "Auth.form.password.hint": "يجب ألا يقل عدد الأحرف عن 8 أحرف ، وحرف كبير واحد ، ورقم واحد صغير ، ورقم واحد", "Auth.form.password.show-password": "عرض كلمة المرور", - "Auth.form.register.news.label": "ابقني على اطلاع بالميزات الجديدة والتحسينات القادمة (من خلال القيام بذلك فأنت تقبل {شروط} و ال {بوليصة}).", + "Auth.form.register.news.label": "ابقني على اطلاع بالميزات الجديدة والتحسينات القادمة (من خلال القيام بذلك فأنت تقبل {terms} و ال {policy}).", "Auth.form.register.subtitle": "تُستخدم بيانات الاعتماد فقط للمصادقة في Strapi. سيتم تخزين جميع البيانات المحفوظة في قاعدة البيانات الخاصة بك.", "Auth.form.welcome.subtitle": "Strapi قم بتسجيل الدخول إلى حسابك على", "Auth.form.welcome.title": "Strapi! مرحبا بك في", @@ -442,7 +442,7 @@ "content-manager.components.DynamicZone.ComponentPicker-label": "اختر مكونًا واحدًا", "content-manager.components.DynamicZone.delete-label": "{name} حذف", "content-manager.components.DynamicZone.error-message": "يحتوي المكون على خطأ (أخطاء)", - "content-manager.components.DynamicZone.missing-components": "There {number, plural, =0 {are # missing components} one {is # missing component} other {are # missing components}}", + "content-manager.components.DynamicZone.missing-components": "There {number, plural, =0 {are # missing components} واحد {is # missing component} آخر {are # missing components}}", "content-manager.components.DynamicZone.move-down-label": "انقل المكون لأسفل", "content-manager.components.DynamicZone.move-up-label": "انقل المكون لأعلى", "content-manager.components.DynamicZone.pick-compo": "اختر مكونًا واحدًا", @@ -465,7 +465,7 @@ "content-manager.components.SettingsViewWrapper.pluginHeader.description.edit-settings": "تخصيص كيف سيبدو عرض التحرير.", "content-manager.components.SettingsViewWrapper.pluginHeader.description.list-settings": "حدد إعدادات عرض القائمة.", "content-manager.components.SettingsViewWrapper.pluginHeader.title": "{name} تكوين العرض -", - "content-manager.components.TableDelete.label": "{number, plural, one {# entry} other {# entries}} selected", + "content-manager.components.TableDelete.label": "{number, plural, one {# entry} آخر {# entries}} selected", "content-manager.components.uid.apply": "طبق", "content-manager.components.uid.available": "متاح", "content-manager.components.uid.regenerate": "تجديد", @@ -542,7 +542,7 @@ "content-manager.permissions.not-allowed.update": "لا يسمح لك أن ترى هذه الوثيقة", "content-manager.popover.display-relations.label": "عرض العلاقات", "content-manager.popUpwarning.warning.has-draft-relations.button-confirm": "نعم ، انشر", - "content-manager.popUpwarning.warning.has-draft-relations.message": "{count, plural, one { relation is } other { relations are } } not published yet and might lead to unexpected behavior.", + "content-manager.popUpwarning.warning.has-draft-relations.message": "{count, plural, one { relation is } آخر { relations are } } لم تنشر بعد وقد تؤدي إلى سلوك غير متوقع.", "content-manager.popUpWarning.warning.has-draft-relations.title": "تأكيد", "content-manager.popUpWarning.warning.publish-question": "هل مازلت تريد النشر؟", "content-manager.popUpWarning.warning.unpublish": "إذا لم تنشر هذا المحتوى ، فسيتحول تلقائيًا إلى مسودة.", @@ -641,7 +641,7 @@ "notification.warning.title": "تحذير:", "or": "أو", "Roles & Permissions": "الأدوار والأذونات", - "Roles.components.List.empty.withSearch": "لا يوجد دور مطابق للبحث ({بحث}) ...", + "Roles.components.List.empty.withSearch": "لا يوجد دور مطابق للبحث ({search}) ...", "Roles.ListPage.notification.delete-all-not-allowed": "تعذر حذف بعض الأدوار لأنها مرتبطة بالمستخدمين", "Roles.ListPage.notification.delete-not-allowed": "لا يمكن حذف الدور إذا كان مرتبطًا بالمستخدمين", "Roles.RoleRow.select-all": "حدد {name} للإجراءات المجمعة", @@ -667,7 +667,7 @@ "Settings.apiTokens.title": "رموز API", "Settings.application.customization": "التخصيص", "Settings.application.customization.auth-logo.carousel-hint": "استبدل الشعار في صفحات المصادقة", - "Settings.application.customization.carousel-hint": "تغيير شعار لوحة الإدارة (الحد الأقصى للبعد: {البعد} × {البعد} ، الحد الأقصى لحجم الملف: {الحجم} كيلوبايت)", + "Settings.application.customization.carousel-hint": "تغيير شعار لوحة الإدارة (الحد الأقصى للبعد: {dimension} {dimension} ، الحد الأقصى لحجم الملف: {size} كيلوبايت)", "Settings.application.customization.carousel-slide.label": "شريحة الشعار", "Settings.application.customization.carousel.auth-logo.title": "شعار Auth", "Settings.application.customization.carousel.change-action": "تغيير الشعار", @@ -688,13 +688,13 @@ "Settings.application.customization.modal.upload.drag-drop": "قم بالسحب والإفلات هنا أو", "Settings.application.customization.modal.upload.error-format": "تم تحميل تنسيق خاطئ (التنسيقات المقبولة فقط: jpeg ، jpg ، png ، svg).", "Settings.application.customization.modal.upload.error-network": "خطأ في الشبكة", - "Settings.application.customization.modal.upload.error-size": "الملف الذي تم تحميله كبير جدًا (الحد الأقصى للبعد: {البعد} x {البعد} ، الحد الأقصى لحجم الملف: {الحجم} كيلوبايت)", - "Settings.application.customization.modal.upload.file-validation": "أقصى بُعد: {البعد} × {البعد} ، الحد الأقصى للحجم: {الحجم} كيلوبايت", + "Settings.application.customization.modal.upload.error-size": "الملف الذي تم تحميله كبير جدًا (الحد الأقصى للبعد: {dimension} x {dimension} ، الحد الأقصى لحجم الملف: {size} كيلوبايت)", + "Settings.application.customization.modal.upload.file-validation": "أقصى بُعد: {dimension} x {dimension} ، الحد الأقصى للحجم: {size} كيلوبايت", "Settings.application.customization.modal.upload.from-computer": "من الكمبيوتر", "Settings.application.customization.modal.upload.from-url": "من URL", "Settings.application.customization.modal.upload.from-url.input-label": "URL", "Settings.application.customization.modal.upload.next": "التالي", - "Settings.application.customization.size-details": "أقصى بُعد: {البعد} x {البعد} ، الحد الأقصى لحجم الملف: {الحجم} كيلوبايت", + "Settings.application.customization.size-details": "أقصى بُعد: {dimension} x {dimension} ، الحد الأقصى لحجم الملف: {size} كيلوبايت", "Settings.application.description": "المعلومات العالمية للوحة الإدارة", "Settings.application.edition-title": "الخطة الحالية", "Settings.application.ee-or-ce": "{communityEdition، select، true {Community Edition} أخرى {Enterprise Edition}}", From 839e57fa449aa5f7f89cc95f75b375fb02f23757 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 28 May 2023 23:01:14 +0000 Subject: [PATCH 79/84] chore(deps): bump axios from 1.3.4 to 1.4.0 Bumps [axios](https://github.com/axios/axios) from 1.3.4 to 1.4.0. - [Release notes](https://github.com/axios/axios/releases) - [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md) - [Commits](https://github.com/axios/axios/compare/v1.3.4...v1.4.0) --- updated-dependencies: - dependency-name: axios dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- packages/core/admin/package.json | 2 +- packages/core/helper-plugin/package.json | 2 +- packages/core/upload/package.json | 2 +- yarn.lock | 25 +++++++++++++++++------- 4 files changed, 21 insertions(+), 10 deletions(-) diff --git a/packages/core/admin/package.json b/packages/core/admin/package.json index 7644c8f50f..ab99cb67d9 100644 --- a/packages/core/admin/package.json +++ b/packages/core/admin/package.json @@ -57,7 +57,7 @@ "@strapi/provider-audit-logs-local": "4.10.6", "@strapi/typescript-utils": "4.10.6", "@strapi/utils": "4.10.6", - "axios": "1.3.4", + "axios": "1.4.0", "babel-loader": "^9.1.2", "babel-plugin-styled-components": "2.1.1", "bcryptjs": "2.4.3", diff --git a/packages/core/helper-plugin/package.json b/packages/core/helper-plugin/package.json index 9e2e23cf69..0a50e6bc16 100644 --- a/packages/core/helper-plugin/package.json +++ b/packages/core/helper-plugin/package.json @@ -44,7 +44,7 @@ "lint": "run -T eslint ." }, "dependencies": { - "axios": "1.3.4", + "axios": "1.4.0", "date-fns": "2.30.0", "formik": "^2.2.6", "immer": "9.0.19", diff --git a/packages/core/upload/package.json b/packages/core/upload/package.json index 474fe06b5b..d0abc4119c 100644 --- a/packages/core/upload/package.json +++ b/packages/core/upload/package.json @@ -30,7 +30,7 @@ "@strapi/icons": "1.7.9", "@strapi/provider-upload-local": "4.10.6", "@strapi/utils": "4.10.6", - "axios": "1.3.4", + "axios": "1.4.0", "byte-size": "7.0.1", "cropperjs": "1.5.12", "date-fns": "2.30.0", diff --git a/yarn.lock b/yarn.lock index 719d056e6a..54a1f8300c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7769,7 +7769,7 @@ __metadata: "@testing-library/react": 12.1.4 "@testing-library/react-hooks": 8.0.1 "@testing-library/user-event": 14.4.3 - axios: 1.3.4 + axios: 1.4.0 babel-loader: ^9.1.2 babel-plugin-styled-components: 2.1.1 bcryptjs: 2.4.3 @@ -8028,7 +8028,7 @@ __metadata: "@testing-library/react": 12.1.4 "@testing-library/react-hooks": 8.0.1 "@testing-library/user-event": 14.4.3 - axios: 1.3.4 + axios: 1.4.0 browserslist-to-esbuild: 1.2.0 cross-env: ^7.0.3 date-fns: 2.30.0 @@ -8347,7 +8347,7 @@ __metadata: "@testing-library/react": 12.1.4 "@testing-library/react-hooks": 8.0.1 "@testing-library/user-event": 14.4.3 - axios: 1.3.4 + axios: 1.4.0 byte-size: 7.0.1 cropperjs: 1.5.12 date-fns: 2.30.0 @@ -12021,14 +12021,14 @@ __metadata: languageName: node linkType: hard -"axios@npm:1.3.4, axios@npm:^1.0.0": - version: 1.3.4 - resolution: "axios@npm:1.3.4" +"axios@npm:1.4.0": + version: 1.4.0 + resolution: "axios@npm:1.4.0" dependencies: follow-redirects: ^1.15.0 form-data: ^4.0.0 proxy-from-env: ^1.1.0 - checksum: 7440edefcf8498bc3cdf39de00443e8101f249972c83b739c6e880d9d669fea9486372dbe8739e88b3bf8bb1ad15f6106693f206f078f4516fe8fd47b1c3093c + checksum: 7fb6a4313bae7f45e89d62c70a800913c303df653f19eafec88e56cea2e3821066b8409bc68be1930ecca80e861c52aa787659df0ffec6ad4d451c7816b9386b languageName: node linkType: hard @@ -12041,6 +12041,17 @@ __metadata: languageName: node linkType: hard +"axios@npm:^1.0.0": + version: 1.3.4 + resolution: "axios@npm:1.3.4" + dependencies: + follow-redirects: ^1.15.0 + form-data: ^4.0.0 + proxy-from-env: ^1.1.0 + checksum: 7440edefcf8498bc3cdf39de00443e8101f249972c83b739c6e880d9d669fea9486372dbe8739e88b3bf8bb1ad15f6106693f206f078f4516fe8fd47b1c3093c + languageName: node + linkType: hard + "axios@npm:^1.3.3": version: 1.3.5 resolution: "axios@npm:1.3.5" From 595f2ec00ff84b2b1757073db7dca31dd605da0a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 28 May 2023 23:02:26 +0000 Subject: [PATCH 80/84] chore(deps-dev): bump @testing-library/dom from 8.19.0 to 8.20.0 Bumps [@testing-library/dom](https://github.com/testing-library/dom-testing-library) from 8.19.0 to 8.20.0. - [Release notes](https://github.com/testing-library/dom-testing-library/releases) - [Changelog](https://github.com/testing-library/dom-testing-library/blob/main/CHANGELOG.md) - [Commits](https://github.com/testing-library/dom-testing-library/compare/v8.19.0...v8.20.0) --- updated-dependencies: - dependency-name: "@testing-library/dom" dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- packages/core/admin/package.json | 2 +- packages/core/upload/package.json | 2 +- .../plugins/users-permissions/package.json | 2 +- yarn.lock | 23 ++++++++++++------- 4 files changed, 18 insertions(+), 11 deletions(-) diff --git a/packages/core/admin/package.json b/packages/core/admin/package.json index 7644c8f50f..c9445f4449 100644 --- a/packages/core/admin/package.json +++ b/packages/core/admin/package.json @@ -139,7 +139,7 @@ "yup": "^0.32.9" }, "devDependencies": { - "@testing-library/dom": "8.19.0", + "@testing-library/dom": "8.20.0", "@testing-library/react": "12.1.4", "@testing-library/react-hooks": "8.0.1", "@testing-library/user-event": "14.4.3", diff --git a/packages/core/upload/package.json b/packages/core/upload/package.json index 474fe06b5b..2dab0fb8d0 100644 --- a/packages/core/upload/package.json +++ b/packages/core/upload/package.json @@ -53,7 +53,7 @@ "yup": "^0.32.9" }, "devDependencies": { - "@testing-library/dom": "8.19.0", + "@testing-library/dom": "8.20.0", "@testing-library/react": "12.1.4", "@testing-library/react-hooks": "8.0.1", "@testing-library/user-event": "14.4.3", diff --git a/packages/plugins/users-permissions/package.json b/packages/plugins/users-permissions/package.json index d6ddfdc37e..9b082d116c 100644 --- a/packages/plugins/users-permissions/package.json +++ b/packages/plugins/users-permissions/package.json @@ -51,7 +51,7 @@ "yup": "^0.32.9" }, "devDependencies": { - "@testing-library/dom": "8.19.0", + "@testing-library/dom": "8.20.0", "@testing-library/react": "12.1.4", "@testing-library/react-hooks": "8.0.1", "@testing-library/user-event": "14.4.3", diff --git a/yarn.lock b/yarn.lock index 719d056e6a..a356568689 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7765,7 +7765,7 @@ __metadata: "@strapi/provider-audit-logs-local": 4.10.6 "@strapi/typescript-utils": 4.10.6 "@strapi/utils": 4.10.6 - "@testing-library/dom": 8.19.0 + "@testing-library/dom": 8.20.0 "@testing-library/react": 12.1.4 "@testing-library/react-hooks": 8.0.1 "@testing-library/user-event": 14.4.3 @@ -8343,7 +8343,7 @@ __metadata: "@strapi/icons": 1.7.9 "@strapi/provider-upload-local": 4.10.6 "@strapi/utils": 4.10.6 - "@testing-library/dom": 8.19.0 + "@testing-library/dom": 8.20.0 "@testing-library/react": 12.1.4 "@testing-library/react-hooks": 8.0.1 "@testing-library/user-event": 14.4.3 @@ -8389,7 +8389,7 @@ __metadata: "@strapi/helper-plugin": 4.10.6 "@strapi/icons": 1.7.9 "@strapi/utils": 4.10.6 - "@testing-library/dom": 8.19.0 + "@testing-library/dom": 8.20.0 "@testing-library/react": 12.1.4 "@testing-library/react-hooks": 8.0.1 "@testing-library/user-event": 14.4.3 @@ -8853,19 +8853,19 @@ __metadata: languageName: node linkType: hard -"@testing-library/dom@npm:8.19.0": - version: 8.19.0 - resolution: "@testing-library/dom@npm:8.19.0" +"@testing-library/dom@npm:8.20.0": + version: 8.20.0 + resolution: "@testing-library/dom@npm:8.20.0" dependencies: "@babel/code-frame": ^7.10.4 "@babel/runtime": ^7.12.5 - "@types/aria-query": ^4.2.0 + "@types/aria-query": ^5.0.1 aria-query: ^5.0.0 chalk: ^4.1.0 dom-accessibility-api: ^0.5.9 lz-string: ^1.4.4 pretty-format: ^27.0.2 - checksum: 6bb93fef96703b6c47cf1b7cc8f71d402a9576084a94ba4e9926f51bd7bb1287fbb4f6942d82bd03fc6f3d998ae97e60f6aea4618f3a1ce6139597d2a4ecb7b9 + checksum: 1e599129a2fe91959ce80900a0a4897232b89e2a8e22c1f5950c36d39c97629ea86b4986b60b173b5525a05de33fde1e35836ea597b03de78cc51b122835c6f0 languageName: node linkType: hard @@ -8998,6 +8998,13 @@ __metadata: languageName: node linkType: hard +"@types/aria-query@npm:^5.0.1": + version: 5.0.1 + resolution: "@types/aria-query@npm:5.0.1" + checksum: 69fd7cceb6113ed370591aef04b3fd0742e9a1b06dd045c43531448847b85de181495e4566f98e776b37c422a12fd71866e0a1dfd904c5ec3f84d271682901de + languageName: node + linkType: hard + "@types/babel__core@npm:^7.1.14": version: 7.1.19 resolution: "@types/babel__core@npm:7.1.19" From 71902a4f5c6d373bb39e574f44509b9dcf7300b5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 28 May 2023 23:03:37 +0000 Subject: [PATCH 81/84] chore(deps): bump react-query from 3.24.3 to 3.39.3 Bumps [react-query](https://github.com/tannerlinsley/react-query) from 3.24.3 to 3.39.3. - [Release notes](https://github.com/tannerlinsley/react-query/releases) - [Commits](https://github.com/tannerlinsley/react-query/commits) --- updated-dependencies: - dependency-name: react-query dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- packages/core/admin/package.json | 2 +- packages/core/upload/package.json | 2 +- packages/plugins/documentation/package.json | 2 +- packages/plugins/i18n/package.json | 2 +- .../plugins/users-permissions/package.json | 2 +- yarn.lock | 20 +++++++++---------- 6 files changed, 15 insertions(+), 15 deletions(-) diff --git a/packages/core/admin/package.json b/packages/core/admin/package.json index 7644c8f50f..6b081dd7cf 100644 --- a/packages/core/admin/package.json +++ b/packages/core/admin/package.json @@ -117,7 +117,7 @@ "react-helmet": "^6.1.0", "react-intl": "6.4.1", "react-is": "^17.0.2", - "react-query": "3.24.3", + "react-query": "3.39.3", "react-redux": "8.0.5", "react-refresh": "0.14.0", "react-router-dom": "5.3.4", diff --git a/packages/core/upload/package.json b/packages/core/upload/package.json index 474fe06b5b..bdf0d9531f 100644 --- a/packages/core/upload/package.json +++ b/packages/core/upload/package.json @@ -46,7 +46,7 @@ "react-dnd": "15.1.2", "react-helmet": "^6.1.0", "react-intl": "6.4.1", - "react-query": "3.24.3", + "react-query": "3.39.3", "react-redux": "8.0.5", "react-select": "5.7.0", "sharp": "0.32.0", diff --git a/packages/plugins/documentation/package.json b/packages/plugins/documentation/package.json index fe346737f6..f3cbcee06b 100644 --- a/packages/plugins/documentation/package.json +++ b/packages/plugins/documentation/package.json @@ -45,7 +45,7 @@ "pluralize": "8.0.0", "react-helmet": "^6.1.0", "react-intl": "6.4.1", - "react-query": "3.24.3", + "react-query": "3.39.3", "react-redux": "8.0.5", "redux": "^4.2.1", "reselect": "^4.1.7", diff --git a/packages/plugins/i18n/package.json b/packages/plugins/i18n/package.json index 8c064e7378..12b117cc13 100644 --- a/packages/plugins/i18n/package.json +++ b/packages/plugins/i18n/package.json @@ -40,7 +40,7 @@ "prop-types": "^15.7.2", "qs": "6.11.1", "react-intl": "6.4.1", - "react-query": "3.24.3", + "react-query": "3.39.3", "react-redux": "8.0.5", "redux": "^4.2.1", "yup": "^0.32.9" diff --git a/packages/plugins/users-permissions/package.json b/packages/plugins/users-permissions/package.json index d6ddfdc37e..c29bb63eec 100644 --- a/packages/plugins/users-permissions/package.json +++ b/packages/plugins/users-permissions/package.json @@ -45,7 +45,7 @@ "prop-types": "^15.7.2", "purest": "4.0.2", "react-intl": "6.4.1", - "react-query": "3.24.3", + "react-query": "3.39.3", "react-redux": "8.0.5", "url-join": "4.0.1", "yup": "^0.32.9" diff --git a/yarn.lock b/yarn.lock index 719d056e6a..6976cbf0c8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7832,7 +7832,7 @@ __metadata: react-helmet: ^6.1.0 react-intl: 6.4.1 react-is: ^17.0.2 - react-query: 3.24.3 + react-query: 3.39.3 react-redux: 8.0.5 react-refresh: 0.14.0 react-router-dom: 5.3.4 @@ -8199,7 +8199,7 @@ __metadata: react-dom: ^17.0.2 react-helmet: ^6.1.0 react-intl: 6.4.1 - react-query: 3.24.3 + react-query: 3.39.3 react-redux: 8.0.5 react-router-dom: 5.3.4 redux: ^4.2.1 @@ -8299,7 +8299,7 @@ __metadata: react: ^17.0.2 react-dom: ^17.0.2 react-intl: 6.4.1 - react-query: 3.24.3 + react-query: 3.39.3 react-redux: 8.0.5 react-router-dom: 5.3.4 redux: ^4.2.1 @@ -8366,7 +8366,7 @@ __metadata: react-dom: ^17.0.2 react-helmet: ^6.1.0 react-intl: 6.4.1 - react-query: 3.24.3 + react-query: 3.39.3 react-redux: 8.0.5 react-router-dom: 5.3.4 react-select: 5.7.0 @@ -8409,7 +8409,7 @@ __metadata: react: ^17.0.2 react-dom: ^17.0.2 react-intl: 6.4.1 - react-query: 3.24.3 + react-query: 3.39.3 react-redux: 8.0.5 react-router-dom: 5.3.4 styled-components: 5.3.3 @@ -28065,21 +28065,21 @@ __metadata: languageName: node linkType: hard -"react-query@npm:3.24.3": - version: 3.24.3 - resolution: "react-query@npm:3.24.3" +"react-query@npm:3.39.3": + version: 3.39.3 + resolution: "react-query@npm:3.39.3" dependencies: "@babel/runtime": ^7.5.5 broadcast-channel: ^3.4.1 match-sorter: ^6.0.2 peerDependencies: - react: ^16.8.0 || ^17.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 peerDependenciesMeta: react-dom: optional: true react-native: optional: true - checksum: 0b86a33b860c092d36e269db1331afbf0df5b720ea746c9093cd8241204a076ff404affb8b4dae08904e3714545d4bd8920babe2a6e5ee9660d94bbcdbeb8072 + checksum: d2de6a0992dbf039ff2de564de1ae6361f8ac7310159dae42ec16f833b79c05caedced187235c42373ac331cc5f2fe9e2b31b14ae75a815e86d86e30ca9887ad languageName: node linkType: hard From 1c5f857faaa091161e4bf07efee22f0525843d10 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 28 May 2023 23:04:50 +0000 Subject: [PATCH 82/84] chore(deps): bump formik from 2.2.9 to 2.4.0 Bumps [formik](https://github.com/formium/formik) from 2.2.9 to 2.4.0. - [Release notes](https://github.com/formium/formik/releases) - [Commits](https://github.com/formium/formik/compare/formik@2.2.9...formik@2.4.0) --- updated-dependencies: - dependency-name: formik dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- packages/core/admin/package.json | 2 +- packages/core/helper-plugin/package.json | 2 +- packages/core/upload/package.json | 2 +- packages/plugins/documentation/package.json | 2 +- packages/plugins/i18n/package.json | 2 +- .../plugins/users-permissions/package.json | 2 +- yarn.lock | 20 +++++++++---------- 7 files changed, 16 insertions(+), 16 deletions(-) diff --git a/packages/core/admin/package.json b/packages/core/admin/package.json index 7644c8f50f..407fff8316 100644 --- a/packages/core/admin/package.json +++ b/packages/core/admin/package.json @@ -75,7 +75,7 @@ "fast-deep-equal": "3.1.3", "find-root": "1.1.0", "fork-ts-checker-webpack-plugin": "7.3.0", - "formik": "^2.2.6", + "formik": "^2.4.0", "fractional-indexing": "3.2.0", "fs-extra": "10.0.0", "highlight.js": "^10.4.1", diff --git a/packages/core/helper-plugin/package.json b/packages/core/helper-plugin/package.json index 9e2e23cf69..a687a4e0fd 100644 --- a/packages/core/helper-plugin/package.json +++ b/packages/core/helper-plugin/package.json @@ -46,7 +46,7 @@ "dependencies": { "axios": "1.3.4", "date-fns": "2.30.0", - "formik": "^2.2.6", + "formik": "^2.4.0", "immer": "9.0.19", "lodash": "4.17.21", "prop-types": "^15.7.2", diff --git a/packages/core/upload/package.json b/packages/core/upload/package.json index 474fe06b5b..c5b14118df 100644 --- a/packages/core/upload/package.json +++ b/packages/core/upload/package.json @@ -34,7 +34,7 @@ "byte-size": "7.0.1", "cropperjs": "1.5.12", "date-fns": "2.30.0", - "formik": "2.2.9", + "formik": "2.4.0", "fs-extra": "10.0.0", "immer": "9.0.19", "koa-range": "0.3.0", diff --git a/packages/plugins/documentation/package.json b/packages/plugins/documentation/package.json index fe346737f6..983fda8d51 100644 --- a/packages/plugins/documentation/package.json +++ b/packages/plugins/documentation/package.json @@ -36,7 +36,7 @@ "@strapi/utils": "4.10.6", "bcryptjs": "2.4.3", "cheerio": "^1.0.0-rc.12", - "formik": "2.2.9", + "formik": "2.4.0", "fs-extra": "10.0.0", "immer": "9.0.19", "koa-static": "^5.0.0", diff --git a/packages/plugins/i18n/package.json b/packages/plugins/i18n/package.json index 8c064e7378..28c7888510 100644 --- a/packages/plugins/i18n/package.json +++ b/packages/plugins/i18n/package.json @@ -34,7 +34,7 @@ "@strapi/helper-plugin": "4.10.6", "@strapi/icons": "1.7.9", "@strapi/utils": "4.10.6", - "formik": "2.2.9", + "formik": "2.4.0", "immer": "9.0.19", "lodash": "4.17.21", "prop-types": "^15.7.2", diff --git a/packages/plugins/users-permissions/package.json b/packages/plugins/users-permissions/package.json index d6ddfdc37e..5289ef0fe2 100644 --- a/packages/plugins/users-permissions/package.json +++ b/packages/plugins/users-permissions/package.json @@ -34,7 +34,7 @@ "@strapi/icons": "1.7.9", "@strapi/utils": "4.10.6", "bcryptjs": "2.4.3", - "formik": "2.2.9", + "formik": "2.4.0", "grant-koa": "5.4.8", "immer": "9.0.19", "jsonwebtoken": "9.0.0", diff --git a/yarn.lock b/yarn.lock index 719d056e6a..f2454a7ac2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7788,7 +7788,7 @@ __metadata: fast-deep-equal: 3.1.3 find-root: 1.1.0 fork-ts-checker-webpack-plugin: 7.3.0 - formik: ^2.2.6 + formik: ^2.4.0 fractional-indexing: 3.2.0 fs-extra: 10.0.0 glob: 8.0.3 @@ -8033,7 +8033,7 @@ __metadata: cross-env: ^7.0.3 date-fns: 2.30.0 esbuild-loader: ^2.21.0 - formik: ^2.2.6 + formik: ^2.4.0 history: ^4.9.0 immer: 9.0.19 lodash: 4.17.21 @@ -8186,7 +8186,7 @@ __metadata: "@testing-library/react": 12.1.4 bcryptjs: 2.4.3 cheerio: ^1.0.0-rc.12 - formik: 2.2.9 + formik: 2.4.0 fs-extra: 10.0.0 history: ^4.9.0 immer: 9.0.19 @@ -8290,7 +8290,7 @@ __metadata: "@strapi/icons": 1.7.9 "@strapi/utils": 4.10.6 "@testing-library/react": 12.1.4 - formik: 2.2.9 + formik: 2.4.0 immer: 9.0.19 lodash: 4.17.21 msw: 1.2.1 @@ -8351,7 +8351,7 @@ __metadata: byte-size: 7.0.1 cropperjs: 1.5.12 date-fns: 2.30.0 - formik: 2.2.9 + formik: 2.4.0 fs-extra: 10.0.0 immer: 9.0.19 koa-range: 0.3.0 @@ -8394,7 +8394,7 @@ __metadata: "@testing-library/react-hooks": 8.0.1 "@testing-library/user-event": 14.4.3 bcryptjs: 2.4.3 - formik: 2.2.9 + formik: 2.4.0 grant-koa: 5.4.8 history: ^4.9.0 immer: 9.0.19 @@ -18027,9 +18027,9 @@ __metadata: languageName: node linkType: hard -"formik@npm:2.2.9, formik@npm:^2.2.6": - version: 2.2.9 - resolution: "formik@npm:2.2.9" +"formik@npm:2.4.0, formik@npm:^2.4.0": + version: 2.4.0 + resolution: "formik@npm:2.4.0" dependencies: deepmerge: ^2.1.1 hoist-non-react-statics: ^3.3.0 @@ -18040,7 +18040,7 @@ __metadata: tslib: ^1.10.0 peerDependencies: react: ">=16.8.0" - checksum: f07f80eee8423b4c5560546c48c4093c47530dae7d931a4e0d947d68ae1aab94291b1bf2e99ecaa5854ee50593b415fb5724c624c787338f0577f066009e8812 + checksum: 54ada391af4e59f6439ac3492f66fbe562523de585b47b7169964d7f32b2ed03d8bfe485e7a14bd69ae5e76a77aa8cebd950a7a64822b77822a43b7801096ac2 languageName: node linkType: hard From fd7a5c7a999d5f22edb76033e0ae6768a2547699 Mon Sep 17 00:00:00 2001 From: Gustav Hansen Date: Tue, 30 May 2023 10:03:47 +0200 Subject: [PATCH 83/84] Chore: Notification - Add missing translation --- packages/core/admin/admin/src/translations/en.json | 1 + packages/core/helper-plugin/src/features/Notifications.js | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/core/admin/admin/src/translations/en.json b/packages/core/admin/admin/src/translations/en.json index efcec6be4c..b7698b8d9a 100644 --- a/packages/core/admin/admin/src/translations/en.json +++ b/packages/core/admin/admin/src/translations/en.json @@ -826,6 +826,7 @@ "global.back": "Back", "global.cancel": "Cancel", "global.change-password": "Change password", + "global.close": "Close", "global.content-manager": "Content Manager", "global.continue": "Continue", "global.delete": "Delete", diff --git a/packages/core/helper-plugin/src/features/Notifications.js b/packages/core/helper-plugin/src/features/Notifications.js index 2bee5a8af4..73285922b1 100644 --- a/packages/core/helper-plugin/src/features/Notifications.js +++ b/packages/core/helper-plugin/src/features/Notifications.js @@ -211,7 +211,10 @@ const Notification = ({ ) : undefined } onClose={handleClose} - closeLabel="Close" + closeLabel={formatMessage({ + id: 'global.close', + defaultMessage: 'Close', + })} title={alertTitle} variant={variant} > From 8259d9836d3bcc44928735692cbce5d47b4591fa Mon Sep 17 00:00:00 2001 From: Gustav Hansen Date: Tue, 30 May 2023 10:23:18 +0200 Subject: [PATCH 84/84] Chore: Remove stray console log --- .../admin/admin/src/hooks/useContentTypes/useContentTypes.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/core/admin/admin/src/hooks/useContentTypes/useContentTypes.js b/packages/core/admin/admin/src/hooks/useContentTypes/useContentTypes.js index c39607e027..52ba5fe4fb 100644 --- a/packages/core/admin/admin/src/hooks/useContentTypes/useContentTypes.js +++ b/packages/core/admin/admin/src/hooks/useContentTypes/useContentTypes.js @@ -2,8 +2,6 @@ import { useAPIErrorHandler, useFetchClient, useNotification } from '@strapi/hel import { useQueries } from 'react-query'; export function useContentTypes() { - console.log('----> read'); - const { get } = useFetchClient(); const { formatAPIError } = useAPIErrorHandler(); const toggleNotification = useNotification();