0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-03-11 02:12:21 -05:00

Updated webhooks schema and add relation (#10018)

* Extended webhooks schema/model and connected with integrations

refs #9942

- Updated webhooks schema with new columns - name, integration_id, secret, last_triggered_at, api_version
- Updated webhooks and integration model to map relationships
- Updated schema hash
- Updated test utils to exclude new webhooks columns for response comparison

* Added migration script for new webhooks columns

refs #9942

- Added migration script in 2.3 to add new columns to webhooks

* Updated schema hash

* Updated maxLength for api_version in schema

* Removed concurrency value from migration script

* Added defaults for webhooks model

* Added status field to webhooks for last trigger status

* Updated schema hash

* Fixed tests with status field

* Removed concurrency value in migration script

* Cleanup

* Updated schema with new fields

 - last_triggered_status, last_triggered_error
This commit is contained in:
Rishabh Garg 2018-10-17 16:47:13 +05:30 committed by Fabien O'Carroll
parent 079a0d30d2
commit c638863cb9
8 changed files with 122 additions and 6 deletions

View file

@ -0,0 +1,47 @@
const common = require('../../../../lib/common');
const commands = require('../../../schema').commands;
const table = 'webhooks';
const newColumnNames = [
'name',
'secret',
'api_version',
'integration_id',
'status',
'last_triggered_at',
'last_triggered_status',
'last_triggered_error'
];
function printResult(operation, columnName) {
return `${operation} column ${columnName} in ${table} table`;
}
module.exports.up = (options) => {
const connection = options.connection;
return Promise.map(newColumnNames, (newColumnName) => {
return connection.schema.hasColumn(table, newColumnName)
.then((exists) => {
if (exists) {
common.logging.warn(printResult('Adding', newColumnName));
return;
}
common.logging.info(printResult('Adding', newColumnName));
return commands.addColumn(table, newColumnName, connection);
});
});
};
module.exports.down = (options) => {
const connection = options.connection;
return Promise.map(newColumnNames, (newColumnName) => {
return connection.schema.hasColumn(table, newColumnName)
.then((exists) => {
if (!exists) {
common.logging.warn(printResult('Dropping', newColumnName));
return;
}
common.logging.info(printResult('Dropping', newColumnName));
return commands.dropColumn(table, newColumnName, connection);
});
});
};

View file

@ -296,6 +296,14 @@ module.exports = {
id: {type: 'string', maxlength: 24, nullable: false, primary: true},
event: {type: 'string', maxlength: 50, nullable: false, validations: {isLowercase: true}},
target_url: {type: 'string', maxlength: 2000, nullable: false},
name: {type: 'string', maxlength: 191, nullable: true},
secret: {type: 'string', maxlength: 191, nullable: true},
api_version: {type: 'string', maxlength: 50, nullable: false, defaultTo: 'v2'},
integration_id: {type: 'string', maxlength: 24, nullable: true},
status: {type: 'string', maxlength: 50, nullable: false, defaultTo: 'available'},
last_triggered_at: {type: 'dateTime', nullable: true},
last_triggered_status: {type: 'string', maxlength: 50, nullable: true},
last_triggered_error: {type: 'string', maxlength: 50, nullable: true},
created_at: {type: 'dateTime', nullable: false},
created_by: {type: 'string', maxlength: 24, nullable: false},
updated_at: {type: 'dateTime', nullable: true},

View file

@ -3,10 +3,11 @@ const ghostBookshelf = require('./base');
const Integration = ghostBookshelf.Model.extend({
tableName: 'integrations',
relationships: ['api_keys'],
relationships: ['api_keys', 'webhooks'],
relationshipBelongsTo: {
api_keys: 'api_keys'
api_keys: 'api_keys',
webhooks: 'webhooks'
},
onSaving(newIntegration, attr, options) {
@ -26,6 +27,10 @@ const Integration = ghostBookshelf.Model.extend({
api_keys: function apiKeys() {
return this.hasMany('ApiKey', 'integration_id');
},
webhooks: function webhooks() {
return this.hasMany('Webhook', 'integration_id');
}
});

View file

@ -7,6 +7,17 @@ let Webhook,
Webhook = ghostBookshelf.Model.extend({
tableName: 'webhooks',
defaults() {
return {
api_version: 'v2',
status: 'available'
};
},
integration() {
return this.belongsTo('Integration');
},
emitChange: function emitChange(event, options) {
const eventToTrigger = 'webhook' + '.' + event;
ghostBookshelf.Model.prototype.emitChange.bind(this)(this, eventToTrigger, options);

View file

@ -48,7 +48,6 @@ describe('Webhooks API', function () {
should.exist(jsonResponse.webhooks);
testUtils.API.checkResponse(jsonResponse.webhooks[0], 'webhook');
jsonResponse.webhooks[0].event.should.equal(newWebhook.event);
jsonResponse.webhooks[0].target_url.should.equal(newWebhook.target_url);

View file

@ -53,6 +53,41 @@ describe('Webhooks API', function () {
done();
});
});
it('creates a new webhook with name, secret and api version', function (done) {
let webhookData = {
event: 'test.create',
target_url: 'http://example.com/webhooks/test/extra/1',
name: 'test',
secret: 'thisissecret',
api_version: 'v2'
};
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(201)
.end(function (err, res) {
if (err) {
return done(err);
}
var jsonResponse = res.body;
should.exist(jsonResponse.webhooks);
testUtils.API.checkResponse(jsonResponse.webhooks[0], 'webhook', ['name', 'secret']);
jsonResponse.webhooks[0].event.should.equal(webhookData.event);
jsonResponse.webhooks[0].target_url.should.equal(webhookData.target_url);
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);
done();
});
});
});
describe('Delete', function () {
@ -80,7 +115,6 @@ describe('Webhooks API', function () {
should.exist(jsonResponse.webhooks);
testUtils.API.checkResponse(jsonResponse.webhooks[0], 'webhook');
jsonResponse.webhooks[0].event.should.equal(newWebhook.event);
jsonResponse.webhooks[0].target_url.should.equal(newWebhook.target_url);

View file

@ -19,7 +19,7 @@ var should = require('should'),
*/
describe('DB version integrity', function () {
// Only these variables should need updating
const currentSchemaHash = '1e26cc4d159e43a0607d72d1e44050d1';
const currentSchemaHash = '92cb4391c426520d2e3e80c46f6ae100';
const currentFixturesHash = '20292edf9fd692cbd6485267a2ac8e75';
// If this test is failing, then it is likely a change has been made that requires a DB version bump,

View file

@ -57,7 +57,19 @@ var _ = require('lodash'),
themes: ['themes'],
invites: ['invites', 'meta'],
invite: _(schema.invites).keys().without('token').value(),
webhook: _.keys(schema.webhooks)
webhook: {
default: _(schema.webhooks)
.keys()
.without(
'name',
'last_triggered_at',
'last_triggered_error',
'last_triggered_status',
'secret',
'integration_id'
)
.value()
}
};
function getURL() {