2020-10-28 18:47:14 +01:00
|
|
|
'use strict';
|
|
|
|
|
|
|
|
const { assoc, has, prop, omit } = require('lodash/fp');
|
2021-04-29 13:51:12 +02:00
|
|
|
const strapiUtils = require('@strapi/utils');
|
2020-10-28 18:47:14 +01:00
|
|
|
|
|
|
|
const { sanitizeEntity } = strapiUtils;
|
2021-09-27 11:07:41 +02:00
|
|
|
const { hasDraftAndPublish, isVisibleAttribute } = strapiUtils.contentTypes;
|
2020-10-28 18:47:14 +01:00
|
|
|
const { PUBLISHED_AT_ATTRIBUTE, CREATED_BY_ATTRIBUTE } = strapiUtils.contentTypes.constants;
|
|
|
|
const { ENTRY_PUBLISH, ENTRY_UNPUBLISH } = strapiUtils.webhook.webhookEvents;
|
2021-09-24 15:40:02 +02:00
|
|
|
const { MANY_RELATIONS } = strapiUtils.relations.constants;
|
2020-10-28 18:47:14 +01:00
|
|
|
|
|
|
|
const omitPublishedAtField = omit(PUBLISHED_AT_ATTRIBUTE);
|
|
|
|
|
2021-09-21 17:18:24 +02:00
|
|
|
const wrapWithEmitEvent = (event, fn) => async (entity, model) => {
|
2020-10-28 18:47:14 +01:00
|
|
|
const result = await fn(entity, model);
|
|
|
|
|
|
|
|
const modelDef = strapi.getModel(model);
|
|
|
|
|
|
|
|
strapi.eventHub.emit(event, {
|
|
|
|
model: modelDef.modelName,
|
|
|
|
entry: sanitizeEntity(result, { model: modelDef }),
|
|
|
|
});
|
|
|
|
|
|
|
|
return result;
|
|
|
|
};
|
|
|
|
|
|
|
|
const findCreatorRoles = entity => {
|
|
|
|
const createdByPath = `${CREATED_BY_ATTRIBUTE}.id`;
|
|
|
|
|
|
|
|
if (has(createdByPath, entity)) {
|
|
|
|
const creatorId = prop(createdByPath, entity);
|
2021-08-23 22:25:31 +02:00
|
|
|
return strapi.query('admin::role').findMany({ where: { users: { id: creatorId } } });
|
2020-10-28 18:47:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return [];
|
|
|
|
};
|
|
|
|
|
2021-07-28 15:32:21 +02:00
|
|
|
// TODO: define when we use this one vs basic populate
|
|
|
|
const getDeepPopulate = (uid, populate, depth = 0) => {
|
|
|
|
if (populate) {
|
|
|
|
return populate;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (depth > 2) {
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
|
|
|
const { attributes } = strapi.getModel(uid);
|
|
|
|
|
|
|
|
return Object.keys(attributes).reduce((populateAcc, attributeName) => {
|
|
|
|
const attribute = attributes[attributeName];
|
|
|
|
|
|
|
|
if (attribute.type === 'relation') {
|
|
|
|
populateAcc[attributeName] = attribute.target
|
|
|
|
? { populate: getDeepPopulate(attribute.target, null, depth + 1) }
|
|
|
|
: true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (attribute.type === 'component') {
|
|
|
|
populateAcc[attributeName] = {
|
|
|
|
populate: getDeepPopulate(attribute.component, null, depth + 1),
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2021-07-30 20:45:51 +02:00
|
|
|
if (attribute.type === 'media') {
|
|
|
|
populateAcc[attributeName] = true;
|
|
|
|
}
|
|
|
|
|
2021-07-28 15:32:21 +02:00
|
|
|
if (attribute.type === 'dynamiczone') {
|
|
|
|
populateAcc[attributeName] = {
|
|
|
|
populate: (attribute.components || []).reduce((acc, componentUID) => {
|
|
|
|
return Object.assign(acc, getDeepPopulate(componentUID, null, depth + 1));
|
|
|
|
}, {}),
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
return populateAcc;
|
|
|
|
}, {});
|
|
|
|
};
|
|
|
|
|
|
|
|
// TODO: define when we use this one vs deep populate
|
|
|
|
const getBasePopulate = (uid, populate) => {
|
|
|
|
if (populate) {
|
|
|
|
return populate;
|
|
|
|
}
|
|
|
|
|
2021-07-08 18:15:32 +02:00
|
|
|
const { attributes } = strapi.getModel(uid);
|
|
|
|
|
|
|
|
return Object.keys(attributes).filter(attributeName => {
|
2021-07-30 20:45:51 +02:00
|
|
|
return ['relation', 'component', 'dynamiczone', 'media'].includes(
|
|
|
|
attributes[attributeName].type
|
|
|
|
);
|
2021-07-08 18:15:32 +02:00
|
|
|
});
|
|
|
|
};
|
|
|
|
|
2021-09-24 15:40:02 +02:00
|
|
|
const getCounterPopulate = (uid, populate) => {
|
|
|
|
const basePopulate = getBasePopulate(uid, populate);
|
|
|
|
|
2021-09-27 11:07:41 +02:00
|
|
|
const model = strapi.getModel(uid);
|
2021-09-24 15:40:02 +02:00
|
|
|
|
|
|
|
return basePopulate.reduce((populate, attributeName) => {
|
2021-09-27 11:07:41 +02:00
|
|
|
const attribute = model.attributes[attributeName];
|
2021-09-24 15:40:02 +02:00
|
|
|
|
2021-09-27 11:07:41 +02:00
|
|
|
if (MANY_RELATIONS.includes(attribute.relation) && isVisibleAttribute(model, attributeName)) {
|
2021-09-24 15:40:02 +02:00
|
|
|
populate[attributeName] = { count: true };
|
|
|
|
} else {
|
|
|
|
populate[attributeName] = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return populate;
|
|
|
|
}, {});
|
|
|
|
};
|
|
|
|
|
|
|
|
const addCreatedByRolesPopulate = populate => {
|
|
|
|
return {
|
|
|
|
...populate,
|
|
|
|
createdBy: {
|
|
|
|
populate: ['roles'],
|
|
|
|
},
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2021-09-21 17:18:24 +02:00
|
|
|
/**
|
|
|
|
* @type {import('./entity-manager').default}
|
|
|
|
*/
|
2021-07-13 18:46:36 +02:00
|
|
|
module.exports = ({ strapi }) => ({
|
2020-11-02 12:40:35 +01:00
|
|
|
async assocCreatorRoles(entity) {
|
2020-10-28 18:47:14 +01:00
|
|
|
if (!entity) {
|
|
|
|
return entity;
|
|
|
|
}
|
|
|
|
|
|
|
|
const roles = await findCreatorRoles(entity);
|
|
|
|
return assoc(`${CREATED_BY_ATTRIBUTE}.roles`, roles, entity);
|
|
|
|
},
|
|
|
|
|
2021-06-30 20:00:03 +02:00
|
|
|
find(opts, uid, populate) {
|
2021-07-28 15:32:21 +02:00
|
|
|
const params = { ...opts, populate: getDeepPopulate(uid, populate) };
|
2021-06-30 20:00:03 +02:00
|
|
|
|
2021-09-21 17:18:24 +02:00
|
|
|
return strapi.entityService.findMany(uid, params);
|
2020-10-28 18:47:14 +01:00
|
|
|
},
|
|
|
|
|
2021-06-30 20:00:03 +02:00
|
|
|
findPage(opts, uid, populate) {
|
2021-07-28 15:32:21 +02:00
|
|
|
const params = { ...opts, populate: getBasePopulate(uid, populate) };
|
2021-06-30 20:00:03 +02:00
|
|
|
|
2021-09-21 17:18:24 +02:00
|
|
|
return strapi.entityService.findPage(uid, params);
|
2020-11-02 22:10:51 +01:00
|
|
|
},
|
|
|
|
|
2021-06-30 20:00:03 +02:00
|
|
|
findWithRelationCounts(opts, uid, populate) {
|
2021-09-24 15:40:02 +02:00
|
|
|
const counterPopulate = addCreatedByRolesPopulate(getCounterPopulate(uid, populate));
|
|
|
|
const params = { ...opts, populate: counterPopulate };
|
2021-06-30 20:00:03 +02:00
|
|
|
|
2021-09-21 17:18:24 +02:00
|
|
|
return strapi.entityService.findWithRelationCounts(uid, params);
|
2020-12-16 15:28:11 +01:00
|
|
|
},
|
|
|
|
|
2021-06-30 20:00:03 +02:00
|
|
|
async findOne(id, uid, populate) {
|
2021-07-30 20:45:51 +02:00
|
|
|
const params = { populate: getDeepPopulate(uid, populate) };
|
2021-07-08 18:15:32 +02:00
|
|
|
|
2021-09-21 17:18:24 +02:00
|
|
|
return strapi.entityService.findOne(uid, id, params);
|
2020-10-28 18:47:14 +01:00
|
|
|
},
|
|
|
|
|
2021-06-30 20:00:03 +02:00
|
|
|
async findOneWithCreatorRoles(id, uid, populate) {
|
|
|
|
const entity = await this.findOne(id, uid, populate);
|
2020-10-28 18:47:14 +01:00
|
|
|
|
|
|
|
if (!entity) {
|
|
|
|
return entity;
|
|
|
|
}
|
|
|
|
|
2020-11-02 12:40:35 +01:00
|
|
|
return this.assocCreatorRoles(entity);
|
2020-10-28 18:47:14 +01:00
|
|
|
},
|
|
|
|
|
2021-06-30 20:00:03 +02:00
|
|
|
async create(body, uid) {
|
|
|
|
const modelDef = strapi.getModel(uid);
|
2020-11-03 10:00:50 +01:00
|
|
|
const publishData = { ...body };
|
2020-10-28 18:47:14 +01:00
|
|
|
|
|
|
|
if (hasDraftAndPublish(modelDef)) {
|
|
|
|
publishData[PUBLISHED_AT_ATTRIBUTE] = null;
|
|
|
|
}
|
|
|
|
|
2021-09-21 17:18:24 +02:00
|
|
|
const params = { data: publishData, populate: getDeepPopulate(uid) };
|
2021-07-08 18:15:32 +02:00
|
|
|
|
2021-09-21 17:18:24 +02:00
|
|
|
return strapi.entityService.create(uid, params);
|
2020-10-28 18:47:14 +01:00
|
|
|
},
|
|
|
|
|
2021-06-30 20:00:03 +02:00
|
|
|
update(entity, body, uid) {
|
2020-11-03 10:00:50 +01:00
|
|
|
const publishData = omitPublishedAtField(body);
|
2020-10-28 18:47:14 +01:00
|
|
|
|
2021-09-21 17:18:24 +02:00
|
|
|
const params = { data: publishData, populate: getDeepPopulate(uid) };
|
2021-07-08 18:15:32 +02:00
|
|
|
|
2021-09-21 17:18:24 +02:00
|
|
|
return strapi.entityService.update(uid, entity.id, params);
|
2020-10-28 18:47:14 +01:00
|
|
|
},
|
|
|
|
|
2021-06-30 20:00:03 +02:00
|
|
|
delete(entity, uid) {
|
2021-07-30 20:45:51 +02:00
|
|
|
const params = { populate: getDeepPopulate(uid) };
|
2021-07-08 18:15:32 +02:00
|
|
|
|
2021-09-21 17:18:24 +02:00
|
|
|
return strapi.entityService.delete(uid, entity.id, params);
|
2020-10-28 18:47:14 +01:00
|
|
|
},
|
|
|
|
|
2021-07-08 18:15:32 +02:00
|
|
|
// FIXME: handle relations
|
2021-07-05 23:31:23 +02:00
|
|
|
deleteMany(opts, uid) {
|
2021-06-30 20:00:03 +02:00
|
|
|
const params = { ...opts };
|
|
|
|
|
2021-09-21 17:18:24 +02:00
|
|
|
return strapi.entityService.deleteMany(uid, params);
|
2020-11-03 10:00:50 +01:00
|
|
|
},
|
|
|
|
|
2021-09-21 17:18:24 +02:00
|
|
|
publish: wrapWithEmitEvent(ENTRY_PUBLISH, async (entity, uid) => {
|
2020-11-02 19:39:48 +01:00
|
|
|
if (entity[PUBLISHED_AT_ATTRIBUTE]) {
|
|
|
|
throw strapi.errors.badRequest('already.published');
|
|
|
|
}
|
|
|
|
|
|
|
|
// validate the entity is valid for publication
|
2021-06-30 20:00:03 +02:00
|
|
|
await strapi.entityValidator.validateEntityCreation(strapi.getModel(uid), entity);
|
2020-11-02 19:39:48 +01:00
|
|
|
|
2020-10-28 18:47:14 +01:00
|
|
|
const data = { [PUBLISHED_AT_ATTRIBUTE]: new Date() };
|
|
|
|
|
2021-09-21 17:18:24 +02:00
|
|
|
const params = { data, populate: getDeepPopulate(uid) };
|
2021-07-08 18:15:32 +02:00
|
|
|
|
2021-09-21 17:18:24 +02:00
|
|
|
return strapi.entityService.update(uid, entity.id, params);
|
2020-10-28 18:47:14 +01:00
|
|
|
}),
|
|
|
|
|
2021-09-21 17:18:24 +02:00
|
|
|
unpublish: wrapWithEmitEvent(ENTRY_UNPUBLISH, (entity, uid) => {
|
2020-11-02 19:39:48 +01:00
|
|
|
if (!entity[PUBLISHED_AT_ATTRIBUTE]) {
|
|
|
|
throw strapi.errors.badRequest('already.draft');
|
|
|
|
}
|
|
|
|
|
2020-10-28 18:47:14 +01:00
|
|
|
const data = { [PUBLISHED_AT_ATTRIBUTE]: null };
|
|
|
|
|
2021-09-21 17:18:24 +02:00
|
|
|
const params = { data, populate: getDeepPopulate(uid) };
|
2021-07-08 18:15:32 +02:00
|
|
|
|
2021-09-21 17:18:24 +02:00
|
|
|
return strapi.entityService.update(uid, entity.id, params);
|
2020-10-28 18:47:14 +01:00
|
|
|
}),
|
2021-07-13 18:46:36 +02:00
|
|
|
});
|