ProjectsController.java
package edu.ucsb.cs.citelines.controller;
import edu.ucsb.cs.citelines.entity.Project;
import edu.ucsb.cs.citelines.entity.ProjectCollaborator;
import edu.ucsb.cs.citelines.errors.EntityNotFoundException;
import edu.ucsb.cs.citelines.model.CurrentUser;
import edu.ucsb.cs.citelines.repository.ProjectCollaboratorRepository;
import edu.ucsb.cs.citelines.repository.ProjectRepository;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import java.time.LocalDateTime;
import java.util.List;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@Tag(name = "Projects")
@RequestMapping("/api/projects")
@RestController
@Slf4j
public class ProjectsController extends ApiController {
@Autowired private ProjectRepository projectRepository;
@Autowired private ProjectCollaboratorRepository projectCollaboratorRepository;
/**
* This method creates a new Project, owned by the current user.
*
* @param name the name of the project
* @param description the description of the project
* @return the created project
*/
@Operation(summary = "Create a new project")
@PreAuthorize("hasRole('ROLE_ADMIN') || hasRole('ROLE_RESEARCHER')")
@PostMapping("/post")
public Project postProject(
@Parameter(name = "name") @RequestParam String name,
@Parameter(name = "description") @RequestParam String description) {
CurrentUser currentUser = getCurrentUser();
Project project =
Project.builder()
.name(name)
.description(description)
.owner(currentUser.getUser().getEmail())
.dateCreated(LocalDateTime.now())
.build();
return projectRepository.save(project);
}
/**
* This method returns a list of projects owned by the current user.
*
* @return a list of projects owned by the current user.
*/
@Operation(summary = "List all projects owned by the current user")
@PreAuthorize("hasRole('ROLE_RESEARCHER')")
@GetMapping("/list/owner")
public Iterable<Project> listForOwner() {
String email = getCurrentUser().getUser().getEmail();
return projectRepository.findByOwner(email);
}
/**
* This method returns a list of projects the current user collaborates on.
*
* @return a list of projects the current user collaborates on.
*/
@Operation(summary = "List all projects the current user collaborates on")
@PreAuthorize("hasRole('ROLE_USER')")
@GetMapping("/list/collaborator")
public List<Project> listForCollaborator() {
String email = getCurrentUser().getUser().getEmail();
return projectCollaboratorRepository.findAllByEmail(email).stream()
.map(ProjectCollaborator::getProject)
.distinct()
.toList();
}
/**
* This method returns a single project by its id.
*
* @return a project
*/
@Operation(summary = "Get project by id")
@PreAuthorize("@ProjectSecurity.hasManagePermissions(#root, #id)")
@GetMapping("/{id}")
public Project getProjectById(@Parameter(name = "id") @PathVariable Long id) {
return projectRepository
.findById(id)
.orElseThrow(() -> new EntityNotFoundException(Project.class, id));
}
/**
* This method updates the name and description of an existing project.
*
* @param projectId the id of the project to update
* @param name the new name of the project
* @param description the new description of the project
* @return the updated project
*/
@Operation(summary = "Update an existing project")
@PreAuthorize("@ProjectSecurity.hasOwnerPermissions(#root, #projectId)")
@PutMapping("")
public Project updateProject(
@Parameter(name = "projectId") @RequestParam Long projectId,
@Parameter(name = "name") @RequestParam String name,
@Parameter(name = "description") @RequestParam String description) {
Project project =
projectRepository
.findById(projectId)
.orElseThrow(() -> new EntityNotFoundException(Project.class, projectId));
project.setName(name);
project.setDescription(description);
return projectRepository.save(project);
}
/**
* This method deletes a project, along with any collaborators on it.
*
* @param projectId the id of the project to delete
* @return a message confirming deletion
*/
@Operation(summary = "Delete a project")
@PreAuthorize("@ProjectSecurity.hasOwnerPermissions(#root, #projectId)")
@DeleteMapping("")
@Transactional
public Object deleteProject(@RequestParam Long projectId) {
Project project =
projectRepository
.findById(projectId)
.orElseThrow(() -> new EntityNotFoundException(Project.class, projectId));
projectCollaboratorRepository.deleteAll(
projectCollaboratorRepository.findByProjectId(projectId));
projectRepository.delete(project);
return genericMessage("Project with id %s deleted".formatted(project.getId()));
}
}