Просмотр исходного кода

#445: mark forum as read + tweaks in readtracker

Rafał Pitoń 10 лет назад
Родитель
Сommit
f75a3cd46c

+ 36 - 12
misago/readtracker/forumstracker.py

@@ -5,12 +5,16 @@ from misago.threads.permissions import exclude_invisible_threads
 
 from misago.readtracker import signals
 from misago.readtracker.dates import is_date_tracked
+from misago.readtracker.models import ForumRead
 
 
 __all__ = ['make_read_aware', 'sync_record']
 
 
 def make_read_aware(user, forums):
+    if not hasattr(forums, '__iter__'):
+        forums = [forums]
+
     if user.is_anonymous():
         make_read(forums)
         return None
@@ -18,12 +22,14 @@ def make_read_aware(user, forums):
     forums_dict = {}
     for forum in forums:
         forum.is_read = not is_date_tracked(forum.last_post_on, user)
-        forums_dict[forum.pk] = forum
+        if not forum.is_read:
+            forums_dict[forum.pk] = forum
 
-    for record in user.forumread_set.filter(forum__in=forums_dict.keys()):
-        if not forum.is_read and record.forum_id in forums_dict:
+    if forums_dict:
+        for record in user.forumread_set.filter(forum__in=forums_dict.keys()):
             forum = forums_dict[record.forum_id]
-            forum.is_read = record.last_read_on >= forum.last_post_on
+            forum.last_read_on = record.last_read_on
+            forum.is_read = forum.last_read_on >= forum.last_post_on
 
 
 def make_read(forums):
@@ -32,14 +38,22 @@ def make_read(forums):
 
 
 def sync_record(user, forum):
-    recorded_threads = forum.thread_set.filter(
-        last_post_on__gt=user.reads_cutoff)
+    cutoff_date = user.reads_cutoff
+
+    try:
+        forum_record = user.forumread_set.get(forum=forum)
+        if forum_record.last_read_on > cutoff_date:
+            cutoff_date = forum_record.last_read_on
+    except ForumRead.DoesNotExist:
+        forum_record = None
+
+    recorded_threads = forum.thread_set.filter(last_post_on__gt=cutoff_date)
     recorded_threads = exclude_invisible_threads(recorded_threads, user, forum)
 
     all_threads_count = recorded_threads.count()
 
     read_threads = user.threadread_set.filter(
-        forum=forum, last_read_on__gt=user.joined_on)
+        forum=forum, last_read_on__gt=cutoff_date)
     read_threads_count = read_threads.filter(
         thread__last_post_on__lte=F("last_read_on")).count()
 
@@ -48,19 +62,29 @@ def sync_record(user, forum):
     if forum_is_read:
         signals.forum_read.send(sender=user, forum=forum)
 
-    try:
-        forum_record = user.forumread_set.filter(forum=forum).all()[0]
+    if forum_record:
         if forum_is_read:
             forum_record.last_read_on = forum_record.last_read_on
         else:
-            forum_record.last_read_on = user.reads_cutoff
+            forum_record.last_read_on = cutoff_date
         forum_record.save(update_fields=['last_read_on'])
-    except IndexError:
+    else:
         if forum_is_read:
             last_read_on = timezone.now()
         else:
-            last_read_on = user.joined_on
+            last_read_on = cutoff_date
 
         forum_record = user.forumread_set.create(
             forum=forum,
             last_read_on=last_read_on)
+
+
+def read_forum(user, forum):
+    try:
+        forum_record = user.forumread_set.get(forum=forum)
+        forum_record.last_read_on = timezone.now()
+        forum_record.save(update_fields=['last_read_on'])
+    except ForumRead.DoesNotExist:
+        user.forumread_set.create(forum=forum, last_read_on=timezone.now())
+    signals.forum_read.send(sender=user, forum=forum)
+

+ 78 - 29
misago/readtracker/threadstracker.py

@@ -1,5 +1,8 @@
+from django.utils import timezone
+
 from misago.readtracker import forumstracker, signals
 from misago.readtracker.dates import is_date_tracked
+from misago.readtracker.models import ForumRead, ThreadRead
 
 
 __all__ = ['make_read_aware', 'read_thread']
@@ -12,7 +15,7 @@ def make_read_aware(user, target):
         make_thread_read_aware(user, target)
 
 
-def make_threads_read_aware(user, threads):
+def make_threads_read_aware(user, threads, forum=None):
     if not threads:
         return None
 
@@ -20,6 +23,39 @@ def make_threads_read_aware(user, threads):
         make_read(threads)
         return None
 
+    if forum:
+        make_forum_threads_read_aware(user, forum, threads)
+    else:
+        make_forums_threads_read_aware(user, threads)
+
+
+def make_read(threads):
+    for thread in threads:
+        thread.unread_replies = 0
+        thread.is_read = True
+        thread.is_new = False
+
+
+def make_forum_threads_read_aware(user, forum, threads):
+    if forum.is_read:
+        make_read(threads)
+    else:
+        threads_dict = {}
+        for thread in threads:
+            thread.is_read = not is_date_tracked(
+                thread.last_post_on, user, forum.last_read_on)
+            thread.is_new = True
+            if thread.is_read:
+                thread.unread_replies = 0
+            else:
+                thread.unread_replies = thread.replies
+                threads_dict[thread.pk] = thread
+
+        if threads_dict:
+            make_threads_dict_read_aware(user, threads_dict)
+
+
+def make_forums_threads_read_aware(user, threads):
     forums_cutoffs = fetch_forums_cutoffs_for_threads(user, threads)
 
     threads_dict = {}
@@ -33,6 +69,23 @@ def make_threads_read_aware(user, threads):
             thread.unread_replies = thread.replies
             threads_dict[thread.pk] = thread
 
+    if threads_dict:
+        make_threads_dict_read_aware(user, threads_dict)
+
+
+def fetch_forums_cutoffs_for_threads(user, threads):
+    forums = []
+    for thread in threads:
+        if thread.forum_id not in forums:
+            forums.append(thread.forum_id)
+
+    forums_dict = {}
+    for record in user.forumread_set.filter(forum__in=forums):
+        forums_dict[record.forum_id] = record.last_read_on
+    return forums_dict
+
+
+def make_threads_dict_read_aware(user, threads_dict):
     for record in user.threadread_set.filter(thread__in=threads_dict.keys()):
         if record.thread_id in threads_dict:
             thread = threads_dict[record.thread_id]
@@ -46,38 +99,34 @@ def make_threads_read_aware(user, threads):
                     thread.unread_replies = 1
 
 
-def make_read(threads):
-    for thread in threads:
-        thread.unread_replies = 0
-        thread.is_read = True
-
-
-def fetch_forums_cutoffs_for_threads(users, threads):
-    forums = []
-    for thread in threads:
-        if thread.forum_id not in forums:
-            forums.append(thread.forum_id)
-
-    forums_dict = {}
-    for record in user.forumread_set.filter(forum__in=forums):
-        forums_dict[record.forum_id] = record.forum.last_read_on
-    return forums_dict
-
-
 def make_thread_read_aware(user, thread):
     thread.is_read = True
+    thread.is_new = False
+    thread.read_record = None
+
+    if user.is_anonymous():
+        thread.last_read_on = timezone.now()
+    else:
+        thread.last_read_on = user.reads_cutoff
+
     if user.is_authenticated() and is_date_tracked(thread.last_post_on, user):
+        thread.is_read = False
+        thread.is_new = True
+
         try:
-            record = user.threadread_set.filter(thread=thread).all()[0]
-            thread.last_read_on = record.last_read_on
-            thread.is_new = False
-            thread.is_read = thread.last_post_on <= record.last_read_on
-            thread.read_record = record
-        except IndexError:
-            thread.read_record = None
-            thread.is_new = True
-            thread.is_read = False
-            thread.last_read_on = user.joined_on
+            forum_record = user.forumread_set.get(forum_id=thread.forum_id)
+            if thread.last_post_on > forum_record.last_read_on:
+                try:
+                    thread_record = user.threadread_set.get(thread=thread)
+                    thread.last_read_on = record.last_read_on
+                    thread.is_new = False
+                    if thread.last_post_on <= thread_record.last_read_on:
+                        thread.is_read = True
+                    thread.read_record = thread_record
+                except ThreadRead.DoesNotExist:
+                    pass
+        except ForumRead.DoesNotExist:
+            pass
 
 
 def make_posts_read_aware(user, thread, posts):

+ 1 - 0
misago/readtracker/urls.py

@@ -3,4 +3,5 @@ from django.conf.urls import include, patterns, url
 
 urlpatterns = patterns('misago.readtracker.views',
     url(r'^read-all/$', 'read_all', name='read_all'),
+    url(r'^read-forum/(?P<forum_id>\d+)/$', 'read_forum', name='read_forum'),
 )

+ 24 - 6
misago/readtracker/views.py

@@ -1,22 +1,31 @@
 from django.contrib import messages
 from django.db.transaction import atomic
-from django.shortcuts import redirect
+from django.shortcuts import get_object_or_404, redirect
 from django.utils import timezone
 from django.utils.translation import ugettext as _
 from django.views.decorators.cache import never_cache
 from django.views.decorators.csrf import csrf_protect
 
 from misago.core.decorators import require_POST
+from misago.forums.models import Forum
 from misago.users.decorators import deny_guests
 
+from misago.readtracker import forumstracker
 from misago.readtracker.signals import all_read
 
 
-@deny_guests
-@require_POST
-@csrf_protect
-@never_cache
-@atomic
+def read_view(f):
+    @deny_guests
+    @require_POST
+    @csrf_protect
+    @never_cache
+    @atomic
+    def decorator(request, *args, **kwargs):
+        return f(request, *args, **kwargs)
+    return decorator
+
+
+@read_view
 def read_all(request):
     request.user.reads_cutoff = timezone.now()
     request.user.save(update_fields=['reads_cutoff'])
@@ -25,3 +34,12 @@ def read_all(request):
 
     messages.info(request, _("All forums and threads were marked as read."))
     return redirect('misago:index')
+
+
+@read_view
+def read_forum(request, forum_id):
+    forum = get_object_or_404(Forum.objects, id=forum_id)
+    forumstracker.read_forum(request.user, forum)
+
+    messages.info(request, _("Threads were marked as read."))
+    return redirect(forum.get_absolute_url())

+ 11 - 0
misago/templates/misago/threads/forum.html

@@ -65,7 +65,18 @@
 
 <div class="table-actions">
   {% include "misago/threads/paginator.html" %}
+
   {% include "misago/threads/reply_btn.html" %}
+
+  {% if not forum.is_read and user.is_authenticated %}
+  <form action="{% url 'misago:read_forum' forum_id=forum.id %}" method="POST" class="pull-right">
+    {% csrf_token %}
+    <button type="submit" class="btn btn-default">
+      <span class="fa fa-circle-o fa-fw"></span>
+      {% trans "Mark threads as read" %}
+    </button>
+  </form>
+  {% endif %}
 </div>
 {% endblock threads-panel %}
 

+ 4 - 0
misago/threads/views/generic/forum/threads.py

@@ -1,4 +1,5 @@
 from misago.core.shortcuts import paginate
+from misago.readtracker import threadstracker
 
 from misago.threads.permissions import exclude_invisible_threads
 from misago.threads.views.generic.threads import Threads
@@ -68,3 +69,6 @@ class ForumThreads(Threads):
                         return queryset.filter(label_id=label.pk)
                 else:
                     return queryset
+
+    def make_threads_read_aware(self, threads):
+        threadstracker.make_threads_read_aware(self.user, threads, self.forum)

+ 3 - 0
misago/threads/views/generic/forum/view.py

@@ -1,6 +1,7 @@
 from django.shortcuts import redirect
 
 from misago.forums.lists import get_forums_list, get_forum_path
+from misago.readtracker import forumstracker
 
 from misago.threads.models import Label
 from misago.threads.views.generic.forum.actions import ForumActions
@@ -25,6 +26,8 @@ class ForumView(ThreadsView):
 
     def dispatch(self, request, *args, **kwargs):
         forum = self.get_forum(request, **kwargs)
+        forumstracker.make_read_aware(request.user, forum)
+
         forum.labels = Label.objects.get_forum_labels(forum)
 
         if forum.lft + 1 < forum.rght: