Skip to content

Commit

Permalink
Add heal category trees utils (#1809)
Browse files Browse the repository at this point in the history
  • Loading branch information
rafalp authored Sep 5, 2024
1 parent 67fbf46 commit 740710c
Show file tree
Hide file tree
Showing 8 changed files with 292 additions and 142 deletions.
5 changes: 5 additions & 0 deletions misago/categories/delete.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from .models import Category


def delete_category(category: Category):
category.delete()
31 changes: 0 additions & 31 deletions misago/categories/management/commands/fixcategoriestree.py

This file was deleted.

30 changes: 30 additions & 0 deletions misago/categories/management/commands/healcategorytrees.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
from django.core.management.base import BaseCommand

from ....acl.cache import clear_acl_cache
from ....cache.enums import CacheName
from ....cache.versions import invalidate_cache
from ...mptt import heal_category_trees


class Command(BaseCommand):
"""
This command rebuilds the category trees in the database.
It's useful when the MPTT data of one or more categories becomes invalid,
either due to a bug or manual database manipulation.
"""

help = "Heals the category trees in the database"

def handle(self, *args, **options):
heal_category_trees()
self.stdout.write("Rebuild category trees in the database.")

invalidate_cache(
CacheName.CATEGORIES,
CacheName.MODERATORS,
CacheName.PERMISSIONS,
)

clear_acl_cache()
self.stdout.write("Cleared caches associated with category trees.")
8 changes: 4 additions & 4 deletions misago/categories/migrations/0002_default_categories.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ def create_default_categories_tree(apps, schema_editor):
special_role="root_category",
name="Root",
slug="root",
lft=3,
rght=6,
lft=1,
rght=4,
tree_id=CategoryTreeDeprecated.THREADS,
level=0,
)
Expand All @@ -33,8 +33,8 @@ def create_default_categories_tree(apps, schema_editor):

Category.objects.create(
parent=root,
lft=4,
rght=5,
lft=2,
rght=3,
tree_id=CategoryTreeDeprecated.THREADS,
level=1,
name=category_name,
Expand Down
72 changes: 72 additions & 0 deletions misago/categories/mptt.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
from .models import Category

MPTTData = tuple[int, int, int]


def heal_category_trees() -> int:
trees: set[int] = set()
categories: dict[int, dict] = {}

queryset = Category.objects.values(
"id",
"parent_id",
"tree_id",
"level",
"lft",
"rght",
).order_by("tree_id", "lft")

for category in queryset:
trees.add(category["tree_id"])
categories[category["id"]] = category

healthy_categories: list[dict] = []
for tree_id in trees:
healthy_categories += heal_tree(tree_id, categories)

updates = 0
for healed_category in healthy_categories:
org_category = categories[healed_category["id"]]
if org_category != healed_category:
Category.objects.filter(id=healed_category["id"]).update(
level=healed_category["level"],
lft=healed_category["lft"],
rght=healed_category["rght"],
)
updates += 1

return updates


def heal_tree(tree_id: int, categories: dict[int, dict]) -> list[dict]:
tree_categories = {
c["id"]: c.copy() for c in categories.values() if c["tree_id"] == tree_id
}
tree_categories_list = list(tree_categories.values())

cursor = 0
for category in tree_categories_list:
if category["parent_id"]:
continue

category["level"] = 0
cursor += 1
category["lft"] = cursor
category["rght"] = cursor = heal_category(category, tree_categories_list) + 1

return sorted(tree_categories_list, key=lambda i: i["lft"])


def heal_category(category: dict, tree_categories_list: list[dict]) -> int:
cursor = category["lft"]
for child in tree_categories_list:
if child["parent_id"] != category["id"]:
continue

child["level"] = category["level"] + 1

cursor += 1
child["lft"] = cursor
child["rght"] = cursor = heal_category(child, tree_categories_list) + 1

return cursor
107 changes: 0 additions & 107 deletions misago/categories/tests/test_fixcategoriestree.py

This file was deleted.

Loading

0 comments on commit 740710c

Please sign in to comment.