Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
115 changes: 114 additions & 1 deletion src/services/account/account.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,30 @@ module.exports = class Account extends Service {

this.API = {
fetchInstance: `/instances/${instanceZUID}`,
fetchInstanceUsers: `/instances/${instanceZUID}/users/roles`
fetchInstanceUsers: `/instances/${instanceZUID}/users/roles`,

//
// WEBHOOKS
//
createWebhook: `/webhooks`,
getInstanceWebhook: `/instances/${instanceZUID}/webhooks`,
getWebhook: `/webhooks/WEBHOOK_ZUID`,
};

// WEBHOOK CONSTANTS

// event actions
this.CREATE = 1
this.UPDATE = 2
this.DELETE = 3
this.PUBLISH = 4
this.UNPUBLISH = 5
this.UNDO_DELETE = 6

// HTTP Application Content Types
this.JSON = "application/json"
this.formEncoded = "application/x-www-form-url-encoded"

}

async getInstance() {
Expand All @@ -33,4 +55,95 @@ module.exports = class Account extends Service {
return this.siteId;
}
}

// Creates a single webhook to listen for events
// At this point the SDK will only allow users to
// create webhooks for a given Zesty instance.

async createWebhook(opts = {
scopedResource: "",
eventAction: "",
parentResourceZUID: null,
resource: "",
method: "",
URL: "",
contentType: "",
authorization: null,
body: null,
description: null,
}){

// validate event action
if (opts.eventAction != this.CREATE &&
opts.eventAction != this.UPDATE &&
opts.eventAction != this.DELETE &&
opts.eventAction != this.PUBLISH &&
opts.eventAction != this.UNPUBLISH &&
opts.eventAction != this.UNDO_DELETE) {
throw new Error(
"Invalid eventAction value"
);
}

// validate method
if (opts.method != "POST" &&
opts.method != "GET") {
throw new Error(
`Unsupported method type: ${opts.method}`
);
}

// validate resource type

// validate content-type
if (opts.contentType != this.JSON &&
opts.contentType != this.formEncoded) {
throw new Error(
`Unsupported content-type: ${opts.contentType}`
);
}

// send request
return await this.postRequest(
this.API.createWebhook,
{
payload: opts
}
);

}

// get all webhooks for the current instance
async getWebhooks() {
// validate the scoped resource
const instance = this.getInstance();
const instanceZUID = instance.ZUID;

return await this.getRequest(
this.interpolate(
this.API.getInstanceWebhook, {
INSTANCE_ZUID: instanceZUID
}
)
);
}

// get a single webhook by its webhook ZUID
async getWebhook(webhookZUID) {
// validate webhook ZUID
if (!webhookZUID.startsWith("40-")) {
throw new Error(
`Invalid webhook ZUID: ${webhookZUID}`
);
}

return await this.getRequest(
this.interpolate(
this.API.getWebhook, {
WEBHOOK_ZUID: webhookZUID
}
)
);
}

};
136 changes: 136 additions & 0 deletions src/services/account/account.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,139 @@ test("getInstanceUsers:200", async t => {
t.truthy(Array.isArray(res.data));
t.truthy(res.data.length > 0);
});

//
// WEBHOOKS
//

//
// WEBHOOK CREATE
//

// test successful webhook creation
test.serial("create a webhook", async t => {
const opts = {
scopedResource: process.env.ZESTY_INSTANCE_ZUID,
eventAction: t.context.sdk.account.CREATE,
parentResourceZUID: null,
resource: "items",
method: "POST",
URL: "http://website.com",
contentType: t.context.sdk.account.JSON,
authorization: null,
body: null,
description: null,
};

const res = await t.context.sdk.account.createWebhook(opts);
t.is(res.statusCode, 201)
t.is(
res.data.eventAction,
t.context.sdk.account.CREATE
);
t.is(
res.data.resource,
"items"
);
t.is(
res.data.method,
"POST"
);
t.is(
res.data.contentType,
t.context.sdk.account.JSON
);
});


// test failed webhook creation with an invalid event action
test.serial("create a webhook with an invalid event action", async t => {
const badAction = await t.throwsAsync(
t.context.sdk.account.createWebhook({
eventAction: 0
})
);
t.is(
badAction.message,
"Invalid eventAction value"
);
});

// test failed webhook creation with an invalid method
test.serial("create a webhook with an invalid method", async t => {
const opts = {
eventAction: 1,
method: "PUT"
};
const badMethod = await t.throwsAsync(
t.context.sdk.account.createWebhook(opts)
);

t.is(
badMethod.message,
`Unsupported method type: ${opts.method}`
);
});

// test failed webhook creation with an invalid content type
test.serial("create a webhook with an invalid content type", async t => {
const opts = {
eventAction: 1,
method: "POST",
contentType: "text/html"
};
const badContentType = await t.throwsAsync(
t.context.sdk.account.createWebhook(opts)
);

t.is(
badContentType.message,
`Unsupported content-type: ${opts.contentType}`
);
});

//
// WEBHOOKS GET
//

// test successful webhhooks retrieval on a given instance
test.serial("get all webhooks for a specific instance", async t => {
const res = await t.context.sdk.account.getWebhooks();

t.truthy(
Array.isArray(res.data)
);

t.truthy(
res.data.length > 0
);
});

//
// WEBHOOK GET
//

// test successful single webhook retrieval
test.serial("get a single webhook", async t => {
const res = await t.context.sdk.account.getWebhook(
process.env.TEST_WEBHOOK_ZUID
);

t.is(
res.statusCode,
200
);
});

// test failed single webhook retrieval
test.serial("get a webhook with an invalid webhook ZUID", async t => {
const BAD_WEBHOOK_ZUID = "39-1234-ABCD";
const badWebhookZUID = await t.throwsAsync(
t.context.sdk.account.getWebhook(BAD_WEBHOOK_ZUID)
);

t.is(
badWebhookZUID.message,
`Invalid webhook ZUID: ${BAD_WEBHOOK_ZUID}`
);
});