Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@
<name>Testify-Backend</name>
<description>Spring Boot Backend for Testify</description>
<properties>
<java.version>21</java.version>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<java.version>22</java.version>
<maven.compiler.source>22</maven.compiler.source>
<maven.compiler.target>22</maven.compiler.target>
</properties>
<dependencies>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import com.testify.Testify_Backend.service.ExamManagementService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

Expand Down Expand Up @@ -169,9 +170,7 @@ public ResponseEntity<String> submitExam(@PathVariable Long sessionId) {
}

@PostMapping("/{examId}/proctors")
public ResponseEntity<GenericAddOrUpdateResponse> addOrUpdateProctors(
@PathVariable Long examId,
@RequestBody List<String> emails) {
public ResponseEntity<GenericAddOrUpdateResponse> addOrUpdateProctors(@PathVariable Long examId, @RequestBody List<String> emails) {
log.info("Adding proctors to examId: " + examId);
log.info("Emails: " + emails);
return examManagementService.addProctorsToExam(examId, emails);
Expand Down Expand Up @@ -209,4 +208,87 @@ public ResponseEntity<List<CandidateConflictExamResponse>> getCandidateConflicti
return ResponseEntity.ok(response);
}

@PutMapping("/{examId}/real-time-monitoring")
public ResponseEntity<GenericResponse> updateRealTimeMonitoring(
@PathVariable Long examId,
@RequestBody RealTimeMonitoringRequest dto) {
try {
// Delegate to the service and return the response directly
GenericResponse response = examManagementService.updateRealTimeMonitoring(examId, dto);
return ResponseEntity.ok(response);
} catch (Exception ex) {
return ResponseEntity.status(500).body(new GenericResponse("false", "Error: " + ex.getMessage()));
}
}

@GetMapping("/{examId}/real-time-monitoring")
public ResponseEntity<RealTimeMonitoringResponse> getRealTimeMonitoringStatus(@PathVariable Long examId) {
try {
RealTimeMonitoringResponse response = examManagementService.getRealTimeMonitoringStatus(examId);
return ResponseEntity.ok(response);
} catch (Exception ex) {
return ResponseEntity.status(500).body(null);
}
}

@PutMapping("/{examId}/browser-lockdown")
public ResponseEntity<GenericResponse> updateBrowserLockdown(
@PathVariable Long examId,
@RequestParam boolean browserLockdown) {
try {
GenericResponse response = examManagementService.updateBrowserLockdown(examId, browserLockdown);
return ResponseEntity.ok(response);
} catch (Exception ex) {
return ResponseEntity.status(500).body(new GenericResponse("false", "Error: " + ex.getMessage()));
}
}

@GetMapping("/{examId}/browser-lockdown")
public ResponseEntity<BrowserLockdownResponse> getBrowserLockdown(@PathVariable Long examId) {
try {
boolean browserLockdown = examManagementService.getBrowserLockdownStatus(examId);
return ResponseEntity.ok(new BrowserLockdownResponse(browserLockdown));
} catch (Exception ex) {
return ResponseEntity.status(500).body(null); // Handle errors gracefully
}
}

@PutMapping("/{examId}/hosted")
public ResponseEntity<GenericResponse> updateHosted(@PathVariable Long examId, @RequestParam boolean hosted) {
try {
GenericResponse response = examManagementService.updateHostedStatus(examId, hosted);
return ResponseEntity.ok(response);
} catch (Exception ex) {
return ResponseEntity.status(500).body(new GenericResponse("false", "Error: " + ex.getMessage()));
}
}

@GetMapping("/{examId}/hosted")
public ResponseEntity<HostedResponse> getHosted(@PathVariable Long examId) {
try {
boolean hosted = examManagementService.getHostedStatus(examId);
log.info(String.valueOf(hosted));
return ResponseEntity.ok(new HostedResponse(hosted));
} catch (Exception ex) {
return ResponseEntity.status(500).body(null);
}
}

@PostMapping("/{examId}/set-moderator")
public ResponseEntity<String> setModerator(@PathVariable Long examId, @RequestBody ModeratorRequest moderatorRequest) {
log.info("Setting moderator for examId: " + examId);
try {
examManagementService.assignModerator(examId, moderatorRequest.getModeratorEmail());
return ResponseEntity.ok("Moderator assigned successfully.");
} catch (RuntimeException ex) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(ex.getMessage());
}
}

@GetMapping("/{examId}/moderator")
public ResponseEntity<ModeratorResponse> getModerator(@PathVariable Long examId) {
ModeratorResponse moderatorResponse = examManagementService.getModeratorDetails(examId);
return ResponseEntity.ok(moderatorResponse); // Returns null in the body if no moderator exists
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,10 @@ public ResponseEntity<GenericAddOrUpdateResponse> addSetterToOrganization(@PathV
GenericAddOrUpdateResponse response = examSetterService.addSetterToOrganization(token);
return ResponseEntity.ok(response);
}

@PutMapping("/{setterId}/{organizationId}/deleteSetter")
public ResponseEntity<GenericAddOrUpdateResponse> deleteSetter(@PathVariable("setterId") String setterId, @PathVariable("organizationId") String organizationId) {
GenericAddOrUpdateResponse response = examSetterService.deleteSetter(setterId, organizationId);
return ResponseEntity.ok(response);
}
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
package com.testify.Testify_Backend.controller;

import com.testify.Testify_Backend.model.CandidateExamSession;
import com.testify.Testify_Backend.model.ExamCandidateGrade;
import com.testify.Testify_Backend.model.Grade;
import com.testify.Testify_Backend.requests.exam_management.ExamCandidateGradeRequest;
import com.testify.Testify_Backend.responses.EssayDetailsResponse;
import com.testify.Testify_Backend.responses.McqDetailsResponse;
import com.testify.Testify_Backend.responses.exam_management.ExamCandidateGradeResponse;
import com.testify.Testify_Backend.service.GradingService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -46,5 +46,16 @@ public ResponseEntity<List<Map<String, String>>> getResultsBySessionId(
return ResponseEntity.ok(results);
}

@PostMapping("/setExamCandidateGrade")
public ResponseEntity<String> setExamCandidateGrade(@RequestBody ExamCandidateGradeRequest examCandidateGradeRequest) {
String response = gradingService.setExamCandidateGrade(examCandidateGradeRequest);
return ResponseEntity.ok(response);
}

@GetMapping("/getExamCandidateGrade")
public ResponseEntity<List<ExamCandidateGradeResponse>> getExamCandidateGrade() {
List<ExamCandidateGradeResponse> response = gradingService.getExamCandidateGrade();
return ResponseEntity.ok(response);
}

}
14 changes: 14 additions & 0 deletions src/main/java/com/testify/Testify_Backend/model/Exam.java
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ public class Exam {
joinColumns = @JoinColumn(name = "exam_id"),
inverseJoinColumns = @JoinColumn(name = "candidate_id")
)

private Set<Candidate> candidates;

@OneToMany(mappedBy = "exam", cascade = CascadeType.ALL)
Expand All @@ -104,4 +105,17 @@ public class Exam {
@JsonIgnore
private List<Grade> gradings;

@Column(nullable = false)
private boolean realTimeMonitoring = false;

@Column
private String zoomLink;

@Column(nullable = false)
private boolean browserLockdown = false;

@Column(nullable = false)
private boolean hosted = false;


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package com.testify.Testify_Backend.model;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import lombok.*;
import org.springframework.data.annotation.Id;

@Entity
@Data
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class ExamCandidateGrade {

@Setter
@jakarta.persistence.Id
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY) // Auto-generate the ID
@Column
private Long id;

@Column(nullable = false)
private String examID;

@Column(nullable = false)
private String candidateID;

private String status;

private String grade;

private String score;

public Long getId() {
return id;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,6 @@ public class ExamSetter extends User{

@OneToMany(mappedBy = "moderator")
private Set<Exam> moderatedExams;


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.testify.Testify_Backend.model;

import jakarta.annotation.Nullable;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import lombok.*;
import org.springframework.data.annotation.Id;

@Entity
@Data
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class ExamSetterOrganization {
@Setter
@jakarta.persistence.Id
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY) // Auto-generate the ID
@Column
private Long id;

@Column(nullable = false)
private String organizationID;

@Column(nullable = false)
private String examSetterID;

private boolean isDeleted = false;

public Long getId() {
return id;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.testify.Testify_Backend.repository;

import com.testify.Testify_Backend.model.ExamCandidateGrade;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
public interface ExamCandidateGradeRepository extends JpaRepository<ExamCandidateGrade, String> {

// write a query to get the exam candidate grade details along with exam name and candidate name
@Query("SELECT ecg FROM ExamCandidateGrade ecg")
List<ExamCandidateGrade> getExamCandidateGradeDetails();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.testify.Testify_Backend.repository;

import com.testify.Testify_Backend.model.ExamSetterOrganization;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
public interface ExamSetterOrganizationRepository extends JpaRepository<ExamSetterOrganization, String> {
// write a method to update is deleted to true by organizationID and examSetterID
// write a method to find by organizationID and examSetterID
ExamSetterOrganization findByOrganizationIDAndExamSetterID(String organizationID, String examSetterID);
List<ExamSetterOrganization> findByOrganizationID(String organizationID);
ExamSetterOrganization findByExamSetterID(String examSetterID);

@Query("SELECT e.examSetterID FROM ExamSetterOrganization e WHERE e.organizationID = :organizationId AND e.isDeleted = false")
List<String> findActiveExamSetterIDs(@Param("organizationId") String organizationId);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.testify.Testify_Backend.requests.exam_management;

import lombok.*;

@Data
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
public class ExamCandidateGradeRequest
{
private String examID;
private String candidateID;
private String status;
private String grade;
private String score;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.testify.Testify_Backend.requests.exam_management;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class ModeratorRequest {
private String moderatorEmail;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.testify.Testify_Backend.requests.exam_management;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class RealTimeMonitoringRequest {
private boolean realTimeMonitoring;
private String zoomLink;
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
@AllArgsConstructor
@Data
public class GenericResponse {
private String code;
private String success;
private String message;
private Object content;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.testify.Testify_Backend.responses.exam_management;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class BrowserLockdownResponse {
private boolean browserLockdown;
}
Loading