package qa.qcri.aidr.manager.controller; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.ws.rs.Consumes; import javax.ws.rs.DefaultValue; import javax.ws.rs.QueryParam; import javax.ws.rs.core.MediaType; import org.apache.log4j.Logger; import org.json.simple.JSONObject; import org.json.simple.parser.JSONParser; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.propertyeditors.CustomDateEditor; import org.springframework.stereotype.Controller; import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.annotation.InitBinder; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import qa.qcri.aidr.common.values.UsageType; import qa.qcri.aidr.manager.dto.AidrCollectionTotalDTO; import qa.qcri.aidr.manager.dto.CollectionBriefInfo; import qa.qcri.aidr.manager.dto.CollectionDetailsInfo; import qa.qcri.aidr.manager.dto.CollectionSummaryInfo; import qa.qcri.aidr.manager.dto.TaggerCrisisType; import qa.qcri.aidr.manager.exception.AidrException; import qa.qcri.aidr.manager.persistence.entities.Collection; import qa.qcri.aidr.manager.persistence.entities.UserAccount; import qa.qcri.aidr.manager.service.CollectionCollaboratorService; import qa.qcri.aidr.manager.service.CollectionLogService; import qa.qcri.aidr.manager.service.CollectionService; import qa.qcri.aidr.manager.service.CrisisTypeService; import qa.qcri.aidr.manager.service.TaggerService; import qa.qcri.aidr.manager.util.CollectionStatus; import qa.qcri.aidr.manager.util.GeoRestrictionType; import qa.qcri.aidr.manager.util.JsonDataValidator; import qa.qcri.aidr.manager.util.SMS; import com.fasterxml.jackson.databind.ObjectMapper; @Controller @RequestMapping("public/collection") public class PublicController extends BaseController{ private static Logger logger = Logger.getLogger(PublicController.class); @Autowired private CollectionService collectionService; @Autowired private TaggerService taggerService; @Autowired private CollectionLogService collectionLogService; @Autowired private CrisisTypeService crisisTypeService; @Autowired private CollectionCollaboratorService collaboratorService; @InitBinder public void initBinder(WebDataBinder binder) { SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true)); } @RequestMapping(value = "/updateGeo.action", method = RequestMethod.POST) @Consumes(MediaType.APPLICATION_JSON) @ResponseBody public Map<String,Object> update(@RequestBody final String jsonCollection ) throws Exception { logger.info("updateGeo.action JSON:" + jsonCollection); if(jsonCollection == null){ return getUIWrapper(false); } if(!JsonDataValidator.isValidEMSCJson(jsonCollection)){ return getUIWrapper(false); } JSONParser parser = new JSONParser(); Object obj = parser.parse(jsonCollection); JSONObject jsonObject = (JSONObject) obj; String geoString = (String)jsonObject.get("geo"); long collectionId = (Long)jsonObject.get("id"); long durationInHours = (Long)jsonObject.get("durationInHours"); Boolean updateDuration = (Boolean)jsonObject.get("updateDuration"); if(updateDuration){ String token = (String)jsonObject.get("token"); if(!collectionService.isValidToken(token)){ logger.error("authentication failed : token - " + token); return getUIWrapper(false); } } try{ //logger.info("try:" + geoString) ; Collection dbCollection = collectionService.findById(collectionId); if(dbCollection != null) { CollectionStatus status = dbCollection.getStatus(); if (CollectionStatus.RUNNING_WARNING.equals(status) || CollectionStatus.RUNNING.equals(status) || CollectionStatus.INITIALIZING.equals(status)) { collectionService.stop(dbCollection.getId(), 1L); } dbCollection.setGeo(geoString); dbCollection.setGeoR(GeoRestrictionType.STRICT.name().toLowerCase()); dbCollection.setDurationHours((int)durationInHours); collectionService.update(dbCollection); if(!geoString.isEmpty() && geoString != null) { // status collectionService.startFetcher(collectionService.prepareFetcherRequest(dbCollection), dbCollection); } return getUIWrapper(true); } }catch(Exception e){ logger.error(String.format("Exception while Updating Collection : "+jsonCollection, e)); } return getUIWrapper(false); } @RequestMapping(value = "/findByRequestCode.action", method = RequestMethod.GET) @ResponseBody public Map<String,Object> findByRequestCode(@QueryParam("code") String code) throws Exception { try { //logger.info("Finding collection by code: "+code); Collection data = collectionService.findByCode(code); return getUIWrapper(data, true); } catch (Exception e) { logger.error("Exception while finding collection by code: "+code, e); return getUIWrapper(false); } } @RequestMapping(value = "/findAll.action", method = RequestMethod.GET) @ResponseBody public Map<String,Object> findAll(@RequestParam Integer start, @RequestParam Integer limit, @RequestParam Enum statusValue, @DefaultValue("no") @QueryParam("trashed") String trashed) throws Exception { start = (start != null) ? start : 0; limit = (limit != null) ? limit : 50; try { List<Collection> data = collectionService.findAllForPublic(start, limit, statusValue); logger.info("[findAll] fetched data size: " + ((data != null) ? data.size() : 0)); return getUIWrapper(data, true); } catch (Exception e) { logger.error("Error in find All collection for public",e); return getUIWrapper(false); } //return getUIWrapper(false); } @RequestMapping(value = "/create", method={RequestMethod.POST}) @ResponseBody public Map<String,Object> createCollection(CollectionDetailsInfo collectionDetailsInfo, @RequestParam(value = "runAfterCreate", defaultValue = "false", required = false) Boolean runAfterCreate) throws Exception { logger.info("Save Collection to Database having code : "+ collectionDetailsInfo.getCode()); //logger.info("Following users: " + collection.getFollow()); try{ UserAccount user = getAuthenticatedUser(); Collection collection = collectionService.create(collectionDetailsInfo, user); return getUIWrapper(true); }catch(Exception e){ logger.error("Error while saving Collection Info to database", e); return getUIWrapper(false); } } @RequestMapping(value = "/findAllRunning.action", method = RequestMethod.GET) @ResponseBody public Map<String,Object> findAllRunning(@RequestParam Integer start, @RequestParam Integer limit, @DefaultValue("no") @QueryParam("trashed") String trashed) throws Exception { start = (start != null) ? start : 0; limit = (limit != null) ? limit : 50; Integer count = 0; List<AidrCollectionTotalDTO> dtoList = new ArrayList<AidrCollectionTotalDTO>(); try { //logger.info("************************************************* CollectionStatus.RUNNING ****************************"); List<Collection> data = collectionService.findAllForPublic(start, limit, CollectionStatus.RUNNING); //logger.info("data size : " + data.size()); for (Collection collection : data) { String taggingOutPut = taggerService.loadLatestTweetsWithCount(collection.getCode(), 1); //String stripped = taggingOutPut.substring(1, taggingOutPut.lastIndexOf("]")); //logger.info("stripped taggingOutPut : " + taggingOutPut ); if(!JsonDataValidator.isEmptySON(taggingOutPut)) { AidrCollectionTotalDTO dto = convertAidrCollectionToDTO(collection, true); dtoList.add(dto); count = count +1; } } //logger.info("count = " + count); return getUIWrapper(dtoList, count.longValue()); } catch (Exception e) { logger.error("Error in find All Running collection for public",e); return getUIWrapper(false); } } @RequestMapping(value = "/findAllRunningWithNoOutput.action", method = RequestMethod.GET) @ResponseBody public Map<String,Object> findAllRunningWithNoOutput(@RequestParam Integer start, @RequestParam Integer limit, @DefaultValue("no") @QueryParam("trashed") String trashed) throws Exception { start = (start != null) ? start : 0; limit = (limit != null) ? limit : 50; Integer count = 0; List<AidrCollectionTotalDTO> dtoList = new ArrayList<AidrCollectionTotalDTO>(); try { List<Collection> data = collectionService.findAllForPublic(start, limit, CollectionStatus.RUNNING); //count = collectionService.getPublicCollectionsCount(CollectionStatus.RUNNING); for (Collection collection : data) { String taggingOutPut = taggerService.loadLatestTweetsWithCount(collection.getCode(), 1); if(JsonDataValidator.isEmptySON(taggingOutPut)) { AidrCollectionTotalDTO dto = convertAidrCollectionToDTO(collection, false); dtoList.add(dto); count = count +1; } } //logger.info("count = " + count); return getUIWrapper(dtoList, count.longValue()); } catch (Exception e) { logger.error("Error in find All Running collection With No Output for public",e); return getUIWrapper(false); } //return getUIWrapper(false); } @RequestMapping(value = "/findAllStoped.action", method = RequestMethod.GET) @ResponseBody public Map<String,Object> findAllStop(@RequestParam Integer start, @RequestParam Integer limit, @DefaultValue("no") @QueryParam("trashed") String trashed) throws Exception { start = (start != null) ? start : 0; limit = (limit != null) ? limit : 50; Integer count = 0; List<AidrCollectionTotalDTO> dtoList = new ArrayList<AidrCollectionTotalDTO>(); try { List<Collection> data = collectionService.findAllForPublic(start, limit, CollectionStatus.STOPPED); count = collectionService.getPublicCollectionsCount(CollectionStatus.STOPPED); boolean hasTagggerOutput; for (Collection collection : data) { String taggingOutPut = taggerService.loadLatestTweetsWithCount(collection.getCode(), 1); if(JsonDataValidator.isEmptySON(taggingOutPut)) { hasTagggerOutput = false; } else{ hasTagggerOutput = true; } AidrCollectionTotalDTO dto = convertAidrCollectionToDTO(collection, hasTagggerOutput); dtoList.add(dto); } //logger.info("count = " + count); return getUIWrapper(dtoList, count.longValue()); } catch (Exception e) { logger.error("Error in finding All stopped collections",e); return getUIWrapper(false); } } @RequestMapping(value = "/findById.action", method = RequestMethod.GET) @ResponseBody public AidrCollectionTotalDTO findById(Long id) throws Exception { Collection collection = collectionService.findById(id); AidrCollectionTotalDTO dto = convertAidrCollectionToDTO(collection, false); if (dto != null) { Integer totalCount = collectionLogService.countTotalDownloadedItemsForCollection(id); if (CollectionStatus.RUNNING.equals(dto.getStatus()) || CollectionStatus.RUNNING_WARNING.equals(dto.getStatus())){ totalCount += dto.getCount(); } dto.setTotalCount(totalCount); } return dto; } @RequestMapping(value = "/generateTweetIdsLink.action", method = RequestMethod.GET) @ResponseBody public Map<String,Object> generateTweetIdsLink(@RequestParam String code) throws Exception { Map<String, Object> result = null; try { result = collectionLogService.generateTweetIdsLink(code); if (result != null && result.get("url") != null) { return getUIWrapper(result.get("url"),true, null, (String)result.get("message")); } else { return getUIWrapper(false, "System is down or under maintenance. For further inquiries please contact admin."); } } catch (Exception e) { logger.error("Error in generateTweetIdsLink for collection : " + code, e); return getUIWrapper(false, "System is down or under maintenance. For further inquiries please contact admin."); } } @RequestMapping(value = "/getAttributesAndLabelsByCrisisId.action", method = RequestMethod.GET) @ResponseBody public Map<String,Object> getAttributesAndLabelsByCrisisId(@RequestParam Integer id) throws Exception { String result = ""; try { result = taggerService.getAttributesAndLabelsByCrisisId(id); } catch (Exception e) { logger.error("Error while getting attributes and labels for crisis: " + id, e); return getUIWrapper(false, "System is down or under maintenance. For further inquiries please contact admin."); } return getUIWrapper(result,true); } @RequestMapping(value = "/loadLatestTweets.action", method = RequestMethod.GET) @ResponseBody public Map<String,Object> loadLatestTweets(@RequestParam String code, @RequestParam String constraints) throws Exception { String result = ""; try { result = taggerService.loadLatestTweets(code, constraints); } catch (Exception e) { logger.error("Error while loading latest tweets for collection : " + code + " and constraints : " + constraints, e); return getUIWrapper(false, "System is down or under maintenance. For further inquiries please contact admin."); } return getUIWrapper(result,true); } @RequestMapping(value = "/getPublicFlagStatus", method = RequestMethod.GET) @ResponseBody public Map<String, Boolean> getPublicFlagStatus() { List<Collection> resultList; try { //long startTime = System.currentTimeMillis(); resultList = collectionService.getRunningCollections(); if (resultList != null) { Map<String, Boolean> runningCollections = new HashMap<String, Boolean>(resultList.size()); for (Collection c: resultList) { runningCollections.put(c.getCode(), c.isPubliclyListed()); } //logger.debug("Fetched map to send: " + runningCollections); return runningCollections; } } catch (Exception e) { logger.error("Unable to fetch list of running collections from DB for public", e); } return null; } @RequestMapping(value = "/getChannelPublicFlagStatus", method = RequestMethod.GET) @ResponseBody public Map<String, Boolean> getCollectionPublicFlagStatus(@QueryParam("channelCode") String channelCode) { Collection collection = null; try { //long startTime = System.currentTimeMillis(); collection = collectionService.findByCode(channelCode); //System.out.println("Time to retrieve publiclyStatus from DB: " + (System.currentTimeMillis() - startTime)); if (collection != null) { Map<String, Boolean> result = new HashMap<String, Boolean>(); result.put(channelCode, collection.isPubliclyListed()); //logger.debug("Fetched map to send: " + result); return result; } } catch (Exception e) { logger.error("Unable to fetch running status for collection: "+channelCode,e); } return null; } @RequestMapping(value = "/findTotalCount", method = RequestMethod.GET) @ResponseBody public Map<String, Integer> findTotalCount(final String collectionCode) throws Exception { try { Collection collection = collectionService.findByCode(collectionCode); AidrCollectionTotalDTO dto = convertAidrCollectionToDTO(collection, false); if (dto != null) { Integer totalCount = collectionLogService.countTotalDownloadedItemsForCollection(dto.getId()); if (CollectionStatus.RUNNING.equals(dto.getStatus()) || CollectionStatus.RUNNING_WARNING.equals(dto.getStatus())){ totalCount += dto.getCount(); } dto.setTotalCount(totalCount); } Map<String, Integer> result = new HashMap<String, Integer>(); result.put(collectionCode, dto.getTotalCount()); return result; } catch (Exception e) { logger.error("Unable to fetch total count of downloaded documents for collection = " + collectionCode, e); } return null; } private AidrCollectionTotalDTO convertAidrCollectionToDTO(Collection collection, boolean hasTaggerOutput){ if (collection == null){ return null; } AidrCollectionTotalDTO dto = new AidrCollectionTotalDTO(); dto.setId(collection.getId()); dto.setCode(collection.getCode()); dto.setName(collection.getName()); //dto.setTarget(collection.getTarget()); UserAccount user = collection.getOwner(); dto.setUser(user); if (collection.getCount() != null) { dto.setCount(collection.getCount()); } else { dto.setCount(0); } dto.setStatus(collection.getStatus()); dto.setTrack(collection.getTrack()); dto.setFollow(collection.getFollow()); dto.setGeo(collection.getGeo()); dto.setLangFilters(collection.getLangFilters()); dto.setStartDate(collection.getStartDate()); dto.setEndDate(collection.getEndDate()); dto.setCreatedDate(collection.getCreatedAt()); dto.setLastDocument(collection.getLastDocument()); dto.setDurationHours(collection.getDurationHours()); dto.setPubliclyListed(collection.isPubliclyListed()); dto.setCrisisType(collection.getCrisisType()); dto.setHasTaggerOutput(hasTaggerOutput); dto.setCollectionType(collection.getProvider()); dto.setCrisisType(collection.getCrisisType()); List<UserAccount> managers = collaboratorService.fetchCollaboratorsByCollection(collection.getId()); dto.setManagers(managers); return dto; } private String getCrisisTypeName(int typeID){ String name = "Not specified"; try { List<TaggerCrisisType> crisisTypes = taggerService.getAllCrisisTypes(); for (TaggerCrisisType cType : crisisTypes) { if(cType.getCrisisTypeID() == typeID) { name = cType.getName(); } } } catch (AidrException e) { logger.error("Error while fetching all crisisTypes for public",e); } return name; } @RequestMapping(value = "/stopAllRunningCollection", method = RequestMethod.POST) @ResponseBody public Map<String,Object> stopAllRunningCollections(@RequestBody final String jsonString) throws Exception { if(jsonString == null){ return getUIWrapper(false); } JSONParser parser = new JSONParser(); JSONObject jsonObject = (JSONObject)parser.parse(jsonString); String token = (String)jsonObject.get("token"); if(collectionService.isValidToken(token)){ List<Collection> runningCollections = collectionService.getRunningCollections(); List<Collection> stoppedCollections = new ArrayList<Collection>(); for (Collection aidrCollection : runningCollections) { stoppedCollections.add(collectionService.stop(aidrCollection.getId(), 1L)); } return getUIWrapper(stoppedCollections, true); } else{ return getUIWrapper("Authentication Failed", false); } } @RequestMapping(value = "/startCollections", method = RequestMethod.POST) @ResponseBody public Map<String,Object> startMultipleCollections(@RequestBody String jsonString) throws Exception { if(jsonString == null){ return getUIWrapper(false); } JSONParser parser = new JSONParser(); JSONObject jsonObject = (JSONObject)parser.parse(jsonString); String token = (String)jsonObject.get("token"); List<Collection> collections = new ArrayList<Collection>(); if(collectionService.isValidToken(token)){ ObjectMapper mapper = new ObjectMapper(); collections = Arrays.asList(mapper.readValue(jsonObject.get("collections").toString(), Collection[].class)); List<String> startedCollections = new ArrayList<String>(); for (Collection collection : collections) { collection = collectionService.findByCode(collection.getCode()); if (!collection.getStatus().equals(CollectionStatus.TRASHED)) { collection = collectionService.start(collection.getId()); startedCollections.add(collection.getCode()); } } return getUIWrapper(startedCollections, true); } else{ return getUIWrapper("Authentication Failed", false); } } @RequestMapping(value = "/sms/push/{collectionCode}", method = RequestMethod.POST) @ResponseBody public Map<String,Object> receive(@PathVariable(value = "collectionCode") String collectionCode, @RequestHeader("apiKey") String apiKey, @RequestBody SMS sms) throws Exception { if(collectionService.isValidAPIKey(collectionCode, apiKey)){ Boolean response = collectionService.pushSMS(collectionCode, sms); if(response){ return getUIWrapper("Successfully posted SMS", true); //Response.ok("Successfully posted SMS").build(); } else{ return getUIWrapper("Exception while posting SMS", false); //Response.ok("Exception while posting SMS").build(); } } else{ return getUIWrapper("API Key is not valid", false); //Response.ok("API Key is not valid").build(); } } @RequestMapping(value = "{usage}/all") @ResponseBody public List<CollectionSummaryInfo> getCollections(@PathVariable(value = "usage") String usage) { List<CollectionSummaryInfo> summaryInfos = new ArrayList<CollectionSummaryInfo>(); try { UsageType usageType = UsageType.valueOf(usage); summaryInfos = collectionService.getAllCollectionDataByUsage(usageType); } catch (Exception e) { // TODO Auto-generated catch block logger.error("error", e); return Collections.EMPTY_LIST; } return summaryInfos; } @RequestMapping(value = "/list") @ResponseBody public List<CollectionBriefInfo> getCollectionsBriefInfo(@RequestParam(defaultValue="false") Boolean micromappersEnabled) { List<CollectionBriefInfo> briefInfos = new ArrayList<CollectionBriefInfo>(); try { briefInfos = collectionService.getMicromappersFilteredCollections(micromappersEnabled); } catch (Exception e) { logger.error("Error is fetching collection list.", e); } return briefInfos; } @RequestMapping("/statistics") @ResponseBody public String getCollectionStatistics() throws Exception { Map<String, Object> result = new HashMap<>(); ObjectMapper mapper = new ObjectMapper(); try { result = getUIWrapper(collectionService.getCollectionStatistics(),true); } catch (Exception e) { logger.error("Error while fetching tweets counts", e); result = getUIWrapper(false, "System is down or under maintenance. For further inquiries please contact admin."); } return "jsonp(" + mapper.writeValueAsString(result) + ")"; } }