embulk-input-zendesk-all 0.3.7

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 (93) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +12 -0
  3. data/.travis.yml +5 -0
  4. data/CHANGELOG.md +126 -0
  5. data/LICENSE.txt +21 -0
  6. data/README.md +91 -0
  7. data/build.gradle +123 -0
  8. data/config/checkstyle/checkstyle.xml +128 -0
  9. data/config/checkstyle/default.xml +108 -0
  10. data/gradle/wrapper/gradle-wrapper.jar +0 -0
  11. data/gradle/wrapper/gradle-wrapper.properties +5 -0
  12. data/gradlew +172 -0
  13. data/gradlew.bat +84 -0
  14. data/lib/embulk/guess/zendesk.rb +21 -0
  15. data/lib/embulk/input/zendesk.rb +3 -0
  16. data/src/main/java/org/embulk/input/zendesk/RecordImporter.java +134 -0
  17. data/src/main/java/org/embulk/input/zendesk/ZendeskInputPlugin.java +513 -0
  18. data/src/main/java/org/embulk/input/zendesk/clients/ZendeskRestClient.java +291 -0
  19. data/src/main/java/org/embulk/input/zendesk/models/AuthenticationMethod.java +23 -0
  20. data/src/main/java/org/embulk/input/zendesk/models/Target.java +47 -0
  21. data/src/main/java/org/embulk/input/zendesk/models/ZendeskException.java +25 -0
  22. data/src/main/java/org/embulk/input/zendesk/services/ZendeskCustomObjectService.java +110 -0
  23. data/src/main/java/org/embulk/input/zendesk/services/ZendeskNPSService.java +30 -0
  24. data/src/main/java/org/embulk/input/zendesk/services/ZendeskNormalServices.java +347 -0
  25. data/src/main/java/org/embulk/input/zendesk/services/ZendeskService.java +14 -0
  26. data/src/main/java/org/embulk/input/zendesk/services/ZendeskSupportAPIService.java +63 -0
  27. data/src/main/java/org/embulk/input/zendesk/services/ZendeskUserEventService.java +158 -0
  28. data/src/main/java/org/embulk/input/zendesk/stream/PagingSpliterator.java +40 -0
  29. data/src/main/java/org/embulk/input/zendesk/stream/paginator/sunshine/CustomObjectSpliterator.java +42 -0
  30. data/src/main/java/org/embulk/input/zendesk/stream/paginator/sunshine/SunshineSpliterator.java +66 -0
  31. data/src/main/java/org/embulk/input/zendesk/stream/paginator/sunshine/UserEventSpliterator.java +35 -0
  32. data/src/main/java/org/embulk/input/zendesk/stream/paginator/support/OrganizationSpliterator.java +13 -0
  33. data/src/main/java/org/embulk/input/zendesk/stream/paginator/support/SupportSpliterator.java +44 -0
  34. data/src/main/java/org/embulk/input/zendesk/stream/paginator/support/UserSpliterator.java +13 -0
  35. data/src/main/java/org/embulk/input/zendesk/utils/ZendeskConstants.java +72 -0
  36. data/src/main/java/org/embulk/input/zendesk/utils/ZendeskDateUtils.java +68 -0
  37. data/src/main/java/org/embulk/input/zendesk/utils/ZendeskUtils.java +92 -0
  38. data/src/test/java/org/embulk/input/zendesk/TestRecordImporter.java +114 -0
  39. data/src/test/java/org/embulk/input/zendesk/TestZendeskInputPlugin.java +402 -0
  40. data/src/test/java/org/embulk/input/zendesk/clients/TestZendeskRestClient.java +337 -0
  41. data/src/test/java/org/embulk/input/zendesk/services/TestZendeskCustomObjectService.java +161 -0
  42. data/src/test/java/org/embulk/input/zendesk/services/TestZendeskNPSService.java +56 -0
  43. data/src/test/java/org/embulk/input/zendesk/services/TestZendeskNormalService.java +261 -0
  44. data/src/test/java/org/embulk/input/zendesk/services/TestZendeskSupportAPIService.java +130 -0
  45. data/src/test/java/org/embulk/input/zendesk/services/TestZendeskUserEventService.java +158 -0
  46. data/src/test/java/org/embulk/input/zendesk/utils/TestZendeskDateUtils.java +87 -0
  47. data/src/test/java/org/embulk/input/zendesk/utils/TestZendeskUtil.java +22 -0
  48. data/src/test/java/org/embulk/input/zendesk/utils/ZendeskPluginTestRuntime.java +133 -0
  49. data/src/test/java/org/embulk/input/zendesk/utils/ZendeskTestHelper.java +92 -0
  50. data/src/test/resources/config/base.yml +14 -0
  51. data/src/test/resources/config/base_validator.yml +48 -0
  52. data/src/test/resources/config/incremental.yml +54 -0
  53. data/src/test/resources/config/non-incremental.yml +39 -0
  54. data/src/test/resources/config/nps.yml +31 -0
  55. data/src/test/resources/config/object_records.yml +24 -0
  56. data/src/test/resources/config/relationship_records.yml +23 -0
  57. data/src/test/resources/config/user_events.yml +29 -0
  58. data/src/test/resources/config/util.yml +18 -0
  59. data/src/test/resources/data/client.json +293 -0
  60. data/src/test/resources/data/duplicate_user.json +0 -0
  61. data/src/test/resources/data/empty_result.json +7 -0
  62. data/src/test/resources/data/error_data.json +187 -0
  63. data/src/test/resources/data/expected/ticket_column.json +148 -0
  64. data/src/test/resources/data/expected/ticket_column_with_related_objects.json +152 -0
  65. data/src/test/resources/data/expected/ticket_fields_column.json +92 -0
  66. data/src/test/resources/data/expected/ticket_metrics_column.json +98 -0
  67. data/src/test/resources/data/expected/user_events_column.json +40 -0
  68. data/src/test/resources/data/object_records.json +30 -0
  69. data/src/test/resources/data/organization.json +39 -0
  70. data/src/test/resources/data/relationship_records.json +57 -0
  71. data/src/test/resources/data/scores.json +21 -0
  72. data/src/test/resources/data/scores_share_same_time_with_next_page.json +35 -0
  73. data/src/test/resources/data/scores_share_same_time_without_next_page.json +35 -0
  74. data/src/test/resources/data/simple_organization.json +23 -0
  75. data/src/test/resources/data/simple_user.json +50 -0
  76. data/src/test/resources/data/simple_user_event.json +19 -0
  77. data/src/test/resources/data/ticket_events_share_same_time_with_next_page.json +279 -0
  78. data/src/test/resources/data/ticket_events_share_same_time_without_next_page.json +279 -0
  79. data/src/test/resources/data/ticket_events_updated_by_system_records.json +279 -0
  80. data/src/test/resources/data/ticket_fields.json +225 -0
  81. data/src/test/resources/data/ticket_metrics.json +397 -0
  82. data/src/test/resources/data/ticket_share_same_time_with_next_page.json +232 -0
  83. data/src/test/resources/data/ticket_share_same_time_without_next_page.json +232 -0
  84. data/src/test/resources/data/ticket_with_related_objects.json +67 -0
  85. data/src/test/resources/data/ticket_with_updated_by_system_records.json +187 -0
  86. data/src/test/resources/data/tickets.json +232 -0
  87. data/src/test/resources/data/tickets_continue.json +52 -0
  88. data/src/test/resources/data/user_event.json +19 -0
  89. data/src/test/resources/data/user_event_contain_latter_create_at.json +19 -0
  90. data/src/test/resources/data/user_event_multiple.json +33 -0
  91. data/src/test/resources/data/util.json +19 -0
  92. data/src/test/resources/data/util_page.json +227 -0
  93. metadata +168 -0
@@ -0,0 +1,30 @@
1
+ package org.embulk.input.zendesk.services;
2
+
3
+ import org.embulk.input.zendesk.ZendeskInputPlugin;
4
+ import org.embulk.input.zendesk.utils.ZendeskConstants;
5
+ import org.embulk.input.zendesk.utils.ZendeskUtils;
6
+
7
+ public class ZendeskNPSService extends ZendeskNormalServices
8
+ {
9
+ public ZendeskNPSService(final ZendeskInputPlugin.PluginTask task)
10
+ {
11
+ super(task);
12
+ }
13
+
14
+ public boolean isSupportIncremental()
15
+ {
16
+ return true;
17
+ }
18
+
19
+ @Override
20
+ protected String buildURI(final int page, final long startTime)
21
+ {
22
+ return ZendeskUtils.getURIBuilder(task.getLoginUrl())
23
+ .setPath(ZendeskConstants.Url.API_NPS_INCREMENTAL
24
+ + "/"
25
+ + task.getTarget().getJsonName()
26
+ + ".json")
27
+ .setParameter(ZendeskConstants.Field.START_TIME, String.valueOf(startTime))
28
+ .toString();
29
+ }
30
+ }
@@ -0,0 +1,347 @@
1
+ package org.embulk.input.zendesk.services;
2
+
3
+ import com.fasterxml.jackson.databind.JsonNode;
4
+ import com.fasterxml.jackson.databind.node.ObjectNode;
5
+ import com.google.common.annotations.VisibleForTesting;
6
+ import com.google.common.base.Throwables;
7
+ import org.apache.http.HttpStatus;
8
+ import org.apache.http.client.utils.URIBuilder;
9
+ import org.embulk.config.ConfigException;
10
+ import org.embulk.config.TaskReport;
11
+ import org.embulk.input.zendesk.RecordImporter;
12
+ import org.embulk.input.zendesk.ZendeskInputPlugin;
13
+ import org.embulk.input.zendesk.clients.ZendeskRestClient;
14
+ import org.embulk.input.zendesk.models.Target;
15
+ import org.embulk.input.zendesk.models.ZendeskException;
16
+ import org.embulk.input.zendesk.utils.ZendeskConstants;
17
+ import org.embulk.input.zendesk.utils.ZendeskDateUtils;
18
+ import org.embulk.input.zendesk.utils.ZendeskUtils;
19
+ import org.embulk.spi.Exec;
20
+ import org.slf4j.Logger;
21
+
22
+ import java.time.Instant;
23
+
24
+ import java.util.Iterator;
25
+ import java.util.Set;
26
+ import java.util.concurrent.ConcurrentHashMap;
27
+ import java.util.concurrent.LinkedBlockingQueue;
28
+ import java.util.concurrent.ThreadPoolExecutor;
29
+ import java.util.concurrent.TimeUnit;
30
+
31
+ public abstract class ZendeskNormalServices implements ZendeskService
32
+ {
33
+ private static final Logger logger = Exec.getLogger(ZendeskNormalServices.class);
34
+
35
+ protected ZendeskInputPlugin.PluginTask task;
36
+
37
+ private ZendeskRestClient zendeskRestClient;
38
+
39
+ protected ZendeskNormalServices(final ZendeskInputPlugin.PluginTask task)
40
+ {
41
+ this.task = task;
42
+ }
43
+
44
+ public TaskReport addRecordToImporter(final int taskIndex, final RecordImporter recordImporter)
45
+ {
46
+ TaskReport taskReport = Exec.newTaskReport();
47
+
48
+ if (isSupportIncremental()) {
49
+ importDataForIncremental(task, recordImporter, taskReport);
50
+ }
51
+ else {
52
+ if(task.getTarget().equals(Target.SATISFACTION_RATINGS)){
53
+ importDataForNonIncremental(task, taskIndex, recordImporter, true);
54
+ }
55
+ else{
56
+ importDataForNonIncremental(task, taskIndex, recordImporter, false);
57
+ }
58
+ }
59
+
60
+ return taskReport;
61
+ }
62
+
63
+ public JsonNode getDataFromPath(String path, final int page, final boolean isPreview, final long startTime)
64
+ {
65
+ if (path.isEmpty()) {
66
+ path = buildURI(page, startTime);
67
+ }
68
+
69
+ final String response = getZendeskRestClient().doGet(path, task, isPreview);
70
+ return ZendeskUtils.parseJsonObject(response);
71
+ }
72
+
73
+ protected abstract String buildURI(int page, long startTime);
74
+
75
+ @VisibleForTesting
76
+ protected ZendeskRestClient getZendeskRestClient()
77
+ {
78
+ if (zendeskRestClient == null) {
79
+ zendeskRestClient = new ZendeskRestClient();
80
+ }
81
+ return zendeskRestClient;
82
+ }
83
+
84
+ private void importDataForIncremental(final ZendeskInputPlugin.PluginTask task, final RecordImporter recordImporter, final TaskReport taskReport)
85
+ {
86
+ long initStartTime = 0;
87
+ long startTime = 0;
88
+ long endTime = Long.MAX_VALUE;
89
+
90
+ if (task.getStartTime().isPresent()) {
91
+ startTime = ZendeskDateUtils.getStartTime(task.getStartTime().get());
92
+ initStartTime = startTime;
93
+ }
94
+
95
+ if (task.getEndTime().isPresent()) {
96
+ endTime = ZendeskDateUtils.isoToEpochSecond(task.getEndTime().get());
97
+ }
98
+
99
+ // For incremental target, we will run in one task but split in multiple threads inside for data deduplication.
100
+ // Run with incremental will contain duplicated data.
101
+ ThreadPoolExecutor pool = null;
102
+ try {
103
+ final Set<String> knownIds = ConcurrentHashMap.newKeySet();
104
+ pool = new ThreadPoolExecutor(
105
+ 10, 100, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<>()
106
+ );
107
+
108
+ long apiEndTime = 0;
109
+ int afterStartTimeIndex = 11;
110
+ while (true) {
111
+ int recordCount = 0;
112
+
113
+ // Page argument isn't used in incremental API so we just set it to 0
114
+ final JsonNode result = getDataFromPath("", 0, false, startTime);
115
+ final Iterator<JsonNode> iterator = ZendeskUtils.getListRecords(result, task.getTarget().getJsonName());
116
+
117
+ if (result.has(ZendeskConstants.Field.END_TIME)){
118
+ apiEndTime = result.get(ZendeskConstants.Field.END_TIME).asLong();
119
+ }
120
+ else{
121
+ if(result.has(ZendeskConstants.Field.NEXT_PAGE)){
122
+ String next_page = result.get(ZendeskConstants.Field.NEXT_PAGE).textValue();
123
+ apiEndTime = Long.parseLong(next_page.substring(next_page.indexOf(ZendeskConstants.Field.START_TIME)+afterStartTimeIndex));
124
+ }
125
+ }
126
+ logger.info("Api END Time = '{}'", apiEndTime);
127
+ int numberOfRecords = 0;
128
+ if (result.has(ZendeskConstants.Field.COUNT)) {
129
+ numberOfRecords = result.get(ZendeskConstants.Field.COUNT).asInt();
130
+ }
131
+
132
+ while (iterator.hasNext()) {
133
+ final JsonNode recordJsonNode = iterator.next();
134
+
135
+ if (isUpdatedBySystem(recordJsonNode, startTime)) {
136
+ continue;
137
+ }
138
+
139
+ // Contain some records that later than end_time. Checked and don't add.
140
+ // Because the api already sorted by updated_at or timestamp for ticket_events, we just need to break no need to check further.
141
+ if (apiEndTime > endTime) {
142
+ long checkedTime = 0;
143
+ if (recordJsonNode.has(ZendeskConstants.Field.UPDATED_AT) && !recordJsonNode.get(ZendeskConstants.Field.UPDATED_AT).isNull()) {
144
+ checkedTime = ZendeskDateUtils.isoToEpochSecond(recordJsonNode.get(ZendeskConstants.Field.UPDATED_AT).textValue());
145
+ }
146
+
147
+ // ticket events is updated by system not user's action so it only has timestamp field
148
+ if (task.getTarget().equals(Target.TICKET_EVENTS) && recordJsonNode.has("timestamp") && !recordJsonNode.get("timestamp").isNull()) {
149
+ checkedTime = recordJsonNode.get("timestamp").asLong();
150
+ }
151
+
152
+ // scores (or response) is only store rated_at time
153
+ if (task.getTarget().equals(Target.SCORES) && recordJsonNode.has("rated_at") && !recordJsonNode.get("rated_at").isNull()) {
154
+ checkedTime = ZendeskDateUtils.isoToEpochSecond(recordJsonNode.get("rated_at").textValue());
155
+ }
156
+
157
+ if (checkedTime > endTime) {
158
+ break;
159
+ }
160
+ }
161
+
162
+ if (task.getDedup()) {
163
+ final String recordID = recordJsonNode.get(ZendeskConstants.Field.ID).asText();
164
+
165
+ // add success -> no duplicate
166
+ if (!knownIds.add(recordID)) {
167
+ continue;
168
+ }
169
+ }
170
+
171
+ pool.submit(() -> fetchSubResourceAndAddToImporter(recordJsonNode, task, recordImporter));
172
+ recordCount++;
173
+ if (Exec.isPreview()) {
174
+ return;
175
+ }
176
+ }
177
+
178
+ logger.info("Fetched '{}' records from start_time '{}'", recordCount, startTime);
179
+
180
+ // https://developer.zendesk.com/rest_api/docs/support/incremental_export#pagination
181
+ // When there are more than 1000 records share the same time stamp, the count > 1000
182
+ startTime = startTime == apiEndTime
183
+ ? apiEndTime + 1
184
+ : apiEndTime;
185
+
186
+ if (numberOfRecords < ZendeskConstants.Misc.MAXIMUM_RECORDS_INCREMENTAL || startTime > endTime) {
187
+ break;
188
+ }
189
+ }
190
+
191
+ if (!Exec.isPreview()) {
192
+ storeStartTimeForConfigDiff(taskReport, initStartTime, startTime);
193
+ }
194
+ }
195
+ finally {
196
+ if (pool != null) {
197
+ pool.shutdown();
198
+ try {
199
+ pool.awaitTermination(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
200
+ }
201
+ catch (final InterruptedException e) {
202
+ logger.warn("Error when wait pool to finish");
203
+ throw Throwables.propagate(e);
204
+ }
205
+ }
206
+ }
207
+ }
208
+
209
+ private void storeStartTimeForConfigDiff(final TaskReport taskReport, final long initStartTime, final long resultEndTime)
210
+ {
211
+ if (task.getIncremental()) {
212
+ long nextStartTime;
213
+ long now = Instant.now().getEpochSecond();
214
+ // no record to add
215
+ if (resultEndTime == 0) {
216
+ nextStartTime = now;
217
+ }
218
+ else {
219
+ if (task.getEndTime().isPresent()) {
220
+ long endTime = ZendeskDateUtils.isoToEpochSecond(task.getEndTime().get());
221
+ nextStartTime = endTime + 1;
222
+ }
223
+ else {
224
+ // NOTE: start_time compared as "=>", not ">".
225
+ // If we will use end_time for next start_time, we got the same records that are fetched
226
+ // end_time + 1 is workaround for that
227
+ nextStartTime = resultEndTime + 1;
228
+ }
229
+ }
230
+
231
+ if (task.getEndTime().isPresent()) {
232
+ long endTime = ZendeskDateUtils.isoToEpochSecond(task.getEndTime().get());
233
+ taskReport.set(ZendeskConstants.Field.END_TIME, nextStartTime + endTime - initStartTime);
234
+ }
235
+
236
+ taskReport.set(ZendeskConstants.Field.START_TIME, nextStartTime);
237
+ }
238
+ }
239
+
240
+ private void fetchSubResourceAndAddToImporter(final JsonNode jsonNode, final ZendeskInputPlugin.PluginTask task, final RecordImporter recordImporter)
241
+ {
242
+ task.getIncludes().forEach(include -> {
243
+ final String relatedObjectName = include.trim();
244
+
245
+ final URIBuilder uriBuilder = ZendeskUtils.getURIBuilder(task.getLoginUrl())
246
+ .setPath(ZendeskConstants.Url.API
247
+ + "/" + task.getTarget().toString()
248
+ + "/" + jsonNode.get(ZendeskConstants.Field.ID).asText()
249
+ + "/" + relatedObjectName + ".json");
250
+ try {
251
+ final JsonNode result = getDataFromPath(uriBuilder.toString(), 0, false, 0);
252
+ if (result != null && result.has(relatedObjectName)) {
253
+ ((ObjectNode) jsonNode).set(include, result.get(relatedObjectName));
254
+ }
255
+ }
256
+ catch (final ConfigException e) {
257
+ // Sometimes we get 404 when having invalid endpoint, so ignore when we get 404 InvalidEndpoint
258
+ if (!(e.getCause() instanceof ZendeskException && ((ZendeskException) e.getCause()).getStatusCode() == HttpStatus.SC_NOT_FOUND)) {
259
+ throw e;
260
+ }
261
+ }
262
+ });
263
+
264
+ recordImporter.addRecord(jsonNode);
265
+ }
266
+
267
+ private boolean isUpdatedBySystem(final JsonNode recordJsonNode, final long startTime)
268
+ {
269
+ /*
270
+ * https://developer.zendesk.com/rest_api/docs/core/incremental_export#excluding-system-updates
271
+ * "generated_timestamp" will be updated when Zendesk internal changing
272
+ * "updated_at" will be updated when ticket data was changed
273
+ * start_time for query parameter will be processed on Zendesk with generated_timestamp,
274
+ * but it was calculated by record' updated_at time.
275
+ * So the doesn't changed record from previous import would be appear by Zendesk internal changes.
276
+ */
277
+ if (recordJsonNode.has(ZendeskConstants.Field.GENERATED_TIMESTAMP) && recordJsonNode.has(ZendeskConstants.Field.UPDATED_AT)) {
278
+ final String recordUpdatedAtTime = recordJsonNode.get(ZendeskConstants.Field.UPDATED_AT).asText();
279
+ final long recordUpdatedAtToEpochSecond = ZendeskDateUtils.isoToEpochSecond(recordUpdatedAtTime);
280
+
281
+ return recordUpdatedAtToEpochSecond <= startTime;
282
+ }
283
+
284
+ return false;
285
+ }
286
+
287
+ private void importDataForNonIncremental(final ZendeskInputPlugin.PluginTask task, final int taskIndex, RecordImporter recordImporter, final boolean getStartDate)
288
+ {
289
+ long startTime = 0;
290
+
291
+ if (Target.SATISFACTION_RATINGS.equals(task.getTarget())){
292
+ if (getStartDate && task.getStartTime().isPresent()) {
293
+ startTime = ZendeskDateUtils.getStartTime(task.getStartTime().get());
294
+ }
295
+ logger.info("Start time = {}", startTime);
296
+
297
+ int i = 1;
298
+ final Set<String> knownIds = ConcurrentHashMap.newKeySet();
299
+ while (true) {
300
+ final JsonNode result = getDataFromPath("", taskIndex +i, false, startTime);
301
+ final Iterator<JsonNode> iterator = ZendeskUtils.getListRecords(result, task.getTarget().getJsonName());
302
+ while (iterator.hasNext()) {
303
+ final JsonNode recordJsonNode = iterator.next();
304
+
305
+ if (task.getDedup()) {
306
+ final String recordID = recordJsonNode.get(ZendeskConstants.Field.ID).asText();
307
+
308
+ // add success -> no duplicate
309
+ if (!knownIds.add(recordID)) {
310
+ continue;
311
+ }
312
+ }
313
+ fetchSubResourceAndAddToImporter(recordJsonNode, task, recordImporter);
314
+
315
+ if (Exec.isPreview()) {
316
+ break;
317
+ }
318
+ }
319
+
320
+ i++;
321
+ if(result.has(ZendeskConstants.Field.NEXT_PAGE)){
322
+ String next_page = result.get(ZendeskConstants.Field.NEXT_PAGE).textValue();
323
+ if (next_page == null){
324
+ logger.info("No next page exists. Exiting...");
325
+ return;
326
+ }
327
+ logger.info("Next page = {}", next_page);
328
+ }
329
+ }
330
+
331
+ }
332
+ else{
333
+
334
+ // Page start from 1 => page = taskIndex + 1
335
+ final JsonNode result = getDataFromPath("", taskIndex + 1 , false, 0);
336
+ final Iterator<JsonNode> iterator = ZendeskUtils.getListRecords(result, task.getTarget().getJsonName());
337
+ while (iterator.hasNext()) {
338
+ fetchSubResourceAndAddToImporter(iterator.next(), task, recordImporter);
339
+
340
+ if (Exec.isPreview()) {
341
+ break;
342
+ }
343
+ }
344
+ }
345
+
346
+ }
347
+ }
@@ -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
+ }
@@ -0,0 +1,63 @@
1
+ package org.embulk.input.zendesk.services;
2
+
3
+ import org.apache.http.client.utils.URIBuilder;
4
+ import org.embulk.input.zendesk.ZendeskInputPlugin.PluginTask;
5
+ import org.embulk.input.zendesk.models.Target;
6
+ import org.embulk.input.zendesk.utils.ZendeskConstants;
7
+ import org.embulk.input.zendesk.utils.ZendeskUtils;
8
+
9
+ public class ZendeskSupportAPIService extends ZendeskNormalServices
10
+ {
11
+ public ZendeskSupportAPIService(final PluginTask task)
12
+ {
13
+ super(task);
14
+ }
15
+
16
+ public boolean isSupportIncremental()
17
+ {
18
+ return !(task.getTarget().equals(Target.TICKET_FORMS)
19
+ || task.getTarget().equals(Target.TICKET_FIELDS)
20
+ || task.getTarget().equals(Target.SATISFACTION_RATINGS));
21
+ }
22
+
23
+ @Override
24
+ protected String buildURI(final int page, long startTime)
25
+ {
26
+ final URIBuilder uriBuilder = ZendeskUtils.getURIBuilder(task.getLoginUrl()).setPath(buildPath());
27
+
28
+ if (isSupportIncremental()) {
29
+ uriBuilder.setParameter(ZendeskConstants.Field.START_TIME, String.valueOf(startTime));
30
+ if (Target.TICKET_METRICS.equals(task.getTarget())) {
31
+ uriBuilder.setParameter("include", "metric_sets");
32
+ }
33
+ }
34
+ else {
35
+ if (Target.SATISFACTION_RATINGS.equals(task.getTarget())){
36
+ uriBuilder.setParameter(ZendeskConstants.Field.START_TIME, String.valueOf(startTime))
37
+ .setParameter("sort_by", "id")
38
+ .setParameter("per_page", String.valueOf(100))
39
+ .setParameter("page", String.valueOf(page));
40
+
41
+ }
42
+ else{
43
+ uriBuilder.setParameter("sort_by", "id")
44
+ .setParameter("per_page", String.valueOf(100))
45
+ .setParameter("page", String.valueOf(page));
46
+ }
47
+ }
48
+
49
+ return uriBuilder.toString();
50
+ }
51
+
52
+ private String buildPath()
53
+ {
54
+ return (isSupportIncremental() && !(Target.SATISFACTION_RATINGS.equals(task.getTarget()))
55
+ ? ZendeskConstants.Url.API_INCREMENTAL
56
+ : ZendeskConstants.Url.API) +
57
+ "/" +
58
+ (Target.TICKET_METRICS.equals(task.getTarget())
59
+ ? Target.TICKETS.toString()
60
+ : task.getTarget().toString())
61
+ + ".json";
62
+ }
63
+ }