Release 1.1.0 #16

Merged
Cedric merged 21 commits from dev into main 2026-07-05 00:03:47 +02:00
3 changed files with 74 additions and 0 deletions
Showing only changes of commit 41e32efd7e - Show all commits
@@ -80,6 +80,18 @@ public class ExpenseListController {
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}
@PutMapping("/{id}/rename")
public ResponseEntity<ExpenseList> rename(@PathVariable("id") Long id,
@RequestBody @Valid CreateExpenseListRequest request, Authentication authentication) {
AppUser user = authenticatedUserResolver.resolveCurrentUser(authentication);
Optional<ExpenseList> 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<Expense> addExpenseToList(
@PathVariable("id") Long expenseListId,
@@ -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<ExpenseList> findById(Long id) {
return repository.findById(id);
}
@@ -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