diff --git a/apps/dnet-orgs-database-application/pom.xml b/apps/dnet-orgs-database-application/pom.xml index 72e973ce..e80fec55 100644 --- a/apps/dnet-orgs-database-application/pom.xml +++ b/apps/dnet-orgs-database-application/pom.xml @@ -33,8 +33,7 @@ org.thymeleaf.extras - thymeleaf-extras-springsecurity4 - 3.0.4.RELEASE + thymeleaf-extras-springsecurity5 org.postgresql @@ -43,7 +42,7 @@ com.vladmihalcea hibernate-types-52 - 2.3.5 + 2.9.13 diff --git a/apps/dnet-orgs-database-application/src/main/java/eu/dnetlib/organizations/MainApplication.java b/apps/dnet-orgs-database-application/src/main/java/eu/dnetlib/organizations/MainApplication.java index 4a8686c6..f845ceb1 100644 --- a/apps/dnet-orgs-database-application/src/main/java/eu/dnetlib/organizations/MainApplication.java +++ b/apps/dnet-orgs-database-application/src/main/java/eu/dnetlib/organizations/MainApplication.java @@ -30,17 +30,19 @@ public class MainApplication { log.info("Initializing SWAGGER..."); return new Docket(DocumentationType.SWAGGER_2) - .select() - .apis(RequestHandlerSelectors.any()) - .paths(p -> p.startsWith("/api/")) - .build().apiInfo(new ApiInfoBuilder() - .title("D-Net Organizations Service APIs") - .description("APIs documentation") - .version("1.1") - .contact(ApiInfo.DEFAULT_CONTACT) - .license("Apache 2.0") - .licenseUrl("http://www.apache.org/licenses/LICENSE-2.0") - .build()); + .select() + .apis(RequestHandlerSelectors.any()) + .paths(p -> p.startsWith("/api/")) + .build() + .apiInfo(new ApiInfoBuilder() + .title("D-Net Organizations Service APIs") + .description("APIs documentation") + .version("1.1") + .contact(ApiInfo.DEFAULT_CONTACT) + .license("Apache 2.0") + .licenseUrl("http://www.apache.org/licenses/LICENSE-2.0") + .build()); } + } 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 505a9b0d..29a33df6 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 @@ -73,6 +73,7 @@ public class OrganizationController { @RequestMapping(value = "/save", method = RequestMethod.POST) public List save(@RequestBody final OrganizationView org, final Authentication authentication) { + if (StringUtils.isBlank(org.getName())) { throw new RuntimeException("Missing field: name"); } else if (StringUtils.isBlank(org.getCountry())) { @@ -100,11 +101,11 @@ public class OrganizationController { suggestionInfoViewByCountryRepository.findAll().forEach(info::add); } else if (UserInfo.isSimpleUser(authentication) || UserInfo.isNationalAdmin(authentication)) { userCountryRepository.getCountriesForUser(authentication.getName()) - .stream() - .map(suggestionInfoViewByCountryRepository::findById) - .filter(Optional::isPresent) - .map(Optional::get) - .forEach(info::add); + .stream() + .map(suggestionInfoViewByCountryRepository::findById) + .filter(Optional::isPresent) + .map(Optional::get) + .forEach(info::add); } return info; } @@ -147,11 +148,11 @@ public class OrganizationController { return groupConflicts(conflictGroupViewRepository.findByCountry1OrCountry2(country, country).stream()); } else if (UserInfo.isSimpleUser(authentication) || UserInfo.isNationalAdmin(authentication)) { final Stream list = userCountryRepository.getCountriesForUser(authentication.getName()) - .stream() - .filter(country::equalsIgnoreCase) - .map(c -> conflictGroupViewRepository.findByCountry1OrCountry2(c, c).stream()) - .findFirst() - .orElse(Stream.empty()); + .stream() + .filter(country::equalsIgnoreCase) + .map(c -> conflictGroupViewRepository.findByCountry1OrCountry2(c, c).stream()) + .findFirst() + .orElse(Stream.empty()); return groupConflicts(list); } else { throw new RuntimeException("User not authorized"); @@ -166,11 +167,11 @@ public class OrganizationController { return duplicateGroupViewRepository.findByCountry(country); } else if (UserInfo.isSimpleUser(authentication) || UserInfo.isNationalAdmin(authentication)) { return userCountryRepository.getCountriesForUser(authentication.getName()) - .stream() - .filter(country::equalsIgnoreCase) - .map(duplicateGroupViewRepository::findByCountry) - .findFirst() - .orElse(new ArrayList()); + .stream() + .filter(country::equalsIgnoreCase) + .map(duplicateGroupViewRepository::findByCountry) + .findFirst() + .orElse(new ArrayList()); } else { throw new RuntimeException("User not authorized"); } @@ -193,10 +194,10 @@ public class OrganizationController { public List duplicates(@RequestBody final List simrels, final Authentication authentication) { final boolean b = UserInfo.isSuperAdmin(authentication) - || simrels.stream() - .map(OpenaireDuplicate::getLocalId) - .distinct() - .allMatch(id -> userCountryRepository.verifyAuthorizationForId(id, authentication.getName())); + || simrels.stream() + .map(OpenaireDuplicate::getLocalId) + .distinct() + .allMatch(id -> userCountryRepository.verifyAuthorizationForId(id, authentication.getName())); if (b) { return openaireDuplicateRepository.saveAll(simrels); @@ -207,19 +208,19 @@ public class OrganizationController { @RequestMapping(value = "/search/{page}/{size}", method = RequestMethod.GET) public Page search(@PathVariable final int page, - @PathVariable final int size, - @RequestParam final String q, - final Authentication authentication) { + @PathVariable final int size, + @RequestParam final String q, + final Authentication authentication) { return UserInfo.isSuperAdmin(authentication) - ? organizationSimpleViewRepository.findByNameContainingIgnoreCase(q, PageRequest.of(page, size)) - : organizationSimpleViewRepository.findByNameForUser(q, authentication.getName(), PageRequest.of(page, size)); + ? organizationSimpleViewRepository.findByNameContainingIgnoreCase(q, PageRequest.of(page, size)) + : organizationSimpleViewRepository.findByNameForUser(q, authentication.getName(), PageRequest.of(page, size)); } @RequestMapping(value = "/byCountry/{code}/{page}/{size}", method = RequestMethod.GET) public Page findByCountry(@PathVariable final String code, - @PathVariable final int page, - @PathVariable final int size, - final Authentication authentication) { + @PathVariable final int page, + @PathVariable final int size, + final Authentication authentication) { if (UserInfo.isSuperAdmin(authentication) || userCountryRepository.verifyAuthorizationForCountry(code, authentication.getName())) { return organizationSimpleViewRepository.findByCountry(code, PageRequest.of(page, size)); } else { @@ -229,26 +230,26 @@ public class OrganizationController { @RequestMapping(value = "/byType/{type}/{page}/{size}", method = RequestMethod.GET) public Page findByType(@PathVariable final String type, - @PathVariable final int page, - @PathVariable final int size, - final Authentication authentication) { + @PathVariable final int page, + @PathVariable final int size, + final Authentication authentication) { return UserInfo.isSuperAdmin(authentication) - ? organizationSimpleViewRepository.findByType(type, PageRequest.of(page, size)) - : organizationSimpleViewRepository.findByTypeForUser(type, authentication.getName(), PageRequest.of(page, size)); + ? organizationSimpleViewRepository.findByType(type, PageRequest.of(page, size)) + : organizationSimpleViewRepository.findByTypeForUser(type, authentication.getName(), PageRequest.of(page, size)); } @RequestMapping(value = "/browse/countries", method = RequestMethod.GET) public List browseCountries(final Authentication authentication) { return UserInfo.isSuperAdmin(authentication) - ? organizationSimpleViewRepository.browseCountries() - : organizationSimpleViewRepository.browseCountriesForUser(authentication.getName()); + ? databaseUtils.browseCountries() + : databaseUtils.browseCountriesForUser(authentication.getName()); } @RequestMapping(value = "/browse/types", method = RequestMethod.GET) public List browseOrganizationTypes(final Authentication authentication) { return UserInfo.isSuperAdmin(authentication) - ? organizationSimpleViewRepository.browseTypes() - : organizationSimpleViewRepository.browseTypesForUser(authentication.getName()); + ? databaseUtils.browseTypes() + : databaseUtils.browseTypesForUser(authentication.getName()); } @RequestMapping(value = "/conflicts/fix/{masterId}", method = RequestMethod.POST) @@ -256,10 +257,10 @@ public class OrganizationController { if (UserInfo.isSuperAdmin(authentication) || userCountryRepository.verifyAuthorizationForId(masterId, authentication.getName())) { return otherIds.stream() - .filter(id -> UserInfo.isSuperAdmin(authentication) || userCountryRepository.verifyAuthorizationForId(id, authentication.getName())) - .map(id -> databaseUtils.makeRelation(masterId, id, RelationType.Merges)) - .flatMap(List::stream) - .collect(Collectors.toList()); + .filter(id -> UserInfo.isSuperAdmin(authentication) || userCountryRepository.verifyAuthorizationForId(id, authentication.getName())) + .map(id -> databaseUtils.makeRelation(masterId, id, RelationType.Merges)) + .flatMap(List::stream) + .collect(Collectors.toList()); } else { return new ArrayList<>(); diff --git a/apps/dnet-orgs-database-application/src/main/java/eu/dnetlib/organizations/model/utils/BrowseEntry.java b/apps/dnet-orgs-database-application/src/main/java/eu/dnetlib/organizations/model/utils/BrowseEntry.java index d0f1fbdc..8895f1c1 100644 --- a/apps/dnet-orgs-database-application/src/main/java/eu/dnetlib/organizations/model/utils/BrowseEntry.java +++ b/apps/dnet-orgs-database-application/src/main/java/eu/dnetlib/organizations/model/utils/BrowseEntry.java @@ -1,9 +1,31 @@ package eu.dnetlib.organizations.model.utils; -public interface BrowseEntry { +import java.io.Serializable; - String getValue(); +public class BrowseEntry implements Serializable { - int getCount(); + /** + * + */ + private static final long serialVersionUID = 8854955977257064470L; + + private String value; + private int count; + + public String getValue() { + return value; + } + + public void setValue(final String value) { + this.value = value; + } + + public int getCount() { + return count; + } + + public void setCount(final int count) { + this.count = count; + } } diff --git a/apps/dnet-orgs-database-application/src/main/java/eu/dnetlib/organizations/repository/readonly/OrganizationSimpleViewRepository.java b/apps/dnet-orgs-database-application/src/main/java/eu/dnetlib/organizations/repository/readonly/OrganizationSimpleViewRepository.java index 7cefa051..ced650fa 100644 --- a/apps/dnet-orgs-database-application/src/main/java/eu/dnetlib/organizations/repository/readonly/OrganizationSimpleViewRepository.java +++ b/apps/dnet-orgs-database-application/src/main/java/eu/dnetlib/organizations/repository/readonly/OrganizationSimpleViewRepository.java @@ -1,13 +1,10 @@ package eu.dnetlib.organizations.repository.readonly; -import java.util.List; - import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.Query; import org.springframework.stereotype.Repository; -import eu.dnetlib.organizations.model.utils.BrowseEntry; import eu.dnetlib.organizations.model.view.OrganizationSimpleView; @Repository @@ -20,29 +17,8 @@ public interface OrganizationSimpleViewRepository extends ReadOnlyRepository findByNameForUser(String text, String email, Pageable pageable); - // BROWSE BY COUNTRY - @Query(value = "select country as value, count(*) as count from organizations group by country order by count desc", nativeQuery = true) - List browseCountries(); - - // BROWSE BY COUNTRY FOR USER - @Query(value = "select o.country as value, count(o.country) as count from user_countries uc left outer join organizations o on (uc.country = o.country) where uc.email=?1 group by o.country order by count desc", nativeQuery = true) - List browseCountriesForUser(String email); - Page findByCountry(String country, Pageable pageable); - // BROWSE BY ORG TYPE - @Query(value = "select type as value, count(*) as count from organizations group by type order by count desc", nativeQuery = true) - List browseTypes(); - - // BROWSE BY ORG TYPE FOR USER - @Query(value = "select o.type as value, count(o.type) as count " - + "from organizations o " - + "left outer join user_countries uc on (uc.country = o.country) " - + "where uc.email=?1 " - + "group by o.type " - + "order by count desc;", nativeQuery = true) - List browseTypesForUser(String email); - Page findByType(String type, Pageable pageable); @Query(value = "select o.* from organizations_simple_view o left outer join user_countries uc on (uc.country = o.country) where uc.email = ?2 and o.type = ?1", nativeQuery = true) 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 c3ff772a..732f88c2 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 @@ -16,6 +16,7 @@ import javax.transaction.Transactional; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.annotation.Cacheable; +import org.springframework.jdbc.core.BeanPropertyRowMapper; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Component; import org.springframework.web.bind.annotation.RequestBody; @@ -31,6 +32,7 @@ import eu.dnetlib.organizations.model.Relationship; import eu.dnetlib.organizations.model.Url; import eu.dnetlib.organizations.model.User; import eu.dnetlib.organizations.model.UserCountry; +import eu.dnetlib.organizations.model.utils.BrowseEntry; import eu.dnetlib.organizations.model.view.OrganizationView; import eu.dnetlib.organizations.model.view.UserView; import eu.dnetlib.organizations.repository.AcronymRepository; @@ -68,7 +70,12 @@ public class DatabaseUtils { private JdbcTemplate jdbcTemplate; public enum VocabularyTable { - languages, countries, org_types, id_types, rel_types, simrel_types + languages, + countries, + org_types, + id_types, + rel_types, + simrel_types } @Transactional @@ -79,10 +86,10 @@ public class DatabaseUtils { } final Organization org = new Organization(update ? orgView.getId() : null, - orgView.getName(), - orgView.getType(), - orgView.getLat(), orgView.getLng(), - orgView.getCity(), orgView.getCountry()); + orgView.getName(), + orgView.getType(), + orgView.getLat(), orgView.getLng(), + orgView.getCity(), orgView.getCountry()); final String orgId = organizationRepository.save(org).getId(); @@ -139,7 +146,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())); } } @@ -208,13 +215,13 @@ public class DatabaseUtils { private List findExistingGroupsForRel(final OpenaireConflict w, final Map> groups) { return groups.entrySet() - .stream() - .filter(e -> { - return e.getValue().contains(w.getId1()) || e.getValue().contains(w.getId2()); - }) - .map(e -> e.getKey()) - .distinct() - .collect(Collectors.toList()); + .stream() + .filter(e -> { + return e.getValue().contains(w.getId1()) || e.getValue().contains(w.getId2()); + }) + .map(e -> e.getKey()) + .distinct() + .collect(Collectors.toList()); } private void addToGroup(final Map> groups, final String gid, final OpenaireConflict w) { @@ -236,4 +243,36 @@ public class DatabaseUtils { return Arrays.asList(r1, r2); } + + // BROWSE BY COUNTRY + public List browseCountries() { + final String sql = "select country as value, count(*) as count from organizations group by country order by count desc"; + return jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(BrowseEntry.class)); + } + + // BROWSE BY COUNTRY FOR USER + public List browseCountriesForUser(final String email) { + final String sql = + "select o.country as value, count(o.country) as count from user_countries uc left outer join organizations o on (uc.country = o.country) where uc.email=? group by o.country order by count desc"; + return jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(BrowseEntry.class), email); + } + + // BROWSE BY ORG TYPE + public List browseTypes() { + final String sql = "select type as value, count(*) as count from organizations group by type order by count desc"; + return jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(BrowseEntry.class)); + } + + // BROWSE BY ORG TYPE FOR USER + public List browseTypesForUser(final String email) { + final String sql = "select o.type as value, count(o.type) as count " + + "from organizations o " + + "left outer join user_countries uc on (uc.country = o.country) " + + "where uc.email=? " + + "group by o.type " + + "order by count desc;"; + return jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(BrowseEntry.class), email); + + } + } 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 a9bd8d11..c116d7ee 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 @@ -31,6 +31,7 @@ orgsModule.directive('selectOrgModal', function($http) { scope.search = function(text, page, size) { scope.searchOrgs = {}; + $http.get('api/organizations/search/' + page + '/' + size + '?q=' + text).then(function successCallback(res) { if((typeof res.data) == 'string') { alert("Session expired !"); location.reload(true); } scope.searchValue = text; @@ -438,14 +439,21 @@ orgsModule.controller('newOrgCtrl', function ($scope, $http, $routeParams, $loca orgsModule.controller('searchCtrl', function ($scope, $location) { $scope.searchText = ''; $scope.search = function() { - $location.url('/searchResults/0/50/' + encodeURIComponent(encodeURIComponent($scope.searchText))); + if ($scope.searchText) { + $location.url('/searchResults/0/50/' + encodeURIComponent(encodeURIComponent($scope.searchText))); + } else { + $location.url('/searchResults/0/50/_'); + } } }); orgsModule.controller('searchResultsCtrl', function ($scope, $http, $routeParams, $location) { - $scope.searchText = decodeURIComponent($routeParams.text); + $scope.searchText = ''; + if ($routeParams.text != '_') { + $scope.searchText = decodeURIComponent($routeParams.text); + } $scope.orgs = {}; - + $http.get('api/organizations/search/' + $routeParams.page + '/' + $routeParams.size + '?q=' + $scope.searchText).then(function successCallback(res) { if((typeof res.data) == 'string') { alert("Session expired !"); location.reload(true); } $scope.orgs = res.data; @@ -454,11 +462,19 @@ orgsModule.controller('searchResultsCtrl', function ($scope, $http, $routeParams }); $scope.prev = function() { - $location.url('/searchResults/' + ($scope.orgs.number - 1) + '/' + $scope.orgs.size + '/' + encodeURIComponent($scope.searchText)); + if ($scope.searchText) { + $location.url('/searchResults/' + ($scope.orgs.number - 1) + '/' + $scope.orgs.size + '/' + encodeURIComponent($scope.searchText)); + } else { + $location.url('/searchResults/' + ($scope.orgs.number - 1) + '/' + $scope.orgs.size + '/_'); + } } $scope.next = function() { - $location.url('/searchResults/' + ($scope.orgs.number + 1) + '/' + $scope.orgs.size + '/' + encodeURIComponent($scope.searchText)); + if ($scope.searchText) { + $location.url('/searchResults/' + ($scope.orgs.number + 1) + '/' + $scope.orgs.size + '/' + encodeURIComponent($scope.searchText)); + } else { + $location.url('/searchResults/' + ($scope.orgs.number + 1) + '/' + $scope.orgs.size + '/_'); + } } }); diff --git a/pom.xml b/pom.xml index e3183463..edc39d1a 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.springframework.boot spring-boot-starter-parent - 2.3.1.RELEASE + 2.3.2.RELEASE