diff --git a/core/fhir/content_negotiation.py b/core/fhir/content_negotiation.py new file mode 100644 index 000000000..4d55754d9 --- /dev/null +++ b/core/fhir/content_negotiation.py @@ -0,0 +1,14 @@ +from rest_framework.negotiation import BaseContentNegotiation + +class IgnoreClientContentNegotiation(BaseContentNegotiation): + def select_parser(self, request, parsers): + """ + Select the first parser in the `.parser_classes` list. + """ + return parsers[0] + + def select_renderer(self, request, renderers, format_suffix): + """ + Select the first renderer in the `.renderer_classes` list. + """ + return (renderers[0], renderers[0].media_type) \ No newline at end of file diff --git a/core/fhir/urls.py b/core/fhir/urls.py new file mode 100644 index 000000000..43e597ed6 --- /dev/null +++ b/core/fhir/urls.py @@ -0,0 +1,9 @@ +from django.urls import re_path + +from core.common.constants import NAMESPACE_PATTERN +from . import views + +urlpatterns = [ + re_path(r'^$', views.CapabilityStatementView.as_view(), name='capability-statement'), + re_path(r'^metadata$', views.CapabilityStatementView.as_view(), name='capability-statement'), +] diff --git a/core/fhir/views.py b/core/fhir/views.py new file mode 100644 index 000000000..35f5a2016 --- /dev/null +++ b/core/fhir/views.py @@ -0,0 +1,273 @@ +import logging + +from django.db.models import F +from rest_framework.exceptions import ValidationError, NotAuthenticated +from rest_framework.permissions import AllowAny +from rest_framework.response import Response +from rest_framework.views import APIView + +from core.bundles.serializers import FHIRBundleSerializer +from core.code_systems.serializers import CodeSystemDetailSerializer, \ + ValidateCodeParametersSerializer +from core.common.constants import HEAD +from core.common.fhir_helpers import translate_fhir_query +from core.common.serializers import IdentifierSerializer +from core.concepts.permissions import CanViewParentDictionaryAsGuest +from core.concepts.views import ConceptRetrieveUpdateDestroyView +from core.fhir.content_negotiation import IgnoreClientContentNegotiation +from core.parameters.serializers import ParametersSerializer +from core.sources.models import Source +from core.sources.views import SourceListView, SourceRetrieveUpdateDestroyView + +logger = logging.getLogger('oclapi') + + +class CapabilityStatementView(APIView): + content_negotiation_class = IgnoreClientContentNegotiation + permission_classes = (AllowAny,) + + def get(self, request): + mode = request.query_params.get('mode') + if mode == 'terminology': + response = { + "resourceType" : "TerminologyCapabilities", + "id" : "example", + "text" : { + "status" : "generated", + "div" : "
\n\t\t\t\n

The OCL Server supports the following transactions for the resource Person: read, vread, \n update, history, search(name,gender), create and updates.

\n\t\t\t\n

The EHR System supports the following message: admin-notify::Person.

\n\t\t\t\n

The EHR Application has a \n \n general document profile.\n \n

\n\t\t\n
" + }, + "url" : "urn:uuid:68d043b5-9ecf-4559-a57a-396e0d452311", + "identifier" : [{ + "system" : "urn:ietf:rfc:3986", + "value" : "urn:oid:2.16.840.1.113883.4.642.6.2" + }], + "version" : "20130510", + "name" : "OCL", + "title" : "OCL capability statement", + "status" : "draft", + "experimental" : True, + "date" : "2012-01-04", + "publisher" : "OCL", + "contact" : [{ + "name" : "System Administrator", + "telecom" : [{ + "system" : "email", + "value" : "admin@openconceptlab.org" + }] + }], + "description" : "This is the FHIR capability statement for the main EHR at ACME for the private interface - it does not describe the public interface", + "kind" : "instance", + "software" : { + "name" : "TxServer", + "version" : "0.1.2" + }, + "implementation" : { + "description" : "OCL Terminology Server", + "url" : "http://example.org/tx" + }, + "codeSearch" : "in-compose-or-expansion" + } + else: + response = { + "resourceType" : "CapabilityStatement", + "id" : "openconceptlab-terminology-server", + "text" : { + "status" : "extensions", + "div" : "
\n

ACMETerminologyServiceCapabilityStatement

\n
\n

Example capability statement for a Terminology Server. A server can support more fucntionality than defined here, but this is the minimum amount

\n\n
\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
ModeSERVER
Description\n
Transaction\n
System History\n
System Search\n
\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
\n Resource Type\n \n Profile\n \n Read\n \n Search\n \n Update\n \n Create\n
CodeSystem\n http://hl7.org/fhir/StructureDefinition/CodeSystem\n yy\n \n
ValueSet\n http://hl7.org/fhir/StructureDefinition/ValueSet\n yy\n \n
ConceptMap\n http://hl7.org/fhir/StructureDefinition/ConceptMap\n yy\n \n
\n
" + }, + "url" : "http://hl7.org/fhir/CapabilityStatement/terminology-server", + "version" : "5.0.0", + "name" : "OCLTerminologyServiceCapabilityStatement", + "title" : "OCL Terminology Service — Capability Statement", + "status" : "draft", + "experimental" : True, + "date" : "2022-09-01", + "description" : "Example capability statement for a Terminology Server. A server can support more fucntionality than defined here, but this is the minimum amount", + "kind" : "instance", + "implementation" : { + "description" : "The OCL FHIR Terminology Server" + }, + "fhirVersion" : "5.0.0", + "format" : ["json", "xml"], + "rest" : [{ + "mode" : "server", + "resource" : [{ + "type" : "CodeSystem", + "profile" : "http://hl7.org/fhir/StructureDefinition/CodeSystem", + "interaction" : [{ + "extension" : [{ + "url" : "http://hl7.org/fhir/StructureDefinition/capabilitystatement-expectation", + "valueCode" : "SHALL" + }], + "code" : "read" + }, + { + "extension" : [{ + "url" : "http://hl7.org/fhir/StructureDefinition/capabilitystatement-expectation", + "valueCode" : "SHALL" + }], + "code" : "search-type" + }], + "searchParam" : [{ + "name" : "url", + "definition" : "http://hl7.org/fhir/SearchParameter/CodeSystem-url", + "type" : "uri" + }, + { + "name" : "version", + "definition" : "http://hl7.org/fhir/SearchParameter/CodeSystem-version", + "type" : "token" + }, + { + "name" : "name", + "definition" : "http://hl7.org/fhir/SearchParameter/CodeSystem-name", + "type" : "string" + }, + { + "name" : "title", + "definition" : "http://hl7.org/fhir/SearchParameter/CodeSystem-title", + "type" : "string" + }, + { + "name" : "status", + "definition" : "http://hl7.org/fhir/SearchParameter/CodeSystem-status", + "type" : "token" + }], + "operation" : [{ + "extension" : [{ + "url" : "http://hl7.org/fhir/StructureDefinition/capabilitystatement-expectation", + "valueCode" : "SHALL" + }], + "name" : "expand", + "definition" : "http://hl7.org/fhir/OperationDefinition/CodeSystem-lookup" + }, + { + "extension" : [{ + "url" : "http://hl7.org/fhir/StructureDefinition/capabilitystatement-expectation", + "valueCode" : "SHALL" + }], + "name" : "expand", + "definition" : "http://hl7.org/fhir/OperationDefinition/CodeSystem-validate-code" + }, + { + "extension" : [{ + "url" : "http://hl7.org/fhir/StructureDefinition/capabilitystatement-expectation", + "valueCode" : "SHALL" + }], + "name" : "expand", + "definition" : "http://hl7.org/fhir/OperationDefinition/CodeSystem-subsumes" + }] + }, + { + "type" : "ValueSet", + "profile" : "http://hl7.org/fhir/StructureDefinition/ValueSet", + "interaction" : [{ + "extension" : [{ + "url" : "http://hl7.org/fhir/StructureDefinition/capabilitystatement-expectation", + "valueCode" : "SHALL" + }], + "code" : "read" + }, + { + "extension" : [{ + "url" : "http://hl7.org/fhir/StructureDefinition/capabilitystatement-expectation", + "valueCode" : "SHALL" + }], + "code" : "search-type" + }], + "searchParam" : [{ + "name" : "url", + "definition" : "http://hl7.org/fhir/SearchParameter/ValueSet-url", + "type" : "uri" + }, + { + "name" : "version", + "definition" : "http://hl7.org/fhir/SearchParameter/ValueSet-version", + "type" : "token" + }, + { + "name" : "name", + "definition" : "http://hl7.org/fhir/SearchParameter/ValueSet-name", + "type" : "string" + }, + { + "name" : "title", + "definition" : "http://hl7.org/fhir/SearchParameter/ValueSet-title", + "type" : "string" + }, + { + "name" : "status", + "definition" : "http://hl7.org/fhir/SearchParameter/ValueSet-status", + "type" : "token" + }], + "operation" : [{ + "extension" : [{ + "url" : "http://hl7.org/fhir/StructureDefinition/capabilitystatement-expectation", + "valueCode" : "SHALL" + }], + "name" : "expand", + "definition" : "http://hl7.org/fhir/OperationDefinition/ValueSet-expand" + }, + { + "extension" : [{ + "url" : "http://hl7.org/fhir/StructureDefinition/capabilitystatement-expectation", + "valueCode" : "SHALL" + }], + "name" : "expand", + "definition" : "http://hl7.org/fhir/OperationDefinition/ValueSet-validate-code" + }] + }, + { + "type" : "ConceptMap", + "profile" : "http://hl7.org/fhir/StructureDefinition/ConceptMap", + "interaction" : [{ + "extension" : [{ + "url" : "http://hl7.org/fhir/StructureDefinition/capabilitystatement-expectation", + "valueCode" : "SHALL" + }], + "code" : "read" + }, + { + "extension" : [{ + "url" : "http://hl7.org/fhir/StructureDefinition/capabilitystatement-expectation", + "valueCode" : "SHALL" + }], + "code" : "search-type" + }], + "searchParam" : [{ + "name" : "url", + "definition" : "http://hl7.org/fhir/SearchParameter/ConceptMap-url", + "type" : "uri" + }, + { + "name" : "version", + "definition" : "http://hl7.org/fhir/SearchParameter/ConceptMap-version", + "type" : "token" + }, + { + "name" : "name", + "definition" : "http://hl7.org/fhir/SearchParameter/ConceptMap-name", + "type" : "string" + }, + { + "name" : "title", + "definition" : "http://hl7.org/fhir/SearchParameter/ConceptMap-title", + "type" : "string" + }, + { + "name" : "status", + "definition" : "http://hl7.org/fhir/SearchParameter/ConceptMap-status", + "type" : "token" + }], + "operation" : [{ + "extension" : [{ + "url" : "http://hl7.org/fhir/StructureDefinition/capabilitystatement-expectation", + "valueCode" : "SHALL" + }], + "name" : "expand", + "definition" : "http://hl7.org/fhir/OperationDefinition/ConceptMap-translate" + }] + }] + }] + } + return Response(response) diff --git a/core/urls.py b/core/urls.py index 18653ba0f..d8dfade93 100644 --- a/core/urls.py +++ b/core/urls.py @@ -67,6 +67,7 @@ path('repos/', include('core.repos.urls'), name='repos_url'), path('url-registry/', include('core.url_registry.urls'), name='url_registry_url'), #TODO: require FHIR subdomain + path('fhir/', include('core.fhir.urls'), name='fhir_urls'), path('fhir/CodeSystem/', include('core.code_systems.urls'), name='code_systems_urls'), path('fhir/ValueSet/', include('core.value_sets.urls'), name='value_sets_urls'), path('fhir/ConceptMap/', include('core.concept_maps.urls'), name='concept_maps_urls'),