Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Components] engage #13410 #15656

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions components/engage/.gitignore

This file was deleted.

39 changes: 39 additions & 0 deletions components/engage/actions/add-customer/add-customer.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import app from "../../engage.app.mjs";

export default {
key: "engage-add-customer",
name: "Add Customer",
description: "Adds Customer to Accounts. [See the documentation](https://docs.engage.so/en-us/a/62bbdd015bfea4dca4834042-users#add-customer-to-accounts)",
version: "0.0.1",
type: "action",
props: {
app,
uid: {
propDefinition: [
app,
"uid",
],
},
customerId: {
propDefinition: [
app,
"customerId",
],
},
},
async run({ $ }) {
const response = await this.app.addCustomer({
$,
uid: this.uid,
data: {
accounts: [
{
id: this.customerId,
},
],
},
});
$.export("$summary", "add-customer executed successfully");
return response;
},
Comment on lines +24 to +38
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add validation for customer ID and improve error handling.

The run method should validate inputs and handle potential errors from the API call.

 async run({ $ }) {
+  if (!this.uid || !this.customerId) {
+    throw new Error("User ID and Customer ID are required");
+  }
+
+  try {
     const response = await this.app.addCustomer({
       $,
       uid: this.uid,
       data: {
         accounts: [
           {
             id: this.customerId,
           },
         ],
       },
     });
     $.export("$summary", "add-customer executed successfully");
     return response;
+  } catch (error) {
+    throw new Error(`Failed to add customer: ${error.message}`);
+  }
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
async run({ $ }) {
const response = await this.app.addCustomer({
$,
uid: this.uid,
data: {
accounts: [
{
id: this.customerId,
},
],
},
});
$.export("$summary", "add-customer executed successfully");
return response;
},
async run({ $ }) {
if (!this.uid || !this.customerId) {
throw new Error("User ID and Customer ID are required");
}
try {
const response = await this.app.addCustomer({
$,
uid: this.uid,
data: {
accounts: [
{
id: this.customerId,
},
],
},
});
$.export("$summary", "add-customer executed successfully");
return response;
} catch (error) {
throw new Error(`Failed to add customer: ${error.message}`);
}
},

};
49 changes: 49 additions & 0 deletions components/engage/actions/add-event/add-event.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import app from "../../engage.app.mjs";

export default {
key: "engage-add-event",
name: "Add Event",
description: "Adds user events to Engage. [See the documentation](https://docs.engage.so/en-us/a/62bbdd015bfea4dca4834042-users#track-user-event)",
version: "0.0.1",
type: "action",
props: {
app,
uid: {
propDefinition: [
app,
"uid",
],
},
event: {
propDefinition: [
app,
"event",
],
},
timestamp: {
propDefinition: [
app,
"timestamp",
],
},
properties: {
propDefinition: [
app,
"properties",
],
},
},
async run({ $ }) {
const response = await this.app.addEvent({
$,
uid: this.uid,
data: {
event: this.event,
timestamp: this.timestamp,
properties: this.properties,
},
});
$.export("$summary", `Successfully added event. Status: ${response.status}`);
return response;
},
};
63 changes: 63 additions & 0 deletions components/engage/actions/create-user/create-user.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import app from "../../engage.app.mjs";

export default {
key: "engage-create-user",
name: "Create User",
description: "Adds a new user to your Engage account. Use this to sync customer data with Engage. [See the documentation](https://docs.engage.so/en-us/a/62bbdd015bfea4dca4834042-users#create-a-user)",
version: "0.0.1",
type: "action",
props: {
app,
userId: {
propDefinition: [
app,
"userId",
],
},
firstName: {
propDefinition: [
app,
"firstName",
],
},
lastName: {
propDefinition: [
app,
"lastName",
],
},
isAccount: {
propDefinition: [
app,
"isAccount",
],
},
number: {
propDefinition: [
app,
"number",
],
},
email: {
propDefinition: [
app,
"email",
],
},
},
async run({ $ }) {
const response = await this.app.createUser({
$,
data: {
id: this.userId,
first_name: this.firstName,
last_name: this.lastName,
is_account: this.isAccount,
number: this.number,
email: this.email,
},
});
$.export("$summary", `Successfully created user with ID: ${response.id}`);
return response;
},
Comment on lines +48 to +62
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add input validation and error handling.

The run method should validate inputs and handle potential errors from the API call.

 async run({ $ }) {
+  // Validate required fields
+  if (!this.userId || !this.email) {
+    throw new Error("User ID and email are required fields");
+  }
+
+  try {
     const response = await this.app.createUser({
       $,
       data: {
         id: this.userId,
         first_name: this.firstName,
         last_name: this.lastName,
         is_account: this.isAccount,
         number: this.number,
         email: this.email,
       },
     });
     $.export("$summary", `Successfully created user with ID: ${response.id}`);
     return response;
+  } catch (error) {
+    throw new Error(`Failed to create user: ${error.message}`);
+  }
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
async run({ $ }) {
const response = await this.app.createUser({
$,
data: {
id: this.userId,
first_name: this.firstName,
last_name: this.lastName,
is_account: this.isAccount,
number: this.number,
email: this.email,
},
});
$.export("$summary", `Successfully created user with ID: ${response.id}`);
return response;
},
async run({ $ }) {
// Validate required fields
if (!this.userId || !this.email) {
throw new Error("User ID and email are required fields");
}
try {
const response = await this.app.createUser({
$,
data: {
id: this.userId,
first_name: this.firstName,
last_name: this.lastName,
is_account: this.isAccount,
number: this.number,
email: this.email,
},
});
$.export("$summary", `Successfully created user with ID: ${response.id}`);
return response;
} catch (error) {
throw new Error(`Failed to create user: ${error.message}`);
}
},

};
13 changes: 0 additions & 13 deletions components/engage/app/engage.app.ts

This file was deleted.

136 changes: 136 additions & 0 deletions components/engage/engage.app.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
import { axios } from "@pipedream/platform";

export default {
type: "app",
app: "engage",
propDefinitions: {
userId: {
type: "string",
label: "User ID",
description: "Unique identifier for the user",
},
firstName: {
type: "string",
label: "First name",
description: "The user's first name",
},
lastName: {
type: "string",
label: "Last name",
description: "The user's last name",
},
isAccount: {
type: "boolean",
label: "Is account",
description: "Indicates whether the user is also an account",
},
number: {
type: "string",
label: "Number",
description: "A contact number associated with the user",
},
email: {
type: "string",
label: "Email",
description: "The user's email address",
},
uid: {
type: "string",
label: "User ID",
description: "ID of the user",
async options() {
const response = await this.getUsers();
const usersIds = response.data;
return usersIds.map(({
uid, first_name, last_name,
}) => ({
label: `${first_name} ${last_name}`,
value: uid,
}));
},
},
customerId: {
type: "string",
label: "Customer ID",
description: "ID of the customer that will be added to the user",
async options() {
const response = await this.getUsers();
const usersIds = response.data;
return usersIds.map(({
uid, first_name, last_name,
}) => ({
label: `${first_name} ${last_name}`,
value: uid,
}));
},
},
event: {
type: "string",
label: "Event",
description: "The name of the event associated with the user",
},
timestamp: {
type: "string",
label: "Timestamp",
description: "Timestamp of the event. If none is provided, the current time is used",
},
properties: {
type: "object",
label: "Properties",
description: "The properties of the event",
},
Comment on lines +77 to +81
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Consider adding schema validation for properties object.

The properties field accepts any object structure. Consider adding schema validation to ensure the properties match expected format.


🌐 Web query:

What is the expected format for event properties in Engage.so?

💡 Result:

In Engage.so, event properties are structured as key-value pairs associated with user actions, allowing granular tracking and segmentation. Here's the breakdown based on available documentation:

Event Properties Format

  1. Event Structure
    Each event consists of:

    • Event Name: A descriptive label for the user action (e.g., button_clicked, order_placed).
    • Properties: Customizable key-value pairs providing context (e.g., plan_type: "premium", button_color: "blue").
  2. Data Types
    Events support dynamic property values, including:

    • Strings ("success")
    • Numbers (42)
    • Booleans (true/false)
    • Timestamps (automatically recorded for each event)[10].
  3. Usage Guidelines

    • Timestamps: Automatically attached to events for historical analysis[10].
    • Overwriting Behavior: Unlike attributes (which store only the latest value), events retain all historical instances[10].
    • Segmentation: Properties enable filtering users based on past actions (e.g., "users who clicked ‘Upgrade’ in the last 30 days")[10].

Example Implementation

// Tracking a plan upgrade event with properties
Engage.track('plan_upgraded', {
  plan_name: "Pro",
  previous_plan: "Basic",
  payment_method: "credit_card"
});

Key Differences from Attributes

Feature Events Attributes
Storage Historical records with timestamps[10] Latest value only[10]
Use Case Tracking actions over time Storing static user traits
Example plan_upgraded with details current_plan: "Pro"

For optimal results, use events when you need to analyze temporal patterns or count occurrences (e.g., logins per week), and attributes for fixed user states (e.g., subscription tier)[10].

Citations:


Action Required: Enhance Schema Validation for Event Properties

The current definition for the properties field only specifies it as an object without enforcing the key-value structure demanded by Engage.so. According to the documentation, event properties should be dynamic key-value pairs with values limited to strings, numbers, booleans, or timestamps. Please add schema validation (for example, using JSON Schema with appropriate patternProperties or additionalProperties constraints) to ensure that properties strictly adhere to this format.

  • Location: components/engage/engage.app.mjs (lines 77-81)
  • Action: Enhance the validation logic for the properties object by enforcing allowed types and structure.

},
methods: {
_baseUrl() {
return "https://api.engage.so/v1";
},
async _makeRequest(opts = {}) {
const {
$ = this,
path,
auth,
...otherOpts
} = opts;
return axios($, {
...otherOpts,
url: this._baseUrl() + path,
auth: {
...auth,
username: `${this.$auth.public_key}`,
password: `${this.$auth.secret_key}`,
},
});
},
Comment on lines +87 to +103
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Consider adding error handling and request validation.

The _makeRequest method should include:

  • Error handling for network failures
  • Request validation
  • Rate limiting considerations
 async _makeRequest(opts = {}) {
   const {
     $ = this,
     path,
     auth,
     ...otherOpts
   } = opts;
+  if (!path) {
+    throw new Error("Path is required");
+  }
+  try {
     return axios($, {
       ...otherOpts,
       url: this._baseUrl() + path,
       auth: {
         ...auth,
         username: `${this.$auth.public_key}`,
         password: `${this.$auth.secret_key}`,
       },
     });
+  } catch (error) {
+    const errorMessage = error.response?.data?.message || error.message;
+    throw new Error(`Request failed: ${errorMessage}`);
+  }
 }

Committable suggestion skipped: line range outside the PR's diff.

async createUser(args = {}) {
return this._makeRequest({
path: "/users",
method: "post",
...args,
});
},
async addCustomer({
uid, ...args
}) {
return this._makeRequest({
path: `/users/${uid}/accounts`,
method: "post",
...args,
});
},
async addEvent({
uid, ...args
}) {
return this._makeRequest({
path: `/users/${uid}/events`,
method: "post",
...args,
});
},
async getUsers(args = {}) {
return this._makeRequest({
path: "/users",
...args,
});
},
},
};
8 changes: 5 additions & 3 deletions components/engage/package.json
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
{
"name": "@pipedream/engage",
"version": "0.0.2",
"version": "0.1.0",
"description": "Pipedream Engage Components",
"main": "dist/app/engage.app.mjs",
"main": "engage.app.mjs",
"keywords": [
"pipedream",
"engage"
],
"files": ["dist"],
"homepage": "https://pipedream.com/apps/engage",
"author": "Pipedream <[email protected]> (https://pipedream.com/)",
"publishConfig": {
"access": "public"
},
"dependencies": {
"@pipedream/platform": "^3.0.3"
}
}
6 changes: 5 additions & 1 deletion pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading