diff --git a/src/main/java/org/example/team6backend/config/SecurityConfig.java b/src/main/java/org/example/team6backend/config/SecurityConfig.java index ade9000..26b96fa 100644 --- a/src/main/java/org/example/team6backend/config/SecurityConfig.java +++ b/src/main/java/org/example/team6backend/config/SecurityConfig.java @@ -20,17 +20,18 @@ public class SecurityConfig { public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http.authorizeHttpRequests( auth -> auth.requestMatchers("/", "/index", "/demo", "/error", "/login/**", "/oauth2/**", "/dev/**") - .permitAll().requestMatchers("/dashboard", "/profile").authenticated() - .requestMatchers("/incidents", "/api/incidents/**").hasAnyRole("RESIDENT", "HANDLER", "ADMIN") - .requestMatchers("/admin", "/api/admin/**").hasRole("ADMIN") - .requestMatchers("/swagger-ui.html", "/swagger-ui/**", "/v3/api-docs/**").hasRole("ADMIN") - .anyRequest().authenticated()) + .permitAll().requestMatchers("/dashboard.html", "/profile.html", "/viewincident.html") + .authenticated().requestMatchers("/incidents.html/**", "/api/incidents/**") + .hasAnyRole("RESIDENT", "HANDLER", "ADMIN").requestMatchers("/admin.html", "/api/admin/**") + .hasRole("ADMIN").requestMatchers("/swagger-ui.html", "/swagger-ui/**", "/v3/api-docs/**") + .hasRole("ADMIN").anyRequest().authenticated()) .oauth2Login( oauth2 -> oauth2.userInfoEndpoint(userInfo -> userInfo.userService(customOAuth2UserService)) - .defaultSuccessUrl("/dashboard", true)) + .defaultSuccessUrl("/dashboard.html", true)) .logout(logout -> logout.logoutSuccessUrl("/").invalidateHttpSession(true).clearAuthentication(true) .deleteCookies("JSESSIONID")) - .csrf(csrf -> csrf.ignoringRequestMatchers("/api/admin/**", "/api/incidents/**", "/dev/**")); + .csrf(csrf -> csrf.ignoringRequestMatchers("/api/admin/**", "/api/incidents/**", "/api/documents/**", + "/dev/**")); return http.build(); } diff --git a/src/main/java/org/example/team6backend/document/controller/DocumentController.java b/src/main/java/org/example/team6backend/document/controller/DocumentController.java index b79a709..4fd8fc9 100644 --- a/src/main/java/org/example/team6backend/document/controller/DocumentController.java +++ b/src/main/java/org/example/team6backend/document/controller/DocumentController.java @@ -14,7 +14,6 @@ import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.security.core.annotation.AuthenticationPrincipal; -import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import org.springframework.web.server.ResponseStatusException; @@ -22,8 +21,8 @@ import java.io.InputStream; import java.util.List; -@Controller -@RequestMapping("/documents") +@RestController +@RequestMapping("/api/documents") public class DocumentController { private final DocumentService documentService; @@ -38,10 +37,13 @@ public DocumentController(DocumentService documentService, IncidentService incid } @GetMapping("/{fileKey}") - @ResponseBody public ResponseEntity getFile(@PathVariable String fileKey, @AuthenticationPrincipal CustomUserDetails userDetails) { + if (userDetails == null) { + throw new ResponseStatusException(HttpStatus.UNAUTHORIZED); + } + AppUser user = userDetails.getUser(); Document document = documentService.getByFileKey(fileKey) @@ -64,8 +66,8 @@ public ResponseEntity getFile(@PathVariable String fileKey, } @PostMapping("/upload/{incidentId}") - public String uploadFile(@PathVariable Long incidentId, @RequestParam("files") List files, - @AuthenticationPrincipal CustomUserDetails userDetails) { + public ResponseEntity uploadFile(@PathVariable Long incidentId, + @RequestParam("files") List files, @AuthenticationPrincipal CustomUserDetails userDetails) { AppUser user = userDetails.getUser(); Incident incident = incidentService.getById(incidentId, user); @@ -75,22 +77,18 @@ public String uploadFile(@PathVariable Long incidentId, @RequestParam("files") L documentService.uploadFile(file, incident); } } - return "redirect:/incidents/" + incidentId; + return ResponseEntity.ok().build(); } - @GetMapping("/download/{incidentId}") - public ResponseEntity downloadFile(@PathVariable Long incidentId, + @GetMapping("/{fileKey}/download") + public ResponseEntity downloadFile(@PathVariable String fileKey, @AuthenticationPrincipal CustomUserDetails userDetails) { AppUser user = userDetails.getUser(); - Incident incident = incidentService.getById(incidentId, user); - List documents = documentService.getDocumentsByIncident(incident); - if (documents.isEmpty()) { - return ResponseEntity.notFound().build(); - } - Document document = documents.get(0); + Document document = documentService.getByFileKey(fileKey) + .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND)); - InputStream stream = documentService.downloadFile(document.getFileKey()); + InputStream stream = minioService.getFile(fileKey); return ResponseEntity.ok() .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + document.getFileName() + "\"") diff --git a/src/main/java/org/example/team6backend/document/service/DocumentService.java b/src/main/java/org/example/team6backend/document/service/DocumentService.java index c57c8a9..3b77be6 100644 --- a/src/main/java/org/example/team6backend/document/service/DocumentService.java +++ b/src/main/java/org/example/team6backend/document/service/DocumentService.java @@ -60,11 +60,10 @@ public InputStream downloadFile(String objectKey) { /** Delete file */ @Transactional public void deleteFile(Document document) { - documentRepository.delete(document); - try { + documentRepository.delete(document); minioService.deleteFile(document.getFileKey()); - } catch (Exception e) { + } catch (RuntimeException e) { log.warn("Could not delete file: {}", document.getFileKey(), e); } } diff --git a/src/main/java/org/example/team6backend/document/service/MinioService.java b/src/main/java/org/example/team6backend/document/service/MinioService.java index 4bb107d..6fbe36f 100644 --- a/src/main/java/org/example/team6backend/document/service/MinioService.java +++ b/src/main/java/org/example/team6backend/document/service/MinioService.java @@ -57,7 +57,7 @@ public void deleteFile(String fileKey) { try { minioClient.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(fileKey).build()); } catch (Exception e) { - throw new RuntimeException("Failed to delete file " + fileKey, e); + System.err.println("MinIO delete failed for " + fileKey + ": " + e.getMessage()); } } diff --git a/src/main/java/org/example/team6backend/page/PageController.java b/src/main/java/org/example/team6backend/page/PageController.java deleted file mode 100644 index 5636378..0000000 --- a/src/main/java/org/example/team6backend/page/PageController.java +++ /dev/null @@ -1,148 +0,0 @@ -package org.example.team6backend.page; - -import jakarta.validation.Valid; -import org.example.team6backend.document.service.DocumentService; -import org.example.team6backend.incident.dto.IncidentRequest; -import org.example.team6backend.incident.entity.Incident; -import org.example.team6backend.incident.service.IncidentService; -import org.example.team6backend.security.CustomUserDetails; -import org.example.team6backend.user.entity.AppUser; -import org.example.team6backend.user.entity.UserRole; -import org.example.team6backend.user.service.UserService; -import jakarta.servlet.http.HttpServletRequest; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.security.core.annotation.AuthenticationPrincipal; -import org.springframework.security.web.csrf.CsrfToken; -import org.springframework.stereotype.Controller; -import org.springframework.ui.Model; -import org.springframework.validation.BindingResult; -import org.springframework.web.bind.annotation.*; -import org.springframework.web.multipart.MultipartFile; - -import java.util.List; - -@Controller -public class PageController { - private final UserService userService; - private final IncidentService incidentService; - private final DocumentService documentService; - - public PageController(UserService userService, IncidentService incidentService, DocumentService documentService) { - this.userService = userService; - this.incidentService = incidentService; - this.documentService = documentService; - } - - @GetMapping("/") - public String index() { - return "index"; - } - - @GetMapping("/dashboard") - public String dashboard(@AuthenticationPrincipal CustomUserDetails userDetails, Model model, Pageable pageable) { - - if (userDetails != null && userDetails.getUser() != null) { - AppUser user = userDetails.getUser(); - model.addAttribute("user", userDetails.getUser()); - model.addAttribute("role", user.getRole().name()); - - Page incidents; - - switch (user.getRole()) { - case RESIDENT -> incidents = incidentService.findByCreatedBy(user, pageable); - case HANDLER -> incidents = incidentService.findByAssignedTo(user, pageable); - case ADMIN -> incidents = incidentService.findAll(pageable); - default -> incidents = Page.empty(); - } - model.addAttribute("incidents", incidents); - - } else { - model.addAttribute("role", "PENDING"); - } - return "dashboard"; - } - - @GetMapping("/incidents") - public String incidents(@AuthenticationPrincipal CustomUserDetails userDetails, Model model) { - model.addAttribute("role", userDetails.getUser().getRole().name()); - return "incidents"; - } - - @GetMapping("/create-incident") - public String createIncident(@AuthenticationPrincipal CustomUserDetails userDetails, Model model, - HttpServletRequest request) { - AppUser user = userDetails.getUser(); - String role = user.getRole().name(); - - CsrfToken csrf = (CsrfToken) request.getAttribute("_csrf"); - model.addAttribute("_csrf", csrf); - - if (role.equals("RESIDENT") || role.equals("ADMIN")) { - model.addAttribute("role", role); - model.addAttribute("user", user); - model.addAttribute("incidentRequest", new IncidentRequest()); - return "createincident"; - } - return "redirect:/dashboard"; - } - - @PreAuthorize("hasAnyRole('RESIDENT', 'ADMIN')") - @PostMapping("/create-incident") - public String submitIncident(@AuthenticationPrincipal CustomUserDetails userDetails, - @Valid @ModelAttribute IncidentRequest incidentRequest, BindingResult bindingResult, - @RequestParam(value = "files", required = false) List files, Model model, - HttpServletRequest request) { - - AppUser user = userDetails.getUser(); - - if (bindingResult.hasErrors()) { - CsrfToken csrf = (CsrfToken) request.getAttribute("_csrf"); - model.addAttribute("_csrf", csrf); - model.addAttribute("role", user.getRole().name()); - model.addAttribute("user", user); - return "createincident"; - } - - Incident saved = incidentService.createIncident(incidentRequest, files, user); - - return "redirect:/incidents/" + saved.getId(); - } - - @GetMapping("/profile") - public String profile(@AuthenticationPrincipal CustomUserDetails userDetails, Model model) { - AppUser user = userDetails.getUser(); - model.addAttribute("user", user); - model.addAttribute("role", user.getRole().name()); - return "profile"; - } - - @GetMapping("/admin") - public String admin(@AuthenticationPrincipal CustomUserDetails userDetails, Model model) { - AppUser user = userDetails.getUser(); - - if (user.getRole().name().equals("ADMIN")) { - model.addAttribute("user", user); - model.addAttribute("role", user.getRole().name()); - model.addAttribute("handlers", userService.getUsersByRole(UserRole.HANDLER)); - return "admin"; - } - - return "redirect:/dashboard"; - } - - @GetMapping("/incidents/{id}") - public String viewIncident(@PathVariable Long id, @AuthenticationPrincipal CustomUserDetails userDetails, - Model model) { - model.addAttribute("role", userDetails.getUser().getRole().name()); - model.addAttribute("incidentId", id); - model.addAttribute("userId", userDetails.getUser().getId()); - return "viewincident"; - } - - @GetMapping("/demo") - public String demo() { - return "demo"; - } -} diff --git a/src/main/resources/templates/admin.html b/src/main/resources/static/admin.html similarity index 99% rename from src/main/resources/templates/admin.html rename to src/main/resources/static/admin.html index 2926868..a360c5f 100644 --- a/src/main/resources/templates/admin.html +++ b/src/main/resources/static/admin.html @@ -771,10 +771,10 @@ Incident Management System