feat(quick-upload): generate better title from structured filename
Some checks failed
CI / Unit & Component Tests (push) Has been cancelled
CI / Backend Unit Tests (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
CI / Unit & Component Tests (pull_request) Successful in 2m16s
CI / Backend Unit Tests (pull_request) Successful in 2m8s
CI / E2E Tests (pull_request) Failing after 26m22s

titleFromFilename() mirrors the same four patterns as the frontend
parseFilename() utility. Dropzone uploads to Mueller_Hans_19650312.pdf
now land with title "Hans Mueller (12.03.1965)" instead of the raw
stripped filename.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Marcel
2026-03-26 15:18:34 +01:00
parent 654e736f8a
commit a302f96560
2 changed files with 88 additions and 1 deletions

View File

@@ -65,7 +65,7 @@ public class DocumentService {
// New uploads from the drop zone always start as incomplete
document = Document.builder()
.originalFilename(originalFilename)
.title(stripExtension(originalFilename))
.title(titleFromFilename(originalFilename))
.status(DocumentStatus.UPLOADED)
.metadataComplete(false)
.build();
@@ -356,6 +356,57 @@ public class DocumentService {
return dot > 0 ? filename.substring(0, dot) : filename;
}
/**
* Derives a human-readable title from a structured filename.
* Supports patterns (full match only):
* YYYY-MM-DD_Lastname_Firstname.ext
* YYYYMMDD_Lastname_Firstname.ext
* Lastname_Firstname_YYYY-MM-DD.ext
* Lastname_Firstname_YYYYMMDD.ext
* Falls back to stripExtension for unrecognised names.
*/
private static final java.util.regex.Pattern FN_DATE_ISO_NAME =
java.util.regex.Pattern.compile("^(\\d{4}-\\d{2}-\\d{2})_(\\p{L}+)_(\\p{L}+)\\.[^.]+$");
private static final java.util.regex.Pattern FN_DATE_COMPACT_NAME =
java.util.regex.Pattern.compile("^(\\d{8})_(\\p{L}+)_(\\p{L}+)\\.[^.]+$");
private static final java.util.regex.Pattern FN_NAME_DATE_ISO =
java.util.regex.Pattern.compile("^(\\p{L}+)_(\\p{L}+)_(\\d{4}-\\d{2}-\\d{2})\\.[^.]+$");
private static final java.util.regex.Pattern FN_NAME_DATE_COMPACT =
java.util.regex.Pattern.compile("^(\\p{L}+)_(\\p{L}+)_(\\d{8})\\.[^.]+$");
static String titleFromFilename(String filename) {
if (filename == null) return null;
java.util.regex.Matcher m;
String dateIso, lastName, firstName;
if ((m = FN_DATE_ISO_NAME.matcher(filename)).matches()) {
dateIso = m.group(1);
lastName = m.group(2);
firstName = m.group(3);
} else if ((m = FN_DATE_COMPACT_NAME.matcher(filename)).matches()) {
String compact = m.group(1);
dateIso = compact.substring(0, 4) + "-" + compact.substring(4, 6) + "-" + compact.substring(6, 8);
lastName = m.group(2);
firstName = m.group(3);
} else if ((m = FN_NAME_DATE_ISO.matcher(filename)).matches()) {
lastName = m.group(1);
firstName = m.group(2);
dateIso = m.group(3);
} else if ((m = FN_NAME_DATE_COMPACT.matcher(filename)).matches()) {
lastName = m.group(1);
firstName = m.group(2);
String compact = m.group(3);
dateIso = compact.substring(0, 4) + "-" + compact.substring(4, 6) + "-" + compact.substring(6, 8);
} else {
return stripExtension(filename);
}
// Format date as DD.MM.YYYY for the title
LocalDate date = LocalDate.parse(dateIso);
String dateDisplay = String.format("%02d.%02d.%d", date.getDayOfMonth(), date.getMonthValue(), date.getYear());
return firstName + " " + lastName + " (" + dateDisplay + ")";
}
private static String sha256Hex(byte[] bytes) {
try {
MessageDigest digest = MessageDigest.getInstance("SHA-256");

View File

@@ -518,4 +518,40 @@ class DocumentServiceTest {
assertThat(count).isEqualTo(2);
}
// ─── titleFromFilename ────────────────────────────────────────────────────
@Test
void titleFromFilename_dateIso_name() {
assertThat(DocumentService.titleFromFilename("1965-03-12_Mueller_Hans.pdf"))
.isEqualTo("Hans Mueller (12.03.1965)");
}
@Test
void titleFromFilename_dateCompact_name() {
assertThat(DocumentService.titleFromFilename("19650312_Mueller_Hans.pdf"))
.isEqualTo("Hans Mueller (12.03.1965)");
}
@Test
void titleFromFilename_name_dateIso() {
assertThat(DocumentService.titleFromFilename("Mueller_Hans_1965-03-12.pdf"))
.isEqualTo("Hans Mueller (12.03.1965)");
}
@Test
void titleFromFilename_name_dateCompact() {
assertThat(DocumentService.titleFromFilename("Mueller_Hans_19650312.pdf"))
.isEqualTo("Hans Mueller (12.03.1965)");
}
@Test
void titleFromFilename_fallsBackToStripExtension() {
assertThat(DocumentService.titleFromFilename("scan_001.pdf")).isEqualTo("scan_001");
}
@Test
void titleFromFilename_null_returnsNull() {
assertThat(DocumentService.titleFromFilename(null)).isNull();
}
}