Ejemplo n.º 1
0
    def dispatch(self, request, *args, **kwargs):
        relations = ['forum']
        thread = self.fetch_thread(request, select_related=relations, **kwargs)
        forum = thread.forum

        self.check_forum_permissions(request, forum)
        self.check_thread_permissions(request, thread)

        self.allow_action(thread)

        if not request.is_ajax():
            response = render(request, 'misago/errorpages/wrong_way.html')
            response.status_code = 405
            return response

        queryset = exclude_invisible_posts(
            thread.post_set, request.user, forum)
        queryset = self.filter_posts_queryset(queryset)
        final_queryset = queryset.select_related('poster').order_by('-id')[:15]

        return self.render(request, {
            'forum': forum,
            'thread': thread,

            'posts_count': queryset.count(),
            'posts': final_queryset.iterator()
        })
Ejemplo n.º 2
0
def clean_posts_for_split(request, thread):
    posts_ids = clean_ids_list(
        request.data.get('posts', []),
        _("One or more post ids received were invalid."),
    )

    if not posts_ids:
        raise PermissionDenied(_("You have to specify at least one post to split."))
    elif len(posts_ids) > SPLIT_LIMIT:
        message = ungettext(
            "No more than %(limit)s post can be split at single time.",
            "No more than %(limit)s posts can be split at single time.",
            SPLIT_LIMIT,
        )
        raise PermissionDenied(message % {'limit': SPLIT_LIMIT})

    posts_queryset = exclude_invisible_posts(request.user, thread.category, thread.post_set)
    posts_queryset = posts_queryset.filter(id__in=posts_ids).order_by('id')

    posts = []
    for post in posts_queryset:
        post.category = thread.category
        post.thread = thread

        allow_split_post(request.user, post)

        posts.append(post)

    if len(posts) != len(posts_ids):
        raise PermissionDenied(_("One or more posts to split could not be found."))

    return posts
Ejemplo n.º 3
0
    def validate_posts(self, data):
        data = list(set(data))
        if len(data) > POSTS_MOVE_LIMIT:
            message = ungettext(
                "No more than %(limit)s post can be moved at single time.",
                "No more than %(limit)s posts can be moved at single time.",
                POSTS_MOVE_LIMIT,
            )
            raise serializers.ValidationError(message % {'limit': POSTS_MOVE_LIMIT})

        request = self.context['request']
        thread = self.context['thread']

        posts_queryset = exclude_invisible_posts(request.user, thread.category, thread.post_set)
        posts_queryset = posts_queryset.filter(id__in=data).order_by('id')

        posts = []
        for post in posts_queryset:
            post.category = thread.category
            post.thread = thread

            try:
                allow_move_post(request.user, post)
                posts.append(post)
            except PermissionDenied as e:
                raise serializers.ValidationError(six.text_type(e))

        if len(posts) != len(data):
            raise serializers.ValidationError(_("One or more posts to move could not be found."))

        self.posts_cache = posts

        return data
Ejemplo n.º 4
0
    def real_dispatch(self, request, post):
        post_id = post.id

        permissions.allow_delete_post(request.user, post)
        moderation.delete_post(request.user, post)

        post.thread.synchronize()
        post.thread.save()
        post.forum.synchronize()
        post.forum.save()

        posts_queryset = exclude_invisible_posts(post.thread.post_set,
                                                 request.user, post.forum)
        posts_queryset = posts_queryset.select_related('thread', 'forum')

        if post_id < post.thread.last_post_id:
            target_post = posts_queryset.order_by('id').filter(id__gt=post_id)
        else:
            target_post = posts_queryset.order_by('-id').filter(id__lt=post_id)

        target_post = target_post[:1][0]
        target_post.thread.forum = target_post.forum

        add_acl(request.user, target_post.forum)
        add_acl(request.user, target_post.thread)
        add_acl(request.user, target_post)

        messages.success(request, _("Post has been deleted."))
        return self.redirect_to_post(request.user, target_post)
Ejemplo n.º 5
0
    def dispatch(self, request, *args, **kwargs):
        relations = ['forum']
        thread = self.fetch_thread(request, select_related=relations, **kwargs)
        forum = thread.forum

        self.check_forum_permissions(request, forum)
        self.check_thread_permissions(request, thread)

        self.allow_action(thread)

        if not request.is_ajax():
            response = render(request, 'misago/errorpages/wrong_way.html')
            response.status_code = 405
            return response

        queryset = exclude_invisible_posts(thread.post_set, request.user,
                                           forum)
        queryset = self.filter_posts_queryset(queryset)
        final_queryset = queryset.select_related('poster').order_by('-id')[:15]

        return self.render(
            request, {
                'forum': forum,
                'thread': thread,
                'posts_count': queryset.count(),
                'posts': final_queryset.iterator()
            })
Ejemplo n.º 6
0
    def validate_posts(self, data):
        if len(data) > POSTS_LIMIT:
            message = ngettext(
                "No more than %(limit)s post can be deleted at single time.",
                "No more than %(limit)s posts can be deleted at single time.",
                POSTS_LIMIT,
            )
            raise ValidationError(message % {'limit': POSTS_LIMIT})

        user = self.context['user']
        thread = self.context['thread']

        posts_queryset = exclude_invisible_posts(user, thread.category, thread.post_set)
        posts_queryset = posts_queryset.filter(id__in=data).order_by('id')

        posts = []
        for post in posts_queryset:
            post.category = thread.category
            post.thread = thread

            if post.is_event:
                allow_delete_event(user, post)
            else:
                allow_delete_best_answer(user, post)
                allow_delete_post(user, post)

            posts.append(post)

        if len(posts) != len(data):
            raise PermissionDenied(_("One or more posts to delete could not be found."))

        return posts
Ejemplo n.º 7
0
def make_read_aware(user, categories):
    if not categories:
        return

    if not hasattr(categories, '__iter__'):
        categories = [categories]

    make_read(categories)

    if user.is_anonymous:
        return

    threads = Thread.objects.filter(category__in=categories)
    threads = exclude_invisible_threads(user, categories, threads)

    queryset = Post.objects.filter(
        category__in=categories,
        thread__in=threads,
        posted_on__gt=get_cutoff_date(user),
    ).values_list('category', flat=True).distinct()

    queryset = queryset.exclude(id__in=user.postread_set.values('post'))
    queryset = exclude_invisible_posts(user, categories, queryset)

    unread_categories = list(queryset)

    for category in categories:
        if category.pk in unread_categories:
            category.is_read = False
            category.is_new = True
Ejemplo n.º 8
0
def clean_posts_for_move(request, thread):
    posts_ids = clean_ids_list(
        request.data.get('posts', []),
        _("One or more post ids received were invalid."),
    )

    if not posts_ids:
        raise PermissionDenied(
            _("You have to specify at least one post to move."))
    elif len(posts_ids) > MOVE_LIMIT:
        message = ungettext(
            "No more than %(limit)s post can be moved at single time.",
            "No more than %(limit)s posts can be moved at single time.",
            MOVE_LIMIT,
        )
        raise PermissionDenied(message % {'limit': MOVE_LIMIT})

    posts_queryset = exclude_invisible_posts(request.user, thread.category,
                                             thread.post_set)
    posts_queryset = posts_queryset.filter(id__in=posts_ids).order_by('id')

    posts = []
    for post in posts_queryset:
        post.category = thread.category
        post.thread = thread

        allow_move_post(request.user, post)
        posts.append(post)

    if len(posts) != len(posts_ids):
        raise PermissionDenied(
            _("One or more posts to move could not be found."))

    return posts
Ejemplo n.º 9
0
    def validate_posts(self, data):
        if len(data) > POSTS_LIMIT:
            message = ungettext(
                "No more than %(limit)s post can be split at single time.",
                "No more than %(limit)s posts can be split at single time.",
                POSTS_LIMIT,
            )
            raise ValidationError(message % {'limit': POSTS_LIMIT})

        thread = self.context['thread']
        user = self.context['user']

        posts_queryset = exclude_invisible_posts(user, thread.category,
                                                 thread.post_set)
        posts_queryset = posts_queryset.filter(id__in=data).order_by('id')

        posts = []
        for post in posts_queryset:
            post.category = thread.category
            post.thread = thread

            try:
                allow_split_post(user, post)
            except PermissionDenied as e:
                raise ValidationError(e)

            posts.append(post)

        if len(posts) != len(data):
            raise ValidationError(
                _("One or more posts to split could not be found."))

        return posts
Ejemplo n.º 10
0
    def validate_posts(self, data):
        data = list(set(data))

        if len(data) < 2:
            raise ValidationError(self.error_empty_or_required)
        if len(data) > POSTS_LIMIT:
            message = ungettext(
                "No more than %(limit)s post can be merged at single time.",
                "No more than %(limit)s posts can be merged at single time.",
                POSTS_LIMIT,
            )
            raise ValidationError(message % {'limit': POSTS_LIMIT})

        user = self.context['user']
        thread = self.context['thread']

        posts_queryset = exclude_invisible_posts(user, thread.category,
                                                 thread.post_set)
        posts_queryset = posts_queryset.filter(id__in=data).order_by('id')

        posts = []
        for post in posts_queryset:
            post.category = thread.category
            post.thread = thread

            try:
                allow_merge_post(user, post)
            except PermissionDenied as e:
                raise ValidationError(e)

            if not posts:
                posts.append(post)
                continue

            authorship_error = _(
                "Posts made by different users can't be merged.")
            if post.poster_id != posts[0].poster_id:
                raise serializers.ValidationError(authorship_error)
            elif (post.poster_id is None and posts[0].poster_id is None
                  and post.poster_name != posts[0].poster_name):
                raise serializers.ValidationError(authorship_error)

            if posts[0].is_first_post and post.is_best_answer:
                raise serializers.ValidationError(
                    _("Post marked as best answer can't be merged with thread's first post."
                      ))

            if not posts[0].is_first_post:
                if (posts[0].is_hidden != post.is_hidden
                        or posts[0].is_unapproved != post.is_unapproved):
                    raise serializers.ValidationError(
                        _("Posts with different visibility can't be merged."))

            posts.append(post)

        if len(posts) != len(data):
            raise ValidationError(
                _("One or more posts to merge could not be found."))

        return posts
def make_read_aware(user, threads):
    if not threads:
        return

    if not hasattr(threads, '__iter__'):
        threads = [threads]

    make_read(threads)

    if user.is_anonymous:
        return

    categories = [t.category for t in threads]

    queryset = Post.objects.filter(
        thread__in=threads,
        posted_on__gt=get_cutoff_date(user),
    ).values_list('thread', flat=True).distinct()

    queryset = queryset.exclude(id__in=user.postread_set.values('post'))
    queryset = exclude_invisible_posts(user, categories, queryset)

    unread_threads = list(queryset)

    for thread in threads:
        if thread.pk in unread_threads:
            thread.is_read = False
            thread.is_new = True
Ejemplo n.º 12
0
    def real_dispatch(self, request, post):
        post_id = post.id

        permissions.allow_delete_post(request.user, post)
        moderation.delete_post(request.user, post)

        post.thread.synchronize()
        post.thread.save()
        post.forum.synchronize()
        post.forum.save()

        posts_queryset = exclude_invisible_posts(post.thread.post_set,
                                                 request.user,
                                                 post.forum)
        posts_queryset = posts_queryset.select_related('thread', 'forum')

        if post_id < post.thread.last_post_id:
            target_post = posts_queryset.order_by('id').filter(id__gt=post_id)
        else:
            target_post = posts_queryset.order_by('-id').filter(id__lt=post_id)

        target_post = target_post[:1][0]
        target_post.thread.forum = target_post.forum

        add_acl(request.user, target_post.forum)
        add_acl(request.user, target_post.thread)
        add_acl(request.user, target_post)

        messages.success(request, _("Post has been deleted."))
        return self.redirect_to_post(request.user, target_post)
Ejemplo n.º 13
0
def filter_read_threads_queryset(user, categories, list_type, queryset):
    # grab cutoffs for categories
    cutoff_date = get_cutoff_date(user)

    visible_posts = Post.objects.filter(posted_on__gt=cutoff_date)
    visible_posts = exclude_invisible_posts(user, categories, visible_posts)

    queryset = queryset.filter(
        id__in=visible_posts.distinct().values('thread'))

    read_posts = visible_posts.filter(id__in=user.postread_set.values('post'))

    if list_type == 'new':
        # new threads have no entry in reads table
        return queryset.exclude(id__in=read_posts.distinct().values('thread'))

    if list_type == 'unread':
        # unread threads were read in past but have new posts
        unread_posts = visible_posts.exclude(
            id__in=user.postread_set.values('post'))
        queryset = queryset.filter(
            id__in=read_posts.distinct().values('thread'))
        queryset = queryset.filter(
            id__in=unread_posts.distinct().values('thread'))
        return queryset
Ejemplo n.º 14
0
def clean_posts_for_patch(request, thread):
    if not isinstance(request.data, dict):
        raise PermissionDenied(_("Bulk PATCH request should be a dict with ids and ops keys."))

    # todo: move this ids list cleanup step to utility

    try:
        posts_ids = list(map(int, request.data.get('ids', [])))
    except (ValueError, TypeError):
        raise PermissionDenied(_("One or more post ids received were invalid."))

    if not posts_ids:
        raise PermissionDenied(_("You have to specify at least one post to update."))
    elif len(posts_ids) > PATCH_LIMIT:
        message = ungettext(
            "No more than %(limit)s post can be updated at single time.",
            "No more than %(limit)s posts can be updated at single time.",
            PATCH_LIMIT,
        )
        raise PermissionDenied(message % {'limit': PATCH_LIMIT})

    posts_queryset = exclude_invisible_posts(request.user, thread.category, thread.post_set)
    posts_queryset = posts_queryset.filter(id__in=posts_ids).order_by('id')

    posts = []
    for post in posts_queryset:
        post.category = thread.category
        post.thread = thread
        posts.append(post)

    if len(posts) != len(posts_ids):
        raise PermissionDenied(_("One or more posts to update could not be found."))

    return posts
Ejemplo n.º 15
0
 def get_posts_queryset(self, request, thread):
     queryset = thread.post_set.select_related(
         'poster',
         'poster__rank',
         'poster__ban_cache',
         'poster__online_tracker',
     ).filter(is_event=False).order_by('id')
     return exclude_invisible_posts(request.user, thread.category, queryset)
Ejemplo n.º 16
0
 def get_posts_queryset(self, request, thread):
     queryset = thread.post_set.select_related(
         'poster',
         'poster__rank',
         'poster__ban_cache',
         'poster__online_tracker',
     ).filter(is_event=False).order_by('id')
     return exclude_invisible_posts(request.user, thread.category, queryset)
Ejemplo n.º 17
0
 def get_posts_queryset(self, user, forum, thread):
     queryset = thread.post_set.select_related(
         'poster',
         'poster__rank',
         'poster__ban_cache',
         'poster__online_tracker'
     )
     return exclude_invisible_posts(queryset, user, forum).order_by('id')
Ejemplo n.º 18
0
    def get_events_queryset(self, request, thread, limit, first_post=None, last_post=None):
        queryset = thread.post_set.select_related('poster').filter(is_event=True)

        if first_post:
            queryset = queryset.filter(pk__gt=first_post.pk)
        if last_post:
            queryset = queryset.filter(pk__lt=last_post.pk)

        queryset = exclude_invisible_posts(request.user, thread.category, queryset)
        return list(queryset.order_by('-id')[:limit])
Ejemplo n.º 19
0
    def get(self, request, pk, slug, **kwargs):
        thread = self.get_thread(request, pk, slug).unwrap()
        self.test_permissions(request, thread)

        posts_queryset = exclude_invisible_posts(request.user, thread.category, thread.post_set)

        target_post = self.get_target_post(thread, posts_queryset.order_by('id'), **kwargs)
        target_page = self.compute_post_page(target_post, posts_queryset)

        return self.get_redirect(thread, target_post, target_page)
Ejemplo n.º 20
0
    def get(self, request, pk, slug, **kwargs):
        thread = self.get_thread(request, pk, slug).unwrap()
        self.test_permissions(request, thread)

        posts_queryset = exclude_invisible_posts(request.user, thread.category, thread.post_set)

        target_post = self.get_target_post(request.user, thread, posts_queryset.order_by('id'), **kwargs)
        target_page = self.compute_post_page(target_post, posts_queryset)

        return self.get_redirect(thread, target_post, target_page)
Ejemplo n.º 21
0
    def validate_posts(self, data):
        data = list(set(data))

        if len(data) < 2:
            raise serializers.ValidationError(_("You have to select at least two posts to merge."))
        if len(data) > POSTS_MERGE_LIMIT:
            message = ungettext(
                "No more than %(limit)s post can be merged at single time.",
                "No more than %(limit)s posts can be merged at single time.",
                POSTS_MERGE_LIMIT,
            )
            raise serializers.ValidationError(message % {'limit': POSTS_MERGE_LIMIT})

        user = self.context['user']
        thread = self.context['thread']

        posts_queryset = exclude_invisible_posts(user, thread.category, thread.post_set)
        posts_queryset = posts_queryset.filter(id__in=data).order_by('id')

        posts = []
        for post in posts_queryset:
            post.category = thread.category
            post.thread = thread

            try:
                allow_merge_post(user, post)
            except PermissionDenied as e:
                raise serializers.ValidationError(six.text_type(e))

            if not posts:
                posts.append(post)
            else:
                authorship_error = _("Posts made by different users can't be merged.")
                if posts[0].poster_id:
                    if post.poster_id != posts[0].poster_id:
                        raise serializers.ValidationError(authorship_error)
                else:
                    if post.poster_id or post.poster_name != posts[0].poster_name:
                        raise serializers.ValidationError(authorship_error)

                if posts[0].pk != thread.first_post_id:
                    if (posts[0].is_hidden != post.is_hidden or
                            posts[0].is_unapproved != post.is_unapproved):
                        raise serializers.ValidationError(
                            _("Posts with different visibility can't be merged.")
                        )

                posts.append(post)

        if len(posts) != len(data):
            raise serializers.ValidationError(_("One or more posts to merge could not be found."))

        self.posts_cache = posts

        return data
Ejemplo n.º 22
0
def clean_posts_for_merge(request, thread):
    try:
        posts_ids = list(map(int, request.data.get('posts', [])))
    except (ValueError, TypeError):
        raise PermissionDenied(
            _("One or more post ids received were invalid."))

    if len(posts_ids) < 2:
        raise PermissionDenied(
            _("You have to select at least two posts to merge."))
    elif len(posts_ids) > MERGE_LIMIT:
        message = ungettext(
            "No more than %(limit)s post can be merged at single time.",
            "No more than %(limit)s posts can be merged at single time.",
            MERGE_LIMIT,
        )
        raise PermissionDenied(message % {'limit': MERGE_LIMIT})

    posts_queryset = exclude_invisible_posts(request.user, thread.category,
                                             thread.post_set)
    posts_queryset = posts_queryset.filter(id__in=posts_ids).order_by('id')

    posts = []
    for post in posts_queryset:
        post.category = thread.category
        post.thread = thread

        allow_merge_post(request.user, post)

        if not posts:
            posts.append(post)
        else:
            authorship_error = _(
                "Posts made by different users can't be merged.")
            if posts[0].poster_id:
                if post.poster_id != posts[0].poster_id:
                    raise PermissionDenied(authorship_error)
            else:
                if post.poster_id or post.poster_name != posts[0].poster_name:
                    raise PermissionDenied(authorship_error)

            if posts[0].pk != thread.first_post_id:
                if (posts[0].is_hidden != post.is_hidden
                        or posts[0].is_unapproved != post.is_unapproved):
                    raise PermissionDenied(
                        _("Posts with different visibility can't be merged."))

            posts.append(post)

    if len(posts) != len(posts_ids):
        raise PermissionDenied(
            _("One or more posts to merge could not be found."))

    return posts
Ejemplo n.º 23
0
    def get_events_queryset(self, request, thread, limit, first_post=None, last_post=None):
        queryset = thread.post_set.select_related(
            'category',
            'poster',
            'poster__rank',
            'poster__ban_cache',
            'poster__online_tracker',
        ).filter(is_event=True)

        if first_post:
            queryset = queryset.filter(pk__gt=first_post.pk)
        if last_post:
            queryset = queryset.filter(pk__lt=last_post.pk)

        queryset = exclude_invisible_posts(request.user, thread.category, queryset)
        return list(queryset.order_by('-id')[:limit])
Ejemplo n.º 24
0
def clean_posts_for_patch(request, thread, posts_ids):
    posts_queryset = exclude_invisible_posts(request.user, thread.category, thread.post_set)
    posts_queryset = posts_queryset.filter(
        id__in=posts_ids,
        is_event=False,
    ).order_by('id')

    posts = []
    for post in posts_queryset:
        post.category = thread.category
        post.thread = thread
        posts.append(post)

    if len(posts) != len(posts_ids):
        raise PermissionDenied(_("One or more posts to update could not be found."))

    return posts
Ejemplo n.º 25
0
def clean_posts_for_split(request, thread):
    try:
        posts_ids = list(map(int, request.data.get('posts', [])))
    except (ValueError, TypeError):
        raise SplitError(_("One or more post ids received were invalid."))

    if not posts_ids:
        raise SplitError(_("You have to specify at least one post to split."))
    elif len(posts_ids) > SPLIT_LIMIT:
        message = ungettext(
            "No more than %(limit)s post can be split at single time.",
            "No more than %(limit)s posts can be split at single time.",
            SPLIT_LIMIT,
        )
        raise SplitError(message % {'limit': SPLIT_LIMIT})

    posts_queryset = exclude_invisible_posts(request.user, thread.category,
                                             thread.post_set)
    posts_queryset = posts_queryset.select_for_update().filter(
        id__in=posts_ids).order_by('id')

    posts = []
    for post in posts_queryset:
        if post.is_event:
            raise SplitError(_("Events can't be split."))
        if post.pk == thread.first_post_id:
            raise SplitError(_("You can't split thread's first post."))
        if post.is_hidden and not thread.category.acl['can_hide_posts']:
            raise SplitError(
                _("You can't split posts the content you can't see."))

        posts.append(post)

    if len(posts) != len(posts_ids):
        raise SplitError(_("One or more posts to split could not be found."))

    return posts
Ejemplo n.º 26
0
def clean_posts_for_delete(request, thread):
    try:
        posts_ids = list(map(int, request.data or []))
    except (ValueError, TypeError):
        raise PermissionDenied(
            _("One or more post ids received were invalid."))

    if not posts_ids:
        raise PermissionDenied(
            _("You have to specify at least one post to delete."))
    elif len(posts_ids) > DELETE_LIMIT:
        message = ungettext(
            "No more than %(limit)s post can be deleted at single time.",
            "No more than %(limit)s posts can be deleted at single time.",
            DELETE_LIMIT,
        )
        raise PermissionDenied(message % {'limit': DELETE_LIMIT})

    posts_queryset = exclude_invisible_posts(request.user, thread.category,
                                             thread.post_set)
    posts_queryset = posts_queryset.filter(id__in=posts_ids).order_by('id')

    posts = []
    for post in posts_queryset:
        post.thread = thread
        if post.is_event:
            allow_delete_event(request.user, post)
        else:
            allow_delete_post(request.user, post)
        posts.append(post)

    if len(posts) != len(posts_ids):
        raise PermissionDenied(
            _("One or more posts to delete could not be found."))

    return posts
Ejemplo n.º 27
0
 def get_queryset(self, request, thread):
     return exclude_invisible_posts(request.user, thread.category, thread.post_set)
Ejemplo n.º 28
0
def posts_queryset(user, thread):
    qs = exclude_invisible_posts(thread.post_set, user, thread.forum)
    return qs.count(), qs.order_by('id')
Ejemplo n.º 29
0
 def exclude_invisible_posts(self, queryset, user, forum, thread):
     return exclude_invisible_posts(queryset, user, forum)
Ejemplo n.º 30
0
 def exclude_invisible_posts(self, queryset, user, forum, thread):
     return exclude_invisible_posts(queryset, user, forum)
Ejemplo n.º 31
0
def posts_queryset(user, thread):
    qs = exclude_invisible_posts(thread.post_set, user, thread.forum)
    return qs.count(), qs.order_by('id')
Ejemplo n.º 32
0
 def get_queryset(self, request, thread):
     return exclude_invisible_posts(request.user, thread.category,
                                    thread.post_set)