예제 #1
0
 def test_archive(self):
     log = SyncLog(cases_on_phone=[CaseState(case_id="c1", 
                                             indices=[CommCareCaseIndex(identifier="d1-id",
                                                                        referenced_id="d1")]),
                                   CaseState(case_id="c2", 
                                             indices=[CommCareCaseIndex(identifier="d1-id",
                                                                        referenced_id="d1"),
                                                      CommCareCaseIndex(identifier="d2-id",
                                                                        referenced_id="d2")]),
                                   CaseState(case_id="c3", indices=[])],
                   dependent_cases_on_phone=[CaseState(case_id="d1", indices=[]),
                                             CaseState(case_id="d2", indices=[])])
     self.assertEqual(5, len(log.get_footprint_of_cases_on_phone()))
     
     self.assertTrue("c3" in log.get_footprint_of_cases_on_phone())
     log.archive_case("c3")
     self.assertEqual(4, len(log.get_footprint_of_cases_on_phone()))
     self.assertFalse("c3" in log.get_footprint_of_cases_on_phone())
     
     self.assertTrue("c2" in log.get_footprint_of_cases_on_phone())
     self.assertTrue("d2" in log.get_footprint_of_cases_on_phone())
     log.archive_case("c2")
     self.assertEqual(2, len(log.get_footprint_of_cases_on_phone()))
     self.assertFalse("c2" in log.get_footprint_of_cases_on_phone())
     self.assertFalse("d2" in log.get_footprint_of_cases_on_phone())
     
     self.assertTrue("c1" in log.get_footprint_of_cases_on_phone())
     self.assertTrue("d1" in log.get_footprint_of_cases_on_phone())
     log.archive_case("c1")
     self.assertEqual(0, len(log.get_footprint_of_cases_on_phone()))
예제 #2
0
 def test_update_dependent_case_owner_still_present(self):
     dependent_case_state = CaseState(case_id="d1", indices=[])
     sync_log = SyncLog(domain="domain",
                        user_id="user",
                        cases_on_phone=[
                            CaseState(case_id="c1",
                                      indices=[
                                          CommCareCaseIndex(
                                              identifier="d1-id",
                                              referenced_id="d1")
                                      ])
                        ],
                        dependent_cases_on_phone=[dependent_case_state],
                        owner_ids_on_phone=['user1'])
     xform_id = uuid.uuid4().hex
     xform = XFormInstance(_id=xform_id)
     form_actions = [
         CommCareCaseAction(action_type=CASE_ACTION_UPDATE,
                            updated_known_properties={'owner_id': 'user2'})
     ]
     with patch.object(CommCareCase,
                       'get_actions_for_form',
                       return_value=form_actions):
         parent_case = CommCareCase(_id='d1')
         # before this test was added, the following call raised a ValueError on legacy logs.
         for log in [
                 sync_log,
                 SimplifiedSyncLog.from_other_format(sync_log)
         ]:
             log.update_phone_lists(xform, [parent_case])
             self.assertIn(dependent_case_state,
                           log.test_only_get_dependent_cases_on_phone())
예제 #3
0
 def test_indices(self):
     parents = ['catelyn', 'ned', 'cersei', 'jaimie']
     index_structure = {
         'bran': [
             {'identifier': 'mom', 'referenced_id': 'catelyn'},
             {'identifier': 'dad', 'referenced_id': 'ned'},
         ],
         'myrcella': [
             {'identifier': 'mom', 'referenced_id': 'cersei'},
             {'identifier': 'dad', 'referenced_id': 'jaimie'},
         ]
     }
     sync_log = SyncLog(
         cases_on_phone=[
             CaseState(case_id='bran', indices=[
                 CommCareCaseIndex(**args) for args in index_structure['bran']
             ]),
             CaseState(case_id='myrcella', indices=[
                 CommCareCaseIndex(**args) for args in index_structure['myrcella']
             ])
         ],
         dependent_cases_on_phone=[
             CaseState(case_id=parent) for parent in parents
         ]
     )
     migrated = SimplifiedSyncLog.from_other_format(sync_log)
     for case_id, indices in index_structure.items():
         self.assertTrue(case_id in migrated.index_tree.indices)
         for index in indices:
             self.assertEqual(index['referenced_id'],
                              migrated.index_tree.indices[case_id][index['identifier']])
     for parent in parents:
         self.assertTrue(parent in migrated.case_ids_on_phone)
         self.assertTrue(parent in migrated.dependent_case_ids_on_phone)
예제 #4
0
    def _get_case_payload(self, response, user, last_sync, synclog):
        sync_operation = user.get_case_updates(last_sync)
        synclog.cases_on_phone = [
            CaseState.from_case(c) for c in sync_operation.actual_owned_cases
        ]
        synclog.dependent_cases_on_phone = [
            CaseState.from_case(c) for c in sync_operation.actual_extended_cases
        ]
        synclog.save(**get_safe_write_kwargs())

        # case blocks
        case_xml_elements = (
            xml.get_case_element(op.case, op.required_updates, self.version)
            for op in sync_operation.actual_cases_to_sync
        )
        for case_elem in case_xml_elements:
            response.append(case_elem)

        # commtrack balance sections
        case_state_list = [CaseState.from_case(op.case) for op in sync_operation.actual_cases_to_sync]
        commtrack_elements = self.get_stock_payload(case_state_list)
        for ct_elem in commtrack_elements:
            response.append(ct_elem)

        return response
예제 #5
0
 def test_cases_in_footprint(self):
     log = SyncLog(cases_on_phone=[CaseState(case_id="c1", indices=[]),
                                   CaseState(case_id="c2", indices=[])])
     self.assertEqual(2, len(log.get_footprint_of_cases_on_phone()))
     
     log.cases_on_phone.append(CaseState(case_id="c3", indices=[]))
     self.assertEqual(3, len(log.get_footprint_of_cases_on_phone()))
예제 #6
0
 def test_update_dependent_case(self):
     sync_log = SyncLog(
         cases_on_phone=[
             CaseState(
                 case_id='bran',
                 indices=[
                     CommCareCaseIndex(identifier='legs',
                                       referenced_id='hodor')
                 ],
             ),
         ],
         dependent_cases_on_phone=[CaseState(case_id='hodor')],
         user_id="someuser")
     xform_id = uuid.uuid4().hex
     xform = XFormInstance(_id=xform_id)
     form_actions = [CommCareCaseAction(action_type=CASE_ACTION_UPDATE, )]
     with patch.object(CommCareCase,
                       'get_actions_for_form',
                       return_value=form_actions):
         parent_case = CommCareCase(_id='hodor')
         # before this test was added, the following call raised a SyncLogAssertionError on legacy logs.
         # this test just ensures it doesn't still do that.
         for log in [
                 sync_log,
                 SimplifiedSyncLog.from_other_format(sync_log)
         ]:
             log.update_phone_lists(xform, [parent_case])
예제 #7
0
    def get_payload(self):
        user = self.user
        last_sync = self.sync_log

        self.validate()

        cached_payload = self.get_cached_payload()
        if cached_payload:
            return cached_payload

        sync_operation = user.get_case_updates(last_sync)
        case_xml_elements = [
            xml.get_case_element(op.case, op.required_updates, self.version)
            for op in sync_operation.actual_cases_to_sync
        ]
        commtrack_elements = self.get_stock_payload(sync_operation)

        last_seq = str(get_db().info()["update_seq"])

        # create a sync log for this
        previous_log_id = last_sync.get_id if last_sync else None

        synclog = SyncLog(
            user_id=user.user_id,
            last_seq=last_seq,
            owner_ids_on_phone=user.get_owner_ids(),
            date=datetime.utcnow(),
            previous_log_id=previous_log_id,
            cases_on_phone=[CaseState.from_case(c) for c in sync_operation.actual_owned_cases],
            dependent_cases_on_phone=[CaseState.from_case(c) for c in sync_operation.actual_extended_cases],
        )
        synclog.save(**get_safe_write_kwargs())

        # start with standard response
        response = get_response_element(
            "Successfully restored account %s!" % user.username, ResponseNature.OTA_RESTORE_SUCCESS
        )

        # add sync token info
        response.append(xml.get_sync_element(synclog.get_id))
        # registration block
        response.append(xml.get_registration_element(user))
        # fixture block
        for fixture in generator.get_fixtures(user, self.version, last_sync):
            response.append(fixture)
        # case blocks
        for case_elem in case_xml_elements:
            response.append(case_elem)
        for ct_elem in commtrack_elements:
            response.append(ct_elem)

        if self.items:
            response.attrib["items"] = "%d" % len(response.getchildren())

        resp = xml.tostring(response)
        self.set_cached_payload_if_enabled(resp)
        return resp
 def test_purge_on_migrate(self):
     sync_log = SyncLog(
         cases_on_phone=[
             CaseState(case_id='robert'),
             CaseState(case_id='cersei'),
         ],
         dependent_cases_on_phone=[CaseState(case_id='gendry')])
     migrated = SimplifiedSyncLog.from_other_format(sync_log)
     self.assertTrue('gendry' not in migrated.case_ids_on_phone)
     self.assertEqual(sync_log.get_state_hash(), migrated.get_state_hash())
 def test_properties_deleted(self):
     sync_log = SyncLog(
         cases_on_phone=[CaseState(case_id='nymeria')],
         dependent_cases_on_phone=[CaseState(case_id='lady')],
     )
     self.assertTrue(hasattr(sync_log, 'cases_on_phone'))
     self.assertTrue(hasattr(sync_log, 'dependent_cases_on_phone'))
     migrated = SimplifiedSyncLog.from_other_format(sync_log)
     self.assertFalse(hasattr(migrated, 'cases_on_phone'))
     self.assertFalse(hasattr(migrated, 'dependent_cases_on_phone'))
예제 #10
0
 def test_dependent_cases(self):
     log = SyncLog(cases_on_phone=[CaseState(case_id="c1", 
                                             indices=[CommCareCaseIndex(identifier="d1-id",
                                                                        referenced_id="d1")])],
                   dependent_cases_on_phone=[CaseState(case_id="d1", indices=[]),
                                             CaseState(case_id="d2", indices=[])])
     
     # d1 counts because it's referenced, d2 doesn't
     self.assertEqual(2, len(log.get_footprint_of_cases_on_phone()))
     self.assertTrue("d1" in log.get_footprint_of_cases_on_phone())
     self.assertFalse("d2" in log.get_footprint_of_cases_on_phone())
예제 #11
0
 def test_dependent_cases_on_phone(self):
     sync_log = SyncLog(
         cases_on_phone=[
             CaseState(
                 case_id='bran',
                 indices=[CommCareCaseIndex(identifier='legs', referenced_id='hodor')],
             ),
         ],
         dependent_cases_on_phone=[CaseState(case_id='hodor')]
     )
     migrated = SimplifiedSyncLog.from_other_format(sync_log)
     self.assertTrue('bran' in migrated.case_ids_on_phone)
     self.assertTrue('hodor' in migrated.case_ids_on_phone)
     self.assertTrue('hodor' in migrated.dependent_case_ids_on_phone)
    def test_update_dependent_case_owner_still_present(self):
        sync_log = SimplifiedSyncLog(
            domain="domain",
            case_ids_on_phone={'c1', 'd1'},
            dependent_case_ids_on_phone={'d1'},
            index_tree=IndexTree(indices={'c1': {
                'd1-id': 'd1'
            }}),
            user_id="user",
            owner_ids_on_phone={'user1'})

        dependent_case_state = CaseState(case_id="d1", indices=[])
        xform_id = uuid.uuid4().hex
        xform = XFormInstance(_id=xform_id)
        form_actions = [
            CommCareCaseAction(action_type=CASE_ACTION_UPDATE,
                               updated_known_properties={'owner_id': 'user2'})
        ]
        with patch.object(CommCareCase,
                          'get_actions_for_form',
                          return_value=form_actions):
            parent_case = CommCareCase(_id='d1')
            # before this test was added, the following call raised a ValueError on legacy logs.
            sync_log.update_phone_lists(xform, [parent_case])
            self.assertIn(dependent_case_state,
                          sync_log.test_only_get_dependent_cases_on_phone())
예제 #13
0
 def test_cases_on_phone(self):
     case_ids = ['nymeria', 'lady']
     sync_log = SyncLog(cases_on_phone=[
         CaseState(case_id=case_id) for case_id in case_ids
     ], )
     migrated = SimplifiedSyncLog.from_other_format(sync_log)
     for case_id in case_ids:
         self.assertTrue(case_id in migrated.case_ids_on_phone)
         self.assertFalse(case_id in migrated.dependent_case_ids_on_phone)
예제 #14
0
    def update_relevant_cases(self, cases):
        new_cases = []
        for case in cases:
            state = CaseState.from_case(case)
            if state.case_id not in self.actual_relevant_cases_dict:
                self.actual_relevant_cases_dict[state.case_id] = state
                new_cases.append(case)

        return new_cases
예제 #15
0
def generate_restore_payload(user, restore_id="", version="1.0", state_hash=""):
    """
    Gets an XML payload suitable for OTA restore. If you need to do something
    other than find all cases matching user_id = user.user_id then you have
    to pass in a user object that overrides the get_case_updates() method.
    
    It should match the same signature as models.user.get_case_updates():
    
        user:          who the payload is for. must implement get_case_updates
        restore_id:    sync token
        version:       the CommCare version 
        
        returns: the xml payload of the sync operation
    """
    check_version(version)
    
    last_sync = None
    if restore_id:
        try:
            last_sync = SyncLog.get(restore_id)
        except Exception:
            logging.error("Request for bad sync log %s by %s, ignoring..." % (restore_id, user))
    
    if last_sync and state_hash:
        parsed_hash = CaseStateHash.parse(state_hash)
        if last_sync.get_state_hash() != parsed_hash:
            raise BadStateException(expected=last_sync.get_state_hash(), 
                                    actual=parsed_hash,
                                    case_ids=last_sync.get_footprint_of_cases_on_phone())
        
    sync_operation = user.get_case_updates(last_sync)
    case_xml_elements = [xml.get_case_element(op.case, op.required_updates, version) \
                         for op in sync_operation.actual_cases_to_sync]
    
    
    last_seq = get_db().info()["update_seq"]
    
    # create a sync log for this
    previous_log_id = last_sync.get_id if last_sync else None
    
    synclog = SyncLog(user_id=user.user_id, last_seq=last_seq,
                      owner_ids_on_phone=user.get_owner_ids(),
                      date=datetime.utcnow(), previous_log_id=previous_log_id,
                      cases_on_phone=[CaseState.from_case(c) for c in \
                                      sync_operation.actual_owned_cases],
                      dependent_cases_on_phone=[CaseState.from_case(c) for c in \
                                                sync_operation.actual_extended_cases])
    synclog.save()
    
    # start with standard response
    response = get_response_element(
        "Successfully restored account %s!" % user.username, 
        ResponseNature.OTA_RESTORE_SUCCESS)
    
    # add sync token info
    response.append(xml.get_sync_element(synclog.get_id))
    # registration block
    response.append(xml.get_registration_element(user))
    # fixture block
    for fixture in generator.get_fixtures(user, version, last_sync):
        response.append(fixture)
    # case blocks
    for case_elem in case_xml_elements:
        response.append(case_elem)
    
    return xml.tostring(response)
예제 #16
0
            return cached_payload

        sync_operation = user.get_case_updates(last_sync)
        case_xml_elements = [xml.get_case_element(op.case, op.required_updates, self.version)
                             for op in sync_operation.actual_cases_to_sync]
        commtrack_elements = self.get_stock_payload(sync_operation)

        last_seq = str(get_db().info()["update_seq"])

        # create a sync log for this
        previous_log_id = last_sync.get_id if last_sync else None

        synclog = SyncLog(user_id=user.user_id, last_seq=last_seq,
                          owner_ids_on_phone=user.get_owner_ids(),
                          date=datetime.utcnow(), previous_log_id=previous_log_id,
                          cases_on_phone=[CaseState.from_case(c) for c in \
                                          sync_operation.actual_owned_cases],
                          dependent_cases_on_phone=[CaseState.from_case(c) for c in \
                                                    sync_operation.actual_extended_cases])
        synclog.save(**get_safe_write_kwargs())

        # start with standard response
        response = get_response_element(
            "Successfully restored account %s!" % user.username,
            ResponseNature.OTA_RESTORE_SUCCESS)

        # add sync token info
        response.append(xml.get_sync_element(synclog.get_id))
        # registration block
        response.append(xml.get_registration_element(user))
        # fixture block
예제 #17
0
 def update_synced_cases(self, case_updates):
     self.all_synced_cases_dict.update(
         {update.case.case_id: CaseState.from_case(update.case) for update in case_updates}
     )
예제 #18
0
 def update_owned_cases(self, cases):
     self.actual_owned_cases_dict.update(
         {case['_id']: CaseState.from_case(case) for case in cases}
     )