diff --git a/apps/dnet-orgs-database-application/src/main/java/eu/dnetlib/organizations/controller/PublicApiController.java b/apps/dnet-orgs-database-application/src/main/java/eu/dnetlib/organizations/controller/PublicApiController.java index a7787c0f..88182f06 100644 --- a/apps/dnet-orgs-database-application/src/main/java/eu/dnetlib/organizations/controller/PublicApiController.java +++ b/apps/dnet-orgs-database-application/src/main/java/eu/dnetlib/organizations/controller/PublicApiController.java @@ -1,35 +1,53 @@ package eu.dnetlib.organizations.controller; +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.io.IOUtils; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.PageRequest; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; -import eu.dnetlib.organizations.model.view.ApiJournalView; -import eu.dnetlib.organizations.repository.OrganizationRepository; -import eu.dnetlib.organizations.repository.readonly.ApiJournalViewRepository; +import eu.dnetlib.organizations.utils.DatabaseUtils; @RestController @RequestMapping("/public-api") public class PublicApiController { @Autowired - private ApiJournalViewRepository apiJournalViewRepository; + private DatabaseUtils dbUtils; - @Autowired - private OrganizationRepository organizationRepository; + @GetMapping("/logs/{year}/{month}/{country}") + public void findJournalByCountry(@PathVariable final int year, + @PathVariable final int month, + @PathVariable final String country, + final HttpServletResponse res) throws IOException { + + if (month < 1 || month > 12) { + res.sendError(HttpStatus.BAD_REQUEST.value(), "Invalid month"); + } + if (year < 2020 || year > 2100) { + res.sendError(HttpStatus.BAD_REQUEST.value(), "Invalid year"); + } + + res.setContentType(MediaType.TEXT_PLAIN.getType()); + final ServletOutputStream out = res.getOutputStream(); + + dbUtils.obtainLogEntries(year, month, country).forEach(s -> { + try { + IOUtils.write(s, out, StandardCharsets.UTF_8); + } catch (final IOException e) { + throw new RuntimeException(e); + } + }); - @GetMapping("/logs") - public ApiJournalView findJournalByDsId(@RequestParam final String id) { - return apiJournalViewRepository.findById(id).orElse(organizationRepository.findById(id).map(ApiJournalView::new).orElse(new ApiJournalView())); } - @GetMapping("/logs/{country}/{page}/{size}") - public Page findJournalByCountry(@PathVariable final String country, @PathVariable final int page, @PathVariable final int size) { - return apiJournalViewRepository.findByCountry(country, PageRequest.of(page, size)); - } } diff --git a/apps/dnet-orgs-database-application/src/main/java/eu/dnetlib/organizations/model/utils/ApiOperation.java b/apps/dnet-orgs-database-application/src/main/java/eu/dnetlib/organizations/model/utils/ApiOperation.java deleted file mode 100644 index cc8a9a63..00000000 --- a/apps/dnet-orgs-database-application/src/main/java/eu/dnetlib/organizations/model/utils/ApiOperation.java +++ /dev/null @@ -1,37 +0,0 @@ -package eu.dnetlib.organizations.model.utils; - -import java.io.Serializable; -import java.time.LocalDateTime; - -public class ApiOperation implements Serializable { - - private static final long serialVersionUID = -7111524441502889608L; - - private String operation; - private String description; - private LocalDateTime date; - - public String getOperation() { - return operation; - } - - public void setOperation(final String operation) { - this.operation = operation; - } - - public String getDescription() { - return description; - } - - public void setDescription(final String description) { - this.description = description; - } - - public LocalDateTime getDate() { - return date; - } - - public void setDate(final LocalDateTime date) { - this.date = date; - } -} diff --git a/apps/dnet-orgs-database-application/src/main/java/eu/dnetlib/organizations/model/view/ApiJournalView.java b/apps/dnet-orgs-database-application/src/main/java/eu/dnetlib/organizations/model/view/ApiJournalView.java deleted file mode 100644 index b33eb2b8..00000000 --- a/apps/dnet-orgs-database-application/src/main/java/eu/dnetlib/organizations/model/view/ApiJournalView.java +++ /dev/null @@ -1,87 +0,0 @@ -package eu.dnetlib.organizations.model.view; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; - -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.Id; -import javax.persistence.Table; - -import org.hibernate.annotations.Type; -import org.hibernate.annotations.TypeDef; -import org.hibernate.annotations.TypeDefs; - -import com.vladmihalcea.hibernate.type.json.JsonBinaryType; -import com.vladmihalcea.hibernate.type.json.JsonStringType; - -import eu.dnetlib.organizations.model.Organization; -import eu.dnetlib.organizations.model.utils.ApiOperation; - -@Entity -@Table(name = "api_journal_view") -@TypeDefs({ - @TypeDef(name = "json", typeClass = JsonStringType.class), - @TypeDef(name = "jsonb", typeClass = JsonBinaryType.class) -}) -public class ApiJournalView implements Serializable { - - private static final long serialVersionUID = 1270660185726854334L; - - @Id - @Column(name = "id") - private String id; - - @Column(name = "name") - private String name; - - @Column(name = "country") - private String country; - - @Type(type = "json") - @Column(name = "logs", columnDefinition = "json") - private List logs; - - public ApiJournalView() {} - - public ApiJournalView(final Organization o) { - id = o.getId(); - name = o.getName(); - country = o.getCountry(); - logs = new ArrayList<>(); - } - - 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 getCountry() { - return country; - } - - public void setCountry(final String country) { - this.country = country; - } - - public List getLogs() { - return logs; - } - - public void setLogs(final List logs) { - this.logs = logs; - } - -} diff --git a/apps/dnet-orgs-database-application/src/main/java/eu/dnetlib/organizations/repository/readonly/ApiJournalViewRepository.java b/apps/dnet-orgs-database-application/src/main/java/eu/dnetlib/organizations/repository/readonly/ApiJournalViewRepository.java deleted file mode 100644 index 9c8eba6c..00000000 --- a/apps/dnet-orgs-database-application/src/main/java/eu/dnetlib/organizations/repository/readonly/ApiJournalViewRepository.java +++ /dev/null @@ -1,14 +0,0 @@ -package eu.dnetlib.organizations.repository.readonly; - -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.stereotype.Repository; - -import eu.dnetlib.organizations.model.view.ApiJournalView; - -@Repository -public interface ApiJournalViewRepository extends ReadOnlyRepository { - - Page findByCountry(String country, Pageable page); - -} 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 e58add34..31ace246 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 @@ -1,5 +1,6 @@ package eu.dnetlib.organizations.utils; +import java.io.StringWriter; import java.time.OffsetDateTime; import java.util.ArrayList; import java.util.Arrays; @@ -104,12 +105,7 @@ public class DatabaseUtils { private static final Log log = LogFactory.getLog(DatabaseUtils.class); public enum VocabularyTable { - languages, - countries, - org_types, - id_types, - rel_types, - simrel_types + languages, countries, org_types, id_types, rel_types, simrel_types } @Transactional @@ -118,8 +114,8 @@ public class DatabaseUtils { final String oldId = StringUtils.isNotBlank(orgView.getId()) ? new String(orgView.getId()) : null; final String oldStatus = oldId != null ? organizationRepository.findById(oldId) - .map(Organization::getStatus) - .orElse(null) : null; + .map(Organization::getStatus) + .orElse(null) : null; final boolean alreadyApproved = StringUtils.equals(oldStatus, OrganizationStatus.approved.toString()); @@ -146,15 +142,15 @@ public class DatabaseUtils { } final Organization org = new Organization(orgView.getId(), - orgView.getName(), - orgView.getType(), - orgView.getLat(), orgView.getLng(), - orgView.getCity(), orgView.getCountry(), - newStatus, - orgView.getEcLegalBody(), - orgView.getEcLegalPerson(), orgView.getEcNonProfit(), orgView.getEcResearchOrganization(), orgView.getEcHigherEducation(), - orgView.getEcInternationalOrganizationEurInterests(), orgView.getEcInternationalOrganization(), orgView.getEcEnterprise(), - orgView.getEcSmeValidated(), orgView.getEcNutscode()); + orgView.getName(), + orgView.getType(), + orgView.getLat(), orgView.getLng(), + orgView.getCity(), orgView.getCountry(), + newStatus, + orgView.getEcLegalBody(), + orgView.getEcLegalPerson(), orgView.getEcNonProfit(), orgView.getEcResearchOrganization(), orgView.getEcHigherEducation(), + orgView.getEcInternationalOrganizationEurInterests(), orgView.getEcInternationalOrganization(), orgView.getEcEnterprise(), + orgView.getEcSmeValidated(), orgView.getEcNutscode()); final String newId = organizationRepository.save(org).getId(); @@ -168,9 +164,9 @@ public class DatabaseUtils { if (oldId != null) { final List dups = openaireDuplicateRepository.findByLocalId(oldId) - .stream() - .map(d -> prepareNewDuplicate(newId, oldId, d)) - .collect(Collectors.toList()); + .stream() + .map(d -> prepareNewDuplicate(newId, oldId, d)) + .collect(Collectors.toList()); openaireDuplicateRepository.saveAll(dups); @@ -194,7 +190,7 @@ public class DatabaseUtils { if (oldStatus == null) { op = JournalOperations.NEW_SUGG_ORG; message = "Created a new suggested org"; - } else if (oldStatus != null) { + } else { op = JournalOperations.EDIT_SUGG_ORG; message = "Metadata updated"; } @@ -227,9 +223,9 @@ public class DatabaseUtils { d.setOaCollectedFrom(old.getOaCollectedFrom()); if (oldId != null - && newId.startsWith(OpenOrgsConstants.OPENORGS_PREFIX) - && oldId.startsWith(OpenOrgsConstants.OPENORGS_PENDING_PREFIX) - && StringUtils.substringAfter(oldId, OpenOrgsConstants.OPENORGS_PENDING_PREFIX).equalsIgnoreCase(DigestUtils.md5Hex(d.getOaOriginalId()))) { + && newId.startsWith(OpenOrgsConstants.OPENORGS_PREFIX) + && oldId.startsWith(OpenOrgsConstants.OPENORGS_PENDING_PREFIX) + && StringUtils.substringAfter(oldId, OpenOrgsConstants.OPENORGS_PENDING_PREFIX).equalsIgnoreCase(DigestUtils.md5Hex(d.getOaOriginalId()))) { d.setRelType(SimilarityType.is_similar.toString()); } else { d.setRelType(SimilarityType.suggested.toString()); @@ -276,16 +272,16 @@ public class DatabaseUtils { // Updating journal toSave.stream().collect(Collectors.groupingBy(OpenaireDuplicate::getLocalId)).forEach((id, list) -> { final long sim = list.stream() - .filter(d -> d.getRelType().equals(SimilarityType.is_similar.toString())) - .count(); + .filter(d -> d.getRelType().equals(SimilarityType.is_similar.toString())) + .count(); final long diff = list.stream() - .filter(d -> d.getRelType().equals(SimilarityType.is_different.toString())) - .count(); + .filter(d -> d.getRelType().equals(SimilarityType.is_different.toString())) + .count(); final long sugg = list.stream() - .filter(d -> d.getRelType().equals(SimilarityType.suggested.toString())) - .count(); + .filter(d -> d.getRelType().equals(SimilarityType.suggested.toString())) + .count(); final String message = String.format("Duplicates updated (%s similars, %s differents, %s suggested)", sim, diff, sugg); @@ -300,7 +296,7 @@ public class DatabaseUtils { // delete invalid pending orgs (without simrels) final int n = jdbcTemplate - .update("delete from organizations where id in (select o.id from organizations o left outer join oa_duplicates d on (o.id = d.local_id) where o.status = 'suggested' and o.created_by = 'dedupWf' group by o.id having count(d.local_id) = 0)"); + .update("delete from organizations where id in (select o.id from organizations o left outer join oa_duplicates d on (o.id = d.local_id) where o.status = 'suggested' and o.created_by = 'dedupWf' group by o.id having count(d.local_id) = 0)"); if (n > 0) { log.info("Invalid pending orgs deleted: " + n); @@ -335,12 +331,12 @@ public class DatabaseUtils { @Cacheable("countries_for_user") public List listCountriesForUser(final String name) { final String sql = - "select uc.country as value, c.name as name from user_countries uc left outer join countries c on (c.val = uc.country) where uc.email = ? order by c.name"; + "select uc.country as value, c.name as name from user_countries uc left outer join countries c on (c.val = uc.country) where uc.email = ? order by c.name"; return jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(VocabularyTerm.class), name); } @CacheEvict(value = { - "vocs", "countries_for_user" + "vocs", "countries_for_user" }, allEntries = true) public void clearCache() { log.info("All caches cleaned"); @@ -359,7 +355,7 @@ public class DatabaseUtils { userCountryRepository.deleteByEmail(userView.getEmail()); if (userView.getCountries() != null) { userCountryRepository - .saveAll(Arrays.stream(userView.getCountries()).map(c -> new UserCountry(userView.getEmail(), c)).collect(Collectors.toList())); + .saveAll(Arrays.stream(userView.getCountries()).map(c -> new UserCountry(userView.getEmail(), c)).collect(Collectors.toList())); } } @@ -371,11 +367,11 @@ public class DatabaseUtils { @Transactional public void newUser(final String email, - final String fullname, - final String organization, - final String referencePerson, - final String requestMessage, - final List countries) { + final String fullname, + final String organization, + final String referencePerson, + final String requestMessage, + final List countries) { final User user = new User(); user.setEmail(email); @@ -405,32 +401,32 @@ public class DatabaseUtils { // BROWSE BY COUNTRY public List browseCountries() { final String sql = - "select o.country as code, c.name as name, o.status as group, count(o.status) as count from organizations o left outer join countries c on (o.country = c.val) group by o.country, c.name, o.status"; + "select o.country as code, c.name as name, o.status as group, count(o.status) as count from organizations o left outer join countries c on (o.country = c.val) group by o.country, c.name, o.status"; return listBrowseEntries(sql); } // BROWSE BY COUNTRY FOR USER public List browseCountriesForUser(final String email) { final String sql = - "select o.country as code, c.name as name, o.status as group, count(o.status) as count from user_countries uc left outer join organizations o on (uc.country = o.country) left outer join countries c on (o.country = c.val) where uc.email=? group by o.country, c.name, o.status"; + "select o.country as code, c.name as name, o.status as group, count(o.status) as count from user_countries uc left outer join organizations o on (uc.country = o.country) left outer join countries c on (o.country = c.val) where uc.email=? group by o.country, c.name, o.status"; return listBrowseEntries(sql, email); } // BROWSE BY ORG TYPE public List browseTypes() { final String sql = - "select type as code, type as name, status as group, count(status) as count from organizations group by type, status"; + "select type as code, type as name, status as group, count(status) as count from organizations group by type, status"; return listBrowseEntries(sql); } // BROWSE BY ORG TYPE FOR USER public List browseTypesForUser(final String email) { final String sql = "select o.type as code, o.type as name," - + "o.status as group, count(o.status) as count " - + "from organizations o " - + "left outer join user_countries uc on (uc.country = o.country) " - + "where uc.email=? " - + "group by o.type, o.status"; + + "o.status as group, count(o.status) as count " + + "from organizations o " + + "left outer join user_countries uc on (uc.country = o.country) " + + "where uc.email=? " + + "group by o.type, o.status"; return listBrowseEntries(sql, email); } @@ -454,7 +450,7 @@ public class DatabaseUtils { public List listConflictsForId(final String id) { final String sql = - "select o.id, o.name, o.type, o.city, o.country from oa_conflicts c left outer join organizations o on (c.id2 = o.id) where o.id is not null and c.id1 = ? and c.reltype = 'suggested'"; + "select o.id, o.name, o.type, o.city, o.country from oa_conflicts c left outer join organizations o on (c.id2 = o.id) where o.id is not null and c.id1 = ? and c.reltype = 'suggested'"; return jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(OrganizationConflict.class), id); } @@ -479,15 +475,14 @@ public class DatabaseUtils { public String fixConflictSimilars(final List similarIds, final String user) { final List views = - similarIds.stream().map(organizationViewRepository::findById).filter(Optional::isPresent).map(Optional::get).collect(Collectors.toList()); + similarIds.stream().map(organizationViewRepository::findById).filter(Optional::isPresent).map(Optional::get).collect(Collectors.toList()); - final List persistents = views.stream().filter(v -> v.getPersistent()).collect(Collectors.toList()); + final List persistents = views.stream().filter(OrganizationView::getPersistent).collect(Collectors.toList()); final OrganizationView masterOrg = new OrganizationView(); - if (persistents.size() > 1) { - throw new RuntimeException("Too many persintent organizations"); - } else if (persistents.size() == 1) { + if (persistents.size() > 1) { throw new RuntimeException("Too many persintent organizations"); } + if (persistents.size() == 1) { backupOrg(persistents.get(0), user); masterOrg.setId(persistents.get(0).getId()); masterOrg.setStatus(OrganizationStatus.approved.toString()); @@ -513,9 +508,9 @@ public class DatabaseUtils { organizationRepository.updateStatus(backupId, OrganizationStatus.hidden.toString()); journalEntryRepository - .save(new JournalEntry(origId, JournalOperations.BACKUP_ORG, "Saved a backup copy: " + backupId, user)); + .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)); + .save(new JournalEntry(backupId, JournalOperations.BACKUP_ORG, "Saved a backup copy of " + origId, user)); return backupId; } catch (final Exception e) { @@ -529,9 +524,9 @@ public class DatabaseUtils { 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(", ")); + orgs.stream() + .map(OrganizationView::getId) + .collect(Collectors.joining(", ")); masterOrg.setName(findFirstString(orgs, OrganizationView::getName)); masterOrg.setType(findFirstString(orgs, OrganizationView::getType)); @@ -544,35 +539,35 @@ public class DatabaseUtils { 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()))); + && !r.getType().equals(RelationType.Merged_In.toString()))); masterOrg.getOtherNames() - .addAll(orgs.stream() - .map(OrganizationView::getName) - .filter(StringUtils::isNotBlank) - .filter(s -> StringUtils.equalsIgnoreCase(s, masterOrg.getName())) - .map(s -> new eu.dnetlib.organizations.model.view.OtherName(s, "UNKNOWN")) - .collect(Collectors.toList())); + .addAll(orgs.stream() + .map(OrganizationView::getName) + .filter(StringUtils::isNotBlank) + .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(masterOrg, user, false); // I hide the merged organizations 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)); - }); + .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 = orgs.stream() - .map(OrganizationView::getId) - .map(openaireDuplicateRepository::findByLocalId) - .flatMap(l -> l.stream()) - .map(d -> new OpenaireDuplicate(masterId, d.getOaOriginalId(), d.getRelType(), d.getOaCollectedFrom())) - .collect(Collectors.toList()); + .map(OrganizationView::getId) + .map(openaireDuplicateRepository::findByLocalId) + .flatMap(List::stream) + .map(d -> new OpenaireDuplicate(masterId, d.getOaOriginalId(), d.getRelType(), d.getOaCollectedFrom())) + .collect(Collectors.toList()); openaireDuplicateRepository.saveAll(newDuplicates); newDuplicates.forEach(d -> { @@ -588,12 +583,12 @@ public class DatabaseUtils { 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); + .updateStatusAndResetGroup(orgs.get(i).getId(), orgs.get(j).getId(), SimilarityType.is_similar.toString(), user, now); } } journalEntryRepository - .save(new JournalEntry(masterId, JournalOperations.FIX_CONFLICT, finalMessage, user)); + .save(new JournalEntry(masterId, JournalOperations.FIX_CONFLICT, finalMessage, user)); return masterId; } @@ -608,7 +603,7 @@ public class DatabaseUtils { for (int i = 0; i < differentsIds.size(); i++) { for (int j = i + 1; j < differentsIds.size(); j++) { openaireConflictRepository - .updateStatusAndResetGroup(differentsIds.get(i), differentsIds.get(j), SimilarityType.is_different.toString(), user, now); + .updateStatusAndResetGroup(differentsIds.get(i), differentsIds.get(j), SimilarityType.is_different.toString(), user, now); } journalEntryRepository.save(new JournalEntry(differentsIds.get(i), JournalOperations.NO_CONFLICT, message, user)); } @@ -633,11 +628,11 @@ public class DatabaseUtils { } private Set findAll(final List views, final Function> mapper) { - return views.stream().map(mapper).flatMap(s -> s.stream()).collect(Collectors.toCollection(LinkedHashSet::new)); + return views.stream().map(mapper).flatMap(Set::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)); + return views.stream().map(mapper).flatMap(Set::stream).filter(filter).collect(Collectors.toCollection(LinkedHashSet::new)); } private List hideConflictOrgs(final String masterId, final String otherId) { @@ -649,7 +644,7 @@ public class DatabaseUtils { public List invalidCountriesInSuggestions() { final String sql = - " select distinct t.oa_country from tmp_dedup_events t left outer join countries c on (t.oa_country = c.val) where c.val is null order by t.oa_country"; + " select distinct t.oa_country from tmp_dedup_events t left outer join countries c on (t.oa_country = c.val) where c.val is null order by t.oa_country"; return jdbcTemplate.queryForList(sql, String.class); } @@ -665,27 +660,81 @@ public class DatabaseUtils { if (id.length() == 46) { final Optional orgView = organizationViewRepository.findByOpenaireId(id); valid = orgView.map(OrganizationView::getStatus) - .filter(s -> s.equals(OrganizationStatus.approved.toString())) - .isPresent(); + .filter(s -> s.equals(OrganizationStatus.approved.toString())) + .isPresent(); ooid = orgView.get().getId(); } else { valid = organizationRepository.findById(id) - .map(Organization::getStatus) - .filter(s -> s.equals(OrganizationStatus.approved.toString())) - .isPresent(); + .map(Organization::getStatus) + .filter(s -> s.equals(OrganizationStatus.approved.toString())) + .isPresent(); ooid = id; } if (valid) { persistentOrganizationRepository.save(new PersistentOrganization(ooid)); return ooid; - } else { - throw new RuntimeException("The ID does not refer to an approved Organization"); } + throw new RuntimeException("The ID does not refer to an approved Organization"); } public void deletePersistentOrgs(final String id) { persistentOrganizationRepository.deleteById(id); } + public List obtainLogEntries(final int year, final int month, final String country) { + final String query = "SELECT o.id, o.name, j.operation, j.description, date(j.op_date) as op_date " + + "FROM organizations o JOIN journal j ON o.id = j.id " + + "WHERE o.country=? AND extract(year FROM j.op_date)=? AND extract(month FROM j.op_date)=? " + + "ORDER BY date(j.op_date), o,id"; + return jdbcTemplate.queryForList(query, country, year, month) + .stream() + .map(this::asLogEntry) + .collect(Collectors.toList()); + + } + + private String asLogEntry(final Map map) { + final JournalOperations op = JournalOperations.valueOf("" + map.get("operation")); + + final StringWriter sw = new StringWriter(); + sw.write("On %s a curator "); + + switch (op) { + case APPROVE_SUGG_ORG: + sw.write("approved the suggested organisation %s (ID: %s)"); + break; + case NEW_ORG: + sw.write("created the organisation %s (ID: %s)"); + break; + case NEW_SUGG_ORG: + sw.write("suggested the organisation %s (ID: %s)"); + break; + case EDIT_ORG: + sw.write("updated the metadata of %s (ID: %s)"); + break; + case EDIT_SUGG_ORG: + sw.write("updated the metadata of the suggested organisation %s (ID: %s)"); + break; + case DUPLICATES: + sw.write("updated the list of duplicates for %s (ID: %s)"); + break; + case FIX_CONFLICT: + sw.write("chose as master the organisation %s (id: %s), which has been involved in a conflict resolution"); + break; + case NO_CONFLICT: + sw.write("stated that the conflict where the organisation %s (id: %s) was involved was a false positive"); + break; + case BACKUP_ORG: + sw.write("resolved a conflict and the organisation %s (id: %s) involved has been hidden, because another organisation has been chosen as master"); + break; + case UNKNOWN: + default: + sw.write("performed an unknown operation on %s (ID: %s)"); + } + sw.write(". \"%s\"\n"); + + return String.format(sw.toString(), map.get("op_date"), map.get("name"), map.get("id"), map.get("description")); + } + } 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 78a69025..7da2de1a 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 @@ -749,4 +749,15 @@ $$; CREATE TRIGGER insert_or_update_index_search_trigger AFTER INSERT OR UPDATE ON organizations FOR EACH ROW EXECUTE PROCEDURE insert_or_update_index_search_trigger(); CREATE TRIGGER delete_index_search_trigger BEFORE DELETE ON organizations FOR EACH ROW EXECUTE PROCEDURE delete_index_search(); +-- PUBLIC VIEW + +CREATE VIEW api_journal_view AS SELECT + o.id AS org_id, + o.name AS org_name, + o.country AS country, + j.operation AS operation, + j.description AS description, + j.op_date AS op_date +FROM organizations o JOIN journal j ON o.id = j.id; +