-
Notifications
You must be signed in to change notification settings - Fork 1
Kaumadi #68
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Kaumadi #68
Changes from all commits
8e503e1
408f868
3ceee47
88fec54
6203900
f084cf2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,10 @@ | ||
| package com.testify.Testify_Backend.controller; | ||
|
|
||
| import com.testify.Testify_Backend.responses.GenericAddOrUpdateResponse; | ||
| import com.testify.Testify_Backend.responses.exam_management.CandidateResponse; | ||
| import com.testify.Testify_Backend.responses.exam_management.ExamResponse; | ||
| import com.testify.Testify_Backend.responses.exam_management.OrganizationResponse; | ||
| import com.testify.Testify_Backend.service.ExamManagementService; | ||
| import com.testify.Testify_Backend.responses.exam_management.ExamResponse; | ||
| import com.testify.Testify_Backend.responses.exam_management.OrganizationResponse; | ||
| import com.testify.Testify_Backend.responses.examsetter_management.ModerateExamResponse; | ||
|
|
@@ -20,6 +24,7 @@ | |
| public class ExamSetterController { | ||
| private static final Logger log = LoggerFactory.getLogger(ExamSetterController.class); | ||
| private final ExamSetterService examSetterService; | ||
| private final ExamManagementService examManagementService; | ||
|
|
||
| @GetMapping("/{setterId}/getOrganizations") | ||
| public ResponseEntity<Set<OrganizationResponse>> getOrganizations(@PathVariable("setterId") long setterId) { | ||
|
|
@@ -40,6 +45,17 @@ public ResponseEntity<GenericAddOrUpdateResponse> addSetterToOrganization(@PathV | |
| return ResponseEntity.ok(response); | ||
| } | ||
|
|
||
| @GetMapping("/proctor/{proctorId}/{organizationId}") | ||
| public ResponseEntity<List<ExamResponse>> getExamsForProctor(@PathVariable Long proctorId, @PathVariable Long organizationId) { | ||
| List<ExamResponse> exams = examSetterService.getExamsForProctor(proctorId, organizationId); | ||
| return ResponseEntity.ok(exams); | ||
| } | ||
|
|
||
| @GetMapping("/{examId}/candidates") | ||
| public ResponseEntity<Set<CandidateResponse>> getCandidatesForExam(@PathVariable Long examId) { | ||
| Set<CandidateResponse> candidates = examSetterService.getCandidatesForExam(examId); | ||
| return ResponseEntity.ok(candidates); | ||
| } | ||
|
Comment on lines
+54
to
+58
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Add input validation and error handling. The endpoint needs validation for:
Add validation and error handling: @GetMapping("/{examId}/candidates")
public ResponseEntity<Set<CandidateResponse>> getCandidatesForExam(@PathVariable Long examId) {
+ if (examId == null || examId <= 0) {
+ return ResponseEntity.badRequest().build();
+ }
Set<CandidateResponse> candidates = examSetterService.getCandidatesForExam(examId);
return ResponseEntity.ok(candidates);
}
|
||
| @GetMapping("/{examSetterId}/moderating-exams") | ||
| public ResponseEntity<List<ModerateExamResponse>> getModeratingExams(@PathVariable long examSetterId) { | ||
| List<ModerateExamResponse> responses = examSetterService.getModeratingExams(examSetterId); | ||
|
|
@@ -52,4 +68,10 @@ public ResponseEntity<List<ModerateExamResponse>> getModeratingExams(@PathVariab | |
| return ResponseEntity.ok(responses); | ||
| } | ||
|
|
||
| @PostMapping("/{candidateId}/{examId}/proctorComments") | ||
| public ResponseEntity<String> addComment(@PathVariable Long candidateId, @PathVariable Long examId, @RequestBody String content) { | ||
| examSetterService.addCommentToCandidate(candidateId, examId, content); | ||
| return ResponseEntity.ok("Comment added successfully"); | ||
| } | ||
|
Comment on lines
+71
to
+75
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Enhance POST endpoint with proper request mapping and validation. The endpoint needs:
Apply these improvements: @PostMapping("/{candidateId}/{examId}/proctorComments")
+ @Consumes(MediaType.APPLICATION_JSON_VALUE)
- public ResponseEntity<String> addComment(@PathVariable Long candidateId, @PathVariable Long examId, @RequestBody String content) {
+ public ResponseEntity<String> addComment(
+ @PathVariable Long candidateId,
+ @PathVariable Long examId,
+ @Valid @RequestBody ProctorCommentRequest request
+ ) {
+ if (candidateId == null || candidateId <= 0 || examId == null || examId <= 0) {
+ return ResponseEntity.badRequest().body("Invalid candidate or exam ID");
+ }
+ if (request.getContent() == null || request.getContent().trim().isEmpty()) {
+ return ResponseEntity.badRequest().body("Comment content cannot be empty");
+ }
- examSetterService.addCommentToCandidate(candidateId, examId, content);
+ examSetterService.addCommentToCandidate(candidateId, examId, request.getContent());
return ResponseEntity.ok("Comment added successfully");
}Create a new DTO: @Data
public class ProctorCommentRequest {
@NotBlank(message = "Comment content is required")
private String content;
} |
||
|
|
||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -116,4 +116,7 @@ public class Exam { | |||||||||||||||||||||||||||||||
| @Column(nullable = false) | ||||||||||||||||||||||||||||||||
| private boolean hosted = false; | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| @OneToMany(mappedBy = "exam", cascade = CascadeType.ALL, orphanRemoval = true) | ||||||||||||||||||||||||||||||||
| private List<ProctorComment> proctorComments; | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
|
Comment on lines
+119
to
+121
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Consider initializing the List and managing JSON serialization. While the relationship mapping is correct, consider these improvements:
Apply this diff: @OneToMany(mappedBy = "exam", cascade = CascadeType.ALL, orphanRemoval = true)
+ @JsonIgnore
- private List<ProctorComment> proctorComments;
+ private List<ProctorComment> proctorComments = new ArrayList<>();
+
+ public void addProctorComment(ProctorComment comment) {
+ proctorComments.add(comment);
+ comment.setExam(this);
+ }
+
+ public void removeProctorComment(ProctorComment comment) {
+ proctorComments.remove(comment);
+ comment.setExam(null);
+ }📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| package com.testify.Testify_Backend.model; | ||
|
|
||
| import jakarta.persistence.*; | ||
| import lombok.AllArgsConstructor; | ||
| import lombok.Getter; | ||
| import lombok.NoArgsConstructor; | ||
| import lombok.Setter; | ||
|
|
||
| import java.time.LocalDateTime; | ||
|
|
||
| @Entity | ||
| @AllArgsConstructor | ||
| @NoArgsConstructor | ||
| @Getter | ||
| @Setter | ||
| public class ProctorComment { | ||
| @Id | ||
| @GeneratedValue(strategy = GenerationType.IDENTITY) | ||
| private Long id; | ||
|
|
||
| @ManyToOne | ||
| @JoinColumn(name = "candidate_id", nullable = false) | ||
| private Candidate candidate; | ||
|
|
||
| @ManyToOne | ||
| @JoinColumn(name = "exam_id", nullable = false) | ||
| private Exam exam; | ||
|
|
||
| private String content; | ||
|
|
||
| private LocalDateTime createdAt; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| package com.testify.Testify_Backend.repository; | ||
|
|
||
| import com.testify.Testify_Backend.model.ProctorComment; | ||
| import org.springframework.data.jpa.repository.JpaRepository; | ||
|
|
||
| public interface ProctorCommentRepository extends JpaRepository<ProctorComment, Long> { | ||
|
|
||
| } |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,5 +1,12 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| package com.testify.Testify_Backend.service; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import com.testify.Testify_Backend.model.*; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import com.testify.Testify_Backend.repository.*; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import com.testify.Testify_Backend.responses.GenericAddOrUpdateResponse; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import com.testify.Testify_Backend.responses.exam_management.CandidateResponse; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import com.testify.Testify_Backend.responses.exam_management.ExamResponse; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import com.testify.Testify_Backend.responses.exam_management.OrganizationResponse; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import jakarta.transaction.Transactional; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import com.testify.Testify_Backend.model.ExamSetter; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import com.testify.Testify_Backend.model.ExamSetterInvitation; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import com.testify.Testify_Backend.model.Organization; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -17,6 +24,8 @@ | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.springframework.http.ResponseEntity; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.springframework.stereotype.Service; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import java.time.LocalDateTime; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import java.util.*; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import java.util.HashSet; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import java.util.List; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import java.util.Optional; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -30,6 +39,8 @@ public class ExamSetterServiceImpl implements ExamSetterService { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private final ExamSetterInvitationRepository examSetterInvitationRepository; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private final OrganizationRepository organizationRepository; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private final ExamRepository examRepository; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private final CandidateRepository candidateRepository; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private final ProctorCommentRepository proctorCommentRepository; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @Autowired | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private ModelMapper modelMapper; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -77,6 +88,28 @@ public GenericAddOrUpdateResponse addSetterToOrganization(String token) { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return response; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @Override | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @Transactional | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public List<ExamResponse> getExamsForProctor(Long proctorId, Long organizationId) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| List<Exam> exams = examRepository.findByProctorIdAndOrganizationId(proctorId, organizationId); // Ensure repository method returns a List | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| List<ExamResponse> examResponses = new ArrayList<>(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for (Exam exam : exams) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| examResponses.add(modelMapper.map(exam, ExamResponse.class)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return examResponses; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @Override | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public Set<CandidateResponse> getCandidatesForExam(Long examId) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Set<Candidate> candidates = candidateRepository.findByExamId(examId); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Set<CandidateResponse> candidateResponses = new HashSet<>(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for (Candidate candidate : candidates) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| candidateResponses.add(modelMapper.map(candidate, CandidateResponse.class)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return candidateResponses; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public List<ModerateExamResponse> getModeratingExams(long examSetterId) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return examRepository.findByModeratorId(examSetterId).stream() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .map(exam -> new ModerateExamResponse( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -87,4 +120,19 @@ public List<ModerateExamResponse> getModeratingExams(long examSetterId) { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| )) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .collect(Collectors.toList()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @Override | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public void addCommentToCandidate(Long candidateId, Long examId, String content) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Candidate candidate = candidateRepository.findById(candidateId) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .orElseThrow(() -> new RuntimeException("Candidate not found")); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Exam exam = examRepository.findById(examId).orElseThrow(() -> new RuntimeException("Exam not found")); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ProctorComment comment = new ProctorComment(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| comment.setCandidate(candidate); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| comment.setExam(exam); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| comment.setContent(content); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| comment.setCreatedAt(LocalDateTime.now()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| proctorCommentRepository.save(comment); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+125
to
+137
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Enhance exception handling and transaction management
Apply this diff: +@Transactional
public void addCommentToCandidate(Long candidateId, Long examId, String content) {
Candidate candidate = candidateRepository.findById(candidateId)
- .orElseThrow(() -> new RuntimeException("Candidate not found"));
+ .orElseThrow(() -> new EntityNotFoundException("Candidate not found with id: " + candidateId));
Exam exam = examRepository.findById(examId)
- .orElseThrow(() -> new RuntimeException("Exam not found"));
+ .orElseThrow(() -> new EntityNotFoundException("Exam not found with id: " + examId));
ProctorComment comment = new ProctorComment();
comment.setCandidate(candidate);
comment.setExam(exam);
comment.setContent(content);
comment.setCreatedAt(LocalDateTime.now());
proctorCommentRepository.save(comment);
}Ensure to import 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Add input validation and error handling.
The endpoint needs validation for:
Add validation and error handling:
@GetMapping("/proctor/{proctorId}/{organizationId}") public ResponseEntity<List<ExamResponse>> getExamsForProctor(@PathVariable Long proctorId, @PathVariable Long organizationId) { + if (proctorId == null || proctorId <= 0 || organizationId == null || organizationId <= 0) { + return ResponseEntity.badRequest().build(); + } List<ExamResponse> exams = examSetterService.getExamsForProctor(proctorId, organizationId); return ResponseEntity.ok(exams); }