Skip to content

Commit

Permalink
Sync with main
Browse files Browse the repository at this point in the history
  • Loading branch information
amontenegro committed Feb 24, 2025
2 parents 9f5eeb0 + 1f2ce24 commit d41d686
Show file tree
Hide file tree
Showing 150 changed files with 1,023 additions and 6,350 deletions.
6 changes: 6 additions & 0 deletions .tx/config
Original file line number Diff line number Diff line change
Expand Up @@ -180,3 +180,9 @@ file_filter = orcid-core/src/main/resources/i18n/email_add_works_to_record_<lang
source_file = orcid-core/src/main/resources/i18n/email_add_works_to_record_en.properties
source_lang = en
type = UNICODEPROPERTIES

[o:orcid-inc-1:p:registry:r:papi_rate_limit_email]
file_filter = orcid-core/src/main/resources/i18n/papi_rate_limit_email_<lang>.properties
source_file = orcid-core/src/main/resources/i18n/papi_rate_limit_email_en.properties
source_lang = en
type = UNICODEPROPERTIES
106 changes: 106 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,109 @@
## v2.71.22 - 2025-02-20

[Full Changelog](https://github.com/ORCID/ORCID-Source/compare/v2.71.21...v2.71.22)

## v2.71.21 - 2025-02-19

[Full Changelog](https://github.com/ORCID/ORCID-Source/compare/v2.71.20...v2.71.21)

## v2.71.20 - 2025-02-15

[Full Changelog](https://github.com/ORCID/ORCID-Source/compare/v2.71.19...v2.71.20)

## v2.71.19 - 2025-02-14

[Full Changelog](https://github.com/ORCID/ORCID-Source/compare/v2.71.18...v2.71.19)

- [#7222](https://github.com/ORCID/ORCID-Source/pull/7222): Changed Accept type from wild card to octet stream, logging error

## v2.71.18 - 2025-02-14

[Full Changelog](https://github.com/ORCID/ORCID-Source/compare/v2.71.17...v2.71.18)

## v2.71.17 - 2025-02-14

[Full Changelog](https://github.com/ORCID/ORCID-Source/compare/v2.71.16...v2.71.17)

## v2.71.16 - 2025-02-14

[Full Changelog](https://github.com/ORCID/ORCID-Source/compare/v2.71.15...v2.71.16)

## v2.71.15 - 2025-02-13

[Full Changelog](https://github.com/ORCID/ORCID-Source/compare/v2.71.14...v2.71.15)

## v2.71.14 - 2025-02-13

[Full Changelog](https://github.com/ORCID/ORCID-Source/compare/v2.71.13...v2.71.14)

## v2.71.13 - 2025-02-13

[Full Changelog](https://github.com/ORCID/ORCID-Source/compare/v2.71.12...v2.71.13)

## v2.71.12 - 2025-02-13

[Full Changelog](https://github.com/ORCID/ORCID-Source/compare/v2.71.11...v2.71.12)

## v2.71.11 - 2025-02-12

[Full Changelog](https://github.com/ORCID/ORCID-Source/compare/v2.71.10...v2.71.11)

- [#7216](https://github.com/ORCID/ORCID-Source/pull/7216): pull tx

## v2.71.10 - 2025-02-11

[Full Changelog](https://github.com/ORCID/ORCID-Source/compare/v2.71.9...v2.71.10)

- [#7215](https://github.com/ORCID/ORCID-Source/pull/7215): Lmendoza/9623 prod professional personal email detection is case sensitive

## v2.71.9 - 2025-02-10

[Full Changelog](https://github.com/ORCID/ORCID-Source/compare/v2.71.8...v2.71.9)

## v2.71.8 - 2025-02-10

[Full Changelog](https://github.com/ORCID/ORCID-Source/compare/v2.71.7...v2.71.8)

## v2.71.7 - 2025-02-10

[Full Changelog](https://github.com/ORCID/ORCID-Source/compare/v2.71.6...v2.71.7)

## v2.71.6 - 2025-02-06

[Full Changelog](https://github.com/ORCID/ORCID-Source/compare/v2.71.5...v2.71.6)

## v2.71.5 - 2025-02-06

[Full Changelog](https://github.com/ORCID/ORCID-Source/compare/v2.71.4...v2.71.5)

## v2.71.4 - 2025-02-06

[Full Changelog](https://github.com/ORCID/ORCID-Source/compare/v2.71.3...v2.71.4)

- [#7206](https://github.com/ORCID/ORCID-Source/pull/7206): Revert "Revert "Update the cached token info so it indicate if the token is an OBO one""

## v2.71.3 - 2025-02-06

[Full Changelog](https://github.com/ORCID/ORCID-Source/compare/v2.71.2...v2.71.3)

- [#7205](https://github.com/ORCID/ORCID-Source/pull/7205): Revert "Update the cached token info so it indicate if the token is an OBO one"

## v2.71.2 - 2025-02-05

[Full Changelog](https://github.com/ORCID/ORCID-Source/compare/v2.71.1...v2.71.2)

## v2.71.1 - 2025-02-05

[Full Changelog](https://github.com/ORCID/ORCID-Source/compare/v2.71.0...v2.71.1)

## v2.71.0 - 2025-02-05

[Full Changelog](https://github.com/ORCID/ORCID-Source/compare/v2.70.16...v2.71.0)

## v2.70.16 - 2025-02-05

[Full Changelog](https://github.com/ORCID/ORCID-Source/compare/v2.70.15...v2.70.16)

## v2.70.15 - 2025-01-31

[Full Changelog](https://github.com/ORCID/ORCID-Source/compare/v2.70.14...v2.70.15)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,30 +1,43 @@
package org.orcid.api.common.filter;

import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;

import javax.inject.Inject;
import javax.inject.Named;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.ext.Provider;

import org.apache.commons.lang3.StringUtils;
import org.orcid.core.constants.OrcidOauth2Constants;
import org.orcid.core.exception.OboNotValidForApiVersionException;
import org.orcid.core.oauth.OrcidOauth2TokenDetailService;
import org.orcid.core.utils.JsonUtils;
import org.orcid.core.utils.cache.redis.RedisClient;
import org.orcid.persistence.jpa.entities.OrcidOauth2TokenDetail;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationDetails;
import org.springframework.stereotype.Component;


@Component
@Provider
public class OboApiVersionCheckFilter implements ContainerRequestFilter {

@Autowired
private OrcidOauth2TokenDetailService orcidOauth2TokenService;


@Autowired
private RedisClient redisClient;

@Value("${org.orcid.core.utils.cache.redis.enabled:true}")
private boolean isTokenCacheEnabled;

@Override
public void filter(ContainerRequestContext request) {
String version = getApiVersion(request);
Expand All @@ -44,9 +57,19 @@ private boolean isOboRequest() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (OAuth2Authentication.class.isAssignableFrom(authentication.getClass())) {
OAuth2AuthenticationDetails authDetails = (OAuth2AuthenticationDetails) ((OAuth2Authentication) authentication).getDetails();
if (authDetails != null && authDetails.getTokenValue() != null) {
OrcidOauth2TokenDetail tokenDetail = orcidOauth2TokenService.findIgnoringDisabledByTokenValue(authDetails.getTokenValue());
return tokenDetail.getOboClientDetailsId() != null;
if (authDetails != null && authDetails.getTokenValue() != null) {
Map<String, String> cachedAccessToken = getTokenFromCache(authDetails.getTokenValue());
if(cachedAccessToken != null) {
if(cachedAccessToken.containsKey(OrcidOauth2Constants.IS_OBO_TOKEN)) {
return true;
}
} else {
// Fallback to database if it is not in the cache
OrcidOauth2TokenDetail tokenDetail = orcidOauth2TokenService.findIgnoringDisabledByTokenValue(authDetails.getTokenValue());
if(tokenDetail != null) {
return tokenDetail.getOboClientDetailsId() != null;
}
}
}
}
}
Expand All @@ -62,4 +85,14 @@ private String getApiVersion(ContainerRequestContext request) {
return null;
}

private Map<String, String> getTokenFromCache(String accessTokenValue) {
if(isTokenCacheEnabled) {
String tokenJsonInfo = redisClient.get(accessTokenValue);
if(StringUtils.isNotBlank(tokenJsonInfo)) {
return JsonUtils.readObjectFromJsonString(tokenJsonInfo, HashMap.class);
}
}
return null;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import org.orcid.persistence.dao.ProfileLastModifiedDao;
import org.orcid.persistence.jpa.entities.IndexingStatus;
import org.orcid.persistence.jpa.entities.OrcidOauth2AuthoriziationCodeDetail;
import org.orcid.persistence.jpa.entities.OrcidOauth2TokenDetail;
import org.orcid.pojo.ajaxForm.PojoUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -191,6 +192,9 @@ protected void setToCache(String clientId, OAuth2AccessToken accessToken) {
tokenData.put(OrcidOauth2Constants.CLIENT_ID, clientId);
tokenData.put(OrcidOauth2Constants.RESOURCE_IDS, OrcidOauth2Constants.ORCID);
tokenData.put(OrcidOauth2Constants.APPROVED, Boolean.TRUE.toString());
if(accessToken.getAdditionalInformation().containsKey(OrcidOauth2Constants.IS_OBO_TOKEN)) {
tokenData.put(OrcidOauth2Constants.IS_OBO_TOKEN, Boolean.TRUE.toString());
}
redisClient.set(tokenValue, JsonUtils.convertToJsonString(tokenData));
} catch(Exception e) {
LOGGER.info("Unable to set token in Redis cache", e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ public class OrcidOauth2Constants {
public static final String GRANT_TYPE_CLIENT_CREDENTIALS = "client_credentials";
public static final String DATE_CREATED = "date_created";
public static final String CLIENT_ID = "client_id";
public static final String IS_OBO_TOKEN = "is_obo_token";
public static final String ORCID = "orcid";
public static final String NAME = "name";
public static final String CLIENT_ID_PARAM = "client_id";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,6 @@
public interface ProfileEmailDomainManager extends ProfileEmailDomainManagerReadOnly {
void updateEmailDomains(String orcid, org.orcid.pojo.ajaxForm.Emails emails);
void processDomain(String orcid, String email);
void removeAllEmailDomains(String orcid);
void moveEmailDomainToAnotherAccount(String emailDomain, String deprecatedOrcid, String primaryOrcid);
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public void updateEmailDomains(String orcid, org.orcid.pojo.ajaxForm.Emails newE
if (orcid == null || orcid.isBlank()) {
throw new IllegalArgumentException("ORCID must not be empty");
}
List<ProfileEmailDomainEntity> existingEmailDomains = profileEmailDomainDao.findByOrcid(orcid);
List<ProfileEmailDomainEntity> existingEmailDomains = profileEmailDomainDaoReadOnly.findByOrcid(orcid);

if (existingEmailDomains != null) {
// VISIBILITY UPDATE FOR EXISTING DOMAINS
Expand Down Expand Up @@ -98,7 +98,7 @@ public void processDomain(String orcid, String email) {
}
}
if(StringUtils.equalsIgnoreCase(category, EmailDomainEntity.DomainCategory.PROFESSIONAL.name())) {
ProfileEmailDomainEntity existingDomain = profileEmailDomainDao.findByEmailDomain(orcid, domain);
ProfileEmailDomainEntity existingDomain = profileEmailDomainDaoReadOnly.findByEmailDomain(orcid, domain);
// ADD NEW DOMAIN IF ONE DOESN'T EXIST
if (existingDomain == null) {
// Verify the user doesn't have more emails with that domain
Expand All @@ -109,4 +109,19 @@ public void processDomain(String orcid, String email) {
}
}
}

public void removeAllEmailDomains(String orcid) {
if (orcid == null || orcid.isBlank()) {
throw new IllegalArgumentException("ORCID must not be empty");
}
profileEmailDomainDao.removeAllEmailDomains(orcid);
}

@Transactional
public void moveEmailDomainToAnotherAccount(String emailDomain, String deprecatedOrcid, String primaryOrcid) {
ProfileEmailDomainEntity existingEmailDomain = getEmailDomain(primaryOrcid, emailDomain);
if (existingEmailDomain == null) {
profileEmailDomainDao.moveEmailDomainToAnotherAccount(emailDomain, deprecatedOrcid, primaryOrcid);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,7 @@
import org.orcid.persistence.dao.BackupCodeDao;
import org.orcid.persistence.dao.ProfileLastModifiedDao;
import org.orcid.persistence.dao.UserConnectionDao;
import org.orcid.persistence.jpa.entities.ClientDetailsEntity;
import org.orcid.persistence.jpa.entities.IndexingStatus;
import org.orcid.persistence.jpa.entities.OrcidOauth2TokenDetail;
import org.orcid.persistence.jpa.entities.ProfileEntity;
import org.orcid.persistence.jpa.entities.*;
import org.orcid.pojo.ApplicationSummary;
import org.orcid.pojo.ajaxForm.Claim;
import org.orcid.pojo.ajaxForm.PojoUtil;
Expand Down Expand Up @@ -190,7 +187,6 @@ public Boolean doInTransaction(TransactionStatus status) {
// If it was successfully deprecated
if (wasDeprecated) {
LOGGER.info("Account {} was deprecated to primary account: {}", deprecatedOrcid, primaryOrcid);
clearRecord(deprecatedOrcid, false);
// Move all email's to the primary record
Emails deprecatedAccountEmails = emailManager.getEmails(deprecatedOrcid);
if (deprecatedAccountEmails != null) {
Expand All @@ -202,6 +198,14 @@ public Boolean doInTransaction(TransactionStatus status) {
emailManager.moveEmailToOtherAccount(email.getEmail(), deprecatedOrcid, primaryOrcid);
}
}
List<ProfileEmailDomainEntity> deprecatedEmailDomains = profileEmailDomainManager.getEmailDomains(deprecatedOrcid);
if (deprecatedEmailDomains != null && !deprecatedEmailDomains.isEmpty()) {
for (ProfileEmailDomainEntity emailDomain : deprecatedEmailDomains) {
profileEmailDomainManager.moveEmailDomainToAnotherAccount(emailDomain.getEmailDomain(), deprecatedOrcid, primaryOrcid);
}
}
// important to run this after moving domains, as this function will delete the domains from the database
clearRecord(deprecatedOrcid, false);

profileLastModifiedDao.updateLastModifiedDateAndIndexingStatus(deprecatedOrcid, IndexingStatus.REINDEX);
return true;
Expand Down Expand Up @@ -640,6 +644,10 @@ private void clearRecord(String orcid, Boolean disableTokens) {
// remove trusted individuals
givenPermissionToManager.removeAllForProfile(orcid);

// remove email domains
// NOTE: when deprecating, the domains get moved to the other record before this code is executed
profileEmailDomainManager.removeAllEmailDomains(orcid);

// Remove biography
if (biographyManager.exists(orcid)) {
Biography deprecatedBio = new Biography();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,6 @@
*/
public interface ProfileEmailDomainManagerReadOnly {
List<ProfileEmailDomainEntity> getEmailDomains(String orcid);
ProfileEmailDomainEntity getEmailDomain(String orcid, String emailDomain);
List<ProfileEmailDomainEntity> getPublicEmailDomains(String orcid);
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ public List<ProfileEmailDomainEntity> getEmailDomains(String orcid) {
return profileEmailDomainDaoReadOnly.findByOrcid(orcid);
};

public ProfileEmailDomainEntity getEmailDomain(String orcid, String emailDomain) {
return profileEmailDomainDaoReadOnly.findByEmailDomain(orcid, emailDomain);
}

public List<ProfileEmailDomainEntity> getPublicEmailDomains(String orcid) {
return profileEmailDomainDaoReadOnly.findPublicEmailDomains(orcid);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import com.nimbusds.jwt.SignedJWT;

import static org.orcid.core.constants.OrcidOauth2Constants.TOKEN_DISABLED;
import static org.orcid.core.constants.OrcidOauth2Constants.IS_OBO_TOKEN;

public class IETFTokenExchangeResponse implements OAuth2AccessToken {

Expand Down Expand Up @@ -52,6 +53,10 @@ public static IETFTokenExchangeResponse accessToken(OAuth2AccessToken accessTok
if(accessToken.getAdditionalInformation().containsKey(TOKEN_DISABLED)) {
token.additionalInformation.put(TOKEN_DISABLED, "true");
}
if(accessToken.getAdditionalInformation().containsKey(IS_OBO_TOKEN)) {
token.additionalInformation.put(IS_OBO_TOKEN, "true");
}

return token;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,9 @@ public void storeAccessToken(OAuth2AccessToken token, OAuth2Authentication authe
orcidOauthTokenDetailService.createNew(detail);
// Set the token id in the additional details
token.getAdditionalInformation().put(OrcidOauth2Constants.TOKEN_ID, detail.getId());
if(detail.getOboClientDetailsId() != null) {
token.getAdditionalInformation().put(OrcidOauth2Constants.IS_OBO_TOKEN, "true");
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ public List<OrgDisambiguatedSolrDocument> getOrgs(String searchTerm, int firstRe

// Set the preserveMulti parameter
query.setParam("preserveMulti", "true");
query.setParam("lowercaseOperators", "true");

if(fundersOnly) {
query.addFilterQuery(String.format("(%s:(%s OR %s))", SolrConstants.ORG_DISAMBIGUATED_ID_SOURCE_TYPE, "ROR", "FUNDREF"));
Expand Down
Loading

0 comments on commit d41d686

Please sign in to comment.