Пример #1
0
def warnings(request, profile, page=0):
    warnings_qs = profile.warnings.order_by('-id')
    warnings = paginate(warnings_qs, page, 5, 2)
    items_left = warnings.paginator.count - warnings.end_index()

    add_acl(request.user, warnings.object_list)

    warning_level = get_user_warning_level(profile)
    warning_level_obj = get_user_warning_obj(profile)

    active_warnings = warning_level - warnings.start_index() + 1
    for warning in warnings.object_list:
        if warning.is_canceled:
            warning.is_active = False
        else:
            warning.is_active = active_warnings > 0
            active_warnings -= 1

    levels_total = len(get_warning_levels()) - 1
    if levels_total and warning_level:
        warning_progress = 100 - warning_level * 100 / levels_total
    else:
        warning_progress = 100

    if warning_level:
        warning_level_obj.level = warning_level

    return render(request, 'misago/profile/warnings.html', {
        'profile': profile,
        'warnings': warnings,
        'warning_level': warning_level_obj,
        'warning_progress': warning_progress,
        'page_number': warnings.number,
        'items_left': items_left
    })
Пример #2
0
def clean_threads_for_merge(request):
    try:
        threads_ids = map(int, request.data.get('threads', []))
    except (ValueError, TypeError):
        raise MergeError(_("One or more thread ids received were invalid."))

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

    threads_queryset = Thread.objects.filter(
        id__in=threads_ids,
        category__tree_id=CATEGORIES_TREE_ID,
    ).select_related('category').order_by('-id')

    threads = []
    for thread in threads_queryset:
        add_acl(request.user, thread)
        if can_see_thread(request.user, thread):
            threads.append(thread)

    if len(threads) != len(threads_ids):
        raise MergeError(_("One or more threads to merge could not be found."))

    return threads
Пример #3
0
    def decorator(request, *args, **kwargs):
        User = get_user_model()

        relations = ('rank', 'online_tracker', 'ban_cache')
        queryset = User.objects.select_related(*relations)
        profile = get_object_or_404(queryset, id=kwargs.pop('user_id'))

        validate_slug(profile, kwargs.pop('user_slug'))
        kwargs['profile'] = profile

        add_acl(request.user, profile)

        if profile.acl_['can_follow']:
            profile.is_followed = request.user.is_following(profile)
        else:
            profile.is_followed = False

        if profile.acl_['can_block'] and request.user.is_authenticated():
            profile.is_blocked = request.user.is_blocking(profile)
        else:
            profile.is_blocked = False

        if request.user.is_authenticated and request.method == "GET":
            read_user_notification(request.user, "profile_%s" % profile.pk)

        return f(request, *args, **kwargs)
Пример #4
0
    def check_forum_permissions(self, request, forum):
        if forum.special_role:
            raise Http404()

        add_acl(request.user, forum)
        allow_see_forum(request.user, forum)
        allow_browse_forum(request.user, forum)
Пример #5
0
    def __init__(self, request, thread, page):
        try:
            thread_model = thread.unwrap()
        except AttributeError:
            thread_model = thread

        posts_queryset = self.get_queryset(request, thread_model)

        list_page = paginate(
            posts_queryset, page, settings.MISAGO_POSTS_PER_PAGE, settings.MISAGO_POSTS_TAIL)
        paginator = pagination_dict(list_page, include_page_range=False)

        posts = list(list_page.object_list)
        posters = []

        for post in posts:
            post.category = thread.category
            post.thread = thread_model

            if post.poster:
                posters.append(post.poster)

        add_acl(request.user, posts)

        make_posts_read_aware(request.user, thread_model, posts)
        make_users_status_aware(request.user, posters)

        if thread.category.acl['can_see_posts_likes']:
            add_likes_to_posts(request.user, posts)

        self._user = request.user

        self.posts = posts
        self.paginator = paginator
def patch_acl(request, event, value):
    """useful little op that updates event acl to current state"""
    if value:
        add_acl(request.user, event)
        return {'acl': event.acl}
    else:
        return {'acl': None}
Пример #7
0
    def __init__(self, request, thread, page):
        posts_queryset = self.get_queryset(request, thread.model)

        list_page = paginate(posts_queryset, page, settings.MISAGO_POSTS_PER_PAGE, settings.MISAGO_POSTS_TAIL)
        paginator = pagination_dict(list_page, include_page_range=False)

        posts = list(list_page.object_list)
        posters = []

        for post in posts:
            post.category = thread.category
            post.thread = thread.model

            if post.poster:
                posters.append(post.poster)

        add_acl(request.user, posts)

        make_posts_read_aware(request.user, thread.model, posts)
        make_users_status_aware(request.user, posters)

        self._user = request.user

        self.posts = posts
        self.paginator = paginator
Пример #8
0
    def clean(self):
        data = super(MovePostsForm, self).clean()

        new_thread_url = data.get('new_thread_url')
        try:
            if not new_thread_url:
                raise Http404()

            resolution = resolve(urlparse(new_thread_url).path)
            if not 'thread_id' in resolution.kwargs:
                raise Http404()

            queryset = Thread.objects.select_related('forum')
            self.new_thread = queryset.get(id=resolution.kwargs['thread_id'])

            add_acl(self.user, self.new_thread.forum)
            add_acl(self.user, self.new_thread)

            allow_see_forum(self.user, self.new_thread.forum)
            allow_browse_forum(self.user, self.new_thread.forum)
            allow_see_thread(self.user, self.new_thread)

        except (Http404, Thread.DoesNotExist):
            message = _("You have to enter valid link to thread.")
            raise forms.ValidationError(message)

        if self.thread == self.new_thread:
            message = _("New thread is same as current one.")
            raise forms.ValidationError(message)

        if self.new_thread.forum.special_role:
            message = _("You can't move posts to special threads.")
            raise forms.ValidationError(message)

        return data
def poll_vote_create(request, thread, poll):
    poll.make_choices_votes_aware(request.user)

    allow_vote_poll(request.user, poll)

    serializer = NewVoteSerializer(
        data={
            'choices': request.data,
        },
        context={
            'allowed_choices': poll.allowed_choices,
            'choices': poll.choices,
        },
    )

    if not serializer.is_valid():
        return Response(
            {
                'detail': serializer.errors['choices'][0],
            },
            status=400,
        )

    remove_user_votes(request.user, poll, serializer.data['choices'])
    set_new_votes(request, poll, serializer.data['choices'])

    add_acl(request.user, poll)
    serialized_poll = PollSerializer(poll).data

    poll.choices = list(map(presave_clean_choice, deepcopy(poll.choices)))
    poll.save()

    return Response(serialized_poll)
Пример #10
0
    def create(self, request, thread_pk):
        thread = self.get_thread_for_update(request, thread_pk)
        allow_start_poll(request.user, thread)

        try:
            if thread.poll and thread.poll.pk:
                raise PermissionDenied(_("There's already a poll in this thread."))
        except Poll.DoesNotExist:
            pass

        instance = Poll(
            thread=thread,
            category=thread.category,
            poster=request.user,
            poster_name=request.user.username,
            poster_slug=request.user.slug,
            poster_ip=request.user_ip,
        )

        serializer = NewPollSerializer(instance, data=request.data)
        if serializer.is_valid():
            serializer.save()

            add_acl(request.user, instance)
            for choice in instance.choices:
                choice['selected'] = False

            return Response(PollSerializer(instance).data)
        else:
            return Response(serializer.errors, status=400)
Пример #11
0
def patch_acl(request, thread, value):
    """useful little op that updates thread acl to current state"""
    if value:
        add_acl(request.user, thread)
        return {'acl': thread.acl}
    else:
        return {'acl': None}
Пример #12
0
    def get_posts(self, user, forum, thread, kwargs):
        queryset = self.get_posts_queryset(user, forum, thread)
        queryset = self.exclude_invisible_posts(queryset, user, forum, thread)
        page = paginate(queryset, kwargs.get('page', 0),
                        settings.MISAGO_POSTS_PER_PAGE,
                        settings.MISAGO_THREAD_TAIL)

        posts = []
        for post in page.object_list:
            post.forum = forum
            post.thread = thread

            add_acl(user, post)

            if post.poster:
                poster_state = get_user_state(post.poster, user.acl)
                post.poster.online_state = poster_state
            posts.append(post)

        if page.next_page_first_item:
            add_events_to_posts(
                user, thread, posts, page.next_page_first_item.posted_on)
        else:
            add_events_to_posts(user, thread, posts)

        return page, posts
Пример #13
0
    def create_attachment(self, request):
        upload = request.FILES.get('upload')
        if not upload:
            raise ValidationError(_("No file has been uploaded."))

        user_roles = set(r.pk for r in request.user.get_roles())
        filetype = validate_filetype(upload, user_roles)
        validate_filesize(upload, filetype, request.user.acl['max_attachment_size'])

        attachment = Attachment(
            secret=Attachment.generate_new_secret(),
            filetype=filetype,
            size=upload.size,
            uploader=request.user,
            uploader_name=request.user.username,
            uploader_slug=request.user.slug,
            uploader_ip=request.user_ip,
            filename=upload.name,
        )

        if is_upload_image(upload):
            try:
                attachment.set_image(upload)
            except IOError:
                raise ValidationError(_("Uploaded image was corrupted or invalid."))
        else:
            attachment.set_file(upload)

        attachment.save()
        add_acl(request.user, attachment)

        return Response(AttachmentSerializer(attachment, context={'user': request.user}).data)
Пример #14
0
    def __init__(self, request, **kwargs):
        self._categories = self.get_categories(request)
        add_acl(request.user, self._categories)

        self._model = self.get_category(request, self._categories, **kwargs)
        self._subcategories = list(filter(self._model.has_child, self._categories))
        self._children = list(filter(lambda s: s.parent_id == self._model.pk, self._subcategories))
Пример #15
0
def get_categories_tree(user, parent=None):
    if not user.acl['visible_categories']:
        return []

    if parent:
        queryset = parent.get_descendants().order_by('lft')
    else:
        queryset = Category.objects.all_categories()

    queryset_with_acl = queryset.filter(id__in=user.acl['visible_categories'])
    visible_categories = list(queryset_with_acl)

    categories_dict = {}
    categories_list = []

    parent_level = parent.level + 1 if parent else 1

    for category in visible_categories:
        category.subcategories = []
        categories_dict[category.pk] = category
        categories_list.append(category)

        if category.parent_id and category.level > parent_level:
            categories_dict[category.parent_id].subcategories.append(category)

    add_acl(user, categories_list)
    categoriestracker.make_read_aware(user, categories_list)

    for category in reversed(visible_categories):
        if category.acl['can_browse']:
            category.parent = categories_dict.get(category.parent_id)
            if category.parent:
                category.parent.threads += category.threads
                category.parent.posts += category.posts

                if category.parent.last_post_on and category.last_post_on:
                    parent_last_post = category.parent.last_post_on
                    category_last_post = category.last_post_on
                    update_last_thead = parent_last_post < category_last_post
                elif not category.parent.last_post_on and category.last_post_on:
                    update_last_thead = True
                else:
                    update_last_thead = False

                if update_last_thead:
                    category.parent.last_post_on = category.last_post_on
                    category.parent.last_thread_id = category.last_thread_id
                    category.parent.last_thread_title = category.last_thread_title
                    category.parent.last_thread_slug = category.last_thread_slug
                    category.parent.last_poster_name = category.last_poster_name
                    category.parent.last_poster_slug = category.last_poster_slug

                if not category.is_read:
                    category.parent.is_read = False

    flat_list = []
    for category in categories_list:
        if category.level == parent_level:
            flat_list.append(category)
    return flat_list
Пример #16
0
    def post_editor(self, request, thread_pk, pk):
        thread = self.get_thread(
            request,
            get_int_or_404(thread_pk),
            read_aware=False,
            subscription_aware=False
        )
        post = self.get_post(request, thread, get_int_or_404(pk)).model

        allow_edit_post(request.user, post)

        attachments = []
        for attachment in post.attachment_set.order_by('-id'):
            add_acl(request.user, attachment)
            attachments.append(attachment)
        attachments_json = AttachmentSerializer(
            attachments, many=True, context={'user': request.user}).data

        return Response({
            'id': post.pk,
            'api': post.get_api_url(),
            'post': post.original,
            'attachments': attachments_json,
            'can_protect': bool(thread.category.acl['can_protect_posts']),
            'is_protected': post.is_protected,
            'poster': post.poster_name
        })
Пример #17
0
    def __init__(self, request, category, list_type, page):
        self.allow_see_list(request, category, list_type)

        base_queryset = self.get_base_queryset(request, category.categories, list_type)
        threads_categories = [category.category] + category.subcategories

        threads_queryset = self.get_remaining_threads_queryset(base_queryset, category.category, threads_categories)

        list_page = paginate(threads_queryset, page, settings.MISAGO_THREADS_PER_PAGE, settings.MISAGO_THREADS_TAIL)
        paginator = pagination_dict(list_page, include_page_range=False)

        if list_page.number > 1:
            threads = list(list_page.object_list)
        else:
            pinned_threads = list(self.get_pinned_threads(base_queryset, category.category, threads_categories))
            threads = list(pinned_threads) + list(list_page.object_list)

        if list_type in ('new', 'unread'):
            # we already know all threads on list are unread
            threadstracker.make_unread(threads)
        else:
            threadstracker.make_threads_read_aware(request.user, threads)

        add_categories_to_threads(category.category, category.categories, threads)
        add_acl(request.user, threads)
        make_subscription_aware(request.user, threads)

        # set state on object for easy access from hooks
        self.category = category
        self.threads = threads
        self.list_type = list_type
        self.paginator = paginator
Пример #18
0
 def get_initial_attachments(self, mode, user, post):
     attachments = []
     if mode == PostingEndpoint.EDIT:
         queryset = post.attachment_set.select_related('filetype')
         attachments = list(queryset)
         add_acl(user, attachments)
     return attachments
Пример #19
0
def posts_merge_endpoint(request, thread):
    if not thread.acl['can_merge_posts']:
        raise PermissionDenied(_("You can't merge posts in this thread."))

    try:
        posts = clean_posts_for_merge(request, thread)
    except MergeError as e:
        return Response({'detail': e.msg}, status=400)

    first_post, merged_posts = posts[0], posts[1:]
    for post in merged_posts:
        post.merge(first_post)
        post.delete()
    first_post.save()

    thread.synchronize()
    thread.save()

    thread.category.synchronize()
    thread.category.save()

    first_post.thread = thread
    first_post.category = thread.category

    add_acl(request.user, first_post)

    return Response(PostSerializer(first_post, context={'user': request.user}).data)
Пример #20
0
    def _test_thread_read(self):
        """thread read flag is set for user, then its set as unread by reply"""
        self.reply_thread(self.thread)

        add_acl(self.user, self.categories)
        threadstracker.make_read_aware(self.user, self.thread)
        self.assertFalse(self.thread.is_read)

        threadstracker.read_thread(self.user, self.thread, self.post)
        threadstracker.make_read_aware(self.user, self.thread)
        self.assertTrue(self.thread.is_read)
        categoriestracker.make_read_aware(self.user, self.categories)
        self.assertTrue(self.category.is_read)

        self.thread.last_post_on = timezone.now()
        self.thread.save()
        self.category.synchronize()
        self.category.save()

        self.reply_thread()
        threadstracker.make_read_aware(self.user, self.thread)
        self.assertFalse(self.thread.is_read)
        categoriestracker.make_read_aware(self.user, self.categories)
        self.assertFalse(self.category.is_read)

        posts = [post for post in self.thread.post_set.order_by('id')]
        threadstracker.make_posts_read_aware(self.user, self.thread, posts)

        for post in posts[:-1]:
            self.assertTrue(post.is_read)
        self.assertFalse(posts[-1].is_read)
Пример #21
0
def clean_threads_for_merge(request):
    threads_ids = clean_ids_list(
        request.data.get('threads', []),
        _("One or more thread ids received were invalid."),
    )

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

    threads_tree_id = trees_map.get_tree_id_for_root(THREADS_ROOT_NAME)

    threads_queryset = Thread.objects.filter(
        id__in=threads_ids,
        category__tree_id=threads_tree_id,
    ).select_related('category').order_by('-id')

    threads = []
    for thread in threads_queryset:
        add_acl(request.user, thread)
        if can_see_thread(request.user, thread):
            threads.append(thread)

    if len(threads) != len(threads_ids):
        raise MergeError(_("One or more threads to merge could not be found."))

    return threads
Пример #22
0
    def override_acl(self, new_acl):
        new_acl.update({'can_browse': True})

        forums_acl = self.user.acl
        forums_acl['visible_forums'].append(self.forum.pk)
        forums_acl['forums'][self.forum.pk] = new_acl
        override_acl(self.user, forums_acl)
        add_acl(self.user, self.forum)
Пример #23
0
    def test_sync_record_for_empty_forum(self):
        """sync_record sets read flag on empty forum"""
        add_acl(self.user, self.forums)
        forumstracker.sync_record(self.user, self.forum)
        self.user.forumread_set.get(forum=self.forum)

        forumstracker.make_read_aware(self.user, self.forums)
        self.assertTrue(self.forum.is_read)
Пример #24
0
    def check_thread_permissions(self, request, thread):
        add_acl(request.user, thread.forum)
        add_acl(request.user, thread)

        self.fetch_thread_participants(request.user, thread)

        allow_see_private_thread(request.user, thread)
        allow_use_private_threads(request.user)
Пример #25
0
    def test_sync_record_for_empty_category(self):
        """sync_record sets read flag on empty category"""
        add_acl(self.user, self.categories)
        categoriestracker.sync_record(self.user, self.category)
        self.user.categoryread_set.get(category=self.category)

        categoriestracker.make_read_aware(self.user, self.categories)
        self.assertTrue(self.category.is_read)
Пример #26
0
    def __init__(self, request, thread, pk, select_for_update=False):
        model = self.get_post(request, thread, pk, select_for_update)

        add_acl(request.user, model)

        self._model = model
        self._thread = model.thread
        self._category = model.category
Пример #27
0
    def retrieve(self, request, pk=None):
        profile = self.get_user(pk)

        add_acl(request.user, profile)
        profile.status = get_user_status(request.user, profile)

        serializer = UserProfileSerializer(profile, context={'user': request.user})
        return Response(serializer.data)
Пример #28
0
def merge_threads(request, validated_data, threads, poll):
    new_thread = Thread(
        category=validated_data['category'],
        started_on=threads[0].started_on,
        last_post_on=threads[0].last_post_on
    )

    new_thread.set_title(validated_data['title'])
    new_thread.save()

    if poll:
        poll.move(new_thread)

    categories = []
    for thread in threads:
        categories.append(thread.category)
        new_thread.merge(thread)
        thread.delete()

        record_event(request, new_thread, 'merged', {
            'merged_thread': thread.title,
        }, commit=False)

    new_thread.synchronize()
    new_thread.save()

    if validated_data.get('weight') == THREAD_WEIGHT_GLOBAL:
        moderation.pin_thread_globally(request, new_thread)
    elif validated_data.get('weight'):
        moderation.pin_thread_locally(request, new_thread)
    if validated_data.get('is_hidden', False):
        moderation.hide_thread(request, new_thread)
    if validated_data.get('is_closed', False):
        moderation.close_thread(request, new_thread)

    if new_thread.category not in categories:
        categories.append(new_thread.category)

    for category in categories:
        category.synchronize()
        category.save()

    # set extra attrs on thread for UI
    new_thread.is_read = False
    new_thread.subscription = None

    # add top category to thread
    if validated_data.get('top_category'):
        categories = list(Category.objects.all_categories().filter(
            id__in=request.user.acl['visible_categories']
        ))
        add_categories_to_items(validated_data['top_category'], categories, [new_thread])
    else:
        new_thread.top_category = None

    add_acl(request.user, new_thread)
    return new_thread
Пример #29
0
    def validate_is_hidden(self, is_hidden):
        try:
            add_acl(self.context, self.category)
        except AttributeError:
            return is_hidden  # don't validate hidden further if category failed

        if is_hidden and not self.category.acl.get('can_hide_threads'):
            raise ValidationError(_("You don't have permission to hide threads in this category."))
        return is_hidden
Пример #30
0
    def retrieve(self, request, pk=None):
        qs = self.get_queryset()
        profile = get_object_or_404(self.get_queryset(), id=pk)

        add_acl(request.user, profile)

        serializer = UserProfileSerializer(
            profile, context={'user': request.user})
        return Response(serializer.data)
Пример #31
0
def thread_start_editor(request):
    if request.user.is_anonymous:
        raise PermissionDenied(_("You need to be signed in to start threads."))

    # list of categories that allow or contain subcategories that allow new threads
    available = []
    categories = []

    queryset = Category.objects.filter(
        pk__in=request.user.acl_cache['browseable_categories'],
        tree_id=trees_map.get_tree_id_for_root(THREADS_ROOT_NAME)).order_by(
            '-lft')

    for category in queryset:
        add_acl(request.user, category)

        post = False
        if can_start_thread(request.user, category):
            post = {
                'close': bool(category.acl['can_close_threads']),
                'hide': bool(category.acl['can_hide_threads']),
                'pin': category.acl['can_pin_threads'],
            }

            available.append(category.pk)
            available.append(category.parent_id)
        elif category.pk in available:
            available.append(category.parent_id)

        categories.append({
            'id': category.pk,
            'name': category.name,
            'level': category.level - 1,
            'post': post,
        })

    # list only categories that allow new threads, or contains subcategory that allows one
    cleaned_categories = []
    for category in reversed(categories):
        if category['id'] in available:
            cleaned_categories.append(category)

    if not cleaned_categories:
        raise PermissionDenied(
            _("No categories that allow new threads are available to you at the moment."
              ))

    return Response(cleaned_categories)
Пример #32
0
    def update(self, request, thread_pk, pk):
        thread = self.get_thread_for_update(request, thread_pk)
        instance = self.get_poll(thread, pk)

        allow_edit_poll(request.user, instance)

        serializer = EditPollSerializer(instance, data=request.data)
        if serializer.is_valid():
            serializer.save()

            add_acl(request.user, instance)
            instance.make_choices_votes_aware(request.user)

            return Response(PollSerializer(instance).data)
        else:
            return Response(serializer.errors, status=400)
Пример #33
0
        def decorator(request, *args, **kwargs):
            queryset = kwargs['user'].warnings
            warning_id = kwargs.pop('warning_id')

            kwargs['warning'] = get_object_or_404(queryset, id=warning_id)
            add_acl(request.user, kwargs['warning'])

            required_permission(request.user, kwargs['warning'])

            response = f(request, *args, **kwargs)

            if response:
                return response
            else:
                return_path = moderation_return_path(request, kwargs['user'])
                return redirect(return_path)
Пример #34
0
    def validate_weight(self, weight):
        try:
            add_acl(self.context, self.category)
        except AttributeError:
            return weight  # don't validate weight further if category failed

        if weight > self.category.acl.get('can_pin_threads', 0):
            if weight == 2:
                raise ValidationError(
                    _("You don't have permission to pin threads globally in this category.")
                )
            else:
                raise ValidationError(
                    _("You don't have permission to pin threads in this category.")
                )
        return weight
Пример #35
0
    def retrieve(self, request, pk=None):
        profile = self.get_user(request, pk)

        add_acl(request.user, profile)
        profile.status = get_user_status(request.user, profile)

        serializer = UserProfileSerializer(profile,
                                           context={'user': request.user})
        profile_json = serializer.data

        if not profile.is_active:
            profile_json['is_active'] = False
        if profile.is_deleting_account:
            profile_json['is_deleting_account'] = True

        return Response(profile_json)
Пример #36
0
    def __init__(self, request, pk, slug=None, read_aware=False, subscription_aware=False, select_for_update=False):
        model = self.get_thread(request, pk, slug, select_for_update)

        model.path = self.get_thread_path(model.category)

        add_acl(request.user, model.category)
        add_acl(request.user, model)

        if read_aware:
            make_read_aware(request.user, model)
        if subscription_aware:
            make_subscription_aware(request.user, model)

        self._model = model
        self._category = model.category
        self._path = model.path
Пример #37
0
    def __init__(self, request, profile, page=0):
        root_category = ThreadsRootCategory(request)
        threads_categories = [root_category.unwrap()] + root_category.subcategories

        threads_queryset = self.get_threads_queryset(
            request, threads_categories, profile)
        posts_queryset = self.get_posts_queryset(
            request.user, profile, threads_queryset
            ).filter(
                is_event=False,
                is_hidden=False,
                is_unapproved=False
            ).order_by('-pk')

        list_page = paginate(
            posts_queryset, page, settings.MISAGO_POSTS_PER_PAGE, settings.MISAGO_POSTS_TAIL)
        paginator = pagination_dict(list_page, include_page_range=False)

        posts = list(list_page.object_list)

        posters = []
        threads = []

        for post in posts:
            threads.append(post.thread)

            if post.poster:
                posters.append(post.poster)

        add_categories_to_items(
            root_category.unwrap(), threads_categories, posts + threads)

        add_acl(request.user, threads)
        add_acl(request.user, posts)

        threadstracker.make_threads_read_aware(request.user, threads)
        for post in posts:
            threadstracker.make_posts_read_aware(request.user, post.thread, [post])

        add_likes_to_posts(request.user, posts)

        make_users_status_aware(request.user, posters)

        self._user = request.user

        self.posts = posts
        self.paginator = paginator
Пример #38
0
    def decorator(request, *args, **kwargs):
        User = get_user_model()

        relations = ('rank', 'online_tracker', 'ban_cache')
        queryset = User.objects.select_related(*relations)

        profile = get_object_or_404(queryset, pk=kwargs.pop('pk'))

        if not profile.is_active and not request.user.is_staff:
            raise Http404()

        validate_slug(profile, kwargs.pop('slug'))
        kwargs['profile'] = profile

        add_acl(request.user, profile)

        return f(request, *args, **kwargs)
Пример #39
0
    def test_sync_record_for_category_deleted_threads(self):
        """unread category reverts to read after its emptied"""
        self.post_thread(self.user.joined_on + timedelta(days=1))
        self.post_thread(self.user.joined_on + timedelta(days=1))
        self.post_thread(self.user.joined_on + timedelta(days=1))

        add_acl(self.user, self.categories)
        categoriestracker.sync_record(self.user, self.category)
        categoriestracker.make_read_aware(self.user, self.categories)
        self.assertFalse(self.category.is_read)

        self.category.thread_set.all().delete()
        self.category.synchronize()
        self.category.save()

        categoriestracker.make_read_aware(self.user, self.categories)
        self.assertTrue(self.category.is_read)
Пример #40
0
    def update(self, request, thread_pk, pk=None):
        thread = self.get_thread(request, thread_pk)
        instance = self.get_poll(thread, pk)

        allow_edit_poll(request.user, instance)

        serializer = EditPollSerializer(instance, data=request.data)
        serializer.is_valid(raise_exception=True)

        serializer.save()

        add_acl(request.user, instance)
        instance.make_choices_votes_aware(request.user)

        create_audit_trail(request, instance)

        return Response(PollSerializer(instance).data)
Пример #41
0
    def test_sync_record_for_forum_with_deleted_threads(self):
        """unread forum reverts to read after its emptied"""
        self.post_thread(self.user.joined_on + timedelta(days=1))
        self.post_thread(self.user.joined_on + timedelta(days=1))
        self.post_thread(self.user.joined_on + timedelta(days=1))

        add_acl(self.user, self.forums)
        forumstracker.sync_record(self.user, self.forum)
        forumstracker.make_read_aware(self.user, self.forums)
        self.assertFalse(self.forum.is_read)

        self.forum.thread_set.all().delete()
        self.forum.synchronize()
        self.forum.save()

        forumstracker.make_read_aware(self.user, self.forums)
        self.assertTrue(self.forum.is_read)
Пример #42
0
    def __init__(self, request, category, list_type, page):
        self.allow_see_list(request, category, list_type)

        category_model = category.unwrap()

        base_queryset = self.get_base_queryset(request, category.categories,
                                               list_type)
        base_queryset = base_queryset.select_related('starter', 'last_poster')

        threads_categories = [category_model] + category.subcategories

        threads_queryset = self.get_remaining_threads_queryset(
            base_queryset, category_model, threads_categories)

        list_page = paginate(threads_queryset, page,
                             settings.MISAGO_THREADS_PER_PAGE,
                             settings.MISAGO_THREADS_TAIL)
        paginator = pagination_dict(list_page)

        if list_page.number > 1:
            threads = list(list_page.object_list)
        else:
            pinned_threads = list(
                self.get_pinned_threads(base_queryset, category_model,
                                        threads_categories))
            threads = list(pinned_threads) + list(list_page.object_list)

        add_categories_to_items(category_model, category.categories, threads)
        add_acl(request.user, threads)
        make_subscription_aware(request.user, threads)

        if list_type in ('new', 'unread'):
            # we already know all threads on list are unread
            for thread in threads:
                thread.is_read = False
                thread.is_new = True
        else:
            threadstracker.make_read_aware(request.user, threads)

        self.filter_threads(request, threads)

        # set state on object for easy access from hooks
        self.category = category
        self.threads = threads
        self.list_type = list_type
        self.paginator = paginator
Пример #43
0
def merge_threads(user, validated_data, threads):
    new_thread = Thread(
        category=validated_data['category'],
        weight=validated_data.get('weight', 0),
        is_closed=validated_data.get('is_closed', False),
        started_on=threads[0].started_on,
        last_post_on=threads[0].last_post_on,
    )

    new_thread.set_title(validated_data['title'])
    new_thread.save()

    categories = []
    for thread in threads:
        categories.append(thread.category)
        new_thread.merge(thread)
        thread.delete()

    new_thread.synchronize()
    new_thread.save()

    if new_thread.category not in categories:
        categories.append(new_thread.category)

    for category in categories:
        category.synchronize()
        category.save()

    # set extra attrs on thread for UI
    new_thread.is_read = False
    new_thread.subscription = None

    # add top category to thread
    if validated_data.get('top_category'):
        categories = list(Category.objects.all_categories().filter(
            id__in=user.acl['visible_categories']))
        add_categories_to_threads(validated_data['top_category'], categories,
                                  [new_thread])
    else:
        new_thread.top_category = None

    new_thread.save()

    add_acl(user, new_thread)
    return new_thread
Пример #44
0
    def test_merge_with_top_category(self):
        """api performs merge with top category"""
        posts_ids = [p.id for p in Post.objects.all()]

        self.override_acl({
            'can_merge_threads': True,
            'can_close_threads': False,
            'can_edit_threads': False,
            'can_reply_threads': False,
        })

        thread = testutils.post_thread(category=self.category)

        response = self.client.post(self.api_link,
                                    json.dumps({
                                        'top_category':
                                        self.root.id,
                                        'threads': [self.thread.id, thread.id],
                                        'title':
                                        'Merged thread!',
                                        'category':
                                        self.category.id,
                                    }),
                                    content_type="application/json")
        self.assertEqual(response.status_code, 200)

        # is response json with new thread?
        response_json = json.loads(response.content)

        new_thread = Thread.objects.get(pk=response_json['id'])
        new_thread.is_read = False
        new_thread.subscription = None
        new_thread.top_category = self.category

        add_acl(self.user, new_thread.category)
        add_acl(self.user, new_thread)

        self.assertEqual(response_json, ThreadListSerializer(new_thread).data)

        # did posts move to new thread?
        for post in Post.objects.filter(id__in=posts_ids):
            self.assertEqual(post.thread_id, new_thread.id)

        # are old threads gone?
        self.assertEqual([t.pk for t in Thread.objects.all()], [new_thread.pk])
Пример #45
0
def posts_merge_endpoint(request, thread):
    if not thread.acl['can_merge_posts']:
        raise PermissionDenied(_("You can't merge posts in this thread."))

    serializer = MergePostsSerializer(
        data=request.data,
        context={
            'thread': thread,
            'user': request.user,
        },
    )

    serializer.is_valid(raise_exception=True)

    posts = serializer.validated_data['posts']
    first_post, merged_posts = posts[0], posts[1:]

    for post in merged_posts:
        post.merge(first_post)
        post.delete()

    if first_post.pk == thread.first_post_id:
        first_post.set_search_document(thread.title)
    else:
        first_post.set_search_document()

    first_post.save()

    first_post.update_search_vector()
    first_post.save(update_fields=['search_vector'])

    first_post.postread_set.all().delete()

    thread.synchronize()
    thread.save()

    thread.category.synchronize()
    thread.category.save()

    first_post.thread = thread
    first_post.category = thread.category

    add_acl(request.user, first_post)

    return Response(PostSerializer(first_post, context={'user': request.user}).data)
Пример #46
0
def exclude_all_invisible_threads(queryset, user):
    forums_in = []
    conditions = None

    for forum in Forum.objects.all_forums():
        add_acl(user, forum)

        condition_forum = Q(forum=forum)
        condition_author = Q(starter_id=user.id)

        # can see all threads?
        if forum.acl['can_see_all_threads']:
            can_mod = forum.acl['can_review_moderated_content']
            can_hide = forum.acl['can_hide_threads']

            if not can_mod or not can_hide:
                if not can_mod and not can_hide:
                    condition = Q(is_moderated=False) & Q(is_hidden=False)
                elif not can_mod:
                    condition = Q(is_moderated=False)
                elif not can_hide:
                    condition = Q(is_hidden=False)
                visibility_condition = condition_author | condition
                visibility_condition = condition_forum & visibility_condition
            else:
                # user can see everything so don't bother with rest of routine
                forums_in.append(forum.pk)
                continue
        else:
            # show all threads in forum made by user
            visibility_condition = condition_forum & condition_author

        if conditions:
            conditions = conditions | visibility_condition
        else:
            conditions = visibility_condition

    if conditions and forums_in:
        return queryset.filter(Q(forum_id__in=forums_in) | conditions)
    elif conditions:
        return queryset.filter(conditions)
    elif forums_in:
        return queryset.filter(forum_id__in=forums_in)
    else:
        return Thread.objects.none()
Пример #47
0
    def test_sync_record_for_forum_with_many_threads(self):
        """sync_record sets unread flag on forum with many threads"""
        self.post_thread(self.user.joined_on + timedelta(days=1))
        self.post_thread(self.user.joined_on - timedelta(days=1))
        self.post_thread(self.user.joined_on + timedelta(days=1))
        self.post_thread(self.user.joined_on - timedelta(days=1))

        add_acl(self.user, self.forums)
        forumstracker.sync_record(self.user, self.forum)
        self.user.forumread_set.get(forum=self.forum)

        forumstracker.make_read_aware(self.user, self.forums)
        self.assertFalse(self.forum.is_read)

        self.post_thread(self.user.joined_on + timedelta(days=1))
        forumstracker.sync_record(self.user, self.forum)
        forumstracker.make_read_aware(self.user, self.forums)
        self.assertFalse(self.forum.is_read)
Пример #48
0
    def test_sync_record_for_forum_with_new_thread(self):
        """
        sync_record sets read flag on forum with old thread,
        then keeps flag to unread when new reply is posted
        """
        self.post_thread(self.user.joined_on + timedelta(days=1))

        add_acl(self.user, self.forums)
        forumstracker.sync_record(self.user, self.forum)
        self.user.forumread_set.get(forum=self.forum)

        forumstracker.make_read_aware(self.user, self.forums)
        self.assertFalse(self.forum.is_read)

        self.post_thread(self.user.joined_on + timedelta(days=1))
        forumstracker.sync_record(self.user, self.forum)
        forumstracker.make_read_aware(self.user, self.forums)
        self.assertFalse(self.forum.is_read)
Пример #49
0
    def test_sync_record_for_category_new_thread(self):
        """
        sync_record sets read flag on category with old thread,
        then keeps flag to unread when new reply is posted
        """
        self.post_thread(self.user.joined_on + timedelta(days=1))

        add_acl(self.user, self.categories)
        categoriestracker.sync_record(self.user, self.category)
        self.user.categoryread_set.get(category=self.category)

        categoriestracker.make_read_aware(self.user, self.categories)
        self.assertFalse(self.category.is_read)

        self.post_thread(self.user.joined_on + timedelta(days=1))
        categoriestracker.sync_record(self.user, self.category)
        categoriestracker.make_read_aware(self.user, self.categories)
        self.assertFalse(self.category.is_read)
Пример #50
0
    def test_sync_record_for_forum_with_old_thread_and_reply(self):
        """
        sync_record sets read flag on forum with old thread,
        then changes flag to unread when new reply is posted
        """
        self.post_thread(self.user.reads_cutoff - timedelta(days=1))

        add_acl(self.user, self.forums)
        forumstracker.sync_record(self.user, self.forum)
        self.user.forumread_set.get(forum=self.forum)

        forumstracker.make_read_aware(self.user, self.forums)
        self.assertTrue(self.forum.is_read)

        thread = self.post_thread(self.user.reads_cutoff + timedelta(days=1))
        forumstracker.sync_record(self.user, self.forum)
        forumstracker.make_read_aware(self.user, self.forums)
        self.assertFalse(self.forum.is_read)
Пример #51
0
    def test_sync_record_for_category_many_threads(self):
        """sync_record sets unread flag on category with many threads"""
        self.post_thread(self.user.joined_on + timedelta(days=1))
        self.post_thread(self.user.joined_on - timedelta(days=1))
        self.post_thread(self.user.joined_on + timedelta(days=1))
        self.post_thread(self.user.joined_on - timedelta(days=1))

        add_acl(self.user, self.categories)
        categoriestracker.sync_record(self.user, self.category)
        self.user.categoryread_set.get(category=self.category)

        categoriestracker.make_read_aware(self.user, self.categories)
        self.assertFalse(self.category.is_read)

        self.post_thread(self.user.joined_on + timedelta(days=1))
        categoriestracker.sync_record(self.user, self.category)
        categoriestracker.make_read_aware(self.user, self.categories)
        self.assertFalse(self.category.is_read)
Пример #52
0
def revert_post_endpoint(request, post):
    edit = get_edit_by_pk(post, request.GET.get('edit'))

    datetime = timezone.now()
    post_edits = post.edits

    post.edits_record.create(
        category=post.category,
        thread=post.thread,
        edited_on=datetime,
        editor=request.user,
        editor_name=request.user.username,
        editor_slug=request.user.slug,
        editor_ip=request.user_ip,
        edited_from=post.original,
        edited_to=edit.edited_from,
    )

    parsing_result = common_flavour(request, post.poster, edit.edited_from)

    post.original = parsing_result['original_text']
    post.parsed = parsing_result['parsed_text']

    update_post_checksum(post)

    post.updated_on = datetime
    post.edits = F('edits') + 1

    post.last_editor = request.user
    post.last_editor_name = request.user.username
    post.last_editor_slug = request.user.slug

    post.save()

    post.is_read = True
    post.is_new = False
    post.edits = post_edits + 1

    add_acl(request.user, post)

    if post.poster:
        make_users_status_aware(request.user, [post.poster])

    return Response(PostSerializer(post, context={'user': request.user}).data)
Пример #53
0
    def get_posts(self, user, forum, thread, kwargs):
        queryset = self.get_posts_queryset(user, forum, thread)
        page = paginate(queryset, kwargs.get('page', 0), 10, 3)

        posts = []
        for post in page.object_list:
            add_acl(user, post)
            if post.poster:
                poster_state = get_user_state(post.poster, user.acl)
                post.poster.online_state = poster_state
            posts.append(post)

        if page.next_page_first_item:
            add_events_to_posts(user, thread, posts,
                                page.next_page_first_item.posted_on)
        else:
            add_events_to_posts(user, thread, posts)

        return page, posts
Пример #54
0
def patch_move(request, thread, value):
    allow_move_thread(request.user, thread)

    category_pk = get_int_or_404(value)
    new_category = get_object_or_404(
        Category.objects.all_categories().select_related('parent'), pk=category_pk
    )

    add_acl(request.user, new_category)
    allow_see_category(request.user, new_category)
    allow_browse_category(request.user, new_category)
    allow_start_thread(request.user, new_category)

    if new_category == thread.category:
        raise ValidationError(_("You can't move thread to the category it's already in."))

    moderation.move_thread(request, thread, new_category)

    return {'category': CategorySerializer(new_category).data}
Пример #55
0
def patch_move(request, thread, value):
    if thread.acl.get('can_move'):
        category_pk = get_int_or_404(value)
        new_category = get_object_or_404(
            Category.objects.all_categories().select_related('parent'),
            pk=category_pk
        )

        add_acl(request.user, new_category)
        allow_see_category(request.user, new_category)
        allow_browse_category(request.user, new_category)
        allow_start_thread(request.user, new_category)

        moderation.move_thread(request.user, thread, new_category)

        return {'category': CategorySerializer(new_category).data}
    else:
        raise PermissionDenied(
            _("You don't have permission to move this thread."))
Пример #56
0
    def test_edit(self):
        """endpoint returns valid configuration for editor"""
        for i in range(3):
            self.override_acl({
                'max_attachment_size': 1000,
            })

            with open(TEST_DOCUMENT_PATH, 'rb') as upload:
                response = self.client.post(reverse('misago:api:attachment-list'), data={
                    'upload': upload
                })
            self.assertEqual(response.status_code, 200)

        attachments = list(Attachment.objects.order_by('id'))

        attachments[0].uploader = None
        attachments[0].save()

        for attachment in attachments[:2]:
            attachment.post = self.post
            attachment.save()

        self.override_acl({
            'can_edit_posts': 1,
        })
        response = self.client.get(self.api_link)

        for attachment in attachments:
            add_acl(self.user, attachment)

        self.assertEqual(response.status_code, 200)
        self.assertEqual(json.loads(smart_str(response.content)), {
            'id': self.post.pk,
            'api': self.post.get_api_url(),
            'post': self.post.original,
            'can_protect': False,
            'is_protected': self.post.is_protected,
            'poster': self.post.poster_name,
            'attachments': [
                AttachmentSerializer(attachments[1], context={'user': self.user}).data,
                AttachmentSerializer(attachments[0], context={'user': self.user}).data,
            ]
        })
Пример #57
0
    def setUp(self):
        User = get_user_model()
        self.user = User.objects.create_user("Bob", "*****@*****.**", "Pass.123")

        datetime = timezone.now()

        self.category = Category.objects.all_categories()[:1][0]
        self.thread = Thread(category=self.category,
                             started_on=datetime,
                             starter_name='Tester',
                             starter_slug='tester',
                             last_post_on=datetime,
                             last_poster_name='Tester',
                             last_poster_slug='tester')

        self.thread.set_title("Test thread")
        self.thread.save()

        add_acl(self.user, self.category)
        add_acl(self.user, self.thread)
def poll_vote_create(request, thread, poll):
    poll.make_choices_votes_aware(request.user)

    allow_vote_poll(request.user, poll)

    try:
        clean_votes = validate_votes(poll, request.data)
    except ValidationError as e:
        return Response({'detail': six.text_type(e)}, status=400)

    remove_user_votes(request.user, poll, clean_votes)
    set_new_votes(request, poll, clean_votes)

    add_acl(request.user, poll)
    serialized_poll = PollSerializer(poll).data

    poll.choices = list(map(presave_clean_choice, deepcopy(poll.choices)))
    poll.save()

    return Response(serialized_poll)
Пример #59
0
def real_add_events_to_posts(user, thread, posts, delimeter=None):
    start_date = posts[0].posted_on
    events_queryset = thread.event_set.filter(occured_on__gte=start_date)
    if delimeter:
        events_queryset = events_queryset.filter(occured_on__lt=delimeter)
    events_queryset = events_queryset.order_by('id')

    acl = user.acl['categories'].get(thread.category_id, {})
    if not acl.get('can_hide_events'):
        events_queryset = events_queryset.filter(is_hidden=False)

    events = [e for e in events_queryset[:50]]
    add_acl(user, events)

    for i, post in enumerate(posts[:-1]):
        post.events = []
        while events and events[0].occured_on < posts[i + 1].posted_on:
            post.events.append(events.pop(0))

    posts[-1].events = events
Пример #60
0
    def setUp(self):
        User = get_user_model()
        self.user = User.objects.create_user("Bob", "*****@*****.**", "Pass.123")

        datetime = timezone.now()

        self.forum = Forum.objects.filter(role="forum")[:1][0]
        self.thread = Thread(forum=self.forum,
                             started_on=datetime,
                             starter_name='Tester',
                             starter_slug='tester',
                             last_post_on=datetime,
                             last_poster_name='Tester',
                             last_poster_slug='tester')

        self.thread.set_title("Test thread")
        self.thread.save()

        add_acl(self.user, self.forum)
        add_acl(self.user, self.thread)