diff --git a/components/cronlytic/cronlytic.app.mjs b/components/cronlytic/cronlytic.app.mjs index 0aaf08165d6b0..0da2c886ae83d 100644 --- a/components/cronlytic/cronlytic.app.mjs +++ b/components/cronlytic/cronlytic.app.mjs @@ -8,4 +8,4 @@ export default { console.log(Object.keys(this.$auth)); }, }, -}; \ No newline at end of file +}; diff --git a/components/deep_tagger/deep_tagger.app.mjs b/components/deep_tagger/deep_tagger.app.mjs index 6ebba7a147af2..553f535d95bef 100644 --- a/components/deep_tagger/deep_tagger.app.mjs +++ b/components/deep_tagger/deep_tagger.app.mjs @@ -8,4 +8,4 @@ export default { console.log(Object.keys(this.$auth)); }, }, -}; \ No newline at end of file +}; diff --git a/components/ticketsauce/actions/get-event-details/get-event-details.mjs b/components/ticketsauce/actions/get-event-details/get-event-details.mjs new file mode 100644 index 0000000000000..d2374d5618423 --- /dev/null +++ b/components/ticketsauce/actions/get-event-details/get-event-details.mjs @@ -0,0 +1,68 @@ +import ticketsauce from "../../ticketsauce.app.mjs"; + +export default { + key: "ticketsauce-get-event-details", + name: "Get Event Details", + description: "Get details for a specified event. [See documentation](https://speca.io/ticketsauce/ticketsauce-public-api?key=204000d6bda66da78315e721920f43aa#event-details)", + version: "0.0.1", + type: "action", + annotations: { + destructiveHint: false, + openWorldHint: true, + readOnlyHint: true, + }, + props: { + ticketsauce, + partnerId: { + propDefinition: [ + ticketsauce, + "partnerId", + ], + }, + organizationId: { + propDefinition: [ + ticketsauce, + "organizationId", + ], + }, + eventId: { + propDefinition: [ + ticketsauce, + "eventId", + (c) => ({ + partnerId: c.partnerId, + organizationId: c.organizationId, + }), + ], + }, + photos: { + type: "boolean", + label: "Photos", + description: "Whether or not to return the event's photo gallery records.", + optional: true, + default: false, + }, + includePerformers: { + propDefinition: [ + ticketsauce, + "includePerformers", + ], + }, + }, + async run({ $ }) { + const params = { + photos: this.photos ? + 1 : + 0, + include_performers: String(this.includePerformers), + }; + + const response = await this.ticketsauce.getEventDetails($, { + eventId: this.eventId, + params, + }); + + $.export("$summary", `Successfully retrieved details for event ID: ${this.eventId}`); + return response; + }, +}; diff --git a/components/ticketsauce/actions/get-events/get-events.mjs b/components/ticketsauce/actions/get-events/get-events.mjs new file mode 100644 index 0000000000000..2620f2e6d976c --- /dev/null +++ b/components/ticketsauce/actions/get-events/get-events.mjs @@ -0,0 +1,127 @@ +import ticketsauce from "../../ticketsauce.app.mjs"; + +export default { + key: "ticketsauce-get-events", + name: "Get Events", + description: "Get a list of all events owned by the authenticated account. [See documentation](https://speca.io/ticketsauce/ticketsauce-public-api?key=204000d6bda66da78315e721920f43aa#list-of-events)", + version: "0.0.1", + type: "action", + annotations: { + destructiveHint: false, + openWorldHint: true, + readOnlyHint: true, + }, + props: { + ticketsauce, + partnerId: { + propDefinition: [ + ticketsauce, + "partnerId", + ], + }, + organizationId: { + propDefinition: [ + ticketsauce, + "organizationId", + ], + }, + startAfter: { + type: "string", + label: "Start After", + description: "Only retrieve events that start AFTER the specified UTC date (format: `YYYY-MM-DD`).", + optional: true, + }, + endBefore: { + type: "string", + label: "End Before", + description: "Only retrieve events that end BEFORE the specified UTC date (format: `YYYY-MM-DD`).", + optional: true, + }, + activeOnly: { + type: "boolean", + label: "Active Only", + description: "Leaving this as true will restrict retrieved events to only 'active' events. Setting to false will allow the retrieval of both active and inactive events.", + optional: true, + default: true, + }, + privacyType: { + type: "string", + label: "Privacy Type", + description: "Filter events by privacy type.", + optional: true, + default: "public", + options: [ + { + label: "Public events only", + value: "public", + }, + { + label: "All events (no restriction)", + value: "all", + }, + { + label: "Unlisted events only", + value: "unlisted", + }, + ], + }, + sortBy: { + type: "string", + label: "Sort By", + description: "Field to sort events by.", + optional: true, + options: [ + { + label: "Event start date", + value: "date", + }, + { + label: "Event name", + value: "name", + }, + { + label: "City location", + value: "city", + }, + ], + }, + sortDir: { + type: "string", + label: "Sort Direction", + description: "Direction to sort results.", + optional: true, + options: [ + { + label: "Ascending", + value: "asc", + }, + { + label: "Descending", + value: "desc", + }, + ], + }, + includePerformers: { + propDefinition: [ + ticketsauce, + "includePerformers", + ], + }, + }, + async run({ $ }) { + const params = { + partner_id: this.partnerId, + organization_id: this.organizationId, + start_after: this.startAfter, + end_before: this.endBefore, + active_only: String(this.activeOnly), + privacy_type: this.privacyType, + sort_by: this.sortBy, + sort_dir: this.sortDir, + include_performers: String(this.includePerformers), + }; + return this.ticketsauce.listEvents($, { + params, + }); + }, +}; diff --git a/components/ticketsauce/actions/get-order-details/get-order-details.mjs b/components/ticketsauce/actions/get-order-details/get-order-details.mjs new file mode 100644 index 0000000000000..49bfea8a86dc7 --- /dev/null +++ b/components/ticketsauce/actions/get-order-details/get-order-details.mjs @@ -0,0 +1,56 @@ +import ticketsauce from "../../ticketsauce.app.mjs"; + +export default { + key: "ticketsauce-get-order-details", + name: "Get Order Details", + description: "Get details for the specified order. [See documentation](https://speca.io/ticketsauce/ticketsauce-public-api?key=204000d6bda66da78315e721920f43aa#order-details)", + version: "0.0.1", + type: "action", + annotations: { + destructiveHint: false, + openWorldHint: true, + readOnlyHint: true, + }, + props: { + ticketsauce, + partnerId: { + propDefinition: [ + ticketsauce, + "partnerId", + ], + }, + organizationId: { + propDefinition: [ + ticketsauce, + "organizationId", + ], + }, + eventId: { + propDefinition: [ + ticketsauce, + "eventId", + (c) => ({ + partnerId: c.partnerId, + organizationId: c.organizationId, + }), + ], + }, + orderId: { + propDefinition: [ + ticketsauce, + "orderId", + (c) => ({ + eventId: c.eventId, + }), + ], + }, + }, + async run({ $ }) { + const response = await this.ticketsauce.getOrderDetails($, { + orderId: this.orderId, + }); + + $.export("$summary", `Successfully retrieved details for order ID: ${this.orderId}`); + return response; + }, +}; diff --git a/components/ticketsauce/actions/get-orders/get-orders.mjs b/components/ticketsauce/actions/get-orders/get-orders.mjs new file mode 100644 index 0000000000000..0fad6a80d85df --- /dev/null +++ b/components/ticketsauce/actions/get-orders/get-orders.mjs @@ -0,0 +1,173 @@ +import ticketsauce from "../../ticketsauce.app.mjs"; + +export default { + key: "ticketsauce-get-orders", + name: "Get Orders", + description: "Get a list of orders from the specified event. [See documentation](https://speca.io/ticketsauce/ticketsauce-public-api?key=204000d6bda66da78315e721920f43aa#orders)", + version: "0.0.1", + type: "action", + annotations: { + destructiveHint: false, + openWorldHint: true, + readOnlyHint: true, + }, + props: { + ticketsauce, + partnerId: { + propDefinition: [ + ticketsauce, + "partnerId", + ], + }, + organizationId: { + propDefinition: [ + ticketsauce, + "organizationId", + ], + }, + eventId: { + propDefinition: [ + ticketsauce, + "eventId", + (c) => ({ + partnerId: c.partnerId, + organizationId: c.organizationId, + }), + ], + }, + perPage: { + type: "string", + label: "Per Page", + description: "How many results to retrieve (per page). Max 500.", + optional: true, + default: "100", + }, + page: { + type: "string", + label: "Page", + description: "Which page to return. For example, if per_page is 20, and page is 3, the results would show 41-60.", + optional: true, + default: "1", + }, + q: { + type: "string", + label: "Search Query", + description: "Exact email address or last name attached to an order.", + optional: true, + }, + returnQuestionnaires: { + type: "boolean", + label: "Return Questionnaires", + description: "Whether or not to return the question responses from questionnaires (will include attendee responses as well IF tickets are returned)", + optional: true, + default: false, + }, + returnTickets: { + type: "boolean", + label: "Return Tickets", + description: "Whether or not to return the tickets for each order as well.", + optional: true, + default: false, + }, + returnLineItemFees: { + type: "boolean", + label: "Return Line Item Fees", + description: "Whether or not to return the itemized line item fees for each order (if they exist).", + optional: true, + default: false, + }, + orderedAfter: { + type: "string", + label: "Ordered After", + description: "Only retrieve orders that were ordered AFTER the specified date/time (format`: YYYY-MM-DD` or `YYYY-MM-DD HH:MM:SS`).", + optional: true, + }, + orderedBefore: { + type: "string", + label: "Ordered Before", + description: "Only retrieve orders that were ordered BEFORE the specified date/time (format`: YYYY-MM-DD` or `YYYY-MM-DD HH:MM:SS`).", + optional: true, + }, + modifiedAfter: { + type: "string", + label: "Modified After", + description: "Only retrieve orders that were modified AFTER the specified date/time (format`: YYYY-MM-DD` or `YYYY-MM-DD HH:MM:SS`).", + optional: true, + }, + modifiedBefore: { + type: "string", + label: "Modified Before", + description: "Only retrieve orders that were modified BEFORE the specified date/time (format`: YYYY-MM-DD` or `YYYY-MM-DD HH:MM:SS`).", + optional: true, + }, + sortBy: { + type: "string", + label: "Sort By", + description: "Field to sort orders by.", + optional: true, + default: "date", + options: [ + { + label: "Ordered date", + value: "date", + }, + { + label: "Last name", + value: "name", + }, + ], + }, + sortDir: { + type: "string", + label: "Sort Direction", + description: "Direction to sort results.", + optional: true, + default: "asc", + options: [ + { + label: "Ascending", + value: "asc", + }, + { + label: "Descending", + value: "desc", + }, + ], + }, + totalAbove: { + type: "string", + label: "Total Above", + description: "Return only orders whose order total is greater than this value.", + optional: true, + }, + totalBelow: { + type: "string", + label: "Total Below", + description: "Return only orders whose order total is less than this value.", + optional: true, + }, + }, + async run({ $ }) { + const params = { + per_page: this.perPage, + page: this.page, + q: this.q, + return_questionnaires: String(this.returnQuestionnaires), + return_tickets: String(this.returnTickets), + return_line_item_fees: String(this.returnLineItemFees), + ordered_after: this.orderedAfter, + ordered_before: this.orderedBefore, + modified_after: this.modifiedAfter, + modified_before: this.modifiedBefore, + sort_by: this.sortBy, + sort_dir: this.sortDir, + total_above: this.totalAbove, + total_below: this.totalBelow, + }; + + return this.ticketsauce.listOrders($, { + eventId: this.eventId, + params, + }); + }, +}; diff --git a/components/ticketsauce/actions/get-ticket-checkin-ids/get-ticket-checkin-ids.mjs b/components/ticketsauce/actions/get-ticket-checkin-ids/get-ticket-checkin-ids.mjs new file mode 100644 index 0000000000000..10c915fc050ee --- /dev/null +++ b/components/ticketsauce/actions/get-ticket-checkin-ids/get-ticket-checkin-ids.mjs @@ -0,0 +1,66 @@ +import ticketsauce from "../../ticketsauce.app.mjs"; + +export default { + key: "ticketsauce-get-ticket-checkin-ids", + name: "Get Ticket Check-in IDs", + description: "Get a list of ticket check-in IDs from the specified event. [See documentation](https://speca.io/ticketsauce/ticketsauce-public-api?key=204000d6bda66da78315e721920f43aa#ticket-checkin-ids)", + version: "0.0.1", + type: "action", + annotations: { + destructiveHint: false, + openWorldHint: true, + readOnlyHint: true, + }, + props: { + ticketsauce, + partnerId: { + propDefinition: [ + ticketsauce, + "partnerId", + ], + }, + organizationId: { + propDefinition: [ + ticketsauce, + "organizationId", + ], + }, + eventId: { + propDefinition: [ + ticketsauce, + "eventId", + (c) => ({ + partnerId: c.partnerId, + organizationId: c.organizationId, + }), + ], + }, + perPage: { + type: "string", + label: "Per Page", + description: "How many results to retrieve (per page). Max 5000.", + optional: true, + }, + page: { + type: "string", + label: "Page", + description: "Which page to return. For example, if per_page is 20, and page is 3, the results would show 41-60.", + optional: true, + default: "1", + }, + }, + async run({ $ }) { + const params = { + per_page: this.perPage, + page: this.page, + }; + + const response = await this.ticketsauce.getTicketCheckinIds($, { + eventId: this.eventId, + params, + }); + + $.export("$summary", `Successfully retrieved ticket check-in IDs for event ID: ${this.eventId}`); + return response; + }, +}; diff --git a/components/ticketsauce/package.json b/components/ticketsauce/package.json index 9d812ec5b5894..78cbed9a12351 100644 --- a/components/ticketsauce/package.json +++ b/components/ticketsauce/package.json @@ -1,6 +1,6 @@ { "name": "@pipedream/ticketsauce", - "version": "0.0.1", + "version": "0.1.0", "description": "Pipedream TicketSauce Components", "main": "ticketsauce.app.mjs", "keywords": [ @@ -11,5 +11,8 @@ "author": "Pipedream (https://pipedream.com/)", "publishConfig": { "access": "public" + }, + "dependencies": { + "@pipedream/platform": "^3.1.0" } -} \ No newline at end of file +} diff --git a/components/ticketsauce/sources/new-event/new-event.mjs b/components/ticketsauce/sources/new-event/new-event.mjs new file mode 100644 index 0000000000000..e1d6b5b4d5a50 --- /dev/null +++ b/components/ticketsauce/sources/new-event/new-event.mjs @@ -0,0 +1,110 @@ +import ticketsauce from "../../ticketsauce.app.mjs"; +import sampleEmit from "./test-event.mjs"; + +export default { + key: "ticketsauce-new-event", + name: "New Event", + description: "Emit new event when an event is created in Ticketsauce. [See the documentation](https://speca.io/ticketsauce/ticketsauce-public-api?key=204000d6bda66da78315e721920f43aa#list-of-events)", + version: "0.0.1", + type: "source", + dedupe: "unique", + props: { + ticketsauce, + db: "$.service.db", + alert: { + type: "alert", + alertType: "info", + content: "The TicketSauce API caches responses to the **List of Events** endpoint for 1 hour. This affects how new events are polled. To avoid unnecessary API calls, set the polling interval accordingly. [See the documentation](https://speca.io/ticketsauce/ticketsauce-public-api?key=204000d6bda66da78315e721920f43aa#list-of-events)", + }, + timer: { + type: "$.interface.timer", + default: { + intervalSeconds: 60 * 60, + }, + }, + partnerId: { + propDefinition: [ + ticketsauce, + "partnerId", + ], + description: "Filter events by a specific partner ID (optional)", + }, + organizationId: { + propDefinition: [ + ticketsauce, + "organizationId", + ], + description: "Filter events by a specific organization ID (optional)", + }, + }, + methods: { + _getLastCreated() { + return this.db.get("lastCreated") || "1970-01-01 00:00:00"; + }, + _setLastCreated(lastCreated) { + this.db.set("lastCreated", lastCreated); + }, + generateMeta(event) { + return { + id: event.Event.id, + summary: `New Event: ${event.Event.name}`, + ts: Date.parse(event.Event.created), + }; + }, + async startEvent(maxResults = 0) { + const lastCreated = this._getLastCreated(); + + const events = await this.ticketsauce.listEvents(this, { + partnerId: this.partnerId, + organizationId: this.organizationId, + params: { + sort_by: "date", + sort_dir: "desc", + active_only: false, + }, + }); + + if (!events?.length) { + return; + } + + // Filter events created after lastCreated and sort by creation date + const newEvents = events.filter((event) => + Date.parse(event.Event.created) > Date.parse(lastCreated)); + + // Sort by created date ascending (oldest first) for emission order + newEvents.sort((a, b) => + Date.parse(a.Event.created) - Date.parse(b.Event.created)); + + // Limit results if maxResults is specified + const eventsToEmit = maxResults && maxResults > 0 + ? newEvents.slice(0, maxResults) + : newEvents; + + // Update last created date if we have new events + if (newEvents.length > 0) { + // Find the most recent created date + const mostRecentEvent = events.reduce((latest, current) => + Date.parse(current.Event.created) > Date.parse(latest.Event.created) + ? current + : latest); + this._setLastCreated(mostRecentEvent.Event.created); + } + + // Emit events + for (const event of eventsToEmit) { + this.$emit(event, this.generateMeta(event)); + } + }, + }, + hooks: { + async deploy() { + await this.startEvent(25); + }, + }, + async run() { + await this.startEvent(); + }, + sampleEmit, +}; + diff --git a/components/ticketsauce/sources/new-event/test-event.mjs b/components/ticketsauce/sources/new-event/test-event.mjs new file mode 100644 index 0000000000000..db2381dc33b2c --- /dev/null +++ b/components/ticketsauce/sources/new-event/test-event.mjs @@ -0,0 +1,47 @@ +export default { + "Event": { + "id": "5471eea9-0bf8-4d1e-ab14-313e0ad0a778", + "name": "Example Event", + "active": true, + "address": "1234 Happy St", + "address2": "Apt B.", + "city": "San Diego", + "state": "CA", + "postal_code": "12345", + "country": "United States", + "location": "The Joyful Theatre", + "latitude": "33.394299", + "longitude": "-111.598045", + "map_zoom": "13", + "online_only": false, + "start": "2024-11-28 18:00:00", + "start_utc": "2024-11-29 02:00:00", + "end": "2024-11-28 20:00:00", + "end_utc": "2024-11-29 04:00:00", + "show_start": true, + "show_end": true, + "timezone": "America/Los_Angeles", + "created": "2024-01-01 16:30:32", + "modified": "2024-01-01 18:45:12", + "locale": "eng", + "privacy_type": "0", + "region": null, + "slug": "example-event", + "tickets_active": true, + "website": "https://www.example-event.com", + "organization_id": "565xxxxx-xxxx-xxxx-xxxx-xxxxxxxx128", + "event_topic_id": "445xxxxx-xxxx-xxxx-xxxx-xxxxxxxx554", + "event_topic": "Outdoors, Camping & Hiking", + "event_type_id": "987xxxxx-xxxx-xxxx-xxxx-xxxxxxxx789", + "event_type": "Trade Show", + "event_url": "https://www.example-event.com/e/an-event", + "tickets_url": "https://www.example-event.com/e/an-event/tickets", + }, + "Logo": { + "url": "https://cd2cafd.ssl.cf5.rackcdn.com/6fc4165cb768be302d2ec387a058f81e_sm.png" + }, + "Masthead": { + "url": null, + "created":null + }, +}; diff --git a/components/ticketsauce/ticketsauce.app.mjs b/components/ticketsauce/ticketsauce.app.mjs index f665cd726ff5b..27aeda811e6d4 100644 --- a/components/ticketsauce/ticketsauce.app.mjs +++ b/components/ticketsauce/ticketsauce.app.mjs @@ -1,11 +1,160 @@ +import { axios } from "@pipedream/platform"; + export default { type: "app", app: "ticketsauce", - propDefinitions: {}, + propDefinitions: { + partnerId: { + type: "string", + label: "Partner ID", + description: "Including this ID will limit the result set to the specific partner.", + optional: true, + }, + organizationId: { + type: "string", + label: "Organization ID", + description: "Including this ID will limit the result set to the specific organization.", + optional: true, + }, + includePerformers: { + type: "boolean", + label: "Include Performers", + description: "If true, returns any associated performers/artists with the event.", + optional: true, + default: false, + }, + eventId: { + type: "string", + label: "Event", + description: "Select an event", + async options({ + partnerId, organizationId, + }) { + const events = await this.listEvents(this, { + partnerId, + organizationId, + }); + + if (!events?.length) { + return []; + } + + const options = events.map((eventData) => ({ + label: `${eventData.Event.name} - ${eventData.Event.city} (${eventData.Event.start})`, + value: eventData.Event.id, + })); + + return options; + }, + }, + orderId: { + type: "string", + label: "Order", + description: "Select an order", + async options({ + eventId, prevContext, + }) { + if (!eventId) { + return []; + } + + const orders = await this.listOrders(this, { + eventId, + params: { + per_page: 100, + page: prevContext?.page || 0, + }, + }); + + if (!orders?.length) { + return prevContext?.page > 0 + ? { + options: [], + context: {}, + } + : []; + } + + const options = orders.map((orderData) => ({ + label: `${orderData.Order.first_name} ${orderData.Order.last_name} - ${orderData.Order.email} (${orderData.Order.total_paid})`, + value: orderData.Order.id, + })); + + return { + options, + context: { + page: (prevContext?.page || 0) + 1, + }, + }; + }, + }, + }, methods: { - // this.$auth contains connected account data - authKeys() { - console.log(Object.keys(this.$auth)); + _makeRequest({ + $ = this, path, params = {}, ...opts + }) { + return axios($, { + url: `https://api.ticketsauce.com/v2${path}`, + params: { + access_token: this.$auth.oauth_access_token, + ...params, + }, + ...opts, + }); + }, + async listEvents($, { + partnerId, organizationId, params, + } = {}) { + const requestParams = { + ...params, + }; + + if (partnerId) { + requestParams.partner_id = partnerId; + } + + if (organizationId) { + requestParams.organization_id = organizationId; + } + + return this._makeRequest({ + $, + path: "/events", + params: requestParams, + }); + }, + async getEventDetails($, { + eventId, params, + } = {}) { + return this._makeRequest({ + $, + path: `/event/${eventId}`, + params, + }); + }, + async listOrders($, { + eventId, params, + } = {}) { + return this._makeRequest({ + $, + path: `/orders/${eventId}`, + params, + }); + }, + async getOrderDetails($, { orderId }) { + return this._makeRequest({ + $, + path: `/order/${orderId}`, + }); + }, + async getTicketCheckinIds($, { + eventId, params, + } = {}) { + return this._makeRequest({ + $, + path: `/tickets/checkin_ids/${eventId}`, + params, + }); }, }, }; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 16b001fd989b6..6f38d663bc347 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -14671,7 +14671,11 @@ importers: specifier: ^1.2.0 version: 1.6.6 - components/ticketsauce: {} + components/ticketsauce: + dependencies: + '@pipedream/platform': + specifier: ^3.1.0 + version: 3.1.0 components/ticktick: dependencies: