permissions.py 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. from django import forms
  2. from django.contrib.auth import get_user_model
  3. from django.core.exceptions import PermissionDenied
  4. from django.http import Http404
  5. from django.utils.translation import gettext_lazy as _
  6. from ..acl import algebra
  7. from ..acl.decorators import return_boolean
  8. from ..admin.forms import YesNoSwitch
  9. from ..users.models import AnonymousUser
  10. from .models import Category, CategoryRole, RoleCategoryACL
  11. class PermissionsForm(forms.Form):
  12. legend = _("Category access")
  13. can_see = YesNoSwitch(label=_("Can see category"))
  14. can_browse = YesNoSwitch(label=_("Can see category contents"))
  15. def change_permissions_form(role):
  16. if isinstance(role, CategoryRole):
  17. return PermissionsForm
  18. else:
  19. return None
  20. def build_acl(acl, roles, key_name):
  21. new_acl = {"visible_categories": [], "browseable_categories": [], "categories": {}}
  22. new_acl.update(acl)
  23. roles = get_categories_roles(roles)
  24. for category in Category.objects.all_categories():
  25. build_category_acl(new_acl, category, roles, key_name)
  26. return new_acl
  27. def get_categories_roles(roles):
  28. queryset = RoleCategoryACL.objects.filter(role__in=roles)
  29. queryset = queryset.select_related("category_role")
  30. roles = {}
  31. for acl_relation in queryset.iterator():
  32. role = acl_relation.category_role
  33. roles.setdefault(acl_relation.category_id, []).append(role)
  34. return roles
  35. def build_category_acl(acl, category, categories_roles, key_name):
  36. if category.level > 1:
  37. if category.parent_id not in acl["visible_categories"]:
  38. # dont bother with child categories of invisible parents
  39. return
  40. elif not acl["categories"][category.parent_id]["can_browse"]:
  41. # parent's visible, but its contents aint
  42. return
  43. category_roles = categories_roles.get(category.pk, [])
  44. final_acl = {"can_see": 0, "can_browse": 0}
  45. algebra.sum_acls(
  46. final_acl,
  47. roles=category_roles,
  48. key=key_name,
  49. can_see=algebra.greater,
  50. can_browse=algebra.greater,
  51. )
  52. if final_acl["can_see"]:
  53. acl["visible_categories"].append(category.pk)
  54. acl["categories"][category.pk] = final_acl
  55. if final_acl["can_browse"]:
  56. acl["browseable_categories"].append(category.pk)
  57. def add_acl_to_category(user_acl, target):
  58. target.acl["can_see"] = can_see_category(user_acl, target)
  59. target.acl["can_browse"] = can_browse_category(user_acl, target)
  60. def serialize_categories_acls(user_acl):
  61. categories_acl = []
  62. for category, acl in user_acl.pop("categories").items():
  63. if acl["can_browse"]:
  64. categories_acl.append(
  65. {
  66. "id": category,
  67. "can_start_threads": acl.get("can_start_threads", False),
  68. "can_reply_threads": acl.get("can_reply_threads", False),
  69. "can_pin_threads": acl.get("can_pin_threads", 0),
  70. "can_hide_threads": acl.get("can_hide_threads", 0),
  71. "can_close_threads": acl.get("can_close_threads", False),
  72. }
  73. )
  74. user_acl["categories"] = categories_acl
  75. def register_with(registry):
  76. registry.acl_annotator(Category, add_acl_to_category)
  77. registry.user_acl_serializer(serialize_categories_acls)
  78. def allow_see_category(user_acl, target):
  79. try:
  80. category_id = target.pk
  81. except AttributeError:
  82. category_id = int(target)
  83. if not category_id in user_acl["visible_categories"]:
  84. raise Http404()
  85. can_see_category = return_boolean(allow_see_category)
  86. def allow_browse_category(user_acl, target):
  87. target_acl = user_acl["categories"].get(target.id, {"can_browse": False})
  88. if not target_acl["can_browse"]:
  89. message = _('You don\'t have permission to browse "%(category)s" contents.')
  90. raise PermissionDenied(message % {"category": target.name})
  91. can_browse_category = return_boolean(allow_browse_category)