Newer
Older
/*
* This file is part of vospace-rest
* Copyright (C) 2021 Istituto Nazionale di Astrofisica
* SPDX-License-Identifier: GPL-3.0-or-later
*/
package it.inaf.oats.vospace;
import it.inaf.ia2.aa.data.User;
import it.inaf.oats.vospace.datamodel.NodeUtils;
import it.inaf.oats.vospace.exception.NodeNotFoundException;
import it.inaf.oats.vospace.exception.PermissionDeniedException;
import it.inaf.oats.vospace.persistence.NodeDAO;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
Sonia Zorba
committed
import net.ivoa.xml.vospace.v2.DataNode;
Sonia Zorba
committed
import net.ivoa.xml.vospace.v2.View;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class SetNodeController extends BaseNodeController {
Sonia Zorba
committed
private static final Logger LOG = LoggerFactory.getLogger(SetNodeController.class);
@Autowired
private NodeDAO nodeDao;
@PostMapping(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})
public ResponseEntity<Node> setNode(@RequestBody Node node, User principal, HttpServletRequest request,
@RequestParam(value = "recursive", required = false, defaultValue = "false") boolean recursive) {
Sonia Zorba
committed
//The service SHALL throw a HTTP 404 status code including a NodeNotFound
//fault in the entity-body if the target Node does not exist
Node toBeModifiedNode = nodeDao.listNode(path)
Sonia Zorba
committed
.orElseThrow(() -> new NodeNotFoundException(path));
// The service SHALL throw a HTTP 403 status code including a PermissionDenied fault
// in the entity-body if the user does not have permissions to perform the operation
Sonia Zorba
committed
if (!NodeUtils.checkIfWritable(toBeModifiedNode, principal.getName(), principal.getGroups())) {
Sonia Zorba
committed
// The service SHALL throw a HTTP 403 status code including a PermissionDenied fault
// in the entity-body if the request attempts to modify a read-only Property.
// This method cannot be used to modify the Node type.
String storedNodeType = toBeModifiedNode.getType();
String newNodeType = node.getType();
Sonia Zorba
committed
if (!storedNodeType.equals(newNodeType)) {
LOG.debug("setNode trying to modify type. Stored ", storedNodeType + ", requested " + newNodeType);
Sonia Zorba
committed
throw new PermissionDeniedException(path);
}
// This method cannot be used to modify the accepts or provides list of Views for the Node.
// Only DataNodes has Views (see VOSpace Data Model)
if (node instanceof DataNode) {
checkViews((DataNode) node, (DataNode) toBeModifiedNode);
}
//The service SHOULD throw a HTTP 500 status code including an InternalFault fault
// in the entity-body if the operation fails
// Done in NodeDAO
// to be fixed
// A HTTP 200 status code and a Node representation in the entity-body The full
// expanded record for the node SHALL be returned, including any xsi:type
// specific extensions.
return ResponseEntity.ok(nodeDao.setNode(node, recursive));
Sonia Zorba
committed
}
private void checkViews(DataNode requestedDataNode, DataNode savedDataNode) {
checkAcceptsView(requestedDataNode, savedDataNode);
checkProvidesView(requestedDataNode, savedDataNode);
}
private void checkAcceptsView(DataNode requestedDataNode, DataNode savedDataNode) {
List<View> requestedAcceptedViews = requestedDataNode.getAccepts();
List<View> savedAcceptedViews = savedDataNode.getAccepts();
// If views are present it is necessary to perform the check, otherwise
// it means that the user is not going to change them
if (!requestedAcceptedViews.isEmpty() && !checkIfViewsAreEquals(requestedAcceptedViews, savedAcceptedViews)) {
LOG.debug("setNode trying to modify accepted Views.");
throw new PermissionDeniedException("Trying to modify accepted views");
Sonia Zorba
committed
98
99
100
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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
}
private void checkProvidesView(DataNode requestedDataNode, DataNode savedDataNode) {
List<View> requestedProvidedViews = requestedDataNode.getProvides();
List<View> savedProvidedViews = savedDataNode.getProvides();
// If views are present it is necessary to perform the check, otherwise
// it means that the user is not going to change them
if (!requestedProvidedViews.isEmpty() && !checkIfViewsAreEquals(requestedProvidedViews, savedProvidedViews)) {
LOG.debug("setNode trying to modify provided Views.");
throw new PermissionDeniedException("Trying to modify provided views");
}
}
private boolean checkIfViewsAreEquals(List<View> viewsA, List<View> viewsB) {
boolean viewsAreEqual = true;
if ((viewsA == null || viewsA.isEmpty())
&& (viewsB == null || viewsB.isEmpty())) {
return true;
}
if ((viewsA == null || viewsA.isEmpty())
|| (viewsB == null || viewsB.isEmpty())) {
return false;
}
if (viewsA.size() != viewsB.size()) {
return false;
}
for (int i = 0; i < viewsA.size(); i++) {
String viewUriA = viewsA.get(i).getUri();
boolean found = false;
for (int j = 0; j < viewsB.size(); j++) {
String viewUriB = viewsB.get(i).getUri();
if (viewUriA.compareTo(viewUriB) == 0) {
found = true;
}
}
if (found == false) {
viewsAreEqual = false;
break;
}
}
return viewsAreEqual;
}