Skip to content

Commit 62924cc

Browse files
committed
unduplicated
1 parent c2d5ffa commit 62924cc

File tree

3 files changed

+170
-142
lines changed

3 files changed

+170
-142
lines changed
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
import trustpilot from "../../trustpilot.app.mjs";
2+
3+
/**
4+
* Base polling source for Trustpilot integration
5+
*
6+
* Provides common functionality for polling Trustpilot API endpoints
7+
* and emitting new events with deduplication.
8+
*/
9+
export default {
10+
props: {
11+
trustpilot,
12+
db: "$.service.db",
13+
timer: {
14+
type: "$.interface.timer",
15+
default: {
16+
intervalSeconds: 15 * 60, // 15 minutes
17+
},
18+
},
19+
businessUnitId: {
20+
propDefinition: [
21+
trustpilot,
22+
"businessUnitId",
23+
],
24+
},
25+
},
26+
methods: {
27+
_getLastReviewTime() {
28+
return this.db.get("lastReviewTime");
29+
},
30+
_setLastReviewTime(time) {
31+
this.db.set("lastReviewTime", time);
32+
},
33+
/**
34+
* Override in child classes to provide review type-specific summary
35+
* @param {Object} _review - The review object
36+
* @returns {string} - Human-readable summary
37+
*/
38+
// eslint-disable-next-line no-unused-vars
39+
generateSummary(_review) {
40+
throw new Error("generateSummary must be implemented in child class");
41+
},
42+
/**
43+
* Override in child classes to fetch reviews using appropriate method
44+
* @param {Object} _$ - Pipedream step context
45+
* @param {Object} _params - Fetch parameters
46+
* @returns {Object} - API response with reviews array
47+
*/
48+
// eslint-disable-next-line no-unused-vars
49+
async fetchReviews(_$, _params) {
50+
throw new Error("fetchReviews must be implemented in child class");
51+
},
52+
/**
53+
* Override in child classes to provide fetch parameters
54+
* @param {string} _lastReviewTime - ISO timestamp of last review
55+
* @returns {Object} - Parameters for fetchReviews call
56+
*/
57+
// eslint-disable-next-line no-unused-vars
58+
getFetchParams(_lastReviewTime) {
59+
return {
60+
businessUnitId: this.businessUnitId,
61+
perPage: 100,
62+
};
63+
},
64+
/**
65+
* Override in child classes to filter reviews (for APIs without time filtering)
66+
* @param {Array} reviews - Array of reviews from API
67+
* @param {string} _lastReviewTime - ISO timestamp of last review
68+
* @returns {Array} - Filtered array of new reviews
69+
*/
70+
// eslint-disable-next-line no-unused-vars
71+
filterNewReviews(reviews, _lastReviewTime) {
72+
// Default: return all reviews (for APIs with server-side time filtering)
73+
return reviews;
74+
},
75+
},
76+
async run({ $ }) {
77+
try {
78+
// Get the last review time for filtering new reviews
79+
const lastReviewTime = this._getLastReviewTime();
80+
81+
// Get fetch parameters from child class
82+
const fetchParams = this.getFetchParams(lastReviewTime);
83+
84+
// Fetch reviews using child class method
85+
const result = await this.fetchReviews($, fetchParams);
86+
const reviews = result.reviews || [];
87+
88+
if (!reviews.length) {
89+
console.log("No reviews found");
90+
return;
91+
}
92+
93+
// Filter for new reviews (child class may override)
94+
const newReviews = this.filterNewReviews(reviews, lastReviewTime);
95+
96+
if (!newReviews.length) {
97+
console.log("No new reviews since last poll");
98+
return;
99+
}
100+
101+
// Track the latest review time
102+
let latestReviewTime = lastReviewTime;
103+
104+
for (const review of newReviews) {
105+
// Track the latest review time
106+
const reviewTime = new Date(review.createdAt).toISOString();
107+
if (!latestReviewTime || new Date(reviewTime) > new Date(latestReviewTime)) {
108+
latestReviewTime = reviewTime;
109+
}
110+
111+
// Emit the review with unique ID and summary
112+
this.$emit(review, {
113+
id: review.id,
114+
summary: this.generateSummary(review),
115+
ts: new Date(review.createdAt).getTime(),
116+
});
117+
}
118+
119+
// Update the last review time for next poll
120+
if (latestReviewTime && latestReviewTime !== lastReviewTime) {
121+
this._setLastReviewTime(latestReviewTime);
122+
}
123+
124+
} catch (error) {
125+
throw new Error(`Failed to fetch reviews: ${error.message}`);
126+
}
127+
},
128+
};
Lines changed: 26 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,15 @@
1-
import trustpilot from "../../trustpilot.app.mjs";
1+
import common from "../common/polling.mjs";
22

33
export default {
4+
...common,
45
key: "trustpilot-new-product-reviews",
56
name: "New Product Reviews",
67
description: "Emit new event when a customer posts a new product review on Trustpilot. This source periodically polls the Trustpilot API to detect new product reviews. Each event contains the complete review data including star rating, review text, product information, consumer details, and timestamps. Perfect for monitoring product feedback, analyzing customer satisfaction trends, and triggering automated responses or alerts for specific products.",
78
version: "0.1.0",
89
type: "source",
910
dedupe: "unique",
10-
props: {
11-
trustpilot,
12-
db: "$.service.db",
13-
timer: {
14-
type: "$.interface.timer",
15-
default: {
16-
intervalSeconds: 15 * 60, // 15 minutes
17-
},
18-
},
19-
businessUnitId: {
20-
propDefinition: [
21-
trustpilot,
22-
"businessUnitId",
23-
],
24-
},
25-
},
2611
methods: {
27-
_getLastReviewTime() {
28-
return this.db.get("lastReviewTime");
29-
},
30-
_setLastReviewTime(time) {
31-
this.db.set("lastReviewTime", time);
32-
},
12+
...common.methods,
3313
generateSummary(review) {
3414
const stars = review.stars || "N/A";
3515
const consumerName = review.consumer?.name || "Anonymous";
@@ -38,66 +18,39 @@ export default {
3818

3919
return `New ${stars}-star product review by ${consumerName} for "${productName}" (${businessUnit})`;
4020
},
41-
},
42-
async run({ $ }) {
43-
try {
44-
// Get the last review time for filtering new reviews
45-
const lastReviewTime = this._getLastReviewTime();
46-
47-
// Use the fetch-product-reviews action to get reviews
21+
getFetchParams() {
4822
// Note: Product reviews API doesn't support time-based filtering,
4923
// so we'll rely on pagination and client-side filtering
50-
const fetchParams = {
24+
return {
5125
businessUnitId: this.businessUnitId,
5226
perPage: 100,
5327
page: 1,
5428
};
55-
29+
},
30+
async fetchReviews($, params) {
5631
// Use the shared method from the app directly
57-
const result = await this.trustpilot.fetchProductReviews($, fetchParams);
58-
59-
const reviews = result.reviews || [];
60-
61-
if (!reviews.length) {
62-
console.log("No new product reviews found");
63-
return;
64-
}
65-
66-
// Filter for new reviews since last poll (client-side filtering)
32+
return await this.trustpilot.fetchProductReviews($, params);
33+
},
34+
filterNewReviews(reviews, lastReviewTime) {
35+
// Product reviews require client-side filtering since API doesn't support
36+
// time-based filtering
6737
const lastTs = Number(lastReviewTime) || 0;
6838
const toMs = (d) => new Date(d).getTime();
69-
let newReviews = lastTs
39+
40+
return lastTs
7041
? reviews.filter((r) => toMs(r.createdAt) > lastTs)
7142
: reviews;
72-
73-
if (!newReviews.length) {
74-
console.log("No new product reviews since last poll");
75-
return;
76-
}
77-
78-
// Track the latest review time
79-
// Initialize latestReviewTime as a numeric timestamp (ms)
80-
let latestReviewTime = Number(lastReviewTime) || 0;
81-
82-
for (const review of newReviews) {
83-
// Track the latest review time
84-
const createdTs = new Date(review.createdAt).getTime();
85-
if (createdTs > latestReviewTime) latestReviewTime = createdTs;
86-
// Emit the review with unique ID and summary
87-
this.$emit(review, {
88-
id: review.id,
89-
summary: this.generateSummary(review),
90-
ts: new Date(review.createdAt).getTime(),
91-
});
92-
}
93-
94-
// Update the last review time for next poll
95-
if (latestReviewTime && latestReviewTime !== Number(lastReviewTime)) {
96-
this._setLastReviewTime(latestReviewTime);
97-
}
98-
99-
} catch (error) {
100-
throw new Error(`Failed to fetch new product reviews: ${error.message}`);
101-
}
43+
},
44+
_getLastReviewTime() {
45+
// Product reviews store timestamp as number (ms), others store as ISO string
46+
return this.db.get("lastReviewTime");
47+
},
48+
_setLastReviewTime(time) {
49+
// Store as number for product reviews to match existing behavior
50+
const timeMs = typeof time === "string"
51+
? new Date(time).getTime()
52+
: time;
53+
this.db.set("lastReviewTime", timeMs);
54+
},
10255
},
10356
};
Lines changed: 16 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,101 +1,48 @@
1-
import trustpilot from "../../trustpilot.app.mjs";
1+
import common from "../common/polling.mjs";
22

33
export default {
4+
...common,
45
key: "trustpilot-new-service-reviews",
56
name: "New Service Reviews",
67
description: "Emit new event when a customer posts a new service review on Trustpilot. This source periodically polls the Trustpilot API to detect new service reviews using the private reviews API for comprehensive coverage. Each event contains the complete review data including star rating, review text, consumer details, business unit info, customer email, and timestamps. Ideal for monitoring overall business reputation, tracking customer satisfaction metrics, and triggering workflows based on review ratings or content.",
78
version: "0.1.0",
89
type: "source",
910
dedupe: "unique",
10-
props: {
11-
trustpilot,
12-
db: "$.service.db",
13-
timer: {
14-
type: "$.interface.timer",
15-
default: {
16-
intervalSeconds: 15 * 60, // 15 minutes
17-
},
18-
},
19-
businessUnitId: {
20-
propDefinition: [
21-
trustpilot,
22-
"businessUnitId",
23-
],
24-
},
25-
},
2611
methods: {
27-
_getLastReviewTime() {
28-
return this.db.get("lastReviewTime");
29-
},
30-
_setLastReviewTime(time) {
31-
this.db.set("lastReviewTime", time);
32-
},
12+
...common.methods,
3313
generateSummary(review) {
3414
const stars = review.stars || "N/A";
3515
const consumerName = review.consumer?.displayName || "Anonymous";
3616
const businessUnit = review.businessUnit?.displayName || this.businessUnitId || "Unknown";
3717

3818
return `New ${stars}-star service review by ${consumerName} for ${businessUnit}`;
3919
},
40-
},
41-
async run({ $ }) {
42-
try {
43-
// Get the last review time for filtering new reviews
44-
const lastReviewTime = this._getLastReviewTime();
45-
46-
// Use the fetch-service-reviews action to get reviews
47-
const fetchParams = {
20+
getFetchParams(lastReviewTime) {
21+
const params = {
4822
businessUnitId: this.businessUnitId,
4923
perPage: 100,
5024
orderBy: "createdat.desc",
5125
};
5226

5327
// If we have a last review time, filter for reviews after that time
5428
if (lastReviewTime) {
55-
fetchParams.startDateTime = lastReviewTime;
29+
params.startDateTime = lastReviewTime;
5630
}
5731

58-
// Use the shared method from the app directly
59-
let result = await this.trustpilot.fetchServiceReviews($, fetchParams);
32+
return params;
33+
},
34+
async fetchReviews($, params) {
35+
// Use the shared method from the app directly with pagination support
36+
let result = await this.trustpilot.fetchServiceReviews($, params);
6037

38+
// Handle pagination for service reviews
6139
while (result.reviews && result.reviews.length === 100) {
62-
fetchParams.page = (fetchParams.page || 1) + 1;
63-
const nextResult = await this.trustpilot.fetchServiceReviews($, fetchParams);
40+
params.page = (params.page || 1) + 1;
41+
const nextResult = await this.trustpilot.fetchServiceReviews($, params);
6442
result.reviews = result.reviews.concat(nextResult.reviews || []);
6543
}
6644

67-
const reviews = result.reviews || [];
68-
69-
if (!reviews.length) {
70-
console.log("No new service reviews found");
71-
return;
72-
}
73-
74-
// Emit reviews (already parsed by the action)
75-
let latestReviewTime = lastReviewTime;
76-
77-
for (const review of reviews) {
78-
// Track the latest review time
79-
const reviewTime = new Date(review.createdAt).toISOString();
80-
if (!latestReviewTime || new Date(reviewTime) > new Date(latestReviewTime)) {
81-
latestReviewTime = reviewTime;
82-
}
83-
84-
// Emit the review with unique ID and summary
85-
this.$emit(review, {
86-
id: review.id,
87-
summary: this.generateSummary(review),
88-
ts: new Date(review.createdAt).getTime(),
89-
});
90-
}
91-
92-
// Update the last review time for next poll
93-
if (latestReviewTime && latestReviewTime !== lastReviewTime) {
94-
this._setLastReviewTime(latestReviewTime);
95-
}
96-
97-
} catch (error) {
98-
throw new Error(`Failed to fetch new service reviews: ${error.message}`);
99-
}
45+
return result;
46+
},
10047
},
10148
};

0 commit comments

Comments
 (0)