Improved Zenodo Account Integration
This commit is contained in:
parent
417ee02087
commit
982aea0cbf
|
@ -95,6 +95,14 @@ public class Users extends BaseController {
|
||||||
userManager.registerDOIToken(doiRequest, principal);
|
userManager.registerDOIToken(doiRequest, principal);
|
||||||
return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem<UserProfile>().status(ApiMessageCode.NO_MESSAGE));
|
return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem<UserProfile>().status(ApiMessageCode.NO_MESSAGE));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
@RequestMapping(method = RequestMethod.DELETE, value = {"/deleteDOIToken"}, consumes = "application/json", produces = "application/json")
|
||||||
|
public @ResponseBody
|
||||||
|
ResponseEntity<ResponseItem<UserProfile>> deleteDOIToken(Principal principal) throws NullEmailException, IOException {
|
||||||
|
userManager.deleteDOIToken(principal);
|
||||||
|
return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem<UserProfile>().status(ApiMessageCode.NO_MESSAGE));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,8 @@ public class PrincipalBuilder extends Builder<Principal> {
|
||||||
private String timezone;
|
private String timezone;
|
||||||
private String zenodoToken;
|
private String zenodoToken;
|
||||||
private Instant zenodoDuration;
|
private Instant zenodoDuration;
|
||||||
|
private String zenodoEmail;
|
||||||
|
private String zenodoRefresh;
|
||||||
|
|
||||||
public PrincipalBuilder id(UUID id) {
|
public PrincipalBuilder id(UUID id) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
|
@ -81,6 +83,16 @@ public class PrincipalBuilder extends Builder<Principal> {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public PrincipalBuilder zenodoEmail(String zenodoEmail) {
|
||||||
|
this.zenodoEmail = zenodoEmail;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PrincipalBuilder zenodoRefresh(String zenodoRefresh) {
|
||||||
|
this.zenodoRefresh = zenodoRefresh;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Principal build() {
|
public Principal build() {
|
||||||
Principal principal = new Principal();
|
Principal principal = new Principal();
|
||||||
|
@ -95,6 +107,8 @@ public class PrincipalBuilder extends Builder<Principal> {
|
||||||
principal.setTimezone(timezone);
|
principal.setTimezone(timezone);
|
||||||
principal.setZenodoToken(zenodoToken);
|
principal.setZenodoToken(zenodoToken);
|
||||||
principal.setZenodoDuration(zenodoDuration);
|
principal.setZenodoDuration(zenodoDuration);
|
||||||
|
principal.setZenodoEmail(zenodoEmail);
|
||||||
|
principal.setZenodoRefresh(zenodoRefresh);
|
||||||
return principal;
|
return principal;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ import eu.eudat.exceptions.security.NullEmailException;
|
||||||
import eu.eudat.exceptions.security.UnauthorisedException;
|
import eu.eudat.exceptions.security.UnauthorisedException;
|
||||||
import eu.eudat.logic.builders.entity.UserRoleBuilder;
|
import eu.eudat.logic.builders.entity.UserRoleBuilder;
|
||||||
import eu.eudat.logic.builders.model.models.DataTableDataBuilder;
|
import eu.eudat.logic.builders.model.models.DataTableDataBuilder;
|
||||||
|
import eu.eudat.logic.security.customproviders.Zenodo.ZenodoAccessType;
|
||||||
import eu.eudat.logic.security.customproviders.Zenodo.ZenodoCustomProvider;
|
import eu.eudat.logic.security.customproviders.Zenodo.ZenodoCustomProvider;
|
||||||
import eu.eudat.logic.security.validators.zenodo.helpers.ZenodoResponseToken;
|
import eu.eudat.logic.security.validators.zenodo.helpers.ZenodoResponseToken;
|
||||||
import eu.eudat.logic.services.ApiContext;
|
import eu.eudat.logic.services.ApiContext;
|
||||||
|
@ -129,21 +130,38 @@ public class UserManager {
|
||||||
if (Instant.now().isBefore(principal.getZenodoDuration())) {
|
if (Instant.now().isBefore(principal.getZenodoDuration())) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
Map<String, Object> settings = Collections.singletonMap("zenodoToken", "");
|
try {
|
||||||
this.updateSettings(settings, principal);
|
this.updateDOIToken(ZenodoAccessType.REFRESH_TOKEN, principal.getZenodoRefresh(), this.environment.getProperty("zenodo.login.redirect_uri"), principal);
|
||||||
throw new ExpiredTokenException("Zenodo Token is expired");
|
}catch (IOException e) {
|
||||||
|
throw new ExpiredTokenException("Zenodo Token is expired.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
throw new NonValidTokenException("This account has no Zenodo Token");
|
throw new NonValidTokenException("This account has no Zenodo Token");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void registerDOIToken(DOIRequest doiRequest, Principal principal) throws IOException {
|
public void registerDOIToken(DOIRequest doiRequest, Principal principal) throws IOException {
|
||||||
ZenodoResponseToken responseToken = this.zenodoCustomProvider.getAccessToken(doiRequest.getZenodoRequest().getCode()
|
this.updateDOIToken(ZenodoAccessType.AUTHORIZATION_CODE, doiRequest.getZenodoRequest().getCode(), doiRequest.getRedirectUri(), principal);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateDOIToken(ZenodoAccessType accessType, String code, String redirectUri, Principal principal) throws IOException {
|
||||||
|
ZenodoResponseToken responseToken = this.zenodoCustomProvider.getAccessToken(accessType, code
|
||||||
, this.environment.getProperty("zenodo.login.client_id")
|
, this.environment.getProperty("zenodo.login.client_id")
|
||||||
, this.environment.getProperty("zenodo.login.client_secret")
|
, this.environment.getProperty("zenodo.login.client_secret")
|
||||||
, doiRequest.getRedirectUri());
|
, redirectUri);
|
||||||
Map<String, Object> settings = new HashMap<>();
|
Map<String, Object> settings = new HashMap<>();
|
||||||
|
settings.put("zenodoEmail", responseToken.getEmail());
|
||||||
|
settings.put("zenodoRefresh", responseToken.getRefreshToken());
|
||||||
settings.put("zenodoToken", responseToken.getAccessToken());
|
settings.put("zenodoToken", responseToken.getAccessToken());
|
||||||
settings.put("expirationDate", Instant.now().plusSeconds(responseToken.getExpiresIn()).toEpochMilli());
|
settings.put("expirationDate", Instant.now().plusSeconds(responseToken.getExpiresIn()).toEpochMilli());
|
||||||
this.updateSettings(settings, principal);
|
this.updateSettings(settings, principal);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void deleteDOIToken(Principal principal) throws IOException {
|
||||||
|
Map<String, Object> settings = new HashMap<>();
|
||||||
|
settings.put("zenodoEmail", "");
|
||||||
|
settings.put("zenodoRefresh", "");
|
||||||
|
settings.put("zenodoToken", "");
|
||||||
|
settings.put("expirationDate", 0);
|
||||||
|
this.updateSettings(settings, principal);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
package eu.eudat.logic.security.customproviders.Zenodo;
|
||||||
|
|
||||||
|
public enum ZenodoAccessType {
|
||||||
|
AUTHORIZATION_CODE("authorization_code", "code"),
|
||||||
|
REFRESH_TOKEN("refresh_token", "refresh_token");
|
||||||
|
|
||||||
|
private final String grantType;
|
||||||
|
private final String property;
|
||||||
|
|
||||||
|
ZenodoAccessType(String grantType, String property) {
|
||||||
|
this.grantType = grantType;
|
||||||
|
this.property = property;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getGrantType() {
|
||||||
|
return grantType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getProperty() {
|
||||||
|
return property;
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,5 +4,5 @@ import eu.eudat.logic.security.validators.orcid.helpers.ORCIDResponseToken;
|
||||||
import eu.eudat.logic.security.validators.zenodo.helpers.ZenodoResponseToken;
|
import eu.eudat.logic.security.validators.zenodo.helpers.ZenodoResponseToken;
|
||||||
|
|
||||||
public interface ZenodoCustomProvider {
|
public interface ZenodoCustomProvider {
|
||||||
ZenodoResponseToken getAccessToken(String code, String clientId, String clientSecret, String redirectUri);
|
ZenodoResponseToken getAccessToken(ZenodoAccessType accessType, String code, String clientId, String clientSecret, String redirectUri);
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,7 @@ public class ZenodoCustomProviderImpl implements ZenodoCustomProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ZenodoResponseToken getAccessToken(String code, String clientId, String clientSecret, String redirectUri) {
|
public ZenodoResponseToken getAccessToken(ZenodoAccessType accessType, String code, String clientId, String clientSecret, String redirectUri) {
|
||||||
RestTemplate restTemplate = new RestTemplate();
|
RestTemplate restTemplate = new RestTemplate();
|
||||||
HttpHeaders headers = new HttpHeaders();
|
HttpHeaders headers = new HttpHeaders();
|
||||||
headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
|
headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
|
||||||
|
@ -41,8 +41,8 @@ public class ZenodoCustomProviderImpl implements ZenodoCustomProvider {
|
||||||
MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
|
MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
|
||||||
map.add("client_id", clientId);
|
map.add("client_id", clientId);
|
||||||
map.add("client_secret", clientSecret);
|
map.add("client_secret", clientSecret);
|
||||||
map.add("grant_type", "authorization_code");
|
map.add("grant_type", accessType.getGrantType());
|
||||||
map.add("code", code);
|
map.add(accessType.getProperty(), code);
|
||||||
map.add("redirect_uri", redirectUri);
|
map.add("redirect_uri", redirectUri);
|
||||||
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(map, headers);
|
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(map, headers);
|
||||||
|
|
||||||
|
@ -54,6 +54,7 @@ public class ZenodoCustomProviderImpl implements ZenodoCustomProvider {
|
||||||
zenodoResponseToken.setEmail((String) user.get("email"));
|
zenodoResponseToken.setEmail((String) user.get("email"));
|
||||||
zenodoResponseToken.setExpiresIn((Integer) values.get("expires_in"));
|
zenodoResponseToken.setExpiresIn((Integer) values.get("expires_in"));
|
||||||
zenodoResponseToken.setAccessToken((String) values.get("access_token"));
|
zenodoResponseToken.setAccessToken((String) values.get("access_token"));
|
||||||
|
zenodoResponseToken.setRefreshToken((String) values.get("refresh_token"));
|
||||||
|
|
||||||
return zenodoResponseToken;
|
return zenodoResponseToken;
|
||||||
} catch (HttpClientErrorException ex) {
|
} catch (HttpClientErrorException ex) {
|
||||||
|
|
|
@ -7,6 +7,7 @@ public class ZenodoUser {
|
||||||
private String email;
|
private String email;
|
||||||
private String accessToken;
|
private String accessToken;
|
||||||
private Integer expiresIn;
|
private Integer expiresIn;
|
||||||
|
private String refreshToken;
|
||||||
|
|
||||||
public String getUserId() {
|
public String getUserId() {
|
||||||
return userId;
|
return userId;
|
||||||
|
@ -39,11 +40,20 @@ public class ZenodoUser {
|
||||||
this.expiresIn = expiresIn;
|
this.expiresIn = expiresIn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getRefreshToken() {
|
||||||
|
return refreshToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRefreshToken(String refreshToken) {
|
||||||
|
this.refreshToken = refreshToken;
|
||||||
|
}
|
||||||
|
|
||||||
public ZenodoUser getZenodoUser(Object data) {
|
public ZenodoUser getZenodoUser(Object data) {
|
||||||
this.userId = (String) ((Map) data).get("userId");
|
this.userId = (String) ((Map) data).get("userId");
|
||||||
this.email = (String) ((Map) data).get("email");
|
this.email = (String) ((Map) data).get("email");
|
||||||
this.accessToken = (String) ((Map) data).get("accessToken");
|
this.accessToken = (String) ((Map) data).get("accessToken");
|
||||||
this.expiresIn = (Integer) ((Map) data).get("expiresIn");
|
this.expiresIn = (Integer) ((Map) data).get("expiresIn");
|
||||||
|
this.refreshToken = (String) ((Map) data).get("refreshToken");
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import eu.eudat.exceptions.security.NonValidTokenException;
|
||||||
import eu.eudat.exceptions.security.NullEmailException;
|
import eu.eudat.exceptions.security.NullEmailException;
|
||||||
import eu.eudat.logic.security.customproviders.ORCID.ORCIDCustomProvider;
|
import eu.eudat.logic.security.customproviders.ORCID.ORCIDCustomProvider;
|
||||||
import eu.eudat.logic.security.customproviders.ORCID.ORCIDUser;
|
import eu.eudat.logic.security.customproviders.ORCID.ORCIDUser;
|
||||||
|
import eu.eudat.logic.security.customproviders.Zenodo.ZenodoAccessType;
|
||||||
import eu.eudat.logic.security.customproviders.Zenodo.ZenodoCustomProvider;
|
import eu.eudat.logic.security.customproviders.Zenodo.ZenodoCustomProvider;
|
||||||
import eu.eudat.logic.security.customproviders.Zenodo.ZenodoUser;
|
import eu.eudat.logic.security.customproviders.Zenodo.ZenodoUser;
|
||||||
import eu.eudat.logic.security.validators.TokenValidator;
|
import eu.eudat.logic.security.validators.TokenValidator;
|
||||||
|
@ -43,13 +44,14 @@ public class ZenodoTokenValidator implements TokenValidator {
|
||||||
user.setEmail(zenodoUser.getEmail());
|
user.setEmail(zenodoUser.getEmail());
|
||||||
user.setZenodoId(zenodoUser.getAccessToken());
|
user.setZenodoId(zenodoUser.getAccessToken());
|
||||||
user.setZenodoExpire(zenodoUser.getExpiresIn());
|
user.setZenodoExpire(zenodoUser.getExpiresIn());
|
||||||
|
user.setZenodoRefresh(zenodoUser.getRefreshToken());
|
||||||
user.setProvider(credentials.getProvider());
|
user.setProvider(credentials.getProvider());
|
||||||
user.setSecret(credentials.getTicket());
|
user.setSecret(credentials.getTicket());
|
||||||
return this.nonVerifiedUserAuthenticationService.Touch(user);
|
return this.nonVerifiedUserAuthenticationService.Touch(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ZenodoResponseToken getAccessToken(ZenodoRequest zenodoRequest) {
|
public ZenodoResponseToken getAccessToken(ZenodoRequest zenodoRequest) {
|
||||||
return this.zenodoCustomProvider.getAccessToken(zenodoRequest.getCode()
|
return this.zenodoCustomProvider.getAccessToken(ZenodoAccessType.AUTHORIZATION_CODE, zenodoRequest.getCode()
|
||||||
, this.environment.getProperty("zenodo.login.client_id")
|
, this.environment.getProperty("zenodo.login.client_id")
|
||||||
, this.environment.getProperty("zenodo.login.client_secret")
|
, this.environment.getProperty("zenodo.login.client_secret")
|
||||||
, this.environment.getProperty("zenodo.login.redirect_uri"));
|
, this.environment.getProperty("zenodo.login.redirect_uri"));
|
||||||
|
|
|
@ -5,6 +5,7 @@ public class ZenodoResponseToken {
|
||||||
private String email;
|
private String email;
|
||||||
private Integer expiresIn;
|
private Integer expiresIn;
|
||||||
private String accessToken;
|
private String accessToken;
|
||||||
|
private String refreshToken;
|
||||||
|
|
||||||
public String getUserId() {
|
public String getUserId() {
|
||||||
return userId;
|
return userId;
|
||||||
|
@ -35,4 +36,12 @@ public class ZenodoResponseToken {
|
||||||
public void setAccessToken(String accessToken) {
|
public void setAccessToken(String accessToken) {
|
||||||
this.accessToken = accessToken;
|
this.accessToken = accessToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getRefreshToken() {
|
||||||
|
return refreshToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRefreshToken(String refreshToken) {
|
||||||
|
this.refreshToken = refreshToken;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -133,7 +133,11 @@ public abstract class AbstractAuthenticationService implements AuthenticationSer
|
||||||
userInfo = this.apiContext.getOperationsContext().getBuilderFactory().getBuilder(UserInfoBuilder.class)
|
userInfo = this.apiContext.getOperationsContext().getBuilderFactory().getBuilder(UserInfoBuilder.class)
|
||||||
.name(profile.getName()).verified_email(profile.getIsVerified())
|
.name(profile.getName()).verified_email(profile.getIsVerified())
|
||||||
.email(profile.getEmail()).created(new Date()).lastloggedin(new Date())
|
.email(profile.getEmail()).created(new Date()).lastloggedin(new Date())
|
||||||
.additionalinfo("{\"data\":{\"avatar\":{\"url\":\"" + profile.getAvatarUrl() + "\"}},{\"zenodoToken\":\"" + profile.getZenodoId() + "\", \"expirationDate\": \"" + Instant.now().plusSeconds(profile.getZenodoExpire()).toEpochMilli() + "\"}")
|
.additionalinfo("{\"data\":{\"avatar\":{\"url\":\"" + profile.getAvatarUrl()
|
||||||
|
+ "\"}},{\"zenodoToken\":\"" + profile.getZenodoId()
|
||||||
|
+ "\", \"expirationDate\": \"" + Instant.now().plusSeconds(profile.getZenodoExpire()).toEpochMilli()
|
||||||
|
+ "\", \"zenodoRefresh\": \"" + profile.getZenodoRefresh()
|
||||||
|
+ (profile.getProvider() == TokenValidatorFactoryImpl.LoginProvider.ZENODO ? "\", \"zenodoEmail\": \"" + profile.getEmail() : "") +"\"}")
|
||||||
.authorization_level((short) 1).usertype((short) 1)
|
.authorization_level((short) 1).usertype((short) 1)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
@ -159,6 +163,12 @@ public abstract class AbstractAuthenticationService implements AuthenticationSer
|
||||||
if (profile.getZenodoExpire() != null) {
|
if (profile.getZenodoExpire() != null) {
|
||||||
additionalInfo.put("expirationDate", Instant.now().plusSeconds(profile.getZenodoExpire()).toEpochMilli());
|
additionalInfo.put("expirationDate", Instant.now().plusSeconds(profile.getZenodoExpire()).toEpochMilli());
|
||||||
}
|
}
|
||||||
|
if (profile.getZenodoRefresh() != null) {
|
||||||
|
additionalInfo.put("zenodoRefresh", profile.getZenodoRefresh());
|
||||||
|
}
|
||||||
|
if (profile.getProvider() == TokenValidatorFactoryImpl.LoginProvider.ZENODO) {
|
||||||
|
additionalInfo.put("zenodoEmail", profile.getEmail());
|
||||||
|
}
|
||||||
userInfo.setLastloggedin(new Date());
|
userInfo.setLastloggedin(new Date());
|
||||||
userInfo.setAdditionalinfo(new JSONObject(additionalInfo).toString());
|
userInfo.setAdditionalinfo(new JSONObject(additionalInfo).toString());
|
||||||
Set<Credential> credentials = userInfo.getCredentials();
|
Set<Credential> credentials = userInfo.getCredentials();
|
||||||
|
|
|
@ -46,6 +46,18 @@ public class NonVerifiedUserEmailAuthenticationService extends AbstractAuthentic
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
zenodoDuration = Instant.now();
|
zenodoDuration = Instant.now();
|
||||||
}
|
}
|
||||||
|
String zenodoEmail;
|
||||||
|
try {
|
||||||
|
zenodoEmail = user.getAdditionalinfo() != null ? new ObjectMapper().readTree(user.getAdditionalinfo()).get("zenodoEmail").asText() : "";
|
||||||
|
} catch (Exception e) {
|
||||||
|
zenodoEmail = "";
|
||||||
|
}
|
||||||
|
String zenodoRefresh;
|
||||||
|
try {
|
||||||
|
zenodoRefresh = user.getAdditionalinfo() != null ? new ObjectMapper().readTree(user.getAdditionalinfo()).get("zenodoRefresh").asText() : "";
|
||||||
|
} catch (Exception e) {
|
||||||
|
zenodoRefresh = "";
|
||||||
|
}
|
||||||
String culture;
|
String culture;
|
||||||
try {
|
try {
|
||||||
culture = user.getAdditionalinfo() != null ? new ObjectMapper().readTree(user.getAdditionalinfo()).get("culture").get("name").asText() : "";
|
culture = user.getAdditionalinfo() != null ? new ObjectMapper().readTree(user.getAdditionalinfo()).get("culture").get("name").asText() : "";
|
||||||
|
@ -73,6 +85,8 @@ public class NonVerifiedUserEmailAuthenticationService extends AbstractAuthentic
|
||||||
.timezone(timezone)
|
.timezone(timezone)
|
||||||
.zenodoToken(zenodoToken)
|
.zenodoToken(zenodoToken)
|
||||||
.zenodoDuration(zenodoDuration)
|
.zenodoDuration(zenodoDuration)
|
||||||
|
.zenodoEmail(zenodoEmail)
|
||||||
|
.zenodoRefresh(zenodoRefresh)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
List<UserRole> userRoles = apiContext.getOperationsContext().getDatabaseRepository().getUserRoleDao().getUserRoles(user);
|
List<UserRole> userRoles = apiContext.getOperationsContext().getDatabaseRepository().getUserRoleDao().getUserRoles(user);
|
||||||
|
|
|
@ -55,6 +55,18 @@ public class VerifiedUserAuthenticationService extends AbstractAuthenticationSer
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
zenodoDuration = Instant.now();
|
zenodoDuration = Instant.now();
|
||||||
}
|
}
|
||||||
|
String zenodoEmail;
|
||||||
|
try {
|
||||||
|
zenodoEmail = user.getAdditionalinfo() != null ? new ObjectMapper().readTree(user.getAdditionalinfo()).get("zenodoEmail").asText() : "";
|
||||||
|
} catch (Exception e) {
|
||||||
|
zenodoEmail = "";
|
||||||
|
}
|
||||||
|
String zenodoRefresh;
|
||||||
|
try {
|
||||||
|
zenodoRefresh = user.getAdditionalinfo() != null ? new ObjectMapper().readTree(user.getAdditionalinfo()).get("zenodoRefresh").asText() : "";
|
||||||
|
} catch (Exception e) {
|
||||||
|
zenodoRefresh = "";
|
||||||
|
}
|
||||||
String culture;
|
String culture;
|
||||||
try {
|
try {
|
||||||
culture = user.getAdditionalinfo() != null ? new ObjectMapper().readTree(user.getAdditionalinfo()).get("culture").get("name").asText() : "";
|
culture = user.getAdditionalinfo() != null ? new ObjectMapper().readTree(user.getAdditionalinfo()).get("culture").get("name").asText() : "";
|
||||||
|
@ -82,6 +94,8 @@ public class VerifiedUserAuthenticationService extends AbstractAuthenticationSer
|
||||||
.timezone(timezone)
|
.timezone(timezone)
|
||||||
.zenodoToken(zenodoToken)
|
.zenodoToken(zenodoToken)
|
||||||
.zenodoDuration(zenodoDuration)
|
.zenodoDuration(zenodoDuration)
|
||||||
|
.zenodoEmail(zenodoEmail)
|
||||||
|
.zenodoRefresh(zenodoRefresh)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
List<UserRole> userRoles = apiContext.getOperationsContext().getDatabaseRepository().getUserRoleDao().getUserRoles(user);
|
List<UserRole> userRoles = apiContext.getOperationsContext().getDatabaseRepository().getUserRoleDao().getUserRoles(user);
|
||||||
|
|
|
@ -13,6 +13,7 @@ public class LoginProviderUser {
|
||||||
private TokenValidatorFactoryImpl.LoginProvider provider;
|
private TokenValidatorFactoryImpl.LoginProvider provider;
|
||||||
private String zenodoId;
|
private String zenodoId;
|
||||||
private Integer zenodoExpire;
|
private Integer zenodoExpire;
|
||||||
|
private String zenodoRefresh;
|
||||||
|
|
||||||
public String getId() {
|
public String getId() {
|
||||||
return id;
|
return id;
|
||||||
|
@ -85,4 +86,12 @@ public class LoginProviderUser {
|
||||||
public void setZenodoExpire(Integer zenodoExpire) {
|
public void setZenodoExpire(Integer zenodoExpire) {
|
||||||
this.zenodoExpire = zenodoExpire;
|
this.zenodoExpire = zenodoExpire;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getZenodoRefresh() {
|
||||||
|
return zenodoRefresh;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setZenodoRefresh(String zenodoRefresh) {
|
||||||
|
this.zenodoRefresh = zenodoRefresh;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,8 @@ public class Principal {
|
||||||
private String timezone;
|
private String timezone;
|
||||||
private String zenodoToken;
|
private String zenodoToken;
|
||||||
private Instant zenodoDuration;
|
private Instant zenodoDuration;
|
||||||
|
private String zenodoRefresh;
|
||||||
|
private String zenodoEmail;
|
||||||
|
|
||||||
public UUID getId() {
|
public UUID getId() {
|
||||||
return id;
|
return id;
|
||||||
|
@ -105,6 +107,22 @@ public class Principal {
|
||||||
this.zenodoDuration = zenodoDuration;
|
this.zenodoDuration = zenodoDuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getZenodoRefresh() {
|
||||||
|
return zenodoRefresh;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setZenodoRefresh(String zenodoRefresh) {
|
||||||
|
this.zenodoRefresh = zenodoRefresh;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getZenodoEmail() {
|
||||||
|
return zenodoEmail;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setZenodoEmail(String zenodoEmail) {
|
||||||
|
this.zenodoEmail = zenodoEmail;
|
||||||
|
}
|
||||||
|
|
||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
public Set<Authorities> getAuthz() {
|
public Set<Authorities> getAuthz() {
|
||||||
return this.authorities;
|
return this.authorities;
|
||||||
|
|
|
@ -10,4 +10,5 @@ export interface Principal {
|
||||||
timezone: string;
|
timezone: string;
|
||||||
language: string;
|
language: string;
|
||||||
culture: string;
|
culture: string;
|
||||||
|
zenodoEmail: string;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,5 +3,8 @@ import { AppRole } from "../../common/enum/app-role";
|
||||||
export interface UserListingModel {
|
export interface UserListingModel {
|
||||||
id: String;
|
id: String;
|
||||||
name: String;
|
name: String;
|
||||||
|
email: string;
|
||||||
appRoles: AppRole[];
|
appRoles: AppRole[];
|
||||||
|
additionalinfo: any;
|
||||||
|
associatedDmps: any[];
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,4 +3,5 @@ export class ZenodoToken {
|
||||||
expiresIn: number;
|
expiresIn: number;
|
||||||
accessToken:string;
|
accessToken:string;
|
||||||
email: string;
|
email: string;
|
||||||
|
refreshToken: string;
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,4 +57,9 @@ export class UserService {
|
||||||
const url = this.actionUrl + 'registerDOIToken';
|
const url = this.actionUrl + 'registerDOIToken';
|
||||||
return this.http.post(url, {zenodoRequest: {code: code}, redirectUri: redirectUri}, { headers: this.headers });
|
return this.http.post(url, {zenodoRequest: {code: code}, redirectUri: redirectUri}, { headers: this.headers });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public deleteDOIToken(): Observable<any> {
|
||||||
|
const url = this.actionUrl + 'deleteDOIToken';
|
||||||
|
return this.http.delete(url, { headers: this.headers });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,6 +64,7 @@ export class ZenodoLoginComponent extends BaseComponent implements OnInit {
|
||||||
this.zenodoToken.expiresIn = responseData.payload.expiresIn;
|
this.zenodoToken.expiresIn = responseData.payload.expiresIn;
|
||||||
this.accessToken = this.zenodoToken.accessToken = responseData.payload.accessToken;
|
this.accessToken = this.zenodoToken.accessToken = responseData.payload.accessToken;
|
||||||
this.zenodoToken.email = responseData.payload.email;
|
this.zenodoToken.email = responseData.payload.email;
|
||||||
|
this.zenodoToken.refreshToken = responseData.payload.refreshToken;
|
||||||
this.authService.login({ ticket: this.accessToken, provider: AuthProvider.Zenodo, data: this.zenodoToken })
|
this.authService.login({ ticket: this.accessToken, provider: AuthProvider.Zenodo, data: this.zenodoToken })
|
||||||
.pipe(takeUntil(this._destroyed))
|
.pipe(takeUntil(this._destroyed))
|
||||||
.subscribe(
|
.subscribe(
|
||||||
|
|
|
@ -45,6 +45,7 @@ export class DmpOverviewComponent extends BaseComponent implements OnInit {
|
||||||
breadCrumbs: Observable<BreadcrumbItem[]> = observableOf();
|
breadCrumbs: Observable<BreadcrumbItem[]> = observableOf();
|
||||||
isUserOwner: boolean;
|
isUserOwner: boolean;
|
||||||
expand = false;
|
expand = false;
|
||||||
|
hasDOIToken = false;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private route: ActivatedRoute,
|
private route: ActivatedRoute,
|
||||||
|
@ -149,7 +150,7 @@ export class DmpOverviewComponent extends BaseComponent implements OnInit {
|
||||||
this.expand = !this.expand;
|
this.expand = !this.expand;
|
||||||
}
|
}
|
||||||
|
|
||||||
checkOverflow (element) {
|
checkOverflow(element) {
|
||||||
if (this.expand || (element.offsetHeight < element.scrollHeight ||
|
if (this.expand || (element.offsetHeight < element.scrollHeight ||
|
||||||
element.offsetWidth < element.scrollWidth)) {
|
element.offsetWidth < element.scrollWidth)) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -335,25 +336,28 @@ export class DmpOverviewComponent extends BaseComponent implements OnInit {
|
||||||
const redirectUri = this.configurationService.app + 'oauth2';
|
const redirectUri = this.configurationService.app + 'oauth2';
|
||||||
const url = this.configurationService.loginProviders.zenodoConfiguration.oauthUrl
|
const url = this.configurationService.loginProviders.zenodoConfiguration.oauthUrl
|
||||||
+ '?client_id=' + this.configurationService.loginProviders.zenodoConfiguration.clientId
|
+ '?client_id=' + this.configurationService.loginProviders.zenodoConfiguration.clientId
|
||||||
+ '&response_type=code&scope=deposit:write+deposit:actions&state=astate&redirect_uri='
|
+ '&response_type=code&scope=deposit:write+deposit:actions+user:email&state=astate&redirect_uri='
|
||||||
+ redirectUri;
|
+ redirectUri;
|
||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
|
|
||||||
getDoi(dmp: DmpOverviewModel) {
|
getDoi(dmp: DmpOverviewModel) {
|
||||||
this.userService.hasDOIToken().subscribe(response => {
|
this.userService.hasDOIToken().subscribe(response => {
|
||||||
|
this.hasDOIToken = true;
|
||||||
this.showConfirmationDOIDialog(dmp);
|
this.showConfirmationDOIDialog(dmp);
|
||||||
}, error => {
|
}, error => {
|
||||||
|
this.hasDOIToken = false;
|
||||||
this.showErrorConfirmationDOIDialog(error.error.message, dmp);
|
this.showErrorConfirmationDOIDialog(error.error.message, dmp);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
showConfirmationDOIDialog(dmp: DmpOverviewModel) {
|
showConfirmationDOIDialog(dmp: DmpOverviewModel) {
|
||||||
const dialogRef = this.dialog.open(ConfirmationDialogComponent, {
|
const dialogRef = this.dialog.open(ConfirmationDialogComponent, {
|
||||||
maxWidth: '600px',
|
maxWidth: '600px',
|
||||||
restoreFocus: false,
|
restoreFocus: false,
|
||||||
data: {
|
data: {
|
||||||
message: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ZENODO-DOI'),
|
message: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ZENODO-DOI', { 'username': this.hasDOIToken ? this.authentication.current().zenodoEmail : 'default'}),
|
||||||
confirmButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.CONFIRM'),
|
confirmButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.CONFIRM'),
|
||||||
cancelButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.CANCEL'),
|
cancelButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.CANCEL'),
|
||||||
}
|
}
|
||||||
|
@ -379,7 +383,7 @@ export class DmpOverviewComponent extends BaseComponent implements OnInit {
|
||||||
restoreFocus: false,
|
restoreFocus: false,
|
||||||
data: {
|
data: {
|
||||||
message: message,
|
message: message,
|
||||||
titles: [ this.language.instant('DMP-OVERVIEW.MULTIPLE-DIALOG.ZENODO-LOGIN'), this.language.instant('DMP-OVERVIEW.MULTIPLE-DIALOG.USE-DEFAULT')]
|
titles: [this.language.instant('DMP-OVERVIEW.MULTIPLE-DIALOG.ZENODO-LOGIN'), this.language.instant('DMP-OVERVIEW.MULTIPLE-DIALOG.USE-DEFAULT')]
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => {
|
dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => {
|
||||||
|
@ -403,7 +407,10 @@ export class DmpOverviewComponent extends BaseComponent implements OnInit {
|
||||||
if (!isNullOrUndefined(code)) {
|
if (!isNullOrUndefined(code)) {
|
||||||
this.userService.registerDOIToken(code, this.configurationService.app + 'oauth2')
|
this.userService.registerDOIToken(code, this.configurationService.app + 'oauth2')
|
||||||
.pipe(takeUntil(this._destroyed))
|
.pipe(takeUntil(this._destroyed))
|
||||||
.subscribe(() => this.showConfirmationDOIDialog(dmp));
|
.subscribe(() => {
|
||||||
|
this.hasDOIToken = true;
|
||||||
|
this.showConfirmationDOIDialog(dmp);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,7 +63,7 @@
|
||||||
</div>
|
</div>
|
||||||
</mat-card-title>
|
</mat-card-title>
|
||||||
</mat-card-header>
|
</mat-card-header>
|
||||||
<mat-card-content>
|
<mat-card-content disabled="false">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row" [formGroup]="formGroup">
|
<div class="row" [formGroup]="formGroup">
|
||||||
<mat-form-field class="col-md-4">
|
<mat-form-field class="col-md-4">
|
||||||
|
@ -98,6 +98,29 @@
|
||||||
</div>
|
</div>
|
||||||
</mat-card-content>
|
</mat-card-content>
|
||||||
</mat-card>
|
</mat-card>
|
||||||
|
<mat-card class="col-12 profile-card">
|
||||||
|
<mat-card-header>
|
||||||
|
<mat-card-title>
|
||||||
|
<div class="row">
|
||||||
|
<h4 class="settings col-auto">{{ 'USER-PROFILE.ZENODO.TITLE' | translate}}</h4>
|
||||||
|
</div>
|
||||||
|
</mat-card-title>
|
||||||
|
</mat-card-header>
|
||||||
|
<mat-card-content>
|
||||||
|
<div class="container">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-4" *ngIf="!hasZenodo()">
|
||||||
|
<button mat-raised-button type="button" (click)="loginToZenodo()" class="confirm">{{'USER-PROFILE.ZENODO.LOGIN' | translate}}</button>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4" *ngIf="hasZenodo()">
|
||||||
|
<div><label class="zenodo-email">{{ 'USER-PROFILE.ZENODO.DESCRIPTION' | translate}}</label></div>
|
||||||
|
<label class="zenodo-email">{{zenodoEmail}}</label>
|
||||||
|
<div><button mat-raised-button type="button" (click)="RemoveZenodo()" class="confirm">{{'USER-PROFILE.ZENODO.LOGOUT' | translate}}</button></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</mat-card-content>
|
||||||
|
</mat-card>
|
||||||
</div>
|
</div>
|
||||||
<ng-template #loading>
|
<ng-template #loading>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
|
|
@ -25,3 +25,7 @@
|
||||||
.settings {
|
.settings {
|
||||||
line-height: 2.4em !important;
|
line-height: 2.4em !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.zenodo-email {
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
|
|
@ -13,6 +13,9 @@ import * as moment from 'moment-timezone';
|
||||||
import { Observable, of } from 'rxjs';
|
import { Observable, of } from 'rxjs';
|
||||||
import { map, takeUntil } from 'rxjs/operators';
|
import { map, takeUntil } from 'rxjs/operators';
|
||||||
import { LanguageService } from '@app/core/services/language/language.service';
|
import { LanguageService } from '@app/core/services/language/language.service';
|
||||||
|
import { isNullOrUndefined } from 'util';
|
||||||
|
import { Oauth2DialogService } from '../misc/oauth2-dialog/service/oauth2-dialog.service';
|
||||||
|
import { ConfigurationService } from '@app/core/services/configuration/configuration.service';
|
||||||
|
|
||||||
const availableLanguages: any[] = require('../../../assets/resources/language.json');
|
const availableLanguages: any[] = require('../../../assets/resources/language.json');
|
||||||
|
|
||||||
|
@ -29,6 +32,8 @@ export class UserProfileComponent extends BaseComponent implements OnInit, OnDes
|
||||||
timezones: Observable<any[]>;
|
timezones: Observable<any[]>;
|
||||||
editMode = false;
|
editMode = false;
|
||||||
languages = availableLanguages;
|
languages = availableLanguages;
|
||||||
|
zenodoToken: string;
|
||||||
|
zenodoEmail: string;
|
||||||
|
|
||||||
formGroup: FormGroup;
|
formGroup: FormGroup;
|
||||||
constructor(
|
constructor(
|
||||||
|
@ -39,7 +44,9 @@ export class UserProfileComponent extends BaseComponent implements OnInit, OnDes
|
||||||
private language: TranslateService,
|
private language: TranslateService,
|
||||||
private cultureService: CultureService,
|
private cultureService: CultureService,
|
||||||
private authentication: AuthService,
|
private authentication: AuthService,
|
||||||
private languageService: LanguageService
|
private languageService: LanguageService,
|
||||||
|
private configurationService: ConfigurationService,
|
||||||
|
private oauth2DialogService: Oauth2DialogService
|
||||||
) { super(); }
|
) { super(); }
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
|
@ -50,6 +57,8 @@ export class UserProfileComponent extends BaseComponent implements OnInit, OnDes
|
||||||
const userId = !params['id'] ? 'me' : params['id'];
|
const userId = !params['id'] ? 'me' : params['id'];
|
||||||
this.user = this.userService.getUser(userId).pipe(map(result => {
|
this.user = this.userService.getUser(userId).pipe(map(result => {
|
||||||
result['additionalinfo'] = JSON.parse(result['additionalinfo']);
|
result['additionalinfo'] = JSON.parse(result['additionalinfo']);
|
||||||
|
this.zenodoToken = result['additionalinfo']['zenodoToken'];
|
||||||
|
this.zenodoEmail = result['additionalinfo']['zenodoEmail'];
|
||||||
this.formGroup = new FormBuilder().group({
|
this.formGroup = new FormBuilder().group({
|
||||||
language: new FormControl(result['additionalinfo']['language'] ? availableLanguages.filter(x => x.value === result['additionalinfo']['language']['value']).pop() : '', [Validators.required]),
|
language: new FormControl(result['additionalinfo']['language'] ? availableLanguages.filter(x => x.value === result['additionalinfo']['language']['value']).pop() : '', [Validators.required]),
|
||||||
timezone: new FormControl(result['additionalinfo']['timezone'], [Validators.required]),
|
timezone: new FormControl(result['additionalinfo']['timezone'], [Validators.required]),
|
||||||
|
@ -147,4 +156,39 @@ export class UserProfileComponent extends BaseComponent implements OnInit, OnDes
|
||||||
(ev.target as HTMLImageElement).src = 'assets/images/profile-placeholder.png';
|
(ev.target as HTMLImageElement).src = 'assets/images/profile-placeholder.png';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public hasZenodo(): boolean {
|
||||||
|
return !isNullOrUndefined(this.zenodoToken) && this.zenodoToken !== "";
|
||||||
|
}
|
||||||
|
|
||||||
|
public loginToZenodo() {
|
||||||
|
this.showOauth2Dialog(this.getAccessUrl());
|
||||||
|
}
|
||||||
|
|
||||||
|
getAccessUrl(): string {
|
||||||
|
const redirectUri = this.configurationService.app + 'oauth2';
|
||||||
|
const url = this.configurationService.loginProviders.zenodoConfiguration.oauthUrl
|
||||||
|
+ '?client_id=' + this.configurationService.loginProviders.zenodoConfiguration.clientId
|
||||||
|
+ '&response_type=code&scope=deposit:write+deposit:actions+user:email&state=astate&redirect_uri='
|
||||||
|
+ redirectUri;
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
showOauth2Dialog(url: string) {
|
||||||
|
this.oauth2DialogService.login(url)
|
||||||
|
.pipe(takeUntil(this._destroyed))
|
||||||
|
.subscribe(code => {
|
||||||
|
if (!isNullOrUndefined(code)) {
|
||||||
|
this.userService.registerDOIToken(code, this.configurationService.app + 'oauth2')
|
||||||
|
.pipe(takeUntil(this._destroyed))
|
||||||
|
.subscribe(() => this.router.navigate(['/reload']).then(() => this.router.navigate(['/profile'])));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public RemoveZenodo() {
|
||||||
|
this.userService.deleteDOIToken()
|
||||||
|
.pipe(takeUntil(this._destroyed))
|
||||||
|
.subscribe(() => this.router.navigate(['/reload']).then(() => this.router.navigate(['/profile'])));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,7 +52,7 @@
|
||||||
"FINALIZE-ITEM": "Finalize this item?",
|
"FINALIZE-ITEM": "Finalize this item?",
|
||||||
"PUBLISH-ITEM": "Publish this item?",
|
"PUBLISH-ITEM": "Publish this item?",
|
||||||
"ADD-DATASET": "Do you want to continue by adding a Dataset Description to your DMP? You can always add more Dataset Descriptions using \"Add Dataset Description (Wizard)\" menu.",
|
"ADD-DATASET": "Do you want to continue by adding a Dataset Description to your DMP? You can always add more Dataset Descriptions using \"Add Dataset Description (Wizard)\" menu.",
|
||||||
"ZENODO-DOI": "Would you like to create digital object identifier (DOI) for the DMP?",
|
"ZENODO-DOI": "Would you like to create digital object identifier (DOI) with {{username}} account for the DMP?",
|
||||||
"LEAVE-PAGE": "If you leave, your changes will be lost.",
|
"LEAVE-PAGE": "If you leave, your changes will be lost.",
|
||||||
"LEAVE-WARNING": "You have unsaved changes!",
|
"LEAVE-WARNING": "You have unsaved changes!",
|
||||||
"PRIVACY-POLICY-NAMES": "The names of all people involved into this DMP will be publicly visible. Do you agree with that?",
|
"PRIVACY-POLICY-NAMES": "The names of all people involved into this DMP will be publicly visible. Do you agree with that?",
|
||||||
|
@ -218,7 +218,7 @@
|
||||||
"DATASET-TEMPLATES": "Dataset Description Templates",
|
"DATASET-TEMPLATES": "Dataset Description Templates",
|
||||||
"DMP-TEMPLATES": "DMP Templates",
|
"DMP-TEMPLATES": "DMP Templates",
|
||||||
"USERS": "Users",
|
"USERS": "Users",
|
||||||
"LANGUAGE-EDITOR":"Language Editor",
|
"LANGUAGE-EDITOR": "Language Editor",
|
||||||
"GUIDE-EDITOR": "User Guide Editor"
|
"GUIDE-EDITOR": "User Guide Editor"
|
||||||
},
|
},
|
||||||
"DATASET-PROFILE-EDITOR": {
|
"DATASET-PROFILE-EDITOR": {
|
||||||
|
@ -431,7 +431,7 @@
|
||||||
"TITLE": "Published Data Management Plans",
|
"TITLE": "Published Data Management Plans",
|
||||||
"OWNER": "Owner",
|
"OWNER": "Owner",
|
||||||
"MEMBER": "Member",
|
"MEMBER": "Member",
|
||||||
"CREATOR":"Creator",
|
"CREATOR": "Creator",
|
||||||
"VIEW-ONLY": "View Only",
|
"VIEW-ONLY": "View Only",
|
||||||
"TOOLTIP": {
|
"TOOLTIP": {
|
||||||
"PUBLISHED": "Public access - Closed DMP",
|
"PUBLISHED": "Public access - Closed DMP",
|
||||||
|
@ -1090,6 +1090,12 @@
|
||||||
"SHOW-ALL": "Show All",
|
"SHOW-ALL": "Show All",
|
||||||
"CREATOR": "Creator",
|
"CREATOR": "Creator",
|
||||||
"MEMBER": "Member"
|
"MEMBER": "Member"
|
||||||
|
},
|
||||||
|
"ZENODO": {
|
||||||
|
"LOGIN": "Login to Zenodo",
|
||||||
|
"LOGOUT": "Remove Zenodo",
|
||||||
|
"TITLE": "Zenodo Account",
|
||||||
|
"DESCRIPTION": "Linked Zenodo Account:"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"DATASET-REFERENCED-MODELS": {
|
"DATASET-REFERENCED-MODELS": {
|
||||||
|
|
Loading…
Reference in New Issue