categoriesadmin.py 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. from django.contrib import messages
  2. from django.shortcuts import redirect
  3. from django.utils.translation import gettext_lazy as _
  4. from .. import THREADS_ROOT_NAME
  5. from ...acl.cache import clear_acl_cache
  6. from ...admin.views import generic
  7. from ...threads.threadtypes import trees_map
  8. from ..forms import CategoryFormFactory, DeleteFormFactory
  9. from ..models import Category, RoleCategoryACL
  10. class CategoryAdmin(generic.AdminBaseMixin):
  11. root_link = "misago:admin:categories:nodes:index"
  12. model = Category
  13. templates_dir = "misago/admin/categories"
  14. message_404 = _("Requested category does not exist.")
  15. def get_target(self, kwargs):
  16. target = super().get_target(kwargs)
  17. threads_tree_id = trees_map.get_tree_id_for_root(THREADS_ROOT_NAME)
  18. target_is_special = bool(target.special_role)
  19. target_not_in_categories_tree = target.tree_id != threads_tree_id
  20. if target.pk and (target_is_special or target_not_in_categories_tree):
  21. raise Category.DoesNotExist()
  22. else:
  23. return target
  24. class CategoriesList(CategoryAdmin, generic.ListView):
  25. def get_queryset(self):
  26. return Category.objects.all_categories()
  27. def process_context(self, request, context):
  28. context["items"] = [f for f in context["items"]]
  29. children_lists = {}
  30. for item in context["items"]:
  31. item.level_range = range(item.level - 1)
  32. item.first = False
  33. item.last = False
  34. children_lists.setdefault(item.parent_id, []).append(item)
  35. for level_items in children_lists.values():
  36. level_items[0].first = True
  37. level_items[-1].last = True
  38. return context
  39. class CategoryFormMixin(object):
  40. def create_form_type(self, request, target):
  41. return CategoryFormFactory(target)
  42. def handle_form(self, form, request, target):
  43. if form.instance.pk:
  44. if form.instance.parent_id != form.cleaned_data["new_parent"].pk:
  45. form.instance.move_to(
  46. form.cleaned_data["new_parent"], position="last-child"
  47. )
  48. form.instance.save()
  49. if form.instance.parent_id != form.cleaned_data["new_parent"].pk:
  50. Category.objects.clear_cache()
  51. else:
  52. form.instance.insert_at(
  53. form.cleaned_data["new_parent"], position="last-child", save=True
  54. )
  55. Category.objects.clear_cache()
  56. if form.cleaned_data.get("copy_permissions"):
  57. form.instance.category_role_set.all().delete()
  58. copy_from = form.cleaned_data["copy_permissions"]
  59. copied_acls = []
  60. for acl in copy_from.category_role_set.all():
  61. copied_acls.append(
  62. RoleCategoryACL(
  63. role_id=acl.role_id,
  64. category=form.instance,
  65. category_role_id=acl.category_role_id,
  66. )
  67. )
  68. if copied_acls:
  69. RoleCategoryACL.objects.bulk_create(copied_acls)
  70. clear_acl_cache()
  71. messages.success(request, self.message_submit % {"name": target.name})
  72. class NewCategory(CategoryFormMixin, CategoryAdmin, generic.ModelFormView):
  73. message_submit = _('New category "%(name)s" has been saved.')
  74. class EditCategory(CategoryFormMixin, CategoryAdmin, generic.ModelFormView):
  75. message_submit = _('Category "%(name)s" has been edited.')
  76. class DeleteCategory(CategoryAdmin, generic.ModelFormView):
  77. message_submit = _('Category "%(name)s" has been deleted.')
  78. template = "delete.html"
  79. def create_form_type(self, request, target):
  80. return DeleteFormFactory(target)
  81. def handle_form(self, form, request, target):
  82. move_children_to = form.cleaned_data.get("move_children_to")
  83. move_threads_to = form.cleaned_data.get("move_threads_to")
  84. if move_children_to:
  85. for child in target.get_children():
  86. # refresh child and new parent
  87. move_children_to = Category.objects.get(pk=move_children_to.pk)
  88. child = Category.objects.get(pk=child.pk)
  89. child.move_to(move_children_to, "last-child")
  90. if move_threads_to and child.pk == move_threads_to.pk:
  91. move_threads_to = child
  92. else:
  93. for child in target.get_descendants().order_by("-lft"):
  94. child.delete_content()
  95. child.delete()
  96. if move_threads_to:
  97. target.move_content(move_threads_to)
  98. move_threads_to.synchronize()
  99. move_threads_to.save()
  100. else:
  101. target.delete_content()
  102. # refresh instance
  103. instance = Category.objects.get(pk=form.instance.pk)
  104. instance.delete()
  105. messages.success(request, self.message_submit % {"name": target.name})
  106. return redirect(self.root_link)
  107. class MoveDownCategory(CategoryAdmin, generic.ButtonView):
  108. def button_action(self, request, target):
  109. try:
  110. other_target = target.get_next_sibling()
  111. except Category.DoesNotExist:
  112. other_target = None
  113. if other_target:
  114. Category.objects.move_node(target, other_target, "right")
  115. Category.objects.clear_cache()
  116. message = _('Category "%(name)s" has been moved below "%(other)s".')
  117. targets_names = {"name": target.name, "other": other_target.name}
  118. messages.success(request, message % targets_names)
  119. class MoveUpCategory(CategoryAdmin, generic.ButtonView):
  120. def button_action(self, request, target):
  121. try:
  122. other_target = target.get_previous_sibling()
  123. except Category.DoesNotExist:
  124. other_target = None
  125. if other_target:
  126. Category.objects.move_node(target, other_target, "left")
  127. Category.objects.clear_cache()
  128. message = _('Category "%(name)s" has been moved above "%(other)s".')
  129. targets_names = {"name": target.name, "other": other_target.name}
  130. messages.success(request, message % targets_names)