Merge branch 'dmp-refactoring' into micro-service
This commit is contained in:
commit
430c359043
|
@ -45,7 +45,7 @@
|
|||
<dependency>
|
||||
<groupId>gr.cite.opendmp</groupId>
|
||||
<artifactId>repositorydepositbase</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<version>2.0.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
|
@ -58,6 +58,11 @@
|
|||
<artifactId>json</artifactId>
|
||||
<version>20160810</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>gr.cite</groupId>
|
||||
<artifactId>cache</artifactId>
|
||||
<version>2.1.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
|
|
@ -8,26 +8,19 @@ import java.util.List;
|
|||
@ConfigurationProperties(prefix = "funder")
|
||||
public class FunderProperties {
|
||||
|
||||
private final List<DOIFunder> available;
|
||||
private List<DoiFunder> available;
|
||||
|
||||
@ConstructorBinding
|
||||
public FunderProperties(List<DOIFunder> available) {
|
||||
this.available = available;
|
||||
}
|
||||
|
||||
public List<DOIFunder> getAvailable() {
|
||||
public List<DoiFunder> getAvailable() {
|
||||
return available;
|
||||
}
|
||||
|
||||
public static class DOIFunder {
|
||||
private final String funder;
|
||||
private final String doi;
|
||||
public void setAvailable(List<DoiFunder> available) {
|
||||
this.available = available;
|
||||
}
|
||||
|
||||
@ConstructorBinding
|
||||
public DOIFunder(String funder, String doi) {
|
||||
this.funder = funder;
|
||||
this.doi = doi;
|
||||
}
|
||||
public static class DoiFunder {
|
||||
private String funder;
|
||||
private String doi;
|
||||
|
||||
public String getFunder() {
|
||||
return funder;
|
||||
|
@ -36,5 +29,13 @@ public class FunderProperties {
|
|||
public String getDoi() {
|
||||
return doi;
|
||||
}
|
||||
|
||||
public void setFunder(String funder) {
|
||||
this.funder = funder;
|
||||
}
|
||||
|
||||
public void setDoi(String doi) {
|
||||
this.doi = doi;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,14 +7,13 @@ import java.util.List;
|
|||
|
||||
@ConfigurationProperties(prefix = "identifiers")
|
||||
public class IdentifierProperties {
|
||||
private final List<String> related;
|
||||
|
||||
@ConstructorBinding
|
||||
public IdentifierProperties(List<String> related) {
|
||||
this.related = related;
|
||||
}
|
||||
private List<String> related;
|
||||
|
||||
public List<String> getRelated() {
|
||||
return related;
|
||||
}
|
||||
|
||||
public void setRelated(List<String> related) {
|
||||
this.related = related;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,14 +8,8 @@ import java.util.List;
|
|||
@ConfigurationProperties(prefix = "pid")
|
||||
public class PidProperties {
|
||||
|
||||
private final List<String> acceptedTypes;
|
||||
private final PidFieldNames fields;
|
||||
|
||||
@ConstructorBinding
|
||||
public PidProperties(List<String> acceptedTypes, PidFieldNames fields) {
|
||||
this.acceptedTypes = acceptedTypes;
|
||||
this.fields = fields;
|
||||
}
|
||||
private List<String> acceptedTypes;
|
||||
private PidFieldNames fields;
|
||||
|
||||
public List<String> getAcceptedTypes() {
|
||||
return acceptedTypes;
|
||||
|
@ -25,22 +19,32 @@ public class PidProperties {
|
|||
return fields;
|
||||
}
|
||||
|
||||
public static class PidFieldNames {
|
||||
private final String pidName;
|
||||
private final String pidTypeName;
|
||||
public void setAcceptedTypes(List<String> acceptedTypes) {
|
||||
this.acceptedTypes = acceptedTypes;
|
||||
}
|
||||
|
||||
@ConstructorBinding
|
||||
public PidFieldNames(String pidName, String pidTypeName) {
|
||||
this.pidName = pidName;
|
||||
this.pidTypeName = pidTypeName;
|
||||
}
|
||||
public void setFields(PidFieldNames fields) {
|
||||
this.fields = fields;
|
||||
}
|
||||
|
||||
public static class PidFieldNames {
|
||||
private String pidName;
|
||||
private String pidTypeName;
|
||||
|
||||
public String getPidName() {
|
||||
return pidName;
|
||||
}
|
||||
|
||||
public void setPidName(String pidName) {
|
||||
this.pidName = pidName;
|
||||
}
|
||||
|
||||
public String getPidTypeName() {
|
||||
return pidTypeName;
|
||||
}
|
||||
|
||||
public void setPidTypeName(String pidTypeName) {
|
||||
this.pidTypeName = pidTypeName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,149 +1,57 @@
|
|||
package eu.eudat.depositinterface.zenodorepository.configuration.zenodo;
|
||||
|
||||
import eu.eudat.depositinterface.repository.RepositoryDepositConfiguration;
|
||||
import eu.eudat.depositinterface.repository.DepositConfiguration;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.boot.context.properties.ConstructorBinding;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@ConfigurationProperties(prefix = "zenodo")
|
||||
public class ZenodoProperties {
|
||||
private String logo;
|
||||
|
||||
private final String tempStorage;
|
||||
private String community;
|
||||
|
||||
private final List<ZenodoConfig> configuration;
|
||||
private String domain;
|
||||
|
||||
@ConstructorBinding
|
||||
public ZenodoProperties(Map<String, String> storage, List<ZenodoConfig> configuration) {
|
||||
this.tempStorage = storage.get("temp");
|
||||
this.configuration = configuration;
|
||||
private String affiliation;
|
||||
|
||||
private DepositConfiguration depositConfiguration;
|
||||
|
||||
public void setLogo(String logo) {
|
||||
this.logo = logo;
|
||||
}
|
||||
|
||||
public String getTempStorage() {
|
||||
return tempStorage;
|
||||
public String getLogo() {
|
||||
return logo;
|
||||
}
|
||||
|
||||
public List<ZenodoConfig> getConfiguration() {
|
||||
return configuration;
|
||||
public String getCommunity() {
|
||||
return community;
|
||||
}
|
||||
|
||||
public static class ZenodoConfig extends RepositoryDepositConfiguration {
|
||||
private final int depositType;
|
||||
private final String repositoryId;
|
||||
private final String accessToken;
|
||||
private final String repositoryUrl;
|
||||
private final String repositoryAuthorizationUrl;
|
||||
private final String repositoryRecordUrl;
|
||||
private final String repositoryAccessTokenUrl;
|
||||
private final String repositoryClientId;
|
||||
private final String repositoryClientSecret;
|
||||
private final String redirectUri;
|
||||
private final boolean hasLogo;
|
||||
private final String logo;
|
||||
private final String doiFunder;
|
||||
private final String community;
|
||||
private final String affiliation;
|
||||
private final String domain;
|
||||
public void setCommunity(String community) {
|
||||
this.community = community;
|
||||
}
|
||||
|
||||
@ConstructorBinding
|
||||
public ZenodoConfig(int depositType, String repositoryId, String accessToken, String repositoryUrl, String repositoryAuthorizationUrl, String repositoryRecordUrl, String repositoryAccessTokenUrl, String repositoryClientId, String repositoryClientSecret, String redirectUri, boolean hasLogo, String logo, String doiFunder, String community, String affiliation, String domain) {
|
||||
this.depositType = depositType;
|
||||
this.repositoryId = repositoryId;
|
||||
this.accessToken = accessToken;
|
||||
this.repositoryUrl = repositoryUrl;
|
||||
this.repositoryAuthorizationUrl = repositoryAuthorizationUrl;
|
||||
this.repositoryRecordUrl = repositoryRecordUrl;
|
||||
this.repositoryAccessTokenUrl = repositoryAccessTokenUrl;
|
||||
this.repositoryClientId = repositoryClientId;
|
||||
this.repositoryClientSecret = repositoryClientSecret;
|
||||
this.redirectUri = redirectUri;
|
||||
this.hasLogo = hasLogo;
|
||||
this.logo = logo;
|
||||
this.doiFunder = doiFunder;
|
||||
this.community = community;
|
||||
this.affiliation = affiliation;
|
||||
this.domain = domain;
|
||||
}
|
||||
public String getDomain() {
|
||||
return domain;
|
||||
}
|
||||
|
||||
public int getDepositType() {
|
||||
return depositType;
|
||||
}
|
||||
public void setDomain(String domain) {
|
||||
this.domain = domain;
|
||||
}
|
||||
|
||||
public String getRepositoryId() {
|
||||
return repositoryId;
|
||||
}
|
||||
public String getAffiliation() {
|
||||
return affiliation;
|
||||
}
|
||||
|
||||
public String getAccessToken() {
|
||||
return accessToken;
|
||||
}
|
||||
public void setAffiliation(String affiliation) {
|
||||
this.affiliation = affiliation;
|
||||
}
|
||||
|
||||
public String getRepositoryUrl() {
|
||||
return repositoryUrl;
|
||||
}
|
||||
public DepositConfiguration getDepositConfiguration() {
|
||||
return depositConfiguration;
|
||||
}
|
||||
|
||||
public String getRepositoryAuthorizationUrl() {
|
||||
return repositoryAuthorizationUrl;
|
||||
}
|
||||
|
||||
public String getRepositoryRecordUrl() {
|
||||
return repositoryRecordUrl;
|
||||
}
|
||||
|
||||
public String getRepositoryAccessTokenUrl() {
|
||||
return repositoryAccessTokenUrl;
|
||||
}
|
||||
|
||||
public String getRepositoryClientId() {
|
||||
return repositoryClientId;
|
||||
}
|
||||
|
||||
public String getRepositoryClientSecret() {
|
||||
return repositoryClientSecret;
|
||||
}
|
||||
|
||||
public String getRedirectUri() {
|
||||
return redirectUri;
|
||||
}
|
||||
|
||||
public boolean isHasLogo() {
|
||||
return hasLogo;
|
||||
}
|
||||
|
||||
public String getLogo() {
|
||||
return logo;
|
||||
}
|
||||
|
||||
public String getDoiFunder() {
|
||||
return doiFunder;
|
||||
}
|
||||
|
||||
public String getCommunity() {
|
||||
return community;
|
||||
}
|
||||
|
||||
public String getAffiliation() {
|
||||
return affiliation;
|
||||
}
|
||||
|
||||
public String getDomain() {
|
||||
return domain;
|
||||
}
|
||||
|
||||
public RepositoryDepositConfiguration toRepoConfig() {
|
||||
RepositoryDepositConfiguration config = new RepositoryDepositConfiguration();
|
||||
config.setDepositType(this.depositType);
|
||||
config.setRepositoryId(this.repositoryId);
|
||||
config.setAccessToken(this.accessToken);
|
||||
config.setRepositoryUrl(this.repositoryUrl);
|
||||
config.setRepositoryAuthorizationUrl(this.repositoryAuthorizationUrl);
|
||||
config.setRepositoryRecordUrl(this.repositoryRecordUrl);
|
||||
config.setRepositoryAccessTokenUrl(this.repositoryAccessTokenUrl);
|
||||
config.setRepositoryClientId(this.repositoryClientId);
|
||||
config.setRepositoryClientSecret(this.repositoryClientSecret);
|
||||
config.setRedirectUri(this.redirectUri);
|
||||
config.setHasLogo(this.hasLogo);
|
||||
return config;
|
||||
}
|
||||
public void setDepositConfiguration(DepositConfiguration depositConfiguration) {
|
||||
this.depositConfiguration = depositConfiguration;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
package eu.eudat.depositinterface.zenodorepository.enums;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonValue;
|
||||
import eu.eudat.depositinterface.enums.EnumUtils;
|
||||
import eu.eudat.depositinterface.enums.EnumValueProvider;
|
||||
import eu.eudat.depositinterface.enums.FieldType;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public enum ZenodoAccessRight implements EnumValueProvider<String> {
|
||||
RESTRICTED(Names.Restricted), EMBARGOED(Names.Embargoed), OPEN(Names.Open);
|
||||
|
||||
private final String value;
|
||||
|
||||
public static class Names {
|
||||
public static final String Restricted = "restricted";
|
||||
public static final String Embargoed = "embargoed";
|
||||
public static final String Open = "open";
|
||||
}
|
||||
|
||||
ZenodoAccessRight(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonValue
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
private static final Map<String, ZenodoAccessRight> map = EnumUtils.getEnumValueMap(ZenodoAccessRight.class);
|
||||
|
||||
public static ZenodoAccessRight of(String i) {
|
||||
return map.get(i);
|
||||
}
|
||||
}
|
|
@ -1,284 +0,0 @@
|
|||
package eu.eudat.depositinterface.zenodorepository.interfaces;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
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 eu.eudat.depositinterface.zenodorepository.configuration.zenodo.ZenodoProperties;
|
||||
import eu.eudat.depositinterface.zenodorepository.mapper.DMPToZenodoMapper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.core.ParameterizedTypeReference;
|
||||
import org.springframework.core.io.ByteArrayResource;
|
||||
import org.springframework.http.*;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.util.ResourceUtils;
|
||||
import org.springframework.web.client.HttpClientErrorException;
|
||||
import org.springframework.web.client.HttpServerErrorException;
|
||||
import org.springframework.web.reactive.function.BodyInserters;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.file.Files;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Component
|
||||
public class ZenodoDeposit implements RepositoryDeposit {
|
||||
private static final Logger logger = LoggerFactory.getLogger(ZenodoDeposit.class);
|
||||
private static final ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
private final ZenodoProperties zenodoProperties;
|
||||
private final DMPToZenodoMapper mapper;
|
||||
|
||||
@Autowired
|
||||
public ZenodoDeposit(ZenodoProperties zenodoProperties, DMPToZenodoMapper mapper){
|
||||
this.zenodoProperties = zenodoProperties;
|
||||
this.mapper = mapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String deposit(String repositoryId, DMPDepositModel dmpDepositModel, String zenodoToken) throws Exception {
|
||||
|
||||
RepositoryDepositConfiguration conf = this.getConfiguration().stream().filter(x -> x.getRepositoryId().equals(repositoryId)).findFirst().orElse(null);
|
||||
|
||||
if(conf != null) {
|
||||
|
||||
if (zenodoToken == null || zenodoToken.isEmpty()) {
|
||||
zenodoToken = conf.getAccessToken();
|
||||
}
|
||||
|
||||
String zenodoUrl = conf.getRepositoryUrl();
|
||||
|
||||
// First step, post call to Zenodo, to create the entry.
|
||||
WebClient zenodoClient = WebClient.builder().build();
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
|
||||
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||
|
||||
ZenodoProperties.ZenodoConfig zenodoConfig = this.zenodoProperties.getConfiguration().stream().filter(x -> x.getRepositoryId().equals(repositoryId)).findFirst().orElse(null);
|
||||
eu.eudat.depositinterface.zenodorepository.models.ZenodoDeposit deposit = mapper.fromDMP(dmpDepositModel, zenodoConfig);
|
||||
|
||||
Map createResponse;
|
||||
LinkedHashMap<String, String> links;
|
||||
String previousDOI = dmpDepositModel.getPreviousDOI();
|
||||
String unpublishedUrl = null;
|
||||
String publishUrl;
|
||||
try {
|
||||
|
||||
if (previousDOI == null) {
|
||||
String createUrl = zenodoUrl + "deposit/depositions" + "?access_token=" + zenodoToken;
|
||||
createResponse = zenodoClient.post().uri(createUrl).headers(httpHeaders -> {
|
||||
httpHeaders.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
|
||||
httpHeaders.setContentType(MediaType.APPLICATION_JSON);
|
||||
})
|
||||
.bodyValue(deposit).exchangeToMono(mono -> mono.bodyToMono(new ParameterizedTypeReference<Map<String, Object>>() {})).block();
|
||||
links = (LinkedHashMap<String, String>) createResponse.get("links");
|
||||
} else {
|
||||
unpublishedUrl = this.getUnpublishedDOI(zenodoUrl, previousDOI, zenodoToken, dmpDepositModel.getVersion());
|
||||
if (unpublishedUrl == null) {
|
||||
//It requires more than one step to create a new version
|
||||
//First, get the deposit related to the concept DOI
|
||||
String listUrl = zenodoUrl + "deposit/depositions" + "?q=conceptdoi:\"" + previousDOI + "\"&access_token=" + zenodoToken;
|
||||
logger.debug("listUrl = " + listUrl);
|
||||
ResponseEntity<List<Map>> listResponses = zenodoClient.get().uri(listUrl).retrieve().toEntityList(Map.class).block();
|
||||
createResponse = listResponses.getBody().get(0);
|
||||
logger.debug("createResponse-previousDoi:");
|
||||
logger.debug(objectMapper.writeValueAsString(createResponse));
|
||||
links = (LinkedHashMap<String, String>) createResponse.get("links");
|
||||
//Second, make the new version (not in the links?)
|
||||
String newVersionUrl = links.get("self") + "/actions/newversion" + "?access_token=" + zenodoToken;
|
||||
logger.debug("new version url: " + newVersionUrl);
|
||||
createResponse = zenodoClient.post().uri(newVersionUrl)
|
||||
.bodyValue(null).exchangeToMono(mono -> mono.bodyToMono(Map.class)).block();
|
||||
logger.debug("createResponse-newVersion:");
|
||||
logger.debug(objectMapper.writeValueAsString(createResponse));
|
||||
links = (LinkedHashMap<String, String>) createResponse.get("links");
|
||||
//Third, get the new deposit
|
||||
String latestDraftUrl = links.get("latest_draft") + "?access_token=" + zenodoToken;
|
||||
createResponse = zenodoClient.get().uri(latestDraftUrl)
|
||||
.exchangeToMono(mono -> mono.bodyToMono(Map.class)).block();
|
||||
logger.debug("createResponse-latestDraft:");
|
||||
logger.debug(objectMapper.writeValueAsString(createResponse));
|
||||
links = (LinkedHashMap<String, String>) createResponse.get("links");
|
||||
//At this point it might fail to perform the next requests so enclose them with try catch
|
||||
try {
|
||||
//Forth, update the new deposit's metadata
|
||||
String updateUrl = links.get("self") + "?access_token=" + zenodoToken;
|
||||
zenodoClient.put().uri(updateUrl)
|
||||
.headers(httpHeaders -> {
|
||||
httpHeaders.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
|
||||
httpHeaders.setContentType(MediaType.APPLICATION_JSON);
|
||||
})
|
||||
.bodyValue(deposit).retrieve().toEntity(Map.class).block();
|
||||
//And finally remove pre-existing files from it
|
||||
String fileListUrl = links.get("self") + "/files" + "?access_token=" + zenodoToken;
|
||||
ResponseEntity<List<Map>> fileListResponse = zenodoClient.get().uri(fileListUrl).retrieve().toEntityList(Map.class).block();
|
||||
for (Map file : fileListResponse.getBody()) {
|
||||
String fileDeleteUrl = links.get("self") + "/files/" + file.get("id") + "?access_token=" + zenodoToken;
|
||||
zenodoClient.delete().uri(fileDeleteUrl).retrieve().toEntity(Map.class).block();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
//In case the last two steps fail delete the latest Deposit it in order to create a new one (only one at a time is allowed)
|
||||
//restTemplate.delete(latestDraftUrl);
|
||||
zenodoClient.delete().uri(latestDraftUrl).retrieve().toEntity(Map.class).block();
|
||||
throw e;
|
||||
}
|
||||
} else {
|
||||
String listUrl = zenodoUrl + "deposit/depositions" + "?q=conceptdoi:\"" + previousDOI + "\"&access_token=" + zenodoToken;
|
||||
ResponseEntity<List<Map>> listResponses = zenodoClient.get().uri(listUrl).retrieve().toEntityList(Map.class).block();//restTemplate.getForEntity(listUrl, Map[].class);
|
||||
createResponse = listResponses.getBody().get(0);
|
||||
links = (LinkedHashMap<String, String>) createResponse.get("links");
|
||||
}
|
||||
}
|
||||
|
||||
if (unpublishedUrl == null) {
|
||||
// Second step, add the file to the entry.
|
||||
FileEnvelope pdfEnvelope = dmpDepositModel.getPdfFile();
|
||||
|
||||
String addFileUrl = links.get("bucket") + "/" + pdfEnvelope.getFilename() + "?access_token=" + zenodoToken;
|
||||
zenodoClient.put().uri(addFileUrl)
|
||||
.body(BodyInserters
|
||||
.fromResource(new ByteArrayResource(Files.readAllBytes(pdfEnvelope.getFile().toPath()))))
|
||||
.retrieve().toEntity(Map.class).block();
|
||||
FileEnvelope rdaJsonEnvelope = dmpDepositModel.getRdaJsonFile();
|
||||
|
||||
String jsonFileName = rdaJsonEnvelope.getFilename();
|
||||
addFileUrl = links.get("bucket") + "/" + jsonFileName + "?access_token=" + zenodoToken;
|
||||
zenodoClient.put().uri(addFileUrl).headers(httpHeaders -> httpHeaders.setContentType(MediaType.APPLICATION_OCTET_STREAM)).body(BodyInserters.fromResource(new ByteArrayResource(Files.readAllBytes(rdaJsonEnvelope.getFile().toPath())))).retrieve().toEntity(Map.class).block();
|
||||
|
||||
if (dmpDepositModel.getSupportingFilesZip() != null) {
|
||||
File supportinFilesZip = dmpDepositModel.getSupportingFilesZip();
|
||||
String supportinFilesZipName = dmpDepositModel.getSupportingFilesZip().getName();
|
||||
|
||||
addFileUrl = links.get("bucket") + "/" + supportinFilesZipName + "?access_token=" + zenodoToken;
|
||||
zenodoClient.put().uri(addFileUrl).body(BodyInserters.fromResource(new ByteArrayResource(Files.readAllBytes(supportinFilesZip.toPath())))).retrieve().toEntity(Map.class).block();
|
||||
}
|
||||
|
||||
// Third post call to Zenodo to publish the entry and return the DOI.
|
||||
publishUrl = links.get("publish") + "?access_token=" + zenodoToken;
|
||||
} else {
|
||||
publishUrl = unpublishedUrl + "?access_token=" + zenodoToken;
|
||||
}
|
||||
|
||||
return this.publish(publishUrl);
|
||||
|
||||
} catch (HttpClientErrorException | HttpServerErrorException ex) {
|
||||
Map<String, String> parsedException = objectMapper.readValue(ex.getResponseBodyAsString(), HashMap.class);
|
||||
throw new IOException(parsedException.get("message"), ex);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
private String publish(String publishUrl){
|
||||
//RestTemplate restTemplate = new RestTemplate();
|
||||
WebClient webClient = WebClient.builder().build();
|
||||
Map<String, Object> publishResponce = webClient.post().uri(publishUrl).bodyValue("").exchangeToMono(mono -> {
|
||||
if (!mono.statusCode().is2xxSuccessful()) {
|
||||
mono.createException();
|
||||
throw new UnsupportedOperationException("Failed to publish to Zenodo");
|
||||
}
|
||||
return mono.bodyToMono(new ParameterizedTypeReference<Map<String, Object>>() {
|
||||
});
|
||||
}).block();
|
||||
return (String) publishResponce.get("conceptdoi");
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<RepositoryDepositConfiguration> getConfiguration() {
|
||||
List<ZenodoProperties.ZenodoConfig> zenodoConfigs = this.zenodoProperties.getConfiguration();
|
||||
return (zenodoConfigs != null) ? zenodoConfigs.stream().map(ZenodoProperties.ZenodoConfig::toRepoConfig).collect(Collectors.toList()) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String authenticate(String repositoryId, String code){
|
||||
|
||||
RepositoryDepositConfiguration conf = this.getConfiguration().stream().filter(x -> x.getRepositoryId().equals(repositoryId)).findFirst().orElse(null);
|
||||
|
||||
if(conf != null) {
|
||||
|
||||
WebClient client = WebClient.builder().defaultHeaders(httpHeaders -> {
|
||||
httpHeaders.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
|
||||
httpHeaders.setContentType(MediaType.MULTIPART_FORM_DATA);
|
||||
}).build();
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
|
||||
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
|
||||
|
||||
MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
|
||||
map.add("client_id", conf.getRepositoryClientId());
|
||||
map.add("client_secret", conf.getRepositoryClientSecret());
|
||||
map.add("grant_type", "authorization_code");
|
||||
map.add("code", code);
|
||||
map.add("redirect_uri", conf.getRedirectUri());
|
||||
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(map, headers);
|
||||
|
||||
try {
|
||||
Map<String, Object> values = client.post().uri(conf.getRepositoryAccessTokenUrl()).bodyValue(map).retrieve().bodyToMono(Map.class).block();
|
||||
Map<String, Object> user = (Map<String, Object>) values.get("user");
|
||||
return (String) values.get("access_token");
|
||||
} catch (HttpClientErrorException ex) {
|
||||
logger.error(ex.getResponseBodyAsString(), ex);
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLogo(String repositoryId) {
|
||||
ZenodoProperties.ZenodoConfig conf = this.zenodoProperties.getConfiguration().stream().filter(x -> x.getRepositoryId().equals(repositoryId)).findFirst().orElse(null);
|
||||
if(conf != null) {
|
||||
if(conf.isHasLogo()){
|
||||
byte[] logo;
|
||||
try {
|
||||
File logoFile = ResourceUtils.getFile(conf.getLogo());
|
||||
InputStream logoStream = new FileInputStream(logoFile);
|
||||
logo = logoStream.readAllBytes();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return (logo != null && logo.length != 0) ? Base64.getEncoder().encodeToString(logo) : null;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String getUnpublishedDOI(String zenodoUrl, String DOI, String token, Integer version) {
|
||||
try {
|
||||
WebClient client = WebClient.builder().build();
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
|
||||
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||
Map createResponse = null;
|
||||
LinkedHashMap<String, String> links;
|
||||
LinkedHashMap<String, String> metadata;
|
||||
String listUrl = zenodoUrl + "deposit/depositions" + "?q=conceptdoi:\"" + DOI + "\"&access_token=" + token;
|
||||
ResponseEntity<List<Map>> listResponses = client.get().uri(listUrl).retrieve().toEntityList(Map.class).block();
|
||||
createResponse = listResponses.getBody().get(0);
|
||||
metadata = (LinkedHashMap<String, String>) createResponse.get("metadata");
|
||||
links = (LinkedHashMap<String, String>) createResponse.get("links");
|
||||
|
||||
if (metadata.get("version").equals(version.toString())) {
|
||||
return links.get("publish");
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}catch (Exception e) {
|
||||
logger.warn(e.getMessage(), e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,274 +0,0 @@
|
|||
package eu.eudat.depositinterface.zenodorepository.mapper;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import eu.eudat.depositinterface.enums.FieldType;
|
||||
import eu.eudat.depositinterface.models.*;
|
||||
import eu.eudat.depositinterface.zenodorepository.configuration.funder.FunderProperties;
|
||||
import eu.eudat.depositinterface.zenodorepository.configuration.identifier.IdentifierProperties;
|
||||
import eu.eudat.depositinterface.zenodorepository.configuration.pid.PidProperties;
|
||||
import eu.eudat.depositinterface.zenodorepository.configuration.zenodo.ZenodoProperties;
|
||||
import eu.eudat.depositinterface.zenodorepository.models.*;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Component
|
||||
public class DMPToZenodoMapper {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(DMPToZenodoMapper.class);
|
||||
private static final ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
private final PidProperties pidProperties;
|
||||
private final IdentifierProperties identifierProperties;
|
||||
private final FunderProperties funderProperties;
|
||||
|
||||
@Autowired
|
||||
public DMPToZenodoMapper(PidProperties pidProperties, IdentifierProperties identifierProperties, FunderProperties funderProperties){
|
||||
this.pidProperties = pidProperties;
|
||||
this.identifierProperties = identifierProperties;
|
||||
this.funderProperties = funderProperties;
|
||||
}
|
||||
|
||||
private List<DatasetFieldsDepositModel> findSchemanticValues(String relatedId, List<DatasetFieldsDepositModel> fields){
|
||||
return fields.stream().filter(f -> f.getSchematics().contains(relatedId)).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private Set<String> extractSchemanticValues(List<DatasetFieldsDepositModel> fields, List<String> acceptedPidTypes) throws JsonProcessingException{
|
||||
Set<String> values = new HashSet<>();
|
||||
for(DatasetFieldsDepositModel field: fields){
|
||||
String value = (String) field.getValue();
|
||||
if(value != null && !value.isEmpty()) {
|
||||
switch (FieldType.fromName(field.getRenderStyleType())) {
|
||||
case FREE_TEXT:
|
||||
case TEXT_AREA:
|
||||
case RICH_TEXT_AREA:
|
||||
case RADIO_BOX:
|
||||
case DATE_PICKER:
|
||||
values.add(value);
|
||||
break;
|
||||
case COMBO_BOX:
|
||||
if (field.isMultiple()) {
|
||||
List<String> selected = objectMapper.readValue(value, new TypeReference<List<String>>() {});
|
||||
values.addAll(selected);
|
||||
}
|
||||
else {
|
||||
values.add(value);
|
||||
}
|
||||
break;
|
||||
case REGISTRIES:
|
||||
case SERVICES:
|
||||
case EXTERNAL_DATASETS:
|
||||
case DATA_REPOSITORIES:
|
||||
case PUB_REPOSITORIES:
|
||||
case JOURNAL_REPOSITORIES:
|
||||
case TAXONOMIES:
|
||||
case PUBLICATIONS:
|
||||
if (field.isMultiple()) {
|
||||
List<String> selected = objectMapper.readValue(value, new TypeReference<List<String>>() {});
|
||||
for (String s : selected) {
|
||||
Map<String, String> valueMap = objectMapper.readValue(s, new TypeReference<Map<String, String>>() {});
|
||||
String pid = valueMap.get(this.pidProperties.getFields().getPidName());
|
||||
String pidType = valueMap.get(this.pidProperties.getFields().getPidTypeName());
|
||||
if (acceptedPidTypes.contains(pidType)) {
|
||||
values.add(pid);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
Map<String, String> valueMap = objectMapper.readValue(value, new TypeReference<Map<String, String>>() {});
|
||||
String pid = valueMap.get(this.pidProperties.getFields().getPidName());
|
||||
String pidType = valueMap.get(this.pidProperties.getFields().getPidTypeName());
|
||||
if (acceptedPidTypes.contains(pidType)) {
|
||||
values.add(pid);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ORGANIZATIONS:
|
||||
case RESEARCHERS:
|
||||
if (field.isMultiple()) {
|
||||
List<String> selected = objectMapper.readValue(value, new TypeReference<List<String>>() {});
|
||||
for (String s : selected) {
|
||||
Map<String, String> valueMap = objectMapper.readValue(s, new TypeReference<Map<String, String>>() {});
|
||||
String pid = valueMap.get("reference");
|
||||
if(pid != null) {
|
||||
values.add(pid);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
Map<String, String> valueMap = objectMapper.readValue(value, new TypeReference<Map<String, String>>() {});
|
||||
String pid = valueMap.get("reference");
|
||||
if(pid != null) {
|
||||
values.add(pid);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case DATASET_IDENTIFIER:
|
||||
Map<String, String> valueMap = objectMapper.readValue(value, new TypeReference<Map<String, String>>() {});
|
||||
values.add(valueMap.get("identifier"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
public ZenodoDeposit fromDMP(DMPDepositModel dmp, ZenodoProperties.ZenodoConfig zenodoConfig) throws JsonProcessingException {
|
||||
Map<String, Object> extraProperties = dmp.getExtraProperties() != null ? new org.json.JSONObject(dmp.getExtraProperties()).toMap() : new HashMap<>();
|
||||
ZenodoDeposit deposit = new ZenodoDeposit();
|
||||
|
||||
Map<String, Object> schematicsMap = new HashMap<>();
|
||||
|
||||
List<ZenodoRelator> relatedIdentifiers = new ArrayList<>();
|
||||
List<ZenodoComunity> communities = new ArrayList<>();
|
||||
List<ZenodoContributor> contributors = new ArrayList<>();
|
||||
List<ZenodoCreator> creators = new ArrayList<>();
|
||||
List<ZenodoGrant> grants = new ArrayList<>();
|
||||
List<String> keywords = new ArrayList<>();
|
||||
List<String> references = new ArrayList<>();
|
||||
|
||||
List<String> acceptedPidTypes = this.pidProperties.getAcceptedTypes();
|
||||
|
||||
for(DatasetDepositModel dataset: dmp.getDatasets()){
|
||||
|
||||
for(String relatedId: this.identifierProperties.getRelated()){
|
||||
|
||||
List<DatasetFieldsDepositModel> fields = findSchemanticValues(relatedId, dataset.getFields());
|
||||
Set<String> values = extractSchemanticValues(fields, acceptedPidTypes);
|
||||
for(String value: values){
|
||||
ZenodoRelator relator = new ZenodoRelator();
|
||||
relator.setRelation(relatedId.substring(relatedId.lastIndexOf(".") + 1));
|
||||
relator.setIdentifier(value);
|
||||
relatedIdentifiers.add(relator);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
schematicsMap.put("related_identifiers", relatedIdentifiers);
|
||||
schematicsMap.put("communities", communities);
|
||||
schematicsMap.put("contributors", contributors);
|
||||
schematicsMap.put("creators", creators);
|
||||
schematicsMap.put("grants", grants);
|
||||
schematicsMap.put("keywords", keywords);
|
||||
schematicsMap.put("references", references);
|
||||
|
||||
String schematicsString = objectMapper.writeValueAsString(schematicsMap);
|
||||
objectMapper.enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY);
|
||||
ZenodoDepositMetadata metadata = objectMapper.readValue(schematicsString, new TypeReference<ZenodoDepositMetadata>(){});
|
||||
|
||||
deposit.setMetadata(metadata);
|
||||
deposit.getMetadata().setTitle(dmp.getLabel());
|
||||
deposit.getMetadata().setUploadType("publication");
|
||||
deposit.getMetadata().setPublicationType("datamanagementplan");
|
||||
deposit.getMetadata().setDescription((dmp.getDescription() != null && !dmp.getDescription().isEmpty() ? dmp.getDescription() : "<p></p>"));
|
||||
deposit.getMetadata().setVersion(String.valueOf(dmp.getVersion()));
|
||||
String zenodoCommunity = zenodoConfig.getCommunity();
|
||||
if(zenodoCommunity != null && !zenodoCommunity.isEmpty()) {
|
||||
ZenodoComunity community = new ZenodoComunity();
|
||||
community.setIdentifier(zenodoCommunity);
|
||||
deposit.getMetadata().getCommunities().add(community);
|
||||
}
|
||||
if (extraProperties.get("visible") == null) {
|
||||
deposit.getMetadata().setAccessRight(ZenodoAccessRight.RESTRICTED);
|
||||
deposit.getMetadata().setAccessConditions("");
|
||||
} else {
|
||||
if (((Boolean) extraProperties.get("visible"))) {
|
||||
Instant publicationDate = Instant.parse(extraProperties.get("publicDate").toString());
|
||||
if (publicationDate.isBefore(Instant.now())) {
|
||||
deposit.getMetadata().setAccessRight(ZenodoAccessRight.OPEN);
|
||||
} else {
|
||||
deposit.getMetadata().setAccessRight(ZenodoAccessRight.EMBARGOED);
|
||||
deposit.getMetadata().setEmbargoDate(publicationDate.toString());
|
||||
}
|
||||
|
||||
if (extraProperties.get("license") != null) {
|
||||
deposit.getMetadata().setLicense(((Map<?, ?>) extraProperties.get("license")).get("pid").toString());
|
||||
}
|
||||
} else {
|
||||
deposit.getMetadata().setAccessRight(ZenodoAccessRight.RESTRICTED);
|
||||
deposit.getMetadata().setAccessConditions("");
|
||||
}
|
||||
}
|
||||
if (dmp.isPublic()) {
|
||||
ZenodoRelator relator = new ZenodoRelator();
|
||||
relator.setIdentifier(zenodoConfig.getDomain() + "/external/zenodo/" + dmp.getId().toString());
|
||||
relator.setRelation("isIdenticalTo");
|
||||
deposit.getMetadata().getRelatedIdentifiers().add(relator);
|
||||
}
|
||||
String zenodoAffiliation = zenodoConfig.getAffiliation();
|
||||
List<ZenodoContributor> contributors1 = dmp.getUsers().stream().map(userDMP -> {
|
||||
ZenodoContributor contributor = new ZenodoContributor();
|
||||
contributor.setName(userDMP.getUser().getName());
|
||||
contributor.setType("ProjectMember");
|
||||
if (dmp.getOrganisations() != null && !dmp.getOrganisations().isEmpty()) {
|
||||
contributor.setAffiliation(dmp.getOrganisations()
|
||||
.stream().map(OrganisationDepositModel::getLabel).collect(Collectors.joining(", ")));
|
||||
} else {
|
||||
if(zenodoAffiliation != null && !zenodoAffiliation.isEmpty()) {
|
||||
contributor.setAffiliation(zenodoAffiliation);
|
||||
}
|
||||
}
|
||||
return contributor;
|
||||
}).collect(Collectors.toList());
|
||||
|
||||
List<ZenodoContributor> researchers = dmp.getResearchers().stream().map(researcher -> {
|
||||
ZenodoContributor contributor = new ZenodoContributor();
|
||||
contributor.setName(researcher.getLabel());
|
||||
contributor.setType("Researcher");
|
||||
String referenceHead = researcher.getReference().split(":")[0];
|
||||
String referenceTail = researcher.getReference().replace(referenceHead + ":", "");
|
||||
contributor.setAffiliation(referenceHead);
|
||||
if (referenceHead.equalsIgnoreCase("ORCID")) {
|
||||
contributor.setOrcid(referenceTail);
|
||||
}
|
||||
return contributor;
|
||||
}).collect(Collectors.toList());
|
||||
|
||||
deposit.getMetadata().getContributors().addAll(contributors1);
|
||||
deposit.getMetadata().getContributors().addAll(researchers);
|
||||
|
||||
if (dmp.getGrant() != null) {
|
||||
if (dmp.getGrant().getReference() == null) {
|
||||
dmp.getGrant().setReference("dmp:" + dmp.getGrant().getId());
|
||||
}
|
||||
String grantReferenceHead = dmp.getGrant().getReference().split(":")[0];
|
||||
if (grantReferenceHead.equals("openaire")) {
|
||||
String grantReferenceTail = dmp.getGrant().getReference().split(":")[3];
|
||||
List<FunderProperties.DOIFunder> doiFunders = this.funderProperties.getAvailable();
|
||||
if (dmp.getGrant().getFunder() != null && dmp.getGrant().getFunder().getLabel() != null) {
|
||||
FunderProperties.DOIFunder doiFunder = doiFunders.stream()
|
||||
.filter(doiFunder1 -> dmp.getGrant().getFunder().getLabel().contains(doiFunder1.getFunder()) || doiFunder1.getFunder().contains(dmp.getGrant().getFunder().getLabel()))
|
||||
.findFirst().orElse(null);
|
||||
if (doiFunder != null) {
|
||||
String finalId = doiFunder.getDoi() + "::" + grantReferenceTail;
|
||||
ZenodoGrant grant = new ZenodoGrant();
|
||||
grant.setId(finalId);
|
||||
deposit.getMetadata().getGrants().add(grant);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ZenodoCreator creator = new ZenodoCreator();
|
||||
creator.setName(dmp.getUsers().stream().filter(userDMP -> userDMP.getRole().equals(UserDMPDepositModel.UserDMPRoles.OWNER.getValue())).findFirst().get().getUser().getName());
|
||||
if (dmp.getOrganisations() != null && !dmp.getOrganisations().isEmpty()) {
|
||||
creator.setAffiliation(dmp.getOrganisations()
|
||||
.stream().map(OrganisationDepositModel::getLabel).collect(Collectors.joining(", ")));
|
||||
} else {
|
||||
if(zenodoAffiliation != null && !zenodoAffiliation.isEmpty()) {
|
||||
creator.setAffiliation(zenodoAffiliation);
|
||||
}
|
||||
}
|
||||
deposit.getMetadata().getCreators().add(creator);
|
||||
|
||||
return deposit;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
package eu.eudat.depositinterface.zenodorepository.models;
|
||||
package eu.eudat.depositinterface.zenodorepository.model;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public class ZenodoComunity {
|
||||
public class ZenodoCommunity {
|
||||
|
||||
private String identifier;
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package eu.eudat.depositinterface.zenodorepository.models;
|
||||
package eu.eudat.depositinterface.zenodorepository.model;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
|
@ -1,4 +1,4 @@
|
|||
package eu.eudat.depositinterface.zenodorepository.models;
|
||||
package eu.eudat.depositinterface.zenodorepository.model;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
|
@ -1,4 +1,4 @@
|
|||
package eu.eudat.depositinterface.zenodorepository.models;
|
||||
package eu.eudat.depositinterface.zenodorepository.model;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
|
@ -1,8 +1,9 @@
|
|||
package eu.eudat.depositinterface.zenodorepository.models;
|
||||
package eu.eudat.depositinterface.zenodorepository.model;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import eu.eudat.depositinterface.zenodorepository.enums.ZenodoAccessRight;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
@ -31,7 +32,7 @@ public class ZenodoDepositMetadata {
|
|||
|
||||
private List<String> references;
|
||||
|
||||
private List<ZenodoComunity> communities;
|
||||
private List<ZenodoCommunity> communities;
|
||||
|
||||
@JsonProperty("access_right")
|
||||
private ZenodoAccessRight accessRight;
|
||||
|
@ -125,11 +126,11 @@ public class ZenodoDepositMetadata {
|
|||
this.version = version;
|
||||
}
|
||||
|
||||
public List<ZenodoComunity> getCommunities() {
|
||||
public List<ZenodoCommunity> getCommunities() {
|
||||
return communities;
|
||||
}
|
||||
|
||||
public void setCommunities(List<ZenodoComunity> communities) {
|
||||
public void setCommunities(List<ZenodoCommunity> communities) {
|
||||
this.communities = communities;
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package eu.eudat.depositinterface.zenodorepository.models;
|
||||
package eu.eudat.depositinterface.zenodorepository.model;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
|
@ -1,4 +1,4 @@
|
|||
package eu.eudat.depositinterface.zenodorepository.models;
|
||||
package eu.eudat.depositinterface.zenodorepository.model;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
|
@ -0,0 +1,319 @@
|
|||
package eu.eudat.depositinterface.zenodorepository.model.builder;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import eu.eudat.depositinterface.enums.DmpAccessType;
|
||||
import eu.eudat.depositinterface.enums.DmpUserRole;
|
||||
import eu.eudat.depositinterface.enums.ReferenceType;
|
||||
import eu.eudat.depositinterface.models.*;
|
||||
import eu.eudat.depositinterface.models.reference.FieldDepositModel;
|
||||
import eu.eudat.depositinterface.zenodorepository.configuration.funder.FunderProperties;
|
||||
import eu.eudat.depositinterface.zenodorepository.configuration.identifier.IdentifierProperties;
|
||||
import eu.eudat.depositinterface.zenodorepository.configuration.pid.PidProperties;
|
||||
import eu.eudat.depositinterface.zenodorepository.configuration.zenodo.ZenodoProperties;
|
||||
import eu.eudat.depositinterface.zenodorepository.enums.ZenodoAccessRight;
|
||||
import eu.eudat.depositinterface.zenodorepository.model.*;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Component
|
||||
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
|
||||
public class ZenodoBuilder {
|
||||
|
||||
private static final String UPLOAD_TYPE = "publication";
|
||||
private static final String PUBLICATION_TYPE = "datamanagementplan";
|
||||
private static final String IS_IDENTICAL_TO = "isIdenticalTo";
|
||||
private static final String CONTRIBUTOR_TYPE_RESEARCHER = "Researcher";
|
||||
private static final String CONTRIBUTOR_TYPE_PROJECT_MANAGER = "ProjectMember";
|
||||
private static final String SOURCE_OPENAIRE = "openaire";
|
||||
private static final String SOURCE_ORCID = "ORCID";
|
||||
private static final String PID = "pid";
|
||||
|
||||
|
||||
|
||||
private final PidProperties pidProperties;
|
||||
private final IdentifierProperties identifierProperties;
|
||||
private final FunderProperties funderProperties;
|
||||
|
||||
@Autowired
|
||||
public ZenodoBuilder(PidProperties pidProperties, IdentifierProperties identifierProperties, FunderProperties funderProperties){
|
||||
this.pidProperties = pidProperties;
|
||||
this.identifierProperties = identifierProperties;
|
||||
this.funderProperties = funderProperties;
|
||||
}
|
||||
|
||||
public ZenodoDeposit build(DmpDepositModel dmp, ZenodoProperties zenodoConfig) throws JsonProcessingException {
|
||||
ZenodoDeposit deposit = new ZenodoDeposit();
|
||||
this.applyZenodoRelator(dmp, deposit);
|
||||
deposit.getMetadata().setTitle(dmp.getLabel());
|
||||
deposit.getMetadata().setUploadType(UPLOAD_TYPE);
|
||||
deposit.getMetadata().setPublicationType(PUBLICATION_TYPE);
|
||||
deposit.getMetadata().setDescription((dmp.getDescription() != null && !dmp.getDescription().isEmpty() ? dmp.getDescription() : "<p></p>"));
|
||||
deposit.getMetadata().setVersion(String.valueOf(dmp.getVersion()));
|
||||
String zenodoCommunity = zenodoConfig.getCommunity();
|
||||
if(zenodoCommunity != null && !zenodoCommunity.isEmpty()) {
|
||||
ZenodoCommunity community = new ZenodoCommunity();
|
||||
community.setIdentifier(zenodoCommunity);
|
||||
deposit.getMetadata().getCommunities().add(community);
|
||||
}
|
||||
this.applyAccessRight(dmp, deposit);
|
||||
this.applyIsIdenticalTo(dmp, deposit, zenodoConfig);
|
||||
this.applyLicenses(dmp, deposit);
|
||||
this.applyResearchers(dmp, deposit);
|
||||
this.applyGrants(dmp, deposit);
|
||||
this.applyContributors(dmp, deposit, zenodoConfig);
|
||||
this.applyCreators(dmp, deposit, zenodoConfig);
|
||||
|
||||
|
||||
|
||||
return deposit;
|
||||
}
|
||||
|
||||
private List<DescriptionFieldDepositModel> findSchematicValues(String relatedId, List<DescriptionFieldDepositModel> fields){
|
||||
return fields.stream().filter(f -> f.getSchematics().contains(relatedId)).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private Set<String> extractSchematicValues(List<DescriptionFieldDepositModel> fields, List<String> acceptedPidTypes) throws JsonProcessingException{
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
Set<String> values = new HashSet<>();
|
||||
for(DescriptionFieldDepositModel field: fields){
|
||||
//TODO: Check how to parse this values after update the logic of description persist from the main app
|
||||
List<String> value =field.getValues() == null ? new ArrayList<>() : field.getValues().stream().map(x-> (String)x).filter(x-> x == null || x.isEmpty()).toList();
|
||||
if(!value.isEmpty()) {
|
||||
switch (field.getFieldType()) {
|
||||
case FREE_TEXT:
|
||||
case TEXT_AREA:
|
||||
case RICH_TEXT_AREA:
|
||||
case RADIO_BOX:
|
||||
case DATE_PICKER:
|
||||
case AUTO_COMPLETE:
|
||||
case WORD_LIST:
|
||||
values.addAll(value);
|
||||
break;
|
||||
case SERVICES:
|
||||
case EXTERNAL_DATASETS:
|
||||
case DATA_REPOSITORIES:
|
||||
case PUB_REPOSITORIES:
|
||||
case JOURNAL_REPOSITORIES:
|
||||
case TAXONOMIES:
|
||||
case PUBLICATIONS:
|
||||
for (String s : value) {
|
||||
Map<String, String> valueMap = objectMapper.readValue(s, new TypeReference<Map<String, String>>() {
|
||||
});
|
||||
String pid = valueMap.get(this.pidProperties.getFields().getPidName());
|
||||
String pidType = valueMap.get(this.pidProperties.getFields().getPidTypeName());
|
||||
if (acceptedPidTypes.contains(pidType)) {
|
||||
values.add(pid);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ORGANIZATIONS:
|
||||
case RESEARCHERS:
|
||||
for (String s : value) {
|
||||
Map<String, String> valueMap = objectMapper.readValue(s, new TypeReference<Map<String, String>>() {});
|
||||
String pid = valueMap.get("reference");
|
||||
if(pid != null) {
|
||||
values.add(pid);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case DATASET_IDENTIFIER:
|
||||
for (String s : value) {
|
||||
Map<String, String> valueMap = objectMapper.readValue(s, new TypeReference<Map<String, String>>() {});
|
||||
values.add(valueMap.get("identifier"));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
private List<ReferenceDepositModel> getReferenceDepositModelOfType(DmpDepositModel dmp, ReferenceType referenceType){
|
||||
if (dmp.getReferences() == null) return new ArrayList<>();
|
||||
return dmp.getReferences().stream().filter(x -> x.getType().equals(referenceType)).toList();
|
||||
}
|
||||
|
||||
private void applyZenodoRelator(DmpDepositModel dmp, ZenodoDeposit deposit) throws JsonProcessingException {
|
||||
if (deposit.getMetadata() == null) deposit.setMetadata(new ZenodoDepositMetadata());
|
||||
|
||||
List<String> acceptedPidTypes = this.pidProperties.getAcceptedTypes();
|
||||
List<ZenodoRelator> relatedIdentifiers = new ArrayList<>();
|
||||
for(DescriptionDepositModel descriptionDepositModel: dmp.getDescriptions()){
|
||||
for(String relatedId: this.identifierProperties.getRelated()){
|
||||
List<DescriptionFieldDepositModel> fields = findSchematicValues(relatedId, descriptionDepositModel.getFields());
|
||||
Set<String> values = extractSchematicValues(fields, acceptedPidTypes);
|
||||
for(String value: values){
|
||||
ZenodoRelator relator = new ZenodoRelator();
|
||||
relator.setRelation(relatedId.substring(relatedId.lastIndexOf(".") + 1));
|
||||
relator.setIdentifier(value);
|
||||
relatedIdentifiers.add(relator);
|
||||
}
|
||||
}
|
||||
}
|
||||
deposit.getMetadata().setRelatedIdentifiers(relatedIdentifiers);
|
||||
}
|
||||
|
||||
private void applyAccessRight(DmpDepositModel dmp, ZenodoDeposit deposit){
|
||||
if (deposit.getMetadata() == null) deposit.setMetadata(new ZenodoDepositMetadata());
|
||||
|
||||
if (dmp.getAccessType() == null) {
|
||||
deposit.getMetadata().setAccessRight(ZenodoAccessRight.RESTRICTED);
|
||||
deposit.getMetadata().setAccessConditions("");
|
||||
} else {
|
||||
if (dmp.getAccessType().equals(DmpAccessType.Public)) {
|
||||
Instant publicationDate = dmp.getFinalizedAt();
|
||||
if (publicationDate == null) publicationDate = Instant.now().minusSeconds(1);
|
||||
|
||||
if (publicationDate.isBefore(Instant.now())) {
|
||||
deposit.getMetadata().setAccessRight(ZenodoAccessRight.OPEN);
|
||||
} else {
|
||||
deposit.getMetadata().setAccessRight(ZenodoAccessRight.EMBARGOED);
|
||||
deposit.getMetadata().setEmbargoDate(publicationDate.toString());
|
||||
}
|
||||
} else {
|
||||
deposit.getMetadata().setAccessRight(ZenodoAccessRight.RESTRICTED);
|
||||
deposit.getMetadata().setAccessConditions("");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void applyIsIdenticalTo(DmpDepositModel dmp, ZenodoDeposit deposit, ZenodoProperties zenodoConfig){
|
||||
if (deposit.getMetadata() == null) deposit.setMetadata(new ZenodoDepositMetadata());
|
||||
|
||||
if (dmp.getAccessType().equals(DmpAccessType.Public)) {
|
||||
ZenodoRelator relator = new ZenodoRelator();
|
||||
relator.setIdentifier(zenodoConfig.getDomain() + "/external/zenodo/" + dmp.getId().toString());
|
||||
relator.setRelation(IS_IDENTICAL_TO);
|
||||
if (deposit.getMetadata().getRelatedIdentifiers() == null)deposit.getMetadata().setRelatedIdentifiers(new ArrayList<>());
|
||||
deposit.getMetadata().getRelatedIdentifiers().add(relator);
|
||||
}
|
||||
}
|
||||
|
||||
private void applyLicenses(DmpDepositModel dmp, ZenodoDeposit deposit){
|
||||
if (deposit.getMetadata() == null) deposit.setMetadata(new ZenodoDepositMetadata());
|
||||
|
||||
List<ReferenceDepositModel> dmpLicenses = this.getReferenceDepositModelOfType(dmp, ReferenceType.Licenses);
|
||||
if (dmpLicenses != null && !dmpLicenses.isEmpty()) {
|
||||
for (ReferenceDepositModel dmpLicense : dmpLicenses) {
|
||||
String pid = dmpLicense.getDefinition().getFields().stream().filter(x-> PID.equalsIgnoreCase(x.getCode())).map(FieldDepositModel::getValue).findFirst().orElse(null);
|
||||
if (pid != null && !pid.isBlank()) {
|
||||
deposit.getMetadata().setLicense(pid);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void applyResearchers(DmpDepositModel dmp, ZenodoDeposit deposit){
|
||||
if (deposit.getMetadata() == null) deposit.setMetadata(new ZenodoDepositMetadata());
|
||||
|
||||
List<ZenodoContributor> researchers = new ArrayList<>();
|
||||
List<ReferenceDepositModel> dmpResearchers = this.getReferenceDepositModelOfType(dmp, ReferenceType.Researcher);
|
||||
if (dmpResearchers != null && !dmpResearchers.isEmpty()) {
|
||||
for (ReferenceDepositModel researcher : dmpResearchers) {
|
||||
ZenodoContributor contributor = new ZenodoContributor();
|
||||
contributor.setName(researcher.getLabel());
|
||||
contributor.setType(CONTRIBUTOR_TYPE_RESEARCHER);
|
||||
contributor.setAffiliation(researcher.getSource());
|
||||
if (researcher.getSource().equalsIgnoreCase(SOURCE_ORCID)) {
|
||||
contributor.setOrcid(researcher.getReference());
|
||||
}
|
||||
researchers.add(contributor);
|
||||
}
|
||||
}
|
||||
|
||||
if (deposit.getMetadata().getContributors() == null)deposit.getMetadata().setContributors(new ArrayList<>());
|
||||
|
||||
deposit.getMetadata().getContributors().addAll(researchers);
|
||||
}
|
||||
|
||||
private void applyGrants(DmpDepositModel dmp, ZenodoDeposit deposit){
|
||||
if (deposit.getMetadata() == null) deposit.setMetadata(new ZenodoDepositMetadata());
|
||||
List<ReferenceDepositModel> dmpGrants = this.getReferenceDepositModelOfType(dmp, ReferenceType.Grants);
|
||||
List<ReferenceDepositModel> dmpFunders = this.getReferenceDepositModelOfType(dmp, ReferenceType.Funder);
|
||||
|
||||
|
||||
if (dmpGrants != null && !dmpGrants.isEmpty()) {
|
||||
ReferenceDepositModel depositGrant = dmpGrants.stream().filter(x-> x.getSource().equals(SOURCE_OPENAIRE)).findFirst().orElse(null);
|
||||
|
||||
if (depositGrant != null) {
|
||||
String grantReferenceTail = depositGrant.getReference().split(":")[2];
|
||||
List<FunderProperties.DoiFunder> doiFunders = this.funderProperties.getAvailable();
|
||||
if (dmpFunders != null && !dmpFunders.isEmpty()) {
|
||||
ReferenceDepositModel depositFunder = dmpFunders.get(0);
|
||||
FunderProperties.DoiFunder doiFunder = doiFunders.stream()
|
||||
.filter(doiFunder1 -> depositFunder.getLabel().contains(doiFunder1.getFunder()) || doiFunder1.getFunder().contains(depositFunder.getLabel()))
|
||||
.findFirst().orElse(null);
|
||||
if (doiFunder != null) {
|
||||
String finalId = doiFunder.getDoi() + "::" + grantReferenceTail;
|
||||
ZenodoGrant grant = new ZenodoGrant();
|
||||
grant.setId(finalId);
|
||||
if (deposit.getMetadata().getGrants() == null)deposit.getMetadata().setGrants(new ArrayList<>());
|
||||
deposit.getMetadata().getGrants().add(grant);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void applyContributors(DmpDepositModel dmp, ZenodoDeposit deposit, ZenodoProperties zenodoConfig){
|
||||
if (dmp.getUsers() == null) return;
|
||||
|
||||
if (deposit.getMetadata() == null) deposit.setMetadata(new ZenodoDepositMetadata());
|
||||
|
||||
List<ReferenceDepositModel> dmpOrganizations = this.getReferenceDepositModelOfType(dmp, ReferenceType.Organizations);
|
||||
String zenodoAffiliation = zenodoConfig.getAffiliation();
|
||||
|
||||
List<ZenodoContributor> contributors = new ArrayList<>();
|
||||
for (DmpUserDepositModel userDMP: dmp.getUsers()) {
|
||||
ZenodoContributor contributor = new ZenodoContributor();
|
||||
contributor.setName(userDMP.getUser().getName());
|
||||
contributor.setType(CONTRIBUTOR_TYPE_PROJECT_MANAGER);
|
||||
if (dmpOrganizations != null && !dmpOrganizations.isEmpty()) {
|
||||
contributor.setAffiliation(dmpOrganizations.stream().map(ReferenceDepositModel::getLabel).collect(Collectors.joining(", ")));
|
||||
} else {
|
||||
if(zenodoAffiliation != null && !zenodoAffiliation.isEmpty()) {
|
||||
contributor.setAffiliation(zenodoAffiliation);
|
||||
}
|
||||
}
|
||||
contributors.add(contributor);
|
||||
}
|
||||
if (deposit.getMetadata().getContributors() == null)deposit.getMetadata().setContributors(new ArrayList<>());
|
||||
|
||||
deposit.getMetadata().getContributors().addAll(contributors);
|
||||
|
||||
}
|
||||
|
||||
private void applyCreators(DmpDepositModel dmp, ZenodoDeposit deposit, ZenodoProperties zenodoConfig){
|
||||
if (dmp.getUsers() == null) return;
|
||||
|
||||
if (deposit.getMetadata() == null) deposit.setMetadata(new ZenodoDepositMetadata());
|
||||
|
||||
List<ReferenceDepositModel> dmpOrganizations = this.getReferenceDepositModelOfType(dmp, ReferenceType.Organizations);
|
||||
String zenodoAffiliation = zenodoConfig.getAffiliation();
|
||||
|
||||
ZenodoCreator creator = new ZenodoCreator();
|
||||
DmpUserDepositModel dmpDepositModel = dmp.getUsers().stream().filter(userDMP -> userDMP.getRole().equals(DmpUserRole.Owner)).findFirst().orElse(null);
|
||||
if (dmpDepositModel == null || dmpDepositModel.getUser() == null) return;
|
||||
|
||||
creator.setName(dmpDepositModel.getUser().getName());
|
||||
if (dmpOrganizations != null && !dmpOrganizations.isEmpty()) {
|
||||
creator.setAffiliation(dmpOrganizations.stream().map(ReferenceDepositModel::getLabel).collect(Collectors.joining(", ")));
|
||||
} else {
|
||||
if(zenodoAffiliation != null && !zenodoAffiliation.isEmpty()) {
|
||||
creator.setAffiliation(zenodoAffiliation);
|
||||
}
|
||||
}
|
||||
if (deposit.getMetadata().getCreators() == null)deposit.getMetadata().setCreators(new ArrayList<>());
|
||||
deposit.getMetadata().getCreators().add(creator);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
package eu.eudat.depositinterface.zenodorepository.models;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonValue;
|
||||
|
||||
public enum ZenodoAccessRight {
|
||||
RESTRICTED("restricted"), EMBARGOED("embargoed"), OPEN("open");
|
||||
|
||||
private final String value;
|
||||
|
||||
ZenodoAccessRight(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@JsonValue
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package eu.eudat.depositinterface.zenodorepository.service;
|
||||
|
||||
import eu.eudat.depositinterface.models.DmpDepositModel;
|
||||
import eu.eudat.depositinterface.repository.DepositConfiguration;
|
||||
|
||||
public interface ZenodoDepositService {
|
||||
String deposit(DmpDepositModel dmpDepositModel, String zenodoToken) throws Exception;
|
||||
|
||||
DepositConfiguration getConfiguration();
|
||||
|
||||
String authenticate(String code);
|
||||
|
||||
String getLogo();
|
||||
}
|
|
@ -0,0 +1,326 @@
|
|||
package eu.eudat.depositinterface.zenodorepository.service;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import eu.eudat.depositinterface.models.DmpDepositModel;
|
||||
import eu.eudat.depositinterface.models.FileEnvelope;
|
||||
import eu.eudat.depositinterface.repository.DepositConfiguration;
|
||||
import eu.eudat.depositinterface.zenodorepository.configuration.zenodo.ZenodoProperties;
|
||||
import eu.eudat.depositinterface.zenodorepository.model.ZenodoDeposit;
|
||||
import eu.eudat.depositinterface.zenodorepository.model.builder.ZenodoBuilder;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.core.ParameterizedTypeReference;
|
||||
import org.springframework.core.io.ByteArrayResource;
|
||||
import org.springframework.http.*;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.util.ResourceUtils;
|
||||
import org.springframework.web.client.HttpClientErrorException;
|
||||
import org.springframework.web.client.HttpServerErrorException;
|
||||
import org.springframework.web.reactive.function.BodyInserters;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
@Component
|
||||
public class ZenodoDepositServiceImpl implements ZenodoDepositService {
|
||||
private static final String PUBLISH_ID = "conceptdoi";
|
||||
|
||||
private static final String CLIENT_ID = "client_id";
|
||||
private static final String CLIENT_SECRET = "client_secret";
|
||||
private static final String GRANT_TYPE = "grant_type";
|
||||
private static final String AUTHORIZATION_CODE = "authorization_code";
|
||||
private static final String CODE = "code";
|
||||
private static final String ZENODO_LINKS = "links";
|
||||
private static final String REDIRECT_URI = "redirect_uri";
|
||||
private static final String ACCESS_TOKEN = "access_token";
|
||||
private static final String ZENODO_LINKS_BUCKET = "bucket";
|
||||
private static final String ZENODO_LINKS_PUBLISH = "publish";
|
||||
private static final String ZENODO_LINKS_SELF = "self";
|
||||
private static final String ZENODO_LINKS_LATEST_DRAFT = "latest_draft";
|
||||
private static final String ZENODO_METADATA = "metadata";
|
||||
private static final String ZENODO_METADATA_VERSION = "version";
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(ZenodoDepositServiceImpl.class);
|
||||
private static final ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
private final ZenodoProperties zenodoProperties;
|
||||
private final ZenodoBuilder mapper;
|
||||
|
||||
private byte[] logo;
|
||||
|
||||
@Autowired
|
||||
public ZenodoDepositServiceImpl(ZenodoProperties zenodoProperties, ZenodoBuilder mapper){
|
||||
this.zenodoProperties = zenodoProperties;
|
||||
this.mapper = mapper;
|
||||
this.logo = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String deposit(DmpDepositModel dmpDepositModel, String zenodoToken) throws Exception {
|
||||
|
||||
DepositConfiguration depositConfiguration = this.getConfiguration();
|
||||
|
||||
if(depositConfiguration != null) {
|
||||
|
||||
if (zenodoToken == null || zenodoToken.isEmpty()) {
|
||||
zenodoToken = depositConfiguration.getAccessToken();
|
||||
}
|
||||
|
||||
String zenodoUrl = depositConfiguration.getRepositoryUrl();
|
||||
|
||||
// First step, post call to Zenodo, to create the entry.
|
||||
WebClient zenodoClient = WebClient.builder().build();
|
||||
|
||||
DepositConfiguration zenodoConfig = this.zenodoProperties.getDepositConfiguration();
|
||||
if (zenodoConfig == null) return null;
|
||||
eu.eudat.depositinterface.zenodorepository.model.ZenodoDeposit deposit = mapper.build(dmpDepositModel, this.zenodoProperties);
|
||||
|
||||
LinkedHashMap<String, String> links;
|
||||
String previousDOI = dmpDepositModel.getPreviousDOI();
|
||||
String unpublishedUrl = null;
|
||||
String publishUrl;
|
||||
try {
|
||||
|
||||
if (previousDOI == null) {
|
||||
links = deposit(zenodoToken, zenodoUrl, zenodoClient, deposit);
|
||||
} else {
|
||||
unpublishedUrl = this.getUnpublishedDOI(zenodoUrl, previousDOI, zenodoToken, dmpDepositModel.getVersion());
|
||||
if (unpublishedUrl == null) {
|
||||
//It requires more than one step to create a new version
|
||||
//First, get the deposit related to the concept DOI
|
||||
links = depositNewVersion(zenodoToken, zenodoUrl, previousDOI, zenodoClient, deposit);
|
||||
} else {
|
||||
links = depositFromPreviousDoi(zenodoToken, zenodoUrl, previousDOI, zenodoClient);
|
||||
}
|
||||
}
|
||||
|
||||
if (unpublishedUrl == null) {
|
||||
// Second step, add the file to the entry.
|
||||
FileEnvelope pdfEnvelope = dmpDepositModel.getPdfFile();
|
||||
|
||||
if (links == null || !links.containsKey(ZENODO_LINKS_BUCKET)) throw new Exception("bucket not found");
|
||||
|
||||
String addFileUrl = links.get(ZENODO_LINKS_BUCKET) + "/" + pdfEnvelope.getFilename() + "?access_token=" + zenodoToken;
|
||||
zenodoClient.put().uri(addFileUrl)
|
||||
.body(BodyInserters
|
||||
.fromResource(new ByteArrayResource(pdfEnvelope.getFile())))
|
||||
.retrieve().toEntity(Map.class).block();
|
||||
FileEnvelope rdaJsonEnvelope = dmpDepositModel.getRdaJsonFile();
|
||||
|
||||
String jsonFileName = rdaJsonEnvelope.getFilename();
|
||||
addFileUrl = links.get(ZENODO_LINKS_BUCKET) + "/" + jsonFileName + "?access_token=" + zenodoToken;
|
||||
zenodoClient.put().uri(addFileUrl).headers(httpHeaders -> httpHeaders.setContentType(MediaType.APPLICATION_OCTET_STREAM)).body(BodyInserters.fromResource(new ByteArrayResource(rdaJsonEnvelope.getFile()))).retrieve().toEntity(Map.class).block();
|
||||
|
||||
if (dmpDepositModel.getSupportingFilesZip() != null) {
|
||||
String supportingFilesZipName = dmpDepositModel.getSupportingFilesZip().getFilename();
|
||||
|
||||
addFileUrl = links.get(ZENODO_LINKS_BUCKET) + "/" + supportingFilesZipName + "?access_token=" + zenodoToken;
|
||||
zenodoClient.put().uri(addFileUrl).body(BodyInserters.fromResource(new ByteArrayResource(supportingFilesZipName.getBytes()))).retrieve().toEntity(Map.class).block();
|
||||
}
|
||||
|
||||
// Third post call to Zenodo to publish the entry and return the DOI.
|
||||
publishUrl = links.get(ZENODO_LINKS_PUBLISH) + "?access_token=" + zenodoToken;
|
||||
} else {
|
||||
publishUrl = unpublishedUrl + "?access_token=" + zenodoToken;
|
||||
}
|
||||
|
||||
return this.publish(publishUrl);
|
||||
|
||||
} catch (HttpClientErrorException | HttpServerErrorException ex) {
|
||||
Map<String, String> parsedException = objectMapper.readValue(ex.getResponseBodyAsString(), Map.class);
|
||||
throw new IOException(parsedException.get("message"), ex);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
private static LinkedHashMap<String, String> depositNewVersion(String zenodoToken, String zenodoUrl, String previousDOI, WebClient zenodoClient, ZenodoDeposit deposit) throws Exception {
|
||||
Map<String, LinkedHashMap<String, String>> createResponse;
|
||||
LinkedHashMap<String, String> links;
|
||||
String listUrl = zenodoUrl + "deposit/depositions" + "?q=conceptdoi:\"" + previousDOI + "\"&access_token=" + zenodoToken;
|
||||
logger.debug("listUrl = " + listUrl);
|
||||
ResponseEntity<List<Map>> listResponses = zenodoClient.get().uri(listUrl).retrieve().toEntityList(Map.class).block();
|
||||
if (listResponses == null || listResponses.getBody() == null || listResponses.getBody().isEmpty()) return null;
|
||||
createResponse = (Map<String, LinkedHashMap<String, String>>) listResponses.getBody().get(0);
|
||||
logger.debug("createResponse-previousDoi:");
|
||||
logger.debug(objectMapper.writeValueAsString(createResponse));
|
||||
links = (LinkedHashMap<String, String>) createResponse.getOrDefault(ZENODO_LINKS, new LinkedHashMap<>());
|
||||
|
||||
//Second, make the new version (not in the links?)
|
||||
if (!links.containsKey(ZENODO_LINKS_LATEST_DRAFT)) throw new Exception("previousDOI not found");
|
||||
String newVersionUrl = links.get(ZENODO_LINKS_LATEST_DRAFT) + "/actions/newversion" + "?access_token=" + zenodoToken;
|
||||
logger.debug("new version url: " + newVersionUrl);
|
||||
createResponse = zenodoClient.post().uri(newVersionUrl)
|
||||
.bodyValue(null).exchangeToMono(mono -> mono.bodyToMono(new ParameterizedTypeReference<Map<String, LinkedHashMap<String, String>>>() {})).block();
|
||||
logger.debug("createResponse-newVersion:");
|
||||
logger.debug(objectMapper.writeValueAsString(createResponse));
|
||||
links = createResponse == null ? new LinkedHashMap<>() : createResponse.getOrDefault(ZENODO_LINKS, new LinkedHashMap<>());
|
||||
|
||||
//Third, get the new deposit
|
||||
if (!links.containsKey(ZENODO_LINKS_LATEST_DRAFT)) throw new Exception("can not create latest draft");
|
||||
String latestDraftUrl = links.get(ZENODO_LINKS_LATEST_DRAFT) + "?access_token=" + zenodoToken;
|
||||
createResponse = zenodoClient.get().uri(latestDraftUrl)
|
||||
.exchangeToMono(mono -> mono.bodyToMono(new ParameterizedTypeReference<Map<String, LinkedHashMap<String, String>>>() {})).block();
|
||||
logger.debug("createResponse-latestDraft:");
|
||||
logger.debug(objectMapper.writeValueAsString(createResponse));
|
||||
links = createResponse == null ? new LinkedHashMap<>() : createResponse.getOrDefault(ZENODO_LINKS, new LinkedHashMap<>());
|
||||
|
||||
//At this point it might fail to perform the next requests so enclose them with try catch
|
||||
try {
|
||||
//Forth, update the new deposit's metadata
|
||||
String updateUrl = links.get(ZENODO_LINKS_SELF) + "?access_token=" + zenodoToken;
|
||||
zenodoClient.put().uri(updateUrl)
|
||||
.headers(httpHeaders -> {
|
||||
httpHeaders.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
|
||||
httpHeaders.setContentType(MediaType.APPLICATION_JSON);
|
||||
})
|
||||
.bodyValue(deposit).retrieve().toEntity(Map.class).block();
|
||||
//And finally remove pre-existing files from it
|
||||
String fileListUrl = links.get(ZENODO_LINKS_SELF) + "/files" + "?access_token=" + zenodoToken;
|
||||
ResponseEntity<List<Map>> fileListResponse = zenodoClient.get().uri(fileListUrl).retrieve().toEntityList(Map.class).block();
|
||||
for (Map file : fileListResponse.getBody()) {
|
||||
String fileDeleteUrl = links.get(ZENODO_LINKS_SELF) + "/files/" + file.get("id") + "?access_token=" + zenodoToken;
|
||||
zenodoClient.delete().uri(fileDeleteUrl).retrieve().toEntity(Map.class).block();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
//In case the last two steps fail delete the latest Deposit it in order to create a new one (only one at a time is allowed)
|
||||
//restTemplate.delete(latestDraftUrl);
|
||||
zenodoClient.delete().uri(latestDraftUrl).retrieve().toEntity(Map.class).block();
|
||||
throw e;
|
||||
}
|
||||
return links;
|
||||
}
|
||||
|
||||
private static LinkedHashMap<String, String> depositFromPreviousDoi(String zenodoToken, String zenodoUrl, String previousDOI, WebClient zenodoClient) {
|
||||
Map<String, LinkedHashMap<String, String>> createResponse;
|
||||
String listUrl = zenodoUrl + "deposit/depositions" + "?q=conceptdoi:\"" + previousDOI + "\"&access_token=" + zenodoToken;
|
||||
ResponseEntity<List<Map>> listResponses = zenodoClient.get().uri(listUrl).retrieve().toEntityList(Map.class).block();
|
||||
if (listResponses == null || listResponses.getBody() == null || listResponses.getBody().isEmpty()) return null;
|
||||
|
||||
createResponse = (Map<String, LinkedHashMap<String, String>>) listResponses.getBody().get(0);
|
||||
|
||||
return createResponse.getOrDefault(ZENODO_LINKS, null);
|
||||
}
|
||||
|
||||
private LinkedHashMap<String, String> deposit(String zenodoToken, String zenodoUrl, WebClient zenodoClient, ZenodoDeposit deposit) {
|
||||
Map<String, Object> createResponse;
|
||||
String createUrl = zenodoUrl + "deposit/depositions" + "?access_token=" + zenodoToken;
|
||||
createResponse = zenodoClient.post().uri(createUrl).headers(httpHeaders -> {
|
||||
httpHeaders.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
|
||||
httpHeaders.setContentType(MediaType.APPLICATION_JSON);
|
||||
})
|
||||
.bodyValue(deposit).exchangeToMono(mono -> mono.bodyToMono(new ParameterizedTypeReference<Map<String, Object>>() {})).block();
|
||||
return (LinkedHashMap<String, String>) createResponse.getOrDefault(ZENODO_LINKS, null);
|
||||
}
|
||||
|
||||
private String publish(String publishUrl){
|
||||
WebClient webClient = WebClient.builder().build();
|
||||
Map<String, Object> publishResponse = webClient.post().uri(publishUrl).bodyValue("").exchangeToMono(mono -> {
|
||||
if (!mono.statusCode().is2xxSuccessful()) {
|
||||
mono.createException();
|
||||
throw new UnsupportedOperationException("Failed to publish to Zenodo");
|
||||
}
|
||||
return mono.bodyToMono(new ParameterizedTypeReference<Map<String, Object>>() {
|
||||
});
|
||||
}).block();
|
||||
if (publishResponse == null) throw new UnsupportedOperationException("Failed to publish to Zenodo");
|
||||
return (String) publishResponse.get(PUBLISH_ID);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public DepositConfiguration getConfiguration() {
|
||||
return this.zenodoProperties.getDepositConfiguration();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String authenticate(String code){
|
||||
|
||||
DepositConfiguration depositConfiguration = this.getConfiguration();
|
||||
|
||||
if(depositConfiguration != null) {
|
||||
|
||||
WebClient client = WebClient.builder().defaultHeaders(httpHeaders -> {
|
||||
httpHeaders.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
|
||||
httpHeaders.setContentType(MediaType.MULTIPART_FORM_DATA);
|
||||
}).build();
|
||||
|
||||
MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
|
||||
map.add(CLIENT_ID, depositConfiguration.getRepositoryClientId());
|
||||
map.add(CLIENT_SECRET, depositConfiguration.getRepositoryClientSecret());
|
||||
map.add(GRANT_TYPE, AUTHORIZATION_CODE);
|
||||
map.add(CODE, code);
|
||||
map.add(REDIRECT_URI, depositConfiguration.getRedirectUri());
|
||||
|
||||
try {
|
||||
Map<String, Object> values = client.post().uri(depositConfiguration.getRepositoryAccessTokenUrl()).bodyValue(map).exchangeToMono(mono -> {
|
||||
if (!mono.statusCode().is2xxSuccessful()) {
|
||||
mono.createException();
|
||||
throw new HttpClientErrorException(mono.statusCode());
|
||||
}
|
||||
return mono.bodyToMono(new ParameterizedTypeReference<Map<String, Object>>() {
|
||||
});
|
||||
}).block();
|
||||
|
||||
return values != null ? (String) values.getOrDefault(ACCESS_TOKEN, null) : null;
|
||||
} catch (HttpClientErrorException ex) {
|
||||
logger.error(ex.getResponseBodyAsString(), ex);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLogo() {
|
||||
DepositConfiguration zenodoConfig = this.zenodoProperties.getDepositConfiguration();
|
||||
if(zenodoConfig != null && zenodoConfig.isHasLogo() && this.zenodoProperties.getLogo() != null && !this.zenodoProperties.getLogo().isBlank()) {
|
||||
if (this.logo == null) {
|
||||
try {
|
||||
java.io.File logoFile = ResourceUtils.getFile(this.zenodoProperties.getLogo());
|
||||
if (!logoFile.exists()) return null;
|
||||
try(InputStream inputStream = new FileInputStream(logoFile)){
|
||||
this.logo = inputStream.readAllBytes();
|
||||
};
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
return (this.logo != null && this.logo.length != 0) ? Base64.getEncoder().encodeToString(this.logo) : null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String getUnpublishedDOI(String zenodoUrl, String doi, String token, Short version) {
|
||||
try {
|
||||
WebClient client = WebClient.builder().build();
|
||||
Map<String, LinkedHashMap<String, String>> createResponse = null;
|
||||
LinkedHashMap<String, String> links;
|
||||
LinkedHashMap<String, String> metadata;
|
||||
String listUrl = zenodoUrl + "deposit/depositions" + "?q=conceptdoi:\"" + doi + "\"&access_token=" + token;
|
||||
ResponseEntity<List<Map>> listResponses = client.get().uri(listUrl).retrieve().toEntityList(Map.class).block();
|
||||
if (listResponses == null || listResponses.getBody() == null || listResponses.getBody().isEmpty()) return null;
|
||||
|
||||
createResponse = (Map<String, LinkedHashMap<String, String>>) listResponses.getBody().get(0);
|
||||
metadata = createResponse.getOrDefault(ZENODO_METADATA, new LinkedHashMap<>());
|
||||
links = createResponse.getOrDefault(ZENODO_LINKS, new LinkedHashMap<>());
|
||||
|
||||
if (metadata.get(ZENODO_METADATA_VERSION).equals(version.toString())) {
|
||||
return links.get(ZENODO_LINKS_PUBLISH);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}catch (Exception e) {
|
||||
logger.warn(e.getMessage(), e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -12,6 +12,9 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
|||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
|
||||
import org.springframework.security.config.http.SessionCreationPolicy;
|
||||
import org.springframework.security.oauth2.jwt.JwtDecoder;
|
||||
import org.springframework.security.oauth2.jwt.JwtDecoders;
|
||||
import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter;
|
||||
|
||||
|
@ -21,13 +24,11 @@ import java.util.Set;
|
|||
@EnableWebSecurity
|
||||
public class SecurityConfiguration {
|
||||
|
||||
private final ApiKeyFilter apiKeyFilter;
|
||||
private final WebSecurityProperties webSecurityProperties;
|
||||
private final AuthenticationManagerResolver<HttpServletRequest> authenticationManagerResolver;
|
||||
|
||||
@Autowired
|
||||
public SecurityConfiguration(ApiKeyFilter apiKeyFilter, WebSecurityProperties webSecurityProperties, AuthenticationManagerResolver<HttpServletRequest> authenticationManagerResolver) {
|
||||
this.apiKeyFilter = apiKeyFilter;
|
||||
public SecurityConfiguration(WebSecurityProperties webSecurityProperties, AuthenticationManagerResolver<HttpServletRequest> authenticationManagerResolver) {
|
||||
this.webSecurityProperties = webSecurityProperties;
|
||||
this.authenticationManagerResolver = authenticationManagerResolver;
|
||||
}
|
||||
|
@ -36,7 +37,6 @@ public class SecurityConfiguration {
|
|||
protected SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||
http.csrf(AbstractHttpConfigurer::disable)
|
||||
.cors(Customizer.withDefaults())
|
||||
.addFilterBefore(apiKeyFilter, AbstractPreAuthenticatedProcessingFilter.class)
|
||||
.authorizeHttpRequests(authorizationManagerRequestMatcherRegistry -> authorizationManagerRequestMatcherRegistry
|
||||
.requestMatchers(buildAntPatterns(webSecurityProperties.getAuthorizedEndpoints())).authenticated()
|
||||
.requestMatchers(buildAntPatterns(webSecurityProperties.getAllowedEndpoints())).anonymous())
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package eu.eudat.deposit.controller;
|
||||
|
||||
import eu.eudat.depositinterface.models.DMPDepositModel;
|
||||
import eu.eudat.depositinterface.repository.RepositoryDeposit;
|
||||
import eu.eudat.depositinterface.repository.RepositoryDepositConfiguration;
|
||||
import eu.eudat.depositinterface.models.DmpDepositModel;
|
||||
import eu.eudat.depositinterface.repository.DepositConfiguration;
|
||||
import eu.eudat.depositinterface.zenodorepository.service.ZenodoDepositService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
|
@ -10,33 +10,29 @@ import java.util.List;
|
|||
|
||||
@RestController
|
||||
@RequestMapping("/api/deposit")
|
||||
public class DepositController {
|
||||
public class DepositController implements eu.eudat.depositinterface.repository.DepositController {
|
||||
|
||||
private final RepositoryDeposit repositoryDeposit;
|
||||
private final ZenodoDepositService depositClient;
|
||||
|
||||
@Autowired
|
||||
public DepositController(RepositoryDeposit repositoryDeposit) {
|
||||
this.repositoryDeposit = repositoryDeposit;
|
||||
public DepositController(ZenodoDepositService depositClient) {
|
||||
this.depositClient = depositClient;
|
||||
}
|
||||
|
||||
@PostMapping("/{id}")
|
||||
public String deposit(@PathVariable("id") String repositoryId, @RequestBody DMPDepositModel dmpDepositModel, @RequestParam("authToken")String authToken) throws Exception {
|
||||
return repositoryDeposit.deposit(repositoryId, dmpDepositModel, authToken);
|
||||
public String deposit(@RequestBody DmpDepositModel dmpDepositModel, @RequestParam("authToken")String authToken) throws Exception {
|
||||
return depositClient.deposit(dmpDepositModel, authToken);
|
||||
}
|
||||
|
||||
@GetMapping("/authenticate/{id}")
|
||||
public String authenticate(@PathVariable("id") String repositoryId, @RequestParam("authToken") String authToken) {
|
||||
return repositoryDeposit.authenticate(repositoryId, authToken);
|
||||
public String authenticate(@RequestParam("authToken") String code) {
|
||||
return depositClient.authenticate(code);
|
||||
}
|
||||
|
||||
@GetMapping("/configuration")
|
||||
public List<RepositoryDepositConfiguration> getConfiguration() {
|
||||
return repositoryDeposit.getConfiguration();
|
||||
public DepositConfiguration getConfiguration() {
|
||||
return depositClient.getConfiguration();
|
||||
}
|
||||
|
||||
@GetMapping("/logo/{id}")
|
||||
public String getLogo(@PathVariable("id") String repositoryId) {
|
||||
return repositoryDeposit.getLogo(repositoryId);
|
||||
public String getLogo() {
|
||||
return depositClient.getLogo();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ cache:
|
|||
manager:
|
||||
fallbackToNoOpCache: true
|
||||
caffeineCaches:
|
||||
- names: [ "apikey" ]
|
||||
- names: [ "logoByRepository" ]
|
||||
allowNullValues: true
|
||||
initialCapacity: 100
|
||||
maximumSize: 500
|
||||
|
@ -11,6 +11,8 @@ cache:
|
|||
expireAfterAccessMinutes: 10
|
||||
refreshAfterWriteMinutes: 10
|
||||
mapCaches:
|
||||
apiKey:
|
||||
name: apikey
|
||||
keyPattern: resolve_$keyhash$:v0
|
||||
logoByRepository:
|
||||
name: logoByRepository
|
||||
keyPattern: zenodoplugin_$repo$:v0
|
||||
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
web:
|
||||
security:
|
||||
idp:
|
||||
resource:
|
||||
jwt:
|
||||
audiences: [ "dmp_zenodo_bridge" ]
|
||||
validIssuer: ${IDP_ISSUER_URI:}
|
|
@ -5,16 +5,9 @@ web:
|
|||
allowed-endpoints: [ health ]
|
||||
idp:
|
||||
api-key:
|
||||
enabled: true
|
||||
authorization-header: Authorization
|
||||
client-id: ${IDP_APIKEY_CLIENT_ID:}
|
||||
client-secret: ${IDP_APIKEY_CLIENT_SECRET:}
|
||||
scope: ${IDP_APIKEY_SCOPE:}
|
||||
enabled: false
|
||||
resource:
|
||||
token-type: JWT #| opaque
|
||||
opaque:
|
||||
client-id: ${IDP_OPAQUE_CLIENT_ID:}
|
||||
client-secret: ${IDP_OPAQUE_CLIENT_SECRET:}
|
||||
jwt:
|
||||
claims: [ role, x-role ]
|
||||
issuer-uri: ${IDP_ISSUER_URI:}
|
|
@ -1,18 +1,17 @@
|
|||
zenodo:
|
||||
configuration:
|
||||
- deposit-type: 2
|
||||
repository-id: Zenodo
|
||||
access-token: ${ZENODO_ACCESS_TOKEN}
|
||||
repository-url: https://sandbox.zenodo.org/api/
|
||||
repository-authorization-url: https://sandbox.zenodo.org/oauth/authorize
|
||||
repository-record-url: https://sandbox.zenodo.org/record/
|
||||
repository-access-token-url: https://sandbox.zenodo.org/oauth/token
|
||||
repository-client-id:
|
||||
repository-client-secret:
|
||||
redirect-uri: http://localhost:4200/login/external/zenodo
|
||||
has-logo: true
|
||||
logo: classpath:zenodo.jpg
|
||||
doi-funder:
|
||||
community: argos
|
||||
affiliation: ARGOS
|
||||
domain: https://argos.openaire.eu/
|
||||
community: argos
|
||||
affiliation: ARGOS
|
||||
domain: https://argos.openaire.eu/
|
||||
logo: classpath:zenodo.jpg
|
||||
depositConfiguration:
|
||||
deposit-type: 2
|
||||
repository-id: Zenodo
|
||||
access-token: ${ZENODO_ACCESS_TOKEN}
|
||||
repository-url: https://sandbox.zenodo.org/api/
|
||||
repository-authorization-url: https://sandbox.zenodo.org/oauth/authorize
|
||||
repository-record-url: https://sandbox.zenodo.org/record/
|
||||
repository-access-token-url: https://sandbox.zenodo.org/oauth/token
|
||||
repository-client-id:
|
||||
repository-client-secret:
|
||||
redirect-uri: http://localhost:4200/login/external/zenodo
|
||||
has-logo: true
|
|
@ -1,3 +1 @@
|
|||
zenodo:
|
||||
storage:
|
||||
temp: ${STORAGE_TMP_ZENODO}
|
Loading…
Reference in New Issue