diff --git a/apps/dnet-orgs-database-application/src/main/java/eu/dnetlib/organizations/controller/AdminController.java b/apps/dnet-orgs-database-application/src/main/java/eu/dnetlib/organizations/controller/AdminController.java
index 0e835d19..943ceadf 100644
--- a/apps/dnet-orgs-database-application/src/main/java/eu/dnetlib/organizations/controller/AdminController.java
+++ b/apps/dnet-orgs-database-application/src/main/java/eu/dnetlib/organizations/controller/AdminController.java
@@ -22,6 +22,7 @@ import eu.dnetlib.organizations.importer.ImportExecution;
import eu.dnetlib.organizations.importer.ImportExecutor;
import eu.dnetlib.organizations.model.SystemConfiguration;
import eu.dnetlib.organizations.model.utils.VocabularyTerm;
+import eu.dnetlib.organizations.model.view.PersistentOrganizationView;
import eu.dnetlib.organizations.model.view.UserView;
import eu.dnetlib.organizations.repository.SystemConfigurationRepository;
import eu.dnetlib.organizations.repository.UserRepository;
@@ -202,4 +203,22 @@ public class AdminController extends AbstractDnetController {
throw new RuntimeException("User not authorized");
}
}
+
+ @GetMapping("/api/persistentOrgs")
+ public Iterable listPersistentOrgs() {
+ return dbUtils.listPersistentOrgs();
+ }
+
+ @PostMapping("/api/persistentOrgs")
+ public Iterable addPersistentOrgs(@RequestBody final List ids) {
+ ids.forEach(id -> dbUtils.addPersistentOrgs(id));
+ return dbUtils.listPersistentOrgs();
+ }
+
+ @DeleteMapping("/api/persistentOrgs")
+ public Iterable deletePersistentOrgs(@RequestParam final String id) {
+ dbUtils.deletePersistentOrgs(id);
+ return dbUtils.listPersistentOrgs();
+ }
+
}
diff --git a/apps/dnet-orgs-database-application/src/main/java/eu/dnetlib/organizations/controller/HomeController.java b/apps/dnet-orgs-database-application/src/main/java/eu/dnetlib/organizations/controller/HomeController.java
index db337ffd..7d76fb8d 100644
--- a/apps/dnet-orgs-database-application/src/main/java/eu/dnetlib/organizations/controller/HomeController.java
+++ b/apps/dnet-orgs-database-application/src/main/java/eu/dnetlib/organizations/controller/HomeController.java
@@ -11,6 +11,7 @@ import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
+import org.springframework.web.bind.annotation.PathVariable;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
@@ -30,6 +31,9 @@ public class HomeController extends AbstractDnetController {
@Autowired
private SystemConfigurationRepository systemConfigurationRepository;
+ @Value("${openaire.explore.organization.baseurl}")
+ private String openaireBaseUrl;
+
@Value("${openorgs.support.pages}")
private String supportPagesJson;
@@ -40,6 +44,11 @@ public class HomeController extends AbstractDnetController {
return env.acceptsProfiles(Profiles.of("dev")) ? "redirect:main" : "home";
}
+ @GetMapping("/redirect/oa/{orgId}")
+ public String openaireUrl(@PathVariable final String orgId) {
+ return "redirect:" + String.format(openaireBaseUrl, orgId);
+ }
+
@GetMapping("/main")
public String main() {
return "main";
diff --git a/apps/dnet-orgs-database-application/src/main/java/eu/dnetlib/organizations/controller/OrganizationController.java b/apps/dnet-orgs-database-application/src/main/java/eu/dnetlib/organizations/controller/OrganizationController.java
index 9ecd3cca..eb706c5f 100644
--- a/apps/dnet-orgs-database-application/src/main/java/eu/dnetlib/organizations/controller/OrganizationController.java
+++ b/apps/dnet-orgs-database-application/src/main/java/eu/dnetlib/organizations/controller/OrganizationController.java
@@ -17,7 +17,6 @@ import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.security.core.Authentication;
@@ -83,8 +82,6 @@ public class OrganizationController extends AbstractDnetController {
private JournalEntryRepository journalEntryRepository;
@Autowired
private DatabaseUtils databaseUtils;
- @Value("${openaire.explore.organization.baseurl}")
- private String oaBaseUrl;
@PostMapping("/save")
public List save(@RequestBody final OrganizationView org, final Authentication authentication) {
@@ -107,9 +104,7 @@ public class OrganizationController extends AbstractDnetController {
@GetMapping("/info")
public OrganizationInfoView infoById(@RequestParam final String id, final Authentication authentication) {
- final OrganizationInfoView info = organizationInfoViewRepository.findById(id).get();
- info.fillGraphNodeInfo(info.getId(), oaBaseUrl);
- return info;
+ return organizationInfoViewRepository.findById(id).get();
}
@GetMapping("/suggestionsInfo")
@@ -160,9 +155,7 @@ public class OrganizationController extends AbstractDnetController {
}
private List listDuplicates(final String id) {
- final List list = openaireDuplicateViewRepository.findByLocalId(id);
- list.forEach(d -> d.fillGraphNodeInfo(d.getOaOriginalId(), oaBaseUrl));
- return list;
+ return openaireDuplicateViewRepository.findByLocalId(id);
}
@GetMapping("/conflicts/byCountry/{country}")
diff --git a/apps/dnet-orgs-database-application/src/main/java/eu/dnetlib/organizations/model/PersistentOrganization.java b/apps/dnet-orgs-database-application/src/main/java/eu/dnetlib/organizations/model/PersistentOrganization.java
new file mode 100644
index 00000000..b01ea8a1
--- /dev/null
+++ b/apps/dnet-orgs-database-application/src/main/java/eu/dnetlib/organizations/model/PersistentOrganization.java
@@ -0,0 +1,34 @@
+package eu.dnetlib.organizations.model;
+
+import java.io.Serializable;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Table;
+
+@Entity
+@Table(name = "persistent_orgs")
+public class PersistentOrganization implements Serializable {
+
+ private static final long serialVersionUID = 7684478315366015099L;
+
+ @Id
+ @Column(name = "id")
+ private String id;
+
+ public PersistentOrganization() {}
+
+ public PersistentOrganization(final String id) {
+ this.id = id;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(final String id) {
+ this.id = id;
+ }
+
+}
diff --git a/apps/dnet-orgs-database-application/src/main/java/eu/dnetlib/organizations/model/utils/OpenaireGraphNode.java b/apps/dnet-orgs-database-application/src/main/java/eu/dnetlib/organizations/model/utils/OpenaireGraphNode.java
index 6867942b..1b34ab01 100644
--- a/apps/dnet-orgs-database-application/src/main/java/eu/dnetlib/organizations/model/utils/OpenaireGraphNode.java
+++ b/apps/dnet-orgs-database-application/src/main/java/eu/dnetlib/organizations/model/utils/OpenaireGraphNode.java
@@ -1,23 +1,31 @@
package eu.dnetlib.organizations.model.utils;
-import org.apache.commons.codec.digest.DigestUtils;
-import org.apache.commons.lang3.StringUtils;
+import javax.persistence.Column;
+import javax.persistence.MappedSuperclass;
-public interface OpenaireGraphNode {
+@MappedSuperclass
+public abstract class OpenaireGraphNode {
- String getOaGraphId();
+ @Column(name = "openaire_id")
+ private String openaireId;
- void setOaGraphId(String oaGraphId);
+ @Column(name = "openaire_persistent")
+ private Boolean persistent = false;
- String getOaGraphUrl();
+ public String getOpenaireId() {
+ return openaireId;
+ }
- void setOaGraphUrl(String oaGraphUrl);
+ public void setOpenaireId(final String openaireId) {
+ this.openaireId = openaireId;
+ }
- default void fillGraphNodeInfo(final String origId, final String baseUrl) {
- final String oaGraphId = StringUtils.substringBefore(origId, "::") + "::"
- + DigestUtils.md5Hex(StringUtils.substringAfter(origId, "::"));
- setOaGraphId(oaGraphId);
- setOaGraphUrl(baseUrl + oaGraphId);
+ public Boolean getPersistent() {
+ return persistent;
+ }
+
+ public void setPersistent(final Boolean persistent) {
+ this.persistent = persistent;
}
}
diff --git a/apps/dnet-orgs-database-application/src/main/java/eu/dnetlib/organizations/model/view/OpenaireDuplicateView.java b/apps/dnet-orgs-database-application/src/main/java/eu/dnetlib/organizations/model/view/OpenaireDuplicateView.java
index 2a02ed35..9cfba1a3 100644
--- a/apps/dnet-orgs-database-application/src/main/java/eu/dnetlib/organizations/model/view/OpenaireDuplicateView.java
+++ b/apps/dnet-orgs-database-application/src/main/java/eu/dnetlib/organizations/model/view/OpenaireDuplicateView.java
@@ -8,7 +8,6 @@ import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.IdClass;
import javax.persistence.Table;
-import javax.persistence.Transient;
import org.hibernate.annotations.Type;
@@ -18,7 +17,7 @@ import eu.dnetlib.organizations.model.utils.OpenaireGraphNode;
@Entity
@Table(name = "oa_duplicates_view")
@IdClass(OpenaireDuplicatePK.class)
-public class OpenaireDuplicateView implements Serializable, OpenaireGraphNode {
+public class OpenaireDuplicateView extends OpenaireGraphNode implements Serializable {
/**
*
@@ -88,12 +87,6 @@ public class OpenaireDuplicateView implements Serializable, OpenaireGraphNode {
@Column(name = "ec_nutscode")
private Boolean ecNutscode;
- @Transient
- private String oaGraphId;
-
- @Transient
- private String oaGraphUrl;
-
public String getLocalId() {
return localId;
}
@@ -254,24 +247,4 @@ public class OpenaireDuplicateView implements Serializable, OpenaireGraphNode {
this.ecNutscode = ecNutscode;
}
- @Override
- public String getOaGraphId() {
- return oaGraphId;
- }
-
- @Override
- public void setOaGraphId(final String oaGraphId) {
- this.oaGraphId = oaGraphId;
- }
-
- @Override
- public String getOaGraphUrl() {
- return oaGraphUrl;
- }
-
- @Override
- public void setOaGraphUrl(final String oaGraphUrl) {
- this.oaGraphUrl = oaGraphUrl;
- }
-
}
diff --git a/apps/dnet-orgs-database-application/src/main/java/eu/dnetlib/organizations/model/view/OrganizationInfoView.java b/apps/dnet-orgs-database-application/src/main/java/eu/dnetlib/organizations/model/view/OrganizationInfoView.java
index 7109d8a1..3ca41df6 100644
--- a/apps/dnet-orgs-database-application/src/main/java/eu/dnetlib/organizations/model/view/OrganizationInfoView.java
+++ b/apps/dnet-orgs-database-application/src/main/java/eu/dnetlib/organizations/model/view/OrganizationInfoView.java
@@ -7,13 +7,12 @@ import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
-import javax.persistence.Transient;
import eu.dnetlib.organizations.model.utils.OpenaireGraphNode;
@Entity
@Table(name = "organizations_info_view")
-public class OrganizationInfoView implements Serializable, OpenaireGraphNode {
+public class OrganizationInfoView extends OpenaireGraphNode implements Serializable {
/**
*
@@ -48,12 +47,6 @@ public class OrganizationInfoView implements Serializable, OpenaireGraphNode {
@Column(name = "note")
private boolean note;
- @Transient
- private String oaGraphId;
-
- @Transient
- private String oaGraphUrl;
-
public String getId() {
return id;
}
@@ -126,24 +119,4 @@ public class OrganizationInfoView implements Serializable, OpenaireGraphNode {
this.note = note;
}
- @Override
- public String getOaGraphId() {
- return oaGraphId;
- }
-
- @Override
- public void setOaGraphId(final String oaGraphId) {
- this.oaGraphId = oaGraphId;
- }
-
- @Override
- public String getOaGraphUrl() {
- return oaGraphUrl;
- }
-
- @Override
- public void setOaGraphUrl(final String oaGraphUrl) {
- this.oaGraphUrl = oaGraphUrl;
- }
-
}
diff --git a/apps/dnet-orgs-database-application/src/main/java/eu/dnetlib/organizations/model/view/OrganizationView.java b/apps/dnet-orgs-database-application/src/main/java/eu/dnetlib/organizations/model/view/OrganizationView.java
index 06d92519..cdf41c94 100644
--- a/apps/dnet-orgs-database-application/src/main/java/eu/dnetlib/organizations/model/view/OrganizationView.java
+++ b/apps/dnet-orgs-database-application/src/main/java/eu/dnetlib/organizations/model/view/OrganizationView.java
@@ -15,13 +15,15 @@ import org.hibernate.annotations.TypeDefs;
import com.vladmihalcea.hibernate.type.json.JsonBinaryType;
import com.vladmihalcea.hibernate.type.json.JsonStringType;
+import eu.dnetlib.organizations.model.utils.OpenaireGraphNode;
+
@Entity
@Table(name = "organizations_view")
@TypeDefs({
@TypeDef(name = "json", typeClass = JsonStringType.class),
@TypeDef(name = "jsonb", typeClass = JsonBinaryType.class)
})
-public class OrganizationView implements Serializable {
+public class OrganizationView extends OpenaireGraphNode implements Serializable {
/**
*
diff --git a/apps/dnet-orgs-database-application/src/main/java/eu/dnetlib/organizations/model/view/PersistentOrganizationView.java b/apps/dnet-orgs-database-application/src/main/java/eu/dnetlib/organizations/model/view/PersistentOrganizationView.java
new file mode 100644
index 00000000..872fa06a
--- /dev/null
+++ b/apps/dnet-orgs-database-application/src/main/java/eu/dnetlib/organizations/model/view/PersistentOrganizationView.java
@@ -0,0 +1,63 @@
+package eu.dnetlib.organizations.model.view;
+
+import java.io.Serializable;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Table;
+
+import eu.dnetlib.organizations.model.utils.OpenaireGraphNode;
+
+@Entity
+@Table(name = "persistent_orgs_view")
+public class PersistentOrganizationView extends OpenaireGraphNode implements Serializable {
+
+ private static final long serialVersionUID = -8906936709574708538L;
+
+ @Id
+ @Column(name = "id")
+ private String id;
+
+ @Column(name = "name")
+ private String name;
+
+ @Column(name = "city")
+ private String city;
+
+ @Column(name = "country")
+ private String country;
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(final String id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(final String name) {
+ this.name = name;
+ }
+
+ public String getCity() {
+ return city;
+ }
+
+ public void setCity(final String city) {
+ this.city = city;
+ }
+
+ public String getCountry() {
+ return country;
+ }
+
+ public void setCountry(final String country) {
+ this.country = country;
+ }
+
+}
diff --git a/apps/dnet-orgs-database-application/src/main/java/eu/dnetlib/organizations/repository/OrganizationRepository.java b/apps/dnet-orgs-database-application/src/main/java/eu/dnetlib/organizations/repository/OrganizationRepository.java
index 6071b0d4..30301239 100644
--- a/apps/dnet-orgs-database-application/src/main/java/eu/dnetlib/organizations/repository/OrganizationRepository.java
+++ b/apps/dnet-orgs-database-application/src/main/java/eu/dnetlib/organizations/repository/OrganizationRepository.java
@@ -22,9 +22,10 @@ public interface OrganizationRepository extends JpaRepository {
+
+}
diff --git a/apps/dnet-orgs-database-application/src/main/java/eu/dnetlib/organizations/repository/readonly/PersistentOrganizationViewRepository.java b/apps/dnet-orgs-database-application/src/main/java/eu/dnetlib/organizations/repository/readonly/PersistentOrganizationViewRepository.java
new file mode 100644
index 00000000..c53dd904
--- /dev/null
+++ b/apps/dnet-orgs-database-application/src/main/java/eu/dnetlib/organizations/repository/readonly/PersistentOrganizationViewRepository.java
@@ -0,0 +1,10 @@
+package eu.dnetlib.organizations.repository.readonly;
+
+import org.springframework.stereotype.Repository;
+
+import eu.dnetlib.organizations.model.view.PersistentOrganizationView;
+
+@Repository
+public interface PersistentOrganizationViewRepository extends ReadOnlyRepository {
+
+}
diff --git a/apps/dnet-orgs-database-application/src/main/java/eu/dnetlib/organizations/utils/DatabaseUtils.java b/apps/dnet-orgs-database-application/src/main/java/eu/dnetlib/organizations/utils/DatabaseUtils.java
index 4e9c3c07..6b62494c 100644
--- a/apps/dnet-orgs-database-application/src/main/java/eu/dnetlib/organizations/utils/DatabaseUtils.java
+++ b/apps/dnet-orgs-database-application/src/main/java/eu/dnetlib/organizations/utils/DatabaseUtils.java
@@ -12,10 +12,12 @@ import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import java.util.function.Function;
+import java.util.function.Predicate;
import java.util.stream.Collectors;
import javax.transaction.Transactional;
+import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
@@ -37,6 +39,7 @@ import eu.dnetlib.organizations.model.OpenaireDuplicate;
import eu.dnetlib.organizations.model.Organization;
import eu.dnetlib.organizations.model.OtherIdentifier;
import eu.dnetlib.organizations.model.OtherName;
+import eu.dnetlib.organizations.model.PersistentOrganization;
import eu.dnetlib.organizations.model.Relationship;
import eu.dnetlib.organizations.model.Url;
import eu.dnetlib.organizations.model.User;
@@ -46,6 +49,7 @@ import eu.dnetlib.organizations.model.utils.OrganizationConflict;
import eu.dnetlib.organizations.model.utils.TempBrowseEntry;
import eu.dnetlib.organizations.model.utils.VocabularyTerm;
import eu.dnetlib.organizations.model.view.OrganizationView;
+import eu.dnetlib.organizations.model.view.PersistentOrganizationView;
import eu.dnetlib.organizations.model.view.UserView;
import eu.dnetlib.organizations.repository.AcronymRepository;
import eu.dnetlib.organizations.repository.JournalEntryRepository;
@@ -54,11 +58,13 @@ import eu.dnetlib.organizations.repository.OpenaireDuplicateRepository;
import eu.dnetlib.organizations.repository.OrganizationRepository;
import eu.dnetlib.organizations.repository.OtherIdentifierRepository;
import eu.dnetlib.organizations.repository.OtherNameRepository;
+import eu.dnetlib.organizations.repository.PersistentOrganizationRepository;
import eu.dnetlib.organizations.repository.RelationshipRepository;
import eu.dnetlib.organizations.repository.UrlRepository;
import eu.dnetlib.organizations.repository.UserCountryRepository;
import eu.dnetlib.organizations.repository.UserRepository;
import eu.dnetlib.organizations.repository.readonly.OrganizationViewRepository;
+import eu.dnetlib.organizations.repository.readonly.PersistentOrganizationViewRepository;
@Component
public class DatabaseUtils {
@@ -87,6 +93,10 @@ public class DatabaseUtils {
private OrganizationViewRepository organizationViewRepository;
@Autowired
private JournalEntryRepository journalEntryRepository;
+ @Autowired
+ private PersistentOrganizationRepository persistentOrganizationRepository;
+ @Autowired
+ private PersistentOrganizationViewRepository persistentOrganizationViewRepository;
@Autowired
private JdbcTemplate jdbcTemplate;
@@ -129,7 +139,7 @@ public class DatabaseUtils {
final String pendingId = OpenOrgsConstants.OPENORGS_PENDING_PREFIX + UUID.randomUUID();
orgView.setId(pendingId);
// to override the generation strategy of the ID
- organizationRepository.preparePendingOrg(pendingId);
+ organizationRepository.prepareOrgWithId(pendingId);
} else {
orgView.setId(null); // The ID is generated by the DB
}
@@ -468,45 +478,97 @@ public class DatabaseUtils {
@Transactional
public String fixConflictSimilars(final List similarIds, final String user) {
- final OffsetDateTime now = OffsetDateTime.now();
-
final List views =
similarIds.stream().map(organizationViewRepository::findById).filter(Optional::isPresent).map(Optional::get).collect(Collectors.toList());
- // I create a new org
- final OrganizationView newOrg = new OrganizationView();
- newOrg.setId(null);
- newOrg.setStatus(null);
- newOrg.setName(findFirstString(views, OrganizationView::getName));
- newOrg.setType(findFirstString(views, OrganizationView::getType));
- newOrg.setLat(findFirstNumber(views, OrganizationView::getLat));
- newOrg.setLng(findFirstNumber(views, OrganizationView::getLng));
- newOrg.setCity(findFirstString(views, OrganizationView::getCity));
- newOrg.setCountry(findFirstString(views, OrganizationView::getCountry));
- newOrg.setOtherIdentifiers(findAll(views, OrganizationView::getOtherIdentifiers));
- newOrg.setOtherNames(findAll(views, OrganizationView::getOtherNames));
- newOrg.setAcronyms(findAll(views, OrganizationView::getAcronyms));
- newOrg.setUrls(findAll(views, OrganizationView::getUrls));
- newOrg.setRelations(findAll(views, OrganizationView::getRelations));
+ final List persistents = views.stream().filter(v -> v.getPersistent()).collect(Collectors.toList());
- newOrg.getOtherNames()
- .addAll(views.stream()
+ final OrganizationView masterOrg = new OrganizationView();
+
+ if (persistents.size() > 1) {
+ throw new RuntimeException("Too many persintent organizations");
+ } else if (persistents.size() == 1) {
+ backupOrg(persistents.get(0), user);
+ masterOrg.setId(persistents.get(0).getId());
+ masterOrg.setStatus(OrganizationStatus.approved.toString());
+ } else {
+ masterOrg.setId(null);
+ masterOrg.setStatus(null);
+ }
+ return fixConflicts(masterOrg, views, user);
+ }
+
+ private String backupOrg(final OrganizationView org, final String user) {
+ final String origId = org.getId();
+ final String backupId = origId + "::" + OffsetDateTime.now().toEpochSecond();
+
+ organizationRepository.prepareOrgWithId(backupId);
+ try {
+
+ final OrganizationView backupOrg = (OrganizationView) BeanUtils.cloneBean(org);
+ backupOrg.setId(backupId);
+
+ insertOrUpdateOrganization(backupOrg, user, false);
+
+ organizationRepository.updateStatus(backupId, OrganizationStatus.hidden.toString());
+
+ journalEntryRepository
+ .save(new JournalEntry(origId, JournalOperations.BACKUP_ORG, "Saved a backup copy: " + backupId, user));
+ journalEntryRepository
+ .save(new JournalEntry(backupId, JournalOperations.BACKUP_ORG, "Saved a backup copy of " + origId, user));
+
+ return backupId;
+ } catch (final Exception e) {
+ log.error("Error performing the backup of " + origId, e);
+ throw new RuntimeException("Error performing the backup of " + origId, e);
+ }
+ }
+
+ private String fixConflicts(final OrganizationView masterOrg, final List orgs, final String user) {
+
+ final OffsetDateTime now = OffsetDateTime.now();
+
+ final String finalMessage = (masterOrg.getId() == null ? "New org created merging: " : "Merging in persistent org: ") +
+ orgs.stream()
+ .map(OrganizationView::getId)
+ .collect(Collectors.joining(", "));
+
+ masterOrg.setName(findFirstString(orgs, OrganizationView::getName));
+ masterOrg.setType(findFirstString(orgs, OrganizationView::getType));
+ masterOrg.setLat(findFirstNumber(orgs, OrganizationView::getLat));
+ masterOrg.setLng(findFirstNumber(orgs, OrganizationView::getLng));
+ masterOrg.setCity(findFirstString(orgs, OrganizationView::getCity));
+ masterOrg.setCountry(findFirstString(orgs, OrganizationView::getCountry));
+ masterOrg.setOtherIdentifiers(findAll(orgs, OrganizationView::getOtherIdentifiers));
+ masterOrg.setOtherNames(findAll(orgs, OrganizationView::getOtherNames));
+ masterOrg.setAcronyms(findAll(orgs, OrganizationView::getAcronyms));
+ masterOrg.setUrls(findAll(orgs, OrganizationView::getUrls));
+ masterOrg.setRelations(findAll(orgs, OrganizationView::getRelations, r -> !r.getType().equals(RelationType.Merged_In.toString())
+ && !r.getType().equals(RelationType.Merged_In.toString())));
+
+ masterOrg.getOtherNames()
+ .addAll(orgs.stream()
.map(OrganizationView::getName)
.filter(StringUtils::isNotBlank)
- .filter(s -> StringUtils.equalsIgnoreCase(s, newOrg.getName()))
+ .filter(s -> StringUtils.equalsIgnoreCase(s, masterOrg.getName()))
.map(s -> new eu.dnetlib.organizations.model.view.OtherName(s, "UNKNOWN"))
.collect(Collectors.toList()));
- final String masterId = insertOrUpdateOrganization(newOrg, user, false);
+ final String masterId = insertOrUpdateOrganization(masterOrg, user, false);
// I hide the merged organizations
- similarIds.forEach(id -> {
- hideConflictOrgs(masterId, id);
- journalEntryRepository.save(new JournalEntry(masterId, JournalOperations.FIX_CONFLICT, "The org has been hidded and merged in " + masterId, user));
- });
+ orgs.stream()
+ .map(OrganizationView::getId)
+ .filter(id -> !id.equals(masterId))
+ .forEach(id -> {
+ hideConflictOrgs(masterId, id);
+ journalEntryRepository
+ .save(new JournalEntry(id, JournalOperations.FIX_CONFLICT, "The org has been hidded and merged in " + masterId, user));
+ });
// I reassign the duplicates to the new org
- final List newDuplicates = similarIds.stream()
+ final List newDuplicates = orgs.stream()
+ .map(OrganizationView::getId)
.map(openaireDuplicateRepository::findByLocalId)
.flatMap(l -> l.stream())
.map(d -> new OpenaireDuplicate(masterId, d.getOaOriginalId(), d.getRelType(), d.getOaCollectedFrom()))
@@ -518,18 +580,20 @@ public class DatabaseUtils {
openaireDuplicateRepository.updateModificationDate(d.getLocalId(), d.getOaOriginalId(), user, now);
});
- for (final String similarId : similarIds) {
+ orgs.forEach(org -> {
+ final String similarId = org.getId();
openaireConflictRepository.updateMultipleStatusAndResetGroup(similarId, SimilarityType.is_different.toString(), user, now);
- }
+ });
- for (int i = 0; i < similarIds.size(); i++) {
- for (int j = i + 1; j < similarIds.size(); j++) {
- openaireConflictRepository.updateStatusAndResetGroup(similarIds.get(i), similarIds.get(j), SimilarityType.is_similar.toString(), user, now);
+ for (int i = 0; i < orgs.size(); i++) {
+ for (int j = i + 1; j < orgs.size(); j++) {
+ openaireConflictRepository
+ .updateStatusAndResetGroup(orgs.get(i).getId(), orgs.get(j).getId(), SimilarityType.is_similar.toString(), user, now);
}
}
journalEntryRepository
- .save(new JournalEntry(masterId, JournalOperations.FIX_CONFLICT, "New org created merging: " + StringUtils.join(similarIds, ", "), user));
+ .save(new JournalEntry(masterId, JournalOperations.FIX_CONFLICT, finalMessage, user));
return masterId;
}
@@ -572,6 +636,10 @@ public class DatabaseUtils {
return views.stream().map(mapper).flatMap(s -> s.stream()).collect(Collectors.toCollection(LinkedHashSet::new));
}
+ private Set findAll(final List views, final Function> mapper, final Predicate filter) {
+ return views.stream().map(mapper).flatMap(s -> s.stream()).filter(filter).collect(Collectors.toCollection(LinkedHashSet::new));
+ }
+
private List hideConflictOrgs(final String masterId, final String otherId) {
organizationRepository.updateStatus(otherId, OrganizationStatus.hidden.toString());
openaireConflictRepository.findById(new OpenaireConflictPK(masterId, otherId)).ifPresent(openaireConflictRepository::delete);
@@ -585,4 +653,24 @@ public class DatabaseUtils {
return jdbcTemplate.queryForList(sql, String.class);
}
+ public Iterable listPersistentOrgs() {
+ return persistentOrganizationViewRepository.findAll();
+ }
+
+ public void addPersistentOrgs(final String id) {
+ final boolean valid = organizationRepository.findById(id)
+ .map(Organization::getStatus)
+ .filter(s -> s.equals(OrganizationStatus.approved.toString()))
+ .isPresent();
+ if (valid) {
+ persistentOrganizationRepository.save(new PersistentOrganization(id));
+ } else {
+ throw new RuntimeException("The ID does not refer to an approved Organization");
+ }
+ }
+
+ public void deletePersistentOrgs(final String id) {
+ persistentOrganizationRepository.deleteById(id);
+ }
+
}
diff --git a/apps/dnet-orgs-database-application/src/main/java/eu/dnetlib/organizations/utils/JournalOperations.java b/apps/dnet-orgs-database-application/src/main/java/eu/dnetlib/organizations/utils/JournalOperations.java
index d2db9715..7bcb1ec7 100644
--- a/apps/dnet-orgs-database-application/src/main/java/eu/dnetlib/organizations/utils/JournalOperations.java
+++ b/apps/dnet-orgs-database-application/src/main/java/eu/dnetlib/organizations/utils/JournalOperations.java
@@ -9,5 +9,6 @@ public enum JournalOperations {
DUPLICATES,
FIX_CONFLICT,
NO_CONFLICT,
+ BACKUP_ORG,
UNKNOWN
}
diff --git a/apps/dnet-orgs-database-application/src/main/resources/application.properties b/apps/dnet-orgs-database-application/src/main/resources/application.properties
index 6425e130..83038eca 100644
--- a/apps/dnet-orgs-database-application/src/main/resources/application.properties
+++ b/apps/dnet-orgs-database-application/src/main/resources/application.properties
@@ -51,4 +51,4 @@ openorgs.support.pages = { "Ask a question": "https://www.openaire.eu/support/he
openaire.override.logout.url =
-openaire.explore.organization.baseurl = https://explore.openaire.eu/search/organization?organizationId=
+openaire.explore.organization.baseurl = https://explore.openaire.eu/search/organization?organizationId=%s
diff --git a/apps/dnet-orgs-database-application/src/main/resources/sql/schema.sql b/apps/dnet-orgs-database-application/src/main/resources/sql/schema.sql
index cb91a260..50c9e0f9 100644
--- a/apps/dnet-orgs-database-application/src/main/resources/sql/schema.sql
+++ b/apps/dnet-orgs-database-application/src/main/resources/sql/schema.sql
@@ -5,6 +5,7 @@ DROP VIEW IF EXISTS users_view;
DROP VIEW IF EXISTS conflict_groups_view;
DROP VIEW IF EXISTS suggestions_info_by_country_view;
DROP VIEW IF EXISTS duplicate_groups_view;
+DROP VIEW IF EXISTS persistent_orgs_view;
DROP TABLE IF EXISTS sysconf;
DROP TABLE IF EXISTS other_ids;
@@ -14,6 +15,8 @@ DROP TABLE IF EXISTS relationships;
DROP TABLE IF EXISTS urls;
DROP TABLE IF EXISTS oa_duplicates;
DROP TABLE IF EXISTS oa_conflicts;
+DROP TABLE IF EXISTS persistent_orgs;
+
DROP TABLE IF EXISTS organizations;
DROP TABLE IF EXISTS org_types;
@@ -374,6 +377,10 @@ CREATE TABLE organizations (
CREATE INDEX organizations_type_idx ON organizations(type);
CREATE INDEX organizations_country_idx ON organizations(country);
+CREATE TABLE persistent_orgs (
+ id text PRIMARY KEY REFERENCES organizations(id) ON UPDATE CASCADE ON DELETE CASCADE
+);
+
CREATE TABLE other_ids (
id text REFERENCES organizations(id) ON UPDATE CASCADE ON DELETE CASCADE,
otherid text,
@@ -464,7 +471,9 @@ CREATE VIEW oa_duplicates_view AS
o.ec_internationalorganization,
o.ec_enterprise,
o.ec_smevalidated,
- o.ec_nutscode
+ o.ec_nutscode,
+ substr(d.oa_original_id, 1, 14)||md5(substr(d.oa_original_id, 15)) as openaire_id,
+ false as openaire_persistent
FROM
oa_duplicates d
LEFT OUTER JOIN organizations o ON (o.id = d.oa_original_id)
@@ -524,6 +533,8 @@ CREATE VIEW organizations_view AS SELECT
org.ec_enterprise,
org.ec_smevalidated,
org.ec_nutscode,
+ substr(org.id, 1, 14)||md5(substr(org.id, 15)) as openaire_id,
+ count(po.id) > 0 as openaire_persistent,
COALESCE(jsonb_agg(DISTINCT jsonb_build_object('id', oid.otherid, 'type', oid.type)) FILTER (WHERE oid.otherid IS NOT NULL), '[]') AS other_ids,
COALESCE(jsonb_agg(DISTINCT jsonb_build_object('name', n.name, 'lang', n.lang)) FILTER (WHERE n.name IS NOT NULL), '[]') AS other_names,
COALESCE(jsonb_agg(DISTINCT a.acronym) FILTER (WHERE a.acronym IS NOT NULL), '[]') AS acronyms,
@@ -537,6 +548,7 @@ FROM
LEFT OUTER JOIN urls u ON (org.id = u.id)
LEFT OUTER JOIN relationships r ON (org.id = r.id1)
LEFT OUTER JOIN organizations relorg ON (relorg.id = r.id2)
+ LEFT OUTER JOIN persistent_orgs po ON (org.id = po.id)
GROUP BY
org.id,
org.name,
@@ -564,13 +576,16 @@ CREATE VIEW organizations_info_view AS SELECT
org.creation_date,
org.modified_by,
org.modification_date,
+ substr(org.id, 1, 14)||md5(substr(org.id, 15)) as openaire_id,
+ count(po.id) > 0 as openaire_persistent,
count(DISTINCT d.oa_original_id) as n_duplicates,
count(DISTINCT c.id2) as n_conflicts,
count(DISTINCT n.note) > 0 as note
FROM organizations org
- LEFT OUTER JOIN oa_duplicates d ON (org.id = d.local_id AND d.reltype = 'suggested')
- LEFT OUTER JOIN oa_conflicts c ON (org.id = c.id1 AND c.reltype = 'suggested')
- LEFT OUTER JOIN notes n ON (org.id = n.id)
+ LEFT OUTER JOIN oa_duplicates d ON (org.id = d.local_id AND d.reltype = 'suggested')
+ LEFT OUTER JOIN oa_conflicts c ON (org.id = c.id1 AND c.reltype = 'suggested')
+ LEFT OUTER JOIN notes n ON (org.id = n.id)
+ LEFT OUTER JOIN persistent_orgs po ON (org.id = po.id)
GROUP BY org.id;
CREATE VIEW organizations_simple_view AS SELECT
@@ -674,6 +689,18 @@ WHERE
GROUP BY o.id, o.name, o.city, o.country
ORDER BY o.name;
+CREATE VIEW persistent_orgs_view AS SELECT
+ po.id,
+ substr(po.id, 1, 14)||md5(substr(po.id,15)) as openaire_id,
+ true as openaire_persistent,
+ o.name,
+ o.city,
+ o.country
+FROM
+ persistent_orgs po
+ JOIN organizations o ON (po.id = o.id)
+ORDER BY o.name;
+
CREATE TABLE org_index_search(id text PRIMARY KEY, txt tsvector);
CREATE INDEX org_index_search_txt_gin_idx ON org_index_search USING gin(txt);
diff --git a/apps/dnet-orgs-database-application/src/main/resources/static/resources/html/pages/admin/persistentOrgs.html b/apps/dnet-orgs-database-application/src/main/resources/static/resources/html/pages/admin/persistentOrgs.html
new file mode 100644
index 00000000..406d155a
--- /dev/null
+++ b/apps/dnet-orgs-database-application/src/main/resources/static/resources/html/pages/admin/persistentOrgs.html
@@ -0,0 +1,47 @@
+Persistent Organizations
+
+
+ It is necessary to persist the identifiers of the organizations associated to an Institutional Dashboard
+
+
+
\ No newline at end of file
diff --git a/apps/dnet-orgs-database-application/src/main/resources/static/resources/html/pages/edit/edit.html b/apps/dnet-orgs-database-application/src/main/resources/static/resources/html/pages/edit/edit.html
index 5d7c1599..9cac6d11 100644
--- a/apps/dnet-orgs-database-application/src/main/resources/static/resources/html/pages/edit/edit.html
+++ b/apps/dnet-orgs-database-application/src/main/resources/static/resources/html/pages/edit/edit.html
@@ -6,7 +6,9 @@
ID: {{info.id}}
Created at {{info.creationDate | date:'MMMM d, y HH:mm:ss'}} by {{info.createdBy}}
Modified at {{info.modificationDate | date:'MMMM d, y HH:mm:ss'}} by {{info.modifiedBy}}
- OA Graph Node ID: {{info.oaGraphId}} [try on OA Explore]
+ OA Graph Node ID: {{info.openaireId}} [try on OA Explore]
+ persistent
+
diff --git a/apps/dnet-orgs-database-application/src/main/resources/static/resources/html/parts/org_details.html b/apps/dnet-orgs-database-application/src/main/resources/static/resources/html/parts/org_details.html
index 7452777d..c5751c6e 100644
--- a/apps/dnet-orgs-database-application/src/main/resources/static/resources/html/parts/org_details.html
+++ b/apps/dnet-orgs-database-application/src/main/resources/static/resources/html/parts/org_details.html
@@ -4,7 +4,7 @@
'text-white bg-success' : show == 'success',
'text-white bg-info' : show == 'info',
'bg-secondary' : show == 'secondary',
- }">{{orgTitle}}
+ }">{{orgTitle}} persistent ID
Name |
diff --git a/apps/dnet-orgs-database-application/src/main/resources/static/resources/html/parts/org_duplicates.html b/apps/dnet-orgs-database-application/src/main/resources/static/resources/html/parts/org_duplicates.html
index 48f79291..23c22e88 100644
--- a/apps/dnet-orgs-database-application/src/main/resources/static/resources/html/parts/org_duplicates.html
+++ b/apps/dnet-orgs-database-application/src/main/resources/static/resources/html/parts/org_duplicates.html
@@ -36,7 +36,7 @@
{{sr.oaCountry}} |
Original Id: {{sr.oaOriginalId}}
- OA Graph Node ID: {{sr.oaGraphId}} [try]
+ OA Graph Node ID: {{sr.openaireId}} [try]
Provenance: {{sr.oaCollectedFrom}}
Added by: {{sr.createdBy}}
|
diff --git a/apps/dnet-orgs-database-application/src/main/resources/static/resources/js/organizations.js b/apps/dnet-orgs-database-application/src/main/resources/static/resources/js/organizations.js
index e5ec7f74..b7fb83a7 100644
--- a/apps/dnet-orgs-database-application/src/main/resources/static/resources/js/organizations.js
+++ b/apps/dnet-orgs-database-application/src/main/resources/static/resources/js/organizations.js
@@ -119,7 +119,12 @@ orgsModule.directive('resolveConflictsModal', function($http, $route, $window) {
call_http_post($http, 'api/organizations/conflicts/fix/similar', ids, function(res) {
$('#' + scope.modalId).modal('hide');
if (scope.openNewOrg == '1') {
- $('#' + scope.modalId).on('hidden.bs.modal', function (e) { $window.location.assign('#!/edit/0/' + res.data[0]); });
+ $('#' + scope.modalId).on('hidden.bs.modal', function (e) {
+ var oldLoc = $window.location;
+ $window.location.assign('#!/edit/0/' + res.data[0]);
+ var newLoc = $window.location;
+ if (oldLoc == newLoc) $route.reload();
+ });
} else {
$('#' + scope.modalId).on('hidden.bs.modal', function (e) { $route.reload(); });
}
@@ -323,7 +328,13 @@ orgsModule.directive('orgConflicts', function($http, $window, $location, $route,
angular.forEach(scope.conflicts, function(o, pos) { ids.push(o.id); });
if (merge) {
- call_http_post($http, "api/organizations/conflicts/fix/similar", ids, function(res) { $window.location.assign('#!/edit/0/' + res.data[0]); });
+ call_http_post($http, "api/organizations/conflicts/fix/similar", ids, function(res) {
+ if (res.data[0] == scope.org.id) {
+ $route.reload();
+ } else {
+ $window.location.assign('#!/edit/0/' + res.data[0]);
+ }
+ });
} else {
call_http_post($http, "api/organizations/conflicts/fix/different", ids, function(res) { $route.reload(); });
}
@@ -379,6 +390,7 @@ orgsModule.config(function($routeProvider) {
.when('/sysconf', { templateUrl: 'resources/html/pages/admin/sysConf.html', controller: 'sysConfCtrl' })
.when('/utils', { templateUrl: 'resources/html/pages/admin/utils.html', controller: 'utilsCtrl' })
.when('/lastImport', { templateUrl: 'resources/html/pages/admin/lastImport.html', controller: 'lastImportCtrl' })
+ .when('/persistentOrgs', { templateUrl: 'resources/html/pages/admin/persistentOrgs.html', controller: 'persistentOrgsCtrl' })
.otherwise({ redirectTo: '/search' });
});
@@ -806,6 +818,26 @@ orgsModule.controller('lastImportCtrl', function ($scope, $http) {
$scope.refresh();
});
+orgsModule.controller('persistentOrgsCtrl', function ($scope, $http) {
+ $scope.orgs = {};
+
+ $scope.refresh = function() {
+ call_http_get($http, 'api/persistentOrgs', function(res) { $scope.orgs = res.data; });
+ }
+
+ $scope.addPersistentOrg = function(id) {
+ call_http_post($http, 'api/persistentOrgs', [ id ], function(res) { $scope.orgs = res.data; });
+ }
+
+ $scope.deletePersistentOrg = function(id) {
+ if (confirm("Are you sure ?")) {
+ call_http_delete($http, 'api/persistentOrgs?id=' + id, function(res) { $scope.orgs = res.data; });
+ }
+ }
+
+ $scope.refresh();
+});
+
orgsModule.controller('utilsCtrl', function ($scope, $http) {
$scope.fulltextIndexMessage = '';
diff --git a/apps/dnet-orgs-database-application/src/main/resources/templates/main.html b/apps/dnet-orgs-database-application/src/main/resources/templates/main.html
index 461dab24..5c3e863a 100644
--- a/apps/dnet-orgs-database-application/src/main/resources/templates/main.html
+++ b/apps/dnet-orgs-database-application/src/main/resources/templates/main.html
@@ -117,6 +117,8 @@ fieldset > legend { font-size : 1.2rem !important; }
System utilities
Last import of suggestions
+ Configure persistent organizations
+
Manage users