feat(Gotify Node): Add Gotify extra notification settings (#23915)

Co-authored-by: Dimitri Lavrenük <20122620+dlavrenuek@users.noreply.github.com>
This commit is contained in:
Michiel Kalle
2026-08-27 08:01:59 +00:00
committed by GitHub
parent 5179e5e754
commit 0aa9aa8348
11 changed files with 971 additions and 3 deletions
@@ -147,6 +147,27 @@ export class Gotify implements INodeType {
},
],
},
{
displayName: 'Click URL',
name: 'clickUrl',
type: 'string',
default: '',
description: 'Opens this URL when the notification is clicked',
},
{
displayName: 'Big Image URL',
name: 'bigImageUrl',
type: 'string',
default: '',
description: 'Shows a big image in the notification',
},
{
displayName: 'Intent URL',
name: 'intentUrl',
type: 'string',
default: '',
description: 'Opens an intent URL after the notification is delivered (Android only)',
},
],
},
{
@@ -216,14 +237,40 @@ export class Gotify implements INodeType {
message,
};
// Build extras object conditionally
const extras: IDataObject = {};
if (options.contentType) {
body.extras = {
'client::display': {
contentType: options.contentType,
extras['client::display'] = {
contentType: options.contentType,
};
}
const clientNotification: IDataObject = {};
if (options.clickUrl) {
clientNotification.click = {
url: options.clickUrl,
};
}
if (options.bigImageUrl) {
clientNotification.bigImageUrl = options.bigImageUrl;
}
if (Object.keys(clientNotification).length > 0) {
extras['client::notification'] = clientNotification;
}
if (options.intentUrl) {
extras['android::action'] = {
onReceive: {
intentUrl: options.intentUrl,
},
};
}
if (Object.keys(extras).length > 0) {
body.extras = extras;
}
Object.assign(body, additionalFields);
responseData = await gotifyApiRequest.call(this, 'POST', '/message', body);
@@ -0,0 +1,281 @@
import { NodeTestHarness } from '@nodes-testing/node-test-harness';
import nock from 'nock';
describe('Gotify Node', () => {
const baseUrl = 'https://gotify.example.com';
const credentials = {
gotifyApi: {
url: baseUrl,
appApiToken: 'test-app-token',
clientApiToken: 'test-client-token',
},
};
afterEach(() => {
nock.cleanAll();
});
describe('Message Operations', () => {
describe('Create message - basic', () => {
beforeAll(() => {
nock(baseUrl)
.matchHeader('X-Gotify-Key', 'test-app-token')
.post('/message', { message: 'Test message' })
.reply(200, {
id: 1,
appid: 1,
message: 'Test message',
title: '',
priority: 1,
date: '2024-01-01T00:00:00Z',
});
});
new NodeTestHarness().setupTests({
credentials,
workflowFiles: ['create-message-basic.workflow.json'],
});
});
describe('Create message - markdown', () => {
beforeAll(() => {
nock(baseUrl)
.matchHeader('X-Gotify-Key', 'test-app-token')
.post('/message', (body) => {
return (
body.message === 'Markdown message' &&
body.extras?.['client::display']?.contentType === 'text/markdown'
);
})
.reply(200, {
id: 2,
appid: 1,
message: 'Markdown message',
title: '',
priority: 1,
date: '2024-01-01T00:00:00Z',
});
});
new NodeTestHarness().setupTests({
credentials,
workflowFiles: ['create-message-markdown.workflow.json'],
});
});
describe('Create message - click URL', () => {
beforeAll(() => {
nock(baseUrl)
.matchHeader('X-Gotify-Key', 'test-app-token')
.post('/message', (body) => {
return (
body.message === 'Message with click URL' &&
body.extras?.['client::notification']?.click?.url === 'https://example.com'
);
})
.reply(200, {
id: 3,
appid: 1,
message: 'Message with click URL',
title: '',
priority: 1,
date: '2024-01-01T00:00:00Z',
});
});
new NodeTestHarness().setupTests({
credentials,
workflowFiles: ['create-message-click-url.workflow.json'],
});
});
describe('Create message - big image', () => {
beforeAll(() => {
nock(baseUrl)
.matchHeader('X-Gotify-Key', 'test-app-token')
.post('/message', (body) => {
return (
body.message === 'Message with big image' &&
body.extras?.['client::notification']?.bigImageUrl === 'https://example.com/image.jpg'
);
})
.reply(200, {
id: 4,
appid: 1,
message: 'Message with big image',
title: '',
priority: 1,
date: '2024-01-01T00:00:00Z',
});
});
new NodeTestHarness().setupTests({
credentials,
workflowFiles: ['create-message-big-image.workflow.json'],
});
});
describe('Create message - intent URL', () => {
beforeAll(() => {
nock(baseUrl)
.matchHeader('X-Gotify-Key', 'test-app-token')
.post('/message', (body) => {
return (
body.message === 'Message with intent URL' &&
body.extras?.['android::action']?.onReceive?.intentUrl ===
'https://example.com/intent'
);
})
.reply(200, {
id: 5,
appid: 1,
message: 'Message with intent URL',
title: '',
priority: 1,
date: '2024-01-01T00:00:00Z',
});
});
new NodeTestHarness().setupTests({
credentials,
workflowFiles: ['create-message-intent-url.workflow.json'],
});
});
describe('Create message - all extras', () => {
beforeAll(() => {
nock(baseUrl)
.matchHeader('X-Gotify-Key', 'test-app-token')
.post('/message', (body) => {
return (
body.message === 'Message with all extras' &&
body.extras?.['client::display']?.contentType === 'text/markdown' &&
body.extras?.['client::notification']?.click?.url === 'https://example.com' &&
body.extras?.['client::notification']?.bigImageUrl ===
'https://example.com/image.jpg' &&
body.extras?.['android::action']?.onReceive?.intentUrl ===
'https://example.com/intent'
);
})
.reply(200, {
id: 6,
appid: 1,
message: 'Message with all extras',
title: '',
priority: 1,
date: '2024-01-01T00:00:00Z',
});
});
new NodeTestHarness().setupTests({
credentials,
workflowFiles: ['create-message-all-extras.workflow.json'],
});
});
describe('Create message - priority and title', () => {
beforeAll(() => {
nock(baseUrl)
.matchHeader('X-Gotify-Key', 'test-app-token')
.post('/message', (body) => {
return (
body.message === 'Message with priority and title' &&
body.priority === 5 &&
body.title === 'Test Title'
);
})
.reply(200, {
id: 7,
appid: 1,
message: 'Message with priority and title',
title: 'Test Title',
priority: 5,
date: '2024-01-01T00:00:00Z',
});
});
new NodeTestHarness().setupTests({
credentials,
workflowFiles: ['create-message-priority-title.workflow.json'],
});
});
describe('Delete message', () => {
beforeAll(() => {
const mock = nock(baseUrl);
mock.delete('/message/123').matchHeader('X-Gotify-Key', 'test-client-token').reply(200, {});
});
new NodeTestHarness().setupTests({
credentials,
workflowFiles: ['delete-message.workflow.json'],
});
});
describe('Get all messages', () => {
beforeAll(() => {
const mock = nock(baseUrl);
mock
.get('/message')
.query({ limit: 20 })
.matchHeader('X-Gotify-Key', 'test-client-token')
.reply(200, {
messages: [
{
id: 1,
appid: 1,
message: 'Test message 1',
title: '',
priority: 1,
date: '2024-01-01T00:00:00Z',
},
{
id: 2,
appid: 1,
message: 'Test message 2',
title: '',
priority: 1,
date: '2024-01-01T00:00:00Z',
},
],
paging: {
limit: 20,
next: null,
since: 0,
size: 2,
},
});
mock
.get('/message')
.query({ limit: 100 })
.matchHeader('X-Gotify-Key', 'test-client-token')
.reply(200, {
messages: [
{
id: 1,
appid: 1,
message: 'Test message 1',
title: '',
priority: 1,
date: '2024-01-01T00:00:00Z',
},
],
paging: {
limit: 100,
next: null,
since: 0,
size: 1,
},
});
});
new NodeTestHarness().setupTests({
credentials,
workflowFiles: ['get-all-messages.workflow.json'],
});
});
});
});
@@ -0,0 +1,74 @@
{
"name": "create-message-all-extras",
"nodes": [
{
"parameters": {},
"id": "test-trigger-node-id",
"name": "When clicking 'Execute workflow'",
"type": "n8n-nodes-base.manualTrigger",
"typeVersion": 1,
"position": [0, 0]
},
{
"parameters": {
"resource": "message",
"operation": "create",
"message": "Message with all extras",
"options": {
"contentType": "text/markdown",
"clickUrl": "https://example.com",
"bigImageUrl": "https://example.com/image.jpg",
"intentUrl": "https://example.com/intent"
}
},
"id": "test-gotify-node-id",
"name": "Gotify",
"type": "n8n-nodes-base.gotify",
"typeVersion": 1,
"position": [220, 0],
"credentials": {
"gotifyApi": {
"id": "test-credentials-id",
"name": "Test Gotify API"
}
}
}
],
"connections": {
"When clicking 'Execute workflow'": {
"main": [
[
{
"node": "Gotify",
"type": "main",
"index": 0
}
]
]
}
},
"pinData": {
"Gotify": [
{
"json": {
"id": 6,
"appid": 1,
"message": "Message with all extras",
"title": "",
"priority": 1,
"date": "2024-01-01T00:00:00Z"
}
}
]
},
"active": false,
"settings": {
"executionOrder": "v1"
},
"versionId": "test-version-id",
"meta": {
"instanceId": "test-instance-id"
},
"id": "test-workflow-id-6",
"tags": []
}
@@ -0,0 +1,68 @@
{
"name": "create-message-basic",
"nodes": [
{
"parameters": {},
"id": "test-trigger-node-id",
"name": "When clicking 'Execute workflow'",
"type": "n8n-nodes-base.manualTrigger",
"typeVersion": 1,
"position": [0, 0]
},
{
"parameters": {
"resource": "message",
"operation": "create",
"message": "Test message"
},
"id": "test-gotify-node-id",
"name": "Gotify",
"type": "n8n-nodes-base.gotify",
"typeVersion": 1,
"position": [220, 0],
"credentials": {
"gotifyApi": {
"id": "test-credentials-id",
"name": "Test Gotify API"
}
}
}
],
"connections": {
"When clicking 'Execute workflow'": {
"main": [
[
{
"node": "Gotify",
"type": "main",
"index": 0
}
]
]
}
},
"pinData": {
"Gotify": [
{
"json": {
"id": 1,
"appid": 1,
"message": "Test message",
"title": "",
"priority": 1,
"date": "2024-01-01T00:00:00Z"
}
}
]
},
"active": false,
"settings": {
"executionOrder": "v1"
},
"versionId": "test-version-id",
"meta": {
"instanceId": "test-instance-id"
},
"id": "test-workflow-id-1",
"tags": []
}
@@ -0,0 +1,71 @@
{
"name": "create-message-big-image",
"nodes": [
{
"parameters": {},
"id": "test-trigger-node-id",
"name": "When clicking 'Execute workflow'",
"type": "n8n-nodes-base.manualTrigger",
"typeVersion": 1,
"position": [0, 0]
},
{
"parameters": {
"resource": "message",
"operation": "create",
"message": "Message with big image",
"options": {
"bigImageUrl": "https://example.com/image.jpg"
}
},
"id": "test-gotify-node-id",
"name": "Gotify",
"type": "n8n-nodes-base.gotify",
"typeVersion": 1,
"position": [220, 0],
"credentials": {
"gotifyApi": {
"id": "test-credentials-id",
"name": "Test Gotify API"
}
}
}
],
"connections": {
"When clicking 'Execute workflow'": {
"main": [
[
{
"node": "Gotify",
"type": "main",
"index": 0
}
]
]
}
},
"pinData": {
"Gotify": [
{
"json": {
"id": 4,
"appid": 1,
"message": "Message with big image",
"title": "",
"priority": 1,
"date": "2024-01-01T00:00:00Z"
}
}
]
},
"active": false,
"settings": {
"executionOrder": "v1"
},
"versionId": "test-version-id",
"meta": {
"instanceId": "test-instance-id"
},
"id": "test-workflow-id-4",
"tags": []
}
@@ -0,0 +1,71 @@
{
"name": "create-message-click-url",
"nodes": [
{
"parameters": {},
"id": "test-trigger-node-id",
"name": "When clicking 'Execute workflow'",
"type": "n8n-nodes-base.manualTrigger",
"typeVersion": 1,
"position": [0, 0]
},
{
"parameters": {
"resource": "message",
"operation": "create",
"message": "Message with click URL",
"options": {
"clickUrl": "https://example.com"
}
},
"id": "test-gotify-node-id",
"name": "Gotify",
"type": "n8n-nodes-base.gotify",
"typeVersion": 1,
"position": [220, 0],
"credentials": {
"gotifyApi": {
"id": "test-credentials-id",
"name": "Test Gotify API"
}
}
}
],
"connections": {
"When clicking 'Execute workflow'": {
"main": [
[
{
"node": "Gotify",
"type": "main",
"index": 0
}
]
]
}
},
"pinData": {
"Gotify": [
{
"json": {
"id": 3,
"appid": 1,
"message": "Message with click URL",
"title": "",
"priority": 1,
"date": "2024-01-01T00:00:00Z"
}
}
]
},
"active": false,
"settings": {
"executionOrder": "v1"
},
"versionId": "test-version-id",
"meta": {
"instanceId": "test-instance-id"
},
"id": "test-workflow-id-3",
"tags": []
}
@@ -0,0 +1,71 @@
{
"name": "create-message-intent-url",
"nodes": [
{
"parameters": {},
"id": "test-trigger-node-id",
"name": "When clicking 'Execute workflow'",
"type": "n8n-nodes-base.manualTrigger",
"typeVersion": 1,
"position": [0, 0]
},
{
"parameters": {
"resource": "message",
"operation": "create",
"message": "Message with intent URL",
"options": {
"intentUrl": "https://example.com/intent"
}
},
"id": "test-gotify-node-id",
"name": "Gotify",
"type": "n8n-nodes-base.gotify",
"typeVersion": 1,
"position": [220, 0],
"credentials": {
"gotifyApi": {
"id": "test-credentials-id",
"name": "Test Gotify API"
}
}
}
],
"connections": {
"When clicking 'Execute workflow'": {
"main": [
[
{
"node": "Gotify",
"type": "main",
"index": 0
}
]
]
}
},
"pinData": {
"Gotify": [
{
"json": {
"id": 5,
"appid": 1,
"message": "Message with intent URL",
"title": "",
"priority": 1,
"date": "2024-01-01T00:00:00Z"
}
}
]
},
"active": false,
"settings": {
"executionOrder": "v1"
},
"versionId": "test-version-id",
"meta": {
"instanceId": "test-instance-id"
},
"id": "test-workflow-id-5",
"tags": []
}
@@ -0,0 +1,71 @@
{
"name": "create-message-markdown",
"nodes": [
{
"parameters": {},
"id": "test-trigger-node-id",
"name": "When clicking 'Execute workflow'",
"type": "n8n-nodes-base.manualTrigger",
"typeVersion": 1,
"position": [0, 0]
},
{
"parameters": {
"resource": "message",
"operation": "create",
"message": "Markdown message",
"options": {
"contentType": "text/markdown"
}
},
"id": "test-gotify-node-id",
"name": "Gotify",
"type": "n8n-nodes-base.gotify",
"typeVersion": 1,
"position": [220, 0],
"credentials": {
"gotifyApi": {
"id": "test-credentials-id",
"name": "Test Gotify API"
}
}
}
],
"connections": {
"When clicking 'Execute workflow'": {
"main": [
[
{
"node": "Gotify",
"type": "main",
"index": 0
}
]
]
}
},
"pinData": {
"Gotify": [
{
"json": {
"id": 2,
"appid": 1,
"message": "Markdown message",
"title": "",
"priority": 1,
"date": "2024-01-01T00:00:00Z"
}
}
]
},
"active": false,
"settings": {
"executionOrder": "v1"
},
"versionId": "test-version-id",
"meta": {
"instanceId": "test-instance-id"
},
"id": "test-workflow-id-2",
"tags": []
}
@@ -0,0 +1,72 @@
{
"name": "create-message-priority-title",
"nodes": [
{
"parameters": {},
"id": "test-trigger-node-id",
"name": "When clicking 'Execute workflow'",
"type": "n8n-nodes-base.manualTrigger",
"typeVersion": 1,
"position": [0, 0]
},
{
"parameters": {
"resource": "message",
"operation": "create",
"message": "Message with priority and title",
"additionalFields": {
"priority": 5,
"title": "Test Title"
}
},
"id": "test-gotify-node-id",
"name": "Gotify",
"type": "n8n-nodes-base.gotify",
"typeVersion": 1,
"position": [220, 0],
"credentials": {
"gotifyApi": {
"id": "test-credentials-id",
"name": "Test Gotify API"
}
}
}
],
"connections": {
"When clicking 'Execute workflow'": {
"main": [
[
{
"node": "Gotify",
"type": "main",
"index": 0
}
]
]
}
},
"pinData": {
"Gotify": [
{
"json": {
"id": 7,
"appid": 1,
"message": "Message with priority and title",
"title": "Test Title",
"priority": 5,
"date": "2024-01-01T00:00:00Z"
}
}
]
},
"active": false,
"settings": {
"executionOrder": "v1"
},
"versionId": "test-version-id",
"meta": {
"instanceId": "test-instance-id"
},
"id": "test-workflow-id-7",
"tags": []
}
@@ -0,0 +1,63 @@
{
"name": "delete-message",
"nodes": [
{
"parameters": {},
"id": "test-trigger-node-id",
"name": "When clicking 'Execute workflow'",
"type": "n8n-nodes-base.manualTrigger",
"typeVersion": 1,
"position": [0, 0]
},
{
"parameters": {
"resource": "message",
"operation": "delete",
"messageId": "123"
},
"id": "test-gotify-node-id",
"name": "Gotify",
"type": "n8n-nodes-base.gotify",
"typeVersion": 1,
"position": [220, 0],
"credentials": {
"gotifyApi": {
"id": "test-credentials-id",
"name": "Test Gotify API"
}
}
}
],
"connections": {
"When clicking 'Execute workflow'": {
"main": [
[
{
"node": "Gotify",
"type": "main",
"index": 0
}
]
]
}
},
"pinData": {
"Gotify": [
{
"json": {
"success": true
}
}
]
},
"active": false,
"settings": {
"executionOrder": "v1"
},
"versionId": "test-version-id",
"meta": {
"instanceId": "test-instance-id"
},
"id": "test-workflow-id-8",
"tags": []
}
@@ -0,0 +1,79 @@
{
"name": "get-all-messages",
"nodes": [
{
"parameters": {},
"id": "test-trigger-node-id",
"name": "When clicking 'Execute workflow'",
"type": "n8n-nodes-base.manualTrigger",
"typeVersion": 1,
"position": [0, 0]
},
{
"parameters": {
"resource": "message",
"operation": "getAll",
"returnAll": false,
"limit": 20
},
"id": "test-gotify-node-id",
"name": "Gotify",
"type": "n8n-nodes-base.gotify",
"typeVersion": 1,
"position": [220, 0],
"credentials": {
"gotifyApi": {
"id": "test-credentials-id",
"name": "Test Gotify API"
}
}
}
],
"connections": {
"When clicking 'Execute workflow'": {
"main": [
[
{
"node": "Gotify",
"type": "main",
"index": 0
}
]
]
}
},
"pinData": {
"Gotify": [
{
"json": {
"id": 1,
"appid": 1,
"message": "Test message 1",
"title": "",
"priority": 1,
"date": "2024-01-01T00:00:00Z"
}
},
{
"json": {
"id": 2,
"appid": 1,
"message": "Test message 2",
"title": "",
"priority": 1,
"date": "2024-01-01T00:00:00Z"
}
}
]
},
"active": false,
"settings": {
"executionOrder": "v1"
},
"versionId": "test-version-id",
"meta": {
"instanceId": "test-instance-id"
},
"id": "test-workflow-id-9",
"tags": []
}