@pipedream/google_ads 0.6.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/actions/add-contact-to-list-by-email/add-contact-to-list-by-email.mjs +1 -1
  2. package/actions/create-ad-group-report/create-ad-group-report.mjs +1 -1
  3. package/actions/create-ad-report/create-ad-report.mjs +1 -1
  4. package/actions/create-campaign-report/create-campaign-report.mjs +1 -1
  5. package/actions/create-customer-list/create-customer-list.mjs +1 -1
  6. package/actions/create-customer-report/create-customer-report.mjs +1 -1
  7. package/actions/create-or-remove-campaign-criteria/create-or-remove-campaign-criteria.mjs +214 -0
  8. package/actions/create-or-remove-campaign-shared-set/create-or-remove-campaign-shared-set.mjs +155 -0
  9. package/actions/create-or-remove-shared-criteria/create-or-remove-shared-criteria.mjs +180 -0
  10. package/actions/create-or-update-ad-group/create-or-update-ad-group.mjs +315 -0
  11. package/actions/create-or-update-ad-group-ad/create-or-update-ad-group-ad.mjs +203 -0
  12. package/actions/create-or-update-bidding-strategy/create-or-update-bidding-strategy.mjs +180 -0
  13. package/actions/create-or-update-campaign/create-or-update-campaign.mjs +243 -0
  14. package/actions/create-or-update-campaign-budget/create-or-update-campaign-budget.mjs +212 -0
  15. package/actions/create-or-update-keywords/create-or-update-keywords.mjs +275 -0
  16. package/actions/create-or-update-shared-sets/create-or-update-shared-sets.mjs +180 -0
  17. package/actions/create-report/create-report.mjs +123 -121
  18. package/actions/create-responsive-search-ad/create-responsive-search-ad.mjs +202 -0
  19. package/actions/generate-keyword-ideas/generate-keyword-ideas.mjs +1 -1
  20. package/actions/get-keyword-quality-scores/get-keyword-quality-scores.mjs +107 -0
  21. package/actions/list-account-id-options/list-account-id-options.mjs +1 -1
  22. package/actions/list-ad-group-ads/list-ad-group-ads.mjs +55 -0
  23. package/actions/list-ad-group-criteria/list-ad-group-criteria.mjs +55 -0
  24. package/actions/list-ad-groups/list-ad-groups.mjs +55 -0
  25. package/actions/list-bidding-strategies/list-bidding-strategies.mjs +55 -0
  26. package/actions/list-campaign-budgets/list-campaign-budgets.mjs +55 -0
  27. package/actions/list-campaign-criteria/list-campaign-criteria.mjs +55 -0
  28. package/actions/list-campaign-shared-sets/list-campaign-shared-sets.mjs +55 -0
  29. package/actions/list-campaigns/list-campaigns.mjs +55 -0
  30. package/actions/list-customer-clients/list-customer-clients.mjs +43 -0
  31. package/actions/list-keywords/list-keywords.mjs +55 -0
  32. package/actions/list-shared-criteria/list-shared-criteria.mjs +55 -0
  33. package/actions/list-shared-sets/list-shared-sets.mjs +55 -0
  34. package/actions/send-offline-conversion/send-offline-conversion.mjs +1 -1
  35. package/actions/update-campaign-ai-max-settings/update-campaign-ai-max-settings.mjs +167 -0
  36. package/common/constants.mjs +269 -0
  37. package/common/queries.mjs +4 -2
  38. package/common/utils.mjs +4 -0
  39. package/google_ads.app.mjs +591 -3
  40. package/package.json +1 -1
  41. package/sources/new-campaign-created/new-campaign-created.mjs +1 -1
  42. package/sources/new-lead-form-entry/new-lead-form-entry.mjs +1 -1
@@ -0,0 +1,167 @@
1
+ import { ConfigurationError } from "@pipedream/platform";
2
+ import googleAds from "../../google_ads.app.mjs";
3
+ import { ASSET_AUTOMATION_STATUSES } from "../../common/constants.mjs";
4
+ import { parseObject } from "../../common/utils.mjs";
5
+ import { getAdditionalFields } from "../common/props.mjs";
6
+
7
+ const docLink =
8
+ "https://developers.google.com/google-ads/api/docs/campaigns/ai-max-for-search-campaigns/getting-started";
9
+
10
+ export default {
11
+ key: "google_ads-update-campaign-ai-max-settings",
12
+ name: "Update Campaign AI Max Settings",
13
+ description: `Enables or configures AI Max for Search settings on a campaign. Only supported on Search campaigns. Toggling AI Max while simultaneously editing brand or text customization settings on the same campaign may fail — update them separately. Ad group-level search term matching is controlled via the **Create or Update Ad Group** action. [See the documentation](${docLink})`,
14
+ version: "0.0.1",
15
+ type: "action",
16
+ annotations: {
17
+ destructiveHint: false,
18
+ openWorldHint: true,
19
+ readOnlyHint: false,
20
+ },
21
+ props: {
22
+ googleAds,
23
+ accountId: {
24
+ propDefinition: [
25
+ googleAds,
26
+ "accountId",
27
+ ],
28
+ },
29
+ customerClientId: {
30
+ propDefinition: [
31
+ googleAds,
32
+ "customerClientId",
33
+ ({ accountId }) => ({
34
+ accountId,
35
+ }),
36
+ ],
37
+ optional: true,
38
+ },
39
+ campaignId: {
40
+ propDefinition: [
41
+ googleAds,
42
+ "campaignId",
43
+ ({
44
+ accountId, customerClientId,
45
+ }) => ({
46
+ accountId,
47
+ customerClientId,
48
+ }),
49
+ ],
50
+ },
51
+ enableAiMax: {
52
+ type: "boolean",
53
+ label: "Enable AI Max",
54
+ description: "Whether to enable AI Max for Search on this campaign (`aiMaxSetting.enableAiMax`).",
55
+ optional: true,
56
+ },
57
+ bundlingRequired: {
58
+ type: "boolean",
59
+ label: "Bundling Required",
60
+ description: "Whether bundling is required for AI Max asset serving (`aiMaxSetting.bundlingRequired`).",
61
+ optional: true,
62
+ },
63
+ textAssetAutomation: {
64
+ type: "string",
65
+ label: "Text Asset Automation",
66
+ description: "Opt in or out of automatically generated text assets (`TEXT_ASSET_AUTOMATION`).",
67
+ options: ASSET_AUTOMATION_STATUSES,
68
+ optional: true,
69
+ },
70
+ finalUrlExpansionAutomation: {
71
+ type: "string",
72
+ label: "Final URL Expansion Automation",
73
+ description: "Opt in or out of automatically expanding final URLs (`FINAL_URL_EXPANSION_TEXT_ASSET_AUTOMATION`).",
74
+ options: ASSET_AUTOMATION_STATUSES,
75
+ optional: true,
76
+ },
77
+ additionalFields: getAdditionalFields(docLink),
78
+ },
79
+ async run({ $ }) {
80
+ const {
81
+ googleAds,
82
+ accountId,
83
+ customerClientId,
84
+ campaignId,
85
+ enableAiMax,
86
+ bundlingRequired,
87
+ textAssetAutomation,
88
+ finalUrlExpansionAutomation,
89
+ additionalFields,
90
+ } = this;
91
+
92
+ const updateMaskFields = [];
93
+ const aiMaxSetting = {};
94
+
95
+ if (enableAiMax !== undefined) {
96
+ aiMaxSetting.enableAiMax = enableAiMax;
97
+ updateMaskFields.push("aiMaxSetting.enableAiMax");
98
+ }
99
+ if (bundlingRequired !== undefined) {
100
+ aiMaxSetting.bundlingRequired = bundlingRequired;
101
+ updateMaskFields.push("aiMaxSetting.bundlingRequired");
102
+ }
103
+
104
+ const assetAutomationSettings = [];
105
+ if (textAssetAutomation) {
106
+ assetAutomationSettings.push({
107
+ assetAutomationType: "TEXT_ASSET_AUTOMATION",
108
+ assetAutomationStatus: textAssetAutomation,
109
+ });
110
+ }
111
+ if (finalUrlExpansionAutomation) {
112
+ assetAutomationSettings.push({
113
+ assetAutomationType: "FINAL_URL_EXPANSION_TEXT_ASSET_AUTOMATION",
114
+ assetAutomationStatus: finalUrlExpansionAutomation,
115
+ });
116
+ }
117
+ if (assetAutomationSettings.length) {
118
+ updateMaskFields.push("assetAutomationSettings");
119
+ }
120
+
121
+ const extraFields = parseObject(additionalFields);
122
+ const extraKeys = Object.keys(extraFields);
123
+ if (extraKeys.length) {
124
+ updateMaskFields.push(...extraKeys);
125
+ }
126
+
127
+ if (!updateMaskFields.length) {
128
+ throw new ConfigurationError(
129
+ "At least one AI Max setting must be provided.",
130
+ );
131
+ }
132
+
133
+ const customerId = customerClientId ?? accountId;
134
+ const resourceName = `customers/${customerId}/campaigns/${campaignId}`;
135
+
136
+ const campaignData = {
137
+ resourceName,
138
+ ...(Object.keys(aiMaxSetting).length && {
139
+ aiMaxSetting,
140
+ }),
141
+ ...(assetAutomationSettings.length && {
142
+ assetAutomationSettings,
143
+ }),
144
+ ...extraFields,
145
+ };
146
+
147
+ const response = await googleAds.mutateCampaign({
148
+ $,
149
+ accountId,
150
+ customerClientId,
151
+ data: {
152
+ operations: [
153
+ {
154
+ update: campaignData,
155
+ updateMask: updateMaskFields.join(","),
156
+ },
157
+ ],
158
+ },
159
+ });
160
+
161
+ $.export(
162
+ "$summary",
163
+ `Successfully updated AI Max settings for campaign \`${campaignId}\`.`,
164
+ );
165
+ return response;
166
+ },
167
+ };
@@ -1,3 +1,272 @@
1
+ export const SHARED_SET_TYPES = [
2
+ {
3
+ label: "Negative Keywords",
4
+ value: "NEGATIVE_KEYWORDS",
5
+ },
6
+ {
7
+ label: "Negative Placements",
8
+ value: "NEGATIVE_PLACEMENTS",
9
+ },
10
+ ];
11
+
12
+ export const CREATE_REMOVE_OPERATION_TYPES = [
13
+ {
14
+ label: "Create",
15
+ value: "create",
16
+ },
17
+ {
18
+ label: "Remove",
19
+ value: "remove",
20
+ },
21
+ ];
22
+
23
+ export const CAMPAIGN_OPERATION_TYPES = [
24
+ {
25
+ label: "Create",
26
+ value: "create",
27
+ },
28
+ {
29
+ label: "Update",
30
+ value: "update",
31
+ },
32
+ {
33
+ label: "Remove",
34
+ value: "remove",
35
+ },
36
+ ];
37
+
38
+ export const CAMPAIGN_STATUSES = [
39
+ "ENABLED",
40
+ "PAUSED",
41
+ "REMOVED",
42
+ ];
43
+
44
+ export const ADVERTISING_CHANNEL_TYPES = [
45
+ {
46
+ label: "Search",
47
+ value: "SEARCH",
48
+ },
49
+ {
50
+ label: "Display",
51
+ value: "DISPLAY",
52
+ },
53
+ {
54
+ label: "Shopping",
55
+ value: "SHOPPING",
56
+ },
57
+ {
58
+ label: "Hotel",
59
+ value: "HOTEL",
60
+ },
61
+ {
62
+ label: "Video",
63
+ value: "VIDEO",
64
+ },
65
+ {
66
+ label: "Multi-Channel (App)",
67
+ value: "MULTI_CHANNEL",
68
+ },
69
+ {
70
+ label: "Local",
71
+ value: "LOCAL",
72
+ },
73
+ {
74
+ label: "Smart",
75
+ value: "SMART",
76
+ },
77
+ {
78
+ label: "Performance Max",
79
+ value: "PERFORMANCE_MAX",
80
+ },
81
+ {
82
+ label: "Local Services",
83
+ value: "LOCAL_SERVICES",
84
+ },
85
+ {
86
+ label: "Discovery",
87
+ value: "DISCOVERY",
88
+ },
89
+ {
90
+ label: "Travel",
91
+ value: "TRAVEL",
92
+ },
93
+ {
94
+ label: "Demand Gen",
95
+ value: "DEMAND_GEN",
96
+ },
97
+ ];
98
+
99
+ export const KEYWORD_MATCH_TYPES = [
100
+ {
101
+ label: "Exact",
102
+ value: "EXACT",
103
+ },
104
+ {
105
+ label: "Phrase",
106
+ value: "PHRASE",
107
+ },
108
+ {
109
+ label: "Broad",
110
+ value: "BROAD",
111
+ },
112
+ ];
113
+
114
+ export const AD_GROUP_STATUSES = [
115
+ "ENABLED",
116
+ "PAUSED",
117
+ "REMOVED",
118
+ ];
119
+
120
+ export const AD_GROUP_TYPES = [
121
+ {
122
+ label: "Search Standard",
123
+ value: "SEARCH_STANDARD",
124
+ },
125
+ {
126
+ label: "Display Standard",
127
+ value: "DISPLAY_STANDARD",
128
+ },
129
+ {
130
+ label: "Shopping Product Ads",
131
+ value: "SHOPPING_PRODUCT_ADS",
132
+ },
133
+ {
134
+ label: "Hotel Ads",
135
+ value: "HOTEL_ADS",
136
+ },
137
+ {
138
+ label: "Shopping Smart Ads",
139
+ value: "SHOPPING_SMART_ADS",
140
+ },
141
+ {
142
+ label: "Video Bumper",
143
+ value: "VIDEO_BUMPER",
144
+ },
145
+ {
146
+ label: "Video TrueView In-Stream",
147
+ value: "VIDEO_TRUE_VIEW_IN_STREAM",
148
+ },
149
+ {
150
+ label: "Video TrueView In-Display",
151
+ value: "VIDEO_TRUE_VIEW_IN_DISPLAY",
152
+ },
153
+ {
154
+ label: "Video Non-Skippable In-Stream",
155
+ value: "VIDEO_NON_SKIPPABLE_IN_STREAM",
156
+ },
157
+ {
158
+ label: "Video Outstream",
159
+ value: "VIDEO_OUTSTREAM",
160
+ },
161
+ {
162
+ label: "Search Dynamic Ads",
163
+ value: "SEARCH_DYNAMIC_ADS",
164
+ },
165
+ {
166
+ label: "Shopping Comparison Listing Ads",
167
+ value: "SHOPPING_COMPARISON_LISTING_ADS",
168
+ },
169
+ {
170
+ label: "Promoted Hotel Ads",
171
+ value: "PROMOTED_HOTEL_ADS",
172
+ },
173
+ {
174
+ label: "Video Responsive",
175
+ value: "VIDEO_RESPONSIVE",
176
+ },
177
+ {
178
+ label: "Video Efficient Reach",
179
+ value: "VIDEO_EFFICIENT_REACH",
180
+ },
181
+ {
182
+ label: "Smart Campaign Ads",
183
+ value: "SMART_CAMPAIGN_ADS",
184
+ },
185
+ {
186
+ label: "Travel Ads",
187
+ value: "TRAVEL_ADS",
188
+ },
189
+ ];
190
+
191
+ export const AD_ROTATION_MODES = [
192
+ {
193
+ label: "Optimize",
194
+ value: "OPTIMIZE",
195
+ },
196
+ {
197
+ label: "Rotate Forever",
198
+ value: "ROTATE_FOREVER",
199
+ },
200
+ ];
201
+
202
+ export const BUDGET_DELIVERY_METHODS = [
203
+ {
204
+ label: "Standard",
205
+ value: "STANDARD",
206
+ },
207
+ {
208
+ label: "Accelerated",
209
+ value: "ACCELERATED",
210
+ },
211
+ ];
212
+
213
+ export const BUDGET_PERIODS = [
214
+ {
215
+ label: "Daily",
216
+ value: "DAILY",
217
+ },
218
+ {
219
+ label: "Custom Period",
220
+ value: "CUSTOM_PERIOD",
221
+ },
222
+ ];
223
+
224
+ export const ASSET_AUTOMATION_STATUSES = [
225
+ {
226
+ label: "Opted In",
227
+ value: "OPTED_IN",
228
+ },
229
+ {
230
+ label: "Opted Out",
231
+ value: "OPTED_OUT",
232
+ },
233
+ ];
234
+
235
+ export const PORTFOLIO_BIDDING_STRATEGY_TYPES = [
236
+ {
237
+ label: "Target CPA",
238
+ value: "TARGET_CPA",
239
+ },
240
+ {
241
+ label: "Target ROAS",
242
+ value: "TARGET_ROAS",
243
+ },
244
+ {
245
+ label: "Target Spend",
246
+ value: "TARGET_SPEND",
247
+ },
248
+ {
249
+ label: "Maximize Conversions",
250
+ value: "MAXIMIZE_CONVERSIONS",
251
+ },
252
+ {
253
+ label: "Maximize Conversion Value",
254
+ value: "MAXIMIZE_CONVERSION_VALUE",
255
+ },
256
+ {
257
+ label: "Target Impression Share",
258
+ value: "TARGET_IMPRESSION_SHARE",
259
+ },
260
+ {
261
+ label: "Enhanced CPC",
262
+ value: "ENHANCED_CPC",
263
+ },
264
+ {
265
+ label: "Percent CPC",
266
+ value: "PERCENT_CPC",
267
+ },
268
+ ];
269
+
1
270
  export const CORE_DATE_SEGMENTS = [
2
271
  "segments.date",
3
272
  "segments.week",
@@ -1,3 +1,5 @@
1
+ import { sanitizeGaqlString } from "./utils.mjs";
2
+
1
3
  function listCustomerClients(query) {
2
4
  const fields = [
3
5
  "client_customer",
@@ -10,7 +12,7 @@ function listCustomerClients(query) {
10
12
  .join(", ");
11
13
 
12
14
  const condition = query
13
- ? `customer_client.descriptive_name LIKE '%${query}%'`
15
+ ? `customer_client.descriptive_name LIKE '%${sanitizeGaqlString(query)}%'`
14
16
  : "customer_client.level <= 3";
15
17
 
16
18
  return `SELECT ${fields} FROM customer_client WHERE ${condition}`;
@@ -105,7 +107,7 @@ function listResources(resource, query) {
105
107
 
106
108
  let result = `SELECT ${fieldResource}.id, ${fieldResource}.${name} FROM ${resource}`;
107
109
  if (query) {
108
- result += ` WHERE ${fieldResource}.${name} LIKE '%${query}%'`;
110
+ result += ` WHERE ${fieldResource}.${name} LIKE '%${sanitizeGaqlString(query)}%'`;
109
111
  }
110
112
  return result;
111
113
  }
package/common/utils.mjs CHANGED
@@ -68,6 +68,10 @@ export function getResourceOption(item, resource) {
68
68
  };
69
69
  }
70
70
 
71
+ export function sanitizeGaqlString(value) {
72
+ return String(value).replace(/'/g, "''");
73
+ }
74
+
71
75
  export function checkPrefix(value, prefix) {
72
76
  const checkStr = (s) => s && (s?.startsWith?.(prefix)
73
77
  ? s