2020-10-28 18:47:14 +01:00
|
|
|
'use strict';
|
|
|
|
|
2023-05-25 14:36:50 +02:00
|
|
|
const { omit } = require('lodash/fp');
|
2021-04-29 13:51:12 +02:00
|
|
|
const strapiUtils = require('@strapi/utils');
|
2023-02-13 11:06:57 +00:00
|
|
|
const { mapAsync } = require('@strapi/utils');
|
2021-10-20 17:30:05 +02:00
|
|
|
const { ApplicationError } = require('@strapi/utils').errors;
|
2023-05-26 17:26:55 +02:00
|
|
|
const { getService } = require('../utils');
|
2022-10-05 18:42:50 +02:00
|
|
|
const { getDeepPopulate, getDeepPopulateDraftCount } = require('./utils/populate');
|
2023-01-16 18:20:42 +01:00
|
|
|
const { getDeepRelationsCount } = require('./utils/count');
|
2022-10-05 18:42:50 +02:00
|
|
|
const { sumDraftCounts } = require('./utils/draft');
|
2023-05-26 17:26:55 +02:00
|
|
|
const { isWebhooksPopulateRelationsEnabled } = require('./utils/populate');
|
2023-06-01 15:20:13 +01:00
|
|
|
const {
|
|
|
|
ALLOWED_WEBHOOK_EVENTS: { ENTRY_PUBLISH, ENTRY_UNPUBLISH },
|
|
|
|
} = require('../constants');
|
2020-10-28 18:47:14 +01:00
|
|
|
|
2022-10-05 18:42:50 +02:00
|
|
|
const { hasDraftAndPublish } = strapiUtils.contentTypes;
|
2023-05-25 14:36:50 +02:00
|
|
|
const { PUBLISHED_AT_ATTRIBUTE } = strapiUtils.contentTypes.constants;
|
2020-10-28 18:47:14 +01:00
|
|
|
|
|
|
|
const omitPublishedAtField = omit(PUBLISHED_AT_ATTRIBUTE);
|
|
|
|
|
2023-06-01 15:20:13 +01:00
|
|
|
const emitEvent = async (uid, event, entity) => {
|
2023-05-30 16:13:10 +01:00
|
|
|
const modelDef = strapi.getModel(uid);
|
2021-11-10 17:08:54 +01:00
|
|
|
const sanitizedEntity = await strapiUtils.sanitize.sanitizers.defaultSanitizeOutput(
|
|
|
|
modelDef,
|
|
|
|
entity
|
|
|
|
);
|
2020-10-28 18:47:14 +01:00
|
|
|
|
|
|
|
strapi.eventHub.emit(event, {
|
|
|
|
model: modelDef.modelName,
|
2021-11-05 10:36:10 +01:00
|
|
|
entry: sanitizedEntity,
|
2020-10-28 18:47:14 +01:00
|
|
|
});
|
|
|
|
};
|
|
|
|
|
2023-05-29 09:34:45 +02:00
|
|
|
const buildDeepPopulate = (uid) => {
|
2023-05-26 12:35:22 +02:00
|
|
|
// User can configure to populate relations, so downstream services can use them.
|
|
|
|
// They will be transformed into counts later if this is set to true.
|
2023-05-26 17:26:55 +02:00
|
|
|
return getService('populate-builder')(uid)
|
2023-05-26 12:35:22 +02:00
|
|
|
.populateDeep(Infinity)
|
2023-06-19 12:34:24 +02:00
|
|
|
.countRelationsIf(!isWebhooksPopulateRelationsEnabled(uid))
|
2023-05-26 12:35:22 +02:00
|
|
|
.build();
|
|
|
|
};
|
|
|
|
|
2021-09-21 17:18:24 +02:00
|
|
|
/**
|
|
|
|
* @type {import('./entity-manager').default}
|
|
|
|
*/
|
2021-07-13 18:46:36 +02:00
|
|
|
module.exports = ({ strapi }) => ({
|
2023-02-13 11:06:57 +00:00
|
|
|
/**
|
|
|
|
* Extend this function from other plugins to add custom mapping of entity
|
|
|
|
* responses
|
|
|
|
* @param {Object} entity
|
|
|
|
* @returns
|
|
|
|
*/
|
|
|
|
mapEntity(entity) {
|
|
|
|
return entity;
|
|
|
|
},
|
|
|
|
|
2023-02-27 11:50:49 +00:00
|
|
|
/**
|
2023-03-01 11:31:52 +00:00
|
|
|
* Some entity manager functions may return multiple entities or one entity.
|
2023-02-27 11:50:49 +00:00
|
|
|
* This function maps the response in both cases
|
|
|
|
* @param {Array|Object|null} entities
|
|
|
|
* @param {string} uid
|
|
|
|
*/
|
2023-03-01 11:31:52 +00:00
|
|
|
async mapEntitiesResponse(entities, uid) {
|
2023-02-27 11:50:49 +00:00
|
|
|
if (entities?.results) {
|
|
|
|
const mappedResults = await mapAsync(entities.results, (entity) =>
|
|
|
|
this.mapEntity(entity, uid)
|
|
|
|
);
|
|
|
|
return { ...entities, results: mappedResults };
|
|
|
|
}
|
|
|
|
// if entity is single type
|
|
|
|
return this.mapEntity(entities, uid);
|
|
|
|
},
|
|
|
|
|
2023-02-13 11:06:57 +00:00
|
|
|
async find(opts, uid) {
|
2022-11-16 15:06:55 +01:00
|
|
|
const params = { ...opts, populate: getDeepPopulate(uid) };
|
2023-02-13 11:06:57 +00:00
|
|
|
const entities = await strapi.entityService.findMany(uid, params);
|
2023-03-01 11:31:52 +00:00
|
|
|
return this.mapEntitiesResponse(entities, uid);
|
2020-10-28 18:47:14 +01:00
|
|
|
},
|
|
|
|
|
2023-02-13 11:06:57 +00:00
|
|
|
async findPage(opts, uid) {
|
2023-05-25 14:36:50 +02:00
|
|
|
const entities = await strapi.entityService.findPage(uid, opts);
|
2023-03-01 11:31:52 +00:00
|
|
|
return this.mapEntitiesResponse(entities, uid);
|
2020-12-16 15:28:11 +01:00
|
|
|
},
|
|
|
|
|
2023-05-25 14:36:50 +02:00
|
|
|
async findOne(id, uid, opts = {}) {
|
2023-02-14 09:11:10 +01:00
|
|
|
return strapi.entityService
|
2023-05-25 14:36:50 +02:00
|
|
|
.findOne(uid, id, opts)
|
2023-02-14 09:11:10 +01:00
|
|
|
.then((entity) => this.mapEntity(entity, uid));
|
2022-08-26 10:41:31 +02:00
|
|
|
},
|
|
|
|
|
2023-05-26 12:35:22 +02:00
|
|
|
async create(body, uid) {
|
2021-06-30 20:00:03 +02:00
|
|
|
const modelDef = strapi.getModel(uid);
|
2020-11-03 10:00:50 +01:00
|
|
|
const publishData = { ...body };
|
2023-05-29 09:34:45 +02:00
|
|
|
const populate = await buildDeepPopulate(uid);
|
2020-10-28 18:47:14 +01:00
|
|
|
|
|
|
|
if (hasDraftAndPublish(modelDef)) {
|
|
|
|
publishData[PUBLISHED_AT_ATTRIBUTE] = null;
|
|
|
|
}
|
|
|
|
|
2023-05-26 12:35:22 +02:00
|
|
|
const params = { data: publishData, populate };
|
2021-07-08 18:15:32 +02:00
|
|
|
|
2023-02-14 09:11:10 +01:00
|
|
|
const entity = await strapi.entityService
|
|
|
|
.create(uid, params)
|
|
|
|
.then((entity) => this.mapEntity(entity, uid));
|
2023-01-10 15:15:01 +01:00
|
|
|
|
2023-05-26 17:26:55 +02:00
|
|
|
if (isWebhooksPopulateRelationsEnabled(uid)) {
|
2023-01-16 18:20:42 +01:00
|
|
|
return getDeepRelationsCount(entity, uid);
|
2023-01-12 14:31:04 +01:00
|
|
|
}
|
|
|
|
|
2023-02-14 18:20:16 +01:00
|
|
|
return entity;
|
2020-10-28 18:47:14 +01:00
|
|
|
},
|
|
|
|
|
2023-05-26 12:35:22 +02:00
|
|
|
async update(entity, body, uid) {
|
2020-11-03 10:00:50 +01:00
|
|
|
const publishData = omitPublishedAtField(body);
|
2023-05-29 09:34:45 +02:00
|
|
|
const populate = await buildDeepPopulate(uid);
|
2023-05-26 12:35:22 +02:00
|
|
|
const params = { data: publishData, populate };
|
2021-07-08 18:15:32 +02:00
|
|
|
|
2023-02-14 09:11:10 +01:00
|
|
|
const updatedEntity = await strapi.entityService
|
|
|
|
.update(uid, entity.id, params)
|
|
|
|
.then((entity) => this.mapEntity(entity, uid));
|
2023-01-10 15:15:01 +01:00
|
|
|
|
2023-05-26 17:26:55 +02:00
|
|
|
if (isWebhooksPopulateRelationsEnabled(uid)) {
|
2023-01-16 18:20:42 +01:00
|
|
|
return getDeepRelationsCount(updatedEntity, uid);
|
2023-01-12 14:31:04 +01:00
|
|
|
}
|
|
|
|
|
2023-02-14 09:11:10 +01:00
|
|
|
return updatedEntity;
|
2020-10-28 18:47:14 +01:00
|
|
|
},
|
2023-03-28 11:07:02 +02:00
|
|
|
async clone(entity, body, uid) {
|
|
|
|
const modelDef = strapi.getModel(uid);
|
|
|
|
const publishData = { ...body };
|
|
|
|
const populateRelations = isRelationsPopulateEnabled(uid);
|
|
|
|
|
|
|
|
if (hasDraftAndPublish(modelDef)) {
|
|
|
|
publishData[PUBLISHED_AT_ATTRIBUTE] = null;
|
|
|
|
}
|
2020-10-28 18:47:14 +01:00
|
|
|
|
2023-03-28 11:07:02 +02:00
|
|
|
const params = {
|
|
|
|
data: publishData,
|
|
|
|
populate: populateRelations
|
|
|
|
? getDeepPopulate(uid, {})
|
|
|
|
: getDeepPopulate(uid, { countMany: true, countOne: true }),
|
|
|
|
};
|
|
|
|
|
|
|
|
const clonedEntity = await strapi.entityService.clone(uid, entity.id, params);
|
|
|
|
|
|
|
|
// If relations were populated, relations count will be returned instead of the array of relations.
|
|
|
|
if (populateRelations) {
|
|
|
|
return getDeepRelationsCount(clonedEntity, uid);
|
|
|
|
}
|
|
|
|
|
|
|
|
return clonedEntity;
|
|
|
|
},
|
2023-05-29 09:34:45 +02:00
|
|
|
async delete(entity, uid) {
|
|
|
|
const populate = await buildDeepPopulate(uid);
|
|
|
|
const deletedEntity = await strapi.entityService.delete(uid, entity.id, { populate });
|
2023-01-16 18:20:42 +01:00
|
|
|
|
2023-01-30 16:35:45 +01:00
|
|
|
// If relations were populated, relations count will be returned instead of the array of relations.
|
2023-05-26 17:26:55 +02:00
|
|
|
if (isWebhooksPopulateRelationsEnabled(uid)) {
|
2023-01-16 18:20:42 +01:00
|
|
|
return getDeepRelationsCount(deletedEntity, uid);
|
2023-01-12 14:31:04 +01:00
|
|
|
}
|
2023-01-10 15:15:01 +01:00
|
|
|
|
2023-01-16 18:20:42 +01:00
|
|
|
return deletedEntity;
|
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) {
|
2023-05-25 14:36:50 +02:00
|
|
|
return strapi.entityService.deleteMany(uid, opts);
|
2020-11-03 10:00:50 +01:00
|
|
|
},
|
|
|
|
|
2023-06-01 15:21:47 +01:00
|
|
|
async publish(entity, uid, body = {}) {
|
2020-11-02 19:39:48 +01:00
|
|
|
if (entity[PUBLISHED_AT_ATTRIBUTE]) {
|
2021-10-20 17:30:05 +02:00
|
|
|
throw new ApplicationError('already.published');
|
2020-11-02 19:39:48 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// validate the entity is valid for publication
|
2021-11-29 19:22:49 +01:00
|
|
|
await strapi.entityValidator.validateEntityCreation(
|
|
|
|
strapi.getModel(uid),
|
|
|
|
entity,
|
|
|
|
undefined,
|
|
|
|
entity
|
|
|
|
);
|
2020-11-02 19:39:48 +01:00
|
|
|
|
2021-11-18 16:13:28 +01:00
|
|
|
const data = { ...body, [PUBLISHED_AT_ATTRIBUTE]: new Date() };
|
2023-05-29 09:34:45 +02:00
|
|
|
const populate = await buildDeepPopulate(uid);
|
2023-05-25 14:36:50 +02:00
|
|
|
|
2023-05-26 12:35:22 +02:00
|
|
|
const params = { data, populate };
|
2021-07-08 18:15:32 +02:00
|
|
|
|
2023-01-30 16:35:45 +01:00
|
|
|
const updatedEntity = await strapi.entityService.update(uid, entity.id, params);
|
|
|
|
|
2023-06-01 15:20:13 +01:00
|
|
|
await emitEvent(uid, ENTRY_PUBLISH, updatedEntity);
|
2023-01-30 16:35:45 +01:00
|
|
|
|
2023-02-14 09:11:10 +01:00
|
|
|
const mappedEntity = await this.mapEntity(updatedEntity, uid);
|
|
|
|
|
2023-01-30 16:35:45 +01:00
|
|
|
// If relations were populated, relations count will be returned instead of the array of relations.
|
2023-05-26 17:26:55 +02:00
|
|
|
if (isWebhooksPopulateRelationsEnabled(uid)) {
|
2023-02-14 09:11:10 +01:00
|
|
|
return getDeepRelationsCount(mappedEntity, uid);
|
2023-01-30 16:35:45 +01:00
|
|
|
}
|
|
|
|
|
2023-02-14 09:11:10 +01:00
|
|
|
return mappedEntity;
|
2023-01-30 16:35:45 +01:00
|
|
|
},
|
2020-10-28 18:47:14 +01:00
|
|
|
|
2023-05-04 10:38:09 +02:00
|
|
|
async publishMany(entities, uid) {
|
|
|
|
if (!entities.length) {
|
2023-04-28 09:46:04 +02:00
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Validate entities before publishing, throw if invalid
|
|
|
|
await Promise.all(
|
2023-06-09 10:32:42 +02:00
|
|
|
entities.map((entity) => {
|
2023-05-04 10:38:09 +02:00
|
|
|
return strapi.entityValidator.validateEntityCreation(
|
2023-04-28 09:46:04 +02:00
|
|
|
strapi.getModel(uid),
|
2023-06-09 10:32:42 +02:00
|
|
|
entity,
|
2023-06-19 17:39:31 +02:00
|
|
|
undefined,
|
2023-06-09 10:32:42 +02:00
|
|
|
entity
|
2023-05-04 10:38:09 +02:00
|
|
|
);
|
|
|
|
})
|
2023-04-28 09:46:04 +02:00
|
|
|
);
|
|
|
|
|
2023-05-09 09:54:53 +02:00
|
|
|
// Only publish entities without a published_at date
|
|
|
|
const entitiesToPublish = entities
|
|
|
|
.filter((entity) => !entity[PUBLISHED_AT_ATTRIBUTE])
|
|
|
|
.map((entity) => entity.id);
|
2023-06-01 11:24:07 +02:00
|
|
|
|
|
|
|
const filters = { id: { $in: entitiesToPublish } };
|
2023-06-09 10:32:42 +02:00
|
|
|
const data = { [PUBLISHED_AT_ATTRIBUTE]: new Date() };
|
|
|
|
const populate = await buildDeepPopulate(uid);
|
|
|
|
|
2023-05-04 10:38:09 +02:00
|
|
|
// Everything is valid, publish
|
|
|
|
const publishedEntitiesCount = await strapi.db.query(uid).updateMany({
|
2023-06-01 11:24:07 +02:00
|
|
|
where: filters,
|
2023-05-04 10:38:09 +02:00
|
|
|
data,
|
|
|
|
});
|
2023-04-28 09:46:04 +02:00
|
|
|
// Get the updated entities since updateMany only returns the count
|
2023-06-01 11:24:07 +02:00
|
|
|
const publishedEntities = await strapi.entityService.findMany(uid, { filters, populate });
|
2023-04-28 09:46:04 +02:00
|
|
|
// Emit the publish event for all updated entities
|
2023-06-07 11:43:09 +01:00
|
|
|
await Promise.all(publishedEntities.map((entity) => emitEvent(uid, ENTRY_PUBLISH, entity)));
|
2023-04-28 09:46:04 +02:00
|
|
|
|
|
|
|
// Return the number of published entities
|
|
|
|
return publishedEntitiesCount;
|
|
|
|
},
|
|
|
|
|
2023-05-04 10:38:09 +02:00
|
|
|
async unpublishMany(entities, uid) {
|
|
|
|
if (!entities.length) {
|
2023-04-28 09:46:04 +02:00
|
|
|
return null;
|
|
|
|
}
|
2023-06-01 11:24:07 +02:00
|
|
|
|
|
|
|
// Only unpublish entities with a published_at date
|
|
|
|
const entitiesToUnpublish = entities
|
|
|
|
.filter((entity) => entity[PUBLISHED_AT_ATTRIBUTE])
|
|
|
|
.map((entity) => entity.id);
|
|
|
|
|
|
|
|
const filters = { id: { $in: entitiesToUnpublish } };
|
2023-06-09 10:32:42 +02:00
|
|
|
const data = { [PUBLISHED_AT_ATTRIBUTE]: null };
|
|
|
|
const populate = await buildDeepPopulate(uid);
|
2023-05-04 10:38:09 +02:00
|
|
|
|
|
|
|
// No need to validate, unpublish
|
|
|
|
const unpublishedEntitiesCount = await strapi.db.query(uid).updateMany({
|
2023-06-01 11:24:07 +02:00
|
|
|
where: filters,
|
2023-05-04 10:38:09 +02:00
|
|
|
data,
|
|
|
|
});
|
2023-04-28 09:46:04 +02:00
|
|
|
// Get the updated entities since updateMany only returns the count
|
2023-06-01 11:24:07 +02:00
|
|
|
const unpublishedEntities = await strapi.entityService.findMany(uid, { filters, populate });
|
2023-04-28 09:46:04 +02:00
|
|
|
// Emit the unpublish event for all updated entities
|
2023-06-07 11:43:09 +01:00
|
|
|
await Promise.all(unpublishedEntities.map((entity) => emitEvent(uid, ENTRY_UNPUBLISH, entity)));
|
2023-04-28 09:46:04 +02:00
|
|
|
|
|
|
|
// Return the number of unpublished entities
|
|
|
|
return unpublishedEntitiesCount;
|
|
|
|
},
|
|
|
|
|
2023-06-01 15:21:47 +01:00
|
|
|
async unpublish(entity, uid, body = {}) {
|
2020-11-02 19:39:48 +01:00
|
|
|
if (!entity[PUBLISHED_AT_ATTRIBUTE]) {
|
2021-10-20 17:30:05 +02:00
|
|
|
throw new ApplicationError('already.draft');
|
2020-11-02 19:39:48 +01:00
|
|
|
}
|
|
|
|
|
2021-11-18 16:13:28 +01:00
|
|
|
const data = { ...body, [PUBLISHED_AT_ATTRIBUTE]: null };
|
2023-05-29 09:34:45 +02:00
|
|
|
const populate = await buildDeepPopulate(uid);
|
2020-10-28 18:47:14 +01:00
|
|
|
|
2023-05-26 12:35:22 +02:00
|
|
|
const params = { data, populate };
|
2021-07-08 18:15:32 +02:00
|
|
|
|
2023-01-30 16:35:45 +01:00
|
|
|
const updatedEntity = await strapi.entityService.update(uid, entity.id, params);
|
|
|
|
|
2023-06-01 15:20:13 +01:00
|
|
|
await emitEvent(uid, ENTRY_UNPUBLISH, updatedEntity);
|
2023-01-30 16:35:45 +01:00
|
|
|
|
2023-02-14 09:11:10 +01:00
|
|
|
const mappedEntity = await this.mapEntity(updatedEntity, uid);
|
|
|
|
|
2023-01-30 16:35:45 +01:00
|
|
|
// If relations were populated, relations count will be returned instead of the array of relations.
|
2023-05-26 17:26:55 +02:00
|
|
|
if (isWebhooksPopulateRelationsEnabled(uid)) {
|
2023-02-14 09:11:10 +01:00
|
|
|
return getDeepRelationsCount(mappedEntity, uid);
|
2023-01-30 16:35:45 +01:00
|
|
|
}
|
|
|
|
|
2023-02-14 09:11:10 +01:00
|
|
|
return mappedEntity;
|
2023-01-30 16:35:45 +01:00
|
|
|
},
|
2022-10-05 18:42:50 +02:00
|
|
|
|
|
|
|
async getNumberOfDraftRelations(id, uid) {
|
|
|
|
const { populate, hasRelations } = getDeepPopulateDraftCount(uid);
|
|
|
|
|
|
|
|
if (!hasRelations) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
const entity = await strapi.entityService.findOne(uid, id, { populate });
|
|
|
|
|
|
|
|
return sumDraftCounts(entity, uid);
|
|
|
|
},
|
2021-07-13 18:46:36 +02:00
|
|
|
});
|