Skip to content

Commit 47cee75

Browse files
committed
Implement comprehensive Trustpilot integration with polling sources
## Overview Complete Trustpilot integration using polling approach (webhooks not supported by Trustpilot API). ## Features Implemented ### Authentication & Core App - Enhanced trustpilot.app.ts with OAuth and API key authentication - Added comprehensive API methods for reviews, products, and conversations - Support for both public and private endpoints - Proper error handling, validation, and retry logic with rate limiting ### Actions (6 total) - **fetch-service-reviews** - Get service reviews with filtering and pagination - **fetch-service-review-by-id** - Get specific service review - **fetch-product-reviews** - Get product reviews with filtering and pagination - **fetch-product-review-by-id** - Get specific product review - **reply-to-service-review** - Reply to service reviews - **reply-to-product-review** - Reply to product reviews ### Polling Sources (8 total) - **new-service-reviews** - New service reviews (public + private endpoints) - **updated-service-reviews** - Updated/revised service reviews - **new-product-reviews** - New product reviews - **updated-product-reviews** - Updated/revised product reviews - **new-service-review-replies** - New replies to service reviews - **new-product-review-replies** - New replies to product reviews - **new-conversations** - New conversations started - **updated-conversations** - Updated conversations (new messages) ### Technical Implementation - 15-minute polling intervals following Google Drive pattern - Smart deduplication by reviewId + timestamp - Business unit filtering (optional) - 24-hour lookback on first run - Comprehensive constants and utilities - Proper pagination and error handling ## API Endpoints Used - `/business-units/{businessUnitId}/reviews` (public) - `/private/business-units/{businessUnitId}/reviews` (private service) - `/private/product-reviews/business-units/{businessUnitId}/reviews` (products) - `/private/conversations` (conversations) - All reply endpoints for posting responses Addresses all requirements from https://developers.trustpilot.com/introduction/
1 parent e21d334 commit 47cee75

File tree

20 files changed

+1714
-4
lines changed

20 files changed

+1714
-4
lines changed

components/trustpilot/.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,2 @@
11
*.js
2-
*.mjs
32
dist
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import trustpilot from "../../app/trustpilot.app.ts";
2+
3+
export default {
4+
key: "trustpilot-fetch-product-review-by-id",
5+
name: "Fetch Product Review by ID",
6+
description: "Fetch a specific product review by its ID. [See the documentation](https://developers.trustpilot.com/product-reviews-api#get-private-product-review)",
7+
version: "0.0.1",
8+
type: "action",
9+
props: {
10+
trustpilot,
11+
reviewId: {
12+
propDefinition: [
13+
trustpilot,
14+
"reviewId",
15+
],
16+
},
17+
},
18+
async run({ $ }) {
19+
const { reviewId } = this;
20+
21+
try {
22+
const review = await this.trustpilot.getProductReviewById({
23+
reviewId,
24+
});
25+
26+
$.export("$summary", `Successfully fetched product review ${reviewId}`);
27+
28+
return {
29+
review,
30+
metadata: {
31+
reviewId,
32+
requestTime: new Date().toISOString(),
33+
},
34+
};
35+
} catch (error) {
36+
throw new Error(`Failed to fetch product review: ${error.message}`);
37+
}
38+
},
39+
};
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
import trustpilot from "../../app/trustpilot.app.ts";
2+
3+
export default {
4+
key: "trustpilot-fetch-product-reviews",
5+
name: "Fetch Product Reviews",
6+
description: "Fetch product reviews for a business unit. [See the documentation](https://developers.trustpilot.com/product-reviews-api#get-private-product-reviews)",
7+
version: "0.0.1",
8+
type: "action",
9+
props: {
10+
trustpilot,
11+
businessUnitId: {
12+
propDefinition: [
13+
trustpilot,
14+
"businessUnitId",
15+
],
16+
},
17+
stars: {
18+
propDefinition: [
19+
trustpilot,
20+
"stars",
21+
],
22+
},
23+
sortBy: {
24+
propDefinition: [
25+
trustpilot,
26+
"sortBy",
27+
],
28+
},
29+
limit: {
30+
propDefinition: [
31+
trustpilot,
32+
"limit",
33+
],
34+
},
35+
includeReportedReviews: {
36+
propDefinition: [
37+
trustpilot,
38+
"includeReportedReviews",
39+
],
40+
},
41+
tags: {
42+
propDefinition: [
43+
trustpilot,
44+
"tags",
45+
],
46+
},
47+
language: {
48+
propDefinition: [
49+
trustpilot,
50+
"language",
51+
],
52+
},
53+
offset: {
54+
type: "integer",
55+
label: "Offset",
56+
description: "Number of results to skip (for pagination)",
57+
min: 0,
58+
default: 0,
59+
optional: true,
60+
},
61+
},
62+
async run({ $ }) {
63+
const {
64+
businessUnitId,
65+
stars,
66+
sortBy,
67+
limit,
68+
includeReportedReviews,
69+
tags,
70+
language,
71+
offset,
72+
} = this;
73+
74+
try {
75+
const result = await this.trustpilot.getProductReviews({
76+
businessUnitId,
77+
stars,
78+
sortBy,
79+
limit,
80+
includeReportedReviews,
81+
tags,
82+
language,
83+
offset,
84+
});
85+
86+
const { reviews, pagination } = result;
87+
88+
$.export("$summary", `Successfully fetched ${reviews.length} product review(s) for business unit ${businessUnitId}`);
89+
90+
return {
91+
reviews,
92+
pagination,
93+
metadata: {
94+
businessUnitId,
95+
filters: {
96+
stars,
97+
sortBy,
98+
includeReportedReviews,
99+
tags,
100+
language,
101+
},
102+
requestTime: new Date().toISOString(),
103+
},
104+
};
105+
} catch (error) {
106+
throw new Error(`Failed to fetch product reviews: ${error.message}`);
107+
}
108+
},
109+
};
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import trustpilot from "../../app/trustpilot.app.ts";
2+
3+
export default {
4+
key: "trustpilot-fetch-service-review-by-id",
5+
name: "Fetch Service Review by ID",
6+
description: "Fetch a specific service review by its ID. [See the documentation](https://developers.trustpilot.com/business-units-api#get-business-unit-review)",
7+
version: "0.0.1",
8+
type: "action",
9+
props: {
10+
trustpilot,
11+
businessUnitId: {
12+
propDefinition: [
13+
trustpilot,
14+
"businessUnitId",
15+
],
16+
},
17+
reviewId: {
18+
propDefinition: [
19+
trustpilot,
20+
"reviewId",
21+
],
22+
},
23+
},
24+
async run({ $ }) {
25+
const {
26+
businessUnitId,
27+
reviewId,
28+
} = this;
29+
30+
try {
31+
const review = await this.trustpilot.getServiceReviewById({
32+
businessUnitId,
33+
reviewId,
34+
});
35+
36+
$.export("$summary", `Successfully fetched service review ${reviewId} for business unit ${businessUnitId}`);
37+
38+
return {
39+
review,
40+
metadata: {
41+
businessUnitId,
42+
reviewId,
43+
requestTime: new Date().toISOString(),
44+
},
45+
};
46+
} catch (error) {
47+
throw new Error(`Failed to fetch service review: ${error.message}`);
48+
}
49+
},
50+
};
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
import trustpilot from "../../app/trustpilot.app.ts";
2+
3+
export default {
4+
key: "trustpilot-fetch-service-reviews",
5+
name: "Fetch Service Reviews",
6+
description: "Fetch service reviews for a business unit. [See the documentation](https://developers.trustpilot.com/business-units-api#get-business-unit-reviews)",
7+
version: "0.0.1",
8+
type: "action",
9+
props: {
10+
trustpilot,
11+
businessUnitId: {
12+
propDefinition: [
13+
trustpilot,
14+
"businessUnitId",
15+
],
16+
},
17+
stars: {
18+
propDefinition: [
19+
trustpilot,
20+
"stars",
21+
],
22+
},
23+
sortBy: {
24+
propDefinition: [
25+
trustpilot,
26+
"sortBy",
27+
],
28+
},
29+
limit: {
30+
propDefinition: [
31+
trustpilot,
32+
"limit",
33+
],
34+
},
35+
includeReportedReviews: {
36+
propDefinition: [
37+
trustpilot,
38+
"includeReportedReviews",
39+
],
40+
},
41+
tags: {
42+
propDefinition: [
43+
trustpilot,
44+
"tags",
45+
],
46+
},
47+
language: {
48+
propDefinition: [
49+
trustpilot,
50+
"language",
51+
],
52+
},
53+
offset: {
54+
type: "integer",
55+
label: "Offset",
56+
description: "Number of results to skip (for pagination)",
57+
min: 0,
58+
default: 0,
59+
optional: true,
60+
},
61+
},
62+
async run({ $ }) {
63+
const {
64+
businessUnitId,
65+
stars,
66+
sortBy,
67+
limit,
68+
includeReportedReviews,
69+
tags,
70+
language,
71+
offset,
72+
} = this;
73+
74+
try {
75+
const result = await this.trustpilot.getServiceReviews({
76+
businessUnitId,
77+
stars,
78+
sortBy,
79+
limit,
80+
includeReportedReviews,
81+
tags,
82+
language,
83+
offset,
84+
});
85+
86+
const { reviews, pagination } = result;
87+
88+
$.export("$summary", `Successfully fetched ${reviews.length} service review(s) for business unit ${businessUnitId}`);
89+
90+
return {
91+
reviews,
92+
pagination,
93+
metadata: {
94+
businessUnitId,
95+
filters: {
96+
stars,
97+
sortBy,
98+
includeReportedReviews,
99+
tags,
100+
language,
101+
},
102+
requestTime: new Date().toISOString(),
103+
},
104+
};
105+
} catch (error) {
106+
throw new Error(`Failed to fetch service reviews: ${error.message}`);
107+
}
108+
},
109+
};
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import trustpilot from "../../app/trustpilot.app.ts";
2+
3+
export default {
4+
key: "trustpilot-reply-to-product-review",
5+
name: "Reply to Product Review",
6+
description: "Reply to a product review on behalf of your business. [See the documentation](https://developers.trustpilot.com/product-reviews-api#reply-to-product-review)",
7+
version: "0.0.1",
8+
type: "action",
9+
props: {
10+
trustpilot,
11+
reviewId: {
12+
propDefinition: [
13+
trustpilot,
14+
"reviewId",
15+
],
16+
},
17+
message: {
18+
type: "string",
19+
label: "Reply Message",
20+
description: "The message to reply to the review with",
21+
},
22+
},
23+
async run({ $ }) {
24+
const {
25+
reviewId,
26+
message,
27+
} = this;
28+
29+
if (!message || message.trim().length === 0) {
30+
throw new Error("Reply message cannot be empty");
31+
}
32+
33+
try {
34+
const result = await this.trustpilot.replyToProductReview({
35+
reviewId,
36+
message: message.trim(),
37+
});
38+
39+
$.export("$summary", `Successfully replied to product review ${reviewId}`);
40+
41+
return {
42+
success: true,
43+
reply: result,
44+
metadata: {
45+
reviewId,
46+
messageLength: message.trim().length,
47+
requestTime: new Date().toISOString(),
48+
},
49+
};
50+
} catch (error) {
51+
throw new Error(`Failed to reply to product review: ${error.message}`);
52+
}
53+
},
54+
};

0 commit comments

Comments
 (0)