Commit cd5726d6 authored by Sonia Zorba's avatar Sonia Zorba
Browse files

Removed JPA and used Postgresql ltree extension

parent d2d3a98b
Pipeline #258 failed with stages
......@@ -34,14 +34,14 @@
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.2.6</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
......@@ -58,11 +58,6 @@
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.zonky.test</groupId>
<artifactId>embedded-database-spring-test</artifactId>
......
package it.inaf.ia2.gms.authn;
import it.inaf.ia2.gms.persistence.UsersRepository;
import it.inaf.ia2.gms.persistence.model.User;
import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
......@@ -16,9 +14,6 @@ public class SessionData {
@Autowired
private HttpServletRequest request;
@Autowired
private UsersRepository usersRepository;
private String userId;
private String accessToken;
......@@ -27,12 +22,6 @@ public class SessionData {
CustomAuthenticationData authn = (CustomAuthenticationData) ((OAuth2Authentication) request.getUserPrincipal()).getUserAuthentication();
userId = (String) authn.getPrincipal();
accessToken = (String) authn.getAccessToken().getValue();
if (!usersRepository.findById(userId).isPresent()) {
User user = new User();
user.setId(userId);
usersRepository.save(user);
}
}
public String getUserId() {
......
......@@ -8,12 +8,10 @@ import it.inaf.ia2.gms.model.GroupsModelResponse;
import it.inaf.ia2.gms.model.PaginatedData;
import it.inaf.ia2.gms.model.PaginatedModelRequest;
import it.inaf.ia2.gms.model.RenameGroupRequest;
import it.inaf.ia2.gms.persistence.model.Group;
import it.inaf.ia2.gms.persistence.model.User;
import it.inaf.ia2.gms.service.GroupsModelService;
import it.inaf.ia2.gms.persistence.model.GroupEntity;
import it.inaf.ia2.gms.service.GroupsModelBuilder;
import it.inaf.ia2.gms.service.GroupsService;
import it.inaf.ia2.gms.service.UsersService;
import java.util.List;
import it.inaf.ia2.gms.service.GroupsTreeBuilder;
import javax.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
......@@ -34,13 +32,13 @@ public class GroupsController {
private SessionData session;
@Autowired
private UsersService usersService;
private GroupsService groupsService;
@Autowired
private GroupsModelService groupsModelService;
private GroupsModelBuilder groupsModelService;
@Autowired
private GroupsService groupsService;
private GroupsTreeBuilder groupsTreeBuilder;
@GetMapping(value = "/groups", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public GroupsModelResponse getGroupsModelResponse(@Valid GroupsModelRequest groupsModelRequest) {
......@@ -50,10 +48,9 @@ public class GroupsController {
@PostMapping(value = "/group", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public ResponseEntity<PaginatedData<GroupNode>> createGroup(@Valid @RequestBody CreateGroupRequest request) {
User user = getUser();
Group newGroup = groupsService.addGroup(request.getParentGroupId(), request.getNewGroupName(), user);
GroupEntity newGroup = groupsService.addGroup(request.getParentGroupId(), request.getNewGroupName(), session.getUserId());
PaginatedData<GroupNode> groupsPanel = getGroupsPanel(newGroup.getParentGroup(), request, user);
PaginatedData<GroupNode> groupsPanel = getGroupsPanel(request.getParentGroupId(), request);
return new ResponseEntity<>(groupsPanel, HttpStatus.CREATED);
}
......@@ -61,10 +58,11 @@ public class GroupsController {
@PutMapping(value = "/group/{groupId}", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public ResponseEntity<PaginatedData<GroupNode>> renameGroup(@PathVariable("groupId") String groupId, @Valid @RequestBody RenameGroupRequest request) {
User user = getUser();
Group renamedGroup = groupsService.renameGroup(groupId, request.getNewGroupName(), user);
GroupEntity renamedGroup = groupsService.renameGroup(groupId, request.getNewGroupName(), session.getUserId());
GroupEntity parent = groupsService.getGroupByPath(renamedGroup.getParentPath());
PaginatedData<GroupNode> groupsPanel = getGroupsPanel(renamedGroup.getParentGroup(), request, user);
PaginatedData<GroupNode> groupsPanel = getGroupsPanel(parent.getId(), request);
return ResponseEntity.ok(groupsPanel);
}
......@@ -72,20 +70,14 @@ public class GroupsController {
@DeleteMapping(value = "/group/{groupId}", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public ResponseEntity<?> deleteGroup(@PathVariable("groupId") String groupId, PaginatedModelRequest request) {
User user = getUser();
Group parent = groupsService.deleteGroup(groupId, user);
GroupEntity parent = groupsService.deleteGroup(groupId, session.getUserId());
PaginatedData<GroupNode> groupsPanel = getGroupsPanel(parent, request, user);
PaginatedData<GroupNode> groupsPanel = getGroupsPanel(parent.getId(), request);
return ResponseEntity.ok(groupsPanel);
}
private User getUser() {
return usersService.getUserById(session.getUserId());
}
private PaginatedData<GroupNode> getGroupsPanel(Group parentGroup, PaginatedModelRequest paginatedRequest, User user) {
List<GroupNode> groupNodes = groupsService.getSubgroups(parentGroup, user);
return new PaginatedData<>(groupNodes, paginatedRequest.getPaginatorPage(), paginatedRequest.getPaginatorPageSize());
private PaginatedData<GroupNode> getGroupsPanel(String parentGroupId, PaginatedModelRequest paginatedRequest) {
return groupsTreeBuilder.listSubGroups(parentGroupId, session.getUserId(), paginatedRequest);
}
}
......@@ -2,9 +2,7 @@ package it.inaf.ia2.gms.controller;
import it.inaf.ia2.gms.authn.SessionData;
import it.inaf.ia2.gms.model.Permission;
import it.inaf.ia2.gms.persistence.model.User;
import it.inaf.ia2.gms.service.PermissionsService;
import it.inaf.ia2.gms.service.UsersService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
......@@ -18,19 +16,11 @@ public class PermissionsController {
@Autowired
private SessionData session;
@Autowired
private UsersService usersService;
@Autowired
private PermissionsService permissionsService;
@DeleteMapping(value = "/permission", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public ResponseEntity deletePermission(@RequestParam("user") String userId, @RequestParam("group") String group, @RequestParam("permission") Permission permission) {
User user = getUser();
return null;
}
private User getUser() {
return usersService.getUserById(session.getUserId());
}
}
package it.inaf.ia2.gms.model;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class GroupNode {
private String groupId;
private String groupName;
private Set<Permission> permissions;
private Permission permission;
private boolean hasChildren;
public GroupNode() {
permissions = new HashSet<>();
}
public String getGroupId() {
return groupId;
}
......@@ -33,44 +23,12 @@ public class GroupNode {
this.groupName = groupName;
}
public List<Permission> getPermissions() {
return Collections.unmodifiableList(new ArrayList<>(permissions));
public Permission getPermission() {
return permission;
}
public void setPermissions(Set<Permission> permissions) {
this.permissions = permissions;
}
public void addPermission(Permission permission) {
// remove implied permissions
switch (permission) {
case ADMIN:
permissions.add(permission);
permissions.remove(Permission.MANAGE_MEMBERS);
permissions.remove(Permission.VIEW_MEMBERS);
permissions.remove(Permission.TRAVERSE);
break;
case MANAGE_MEMBERS:
if (!permissions.contains(Permission.ADMIN)) {
permissions.add(permission);
permissions.remove(Permission.VIEW_MEMBERS);
permissions.remove(Permission.TRAVERSE);
}
break;
case VIEW_MEMBERS:
if (!permissions.contains(Permission.ADMIN)
&& !permissions.contains(Permission.MANAGE_MEMBERS)) {
permissions.add(permission);
permissions.remove(Permission.TRAVERSE);
}
break;
case TRAVERSE:
if (permissions.isEmpty()) {
permissions.add(permission);
}
break;
}
public void setPermission(Permission permission) {
this.permission = permission;
}
public boolean isHasChildren() {
......
......@@ -9,7 +9,7 @@ public class GroupsModelResponse extends BaseModelResponse {
private PaginatedData<RapUser> membersPanel;
private PaginatedData<UserPermission> permissionsPanel;
// current group permissions
private List<Permission> permissions;
private Permission permission;
public List<GroupBreadcrumb> getBreadcrumbs() {
return breadcrumbs;
......@@ -43,11 +43,11 @@ public class GroupsModelResponse extends BaseModelResponse {
this.permissionsPanel = permissionsPanel;
}
public List<Permission> getPermissions() {
return permissions;
public Permission getPermission() {
return permission;
}
public void setPermissions(List<Permission> permissions) {
this.permissions = permissions;
public void setPermission(Permission permission) {
this.permission = permission;
}
}
......@@ -5,5 +5,31 @@ public enum Permission {
ADMIN,
MANAGE_MEMBERS,
VIEW_MEMBERS,
TRAVERSE
TRAVERSE;
/**
* Updates the permission keeping the priority (e.g. MANAGE_MEMBERS
* overrides VIEW_MEMBERS, but not the opposite).
*/
public static Permission addPermission(Permission oldPermission, Permission newPermission) {
if (oldPermission == null) {
return newPermission;
}
switch (newPermission) {
case ADMIN:
return ADMIN;
case MANAGE_MEMBERS:
if (oldPermission != Permission.ADMIN) {
return MANAGE_MEMBERS;
}
case VIEW_MEMBERS:
if (oldPermission == Permission.TRAVERSE) {
return VIEW_MEMBERS;
}
}
return oldPermission;
}
}
package it.inaf.ia2.gms.persistence;
import it.inaf.ia2.gms.persistence.model.NewGroup;
import it.inaf.ia2.gms.model.GroupBreadcrumb;
import it.inaf.ia2.gms.persistence.model.GroupEntity;
import java.sql.PreparedStatement;
import java.sql.Types;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import javax.sql.DataSource;
......@@ -24,7 +26,7 @@ public class GroupsDAO {
jdbcTemplate = new JdbcTemplate(dataSource);
}
public NewGroup createGroup(NewGroup group) {
public GroupEntity createGroup(GroupEntity group) {
String sql = "INSERT INTO gms_group (id, name, path) VALUES (?, ?, ?)";
......@@ -39,12 +41,67 @@ public class GroupsDAO {
return group;
}
public GroupEntity updateGroup(GroupEntity group) {
String sql = "UPDATE gms_group SET name = ?, path = ? WHERE id = ?";
jdbcTemplate.update(conn -> {
PreparedStatement ps = conn.prepareStatement(sql);
ps.setString(1, group.getName());
ps.setObject(2, group.getPath(), Types.OTHER);
ps.setString(3, group.getId());
return ps;
});
return group;
}
public void deleteGroupById(String groupId) {
String sql = "DELETE FROM gms_group WHERE id = ?";
jdbcTemplate.update(sql, groupId);
}
public List<NewGroup> listSubGroups(String path) {
public Optional<GroupEntity> findGroupById(String groupId) {
String sql = "SELECT id, name, path from gms_group WHERE id = ?";
return jdbcTemplate.query(conn -> {
PreparedStatement ps = conn.prepareStatement(sql);
ps.setString(1, groupId);
return ps;
}, resultSet -> {
if (resultSet.next()) {
GroupEntity group = new GroupEntity();
group.setId(resultSet.getString("id"));
group.setName(resultSet.getString("name"));
group.setPath(resultSet.getString("path"));
return Optional.of(group);
}
return Optional.empty();
});
}
public Optional<GroupEntity> findGroupByPath(String path) {
String sql = "SELECT id, name from gms_group WHERE path = ?";
return jdbcTemplate.query(conn -> {
PreparedStatement ps = conn.prepareStatement(sql);
ps.setObject(1, path, Types.OTHER);
return ps;
}, resultSet -> {
if (resultSet.next()) {
GroupEntity group = new GroupEntity();
group.setId(resultSet.getString("id"));
group.setName(resultSet.getString("name"));
group.setPath(path);
return Optional.of(group);
}
return Optional.empty();
});
}
public List<GroupEntity> listSubGroups(String path) {
String sql = "SELECT id, name, path from gms_group WHERE path ~ ? ORDER BY name";
......@@ -53,9 +110,9 @@ public class GroupsDAO {
ps.setObject(1, getSubGroupsPath(path), Types.OTHER);
return ps;
}, resultSet -> {
List<NewGroup> groups = new ArrayList<>();
List<GroupEntity> groups = new ArrayList<>();
while (resultSet.next()) {
NewGroup group = new NewGroup();
GroupEntity group = new GroupEntity();
group.setId(resultSet.getString("id"));
group.setName(resultSet.getString("name"));
group.setPath(resultSet.getString("path"));
......@@ -98,4 +155,37 @@ public class GroupsDAO {
return map;
});
}
/**
* Returns the number of groups.
*/
public long count() {
String sql = "SELECT COUNT(*) FROM gms_group";
return jdbcTemplate.query(sql, resultSet -> {
resultSet.next();
return resultSet.getLong(1);
});
}
public List<GroupBreadcrumb> getBreadcrumbs(String path) {
String sql = "SELECT id, name FROM gms_group WHERE path @> ? ORDER BY length(path::varchar) ASC";
return jdbcTemplate.query(conn -> {
PreparedStatement ps = conn.prepareStatement(sql);
ps.setObject(1, path, Types.OTHER);
return ps;
}, resultSet -> {
List<GroupBreadcrumb> breadcrumbs = new ArrayList<>();
while (resultSet.next()) {
GroupBreadcrumb bc = new GroupBreadcrumb();
bc.setGroupId(resultSet.getString("id"));
bc.setGroupName(resultSet.getString("name"));
breadcrumbs.add(bc);
}
return breadcrumbs;
});
}
}
package it.inaf.ia2.gms.persistence;
import it.inaf.ia2.gms.persistence.model.Group;
import java.util.List;
import javax.transaction.Transactional;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
@Transactional
public interface GroupsRepository extends JpaRepository<Group, String> {
List<Group> findByParentGroup(Group parent);
}
package it.inaf.ia2.gms.persistence;
import it.inaf.ia2.gms.persistence.model.Group;
import it.inaf.ia2.gms.persistence.model.Membership;
import it.inaf.ia2.gms.persistence.model.MembershipId;
import it.inaf.ia2.gms.persistence.model.User;
import java.util.List;
import javax.transaction.Transactional;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
@Transactional
public interface MembershipRepository extends JpaRepository<Membership, MembershipId> {
List<Membership> findBy_user(User user);
List<Membership> findBy_group(Group group);
}
package it.inaf.ia2.gms.persistence;
import it.inaf.ia2.gms.persistence.model.MembershipEntity;
import java.util.List;
import org.springframework.stereotype.Component;
@Component
public class MembershipsDAO {
public List<MembershipEntity> findByGroup(String groupId) {
throw new UnsupportedOperationException("TODO");
}
}
package it.inaf.ia2.gms.persistence;
import it.inaf.ia2.gms.model.Permission;
import it.inaf.ia2.gms.persistence.model.UserPermission;
import it.inaf.ia2.gms.persistence.model.PermissionEntity;
import java.sql.PreparedStatement;
import java.sql.Types;
import java.util.ArrayList;
......@@ -21,51 +21,100 @@ public class PermissionsDAO {
jdbcTemplate = new JdbcTemplate(dataSource);
}
public UserPermission createPermission(UserPermission userPermission) {
public PermissionEntity createPermission(PermissionEntity userPermission) {
String sql = "INSERT INTO gms_permission(group_id, user_id, permission) VALUES(?, ?, ?)";
String sql = "INSERT INTO gms_permission(group_id, user_id, permission, group_path) VALUES(?, ?, ?, ?)";
jdbcTemplate.update(conn -> {
PreparedStatement ps = conn.prepareStatement(sql);
ps.setString(1, userPermission.getGroupId());
ps.setString(2, userPermission.getUserId());
ps.setObject(3, userPermission.getPermission().toString(), Types.OTHER);
ps.setObject(4, userPermission.getGroupPath(), Types.OTHER);
return ps;
});
return userPermission;
}
public List<UserPermission> findUserPermissions(String userId) {
public List<PermissionEntity> findUserPermissions(String userId) {
String sql = "SELECT group_id, permission FROM gms_permission WHERE user_id = ?";
String sql = "SELECT group_id, permission, group_path FROM gms_permission WHERE user_id = ?";
return jdbcTemplate.query(conn -> {
PreparedStatement ps = conn.prepareStatement(sql);
ps.setString(1, userId);
return ps;
}, resultSet -> {
List<UserPermission> permissions = new ArrayList<>();
List<PermissionEntity> permissions = new ArrayList<>();
while (resultSet.next()) {
UserPermission permission = new UserPermission();
PermissionEntity permission = new PermissionEntity();
permission.setGroupId(resultSet.getString("group_id"));
permission.setUserId(userId);
permission.setPermission(Permission.valueOf(resultSet.getString("permission")));
permission.setGroupPath(resultSet.getString("group_path"));
permissions.add(permission);
}
return permissions;
});
}
public void deletePermission(UserPermission userPermission) {
public List<PermissionEntity> findUserPermissions(String userId, String path) {
String sql = "SELECT group_id, permission, group_path FROM gms_permission WHERE user_id = ?\n"
+ "AND (group_path <@ ? OR group_path @> ?)";
return jdbcTemplate.query(conn -> {
PreparedStatement ps = conn.prepareStatement(sql);
ps.setString(1, userId);
ps.setObject(2, path, Types.OTHER);
ps.setObject(3, path, Types.OTHER);
return ps;
}, resultSet -> {
List<PermissionEntity> permissions = new ArrayList<>();
while (resultSet.next()) {
PermissionEntity permission = new PermissionEntity();
permission.setGroupId(resultSet.getString("group_id"));
permission.setUserId(userId);
permission.setPermission(Permission.valueOf(resultSet.getString("permission")));
permission.setGroupPath(resultSet.getString("group_path"));
permissions.add(permission);
}