/* * Copyright (c) 2014. * * BaasBox - info-at-baasbox.com * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.baasbox.controllers; import static play.libs.Json.toJson; import java.io.IOException; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import org.apache.commons.lang3.exception.ExceptionUtils; import play.mvc.BodyParser; import play.mvc.Controller; import play.mvc.Http; import play.mvc.Result; import play.mvc.With; import com.baasbox.controllers.actions.filters.ConnectToDBFilter; import com.baasbox.controllers.actions.filters.UserCredentialWrapFilter; import com.baasbox.dao.UserDao; import com.baasbox.dao.exception.SqlInjectionException; import com.baasbox.db.DbHelper; import com.baasbox.exception.UserNotFoundException; import com.baasbox.service.logging.BaasBoxLogger; import com.baasbox.service.logging.PushLogger; import com.baasbox.service.push.PushNotInitializedException; import com.baasbox.service.push.PushProfileDisabledException; import com.baasbox.service.push.PushProfileInvalidException; import com.baasbox.service.push.PushService; import com.baasbox.service.push.providers.PushActionLocalizedKeyFormatException; import com.baasbox.service.push.providers.PushBadgeFormatException; import com.baasbox.service.push.providers.PushCategoryFormatException; import com.baasbox.service.push.providers.PushCollapseKeyFormatException; import com.baasbox.service.push.providers.PushContentAvailableFormatException; import com.baasbox.service.push.providers.PushInvalidApiKeyException; import com.baasbox.service.push.providers.PushLocalizedArgumentsFormatException; import com.baasbox.service.push.providers.PushLocalizedKeyFormatException; import com.baasbox.service.push.providers.PushSoundKeyFormatException; import com.baasbox.service.push.providers.PushTimeToLiveFormatException; import com.baasbox.service.user.UserService; import com.fasterxml.jackson.databind.JsonNode; import com.google.android.gcm.server.InvalidRequestException; import com.google.common.base.Joiner; import com.google.common.primitives.Booleans; @With ({UserCredentialWrapFilter.class,ConnectToDBFilter.class}) @BodyParser.Of(BodyParser.Json.class) public class Push extends Controller { public static Result send(String username) throws Exception { if (BaasBoxLogger.isTraceEnabled()) BaasBoxLogger.trace("Method Start"); Http.RequestBody body = request().body(); JsonNode bodyJson= body.asJson(); //{"message":"Text"} if (BaasBoxLogger.isTraceEnabled()) BaasBoxLogger.trace("send bodyJson: " + bodyJson); if (bodyJson==null) return status(CustomHttpCode.JSON_PAYLOAD_NULL.getBbCode(),CustomHttpCode.JSON_PAYLOAD_NULL.getDescription()); JsonNode messageNode=bodyJson.findValue("message"); if (messageNode==null) return status(CustomHttpCode.PUSH_MESSAGE_INVALID.getBbCode(),CustomHttpCode.PUSH_MESSAGE_INVALID.getDescription()); if(!messageNode.isTextual()) return status(CustomHttpCode.PUSH_MESSAGE_INVALID.getBbCode(),CustomHttpCode.PUSH_MESSAGE_INVALID.getDescription()); String message=messageNode.asText(); List<String> usernames = new ArrayList<String>(); usernames.add(username); JsonNode pushProfilesNodes=bodyJson.get("profiles"); List<Integer> pushProfiles = new ArrayList<Integer>(); if(!(pushProfilesNodes==null)){ if(!(pushProfilesNodes.isArray())) return status(CustomHttpCode.PUSH_PROFILE_FORMAT_INVALID.getBbCode(),CustomHttpCode.PUSH_PROFILE_FORMAT_INVALID.getDescription()); for(JsonNode pushProfileNode : pushProfilesNodes) { pushProfiles.add(pushProfileNode.asInt()); } } else { pushProfiles.add(1); } boolean[] withError=new boolean[6]; PushService ps=new PushService(); try{ if(ps.validate(pushProfiles)) withError=ps.send(message, usernames, pushProfiles, bodyJson, withError); } catch (UserNotFoundException e) { BaasBoxLogger.error("Username not found " + username, e); return notFound("Username not found"); } catch (SqlInjectionException e) { return badRequest("the supplied name appears invalid (Sql Injection Attack detected)"); } catch (PushNotInitializedException e){ BaasBoxLogger.error(ExceptionUtils.getMessage(e)); return status(CustomHttpCode.PUSH_CONFIG_INVALID.getBbCode(), CustomHttpCode.PUSH_CONFIG_INVALID.getDescription()); } catch (PushProfileDisabledException e) { BaasBoxLogger.error(ExceptionUtils.getMessage(e)); return status(CustomHttpCode.PUSH_PROFILE_DISABLED.getBbCode(),CustomHttpCode.PUSH_PROFILE_DISABLED.getDescription()); } catch (PushProfileInvalidException e) { BaasBoxLogger.error(ExceptionUtils.getMessage(e)); return status(CustomHttpCode.PUSH_PROFILE_FORMAT_INVALID.getBbCode(),CustomHttpCode.PUSH_PROFILE_FORMAT_INVALID.getDescription()); } catch (UnknownHostException e){ BaasBoxLogger.error(ExceptionUtils.getMessage(e)); return status(CustomHttpCode.PUSH_HOST_UNREACHABLE.getBbCode(),CustomHttpCode.PUSH_HOST_UNREACHABLE.getDescription()); } catch (InvalidRequestException e) { BaasBoxLogger.error(ExceptionUtils.getMessage(e)); return status(CustomHttpCode.PUSH_INVALID_REQUEST.getBbCode(),CustomHttpCode.PUSH_INVALID_REQUEST.getDescription()); } catch(PushSoundKeyFormatException e) { BaasBoxLogger.error(ExceptionUtils.getMessage(e)); return status(CustomHttpCode.PUSH_SOUND_FORMAT_INVALID.getBbCode(),CustomHttpCode.PUSH_SOUND_FORMAT_INVALID.getDescription()); } catch(PushBadgeFormatException e) { BaasBoxLogger.error(ExceptionUtils.getMessage(e)); return status(CustomHttpCode.PUSH_BADGE_FORMAT_INVALID.getBbCode(),CustomHttpCode.PUSH_BADGE_FORMAT_INVALID.getDescription()); } catch(PushActionLocalizedKeyFormatException e) { BaasBoxLogger.error(ExceptionUtils.getMessage(e)); return status(CustomHttpCode.PUSH_ACTION_LOCALIZED_KEY_FORMAT_INVALID.getBbCode(),CustomHttpCode.PUSH_ACTION_LOCALIZED_KEY_FORMAT_INVALID.getDescription()); } catch(PushLocalizedKeyFormatException e) { BaasBoxLogger.error(ExceptionUtils.getMessage(e)); return status(CustomHttpCode.PUSH_LOCALIZED_KEY_FORMAT_INVALID.getBbCode(),CustomHttpCode.PUSH_LOCALIZED_ARGUMENTS_FORMAT_INVALID.getDescription()); } catch(PushLocalizedArgumentsFormatException e) { BaasBoxLogger.error(ExceptionUtils.getMessage(e)); return status(CustomHttpCode.PUSH_LOCALIZED_ARGUMENTS_FORMAT_INVALID.getBbCode(),CustomHttpCode.PUSH_LOCALIZED_ARGUMENTS_FORMAT_INVALID.getDescription()); } catch(PushCollapseKeyFormatException e) { BaasBoxLogger.error(ExceptionUtils.getMessage(e)); return status(CustomHttpCode.PUSH_COLLAPSE_KEY_FORMAT_INVALID.getBbCode(),CustomHttpCode.PUSH_COLLAPSE_KEY_FORMAT_INVALID.getDescription()); } catch(PushTimeToLiveFormatException e) { BaasBoxLogger.error(ExceptionUtils.getMessage(e)); return status(CustomHttpCode.PUSH_TIME_TO_LIVE_FORMAT_INVALID.getBbCode(),CustomHttpCode.PUSH_TIME_TO_LIVE_FORMAT_INVALID.getDescription()); } catch(PushContentAvailableFormatException e) { BaasBoxLogger.error(ExceptionUtils.getMessage(e)); return status(CustomHttpCode.PUSH_CONTENT_AVAILABLE_FORMAT_INVALID.getBbCode(),CustomHttpCode.PUSH_CONTENT_AVAILABLE_FORMAT_INVALID.getDescription()); } catch(PushCategoryFormatException e) { BaasBoxLogger.error(ExceptionUtils.getMessage(e)); return status(CustomHttpCode.PUSH_CATEGORY_FORMAT_INVALID.getBbCode(),CustomHttpCode.PUSH_CATEGORY_FORMAT_INVALID.getDescription()); } if (BaasBoxLogger.isTraceEnabled()) BaasBoxLogger.trace("Method End"); for(int i=0;i<withError.length;i++) { if(withError[i]==true) return status(CustomHttpCode.PUSH_SENT_WITH_ERROR.getBbCode(),CustomHttpCode.PUSH_SENT_WITH_ERROR.getDescription()); } return ok(); } public static Result sendUsers() throws Exception { boolean verbose=false; try{ if (BaasBoxLogger.isTraceEnabled()) BaasBoxLogger.trace("Method Start"); PushLogger pushLogger = PushLogger.getInstance().init(); if (UserService.isAnAdmin(DbHelper.currentUsername())) { pushLogger.enable(); }else{ pushLogger.disable(); } if (request().getQueryString("verbose")!=null && request().getQueryString("verbose").equalsIgnoreCase("true")) verbose=true; Http.RequestBody body = request().body(); JsonNode bodyJson= body.asJson(); //{"message":"Text"} if (BaasBoxLogger.isTraceEnabled()) BaasBoxLogger.trace("send bodyJson: " + bodyJson); if (bodyJson==null) return status(CustomHttpCode.JSON_PAYLOAD_NULL.getBbCode(),CustomHttpCode.JSON_PAYLOAD_NULL.getDescription()); pushLogger.addMessage("Payload received: %s",bodyJson.toString()); JsonNode messageNode=bodyJson.findValue("message"); pushLogger.addMessage("Payload message received: %s", messageNode==null? "null":messageNode.asText()); if (messageNode==null) return status(CustomHttpCode.PUSH_MESSAGE_INVALID.getBbCode(),CustomHttpCode.PUSH_MESSAGE_INVALID.getDescription()); if(!messageNode.isTextual()) return status(CustomHttpCode.PUSH_MESSAGE_INVALID.getBbCode(),CustomHttpCode.PUSH_MESSAGE_INVALID.getDescription()); String message=messageNode.asText(); JsonNode usernamesNodes=bodyJson.get("users"); pushLogger.addMessage("users: %s", usernamesNodes==null? "null" : usernamesNodes.toString() ); List<String> usernames = new ArrayList<String>(); if(!(usernamesNodes==null)){ if(!(usernamesNodes.isArray())) return status(CustomHttpCode.PUSH_USERS_FORMAT_INVALID.getBbCode(),CustomHttpCode.PUSH_USERS_FORMAT_INVALID.getDescription()); for(JsonNode usernamesNode : usernamesNodes) { usernames.add(usernamesNode.asText()); } HashSet<String> hs = new HashSet<String>(); hs.addAll(usernames); usernames.clear(); usernames.addAll(hs); pushLogger.addMessage("Users extracted: %s", Joiner.on(",").join(usernames)); } else { return status(CustomHttpCode.PUSH_NOTFOUND_KEY_USERS.getBbCode(),CustomHttpCode.PUSH_NOTFOUND_KEY_USERS.getDescription()); } JsonNode pushProfilesNodes=bodyJson.get("profiles"); pushLogger.addMessage("profiles: %s", pushProfilesNodes==null? "null" : pushProfilesNodes.toString() ); List<Integer> pushProfiles = new ArrayList<Integer>(); if(!(pushProfilesNodes==null)){ if(!(pushProfilesNodes.isArray())) return status(CustomHttpCode.PUSH_PROFILE_FORMAT_INVALID.getBbCode(),CustomHttpCode.PUSH_PROFILE_FORMAT_INVALID.getDescription()); for(JsonNode pushProfileNode : pushProfilesNodes) { if(pushProfileNode.isTextual()) return status(CustomHttpCode.PUSH_PROFILE_FORMAT_INVALID.getBbCode(),CustomHttpCode.PUSH_PROFILE_FORMAT_INVALID.getDescription()); pushProfiles.add(pushProfileNode.asInt()); } HashSet<Integer> hs = new HashSet<Integer>(); hs.addAll(pushProfiles); pushProfiles.clear(); pushProfiles.addAll(hs); } else { pushProfiles.add(1); } pushLogger.addMessage("Profiles computed: %s", Joiner.on(",").join(pushProfiles)); boolean[] withError=new boolean[6]; PushService ps=new PushService(); Result toRet=null; try{ boolean isValid=(ps.validate(pushProfiles)); pushLogger.addMessage("Profiles validation: %s", isValid); if (isValid) withError=ps.send(message, usernames, pushProfiles, bodyJson, withError); pushLogger.addMessage("Service result: %s", Booleans.join(", ", withError)); } catch (UserNotFoundException e) { return notFound("Username not found"); } catch (SqlInjectionException e) { return badRequest("The supplied name appears invalid (Sql Injection Attack detected)"); } catch (PushNotInitializedException e){ BaasBoxLogger.error(ExceptionUtils.getMessage(e)); return status(CustomHttpCode.PUSH_CONFIG_INVALID.getBbCode(), CustomHttpCode.PUSH_CONFIG_INVALID.getDescription()); } catch (PushProfileDisabledException e) { BaasBoxLogger.error(ExceptionUtils.getMessage(e)); return status(CustomHttpCode.PUSH_PROFILE_DISABLED.getBbCode(),CustomHttpCode.PUSH_PROFILE_DISABLED.getDescription()); } catch (PushProfileInvalidException e) { BaasBoxLogger.error(ExceptionUtils.getMessage(e)); return status(CustomHttpCode.PUSH_PROFILE_FORMAT_INVALID.getBbCode(),CustomHttpCode.PUSH_PROFILE_FORMAT_INVALID.getDescription()); } catch (PushInvalidApiKeyException e) { BaasBoxLogger.error(ExceptionUtils.getMessage(e)); return status(CustomHttpCode.PUSH_INVALID_APIKEY.getBbCode(),CustomHttpCode.PUSH_INVALID_APIKEY.getDescription()); } catch (UnknownHostException e){ BaasBoxLogger.error(ExceptionUtils.getMessage(e)); return status(CustomHttpCode.PUSH_HOST_UNREACHABLE.getBbCode(),CustomHttpCode.PUSH_HOST_UNREACHABLE.getDescription()); } catch (InvalidRequestException e) { BaasBoxLogger.error(ExceptionUtils.getMessage(e)); return status(CustomHttpCode.PUSH_INVALID_REQUEST.getBbCode(),CustomHttpCode.PUSH_INVALID_REQUEST.getDescription()); } catch(IOException e){ BaasBoxLogger.error(ExceptionUtils.getMessage(e)); return badRequest(ExceptionUtils.getMessage(e)); } catch(PushSoundKeyFormatException e) { BaasBoxLogger.error(ExceptionUtils.getMessage(e)); return status(CustomHttpCode.PUSH_SOUND_FORMAT_INVALID.getBbCode(),CustomHttpCode.PUSH_SOUND_FORMAT_INVALID.getDescription()); } catch(PushBadgeFormatException e) { BaasBoxLogger.error(ExceptionUtils.getMessage(e)); return status(CustomHttpCode.PUSH_BADGE_FORMAT_INVALID.getBbCode(),CustomHttpCode.PUSH_BADGE_FORMAT_INVALID.getDescription()); } catch(PushActionLocalizedKeyFormatException e) { BaasBoxLogger.error(ExceptionUtils.getMessage(e)); return status(CustomHttpCode.PUSH_ACTION_LOCALIZED_KEY_FORMAT_INVALID.getBbCode(),CustomHttpCode.PUSH_ACTION_LOCALIZED_KEY_FORMAT_INVALID.getDescription()); } catch(PushLocalizedKeyFormatException e) { BaasBoxLogger.error(ExceptionUtils.getMessage(e)); return status(CustomHttpCode.PUSH_LOCALIZED_KEY_FORMAT_INVALID.getBbCode(),CustomHttpCode.PUSH_LOCALIZED_ARGUMENTS_FORMAT_INVALID.getDescription()); } catch(PushLocalizedArgumentsFormatException e) { BaasBoxLogger.error(ExceptionUtils.getMessage(e)); return status(CustomHttpCode.PUSH_LOCALIZED_ARGUMENTS_FORMAT_INVALID.getBbCode(),CustomHttpCode.PUSH_LOCALIZED_ARGUMENTS_FORMAT_INVALID.getDescription()); } catch(PushCollapseKeyFormatException e) { BaasBoxLogger.error(ExceptionUtils.getMessage(e)); return status(CustomHttpCode.PUSH_COLLAPSE_KEY_FORMAT_INVALID.getBbCode(),CustomHttpCode.PUSH_COLLAPSE_KEY_FORMAT_INVALID.getDescription()); } catch(PushTimeToLiveFormatException e) { BaasBoxLogger.error(ExceptionUtils.getMessage(e)); return status(CustomHttpCode.PUSH_TIME_TO_LIVE_FORMAT_INVALID.getBbCode(),CustomHttpCode.PUSH_TIME_TO_LIVE_FORMAT_INVALID.getDescription()); } catch(PushContentAvailableFormatException e) { BaasBoxLogger.error(ExceptionUtils.getMessage(e)); return status(CustomHttpCode.PUSH_CONTENT_AVAILABLE_FORMAT_INVALID.getBbCode(),CustomHttpCode.PUSH_CONTENT_AVAILABLE_FORMAT_INVALID.getDescription()); } catch(PushCategoryFormatException e) { BaasBoxLogger.error(ExceptionUtils.getMessage(e)); return status(CustomHttpCode.PUSH_CATEGORY_FORMAT_INVALID.getBbCode(),CustomHttpCode.PUSH_CATEGORY_FORMAT_INVALID.getDescription()); } if (BaasBoxLogger.isTraceEnabled()) BaasBoxLogger.trace("Method End"); for(int i=0;i<withError.length;i++) { if(withError[i]==true) return status(CustomHttpCode.PUSH_SENT_WITH_ERROR.getBbCode(),CustomHttpCode.PUSH_SENT_WITH_ERROR.getDescription()); } PushLogger.getInstance().messages(); if (UserService.isAnAdmin(DbHelper.currentUsername()) && verbose){ return ok (toJson(PushLogger.getInstance().messages())); } else { return ok("Push Notification(s) has been sent"); } }finally{ if (UserService.isAnAdmin(DbHelper.currentUsername()) && verbose){ return ok (toJson(PushLogger.getInstance().messages())); } BaasBoxLogger.debug("Push execution flow:\n{}", PushLogger.getInstance().toString()); } } public static Result enablePush(String os, String pushToken) throws SqlInjectionException{ if (BaasBoxLogger.isTraceEnabled()) BaasBoxLogger.trace("Method Start"); if(os==null) return badRequest("OS value cannot be null"); if(pushToken==null) return badRequest("pushToken value cannot be null"); if (BaasBoxLogger.isDebugEnabled()) BaasBoxLogger.debug("Trying to enable push to OS: "+os+" pushToken: "+ pushToken); HashMap<String, Object> data = new HashMap<String, Object>(); data.put("os",os); data.put(UserDao.USER_PUSH_TOKEN, pushToken); UserService.registerDevice(data); if (BaasBoxLogger.isTraceEnabled()) BaasBoxLogger.trace("Method End"); return ok(); } public static Result disablePush(String pushToken) throws SqlInjectionException{ if (BaasBoxLogger.isTraceEnabled()) BaasBoxLogger.trace("Method Start"); if(pushToken==null) return badRequest("pushToken value cannot be null"); if (BaasBoxLogger.isDebugEnabled()) BaasBoxLogger.debug("Trying to disable push to pushToken: "+ pushToken); UserService.unregisterDevice(pushToken); if (BaasBoxLogger.isTraceEnabled()) BaasBoxLogger.trace("Method End"); return ok(); } /* public static Result sendAll(String message) throws PushNotInitializedException { }*/ }