feat(auth): remove username field, migrate identity to email
- AppUser entity: replace username with email (NOT NULL, UNIQUE, colon-pattern validated) - AppUserRepository: remove findByUsername, rename search JPQL to searchByEmailOrName (searches email + firstName + lastName) - CreateUserRequest: remove username, require email with colon guard - UserService: rename findByUsername→findByEmail, createUserOrUpdate upserts by email, blank-email guard throws instead of setting null - UserController + all other controllers: findByEmail(auth.getName()) - DataInitializer: email-based config and lookup, E2E users have email - V44 migration: pre-check + email NOT NULL + drop username column - All tests updated: .username() builders removed, mocks updated, NotificationRepositoryTest fixtures include email fields Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -31,8 +31,8 @@ import java.util.Set;
|
||||
@DependsOn("flyway")
|
||||
public class DataInitializer {
|
||||
|
||||
@Value("${app.admin.username:admin}")
|
||||
private String adminUsername;
|
||||
@Value("${app.admin.email:admin@familyarchive.local}")
|
||||
private String adminEmail;
|
||||
|
||||
@Value("${app.admin.password:admin123}")
|
||||
private String adminPassword;
|
||||
@@ -43,26 +43,23 @@ public class DataInitializer {
|
||||
@Bean
|
||||
public CommandLineRunner initAdminUser(PasswordEncoder passwordEncoder) {
|
||||
return args -> {
|
||||
if (userRepository.findByUsername(adminUsername).isEmpty()) {
|
||||
log.info("Kein Admin-User '{}' gefunden. Erstelle Default-Admin...", adminUsername);
|
||||
if (userRepository.findByEmail(adminEmail).isEmpty()) {
|
||||
log.info("Kein Admin-User '{}' gefunden. Erstelle Default-Admin...", adminEmail);
|
||||
|
||||
// 1. Admin Gruppe erstellen
|
||||
UserGroup adminGroup = UserGroup.builder()
|
||||
.name("Administrators")
|
||||
.permissions(Set.of("ADMIN", "READ_ALL", "WRITE_ALL", "ANNOTATE_ALL", "ADMIN_USER", "ADMIN_TAG", "ADMIN_PERMISSION"))
|
||||
.build();
|
||||
groupRepository.save(adminGroup);
|
||||
|
||||
// 2. Admin User erstellen
|
||||
AppUser admin = AppUser.builder()
|
||||
.username(adminUsername)
|
||||
.password(passwordEncoder.encode(adminPassword)) // Passwort verschlüsseln!
|
||||
.email("admin@familyarchive.local")
|
||||
.email(adminEmail)
|
||||
.password(passwordEncoder.encode(adminPassword))
|
||||
.groups(Set.of(adminGroup))
|
||||
.build();
|
||||
userRepository.save(admin);
|
||||
|
||||
log.info("Default Admin erstellt: User='{}'", adminUsername);
|
||||
log.info("Default Admin erstellt: Email='{}'", adminEmail);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -84,16 +81,13 @@ public class DataInitializer {
|
||||
TagRepository tagRepo,
|
||||
PasswordEncoder passwordEncoder) {
|
||||
return args -> {
|
||||
// Always reset the admin password to the configured value so a failed password-reset
|
||||
// test from a previous run can never leave the account locked out.
|
||||
userRepository.findByUsername(adminUsername).ifPresent(admin -> {
|
||||
userRepository.findByEmail(adminEmail).ifPresent(admin -> {
|
||||
admin.setPassword(passwordEncoder.encode(adminPassword));
|
||||
userRepository.save(admin);
|
||||
log.info("E2E seed: Admin-Passwort auf konfigurierten Wert zurückgesetzt.");
|
||||
});
|
||||
|
||||
// Always ensure the read-only test user exists, even when seed data was already loaded.
|
||||
if (userRepository.findByUsername("reader").isEmpty()) {
|
||||
if (userRepository.findByEmail("reader@familyarchive.local").isEmpty()) {
|
||||
log.info("E2E seed: Erstelle 'reader'-Testbenutzer...");
|
||||
UserGroup leserGroup = groupRepository.findByName("Leser").orElseGet(() ->
|
||||
groupRepository.save(UserGroup.builder()
|
||||
@@ -101,7 +95,7 @@ public class DataInitializer {
|
||||
.permissions(Set.of("READ_ALL"))
|
||||
.build()));
|
||||
userRepository.save(AppUser.builder()
|
||||
.username("reader")
|
||||
.email("reader@familyarchive.local")
|
||||
.password(passwordEncoder.encode("reader123"))
|
||||
.groups(Set.of(leserGroup))
|
||||
.build());
|
||||
@@ -131,7 +125,6 @@ public class DataInitializer {
|
||||
Tag tagUrlaub = tagRepo.save(Tag.builder().name("Urlaub").build());
|
||||
|
||||
// ── Documents ────────────────────────────────────────────────────
|
||||
// 1. Fully transcribed letter — used by search + detail E2E tests
|
||||
docRepo.save(Document.builder()
|
||||
.title("Geburtsurkunde Hans Müller")
|
||||
.originalFilename("geburtsurkunde_hans.pdf")
|
||||
@@ -144,7 +137,6 @@ public class DataInitializer {
|
||||
.transcription("Hiermit wird beurkundet, dass Hans Müller am 12. April 1923 in Berlin geboren wurde.")
|
||||
.build());
|
||||
|
||||
// 2. Letter with multiple receivers and tags — tests multi-receiver display
|
||||
docRepo.save(Document.builder()
|
||||
.title("Brief aus dem Krieg")
|
||||
.originalFilename("brief_krieg_1944.pdf")
|
||||
@@ -157,7 +149,6 @@ public class DataInitializer {
|
||||
.transcription("Liebe Anna, ich schreibe dir aus der Front. Es geht mir den Umständen entsprechend gut.")
|
||||
.build());
|
||||
|
||||
// 3. Postcard — no transcription, tests PLACEHOLDER status
|
||||
docRepo.save(Document.builder()
|
||||
.title("Urlaubspostkarte Ostsee")
|
||||
.originalFilename("postkarte_1965.jpg")
|
||||
@@ -169,7 +160,6 @@ public class DataInitializer {
|
||||
.tags(Set.of(tagUrlaub))
|
||||
.build());
|
||||
|
||||
// 4. Document with no sender — tests null-sender display ("Unbekannt")
|
||||
docRepo.save(Document.builder()
|
||||
.title("Unbekanntes Dokument")
|
||||
.originalFilename("unbekannt.pdf")
|
||||
@@ -179,7 +169,6 @@ public class DataInitializer {
|
||||
.receivers(Set.of(maria))
|
||||
.build());
|
||||
|
||||
// 5. Document with minimal metadata — tests sparse display
|
||||
docRepo.save(Document.builder()
|
||||
.title("Scan ohne Titel")
|
||||
.originalFilename("scan_ohne_titel.pdf")
|
||||
|
||||
Reference in New Issue
Block a user