Init compo & add publication field

This commit is contained in:
Alexandre Bodin 2021-07-07 18:04:39 +02:00
parent 65d612f364
commit 3ded0ef2bd
14 changed files with 304 additions and 149 deletions

View File

@ -26,6 +26,7 @@ const permissionDomain = require('../../domain/permission/index');
* @returns {Promise<array>} * @returns {Promise<array>}
*/ */
const deleteByRolesIds = async rolesIds => { const deleteByRolesIds = async rolesIds => {
// FIXME: need to delete associations in delete many
await strapi.query('strapi::permission').deleteMany({ await strapi.query('strapi::permission').deleteMany({
where: { where: {
role: { id: rolesIds }, role: { id: rolesIds },

View File

@ -21,26 +21,28 @@ async function main(connection) {
await orm.schema.sync(); await orm.schema.sync();
await orm.schema.reset(); await orm.schema.reset();
await orm.query('compo').create({
data: {
key: 'A',
value: 1,
},
});
await orm.query('article').create({ await orm.query('article').create({
// select: {}, // select: {},
// populate: {}, // populate: {},
data: { data: {
compo: { compo: 1,
id: 1,
__pivot: {
order: 1,
field: 'compo',
},
},
}, },
}); });
const articles = await orm.query('article').findMany({ await orm.query('article').findMany({
limit: 5, populate: ['category.compo'],
where: { title: 'Article 001', createdAt: { $null: true } },
}); });
console.log(articles); // console.log(await orm.query('article').load(1, 'compo'));
// await orm.query('article').delete({ where: { id: 1 } });
// await tests(orm); // await tests(orm);
} finally { } finally {
@ -391,28 +393,40 @@ const tests = async orm => {
// }); // });
await orm.query('article').findMany({ await orm.query('article').findMany({
limit: 5,
where: { where: {
compos: { $not: {
key: 'xx', $or: [
{
category: {
title: 'Article 003',
},
},
{
title: {
$in: ['Article 001', 'Article 002'],
},
},
],
title: {
$not: 'Article 007',
},
}, },
}, },
orderBy: [{ category: { name: 'asc' } }],
offset: 0,
limit: 10,
populate: { populate: {
category: { category: {
select: ['id', 'title'],
limit: 5,
offset: 2,
orderBy: 'title', orderBy: 'title',
populate: { populate: {
articles: { categories: {
populate: { populate: {
tags: true, tags: true,
}, },
}, },
}, },
}, },
compos: true, seo: true,
}, },
orderBy: { compos: { key: 'DESC' } },
}); });
}; };

View File

@ -38,24 +38,24 @@ const article = {
title: { title: {
type: 'string', type: 'string',
}, },
// category: { category: {
// type: 'relation', type: 'relation',
// relation: 'manyToOne', relation: 'manyToOne',
// target: 'category', target: 'category',
// inversedBy: 'articles', inversedBy: 'articles',
// // useJoinTable: false, // useJoinTable: false,
// }, },
// tags: { // tags: {
// type: 'relation', // type: 'relation',
// relation: 'manyToMany', // relation: 'manyToMany',
// target: 'tag', // target: 'tag',
// inversedBy: 'articles', // inversedBy: 'articles',
// }, // },
compo: { // compo: {
type: 'component', // type: 'component',
component: 'compo', // component: 'compo',
// repeatable: true, // // repeatable: true,
}, // },
// cover: { // cover: {
// type: 'media', // type: 'media',
// single: true, // single: true,

View File

@ -55,19 +55,19 @@ const createEntityManager = db => {
const repoMap = {}; const repoMap = {};
return { return {
async findOne(uid, params) { findOne(uid, params) {
const qb = this.createQueryBuilder(uid) const qb = this.createQueryBuilder(uid)
.init(params) .init(params)
.first(); .first();
return await qb.execute(); return qb.execute();
}, },
// should we name it findOne because people are used to it ? // should we name it findOne because people are used to it ?
async findMany(uid, params) { findMany(uid, params) {
const qb = this.createQueryBuilder(uid).init(params); const qb = this.createQueryBuilder(uid).init(params);
return await qb.execute(); return qb.execute();
}, },
async count(uid, params = {}) { async count(uid, params = {}) {
@ -195,15 +195,14 @@ const createEntityManager = db => {
async delete(uid, params = {}) { async delete(uid, params = {}) {
const { where, select, populate } = params; const { where, select, populate } = params;
const metadata = db.metadata.get(uid);
if (_.isEmpty(where)) { if (_.isEmpty(where)) {
throw new Error('Delete requires a where parameter'); throw new Error('Delete requires a where parameter');
} }
const entity = await this.findOne(uid, { const entity = await this.findOne(uid, {
where,
select: select && ['id'].concat(select), select: select && ['id'].concat(select),
where,
populate, populate,
}); });
@ -235,27 +234,6 @@ const createEntityManager = db => {
return { count: deletedRows }; return { count: deletedRows };
}, },
// populate already loaded entry
async populate(uid, entry, name, params) {
return {
...entry,
relation: await this.load(entry, name, params),
};
},
// loads a relation
load(uid, entry, name, params) {
const { attributes } = db.metadata.get(uid);
return this.getRepository(attributes[name].target.uid).findMany({
...params,
where: {
...params.where,
// [parent]: entry.id,
},
});
},
/** /**
* Attach relations to a new entity * Attach relations to a new entity
* *
@ -497,6 +475,35 @@ const createEntityManager = db => {
} }
}, },
// populate already loaded entry
async populate(uid, entry, name, params) {
return {
...entry,
relation: await this.load(entry, name, params),
};
},
// loads a relation
async load(uid, id, field, params) {
const { attributes } = db.metadata.get(uid);
const attribute = attributes[field];
if (!attribute || attribute.type !== 'relation') {
throw new Error('Invalid load expected a relational attribute');
}
const entry = await this.findOne(uid, {
select: ['id'],
where: { id },
populate: {
[field]: params || true,
},
});
return entry[field];
},
// cascading // cascading
// aggregations // aggregations
// -> avg // -> avg

View File

@ -84,12 +84,13 @@ const createRepository = (uid, db) => {
}, },
attachRelations(id, data) { attachRelations(id, data) {
console.log(id, data)
return db.entityManager.attachRelations(uid, id, data); return db.entityManager.attachRelations(uid, id, data);
}, },
updateRelations(id, data) { updateRelations(id, data) {
return db.entityManager.updateRelations(uid, id, data); return db.entityManager.updateRelations(uid, id, data);
}, },
deleteRelations(id) { deleteRelations(id) {
return db.entityManager.deleteRelations(uid, id); return db.entityManager.deleteRelations(uid, id);
}, },
@ -97,7 +98,9 @@ const createRepository = (uid, db) => {
// TODO: add relation API // TODO: add relation API
populate() {}, populate() {},
load() {}, load(id, field, params) {
return db.entityManager.load(uid, id, field, params);
},
}; };
}; };

View File

@ -193,10 +193,10 @@ const relationFactoryMap = {
manyToMany: createManyToMany, manyToMany: createManyToMany,
}; };
const createJoinColum = (metadata, { attribute /*attributeName, meta */ }) => { const createJoinColum = (metadata, { attribute, attributeName /*meta */ }) => {
const targetMeta = metadata.get(attribute.target); const targetMeta = metadata.get(attribute.target);
const joinColumnName = _.snakeCase(`${targetMeta.singularName}_id`); const joinColumnName = _.snakeCase(`${attributeName}_id`);
const joinColumn = { const joinColumn = {
name: joinColumnName, name: joinColumnName,
referencedColumn: 'id', referencedColumn: 'id',

View File

@ -470,7 +470,15 @@ const processPopulate = (populate, ctx) => {
if (Array.isArray(populate)) { if (Array.isArray(populate)) {
for (const key of populate) { for (const key of populate) {
populateMap[key] = true; const [root, ...rest] = key.split('.');
if (rest.length > 0) {
populateMap[root] = {
populate: rest,
};
} else {
populateMap[root] = true;
}
} }
} else { } else {
populateMap = populate; populateMap = populate;

View File

@ -20,11 +20,11 @@ const transformAttribute = attribute => {
} }
}; };
// TODO: add published_at for D&P
// TODO: add locale & localizations for I18N // TODO: add locale & localizations for I18N
// TODO: model logic outside DB
const transformContentTypes = contentTypes => { const transformContentTypes = contentTypes => {
return contentTypes.map(contentType => { return contentTypes.map(contentType => {
return { const model = {
...contentType, ...contentType,
// reuse new model def // reuse new model def
singularName: contentType.modelName, singularName: contentType.modelName,
@ -44,6 +44,8 @@ const transformContentTypes = contentTypes => {
}, {}), }, {}),
}, },
}; };
return model;
}); });
}; };

View File

@ -42,7 +42,7 @@ const getLimitParam = params => {
return defaultLimit; return defaultLimit;
} }
const limit = _.toNumber(params._limit); const limit = _.toNumber(params.limit);
// if there is max limit set and params._limit exceeds this number, return configured max limit // if there is max limit set and params._limit exceeds this number, return configured max limit
if (maxLimit && (limit === -1 || limit > maxLimit)) { if (maxLimit && (limit === -1 || limit > maxLimit)) {
return maxLimit; return maxLimit;
@ -58,9 +58,9 @@ const getLimitParam = params => {
*/ */
const getFetchParams = (params = {}) => { const getFetchParams = (params = {}) => {
return { return {
// _publicationState: DP_PUB_STATE_LIVE, publicationState: DP_PUB_STATE_LIVE,
...params, ...params,
// limit: getLimitParam(params), limit: getLimitParam(params),
}; };
}; };

View File

@ -1,5 +1,6 @@
'use strict'; 'use strict';
const _ = require('lodash');
const { has, pick } = require('lodash/fp'); const { has, pick } = require('lodash/fp');
const delegate = require('delegates'); const delegate = require('delegates');
@ -43,34 +44,59 @@ module.exports = ctx => {
}; };
// TODO: move to Controller ? // TODO: move to Controller ?
const transformParamsToQuery = (params = {}) => { const transformParamsToQuery = (uid, params = {}) => {
const query = {}; const model = strapi.getModel(uid);
const query = {
populate: [],
};
// TODO: check invalid values add defaults .... // TODO: check invalid values add defaults ....
if (params.start) { const { start, limit, sort, filters, fields, populate, publicationState } = params;
query.offset = convertStartQueryParams(params.start);
if (start) {
query.offset = convertStartQueryParams(start);
} }
if (params.limit) { if (limit) {
query.limit = convertLimitQueryParams(params.limit); query.limit = convertLimitQueryParams(limit);
} }
if (params.sort) { if (sort) {
query.orderBy = convertSortQueryParams(params.sort); query.orderBy = convertSortQueryParams(sort);
} }
if (params.filters) { if (filters) {
query.where = params.filters; query.where = filters;
} }
if (params.fields) { if (fields) {
query.select = params.fields; query.select = _.castArray(fields);
} }
if (params.populate) { if (populate) {
const { populate } = params; const { populate } = params;
query.populate = populate; query.populate = _.castArray(populate);
}
// TODO: move to layer above ?
if (publicationState && contentTypesUtils.hasDraftAndPublish(model)) {
const { publicationState = 'live' } = params;
const liveClause = {
published_at: {
$notNull: true,
},
};
if (publicationState === 'live') {
query.where = {
$and: [liveClause, query.where || {}],
};
// TODO: propagate nested publicationState filter somehow
}
} }
return query; return query;
@ -85,12 +111,21 @@ const createDefaultImplementation = ({ db, eventHub, entityValidator }) => ({
return options; return options;
}, },
emitEvent(uid, event, entity) {
const model = strapi.getModel(uid);
eventHub.emit(event, {
model: model.modelName,
entry: sanitizeEntity(entity, { model }),
});
},
async find(uid, opts) { async find(uid, opts) {
const { kind } = strapi.getModel(uid); const { kind } = strapi.getModel(uid);
const { params } = await this.wrapOptions(opts, { uid, action: 'find' }); const { params } = await this.wrapOptions(opts, { uid, action: 'find' });
const query = transformParamsToQuery(params); const query = transformParamsToQuery(uid, params);
// return first element and ignore filters // return first element and ignore filters
if (kind === 'singleType') { if (kind === 'singleType') {
@ -103,26 +138,21 @@ const createDefaultImplementation = ({ db, eventHub, entityValidator }) => ({
async findPage(uid, opts) { async findPage(uid, opts) {
const { params } = await this.wrapOptions(opts, { uid, action: 'findPage' }); const { params } = await this.wrapOptions(opts, { uid, action: 'findPage' });
// TODO: transform page pageSize const query = transformParamsToQuery(uid, params);
const query = transformParamsToQuery(params);
return db.query(uid).findPage(query); return db.query(uid).findPage(query);
}, },
async findWithRelationCounts(uid, opts) { async findWithRelationCounts(uid, opts) {
const { params, populate } = await this.wrapOptions(opts, { const { params } = await this.wrapOptions(opts, { uid, action: 'findWithRelationCounts' });
uid,
action: 'findWithRelationCounts',
});
// TODO: to impl return db.query(uid).findWithRelationCounts(params);
return db.query(uid).findWithRelationCounts(params, populate);
}, },
async findOne(uid, entityId, opts) { async findOne(uid, entityId, opts) {
const { params } = await this.wrapOptions(opts, { uid, action: 'findOne' }); const { params } = await this.wrapOptions(opts, { uid, action: 'findOne' });
const query = transformParamsToQuery(pickSelectionParams(params)); const query = transformParamsToQuery(uid, pickSelectionParams(params));
return db.query(uid).findOne({ ...query, where: { id: entityId } }); return db.query(uid).findOne({ ...query, where: { id: entityId } });
}, },
@ -130,7 +160,7 @@ const createDefaultImplementation = ({ db, eventHub, entityValidator }) => ({
async count(uid, opts) { async count(uid, opts) {
const { params } = await this.wrapOptions(opts, { uid, action: 'count' }); const { params } = await this.wrapOptions(opts, { uid, action: 'count' });
const query = transformParamsToQuery(params); const query = transformParamsToQuery(uid, params);
return db.query(uid).count(query); return db.query(uid).count(query);
}, },
@ -138,36 +168,27 @@ const createDefaultImplementation = ({ db, eventHub, entityValidator }) => ({
async create(uid, opts) { async create(uid, opts) {
const { params, data, files } = await this.wrapOptions(opts, { uid, action: 'create' }); const { params, data, files } = await this.wrapOptions(opts, { uid, action: 'create' });
const modelDef = strapi.getModel(uid); const model = strapi.getModel(uid);
const isDraft = contentTypesUtils.isDraft(data, model);
const isDraft = contentTypesUtils.isDraft(data, modelDef); const validData = await entityValidator.validateEntityCreation(model, data, { isDraft });
const validData = await entityValidator.validateEntityCreation(modelDef, data, { isDraft });
// select / populate // select / populate
const query = transformParamsToQuery(pickSelectionParams(params)); const query = transformParamsToQuery(uid, pickSelectionParams(params));
// TODO: wrap into transaction // TODO: wrap into transaction
const componentData = await createComponents(uid, validData); const componentData = await createComponents(uid, validData);
const entity = await db.query(uid).create({ const entity = await db.query(uid).create({
...query, ...query,
data: Object.assign(validData, componentData), data: Object.assign(validData, componentData),
}); });
// TODO: Implement components CRUD
// TODO: implement files outside of the entity service // TODO: implement files outside of the entity service
// if (files && Object.keys(files).length > 0) { // if (files && Object.keys(files).length > 0) {
// await this.uploadFiles(entry, files, { model }); // await this.uploadFiles(entry, files, { model });
// entry = await this.findOne({ params: { id: entry.id } }, { model }); // entry = await this.findOne({ params: { id: entry.id } }, { model });
// } // }
eventHub.emit(ENTRY_CREATE, { this.emitEvent(uid, ENTRY_CREATE, entity);
model: modelDef.modelName,
entry: sanitizeEntity(entity, { model: modelDef }),
});
return entity; return entity;
}, },
@ -175,72 +196,71 @@ const createDefaultImplementation = ({ db, eventHub, entityValidator }) => ({
async update(uid, entityId, opts) { async update(uid, entityId, opts) {
const { params, data, files } = await this.wrapOptions(opts, { uid, action: 'update' }); const { params, data, files } = await this.wrapOptions(opts, { uid, action: 'update' });
const modelDef = strapi.getModel(uid); const model = strapi.getModel(uid);
// const existingEntry = await db.query(uid).findOne({ where: { id: entityId } }); const existingEntry = await db.query(uid).findOne({ where: { id: entityId } });
// const isDraft = contentTypesUtils.isDraft(existingEntry, modelDef); const isDraft = contentTypesUtils.isDraft(existingEntry, model);
// TODO: validate const validData = await entityValidator.validateEntityUpdate(model, data, {
// // const validData = await entityValidator.validateEntityUpdate(modelDef, data, { isDraft,
// // isDraft,
// // });
// select / populate
const query = transformParamsToQuery(pickSelectionParams(params));
// TODO: wrap in transaction
const componentData = await updateComponents(uid, data);
let entry = await db.query(uid).update({
...query,
where: { id: entityId },
data: Object.assign(data, componentData),
}); });
// TODO: implement files const query = transformParamsToQuery(uid, pickSelectionParams(params));
// TODO: wrap in transaction
const componentData = await updateComponents(uid, entityId, validData);
const entity = await db.query(uid).update({
...query,
where: { id: entityId },
data: Object.assign(validData, componentData),
});
// TODO: implement files outside of the entity service
// if (files && Object.keys(files).length > 0) { // if (files && Object.keys(files).length > 0) {
// await this.uploadFiles(entry, files, { model }); // await this.uploadFiles(entry, files, { model });
// entry = await this.findOne({ params: { id: entry.id } }, { model }); // entry = await this.findOne({ params: { id: entry.id } }, { model });
// } // }
eventHub.emit(ENTRY_UPDATE, { this.emitEvent(uid, ENTRY_UPDATE, entity);
model: modelDef.modelName,
entry: sanitizeEntity(entry, { model: modelDef }),
});
return entry; return entity;
}, },
async delete(uid, entityId, opts) { async delete(uid, entityId, opts) {
const { params } = await this.wrapOptions(opts, { uid, action: 'delete' }); const { params } = await this.wrapOptions(opts, { uid, action: 'delete' });
// select / populate // select / populate
const query = transformParamsToQuery(pickSelectionParams(params)); const query = transformParamsToQuery(uid, pickSelectionParams(params));
const entry = await db.query(uid).delete({ ...query, where: { id: entityId } }); const entity = await db.query(uid).findOne({
...query,
const modelDef = strapi.getModel(uid); where: { id: entityId },
eventHub.emit(ENTRY_DELETE, {
model: modelDef.modelName,
entry: sanitizeEntity(entry, { model: modelDef }),
}); });
return entry; if (!entity) {
throw new Error('Entity not found');
}
await deleteComponents(uid, entityId);
await db.query(uid).delete({ where: { id: entity.id } });
this.emitEvent(uid, ENTRY_DELETE, entity);
return entity;
}, },
async deleteMany(uid, opts) { async deleteMany(uid, opts) {
const { params } = await this.wrapOptions(opts, { uid, action: 'delete' }); const { params } = await this.wrapOptions(opts, { uid, action: 'delete' });
// select / populate // select / populate
const query = transformParamsToQuery(pickSelectionParams(params)); const query = transformParamsToQuery(uid, pickSelectionParams(params));
return db.query(uid).deleteMany(query); return db.query(uid).deleteMany(query);
}, },
// TODO: Implement search features // TODO: Implement search features
async search(uid, opts) { async search(uid, opts) {
const { params, populate } = await this.wrapOptions(opts, { uid, action: 'search' }); const { params, populate } = await this.wrapOptions(opts, { uid, action: 'search' });
@ -350,6 +370,7 @@ const createComponents = async (uid, data) => {
const updateOrCreateComponent = (componentUID, value) => { const updateOrCreateComponent = (componentUID, value) => {
// update // update
if (has('id', value)) { if (has('id', value)) {
// TODO: verify the compo is associated with the entity
return strapi.query(componentUID).update({ where: { id: value.id }, data: value }); return strapi.query(componentUID).update({ where: { id: value.id }, data: value });
} }
@ -357,9 +378,8 @@ const updateOrCreateComponent = (componentUID, value) => {
return strapi.query(componentUID).create({ data: value }); return strapi.query(componentUID).create({ data: value });
}; };
const updateComponents = async (uid, data) => { // TODO: delete old components
// TODO: clear old -> done in the updateRelation const updateComponents = async (uid, entityId, data) => {
const { attributes } = strapi.getModel(uid); const { attributes } = strapi.getModel(uid);
for (const attributeName in attributes) { for (const attributeName in attributes) {
@ -372,8 +392,12 @@ const updateComponents = async (uid, data) => {
if (attribute.type === 'component') { if (attribute.type === 'component') {
const { component: componentUID, repeatable = false } = attribute; const { component: componentUID, repeatable = false } = attribute;
const previousValue = await strapi.query(uid).load(entityId, attributeName);
const componentValue = data[attributeName]; const componentValue = data[attributeName];
// TODO: diff prev & new
// make diff between prev ids & data ids
if (componentValue === null) { if (componentValue === null) {
continue; continue;
} }
@ -423,3 +447,39 @@ const updateComponents = async (uid, data) => {
} }
} }
}; };
const deleteComponents = async (uid, entityId) => {
const { attributes } = strapi.getModel(uid);
// TODO: find components and then delete them
for (const attributeName in attributes) {
const attribute = attributes[attributeName];
if (attribute.type === 'component') {
const { component: componentUID } = attribute;
// TODO: need to load before deleting the entry then delete the components then the entry
const value = await strapi.query(uid).load(entityId, attributeName);
if (!value) {
continue;
}
if (Array.isArray(value)) {
await Promise.all(
value.map(subValue => {
return strapi.query(componentUID).delete({ where: { id: subValue.id } });
})
);
} else {
await strapi.query(componentUID).delete({ where: { id: value.id } });
}
continue;
}
if (attribute.type === 'dynamiczone') {
continue;
}
}
};

View File

@ -80,6 +80,9 @@ describe('Core API - Basic + compo + draftAndPublish', () => {
method: 'POST', method: 'POST',
url: '/product-with-compo-and-dps', url: '/product-with-compo-and-dps',
body: product, body: product,
qs: {
populate: ['compo'],
},
}); });
expect(res.statusCode).toBe(200); expect(res.statusCode).toBe(200);
@ -92,6 +95,9 @@ describe('Core API - Basic + compo + draftAndPublish', () => {
const res = await rq({ const res = await rq({
method: 'GET', method: 'GET',
url: '/product-with-compo-and-dps', url: '/product-with-compo-and-dps',
qs: {
populate: ['compo'],
},
}); });
expect(res.statusCode).toBe(200); expect(res.statusCode).toBe(200);
@ -118,6 +124,9 @@ describe('Core API - Basic + compo + draftAndPublish', () => {
method: 'PUT', method: 'PUT',
url: `/product-with-compo-and-dps/${data.productsWithCompoAndDP[0].id}`, url: `/product-with-compo-and-dps/${data.productsWithCompoAndDP[0].id}`,
body: product, body: product,
qs: {
populate: ['compo'],
},
}); });
expect(res.statusCode).toBe(200); expect(res.statusCode).toBe(200);
@ -131,6 +140,9 @@ describe('Core API - Basic + compo + draftAndPublish', () => {
const res = await rq({ const res = await rq({
method: 'DELETE', method: 'DELETE',
url: `/product-with-compo-and-dps/${data.productsWithCompoAndDP[0].id}`, url: `/product-with-compo-and-dps/${data.productsWithCompoAndDP[0].id}`,
qs: {
populate: ['compo'],
},
}); });
expect(res.statusCode).toBe(200); expect(res.statusCode).toBe(200);

View File

@ -77,6 +77,9 @@ describe('Core API - Basic + compo + draftAndPublish', () => {
method: 'POST', method: 'POST',
url: '/product-with-compo-and-dps', url: '/product-with-compo-and-dps',
body: product, body: product,
qs: {
populate: ['compo'],
},
}); });
expect(res.statusCode).toBe(200); expect(res.statusCode).toBe(200);
@ -89,6 +92,9 @@ describe('Core API - Basic + compo + draftAndPublish', () => {
const res = await rq({ const res = await rq({
method: 'GET', method: 'GET',
url: '/product-with-compo-and-dps', url: '/product-with-compo-and-dps',
qs: {
populate: ['compo'],
},
}); });
expect(res.statusCode).toBe(200); expect(res.statusCode).toBe(200);
@ -113,6 +119,9 @@ describe('Core API - Basic + compo + draftAndPublish', () => {
method: 'PUT', method: 'PUT',
url: `/product-with-compo-and-dps/${data.productsWithCompoAndDP[0].id}`, url: `/product-with-compo-and-dps/${data.productsWithCompoAndDP[0].id}`,
body: product, body: product,
qs: {
populate: ['compo'],
},
}); });
expect(res.statusCode).toBe(200); expect(res.statusCode).toBe(200);
@ -126,6 +135,9 @@ describe('Core API - Basic + compo + draftAndPublish', () => {
const res = await rq({ const res = await rq({
method: 'DELETE', method: 'DELETE',
url: `/product-with-compo-and-dps/${data.productsWithCompoAndDP[0].id}`, url: `/product-with-compo-and-dps/${data.productsWithCompoAndDP[0].id}`,
qs: {
populate: ['compo'],
},
}); });
expect(res.statusCode).toBe(200); expect(res.statusCode).toBe(200);

View File

@ -122,7 +122,7 @@ const lengthFor = (name, { mode = 'live' } = {}) => {
const getQueryFromMode = mode => { const getQueryFromMode = mode => {
if (['live', 'preview'].includes(mode)) { if (['live', 'preview'].includes(mode)) {
return `?_publicationState=${mode}`; return `?publicationState=${mode}`;
} }
return ''; return '';
@ -188,7 +188,10 @@ describe('Publication State', () => {
beforeEach(async () => { beforeEach(async () => {
const res = await rq({ const res = await rq({
method: 'GET', method: 'GET',
url: `/${pluralizedModelName}?_publicationState=live`, url: `/${pluralizedModelName}?publicationState=live`,
qs: {
populate: ['categories', 'comp.countries'],
},
}); });
products = res.body; products = res.body;
}); });

View File

@ -168,9 +168,42 @@ const createContentType = (model, { modelName }, { apiName, pluginName } = {}) =
get() { get() {
// FIXME: to fix // FIXME: to fix
// return strapi.getModel(model.uid).privateAttributes; // return strapi.getModel(model.uid).privateAttributes;
return [] return [];
}, },
}); });
if (hasDraftAndPublish(model)) {
model.attributes[PUBLISHED_AT_ATTRIBUTE] = {
type: 'datetime',
configurable: false,
writable: true,
visible: false,
};
}
const isPrivate = !_.get(model, 'options.populateCreatorFields', false);
model.attributes[CREATED_BY_ATTRIBUTE] = {
type: 'relation',
relation: 'oneToOne',
target: 'strapi::user',
configurable: false,
writable: false,
visible: false,
useJoinTable: false,
private: isPrivate,
};
model.attributes[UPDATED_BY_ATTRIBUTE] = {
type: 'relation',
relation: 'oneToOne',
target: 'strapi::user',
configurable: false,
writable: false,
visible: false,
useJoinTable: false,
private: isPrivate,
};
}; };
const getGlobalId = (model, modelName, prefix) => { const getGlobalId = (model, modelName, prefix) => {