updated public logs api

This commit is contained in:
Michele Artini 2023-12-14 11:10:43 +01:00
parent e4cbfe863b
commit a0e7425379
6 changed files with 184 additions and 244 deletions

View File

@ -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<ApiJournalView> findJournalByCountry(@PathVariable final String country, @PathVariable final int page, @PathVariable final int size) {
return apiJournalViewRepository.findByCountry(country, PageRequest.of(page, size));
}
}

View File

@ -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;
}
}

View File

@ -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<ApiOperation> 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<ApiOperation> getLogs() {
return logs;
}
public void setLogs(final List<ApiOperation> logs) {
this.logs = logs;
}
}

View File

@ -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<ApiJournalView, String> {
Page<ApiJournalView> findByCountry(String country, Pageable page);
}

View File

@ -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<OpenaireDuplicate> 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<VocabularyTerm> 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<String> countries) {
final String fullname,
final String organization,
final String referencePerson,
final String requestMessage,
final List<String> countries) {
final User user = new User();
user.setEmail(email);
@ -405,32 +401,32 @@ public class DatabaseUtils {
// BROWSE BY COUNTRY
public List<BrowseEntry> 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<BrowseEntry> 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<BrowseEntry> 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<BrowseEntry> 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<OrganizationConflict> 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<String> similarIds, final String user) {
final List<OrganizationView> 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<OrganizationView> persistents = views.stream().filter(v -> v.getPersistent()).collect(Collectors.toList());
final List<OrganizationView> 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<OpenaireDuplicate> 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 <T> Set<T> findAll(final List<OrganizationView> views, final Function<OrganizationView, Set<T>> 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 <T> Set<T> findAll(final List<OrganizationView> views, final Function<OrganizationView, Set<T>> mapper, final Predicate<T> 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<Relationship> hideConflictOrgs(final String masterId, final String otherId) {
@ -649,7 +644,7 @@ public class DatabaseUtils {
public List<String> 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<OrganizationView> 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<String> 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<String, Object> 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"));
}
}

View File

@ -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;