Exemplo n.º 1
0
def clean_threads_for_merge(request):
    try:
        threads_ids = list(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_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_for_update().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
Exemplo n.º 2
0
    def validate_threads(self, data):
        if len(data) > THREADS_LIMIT:
            message = ngettext(
                "No more than %(limit)s thread can be merged at single time.",
                "No more than %(limit)s threads can be merged at single time.",
                POSTS_LIMIT,
            )
            raise ValidationError(message % {'limit': THREADS_LIMIT})

        threads_tree_id = trees_map.get_tree_id_for_root(THREADS_ROOT_NAME)

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

        user = self.context['user']

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

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

        return threads
Exemplo n.º 3
0
    def test_delete_private_thread(self):
        """attempt to delete private thread fails"""
        private_thread = self.threads[0]

        private_thread.category = Category.objects.get(
            tree_id=trees_map.get_tree_id_for_root(PRIVATE_THREADS_ROOT), )
        private_thread.save()

        private_thread.threadparticipant_set.create(
            user=self.user,
            is_owner=True,
        )

        self.override_acl({
            'can_hide_own_threads': 2,
            'can_hide_threads': 2,
        })

        threads_ids = [p.id for p in self.threads]

        response = self.delete(self.api_link, threads_ids)
        self.assertEqual(response.status_code, 400)
        self.assertEqual(response.json(), {
            'threads': ["One or more threads to delete could not be found."],
        })

        Thread.objects.get(pk=private_thread.pk)
    def test_delete_private_thread(self):
        """attempt to delete private thread fails"""
        private_thread = self.threads[0]

        private_thread.category = Category.objects.get(
            tree_id=trees_map.get_tree_id_for_root(
                PRIVATE_THREADS_ROOT_NAME), )
        private_thread.save()

        private_thread.threadparticipant_set.create(
            user=self.user,
            is_owner=True,
        )

        self.override_acl({
            'can_hide_own_threads': 2,
            'can_hide_threads': 2,
        })

        threads_ids = [p.id for p in self.threads]

        response = self.delete(self.api_link, threads_ids)

        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.json(), [])

        Thread.objects.get(pk=private_thread.pk)

        deleted_threads = [self.threads[1], self.threads[2]]
        for thread in deleted_threads:
            with self.assertRaises(Thread.DoesNotExist):
                Thread.objects.get(pk=thread.pk)

        category = Category.objects.get(pk=self.category.pk)
        self.assertNotIn(category.last_thread_id, threads_ids)
Exemplo n.º 5
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
Exemplo n.º 6
0
    def setUp(self):
        super(StartThreadTests, self).setUp()

        threads_tree_id = trees_map.get_tree_id_for_root(THREADS_ROOT_NAME)

        self.category = Category.objects.get(slug='first-category')
        self.api_link = reverse('misago:api:thread-list')
    def test_delete_private_thread(self):
        """attempt to delete private thread fails"""
        private_thread = self.threads[0]

        private_thread.category = Category.objects.get(
            tree_id=trees_map.get_tree_id_for_root(PRIVATE_THREADS_ROOT_NAME),
        )
        private_thread.save()

        private_thread.threadparticipant_set.create(
            user=self.user,
            is_owner=True,
        )

        self.override_acl({
            'can_hide_own_threads': 2,
            'can_hide_threads': 2,
        })

        threads_ids = [p.id for p in self.threads]

        response = self.delete(self.api_link, threads_ids)

        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.json(), [])

        Thread.objects.get(pk=private_thread.pk)

        deleted_threads = [self.threads[1], self.threads[2]]
        for thread in deleted_threads:
            with self.assertRaises(Thread.DoesNotExist):
                Thread.objects.get(pk=thread.pk)

        category = Category.objects.get(pk=self.category.pk)
        self.assertNotIn(category.last_thread_id, threads_ids)
Exemplo n.º 8
0
    def test_get_categories_dict_from_db(self):
        """get_categories_dict_from_db returns dict with categories"""
        test_dict = Category.objects.get_categories_dict_from_db()

        for category in Category.objects.all():
            threads_tree_id = trees_map.get_tree_id_for_root(THREADS_ROOT_NAME)
            if category.tree_id == threads_tree_id:
                self.assertIn(category.id, test_dict)
            else:
                self.assertNotIn(category.id, test_dict)
Exemplo n.º 9
0
    def setUp(self):
        super(ThreadsApiTestCase, self).setUp()

        threads_tree_id = trees_map.get_tree_id_for_root(THREADS_ROOT_NAME)

        self.root = Category.objects.get(tree_id=threads_tree_id, level=0)
        self.category = Category.objects.get(slug='first-category')

        self.thread = testutils.post_thread(category=self.category)
        self.api_link = self.thread.get_api_url()
    def test_get_categories_dict_from_db(self):
        """get_categories_dict_from_db returns dict with categories"""
        test_dict = Category.objects.get_categories_dict_from_db()

        for category in Category.objects.all():
            threads_tree_id = trees_map.get_tree_id_for_root(THREADS_ROOT_NAME)
            if category.tree_id == threads_tree_id:
                self.assertIn(category.id, test_dict)
            else:
                self.assertNotIn(category.id, test_dict)
    def setUp(self):
        super(ThreadsApiTestCase, self).setUp()

        threads_tree_id = trees_map.get_tree_id_for_root(THREADS_ROOT_NAME)

        self.root = Category.objects.get(tree_id=threads_tree_id, level=0)
        self.category = Category.objects.get(slug='first-category')

        self.thread = testutils.post_thread(category=self.category)
        self.api_link = self.thread.get_api_url()
Exemplo n.º 12
0
    def get_thread(self, request, pk, slug=None):
        thread = get_object_or_404(
            Thread.objects.select_related(*BASE_RELATIONS),
            pk=pk,
            category__tree_id=trees_map.get_tree_id_for_root(THREADS_ROOT_NAME),
        )

        allow_see_thread(request.user, thread)
        if slug:
            validate_slug(thread, slug)
        return thread
Exemplo n.º 13
0
    def get_target(self, kwargs):
        target = super(CategoryAdmin, self).get_target(kwargs)

        threads_tree_id = trees_map.get_tree_id_for_root(THREADS_ROOT_NAME)

        target_is_special = bool(target.special_role)
        target_not_in_categories_tree = target.tree_id != threads_tree_id

        if target.pk and (target_is_special or target_not_in_categories_tree):
            raise Category.DoesNotExist()
        else:
            return target
Exemplo n.º 14
0
    def __init__(self, *args, **kwargs):
        self.base_level = kwargs.pop('base_level', 1)
        kwargs['level_indicator'] = kwargs.get('level_indicator', '- - ')

        threads_tree_id = trees_map.get_tree_id_for_root(THREADS_ROOT_NAME)
        queryset = Category.objects.filter(tree_id=threads_tree_id)
        if not kwargs.pop('include_root', False):
            queryset = queryset.exclude(special_role="root_category")

        kwargs.setdefault('queryset', queryset)

        super(AdminCategoryFieldMixin, self).__init__(*args, **kwargs)
Exemplo n.º 15
0
    def get_target(self, kwargs):
        target = super(CategoryAdmin, self).get_target(kwargs)

        threads_tree_id = trees_map.get_tree_id_for_root(THREADS_ROOT_NAME)

        target_is_special = bool(target.special_role)
        target_not_in_categories_tree = target.tree_id != threads_tree_id

        if target.pk and (target_is_special or target_not_in_categories_tree):
            raise Category.DoesNotExist()
        else:
            return target
Exemplo n.º 16
0
    def __init__(self, *args, **kwargs):
        self.base_level = kwargs.pop('base_level', 1)
        kwargs['level_indicator'] = kwargs.get('level_indicator', '- - ')

        threads_tree_id = trees_map.get_tree_id_for_root(THREADS_ROOT_NAME)
        queryset = Category.objects.filter(tree_id=threads_tree_id)
        if not kwargs.pop('include_root', False):
            queryset = queryset.exclude(special_role="root_category")

        kwargs.setdefault('queryset', queryset)

        super(AdminCategoryFieldMixin, self).__init__(*args, **kwargs)
Exemplo n.º 17
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['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)
Exemplo n.º 18
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)
Exemplo n.º 19
0
    def get_thread(self, request, pk, slug=None, select_for_update=False):
        if select_for_update:
            queryset = Thread.objects.select_for_update()
        else:
            queryset = Thread.objects.select_related(*BASE_RELATIONS)

        thread = get_object_or_404(
            queryset,
            pk=pk,
            category__tree_id=trees_map.get_tree_id_for_root(
                THREADS_ROOT_NAME))

        allow_see_thread(request.user, thread)
        if slug:
            validate_slug(thread, slug)
        return thread
Exemplo n.º 20
0
    def get_thread(self, request, pk, slug=None):
        allow_use_private_threads(request.user)

        thread = get_object_or_404(
            Thread.objects.select_related(*BASE_RELATIONS),
            pk=pk,
            category__tree_id=trees_map.get_tree_id_for_root(PRIVATE_THREADS_ROOT_NAME),
        )

        make_participants_aware(request.user, thread)
        allow_see_private_thread(request.user, thread)

        if slug:
            validate_slug(thread, slug)

        return thread
Exemplo n.º 21
0
    def validate_category(self, value):
        try:
            self.category_cache = Category.objects.get(
                pk=value, tree_id=trees_map.get_tree_id_for_root(THREADS_ROOT))

            can_see = can_see_category(self.user, self.category_cache)
            can_browse = can_browse_category(self.user, self.category_cache)
            if not (self.category_cache.level and can_see and can_browse):
                raise PermissionDenied(_("Selected category is invalid."))

            allow_start_thread(self.user, self.category_cache)
        except PermissionDenied as e:
            raise serializers.ValidationError(e.args[0])
        except Category.DoesNotExist:
            raise serializers.ValidationError(
                _("Selected category doesn't exist or you don't have permission to browse it."
                  ))
Exemplo n.º 22
0
def read_threads(user, pk):
    user.lock()

    category_id = get_int_or_404(pk)
    threads_tree_id = trees_map.get_tree_id_for_root(THREADS_ROOT_NAME)

    category = get_object_or_404(
        Category,
        id=category_id,
        tree_id=threads_tree_id,
    )

    if category.level:
        allow_see_category(user, category)
        allow_browse_category(user, category)

    read_category(user, category)
Exemplo n.º 23
0
def read_threads(user, pk):
    user.lock()

    category_id = get_int_or_404(pk)
    threads_tree_id = trees_map.get_tree_id_for_root(THREADS_ROOT_NAME)

    category = get_object_or_404(
        Category,
        id=category_id,
        tree_id=threads_tree_id,
    )

    if category.level:
        allow_see_category(user, category)
        allow_browse_category(user, category)

    read_category(user, category)
Exemplo n.º 24
0
    def read(self, request, pk):
        request.user.lock()

        category_id = get_int_or_404(pk)
        threads_tree_id = trees_map.get_tree_id_for_root(THREADS_ROOT_NAME)

        category = get_object_or_404(Category,
            id=category_id,
            tree_id=threads_tree_id,
        )

        if category.level:
            allow_see_category(request.user, category)
            allow_browse_category(request.user, category)

        read_category(request.user, category)

        return Response({'detail': 'ok'})
Exemplo n.º 25
0
    def get_valid_threads(self, threads_ids):
        user = self.context['user']

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

        invalid_threads = []
        valid_threads = []
        for thread in threads_queryset:
            add_acl(user, thread)
            if can_see_thread(user, thread):
                valid_threads.append(thread)
                try:
                    allow_merge_thread(user, thread)
                except PermissionDenied as permission_error:
                    invalid_threads.append({
                        'id': thread.id,
                        'status': 403,
                        'detail': permission_error
                    })

        not_found_ids = set(threads_ids) - set([t.id for t in valid_threads])
        for not_found_id in not_found_ids:
            invalid_threads.append({
                'id':
                not_found_id,
                'status':
                404,
                'detail':
                _("Requested thread doesn't exist or you don't have permission to see it."
                  ),
            })

        if invalid_threads:
            invalid_threads.sort(key=lambda item: item['id'])
            raise ValidationError({'merge': invalid_threads})

        return valid_threads
Exemplo n.º 26
0
 def all_categories(self, include_root=False):
     tree_id = trees_map.get_tree_id_for_root(THREADS_ROOT_NAME)
     queryset = self.filter(tree_id=tree_id)
     if not include_root:
         queryset = queryset.filter(level__gt=0)
     return queryset.order_by('lft')
Exemplo n.º 27
0
 def all_categories(self, include_root=False):
     tree_id = trees_map.get_tree_id_for_root(THREADS_ROOT_NAME)
     queryset = self.filter(tree_id=tree_id)
     if not include_root:
         queryset = queryset.filter(level__gt=0)
     return queryset.order_by('lft')