from django import forms from django.core.exceptions import PermissionDenied from django.db.models import Q from django.http import Http404 from django.utils import timezone from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ungettext from misago.acl import add_acl, algebra from misago.acl.decorators import return_boolean from misago.acl.models import Role from misago.categories.models import Category, CategoryRole from misago.categories.permissions import get_categories_roles from misago.core.forms import YesNoSwitch from misago.threads.models import Post, Thread __all__ = [ 'allow_see_thread', 'can_see_thread', 'allow_start_thread', 'can_start_thread', 'allow_reply_thread', 'can_reply_thread', 'allow_edit_thread', 'can_edit_thread', 'allow_see_post', 'can_see_post', 'allow_edit_post', 'can_edit_post', 'allow_unhide_post', 'can_unhide_post', 'allow_hide_post', 'can_hide_post', 'allow_delete_post', 'can_delete_post', 'allow_protect_post', 'can_protect_post', 'allow_approve_post', 'can_approve_post', 'allow_move_post', 'can_move_post', 'allow_delete_event', 'can_delete_event', 'exclude_invisible_threads', 'exclude_invisible_posts', ] """ Admin Permissions Forms """ class RolePermissionsForm(forms.Form): legend = _("Threads") can_see_unapproved_content_lists = YesNoSwitch( label=_("Can see unapproved content list"), help_text=_( 'Allows access to "unapproved" tab on threads lists for ' "easy listing of threads that are unapproved or contain " "unapproved posts. Despite the tab being available on all " "threads lists, it will only display threads belonging to " "categories in which the user has permission to approve " "content." ), ) can_see_reported_content_lists = YesNoSwitch( label=_("Can see reported content list"), help_text=_( 'Allows access to "reported" tab on threads lists for ' "easy listing of threads that contain reported posts. " "Despite the tab being available on all categories " "threads lists, it will only display threads belonging to " "categories in which the user has permission to see posts " "reports." ), ) can_omit_flood_protection = YesNoSwitch( label=_("Can omit flood protection"), help_text=_("Allows posting more frequently than flood protection would."), ) class CategoryPermissionsForm(forms.Form): legend = _("Threads") can_see_all_threads = forms.TypedChoiceField( label=_("Can see threads"), coerce=int, initial=0, choices=((0, _("Started threads")), (1, _("All threads")), ), ) can_start_threads = YesNoSwitch(label=_("Can start threads")) can_reply_threads = YesNoSwitch(label=_("Can reply to threads")) can_edit_threads = forms.TypedChoiceField( label=_("Can edit threads"), coerce=int, initial=0, choices=((0, _("No")), (1, _("Own threads")), (2, _("All threads")), ), ) can_hide_own_threads = forms.TypedChoiceField( label=_("Can hide own threads"), help_text=_( "Only threads started within time limit and " "with no replies can be hidden." ), coerce=int, initial=0, choices=((0, _("No")), (1, _("Hide threads")), (2, _("Delete threads")), ), ) thread_edit_time = forms.IntegerField( label=_("Time limit for own threads edits, in minutes"), help_text=_("Enter 0 to don't limit time for editing own threads."), initial=0, min_value=0, ) can_hide_threads = forms.TypedChoiceField( label=_("Can hide all threads"), coerce=int, initial=0, choices=((0, _("No")), (1, _("Hide threads")), (2, _("Delete threads")), ), ) can_pin_threads = forms.TypedChoiceField( label=_("Can pin threads"), coerce=int, initial=0, choices=((0, _("No")), (1, _("Locally")), (2, _("Globally")), ), ) can_close_threads = YesNoSwitch(label=_("Can close threads")) can_move_threads = YesNoSwitch(label=_("Can move threads")) can_merge_threads = YesNoSwitch(label=_("Can merge threads")) can_edit_posts = forms.TypedChoiceField( label=_("Can edit posts"), coerce=int, initial=0, choices=((0, _("No")), (1, _("Own posts")), (2, _("All posts")), ), ) can_hide_own_posts = forms.TypedChoiceField( label=_("Can hide own posts"), help_text=_("Only last posts to thread made within edit time limit can be hidden."), coerce=int, initial=0, choices=((0, _("No")), (1, _("Hide posts")), (2, _("Delete posts")), ), ) post_edit_time = forms.IntegerField( label=_("Time limit for own post edits, in minutes"), help_text=_("Enter 0 to don't limit time for editing own posts."), initial=0, min_value=0, ) can_hide_posts = forms.TypedChoiceField( label=_("Can hide all posts"), coerce=int, initial=0, choices=((0, _("No")), (1, _("Hide posts")), (2, _("Delete posts")), ), ) can_see_posts_likes = forms.TypedChoiceField( label=_("Can see posts likes"), coerce=int, initial=0, choices=((0, _("No")), (1, _("Number only")), (2, _("Number and list of likers")), ), ) can_like_posts = YesNoSwitch( label=_("Can like posts"), help_text=_("Only users with this permission to see likes can like posts."), ) can_protect_posts = YesNoSwitch( label=_("Can protect posts"), help_text=_("Only users with this permission can edit protected posts."), ) can_move_posts = YesNoSwitch( label=_("Can move posts"), help_text=_("Will be able to move posts to other threads.") ) can_merge_posts = YesNoSwitch(label=_("Can merge posts")) can_approve_content = YesNoSwitch( label=_("Can approve content"), help_text=_("Will be able to see and approve unapproved content."), ) can_report_content = YesNoSwitch(label=_("Can report posts")) can_see_reports = YesNoSwitch(label=_("Can see reports")) can_hide_events = forms.TypedChoiceField( label=_("Can hide events"), coerce=int, initial=0, choices=((0, _("No")), (1, _("Hide events")), (2, _("Delete events")), ), ) def change_permissions_form(role): if isinstance(role, Role) and role.special_role != 'anonymous': return RolePermissionsForm elif isinstance(role, CategoryRole): return CategoryPermissionsForm else: return None """ ACL Builder """ def build_acl(acl, roles, key_name): acl.update({ 'can_see_unapproved_content_lists': False, 'can_see_reported_content_lists': False, 'can_omit_flood_protection': False, 'can_approve_content': [], 'can_see_reports': [], }) acl = algebra.sum_acls( acl, roles=roles, key=key_name, can_see_unapproved_content_lists=algebra.greater, can_see_reported_content_lists=algebra.greater, can_omit_flood_protection=algebra.greater ) categories_roles = get_categories_roles(roles) categories = list(Category.objects.all_categories(include_root=True)) for category in categories: category_acl = acl['categories'].get(category.pk, {'can_browse': 0}) if category_acl['can_browse']: category_acl = acl['categories'][category.pk] = build_category_acl( category_acl, category, categories_roles, key_name ) if category_acl.get('can_approve_content'): acl['can_approve_content'].append(category.pk) if category_acl.get('can_see_reports'): acl['can_see_reports'].append(category.pk) return acl def build_category_acl(acl, category, categories_roles, key_name): category_roles = categories_roles.get(category.pk, []) final_acl = { 'can_see_all_threads': 0, 'can_start_threads': 0, 'can_reply_threads': 0, 'can_edit_threads': 0, 'can_edit_posts': 0, 'can_hide_own_threads': 0, 'can_hide_own_posts': 0, 'thread_edit_time': 0, 'post_edit_time': 0, 'can_hide_threads': 0, 'can_hide_posts': 0, 'can_protect_posts': 0, 'can_move_posts': 0, 'can_merge_posts': 0, 'can_pin_threads': 0, 'can_close_threads': 0, 'can_move_threads': 0, 'can_merge_threads': 0, 'can_approve_content': 0, 'can_report_content': 0, 'can_see_reports': 0, 'can_see_posts_likes': 0, 'can_like_posts': 0, 'can_hide_events': 0, } final_acl.update(acl) algebra.sum_acls( final_acl, roles=category_roles, key=key_name, can_see_all_threads=algebra.greater, can_start_threads=algebra.greater, can_reply_threads=algebra.greater, can_edit_threads=algebra.greater, can_edit_posts=algebra.greater, can_hide_threads=algebra.greater, can_hide_posts=algebra.greater, can_hide_own_threads=algebra.greater, can_hide_own_posts=algebra.greater, thread_edit_time=algebra.greater_or_zero, post_edit_time=algebra.greater_or_zero, can_protect_posts=algebra.greater, can_move_posts=algebra.greater, can_merge_posts=algebra.greater, can_pin_threads=algebra.greater, can_close_threads=algebra.greater, can_move_threads=algebra.greater, can_merge_threads=algebra.greater, can_approve_content=algebra.greater, can_report_content=algebra.greater, can_see_reports=algebra.greater, can_see_posts_likes=algebra.greater, can_like_posts=algebra.greater, can_hide_events=algebra.greater, ) return final_acl """ ACL's for targets """ def add_acl_to_category(user, category): category_acl = user.acl_cache['categories'].get(category.pk, {}) category.acl.update({ 'can_see_all_threads': 0, 'can_see_own_threads': 0, 'can_start_threads': 0, 'can_reply_threads': 0, 'can_edit_threads': 0, 'can_edit_posts': 0, 'can_hide_own_threads': 0, 'can_hide_own_posts': 0, 'thread_edit_time': 0, 'post_edit_time': 0, 'can_hide_threads': 0, 'can_hide_posts': 0, 'can_protect_posts': 0, 'can_move_posts': 0, 'can_merge_posts': 0, 'can_pin_threads': 0, 'can_close_threads': 0, 'can_move_threads': 0, 'can_merge_threads': 0, 'can_approve_content': 0, 'can_report_content': 0, 'can_see_reports': 0, 'can_see_posts_likes': 0, 'can_like_posts': 0, 'can_hide_events': 0, }) algebra.sum_acls( category.acl, acls=[category_acl], can_see_all_threads=algebra.greater, can_see_posts_likes=algebra.greater, ) if user.is_authenticated: algebra.sum_acls( category.acl, acls=[category_acl], can_start_threads=algebra.greater, can_reply_threads=algebra.greater, can_edit_threads=algebra.greater, can_edit_posts=algebra.greater, can_hide_threads=algebra.greater, can_hide_posts=algebra.greater, can_hide_own_threads=algebra.greater, can_hide_own_posts=algebra.greater, thread_edit_time=algebra.greater_or_zero, post_edit_time=algebra.greater_or_zero, can_protect_posts=algebra.greater, can_move_posts=algebra.greater, can_merge_posts=algebra.greater, can_pin_threads=algebra.greater, can_close_threads=algebra.greater, can_move_threads=algebra.greater, can_merge_threads=algebra.greater, can_approve_content=algebra.greater, can_report_content=algebra.greater, can_see_reports=algebra.greater, can_like_posts=algebra.greater, can_hide_events=algebra.greater, ) category.acl['can_see_own_threads'] = not category.acl['can_see_all_threads'] def add_acl_to_thread(user, thread): category_acl = user.acl_cache['categories'].get(thread.category_id, {}) thread.acl.update({ 'can_reply': can_reply_thread(user, thread), 'can_edit': can_edit_thread(user, thread), 'can_hide': category_acl.get('can_hide_threads', False), 'can_pin': 0, 'can_close': category_acl.get('can_close_threads', False), 'can_move': False, 'can_merge': False, 'can_move_posts': False, 'can_merge_posts': False, 'can_approve': category_acl.get('can_approve_content', False), 'can_see_reports': category_acl.get('can_see_reports', False), }) if not category_acl.get('can_close_threads'): thread_is_protected = thread.is_closed or thread.category.is_closed else: thread_is_protected = False if (can_change_owned_thread(user, thread) and not thread_is_protected and not thread.replies and not thread.acl['can_hide']): can_hide_thread = category_acl.get('can_hide_own_threads') thread.acl['can_hide'] = can_hide_thread if not thread_is_protected: thread.acl['can_pin'] = category_acl.get('can_pin_threads', 0) thread.acl['can_move'] = category_acl.get('can_move_threads', False) thread.acl['can_merge'] = category_acl.get('can_merge_threads', False) thread.acl['can_move_posts'] = category_acl.get('can_move_posts', False) thread.acl['can_merge_posts'] = category_acl.get('can_merge_posts', False) def add_acl_to_post(user, post): if post.is_event: add_acl_to_event(user, post) else: add_acl_to_reply(user, post) def add_acl_to_event(user, event): if user.is_authenticated: category_acl = user.acl_cache['categories'].get(event.category_id, {}) can_hide_events = category_acl.get('can_hide_events', 0) else: can_hide_events = 0 event.acl.update({ 'can_see_hidden': can_hide_events > 0, 'can_hide': can_hide_events > 0, 'can_delete': can_hide_events == 2, }) def add_acl_to_reply(user, post): category_acl = user.acl_cache['categories'].get(post.category_id, {}) post.acl.update({ 'can_reply': can_reply_thread(user, post.thread), 'can_edit': can_edit_post(user, post), 'can_see_hidden': post.is_first_post or category_acl.get('can_hide_posts'), 'can_unhide': can_unhide_post(user, post), 'can_hide': can_hide_post(user, post), 'can_delete': can_delete_post(user, post), 'can_protect': can_protect_post(user, post), 'can_approve': can_approve_post(user, post), 'can_move': can_move_post(user, post), 'can_report': category_acl.get('can_report_content', False), 'can_see_reports': category_acl.get('can_see_reports', False), 'can_see_likes': category_acl.get('can_see_posts_likes', 0), 'can_like': False, }) if not post.acl['can_see_hidden']: post.acl['can_see_hidden'] = post.id == post.thread.first_post_id if user.is_authenticated and post.acl['can_see_likes']: post.acl['can_like'] = category_acl.get('can_like_posts', False) def register_with(registry): registry.acl_annotator(Category, add_acl_to_category) registry.acl_annotator(Thread, add_acl_to_thread) registry.acl_annotator(Post, add_acl_to_post) """ ACL tests """ def allow_see_thread(user, target): category_acl = user.acl_cache['categories'].get( target.category_id, { 'can_see': False, 'can_browse': False, } ) if not (category_acl['can_see'] and category_acl['can_browse']): raise Http404() if target.is_hidden and (user.is_anonymous or not category_acl['can_hide_threads']): raise Http404() if user.is_anonymous or user.pk != target.starter_id: if not category_acl['can_see_all_threads']: raise Http404() if target.is_unapproved and not category_acl['can_approve_content']: raise Http404() can_see_thread = return_boolean(allow_see_thread) def allow_start_thread(user, target): if user.is_anonymous: raise PermissionDenied(_("You have to sign in to start threads.")) category_acl = user.acl_cache['categories'].get( target.pk, { 'can_close_threads': False, 'can_start_threads': False, } ) if target.is_closed and not category_acl['can_close_threads']: raise PermissionDenied(_("This category is closed. You can't start new threads in it.")) if not category_acl['can_start_threads']: raise PermissionDenied( _("You don't have permission to start new threads in this category.") ) can_start_thread = return_boolean(allow_start_thread) def allow_reply_thread(user, target): if user.is_anonymous: raise PermissionDenied(_("You have to sign in to reply threads.")) category_acl = user.acl_cache['categories'].get( target.category_id, { 'can_close_threads': False, 'can_reply_threads': False, } ) if not category_acl['can_close_threads']: if target.category.is_closed: raise PermissionDenied(_("This category is closed. You can't reply to threads in it.")) if target.is_closed: raise PermissionDenied(_("You can't reply to closed threads in this category.")) if not category_acl['can_reply_threads']: raise PermissionDenied(_("You can't reply to threads in this category.")) can_reply_thread = return_boolean(allow_reply_thread) def allow_edit_thread(user, target): if user.is_anonymous: raise PermissionDenied(_("You have to sign in to edit threads.")) category_acl = user.acl_cache['categories'].get( target.category_id, {'can_edit_threads': False} ) if not category_acl['can_edit_threads']: raise PermissionDenied(_("You can't edit threads in this category.")) if category_acl['can_edit_threads'] == 1: if target.starter_id != user.pk: raise PermissionDenied(_("You can't edit other users threads in this category.")) if not category_acl['can_close_threads']: if target.category.is_closed: raise PermissionDenied(_("This category is closed. You can't edit threads in it.")) if target.is_closed: raise PermissionDenied(_("You can't edit closed threads in this category.")) if not has_time_to_edit_thread(user, target): message = ungettext( "You can't edit threads that are older than %(minutes)s minute.", "You can't edit threads that are older than %(minutes)s minutes.", category_acl['thread_edit_time'] ) raise PermissionDenied(message % {'minutes': category_acl['thread_edit_time']}) can_edit_thread = return_boolean(allow_edit_thread) def allow_see_post(user, target): category_acl = user.acl_cache['categories'].get( target.category_id, { 'can_approve_content': False, 'can_hide_events': False, } ) if not target.is_event and target.is_unapproved: if user.is_anonymous: raise Http404() if not category_acl['can_approve_content'] and user.id != target.poster_id: raise Http404() if target.is_event and target.is_hidden and not category_acl['can_hide_events']: raise Http404() can_see_post = return_boolean(allow_see_post) def allow_edit_post(user, target): if user.is_anonymous: raise PermissionDenied(_("You have to sign in to edit posts.")) if target.is_event: raise PermissionDenied(_("Events can't be edited.")) category_acl = user.acl_cache['categories'].get(target.category_id, {'can_edit_posts': False}) if not category_acl['can_edit_posts']: raise PermissionDenied(_("You can't edit posts in this category.")) if not category_acl['can_close_threads']: if target.category.is_closed: raise PermissionDenied(_("This category is closed. You can't edit posts in it.")) if target.thread.is_closed: raise PermissionDenied(_("This thread is closed. You can't edit posts in it.")) if target.is_hidden and not target.is_first_post and not category_acl['can_hide_posts']: raise PermissionDenied(_("This post is hidden, you can't edit it.")) if category_acl['can_edit_posts'] == 1: if target.poster_id != user.pk: raise PermissionDenied(_("You can't edit other users posts in this category.")) if target.is_protected and not category_acl['can_protect_posts']: raise PermissionDenied(_("This post is protected. You can't edit it.")) if not has_time_to_edit_post(user, target): message = ungettext( "You can't edit posts that are older than %(minutes)s minute.", "You can't edit posts that are older than %(minutes)s minutes.", category_acl['post_edit_time'], ) raise PermissionDenied(message % {'minutes': category_acl['post_edit_time']}) can_edit_post = return_boolean(allow_edit_post) def allow_unhide_post(user, target): if user.is_anonymous: raise PermissionDenied(_("You have to sign in to reveal posts.")) category_acl = user.acl_cache['categories'].get( target.category_id, { 'can_hide_posts': 0, 'can_hide_own_posts': 0, } ) if not category_acl['can_hide_posts']: if not category_acl['can_hide_own_posts']: raise PermissionDenied(_("You can't reveal posts in this category.")) if user.id != target.poster_id: raise PermissionDenied(_("You can't reveal other users posts in this category.")) if not category_acl['can_close_threads']: if target.category.is_closed: raise PermissionDenied(_("This category is closed. You can't reveal posts in it.")) if target.thread.is_closed: raise PermissionDenied(_("This thread is closed. You can't reveal posts in it.")) if target.is_protected and not category_acl['can_protect_posts']: raise PermissionDenied(_("This post is protected. You can't reveal it.")) if not has_time_to_edit_post(user, target): message = ungettext( "You can't reveal posts that are older than %(minutes)s minute.", "You can't reveal posts that are older than %(minutes)s minutes.", category_acl['post_edit_time'], ) raise PermissionDenied(message % {'minutes': category_acl['post_edit_time']}) if target.is_first_post: raise PermissionDenied(_("You can't reveal thread's first post.")) can_unhide_post = return_boolean(allow_unhide_post) def allow_hide_post(user, target): if user.is_anonymous: raise PermissionDenied(_("You have to sign in to hide posts.")) category_acl = user.acl_cache['categories'].get( target.category_id, { 'can_hide_posts': 0, 'can_hide_own_posts': 0, } ) if not category_acl['can_hide_posts']: if not category_acl['can_hide_own_posts']: raise PermissionDenied(_("You can't hide posts in this category.")) if user.id != target.poster_id: raise PermissionDenied(_("You can't hide other users posts in this category.")) if not category_acl['can_close_threads']: if target.category.is_closed: raise PermissionDenied(_("This category is closed. You can't hide posts in it.")) if target.thread.is_closed: raise PermissionDenied(_("This thread is closed. You can't hide posts in it.")) if target.is_protected and not category_acl['can_protect_posts']: raise PermissionDenied(_("This post is protected. You can't hide it.")) if not has_time_to_edit_post(user, target): message = ungettext( "You can't hide posts that are older than %(minutes)s minute.", "You can't hide posts that are older than %(minutes)s minutes.", category_acl['post_edit_time'], ) raise PermissionDenied(message % {'minutes': category_acl['post_edit_time']}) if target.is_first_post: raise PermissionDenied(_("You can't hide thread's first post.")) can_hide_post = return_boolean(allow_hide_post) def allow_delete_post(user, target): if user.is_anonymous: raise PermissionDenied(_("You have to sign in to delete posts.")) category_acl = user.acl_cache['categories'].get( target.category_id, { 'can_hide_posts': 0, 'can_hide_own_posts': 0, } ) if category_acl['can_hide_posts'] != 2: if category_acl['can_hide_own_posts'] != 2: raise PermissionDenied(_("You can't delete posts in this category.")) if user.id != target.poster_id: raise PermissionDenied(_("You can't delete other users posts in this category.")) if not category_acl['can_close_threads']: if target.category.is_closed: raise PermissionDenied(_("This category is closed. You can't delete posts in it.")) if target.thread.is_closed: raise PermissionDenied(_("This thread is closed. You can't delete posts in it.")) if target.is_protected and not category_acl['can_protect_posts']: raise PermissionDenied(_("This post is protected. You can't delete it.")) if not has_time_to_edit_post(user, target): message = ungettext( "You can't delete posts that are older than %(minutes)s minute.", "You can't delete posts that are older than %(minutes)s minutes.", category_acl['post_edit_time'], ) raise PermissionDenied(message % {'minutes': category_acl['post_edit_time']}) if target.is_first_post: raise PermissionDenied(_("You can't delete thread's first post.")) can_delete_post = return_boolean(allow_delete_post) def allow_protect_post(user, target): if user.is_anonymous: raise PermissionDenied(_("You have to sign in to protect posts.")) category_acl = user.acl_cache['categories'].get( target.category_id, {'can_protect_posts': False} ) if not category_acl['can_protect_posts']: raise PermissionDenied(_("You can't protect posts in this category.")) if not can_edit_post(user, target): raise PermissionDenied(_("You can't protect posts you can't edit.")) can_protect_post = return_boolean(allow_protect_post) def allow_approve_post(user, target): if user.is_anonymous: raise PermissionDenied(_("You have to sign in to approve posts.")) category_acl = user.acl_cache['categories'].get( target.category_id, {'can_approve_content': False} ) if not category_acl['can_approve_content']: raise PermissionDenied(_("You can't approve posts in this category.")) if target.is_first_post: raise PermissionDenied(_("You can't approve thread's first post.")) if not target.is_first_post and not category_acl['can_hide_posts'] and target.is_hidden: raise PermissionDenied(_("You can't approve posts the content you can't see.")) can_approve_post = return_boolean(allow_approve_post) def allow_move_post(user, target): if user.is_anonymous: raise PermissionDenied(_("You have to sign in to move posts.")) category_acl = user.acl_cache['categories'].get(target.category_id, {'can_move_posts': False}) if not category_acl['can_move_posts']: raise PermissionDenied(_("You can't move posts in this category.")) if target.is_event: raise PermissionDenied(_("Events can't be moved.")) if target.is_first_post: raise PermissionDenied(_("You can't move thread's first post.")) if not category_acl['can_hide_posts'] and target.is_hidden: raise PermissionDenied(_("You can't move posts the content you can't see.")) can_move_post = return_boolean(allow_move_post) def allow_delete_event(user, target): if user.is_anonymous: raise PermissionDenied(_("You have to sign in to delete events.")) category_acl = user.acl_cache['categories'].get(target.category_id) if not category_acl or category_acl['can_hide_events'] != 2: raise PermissionDenied(_("You can't delete events in this category.")) can_delete_event = return_boolean(allow_delete_event) """ Permission check helpers """ def can_change_owned_thread(user, target): if user.is_anonymous or user.pk != target.starter_id: return False if target.category.is_closed or target.is_closed: return False return has_time_to_edit_thread(user, target) def has_time_to_edit_thread(user, target): edit_time = user.acl_cache['categories'].get(target.category_id, {}).get('thread_edit_time', 0) if edit_time: diff = timezone.now() - target.started_on diff_minutes = int(diff.total_seconds() / 60) return diff_minutes < edit_time else: return True def has_time_to_edit_post(user, target): edit_time = user.acl_cache['categories'].get(target.category_id, {}).get('post_edit_time', 0) if edit_time: diff = timezone.now() - target.posted_on diff_minutes = int(diff.total_seconds() / 60) return diff_minutes < edit_time else: return True """ Queryset helpers """ def exclude_invisible_threads(user, categories, queryset): show_all = [] show_accepted_visible = [] show_accepted = [] show_visible = [] show_owned = [] show_owned_visible = [] for category in categories: add_acl(user, category) if not (category.acl['can_see'] and category.acl['can_browse']): continue can_hide = category.acl['can_hide_threads'] if category.acl['can_see_all_threads']: can_mod = category.acl['can_approve_content'] if can_mod and can_hide: show_all.append(category) elif user.is_authenticated: if not can_mod and not can_hide: show_accepted_visible.append(category) elif not can_mod: show_accepted.append(category) elif not can_hide: show_visible.append(category) else: show_accepted_visible.append(category) elif user.is_authenticated: if can_hide: show_owned.append(category) else: show_owned_visible.append(category) conditions = None if show_all: conditions = Q(category__in=show_all) if show_accepted_visible: if user.is_authenticated: condition = Q( Q(starter=user) | Q(is_unapproved=False), category__in=show_accepted_visible, is_hidden=False, ) else: condition = Q( category__in=show_accepted_visible, is_hidden=False, is_unapproved=False, ) if conditions: conditions = conditions | condition else: conditions = condition if show_accepted: condition = Q( Q(starter=user) | Q(is_unapproved=False), category__in=show_accepted, ) if conditions: conditions = conditions | condition else: conditions = condition if show_visible: condition = Q(category__in=show_visible, is_hidden=False) if conditions: conditions = conditions | condition else: conditions = condition if show_owned: condition = Q(category__in=show_owned, starter=user) if conditions: conditions = conditions | condition else: conditions = condition if show_owned_visible: condition = Q( category__in=show_owned_visible, starter=user, is_hidden=False, ) if conditions: conditions = conditions | condition else: conditions = condition if conditions: return queryset.filter(conditions) else: return Thread.objects.none() def exclude_invisible_posts(user, category, queryset): if not category.acl['can_approve_content']: if user.is_authenticated: queryset = queryset.filter(Q(is_unapproved=False) | Q(poster=user)) else: queryset = queryset.exclude(is_unapproved=True) if not category.acl['can_hide_events']: queryset = queryset.exclude(is_event=True, is_hidden=True) return queryset