privatethreads.py 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. from django.contrib.auth import get_user_model
  2. from django.core.exceptions import PermissionDenied
  3. from django.db.models import Q
  4. from django.http import Http404
  5. from django.utils.translation import ugettext_lazy as _
  6. from misago.acl import add_acl, algebra
  7. from misago.acl.decorators import return_boolean
  8. from misago.acl.models import Role
  9. from misago.core import forms
  10. from misago.forums.models import Forum
  11. __all__ = [
  12. 'allow_use_private_threads',
  13. 'can_use_private_threads',
  14. 'allow_see_private_thread',
  15. 'can_see_private_thread',
  16. 'allow_see_private_post',
  17. 'can_see_private_post',
  18. 'allow_message_user',
  19. 'can_message_user',
  20. 'exclude_invisible_private_threads',
  21. 'exclude_invisible_private_posts'
  22. ]
  23. """
  24. Admin Permissions Form
  25. """
  26. class PermissionsForm(forms.Form):
  27. legend = _("Private threads")
  28. can_use_private_threads = forms.YesNoSwitch(
  29. label=_("Can use private threads"))
  30. can_start_private_threads = forms.YesNoSwitch(
  31. label=_("Can start private threads"))
  32. max_private_thread_participants = forms.IntegerField(
  33. label=_("Max number of users invited to private thread"),
  34. help_text=_("Enter 0 to don't limit number of participants."),
  35. initial=3,
  36. min_value=0)
  37. can_add_everyone_to_private_threads = forms.YesNoSwitch(
  38. label=_("Can add everyone to threads"),
  39. help_text=_("Allows user to add users that are "
  40. "blocking him to private threads."))
  41. can_report_private_threads = forms.YesNoSwitch(
  42. label=_("Can report private threads"),
  43. help_text=_("Allows user to report private threads they are "
  44. "participating in, making them accessible to moderators."))
  45. can_moderate_private_threads = forms.YesNoSwitch(
  46. label=_("Can moderate private threads"),
  47. help_text=_("Allows user to read, reply, edit and delete "
  48. "content in reported private threads."))
  49. def change_permissions_form(role):
  50. if isinstance(role, Role) and role.special_role != 'anonymous':
  51. return PermissionsForm
  52. else:
  53. return None
  54. """
  55. ACL Builder
  56. """
  57. def build_acl(acl, roles, key_name):
  58. new_acl = {
  59. 'can_use_private_threads': 0,
  60. 'can_start_private_threads': 0,
  61. 'max_private_thread_participants': 3,
  62. 'can_add_everyone_to_private_threads': 0,
  63. 'can_report_private_threads': 0,
  64. 'can_moderate_private_threads': 0,
  65. }
  66. new_acl.update(acl)
  67. algebra.sum_acls(new_acl, roles=roles, key=key_name,
  68. can_use_private_threads=algebra.greater,
  69. can_start_private_threads=algebra.greater,
  70. max_private_thread_participants=algebra.greater_or_zero,
  71. can_add_everyone_to_private_threads=algebra.greater,
  72. can_report_private_threads=algebra.greater,
  73. can_moderate_private_threads=algebra.greater
  74. )
  75. if not new_acl['can_use_private_threads']:
  76. return new_acl
  77. private_forum = Forum.objects.private_threads()
  78. if new_acl['can_moderate_private_threads']:
  79. new_acl['moderated_forums'].append(private_forum.pk)
  80. forum_acl = {
  81. 'can_see': 1,
  82. 'can_browse': 1,
  83. 'can_see_all_threads': 1,
  84. 'can_see_own_threads': 0,
  85. 'can_start_threads': new_acl['can_start_private_threads'],
  86. 'can_reply_threads': 1,
  87. 'can_edit_threads': 1,
  88. 'can_edit_posts': 1,
  89. 'can_hide_own_threads': 0,
  90. 'can_hide_own_posts': 1,
  91. 'thread_edit_time': 0,
  92. 'post_edit_time': 0,
  93. 'can_hide_threads': 0,
  94. 'can_hide_posts': 0,
  95. 'can_protect_posts': 0,
  96. 'can_merge_posts': 0,
  97. 'can_close_threads': 0,
  98. 'can_review_moderated_content': 0,
  99. 'can_report_content': new_acl['can_report_private_threads'],
  100. 'can_see_reports': 0,
  101. 'can_hide_events': 0,
  102. }
  103. if new_acl['can_moderate_private_threads']:
  104. forum_acl.update({
  105. 'can_edit_threads': 2,
  106. 'can_edit_posts': 2,
  107. 'can_hide_threads': 2,
  108. 'can_hide_posts': 2,
  109. 'can_protect_posts': 1,
  110. 'can_merge_posts': 1,
  111. 'can_see_reports': 1,
  112. 'can_see_reports': 1,
  113. 'can_review_moderated_content': 1,
  114. 'can_hide_events': 2,
  115. })
  116. new_acl['forums'][private_forum.pk] = forum_acl
  117. return new_acl
  118. """
  119. ACL tests
  120. """
  121. def allow_use_private_threads(user):
  122. if user.is_anonymous():
  123. raise PermissionDenied(_("Unsigned members can't use "
  124. "private threads system."))
  125. if not user.acl['can_use_private_threads']:
  126. raise PermissionDenied(_("You can't use private threads system."))
  127. can_use_private_threads = return_boolean(allow_use_private_threads)
  128. def allow_see_private_thread(user, target):
  129. can_see_moderated = user.acl.get('can_moderate_private_threads')
  130. can_see_moderated = can_see_moderated and target.has_reported_posts
  131. can_see_participating = user in [p.user for p in target.participants_list]
  132. if not (can_see_participating or can_see_moderated):
  133. raise Http404()
  134. can_see_private_thread = return_boolean(allow_see_private_thread)
  135. def allow_see_private_post(user, target):
  136. can_see_moderated = user.acl.get('can_moderate_private_threads')
  137. if not (can_see_moderated and target.thread.has_reported_posts):
  138. for participant in target.thread.participants_list:
  139. if participant.user == user and participant.is_removed:
  140. if post.posted_on > target.last_post_on:
  141. raise Http404()
  142. can_see_private_post = return_boolean(allow_see_private_post)
  143. def allow_message_user(user, target):
  144. allow_use_private_threads(user)
  145. if user == target:
  146. raise PermissionDenied(_("You can't message yourself."))
  147. if not user.acl['can_start_private_threads']:
  148. raise PermissionDenied(_("You can't start private threads."))
  149. message_format = {'user': user.username}
  150. if not can_use_private_threads(target):
  151. message = _("%(user)s can't participate in private threads.")
  152. raise PermissionDenied(message % message_format)
  153. if user.acl['can_add_everyone_to_private_threads']:
  154. return None
  155. if user.acl['can_be_blocked'] and target.is_blocking(user):
  156. message = _("%(user)s is blocking you.")
  157. raise PermissionDenied(message % message_format)
  158. if target.can_be_messaged_by_nobody:
  159. message = _("%(user)s is not allowing invitations to private threads.")
  160. raise PermissionDenied(message % message_format)
  161. if target.can_be_messaged_by_followed and not target.is_following(user):
  162. message = _("%(user)s is allowing invitations to private "
  163. "threads only from followed users.")
  164. raise PermissionDenied(message % message_format)
  165. can_message_user = return_boolean(allow_message_user)
  166. """
  167. Queryset helpers
  168. """
  169. def exclude_invisible_private_threads(queryset, user):
  170. if user.acl['can_moderate_private_threads']:
  171. see_participating = Q(participants=user)
  172. see_reported = Q(has_reported_posts=True)
  173. return queryset.filter(see_reported | see_participating)
  174. else:
  175. return queryset.filter(participants=user)
  176. def exclude_invisible_private_posts(queryset, user, forum, thread):
  177. if not forum.acl['can_review_moderated_content']:
  178. for participant in thread.participants_list:
  179. if participant.user == user and participant.is_removed:
  180. left_on = participant.last_post_on
  181. return queryset.filter(posted_on__lte=left_on)
  182. return queryset