diff --git a/src/main/java/org/example/crimearchive/cases/CaseService.java b/src/main/java/org/example/crimearchive/cases/CaseService.java index 341c6c2..8c3e8a8 100644 --- a/src/main/java/org/example/crimearchive/cases/CaseService.java +++ b/src/main/java/org/example/crimearchive/cases/CaseService.java @@ -1,5 +1,6 @@ package org.example.crimearchive.cases; +import org.example.crimearchive.exceptions.NotFoundException; import org.example.crimearchive.polis.Account; import org.example.crimearchive.polis.UserRepository; import org.example.crimearchive.reports.Report; @@ -28,9 +29,9 @@ public CaseService(ReportRepository reportRepository, CasesRepository casesRepos @Transactional public void addAccountToCase(Long accountId, String caseNumber) { Optional account = userRepository.findById(accountId); - if (account.isEmpty()) throw new RuntimeException("account not found"); + if (account.isEmpty()) throw new NotFoundException("Account not found"); Optional cases = casesRepository.findFirstByCaseNumber(caseNumber); - if (cases.isEmpty()) throw new RuntimeException("Case does not exist"); + if (cases.isEmpty()) throw new NotFoundException("Case does not exist"); if (cases.get().getAccounts().stream().anyMatch(acc -> acc.getId().equals(accountId))) { cases.get().removeAccountFromCase(account.get()); } else { @@ -42,9 +43,9 @@ public void addAccountToCase(Long accountId, String caseNumber) { @Transactional public void addAccountToCase(Long accountId, Long caseId) { Optional account = userRepository.findById(accountId); - if (account.isEmpty()) throw new RuntimeException("Account not found with id: " + accountId); + if (account.isEmpty()) throw new NotFoundException("Account not found with id: " + accountId); Optional cases = casesRepository.findById(caseId); - if (cases.isEmpty()) throw new RuntimeException("Case not found with id: " + caseId); + if (cases.isEmpty()) throw new NotFoundException("Case not found with id: " + caseId); cases.get().addAccountToCase(account.get()); casesRepository.save(cases.get()); } @@ -55,7 +56,7 @@ public List getAllCases() { public List getAllPoliceForCase(String casenumber) { return casesRepository.findFirstByCaseNumber(casenumber) - .orElseThrow(() -> new RuntimeException("Case not found: " + casenumber)) + .orElseThrow(() -> new NotFoundException("Case not found: " + casenumber)) .getAccounts().stream().toList(); } @@ -73,14 +74,14 @@ public Report getReport(Cases caseId) { @Transactional(readOnly = true) public Set getReportSet(Long caseId) { - return casesRepository.findById(caseId).orElseThrow(() -> new RuntimeException("Case not found with id: " + caseId)) + return casesRepository.findById(caseId).orElseThrow(() -> new NotFoundException("Case not found with id: " + caseId)) .getReports(); } @Transactional(readOnly = true) public Set getReportSet(String caseNumber) { Long id = caseIdFromCaseNumber(caseNumber); - return casesRepository.findById(id).orElseThrow(() -> new RuntimeException("Case not found with case number: " + caseNumber)) + return casesRepository.findById(id).orElseThrow(() -> new NotFoundException("Case not found with case number: " + caseNumber)) .getReports(); } @@ -98,7 +99,7 @@ public List getAllUnSignedCases() { public Long caseIdFromCaseNumber(String casenumber) { return casesRepository.findFirstByCaseNumber(casenumber) - .orElseThrow(() -> new RuntimeException("Case not found: " + casenumber)) + .orElseThrow(() -> new NotFoundException("Case not found: " + casenumber)) .getId(); } diff --git a/src/main/java/org/example/crimearchive/controllers/HomeController.java b/src/main/java/org/example/crimearchive/controllers/HomeController.java index 03116ad..9e677e9 100644 --- a/src/main/java/org/example/crimearchive/controllers/HomeController.java +++ b/src/main/java/org/example/crimearchive/controllers/HomeController.java @@ -76,4 +76,12 @@ public String saveReport( return "redirect:/userpage"; } + + @GetMapping("/403") + public String accessDenied(Model model) { + model.addAttribute("status", 403); + model.addAttribute("title", "Åtkomst nekad"); + model.addAttribute("message", "Du saknar rättigheter för att visa denna sida."); + return "error/error"; + } } diff --git a/src/main/java/org/example/crimearchive/exceptions/GlobalExceptionHandler.java b/src/main/java/org/example/crimearchive/exceptions/GlobalExceptionHandler.java new file mode 100644 index 0000000..2338eea --- /dev/null +++ b/src/main/java/org/example/crimearchive/exceptions/GlobalExceptionHandler.java @@ -0,0 +1,52 @@ +package org.example.crimearchive.exceptions; + +import org.springframework.http.HttpStatus; +import org.springframework.ui.Model; +import org.springframework.web.servlet.resource.NoResourceFoundException; +import org.springframework.web.bind.annotation.*; + +@ControllerAdvice +public class GlobalExceptionHandler { + + private static final String ERROR_VIEW = "error/error"; + + private String buildError(Model model, int status, String title, String message) { + model.addAttribute("status", status); + model.addAttribute("title", title); + model.addAttribute("message", message); + return ERROR_VIEW; + } + + @ExceptionHandler(NotFoundException.class) + @ResponseStatus(HttpStatus.NOT_FOUND) + public String handleNotFound(NotFoundException ex, Model model) { + return buildError( + model, + HttpStatus.NOT_FOUND.value(), + "Sidan finns inte", + ex.getMessage() + ); + } + + @ExceptionHandler(NoResourceFoundException.class) + @ResponseStatus(HttpStatus.NOT_FOUND) + public String handleNoResource(NoResourceFoundException ex, Model model) { + return buildError( + model, + HttpStatus.NOT_FOUND.value(), + "Sidan finns inte", + "Sidan du försöker nå kunde inte hittas." + ); + } + + @ExceptionHandler(RuntimeException.class) + @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) + public String handleRuntime(RuntimeException ex, Model model) { + return buildError( + model, + HttpStatus.INTERNAL_SERVER_ERROR.value(), + "Internt serverfel", + "Ett oväntat fel inträffade." + ); + } +} diff --git a/src/main/java/org/example/crimearchive/exceptions/NotFoundException.java b/src/main/java/org/example/crimearchive/exceptions/NotFoundException.java new file mode 100644 index 0000000..2154d31 --- /dev/null +++ b/src/main/java/org/example/crimearchive/exceptions/NotFoundException.java @@ -0,0 +1,12 @@ +package org.example.crimearchive.exceptions; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +@ResponseStatus(HttpStatus.NOT_FOUND) +public class NotFoundException extends RuntimeException { + + public NotFoundException(String message) { + super(message); + } +} diff --git a/src/main/resources/templates/error/403.html b/src/main/resources/templates/error/403.html new file mode 100644 index 0000000..7b67132 --- /dev/null +++ b/src/main/resources/templates/error/403.html @@ -0,0 +1,63 @@ + + + + + Åtkomst nekad + + + + + +
+ +
+
+ + +
+
+ DurTre + Polismyndigheten +
+ Åtkomst nekad +
+
+
+ +
+ +
+ + + 403 + + +

+ Du har inte behörighet +

+ +

+ Du saknar rättigheter för att visa denna sida. +

+ +

+ Kontakta administratör om du anser att detta är fel. +

+ + + Startsida + + +
+ +
+ +
+ + + diff --git a/src/main/resources/templates/error/error.html b/src/main/resources/templates/error/error.html new file mode 100644 index 0000000..7f5ecce --- /dev/null +++ b/src/main/resources/templates/error/error.html @@ -0,0 +1,65 @@ + + + + + Fel + + + + + +
+ +
+
+ + +
+
+ DurTre + Polismyndigheten +
+ + + Fel + +
+
+
+ +
+ +
+ + + 500 + + +

+ Fel +

+ +

+ Något gick fel +

+ + + Startsida + + +
+ +
+ +
+ + + diff --git a/src/test/java/org/example/crimearchive/exceptions/GlobalExceptionHandlerTest.java b/src/test/java/org/example/crimearchive/exceptions/GlobalExceptionHandlerTest.java new file mode 100644 index 0000000..e9586a9 --- /dev/null +++ b/src/test/java/org/example/crimearchive/exceptions/GlobalExceptionHandlerTest.java @@ -0,0 +1,62 @@ +package org.example.crimearchive.exceptions; + +import org.junit.jupiter.api.Test; +import org.springframework.ui.ExtendedModelMap; +import org.springframework.ui.Model; +import org.springframework.http.HttpMethod; +import org.springframework.web.servlet.resource.NoResourceFoundException; + +import static org.junit.jupiter.api.Assertions.*; + +class GlobalExceptionHandlerTest { + + private final GlobalExceptionHandler handler = new GlobalExceptionHandler(); + + @Test + void shouldHandleNotFoundException() { + Model model = new ExtendedModelMap(); + + String view = handler.handleNotFound( + new NotFoundException("Testmeddelande"), + model + ); + + assertEquals("error/error", view); + assertEquals(404, model.getAttribute("status")); + assertEquals("Sidan finns inte", model.getAttribute("title")); + assertEquals("Testmeddelande", model.getAttribute("message")); + } + + @Test + void shouldHandleRuntimeException() { + Model model = new ExtendedModelMap(); + + String view = handler.handleRuntime( + new RuntimeException("Boom"), + model + ); + + assertEquals("error/error", view); + assertEquals(500, model.getAttribute("status")); + assertEquals("Internt serverfel", model.getAttribute("title")); + assertEquals("Ett oväntat fel inträffade.", model.getAttribute("message")); + } + + @Test + void shouldHandleNoResourceFoundException() { + Model model = new ExtendedModelMap(); + + String view = handler.handleNoResource( + new NoResourceFoundException( + HttpMethod.GET, + "/test", + "Resource not found" + ), + model + ); + + assertEquals("error/error", view); + assertEquals(404, model.getAttribute("status")); + assertEquals("Sidan finns inte", model.getAttribute("title")); + } +}