/***************************************************************************************** Infosistema - OpenBaas Copyright(C) 2002-2014 Infosistema, S.A. This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program 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 for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. www.infosistema.com info@openbaas.com Av. José Gomes Ferreira, 11 3rd floor, s.34 Miraflores 1495-139 Algés Portugal ****************************************************************************************/ package infosistema.openbaas.rest; import infosistema.openbaas.data.Error; import infosistema.openbaas.data.Metadata; import infosistema.openbaas.data.Result; import infosistema.openbaas.data.enums.FileMode; import infosistema.openbaas.data.models.Application; import infosistema.openbaas.data.models.User; import infosistema.openbaas.data.models.UsersState; import infosistema.openbaas.dataaccess.files.DropboxModel; import infosistema.openbaas.middleLayer.AppsMiddleLayer; import infosistema.openbaas.middleLayer.MediaMiddleLayer; import infosistema.openbaas.middleLayer.SessionMiddleLayer; import infosistema.openbaas.middleLayer.UsersMiddleLayer; import infosistema.openbaas.utils.Const; import infosistema.openbaas.utils.Log; import infosistema.openbaas.utils.Utils; import java.io.InputStream; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.util.ArrayList; import java.util.List; import java.util.Set; import javax.ws.rs.Consumes; import javax.ws.rs.DELETE; import javax.ws.rs.GET; import javax.ws.rs.HttpMethod; import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.Context; import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.Status; import javax.ws.rs.core.UriInfo; import org.codehaus.jettison.json.JSONArray; import org.codehaus.jettison.json.JSONException; import org.codehaus.jettison.json.JSONObject; import com.sun.jersey.api.client.ClientResponse; import com.sun.jersey.api.view.Viewable; import com.sun.jersey.core.header.FormDataContentDisposition; import com.sun.jersey.multipart.FormDataParam; public class AppResource { private AppsMiddleLayer appsMid; private UsersMiddleLayer usersMid; private SessionMiddleLayer sessionMid; private MediaMiddleLayer mediaMid; public AppResource() { appsMid = AppsMiddleLayer.getInstance(); usersMid = UsersMiddleLayer.getInstance(); sessionMid = SessionMiddleLayer.getInstance(); mediaMid = MediaMiddleLayer.getInstance(); } @Context UriInfo uriInfo; @GET @Path("/GetDropBoxToken") @Produces(MediaType.APPLICATION_JSON) public Response getDropboxTokens(@Context UriInfo ui, @Context HttpHeaders hh) { try { DropboxModel.getDropboxTokens(); } catch (Exception e) { return null; } return Response.status(200).build(); } // *** CREATE *** // /** * Create application, fields necessary are: appName. An unique identifier * is generated and returned in the reply. * * This is the time to define the optional parameters of the app such as if the developer wants to confirm the users * email before allowing them to perform operations, and other relevant options. * * @param inputJsonObj * @return */ @POST @Consumes({ MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON }) public Response createApp(JSONObject inputJsonObj, @Context UriInfo ui, @Context HttpHeaders hh) { Response response = null; int code = Utils.treatParametersAdmin(ui, hh); if (code == 1) { Application temp = null; String appName = null; boolean confirmUsersEmail; boolean AWS; boolean FTP; boolean FileSystem; boolean DropboxCloud; String appId = null; String appKey = null; boolean readSucess = false; JSONObject imageRes = null; JSONObject videoRes = null; JSONObject audioRes = null; JSONObject imageBars = null; List<String> clientsList = null; try { appName = (String) inputJsonObj.get(Application.APP_NAME); imageRes = (JSONObject) inputJsonObj.get(Application.IMAGE_RES); videoRes = (JSONObject) inputJsonObj.get(Application.AUDIO_RES); audioRes = (JSONObject) inputJsonObj.get(Application.VIDEO_RES); imageBars = (JSONObject) inputJsonObj.get(Application.IMAGE_BARS); clientsList = Utils.getListByJsonArray((JSONArray) inputJsonObj.opt(Application.CLIENTS_LIST)); confirmUsersEmail = (boolean) inputJsonObj.optBoolean(Application.CONFIRM_USERS_EMAIL, false); AWS = (boolean) inputJsonObj.optBoolean(FileMode.aws.toString(), false); FTP = (boolean) inputJsonObj.optBoolean(FileMode.ftp.toString(), false); DropboxCloud = (boolean) inputJsonObj.optBoolean(FileMode.dropbox_cloud.toString(), false); if(!AWS && !FTP && !DropboxCloud ) FileSystem = (boolean) inputJsonObj.optBoolean(FileMode.filesystem.toString(), true); else FileSystem = (boolean) inputJsonObj.optBoolean(FileMode.filesystem.toString(), false); if(!AWS && !FTP && !FileSystem && !DropboxCloud) FileSystem = true; readSucess = true; } catch (JSONException e) { Log.error("", this, "createApp", "Error parsing the JSON.", e); return Response.status(Status.BAD_REQUEST).entity(new Error("Error parsing the JSON.")).build(); } if (readSucess) { appId = Utils.getRandomString(Const.getIdLength()); appKey = Utils.getRandomString(Const.getIdLength()); temp = appsMid.createApp(appId, appKey, appName, confirmUsersEmail, AWS, FTP, FileSystem,DropboxCloud, imageRes,imageBars,videoRes,audioRes, clientsList); } if (temp != null) { Result res = new Result(temp, null); response = Response.status(Status.CREATED).entity(res).build(); } else { response = Response.status(302).entity(new Error("not created")).build(); } } else if(code == -2){ response = Response.status(Status.FORBIDDEN).entity(new Error("Invalid Session Token.")).build(); }else if(code == -1) response = Response.status(Status.BAD_REQUEST).entity(new Error("Error handling the request.")).build(); return response; } @Path("{appId}/usersstate") @POST @Produces(MediaType.APPLICATION_JSON) public Response getUserState(@PathParam(Const.APP_ID) String appId, JSONObject inputJsonObj, @Context UriInfo ui, @Context HttpHeaders hh) { Response response = null; List<UsersState> listRes = new ArrayList<UsersState>(); int code = Utils.treatParameters(ui, hh); if (code == 1) { try { JSONArray inputJsonArray = inputJsonObj.getJSONArray(Application.USERS); Boolean includeNulls = inputJsonObj.optBoolean(Application.INCLUDEMISSES, false); if(inputJsonArray.length()>0){ for(int i = 0; i < inputJsonArray.length(); i++){ Object pos = inputJsonArray.get(i); if(pos instanceof String){ String userId = (String) pos; Result res = usersMid.getUserInApp(appId, userId); User usr = (User)res.getData(); Metadata meta = (Metadata)res.getMetadata(); if(usr!=null && meta!=null){ Boolean online = Boolean.parseBoolean(usr.getOnline()); UsersState userState = new UsersState(userId, online, meta.getLastUpdateDate()); listRes.add(userState); }else{ if(includeNulls) listRes.add(null); } }else{ if(includeNulls) listRes.add(null); } } return Response.status(Status.OK).entity(listRes).build(); }else{ return Response.status(Status.NOT_FOUND).entity(new Error("UserIds Array empty")).build(); } } catch (Exception e) { Log.error("", this, "getUserState", "Error in getUserState.", e); return Response.status(Status.INTERNAL_SERVER_ERROR).entity(new Error("Error in getUserState.")).build(); } } else if(code == -2){ return Response.status(Status.FORBIDDEN).entity(new Error("Invalid Session Token.")).build(); }else if(code == -1) return Response.status(Status.BAD_REQUEST).entity(new Error("Error handling the request.")).build(); return response; } @POST @Path("{appId}/log") @Consumes({ MediaType.MULTIPART_FORM_DATA }) @Produces({ MediaType.APPLICATION_JSON }) public Response uploadLog(@PathParam(Const.APP_ID) String appId, @Context HttpHeaders hh, @Context UriInfo ui, @FormDataParam(Const.FILE) InputStream uploadedInputStream, @FormDataParam(Const.FILE) FormDataContentDisposition fileDetail) { Response response = null; String sessionToken = Utils.getSessionToken(hh); if (!sessionMid.checkAppForToken(sessionToken, appId)) return Response.status(Status.UNAUTHORIZED).entity(new Error("Action in wrong app: "+appId)).build(); String userId = sessionMid.getUserIdUsingSessionToken(sessionToken); int code = Utils.treatParameters(ui, hh); if (code == 1) { Boolean res = mediaMid.createLog(uploadedInputStream, fileDetail, appId, userId); if (!res) response = Response.status(Status.BAD_REQUEST).entity(new Error(appId)).build(); else response = Response.status(Status.OK).entity(res).build(); } else if(code == -2) { response = Response.status(Status.FORBIDDEN).entity(new Error("Invalid Session Token.")).build(); } else if(code == -1) response = Response.status(Status.BAD_REQUEST).entity(new Error("Error handling the request.")).build(); return response; } // *** UPDATE *** // /** * Updates the application, optional fields: "newAppName" (new application * name to set), alive (true to reactivate a dead app). * * @param appId * @param inputJsonObj * @return */ @Path("{appId}") @PATCH @Produces(MediaType.APPLICATION_JSON) public Response updateApp(@PathParam(Const.APP_ID) String appId, JSONObject inputJsonObj, @Context UriInfo ui, @Context HttpHeaders hh) { List<String> oldImageRes = new ArrayList<String>(); List<String> oldVideoRes = new ArrayList<String>(); List<String> oldAudioRes = new ArrayList<String>(); Response response = null; int code = Utils.treatParametersAdmin(ui, hh); if (code == 1) { String newAlive = null; String newAppName = null; Application temp = null; JSONObject imageRes = null; JSONObject imageBars = null; JSONObject videoRes = null; JSONObject audioRes = null; List<String> clientsList = null; Boolean newAWS; Boolean newFTP; Boolean newFileSystem; Boolean newDropbox; Boolean newConfirmUsersEmail; newAlive = inputJsonObj.optString(Application.ALIVE); //mudar para boolean newAppName = inputJsonObj.optString(Application.APP_NAME); newConfirmUsersEmail = (boolean) inputJsonObj.optBoolean(Application.CONFIRM_USERS_EMAIL, false); newAWS = (Boolean) inputJsonObj.opt(FileMode.aws.toString()); newFTP = (Boolean) inputJsonObj.opt(FileMode.ftp.toString()); newFileSystem = (Boolean) inputJsonObj.opt(FileMode.filesystem.toString()); newDropbox = (Boolean) inputJsonObj.opt(FileMode.dropbox_cloud.toString()); imageRes = (JSONObject) inputJsonObj.opt(Application.IMAGE_RES); imageBars = (JSONObject) inputJsonObj.opt(Application.IMAGE_BARS); videoRes = (JSONObject) inputJsonObj.opt(Application.VIDEO_RES); audioRes = (JSONObject) inputJsonObj.opt(Application.AUDIO_RES); clientsList = Utils.getListByJsonArray((JSONArray) inputJsonObj.opt(Application.CLIENTS_LIST)); Application app = this.appsMid.getApp(appId); Set<String> imagesRes = app.getImageResolutions().keySet(); Set<String> videosRes = app.getVideoResolutions().keySet(); Set<String> audiosRes = app.getAudioResolutions().keySet(); if(newAlive.equals("")) newAlive = app.getAlive(); if(newAppName.equals("")) newAppName = app.getAppName(); if(newConfirmUsersEmail.equals("")) newConfirmUsersEmail = app.getConfirmUsersEmail(); if(newAWS==null) newAWS = app.getAWS(); if(newFTP==null) newFTP = app.getFTP(); if(newFileSystem==null) newFileSystem = app.getFileSystem(); if(newDropbox==null) newDropbox = app.getDropbox(); if(!newAWS && !newFTP && !newFileSystem && !newDropbox) newFileSystem = true; if (this.appsMid.appExists(appId)) { if((imageRes!=null && imageRes.length()>0) || (videoRes!=null && videoRes.length()>0) || (audioRes!=null && audioRes.length()>0) || (imageBars!=null && imageBars.length()>0)){ if(!imagesRes.isEmpty()){ oldImageRes.addAll(imagesRes); } if(!videosRes.isEmpty()){ oldVideoRes.addAll(videosRes); } if(!audiosRes.isEmpty()){ oldAudioRes.addAll(audiosRes); } this.appsMid.updateFilesRes(imageRes,imageBars,videoRes,audioRes,appId, oldImageRes,oldVideoRes,oldAudioRes); } temp = this.appsMid.updateAllAppFields(appId, newAlive, newAppName,newConfirmUsersEmail,newAWS,newFTP,newFileSystem,newDropbox, clientsList); Result res = new Result(temp, null); response = Response.status(Status.OK).entity(res).build(); } else { response = Response.status(Status.NOT_FOUND).entity(new Error(appId)).build(); } }else if(code == -2){ response = Response.status(Status.FORBIDDEN).entity(new Error("Invalid Session Token.")).build(); }else if(code == -1) response = Response.status(Status.BAD_REQUEST).entity(new Error("Error handling the request.")).build(); return response; } // *** DELETE *** // /** * Delete application using its application Identifier. * * @param appId * @return */ /*Danger NOT to USE!!! @Path("{appId}") @DELETE @Produces({ MediaType.APPLICATION_JSON }) public Response deleteApp(@PathParam(Const.APP_ID) String appId, @Context UriInfo ui, @Context HttpHeaders hh) { Response response = null; int code = Utils.treatParametersAdmin(ui, hh); if (code == 1) { if (this.appsMid.removeApp(appId)) { response = Response.status(Status.OK).entity(appId).build(); } else response = Response.status(Status.NOT_FOUND).entity(new Error(appId)).build(); } else if(code == -2){ response = Response.status(Status.FORBIDDEN).entity(new Error("Invalid Session Token.")).build(); }else if(code == -1) response = Response.status(Status.BAD_REQUEST).entity(new Error("Error handling the request.")).build(); return response; } */ // *** GET LIST *** // // *** GET *** // /** * Get Application Information using its Application Identifier. * * @param appId * @return */ @Path("{appId}") @GET @Produces({ MediaType.APPLICATION_JSON }) public Response findById(@PathParam(Const.APP_ID) String appId, @Context UriInfo ui, @Context HttpHeaders hh) { Response response = null; int code = Utils.treatParametersAdmin(ui, hh); if (code == 1) { Application temp = appsMid.getApp(appId); if (temp == null) return Response.status(Status.NOT_FOUND).entity(new Error("App not exist")).build(); else { Result res = new Result(temp, null); response = Response.status(Status.OK).entity(res).build(); } } else if(code == -2){ response = Response.status(Status.FORBIDDEN).entity(new Error("Invalid Session Token.")).build(); }else if(code == -1) response = Response.status(Status.BAD_REQUEST).entity(new Error("Error handling the request.")).build(); return response; } // *** OTHERS *** // // *** RESOURCES *** // // This is needed to use patch methods, don't delete it! @Target({ ElementType.METHOD }) @Retention(RetentionPolicy.RUNTIME) @HttpMethod("PATCH") public @interface PATCH { } /** * Launches the resource to handle /users requests. * * @param appId * @return */ @Path("{appId}/users") public UsersResource users(@PathParam(Const.APP_ID) String appId) { try { return new UsersResource(uriInfo, appId); } catch (IllegalArgumentException e) { Log.error("", this, "users", "Illegal Arguments.", e); throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity("Parse error").build()); } } /** * Launches the resource to handle /media requests. * * @param appId * @return */ @Path("{appId}/media") public MediaResource media(@PathParam(Const.APP_ID) String appId) { try { return new MediaResource(appId) ; } catch (IllegalArgumentException e) { Log.error("", this, "media", "Illegal Arguments.", e); throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity("Parse error").build()); } } /** * Launches the resource to handle /data requests. * * @param appId * @return */ @Path("{appId}/data") public AppDataResource data(@PathParam(Const.APP_ID) String appId) { try { return new AppDataResource(uriInfo, appId); } catch (IllegalArgumentException e) { Log.error("", this, "data", "Illegal Arguments.", e); throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity("Parse error").build()); } } /** * Launches the resource to handle /media/audio requests. * * @param appId * @return */ @Path("{appId}/media/audio") public AudioResource audio(@PathParam(Const.APP_ID) String appId) { try { return new AudioResource(appId); } catch (IllegalArgumentException e) { Log.error("", this, "audio", "Illegal Arguments.", e); throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity("Parse error").build()); } } /** * Launches the resource to handle /media/video requests. * * @param appId * @return */ @Path("{appId}/media/video") public VideoResource video(@PathParam(Const.APP_ID) String appId) { try { return new VideoResource(appId); } catch (IllegalArgumentException e) { Log.error("", this, "video", "Illegal Arguments.", e); throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity("Parse error").build()); } } /** * Launches the resource to handle /media/images requests. * * @param appId * @return */ @Path("{appId}/media/images") public ImageResource image(@PathParam(Const.APP_ID) String appId) { try { return new ImageResource(appId); } catch (IllegalArgumentException e) { Log.error("", this, "image", "Illegal Arguments.", e); throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity("Parse error").build()); } } /** * Launches the resource to handle {appID}/storage requests. * * @param appId * @return */ @Path("{appId}/storage") public StorageResource storage(@PathParam(Const.APP_ID) String appId) { try { return new StorageResource(appId); } catch (IllegalArgumentException e) { Log.error("", this, "storage", "Illegal Arguments.", e); throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity("Parse error").build()); } } /** * Launches the resource to handle {appID}/account requests. * * @param appId * @return */ @Path("{appId}/account") public AccountResource account(@PathParam(Const.APP_ID) String appId) { try { return new AccountResource(appId); } catch (IllegalArgumentException e) { Log.error("", this, "acount", "Illegal Arguments.", e); throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity("Parse error").build()); } } @Path("{appId}/chatroom") public ChatResource chat(@PathParam(Const.APP_ID) String appId) { try { return new ChatResource(appId); } catch (IllegalArgumentException e) { Log.error("", this, "storage", "Illegal Arguments.", e); throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity("Parse error").build()); } } @Path("{appId}/settings") public SettingsResource settings(@PathParam(Const.APP_ID) String appId) { try { return new SettingsResource(appId); } catch (IllegalArgumentException e) { Log.error("", this, "storage", "Illegal Arguments.", e); throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity("Parse error").build()); } } }