Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OH2-418 | Orthanc Integration #1466

Draft
wants to merge 11 commits into
base: develop
Choose a base branch
from
4 changes: 4 additions & 0 deletions sql/load_demo_data.sql
Original file line number Diff line number Diff line change
Expand Up @@ -1912,6 +1912,8 @@ INSERT INTO `oh_grouppermission` (`GP_ID`, `GP_UG_ID_A`, `GP_P_ID_A`, `GP_ACTIVE
INSERT INTO `oh_grouppermission` (`GP_ID`, `GP_UG_ID_A`, `GP_P_ID_A`, `GP_ACTIVE`, `GP_CREATED_BY`, `GP_CREATED_DATE`, `GP_LAST_MODIFIED_BY`, `GP_LAST_MODIFIED_DATE`) VALUES (315,'admin',170,'1',NULL,NULL,NULL,NULL);
INSERT INTO `oh_grouppermission` (`GP_ID`, `GP_UG_ID_A`, `GP_P_ID_A`, `GP_ACTIVE`, `GP_CREATED_BY`, `GP_CREATED_DATE`, `GP_LAST_MODIFIED_BY`, `GP_LAST_MODIFIED_DATE`) VALUES (316,'admin',171,'1',NULL,NULL,NULL,NULL);
INSERT INTO `oh_grouppermission` (`GP_ID`, `GP_UG_ID_A`, `GP_P_ID_A`, `GP_ACTIVE`, `GP_CREATED_BY`, `GP_CREATED_DATE`, `GP_LAST_MODIFIED_BY`, `GP_LAST_MODIFIED_DATE`) VALUES (317,'laboratorist',96,'1',NULL,NULL,NULL,NULL);
INSERT INTO `oh_grouppermission` (`GP_ID`, `GP_UG_ID_A`, `GP_P_ID_A`, `GP_ACTIVE`, `GP_CREATED_BY`, `GP_CREATED_DATE`, `GP_LAST_MODIFIED_BY`, `GP_LAST_MODIFIED_DATE`) VALUES (318,'admin',172,'1',NULL,NULL,NULL,NULL);
INSERT INTO `oh_grouppermission` (`GP_ID`, `GP_UG_ID_A`, `GP_P_ID_A`, `GP_ACTIVE`, `GP_CREATED_BY`, `GP_CREATED_DATE`, `GP_LAST_MODIFIED_BY`, `GP_LAST_MODIFIED_DATE`) VALUES (319,'admin',173,'1',NULL,NULL,NULL,NULL);
/*!40000 ALTER TABLE `oh_grouppermission` ENABLE KEYS */;
UNLOCK TABLES;

Expand Down Expand Up @@ -5040,6 +5042,8 @@ INSERT INTO `oh_permissions` (`P_ID_A`, `P_NAME`, `P_DESCRIPTION`, `P_ACTIVE`, `
INSERT INTO `oh_permissions` (`P_ID_A`, `P_NAME`, `P_DESCRIPTION`, `P_ACTIVE`, `P_CREATED_BY`, `P_CREATED_DATE`, `P_LAST_MODIFIED_BY`, `P_LAST_MODIFIED_DATE`) VALUES (169,'usergroups.read','','1',NULL,NULL,NULL,NULL);
INSERT INTO `oh_permissions` (`P_ID_A`, `P_NAME`, `P_DESCRIPTION`, `P_ACTIVE`, `P_CREATED_BY`, `P_CREATED_DATE`, `P_LAST_MODIFIED_BY`, `P_LAST_MODIFIED_DATE`) VALUES (170,'usergroups.update','','1',NULL,NULL,NULL,NULL);
INSERT INTO `oh_permissions` (`P_ID_A`, `P_NAME`, `P_DESCRIPTION`, `P_ACTIVE`, `P_CREATED_BY`, `P_CREATED_DATE`, `P_LAST_MODIFIED_BY`, `P_LAST_MODIFIED_DATE`) VALUES (171,'usergroups.delete','','1',NULL,NULL,NULL,NULL);
INSERT INTO `oh_permissions` (`P_ID_A`, `P_NAME`, `P_DESCRIPTION`, `P_ACTIVE`, `P_CREATED_BY`, `P_CREATED_DATE`, `P_LAST_MODIFIED_BY`, `P_LAST_MODIFIED_DATE`) VALUES (172,'radiology.access','','1',NULL,NULL,NULL,NULL);
INSERT INTO `oh_permissions` (`P_ID_A`, `P_NAME`, `P_DESCRIPTION`, `P_ACTIVE`, `P_CREATED_BY`, `P_CREATED_DATE`, `P_LAST_MODIFIED_BY`, `P_LAST_MODIFIED_DATE`) VALUES (173,'radiology.read','','1',NULL,NULL,NULL,NULL);
/*!40000 ALTER TABLE `oh_permissions` ENABLE KEYS */;
UNLOCK TABLES;

Expand Down
1 change: 1 addition & 0 deletions sql/step_04_all_following_steps.sql
Original file line number Diff line number Diff line change
Expand Up @@ -108,3 +108,4 @@ source step_a111_add_missing_lock_columns.sql;
source step_a112_users_and_groups_soft_deletion.sql;
source step_a113_alter_table_medicalinventory.sql;
source step_a114_medical_type_soft_deletion.sql;
source step_a115_add_radiology_permissions.sql;
5 changes: 5 additions & 0 deletions sql/step_a115_add_radiology_permissions.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
INSERT INTO `oh_permissions` (`P_ID_A`, `P_NAME`, `P_DESCRIPTION`, `P_ACTIVE`, `P_CREATED_BY`, `P_CREATED_DATE`, `P_LAST_MODIFIED_BY`, `P_LAST_MODIFIED_DATE`) VALUES (172,'radiology.access','','1',NULL,NULL,NULL,NULL);
INSERT INTO `oh_permissions` (`P_ID_A`, `P_NAME`, `P_DESCRIPTION`, `P_ACTIVE`, `P_CREATED_BY`, `P_CREATED_DATE`, `P_LAST_MODIFIED_BY`, `P_LAST_MODIFIED_DATE`) VALUES (173,'radiology.read','','1',NULL,NULL,NULL,NULL);

INSERT INTO `oh_grouppermission` (`GP_ID`, `GP_UG_ID_A`, `GP_P_ID_A`, `GP_ACTIVE`, `GP_CREATED_BY`, `GP_CREATED_DATE`, `GP_LAST_MODIFIED_BY`, `GP_LAST_MODIFIED_DATE`) VALUES (318,'admin',172,'1',NULL,NULL,NULL,NULL);
INSERT INTO `oh_grouppermission` (`GP_ID`, `GP_UG_ID_A`, `GP_P_ID_A`, `GP_ACTIVE`, `GP_CREATED_BY`, `GP_CREATED_DATE`, `GP_LAST_MODIFIED_BY`, `GP_LAST_MODIFIED_DATE`) VALUES (319,'admin',173,'1',NULL,NULL,NULL,NULL);
75 changes: 75 additions & 0 deletions src/main/java/org/isf/generaldata/OrthancConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
* Open Hospital (www.open-hospital.org)
* Copyright © 2006-2024 Informatici Senza Frontiere ([email protected])
*
* Open Hospital is a free and open source software for healthcare data management.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* https://www.gnu.org/licenses/gpl-3.0-standalone.html
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.isf.generaldata;

/**
* @author Silevester D.
* @since 1.15
*/
public final class OrthancConfig extends ConfigurationProperties {

private static final String FILE_PROPERTIES = "orthanc.properties";

/**
* Enable ORTHANC integration
*/
public static boolean ORTHANC_ENABLED;

/**
* Base URL of the ORTHANC server
*/
public static String ORTHANC_BASE_URL;

/**
* Name of the user to use for ORTHANC APIs calls
*/
public static String ORTHANC_USERNAME;

/**
* Password of the user to use for ORTHANC APIs calls
*/
public static String ORTHANC_PASSWORD;

/**
* Full URL of the ORTHANC explorer
*/
public static String ORTHANC_EXPLORER_URL;

private static final boolean DEFAULT_ORTHANC_ENABLED = false;
private static final String DEFAULT_ORTHANC_BASE_URL = "";
private static final String DEFAULT_ORTHANC_USERNAME = "admin";
private static final String DEFAULT_ORTHANC_PASSWORD = "adminADMIN!123#";
private static final String DEFAULT_ORTHANC_EXPLORER_URL = "";

private OrthancConfig(String fileProperties) {
super(fileProperties);
ORTHANC_ENABLED = myGetProperty("orthanc.enabled", DEFAULT_ORTHANC_ENABLED);
ORTHANC_BASE_URL = myGetProperty("orthanc.base-url", DEFAULT_ORTHANC_BASE_URL);
ORTHANC_USERNAME = myGetProperty("orthanc.username", DEFAULT_ORTHANC_USERNAME);
ORTHANC_PASSWORD = myGetProperty("orthanc.password", DEFAULT_ORTHANC_PASSWORD);
ORTHANC_EXPLORER_URL = myGetProperty("orthanc.explorer-url", DEFAULT_ORTHANC_EXPLORER_URL);
}

public static void initialize() {
new OrthancConfig(FILE_PROPERTIES);
}
}
74 changes: 74 additions & 0 deletions src/main/java/org/isf/orthanc/client/OrthancAPIClient.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
* Open Hospital (www.open-hospital.org)
* Copyright © 2006-2024 Informatici Senza Frontiere ([email protected])
*
* Open Hospital is a free and open source software for healthcare data management.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* https://www.gnu.org/licenses/gpl-3.0-standalone.html
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.isf.orthanc.client;

import java.util.List;

import org.isf.orthanc.model.FindRequest;
import org.isf.orthanc.model.InstanceResponse;
import org.isf.orthanc.model.SeriesResponse;
import org.isf.orthanc.model.StudyResponse;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;

import feign.Response;

/**
* @author Silevester D.
* @since 1.15
*/
@FeignClient(name = "orthanc-rest-api-client")
public interface OrthancAPIClient {
@GetMapping(value = "/tools/now", produces = MediaType.TEXT_PLAIN_VALUE)
String testConnection();

@GetMapping(value = "/studies?expand=true", produces = MediaType.APPLICATION_JSON_VALUE)
List<StudyResponse> getAllStudies();

@PostMapping(value = "/tools/find", produces = MediaType.APPLICATION_JSON_VALUE)
List<StudyResponse> getPatientStudiesById(@RequestBody FindRequest request);

@GetMapping(value = "/patients/{id}/studies", produces = MediaType.APPLICATION_JSON_VALUE)
List<StudyResponse> getPatientStudiesByUuid(@PathVariable("id") String patientUuid);

@GetMapping(value = "/studies/{id}", produces = MediaType.APPLICATION_JSON_VALUE)
StudyResponse getStudyById(@PathVariable("id") String id);

@GetMapping(value = "/studies/{id}/series", produces = MediaType.APPLICATION_JSON_VALUE)
List<SeriesResponse> getStudySeries(@PathVariable("id") String id);

@GetMapping(value = "/series/{id}", produces = MediaType.APPLICATION_JSON_VALUE)
SeriesResponse getSeriesById(@PathVariable("id") String id);

@GetMapping(value = "/series/{id}/instances", produces = MediaType.APPLICATION_JSON_VALUE)
List<InstanceResponse> getSeriesInstances(@PathVariable("id") String id);

@GetMapping(value = "/instances/{id}", produces = MediaType.APPLICATION_JSON_VALUE)
InstanceResponse getInstanceById(@PathVariable("id") String id);

@GetMapping(value = "/instances/{id}/preview", produces = MediaType.IMAGE_PNG_VALUE)
Response getInstancePreview(@PathVariable("id") String id);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/*
* Open Hospital (www.open-hospital.org)
* Copyright © 2006-2024 Informatici Senza Frontiere ([email protected])
*
* Open Hospital is a free and open source software for healthcare data management.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* https://www.gnu.org/licenses/gpl-3.0-standalone.html
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.isf.orthanc.client;

import org.isf.generaldata.OrthancConfig;
import org.isf.orthanc.utils.CustomErrorDecoder;
import org.isf.utils.exception.OHServiceException;
import org.isf.utils.exception.model.OHExceptionMessage;
import org.springframework.cloud.openfeign.support.SpringMvcContract;
import org.springframework.stereotype.Component;

import feign.Feign;
import feign.Logger;
import feign.auth.BasicAuthRequestInterceptor;
import feign.gson.GsonDecoder;
import feign.gson.GsonEncoder;
import feign.slf4j.Slf4jLogger;

/**
* @author Silevester D.
* @since 1.15
*/
@Component
public class OrthancFeignClientFactory {

private OrthancAPIClient client;

public OrthancFeignClientFactory() {
OrthancConfig.initialize();
}

/**
* Create a client to perform request
*
* @return an instance of {@link OrthancAPIClient}
* @throws OHServiceException When ORTHANC not properly configured
*/
public OrthancAPIClient createClient(boolean reset) throws OHServiceException {
if (!validateConfiguration()) {
throw new OHServiceException(new OHExceptionMessage("ORTHANC server is not properly configured"));
}

if (client != null && !reset) return client;

client = Feign.builder()
.encoder(new GsonEncoder())
.decoder(new GsonDecoder())
.requestInterceptor(new BasicAuthRequestInterceptor(OrthancConfig.ORTHANC_USERNAME, OrthancConfig.ORTHANC_PASSWORD))
.logger(new Slf4jLogger(OrthancAPIClient.class))
.errorDecoder(new CustomErrorDecoder())
.logLevel(Logger.Level.FULL)
.contract(new SpringMvcContract())
.target(OrthancAPIClient.class, OrthancConfig.ORTHANC_BASE_URL);

return client;
}

/**
* Validate ORTHANC configuration
* This method only ensures that necessary parameters have been set
*
* @return <code>true</code> if the configuration is valid, <code>false</code> otherwise
*/
public boolean validateConfiguration() {
return OrthancConfig.ORTHANC_BASE_URL != null
&& !OrthancConfig.ORTHANC_BASE_URL.isEmpty()
&& OrthancConfig.ORTHANC_USERNAME != null
&& !OrthancConfig.ORTHANC_USERNAME.isEmpty()
&& OrthancConfig.ORTHANC_PASSWORD != null
&& !OrthancConfig.ORTHANC_PASSWORD.isEmpty();
}
}
101 changes: 101 additions & 0 deletions src/main/java/org/isf/orthanc/model/BaseResponse.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/*
* Open Hospital (www.open-hospital.org)
* Copyright © 2006-2024 Informatici Senza Frontiere ([email protected])
*
* Open Hospital is a free and open source software for healthcare data management.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* https://www.gnu.org/licenses/gpl-3.0-standalone.html
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.isf.orthanc.model;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;

import com.google.gson.annotations.SerializedName;

/**
* @author Silevester D.
* @since 1.15
*/
public class BaseResponse {
@SerializedName("ID")
private String id;

@SerializedName("IsStable")
private Boolean isStable;

@SerializedName("Type")
private String objectType;

@SerializedName("Labels")
private List<String> labels;

@SerializedName("LastUpdate")
private String lastUpdate;

public String getId() {
return id;
}

public void setId(String id) {
this.id = id;
}

public Boolean getStable() {
return isStable;
}

public void setStable(Boolean stable) {
isStable = stable;
}

public String getObjectType() {
return objectType;
}

public void setObjectType(String objectType) {
this.objectType = objectType;
}

public List<String> getLabels() {
return labels;
}

public void setLabels(List<String> labels) {
this.labels = labels;
}

public String getLastUpdate() {
return lastUpdate;
}

public void setLastUpdate(String lastUpdate) {
this.lastUpdate = lastUpdate;
}

/**
* Parse last update date into LocalDateTime
*
* @return {@link LocalDateTime} instance
*/
public LocalDateTime lastUpdateToLocalDateTime() {
if (lastUpdate == null || lastUpdate.isEmpty()) {
return null;
}
return LocalDateTime.parse(lastUpdate, DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmss"));
}
}
Loading
Loading