diff --git a/gms/src/main/java/it/inaf/ia2/gms/authn/CustomAuthenticationData.java b/gms/src/main/java/it/inaf/ia2/gms/authn/CustomAuthenticationData.java index 66f86bcd9e2ba89e3548ac0e06986747d0d52bfd..71c9da2c349c61dec4ec7d359bf91a55538a154c 100644 --- a/gms/src/main/java/it/inaf/ia2/gms/authn/CustomAuthenticationData.java +++ b/gms/src/main/java/it/inaf/ia2/gms/authn/CustomAuthenticationData.java @@ -4,17 +4,33 @@ import java.util.Collection; import java.util.Map; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.oauth2.common.OAuth2AccessToken; +import org.springframework.security.oauth2.common.OAuth2RefreshToken; public class CustomAuthenticationData extends UsernamePasswordAuthenticationToken { private final Map<String, Object> attributes; + private final OAuth2AccessToken accessToken; + private final OAuth2RefreshToken refreshToken; - public CustomAuthenticationData(String username, Map<String, Object> attributes, Collection<? extends GrantedAuthority> authorities) { + public CustomAuthenticationData(String username, Map<String, Object> attributes, + Collection<? extends GrantedAuthority> authorities, + OAuth2AccessToken accessToken, OAuth2RefreshToken refreshToken) { super(username, "N/A", authorities); this.attributes = attributes; + this.accessToken = accessToken; + this.refreshToken = refreshToken; } public Map<String, Object> getAttributes() { return attributes; } + + public OAuth2AccessToken getAccessToken() { + return accessToken; + } + + public OAuth2RefreshToken getRefreshToken() { + return refreshToken; + } } diff --git a/gms/src/main/java/it/inaf/ia2/gms/authn/CustomIdTokenConverter.java b/gms/src/main/java/it/inaf/ia2/gms/authn/CustomIdTokenConverter.java index d3decd339b8cf51a1d9fa84c0006b68800ba873b..7d0bc239c842bc738fe100c86cc38e5aec3fab34 100644 --- a/gms/src/main/java/it/inaf/ia2/gms/authn/CustomIdTokenConverter.java +++ b/gms/src/main/java/it/inaf/ia2/gms/authn/CustomIdTokenConverter.java @@ -6,6 +6,7 @@ import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.AuthorityUtils; import org.springframework.security.oauth2.common.OAuth2AccessToken; +import org.springframework.security.oauth2.common.OAuth2RefreshToken; import org.springframework.security.oauth2.provider.token.DefaultUserAuthenticationConverter; import org.springframework.security.oauth2.provider.token.store.jwk.JwkTokenStore; @@ -25,12 +26,12 @@ public class CustomIdTokenConverter extends DefaultUserAuthenticationConverter { OAuth2AccessToken token = jwkTokenStore.readAccessToken(idToken); Map<String, Object> claims = token.getAdditionalInformation(); - //OAuth2RefreshToken refreshToken = token.getRefreshToken(); + OAuth2RefreshToken refreshToken = token.getRefreshToken(); String principal = (String) claims.get("sub"); List<GrantedAuthority> authorities = AuthorityUtils.createAuthorityList("ROLE_USER"); - return new CustomAuthenticationData(principal, claims, authorities); + return new CustomAuthenticationData(principal, claims, authorities, token, refreshToken); } } diff --git a/gms/src/main/java/it/inaf/ia2/gms/authn/LoginController.java b/gms/src/main/java/it/inaf/ia2/gms/authn/LoginController.java index 6e0b895164d8a49eb48e5103131813298b7b9d69..190aaf038f5bb56c593a14442d9c9455e4518c94 100644 --- a/gms/src/main/java/it/inaf/ia2/gms/authn/LoginController.java +++ b/gms/src/main/java/it/inaf/ia2/gms/authn/LoginController.java @@ -1,6 +1,7 @@ package it.inaf.ia2.gms.authn; import java.security.Principal; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @@ -8,6 +9,9 @@ import org.springframework.web.bind.annotation.RestController; @RestController public class LoginController { + @Autowired + private SessionData sessionData; + @GetMapping("/login") public Principal start(Principal principal) { return principal; diff --git a/gms/src/main/java/it/inaf/ia2/gms/authn/SecurityConfig.java b/gms/src/main/java/it/inaf/ia2/gms/authn/SecurityConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..130505eda977da570488e320b1d32dcf8530abaf --- /dev/null +++ b/gms/src/main/java/it/inaf/ia2/gms/authn/SecurityConfig.java @@ -0,0 +1,16 @@ +package it.inaf.ia2.gms.authn; + +import org.springframework.context.annotation.Configuration; +import org.springframework.core.annotation.Order; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; + +@Configuration +@Order(1000) +public class SecurityConfig extends WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) throws Exception { + http.csrf().disable(); + } +} diff --git a/gms/src/main/java/it/inaf/ia2/gms/authn/SessionData.java b/gms/src/main/java/it/inaf/ia2/gms/authn/SessionData.java new file mode 100644 index 0000000000000000000000000000000000000000..5a82085919f2548f299634a278583492fb18e3bc --- /dev/null +++ b/gms/src/main/java/it/inaf/ia2/gms/authn/SessionData.java @@ -0,0 +1,41 @@ +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; +import org.springframework.security.oauth2.provider.OAuth2Authentication; +import org.springframework.stereotype.Component; +import org.springframework.web.context.annotation.SessionScope; + +@Component +@SessionScope +public class SessionData { + + @Autowired + private HttpServletRequest request; + + @Autowired + private UsersRepository usersRepository; + + private String userId; + + @PostConstruct + public void init() { + CustomAuthenticationData authn = (CustomAuthenticationData) ((OAuth2Authentication) request.getUserPrincipal()).getUserAuthentication(); + userId = (String) authn.getPrincipal(); + //accessToken = (String) ((CustomAuthenticationData) request.getUserPrincipal()).getAttributes().get("access_token"); + //System.out.println("SessionData initialized: " + accessToken); + + if (!usersRepository.findById(userId).isPresent()) { + User user = new User(); + user.setId(userId); + usersRepository.save(user); + } + } + + public String getUserId() { + return userId; + } +} diff --git a/gms/src/main/java/it/inaf/ia2/gms/controller/GroupsController.java b/gms/src/main/java/it/inaf/ia2/gms/controller/GroupsController.java new file mode 100644 index 0000000000000000000000000000000000000000..7586fd84e5d04aabc3cd9bd2950f9c6f0c476e4b --- /dev/null +++ b/gms/src/main/java/it/inaf/ia2/gms/controller/GroupsController.java @@ -0,0 +1,47 @@ +package it.inaf.ia2.gms.controller; + +import it.inaf.ia2.gms.authn.SessionData; +import it.inaf.ia2.gms.model.CreateGroupRequest; +import it.inaf.ia2.gms.model.GroupsModelRequest; +import it.inaf.ia2.gms.model.GroupsModelResponse; +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.service.GroupsService; +import it.inaf.ia2.gms.service.UsersService; +import javax.validation.Valid; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class GroupsController { + + @Autowired + private SessionData session; + + private UsersService usersService; + + @Autowired + private GroupsModelService groupsModelService; + + @Autowired + private GroupsService groupsService; + + @GetMapping(value = "/groups", produces = MediaType.APPLICATION_JSON_UTF8_VALUE) + public GroupsModelResponse getGroupsModelResponse(@Valid @RequestBody GroupsModelRequest groupsModelRequest) { + return groupsModelService.getGroupsModel(groupsModelRequest, session.getUserId()); + } + + @PostMapping(value = "/group", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) + public ResponseEntity<String> createGroup(@Valid @RequestBody CreateGroupRequest createGroupRequest) { + User user = usersService.getUserById(session.getUserId()); + Group group = groupsService.addGroup(createGroupRequest.getParentGroupId(), createGroupRequest.getGroupName(), user); + return new ResponseEntity<>(group.getId(), HttpStatus.CREATED); + } +} diff --git a/gms/src/main/java/it/inaf/ia2/gms/controller/GroupsModelController.java b/gms/src/main/java/it/inaf/ia2/gms/controller/GroupsModelController.java deleted file mode 100644 index 56a344ea4c8f7cf51e246f29478701c96aa73999..0000000000000000000000000000000000000000 --- a/gms/src/main/java/it/inaf/ia2/gms/controller/GroupsModelController.java +++ /dev/null @@ -1,17 +0,0 @@ -package it.inaf.ia2.gms.controller; - -import it.inaf.ia2.gms.controller.model.GroupsModelRequest; -import it.inaf.ia2.gms.controller.model.GroupsModelResponse; -import javax.validation.Valid; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RestController; - -@RestController -public class GroupsModelController { - - @GetMapping - public GroupsModelResponse getGroupsModelResponse(@Valid @RequestBody GroupsModelRequest groupsModelRequest) { - return null; - } -} diff --git a/gms/src/main/java/it/inaf/ia2/gms/controller/model/GroupsModelRequest.java b/gms/src/main/java/it/inaf/ia2/gms/controller/model/GroupsModelRequest.java deleted file mode 100644 index 8a5c00a1ab1ea02b3c45367c9da177dd33aa0977..0000000000000000000000000000000000000000 --- a/gms/src/main/java/it/inaf/ia2/gms/controller/model/GroupsModelRequest.java +++ /dev/null @@ -1,14 +0,0 @@ -package it.inaf.ia2.gms.controller.model; - -public class GroupsModelRequest extends BaseModelRequest { - - private String groupId; - - public String getGroupId() { - return groupId; - } - - public void setGroupId(String groupId) { - this.groupId = groupId; - } -} diff --git a/gms/src/main/java/it/inaf/ia2/gms/controller/model/GroupsModelResponse.java b/gms/src/main/java/it/inaf/ia2/gms/controller/model/GroupsModelResponse.java deleted file mode 100644 index 8bc0046cd5a6bd04988a614a481aca27fb1dc982..0000000000000000000000000000000000000000 --- a/gms/src/main/java/it/inaf/ia2/gms/controller/model/GroupsModelResponse.java +++ /dev/null @@ -1,6 +0,0 @@ -package it.inaf.ia2.gms.controller.model; - -public class GroupsModelResponse extends BaseModelResponse { - - -} diff --git a/gms/src/main/java/it/inaf/ia2/gms/exception/UnauthorizedException.java b/gms/src/main/java/it/inaf/ia2/gms/exception/UnauthorizedException.java new file mode 100644 index 0000000000000000000000000000000000000000..2b07d8c30bb0f9c9f5df74611726acfc0f781dcc --- /dev/null +++ b/gms/src/main/java/it/inaf/ia2/gms/exception/UnauthorizedException.java @@ -0,0 +1,8 @@ +package it.inaf.ia2.gms.exception; + +public class UnauthorizedException extends RuntimeException { + + public UnauthorizedException(String message) { + super(message); + } +} diff --git a/gms/src/main/java/it/inaf/ia2/gms/controller/model/BaseModelRequest.java b/gms/src/main/java/it/inaf/ia2/gms/model/BaseModelRequest.java similarity index 82% rename from gms/src/main/java/it/inaf/ia2/gms/controller/model/BaseModelRequest.java rename to gms/src/main/java/it/inaf/ia2/gms/model/BaseModelRequest.java index 3e93b83aed42181fe0e2c9a659221fbb04dc7209..1330e697373ab887171e3839102c2d9df31d2f72 100644 --- a/gms/src/main/java/it/inaf/ia2/gms/controller/model/BaseModelRequest.java +++ b/gms/src/main/java/it/inaf/ia2/gms/model/BaseModelRequest.java @@ -1,4 +1,4 @@ -package it.inaf.ia2.gms.controller.model; +package it.inaf.ia2.gms.model; public abstract class BaseModelRequest { diff --git a/gms/src/main/java/it/inaf/ia2/gms/controller/model/BaseModelResponse.java b/gms/src/main/java/it/inaf/ia2/gms/model/BaseModelResponse.java similarity index 89% rename from gms/src/main/java/it/inaf/ia2/gms/controller/model/BaseModelResponse.java rename to gms/src/main/java/it/inaf/ia2/gms/model/BaseModelResponse.java index 98c6b2a09062713a16b46a2b69fb5a9c003f6e32..b8999c5fdaf278aa89e49283198f84b00290e3c4 100644 --- a/gms/src/main/java/it/inaf/ia2/gms/controller/model/BaseModelResponse.java +++ b/gms/src/main/java/it/inaf/ia2/gms/model/BaseModelResponse.java @@ -1,4 +1,4 @@ -package it.inaf.ia2.gms.controller.model; +package it.inaf.ia2.gms.model; public abstract class BaseModelResponse { diff --git a/gms/src/main/java/it/inaf/ia2/gms/model/CreateGroupRequest.java b/gms/src/main/java/it/inaf/ia2/gms/model/CreateGroupRequest.java new file mode 100644 index 0000000000000000000000000000000000000000..a62c852f9186227f7ebaa2a43abc3875eb3a8d2f --- /dev/null +++ b/gms/src/main/java/it/inaf/ia2/gms/model/CreateGroupRequest.java @@ -0,0 +1,23 @@ +package it.inaf.ia2.gms.model; + +public class CreateGroupRequest { + + private String parentGroupId; + private String groupName; + + public String getParentGroupId() { + return parentGroupId; + } + + public void setParentGroupId(String parentGroupId) { + this.parentGroupId = parentGroupId; + } + + public String getGroupName() { + return groupName; + } + + public void setGroupName(String groupName) { + this.groupName = groupName; + } +} diff --git a/gms/src/main/java/it/inaf/ia2/gms/model/GroupBreadcrumb.java b/gms/src/main/java/it/inaf/ia2/gms/model/GroupBreadcrumb.java new file mode 100644 index 0000000000000000000000000000000000000000..8c16742ba9e1e3b94d7a230a6a8b300b801f5a74 --- /dev/null +++ b/gms/src/main/java/it/inaf/ia2/gms/model/GroupBreadcrumb.java @@ -0,0 +1,23 @@ +package it.inaf.ia2.gms.model; + +public class GroupBreadcrumb { + + private String groupId; + private String groupName; + + public String getGroupId() { + return groupId; + } + + public void setGroupId(String groupId) { + this.groupId = groupId; + } + + public String getGroupName() { + return groupName; + } + + public void setGroupName(String groupName) { + this.groupName = groupName; + } +} diff --git a/gms/src/main/java/it/inaf/ia2/gms/model/GroupNode.java b/gms/src/main/java/it/inaf/ia2/gms/model/GroupNode.java new file mode 100644 index 0000000000000000000000000000000000000000..6ca71a1e443eb6815c707eb81837e026d6b15e57 --- /dev/null +++ b/gms/src/main/java/it/inaf/ia2/gms/model/GroupNode.java @@ -0,0 +1,83 @@ +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 boolean hasChildren; + + public GroupNode() { + permissions = new HashSet<>(); + } + + public String getGroupId() { + return groupId; + } + + public void setGroupId(String groupId) { + this.groupId = groupId; + } + + public String getGroupName() { + return groupName; + } + + public void setGroupName(String groupName) { + this.groupName = groupName; + } + + public List<Permission> getPermissions() { + return Collections.unmodifiableList(new ArrayList<>(permissions)); + } + + 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 boolean isHasChildren() { + return hasChildren; + } + + public void setHasChildren(boolean hasChildren) { + this.hasChildren = hasChildren; + } +} diff --git a/gms/src/main/java/it/inaf/ia2/gms/model/GroupsModelRequest.java b/gms/src/main/java/it/inaf/ia2/gms/model/GroupsModelRequest.java new file mode 100644 index 0000000000000000000000000000000000000000..9127d87de239fccf58baa82318ffd5e6fc03fc1d --- /dev/null +++ b/gms/src/main/java/it/inaf/ia2/gms/model/GroupsModelRequest.java @@ -0,0 +1,32 @@ +package it.inaf.ia2.gms.model; + +public class GroupsModelRequest extends BaseModelRequest { + + private String groupId; + private int paginatorPage; + private int paginatorPageSize; + + public String getGroupId() { + return groupId; + } + + public void setGroupId(String groupId) { + this.groupId = groupId; + } + + public int getPaginatorPage() { + return paginatorPage; + } + + public void setPaginatorPage(int paginatorPage) { + this.paginatorPage = paginatorPage; + } + + public int getPaginatorPageSize() { + return paginatorPageSize; + } + + public void setPaginatorPageSize(int paginatorPageSize) { + this.paginatorPageSize = paginatorPageSize; + } +} diff --git a/gms/src/main/java/it/inaf/ia2/gms/model/GroupsModelResponse.java b/gms/src/main/java/it/inaf/ia2/gms/model/GroupsModelResponse.java new file mode 100644 index 0000000000000000000000000000000000000000..415ff5cb6581babcd732768c0e3b7bc289da05b9 --- /dev/null +++ b/gms/src/main/java/it/inaf/ia2/gms/model/GroupsModelResponse.java @@ -0,0 +1,53 @@ +package it.inaf.ia2.gms.model; + +import java.util.List; + +public class GroupsModelResponse extends BaseModelResponse { + + private List<GroupBreadcrumb> breadcrumbs; + private PaginatedData<GroupNode> groupsPanel; + private PaginatedData<RapUser> membersPanel; + private PaginatedData<UserPermission> permissionsPanel; + // current group permissions + private List<Permission> permissions; + + public List<GroupBreadcrumb> getBreadcrumbs() { + return breadcrumbs; + } + + public void setBreadcrumbs(List<GroupBreadcrumb> breadcrumbs) { + this.breadcrumbs = breadcrumbs; + } + + public PaginatedData<GroupNode> getGroupsPanel() { + return groupsPanel; + } + + public void setGroupsPanel(PaginatedData<GroupNode> groupsPanel) { + this.groupsPanel = groupsPanel; + } + + public PaginatedData<RapUser> getMembersPanel() { + return membersPanel; + } + + public void setMembersPanel(PaginatedData<RapUser> membersPanel) { + this.membersPanel = membersPanel; + } + + public PaginatedData<UserPermission> getPermissionsPanel() { + return permissionsPanel; + } + + public void setPermissionsPanel(PaginatedData<UserPermission> permissionsPanel) { + this.permissionsPanel = permissionsPanel; + } + + public List<Permission> getPermissions() { + return permissions; + } + + public void setPermissions(List<Permission> permissions) { + this.permissions = permissions; + } +} diff --git a/gms/src/main/java/it/inaf/ia2/gms/model/Identity.java b/gms/src/main/java/it/inaf/ia2/gms/model/Identity.java new file mode 100644 index 0000000000000000000000000000000000000000..c7031e58fe552167457f2e582e7c58b23280ed51 --- /dev/null +++ b/gms/src/main/java/it/inaf/ia2/gms/model/Identity.java @@ -0,0 +1,23 @@ +package it.inaf.ia2.gms.model; + +public class Identity { + + private IdentityType type; + private String email; + + public IdentityType getType() { + return type; + } + + public void setType(IdentityType type) { + this.type = type; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } +} diff --git a/gms/src/main/java/it/inaf/ia2/gms/model/IdentityType.java b/gms/src/main/java/it/inaf/ia2/gms/model/IdentityType.java new file mode 100644 index 0000000000000000000000000000000000000000..f2a565557eaa455d20d603e54f4fc4fed60fd7bd --- /dev/null +++ b/gms/src/main/java/it/inaf/ia2/gms/model/IdentityType.java @@ -0,0 +1,12 @@ +package it.inaf.ia2.gms.model; + +public enum IdentityType { + + EDU_GAIN, + X509, + ORCID, + GOOGLE, + LINKEDIN, + FACEBOOK, + LOCAL_IDP +} diff --git a/gms/src/main/java/it/inaf/ia2/gms/model/PaginatedData.java b/gms/src/main/java/it/inaf/ia2/gms/model/PaginatedData.java new file mode 100644 index 0000000000000000000000000000000000000000..5ea07f7451ed5aab368ee84ad5e162add7778e20 --- /dev/null +++ b/gms/src/main/java/it/inaf/ia2/gms/model/PaginatedData.java @@ -0,0 +1,83 @@ +package it.inaf.ia2.gms.model; + +import java.util.ArrayList; +import java.util.List; + +public class PaginatedData<T> { + + // how many page index links have to be shown + private static final int LINKS_SIZE = 5; + + private final List<T> items; + private final int currentPage; + private final List<Integer> links; + private final int totalItems; + private final int pageSize; + private final int totalPages; + private final boolean hasPreviousPages; + private final boolean hasFollowingPages; + + public PaginatedData(List<T> allItems, int page, int pageSize) { + + totalItems = allItems.size(); + this.currentPage = page; + this.pageSize = pageSize; + + totalPages = (int) Math.ceil((double) totalItems / pageSize); + + if (allItems.isEmpty()) { + items = allItems; + } else { + int firstElementIndex = (currentPage - 1) * pageSize; + int lastElementIndex = Math.min(currentPage * pageSize - 1, totalItems - 1); + items = new ArrayList<>(allItems.subList(firstElementIndex, lastElementIndex)); + } + + links = new ArrayList<>(); + int start = currentPage - LINKS_SIZE / 2; + if (start > 1 && start + LINKS_SIZE > totalPages) { + start = totalPages - LINKS_SIZE + 1; + } + if (start < 1) { + start = 1; + } + int i = start; + hasPreviousPages = start > 1; + while (i < start + LINKS_SIZE && i <= totalPages) { + links.add(i++); + } + hasFollowingPages = totalPages > i; + } + + public List<T> getItems() { + return items; + } + + public int getCurrentPage() { + return currentPage; + } + + public List<Integer> getLinks() { + return links; + } + + public int getTotalItems() { + return totalItems; + } + + public int getPageSize() { + return pageSize; + } + + public int getTotalPages() { + return totalPages; + } + + public boolean isHasPreviousPages() { + return hasPreviousPages; + } + + public boolean isHasFollowingPages() { + return hasFollowingPages; + } +} diff --git a/gms/src/main/java/it/inaf/ia2/gms/model/Permission.java b/gms/src/main/java/it/inaf/ia2/gms/model/Permission.java new file mode 100644 index 0000000000000000000000000000000000000000..be00ef7092d4e17163a7499e236f5f36a258672c --- /dev/null +++ b/gms/src/main/java/it/inaf/ia2/gms/model/Permission.java @@ -0,0 +1,9 @@ +package it.inaf.ia2.gms.model; + +public enum Permission { + + ADMIN, + MANAGE_MEMBERS, + VIEW_MEMBERS, + TRAVERSE +} diff --git a/gms/src/main/java/it/inaf/ia2/gms/model/RapUser.java b/gms/src/main/java/it/inaf/ia2/gms/model/RapUser.java new file mode 100644 index 0000000000000000000000000000000000000000..e58f27da60c3afc8b7e5f8716ebfa8f6b06a6e5f --- /dev/null +++ b/gms/src/main/java/it/inaf/ia2/gms/model/RapUser.java @@ -0,0 +1,34 @@ +package it.inaf.ia2.gms.model; + +import java.util.List; + +public class RapUser { + + private String id; + private String displayName; + private List<Identity> identities; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getDisplayName() { + return displayName; + } + + public void setDisplayName(String displayName) { + this.displayName = displayName; + } + + public List<Identity> getIdentities() { + return identities; + } + + public void setIdentities(List<Identity> identities) { + this.identities = identities; + } +} diff --git a/gms/src/main/java/it/inaf/ia2/gms/model/UserPermission.java b/gms/src/main/java/it/inaf/ia2/gms/model/UserPermission.java new file mode 100644 index 0000000000000000000000000000000000000000..66ab93a33f3bf02c4337ccd7b033c9ee91e94fdb --- /dev/null +++ b/gms/src/main/java/it/inaf/ia2/gms/model/UserPermission.java @@ -0,0 +1,23 @@ +package it.inaf.ia2.gms.model; + +public class UserPermission { + + private RapUser user; + private Permission permission; + + public RapUser getUser() { + return user; + } + + public void setUser(RapUser user) { + this.user = user; + } + + public Permission getPermission() { + return permission; + } + + public void setPermission(Permission permission) { + this.permission = permission; + } +} diff --git a/gms/src/main/java/it/inaf/ia2/gms/persistence/MembershipRepository.java b/gms/src/main/java/it/inaf/ia2/gms/persistence/MembershipRepository.java new file mode 100644 index 0000000000000000000000000000000000000000..cd336928e77e34081c72e5101f1403aa792cc27e --- /dev/null +++ b/gms/src/main/java/it/inaf/ia2/gms/persistence/MembershipRepository.java @@ -0,0 +1,16 @@ +package it.inaf.ia2.gms.persistence; + +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); +} diff --git a/gms/src/main/java/it/inaf/ia2/gms/persistence/PermissionsRepository.java b/gms/src/main/java/it/inaf/ia2/gms/persistence/PermissionsRepository.java index 9b8b50a13afb474e9697aeca3a5fdd1a9d0056b7..f3e19f1a5cfb956db75c6cc867b7390632f4c54d 100644 --- a/gms/src/main/java/it/inaf/ia2/gms/persistence/PermissionsRepository.java +++ b/gms/src/main/java/it/inaf/ia2/gms/persistence/PermissionsRepository.java @@ -1,8 +1,8 @@ package it.inaf.ia2.gms.persistence; import it.inaf.ia2.gms.persistence.model.User; -import it.inaf.ia2.gms.persistence.model.UserGroup; -import it.inaf.ia2.gms.persistence.model.UserGroupId; +import it.inaf.ia2.gms.persistence.model.UserGroupPermission; +import it.inaf.ia2.gms.persistence.model.UserGroupPermissionId; import java.util.List; import javax.transaction.Transactional; import org.springframework.data.jpa.repository.JpaRepository; @@ -10,7 +10,7 @@ import org.springframework.stereotype.Repository; @Repository @Transactional -public interface PermissionsRepository extends JpaRepository<UserGroup, UserGroupId> { +public interface PermissionsRepository extends JpaRepository<UserGroupPermission, UserGroupPermissionId> { - List<UserGroup> findBy_user(User user); + List<UserGroupPermission> findBy_user(User user); } diff --git a/gms/src/main/java/it/inaf/ia2/gms/persistence/UserGroupsFromParentSpecification.java b/gms/src/main/java/it/inaf/ia2/gms/persistence/UserGroupsFromParentSpecification.java deleted file mode 100644 index 6a991061ce8fc81bfb96f8eb815ddb1277582a1f..0000000000000000000000000000000000000000 --- a/gms/src/main/java/it/inaf/ia2/gms/persistence/UserGroupsFromParentSpecification.java +++ /dev/null @@ -1,5 +0,0 @@ -package it.inaf.ia2.gms.persistence; - -public class UserGroupsFromParentSpecification { - -} diff --git a/gms/src/main/java/it/inaf/ia2/gms/persistence/model/Group.java b/gms/src/main/java/it/inaf/ia2/gms/persistence/model/Group.java index 92cb5d0c1ab8326b0bc2c4b9c146c050c8f1aced..504093e9d8e01965bcd6b3f5519a18ec6a911693 100644 --- a/gms/src/main/java/it/inaf/ia2/gms/persistence/model/Group.java +++ b/gms/src/main/java/it/inaf/ia2/gms/persistence/model/Group.java @@ -18,6 +18,7 @@ import javax.persistence.Table; public class Group { @Id + @Column(length = 50) private String id; @Column(nullable = false) @@ -29,10 +30,10 @@ public class Group { @OneToMany(mappedBy = "parentGroup", fetch = FetchType.LAZY) @OrderBy("name ASC") - private List<Group> groupsMembers; + private List<Group> childrenGroups; public Group() { - groupsMembers = new ArrayList<>(); + childrenGroups = new ArrayList<>(); } public String getId() { @@ -59,12 +60,12 @@ public class Group { this.parentGroup = parentGroup; } - public List<Group> getGroupsMembers() { - return groupsMembers; + public List<Group> getChildrenGroups() { + return childrenGroups; } - public void setGroupsMembers(List<Group> groupsMembers) { - this.groupsMembers = groupsMembers; + public void setChildrenGroups(List<Group> childrenGroups) { + this.childrenGroups = childrenGroups; } @Override diff --git a/gms/src/main/java/it/inaf/ia2/gms/persistence/model/Membership.java b/gms/src/main/java/it/inaf/ia2/gms/persistence/model/Membership.java new file mode 100644 index 0000000000000000000000000000000000000000..69b282fb2301558124ca29dbe4bff2b5d5ecf4ea --- /dev/null +++ b/gms/src/main/java/it/inaf/ia2/gms/persistence/model/Membership.java @@ -0,0 +1,44 @@ +package it.inaf.ia2.gms.persistence.model; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.IdClass; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.Table; + +/** + * Note: if necessary this class could contain also a role (specific for the + * application using the GMS). Currently that is not implemented. + */ +@Entity +@IdClass(MembershipId.class) +@Table(name = "gms_membership") +public class Membership { + + @Id + @ManyToOne + @JoinColumn(name = "user_id", referencedColumnName = "id", columnDefinition = "varchar(50)") + private User _user; + + @Id + @ManyToOne + @JoinColumn(name = "group_id", referencedColumnName = "id", columnDefinition = "varchar(50)") + private Group _group; + + public User getUser() { + return _user; + } + + public void setUser(User _user) { + this._user = _user; + } + + public Group getGroup() { + return _group; + } + + public void setGroup(Group _group) { + this._group = _group; + } +} diff --git a/gms/src/main/java/it/inaf/ia2/gms/persistence/model/MembershipId.java b/gms/src/main/java/it/inaf/ia2/gms/persistence/model/MembershipId.java new file mode 100644 index 0000000000000000000000000000000000000000..c0b1beab333ce7e7304a0f52b361f778a3be0a96 --- /dev/null +++ b/gms/src/main/java/it/inaf/ia2/gms/persistence/model/MembershipId.java @@ -0,0 +1,39 @@ +package it.inaf.ia2.gms.persistence.model; + +import java.io.Serializable; +import java.util.Objects; + +public class MembershipId implements Serializable { + + String _user; + String _group; + + @Override + public int hashCode() { + int hash = 7; + hash = 47 * hash + Objects.hashCode(this._user); + hash = 47 * hash + Objects.hashCode(this._group); + return hash; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final MembershipId other = (MembershipId) obj; + if (!Objects.equals(this._user, other._user)) { + return false; + } + if (!Objects.equals(this._group, other._group)) { + return false; + } + return true; + } +} diff --git a/gms/src/main/java/it/inaf/ia2/gms/persistence/model/User.java b/gms/src/main/java/it/inaf/ia2/gms/persistence/model/User.java index 82238da1765629ce7b38629fc563fef4a6626814..9d2c6d794ea996c48cc2b9158beee2153810d051 100644 --- a/gms/src/main/java/it/inaf/ia2/gms/persistence/model/User.java +++ b/gms/src/main/java/it/inaf/ia2/gms/persistence/model/User.java @@ -1,5 +1,6 @@ package it.inaf.ia2.gms.persistence.model; +import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.Table; @@ -9,6 +10,7 @@ import javax.persistence.Table; public class User { @Id + @Column(length = 50) private String id; public String getId() { diff --git a/gms/src/main/java/it/inaf/ia2/gms/persistence/model/UserGroup.java b/gms/src/main/java/it/inaf/ia2/gms/persistence/model/UserGroupPermission.java similarity index 80% rename from gms/src/main/java/it/inaf/ia2/gms/persistence/model/UserGroup.java rename to gms/src/main/java/it/inaf/ia2/gms/persistence/model/UserGroupPermission.java index 8bfb1fad8cab5529559541db1a4a51aba54716ab..3eebc85e7502d3a38958156628cf6e179cd5dce6 100644 --- a/gms/src/main/java/it/inaf/ia2/gms/persistence/model/UserGroup.java +++ b/gms/src/main/java/it/inaf/ia2/gms/persistence/model/UserGroupPermission.java @@ -1,6 +1,6 @@ package it.inaf.ia2.gms.persistence.model; -import it.inaf.ia2.gms.service.model.Permission; +import it.inaf.ia2.gms.model.Permission; import java.util.Objects; import javax.persistence.Column; import javax.persistence.Entity; @@ -17,23 +17,23 @@ import javax.persistence.Table; * keyword. */ @Entity -@IdClass(UserGroupId.class) -@Table(name = "gms_user_group") -public class UserGroup { +@IdClass(UserGroupPermissionId.class) +@Table(name = "gms_user_group_permission") +public class UserGroupPermission { @Id @ManyToOne - @JoinColumn(name = "user_id", referencedColumnName = "id") + @JoinColumn(name = "user_id", referencedColumnName = "id", columnDefinition = "varchar(50)") private User _user; @Id @ManyToOne - @JoinColumn(name = "group_id", referencedColumnName = "id") + @JoinColumn(name = "group_id", referencedColumnName = "id", columnDefinition = "varchar(50)") private Group _group; @Id @Enumerated(EnumType.STRING) - @Column(name = "permission") + @Column(name = "permission", length = 50) private Permission permission; public User getUser() { @@ -80,7 +80,7 @@ public class UserGroup { if (getClass() != obj.getClass()) { return false; } - final UserGroup other = (UserGroup) obj; + final UserGroupPermission other = (UserGroupPermission) obj; if (!Objects.equals(this._user, other._user)) { return false; } diff --git a/gms/src/main/java/it/inaf/ia2/gms/persistence/model/UserGroupId.java b/gms/src/main/java/it/inaf/ia2/gms/persistence/model/UserGroupPermissionId.java similarity index 85% rename from gms/src/main/java/it/inaf/ia2/gms/persistence/model/UserGroupId.java rename to gms/src/main/java/it/inaf/ia2/gms/persistence/model/UserGroupPermissionId.java index c546caedfa87edbc20f6d8250892233a946f02c2..c036bfd25d7d228207653a385e59b5f02574adf0 100644 --- a/gms/src/main/java/it/inaf/ia2/gms/persistence/model/UserGroupId.java +++ b/gms/src/main/java/it/inaf/ia2/gms/persistence/model/UserGroupPermissionId.java @@ -1,10 +1,10 @@ package it.inaf.ia2.gms.persistence.model; -import it.inaf.ia2.gms.service.model.Permission; +import it.inaf.ia2.gms.model.Permission; import java.io.Serializable; import java.util.Objects; -public class UserGroupId implements Serializable { +public class UserGroupPermissionId implements Serializable { String _user; String _group; @@ -30,7 +30,7 @@ public class UserGroupId implements Serializable { if (getClass() != obj.getClass()) { return false; } - final UserGroupId other = (UserGroupId) obj; + final UserGroupPermissionId other = (UserGroupPermissionId) obj; if (!Objects.equals(this._user, other._user)) { return false; } diff --git a/gms/src/main/java/it/inaf/ia2/gms/rap/RapClient.java b/gms/src/main/java/it/inaf/ia2/gms/rap/RapClient.java new file mode 100644 index 0000000000000000000000000000000000000000..a7eff0d84c6d24acb7256eb98e00ed88338a4fd9 --- /dev/null +++ b/gms/src/main/java/it/inaf/ia2/gms/rap/RapClient.java @@ -0,0 +1,8 @@ +package it.inaf.ia2.gms.rap; + +import org.springframework.stereotype.Component; + +@Component +public class RapClient { + +} diff --git a/gms/src/main/java/it/inaf/ia2/gms/service/GroupsModelService.java b/gms/src/main/java/it/inaf/ia2/gms/service/GroupsModelService.java new file mode 100644 index 0000000000000000000000000000000000000000..1673fd6eafc1707d249cf883b22d74269c7f695a --- /dev/null +++ b/gms/src/main/java/it/inaf/ia2/gms/service/GroupsModelService.java @@ -0,0 +1,56 @@ +package it.inaf.ia2.gms.service; + +import it.inaf.ia2.gms.model.GroupBreadcrumb; +import it.inaf.ia2.gms.model.GroupNode; +import it.inaf.ia2.gms.model.GroupsModelRequest; +import it.inaf.ia2.gms.model.GroupsModelResponse; +import it.inaf.ia2.gms.model.PaginatedData; +import it.inaf.ia2.gms.persistence.model.Group; +import it.inaf.ia2.gms.persistence.model.User; +import java.util.ArrayList; +import java.util.List; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class GroupsModelService { + + @Autowired + private UsersService usersService; + + @Autowired + private GroupsService groupsService; + + public GroupsModelResponse getGroupsModel(GroupsModelRequest request, String userId) { + + User user = usersService.getUserById(userId); + Group group = groupsService.getGroupById(request.getGroupId()); + + GroupsModelResponse response = new GroupsModelResponse(); + + response.setPage("groups"); + + List<GroupNode> groupNodes = groupsService.getSubgroups(group, user); + + response.setGroupsPanel(new PaginatedData<>(groupNodes, request.getPaginatorPage(), request.getPaginatorPageSize())); + + response.setPermissions(groupsService.getPermissions(group, user)); + response.setBreadcrumbs(buildBreadcrumbs(new ArrayList<>(), group)); + + return response; + } + + private List<GroupBreadcrumb> buildBreadcrumbs(List<GroupBreadcrumb> breadcrumbs, Group group) { + + GroupBreadcrumb bc = new GroupBreadcrumb(); + bc.setGroupId(group.getId()); + bc.setGroupName(group.getName()); + breadcrumbs.add(bc); + + if (group.getParentGroup() == null) { + return breadcrumbs; + } else { + return buildBreadcrumbs(breadcrumbs, group.getParentGroup()); + } + } +} 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 f2affaf6be06d382bec45a9604ac9a11192006d2..9a258178876c3da9a0c464dc970aab5e3d90f1ff 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 @@ -1,20 +1,21 @@ package it.inaf.ia2.gms.service; import it.inaf.ia2.gms.exception.BadRequestException; +import it.inaf.ia2.gms.exception.UnauthorizedException; import it.inaf.ia2.gms.persistence.GroupsRepository; -import it.inaf.ia2.gms.persistence.UsersRepository; +import it.inaf.ia2.gms.persistence.MembershipRepository; import it.inaf.ia2.gms.persistence.model.Group; import it.inaf.ia2.gms.persistence.model.User; -import it.inaf.ia2.gms.persistence.model.UserGroup; +import it.inaf.ia2.gms.persistence.model.UserGroupPermission; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import it.inaf.ia2.gms.persistence.PermissionsRepository; -import it.inaf.ia2.gms.service.model.GroupNode; -import it.inaf.ia2.gms.service.model.Permission; +import it.inaf.ia2.gms.persistence.model.Membership; +import it.inaf.ia2.gms.model.GroupNode; +import it.inaf.ia2.gms.model.Permission; import java.util.ArrayList; -import java.util.Iterator; -import java.util.LinkedHashMap; +import java.util.HashMap; import java.util.Map; import java.util.UUID; @@ -24,15 +25,16 @@ public class GroupsService { public static final String ROOT = "ROOT"; private final GroupsRepository groupsRepository; - private final UsersRepository usersRepository; private final PermissionsRepository permissionsRepository; + private final MembershipRepository membershipRepository; @Autowired public GroupsService(GroupsRepository groupsRepository, - UsersRepository usersRepository, PermissionsRepository permissionsRepository) { + PermissionsRepository permissionsRepository, + MembershipRepository membershipRepository) { this.groupsRepository = groupsRepository; - this.usersRepository = usersRepository; this.permissionsRepository = permissionsRepository; + this.membershipRepository = membershipRepository; createRootIfNecessary(); } @@ -45,90 +47,144 @@ public class GroupsService { } } - public Group addGroup(String parentId, String groupName) { + public Group addGroup(String parentId, String groupName, User user) { + Group parent = getGroupById(parentId); + + if (parent.getChildrenGroups().stream() + .anyMatch(g -> g.getName().equals(groupName))) { + throw new BadRequestException("There is already a group named " + groupName); + } + + if (!getPermissions(parent, user).contains(Permission.ADMIN)) { + throw new UnauthorizedException("Missing admin privileges"); + } + Group group = new Group(); group.setId(UUID.randomUUID().toString()); group.setName(groupName); group.setParentGroup(parent); - parent.getGroupsMembers().add(group); + parent.getChildrenGroups().add(group); group = groupsRepository.save(group); groupsRepository.save(parent); return group; } - public List<Group> getSubgroups(String parentId) { - Group parent = getGroupById(parentId); - return groupsRepository.findByParentGroup(parent); - } + public List<GroupNode> getSubgroups(Group parent, User user) { - public List<GroupNode> getSubgroups(String parentGroupId, String userId) { + List<UserGroupPermission> permissions = getAllPermissions(user); + + Map<String, GroupNode> nodesMap = new HashMap<>(); + + for (Group childGroup : parent.getChildrenGroups()) { + addGroupNodeToMap(childGroup, permissions, nodesMap); + } + + List<GroupNode> nodes = new ArrayList<>(nodesMap.values()); + + // Sort by group name + nodes.sort((n1, n2) -> n1.getGroupName().compareTo(n2.getGroupName())); + + return nodes; + } - User user = usersRepository.findById(userId) - .orElseThrow(() -> new BadRequestException("User " + userId + " not found")); + public List<Permission> getPermissions(Group group, User user) { - Group parent = getGroupById(parentGroupId); + List<UserGroupPermission> permissions = getAllPermissions(user); + Map<String, GroupNode> nodesMap = new HashMap<>(); - List<UserGroup> permissions = permissionsRepository.findBy_user(user); + addGroupNodeToMap(group, permissions, nodesMap); - Map<String, GroupNode> nodes = new LinkedHashMap<>(); + GroupNode groupNode = nodesMap.get(group.getId()); + if (groupNode == null) { + return null; + } + return groupNode.getPermissions(); + } - for (Group childGroup : parent.getGroupsMembers()) { + /** + * Returns all the permissions, including also the calculated ones (the ones + * derived from the memberships). + */ + private List<UserGroupPermission> getAllPermissions(User user) { + + // explicit permissions + List<UserGroupPermission> permissions = permissionsRepository.findBy_user(user); + + List<UserGroupPermission> implicitPermissions = new ArrayList<>(); + for (Membership membership : membershipRepository.findBy_user(user)) { + UserGroupPermission userGroupPermission = new UserGroupPermission(); + userGroupPermission.setUser(user); + userGroupPermission.setGroup(membership.getGroup()); + userGroupPermission.setPermission(Permission.TRAVERSE); + implicitPermissions.add(userGroupPermission); + } - Iterator<UserGroup> ite = permissions.iterator(); - while (ite.hasNext()) { + permissions.addAll(implicitPermissions); + return permissions; + } - UserGroup permission = ite.next(); + private void addGroupNodeToMap(Group group, List<UserGroupPermission> permissions, Map<String, GroupNode> nodesMap) { - boolean isChild = false; - if (permission.getGroup().getId().equals(childGroup.getId()) - || (isChild = isChildOf(permission.getGroup(), parentGroupId))) { + for (UserGroupPermission permission : permissions) { - GroupNode node = nodes.get(childGroup.getId()); - if (node == null) { - node = getGroupNode(childGroup); - } + boolean isChild = false; + if (permission.getGroup().getId().equals(group.getId()) + || (isChild = isChildOf(permission.getGroup(), group)) + || (isParentOf(permission.getGroup(), group))) { - if (isChild) { - // Traversal only - node.getPermissions().add(Permission.READ); - } else { - // Direct permission - node.getPermissions().add(permission.getPermission()); - } + GroupNode node = nodesMap.get(group.getId()); + if (node == null) { + node = getGroupNode(group); + } - nodes.put(childGroup.getId(), node); - ite.remove(); + if (isChild) { + // Traversal only + node.addPermission(Permission.TRAVERSE); + } else { + // Direct permission or permission inherited from parent + node.addPermission(permission.getPermission()); } + + nodesMap.put(group.getId(), node); } } - - // TODO: pagination - return new ArrayList<>(nodes.values()); } private GroupNode getGroupNode(Group group) { GroupNode node = new GroupNode(); node.setGroupId(group.getId()); node.setGroupName(group.getName()); - node.setHasChildren(!group.getGroupsMembers().isEmpty()); + node.setHasChildren(!group.getChildrenGroups().isEmpty()); return node; } - private boolean isChildOf(Group group, String parentGroupId) { + private boolean isChildOf(Group group, Group possibleParent) { Group parent = group.getParentGroup(); if (parent == null) { // ROOT has no parent return false; } - if (parentGroupId.equals(parent.getId())) { + if (possibleParent.getId().equals(parent.getId())) { + return true; + } + // recursive call to parent group + return isChildOf(parent, possibleParent); + } + + private boolean isParentOf(Group group, Group possibleChild) { + Group parent = possibleChild.getParentGroup(); + if (parent == null) { + return false; + } + if (parent.getId().equals(group.getId())) { return true; } // recursive call to parent group - return isChildOf(parent, parentGroupId); + return isParentOf(group, parent); } - private Group getGroupById(String groupId) { + public Group getGroupById(String groupId) { return groupsRepository.findById(groupId) .orElseThrow(() -> new BadRequestException("Group " + groupId + " not found")); } diff --git a/gms/src/main/java/it/inaf/ia2/gms/service/MainModelService.java b/gms/src/main/java/it/inaf/ia2/gms/service/MainModelService.java deleted file mode 100644 index cf11a1aa52e7a97e06d047cc4fbc1b9470b62045..0000000000000000000000000000000000000000 --- a/gms/src/main/java/it/inaf/ia2/gms/service/MainModelService.java +++ /dev/null @@ -1,5 +0,0 @@ -package it.inaf.ia2.gms.service; - -public class MainModelService { - -} diff --git a/gms/src/main/java/it/inaf/ia2/gms/service/UsersService.java b/gms/src/main/java/it/inaf/ia2/gms/service/UsersService.java new file mode 100644 index 0000000000000000000000000000000000000000..3cf6a9905b82d8ced1582d1cbcf28ae827a0c5b1 --- /dev/null +++ b/gms/src/main/java/it/inaf/ia2/gms/service/UsersService.java @@ -0,0 +1,24 @@ +package it.inaf.ia2.gms.service; + +import it.inaf.ia2.gms.exception.BadRequestException; +import it.inaf.ia2.gms.persistence.UsersRepository; +import it.inaf.ia2.gms.persistence.model.User; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class UsersService { + + private final UsersRepository usersRepository; + + @Autowired + public UsersService(UsersRepository usersRepository) { + this.usersRepository = usersRepository; + } + + public User getUserById(String userId) { + + return usersRepository.findById(userId) + .orElseThrow(() -> new BadRequestException("User " + userId + " not found")); + } +} diff --git a/gms/src/main/java/it/inaf/ia2/gms/service/model/GroupNode.java b/gms/src/main/java/it/inaf/ia2/gms/service/model/GroupNode.java deleted file mode 100644 index 920ec3d6aa19c1509faa7e921eb3cc92ea9ad2ba..0000000000000000000000000000000000000000 --- a/gms/src/main/java/it/inaf/ia2/gms/service/model/GroupNode.java +++ /dev/null @@ -1,48 +0,0 @@ -package it.inaf.ia2.gms.service.model; - -import java.util.ArrayList; -import java.util.List; - -public class GroupNode { - - private String groupId; - private String groupName; - private List<Permission> permissions; - private boolean hasChildren; - - public GroupNode() { - permissions = new ArrayList<>(); - } - - public String getGroupId() { - return groupId; - } - - public void setGroupId(String groupId) { - this.groupId = groupId; - } - - public String getGroupName() { - return groupName; - } - - public void setGroupName(String groupName) { - this.groupName = groupName; - } - - public List<Permission> getPermissions() { - return permissions; - } - - public void setPermissions(List<Permission> permissions) { - this.permissions = permissions; - } - - public boolean isHasChildren() { - return hasChildren; - } - - public void setHasChildren(boolean hasChildren) { - this.hasChildren = hasChildren; - } -} diff --git a/gms/src/main/java/it/inaf/ia2/gms/service/model/Permission.java b/gms/src/main/java/it/inaf/ia2/gms/service/model/Permission.java deleted file mode 100644 index 899a1b4fc1be254ab225a47d21285f9c15cecf8f..0000000000000000000000000000000000000000 --- a/gms/src/main/java/it/inaf/ia2/gms/service/model/Permission.java +++ /dev/null @@ -1,8 +0,0 @@ -package it.inaf.ia2.gms.service.model; - -public enum Permission { - - ADMIN, - MANAGE_MEMBERS, - READ -} diff --git a/gms/src/test/java/it/inaf/ia2/gms/persistence/GroupsRepositoryTest.java b/gms/src/test/java/it/inaf/ia2/gms/persistence/GroupsRepositoryTest.java deleted file mode 100644 index c5afa9b3558d1e31069aa64bf71e112be665955a..0000000000000000000000000000000000000000 --- a/gms/src/test/java/it/inaf/ia2/gms/persistence/GroupsRepositoryTest.java +++ /dev/null @@ -1,63 +0,0 @@ -package it.inaf.ia2.gms.persistence; - -import it.inaf.ia2.gms.persistence.model.Group; -import it.inaf.ia2.gms.persistence.model.User; -import java.util.Arrays; -import static org.junit.Assert.assertEquals; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; -import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; -import org.springframework.test.context.junit4.SpringRunner; - -@DataJpaTest -@AutoConfigureTestDatabase -@RunWith(SpringRunner.class) -public class GroupsRepositoryTest { - - @Autowired - private UsersRepository usersRepository; - - @Autowired - private GroupsRepository groupsRepository; - - @Test - public void testCreateGroup() { - - User user1 = new User(); - user1.setId("user1"); - user1 = usersRepository.save(user1); - User user2 = new User(); - user2.setId("user2"); - user2 = usersRepository.save(user2); - - Group group = new Group(); - group.setId("parent-group"); - group.setName("Parent"); - - // Test cascade persist - Group childGroup = new Group(); - childGroup.setId("child-group"); - childGroup.setName("Child 1"); - - group.setGroupsMembers(Arrays.asList(childGroup)); - - group = groupsRepository.save(group); - - // Test cascade merge - Group childGroup2 = new Group(); - childGroup2.setId("child-group-2"); - childGroup2.setName("Child 2"); - group.getGroupsMembers().add(childGroup2); - groupsRepository.save(group); - - // Reload - group = groupsRepository.findById("parent-group").get(); - - assertEquals("Parent", group.getName()); - assertEquals(2, group.getGroupsMembers().size()); - assertEquals("Child 1", group.getGroupsMembers().get(0).getName()); - assertEquals("Child 2", group.getGroupsMembers().get(1).getName()); - } -} 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 89f7f86186750a52228c33c5fef48f52d9d444d1..fdf493db76e00c089a0d9d755ce3f1885a594d2a 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 @@ -1,13 +1,16 @@ 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.User; -import it.inaf.ia2.gms.persistence.model.UserGroup; +import it.inaf.ia2.gms.persistence.model.UserGroupPermission; import it.inaf.ia2.gms.service.GroupsService; -import it.inaf.ia2.gms.service.model.GroupNode; -import it.inaf.ia2.gms.service.model.Permission; +import it.inaf.ia2.gms.model.GroupNode; +import it.inaf.ia2.gms.model.Permission; import java.util.List; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; @@ -29,30 +32,126 @@ public class NestedGroupsIntegrationTest { @Autowired private PermissionsRepository permissionsRepository; + @Autowired + private MembershipRepository membershipRepository; + @Test public void testNestedGroupRetrieval() { - GroupsService groupsService = new GroupsService(groupsRepository, usersRepository, permissionsRepository); + GroupsService groupsService = new GroupsService(groupsRepository, + permissionsRepository, membershipRepository); // Create user User user = new User(); user.setId("user"); user = usersRepository.save(user); + // Test super admin + UserGroupPermission superAdminPermission = new UserGroupPermission(); + superAdminPermission.setUser(user); + superAdminPermission.setGroup(groupsRepository.findById(GroupsService.ROOT).get()); + superAdminPermission.setPermission(Permission.ADMIN); + permissionsRepository.save(superAdminPermission); + // Setup groups - Group lbt = groupsService.addGroup(GroupsService.ROOT, "LBT"); - Group lbtInaf = groupsService.addGroup(lbt.getId(), "INAF"); - Group lbtInafProgram = groupsService.addGroup(lbtInaf.getId(), "P1"); - - // Setup permissions - UserGroup permission = new UserGroup(); - permission.setUser(user); - permission.setGroup(lbtInafProgram); - permission.setPermission(Permission.MANAGE_MEMBERS); - permissionsRepository.save(permission); - - List<GroupNode> groupNodes = groupsService.getSubgroups(GroupsService.ROOT, user.getId()); + Group root = groupsService.getGroupById(GroupsService.ROOT); + Group lbt = groupsService.addGroup(GroupsService.ROOT, "LBT", user); + Group tng = groupsService.addGroup(GroupsService.ROOT, "TNG", user); + Group radio = groupsService.addGroup(GroupsService.ROOT, "Radio", user); + Group lbtInaf = groupsService.addGroup(lbt.getId(), "INAF", user); + Group lbtInafProgram1 = groupsService.addGroup(lbtInaf.getId(), "P1", user); + Group lbtInafProgram2 = groupsService.addGroup(lbtInaf.getId(), "P2", user); + + // Test super admin - level 0 (ROOT) + List<GroupNode> groupNodes = groupNodes = groupsService.getSubgroups(root, user); + assertEquals(3, groupNodes.size()); + GroupNode lbtGN = groupNodes.get(0); + assertEquals("LBT", lbtGN.getGroupName()); + assertEquals(1, lbtGN.getPermissions().size()); + assertEquals(Permission.ADMIN, lbtGN.getPermissions().get(0)); + assertTrue(lbtGN.isHasChildren()); + GroupNode radioGN = groupNodes.get(1); + assertEquals("Radio", radioGN.getGroupName()); + assertEquals(Permission.ADMIN, radioGN.getPermissions().get(0)); + assertFalse(radioGN.isHasChildren()); + GroupNode tngGN = groupNodes.get(2); + assertEquals("TNG", tngGN.getGroupName()); + assertEquals(Permission.ADMIN, tngGN.getPermissions().get(0)); + assertFalse(tngGN.isHasChildren()); + + // Test super admin - level 1 + groupNodes = groupsService.getSubgroups(lbt, user); assertEquals(1, groupNodes.size()); - } + GroupNode INAFGN = groupNodes.get(0); + assertEquals("INAF", INAFGN.getGroupName()); + assertEquals(Permission.ADMIN, INAFGN.getPermissions().get(0)); + assertTrue(INAFGN.isHasChildren()); + + // Test super admin - level 2 + groupNodes = groupsService.getSubgroups(lbtInaf, user); + assertEquals(2, groupNodes.size()); + GroupNode p1 = groupNodes.get(0); + assertEquals("P1", p1.getGroupName()); + assertEquals(1, p1.getPermissions().size()); + assertEquals(Permission.ADMIN, p1.getPermissions().get(0)); + assertFalse(p1.isHasChildren()); + GroupNode p2 = groupNodes.get(1); + assertEquals("P2", p2.getGroupName()); + assertEquals(Permission.ADMIN, p2.getPermissions().get(0)); + assertFalse(p2.isHasChildren()); + + // Setup lower permissions + permissionsRepository.delete(superAdminPermission); + UserGroupPermission p1Permission = new UserGroupPermission(); + p1Permission.setUser(user); + p1Permission.setGroup(lbtInafProgram1); + p1Permission.setPermission(Permission.MANAGE_MEMBERS); + permissionsRepository.save(p1Permission); + + UserGroupPermission lbtPermission = new UserGroupPermission(); + lbtPermission.setUser(user); + lbtPermission.setGroup(lbtInaf); + lbtPermission.setPermission(Permission.VIEW_MEMBERS); + permissionsRepository.save(lbtPermission); + + // Setup membership + Membership membership = new Membership(); + membership.setUser(user); + membership.setGroup(radio); + membershipRepository.save(membership); + + // Check level 0 (ROOT) + groupNodes = groupsService.getSubgroups(root, user); + assertEquals(2, groupNodes.size()); + lbtGN = groupNodes.get(0); + assertEquals("LBT", lbtGN.getGroupName()); + assertEquals(Permission.TRAVERSE, lbtGN.getPermissions().get(0)); + assertTrue(lbtGN.isHasChildren()); + radioGN = groupNodes.get(1); + assertEquals("Radio", radioGN.getGroupName()); + assertEquals(Permission.TRAVERSE, radioGN.getPermissions().get(0)); + assertFalse(radioGN.isHasChildren()); + + // Check level 1 + groupNodes = groupsService.getSubgroups(lbt, user); + assertEquals(1, groupNodes.size()); + INAFGN = groupNodes.get(0); + assertEquals("INAF", INAFGN.getGroupName()); + assertEquals(Permission.VIEW_MEMBERS, INAFGN.getPermissions().get(0)); + assertTrue(INAFGN.isHasChildren()); + + // Check level 2 + groupNodes = groupsService.getSubgroups(lbtInaf, user); + assertEquals(2, groupNodes.size()); + p1 = groupNodes.get(0); + assertEquals("P1", p1.getGroupName()); + assertEquals(1, p1.getPermissions().size()); + assertEquals(Permission.MANAGE_MEMBERS, p1.getPermissions().get(0)); + assertFalse(p1.isHasChildren()); + p2 = groupNodes.get(1); + assertEquals("P2", p2.getGroupName()); + assertEquals(Permission.VIEW_MEMBERS, p2.getPermissions().get(0)); + assertFalse(p2.isHasChildren()); + } }