/* * Copyright (C) 2010-2016 Stichting Akvo (Akvo Foundation) * * This file is part of Akvo FLOW. * * Akvo FLOW is free software: you can redistribute it and modify it under the terms of * the GNU Affero General Public License (AGPL) as published by the Free Software Foundation, * either version 3 of the License or any later version. * * Akvo FLOW is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Affero General Public License included below for more details. * * The full license text can also be seen at <http://www.gnu.org/licenses/agpl.html>. */ package org.waterforpeople.mapping.app.web; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.akvo.flow.domain.DataUtils; import org.codehaus.jackson.map.ObjectMapper; import org.waterforpeople.mapping.app.web.dto.SurveyInstanceDto; import org.waterforpeople.mapping.app.web.dto.SurveyedLocaleDto; import org.waterforpeople.mapping.app.web.dto.SurveyedLocaleRequest; import org.waterforpeople.mapping.app.web.dto.SurveyedLocaleResponse; import org.waterforpeople.mapping.dao.SurveyInstanceDAO; import org.waterforpeople.mapping.domain.SurveyInstance; import org.waterforpeople.mapping.serialization.response.MediaResponse; import com.gallatinsystems.device.domain.DeviceSurveyJobQueue; import com.gallatinsystems.framework.rest.AbstractRestApiServlet; import com.gallatinsystems.framework.rest.RestRequest; import com.gallatinsystems.framework.rest.RestResponse; import com.gallatinsystems.survey.dao.DeviceSurveyJobQueueDAO; import com.gallatinsystems.survey.dao.QuestionDao; import com.gallatinsystems.survey.dao.SurveyDAO; import com.gallatinsystems.survey.domain.Question; import com.gallatinsystems.survey.domain.Survey; import com.gallatinsystems.surveyal.dao.SurveyedLocaleDao; import com.gallatinsystems.surveyal.domain.SurveyalValue; import com.gallatinsystems.surveyal.domain.SurveyedLocale; /** * JSON service for returning the list of records for a specific surveyId * * @author Mark Tiele Westra */ public class SurveyedLocaleServlet extends AbstractRestApiServlet { private static final long serialVersionUID = 8748650927754433019L; private SurveyedLocaleDao surveyedLocaleDao; private static final Integer SL_PAGE_SIZE = 300; public SurveyedLocaleServlet() { setMode(JSON_MODE); surveyedLocaleDao = new SurveyedLocaleDao(); } @Override protected RestRequest convertRequest() throws Exception { HttpServletRequest req = getRequest(); RestRequest restRequest = new SurveyedLocaleRequest(); restRequest.populateFromHttpRequest(req); return restRequest; } /** * calls the surveyedLocaleDao to get the list of surveyedLocales for a certain surveyGroupId * passed in via the request, or the total number of available surveyedLocales if the * checkAvailable flag is set. */ @Override protected RestResponse handleRequest(RestRequest req) throws Exception { SurveyedLocaleRequest slReq = (SurveyedLocaleRequest) req; List<SurveyedLocale> slList = null; if (slReq.getSurveyGroupId() != null) { DeviceSurveyJobQueueDAO dsjqDAO = new DeviceSurveyJobQueueDAO(); SurveyDAO surveyDao = new SurveyDAO(); for (DeviceSurveyJobQueue dsjq : dsjqDAO.get(slReq.getPhoneNumber(), slReq.getImei(), slReq.getAndroidId())) { Survey s = surveyDao.getById(dsjq.getSurveyID()); if (s != null && s.getSurveyGroupId().longValue() == slReq.getSurveyGroupId() .longValue()) { slList = surveyedLocaleDao.listLocalesBySurveyGroupAndDate( slReq.getSurveyGroupId(), slReq.getLastUpdateTime(), SL_PAGE_SIZE); return convertToResponse(slList, slReq.getSurveyGroupId(), slReq.getLastUpdateTime()); } } } // A valid assignment has not been found for the given device RestResponse res = new RestResponse(); res.setCode(String.valueOf(HttpServletResponse.SC_FORBIDDEN)); res.setMessage("Invalid assignment"); return res; } /** * converts the domain objects to dtos and then installs them in a RecordDataResponse object * * @param lastUpdateTime */ protected SurveyedLocaleResponse convertToResponse(List<SurveyedLocale> slList, Long surveyGroupId, Date lastUpdateTime) { SurveyedLocaleResponse resp = new SurveyedLocaleResponse(); SurveyedLocaleDao slDao = new SurveyedLocaleDao(); QuestionDao qDao = new QuestionDao(); if (slList == null) { resp.setCode(String.valueOf(HttpServletResponse.SC_INTERNAL_SERVER_ERROR)); resp.setMessage("Internal Server Error"); return resp; } // set meta data resp.setCode(String.valueOf(HttpServletResponse.SC_OK)); resp.setResultCount(slList.size()); // set Locale data List<SurveyedLocaleDto> dtoList = new ArrayList<SurveyedLocaleDto>(); HashMap<Long, String> questionTypeMap = new HashMap<Long, String>(); // for each surveyedLocale, get the surveyalValues and store them in a map for (SurveyedLocale sl : slList) { List<SurveyalValue> svList = slDao.listValuesByLocale(sl.getKey().getId()); HashMap<Long, List<SurveyalValue>> instanceMap = new HashMap<Long, List<SurveyalValue>>(); if (svList != null && svList.size() > 0) { for (SurveyalValue sv : svList) { // put them in a map with the surveyInstance as key if (instanceMap.containsKey(sv.getSurveyInstanceId())) { instanceMap.get(sv.getSurveyInstanceId()).add(sv); } else { instanceMap.put(sv.getSurveyInstanceId(), new ArrayList<SurveyalValue>()); instanceMap.get(sv.getSurveyInstanceId()).add(sv); } } } // put them in the dto SurveyedLocaleDto dto = new SurveyedLocaleDto(); dto.setId(sl.getIdentifier()); dto.setSurveyGroupId(surveyGroupId); dto.setDisplayName(sl.getDisplayName()); dto.setLat(sl.getLatitude()); dto.setLon(sl.getLongitude()); dto.setLastUpdateDateTime(sl.getLastUpdateDateTime()); SurveyInstanceDAO sDao = new SurveyInstanceDAO(); for (Long instanceId : instanceMap.keySet()) { SurveyInstanceDto siDto = new SurveyInstanceDto(); SurveyInstance si = sDao.getByKey(instanceId); if (si != null) { siDto.setUuid(si.getUuid()); siDto.setSubmitter(si.getSubmitterName()); siDto.setSurveyId(si.getSurveyId()); siDto.setCollectionDate(si.getCollectionDate().getTime()); } for (SurveyalValue sv : instanceMap.get(instanceId)) { if (sv.getSurveyQuestionId() == null) { continue;// The question was deleted before storing the response. } String type = sv.getQuestionType(); if (type == null || "".equals(type)) { type = "VALUE"; } else if ("PHOTO".equals(type)) { type = "IMAGE"; } else if ("OPTION".equals(type)) { // first see if we have the question in the map already if (questionTypeMap.containsKey(sv.getSurveyQuestionId())) { type = questionTypeMap.get(sv.getSurveyQuestionId()); } else { // find question by id Question q = qDao.getByKey(sv.getSurveyQuestionId()); if (q != null) { // if the question has the allowOtherFlag set, // use OTHER as the device question type if (q.getAllowOtherFlag()) { type = "OTHER"; } questionTypeMap.put(sv.getSurveyQuestionId(), type); } } } // Make all responses backwards compatible String value = sv.getStringValue() != null ? sv.getStringValue() : ""; switch (type) { case "OPTION": case "OTHER": if (value.startsWith("[")) { value = DataUtils.jsonResponsesToPipeSeparated(value); } break; case "IMAGE": case "VIDEO": value = MediaResponse.format(value, MediaResponse.VERSION_STRING); break; default: break; } siDto.addProperty(sv.getSurveyQuestionId(), value, type); } dto.getSurveyInstances().add(siDto); } dtoList.add(dto); } resp.setSurveyedLocaleData(dtoList); return resp; } /** * writes response as a JSON string */ @Override protected void writeOkResponse(RestResponse resp) throws Exception { int sc; try { sc = Integer.valueOf(resp.getCode()); } catch (NumberFormatException ignored) { // Status code was not properly set in the RestResponse sc = HttpServletResponse.SC_INTERNAL_SERVER_ERROR; } getResponse().setStatus(sc); if (sc == HttpServletResponse.SC_OK) { ObjectMapper jsonMapper = new ObjectMapper(); jsonMapper.writeValue(getResponse().getWriter(), resp); getResponse().getWriter().println(); } else { getResponse().getWriter().println(resp.getMessage()); } } }