|
@@ -0,0 +1,237 @@
|
|
|
+import labkeyInterface
|
|
|
+import labkeyInterface
|
|
|
+import labkeyDatabaseBrowser
|
|
|
+
|
|
|
+# interact with the database (connect, get handle, getRows, uploadRows)
|
|
|
+
|
|
|
+def connectDB(server):
|
|
|
+
|
|
|
+ net=labkeyInterface.labkeyInterface()
|
|
|
+ fconfig=os.path.join(os.path.expanduser('~'),'.labkey',f'{server}.json')
|
|
|
+ net.init(fconfig)
|
|
|
+ return net,labkeyDatabaseBrowser.labkeyDB(net)
|
|
|
+
|
|
|
+def getDB(pars):
|
|
|
+ try:
|
|
|
+ return pars['db']
|
|
|
+ except KeyError:
|
|
|
+ pass
|
|
|
+ pars['net'],pars['db']=connectDB(pars['server'])
|
|
|
+ return pars['db']
|
|
|
+
|
|
|
+def getRows(pars):
|
|
|
+ db=getDB(pars)
|
|
|
+ qFilter=pars.get('qFilter',[])
|
|
|
+ return db.selectRows(pars['project'],pars['schema'],
|
|
|
+ pars['query'],qFilter)['rows']
|
|
|
+
|
|
|
+def modifyRows(pars,mode,rows):
|
|
|
+ db=getDB(pars)
|
|
|
+ return db.modifyRows(mode,pars['project'],pars['schema'],pars['query'],rows)
|
|
|
+
|
|
|
+# helper function
|
|
|
+
|
|
|
+#very generic variable splitting routine
|
|
|
+def parseVariables(q):
|
|
|
+ if q==None:
|
|
|
+ return []
|
|
|
+ arr=q.split(';')
|
|
|
+ v=[x.split('=') for x in arr]
|
|
|
+ return [{'varName':x[0],'varValue':x[1]} for x in v]
|
|
|
+
|
|
|
+
|
|
|
+# get snapshot of the data layout
|
|
|
+
|
|
|
+#this should really look at FormStatus on layout and do the conversion
|
|
|
+def toStatus(x):
|
|
|
+ if x=='Submitted':
|
|
|
+ return 2
|
|
|
+ if x=='InProgress':
|
|
|
+ return 1
|
|
|
+ if x=='Approved':
|
|
|
+ return 5
|
|
|
+
|
|
|
+#get dataset names
|
|
|
+def getInputLists(pars):
|
|
|
+ try:
|
|
|
+ return pars['inputLists']
|
|
|
+ except KeyError:
|
|
|
+ pass
|
|
|
+ parServerLayout={'db':pars['db'],'project':'crfLayout/hypoAfrica'}
|
|
|
+ parInputLists={'schema':'lists','query':'inputLists'}
|
|
|
+ rows=getRows(parServerLayout|parInputLists)
|
|
|
+ pars['inputLists']={r['Key']:r['queryName'] for r in rows}
|
|
|
+ return pars['inputLists']
|
|
|
+
|
|
|
+
|
|
|
+#get datasets for form
|
|
|
+def getDatasets(pars,form):
|
|
|
+ try:
|
|
|
+ return pars['datasets'][form]
|
|
|
+ except KeyError:
|
|
|
+ pass
|
|
|
+ parServerLayout={'db':pars['db'],'project':'crfLayout/hypoAfrica'}
|
|
|
+# set datasets for forms
|
|
|
+ formFilter={'variable':'formName','value':f'{form}','oper':'eq'}
|
|
|
+ parFormSetup={'schema':'lists','query':'FormSetup'}
|
|
|
+ parFilter={'qFilter':[formFilter]}
|
|
|
+ rows=getRows(parServerLayout|parFormSetup|parFilter)
|
|
|
+#ignore show query since 15 has all set to NONE
|
|
|
+#keep variable definition
|
|
|
+ inputLists=getInputLists(pars)
|
|
|
+ datasets={r['Key']:r|{'query':inputLists[r['queryName']]} for r in rows}
|
|
|
+ try:
|
|
|
+ pars['datasets'][form]=datasets
|
|
|
+ except KeyError:
|
|
|
+ pars['datasets']={form:datasets}
|
|
|
+ return datasets
|
|
|
+
|
|
|
+#manager CRF master entries (get, modify, upload)
|
|
|
+
|
|
|
+def getCrfEntry(pars,crf):
|
|
|
+ crfFilter={'variable':'entryId','value':crf,'oper':'eq'}
|
|
|
+ parFilter={'qFilter':[crfFilter]}
|
|
|
+ parCrf={'schema':'lists','query':'crfEntry'}
|
|
|
+ rows=getRows(pars|parCrf|parFilter)
|
|
|
+ if len(rows)!=1:
|
|
|
+ print('Fail crfEntry')
|
|
|
+ return None
|
|
|
+ return rows[0]
|
|
|
+
|
|
|
+def changeFormStatus(pars,crfEntry,targetStatus):
|
|
|
+ crfEntry['FormStatus']=toStatus(targetStatus)
|
|
|
+ updateCrfEntry(pars,crfEntry)
|
|
|
+
|
|
|
+def uploadCrfEntry(pars,crfEntry):
|
|
|
+ parCrf={'schema':'lists','query':'crfEntry'}
|
|
|
+ outcome=modifyRows(pars|parCrf,'update',[crfEntry])
|
|
|
+ try:
|
|
|
+ print(outcome['exception'])
|
|
|
+ except KeyError:
|
|
|
+ pass
|
|
|
+
|
|
|
+
|
|
|
+#manage DATA (set, verify, upload)
|
|
|
+def setData(pars,crfEntry,schema):
|
|
|
+ datasets=getDatasets(pars,crfEntry['Form'])
|
|
|
+ for k in datasets:
|
|
|
+ d=datasets[k]
|
|
|
+ crf=crfEntry['entryId']
|
|
|
+#print('Setting [{}:{}/{}]'.format(schema,d['query'],d['variableDefinition']))
|
|
|
+ crfFilter={'variable':'crfRef','value':crf,'oper':'eq'}
|
|
|
+ qFilter=[crfFilter]
|
|
|
+ qvar=parseVariables(d['variableDefinition'])
|
|
|
+ qvarFilter=[{'variable':x['varName'],'value':x['varValue'],'oper':'eq'} for x in qvar]
|
|
|
+ qFilter.extend(qvarFilter)
|
|
|
+ parD={'schema':schema,'query':d['query'],'qFilter':qFilter}
|
|
|
+ rows=getRows(pars|parD)
|
|
|
+ try:
|
|
|
+ pars['data'][schema][k]=rows
|
|
|
+ except KeyError:
|
|
|
+ try:
|
|
|
+ pars['data'][schema]={k:rows}
|
|
|
+ except KeyError:
|
|
|
+ pars['data']={schema:{k:rows}}
|
|
|
+
|
|
|
+def verifyData(pars,crfEntry,schema):
|
|
|
+ ok=True
|
|
|
+ datasets=getDatasets(pars,crfEntry['Form'])
|
|
|
+ for k in datasets:
|
|
|
+ d=datasets[k]
|
|
|
+ rows=pars['data'][schema][k]
|
|
|
+ testFailed={'lists':len(rows)!=1,'study':len(rows)>1}
|
|
|
+ if testFailed[schema]:
|
|
|
+ print('[{} {}/{}]: {}'.format(schema,d['query'],
|
|
|
+ d['variableDefinition'],len(rows)))
|
|
|
+ #at least one fail
|
|
|
+ ok=False
|
|
|
+ continue
|
|
|
+ return ok
|
|
|
+
|
|
|
+
|
|
|
+def uploadData(pars,crfEntry):
|
|
|
+ status=True
|
|
|
+ datasets=getDatasets(pars,crfEntry['Form'])
|
|
|
+ for k in datasets:
|
|
|
+ listRow=pars['data']['lists'][k][0]
|
|
|
+ studyRows=pars['data']['study'][k]
|
|
|
+ try:
|
|
|
+ outRow=studyRows[0]
|
|
|
+ outRow.update(listRow)
|
|
|
+ mode='update'
|
|
|
+ except IndexError:
|
|
|
+ outRow={x:listRow[x] for x in listRow}
|
|
|
+ mode='insert'
|
|
|
+ outRow['ParticipantId']=crfEntry['participantStudyId']
|
|
|
+ outRow['SequenceNum']=(int(crfEntry['entryId']) % 1000000000 )
|
|
|
+
|
|
|
+
|
|
|
+ d=datasets[k]
|
|
|
+ parD={'schema':'study','query':d['query']}
|
|
|
+ outcome=modifyRows(pars|parD,mode,[outRow])
|
|
|
+ try:
|
|
|
+ print(outcome['exception'])
|
|
|
+ status=False
|
|
|
+ except KeyError:
|
|
|
+ pass
|
|
|
+
|
|
|
+ return status
|
|
|
+
|
|
|
+## mimic CRF actions
|
|
|
+
|
|
|
+def onSubmitedToInProgress(pars,crf):
|
|
|
+ crfEntry=getCrfEntry(pars,crf)
|
|
|
+ statusIn=crfEntry['FormStatus']
|
|
|
+ if statusIn!=toStatus('Submitted'):
|
|
|
+ print(f'[{crf}]: Inappropriate status({statusIn})')
|
|
|
+ return
|
|
|
+ changeFormStatus(pars,crfEntry,'InProgress')
|
|
|
+
|
|
|
+def onApprovedToSubmited(pars,crf):
|
|
|
+ crfEntry=getCrfEntry(pars,crf)
|
|
|
+ statusIn=crfEntry['FormStatus']
|
|
|
+ if statusIn!=toStatus('Approved'):
|
|
|
+ print(f'[{crf}]: Inappropriate status({statusIn})')
|
|
|
+ return
|
|
|
+ changeFormStatus(pars,crfEntry,'Submitted')
|
|
|
+
|
|
|
+def onSubmit(pars,crf):
|
|
|
+ crfEntry=getCrfEntry(pars,crf)
|
|
|
+ statusIn=crfEntry['FormStatus']
|
|
|
+ if statusIn!=toStatus('InProgress'):
|
|
|
+ print(f'[{crf}]: Inappropriate status({statusIn})')
|
|
|
+ return
|
|
|
+
|
|
|
+ form=crfEntry['Form']
|
|
|
+ setData(pars,crfEntry,'lists')
|
|
|
+ status=verifyData(pars,crfEntry,'lists')
|
|
|
+ crf=crfEntry['entryId']
|
|
|
+ if not status:
|
|
|
+ print(f'[{crf}/{form}] verification failed')
|
|
|
+ return
|
|
|
+ changeFormStatus(pars,crfEntry,'Submitted')
|
|
|
+
|
|
|
+
|
|
|
+def onDatabaseUpload(pars,crf):
|
|
|
+ crfEntry=getCrfEntry(pars,crf)
|
|
|
+ statusIn=crfEntry['FormStatus']
|
|
|
+ if statusIn!=toStatus('Submitted'):
|
|
|
+ print(f'[{crf}]: Inappropriate status({statusIn})')
|
|
|
+ return
|
|
|
+
|
|
|
+ form=crfEntry['Form']
|
|
|
+ setData(pars,crfEntry,'lists')
|
|
|
+ setData(pars,crfEntry,'study')
|
|
|
+ dataOK=verifyData(pars,crfEntry,'study')
|
|
|
+ if not dataOK:
|
|
|
+ print(f'[{crf}]: verification failed')
|
|
|
+ return
|
|
|
+ print(f'[{crf}]: verification OK')
|
|
|
+
|
|
|
+ uploadOK=uploadData(pars,crfEntry)
|
|
|
+ if not uploadOK:
|
|
|
+ print(f'[{crf}]: upload failed')
|
|
|
+ return
|
|
|
+ print(f'[{crf}]: upload OK')
|
|
|
+ changeFormStatus(pars,crfEntry,'Approved')
|
|
|
+
|