From 2b2f03a2e0ff32276b26862ebd3f830ececc276b Mon Sep 17 00:00:00 2001 From: Angel Montenegro Date: Thu, 4 Apr 2024 13:53:01 -0600 Subject: [PATCH 1/2] Improve validated activities count (#7014) * Deactivated records should get 409 on GET requests * When looking into a group, if any element inside the group is validated count the group as validated * Working on unit tests * Working on unit tests * Working on unit tests * Still working on moving functionality to the orcid-core package * Still working on moving functionality to the orcid-core package * Still working on moving functionality to the orcid-core package * Still working on unit tests * Happy path unit tests done * Fixing unit tests * Adding more unit tests * ImproveValidatedActivitiesCount * New endpoint in mapi --- .../server/MemberV3ApiServiceImplV3_0.java | 8 + .../MemberV3ApiServiceDelegator.java | 1 + .../impl/MemberV3ApiServiceDelegatorImpl.java | 15 +- .../org/orcid/core/api/OrcidApiConstants.java | 2 + .../core/common/manager/SummaryManager.java | 7 + .../manager/impl/SummaryManagerImpl.java | 277 +++++++ .../v3/impl/ProfileEntityManagerImpl.java | 41 +- .../v3/read_only/WorkManagerReadOnly.java | 1 - .../impl/WorkManagerReadOnlyImpl.java | 23 +- .../java/org/orcid/core/utils/DateUtils.java | 1 + .../org/orcid/core/utils/RecordNameUtils.java | 2 +- .../utils/comparators/DateComparator.java | 34 + .../DateComparatorWorkGroupExtended.java | 31 + .../utils/comparators/TitleComparator.java | 79 ++ .../TitleComparatorWorkGroupExtended.java | 79 ++ .../utils/comparators/TypeComparator.java | 24 + .../TypeComparatorWorkGroupExtended.java | 24 + .../org/orcid/pojo/grouping/WorkGroup.java | 20 +- .../pojo/summary/AffiliationSummary.java | 32 + .../summary/ExternalIdentifiersSummary.java | 8 +- .../src/main/resources/orcid-core-context.xml | 2 + .../manager/EmailDomainManagerTest.java | 1 + .../common/manager/SummaryManagerTest.java | 688 ++++++++++++++++++ .../data/OrgAffiliationEntityData.xml | 2 + .../main/java/org/orcid/utils/DateUtils.java | 11 +- .../controllers/PublicProfileController.java | 30 +- .../controllers/PublicRecordController.java | 300 +------- .../orcid/frontend/web/pagination/Page.java | 8 + .../web/pagination/WorksPaginator.java | 412 ++--------- ... => PublicRecordControllerLegacyTest.java} | 3 +- .../web/pagination/WorksPaginatorTest.java | 46 +- 31 files changed, 1474 insertions(+), 738 deletions(-) create mode 100644 orcid-core/src/main/java/org/orcid/core/common/manager/SummaryManager.java create mode 100644 orcid-core/src/main/java/org/orcid/core/common/manager/impl/SummaryManagerImpl.java create mode 100644 orcid-core/src/main/java/org/orcid/core/utils/comparators/DateComparator.java create mode 100644 orcid-core/src/main/java/org/orcid/core/utils/comparators/DateComparatorWorkGroupExtended.java create mode 100644 orcid-core/src/main/java/org/orcid/core/utils/comparators/TitleComparator.java create mode 100644 orcid-core/src/main/java/org/orcid/core/utils/comparators/TitleComparatorWorkGroupExtended.java create mode 100644 orcid-core/src/main/java/org/orcid/core/utils/comparators/TypeComparator.java create mode 100644 orcid-core/src/main/java/org/orcid/core/utils/comparators/TypeComparatorWorkGroupExtended.java create mode 100644 orcid-core/src/test/java/org/orcid/core/common/manager/SummaryManagerTest.java rename orcid-web/src/test/java/org/orcid/frontend/web/controllers/{PublicRecordControllerTest.java => PublicRecordControllerLegacyTest.java} (99%) diff --git a/orcid-api-web/src/main/java/org/orcid/api/memberV3/server/MemberV3ApiServiceImplV3_0.java b/orcid-api-web/src/main/java/org/orcid/api/memberV3/server/MemberV3ApiServiceImplV3_0.java index 7f0058de4e7..69b1958e314 100644 --- a/orcid-api-web/src/main/java/org/orcid/api/memberV3/server/MemberV3ApiServiceImplV3_0.java +++ b/orcid-api-web/src/main/java/org/orcid/api/memberV3/server/MemberV3ApiServiceImplV3_0.java @@ -60,6 +60,7 @@ import static org.orcid.core.api.OrcidApiConstants.WORK; import static org.orcid.core.api.OrcidApiConstants.WORKS; import static org.orcid.core.api.OrcidApiConstants.WORK_SUMMARY; +import static org.orcid.core.api.OrcidApiConstants.RECORD_SUMMARY; import java.util.HashMap; import java.util.List; @@ -1043,4 +1044,11 @@ public Response updateResearchResource(@PathParam("orcid") String orcid, @PathPa public Response deleteResearchResource(@PathParam("orcid") String orcid, @PathParam("putCode") String putCode) { return serviceDelegator.deleteResearchResource(orcid, getPutCode(putCode)); } + + @GET + @Produces(value = { VND_ORCID_XML, ORCID_XML, MediaType.APPLICATION_XML, VND_ORCID_JSON, ORCID_JSON, MediaType.APPLICATION_JSON }) + @Path(RECORD_SUMMARY) + public Response getRecordSummary(@PathParam("orcid") String orcid) { + return serviceDelegator.getRecordSummary(orcid); + } } \ No newline at end of file diff --git a/orcid-api-web/src/main/java/org/orcid/api/memberV3/server/delegator/MemberV3ApiServiceDelegator.java b/orcid-api-web/src/main/java/org/orcid/api/memberV3/server/delegator/MemberV3ApiServiceDelegator.java index a737daddc44..779a60c4cd2 100644 --- a/orcid-api-web/src/main/java/org/orcid/api/memberV3/server/delegator/MemberV3ApiServiceDelegator.java +++ b/orcid-api-web/src/main/java/org/orcid/api/memberV3/server/delegator/MemberV3ApiServiceDelegator.java @@ -221,4 +221,5 @@ public interface MemberV3ApiServiceDelegator> solrParams); + Response getRecordSummary(String orcid); } diff --git a/orcid-api-web/src/main/java/org/orcid/api/memberV3/server/delegator/impl/MemberV3ApiServiceDelegatorImpl.java b/orcid-api-web/src/main/java/org/orcid/api/memberV3/server/delegator/impl/MemberV3ApiServiceDelegatorImpl.java index a3fb41eb9a5..3c6551e86c4 100644 --- a/orcid-api-web/src/main/java/org/orcid/api/memberV3/server/delegator/impl/MemberV3ApiServiceDelegatorImpl.java +++ b/orcid-api-web/src/main/java/org/orcid/api/memberV3/server/delegator/impl/MemberV3ApiServiceDelegatorImpl.java @@ -1,7 +1,5 @@ package org.orcid.api.memberV3.server.delegator.impl; -import static org.orcid.core.api.OrcidApiConstants.STATUS_OK_MESSAGE; - import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -18,6 +16,7 @@ import org.orcid.api.common.util.v3.ActivityUtils; import org.orcid.api.common.util.v3.ElementUtils; import org.orcid.api.memberV3.server.delegator.MemberV3ApiServiceDelegator; +import org.orcid.core.common.manager.SummaryManager; import org.orcid.core.exception.DeactivatedException; import org.orcid.core.exception.DuplicatedGroupIdRecordException; import org.orcid.core.exception.MismatchedPutCodeException; @@ -128,6 +127,7 @@ import org.orcid.jaxb.model.v3.release.record.summary.Works; import org.orcid.jaxb.model.v3.release.search.Search; import org.orcid.jaxb.model.v3.release.search.expanded.ExpandedSearch; +import org.orcid.pojo.summary.RecordSummary; import org.springframework.context.MessageSource; import org.springframework.stereotype.Component; @@ -269,6 +269,9 @@ public class MemberV3ApiServiceDelegatorImpl implements @Resource private OrcidUrlManager orcidUrlManager; + @Resource + private SummaryManager summaryManager; + public Boolean getFilterVersionOfIdentifiers() { return filterVersionOfIdentifiers; } @@ -1654,4 +1657,12 @@ private Map addParmsMismatchedPutCode(Long urlPutCode, Long body return params; } + @Override + public Response getRecordSummary(String orcid) { + orcidSecurityManager.checkClientAccessAndScopes(orcid, ScopePathType.READ_PUBLIC); + checkProfileStatus(orcid, false); + RecordSummary summary = summaryManager.getRecordSummary(orcid); + return Response.ok(summary).build(); + } + } diff --git a/orcid-core/src/main/java/org/orcid/core/api/OrcidApiConstants.java b/orcid-core/src/main/java/org/orcid/core/api/OrcidApiConstants.java index 0d3c6c64c53..f57155e1593 100644 --- a/orcid-core/src/main/java/org/orcid/core/api/OrcidApiConstants.java +++ b/orcid-core/src/main/java/org/orcid/core/api/OrcidApiConstants.java @@ -117,5 +117,7 @@ public class OrcidApiConstants { public static final String ADDRESS = "/{orcid}/address"; public static final String PERSON = "/{orcid}/person"; + public static final String RECORD_SUMMARY = "/{orcid}/summary"; + public static final int MAX_NOTIFICATIONS_AVAILABLE = 1000; } diff --git a/orcid-core/src/main/java/org/orcid/core/common/manager/SummaryManager.java b/orcid-core/src/main/java/org/orcid/core/common/manager/SummaryManager.java new file mode 100644 index 00000000000..cca83995609 --- /dev/null +++ b/orcid-core/src/main/java/org/orcid/core/common/manager/SummaryManager.java @@ -0,0 +1,7 @@ +package org.orcid.core.common.manager; + +import org.orcid.pojo.summary.RecordSummary; + +public interface SummaryManager { + RecordSummary getRecordSummary(String orcid); +} diff --git a/orcid-core/src/main/java/org/orcid/core/common/manager/impl/SummaryManagerImpl.java b/orcid-core/src/main/java/org/orcid/core/common/manager/impl/SummaryManagerImpl.java new file mode 100644 index 00000000000..86d4e47bf45 --- /dev/null +++ b/orcid-core/src/main/java/org/orcid/core/common/manager/impl/SummaryManagerImpl.java @@ -0,0 +1,277 @@ +package org.orcid.core.common.manager.impl; + +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import javax.annotation.Resource; + +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.Pair; +import org.orcid.core.common.manager.SummaryManager; +import org.orcid.core.manager.ProfileEntityCacheManager; +import org.orcid.core.manager.v3.WorksCacheManager; +import org.orcid.core.manager.v3.read_only.AffiliationsManagerReadOnly; +import org.orcid.core.manager.v3.read_only.ExternalIdentifierManagerReadOnly; +import org.orcid.core.manager.v3.read_only.PeerReviewManagerReadOnly; +import org.orcid.core.manager.v3.read_only.ProfileFundingManagerReadOnly; +import org.orcid.core.manager.v3.read_only.RecordManagerReadOnly; +import org.orcid.core.manager.v3.read_only.RecordNameManagerReadOnly; +import org.orcid.core.manager.v3.read_only.WorkManagerReadOnly; +import org.orcid.jaxb.model.v3.release.common.FuzzyDate; +import org.orcid.jaxb.model.v3.release.common.Source; +import org.orcid.jaxb.model.v3.release.common.Visibility; +import org.orcid.jaxb.model.v3.release.record.AffiliationType; +import org.orcid.jaxb.model.v3.release.record.Group; +import org.orcid.jaxb.model.v3.release.record.GroupableActivity; +import org.orcid.jaxb.model.v3.release.record.GroupsContainer; +import org.orcid.jaxb.model.v3.release.record.PersonExternalIdentifiers; +import org.orcid.jaxb.model.v3.release.record.SourceAware; +import org.orcid.jaxb.model.v3.release.record.summary.AffiliationGroup; +import org.orcid.jaxb.model.v3.release.record.summary.AffiliationSummary; +import org.orcid.jaxb.model.v3.release.record.summary.DistinctionSummary; +import org.orcid.jaxb.model.v3.release.record.summary.Fundings; +import org.orcid.jaxb.model.v3.release.record.summary.WorkGroup; +import org.orcid.jaxb.model.v3.release.record.summary.WorkSummary; +import org.orcid.jaxb.model.v3.release.record.summary.Works; +import org.orcid.persistence.jpa.entities.ProfileEntity; +import org.orcid.pojo.PeerReviewMinimizedSummary; +import org.orcid.pojo.summary.ExternalIdentifiersSummary; +import org.orcid.pojo.summary.RecordSummary; +import org.orcid.utils.DateUtils; + +public class SummaryManagerImpl implements SummaryManager { + + @Resource(name = "recordNameManagerReadOnlyV3") + private RecordNameManagerReadOnly recordNameManagerReadOnly; + + @Resource(name = "affiliationsManagerReadOnlyV3") + private AffiliationsManagerReadOnly affiliationsManagerReadOnly; + + @Resource(name = "externalIdentifierManagerReadOnlyV3") + private ExternalIdentifierManagerReadOnly externalIdentifierManagerReadOnly; + + @Resource(name = "workManagerReadOnlyV3") + private WorkManagerReadOnly workManagerReadOnly; + + @Resource(name = "profileFundingManagerReadOnlyV3") + private ProfileFundingManagerReadOnly profileFundingManagerReadOnly; + + @Resource(name = "peerReviewManagerReadOnlyV3") + private PeerReviewManagerReadOnly peerReviewManagerReadOnly; + + @Resource(name = "recordManagerReadOnlyV3") + private RecordManagerReadOnly recordManagerReadOnly; + + @Resource + private ProfileEntityCacheManager profileEntityCacheManager; + + @Resource + private WorksCacheManager worksCacheManager; + + @Override + public RecordSummary getRecordSummary(String orcid) { + RecordSummary recordSummary = new RecordSummary(); + + // Set ORCID uri + recordSummary.setOrcid(recordManagerReadOnly.getOrcidIdentifier(orcid).getUri()); + + // Set dates + ProfileEntity profileEntity = profileEntityCacheManager.retrieve(orcid); + recordSummary.setLastModified(DateUtils.formatDateISO8601(profileEntity.getLastModified())); + recordSummary.setCreation(DateUtils.formatDateISO8601(profileEntity.getDateCreated())); + + recordSummary.setName(recordNameManagerReadOnly.fetchDisplayablePublicName(orcid)); + + // Generate the affiliations summary + generateAffiliationsSummary(recordSummary, orcid); + + // Generate the external identifiers summary + generateExternalIdentifiersSummary(recordSummary, orcid); + + // Generate the works summary + generateWorksSummary(recordSummary, orcid); + + // Generate the funding summary + generateFundingSummary(recordSummary, orcid); + + // Generate the peer review summary + generatePeerReviewSummary(recordSummary, orcid); + recordSummary.setStatus("active"); + return recordSummary; + } + + public void generateWorksSummary(RecordSummary recordSummary, String orcid) { + Works works = worksCacheManager.getGroupedWorks(orcid); + // TODO Remove non public elements + // TODO There should be a manager that does this, but, the one we have already returns a list of work summaries, so, we need to refactor it to return the same Works element + Iterator workGroupIt = works.getWorkGroup().iterator(); + while (workGroupIt.hasNext()) { + WorkGroup workGroup = workGroupIt.next(); + Iterator summariesIt = workGroup.getWorkSummary().iterator(); + while(summariesIt.hasNext()) { + WorkSummary w = summariesIt.next(); + if(!Visibility.PUBLIC.equals(w.getVisibility())) { + summariesIt.remove(); + } + } + if(workGroup.getActivities() == null || workGroup.getActivities().isEmpty()) { + workGroupIt.remove(); + } + } + Pair validAndSelfAssertedStats = calculateSelfAssertedAndValidated(works, orcid); + + recordSummary.setValidatedWorks(validAndSelfAssertedStats.getLeft()); + recordSummary.setSelfAssertedWorks(validAndSelfAssertedStats.getRight()); + } + + public void generateFundingSummary(RecordSummary recordSummary, String orcid) { + Fundings fundingGroups = profileFundingManagerReadOnly.groupFundings(profileFundingManagerReadOnly.getFundingSummaryList(orcid), true); + Pair validAndSelfAssertedStats = calculateSelfAssertedAndValidated(fundingGroups, orcid); + + recordSummary.setValidatedFunds(validAndSelfAssertedStats.getLeft()); + recordSummary.setSelfAssertedFunds(validAndSelfAssertedStats.getRight()); + } + + public void generatePeerReviewSummary(RecordSummary recordSummary, String orcid) { + List peerReviewMinimizedSummaryList = peerReviewManagerReadOnly.getPeerReviewMinimizedSummaryList(orcid, true); + + Integer totalReviewsCount = 0; + Integer selfAssertedPeerReviews = 0; + + if (peerReviewMinimizedSummaryList != null) { + for (PeerReviewMinimizedSummary pr : peerReviewMinimizedSummaryList) { + totalReviewsCount += (pr.getPutCodes() == null) ? 0 : pr.getPutCodes().size(); + if (orcid.equals(pr.getSourceId()) || orcid.equals(pr.getAssertionOriginSourceId())) { + selfAssertedPeerReviews++; + } + } + } + + recordSummary.setSelfAssertedPeerReviews(selfAssertedPeerReviews); + recordSummary.setPeerReviewsTotal(totalReviewsCount); + recordSummary.setPeerReviewPublicationGrants(peerReviewMinimizedSummaryList.size()); + } + + private Pair calculateSelfAssertedAndValidated(GroupsContainer c, String orcid) { + Integer validated = 0; + Integer selfAsserted = 0; + for (Group g : c.retrieveGroups()) { + boolean validatedFound = false; + for (GroupableActivity ga : g.getActivities()) { + if (ga instanceof SourceAware) { + SourceAware activity = (SourceAware) ga; + Source source = activity.getSource(); + if (!orcid.equals(source.retrieveSourcePath()) && !orcid.equals(source.retrieveAssertionOriginPath())) { + validatedFound = true; + break; + } + } + } + if (validatedFound) { + validated++; + } else { + selfAsserted++; + } + } + return Pair.of(validated, selfAsserted); + } + + public void generateExternalIdentifiersSummary(RecordSummary recordSummary, String orcid) { + PersonExternalIdentifiers personExternalIdentifiers = externalIdentifierManagerReadOnly.getPublicExternalIdentifiers(orcid); + recordSummary.setExternalIdentifiers(ExternalIdentifiersSummary.valueOf(personExternalIdentifiers, orcid)); + } + + public void generateAffiliationsSummary(RecordSummary recordSummary, String orcid) { + Map>> affiliationsMap = affiliationsManagerReadOnly.getGroupedAffiliations(orcid, + true); + + // EMPLOYMENT + List> employmentGroups = affiliationsMap.get(AffiliationType.EMPLOYMENT); + List preferredEmployments = new ArrayList<>(); + if (employmentGroups != null) { + for (AffiliationGroup group : employmentGroups) { + preferredEmployments.add(getDefaultAffiliationFromGroup(group)); + } + } + // Sort them by end date by default + sortAffiliationsByEndDate(preferredEmployments); + + List employmentsTop3 = new ArrayList<>(); + preferredEmployments.stream().limit(3).forEach(t -> { + employmentsTop3.add(org.orcid.pojo.summary.AffiliationSummary.valueof(t, orcid, AffiliationType.EMPLOYMENT.value())); + }); + recordSummary.setEmploymentAffiliations(employmentsTop3); + recordSummary.setEmploymentAffiliationsCount(preferredEmployments.size()); + + // PROFESIONAL ACTIVITIES + List> profesionalActivitesGroups = new ArrayList<>(); + if (affiliationsMap.containsKey(AffiliationType.DISTINCTION)) { + profesionalActivitesGroups.addAll(affiliationsMap.get(AffiliationType.DISTINCTION)); + } + if (affiliationsMap.containsKey(AffiliationType.INVITED_POSITION)) { + profesionalActivitesGroups.addAll(affiliationsMap.get(AffiliationType.INVITED_POSITION)); + } + if (affiliationsMap.containsKey(AffiliationType.MEMBERSHIP)) { + profesionalActivitesGroups.addAll(affiliationsMap.get(AffiliationType.MEMBERSHIP)); + } + if (affiliationsMap.containsKey(AffiliationType.SERVICE)) { + profesionalActivitesGroups.addAll(affiliationsMap.get(AffiliationType.SERVICE)); + } + List preferredProfesionalActivities = new ArrayList<>(); + for (AffiliationGroup group : profesionalActivitesGroups) { + preferredProfesionalActivities.add(getDefaultAffiliationFromGroup(group)); + } + // Sort them by end date by default + sortAffiliationsByEndDate(preferredProfesionalActivities); + + List professionalActivitiesTop3 = new ArrayList<>(); + preferredProfesionalActivities.stream().limit(3).forEach(t -> { + professionalActivitiesTop3.add(org.orcid.pojo.summary.AffiliationSummary.valueof(t, orcid, AffiliationType.EMPLOYMENT.value())); + }); + recordSummary.setProfessionalActivities(professionalActivitiesTop3); + recordSummary.setProfessionalActivitiesCount(preferredProfesionalActivities.size()); + } + + private AffiliationSummary getDefaultAffiliationFromGroup(AffiliationGroup group) { + AffiliationSummary defaultAffiliation = null; + Long maxDisplayIndex = null; + for (AffiliationSummary as : group.getActivities()) { + if (maxDisplayIndex == null || (as.getDisplayIndex() != null && Long.valueOf(as.getDisplayIndex()) > maxDisplayIndex)) { + maxDisplayIndex = Long.valueOf(as.getDisplayIndex()); + defaultAffiliation = as; + } + } + return defaultAffiliation; + } + + private void sortAffiliationsByEndDate(List affiliations) { + List summariesWithOutEndDate = new ArrayList<>(); + LocalDate today = LocalDate.now(); + affiliations.forEach(aff -> { + // TODO: Why do we need to overwrite the end date when it is a + // Distinction? + if ((aff instanceof DistinctionSummary) && aff.getStartDate() != null && aff.getStartDate().getYear() != null) { + aff.setEndDate(aff.getStartDate()); + } + // To any affiliation with no end date, set the end day to today + if (aff.getEndDate() == null || aff.getEndDate().getYear() == null || StringUtils.isEmpty(aff.getEndDate().getYear().getValue())) { + FuzzyDate fd = FuzzyDate.valueOf(today.getYear(), today.getMonthValue(), today.getDayOfMonth()); + aff.setEndDate(fd); + // Store the id so we can roll this back + summariesWithOutEndDate.add(aff); + } + }); + + // TODO: Can we just sort this in reverse in one step? + affiliations.sort(Comparator.comparing(a -> a.getEndDate())); + Collections.reverse(affiliations); + + // Remove the end on the affiliations + summariesWithOutEndDate.forEach(s -> s.setEndDate(null)); + } +} diff --git a/orcid-core/src/main/java/org/orcid/core/manager/v3/impl/ProfileEntityManagerImpl.java b/orcid-core/src/main/java/org/orcid/core/manager/v3/impl/ProfileEntityManagerImpl.java index 1e6b2bc4391..073d129b9ec 100644 --- a/orcid-core/src/main/java/org/orcid/core/manager/v3/impl/ProfileEntityManagerImpl.java +++ b/orcid-core/src/main/java/org/orcid/core/manager/v3/impl/ProfileEntityManagerImpl.java @@ -1,5 +1,16 @@ package org.orcid.core.manager.v3.impl; +import java.security.InvalidParameterException; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.annotation.Resource; + import org.apache.commons.lang.StringUtils; import org.orcid.core.common.manager.EmailFrequencyManager; import org.orcid.core.constants.RevokeReason; @@ -31,7 +42,6 @@ import org.orcid.core.profile.history.ProfileHistoryEventType; import org.orcid.jaxb.model.clientgroup.MemberType; import org.orcid.jaxb.model.common.AvailableLocales; -import org.orcid.jaxb.model.common.OrcidType; import org.orcid.jaxb.model.message.ScopePathType; import org.orcid.jaxb.model.v3.release.common.CreditName; import org.orcid.jaxb.model.v3.release.common.Visibility; @@ -72,16 +82,6 @@ import org.springframework.transaction.support.TransactionCallback; import org.springframework.transaction.support.TransactionTemplate; -import javax.annotation.Resource; -import java.security.InvalidParameterException; -import java.security.NoSuchAlgorithmException; -import java.util.ArrayList; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; - /** * @author Declan Newman (declan) Date: 10/02/2012 */ @@ -360,24 +360,7 @@ private void addApplicationToMap(OrcidOauth2TokenDetail token, Map { + @Override + public int compare(WorkGroup o1, WorkGroup o2) { + PublicationDate date1 = o1.getWorkSummary().get(0).getPublicationDate(); + PublicationDate date2 = o2.getWorkSummary().get(0).getPublicationDate(); + if (date1 == null && date2 == null) { + return new TitleComparator().compare(o1, o2) * -1; // reverse + // secondary + // order + } + + if (date1 == null) { + return -1; + } + + if (date2 == null) { + return 1; + } + if (date1.compareTo(date2) == 0) { + return new TitleComparator().compare(o1, o2) * -1; // reverse + // secondary + // order + } + + return o1.getWorkSummary().get(0).getPublicationDate().compareTo(o2.getWorkSummary().get(0).getPublicationDate()); + } +} diff --git a/orcid-core/src/main/java/org/orcid/core/utils/comparators/DateComparatorWorkGroupExtended.java b/orcid-core/src/main/java/org/orcid/core/utils/comparators/DateComparatorWorkGroupExtended.java new file mode 100644 index 00000000000..56e78aeba5d --- /dev/null +++ b/orcid-core/src/main/java/org/orcid/core/utils/comparators/DateComparatorWorkGroupExtended.java @@ -0,0 +1,31 @@ +package org.orcid.core.utils.comparators; + +import java.util.Comparator; + +import org.orcid.jaxb.model.v3.release.common.PublicationDate; +import org.orcid.pojo.WorkGroupExtended; + +public class DateComparatorWorkGroupExtended implements Comparator { + @Override + public int compare(WorkGroupExtended o1, WorkGroupExtended o2) { + PublicationDate date1 = o1.getWorkSummary().get(0).getPublicationDate(); + PublicationDate date2 = o2.getWorkSummary().get(0).getPublicationDate(); + if (date1 == null && date2 == null) { + return new TitleComparatorWorkGroupExtended().compare(o1, o2) * -1; // reverse secondary order + } + + if (date1 == null) { + return -1; + } + + if (date2 == null) { + return 1; + } + + if (date1.compareTo(date2) == 0) { + return new TitleComparatorWorkGroupExtended().compare(o1, o2) * -1; // reverse secondary order + } + + return o1.getWorkSummary().get(0).getPublicationDate().compareTo(o2.getWorkSummary().get(0).getPublicationDate()); + } +} diff --git a/orcid-core/src/main/java/org/orcid/core/utils/comparators/TitleComparator.java b/orcid-core/src/main/java/org/orcid/core/utils/comparators/TitleComparator.java new file mode 100644 index 00000000000..843abf3c4ea --- /dev/null +++ b/orcid-core/src/main/java/org/orcid/core/utils/comparators/TitleComparator.java @@ -0,0 +1,79 @@ +package org.orcid.core.utils.comparators; + +import java.util.Comparator; + +import org.orcid.jaxb.model.v3.release.record.summary.WorkGroup; +import org.orcid.jaxb.model.v3.release.record.summary.WorkSummary; + +public class TitleComparator implements Comparator { + @Override + public int compare(WorkGroup o1, WorkGroup o2) { + String firstTitle = getTitle(o1.getWorkSummary().get(0)); + String secondTitle = getTitle(o2.getWorkSummary().get(0)); + + if (firstTitle == null && secondTitle != null) { + return -1; + } + + if (secondTitle == null && firstTitle != null) { + return 1; + } + + int comparison = 0; + if (firstTitle != null && secondTitle != null) { + comparison = firstTitle.compareTo(secondTitle); + } + + if (comparison == 0) { + String firstSubtitle = getSubtitle(o1.getWorkSummary().get(0)); + String secondSubtitle = getSubtitle(o2.getWorkSummary().get(0)); + + if (firstSubtitle == null && secondSubtitle == null) { + return 0; + } + + if (firstSubtitle == null) { + return -1; + } + + if (secondSubtitle == null) { + return 1; + } + + comparison = firstSubtitle.compareTo(secondSubtitle); + } + return comparison; + } + + private String getTitle(WorkSummary workSummary) { + if (workSummary.getTitle() == null) { + return null; + } + + if (workSummary.getTitle().getTitle() == null) { + return null; + } + + if (workSummary.getTitle().getTitle().getContent() == null) { + return null; + } + + return workSummary.getTitle().getTitle().getContent().toLowerCase(); + } + + private String getSubtitle(WorkSummary workSummary) { + if (workSummary.getTitle() == null) { + return null; + } + + if (workSummary.getTitle().getSubtitle() == null) { + return null; + } + + if (workSummary.getTitle().getSubtitle().getContent() == null) { + return null; + } + + return workSummary.getTitle().getSubtitle().getContent().toLowerCase(); + } +} diff --git a/orcid-core/src/main/java/org/orcid/core/utils/comparators/TitleComparatorWorkGroupExtended.java b/orcid-core/src/main/java/org/orcid/core/utils/comparators/TitleComparatorWorkGroupExtended.java new file mode 100644 index 00000000000..3c1011849ce --- /dev/null +++ b/orcid-core/src/main/java/org/orcid/core/utils/comparators/TitleComparatorWorkGroupExtended.java @@ -0,0 +1,79 @@ +package org.orcid.core.utils.comparators; + +import java.util.Comparator; + +import org.orcid.pojo.WorkGroupExtended; +import org.orcid.pojo.WorkSummaryExtended; + +public class TitleComparatorWorkGroupExtended implements Comparator { + @Override + public int compare(WorkGroupExtended o1, WorkGroupExtended o2) { + String firstTitle = getTitle(o1.getWorkSummary().get(0)); + String secondTitle = getTitle(o2.getWorkSummary().get(0)); + + if (firstTitle == null && secondTitle != null) { + return -1; + } + + if (secondTitle == null && firstTitle != null) { + return 1; + } + + int comparison = 0; + if (firstTitle != null && secondTitle != null) { + comparison = firstTitle.compareTo(secondTitle); + } + + if (comparison == 0) { + String firstSubtitle = getSubtitle(o1.getWorkSummary().get(0)); + String secondSubtitle = getSubtitle(o2.getWorkSummary().get(0)); + + if (firstSubtitle == null && secondSubtitle == null) { + return 0; + } + + if (firstSubtitle == null) { + return -1; + } + + if (secondSubtitle == null) { + return 1; + } + + comparison = firstSubtitle.compareTo(secondSubtitle); + } + return comparison; + } + + private String getTitle(WorkSummaryExtended workSummary) { + if (workSummary.getTitle() == null) { + return null; + } + + if (workSummary.getTitle().getTitle() == null) { + return null; + } + + if (workSummary.getTitle().getTitle().getContent() == null) { + return null; + } + + return workSummary.getTitle().getTitle().getContent().toLowerCase(); + } + + private String getSubtitle(WorkSummaryExtended workSummary) { + if (workSummary.getTitle() == null) { + return null; + } + + if (workSummary.getTitle().getSubtitle() == null) { + return null; + } + + if (workSummary.getTitle().getSubtitle().getContent() == null) { + return null; + } + + return workSummary.getTitle().getSubtitle().getContent().toLowerCase(); + } +} diff --git a/orcid-core/src/main/java/org/orcid/core/utils/comparators/TypeComparator.java b/orcid-core/src/main/java/org/orcid/core/utils/comparators/TypeComparator.java new file mode 100644 index 00000000000..b1210ded670 --- /dev/null +++ b/orcid-core/src/main/java/org/orcid/core/utils/comparators/TypeComparator.java @@ -0,0 +1,24 @@ +package org.orcid.core.utils.comparators; + +import java.util.Comparator; + +import org.orcid.jaxb.model.v3.release.record.summary.WorkGroup; + +public class TypeComparator implements Comparator{ + @Override + public int compare(org.orcid.jaxb.model.v3.release.record.summary.WorkGroup o1, org.orcid.jaxb.model.v3.release.record.summary.WorkGroup o2) { + if (o1.getWorkSummary().get(0).getType() == null && o2.getWorkSummary().get(0).getType() == null) { + return 0; + } + + if (o1.getWorkSummary().get(0).getType() == null) { + return -1; + } + + if (o2.getWorkSummary().get(0).getType() == null) { + return 1; + } + + return o1.getWorkSummary().get(0).getType().name().compareTo(o2.getWorkSummary().get(0).getType().name()); + } +} diff --git a/orcid-core/src/main/java/org/orcid/core/utils/comparators/TypeComparatorWorkGroupExtended.java b/orcid-core/src/main/java/org/orcid/core/utils/comparators/TypeComparatorWorkGroupExtended.java new file mode 100644 index 00000000000..a429e71e797 --- /dev/null +++ b/orcid-core/src/main/java/org/orcid/core/utils/comparators/TypeComparatorWorkGroupExtended.java @@ -0,0 +1,24 @@ +package org.orcid.core.utils.comparators; + +import java.util.Comparator; + +import org.orcid.pojo.WorkGroupExtended; + +public class TypeComparatorWorkGroupExtended implements Comparator { + @Override + public int compare(WorkGroupExtended o1, WorkGroupExtended o2) { + if (o1.getWorkSummary().get(0).getType() == null && o2.getWorkSummary().get(0).getType() == null) { + return 0; + } + + if (o1.getWorkSummary().get(0).getType() == null) { + return -1; + } + + if (o2.getWorkSummary().get(0).getType() == null) { + return 1; + } + + return o1.getWorkSummary().get(0).getType().name().compareTo(o2.getWorkSummary().get(0).getType().name()); + } +} diff --git a/orcid-core/src/main/java/org/orcid/pojo/grouping/WorkGroup.java b/orcid-core/src/main/java/org/orcid/pojo/grouping/WorkGroup.java index 1bbfa1e2b30..ee77ffddf57 100644 --- a/orcid-core/src/main/java/org/orcid/pojo/grouping/WorkGroup.java +++ b/orcid-core/src/main/java/org/orcid/pojo/grouping/WorkGroup.java @@ -1,6 +1,8 @@ package org.orcid.pojo.grouping; -import org.orcid.core.togglz.Features; +import java.util.ArrayList; +import java.util.List; + import org.orcid.jaxb.model.common.Relationship; import org.orcid.jaxb.model.common.WorkType; import org.orcid.jaxb.model.v3.release.common.PublicationDate; @@ -8,10 +10,11 @@ import org.orcid.jaxb.model.v3.release.record.summary.WorkSummary; import org.orcid.pojo.WorkGroupExtended; import org.orcid.pojo.WorkSummaryExtended; -import org.orcid.pojo.ajaxForm.*; - -import java.util.ArrayList; -import java.util.List; +import org.orcid.pojo.ajaxForm.ActivityExternalIdentifier; +import org.orcid.pojo.ajaxForm.Date; +import org.orcid.pojo.ajaxForm.PojoUtil; +import org.orcid.pojo.ajaxForm.Text; +import org.orcid.pojo.ajaxForm.WorkForm; public class WorkGroup extends ActivityGroup { @@ -27,6 +30,13 @@ public void setWorks(List works) { this.works = works; } + public void addWork(WorkForm work) { + if(this.works == null) { + this.works = new ArrayList(); + } + this.works.add(work); + } + public static WorkGroup valueOf(org.orcid.jaxb.model.v3.release.record.summary.WorkGroup workGroup, int id, String orcid) { WorkGroup group = new WorkGroup(); group.setGroupId(id); diff --git a/orcid-core/src/main/java/org/orcid/pojo/summary/AffiliationSummary.java b/orcid-core/src/main/java/org/orcid/pojo/summary/AffiliationSummary.java index 14ed5f3594d..03ee2c4eae6 100644 --- a/orcid-core/src/main/java/org/orcid/pojo/summary/AffiliationSummary.java +++ b/orcid-core/src/main/java/org/orcid/pojo/summary/AffiliationSummary.java @@ -103,6 +103,38 @@ public static AffiliationSummary valueOf(AffiliationForm as, String orcid, Strin return form; } + public static AffiliationSummary valueof(org.orcid.jaxb.model.v3.release.record.summary.AffiliationSummary as, String orcid, String type) { + AffiliationSummary form = new AffiliationSummary(); + if(as != null) { + form.setType(type); + + if(as.getOrganization() != null && as.getOrganization().getName() != null) { + form.setOrganizationName(as.getOrganization().getName()); + } + + if(as.getUrl() != null && !PojoUtil.isEmpty(as.getUrl().getValue())) { + form.setUrl(as.getUrl().getValue()); + } + + if(as.getStartDate() != null) { + form.setStartDate(as.getStartDate().toString()); + } + + if(as.getEndDate() != null) { + form.setEndDate(as.getEndDate().toString()); + } + + if(as.getRoleTitle() != null) { + form.setRole(as.getRoleTitle()); + } + + if(as.getSource() != null) { + form.setValidated(!SourceUtils.isSelfAsserted(as.getSource(), orcid)); + } + } + return form; + } + private static String getDate(Date date) { return date != null ? date.toFuzzyDate().toString() : null; } diff --git a/orcid-core/src/main/java/org/orcid/pojo/summary/ExternalIdentifiersSummary.java b/orcid-core/src/main/java/org/orcid/pojo/summary/ExternalIdentifiersSummary.java index 61fab224d86..12013555ba8 100644 --- a/orcid-core/src/main/java/org/orcid/pojo/summary/ExternalIdentifiersSummary.java +++ b/orcid-core/src/main/java/org/orcid/pojo/summary/ExternalIdentifiersSummary.java @@ -58,9 +58,11 @@ public void setValidated(boolean validated) { public static List valueOf(PersonExternalIdentifiers personExternalIdentifiers, String orcid) { List externalIdentifiersSummaryList = new ArrayList<>(); - personExternalIdentifiers.getExternalIdentifiers().forEach(personExternalIdentifier -> { - externalIdentifiersSummaryList.add(ExternalIdentifiersSummary.valueOf(personExternalIdentifier, orcid)); - }); + if(personExternalIdentifiers != null) { + personExternalIdentifiers.getExternalIdentifiers().forEach(personExternalIdentifier -> { + externalIdentifiersSummaryList.add(ExternalIdentifiersSummary.valueOf(personExternalIdentifier, orcid)); + }); + } return externalIdentifiersSummaryList; } diff --git a/orcid-core/src/main/resources/orcid-core-context.xml b/orcid-core/src/main/resources/orcid-core-context.xml index 257f53a8821..c0c77f1452d 100644 --- a/orcid-core/src/main/resources/orcid-core-context.xml +++ b/orcid-core/src/main/resources/orcid-core-context.xml @@ -1218,5 +1218,7 @@ + + diff --git a/orcid-core/src/test/java/org/orcid/core/common/manager/EmailDomainManagerTest.java b/orcid-core/src/test/java/org/orcid/core/common/manager/EmailDomainManagerTest.java index de67c61336a..5a89982de1a 100644 --- a/orcid-core/src/test/java/org/orcid/core/common/manager/EmailDomainManagerTest.java +++ b/orcid-core/src/test/java/org/orcid/core/common/manager/EmailDomainManagerTest.java @@ -12,6 +12,7 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import static org.junit.Assert.fail; import java.util.List; diff --git a/orcid-core/src/test/java/org/orcid/core/common/manager/SummaryManagerTest.java b/orcid-core/src/test/java/org/orcid/core/common/manager/SummaryManagerTest.java new file mode 100644 index 00000000000..70088c6ac9b --- /dev/null +++ b/orcid-core/src/test/java/org/orcid/core/common/manager/SummaryManagerTest.java @@ -0,0 +1,688 @@ +package org.orcid.core.common.manager; + +import static org.junit.Assert.assertEquals; + +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.xml.datatype.XMLGregorianCalendar; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; +import org.orcid.core.common.manager.impl.SummaryManagerImpl; +import org.orcid.core.manager.ProfileEntityCacheManager; +import org.orcid.core.manager.v3.WorksCacheManager; +import org.orcid.core.manager.v3.read_only.AffiliationsManagerReadOnly; +import org.orcid.core.manager.v3.read_only.ExternalIdentifierManagerReadOnly; +import org.orcid.core.manager.v3.read_only.PeerReviewManagerReadOnly; +import org.orcid.core.manager.v3.read_only.ProfileFundingManagerReadOnly; +import org.orcid.core.manager.v3.read_only.RecordManagerReadOnly; +import org.orcid.core.manager.v3.read_only.RecordNameManagerReadOnly; +import org.orcid.jaxb.model.v3.release.common.CreatedDate; +import org.orcid.jaxb.model.v3.release.common.CreditName; +import org.orcid.jaxb.model.v3.release.common.FuzzyDate; +import org.orcid.jaxb.model.v3.release.common.LastModifiedDate; +import org.orcid.jaxb.model.v3.release.common.OrcidIdentifier; +import org.orcid.jaxb.model.v3.release.common.Organization; +import org.orcid.jaxb.model.v3.release.common.Source; +import org.orcid.jaxb.model.v3.release.common.SourceClientId; +import org.orcid.jaxb.model.v3.release.common.SourceOrcid; +import org.orcid.jaxb.model.v3.release.common.Title; +import org.orcid.jaxb.model.v3.release.common.Visibility; +import org.orcid.jaxb.model.v3.release.common.Year; +import org.orcid.jaxb.model.v3.release.record.AffiliationType; +import org.orcid.jaxb.model.v3.release.record.FamilyName; +import org.orcid.jaxb.model.v3.release.record.FundingTitle; +import org.orcid.jaxb.model.v3.release.record.GivenNames; +import org.orcid.jaxb.model.v3.release.record.Name; +import org.orcid.jaxb.model.v3.release.record.PersonExternalIdentifier; +import org.orcid.jaxb.model.v3.release.record.PersonExternalIdentifiers; +import org.orcid.jaxb.model.v3.release.record.WorkTitle; +import org.orcid.jaxb.model.v3.release.record.summary.AffiliationGroup; +import org.orcid.jaxb.model.v3.release.record.summary.AffiliationSummary; +import org.orcid.jaxb.model.v3.release.record.summary.DistinctionSummary; +import org.orcid.jaxb.model.v3.release.record.summary.EducationSummary; +import org.orcid.jaxb.model.v3.release.record.summary.EmploymentSummary; +import org.orcid.jaxb.model.v3.release.record.summary.FundingGroup; +import org.orcid.jaxb.model.v3.release.record.summary.FundingSummary; +import org.orcid.jaxb.model.v3.release.record.summary.Fundings; +import org.orcid.jaxb.model.v3.release.record.summary.InvitedPositionSummary; +import org.orcid.jaxb.model.v3.release.record.summary.MembershipSummary; +import org.orcid.jaxb.model.v3.release.record.summary.QualificationSummary; +import org.orcid.jaxb.model.v3.release.record.summary.ServiceSummary; +import org.orcid.jaxb.model.v3.release.record.summary.WorkGroup; +import org.orcid.jaxb.model.v3.release.record.summary.WorkSummary; +import org.orcid.jaxb.model.v3.release.record.summary.Works; +import org.orcid.persistence.jpa.entities.ProfileEntity; +import org.orcid.pojo.PeerReviewMinimizedSummary; +import org.orcid.pojo.summary.RecordSummary; +import org.orcid.utils.DateUtils; +import org.springframework.test.util.ReflectionTestUtils; + +public class SummaryManagerTest { + private final String ORCID = "0000-0000-0000-0000"; + private final String CLIENT1 = "APP-0000"; + + public SummaryManagerImpl manager = new SummaryManagerImpl(); + + @Mock + private AffiliationsManagerReadOnly affiliationsManagerReadOnlyMock; + + @Mock + private RecordNameManagerReadOnly recordNameManagerReadOnlyMock; + + @Mock + private PeerReviewManagerReadOnly peerReviewManagerReadOnlyMock; + + @Mock + private ExternalIdentifierManagerReadOnly externalIdentifierManagerReadOnlyMock; + + @Mock + private RecordManagerReadOnly recordManagerReadOnlyMock; + + @Mock + private ProfileEntityCacheManager profileEntityCacheManagerMock; + + @Mock + private ProfileFundingManagerReadOnly profileFundingManagerReadOnlyMock; + + @Mock + private ProfileEntity profileEntityMock; + + @Mock + private WorksCacheManager worksCacheManagerMock; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + XMLGregorianCalendar now = DateUtils.convertToXMLGregorianCalendar(new Date()); + + // Set record Name + Name n = new Name(); + n.setCreatedDate(new CreatedDate(now)); + n.setLastModifiedDate(new LastModifiedDate(now)); + n.setVisibility(Visibility.PUBLIC); + n.setGivenNames(new GivenNames("ORCID")); + n.setFamilyName(new FamilyName("Test")); + n.setCreditName(new CreditName("ORCID Test Credit Name")); + + Mockito.when(recordNameManagerReadOnlyMock.getRecordName(Mockito.eq(ORCID))).thenReturn(n); + ReflectionTestUtils.setField(manager, "recordNameManagerReadOnly", recordNameManagerReadOnlyMock); + + // Set external identifiers + Mockito.when(externalIdentifierManagerReadOnlyMock.getPublicExternalIdentifiers(Mockito.eq(ORCID))).thenReturn(getPersonExternalIdentifiers()); + ReflectionTestUtils.setField(manager, "externalIdentifierManagerReadOnly", externalIdentifierManagerReadOnlyMock); + + // Set affiliations + Mockito.when(affiliationsManagerReadOnlyMock.getGroupedAffiliations(Mockito.eq(ORCID), Mockito.eq(true))).thenReturn(generateAffiliations()); + ReflectionTestUtils.setField(manager, "affiliationsManagerReadOnly", affiliationsManagerReadOnlyMock); + + // Set works + Mockito.when(worksCacheManagerMock.getGroupedWorks(Mockito.eq(ORCID))).thenReturn(getWorkGroups()); + ReflectionTestUtils.setField(manager, "worksCacheManager", worksCacheManagerMock); + + // Set fundings + Fundings fundings = getFundings(); + Mockito.when(profileFundingManagerReadOnlyMock.getFundingSummaryList(Mockito.eq(ORCID))).thenReturn(new ArrayList()); + Mockito.when(profileFundingManagerReadOnlyMock.groupFundings(Mockito.anyList(), Mockito.eq(true))).thenReturn(fundings); + ReflectionTestUtils.setField(manager, "profileFundingManagerReadOnly", profileFundingManagerReadOnlyMock); + + // Set peer reviews + Mockito.when(peerReviewManagerReadOnlyMock.getPeerReviewMinimizedSummaryList(Mockito.eq(ORCID), Mockito.eq(true))).thenReturn(getPeerReviewSummaryList()); + ReflectionTestUtils.setField(manager, "peerReviewManagerReadOnly", peerReviewManagerReadOnlyMock); + + // Set metadata + OrcidIdentifier oi = new OrcidIdentifier(); + oi.setUri("https://test.orcid.org/0000-0000-0000-0000"); + Mockito.when(recordManagerReadOnlyMock.getOrcidIdentifier(Mockito.eq(ORCID))).thenReturn(oi); + ReflectionTestUtils.setField(manager, "recordManagerReadOnly", recordManagerReadOnlyMock); + + Mockito.when(profileEntityMock.getDateCreated()).thenReturn(new Date(124, 0, 1)); + Mockito.when(profileEntityMock.getLastModified()).thenReturn(new Date(124, 11, 31)); + Mockito.when(profileEntityCacheManagerMock.retrieve(ORCID)).thenReturn(profileEntityMock); + ReflectionTestUtils.setField(manager, "profileEntityCacheManager", profileEntityCacheManagerMock); + } + + @Test + public void getSummaryTest() { + RecordSummary rs = manager.getRecordSummary(ORCID); + assertEquals("https://test.orcid.org/" + ORCID, rs.getOrcid()); + assertEquals("2024-01-01", rs.getCreation()); + assertEquals("2024-12-31", rs.getLastModified()); + // Affiliations + assertEquals(3, rs.getEmploymentAffiliations().size()); + assertEquals(3, rs.getEmploymentAffiliationsCount()); + assertEquals(3, rs.getProfessionalActivities().size()); + assertEquals(12, rs.getProfessionalActivitiesCount()); + // External identifiers + assertEquals(1, rs.getExternalIdentifiers().size()); + // Works + assertEquals(0, rs.getSelfAssertedWorks()); + assertEquals(3, rs.getValidatedWorks()); + // Funding + assertEquals(0, rs.getSelfAssertedFunds()); + assertEquals(3, rs.getValidatedFunds()); + // Peer review + assertEquals(2, rs.getSelfAssertedPeerReviews()); + assertEquals(4, rs.getPeerReviewPublicationGrants()); + assertEquals(16, rs.getPeerReviewsTotal()); + } + + @Test + public void generateAffiliationsSummaryTest() { + RecordSummary rs = new RecordSummary(); + manager.generateAffiliationsSummary(rs, ORCID); + assertEquals(3, rs.getEmploymentAffiliations().size()); + assertEquals(3, rs.getEmploymentAffiliationsCount()); + assertEquals(3, rs.getProfessionalActivities().size()); + // 3 of every professional activity type + assertEquals(12, rs.getProfessionalActivitiesCount()); + } + + @Test + public void generateAffiliationsSummary_EmptyTest() { + RecordSummary rs = new RecordSummary(); + Map>> affiliations = generateAffiliations(); + affiliations.remove(AffiliationType.DISTINCTION); + affiliations.remove(AffiliationType.EDUCATION); + affiliations.remove(AffiliationType.EMPLOYMENT); + affiliations.remove(AffiliationType.INVITED_POSITION); + affiliations.remove(AffiliationType.MEMBERSHIP); + affiliations.remove(AffiliationType.QUALIFICATION); + affiliations.remove(AffiliationType.SERVICE); + + Mockito.when(affiliationsManagerReadOnlyMock.getGroupedAffiliations(Mockito.eq(ORCID), Mockito.eq(true))).thenReturn(affiliations); + manager.generateAffiliationsSummary(rs, ORCID); + assertEquals(0, rs.getEmploymentAffiliations().size()); + assertEquals(0, rs.getEmploymentAffiliationsCount()); + assertEquals(0, rs.getProfessionalActivities().size()); + assertEquals(0, rs.getProfessionalActivitiesCount()); + } + + @Test + public void generateAffiliationsSummary_EmploymentOnlyTest() { + RecordSummary rs = new RecordSummary(); + Map>> affiliations = generateAffiliations(); + affiliations.remove(AffiliationType.DISTINCTION); + affiliations.remove(AffiliationType.EDUCATION); + affiliations.remove(AffiliationType.INVITED_POSITION); + affiliations.remove(AffiliationType.MEMBERSHIP); + affiliations.remove(AffiliationType.QUALIFICATION); + affiliations.remove(AffiliationType.SERVICE); + + Mockito.when(affiliationsManagerReadOnlyMock.getGroupedAffiliations(Mockito.eq(ORCID), Mockito.eq(true))).thenReturn(affiliations); + manager.generateAffiliationsSummary(rs, ORCID); + assertEquals(3, rs.getEmploymentAffiliations().size()); + assertEquals(3, rs.getEmploymentAffiliationsCount()); + assertEquals(0, rs.getProfessionalActivities().size()); + assertEquals(0, rs.getProfessionalActivitiesCount()); + } + + @Test + public void generateAffiliationsSummary_EducationOnlyTest() { + RecordSummary rs = new RecordSummary(); + Map>> affiliations = generateAffiliations(); + affiliations.remove(AffiliationType.DISTINCTION); + affiliations.remove(AffiliationType.EMPLOYMENT); + affiliations.remove(AffiliationType.INVITED_POSITION); + affiliations.remove(AffiliationType.MEMBERSHIP); + affiliations.remove(AffiliationType.QUALIFICATION); + affiliations.remove(AffiliationType.SERVICE); + + Mockito.when(affiliationsManagerReadOnlyMock.getGroupedAffiliations(Mockito.eq(ORCID), Mockito.eq(true))).thenReturn(affiliations); + manager.generateAffiliationsSummary(rs, ORCID); + assertEquals(0, rs.getEmploymentAffiliations().size()); + assertEquals(0, rs.getEmploymentAffiliationsCount()); + assertEquals(0, rs.getProfessionalActivities().size()); + assertEquals(0, rs.getProfessionalActivitiesCount()); + } + + @Test + public void generateAffiliationsSummary_InvitedPositionOnlyTest() { + RecordSummary rs = new RecordSummary(); + Map>> affiliations = generateAffiliations(); + affiliations.remove(AffiliationType.DISTINCTION); + affiliations.remove(AffiliationType.EMPLOYMENT); + affiliations.remove(AffiliationType.MEMBERSHIP); + affiliations.remove(AffiliationType.QUALIFICATION); + affiliations.remove(AffiliationType.SERVICE); + + Mockito.when(affiliationsManagerReadOnlyMock.getGroupedAffiliations(Mockito.eq(ORCID), Mockito.eq(true))).thenReturn(affiliations); + manager.generateAffiliationsSummary(rs, ORCID); + assertEquals(0, rs.getEmploymentAffiliations().size()); + assertEquals(0, rs.getEmploymentAffiliationsCount()); + assertEquals(3, rs.getProfessionalActivities().size()); + assertEquals(3, rs.getProfessionalActivitiesCount()); + } + + @Test + public void generateAffiliationsSummary_ProfessionalActivitiesOnlyTest() { + RecordSummary rs = new RecordSummary(); + Map>> affiliations = generateAffiliations(); + affiliations.remove(AffiliationType.EMPLOYMENT); + + Mockito.when(affiliationsManagerReadOnlyMock.getGroupedAffiliations(Mockito.eq(ORCID), Mockito.eq(true))).thenReturn(affiliations); + manager.generateAffiliationsSummary(rs, ORCID); + assertEquals(0, rs.getEmploymentAffiliations().size()); + assertEquals(0, rs.getEmploymentAffiliationsCount()); + assertEquals(3, rs.getProfessionalActivities().size()); + assertEquals(12, rs.getProfessionalActivitiesCount()); + } + + @Test + public void generateExternalIdentifiersSummaryTest() { + RecordSummary rs = new RecordSummary(); + manager.generateExternalIdentifiersSummary(rs, ORCID); + assertEquals(1, rs.getExternalIdentifiers().size()); + assertEquals("0", rs.getExternalIdentifiers().get(0).getId()); + assertEquals("0000", rs.getExternalIdentifiers().get(0).getReference()); + } + + @Test + public void generateExternalIdentifiersSummary_NullTest() { + RecordSummary rs = new RecordSummary(); + Mockito.when(externalIdentifierManagerReadOnlyMock.getPublicExternalIdentifiers(Mockito.eq(ORCID))).thenReturn(null); + + manager.generateExternalIdentifiersSummary(rs, ORCID); + assertEquals(0, rs.getExternalIdentifiers().size()); + } + + @Test + public void generateExternalIdentifiersSummary_EmptyTest() { + RecordSummary rs = new RecordSummary(); + Mockito.when(externalIdentifierManagerReadOnlyMock.getPublicExternalIdentifiers(Mockito.eq(ORCID))).thenReturn(new PersonExternalIdentifiers()); + + manager.generateExternalIdentifiersSummary(rs, ORCID); + assertEquals(0, rs.getExternalIdentifiers().size()); + } + + @Test + public void generateWorksSummaryTest() { + RecordSummary rs = new RecordSummary(); + manager.generateWorksSummary(rs, ORCID); + assertEquals(0, rs.getSelfAssertedWorks()); + assertEquals(3, rs.getValidatedWorks()); + } + + @Test + public void generateWorksSummary_OboValidatedTest() { + RecordSummary rs = new RecordSummary(); + Works works = getWorkGroups(); + Source s = new Source(); + s.setSourceClientId(new SourceClientId(CLIENT1)); + s.setAssertionOriginClientId(new SourceClientId(CLIENT1)); + for(WorkGroup wg : works.getWorkGroup()) { + for(WorkSummary ws : wg.getWorkSummary()) { + ws.setSource(s); + } + } + Mockito.when(worksCacheManagerMock.getGroupedWorks(Mockito.eq(ORCID))).thenReturn(works); + + manager.generateWorksSummary(rs, ORCID); + assertEquals(0, rs.getSelfAssertedWorks()); + assertEquals(3, rs.getValidatedWorks()); + } + + @Test + public void generateWorksSummary_SelfAssertedOnlyTest() { + RecordSummary rs = new RecordSummary(); + Works works = getWorkGroups(); + Source s = new Source(); + s.setSourceOrcid(new SourceOrcid(ORCID)); + for(WorkGroup wg : works.getWorkGroup()) { + for(WorkSummary ws : wg.getWorkSummary()) { + ws.setSource(s); + } + } + Mockito.when(worksCacheManagerMock.getGroupedWorks(Mockito.eq(ORCID))).thenReturn(works); + + manager.generateWorksSummary(rs, ORCID); + assertEquals(3, rs.getSelfAssertedWorks()); + assertEquals(0, rs.getValidatedWorks()); + } + + @Test + public void generateWorksSummary_OboSelfAssertedOnlyTest() { + RecordSummary rs = new RecordSummary(); + Works works = getWorkGroups(); + Source s = new Source(); + s.setSourceClientId(new SourceClientId(CLIENT1)); + s.setAssertionOriginOrcid(new SourceOrcid(ORCID)); + for(WorkGroup wg : works.getWorkGroup()) { + for(WorkSummary ws : wg.getWorkSummary()) { + ws.setSource(s); + } + } + Mockito.when(worksCacheManagerMock.getGroupedWorks(Mockito.eq(ORCID))).thenReturn(works); + + manager.generateWorksSummary(rs, ORCID); + assertEquals(3, rs.getSelfAssertedWorks()); + assertEquals(0, rs.getValidatedWorks()); + } + + @Test + public void generateFundingSummaryTest() { + RecordSummary rs = new RecordSummary(); + manager.generateFundingSummary(rs, ORCID); + assertEquals(0, rs.getSelfAssertedFunds()); + assertEquals(3, rs.getValidatedFunds()); + } + + @Test + public void generateFundingSummary_OboValidatedTest() { + RecordSummary rs = new RecordSummary(); + Source s = new Source(); + s.setSourceClientId(new SourceClientId(CLIENT1)); + s.setAssertionOriginClientId(new SourceClientId(CLIENT1)); + Fundings fundings = getFundings(); + for(FundingGroup fg : fundings.getFundingGroup()) { + for(FundingSummary fs : fg.getFundingSummary()) { + fs.setSource(s); + } + } + Mockito.when(profileFundingManagerReadOnlyMock.groupFundings(Mockito.anyList(), Mockito.eq(true))).thenReturn(fundings); + + manager.generateFundingSummary(rs, ORCID); + assertEquals(0, rs.getSelfAssertedFunds()); + assertEquals(3, rs.getValidatedFunds()); + } + + @Test + public void generateFundingSummary_SelfAssertedTest() { + RecordSummary rs = new RecordSummary(); + Source s = new Source(); + s.setSourceOrcid(new SourceOrcid(ORCID)); + Fundings fundings = getFundings(); + for(FundingGroup fg : fundings.getFundingGroup()) { + for(FundingSummary fs : fg.getFundingSummary()) { + fs.setSource(s); + } + } + Mockito.when(profileFundingManagerReadOnlyMock.groupFundings(Mockito.anyList(), Mockito.eq(true))).thenReturn(fundings); + + manager.generateFundingSummary(rs, ORCID); + assertEquals(3, rs.getSelfAssertedFunds()); + assertEquals(0, rs.getValidatedFunds()); + } + + @Test + public void generateFundingSummary_OboSelfAssertedTest() { + RecordSummary rs = new RecordSummary(); + Source s = new Source(); + s.setSourceClientId(new SourceClientId(CLIENT1)); + s.setAssertionOriginOrcid(new SourceOrcid(ORCID)); + Fundings fundings = getFundings(); + for(FundingGroup fg : fundings.getFundingGroup()) { + for(FundingSummary fs : fg.getFundingSummary()) { + fs.setSource(s); + } + } + Mockito.when(profileFundingManagerReadOnlyMock.groupFundings(Mockito.anyList(), Mockito.eq(true))).thenReturn(fundings); + + manager.generateFundingSummary(rs, ORCID); + assertEquals(3, rs.getSelfAssertedFunds()); + assertEquals(0, rs.getValidatedFunds()); + } + + @Test + public void generatePeerReviewSummaryTest() { + RecordSummary rs = new RecordSummary(); + manager.generatePeerReviewSummary(rs, ORCID); + // Each peer review group have 1 self asserted peer review and 1 user obo asserted peer review + // So, we have 3 groups = 6 self asserted peer reviews in total + assertEquals(2, rs.getSelfAssertedPeerReviews()); + assertEquals(4, rs.getPeerReviewPublicationGrants()); + assertEquals(16, rs.getPeerReviewsTotal()); + } + + @Test + public void generatePeerReviewSummary_OboValidatedTest() { + RecordSummary rs = new RecordSummary(); + List peerReviews = getPeerReviewSummaryList(); + for(PeerReviewMinimizedSummary pr : peerReviews) { + pr.setClientSourceId(CLIENT1); + pr.setAssertionOriginSourceId(CLIENT1); + pr.setSourceId(null); + } + Mockito.when(peerReviewManagerReadOnlyMock.getPeerReviewMinimizedSummaryList(Mockito.eq(ORCID), Mockito.eq(true))).thenReturn(peerReviews); + + manager.generatePeerReviewSummary(rs, ORCID); + // Each peer review group have 1 self asserted peer review and 1 user obo asserted peer review + // So, we have 3 groups = 6 self asserted peer reviews in total + assertEquals(0, rs.getSelfAssertedPeerReviews()); + assertEquals(4, rs.getPeerReviewPublicationGrants()); + assertEquals(16, rs.getPeerReviewsTotal()); + } + + @Test + public void generatePeerReviewSummary_SelfAssertedTest() { + RecordSummary rs = new RecordSummary(); + List peerReviews = getPeerReviewSummaryList(); + for(PeerReviewMinimizedSummary pr : peerReviews) { + pr.setClientSourceId(null); + pr.setAssertionOriginSourceId(null); + pr.setSourceId(ORCID); + } + Mockito.when(peerReviewManagerReadOnlyMock.getPeerReviewMinimizedSummaryList(Mockito.eq(ORCID), Mockito.eq(true))).thenReturn(peerReviews); + + manager.generatePeerReviewSummary(rs, ORCID); + // Each peer review group have 1 self asserted peer review and 1 user obo asserted peer review + // So, we have 3 groups = 6 self asserted peer reviews in total + assertEquals(4, rs.getSelfAssertedPeerReviews()); + assertEquals(4, rs.getPeerReviewPublicationGrants()); + assertEquals(16, rs.getPeerReviewsTotal()); + } + + @Test + public void generatePeerReviewSummary_Test() { + RecordSummary rs = new RecordSummary(); + List peerReviews = getPeerReviewSummaryList(); + for(PeerReviewMinimizedSummary pr : peerReviews) { + pr.setClientSourceId(CLIENT1); + pr.setAssertionOriginSourceId(ORCID); + pr.setSourceId(null); + } + Mockito.when(peerReviewManagerReadOnlyMock.getPeerReviewMinimizedSummaryList(Mockito.eq(ORCID), Mockito.eq(true))).thenReturn(peerReviews); + + manager.generatePeerReviewSummary(rs, ORCID); + // Each peer review group have 1 self asserted peer review and 1 user obo asserted peer review + // So, we have 3 groups = 6 self asserted peer reviews in total + assertEquals(4, rs.getSelfAssertedPeerReviews()); + assertEquals(4, rs.getPeerReviewPublicationGrants()); + assertEquals(16, rs.getPeerReviewsTotal()); + } + + private PersonExternalIdentifiers getPersonExternalIdentifiers() { + PersonExternalIdentifiers peis = new PersonExternalIdentifiers(); + PersonExternalIdentifier pei = new PersonExternalIdentifier(); + pei.setPutCode(0L); + pei.setSource(new Source(ORCID)); + pei.setValue("0000"); + peis.getExternalIdentifiers().add(pei); + return peis; + } + + private List> getAffiliations(AffiliationType affiliationType) { + List> affiliationGroups = new ArrayList<>(); + for (int i = 0; i < 3; i++) { + AffiliationGroup group = new AffiliationGroup(); + + for(int j = 0; j < 3; j++) { + AffiliationSummary summary = getAffiliationSummary(affiliationType, CLIENT1, Long.valueOf(j)); + group.getActivities().add(summary); + } + + affiliationGroups.add(group); + } + return affiliationGroups; + } + + private AffiliationSummary getAffiliationSummary(AffiliationType affiliationType, String affiliationName, Long putCode) { + AffiliationSummary summary = null; + switch(affiliationType) { + case DISTINCTION: + summary = new DistinctionSummary(); + break; + case EDUCATION: + summary = new EducationSummary(); + break; + case EMPLOYMENT: + summary = new EmploymentSummary(); + break; + case INVITED_POSITION: + summary = new InvitedPositionSummary(); + break; + case MEMBERSHIP: + summary = new MembershipSummary(); + break; + case QUALIFICATION: + summary = new QualificationSummary(); + break; + case SERVICE: + summary = new ServiceSummary(); + break; + } + summary.setVisibility(Visibility.PUBLIC); + Organization org = new Organization(); + org.setName(affiliationName); + summary.setOrganization(org); + summary.setPutCode(putCode); + summary.setDisplayIndex(String.valueOf(putCode)); + summary.setEndDate(new FuzzyDate(new Year(2012), null, null)); + return summary; + } + + private Works getWorkGroups() { + Works works = new Works(); + for (int i = 0; i < 3; i++) { + WorkGroup wg = new WorkGroup(); + + // Add 4 works per group + // First source is the client + // Second source is the user + // Third source is a client through OBO + // Fourth source is the user through OBO + for (int j = 0; j < 4; j++) { + WorkSummary ws = new WorkSummary(); + ws.setVisibility(Visibility.PUBLIC); + WorkTitle wt = new WorkTitle(); + wt.setTitle(new Title("Work-" + j)); + ws.setTitle(wt); + Source source = new Source(); + ws.setSource(source); + switch (j) { + case 0: + source.setSourceClientId(new SourceClientId(CLIENT1)); + break; + case 1: + source.setSourceOrcid(new SourceOrcid(ORCID)); + break; + case 2: + source.setAssertionOriginClientId(new SourceClientId(CLIENT1)); + break; + case 3: + source.setAssertionOriginOrcid(new SourceOrcid(ORCID)); + break; + } + wg.getWorkSummary().add(ws); + } + + works.getWorkGroup().add(wg); + } + return works; + } + + private Fundings getFundings() { + Fundings fundings = new Fundings(); + + for (int i = 0; i < 3; i++) { + FundingGroup fg = new FundingGroup(); + + // Add 4 funding per group + // First source is the client + // Second source is the user + // Third source is a client through OBO + // Fourth source is the user through OBO + for (int j = 0; j < 4; j++) { + FundingSummary fs = new FundingSummary(); + FundingTitle ft = new FundingTitle(); + ft.setTitle(new Title("Funding-" + j)); + fs.setTitle(ft); + Source source = new Source(); + fs.setSource(source); + switch (j) { + case 0: + source.setSourceClientId(new SourceClientId(CLIENT1)); + break; + case 1: + source.setSourceOrcid(new SourceOrcid(ORCID)); + break; + case 2: + source.setAssertionOriginClientId(new SourceClientId(CLIENT1)); + break; + case 3: + source.setAssertionOriginOrcid(new SourceOrcid(ORCID)); + break; + } + fg.getFundingSummary().add(fs); + } + + fundings.getFundingGroup().add(fg); + } + + return fundings; + } + + private List getPeerReviewSummaryList() { + List peerReviews = new ArrayList(); + for(int i = 0; i < 4; i++) { + BigInteger groupId = BigInteger.valueOf(i); + String groupIdValue = "group-id-" + i; + // First source is the client + // Second source is the user + // Third source is a client through OBO + // Fourth source is the user through OBO + PeerReviewMinimizedSummary pr = new PeerReviewMinimizedSummary(ORCID, groupId, groupIdValue, BigInteger.valueOf(0), null, null, 0); + pr.addPutCode(BigInteger.valueOf(1)); + pr.addPutCode(BigInteger.valueOf(2)); + pr.addPutCode(BigInteger.valueOf(3)); + switch (i) { + case 0: + pr.setSourceId(CLIENT1); + break; + case 1: + pr.setSourceId(ORCID); + break; + case 2: + pr.setAssertionOriginSourceId(CLIENT1); + break; + case 3: + pr.setAssertionOriginSourceId(ORCID); + break; + } + peerReviews.add(pr); + } + return peerReviews; + } + + private Map>> generateAffiliations() { + Map>> affiliations = new HashMap>>(); + + affiliations.put(AffiliationType.DISTINCTION, getAffiliations(AffiliationType.DISTINCTION)); + affiliations.put(AffiliationType.EDUCATION, getAffiliations(AffiliationType.EDUCATION)); + affiliations.put(AffiliationType.EMPLOYMENT, getAffiliations(AffiliationType.EMPLOYMENT)); + affiliations.put(AffiliationType.INVITED_POSITION, getAffiliations(AffiliationType.INVITED_POSITION)); + affiliations.put(AffiliationType.MEMBERSHIP, getAffiliations(AffiliationType.MEMBERSHIP)); + affiliations.put(AffiliationType.QUALIFICATION, getAffiliations(AffiliationType.QUALIFICATION)); + affiliations.put(AffiliationType.SERVICE, getAffiliations(AffiliationType.SERVICE)); + return affiliations; + } +} diff --git a/orcid-test/src/main/resources/data/OrgAffiliationEntityData.xml b/orcid-test/src/main/resources/data/OrgAffiliationEntityData.xml index d786f1bc0b7..690ccb39658 100644 --- a/orcid-test/src/main/resources/data/OrgAffiliationEntityData.xml +++ b/orcid-test/src/main/resources/data/OrgAffiliationEntityData.xml @@ -1213,6 +1213,7 @@ end_day="01" visibility="PUBLIC" client_source_id="APP-5555555555555555" + display_index="2" /> diff --git a/orcid-utils/src/main/java/org/orcid/utils/DateUtils.java b/orcid-utils/src/main/java/org/orcid/utils/DateUtils.java index a0f1ba73cd4..5dd94684ce9 100644 --- a/orcid-utils/src/main/java/org/orcid/utils/DateUtils.java +++ b/orcid-utils/src/main/java/org/orcid/utils/DateUtils.java @@ -13,6 +13,7 @@ import javax.xml.datatype.XMLGregorianCalendar; import org.apache.commons.lang.StringUtils; +import java.text.SimpleDateFormat; /** * @@ -23,6 +24,8 @@ public class DateUtils { private static final Pattern DATE_PATTERN = Pattern.compile("(\\d+)(?:-(\\d+))?(?:-(\\d+))?(T\\d\\d:\\d\\d:\\d\\d)?"); + private static final SimpleDateFormat ISO8601 = new SimpleDateFormat("yyyy-MM-dd"); + //Thread safe: see source http://www.docjar.com/html/api/com/sun/org/apache/xerces/internal/jaxp/datatype/DatatypeFactoryImpl.java.html //see also analysis: http://www.javajirawat.com/2015/09/xmlgregoriancalendar-datatypefactory.html private static DatatypeFactory dataTypeFactory; @@ -158,5 +161,11 @@ private static DatatypeFactory createDataTypeFactory() { } return dataTypeFactory; } - + + public static String formatDateISO8601(Date date) { + if (date == null) { + return null; + } + return ISO8601.format(date); + } } diff --git a/orcid-web/src/main/java/org/orcid/frontend/web/controllers/PublicProfileController.java b/orcid-web/src/main/java/org/orcid/frontend/web/controllers/PublicProfileController.java index d80e560b147..34a319f1a69 100644 --- a/orcid-web/src/main/java/org/orcid/frontend/web/controllers/PublicProfileController.java +++ b/orcid-web/src/main/java/org/orcid/frontend/web/controllers/PublicProfileController.java @@ -1,5 +1,19 @@ package org.orcid.frontend.web.controllers; +import java.io.UnsupportedEncodingException; +import java.math.BigDecimal; +import java.text.NumberFormat; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.IntStream; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + import org.apache.commons.lang3.StringUtils; import org.orcid.core.exception.DeactivatedException; import org.orcid.core.exception.LockedException; @@ -77,22 +91,6 @@ import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.view.RedirectView; -import javax.annotation.Resource; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.UnsupportedEncodingException; -import java.math.BigDecimal; -import java.text.NumberFormat; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.stream.Collectors; -import java.util.stream.IntStream; -import java.util.stream.Stream; - @Controller public class PublicProfileController extends BaseWorkspaceController { diff --git a/orcid-web/src/main/java/org/orcid/frontend/web/controllers/PublicRecordController.java b/orcid-web/src/main/java/org/orcid/frontend/web/controllers/PublicRecordController.java index 1458506b188..2ddbc1255d7 100644 --- a/orcid-web/src/main/java/org/orcid/frontend/web/controllers/PublicRecordController.java +++ b/orcid-web/src/main/java/org/orcid/frontend/web/controllers/PublicRecordController.java @@ -1,57 +1,27 @@ package org.orcid.frontend.web.controllers; -import java.text.SimpleDateFormat; import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Comparator; -import java.util.GregorianCalendar; -import java.util.Iterator; -import java.util.List; import java.util.Map; -import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; -import java.util.stream.Stream; import javax.annotation.Resource; -import javax.xml.datatype.XMLGregorianCalendar; import org.orcid.core.common.manager.EventManager; +import org.orcid.core.common.manager.SummaryManager; import org.orcid.core.exception.DeactivatedException; import org.orcid.core.exception.LockedException; import org.orcid.core.exception.OrcidDeprecatedException; import org.orcid.core.exception.OrcidNoResultException; import org.orcid.core.exception.OrcidNotClaimedException; -import org.orcid.core.groupIds.issn.IssnPortalUrlBuilder; -import org.orcid.core.manager.OrgDisambiguatedManager; import org.orcid.core.manager.ProfileEntityCacheManager; -import org.orcid.core.manager.v3.ActivityManager; -import org.orcid.core.manager.v3.MembersManager; -import org.orcid.core.manager.v3.WorksCacheManager; import org.orcid.core.manager.v3.read_only.AddressManagerReadOnly; -import org.orcid.core.manager.v3.read_only.AffiliationsManagerReadOnly; -import org.orcid.core.manager.v3.read_only.EmailManagerReadOnly; import org.orcid.core.manager.v3.read_only.ExternalIdentifierManagerReadOnly; -import org.orcid.core.manager.v3.read_only.GroupIdRecordManagerReadOnly; -import org.orcid.core.manager.v3.read_only.PeerReviewManagerReadOnly; import org.orcid.core.manager.v3.read_only.PersonalDetailsManagerReadOnly; -import org.orcid.core.manager.v3.read_only.ProfileFundingManagerReadOnly; import org.orcid.core.manager.v3.read_only.ProfileKeywordManagerReadOnly; -import org.orcid.core.manager.v3.read_only.RecordManagerReadOnly; -import org.orcid.core.manager.v3.read_only.RecordNameManagerReadOnly; -import org.orcid.core.manager.v3.read_only.ResearchResourceManagerReadOnly; import org.orcid.core.manager.v3.read_only.ResearcherUrlManagerReadOnly; -import org.orcid.core.manager.v3.read_only.WorkManagerReadOnly; -import org.orcid.core.oauth.OrcidOauth2TokenDetailService; import org.orcid.core.togglz.Features; -import org.orcid.core.utils.v3.SourceUtils; -import org.orcid.frontend.web.pagination.Page; -import org.orcid.frontend.web.pagination.ResearchResourcePaginator; -import org.orcid.frontend.web.pagination.WorksPaginator; -import org.orcid.frontend.web.util.LanguagesMap; import org.orcid.jaxb.model.message.OrcidType; import org.orcid.jaxb.model.v3.release.record.Addresses; -import org.orcid.jaxb.model.v3.release.record.AffiliationType; import org.orcid.jaxb.model.v3.release.record.Biography; import org.orcid.jaxb.model.v3.release.record.Email; import org.orcid.jaxb.model.v3.release.record.Emails; @@ -63,25 +33,17 @@ import org.orcid.jaxb.model.v3.release.record.ResearcherUrls; import org.orcid.persistence.jpa.entities.EventType; import org.orcid.persistence.jpa.entities.ProfileEntity; -import org.orcid.pojo.PeerReviewMinimizedSummary; import org.orcid.pojo.PublicRecord; import org.orcid.pojo.ajaxForm.AddressForm; import org.orcid.pojo.ajaxForm.AddressesForm; -import org.orcid.pojo.ajaxForm.AffiliationGroupContainer; -import org.orcid.pojo.ajaxForm.AffiliationGroupForm; import org.orcid.pojo.ajaxForm.BiographyForm; -import org.orcid.pojo.ajaxForm.Date; import org.orcid.pojo.ajaxForm.ExternalIdentifiersForm; import org.orcid.pojo.ajaxForm.KeywordsForm; import org.orcid.pojo.ajaxForm.NamesForm; import org.orcid.pojo.ajaxForm.OtherNamesForm; import org.orcid.pojo.ajaxForm.PojoUtil; import org.orcid.pojo.ajaxForm.WebsitesForm; -import org.orcid.pojo.grouping.WorkGroup; -import org.orcid.pojo.summary.AffiliationSummary; -import org.orcid.pojo.summary.ExternalIdentifiersSummary; import org.orcid.pojo.summary.RecordSummary; -import org.orcid.utils.DateUtils; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; @@ -90,61 +52,12 @@ @Controller public class PublicRecordController extends BaseWorkspaceController { - - @Resource(name = "membersManagerV3") - MembersManager membersManager; - - @Resource(name = "workManagerReadOnlyV3") - private WorkManagerReadOnly workManagerReadOnly; - - @Resource(name = "peerReviewManagerReadOnlyV3") - private PeerReviewManagerReadOnly peerReviewManagerReadOnly; - - @Resource(name = "profileFundingManagerReadOnlyV3") - private ProfileFundingManagerReadOnly profileFundingManagerReadOnly; - - @Resource - private WorksPaginator worksPaginator; - - @Resource(name = "activityManagerV3") - private ActivityManager activityManager; - - @Resource(name = "languagesMap") - private LanguagesMap lm; - @Resource private ProfileEntityCacheManager profileEntityCacheManager; - @Resource(name = "groupIdRecordManagerReadOnlyV3") - private GroupIdRecordManagerReadOnly groupIdRecordManagerReadOnly; - @Resource(name = "personalDetailsManagerReadOnlyV3") private PersonalDetailsManagerReadOnly personalDetailsManagerReadOnly; - @Resource - private OrgDisambiguatedManager orgDisambiguatedManager; - - @Resource - private OrcidOauth2TokenDetailService orcidOauth2TokenService; - - @Resource(name = "sourceUtilsV3") - private SourceUtils sourceUtils; - - @Resource(name = "affiliationsManagerReadOnlyV3") - private AffiliationsManagerReadOnly affiliationsManagerReadOnly; - - @Resource - private ResearchResourcePaginator researchResourcePaginator; - - @Resource(name = "researchResourceManagerReadOnlyV3") - private ResearchResourceManagerReadOnly researchResourceManagerReadOnly; - - @Resource - private IssnPortalUrlBuilder issnPortalUrlBuilder; - - @Resource(name = "emailManagerReadOnlyV3") - protected EmailManagerReadOnly emailManagerReadOnly; - @Resource(name = "addressManagerReadOnlyV3") private AddressManagerReadOnly addressManagerReadOnly; @@ -157,24 +70,12 @@ public class PublicRecordController extends BaseWorkspaceController { @Resource(name = "externalIdentifierManagerReadOnlyV3") private ExternalIdentifierManagerReadOnly externalIdentifierManagerReadOnly; - @Resource(name = "recordManagerReadOnlyV3") - private RecordManagerReadOnly recordManagerReadOnly; - - @Resource - PublicProfileController publicProfileController; - @Resource private EventManager eventManager; - + @Resource - private WorksCacheManager worksCacheManager; + private SummaryManager summaryManager; - @Resource(name = "recordNameManagerReadOnlyV3") - private RecordNameManagerReadOnly recordNameManagerReadOnly; - - public static int ORCID_HASH_LENGTH = 8; - private static final String PAGE_SIZE_DEFAULT = "50"; - @RequestMapping(value = "/{orcid:(?:\\d{4}-){3,}\\d{3}[\\dX]}/public-record.json", method = RequestMethod.GET) public @ResponseBody PublicRecord getPublicRecord(@PathVariable("orcid") String orcid) { @@ -312,8 +213,6 @@ PublicRecord getRecord(String orcid) { @RequestMapping(value = "/{orcid:(?:\\d{4}-){3,}\\d{3}[\\dX]}/summary.json", method = RequestMethod.GET) public @ResponseBody RecordSummary getSummaryRecord(@PathVariable("orcid") String orcid) { RecordSummary recordSummary = new RecordSummary(); - boolean isDeprecated = false; - try { // Check if the profile is deprecated or locked orcidSecurityManager.checkProfile(orcid); @@ -330,142 +229,20 @@ PublicRecord getRecord(String orcid) { recordSummary.setName(localeManager.resolveMessage("orcid.reserved_for_claim")); return recordSummary; } catch (OrcidDeprecatedException e) { - isDeprecated = true; - } catch (OrcidNoResultException e) { - return recordSummary; - } - - if (isDeprecated) { recordSummary.setStatus("deprecated"); recordSummary.setEmploymentAffiliations(null); recordSummary.setProfessionalActivities(null); recordSummary.setExternalIdentifiers(null); - - } else { - recordSummary = getSummary(orcid); - recordSummary.setStatus("active"); - } - return recordSummary; - } - - public @ResponseBody - RecordSummary getSummary(String orcid) { - RecordSummary recordSummary = new RecordSummary(); - - Name name = recordNameManagerReadOnly.getRecordName(orcid); - if(name != null) { - String displayName = null; - if (name != null) { - if (name.getVisibility().equals(org.orcid.jaxb.model.v3.release.common.Visibility.PUBLIC)) { - displayName = getDisplayName(name); - } - } - recordSummary.setName(displayName); - } - - AffiliationGroupContainer groupedAffiliations = publicProfileController.getGroupedAffiliations(orcid); - List groupedEmployments = groupedAffiliations.getAffiliationGroups().get(AffiliationType.EMPLOYMENT); - - List employmentAffiliations = new ArrayList<>(); - - sortAffiliationsByCreatedDate(groupedEmployments); - - if (groupedEmployments.size() > 0) { - Stream employmentsList = groupedEmployments.stream().limit(3); - employmentsList.forEach(e -> employmentAffiliations.add(AffiliationSummary.valueOf(e.getDefaultAffiliation(), orcid, "employment"))); - } - - recordSummary.setEmploymentAffiliationsCount(groupedEmployments.size()); - recordSummary.setEmploymentAffiliations(employmentAffiliations); - - List professionalActivities = retrieveProfessionalActivities(groupedAffiliations, orcid); - - if (professionalActivities.size() > 3) { - recordSummary.setProfessionalActivities(Arrays.asList(professionalActivities.get(0), professionalActivities.get(1), professionalActivities.get(2))); - } else { - recordSummary.setProfessionalActivities(professionalActivities); - } - - recordSummary.setProfessionalActivitiesCount(professionalActivities.size()); - - PersonExternalIdentifiers personExternalIdentifiers; - - personExternalIdentifiers = externalIdentifierManagerReadOnly.getPublicExternalIdentifiers(orcid); - - recordSummary.setExternalIdentifiers(ExternalIdentifiersSummary.valueOf(personExternalIdentifiers, orcid)); - - Page works = publicProfileController.getAllWorkGroupsJson(orcid, "date", true); - - List workGroups = works.getGroups(); - - AtomicInteger validatedWorks = new AtomicInteger(); - AtomicInteger selfAssertedWorks = new AtomicInteger(); - - if (workGroups != null) { - workGroups.forEach(work -> work.getWorks().forEach(w -> { - if (work.getDefaultPutCode().equals(Long.valueOf(w.getPutCode().getValue()))) { - if(orcid.equals(w.getSource()) || orcid.equals(w.getAssertionOriginOrcid())) { - selfAssertedWorks.getAndIncrement(); - } else { - validatedWorks.getAndIncrement(); - } - } - })); - } - - recordSummary.setSelfAssertedWorks(selfAssertedWorks.get()); - recordSummary.setValidatedWorks(validatedWorks.get()); - - List fundingGroups = publicProfileController.getFundingsJson(orcid, "date", true); - - AtomicInteger validatedFunds = new AtomicInteger(); - AtomicInteger selfAssertedFunds = new AtomicInteger(); - - if (fundingGroups != null) { - fundingGroups.forEach(fundingGroup -> { - if(orcid.equals(fundingGroup.getDefaultFunding().getSource()) || orcid.equals(fundingGroup.getDefaultFunding().getAssertionOriginOrcid())) { - selfAssertedFunds.getAndIncrement(); - } else { - validatedFunds.getAndIncrement(); - } - }); - } - - recordSummary.setSelfAssertedFunds(selfAssertedFunds.get()); - recordSummary.setValidatedFunds(validatedFunds.get()); - - List peerReviewMinimizedSummaryList = peerReviewManagerReadOnly.getPeerReviewMinimizedSummaryList(orcid, true); - - AtomicInteger totalReviewsCount = new AtomicInteger(); - AtomicInteger selfAssertedPeerReviews = new AtomicInteger(); - - - if (peerReviewMinimizedSummaryList != null) { - peerReviewMinimizedSummaryList.forEach(peerReviewMinimizedSummary -> { - totalReviewsCount.set(totalReviewsCount.intValue() + peerReviewMinimizedSummary.getPutCodes().size()); - if(orcid.equals(peerReviewMinimizedSummary.getSourceId()) || orcid.equals(peerReviewMinimizedSummary.getAssertionOriginSourceId())) { - selfAssertedPeerReviews.getAndIncrement(); - } - }); - recordSummary.setSelfAssertedPeerReviews(selfAssertedPeerReviews.intValue()); - recordSummary.setPeerReviewsTotal(totalReviewsCount.intValue()); - recordSummary.setPeerReviewPublicationGrants(peerReviewMinimizedSummaryList.size()); - } else { - recordSummary.setPeerReviewsTotal(0); - recordSummary.setSelfAssertedPeerReviews(0); - recordSummary.setPeerReviewPublicationGrants(0); + return recordSummary; + } catch (OrcidNoResultException e) { + return recordSummary; } - ProfileEntity profileEntity = profileEntityManager.findByOrcid(orcid); - - recordSummary.setLastModified(formatDate(DateUtils.convertToXMLGregorianCalendar(profileEntity.getLastModified()))); - recordSummary.setCreation(formatDate(DateUtils.convertToXMLGregorianCalendar(profileEntity.getDateCreated()))); - - recordSummary.setOrcid(recordManagerReadOnly.getOrcidIdentifier(orcid).getUri()); - + // If not exceptions found, set the record as active and generate the summary + recordSummary = summaryManager.getRecordSummary(orcid); return recordSummary; } - + private String getDisplayName(Name name) { String displayName = null; if (name.getCreditName() != null && !PojoUtil.isEmpty(name.getCreditName().getContent())) { @@ -481,64 +258,7 @@ private String getDisplayName(Name name) { return displayName; } - private List retrieveProfessionalActivities(AffiliationGroupContainer groupedAffiliations, String orcid) { - List professionalActivities = new ArrayList<>(); - - List affiliationGroupForms = new ArrayList<>(); - - affiliationGroupForms.addAll(groupedAffiliations.getAffiliationGroups().get(AffiliationType.MEMBERSHIP)); - affiliationGroupForms.addAll(groupedAffiliations.getAffiliationGroups().get(AffiliationType.SERVICE)); - affiliationGroupForms.addAll(groupedAffiliations.getAffiliationGroups().get(AffiliationType.INVITED_POSITION)); - affiliationGroupForms.addAll(groupedAffiliations.getAffiliationGroups().get(AffiliationType.DISTINCTION)); - - sortAffiliationsByCreatedDate(affiliationGroupForms); - - affiliationGroupForms.forEach(e -> professionalActivities.add(AffiliationSummary.valueOf(e.getDefaultAffiliation(), orcid, e.getAffiliationType().value()))); - - return professionalActivities; - } - - private String formatDate(XMLGregorianCalendar xmlGregorianCalendar) { - SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); - GregorianCalendar gc = xmlGregorianCalendar.toGregorianCalendar(); - return sdf.format(gc.getTime()); - } - private Long getLastModifiedTime(String orcid) { return profileEntityManager.getLastModified(orcid); - } - - private void sortAffiliationsByCreatedDate(List affiliationGroupForms) { - List activePutCodesWithOutDate = new ArrayList<>(); - - affiliationGroupForms.forEach(affiliationGroupForm -> { - if ("distinction".equals(affiliationGroupForm.getDefaultAffiliation().getAffiliationType().getValue()) && - affiliationGroupForm.getDefaultAffiliation().getStartDate().getYear() != null - ) { - affiliationGroupForm.getDefaultAffiliation().setEndDate(affiliationGroupForm.getDefaultAffiliation().getStartDate()); - } - - if (affiliationGroupForm.getDefaultAffiliation().getEndDate().getYear() == null || - "".equals(affiliationGroupForm.getDefaultAffiliation().getEndDate().getYear())) { - activePutCodesWithOutDate.add(affiliationGroupForm.getActivePutCode()); - affiliationGroupForm.getDefaultAffiliation().setEndDate(Date.valueOf(new java.util.Date())); - } - }); - - affiliationGroupForms.sort(Comparator.comparing(a -> a.getDefaultAffiliation().getEndDate().toJavaDate())); - Collections.reverse(affiliationGroupForms); - - if (activePutCodesWithOutDate.size() > 0) { - Iterator i = activePutCodesWithOutDate.iterator(); - while (i.hasNext()) { - Long activePutCode = i.next(); - affiliationGroupForms.forEach(affiliationGroupForm -> { - if (activePutCode.equals(affiliationGroupForm.getActivePutCode())) { - affiliationGroupForm.getDefaultAffiliation().setEndDate(null); - i.remove(); - } - }); - } - } - } + } } diff --git a/orcid-web/src/main/java/org/orcid/frontend/web/pagination/Page.java b/orcid-web/src/main/java/org/orcid/frontend/web/pagination/Page.java index 7c4b4678cb0..1c4eba5223e 100644 --- a/orcid-web/src/main/java/org/orcid/frontend/web/pagination/Page.java +++ b/orcid-web/src/main/java/org/orcid/frontend/web/pagination/Page.java @@ -1,6 +1,7 @@ package org.orcid.frontend.web.pagination; import java.io.Serializable; +import java.util.ArrayList; import java.util.List; public class Page implements Serializable { @@ -21,6 +22,13 @@ public void setGroups(List workGroups) { this.groups = workGroups; } + public void addWorkGroup(T workGroup) { + if(groups == null) { + groups = new ArrayList(); + } + groups.add(workGroup); + } + public int getNextOffset() { return nextOffset; } diff --git a/orcid-web/src/main/java/org/orcid/frontend/web/pagination/WorksPaginator.java b/orcid-web/src/main/java/org/orcid/frontend/web/pagination/WorksPaginator.java index 9553e641f11..a0e2892bb94 100644 --- a/orcid-web/src/main/java/org/orcid/frontend/web/pagination/WorksPaginator.java +++ b/orcid-web/src/main/java/org/orcid/frontend/web/pagination/WorksPaginator.java @@ -2,7 +2,6 @@ import java.util.ArrayList; import java.util.Collections; -import java.util.Comparator; import java.util.Iterator; import java.util.List; import java.util.stream.Collectors; @@ -13,8 +12,13 @@ import org.orcid.core.manager.v3.WorksCacheManager; import org.orcid.core.manager.v3.WorksExtendedCacheManager; import org.orcid.core.manager.v3.read_only.WorkManagerReadOnly; +import org.orcid.core.utils.comparators.DateComparator; +import org.orcid.core.utils.comparators.DateComparatorWorkGroupExtended; +import org.orcid.core.utils.comparators.TitleComparator; +import org.orcid.core.utils.comparators.TitleComparatorWorkGroupExtended; +import org.orcid.core.utils.comparators.TypeComparator; +import org.orcid.core.utils.comparators.TypeComparatorWorkGroupExtended; import org.orcid.core.utils.v3.SourceUtils; -import org.orcid.jaxb.model.v3.release.common.PublicationDate; import org.orcid.jaxb.model.v3.release.common.Visibility; import org.orcid.jaxb.model.v3.release.record.summary.WorkSummary; import org.orcid.jaxb.model.v3.release.record.summary.Works; @@ -24,15 +28,12 @@ import org.orcid.pojo.grouping.WorkGroup; public class WorksPaginator { - - static final String TITLE_SORT_KEY = "title"; - - static final String DATE_SORT_KEY = "date"; + public static final String TITLE_SORT_KEY = "title"; - static final String TYPE_SORT_KEY = "type"; - - static final String SOURCE_SORT_KEY = "source"; + public static final String DATE_SORT_KEY = "date"; + public static final String TYPE_SORT_KEY = "type"; + @Resource(name = "workManagerReadOnlyV3") private WorkManagerReadOnly workManagerReadOnly; @@ -50,7 +51,7 @@ public Page getWorksPage(String orcid, int offset, int pageSize, bool if ("source".equals(sort)) { filteredGroups = sortBySource(filteredGroups, sortAsc, orcid); } else { - filteredGroups = sort(filteredGroups, sort, sortAsc, orcid); + filteredGroups = sort(filteredGroups, sort, sortAsc); } worksPage.setTotalGroups(filteredGroups.size()); @@ -74,7 +75,7 @@ public Page getWorksExtendedPage(String orcid, int offset, int pageSi if ("source".equals(sort)) { filteredGroups = sortBySourceExtended(filteredGroups, sortAsc, orcid); } else { - filteredGroups = sortExtended(filteredGroups, sort, sortAsc, orcid); + filteredGroups = sortExtended(filteredGroups, sort, sortAsc); } worksPage.setTotalGroups(filteredGroups.size()); @@ -92,7 +93,7 @@ public Page getWorksExtendedPage(String orcid, int offset, int pageSi public Page refreshWorks(String orcid, int limit, String sort, boolean sortAsc) { Works works = worksCacheManager.getGroupedWorks(orcid); - List sortedGroups = sort(works.getWorkGroup(), sort, sortAsc, orcid); + List sortedGroups = sort(works.getWorkGroup(), sort, sortAsc); Page worksPage = new Page(); worksPage.setTotalGroups(sortedGroups.size()); @@ -113,7 +114,7 @@ public Page getAllWorks(String orcid, boolean justPublic, String sort Page worksPage = new Page(); if (works != null) { List filteredGroups = filter(works, justPublic); - filteredGroups = sort(filteredGroups, sort, sortAsc, orcid); + filteredGroups = sort(filteredGroups, sort, sortAsc); worksPage.setTotalGroups(filteredGroups.size()); @@ -129,7 +130,66 @@ public Page getAllWorks(String orcid, boolean justPublic, String sort return worksPage; } - private List sort(List list, String sort, boolean sortAsc, String orcid) { + public void setWorksCacheManager(WorksCacheManager worksCacheManager) { + this.worksCacheManager = worksCacheManager; + } + + public void setWorksExtendedCacheManager(WorksExtendedCacheManager worksExtendedCacheManager) { + this.worksExtendedCacheManager = worksExtendedCacheManager; + } + + public List sortBySource(List workGroups, boolean sortAsc, String orcid) { + List selfAsserted = workGroups.stream() + .filter(work -> SourceUtils.isSelfAsserted(work.getWorkSummary().get(0).getSource(), orcid)) + .collect(Collectors.toList()); + + List validated = workGroups.stream() + .filter(work -> !SourceUtils.isSelfAsserted(work.getWorkSummary().get(0).getSource(), orcid)) + .collect(Collectors.toList()); + + selfAsserted.sort(new TitleComparator()); + validated.sort(new TitleComparator()); + + return (sortAsc ? Stream.concat(validated.stream(), selfAsserted.stream()) : Stream.concat(selfAsserted.stream(), validated.stream())) + .collect(Collectors.toList()); + } + + public List sortBySourceExtended(List workGroups, boolean sortAsc, String orcid) { + List selfAsserted = workGroups.stream() + .filter(work -> SourceUtils.isSelfAsserted(work.getWorkSummary().get(0).getSource(), orcid)) + .collect(Collectors.toList()); + + List validated = workGroups.stream() + .filter(work -> !SourceUtils.isSelfAsserted(work.getWorkSummary().get(0).getSource(), orcid)) + .collect(Collectors.toList()); + + selfAsserted.sort(new TitleComparatorWorkGroupExtended()); + validated.sort(new TitleComparatorWorkGroupExtended()); + + return (sortAsc ? Stream.concat(validated.stream(), selfAsserted.stream()) : Stream.concat(selfAsserted.stream(), validated.stream())) + .collect(Collectors.toList()); + } + + private List filter(Works works, boolean justPublic) { + List filteredGroups = new ArrayList<>(); + for (org.orcid.jaxb.model.v3.release.record.summary.WorkGroup workGroup : works.getWorkGroup()) { + + Iterator summariesIt = workGroup.getWorkSummary().iterator(); + while(summariesIt.hasNext()) { + WorkSummary w = summariesIt.next(); + if(justPublic && !Visibility.PUBLIC.equals(w.getVisibility())) { + summariesIt.remove(); + } + } + + if(!workGroup.getWorkSummary().isEmpty()) { + filteredGroups.add(workGroup); + } + } + return filteredGroups; + } + + private List sort(List list, String sort, boolean sortAsc) { if (TITLE_SORT_KEY.equals(sort)) { Collections.sort(list, new TitleComparator()); } else if (DATE_SORT_KEY.equals(sort)) { @@ -143,8 +203,8 @@ private List sort(List } return list; } - - private List sortExtended(List list, String sort, boolean sortAsc, String orcid) { + + private List sortExtended(List list, String sort, boolean sortAsc) { if (TITLE_SORT_KEY.equals(sort)) { Collections.sort(list, new TitleComparatorWorkGroupExtended()); } else if (DATE_SORT_KEY.equals(sort)) { @@ -158,26 +218,7 @@ private List sortExtended(List list, Strin } return list; } - - private List filter(Works works, boolean justPublic) { - List filteredGroups = new ArrayList<>(); - for (org.orcid.jaxb.model.v3.release.record.summary.WorkGroup workGroup : works.getWorkGroup()) { - - Iterator summariesIt = workGroup.getWorkSummary().iterator(); - while(summariesIt.hasNext()) { - WorkSummary w = summariesIt.next(); - if(justPublic && !Visibility.PUBLIC.equals(w.getVisibility())) { - summariesIt.remove(); - } - } - - if(!workGroup.getWorkSummary().isEmpty()) { - filteredGroups.add(workGroup); - } - } - return filteredGroups; - } - + private List filterWorksExtended(WorksExtended works, boolean justPublic) { List filteredGroups = new ArrayList<>(); for (WorkGroupExtended workGroup : works.getWorkGroup()) { @@ -196,303 +237,4 @@ private List filterWorksExtended(WorksExtended works, boolean } return filteredGroups; } - - public void setWorksCacheManager(WorksCacheManager worksCacheManager) { - this.worksCacheManager = worksCacheManager; - } - - public void setWorksExtendedCacheManager(WorksExtendedCacheManager worksExtendedCacheManager) { - this.worksExtendedCacheManager = worksExtendedCacheManager; - } - - private class DateComparator implements Comparator { - - @Override - public int compare(org.orcid.jaxb.model.v3.release.record.summary.WorkGroup o1, org.orcid.jaxb.model.v3.release.record.summary.WorkGroup o2) { - PublicationDate date1 = o1.getWorkSummary().get(0).getPublicationDate(); - PublicationDate date2 = o2.getWorkSummary().get(0).getPublicationDate(); - if (date1 == null && date2 == null) { - return new TitleComparator().compare(o1, o2) * -1; // reverse secondary order - } - - if (date1 == null) { - return -1; - } - - if (date2 == null) { - return 1; - } - - if (date1.compareTo(date2) == 0) { - return new TitleComparator().compare(o1, o2) * -1; // reverse secondary order - } - - return o1.getWorkSummary().get(0).getPublicationDate().compareTo(o2.getWorkSummary().get(0).getPublicationDate()); - } - } - - private class TitleComparator implements Comparator { - - @Override - public int compare(org.orcid.jaxb.model.v3.release.record.summary.WorkGroup o1, org.orcid.jaxb.model.v3.release.record.summary.WorkGroup o2) { - String firstTitle = getTitle(o1.getWorkSummary().get(0)); - String secondTitle = getTitle(o2.getWorkSummary().get(0)); - - if (firstTitle == null && secondTitle != null) { - return -1; - } - - if (secondTitle == null && firstTitle != null) { - return 1; - } - - int comparison = 0; - if (firstTitle != null && secondTitle != null) { - comparison = firstTitle.compareTo(secondTitle); - } - - if (comparison == 0) { - String firstSubtitle = getSubtitle(o1.getWorkSummary().get(0)); - String secondSubtitle = getSubtitle(o2.getWorkSummary().get(0)); - - if (firstSubtitle == null && secondSubtitle == null) { - return 0; - } - - if (firstSubtitle == null) { - return -1; - } - - if (secondSubtitle == null) { - return 1; - } - - comparison = firstSubtitle.compareTo(secondSubtitle); - } - return comparison; - } - - private String getTitle(WorkSummary workSummary) { - if (workSummary.getTitle() == null) { - return null; - } - - if (workSummary.getTitle().getTitle() == null) { - return null; - } - - if (workSummary.getTitle().getTitle().getContent() == null) { - return null; - } - - return workSummary.getTitle().getTitle().getContent().toLowerCase(); - } - - private String getSubtitle(WorkSummary workSummary) { - if (workSummary.getTitle() == null) { - return null; - } - - if (workSummary.getTitle().getSubtitle() == null) { - return null; - } - - if (workSummary.getTitle().getSubtitle().getContent() == null) { - return null; - } - - return workSummary.getTitle().getSubtitle().getContent().toLowerCase(); - } - } - - private class TypeComparator implements Comparator { - - @Override - public int compare(org.orcid.jaxb.model.v3.release.record.summary.WorkGroup o1, org.orcid.jaxb.model.v3.release.record.summary.WorkGroup o2) { - if (o1.getWorkSummary().get(0).getType() == null && o2.getWorkSummary().get(0).getType() == null) { - return 0; - } - - if (o1.getWorkSummary().get(0).getType() == null) { - return -1; - } - - if (o2.getWorkSummary().get(0).getType() == null) { - return 1; - } - - return o1.getWorkSummary().get(0).getType().name().compareTo(o2.getWorkSummary().get(0).getType().name()); - } - } - - private class SourceComparator implements Comparator { - - private String orcid; - - SourceComparator(String orcid) { - this.orcid = orcid; - } - - @Override - public int compare(org.orcid.jaxb.model.v3.release.record.summary.WorkGroup o1, org.orcid.jaxb.model.v3.release.record.summary.WorkGroup o2) { - return Boolean.compare(isSelfAsserted(o1.getWorkSummary().get(0)), isSelfAsserted(o2.getWorkSummary().get(0))); - } - - private boolean isSelfAsserted(WorkSummary workSummary) { - return SourceUtils.isSelfAsserted(workSummary.getSource(), orcid); - } - } - - private class DateComparatorWorkGroupExtended implements Comparator { - - @Override - public int compare(WorkGroupExtended o1, WorkGroupExtended o2) { - PublicationDate date1 = o1.getWorkSummary().get(0).getPublicationDate(); - PublicationDate date2 = o2.getWorkSummary().get(0).getPublicationDate(); - if (date1 == null && date2 == null) { - return new TitleComparatorWorkGroupExtended().compare(o1, o2) * -1; // reverse secondary order - } - - if (date1 == null) { - return -1; - } - - if (date2 == null) { - return 1; - } - - if (date1.compareTo(date2) == 0) { - return new TitleComparatorWorkGroupExtended().compare(o1, o2) * -1; // reverse secondary order - } - - return o1.getWorkSummary().get(0).getPublicationDate().compareTo(o2.getWorkSummary().get(0).getPublicationDate()); - } - } - - private class TitleComparatorWorkGroupExtended implements Comparator { - - @Override - public int compare(WorkGroupExtended o1, WorkGroupExtended o2) { - String firstTitle = getTitle(o1.getWorkSummary().get(0)); - String secondTitle = getTitle(o2.getWorkSummary().get(0)); - - if (firstTitle == null && secondTitle != null) { - return -1; - } - - if (secondTitle == null && firstTitle != null) { - return 1; - } - - int comparison = 0; - if (firstTitle != null && secondTitle != null) { - comparison = firstTitle.compareTo(secondTitle); - } - - if (comparison == 0) { - String firstSubtitle = getSubtitle(o1.getWorkSummary().get(0)); - String secondSubtitle = getSubtitle(o2.getWorkSummary().get(0)); - - if (firstSubtitle == null && secondSubtitle == null) { - return 0; - } - - if (firstSubtitle == null) { - return -1; - } - - if (secondSubtitle == null) { - return 1; - } - - comparison = firstSubtitle.compareTo(secondSubtitle); - } - return comparison; - } - - private String getTitle(WorkSummaryExtended workSummary) { - if (workSummary.getTitle() == null) { - return null; - } - - if (workSummary.getTitle().getTitle() == null) { - return null; - } - - if (workSummary.getTitle().getTitle().getContent() == null) { - return null; - } - - return workSummary.getTitle().getTitle().getContent().toLowerCase(); - } - - private String getSubtitle(WorkSummaryExtended workSummary) { - if (workSummary.getTitle() == null) { - return null; - } - - if (workSummary.getTitle().getSubtitle() == null) { - return null; - } - - if (workSummary.getTitle().getSubtitle().getContent() == null) { - return null; - } - - return workSummary.getTitle().getSubtitle().getContent().toLowerCase(); - } - } - - private class TypeComparatorWorkGroupExtended implements Comparator { - - @Override - public int compare(WorkGroupExtended o1, WorkGroupExtended o2) { - if (o1.getWorkSummary().get(0).getType() == null && o2.getWorkSummary().get(0).getType() == null) { - return 0; - } - - if (o1.getWorkSummary().get(0).getType() == null) { - return -1; - } - - if (o2.getWorkSummary().get(0).getType() == null) { - return 1; - } - - return o1.getWorkSummary().get(0).getType().name().compareTo(o2.getWorkSummary().get(0).getType().name()); - } - } - - public List sortBySource(List workGroups, boolean sortAsc, String orcid) { - List selfAsserted = workGroups.stream() - .filter(work -> SourceUtils.isSelfAsserted(work.getWorkSummary().get(0).getSource(), orcid)) - .collect(Collectors.toList()); - - List validated = workGroups.stream() - .filter(work -> !SourceUtils.isSelfAsserted(work.getWorkSummary().get(0).getSource(), orcid)) - .collect(Collectors.toList()); - - selfAsserted.sort(new TitleComparator()); - validated.sort(new TitleComparator()); - - return (sortAsc ? Stream.concat(validated.stream(), selfAsserted.stream()) : Stream.concat(selfAsserted.stream(), validated.stream())) - .collect(Collectors.toList()); - } - - public List sortBySourceExtended(List workGroups, boolean sortAsc, String orcid) { - List selfAsserted = workGroups.stream() - .filter(work -> SourceUtils.isSelfAsserted(work.getWorkSummary().get(0).getSource(), orcid)) - .collect(Collectors.toList()); - - List validated = workGroups.stream() - .filter(work -> !SourceUtils.isSelfAsserted(work.getWorkSummary().get(0).getSource(), orcid)) - .collect(Collectors.toList()); - - selfAsserted.sort(new TitleComparatorWorkGroupExtended()); - validated.sort(new TitleComparatorWorkGroupExtended()); - - return (sortAsc ? Stream.concat(validated.stream(), selfAsserted.stream()) : Stream.concat(selfAsserted.stream(), validated.stream())) - .collect(Collectors.toList()); - } - } diff --git a/orcid-web/src/test/java/org/orcid/frontend/web/controllers/PublicRecordControllerTest.java b/orcid-web/src/test/java/org/orcid/frontend/web/controllers/PublicRecordControllerLegacyTest.java similarity index 99% rename from orcid-web/src/test/java/org/orcid/frontend/web/controllers/PublicRecordControllerTest.java rename to orcid-web/src/test/java/org/orcid/frontend/web/controllers/PublicRecordControllerLegacyTest.java index f910d1a146a..bb1eeb66089 100644 --- a/orcid-web/src/test/java/org/orcid/frontend/web/controllers/PublicRecordControllerTest.java +++ b/orcid-web/src/test/java/org/orcid/frontend/web/controllers/PublicRecordControllerLegacyTest.java @@ -34,7 +34,8 @@ @RunWith(OrcidJUnit4ClassRunner.class) @WebAppConfiguration @ContextConfiguration(locations = { "classpath:test-frontend-web-servlet.xml" }) -public class PublicRecordControllerTest extends DBUnitTest { +@Deprecated(forRemoval = true) +public class PublicRecordControllerLegacyTest extends DBUnitTest { private static final List DATA_FILES = Arrays.asList("/data/SourceClientDetailsEntityData.xml", "/data/ProfileEntityData.xml", "/data/ClientDetailsEntityData.xml", "/data/BiographyEntityData.xml", "/data/OrgsEntityData.xml", diff --git a/orcid-web/src/test/java/org/orcid/frontend/web/pagination/WorksPaginatorTest.java b/orcid-web/src/test/java/org/orcid/frontend/web/pagination/WorksPaginatorTest.java index b9ca7dce213..c55ae11c079 100644 --- a/orcid-web/src/test/java/org/orcid/frontend/web/pagination/WorksPaginatorTest.java +++ b/orcid-web/src/test/java/org/orcid/frontend/web/pagination/WorksPaginatorTest.java @@ -6,9 +6,7 @@ import java.util.Arrays; import java.util.List; -import java.util.Random; import java.util.UUID; -import java.util.stream.Collectors; import org.junit.Before; import org.junit.Test; @@ -20,7 +18,6 @@ import org.orcid.core.manager.v3.WorksCacheManager; import org.orcid.core.manager.v3.WorksExtendedCacheManager; import org.orcid.core.manager.v3.read_only.WorkManagerReadOnly; -import org.orcid.core.utils.DateUtils; import org.orcid.jaxb.model.common.SequenceType; import org.orcid.jaxb.model.common.WorkType; import org.orcid.jaxb.model.v3.release.common.Contributor; @@ -50,6 +47,7 @@ import org.orcid.pojo.WorkSummaryExtended; import org.orcid.pojo.WorksExtended; import org.orcid.pojo.ajaxForm.WorkForm; +import org.orcid.utils.DateUtils; public class WorksPaginatorTest { @@ -164,26 +162,7 @@ public void testGetPublicWorksExtendedPage() { assertEquals(workForm.getVisibility().getVisibility(), Visibility.PUBLIC); } } - } - - @Test - public void testSourceSort() { - int pageSize = 50; - - Works works = getPublicWorkGroups(50); - List workGroups = works.getWorkGroup().stream().limit(2).collect(Collectors.toList()); - for (WorkGroup workGroup : workGroups) { - for (WorkSummary summary : workGroup.getWorkSummary()) { - summary.setSource(new Source("orcid")); - } - } - - Mockito.when(worksCacheManager.getGroupedWorks(Mockito.anyString())).thenReturn(works); - Page page = worksPaginator.getWorksPage("orcid", 0, pageSize, false, WorksPaginator.SOURCE_SORT_KEY, false); - - assertEquals("orcid", page.getGroups().get(0).getWorks().get(0).getSource()); - assertEquals("APP-5555-5555-5555-5555", page.getGroups().get(49).getWorks().get(0).getSource()); - } + } @Test public void testReverseSecondaryTitleSortForNullDates() { @@ -201,26 +180,7 @@ public void testReverseSecondaryTitleSortForNullDates() { assertTrue(previousTitle.toLowerCase().compareTo(nextTitle.toLowerCase()) >= 0); previous = next; } - } - - @Test - public void testTitleSortCase() { - int pageSize = 50; - - Works works = getPublicWorkGroups(50); - List workGroups = works.getWorkGroup().stream().limit(2).collect(Collectors.toList()); - for (WorkGroup workGroup : workGroups) { - for (WorkSummary summary : workGroup.getWorkSummary()) { - summary.setSource(new Source("orcid")); - } - } - - Mockito.when(worksCacheManager.getGroupedWorks(Mockito.anyString())).thenReturn(works); - Page page = worksPaginator.getWorksPage("orcid", 0, pageSize, false, WorksPaginator.SOURCE_SORT_KEY, false); - - assertEquals("orcid", page.getGroups().get(0).getWorks().get(0).getSource()); - assertEquals("APP-5555-5555-5555-5555", page.getGroups().get(49).getWorks().get(0).getSource()); - } + } @Test public void testGetAllWorks() { From 2960ce480fd96d969afe2369933517ffb6d6b16a Mon Sep 17 00:00:00 2001 From: github actions Date: Thu, 4 Apr 2024 20:06:01 +0000 Subject: [PATCH 2/2] v2.57.3 changelog update --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ac758ab27a2..3f5f2deb859 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## v2.57.3 - 2024-04-04 + +[Full Changelog](https://github.com/ORCID/ORCID-Source/compare/v2.57.2...v2.57.3) + ## v2.57.2 - 2024-04-04 [Full Changelog](https://github.com/ORCID/ORCID-Source/compare/v2.57.1...v2.57.2)