From d0d000e192c76953c18d9ade0595899f6738e015 Mon Sep 17 00:00:00 2001 From: Sonia Zorba <sonia.zorba@inaf.it> Date: Thu, 10 Sep 2020 14:49:25 +0200 Subject: [PATCH] Various improvements --- database/Dockerfile | 1 + gms-client/gms-client-lib/pom.xml | 5 +++ .../inaf/ia2/gms/client/call/BaseGmsCall.java | 21 +++++----- gms-ui/src/components/GroupsBreadcrumb.vue | 2 +- gms-ui/src/components/MembersPanel.vue | 2 +- .../src/components/modals/AddGroupModal.vue | 3 +- .../gms/controller/HomePageController.java | 38 +++++++++++++++++-- .../ia2/gms/manager/GroupStatusManager.java | 1 + .../persistence/InvitedRegistrationDAO.java | 29 ++++++++++++++ .../ia2/gms/persistence/MembershipsDAO.java | 4 ++ .../ia2/gms/persistence/PermissionsDAO.java | 6 ++- .../inaf/ia2/gms/service/GroupsService.java | 7 +++- .../NestedGroupsIntegrationTest.java | 3 +- 13 files changed, 101 insertions(+), 21 deletions(-) diff --git a/database/Dockerfile b/database/Dockerfile index d73d745..28a49e7 100644 --- a/database/Dockerfile +++ b/database/Dockerfile @@ -1,4 +1,5 @@ FROM library/postgres:11 COPY gms/src/main/resources/sql/init.sql /docker-entrypoint-initdb.d/ COPY database/user.sql /docker-entrypoint-initdb.d/ +ENV ALLOW_IP_RANGE=0.0.0.0/0 ENV POSTGRES_HOST_AUTH_METHOD=trust diff --git a/gms-client/gms-client-lib/pom.xml b/gms-client/gms-client-lib/pom.xml index b05f489..571ed7f 100644 --- a/gms-client/gms-client-lib/pom.xml +++ b/gms-client/gms-client-lib/pom.xml @@ -11,6 +11,11 @@ <maven.compiler.target>12</maven.compiler.target> </properties> <dependencies> + <dependency> + <groupId>org.apache.logging.log4j</groupId> + <artifactId>log4j-to-slf4j</artifactId> + <version>2.12.1</version> + </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> diff --git a/gms-client/gms-client-lib/src/main/java/it/inaf/ia2/gms/client/call/BaseGmsCall.java b/gms-client/gms-client-lib/src/main/java/it/inaf/ia2/gms/client/call/BaseGmsCall.java index 161de1f..f5304b7 100644 --- a/gms-client/gms-client-lib/src/main/java/it/inaf/ia2/gms/client/call/BaseGmsCall.java +++ b/gms-client/gms-client-lib/src/main/java/it/inaf/ia2/gms/client/call/BaseGmsCall.java @@ -6,12 +6,12 @@ import java.net.http.HttpRequest; import java.net.http.HttpRequest.Builder; import java.net.http.HttpResponse; import java.util.Scanner; -import java.util.logging.Level; -import java.util.logging.Logger; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public abstract class BaseGmsCall { - private static final Logger LOGGER = Logger.getLogger(BaseGmsCall.class.getName()); + private static final Logger LOGGER = LoggerFactory.getLogger(BaseGmsCall.class); protected final HttpClientWrapper clientWrapper; @@ -28,18 +28,17 @@ public abstract class BaseGmsCall { } protected static void logServerError(HttpRequest request, HttpResponse<String> response) { - LOGGER.log(Level.SEVERE, () -> "Error while reading " + request.uri() + LOGGER.error("Error while reading " + request.uri() + "\nServer response status code is " + response.statusCode() + "\nServer response text is " + response.body()); } protected static void logServerErrorInputStream(HttpRequest request, HttpResponse<InputStream> response) { - LOGGER.log(Level.SEVERE, () -> { - Scanner s = new Scanner(response.body()).useDelimiter("\\A"); - String responseBody = s.hasNext() ? s.next() : ""; - return "Error while reading " + request.uri() - + "\nServer response status code is " + response.statusCode() - + "\nServer response text is " + responseBody; - }); + Scanner s = new Scanner(response.body()).useDelimiter("\\A"); + String responseBody = s.hasNext() ? s.next() : ""; + String error = "Error while reading " + request.uri() + + "\nServer response status code is " + response.statusCode() + + "\nServer response text is " + responseBody; + LOGGER.error(error); } } diff --git a/gms-ui/src/components/GroupsBreadcrumb.vue b/gms-ui/src/components/GroupsBreadcrumb.vue index f1e6f6c..c638b20 100644 --- a/gms-ui/src/components/GroupsBreadcrumb.vue +++ b/gms-ui/src/components/GroupsBreadcrumb.vue @@ -6,7 +6,7 @@ <span v-if="group.active">{{group.groupName}}</span> </li> </ol> - <a :href="'group/status/' + currentGroup.groupId" :download="currentGroup.groupName + '.csv'" id="csv-status-download" title="Download CSV"> + <a v-if="currentGroup" :href="'group/status/' + currentGroup.groupId" :download="currentGroup.groupName + '.csv'" id="csv-status-download" title="Download CSV"> <font-awesome-icon icon="download"></font-awesome-icon> </a> </nav> diff --git a/gms-ui/src/components/MembersPanel.vue b/gms-ui/src/components/MembersPanel.vue index 335d23d..eb71f91 100644 --- a/gms-ui/src/components/MembersPanel.vue +++ b/gms-ui/src/components/MembersPanel.vue @@ -7,7 +7,7 @@ <User :user="member" :anchor="false" /> </div> <span v-if="model.permission === 'ADMIN' || model.permission === 'MANAGE_MEMBERS'" class="float-right"> - <a href="#" v-on:click.stop="openRemoveMemberModal(member)" class="text-danger" title="Remove member"> + <a href="#" v-on:click.stop.prevent="openRemoveMemberModal(member)" class="text-danger" title="Remove member"> <font-awesome-icon icon="trash"></font-awesome-icon> </a> </span> diff --git a/gms-ui/src/components/modals/AddGroupModal.vue b/gms-ui/src/components/modals/AddGroupModal.vue index 8850297..e48328f 100644 --- a/gms-ui/src/components/modals/AddGroupModal.vue +++ b/gms-ui/src/components/modals/AddGroupModal.vue @@ -27,7 +27,7 @@ export default { return { newGroupName: '', newGroupNameError: '', - leaf: false + leaf: true }; }, methods: { @@ -37,6 +37,7 @@ export default { }, afterShow: function() { this.$refs.newGroupNameInput.focus(); + this.leaf = true; }, resetError: function() { this.newGroupNameError = null; diff --git a/gms/src/main/java/it/inaf/ia2/gms/controller/HomePageController.java b/gms/src/main/java/it/inaf/ia2/gms/controller/HomePageController.java index bb5240f..ab10140 100644 --- a/gms/src/main/java/it/inaf/ia2/gms/controller/HomePageController.java +++ b/gms/src/main/java/it/inaf/ia2/gms/controller/HomePageController.java @@ -1,12 +1,19 @@ package it.inaf.ia2.gms.controller; import it.inaf.ia2.gms.authn.SessionData; +import it.inaf.ia2.gms.exception.UnauthorizedException; import it.inaf.ia2.gms.manager.InvitedRegistrationManager; +import it.inaf.ia2.gms.model.GroupBreadcrumb; +import it.inaf.ia2.gms.model.GroupNode; +import it.inaf.ia2.gms.model.Permission; import it.inaf.ia2.gms.model.request.GroupsRequest; import it.inaf.ia2.gms.model.response.GroupsTabResponse; import it.inaf.ia2.gms.model.response.HomePageResponse; +import it.inaf.ia2.gms.model.response.PaginatedData; import it.inaf.ia2.gms.persistence.model.InvitedRegistration; import java.io.IOException; +import java.util.ArrayList; +import java.util.List; import java.util.Optional; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; @@ -41,14 +48,37 @@ public class HomePageController { response.setUser(session.getUserName()); - GroupsTabResponse groupsTabResponse = groupsTabResponseBuilder.getGroupsTab(request); - response.setBreadcrumbs(groupsTabResponse.getBreadcrumbs()); - response.setGroupsPanel(groupsTabResponse.getGroupsPanel()); - response.setPermission(groupsTabResponse.getPermission()); + try { + GroupsTabResponse groupsTabResponse = groupsTabResponseBuilder.getGroupsTab(request); + response.setBreadcrumbs(groupsTabResponse.getBreadcrumbs()); + response.setGroupsPanel(groupsTabResponse.getGroupsPanel()); + response.setPermission(groupsTabResponse.getPermission()); + } catch (UnauthorizedException ex) { + if ("ROOT".equals(request.getGroupId())) { + response.setBreadcrumbs(getRootBreadcrumbs()); + response.setGroupsPanel(getEmptyGroupsPanel(request)); + response.setPermission(Permission.TRAVERSE); + } else { + throw ex; + } + } return ResponseEntity.ok(response); } + private List<GroupBreadcrumb> getRootBreadcrumbs() { + List<GroupBreadcrumb> breadcrumbs = new ArrayList<>(); + GroupBreadcrumb breadcrumb = new GroupBreadcrumb(); + breadcrumb.setGroupId("ROOT"); + breadcrumb.setGroupName("ROOT"); + breadcrumbs.add(breadcrumb); + return breadcrumbs; + } + + private PaginatedData<GroupNode> getEmptyGroupsPanel(GroupsRequest request) { + return new PaginatedData<>(new ArrayList<>(), 1, request.getPaginatorPageSize()); + } + @GetMapping(value = "/", produces = MediaType.TEXT_HTML_VALUE) public String index(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { diff --git a/gms/src/main/java/it/inaf/ia2/gms/manager/GroupStatusManager.java b/gms/src/main/java/it/inaf/ia2/gms/manager/GroupStatusManager.java index 07cbb42..7e75650 100644 --- a/gms/src/main/java/it/inaf/ia2/gms/manager/GroupStatusManager.java +++ b/gms/src/main/java/it/inaf/ia2/gms/manager/GroupStatusManager.java @@ -55,6 +55,7 @@ public class GroupStatusManager extends UserAwareComponent { } List<GroupEntity> groups = groupsDAO.getAllChildren(parentGroup.getPath()); + groups.add(parentGroup); List<String> names = groupNameService.getGroupsNames(groups); diff --git a/gms/src/main/java/it/inaf/ia2/gms/persistence/InvitedRegistrationDAO.java b/gms/src/main/java/it/inaf/ia2/gms/persistence/InvitedRegistrationDAO.java index 5fb1057..af61db9 100644 --- a/gms/src/main/java/it/inaf/ia2/gms/persistence/InvitedRegistrationDAO.java +++ b/gms/src/main/java/it/inaf/ia2/gms/persistence/InvitedRegistrationDAO.java @@ -5,8 +5,10 @@ import it.inaf.ia2.gms.persistence.model.InvitedRegistration; import java.sql.PreparedStatement; import java.sql.Types; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.stream.Collectors; import javax.sql.DataSource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; @@ -114,4 +116,31 @@ public class InvitedRegistrationDAO { return ps; }); } + + /** + * Called before deleting a group. + */ + public void deleteAllGroupsInvitedRegistrations(List<String> groupIds) { + + if (groupIds.isEmpty()) { + return; + } + + String sql = "DELETE FROM invited_registration_request_group WHERE group_id = (" + + String.join(",", groupIds.stream().map(g -> "?").collect(Collectors.toList())) + + ")"; + + jdbcTemplate.update(conn -> { + PreparedStatement ps = conn.prepareStatement(sql); + int i = 0; + for (String groupId : groupIds) { + ps.setString(++i, groupId); + } + return ps; + }); + + // Cleanup orphan invited requests + jdbcTemplate.update("DELETE FROM invited_registration_request WHERE id NOT IN " + + "(SELECT request_id FROM invited_registration_request_group)"); + } } diff --git a/gms/src/main/java/it/inaf/ia2/gms/persistence/MembershipsDAO.java b/gms/src/main/java/it/inaf/ia2/gms/persistence/MembershipsDAO.java index 22b0811..d08faf4 100644 --- a/gms/src/main/java/it/inaf/ia2/gms/persistence/MembershipsDAO.java +++ b/gms/src/main/java/it/inaf/ia2/gms/persistence/MembershipsDAO.java @@ -151,6 +151,10 @@ public class MembershipsDAO { public void deleteAllGroupsMembership(List<String> groupIds) { + if (groupIds.isEmpty()) { + return; + } + String sql = "DELETE FROM gms_membership WHERE group_id IN (" + String.join(",", groupIds.stream().map(g -> "?").collect(Collectors.toList())) + ")"; diff --git a/gms/src/main/java/it/inaf/ia2/gms/persistence/PermissionsDAO.java b/gms/src/main/java/it/inaf/ia2/gms/persistence/PermissionsDAO.java index 4ffd9b9..48bc56e 100644 --- a/gms/src/main/java/it/inaf/ia2/gms/persistence/PermissionsDAO.java +++ b/gms/src/main/java/it/inaf/ia2/gms/persistence/PermissionsDAO.java @@ -46,7 +46,7 @@ public class PermissionsDAO { String sql = "UPDATE gms_permission SET permission = ? WHERE group_id = ? AND user_id = ? AND group_path = ?"; userPermission.setPermission(newPermission); - + jdbcTemplate.update(conn -> { PreparedStatement ps = conn.prepareStatement(sql); ps.setObject(1, userPermission.getPermission().toString(), Types.OTHER); @@ -164,6 +164,10 @@ public class PermissionsDAO { public void deleteAllGroupsPermissions(List<String> groupIds) { + if (groupIds.isEmpty()) { + return; + } + String sql = "DELETE FROM gms_permission WHERE group_id IN (" + String.join(",", groupIds.stream().map(g -> "?").collect(Collectors.toList())) + ")"; diff --git a/gms/src/main/java/it/inaf/ia2/gms/service/GroupsService.java b/gms/src/main/java/it/inaf/ia2/gms/service/GroupsService.java index 6ae23bb..14d503e 100644 --- a/gms/src/main/java/it/inaf/ia2/gms/service/GroupsService.java +++ b/gms/src/main/java/it/inaf/ia2/gms/service/GroupsService.java @@ -6,6 +6,7 @@ import it.inaf.ia2.gms.model.GroupBreadcrumb; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import it.inaf.ia2.gms.persistence.GroupsDAO; +import it.inaf.ia2.gms.persistence.InvitedRegistrationDAO; import it.inaf.ia2.gms.persistence.LoggingDAO; import it.inaf.ia2.gms.persistence.MembershipsDAO; import it.inaf.ia2.gms.persistence.PermissionsDAO; @@ -23,14 +24,17 @@ public class GroupsService { private final GroupsDAO groupsDAO; private final PermissionsDAO permissionsDAO; private final MembershipsDAO membershipsDAO; + private final InvitedRegistrationDAO invitedRegistrationDAO; private final LoggingDAO loggingDAO; @Autowired public GroupsService(GroupsDAO groupsDAO, PermissionsDAO permissionsDAO, - MembershipsDAO membershipsDAO, LoggingDAO loggingDAO) { + MembershipsDAO membershipsDAO, InvitedRegistrationDAO invitedRegistrationDAO, + LoggingDAO loggingDAO) { this.groupsDAO = groupsDAO; this.permissionsDAO = permissionsDAO; this.membershipsDAO = membershipsDAO; + this.invitedRegistrationDAO = invitedRegistrationDAO; this.loggingDAO = loggingDAO; createRootIfNecessary(); } @@ -105,6 +109,7 @@ public class GroupsService { List<String> groupsToDeleteIds = groupsToDelete.stream() .map(g -> g.getId()).collect(Collectors.toList()); + invitedRegistrationDAO.deleteAllGroupsInvitedRegistrations(groupsToDeleteIds); membershipsDAO.deleteAllGroupsMembership(groupsToDeleteIds); permissionsDAO.deleteAllGroupsPermissions(groupsToDeleteIds); diff --git a/gms/src/test/java/it/inaf/ia2/gms/persistence/NestedGroupsIntegrationTest.java b/gms/src/test/java/it/inaf/ia2/gms/persistence/NestedGroupsIntegrationTest.java index 21d437e..baa08c1 100644 --- a/gms/src/test/java/it/inaf/ia2/gms/persistence/NestedGroupsIntegrationTest.java +++ b/gms/src/test/java/it/inaf/ia2/gms/persistence/NestedGroupsIntegrationTest.java @@ -46,10 +46,11 @@ public class NestedGroupsIntegrationTest { GroupsDAO groupsDAO = new GroupsDAO(dataSource); PermissionsDAO permissionsDAO = new PermissionsDAO(dataSource); MembershipsDAO membershipsDAO = new MembershipsDAO(dataSource); + InvitedRegistrationDAO invitedRegistrationDAO = new InvitedRegistrationDAO(dataSource); PermissionsService permissionsService = new PermissionsService(permissionsDAO, loggingDAO); PermissionsManager permissionsManager = new PermissionsManager(permissionsService, rapClient, loggingDAO); UserAwareComponentTestUtil.setUser(permissionsManager, userId); - GroupsService groupsService = new GroupsService(groupsDAO, permissionsDAO, membershipsDAO, loggingDAO); + GroupsService groupsService = new GroupsService(groupsDAO, permissionsDAO, membershipsDAO, invitedRegistrationDAO, loggingDAO); GroupsManager groupsManager = new GroupsManager(groupsService, permissionsManager, loggingDAO); GroupsTreeBuilder groupsTreeBuilder = new GroupsTreeBuilder(groupsDAO, permissionsDAO); -- GitLab