Mercurial > hgweb > health
changeset 4870:9ca2d96e5978
task #16043: Migration to GNU Health 4.0: Migrate and cleanup health_federation
| author | Luis Falcon <falcon@gnuhealth.org> |
|---|---|
| date | Sat, 15 Jan 2022 08:44:34 +0000 |
| parents | ad65bace8f56 |
| children | 0e5a7dae2008 |
| files | tryton/health_federation/__init__.py tryton/health_federation/health_federation.py tryton/health_federation/tryton.cfg tryton/health_federation/view/gnuhealth_federation_queue_tree.xml |
| diffstat | 4 files changed, 135 insertions(+), 108 deletions(-) [+] |
line wrap: on
line diff
--- a/tryton/health_federation/__init__.py +++ b/tryton/health_federation/__init__.py @@ -23,7 +23,7 @@ """ health_federation package: HMIS Federation manager -This package is responsible to communicate the GNU Health HMIS +This package is responsible to communicate the GNU Health HMIS with Thalamus, the Federation message server. The main functionalities of the package are : @@ -36,14 +36,14 @@ """ from trytond.pool import Pool -from .health_federation import * +from . import health_federation def register(): Pool.register( - FederationNodeConfig, - FederationQueue, - FederationObject, - PartyFed, - PoLFed, + health_federation.FederationNodeConfig, + health_federation.FederationQueue, + health_federation.FederationObject, + health_federation.PartyFed, + health_federation.PoLFed, module='health_federation', type_='model')
--- a/tryton/health_federation/health_federation.py +++ b/tryton/health_federation/health_federation.py @@ -20,45 +20,50 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. # -import ssl from trytond.model import ModelView, ModelSQL, ModelSingleton, fields, Unique -from trytond.transaction import Transaction from trytond.pool import Pool -from trytond.pyson import Eval, Not, Bool, PYSONEncoder, Equal, And, Or, If +from trytond.pyson import Eval, Equal import requests import json from uuid import uuid4 from trytond.rpc import RPC from datetime import datetime, date +from trytond.modules.health.core import get_institution -__all__ = ['FederationNodeConfig','FederationQueue', 'FederationObject', - 'PartyFed','PoLFed'] +__all__ = [ + 'FederationNodeConfig', 'FederationQueue', 'FederationObject', + 'PartyFed', 'PoLFed'] def set_fsync(model, records, flag): - #Sets or disables the fsync flag that enables the record to be - #enter in the Federation queue + # Sets or disables the fsync flag that enables the record to be + # enter in the Federation queue vals = {'fsync': flag} model.write(records, vals) + class FederationNodeConfig(ModelSingleton, ModelSQL, ModelView): 'Federation Node Configuration' __name__ = 'gnuhealth.federation.config' - host = fields.Char('Thalamus server', required=True, + host = fields.Char( + 'Thalamus server', required=True, help="GNU Health Thalamus server") port = fields.Integer('Port', required=True, help="Thalamus port") - user = fields.Char('User',required=True, + user = fields.Char( + 'User', required=True, help="Admin associated to this institution") - password = fields.Char('Password', required=True, + password = fields.Char( + 'Password', required=True, help="Password of the institution admin user in the Federation") - ssl = fields.Boolean('SSL', - help="Use encrypted communication via SSL") - verify_ssl = fields.Boolean('Verify SSL cert', - help="Check this option if your certificate has been emitted" \ - " by a CA authority. If it is a self-signed certifiate" \ - " leave it unchecked") - enabled = fields.Boolean('Enabled', help="Mark if the node is active" \ + ssl = fields.Boolean('SSL', help="Use encrypted communication via SSL") + verify_ssl = fields.Boolean( + 'Verify SSL cert', + help="Check this option if your certificate has been emitted" + " by a CA authority. If it is a self-signed certifiate" + " leave it unchecked") + enabled = fields.Boolean( + 'Enabled', help="Mark if the node is active" " in the Federation") # TODO: Check the associated institution and use as @@ -120,7 +125,8 @@ url = protocol + host + ':' + str(port) + '/people/' + user try: - conn = requests.get(url, + conn = requests.get( + url, auth=(user, password), verify=verify_ssl) except: @@ -135,7 +141,7 @@ @classmethod def get_conn_params(cls): # Retrieve the connection information for Thalamus - #Retrieve the information from the Singleton object + # Retrieve the information from the Singleton object TInfo = Pool().get(cls.__name__)(1) host = TInfo.host @@ -152,24 +158,30 @@ return host, port, user, password, ssl_conn, verify_ssl, protocol + class FederationQueue(ModelSQL, ModelView): 'Federation Queue' __name__ = 'gnuhealth.federation.queue' - msgid = fields.Char('Message ID', required=True, + msgid = fields.Char( + 'Message ID', required=True, help="Message UID") model = fields.Char('Model', required=True, help="Source Model") - node = fields.Char('Node', required=True, + node = fields.Char( + 'Node', required=True, help="The originating node id") - time_stamp = fields.Char('Timestamp', required=True, + time_stamp = fields.Char( + 'Timestamp', required=True, help="UTC timestamp at the moment of writing record on the node") - federation_locator = fields.Char('Fed ID', + federation_locator = fields.Char( + 'Fed ID', help="Unique locator in Federation, " "such as person Federation account or Page of Life code") - args = fields.Text('Arguments', required=True, + args = fields.Text( + 'Arguments', required=True, help="Arguments") method = fields.Selection([ @@ -178,7 +190,7 @@ ('PATCH', 'PATCH'), ('DELETE', 'DELETE'), ('GET', 'GET'), - ], 'Method', required=True,sort=False) + ], 'Method', required=True, sort=False) state = fields.Selection([ (None, ''), @@ -187,17 +199,18 @@ ('failed', 'Failed'), ], 'Status', sort=False) - url_suffix = fields.Char('URL suffix', + url_suffix = fields.Char( + 'URL suffix', help="suffix to be passed to the URL") @staticmethod def default_node(): # Get the Institution code as the originating node. HealthInst = Pool().get('gnuhealth.institution') - institution = HealthInst.get_institution() + institution = get_institution() if (institution): - #Get the institution code associated to the ID + # Get the institution code associated to the ID institution_code = HealthInst(institution).code else: @@ -207,16 +220,15 @@ return institution_code @classmethod - def send_record(cls,record): + def send_record(cls, record): rc = False host, port, user, password, ssl_conn, verify_ssl, protocol = \ FederationNodeConfig.get_conn_params() - if (record.method == 'PATCH'): if (record.federation_locator): - #Traverse each resource and its data fields. + # Traverse each resource and its data fields. # arg : Dictionary for each of the data elements in the # list of values # [{resource, fields[{name, value}] @@ -226,7 +238,8 @@ modification_info = {} # Include the modification information - modification_info = {'user':user, \ + modification_info = { + 'user': user, 'timestamp': record.time_stamp, 'node': record.node} @@ -242,21 +255,22 @@ for field in fields: fname, fvalue = field['name'], field['value'] - vals[fname]= fvalue + vals[fname] = fvalue - send_data = requests.request('PATCH',url, - data=json.dumps(vals), \ + send_data = requests.request( + 'PATCH', url, + data=json.dumps(vals), auth=(user, password), verify=verify_ssl) if (send_data): rc = True else: - print ("No federation record locator found .. no update") + print("No federation record locator found .. no update") # Create the record on the Federation if (record.method == 'POST'): if (record.federation_locator): - #Traverse each resource and its data fields. + # Traverse each resource and its data fields. # arg : Dictionary for each of the data elements in the # list of values # [{resource, fields[{name, value}] @@ -266,7 +280,8 @@ creation_info = {} # Include the creation information - creation_info = {'user':user, \ + creation_info = { + 'user': user, 'timestamp': record.time_stamp, 'node': record.node} @@ -282,21 +297,22 @@ for field in fields: fname, fvalue = field['name'], field['value'] - vals[fname]= fvalue + vals[fname] = fvalue - send_data = requests.request('POST',url, - data=json.dumps(vals), \ + send_data = requests.request( + 'POST', url, + data=json.dumps(vals), auth=(user, password), verify=verify_ssl) if (send_data): rc = True else: - print ("No federation record locator found .. no update") + print("No federation record locator found .. no update") return rc @classmethod - def parse_fields(cls,values,action,fields): + def parse_fields(cls, values, action, fields): ''' Returns, depending on the action, the fields that will be passed as arguments to Thalamus ''' @@ -308,15 +324,15 @@ fedvals = [] fed_key = {} - n=0 + n = 0 for val in field_mapping: - #Retrieve the field name, the federation resource name - #and the associated federation resource field . - #string of the form field:fed_resource:fed_field + # Retrieve the field name, the federation resource name + # and the associated federation resource field . + # string of the form field:fed_resource:fed_field field, fed_resource, fed_field = val.split(':') if (field in values.keys()): - #Check that the local field is on shared federation list - #and retrieve the equivalent federation field name + # Check that the local field is on shared federation list + # and retrieve the equivalent federation field name # Optimize the process, by not duplicating the resources # Each resource will appear just once, with the list of @@ -331,10 +347,10 @@ if fed_resource not in resources: fed_key = { "resource": fed_resource, - "fields":[ + "fields": [ { - "name": fed_field, - "value": values[field] + "name": fed_field, + "value": values[field] }] } @@ -345,30 +361,31 @@ # Otherwise, if the resource exists on the list, # we add the new field values to it. - n=0 + n = 0 for record in fedvals: if fed_resource == record['resource']: - fedvals[n]['fields'].append({"name": fed_field, \ - "value": values[field]}) - n=n+1 + fedvals[n]['fields'].append( + {"name": fed_field, + "value": values[field]}) + n = n+1 return fedvals @classmethod - def enqueue(cls,model, federation_loc, time_stamp, node, values, - action, url_suffix): + def enqueue(cls, model, federation_loc, time_stamp, node, values, + action, url_suffix): fields = FederationObject.get_object_fields(model) # Federation locator : Unique ID of the resource # such as personal federation account or institution ID # it depends on the resource (people, PoL, institution, ... ) - #Remove spaces and newlines from fields - fields = fields.replace(" ","").replace("\n","") + # Remove spaces and newlines from fields + fields = fields.replace(" ", "").replace("\n", "") if (fields): # retrieve the federation field names and values in a dict - fields_to_enqueue = cls.parse_fields(values,action,fields) + fields_to_enqueue = cls.parse_fields(values, action, fields) # Continue the enqueue process with the fields if fields_to_enqueue: @@ -383,7 +400,7 @@ vals['federation_locator'] = federation_loc vals['url_suffix'] = url_suffix rec.append(vals) - #Write the record to the enqueue list + # Write the record to the enqueue list cls.create(rec) @classmethod @@ -391,8 +408,8 @@ super(FederationQueue, cls).__setup__() t = cls.__table__() cls._sql_constraints = [ - ('msgid_uniq', Unique(t,t.msgid), \ - 'The Message ID must be unique !'),] + ('msgid_uniq', Unique(t, t.msgid), + 'The Message ID must be unique !'), ] cls._buttons.update({ 'send': {'invisible': Equal(Eval('state'), 'sent')} @@ -420,11 +437,13 @@ model = fields.Char('Model', help="Local Model") - enabled = fields.Boolean('Enabled', help="Check if the model" \ + enabled = fields.Boolean( + 'Enabled', help="Check if the model" " is active to participate on the Federation") - fields = fields.Text('Fields', help="Contains a list of " - "the local model fields that participate on the federation.\n" \ + fields = fields.Text( + 'Fields', help="Contains a list of " + "the local model fields that participate on the federation.\n" "Each line will have the format field:endpoint:key") @staticmethod @@ -433,8 +452,9 @@ @classmethod def get_object_fields(cls, obj): - model, = cls.search_read([("model", "=", obj)], - limit=1, fields_names=['fields','enabled']) + model, = cls.search_read( + [("model", "=", obj)], + limit=1, fields_names=['fields', 'enabled']) # If the model exist on the Federation Object, # and is currently enabled, return the field names and their @@ -454,6 +474,7 @@ 'get_object_fields': RPC(check_access=False), }) + class PartyFed(ModelSQL): """ Demographics Model to participate on the Federation @@ -466,9 +487,10 @@ # Controls if the updated information will be sent to the Federation. # True: Info will be sent to the federation queue # False: The info is up-todate with the federation or is local - fsync = fields.Boolean('Fsync', - help="If active, this record information will" \ - " be sent to the Federation") + fsync = fields.Boolean( + 'Fsync', + help="If active, this record information will" + " be sent to the Federation") @staticmethod def default_fsync(): @@ -476,7 +498,7 @@ @classmethod def write(cls, parties, values): - #First exec the Party class write method from health package + # First exec the Party class write method from health package super(PartyFed, cls).write(parties, values) for party in parties: @@ -489,19 +511,20 @@ if (fed_acct and values): if (fsync or 'fsync' not in values.keys()): # Start Enqueue process - node=None - #Because du_address is a functional field + node = None + # Because du_address is a functional field # does not exist at DB level, we always pass the # latest / current value values['du_address'] = party.du_address time_stamp = party.write_date url_suffix = fed_acct - FederationQueue.enqueue(cls.__name__, - fed_acct, time_stamp, node, values,action, + FederationQueue.enqueue( + cls.__name__, + fed_acct, time_stamp, node, values, action, url_suffix) - #Unset the fsync flag locally once the info has been - #sent to the Federation queue + # Unset the fsync flag locally once the info has been + # sent to the Federation queue set_fsync(cls, parties, False) @classmethod @@ -523,27 +546,29 @@ # record to be sent and created in the Federation if fed_acct and fsync: - action="POST" - node=None + action = "POST" + node = None - #Because du_address is a functional field + # Because du_address is a functional field # does not exist at DB level, we always pass the # latest / current value values['du_address'] = parties[0].du_address url_suffix = fed_acct time_stamp = parties[0].create_date - FederationQueue.enqueue(cls.__name__, + FederationQueue.enqueue( + cls.__name__, fed_acct, time_stamp, node, values, - action,url_suffix) + action, url_suffix) - #Unset the fsync flag locally once the info has been - #sent to the Federation queue + # Unset the fsync flag locally once the info has been + # sent to the Federation queue if (fsync): set_fsync(cls, parties, False) return parties + class PoLFed(ModelSQL): """ Page of Life Model to participate on the Federation @@ -556,9 +581,10 @@ # Controls if the updated information will be sent to the Federation. # True: Info will be sent to the federation queue # False: The info is up-todate with the federation or is local - fsync = fields.Boolean('Fsync', - help="If active, this record information will" \ - " be sent to the Federation") + fsync = fields.Boolean( + 'Fsync', + help=" If active, this record information will" + " be sent to the Federation") @staticmethod def default_fsync(): @@ -580,18 +606,18 @@ if (fed_identifier and values): if (fsync or 'fsync' not in values.keys()): # Start Enqueue process - node=None + node = None time_stamp = pol.write_date url_suffix = federation_account + '/' + fed_identifier - FederationQueue.enqueue(cls.__name__, + FederationQueue.enqueue( + cls.__name__, fed_identifier, time_stamp, node, values, action, url_suffix) - #Unset the fsync flag locally once the info has been - #sent to the Federation queue + # Unset the fsync flag locally once the info has been + # sent to the Federation queue set_fsync(cls, pols, False) - @classmethod def create(cls, vlist): vlist = [x.copy() for x in vlist] @@ -611,16 +637,17 @@ # record to be sent and created in the Federation if fed_identifier and fsync: - action="POST" - node=None + action = "POST" + node = None time_stamp = pols[0].create_date url_suffix = federation_account + '/' + fed_identifier - FederationQueue.enqueue(cls.__name__, + FederationQueue.enqueue( + cls.__name__, fed_identifier, time_stamp, node, values, action, url_suffix) - #Unset the fsync flag locally once the info has been - #sent to the Federation queue + # Unset the fsync flag locally once the info has been + # sent to the Federation queue if (fsync): set_fsync(cls, pols, False)
--- a/tryton/health_federation/tryton.cfg +++ b/tryton/health_federation/tryton.cfg @@ -1,5 +1,5 @@ [tryton] -version=3.8.0 +version=3.9.0 depends: health xml:
--- a/tryton/health_federation/view/gnuhealth_federation_queue_tree.xml +++ b/tryton/health_federation/view/gnuhealth_federation_queue_tree.xml @@ -1,5 +1,5 @@ <?xml version="1.0"?> -<tree editable="top"> +<tree editable="1"> <field name="state"/> <button name="send" help="Send the record to the Federation" string="Send"/> <field name="time_stamp"/>
