go to post Guillaume Rongier · Oct 17, 2023 Hi, Are you using docker desktop ? if so, does you file sharing implemention is "VirtioFS" ? Then, that may be a problem, try it with gRPC FUSE, does it fix it ? Why "VirtioFS" and durable doesn't work, i don't know, i will try to gather information about it.
go to post Guillaume Rongier · Oct 17, 2023 Hi, FHIR Profile Validation will be support with IRIS 2023.3. https://community.intersystems.com/post/intersystems-announces-its-secon... Highlights There are several exciting new features in this release, such as support to base HL7® FHIR® version R5, and the integration with the IBM FHIR® Validator. There are also runtime performance improvements for ObjectScript. Note that these features are expected, but nor assured to appear in the final release. Mean while, you can use community edition of Profile Validation : https://openexchange.intersystems.com/package/fhir-profile-validation https://github.com/grongierisc/iris-fhir-validation
go to post Guillaume Rongier · Oct 17, 2023 Hi, FHIR Profile Validation will be support with IRIS 2023.3. https://community.intersystems.com/post/intersystems-announces-its-secon... Highlights There are several exciting new features in this release, such as support to base HL7® FHIR® version R5, and the integration with the IBM FHIR® Validator. There are also runtime performance improvements for ObjectScript. Note that these features are expected, but nor assured to appear in the final release. Mean while, you can use community edition of Profile Validation : https://openexchange.intersystems.com/package/fhir-profile-validation https://github.com/grongierisc/iris-fhir-validation
go to post Guillaume Rongier · Oct 11, 2023 FYI : it works great except that, it create the classes in %SYS namespace, not in our current namespace. I will fill an issue on github.
go to post Guillaume Rongier · Oct 10, 2023 Hi, I can't reproduce your error. I'm missing some information. What I have done so far is : adding the missing imports adding the missing class DFrameRequest i suppose it is a dataclass with a field named dframe of type pd.DataFrame i suppose it is a subclass of Message i have added a main function to run the code i'm not sure of the format of the dataframe and the data in it from dataclasses import dataclass import pandas as pd from grongier.pex import BusinessOperation,Message from sqlalchemy import create_engine, types @dataclass class DFrameRequest(Message): dframe: pd.DataFrame class FileOperationEmbedded(BusinessOperation): tablename = None engine = None def on_init(self): if not hasattr(self, "dsnIris"): self.dnsIris = 'iris+emb:///' if not hasattr(self, "schema"): self.schema = 'Toto' self.engine = create_engine(self.dnsIris) return None def on_message(self, request:DFrameRequest): df = pd.DataFrame(request.dframe.col) for row in request.dframe.col: df = pd.DataFrame.from_dict(row, orient='index').T.reset_index(drop=True) try: df.to_sql(name=self.tablename, con=self.engine, if_exists='append', index=False, schema=self.schema, dtype={'id': types.INTEGER, 'col_type': types.VARCHAR(50), 'col_center': types.VARCHAR(50), 'col_name': types.VARCHAR(50), 'col_issue_name': types.VARCHAR(50), 'col_model': types.VARCHAR(50), 'col_treatment': types.VARCHAR(50), 'source': types.VARCHAR(50), 'filename': types.VARCHAR(100), 'created_at': types.TIMESTAMP}) except Exception as e: self.log_info(f"Une erreur s'est produite : {e}") return None if __name__ == '__main__': # create a new instance of the business operation bo = FileOperationEmbedded() # initialize the business operation bo.on_init() # create a new message msg = DFrameRequest(pd.DataFrame()) msg.dframe.col = [ {'id': 1, 'col_type': 'type1', 'col_center': 'center1', 'col_name': 'name1', 'col_issue_name': 'issue1', 'col_model': 'model1', 'col_treatment': 'treatment1', 'source': 'source1', 'filename': 'file1', 'created_at': '2021-10-01 00:00:00'}, {'id': 2, 'col_type': 'type2', 'col_center': 'center2', 'col_name': 'name2', 'col_issue_name': 'issue2', 'col_model': 'model2', 'col_treatment': 'treatment2', 'source': 'source2', 'filename': 'file2', 'created_at': '2021-10-02 00:00:00'} ] # send the message to the business operation bo.on_message(msg) print("Done") Then, from your code I can see the following issues : you are using the same variable name for the dataframe and the list of rows the variable self.tablename is not initialized the name FileOperationEmbedded it's maybe not the best name for your class as it is not a file operation why are you using a for loop to iterate over the rows of the dataframe ? I have modified your code to fix these issues : from dataclasses import dataclass import pandas as pd from grongier.pex import BusinessOperation,Message from sqlalchemy import create_engine, types @dataclass class DFrameRequest(Message): dframe: pd.DataFrame class IrisSqlAlchmyEmbedded(BusinessOperation): tablename = None engine = None def on_init(self): if not hasattr(self, "dsnIris"): self.dnsIris = 'iris+emb:///' if not hasattr(self, "schema"): self.schema = 'Toto' if not hasattr(self, "tablename") or self.tablename is None: self.tablename = 'mytable' self.engine = create_engine(self.dnsIris) return None def on_message(self, request:DFrameRequest): try: request.dframe.to_sql(name=self.tablename, con=self.engine, if_exists='append', index=False, schema=self.schema, dtype={'id': types.INTEGER, 'col_type': types.VARCHAR(50), 'col_center': types.VARCHAR(50), 'col_name': types.VARCHAR(50), 'col_issue_name': types.VARCHAR(50), 'col_model': types.VARCHAR(50), 'col_treatment': types.VARCHAR(50), 'source': types.VARCHAR(50), 'filename': types.VARCHAR(100), 'created_at': types.TIMESTAMP}) except Exception as e: print(f"Une erreur s'est produite : {e}") return None if __name__ == '__main__': # create a new instance of the business operation bo = IrisSqlAlchmyEmbedded() # initialize the business operation bo.on_init() # create a new message msg = DFrameRequest(pd.DataFrame([ {'id': 1, 'col_type': 'type1', 'col_center': 'center1', 'col_name': 'name1', 'col_issue_name': 'issue1', 'col_model': 'model1', 'col_treatment': 'treatment1', 'source': 'source1', 'filename': 'file1', 'created_at': '2021-10-01 00:00:00'}, {'id': 2, 'col_type': 'type2', 'col_center': 'center2', 'col_name': 'name2', 'col_issue_name': 'issue2', 'col_model': 'model2', 'col_treatment': 'treatment2', 'source': 'source2', 'filename': 'file2', 'created_at': '2021-10-02 00:00:00'} ])) # send the message to the business operation bo.on_message(msg) print("Done")
go to post Guillaume Rongier · Oct 10, 2023 As it's a question written in French, I've moved it here. I'll also try to answer it in English.
go to post Guillaume Rongier · Oct 9, 2023 I don't think so. FHIR is an API rest. FHIR has not been designed to apply deduplication and data merge business rules. This is the role of HealthShare not the role of an FHIR endpoint.
go to post Guillaume Rongier · Oct 9, 2023 It seems that 2022.x have the same capability that 2023.x, I mean by that 2022.x support conditional Update and Create. Then if you want to update only that is needed to be updated you have to go with JSON Patch : PATCH https://localhost:4443/fhir/r4/Organization?identifier=HEAD Accept: application/fhir+json Content-Type: application/json-patch+json [ { "op": "add", "path": "/telecom/0", "value": { "system": "phone", "value": "some-other-phone" } } ] Result : GET https://localhost:4443/fhir/r4/Organization?identifier=HEAD&_elements=telecom Accept: application/fhir+json { "resourceType": "Bundle", "id": "9962a9aa-668b-11ee-8f79-0242ac160003", "type": "searchset", "timestamp": "2023-10-09T10:05:38Z", "total": 1, "link": [ { "relation": "self", "url": "https://localhost:4443/fhir/r4/Organization?_elements=telecom&identifier=HEAD" } ], "entry": [ { "fullUrl": "https://localhost:4443/fhir/r4/Organization/1", "resource": { "resourceType": "Organization", "telecom": [ { "system": "phone", "value": "some-other-phone" }, { "system": "phone", "value": "some-other-phone" } ], "meta": { "tag": [ { "system": "http://terminology.hl7.org/CodeSystem/v3-ObservationValue", "code": "SUBSETTED", "display": "Resource content reduced because _elements search parameter" } ] } }, "search": { "mode": "match" } } ] } Attention JSON patch only work with direct access to the resource, if you need json path in a bundle you have to pass it as a base64 : { "resourceType": "Bundle", "type": "transaction", "entry": [ { "fullUrl": "Patient/1", "resource": { "resourceType": "Binary", "contentType": "application/json-patch+json", "data": "WyB7ICJvcCI6InJlcGxhY2UiLCAicGF0aCI6Ii9hY3RpdmUiLCAidmFsdWUiOmZhbHNlIH0gXQ==" }, "request": { "method": "PATCH", "url": "Patient/1" } } ] } Example of a json path in a bundle for the patient 1 with this patch : [ { "op":"replace", "path":"/active", "value":false } ]
go to post Guillaume Rongier · Oct 6, 2023 { "entry": [ { "request": { "method": "PUT", "url": "Organization?identifier=EFG" }, "resource": { "active": true, "identifier": [ { "system": "https://fhir.domain.de/identifiers/domain-orgid", "value": "EFG" } ], "name": "Allgemeine Einrichtung EFG.", "partOf": { "display": "HEAD", "reference": "urn:uuid:87a8f88a-5223-11ee-8c2c-005056b163cd" }, "resourceType": "Organization", "telecom": [ { "system": "phone", "value": "some-phonenr" }, { "system": "fax", "value": "some-faxnr" } ], "type": [ { "coding": [ { "code": "2", "system": "https://fhir.domain.de/CodeSystem/domain-orglevel" }, { "code": "KL", "display": "Klinik m. Poliklinik", "system": "https://fhir.domain.de/CodeSystem/domain-orgtype" } ] } ] } }, { "request": { "method": "PUT", "url": "Organization?identifier=AEAP" }, "resource": { "active": true, "identifier": [ { "system": "https://fhir.domain.de/identifiers/domain-orgid", "value": "AEAP" } ], "name": "Allgemeine Einrichtung AEAP", "partOf": { "display": "HEAD", "reference": "urn:uuid:87a8f88a-5223-11ee-8c2c-005056b163cd" }, "resourceType": "Organization", "telecom": [ { "system": "phone", "value": "some-phonenr" }, { "system": "fax", "value": "some-faxnr" } ], "type": [ { "coding": [ { "code": "2", "system": "https://fhir.domain.de/CodeSystem/domain-orglevel" }, { "code": "KL", "display": "Klinik m. Poliklinik", "system": "https://fhir.domain.de/CodeSystem/domain-orgtype" } ] } ] } }, { "fullUrl": "urn:uuid:87a8f88a-5223-11ee-8c2c-005056b163cd", "request": { "method": "PUT", "url": "Organization?identifier=HEAD" }, "resource": { "active": true, "address": [ { "line": [ "Some street 2" ], "type": "postal", "use": "work" } ], "identifier": [ { "system": "https://fhir.domain.de/identifiers/domain-orgid", "value": "HEAD" } ], "name": "Some Hospital", "partOf": { "display": "NULL" }, "resourceType": "Organization", "telecom": [ { "system": "phone", "value": "some-phonenr" } ], "type": [ { "coding": [ { "code": "0", "system": "https://fhir.domain.de/CodeSystem/domain-orglevel" }, { "code": "SHOS", "display": "Some Hospital", "system": "https://fhir.domain.de/CodeSystem/domain-orgtype" } ] } ] } } ], "id": "214a4092-eeb9-440d-b645-0ec3b5b30bbe", "resourceType": "Bundle", "type": "transaction" } Here is your bundle with conditional update instead of conditional create. Result on IRIS 2023.2 : First call : { "resourceType": "Bundle", "id": "409996a4-644b-11ee-8e3a-0242ac160003", "type": "transaction-response", "timestamp": "2023-10-06T13:07:35Z", "entry": [ { "response": { "status": "201", "location": "https://localhost:4443/fhir/r4/Organization/2", "etag": "W/\"1\"", "lastModified": "2023-10-06T13:07:35Z" } }, { "response": { "status": "201", "location": "https://localhost:4443/fhir/r4/Organization/3", "etag": "W/\"1\"", "lastModified": "2023-10-06T13:07:35Z" } }, { "fullUrl": "urn:uuid:87a8f88a-5223-11ee-8c2c-005056b163cd", "response": { "status": "201", "location": "https://localhost:4443/fhir/r4/Organization/1", "etag": "W/\"1\"", "lastModified": "2023-10-06T13:07:35Z" } } ] } as you can see we have 201 (mean created) Second call : { "resourceType": "Bundle", "id": "ccc5c35a-644b-11ee-8f77-0242ac160003", "type": "transaction-response", "timestamp": "2023-10-06T13:08:47Z", "entry": [ { "response": { "status": "200", "location": "https://localhost:4443/fhir/r4/Organization/2", "etag": "W/\"2\"", "lastModified": "2023-10-06T13:08:48Z" } }, { "response": { "status": "200", "location": "https://localhost:4443/fhir/r4/Organization/3", "etag": "W/\"2\"", "lastModified": "2023-10-06T13:08:48Z" } }, { "fullUrl": "urn:uuid:87a8f88a-5223-11ee-8c2c-005056b163cd", "response": { "status": "200", "location": "https://localhost:4443/fhir/r4/Organization/1", "etag": "W/\"2\"", "lastModified": "2023-10-06T13:08:47Z" } } ] } we can see 200 mean ok/updated. Get all organization : { "resourceType": "Bundle", "id": "56ccfcb4-644a-11ee-8f78-0242ac160003", "type": "searchset", "timestamp": "2023-10-06T13:09:50Z", "total": 3, "link": [ { "relation": "self", "url": "https://localhost:4443/fhir/r4/Organization" } ], "entry": [ { "fullUrl": "https://localhost:4443/fhir/r4/Organization/1", "resource": { "active": true, "address": [ { "line": [ "Some street 2" ], "type": "postal", "use": "work" } ], "identifier": [ { "system": "https://fhir.domain.de/identifiers/domain-orgid", "value": "HEAD" } ], "name": "Some Hospital", "partOf": { "display": "NULL" }, "resourceType": "Organization", "telecom": [ { "system": "phone", "value": "some-phonenr" } ], "type": [ { "coding": [ { "code": "0", "system": "https://fhir.domain.de/CodeSystem/domain-orglevel" }, { "code": "SHOS", "display": "Some Hospital", "system": "https://fhir.domain.de/CodeSystem/domain-orgtype" } ] } ], "id": "1", "meta": { "lastUpdated": "2023-10-06T13:08:47Z", "versionId": "2" } }, "search": { "mode": "match" } }, { "fullUrl": "https://localhost:4443/fhir/r4/Organization/2", "resource": { "active": true, "identifier": [ { "system": "https://fhir.domain.de/identifiers/domain-orgid", "value": "EFG" } ], "name": "Allgemeine Einrichtung EFG.", "partOf": { "display": "HEAD", "reference": "Organization/1" }, "resourceType": "Organization", "telecom": [ { "system": "phone", "value": "some-phonenr" }, { "system": "fax", "value": "some-faxnr" } ], "type": [ { "coding": [ { "code": "2", "system": "https://fhir.domain.de/CodeSystem/domain-orglevel" }, { "code": "KL", "display": "Klinik m. Poliklinik", "system": "https://fhir.domain.de/CodeSystem/domain-orgtype" } ] } ], "id": "2", "meta": { "lastUpdated": "2023-10-06T13:08:48Z", "versionId": "2" } }, "search": { "mode": "match" } }, { "fullUrl": "https://localhost:4443/fhir/r4/Organization/3", "resource": { "active": true, "identifier": [ { "system": "https://fhir.domain.de/identifiers/domain-orgid", "value": "AEAP" } ], "name": "Allgemeine Einrichtung AEAP", "partOf": { "display": "HEAD", "reference": "Organization/1" }, "resourceType": "Organization", "telecom": [ { "system": "phone", "value": "some-phonenr" }, { "system": "fax", "value": "some-faxnr" } ], "type": [ { "coding": [ { "code": "2", "system": "https://fhir.domain.de/CodeSystem/domain-orglevel" }, { "code": "KL", "display": "Klinik m. Poliklinik", "system": "https://fhir.domain.de/CodeSystem/domain-orgtype" } ] } ], "id": "3", "meta": { "lastUpdated": "2023-10-06T13:08:48Z", "versionId": "2" } }, "search": { "mode": "match" } } ] } As you can see "partOf" are referencing internal id of HEAD. TIP : To quickly test on a fresh server, you can wipe data like this (only do it on dev server, your laptop, never in production !!! ) Set appKey = "/fhir/r4" Set strategy = ##class(HS.FHIRServer.API.InteractionsStrategy).GetStrategyForEndpoint(appKey) Set options("deleteDataOnly") = 1 Do strategy.Delete(.options)
go to post Guillaume Rongier · Oct 2, 2023 Try to follow the article, the last part is about the ingress, this will help you to expose the webgateway and have access to the portal. Right now, I can't help you on specific features of EKS.
go to post Guillaume Rongier · Oct 2, 2023 Hi Roy, I can't tell about the "seed: path" but how to play with the Web Gateway sidecar you can follow this example : https://community.intersystems.com/post/local-k8s-deployment-fhir-server TL; DR : In your topology definition : ## deploy webgateway (web server) nodes webgateway: image: k3d-registry.localhost:5000/intersystems/webgateway:2023.1.1.380.0-linux-amd64 type: apache replicas: 1 applicationPaths: - /csp/sys - /fhir/r4 alternativeServers: LoadBalancing loginSecret: name: iris-webgateway-secret The iris-webgateway-secret : kubectl create secret generic iris-webgateway-secret --from-literal='username=CSPSystem' --from-literal='password=SYS' The config file for iris : [Actions] ModifyService:Name=%Service_CallIn,Enabled=1,AutheEnabled=16 ModifyUser:Name=SuperUser,ChangePassword=0,PasswordHash=a31d24aecc0bfe560a7e45bd913ad27c667dc25a75cbfd358c451bb595b6bd52bd25c82cafaa23ca1dd30b3b4947d12d3bb0ffb2a717df29912b743a281f97c1,0a4c463a2fa1e7542b61aa48800091ab688eb0a14bebf536638f411f5454c9343b9aa6402b4694f0a89b624407a5f43f0a38fc35216bb18aab7dc41ef9f056b1,10000,SHA512 ModifyUser:Name=CSPSystem,ChangePassword=0,PasswordHash=a31d24aecc0bfe560a7e45bd913ad27c667dc25a75cbfd358c451bb595b6bd52bd25c82cafaa23ca1dd30b3b4947d12d3bb0ffb2a717df29912b743a281f97c1,0a4c463a2fa1e7542b61aa48800091ab688eb0a14bebf536638f411f5454c9343b9aa6402b4694f0a89b624407a5f43f0a38fc35216bb18aab7dc41ef9f056b1,10000,SHA512 To generate PasswordHash : docker run --rm -it containers.intersystems.com/intersystems/passwordhash:1.1 -algorithm SHA512 -workfactor 10000 Add the configmap for iris : kubectl create cm iriscluster-config --from-file common.cpf the topology of IRIS + Webgateway : apiVersion: intersystems.com/v1alpha1 kind: IrisCluster metadata: name: sample spec: ## provide InterSystems IRIS license key if required # licenseKeySecret: # name: iris-key-secret ## specify files used to customize the configurations of ## InterSystems IRIS nodes, including passwordHash parameter ## to set the default password, securing InterSystems IRIS configSource: name: iriscluster-config ## topology: defines node types to be deployed; only "data:" is required topology: data: image: k3d-registry.localhost:5000/iris-oauth-fhir-iris:latest ## deploy webgateway (web server) nodes webgateway: image: k3d-registry.localhost:5000/intersystems/webgateway:2023.1.1.380.0-linux-amd64 type: apache replicas: 1 applicationPaths: - /csp/sys - /fhir/r4 alternativeServers: LoadBalancing loginSecret: name: iris-webgateway-secret
go to post Guillaume Rongier · Sep 22, 2023 It's really impressive and easy to use. May be that can be next generation iris terminal. Love it, I will definitely use it !
go to post Guillaume Rongier · Aug 28, 2023 I bet that the issue is related to the fact that recently IRIS 2023.2 was released. This version removed this method InstallFoundation from this class HS.HC.Util.Installer. This was a private method and it was not documented. But it was widely used by the community to install FHIR server. TL;DR : Change : do ##class(HS.HC.Util.Installer).InstallFoundation() to Do ##class(HS.Util.Installer.Foundation).Install(namespace) cf : https://community.intersystems.com/post/installfoundation-method-missing...
go to post Guillaume Rongier · Aug 21, 2023 Wow, neat work, I can see that in your source code that you have pre build grafana dashboard, can you share screenshot of them ?
go to post Guillaume Rongier · Aug 21, 2023 after DP-API support for Python, now Hibernete support for Java ! Great job @Dmitry Maslennikov and @Yuri Marx
go to post Guillaume Rongier · Aug 7, 2023 In theory you are all set. Just take for example the dockerfile. You can also read the pom.xml file to take some insperation. For example take a look how the jdbc driver is added to the project. <dependency> <groupId>intersystems</groupId> <artifactId>jdbc</artifactId> <version>3.3.0</version> <scope>system</scope> <systemPath>${pom.basedir}/lib/intersystems-jdbc-3.3.0.jar</systemPath> </dependency> To sum up, you need obviously the jdbc drive (you have one in the repo), the hibernate dialect, you also have one in the repo, for the hibernete dialet you can also have a look to the article of yuri : https://community.intersystems.com/post/using-new-intersystems-iris-hibe.... Have fun with Iris and quarkus.
go to post Guillaume Rongier · Aug 7, 2023 Hi, you will find here an example of Quarkus + IRIS + Hibernete : https://github.com/grongierisc/iris-orm-examples
go to post Guillaume Rongier · Jul 27, 2023 Thanks and fixed. BTW, now the new version of this project is in python : import time import os import json import iris from FhirInteraction import Interaction, Strategy, OAuthInteraction from google.oauth2 import id_token from google.auth.transport import requests import requests as rq # The following is an example of a custom OAuthInteraction class that class CustomOAuthInteraction(OAuthInteraction): client_id = None last_time_verified = None time_interval = 5 def clear_instance(self): self.token_string = None self.oauth_client = None self.base_url = None self.username = None self.token_obj = None self.scopes = None self.verify_search_results = None def set_instance(self, token:str,oauth_client:str,base_url:str,username:str): self.clear_instance() if not token or not oauth_client: # the token or oauth client is not set, skip the verification return global_time = iris.gref('^FHIR.OAuth2.Time') if global_time[token[0:50]]: self.last_time_verified = global_time[token[0:50]] if self.last_time_verified and (time.time() - self.last_time_verified) < self.time_interval: # the token was verified less than 5 seconds ago, skip the verification return self.token_string = token self.oauth_client = oauth_client self.base_url = base_url self.username = username # try to set the client id try: # first get the var env GOOGLE_CLIENT_ID is not set then None self.client_id = os.environ.get('GOOGLE_CLIENT_ID') # if not set, then by the secret.json file if not self.client_id: with open(os.environ.get('ISC_OAUTH_SECRET_PATH'),encoding='utf-8') as f: data = json.load(f) self.client_id = data['web']['client_id'] except FileNotFoundError: pass try: self.verify_token(token) except Exception as e: self.clear_instance() raise e # token is valid, set the last time verified to now global_time[token[0:50]]=time.time() def verify_token(self,token:str): # check if the token is an access token or an id token if token.startswith('ya29.'): self.verify_access_token(token) else: self.verify_id_token(token) def verify_access_token(self,token:str): # verify the access token is valid # get with a timeout of 5 seconds response = rq.get(f"https://www.googleapis.com/oauth2/v3/tokeninfo?access_token={token}",timeout=5) try: response.raise_for_status() except rq.exceptions.HTTPError as e: # the token is not valid raise e def verify_id_token(self,token:str): # Verify the token and get the user info idinfo = id_token.verify_oauth2_token(token, requests.Request(), self.client_id) if idinfo['iss'] not in ['accounts.google.com', 'https://accounts.google.com']: raise ValueError('Wrong issuer.') def get_introspection(self)->dict: return {} def get_user_info(self,basic_auth_username:str,basic_auth_roles:str)->dict: return {"Username":basic_auth_username,"Roles":basic_auth_roles} def verify_resource_id_request(self,resource_type:str,resource_id:str,required_privilege:str): pass def verify_resource_content(self,resource_dict:dict,required_privilege:str,allow_shared_resource:bool): pass def verify_history_instance_response(self,resource_type:str,resource_dict:dict,required_privilege:str): pass def verify_delete_request(self,resource_type:str,resource_id:str,required_privilege:str): pass def verify_search_request(self, resource_type:str, compartment_resource_type:str, compartment_resource_id:str, parameters:'iris.HS.FHIRServer.API.Data.QueryParameters', required_privilege:str): pass def verify_system_level_request(self): pass class CustomStrategy(Strategy): def on_get_capability_statement(self, capability_statement): # Example : del resources Account capability_statement['rest'][0]['resource'] = [resource for resource in capability_statement['rest'][0]['resource'] if resource['type'] != 'Account'] return capability_statement class CustomInteraction(Interaction): def on_before_request(self, fhir_service, fhir_request, body, timeout): #Extract the user and roles for this request #so consent can be evaluated. self.requesting_user = fhir_request.Username self.requesting_roles = fhir_request.Roles def on_after_request(self, fhir_service, fhir_request, fhir_response, body): #Clear the user and roles between requests. self.requesting_user = "" self.requesting_roles = "" def post_process_read(self, fhir_object): #Evaluate consent based on the resource and user/roles. #Returning 0 indicates this resource shouldn't be displayed - a 404 Not Found #will be returned to the user. return self.consent(fhir_object['resourceType'], self.requesting_user, self.requesting_roles) def post_process_search(self, rs, resource_type): #Iterate through each resource in the search set and evaluate #consent based on the resource and user/roles. #Each row marked as deleted and saved will be excluded from the Bundle. rs._SetIterator(0) while rs._Next(): if not self.consent(rs.ResourceType, self.requesting_user, self.requesting_roles): #Mark the row as deleted and save it. rs.MarkAsDeleted() rs._SaveRow() def consent(self, resource_type, user, roles): #Example consent logic - only allow users with the role '%All' to see #Observation resources. if resource_type == 'Observation': if '%All' in roles: return True else: return False else: return True Based on https://community.intersystems.com/post/iris-fhir-python-strategy
go to post Guillaume Rongier · Jul 13, 2023 That how i read Stream and Write stream with Embedded Python : Read Stream : def stream_to_string(stream)-> str: string = "" stream.Rewind() while not stream.AtEnd: string += stream.Read(1024) return string Write Stream : def string_to_stream(string:str): stream = iris.cls('%Stream.GlobalCharacter')._New() n = 1024 chunks = [string[i:i+n] for i in range(0, len(string), n)] for chunk in chunks: stream.Write(chunk) return stream