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
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,17 @@ To configure the location of the external service, use the following parameters.
| ELASTIC_SEARCH_HOST | Host and port of the elastic search endpoint | `192.168.1.1:9200` | `localhost:9200` |
| ELASTIC_SEARCH_FILTER | Which parameters can be used to filter results | `foo,bar,baz` | `context,terminology,kds_module` |

### Passthrough Variables

There are a few variables that are not used in the backend itself, but are forwarded to the frontend if requested.


| EnvVar | Description | Example | Default |
|-----------------------------|------------------------------------------------------------------|-------------------|-----------------------------------------------------------------------------------------------------------------|
| PT_CCDL_VERSION | The used version of the Clinical Cohort Definition Language | `` | `unknown` |
| PT_PORTAL_LINK | URL to the portal page | `https://foo.bar` | `https://antrag.forschen-fuer-gesundheit.de` |
| PT_DSE_PATIENT_PROFILE_URL | URL of the patient profile used in data selection and extraction | `foo,bar,baz` | `https://www.medizininformatik-initiative.de/fhir/core/modul-person/StructureDefinition/PatientPseudonymisiert` |

## Support for self-signed certificates

The dataportal backend supports the use of self-signed certificates from your own CAs.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ public class WebSecurityConfig {
public static final String PATH_CODEABLE_CONCEPT = "/codeable-concept";
public static final String PATH_SWAGGER_UI = "/swagger-ui/**";
public static final String PATH_SWAGGER_CONFIG = "/v3/api-docs/**";
public static final String PATH_SETTINGS = "/.settings";
@Value("${app.keycloakAllowedRole}")
private String keycloakAllowedRole;

Expand Down Expand Up @@ -97,6 +98,7 @@ public SecurityFilterChain apiFilterChain(
Converter<Jwt, ? extends AbstractAuthenticationToken> authenticationConverter) throws Exception {

http.authorizeHttpRequests(authorize -> authorize
.requestMatchers(PathPatternRequestMatcher.withDefaults().matcher(PATH_SETTINGS)).permitAll()
.requestMatchers(PathPatternRequestMatcher.withDefaults().matcher(PATH_SWAGGER_CONFIG)).permitAll()
.requestMatchers(PathPatternRequestMatcher.withDefaults().matcher(PATH_API + PATH_ACTUATOR_HEALTH)).permitAll()
.requestMatchers(PathPatternRequestMatcher.withDefaults().matcher(PATH_API + PATH_ACTUATOR_INFO)).permitAll()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package de.numcodex.feasibility_gui_backend.settings;

import java.util.Map;

import de.numcodex.feasibility_gui_backend.config.WebSecurityConfig;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@CrossOrigin(origins = "${cors.allowedOrigins}", exposedHeaders = "Location")
public class SettingsController {

private static final String KEY_DSE_URL = "dsePatientProfileUrl";
private static final String KEY_LOCATION_RESULT_LOWERBOUNDARY = "lowerboundarylocationresult";
private static final String KEY_PATIENT_RESULT_LOWERBOUNDARY = "lowerboundarypatientresult";
private static final String KEY_POLLING_INTERVAL = "pollingintervall";
private static final String KEY_POLLING_TIME = "pollingtime";
private static final String KEY_PORTAL_LINK = "proposalPortalLink";
private static final String KEY_CCDL_VERSION = "ccdlVersion";
private static final String KEY_REST_API_PATH = "uiBackendApiUrl";


@Value("${passthrough.dsePatientProfileUrl}")
private String dseUrl;

@Value("${app.privacy.threshold.sites}")
private int lowerboundaryLocationResult;

@Value("${app.privacy.threshold.results}")
private int lowerboundardyPatientResult;

@Value("${app.privacy.quota.read.resultDetailedObfuscated.interval}")
private String pollingInterval;

@Value("${app.privacy.quota.read.resultSummary.pollingInterval}")
private String pollingTime = "PT20S";

@Value("${passthrough.portalLink}")
private String portalLink;

@Value("${passthrough.ccdlVersion}")
private String ccdlVersion = "version";


@GetMapping("/.settings")
public Map<String, Object> getSettings() {
return Map.of(
KEY_DSE_URL, dseUrl,
KEY_LOCATION_RESULT_LOWERBOUNDARY, lowerboundaryLocationResult,
KEY_PATIENT_RESULT_LOWERBOUNDARY, lowerboundardyPatientResult,
KEY_POLLING_INTERVAL, pollingInterval,
KEY_POLLING_TIME, pollingTime,
KEY_PORTAL_LINK, portalLink,
KEY_CCDL_VERSION, ccdlVersion,
KEY_REST_API_PATH, WebSecurityConfig.PATH_API
);
}
}
5 changes: 4 additions & 1 deletion src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,10 @@ app:
pollingInterval: ${PRIVACY_QUOTA_READ_DETAILED_OBFUSCATED_POLLINGINTERVAL:PT10S}
amount: ${PRIVACY_QUOTA_READ_DETAILED_OBFUSCATED_AMOUNT:3}
interval: ${PRIVACY_QUOTA_READ_DETAILED_OBFUSCATED_INTERVAL:PT2H}

passthrough:
ccdlVersion: ${PT_CCDL_VERSION:unknown}
portalLink: ${PT_PORTAL_LINK:https://antrag.forschen-fuer-gesundheit.de}
dsePatientProfileUrl: ${PT_DSE_PATIENT_PROFILE_URL:https://www.medizininformatik-initiative.de/fhir/core/modul-person/StructureDefinition/PatientPseudonymisiert}
logging:
level:
org.hibernate: ${LOG_LEVEL_SQL:warn}
Expand Down
53 changes: 52 additions & 1 deletion src/main/resources/static/v3/api-docs/swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -869,13 +869,27 @@ paths:
operationId: ''
responses:
200:
description: Successful health information.
description: Successful build information.
content:
application/vnd.spring-boot.actuator.v3+json:
schema:
$ref: "#/components/schemas/SystemInfo"
tags:
- intrinsics
/.settings:
get:
summary: Offers config settings needed by the frontend.
description: ''
operationId: ''
responses:
200:
description: Successful health information.
content:
application/json:
schema:
$ref: "#/components/schemas/SettingsInfo"
tags:
- intrinsics
components:
schemas:
Dataquery:
Expand Down Expand Up @@ -1668,6 +1682,43 @@ components:
$ref: "#/components/schemas/BuildInfo"
terminology:
$ref: "#/components/schemas/Terminology"
SettingsInfo:
type: object
properties:
ccdlVersion:
type: string
examples:
- v1
pollingintervall:
type: string
format: duration
examples:
- PT10S
dsePatientProfileUrl:
type: string
examples:
- https://www.medizininformatik-initiative.de/fhir/core/modul-person/StructureDefinition/PatientPseudonymisiert
uiBackendApiUrl:
type: string
examples:
- /api/v5
lowerboundarypatientresult:
type: number
examples:
- 20
proposalPortalLink:
type: string
examples:
- https://antrag.forschen-fuer-gesundheit.de
lowerboundarylocationresult:
type: number
examples:
- 3
pollingtime:
type: string
format: duration
examples:
- PT10S
securitySchemes:
dataportal_auth:
type: oauth2
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package de.numcodex.feasibility_gui_backend.settings;

import de.numcodex.feasibility_gui_backend.query.ratelimiting.RateLimitingInterceptor;
import de.numcodex.feasibility_gui_backend.query.ratelimiting.RateLimitingServiceSpringConfig;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.context.annotation.Import;
import org.springframework.security.test.context.support.WithMockUser;
import org.springframework.test.context.bean.override.mockito.MockitoBean;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.web.servlet.MockMvc;

import java.net.URI;

import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@Tag("info")
@ExtendWith(SpringExtension.class)
@Import(RateLimitingServiceSpringConfig.class)
@WebMvcTest(
controllers = SettingsController.class
)
class SettingsControllerIT {
@Autowired
private MockMvc mockMvc;

@MockitoBean
private RateLimitingInterceptor rateLimitingInterceptor;

@Test
@WithMockUser(roles = "DATAPORTAL_TEST_USER")
void getSettings_succeeds() throws Exception {
mockMvc.perform(get(URI.create("/.settings")).with(csrf()))
.andExpect(status().isOk());
}
}
Loading