Merge remote-tracking branch 'origin/main' into webhooks/edit-view

This commit is contained in:
Jamie Howard 2023-06-02 11:14:18 +01:00
commit 96bfeca3db
20 changed files with 141 additions and 66 deletions

View File

@ -71,6 +71,9 @@ const strapiMock = {
return null; return null;
} }
}, },
webhookStore: {
addAllowedEvent: jest.fn(),
},
}; };
const reviewWorkflowsService = reviewWorkflowsServiceFactory({ strapi: strapiMock }); const reviewWorkflowsService = reviewWorkflowsServiceFactory({ strapi: strapiMock });

View File

@ -108,12 +108,16 @@ function persistStagesJoinTables({ strapi }) {
}; };
} }
const registerWebhookEvents = async ({ strapi }) =>
strapi.webhookStore.addAllowedEvent('WORKFLOW_UPDATE_STAGE', 'workflow.updateEntryStage');
module.exports = ({ strapi }) => { module.exports = ({ strapi }) => {
const workflowsService = getService('workflows', { strapi }); const workflowsService = getService('workflows', { strapi });
const stagesService = getService('stages', { strapi }); const stagesService = getService('stages', { strapi });
return { return {
async bootstrap() { async bootstrap() {
await registerWebhookEvents({ strapi });
await initDefaultWorkflow({ workflowsService, stagesService, strapi }); await initDefaultWorkflow({ workflowsService, stagesService, strapi });
}, },
async register() { async register() {

View File

@ -1,7 +1,7 @@
'use strict'; 'use strict';
const _ = require('lodash'); const _ = require('lodash');
const { yup, webhook: webhookUtils, validateYupSchema } = require('@strapi/utils'); const { yup, validateYupSchema } = require('@strapi/utils');
const urlRegex = const urlRegex =
/^(?:([a-z0-9+.-]+):\/\/)(?:\S+(?::\S*)?@)?(?:(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9_]-*)*[a-z\u00a1-\uffff0-9_]+)(?:\.(?:[a-z\u00a1-\uffff0-9_]-*)*[a-z\u00a1-\uffff0-9_]+)*\.?)(?::\d{2,5})?(?:[/?#]\S*)?$/; /^(?:([a-z0-9+.-]+):\/\/)(?:\S+(?::\S*)?@)?(?:(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9_]-*)*[a-z\u00a1-\uffff0-9_]+)(?:\.(?:[a-z\u00a1-\uffff0-9_]-*)*[a-z\u00a1-\uffff0-9_]+)*\.?)(?::\d{2,5})?(?:[/?#]\S*)?$/;
@ -23,7 +23,7 @@ const webhookValidator = yup
) )
.required(); .required();
}), }),
events: yup.array().of(yup.string().oneOf(_.values(webhookUtils.webhookEvents)).required()), events: yup.array().of(yup.string()).required(),
}) })
.noUnknown(); .noUnknown();
@ -111,10 +111,10 @@ module.exports = {
for (const id of ids) { for (const id of ids) {
const webhook = await strapi.webhookStore.findWebhook(id); const webhook = await strapi.webhookStore.findWebhook(id);
if (!webhook) continue; if (webhook) {
await strapi.webhookStore.deleteWebhook(id);
await strapi.webhookStore.deleteWebhook(id); strapi.webhookRunner.remove(webhook);
strapi.webhookRunner.remove(webhook); }
} }
ctx.send({ data: ids }); ctx.send({ data: ids });

View File

@ -1,8 +1,13 @@
'use strict'; 'use strict';
const { getService } = require('./utils'); const { getService } = require('./utils');
const { ALLOWED_WEBHOOK_EVENTS } = require('./constants');
module.exports = async () => { module.exports = async () => {
Object.entries(ALLOWED_WEBHOOK_EVENTS).forEach(([key, value]) => {
strapi.webhookStore.addAllowedEvent(key, value);
});
await getService('components').syncConfigurations(); await getService('components').syncConfigurations();
await getService('content-types').syncConfigurations(); await getService('content-types').syncConfigurations();
await getService('permission').registerPermissions(); await getService('permission').registerPermissions();

View File

@ -0,0 +1,10 @@
'use strict';
const ALLOWED_WEBHOOK_EVENTS = {
ENTRY_PUBLISH: 'entry.publish',
ENTRY_UNPUBLISH: 'entry.unpublish',
};
module.exports = {
ALLOWED_WEBHOOK_EVENTS,
};

View File

@ -382,7 +382,7 @@ describe('Single Types', () => {
await singleTypes.publish(ctx); await singleTypes.publish(ctx);
expect(publishFn).toHaveBeenCalledWith(entity, { updatedBy: state.user.id }, modelUid); expect(publishFn).toHaveBeenCalledWith(entity, modelUid, { updatedBy: state.user.id });
expect(permissionChecker.cannot.publish).toHaveBeenCalledWith(entity); expect(permissionChecker.cannot.publish).toHaveBeenCalledWith(entity);
expect(permissionChecker.sanitizeOutput).toHaveBeenCalled(); expect(permissionChecker.sanitizeOutput).toHaveBeenCalled();
}); });
@ -479,7 +479,7 @@ describe('Single Types', () => {
await singleTypes.unpublish(ctx); await singleTypes.unpublish(ctx);
expect(unpublishFn).toHaveBeenCalledWith(entity, { updatedBy: state.user.id }, modelUid); expect(unpublishFn).toHaveBeenCalledWith(entity, modelUid, { updatedBy: state.user.id });
expect(permissionChecker.cannot.unpublish).toHaveBeenCalledWith(entity); expect(permissionChecker.cannot.unpublish).toHaveBeenCalledWith(entity);
expect(permissionChecker.sanitizeOutput).toHaveBeenCalled(); expect(permissionChecker.sanitizeOutput).toHaveBeenCalled();
}); });

View File

@ -174,8 +174,8 @@ module.exports = {
const result = await entityManager.publish( const result = await entityManager.publish(
entity, entity,
setCreatorFields({ user, isEdition: true })({}), model,
model setCreatorFields({ user, isEdition: true })({})
); );
ctx.body = await permissionChecker.sanitizeOutput(result); ctx.body = await permissionChecker.sanitizeOutput(result);
@ -204,8 +204,8 @@ module.exports = {
const result = await entityManager.unpublish( const result = await entityManager.unpublish(
entity, entity,
setCreatorFields({ user, isEdition: true })({}), model,
model setCreatorFields({ user, isEdition: true })({})
); );
ctx.body = await permissionChecker.sanitizeOutput(result); ctx.body = await permissionChecker.sanitizeOutput(result);

View File

@ -148,8 +148,8 @@ module.exports = {
const publishedEntity = await entityManager.publish( const publishedEntity = await entityManager.publish(
entity, entity,
setCreatorFields({ user, isEdition: true })({}), model,
model setCreatorFields({ user, isEdition: true })({})
); );
ctx.body = await permissionChecker.sanitizeOutput(publishedEntity); ctx.body = await permissionChecker.sanitizeOutput(publishedEntity);
@ -181,8 +181,8 @@ module.exports = {
const unpublishedEntity = await entityManager.unpublish( const unpublishedEntity = await entityManager.unpublish(
entity, entity,
setCreatorFields({ user, isEdition: true })({}), model,
model setCreatorFields({ user, isEdition: true })({})
); );
ctx.body = await permissionChecker.sanitizeOutput(unpublishedEntity); ctx.body = await permissionChecker.sanitizeOutput(unpublishedEntity);

View File

@ -26,6 +26,9 @@ describe('Content-Manager', () => {
config: { config: {
get: (path, defaultValue) => _.get(defaultConfig, path, defaultValue), get: (path, defaultValue) => _.get(defaultConfig, path, defaultValue),
}, },
webhookStore: {
allowedEvents: new Map([['ENTRY_PUBLISH', 'entry.publish']]),
},
}; };
entityManager = entityManagerLoader({ strapi }); entityManager = entityManagerLoader({ strapi });
}); });
@ -37,7 +40,7 @@ describe('Content-Manager', () => {
test('Publish a content-type', async () => { test('Publish a content-type', async () => {
const uid = 'api::test.test'; const uid = 'api::test.test';
const entity = { id: 1, publishedAt: null }; const entity = { id: 1, publishedAt: null };
await entityManager.publish(entity, {}, uid); await entityManager.publish(entity, uid, {});
expect(strapi.entityService.update).toBeCalledWith(uid, entity.id, { expect(strapi.entityService.update).toBeCalledWith(uid, entity.id, {
data: { publishedAt: expect.any(Date) }, data: { publishedAt: expect.any(Date) },
@ -58,6 +61,9 @@ describe('Content-Manager', () => {
config: { config: {
get: (path, defaultValue) => _.get(defaultConfig, path, defaultValue), get: (path, defaultValue) => _.get(defaultConfig, path, defaultValue),
}, },
webhookStore: {
allowedEvents: new Map([['ENTRY_UNPUBLISH', 'entry.unpublish']]),
},
}; };
entityManager = entityManagerLoader({ strapi }); entityManager = entityManagerLoader({ strapi });
}); });
@ -69,7 +75,7 @@ describe('Content-Manager', () => {
test('Unpublish a content-type', async () => { test('Unpublish a content-type', async () => {
const uid = 'api::test.test'; const uid = 'api::test.test';
const entity = { id: 1, publishedAt: new Date() }; const entity = { id: 1, publishedAt: new Date() };
await entityManager.unpublish(entity, {}, uid); await entityManager.unpublish(entity, uid, {});
expect(strapi.entityService.update).toHaveBeenCalledWith(uid, entity.id, { expect(strapi.entityService.update).toHaveBeenCalledWith(uid, entity.id, {
data: { publishedAt: null }, data: { publishedAt: null },

View File

@ -7,15 +7,17 @@ const { ApplicationError } = require('@strapi/utils').errors;
const { getDeepPopulate, getDeepPopulateDraftCount } = require('./utils/populate'); const { getDeepPopulate, getDeepPopulateDraftCount } = require('./utils/populate');
const { getDeepRelationsCount } = require('./utils/count'); const { getDeepRelationsCount } = require('./utils/count');
const { sumDraftCounts } = require('./utils/draft'); const { sumDraftCounts } = require('./utils/draft');
const {
ALLOWED_WEBHOOK_EVENTS: { ENTRY_PUBLISH, ENTRY_UNPUBLISH },
} = require('../constants');
const { hasDraftAndPublish } = strapiUtils.contentTypes; const { hasDraftAndPublish } = strapiUtils.contentTypes;
const { PUBLISHED_AT_ATTRIBUTE, CREATED_BY_ATTRIBUTE } = strapiUtils.contentTypes.constants; const { PUBLISHED_AT_ATTRIBUTE, CREATED_BY_ATTRIBUTE } = strapiUtils.contentTypes.constants;
const { ENTRY_PUBLISH, ENTRY_UNPUBLISH } = strapiUtils.webhook.webhookEvents;
const omitPublishedAtField = omit(PUBLISHED_AT_ATTRIBUTE); const omitPublishedAtField = omit(PUBLISHED_AT_ATTRIBUTE);
const emitEvent = async (event, entity, modelUid) => { const emitEvent = async (uid, event, entity) => {
const modelDef = strapi.getModel(modelUid); const modelDef = strapi.getModel(uid);
const sanitizedEntity = await strapiUtils.sanitize.sanitizers.defaultSanitizeOutput( const sanitizedEntity = await strapiUtils.sanitize.sanitizers.defaultSanitizeOutput(
modelDef, modelDef,
entity entity
@ -229,7 +231,7 @@ module.exports = ({ strapi }) => ({
return strapi.entityService.deleteMany(uid, params); return strapi.entityService.deleteMany(uid, params);
}, },
async publish(entity, body = {}, uid) { async publish(entity, uid, body = {}) {
if (entity[PUBLISHED_AT_ATTRIBUTE]) { if (entity[PUBLISHED_AT_ATTRIBUTE]) {
throw new ApplicationError('already.published'); throw new ApplicationError('already.published');
} }
@ -254,7 +256,7 @@ module.exports = ({ strapi }) => ({
const updatedEntity = await strapi.entityService.update(uid, entity.id, params); const updatedEntity = await strapi.entityService.update(uid, entity.id, params);
await emitEvent(ENTRY_PUBLISH, updatedEntity, uid); await emitEvent(uid, ENTRY_PUBLISH, updatedEntity);
const mappedEntity = await this.mapEntity(updatedEntity, uid); const mappedEntity = await this.mapEntity(updatedEntity, uid);
@ -266,7 +268,7 @@ module.exports = ({ strapi }) => ({
return mappedEntity; return mappedEntity;
}, },
async unpublish(entity, body = {}, uid) { async unpublish(entity, uid, body = {}) {
if (!entity[PUBLISHED_AT_ATTRIBUTE]) { if (!entity[PUBLISHED_AT_ATTRIBUTE]) {
throw new ApplicationError('already.draft'); throw new ApplicationError('already.draft');
} }
@ -283,7 +285,7 @@ module.exports = ({ strapi }) => ({
const updatedEntity = await strapi.entityService.update(uid, entity.id, params); const updatedEntity = await strapi.entityService.update(uid, entity.id, params);
await emitEvent(ENTRY_UNPUBLISH, updatedEntity, uid); await emitEvent(uid, ENTRY_UNPUBLISH, updatedEntity);
const mappedEntity = await this.mapEntity(updatedEntity, uid); const mappedEntity = await this.mapEntity(updatedEntity, uid);

View File

@ -20,6 +20,9 @@ describe('Entity service triggers webhooks', () => {
instance = createEntityService({ instance = createEntityService({
strapi: { strapi: {
getModel: () => model, getModel: () => model,
webhookStore: {
addAllowedEvent: jest.fn(),
},
}, },
db: { db: {
transaction: (cb) => cb(), transaction: (cb) => cb(),
@ -39,9 +42,6 @@ describe('Entity service triggers webhooks', () => {
global.strapi = { global.strapi = {
getModel: () => model, getModel: () => model,
config: {
get: () => [],
},
}; };
}); });

View File

@ -18,6 +18,10 @@ describe('Entity service', () => {
}, },
}, },
query: jest.fn(() => ({})), query: jest.fn(() => ({})),
webhookStore: {
allowedEvents: new Map([['ENTRY_CREATE', 'entry.create']]),
addAllowedEvent: jest.fn(),
},
}; };
describe('Decorator', () => { describe('Decorator', () => {
@ -25,7 +29,7 @@ describe('Entity service', () => {
'Can decorate', 'Can decorate',
async (method) => { async (method) => {
const instance = createEntityService({ const instance = createEntityService({
strapi: {}, strapi: global.strapi,
db: {}, db: {},
eventHub: new EventEmitter(), eventHub: new EventEmitter(),
}); });
@ -61,6 +65,7 @@ describe('Entity service', () => {
}; };
const fakeStrapi = { const fakeStrapi = {
...global.strapi,
getModel: jest.fn(() => { getModel: jest.fn(() => {
return { kind: 'singleType' }; return { kind: 'singleType' };
}), }),
@ -98,12 +103,15 @@ describe('Entity service', () => {
global.strapi.getModel.mockImplementation((modelName) => fakeModels[modelName]); global.strapi.getModel.mockImplementation((modelName) => fakeModels[modelName]);
global.strapi.query.mockImplementation(() => fakeQuery); global.strapi.query.mockImplementation(() => fakeQuery);
}); });
beforeEach(() => { beforeEach(() => {
jest.clearAllMocks(); jest.clearAllMocks();
}); });
afterAll(() => { afterAll(() => {
global.strapi.getModel.mockImplementation(() => ({})); global.strapi.getModel.mockImplementation(() => ({}));
}); });
describe('assign default values', () => { describe('assign default values', () => {
let instance; let instance;
const entityUID = 'api::entity.entity'; const entityUID = 'api::entity.entity';
@ -373,10 +381,13 @@ describe('Entity service', () => {
}, },
}; };
global.strapi = fakeStrapi; global.strapi = {
...global.strapi,
...fakeStrapi,
};
instance = createEntityService({ instance = createEntityService({
strapi: fakeStrapi, strapi: global.strapi,
db: fakeDB, db: fakeDB,
eventHub: new EventEmitter(), eventHub: new EventEmitter(),
entityValidator, entityValidator,
@ -522,6 +533,7 @@ describe('Entity service', () => {
}; };
global.strapi = { global.strapi = {
...global.strapi,
getModel: jest.fn((uid) => { getModel: jest.fn((uid) => {
return fakeModels[uid]; return fakeModels[uid];
}), }),

View File

@ -4,11 +4,7 @@ const _ = require('lodash');
const delegate = require('delegates'); const delegate = require('delegates');
const { InvalidTimeError, InvalidDateError, InvalidDateTimeError, InvalidRelationError } = const { InvalidTimeError, InvalidDateError, InvalidDateTimeError, InvalidRelationError } =
require('@strapi/database').errors; require('@strapi/database').errors;
const { const { contentTypes: contentTypesUtils, sanitize } = require('@strapi/utils');
webhook: webhookUtils,
contentTypes: contentTypesUtils,
sanitize,
} = require('@strapi/utils');
const { ValidationError } = require('@strapi/utils').errors; const { ValidationError } = require('@strapi/utils').errors;
const { isAnyToMany } = require('@strapi/utils').relations; const { isAnyToMany } = require('@strapi/utils').relations;
const { transformParamsToQuery } = require('@strapi/utils').convertQueryParams; const { transformParamsToQuery } = require('@strapi/utils').convertQueryParams;
@ -31,9 +27,6 @@ const transformLoadParamsToQuery = (uid, field, params = {}, pagination = {}) =>
}; };
}; };
// TODO: those should be strapi events used by the webhooks not the other way arround
const { ENTRY_CREATE, ENTRY_UPDATE, ENTRY_DELETE } = webhookUtils.webhookEvents;
const databaseErrorsToTransform = [ const databaseErrorsToTransform = [
InvalidTimeError, InvalidTimeError,
InvalidDateTimeError, InvalidDateTimeError,
@ -49,6 +42,12 @@ const updatePipeline = (data, context) => {
return applyTransforms(data, context); return applyTransforms(data, context);
}; };
const ALLOWED_WEBHOOK_EVENTS = {
ENTRY_CREATE: 'entry.create',
ENTRY_UPDATE: 'entry.update',
ENTRY_DELETE: 'entry.delete',
};
/** /**
* @type {import('.').default} * @type {import('.').default}
*/ */
@ -180,6 +179,7 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator })
entity = await this.wrapResult(entity, { uid, action: 'create' }); entity = await this.wrapResult(entity, { uid, action: 'create' });
const { ENTRY_CREATE } = ALLOWED_WEBHOOK_EVENTS;
await this.emitEvent(uid, ENTRY_CREATE, entity); await this.emitEvent(uid, ENTRY_CREATE, entity);
return entity; return entity;
@ -233,6 +233,7 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator })
entity = await this.wrapResult(entity, { uid, action: 'update' }); entity = await this.wrapResult(entity, { uid, action: 'update' });
const { ENTRY_UPDATE } = ALLOWED_WEBHOOK_EVENTS;
await this.emitEvent(uid, ENTRY_UPDATE, entity); await this.emitEvent(uid, ENTRY_UPDATE, entity);
return entity; return entity;
@ -260,6 +261,7 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator })
entityToDelete = await this.wrapResult(entityToDelete, { uid, action: 'delete' }); entityToDelete = await this.wrapResult(entityToDelete, { uid, action: 'delete' });
const { ENTRY_DELETE } = ALLOWED_WEBHOOK_EVENTS;
await this.emitEvent(uid, ENTRY_DELETE, entityToDelete); await this.emitEvent(uid, ENTRY_DELETE, entityToDelete);
return entityToDelete; return entityToDelete;
@ -290,6 +292,7 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator })
entitiesToDelete = await this.wrapResult(entitiesToDelete, { uid, action: 'delete' }); entitiesToDelete = await this.wrapResult(entitiesToDelete, { uid, action: 'delete' });
// Trigger webhooks. One for each entity // Trigger webhooks. One for each entity
const { ENTRY_DELETE } = ALLOWED_WEBHOOK_EVENTS;
await Promise.all(entitiesToDelete.map((entity) => this.emitEvent(uid, ENTRY_DELETE, entity))); await Promise.all(entitiesToDelete.map((entity) => this.emitEvent(uid, ENTRY_DELETE, entity)));
return deletedEntities; return deletedEntities;
@ -331,6 +334,10 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator })
}); });
module.exports = (ctx) => { module.exports = (ctx) => {
Object.entries(ALLOWED_WEBHOOK_EVENTS).forEach(([key, value]) => {
ctx.strapi.webhookStore.addAllowedEvent(key, value);
});
const implementation = createDefaultImplementation(ctx); const implementation = createDefaultImplementation(ctx);
const service = { const service = {

View File

@ -4,6 +4,9 @@
'use strict'; 'use strict';
const { mapAsync } = require('@strapi/utils');
const { ValidationError } = require('@strapi/utils').errors;
const webhookModel = { const webhookModel = {
uid: 'webhook', uid: 'webhook',
collectionName: 'strapi_webhooks', collectionName: 'strapi_webhooks',
@ -47,30 +50,56 @@ const fromDBObject = (row) => {
}; };
}; };
const webhookEventValidator = async (allowedEvents, events) => {
const allowedValues = Array.from(allowedEvents.values());
await mapAsync(events, (event) => {
if (allowedValues.includes(event)) {
return;
}
throw new ValidationError(`Webhook event ${event} is not supported`);
});
};
const createWebhookStore = ({ db }) => { const createWebhookStore = ({ db }) => {
const webhookQueries = db.query('webhook'); const webhookQueries = db.query('webhook');
return { return {
allowedEvents: new Map([]),
addAllowedEvent(key, value) {
this.allowedEvents.set(key, value);
},
removeAllowedEvent(key) {
this.allowedEvents.delete(key);
},
listAllowedEvents() {
return Array.from(this.allowedEvents.keys());
},
getAllowedEvent(key) {
return this.allowedEvents.get(key);
},
async findWebhooks() { async findWebhooks() {
const results = await webhookQueries.findMany(); const results = await webhookQueries.findMany();
return results.map(fromDBObject); return results.map(fromDBObject);
}, },
async findWebhook(id) { async findWebhook(id) {
const result = await webhookQueries.findOne({ where: { id } }); const result = await webhookQueries.findOne({ where: { id } });
return result ? fromDBObject(result) : null; return result ? fromDBObject(result) : null;
}, },
async createWebhook(data) {
await webhookEventValidator(this.allowedEvents, data.events);
createWebhook(data) {
return webhookQueries return webhookQueries
.create({ .create({
data: toDBObject({ ...data, isEnabled: true }), data: toDBObject({ ...data, isEnabled: true }),
}) })
.then(fromDBObject); .then(fromDBObject);
}, },
async updateWebhook(id, data) { async updateWebhook(id, data) {
await webhookEventValidator(this.allowedEvents, data.events);
const webhook = await webhookQueries.update({ const webhook = await webhookQueries.update({
where: { id }, where: { id },
data: toDBObject(data), data: toDBObject(data),
@ -78,7 +107,6 @@ const createWebhookStore = ({ db }) => {
return webhook ? fromDBObject(webhook) : null; return webhook ? fromDBObject(webhook) : null;
}, },
async deleteWebhook(id) { async deleteWebhook(id) {
const webhook = await webhookQueries.delete({ where: { id } }); const webhook = await webhookQueries.delete({ where: { id } });
return webhook ? fromDBObject(webhook) : null; return webhook ? fromDBObject(webhook) : null;

View File

@ -68,6 +68,9 @@ describe('Upload plugin bootstrap function', () => {
set: setStore, set: setStore,
}; };
}, },
webhookStore: {
addAllowedEvent: jest.fn(),
},
}; };
await bootstrap({ strapi }); await bootstrap({ strapi });

View File

@ -1,7 +1,7 @@
'use strict'; 'use strict';
const { getService } = require('./utils'); const { getService } = require('./utils');
const { ALLOWED_SORT_STRINGS } = require('./constants'); const { ALLOWED_SORT_STRINGS, ALLOWED_WEBHOOK_EVENTS } = require('./constants');
module.exports = async ({ strapi }) => { module.exports = async ({ strapi }) => {
const defaultConfig = { const defaultConfig = {
@ -36,6 +36,7 @@ module.exports = async ({ strapi }) => {
} }
await registerPermissionActions(); await registerPermissionActions();
await registerWebhookEvents();
await getService('weeklyMetrics').registerCron(); await getService('weeklyMetrics').registerCron();
getService('metrics').sendUploadPluginMetrics(); getService('metrics').sendUploadPluginMetrics();
@ -47,6 +48,11 @@ module.exports = async ({ strapi }) => {
} }
}; };
const registerWebhookEvents = async () =>
Object.entries(ALLOWED_WEBHOOK_EVENTS).forEach(([key, value]) => {
strapi.webhookStore.addAllowedEvent(key, value);
});
const registerPermissionActions = async () => { const registerPermissionActions = async () => {
const actions = [ const actions = [
{ {

View File

@ -19,10 +19,17 @@ const ALLOWED_SORT_STRINGS = [
'updatedAt:ASC', 'updatedAt:ASC',
]; ];
const ALLOWED_WEBHOOK_EVENTS = {
MEDIA_CREATE: 'media.create',
MEDIA_UPDATE: 'media.update',
MEDIA_DELETE: 'media.delete',
};
module.exports = { module.exports = {
ACTIONS, ACTIONS,
FOLDER_MODEL_UID: 'plugin::upload.folder', FOLDER_MODEL_UID: 'plugin::upload.folder',
FILE_MODEL_UID: 'plugin::upload.file', FILE_MODEL_UID: 'plugin::upload.file',
API_UPLOAD_FOLDER_BASE_NAME: 'API Uploads', API_UPLOAD_FOLDER_BASE_NAME: 'API Uploads',
ALLOWED_SORT_STRINGS, ALLOWED_SORT_STRINGS,
ALLOWED_WEBHOOK_EVENTS,
}; };

View File

@ -17,14 +17,14 @@ const {
sanitize, sanitize,
nameToSlug, nameToSlug,
contentTypes: contentTypesUtils, contentTypes: contentTypesUtils,
webhook: webhookUtils,
errors: { ApplicationError, NotFoundError }, errors: { ApplicationError, NotFoundError },
file: { bytesToKbytes }, file: { bytesToKbytes },
} = require('@strapi/utils'); } = require('@strapi/utils');
const { MEDIA_UPDATE, MEDIA_CREATE, MEDIA_DELETE } = webhookUtils.webhookEvents; const {
FILE_MODEL_UID,
const { FILE_MODEL_UID } = require('../constants'); ALLOWED_WEBHOOK_EVENTS: { MEDIA_CREATE, MEDIA_UPDATE, MEDIA_DELETE },
} = require('../constants');
const { getService } = require('../utils'); const { getService } = require('../utils');
const { UPDATED_BY_ATTRIBUTE, CREATED_BY_ATTRIBUTE } = contentTypesUtils.constants; const { UPDATED_BY_ATTRIBUTE, CREATED_BY_ATTRIBUTE } = contentTypesUtils.constants;

View File

@ -28,7 +28,6 @@ const { removeUndefined, keysDeep } = require('./object-formatting');
const { getConfigUrls, getAbsoluteAdminUrl, getAbsoluteServerUrl } = require('./config'); const { getConfigUrls, getAbsoluteAdminUrl, getAbsoluteServerUrl } = require('./config');
const { generateTimestampCode } = require('./code-generator'); const { generateTimestampCode } = require('./code-generator');
const contentTypes = require('./content-types'); const contentTypes = require('./content-types');
const webhook = require('./webhook');
const env = require('./env-helper'); const env = require('./env-helper');
const relations = require('./relations'); const relations = require('./relations');
const setCreatorFields = require('./set-creator-fields'); const setCreatorFields = require('./set-creator-fields');
@ -75,7 +74,6 @@ module.exports = {
isCamelCase, isCamelCase,
toKebabCase, toKebabCase,
contentTypes, contentTypes,
webhook,
env, env,
relations, relations,
setCreatorFields, setCreatorFields,

View File

@ -1,16 +0,0 @@
'use strict';
const webhookEvents = {
ENTRY_CREATE: 'entry.create',
ENTRY_UPDATE: 'entry.update',
ENTRY_DELETE: 'entry.delete',
ENTRY_PUBLISH: 'entry.publish',
ENTRY_UNPUBLISH: 'entry.unpublish',
MEDIA_CREATE: 'media.create',
MEDIA_UPDATE: 'media.update',
MEDIA_DELETE: 'media.delete',
};
module.exports = {
webhookEvents,
};