embulk-output-mailchimp 0.3.25 → 0.3.28

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 94b54333acb168038a0b2537d6bf7c8a71be4993
4
- data.tar.gz: 18b422345048fd9d9681dc24a369c8c16680c55e
3
+ metadata.gz: b429373deb2a79bd444d223f70818c7a7517bd63
4
+ data.tar.gz: 06fb08e83602804217e386754e39cd7cb542c2e8
5
5
  SHA512:
6
- metadata.gz: 8248823129afda3c947fed964e9ea6d080cf7cfb81b18d399cf9ab4aae25b40ead8e71a0981a98a9c184b018b5cc7c948b1df5aef639b35f7c03dba81ce6d7fc
7
- data.tar.gz: 24220688ee272036fa55ce8cf040ee3c95ce76942e424a35121767bf4f8e7924985b236712ffeac1d57ef75c2ae3441ff8646e67cf63b55d5e963c5e0ec97b56
6
+ metadata.gz: b096372c93fcb6a0c2930d0b98ade33a1d52277f65fd1554e6d80178ee2179b300847c69c907d4e2cbb1279f7028e6eac3804d123f8e92681e1955182df5bc22
7
+ data.tar.gz: efd31474670848d2457b2fdc5ea68b990902971543e884dd473fcb57064b34687a79beb95188bc06349e5448cac1a4919b91cadc90083a0fe39cca32d09c5c60
@@ -1,3 +1,11 @@
1
+ ## 0.3.28 - 2018-10-29
2
+
3
+ - Quick fix a typo
4
+
5
+ ## 0.3.26 - 2018-10-29
6
+
7
+ - Fix an NPE when there isn't a column corresponds to a configured group ('category')
8
+
1
9
  ## 0.3.25 - 2018-10-11
2
10
 
3
11
  - Fixed an NPE when column names and merge tags are not exactly (case-sensitive) matched
@@ -18,7 +18,7 @@ configurations {
18
18
  provided
19
19
  }
20
20
 
21
- version = "0.3.25"
21
+ version = "0.3.28"
22
22
 
23
23
  sourceCompatibility = 1.7
24
24
  targetCompatibility = 1.7
@@ -9,6 +9,7 @@ import com.fasterxml.jackson.databind.node.JsonNodeFactory;
9
9
  import com.fasterxml.jackson.databind.node.NullNode;
10
10
  import com.fasterxml.jackson.databind.node.ObjectNode;
11
11
  import com.google.common.base.Function;
12
+ import com.google.common.base.Optional;
12
13
  import com.google.common.base.Throwables;
13
14
  import com.google.common.collect.FluentIterable;
14
15
  import org.embulk.base.restclient.jackson.JacksonServiceRecord;
@@ -25,6 +26,8 @@ import org.embulk.spi.Exec;
25
26
  import org.embulk.spi.Schema;
26
27
  import org.slf4j.Logger;
27
28
 
29
+ import javax.annotation.Nullable;
30
+
28
31
  import java.io.IOException;
29
32
  import java.util.ArrayList;
30
33
  import java.util.Arrays;
@@ -34,11 +37,14 @@ import java.util.List;
34
37
  import java.util.Map;
35
38
  import java.util.Set;
36
39
  import java.util.TreeMap;
40
+ import java.util.TreeSet;
37
41
 
42
+ import static com.google.common.base.Joiner.on;
38
43
  import static java.lang.String.CASE_INSENSITIVE_ORDER;
39
44
  import static java.lang.String.format;
40
45
  import static org.embulk.output.mailchimp.MailChimpOutputPluginDelegate.PluginTask;
41
46
  import static org.embulk.output.mailchimp.helper.MailChimpHelper.fromCommaSeparatedString;
47
+ import static org.embulk.output.mailchimp.helper.MailChimpHelper.jsonGetIgnoreCase;
42
48
  import static org.embulk.output.mailchimp.helper.MailChimpHelper.orderJsonNode;
43
49
  import static org.embulk.output.mailchimp.helper.MailChimpHelper.toJsonNode;
44
50
  import static org.embulk.output.mailchimp.model.MemberStatus.PENDING;
@@ -168,6 +174,13 @@ public class MailChimpRecordBuffer
168
174
  // The reason why we put categories validation here because we can not share data between instance.
169
175
  if (categories == null) {
170
176
  categories = mailChimpClient.extractInterestCategoriesByGroupNames(task);
177
+
178
+ Set<String> categoriesNames = categories.keySet();
179
+ Set<String> columnNames = caseInsensitiveColumnNames();
180
+ if (!columnNames.containsAll(categoriesNames)) {
181
+ categoriesNames.removeAll(columnNames);
182
+ LOG.warn("Data column for category '{}' could not be found", on(", ").join(categoriesNames));
183
+ }
171
184
  }
172
185
 
173
186
  // Extract merge fields detail
@@ -249,7 +262,7 @@ public class MailChimpRecordBuffer
249
262
 
250
263
  // Update interest categories if exist
251
264
  if (task.getGroupingColumns().isPresent() && !task.getGroupingColumns().get().isEmpty()) {
252
- property.set("interests", buildInterestCategories(task, input));
265
+ property.set("interests", buildInterestCategories(input));
253
266
  }
254
267
 
255
268
  // Update language if exist
@@ -262,31 +275,36 @@ public class MailChimpRecordBuffer
262
275
  };
263
276
  }
264
277
 
265
- private ObjectNode buildInterestCategories(final PluginTask task, final JsonNode input)
278
+ private ObjectNode buildInterestCategories(final JsonNode input)
266
279
  {
267
280
  ObjectNode interests = JsonNodeFactory.instance.objectNode();
268
281
 
269
282
  if (task.getGroupingColumns().isPresent()) {
270
283
  for (String category : task.getGroupingColumns().get()) {
271
- String inputValue = input.findValue(category).asText();
272
- List<String> interestValues = fromCommaSeparatedString(inputValue);
273
- Map<String, InterestResponse> availableCategories = categories.get(category);
284
+ Optional<JsonNode> inputValue = jsonGetIgnoreCase(input, category);
285
+ if (!inputValue.isPresent()) {
286
+ // Silently ignore if the grouping column is absent
287
+ continue;
288
+ }
289
+ List<String> recordInterests = fromCommaSeparatedString(inputValue.get().asText());
290
+ // `categories` is guaranteed to contain the `category` as it already did an early check
291
+ Map<String, InterestResponse> availableInterests = categories.get(category);
274
292
 
275
293
  // Only update user-predefined categories if replace interests != true
276
294
  if (!task.getReplaceInterests()) {
277
- for (String interestValue : interestValues) {
278
- if (availableCategories.get(interestValue) != null) {
279
- interests.put(availableCategories.get(interestValue).getId(), true);
295
+ for (String recordInterest : recordInterests) {
296
+ if (availableInterests.get(recordInterest) != null) {
297
+ interests.put(availableInterests.get(recordInterest).getId(), true);
280
298
  }
281
299
  }
282
300
  } // Otherwise, force update all categories include user-predefined categories
283
301
  else if (task.getReplaceInterests()) {
284
- for (String availableCategory : availableCategories.keySet()) {
285
- if (interestValues.contains(availableCategory)) {
286
- interests.put(availableCategories.get(availableCategory).getId(), true);
302
+ for (String availableInterest : availableInterests.keySet()) {
303
+ if (recordInterests.contains(availableInterest)) {
304
+ interests.put(availableInterests.get(availableInterest).getId(), true);
287
305
  }
288
306
  else {
289
- interests.put(availableCategories.get(availableCategory).getId(), false);
307
+ interests.put(availableInterests.get(availableInterest).getId(), false);
290
308
  }
291
309
  }
292
310
  }
@@ -313,7 +331,8 @@ public class MailChimpRecordBuffer
313
331
  private void pushData() throws JsonProcessingException
314
332
  {
315
333
  long startTime = System.currentTimeMillis();
316
- ObjectNode subscribers = processSubcribers(uniqueRecords, task);
334
+ ObjectNode subscribers =
335
+ processSubcribers(uniqueRecords, task);
317
336
  ReportResponse reportResponse = mailChimpClient.push(subscribers, task);
318
337
 
319
338
  LOG.info("Done with {} record(s). Response from MailChimp: {} records created, {} records updated, {} records failed. Batch took {} ms ",
@@ -340,4 +359,21 @@ public class MailChimpRecordBuffer
340
359
  }
341
360
  }
342
361
  }
362
+
363
+ private Set<String> caseInsensitiveColumnNames()
364
+ {
365
+ Set<String> columns = new TreeSet<>(CASE_INSENSITIVE_ORDER);
366
+ columns.addAll(FluentIterable
367
+ .from(schema.getColumns())
368
+ .transform(new Function<Column, String>() {
369
+ @Nullable
370
+ @Override
371
+ public String apply(@Nullable Column col)
372
+ {
373
+ return col.getName();
374
+ }
375
+ })
376
+ .toSet());
377
+ return columns;
378
+ }
343
379
  }
@@ -7,6 +7,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
7
7
  import com.fasterxml.jackson.databind.node.JsonNodeFactory;
8
8
  import com.fasterxml.jackson.databind.node.ObjectNode;
9
9
  import com.google.common.base.Function;
10
+ import com.google.common.base.Optional;
10
11
  import com.google.common.base.Splitter;
11
12
  import com.google.common.collect.Lists;
12
13
  import com.google.common.collect.Multimap;
@@ -16,8 +17,11 @@ import org.embulk.output.mailchimp.model.AddressMergeFieldAttribute;
16
17
  import javax.annotation.Nullable;
17
18
 
18
19
  import java.io.IOException;
20
+ import java.util.Iterator;
19
21
  import java.util.List;
20
22
 
23
+ import static java.util.Objects.requireNonNull;
24
+
21
25
  /**
22
26
  * Created by thangnc on 4/26/17.
23
27
  */
@@ -125,4 +129,17 @@ public final class MailChimpHelper
125
129
 
126
130
  return orderedNode;
127
131
  }
132
+
133
+ public static Optional<JsonNode> jsonGetIgnoreCase(JsonNode node, String fieldName)
134
+ {
135
+ requireNonNull(fieldName);
136
+ Iterator<String> fieldNames = node.fieldNames();
137
+ while (fieldNames.hasNext()) {
138
+ String curFieldName = fieldNames.next();
139
+ if (fieldName.equalsIgnoreCase((curFieldName))) {
140
+ return Optional.of(node.get(curFieldName));
141
+ }
142
+ }
143
+ return Optional.absent();
144
+ }
128
145
  }
@@ -24,6 +24,7 @@ import java.text.MessageFormat;
24
24
  import java.util.concurrent.ExecutionException;
25
25
  import java.util.concurrent.TimeoutException;
26
26
 
27
+ import static com.google.common.base.Throwables.propagate;
27
28
  import static org.eclipse.jetty.http.HttpHeader.AUTHORIZATION;
28
29
  import static org.eclipse.jetty.http.HttpMethod.GET;
29
30
  import static org.eclipse.jetty.http.HttpMethod.POST;
@@ -64,41 +65,47 @@ public class MailChimpRetryable implements AutoCloseable
64
65
 
65
66
  private String sendRequest(final String path, final StringContentProvider contentProvider)
66
67
  {
67
- return retryHelper.requestWithRetry(
68
- new StringJetty92ResponseEntityReader(READER_TIMEOUT_MILLIS),
69
- new Jetty92SingleRequester()
70
- {
71
- @Override
72
- public void requestOnce(HttpClient client, Response.Listener responseListener)
68
+ try {
69
+ return retryHelper.requestWithRetry(
70
+ new StringJetty92ResponseEntityReader(READER_TIMEOUT_MILLIS),
71
+ new Jetty92SingleRequester()
73
72
  {
74
- createTokenHolder(client);
75
- Request request = client.newRequest(tokenHolder.getEndpoint() + path)
76
- .header(AUTHORIZATION, authorizationHeader)
77
- .method(GET);
78
- if (contentProvider != null) {
79
- request = request.method(POST).content(contentProvider);
73
+ @Override
74
+ public void requestOnce(HttpClient client, Response.Listener responseListener)
75
+ {
76
+ createTokenHolder(client);
77
+ Request request = client.newRequest(tokenHolder.getEndpoint() + path)
78
+ .header(AUTHORIZATION, authorizationHeader)
79
+ .method(GET);
80
+ if (contentProvider != null) {
81
+ request = request.method(POST).content(contentProvider);
82
+ }
83
+ request.send(responseListener);
80
84
  }
81
- request.send(responseListener);
82
- }
83
85
 
84
- @Override
85
- protected boolean isResponseStatusToRetry(Response response)
86
- {
87
- // Retry if it's a server or rate limit exceeded error
88
- return (response.getStatus() != 500 && response.getStatus() / 100 != 4) || response.getStatus() == 429;
89
- }
86
+ @Override
87
+ protected boolean isResponseStatusToRetry(Response response)
88
+ {
89
+ // Retry if it's a server or rate limit exceeded error
90
+ return (response.getStatus() != 500 && response.getStatus() / 100 != 4) || response.getStatus() == 429;
91
+ }
90
92
 
91
- @Override
92
- protected boolean isExceptionToRetry(Exception exception)
93
- {
94
- // This check is to make sure if the original exception is retryable, i.e.
95
- // server not found, internal server error...
96
- if (exception instanceof ConfigException || exception instanceof ExecutionException) {
97
- return toRetry((Exception) exception.getCause());
93
+ @Override
94
+ protected boolean isExceptionToRetry(Exception exception)
95
+ {
96
+ // This check is to make sure if the original exception is retryable, i.e.
97
+ // server not found, internal server error...
98
+ if (exception instanceof ConfigException || exception instanceof ExecutionException) {
99
+ return toRetry((Exception) exception.getCause());
100
+ }
101
+ return exception instanceof TimeoutException || super.isExceptionToRetry(exception);
98
102
  }
99
- return exception instanceof TimeoutException || super.isExceptionToRetry(exception);
100
- }
101
- });
103
+ });
104
+ }
105
+ catch (HttpResponseException ex) {
106
+ LOG.error("Unexpected response from request to {}", path, ex);
107
+ throw propagate(ex);
108
+ }
102
109
  }
103
110
 
104
111
  @Override
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: embulk-output-mailchimp
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.25
4
+ version: 0.3.28
5
5
  platform: ruby
6
6
  authors:
7
7
  - Thang Nguyen
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-10-11 00:00:00.000000000 Z
11
+ date: 2018-10-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  requirement: !ruby/object:Gem::Requirement
@@ -89,12 +89,12 @@ files:
89
89
  - test/override_assert_raise.rb
90
90
  - test/run-test.rb
91
91
  - classpath/jetty-io-9.2.14.v20151106.jar
92
- - classpath/embulk-output-mailchimp-0.3.25.jar
93
92
  - classpath/jetty-util-9.2.14.v20151106.jar
94
93
  - classpath/jetty-http-9.2.14.v20151106.jar
95
94
  - classpath/jetty-client-9.2.14.v20151106.jar
96
95
  - classpath/embulk-base-restclient-0.5.3.jar
97
96
  - classpath/embulk-util-retryhelper-jetty92-0.5.3.jar
97
+ - classpath/embulk-output-mailchimp-0.3.28.jar
98
98
  homepage: https://github.com/treasure-data/embulk-output-mailchimp
99
99
  licenses:
100
100
  - MIT