Skip to content

Commit

Permalink
Merge pull request #119 from it-at-m/feat/dms-metadata-subject
Browse files Browse the repository at this point in the history
feat/dms-metadata-subject
  • Loading branch information
simonhir authored Feb 24, 2025
2 parents 174c425 + 90ed0e7 commit f128526
Show file tree
Hide file tree
Showing 11 changed files with 104 additions and 28 deletions.
12 changes: 12 additions & 0 deletions dms-service/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ swim:
filename-to-coo: # for coo-source filename_map
filename-overwrite-pattern: # overwrite ContentObject name via Regex pattern
incoming-name-pattern: # overwrite Incoming name via Regex pattern, only applies to type incoming_object
metadata-subject: # enables incoming subject be built from metadata file
verify-procedure-name-pattern: # verifies target procedure name matches this pattern, only applies to type incoming_object
```
Expand Down Expand Up @@ -110,6 +111,9 @@ The metadata file needs to have the following syntax.
A valid metadata file either has personal `PPK_` or group `GPK_` inbox values defined (empty values are ignored).
If a metadata file is required but missing or is invalid (syntax, value combination, ...) an Exception is thrown, which is handled by the [error-handling](#error-handling).
Beside the usage of the metadata file as coo source (`coo-source: metadata_file`), values starting with `PdE_` (default) could be set as subject (see [Configuration](#configuration) `metadata-subject: true`).
The below example would lead to a subject `ExampleKey1: Example Value 1\nExampleKey2: Example Value 2`.
```json
{
"Document": {
Expand All @@ -129,6 +133,14 @@ If a metadata file is required but missing or is invalid (syntax, value combinat
{
"Name": "GPK_Username",
"Value": ""
},
{
"Name": "PdE_ExampleKey1",
"Value": "Example Value 1"
},
{
"Name": "PdE_ExampleKey2",
"Value": "Example Value 2"
}
]
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package de.muenchen.oss.swim.dms.adapter.out.dms;

import de.muenchen.oss.swim.dms.application.port.out.DmsOutPort;
import de.muenchen.oss.swim.dms.domain.exception.DmsException;
import de.muenchen.oss.swim.dms.domain.model.DmsTarget;
import de.muenchen.refarch.integration.dms.api.ContentObjectsApi;
import de.muenchen.refarch.integration.dms.api.IncomingsApi;
import de.muenchen.refarch.integration.dms.api.ObjectAndImportToInboxApi;
Expand All @@ -10,9 +13,6 @@
import de.muenchen.refarch.integration.dms.model.CreateIncomingAntwortDTO;
import de.muenchen.refarch.integration.dms.model.CreateIncomingBasisAnfrageDTO;
import de.muenchen.refarch.integration.dms.model.CreateObjectAndImportToInboxDTO;
import de.muenchen.oss.swim.dms.application.port.out.DmsOutPort;
import de.muenchen.oss.swim.dms.domain.exception.DmsException;
import de.muenchen.oss.swim.dms.domain.model.DmsTarget;
import de.muenchen.refarch.integration.dms.model.Objektreferenz;
import de.muenchen.refarch.integration.dms.model.ReadProcedureObjectsAntwortDTO;
import de.muenchen.refarch.integration.dms.model.ReadProcedureResponseDTO;
Expand Down Expand Up @@ -59,12 +59,13 @@ public void createContentObjectInInbox(final DmsTarget dmsTarget, final String c
}

@Override
public String createIncoming(final DmsTarget dmsTarget, final String incomingName, final String contentObjectName, final InputStream inputStream) {
public String createIncoming(final DmsTarget dmsTarget, final String incomingName, final String incomingSubject, final String contentObjectName,
final InputStream inputStream) {
log.debug("Putting file {} in procedure {}", contentObjectName, dmsTarget);
final CreateIncomingBasisAnfrageDTO request = new CreateIncomingBasisAnfrageDTO();
request.referrednumber(dmsTarget.coo());
request.shortname(incomingName);
request.filesubj(incomingName);
request.filesubj(incomingSubject);
request.useou(true);
try {
final AbstractResource file = new NamedInputStreamResource(contentObjectName, inputStream);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,12 @@ public interface DmsOutPort {
* @param dmsTarget The target. If {@link DmsTarget#coo()} is defined: Procedure, if not: OU work
* queue.
* @param incomingName The name of the new Incoming.
* @param incomingSubject The subject of the new Incoming.
* @param contentObjectName The name of the ContentObject inside the Incoming.
* @param inputStream The content of the new ContentObject.
* @return The coo of the new Incoming.
*/
String createIncoming(@NotNull @Valid DmsTarget dmsTarget, @NotBlank String incomingName, @NotBlank String contentObjectName,
String createIncoming(@NotNull @Valid DmsTarget dmsTarget, @NotBlank String incomingName, String incomingSubject, @NotBlank String contentObjectName,
@NotNull InputStream inputStream);

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import java.util.Map;
import java.util.Optional;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.util.Strings;
Expand Down Expand Up @@ -108,6 +109,13 @@ protected void processIncoming(final File file, final UseCase useCase, final Dms
// else apply pattern to original filename
incomingName = this.patternHelper.applyPattern(useCase.getIncomingNamePattern(), file.getFileName(), metadataJson);
}
// resolve subject for Incoming;
final String incomingSubject;
if (useCase.isMetadataSubject()) {
incomingSubject = this.subjectFromMetadata(metadataJson);
} else {
incomingSubject = incomingName;
}
// check if incoming already exists
if (useCase.isReuseIncoming()) {
final Optional<String> incomingCoo = this.dmsOutPort.getIncomingCooByName(dmsTarget, incomingName);
Expand All @@ -119,7 +127,7 @@ protected void processIncoming(final File file, final UseCase useCase, final Dms
}
}
// create Incoming
dmsOutPort.createIncoming(dmsTarget, incomingName, contentObjectName, fileStream);
dmsOutPort.createIncoming(dmsTarget, incomingName, incomingSubject, contentObjectName, fileStream);
}

/**
Expand Down Expand Up @@ -172,4 +180,30 @@ protected DmsTarget resolveMetadataTargetCoo(final JsonNode metadataJson, final
// combine with use case joboe and jobposition
return new DmsTarget(metadataTarget.coo(), metadataTarget.userName(), useCase.getJoboe(), useCase.getJobposition());
}

/**
* Build subject from metadata file.
*
* @param metadataJson Parsed JsonNode of metadata file.
* @return Constructed subject.
*/
protected String subjectFromMetadata(final JsonNode metadataJson) throws MetadataException {
// validate metadata json provided
if (metadataJson == null) {
throw new MetadataException("Metadata JSON is required");
}
// map index fields with prefix to subject
final Map<String, String> indexFields = this.dmsMetadataHelper.getIndexFields(metadataJson);
return indexFields.entrySet().stream()
// filter for prefix
.filter(i -> i.getKey().startsWith(swimDmsProperties.getMetadataSubjectPrefix()))
// sort
.sorted(Map.Entry.comparingByKey())
// build subject string
.map(i -> String.format(
"%s: %s",
i.getKey().replaceFirst("^" + swimDmsProperties.getMetadataSubjectPrefix(), ""),
i.getValue()))
.collect(Collectors.joining("\n"));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@ public class SwimDmsProperties {
*/
@NotBlank
private String metadataGroupInboxUserKey;
/**
* Prefix of metadata index fields which should be put into subject.
* See {@link UseCase#isMetadataSubject()}.
*/
@NotBlank
private String metadataSubjectPrefix;

/**
* Resolve use case via name.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,11 @@ public class UseCase {
* Only applies to {@link Type#INCOMING_OBJECT}
*/
private boolean reuseIncoming = false;
/**
* Fill subject with metadata. See {@link de.muenchen.oss.swim.dms.configuration.SwimDmsProperties}.
* Currently only works for {@link Type#INCOMING_OBJECT}.
*/
private boolean metadataSubject = false;
/**
* Username used for accessing dms.
* Used except {@link UseCase.CooSource#METADATA_FILE}
Expand Down
4 changes: 0 additions & 4 deletions dms-service/src/main/resources/application-local.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,3 @@ swim:
- name: test-meta
type: inbox
coo-source: metadata_file
metadata-user-inbox-coo-key: "PPK_COO"
metadata-user-inbox-user-key: "PPK_Username"
metadata-group-inbox-coo-key: "GPK_COO"
metadata-group-inbox-user-key: "GPK_Username"
9 changes: 8 additions & 1 deletion dms-service/src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -81,4 +81,11 @@ info:
description: @project.description@
build:
java.version: @java.version@
spring-cloud.version: @spring-cloud-dependencies.version@
spring-cloud.version: @spring-cloud-dependencies.version@

swim:
metadata-user-inbox-coo-key: "PPK_COO"
metadata-user-inbox-user-key: "PPK_Username"
metadata-group-inbox-coo-key: "GPK_COO"
metadata-group-inbox-user-key: "GPK_Username"
metadata-subject-prefix: "FdE_"
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
Expand Down Expand Up @@ -100,10 +99,14 @@ void testProcessFile_MetadataInbox() throws UnknownUseCaseException, PresignedUr
void testProcessFile_StaticIncoming() throws UnknownUseCaseException, PresignedUrlException, MetadataException {
final String useCaseName = "static-incoming";
final String overwrittenContentObjectName = "test-asd.pdf";
// setup
when(fileSystemOutPort.getPresignedUrlFile(eq(METADATA_PRESIGNED_URL)))
.thenReturn(getClass().getResourceAsStream("/files/example-metadata-subject.json"));
// call
processFileUseCase.processFile(buildFileEvent(useCaseName, null), FILE);
processFileUseCase.processFile(buildFileEvent(useCaseName, METADATA_PRESIGNED_URL), FILE);
// test
testDefaults(useCaseName, STATIC_DMS_TARGET, OVERWRITTEN_INCOMING_NAME, overwrittenContentObjectName);
final String incomingSubject = "TestKey_1: Test_Value_1\nTestKey_2: Test_Value_2";
testDefaults(useCaseName, STATIC_DMS_TARGET, OVERWRITTEN_INCOMING_NAME, incomingSubject, overwrittenContentObjectName);
verify(dmsOutPort, times(0)).getProcedureName(any());
verify(dmsOutPort, times(0)).getIncomingCooByName(any(), any());
}
Expand All @@ -114,7 +117,7 @@ void testProcessFile_FilenameIncoming() throws UnknownUseCaseException, Presigne
// call
processFileUseCase.processFile(buildFileEvent(useCaseName, null), FILE);
// test
testDefaults(useCaseName, FILENAME_DMS_TARGET, FILE_NAME, FILE_NAME);
testDefaults(useCaseName, FILENAME_DMS_TARGET, FILE_NAME, FILE_NAME, FILE_NAME);
}

@Test
Expand All @@ -123,7 +126,7 @@ void testProcessFile_FilenameMapIncoming() throws UnknownUseCaseException, Presi
// call
processFileUseCase.processFile(buildFileEvent(useCaseName, null), FILE);
// test
testDefaults(useCaseName, FILENAME_DMS_TARGET, FILE_NAME, FILE_NAME);
testDefaults(useCaseName, FILENAME_DMS_TARGET, FILE_NAME, FILE_NAME, FILE_NAME);
// call catch all
final String fileName = "asd.pdf";
final String filePath = "test/asd.pdf";
Expand All @@ -133,7 +136,7 @@ void testProcessFile_FilenameMapIncoming() throws UnknownUseCaseException, Presi
processFileUseCase.processFile(new FileEvent(useCaseName, presignedUrl, null), file);
final DmsTarget dmsTarget = new DmsTarget("COO.321.321.321", useCase.getUsername(), useCase.getJoboe(), useCase.getJobposition());
// test catche all
verify(dmsOutPort, times(1)).createIncoming(eq(dmsTarget), eq(fileName), eq(fileName), eq(null));
verify(dmsOutPort, times(1)).createIncoming(eq(dmsTarget), eq(fileName), eq(fileName), eq(fileName), eq(null));
}

@Test
Expand All @@ -144,7 +147,7 @@ void testProcessFile_verifyProcedureName() throws PresignedUrlException, Unknown
// call
processFileUseCase.processFile(buildFileEvent(useCaseName, null), FILE);
// test
testDefaults(useCaseName, FILENAME_DMS_TARGET, FILE_NAME, FILE_NAME);
testDefaults(useCaseName, FILENAME_DMS_TARGET, FILE_NAME, FILE_NAME, FILE_NAME);
verify(dmsOutPort, times(1)).getProcedureName(eq(FILENAME_DMS_TARGET));
// setup failure
when(dmsOutPort.getProcedureName(eq(FILENAME_DMS_TARGET))).thenReturn("asd");
Expand All @@ -161,29 +164,29 @@ void testProcessFile_reuseIncoming() throws UnknownUseCaseException, PresignedUr
// call
processFileUseCase.processFile(buildFileEvent(useCaseName, null), FILE);
// test
testDefaults(useCaseName, FILENAME_DMS_TARGET, OVERWRITTEN_INCOMING_NAME, FILE_NAME);
testDefaults(useCaseName, FILENAME_DMS_TARGET, OVERWRITTEN_INCOMING_NAME, OVERWRITTEN_INCOMING_NAME, FILE_NAME);
verify(dmsOutPort, times(1)).getIncomingCooByName(eq(FILENAME_DMS_TARGET), eq(OVERWRITTEN_INCOMING_NAME));
// setup reuse
when(dmsOutPort.getIncomingCooByName(eq(FILENAME_DMS_TARGET), eq(OVERWRITTEN_INCOMING_NAME))).thenReturn(Optional.of("COO.321.321.321"));
// call
processFileUseCase.processFile(buildFileEvent(useCaseName, null), FILE);
// test
verify(dmsOutPort, times(2)).getIncomingCooByName(eq(FILENAME_DMS_TARGET), eq(OVERWRITTEN_INCOMING_NAME));
verify(dmsOutPort, times(1)).createIncoming(any(), any(), any(), any());
verify(dmsOutPort, times(1)).createIncoming(any(), any(), any(), any(), any());
final UseCase useCase = swimDmsProperties.findUseCase(useCaseName);
final DmsTarget dmsTarget = new DmsTarget("COO.321.321.321", useCase.getUsername(), useCase.getJoboe(), useCase.getJobposition());
verify(dmsOutPort, times(1)).createContentObject(eq(dmsTarget), eq(FILE_NAME), eq(null));
}

private void testDefaults(final String useCaseName, final DmsTarget dmsTarget, final String fileName,
private void testDefaults(final String useCaseName, final DmsTarget dmsTarget, final String incomingName, final String incomingSubject,
final String contentObjectName)
throws UnknownUseCaseException, MetadataException {
final UseCase useCase = swimDmsProperties.findUseCase(useCaseName);
verify(swimDmsProperties, times(2)).findUseCase(eq(useCaseName));
verify(processFileUseCase, times(1)).resolveTargetCoo(isNull(), eq(useCase), eq(FILE));
verify(processFileUseCase, times(1)).resolveTargetCoo(any(), eq(useCase), eq(FILE));
verify(dmsMetadataHelper, times(0)).resolveInboxDmsTarget(any());
verify(dmsOutPort, times(0)).createContentObjectInInbox(any(), any(), any());
verify(dmsOutPort, times(1)).createIncoming(eq(dmsTarget), eq(fileName), eq(contentObjectName), eq(null));
verify(dmsOutPort, times(1)).createIncoming(eq(dmsTarget), eq(incomingName), eq(incomingSubject), eq(contentObjectName), eq(null));
}

private FileEvent buildFileEvent(final String useCaseName, final String metadataPresignedUrl) {
Expand Down
5 changes: 1 addition & 4 deletions dms-service/src/test/resources/application-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ swim:
target-coo: staticCoo
filename-overwrite-pattern: "s/^(.+)(?:-COO.[^-]+-)(.+)$/\\${1}-\\${2}/"
incoming-name-pattern: "s/^(.+)(?:-COO.[^-]+-).+$/\\${1}/"
metadata-subject: true
username: staticUsername
joboe: staticJobOe
jobposition: staticJobPosition
Expand Down Expand Up @@ -45,7 +46,3 @@ swim:
username: staticUsername
joboe: staticJobOe
jobposition: staticJobPosition
metadata-user-inbox-coo-key: "PPK_COO"
metadata-user-inbox-user-key: "PPK_Username"
metadata-group-inbox-coo-key: "GPK_COO"
metadata-group-inbox-user-key: "GPK_Username"
14 changes: 14 additions & 0 deletions dms-service/src/test/resources/files/example-metadata-subject.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"Document": {
"IndexFields": [
{
"Name": "FdE_TestKey_1",
"Value": "Test_Value_1"
},
{
"Name": "FdE_TestKey_2",
"Value": "Test_Value_2"
}
]
}
}

0 comments on commit f128526

Please sign in to comment.