405 lines
18 KiB
Java
405 lines
18 KiB
Java
package eu.eudat.depositinterface.dspacerepository.interfaces;
|
|
|
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
|
import com.fasterxml.jackson.databind.JsonNode;
|
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
import eu.eudat.depositinterface.dspacerepository.config.ConfigLoader;
|
|
import eu.eudat.depositinterface.dspacerepository.config.DSpaceConfig;
|
|
import eu.eudat.depositinterface.models.DMPDepositModel;
|
|
import eu.eudat.depositinterface.models.FileEnvelope;
|
|
import eu.eudat.depositinterface.repository.RepositoryDeposit;
|
|
import eu.eudat.depositinterface.repository.RepositoryDepositConfiguration;
|
|
import org.json.JSONObject;
|
|
import org.jsoup.Jsoup;
|
|
import org.jsoup.nodes.Document;
|
|
import org.jsoup.nodes.Element;
|
|
import org.slf4j.Logger;
|
|
import org.slf4j.LoggerFactory;
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
import org.springframework.core.env.Environment;
|
|
import org.springframework.http.*;
|
|
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
|
|
import org.springframework.stereotype.Component;
|
|
import org.springframework.util.LinkedMultiValueMap;
|
|
import org.springframework.util.MultiValueMap;
|
|
import org.springframework.web.client.RestTemplate;
|
|
|
|
import java.io.File;
|
|
import java.io.FileOutputStream;
|
|
import java.io.IOException;
|
|
import java.io.OutputStream;
|
|
import java.nio.file.Files;
|
|
import java.text.DateFormat;
|
|
import java.text.SimpleDateFormat;
|
|
import java.util.*;
|
|
import java.util.stream.Collectors;
|
|
|
|
@Component
|
|
public class DSpaceDeposit implements RepositoryDeposit {
|
|
private static final Logger logger = LoggerFactory.getLogger(DSpaceDeposit.class);
|
|
private static final ObjectMapper objectMapper = new ObjectMapper();
|
|
|
|
private final ConfigLoader configLoader;
|
|
private final Environment environment;
|
|
|
|
private String csrfToken;
|
|
private String bearerToken;
|
|
private String submitterId;
|
|
|
|
private String repositoryApiUrl;
|
|
|
|
@Autowired
|
|
public DSpaceDeposit(ConfigLoader configLoader, Environment environment){
|
|
this.configLoader = configLoader;
|
|
this.environment = environment;
|
|
}
|
|
|
|
@Override
|
|
public String deposit(String repositoryId, DMPDepositModel dmpDepositModel, String repositoryAccessToken) throws Exception {
|
|
|
|
DSpaceConfig dSpaceConfig = this.configLoader.getDSpaceConfig().stream().filter(x -> x.getRepositoryId().equals(repositoryId)).findFirst().orElse(null);
|
|
|
|
if (dSpaceConfig != null) {
|
|
|
|
this.repositoryApiUrl = dSpaceConfig.getRepositoryUrl();
|
|
|
|
this.setCsrfToken();
|
|
this.setBearerToken(dSpaceConfig.getEmail(), dSpaceConfig.getPassword());
|
|
this.setSubmitterId();
|
|
|
|
if (dmpDepositModel.getPreviousDOI() == null || dmpDepositModel.getPreviousDOI().isEmpty()) {
|
|
RestTemplate restTemplate = new RestTemplate();
|
|
restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory());
|
|
|
|
HttpHeaders headers = this.createHeaders();
|
|
headers.setContentType(MediaType.APPLICATION_JSON);
|
|
String url = this.repositoryApiUrl + "submission/workspaceitems?owningCollection=" + dSpaceConfig.getCollection();
|
|
Object response = restTemplate.exchange(url, HttpMethod.POST, new HttpEntity<>("", headers), Object.class).getBody();
|
|
Map<String, Object> respMap = objectMapper.convertValue(response, Map.class);
|
|
String id = String.valueOf(respMap.get("id"));
|
|
respMap = (Map<String, Object>) respMap.get("_embedded");
|
|
respMap = (Map<String, Object>) respMap.get("item");
|
|
String itemId = String.valueOf(respMap.get("id"));
|
|
|
|
url = this.repositoryApiUrl + "submission/workspaceitems/" + id;
|
|
sendPatchRequest(url, "add", "/sections/traditionalpageone/dc.title", dmpDepositModel.getLabel());
|
|
DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
|
|
sendPatchRequest(url, "add", "/sections/traditionalpageone/dc.date.issued", df.format(new Date()));
|
|
|
|
PatchBooleanEntity entity = new PatchBooleanEntity();
|
|
entity.setOp("add");
|
|
entity.setPath("/sections/license/granted");
|
|
entity.setValue(true);
|
|
|
|
List<PatchBooleanEntity> entityList = new ArrayList<>();
|
|
entityList.add(entity);
|
|
logger.debug(objectMapper.writeValueAsString(entityList));
|
|
restTemplate.exchange(url, HttpMethod.PATCH, new HttpEntity<>(entityList, headers), Object.class);
|
|
|
|
sendPatchRequest(url, "add", "/sections/traditionalpageone/dc.contributor.author", "Argos User");
|
|
sendPatchRequest(url, "add", "/sections/traditionalpageone/dc.publisher", "Argos User");
|
|
|
|
this.uploadFiles(dmpDepositModel, url);
|
|
|
|
String workFlowId = this.createWorkflow(url);
|
|
|
|
this.setBearerToken(dSpaceConfig.getWorkflowEmail(), dSpaceConfig.getWorkflowPassword());
|
|
String claimedTaskId = this.createClaimedTask(workFlowId);
|
|
|
|
this.submitTask(claimedTaskId);
|
|
|
|
return this.getHandle(itemId);
|
|
|
|
}
|
|
else {
|
|
String itemId = this.getItemIdFromHandle(dSpaceConfig.getRepositoryRecordUrl(), dmpDepositModel.getPreviousDOI());
|
|
|
|
this.setBearerToken(dSpaceConfig.getWorkflowEmail(), dSpaceConfig.getWorkflowPassword());
|
|
String workSpaceItemId = this.createNewVersion(itemId);
|
|
|
|
this.deleteFiles(workSpaceItemId);
|
|
|
|
String workSpaceItemUrl = this.repositoryApiUrl + "submission/workspaceitems/" + workSpaceItemId;
|
|
|
|
this.uploadFiles(dmpDepositModel, workSpaceItemUrl);
|
|
|
|
String workFlowId = this.createWorkflow(workSpaceItemUrl);
|
|
|
|
String claimedTaskId = this.createClaimedTask(workFlowId);
|
|
|
|
this.submitTask(claimedTaskId);
|
|
|
|
return this.getHandle(itemId);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
private void deleteFiles(String workSpaceItemId){
|
|
RestTemplate restTemplate = new RestTemplate();
|
|
HttpHeaders headers = this.createHeaders();
|
|
String workSpaceItemUrl = this.repositoryApiUrl + "submission/workspaceitems/" + workSpaceItemId;
|
|
Object response = restTemplate.exchange(workSpaceItemUrl, HttpMethod.GET, new HttpEntity<>(headers), Object.class).getBody();
|
|
Map<String, Object> respMap = objectMapper.convertValue(response, Map.class);
|
|
respMap = (Map<String, Object>) respMap.get("sections");
|
|
respMap = (Map<String, Object>) respMap.get("upload");
|
|
List<Object> files = (List<Object>) respMap.get("files");
|
|
for(Object file: files){
|
|
respMap = objectMapper.convertValue(file, Map.class);
|
|
String fileId = String.valueOf(respMap.get("uuid"));
|
|
String bitStreamUrl = this.repositoryApiUrl + "core/bitstreams/" + fileId;
|
|
restTemplate.exchange(bitStreamUrl, HttpMethod.DELETE, new HttpEntity<>(headers), Object.class);
|
|
}
|
|
}
|
|
|
|
private String createNewVersion(String itemId){
|
|
RestTemplate restTemplate = new RestTemplate();
|
|
|
|
HttpHeaders headers = this.createHeaders();
|
|
headers.add("Content-Type", "text/uri-list");
|
|
|
|
String itemUrl = this.repositoryApiUrl + "core/items/" + itemId;
|
|
Object response = restTemplate.postForEntity(this.repositoryApiUrl + "versioning/versions", new HttpEntity<>(itemUrl, headers), Object.class).getBody();
|
|
Map<String, Object> respMap = objectMapper.convertValue(response, Map.class);
|
|
respMap = (Map<String, Object>) respMap.get("_links");
|
|
respMap = (Map<String, Object>) respMap.get("versionhistory");
|
|
String versionHistoryUrl = (String) respMap.get("href");
|
|
|
|
response = restTemplate.exchange(versionHistoryUrl, HttpMethod.GET, new HttpEntity<>(headers), Object.class).getBody();
|
|
respMap = objectMapper.convertValue(response, Map.class);
|
|
respMap = (Map<String, Object>) respMap.get("_links");
|
|
respMap = (Map<String, Object>) respMap.get("draftVersion");
|
|
String draftVersionUrl = (String) respMap.get("href");
|
|
|
|
response = restTemplate.exchange(draftVersionUrl, HttpMethod.GET, new HttpEntity<>(headers), Object.class).getBody();
|
|
respMap = objectMapper.convertValue(response, Map.class);
|
|
|
|
return String.valueOf(respMap.get("id"));
|
|
}
|
|
|
|
private String getHandle(String itemId){
|
|
RestTemplate restTemplate = new RestTemplate();
|
|
|
|
HttpHeaders headers = this.createHeaders();
|
|
String url = this.repositoryApiUrl + "core/items/" + itemId;
|
|
Object response = restTemplate.exchange(url, HttpMethod.GET, new HttpEntity<>(headers), Object.class).getBody();
|
|
Map<String, Object> respMap = objectMapper.convertValue(response, Map.class);
|
|
|
|
return (String) respMap.get("handle");
|
|
}
|
|
|
|
private void submitTask(String claimedTaskId){
|
|
RestTemplate restTemplate = new RestTemplate();
|
|
|
|
HttpHeaders headers = this.createHeaders();
|
|
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
|
|
|
|
MultiValueMap<String, Boolean> map = new LinkedMultiValueMap<>();
|
|
map.add("submit_approve", true);
|
|
|
|
HttpEntity<MultiValueMap<String, Boolean>> entity = new HttpEntity<>(map, headers);
|
|
String url = this.repositoryApiUrl + "workflow/claimedtasks/" + claimedTaskId;
|
|
restTemplate.exchange(url, HttpMethod.POST, entity, Object.class);
|
|
}
|
|
|
|
private String createClaimedTask(String workFlowId){
|
|
RestTemplate restTemplate = new RestTemplate();
|
|
|
|
HttpHeaders headers = this.createHeaders();
|
|
headers.add("Content-Type", "text/uri-list");
|
|
|
|
String poolTaskId = this.getPoolTaskId(workFlowId);
|
|
|
|
String pooltaskUrl = this.repositoryApiUrl + "workflow/pooltasks/" + poolTaskId;
|
|
Object response = restTemplate.postForEntity(this.repositoryApiUrl + "workflow/claimedtasks", new HttpEntity<>(pooltaskUrl, headers), Object.class).getBody();
|
|
Map<String, Object> respMap = objectMapper.convertValue(response, Map.class);
|
|
|
|
return String.valueOf(respMap.get("id"));
|
|
}
|
|
|
|
private String getPoolTaskId(String workFlowId){
|
|
RestTemplate restTemplate = new RestTemplate();
|
|
|
|
HttpHeaders headers = this.createHeaders();
|
|
String url = this.repositoryApiUrl + "workflow/pooltasks/search/findByUser?uuid=" + this.submitterId;
|
|
Object response = restTemplate.exchange(url, HttpMethod.GET, new HttpEntity<>(headers), Object.class).getBody();
|
|
Map<String, Object> respMap = objectMapper.convertValue(response, Map.class);
|
|
Object embedded = respMap.get("_embedded");
|
|
respMap = objectMapper.convertValue(embedded, Map.class);
|
|
List<Object> pooltasks = (List<Object>) respMap.get("pooltasks");
|
|
for(Object pooltask: pooltasks){
|
|
JsonNode task = objectMapper.valueToTree(pooltask);
|
|
JsonNode workFlowItem = task.get("_embedded").get("workflowitem");
|
|
int wfId = workFlowItem.get("id").asInt();
|
|
if(wfId == Integer.parseInt(workFlowId)){
|
|
return String.valueOf(task.get("id").asInt());
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
private String createWorkflow(String workSpaceItemUrl){
|
|
RestTemplate restTemplate = new RestTemplate();
|
|
|
|
HttpHeaders headers = this.createHeaders();
|
|
headers.add("Content-Type", "text/uri-list");
|
|
|
|
Object response = restTemplate.postForEntity(this.repositoryApiUrl + "workflow/workflowitems", new HttpEntity<>(workSpaceItemUrl, headers), Object.class).getBody();
|
|
Map<String, Object> respMap = objectMapper.convertValue(response, Map.class);
|
|
|
|
return String.valueOf(respMap.get("id"));
|
|
}
|
|
|
|
private void uploadFiles(DMPDepositModel dmpDepositModel, String url) throws IOException {
|
|
this.uploadFile(dmpDepositModel.getPdfFile().getFilename(), dmpDepositModel.getPdfFile().getFile(), url);
|
|
|
|
FileEnvelope rdaJsonEnvelope = dmpDepositModel.getRdaJsonFile();
|
|
HttpHeaders responseHeaders = new HttpHeaders();
|
|
responseHeaders.setContentLength(rdaJsonEnvelope.getFile().length());
|
|
responseHeaders.setContentType(MediaType.APPLICATION_OCTET_STREAM);
|
|
responseHeaders.set("Content-Disposition", "attachment;filename=" + rdaJsonEnvelope.getFilename());
|
|
responseHeaders.set("Access-Control-Expose-Headers", "Content-Disposition");
|
|
responseHeaders.get("Access-Control-Expose-Headers").add("Content-Type");
|
|
|
|
byte[] content = Files.readAllBytes(rdaJsonEnvelope.getFile().toPath());
|
|
|
|
ResponseEntity<byte[]> jsonFile = new ResponseEntity<>(content, responseHeaders, HttpStatus.OK);
|
|
|
|
String contentDisposition = jsonFile.getHeaders().get("Content-Disposition").get(0);
|
|
String jsonFileName = contentDisposition.substring(contentDisposition.lastIndexOf('=') + 1);
|
|
File rdaJson = new File(this.environment.getProperty("storage.temp") + jsonFileName);
|
|
OutputStream output = new FileOutputStream(rdaJson);
|
|
try {
|
|
output.write(Objects.requireNonNull(jsonFile.getBody()));
|
|
output.flush();
|
|
output.close();
|
|
} catch (IOException e) {
|
|
logger.error(e.getMessage(), e);
|
|
}
|
|
this.uploadFile(jsonFileName, rdaJson, url);
|
|
Files.deleteIfExists(rdaJson.toPath());
|
|
|
|
if(dmpDepositModel.getSupportingFilesZip() != null) {
|
|
this.uploadFile(dmpDepositModel.getSupportingFilesZip().getName(), dmpDepositModel.getSupportingFilesZip(), url);
|
|
}
|
|
}
|
|
|
|
private void uploadFile(String filename, File file, String url) throws IOException {
|
|
HttpHeaders headers =this.createHeaders();
|
|
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
|
|
MultiValueMap<String, String> fileMap = new LinkedMultiValueMap<>();
|
|
ContentDisposition contentDisposition = ContentDisposition
|
|
.builder("form-data")
|
|
.name("file")
|
|
.filename(filename)
|
|
.build();
|
|
fileMap.add(HttpHeaders.CONTENT_DISPOSITION, contentDisposition.toString());
|
|
HttpEntity<byte[]> fileEntity = new HttpEntity<>(Files.readAllBytes(file.toPath()), fileMap);
|
|
MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
|
|
body.add("file", fileEntity);
|
|
HttpEntity<MultiValueMap<String, Object>> requestEntity
|
|
= new HttpEntity<>(body, headers);
|
|
|
|
RestTemplate restTemplate = new RestTemplate();
|
|
restTemplate.postForEntity(url, requestEntity, Object.class);
|
|
}
|
|
|
|
private void sendPatchRequest(String url, String op, String path, String value) throws JsonProcessingException {
|
|
RestTemplate restTemplate = new RestTemplate();
|
|
restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory());
|
|
|
|
HttpHeaders headers = this.createHeaders();
|
|
headers.setContentType(MediaType.APPLICATION_JSON);
|
|
|
|
PatchEntity entity = new PatchEntity();
|
|
entity.setOp(op);
|
|
entity.setPath(path);
|
|
List<Map<String, String>> v = new ArrayList<>();
|
|
Map<String, String> map = new HashMap<>();
|
|
map.put("value", value);
|
|
v.add(map);
|
|
entity.setValue(v);
|
|
|
|
List<PatchEntity> entityList = new ArrayList<>();
|
|
entityList.add(entity);
|
|
logger.debug(objectMapper.writeValueAsString(entityList));
|
|
restTemplate.exchange(url, HttpMethod.PATCH, new HttpEntity<>(entityList, headers), Object.class);
|
|
}
|
|
|
|
private String getItemIdFromHandle(String recordUrl, String handle) throws IOException {
|
|
Document doc = Jsoup.connect(recordUrl + handle).get();
|
|
Element element = doc.select("a[href^=/statistics/items]").get(0);
|
|
String hrefToItemId = element.attr("href");
|
|
return hrefToItemId.split("/")[3];
|
|
}
|
|
|
|
private HttpHeaders createHeaders() {
|
|
HttpHeaders headers = new HttpHeaders();
|
|
headers.add("X-XSRF-TOKEN", this.csrfToken);
|
|
headers.add("Cookie", "DSPACE-XSRF-COOKIE=" + this.csrfToken);
|
|
headers.add("Authorization", this.bearerToken);
|
|
headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
|
|
return headers;
|
|
}
|
|
|
|
private void setCsrfToken(){
|
|
RestTemplate restTemplate = new RestTemplate();
|
|
HttpHeaders headers = restTemplate.exchange(this.repositoryApiUrl, HttpMethod.GET, null, Object.class).getHeaders();
|
|
this.csrfToken = headers.get("DSPACE-XSRF-TOKEN").get(0);
|
|
}
|
|
|
|
private void setBearerToken(String email, String password){
|
|
RestTemplate restTemplate = new RestTemplate();
|
|
|
|
HttpHeaders headers = new HttpHeaders();
|
|
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
|
|
headers.add("X-XSRF-TOKEN", this.csrfToken);
|
|
headers.add("Cookie", "DSPACE-XSRF-COOKIE=" + this.csrfToken);
|
|
|
|
MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
|
|
map.add("user", email);
|
|
map.add("password", password);
|
|
|
|
HttpEntity<MultiValueMap<String, String>> entity = new HttpEntity<>(map, headers);
|
|
this.bearerToken = restTemplate.exchange(this.repositoryApiUrl + "authn/login", HttpMethod.POST, entity, Object.class).getHeaders().get("Authorization").get(0);
|
|
}
|
|
|
|
private void setSubmitterId(){
|
|
if(this.bearerToken != null){
|
|
String token = this.bearerToken.split(" ")[1];
|
|
String[] chunks = token.split("\\.");
|
|
Base64.Decoder decoder = Base64.getUrlDecoder();
|
|
String payload = new String(decoder.decode(chunks[1]));
|
|
JSONObject object = new JSONObject(payload);
|
|
this.submitterId = object.getString("eid");
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public List<RepositoryDepositConfiguration> getConfiguration() {
|
|
List<eu.eudat.depositinterface.dspacerepository.config.DSpaceConfig> dSpaceConfigs = this.configLoader.getDSpaceConfig();
|
|
return dSpaceConfigs.stream().map(DSpaceConfig::toRepoConfig).collect(Collectors.toList());
|
|
}
|
|
|
|
@Override
|
|
public String authenticate(String repositoryId, String code) {
|
|
return null;
|
|
}
|
|
|
|
@Override
|
|
public String getLogo(String repositoryId) {
|
|
RepositoryDepositConfiguration conf = this.getConfiguration().stream().filter(x -> x.getRepositoryId().equals(repositoryId)).findFirst().orElse(null);
|
|
if(conf != null) {
|
|
if(conf.isHasLogo()){
|
|
byte[] logo = this.configLoader.getLogo(repositoryId);
|
|
return (logo != null && logo.length != 0) ? Base64.getEncoder().encodeToString(logo) : null;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
}
|