package edu.unc.lib.dl.admin.controller;
import java.io.File;
import java.io.IOException;
import java.util.Map;
import java.util.HashMap;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import edu.unc.lib.dl.acl.util.AccessGroupConstants;
import edu.unc.lib.dl.acl.util.AccessGroupSet;
import edu.unc.lib.dl.acl.util.GroupsThreadStore;
import edu.unc.lib.dl.util.RedisWorkerConstants.DepositField;
import edu.unc.lib.dl.util.RedisWorkerConstants.DepositAction;
import edu.unc.lib.dl.util.RedisWorkerConstants.DepositState;
import edu.unc.lib.dl.util.MetsHeaderScanner;
import edu.unc.lib.dl.fedora.PID;
import edu.unc.lib.dl.util.DepositConstants;
import edu.unc.lib.dl.util.DepositStatusFactory;
@Controller
public class ResubmitIngestController {
private static final Logger log = LoggerFactory.getLogger(ResubmitIngestController.class);
@Autowired
private DepositStatusFactory depositStatusFactory;
@Autowired
private File depositsDirectory;
@RequestMapping(value = "ingest/{pid}/resubmit", method = RequestMethod.POST)
public @ResponseBody
Map<String, ? extends Object> handleResubmit(@PathVariable("pid") String pid, @RequestParam("file") MultipartFile uploadedFile, HttpServletRequest request, HttpServletResponse response) {
Map<String, Object> result = new HashMap<String, Object>();
PID depositPid = new PID(pid);
// Try to retrieve the deposit status
Map<String, String> status = depositStatusFactory.get(depositPid.getUUID());
if (status == null || status.isEmpty()) {
response.setStatus(400);
result.put("error", "Couldn't find the deposit.");
log.error("Tried to resubmit deposit PID {} but couldn't find it", depositPid);
return result;
}
// Check that the current user is either an admin or was the depositor
AccessGroupSet groups = GroupsThreadStore.getGroups();
String depositorName = status.get(DepositField.depositorName.name());
if (!(groups.contains(AccessGroupConstants.ADMIN_GROUP) || depositorName.equals(GroupsThreadStore.getUsername()))) {
response.setStatus(401);
return result;
}
// Check that the deposit is in the failed or paused state
String state = status.get(DepositField.state.name());
if (state == null || !(state.equals(DepositState.failed.name()) || state.equals(DepositState.paused.name()))) {
response.setStatus(400);
result.put("error", "The deposit must be paused or failed.");
log.error("Tried to resubmit deposit {} but it isn't in the failed or paused state", depositPid);
return result;
}
// Create the resubmit deposit directory
String resubmitDirName;
try {
resubmitDirName = createResubmitDirectory();
} catch (IOException e) {
response.setStatus(500);
result.put("error", "Couldn't save the resubmitted ingest package.");
log.error("Couldn't create a resubmit directory for deposit PID " + depositPid, e);
return result;
}
File resubmitDir = new File(depositsDirectory, resubmitDirName);
File resubmitDataDir = new File(resubmitDir, DepositConstants.DATA_DIR);
// Transfer the uploaded file to the resubmit data directory
File resubmitPackageFile = new File(resubmitDataDir, uploadedFile.getOriginalFilename());
try {
uploadedFile.transferTo(resubmitPackageFile);
} catch (IOException e) {
response.setStatus(500);
result.put("error", "Couldn't save the resubmitted ingest package.");
log.error("Couldn't transfer the resubmitted ingest package for deposit PID " + depositPid, e);
return result;
}
// Scan the ingest file
MetsHeaderScanner scanner = new MetsHeaderScanner();
try {
scanner.scan(resubmitPackageFile, uploadedFile.getOriginalFilename());
} catch (Exception e) {
response.setStatus(500);
result.put("error", "Couldn't scan the resubmitted ingest package.");
log.error("Error scanning the resubmitted ingest package for deposit PID " + depositPid, e);
return result;
}
// Check that the ingest file has the same deposit pid as the deposit status
PID depositPackageId = scanner.getObjID();
if (depositPackageId == null) {
response.setStatus(400);
result.put("error", "The resubmitted ingest package doesn't have an ID.");
log.error("The resubmitted ingest package for deposit PID {} doesn't have an ID", depositPid);
return result;
}
if (!depositPackageId.equals(depositPid)) {
response.setStatus(400);
result.put("error", "The resubmitted ingest package doesn't match the deposit.");
log.error("The resubmitted ingest package doesn't match the deposit. The deposit has PID {} but the package has ID {}.", depositPid, depositPackageId);
return result;
}
// Set new deposit status
depositStatusFactory.set(depositPid.getUUID(), DepositField.resubmitDirName, resubmitDirName);
depositStatusFactory.set(depositPid.getUUID(), DepositField.resubmitFileName, resubmitPackageFile.getName());
depositStatusFactory.set(depositPid.getUUID(), DepositField.actionRequest, DepositAction.resubmit.name());
// Return result indicating that we've submitted the file for resubmission
response.setStatus(202);
result.put("pid", pid);
return result;
}
/**
* Create a resubmit directory inside the deposits directory, containing a data directory.
*
* @return the name of the resubmit directory (relative to the deposits directory)
*/
private String createResubmitDirectory() throws IOException {
File resubmitDir = File.createTempFile(DepositConstants.RESUBMIT_DIR_PREFIX, "", depositsDirectory);
resubmitDir.delete();
resubmitDir.mkdir();
File dataDir = new File(resubmitDir, DepositConstants.DATA_DIR);
dataDir.mkdir();
return resubmitDir.getName();
}
}