feat: dedicated /documents search & browse page #282

Merged
marcel merged 50 commits from feat/issue-281-documents-page into main 2026-04-20 09:11:08 +02:00
4 changed files with 86 additions and 18 deletions
Showing only changes of commit 19832dc1e0 - Show all commits

View File

@@ -28,6 +28,7 @@ import org.raddatz.familienarchiv.model.DocumentVersion;
import org.raddatz.familienarchiv.model.AppUser;
import org.raddatz.familienarchiv.security.Permission;
import org.raddatz.familienarchiv.security.RequirePermission;
import org.raddatz.familienarchiv.security.SecurityUtils;
import org.raddatz.familienarchiv.service.DocumentService;
import org.raddatz.familienarchiv.service.DocumentVersionService;
import org.raddatz.familienarchiv.service.FileService;
@@ -286,13 +287,6 @@ public class DocumentController {
}
private UUID requireUserId(Authentication authentication) {
if (authentication == null || !authentication.isAuthenticated()) {
throw DomainException.unauthorized("Authentication required");
}
AppUser user = userService.findByEmail(authentication.getName());
if (user == null) {
throw DomainException.unauthorized("User not found");
}
return user.getId();
return SecurityUtils.requireUserId(authentication, userService);
}
}

View File

@@ -5,12 +5,11 @@ import lombok.extern.slf4j.Slf4j;
import org.raddatz.familienarchiv.dto.CreateTranscriptionBlockDTO;
import org.raddatz.familienarchiv.dto.ReorderTranscriptionBlocksDTO;
import org.raddatz.familienarchiv.dto.UpdateTranscriptionBlockDTO;
import org.raddatz.familienarchiv.exception.DomainException;
import org.raddatz.familienarchiv.model.AppUser;
import org.raddatz.familienarchiv.model.TranscriptionBlock;
import org.raddatz.familienarchiv.model.TranscriptionBlockVersion;
import org.raddatz.familienarchiv.security.Permission;
import org.raddatz.familienarchiv.security.RequirePermission;
import org.raddatz.familienarchiv.security.SecurityUtils;
import org.raddatz.familienarchiv.service.TranscriptionService;
import org.raddatz.familienarchiv.service.UserService;
import org.springframework.http.HttpStatus;
@@ -100,13 +99,6 @@ public class TranscriptionBlockController {
}
private UUID requireUserId(Authentication authentication) {
if (authentication == null || !authentication.isAuthenticated()) {
throw DomainException.unauthorized("Authentication required");
}
AppUser user = userService.findByEmail(authentication.getName());
if (user == null) {
throw DomainException.unauthorized("User not found");
}
return user.getId();
return SecurityUtils.requireUserId(authentication, userService);
}
}

View File

@@ -0,0 +1,24 @@
package org.raddatz.familienarchiv.security;
import org.raddatz.familienarchiv.exception.DomainException;
import org.raddatz.familienarchiv.model.AppUser;
import org.raddatz.familienarchiv.service.UserService;
import org.springframework.security.core.Authentication;
import java.util.UUID;
public final class SecurityUtils {
private SecurityUtils() {}
public static UUID requireUserId(Authentication authentication, UserService userService) {
if (authentication == null || !authentication.isAuthenticated()) {
throw DomainException.unauthorized("Authentication required");
}
AppUser user = userService.findByEmail(authentication.getName());
if (user == null) {
throw DomainException.unauthorized("User not found");
}
return user.getId();
}
}

View File

@@ -0,0 +1,58 @@
package org.raddatz.familienarchiv.security;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.raddatz.familienarchiv.exception.DomainException;
import org.raddatz.familienarchiv.model.AppUser;
import org.raddatz.familienarchiv.service.UserService;
import org.springframework.security.core.Authentication;
import java.util.UUID;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
class SecurityUtilsTest {
@Mock Authentication authentication;
@Mock UserService userService;
@Test
void requireUserId_throwsUnauthorized_whenAuthenticationIsNull() {
assertThatThrownBy(() -> SecurityUtils.requireUserId(null, userService))
.isInstanceOf(DomainException.class);
}
@Test
void requireUserId_throwsUnauthorized_whenNotAuthenticated() {
when(authentication.isAuthenticated()).thenReturn(false);
assertThatThrownBy(() -> SecurityUtils.requireUserId(authentication, userService))
.isInstanceOf(DomainException.class);
}
@Test
void requireUserId_throwsUnauthorized_whenUserNotFound() {
when(authentication.isAuthenticated()).thenReturn(true);
when(authentication.getName()).thenReturn("ghost@example.com");
when(userService.findByEmail("ghost@example.com")).thenReturn(null);
assertThatThrownBy(() -> SecurityUtils.requireUserId(authentication, userService))
.isInstanceOf(DomainException.class);
}
@Test
void requireUserId_returnsUserId_whenAuthenticated() {
UUID userId = UUID.randomUUID();
AppUser user = AppUser.builder().id(userId).email("user@example.com").password("pw").build();
when(authentication.isAuthenticated()).thenReturn(true);
when(authentication.getName()).thenReturn("user@example.com");
when(userService.findByEmail("user@example.com")).thenReturn(user);
UUID result = SecurityUtils.requireUserId(authentication, userService);
assertThat(result).isEqualTo(userId);
}
}