def _add_columns_for_case_details(_module): _module.case_details.short.columns = [ DetailColumn(header={'en': 'a'}, model='case', field='a', format='plain', case_tile_field='header'), DetailColumn(header={'en': 'b'}, model='case', field='b', format='plain', case_tile_field='top_left'), DetailColumn(header={'en': 'c'}, model='case', field='c', format='enum', enum=[ MappingItem(key='male', value={'en': 'Male'}), MappingItem(key='female', value={'en': 'Female'}), ], case_tile_field='sex'), DetailColumn(header={'en': 'd'}, model='case', field='d', format='plain', case_tile_field='bottom_left'), DetailColumn(header={'en': 'e'}, model='case', field='e', format='date', case_tile_field='date'), ]
def test_case_tile_pull_down(self): app = Application.new_app('domain', 'Untitled Application') module = app.add_module(Module.new_module('Untitled Module', None)) module.case_type = 'patient' module.case_details.short.use_case_tiles = True module.case_details.short.persist_tile_on_forms = True module.case_details.short.pull_down_tile = True module.case_details.short.columns = [ DetailColumn( header={'en': 'a'}, model='case', field='a', format='plain', case_tile_field='header' ), DetailColumn( header={'en': 'b'}, model='case', field='b', format='plain', case_tile_field='top_left' ), DetailColumn( header={'en': 'c'}, model='case', field='c', format='enum', enum=[ MappingItem(key='male', value={'en': 'Male'}), MappingItem(key='female', value={'en': 'Female'}), ], case_tile_field='sex' ), DetailColumn( header={'en': 'd'}, model='case', field='d', format='plain', case_tile_field='bottom_left' ), DetailColumn( header={'en': 'e'}, model='case', field='e', format='date', case_tile_field='date' ), ] form = app.new_form(0, "Untitled Form", None) form.xmlns = 'http://id_m0-f0' form.requires = 'case' self.assertXmlPartialEqual( self.get_xml('case_tile_pulldown_session'), app.create_suite(), "./entry/session" )
def test_case_detail_icon_mapping(self): app = Application.new_app('domain', 'Untitled Application', application_version=APP_V2) module = app.add_module(Module.new_module('Untitled Module', None)) module.case_type = 'patient' module.case_details.short.columns = [ DetailColumn( header={'en': 'Age range'}, model='case', field='age', format='enum-image', enum=[ MappingItem(key='10', value={'en': 'jr://icons/10-year-old.png'}), MappingItem(key='age > 50', value={'en': 'jr://icons/old-icon.png'}), ], ), ] key1_varname = '10' key2_varname = hashlib.md5('age > 50').hexdigest()[:8] icon_mapping_spec = """ <partial> <template form="image" width="13%"> <text> <xpath function="if(age = '10', $k{key1_varname}, if(age > 50, $h{key2_varname}, ''))"> <variable name="h{key2_varname}"> <locale id="m0.case_short.case_age_1.enum.h{key2_varname}"/> </variable> <variable name="k{key1_varname}"> <locale id="m0.case_short.case_age_1.enum.k{key1_varname}"/> </variable> </xpath> </text> </template> </partial> """.format( key1_varname=key1_varname, key2_varname=key2_varname, ) # check correct suite is generated self.assertXmlPartialEqual(icon_mapping_spec, app.create_suite(), './detail/field/template[@form="image"]') # check icons map correctly app_strings = commcare_translations.loads(app.create_app_strings('en')) self.assertEqual( app_strings['m0.case_short.case_age_1.enum.h{key2_varname}'.format( key2_varname=key2_varname, )], 'jr://icons/old-icon.png') self.assertEqual( app_strings['m0.case_short.case_age_1.enum.k{key1_varname}'.format( key1_varname=key1_varname, )], 'jr://icons/10-year-old.png')
def test_case_detail_calculated_conditional_enum(self, *args): app = Application.new_app('domain', 'Untitled Application') module = app.add_module(Module.new_module('Unititled Module', None)) module.case_type = 'patient' module.case_details.short.columns = [ DetailColumn( header={'en': 'Gender'}, model='case', field="if(gender = 'male', 'boy', 'girl')", format='enum', enum=[ MappingItem(key="boy", value={'en': 'Boy'}), MappingItem(key="girl", value={'en': 'Girl'}), ], ), ] icon_mapping_spec = """ <partial> <template> <text> <xpath function="replace(join(' ', if(selected(if(gender = 'male', 'boy', 'girl'), 'boy'), $kboy, ''), if(selected(if(gender = 'male', 'boy', 'girl'), 'girl'), $kgirl, '')), '\\s+', ' ')"> <variable name="kboy"> <locale id="m0.case_short.case_if(gender 'male', 'boy', 'girl')_1.enum.kboy"/> </variable> <variable name="kgirl"> <locale id="m0.case_short.case_if(gender 'male', 'boy', 'girl')_1.enum.kgirl"/> </variable> </xpath> </text> </template> </partial> """ # noqa: #501 # check correct suite is generated self.assertXmlPartialEqual( icon_mapping_spec, app.create_suite(), './detail[@id="m0_case_short"]/field/template') # check app strings mapped correctly app_strings = commcare_translations.loads(app.create_app_strings('en')) self.assertEqual( app_strings[ "m0.case_short.case_if(gender 'male', 'boy', 'girl')_1.enum.kboy"], 'Boy') self.assertEqual( app_strings[ "m0.case_short.case_if(gender 'male', 'boy', 'girl')_1.enum.kgirl"], 'Girl')
def test_case_detail_conditional_enum(self, *args): app = Application.new_app('domain', 'Untitled Application') module = app.add_module(Module.new_module('Unititled Module', None)) module.case_type = 'patient' module.case_details.short.columns = [ DetailColumn( header={'en': 'Gender'}, model='case', field='gender', format='conditional-enum', enum=[ MappingItem(key="gender = 'male' and age <= 21", value={'en': 'Boy'}), MappingItem(key="gender = 'female' and age <= 21", value={'en': 'Girl'}), MappingItem(key="gender = 'male' and age > 21", value={'en': 'Man'}), MappingItem(key="gender = 'female' and age > 21", value={'en': 'Woman'}), ], ), ] key1_varname = hashlib.md5( "gender = 'male' and age <= 21".encode('utf-8')).hexdigest()[:8] key2_varname = hashlib.md5( "gender = 'female' and age <= 21".encode('utf-8')).hexdigest()[:8] key3_varname = hashlib.md5( "gender = 'male' and age > 21".encode('utf-8')).hexdigest()[:8] key4_varname = hashlib.md5( "gender = 'female' and age > 21".encode('utf-8')).hexdigest()[:8] icon_mapping_spec = """ <partial> <template> <text> <xpath function="if(gender = 'male' and age <= 21, $h{key1_varname}, if(gender = 'female' and age <= 21, $h{key2_varname}, if(gender = 'male' and age > 21, $h{key3_varname}, if(gender = 'female' and age > 21, $h{key4_varname}, ''))))"> <variable name="h{key4_varname}"> <locale id="m0.case_short.case_gender_1.enum.h{key4_varname}"/> </variable> <variable name="h{key2_varname}"> <locale id="m0.case_short.case_gender_1.enum.h{key2_varname}"/> </variable> <variable name="h{key3_varname}"> <locale id="m0.case_short.case_gender_1.enum.h{key3_varname}"/> </variable> <variable name="h{key1_varname}"> <locale id="m0.case_short.case_gender_1.enum.h{key1_varname}"/> </variable> </xpath> </text> </template> </partial> """.format( # noqa: #501 key1_varname=key1_varname, key2_varname=key2_varname, key3_varname=key3_varname, key4_varname=key4_varname, ) # check correct suite is generated self.assertXmlPartialEqual( icon_mapping_spec, app.create_suite(), './detail[@id="m0_case_short"]/field/template') # check app strings mapped correctly app_strings = commcare_translations.loads(app.create_app_strings('en')) self.assertEqual( app_strings[ 'm0.case_short.case_gender_1.enum.h{key1_varname}'.format( key1_varname=key1_varname, )], 'Boy') self.assertEqual( app_strings[ 'm0.case_short.case_gender_1.enum.h{key2_varname}'.format( key2_varname=key2_varname, )], 'Girl') self.assertEqual( app_strings[ 'm0.case_short.case_gender_1.enum.h{key3_varname}'.format( key3_varname=key3_varname, )], 'Man') self.assertEqual( app_strings[ 'm0.case_short.case_gender_1.enum.h{key4_varname}'.format( key4_varname=key4_varname, )], 'Woman')
def _edit_form_attr(request, domain, app_id, form_unique_id, attr): """ Called to edit any (supported) form attribute, given by attr """ ajax = json.loads(request.POST.get('ajax', 'true')) resp = {} app = get_app(domain, app_id) try: form = app.get_form(form_unique_id) except FormNotFoundException as e: if ajax: return HttpResponseBadRequest(str(e)) else: messages.error(request, _("There was an error saving, please try again!")) return back_to_main(request, domain, app_id=app_id) lang = request.COOKIES.get('lang', app.langs[0]) def should_edit(attribute): return attribute in request.POST if 'sha1' in request.POST and (should_edit("xform") or "xform" in request.FILES): conflict = _get_xform_conflict_response(form, request.POST['sha1']) if conflict is not None: return conflict if should_edit("name"): name = request.POST['name'] form.name[lang] = name if not form.form_type == "shadow_form": xform = form.wrapped_xform() if xform.exists(): xform.set_name(name) save_xform(app, form, xform.render()) resp['update'] = {'.variable-form_name': trans(form.name, [lang], use_delim=False)} if should_edit('comment'): form.comment = request.POST['comment'] if should_edit("name_enum"): name_enum = json.loads(request.POST.get("name_enum")) form.name_enum = [MappingItem(i) for i in name_enum] if should_edit("xform") or "xform" in request.FILES: try: # support FILES for upload and POST for ajax post from Vellum try: xform = request.FILES.get('xform').read() except Exception: xform = request.POST.get('xform') else: try: xform = str(xform, encoding="utf-8") except Exception: raise Exception("Error uploading form: Please make sure your form is encoded in UTF-8") if request.POST.get('cleanup', False): try: # First, we strip all newlines and reformat the DOM. px = parseString(xform.replace('\r\n', '')).toprettyxml() # Then we remove excess newlines from the DOM output. text_re = re.compile(r'>\n\s+([^<>\s].*?)\n\s+</', re.DOTALL) prettyXml = text_re.sub(r'>\g<1></', px) xform = prettyXml except Exception: pass if xform: if isinstance(xform, str): xform = xform.encode('utf-8') save_xform(app, form, xform) else: raise Exception("You didn't select a form to upload") except Exception as e: notify_exception(request, str(e)) if ajax: return HttpResponseBadRequest(str(e)) else: messages.error(request, str(e)) if should_edit("references") or should_edit("case_references"): form.case_references = _get_case_references(request.POST) if should_edit("show_count"): show_count = request.POST['show_count'] form.show_count = True if show_count == "True" else False if should_edit("put_in_root"): put_in_root = request.POST['put_in_root'] form.put_in_root = True if put_in_root == "True" else False if should_edit('form_filter'): form.form_filter = request.POST['form_filter'] if should_edit('post_form_workflow'): form.post_form_workflow = request.POST['post_form_workflow'] if should_edit('auto_gps_capture'): form.auto_gps_capture = request.POST['auto_gps_capture'] == 'true' if should_edit('is_release_notes_form'): form.is_release_notes_form = request.POST['is_release_notes_form'] == 'true' if should_edit('enable_release_notes'): form.enable_release_notes = request.POST['enable_release_notes'] == 'true' if not form.is_release_notes_form and form.enable_release_notes: return json_response( {'message': _("You can't enable a form as release notes without allowing it as " "a release notes form <TODO messaging>")}, status_code=400 ) if should_edit('no_vellum'): form.no_vellum = request.POST['no_vellum'] == 'true' if (should_edit("form_links_xpath_expressions") and should_edit("form_links_form_ids") and toggles.FORM_LINK_WORKFLOW.enabled(domain)): form_links = zip( request.POST.getlist('form_links_xpath_expressions'), request.POST.getlist('form_links_form_ids'), [ json.loads(datum_json) if datum_json else [] for datum_json in request.POST.getlist('datums_json') ], ) form.form_links = [FormLink( xpath=link[0], form_id=link[1], datums=[ FormDatum(name=datum['name'], xpath=datum['xpath']) for datum in link[2] ] ) for link in form_links] if should_edit('post_form_workflow_fallback'): form.post_form_workflow_fallback = request.POST.get('post_form_workflow_fallback') if should_edit('custom_instances'): instances = json.loads(request.POST.get('custom_instances')) try: # validate that custom instances can be added into the XML for instance in instances: etree.fromstring( "<instance id='{}' src='{}' />".format( instance.get('instanceId'), instance.get('instancePath') ) ) except etree.XMLSyntaxError as error: return json_response( {'message': _("There was an issue with your custom instances: {}").format(error)}, status_code=400 ) form.custom_instances = [ CustomInstance( instance_id=instance.get("instanceId"), instance_path=instance.get("instancePath"), ) for instance in instances ] if should_edit('custom_assertions'): assertions = json.loads(request.POST.get('custom_assertions')) try: # validate that custom assertions can be added into the XML for assertion in assertions: etree.fromstring( '<assertion test="{test}"><text><locale id="abc.def"/>{text}</text></assertion>'.format( **assertion ) ) except etree.XMLSyntaxError as error: return json_response( {'message': _("There was an issue with your custom assertions: {}").format(error)}, status_code=400 ) existing_assertions = {assertion.test: assertion for assertion in form.custom_assertions} new_assertions = [] for assertion in assertions: try: new_assertion = existing_assertions[assertion.get('test')] new_assertion.text[lang] = assertion.get('text') except KeyError: new_assertion = CustomAssertion( test=assertion.get('test'), text={lang: assertion.get('text')} ) new_assertions.append(new_assertion) form.custom_assertions = new_assertions if should_edit("shadow_parent"): form.shadow_parent_form_id = request.POST['shadow_parent'] if should_edit("custom_icon_form"): error_message = handle_custom_icon_edits(request, form, lang) if error_message: return json_response( {'message': error_message}, status_code=400 ) handle_media_edits(request, form, should_edit, resp, lang) app.save(resp) notify_form_changed(domain, request.couch_user, app_id, form_unique_id) if ajax: return HttpResponse(json.dumps(resp)) else: return back_to_main(request, domain, app_id=app_id, form_unique_id=form_unique_id)
class SuiteNameEnumsTest(SimpleTestCase, TestXmlMixin, SuiteMixin): file_path = ('data', 'suite') case_type = 'patient' enum = [ MappingItem(key='int(double(now())) mod 1 = 0', value={'en': 'evens'}), MappingItem(key='int(double(now())) mod 1 = 1', value={'en': 'odds'}), ] def setUp(self): self.factory = AppFactory(build_version='2.40.0', domain='domain') self.basic_module, self.basic_form = self.factory.new_basic_module( 'basic', self.case_type) self.basic_module.name_enum = self.enum self.basic_form.name_enum = self.enum def test_module(self): self.assertXmlPartialEqual( """ <partial> <menu id="m0"> <text> <xpath function="if(int(double(now())) mod 1 = 0, $h2cb17fc7, if(int(double(now())) mod 1 = 1, $h137bc41f, ''))"> <variable name="h2cb17fc7"> <locale id="m0.enum.h2cb17fc7"/> </variable> <variable name="h137bc41f"> <locale id="m0.enum.h137bc41f"/> </variable> </xpath> </text> <command id="m0-f0"/> </menu> </partial> """, self.factory.app.create_suite(), 'menu[@id="m0"]', ) def test_module_with_media(self): self.basic_module.media_audio = { 'en': 'jr://file/commcare/audio/en/module0.mp3' } self.basic_module.media_image = { 'en': 'jr://file/commcare/image/module0_en.png' } self.assertXmlPartialEqual( """ <partial> <menu id="m0"> <display> <text> <xpath function="if(int(double(now())) mod 1 = 0, $h2cb17fc7, if(int(double(now())) mod 1 = 1, $h137bc41f, ''))"> <variable name="h2cb17fc7"> <locale id="m0.enum.h2cb17fc7"/> </variable> <variable name="h137bc41f"> <locale id="m0.enum.h137bc41f"/> </variable> </xpath> </text> <text form="image"> <locale id="modules.m0.icon"/> </text> <text form="audio"> <locale id="modules.m0.audio"/> </text> </display> <command id="m0-f0"/> </menu> </partial> """, self.factory.app.create_suite(), 'menu[@id="m0"]', ) def test_report_module(self): self.report_module = self.factory.new_report_module('basic') self.report_module.name_enum = self.enum self.assertXmlPartialEqual( """ <partial> <menu id="m1"> <text> <xpath function="if(int(double(now())) mod 1 = 0, $h2cb17fc7, if(int(double(now())) mod 1 = 1, $h137bc41f, ''))"> <variable name="h2cb17fc7"> <locale id="m1.enum.h2cb17fc7"/> </variable> <variable name="h137bc41f"> <locale id="m1.enum.h137bc41f"/> </variable> </xpath> </text> </menu> </partial> """, self.factory.app.create_suite(), 'menu[@id="m1"]', ) def test_form(self): self.assertXmlPartialEqual( """ <partial> <entry> <command id="m0-f0"> <text> <xpath function="if(int(double(now())) mod 1 = 0, $h2cb17fc7, if(int(double(now())) mod 1 = 1, $h137bc41f, ''))"> <variable name="h2cb17fc7"> <locale id="m0f0.enum.h2cb17fc7"/> </variable> <variable name="h137bc41f"> <locale id="m0f0.enum.h137bc41f"/> </variable> </xpath> </text> </command> </entry> </partial> """, self.factory.app.create_suite(), 'entry[1]', ) def test_form_with_media(self): self.basic_form.media_audio = { 'en': 'jr://file/commcare/audio/en/module0.mp3' } self.basic_form.media_image = { 'en': 'jr://file/commcare/image/module0_en.png' } self.assertXmlPartialEqual( """ <partial> <entry> <command id="m0-f0"> <display> <text> <xpath function="if(int(double(now())) mod 1 = 0, $h2cb17fc7, if(int(double(now())) mod 1 = 1, $h137bc41f, ''))"> <variable name="h2cb17fc7"> <locale id="m0f0.enum.h2cb17fc7"/> </variable> <variable name="h137bc41f"> <locale id="m0f0.enum.h137bc41f"/> </variable> </xpath> </text> <text form="image"> <locale id="forms.m0f0.icon"/> </text> <text form="audio"> <locale id="forms.m0f0.audio"/> </text> </display> </command> </entry> </partial> """, self.factory.app.create_suite(), 'entry[1]', )