Skip to content
This repository was archived by the owner on Mar 2, 2025. It is now read-only.
32 changes: 32 additions & 0 deletions src/main/java/com/projecty/projectyweb/group/Group.java
Original file line number Diff line number Diff line change
@@ -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<R> {
@Id
@GeneratedValue
protected Long id;

@NotBlank
protected String name;

@Transient
protected List<String> usernames;

@UpdateTimestamp
@Temporal(TemporalType.TIMESTAMP)
protected Date modifyDate;

@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
protected List<R> roles;
}
Original file line number Diff line number Diff line change
@@ -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<Group<?>, Long> {
}
18 changes: 18 additions & 0 deletions src/main/java/com/projecty/projectyweb/group/GroupService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.projecty.projectyweb.group;

import org.springframework.stereotype.Service;

@Service
public class GroupService<T> {
private final GroupRepository groupRepository;

public GroupService(GroupRepository groupRepository) {
this.groupRepository = groupRepository;
}

public Group<T> patchGroup(Group<T> existingGroup, Group<T> patchedGroup) {
if (!patchedGroup.getName().isEmpty())
existingGroup.setName(patchedGroup.getName());
return groupRepository.save(existingGroup);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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:
Expand Down
24 changes: 4 additions & 20 deletions src/main/java/com/projecty/projectyweb/project/Project.java
Original file line number Diff line number Diff line change
@@ -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;

Expand All @@ -20,30 +18,16 @@
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class Project {
@Id
@GeneratedValue
private Long id;

@NotBlank
private String name;

public class Project extends Group<ProjectRole> {
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "project")
private List<Task> tasks;

@Transient
private List<String> usernames;

@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
private List<ProjectRole> projectRoles;
private List<ProjectRole> projectRoleInvitations;

@ManyToOne
private Team team;

@UpdateTimestamp
@Temporal(TemporalType.TIMESTAMP)
private Date modifyDate;

@Transient
private Map<TaskStatus, Long> taskSummary;

Expand All @@ -53,7 +37,7 @@ public String toString() {
"id=" + id +
", name='" + name + '\'' +
", tasks=" + tasks +
", projectRoles=" + projectRoles +
", projectRoles=" + roles +
'}';
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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) {
Expand All @@ -41,6 +38,11 @@ public ProjectController(ProjectService projectService, ProjectRepository projec
this.projectRoleService = projectRoleService;
}

@GetMapping("invitations")
public List<ProjectRoleData> myInvitations() {
return projectService.getInvitationsForCurrentUser();
}

@GetMapping("")
public ProjectsData myProjects() {
return projectService.getProjectsForCurrentUser();
Expand Down Expand Up @@ -91,13 +93,13 @@ public void leaveProject(@PathVariable Long projectId) {
}

@PatchMapping("/{projectId}")
public Project patchProject(
public Group<ProjectRole> patchProject(
@PathVariable("projectId") Long projectId,
@RequestBody Project patchedProject
) {
Optional<Project> 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);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
29 changes: 18 additions & 11 deletions src/main/java/com/projecty/projectyweb/project/ProjectService.java
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -20,15 +22,16 @@
import java.util.*;

@Service
public class ProjectService {
public class ProjectService extends GroupService<ProjectRole> {
private final ProjectRepository projectRepository;
private final UserService userService;
private final ProjectRoleRepository projectRoleRepository;
private final ProjectRoleService projectRoleService;
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;
Expand All @@ -41,14 +44,15 @@ public void save(Project project) {
projectRepository.save(project);
}

// -
public boolean hasCurrentUserPermissionToEdit(Project project) {
User current = userService.getCurrentUser();
if (project.getTeam() != null) {
Optional<TeamRole> optionalTeamRole = teamRoleRepository.findByTeamAndAndUser(project.getTeam(), current);
return optionalTeamRole.isPresent() && optionalTeamRole.get().getName().equals(TeamRoles.MANAGER);
}
Optional<ProjectRole> 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) {
Expand All @@ -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<String> 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<ProjectRole> addProjectRolesByUsernames(Project project, List<String> usernames) {
List<ProjectRole> unsavedProjectRoles = projectRoleService.addRolesToProjectByUsernames(project, usernames);
return projectRoleService.saveProjectRoles(unsavedProjectRoles);
Expand All @@ -90,8 +90,15 @@ public ProjectsData getProjectsForCurrentUser() {
return addSummaryToProjectsData(new ProjectsData(projectRoles, teamRoles));
}

public List<ProjectRoleData> getInvitationsForCurrentUser() {
User user = userService.getCurrentUser();
List<ProjectRoleData> projectRoleInvitations = new ArrayList<>();
user.getProjectRoleInvitations().forEach(projectRole -> projectRoleInvitations.add(new ProjectRoleData(projectRole)));
return projectRoleInvitations;
}

public ProjectData getProjectData(Project project) {
List<ProjectRole> projectRoles = project.getProjectRoles();
List<ProjectRole> projectRoles = project.getRoles();
projectRoles.sort(Comparator.comparing(ProjectRole::getId));
return ProjectData.builder()
.project(project)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<ProjectRole> 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<ProjectRole> 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(
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -13,5 +14,6 @@ public interface ProjectRoleRepository extends JpaRepository<ProjectRole, Long>
Optional<ProjectRole> findRoleByUserAndProject(User user, Project project);

List<ProjectRole> findByProjectOrderByIdAsc(Project project);
int countByProjectAndName(Project project, ProjectRoles name);

int countByProjectAndName(Project project, Roles name);
}
Loading