CourseOptionsController.java
package edu.ucsb.cs.scaffold.controller;
import edu.ucsb.cs.scaffold.entity.Course;
import edu.ucsb.cs.scaffold.entity.CourseOption;
import edu.ucsb.cs.scaffold.enums.CourseOptions;
import edu.ucsb.cs.scaffold.errors.EntityNotFoundException;
import edu.ucsb.cs.scaffold.repository.CourseOptionRepository;
import edu.ucsb.cs.scaffold.repository.CourseRepository;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import java.util.LinkedHashMap;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@Tag(name = "CourseOptions")
@RequestMapping("/api/course/options")
@RestController
public class CourseOptionsController extends ApiController {
@Autowired private CourseOptionRepository courseOptionRepository;
@Autowired private CourseRepository courseRepository;
@Operation(summary = "Get toggleable options for a course")
@PreAuthorize("@CourseSecurity.hasInstructorPermissions(#root, #courseId)")
@GetMapping("")
public Map<String, Boolean> getCourseOptions(
@Parameter(name = "courseId") @RequestParam Long courseId,
@Parameter(name = "option") @RequestParam(required = false) String option) {
ensureCourseExists(courseId);
if (option != null && !option.isBlank()) {
String normalizedOption = normalizeAndValidateOption(option);
boolean enabled =
courseOptionRepository
.findByCourseIdAndOption(courseId, normalizedOption)
.map(CourseOption::getEnabled)
.orElse(false);
return Map.of(normalizedOption, enabled);
}
LinkedHashMap<String, Boolean> options = new LinkedHashMap<>();
for (CourseOptions courseOption : CourseOptions.values()) {
options.put(courseOption.name(), false);
}
for (CourseOption courseOption : courseOptionRepository.findByCourseId(courseId)) {
if (options.containsKey(courseOption.getOption())) {
options.put(courseOption.getOption(), courseOption.getEnabled());
}
}
return options;
}
@Operation(summary = "Set toggleable option for a course")
@PreAuthorize("@CourseSecurity.hasInstructorPermissions(#root, #courseId)")
@PostMapping("")
public Map<String, Boolean> setCourseOption(
@Parameter(name = "courseId") @RequestParam Long courseId,
@Parameter(name = "option") @RequestParam String option,
@Parameter(name = "enabled") @RequestParam Boolean enabled) {
ensureCourseExists(courseId);
String normalizedOption = normalizeAndValidateOption(option);
CourseOption courseOption =
courseOptionRepository
.findByCourseIdAndOption(courseId, normalizedOption)
.orElse(CourseOption.builder().courseId(courseId).option(normalizedOption).build());
courseOption.setEnabled(enabled);
courseOptionRepository.save(courseOption);
return Map.of(normalizedOption, enabled);
}
private void ensureCourseExists(Long courseId) {
courseRepository
.findById(courseId)
.orElseThrow(() -> new EntityNotFoundException(Course.class, courseId));
}
private String normalizeAndValidateOption(String option) {
String normalizedOption = option.strip().toUpperCase();
try {
CourseOptions.valueOf(normalizedOption);
return normalizedOption;
} catch (IllegalArgumentException e) {
throw new IllegalArgumentException("Invalid course option: " + option);
}
}
}