threads.py 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750
  1. from datetime import timedelta
  2. from django.db import models
  3. from django.db.models import Q
  4. from django.utils import timezone
  5. from django.utils.translation import ugettext_lazy as _
  6. import floppyforms as forms
  7. from misago.acl.builder import BaseACL
  8. from misago.acl.exceptions import ACLError403, ACLError404
  9. from misago.forms import YesNoSwitch
  10. def make_forum_form(request, role, form):
  11. form.base_fields['can_read_threads'] = forms.TypedChoiceField(label=_("Can read threads"),
  12. choices=(
  13. (0, _("No")),
  14. (1, _("Yes, owned")),
  15. (2, _("Yes, all")),
  16. ), coerce=int)
  17. form.base_fields['can_start_threads'] = forms.TypedChoiceField(label=_("Can start new threads"),
  18. choices=(
  19. (0, _("No")),
  20. (1, _("Yes, with moderation")),
  21. (2, _("Yes")),
  22. ), coerce=int)
  23. form.base_fields['can_edit_own_threads'] = forms.BooleanField(label=_("Can edit own threads"),
  24. widget=YesNoSwitch, initial=False, required=False)
  25. form.base_fields['can_soft_delete_own_threads'] = forms.BooleanField(label=_("Can soft-delete own threads"),
  26. widget=YesNoSwitch, initial=False, required=False)
  27. form.base_fields['can_write_posts'] = forms.TypedChoiceField(label=_("Can write posts"),
  28. choices=(
  29. (0, _("No")),
  30. (1, _("Yes, with moderation")),
  31. (2, _("Yes")),
  32. ), coerce=int)
  33. form.base_fields['can_edit_own_posts'] = forms.BooleanField(label=_("Can edit own posts"),
  34. widget=YesNoSwitch, initial=False, required=False)
  35. form.base_fields['can_soft_delete_own_posts'] = forms.BooleanField(label=_("Can soft-delete own posts"),
  36. widget=YesNoSwitch, initial=False, required=False)
  37. form.base_fields['can_upvote_posts'] = forms.BooleanField(label=_("Can upvote posts"),
  38. widget=YesNoSwitch, initial=False, required=False)
  39. form.base_fields['can_downvote_posts'] = forms.BooleanField(label=_("Can downvote posts"),
  40. widget=YesNoSwitch, initial=False, required=False)
  41. form.base_fields['can_see_posts_scores'] = forms.TypedChoiceField(label=_("Can see post score"),
  42. choices=(
  43. (0, _("No")),
  44. (1, _("Yes, final score")),
  45. (2, _("Yes, both up and down-votes")),
  46. ), coerce=int)
  47. form.base_fields['can_see_votes'] = forms.BooleanField(label=_("Can see who voted on post"),
  48. widget=YesNoSwitch, initial=False, required=False)
  49. form.base_fields['can_make_polls'] = forms.BooleanField(label=_("Can make polls"),
  50. widget=YesNoSwitch, initial=False, required=False)
  51. form.base_fields['can_vote_in_polls'] = forms.BooleanField(label=_("Can vote in polls"),
  52. widget=YesNoSwitch, initial=False, required=False)
  53. form.base_fields['can_see_attachments'] = forms.BooleanField(label=_("Can see attachments"),
  54. widget=YesNoSwitch, initial=False, required=False)
  55. form.base_fields['can_upload_attachments'] = forms.BooleanField(label=_("Can upload attachments"),
  56. widget=YesNoSwitch, initial=False, required=False)
  57. form.base_fields['can_download_attachments'] = forms.BooleanField(label=_("Can download attachments"),
  58. widget=YesNoSwitch, initial=False, required=False)
  59. form.base_fields['attachment_size'] = forms.IntegerField(label=_("Max size of single attachment (in Kb)"),
  60. help_text=_("Enter zero for no limit."),
  61. min_value=0, initial=100)
  62. form.base_fields['attachment_limit'] = forms.IntegerField(label=_("Max number of attachments per post"),
  63. help_text=_("Enter zero for no limit."),
  64. min_value=0, initial=3)
  65. form.base_fields['can_approve'] = forms.BooleanField(label=_("Can accept threads and posts"),
  66. widget=YesNoSwitch, initial=False, required=False)
  67. form.base_fields['can_edit_prefixes'] = forms.BooleanField(label=_("Can edit thread prefixes"),
  68. widget=YesNoSwitch, initial=False, required=False)
  69. form.base_fields['can_see_changelog'] = forms.BooleanField(label=_("Can see edits history"),
  70. widget=YesNoSwitch, initial=False, required=False)
  71. form.base_fields['can_pin_threads'] = forms.TypedChoiceField(label=_("Can change threads weight"),
  72. choices=(
  73. (0, _("No")),
  74. (1, _("Yes, to stickies")),
  75. (2, _("Yes, to announcements")),
  76. ), coerce=int)
  77. form.base_fields['can_edit_threads_posts'] = forms.BooleanField(label=_("Can edit threads and posts"),
  78. widget=YesNoSwitch, initial=False, required=False)
  79. form.base_fields['can_move_threads_posts'] = forms.BooleanField(label=_("Can move, merge and split threads and posts"),
  80. widget=YesNoSwitch, initial=False, required=False)
  81. form.base_fields['can_close_threads'] = forms.BooleanField(label=_("Can close threads"),
  82. widget=YesNoSwitch, initial=False, required=False)
  83. form.base_fields['can_protect_posts'] = forms.BooleanField(label=_("Can protect posts"),
  84. help_text=_("Protected posts cannot be changed by their owners."),
  85. widget=YesNoSwitch, initial=False, required=False)
  86. form.base_fields['can_delete_threads'] = forms.TypedChoiceField(label=_("Can delete threads"),
  87. choices=(
  88. (0, _("No")),
  89. (1, _("Yes, soft-delete")),
  90. (2, _("Yes, hard-delete")),
  91. ), coerce=int)
  92. form.base_fields['can_delete_posts'] = forms.TypedChoiceField(label=_("Can delete posts"),
  93. choices=(
  94. (0, _("No")),
  95. (1, _("Yes, soft-delete")),
  96. (2, _("Yes, hard-delete")),
  97. ), coerce=int)
  98. form.base_fields['can_see_poll_votes'] = forms.BooleanField(label=_("Can always see who voted in poll"),
  99. widget=YesNoSwitch, initial=False, required=False)
  100. form.base_fields['can_edit_polls'] = forms.IntegerField(label=_("Time for poll edition"), min_value=0, initial=15,
  101. help_text=_("Enter number of minutes after poll has been started for which member (or moderator) will be able to edit poll or 0 to always allow edition of unfinished polls. If you enter zero, users will always be able to change (and possibly maniputale) unfinished polls. This permission has also effect on user's permission to delete poll."))
  102. form.base_fields['can_delete_polls'] = forms.TypedChoiceField(label=_("Can delete polls"),
  103. choices=(
  104. (0, _("No")),
  105. (1, _("Yes, within allowed time")),
  106. (2, _("Yes, always")),
  107. ), coerce=int)
  108. form.base_fields['can_delete_attachments'] = forms.BooleanField(label=_("Can delete attachments"),
  109. widget=YesNoSwitch, initial=False, required=False)
  110. form.base_fields['can_delete_checkpoints'] = forms.TypedChoiceField(label=_("Can delete checkpoints"),
  111. choices=(
  112. (0, _("No")),
  113. (1, _("Yes, soft-delete")),
  114. (2, _("Yes, hard-delete")),
  115. ), coerce=int)
  116. form.base_fields['can_see_deleted_checkpoints'] = forms.BooleanField(label=_("Can see deleted checkpoints"),
  117. widget=YesNoSwitch, initial=False, required=False)
  118. form.fieldsets.append((
  119. _("Threads"),
  120. ('can_read_threads', 'can_start_threads', 'can_edit_own_threads', 'can_soft_delete_own_threads')
  121. ))
  122. form.fieldsets.append((
  123. _("Posts"),
  124. ('can_write_posts', 'can_edit_own_posts', 'can_soft_delete_own_posts')
  125. ))
  126. form.fieldsets.append((
  127. _("Karma"),
  128. ('can_upvote_posts', 'can_downvote_posts', 'can_see_posts_scores', 'can_see_votes')
  129. ))
  130. form.fieldsets.append((
  131. _("Polls"),
  132. ('can_make_polls', 'can_vote_in_polls', 'can_see_poll_votes', 'can_edit_polls', 'can_delete_polls')
  133. ))
  134. form.fieldsets.append((
  135. _("Attachments"),
  136. ('can_see_attachments', 'can_upload_attachments',
  137. 'can_download_attachments', 'attachment_size', 'attachment_limit')
  138. ))
  139. form.fieldsets.append((
  140. _("Moderation"),
  141. ('can_approve', 'can_edit_prefixes', 'can_see_changelog', 'can_pin_threads', 'can_edit_threads_posts',
  142. 'can_move_threads_posts', 'can_close_threads', 'can_protect_posts', 'can_delete_threads',
  143. 'can_delete_posts', 'can_delete_attachments', 'can_delete_checkpoints', 'can_see_deleted_checkpoints')
  144. ))
  145. class ThreadsACL(BaseACL):
  146. def get_role(self, forum):
  147. try:
  148. try:
  149. return self.acl[forum.pk]
  150. except AttributeError:
  151. return self.acl[forum]
  152. except KeyError:
  153. return {}
  154. def allow_thread_view(self, user, thread):
  155. try:
  156. forum_role = self.acl[thread.forum_id]
  157. if forum_role['can_read_threads'] == 0:
  158. raise ACLError403(_("You don't have permission to read threads in this forum."))
  159. if forum_role['can_read_threads'] == 1 and thread.weight < 2 and (not user.is_authenticated() or thread.start_poster_id != user.id):
  160. raise ACLError404()
  161. if thread.moderated and not (forum_role['can_approve'] or (user.is_authenticated() and user == thread.start_poster)):
  162. raise ACLError404()
  163. if thread.deleted and not forum_role['can_delete_threads']:
  164. raise ACLError404()
  165. except KeyError:
  166. raise ACLError403(_("You don't have permission to read threads in this forum."))
  167. def allow_post_view(self, user, thread, post):
  168. forum_role = self.acl[thread.forum_id]
  169. if post.moderated and not (forum_role['can_approve'] or (user.is_authenticated() and user == post.user)):
  170. raise ACLError404()
  171. if post.deleted and not (forum_role['can_delete_posts'] or (user.is_authenticated() and user == post.user)):
  172. raise ACLError404()
  173. def filter_threads(self, request, forum, queryset):
  174. try:
  175. forum_role = self.get_role(forum)
  176. if not forum_role['can_approve']:
  177. if request.user.is_authenticated():
  178. queryset = queryset.filter(Q(moderated=False) | Q(start_poster=request.user))
  179. else:
  180. queryset = queryset.filter(moderated=False)
  181. if forum_role['can_read_threads'] == 1:
  182. if request.user.is_authenticated():
  183. queryset = queryset.filter(Q(weight=2) | Q(start_poster_id=request.user.id))
  184. else:
  185. queryset = queryset.filter(weight=2)
  186. if not forum_role['can_delete_threads']:
  187. queryset = queryset.filter(deleted=False)
  188. except KeyError:
  189. return False
  190. return queryset
  191. def filter_posts(self, request, thread, queryset):
  192. try:
  193. forum_role = self.acl[thread.forum.pk]
  194. if not forum_role['can_approve']:
  195. if request.user.is_authenticated():
  196. queryset = queryset.filter(Q(moderated=0) | Q(user=request.user))
  197. else:
  198. queryset = queryset.filter(moderated=0)
  199. except KeyError:
  200. return False
  201. return queryset
  202. def can_read_threads(self, forum):
  203. try:
  204. forum_role = self.get_role(forum)
  205. return forum_role['can_read_threads']
  206. except KeyError:
  207. return False
  208. def can_start_threads(self, forum):
  209. try:
  210. forum_role = self.get_role(forum)
  211. if forum_role['can_read_threads'] == 0 or forum_role['can_start_threads'] == 0:
  212. return False
  213. if forum.closed and forum_role['can_close_threads'] == 0:
  214. return False
  215. return True
  216. except KeyError:
  217. return False
  218. def allow_new_threads(self, forum):
  219. try:
  220. forum_role = self.get_role(forum)
  221. if forum_role['can_read_threads'] == 0 or forum_role['can_start_threads'] == 0:
  222. raise ACLError403(_("You don't have permission to start new threads in this forum."))
  223. if forum.closed and forum_role['can_close_threads'] == 0:
  224. raise ACLError403(_("This forum is closed, you can't start new threads in it."))
  225. except KeyError:
  226. raise ACLError403(_("You don't have permission to start new threads in this forum."))
  227. def can_edit_thread(self, user, forum, thread, post):
  228. try:
  229. forum_role = self.get_role(forum)
  230. if forum_role['can_close_threads'] == 0 and (forum.closed or thread.closed):
  231. return False
  232. if forum_role['can_edit_threads_posts']:
  233. return True
  234. if forum_role['can_edit_own_threads'] and not post.protected and post.user_id == user.pk:
  235. return True
  236. return False
  237. except KeyError:
  238. return False
  239. def allow_thread_edit(self, user, forum, thread, post):
  240. try:
  241. forum_role = self.get_role(forum)
  242. if thread.deleted or post.deleted:
  243. self.allow_deleted_post_view(forum)
  244. if not forum_role['can_close_threads']:
  245. if forum.closed:
  246. raise ACLError403(_("You can't edit threads in closed forums."))
  247. if thread.closed:
  248. raise ACLError403(_("You can't edit closed threads."))
  249. if not forum_role['can_edit_threads_posts']:
  250. if post.user_id != user.pk:
  251. raise ACLError403(_("You can't edit other members threads."))
  252. if not forum_role['can_edit_own_threads']:
  253. raise ACLError403(_("You can't edit your threads."))
  254. if post.protected:
  255. raise ACLError403(_("This thread is protected, you cannot edit it."))
  256. except KeyError:
  257. raise ACLError403(_("You don't have permission to edit threads in this forum."))
  258. def can_reply(self, forum, thread):
  259. try:
  260. forum_role = self.get_role(forum)
  261. if forum_role['can_write_posts'] == 0:
  262. return False
  263. if (forum.closed or thread.closed) and forum_role['can_close_threads'] == 0:
  264. return False
  265. return True
  266. except KeyError:
  267. return False
  268. def allow_reply(self, forum, thread):
  269. try:
  270. forum_role = self.get_role(forum)
  271. if forum_role['can_write_posts'] == 0:
  272. raise ACLError403(_("You don't have permission to write replies in this forum."))
  273. if forum_role['can_close_threads'] == 0:
  274. if forum.closed:
  275. raise ACLError403(_("You can't write replies in closed forums."))
  276. if thread.closed:
  277. raise ACLError403(_("You can't write replies in closed threads."))
  278. except KeyError:
  279. raise ACLError403(_("You don't have permission to write replies in this forum."))
  280. def can_edit_reply(self, user, forum, thread, post):
  281. try:
  282. forum_role = self.get_role(forum)
  283. if forum_role['can_close_threads'] == 0 and (forum.closed or thread.closed):
  284. return False
  285. if forum_role['can_edit_threads_posts']:
  286. return True
  287. if forum_role['can_edit_own_posts'] and not post.protected and post.user_id == user.pk:
  288. return True
  289. return False
  290. except KeyError:
  291. return False
  292. def allow_reply_edit(self, user, forum, thread, post):
  293. try:
  294. forum_role = self.get_role(forum)
  295. if thread.deleted or post.deleted:
  296. self.allow_deleted_post_view(forum)
  297. if not forum_role['can_close_threads']:
  298. if forum.closed:
  299. raise ACLError403(_("You can't edit replies in closed forums."))
  300. if thread.closed:
  301. raise ACLError403(_("You can't edit replies in closed threads."))
  302. if not forum_role['can_edit_threads_posts']:
  303. if post.user_id != user.pk:
  304. raise ACLError403(_("You can't edit other members replies."))
  305. if not forum_role['can_edit_own_posts']:
  306. raise ACLError403(_("You can't edit your replies."))
  307. if post.protected:
  308. raise ACLError403(_("This reply is protected, you cannot edit it."))
  309. except KeyError:
  310. raise ACLError403(_("You don't have permission to edit replies in this forum."))
  311. def can_see_changelog(self, user, forum, post):
  312. try:
  313. forum_role = self.get_role(forum)
  314. return forum_role['can_see_changelog'] or user.pk == post.user_id
  315. except KeyError:
  316. return False
  317. def allow_changelog_view(self, user, forum, post):
  318. try:
  319. forum_role = self.get_role(forum)
  320. if post.thread.deleted or post.deleted:
  321. self.allow_deleted_post_view(forum)
  322. if not (forum_role['can_see_changelog'] or user.pk == post.user_id):
  323. raise ACLError403(_("You don't have permission to see history of changes made to this post."))
  324. except KeyError:
  325. raise ACLError403(_("You don't have permission to see history of changes made to this post."))
  326. def can_make_revert(self, forum, thread):
  327. try:
  328. forum_role = self.get_role(forum)
  329. if not forum_role['can_close_threads'] and (forum.closed or thread.closed):
  330. return False
  331. return forum_role['can_edit_threads_posts']
  332. except KeyError:
  333. return False
  334. def allow_revert(self, forum, thread):
  335. try:
  336. forum_role = self.get_role(forum)
  337. if not forum_role['can_close_threads']:
  338. if forum.closed:
  339. raise ACLError403(_("You can't make reverts in closed forums."))
  340. if thread.closed:
  341. raise ACLError403(_("You can't make reverts in closed threads."))
  342. if not forum_role['can_edit_threads_posts']:
  343. raise ACLError403(_("You don't have permission to make reverts in this forum."))
  344. except KeyError:
  345. raise ACLError403(_("You don't have permission to make reverts in this forum."))
  346. def can_mod_threads(self, forum):
  347. try:
  348. forum_role = self.get_role(forum)
  349. return (
  350. forum_role['can_approve']
  351. or forum_role['can_pin_threads']
  352. or forum_role['can_move_threads_posts']
  353. or forum_role['can_close_threads']
  354. or forum_role['can_delete_threads']
  355. )
  356. except KeyError:
  357. return False
  358. def can_mod_posts(self, forum):
  359. try:
  360. forum_role = self.get_role(forum)
  361. return (
  362. forum_role['can_edit_threads_posts']
  363. or forum_role['can_move_threads_posts']
  364. or forum_role['can_close_threads']
  365. or forum_role['can_delete_threads']
  366. or forum_role['can_delete_posts']
  367. )
  368. except KeyError:
  369. return False
  370. def can_approve(self, forum):
  371. try:
  372. forum_role = self.get_role(forum)
  373. return forum_role['can_approve']
  374. except KeyError:
  375. return False
  376. def can_close(self, forum):
  377. try:
  378. forum_role = self.get_role(forum)
  379. return forum_role['can_close_threads']
  380. except KeyError:
  381. return False
  382. def can_protect(self, forum):
  383. try:
  384. forum_role = self.get_role(forum)
  385. return forum_role['can_protect_posts']
  386. except KeyError:
  387. return False
  388. def can_pin_threads(self, forum):
  389. try:
  390. forum_role = self.get_role(forum)
  391. return forum_role['can_pin_threads']
  392. except KeyError:
  393. return False
  394. def can_delete_thread(self, user, forum, thread, post):
  395. try:
  396. forum_role = self.get_role(forum)
  397. if post.pk != thread.start_post_id:
  398. return False
  399. if not forum_role['can_close_threads'] and (forum.closed or thread.closed):
  400. return False
  401. if post.protected and not forum_role['can_protect_posts'] and not forum_role['can_delete_threads']:
  402. return False
  403. if forum_role['can_delete_threads']:
  404. return forum_role['can_delete_threads']
  405. if thread.start_poster_id == user.pk and forum_role['can_soft_delete_own_threads']:
  406. return 1
  407. return False
  408. except KeyError:
  409. return False
  410. def allow_delete_thread(self, user, forum, thread, post, delete=False):
  411. try:
  412. forum_role = self.get_role(forum)
  413. if not forum_role['can_close_threads']:
  414. if forum.closed:
  415. raise ACLError403(_("You don't have permission to delete threads in closed forum."))
  416. if thread.closed:
  417. raise ACLError403(_("This thread is closed, you cannot delete it."))
  418. if post.protected and not forum_role['can_protect_posts'] and not forum_role['can_delete_threads']:
  419. raise ACLError403(_("This post is protected, you cannot delete it."))
  420. if not (forum_role['can_delete_threads'] == 2 or
  421. (not delete and (forum_role['can_delete_threads'] == 1 or
  422. (thread.start_poster_id == user.pk and forum_role['can_soft_delete_own_threads'])))):
  423. raise ACLError403(_("You don't have permission to delete this thread."))
  424. if thread.deleted and not delete:
  425. raise ACLError403(_("This thread is already deleted."))
  426. except KeyError:
  427. raise ACLError403(_("You don't have permission to delete this thread."))
  428. def can_delete_post(self, user, forum, thread, post):
  429. try:
  430. forum_role = self.get_role(forum)
  431. if post.pk == thread.start_post_id:
  432. return False
  433. if not forum_role['can_close_threads'] and (forum.closed or thread.closed):
  434. return False
  435. if post.protected and not forum_role['can_protect_posts'] and not forum_role['can_delete_posts']:
  436. return False
  437. if forum_role['can_delete_posts']:
  438. return forum_role['can_delete_posts']
  439. if post.user_id == user.pk and not post.protected and forum_role['can_soft_delete_own_posts']:
  440. return 1
  441. return False
  442. except KeyError:
  443. return False
  444. def allow_delete_post(self, user, forum, thread, post, delete=False):
  445. try:
  446. forum_role = self.get_role(forum)
  447. if not forum_role['can_close_threads']:
  448. if forum.closed:
  449. raise ACLError403(_("You don't have permission to delete posts in closed forum."))
  450. if thread.closed:
  451. raise ACLError403(_("This thread is closed, you cannot delete its posts."))
  452. if post.protected and not forum_role['can_protect_posts'] and not forum_role['can_delete_posts']:
  453. raise ACLError403(_("This post is protected, you cannot delete it."))
  454. if not (forum_role['can_delete_posts'] == 2 or
  455. (not delete and (forum_role['can_delete_posts'] == 1 or
  456. (post.user_id == user.pk and forum_role['can_soft_delete_own_posts'])))):
  457. raise ACLError403(_("You don't have permission to delete this post."))
  458. if post.deleted and not delete:
  459. raise ACLError403(_("This post is already deleted."))
  460. except KeyError:
  461. raise ACLError403(_("You don't have permission to delete this post."))
  462. def can_see_deleted_threads(self, forum):
  463. try:
  464. forum_role = self.get_role(forum)
  465. return forum_role['can_delete_threads']
  466. except KeyError:
  467. return False
  468. def can_see_deleted_posts(self, forum):
  469. try:
  470. forum_role = self.get_role(forum)
  471. return forum_role['can_delete_posts']
  472. except KeyError:
  473. return False
  474. def allow_deleted_post_view(self, forum):
  475. try:
  476. forum_role = self.get_role(forum)
  477. if not forum_role['can_delete_posts']:
  478. raise ACLError404()
  479. except KeyError:
  480. raise ACLError404()
  481. def can_upvote_posts(self, forum):
  482. try:
  483. forum_role = self.get_role(forum)
  484. return forum_role['can_upvote_posts']
  485. except KeyError:
  486. return False
  487. def can_downvote_posts(self, forum):
  488. try:
  489. forum_role = self.get_role(forum)
  490. return forum_role['can_downvote_posts']
  491. except KeyError:
  492. return False
  493. def can_see_post_score(self, forum):
  494. try:
  495. forum_role = self.get_role(forum)
  496. return forum_role['can_see_posts_scores']
  497. except KeyError:
  498. return False
  499. def can_see_post_votes(self, forum):
  500. try:
  501. forum_role = self.get_role(forum)
  502. return forum_role['can_see_votes']
  503. except KeyError:
  504. return False
  505. def allow_post_upvote(self, forum):
  506. try:
  507. forum_role = self.get_role(forum)
  508. if not forum_role['can_upvote_posts']:
  509. raise ACLError403(_("You cannot upvote posts in this forum."))
  510. except KeyError:
  511. raise ACLError403(_("You cannot upvote posts in this forum."))
  512. def allow_post_downvote(self, forum):
  513. try:
  514. forum_role = self.get_role(forum)
  515. if not forum_role['can_downvote_posts']:
  516. raise ACLError403(_("You cannot downvote posts in this forum."))
  517. except KeyError:
  518. raise ACLError403(_("You cannot downvote posts in this forum."))
  519. def allow_post_votes_view(self, forum):
  520. try:
  521. forum_role = self.get_role(forum)
  522. if not forum_role['can_see_votes']:
  523. raise ACLError403(_("You don't have permission to see who voted on this post."))
  524. except KeyError:
  525. raise ACLError403(_("You don't have permission to see who voted on this post."))
  526. def can_make_polls(self, forum):
  527. try:
  528. forum_role = self.get_role(forum)
  529. return forum_role['can_make_polls']
  530. except KeyError:
  531. return False
  532. def can_vote_in_polls(self, forum, thread, poll):
  533. try:
  534. forum_role = self.get_role(forum)
  535. return (forum_role['can_vote_in_polls']
  536. and not forum.closed
  537. and not thread.closed
  538. and not thread.deleted
  539. and not poll.over
  540. and (poll.vote_changing or not poll.user_votes))
  541. except KeyError:
  542. return False
  543. def allow_vote_in_polls(self, forum, thread, poll):
  544. try:
  545. forum_role = self.get_role(forum)
  546. if not forum_role['can_vote_in_polls']:
  547. raise ACLError403(_("You don't have permission to vote polls."))
  548. if poll.over:
  549. raise ACLError403(_("This poll has ended."))
  550. if forum.closed or thread.closed:
  551. raise ACLError403(_("This poll has been closed."))
  552. if thread.deleted:
  553. raise ACLError403(_("This poll's thread has been deleted."))
  554. if poll.user_votes and not poll.vote_changing:
  555. raise ACLError403(_("You have already voted in this poll."))
  556. except KeyError:
  557. raise ACLError403(_("You don't have permission to vote in this poll."))
  558. def can_see_poll_votes(self, forum, poll):
  559. try:
  560. forum_role = self.get_role(forum)
  561. return forum_role['can_see_poll_votes'] or poll.public
  562. except KeyError:
  563. return False
  564. def allow_see_poll_votes(self, forum, poll):
  565. try:
  566. forum_role = self.get_role(forum)
  567. if not forum_role['can_see_poll_votes'] and not poll.public:
  568. raise ACLError403(_("You don't have permission to see votes in this poll."))
  569. except KeyError:
  570. raise ACLError403(_("You don't have permission to see votes in this poll."))
  571. def can_edit_poll(self, forum, poll):
  572. try:
  573. if poll.over:
  574. return False
  575. forum_role = self.get_role(forum)
  576. if forum_role['can_edit_polls'] == 0:
  577. return True
  578. edition_expires = poll.start_date + timedelta(minutes=forum_role['can_edit_polls'])
  579. return timezone.now() <= edition_expires
  580. except KeyError:
  581. return False
  582. def can_delete_poll(self, forum, poll):
  583. try:
  584. forum_role = self.get_role(forum)
  585. if not forum_role['can_delete_polls']:
  586. return False
  587. if forum_role['can_edit_threads_posts']:
  588. return True
  589. if poll.over:
  590. return False
  591. if forum_role['can_delete_polls'] == 1:
  592. edition_expires = poll.start_date + timedelta(minutes=forum_role['can_edit_polls'])
  593. return timezone.now() <= edition_expires
  594. return True
  595. except KeyError:
  596. return False
  597. def can_see_all_checkpoints(self, forum):
  598. try:
  599. forum_role = self.get_role(forum)
  600. return forum_role['can_see_deleted_checkpoints']
  601. except KeyError:
  602. raise False
  603. def can_delete_checkpoint(self, forum):
  604. try:
  605. forum_role = self.get_role(forum)
  606. return forum_role['can_delete_checkpoints']
  607. except KeyError:
  608. raise False
  609. def allow_checkpoint_view(self, forum, checkpoint):
  610. if checkpoint.deleted:
  611. try:
  612. forum_role = self.get_role(forum)
  613. if not forum_role['can_see_deleted_checkpoints']:
  614. raise ACLError403(_("Selected checkpoint could not be found."))
  615. except KeyError:
  616. raise ACLError403(_("Selected checkpoint could not be found."))
  617. def allow_checkpoint_hide(self, forum):
  618. try:
  619. forum_role = self.get_role(forum)
  620. if not forum_role['can_delete_checkpoints']:
  621. raise ACLError403(_("You cannot hide checkpoints!"))
  622. except KeyError:
  623. raise ACLError403(_("You cannot hide checkpoints!"))
  624. def allow_checkpoint_delete(self, forum):
  625. try:
  626. forum_role = self.get_role(forum)
  627. if forum_role['can_delete_checkpoints'] != 2:
  628. raise ACLError403(_("You cannot delete checkpoints!"))
  629. except KeyError:
  630. raise ACLError403(_("You cannot delete checkpoints!"))
  631. def allow_checkpoint_show(self, forum):
  632. try:
  633. forum_role = self.get_role(forum)
  634. if not forum_role['can_delete_checkpoints']:
  635. raise ACLError403(_("You cannot show checkpoints!"))
  636. except KeyError:
  637. raise ACLError403(_("You cannot show checkpoints!"))
  638. def build_forums(acl, perms, forums, forum_roles):
  639. acl.threads = ThreadsACL()
  640. for forum in forums:
  641. forum_role = {
  642. 'can_read_threads': 0,
  643. 'can_start_threads': 0,
  644. 'can_edit_own_threads': False,
  645. 'can_soft_delete_own_threads': False,
  646. 'can_write_posts': 0,
  647. 'can_edit_own_posts': False,
  648. 'can_soft_delete_own_posts': False,
  649. 'can_upvote_posts': False,
  650. 'can_downvote_posts': False,
  651. 'can_see_posts_scores': 0,
  652. 'can_see_votes': False,
  653. 'can_make_polls': False,
  654. 'can_vote_in_polls': False,
  655. 'can_see_attachments': False,
  656. 'can_upload_attachments': False,
  657. 'can_download_attachments': False,
  658. 'attachment_size': 100,
  659. 'attachment_limit': 3,
  660. 'can_approve': False,
  661. 'can_edit_prefixes': False,
  662. 'can_see_changelog': False,
  663. 'can_pin_threads': 0,
  664. 'can_edit_threads_posts': False,
  665. 'can_move_threads_posts': False,
  666. 'can_close_threads': False,
  667. 'can_protect_posts': False,
  668. 'can_delete_threads': 0,
  669. 'can_delete_posts': 0,
  670. 'can_see_poll_votes': False,
  671. 'can_edit_polls': 15,
  672. 'can_delete_polls': 0,
  673. 'can_delete_attachments': False,
  674. 'can_see_deleted_checkpoints': False,
  675. 'can_delete_checkpoints': 0,
  676. }
  677. for perm in perms:
  678. try:
  679. role = forum_roles[perm['forums'][forum.pk]]
  680. for p in forum_role:
  681. try:
  682. if p == 'can_edit_polls':
  683. if role[p] < forum_role[p]:
  684. forum_role[p] = role[p]
  685. elif p in ['attachment_size', 'attachment_limit'] and role[p] == 0:
  686. forum_role[p] = 0
  687. elif role[p] > forum_role[p]:
  688. forum_role[p] = role[p]
  689. except KeyError:
  690. pass
  691. except KeyError:
  692. pass
  693. acl.threads.acl[forum.pk] = forum_role