diff --git a/tests/test_sync.py b/tests/test_sync.py index 6ad6833..65cb597 100644 --- a/tests/test_sync.py +++ b/tests/test_sync.py @@ -429,6 +429,28 @@ def test_announce_handler(): shutil.rmtree(dir_a) +def test_prune_old_content(): + """Old threads should be pruned after retention period.""" + dir_a = tempfile.mkdtemp() + try: + fdb = ForumDB(dir_a) + now = "2026-06-05T12:00:00" + old = "2026-01-01T12:00:00" + fdb.create_thread("new_t", "New", "", "", "", "aaa", "", now) + fdb.create_thread("old_t", "Old", "", "", "", "bbb", "", old) + fdb.create_post("old_p", "old_t", "", "old reply", "bbb", "", old) + + # Prune with 30 day retention — old thread is ~5 months old + fdb.prune_old_content(30) + + assert fdb.get_thread("new_t") is not None, "new thread should survive" + assert fdb.get_thread("old_t") is None, "old thread should be pruned" + assert len(list(fdb.get_posts("old_t"))) == 0, "old posts should be pruned" + finally: + import shutil + shutil.rmtree(dir_a) + + if __name__ == "__main__": test_sync_thread() test_sync_reply() @@ -440,4 +462,5 @@ if __name__ == "__main__": test_sync_updated_content() test_sync_peer_discovery() test_announce_handler() + test_prune_old_content() print("all sync tests passed") diff --git a/tinyweb_forum/db.py b/tinyweb_forum/db.py index b81c8e7..6ab12de 100644 --- a/tinyweb_forum/db.py +++ b/tinyweb_forum/db.py @@ -1,6 +1,7 @@ import sqlite3 import os import threading +from datetime import datetime, timedelta FORUM_DB = "forum.db" @@ -497,3 +498,28 @@ class ForumDB: ).fetchall() finally: self.return_db(db) + + def prune_old_content(self, retention_days): + """Delete threads and posts older than retention_days.""" + db = self.get_db() + try: + cutoff = (datetime.utcnow() - timedelta(days=retention_days)).strftime("%Y-%m-%dT%H:%M:%S") + # Delete posts in old threads + db.execute( + "DELETE FROM posts WHERE thread_id IN " + "(SELECT id FROM threads WHERE updated_at < ?)", + (cutoff,), + ) + # Delete orphaned posts (thread already deleted) + db.execute( + "DELETE FROM posts WHERE thread_id NOT IN (SELECT id FROM threads)" + ) + # Delete old threads + db.execute("DELETE FROM threads WHERE updated_at < ?", (cutoff,)) + # Clean up orphaned upvotes + db.execute( + "DELETE FROM upvotes WHERE thread_id NOT IN (SELECT id FROM threads)" + ) + db.commit() + finally: + self.return_db(db) diff --git a/tinyweb_forum/handlers.py b/tinyweb_forum/handlers.py index 72c083f..36fdbef 100644 --- a/tinyweb_forum/handlers.py +++ b/tinyweb_forum/handlers.py @@ -484,10 +484,28 @@ class ForumHandlers: ) synced_items = f"
No instances synced yet.
" + auto_discover = self.fdb.get_setting("forum_auto_discover", "1") + auto_discover_checked = " checked" if auto_discover == "1" else "" + retention_days = self.fdb.get_setting("forum_retention_days", "30") + return self._respond( f"{msg}
" - f"Forum instances on the mesh are discovered and synced automatically.
" + f"