# HG changeset patch # User ymh # Date 1402583255 -7200 # Node ID 8ad1734d9d8a30fa1614184bc77142a2fd2a147b # Parent af4a54a78ba6089ee9f7970bc1a484785f42397c add export link on project diff -r af4a54a78ba6 -r 8ad1734d9d8a server/pom.xml --- a/server/pom.xml Thu Jun 05 18:15:52 2014 +0200 +++ b/server/pom.xml Thu Jun 12 16:27:35 2014 +0200 @@ -41,6 +41,7 @@ 2.2.3 3.1.3 17.0 + 0.9.1 UTF-8 @@ -447,6 +448,12 @@ guava ${guava-version} + + com.jayway.jsonpath + json-path-assert + ${json-path-version} + test + IRI diff -r af4a54a78ba6 -r 8ad1734d9d8a server/src/main/java/org/iri_research/renkan/controller/RenkanController.java --- a/server/src/main/java/org/iri_research/renkan/controller/RenkanController.java Thu Jun 05 18:15:52 2014 +0200 +++ b/server/src/main/java/org/iri_research/renkan/controller/RenkanController.java Thu Jun 12 16:27:35 2014 +0200 @@ -1,8 +1,11 @@ package org.iri_research.renkan.controller; import java.util.HashMap; +import java.util.Iterator; import java.util.Map; +import javax.servlet.http.HttpServletResponse; + import org.iri_research.renkan.Constants; import org.iri_research.renkan.Constants.EditMode; import org.iri_research.renkan.RenkanException; @@ -10,6 +13,7 @@ import org.iri_research.renkan.models.Project; import org.iri_research.renkan.repositories.ProjectsRepository; import org.iri_research.renkan.repositories.SpacesRepository; +import org.iri_research.renkan.rest.ObjectMapperProvider; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -27,6 +31,12 @@ import org.springframework.web.client.HttpServerErrorException; import org.springframework.web.servlet.ModelAndView; +import com.fasterxml.jackson.annotation.ObjectIdGenerators.UUIDGenerator; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; + @Controller @RequestMapping("/p") public class RenkanController { @@ -39,6 +49,9 @@ @Autowired private SpacesRepository spacesRepository; + + @Autowired + private ObjectMapperProvider mapperProvider; private void checkCowebkey(String cowebkey, Project project, Constants.EditMode editMode) { @@ -117,17 +130,17 @@ @RequestMapping(value = "/pub/{project_id}", method = RequestMethod.GET, produces = { "text/html;charset=UTF-8", "!image/*" }) public String renkanPublishProject(Model model, - @PathVariable(value = "project_id") String project_id, + @PathVariable(value = "project_id") String projectId, @RequestParam(value = "cowebkey") String cowebkey) { - if (project_id == null || project_id.length() == 0) { + if (projectId == null || projectId.length() == 0) { throw new IllegalArgumentException( "RenkanContoller.renkanProject: Project id is null or empty."); } - Project project = this.projectsRepository.findOne(project_id); + Project project = this.projectsRepository.findOne(projectId); if (project == null) { throw new HttpClientErrorException(HttpStatus.NOT_FOUND, "Project " - + project_id + " not found."); + + projectId + " not found."); } this.checkCowebkey(cowebkey, project, EditMode.READ_ONLY); @@ -138,5 +151,52 @@ return "renkanProjectPublish"; } + + @RequestMapping(value = "/exp/{project_id}", method = RequestMethod.GET, produces = { "application/json;charset=UTF-8" }) + public @ResponseBody String exportProject(@PathVariable(value = "project_id") String projectId, HttpServletResponse response) throws JsonProcessingException { + + ObjectMapper mapper = this.mapperProvider.getContext(ObjectMapper.class); + + Project project = this.projectsRepository.findOne(projectId); + + if (project == null) { + throw new HttpClientErrorException(HttpStatus.NOT_FOUND, "Project " + + projectId + " not found."); + } + + ObjectNode jsonNode = mapper.valueToTree(project); + + jsonNode.remove("id"); + + Iterator nodes = jsonNode.get("nodes").elements(); + + HashMap nodeIds = new HashMap(); + UUIDGenerator uuidgens = new UUIDGenerator(); + + while(nodes.hasNext()) { + ObjectNode nodeNode = (ObjectNode) nodes.next(); + String nodeId = nodeNode.get("id").asText(); + String atId = uuidgens.generateId(nodeNode).toString(); + nodeIds.put(nodeId, atId); + nodeNode.put("@id", atId); + nodeNode.remove("id"); + } + + Iterator edges = jsonNode.get("edges").elements(); + while(edges.hasNext()) { + ObjectNode edgeNode = (ObjectNode) edges.next(); + edgeNode.put("from", nodeIds.get(edgeNode.get("from").asText())); + edgeNode.put("to", nodeIds.get(edgeNode.get("to").asText())); + edgeNode.remove("id"); + } + + String res = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(jsonNode); + + response.setContentType("application/force-download"); + response.setHeader("Content-Transfer-Encoding", "binary"); + response.setHeader("Content-Disposition", "attachment; filename=\""+ projectId +".json\""); + + return res; + } } diff -r af4a54a78ba6 -r 8ad1734d9d8a server/src/main/java/org/iri_research/renkan/rest/RestApplication.java --- a/server/src/main/java/org/iri_research/renkan/rest/RestApplication.java Thu Jun 05 18:15:52 2014 +0200 +++ b/server/src/main/java/org/iri_research/renkan/rest/RestApplication.java Thu Jun 12 16:27:35 2014 +0200 @@ -19,7 +19,7 @@ ObjectMapper objectMapper = this.objectMapperProvider.getContext(ObjectMapper.class); - JacksonJaxbJsonProvider provider = new JacksonJaxbJsonProvider(objectMapper, JacksonJaxbJsonProvider.DEFAULT_ANNOTATIONS); + JacksonJaxbJsonProvider provider = new JacksonJaxbJsonProvider(objectMapper, JacksonJaxbJsonProvider.DEFAULT_ANNOTATIONS); this.register(provider); diff -r af4a54a78ba6 -r 8ad1734d9d8a server/src/main/webapp/WEB-INF/i18n/messages.properties --- a/server/src/main/webapp/WEB-INF/i18n/messages.properties Thu Jun 05 18:15:52 2014 +0200 +++ b/server/src/main/webapp/WEB-INF/i18n/messages.properties Thu Jun 12 16:27:35 2014 +0200 @@ -15,10 +15,12 @@ renkanIndex.project_copy = Copy renkanIndex.project_delete = Delete renkanIndex.project_render = View +renkanIndex.project_export = Export renkanIndex.project_edit_link = Edit renkan renkanIndex.project_copy_link = Copy renkan renkanIndex.project_delete_link = Delete renkan renkanIndex.project_render_link = View renkan +renkanIndex.project_export_link = Export renkan renkanIndex.project_delete_confirm = Delete renkan "<%= title %>" ? renkanIndex.project_filter = Filter title diff -r af4a54a78ba6 -r 8ad1734d9d8a server/src/main/webapp/WEB-INF/i18n/messages_en.properties --- a/server/src/main/webapp/WEB-INF/i18n/messages_en.properties Thu Jun 05 18:15:52 2014 +0200 +++ b/server/src/main/webapp/WEB-INF/i18n/messages_en.properties Thu Jun 12 16:27:35 2014 +0200 @@ -14,10 +14,12 @@ renkanIndex.project_copy = Copy renkanIndex.project_delete = Delete renkanIndex.project_render = View +renkanIndex.project_export = Export renkanIndex.project_edit_link = Edit renkan renkanIndex.project_copy_link = Copy renkan renkanIndex.project_delete_link = Delete renkan renkanIndex.project_render_link = View renkan +renkanIndex.project_export_link = Export renkan renkanIndex.project_delete_confirm = Delete renkan "<%= title %>" ? renkanIndex.project_filter = Filter title diff -r af4a54a78ba6 -r 8ad1734d9d8a server/src/main/webapp/WEB-INF/i18n/messages_fr.properties --- a/server/src/main/webapp/WEB-INF/i18n/messages_fr.properties Thu Jun 05 18:15:52 2014 +0200 +++ b/server/src/main/webapp/WEB-INF/i18n/messages_fr.properties Thu Jun 12 16:27:35 2014 +0200 @@ -15,10 +15,12 @@ renkanIndex.project_copy = Copier renkanIndex.project_delete = Eff. renkanIndex.project_render = Consult. +renkanIndex.project_export = Export. renkanIndex.project_edit_link = Editer renkan renkanIndex.project_copy_link = Copier renkan renkanIndex.project_delete_link = Eff. renkan renkanIndex.project_render_link = Consult. renkan +renkanIndex.project_export_link = Export. renkan renkanIndex.project_delete_confirm = Voulez-vous effacer le renkan "<%= title %>" ? renkanIndex.project_filter = Filtre titre diff -r af4a54a78ba6 -r 8ad1734d9d8a server/src/main/webapp/WEB-INF/templates/projectIndex.html --- a/server/src/main/webapp/WEB-INF/templates/projectIndex.html Thu Jun 05 18:15:52 2014 +0200 +++ b/server/src/main/webapp/WEB-INF/templates/projectIndex.html Thu Jun 12 16:27:35 2014 +0200 @@ -69,6 +69,7 @@ Copy Del. View + Export @@ -80,6 +81,7 @@ Copy project Delete project View project + Export project diff -r af4a54a78ba6 -r 8ad1734d9d8a server/src/main/webapp/WEB-INF/templates/renkanIndex.html --- a/server/src/main/webapp/WEB-INF/templates/renkanIndex.html Thu Jun 05 18:15:52 2014 +0200 +++ b/server/src/main/webapp/WEB-INF/templates/renkanIndex.html Thu Jun 12 16:27:35 2014 +0200 @@ -14,7 +14,6 @@ - @@ -26,10 +25,12 @@

Renkan Spaces

-
Create a Space
+
Create a Space
- - +
+
+
+

Space list

diff -r af4a54a78ba6 -r 8ad1734d9d8a server/src/main/webapp/WEB-INF/web.xml --- a/server/src/main/webapp/WEB-INF/web.xml Thu Jun 05 18:15:52 2014 +0200 +++ b/server/src/main/webapp/WEB-INF/web.xml Thu Jun 12 16:27:35 2014 +0200 @@ -41,21 +41,13 @@ ws.bufferSize 100000 - + 1 cometd /cometd/* - - cross-origin - org.eclipse.jetty.servlets.CrossOriginFilter - - - cross-origin - /cometd/* - admin org.coweb.servlet.AdminServlet @@ -99,4 +91,13 @@ springSecurityFilterChain /* + + cross-origin + org.eclipse.jetty.servlets.CrossOriginFilter + + + cross-origin + /cometd/* + /rest/* + diff -r af4a54a78ba6 -r 8ad1734d9d8a server/src/test/java/org/iri_research/renkan/test/controller/RenkanControllerTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/src/test/java/org/iri_research/renkan/test/controller/RenkanControllerTest.java Thu Jun 12 16:27:35 2014 +0200 @@ -0,0 +1,191 @@ +package org.iri_research.renkan.test.controller; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.TimeZone; +import java.util.UUID; + +import org.iri_research.renkan.models.Edge; +import org.iri_research.renkan.models.Node; +import org.iri_research.renkan.models.Project; +import org.iri_research.renkan.models.Space; +import org.iri_research.renkan.repositories.EdgesRepository; +import org.iri_research.renkan.repositories.NodesRepository; +import org.iri_research.renkan.repositories.ProjectsRepository; +import org.iri_research.renkan.repositories.SpacesRepository; +import org.joda.time.DateTime; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.mongodb.core.geo.Point; +import org.springframework.http.MediaType; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.context.web.WebAppConfiguration; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.MvcResult; +import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.test.web.servlet.result.MockMvcResultMatchers; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.context.WebApplicationContext; + +@RunWith(SpringJUnit4ClassRunner.class) +@WebAppConfiguration +@ContextConfiguration(locations = { "controller-context.xml", + "file:src/main/webapp/WEB-INF/spring-servlet.xml" }) +public class RenkanControllerTest { + + private final static int SPACE_NB = 3; + + private Logger logger = LoggerFactory.getLogger(RenkanControllerTest.class); + + @Autowired + private SpacesRepository spacesRepository; + @Autowired + private ProjectsRepository projectsRepository; + @Autowired + private NodesRepository nodesRepository; + @Autowired + private EdgesRepository edgesRepository; + + private Map spacesList = new HashMap(SPACE_NB); + private List spacesUuids = new ArrayList<>(SPACE_NB); + + private ArrayList testProjects = new ArrayList<>(); + private ArrayList testNodes = new ArrayList<>(); + private ArrayList testEdges = new ArrayList<>(); + + @Autowired + private WebApplicationContext context; + private MockMvc mvc; + + private void clean() { + edgesRepository.deleteAll(); + nodesRepository.deleteAll(); + projectsRepository.deleteAll(); + spacesRepository.deleteAll(); + } + + @Before + public void setup() { + + logger.debug("Setup"); + TimeZone.setDefault(TimeZone.getTimeZone("UTC")); + this.clean(); + + ArrayList pl = new ArrayList(); + for (int i = 0; i < SPACE_NB; i++) { + DateTime creationDate = new DateTime(); + String uuid = UUID.randomUUID().toString(); + spacesUuids.add(uuid); + Space testSpace = new Space(uuid, "test " + i, "Test space " + 1, + "{}", "http://ldt.iri.centrepompidou.fr", "#ababab", + "test_user", "http://ldt.iri.centrepompidou.fr", + creationDate); + testSpace = spacesRepository.save(testSpace); + this.spacesList.put(uuid, testSpace); + for (int j = 0; j < SPACE_NB - 1 - i; j++) { + pl.add(new Project(testSpace.getId(), UUID.randomUUID() + .toString(), "test" + ((SPACE_NB - 1) * i + j + 1), + "desc" + ((SPACE_NB - 1) * i + j + 1), + "http://localhost:8080/rest/projects/id" + + ((SPACE_NB - 1) * i + j + 1), creationDate)); + } + try { + Thread.sleep(1); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + Project testProject = pl.get(0); + + for (int i = 0; i < 3; i++) { + Node node = new Node("Node" + i, "Node" + i, "Node " + i, + "http://renkan.org/nodes/node" + i, "#ffff0" + i, + "test_user", new Point(0, i), + "http://renkan.org/images/node" + i, i, testProject.getId()); + node = this.nodesRepository.save(node); + testProject.getNodes().add(node); + this.testNodes.add(node); + } + + for (int i = 0; i < 3; i++) { + Edge edge = new Edge("Node" + i, "Node" + i, "Node " + i, + "http://renkan.org/edges/edge" + i, "#ffff0" + i, + this.testNodes.get((i + 2) % 3), this.testNodes.get(i), + "test_user", testProject.getId()); + edge = this.edgesRepository.save(edge); + testProject.getEdges().add(edge); + this.testEdges.add(edge); + } + + + for (Project p : projectsRepository.save(pl)) { + this.testProjects.add(p); + } + + this.mvc = MockMvcBuilders.webAppContextSetup(this.context).build(); + } + + + @After + public void teardown() { + this.clean(); + } + + @Test + public void testExportProject() throws Exception { + MockHttpServletRequestBuilder get = MockMvcRequestBuilders.get("/p/exp/"+this.testProjects.get(0).getId()); + MvcResult res = this.mvc.perform(get) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentTypeCompatibleWith(MediaType.APPLICATION_JSON)) + .andReturn(); + + logger.debug("testExportProject resp : " + + res.getResponse().getContentAsString()); + } + + @Test + public void testExportProjectContent() throws Exception { + MockHttpServletRequestBuilder get = MockMvcRequestBuilders.get("/p/exp/"+this.testProjects.get(0).getId()); + MvcResult res = this.mvc.perform(get) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentTypeCompatibleWith(MediaType.APPLICATION_JSON)) + .andExpect(MockMvcResultMatchers.jsonPath("title").exists()) + .andExpect(MockMvcResultMatchers.jsonPath("title").value("test1")) + .andExpect(MockMvcResultMatchers.jsonPath("description").exists()) + .andExpect(MockMvcResultMatchers.jsonPath("description").value("desc1")) + .andExpect(MockMvcResultMatchers.jsonPath("nodes").isArray()) + .andExpect(MockMvcResultMatchers.jsonPath("edges").isArray()) + .andReturn(); + + logger.debug("testExportProjectContent resp : " + + res.getResponse().getContentAsString()); + } + + + @Test + public void testExportProjectExclude() throws Exception { + MockHttpServletRequestBuilder get = MockMvcRequestBuilders.get("/p/exp/"+this.testProjects.get(0).getId()); + MvcResult res = this.mvc.perform(get) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentTypeCompatibleWith(MediaType.APPLICATION_JSON)) + .andExpect(MockMvcResultMatchers.jsonPath("id").doesNotExist()) + .andExpect(MockMvcResultMatchers.jsonPath("nodes[*].id").doesNotExist()) + .andExpect(MockMvcResultMatchers.jsonPath("nodes[*].@id").exists()) + .andExpect(MockMvcResultMatchers.jsonPath("edges[*].id").doesNotExist()) + .andReturn(); + + logger.debug("testExportProjectContentExclude resp : " + + res.getResponse().getContentAsString()); + } + +}