diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..6a2dee7
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,10 @@
+.idea/
+test.sh
+test176.sh
+/plugins/*jar
+/plugins/
+/xlsx/*xlsx
+/redcap_dict/*.csv
+/builder/__pycache__
+
+
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..b5bf6f8
--- /dev/null
+++ b/README.md
@@ -0,0 +1,32 @@
+Please read the wiki for instructions.
+
+## Updates
+**26 June 2023**:
+* Subforms added
+* Gradlew bug fixed - restarts gradle to clear cache, as can break if schema changed.
+* Date box and ynuo bugs fixed
+* Session/subject assessor label format changed to prevent same day clashes
+
+**22 March 2023**:
+* Redcap rewritten and improved - includeding calcsum and datediff
+* Bug fix: float textboxes did not work - came out string. Fixed
+* Project-specific field added
+* Using modified XNAT 1.8 Plugin Template (not working)
+* Tested on XNAT 1.8.7
+
+**22 March 2023**:
+* Redcap rewritten and improved - includeding calcsum and datediff
+* Bug fix: float textboxes did not work - came out string. Fixed
+* Project-specific field added
+* Using modified XNAT 1.8 Plugin Template
+* Tested on XNAT 1.8.7
+
+**26 Jan 2023**:
+* Subforms added (else potentially not buildable in gradle due to being too long)
+* Tested to XNATv1.8.6.1
+
+## Limitations
+
+* Redcap Calc fields are limited.
+* UK Date formats dd-MM-YYYY
+
diff --git a/builder/__init__.py b/builder/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/builder/handle_csv.py b/builder/handle_csv.py
new file mode 100644
index 0000000..34ae003
--- /dev/null
+++ b/builder/handle_csv.py
@@ -0,0 +1,118 @@
+import os
+import shutil
+
+
+
+
+class CSVHandler(object):
+
+ def __init__(self, configData, deleteExistingFiles=False):
+ self.errors = []
+ self.log = []
+ self.configData = configData
+ self.schemaName = configData['schemaName']
+ self.csvDir = '{}/data'.format(configData['path_plugin_builder'])
+
+
+ if (deleteExistingFiles):
+ self.emptyTheDir()
+
+ def hasError(self):
+ return len(self.errors)
+
+ def errors(self):
+ return self.errors
+
+
+
+
+ def emptyTheDir(self):
+
+ thePath = ('{}/data/{}').format(self.configData['path_plugin_builder'], self.schemaName)
+ if os.path.exists(thePath):
+ self.log.append(' Delete Dir : {}'.format(thePath))
+ shutil.rmtree(thePath)
+ #make new dir
+
+ os.makedirs(thePath)
+
+
+ def getHeader(self, form):
+
+ out = 'ID,'
+ for i in form['inputs']:
+ el = '{}:{}/{}'.format(self.schemaName, form['ref'], i['dataName'])
+ if 'subform' in i['inputFormType']:
+
+ subform = i['options']
+ #insert questions later
+ out = '{}{}@{}@,'.format(out, el,subform)
+
+ elif len(i['children']) > 0:
+ elsub = '{}/{}'.format(el, i['subName'])
+ out = '{}{},'.format(out, elsub)
+ for ii in i['children']:
+ elsub = '{}/{}'.format(el, ii['subName'])
+ if 'subform' in ii['inputFormType']:
+ subform = ii['options']
+ # insert questions later
+ out = '{}{}@{}@,'.format(out, elsub, subform)
+ else:
+ out = '{}{},'.format(out, el)
+ out = '{}subject_ID'.format(out )
+ return out
+
+ def getLineOfData(self, form, data):
+
+
+ form_label = '{}-{}'.format(form['ref'],data['subject_label'])
+ out = '{},'.format(form_label)
+
+ for i in data['inputs']:
+ out = '{},{},'.format(out, data[i])
+ out = '{},{}'.format(out, data['subject_label'] )
+ return out
+
+ def writeToFile(self, form):
+
+ head = self.getHeader(form)
+
+ if len(head) == 0:
+ self.errors.append('no inputs')
+ return
+
+ writeFileName = '{}/{}/{}_{}.csv'.format(self.csvDir,self.schemaName,self.schemaName, form['ref'])
+ #self.checkDir(writeFileName)
+ self.log.append(' write file : {}'.format(writeFileName))
+ f = open(writeFileName, "w")
+
+ f.write('{}'.format(head))
+
+ f.close()
+
+ def write_subforms(self, subform):
+ thePath = ('{}/data/{}').format(self.configData['path_plugin_builder'], self.schemaName)
+ subform_replace = '@{}@'.format(subform['ref'])
+ out = ''
+ if os.path.exists(thePath):
+ for filename in os.listdir(thePath):
+ filepath = os.path.join(thePath, filename)
+ with open(filepath) as f:
+ header = f.readline()
+ heads = header.split(',')
+ for head in heads:
+ print(head)
+ if subform_replace in head:
+ el = head.replace(subform_replace,'')
+ print(el)
+ for i in subform['inputs']:
+ out = '{},{}/{}'.format(out,el, i['dataName'])
+
+ else:
+ out = '{},{}'.format(out,head)
+
+ with open(filepath, "w") as f:
+ #get rid of first and last comma
+ out = out[1:-1]
+ f.write(out)
+
diff --git a/builder/handle_file_plugin.py b/builder/handle_file_plugin.py
new file mode 100644
index 0000000..afb863a
--- /dev/null
+++ b/builder/handle_file_plugin.py
@@ -0,0 +1,111 @@
+import os
+import shutil
+
+class PluginHandler(object):
+
+ def __init__(self, configData, deleteExistingFiles = False):
+
+ self.errors = []
+ self.log =[]
+ self.configData = configData
+ self.schemaName = configData['schemaName']
+
+ self.part_plugin_path = 'src/main/java/org/nrg/xnat/plugins/'
+
+ def hasError(self):
+ return len(self.errors)
+
+ def errors(self):
+ return self.errors
+
+
+
+
+ def copyTemplatesReplace(self,toDir):
+
+ fromDir = ('{}/plugin_template'.format(self.configData['path_builder_templates']))
+
+ self.log.append(' copy plugin template from : {}'.format(fromDir))
+ self.log.append(' copy plugin template to : {}'.format(toDir))
+ if os.path.exists(toDir):
+ shutil.rmtree(toDir)
+
+ shutil.copytree( fromDir,toDir , symlinks=False, ignore=None)
+
+ for root, dirs, files in os.walk(toDir):
+ for file in files:
+ if file == '.DS_Store':
+ continue
+ f_in = os.path.join(root, file)
+ # print ('File : ', f_in)
+ fxsd = open(f_in,"r")
+ lines = fxsd.readlines()
+ fxsd.close()
+ fxsd = open(f_in,"w")
+
+ for line in lines:
+ fxsd.write(line.replace('[HERE_SCHEMANAME_LOWER]',self.schemaName.lower()).replace('[HERE_SCHEMANAME]',self.schemaName.title()))
+
+ fxsd.close()
+
+ for root, dirs, files in os.walk(toDir):
+ for file in files:
+ fo = os.path.join(root, file)
+ if 'Template' in file:
+ print ('Renaming {} to {} '.format(file, file.replace('Template',self.schemaName.title()).replace('template',self.schemaName.lower())))
+ os.rename(fo,os.path.join(root, file.replace('Template',self.schemaName.title()).replace('template',self.schemaName.lower())))
+ if 'template' in file:
+ print ('Renaming {} to {} '.format(file, file.replace('Template',self.schemaName.title()).replace('template',self.schemaName.lower())))
+ os.rename(fo,os.path.join(root, file.replace('template',self.schemaName.lower())))
+
+
+ def createFiles(self,forms):
+
+ toDir = ('{}/{}/{}{}').format(self.configData['path_builder_plugins'],self.schemaName, self.part_plugin_path,self.configData['schemaName'].lower())
+
+ self.copyTemplatesReplace(toDir)
+
+ HERE_IMPORT_BEANS =[]
+ HERE_XNAT_DATA_MODELS =[]
+
+ for f in forms:
+ sc = self.schemaName[:1].upper() + self.schemaName[1:].lower()
+ st = forms[f]['ref'][:1].upper() + forms[f]['ref'][1:].lower()
+ bean = '{}{}Bean'.format(sc,st)
+ formName = forms[f]['name']
+ md = '@XnatDataModel(value = {}.SCHEMA_ELEMENT_NAME, singular = "{}", plural = "{}")'.format(bean,formName,formName)
+
+ HERE_IMPORT_BEANS.append('import org.nrg.xdat.bean.{};'.format(bean) )
+ HERE_XNAT_DATA_MODELS.append(md)
+
+
+ file_plugin = ('{}/plugin/Xnat{}Plugin.java'.format(toDir,self.schemaName.title()))
+ print('FILE', file_plugin)
+ f = open(file_plugin,"r")
+ lines = f.readlines()
+ f.close()
+
+ # print(lines)
+ self.log.append(' replace file contents : {}'.format(file_plugin))
+
+ f = open(file_plugin,"w")
+ for line in lines:
+ # print(line)
+ if '[HERE_IMPORT_BEANS]' in line:
+ f.write(line.replace('[HERE_IMPORT_BEANS]','\n'.join(HERE_IMPORT_BEANS)))
+ elif '[HERE_XNAT_DATA_MODELS]' in line:
+ f.write(line.replace('[HERE_XNAT_DATA_MODELS]',','.join(HERE_XNAT_DATA_MODELS)))
+ elif '[HERE_CLASS_NAME]' in line:
+ f.write(line.replace('[HERE_CLASS_NAME]',sc))
+ elif '[HERE_SCHEMANAME_LOWER]' in line:
+ f.write(line.replace('[HERE_SCHEMANAME_LOWER]',self.configData['schemaName'].lower()))
+ elif '[HERE_PLUGIN_NAME]' in line:
+ f.write(line.replace('[HERE_PLUGIN_NAME]',self.configData['schemaName']))
+ else:
+ # print(line)
+ f.write(line)
+
+ f.close()
+
+
+
diff --git a/builder/handle_file_turbine.py b/builder/handle_file_turbine.py
new file mode 100644
index 0000000..d2f7562
--- /dev/null
+++ b/builder/handle_file_turbine.py
@@ -0,0 +1,122 @@
+import errno
+import os
+import shutil
+
+class TurbineHandler(object):
+
+ def __init__(self, configData, deleteExistingFiles = False):
+
+ self.errors = []
+ self.log =[]
+ self.configData = configData
+ self.schemaName = configData['schemaName']
+
+ self.filesDir = 'src/main/java/org/apache/turbine/app/xnat/modules/screens/'
+ self.actionsDir = 'src/main/java/org/apache/turbine/app/xnat/modules/actions/'
+
+ if(deleteExistingFiles):
+ self.emptyTheDir()
+
+ def hasError(self):
+ return len(self.errors)
+
+
+ def checkDir(self,vmFile):
+
+ if not os.path.exists(os.path.dirname(vmFile)):
+ try:
+ os.makedirs(os.path.dirname(vmFile))
+ except OSError as exc: # Guard against race condition
+ if exc.errno != errno.EEXIST:
+ raise
+
+ def emptyTheDir(self):
+
+ thePath = ('{}/{}/{}').format(self.configData['path_builder_plugins'],self.schemaName,self.filesDir)
+ if os.path.exists(thePath):
+ shutil.rmtree(thePath)
+
+ self.log.append(' Empty Dir : {}'.format(thePath))
+ thePath = ('{}/{}/{}').format(self.configData['path_builder_plugins'],self.schemaName,self.actionsDir)
+ if os.path.exists(thePath):
+ shutil.rmtree(thePath)
+
+ self.log.append(' Empty Dir : {}'.format(thePath))
+
+ def copyAndReplace(self,src,dst, form):
+ sc = self.schemaName[:1].upper() + self.schemaName[1:].lower()
+ st = form['ref'][:1].upper() + form['ref'][1:].lower()
+ om_name = '{}{}'.format(sc, st)
+ class_name = 'XDATScreen_edit_{}_{}'.format(self.schemaName, form['ref'])
+ label_tag = form['ref']
+
+ f = open(src, "r")
+ lines = f.readlines()
+ f.close()
+
+ f = open(dst, "w")
+ for line in lines:
+ if '[SCHEMA_TITLE]' in line or '[OM_NAME]' in line or '[CLASS_NAME]' in line or '[LABEL_TAG]' in line or '[FORM_NAME]' in line:
+ line = line.replace('[OM_NAME]', om_name)
+ line = line.replace('[CLASS_NAME]', class_name)
+ line = line.replace('[FORM_NAME]', form['ref'])
+ line = line.replace('[SCHEMA_TITLE]',self.schemaName.title())
+ f.write(line.replace('[LABEL_TAG]', str(label_tag)))
+ else:
+ f.write(line)
+
+ f.close()
+
+ def loadTemplateReplace(self, form):
+
+ fname = ('{}/turbine_java_template.java'.format(self.configData['path_builder_templates']))
+ if form['ext'] != 'subject':
+ #sesison level
+ fname = ('{}/turbine_java_template_session.java'.format(self.configData['path_builder_templates']))
+ self.log.append(' load file : {}'.format(fname))
+
+ return fname
+
+
+ def copyTemplateScreeen(self, form):
+ src = ('{}/TemplateScreen.java').format(self.configData['path_builder_templates'])
+ dst = ('{}/{}/{}/{}Screen.java').format(self.configData['path_builder_plugins'], self.schemaName, self.filesDir,self.schemaName.title() )
+ self.copyAndReplace(src,dst, form)
+
+ def copyModifyTemplateScreeen(self,form):
+ #under actions dir
+ #for subjects only as dunno about session
+ if 'ubject' in form['ext']:
+
+ dst = ('{}/{}/{}/').format(self.configData['path_builder_plugins'], self.schemaName,self.actionsDir)
+ if not os.path.exists(os.path.dirname(dst)):
+ try:
+ os.makedirs(os.path.dirname(dst))
+ except OSError as exc: # Guard against race condition
+ if exc.errno != errno.EEXIST:
+ raise
+ self.log.append(' write file : {}'.format(dst))
+ #DONT USE title() - as does not work if form contains numbers
+ ref = form['ref'][:1].upper() + form['ref'][1:].lower()
+
+ dst = ('{}/{}/{}/Modify{}{}.java').format(self.configData['path_builder_plugins'], self.schemaName, self.actionsDir, self.schemaName.title(), ref)
+ src = ('{}/ModifyTemplateSample.java').format(self.configData['path_builder_templates'])
+ self.copyAndReplace(src,dst, form)
+
+
+ def pathTemplateReplaceOut(self,templateType,formRef):
+
+ fname = ('{}/{}/{}XDATScreen_{}').format(self.configData['path_builder_plugins'],self.schemaName,self.filesDir,templateType)
+ return fname + ('_{}_{}.java').format(self.configData['schemaName'],formRef)
+
+
+ def formEdit(self,form):
+
+
+ templateName = self.loadTemplateReplace(form)
+ writeFileName = self.pathTemplateReplaceOut('edit',form['ref'])
+
+ self.log.append(' write file : {}'.format(writeFileName))
+ self.checkDir(writeFileName)
+
+ self.copyAndReplace(templateName,writeFileName, form)
diff --git a/builder/handle_vm.py b/builder/handle_vm.py
new file mode 100644
index 0000000..1780d77
--- /dev/null
+++ b/builder/handle_vm.py
@@ -0,0 +1,321 @@
+import os
+import sys
+import shutil
+
+
+import builder.html_vm_report
+import builder.html_vm_edit
+
+class VMHandler(object):
+
+ def __init__(self, configData, deleteExistingFiles = False):
+
+ self.errors = []
+ self.log =[]
+ self.configData = configData
+ self.schemaName = configData['schemaName']
+ self.restrict_to_project= configData['restrict_to_project']
+
+ self.filesDir = 'src/main/resources/META-INF/resources/templates/screens/'
+ self.actionBoxDirSubject = 'xnat_subjectData/actionsBox'
+ self.actionBoxDirImage = 'xnat_imageSessionData/actionsBox'
+
+ if(deleteExistingFiles):
+ self.emptyTheDir()
+ self.emptyTheDir()
+
+ def hasError(self):
+ return len(self.errors)
+
+ def errors(self):
+ return self.errors
+
+ def checkDir(self,vmFile):
+
+ if not os.path.exists(os.path.dirname(vmFile)):
+ try:
+ os.makedirs(os.path.dirname(vmFile))
+ except OSError as exc: # Guard against race condition
+ if exc.errno != errno.EEXIST:
+ raise
+
+ def emptyTheDir(self):
+
+ thePath = ('{}/{}/{}').format(self.configData['path_builder_plugins'],self.schemaName, self.filesDir)
+ if os.path.exists(thePath):
+ self.log.append(' Delete Dir : {}'.format(thePath))
+ shutil.rmtree(thePath)
+
+
+ def loadTemplateReplace(self,templateType,entryType):
+
+ if templateType != 'subject':
+ templateType = 'image'
+
+ fname = ('{}/{}_{}_form17.vm'.format(self.configData['path_builder_templates'],templateType,entryType))
+ self.log.append(' load file : {}'.format(fname))
+
+ f = open(fname,"r")
+ lines = f.readlines()
+ f.close()
+ return lines
+
+ def pathTemplateReplaceOut(self,templateType,formRef):
+
+ pathPlugin = ('{}/{}'.format(self.configData['path_builder_plugins'],self.schemaName))
+ fname = ('{}/{}XDATScreen_{}').format(pathPlugin,self.filesDir,templateType)
+ return fname + ('_{}_{}.vm').format(self.configData['schemaName'],formRef)
+
+ def copyTemplateScreeen(self):
+ src = ('{}/TemplateScreen.vm').format(self.configData['path_builder_templates'])
+ dst = ('{}/{}/{}/{}Screen.vm').format(self.configData['path_builder_plugins'], self.schemaName, self.filesDir,self.schemaName.title())
+ #shutil.copy(src,dst)
+
+ f = open(src,"r")
+ lines = f.readlines()
+ f.close()
+ f = open(dst, "w")
+ for line in lines:
+ if '[SCHEMA_NAME]' in line:
+ line = line.replace('[SCHEMA_NAME]', self.schemaName.title())
+ f.write(line)
+ f.close()
+
+
+ def copyJavascript(self):
+ # copy jquery and other scripts into plugin
+ js_dest = '{}/{}/src/main/resources/META-INF/resources/scripts/'.format(self.configData['path_builder_plugins'],self.schemaName)
+ scriptsDir= ('{}/{}').format(self.configData['path_builder_templates'],'scripts')
+ if not os.path.exists(js_dest):
+ shutil.copytree( scriptsDir, js_dest , symlinks=False, ignore=None)
+ #copy the cusotm javascript
+ js_file = ('{}/formmaker.js').format(self.configData['path_builder_templates'])
+ shutil.copyfile( js_file,'{}/formmaker{}.js'.format( js_dest,self.configData['schemaName']))
+
+ def copyMacros(self):
+
+ macro_file = ('{}/macros/xMacros.vm').format(self.configData['path_builder_templates'])
+ macro_dest = '{}/{}/src/main/resources/META-INF/resources/templates/macros/'.format(self.configData['path_builder_plugins'],self.schemaName)
+
+ if not os.path.exists(macro_dest):
+ os.makedirs(macro_dest)
+ shutil.copyfile( macro_file,'{}/{}Macros.vm'.format( macro_dest,self.configData['schemaName']))
+
+ def handleFormSubforms(self,form,screenType,inputs):
+
+ file_type = '_report_'
+ if 'edit' in screenType:
+ file_type='_edit_'
+
+ #find all references for subform in forms, and replace
+ if len(inputs) == 0 :
+ self.errors.append('no inputs')
+ return
+ formDir = ('{}/{}/{}').format(self.configData['path_builder_plugins'], self.schemaName, self.filesDir)
+ for fl in os.listdir(formDir):
+ print(fl)
+ if file_type in fl:
+ print(os.path.join(formDir, fl))
+ f = open(os.path.join(formDir, fl), "r")
+ lines = f.readlines()
+ f.close()
+ f = open(os.path.join(formDir, fl), "w")
+ for line in lines:
+ if '@{}@'.format(form['ref']) in line:
+ print('REPLACING LINE - ', line)
+ #must be subform type - insert inputs
+ #'line format' @BASE_SCHEMA@ @SUBFORM NAME form['name']@
+ new_schema_base=line.split("@")[1]
+ #f.write(line)
+ f.write(line.replace(line, '\n'.join(inputs).replace('@BASE_SCHEMA@', new_schema_base)))
+ else:
+ f.write(line)
+ f.close()
+
+
+ def handleFormByExtScreen(self,form,screenType,inputs, jscript=''):
+
+ # print('inputs',inputs)
+ if len(inputs) == 0 :
+ self.errors.append('no inputs')
+ return
+
+ replaceTemplate = self.loadTemplateReplace(form['ext'],screenType)
+ writeFileName = self.pathTemplateReplaceOut(screenType,form['ref'])
+
+ self.checkDir(writeFileName)
+ self.log.append(' write file : {}'.format(writeFileName))
+
+ f = open(writeFileName,"w")
+
+ for line in replaceTemplate:
+ if '[HERE_MODIFY_FORM_ACTION]' in line:
+ ref = form['ref'][:1].upper() + form['ref'][1:].lower()
+ line = line.replace('[HERE_MODIFY_FORM_ACTION]', '{}{}'.format(self.schemaName.title(),ref))
+ if '[DATA_TYPE]' in line:
+ f.write(line.replace('[DATA_TYPE]','{}:{}'.format(self.schemaName,form['ref'])))
+ elif '[HERE_FORM_TITLE]' in line:
+ f.write(line.replace('[HERE_FORM_TITLE]', form['name']))
+ elif '[HERE_FORM_REF]' in line:
+ f.write(line.replace('[HERE_FORM_REF]', form['ref']))
+ elif '[HERE_FORM_INPUTS]' in line:
+ try:
+ f.write(line.replace('[HERE_FORM_INPUTS]', '\n'.join(inputs)))
+ except Exception as e:
+ print('Error writing to {} - error: {}'.format(writeFileName ,e))
+ for n in inputs:
+ print('Error {}'.format(n))
+ sys.exit(0)
+
+ elif '[CUSTOM JAVASCRIPT]' in line:
+ f.write(line.replace('[CUSTOM JAVASCRIPT]', '\n'.join(jscript)))
+ elif 'xMacro' in line:
+ f.write(line.replace('xMacro', '{}Macro'.format(self.schemaName)))
+ elif 'formmakerx.js' in line:
+ f.write(line.replace('formmakerx.js', 'formmaker{}.js'.format(self.schemaName)))
+ else:
+ f.write(line)
+
+ f.close()
+
+ def logInput(self,msg,i):
+
+ self.log.append(' {} : {} : sub name: {} : form type : {}'.format(msg,i['question'], i['subName'], i['inputFormType']))
+
+ def formEdit(self,form):
+
+ inputs = []
+ # self.errors.append('eee')
+ self.log.append(' loop Form Ext Screens Edit : {}'.format(form['name']) )
+ inputs.extend(self.formInputsEdit(form))
+
+ jscript = []
+ jscript.extend(self.formJSEdit(form))
+
+
+ # print('inputs',inputs)
+ if len(inputs) == 0 :
+ self.errors.append('no inputs')
+ return
+ if 'subform' in form['ext']:
+ print('SUBFORM making form...')
+ self.handleFormSubforms(form,'edit', inputs)
+ else:
+ self.handleFormByExtScreen(form,'edit',inputs, jscript)
+ #cop marcos
+ self.copyMacros()
+ self.copyJavascript()
+
+
+
+ def formInputsEdit(self,form):
+ #forms=['all forms here']
+
+ out =[]
+ subform = False
+ if 'subform' in form['ext']:
+ subform = True
+
+ for i in form['inputs']:
+ out.extend(builder.html_vm_edit.htmlInputEdit(i, self.schemaName, form['ref'], subform))
+
+ return out
+
+ def formJSEdit(self, form):
+
+ out = []
+ for i in form['inputs']:
+ if 'calc' in i['inputFormType']:
+ self.log.append('edit screen CALC : {}'.format(i['question']))
+ out.extend(builder.html_vm_edit.editTypeCalcJScript(i,self.schemaName,form['ref']))
+ return out
+
+ def formReport(self,form):
+
+ inputs = []
+
+ self.log.append(' loop Form Ext Screens Report : {}'.format(form['name']) )
+
+ inputs.extend(self.formInputsReport(form))
+
+ if len(inputs) == 0 :
+ self.errors.append('no inputs')
+ return
+
+ if 'subform' in form['ext']:
+ print('SUBFORM making form...')
+ self.handleFormSubforms(form,'report', inputs)
+ else:
+ self.handleFormByExtScreen(form,'report',inputs)
+
+
+ def formInputsReport(self,form):
+ subform = False
+ if 'subform' in form['ext']:
+ subform = True
+
+ out =[]
+ for i in form['inputs']:
+
+ el = '{}:{}/{}'.format(self.schemaName,form['ref'],i['dataName'])
+ self.log.append('report screen el : {}'.format(el))
+
+ out.extend(builder.html_vm_report.htmlInputReport(i,self.schemaName,form['ref'], subform))
+
+ return out
+
+
+
+
+
+ def add_to_actionsbox(self,form,sequence, version):
+ print( 'Making sub-actions box' )
+ boxDir = self.actionBoxDirSubject if (form['ext'] == 'subject') else self.actionBoxDirImage
+
+ fname = ('{}/{}/{}{}/{}_assessors.vm').format(self.configData['path_builder_plugins'],self.schemaName, self.filesDir,boxDir,self.schemaName)
+ self.checkDir(fname)
+ if not os.path.isfile(fname):
+ try:
+ fname = ('{}/action_box_template.vm').format(self.configData['path_builder_templates'])
+ print('assessors.vm does not exist, using template {}'.format(fname))
+ except OSError as exc: # Guard against race condition
+ if exc.errno != errno.EEXIST:
+ raise
+
+ f = open(fname,"r")
+ lines = f.readlines()
+ f.close()
+
+ fname = ('{}/{}/{}{}/{}_assessors.vm').format(self.configData['path_builder_plugins'],self.schemaName, self.filesDir,boxDir,self.schemaName)
+ vm_file = ('XDATScreen_edit_{}_{}').format(self.schemaName,form['ref'])
+ f = open(fname,"w")
+
+ for line in lines:
+ if '[PROJECT]' in line:
+ f.write(line.replace('[PROJECT]', self.restrict_to_project))
+ elif '[SCHEMA]' in line:
+ f.write(line.replace('[SCHEMA]', self.schemaName))
+ else:
+ f.write(line)
+ if 'ADD_HERE' in line:
+
+ f.write('
\n'.format(form['name']))
+
+
+ f.close()
+ print ('Created {}'.format(fname) )
+
+
+
\ No newline at end of file
diff --git a/builder/html_vm_edit.py b/builder/html_vm_edit.py
new file mode 100644
index 0000000..0624dd3
--- /dev/null
+++ b/builder/html_vm_edit.py
@@ -0,0 +1,495 @@
+import time
+## Bracnhing - this is redcap branching, not excell spreadhseets
+
+
+def get_panel_name(input, tog_name):
+ panel_name = 'panel{}'.format(tog_name)
+ if 'panelNum' in input:
+ panel_name = 'panel{}{}'.format(tog_name, input['panelNum'])
+ return panel_name
+
+def htmlTextString(input,el, out):
+ iType = input['inputFormType']
+ if 'subheader' in iType:
+ print('SUBHEADER - {}'.format(input['question']))
+ out.extend(editTypeSubHeader(input))
+ elif 'eader' in iType:
+ print('HEADER - {}'.format(input['question']))
+ out.extend(editTypeHeader(input))
+ elif 'insert' in iType:
+ print('PARAGRAPH - {}'.format(input['question']))
+ out.extend(editTypeHtml(input))
+ elif 'paragraph' in iType:
+ print('PARAGRAPH - {}'.format(input['question']))
+ out.extend(editTypeParagraph(input))
+
+
+def htmlInputEditStandard(input,el, out):
+
+ iType = input['inputFormType']
+ #print(iType)
+
+ if 'branchingquestion' in input:
+ out.extend(editTypeBranch(input, el, 'start'))
+
+ if 'text' not in input['schemaInputType']:
+ if iType != 'multiradio' and 'xstart' not in el:
+ out.append('')
+ out.append('{} | '.format(input['question']))
+ out.append(' ')
+
+ if 'branchVals' in input:
+ #assumes radio....
+ out.extend(editBranchToggle(input, el))
+
+ elif iType == 'subform':
+ out.extend(editTypeSubform(input, el))
+
+ elif iType == 'multiradio':
+
+ out.extend(editTypeMultiRadio(input, el))
+
+ elif iType == 'radio':
+ out.extend(editTypeRadio(input, el))
+
+ elif iType == 'dropdown':
+ out.extend(editTypeDropdown(input,el))
+
+ elif iType == 'textarea':
+ out.append(editTypeTextArea(el))
+
+ elif iType == 'tickbox':
+ out.append(editTypeTickBox(input, el))
+ elif iType == 'date':
+ out.append(editTypeDate(el))
+ elif iType == 'datetime':
+ out.append(editTypeDateTime(el))
+ elif iType == 'time':
+ out.append(editTypeTime(el))
+ elif 'calc' in iType:
+ print('CALC TYPE: {}'.format(input))
+ out.append(editTypeCalc(input, el))
+ elif 'text' in input['schemaInputType']:
+ htmlTextString(input, el, out)
+ else:
+ out.append(editTypeText(input,el))
+
+ out.append(' | ')
+ out.append('
')
+
+ if 'branchingquestion' in input:
+ out.extend(editTypeBranch(input, el, 'end'))
+
+
+def htmlInputEdit(input,schema,formRef, subform):
+ out = []
+
+ #print(input)
+ # Special types - shouldn't be here.....
+ toggle_panels = ['ynuo','yn','ny','ynu', 'multipanel']
+
+
+ el = '{}:{}/{}'.format(schema, formRef, input['dataName'])
+ print('TEST EL, ',el, ' TEST EDIT TYPE,',input['inputFormType'])
+ if subform:
+ #must be subform, as includes main element:
+ el = '@BASE_SCHEMA@/{}'.format(input['dataName'])
+
+ iType = input['inputFormType']
+
+ if 'x' in input['hide']:
+ print('Skipping {} - hidden datatype'.format(input['dataName'], input['inputFormType']))
+ elif iType in toggle_panels:
+ print('Toggle panel....')
+ out.extend(editTogglePanel(input,el))
+ elif len(input['children']) > 0:
+ print('{} - {} - has children...'.format(input['dataName'], input['inputFormType']))
+ # check if toggle type with subs....
+
+ elsub ='{}/{}'.format(el,input['subName'])
+ htmlInputEditStandard(input, elsub, out)
+ for i in input['children']:
+ elsub = '{}/{}'.format(el, i['subName'])
+ print('TEST SUB EL, ', elsub, ' TEST EDIT TYPE,', i['inputFormType'])
+ if 'subheader' in i['inputFormType']:
+ out.extend(editTypeSubHeader(i))
+ elif 'header' in i['inputFormType']:
+ out.extend(editTypeHeader(i))
+ elif 'aragraph' in i['inputFormType']:
+ out.extend(editTypeParagraph(i))
+ elif i['inputFormType'] in toggle_panels:
+ out.extend(editTogglePanel(i,elsub))
+ else:
+ htmlInputEditStandard(i, elsub, out)
+ out.append('
|
')
+ else:
+ htmlInputEditStandard(input,el, out)
+ #print('{} - {}'.format(input['dataName'], input['inputFormType']))
+
+ return out
+
+
+def editTypeCalc(input, el):
+ #schematype or inputtype?
+ #return '#fmCalcType("{}" $item $vr "{}")'.format(el, input['inputDataType'])
+ #rounddown, sum, datediff,
+ # datediff NOT from questions - they are entries in the same column! And has formatting....
+ #datediff - [date1,date2, dateformatting options]
+
+ out=[]
+ #datediff = dd
+ if 'dd' in input['inputFormType']:
+
+ #too complex
+ #out.append(''.format(el,el))
+ out = editTypeText(input,el)
+ elif 'sum' in input['inputFormType']:
+ print('SUM, making hidden')
+ out = ''.format(el,el)
+ else:
+ #if statment? just do text box for now
+ out = editTypeText(input,el)
+
+ return out
+
+
+def editTypeCalcJScript(input,schema,formRef):
+ # this creates the javascript at the end
+ # um datediff, can have rounddown and multiple complex datediffs, pluses and minuses
+
+ el = '{}:{}/{}'.format(schema, formRef, input['dataName'])
+ print('test JS: type:{} '.format(input['inputFormType']))
+
+ out=[]
+ dtes = input['options'].split(' ') #already split.... no commas, just spaces....
+
+ if 'dd' in input['inputFormType']:
+ print('test JS - datediff: sc:{} fm:{} in:{}'.format(schema, formRef, input))
+ print(input['rawopts'])
+ print('number of datediffs: {}'.format(input['rawopts'].count('datedif')))
+ if input['rawopts'].count('datedif') == 1:
+
+ if input['rawopts'].count(']') == 2:
+ #simple datediff - sometime ],[, sometimes ], [
+ aarr = input['rawopts'].replace('_','').replace(' ','').split('],[')
+ dt1 = (aarr[0].split('['))[1]
+ dt2 = (aarr[1].split(']'))[0]
+ print('Found dates: {} {} '.format(dt1, dt2))
+ dt1 = '{}:{}/{}'.format(schema, formRef, dt1)
+ dt2 = '{}:{}/{}'.format(schema, formRef, dt2)
+
+ #time.sleep(2)
+ # day, minutes, month etc
+ format = 'd'
+ if '"m"' in aarr[1]:
+ format = 'm'
+
+ out.append(' calcDateDiff(\"{}\",\"{}\", \"{}\", \"{}\" )'.format(dt1,dt2,el, format))
+
+
+ elif 'sum' in input['inputFormType']:
+ print('test JS - sum: sc:{} fm:{} in:{} dtes:{}'.format(schema, formRef, input, dtes))
+ first = True
+ for dt in dtes:
+ a = dt.replace('datediff', '').replace('sum', '').replace(')', '')
+ a = '{}:{}/{}'.format(schema, formRef, a.replace('_',''))
+ if first:
+ args = "[ \"{}\"".format(a)
+ first = False
+ else:
+ args = "{},\"{}\"".format(args,a )
+ args = '{} ]'.format(args)
+ #sys.exit(0)
+ #args = args.replace(' ',',{}:{}/'.format(schema, formRef))
+
+ out.append(" calcSum(\"{}\", {})".format(el,args))
+ return out
+
+
+
+def editTypeHeader(input):
+ head=[]
+
+ head.append('')
+ head.append('{} | '.format(input['question']))
+ head.append(' ')
+ head.append(' | ')
+ head.append('
')
+
+ return head
+
+def editTypeSubHeader(input):
+ head=[]
+
+ head.append('')
+ head.append('{} | '.format(input['question']))
+ head.append(' ')
+ head.append(' | ')
+ head.append('
')
+
+ return head
+
+
+
+def editTypeHtml(input):
+ head=[]
+ head.append(input['question'])
+ return head
+
+def editTypeParagraph(input):
+ head=[]
+ head.append('')
+ head.append('{} | | '.format(input['question']))
+ head.append('
')
+ return head
+
+def editTypeTickBox(input, el):
+ default = 'n'
+ if 'y' in input['options']:
+ default='y'
+ return '#fmBooleanCheckbox("{}" $item $vr "{}")'.format(el, default)
+
+def editTypeTextArea(el):
+
+ return '#xdatTextArea("{}" $item "" $vr 3 60)'.format(el)
+
+def editTypeText(input,el):
+ if "default" in input:
+ return '#xdatTextBox("{}" $item "{}" $vr)'.format(el, input['default'])
+ return '#xdatTextBox("{}" $item "" $vr)'.format(el)
+
+def editTypeSubform(input, el):
+ #format @BASE_ELEMENT@ @SUBFORM@ - repalced later on
+ out = []
+ out.append( '@{}@ @{}@'.format(el, input['options']))
+ return out
+
+def editTypeMultiRadio(input, el):
+ #### so, see if string list. If so,
+ #items = options = input['options'].split(',')
+ out=[]
+ options = input['options'].split(',')
+ #print('# options, multiradio {} - {}'.format(el, options))
+ if len(input['options'])>0:
+ out.append(' #set($list{}={})'.format(input['dataName'],options))
+ out.append(' #renderfmStringMultiRadio("{}" $item $list{} $vr)'.format(el, input['dataName']) )
+
+ return out
+
+
+def editTypeRadio(input, el):
+ #### so, see if string list. If so,
+ #items = options = input['options'].split(',')
+ out=[]
+ options = input['options'].split(',')
+ if len(input['options'])>0:
+ out.append(' #set($list{}={})'.format(input['dataName'],options))
+ out.append(' #renderfmStringRadio("{}" $item $list{} $vr)'.format(el, input['dataName']) )
+ else:
+ out.append(' #fmRadioYesNo("{}" $item "0" $vr)'.format(el))
+ return out
+
+def editTypeDate(el):
+ return '#fmDateBox("{}" $item $vr)'.format(el)
+ #return '#xdatDatetBox("{}" $item $vr $years)'.format(el)
+
+
+def editTypeDateTime(el):
+ dtnum = el.replace(':','').replace('/','')
+ return '#fmDateTimeBox("{}" $item $vr "{}")'.format(el, dtnum)
+ #return '#fmDateTimeLocalBox("{}" $item $vr )'.format(el)
+
+
+def editTypeTime(el):
+ dtnum = el.replace(':','').replace('/','')
+ return '#fmTimeBox("{}" $item $vr "{}")'.format(el, dtnum)
+
+
+
+def editTypeDropdown(input,el):
+
+ out = []
+ # should be comma del by the time you get here
+
+ options = []
+ print('#### DROPDOWN {} - {}'.format(input['inputDataType'], input['options']))
+ #RANGE SAVED AS STRING
+ if input['inputLen']>0:
+ # if inputlen, then save as int.
+ for i in range(0,int(input['inputLen']) + 1 ):
+ options.append("{}".format(i))
+ out.append(' #set($list{}={})'.format(input['dataName'],options))
+ out.append(' #renderfmIntegerDropdown( "{}" $item $list{} $vr)'.format(el,input['dataName']))
+ elif 'tring' in input['inputDataType']:
+ if ',' not in input['options'] and '-' in input['options']:
+ #saved as string
+ options = []
+ opts_range = input['options'].split('-')
+
+ try:
+ min_opt = int(opts_range[0])
+ max_opt = int(opts_range[1])
+ for i in range(min_opt, max_opt + 1):
+ options.append("{}".format(i))
+ except ValueError as ve:
+ options.append(input['options'])
+
+
+ else:
+ options = input['options'].split(',')
+ out.append(' #set($list{}={})'.format(input['dataName'],options))
+ if "default" in input:
+ out.append(' #renderfmStringDropdown("{}" $item $list{} "{}" $vr)'.format(el,input['dataName'],input['default']))
+ else:
+ out.append(' #renderfmStringDropdown("{}" $item $list{} "" $vr)'.format(el,input['dataName']))
+ else:
+ options = input['options'].split(',')
+ #out.append(' #renderfmStringDropdown("{}" $item $list{} $vr)'.format(el,input['dataName']))
+ out.append(' #set($list{}={})'.format(input['dataName'],options))
+ out.append(' #renderfmScalarPropertySelect("{}" $item $list{} $vr)'.format(el,input['dataName']))
+ return out
+
+
+
+
+
+
+def editTypeBranch(input, el, section):
+ out = []
+
+ tog_name = (input['branchingquestion'].split(':')[1]).replace('/', '').replace('_', '')
+ panel_name = get_panel_name(input, tog_name)
+ if 'start' in section:
+ out.append('')
+ out.append(' #set (${} = $!item.getProperty("{}"))'.format(tog_name, input['branchingquestion']))
+ out.append(''.format(panel_name, tog_name, input['branchingvalue']))
+ else:
+ out.append('
')
+ out.append('')
+ return out
+
+def editBranchToggle(input, el):
+ #generic macro - fmGenericStringToggle $name $item $items $default $panel $vals $vr)
+ # numbers each value
+ iType = input['inputFormType']
+ out =[]
+ tog_name = (el.split(':')[1]).replace('/', '').replace('_', '')
+
+ options = input['options'].split(',')
+ vals = ','.join(input['branchVals'])
+
+ if 'default' not in input:
+ default = ''
+ else:
+ default = input['default']
+
+ if 'ynredcap' in iType:
+ out.append(' #fmRedcapBoolToggle("{}" "{}" "panel{}" "{}" $vr)'.format(el, default, tog_name, vals))
+
+ else:
+ out.append(' #set($list{}={})'.format(input['dataName'], options))
+ out.append(' #fmGenericStringToggle("{}" $item $list{} "{}" "panel{}" "{}" $vr)'.format(el, input['dataName'], default, tog_name, vals))
+ print('TOGGLE #fmGenericStringToggle("{}" $item $list{} "{}" {} "{}" $vr)'.format(el,input['dataName'],default,tog_name,vals))
+ #time.sleep(2)
+ #os.exit(0)
+ return out
+
+
+def editTogglePanel(input,el):
+
+ out =[]
+ iType = input['inputFormType']
+ if 'multipanel' in iType:
+ #count number of yes, then split later....
+ opts = input['options'].replace(';','').replace(',','').replace('=','').rstrip()
+ qs = opts.split('N')
+ #print('options: {} '.format(qs))
+ yes_qs = int(qs[0].replace('Y',''))
+ no_qs = int(qs[1].replace('N',''))
+ #print('{} y:{} n:{} '.format(qs, yes_qs, no_qs))
+ tog_name = '{}{}'.format(input['formRef'], input['dataName'])
+ if input['subName'] != '':
+ tog_name = '{}{}'.format(tog_name, input['subName'])
+ el = '{}/{}'.format(el, input['subName'])
+
+ panel_name = get_panel_name(input, tog_name)
+
+ #("toggle type: element:{} - {}".format(el, input))
+ out.append('')
+ out.append(' {} | '.format(input['question']))
+ out.append(' ')
+
+ if 'ynuo' in iType:
+ out.append(' #fmRadioYesNoUnableOtherTogglePanel("{}/completed" $item "{}" $vr)'.format(el, panel_name))
+ out.append(' #set (${} = $!item.getProperty("{}/completed"))'.format(tog_name, el))
+
+ out.append(' '.format(panel_name,tog_name) )
+ out.append(' #getUnableCategories()')
+ out.append(' Reason for not completing: | #renderfmScalarPropertySelect("{}/reasonNotAble" $item $unableCategories $vr) | '.format(el) )
+ out.append(' ')
+ elif 'ny' in iType:
+ out.append(' #fmRadioNoYesToggle("{}" $item 0 "{}" $vr)'.format(el, panel_name))
+ out.append(' #set (${} = $!item.getProperty("{}"))'.format(tog_name, el))
+ elif 'multipanel' in iType:
+ out.append(' #fmRadioYesNoBothToggle("{}" $item 0 "{}Y" "{}N" $vr)'.format(el, panel_name, panel_name))
+ out.append(' #set (${} = $!item.getProperty("{}"))'.format(tog_name, el))
+ else:
+ out.append(' #fmRadioYesNoToggle("{}" $item 0 "{}" $vr)'.format(el, panel_name))
+ out.append(' #set (${} = $!item.getProperty("{}"))'.format(tog_name, el))
+
+
+ childRows = []
+ childRowsY = []
+ childRowsN = []
+ #if i have children, all for answer yes at the moment
+ if len(input['children']) > 0:
+ if 'multipanel' in iType:
+ ii = 0
+ for c in input['children']:
+ el = '{}:{}/{}/{}'.format(c['schema'], c['formRef'], input['dataName'], c['subName'])
+ if ii < yes_qs:
+ htmlInputEditStandard(c, el, childRowsY)
+ else:
+ htmlInputEditStandard(c, el, childRowsN)
+ ii += 1
+
+ else:
+ for c in input['children']:
+ el='{}:{}/{}/{}'.format(c['schema'],c['formRef'],input['dataName'],c['subName'])
+ htmlInputEditStandard(c,el, childRows)
+ #print('adding child rows to toggle panel:{} {} {} {}'.format(el, c['subName'],c['schema'],c['formRef']) )
+ if len(childRows) > 0 and 'ynuo' in iType:
+ out.append(' '.format(panel_name,tog_name) )
+ out.extend(childRows)
+ out.append(' ')
+ elif len(childRows) > 0 and 'yn' in iType:
+ out.append(' '.format(panel_name,tog_name) )
+ out.extend(childRows)
+ out.append(' ')
+ if len(childRows) > 0 and 'ny' in iType:
+ out.append(' '.format(panel_name,tog_name) )
+ out.extend(childRows)
+ out.append(' ')
+ if len(childRowsY) > 0 and 'multip' in iType:
+ out.append(' '.format(panel_name,tog_name) )
+ out.extend(childRowsY)
+ out.append(' ')
+ out.append(' '.format(panel_name,tog_name) )
+ out.extend(childRowsN)
+ out.append(' ')
+ out.append(' | ')
+ out.append('
')
+
+ return out
+
+
+
+def cleanForm(out):
+ ln = 0
+ for line in out:
+ if ln > 0:
+ if out[ln] == out[ln-1]:
+ if '
|
' in out[ln]:
+ del out[ln]
+ ln = ln +1
+ return out
\ No newline at end of file
diff --git a/builder/html_vm_report.py b/builder/html_vm_report.py
new file mode 100644
index 0000000..958c974
--- /dev/null
+++ b/builder/html_vm_report.py
@@ -0,0 +1,288 @@
+def get_panel_name(input, tog_name):
+ panel_name = 'panel{}'.format(tog_name)
+ if 'panelNum' in input:
+ panel_name = 'panel{}{}'.format(tog_name, input['panelNum'])
+ return panel_name
+
+def htmlTextString(input,el, out):
+ iType = input['inputFormType']
+ # print('Test Report: {}'.format(input))
+ if 'subheader' in iType:
+ print('REPORT-SUBHEADER: {} - {} '.format(input['question'], input['inputFormType']))
+ out.extend(reportTypeSubHeader(input))
+ elif 'eader' in iType:
+ print('REPORT-HEADER: {} - {} '.format(input['question'], input['inputFormType']))
+ out.extend(reportTypeHeader(input))
+ elif 'aragraph' in iType:
+ print('REPORT-PARAGRAPH: {} - {} '.format(input['question'], input['inputFormType']))
+ out.extend(reportTypeParagraph(input))
+
+
+def htmlInputReportStandard(input,el, out):
+ dType = ""
+ if input['inputDataType']:
+ dType = input['inputDataType']
+ iType = input['inputFormType']
+ if 'text' in input['schemaInputType']:
+ htmlTextString(input, el, out)
+
+ else:
+ if 'branchingquestion' in input:
+ # only show if....
+ out = reportTypeBranch(input, out)
+ else:
+ out.append('')
+
+ out.append('{} | '.format(input['question']))
+
+ out.append('')
+
+ if iType == 'radio':
+ out.append(reportTypeRadio(input, el))
+
+ elif iType == 'subform':
+ out.extend(reportTypeSubform(input, el))
+
+ elif iType == 'dropdown' and dType == 'int':
+
+ out.extend(reportTypeDropdown(input,el))
+
+ elif iType == 'tickbox':
+ out.append(reportTypeTickBox(el))
+
+ elif iType == 'date':
+ out.append(reportTypeDateBox(el))
+
+ elif iType == 'datetime':
+ out.append(reportTypeDateTimeBox(el))
+
+ elif iType == 'ynredcap':
+ #just shows boolean
+ out.append(reportTypeTickBox(el))
+
+ else:
+ out.append(reportTypeText(el))
+
+ out.append(' | ')
+ out.append('
')
+
+def htmlInputReport(input,schema,formRef, subform):
+ toggle_panels = ['ynuo','yn','ny','ynu', 'multipanel']
+ out =[]
+
+ el='{}:{}/{}'.format(schema,formRef,input['dataName'])
+ if subform:
+ #must be subform, as includes main element:
+ el = '@BASE_SCHEMA@/{}'.format(input['dataName'])
+
+ iType = input['inputFormType']
+
+ if 'x' in input['hide']:
+ print('Skipping {} - {} - hidden datatype'.format(input['dataName'], input['inputFormType']))
+ elif iType in toggle_panels:
+ out.extend(reportTogglePanel(input,el))
+ elif len(input['children']) > 0:
+ elsub='{}/{}'.format(el,input['subName'])
+ htmlInputReportStandard(input, elsub, out)
+ for i in input['children']:
+ print('REPORT-test: {}'.format(i))
+ elsub ='{}/{}'.format(el,i['subName'])
+ if 'subheader' in i['inputFormType']:
+ print('SUB: REPORTSUBHEADER {}'.format(i['question']))
+ out.extend(reportTypeSubHeader(i))
+ elif 'eader' in i['inputFormType']:
+ print('SUB: REPORTHEADER {}'.format(i['question']))
+ out.extend(reportTypeHeader(i))
+ elif 'aragraph' in i['inputFormType']:
+ print('SUB: REPORT PARAGRAPH {}'.format(i['question']))
+ out.extend(reportTypeParagraph(i))
+ elif i['inputFormType'] in toggle_panels:
+ out.extend(reportTogglePanel(i,elsub))
+ else:
+ htmlInputReportStandard(i, elsub, out)
+ out.append('
|
')
+ else:
+ htmlInputReportStandard(input, el, out)
+
+
+ return out
+
+def reportTypeHeader(input):
+ head=[]
+
+ head.append('')
+ head.append('{} | '.format(input['question']))
+ head.append(' ')
+ head.append(' | ')
+ head.append('
')
+
+ return head
+
+
+
+def reportTypeSubHeader(input):
+ head=[]
+
+ head.append('')
+ head.append('{} | '.format(input['question']))
+ head.append(' ')
+ head.append(' | ')
+ head.append('
')
+
+ return head
+
+
+def reportTypeBranch(input, out):
+ tog_name = input['branchingquestion'].replace('/', '').replace(':', '').replace('_', '')
+ out.append(' #set (${} = $!item.getProperty("{}"))'.format(tog_name, input['branchingquestion']))
+ out.append(''.format(tog_name, input['branchingvalue']))
+ return out
+
+def reportTypeParagraph(input):
+ out=[]
+
+ if 'branchingquestion' in input:
+ out = reportTypeBranch(input, out)
+ else:
+ out.append('
')
+ out.append('{} | '.format(input['question']))
+ out.append('
')
+
+ return out
+
+def reportTypeSubform(input, el):
+ #format @BASE_ELEMENT@ @SUBFORM@ - repalced later on
+ out = []
+ out.append('@{}@ @{}@'.format(el, input['options']))
+ return out
+
+def reportTypeDateTimeBox(el):
+ return '#showDateTime("{}" $item)'.format(el)
+
+def reportTypeDateBox(el):
+ return '#showDate("{}" $item)'.format(el)
+
+
+def reportTypeTickBox(el):
+
+ return '#showfmBoolean("{}" $item)'.format(el)
+
+def reportTypeText(el):
+
+ return '$!item.getStringProperty("{}")'.format(el)
+
+def reportTypeRadio(input, el):
+ if len(input['options'])>0:
+ return ' $!item.getProperty("{}")'.format(el)
+ else:
+ return '#showfmBoolean("{}" $item)'.format(el)
+
+
+def reportTypeDropdown(input,el):
+
+ out = []
+ options = []
+
+
+ if input['inputLen'] > 0:
+ # then take from length
+ for i in range(0, int(input['inputLen']) + 1):
+ options.append("{}".format(i))
+ else:
+ if ',' not in input['options'] and '-' in input['options']:
+ #saved as string
+ opts_range = input['options'].split('-')
+ min_opt= int(opts_range[0])
+ max_opt= int(opts_range[1])
+ for i in range(min_opt, max_opt + 1):
+ options.append("{}".format(i))
+ else:
+ options = input['options'].split(',')
+
+
+
+ print(options,el,input['dataName'])
+ if 'nt' not in input['inputDataType']:
+ out.append(' $!item.getProperty("{}")'.format(el) )
+ else:
+ out.append(' #set($list{}={})'.format(input['dataName'],options))
+ out.append(' #showScalarIntProperty("{}" $item $list{} )'.format( el,input['dataName']))
+ return out
+
+
+def reportTogglePanel(input,el):
+
+ out =[]
+ iType = input['inputFormType']
+ if 'multipanel' in iType:
+ #count number of yes, then split later....
+ opts = input['options'].replace(';','').replace(',','').replace('=','')
+ qs = opts.split('N')
+ print('options: {} '.format(qs))
+ yes_qs = int(qs[0].replace('Y',''))
+ no_qs = int(qs[1].replace('N',''))
+ print('{} y:{} n:{} '.format(qs, yes_qs, no_qs))
+
+ tog_name = '{}{}'.format(input['formRef'],input['dataName'])
+ if input['subName'] != '':
+ tog_name = '{}{}'.format(tog_name,input['subName'])
+ el = '{}/{}'.format(el, input['subName'])
+
+ panel_name = get_panel_name(input, tog_name)
+ print("toggle type: element:{} - {}".format(el, input))
+ out.append('')
+ out.append('{} | '.format(input['question']))
+ out.append(' ')
+
+ if 'ynuo' in iType:
+ out.append(' #showNoYesUnableOther("{}/completed" $item "{}" $vr)'.format(el, panel_name))
+ out.append(' #set (${} = $!item.getProperty("{}/completed"))'.format(tog_name, el))
+
+ out.append(' '.format(panel_name,tog_name) )
+ out.append(' Reason for not completing: | #showReasonUnable("{}/reasonNotAble" $item) | '.format(el))
+ out.append(' ')
+ else:
+ out.append(' #showYesNo("{}" $item "{}")'.format(el, panel_name))
+ out.append(' #set (${} = $!item.getProperty("{}"))'.format(tog_name, el))
+
+ childRows = []
+ childRowsY = []
+ childRowsN = []
+ #if i have children, all for answer yes at the moment
+ if len(input['children']) > 0:
+ if 'multipanel' in iType:
+ ii = 0
+ for c in input['children']:
+ el = '{}:{}/{}/{}'.format(c['schema'], c['formRef'], input['dataName'], c['subName'])
+ if ii < yes_qs:
+ htmlInputReportStandard(c,el, childRowsY)
+ else:
+ htmlInputReportStandard(c,el, childRowsN)
+ ii += 1
+
+ else:
+ for c in input['children']:
+ el='{}:{}/{}/{}'.format(c['schema'],c['formRef'],input['dataName'],c['subName'])
+ htmlInputReportStandard(c,el, childRows)
+ print('adding child rows to report panel:{} {} {} {}'.format(el, c['subName'],c['schema'],c['formRef']) )
+ #childRows.extend(htmlInputReport(c,c['schema'],c['formRef']))
+ print('itype: {} childRowsN {}'.format(iType, childRowsN))
+ if len(childRows) > 0 and 'yn' in iType:
+ out.append(' '.format(panel_name,tog_name) )
+ out.extend(childRows)
+ out.append(' ')
+ if len(childRows) > 0 and 'ny' in iType:
+ out.append(' '.format(panel_name,tog_name) )
+ out.extend(childRows)
+ out.append(' ')
+ if len(childRowsY) > 0 and 'multip' in iType:
+ out.append(' '.format(panel_name,tog_name) )
+ out.extend(childRowsY)
+ out.append(' ')
+ out.append(' '.format(panel_name,tog_name) )
+ out.extend(childRowsN)
+ out.append(' ')
+
+ out.append(' |
')
+
+ return out
diff --git a/builder/loader_redcap.py b/builder/loader_redcap.py
new file mode 100644
index 0000000..bc0d0dd
--- /dev/null
+++ b/builder/loader_redcap.py
@@ -0,0 +1,565 @@
+import csv
+import os
+import sys
+import time
+
+
+class LoaderRedcap(object):
+
+
+ #NOTES:
+ # some are required BUT only if showing - ie, branched questions. So skip required if from branched
+
+
+ def __init__(self, configData):
+
+ self.errors = []
+ self.log =[]
+ self.configData = configData
+ self.allowedFormTypes = ['text','dropdown','radio', 'multiradio', 'calc','tickbox','yn','ny','ynu','ynuo','textbox', 'textarea','date', 'header', 'subheader', 'paragraph', 'insertparagraph', 'datetime']
+ self.allowedDataTypes = ['string', 'bool', 'float', 'int', 'header', 'complex', 'date', 'dateTime']
+ self.allowedExtensions = ['subject', 'image', 'session']
+ self.allowedDropDownTypes = ['int', 'string']
+ self.toggle_panels = ['ynuo','yn','ny','ynu']
+ self.textFormTypes = ['header', 'subheader', 'paragraph', 'text']
+
+
+ def hasError(self):
+ return len(self.errors)
+
+ def errors(self):
+ return self.errors
+
+ def dos2unix(self, path):
+ #have to convert
+ os.system("find ./redcap_dict/* -name *.csv -type f -exec dos2unix -u {} \; ")
+
+ def filesList(self,path):
+ out = []
+ for file in os.listdir(path):
+ if file.endswith('.csv') and '~' not in file:
+ out.append(file)
+
+ return out
+
+ def loadRedcap(self,path,fileName):
+
+ #schema name MUST be filename??
+ # take as parmetrs?
+
+ out = {'schema': '', 'order': [], 'forms': dict()}
+
+
+ schemaName = fileName.replace(".csv", "").replace("_","").replace("-","")
+ out['schema'] = schemaName
+ out['restrict_to_project'] = ''
+
+
+ data = dict()
+ questions = dict()
+ qs = []
+ strId = ""
+
+ fullPath = ('{}/{}' .format(path,fileName))
+
+
+
+ #windows-1252?? convert beforehand
+
+ with open(fullPath, mode='r', encoding='windows-1252') as redcap_csv:
+ csv_reader = csv.DictReader(redcap_csv)
+ print(f'Column names are ', csv_reader.fieldnames)
+ line_count = 0
+ prev_form_name = ""
+
+ try:
+
+ for row in csv_reader:
+
+ line_count += 1
+ #ignore images
+ if "img src" not in row["Field Label"]:
+
+ print('#########')
+ #print(row)
+ if row["Form Name"] != prev_form_name:
+ ## complete previous
+ if len(strId) > 0:
+ for q in qs:
+ if 'branch_logic' in q:
+ qs = self.cleanBranching(qs, q)
+ out['forms'][strId]['inputs'] = self.sortByDataName(qs)
+ qs = []
+
+ # The same.... ID and Name
+ prev_form_name = row["Form Name"]
+ strId = row["Form Name"]
+ ## Bean can be tooo long
+ full_length = '{}{}'.format(schemaName, strId.replace("_"," "))
+ if len(full_length) > 68:
+ self.errors.append("Error reading rows: File {} Form {} is too long - {} chars. Replace Form Name in csv or shorten filename".format(schemaName, strId, len(full_length)))
+
+
+ formName = row["Form Name"].replace("_"," ").lower() # the form title
+ formRef = row["Form Name"].replace("_","").replace(' ', '').lower() # database name
+ ext = 'subject'
+ desc = row["Form Name"]
+
+ strId = strId.replace(' ', '')
+ data = dict()
+ data['strId'] = strId
+ data['name'] = formName.replace("'","").replace('-', '')
+ data['ref'] = formRef.replace(' ', '').replace("'","").replace('-', '').lower()
+
+ data['inputs'] = []
+ data['ext'] = ext.lower()
+ data['desc'] = desc
+ data['schema'] = schemaName
+
+ out['order'].append(strId)
+ out['forms'][strId] = data
+ print("Found form:{} - {}".format(strId, out['forms'][strId]['name']))
+
+
+ ## read questions in
+ section_header = self.cleanCellValue(row["Section Header"]).replace('align:center;', 'align:left;')
+ # add paragraph for section_header - ignoring any images
+ if len(section_header) > 1:
+ questions = dict()
+ questions['parent'] = ''
+ questions['children'] = []
+ questions['schema'] = schemaName
+ questions['formRef'] = data['ref']
+
+ questions['question'] = section_header
+ questions['dataName'] = ''
+ questions['subName'] = ''
+ questions['inputFormType'] = 'paragraph'
+ questions['inputDataType'] = ''
+ questions['inputLen'] = 0
+ questions['required'] = '0'
+ questions['schemaInputType'] = 'text'
+ questions['hide'] = ''
+ qs.append(questions)
+
+ questions = dict()
+ questions['question'] = self.cleanCellValue(row["Field Label"]).replace('align:center;', 'align:left;')
+
+ questions['dataName'] = self.cleanCellValue(row["Variable / Field Name"]).replace("_","")
+ fieldType = self.cleanCellValue(row["Field Type"])
+ required = self.cleanCellValue(row["Required Field?"])
+ annotation= self.cleanCellValue(row["Field Annotation"])
+ #print(row["Choices, Calculations, OR Slider Labels"])
+
+ opts = self.cleanDropDownOptions(row["Choices, Calculations, OR Slider Labels"])
+ #print(opts)
+
+ questions['rawopts'] = row["Choices, Calculations, OR Slider Labels"]
+
+ questions['inputLenType'] = self.cleanCellValue(row["Text Validation Type OR Show Slider Number"])
+ inputLenMin = self.cleanCellValue(row["Text Validation Min"])
+ inputLenMax = self.cleanCellValue(row["Text Validation Max"])
+ questions['inputLen'] = 0
+ if inputLenMax != '':
+ if 'int' in questions['inputLenType']:
+ questions['inputLen'] = int(inputLenMax)
+ if 'numb' in questions['inputLenType']:
+ questions['inputLen'] = float(inputLenMax)
+ # IF date_dmy, or time then NOT text as shown in field type
+
+
+ questions['inputFormType'], questions['inputDataType'] = self.convertFieldType(fieldType, row["Choices, Calculations, OR Slider Labels"], questions['inputLenType'])
+
+
+ if 'multiradio' in questions['inputFormType']:
+ num = 1
+ for opt in opts.split(','):
+ print('test, option:',opt)
+ questions = dict()
+ questions['dataName'] = self.cleanCellValue(row["Variable / Field Name"]).replace("_","")
+ questions['inputDataType'] = 'boolean'
+ questions['inputFormType'] = 'tickbox'
+ questions['question'] = '{} - {}'.format(self.cleanCellValue(row["Field Label"]).replace('align:center;', 'align:left;'), opt)
+ questions['inputLen'] = 0
+ questions['required'] = '0'
+ questions['hide'] = ''
+ questions['options'] = ''
+
+ questions['parent'] = ''
+ questions['children'] = []
+ questions['schema'] = schemaName
+ questions['formRef'] = data['ref']
+ # does nto exist in redcap
+ questions['subName'] = num
+ questions['schemaInputType'] = self.schemaInputType(questions['inputFormType'], questions['inputDataType'])
+ num += 1
+
+ qs.append(questions)
+ else:
+
+ questions['parent'] = ''
+ questions['children'] = []
+ questions['schema'] = schemaName
+ questions['formRef'] = data['ref']
+ #does nto exist in redcap
+ questions['subName'] = ""
+
+ questions['required'] = '0'
+ #Skip if conditional required - ie, required if X is selected
+ if 'y' in required and not len(self.cleanCellValue(row["Branching Logic (Show field only if...)"])) > 0:
+ questions['required'] = '1'
+
+ questions['options']= opts
+ questions['hide'] = ''
+
+ if 'HIDE' in annotation:
+ questions['hide'] = 'x'
+ if 'DEFAULT' in annotation:
+ questions['default'] = annotation.replace('@DEFAULT','').replace('=','').replace('"','')
+ defaultopts = row["Choices, Calculations, OR Slider Labels"].split('|')
+ for op in defaultopts:
+ if questions['default'] in op:
+ op = op.translate({ord(c): "" for c in "!@#$%^&*()[]{};:./<>?\`~-=_+"})
+ questions['default'] = " ".join(op.split()[1:])
+
+ print('Default found: {}'.format(questions['default']))
+ if 'aken' in defaultopts:
+ sys.exit()
+
+ questions['schemaInputType'] = self.schemaInputType(questions['inputFormType'], questions['inputDataType'])
+ #other
+
+ if len(self.cleanCellValue(row["Branching Logic (Show field only if...)"])) > 0:
+ print('Only show if - found: ', row["Branching Logic (Show field only if...)"])
+ questions['branch_logic'] = row["Branching Logic (Show field only if...)"]
+
+
+ if len(self.cleanCellValue(row["Field Note"])) > 0:
+ questions['note'] = self.cleanCellValue(row["Field Note"])
+ questions['question'] = '{} ({})'.format(questions['question'], questions['note'])
+
+ qs.append(questions)
+
+ if not questions['question']:
+ print('No question found! form name:{} section_header:{}'.format(row["Form Name"], section_header))
+ continue
+
+
+ #in case there is no extra line, then skips...
+ if len(qs) > 0:
+ for q in qs:
+ if 'branch_logic' in q:
+ qs = self.cleanBranching(qs, q)
+ out['forms'][strId]['inputs'] = self.sortByDataName(qs)
+ qs = []
+ except Exception as e:
+ self.errors.append("Error - last form {} line {} {} - reading rows: {}".format(prev_form_name,line_count,questions['question'],e))
+ print(self.errors())
+ sys.exit(0)
+
+
+ for x in out['forms']:
+ self.checkForm(out['forms'][x])
+
+ return out
+
+
+
+ def checkInput(self,formName,i):
+
+ # check form type
+ if i['inputFormType'] not in self.allowedFormTypes :
+ self.errors.append('Form {} Question : {} ,Invalid Form Type {} '.format(formName, i['question'],i['inputFormType']))
+
+ # check data type
+ if (i['inputDataType'] != '') and (i['inputDataType'] not in self.allowedDataTypes) :
+ self.errors.append('Form {} Question : {} ,Invalid Data Type {} '.format(formName, i['question'],i['inputDataType']))
+
+
+ def convertFieldType(self, fieldType, opts, lenType):
+
+ #Lentype Has to come first, as string in redcap
+ if 'datetime' in lenType:
+ return 'datetime','string'
+ elif 'date' in lenType:
+ return 'date','date'
+ elif 'time' in lenType:
+ return 'time','string'
+ elif 'number' in lenType:
+ return 'textbox','float'
+ elif 'integer' in lenType:
+ return 'textbox','integer'
+
+ if 'text' in fieldType:
+ return 'textbox','string'
+ if 'calc' in fieldType:
+ #datediff and sums...
+ if 'if(' in opts and 'datediff' in opts:
+ # just do text box for now
+ return 'calcifdd', 'string'
+ if 'if(' in opts and 'sum' in opts:
+ # just do text box for now
+ return 'calcifsum', 'string'
+ if 'if(' in opts:
+ # just do text box for now
+ return 'calcif', 'string'
+ elif 'datediff' in opts:
+ return 'calcdd', 'float'
+ elif 'sum' in opts:
+ return 'calcsum', 'float' # need to make hidden in edit form. Usually date difference
+ else:
+ #just do text box for now
+ return 'calc', 'string'
+ if 'yesno' in fieldType or 'truefalse' in fieldType:
+ return 'tickbox', 'boolean'
+ if 'notes' in fieldType:
+ return 'textarea', 'string'
+ if 'radio' in fieldType:
+ return 'radio', 'string'
+ if 'descriptive' in fieldType:
+ return 'paragraph', ''
+ if 'dropdown' in fieldType:
+ return 'dropdown', 'string'
+ if 'checkbox' in fieldType:
+ return 'multiradio', 'string'
+
+
+ def schemaInputType(self,formType,dataType):
+ iType='none'
+ if formType.lower() in self.textFormTypes:
+ iType = 'text'
+ return iType
+ else:
+ iType = 'string' if not dataType else dataType
+
+
+ if 'ool' in dataType:
+ iType='boolean'
+
+ elif 'int' in dataType:
+ iType='integer'
+ elif 'loat' in dataType:
+ iType='float'
+
+ elif formType == 'date':
+ iType = 'date'
+ elif formType == 'datetime':
+ iType = 'string'
+ if formType.lower() in self.textFormTypes:
+ iType == 'text'
+ if formType == 'dropdown' and not dataType:
+ #only assumes int if specifies int
+ iType = 'string'
+
+ if 'tickbox' in formType:
+ iType='boolean'
+
+ return iType
+
+ def setLength(self,data):
+ if not data:
+ return 0
+ else:
+ try:
+ return int(data)
+ except Exception as e:
+ print("not an int - {} - floats not restictable? {}".format(data))
+ return ''
+
+ def cleanBranching(self, qs, question ):
+
+ ## example: in 'Branching Logic (Show field only if...)
+ # [c_section] = '1' - NOT in order, can be anywhere. Also can be muitple OR or refer from another form
+ # panel name: [original question - dataname][panel num]
+ # generic macro - fmGenericStringToggle $name $item $items $default $panel $vals $vr)
+ # for each value, numbers it. Then on each click has a panel.
+ # issue -it appears not in order - the original question can be after
+
+ # only do if simple - so only one
+
+ condition = question['branch_logic']
+ if len(condition.split('=')) == 2:
+ a = condition.split('=')
+ #val = self.cleanDropDownOptions(a[1])#.replace("'","").replace('"','').replace(" ","")
+ val = a[1].replace("'","").replace('"','').replace(" ","")
+
+
+ # excludes referencs to other forms
+ if len(a[0].split(']')) == 2:
+ #el is branching question
+ el = a[0].replace('[','').replace(']','').replace('_','').replace(" ","")
+ print(a, val,el)
+ if ')' not in el:
+ for q in qs:
+ #print(q['dataName'])
+ if q['dataName'] == el:
+ print("CLEAN BRANCHING: FOUND EL {} question: {} val: -{}- schme type: {}".format(el, q['dataName'], val, q['schemaInputType']))
+ if 'ool' in q['schemaInputType']:
+ val = val.replace(" ","")
+ print("FOUND BOOLEAN val {}".format(val))
+ #ynredcap - can open both if 0 or 1
+ q['inputFormType'] = 'ynredcap'
+ if 'branchNum' in q:
+ print(q['branchNum'])
+ q['branchNum'] += 1
+ else:
+ q['branchNum'] = 1
+
+ if 'branchVals' not in q:
+ q['branchVals'] =''
+ if '0' in val:
+ question['panelNum'] = '{}'.format(q['branchNum'])
+ q['branchVals'] = '{}{}'.format(q['branchVals'], 'N')
+ else:
+ question['panelNum'] = '{}'.format(q['branchNum'])
+ q['branchVals'] = '{}{}'.format(q['branchVals'], 'Y')
+
+ elif 'rawopts' in q:
+ for option in q['rawopts'].split('|'):
+
+ if '{},'.format(val) in option:
+ if 'branchVals' not in q:
+ q['branchVals'] = []
+ # remove the option number (format, example '1, yes')
+ val = " ".join(option.split()[1:]).replace(',','')
+ print("FOUND conditional_val: {} option: {}".format(val, option))
+ q['branchVals'].append(val.translate ({ord(c): "" for c in "!@#$%^&*()[]{};:./<>?\`~-=_+"}))
+ if 'branchNum' in q:
+ print(q['branchNum'])
+ q['branchNum'] += 1
+ else:
+ q['branchNum'] = 1
+
+ question['panelNum'] = q['branchNum']
+
+
+ el = '{}:{}/{}'.format(question['schema'], question['formRef'], el)
+
+ question['branchingquestion'] = el
+ question['branchingvalue'] = val.translate ({ord(c): "" for c in "!@#$%^&*()[]{};:./<>?\`~-=_+"})
+ if 'branchNum' in q:
+ print("BRANCHING CLEANING: bracnch found in: {} element {} PanelNUm: {} value {} ".format(question['dataName'], el,question['branchNum'], question['branchingvalue']))
+ #time.sleep(2)
+ ## if redoing, then replace existing:
+ for q in qs:
+ if q['dataName'] == question['dataName']:
+ q['branchingquestion'] = question['branchingquestion']
+ if 'panelNum' in q:
+ print('panel num:',question['panelNum'])
+ q['panelNum'] = question['panelNum']
+ q['branchingvalue'] = question['branchingvalue']
+
+ return qs
+
+
+
+
+
+ def cleanCellValue(self,data):
+
+ if (not data or data == None):
+
+ return ''
+ data = data.strip().encode('ascii', 'ignore')
+ data_str=data.decode()
+
+ return data_str
+
+ # return '' if not data else data.strip()
+
+ def cleanDropDownOptions(self,o):
+
+ # in redcap split by | - need to replace with ,
+ bstr= '{}'.format(o)
+ # have to replace as | sepreated, and need to change to comma seperated
+ bstr = bstr.replace(",", " ")
+
+ bstr = bstr.translate ({ord(c): "" for c in "!@#$%^&*()[]{};:./<>?\`~-=_+"})
+
+ cstr = ''
+ first=True
+ for i in bstr.split('|'):
+ if first:
+ cstr = " ".join(i.split()[1:])
+ #print('test opts in redcap: 1st:', i, ' cstr:', cstr)
+ first = False
+ #sys.exit(0)
+ else:
+ cstr = '{},{}'.format(cstr, " ".join(i.split()[1:]))
+ #cstr = cstr[2:]
+
+ return cstr
+
+ def sortByDataName(self,inputs):
+
+ temp = {'order': [], 'inputs' : {}}
+ out = []
+ #urgh, fix to stop recounting repeated paragraphs/headers
+ textnum = 555
+ for i in inputs:
+
+ dataName = i['dataName']
+ if i['inputFormType'] in self.textFormTypes:
+ dataName = str(textnum)
+ textnum = textnum + 1
+
+ if dataName in temp['inputs'].keys():
+ i['parent'] = dataName
+ temp['inputs'][dataName]['children'].append(i)
+ else:
+ temp['inputs'][dataName] = i
+ temp['order'].append(dataName)
+ # out[i['dataName']] = [i]
+
+ for o in temp['order']:
+ out.append(temp['inputs'][o])
+ #print('------------###########-----------')
+ #print('{}'.format(out))
+ #print temp['order']
+ return out
+
+ #TODO needs update
+ def checkForm(self,form):
+
+
+
+
+ if form['ext'] not in self.allowedExtensions :
+ self.errors.append('Form {} Invalid Extension {} '.format(form['name'], form['ext']))
+ # already checked if no inputs
+ # reset list for questions
+ qs = []
+
+ for i in form['inputs']:
+ print('CHECKDATA: {}'.format(i))
+ # yn do not NEED subnames as already exist. (completed, reasonnotable)
+ #if 'yn' in i['inputFormType'] and len(i['subName'])<1:
+ # self.errors.append('Form {} has missing subname: {} - {} - {}'.format(form['name'], i['question'],i['dataName'], i['inputFormType']))
+
+
+ temp = i['question'].replace(" ",'') + i['dataName']
+ if temp in qs and i['inputFormType'] not in self.textFormTypes:
+ self.errors.append('Form {} has Dupe input {} - {}'.format(form['name'], i['question'],i['dataName']))
+ else:
+ qs.append(temp)
+ # not for redcap, not doing subtypes
+ #if len(i['children']) < 1 and i['inputFormType'] in self.toggle_panels:
+ # self.errors.append('Form {}: Question: {} - Panel Toggle Type {} has no subtypes! '.format(form['name'], i['question'],i['dataName']))
+
+
+ #TODO check for group inputs with no subname
+
+ def printForms(self,forms):
+
+ # already checked if no inputs
+ for f in forms:
+ print('Form {}'.format(forms[f]['name']))
+ print('schema {}'.format(forms[f]['schema']))
+
+ for i in forms[f]['inputs']:
+ print(' -- input : question {} : Type {}'.format(i['question'], i['inputFormType']))
+ if len(i['children']) > 0:
+ for c in i['children']:
+ print(' -- input : question {} : Type {}'.format(c['question'],c['inputFormType']))
+
+
diff --git a/builder/loader_xlsx.py b/builder/loader_xlsx.py
new file mode 100644
index 0000000..4d3c825
--- /dev/null
+++ b/builder/loader_xlsx.py
@@ -0,0 +1,486 @@
+import os
+
+
+from openpyxl import load_workbook
+
+class LoaderXlsx(object):
+
+ def __init__(self, configData):
+
+ self.errors = []
+ self.log =[]
+ self.configData = configData
+ self.allowedFormTypes = ['subform','text','dropdown','radio', 'tickbox','checkbox','yn','ny','ynu','ynuo','multipanel', 'textbox', 'textarea','date', 'header', 'subheader', 'paragraph', 'datetime', 'time']
+ self.allowedDataTypes = ['string', 'bool', 'float', 'int', 'header', 'complex', 'date','dateTime']
+ self.allowedExtensions = ['subform','subject', 'image', 'session']
+ self.allowedDropDownTypes = ['int', 'string']
+ self.toggle_panels = ['ynuo','yn','ny','ynu', 'multipanel']
+ self.textFormTypes = ['header', 'subheader', 'paragraph', 'text']
+
+ def hasError(self):
+ return len(self.errors)
+
+ def errors(self):
+ return self.errors
+
+
+ def filesList(self,path):
+ out = []
+ for file in os.listdir(path):
+ if file.endswith('.xlsx') and '~' not in file:
+ out.append(file)
+
+ return out
+
+ def loadExcel(self,path,fileName):
+
+ fullPath = ('{}/{}' .format(path,fileName))
+ wb = load_workbook(fullPath)
+ out = {'schema': '', 'order' :[] , 'forms':dict()}
+
+ formnames = [] # check for duplicates
+ subformnames = [] # check for duplicates
+
+ out['foundFormDetails'] = False
+
+ for ws in wb:
+
+ if ws.title == 'FormDetails':
+ out['foundFormDetails'] = True
+ schemaName = ws['B1'].value.replace(' ', '').replace("'","").replace('-', '')
+ out['schema'] = schemaName.replace(' ', '').replace("'","").replace('-', '')
+
+
+ out['restrict_to_project'] = ''
+ if ws['A2'].value:
+ if 'Restrict to Project' in ws['A2'].value:
+ if ws['B2'].value:
+ restricted_proj = ws['B2'].value.replace(' ', '').replace("'", "").replace('-', '')
+ out['restrict_to_project'] = restricted_proj.replace(' ', '').replace("'", "").replace('-', '')
+
+
+ for x in range(3,100):
+
+ data = dict()
+
+ strId = self.cleanCellValue(ws['A'+str(x)].value)
+ if 'Form' in strId:
+ formName = self.cleanCellValue(ws['B'+str(x)].value)
+ formRef = self.cleanCellValue(ws['C'+str(x)].value)
+ ext = self.cleanCellValue(ws['D'+str(x)].value)
+ desc = self.cleanCellValue(ws['E'+str(x)].value)
+ if 'ession' in '{}'.format(ext).lower():
+ ext = 'image'
+
+
+ if (strId) and (strId.startswith('Form')):
+
+ if not formName.strip() :
+ continue
+ else:
+
+ if not formName.strip() :
+ self.errors.append('No Form ref, cell C is empty')
+ continue
+ #replace spaces
+ strId = strId.replace(' ', '')
+ data['strId'] = strId
+ data['name'] = formName.replace("'","").replace('-', '')
+ data['ref'] = formRef.replace(' ', '').replace("'","").replace('-', '')
+ if not self.valid_name(data['ref']):
+ self.errors.append(
+ 'Form {} is not valid - {} - Check Form! '.format(
+ strId, data['ref'] ))
+
+ data['inputs'] = []
+ data['ext'] = ext.lower()
+ data['desc'] = desc
+ data['schema'] = schemaName
+
+ out['order'].append(strId)
+ out['forms'][strId] = data
+
+ # check for duplicates
+
+ if data['ref'] in formnames and len(data['ref']) > 0:
+ self.errors.append(
+ 'Duplicate! Form {} is a duplicate: Check Form! '.format(
+ strId ))
+ formnames.append(data['ref'])
+ if 'subform' in data['ext']:
+ #subformnames
+ subformnames.append(data['ref'])
+
+
+ if not out['foundFormDetails']:
+ self.errors.append('Page FormDetails page not found!!! Check CSV')
+
+ if len(out['schema']) < 1:
+ self.errors.append('Form {} Schema too short or missing: {} '.format(out['name'], out['schema']))
+
+
+ for x in out['forms']:
+ inputs = self.addInputs(x,wb,schemaName,out['forms'][x])
+
+ if(len(inputs)) == 0:
+ self.errors.append('Form {} has no inputs'.format(strId))
+ out['forms'][x]['inputs'] = self.sortByDataName(inputs)
+
+ #self.printForms(out['forms'])
+
+ for x in out['forms']:
+ self.checkForm(out['forms'][x],subformnames)
+
+ return out
+
+ def addInputs(self,strId,wb,schema,form):
+ textnum = 1000
+ out = []
+ complex_type=False
+
+
+ for ws in wb:
+
+ if ws.title.replace(' ','') == strId:
+
+ datatypes = [] # check for duplicates
+ for x in range(2,500):
+ data =dict()
+
+ question = self.cleanCellValue(ws['A'+str(x)].value)
+ dataName = self.cleanCellValue(ws['B'+str(x)].value).replace(' ','')
+ subName = self.cleanCellValue(ws['C'+str(x)].value).replace(' ','')
+ formType = self.cleanCellValue(ws['D'+str(x)].value).replace(' ','')
+ dataType = self.cleanCellValue(ws['E'+str(x)].value).replace(' ','')
+ inputLen = self.setLength(ws['F'+str(x)].value)
+ opts = self.cleanDropDownOptions(self.cleanCellValue(ws['G'+str(x)].value))
+ hide = self.cleanCellValue(ws['H'+str(x)].value).replace(' ','')
+ required = self.cleanCellValue(ws['I' + str(x)].value).replace(' ', '')
+
+ if not question :
+ break
+
+ if not dataName:
+ if formType.lower() not in self.textFormTypes:
+ self.errors.append('Form {}, Input {} : has no Data Name'.format(strId,question))
+ if not self.valid_name(dataName):
+ self.errors.append('Form {}, Input {} : data name {} not valid - no special characters'.format(strId,question, dataName))
+
+ if dataName == "date":
+ # date not permiitted as dataname, creates erros
+ dataName = 'date{}'.format(schema)
+
+ if formType in self.textFormTypes:
+ subName = str(textnum)
+ textnum = textnum + 1
+ if 'heckbox' in formType:
+ formType = 'tickbox'
+
+ # need to loop for multiradio... REMOVED - just do checkbox list....
+ if 'multiradio' in formType:
+ mr_opts = opts.split(',')
+ mr_num=0
+ for mr_opt in mr_opts:
+ subName = '{}{}{}'.format(dataName, subName, mr_opt)
+ if mr_num < 1:
+ subName = '{}xstart'.format(subName)
+ if mr_num == len(mr_opts):
+ subName = '{}xend'.format(subName)
+ mr_num += 1
+
+
+
+ data['parent'] = ''
+ data['children'] = []
+ data['schema'] = schema
+ data['formRef'] = form['ref']
+
+ data['question'] = question
+ data['dataName'] = dataName
+ data['subName'] = subName
+ data['inputFormType']= formType.lower()
+ data['inputDataType']= dataType.lower()
+ data['inputLen']= self.setLength(inputLen)
+ data['required'] = "0"
+ if 'y' in required.lower() or 'x' in required.lower():
+ data['required'] = "1"
+
+
+ # check for duplicates
+ dt = '{}{}'.format(dataName, subName)
+ if dt in datatypes and len(dataName) > 0:
+ self.errors.append('Duplicate! Form {}, Input {} Dataname: {} Subname: {}: Check Form! '.format(strId,question, dataName, subName))
+ datatypes.append(dt)
+
+
+ data['hide']= hide
+ data['options']= opts
+
+ if data['inputFormType'] == 'dropdown' and not data['inputDataType']:
+ #only assumes int if specifies int
+ data['inputDataType'] = 'string'
+
+ # SHCEMA INPUT TYPE - if header, paragraph etc, schema type = text and is ignored
+ #print("{}{}".format(data['inputFormType'], data['inputDataType']))
+ data['schemaInputType'] = self.schemaInputType(data['inputFormType'], data['inputDataType'],data['options'])
+ if 'datetime' in formType:
+ #? any need for this?
+ data['inputDataType'] = 'dateTime'
+ #print('LOADER DATA: {} '.format(data))
+
+ self.checkInput(form['name'],data)
+ out.append(data)
+ else:
+ data['parent'] = ''
+ data['children'] = []
+ data['schema'] = schema
+ data['formRef'] = form['ref']
+
+ data['question'] = question
+ data['dataName'] = dataName
+ data['subName'] = subName
+ data['inputFormType'] = formType.lower()
+ data['inputDataType'] = dataType.lower()
+ data['inputLen'] = self.setLength(inputLen)
+ data['required'] = "0"
+ if 'y' in required.lower() or 'x' in required.lower():
+ data['required'] = "1"
+
+ # check for duplicates
+ dt = '{}{}'.format(dataName, subName)
+ if dt in datatypes and len(dataName) > 0:
+ self.errors.append(
+ 'Duplicate! Form {}, Input {} Dataname: {} Subname: {}: Check Form! '.format(strId,
+ question,
+ dataName,
+ subName))
+ datatypes.append(dt)
+
+ data['hide'] = hide
+ data['options'] = opts
+
+ if data['inputFormType'] == 'dropdown' and not data['inputDataType']:
+ # only assumes int if specifies int
+ data['inputDataType'] = 'string'
+
+ # SHCEMA INPUT TYPE - if header, paragraph etc, schema type = text and is ignored
+ # print("{}{}".format(data['inputFormType'], data['inputDataType']))
+ data['schemaInputType'] = self.schemaInputType(data['inputFormType'], data['inputDataType'],data['options'] )
+ if 'datetime' in formType:
+ # ? any need for this?
+ data['inputDataType'] = 'dateTime'
+ #print('LOADER DATA: {} '.format(data))
+
+ #self.checkInput(form['name'], data)
+ out.append(data)
+ return out
+
+ def checkInput(self,form,i, qs, subformnames=''):
+
+ # check form type
+ if i['inputFormType'] not in self.allowedFormTypes :
+ self.errors.append('Form {} Question : {} ,Invalid Form Type {} '.format(form['name'], i['question'],i['inputFormType']))
+
+ # check data type
+ if (i['inputDataType'] != '') and (i['inputDataType'] not in self.allowedDataTypes) :
+ self.errors.append('Form {} Question : {} ,Invalid Data Type {} '.format(form['name'], i['question'],i['inputDataType']))
+
+ ## check to see if subforms exist, and options correct
+ if 'subform' == i['inputFormType'] and i['options'] not in subformnames:
+ self.errors.append('Form {} has subform with no exisiting type: {} - {} - {} '.format(form['name'], i['question'],i['options'], i['inputFormType']))
+
+ # yn do not NEED subnames as already exist. (completed, reasonnotable)
+ # ynuo has no subname
+ if 'yn' == i['inputFormType'] and len(i['subName']) < 1:
+ self.errors.append(
+ 'Form {} has missing subname: {} - {} - {}'.format(form['name'], i['question'], i['dataName'],
+ i['inputFormType']))
+ if 'ny' == i['inputFormType'] and len(i['subName']) < 1:
+ self.errors.append(
+ 'Form {} has missing subname: {} - {} - {}'.format(form['name'], i['question'], i['dataName'],
+ i['inputFormType']))
+ if 'multipanel' == i['inputFormType']:
+ opts = i['options'].split(',')
+ if len(i['subName']) < 1:
+ self.errors.append(
+ 'Form {} has missing subname: {} - {} - {}'.format(form['name'], i['question'], i['dataName'],
+ i['inputFormType']))
+ if len(opts) != 2:
+ self.errors.append(
+ 'Form {} - multipanel question has wrong options format, see Wiki: {} - {} - {}'.format(
+ form['name'], i['question'], i['dataName'], i['options']))
+ elif 'Y' not in opts[0] or 'N' not in opts[1]:
+ self.errors.append(
+ 'Form {} - multipanel question has wrong options format, see Wiki: {} - {} - {}'.format(
+ form['name'], i['question'], i['dataName'], i['options']))
+
+ temp = i['question'].replace(" ", '') + i['dataName'] + i['subName']
+ if temp in qs and i['inputFormType'] not in self.textFormTypes:
+ self.errors.append('Form {} has duplicate input {} - {}'.format(form['name'], i['question'], i['dataName']))
+ else:
+ qs.append(temp)
+ if len(i['children']) < 1 and i['inputFormType'] in self.toggle_panels:
+ self.errors.append(
+ 'Form {}: Question: {} - Panel Toggle Type {} has no subtypes! '.format(form['name'], i['question'],
+ i['dataName']))
+ # check form type
+ if 'date' == i['inputFormType'] and i['inputLen'] != 0:
+ self.errors.append('Form {} Question : {} , Length restriction applied to date type - not valid!'.format(form['name'], i['question'],i['inputFormType']))
+
+
+ def schemaInputType(self,formType,dataType, options):
+ #options should contain the subform name
+
+ iType='none'
+ if formType in self.textFormTypes:
+ iType = 'text'
+ else:
+ iType = 'string' if not dataType else dataType
+
+ #print('itype {} form {} data {} formtype: {}'.format(iType, formType, dataType,self.textFormTypes))
+
+
+ if formType in self.toggle_panels:
+ iType = 'integer'
+ elif formType == 'date':
+ iType = 'date'
+ elif formType == 'datetime':
+ #iType = 'dateTime'
+ # better as string??
+ iType = 'string'
+
+
+ elif formType == 'textbox' and 'int' not in dataType:
+ if 'loat' not in dataType:
+ #can be float as well. So change after
+ iType = 'string'
+
+ if 'ool' in dataType:
+ iType='boolean'
+
+ elif 'int' in dataType:
+ iType='integer'
+ elif 'loat' in dataType:
+ iType='float'
+
+
+ if formType == 'dropdown' and not dataType:
+ #only assumes int if specifies int
+ iType = 'string'
+
+ if 'tickbox' in formType:
+ iType='boolean'
+
+ if formType == 'subform':
+ ## need to check if existing form....
+ iType=options
+
+ return iType
+
+ def setLength(self,data):
+ if not data:
+ return 0
+ else:
+ return int(data)
+
+ def cleanCellValue(self,data):
+
+ if (not data or data == None):
+
+ return ''
+ data = data.strip().encode('ascii', 'ignore')
+ data_str=data.decode()
+
+ return data_str
+
+ # return '' if not data else data.strip()
+
+ def valid_name(selfself, dataName):
+ if set('[~!@#$%^&*()_+{}":;\']+$').intersection(dataName):
+ return False
+ else:
+ return True
+
+
+ def cleanDropDownOptions(self,o):
+
+ a = o.split('-')
+
+ if len(a) == 2 and ',' not in o and isinstance(a[0], int) and isinstance(a[1], int):
+ r = a[0]
+ for i in range(int(a[0]) + 1, int(a[1]) + 1):
+ r = r + "," + str(i)
+
+ print(r)
+ return r
+
+ bstr= '{}'.format(o)
+ bstr = bstr.translate ({ord(c): "" for c in "!@#$%^&*()[]{};:./?\|`~=_"})
+
+ #bstr = bstr.replace(" ","")
+
+ return bstr
+
+ def sortByDataName(self,inputs):
+
+ temp = {'order': [], 'inputs' : {}}
+ out = []
+ #urgh, fix to stop recounting repeated paragraphs/headers
+ textnum = 555
+ for i in inputs:
+
+ dataName = i['dataName']
+ #### need to make so can be in panels
+ if i['inputFormType'] in self.textFormTypes and len(i['dataName'])<1:
+ dataName = str(textnum)
+ textnum = textnum + 1
+
+ if dataName in temp['inputs'].keys():
+ i['parent'] = dataName
+ temp['inputs'][dataName]['children'].append(i)
+ else:
+ temp['inputs'][dataName] = i
+ temp['order'].append(dataName)
+ # out[i['dataName']] = [i]
+
+ for o in temp['order']:
+ out.append(temp['inputs'][o])
+ #print('------------###########-----------')
+ #print('{}'.format(out))
+ #print temp['order']
+ return out
+
+ #TODO needs update
+ def checkForm(self,form, subformnames):
+
+
+ #print('CHECK FORMS: formanems:', subformnames)
+ if form['ext'] not in self.allowedExtensions :
+ self.errors.append('Form {} Invalid Extension {} '.format(form['name'], form['ext']))
+ # already checked if no inputs
+ # reset list for questions
+ qs=[]
+
+ for i in form['inputs']:
+ self.checkInput( form, i,qs, subformnames)
+ if len(i['children']) > 0:
+ for c in i['children']:
+ self.checkInput(form, c,qs, subformnames)
+
+ #TODO check for group inputs with no subname
+
+
+ def printForms(self,forms):
+
+ # already checked if no inputs
+ for f in forms:
+ print('Form {}'.format(forms[f]['name']))
+ print('schema {}'.format(forms[f]['schema']))
+
+ for i in forms[f]['inputs']:
+ print(' -- input : question {} : Type {}'.format(i['question'], i['inputFormType']))
+ if len(i['children']) > 0:
+ for c in i['children']:
+ print(' -- input : question {} : Type {}'.format(c['question'],c['inputFormType']))
+
+
diff --git a/builder/schema.py b/builder/schema.py
new file mode 100644
index 0000000..1219c55
--- /dev/null
+++ b/builder/schema.py
@@ -0,0 +1,335 @@
+# if schmea type = text, then ignores (this includes header, subheader etc.
+import errno
+import os
+
+class SchemaHandler(object):
+
+ def __init__(self, configData):
+
+ self.errors = []
+ self.log =[]
+ self.configData = configData
+ self.schemaName = configData['schemaName']
+ self.version = configData['version']
+
+ self.part_plugin_path = 'src/main/resources/schemas'
+
+ def hasError(self):
+ return len(self.errors)
+
+ def errors(self):
+ return self.errors
+
+
+ def checkDir(self,vmFile):
+
+ if not os.path.exists(os.path.dirname(vmFile)):
+ try:
+ os.makedirs(os.path.dirname(vmFile))
+ except OSError as exc: # Guard against race condition
+ if exc.errno != errno.EEXIST:
+ raise
+
+ def write_schema_xsd(self,plugin_name,data):
+
+
+ dir_name = '{}/plugins/{}/{}/{}'.format(self.configData['path_plugin_builder'],self.schemaName,self.part_plugin_path,self.schemaName)
+ schema_file = '{}/{}.xsd'.format(dir_name,self.schemaName)
+
+ self.log.append('write schema dir : {}'.format(dir_name))
+ self.log.append('write schema file : {}'.format(schema_file))
+
+ if not os.path.exists(dir_name):
+ os.makedirs(dir_name)
+
+ #lets load our [replace me] template
+ fxsd = open(schema_file,"w")
+ for line in data:
+ fxsd.write(line + '\n')
+ fxsd.close()
+
+ def all_data_xsd(self,data):
+ #print(data)
+ out = self.schemaHeader()
+
+ #add all form xml elments -DO SUBFORMS FIRST
+ for f in data['forms']:
+ if 'subform' in data['forms'][f]['ext']:
+ print('SUBFORM', data['forms'][f]['ext'])
+ out.extend(self.formXsd(data['forms'][f]))
+
+
+ for f in data['forms']:
+ if 'subform' not in data['forms'][f]['ext']:
+ print('NOT SUBFORM', data['forms'][f]['ext'])
+ out.extend(self.formName(data['forms'][f]))
+ #os.exit()
+
+ out.append(' ')
+ out.append(' ')
+ out.append(' ')
+
+ for f in data['forms']:
+ if 'subform' not in data['forms'][f]['ext']:
+ out.extend(self.formXsd(data['forms'][f]))
+
+ out.extend(self.end_schema())
+
+ return out
+
+ def formXsd(self,form):
+
+ out =[]
+
+ out.extend(self.start_complex_type_named(form['ref']))
+
+ #not used
+ out.extend(self.make_form_desc(form['name']))
+ if 'subform' not in form['ext']:
+ out.extend(self.start_complex_content())
+ #not for subforms as do not extend
+ s = 'imageAssessorData'
+ if 'ubj' in form['ext']:
+ s = 'subjectAssessorData'
+ out.extend(self.start_extension(s))
+
+ out.extend(self.start_sequence())
+
+ out.extend(self.make_form_inputs(form))
+
+ out.extend(self.end_sequence())
+ if 'subform' not in form['ext']:
+ out.extend(self.end_extension())
+ out.extend(self.end_complex_content())
+
+ out.extend(self.end_complex_type())
+
+ out.append(' ')
+ out.append(' ')
+ out.append(' ')
+ return out
+
+
+ def schemaHeader(self):
+
+ host = self.configData['host']
+
+ if not host.endswith('/'):
+ host = '{}/'.format(host)
+
+ out = []
+
+ out.append('')
+ out.append('')
+ out.append(' ')
+ out.append(' ')
+ out.append(' ')
+ #out.extend(self.addAssessCompleted())
+
+ return out
+
+
+ def addAssessCompleted(self):
+
+ out =[]
+
+ out.append(' ')
+ out.append(' ')
+ out.append(' ')
+ out.append(' ')
+ out.append(' ')
+ out.append(' ')
+ out.append(' ')
+ out.append(' ')
+ out.append(' ')
+ out.append(' ')
+ out.append(' ')
+ out.append(' ')
+ out.append(' ')
+ out.append(' ')
+ out.append(' ')
+ out.append(' ')
+ out.append(' ')
+ return out
+
+
+ def formName(self,form):
+
+ out = []
+ if 'subform' not in form['ext']:
+ out.append(' '.format( form['ref'], self.schemaName,form['ref']) )
+ return out
+
+ def make_form_desc(self,formDesc):
+
+ out = []
+ #out.append(' ')
+ #out.append(' {}'.format(formDesc) )
+ #out.append(' ')
+ return out
+
+
+ def make_form_inputs(self,form):
+
+ out = []
+ doneDataNames = []
+
+ for i in form['inputs']:
+
+
+ dataName = i['dataName']
+ self.log.append(' DATANAME: {} - {}'.format(dataName, i['inputFormType']))
+ if 'text' in i['schemaInputType']:
+ self.log.append('Skipping as header or paragraph - {}'.format(i['question']))
+ elif len(i['children']) > 0:
+ # self.log.append(' create group {}, form type : {} , datatype : {}'.format(i['dataName'], i['inputFormType'],i['schemaInputType']))
+
+ self.log.append(' Group input : {}'.format(i['dataName']))
+ self.log.append(' -- Group input : {}'.format(i['question']))
+ out.extend(self.make_complex_inputs(dataName,i))
+
+ else:
+ self.log.append(' non - group input : {}'.format(i['question']))
+ #### if restriction""""
+
+ if i['inputLen'] > 0:
+ out.extend(self.input_restrict(dataName,i))
+ else:
+ out.extend(self.input_default(dataName,i))
+
+ return out
+
+
+ def make_complex_inputs(self,dataName,input):
+ # self.traverse(input)
+ out = []
+ out.append(''.format(input['dataName']))
+ out.extend(self.start_complex_type())
+ out.extend(self.start_sequence())
+
+ out.extend(self.input_default(input['subName'], input))
+
+ for i in input['children']:
+ self.log.append(' -- Group input : {}'.format(i['question']))
+
+ if 'text' not in i['schemaInputType']:
+ if i['inputLen'] > 0:
+ out.extend(self.input_restrict(i['subName'],i))
+ else:
+ out.extend(self.input_default(i['subName'], i))
+
+ out.extend(self.end_sequence())
+ out.extend(self.end_complex_type())
+
+ out.append('')
+
+ return out
+
+
+ def input_restrict(self,elName,data):
+
+ out = []
+
+ out.append(' '.format(elName, data['required'] ))
+ out.extend(self.input_question(data['question']) )
+ out.append(' ')
+ out.append(' '.format( data['schemaInputType']) )
+ if 'tring' in data['schemaInputType']:
+ out.append(' '.format( data['inputLen']) )
+ else:
+ out.append(' ')
+ out.append(' '.format( data['inputLen']) )
+ out.append(' ')
+ out.append(' ')
+ out.append(' ')
+
+ return out
+
+ def input_default(self,elName,data):
+
+ if data['inputFormType'] == 'ynuo' :
+ return self.input_ynuo(elName)
+
+ out = []
+ if 'text' not in data['schemaInputType']:
+ if 'subform' in data['inputFormType']:
+ out.append(' '.format(elName, self.schemaName, data['schemaInputType'], data['required']))
+ else:
+ out.append(' '.format(elName,data['schemaInputType'], data['required'] ))
+ out.extend(self.input_question(data['question']) )
+ out.append(' ')
+ return out
+
+ def input_ynuo(self,elName):
+ out = []
+ out.append(' ')
+ out.append(' ')
+ out.append(' ')
+ out.append(' ')
+ out.append(' ')
+ out.append(' ')
+ out.append(' ')
+ out.append(' ')
+ out.append(' ')
+ out.append(' ')
+ return out
+ #return [' \n'.format(elName,self.schemaName)]
+
+ def input_question(self,q):
+
+ out = []
+
+ #out.append(' ')
+ #out.append(' {}'.format(q) )
+ #out.append(' ')
+ return out
+
+
+ def end_schema(self,):
+
+ return ['']
+
+ def start_complex_type(self):
+
+ return ['']
+
+ def start_complex_type_named(self,name):
+
+ return [''.format( name)]
+
+ def end_complex_type(self):
+
+
+ return ['']
+
+ def start_complex_content(self):
+
+ return ['']
+
+ def end_complex_content(self):
+
+ return ['']
+
+ def start_extension(self,e):
+
+ return [''.format(e)]
+
+ def end_extension(self):
+
+ return ['']
+
+ def start_sequence(self):
+
+ return ['']
+
+ def end_sequence(self):
+
+ return ['']
\ No newline at end of file
diff --git a/builder_templates/174/ProjectSelector.vm b/builder_templates/174/ProjectSelector.vm
new file mode 100644
index 0000000..04f4964
--- /dev/null
+++ b/builder_templates/174/ProjectSelector.vm
@@ -0,0 +1,96 @@
+##REQUIRES $item=org.nrg.xft.XFTItem $user=org.nrg.xdat.security.XDATUser
+
+#set($user=$data.getSession().getAttribute("user"))
+#set($create_projects= $user.getAllowedValues("$item.getXSIType()","$item.getXSIType()/project","create"))
+ #set($projectMap = $user.getCachedItemValuesHash("xnat:projectData","read",false,"xnat:projectData/ID","xnat:projectData/secondary_ID"))
+#if($project)
+ #if($item.getProperty("project"))
+
+ #else
+ $item.setProperty("$item.getXSIType()/project",$project)
+ #end
+#else
+ #set($project=$item.getProperty("project"))
+#end
+
+
+
+
\ No newline at end of file
diff --git a/builder_templates/174/SubjectFinder.vm b/builder_templates/174/SubjectFinder.vm
new file mode 100644
index 0000000..a7f18af
--- /dev/null
+++ b/builder_templates/174/SubjectFinder.vm
@@ -0,0 +1,72 @@
+
+
+
+
+
+
+#if($part)
+
+#else
+ #set($part=$om.getSubjectData())
+#end
+
+
+
+
+
diff --git a/builder_templates/174/action_box_template.vm b/builder_templates/174/action_box_template.vm
new file mode 100644
index 0000000..8385572
--- /dev/null
+++ b/builder_templates/174/action_box_template.vm
@@ -0,0 +1,15 @@
+