polls.py 8.3 KB

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