diff --git a/src/main/java/de/zendric/app/xpensely_server/controller/ExpenseListController.java b/src/main/java/de/zendric/app/xpensely_server/controller/ExpenseListController.java index ae4bb58..03ce5a9 100644 --- a/src/main/java/de/zendric/app/xpensely_server/controller/ExpenseListController.java +++ b/src/main/java/de/zendric/app/xpensely_server/controller/ExpenseListController.java @@ -80,6 +80,18 @@ public class ExpenseListController { return new ResponseEntity<>(HttpStatus.NO_CONTENT); } + @PutMapping("/{id}/rename") + public ResponseEntity rename(@PathVariable("id") Long id, + @RequestBody @Valid CreateExpenseListRequest request, Authentication authentication) { + AppUser user = authenticatedUserResolver.resolveCurrentUser(authentication); + Optional listOpt = expenseListService.findById(id); + if (listOpt.isEmpty()) + return new ResponseEntity<>(HttpStatus.NOT_FOUND); + assertOwner(user, listOpt.get()); + ExpenseList renamed = expenseListService.renameList(id, request.getName()); + return new ResponseEntity<>(renamed, HttpStatus.OK); + } + @PostMapping("/{id}/add") public ResponseEntity addExpenseToList( @PathVariable("id") Long expenseListId, diff --git a/src/main/java/de/zendric/app/xpensely_server/services/ExpenseListService.java b/src/main/java/de/zendric/app/xpensely_server/services/ExpenseListService.java index 20d8177..7ab97f7 100644 --- a/src/main/java/de/zendric/app/xpensely_server/services/ExpenseListService.java +++ b/src/main/java/de/zendric/app/xpensely_server/services/ExpenseListService.java @@ -39,6 +39,13 @@ public class ExpenseListService { repository.deleteById(id); } + public ExpenseList renameList(Long id, String newName) { + ExpenseList list = repository.findById(id) + .orElseThrow(() -> new ResourceNotFoundException("ExpenseList not found with id: " + id)); + list.setName(newName); + return repository.save(list); + } + public Optional findById(Long id) { return repository.findById(id); } diff --git a/src/test/java/de/zendric/app/xpensely_Server/controller/ExpenseListControllerTest.java b/src/test/java/de/zendric/app/xpensely_Server/controller/ExpenseListControllerTest.java index 50913ea..e203b64 100644 --- a/src/test/java/de/zendric/app/xpensely_Server/controller/ExpenseListControllerTest.java +++ b/src/test/java/de/zendric/app/xpensely_Server/controller/ExpenseListControllerTest.java @@ -207,6 +207,61 @@ class ExpenseListControllerTest { .andExpect(status().isCreated()); } + // --- Rename list --- + + @Test + void renameList_owner_returns200WithRenamedList() throws Exception { + AppUser owner = new AppUser(); owner.setId(1L); + ExpenseList list = new ExpenseList(); list.setId(5L); list.setOwner(owner); + ExpenseList renamed = new ExpenseList(); renamed.setId(5L); renamed.setName("Groceries"); + + when(expenseListService.findById(5L)).thenReturn(Optional.of(list)); + when(authenticatedUserResolver.resolveCurrentUser(any())).thenReturn(owner); + when(expenseListService.renameList(5L, "Groceries")).thenReturn(renamed); + + mockMvc.perform(put("/api/expenselist/5/rename") + .contentType(MediaType.APPLICATION_JSON) + .content("{\"name\":\"Groceries\"}")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.name").value("Groceries")); + } + + @Test + void renameList_nonOwner_returns403() throws Exception { + AppUser owner = new AppUser(); owner.setId(1L); + AppUser nonOwner = new AppUser(); nonOwner.setId(2L); + ExpenseList list = new ExpenseList(); list.setId(5L); list.setOwner(owner); + + when(expenseListService.findById(5L)).thenReturn(Optional.of(list)); + when(authenticatedUserResolver.resolveCurrentUser(any())).thenReturn(nonOwner); + + mockMvc.perform(put("/api/expenselist/5/rename") + .contentType(MediaType.APPLICATION_JSON) + .content("{\"name\":\"Groceries\"}")) + .andExpect(status().isForbidden()); + } + + @Test + void renameList_blankName_returns400() throws Exception { + mockMvc.perform(put("/api/expenselist/5/rename") + .contentType(MediaType.APPLICATION_JSON) + .content("{\"name\":\"\"}")) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.name").exists()); + } + + @Test + void renameList_notFound_returns404() throws Exception { + AppUser owner = new AppUser(); owner.setId(1L); + when(expenseListService.findById(9L)).thenReturn(Optional.empty()); + when(authenticatedUserResolver.resolveCurrentUser(any())).thenReturn(owner); + + mockMvc.perform(put("/api/expenselist/9/rename") + .contentType(MediaType.APPLICATION_JSON) + .content("{\"name\":\"Groceries\"}")) + .andExpect(status().isNotFound()); + } + // --- Duplicate-username invite guard --- @Test