polls.py 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. from django.core.exceptions import PermissionDenied
  2. from django.utils import timezone
  3. from django.utils.translation import ugettext_lazy as _
  4. from django.utils.translation import ungettext
  5. from misago.acl import algebra
  6. from misago.acl.decorators import return_boolean
  7. from misago.acl.models import Role
  8. from misago.core import forms
  9. from ..models import Poll, Thread
  10. """
  11. Admin Permissions Forms
  12. """
  13. class RolePermissionsForm(forms.Form):
  14. legend = _("Polls")
  15. can_start_polls = forms.TypedChoiceField(
  16. label=_("Can start polls"),
  17. coerce=int,
  18. initial=0,
  19. choices=(
  20. (0, _("No")),
  21. (1, _("Own threads")),
  22. (2, _("All threads"))
  23. )
  24. )
  25. can_edit_polls = forms.TypedChoiceField(
  26. label=_("Can edit polls"),
  27. coerce=int,
  28. initial=0,
  29. choices=(
  30. (0, _("No")),
  31. (1, _("Own polls")),
  32. (2, _("All polls"))
  33. )
  34. )
  35. can_delete_polls = forms.TypedChoiceField(
  36. label=_("Can delete polls"),
  37. coerce=int,
  38. initial=0,
  39. choices=(
  40. (0, _("No")),
  41. (1, _("Own polls")),
  42. (2, _("All polls"))
  43. )
  44. )
  45. poll_edit_time = forms.IntegerField(
  46. label=_("Time limit for own polls edits, in minutes"),
  47. help_text=_("Enter 0 to don't limit time for editing own polls."),
  48. initial=0,
  49. min_value=0
  50. )
  51. can_always_see_poll_voters = forms.YesNoSwitch(
  52. label=_("Can always see polls voters"),
  53. help_text=_("Allows users to see who voted in poll even if poll votes are secret.")
  54. )
  55. def change_permissions_form(role):
  56. if isinstance(role, Role) and role.special_role != 'anonymous':
  57. return RolePermissionsForm
  58. else:
  59. return None
  60. """
  61. ACL Builder
  62. """
  63. def build_acl(acl, roles, key_name):
  64. acl.update({
  65. 'can_start_polls': 0,
  66. 'can_edit_polls': 0,
  67. 'can_delete_polls': 0,
  68. 'poll_edit_time': 0,
  69. 'can_always_see_poll_voters': 0
  70. })
  71. return algebra.sum_acls(acl, roles=roles, key=key_name,
  72. can_start_polls=algebra.greater,
  73. can_edit_polls=algebra.greater,
  74. can_delete_polls=algebra.greater,
  75. poll_edit_time=algebra.greater_or_zero,
  76. can_always_see_poll_voters=algebra.greater
  77. )
  78. """
  79. ACL's for targets
  80. """
  81. def add_acl_to_poll(user, poll):
  82. poll.acl.update({
  83. 'can_vote': can_vote_poll(user, poll),
  84. 'can_edit': can_edit_poll(user, poll),
  85. 'can_delete': can_delete_poll(user, poll),
  86. 'can_see_votes': can_see_poll_votes(user, poll),
  87. })
  88. def add_acl_to_thread(user, thread):
  89. thread.acl.update({
  90. 'can_start_poll': can_start_poll(user, thread)
  91. })
  92. def register_with(registry):
  93. registry.acl_annotator(Poll, add_acl_to_poll)
  94. registry.acl_annotator(Thread, add_acl_to_thread)
  95. """
  96. ACL tests
  97. """
  98. def allow_start_poll(user, target):
  99. if user.is_anonymous():
  100. raise PermissionDenied(_("You have to sign in to start polls."))
  101. category_acl = user.acl['categories'].get(target.category_id, {
  102. 'can_close_threads': False,
  103. })
  104. if not user.acl.get('can_start_polls'):
  105. raise PermissionDenied(_("You can't start polls."))
  106. if user.acl.get('can_start_polls') < 2 and user.pk != target.starter_id:
  107. raise PermissionDenied(_("You can't start polls in other users threads."))
  108. if not category_acl.get('can_close_threads'):
  109. if target.category.is_closed:
  110. raise PermissionDenied(_("This category is closed. You can't start polls in it."))
  111. if target.is_closed:
  112. raise PermissionDenied(_("This thread is closed. You can't start polls in it."))
  113. can_start_poll = return_boolean(allow_start_poll)
  114. def allow_edit_poll(user, target):
  115. if user.is_anonymous():
  116. raise PermissionDenied(_("You have to sign in to edit polls."))
  117. category_acl = user.acl['categories'].get(target.category_id, {
  118. 'can_close_threads': False,
  119. })
  120. if not user.acl.get('can_edit_polls'):
  121. raise PermissionDenied(_("You can't edit polls."))
  122. if user.acl.get('can_edit_polls') < 2:
  123. if user.pk != target.poster_id:
  124. raise PermissionDenied(_("You can't edit other users polls in this category."))
  125. if not has_time_to_edit_poll(user, target):
  126. message = ungettext(
  127. "You can't edit polls that are older than %(minutes)s minute.",
  128. "You can't edit polls that are older than %(minutes)s minutes.",
  129. user.acl['poll_edit_time'])
  130. raise PermissionDenied(message % {'minutes': user.acl['poll_edit_time']})
  131. if target.is_over:
  132. raise PermissionDenied(_("This poll is over. You can't edit it."))
  133. if not category_acl.get('can_close_threads'):
  134. if target.category.is_closed:
  135. raise PermissionDenied(_("This category is closed. You can't edit polls in it."))
  136. if target.thread.is_closed:
  137. raise PermissionDenied(_("This thread is closed. You can't edit polls in it."))
  138. can_edit_poll = return_boolean(allow_edit_poll)
  139. def allow_delete_poll(user, target):
  140. if user.is_anonymous():
  141. raise PermissionDenied(_("You have to sign in to delete polls."))
  142. category_acl = user.acl['categories'].get(target.category_id, {
  143. 'can_close_threads': False,
  144. })
  145. if not user.acl.get('can_delete_polls'):
  146. raise PermissionDenied(_("You can't delete polls."))
  147. if user.acl.get('can_delete_polls') < 2:
  148. if user.pk != target.poster_id:
  149. raise PermissionDenied(_("You can't delete other users polls in this category."))
  150. if not has_time_to_edit_poll(user, target):
  151. message = ungettext(
  152. "You can't delete polls that are older than %(minutes)s minute.",
  153. "You can't delete polls that are older than %(minutes)s minutes.",
  154. user.acl['poll_edit_time'])
  155. raise PermissionDenied(message % {'minutes': user.acl['poll_edit_time']})
  156. if target.is_over:
  157. raise PermissionDenied(_("This poll is over. You can't delete it."))
  158. if not category_acl.get('can_close_threads'):
  159. if target.category.is_closed:
  160. raise PermissionDenied(_("This category is closed. You can't delete polls in it."))
  161. if target.thread.is_closed:
  162. raise PermissionDenied(_("This thread is closed. You can't delete polls in it."))
  163. can_delete_poll = return_boolean(allow_delete_poll)
  164. def allow_vote_poll(user, target):
  165. if user.is_anonymous():
  166. raise PermissionDenied(_("You have to sign in to vote in polls."))
  167. if target.has_selected_choices and not target.allow_revotes:
  168. raise PermissionDenied(_("You have already voted in this poll."))
  169. if target.is_over:
  170. raise PermissionDenied(_("This poll is over. You can't vote in it."))
  171. category_acl = user.acl['categories'].get(target.category_id, {
  172. 'can_close_threads': False,
  173. })
  174. if not category_acl.get('can_close_threads'):
  175. if target.category.is_closed:
  176. raise PermissionDenied(_("This category is closed. You can't vote in it."))
  177. if target.thread.is_closed:
  178. raise PermissionDenied(_("This thread is closed. You can't vote in it."))
  179. can_vote_poll = return_boolean(allow_vote_poll)
  180. def allow_see_poll_votes(user, target):
  181. if not target.is_public and not user.acl['can_always_see_poll_voters']:
  182. raise PermissionDenied(_("You dont have permission to this poll's voters."))
  183. can_see_poll_votes = return_boolean(allow_see_poll_votes)
  184. def has_time_to_edit_poll(user, target):
  185. edit_time = user.acl['poll_edit_time']
  186. if edit_time:
  187. diff = timezone.now() - target.posted_on
  188. diff_minutes = int(diff.total_seconds() / 60)
  189. return diff_minutes < edit_time
  190. else:
  191. return True