permissions.py 4.1 KB

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