def save(self, subject, protocol): if self.is_valid(): cleaned_data = self.cleaned_data # Legacy Information old_subject = deepcopy(subject) old_subject.organization_id old_subject.group_name = SubjectUtils.protocol_subject_record_group_name(protocol, old_subject) # Updated Information subject.old_subject = old_subject subject.first_name = cleaned_data.get('first_name') subject.last_name = cleaned_data.get('last_name') subject.dob = cleaned_data.get('dob') subject.organization_subject_id = cleaned_data.get('subject_id') org = self.getOrgFromSelection(cleaned_data.get('organization')) subject.organization_id = org.id srh = ServiceClient.get_rh_for(record_type=ServiceClient.SUBJECT) subject.group_name = SubjectUtils.protocol_subject_record_group_name(protocol, subject) r = srh.update(subject)[0] if SubjectUtils.create_protocol_subject_record_group(protocol, subject): SubjectUtils.delete_protocol_subject_record_group(protocol, old_subject) success = r.get('success') errors = r.get('errors') return [success, subject, errors] else: return None
def cache_records(self): datasources = DataSource.objects.all() protocols = Protocol.objects.all() er_rh = ServiceClient.get_rh_for(record_type=ServiceClient.EXTERNAL_RECORD) for ds in datasources: try: ers = er_rh.query({'external_system_id': ds.ehb_service_es_id})[0]['external_record'] except: print 'failed retrieval of records from external system: {0}'.format(ds) for record in ers: cache.set('externalrecord_{0}'.format(record.id), record.json_from_identity(record)) # Make sure key lasts a day cache.expire('externalrecord_{0}'.format(record.id), 60*60*24) for protocol in protocols: subs = protocol.getSubjects() if subs: subs_dict = [json.loads(subject.json_from_identity(subject)) for subject in subs] for sub in subs: sub_records = [] for record in ers: if record.subject_id == sub.id: sub_records.append(json.loads(record.json_from_identity(record))) ck = '{0}_{1}_externalrecords'.format(protocol.id, sub.id) cache.set(ck, json.dumps(sub_records)) cache.expire(ck, 60*60*24) print 'Caching of ExternalRecords complete'
def getExternalIdentifiers(pds, subject, labels): er_rh = ServiceClient.get_rh_for(record_type=ServiceClient.EXTERNAL_RECORD) ck = '{0}_{1}_externalrecords'.format(pds.protocol.id, subject.id) # See if our records are in the cache. resp = cache.get(ck) if resp: pds_records = [] for record in json.loads(resp): if record['external_system'] == pds.id: pds_records.append( ExternalRecord(-1).identity_from_jsonObject(record)) else: try: pds_records = er_rh.get(external_system_url=pds.data_source.url, path=pds.path, subject_id=subject.id) except PageNotFound: pds_records = [] for ex_rec in pds_records: for label in labels: if ex_rec.label_id == label['id']: if label['label'] == '': ex_rec.label_desc = 'Record' else: ex_rec.label_desc = label['label'] return pds_records
def getEhbServiceInstance(self): ''' Gets the record for this organization as maintained in the ehb service PageNotFound Exception will be thrown if no record is found ''' rh = ServiceClient.get_rh_for(record_type=ServiceClient.ORGANIZATION) return rh.get(name=self.name)
def getOrgFromSelection(self, selection): # This is the organization object in the local portal app db _org = protocols.Organization.objects.get(pk=selection) _org_name = _org.name # the ehb-service organization object this is guaranteed to have the correct id orh = ServiceClient.get_rh_for(record_type=ServiceClient.ORGANIZATION) return orh.get(name=_org_name)
def clean(self): rh = ServiceClient.get_rh_for(record_type=ServiceClient.EXTERNAL_SYSTEM) try: json.loads(self.driver_configuration) except ValueError: msg = ('Please enter a valid JSON object in Driver Configuration Options. ' + 'If there is no configuration enter "{}"') raise ValidationError(msg)
def getProtocolGroup(self, protocol): gh = ServiceClient.get_rh_for(record_type=ServiceClient.GROUP) ck = self._settings_prop('CLIENT_KEY', 'key', '') n = 'BRP:'+protocol.immutable_key.key grp = gh.get(name=n) grp.client_key = ck # grp = Group(name = n, description = 'A BRP Protocol Group', is_locking=True, client_key=ck) # gh.create(grp) return (gh, grp)
def getSubjects(self): ''' Returns the ehb-service representation of the subjects that have external_records for this data_source ''' es = self.getExternalSystem() if es: rh = ServiceClient.get_rh_for(record_type=ServiceClient.EXTERNAL_SYSTEM) return rh.subjects(es.id)
def cache_records(self): datasources = DataSource.objects.all() er_rh = ServiceClient.get_rh_for( record_type=ServiceClient.EXTERNAL_RECORD) for ds in datasources: ers = er_rh.query({'external_system_id': ds.ehb_service_es_id})[0]['external_record'] for record in ers: print record.record_id
def delete_old_ehb_entities(self): ''' This will remove the external_system entry for this protocol and the uneeded external records ''' try: esrh = ServiceClient.get_rh_for(record_type=ServiceClient.EXTERNAL_SYSTEM) brp = esrh.get(url=ServiceClient.APP_URL) errh = ServiceClient.get_rh_for(record_type=ServiceClient.EXTERNAL_RECORD) print 'deleting records on external system: {0}'.format(brp.name) errh.delete(external_system_id=brp.id) print 'deleting external system: {0}'.format(brp.name) esrh.delete(id=brp.id) except PageNotFound: # This only happens if NO records are found when making the record # requests, indicates there are no subjects print '******** page not found in delete old ehb entities'
def migrate_subject(self, subject, protocol): try: # Create a Group for this subject / protocol combination orh = ServiceClient.get_rh_for(record_type=ServiceClient.ORGANIZATION) ehb_org = orh.get(id=subject.organization_id) brp_org = Organization.objects.get(name=ehb_org.name) gh = ServiceClient.get_rh_for(record_type=ServiceClient.GROUP) ck = self._settings_prop('CLIENT_KEY', 'key', '') n = 'BRP:'+protocol.immutable_key.key+':'+brp_org.immutable_key.key+':'+subject.organization_subject_id grp = Group(name=n, description='A BRP Protocol Subject Record Group', is_locking=True, client_key=ck) gh.create(grp) print 'created subject records group: {0} for subject: {1} on protocol: {2}'.format( n, subject.organization_subject_id, protocol.name) # Add the subjects records to this group errh = ServiceClient.get_rh_for(record_type=ServiceClient.EXTERNAL_RECORD) records = errh.get(subject_id=subject.id, path=protocol.name) print 'subject {0}, {1}, id={2} has the following records:'.format( subject.last_name, subject.first_name, subject.id) for rec in records: print 'id={0}, path={1}, ex_sys_id={2}, subject_id={3}'.format( rec.id, rec.path, rec.external_system_id, rec.subject_id ) gh.add_records(grp, records) print 'added {0} records for subject: {1} on protocol: {2} to group: {3}'.format( len(records), subject.organization_subject_id, protocol.name, grp.name ) except Exception: print '********failed to move subject records for ', subject.organization_subject_id
def getExternalSystem(self): ''' This returns the ehb-service representation of this DataSource ''' rh = ServiceClient.get_rh_for(record_type=ServiceClient.EXTERNAL_SYSTEM) es = rh.get(url=self.url) if es: if es.id != self.ehb_service_es_id: # The record id's changed on the ehb-service, so update self.ehb_service_es_id = es.id self.save() return es
def create_new_ehb_external_record(protocol_data_source, user, subject, record_id, label=None): ''' Creates a new external record in the ehb-service for this data source, subject, record_id and Output ------ If successful returns the ehb_client.external_record_request_handler.ExternalRecord object ''' es = protocol_data_source.data_source.getExternalSystem() # Want to make sure we're not going to overwrite a record already in the system try: if not label: label = 1 er = ExternalRecord( record_id=record_id, subject_id=subject.id, external_system_id=es.id, path=protocol_data_source.path, label_id=label ) errh = ServiceClient.get_rh_for( record_type=ServiceClient.EXTERNAL_RECORD ) response = errh.create(er)[0] if(response.get('success')): SubjectUtils.add_record_to_subject_record_group( protocol_data_source.protocol, subject, er ) return er else: errors = response.get('errors') raise RecordCreationError( 'electronic Honest Broker', '', record_id, errors ) except RecordCreationError as rce: raise rce except Exception as e: raise RecordCreationError( 'electronic Honest Broker', '', record_id, str(e) )
def delete_protocol_subject_record_group(protocol, subject): try: n = SubjectUtils.protocol_subject_record_group_name(protocol, subject) gh = ServiceClient.get_rh_for(record_type=ServiceClient.GROUP) ck = protocol._settings_prop('CLIENT_KEY', 'key', '') grp = Group( name=n, description='A BRP Protocol Subject Record Group', is_locking=True, client_key=ck ) r = gh.delete(grp) return r[0].get('success') except: return False
def notify_record_creation_listeners(notifier, notifier_rec_id, notifier_pds, user, subject_id): ''' Inputs: notifier : the driver that created the new record notifier_rec_id : the record in in the external system (not the eHB id) notifier_pds : the protocol data source where the new record was created subject_id : the eHB subject record id (not the organization subject id) ''' # get the data link plugin selections for link in ProtocolDataSourceLink.objects.all(): mod_name = link.linker_module() mod = __import__(mod_name) the_split = mod_name.split('.') subname = '.' for i in range(len(the_split) - 1): subname += the_split[i + 1] + '.' listener = None cmd = 'listener = mod' + subname + link.linker_class() + '()' exec(cmd) do_notify = 0 in listener.notify_on() if do_notify: listener_pds = None if notifier_pds == link.pds_one: listener_pds = link.pds_two else: listener_pds = link.pds_one listener_driver = DriverUtils.getDriverFor( protocol_data_source=listener_pds, user=user) listener.set_listener(listener_driver) es_url = listener_pds.data_source.url # Get the ehb-service external-records, it has the record-id for # the pds er_rh = ServiceClient.get_rh_for( record_type=ServiceClient.EXTERNAL_RECORD) try: records = er_rh.get(external_system_url=es_url, subject_id=subject_id, path=listener_pds.path) if len(records) == 1: listener.set_listener_rec_id(records[0].record_id) except PageNotFound: listener.set_listener_rec_id(None) listener.notify(notifier, notifier_rec_id)
def save(self, *args, **kwargs): ''' On save we need to make sure this organization exists in the ehb-service, otherwise create it ''' rh = ServiceClient.get_rh_for(record_type=ServiceClient.ORGANIZATION) try: org = rh.get(name=self.name) super(Organization, self).save(*args, **kwargs) except PageNotFound: org = Organization(name=self.name, subject_id_label=self.subject_id_label) r = rh.create(org)[0] if(r.get('success')): super(Organization, self).save(*args, **kwargs) else: raise Exception('Unable to create Organization record in ehb-service')
def create_protocol_subject_record_group(protocol, subject): try: n = SubjectUtils.protocol_subject_record_group_name(protocol, subject) gh = ServiceClient.get_rh_for(record_type=ServiceClient.GROUP) ck = protocol._settings_prop('CLIENT_KEY', 'key', '') grp = Group( name=n, description='A BRP Protocol Subject Record Group', is_locking=True, client_key=ck ) r = gh.create(grp) return r[0].get('success') except: logger.error("Failure creating a subject record group for {0}".format(n)) return False
def save(self, *args, **kwargs): super(Protocol, self).save(*args, **kwargs) # Need to create a group for this protocol if it doesn't exist # (i.e. before there is a pk) that will be used to identify subjects # on the protocol gh = ServiceClient.get_rh_for(record_type=ServiceClient.GROUP) try: gh.get(name=self.ehb_group_name()) except RequestedRangeNotSatisfiable: grp = Group( name=self.ehb_group_name(), description='A BRP Protocol Group', is_locking=True, client_key=self._client_key() ) r = gh.create(grp)[0] if not (r.get("success")): raise Exception( 'Unable to create Protocol Subject Group in ehb-service')
def getPDSSubject(pds, sub_id): ck = '{0}_subjects'.format(pds.protocol.id) resp = cache.get(ck) if resp: subs = json.loads(resp) for subject in subs: if subject['id'] == int(sub_id): return Subject(-1).identity_from_jsonObject(subject) else: try: s_rh = ServiceClient.get_rh_for(record_type=ServiceClient.SUBJECT) subject = s_rh.get(id=sub_id) if not pds.protocol.isSubjectOnProtocol(subject): raise Http404 else: return subject except PageNotFound: raise Http404 return None
def save(self, *args, **kwargs): ''' On save we need to make sure this source exists in the ehb service, otherwise create it ''' rh = ServiceClient.get_rh_for(record_type=ServiceClient.EXTERNAL_SYSTEM) try: es = rh.get(url=self.url) self.ehb_service_es_id = es.id super(DataSource, self).save(*args, **kwargs) except PageNotFound: es = ExternalSystem( name=self.name, url=self.url, description=self.description ) r = rh.create(es)[0] if(r.get('success')): self.ehb_service_es_id = es.id super(DataSource, self).save(*args, **kwargs) else: raise Exception('Unable to create ExternalSystem record in ehb-service')
def validate_new_record_id(protocol_data_source, subject, record_id, include_path): ''' Checks if the record_id (an external system record id, not the eHB record id) is acceptable by eHB uniqueness rules. If yes, returns 0. Else returns: 1 : record id already exists for this subject on this protocoldatasource 2 : record id exists for this protocoldatasource for a different subject. ''' er_rh = ServiceClient.get_rh_for(record_type=ServiceClient.EXTERNAL_RECORD) try: ehb_recs = None if include_path: ehb_recs = er_rh.get( external_system_url=protocol_data_source.data_source.url, path=protocol_data_source.path ) else: ehb_recs = er_rh.get( external_system_url=protocol_data_source.data_source.url ) for record in ehb_recs: if record.record_id == record_id: if record.subject_id == subject.id: logger.error( 'Record id {0} already exists for subject {1} on datasource {2}'.format( record.record_id, subject.id, protocol_data_source)) return 1 else: logger.error('Record id {0} already exists for a different Subject'.format(record.record_id)) return 2 return 0 except PageNotFound: return 0
def clean(self): rh = ServiceClient.get_rh_for(record_type=ServiceClient.EXTERNAL_SYSTEM) try: es = rh.get(url=self.url) if(self.name != es.name): self.name = es.name msg = ('Accept existing name? There is already a system in the' + ' ehb-service with this URL but with the name: ' + es.name + '. This DataSource can only be saved with that name.') raise ValidationError(msg) except PageNotFound: # The save method will create the record in the ehb-service pass try: es = rh.get(name=self.name) if(self.url != es.url): msg = ('Please change the name or correct the URL. There is ' + 'already a system in the ehb-service with this name but' + ' with URL: ' + es.url) raise ValidationError(msg) except PageNotFound: # The save method will create the record in the ehb-service pass
def pds_dataentry_list(request, pds_id, subject_id): ''' renders a page with the list of current records in the procotol_data_source with id = pds_id for the Subject with ehb-service id = subject_id. The exact form of this page is protocol_data_source dependent as determined by the driver ''' pds = getProtocolDataSource(pds_id) if not pds.protocol.isUserAuthorized(request.user): return forbidden(request) MANAGE_EXTERNAL_IDS = False er_label_rh = ServiceClient.get_rh_for( record_type=ServiceClient.EXTERNAL_RECORD_LABEL) lbls = er_label_rh.query() # Check to see if this PDS is managing external identifiers for _pds in pds.protocol.getProtocolDataSources(): if _pds.driver == 3: ExIdSource = _pds MANAGE_EXTERNAL_IDS = True subject = getPDSSubject(pds=pds, sub_id=subject_id) # If we are managing external identifiers add them to the subject if MANAGE_EXTERNAL_IDS: subject.external_ids = getExternalIdentifiers(ExIdSource, subject, lbls) o_rh = ServiceClient.get_rh_for(record_type=ServiceClient.ORGANIZATION) org = o_rh.get(id=subject.organization_id) es_url = pds.data_source.url # Get record ids for this (protocol, subject, data source) combination er_rh = ServiceClient.get_rh_for(record_type=ServiceClient.EXTERNAL_RECORD) er_label_rh = ServiceClient.get_rh_for( record_type=ServiceClient.EXTERNAL_RECORD_LABEL) if request.method == 'GET': record_list_html = '<div class="alert alert-info"><h4>No records found.</h4></div>' allow_more_records = False labels = filterLabels(pds, er_label_rh.query()) try: records = er_rh.get(external_system_url=es_url, subject_id=subject_id, path=pds.path) records.sort(key=lambda x: x.created) records = [ json.loads(record.json_from_identity(record)) for record in records ] allow_more_records = pds.max_records_per_subject == ( -1) or len(records) < pds.max_records_per_subject if len(records) > 0: prefix = '%s/dataentry/protocoldatasource/%s/subject/%s/record/' % ( ServiceClient.self_root_path, pds.id, subject.id) record_urls = [ '%s%s/start/' % (prefix, each['id']) for each in records ] driver = DriverUtils.getDriverFor(protocol_data_source=pds, user=request.user) record_list_html = driver.recordListForm( record_urls, records, labels) except PageNotFound: allow_more_records = pds.max_records_per_subject != 0 authorized_sources, unauthorized_sources = _auth_unauth_source_lists( pds.protocol, request.user, pds) # TODO ADD A BOOLEAN ALLOW_CREATE_MORE_RECORDS = # pds.max_recrods_allowed < 0 or pds.max_records_allowed < len(records) # and pass this to render_to_response method to decide to show/hide create # button context = { 'protocol': pds.protocol, 'organization': org, 'subject': subject, 'root_path': ServiceClient.self_root_path, 'pds': pds, 'authorized_data_sources': authorized_sources, 'unauthorized_data_sources': unauthorized_sources, 'record_list_html': record_list_html, 'allow_more_records': allow_more_records, 'record_labels': labels, 'redcap_status': getRedcapStatus() } resp = render_to_response('pds_dataentry_list.html', context, context_instance=RequestContext(request)) return resp if request.method == 'POST': try: data = json.loads(request.body) except: return HttpResponse(json.dumps({'status': 'error'}), 400) record = er_rh.get(id=data['er']) record.label_id = int(data['label_id']) er_rh.update(record) return HttpResponse(json.dumps({'status': 'ok'}), 200)
def protocol_subject_record_group_name(protocol, subject): orh = ServiceClient.get_rh_for(record_type=ServiceClient.ORGANIZATION) ehb_org = orh.get(id=subject.organization_id) brp_org = Organization.objects.get(name=ehb_org.name) return 'BRP:' + protocol.immutable_key.key + ':' +\ brp_org.immutable_key.key + ':' + subject.organization_subject_id
def get_protocol_subject_record_group(protocol, subject): gh = ServiceClient.get_rh_for(record_type=ServiceClient.GROUP) return gh.get( name=SubjectUtils.protocol_subject_record_group_name(protocol, subject) )
def getProtocolSubjects(self, protocol): '''returns the Subject records for this protocol''' try: esrh = ServiceClient.get_rh_for(record_type=ServiceClient.EXTERNAL_SYSTEM) es = esrh.get(url=ServiceClient.APP_URL) return esrh.subjects(es.id, path=protocol.name) except PageNotFound: # This only happens if NO records are found when making the record # requests, indicates there are no subjects print '******** page not found for {0}, in get protocol subjects'.format(protocol.name) def migrate_subject(self, subject, protocol): try: # Create a Group for this subject / protocol combination orh = ServiceClient.get_rh_for(record_type=ServiceClient.ORGANIZATION) ehb_org = orh.get(id=subject.organization_id) brp_org = Organization.objects.get(name=ehb_org.name) gh = ServiceClient.get_rh_for(record_type=ServiceClient.GROUP) ck = self._settings_prop('CLIENT_KEY', 'key', '') n = 'BRP:'+protocol.immutable_key.key+':'+brp_org.immutable_key.key+':'+subject.organization_subject_id grp = Group(name=n, description='A BRP Protocol Subject Record Group', is_locking=True, client_key=ck) gh.create(grp) print 'created subject records group: {0} for subject: {1} on protocol: {2}'.format( n, subject.organization_subject_id, protocol.name) # Add the subjects records to this group errh = ServiceClient.get_rh_for(record_type=ServiceClient.EXTERNAL_RECORD) records = errh.get(subject_id=subject.id, path=protocol.name) print 'subject {0}, {1}, id={2} has the following records:'.format( subject.last_name, subject.first_name, subject.id) for rec in records: print 'id={0}, path={1}, ex_sys_id={2}, subject_id={3}'.format( rec.id, rec.path, rec.external_system_id, rec.subject_id ) gh.add_records(grp, records) print 'added {0} records for subject: {1} on protocol: {2} to group: {3}'.format( len(records), subject.organization_subject_id, protocol.name, grp.name ) except Exception: print '********failed to move subject records for ', subject.organization_subject_id def migrate_orgs(self): for org in Organization.objects.all(): org.save() # This should generate the immutable keys def migrate(self): self.migrate_orgs() for protocol in Protocol.objects.all(): print '----------------------------------' print 'protocol ', protocol.name protocol.save() # This should cause the protocol to create key and create it's group print 'created immutable key: {0} for protocol {1}'.format( protocol.immutable_key.key, protocol.name) gh, group = self.getProtocolGroup(protocol) print 'created protocol subject group {0} with id={1}'.format( group.name, group.id) subjects = self.getProtocolSubjects(protocol) if subjects: print 'adding {0} subjects to protocol {1} using group {2}'.format( str(len(subjects)), protocol.name, group.name ) gh.add_subjects(group, subjects) for subject in subjects: self.migrate_subject(subject, protocol) else: print '********no subjects for protocol ', protocol.name print '----------------------------------' self.delete_old_ehb_entities() def handle(self, *args, **options): self.migrate()
def add_record_to_subject_record_group(protocol, subject, record): grp = SubjectUtils.get_protocol_subject_record_group(protocol, subject) grp.client_key = protocol._settings_prop('CLIENT_KEY', 'key', '') gh = ServiceClient.get_rh_for(record_type=ServiceClient.GROUP) gh.add_records(grp, [record])
def pds_dataentry_form(request, pds_id, subject_id, form_spec, record_id): '''renders a page with a data form as generated by the driver for protocol_data_source with pk=pds_id for Subject with subject_id=subject_id. The specific data form is determined by the driver using the form_spec arg. ''' def generateSubRecordForm(driver, external_record, form_spec, attempt_count, max_attempts): try: key = 'subrecordform_{0}_{1}'.format(external_record.id, form_spec) # Caching turned off for the time being on SRF # cf = cache.get(key) cf = None if cf: return cf else: form = driver.subRecordForm(external_record=external_record, form_spec=form_spec, session=request.session) return form except RecordDoesNotExist: return None pds = getProtocolDataSource(pds_id) if not pds.protocol.isUserAuthorized(request.user): return forbidden(request) MANAGE_EXTERNAL_IDS = False er_label_rh = ServiceClient.get_rh_for( record_type=ServiceClient.EXTERNAL_RECORD_LABEL) lbls = er_label_rh.query() # Check to see if this PDS is managing external identifiers for _pds in pds.protocol.getProtocolDataSources(): if _pds.driver == 3: ExIdSource = _pds MANAGE_EXTERNAL_IDS = True subject = getPDSSubject(pds=pds, sub_id=subject_id) # If we are managing external identifiers add them to the subject if MANAGE_EXTERNAL_IDS: subject.external_ids = getExternalIdentifiers(ExIdSource, subject, lbls) er_rh = ServiceClient.get_rh_for(record_type=ServiceClient.EXTERNAL_RECORD) # this will be the ehb-service externalRecord for this pds, subject NOT the actual datasource record record = None error_msgs = [] try: r = cache.get('externalrecord_{0}'.format(record_id)) if r: record = ExternalRecord(1).identity_from_jsonObject(json.loads(r)) else: record = er_rh.get(id=record_id) except PageNotFound: raise Http404 try: driver = DriverUtils.getDriverFor(protocol_data_source=pds, user=request.user) # Need the external record for this pds, protcol, and subject # Get all external_record objects on the ehb-service for this system, # path, subject combination. if request.method == 'POST': # have the driver process this request key = 'subrecordform_{0}_{1}'.format(record.id, form_spec) # cache.delete(key) errors = driver.processForm(request=request, external_record=record, form_spec=form_spec, session=request.session) if errors: error_msgs = [e for e in errors] else: path = '%s/dataentry/protocoldatasource/%s/subject/%s/record/%s/start/' % ( ServiceClient.self_root_path, pds.id, subject_id, record_id) return HttpResponseRedirect(path) else: # Generate a new form form = generateSubRecordForm(driver, record, form_spec, 0, 1) if form: o_rh = ServiceClient.get_rh_for( record_type=ServiceClient.ORGANIZATION) org = o_rh.get(id=subject.organization_id) form_submission_url = '%s/dataentry/protocoldatasource/%s/subject/%s/record/%s/form_spec/%s/' % ( ServiceClient.self_root_path, pds.id, subject_id, record_id, form_spec) # Find next form to support guided entry try: forms = json.loads(pds.driver_configuration)['form_order'] current_index = forms.index(form_spec) next_form = forms[current_index + 1] next_form_url = '%s/dataentry/protocoldatasource/%s/subject/%s/record/%s/form_spec/%s/' % ( ServiceClient.self_root_path, pds.id, subject_id, record_id, next_form) except: next_form_url = '' context = { 'subRecordForm': form, 'protocol': pds.protocol, 'organization': org, 'subject': subject, 'root_path': ServiceClient.self_root_path, 'pds': pds, 'form_submission_url': form_submission_url, 'next_form_url': next_form_url, 'rec_id': str(record_id), 'redcap_status': getRedcapStatus() } return render_to_response( 'pds_dataentry_srf.html', context, context_instance=RequestContext(request)) else: error_msgs.append( 'No record exists in the data source with the record id supplied by the eHB.' ) log.error('Error {0}'.format(' '.join(error_msgs))) except PageNotFound: error_msgs.append( 'No record could be found in the eHB for this request') log.error('Error {0}'.format(' '.join(error_msgs))) except ProtocolUserCredentials.DoesNotExist: error_msgs.append( 'Your user credentials were not found for %s. Please contact system administrator.' % pds.data_source.name) # Some error must have occured: log.error('Error {0}'.format(' '.join(error_msgs))) return HttpResponse(' '.join(error_msgs))
def pds_dataentry_create(request, pds_id, subject_id): '''renders a page with a data record creation form as generated by the driver for protocol_data_source with pk=pds_id for Subject with subject_id=subject_id. The specific record creation form is driver dependent - and not all drivers implement the form.''' pds = getProtocolDataSource(pk=pds_id) log.info( 'Attempting record creation for {0} on Protocol Datasource {1}'.format( subject_id, pds_id)) MANAGE_EXTERNAL_IDS = False # Check to see if this PDS is managing external identifiers for _pds in pds.protocol.getProtocolDataSources(): if _pds.driver == 3: ExIdSource = _pds MANAGE_EXTERNAL_IDS = True subject = getPDSSubject(pds=pds, sub_id=subject_id) er_label_rh = ServiceClient.get_rh_for( record_type=ServiceClient.EXTERNAL_RECORD_LABEL) lbls = er_label_rh.query() # If we are managing external identifiers add them to the subject if MANAGE_EXTERNAL_IDS: subject.external_ids = getExternalIdentifiers(ExIdSource, subject, lbls) es_url = pds.data_source.url # get record ids for this protocol, subject, data source combination er_rh = ServiceClient.get_rh_for(record_type=ServiceClient.EXTERNAL_RECORD) allow_more_records = False try: records = er_rh.get(external_system_url=es_url, subject_id=subject_id, path=pds.path) allow_more_records = pds.max_records_per_subject == ( -1) or len(records) < pds.max_records_per_subject except PageNotFound: allow_more_records = pds.max_records_per_subject != 0 if not allow_more_records: log.error('Maximum number of records created for subject {0}'.format( subject_id)) return HttpResponse( 'Error: The maximum number of records has been created.') if not pds.protocol.isUserAuthorized(request.user): return forbidden(request) def rec_id_validator(new_record_id, include_path): return SubjectUtils.validate_new_record_id(pds, subject, new_record_id, include_path) error_msgs = [] try: driver = DriverUtils.getDriverFor(protocol_data_source=pds, user=request.user) # TODO ADD A BOOLEAN ALLOW_CREATE_MORE_RECORDS = # pds.max_recrods_allowed < 0 or pds.max_records_allowed < len(records) # if false show error message if driver.new_record_form_required(): form_submission_url = '%s/dataentry/protocoldatasource/%s/subject/%s/create/' % ( ServiceClient.self_root_path, pds.id, subject_id) if request.method == 'POST': # have the driver process the record create form try: grp = SubjectUtils.get_protocol_subject_record_group( pds.protocol, subject) grp.client_key = pds.protocol._settings_prop( 'CLIENT_KEY', 'key', '') rec_id_prefix = '' data = extract_data_from_post_request(request) label_id = data.get('label_id', 1) label = er_label_rh.get(id=label_id) if grp: rec_id_prefix = grp.ehb_key else: log.error( 'Subject record group not found for {0}'.format( subject_id)) raise Exception('No subject record group found') try: rec_id = driver.process_new_record_form( request=request, record_id_prefix=rec_id_prefix, record_id_validator=rec_id_validator) try: notify_record_creation_listeners( driver, rec_id, pds, request.user, subject_id) # this will create the ehb external_record entry # and add that record to the subject's record group ehb_rec_id = SubjectUtils.create_new_ehb_external_record( pds, request.user, subject, rec_id, label_id).id path = '%s/dataentry/protocoldatasource/%s/subject/%s/record/%s/start/' % ( ServiceClient.self_root_path, pds.id, subject_id, ehb_rec_id) return HttpResponseRedirect(path) except RecordCreationError as rce: # exception from the eHB log.error(rce.errmsg) error_msgs.append( ('The record could not be created on the ' 'electronic Honest Broker. Please contact a ' 'system administrator. There could be a ' 'connection problem.')) except IgnoreEhbExceptions as iee: # TODO this is a hack until BRP can create Nautilus records rec_id = iee.record_id ehb_rec_id = '' path = None label_id = request.REQUEST.get('label_id', 1) label = er_label_rh.get(id=label_id) try: # this will create the ehb external_record entry # and add that record to the subject's record group ehb_rec = SubjectUtils.create_new_ehb_external_record( pds, request.user, subject, rec_id, label_id) ehb_rec_id = ehb_rec.id path = '%s/dataentry/protocoldatasource/%s/subject/%s/record/%s/start/' % ( ServiceClient.self_root_path, pds.id, subject_id, ehb_rec_id) notify_record_creation_listeners( driver, rec_id, pds, request.user, subject_id) except RecordCreationError as rce: # exception from the eHB log.error(rce.errmsg) record_already_exists = 6 cause = rce.raw_cause if cause and len( cause ) == 1 and record_already_exists == cause[0]: er_rh = ServiceClient.get_rh_for( record_type=ServiceClient.EXTERNAL_RECORD) ehb_recs = er_rh.get( external_system_url=pds.data_source.url, subject_id=subject_id, path=pds.path) ehb_rec_id = None for record in ehb_recs: if record.record_id == rec_id: ehb_rec_id = record.id if ehb_rec_id: path = '%s/dataentry/protocoldatasource/%s/subject/%s/record/%s/start' % ( ServiceClient.self_root_path, pds.id, subject_id, ehb_rec_id) else: path = None error_msgs.append( 'This Subject ID has already been assigned to another subject.' ) form = driver.create_new_record_form( request) o_rh = ServiceClient.get_rh_for( record_type=ServiceClient.ORGANIZATION) org = o_rh.get(id=subject.organization_id) label = er_label_rh.get(id=label_id) context = { 'recordCreateForm': form, 'protocol': pds.protocol, 'organization': org, 'subject': subject, 'root_path': ServiceClient.self_root_path, 'pds': pds, 'form_submission_url': form_submission_url, 'errors': error_msgs, 'label': label, 'redcap_status': getRedcapStatus() } return render_to_response( 'pds_dataentry_rec_create.html', context, context_instance=RequestContext( request)) else: log.error('Record could not be created') path = None error_msgs.append(( 'The record could not be created on the ' 'electronic Honest Broker. Please contact ' 'a system administrator. There could be a' ' connection problem.')) if path: return HttpResponseRedirect(path) # END OF HACK CODE except RecordCreationError as rce: # exceptions from the driver (i.e. errors in the form) log.error(rce.errmsg) error_msgs.append(rce.cause) form = driver.create_new_record_form(request) o_rh = ServiceClient.get_rh_for( record_type=ServiceClient.ORGANIZATION) org = o_rh.get(id=subject.organization_id) label = er_label_rh.get(id=label_id) context = { 'recordCreateForm': form, 'protocol': pds.protocol, 'organization': org, 'subject': subject, 'root_path': ServiceClient.self_root_path, 'pds': pds, 'form_submission_url': form_submission_url, 'errors': error_msgs, 'label': label, 'redcap_status': getRedcapStatus() } return render_to_response( 'pds_dataentry_rec_create.html', context, context_instance=RequestContext(request)) else: # request method not post # have the driver generate the form and render it form = driver.create_new_record_form(request) o_rh = ServiceClient.get_rh_for( record_type=ServiceClient.ORGANIZATION) org = o_rh.get(id=subject.organization_id) label_id = request.REQUEST.get('label_id', 1) label = er_label_rh.get(id=label_id) context = { 'recordCreateForm': form, 'protocol': pds.protocol, 'organization': org, 'subject': subject, 'root_path': ServiceClient.self_root_path, 'pds': pds, 'form_submission_url': form_submission_url, 'label': label, 'redcap_status': getRedcapStatus() } return render_to_response( 'pds_dataentry_rec_create.html', context, context_instance=RequestContext(request)) else: # Show a confirmation form and on POST just ask driver to create # the new record, and redirect to start page try: label_id = request.REQUEST.get('label_id', 1) label = er_label_rh.get(id=label_id) ehb_rec_id = _create_external_system_record(request, driver, pds, subject, label=label_id) path = '%s/dataentry/protocoldatasource/%s/subject/%s/record/%s/start/' % ( ServiceClient.self_root_path, pds.id, subject_id, ehb_rec_id) return HttpResponseRedirect(path) except RecordCreationError as rce: # exception from the eHB log.error(rce.errmsg) error_msgs.append( ('The record could not be created. Please contact a system' ' administrator. There could be a connection problem.')) except ProtocolUserCredentials.DoesNotExist: error_msgs.append('Your user credentials were not found for ' + pds.data_source.name + '. Please contact system administrator.') # some error must have occurred if this code is reached return HttpResponse(' '.join(error_msgs))
def edit_subject(request, protocol_id, subject_ehb_id): ''' renders / processes a subject edit form to update subject phi in ehb system ''' try: protocol = Protocol.objects.get(pk=protocol_id) # is this user authorized for this protocol? A user could accidently / # maliciously manually enter the URL for an unauthorized protocol if not protocol.isUserAuthorized(request.user): return forbidden(request) organizations = protocol.organizations.all() s_rh = ServiceClient.get_rh_for(record_type=ServiceClient.SUBJECT) msg = None try: subject = s_rh.get(id=subject_ehb_id) ''' Is this subject on this protocol? A user could accidently / maliciously manually enter the URL a protocol they are authorized on but for which the subject is not on OR the link could be stale because the ehb primary key is used to ask for this subject record. this key is NOT stored in this app's DB. Rather it is dynamically added to the link in the subject select page. There is the unlikely chance that the link becomes stale between the time it is rendered and the time it is clicked. Hence, a second check is done to make sure this subject is on this protocol. This check done without reference to the ehb's primary key values ''' if not protocol.isSubjectOnProtocol(subject): raise Http404 except PageNotFound: raise Http404 if request.method == 'POST': # process the form form = EditSubjectForm(request.POST) if form.is_valid(): success, subject, errors = form.save(subject=subject, protocol=protocol) if success: cache.delete('{0}_subjects'.format(protocol.id)) return HttpResponseRedirect( '%s/dataentry/protocol/%s/' % (ServiceClient.self_root_path, protocol_id)) else: msg = [] selected_organization = form.selectedOrg() for error in errors: if error == ErrorConstants.ERROR_SUBJECT_ORG_ID_EXISTS: l = Organization.objects.get( pk=int(selected_organization)).subject_id_label msg.append( 'A Subject record with this %s is already in the ehb-service system.' % l) else: msg.append(error) else: selected_organization = form.selectedOrg() else: # render new form for this subject context = { 'subject_id': str(subject.organization_subject_id), 'subject_id_verify': str(subject.organization_subject_id), 'first_name': subject.first_name, 'last_name': subject.last_name, 'dob': RequestBase.stringFromDate(subject.dob) } form = EditSubjectForm(context) o_rh = ServiceClient.get_rh_for( record_type=ServiceClient.ORGANIZATION) selected_organization = '0' try: org = o_rh.get(id=subject.organization_id) for o in organizations: if o.name == org.name: selected_organization = str(o.id) except PageNotFound: raise Http404 return render_to_response('subject_edit.html', { 'errors': msg, 'form': form, 'selected_organization': selected_organization, 'protocol': protocol, 'organizations': organizations, 'subject': subject, 'root_path': ServiceClient.self_root_path, 'redcap_status': getRedcapStatus() }, context_instance=RequestContext(request)) except Protocol.DoesNotExist: raise Http404
def pds_dataentry_start(request, pds_id, subject_id, record_id): ''' Renders a page with the start page for the protocol_data_source with id = pds_id for the Subject with ehb-service id = subject_id. The exact form of this page is protocol_data_source dependent as determined by the driver ''' def generateSubRecordSelectionForm(driver, record_id, form_url, print_url, attempt_count, max_attempts, allow_print=False, allow_zpl=False, allow_chop_print=False): try: return driver.subRecordSelectionForm( form_url=form_url, print_url=print_url, allow_print=allow_print, allow_zpl=allow_zpl, allow_chop_print=allow_chop_print, record_id=record_id) except RecordDoesNotExist: return None pds = getProtocolDataSource(pds_id) if not pds.protocol.isUserAuthorized(request.user): return forbidden(request) er_label_rh = ServiceClient.get_rh_for( record_type=ServiceClient.EXTERNAL_RECORD_LABEL) lbls = er_label_rh.query() MANAGE_EXTERNAL_IDS = False # Check to see if this PDS is managing external identifiers for _pds in pds.protocol.getProtocolDataSources(): if _pds.driver == 3: ExIdSource = _pds MANAGE_EXTERNAL_IDS = True subject = getPDSSubject(pds=pds, sub_id=subject_id) # If we are managing external identifiers add them to the subject if MANAGE_EXTERNAL_IDS: subject.external_ids = getExternalIdentifiers(ExIdSource, subject, lbls) er_rh = ServiceClient.get_rh_for(record_type=ServiceClient.EXTERNAL_RECORD) record = None # this will be the ehb-service externalRecord for this pds, subject NOT the actual datasource record error_msgs = [] # get the record from the ehb with this record id and verify that it is in # the protocol data source for this subject try: pds_records = er_rh.get(external_system_url=pds.data_source.url, path=pds.path, subject_id=subject.id) record = er_rh.get(id=record_id) if record and pds_records: if record not in pds_records: raise Http404 else: raise Http404 except PageNotFound: raise Http404 # if a proper record exists, get the html from the driver and display it if record: try: o_rh = ServiceClient.get_rh_for( record_type=ServiceClient.ORGANIZATION) er_label_rh = ServiceClient.get_rh_for( record_type=ServiceClient.EXTERNAL_RECORD_LABEL) org = o_rh.get(id=subject.organization_id) driver = DriverUtils.getDriverFor(protocol_data_source=pds, user=request.user) form_url = '%s/dataentry/protocoldatasource/%s/subject/%s/record/%s/form_spec/' % ( ServiceClient.self_root_path, pds.id, subject_id, record_id) print_url = '%s/dataentry/protocoldatasource/%s/subject/%s/record/%s/print/' % ( ServiceClient.self_root_path, pds.id, subject_id, record_id) creds = ProtocolUserCredentials.objects.get(protocol=pds.protocol, user=request.user, data_source=pds) srsf = generateSubRecordSelectionForm( driver, record.record_id, form_url, print_url, 0, 1, allow_print=creds.allow_label_printing, allow_zpl=creds.allow_zpl_export, allow_chop_print=creds.allow_chop_printing) label = er_label_rh.get(id=record.label_id) if srsf: authorized_sources, unauthorized_sources = _auth_unauth_source_lists( pds.protocol, request.user, pds) context = { 'subRecordSelectionForm': srsf, 'protocol': pds.protocol, 'authorized_data_sources': authorized_sources, 'unauthorized_data_sources': unauthorized_sources, 'organization': org, 'subject': subject, 'root_path': ServiceClient.self_root_path, 'pds_id': pds.id, 'label': label, 'redcap_status': getRedcapStatus() } return render_to_response( 'pds_dataentry_start.html', context, context_instance=RequestContext(request)) else: # the ehb has a record id, but the records wasn't created in # the external system. error_msgs.append( 'No record exists in the data source with the record id supplied by the eHB.' ) except ProtocolUserCredentials.DoesNotExist: log.error( 'User {0} attempted access on {1}. Credentials not found'. format(request.user, pds.data_source.name)) error_msgs.append(('Your user credentials were not found for' ' %s. Please contact system administrator.') % (pds.data_source.name)) ''' Either multiple records exist in the ehb-service for this system/path/subject and hence proper record cannot be identified # OR the record does not exist and creation of the record failed ''' return HttpResponse(' '.join(error_msgs))
def _gh(self): return ServiceClient.get_rh_for(record_type=ServiceClient.GROUP)
def subject_select(request, protocol_id): ''' renders a page with a table of subjects on the protocol with links to access the data sources with data on each subject ''' try: p = Protocol.objects.get(pk=protocol_id) except Protocol.DoesNotExist: raise Http404 if not p.isUserAuthorized(request.user): return forbidden(request) subjects = getProtocolSubjects(p) er_label_rh = ServiceClient.get_rh_for( record_type=ServiceClient.EXTERNAL_RECORD_LABEL) lbls = er_label_rh.query() addl_id_column = None MANAGE_EXTERNAL_IDS = False for pds in p.getProtocolDataSources(): if pds.driver == 3: ExIdSource = pds MANAGE_EXTERNAL_IDS = True organizations = p.organizations.all() # add the organization name to the subject object for use in template ehb_orgs = [] for o in organizations: ehb_orgs.append(o.getEhbServiceInstance()) if subjects: for s in subjects: s.dob = s.dob.strftime('%Y-%m-%d') # Check whether or not we're managing External Identifiers if MANAGE_EXTERNAL_IDS: try: config = json.loads(ExIdSource.driver_configuration) if 'sort_on' in config.keys(): lbl = None for l in lbls: if l['id'] == config['sort_on']: lbl = l addl_id_column = lbl except: pass s.external_ids = getExternalIdentifiers(ExIdSource, s, lbls) for o in ehb_orgs: if s.organization_id == o.id: s.organization_name = o.name authorized_sources, unauthorized_sources = _auth_unauth_source_lists( p, request.user) context = { 'addl_id_column': addl_id_column, 'subjects': subjects, 'protocol': p, 'organizations': ehb_orgs, 'authorized_data_sources': authorized_sources, 'unauthorized_data_sources': unauthorized_sources, 'root_path': ServiceClient.self_root_path, 'redcap_status': getRedcapStatus() } return render_to_response('subject_select.html', context, context_instance=RequestContext(request))
def save(self, protocol): ''' Attempts to save the data provided in the form as a new subject in ehb-service database. Output ------ If the form is valid: { subject: Subject_instance, "success": boolean, "errors": errors } (Where errors is only present if there were errors in creating the object in the server db) else: None ''' if self.is_valid(): cleandata = self.cleaned_data sub_id = cleandata.get('subject_id') fn = cleandata.get('first_name') ln = cleandata.get('last_name') dob = cleandata.get('dob') org = self.getOrgFromSelection(cleandata.get('organization')) # Create the subject record for this organization # First check if the subject is in the system at all, if not create it srh = ServiceClient.get_rh_for(record_type=ServiceClient.SUBJECT) errors = [] try: subject = srh.get(organization_id=org.id, organization_subject_id=sub_id) # If found this indicates the subject is already in the ehb for # this organization, but not necessarily for this protocol. # That will be checked below in the external record search # check if all new_subject form fields match this existing # subject if not, the form data must be corrected # should add an option to update the record (permission to do so might be role based) success = True prefix = "A subject with this " + org.subject_id_label + " exists but with " if subject.first_name != fn: success = False errors.append(prefix + "first name: " + subject.first_name) if subject.last_name != ln: success = False errors.append(prefix + "last name: " + subject.last_name) if subject.dob != dob: success = False errors.append(prefix + "birth date: " + str(subject.dob)) except PageNotFound: # Subject not in system so create it s = Subject(first_name=fn, last_name=ln, dob=dob, organization_id=org.id, organization_subject_id=sub_id) r = srh.create(s)[0] success = r.get('success') errors = r.get('errors') subject = r.get(Subject.identityLabel) # Don't proceed any further if there are already errors if not success: logger.error('There was an error creating the subject.') return [success, subject, errors] if not errors: errors = [] # First check if the subject is already in the group if protocol.getSubjects() and subject in protocol.getSubjects(): # Subject is already on this protocol errors.append( 'This subject ' + org.subject_id_label + ' has already been added to this project.' ) logger.error("Could not add subject. They already exist on this protocol.") success = False else: # Add this subject to the protocol and create external record group # Create subject/protocol external record group if SubjectUtils.create_protocol_subject_record_group(protocol, subject): # Add subject to protocol subject group if protocol.addSubject(subject): success = True else: logger.error("Could not add subject. Failure to create Protocol Subject Record Group.") errors.append( 'Failed to complete eHB transactions. Could not add subject to project. Please try again.') success = False else: # For some reason we couldn't get the eHB to add the subject to the protocol group logger.error("Could not add subject to project. Could not add subject to the protocol group.") errors.append( 'Failed to complete eHB transactions. Could not add subject to project. Please try again.') success = False return [success, subject, errors] else: return None