This commit is contained in:
Joshua Hare 2025-08-13 07:31:32 +10:00
parent 62ff8e8a28
commit 57d05eab38
3 changed files with 35 additions and 29 deletions

16
app.py
View File

@ -1907,22 +1907,22 @@ def proxy_hapi(subpath):
return jsonify({'resourceType': 'OperationOutcome', 'issue': [{'severity': 'error', 'code': 'exception', 'diagnostics': 'An unexpected error occurred within the FHIR proxy.', 'details': {'text': str(e)}}]}), 500 return jsonify({'resourceType': 'OperationOutcome', 'issue': [{'severity': 'error', 'code': 'exception', 'diagnostics': 'An unexpected error occurred within the FHIR proxy.', 'details': {'text': str(e)}}]}), 500
@app.route('/api/stream-retrieve', methods=['POST']) @app.route('/api/stream-retrieve', methods=['GET'])
def stream_retrieve_bundles(): def stream_retrieve_bundles():
""" """
Handles streaming FHIR bundle retrieval. This endpoint directly calls the service function, Handles streaming FHIR bundle retrieval. This endpoint directly calls the service function,
bypassing the proxy to avoid conflicts. It receives the target URL, bypassing the proxy to avoid conflicts. It receives the target URL,
resources, and other parameters from the front-end via a JSON body. resources, and other parameters from the front-end via URL query parameters.
""" """
def generate_stream(): def generate_stream():
with app.app_context(): with app.app_context():
# Extract parameters from JSON body # Extract parameters from query string
data = request.json fhir_server_url = request.args.get('fhir_server_url')
fhir_server_url = data.get('fhir_server_url') resources = request.args.getlist('resources')
resources = data.get('resources') validate_references = request.args.get('validate_references', 'false').lower() == 'true'
validate_references = data.get('validate_references', False) fetch_reference_bundles = request.args.get('fetch_reference_bundles', 'false').lower() == 'true'
fetch_reference_bundles = data.get('fetch_reference_bundles', False)
# Extract authentication headers
auth_token = request.headers.get('Authorization') auth_token = request.headers.get('Authorization')
auth_type = 'bearer' if auth_token and auth_token.lower().startswith('bearer') else 'basic' if auth_token and auth_token.lower().startswith('basic') else 'none' auth_type = 'bearer' if auth_token and auth_token.lower().startswith('bearer') else 'basic' if auth_token and auth_token.lower().startswith('basic') else 'none'

View File

@ -4584,7 +4584,8 @@ def retrieve_bundles(fhir_server_url, resources, output_zip, validate_references
yield json.dumps({"type": "info", "message": "Reference fetching OFF"}) + "\n" yield json.dumps({"type": "info", "message": "Reference fetching OFF"}) + "\n"
# Determine the final base URL for requests. # Determine the final base URL for requests.
final_base_url = fhir_server_url.rstrip('/') if fhir_server_url and fhir_server_url != '/fhir' else app.config.get('HAPI_FHIR_URL', 'http://localhost:8080/fhir') from flask import current_app
final_base_url = fhir_server_url.rstrip('/') if fhir_server_url and fhir_server_url != '/fhir' else current_app.config.get('HAPI_FHIR_URL', 'http://localhost:8080/fhir')
headers = {'Accept': 'application/fhir+json, application/fhir+xml;q=0.9, */*;q=0.8'} headers = {'Accept': 'application/fhir+json, application/fhir+xml;q=0.9, */*;q=0.8'}
is_custom_url = fhir_server_url != '/fhir' and fhir_server_url is not None and fhir_server_url.startswith('http') is_custom_url = fhir_server_url != '/fhir' and fhir_server_url is not None and fhir_server_url.startswith('http')

View File

@ -27,7 +27,7 @@
</ul> </ul>
</div> </div>
{% endif %} {% endif %}
<form id="retrieveForm" method="POST" enctype="multipart/form-data"> <form id="retrieveForm" method="POST">
{{ form.hidden_tag() }} {{ form.hidden_tag() }}
<div class="mb-3"> <div class="mb-3">
<label class="form-label fw-bold">FHIR Server</label> <label class="form-label fw-bold">FHIR Server</label>
@ -216,7 +216,6 @@ document.addEventListener('DOMContentLoaded', () => {
toggleServerButton.classList.remove('disabled'); toggleServerButton.classList.remove('disabled');
toggleServerButton.style.pointerEvents = 'auto'; toggleServerButton.style.pointerEvents = 'auto';
toggleServerButton.removeAttribute('aria-disabled'); toggleServerButton.removeAttribute('aria-disabled');
toggleServerButton.title = "Toggle between Local HAPI and Custom URL";
toggleLabel.textContent = useLocalHapi ? 'Using Local HAPI' : 'Using Custom URL'; toggleLabel.textContent = useLocalHapi ? 'Using Local HAPI' : 'Using Custom URL';
fhirServerUrlInput.style.display = useLocalHapi ? 'none' : 'block'; fhirServerUrlInput.style.display = useLocalHapi ? 'none' : 'block';
fhirServerUrlInput.placeholder = "e.g., https://hapi.fhir.org/baseR4"; fhirServerUrlInput.placeholder = "e.g., https://hapi.fhir.org/baseR4";
@ -300,10 +299,9 @@ document.addEventListener('DOMContentLoaded', () => {
fetchMetadataButton.textContent = 'Fetching...'; fetchMetadataButton.textContent = 'Fetching...';
try { try {
const fetchUrl = '/fhir/metadata'; const fetchUrl = useLocalHapi ? '/fhir/metadata' : `${customUrl}/metadata`;
const headers = { 'Accept': 'application/fhir+json' }; const headers = { 'Accept': 'application/fhir+json' };
if (!useLocalHapi && customUrl) { if (!useLocalHapi && customUrl) {
headers['X-Target-FHIR-Server'] = customUrl;
if (authTypeSelect && authTypeSelect.value !== 'none') { if (authTypeSelect && authTypeSelect.value !== 'none') {
const authType = authTypeSelect.value; const authType = authTypeSelect.value;
if (authType === 'bearer' && bearerTokenInput && bearerTokenInput.value) { if (authType === 'bearer' && bearerTokenInput && bearerTokenInput.value) {
@ -313,12 +311,12 @@ document.addEventListener('DOMContentLoaded', () => {
headers['Authorization'] = `Basic ${credentials}`; headers['Authorization'] = `Basic ${credentials}`;
} }
} }
console.log(`Fetching metadata via proxy with X-Target-FHIR-Server: ${customUrl}`); console.log(`Fetching metadata directly from: ${customUrl}`);
} else { } else {
console.log("Fetching metadata via proxy for local HAPI server"); console.log("Fetching metadata from local HAPI server via proxy");
} }
console.log(`Proxy Fetch URL: ${fetchUrl}`); console.log(`Fetch URL: ${fetchUrl}`);
console.log(`Request Headers sent TO PROXY: ${JSON.stringify(headers)}`); console.log(`Request Headers sent: ${JSON.stringify(headers)}`);
const response = await fetch(fetchUrl, { method: 'GET', headers: headers }); const response = await fetch(fetchUrl, { method: 'GET', headers: headers });
@ -383,11 +381,30 @@ document.addEventListener('DOMContentLoaded', () => {
return; return;
} }
const currentFhirServerUrl = useLocalHapi ? null : fhirServerUrlInput.value.trim();
if (!useLocalHapi && !currentFhirServerUrl) {
alert('Custom FHIR Server URL is required.');
fhirServerUrlInput.classList.add('is-invalid');
retrieveButton.disabled = false;
if (spinner) spinner.style.display = 'none';
if (icon) icon.style.display = 'inline-block';
return;
}
const formData = new FormData(); const formData = new FormData();
const csrfTokenInput = retrieveForm.querySelector('input[name="csrf_token"]'); const csrfTokenInput = retrieveForm.querySelector('input[name="csrf_token"]');
if (csrfTokenInput) formData.append('csrf_token', csrfTokenInput.value); if (csrfTokenInput) formData.append('csrf_token', csrfTokenInput.value);
selectedResources.forEach(res => formData.append('resources', res)); selectedResources.forEach(res => formData.append('resources', res));
// --- FIX APPLIED HERE ---
if (!useLocalHapi && currentFhirServerUrl) {
formData.append('fhir_server_url', currentFhirServerUrl);
} else {
// Explicitly use the proxy URL if local HAPI is selected
formData.append('fhir_server_url', '/fhir');
}
// --- END FIX ---
if (validateReferencesCheckbox) { if (validateReferencesCheckbox) {
formData.append('validate_references', validateReferencesCheckbox.checked ? 'true' : 'false'); formData.append('validate_references', validateReferencesCheckbox.checked ? 'true' : 'false');
} }
@ -401,18 +418,6 @@ document.addEventListener('DOMContentLoaded', () => {
formData.append('fetch_reference_bundles', 'false'); formData.append('fetch_reference_bundles', 'false');
} }
const currentFhirServerUrl = useLocalHapi ? '/fhir' : fhirServerUrlInput.value.trim();
if (!useLocalHapi && !currentFhirServerUrl) {
alert('Custom FHIR Server URL is required.');
fhirServerUrlInput.classList.add('is-invalid');
retrieveButton.disabled = false;
if (spinner) spinner.style.display = 'none';
if (icon) icon.style.display = 'inline-block';
return;
}
formData.append('fhir_server_url', currentFhirServerUrl);
// Add authentication fields for custom URL
if (!useLocalHapi && authTypeSelect) { if (!useLocalHapi && authTypeSelect) {
const authType = authTypeSelect.value; const authType = authTypeSelect.value;
formData.append('auth_type', authType); formData.append('auth_type', authType);