fix: cm relation bugs (#19842)

* fix: relations

* fix: hardcode english locale

* fix(cm): don't try and be clever with caching relations

* fix: locale when target is not localized

---------

Co-authored-by: Josh <37798644+joshuaellis@users.noreply.github.com>
This commit is contained in:
Marc Roig 2024-03-19 14:57:36 +01:00 committed by GitHub
parent 49e84a90ad
commit 66c1011328
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 82 additions and 67 deletions

View File

@ -61,10 +61,7 @@ const documentApi = contentManagerApi.injectEndpoints({
}),
invalidatesTags: (result, _error, { model }) => [
{ type: 'Document', id: `${model}_LIST` },
{
type: 'Relations',
id: `${model}_${result?.data.documentId}`,
},
'Relations',
],
}),
deleteDocument: builder.mutation<
@ -127,10 +124,7 @@ const documentApi = contentManagerApi.injectEndpoints({
id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model,
},
{ type: 'Document', id: `${model}_LIST` },
{
type: 'Relations',
id: `${model}_${documentId}`,
},
'Relations',
];
},
}),
@ -278,10 +272,7 @@ const documentApi = contentManagerApi.injectEndpoints({
id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model,
},
{ type: 'Document', id: `${model}_LIST` },
{
type: 'Relations',
id: `${model}_${documentId}`,
},
'Relations',
];
},
}),
@ -321,10 +312,7 @@ const documentApi = contentManagerApi.injectEndpoints({
type: 'Document',
id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model,
},
{
type: 'Relations',
id: `${model}_${documentId}`,
},
'Relations',
];
},
}),

View File

@ -97,9 +97,7 @@ const relationsApi = contentManagerApi.injectEndpoints({
return response;
}
},
providesTags: (result, error, args) => [
{ type: 'Relations', id: `${args.model}_${args.id}` },
],
providesTags: ['Relations'],
}),
searchRelations: build.query<
Contracts.Relations.FindAvailable.Response,

View File

@ -78,42 +78,66 @@ const addStatusToRelations = async (uid: Common.UID.ContentType, relations: Rela
});
};
const getPublishedAtClause = (
status: Documents.Params.PublicationStatus.Kind,
sourceUid: Common.UID.Schema,
targetUid: Common.UID.ContentType
) => {
const sourceModel = strapi.getModel(sourceUid);
const targetModel = strapi.getModel(targetUid);
const getPublishedAtClause = (status: string, uid: Common.UID.Schema) => {
const model = strapi.getModel(uid);
/**
* If target does not have dp, status should be published.
* As it only contains entries with publishedAt set.
* If dp is disabled, ignore the filter
*/
if (!contentTypes.hasDraftAndPublish(targetModel)) {
if (!model || !contentTypes.hasDraftAndPublish(model)) {
return {};
}
/**
* If source does not have dp, status should be draft.
* Both draft and publish entries are connectable, but we are doing it like
* this atm.
*/
if (!contentTypes.hasDraftAndPublish(sourceModel)) {
return { $null: true };
}
// Prioritize the draft status in case it's not provided
return status === 'published' ? { $notNull: true } : { $null: true };
};
export default {
async extractAndValidateRequestInfo(
ctx: any,
id?: Entity.ID,
locale?: Documents.Params.Locale,
const validateLocale = (
sourceUid: Common.UID.Schema,
targetUid: Common.UID.ContentType,
locale?: string
) => {
const sourceModel = strapi.getModel(sourceUid);
const targetModel = strapi.getModel(targetUid);
const isLocalized = strapi.plugin('i18n').service('content-types').isLocalizedContentType;
const isSourceLocalized = isLocalized(sourceModel);
const isTargetLocalized = isLocalized(targetModel);
let validatedLocale = locale;
if (!targetModel || !isTargetLocalized) validatedLocale = undefined;
return {
locale: validatedLocale,
isSourceLocalized,
isTargetLocalized,
};
};
const validateStatus = (
sourceUid: Common.UID.Schema,
status?: Documents.Params.PublicationStatus.Kind
) {
) => {
const sourceModel = strapi.getModel(sourceUid);
const isDP = contentTypes.hasDraftAndPublish;
const isSourceDP = isDP(sourceModel);
// Default to draft if not set
if (!isSourceDP) return { status: undefined };
switch (status) {
case 'published':
return { status: 'published' };
default:
// Assign to draft if the status is not valid
return { status: 'draft' };
}
};
export default {
async extractAndValidateRequestInfo(ctx: any, id?: Entity.ID) {
const { userAbility } = ctx.state;
const { model, targetField } = ctx.params;
@ -129,6 +153,16 @@ export default {
);
}
const sourceUid = model;
const targetUid = attribute.target;
const { locale, isSourceLocalized, isTargetLocalized } = validateLocale(
sourceUid,
targetUid,
ctx.request?.query?.locale
);
const { status } = validateStatus(sourceUid, ctx.request?.query?.status);
const permissionChecker = getService('permission-checker').create({
userAbility,
model,
@ -150,13 +184,9 @@ export default {
where.documentId = id;
if (status) {
where.publishedAt = getPublishedAtClause(status, sourceSchema.uid, attribute.target);
where.publishedAt = getPublishedAtClause(status, sourceUid);
}
const isSourceLocalized = strapi
.plugin('i18n')
.service('content-types')
.isLocalizedContentType(sourceSchema);
if (locale && isSourceLocalized) {
where.locale = locale;
}
@ -197,7 +227,7 @@ export default {
? await getService('components').findConfiguration(sourceSchema)
: await getService('content-types').findConfiguration(sourceSchema);
const targetSchema = strapi.getModel(attribute.target);
const targetSchema = strapi.getModel(targetUid);
const mainField = flow(
prop(`metadatas.${targetField}.edit.mainField`),
@ -212,18 +242,14 @@ export default {
'documentId',
]);
const isTargetLocalized = strapi
.plugin('i18n')
.service('content-types')
.isLocalizedContentType(targetSchema);
// TODO: Locale is always present, should we set it regardless?
if (isTargetLocalized) {
fieldsToSelect.push('locale');
}
return {
entryId,
locale,
status,
attribute,
fieldsToSelect,
mainField,
@ -242,12 +268,12 @@ export default {
*/
async findAvailable(ctx: any) {
const { id } = ctx.request.query;
const locale = ctx.request?.query?.locale || null;
const status = ctx.request?.query?.status;
await validateFindAvailable(ctx.request.query);
const {
locale,
status,
targetField,
fieldsToSelect,
mainField,
@ -258,7 +284,7 @@ export default {
schema: { uid: targetUid },
isLocalized: isTargetLocalized,
},
} = await this.extractAndValidateRequestInfo(ctx, id, locale, status);
} = await this.extractAndValidateRequestInfo(ctx, id);
const { idsToOmit, idsToInclude, _q, ...query } = ctx.request.query;
@ -278,7 +304,7 @@ export default {
// If no status is requested, we find all the draft relations and later update them
// with the latest available status
addFiltersClause(queryParams, {
publishedAt: getPublishedAtClause(status, sourceUid, targetUid),
publishedAt: getPublishedAtClause(status, targetUid),
});
// We will only filter by locale if the target content type is localized
@ -316,7 +342,7 @@ export default {
// Add the status and locale filters if they are provided
if (status) {
where[`${alias}.published_at`] = getPublishedAtClause(status, sourceUid, targetUid);
where[`${alias}.published_at`] = getPublishedAtClause(status, targetUid);
}
if (filterByLocale) {
where[`${alias}.locale`] = locale;
@ -374,9 +400,6 @@ export default {
await validateFindExisting(ctx.request.query);
const locale = ctx.request?.query?.locale || null;
const status = ctx.request?.query?.status;
const {
entryId,
attribute,
@ -388,7 +411,7 @@ export default {
target: {
schema: { uid: targetUid },
},
} = await this.extractAndValidateRequestInfo(ctx, id, locale, status);
} = await this.extractAndValidateRequestInfo(ctx, id);
const permissionQuery = await getService('permission-checker')
.create({ userAbility, model: targetUid })
@ -443,7 +466,12 @@ export default {
const relationsUnion = uniqBy('id', concat(sanitizedRes.results, res.results));
ctx.body = {
pagination: res.pagination,
pagination: res.pagination || {
page: 1,
pageCount: 1,
pageSize: 10,
total: relationsUnion.length,
},
results: await addStatusToRelations(targetUid, relationsUnion),
};
},

View File

@ -9,7 +9,8 @@ export const isLocalizedContentType = (uid: Common.UID.Schema) => {
export const getDefaultLocale = () => {
// TODO: V5 make this more performant
return strapi.plugin('i18n').service('locales').getDefaultLocale();
// return strapi.plugin('i18n').service('locales').getDefaultLocale();
return 'en';
};
export const getRelationTargetLocale = (