Newer
Older
/*
* This file is part of vospace-rest
* Copyright (C) 2021 Istituto Nazionale di Astrofisica
* SPDX-License-Identifier: GPL-3.0-or-later
*/
Sonia Zorba
committed
import it.inaf.ia2.aa.data.User;
Nicola Fulvio Calabria
committed
import it.inaf.oats.vospace.datamodel.NodeProperties;
import it.inaf.oats.vospace.datamodel.NodeUtils;
import net.ivoa.xml.vospace.v2.Node;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.beans.factory.annotation.Autowired;
import it.inaf.oats.vospace.persistence.NodeDAO;
Nicola Fulvio Calabria
committed
import org.springframework.beans.factory.annotation.Value;
Sonia Zorba
committed
import org.springframework.web.bind.annotation.PutMapping;
Nicola Fulvio Calabria
committed
import it.inaf.oats.vospace.exception.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Nicola Fulvio Calabria
committed
import net.ivoa.xml.vospace.v2.Property;
Sonia Zorba
committed
public class CreateNodeController extends BaseNodeController {
private static final Logger LOG = LoggerFactory.getLogger(CreateNodeController.class);
Nicola Fulvio Calabria
committed
Sonia Zorba
committed
@Autowired
private NodeDAO nodeDao;
Nicola Fulvio Calabria
committed
@Value("${vospace-authority}")
private String authority;
Sonia Zorba
committed
@PutMapping(value = {"/nodes", "/nodes/**"},
consumes = {MediaType.APPLICATION_XML_VALUE, MediaType.TEXT_XML_VALUE, MediaType.APPLICATION_JSON_VALUE},
produces = {MediaType.APPLICATION_XML_VALUE, MediaType.TEXT_XML_VALUE, MediaType.APPLICATION_JSON_VALUE})
Sonia Zorba
committed
public Node createNode(@RequestBody Node node, User principal) {
LOG.debug("createNode called for node with URI {}", node.getUri());
Nicola Fulvio Calabria
committed
// Validate payload node URI
Nicola Fulvio Calabria
committed
if (!isValidURI(node.getUri())) {
Nicola Fulvio Calabria
committed
throw new InvalidURIException(node.getUri());
}
String path;
if(getPath() == null) {
LOG.debug("createNode called internally with null path");
path = node.getUri().replaceAll("vos://[^/]+", "");
} else {
path = getPath();
LOG.debug("createNode called for path {}", path);
Nicola Fulvio Calabria
committed
}
Nicola Fulvio Calabria
committed
// Check if payload URI is consistent with http request
Nicola Fulvio Calabria
committed
if (!isUrlConsistentWithPayloadURI(node.getUri(), path)) {
Nicola Fulvio Calabria
committed
throw new InvalidURIException(node.getUri(), path);
}
Nicola Fulvio Calabria
committed
// Check if another node is already present at specified path
Nicola Fulvio Calabria
committed
// This checks if the user is trying to insert the root node at "/" too
if (nodeDao.listNode(path).isPresent()) {
throw new DuplicateNodeException(path);
}
// Retrieve parent node
Node parentNode = nodeDao.listNode(getParentPath(path))
.orElseThrow(() -> new ContainerNotFoundException(getParentPath(path)));
Nicola Fulvio Calabria
committed
// Check if parent node is not a Container node and in case throw
// appropriate exception
if (!parentNode.getType().equals("vos:ContainerNode")) {
if (parentNode.getType().equals("vos:LinkNode")) {
throw new LinkFoundException(getParentPath(path));
} else {
throw new ContainerNotFoundException(getParentPath(path));
}
Nicola Fulvio Calabria
committed
}
if (!NodeUtils.checkIfWritable(parentNode, principal.getName(), principal.getGroups())) {
throw new PermissionDeniedException(path);
Nicola Fulvio Calabria
committed
}
Nicola Fulvio Calabria
committed
Nicola Fulvio Calabria
committed
// Check if node creator property is set. If not set it according to
// token. In case of creator mistmatch between node and token throw
// exception
String creator = NodeProperties.getNodePropertyByURI(
node, NodeProperties.CREATOR_URI);
Nicola Fulvio Calabria
committed
if (creator == null) {
Nicola Fulvio Calabria
committed
Property creatorProperty = new Property();
creatorProperty.setUri(NodeProperties.CREATOR_URI);
creatorProperty.setValue(principal.getName());
node.getProperties().add(creatorProperty);
} else {
Nicola Fulvio Calabria
committed
if (!creator.equals(principal.getName())) // maybe a more specific exception would be more appropriate?
{
Nicola Fulvio Calabria
committed
throw new PermissionDeniedException(path);
Nicola Fulvio Calabria
committed
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
}
}
// If payload has no read groups specified, inherit from parent node
String payloadReadGroups = NodeProperties.getNodePropertyByURI(
node, NodeProperties.GROUP_READ_URI);
if (payloadReadGroups == null) {
String parentNodeReadGroups = NodeProperties.getNodePropertyByURI(
parentNode, NodeProperties.GROUP_READ_URI);
if (parentNodeReadGroups != null) {
Property readGroups = new Property();
readGroups.setUri(NodeProperties.GROUP_READ_URI);
readGroups.setValue(parentNodeReadGroups);
node.getProperties().add(readGroups);
}
}
// If payload has no write groups specified, inherit from parent node
String payloadWriteGroups = NodeProperties.getNodePropertyByURI(
node, NodeProperties.GROUP_WRITE_URI);
if (payloadWriteGroups == null) {
String parentNodeWriteGroups = NodeProperties.getNodePropertyByURI(
parentNode, NodeProperties.GROUP_WRITE_URI);
if (parentNodeWriteGroups != null) {
Property writeGroups = new Property();
writeGroups.setUri(NodeProperties.GROUP_WRITE_URI);
writeGroups.setValue(parentNodeWriteGroups);
node.getProperties().add(writeGroups);
}
}
Nicola Fulvio Calabria
committed
nodeDao.createNode(node);
Sonia Zorba
committed
return node;
Nicola Fulvio Calabria
committed
Nicola Fulvio Calabria
committed
// Assuming that this service implementation uses only ! as a separator
// in the authority part of the URI
Nicola Fulvio Calabria
committed
private boolean isValidURI(String nodeURI) {
Nicola Fulvio Calabria
committed
String parsedAuthority;
Nicola Fulvio Calabria
committed
if (!nodeURI.startsWith("vos://")) {
Nicola Fulvio Calabria
committed
return false;
} else {
Nicola Fulvio Calabria
committed
parsedAuthority = nodeURI.replaceAll("vos://", "").split("/", -1)[0];
Nicola Fulvio Calabria
committed
}
Nicola Fulvio Calabria
committed
if (parsedAuthority.isEmpty()
|| !parsedAuthority.replace("~", "!").equals(authority)) {
Nicola Fulvio Calabria
committed
return false;
Nicola Fulvio Calabria
committed
}
return true;
Nicola Fulvio Calabria
committed
}
private boolean isUrlConsistentWithPayloadURI(String nodeURI, String path) {
// It's assumed that nodeURI has been validated to be in the expected
// form vos://authority[!~]somepath/mynode..."
return nodeURI.replaceAll("vos://[^/]+", "").equals(path);
}