mirror of
https://github.com/strapi/strapi.git
synced 2025-09-16 20:10:05 +00:00
Merge branch 'features/api-token-v2' into api-token-v2/select-all-bug
This commit is contained in:
commit
a1ce4d8fa6
@ -80,7 +80,7 @@ Complete installation requirements can be found in the documentation under <a hr
|
|||||||
- CentOS/RHEL 8
|
- CentOS/RHEL 8
|
||||||
- macOS Mojave
|
- macOS Mojave
|
||||||
- Windows 10
|
- Windows 10
|
||||||
- Docker - [Docker-Repo](https://github.com/strapi/strapi-docker)
|
- Docker
|
||||||
|
|
||||||
(Please note that Strapi may work on other operating systems, but these are not tested nor officially supported at this time.)
|
(Please note that Strapi may work on other operating systems, but these are not tested nor officially supported at this time.)
|
||||||
|
|
||||||
|
@ -47,7 +47,7 @@ const DynamicTable = ({
|
|||||||
...metadatas,
|
...metadatas,
|
||||||
label: formatMessage({
|
label: formatMessage({
|
||||||
id: getTrad(`containers.ListPage.table-headers.${header.name}`),
|
id: getTrad(`containers.ListPage.table-headers.${header.name}`),
|
||||||
defaultMessage: header.name,
|
defaultMessage: metadatas.label,
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
name: sortFieldValue,
|
name: sortFieldValue,
|
||||||
@ -60,7 +60,7 @@ const DynamicTable = ({
|
|||||||
...metadatas,
|
...metadatas,
|
||||||
label: formatMessage({
|
label: formatMessage({
|
||||||
id: getTrad(`containers.ListPage.table-headers.${header.name}`),
|
id: getTrad(`containers.ListPage.table-headers.${header.name}`),
|
||||||
defaultMessage: header.name,
|
defaultMessage: metadatas.label,
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -1,19 +1,32 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const _ = require('lodash/fp');
|
const {
|
||||||
const types = require('./types');
|
isUndefined,
|
||||||
const { createField } = require('./fields');
|
castArray,
|
||||||
const { createQueryBuilder } = require('./query');
|
isNil,
|
||||||
|
has,
|
||||||
|
isString,
|
||||||
|
isInteger,
|
||||||
|
pick,
|
||||||
|
isPlainObject,
|
||||||
|
isEmpty,
|
||||||
|
isArray,
|
||||||
|
isNull,
|
||||||
|
} = require('lodash/fp');
|
||||||
|
const types = require('../types');
|
||||||
|
const { createField } = require('../fields');
|
||||||
|
const { createQueryBuilder } = require('../query');
|
||||||
const { createRepository } = require('./entity-repository');
|
const { createRepository } = require('./entity-repository');
|
||||||
const { isBidirectional, isOneToAny } = require('./metadata/relations');
|
const { isBidirectional, isOneToAny } = require('../metadata/relations');
|
||||||
|
const { deleteRelatedMorphOneRelationsAfterMorphToManyUpdate } = require('./morph-relations');
|
||||||
|
|
||||||
const toId = (value) => value.id || value;
|
const toId = (value) => value.id || value;
|
||||||
const toIds = (value) => _.castArray(value || []).map(toId);
|
const toIds = (value) => castArray(value || []).map(toId);
|
||||||
|
|
||||||
const isValidId = (value) => _.isString(value) || _.isInteger(value);
|
const isValidId = (value) => isString(value) || isInteger(value);
|
||||||
const toAssocs = (data) => {
|
const toAssocs = (data) => {
|
||||||
return _.castArray(data)
|
return castArray(data)
|
||||||
.filter((datum) => !_.isNil(datum))
|
.filter((datum) => !isNil(datum))
|
||||||
.map((datum) => {
|
.map((datum) => {
|
||||||
// if it is a string or an integer return an obj with id = to datum
|
// if it is a string or an integer return an obj with id = to datum
|
||||||
if (isValidId(datum)) {
|
if (isValidId(datum)) {
|
||||||
@ -21,7 +34,7 @@ const toAssocs = (data) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// if it is an object check it has at least a valid id
|
// if it is an object check it has at least a valid id
|
||||||
if (!_.has('id', datum) || !isValidId(datum.id)) {
|
if (!has('id', datum) || !isValidId(datum.id)) {
|
||||||
throw new Error(`Invalid id, expected a string or integer, got ${datum}`);
|
throw new Error(`Invalid id, expected a string or integer, got ${datum}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,8 +53,8 @@ const processData = (metadata, data = {}, { withDefaults = false } = {}) => {
|
|||||||
if (types.isScalar(attribute.type)) {
|
if (types.isScalar(attribute.type)) {
|
||||||
const field = createField(attribute);
|
const field = createField(attribute);
|
||||||
|
|
||||||
if (_.isUndefined(data[attributeName])) {
|
if (isUndefined(data[attributeName])) {
|
||||||
if (!_.isUndefined(attribute.default) && withDefaults) {
|
if (!isUndefined(attribute.default) && withDefaults) {
|
||||||
if (typeof attribute.default === 'function') {
|
if (typeof attribute.default === 'function') {
|
||||||
obj[attributeName] = attribute.default();
|
obj[attributeName] = attribute.default();
|
||||||
} else {
|
} else {
|
||||||
@ -66,11 +79,11 @@ const processData = (metadata, data = {}, { withDefaults = false } = {}) => {
|
|||||||
const joinColumnName = attribute.joinColumn.name;
|
const joinColumnName = attribute.joinColumn.name;
|
||||||
|
|
||||||
// allow setting to null
|
// allow setting to null
|
||||||
const attrValue = !_.isUndefined(data[attributeName])
|
const attrValue = !isUndefined(data[attributeName])
|
||||||
? data[attributeName]
|
? data[attributeName]
|
||||||
: data[joinColumnName];
|
: data[joinColumnName];
|
||||||
|
|
||||||
if (!_.isUndefined(attrValue)) {
|
if (!isUndefined(attrValue)) {
|
||||||
obj[joinColumnName] = attrValue;
|
obj[joinColumnName] = attrValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,8 +104,8 @@ const processData = (metadata, data = {}, { withDefaults = false } = {}) => {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_.isUndefined(value)) {
|
if (!isUndefined(value)) {
|
||||||
if (!_.has('id', value) || !_.has(typeField, value)) {
|
if (!has('id', value) || !has(typeField, value)) {
|
||||||
throw new Error(`Expects properties ${typeField} an id to make a morph association`);
|
throw new Error(`Expects properties ${typeField} an id to make a morph association`);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,7 +150,7 @@ const createEntityManager = (db) => {
|
|||||||
const states = await db.lifecycles.run('beforeCount', uid, { params });
|
const states = await db.lifecycles.run('beforeCount', uid, { params });
|
||||||
|
|
||||||
const res = await this.createQueryBuilder(uid)
|
const res = await this.createQueryBuilder(uid)
|
||||||
.init(_.pick(['_q', 'where', 'filters'], params))
|
.init(pick(['_q', 'where', 'filters'], params))
|
||||||
.count()
|
.count()
|
||||||
.first()
|
.first()
|
||||||
.execute();
|
.execute();
|
||||||
@ -155,7 +168,7 @@ const createEntityManager = (db) => {
|
|||||||
const metadata = db.metadata.get(uid);
|
const metadata = db.metadata.get(uid);
|
||||||
const { data } = params;
|
const { data } = params;
|
||||||
|
|
||||||
if (!_.isPlainObject(data)) {
|
if (!isPlainObject(data)) {
|
||||||
throw new Error('Create expects a data object');
|
throw new Error('Create expects a data object');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -187,7 +200,7 @@ const createEntityManager = (db) => {
|
|||||||
const metadata = db.metadata.get(uid);
|
const metadata = db.metadata.get(uid);
|
||||||
const { data } = params;
|
const { data } = params;
|
||||||
|
|
||||||
if (!_.isArray(data)) {
|
if (!isArray(data)) {
|
||||||
throw new Error('CreateMany expects data to be an array');
|
throw new Error('CreateMany expects data to be an array');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -195,7 +208,7 @@ const createEntityManager = (db) => {
|
|||||||
processData(metadata, datum, { withDefaults: true })
|
processData(metadata, datum, { withDefaults: true })
|
||||||
);
|
);
|
||||||
|
|
||||||
if (_.isEmpty(dataToInsert)) {
|
if (isEmpty(dataToInsert)) {
|
||||||
throw new Error('Nothing to insert');
|
throw new Error('Nothing to insert');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -214,11 +227,11 @@ const createEntityManager = (db) => {
|
|||||||
const metadata = db.metadata.get(uid);
|
const metadata = db.metadata.get(uid);
|
||||||
const { where, data } = params;
|
const { where, data } = params;
|
||||||
|
|
||||||
if (!_.isPlainObject(data)) {
|
if (!isPlainObject(data)) {
|
||||||
throw new Error('Update requires a data object');
|
throw new Error('Update requires a data object');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_.isEmpty(where)) {
|
if (isEmpty(where)) {
|
||||||
throw new Error('Update requires a where parameter');
|
throw new Error('Update requires a where parameter');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -232,7 +245,7 @@ const createEntityManager = (db) => {
|
|||||||
|
|
||||||
const dataToUpdate = processData(metadata, data);
|
const dataToUpdate = processData(metadata, data);
|
||||||
|
|
||||||
if (!_.isEmpty(dataToUpdate)) {
|
if (!isEmpty(dataToUpdate)) {
|
||||||
await this.createQueryBuilder(uid).where({ id }).update(dataToUpdate).execute();
|
await this.createQueryBuilder(uid).where({ id }).update(dataToUpdate).execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -259,7 +272,7 @@ const createEntityManager = (db) => {
|
|||||||
|
|
||||||
const dataToUpdate = processData(metadata, data);
|
const dataToUpdate = processData(metadata, data);
|
||||||
|
|
||||||
if (_.isEmpty(dataToUpdate)) {
|
if (isEmpty(dataToUpdate)) {
|
||||||
throw new Error('Update requires data');
|
throw new Error('Update requires data');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -280,7 +293,7 @@ const createEntityManager = (db) => {
|
|||||||
|
|
||||||
const { where, select, populate } = params;
|
const { where, select, populate } = params;
|
||||||
|
|
||||||
if (_.isEmpty(where)) {
|
if (isEmpty(where)) {
|
||||||
throw new Error('Delete requires a where parameter');
|
throw new Error('Delete requires a where parameter');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -336,7 +349,7 @@ const createEntityManager = (db) => {
|
|||||||
for (const attributeName of Object.keys(attributes)) {
|
for (const attributeName of Object.keys(attributes)) {
|
||||||
const attribute = attributes[attributeName];
|
const attribute = attributes[attributeName];
|
||||||
|
|
||||||
const isValidLink = _.has(attributeName, data) && !_.isNil(data[attributeName]);
|
const isValidLink = has(attributeName, data) && !isNil(data[attributeName]);
|
||||||
|
|
||||||
if (attribute.type !== 'relation' || !isValidLink) {
|
if (attribute.type !== 'relation' || !isValidLink) {
|
||||||
continue;
|
continue;
|
||||||
@ -373,7 +386,7 @@ const createEntityManager = (db) => {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
if (_.isEmpty(rows)) {
|
if (isEmpty(rows)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -398,10 +411,18 @@ const createEntityManager = (db) => {
|
|||||||
...(data.__pivot || {}),
|
...(data.__pivot || {}),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
if (_.isEmpty(rows)) {
|
if (isEmpty(rows)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// delete previous relations
|
||||||
|
await deleteRelatedMorphOneRelationsAfterMorphToManyUpdate(rows, {
|
||||||
|
uid,
|
||||||
|
attributeName,
|
||||||
|
joinTable,
|
||||||
|
db,
|
||||||
|
});
|
||||||
|
|
||||||
await this.createQueryBuilder(joinTable.name).insert(rows).execute();
|
await this.createQueryBuilder(joinTable.name).insert(rows).execute();
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
@ -450,7 +471,7 @@ const createEntityManager = (db) => {
|
|||||||
if (isOneToAny(attribute) && isBidirectional(attribute)) {
|
if (isOneToAny(attribute) && isBidirectional(attribute)) {
|
||||||
await this.createQueryBuilder(joinTable.name)
|
await this.createQueryBuilder(joinTable.name)
|
||||||
.delete()
|
.delete()
|
||||||
.where({ [inverseJoinColumn.name]: _.castArray(data[attributeName]) })
|
.where({ [inverseJoinColumn.name]: castArray(data[attributeName]) })
|
||||||
.where(joinTable.on || {})
|
.where(joinTable.on || {})
|
||||||
.execute();
|
.execute();
|
||||||
}
|
}
|
||||||
@ -490,7 +511,7 @@ const createEntityManager = (db) => {
|
|||||||
for (const attributeName of Object.keys(attributes)) {
|
for (const attributeName of Object.keys(attributes)) {
|
||||||
const attribute = attributes[attributeName];
|
const attribute = attributes[attributeName];
|
||||||
|
|
||||||
if (attribute.type !== 'relation' || !_.has(attributeName, data)) {
|
if (attribute.type !== 'relation' || !has(attributeName, data)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -503,12 +524,14 @@ const createEntityManager = (db) => {
|
|||||||
// set columns
|
// set columns
|
||||||
const { idColumn, typeColumn } = targetAttribute.morphColumn;
|
const { idColumn, typeColumn } = targetAttribute.morphColumn;
|
||||||
|
|
||||||
|
// update instead of deleting because the relation is directly on the entity table
|
||||||
|
// and not in a join table
|
||||||
await this.createQueryBuilder(target)
|
await this.createQueryBuilder(target)
|
||||||
.update({ [idColumn.name]: null, [typeColumn.name]: null })
|
.update({ [idColumn.name]: null, [typeColumn.name]: null })
|
||||||
.where({ [idColumn.name]: id, [typeColumn.name]: uid })
|
.where({ [idColumn.name]: id, [typeColumn.name]: uid })
|
||||||
.execute();
|
.execute();
|
||||||
|
|
||||||
if (!_.isNull(data[attributeName])) {
|
if (!isNull(data[attributeName])) {
|
||||||
await this.createQueryBuilder(target)
|
await this.createQueryBuilder(target)
|
||||||
.update({ [idColumn.name]: id, [typeColumn.name]: uid })
|
.update({ [idColumn.name]: id, [typeColumn.name]: uid })
|
||||||
.where({ id: toId(data[attributeName]) })
|
.where({ id: toId(data[attributeName]) })
|
||||||
@ -540,7 +563,7 @@ const createEntityManager = (db) => {
|
|||||||
field: attributeName,
|
field: attributeName,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
if (_.isEmpty(rows)) {
|
if (isEmpty(rows)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -577,10 +600,18 @@ const createEntityManager = (db) => {
|
|||||||
...(data.__pivot || {}),
|
...(data.__pivot || {}),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
if (_.isEmpty(rows)) {
|
if (isEmpty(rows)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// delete previous relations
|
||||||
|
await deleteRelatedMorphOneRelationsAfterMorphToManyUpdate(rows, {
|
||||||
|
uid,
|
||||||
|
attributeName,
|
||||||
|
joinTable,
|
||||||
|
db,
|
||||||
|
});
|
||||||
|
|
||||||
await this.createQueryBuilder(joinTable.name).insert(rows).execute();
|
await this.createQueryBuilder(joinTable.name).insert(rows).execute();
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
@ -602,7 +633,7 @@ const createEntityManager = (db) => {
|
|||||||
.update({ [attribute.joinColumn.referencedColumn]: null })
|
.update({ [attribute.joinColumn.referencedColumn]: null })
|
||||||
.execute();
|
.execute();
|
||||||
|
|
||||||
if (!_.isNull(data[attributeName])) {
|
if (!isNull(data[attributeName])) {
|
||||||
await this.createQueryBuilder(target)
|
await this.createQueryBuilder(target)
|
||||||
// NOTE: works if it is an array or a single id
|
// NOTE: works if it is an array or a single id
|
||||||
.where({ id: data[attributeName] })
|
.where({ id: data[attributeName] })
|
||||||
@ -633,7 +664,7 @@ const createEntityManager = (db) => {
|
|||||||
.execute();
|
.execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_.isNull(data[attributeName])) {
|
if (!isNull(data[attributeName])) {
|
||||||
const insert = toAssocs(data[attributeName]).map((data) => {
|
const insert = toAssocs(data[attributeName]).map((data) => {
|
||||||
return {
|
return {
|
||||||
[joinColumn.name]: id,
|
[joinColumn.name]: id,
|
||||||
@ -791,7 +822,7 @@ const createEntityManager = (db) => {
|
|||||||
async load(uid, entity, fields, params) {
|
async load(uid, entity, fields, params) {
|
||||||
const { attributes } = db.metadata.get(uid);
|
const { attributes } = db.metadata.get(uid);
|
||||||
|
|
||||||
const fieldsArr = _.castArray(fields);
|
const fieldsArr = castArray(fields);
|
||||||
fieldsArr.forEach((field) => {
|
fieldsArr.forEach((field) => {
|
||||||
const attribute = attributes[field];
|
const attribute = attributes[field];
|
||||||
|
|
||||||
@ -814,7 +845,7 @@ const createEntityManager = (db) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (Array.isArray(fields)) {
|
if (Array.isArray(fields)) {
|
||||||
return _.pick(fields, entry);
|
return pick(fields, entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
return entry[fields];
|
return entry[fields];
|
59
packages/core/database/lib/entity-manager/morph-relations.js
Normal file
59
packages/core/database/lib/entity-manager/morph-relations.js
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const { groupBy, pipe, mapValues, map, isEmpty } = require('lodash/fp');
|
||||||
|
const { createQueryBuilder } = require('../query');
|
||||||
|
|
||||||
|
const getMorphToManyRowsLinkedToMorphOne = (rows, { uid, attributeName, typeColumn, db }) =>
|
||||||
|
rows.filter((row) => {
|
||||||
|
const relatedType = row[typeColumn.name];
|
||||||
|
const field = row.field;
|
||||||
|
|
||||||
|
const targetAttribute = db.metadata.get(relatedType).attributes[field];
|
||||||
|
|
||||||
|
// ensure targeted field is the right one + check if it is a morphOne
|
||||||
|
return (
|
||||||
|
targetAttribute?.target === uid &&
|
||||||
|
targetAttribute?.morphBy === attributeName &&
|
||||||
|
targetAttribute?.relation === 'morphOne'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
const deleteRelatedMorphOneRelationsAfterMorphToManyUpdate = async (
|
||||||
|
rows,
|
||||||
|
{ uid, attributeName, joinTable, db }
|
||||||
|
) => {
|
||||||
|
const { morphColumn } = joinTable;
|
||||||
|
const { idColumn, typeColumn } = morphColumn;
|
||||||
|
|
||||||
|
const morphOneRows = getMorphToManyRowsLinkedToMorphOne(rows, {
|
||||||
|
uid,
|
||||||
|
attributeName,
|
||||||
|
typeColumn,
|
||||||
|
db,
|
||||||
|
});
|
||||||
|
|
||||||
|
const groupByType = groupBy(typeColumn.name);
|
||||||
|
const groupByField = groupBy('field');
|
||||||
|
|
||||||
|
const typeAndFieldIdsGrouped = pipe(groupByType, mapValues(groupByField))(morphOneRows);
|
||||||
|
|
||||||
|
const orWhere = [];
|
||||||
|
|
||||||
|
for (const [type, v] of Object.entries(typeAndFieldIdsGrouped)) {
|
||||||
|
for (const [field, arr] of Object.entries(v)) {
|
||||||
|
orWhere.push({
|
||||||
|
[typeColumn.name]: type,
|
||||||
|
field,
|
||||||
|
[idColumn.name]: { $in: map(idColumn.name, arr) },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isEmpty(orWhere)) {
|
||||||
|
await createQueryBuilder(joinTable.name, db).delete().where({ $or: orWhere }).execute();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
deleteRelatedMorphOneRelationsAfterMorphToManyUpdate,
|
||||||
|
};
|
@ -42,7 +42,7 @@
|
|||||||
"react-redux": "7.2.8",
|
"react-redux": "7.2.8",
|
||||||
"react-router": "^5.2.0",
|
"react-router": "^5.2.0",
|
||||||
"react-router-dom": "5.2.0",
|
"react-router-dom": "5.2.0",
|
||||||
"sharp": "0.30.7"
|
"sharp": "0.31.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@testing-library/dom": "8.17.1",
|
"@testing-library/dom": "8.17.1",
|
||||||
|
@ -9,6 +9,7 @@ const { createStrapiInstance } = require('../../../../../test/helpers/strapi');
|
|||||||
const { createContentAPIRequest } = require('../../../../../test/helpers/request');
|
const { createContentAPIRequest } = require('../../../../../test/helpers/request');
|
||||||
|
|
||||||
const builder = createTestBuilder();
|
const builder = createTestBuilder();
|
||||||
|
const data = { dogs: [] };
|
||||||
let strapi;
|
let strapi;
|
||||||
let rq;
|
let rq;
|
||||||
|
|
||||||
@ -24,7 +25,7 @@ const dogModel = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
describe('Upload plugin end to end tests', () => {
|
describe('Upload plugin', () => {
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
await builder.addContentType(dogModel).build();
|
await builder.addContentType(dogModel).build();
|
||||||
strapi = await createStrapiInstance();
|
strapi = await createStrapiInstance();
|
||||||
@ -155,6 +156,8 @@ describe('Upload plugin end to end tests', () => {
|
|||||||
id: expect.anything(),
|
id: expect.anything(),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
data.dogs.push(res.body);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('With a pdf', async () => {
|
test('With a pdf', async () => {
|
||||||
@ -183,6 +186,51 @@ describe('Upload plugin end to end tests', () => {
|
|||||||
id: expect.anything(),
|
id: expect.anything(),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
data.dogs.push(res.body);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// see https://github.com/strapi/strapi/issues/14125
|
||||||
|
describe('File relations are correctly removed', () => {
|
||||||
|
test('Update an entity with a file correctly removes the relation between the entity and its old file', async () => {
|
||||||
|
const res = await rq({
|
||||||
|
method: 'PUT',
|
||||||
|
url: `/dogs/${data.dogs[0].data.id}?populate=*`,
|
||||||
|
formData: {
|
||||||
|
data: '{}',
|
||||||
|
'files.profilePicture': fs.createReadStream(path.join(__dirname, '../utils/strapi.jpg')),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(res.statusCode).toBe(200);
|
||||||
|
expect(res.body.data.attributes.profilePicture.data.id).not.toBe(
|
||||||
|
data.dogs[0].data.attributes.profilePicture.data.id
|
||||||
|
);
|
||||||
|
|
||||||
|
data.dogs[0] = res.body;
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Update a file with an entity correctly removes the relation between the entity and its old file', async () => {
|
||||||
|
const fileId = data.dogs[1].data.attributes.profilePicture.data.id;
|
||||||
|
await strapi.entityService.update('plugin::upload.file', fileId, {
|
||||||
|
data: {
|
||||||
|
related: [
|
||||||
|
{
|
||||||
|
id: data.dogs[0].data.id,
|
||||||
|
__type: 'api::dog.dog',
|
||||||
|
__pivot: { field: 'profilePicture' },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const res = await rq({
|
||||||
|
method: 'GET',
|
||||||
|
url: `/dogs/${data.dogs[0].data.id}?populate=*`,
|
||||||
|
});
|
||||||
|
expect(res.body.data.attributes.profilePicture.data.id).toBe(fileId);
|
||||||
|
|
||||||
|
data.dogs[0] = res.body;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user