Panagiotis Triantafyllou

questionnaire part3

...@@ -72,7 +72,7 @@ public class User implements Parcelable, Serializable { ...@@ -72,7 +72,7 @@ public class User implements Parcelable, Serializable {
72 private String msisdn; 72 private String msisdn;
73 private String profileMetadata; 73 private String profileMetadata;
74 private Questionnaire questionnaire; 74 private Questionnaire questionnaire;
75 - private JSONObject questionnaireAnswers; 75 + private ArrayList<QuestionnaireAnswer> questionnaireAnswers;
76 private JSONObject userAnswers; 76 private JSONObject userAnswers;
77 private String userId; 77 private String userId;
78 private JSONArray userSegments; 78 private JSONArray userSegments;
...@@ -128,7 +128,18 @@ public class User implements Parcelable, Serializable { ...@@ -128,7 +128,18 @@ public class User implements Parcelable, Serializable {
128 this.msisdn = optNullableString(json, MSISDN); 128 this.msisdn = optNullableString(json, MSISDN);
129 this.profileMetadata = optNullableString(json, PROFILE_METADATA); 129 this.profileMetadata = optNullableString(json, PROFILE_METADATA);
130 this.questionnaire = json.isNull(QUESTIONNAIRE) ? null : new Questionnaire(json.optJSONObject(QUESTIONNAIRE)); 130 this.questionnaire = json.isNull(QUESTIONNAIRE) ? null : new Questionnaire(json.optJSONObject(QUESTIONNAIRE));
131 - this.questionnaireAnswers = json.optJSONObject(QUESTIONNAIRE_ANSWERS); 131 + JSONArray answersArr = json.optJSONArray(QUESTIONNAIRE_ANSWERS);
132 + if (answersArr != null) {
133 + this.questionnaireAnswers = new ArrayList<>();
134 + for (int i = 0; i < answersArr.length(); i++) {
135 + JSONObject answerJson = answersArr.optJSONObject(i);
136 + if (answerJson != null) {
137 + this.questionnaireAnswers.add(new QuestionnaireAnswer(answerJson));
138 + }
139 + }
140 + } else {
141 + this.questionnaireAnswers = null;
142 + }
132 this.userAnswers = json.optJSONObject(USER_ANSWERS); 143 this.userAnswers = json.optJSONObject(USER_ANSWERS);
133 this.userId = optNullableString(json, USER_ID); 144 this.userId = optNullableString(json, USER_ID);
134 this.userSegments = json.optJSONArray(USER_SEGMENTS); 145 this.userSegments = json.optJSONArray(USER_SEGMENTS);
...@@ -164,7 +175,18 @@ public class User implements Parcelable, Serializable { ...@@ -164,7 +175,18 @@ public class User implements Parcelable, Serializable {
164 } 175 }
165 try { 176 try {
166 String questionnaireAnswersStr = source.readString(); 177 String questionnaireAnswersStr = source.readString();
167 - this.questionnaireAnswers = questionnaireAnswersStr != null ? new JSONObject(questionnaireAnswersStr) : null; 178 + if (questionnaireAnswersStr != null) {
179 + this.questionnaireAnswers = new ArrayList<>();
180 + JSONArray answersArr = new JSONArray(questionnaireAnswersStr);
181 + for (int i = 0; i < answersArr.length(); i++) {
182 + JSONObject answerJson = answersArr.optJSONObject(i);
183 + if (answerJson != null) {
184 + this.questionnaireAnswers.add(new QuestionnaireAnswer(answerJson));
185 + }
186 + }
187 + } else {
188 + this.questionnaireAnswers = null;
189 + }
168 } catch (JSONException e) { 190 } catch (JSONException e) {
169 this.questionnaireAnswers = null; 191 this.questionnaireAnswers = null;
170 } 192 }
...@@ -194,7 +216,15 @@ public class User implements Parcelable, Serializable { ...@@ -194,7 +216,15 @@ public class User implements Parcelable, Serializable {
194 dest.writeString(this.consumerMetadata != null ? this.consumerMetadata.toString() : null); 216 dest.writeString(this.consumerMetadata != null ? this.consumerMetadata.toString() : null);
195 dest.writeString(this.favoriteCouponsets != null ? this.favoriteCouponsets.toString() : null); 217 dest.writeString(this.favoriteCouponsets != null ? this.favoriteCouponsets.toString() : null);
196 dest.writeString(this.questionnaire != null ? this.questionnaire.toString() : null); 218 dest.writeString(this.questionnaire != null ? this.questionnaire.toString() : null);
197 - dest.writeString(this.questionnaireAnswers != null ? this.questionnaireAnswers.toString() : null); 219 + if (this.questionnaireAnswers != null) {
220 + JSONArray answersArr = new JSONArray();
221 + for (QuestionnaireAnswer qa : this.questionnaireAnswers) {
222 + answersArr.put(qa.toJSONObject());
223 + }
224 + dest.writeString(answersArr.toString());
225 + } else {
226 + dest.writeString(null);
227 + }
198 dest.writeString(this.userAnswers != null ? this.userAnswers.toString() : null); 228 dest.writeString(this.userAnswers != null ? this.userAnswers.toString() : null);
199 dest.writeString(this.userSegments != null ? this.userSegments.toString() : null); 229 dest.writeString(this.userSegments != null ? this.userSegments.toString() : null);
200 } 230 }
...@@ -215,7 +245,15 @@ public class User implements Parcelable, Serializable { ...@@ -215,7 +245,15 @@ public class User implements Parcelable, Serializable {
215 jObj.put(MSISDN, this.msisdn != null ? this.msisdn : JSONObject.NULL); 245 jObj.put(MSISDN, this.msisdn != null ? this.msisdn : JSONObject.NULL);
216 jObj.put(PROFILE_METADATA, this.profileMetadata != null ? this.profileMetadata : JSONObject.NULL); 246 jObj.put(PROFILE_METADATA, this.profileMetadata != null ? this.profileMetadata : JSONObject.NULL);
217 jObj.put(QUESTIONNAIRE, this.questionnaire != null ? this.questionnaire.toJSONObject() : JSONObject.NULL); 247 jObj.put(QUESTIONNAIRE, this.questionnaire != null ? this.questionnaire.toJSONObject() : JSONObject.NULL);
218 - jObj.put(QUESTIONNAIRE_ANSWERS, this.questionnaireAnswers != null ? this.questionnaireAnswers : JSONObject.NULL); 248 + if (this.questionnaireAnswers != null) {
249 + JSONArray answersArr = new JSONArray();
250 + for (QuestionnaireAnswer qa : this.questionnaireAnswers) {
251 + answersArr.put(qa.toJSONObject());
252 + }
253 + jObj.put(QUESTIONNAIRE_ANSWERS, answersArr);
254 + } else {
255 + jObj.put(QUESTIONNAIRE_ANSWERS, JSONObject.NULL);
256 + }
219 jObj.put(USER_ANSWERS, this.userAnswers != null ? this.userAnswers : JSONObject.NULL); 257 jObj.put(USER_ANSWERS, this.userAnswers != null ? this.userAnswers : JSONObject.NULL);
220 jObj.put(USER_ID, this.userId != null ? this.userId : JSONObject.NULL); 258 jObj.put(USER_ID, this.userId != null ? this.userId : JSONObject.NULL);
221 jObj.put(USER_SEGMENTS, this.userSegments != null ? this.userSegments : JSONObject.NULL); 259 jObj.put(USER_SEGMENTS, this.userSegments != null ? this.userSegments : JSONObject.NULL);
...@@ -312,7 +350,7 @@ public class User implements Parcelable, Serializable { ...@@ -312,7 +350,7 @@ public class User implements Parcelable, Serializable {
312 return questionnaire; 350 return questionnaire;
313 } 351 }
314 352
315 - public JSONObject getQuestionnaireAnswers() { 353 + public ArrayList<QuestionnaireAnswer> getQuestionnaireAnswers() {
316 return questionnaireAnswers; 354 return questionnaireAnswers;
317 } 355 }
318 356
...@@ -372,7 +410,7 @@ public class User implements Parcelable, Serializable { ...@@ -372,7 +410,7 @@ public class User implements Parcelable, Serializable {
372 this.questionnaire = questionnaire; 410 this.questionnaire = questionnaire;
373 } 411 }
374 412
375 - public void setQuestionnaireAnswers(JSONObject questionnaireAnswers) { 413 + public void setQuestionnaireAnswers(ArrayList<QuestionnaireAnswer> questionnaireAnswers) {
376 this.questionnaireAnswers = questionnaireAnswers; 414 this.questionnaireAnswers = questionnaireAnswers;
377 } 415 }
378 416
...@@ -417,6 +455,108 @@ public class User implements Parcelable, Serializable { ...@@ -417,6 +455,108 @@ public class User implements Parcelable, Serializable {
417 return listData; 455 return listData;
418 } 456 }
419 457
458 + public static class QuestionnaireAnswer implements Parcelable, Serializable {
459 + private int questionId;
460 + private JSONArray answer; // Stored as JSONArray internally for uniformity
461 + private int version;
462 + private boolean isSingleAnswer; // Tracks original format for serialization
463 +
464 + public QuestionnaireAnswer() {}
465 +
466 + public QuestionnaireAnswer(JSONObject json) {
467 + if (json != null) {
468 + this.questionId = json.optInt("question_id", -1);
469 + this.version = json.optInt("version", 0);
470 + Object rawAnswer = json.opt("answer");
471 + if (rawAnswer instanceof JSONArray) {
472 + this.answer = (JSONArray) rawAnswer;
473 + this.isSingleAnswer = false;
474 + } else {
475 + // Single string answer — wrap into JSONArray for uniformity
476 + this.answer = new JSONArray();
477 + this.answer.put(rawAnswer != null ? rawAnswer.toString() : "");
478 + this.isSingleAnswer = true;
479 + }
480 + }
481 + }
482 +
483 + protected QuestionnaireAnswer(Parcel in) {
484 + questionId = in.readInt();
485 + version = in.readInt();
486 + isSingleAnswer = in.readByte() != 0;
487 + try {
488 + String answerStr = in.readString();
489 + answer = answerStr != null ? new JSONArray(answerStr) : null;
490 + } catch (JSONException e) {
491 + answer = null;
492 + }
493 + }
494 +
495 + @Override
496 + public void writeToParcel(Parcel dest, int flags) {
497 + dest.writeInt(questionId);
498 + dest.writeInt(version);
499 + dest.writeByte((byte) (isSingleAnswer ? 1 : 0));
500 + dest.writeString(answer != null ? answer.toString() : null);
501 + }
502 +
503 + @Override
504 + public int describeContents() {
505 + return 0;
506 + }
507 +
508 + public static final Creator<QuestionnaireAnswer> CREATOR = new Creator<QuestionnaireAnswer>() {
509 + @Override
510 + public QuestionnaireAnswer createFromParcel(Parcel in) {
511 + return new QuestionnaireAnswer(in);
512 + }
513 +
514 + @Override
515 + public QuestionnaireAnswer[] newArray(int size) {
516 + return new QuestionnaireAnswer[size];
517 + }
518 + };
519 +
520 + public JSONObject toJSONObject() {
521 + JSONObject jObj = new JSONObject();
522 + try {
523 + jObj.put("question_id", this.questionId);
524 + jObj.put("version", this.version);
525 + // Serialize back to original format
526 + if (this.isSingleAnswer && this.answer != null && this.answer.length() > 0) {
527 + jObj.put("answer", this.answer.optString(0));
528 + } else {
529 + jObj.put("answer", this.answer != null ? this.answer : JSONObject.NULL);
530 + }
531 + } catch (JSONException e) {
532 + if (WarpConstants.DEBUG) e.printStackTrace();
533 + }
534 + return jObj;
535 + }
536 +
537 + public int getQuestionId() { return questionId; }
538 + public void setQuestionId(int questionId) { this.questionId = questionId; }
539 + public JSONArray getAnswer() { return answer; }
540 + public void setAnswer(JSONArray answer) { this.answer = answer; }
541 + public boolean isSingleAnswer() { return isSingleAnswer; }
542 + public void setSingleAnswer(boolean singleAnswer) { isSingleAnswer = singleAnswer; }
543 + public int getVersion() { return version; }
544 + public void setVersion(int version) { this.version = version; }
545 +
546 + /**
547 + * Convenience method to get the answer as a list of strings.
548 + */
549 + public ArrayList<String> getAnswerList() {
550 + ArrayList<String> list = new ArrayList<>();
551 + if (answer != null) {
552 + for (int i = 0; i < answer.length(); i++) {
553 + list.add(answer.optString(i));
554 + }
555 + }
556 + return list;
557 + }
558 + }
559 +
420 public static class Questionnaire implements Parcelable, Serializable { 560 public static class Questionnaire implements Parcelable, Serializable {
421 private String questionnaireId; 561 private String questionnaireId;
422 private ArrayList<Question> questions; 562 private ArrayList<Question> questions;
......
...@@ -204,6 +204,18 @@ public interface ApiService { ...@@ -204,6 +204,18 @@ public interface ApiService {
204 @Header(WarpConstants.HEADER_SIGNATURE) String signature, 204 @Header(WarpConstants.HEADER_SIGNATURE) String signature,
205 @Header(WarpConstants.HEADER_AUTHORIZATION) String bearer); 205 @Header(WarpConstants.HEADER_AUTHORIZATION) String bearer);
206 206
207 + @Headers("Content-Type: application/json")
208 + @POST("/oauth/{appUuid}/context")
209 + Call<ResponseBody> saveQuestionnaire(@Path("appUuid") String appUuid,
210 + @Body RequestBody request,
211 + @Header(WarpConstants.HEADER_DATE) String timeStamp,
212 + @Header(WarpConstants.HEADER_LOYALTY_BUNDLE_ID) String bundleId,
213 + @Header(WarpConstants.HEADER_UNIQUE_DEVICE_ID) String deviceId,
214 + @Header(WarpConstants.HEADER_CHANNEL) String channel,
215 + @Header(WarpConstants.HEADER_WEB_ID) String webId,
216 + @Header(WarpConstants.HEADER_SIGNATURE) String signature,
217 + @Header(WarpConstants.HEADER_AUTHORIZATION) String bearer);
218 +
207 // =========================================================== 219 // ===========================================================
208 // Getter & Setter 220 // Getter & Setter
209 // =========================================================== 221 // ===========================================================
......
...@@ -1549,4 +1549,112 @@ public class WarplyManager { ...@@ -1549,4 +1549,112 @@ public class WarplyManager {
1549 }); 1549 });
1550 return future; 1550 return future;
1551 } 1551 }
1552 +
1553 + public static void saveQuestionnaire(ArrayList<User.QuestionnaireAnswer> answers, String questionnaireId, final CallbackReceiver<JSONObject> receiver) {
1554 + WarpUtils.log("************* WARPLY Questionnaire Request ********************");
1555 + WarpUtils.log("[WARP Trace] WARPLY Questionnaire Request is active");
1556 + WarpUtils.log("**************************************************");
1557 +
1558 + ApiService service = ApiClient.getRetrofitInstance().create(ApiService.class);
1559 + ListeningExecutorService executorService = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(1));
1560 +
1561 + ListenableFuture<JSONObject> futureFilters = saveQuestionnaireRetro(answers, questionnaireId, service);
1562 +
1563 + ListenableFuture<List<Object>> allResultsFuture = Futures.allAsList(futureFilters);
1564 + ListenableFuture<JSONObject> mergedResultFuture = Futures.transformAsync(allResultsFuture, results -> {
1565 + JSONObject resultFilters = (JSONObject) results.get(0);
1566 + return executorService.submit(() -> resultFilters);
1567 + }, executorService);
1568 +
1569 + Futures.addCallback(mergedResultFuture, new FutureCallback<JSONObject>() {
1570 + @Override
1571 + public void onSuccess(JSONObject mergedResult) {
1572 + executorService.shutdownNow();
1573 + new Handler(Looper.getMainLooper()).post(() -> receiver.onSuccess(mergedResult));
1574 + }
1575 +
1576 + @Override
1577 + public void onFailure(Throwable throwable) {
1578 + executorService.shutdownNow();
1579 + new Handler(Looper.getMainLooper()).post(() -> receiver.onFailure(2));
1580 + }
1581 + }, executorService);
1582 + }
1583 +
1584 + private static ListenableFuture<JSONObject> saveQuestionnaireRetro(ArrayList<User.QuestionnaireAnswer> answers, String questionnaireId, ApiService service) {
1585 + SettableFuture<JSONObject> future = SettableFuture.create();
1586 +
1587 + String timeStamp = DateFormat.format("yyyy-MM-dd hh:mm:ss", System.currentTimeMillis()).toString();
1588 + String apiKey = WarpUtils.getApiKey(Warply.getWarplyContext());
1589 + String webId = WarpUtils.getWebId(Warply.getWarplyContext());
1590 +
1591 + // Serialize answers list to JSONArray using toJSONObject() on each element
1592 + JSONArray answersJsonArray = new JSONArray();
1593 + for (User.QuestionnaireAnswer answer : answers) {
1594 + answersJsonArray.put(answer.toJSONObject());
1595 + }
1596 +
1597 + Map<String, Object> jsonParamsDetails = new ArrayMap<>();
1598 + Map<String, Object> jsonParams = new ArrayMap<>();
1599 + jsonParams.put("action", "handle_user_details");
1600 + jsonParams.put("process", "questionnaire");
1601 + jsonParams.put("del_empty", false);
1602 + Map<String, Object> jsonParamsQuestionnaireAnswers = new ArrayMap<>();
1603 + jsonParamsQuestionnaireAnswers.put("questionnaire_answers", answersJsonArray);
1604 + jsonParamsQuestionnaireAnswers.put("questionnaire_id", questionnaireId);
1605 + jsonParamsQuestionnaireAnswers.put("first_write", false);
1606 + jsonParams.put("data", jsonParamsQuestionnaireAnswers);
1607 + jsonParamsDetails.put("consumer_data", jsonParams);
1608 +
1609 + RequestBody detailsRequest = RequestBody.create(MediaType.get("application/json; charset=utf-8"), (new JSONObject(jsonParamsDetails)).toString());
1610 + Call<ResponseBody> detailsCall = service.saveQuestionnaire(
1611 + WarplyProperty.getAppUuid(Warply.getWarplyContext()),
1612 + detailsRequest,
1613 + timeStamp,
1614 + "android:" + Warply.getWarplyContext().getPackageName(),
1615 + new WarplyDeviceInfoCollector(Warply.getWarplyContext()).getUniqueDeviceId(),
1616 + "mobile",
1617 + webId,
1618 + WarpUtils.produceSignature(apiKey + timeStamp),
1619 + "Bearer " + WarplyDBHelper.getInstance(Warply.getWarplyContext()).getAuthValue("access_token")
1620 + );
1621 + detailsCall.enqueue(new Callback<ResponseBody>() {
1622 + @Override
1623 + public void onResponse(@NonNull Call<ResponseBody> call, @NonNull Response<ResponseBody> response) {
1624 + if (response.code() == 200 && response.body() != null) {
1625 + JSONObject jobjDetailsResponse = null;
1626 + try {
1627 + jobjDetailsResponse = new JSONObject(response.body().string());
1628 + } catch (Exception e) {
1629 + e.printStackTrace();
1630 + }
1631 + if (jobjDetailsResponse != null && jobjDetailsResponse.has("status") && jobjDetailsResponse.optString("status", "2").equals("1")) {
1632 + JSONObject newResult = new JSONObject();
1633 + try {
1634 + newResult.putOpt("status", 1);
1635 + newResult.putOpt("message", "Success");
1636 + future.set(newResult);
1637 + } catch (JSONException e) {
1638 + e.printStackTrace();
1639 + future.set(new JSONObject());
1640 + }
1641 + } else {
1642 + future.set(new JSONObject());
1643 + }
1644 + } else if (String.valueOf(response.code()).startsWith("5")) {
1645 + future.set(new JSONObject());
1646 + } else {
1647 +// future.set(new CouponsetsList());
1648 + future.setException(new Throwable());
1649 + }
1650 + }
1651 +
1652 + @Override
1653 + public void onFailure(@NonNull Call<ResponseBody> call, @NonNull Throwable t) {
1654 +// future.set(new CouponsetsList());
1655 + future.setException(new Throwable());
1656 + }
1657 + });
1658 + return future;
1659 + }
1552 } 1660 }
......