privatethreads.py 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. from django import forms
  2. from django.core.exceptions import PermissionDenied
  3. from django.http import Http404
  4. from django.utils.translation import ugettext_lazy as _
  5. from misago.acl import algebra
  6. from misago.acl.decorators import return_boolean
  7. from misago.acl.models import Role
  8. from misago.categories.models import PRIVATE_THREADS_ROOT, Category
  9. from misago.core.forms import YesNoSwitch
  10. from misago.threads.models import Thread
  11. class PermissionsForm(forms.Form):
  12. legend = _("Private threads")
  13. can_use_private_threads = YesNoSwitch(label=_("Can use private threads"))
  14. can_start_private_threads = YesNoSwitch(label=_("Can start private threads"))
  15. max_private_thread_participants = forms.IntegerField(
  16. label=_("Max number of users invited to private thread"),
  17. help_text=_("Enter 0 to don't limit number of participants."),
  18. initial=3,
  19. min_value=0,
  20. )
  21. can_add_everyone_to_private_threads = YesNoSwitch(
  22. label=_("Can add everyone to threads"),
  23. help_text=_("Allows user to add users that are blocking him to private threads."),
  24. )
  25. can_report_private_threads = YesNoSwitch(
  26. label=_("Can report private threads"),
  27. help_text=_(
  28. "Allows user to report private threads they are "
  29. "participating in, making them accessible to moderators."
  30. ),
  31. )
  32. can_moderate_private_threads = YesNoSwitch(
  33. label=_("Can moderate private threads"),
  34. help_text=_(
  35. "Allows user to read, reply, edit and delete content "
  36. "in reported private threads."
  37. ),
  38. )
  39. def change_permissions_form(role):
  40. if isinstance(role, Role) and role.special_role != 'anonymous':
  41. return PermissionsForm
  42. else:
  43. return None
  44. def build_acl(acl, roles, key_name):
  45. new_acl = {
  46. 'can_use_private_threads': 0,
  47. 'can_start_private_threads': 0,
  48. 'max_private_thread_participants': 3,
  49. 'can_add_everyone_to_private_threads': 0,
  50. 'can_report_private_threads': 0,
  51. 'can_moderate_private_threads': 0,
  52. }
  53. new_acl.update(acl)
  54. algebra.sum_acls(
  55. new_acl,
  56. roles=roles,
  57. key=key_name,
  58. can_use_private_threads=algebra.greater,
  59. can_start_private_threads=algebra.greater,
  60. max_private_thread_participants=algebra.greater_or_zero,
  61. can_add_everyone_to_private_threads=algebra.greater,
  62. can_report_private_threads=algebra.greater,
  63. can_moderate_private_threads=algebra.greater
  64. )
  65. if not new_acl['can_use_private_threads']:
  66. new_acl['can_start_private_threads'] = 0
  67. return new_acl
  68. private_category = Category.objects.private_threads()
  69. new_acl['visible_categories'].append(private_category.pk)
  70. new_acl['browseable_categories'].append(private_category.pk)
  71. if new_acl['can_moderate_private_threads']:
  72. new_acl['can_see_reports'].append(private_category.pk)
  73. category_acl = {
  74. 'can_see': 1,
  75. 'can_browse': 1,
  76. 'can_see_all_threads': 1,
  77. 'can_see_own_threads': 0,
  78. 'can_start_threads': new_acl['can_start_private_threads'],
  79. 'can_reply_threads': 1,
  80. 'can_edit_threads': 1,
  81. 'can_edit_posts': 1,
  82. 'can_hide_own_threads': 0,
  83. 'can_hide_own_posts': 1,
  84. 'thread_edit_time': 0,
  85. 'post_edit_time': 0,
  86. 'can_hide_threads': 0,
  87. 'can_hide_posts': 0,
  88. 'can_protect_posts': 0,
  89. 'can_move_posts': 0,
  90. 'can_merge_posts': 0,
  91. 'can_pin_threads': 0,
  92. 'can_close_threads': 0,
  93. 'can_move_threads': 0,
  94. 'can_merge_threads': 0,
  95. 'can_approve_content': 0,
  96. 'can_report_content': new_acl['can_report_private_threads'],
  97. 'can_see_reports': 0,
  98. 'can_see_posts_likes': 0,
  99. 'can_like_posts': 0,
  100. 'can_hide_events': 0,
  101. }
  102. if new_acl['can_moderate_private_threads']:
  103. category_acl.update({
  104. 'can_edit_threads': 2,
  105. 'can_edit_posts': 2,
  106. 'can_hide_threads': 2,
  107. 'can_hide_posts': 2,
  108. 'can_protect_posts': 1,
  109. 'can_merge_posts': 1,
  110. 'can_see_reports': 1,
  111. 'can_close_threads': 1,
  112. 'can_hide_events': 2,
  113. })
  114. new_acl['categories'][private_category.pk] = category_acl
  115. return new_acl
  116. def add_acl_to_thread(user, thread):
  117. if thread.thread_type.root_name != PRIVATE_THREADS_ROOT:
  118. return
  119. if not hasattr(thread, 'participant'):
  120. thread.participants_list = []
  121. thread.participant = None
  122. thread.acl.update({
  123. 'can_start_poll': False,
  124. 'can_change_owner': can_change_owner(user, thread),
  125. 'can_add_participants': can_add_participants(user, thread),
  126. })
  127. def register_with(registry):
  128. registry.acl_annotator(Thread, add_acl_to_thread)
  129. def allow_use_private_threads(user):
  130. if user.is_anonymous:
  131. raise PermissionDenied(_("You have to sign in to use private threads."))
  132. if not user.acl_cache['can_use_private_threads']:
  133. raise PermissionDenied(_("You can't use private threads."))
  134. can_use_private_threads = return_boolean(allow_use_private_threads)
  135. def allow_see_private_thread(user, target):
  136. if user.acl_cache['can_moderate_private_threads']:
  137. can_see_reported = target.has_reported_posts
  138. else:
  139. can_see_reported = False
  140. can_see_participating = user in [p.user for p in target.participants_list]
  141. if not (can_see_participating or can_see_reported):
  142. raise Http404()
  143. can_see_private_thread = return_boolean(allow_see_private_thread)
  144. def allow_change_owner(user, target):
  145. is_moderator = user.acl_cache['can_moderate_private_threads']
  146. is_owner = target.participant and target.participant.is_owner
  147. if not (is_owner or is_moderator):
  148. raise PermissionDenied(_("Only thread owner and moderators can change threads owners."))
  149. if not is_moderator and target.is_closed:
  150. raise PermissionDenied(_("Only moderators can change closed threads owners."))
  151. can_change_owner = return_boolean(allow_change_owner)
  152. def allow_add_participants(user, target):
  153. is_moderator = user.acl_cache['can_moderate_private_threads']
  154. if not is_moderator:
  155. if not target.participant or not target.participant.is_owner:
  156. raise PermissionDenied(_("You have to be thread owner to add new participants to it."))
  157. if target.is_closed:
  158. raise PermissionDenied(_("Only moderators can add participants to closed threads."))
  159. can_add_participants = return_boolean(allow_add_participants)
  160. def allow_remove_participant(user, thread, target):
  161. if user.acl_cache['can_moderate_private_threads']:
  162. return
  163. if user == target:
  164. return # we can always remove ourselves
  165. if thread.is_closed:
  166. raise PermissionDenied(_("Only moderators can remove participants from closed threads."))
  167. if not thread.participant or not thread.participant.is_owner:
  168. raise PermissionDenied(_("You have to be thread owner to remove participants from it."))
  169. can_remove_participant = return_boolean(allow_remove_participant)
  170. def allow_add_participant(user, target):
  171. message_format = {'user': target.username}
  172. if not can_use_private_threads(target):
  173. raise PermissionDenied(
  174. _("%(user)s can't participate in private threads.") % message_format
  175. )
  176. if user.acl_cache['can_add_everyone_to_private_threads']:
  177. return
  178. if user.acl_cache['can_be_blocked'] and target.is_blocking(user):
  179. raise PermissionDenied(_("%(user)s is blocking you.") % message_format)
  180. if target.can_be_messaged_by_nobody:
  181. raise PermissionDenied(
  182. _("%(user)s is not allowing invitations to private threads.") % message_format
  183. )
  184. if target.can_be_messaged_by_followed and not target.is_following(user):
  185. message = _("%(user)s limits invitations to private threads to followed users.")
  186. raise PermissionDenied(message % message_format)
  187. can_add_participant = return_boolean(allow_add_participant)
  188. def allow_message_user(user, target):
  189. allow_use_private_threads(user)
  190. allow_add_participant(user, target)
  191. can_message_user = return_boolean(allow_message_user)