diff --git a/packages/backend/src/apps/wordpress/assets/favicon.svg b/packages/backend/src/apps/wordpress/assets/favicon.svg new file mode 100644 index 00000000..39be6e12 --- /dev/null +++ b/packages/backend/src/apps/wordpress/assets/favicon.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/packages/backend/src/apps/wordpress/auth/generate-auth-url.ts b/packages/backend/src/apps/wordpress/auth/generate-auth-url.ts new file mode 100644 index 00000000..ef4e0b84 --- /dev/null +++ b/packages/backend/src/apps/wordpress/auth/generate-auth-url.ts @@ -0,0 +1,24 @@ +import { URL, URLSearchParams } from 'node:url'; +import { IGlobalVariable } from '@automatisch/types'; + +import appConfig from '../../../config/app'; +import getInstanceUrl from '../common/get-instance-url'; + +export default async function generateAuthUrl($: IGlobalVariable) { + const successUrl = new URL( + '/app/wordpress/connections/add', + appConfig.webAppUrl + ).toString(); + const baseUrl = getInstanceUrl($); + + const searchParams = new URLSearchParams({ + app_name: 'automatisch', + success_url: successUrl, + }); + + const url = new URL(`/wp-admin/authorize-application.php?${searchParams}`, baseUrl).toString(); + + await $.auth.set({ + url, + }); +} diff --git a/packages/backend/src/apps/wordpress/auth/index.ts b/packages/backend/src/apps/wordpress/auth/index.ts new file mode 100644 index 00000000..e4883f11 --- /dev/null +++ b/packages/backend/src/apps/wordpress/auth/index.ts @@ -0,0 +1,24 @@ +import generateAuthUrl from './generate-auth-url'; +import isStillVerified from './is-still-verified'; +import verifyCredentials from './verify-credentials'; + +export default { + fields: [ + { + key: 'instanceUrl', + label: 'WordPress instance URL', + type: 'string' as const, + required: false, + readOnly: false, + value: null, + placeholder: null, + description: 'Your WordPress instance URL.', + docUrl: 'https://automatisch.io/docs/wordpress#instance-url', + clickToCopy: true, + }, + ], + + generateAuthUrl, + isStillVerified, + verifyCredentials, +}; diff --git a/packages/backend/src/apps/wordpress/auth/is-still-verified.ts b/packages/backend/src/apps/wordpress/auth/is-still-verified.ts new file mode 100644 index 00000000..9cc179ed --- /dev/null +++ b/packages/backend/src/apps/wordpress/auth/is-still-verified.ts @@ -0,0 +1,9 @@ +import { IGlobalVariable } from '@automatisch/types'; + +const isStillVerified = async ($: IGlobalVariable) => { + await $.http.get('?rest_route=/wp/v2/settings'); + + return true; +}; + +export default isStillVerified; diff --git a/packages/backend/src/apps/wordpress/auth/verify-credentials.ts b/packages/backend/src/apps/wordpress/auth/verify-credentials.ts new file mode 100644 index 00000000..0c9f4f73 --- /dev/null +++ b/packages/backend/src/apps/wordpress/auth/verify-credentials.ts @@ -0,0 +1,24 @@ +import { IGlobalVariable } from '@automatisch/types'; + +const verifyCredentials = async ($: IGlobalVariable) => { + const instanceUrl = $.auth.data.instanceUrl as string; + const password = $.auth.data.password as string; + const siteUrl = $.auth.data.site_url as string; + const url = $.auth.data.url as string; + const userLogin = $.auth.data.user_login as string; + + if (!password) { + throw new Error('Failed while authorizing!'); + } + + await $.auth.set({ + screenName: `${userLogin} @ ${siteUrl}`, + instanceUrl, + password, + siteUrl, + url, + userLogin, + }); +}; + +export default verifyCredentials; diff --git a/packages/backend/src/apps/wordpress/common/add-auth-header.ts b/packages/backend/src/apps/wordpress/common/add-auth-header.ts new file mode 100644 index 00000000..af5f1237 --- /dev/null +++ b/packages/backend/src/apps/wordpress/common/add-auth-header.ts @@ -0,0 +1,17 @@ +import { TBeforeRequest } from '@automatisch/types'; + +const addAuthHeader: TBeforeRequest = ($, requestConfig) => { + const userLogin = $.auth.data.userLogin as string; + const password = $.auth.data.password as string; + + if (userLogin && password) { + requestConfig.auth = { + username: userLogin, + password, + }; + } + + return requestConfig; +}; + +export default addAuthHeader; diff --git a/packages/backend/src/apps/wordpress/common/get-instance-url.ts b/packages/backend/src/apps/wordpress/common/get-instance-url.ts new file mode 100644 index 00000000..72b9bc73 --- /dev/null +++ b/packages/backend/src/apps/wordpress/common/get-instance-url.ts @@ -0,0 +1,7 @@ +import { IGlobalVariable } from '@automatisch/types'; + +const getInstanceUrl = ($: IGlobalVariable): string => { + return $.auth.data.instanceUrl as string; +}; + +export default getInstanceUrl; diff --git a/packages/backend/src/apps/wordpress/common/set-base-url.ts b/packages/backend/src/apps/wordpress/common/set-base-url.ts new file mode 100644 index 00000000..f02c49e9 --- /dev/null +++ b/packages/backend/src/apps/wordpress/common/set-base-url.ts @@ -0,0 +1,12 @@ +import { TBeforeRequest } from '@automatisch/types'; + +const setBaseUrl: TBeforeRequest = ($, requestConfig) => { + const instanceUrl = $.auth.data.instanceUrl as string; + if (instanceUrl) { + requestConfig.baseURL = instanceUrl; + } + + return requestConfig; +}; + +export default setBaseUrl; diff --git a/packages/backend/src/apps/wordpress/dynamic-data/index.ts b/packages/backend/src/apps/wordpress/dynamic-data/index.ts new file mode 100644 index 00000000..640a00f3 --- /dev/null +++ b/packages/backend/src/apps/wordpress/dynamic-data/index.ts @@ -0,0 +1,3 @@ +import listStatuses from './list-statuses'; + +export default [listStatuses]; diff --git a/packages/backend/src/apps/wordpress/dynamic-data/list-statuses/index.ts b/packages/backend/src/apps/wordpress/dynamic-data/list-statuses/index.ts new file mode 100644 index 00000000..0a6af758 --- /dev/null +++ b/packages/backend/src/apps/wordpress/dynamic-data/list-statuses/index.ts @@ -0,0 +1,37 @@ +import { IGlobalVariable, IJSONObject } from '@automatisch/types'; + +type Status = { + slug: string; + name: string; +} +type Statuses = Record; + +export default { + name: 'List statuses', + key: 'listStatuses', + + async run($: IGlobalVariable) { + const statuses: { + data: IJSONObject[]; + } = { + data: [], + }; + + const { data } = await $.http.get('?rest_route=/wp/v2/statuses'); + + if (!data) return statuses; + + const values = Object.values(data); + + if (!values?.length) return statuses; + + for (const status of values) { + statuses.data.push({ + value: status.slug, + name: status.name, + }) + } + + return statuses; + }, +}; diff --git a/packages/backend/src/apps/wordpress/index.d.ts b/packages/backend/src/apps/wordpress/index.d.ts new file mode 100644 index 00000000..e69de29b diff --git a/packages/backend/src/apps/wordpress/index.ts b/packages/backend/src/apps/wordpress/index.ts new file mode 100644 index 00000000..521f7e93 --- /dev/null +++ b/packages/backend/src/apps/wordpress/index.ts @@ -0,0 +1,21 @@ +import defineApp from '../../helpers/define-app'; +import addAuthHeader from './common/add-auth-header'; +import setBaseUrl from './common/set-base-url'; +import auth from './auth'; +import triggers from './triggers'; +import dynamicData from './dynamic-data'; + +export default defineApp({ + name: 'WordPress', + key: 'wordpress', + iconUrl: '{BASE_URL}/apps/wordpress/assets/favicon.svg', + authDocUrl: 'https://automatisch.io/docs/apps/wordpress/connection', + supportsConnections: true, + baseUrl: 'https://wordpress.com', + apiBaseUrl: '', + primaryColor: '464342', + beforeRequest: [setBaseUrl, addAuthHeader], + auth, + triggers, + dynamicData, +}); diff --git a/packages/backend/src/apps/wordpress/triggers/index.ts b/packages/backend/src/apps/wordpress/triggers/index.ts new file mode 100644 index 00000000..7d0bbda4 --- /dev/null +++ b/packages/backend/src/apps/wordpress/triggers/index.ts @@ -0,0 +1,3 @@ +import newPost from './new-post'; + +export default [newPost]; diff --git a/packages/backend/src/apps/wordpress/triggers/new-post/index.ts b/packages/backend/src/apps/wordpress/triggers/new-post/index.ts new file mode 100644 index 00000000..5d481980 --- /dev/null +++ b/packages/backend/src/apps/wordpress/triggers/new-post/index.ts @@ -0,0 +1,60 @@ +import defineTrigger from '../../../../helpers/define-trigger'; + +export default defineTrigger({ + name: 'New post', + key: 'newPost', + description: 'Triggers when a new post is created.', + arguments: [ + { + label: 'Status', + key: 'status', + type: 'dropdown' as const, + required: true, + variables: true, + source: { + type: 'query', + name: 'getDynamicData', + arguments: [ + { + name: 'key', + value: 'listStatuses', + }, + ], + }, + }, + ], + + async run($) { + const params = { + per_page: 100, + page: 1, + order: 'desc', + orderby: 'date', + status: $.step.parameters.status || '', + }; + + let totalPages = 1; + do { + const { + data, + headers + } = await $.http.get('?rest_route=/wp/v2/posts', { params }); + + params.page = params.page + 1; + totalPages = Number(headers['x-wp-totalpages']); + + if (data.length) { + for (const post of data) { + const dataItem = { + raw: post, + meta: { + internalId: post.id.toString(), + }, + }; + + $.pushTriggerItem(dataItem); + } + } + } while (params.page <= totalPages); + }, +}); diff --git a/packages/docs/pages/.vitepress/config.js b/packages/docs/pages/.vitepress/config.js index 7ba17216..20d0b618 100644 --- a/packages/docs/pages/.vitepress/config.js +++ b/packages/docs/pages/.vitepress/config.js @@ -337,6 +337,15 @@ export default defineConfig({ { text: 'Connection', link: '/apps/webhooks/connection' }, ], }, + { + text: 'WordPress', + collapsible: true, + collapsed: true, + items: [ + { text: 'Triggers', link: '/apps/wordpress/triggers' }, + { text: 'Connection', link: '/apps/wordpress/connection' }, + ], + }, ], '/': [ { diff --git a/packages/docs/pages/apps/wordpress/connection.md b/packages/docs/pages/apps/wordpress/connection.md new file mode 100644 index 00000000..9cce51bb --- /dev/null +++ b/packages/docs/pages/apps/wordpress/connection.md @@ -0,0 +1,9 @@ +# WordPress + +:::info +This page explains the steps you need to follow to set up the WordPress connection in Automatisch. If any of the steps are outdated, please let us know! +::: + +1. Add your WordPress public URL (without any path in the address) in the **WordPress instance URL** field on Automatisch. +1. Click **Submit** button on Automatisch. +1. Congrats! Start using your new WordPress connection within the flows. diff --git a/packages/docs/pages/apps/wordpress/triggers.md b/packages/docs/pages/apps/wordpress/triggers.md new file mode 100644 index 00000000..a41d54d7 --- /dev/null +++ b/packages/docs/pages/apps/wordpress/triggers.md @@ -0,0 +1,12 @@ +--- +favicon: /favicons/wordpress.svg +items: + - name: New post + desc: Triggers when a new post is created. +--- + + + + diff --git a/packages/docs/pages/guide/available-apps.md b/packages/docs/pages/guide/available-apps.md index f4568916..35f6e678 100644 --- a/packages/docs/pages/guide/available-apps.md +++ b/packages/docs/pages/guide/available-apps.md @@ -35,3 +35,4 @@ Following integrations are currently supported by Automatisch. - [Twitter](/apps/twitter/triggers) - [Typeform](/apps/typeform/triggers) - [Webhooks](/apps/webhooks/triggers) +- [WordPress](/apps/wordpress/triggers) diff --git a/packages/docs/pages/public/favicons/wordpress.svg b/packages/docs/pages/public/favicons/wordpress.svg new file mode 100644 index 00000000..39be6e12 --- /dev/null +++ b/packages/docs/pages/public/favicons/wordpress.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file