package eu.eudat.depositinterface.dataverserepository.interfaces; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.researchspace.dataverse.api.v1.DataverseAPI; import com.researchspace.dataverse.api.v1.DataverseConfig; import com.researchspace.dataverse.entities.*; import com.researchspace.dataverse.entities.facade.DatasetAuthor; import com.researchspace.dataverse.entities.facade.DatasetContact; import com.researchspace.dataverse.entities.facade.DatasetDescription; import com.researchspace.dataverse.entities.facade.DatasetFacade; import com.researchspace.dataverse.http.DataverseAPIImpl; import eu.eudat.depositinterface.dataverserepository.config.ConfigLoader; import eu.eudat.depositinterface.models.DMPDepositModel; import eu.eudat.depositinterface.repository.RepositoryDeposit; import eu.eudat.depositinterface.repository.RepositoryDepositConfiguration; import org.json.JSONObject; 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.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.net.MalformedURLException; import java.net.URL; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.util.*; import java.util.stream.Collectors; import static com.researchspace.dataverse.entities.Version.MAJOR; import static com.researchspace.dataverse.entities.Version.MINOR; @Component public class DataverseDeposit implements RepositoryDeposit { private static final Logger logger = LoggerFactory.getLogger(DataverseDeposit.class); private static final ObjectMapper objectMapper = new ObjectMapper(); private DataverseAPI api; private boolean isApiSet; private ConfigLoader configLoader; private Environment environment; @Autowired public DataverseDeposit(ConfigLoader configLoader, Environment environment){ this.configLoader = configLoader; this.environment = environment; this.isApiSet = false; } private void setDataverseApi() throws MalformedURLException { if(!this.isApiSet) { this.api = new DataverseAPIImpl(); eu.eudat.depositinterface.dataverserepository.config.DataverseConfig jsonConfig = this.configLoader.getDataverseConfig(); DataverseConfig config = new DataverseConfig(new URL(jsonConfig.getServer()), jsonConfig.getApiToken(), jsonConfig.getParentDataverseAlias()); api.configure(config); this.isApiSet = true; } } @Override public String deposit(DMPDepositModel dmpDepositModel, String repositoryAccessToken) throws Exception { if(!this.isApiSet) this.setDataverseApi(); String doi; DatasetFacade dataset = DatasetFacade.builder() .title(dmpDepositModel.getLabel()) .authors(dmpDepositModel.getUsers().stream().map(x -> DatasetAuthor.builder().authorName(x.getUser().getName()).build()).collect(Collectors.toList())) .contacts(dmpDepositModel.getUsers().stream().map(x -> DatasetContact.builder().datasetContactEmail(x.getUser().getEmail()).build()).collect(Collectors.toList())) .subject("Other") .description(DatasetDescription.builder().description(dmpDepositModel.getDescription()).build()) .languages(new ArrayList<>()) .depositor("") .build(); if(dmpDepositModel.getPreviousDOI() == null || dmpDepositModel.getPreviousDOI().isEmpty()){ Identifier id = this.api.getDataverseOperations().createDataset(dataset, this.configLoader.getDataverseConfig().getParentDataverseAlias()); doi = this.api.getDatasetOperations().getDataset(id).getDoiId().orElse(null); this.uploadFiles(dmpDepositModel, doi); this.api.getDatasetOperations().publishDataset(id, MAJOR); } else{ Map datasetJson = this.getDatasetIdentifier(dmpDepositModel.getPreviousDOI()); Identifier id = new Identifier(); id.setId(((Integer) datasetJson.get("id")).longValue()); JsonNode jsonNode = this.objectMapper.readTree(new JSONObject(datasetJson).toString()); List files = jsonNode.findValues("dataFile"); for(JsonNode file: files){ int fileId = file.get("id").asInt(); this.deleteFile(fileId); } this.uploadFiles(dmpDepositModel, dmpDepositModel.getPreviousDOI()); this.api.getDatasetOperations().updateDataset(dataset, id); DataverseResponse publishedDataset = this.api.getDatasetOperations().publishDataset(id, MAJOR); doi = publishedDataset.getData().getAuthority() + "/" + publishedDataset.getData().getIdentifier(); } return doi; } private void deleteFile(int fileId){ HttpHeaders headers = this.createBasicAuthHeaders(this.configLoader.getDataverseConfig().getApiToken(), ""); String serverUrl = this.configLoader.getDataverseConfig().getServer() + "/dvn/api/data-deposit/v1.1/swordv2/edit-media/file/" + fileId; RestTemplate restTemplate = new RestTemplate(); restTemplate.exchange(serverUrl, HttpMethod.DELETE, new HttpEntity<>(headers), Object.class); } private HttpHeaders createBasicAuthHeaders(String username, String password) { return new HttpHeaders() {{ String auth = username + ":" + password; byte[] encodedAuth = Base64.getEncoder().encode( auth.getBytes(StandardCharsets.UTF_8)); String authHeader = "Basic " + new String(encodedAuth); set("Authorization", authHeader); }}; } private void uploadFiles(DMPDepositModel dmpDepositModel, String doi) throws IOException { this.uploadFile(dmpDepositModel.getPdfFileName(), dmpDepositModel.getPdfFile(), doi); 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, doi); Files.deleteIfExists(rdaJson.toPath()); if(dmpDepositModel.getSupportingFilesZip() != null) { this.uploadFile(dmpDepositModel.getSupportingFilesZip().getName(), dmpDepositModel.getSupportingFilesZip(), doi); } } private Map getDatasetIdentifier(String previousDOI) { HttpHeaders headers = new HttpHeaders(); headers.set("X-Dataverse-key", this.configLoader.getDataverseConfig().getApiToken()); String serverUrl = this.configLoader.getDataverseConfig().getServer() + "/api/datasets/:persistentId?persistentId=doi:" + previousDOI; RestTemplate restTemplate = new RestTemplate(); return (Map) restTemplate.exchange(serverUrl, HttpMethod.GET, new HttpEntity<>(headers), Map.class).getBody().get("data"); } private void uploadFile(String filename, File file, String doi) throws IOException { HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.MULTIPART_FORM_DATA); headers.set("X-Dataverse-key", this.configLoader.getDataverseConfig().getApiToken()); MultiValueMap fileMap = new LinkedMultiValueMap<>(); ContentDisposition contentDisposition = ContentDisposition .builder("form-data") .name("file") .filename(filename) .build(); fileMap.add(HttpHeaders.CONTENT_DISPOSITION, contentDisposition.toString()); HttpEntity fileEntity = new HttpEntity<>(Files.readAllBytes(file.toPath()), fileMap); MultiValueMap body = new LinkedMultiValueMap<>(); body.add("file", fileEntity); body.add("jsonData", "{\"restrict\":\"false\", \"tabIngest\":\"false\"}"); HttpEntity> requestEntity = new HttpEntity<>(body, headers); String serverUrl = this.configLoader.getDataverseConfig().getServer() + "/api/datasets/:persistentId/add?persistentId=doi:" + doi; RestTemplate restTemplate = new RestTemplate(); ResponseEntity resp = restTemplate.postForEntity(serverUrl, requestEntity, Object.class); } @Override public RepositoryDepositConfiguration getConfiguration() { eu.eudat.depositinterface.dataverserepository.config.DataverseConfig dataverseConfig = this.configLoader.getDataverseConfig(); return dataverseConfig.toRepoConfig(); } @Override public String authenticate(String code) { return null; } }