threads.py 40 KB

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