Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import org.karnak.backend.model.profilepipe.HMAC;
import org.karnak.backend.model.profilepipe.TagActionMap;
import org.karnak.backend.util.DateFormat;
import org.karnak.backend.util.ShiftApiDate;
import org.karnak.backend.util.ShiftByTagDate;
import org.karnak.backend.util.ShiftDate;
import org.karnak.backend.util.ShiftRangeDate;
Expand All @@ -48,15 +49,16 @@ public ActionDates(ProfileElementEntity profileElementEntity) throws ProfileExce
public void profileValidation() throws ProfileException {
if (option == null) {
throw new ProfileException("Cannot build the profile " + codeName
+ " : An option must be given. Option available: [shift, shift_range, shift_by_tag, date_format]");
+ " : An option must be given. Option available: [shift, shift_range, shift_by_tag, shift_from_api, date_format]");
}
switch (option) {
case "shift" -> ShiftDate.verifyShiftArguments(argumentEntities);
case "shift_range" -> ShiftRangeDate.verifyShiftArguments(argumentEntities);
case "shift_by_tag" -> ShiftByTagDate.verifyShiftArguments(argumentEntities);
case "shift_from_api" -> ShiftApiDate.verifyShiftArguments(argumentEntities);
case "date_format" -> DateFormat.verifyPatternArguments(argumentEntities);
default -> throw new ProfileException("Cannot build the profile " + codeName + " with the option given "
+ option + " : Option available (shift, shift_range, shift_by_tag, date_format)");
+ option + " : Option available (shift, shift_range, shift_by_tag, shift_from_api, date_format)");
}

validateCondition();
Expand Down Expand Up @@ -96,6 +98,7 @@ public void profileValidation() throws ProfileException {
case "shift" -> ShiftDate.shift(dcmCopy, tag, argumentEntities);
case "shift_range" -> ShiftRangeDate.shift(dcmCopy, tag, argumentEntities, hmac);
case "shift_by_tag" -> ShiftByTagDate.shift(dcmCopy, tag, argumentEntities, hmac);
case "shift_from_api" -> ShiftApiDate.shift(dcmCopy, tag, argumentEntities, hmac);
case "date_format" -> DateFormat.format(dcmCopy, tag, argumentEntities);
default -> null;
};
Expand Down
187 changes: 187 additions & 0 deletions src/main/java/org/karnak/backend/util/ShiftApiDate.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
/*
* Copyright (c) 2021-2026 Karnak Team and other contributors.
*
* This program and the accompanying materials are made available under the terms of the Eclipse
* Public License 2.0 which is available at https://www.eclipse.org/legal/epl-2.0, or the Apache
* License, Version 2.0 which is available at https://www.apache.org/licenses/LICENSE-2.0.
*
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
*/
package org.karnak.backend.util;

import static org.karnak.backend.service.EndpointService.evaluateStringWithExpression;
import static org.karnak.backend.service.EndpointService.validateStringWithExpression;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.time.DateTimeException;
import java.util.List;
import lombok.extern.slf4j.Slf4j;
import org.dcm4che3.data.Attributes;
import org.karnak.backend.data.entity.ArgumentEntity;
import org.karnak.backend.exception.AbortException;
import org.karnak.backend.exception.EndpointException;
import org.karnak.backend.model.profilepipe.HMAC;
import org.karnak.backend.service.ApplicationContextProvider;
import org.karnak.backend.service.EndpointService;
import org.springframework.web.client.HttpClientErrorException;
import org.weasis.dicom.param.AttributeEditorContext;

@Slf4j
public class ShiftApiDate {

private static EndpointService endpointService;

private ShiftApiDate() {
}

public static void verifyShiftArguments(List<ArgumentEntity> argumentEntities) throws IllegalArgumentException {

Check failure on line 39 in src/main/java/org/karnak/backend/util/ShiftApiDate.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Refactor this method to reduce its Cognitive Complexity from 25 to the 15 allowed.

See more on https://sonarcloud.io/project/issues?id=nroduit_karnak&issues=AZ9-srHbkNedhpF87oY6&open=AZ9-srHbkNedhpF87oY6&pullRequest=294
if (argumentEntities == null || argumentEntities.isEmpty()) {
throw new IllegalArgumentException(
"Cannot build the option ShiftApiDate: Missing argument, url and days_path are required");
}

boolean urlProvided = false;
boolean daysPathProvided = false;
boolean isPost = false;
boolean bodyProvided = false;

for (ArgumentEntity ae : argumentEntities) {
final String key = ae.getArgumentKey();
if ("url".equals(key)) {
urlProvided = true;
String error = validateStringWithExpression(ae.getArgumentValue());
if (error != null) {
throw new IllegalArgumentException(String.format("Expression is not valid: \n\r%s", error));

Check warning on line 56 in src/main/java/org/karnak/backend/util/ShiftApiDate.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

%n should be used in place of \n to produce the platform-specific line separator.

See more on https://sonarcloud.io/project/issues?id=nroduit_karnak&issues=AZ9-srHbkNedhpF87oY7&open=AZ9-srHbkNedhpF87oY7&pullRequest=294
}
}
else if ("days_path".equals(key)) {

Check failure on line 59 in src/main/java/org/karnak/backend/util/ShiftApiDate.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Define a constant instead of duplicating this literal "days_path" 3 times.

See more on https://sonarcloud.io/project/issues?id=nroduit_karnak&issues=AZ9-srHbkNedhpF87oY5&open=AZ9-srHbkNedhpF87oY5&pullRequest=294
daysPathProvided = true;
}
else if ("method".equals(key)) {
if (!ae.getArgumentValue().equalsIgnoreCase("post") && !ae.getArgumentValue().equalsIgnoreCase("get")) {
throw new IllegalArgumentException(
"Cannot build the option ShiftApiDate: method must be get or post");
}
if (ae.getArgumentValue().equalsIgnoreCase("post")) {
isPost = true;
}
}
else if ("body".equals(key)) {
bodyProvided = true;
String error = validateStringWithExpression(ae.getArgumentValue());
if (error != null) {
throw new IllegalArgumentException(String.format("Expression is not valid: \n\r%s", error));

Check warning on line 75 in src/main/java/org/karnak/backend/util/ShiftApiDate.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

%n should be used in place of \n to produce the platform-specific line separator.

See more on https://sonarcloud.io/project/issues?id=nroduit_karnak&issues=AZ9-srHbkNedhpF87oY8&open=AZ9-srHbkNedhpF87oY8&pullRequest=294
}
}
}

if (!urlProvided) {
throw new IllegalArgumentException("Cannot build the option ShiftApiDate: url argument is mandatory");
}
if (!daysPathProvided) {
throw new IllegalArgumentException("Cannot build the option ShiftApiDate: days_path argument is mandatory");
}
if (isPost && !bodyProvided) {
throw new IllegalArgumentException(
"Cannot build the option ShiftApiDate: body argument is mandatory for a POST request");
}
}

public static String shift(Attributes dcmCopy, int tag, List<ArgumentEntity> argumentEntities, HMAC hmac)

Check warning on line 92 in src/main/java/org/karnak/backend/util/ShiftApiDate.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Remove this unused method parameter "hmac".

See more on https://sonarcloud.io/project/issues?id=nroduit_karnak&issues=AZ9-srHbkNedhpF87oY9&open=AZ9-srHbkNedhpF87oY9&pullRequest=294
throws DateTimeException {
verifyShiftArguments(argumentEntities);

String url = null;
String daysPath = null;
String secondsPath = null;
String method = "get";
String body = null;
String authConfig = null;

for (ArgumentEntity ae : argumentEntities) {
switch (ae.getArgumentKey()) {
case "url" -> url = ae.getArgumentValue();
case "days_path" -> daysPath = normalizeJsonPath(ae.getArgumentValue());
case "seconds_path" -> secondsPath = normalizeJsonPath(ae.getArgumentValue());
case "method" -> method = ae.getArgumentValue();
case "body" -> body = ae.getArgumentValue();
case "authConfig" -> authConfig = ae.getArgumentValue();
default -> {

Check warning on line 111 in src/main/java/org/karnak/backend/util/ShiftApiDate.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Remove this block of code, fill it in, or add a comment explaining why it is empty.

See more on https://sonarcloud.io/project/issues?id=nroduit_karnak&issues=AZ9-srHbkNedhpF87oY-&open=AZ9-srHbkNedhpF87oY-&pullRequest=294
}
}
}

url = evaluateStringWithExpression(url, dcmCopy);
if (body != null) {
body = evaluateStringWithExpression(body, dcmCopy);
}

String response = fetchResponse(authConfig, url, method, body);
int shiftDays = parseShiftValue(response, daysPath, "days_path");
int shiftSeconds = 0;
if (secondsPath != null) {
shiftSeconds = parseShiftValue(response, secondsPath, "seconds_path");
}

String dcmElValue = dcmCopy.getString(tag);
return ShiftDate.shiftValue(dcmCopy, tag, dcmElValue, shiftDays, shiftSeconds);
}

private static String normalizeJsonPath(String path) {
if (path != null && !path.startsWith("/")) {
return "/" + path;
}
return path;
}

private static String fetchResponse(String authConfig, String url, String method, String body) {
if (endpointService == null) {
endpointService = ApplicationContextProvider.bean(EndpointService.class);
}

try {
if (method.equalsIgnoreCase("post")) {
return endpointService.post(authConfig, url, body);
}
if (method.equalsIgnoreCase("get")) {
return endpointService.get(authConfig, url);
}
throw new EndpointException("Unsupported HTTP Method : " + method);
}
catch (IllegalArgumentException e) {
throw new EndpointException(e.getMessage());
}
catch (HttpClientErrorException e) {
throw new EndpointException("HTTP Client Error : " + e.getStatusText() + " - " + url);
}
}

private static int parseShiftValue(String response, String jsonPath, String argumentName) {
try {
ObjectMapper objectMapper = new ObjectMapper();
JsonNode node = objectMapper.readTree(response).at(jsonPath);
if (node == null || node.isMissingNode() || node.isNull()) {
throw new AbortException(AttributeEditorContext.Abort.CONNECTION_EXCEPTION,
"Transfer aborted, shift value not found in response - " + argumentName + " (" + jsonPath
+ ")");
}
String textValue = node.isNumber() ? String.valueOf(node.intValue()) : node.asText();
if (textValue == null || textValue.isEmpty()) {
throw new AbortException(AttributeEditorContext.Abort.CONNECTION_EXCEPTION,
"Transfer aborted, shift value not found in response - " + argumentName + " (" + jsonPath
+ ")");
}
return Integer.parseInt(textValue);
}
catch (JsonProcessingException e) {
throw new EndpointException("An error occurred while parsing the JSON response ", e);
}
catch (NumberFormatException e) {

Check warning on line 181 in src/main/java/org/karnak/backend/util/ShiftApiDate.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Replace "e" with an unnamed pattern.

See more on https://sonarcloud.io/project/issues?id=nroduit_karnak&issues=AZ9-srHbkNedhpF87oY_&open=AZ9-srHbkNedhpF87oY_&pullRequest=294
throw new AbortException(AttributeEditorContext.Abort.CONNECTION_EXCEPTION,
"Transfer aborted, shift value is not a valid integer - " + argumentName + " (" + jsonPath + ")");
}
}

}
Loading