Skip to content

Commit

Permalink
Reduce test fails (#1807)
Browse files Browse the repository at this point in the history
  • Loading branch information
rafalp committed Sep 5, 2024
1 parent 98dbd69 commit 67fbf46
Show file tree
Hide file tree
Showing 15 changed files with 305 additions and 195 deletions.
42 changes: 42 additions & 0 deletions misago/middleware/privatethreads.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
from typing import TYPE_CHECKING

from django.http import HttpRequest

from ..categories.enums import CategoryTree
from ..categories.models import Category
from ..readtracker.privatethreads import get_unread_private_threads
from ..readtracker.tracker import annotate_categories_read_time

if TYPE_CHECKING:
from ..users.models import User


def sync_user_unread_private_threads(get_response):
def middleware(request):
if request.user.is_authenticated and request.user.sync_unread_private_threads:
user = request.user
category = get_private_threads_category(user)
queryset = get_unread_private_threads(request, category, category.read_time)
update_user_unread_private_threads(user, queryset.count())

return get_response(request)

return middleware


def get_private_threads_category(user: "User") -> Category:
return annotate_categories_read_time(
user,
Category.objects.filter(tree_id=CategoryTree.PRIVATE_THREADS),
).first()


def update_user_unread_private_threads(user: "User", unread_count: int):
user.unread_private_threads = unread_count
user.sync_unread_private_threads = False
user.save(
update_fields=[
"unread_private_threads",
"sync_unread_private_threads",
],
)
Empty file.
98 changes: 98 additions & 0 deletions misago/middleware/tests/test_sync_user_unread_private_threads.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
from datetime import timedelta
from unittest.mock import Mock

from django.utils import timezone

from ...categories.proxy import CategoriesProxy
from ...permissions.proxy import UserPermissionsProxy
from ...threads.models import ThreadParticipant
from ...threads.test import post_thread
from ...readtracker.models import ReadThread
from ..privatethreads import sync_user_unread_private_threads


def test_sync_user_unread_private_threads_middleware_updates_user_with_unread_threads(
dynamic_settings, cache_versions, user, user_private_thread
):
user.unread_private_threads = 0
user.sync_unread_private_threads = True
user.joined_on = user.joined_on.replace(year=2010)
user.save()

user_permissions = UserPermissionsProxy(user, cache_versions)
request = Mock(
categories=CategoriesProxy(user_permissions, cache_versions),
settings=dynamic_settings,
user=user,
user_permissions=user_permissions,
)

middleware = sync_user_unread_private_threads(Mock())
middleware(request)

user.refresh_from_db()
assert user.unread_private_threads == 1
assert not user.sync_unread_private_threads


def test_sync_user_unread_private_threads_middleware_updates_user_without_unread_threads(
dynamic_settings, cache_versions, user
):
user.unread_private_threads = 100
user.sync_unread_private_threads = True
user.joined_on = user.joined_on.replace(year=2010)
user.save()

user_permissions = UserPermissionsProxy(user, cache_versions)
request = Mock(
categories=CategoriesProxy(user_permissions, cache_versions),
settings=dynamic_settings,
user=user,
user_permissions=user_permissions,
)

middleware = sync_user_unread_private_threads(Mock())
middleware(request)

user.refresh_from_db()
assert user.unread_private_threads == 0
assert not user.sync_unread_private_threads


def test_sync_user_unread_private_threads_middleware_skips_anonymous_user(
dynamic_settings, cache_versions, anonymous_user
):
user_permissions = UserPermissionsProxy(anonymous_user, cache_versions)
request = Mock(
categories=CategoriesProxy(user_permissions, cache_versions),
settings=dynamic_settings,
user=anonymous_user,
user_permissions=user_permissions,
)

middleware = sync_user_unread_private_threads(Mock())
middleware(request)


def test_sync_user_unread_private_threads_middleware_skips_user_without_sync_flag(
dynamic_settings, cache_versions, user
):
user.unread_private_threads = 100
user.sync_unread_private_threads = False
user.joined_on = user.joined_on.replace(year=2010)
user.save()

user_permissions = UserPermissionsProxy(user, cache_versions)
request = Mock(
categories=CategoriesProxy(user_permissions, cache_versions),
settings=dynamic_settings,
user=user,
user_permissions=user_permissions,
)

middleware = sync_user_unread_private_threads(Mock())
middleware(request)

user.refresh_from_db()
assert user.unread_private_threads == 100
assert not user.sync_unread_private_threads
19 changes: 14 additions & 5 deletions misago/readtracker/privatethreads.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,26 @@
from .tracker import annotate_threads_read_time


def are_private_threads_read(
request: HttpRequest, category: Category, category_read_time: datetime | None
def unread_private_threads_exist(
request: HttpRequest,
category: Category,
category_read_time: datetime | None,
) -> bool:
queryset = get_unread_private_threads(request, category, category_read_time)
return queryset.exists()


def get_unread_private_threads(
request: HttpRequest,
category: Category,
category_read_time: datetime | None,
):
read_time = get_default_read_time(request.settings, request.user)

if category_read_time:
read_time = max(read_time, category_read_time)

queryset = (
return (
filter_private_threads_queryset(
request.user_permissions,
annotate_threads_read_time(
Expand All @@ -27,5 +38,3 @@ def are_private_threads_read(
.filter(last_post_on__gt=read_time)
.filter(Q(last_post_on__gt=F("read_time")) | Q(read_time__isnull=True))
)

return not queryset.exists()
36 changes: 7 additions & 29 deletions misago/readtracker/signals.py
Original file line number Diff line number Diff line change
@@ -1,51 +1,29 @@
from django.dispatch import Signal, receiver

from ..categories import PRIVATE_THREADS_ROOT_NAME
from ..categories.signals import delete_category_content, move_category_content
from ..threads.signals import merge_post, merge_thread, move_post, move_thread
from ..threads.signals import merge_thread, move_thread

thread_read = Signal()


@receiver(delete_category_content)
def delete_category_threads(sender, **kwargs):
sender.postread_set.all().delete()
sender.readthread_set.all().delete()
sender.readcategory_set.all().delete()


@receiver(move_category_content)
def move_category_tracker(sender, **kwargs):
sender.postread_set.update(category=kwargs["new_category"])
sender.readthread_set.update(category=kwargs["new_category"])
sender.readcategory_set.update(category=kwargs["new_category"])


@receiver(merge_thread)
def merge_thread_tracker(sender, **kwargs):
other_thread = kwargs["other_thread"]
other_thread.postread_set.update(category=sender.category, thread=sender)
other_thread.readthread_set.all().delete()


@receiver(move_thread)
def move_thread_tracker(sender, **kwargs):
sender.postread_set.update(category=sender.category, thread=sender)


@receiver(merge_post)
def merge_post_delete_tracker(sender, **kwargs):
sender.postread_set.all().delete()


@receiver(move_post)
def move_post_delete_tracker(sender, **kwargs):
sender.postread_set.all().delete()


@receiver(thread_read)
def decrease_unread_private_count(sender, **kwargs):
user = sender
thread = kwargs["thread"]

if thread.category.thread_type.root_name != PRIVATE_THREADS_ROOT_NAME:
return

if user.unread_private_threads:
user.unread_private_threads -= 1
user.save(update_fields=["unread_private_threads"])
sender.readthread_set.update(category=sender.category, thread=sender)
Loading

0 comments on commit 67fbf46

Please sign in to comment.