/* * Copyright 2015 Ranjan Kumar * * 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.restfiddle.controller.rest; import java.util.Date; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import org.bson.types.ObjectId; import org.json.JSONArray; import org.json.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.transaction.annotation.Transactional; 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 org.springframework.web.bind.annotation.RestController; import com.mongodb.BasicDBObject; import com.mongodb.DBCollection; import com.mongodb.DBCursor; import com.mongodb.DBObject; import com.mongodb.DBRef; import com.mongodb.util.JSON; import com.restfiddle.dto.StatusResponse; import com.restfiddle.entity.GenericEntityData; import com.restfiddle.service.auth.EntityAuthService; @RestController @Transactional public class EntityDataController { private static final String SUCCESS = "success"; private static final String PASSWORD = "password"; private static final String USERNAME = "username"; Logger logger = LoggerFactory.getLogger(EntityDataController.class); @Autowired private MongoTemplate mongoTemplate; @Autowired private EntityAuthService authService; // Note : SORT PARAM : Specify in the sort parameter the field or fields to sort by and a value of 1 or -1 to specify an ascending or descending // sort respectively (http://docs.mongodb.org/manual/reference/method/cursor.sort/). @RequestMapping(value = "/api/{projectId}/entities/{name}/list", method = RequestMethod.GET, headers = "Accept=application/json") public @ResponseBody String getEntityDataList(@PathVariable("projectId") String projectId, @PathVariable("name") String entityName, @RequestParam(value = "page", required = false) Integer page, @RequestParam(value = "limit", required = false) Integer limit, @RequestParam(value = "sort", required = false) String sort, @RequestParam(value = "query", required = false) String query, @RequestHeader(value = "authToken", required = false) String authToken) { JSONObject authRes = authService.authorize(projectId,authToken,"USER"); if(!authRes.getBoolean(SUCCESS)){ return authRes.toString(4); } DBCollection dbCollection = mongoTemplate.getCollection(projectId+"_"+entityName); DBCursor cursor; if (query != null && !query.isEmpty()) { Object queryObject = JSON.parse(query); cursor = dbCollection.find((BasicDBObject) queryObject); } else { cursor = dbCollection.find(); } if (sort != null && !sort.isEmpty()) { Object sortObject = JSON.parse(sort); cursor.sort((BasicDBObject) sortObject); } if (limit != null && limit > 0) { if (page != null && page > 0) { cursor.skip((page - 1) * limit); } cursor.limit(limit); } List<DBObject> array = cursor.toArray(); if(entityName.equals("User")){ for(DBObject dbObject : array){ dbObject.removeField(PASSWORD); } } for(DBObject dbObject : array){ dbRefToRelation(dbObject); } String json = JSON.serialize(array); // Indentation JSONArray jsonArr = new JSONArray(json); return jsonArr.toString(4); } @RequestMapping(value = "/api/{projectId}/entities/{name}/{id}", method = RequestMethod.GET, headers = "Accept=application/json") public @ResponseBody String getEntityDataById(@PathVariable("projectId") String projectId, @PathVariable("name") String entityName, @PathVariable("id") String entityDataId, @RequestHeader(value = "authToken", required = false) String authToken) { JSONObject authRes = authService.authorize(projectId,authToken,"USER"); if(!authRes.getBoolean(SUCCESS)){ return authRes.toString(4); } DBCollection dbCollection = mongoTemplate.getCollection(projectId+"_"+entityName); BasicDBObject queryObject = new BasicDBObject(); queryObject.append("_id", new ObjectId(entityDataId)); DBObject resultObject = dbCollection.findOne(queryObject); if(resultObject == null){ return "Not Found"; } if(entityName.equals("User")){ resultObject.removeField(PASSWORD); } dbRefToRelation(resultObject); String json = resultObject.toString(); // Indentation JSONObject jsonObject = new JSONObject(json); return jsonObject.toString(4); } /** * [NOTE] http://stackoverflow.com/questions/25953056/how-to-access-fields-of-converted-json-object-sent-in-post-body */ @RequestMapping(value = "/api/{projectId}/entities/{name}", method = RequestMethod.POST, headers = "Accept=application/json", consumes = "application/json") public @ResponseBody String createEntityData(@PathVariable("projectId") String projectId, @PathVariable("name") String entityName, @RequestBody Object genericEntityDataDTO, @RequestHeader(value = "authToken", required = false) String authToken) { String data; if (!(genericEntityDataDTO instanceof Map)) { return null; } else { // Note : Entity data is accessible through this map. Map map = (Map) genericEntityDataDTO; JSONObject jsonObj = createJsonFromMap(map); data = jsonObj.toString(); } DBObject dbObject = (DBObject) JSON.parse(data); if (entityName.equals("User")) { return handleUserEntityData(projectId, dbObject, true); } DBRef user; JSONObject authRes = authService.authorize(projectId,authToken,"USER"); if(authRes.getBoolean(SUCCESS)){ user = (DBRef) authRes.get("user"); } else { return authRes.toString(4); } // Create a new document for the entity. DBCollection dbCollection = mongoTemplate.getCollection(projectId+"_"+entityName); relationToDBRef(dbObject, projectId); dbObject.put("createdBy", user); dbObject.put("createdAt", new Date()); dbCollection.save(dbObject); dbRefToRelation(dbObject); String json = dbObject.toString(); // Indentation JSONObject jsonObject = new JSONObject(json); return jsonObject.toString(4); } @RequestMapping(value = "/api/{projectId}/entities/{name}/{uuid}", method = RequestMethod.PUT, headers = "Accept=application/json", consumes = "application/json") public @ResponseBody String updateEntityData(@PathVariable("projectId") String projectId, @PathVariable("name") String entityName, @PathVariable("uuid") String uuid, @RequestBody Object genericEntityDataDTO, @RequestHeader(value = "authToken", required = false) String authToken) { DBRef user; JSONObject authRes = authService.authorize(projectId,authToken,"USER"); if(authRes.getBoolean(SUCCESS)){ user = (DBRef) authRes.get("user"); } else { return authRes.toString(4); } DBObject resultObject = new BasicDBObject(); if (genericEntityDataDTO instanceof Map) { Map map = (Map) genericEntityDataDTO; if (map.get("id") != null && map.get("id") instanceof String) { String entityDataId = (String) map.get("id"); logger.debug("Updating Entity Data with Id " + entityDataId); } JSONObject uiJson = new JSONObject(map); // ID is stored separately (in a different column). DBObject obj = (DBObject) JSON.parse(uiJson.toString()); obj.removeField("_id"); DBCollection dbCollection = mongoTemplate.getCollection(projectId+"_"+entityName); BasicDBObject queryObject = new BasicDBObject(); queryObject.append("_id", new ObjectId(uuid)); resultObject = dbCollection.findOne(queryObject); Set<String> keySet = obj.keySet(); for (String key : keySet) { resultObject.put(key, obj.get(key)); } if(entityName.equals("User")){ DBObject loggedInUser = dbCollection.findOne(user); if(loggedInUser.get(USERNAME).equals(resultObject.get(USERNAME))){ return handleUserEntityData(projectId, resultObject, obj.containsField(PASSWORD)); }else{ return new JSONObject().put(SUCCESS, false).put("msg", "unauthorized").toString(4); } } relationToDBRef(resultObject, projectId); resultObject.put("updatedBy", user); resultObject.put("updatedAt", new Date()); dbCollection.save(resultObject); } dbRefToRelation(resultObject); String json = resultObject.toString(); // Indentation JSONObject jsonObject = new JSONObject(json); return jsonObject.toString(4); } @RequestMapping(value = "/api/{projectId}/entities/{name}/{uuid}", method = RequestMethod.DELETE, headers = "Accept=application/json") public @ResponseBody StatusResponse deleteEntityData(@PathVariable("projectId") String projectId, @PathVariable("name") String entityName, @PathVariable("uuid") String uuid, @RequestHeader(value = "authToken", required = false) String authToken) { StatusResponse res = new StatusResponse(); JSONObject authRes = authService.authorize(projectId,authToken,"USER"); if(!authRes.getBoolean(SUCCESS)){ res.setStatus("Unauthorized"); return res; } DBCollection dbCollection = mongoTemplate.getCollection(projectId+"_"+entityName); BasicDBObject queryObject = new BasicDBObject(); queryObject.append("_id", new ObjectId(uuid)); dbCollection.remove(queryObject); res.setStatus("DELETED"); return res; } @SuppressWarnings("unchecked") private JSONObject createJsonFromMap(Map map) { JSONObject jsonObject = new JSONObject(); for (Iterator<String> iterator = map.keySet().iterator(); iterator.hasNext();) { String key = iterator.next(); jsonObject.put(key, map.get(key)); } return jsonObject; } private JSONObject createJsonFromEntityData(GenericEntityData entityData) { JSONObject jsonObject = new JSONObject(entityData.getData()); jsonObject.put("id", entityData.getId()); jsonObject.put("version", entityData.getVersion()); jsonObject.put("createdDate", entityData.getCreatedDate()); jsonObject.put("lastModifiedDate", entityData.getLastModifiedDate()); return jsonObject; } private void dbRefToRelation(DBObject dbObject) { if (dbObject == null) { return; } if (dbObject.containsField("_id")) dbObject.put("_id", ((ObjectId) dbObject.get("_id")).toHexString()); for (String key : dbObject.keySet()) { Object obj = dbObject.get(key); if (obj instanceof DBRef) { DBRef ref = (DBRef) obj; dbObject.put(key, dbRefToRel(ref)); } else if (obj instanceof DBObject) { dbRefToRelation((DBObject) obj); } } } private DBObject dbRefToRel(DBRef obj){ return new BasicDBObject().append("_rel",new BasicDBObject().append("entity", (obj.toString()).split("_")[1]).append("_id", ((ObjectId)obj.getId()).toHexString())); } private void relationToDBRef(DBObject dbObject, String projectId) { for (String key : dbObject.keySet()) { Object obj = dbObject.get(key); if (obj instanceof DBObject) { DBObject doc = (DBObject) obj; if (doc.containsField("_rel")) { DBObject relation = (DBObject) doc.get("_rel"); dbObject.put(key, new DBRef(projectId + "_" + (String) relation.get("entity"), new ObjectId((String) relation.get("_id")))); } else { relationToDBRef(doc, projectId); } } } } private String handleUserEntityData(String projectId, DBObject user, boolean encryptPassword) { JSONObject response = new JSONObject(); if (!user.containsField(USERNAME)) { response.put("msg", "username is mandotary"); return response.toString(4); } if (((String) user.get(USERNAME)).length() < 3) { response.put("msg", "username must be more then 3 character"); return response.toString(4); } if (!user.containsField(PASSWORD)) { response.put("msg", "password is mandotary"); return response.toString(4); } if (((String) user.get(PASSWORD)).length() < 3) { response.put("msg", "password must be more then 3 character"); return response.toString(4); } DBCollection dbCollection = mongoTemplate.getCollection(projectId + "_User"); BasicDBObject query = new BasicDBObject(); query.append(USERNAME, user.get(USERNAME)); DBObject existingUser = dbCollection.findOne(query); if (existingUser != null && !existingUser.get("_id").equals(user.get("_id"))) { response.put("msg", "username already exists"); return response.toString(4); } if (encryptPassword) { BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(); user.put(PASSWORD, encoder.encode((String) user.get(PASSWORD))); } relationToDBRef(user, projectId); dbCollection.save(user); user.removeField(PASSWORD); dbRefToRelation(user); String json = user.toString(); // Indentation response = new JSONObject(json); return response.toString(4); } }