diff --git a/test/api/v3/integration/webhook/POST-user_add_webhook.test.js b/test/api/v3/integration/webhook/POST-user_add_webhook.test.js index 50187515b8..accb834dc4 100644 --- a/test/api/v3/integration/webhook/POST-user_add_webhook.test.js +++ b/test/api/v3/integration/webhook/POST-user_add_webhook.test.js @@ -100,6 +100,16 @@ describe('POST /user/webhook', () => { expect(webhook.url).to.eql(body.url); }); + it('cannot use an id of a webhook that already exists', async () => { + await user.post('/user/webhook', body); + + await expect(user.post('/user/webhook', body)).to.eventually.be.rejected.and.eql({ + code: 400, + error: 'BadRequest', + message: t('webhookIdAlreadyTaken', { id: body.id }), + }); + }); + it('defaults taskActivity options', async () => { body.type = 'taskActivity'; diff --git a/website/common/locales/en/settings.json b/website/common/locales/en/settings.json index 5fa2d2c072..f3b98657c0 100644 --- a/website/common/locales/en/settings.json +++ b/website/common/locales/en/settings.json @@ -159,6 +159,7 @@ "missingWebhookId": "The webhook's id is required.", "invalidWebhookType": "\"<%= type %>\" is not a valid value for the parameter \"type\".", "webhookBooleanOption": "\"<%= option %>\" must be a Boolean value.", + "webhookIdAlreadyTaken": "A webhook with the id <%= id %> already exists.", "noWebhookWithId": "There is no webhook with the id <%= id %>.", "regIdRequired": "RegId is required", "invalidPushClient": "Invalid client. Only Official Habitica clients can receive push notifications.", diff --git a/website/server/controllers/api-v3/webhook.js b/website/server/controllers/api-v3/webhook.js index 4c6baaf0eb..4c51140285 100644 --- a/website/server/controllers/api-v3/webhook.js +++ b/website/server/controllers/api-v3/webhook.js @@ -1,7 +1,7 @@ import { authWithHeaders } from '../../middlewares/auth'; import { model as Webhook } from '../../models/webhook'; import { removeFromArray } from '../../libs/collectionManipulators'; -import { NotFound } from '../../libs/errors'; +import { NotFound, BadRequest } from '../../libs/errors'; let api = {}; @@ -53,6 +53,7 @@ let api = {}; * @apiSuccess {Object} data.options The options for the webhook (See examples) * * @apiError InvalidUUID The `id` was not a valid `UUID` +* @apiError IdTaken The `id` is already being used by another webhook * @apiError InvalidEnable The `enable` param was not a `Boolean` value * @apiError InvalidUrl The `url` param was not valid url * @apiError InvalidWebhookType The `type` param was not a supported Webhook type @@ -67,6 +68,14 @@ api.addWebhook = { let user = res.locals.user; let webhook = new Webhook(req.body); + let existingWebhook = user.webhooks.find((wh) => { + return wh.id === webhook.id; + }); + + if (existingWebhook) { + throw new BadRequest(res.t('webhookIdAlreadyTaken', { id: webhook.id })); + } + webhook.formatOptions(res); user.webhooks.push(webhook);