repository-deposit-dspace/src/main/java/eu/eudat/depositinterface/dspacerepository/interfaces/DSpaceDeposit.java

382 lines
17 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.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.*;
@Component
public class DSpaceDeposit implements RepositoryDeposit {
private static final Logger logger = LoggerFactory.getLogger(DSpaceDeposit.class);
private static final ObjectMapper objectMapper = new ObjectMapper();
private ConfigLoader configLoader;
private 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;
this.repositoryApiUrl = configLoader.getDSpaceConfig().getRepositoryUrl();
}
@Override
public String deposit(DMPDepositModel dmpDepositModel, String repositoryAccessToken) throws Exception {
DSpaceConfig dSpaceConfig = this.configLoader.getDSpaceConfig();
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);
}
}
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.getPdfFileName(), dmpDepositModel.getPdfFile(), url);
String contentDisposition = dmpDepositModel.getRdaJson().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(dmpDepositModel.getRdaJson().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 RepositoryDepositConfiguration getConfiguration() {
eu.eudat.depositinterface.dspacerepository.config.DSpaceConfig dspaceConfig = this.configLoader.getDSpaceConfig();
return dspaceConfig.toRepoConfig();
}
@Override
public String authenticate(String code) {
return null;
}
@Override
public String getLogo() {
RepositoryDepositConfiguration conf = this.getConfiguration();
if(conf.isHasLogo()){
byte[] logo = this.configLoader.getLogo();
return (logo != null && logo.length != 0) ? Base64.getEncoder().encodeToString(logo) : null;
}
return null;
}
}