| 1 | package edu.ucsb.cs.scaffold.controller; | |
| 2 | ||
| 3 | import edu.ucsb.cs.scaffold.entity.PlRepo; | |
| 4 | import edu.ucsb.cs.scaffold.errors.EntityNotFoundException; | |
| 5 | import edu.ucsb.cs.scaffold.repository.PlAssessmentQuestionRepository; | |
| 6 | import edu.ucsb.cs.scaffold.repository.PlAssessmentRepository; | |
| 7 | import edu.ucsb.cs.scaffold.repository.PlInstanceRepository; | |
| 8 | import edu.ucsb.cs.scaffold.repository.PlQuestionRepository; | |
| 9 | import edu.ucsb.cs.scaffold.repository.PlRepoRepository; | |
| 10 | import edu.ucsb.cs.scaffold.repository.PlScaffoldAssessmentRepository; | |
| 11 | import io.swagger.v3.oas.annotations.Operation; | |
| 12 | import io.swagger.v3.oas.annotations.Parameter; | |
| 13 | import io.swagger.v3.oas.annotations.tags.Tag; | |
| 14 | import java.util.regex.Pattern; | |
| 15 | import lombok.extern.slf4j.Slf4j; | |
| 16 | import org.springframework.beans.factory.annotation.Autowired; | |
| 17 | import org.springframework.security.access.prepost.PreAuthorize; | |
| 18 | import org.springframework.transaction.annotation.Transactional; | |
| 19 | import org.springframework.web.bind.annotation.DeleteMapping; | |
| 20 | import org.springframework.web.bind.annotation.GetMapping; | |
| 21 | import org.springframework.web.bind.annotation.PostMapping; | |
| 22 | import org.springframework.web.bind.annotation.RequestMapping; | |
| 23 | import org.springframework.web.bind.annotation.RequestParam; | |
| 24 | import org.springframework.web.bind.annotation.RestController; | |
| 25 | ||
| 26 | @Tag(name = "PlRepo") | |
| 27 | @RequestMapping("/api/plrepo") | |
| 28 | @RestController | |
| 29 | @Slf4j | |
| 30 | public class PLRepoController extends ApiController { | |
| 31 | ||
| 32 | // A GitHub owner/organization name: alphanumeric characters or hyphens, cannot begin or end | |
| 33 | // with a hyphen. | |
| 34 | private static final String OWNER_PATTERN = "[A-Za-z0-9](?:[A-Za-z0-9-]{0,37}[A-Za-z0-9])?"; | |
| 35 | ||
| 36 | // A GitHub repository name: alphanumeric characters, hyphens, underscores, or periods. | |
| 37 | private static final String REPO_PATTERN = "[A-Za-z0-9._-]{1,100}"; | |
| 38 | ||
| 39 | private static final Pattern REPO_NAME_PATTERN = | |
| 40 | Pattern.compile("^" + OWNER_PATTERN + "/" + REPO_PATTERN + "$"); | |
| 41 | ||
| 42 | @Autowired private PlRepoRepository plRepoRepository; | |
| 43 | ||
| 44 | @Autowired private PlInstanceRepository plInstanceRepository; | |
| 45 | ||
| 46 | @Autowired private PlQuestionRepository plQuestionRepository; | |
| 47 | ||
| 48 | @Autowired private PlScaffoldAssessmentRepository plScaffoldAssessmentRepository; | |
| 49 | ||
| 50 | @Autowired private PlAssessmentRepository plAssessmentRepository; | |
| 51 | ||
| 52 | @Autowired private PlAssessmentQuestionRepository plAssessmentQuestionRepository; | |
| 53 | ||
| 54 | @Operation(summary = "List all PlRepos") | |
| 55 | @PreAuthorize("hasRole('ROLE_ADMIN') || hasRole('ROLE_INSTRUCTOR')") | |
| 56 | @GetMapping("") | |
| 57 | public Iterable<PlRepo> allPlRepos() { | |
| 58 |
1
1. allPlRepos : replaced return value with Collections.emptyList for edu/ucsb/cs/scaffold/controller/PLRepoController::allPlRepos → KILLED |
return plRepoRepository.findAll(); |
| 59 | } | |
| 60 | ||
| 61 | @Operation(summary = "Create a new PlRepo") | |
| 62 | @PreAuthorize("hasRole('ROLE_ADMIN')") | |
| 63 | @PostMapping("") | |
| 64 | public PlRepo postPlRepo(@Parameter(name = "repoName") @RequestParam String repoName) { | |
| 65 | String trimmedRepoName = repoName.strip(); | |
| 66 |
1
1. postPlRepo : removed call to edu/ucsb/cs/scaffold/controller/PLRepoController::validateRepoName → KILLED |
validateRepoName(trimmedRepoName); |
| 67 | ||
| 68 |
1
1. postPlRepo : negated conditional → KILLED |
if (plRepoRepository.existsByRepoName(trimmedRepoName)) { |
| 69 | throw new IllegalArgumentException( | |
| 70 | "PlRepo with repoName %s already exists".formatted(trimmedRepoName)); | |
| 71 | } | |
| 72 | ||
| 73 | PlRepo plRepo = PlRepo.builder().repoName(trimmedRepoName).build(); | |
| 74 |
1
1. postPlRepo : replaced return value with null for edu/ucsb/cs/scaffold/controller/PLRepoController::postPlRepo → KILLED |
return plRepoRepository.save(plRepo); |
| 75 | } | |
| 76 | ||
| 77 | @Operation( | |
| 78 | summary = | |
| 79 | "Delete a PlRepo, cascading the delete to its PlInstances, PlQuestions, " | |
| 80 | + "PlScaffoldAssessments, and PlAssessments") | |
| 81 | @PreAuthorize("hasRole('ROLE_ADMIN')") | |
| 82 | @DeleteMapping("") | |
| 83 | @Transactional | |
| 84 | public Object deletePlRepo(@Parameter(name = "id") @RequestParam Long id) { | |
| 85 | PlRepo plRepo = | |
| 86 | plRepoRepository | |
| 87 | .findById(id) | |
| 88 |
1
1. lambda$deletePlRepo$0 : replaced return value with null for edu/ucsb/cs/scaffold/controller/PLRepoController::lambda$deletePlRepo$0 → KILLED |
.orElseThrow(() -> new EntityNotFoundException(PlRepo.class, id)); |
| 89 | ||
| 90 |
1
1. deletePlRepo : removed call to edu/ucsb/cs/scaffold/repository/PlAssessmentQuestionRepository::deleteByPlRepoId → KILLED |
plAssessmentQuestionRepository.deleteByPlRepoId(id); |
| 91 |
1
1. deletePlRepo : removed call to edu/ucsb/cs/scaffold/repository/PlScaffoldAssessmentRepository::deleteByPlRepoId → KILLED |
plScaffoldAssessmentRepository.deleteByPlRepoId(id); |
| 92 |
1
1. deletePlRepo : removed call to edu/ucsb/cs/scaffold/repository/PlAssessmentRepository::deleteByPlRepoId → KILLED |
plAssessmentRepository.deleteByPlRepoId(id); |
| 93 |
1
1. deletePlRepo : removed call to edu/ucsb/cs/scaffold/repository/PlInstanceRepository::deleteByPlRepoId → KILLED |
plInstanceRepository.deleteByPlRepoId(id); |
| 94 |
1
1. deletePlRepo : removed call to edu/ucsb/cs/scaffold/repository/PlQuestionRepository::deleteByPlRepoId → KILLED |
plQuestionRepository.deleteByPlRepoId(id); |
| 95 |
1
1. deletePlRepo : removed call to edu/ucsb/cs/scaffold/repository/PlRepoRepository::delete → KILLED |
plRepoRepository.delete(plRepo); |
| 96 | ||
| 97 |
1
1. deletePlRepo : replaced return value with null for edu/ucsb/cs/scaffold/controller/PLRepoController::deletePlRepo → KILLED |
return genericMessage("PlRepo with id %s deleted".formatted(id)); |
| 98 | } | |
| 99 | ||
| 100 | private void validateRepoName(String repoName) { | |
| 101 |
1
1. validateRepoName : negated conditional → KILLED |
if (repoName.isBlank()) { |
| 102 | throw new IllegalArgumentException("repoName is required"); | |
| 103 | } | |
| 104 |
1
1. validateRepoName : negated conditional → KILLED |
if (!REPO_NAME_PATTERN.matcher(repoName).matches()) { |
| 105 | throw new IllegalArgumentException( | |
| 106 | "repoName must be in the format owner/repo, e.g. PrairieLearn/pl-ucsb-cmpsc5b"); | |
| 107 | } | |
| 108 | } | |
| 109 | } | |
Mutations | ||
| 58 |
1.1 |
|
| 66 |
1.1 |
|
| 68 |
1.1 |
|
| 74 |
1.1 |
|
| 88 |
1.1 |
|
| 90 |
1.1 |
|
| 91 |
1.1 |
|
| 92 |
1.1 |
|
| 93 |
1.1 |
|
| 94 |
1.1 |
|
| 95 |
1.1 |
|
| 97 |
1.1 |
|
| 101 |
1.1 |
|
| 104 |
1.1 |