From e12e7667c512ba247da9e0455cf55e95e5f4ab62 Mon Sep 17 00:00:00 2001 From: Russell Ballestrini Date: Sat, 5 Apr 2025 14:12:30 +0000 Subject: [PATCH] Update delete_disabled_nodes.py --- .gitlab-ci.yml | 4 +- remarkbox/scripts/delete_disabled_nodes.py | 73 +++++++++++----------- 2 files changed, 38 insertions(+), 39 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 8325fea..a25ef46 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -27,6 +27,8 @@ build: # Make tarball of the static files. - cp -pr env/static static - tar -zcf static.tar.gz static + # Clean up the directory outside of the gitlab-runner filesystem. + - rm -rf /opt/remarkbox/env # Clone the virtualenv with virtualenv-clone into the desired location. - virtualenv-clone -vvv $PWD/env /opt/remarkbox/env # Create a tarball of the virtualenv. @@ -35,8 +37,6 @@ build: - sha512sum env.tar.gz >> env.tar.gz.hash # Create commit-hash.txt to track this build's git commit hash. - echo $CI_COMMIT_SHA >> commit-hash.txt - # Clean up the directory outside of the gitlab-runner filesystem. - - rm -rf /opt/remarkbox/env artifacts: paths: - env.tar.gz diff --git a/remarkbox/scripts/delete_disabled_nodes.py b/remarkbox/scripts/delete_disabled_nodes.py index 065e6b8..1c70a41 100644 --- a/remarkbox/scripts/delete_disabled_nodes.py +++ b/remarkbox/scripts/delete_disabled_nodes.py @@ -2,16 +2,8 @@ import transaction import logging -from . import base_parser from pyramid.paster import bootstrap, setup_logging -from sqlalchemy import select -from ..models import Node, get_session_factory, get_tm_session -from ..models.vote import Vote -from ..models.watcher import Watcher -from ..models.event import NodeEvent -from ..models.notification import NodeEventNotification -from ..models.uri import Uri -from ..models.meta import now_timestamp +from ..models import Node, get_tm_session, now_timestamp log = logging.getLogger(__name__) @@ -25,6 +17,7 @@ def is_node_anonymized(node): 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 @@ -36,15 +29,9 @@ def is_node_anonymized(node): def delete_disabled_nodes(request): """ - Delete disabled leaf nodes (nodes without children) and anonymize disabled parent nodes while leaving children intact. + Delete disabled leaf nodes and anonymize disabled parent nodes while preserving children. Skips re-anonymizing already anonymized parent nodes. - This function: - 1. Queries for all disabled nodes - 2. Deletes disabled nodes without children - 3. Anonymizes disabled nodes with children leaving children intact (if not already anonymized) - 4. Verifies the deletion/anonymization was successful - Args: request: Pyramid request object with transaction manager @@ -52,30 +39,31 @@ def delete_disabled_nodes(request): bool: True if successful, False on error """ try: + # Get database session with transaction manager dbsession = get_tm_session(request.registry['dbsession_factory'], transaction.manager) - # Query disabled nodes using the Node model's properties + # 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 all nodes in one pass + # Process each disabled node for node in disabled_nodes: - # Use the children relationship from Node model - children_query = node.children - has_children = children_query.count() > 0 + # Check if node has children using relationship count + has_children = node.children.count() > 0 if has_children: - # Check if node is already anonymized + # Skip if node is already anonymized if is_node_anonymized(node): - print(f"Skipped already anonymized parent node {node.id} with {children_query.count()} children") + print(f"Skipped already anonymized parent node {node.id} with {node.children.count()} children") skipped_count += 1 continue - # Anonymize parent node with children, leave children intact + # Anonymize parent node while preserving children node.title = 'deleted' if node.title else None node.data = 'deleted' node.data_html = 'deleted' @@ -88,42 +76,48 @@ def delete_disabled_nodes(request): node.cache = None node.changed = now_timestamp() - # Clean up related objects using relationship properties + # Clean up URI if it exists if node.has_uri and node.uri: 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 {children_query.count()} children") + print(f"Anonymized parent node {node.id} with {node.children.count()} children") anonymized_count += 1 else: - # Delete disabled node with no children - node.events.delete() - dbsession.query(Vote).filter(Vote.node_id == node.id).delete() - watchers = node.watchers - for watcher in watchers: - dbsession.query(NodeEventNotification).filter( - NodeEventNotification.watcher_id == watcher.id - ).delete() - watchers.delete() + # Delete leaf node and its related data + # Handle events deletion + 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 using Node model queries + # Verify results 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") if remaining_disabled_nodes > 0: @@ -134,18 +128,23 @@ def delete_disabled_nodes(request): 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. + 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.") 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"] with request.tm: