diff --git a/remarkbox/scripts/delete_disabled_nodes.py b/remarkbox/scripts/delete_disabled_nodes.py index 1c70a41..49d9642 100644 --- a/remarkbox/scripts/delete_disabled_nodes.py +++ b/remarkbox/scripts/delete_disabled_nodes.py @@ -5,68 +5,76 @@ import logging from pyramid.paster import bootstrap, setup_logging from ..models import Node, get_tm_session, now_timestamp +from . import base_parser + log = logging.getLogger(__name__) + def is_node_anonymized(node): """ Check if a node has already been anonymized based on its attributes. - + Args: node: Node object to check - + Returns: bool: True if already anonymized, False otherwise """ # Check if all identifying attributes are cleared return ( - (node.title == 'deleted' or node.title is None) and - node.data == 'deleted' and - node.data_html == 'deleted' and - node.user_id is None and - node.user_surrogate_id is None and - node.ip_address is None + (node.title == "deleted" or node.title is None) + and node.data == "deleted" + and node.data_html == "deleted" + and node.user_id is None + and node.user_surrogate_id is None + and node.ip_address is None ) + def delete_disabled_nodes(request): """ Delete disabled leaf nodes and anonymize disabled parent nodes while preserving children. Skips re-anonymizing already anonymized parent nodes. - + Args: request: Pyramid request object with transaction manager - + Returns: bool: True if successful, False on error """ try: # Get database session with transaction manager - dbsession = get_tm_session(request.registry['dbsession_factory'], transaction.manager) - + dbsession = get_tm_session( + request.registry["dbsession_factory"], transaction.manager + ) + # Fetch all disabled nodes in one query disabled_nodes = dbsession.query(Node).filter(Node.disabled == True).all() print(f"Found {len(disabled_nodes)} disabled nodes.") - + # Initialize counters for reporting deleted_count = 0 anonymized_count = 0 skipped_count = 0 - + # Process each disabled node for node in disabled_nodes: # Check if node has children using relationship count has_children = node.children.count() > 0 - + if has_children: # Skip if node is already anonymized if is_node_anonymized(node): - print(f"Skipped already anonymized parent node {node.id} with {node.children.count()} children") + print( + f"Skipped already anonymized parent node {node.id} with {node.children.count()} children" + ) skipped_count += 1 continue - + # Anonymize parent node while preserving children - node.title = 'deleted' if node.title else None - node.data = 'deleted' - node.data_html = 'deleted' + node.title = "deleted" if node.title else None + node.data = "deleted" + node.data_html = "deleted" node.ip_address = None node.user_id = None node.user_surrogate_id = None @@ -75,18 +83,20 @@ def delete_disabled_nodes(request): node.watchers = None node.cache = None node.changed = now_timestamp() - + # Clean up URI if it exists if node.has_uri and node.uri: - node.uri.data = 'deleted' + node.uri.data = "deleted" node.has_uri = False - + # Clear cache if it exists if node.cache: node.cache.stats = {} node.cache.invalidate() - - print(f"Anonymized parent node {node.id} with {node.children.count()} children") + + print( + f"Anonymized parent node {node.id} with {node.children.count()} children" + ) anonymized_count += 1 else: # Delete leaf node and its related data @@ -94,56 +104,69 @@ def delete_disabled_nodes(request): if node.events: for event in node.events: dbsession.delete(event) - + # Handle watchers deletion with a loop if node.watchers: for watcher in node.watchers: dbsession.delete(watcher) - + # Delete cache if it exists if node.cache: dbsession.delete(node.cache) - + # Delete URI if it exists if node.has_uri and node.uri: dbsession.delete(node.uri) - + # Delete the node itself dbsession.delete(node) print(f"Deleted leaf node {node.id}") deleted_count += 1 - + # Verify results - remaining_disabled_nodes = dbsession.query(Node).filter(Node.disabled == True).count() - active_nodes_count = dbsession.query(Node).filter(Node.disabled == False).count() + remaining_disabled_nodes = ( + dbsession.query(Node).filter(Node.disabled == True).count() + ) + active_nodes_count = ( + dbsession.query(Node).filter(Node.disabled == False).count() + ) # Print summary of operations - print(f"Summary: Deleted {deleted_count} leaf nodes, anonymized {anonymized_count} parent nodes with children, skipped {skipped_count} already anonymized nodes") - + print( + f"Summary: Deleted {deleted_count} leaf nodes, anonymized {anonymized_count} parent nodes with children, skipped {skipped_count} already anonymized nodes" + ) + if remaining_disabled_nodes > 0: - print(f"Note: {remaining_disabled_nodes} disabled nodes remain (all have children)") - - print(f"Total active nodes: {active_nodes_count}, Remaining disabled nodes: {remaining_disabled_nodes}") + print( + f"Note: {remaining_disabled_nodes} disabled nodes remain (all have children)" + ) + + print( + f"Total active nodes: {active_nodes_count}, Remaining disabled nodes: {remaining_disabled_nodes}" + ) return True - + except Exception as e: # Handle any errors and rollback transaction print(f"An error occurred: {e}") dbsession.rollback() return False + def main(): """ Main entry point for the script to handle command-line execution. """ # Set up argument parser with description - parser = base_parser("Delete disabled leaf nodes and anonymize disabled parent nodes with children.") + parser = base_parser( + "Delete disabled leaf nodes and anonymize disabled parent nodes with children." + ) args = parser.parse_args() - + # Configure logging from config file setup_logging(args.config) - + # Bootstrap Pyramid environment and process nodes with bootstrap(args.config) as env: request = env["request"] @@ -158,5 +181,6 @@ def main(): transaction.abort() raise SystemExit(1) + if __name__ == "__main__": - main() \ No newline at end of file + main()