diff --git a/components/planning_center/.gitignore b/components/planning_center/.gitignore deleted file mode 100644 index ec761ccab7595..0000000000000 --- a/components/planning_center/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -*.js -*.mjs -dist \ No newline at end of file diff --git a/components/planning_center/app/planning_center.app.ts b/components/planning_center/app/planning_center.app.ts deleted file mode 100644 index 92b537320f1ce..0000000000000 --- a/components/planning_center/app/planning_center.app.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { defineApp } from "@pipedream/types"; - -export default defineApp({ - type: "app", - app: "planning_center", - propDefinitions: {}, - methods: { - // this.$auth contains connected account data - authKeys() { - console.log(Object.keys(this.$auth)); - }, - }, -}); diff --git a/components/planning_center/package.json b/components/planning_center/package.json index 4b78ac18cce14..69b39d0973dee 100644 --- a/components/planning_center/package.json +++ b/components/planning_center/package.json @@ -1,16 +1,18 @@ { "name": "@pipedream/planning_center", - "version": "0.0.2", + "version": "0.1.0", "description": "Pipedream Planning Center Components", - "main": "dist/app/planning_center.app.mjs", + "main": "planning_center.app.mjs", "keywords": [ "pipedream", "planning_center" ], - "files": ["dist"], "homepage": "https://pipedream.com/apps/planning_center", "author": "Pipedream (https://pipedream.com/)", "publishConfig": { "access": "public" + }, + "dependencies": { + "@pipedream/platform": "^3.0.3" } } diff --git a/components/planning_center/planning_center.app.mjs b/components/planning_center/planning_center.app.mjs new file mode 100644 index 0000000000000..c36e1979471cd --- /dev/null +++ b/components/planning_center/planning_center.app.mjs @@ -0,0 +1,98 @@ +import { axios } from "@pipedream/platform"; +const DEFAULT_LIMIT = 25; +const MAX_LIMIT = 100; + +export default { + type: "app", + app: "planning_center", + propDefinitions: { + listId: { + type: "string", + label: "List ID", + description: "The ID of the list to monitor for new persons", + async options({ page }) { + const { data } = await this.listLists({ + params: { + per_page: DEFAULT_LIMIT, + offset: page * DEFAULT_LIMIT, + }, + }); + return data?.map(({ + id: value, attributes, + }) => ({ + label: attributes.name_or_description, + value, + })) || []; + }, + }, + }, + methods: { + _baseUrl() { + return "https://api.planningcenteronline.com"; + }, + _makeRequest({ + $ = this, + path, + ...otherOpts + }) { + return axios($, { + url: `${this._baseUrl()}${path}`, + headers: { + Authorization: `Bearer ${this.$auth.oauth_access_token}`, + }, + ...otherOpts, + }); + }, + getListResult({ + listId, ...opts + }) { + return this._makeRequest({ + path: `/people/v2/lists/${listId}/list_results`, + ...opts, + }); + }, + listLists(opts = {}) { + return this._makeRequest({ + path: "/people/v2/lists", + ...opts, + }); + }, + listDonations(opts = {}) { + return this._makeRequest({ + path: "/giving/v2/donations", + ...opts, + }); + }, + getCalendarEvents(opts = {}) { + return this._makeRequest({ + path: "/calendar/v2/events", + ...opts, + }); + }, + async *paginate({ + fn, args, max, + }) { + args = { + ...args, + params: { + ...args?.params, + per_page: MAX_LIMIT, + offset: 0, + }, + }; + let total, count = 0; + + do { + const { data } = await fn(args); + for (const item of data) { + yield item; + if (max && ++count >= max) { + return; + } + } + total = data?.length; + args.params.offset += args.params.per_page; + } while (total); + }, + }, +}; diff --git a/components/planning_center/sources/common/base.mjs b/components/planning_center/sources/common/base.mjs new file mode 100644 index 0000000000000..a47c8a2922e39 --- /dev/null +++ b/components/planning_center/sources/common/base.mjs @@ -0,0 +1,82 @@ +import planningCenter from "../../planning_center.app.mjs"; +import { DEFAULT_POLLING_SOURCE_TIMER_INTERVAL } from "@pipedream/platform"; + +export default { + props: { + planningCenter, + db: "$.service.db", + timer: { + type: "$.interface.timer", + default: { + intervalSeconds: DEFAULT_POLLING_SOURCE_TIMER_INTERVAL, + }, + }, + }, + methods: { + _getLastTs() { + return this.db.get("lastTs") || 0; + }, + _setLastTs(lastTs) { + this.db.set("lastTs", lastTs); + }, + getArgs() { + return {}; + }, + getTs(item) { + return Date.parse(item.attributes.created_at); + }, + isSorted() { + return true; + }, + emitEvent(item) { + const meta = this.generateMeta(item); + this.$emit(item, meta); + }, + generateMeta(item) { + return { + id: item.id, + summary: this.getSummary(item), + ts: this.getTs(item), + }; + }, + async processEvent(max) { + const lastTs = this._getLastTs(); + let maxTs = lastTs; + const fn = this.getResourceFn(); + const args = this.getArgs(); + const isSorted = this.isSorted(); + + const results = this.planningCenter.paginate({ + fn, + args, + max, + }); + + for await (const item of results) { + const ts = this.getTs(item); + if (ts >= lastTs) { + this.emitEvent(item); + maxTs = Math.max(ts, maxTs); + } else if (isSorted) { + break; + } + } + + this._setLastTs(maxTs); + }, + getResourceFn() { + throw new Error("getResourceFn is not implemented"); + }, + getSummary() { + throw new Error("getSummary is not implemented"); + }, + }, + hooks: { + async deploy() { + await this.processEvent(25); + }, + }, + async run() { + await this.processEvent(); + }, +}; diff --git a/components/planning_center/sources/new-calendar-event/new-calendar-event.mjs b/components/planning_center/sources/new-calendar-event/new-calendar-event.mjs new file mode 100644 index 0000000000000..dfaf1c909b6ab --- /dev/null +++ b/components/planning_center/sources/new-calendar-event/new-calendar-event.mjs @@ -0,0 +1,23 @@ +import common from "../common/base.mjs"; + +export default { + ...common, + key: "planning_center-new-calendar-event", + name: "New Calendar Event", + description: "Emit new event when a new calendar event is created. [See the documentation](https://developer.planning.center/docs/#/apps/calendar/2022-07-07/vertices/event)", + version: "0.0.1", + type: "source", + dedupe: "unique", + methods: { + ...common.methods, + getResourceFn() { + return this.planningCenter.getCalendarEvents; + }, + isSorted() { + return false; + }, + getSummary(item) { + return `New Calendar Event with ID: ${item.id}`; + }, + }, +}; diff --git a/components/planning_center/sources/new-donation/new-donation.mjs b/components/planning_center/sources/new-donation/new-donation.mjs new file mode 100644 index 0000000000000..aff334faf72b2 --- /dev/null +++ b/components/planning_center/sources/new-donation/new-donation.mjs @@ -0,0 +1,27 @@ +import common from "../common/base.mjs"; + +export default { + ...common, + key: "planning_center-new-donation", + name: "New Donation Received", + description: "Emit new event when a donation is received. [See the documentation](https://developer.planning.center/docs/#/apps/giving/2019-10-18/vertices/donation)", + version: "0.0.1", + type: "source", + dedupe: "unique", + methods: { + ...common.methods, + getResourceFn() { + return this.planningCenter.listDonations; + }, + getArgs() { + return { + params: { + order: "-created_at", + }, + }; + }, + getSummary(item) { + return `New Donation with ID: ${item.id}`; + }, + }, +}; diff --git a/components/planning_center/sources/new-list-result/new-list-result.mjs b/components/planning_center/sources/new-list-result/new-list-result.mjs new file mode 100644 index 0000000000000..c418682e44b93 --- /dev/null +++ b/components/planning_center/sources/new-list-result/new-list-result.mjs @@ -0,0 +1,37 @@ +import common from "../common/base.mjs"; + +export default { + ...common, + key: "planning_center-new-list-result", + name: "New Person Added to List", + description: "Emit new event when a person is added to the specified list. [See the documentation](https://developer.planning.center/docs/#/apps/people/2025-03-20/vertices/list_result)", + version: "0.0.1", + type: "source", + dedupe: "unique", + props: { + ...common.props, + listId: { + propDefinition: [ + common.props.planningCenter, + "listId", + ], + }, + }, + methods: { + ...common.methods, + getResourceFn() { + return this.planningCenter.getListResult; + }, + getArgs() { + return { + listId: this.listId, + params: { + order: "-created_at", + }, + }; + }, + getSummary(item) { + return `New List Result with ID: ${item.id}`; + }, + }, +}; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b5ecaa8caadd1..ff196db2f461a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9939,7 +9939,11 @@ importers: components/planly: {} - components/planning_center: {} + components/planning_center: + dependencies: + '@pipedream/platform': + specifier: ^3.0.3 + version: 3.0.3 components/planpoint: {}