Files
magistr/backend/src/main/java/com/magistr/app/controller/TimeSlotAdminController.java

219 lines
9.6 KiB
Java

package com.magistr.app.controller;
import com.magistr.app.config.auth.RequireRoles;
import com.magistr.app.dto.TimeSlotDateAssignmentDto;
import com.magistr.app.dto.TimeSlotDto;
import com.magistr.app.dto.TimeSlotScopeDto;
import com.magistr.app.model.TimeSlot;
import com.magistr.app.model.TimeSlotDateAssignment;
import com.magistr.app.model.TimeSlotScope;
import com.magistr.app.model.Role;
import com.magistr.app.repository.TimeSlotDateAssignmentRepository;
import com.magistr.app.repository.TimeSlotRepository;
import com.magistr.app.repository.TimeSlotScopeRepository;
import com.magistr.app.service.TimeSlotService;
import com.magistr.app.service.EffectiveTimeSlotService;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
@RestController
@RequestMapping("/api/admin/time-slots")
@RequireRoles({Role.ADMIN, Role.EDUCATION_OFFICE})
public class TimeSlotAdminController {
private static final String APPLY_MODE_DEFAULT = "DEFAULT";
private static final String APPLY_MODE_WEEKDAY = "WEEKDAY";
private static final String APPLY_MODE_MANUAL = "MANUAL";
private final TimeSlotRepository timeSlotRepository;
private final TimeSlotScopeRepository timeSlotScopeRepository;
private final TimeSlotDateAssignmentRepository dateAssignmentRepository;
private final TimeSlotService timeSlotService;
private final EffectiveTimeSlotService effectiveTimeSlotService;
public TimeSlotAdminController(TimeSlotRepository timeSlotRepository,
TimeSlotScopeRepository timeSlotScopeRepository,
TimeSlotDateAssignmentRepository dateAssignmentRepository,
TimeSlotService timeSlotService,
EffectiveTimeSlotService effectiveTimeSlotService) {
this.timeSlotRepository = timeSlotRepository;
this.timeSlotScopeRepository = timeSlotScopeRepository;
this.dateAssignmentRepository = dateAssignmentRepository;
this.timeSlotService = timeSlotService;
this.effectiveTimeSlotService = effectiveTimeSlotService;
}
@GetMapping
public List<TimeSlotDto> getAll() {
return timeSlotRepository.findAllByOrderByTimeSlotScopeDisplayOrderAscOrderNumberAscStartTimeAsc().stream()
.map(this::toDto)
.toList();
}
@GetMapping("/effective")
public ResponseEntity<?> getEffective(@RequestParam LocalDate date) {
return ResponseEntity.ok(effectiveTimeSlotService.findEffective(date).stream().map(this::toDto).toList());
}
@GetMapping("/scopes")
public List<TimeSlotScopeDto> getScopes() {
return timeSlotScopeRepository.findAllByOrderByDisplayOrderAscNameAsc().stream()
.map(this::toScopeDto)
.toList();
}
@PostMapping("/scopes")
public ResponseEntity<?> createScope(@RequestBody TimeSlotScopeDto request) {
if (request.name() == null || request.name().isBlank()) {
return ResponseEntity.badRequest().body(Map.of("message", "Название сетки обязательно"));
}
TimeSlotScope scope = new TimeSlotScope();
scope.setCode("manual_" + UUID.randomUUID().toString().replace("-", ""));
scope.setName(request.name().trim());
scope.setApplyMode(APPLY_MODE_MANUAL);
scope.setDayOfWeek(null);
scope.setSystemScope(false);
scope.setDisplayOrder(nextManualDisplayOrder());
return ResponseEntity.ok(toScopeDto(timeSlotScopeRepository.save(scope)));
}
@PutMapping("/scopes/{id}")
public ResponseEntity<?> updateScope(@PathVariable Long id, @RequestBody TimeSlotScopeDto request) {
TimeSlotScope scope = timeSlotScopeRepository.findById(id).orElse(null);
if (scope == null) {
return ResponseEntity.notFound().build();
}
if (Boolean.TRUE.equals(scope.getSystemScope())) {
return ResponseEntity.badRequest().body(Map.of("message", "Системную сетку нельзя изменять"));
}
if (request.name() == null || request.name().isBlank()) {
return ResponseEntity.badRequest().body(Map.of("message", "Название сетки обязательно"));
}
scope.setName(request.name().trim());
return ResponseEntity.ok(toScopeDto(timeSlotScopeRepository.save(scope)));
}
@DeleteMapping("/scopes/{id}")
public ResponseEntity<?> deleteScope(@PathVariable Long id) {
TimeSlotScope scope = timeSlotScopeRepository.findById(id).orElse(null);
if (scope == null) {
return ResponseEntity.notFound().build();
}
if (Boolean.TRUE.equals(scope.getSystemScope())) {
return ResponseEntity.badRequest().body(Map.of("message", "Системную сетку нельзя удалить"));
}
timeSlotScopeRepository.delete(scope);
return ResponseEntity.ok(Map.of("message", "Сетка времени удалена"));
}
@GetMapping("/date-assignments")
public List<TimeSlotDateAssignmentDto> getDateAssignments(@RequestParam(required = false) LocalDate startDate,
@RequestParam(required = false) LocalDate endDate) {
List<TimeSlotDateAssignment> assignments = startDate != null && endDate != null
? dateAssignmentRepository.findByDateBetweenOrderByDateAsc(startDate, endDate)
: dateAssignmentRepository.findAllByOrderByDateAsc();
return assignments.stream().map(this::toAssignmentDto).toList();
}
@PostMapping("/date-assignments")
public ResponseEntity<?> saveDateAssignment(@RequestBody TimeSlotDateAssignmentDto request) {
if (request.date() == null) {
return ResponseEntity.badRequest().body(Map.of("message", "Дата обязательна"));
}
if (request.scopeId() == null) {
return ResponseEntity.badRequest().body(Map.of("message", "Сетка времени обязательна"));
}
TimeSlotScope scope = timeSlotScopeRepository.findById(request.scopeId()).orElse(null);
if (scope == null) {
return ResponseEntity.badRequest().body(Map.of("message", "Сетка времени не найдена"));
}
if (!APPLY_MODE_MANUAL.equals(scope.getApplyMode())) {
return ResponseEntity.badRequest().body(Map.of("message", "Вручную можно применять только пользовательские сетки"));
}
TimeSlotDateAssignment assignment = dateAssignmentRepository.findByDate(request.date())
.orElseGet(TimeSlotDateAssignment::new);
assignment.setDate(request.date());
assignment.setTimeSlotScope(scope);
return ResponseEntity.ok(toAssignmentDto(dateAssignmentRepository.save(assignment)));
}
@DeleteMapping("/date-assignments/{id}")
public ResponseEntity<?> deleteDateAssignment(@PathVariable Long id) {
if (!dateAssignmentRepository.existsById(id)) {
return ResponseEntity.notFound().build();
}
dateAssignmentRepository.deleteById(id);
return ResponseEntity.ok(Map.of("message", "Ручное назначение удалено"));
}
@PostMapping
public ResponseEntity<?> create(@RequestBody TimeSlotDto request) {
return ResponseEntity.ok(toDto(timeSlotService.create(request)));
}
@PutMapping("/{id}")
public ResponseEntity<?> update(@PathVariable Long id, @RequestBody TimeSlotDto request) {
return ResponseEntity.ok(toDto(timeSlotService.update(id, request)));
}
@DeleteMapping("/{id}")
public ResponseEntity<?> delete(@PathVariable Long id) {
timeSlotService.delete(id);
return ResponseEntity.ok(Map.of("message", "Временной слот удалён"));
}
private int nextManualDisplayOrder() {
return timeSlotScopeRepository.findAllByOrderByDisplayOrderAscNameAsc().stream()
.map(TimeSlotScope::getDisplayOrder)
.filter(value -> value != null)
.max(Integer::compareTo)
.orElse(100) + 10;
}
private TimeSlotDto toDto(TimeSlot timeSlot) {
TimeSlotScope scope = timeSlot.getTimeSlotScope();
return new TimeSlotDto(
timeSlot.getId(),
timeSlot.getOrderNumber(),
scope == null ? null : scope.getId(),
scope == null ? null : scope.getName(),
scope == null ? null : scope.getApplyMode(),
scope == null ? null : scope.getDayOfWeek(),
timeSlot.getStartTime(),
timeSlot.getEndTime(),
timeSlot.getDurationMinutes()
);
}
private TimeSlotScopeDto toScopeDto(TimeSlotScope scope) {
return new TimeSlotScopeDto(
scope.getId(),
scope.getCode(),
scope.getName(),
scope.getApplyMode(),
scope.getDayOfWeek(),
scope.getSystemScope(),
scope.getDisplayOrder()
);
}
private TimeSlotDateAssignmentDto toAssignmentDto(TimeSlotDateAssignment assignment) {
TimeSlotScope scope = assignment.getTimeSlotScope();
return new TimeSlotDateAssignmentDto(
assignment.getId(),
assignment.getDate(),
scope.getId(),
scope.getName()
);
}
}