diff --git a/components/easypromos/easypromos.app.mjs b/components/easypromos/easypromos.app.mjs index 2d7736c9c3eb6..9b199adf5ad4f 100644 --- a/components/easypromos/easypromos.app.mjs +++ b/components/easypromos/easypromos.app.mjs @@ -1,11 +1,139 @@ +import { axios } from "@pipedream/platform"; + export default { type: "app", app: "easypromos", - propDefinitions: {}, + propDefinitions: { + userId: { + type: "integer", + label: "User ID", + description: "The ID of the user", + async options({ + promotionId, prevContext, + }) { + const { + items, paging, + } = await this.getUsers({ + promotionId, + params: { + next_cursor: prevContext.nextCursor, + }, + }); + return { + options: items.map(({ + id: value, email: label, + }) => ({ + label, + value, + })), + context: { + nextCursor: paging.next_cursor, + }, + }; + }, + }, + promotionId: { + type: "integer", + label: "Promotion ID", + description: "The ID of the promotion", + async options({ prevContext }) { + const { + items, paging, + } = await this.getPromotions({ + params: { + next_cursor: prevContext.nextCursor, + }, + }); + return { + options: items.map(({ + id, title, internal_ref: ref, + }) => ({ + label: ref || title, + value: parseInt(id), + })), + context: { + nextCursor: paging.next_cursor, + }, + }; + }, + }, + }, methods: { - // this.$auth contains connected account data - authKeys() { - console.log(Object.keys(this.$auth)); + _baseUrl() { + return "https://api.easypromosapp.com/v2"; + }, + _headers() { + return { + Authorization: `Bearer ${this.$auth.api_key}`, + }; + }, + _makeRequest({ + $ = this, path, ...opts + }) { + return axios($, { + url: this._baseUrl() + path, + headers: this._headers(), + ...opts, + }); + }, + getCoinTransactions({ + promotionId, ...opts + }) { + return this._makeRequest({ + path: `/coin_transactions/${promotionId}`, + ...opts, + }); + }, + getUsers({ + promotionId, ...opts + }) { + return this._makeRequest({ + path: `/users/${promotionId}`, + ...opts, + }); + }, + getParticipations({ + promotionId, ...opts + }) { + return this._makeRequest({ + path: `/participations/${promotionId}`, + ...opts, + }); + }, + getPromotions(opts = {}) { + return this._makeRequest({ + path: "/promotions", + ...opts, + }); + }, + async *paginate({ + fn, params = {}, maxResults = null, ...opts + }) { + let hasMore = false; + let count = 0; + let nextCursor = null; + + do { + params.next_cursor = nextCursor; + const { + items, + paging: { next_cursor }, + } = await fn({ + params, + ...opts, + }); + for (const d of items) { + yield d; + + if (maxResults && ++count === maxResults) { + return count; + } + } + + nextCursor = next_cursor; + hasMore = nextCursor; + + } while (hasMore); }, }, }; diff --git a/components/easypromos/package.json b/components/easypromos/package.json index 34a1b87bc7549..ff4fa8d3e4e16 100644 --- a/components/easypromos/package.json +++ b/components/easypromos/package.json @@ -1,6 +1,6 @@ { "name": "@pipedream/easypromos", - "version": "0.0.1", + "version": "0.1.0", "description": "Pipedream Easypromos Components", "main": "easypromos.app.mjs", "keywords": [ @@ -11,5 +11,8 @@ "author": "Pipedream (https://pipedream.com/)", "publishConfig": { "access": "public" + }, + "dependencies": { + "@pipedream/platform": "^3.0.3" } -} \ No newline at end of file +} diff --git a/components/easypromos/sources/common/base.mjs b/components/easypromos/sources/common/base.mjs new file mode 100644 index 0000000000000..3123e3876ee1b --- /dev/null +++ b/components/easypromos/sources/common/base.mjs @@ -0,0 +1,87 @@ +import { + ConfigurationError, DEFAULT_POLLING_SOURCE_TIMER_INTERVAL, +} from "@pipedream/platform"; +import easypromos from "../../easypromos.app.mjs"; + +export default { + props: { + easypromos, + db: "$.service.db", + timer: { + type: "$.interface.timer", + default: { + intervalSeconds: DEFAULT_POLLING_SOURCE_TIMER_INTERVAL, + }, + }, + info: { + type: "alert", + alertType: "info", + content: "The Easypromos API only works with \"White Label\" promotions, any other type will not appear in the list.", + }, + promotionId: { + propDefinition: [ + easypromos, + "promotionId", + ], + }, + }, + methods: { + _getLastId() { + return this.db.get("lastId") || 0; + }, + _setLastId(lastId) { + this.db.set("lastId", lastId); + }, + getOpts() { + return {}; + }, + async emitEvent(maxResults = false) { + const lastId = this._getLastId(); + let responseArray = []; + + try { + const response = this.easypromos.paginate({ + fn: this.getFunction(), + ...this.getOpts(), + params: { + order: "created_desc", + }, + }); + + for await (const item of response) { + if (item.id <= lastId) break; + responseArray.push(item); + } + } catch (err) { + console.log(err); + if (err?.response?.data?.code === 0) { + throw new ConfigurationError("You can only use this trigger with promotions that have the 'Virtual Coins' feature enabled."); + } + throw new ConfigurationError(err); + } + + if (responseArray.length) { + if (maxResults && (responseArray.length > maxResults)) { + responseArray.length = maxResults; + } + this._setLastId(responseArray[0].id); + } + + for (const item of responseArray.reverse()) { + this.$emit(item, { + id: item.id || item.transaction.id, + summary: this.getSummary(item), + ts: Date.parse(item.created || new Date()), + }); + } + }, + }, + hooks: { + async deploy() { + await this.emitEvent(25); + }, + }, + async run() { + await this.emitEvent(); + }, +}; diff --git a/components/easypromos/sources/new-coin-transaction/new-coin-transaction.mjs b/components/easypromos/sources/new-coin-transaction/new-coin-transaction.mjs new file mode 100644 index 0000000000000..2f0f305dccb2b --- /dev/null +++ b/components/easypromos/sources/new-coin-transaction/new-coin-transaction.mjs @@ -0,0 +1,37 @@ +import common from "../common/base.mjs"; +import sampleEmit from "./test-event.mjs"; + +export default { + ...common, + key: "easypromos-new-coin-transaction", + name: "New Coin Transaction", + description: "Emit new event when a user earns or spends coins.", + version: "0.0.1", + type: "source", + dedupe: "unique", + props: { + ...common.props, + info2: { + type: "alert", + alertType: "warning", + content: "You can only use this trigger with promotions that have the 'Virtual Coins' feature enabled.", + }, + }, + methods: { + ...common.methods, + getFunction() { + return this.easypromos.getCoinTransactions; + }, + getOpts() { + return { + promotionId: this.promotionId, + }; + }, + getSummary({ + transaction, user, + }) { + return `Coin transaction: ${transaction.amount} for user ${user.email}`; + }, + }, + sampleEmit, +}; diff --git a/components/easypromos/sources/new-coin-transaction/test-event.mjs b/components/easypromos/sources/new-coin-transaction/test-event.mjs new file mode 100644 index 0000000000000..ef6dc9f2de2ec --- /dev/null +++ b/components/easypromos/sources/new-coin-transaction/test-event.mjs @@ -0,0 +1,54 @@ +export default { + "transaction": { + "id": 1, + "user_id": 1, + "promotion_id": 1, + "coin_id": 1, + "coin_name": "Points", + "amount": 5, + "balance": 5, + "created": "2019-08-24T14:15:22Z", + "transaction_type": 1, + "reason": "Earned for participating in a stage", + "extra": "string" + }, + "user": { + "id": 1, + "promotion_id": 1, + "first_name": "John", + "last_name": "Smith", + "nickname": "jsmith", + "login_type": "email", + "social_id": "string", + "external_id": "string", + "status": 0, + "email": "user@example.com", + "phone": "string", + "birthday": "2019-08-24", + "created": "2019-08-24T14:15:22Z", + "avatar_img": "http://example.com", + "language": "ara", + "country": "FR", + "custom_properties": [ + { + "id": 1, + "title": "Postal code", + "ref": "postalcode", + "value": "PC98776" + } + ], + "meta_data": { + "utm_source": "instagram", + "utm_medium": "ads", + "utm_campaign": "campaign-week1", + "referral_url": "http://example.com", + "ip": "192.168.0.1", + "user_agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 15_3_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148", + "legals": { + "terms_url": "https://a.cstmapp.com/promo_terms/919755", + "privacy_url": "https://a.cstmapp.com/policy/987543", + "accepted_cookies": 1 + } + } + } +} \ No newline at end of file diff --git a/components/easypromos/sources/new-participation/new-participation.mjs b/components/easypromos/sources/new-participation/new-participation.mjs new file mode 100644 index 0000000000000..6333b45edf447 --- /dev/null +++ b/components/easypromos/sources/new-participation/new-participation.mjs @@ -0,0 +1,27 @@ +import common from "../common/base.mjs"; +import sampleEmit from "./test-event.mjs"; + +export default { + ...common, + key: "easypromos-new-participation", + name: "New Participation Submitted", + description: "Emit new event when a registered user submits a participation in the promotion.", + version: "0.0.1", + type: "source", + dedupe: "unique", + methods: { + ...common.methods, + getFunction() { + return this.easypromos.getParticipations; + }, + getOpts() { + return { + promotionId: this.promotionId, + }; + }, + getSummary(participation) { + return `New Participation: ${participation.id}`; + }, + }, + sampleEmit, +}; diff --git a/components/easypromos/sources/new-participation/test-event.mjs b/components/easypromos/sources/new-participation/test-event.mjs new file mode 100644 index 0000000000000..9a483b1afc87c --- /dev/null +++ b/components/easypromos/sources/new-participation/test-event.mjs @@ -0,0 +1,19 @@ +export default { + "id": 1, + "promotion_id": 1, + "stage_id": 1, + "user_id": 1, + "created": "2019-08-24T14:15:22Z", + "ip": "192.168.0.1", + "user_agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 15_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) GSA/201.0.429950705 Mobile/15E148 Safari/604.1", + "points": 786.43, + "data": [ + { + "ref": "Question1", + "title": "Pick your favorite city", + "values": [ + "Barcelona" + ] + } + ] +} \ No newline at end of file diff --git a/components/easypromos/sources/new-user/new-user.mjs b/components/easypromos/sources/new-user/new-user.mjs new file mode 100644 index 0000000000000..ed50831382516 --- /dev/null +++ b/components/easypromos/sources/new-user/new-user.mjs @@ -0,0 +1,27 @@ +import common from "../common/base.mjs"; +import sampleEmit from "./test-event.mjs"; + +export default { + ...common, + key: "easypromos-new-user", + name: "New User Registration", + description: "Emit new event when a user registers in the promotion.", + version: "0.0.1", + type: "source", + dedupe: "unique", + methods: { + ...common.methods, + getFunction() { + return this.easypromos.getUsers; + }, + getOpts() { + return { + promotionId: this.promotionId, + }; + }, + getSummary(user) { + return `New User Registration: ${user.email}`; + }, + }, + sampleEmit, +}; diff --git a/components/easypromos/sources/new-user/test-event.mjs b/components/easypromos/sources/new-user/test-event.mjs new file mode 100644 index 0000000000000..956839b52c54c --- /dev/null +++ b/components/easypromos/sources/new-user/test-event.mjs @@ -0,0 +1,39 @@ +export default { + "id": 1, + "promotion_id": 1, + "first_name": "John", + "last_name": "Smith", + "nickname": "jsmith", + "login_type": "email", + "social_id": "string", + "external_id": "string", + "status": 0, + "email": "user@example.com", + "phone": "string", + "birthday": "2019-08-24", + "created": "2019-08-24T14:15:22Z", + "avatar_img": "http://example.com", + "language": "ara", + "country": "FR", + "custom_properties": [ + { + "id": 1, + "title": "Postal code", + "ref": "postalcode", + "value": "PC98776" + } + ], + "meta_data": { + "utm_source": "instagram", + "utm_medium": "ads", + "utm_campaign": "campaign-week1", + "referral_url": "http://example.com", + "ip": "192.168.0.1", + "user_agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 15_3_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148", + "legals": { + "terms_url": "https://a.cstmapp.com/promo_terms/919755", + "privacy_url": "https://a.cstmapp.com/policy/987543", + "accepted_cookies": 1 + } + } +} \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4c3319d9e5ff8..85f8bd08550ad 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -3126,7 +3126,11 @@ importers: components/easypost: {} - components/easypromos: {} + components/easypromos: + dependencies: + '@pipedream/platform': + specifier: ^3.0.3 + version: 3.0.3 components/easysendy: dependencies: