Skip to content
Snippets Groups Projects
Commit a1a843a3 authored by Sara Bertocco's avatar Sara Bertocco
Browse files

Finalized task #3549 - Implement deleteNode endpoint

parent b1acafa1
No related branches found
No related tags found
No related merge requests found
......@@ -20,8 +20,10 @@ import java.util.stream.Collectors;
import javax.servlet.http.HttpServletRequest;
import net.ivoa.xml.vospace.v2.Node;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
......@@ -32,10 +34,9 @@ public class DeleteNodeController extends BaseNodeController {
@Autowired
private NodeDAO nodeDAO;
@GetMapping(value = {"/nodes", "/nodes/**"},
consumes = {MediaType.APPLICATION_XML_VALUE, MediaType.TEXT_XML_VALUE, MediaType.APPLICATION_JSON_VALUE},
@DeleteMapping(value = {"/nodes", "/nodes/**"},
produces = {MediaType.APPLICATION_XML_VALUE, MediaType.TEXT_XML_VALUE, MediaType.APPLICATION_JSON_VALUE})
public ResponseEntity<Node> deleteNode(HttpServletRequest request, User principal) {
public ResponseEntity<String> deleteNode(HttpServletRequest request, User principal) {
String path = getPath();
......@@ -60,7 +61,7 @@ public class DeleteNodeController extends BaseNodeController {
} else {
// Manage all precursors in full path
for (int i = 1; i < pathComponents.size(); i++) {
for (int i = 0; i < pathComponents.size(); i++) {
String tmpPath = pathComponents.get(i);
Node mynode = nodeDAO.listNode(tmpPath)
.orElseThrow(() -> new NodeNotFoundException(tmpPath));
......@@ -71,55 +72,17 @@ public class DeleteNodeController extends BaseNodeController {
}
// DUPLICATED code from CreateNodeController - BEGIN
List<String> nodeOwner
= NodeProperties.getNodePropertyByURI(toBeDeletedNode, NodeProperties.CREATOR_URI);
//= getNodePropertyByURI(
// toBeDeletedNode, "ivo://ivoa.net/vospace/core#creator");
if (nodeOwner == null
|| nodeOwner.isEmpty()
|| !nodeOwner.get(0).equals(principal.getName())) {
// Node owner check has failed: let's check if user can write
// due to group privileges
List<String> userGroups = principal.getGroups();
// If the user doesn't belong to any groups throw exception
if (userGroups == null || userGroups.isEmpty()) {
if(!NodeUtils.checkIfWritable(toBeDeletedNode, principal.getName(), principal.getGroups())) {
throw new PermissionDeniedException(path);
}
List<String> groupWritePropValues
= NodeProperties.getNodePropertyByURI(toBeDeletedNode,
NodeProperties.CREATOR_URI);
// If groupwrite property is absent in Parent Node throw exception
if (groupWritePropValues == null
|| groupWritePropValues.isEmpty()) {
throw new PermissionDeniedException(path);
try {
nodeDAO.deleteNode(path);
return ResponseEntity.ok("Node deleted");
} catch(Exception ex) {
return new ResponseEntity<>(ex.getMessage(), HttpStatus.BAD_REQUEST);
}
List<String> nodeGroups
= NodeProperties.parsePropertyStringToList(groupWritePropValues.get(0));
if (nodeGroups.isEmpty()
|| !nodeGroups.stream()
.anyMatch((i) -> userGroups.contains(i))) {
throw new PermissionDeniedException(path);
}
}
// DUPLICATED code from CreateNodeController - END
return ResponseEntity.ok(toBeDeletedNode);
//return toBeDeletedNode;
//return ResponseEntity.ok(nodeDAO.deleteNode(path)
// .orElseThrow(() -> new InternalFaultException(path)));
}
}
......
......@@ -23,10 +23,7 @@ import org.springframework.beans.factory.annotation.Value;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
/**
*
* @author bertocco
*/
@Repository
public class NodeDAO {
......@@ -126,16 +123,6 @@ public class NodeDAO {
return Optional.of(node);
}
public Optional<String> deleteNode(String path) {
// To be filled
// In case of failure return empty object to trigger HTTP 500
// status code for InternalFault
return Optional.of("OK");
}
private String getFirstLevelChildrenSelector(String path) {
String select = "(SELECT path FROM node WHERE node_id = (SELECT node_id FROM node_vos_path WHERE vos_path = ?))::varchar || '";
......
package it.inaf.oats.vospace;
import static it.inaf.oats.vospace.CreateNodeControllerTest.getResourceFileContent;
import it.inaf.oats.vospace.datamodel.NodeProperties;
import it.inaf.oats.vospace.persistence.NodeDAO;
import java.util.List;
import java.util.Optional;
import net.ivoa.xml.vospace.v2.ContainerNode;
import net.ivoa.xml.vospace.v2.DataNode;
import net.ivoa.xml.vospace.v2.LinkNode;
import net.ivoa.xml.vospace.v2.Node;
import net.ivoa.xml.vospace.v2.Property;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
......@@ -17,6 +21,7 @@ import org.springframework.test.web.servlet.MockMvc;
import org.junit.jupiter.api.Test;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.when;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
......@@ -34,10 +39,6 @@ public class DeleteNodeControllerTest {
@MockBean
private NodeDAO nodeDao;
@SpyBean
@Autowired
private DeleteNodeController controller;
@Autowired
private MockMvc mockMvc;
......@@ -51,157 +52,156 @@ public class DeleteNodeControllerTest {
.delete("/nodes")
.header("Authorization", "Bearer user2_token"))
.andExpect(status().isForbidden());
/*
mockMvc.perform(delete("/members/1").
.header("Authorization", "Bearer user2_token"))
.andExpect(status().isNotFound());
mockMvc.perform(delete("/")
.header("Authorization", "Bearer user2_token"))
.andExpect(status().isNotFound());
*/
}
@Test
public void testNodeNotFound() throws Exception {
public void testDeleteFirstLevelNode() throws Exception {
when(nodeDao.listNode(eq("/mynode"))).thenReturn(Optional.of(getDataNode()));
when(nodeDao.listNode(eq("/mynode"))).thenReturn(Optional.of(getWritableDataNode()));
mockMvc.perform(MockMvcRequestBuilders
.delete("/nodes/mynode")
.header("Authorization", "Bearer user2_token"))
.andExpect(status().isOk());
/*
mockMvc.perform(delete("/members/1").
.header("Authorization", "Bearer user2_token"))
.andExpect(status().isNotFound());
mockMvc.perform(delete("/")
.header("Authorization", "Bearer user2_token"))
.andExpect(status().isNotFound());
*/
}
/*
@Test
public void testDeleteRoot1() throws Exception {
mockMvc.perform(put("/nodes/mydata1")
.header("Authorization", "Bearer user2_token"))
//.content(requestBody)
//.contentType(MediaType.APPLICATION_JSON)
//.accept(MediaType.APPLICATION_XML))
//.andDo(print())
.andExpect(status().isOk());
}
@Test
public void testDeleteRoot2() throws Exception {
public void testDeleteMoreLevelNode() throws Exception {
when(nodeDao.listNode(eq("/mynode"))).thenReturn(Optional.of(getWritableDataNode("/mynode")));
when(nodeDao.listNode(eq("/mynode/middlenode"))).thenReturn(Optional.of(getWritableDataNode("/mynode/middlenode")));
when(nodeDao.listNode(eq("/mynode/middlenode/myfile.txt"))).thenReturn(Optional.of(getWritableDataNode("/mynode/middlenode/myfile.txt")));
mockMvc.perform(put("/nodes/mydata1")
mockMvc.perform(MockMvcRequestBuilders
.delete("/nodes/mynode/middlenode/myfile.txt")
.header("Authorization", "Bearer user2_token"))
//.content(requestBody)
//.contentType(MediaType.APPLICATION_JSON)
//.accept(MediaType.APPLICATION_XML))
//.andDo(print())
.andExpect(status().isOk());
}
@Test
public void testDeleteExistingNodeInRoot() throws Exception {
public void testLeafNodeNotFound() throws Exception {
mockMvc.perform(put("/nodes/mydata1")
.header("Authorization", "Bearer user2_token"))
//.content(requestBody)
//.contentType(MediaType.APPLICATION_JSON)
//.accept(MediaType.APPLICATION_XML))
//.andDo(print())
.andExpect(status().isOk());
when(nodeDao.listNode(eq("/mynode"))).thenReturn(Optional.of(getWritableDataNode("/mynode")));
mockMvc.perform(MockMvcRequestBuilders
.delete("/nodes/mynode/notexisting")
.header("Authorization", "Bearer user2_token"))
.andExpect(status().isNotFound());
}
@Test
public void testDeleteExistingNodeLeaf() throws Exception {
public void testMiddleLevelNodeNotFound() throws Exception {
mockMvc.perform(put("/nodes/mydata1")
.header("Authorization", "Bearer user2_token"))
//.content(requestBody)
//.contentType(MediaType.APPLICATION_JSON)
//.accept(MediaType.APPLICATION_XML))
//.andDo(print())
.andExpect(status().isOk());
when(nodeDao.listNode(eq("/mynode"))).thenReturn(Optional.of(getWritableDataNode("/mynode")));
when(nodeDao.listNode(eq("/mynode/middlenode/myfile.txt"))).thenReturn(Optional.of(getWritableDataNode("/mynode/middlenode/myfile.txt")));
mockMvc.perform(MockMvcRequestBuilders
.delete("/mynode/middlenode/myfile.txt")
.header("Authorization", "Bearer user2_token"))
.andExpect(status().isNotFound());
}
@Test
public void testDeleteExistingDataLinkInRoot() throws Exception {
public void testLinkNodeLeafDelete() throws Exception {
mockMvc.perform(put("/nodes/mydata1")
when(nodeDao.listNode(eq("/mynode"))).thenReturn(Optional.of(getWritableLinkNode("/mynode")));
mockMvc.perform(MockMvcRequestBuilders
.delete("/nodes/mynode")
.header("Authorization", "Bearer user2_token"))
//.content(requestBody)
//.contentType(MediaType.APPLICATION_JSON)
//.accept(MediaType.APPLICATION_XML))
//.andDo(print())
.andExpect(status().isOk());
}
@Test
public void testDeleteExistingDataLinkLeaf() throws Exception {
public void testMiddleLevelLinkNodeDelete() throws Exception {
mockMvc.perform(put("/nodes/mydata1")
.header("Authorization", "Bearer user2_token"))
//.content(requestBody)
//.contentType(MediaType.APPLICATION_JSON)
//.accept(MediaType.APPLICATION_XML))
//.andDo(print())
.andExpect(status().isOk());
when(nodeDao.listNode(eq("/mynode"))).thenReturn(Optional.of(getWritableDataNode("/mynode")));
when(nodeDao.listNode(eq("/mynode/middlenode"))).thenReturn(Optional.of(getWritableLinkNode("/mynode/middlenode")));
when(nodeDao.listNode(eq("/mynode/middlenode/myfile.txt"))).thenReturn(Optional.of(getWritableDataNode("/mynode/middlenode/myfile.txt")));
mockMvc.perform(MockMvcRequestBuilders
.delete("/nodes/mynode/middlenode/myfile.txt")
.header("Authorization", "Bearer user2_token"))
.andExpect(status().isBadRequest());
}
@Test
public void testDeleteExistingNodeWithDataLinkInPath() throws Exception {
public void testDeleteMoreLevelNodeNotAllowed() throws Exception {
mockMvc.perform(put("/nodes/mydata1")
.header("Authorization", "Bearer user2_token"))
//.content(requestBody)
//.contentType(MediaType.APPLICATION_JSON)
//.accept(MediaType.APPLICATION_XML))
//.andDo(print())
.andExpect(status().isOk());
when(nodeDao.listNode(eq("/mynode"))).thenReturn(Optional.of(getWritableDataNode("/mynode")));
when(nodeDao.listNode(eq("/mynode/middlenode"))).thenReturn(Optional.of(getWritableDataNode("/mynode/middlenode")));
when(nodeDao.listNode(eq("/mynode/middlenode/myfile.txt"))).thenReturn(Optional.of(getWritableDataNode("/mynode/middlenode/myfile.txt")));
mockMvc.perform(MockMvcRequestBuilders
.delete("/nodes/mynode/middlenode/myfile.txt"))
.andExpect(status().isForbidden());
}
*/
private Optional<Node> getRootNode() {
ContainerNode root = new ContainerNode();
root.setUri(URI_PREFIX + "/");
root.getNodes().add(getDataNode());
root.getNodes().add(getWritableDataNode());
return Optional.of(root);
}
private Node getDataNode() {
private Node getWritableDataNode() {
DataNode node = new DataNode();
List nodeProperties = node.getProperties();
Property groupWriteProp = new Property();
groupWriteProp.setUri(NodeProperties.GROUP_WRITE_URI);
groupWriteProp.setValue("group1");
nodeProperties.add(groupWriteProp);
node.setUri(URI_PREFIX + "/mynode");
return node;
}
private Node getWritableDataNode(String path) {
DataNode node = new DataNode();
List nodeProperties = node.getProperties();
Property groupWriteProp = new Property();
groupWriteProp.setUri(NodeProperties.GROUP_WRITE_URI);
groupWriteProp.setValue("group1");
nodeProperties.add(groupWriteProp);
node.setUri(URI_PREFIX + path);
return node;
}
private LinkNode getWritableLinkNode(String path) {
LinkNode myNode = new LinkNode();
// Set parent node address at /
myNode.setUri("vos://example.com!vospace" + path);
// Set groupwrite property
Property groups = new Property();
groups.setUri("ivo://ivoa.net/vospace/core#groupwrite");
groups.setValue("group1");
myNode.setProperties(List.of(groups));
return myNode;
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment