Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial commit #6911

Merged
merged 11 commits into from
Oct 20, 2023
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,17 @@

import java.util.List;

import org.orcid.core.common.manager.impl.EmailDomainManagerImpl.STATUS;
import org.orcid.persistence.jpa.entities.EmailDomainEntity;

public interface EmailDomainManager {
EmailDomainEntity createEmailDomain(String emailDomain, EmailDomainEntity.DomainCategory category);

boolean updateCategory(long id, EmailDomainEntity.DomainCategory category);

EmailDomainEntity findByEmailDoman(String emailDomain);

List<EmailDomainEntity> findByCategory(EmailDomainEntity.DomainCategory category);

STATUS createOrUpdateEmailDomain(String emailDomain, String rorId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,26 @@

public class EmailDomainManagerImpl implements EmailDomainManager {

public enum STATUS {CREATED, UPDATED};

@Resource(name = "emailDomainDao")
private EmailDomainDao emailDomainDao;

@Resource(name = "emailDomainDaoReadOnly")
private EmailDomainDao emailDomainDaoReadOnly;

@Override
public EmailDomainEntity createEmailDomain(String emailDomain, DomainCategory category) {
private void validateEmailDomain(String emailDomain) {
if (emailDomain == null || emailDomain.isBlank()) {
throw new IllegalArgumentException("Email Domain must not be empty");
}
if(!InternetDomainName.isValid(emailDomain)) {
throw new IllegalArgumentException("Email Domain '" + emailDomain + "' is invalid");
}
}

@Override
public EmailDomainEntity createEmailDomain(String emailDomain, DomainCategory category) {
validateEmailDomain(emailDomain);
if (category == null) {
throw new IllegalArgumentException("Category must not be empty");
}
Expand Down Expand Up @@ -57,4 +63,22 @@ public List<EmailDomainEntity> findByCategory(DomainCategory category) {
return emailDomainDaoReadOnly.findByCategory(category);
}

@Override
public STATUS createOrUpdateEmailDomain(String emailDomain, String rorId) {
EmailDomainEntity existingEntity = emailDomainDaoReadOnly.findByEmailDoman(emailDomain);
if(existingEntity != null) {
if(!rorId.equals(existingEntity.getRorId())) {
boolean updated = emailDomainDao.updateRorId(existingEntity.getId(), rorId);
if(updated)
return STATUS.UPDATED;
}
} else {
EmailDomainEntity newEntity = emailDomainDao.createEmailDomain(emailDomain, DomainCategory.PROFESSIONAL, rorId);
if (newEntity != null) {
return STATUS.CREATED;
}
}
return null;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public class OrcidSolrOrgsClient {

private static final String SOLR_SELF_SERVICE_ORGS_QUERY = "(org-disambiguated-id-from-source:%s)^50.0 (org-disambiguated-name%s)^50.0 (org-disambiguated-name-string:%s)^25.0";


private static final String SOLR_ORG_BY_ROR_ID_QUERY = "org-disambiguated-id-from-source:%s";

public OrgDisambiguatedSolrDocument findById(Long id) {
SolrQuery query = new SolrQuery();
Expand Down Expand Up @@ -93,4 +93,19 @@ public List<OrgDisambiguatedSolrDocument> getOrgsForSelfService(String searchTer
throw new NonTransientDataAccessResourceException(errorMessage, se);
}
}

public OrgDisambiguatedSolrDocument getOrgByRorId(String rorId) {
SolrQuery query = new SolrQuery();
// Escape the : on the email domain to be able to search in solr
query.setQuery(SOLR_ORG_BY_ROR_ID_QUERY.replace("%s", rorId.replace(":", "\\:")));
query.addOrUpdateSort("score", ORDER.desc);
try {
QueryResponse queryResponse = solrReadOnlyOrgsClient.query(query);
List<OrgDisambiguatedSolrDocument> result = queryResponse.getBeans(OrgDisambiguatedSolrDocument.class);
return (result == null || result.isEmpty()) ? null : result.get(0);
} catch (SolrServerException | IOException se) {
String errorMessage = MessageFormat.format("Error when attempting to search for orgs by ror id, with ror id {0}", new Object[] { rorId });
throw new NonTransientDataAccessResourceException(errorMessage, se);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
Expand All @@ -16,6 +20,7 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.orcid.core.common.manager.impl.EmailDomainManagerImpl;
import org.orcid.core.common.manager.impl.EmailDomainManagerImpl.STATUS;
import org.orcid.persistence.dao.EmailDomainDao;
import org.orcid.persistence.jpa.entities.EmailDomainEntity;
import org.orcid.persistence.jpa.entities.EmailDomainEntity.DomainCategory;
Expand All @@ -38,12 +43,17 @@ public void before() {

EmailDomainEntity e1 = new EmailDomainEntity("gmail.com", DomainCategory.PERSONAL);
EmailDomainEntity e2 = new EmailDomainEntity("yahoo.com", DomainCategory.PERSONAL);
EmailDomainEntity e3 = new EmailDomainEntity("orcid.org", DomainCategory.PROFESSIONAL);
EmailDomainEntity e3 = new EmailDomainEntity("orcid.org", DomainCategory.PROFESSIONAL, "https://ror.org/04fa4r544");
e3.setId(1000L);

when(emailDomainDaoReadOnlyMock.findByCategory(eq(DomainCategory.PERSONAL))).thenReturn(List.of(e1, e2));
when(emailDomainDaoReadOnlyMock.findByCategory(eq(DomainCategory.PROFESSIONAL))).thenReturn(List.of(e3));

when(emailDomainDaoReadOnlyMock.findByEmailDoman("gmail.com")).thenReturn(e1);
when(emailDomainDaoReadOnlyMock.findByEmailDoman("orcid.org")).thenReturn(e3);

when(emailDomainDaoMock.createEmailDomain(eq("new.domain"), eq(DomainCategory.PROFESSIONAL), eq("https://ror.org/0"))).thenReturn(new EmailDomainEntity("new.domain", DomainCategory.PROFESSIONAL, "https://ror.org/0"));
when(emailDomainDaoMock.updateRorId(1000L, "https://ror.org/0")).thenReturn(true);
}

@Test(expected = IllegalArgumentException.class)
Expand Down Expand Up @@ -135,4 +145,28 @@ public void findByCategory_TwoResultsTest() {
assertEquals(DomainCategory.PERSONAL, personal.get(1).getCategory());
assertEquals("yahoo.com", personal.get(1).getEmailDomain());
}

@Test
public void createOrUpdateEmailDomain_CreateTest() {
STATUS s = edm.createOrUpdateEmailDomain("new.domain", "https://ror.org/0");
assertEquals(STATUS.CREATED, s);
verify(emailDomainDaoMock, times(1)).createEmailDomain(eq("new.domain"), eq(DomainCategory.PROFESSIONAL), eq("https://ror.org/0"));
verify(emailDomainDaoMock, never()).updateRorId(anyLong(), anyString());
}

@Test
public void createOrUpdateEmailDomain_UpdateTest() {
STATUS s = edm.createOrUpdateEmailDomain("orcid.org", "https://ror.org/0");
assertEquals(STATUS.UPDATED, s);
verify(emailDomainDaoMock, times(1)).updateRorId(eq(1000L), eq("https://ror.org/0"));
verify(emailDomainDaoMock, never()).createEmailDomain(anyString(), any(), anyString());
}

@Test
public void createOrUpdateEmailDomain_NoUpdatesTest() {
STATUS s = edm.createOrUpdateEmailDomain("orcid.org", "https://ror.org/04fa4r544");
assertNull(s);
verify(emailDomainDaoMock, never()).updateRorId(anyLong(), anyString());
verify(emailDomainDaoMock, never()).createEmailDomain(anyString(), any(), anyString());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,12 @@

public interface EmailDomainDao extends GenericDao<EmailDomainEntity, Long> {
EmailDomainEntity createEmailDomain(String emailDomain, EmailDomainEntity.DomainCategory category);

EmailDomainEntity createEmailDomain(String emailDomain, EmailDomainEntity.DomainCategory category, String rorId);

boolean updateCategory(long id, EmailDomainEntity.DomainCategory category);

boolean updateRorId(long id, String rorId);

EmailDomainEntity findByEmailDoman(String emailDomain);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,18 @@ public EmailDomainEntity createEmailDomain(String emailDomain, DomainCategory ca
entityManager.persist(e);
return e;
}

@Override
@Transactional
public EmailDomainEntity createEmailDomain(String emailDomain, DomainCategory category, String rorId) {
LOG.debug("Creating domain {} with category {} and ror Id {}", emailDomain, category, rorId);
EmailDomainEntity e = new EmailDomainEntity();
e.setEmailDomain(emailDomain);
e.setCategory(category);
e.setRorId(rorId);
entityManager.persist(e);
return e;
}

@Override
@Transactional
Expand All @@ -42,6 +54,16 @@ public boolean updateCategory(long id, DomainCategory category) {
return query.executeUpdate() > 0;
}

@Override
@Transactional
public boolean updateRorId(long id, String rorId) {
LOG.debug("Updating domain with id {} with rorId {}", id, rorId);
Query query = entityManager.createNativeQuery("UPDATE email_domain SET ror_id=:rorId WHERE id = :id");
query.setParameter("id", id);
query.setParameter("rorId", rorId.toString());
return query.executeUpdate() > 0;
}

@Override
public EmailDomainEntity findByEmailDoman(String emailDomain) {
TypedQuery<EmailDomainEntity> query = entityManager.createQuery("from EmailDomainEntity where emailDomain = :emailDomain", EmailDomainEntity.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ public static enum DomainCategory {PERSONAL, PROFESSIONAL, UNDEFINED}
private Long id;
private String emailDomain;
private DomainCategory category;
private String rorId;

public EmailDomainEntity() {

Expand All @@ -38,6 +39,12 @@ public EmailDomainEntity(String emailDomain, DomainCategory category) {
this.category = category;
}

public EmailDomainEntity(String emailDomain, DomainCategory category, String rorId) {
this.emailDomain = emailDomain;
this.category = category;
this.rorId = rorId;
}

@Override
@Id
@GeneratedValue(strategy = GenerationType.AUTO, generator = "email_domain_seq")
Expand Down Expand Up @@ -70,9 +77,18 @@ public void setEmailDomain(String emailDomain) {
this.emailDomain = emailDomain;
}

@Column(name = "ror_id")
public String getRorId() {
return rorId;
}

public void setRorId(String rorId) {
this.rorId = rorId;
}

@Override
public int hashCode() {
return Objects.hash(category, emailDomain, id);
return Objects.hash(category, emailDomain, id, rorId);
}

@Override
Expand All @@ -84,6 +100,6 @@ public boolean equals(Object obj) {
if (getClass() != obj.getClass())
return false;
EmailDomainEntity other = (EmailDomainEntity) obj;
return category == other.category && Objects.equals(emailDomain, other.emailDomain) && Objects.equals(id, other.id);
}
return category == other.category && Objects.equals(emailDomain, other.emailDomain) && Objects.equals(id, other.id) && Objects.equals(rorId, other.rorId);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,53 +20,25 @@
<column name="category" type="VARCHAR(16)">
<constraints nullable="false" />
</column>
<column name="date_created" type="TIMESTAMP WITH TIME ZONE" />
<column name="last_modified" type="TIMESTAMP WITH TIME ZONE" />
</createTable>
</changeSet>

<changeSet author="Angel Montenegro" id="CREATE-EMAIL-DOMAIN-TO-ORG-ID-TABLE">
<preConditions onFail="MARK_RAN">
<not>
<tableExists tableName="email_domain_to_org_id" />
</not>
</preConditions>

<createTable tableName="email_domain_to_org_id">
<column name="id" type="bigint">
<constraints nullable="false" primaryKey="true"
primaryKeyName="email_domain_to_org_id_pkey" />
</column>
<column name="email_domian_id" type="bigint">
<constraints nullable="false" />
</column>
<column name="org_disambiguated_id" type="bigint">
<constraints nullable="false" />
<column name="ror_id" type="VARCHAR(30)">
<constraints nullable="true" />
</column>
<column name="date_created" type="TIMESTAMP WITH TIME ZONE" />
<column name="last_modified" type="TIMESTAMP WITH TIME ZONE" />
</createTable>

<sql>ALTER TABLE email_domain_to_org_id ADD CONSTRAINT email_domain_fk FOREIGN KEY (email_domian_id) REFERENCES email_domain (id);</sql>
<sql>ALTER TABLE email_domain_to_org_id ADD CONSTRAINT org_disambiguated_id_fk FOREIGN KEY (org_disambiguated_id) REFERENCES org_disambiguated (id);</sql>
<sql>create index email_domain_to_org_id_domain_index on email_domain_to_org_id(email_domian_id);</sql>
<sql>create index email_domain_to_org_id_org_index on email_domain_to_org_id(org_disambiguated_id);</sql>
</changeSet>

<changeSet id="CREATE-SEQUENCES" author="Angel Montenegro" dbms="postgresql">
<preConditions onFail="MARK_RAN">
<not>
<sequenceExists sequenceName="email_domain_seq"/>
<sequenceExists sequenceName="email_domain_to_org_id_seq"/>
</not>
</preConditions>
<createSequence sequenceName="email_domain_seq" startValue="1000" />
<createSequence sequenceName="email_domain_to_org_id_seq" startValue="1000" />
</changeSet>

<changeSet id="CREATE-AUTOCOLS" author="Angel Montenegro" dbms="hsqldb">
<addAutoIncrement tableName="email_domain" columnName="id" columnDataType="bigint"/>
<addAutoIncrement tableName="email_domain_to_org_id" columnName="id" columnDataType="bigint"/>
</changeSet>

<changeSet id="EMAIL-DOMAIN-INDEX" author="Angel Montenegro" dbms="postgresql">
Expand All @@ -76,11 +48,11 @@
</not>
</preConditions>
<sql>create index email_domain_domain_index on email_domain(email_domain);</sql>
<sql>create index email_domain_ror_id_index on email_domain(ror_id);</sql>
</changeSet>

<changeSet id="GRANT-READ-PERMISSIONS-TO-ORCIDRO" author="Angel Montenegro" dbms="postgresql">
<sql>GRANT SELECT ON email_domain to orcidro;</sql>
<sql>GRANT SELECT ON email_domain_to_org_id to orcidro;</sql>
<sql>GRANT SELECT ON email_domain to orcidro;</sql>
</changeSet>

</databaseChangeLog>
Original file line number Diff line number Diff line change
Expand Up @@ -97,9 +97,11 @@ private void process() {
total += 1;
}
}
LOG.warn("List of invalid domains:");
for(String invalidDomain : invalidDomains) {
LOG.warn(invalidDomain);
if(!invalidDomains.isEmpty()) {
LOG.warn("List of invalid domains:");
for(String invalidDomain : invalidDomains) {
LOG.info(invalidDomain);
}
}
LOG.info("Process done, total: {}, new entities: {}, updated entities: {}", total, newEntities, updatedEntities);
}
Expand Down
Loading