def test_manual_form_link(self): factory = AppFactory(build_version='2.9.0/latest') m0, m0f0 = factory.new_basic_module('enroll child', 'child') factory.form_opens_case(m0f0) m1, m1f0 = factory.new_basic_module('child visit', 'child') factory.form_requires_case(m1f0) factory.form_opens_case(m1f0, case_type='visit', is_subcase=True) m2, m2f0 = factory.new_advanced_module('visit history', 'visit', parent_module=m1) factory.form_requires_case(m2f0, 'child') factory.form_requires_case(m2f0, 'visit', parent_case_type='child') m0f0.post_form_workflow = WORKFLOW_FORM m0f0.form_links = [ FormLink(xpath="true()", form_id=m1f0.unique_id, datums=[ FormDatum(name='case_id', xpath="instance('commcaresession')/session/data/case_id_new_child_0") ]), ] m1f0.post_form_workflow = WORKFLOW_FORM m1f0.form_links = [ FormLink(xpath="true()", form_id=m2f0.unique_id, datums=[ FormDatum(name='case_id', xpath="instance('commcaresession')/session/data/case_id"), FormDatum(name='case_id_load_visit_0', xpath="instance('commcaresession')/session/data/case_id_new_visit_0"), ]), ] self.assertXmlPartialEqual(self.get_xml('form_link_tdh'), factory.app.create_suite(), "./entry")
def test_manual_form_link_with_fallback(self): factory = AppFactory(build_version='2.9.0/latest') m0, m0f0 = factory.new_basic_module('enroll child', 'child') factory.form_opens_case(m0f0) m1, m1f0 = factory.new_basic_module('child visit', 'child') factory.form_requires_case(m1f0) factory.form_opens_case(m1f0, case_type='visit', is_subcase=True) m2, m2f0 = factory.new_advanced_module('visit history', 'visit', parent_module=m1) factory.form_requires_case(m2f0, 'child') factory.form_requires_case(m2f0, 'visit', parent_case_type='child') m0f0.post_form_workflow = WORKFLOW_FORM m0f0.form_links = [ FormLink(xpath="true()", form_id=m1f0.unique_id, datums=[ FormDatum(name='case_id', xpath="instance('commcaresession')/session/data/case_id_new_child_0") ]), ] m1f0.post_form_workflow = WORKFLOW_FORM condition_for_xpath = "instance('casedb')/casedb/case[@case_id = " \ "instance('commcaresession')/session/data/case_id]/prop = 'value'" m1f0.form_links = [ FormLink(xpath="true()", form_id=m2f0.unique_id, datums=[ FormDatum(name='case_id', xpath="instance('commcaresession')/session/data/case_id"), FormDatum(name='case_id_load_visit_0', xpath="instance('commcaresession')/session/data/case_id_new_visit_0"), ]), FormLink(xpath=condition_for_xpath, form_id=m2f0.unique_id, datums=[ FormDatum(name='case_id', xpath="instance('commcaresession')/session/data/case_id"), FormDatum(name='case_id_load_visit_0', xpath="instance('commcaresession')/session/data/case_id_new_visit_0"), ]), ] m1f0.post_form_workflow_fallback = WORKFLOW_PREVIOUS self.assertXmlPartialEqual(self.get_xml('form_link_tdh_with_fallback_previous'), factory.app.create_suite(), "./entry") m1f0.post_form_workflow_fallback = WORKFLOW_MODULE self.assertXmlPartialEqual(self.get_xml('form_link_tdh_with_fallback_module'), factory.app.create_suite(), "./entry") m1f0.post_form_workflow_fallback = WORKFLOW_ROOT self.assertXmlPartialEqual(self.get_xml('form_link_tdh_with_fallback_root'), factory.app.create_suite(), "./entry")
def test_reference_to_missing_session_variable_in_stack(self): # http://manage.dimagi.com/default.asp?236750 # # Stack create blocks do not update the session after each datum # so items put into the session in one step aren't available later steps # # <datum id="case_id_A" value="instance('commcaresession')/session/data/case_id_new_A"/> # - <datum id="case_id_B" value="instance('casedb')/casedb/case[@case_id=instance('commcaresession')/session/data/case_id_A]/index/host"/> # + <datum id="case_id_B" value="instance('casedb')/casedb/case[@case_id=instance('commcaresession')/session/data/case_id_new_A]/index/host"/> # # in the above example ``case_id_A`` is being added to the session and then # later referenced. However since the session doesn't get updated # the value isn't available in the session. # # To fix this we need to replace any references to previous variables with the full xpath which # that session variable references. # # See corehq.apps.app_manager.suite_xml.post_process.workflow._replace_session_references_in_stack factory = AppFactory(build_version='2.9.0/latest') m0, m0f0 = factory.new_basic_module('person registration', 'person') factory.form_opens_case(m0f0) m1, m1f0 = factory.new_advanced_module('episode registration', 'episode') factory.form_requires_case(m1f0, case_type='person') factory.form_opens_case(m1f0, case_type='episode', is_subcase=True, is_extension=True) m2, m2f0 = factory.new_advanced_module('tests', 'episode') factory.form_requires_case(m2f0, 'episode') factory.advanced_form_autoloads(m2f0, AUTO_SELECT_CASE, 'host', 'load_episode_0') m1f0.post_form_workflow = WORKFLOW_FORM m1f0.form_links = [ FormLink( xpath="true()", form_id=m2f0.unique_id, datums=[ FormDatum( name='case_id_load_episode_0', xpath= "instance('commcaresession')/session/data/case_id_new_episode_0" ) ]), ] self.assertXmlPartialEqual(self.get_xml('form_link_enikshay'), factory.app.create_suite(), "./entry")
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': clean_trans(form.name, [lang])} if should_edit('comment'): form.comment = request.POST['comment'] 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("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') ], ) module_unique_ids = [m.unique_id for m in app.get_modules()] form.form_links = [FormLink( xpath=link[0], form_id=link[1] if link[1] not in module_unique_ids else None, module_unique_id=link[1] if link[1] in module_unique_ids else None, 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 ) if should_edit('session_endpoint_id'): raw_endpoint_id = request.POST['session_endpoint_id'] try: set_session_endpoint(form, raw_endpoint_id, app) except InvalidSessionEndpoint as e: return json_response({'message': str(e)}, status_code=400) if should_edit('function_datum_endpoints'): if request.POST['function_datum_endpoints']: form.function_datum_endpoints = request.POST['function_datum_endpoints'].replace(" ", "").split(",") else: form.function_datum_endpoints = [] 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)
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] handle_media_edits(request, form, should_edit, resp, lang) app.save(resp) notify_form_changed(domain, request.couch_user, app_id, unique_form_id) if ajax: return HttpResponse(json.dumps(resp)) else: return back_to_main(request, domain, app_id=app_id, unique_form_id=unique_form_id) @no_conflict_require_POST
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(unicode(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 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("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 = unicode(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('>\n\s+([^<>\s].*?)\n\s+</', re.DOTALL) prettyXml = text_re.sub('>\g<1></', px) xform = prettyXml except Exception: pass if xform: save_xform(app, form, xform) else: raise Exception("You didn't select a form to upload") except Exception as e: if ajax: return HttpResponseBadRequest(unicode(e)) else: messages.error(request, unicode(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('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.message) }, status_code=400) form.custom_instances = [ CustomInstance( instance_id=instance.get("instanceId"), instance_path=instance.get("instancePath"), ) for instance in instances ] 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)