def get_history(project, human_readable_names=True): """ Fetch history for all models associated with a given project. :param human_readable_names Whether to replace id numbers with readable names :return A sorted list of dicts with history information """ person_query, project_query, bill_query = get_history_queries(project) history = [] for version_list in [ person_query.all(), project_query.all(), bill_query.all() ]: for version in version_list: object_type = { "Person": _("Person"), "Bill": _("Bill"), "Project": _("Project"), }[parent_class(type(version)).__name__] # Use the old name if applicable if version.previous: object_str = describe_version(version.previous) else: object_str = describe_version(version) common_properties = { "time": version.transaction.issued_at.strftime("%Y-%m-%dT%H:%M:%SZ"), "operation_type": version.operation_type, "object_type": object_type, "object_desc": object_str, "ip": version.transaction.remote_addr, } if version.operation_type == Operation.UPDATE: # Only iterate the changeset if the previous version # Was logged if version.previous: changeset = version.changeset if isinstance(version, BillVersion): if version.owers != version.previous.owers: added, removed = describe_owers_change( version, human_readable_names) if added: changeset["owers_added"] = (None, added) if removed: changeset["owers_removed"] = (None, removed) for ( prop, (val_before, val_after), ) in changeset.items(): if human_readable_names: if prop == "payer_id": prop = "payer" if val_after is not None: val_after = describe_version(version.payer) if version.previous and val_before is not None: val_before = describe_version( version.previous.payer) else: val_after = None next_event = common_properties.copy() next_event["prop_changed"] = prop next_event["val_before"] = val_before next_event["val_after"] = val_after history.append(next_event) else: history.append(common_properties) else: history.append(common_properties) return sorted(history, key=history_sort_key, reverse=True)
def describe_version(version_obj): """Use the base model str() function to describe a version object""" return parent_class(type(version_obj)).__str__(version_obj)
def test_throws_error_for_non_version_class(self): with raises(KeyError): parent_class(self.Article)
def test_parent_class_for_version_class(self): ArticleVersion = version_class(self.Article) assert parent_class(ArticleVersion) == self.Article
def _marshal_changed_entities(transaction: TransactionBase, with_details): return [{ 'entity': parent_class(versioned_class).__name__, 'changesets': [_marshal_changeset(changeset, with_details) for changeset in changesets] } for versioned_class, changesets in transaction.changed_entities.items()]