mirror of
https://github.com/strapi/strapi.git
synced 2025-09-25 16:29:34 +00:00
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:
parent
49e84a90ad
commit
66c1011328
@ -61,10 +61,7 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|||||||
}),
|
}),
|
||||||
invalidatesTags: (result, _error, { model }) => [
|
invalidatesTags: (result, _error, { model }) => [
|
||||||
{ type: 'Document', id: `${model}_LIST` },
|
{ type: 'Document', id: `${model}_LIST` },
|
||||||
{
|
'Relations',
|
||||||
type: 'Relations',
|
|
||||||
id: `${model}_${result?.data.documentId}`,
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
deleteDocument: builder.mutation<
|
deleteDocument: builder.mutation<
|
||||||
@ -127,10 +124,7 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|||||||
id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model,
|
id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model,
|
||||||
},
|
},
|
||||||
{ type: 'Document', id: `${model}_LIST` },
|
{ type: 'Document', id: `${model}_LIST` },
|
||||||
{
|
'Relations',
|
||||||
type: 'Relations',
|
|
||||||
id: `${model}_${documentId}`,
|
|
||||||
},
|
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
@ -278,10 +272,7 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|||||||
id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model,
|
id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model,
|
||||||
},
|
},
|
||||||
{ type: 'Document', id: `${model}_LIST` },
|
{ type: 'Document', id: `${model}_LIST` },
|
||||||
{
|
'Relations',
|
||||||
type: 'Relations',
|
|
||||||
id: `${model}_${documentId}`,
|
|
||||||
},
|
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
@ -321,10 +312,7 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|||||||
type: 'Document',
|
type: 'Document',
|
||||||
id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model,
|
id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model,
|
||||||
},
|
},
|
||||||
{
|
'Relations',
|
||||||
type: 'Relations',
|
|
||||||
id: `${model}_${documentId}`,
|
|
||||||
},
|
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
@ -97,9 +97,7 @@ const relationsApi = contentManagerApi.injectEndpoints({
|
|||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
providesTags: (result, error, args) => [
|
providesTags: ['Relations'],
|
||||||
{ type: 'Relations', id: `${args.model}_${args.id}` },
|
|
||||||
],
|
|
||||||
}),
|
}),
|
||||||
searchRelations: build.query<
|
searchRelations: build.query<
|
||||||
Contracts.Relations.FindAvailable.Response,
|
Contracts.Relations.FindAvailable.Response,
|
||||||
|
@ -78,42 +78,66 @@ const addStatusToRelations = async (uid: Common.UID.ContentType, relations: Rela
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const getPublishedAtClause = (
|
const getPublishedAtClause = (status: string, uid: Common.UID.Schema) => {
|
||||||
status: Documents.Params.PublicationStatus.Kind,
|
const model = strapi.getModel(uid);
|
||||||
sourceUid: Common.UID.Schema,
|
|
||||||
targetUid: Common.UID.ContentType
|
|
||||||
) => {
|
|
||||||
const sourceModel = strapi.getModel(sourceUid);
|
|
||||||
const targetModel = strapi.getModel(targetUid);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If target does not have dp, status should be published.
|
* If dp is disabled, ignore the filter
|
||||||
* As it only contains entries with publishedAt set.
|
|
||||||
*/
|
*/
|
||||||
if (!contentTypes.hasDraftAndPublish(targetModel)) {
|
if (!model || !contentTypes.hasDraftAndPublish(model)) {
|
||||||
return {};
|
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
|
// Prioritize the draft status in case it's not provided
|
||||||
return status === 'published' ? { $notNull: true } : { $null: true };
|
return status === 'published' ? { $notNull: true } : { $null: true };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
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 {
|
export default {
|
||||||
async extractAndValidateRequestInfo(
|
async extractAndValidateRequestInfo(ctx: any, id?: Entity.ID) {
|
||||||
ctx: any,
|
|
||||||
id?: Entity.ID,
|
|
||||||
locale?: Documents.Params.Locale,
|
|
||||||
status?: Documents.Params.PublicationStatus.Kind
|
|
||||||
) {
|
|
||||||
const { userAbility } = ctx.state;
|
const { userAbility } = ctx.state;
|
||||||
const { model, targetField } = ctx.params;
|
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({
|
const permissionChecker = getService('permission-checker').create({
|
||||||
userAbility,
|
userAbility,
|
||||||
model,
|
model,
|
||||||
@ -150,13 +184,9 @@ export default {
|
|||||||
where.documentId = id;
|
where.documentId = id;
|
||||||
|
|
||||||
if (status) {
|
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) {
|
if (locale && isSourceLocalized) {
|
||||||
where.locale = locale;
|
where.locale = locale;
|
||||||
}
|
}
|
||||||
@ -197,7 +227,7 @@ export default {
|
|||||||
? await getService('components').findConfiguration(sourceSchema)
|
? await getService('components').findConfiguration(sourceSchema)
|
||||||
: await getService('content-types').findConfiguration(sourceSchema);
|
: await getService('content-types').findConfiguration(sourceSchema);
|
||||||
|
|
||||||
const targetSchema = strapi.getModel(attribute.target);
|
const targetSchema = strapi.getModel(targetUid);
|
||||||
|
|
||||||
const mainField = flow(
|
const mainField = flow(
|
||||||
prop(`metadatas.${targetField}.edit.mainField`),
|
prop(`metadatas.${targetField}.edit.mainField`),
|
||||||
@ -212,18 +242,14 @@ export default {
|
|||||||
'documentId',
|
'documentId',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const isTargetLocalized = strapi
|
|
||||||
.plugin('i18n')
|
|
||||||
.service('content-types')
|
|
||||||
.isLocalizedContentType(targetSchema);
|
|
||||||
|
|
||||||
// TODO: Locale is always present, should we set it regardless?
|
|
||||||
if (isTargetLocalized) {
|
if (isTargetLocalized) {
|
||||||
fieldsToSelect.push('locale');
|
fieldsToSelect.push('locale');
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
entryId,
|
entryId,
|
||||||
|
locale,
|
||||||
|
status,
|
||||||
attribute,
|
attribute,
|
||||||
fieldsToSelect,
|
fieldsToSelect,
|
||||||
mainField,
|
mainField,
|
||||||
@ -242,12 +268,12 @@ export default {
|
|||||||
*/
|
*/
|
||||||
async findAvailable(ctx: any) {
|
async findAvailable(ctx: any) {
|
||||||
const { id } = ctx.request.query;
|
const { id } = ctx.request.query;
|
||||||
const locale = ctx.request?.query?.locale || null;
|
|
||||||
const status = ctx.request?.query?.status;
|
|
||||||
|
|
||||||
await validateFindAvailable(ctx.request.query);
|
await validateFindAvailable(ctx.request.query);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
|
locale,
|
||||||
|
status,
|
||||||
targetField,
|
targetField,
|
||||||
fieldsToSelect,
|
fieldsToSelect,
|
||||||
mainField,
|
mainField,
|
||||||
@ -258,7 +284,7 @@ export default {
|
|||||||
schema: { uid: targetUid },
|
schema: { uid: targetUid },
|
||||||
isLocalized: isTargetLocalized,
|
isLocalized: isTargetLocalized,
|
||||||
},
|
},
|
||||||
} = await this.extractAndValidateRequestInfo(ctx, id, locale, status);
|
} = await this.extractAndValidateRequestInfo(ctx, id);
|
||||||
|
|
||||||
const { idsToOmit, idsToInclude, _q, ...query } = ctx.request.query;
|
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
|
// If no status is requested, we find all the draft relations and later update them
|
||||||
// with the latest available status
|
// with the latest available status
|
||||||
addFiltersClause(queryParams, {
|
addFiltersClause(queryParams, {
|
||||||
publishedAt: getPublishedAtClause(status, sourceUid, targetUid),
|
publishedAt: getPublishedAtClause(status, targetUid),
|
||||||
});
|
});
|
||||||
|
|
||||||
// We will only filter by locale if the target content type is localized
|
// 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
|
// Add the status and locale filters if they are provided
|
||||||
if (status) {
|
if (status) {
|
||||||
where[`${alias}.published_at`] = getPublishedAtClause(status, sourceUid, targetUid);
|
where[`${alias}.published_at`] = getPublishedAtClause(status, targetUid);
|
||||||
}
|
}
|
||||||
if (filterByLocale) {
|
if (filterByLocale) {
|
||||||
where[`${alias}.locale`] = locale;
|
where[`${alias}.locale`] = locale;
|
||||||
@ -374,9 +400,6 @@ export default {
|
|||||||
|
|
||||||
await validateFindExisting(ctx.request.query);
|
await validateFindExisting(ctx.request.query);
|
||||||
|
|
||||||
const locale = ctx.request?.query?.locale || null;
|
|
||||||
const status = ctx.request?.query?.status;
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
entryId,
|
entryId,
|
||||||
attribute,
|
attribute,
|
||||||
@ -388,7 +411,7 @@ export default {
|
|||||||
target: {
|
target: {
|
||||||
schema: { uid: targetUid },
|
schema: { uid: targetUid },
|
||||||
},
|
},
|
||||||
} = await this.extractAndValidateRequestInfo(ctx, id, locale, status);
|
} = await this.extractAndValidateRequestInfo(ctx, id);
|
||||||
|
|
||||||
const permissionQuery = await getService('permission-checker')
|
const permissionQuery = await getService('permission-checker')
|
||||||
.create({ userAbility, model: targetUid })
|
.create({ userAbility, model: targetUid })
|
||||||
@ -443,7 +466,12 @@ export default {
|
|||||||
const relationsUnion = uniqBy('id', concat(sanitizedRes.results, res.results));
|
const relationsUnion = uniqBy('id', concat(sanitizedRes.results, res.results));
|
||||||
|
|
||||||
ctx.body = {
|
ctx.body = {
|
||||||
pagination: res.pagination,
|
pagination: res.pagination || {
|
||||||
|
page: 1,
|
||||||
|
pageCount: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
total: relationsUnion.length,
|
||||||
|
},
|
||||||
results: await addStatusToRelations(targetUid, relationsUnion),
|
results: await addStatusToRelations(targetUid, relationsUnion),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
@ -9,7 +9,8 @@ export const isLocalizedContentType = (uid: Common.UID.Schema) => {
|
|||||||
|
|
||||||
export const getDefaultLocale = () => {
|
export const getDefaultLocale = () => {
|
||||||
// TODO: V5 make this more performant
|
// 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 = (
|
export const getRelationTargetLocale = (
|
||||||
|
Loading…
x
Reference in New Issue
Block a user