diff --git a/packages/backend/src/apps/pushover/actions/index.ts b/packages/backend/src/apps/pushover/actions/index.ts new file mode 100644 index 00000000..8b423a8a --- /dev/null +++ b/packages/backend/src/apps/pushover/actions/index.ts @@ -0,0 +1,3 @@ +import sendAPushoverNotification from './send-a-pushover-notification'; + +export default [sendAPushoverNotification]; diff --git a/packages/backend/src/apps/pushover/actions/send-a-pushover-notification/index.ts b/packages/backend/src/apps/pushover/actions/send-a-pushover-notification/index.ts new file mode 100644 index 00000000..504f7375 --- /dev/null +++ b/packages/backend/src/apps/pushover/actions/send-a-pushover-notification/index.ts @@ -0,0 +1,136 @@ +import { IJSONArray, IJSONObject } from '@automatisch/types'; +import defineAction from '../../../../helpers/define-action'; + +export default defineAction({ + name: 'Send a Pushover Notification', + key: 'sendPushoverNotification', + description: + 'Generates a Pushover notification on the devices you have subscribed to.', + arguments: [ + { + label: 'Title', + key: 'title', + type: 'string' as const, + required: false, + description: 'An optional title displayed with the message.', + variables: true, + }, + { + label: 'Message', + key: 'message', + type: 'string' as const, + required: true, + description: 'The main message text of your notification.', + variables: true, + }, + { + label: 'Priority', + key: 'priority', + type: 'dropdown' as const, + required: false, + description: '', + variables: true, + options: [ + { label: 'Lowest (no notification, just in-app message)', value: -2 }, + { label: 'Low (no sound or vibration)', value: -1 }, + { label: 'Normal', value: 0 }, + { label: 'High (bypass quiet hours, highlight)', value: 1 }, + { + label: 'Emergency (repeat every 30 seconds until acknowledged)', + value: 2, + }, + ], + }, + { + label: 'Sound', + key: 'sound', + type: 'dropdown' as const, + required: false, + description: 'Optional sound to override your default.', + variables: true, + source: { + type: 'query', + name: 'getDynamicData', + arguments: [ + { + name: 'key', + value: 'listSounds', + }, + ], + }, + }, + { + label: 'URL', + key: 'url', + type: 'string' as const, + required: false, + description: 'URL to display with message.', + variables: true, + }, + { + label: 'URL Title', + key: 'urlTitle', + type: 'string' as const, + required: false, + description: + 'Title of URL to display, otherwise URL itself will be displayed.', + variables: true, + }, + { + label: 'Devices', + key: 'devices', + type: 'dynamic' as const, + required: false, + description: '', + fields: [ + { + label: 'Device', + key: 'device', + type: 'dropdown' as const, + required: false, + description: + 'Restrict sending to just these devices on your account.', + variables: true, + source: { + type: 'query', + name: 'getDynamicData', + arguments: [ + { + name: 'key', + value: 'listDevices', + }, + ], + }, + }, + ], + }, + ], + + async run($) { + const { title, message, priority, sound, url, urlTitle } = + $.step.parameters; + + const devices = $.step.parameters.devices as IJSONArray; + const allDevices = devices + .map((device: IJSONObject) => device.device) + .join(','); + + const payload = { + token: $.auth.data.apiToken, + user: $.auth.data.userKey, + title, + message, + priority, + sound, + url, + url_title: urlTitle, + device: allDevices, + }; + + const { data } = await $.http.post('/1/messages.json', payload); + + $.setActionItem({ + raw: data, + }); + }, +}); diff --git a/packages/backend/src/apps/pushover/dynamic-data/index.ts b/packages/backend/src/apps/pushover/dynamic-data/index.ts new file mode 100644 index 00000000..28aececc --- /dev/null +++ b/packages/backend/src/apps/pushover/dynamic-data/index.ts @@ -0,0 +1,4 @@ +import listDevices from './list-devices'; +import listSounds from './list-sounds'; + +export default [listDevices, listSounds]; diff --git a/packages/backend/src/apps/pushover/dynamic-data/list-devices/index.ts b/packages/backend/src/apps/pushover/dynamic-data/list-devices/index.ts new file mode 100644 index 00000000..ef5d6180 --- /dev/null +++ b/packages/backend/src/apps/pushover/dynamic-data/list-devices/index.ts @@ -0,0 +1,32 @@ +import { IGlobalVariable, IJSONObject } from '@automatisch/types'; + +export default { + name: 'List devices', + key: 'listDevices', + + async run($: IGlobalVariable) { + const devices: { + data: IJSONObject[]; + } = { + data: [], + }; + + const { data } = await $.http.post(`/1/users/validate.json`, { + token: $.auth.data.apiToken, + user: $.auth.data.userKey, + }); + + if (!data?.devices?.length) { + return; + } + + for (const device of data.devices) { + devices.data.push({ + value: device, + name: device, + }); + } + + return devices; + }, +}; diff --git a/packages/backend/src/apps/pushover/dynamic-data/list-sounds/index.ts b/packages/backend/src/apps/pushover/dynamic-data/list-sounds/index.ts new file mode 100644 index 00000000..c45f1fe0 --- /dev/null +++ b/packages/backend/src/apps/pushover/dynamic-data/list-sounds/index.ts @@ -0,0 +1,30 @@ +import { IGlobalVariable, IJSONObject } from '@automatisch/types'; + +export default { + name: 'List sounds', + key: 'listSounds', + + async run($: IGlobalVariable) { + const sounds: { + data: IJSONObject[]; + } = { + data: [], + }; + + const params = { + token: $.auth.data.apiToken, + }; + + const { data } = await $.http.get(`/1/sounds.json`, { params }); + const soundEntries = Object.entries(data.sounds); + + for (const [key, value] of soundEntries) { + sounds.data.push({ + value: key, + name: value as string, + }); + } + + return sounds; + }, +}; diff --git a/packages/backend/src/apps/pushover/index.ts b/packages/backend/src/apps/pushover/index.ts index 212df7d3..6a88e23d 100644 --- a/packages/backend/src/apps/pushover/index.ts +++ b/packages/backend/src/apps/pushover/index.ts @@ -1,5 +1,7 @@ import defineApp from '../../helpers/define-app'; import auth from './auth'; +import actions from './actions'; +import dynamicData from './dynamic-data'; export default defineApp({ name: 'Pushover', @@ -11,4 +13,6 @@ export default defineApp({ primaryColor: '249DF1', supportsConnections: true, auth, + actions, + dynamicData, }); diff --git a/packages/docs/pages/.vitepress/config.js b/packages/docs/pages/.vitepress/config.js index 741200f3..8fe263df 100644 --- a/packages/docs/pages/.vitepress/config.js +++ b/packages/docs/pages/.vitepress/config.js @@ -266,7 +266,10 @@ export default defineConfig({ text: 'Pushover', collapsible: true, collapsed: true, - items: [{ text: 'Connection', link: '/apps/pushover/connection' }], + items: [ + { text: 'Actions', link: '/apps/pushover/actions' }, + { text: 'Connection', link: '/apps/pushover/connection' }, + ], }, { text: 'RSS', diff --git a/packages/docs/pages/apps/pushover/actions.md b/packages/docs/pages/apps/pushover/actions.md new file mode 100644 index 00000000..8e799a17 --- /dev/null +++ b/packages/docs/pages/apps/pushover/actions.md @@ -0,0 +1,12 @@ +--- +favicon: /favicons/pushover.svg +items: + - name: Send a Pushover Notification + desc: Generates a Pushover notification on the devices you have subscribed to. +--- + + + + diff --git a/packages/docs/pages/guide/available-apps.md b/packages/docs/pages/guide/available-apps.md index 8b6a0d9c..b6f2d901 100644 --- a/packages/docs/pages/guide/available-apps.md +++ b/packages/docs/pages/guide/available-apps.md @@ -27,6 +27,7 @@ The following integrations are currently supported by Automatisch. - [Pipedrive](/apps/pipedrive/triggers) - [Placetel](/apps/placetel/triggers) - [PostgreSQL](/apps/postgresql/actions) +- [Pushover](/apps/pushover/actions) - [RSS](/apps/rss/triggers) - [Salesforce](/apps/salesforce/triggers) - [Scheduler](/apps/scheduler/triggers)