add unread count to thread title in topic view and thread view

This commit is contained in:
2025-08-17 15:15:06 +03:00
parent 1f80ed7ca5
commit 6dd9f5bf65
5 changed files with 31 additions and 5 deletions

View File

@ -178,7 +178,7 @@ class Topics(Model):
q = """ q = """
SELECT SELECT
threads.title, threads.slug, threads.created_at, threads.is_locked, threads.is_stickied, threads.id, threads.title, threads.slug, threads.created_at, threads.is_locked, threads.is_stickied,
users.username AS started_by, users.username AS started_by,
u.username AS latest_post_username, u.username AS latest_post_username,
ph.content AS latest_post_content, ph.content AS latest_post_content,
@ -251,6 +251,13 @@ class Avatars(Model):
class Subscriptions(Model): class Subscriptions(Model):
table = "subscriptions" table = "subscriptions"
def get_unread_count(self):
q = """SELECT COUNT(*) AS unread_count
FROM posts
LEFT JOIN subscriptions ON subscriptions.thread_id = posts.thread_id
WHERE subscriptions.user_id = ? AND posts.created_at > subscriptions.last_seen"""
return db.fetch_one(q, self.user_id)['unread_count']
class APIRateLimits(Model): class APIRateLimits(Model):
table = 'api_rate_limits' table = 'api_rate_limits'

View File

@ -54,12 +54,14 @@ def thread(slug):
other_topics = Topics.select() other_topics = Topics.select()
is_subscribed = False is_subscribed = False
unread_count = None
if is_logged_in(): if is_logged_in():
subscription = Subscriptions.find({ subscription = Subscriptions.find({
'thread_id': thread.id, 'thread_id': thread.id,
'user_id': get_active_user().id, 'user_id': get_active_user().id,
}) })
if subscription: if subscription:
unread_count = subscription.get_unread_count()
if int(posts[-1]['created_at']) > int(subscription.last_seen): if int(posts[-1]['created_at']) > int(subscription.last_seen):
subscription.update({ subscription.update({
'last_seen': int(posts[-1]['created_at']) 'last_seen': int(posts[-1]['created_at'])
@ -76,6 +78,7 @@ def thread(slug):
topics = other_topics, topics = other_topics,
is_subscribed = is_subscribed, is_subscribed = is_subscribed,
Reactions = Reactions, Reactions = Reactions,
unread_count = unread_count,
) )

View File

@ -1,8 +1,8 @@
from flask import ( from flask import (
Blueprint, render_template, request, redirect, url_for, flash, session Blueprint, render_template, request, redirect, url_for, flash, session
) )
from .users import login_required, mod_only from .users import login_required, mod_only, get_active_user, is_logged_in
from ..models import Users, Topics, Threads from ..models import Users, Topics, Threads, Subscriptions
from ..constants import InfoboxKind from ..constants import InfoboxKind
from slugify import slugify from slugify import slugify
import time import time
@ -62,9 +62,22 @@ def topic(slug):
page_count = max(math.ceil(threads_count / THREADS_PER_PAGE), 1) page_count = max(math.ceil(threads_count / THREADS_PER_PAGE), 1)
page = max(1, min(int(request.args.get('page', default=1)), page_count)) page = max(1, min(int(request.args.get('page', default=1)), page_count))
threads_list = target_topic.get_threads(THREADS_PER_PAGE, page, sort_by)
subscriptions = {}
if is_logged_in():
for thread in threads_list:
subscription = Subscriptions.find({
'user_id': get_active_user().id,
'thread_id': thread['id'],
})
if subscription:
print(subscription.get_unread_count())
subscriptions[subscription.id] = subscription.get_unread_count()
return render_template( return render_template(
"topics/topic.html", "topics/topic.html",
threads_list = target_topic.get_threads(THREADS_PER_PAGE, page, sort_by), threads_list = threads_list,
subscriptions = subscriptions,
topic = target_topic, topic = target_topic,
current_page = page, current_page = page,
page_count = page_count page_count = page_count

View File

@ -12,7 +12,7 @@
{% endif %} {% endif %}
<main> <main>
<nav class="darkbg"> <nav class="darkbg">
<h1 class="thread-title">{{ thread.title }}</h1> <h1 class="thread-title">{{ thread.title }}{% if unread_count is not none %} ({{ unread_count }} unread){% endif %}</h1>
<span>Posted in <a href="{{ url_for("topics.topic", slug=topic.slug) }}">{{ topic.name }}</a> <span>Posted in <a href="{{ url_for("topics.topic", slug=topic.slug) }}">{{ topic.name }}</a>
{% if thread.is_stickied %} {% if thread.is_stickied %}
&bullet; <i>stickied, so it's probably important</i> &bullet; <i>stickied, so it's probably important</i>

View File

@ -40,6 +40,9 @@
<div class="thread-info-container"> <div class="thread-info-container">
<span> <span>
<span class="thread-title"><a href="{{ url_for("threads.thread", slug=thread['slug']) }}">{{thread['title']}}</a></span> <span class="thread-title"><a href="{{ url_for("threads.thread", slug=thread['slug']) }}">{{thread['title']}}</a></span>
{% if thread['id'] in subscriptions %}
({{ subscriptions[thread['id']] }} unread)
{% endif %}
&bullet; &bullet;
Started by <a href="{{ url_for("users.page", username=thread['started_by']) }}">{{ thread['started_by'] }}</a> on {{ timestamp(thread['created_at'])}} Started by <a href="{{ url_for("users.page", username=thread['started_by']) }}">{{ thread['started_by'] }}</a> on {{ timestamp(thread['created_at'])}}
</span> </span>