From 72172dbb1c3c06f3a54b7fa08bb438eb605da3e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lera=20Elvo=C3=A9?= Date: Wed, 20 May 2026 21:12:05 +0300 Subject: [PATCH] add inbox view --- app/models.py | 17 +++++++-------- app/routes/threads.py | 10 ++++++--- app/routes/users.py | 6 ++++-- app/templates/users/inbox.html | 38 ++++++++++++++++++++++++++++++++++ data/static/css/style.css | 31 +++++++++++++++++++++++---- 5 files changed, 84 insertions(+), 18 deletions(-) create mode 100644 app/templates/users/inbox.html diff --git a/app/models.py b/app/models.py index 9ae3001..572e2ad 100644 --- a/app/models.py +++ b/app/models.py @@ -63,15 +63,7 @@ class Users(Model): return db.query(q, self.id, per_page, (page - 1) * per_page) def get_all_subscriptions(self): - q = """ - SELECT threads.title AS thread_title, threads.slug AS thread_slug - FROM - threads - JOIN - subscriptions ON subscriptions.thread_id = threads.id - WHERE - subscriptions.user_id = ?""" - return db.query(q, self.id) + return Subscriptions.findall({'user_id': self.id}) def can_post_to_thread_or_topic(self, thread_or_topic): if self.is_guest(): @@ -420,6 +412,13 @@ class Subscriptions(Model): return res['unread_count'] return None + def get_thread(self): + return Threads.find({'id': self.thread_id}) + + def get_full_posts_view(self): + q = f'{Posts.FULL_POSTS_QUERY} WHERE posts.thread_id = ? AND posts.created_at > ? ORDER BY posts.created_at ASC' + return db.query(q, self.thread_id, self.last_seen) + class APIRateLimits(Model): table = 'api_rate_limits' diff --git a/app/routes/threads.py b/app/routes/threads.py index a0d0f9d..f01ffa0 100644 --- a/app/routes/threads.py +++ b/app/routes/threads.py @@ -148,15 +148,19 @@ def unsubscribe(thread_id): user = get_active_user() last_post_id = request.form.get('last_post_id', None) - if last_post_id is None: + + return_to = request.form.get('return_to', None) + if return_to is None and last_post_id is None: abort(400) + elif return_to is None and last_post_id is not None: + return_to = url_for('.thread_by_id', thread_id=thread_id, after=last_post_id) subscription = Subscriptions.find({'user_id': user.id, 'thread_id': thread_id}) if not subscription: - return redirect(url_for('.thread_by_id', thread_id=thread_id, after=last_post_id)) + return redirect(return_to) subscription.delete() - return redirect(url_for('.thread_by_id', thread_id=thread_id, after=last_post_id)) + return redirect(return_to) @bp.get('//feed.atom/') def feed(thread_id): diff --git a/app/routes/users.py b/app/routes/users.py index 77603ad..839b993 100644 --- a/app/routes/users.py +++ b/app/routes/users.py @@ -189,8 +189,10 @@ def settings(username): @login_required @redirect_to_own def inbox(username): - username = username.lower() - return 'stub' + user = get_active_user() + unread_count = user.get_unread_count() + subscriptions = user.get_all_subscriptions() + return render_template('users/inbox.html', unread_count=unread_count, subscriptions=subscriptions) @bp.get('//bookmarks/') @login_required diff --git a/app/templates/users/inbox.html b/app/templates/users/inbox.html new file mode 100644 index 0000000..26f1887 --- /dev/null +++ b/app/templates/users/inbox.html @@ -0,0 +1,38 @@ +{% from 'common/macros.html' import subheader %} +{% from 'common/macros.html' import full_post with context %} +{%- extends 'base.html' -%} +{%- block title -%}inbox{%- endblock -%} +{%- block content -%} +{%- set topline -%} + {%- if unread_count -%} + You have {{unread_count}} unread posts across {{subscriptions | length}} threads. + {%- elif subscriptions | length > 0 -%} + You have no unread posts. + {%- else -%} + You do not have any subscriptions. + {%- endif -%} +{%- endset -%} +{{ subheader('Your inbox', topline) }} +{%- if subscriptions | length > 0 -%} +
+ {%- for sub in subscriptions -%} +
+ {%- set thread = sub.get_thread() -%} + + {{thread.title}} ({{sub.get_unread_count()}} unread) +
+ + Go to thread + +
+
+ {%- set posts = sub.get_full_posts_view() -%} + + {%- for post in posts -%} +
{{full_post(post, show_toolbar=false, show_reactions=false)}}
+ {%- endfor -%} +
+ {%- endfor -%} +
+{%- endif -%} +{%- endblock -%} diff --git a/data/static/css/style.css b/data/static/css/style.css index 3a58b58..680cde5 100644 --- a/data/static/css/style.css +++ b/data/static/css/style.css @@ -625,6 +625,33 @@ form.full-width { justify-content: space-evenly; } +details { + summary { + cursor: pointer; + display: flex; + align-items: center; + flex-wrap: wrap; + + & :last-child { + margin-left: auto; + } + } + + &:not([open]) summary::before { + content: '▶'; + padding-inline: var(--base-padding); + } + + &[open] summary::before { + content: '▼'; + padding-inline: var(--base-padding); + } +} + +details.separated { + margin: 0.5em 0; +} + /* babycode tags */ .inline-code { background-color: var(--code-bg-color); @@ -768,10 +795,6 @@ pre code { .il { color: #A5D6FF } /* Literal.Number.Integer.Long */ } -summary { - cursor: pointer; -} - p { margin: 0.5em 0; }