def test_second_edit_fails(self): form_id = uuid.uuid4().hex case_id = uuid.uuid4().hex case_block = CaseBlock( create=True, case_id=case_id, case_type='person', version=V2, ).as_string() submit_case_blocks(case_block, domain=self.domain, form_id=form_id) # submit an edit form with a bad case update (for example a bad ID) case_block = CaseBlock( create=True, case_id='', case_type='person', version=V2, ).as_string() submit_case_blocks(case_block, domain=self.domain, form_id=form_id) form = XFormInstance.get(form_id) self.assertEqual('XFormError', form.doc_type) deprecated_form = XFormInstance.get(form.deprecated_form_id) self.assertEqual('XFormDeprecated', deprecated_form.doc_type)
def test_simple_swap(self): # Test a form with a single dup bad_form_id = self._submit_form()._id good_dup_id = self._submit_form(bad_form_id)._id with tempdir() as tmp: ids_file_path = os.path.join(tmp, 'ids') with open(ids_file_path, "w") as ids_file: ids_file.write("{} {}\n".format(DOMAIN, bad_form_id)) call_command('swap_duplicate_xforms', ids_file_path, '/dev/null', no_input=True) # Throw in a second call to the script to test idempotence as well call_command('swap_duplicate_xforms', ids_file_path, '/dev/null', no_input=True) bad_form = XFormInstance.get(bad_form_id) self.assertEqual(bad_form.doc_type, "XFormDuplicate") self.assertRegexpMatches( bad_form.problem, BAD_FORM_PROBLEM_TEMPLATE.format(good_dup_id, "") ) good_dup_form = XFormInstance.get(good_dup_id) self.assertEqual(good_dup_form.doc_type, "XFormInstance") self.assertRegexpMatches( good_dup_form.problem, FIXED_FORM_PROBLEM_TEMPLATE.format( id_=bad_form_id, datetime_="" ) )
def tearDown(self): self.case_repeater.delete() self.form_repeater.delete() XFormInstance.get(instance_id).delete() repeat_records = RepeatRecord.all() for repeat_record in repeat_records: repeat_record.delete()
def swap_doc_types(self, log_file, bad_xform_id, duplicate_xform_id, domain, dry_run): bad_xform = XFormInstance.get(bad_xform_id) # confirm that the doc hasn't already been fixed: bad_xform_problem = None try: bad_xform_problem = bad_xform.problem or "" except AttributeError: pass if bad_xform_problem: if re.match(PROBLEM_TEMPLATE_START, bad_xform_problem): self.log_already_fixed(log_file, bad_xform_id, domain) return duplicate_xform = XFormInstance.get(duplicate_xform_id) now = datetime.now().isoformat() # Convert the XFormInstance to an XFormDuplicate bad_xform.doc_type = XFormDuplicate.__name__ bad_xform.problem = BAD_FORM_PROBLEM_TEMPLATE.format(duplicate_xform_id, now) bad_xform = XFormDuplicate.wrap(bad_xform.to_json()) # Convert the XFormDuplicate to an XFormInstance duplicate_xform.problem = FIXED_FORM_PROBLEM_TEMPLATE.format( id_=bad_xform_id, datetime_=now ) duplicate_xform.doc_type = XFormInstance.__name__ duplicate_xform = XFormInstance.wrap(duplicate_xform.to_json()) self.log_swap(log_file, bad_xform_id, domain, duplicate_xform_id, dry_run) if not dry_run: duplicate_xform.save() bad_xform.save()
def test_migration(self): now = datetime.utcnow() repeats = [ { "url": "http://example.com/", "doc_type": "RepeatRecord", "next_check": now, "last_checked": None, "succeeded": False } ] xform = XFormInstance.get(instance_id) xform.repeats = repeats xform.save() def always_success(): while True: yield 200 self.clear_log() check_inline_form_repeaters(post_fn=self.make_post_fn(always_success())) self.assertEqual(len(self.log), 1) self.assertEqual(self.log[0], (repeats[0]['url'], 200, xform_xml)) self.clear_log() check_inline_form_repeaters(post_fn=self.make_post_fn(always_success())) self.assertEqual(len(self.log), 0)
def testArchivingOnlyForm(self): """ Checks that archiving the only form associated with the case archives the case and unarchiving unarchives it. """ case_id = _post_util(create=True, p1='p1-1', p2='p2-1') case = CommCareCase.get(case_id) self.assertEqual('CommCareCase', case._doc['doc_type']) self.assertEqual(2, len(case.actions)) [form_id] = case.xform_ids form = XFormInstance.get(form_id) form.archive() case = CommCareCase.get(case_id) self.assertEqual('CommCareCase-Deleted', case._doc['doc_type']) # should just have the 'rebuild' action self.assertEqual(1, len(case.actions)) self.assertEqual(const.CASE_ACTION_REBUILD, case.actions[0].action_type) form.unarchive() case = CommCareCase.get(case_id) self.assertEqual('CommCareCase', case._doc['doc_type']) self.assertEqual(3, len(case.actions)) self.assertEqual(const.CASE_ACTION_REBUILD, case.actions[-1].action_type)
def testDecimalAppVersion(self): """ Tests that an appVersion that looks like a decimal: (a) is not converted to a Decimal by couchdbkit (b) does not crash anything """ file_path = os.path.join(os.path.dirname(__file__), "data", "decimalmeta.xml") xml_data = open(file_path, "rb").read() with create_xform_from_xml(xml_data) as doc_id: xform = XFormInstance.get(doc_id) self.assertEqual(xform.metadata.appVersion, "2.0") self.assertEqual( xform.metadata.to_json(), { "username": u"admin", "doc_type": "Metadata", "instanceID": None, "userID": u"f7f0c79e-8b79-11df-b7de-005056c00008", "timeEnd": "2010-07-23T13:55:11Z", "appVersion": u"2.0", "timeStart": "2010-07-22T13:54:27Z", "deprecatedID": None, "deviceID": None, "clinic_id": u"5020280", "location": None, }, )
def _test(self, name, any_id_ok=False, tz_differs=False): with open(os.path.join(os.path.dirname(__file__), 'data', '{name}.xml'.format(name=name))) as f: instance = f.read() if tz_differs and phone_timezones_should_be_processed(): expected_name = name + '-tz' else: expected_name = name with open(os.path.join(os.path.dirname(__file__), 'data', '{name}.json'.format(name=expected_name))) as f: result = json.load(f) with create_and_save_xform(instance) as doc_id: xform = XFormInstance.get(doc_id) try: xform_json = xform.to_json() result['received_on'] = xform_json['received_on'] result['_rev'] = xform_json['_rev'] if any_id_ok: result['_id'] = xform_json['_id'] self.assertDictEqual(xform_json, result) except Exception: # to help when bootstrapping a new test case print json.dumps(xform_json) raise finally: xform.delete()
def test_gps_location(self): file_path = os.path.join(os.path.dirname(__file__), "data", "gps_location.xml") xml_data = open(file_path, "rb").read() with create_xform_from_xml(xml_data) as doc_id: xform = XFormInstance.get(doc_id) self.assertEqual( xform.metadata.location, # '42.3739063 -71.1109113 0.0 886.0' GeoPoint( latitude=Decimal("42.3739063"), longitude=Decimal("-71.1109113"), altitude=Decimal("0.0"), accuracy=Decimal("886.0"), ), ) j = xform.metadata.to_json() self.assertEqual( xform.metadata.to_json(), { "username": u"*****@*****.**", "doc_type": "Metadata", "instanceID": u"5d3d01561f584e85b53669a48bfc6039", "userID": u"f7f0c79e-8b79-11df-b7de-005056c00008", "timeEnd": "2013-07-20T00:02:27Z", "appVersion": u"2.0", "timeStart": "2013-07-19T21:21:31Z", "deprecatedID": None, "deviceID": u"commconnect", "location": "42.3739063 -71.1109113 0.0 886.0", }, ) xform.delete()
def process_xform(self, form_id, new_domain, new_owner, level): if form_id not in self.forms_processing: self.forms_processing[form_id] = self.new_id() else: return print "{}=== xform: {} -> {}".format(' ' * (level+1), form_id, self.forms_processing[form_id]) instance = XFormInstance.get(form_id) xml = instance.get_xml() referenced_case_ids = set(re.findall(r'case_id="([\w-]*)"', xml)) for ref_case_id in referenced_case_ids: if ref_case_id not in self.cases_processing: self.duplicate_case(ref_case_id, new_domain, new_owner, level=level+1) xml = xml.replace(ref_case_id, self.cases_processing[ref_case_id]) referenced_user_ids = set(re.findall(r'user_id="([\w-]*)"', xml)) for ref_form_id in referenced_user_ids: xml = xml.replace(ref_form_id, new_owner) instance_ids = set(re.findall(r'instanceID>([\w-]*)</', xml)) for inst_id in instance_ids: xml = xml.replace(inst_id, self.forms_processing[form_id]) resp = simple_post(xml, self.submit_url, content_type='text/xml') if not resp.status in [200, 201]: raise Exception(resp.read()) # with open("{}/{}.xml".format(OUT, self.forms_processing[form_id]), "w") as form: # form.write(xml) self.processed_docs.append(('form', form_id, self.forms_processing[form_id]))
def test_blank_product_id(self): initial = float(100) balances = [("", initial)] instance_id = self.submit_xml_form(balance_submission(balances)) instance = XFormInstance.get(instance_id) self.assertEqual("XFormError", instance.doc_type) self.assertTrue("MissingProductId" in instance.problem)
def test_form_pillow_indicators(self): form_id = self._save_doc_to_db("indicator_form.json", XFormInstance) form_instance = XFormInstance.get(form_id) # Form Label Indicator form_label = FormLabelIndicatorDefinition.increment_or_create_unique( INDICATOR_TEST_NAMESPACE, INDICATOR_TEST_DOMAIN, slug="create_form", xmlns="http://openrosa.org/formdesigner/indicator-create-xmlns", ) form_label.save() # Form Alias form_alias = FormDataAliasIndicatorDefinition.increment_or_create_unique( INDICATOR_TEST_NAMESPACE, INDICATOR_TEST_DOMAIN, slug="club_name", question_id="location.club", xmlns="http://openrosa.org/formdesigner/indicator-create-xmlns", ) form_alias.save() self.form_pillow.run_burst() indicator_form = IndicatorXForm.get(form_id) self.assertNotEqual(indicator_form.get_db().dbname, form_instance.get_db().dbname) self.assertNotEqual(indicator_form.computed_, {})
def update_sync_log_with_checks(sync_log, xform, cases, case_db, case_id_blacklist=None): assert case_db is not None from casexml.apps.case.xform import CaseProcessingConfig case_id_blacklist = case_id_blacklist or [] try: sync_log.update_phone_lists(xform, cases) except SyncLogAssertionError, e: if e.case_id and e.case_id not in case_id_blacklist: form_ids = get_case_xform_ids(e.case_id) case_id_blacklist.append(e.case_id) for form_id in form_ids: if form_id != xform._id: form = XFormInstance.get(form_id) if form.doc_type in ['XFormInstance', 'XFormError']: reprocess_form_cases( form, CaseProcessingConfig( strict_asserts=True, case_id_blacklist=case_id_blacklist ), case_db=case_db ) updated_log = SyncLog.get(sync_log._id) update_sync_log_with_checks(updated_log, xform, cases, case_db, case_id_blacklist=case_id_blacklist)
def testClosed(self): file_path = os.path.join(os.path.dirname(__file__), "data", "meta.xml") xml_data = open(file_path, "rb").read() with create_xform_from_xml(xml_data) as doc_id: xform = XFormInstance.get(doc_id) self.assertNotEqual(None, xform.metadata) self.assertEqual(date(2010, 07, 22), xform.metadata.timeStart.date()) self.assertEqual(date(2010, 07, 23), xform.metadata.timeEnd.date()) self.assertEqual("admin", xform.metadata.username) self.assertEqual("f7f0c79e-8b79-11df-b7de-005056c00008", xform.metadata.userID) self.assertEqual("v1.2.3 (biz bazzle)", xform.metadata.appVersion) self.assertEqual( xform.metadata.to_json(), { "username": u"admin", "doc_type": "Metadata", "instanceID": None, "userID": u"f7f0c79e-8b79-11df-b7de-005056c00008", "timeEnd": "2010-07-23T13:55:11Z", "appVersion": u"v1.2.3 (biz bazzle)", "timeStart": "2010-07-22T13:54:27Z", "deprecatedID": None, "deviceID": None, "clinic_id": u"5020280", "location": None, }, )
def form_data(request, domain, instance_id): timezone = util.get_timezone(request.couch_user.user_id, domain) try: instance = XFormInstance.get(instance_id) except Exception: raise Http404() try: assert(domain == instance.domain) except AssertionError: raise Http404() cases = CommCareCase.view("case/by_xform_id", key=instance_id, reduce=False, include_docs=True).all() try: form_name = instance.get_form["@name"] except KeyError: form_name = "Untitled Form" is_archived = instance.doc_type == "XFormArchived" if is_archived: messages.info(request, _("This form is archived. To restore it, click 'Restore this form' at the bottom of the page.")) return render(request, "reports/reportdata/form_data.html", dict(domain=domain, instance=instance, cases=cases, timezone=timezone, slug=inspect.SubmitHistory.slug, is_archived=is_archived, form_data=dict(name=form_name, modified=instance.received_on)))
def process_indicators(self, doc_dict, domain, namespaces): case_type = doc_dict.get('type') if not case_type: return case_indicators = [] for namespace in namespaces: case_indicators.extend(CaseIndicatorDefinition.get_all(namespace, domain, case_type=case_type)) if case_indicators: case_doc = CommCareCase.get(doc_dict['_id']) case_doc.update_indicators_in_bulk(case_indicators, logger=pillow_logging) xform_ids = doc_dict.get('xform_ids', []) for namespace in namespaces: for xform_id in xform_ids: try: xform_doc = XFormInstance.get(xform_id) if not xform_doc.xmlns: continue related_xform_indicators = CaseDataInFormIndicatorDefinition.get_all(namespace, domain, xmlns=xform_doc.xmlns) xform_doc.update_indicators_in_bulk(related_xform_indicators, logger=pillow_logging) except ResourceNotFound: pillow_logging.error("[INDICATOR %(namespace)s %(domain)s] Tried to form indicator %(xform_id)s " "from case %(case_id)s and failed." % { 'namespace': namespace, 'domain': domain, 'xform_id': xform_id, 'case_id': doc_dict['_id'], })
def test_form_pillow_indicators(self): form_id = self._save_doc_to_db('indicator_form.json', XFormInstance) form_instance = XFormInstance.get(form_id) # Form Label Indicator form_label = FormLabelIndicatorDefinition.increment_or_create_unique( INDICATOR_TEST_NAMESPACE, INDICATOR_TEST_DOMAIN, slug='create_form', xmlns='http://openrosa.org/formdesigner/indicator-create-xmlns', ) form_label.save() # Form Alias form_alias = FormDataAliasIndicatorDefinition.increment_or_create_unique( INDICATOR_TEST_NAMESPACE, INDICATOR_TEST_DOMAIN, slug='club_name', question_id='location.club', xmlns='http://openrosa.org/formdesigner/indicator-create-xmlns', ) form_alias.save() self.form_pillow.process_changes(since=None, forever=False) indicator_form = IndicatorXForm.get(form_id) self.assertNotEqual( indicator_form.get_db().dbname, form_instance.get_db().dbname ) self.assertNotEqual(indicator_form.computed_, {})
def test_gps_location(self): file_path = os.path.join(os.path.dirname(__file__), "data", "gps_location.xml") xml_data = open(file_path, "rb").read() with create_and_save_xform(xml_data) as doc_id: xform = XFormInstance.get(doc_id) self.assertEqual( xform.metadata.location, # '42.3739063 -71.1109113 0.0 886.0' GeoPoint( latitude=Decimal('42.3739063'), longitude=Decimal('-71.1109113'), altitude=Decimal('0.0'), accuracy=Decimal('886.0'), ) ) self.assertEqual(xform.metadata.to_json(), { 'username': u'*****@*****.**', 'doc_type': 'Metadata', 'instanceID': u'5d3d01561f584e85b53669a48bfc6039', 'userID': u'f7f0c79e-8b79-11df-b7de-005056c00008', 'timeEnd': '2013-07-20T00:02:27Z', 'appVersion': u'2.0', 'timeStart': '2013-07-19T21:21:31Z', 'deprecatedID': None, 'deviceID': u'commconnect', 'location': '42.3739063 -71.1109113 0.0 886.0', }) xform.delete()
def _get_case(session): session = XFormsSession.get(session.get_id) self.assertTrue(session.submission_id) instance = XFormInstance.get(session.submission_id) case_id = instance.xpath("form/case/@case_id") self.assertTrue(case_id) return CommCareCase.get(case_id)
def get_indicators_by_doc(self, doc_dict): indicators = [] case_type = doc_dict.get('type') domain = doc_dict.get('domain') form_ids = doc_dict.get('xform_ids') or [] if case_type and domain: # relevant namespaces namespaces = INDICATOR_CONFIG[domain] for namespace in namespaces: # need all the relevant Case Indicator Defs indicators.extend(CaseIndicatorDefinition.get_all(namespace, domain, case_type=case_type)) # we also need to update forms that are related to this case and might use data which # may have just been updated for form_id in form_ids: try: xform = XFormInstance.get(form_id) if xform.xmlns and isinstance(xform, XFormInstance): case_related_indicators = CaseDataInFormIndicatorDefinition.get_all(namespace, domain, xmlns=xform.xmlns) logging.info("Grabbed Related XForm %s and now processing %d indicators." % (form_id, len(case_related_indicators))) FormIndicatorPillow.update_indicators_in_doc_instance(xform, case_related_indicators) logging.info("Done processing indicators.") except Exception as e: logging.error("Error grabbing related xform for CommCareCase %s: %s" % (doc_dict['_id'], e)) return indicators
def form_inline_display(form_id): if form_id: form = XFormInstance.get(form_id) if form: return "%s: %s" % (form.received_on.date(), form.xmlns) return "missing form: %s" % form_id return "empty form id found"
def testArchiveLastForm(self): initial_amounts = [(p._id, float(100)) for p in self.products] self.submit_xml_form(balance_submission(initial_amounts)) final_amounts = [(p._id, float(50)) for i, p in enumerate(self.products)] second_form_id = self.submit_xml_form(balance_submission(final_amounts)) def _assert_initial_state(): self.assertEqual(1, StockReport.objects.filter(form_id=second_form_id).count()) # 6 = 3 stockonhand and 3 inferred consumption txns self.assertEqual(6, StockTransaction.objects.filter(report__form_id=second_form_id).count()) self.assertEqual(3, StockState.objects.filter(case_id=self.sp._id).count()) for state in StockState.objects.filter(case_id=self.sp._id): self.assertEqual(Decimal(50), state.stock_on_hand) self.assertIsNotNone(state.daily_consumption) # check initial setup _assert_initial_state() # archive and confirm commtrack data is deleted form = XFormInstance.get(second_form_id) form.archive() self.assertEqual(0, StockReport.objects.filter(form_id=second_form_id).count()) self.assertEqual(0, StockTransaction.objects.filter(report__form_id=second_form_id).count()) self.assertEqual(3, StockState.objects.filter(case_id=self.sp._id).count()) for state in StockState.objects.filter(case_id=self.sp._id): # balance should be reverted to 100 in the StockState self.assertEqual(Decimal(100), state.stock_on_hand) # consumption should be none since there will only be 1 data point self.assertIsNone(state.daily_consumption) # unarchive and confirm commtrack data is restored form.unarchive() _assert_initial_state()
def _test_post(self, client, url, expected_auth_context): with open(self.file_path, "rb") as f: response = client.post(url, {"xml_submission_file": f}) xform_id = response['X-CommCareHQ-FormID'] xform = XFormInstance.get(xform_id) self.assertEqual(xform.auth_context, expected_auth_context) return xform
def testArchiveOnlyForm(self): # check no data in stock states self.assertEqual(0, StockState.objects.filter(case_id=self.sp._id).count()) initial_amounts = [(p._id, float(100)) for p in self.products] form_id = self.submit_xml_form(balance_submission(initial_amounts)) # check that we made stuff def _assert_initial_state(): self.assertEqual(1, StockReport.objects.filter(form_id=form_id).count()) self.assertEqual(3, StockTransaction.objects.filter(report__form_id=form_id).count()) self.assertEqual(3, StockState.objects.filter(case_id=self.sp._id).count()) for state in StockState.objects.filter(case_id=self.sp._id): self.assertEqual(Decimal(100), state.stock_on_hand) _assert_initial_state() # archive and confirm commtrack data is cleared form = XFormInstance.get(form_id) form.archive() self.assertEqual(0, StockReport.objects.filter(form_id=form_id).count()) self.assertEqual(0, StockTransaction.objects.filter(report__form_id=form_id).count()) self.assertEqual(0, StockState.objects.filter(case_id=self.sp._id).count()) # unarchive and confirm commtrack data is restored form.unarchive() _assert_initial_state()
def testDecimalAppVersion(self): ''' Tests that an appVersion that looks like a decimal: (a) is not converted to a Decimal by couchdbkit (b) does not crash anything ''' file_path = os.path.join(os.path.dirname(__file__), "data", "decimalmeta.xml") xml_data = open(file_path, "rb").read() with create_and_save_xform(xml_data) as doc_id: xform = XFormInstance.get(doc_id) self.assertEqual(xform.metadata.appVersion, '2.0') self.assertEqual(xform.metadata.to_json(), { 'username': u'admin', 'doc_type': 'Metadata', 'instanceID': None, 'userID': u'f7f0c79e-8b79-11df-b7de-005056c00008', 'timeEnd': '2010-07-23T13:55:11Z', 'appVersion': u'2.0', 'timeStart': '2010-07-22T13:54:27Z', 'deprecatedID': None, 'deviceID': None, 'clinic_id': u'5020280', 'location': None, })
def form_inline_display(form_id, timezone=pytz.utc): if form_id: form = XFormInstance.get(form_id) if form: return "%s: %s" % (tz_utils.adjust_datetime_to_timezone(form.received_on, pytz.utc.zone, timezone.zone).date(), form.xmlns) return "missing form: %s" % form_id return "empty form id found"
def xform(self): try: return XFormInstance.get(self.xform_id) if self.xform_id else None except ResourceNotFound: logging.exception("couldn't access form {form} inside of a referenced case.".format( form=self.xform_id, )) return None
def download_form(request, instance_id): instance = XFormInstance.get(instance_id) response = HttpResponse(mimetype='application/xml') response.write(instance.get_xml()) # if we want it to download like a file put somethingl like this # HttpResponse(mimetype='application/vnd.ms-excel') # response['Content-Disposition'] = 'attachment; filename=%s.xml' % instance_id return response
def xform(self): try: return XFormInstance.get(self.xform_id) if self.xform_id else None except ResourceNotFound: logging.exception( "couldn't access form {form} inside of a referenced case.". format(form=self.xform_id, )) return None
def testMetaDateInDatetimeFields(self): file_path = os.path.join(os.path.dirname(__file__), "data", "date_in_meta.xml") xml_data = open(file_path, "rb").read() with create_and_save_xform(xml_data) as doc_id: xform = XFormInstance.get(doc_id) self.assertEqual(datetime(2014, 7, 10), xform.metadata.timeStart) self.assertEqual(datetime(2014, 7, 11), xform.metadata.timeEnd) xform.delete()
def test_form_extras_override_defaults(self): domain = uuid.uuid4().hex LOOSE_SYNC_TOKEN_VALIDATION.set(domain, True, namespace='domain') token_id = uuid.uuid4().hex factory = CaseFactory(domain=domain, form_extras={'last_sync_token': token_id}) [case] = factory.create_or_update_case(CaseStructure(), form_extras={'last_sync_token': 'differenttoken'}) form = XFormInstance.get(case.xform_ids[0]) self.assertEqual('differenttoken', form.last_sync_token)
def download_form(request, instance_id): instance = XFormInstance.get(instance_id) response = HttpResponse(content_type='application/xml') response.write(instance.get_xml()) # if we want it to download like a file put somethingl like this # HttpResponse(content_type='application/vnd.ms-excel') # response['Content-Disposition'] = 'attachment; filename=%s.xml' % instance_id return response
def download_attachment(request, instance_id, attachment): instance = XFormInstance.get(instance_id) try: attach = instance._attachments[attachment] except KeyError: raise Http404() response = HttpResponse(content_type=attach["content_type"]) response.write(instance.fetch_attachment(attachment)) return response
def form_exists(form_id, domain=None): if not domain: return XFormInstance.get_db().doc_exist(form_id) else: try: xform = XFormInstance.get(form_id) except ResourceNotFound: return False return xform.domain == domain
def form_inline_display(form_id, timezone=pytz.utc): if form_id: try: form = XFormInstance.get(form_id) if form: return "%s: %s" % (ServerTime(form.received_on).user_time(timezone).done().date(), form.xmlns) except ResourceNotFound: pass return "%s: %s" % (_("missing form"), form_id) return _("empty form id found")
def test_archive_forms_basic(self): uploaded_file = WorkbookJSONReader(join(BASE_PATH, BASIC_XLSX)) response = archive_forms(self.domain_name, self.user, list(uploaded_file.get_worksheet())) # Need to re-get instance from DB to get updated attributes for key, _id in self.XFORMS.iteritems(): self.assertEqual(XFormInstance.get(_id).doc_type, 'XFormArchived') self.assertEqual(len(response['success']), len(self.xforms))
def submit_unfinished_form(session_id, include_case_side_effects=False): """ Gets the raw instance of the session's form and submits it. This is used with sms and ivr surveys to save all questions answered so far in a session that needs to close. If include_case_side_effects is False, no case create / update / close actions will be performed, but the form will still be submitted. The form is only submitted if the smsforms session has not yet completed. """ session = SQLXFormsSession.by_session_id(session_id) if session is not None and session.end_time is None: # Get and clean the raw xml try: xml = get_raw_instance(session_id)['output'] except InvalidSessionIdException: session.end(completed=False) session.save() return root = XML(xml) case_tag_regex = re.compile("^(\{.*\}){0,1}case$") # Use regex in order to search regardless of namespace meta_tag_regex = re.compile("^(\{.*\}){0,1}meta$") timeEnd_tag_regex = re.compile("^(\{.*\}){0,1}timeEnd$") current_timstamp = json_format_datetime(datetime.utcnow()) for child in root: if case_tag_regex.match(child.tag) is not None: # Found the case tag case_element = child case_element.set("date_modified", current_timstamp) if not include_case_side_effects: # Remove case actions (create, update, close) child_elements = [case_action for case_action in case_element] for case_action in child_elements: case_element.remove(case_action) elif meta_tag_regex.match(child.tag) is not None: # Found the meta tag, now set the value for timeEnd for meta_child in child: if timeEnd_tag_regex.match(meta_child.tag): meta_child.text = current_timstamp cleaned_xml = tostring(root) # Submit the xml and end the session resp = submit_form_locally(cleaned_xml, session.domain, app_id=session.app_id) xform_id = resp['X-CommCareHQ-FormID'] session.end(completed=False) session.submission_id = xform_id session.save() # Tag the submission as a partial submission xform = XFormInstance.get(xform_id) xform.partial_submission = True xform.survey_incentive = session.survey_incentive xform.save()
def test_archive_forms_missing(self): uploaded_file = WorkbookJSONReader(join(BASE_PATH, MISSING_XLSX)) response = archive_forms(self.domain_name, self.user, list(uploaded_file.get_worksheet())) for key, _id in self.XFORMS.iteritems(): self.assertEqual(XFormInstance.get(_id).doc_type, 'XFormArchived') self.assertEqual(len(response['success']), len(self.xforms)) self.assertEqual(len(response['errors']), 1, "One error for trying to archive a missing form")
def _test(self, id, expected_app_id, expected_build_id): r = spoof_submission( '/a/{domain}/receiver/{id}/'.format(domain=self.domain, id=id), '<data xmlns="http://example.com/"><question1/></data>', hqsubmission=False, ) form_id = r['X-CommCareHQ-FormID'] form = XFormInstance.get(form_id) self.assertEqual(form.app_id, expected_app_id) self.assertEqual(form.build_id, expected_build_id) return form
def test_couch_blob_migration_edit(self): form_id = uuid.uuid4().hex case_id = uuid.uuid4().hex case_block = CaseBlock(create=True, case_id=case_id).as_string() xform = submit_case_blocks(case_block, domain=self.domain, form_id=form_id) # explicitly convert to old-style couch attachments to test the migration workflow form_xml = xform.get_xml() xform.delete_attachment('form.xml') xform.get_db().put_attachment(xform.to_json(), form_xml, 'form.xml') # make sure that worked updated_form_xml = XFormInstance.get(xform._id).get_xml() self.assertEqual(form_xml, updated_form_xml) # this call was previously failing updated_form = submit_case_blocks(case_block, domain=self.domain, form_id=form_id) self.assertEqual( form_xml, XFormInstance.get(updated_form.deprecated_form_id).get_xml())
def testArchiveAfterAttach(self): single_attach = 'fruity_file' self._doCreateCaseWithMultimedia(attachments=[single_attach]) case = CommCareCase.get(TEST_CASE_ID) for xform in case.xform_ids: form = XFormInstance.get(xform) form.archive() self.assertEqual('XFormArchived', form.doc_type) form.unarchive() self.assertEqual('XFormInstance', form.doc_type)
def handle(self, *args, **options): ids = get_form_ids_by_type('ipm-senegal', 'XFormInstance') to_save = [] locations = SQLLocation.objects.filter( domain='ipm-senegal').values_list('location_id', 'name') locations_map = { location_id: name for (location_id, name) in locations } for doc in iter_docs(XFormInstance.get_db(), ids): try: if 'PPS_name' in doc['form'] and not doc['form']['PPS_name']: case = SupplyPointCase.get(doc['form']['case']['@case_id']) if case.type == 'supply-point': print 'Updating XFormInstance:', doc['_id'] pps_name = locations_map[case.location_id] instance = XFormInstance.get(doc['_id']) # fix the XFormInstance instance.form['PPS_name'] = pps_name for instance_prod in instance.form['products']: instance_prod['PPS_name'] = instance_prod[ 'PPS_name'] or pps_name # fix the actual form.xml xml_object = etree.fromstring(instance.get_xml()) pps_name_node = xml_object.find( re.sub('}.*', '}PPS_name', xml_object.tag)) pps_name_node.text = pps_name products_nodes = xml_object.findall( re.sub('}.*', '}products', xml_object.tag)) for product_node in products_nodes: product_pps_name_node = product_node.find( re.sub('}.*', '}PPS_name', xml_object.tag)) product_pps_name_node.text = pps_name updated_xml = etree.tostring(xml_object) attachment_builder = CouchAttachmentsBuilder( instance._attachments) attachment_builder.add( name='form.xml', content=updated_xml, content_type=instance._attachments['form.xml'] ['content_type']) instance._attachments = attachment_builder.to_json() to_save.append(instance)
def test_empty_gps_location(self): file_path = os.path.join(os.path.dirname(__file__), "data", "gps_empty_location.xml") xml_data = open(file_path, "rb").read() with create_xform_from_xml(xml_data) as doc_id: xform = XFormInstance.get(doc_id) self.assertEqual( xform.metadata.location, None ) self.assertEqual(xform.metadata.to_json()['location'], None) xform.delete()
def _add_eligible_9months(row_data, start_date, end_date, domain): eligible_9months = McctStatus.objects\ .filter(domain__exact=domain)\ .filter(status__exact="eligible")\ .filter(immunized=False)\ .filter(is_booking=False)\ .filter(received_on__range=(start_date, end_date)) forms = [form for form in [XFormInstance.get(status.form_id) for status in eligible_9months] if form.xmlns in FOLLOW_UP_FORMS] forms_4th_visit = [form for form in forms if form.form.get("visits", "") == "4"] row_data["all_eligible_clients_total"]["value"] += len(forms) - len(forms_4th_visit) row_data["status_eligible_due_to_4th_visit"]["value"] += len(forms_4th_visit)
def _doTestNoPillbox(self, bundle): submit_xform(self.submit_url, self.domain.name, bundle['xml']) submitted = XFormInstance.get(bundle['xform_id']) self.assertTrue(hasattr(submitted, PACT_DOTS_DATA_PROPERTY)) observations = query_observations(CASE_ID, bundle['start_date'], bundle['end_date']) observed_dates = set() #assume to be five - 3,2 same as the regimen count, we are refilling empties self.assertEqual( 5, len(observations), msg="Observations do not match regimen count: %d != %d" % (5, len(observations))) art_nonart = set() for obs in observations: observed_dates.add(obs.observed_date) self.assertEquals( obs.day_note, "No check, from form" ) #magic string from the view to indicate a generated DOT observation from form data. art_nonart.add(obs.is_art) self.assertEquals(obs.doc_id, bundle['xform_id']) art = filter(lambda x: x.is_art, observations) self.assertEquals(2, len(art)) art_answered = filter(lambda x: x.adherence != "unchecked", art) self.assertEquals(1, len(art_answered)) nonart = filter(lambda x: not x.is_art, observations) self.assertEquals(3, len(nonart)) nonart_answered = filter(lambda x: x.adherence != "unchecked", nonart) self.assertEquals(1, len(nonart_answered)) #this only does SINGLE observations for art and non art self.assertEquals(len(observed_dates), 1) self.assertEquals(len(art_nonart), 2) # inspect the regenerated submission and ensure the built xml block is correctly filled. case_json = get_dots_case_json(PactPatientCase.get(CASE_ID), anchor_date=bundle['anchor_date']) enddate = bundle['anchor_date'] # anchor date of this submission #encounter_date = datetime.strptime(submitted.form['encounter_date'], '%Y-%m-%d') encounter_date = submitted.form['encounter_date'] for day_delta in range(DOT_DAYS_INTERVAL): obs_date = enddate - timedelta(days=day_delta) ret_index = DOT_DAYS_INTERVAL - day_delta - 1 day_arr = case_json['days'][ret_index] nonart_day_data = day_arr[0] art_day_data = day_arr[1] self.assertEquals(len(nonart_day_data), 3) self.assertEquals(len(art_day_data), 2)
def test_broken_save(self): """ Test that if the second form submission terminates unexpectedly and the main form isn't saved, then there are no side effects such as the original having been marked as deprecated. """ class BorkDB(object): """context manager for making a db's bulk_save temporarily fail""" def __init__(self, db): self.old = {} self.db = db def __enter__(self): self.old['bulk_save'] = self.db.bulk_save self.db.bulk_save = MagicMock(name='bulk_save', side_effect=RequestFailed()) def __exit__(self, exc_type, exc_val, exc_tb): self.db.bulk_save = self.old['bulk_save'] self.assertEqual(access_edits(key=self.ID).count(), 0) self.assertFalse(XFormInstance.get_db().doc_exist(self.ID)) xml_data1, xml_data2 = self._get_files() submit_form_locally(xml_data1, self.domain) doc = XFormInstance.get(self.ID) self.assertEqual(self.ID, doc.get_id) self.assertEqual("XFormInstance", doc.doc_type) self.assertEqual(self.domain, doc.domain) self.assertEqual( UnfinishedSubmissionStub.objects.filter(xform_id=self.ID).count(), 0 ) with BorkDB(XFormInstance.get_db()): with self.assertRaises(RequestFailed): submit_form_locally(xml_data2, self.domain) # it didn't go through, so make sure there are no edits still self.assertEqual(access_edits(key=self.ID).count(), 0) self.assertTrue(XFormInstance.get_db().doc_exist(self.ID)) self.assertEqual( UnfinishedSubmissionStub.objects.filter(xform_id=self.ID, saved=False).count(), 1 ) self.assertEqual( UnfinishedSubmissionStub.objects.filter(xform_id=self.ID).count(), 1 )
def form_inline_display(form_id, timezone=pytz.utc): if form_id: try: form = XFormInstance.get(form_id) if form: return "%s: %s" % (tz_utils.adjust_datetime_to_timezone\ (form.received_on, pytz.utc.zone, timezone.zone).date(), form.xmlns) except ResourceNotFound: pass return "%s: %s" % (_("missing form"), form_id) return _("empty form id found")
def spoof_submission(submit_url, body, name="form.xml", hqsubmission=True, headers={}): client = Client() f = StringIO(body.encode('utf-8')) f.name = name response = client.post(submit_url, { 'xml_submission_file': f, }, **headers) if hqsubmission: xform_id = response['X-CommCareHQ-FormID'] xform = XFormInstance.get(xform_id) xform['doc_type'] = "HQSubmission" xform.save() return response
def template_context(self): return { 'xforms_session': self.xforms_session, 'xform_instance': (XFormInstance.get(self.xforms_session.submission_id) if self.xforms_session.submission_id else None), 'contact': get_doc_info_by_id(self.domain, self.xforms_session.connection_id), 'start_time': (ServerTime(self.xforms_session.start_time).user_time( self.timezone).done().strftime(SERVER_DATETIME_FORMAT)), }
def reprocess_form_cases(form): """ For a given form, reprocess all case elements inside it. This operation should be a no-op if the form was sucessfully processed, but should correctly inject the update into the case history if the form was NOT successfully processed. """ _process_cases(form) # mark cleaned up now that we've reprocessed it if form.doc_type != 'XFormInstance': form = XFormInstance.get(form._id) form.doc_type = 'XFormInstance' form.save()
def testSignal(self): """ Test to ensure that with a DOT submission the signal works """ start_dot = len(XFormInstance.view( 'reports_forms/all_forms', startkey=['submission xmlns', self.domain.name, XMLNS_DOTS_FORM], endkey=['submission xmlns', self.domain.name, XMLNS_DOTS_FORM, {}], reduce=False ).all()) start_update = len(XFormInstance.view( 'reports_forms/all_forms', startkey=['submission xmlns', self.domain.name, XMLNS_PATIENT_UPDATE_DOT], endkey=['submission xmlns', self.domain.name, XMLNS_PATIENT_UPDATE_DOT, {}], reduce=False ).all()) submit_xform(self.submit_url, self.domain.name, self.pillbox_form) submitted = XFormInstance.get(PILLBOX_ID) self.assertTrue(hasattr(submitted, PACT_DOTS_DATA_PROPERTY)) dot_count = XFormInstance.view( 'reports_forms/all_forms', startkey=['submission xmlns', self.domain.name, XMLNS_DOTS_FORM], endkey=['submission xmlns', self.domain.name, XMLNS_DOTS_FORM, {}], ).all()[0]['value'] update_count = XFormInstance.view( 'reports_forms/all_forms', startkey=['submission xmlns', self.domain.name, XMLNS_PATIENT_UPDATE_DOT], endkey=['submission xmlns', self.domain.name, XMLNS_PATIENT_UPDATE_DOT, {}], ).all()[0]['value'] self.assertEquals(dot_count, update_count) self.assertEquals(start_dot+start_update + 2, dot_count + update_count) casedoc = CommCareCase.get(CASE_ID) self.assertEqual(casedoc.xform_ids[-2], PILLBOX_ID) computed_submit = XFormInstance.get(casedoc.xform_ids[-1]) self.assertEqual(computed_submit.xmlns, XMLNS_PATIENT_UPDATE_DOT)
def handle_sms_form_complete(sender, session_id, form, **kwargs): from corehq.apps.smsforms.models import XFormsSession session = XFormsSession.by_session_id(session_id) if session: resp = submit_form_locally(form, session.domain, app_id=session.app_id) xform_id = resp['X-CommCareHQ-FormID'] session.end(completed=True) session.submission_id = xform_id session.save() xform = XFormInstance.get(xform_id) xform.survey_incentive = session.survey_incentive xform.save()
def test_non_swaps(self): # Test a form with multiple dups form_with_multi_dups_id = self._submit_form()._id self._submit_form(form_with_multi_dups_id) self._submit_form(form_with_multi_dups_id) # Test a form with no dups another_form_id = self._submit_form()._id with tempdir() as tmp: ids_file_path = os.path.join(tmp, 'ids') with open(ids_file_path, "w") as ids_file: for id_ in (form_with_multi_dups_id, another_form_id): ids_file.write("{} {}\n".format(DOMAIN, id_)) call_command('swap_duplicate_xforms', ids_file_path, '/dev/null', no_input=True) form_with_multi_dups = XFormInstance.get(form_with_multi_dups_id) self.assertEqual(form_with_multi_dups.doc_type, "XFormInstance") another_form = XFormInstance.get(another_form_id) self.assertEqual(another_form.doc_type, "XFormInstance")
def testClosed(self): file_path = os.path.join(os.path.dirname(__file__), "data", "meta.xml") xml_data = open(file_path, "rb").read() doc_id, errors = post_authenticated_data(xml_data, settings.XFORMS_POST_URL, settings.COUCH_USERNAME, settings.COUCH_PASSWORD) xform = XFormInstance.get(doc_id) self.assertNotEqual(None, xform.metadata) self.assertEqual(date(2010, 07, 22), xform.metadata.timeStart.date()) self.assertEqual(date(2010, 07, 23), xform.metadata.timeEnd.date()) self.assertEqual("admin", xform.metadata.username) self.assertEqual("f7f0c79e-8b79-11df-b7de-005056c00008", xform.metadata.userID)
def submit_unfinished_form(session_id, include_case_side_effects=False): session = XFormsSession.latest_by_session_id(session_id) if session is not None and session.end_time is None: # Get and clean the raw xml try: xml = get_raw_instance(session_id) except InvalidSessionIdException: session.end(completed=False) session.save() return root = XML(xml) case_tag_regex = re.compile( "^(\{.*\}){0,1}case$" ) # Use regex in order to search regardless of namespace meta_tag_regex = re.compile("^(\{.*\}){0,1}meta$") timeEnd_tag_regex = re.compile("^(\{.*\}){0,1}timeEnd$") current_timstamp = json_format_datetime(datetime.utcnow()) for child in root: if case_tag_regex.match(child.tag) is not None: # Found the case tag case_element = child case_element.set("date_modified", current_timstamp) if not include_case_side_effects: # Remove case actions (create, update, close) child_elements = [ case_action for case_action in case_element ] for case_action in child_elements: case_element.remove(case_action) elif meta_tag_regex.match(child.tag) is not None: # Found the meta tag, now set the value for timeEnd for meta_child in child: if timeEnd_tag_regex.match(meta_child.tag): meta_child.text = current_timstamp cleaned_xml = tostring(root) # Submit the xml and end the session resp = submit_form_locally(cleaned_xml, session.domain, app_id=session.app_id) xform_id = resp['X-CommCareHQ-FormID'] session.end(completed=False) session.submission_id = xform_id session.save() # Tag the submission as a partial submission xform = XFormInstance.get(xform_id) xform.partial_submission = True xform.survey_incentive = session.survey_incentive xform.save()
def testArchiveLastForm(self): initial_amounts = [(p._id, float(100)) for p in self.products] self.submit_xml_form(balance_submission(initial_amounts)) final_amounts = [(p._id, float(50)) for i, p in enumerate(self.products)] second_form_id = self.submit_xml_form( balance_submission(final_amounts)) def _assert_initial_state(): self.assertEqual( 1, StockReport.objects.filter(form_id=second_form_id).count()) # 6 = 3 stockonhand and 3 inferred consumption txns self.assertEqual( 6, StockTransaction.objects.filter( report__form_id=second_form_id).count()) self.assertEqual( 3, StockState.objects.filter(case_id=self.sp._id).count()) for state in StockState.objects.filter(case_id=self.sp._id): self.assertEqual(Decimal(50), state.stock_on_hand) self.assertIsNotNone(state.daily_consumption) # check initial setup _assert_initial_state() # archive and confirm commtrack data is deleted form = XFormInstance.get(second_form_id) form.archive() self.assertEqual( 0, StockReport.objects.filter(form_id=second_form_id).count()) self.assertEqual( 0, StockTransaction.objects.filter( report__form_id=second_form_id).count()) self.assertEqual( 3, StockState.objects.filter(case_id=self.sp._id).count()) for state in StockState.objects.filter(case_id=self.sp._id): # balance should be reverted to 100 in the StockState self.assertEqual(Decimal(100), state.stock_on_hand) # consumption should be none since there will only be 1 data point self.assertIsNone(state.daily_consumption) # unarchive and confirm commtrack data is restored form.unarchive() _assert_initial_state()
def testComplicatedGatesBug(self): # found this bug in the wild, used the real (test) forms to fix it # just running through this test used to fail hard, even though there # are no asserts self.assertEqual( 0, len(CommCareCase.view("case/by_user", reduce=False).all())) folder_path = os.path.join("bugs", "dependent_case_conflicts") files = ["reg1.xml", "reg2.xml", "cf.xml", "close.xml"] for f in files: form = self._postWithSyncToken(os.path.join(folder_path, f), self.sync_log.get_id) form = XFormInstance.get(form.get_id) self.assertFalse(hasattr(form, "problem")) self.sync_log = synclog_from_restore_payload( generate_restore_payload(self.user, version="2.0"))
def testClosed(self): file_path = os.path.join(os.path.dirname(__file__), "data", "namespaces.xml") xml_data = open(file_path, "rb").read() with create_and_save_xform(xml_data) as doc_id: xform = XFormInstance.get(doc_id) self.assertEqual("http://commcarehq.org/test/ns", xform.xmlns) self.assertEqual("no namespace here", xform.xpath("form/empty")) self.assertEqual("http://commcarehq.org/test/flatns", xform.xpath("form/flat")["@xmlns"]) self.assertEqual("http://commcarehq.org/test/parent", xform.xpath("form/parent")["@xmlns"]) self.assertEqual("cwo", xform.xpath("form/parent/childwithout")) self.assertEqual("http://commcarehq.org/test/child1", xform.xpath("form/parent/childwith")["@xmlns"]) self.assertEqual("http://commcarehq.org/test/child2", xform.xpath("form/parent/childwithelement")["@xmlns"]) self.assertEqual("gc", xform.xpath("form/parent/childwithelement/grandchild")) self.assertEqual("lcwo", xform.xpath("form/parent/lastchildwithout")) self.assertEqual("nothing here either", xform.xpath("form/lastempty"))
def swap_doc_types(self, log_file, bad_xform_id, duplicate_xform_id, domain, dry_run): bad_xform = XFormInstance.get(bad_xform_id) # confirm that the doc hasn't already been fixed: bad_xform_problem = None try: bad_xform_problem = bad_xform.problem or "" except AttributeError: pass if bad_xform_problem: if re.match(PROBLEM_TEMPLATE_START, bad_xform_problem): self.log_already_fixed(log_file, bad_xform_id, domain) return duplicate_xform = XFormInstance.get(duplicate_xform_id) now = datetime.now().isoformat() # Convert the XFormInstance to an XFormDuplicate bad_xform.doc_type = XFormDuplicate.__name__ bad_xform.problem = BAD_FORM_PROBLEM_TEMPLATE.format( duplicate_xform_id, now) bad_xform = XFormDuplicate.wrap(bad_xform.to_json()) # Convert the XFormDuplicate to an XFormInstance duplicate_xform.problem = FIXED_FORM_PROBLEM_TEMPLATE.format( id_=bad_xform_id, datetime_=now) duplicate_xform.doc_type = XFormInstance.__name__ duplicate_xform = XFormInstance.wrap(duplicate_xform.to_json()) self.log_swap(log_file, bad_xform_id, domain, duplicate_xform_id, dry_run) if not dry_run: duplicate_xform.save() bad_xform.save()