mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-11-28 05:37:34 +03:00
Added JSON Schema validations to Webhooks Admin API v3
closes #12033 - Added webhooks schemas and definitions. - Added validation checking if integration_id is present when using session auth. This is needed to prevent orphan webhooks. - Integrated webhook schemas into frame's validation layer. - Added isLowerCase ajv keyword support. This is needed to be able to do isLowerCase validation using JSON Schema for webhooks.
This commit is contained in:
parent
8f660c3259
commit
a520cdad0b
@ -49,5 +49,9 @@ module.exports = {
|
||||
|
||||
get oembed() {
|
||||
return require('./oembed');
|
||||
},
|
||||
|
||||
get webhooks() {
|
||||
return require('./webhooks');
|
||||
}
|
||||
};
|
||||
|
@ -0,0 +1,21 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"$id": "webhooks.add",
|
||||
"title": "webhooks.add",
|
||||
"description": "Schema for webhooks.add",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"webhooks": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"maxItems": 1,
|
||||
"items": {
|
||||
"type": "object",
|
||||
"allOf": [{"$ref": "webhooks#/definitions/webhook"}],
|
||||
"required": ["event", "target_url"]
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": ["webhooks"]
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"$id": "webhooks.edit",
|
||||
"title": "webhooks.edit",
|
||||
"description": "Schema for webhooks.edit",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"webhooks": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"maxItems": 1,
|
||||
"items": {"$ref": "webhooks#/definitions/webhook"}
|
||||
}
|
||||
},
|
||||
"required": ["webhooks"]
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"$id": "webhooks",
|
||||
"title": "webhooks",
|
||||
"description": "Base webhooks definitions",
|
||||
"definitions": {
|
||||
"webhook": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"event": {
|
||||
"type": "string",
|
||||
"maxLength": 50,
|
||||
"isLowercase": true
|
||||
},
|
||||
"target_url": {
|
||||
"type": "string",
|
||||
"format": "uri-reference",
|
||||
"maxLength": 2000
|
||||
},
|
||||
"name": {
|
||||
"type": ["string", "null"],
|
||||
"maxLength": 191
|
||||
},
|
||||
"secret": {
|
||||
"type": ["string", "null"],
|
||||
"maxLength": 191
|
||||
},
|
||||
"api_version": {
|
||||
"type": ["string", "null"],
|
||||
"maxLength": 50
|
||||
},
|
||||
"integration_id": {
|
||||
"type": ["string", "null"],
|
||||
"maxLength": 24
|
||||
},
|
||||
"id": {
|
||||
"strip": true
|
||||
},
|
||||
"status": {
|
||||
"strip": true
|
||||
},
|
||||
"last_triggered_at": {
|
||||
"strip": true
|
||||
},
|
||||
"last_triggered_status": {
|
||||
"strip": true
|
||||
},
|
||||
"last_triggered_error": {
|
||||
"strip": true
|
||||
},
|
||||
"created_at": {
|
||||
"strip": true
|
||||
},
|
||||
"created_by": {
|
||||
"strip": true
|
||||
},
|
||||
"updated_at": {
|
||||
"strip": true
|
||||
},
|
||||
"updated_by": {
|
||||
"strip": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
28
core/server/api/canary/utils/validators/input/webhooks.js
Normal file
28
core/server/api/canary/utils/validators/input/webhooks.js
Normal file
@ -0,0 +1,28 @@
|
||||
const _ = require('lodash');
|
||||
const errors = require('@tryghost/errors');
|
||||
const {i18n} = require('../../../../../lib/common');
|
||||
const jsonSchema = require('../utils/json-schema');
|
||||
|
||||
module.exports = {
|
||||
add(apiConfig, frame) {
|
||||
if (!_.get(frame, 'options.context.api_key.id') && !_.get(frame.data, 'webhooks[0].integration_id')) {
|
||||
return Promise.reject(new errors.ValidationError({
|
||||
message: i18n.t('notices.data.validation.index.schemaValidationFailed', {
|
||||
key: 'integration_id'
|
||||
}),
|
||||
context: i18n.t('errors.api.webhooks.noIntegrationIdProvided.context'),
|
||||
property: 'integration_id'
|
||||
}));
|
||||
}
|
||||
|
||||
const schema = require('./schemas/webhooks-add');
|
||||
const definitions = require('./schemas/webhooks');
|
||||
return jsonSchema.validate(schema, definitions, frame.data);
|
||||
},
|
||||
|
||||
edit(apiConfig, frame) {
|
||||
const schema = require('./schemas/webhooks-edit');
|
||||
const definitions = require('./schemas/webhooks');
|
||||
return jsonSchema.validate(schema, definitions, frame.data);
|
||||
}
|
||||
};
|
@ -0,0 +1,15 @@
|
||||
module.exports = function defFunc(ajv) {
|
||||
defFunc.definition = {
|
||||
errors: false,
|
||||
validate: function (schema, data) {
|
||||
if (data) {
|
||||
return data === data.toLowerCase();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
ajv.addKeyword('isLowercase', defFunc.definition);
|
||||
return ajv;
|
||||
};
|
@ -1,6 +1,7 @@
|
||||
const _ = require('lodash');
|
||||
const Ajv = require('ajv');
|
||||
const stripKeyword = require('./strip-keyword');
|
||||
const isLowercaseKeyword = require('./is-lowercase-keyword');
|
||||
const {i18n} = require('../../../../../lib/common');
|
||||
const errors = require('@tryghost/errors');
|
||||
|
||||
@ -20,6 +21,7 @@ const ajv = new Ajv({
|
||||
});
|
||||
|
||||
stripKeyword(ajv);
|
||||
isLowercaseKeyword(ajv);
|
||||
|
||||
const getValidation = (schema, def) => {
|
||||
if (!ajv.getSchema(def.$id)) {
|
||||
|
@ -10,16 +10,6 @@ module.exports = {
|
||||
headers: {},
|
||||
options: [],
|
||||
data: [],
|
||||
validation: {
|
||||
data: {
|
||||
event: {
|
||||
required: true
|
||||
},
|
||||
target_url: {
|
||||
required: true
|
||||
}
|
||||
}
|
||||
},
|
||||
permissions: true,
|
||||
query(frame) {
|
||||
return models.Webhook.getByEventAndTarget(
|
||||
|
@ -452,6 +452,9 @@
|
||||
"message": "You do not have permission to {method} this webhook.",
|
||||
"context": "You may only {method} webhooks that belong to the authenticated integration. Check the supplied Admin API Key."
|
||||
},
|
||||
"noIntegrationIdProvided": {
|
||||
"context": "You may only create webhooks with 'integration_id' when using session authentication."
|
||||
},
|
||||
"webhookAlreadyExists": "Target URL has already been used for this event."
|
||||
},
|
||||
"oembed": {
|
||||
|
@ -27,7 +27,8 @@ describe('Webhooks API', function () {
|
||||
target_url: 'http://example.com/webhooks/test/extra/1',
|
||||
name: 'test',
|
||||
secret: 'thisissecret',
|
||||
api_version: 'v2'
|
||||
api_version: 'v2',
|
||||
integration_id: '12345'
|
||||
};
|
||||
|
||||
return request.post(localUtils.API.getApiQuery('webhooks/'))
|
||||
@ -48,6 +49,7 @@ describe('Webhooks API', function () {
|
||||
jsonResponse.webhooks[0].secret.should.equal(webhookData.secret);
|
||||
jsonResponse.webhooks[0].name.should.equal(webhookData.name);
|
||||
jsonResponse.webhooks[0].api_version.should.equal(webhookData.api_version);
|
||||
jsonResponse.webhooks[0].integration_id.should.equal(webhookData.integration_id);
|
||||
});
|
||||
});
|
||||
|
||||
@ -109,7 +111,8 @@ describe('Webhooks API', function () {
|
||||
const newWebhook = {
|
||||
event: 'test.create',
|
||||
// a different target_url from above is needed to avoid an "already exists" error
|
||||
target_url: 'http://example.com/webhooks/test/2'
|
||||
target_url: 'http://example.com/webhooks/test/2',
|
||||
integration_id: '123423'
|
||||
};
|
||||
|
||||
// create the webhook that is to be deleted
|
||||
@ -120,7 +123,6 @@ describe('Webhooks API', function () {
|
||||
.expect('Cache-Control', testUtils.cacheRules.private)
|
||||
.expect(201)
|
||||
.then((res) => {
|
||||
const location = res.headers.location;
|
||||
const jsonResponse = res.body;
|
||||
|
||||
should.exist(jsonResponse.webhooks);
|
||||
|
@ -47,11 +47,62 @@ describe('Webhooks API (canary)', function () {
|
||||
jsonResponse.webhooks[0].event.should.eql('test.create');
|
||||
jsonResponse.webhooks[0].target_url.should.eql('http://example.com/webhooks/test/extra/canary');
|
||||
jsonResponse.webhooks[0].integration_id.should.eql(testUtils.DataGenerator.Content.api_keys[0].id);
|
||||
jsonResponse.webhooks[0].name.should.eql('test');
|
||||
jsonResponse.webhooks[0].secret.should.eql('thisissecret');
|
||||
jsonResponse.webhooks[0].api_version.should.eql('v3');
|
||||
|
||||
localUtils.API.checkResponse(jsonResponse.webhooks[0], 'webhook');
|
||||
});
|
||||
});
|
||||
|
||||
it('Fails validation for when integration_id is missing', function () {
|
||||
let webhookData = {
|
||||
event: 'test.create',
|
||||
target_url: 'http://example.com/webhooks/test/extra/1',
|
||||
name: 'test',
|
||||
secret: 'thisissecret',
|
||||
api_version: 'v2'
|
||||
};
|
||||
|
||||
return request.post(localUtils.API.getApiQuery('webhooks/'))
|
||||
.set('Origin', config.get('url'))
|
||||
.send({webhooks: [webhookData]})
|
||||
.expect('Content-Type', /json/)
|
||||
.expect('Cache-Control', testUtils.cacheRules.private)
|
||||
.expect(422);
|
||||
});
|
||||
|
||||
it('Fails validation for non-lowercase event name', function () {
|
||||
let webhookData = {
|
||||
event: 'tEst.evenT',
|
||||
target_url: 'http://example.com/webhooks/test/extra/1',
|
||||
name: 'test',
|
||||
secret: 'thisissecret',
|
||||
api_version: 'v2'
|
||||
};
|
||||
|
||||
return request.post(localUtils.API.getApiQuery('webhooks/'))
|
||||
.set('Origin', config.get('url'))
|
||||
.send({webhooks: [webhookData]})
|
||||
.expect('Content-Type', /json/)
|
||||
.expect('Cache-Control', testUtils.cacheRules.private)
|
||||
.expect(422);
|
||||
});
|
||||
|
||||
it('Fails validation when required fields are not present', function () {
|
||||
let webhookData = {
|
||||
api_version: 'v2',
|
||||
integration_id: 'dummy'
|
||||
};
|
||||
|
||||
return request.post(localUtils.API.getApiQuery('webhooks/'))
|
||||
.set('Origin', config.get('url'))
|
||||
.send({webhooks: [webhookData]})
|
||||
.expect('Content-Type', /json/)
|
||||
.expect('Cache-Control', testUtils.cacheRules.private)
|
||||
.expect(422);
|
||||
});
|
||||
|
||||
it('Integration cannot edit or delete other integration\'s webhook', function () {
|
||||
let createdIntegration;
|
||||
let createdWebhook;
|
||||
|
255
test/unit/api/canary/utils/validators/input/webhooks_spec.js
Normal file
255
test/unit/api/canary/utils/validators/input/webhooks_spec.js
Normal file
@ -0,0 +1,255 @@
|
||||
const errors = require('@tryghost/errors');
|
||||
const _ = require('lodash');
|
||||
const should = require('should');
|
||||
const sinon = require('sinon');
|
||||
const Promise = require('bluebird');
|
||||
const validators = require('../../../../../../../core/server/api/canary/utils/validators');
|
||||
|
||||
describe('Unit: canary/utils/validators/input/webhooks', function () {
|
||||
afterEach(function () {
|
||||
sinon.restore();
|
||||
});
|
||||
|
||||
describe('add', function () {
|
||||
const apiConfig = {
|
||||
docName: 'webhooks'
|
||||
};
|
||||
|
||||
describe('required fields', function () {
|
||||
it('should fail with no data', function () {
|
||||
const frame = {
|
||||
options: {},
|
||||
data: {}
|
||||
};
|
||||
|
||||
return validators.input.webhooks.add(apiConfig, frame)
|
||||
.then(Promise.reject)
|
||||
.catch((err) => {
|
||||
(err instanceof errors.ValidationError).should.be.true();
|
||||
});
|
||||
});
|
||||
|
||||
it('should fail with no webhooks', function () {
|
||||
const frame = {
|
||||
options: {},
|
||||
data: {
|
||||
posts: []
|
||||
}
|
||||
};
|
||||
|
||||
return validators.input.webhooks.add(apiConfig, frame)
|
||||
.then(Promise.reject)
|
||||
.catch((err) => {
|
||||
(err instanceof errors.ValidationError).should.be.true();
|
||||
});
|
||||
});
|
||||
|
||||
it('should fail with no webhooks in array', function () {
|
||||
const frame = {
|
||||
options: {},
|
||||
data: {
|
||||
webhooks: []
|
||||
}
|
||||
};
|
||||
|
||||
return validators.input.webhooks.add(apiConfig, frame)
|
||||
.then(Promise.reject)
|
||||
.catch((err) => {
|
||||
(err instanceof errors.ValidationError).should.be.true();
|
||||
});
|
||||
});
|
||||
|
||||
it('should fail with more than webhooks', function () {
|
||||
const frame = {
|
||||
options: {},
|
||||
data: {
|
||||
webhooks: [],
|
||||
posts: []
|
||||
}
|
||||
};
|
||||
|
||||
return validators.input.webhooks.add(apiConfig, frame)
|
||||
.then(Promise.reject)
|
||||
.catch((err) => {
|
||||
(err instanceof errors.ValidationError).should.be.true();
|
||||
});
|
||||
});
|
||||
|
||||
it('should fail without required fields', function () {
|
||||
const frame = {
|
||||
options: {},
|
||||
data: {
|
||||
webhooks: [{
|
||||
what: 'a fail'
|
||||
}]
|
||||
}
|
||||
};
|
||||
|
||||
return validators.input.webhooks.add(apiConfig, frame)
|
||||
.then(Promise.reject)
|
||||
.catch((err) => {
|
||||
(err instanceof errors.ValidationError).should.be.true();
|
||||
});
|
||||
});
|
||||
|
||||
it('should pass with required fields', function () {
|
||||
const frame = {
|
||||
options: {},
|
||||
data: {
|
||||
webhooks: [{
|
||||
integration_id: '123',
|
||||
event: 'post.edited',
|
||||
target_url: 'https://example.com'
|
||||
}]
|
||||
}
|
||||
};
|
||||
|
||||
return validators.input.webhooks.add(apiConfig, frame);
|
||||
});
|
||||
|
||||
it('should remove `strip`able fields and leave regular fields', function () {
|
||||
const frame = {
|
||||
options: {},
|
||||
data: {
|
||||
webhooks: [{
|
||||
name: 'pass',
|
||||
target_url: 'https://example.com/target/1',
|
||||
event: 'post.published',
|
||||
integration_id: '1234',
|
||||
id: 'strip me',
|
||||
status: 'strip me',
|
||||
last_triggered_at: 'strip me',
|
||||
last_triggered_status: 'strip me',
|
||||
last_triggered_error: 'strip me',
|
||||
created_at: 'strip me',
|
||||
created_by: 'strip me',
|
||||
updated_at: 'strip me',
|
||||
updated_by: 'strip me'
|
||||
}]
|
||||
}
|
||||
};
|
||||
|
||||
let result = validators.input.webhooks.add(apiConfig, frame);
|
||||
|
||||
frame.data.webhooks[0].name.should.equal('pass');
|
||||
frame.data.webhooks[0].target_url.should.equal('https://example.com/target/1');
|
||||
frame.data.webhooks[0].event.should.equal('post.published');
|
||||
frame.data.webhooks[0].integration_id.should.equal('1234');
|
||||
should.not.exist(frame.data.webhooks[0].status);
|
||||
should.not.exist(frame.data.webhooks[0].last_triggered_at);
|
||||
should.not.exist(frame.data.webhooks[0].last_triggered_status);
|
||||
should.not.exist(frame.data.webhooks[0].last_triggered_error);
|
||||
should.not.exist(frame.data.webhooks[0].created_at);
|
||||
should.not.exist(frame.data.webhooks[0].created_by);
|
||||
should.not.exist(frame.data.webhooks[0].updated_at);
|
||||
should.not.exist(frame.data.webhooks[0].updated_by);
|
||||
});
|
||||
});
|
||||
|
||||
describe('field formats', function () {
|
||||
const fieldMap = {
|
||||
name: [123, new Date(), '', _.repeat('a', 192), null],
|
||||
secret: [123, new Date(), _.repeat('a', 192)],
|
||||
api_version: [123, new Date(), _.repeat('a', 51)],
|
||||
integration_id: [123, new Date(), 'not uri']
|
||||
};
|
||||
|
||||
Object.keys(fieldMap).forEach((key) => {
|
||||
it(`should fail for bad ${key}`, function () {
|
||||
const badValues = fieldMap[key];
|
||||
|
||||
const checks = badValues.map((value) => {
|
||||
const webhook = {};
|
||||
webhook[key] = value;
|
||||
|
||||
if (key !== 'name') {
|
||||
webhook.name = 'abc';
|
||||
}
|
||||
|
||||
const frame = {
|
||||
options: {},
|
||||
data: {
|
||||
webhooks: [webhook]
|
||||
}
|
||||
};
|
||||
|
||||
return validators.input.webhooks.add(apiConfig, frame)
|
||||
.then(Promise.reject)
|
||||
.catch((err) => {
|
||||
(err instanceof errors.ValidationError).should.be.true();
|
||||
});
|
||||
});
|
||||
|
||||
return Promise.all(checks);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('edit', function () {
|
||||
const apiConfig = {
|
||||
docName: 'webhooks'
|
||||
};
|
||||
|
||||
describe('required fields', function () {
|
||||
it('should fail with no data', function () {
|
||||
const frame = {
|
||||
options: {},
|
||||
data: {}
|
||||
};
|
||||
|
||||
return validators.input.webhooks.edit(apiConfig, frame)
|
||||
.then(Promise.reject)
|
||||
.catch((err) => {
|
||||
(err instanceof errors.ValidationError).should.be.true();
|
||||
});
|
||||
});
|
||||
|
||||
it('should fail with no webhooks', function () {
|
||||
const frame = {
|
||||
options: {},
|
||||
data: {
|
||||
posts: []
|
||||
}
|
||||
};
|
||||
|
||||
return validators.input.webhooks.edit(apiConfig, frame)
|
||||
.then(Promise.reject)
|
||||
.catch((err) => {
|
||||
(err instanceof errors.ValidationError).should.be.true();
|
||||
});
|
||||
});
|
||||
|
||||
it('should fail with more than webhooks', function () {
|
||||
const frame = {
|
||||
options: {},
|
||||
data: {
|
||||
webhooks: [],
|
||||
posts: []
|
||||
}
|
||||
};
|
||||
|
||||
return validators.input.webhooks.edit(apiConfig, frame)
|
||||
.then(Promise.reject)
|
||||
.catch((err) => {
|
||||
(err instanceof errors.ValidationError).should.be.true();
|
||||
});
|
||||
});
|
||||
|
||||
it('should pass with required fields', function () {
|
||||
const frame = {
|
||||
options: {},
|
||||
data: {
|
||||
webhooks: [{
|
||||
target_url: 'https://example.com/target/1',
|
||||
event: 'post.published',
|
||||
integration_id: '1234'
|
||||
}]
|
||||
}
|
||||
};
|
||||
|
||||
return validators.input.webhooks.edit(apiConfig, frame);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
255
test/unit/api/v3/utils/validators/input/webhooks_spec.js
Normal file
255
test/unit/api/v3/utils/validators/input/webhooks_spec.js
Normal file
@ -0,0 +1,255 @@
|
||||
const errors = require('@tryghost/errors');
|
||||
const _ = require('lodash');
|
||||
const should = require('should');
|
||||
const sinon = require('sinon');
|
||||
const Promise = require('bluebird');
|
||||
const validators = require('../../../../../../../core/server/api/canary/utils/validators');
|
||||
|
||||
describe('Unit: v3/utils/validators/input/webhooks', function () {
|
||||
afterEach(function () {
|
||||
sinon.restore();
|
||||
});
|
||||
|
||||
describe('add', function () {
|
||||
const apiConfig = {
|
||||
docName: 'webhooks'
|
||||
};
|
||||
|
||||
describe('required fields', function () {
|
||||
it('should fail with no data', function () {
|
||||
const frame = {
|
||||
options: {},
|
||||
data: {}
|
||||
};
|
||||
|
||||
return validators.input.webhooks.add(apiConfig, frame)
|
||||
.then(Promise.reject)
|
||||
.catch((err) => {
|
||||
(err instanceof errors.ValidationError).should.be.true();
|
||||
});
|
||||
});
|
||||
|
||||
it('should fail with no webhooks', function () {
|
||||
const frame = {
|
||||
options: {},
|
||||
data: {
|
||||
posts: []
|
||||
}
|
||||
};
|
||||
|
||||
return validators.input.webhooks.add(apiConfig, frame)
|
||||
.then(Promise.reject)
|
||||
.catch((err) => {
|
||||
(err instanceof errors.ValidationError).should.be.true();
|
||||
});
|
||||
});
|
||||
|
||||
it('should fail with no webhooks in array', function () {
|
||||
const frame = {
|
||||
options: {},
|
||||
data: {
|
||||
webhooks: []
|
||||
}
|
||||
};
|
||||
|
||||
return validators.input.webhooks.add(apiConfig, frame)
|
||||
.then(Promise.reject)
|
||||
.catch((err) => {
|
||||
(err instanceof errors.ValidationError).should.be.true();
|
||||
});
|
||||
});
|
||||
|
||||
it('should fail with more than webhooks', function () {
|
||||
const frame = {
|
||||
options: {},
|
||||
data: {
|
||||
webhooks: [],
|
||||
posts: []
|
||||
}
|
||||
};
|
||||
|
||||
return validators.input.webhooks.add(apiConfig, frame)
|
||||
.then(Promise.reject)
|
||||
.catch((err) => {
|
||||
(err instanceof errors.ValidationError).should.be.true();
|
||||
});
|
||||
});
|
||||
|
||||
it('should fail without required fields', function () {
|
||||
const frame = {
|
||||
options: {},
|
||||
data: {
|
||||
webhooks: [{
|
||||
what: 'a fail'
|
||||
}]
|
||||
}
|
||||
};
|
||||
|
||||
return validators.input.webhooks.add(apiConfig, frame)
|
||||
.then(Promise.reject)
|
||||
.catch((err) => {
|
||||
(err instanceof errors.ValidationError).should.be.true();
|
||||
});
|
||||
});
|
||||
|
||||
it('should pass with required fields', function () {
|
||||
const frame = {
|
||||
options: {},
|
||||
data: {
|
||||
webhooks: [{
|
||||
integration_id: '123',
|
||||
event: 'post.edited',
|
||||
target_url: 'https://example.com'
|
||||
}]
|
||||
}
|
||||
};
|
||||
|
||||
return validators.input.webhooks.add(apiConfig, frame);
|
||||
});
|
||||
|
||||
it('should remove `strip`able fields and leave regular fields', function () {
|
||||
const frame = {
|
||||
options: {},
|
||||
data: {
|
||||
webhooks: [{
|
||||
name: 'pass',
|
||||
target_url: 'https://example.com/target/1',
|
||||
event: 'post.published',
|
||||
integration_id: '1234',
|
||||
id: 'strip me',
|
||||
status: 'strip me',
|
||||
last_triggered_at: 'strip me',
|
||||
last_triggered_status: 'strip me',
|
||||
last_triggered_error: 'strip me',
|
||||
created_at: 'strip me',
|
||||
created_by: 'strip me',
|
||||
updated_at: 'strip me',
|
||||
updated_by: 'strip me'
|
||||
}]
|
||||
}
|
||||
};
|
||||
|
||||
let result = validators.input.webhooks.add(apiConfig, frame);
|
||||
|
||||
frame.data.webhooks[0].name.should.equal('pass');
|
||||
frame.data.webhooks[0].target_url.should.equal('https://example.com/target/1');
|
||||
frame.data.webhooks[0].event.should.equal('post.published');
|
||||
frame.data.webhooks[0].integration_id.should.equal('1234');
|
||||
should.not.exist(frame.data.webhooks[0].status);
|
||||
should.not.exist(frame.data.webhooks[0].last_triggered_at);
|
||||
should.not.exist(frame.data.webhooks[0].last_triggered_status);
|
||||
should.not.exist(frame.data.webhooks[0].last_triggered_error);
|
||||
should.not.exist(frame.data.webhooks[0].created_at);
|
||||
should.not.exist(frame.data.webhooks[0].created_by);
|
||||
should.not.exist(frame.data.webhooks[0].updated_at);
|
||||
should.not.exist(frame.data.webhooks[0].updated_by);
|
||||
});
|
||||
});
|
||||
|
||||
describe('field formats', function () {
|
||||
const fieldMap = {
|
||||
name: [123, new Date(), '', _.repeat('a', 192), null],
|
||||
secret: [123, new Date(), _.repeat('a', 192)],
|
||||
api_version: [123, new Date(), _.repeat('a', 51)],
|
||||
integration_id: [123, new Date(), 'not uri']
|
||||
};
|
||||
|
||||
Object.keys(fieldMap).forEach((key) => {
|
||||
it(`should fail for bad ${key}`, function () {
|
||||
const badValues = fieldMap[key];
|
||||
|
||||
const checks = badValues.map((value) => {
|
||||
const webhook = {};
|
||||
webhook[key] = value;
|
||||
|
||||
if (key !== 'name') {
|
||||
webhook.name = 'abc';
|
||||
}
|
||||
|
||||
const frame = {
|
||||
options: {},
|
||||
data: {
|
||||
webhooks: [webhook]
|
||||
}
|
||||
};
|
||||
|
||||
return validators.input.webhooks.add(apiConfig, frame)
|
||||
.then(Promise.reject)
|
||||
.catch((err) => {
|
||||
(err instanceof errors.ValidationError).should.be.true();
|
||||
});
|
||||
});
|
||||
|
||||
return Promise.all(checks);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('edit', function () {
|
||||
const apiConfig = {
|
||||
docName: 'webhooks'
|
||||
};
|
||||
|
||||
describe('required fields', function () {
|
||||
it('should fail with no data', function () {
|
||||
const frame = {
|
||||
options: {},
|
||||
data: {}
|
||||
};
|
||||
|
||||
return validators.input.webhooks.edit(apiConfig, frame)
|
||||
.then(Promise.reject)
|
||||
.catch((err) => {
|
||||
(err instanceof errors.ValidationError).should.be.true();
|
||||
});
|
||||
});
|
||||
|
||||
it('should fail with no webhooks', function () {
|
||||
const frame = {
|
||||
options: {},
|
||||
data: {
|
||||
posts: []
|
||||
}
|
||||
};
|
||||
|
||||
return validators.input.webhooks.edit(apiConfig, frame)
|
||||
.then(Promise.reject)
|
||||
.catch((err) => {
|
||||
(err instanceof errors.ValidationError).should.be.true();
|
||||
});
|
||||
});
|
||||
|
||||
it('should fail with more than webhooks', function () {
|
||||
const frame = {
|
||||
options: {},
|
||||
data: {
|
||||
webhooks: [],
|
||||
posts: []
|
||||
}
|
||||
};
|
||||
|
||||
return validators.input.webhooks.edit(apiConfig, frame)
|
||||
.then(Promise.reject)
|
||||
.catch((err) => {
|
||||
(err instanceof errors.ValidationError).should.be.true();
|
||||
});
|
||||
});
|
||||
|
||||
it('should pass with required fields', function () {
|
||||
const frame = {
|
||||
options: {},
|
||||
data: {
|
||||
webhooks: [{
|
||||
target_url: 'https://example.com/target/1',
|
||||
event: 'post.published',
|
||||
integration_id: '1234'
|
||||
}]
|
||||
}
|
||||
};
|
||||
|
||||
return validators.input.webhooks.edit(apiConfig, frame);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue
Block a user