64640: Move PATCH request for bitstreams in bundles

This commit is contained in:
Kristof De Langhe
2019-09-25 12:36:06 +02:00
parent 6c807f8a62
commit 04a7a31797
7 changed files with 223 additions and 2 deletions

View File

@@ -268,6 +268,30 @@ public class BundleServiceImpl extends DSpaceObjectServiceImpl<Bundle> implement
return authorizeService.getPolicies(context, bundle);
}
@Override
public void moveBitstream(Context context, Bundle bundle, int from, int to)
throws AuthorizeException, SQLException {
List<Bitstream> bitstreams = bundle.getBitstreams();
if (bitstreams.size() < 1 || from >= bitstreams.size() || to >= bitstreams.size() || from < 0 || to < 0) {
throw new IllegalArgumentException(
"Invalid 'from' and 'to' arguments supplied for moving a bitstream within bundle " +
bundle.getID() + ". from: " + from + "; to: " + to
);
}
List<UUID> bitstreamIds = new LinkedList<>();
for (Bitstream bitstream : bitstreams) {
bitstreamIds.add(bitstream.getID());
}
if (from < to) {
bitstreamIds.add(to + 1, bitstreamIds.get(from));
bitstreamIds.remove(from);
} else {
bitstreamIds.add(to, bitstreamIds.get(from));
bitstreamIds.remove(from + 1);
}
setOrder(context, bundle, bitstreamIds.toArray(new UUID[bitstreamIds.size()]));
}
@Override
public void setOrder(Context context, Bundle bundle, UUID[] bitstreamIds) throws AuthorizeException, SQLException {
authorizeService.authorizeAction(context, bundle, Constants.WRITE);

View File

@@ -109,6 +109,18 @@ public interface BundleService extends DSpaceObjectService<Bundle>, DSpaceObject
public List<ResourcePolicy> getBundlePolicies(Context context, Bundle bundle) throws SQLException;
/**
* Moves a bitstream within a bundle from one place to another, shifting all other bitstreams in the process
*
* @param context DSpace Context
* @param bundle The bitstream bundle
* @param from The index of the bitstream to move
* @param to The index to move the bitstream to
* @throws AuthorizeException when an SQL error has occurred (querying DSpace)
* @throws SQLException If the user can't make the changes
*/
public void moveBitstream(Context context, Bundle bundle, int from, int to) throws AuthorizeException, SQLException;
/**
* Changes bitstream order according to the array
*

View File

@@ -10,11 +10,16 @@ package org.dspace.app.rest.repository;
import java.sql.SQLException;
import java.util.UUID;
import javax.servlet.http.HttpServletRequest;
import org.dspace.app.rest.converter.BundleConverter;
import org.dspace.app.rest.model.BundleRest;
import org.dspace.app.rest.model.hateoas.BundleResource;
import org.dspace.app.rest.model.hateoas.DSpaceResource;
import org.dspace.app.rest.model.patch.Patch;
import org.dspace.app.rest.repository.patch.BundlePatch;
import org.dspace.app.rest.repository.patch.DSpaceObjectPatch;
import org.dspace.authorize.AuthorizeException;
import org.dspace.content.Bundle;
import org.dspace.content.service.BundleService;
import org.dspace.core.Context;
@@ -36,9 +41,13 @@ public class BundleRestRepository extends DSpaceObjectRestRepository<Bundle, Bun
@Autowired
private BundleService bundleService;
@Autowired
private BundlePatch bundlePatch;
public BundleRestRepository(BundleService dsoService,
BundleConverter dsoConverter) {
super(dsoService, dsoConverter, new DSpaceObjectPatch<BundleRest>() {});
BundleConverter dsoConverter,
BundlePatch dsoPatch) {
super(dsoService, dsoConverter, dsoPatch);
this.bundleService = dsoService;
}
@@ -60,6 +69,13 @@ public class BundleRestRepository extends DSpaceObjectRestRepository<Bundle, Bun
throw new RuntimeException("Method not allowed!");
}
@Override
@PreAuthorize("hasPermission(#uuid, 'BUNDLE', 'WRITE')")
protected void patch(Context context, HttpServletRequest request, String apiCategory, String model, UUID uuid,
Patch patch) throws AuthorizeException, SQLException {
patchDSpaceObject(apiCategory, model, uuid, patch);
}
public Class<BundleRest> getDomainClass() {
return BundleRest.class;
}

View File

@@ -0,0 +1,23 @@
package org.dspace.app.rest.repository.patch;
import org.dspace.app.rest.model.BundleRest;
import org.dspace.app.rest.model.patch.Operation;
import org.dspace.app.rest.repository.patch.factories.BundleOperationFactory;
import org.dspace.app.rest.repository.patch.factories.impl.ResourcePatchOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* Created by kristof on 24/09/2019
*/
@Component
public class BundlePatch extends DSpaceObjectPatch<BundleRest> {
@Autowired
BundleOperationFactory patchFactory;
protected BundleRest move(BundleRest restModel, Operation operation) {
ResourcePatchOperation<BundleRest> patchOperation = patchFactory.getMoveOperation();
return patchOperation.perform(restModel, operation);
}
}

View File

@@ -0,0 +1,21 @@
package org.dspace.app.rest.repository.patch.factories;
import org.dspace.app.rest.model.BundleRest;
import org.dspace.app.rest.repository.patch.factories.impl.BundleMoveOperation;
import org.dspace.app.rest.repository.patch.factories.impl.ResourcePatchOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* Created by kristof on 24/09/2019
*/
@Component
public class BundleOperationFactory {
@Autowired
BundleMoveOperation bundleMoveOperation;
public ResourcePatchOperation<BundleRest> getMoveOperation() {
return bundleMoveOperation;
}
}

View File

@@ -0,0 +1,68 @@
package org.dspace.app.rest.repository.patch.factories.impl;
import java.sql.SQLException;
import org.dspace.app.rest.exception.DSpaceBadRequestException;
import org.dspace.app.rest.model.BundleRest;
import org.dspace.app.rest.model.patch.Operation;
import org.dspace.app.rest.utils.ContextUtil;
import org.dspace.authorize.AuthorizeException;
import org.dspace.content.Bundle;
import org.dspace.content.service.BundleService;
import org.dspace.core.Context;
import org.dspace.services.RequestService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* Created by kristof on 24/09/2019
*/
@Component
public class BundleMoveOperation extends MovePatchOperation<BundleRest, Integer> {
@Autowired
BundleService bundleService;
@Autowired
RequestService requestService;
@Override
public BundleRest move(BundleRest resource, Operation operation) {
Context context = ContextUtil.obtainContext(requestService.getCurrentRequest().getServletRequest());
try {
Bundle bundle = bundleService.findByIdOrLegacyId(context, resource.getId());
int totalAmount = bundle.getBitstreams().size();
if(totalAmount < 1) {
throw new DSpaceBadRequestException(createMoveExceptionMessage(bundle, from, to, "No sub-communities found."));
}
if(from >= totalAmount) {
throw new DSpaceBadRequestException(createMoveExceptionMessage(bundle, from, to, "\"from\" location out of bounds. Latest available position: " + (totalAmount-1)));
}
if(to >= totalAmount) {
throw new DSpaceBadRequestException(createMoveExceptionMessage(bundle, from, to, "\"to\" location out of bounds. Latest available position: " + (totalAmount-1)));
}
bundleService.moveBitstream(context, bundle, from, to);
} catch (SQLException | AuthorizeException e) {
throw new DSpaceBadRequestException(e.getMessage(), e);
}
return resource;
}
@Override
protected Class<Integer[]> getArrayClassForEvaluation() {
return Integer[].class;
}
@Override
protected Class<Integer> getClassForEvaluation() {
return Integer.class;
}
private String createMoveExceptionMessage(Bundle bundle, int from, int to, String message) {
return "Failed moving bitstreams of bundle with id " + bundle.getID() + " from location " + from + " to " + to + ": " + message;
}
}

View File

@@ -0,0 +1,57 @@
package org.dspace.app.rest.repository.patch.factories.impl;
import org.apache.commons.lang3.StringUtils;
import org.dspace.app.rest.exception.DSpaceBadRequestException;
import org.dspace.app.rest.model.RestModel;
import org.dspace.app.rest.model.patch.MoveOperation;
import org.dspace.app.rest.model.patch.Operation;
/**
* Created by kristof on 24/09/2019
*/
public abstract class MovePatchOperation<R extends RestModel, T> extends PatchOperation<R, T> {
protected int from;
protected int to;
@Override
public R perform(R resource, Operation operation) {
checkMoveOperation(operation);
return move(resource, operation);
}
abstract R move(R resource, Operation operation);
private void checkMoveOperation(Operation operation) {
if(!(operation instanceof MoveOperation)) {
throw new DSpaceBadRequestException("Expected a MoveOperation, but received " + operation.getClass().getName() + " instead.");
}
from = getLocationFromPath(((MoveOperation)operation).getFrom());
to = getLocationFromPath(operation.getPath());
if(from == to) {
throw new DSpaceBadRequestException("The \"from\" location must be different from the \"to\" location.");
}
if(from < 0) {
throw new DSpaceBadRequestException("A negative \"from\" location was provided: " + from);
}
if(to < 0) {
throw new DSpaceBadRequestException("A negative \"to\" location was provided: " + to);
}
}
protected int getLocationFromPath(String path) {
String[] parts = StringUtils.split(path, "/");
String locationStr;
if(parts.length > 1) {
if(StringUtils.equals(parts[parts.length-1], "href")) {
locationStr = parts[parts.length-2];
} else {
locationStr = parts[parts.length-1];
}
} else {
locationStr = parts[0];
}
return Integer.parseInt(locationStr);
}
}