Public Access
chore(library)!: drop the full-replace PUT of a backlog entry
The Frontend sends PATCH since item 27 batch 2.
This commit is contained in:
1 parent
34d64e7215
commit
23bf5c41b4
5 files changed
+6
-100
No files matched your search
@@ -3,7 +3,6 @@ package core_service.modules.library.api;
|
||||
import core_service.shared.api.ErrorResponse;
|
||||
import core_service.modules.library.api.dto.AchievementSummaryDto;
|
||||
import core_service.modules.library.api.dto.ActivityDto;
|
||||
import core_service.modules.library.api.dto.BacklogEntryDto;
|
||||
import core_service.modules.library.api.dto.BacklogPatch;
|
||||
import core_service.modules.library.api.dto.BrokenImageReport;
|
||||
import core_service.modules.library.api.dto.CorrectionDto;
|
||||
@@ -219,16 +218,6 @@ public class LibraryController {
|
||||
return ResponseEntity.badRequest().body(new ErrorResponse("INVALID_CORRECTION", message));
|
||||
}
|
||||
|
||||
@PutMapping("/games/{appid}/backlog")
|
||||
public ResponseEntity<?> updateBacklog(@AuthenticationPrincipal UserPrincipal principal,
|
||||
@PathVariable("appid") Long appid,
|
||||
@Valid @RequestBody BacklogEntryDto entry) {
|
||||
return backlogService.update(principal.getIdAsLong(), appid, entry)
|
||||
.<ResponseEntity<?>>map(ResponseEntity::ok)
|
||||
.orElseGet(() -> ResponseEntity.status(HttpStatus.NOT_FOUND)
|
||||
.body(GAME_NOT_FOUND));
|
||||
}
|
||||
|
||||
@PatchMapping("/games/{appid}/backlog")
|
||||
public ResponseEntity<?> patchBacklog(@AuthenticationPrincipal UserPrincipal principal,
|
||||
@PathVariable("appid") Long appid,
|
||||
|
||||
@@ -24,23 +24,6 @@ public class BacklogService {
|
||||
|
||||
private final UserGameRepository userGameRepository;
|
||||
|
||||
/**
|
||||
* @return empty when the game is not in the user's active library
|
||||
*/
|
||||
@Transactional
|
||||
public Optional<BacklogEntryDto> update(Long userId, Long appid, BacklogEntryDto entry) {
|
||||
return userGameRepository.findById(new UserGameId(userId, appid))
|
||||
.filter(game -> game.getRemovedAt() == null)
|
||||
.map(game -> {
|
||||
game.setStatus(entry.status());
|
||||
game.setStatusSetByUser(true);
|
||||
game.setRating(entry.rating());
|
||||
game.setNotes(entry.notes() == null || entry.notes().isBlank() ? null : entry.notes());
|
||||
game.setPriority(entry.priority());
|
||||
return toDto(game);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes only the fields the patch sends. Only a sent status counts as set by the user, so a save of the notes
|
||||
* alone still lets the sync move the game from BACKLOG to PLAYING.
|
||||
|
||||
@@ -60,88 +60,23 @@ class LibraryControllerBacklogTest extends AbstractIntegrationTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void updateBacklog_StoresAllFields() throws Exception {
|
||||
mockMvc.perform(put("/api/library/games/220/backlog").header(ClientHeaderFilter.CLIENT_HEADER, "test").contentType(MediaType.APPLICATION_JSON)
|
||||
.content("{\"status\":\"FINISHED\",\"rating\":4,\"notes\":\"Great ending\",\"priority\":\"HIGH\"}"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.status").value("FINISHED"))
|
||||
.andExpect(jsonPath("$.rating").value(4));
|
||||
|
||||
UserGame game = stored();
|
||||
assertEquals(GameStatus.FINISHED, game.getStatus());
|
||||
assertEquals(4, game.getRating());
|
||||
assertEquals("Great ending", game.getNotes());
|
||||
assertEquals("HIGH", game.getPriority().name());
|
||||
}
|
||||
|
||||
@Test
|
||||
void updateBacklog_NullsClearOptionalFieldsAndBlankNotesAreNull() throws Exception {
|
||||
UserGame game = stored();
|
||||
game.setRating(5);
|
||||
game.setNotes("old");
|
||||
userGameRepository.save(game);
|
||||
|
||||
mockMvc.perform(put("/api/library/games/220/backlog").header(ClientHeaderFilter.CLIENT_HEADER, "test").contentType(MediaType.APPLICATION_JSON)
|
||||
.content("{\"status\":\"DROPPED\",\"notes\":\" \"}"))
|
||||
.andExpect(status().isOk());
|
||||
|
||||
game = stored();
|
||||
assertEquals(GameStatus.DROPPED, game.getStatus());
|
||||
assertNull(game.getRating());
|
||||
assertNull(game.getNotes());
|
||||
assertNull(game.getPriority());
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = {
|
||||
"{}",
|
||||
"{\"status\":\"WISHLIST\"}",
|
||||
"{\"status\":\"PLAYING\",\"rating\":0}",
|
||||
"{\"status\":\"PLAYING\",\"rating\":6}",
|
||||
"{\"status\":\"PLAYING\",\"priority\":\"URGENT\"}"})
|
||||
void updateBacklog_InvalidBody_Is400AndStoresNothing(String body) throws Exception {
|
||||
mockMvc.perform(put("/api/library/games/220/backlog").header(ClientHeaderFilter.CLIENT_HEADER, "test").contentType(MediaType.APPLICATION_JSON).content(body))
|
||||
.andExpect(status().isBadRequest());
|
||||
|
||||
assertEquals(GameStatus.BACKLOG, stored().getStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
void updateBacklog_FractionalRating_Is400() throws Exception {
|
||||
mockMvc.perform(put("/api/library/games/220/backlog").header(ClientHeaderFilter.CLIENT_HEADER, "test").contentType(MediaType.APPLICATION_JSON)
|
||||
.content("{\"status\":\"PLAYING\",\"rating\":4.7}"))
|
||||
.andExpect(status().isBadRequest());
|
||||
void patchBacklog_FractionalRating_Is400() throws Exception {
|
||||
patchBacklog(APPID, "{\"rating\":4.7}").andExpect(status().isBadRequest());
|
||||
|
||||
assertNull(stored().getRating());
|
||||
}
|
||||
|
||||
@Test
|
||||
void updateBacklog_NotesTooLong_Is400() throws Exception {
|
||||
String notes = "x".repeat(2001);
|
||||
mockMvc.perform(put("/api/library/games/220/backlog").header(ClientHeaderFilter.CLIENT_HEADER, "test").contentType(MediaType.APPLICATION_JSON)
|
||||
.content("{\"status\":\"PLAYING\",\"notes\":\"" + notes + "\"}"))
|
||||
.andExpect(status().isBadRequest());
|
||||
}
|
||||
|
||||
@Test
|
||||
void updateBacklog_RemovedGame_Is404() throws Exception {
|
||||
void patchBacklog_RemovedGame_Is404() throws Exception {
|
||||
UserGame game = stored();
|
||||
game.setRemovedAt(Instant.now());
|
||||
userGameRepository.save(game);
|
||||
|
||||
mockMvc.perform(put("/api/library/games/220/backlog").header(ClientHeaderFilter.CLIENT_HEADER, "test").contentType(MediaType.APPLICATION_JSON)
|
||||
.content("{\"status\":\"PLAYING\"}"))
|
||||
patchBacklog(APPID, "{\"notes\":\"x\"}")
|
||||
.andExpect(status().isNotFound())
|
||||
.andExpect(jsonPath("$.code").value("GAME_NOT_FOUND"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void updateBacklog_GameNotOwned_Is404() throws Exception {
|
||||
mockMvc.perform(put("/api/library/games/999/backlog").header(ClientHeaderFilter.CLIENT_HEADER, "test").contentType(MediaType.APPLICATION_JSON)
|
||||
.content("{\"status\":\"PLAYING\"}"))
|
||||
.andExpect(status().isNotFound());
|
||||
}
|
||||
|
||||
private ResultActions patchBacklog(long appid, String body) throws Exception {
|
||||
return mockMvc.perform(patch("/api/library/games/" + appid + "/backlog").header(ClientHeaderFilter.CLIENT_HEADER, "test")
|
||||
.contentType(MediaType.APPLICATION_JSON).content(body));
|
||||
|
||||
@@ -24,7 +24,7 @@ import java.util.List;
|
||||
import static org.hamcrest.Matchers.hasSize;
|
||||
import static org.hamcrest.Matchers.nullValue;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
@@ -189,7 +189,7 @@ class PublicProfileControllerTest extends AbstractIntegrationTest {
|
||||
// The dev filter falls back to the dummy user 1 for a token it rejects; user 7's game would answer 200.
|
||||
@Test
|
||||
void profileTicket_IsNoLoginForTheLibraryApi() throws Exception {
|
||||
mockMvc.perform(put("/api/library/games/220/backlog").header("Authorization", "Bearer " + ticket(USER_ID))
|
||||
mockMvc.perform(patch("/api/library/games/220/backlog").header("Authorization", "Bearer " + ticket(USER_ID))
|
||||
.contentType("application/json").content("{\"status\":\"DROPPED\"}"))
|
||||
.andExpect(status().isNotFound());
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user