embulk-input-zendesk 0.3.4 → 0.3.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +3 -0
  3. data/README.md +32 -2
  4. data/build.gradle +1 -1
  5. data/src/main/java/org/embulk/input/zendesk/RecordImporter.java +134 -0
  6. data/src/main/java/org/embulk/input/zendesk/ZendeskInputPlugin.java +182 -202
  7. data/src/main/java/org/embulk/input/zendesk/clients/ZendeskRestClient.java +54 -52
  8. data/src/main/java/org/embulk/input/zendesk/models/Target.java +3 -3
  9. data/src/main/java/org/embulk/input/zendesk/models/ZendeskException.java +1 -1
  10. data/src/main/java/org/embulk/input/zendesk/services/ZendeskCustomObjectService.java +110 -0
  11. data/src/main/java/org/embulk/input/zendesk/services/ZendeskNPSService.java +30 -0
  12. data/src/main/java/org/embulk/input/zendesk/services/ZendeskNormalServices.java +239 -0
  13. data/src/main/java/org/embulk/input/zendesk/services/ZendeskService.java +14 -0
  14. data/src/main/java/org/embulk/input/zendesk/services/ZendeskSupportAPIService.java +25 -83
  15. data/src/main/java/org/embulk/input/zendesk/services/ZendeskUserEventService.java +158 -0
  16. data/src/main/java/org/embulk/input/zendesk/stream/PagingSpliterator.java +40 -0
  17. data/src/main/java/org/embulk/input/zendesk/stream/paginator/sunshine/CustomObjectSpliterator.java +42 -0
  18. data/src/main/java/org/embulk/input/zendesk/stream/paginator/sunshine/SunshineSpliterator.java +66 -0
  19. data/src/main/java/org/embulk/input/zendesk/stream/paginator/sunshine/UserEventSpliterator.java +35 -0
  20. data/src/main/java/org/embulk/input/zendesk/stream/paginator/support/OrganizationSpliterator.java +13 -0
  21. data/src/main/java/org/embulk/input/zendesk/stream/paginator/support/SupportSpliterator.java +44 -0
  22. data/src/main/java/org/embulk/input/zendesk/stream/paginator/support/UserSpliterator.java +13 -0
  23. data/src/main/java/org/embulk/input/zendesk/utils/ZendeskConstants.java +13 -1
  24. data/src/main/java/org/embulk/input/zendesk/utils/ZendeskDateUtils.java +22 -11
  25. data/src/main/java/org/embulk/input/zendesk/utils/ZendeskUtils.java +52 -114
  26. data/src/test/java/org/embulk/input/zendesk/TestRecordImporter.java +114 -0
  27. data/src/test/java/org/embulk/input/zendesk/TestZendeskInputPlugin.java +184 -99
  28. data/src/test/java/org/embulk/input/zendesk/clients/TestZendeskRestClient.java +6 -20
  29. data/src/test/java/org/embulk/input/zendesk/services/TestZendeskCustomObjectService.java +161 -0
  30. data/src/test/java/org/embulk/input/zendesk/services/TestZendeskNPSService.java +56 -0
  31. data/src/test/java/org/embulk/input/zendesk/services/TestZendeskNormalService.java +189 -0
  32. data/src/test/java/org/embulk/input/zendesk/services/TestZendeskSupportAPIService.java +18 -60
  33. data/src/test/java/org/embulk/input/zendesk/services/TestZendeskUserEventService.java +158 -0
  34. data/src/test/java/org/embulk/input/zendesk/utils/TestZendeskDateUtils.java +50 -2
  35. data/src/test/java/org/embulk/input/zendesk/utils/TestZendeskUtil.java +0 -138
  36. data/src/test/java/org/embulk/input/zendesk/utils/ZendeskTestHelper.java +16 -0
  37. data/src/test/resources/config/nps.yml +29 -0
  38. data/src/test/resources/config/object_records.yml +24 -0
  39. data/src/test/resources/config/relationship_records.yml +23 -0
  40. data/src/test/resources/config/user_events.yml +29 -0
  41. data/src/test/resources/data/duplicate_user.json +0 -0
  42. data/src/test/resources/data/empty_result.json +7 -0
  43. data/src/test/resources/data/expected/user_events_column.json +40 -0
  44. data/src/test/resources/data/object_records.json +30 -0
  45. data/src/test/resources/data/organization.json +39 -0
  46. data/src/test/resources/data/relationship_records.json +57 -0
  47. data/src/test/resources/data/scores.json +21 -0
  48. data/src/test/resources/data/scores_share_same_time_with_next_page.json +35 -0
  49. data/src/test/resources/data/scores_share_same_time_without_next_page.json +35 -0
  50. data/src/test/resources/data/simple_organization.json +23 -0
  51. data/src/test/resources/data/simple_user.json +50 -0
  52. data/src/test/resources/data/simple_user_event.json +19 -0
  53. data/src/test/resources/data/ticket_events_share_same_time_with_next_page.json +279 -0
  54. data/src/test/resources/data/ticket_events_share_same_time_without_next_page.json +279 -0
  55. data/src/test/resources/data/ticket_events_updated_by_system_records.json +279 -0
  56. data/src/test/resources/data/ticket_share_same_time_with_next_page.json +232 -0
  57. data/src/test/resources/data/ticket_share_same_time_without_next_page.json +232 -0
  58. data/src/test/resources/data/ticket_with_updated_by_system_records.json +187 -0
  59. data/src/test/resources/data/user_event.json +19 -0
  60. data/src/test/resources/data/user_event_contain_latter_create_at.json +19 -0
  61. data/src/test/resources/data/user_event_multiple.json +33 -0
  62. metadata +46 -5
  63. data/src/main/java/org/embulk/input/zendesk/utils/ZendeskValidatorUtils.java +0 -79
  64. data/src/test/java/org/embulk/input/zendesk/utils/TestZendeskValidatorUtils.java +0 -130
@@ -0,0 +1,14 @@
1
+ package org.embulk.input.zendesk.services;
2
+
3
+ import com.fasterxml.jackson.databind.JsonNode;
4
+ import org.embulk.config.TaskReport;
5
+ import org.embulk.input.zendesk.RecordImporter;
6
+
7
+ public interface ZendeskService
8
+ {
9
+ boolean isSupportIncremental();
10
+
11
+ TaskReport addRecordToImporter(int taskIndex, RecordImporter recordImporter);
12
+
13
+ JsonNode getDataFromPath(String path, int page, boolean isPreview, long startTime);
14
+ }
@@ -1,110 +1,52 @@
1
1
  package org.embulk.input.zendesk.services;
2
2
 
3
- import com.fasterxml.jackson.databind.DeserializationFeature;
4
- import com.fasterxml.jackson.databind.JsonNode;
5
- import com.fasterxml.jackson.databind.ObjectMapper;
6
- import com.fasterxml.jackson.databind.node.ObjectNode;
7
- import com.google.common.annotations.VisibleForTesting;
8
- import com.google.common.base.Throwables;
3
+ import org.apache.http.client.utils.URIBuilder;
9
4
  import org.embulk.input.zendesk.ZendeskInputPlugin.PluginTask;
10
- import org.embulk.input.zendesk.clients.ZendeskRestClient;
11
5
  import org.embulk.input.zendesk.models.Target;
12
6
  import org.embulk.input.zendesk.utils.ZendeskConstants;
13
7
  import org.embulk.input.zendesk.utils.ZendeskUtils;
14
- import org.embulk.spi.DataException;
15
8
 
16
- import java.io.IOException;
17
-
18
- public class ZendeskSupportAPIService
9
+ public class ZendeskSupportAPIService extends ZendeskNormalServices
19
10
  {
20
- private ZendeskRestClient zendeskRestClient;
21
-
22
- private PluginTask task;
23
-
24
- private static ObjectMapper mapper = new ObjectMapper();
25
-
26
- static {
27
- mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
28
- mapper.configure(com.fasterxml.jackson.core.JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, false);
29
- }
30
-
31
11
  public ZendeskSupportAPIService(final PluginTask task)
32
12
  {
33
- this.task = task;
13
+ super(task);
34
14
  }
35
15
 
36
- public void setTask(PluginTask task)
16
+ public boolean isSupportIncremental()
37
17
  {
38
- this.task = task;
18
+ return !(task.getTarget().equals(Target.TICKET_FORMS) || task.getTarget().equals(Target.TICKET_FIELDS));
39
19
  }
40
20
 
41
- public JsonNode getData(String path, final int page, final boolean isPreview, long startTime)
21
+ @Override
22
+ protected String buildURI(final int page, long startTime)
42
23
  {
43
- if (path.isEmpty()) {
44
- path = buildPath(page, startTime);
45
- }
46
- try {
47
- final String response = getZendeskRestClient().doGet(path, task, isPreview);
48
- return parseJsonObject(response);
49
- }
50
- catch (final Exception e) {
51
- throw Throwables.propagate(e);
52
- }
53
- }
24
+ final URIBuilder uriBuilder = ZendeskUtils.getURIBuilder(task.getLoginUrl()).setPath(buildPath());
54
25
 
55
- @VisibleForTesting
56
- protected ZendeskRestClient getZendeskRestClient()
57
- {
58
- if (zendeskRestClient == null) {
59
- zendeskRestClient = new ZendeskRestClient();
26
+ if (isSupportIncremental()) {
27
+ uriBuilder.setParameter(ZendeskConstants.Field.START_TIME, String.valueOf(startTime));
28
+ if (Target.TICKET_METRICS.equals(task.getTarget())) {
29
+ uriBuilder.setParameter("include", "metric_sets");
30
+ }
60
31
  }
61
- return zendeskRestClient;
62
- }
63
-
64
- private ObjectNode parseJsonObject(final String jsonText)
65
- {
66
- JsonNode node = parseJsonNode(jsonText);
67
- if (node.isObject()) {
68
- return (ObjectNode) node;
32
+ else {
33
+ uriBuilder.setParameter("sort_by", "id")
34
+ .setParameter("per_page", String.valueOf(100))
35
+ .setParameter("page", String.valueOf(page));
69
36
  }
70
37
 
71
- throw new DataException("Expected object node to parse but doesn't get");
72
- }
73
-
74
- private JsonNode parseJsonNode(final String jsonText)
75
- {
76
- try {
77
- return mapper.readTree(jsonText);
78
- }
79
- catch (final IOException e) {
80
- throw Throwables.propagate(e);
81
- }
38
+ return uriBuilder.toString();
82
39
  }
83
40
 
84
- private String buildPath(final int page, long startTime)
41
+ private String buildPath()
85
42
  {
86
- boolean isSupportIncremental = ZendeskUtils.isSupportAPIIncremental(task.getTarget());
87
-
88
- StringBuilder urlBuilder = new StringBuilder(task.getLoginUrl())
89
- .append("/")
90
- .append(isSupportIncremental
91
- ? ZendeskConstants.Url.API_INCREMENTAL
92
- : ZendeskConstants.Url.API)
93
- .append("/")
94
- .append(Target.TICKET_METRICS.equals(task.getTarget())
43
+ return (isSupportIncremental()
44
+ ? ZendeskConstants.Url.API_INCREMENTAL
45
+ : ZendeskConstants.Url.API) +
46
+ "/" +
47
+ (Target.TICKET_METRICS.equals(task.getTarget())
95
48
  ? Target.TICKETS.toString()
96
49
  : task.getTarget().toString())
97
- .append(".json?");
98
-
99
- urlBuilder
100
- .append(isSupportIncremental
101
- ? "start_time=" + startTime
102
- : "sort_by=id&per_page=100&page=" + page);
103
-
104
- if (Target.TICKET_METRICS.equals(task.getTarget())) {
105
- urlBuilder.append("&include=metric_sets");
106
- }
107
-
108
- return urlBuilder.toString();
50
+ + ".json";
109
51
  }
110
52
  }
@@ -0,0 +1,158 @@
1
+ package org.embulk.input.zendesk.services;
2
+
3
+ import com.fasterxml.jackson.databind.JsonNode;
4
+ import com.fasterxml.jackson.databind.ObjectMapper;
5
+ import com.google.common.annotations.VisibleForTesting;
6
+ import org.apache.http.client.utils.URIBuilder;
7
+ import org.embulk.config.TaskReport;
8
+ import org.embulk.input.zendesk.RecordImporter;
9
+ import org.embulk.input.zendesk.ZendeskInputPlugin;
10
+ import org.embulk.input.zendesk.clients.ZendeskRestClient;
11
+ import org.embulk.input.zendesk.models.Target;
12
+ import org.embulk.input.zendesk.stream.paginator.sunshine.UserEventSpliterator;
13
+ import org.embulk.input.zendesk.stream.paginator.support.OrganizationSpliterator;
14
+ import org.embulk.input.zendesk.stream.paginator.support.UserSpliterator;
15
+ import org.embulk.input.zendesk.utils.ZendeskConstants;
16
+ import org.embulk.input.zendesk.utils.ZendeskDateUtils;
17
+ import org.embulk.input.zendesk.utils.ZendeskUtils;
18
+ import org.embulk.spi.DataException;
19
+ import org.embulk.spi.Exec;
20
+
21
+ import java.io.IOException;
22
+ import java.time.Instant;
23
+ import java.util.List;
24
+ import java.util.Set;
25
+ import java.util.concurrent.ConcurrentHashMap;
26
+ import java.util.stream.Collectors;
27
+ import java.util.stream.Stream;
28
+ import java.util.stream.StreamSupport;
29
+
30
+ public class ZendeskUserEventService implements ZendeskService
31
+ {
32
+ protected ZendeskInputPlugin.PluginTask task;
33
+
34
+ private ZendeskRestClient zendeskRestClient;
35
+
36
+ public ZendeskUserEventService(final ZendeskInputPlugin.PluginTask task)
37
+ {
38
+ this.task = task;
39
+ }
40
+
41
+ public boolean isSupportIncremental()
42
+ {
43
+ return false;
44
+ }
45
+
46
+ @Override
47
+ public TaskReport addRecordToImporter(final int taskIndex, final RecordImporter recordImporter)
48
+ {
49
+ final TaskReport taskReport = Exec.newTaskReport();
50
+
51
+ if (Exec.isPreview()) {
52
+ JsonNode jsonNode = mockJsonNode();
53
+ recordImporter.addRecord(jsonNode.get(0));
54
+ return taskReport;
55
+ }
56
+
57
+ final List<JsonNode> organizations = StreamSupport.stream(new OrganizationSpliterator(buildOrganizationURI(), getZendeskRestClient(), task), false)
58
+ .collect(Collectors.toList());
59
+ final Set<String> knownUserIds = ConcurrentHashMap.newKeySet();
60
+ organizations.parallelStream().forEach(
61
+ organization -> {
62
+ Stream<JsonNode> stream = StreamSupport.stream(new UserSpliterator(buildOrganizationWithUserURI(organization.get("url").asText()),
63
+ getZendeskRestClient(), task, Exec.isPreview()), true);
64
+
65
+ if (task.getDedup()) {
66
+ stream = stream.filter(item -> knownUserIds.add(item.get("id").asText()));
67
+ }
68
+
69
+ stream.forEach(s ->
70
+ {
71
+ Stream<JsonNode> userEventStream = StreamSupport.stream(new UserEventSpliterator(s.get("id").asText(), buildUserEventURI(s.get("id").asText()),
72
+ getZendeskRestClient(), task, Exec.isPreview()), true);
73
+ userEventStream.forEach(recordImporter::addRecord);
74
+ });
75
+ }
76
+ );
77
+ return taskReport;
78
+ }
79
+
80
+ @Override
81
+ public JsonNode getDataFromPath(final String path, final int page, final boolean isPreview, final long startTime)
82
+ {
83
+ return new ObjectMapper().createObjectNode().set(task.getTarget().getJsonName(), mockJsonNode());
84
+ }
85
+
86
+ @VisibleForTesting
87
+ protected ZendeskRestClient getZendeskRestClient()
88
+ {
89
+ if (zendeskRestClient == null) {
90
+ zendeskRestClient = new ZendeskRestClient();
91
+ }
92
+ return zendeskRestClient;
93
+ }
94
+
95
+ private String buildOrganizationURI()
96
+ {
97
+ return ZendeskUtils.getURIBuilder(task.getLoginUrl())
98
+ .setPath(ZendeskConstants.Url.API + "/" + Target.ORGANIZATIONS.getJsonName())
99
+ .setParameter("per_page", "100")
100
+ .setParameter("page", "1")
101
+ .toString();
102
+ }
103
+
104
+ private String buildOrganizationWithUserURI(final String path)
105
+ {
106
+ return path.replace(".json", "")
107
+ + "/users.json?per_page=100&page=1";
108
+ }
109
+
110
+ private String buildUserEventURI(final String userID)
111
+ {
112
+ final URIBuilder uriBuilder = ZendeskUtils.getURIBuilder(task.getLoginUrl())
113
+ .setPath(ZendeskConstants.Url.API_USER_EVENT)
114
+ .setParameter("identifier", task.getProfileSource().get() + ":user_id:" + userID);
115
+
116
+ task.getUserEventSource().ifPresent(eventSource -> uriBuilder.setParameter("source", eventSource));
117
+ task.getUserEventType().ifPresent(eventType -> uriBuilder.setParameter("type", eventType));
118
+ task.getStartTime().ifPresent(startTime -> {
119
+ try {
120
+ uriBuilder.setParameter("start_time", ZendeskDateUtils.convertToDateTimeFormat(startTime, ZendeskConstants.Misc.ISO_INSTANT));
121
+ }
122
+ catch (DataException e) {
123
+ uriBuilder.setParameter("start_time", ZendeskDateUtils.convertToDateTimeFormat(Instant.EPOCH.toString(), ZendeskConstants.Misc.ISO_INSTANT));
124
+ }
125
+ });
126
+
127
+ task.getEndTime().ifPresent(endTime -> uriBuilder.setParameter("end_time", ZendeskDateUtils.convertToDateTimeFormat(endTime, ZendeskConstants.Misc.ISO_INSTANT)));
128
+
129
+ return uriBuilder.toString();
130
+ }
131
+
132
+ private JsonNode mockJsonNode()
133
+ {
134
+ try {
135
+ String mockData = "[\n" +
136
+ " {\n" +
137
+ " \"id\": \"5c7f31aef8df240001e60bbf\",\n" +
138
+ " \"type\": \"remove_from_cart\",\n" +
139
+ " \"source\": \"shopify\",\n" +
140
+ " \"description\": \"\",\n" +
141
+ " \"authenticated\": true,\n" +
142
+ " \"created_at\": \"2019-03-06T02:34:22Z\",\n" +
143
+ " \"received_at\": \"2019-03-06T02:34:22Z\",\n" +
144
+ " \"properties\": {\n" +
145
+ " \"model\": 221,\n" +
146
+ " \"size\": 6\n" +
147
+ " },\n" +
148
+ " \"user_id\": \"12312354234\"\n" +
149
+ " }\n" +
150
+ "]";
151
+
152
+ return new ObjectMapper().readTree(mockData);
153
+ }
154
+ catch (IOException ex) {
155
+ throw new RuntimeException("Can not create sample data " + ex.getMessage());
156
+ }
157
+ }
158
+ }
@@ -0,0 +1,40 @@
1
+ package org.embulk.input.zendesk.stream;
2
+
3
+ import org.embulk.input.zendesk.ZendeskInputPlugin;
4
+ import org.embulk.input.zendesk.clients.ZendeskRestClient;
5
+
6
+ import java.util.Spliterator;
7
+
8
+ public abstract class PagingSpliterator<E> implements Spliterator<E>
9
+ {
10
+ protected ZendeskRestClient zendeskRestClient;
11
+ protected boolean isPreview;
12
+ protected ZendeskInputPlugin.PluginTask task;
13
+ protected String path;
14
+
15
+ protected PagingSpliterator(final String path, final ZendeskRestClient zendeskRestClient, final ZendeskInputPlugin.PluginTask task, final boolean isPreview)
16
+ {
17
+ this.path = path;
18
+ this.zendeskRestClient = zendeskRestClient;
19
+ this.task = task;
20
+ this.isPreview = isPreview;
21
+ }
22
+
23
+ @Override
24
+ public Spliterator<E> trySplit()
25
+ {
26
+ return null;
27
+ }
28
+
29
+ @Override
30
+ public int characteristics()
31
+ {
32
+ return DISTINCT | NONNULL | IMMUTABLE;
33
+ }
34
+
35
+ @Override
36
+ public long estimateSize()
37
+ {
38
+ return Long.MAX_VALUE;
39
+ }
40
+ }
@@ -0,0 +1,42 @@
1
+ package org.embulk.input.zendesk.stream.paginator.sunshine;
2
+
3
+ import com.fasterxml.jackson.databind.JsonNode;
4
+ import org.embulk.input.zendesk.ZendeskInputPlugin;
5
+ import org.embulk.input.zendesk.clients.ZendeskRestClient;
6
+ import org.embulk.input.zendesk.utils.ZendeskUtils;
7
+
8
+ import java.util.Iterator;
9
+ import java.util.function.Consumer;
10
+
11
+ public class CustomObjectSpliterator extends SunshineSpliterator
12
+ {
13
+ public CustomObjectSpliterator(final String path, final ZendeskRestClient zendeskRestClient, final ZendeskInputPlugin.PluginTask task, final boolean isPreview)
14
+ {
15
+ super(path, zendeskRestClient, task, isPreview);
16
+ }
17
+
18
+ @Override
19
+ protected boolean isContinue(final JsonNode jsonNode, final Consumer<? super JsonNode> action)
20
+ {
21
+ final Iterator<JsonNode> iterator = ZendeskUtils.getListRecords(jsonNode, task.getTarget().getJsonName());
22
+
23
+ if (isPreview) {
24
+ if (iterator.hasNext()) {
25
+ JsonNode item = iterator.next();
26
+ // we have data for preview, no need to continue
27
+ if (item != null && !item.isNull()) {
28
+ action.accept(item);
29
+ return false;
30
+ }
31
+ }
32
+ }
33
+ handleRunIterator(iterator, action);
34
+
35
+ if (jsonNode.has("links") && !ZendeskUtils.isNull(jsonNode.get("links"))
36
+ && jsonNode.get("links").has("next") && !ZendeskUtils.isNull(jsonNode.get("links").get("next"))) {
37
+ path = task.getLoginUrl() + jsonNode.get("links").get("next");
38
+ return true;
39
+ }
40
+ return false;
41
+ }
42
+ }
@@ -0,0 +1,66 @@
1
+ package org.embulk.input.zendesk.stream.paginator.sunshine;
2
+
3
+ import com.fasterxml.jackson.databind.JsonNode;
4
+ import org.apache.http.HttpStatus;
5
+ import org.embulk.config.ConfigException;
6
+ import org.embulk.input.zendesk.ZendeskInputPlugin;
7
+ import org.embulk.input.zendesk.clients.ZendeskRestClient;
8
+ import org.embulk.input.zendesk.models.ZendeskException;
9
+ import org.embulk.input.zendesk.stream.PagingSpliterator;
10
+ import org.embulk.input.zendesk.utils.ZendeskUtils;
11
+
12
+ import java.util.Iterator;
13
+ import java.util.function.Consumer;
14
+
15
+ public class SunshineSpliterator extends PagingSpliterator<JsonNode>
16
+ {
17
+ public SunshineSpliterator(final String path, final ZendeskRestClient zendeskRestClient, final ZendeskInputPlugin.PluginTask task, final boolean isPreview)
18
+ {
19
+ super(path, zendeskRestClient, task, isPreview);
20
+ }
21
+
22
+ @Override
23
+ public boolean tryAdvance(final Consumer<? super JsonNode> action)
24
+ {
25
+ try {
26
+ final String result = zendeskRestClient.doGet(path, task, isPreview);
27
+
28
+ if (result != null && !result.isEmpty()) {
29
+ final JsonNode jsonNode = ZendeskUtils.parseJsonObject(result);
30
+ final JsonNode targetJsonNode = jsonNode.get(task.getTarget().getJsonName());
31
+ if (!ZendeskUtils.isNull(targetJsonNode)) {
32
+ return isContinue(jsonNode, action);
33
+ }
34
+ }
35
+ }
36
+ catch (final ConfigException e) {
37
+ if (!(e.getCause() instanceof ZendeskException && ((ZendeskException) e.getCause()).getStatusCode() == HttpStatus.SC_NOT_FOUND)) {
38
+ throw e;
39
+ }
40
+ }
41
+ return false;
42
+ }
43
+
44
+ protected void handleRunIterator(Iterator<JsonNode> iterator, final Consumer<? super JsonNode> action)
45
+ {
46
+ iterator.forEachRemaining(
47
+ item -> {
48
+ if (item != null && !item.isNull()) {
49
+ action.accept(iterator.next());
50
+ }
51
+ });
52
+ }
53
+
54
+ protected boolean isContinue(final JsonNode jsonNode, final Consumer<? super JsonNode> action)
55
+ {
56
+ final Iterator<JsonNode> iterator = ZendeskUtils.getListRecords(jsonNode, task.getTarget().getJsonName());
57
+ handleRunIterator(iterator, action);
58
+
59
+ if (jsonNode.has("links") && !ZendeskUtils.isNull(jsonNode.get("links"))
60
+ && jsonNode.get("links").has("next") && !ZendeskUtils.isNull(jsonNode.get("links").get("next"))) {
61
+ path = task.getLoginUrl() + jsonNode.get("links").get("next");
62
+ return true;
63
+ }
64
+ return false;
65
+ }
66
+ }