feat(geschichten): show blog writers' own drafts on the Geschichten overview (#807) #813
@@ -117,12 +117,17 @@ public class GeschichteService {
|
||||
*
|
||||
* <p>Returns a {@link GeschichteSummary} projection — never carries items, preventing
|
||||
* LazyInitializationException on the non-transactional list path.
|
||||
*
|
||||
* <p>Security: {@code null} status always resolves to PUBLISHED — even for blog writers.
|
||||
* Only an explicit {@code DRAFT} request scopes the query to the caller's own drafts.
|
||||
* This prevents CWE-639: a blog writer passing {@code null} must not see all authors' drafts.
|
||||
*/
|
||||
public List<GeschichteSummary> list(GeschichteStatus status, List<UUID> personIds, UUID documentId, int limit) {
|
||||
GeschichteStatus effective = currentUserHasBlogWrite() ? status : GeschichteStatus.PUBLISHED;
|
||||
boolean isDraftRequest = currentUserHasBlogWrite() && status == GeschichteStatus.DRAFT;
|
||||
GeschichteStatus effective = isDraftRequest ? GeschichteStatus.DRAFT : GeschichteStatus.PUBLISHED;
|
||||
int safeLimit = limit <= 0 ? DEFAULT_LIMIT : Math.min(limit, MAX_LIMIT);
|
||||
|
||||
UUID authorId = effective == GeschichteStatus.DRAFT ? currentUser().getId() : null;
|
||||
UUID authorId = isDraftRequest ? currentUser().getId() : null;
|
||||
|
||||
// When personIds is empty, personCount=0 short-circuits the IN() predicate.
|
||||
// Pass a sentinel UUID to avoid invalid empty IN() SQL while the predicate is skipped.
|
||||
|
||||
@@ -324,6 +324,7 @@ class GeschichteServiceTest {
|
||||
@DisplayName("security: DRAFT status scopes to current user only")
|
||||
void list_with_DRAFT_status_scopes_to_current_user_not_all_authors() {
|
||||
authenticateAs(writer, Permission.BLOG_WRITE);
|
||||
when(userService.findByEmail(writer.getEmail())).thenReturn(writer);
|
||||
when(geschichteRepository.findSummaries(any(), any(), any(), anyLong(), any()))
|
||||
.thenReturn(List.of());
|
||||
|
||||
|
||||
Reference in New Issue
Block a user