diff --git a/src/main/java/com/projecty/projectyweb/group/Group.java b/src/main/java/com/projecty/projectyweb/group/Group.java new file mode 100644 index 0000000..b0be0fc --- /dev/null +++ b/src/main/java/com/projecty/projectyweb/group/Group.java @@ -0,0 +1,32 @@ +package com.projecty.projectyweb.group; + +import lombok.Getter; +import lombok.Setter; +import org.hibernate.annotations.UpdateTimestamp; + +import javax.persistence.*; +import javax.validation.constraints.NotBlank; +import java.util.Date; +import java.util.List; + +@MappedSuperclass +@Getter +@Setter +public class Group { + @Id + @GeneratedValue + protected Long id; + + @NotBlank + protected String name; + + @Transient + protected List usernames; + + @UpdateTimestamp + @Temporal(TemporalType.TIMESTAMP) + protected Date modifyDate; + + @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true) + protected List roles; +} diff --git a/src/main/java/com/projecty/projectyweb/group/GroupRepository.java b/src/main/java/com/projecty/projectyweb/group/GroupRepository.java new file mode 100644 index 0000000..5973514 --- /dev/null +++ b/src/main/java/com/projecty/projectyweb/group/GroupRepository.java @@ -0,0 +1,8 @@ +package com.projecty.projectyweb.group; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface GroupRepository extends JpaRepository, Long> { +} diff --git a/src/main/java/com/projecty/projectyweb/group/GroupService.java b/src/main/java/com/projecty/projectyweb/group/GroupService.java new file mode 100644 index 0000000..a74a350 --- /dev/null +++ b/src/main/java/com/projecty/projectyweb/group/GroupService.java @@ -0,0 +1,18 @@ +package com.projecty.projectyweb.group; + +import org.springframework.stereotype.Service; + +@Service +public class GroupService { + private final GroupRepository groupRepository; + + public GroupService(GroupRepository groupRepository) { + this.groupRepository = groupRepository; + } + + public Group patchGroup(Group existingGroup, Group patchedGroup) { + if (!patchedGroup.getName().isEmpty()) + existingGroup.setName(patchedGroup.getName()); + return groupRepository.save(existingGroup); + } +} diff --git a/src/main/java/com/projecty/projectyweb/notifications/NotificationService.java b/src/main/java/com/projecty/projectyweb/notifications/NotificationService.java index dd4c9fd..9b508e7 100644 --- a/src/main/java/com/projecty/projectyweb/notifications/NotificationService.java +++ b/src/main/java/com/projecty/projectyweb/notifications/NotificationService.java @@ -2,7 +2,7 @@ import com.projecty.projectyweb.project.Project; import com.projecty.projectyweb.project.ProjectRepository; -import com.projecty.projectyweb.project.role.ProjectRoles; +import com.projecty.projectyweb.role.Roles; import com.projecty.projectyweb.team.Team; import com.projecty.projectyweb.team.TeamRepository; import com.projecty.projectyweb.team.role.TeamRoles; @@ -80,7 +80,7 @@ public String buildNotificationString(Notification notification) { case CHANGED_PROJECT_ROLE: User user3 = userRepository.findById(Long.parseLong(ids.get(NotificationObjectType.USER))).get(); Project project3 = projectRepository.findById(Long.parseLong(ids.get(NotificationObjectType.PROJECT))).get(); - ProjectRoles projectRole3 = ProjectRoles.valueOf(ids.get(NotificationObjectType.PROJECT_ROLE_NAME)); + Roles projectRole3 = Roles.valueOf(ids.get(NotificationObjectType.PROJECT_ROLE_NAME)); values = new String[]{user3.getUsername(), project3.getName(), projectRole3.toString()}; break; case CHANGED_TEAM_ROLE: diff --git a/src/main/java/com/projecty/projectyweb/project/Project.java b/src/main/java/com/projecty/projectyweb/project/Project.java index 483c058..0db5ee4 100644 --- a/src/main/java/com/projecty/projectyweb/project/Project.java +++ b/src/main/java/com/projecty/projectyweb/project/Project.java @@ -1,16 +1,14 @@ package com.projecty.projectyweb.project; +import com.projecty.projectyweb.group.Group; import com.projecty.projectyweb.project.role.ProjectRole; import com.projecty.projectyweb.task.Task; import com.projecty.projectyweb.task.TaskStatus; import com.projecty.projectyweb.team.Team; import lombok.*; -import org.hibernate.annotations.UpdateTimestamp; import javax.persistence.*; -import javax.validation.constraints.NotBlank; -import java.util.Date; import java.util.List; import java.util.Map; @@ -20,30 +18,16 @@ @AllArgsConstructor @NoArgsConstructor @Builder -public class Project { - @Id - @GeneratedValue - private Long id; - - @NotBlank - private String name; - +public class Project extends Group { @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "project") private List tasks; - @Transient - private List usernames; - @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true) - private List projectRoles; + private List projectRoleInvitations; @ManyToOne private Team team; - @UpdateTimestamp - @Temporal(TemporalType.TIMESTAMP) - private Date modifyDate; - @Transient private Map taskSummary; @@ -53,7 +37,7 @@ public String toString() { "id=" + id + ", name='" + name + '\'' + ", tasks=" + tasks + - ", projectRoles=" + projectRoles + + ", projectRoles=" + roles + '}'; } } diff --git a/src/main/java/com/projecty/projectyweb/project/ProjectController.java b/src/main/java/com/projecty/projectyweb/project/ProjectController.java index 446fd54..da72225 100644 --- a/src/main/java/com/projecty/projectyweb/project/ProjectController.java +++ b/src/main/java/com/projecty/projectyweb/project/ProjectController.java @@ -2,6 +2,7 @@ import com.projecty.projectyweb.configurations.AnyPermission; import com.projecty.projectyweb.configurations.EditPermission; +import com.projecty.projectyweb.group.Group; import com.projecty.projectyweb.project.dto.ProjectData; import com.projecty.projectyweb.project.dto.ProjectsData; import com.projecty.projectyweb.project.role.ProjectRole; @@ -24,13 +25,9 @@ @RequestMapping("projects") public class ProjectController { private final ProjectService projectService; - private final ProjectRepository projectRepository; - private final UserService userService; - private final ProjectValidator projectValidator; - private final ProjectRoleService projectRoleService; public ProjectController(ProjectService projectService, ProjectRepository projectRepository, UserService userService, ProjectValidator projectValidator, ProjectRoleService projectRoleService) { @@ -41,6 +38,11 @@ public ProjectController(ProjectService projectService, ProjectRepository projec this.projectRoleService = projectRoleService; } + @GetMapping("invitations") + public List myInvitations() { + return projectService.getInvitationsForCurrentUser(); + } + @GetMapping("") public ProjectsData myProjects() { return projectService.getProjectsForCurrentUser(); @@ -91,13 +93,13 @@ public void leaveProject(@PathVariable Long projectId) { } @PatchMapping("/{projectId}") - public Project patchProject( + public Group patchProject( @PathVariable("projectId") Long projectId, @RequestBody Project patchedProject ) { Optional optionalProject = projectRepository.findById(projectId); if (optionalProject.isPresent() && projectService.hasCurrentUserPermissionToEdit(optionalProject.get())) { - return projectService.patchProject(optionalProject.get(), patchedProject); + return projectService.patchGroup(optionalProject.get(), patchedProject); } else { throw new ResponseStatusException(HttpStatus.NOT_FOUND); } diff --git a/src/main/java/com/projecty/projectyweb/project/ProjectNotificationAspect.java b/src/main/java/com/projecty/projectyweb/project/ProjectNotificationAspect.java index 3911113..c53d265 100644 --- a/src/main/java/com/projecty/projectyweb/project/ProjectNotificationAspect.java +++ b/src/main/java/com/projecty/projectyweb/project/ProjectNotificationAspect.java @@ -29,8 +29,8 @@ public ProjectNotificationAspect(UserService userService, UserRepository userRep @AfterReturning(value = "execution (* com.projecty.projectyweb.project.ProjectController.addProjectPost(..))", returning = "project") public void afterNewProjectCreated(Project project) { User currentUser = userService.getCurrentUser(); - if (project.getProjectRoles() != null) { - project.getProjectRoles().forEach(projectRole -> { + if (project.getRoles() != null) { + project.getRoles().forEach(projectRole -> { User projectRoleUser = projectRole.getUser(); if (!projectRoleUser.equals(currentUser)) { createAddedToProjectNotification(currentUser, project, projectRoleUser); diff --git a/src/main/java/com/projecty/projectyweb/project/ProjectService.java b/src/main/java/com/projecty/projectyweb/project/ProjectService.java index 742653f..64e766d 100644 --- a/src/main/java/com/projecty/projectyweb/project/ProjectService.java +++ b/src/main/java/com/projecty/projectyweb/project/ProjectService.java @@ -1,13 +1,15 @@ package com.projecty.projectyweb.project; +import com.projecty.projectyweb.group.GroupRepository; +import com.projecty.projectyweb.group.GroupService; import com.projecty.projectyweb.project.dto.ProjectData; import com.projecty.projectyweb.project.dto.ProjectsData; import com.projecty.projectyweb.project.dto.ProjectsTeamData; import com.projecty.projectyweb.project.role.ProjectRole; import com.projecty.projectyweb.project.role.ProjectRoleRepository; import com.projecty.projectyweb.project.role.ProjectRoleService; -import com.projecty.projectyweb.project.role.ProjectRoles; import com.projecty.projectyweb.project.role.dto.ProjectRoleData; +import com.projecty.projectyweb.role.Roles; import com.projecty.projectyweb.task.TaskRepository; import com.projecty.projectyweb.task.TaskStatus; import com.projecty.projectyweb.team.role.TeamRole; @@ -20,7 +22,7 @@ import java.util.*; @Service -public class ProjectService { +public class ProjectService extends GroupService { private final ProjectRepository projectRepository; private final UserService userService; private final ProjectRoleRepository projectRoleRepository; @@ -28,7 +30,8 @@ public class ProjectService { private final TeamRoleRepository teamRoleRepository; private final TaskRepository taskRepository; - public ProjectService(ProjectRepository projectRepository, UserService userService, ProjectRoleRepository projectRoleRepository, ProjectRoleService projectRoleService, TeamRoleRepository teamRoleRepository, TaskRepository taskRepository) { + public ProjectService(ProjectRepository projectRepository, UserService userService, ProjectRoleRepository projectRoleRepository, ProjectRoleService projectRoleService, TeamRoleRepository teamRoleRepository, TaskRepository taskRepository, GroupRepository groupRepository) { + super(groupRepository); this.projectRepository = projectRepository; this.userService = userService; this.projectRoleRepository = projectRoleRepository; @@ -41,6 +44,7 @@ public void save(Project project) { projectRepository.save(project); } + // - public boolean hasCurrentUserPermissionToEdit(Project project) { User current = userService.getCurrentUser(); if (project.getTeam() != null) { @@ -48,7 +52,7 @@ public boolean hasCurrentUserPermissionToEdit(Project project) { return optionalTeamRole.isPresent() && optionalTeamRole.get().getName().equals(TeamRoles.MANAGER); } Optional optionalRole = projectRoleRepository.findRoleByUserAndProject(current, project); - return optionalRole.isPresent() && optionalRole.get().getName().equals(ProjectRoles.ADMIN); + return optionalRole.isPresent() && optionalRole.get().getName().equals(Roles.MANAGER); } public boolean hasCurrentUserPermissionToView(Project project) { @@ -59,22 +63,18 @@ public boolean hasCurrentUserPermissionToView(Project project) { return hasUserRoleInProject(current, project); } + // + public boolean hasUserRoleInProject(User user, Project project) { return projectRoleRepository.findRoleByUserAndProject(user, project).isPresent(); } + // + Project createNewProjectAndSave(Project project, List usernames) { projectRoleService.addCurrentUserToProjectAsAdmin(project); projectRoleService.addRolesToProjectByUsernames(project, usernames); return projectRepository.save(project); } - Project patchProject(Project existingProject, Project patchedProject) { - if (!patchedProject.getName().isEmpty()) - existingProject.setName(patchedProject.getName()); - return projectRepository.save(existingProject); - } - public List addProjectRolesByUsernames(Project project, List usernames) { List unsavedProjectRoles = projectRoleService.addRolesToProjectByUsernames(project, usernames); return projectRoleService.saveProjectRoles(unsavedProjectRoles); @@ -90,8 +90,15 @@ public ProjectsData getProjectsForCurrentUser() { return addSummaryToProjectsData(new ProjectsData(projectRoles, teamRoles)); } + public List getInvitationsForCurrentUser() { + User user = userService.getCurrentUser(); + List projectRoleInvitations = new ArrayList<>(); + user.getProjectRoleInvitations().forEach(projectRole -> projectRoleInvitations.add(new ProjectRoleData(projectRole))); + return projectRoleInvitations; + } + public ProjectData getProjectData(Project project) { - List projectRoles = project.getProjectRoles(); + List projectRoles = project.getRoles(); projectRoles.sort(Comparator.comparing(ProjectRole::getId)); return ProjectData.builder() .project(project) diff --git a/src/main/java/com/projecty/projectyweb/project/role/ProjectRole.java b/src/main/java/com/projecty/projectyweb/project/role/ProjectRole.java index 1e9ef1e..2a7e10e 100644 --- a/src/main/java/com/projecty/projectyweb/project/role/ProjectRole.java +++ b/src/main/java/com/projecty/projectyweb/project/role/ProjectRole.java @@ -4,35 +4,39 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.projecty.projectyweb.project.Project; +import com.projecty.projectyweb.role.Role; +import com.projecty.projectyweb.role.Roles; import com.projecty.projectyweb.user.User; import lombok.Getter; import lombok.Setter; -import javax.persistence.*; +import javax.persistence.Entity; +import javax.persistence.ManyToOne; @Entity @JsonSerialize @Getter @Setter -public class ProjectRole { - public ProjectRole(ProjectRoles name, User user, Project project) { +public class ProjectRole extends Role { + + public ProjectRole(Roles name, User user, Project project) { this.name = name; - this.user = user; this.project = project; + this.user = user; } public ProjectRole() { } - @Id - @GeneratedValue - private Long id; - - // TODO Remove this redundancy - private ProjectRoles name; - - @ManyToOne(fetch = FetchType.LAZY) - private User user; + public ProjectRole(Roles name, User user, Project project, boolean isInvitation) { + this.name = name; + this.project = project; + if (isInvitation) { + this.invitedUser = user; + } else { + this.user = user; + } + } @ManyToOne @JsonIgnore diff --git a/src/main/java/com/projecty/projectyweb/project/role/ProjectRoleController.java b/src/main/java/com/projecty/projectyweb/project/role/ProjectRoleController.java index ff67cff..5da7a09 100644 --- a/src/main/java/com/projecty/projectyweb/project/role/ProjectRoleController.java +++ b/src/main/java/com/projecty/projectyweb/project/role/ProjectRoleController.java @@ -23,6 +23,31 @@ public ProjectRoleController(UserService userService, ProjectRoleRepository proj this.projectRoleService = projectRoleService; } + @PostMapping("/{roleId}/accept") + public ProjectRole acceptInvitation(@PathVariable Long roleId) { + User current = userService.getCurrentUser(); + Optional optionalProjectRole = projectRoleRepository.findById(roleId); + if (optionalProjectRole.isPresent() && optionalProjectRole.get().getInvitedUser().equals(current)) { + return projectRoleService.acceptInvitation(optionalProjectRole.get()); + } + throw new ResponseStatusException(HttpStatus.NOT_FOUND); + } + + + @DeleteMapping("/{roleId}/delete") + @EditPermission + public void deleteInvitation( + @PathVariable Long roleId + ) { + User current = userService.getCurrentUser(); + Optional toDeleteProjectRoleInvitation = projectRoleRepository.findById(roleId); + if (toDeleteProjectRoleInvitation.isPresent() && toDeleteProjectRoleInvitation.get().getInvitedUser().equals(current)) { + projectRoleService.deleteInvitationFromProject(toDeleteProjectRoleInvitation.get()); + } else { + throw new ResponseStatusException(HttpStatus.NOT_FOUND); + } + } + @DeleteMapping("/{roleId}") @EditPermission public void deleteUserPost( diff --git a/src/main/java/com/projecty/projectyweb/project/role/ProjectRoleRepository.java b/src/main/java/com/projecty/projectyweb/project/role/ProjectRoleRepository.java index f7d0901..15909a2 100644 --- a/src/main/java/com/projecty/projectyweb/project/role/ProjectRoleRepository.java +++ b/src/main/java/com/projecty/projectyweb/project/role/ProjectRoleRepository.java @@ -1,6 +1,7 @@ package com.projecty.projectyweb.project.role; import com.projecty.projectyweb.project.Project; +import com.projecty.projectyweb.role.Roles; import com.projecty.projectyweb.user.User; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; @@ -13,5 +14,6 @@ public interface ProjectRoleRepository extends JpaRepository Optional findRoleByUserAndProject(User user, Project project); List findByProjectOrderByIdAsc(Project project); - int countByProjectAndName(Project project, ProjectRoles name); + + int countByProjectAndName(Project project, Roles name); } diff --git a/src/main/java/com/projecty/projectyweb/project/role/ProjectRoleService.java b/src/main/java/com/projecty/projectyweb/project/role/ProjectRoleService.java index a59b1ee..f8234ff 100644 --- a/src/main/java/com/projecty/projectyweb/project/role/ProjectRoleService.java +++ b/src/main/java/com/projecty/projectyweb/project/role/ProjectRoleService.java @@ -2,6 +2,7 @@ import com.projecty.projectyweb.project.Project; import com.projecty.projectyweb.project.ProjectRepository; +import com.projecty.projectyweb.role.Roles; import com.projecty.projectyweb.user.User; import com.projecty.projectyweb.user.UserService; import org.springframework.stereotype.Service; @@ -26,28 +27,28 @@ public void save(ProjectRole projectRole) { private void removeExistingUsersInProjectFromSet(Set users, Project project) { if (project.getId() != null) { - Set existingUsers = getProjectRoleUsers(project); + Set existingUsers = getProjectRoleUsersAndInvitedUsers(project); users.removeAll(existingUsers); } } public List addRolesToProjectByUsernames(Project project, List usernames) { - List projectRoles = new ArrayList<>(); + List invitedRoles = new ArrayList<>(); if (usernames != null) { Set users = userService.getUserSetByUsernamesWithoutCurrentUser(usernames); removeExistingUsersInProjectFromSet(users, project); users.forEach(user -> { if (user.getSettings().getCanBeAddedToProject()) { - projectRoles.add(new ProjectRole(ProjectRoles.USER, user, project)); + invitedRoles.add(new ProjectRole(Roles.MEMBER, user, project, true)); } }); } - if (project.getProjectRoles() == null) { - project.setProjectRoles(projectRoles); - } else if (projectRoles.size() > 0) { - project.getProjectRoles().addAll(projectRoles); + if (project.getProjectRoleInvitations() == null) { + project.setProjectRoleInvitations(invitedRoles); + } else if (invitedRoles.size() > 0) { + project.getProjectRoleInvitations().addAll(invitedRoles); } - return projectRoles; + return invitedRoles; } public List saveProjectRoles(List projectRoles) { @@ -56,41 +57,51 @@ public List saveProjectRoles(List projectRoles) { return savedProjectRoles; } - public Set getProjectRoleUsers(Project project) { + public Set getProjectRoleUsersAndInvitedUsers(Project project) { List projectRoles = projectRoleRepository.findByProjectOrderByIdAsc(project); Set users = new HashSet<>(); - projectRoles.forEach(projectRole -> users.add(projectRole.getUser())); + projectRoles.forEach(projectRole -> { + if (projectRole.getUser() != null) { + users.add(projectRole.getUser()); + } else { + users.add(projectRole.getInvitedUser()); + } + }); return users; } public void addCurrentUserToProjectAsAdmin(Project project) { User current = userService.getCurrentUser(); - ProjectRole projectRole = new ProjectRole(ProjectRoles.ADMIN, current, project); - if (project.getProjectRoles() == null) { + ProjectRole projectRole = new ProjectRole(Roles.MANAGER, current, project); + if (project.getRoles() == null) { List projectRoles = new ArrayList<>(); projectRoles.add(projectRole); - project.setProjectRoles(projectRoles); + project.setRoles(projectRoles); } else { - project.getProjectRoles().add(projectRole); + project.getRoles().add(projectRole); } } public void deleteRoleFromProject(ProjectRole role) { Project project = role.getProject(); - List projectRoles = project.getProjectRoles(); + List projectRoles = project.getRoles(); projectRoles.remove(role); - project.setProjectRoles(projectRoles); + project.setRoles(projectRoles); projectRepository.save(project); } + public void deleteInvitationFromProject(ProjectRole projectRole) { + deleteRoleFromProject(projectRole); + } + public void leaveProject(Project project) throws NoAdminsInProjectException { User user = userService.getCurrentUser(); Optional optionalProjectRole = projectRoleRepository.findRoleByUserAndProject(user, project); if (optionalProjectRole.isPresent()) { ProjectRole projectRole = optionalProjectRole.get(); - int admins = projectRoleRepository.countByProjectAndName(project, ProjectRoles.ADMIN); - if ((projectRole.getName().equals(ProjectRoles.ADMIN) && admins - 1 > 0) || project.getName().equals(ProjectRoles.USER)) { - project.getProjectRoles().remove(optionalProjectRole.get()); + int admins = projectRoleRepository.countByProjectAndName(project, Roles.MANAGER); + if ((projectRole.getName().equals(Roles.MANAGER) && admins - 1 > 0)) { + project.getRoles().remove(optionalProjectRole.get()); projectRepository.save(project); } else { throw new NoAdminsInProjectException(); @@ -105,4 +116,20 @@ public ProjectRole patchProjectRole(ProjectRole projectRole, ProjectRole patched } return projectRole; } + + public ProjectRole acceptInvitation(ProjectRole projectRole) { + projectRole.setUser(projectRole.getInvitedUser()); + projectRole.setInvitedUser(null); + projectRole = projectRoleRepository.save(projectRole); + + Project project = projectRole.getProject(); + List projectRoles = project.getRoles(); + List projectRoleInvitations = project.getProjectRoleInvitations(); + projectRoles.add(projectRole); + projectRoleInvitations.remove(projectRole); + project.setRoles(projectRoles); + project.setProjectRoleInvitations(projectRoleInvitations); + projectRepository.save(project); + return projectRole; + } } diff --git a/src/main/java/com/projecty/projectyweb/project/role/ProjectRoles.java b/src/main/java/com/projecty/projectyweb/project/role/ProjectRoles.java deleted file mode 100644 index 83e8340..0000000 --- a/src/main/java/com/projecty/projectyweb/project/role/ProjectRoles.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.projecty.projectyweb.project.role; - -public enum ProjectRoles { - OWNER, ADMIN, USER -} diff --git a/src/main/java/com/projecty/projectyweb/project/role/dto/ProjectRoleData.java b/src/main/java/com/projecty/projectyweb/project/role/dto/ProjectRoleData.java index c31858e..aef4205 100644 --- a/src/main/java/com/projecty/projectyweb/project/role/dto/ProjectRoleData.java +++ b/src/main/java/com/projecty/projectyweb/project/role/dto/ProjectRoleData.java @@ -2,7 +2,7 @@ import com.projecty.projectyweb.project.Project; import com.projecty.projectyweb.project.role.ProjectRole; -import com.projecty.projectyweb.project.role.ProjectRoles; +import com.projecty.projectyweb.role.Roles; import lombok.Getter; import lombok.Setter; @@ -11,7 +11,7 @@ public class ProjectRoleData { private Long id; private Project project; - private ProjectRoles name; + private Roles name; public ProjectRoleData(ProjectRole projectRole) { this.id = projectRole.getId(); diff --git a/src/main/java/com/projecty/projectyweb/role/Role.java b/src/main/java/com/projecty/projectyweb/role/Role.java new file mode 100644 index 0000000..f35c8ca --- /dev/null +++ b/src/main/java/com/projecty/projectyweb/role/Role.java @@ -0,0 +1,26 @@ +package com.projecty.projectyweb.role; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.projecty.projectyweb.user.User; +import lombok.Getter; +import lombok.Setter; + +import javax.persistence.*; + +@MappedSuperclass +@Getter +@Setter +public class Role { + @Id + @GeneratedValue + protected Long id; + + @ManyToOne(fetch = FetchType.LAZY) + protected User user; + + @ManyToOne(fetch = FetchType.LAZY) + @JsonIgnore + protected User invitedUser; + + protected Roles name; +} diff --git a/src/main/java/com/projecty/projectyweb/role/Roles.java b/src/main/java/com/projecty/projectyweb/role/Roles.java new file mode 100644 index 0000000..9f86a62 --- /dev/null +++ b/src/main/java/com/projecty/projectyweb/role/Roles.java @@ -0,0 +1,5 @@ +package com.projecty.projectyweb.role; + +public enum Roles { + MANAGER, MEMBER +} diff --git a/src/main/java/com/projecty/projectyweb/task/TaskService.java b/src/main/java/com/projecty/projectyweb/task/TaskService.java index b6b86ad..803dee1 100644 --- a/src/main/java/com/projecty/projectyweb/task/TaskService.java +++ b/src/main/java/com/projecty/projectyweb/task/TaskService.java @@ -93,14 +93,14 @@ public List getNotAssignedUsernameListForTask(Task task) { teamRoleUsers.removeAll(task.getAssignedUsers()); return userService.getUsernamesFromUserList(new ArrayList<>(teamRoleUsers)); } - Set projectRoleUsers = projectRoleService.getProjectRoleUsers(project); + Set projectRoleUsers = projectRoleService.getProjectRoleUsersAndInvitedUsers(project); projectRoleUsers.removeAll(task.getAssignedUsers()); return userService.getUsernamesFromUserList(new ArrayList<>(projectRoleUsers)); } private boolean hasUserAccessToTask(Task task, User user) { - return (task.getProject().getProjectRoles() != null && - projectRoleService.getProjectRoleUsers(task.getProject()).contains(user)) + return (task.getProject().getRoles() != null && + projectRoleService.getProjectRoleUsersAndInvitedUsers(task.getProject()).contains(user)) || (task.getProject().getTeam() != null && (teamRoleService.getTeamRoleUsers(task.getProject().getTeam()).contains(user))); } diff --git a/src/main/java/com/projecty/projectyweb/user/User.java b/src/main/java/com/projecty/projectyweb/user/User.java index 322e35e..34082bb 100644 --- a/src/main/java/com/projecty/projectyweb/user/User.java +++ b/src/main/java/com/projecty/projectyweb/user/User.java @@ -48,6 +48,14 @@ public class User implements Serializable { @JsonIgnore private List projectRoles; + @OneToMany( + mappedBy = "invitedUser", + cascade = CascadeType.ALL, + orphanRemoval = true + ) + @JsonIgnore + private List projectRoleInvitations; + @OneToMany( mappedBy = "user", cascade = CascadeType.ALL, diff --git a/src/test/java/com/projecty/projectyweb/notification/NotificationServiceTests.java b/src/test/java/com/projecty/projectyweb/notification/NotificationServiceTests.java index 112fefb..edf5037 100644 --- a/src/test/java/com/projecty/projectyweb/notification/NotificationServiceTests.java +++ b/src/test/java/com/projecty/projectyweb/notification/NotificationServiceTests.java @@ -49,7 +49,9 @@ public void init() { public void whenBuildNotificationString_shouldReturnNotificationString() { final String USERNAME = "notificationServiceUsernameA"; User user = userRepository.save(User.builder().username(USERNAME).build()); - Project project = projectRepository.save(Project.builder().name(PROJECT_NAME).build()); + Project project = new Project(); + project.setName(PROJECT_NAME); + project = projectRepository.save(project); Map ids = new LinkedHashMap<>(); ids.put(NotificationObjectType.USER, String.valueOf(user.getId())); ids.put(NotificationObjectType.PROJECT, String.valueOf(project.getId())); @@ -63,7 +65,9 @@ public void whenBuildNotificationString_shouldReturnNotificationString() { @Transactional public void whenGetAllNotifications_shouldReturnAllNotifications() { User user = userRepository.save(User.builder().username(USERNAME_B).build()); - Project project = projectRepository.save(Project.builder().name(PROJECT_NAME).build()); + Project project = new Project(); + project.setName(PROJECT_NAME); + project = projectRepository.save(project); Map ids = new LinkedHashMap<>(); ids.put(NotificationObjectType.USER, String.valueOf(user.getId())); ids.put(NotificationObjectType.PROJECT, String.valueOf(project.getId())); diff --git a/src/test/java/com/projecty/projectyweb/notification/ProjectNotificationAspectTests.java b/src/test/java/com/projecty/projectyweb/notification/ProjectNotificationAspectTests.java index 6df06bb..bf7a48b 100644 --- a/src/test/java/com/projecty/projectyweb/notification/ProjectNotificationAspectTests.java +++ b/src/test/java/com/projecty/projectyweb/notification/ProjectNotificationAspectTests.java @@ -7,7 +7,7 @@ import com.projecty.projectyweb.project.ProjectRepository; import com.projecty.projectyweb.project.role.ProjectRole; import com.projecty.projectyweb.project.role.ProjectRoleRepository; -import com.projecty.projectyweb.project.role.ProjectRoles; +import com.projecty.projectyweb.role.Roles; import com.projecty.projectyweb.user.User; import com.projecty.projectyweb.user.UserRepository; import org.junit.Test; @@ -55,7 +55,7 @@ public void whenCreateProject_shouldSendNotifications() { projectRole.setProject(project); projectRole.setUser(savedUser); projectRole = projectRoleRepository.save(projectRole); - project.setProjectRoles(Collections.singletonList(projectRole)); + project.setRoles(Collections.singletonList(projectRole)); project = projectRepository.findById(project.getId()).get(); projectNotificationAspect.afterNewProjectCreated(project); assertThat(notificationRepository.findByUser(savedUser).size(), is(1)); @@ -85,9 +85,9 @@ public void whenChangeProjectRole_shouldSendNotifications() { ProjectRole projectRole = new ProjectRole(); projectRole.setProject(project); projectRole.setUser(savedUser); - projectRole.setName(ProjectRoles.ADMIN); + projectRole.setName(Roles.MANAGER); projectRole = projectRoleRepository.save(projectRole); - project.setProjectRoles(Collections.singletonList(projectRole)); + project.setRoles(Collections.singletonList(projectRole)); projectNotificationAspect.afterProjectRolePatched(projectRole); assertThat(notificationRepository.findByUser(savedUser).size(), is(1)); } diff --git a/src/test/java/com/projecty/projectyweb/project/ProjectControllerTests.java b/src/test/java/com/projecty/projectyweb/project/ProjectControllerTests.java index 2519536..a3b26b0 100644 --- a/src/test/java/com/projecty/projectyweb/project/ProjectControllerTests.java +++ b/src/test/java/com/projecty/projectyweb/project/ProjectControllerTests.java @@ -2,9 +2,10 @@ import com.google.gson.Gson; import com.projecty.projectyweb.ProjectyWebApplication; +import com.projecty.projectyweb.group.GroupRepository; import com.projecty.projectyweb.project.role.ProjectRole; import com.projecty.projectyweb.project.role.ProjectRoleRepository; -import com.projecty.projectyweb.project.role.ProjectRoles; +import com.projecty.projectyweb.role.Roles; import com.projecty.projectyweb.team.Team; import com.projecty.projectyweb.team.role.TeamRole; import com.projecty.projectyweb.team.role.TeamRoles; @@ -50,11 +51,15 @@ public class ProjectControllerTests { ProjectRoleRepository projectRoleRepository; @MockBean UserService userService; + + @MockBean + GroupRepository groupRepository; @Autowired private MockMvc mockMvc; private Project project; private User user; + @Before public void setup() { user = new User(); @@ -70,11 +75,11 @@ public void setup() { List projectRoles = new ArrayList<>(); - ProjectRole projectRole = new ProjectRole(ProjectRoles.ADMIN, user, project); + ProjectRole projectRole = new ProjectRole(Roles.MANAGER, user, project); projectRole.setId(1L); projectRoles.add(projectRole); - ProjectRole projectRole1 = new ProjectRole(ProjectRoles.USER, user1, project); + ProjectRole projectRole1 = new ProjectRole(Roles.MEMBER, user1, project); projectRole1.setId(2L); projectRoles.add(projectRole1); @@ -94,7 +99,7 @@ public void setup() { rolesUser1.add(projectRole1); user1.setProjectRoles(rolesUser1); - project.setProjectRoles(projectRoles); + project.setRoles(projectRoles); Mockito.when(userRepository.findByUsername(user.getUsername())) .thenReturn(Optional.of(user)); @@ -104,7 +109,7 @@ public void setup() { .thenReturn(Optional.of(user)); Mockito.when(userRepository.findById(user1.getId())) .thenReturn(Optional.of(user1)); - Mockito.when(projectRepository.save(project)) + Mockito.when(groupRepository.save(project)) .thenReturn(project); Mockito.when(projectRepository.save(any(Project.class))) .thenReturn(project); @@ -131,11 +136,17 @@ public void givenRequestOnMyProject_shouldReturnProjectRolesAndTeamRoles() throw .andExpect(jsonPath("teamProjects").exists()); } + public void givenRequestOnGetMyProjectIntivations_shouldReturnProjectInvitations() throws Exception { + mockMvc.perform(get("/projects/invitations")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$").isArray()); + } + @Test @WithMockUser public void givenRequestOnPostFormWithoutOtherUsers_shouldReturnOk() throws Exception { Project project1 = project; - project1.setProjectRoles(null); + project1.setRoles(null); mockMvc.perform(post("/projects").with(csrf()) .contentType(MediaType.APPLICATION_JSON) .content(new Gson().toJson(project1))) @@ -170,7 +181,7 @@ public void givenRequestOnAddUsers_shouldReturnOk() throws Exception { @Test - @WithMockUser + @WithMockUser("projectUser") public void givenRequestOnChangeName_shouldReturnOk() throws Exception { Project editedProject = new Project(); editedProject.setId(1L); @@ -194,7 +205,7 @@ public void givenRequestOnGetProject_shouldReturnProject() throws Exception { public void givenRequestOnChangeRole_shouldReturnOk() throws Exception { mockMvc.perform(patch("/projectRoles/2").with(csrf()) .contentType(MediaType.APPLICATION_JSON) - .content("{\"name\":\"" + ProjectRoles.ADMIN + "\"}")) + .content("{\"name\":\"" + Roles.MANAGER + "\"}")) .andExpect(status().isOk()); } diff --git a/src/test/java/com/projecty/projectyweb/project/ProjectServiceTests.java b/src/test/java/com/projecty/projectyweb/project/ProjectServiceTests.java index acead65..8b69d7d 100644 --- a/src/test/java/com/projecty/projectyweb/project/ProjectServiceTests.java +++ b/src/test/java/com/projecty/projectyweb/project/ProjectServiceTests.java @@ -2,8 +2,8 @@ import com.projecty.projectyweb.ProjectyWebApplication; import com.projecty.projectyweb.project.role.ProjectRole; -import com.projecty.projectyweb.project.role.ProjectRoles; import com.projecty.projectyweb.project.role.dto.ProjectRoleData; +import com.projecty.projectyweb.role.Roles; import com.projecty.projectyweb.user.User; import com.projecty.projectyweb.user.UserRepository; import org.hamcrest.core.Is; @@ -37,19 +37,21 @@ public class ProjectServiceTests { private static final String USERNAME_1 = "projectServiceUser1"; private static final String USERNAME_2 = "projectServiceUser2"; + private static final String USERNAME_3 = "projectServiceUser3"; @SuppressWarnings("OptionalGetWithoutIsPresent") @Test - @WithMockUser + @WithMockUser(USERNAME_1) @Transactional - public void whenAddRolesToProjectSByUsernames_shouldReturnSavedProjectRoles() { + public void whenInviteToProjectByUsernames_shouldReturnSavedProjectRoles() { userRepository.save(User.builder().username(USERNAME_1).build()); + userRepository.save(User.builder().username(USERNAME_3).build()); Project project = new Project(); project = projectRepository.save(project); - List usernames = Collections.singletonList(USERNAME_1); + List usernames = Collections.singletonList(USERNAME_3); List savedRoles = projectService.addProjectRolesByUsernames(project, usernames); assertThat(savedRoles.size(), is(1)); - assertThat(projectRepository.findById(project.getId()).get().getProjectRoles().size(), is(1)); + assertThat(projectRepository.findById(project.getId()).get().getProjectRoleInvitations().size(), is(1)); } @Test @@ -59,6 +61,6 @@ public void whenGetProjectRoleForCurrentUserByProjectId_shouldReturnProjectRoleD Project project = projectService.createNewProjectAndSave(new Project(), null); ProjectRoleData projectRoleData = projectService.getProjectRoleForCurrentUserByProjectId(project.getId()); assertThat(projectRoleData.getProject().getId(), Is.is(project.getId())); - assertThat(projectRoleData.getName(), Is.is(ProjectRoles.ADMIN)); + assertThat(projectRoleData.getName(), Is.is(Roles.MANAGER)); } } diff --git a/src/test/java/com/projecty/projectyweb/project/role/ProjectRoleServiceTests.java b/src/test/java/com/projecty/projectyweb/project/role/ProjectRoleServiceTests.java index 0ddfed2..d5f90de 100644 --- a/src/test/java/com/projecty/projectyweb/project/role/ProjectRoleServiceTests.java +++ b/src/test/java/com/projecty/projectyweb/project/role/ProjectRoleServiceTests.java @@ -21,8 +21,7 @@ import java.util.List; import java.util.Optional; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.CoreMatchers.*; import static org.hamcrest.MatcherAssert.assertThat; @ActiveProfiles("test") @@ -83,4 +82,24 @@ public void whenAddTeamRolesByUsernames_shouldReturnTeamWithTeamRoles() { assert false; } } + + @Test + @Transactional + public void whenAcceptInvitation_shouldBeAccepted() { + Project project = new Project(); + project.setRoles(new ArrayList<>()); + project = projectRepository.save(project); + User user = userRepository.save(new User()); + ProjectRole projectRole = new ProjectRole(); + projectRole.setInvitedUser(user); + projectRole.setProject(project); + projectRole = projectRoleRepository.save(projectRole); + List projectRoleInvitations = new ArrayList<>(); + projectRoleInvitations.add(projectRole); + project.setProjectRoleInvitations(projectRoleInvitations); + project = projectRepository.save(project); + projectRole = projectRoleService.acceptInvitation(projectRole); + assertThat(projectRole.getInvitedUser(), is(nullValue())); + assertThat(projectRole.getProject().getProjectRoleInvitations().size(), is(0)); + } } diff --git a/src/test/java/com/projecty/projectyweb/task/TaskControllerTests.java b/src/test/java/com/projecty/projectyweb/task/TaskControllerTests.java index 07febf2..aac53dd 100644 --- a/src/test/java/com/projecty/projectyweb/task/TaskControllerTests.java +++ b/src/test/java/com/projecty/projectyweb/task/TaskControllerTests.java @@ -7,7 +7,7 @@ import com.projecty.projectyweb.project.ProjectRepository; import com.projecty.projectyweb.project.role.ProjectRole; import com.projecty.projectyweb.project.role.ProjectRoleRepository; -import com.projecty.projectyweb.project.role.ProjectRoles; +import com.projecty.projectyweb.role.Roles; import com.projecty.projectyweb.user.User; import com.projecty.projectyweb.user.UserRepository; import org.junit.Before; @@ -77,14 +77,14 @@ public void setup() { projectRole.setId(1L); projectRole.setUser(user); projectRole.setProject(project); - projectRole.setName(ProjectRoles.ADMIN); + projectRole.setName(Roles.MANAGER); projectRoles.add(projectRole); ProjectRole projectRole1 = new ProjectRole(); projectRole1.setId(2L); projectRole1.setUser(user1); projectRole1.setProject(project); - projectRole1.setName(ProjectRoles.USER); + projectRole1.setName(Roles.MEMBER); projectRoles.add(projectRole1); @@ -96,7 +96,7 @@ public void setup() { rolesUser1.add(projectRole1); user1.setProjectRoles(rolesUser1); - project.setProjectRoles(projectRoles); + project.setRoles(projectRoles); List tasks = new ArrayList<>(); diff --git a/src/test/java/com/projecty/projectyweb/task/TaskServiceTests.java b/src/test/java/com/projecty/projectyweb/task/TaskServiceTests.java index c8795c0..7c47d6d 100644 --- a/src/test/java/com/projecty/projectyweb/task/TaskServiceTests.java +++ b/src/test/java/com/projecty/projectyweb/task/TaskServiceTests.java @@ -6,7 +6,7 @@ import com.projecty.projectyweb.project.role.ProjectRole; import com.projecty.projectyweb.project.role.ProjectRoleRepository; import com.projecty.projectyweb.project.role.ProjectRoleService; -import com.projecty.projectyweb.project.role.ProjectRoles; +import com.projecty.projectyweb.role.Roles; import com.projecty.projectyweb.user.User; import com.projecty.projectyweb.user.UserRepository; import com.projecty.projectyweb.user.UserService; @@ -171,14 +171,14 @@ public void whenAssignUserByUsername_shouldReturnTaskWithAssignedUser() { project = projectRepository.save(project); ProjectRole projectRole = new ProjectRole(); - projectRole.setName(ProjectRoles.ADMIN); + projectRole.setName(Roles.MANAGER); projectRole.setUser(user); projectRole.setProject(project); projectRoleRepository.save(projectRole); List projectRoles = new ArrayList<>(); projectRoles.add(projectRole); - project.setProjectRoles(projectRoles); + project.setRoles(projectRoles); project = projectRepository.save(project); Task task = new Task(); @@ -213,13 +213,13 @@ public void whenGetNotAssignedUsernameListForTask_shouldReturnListStringWithUser project = projectRepository.save(project); ProjectRole projectRole = new ProjectRole(); - projectRole.setName(ProjectRoles.ADMIN); + projectRole.setName(Roles.MANAGER); projectRole.setUser(user); projectRole.setProject(project); projectRoleRepository.save(projectRole); ProjectRole projectRole1 = new ProjectRole(); - projectRole1.setName(ProjectRoles.ADMIN); + projectRole1.setName(Roles.MANAGER); projectRole1.setUser(notAssigned); projectRole1.setProject(project); projectRoleRepository.save(projectRole1); @@ -295,7 +295,7 @@ public void whenCheckIfHasPermissionToEdit_shouldReturnTrue() { ProjectRole projectRole = new ProjectRole(); projectRole.setUser(currentUser); projectRole.setProject(project); - projectRole.setName(ProjectRoles.ADMIN); + projectRole.setName(Roles.MANAGER); projectRoleService.save(projectRole); Task task = new Task();