Bubble [main]
Comment pages: partial thread view, give thanks
[1mdiff --git a/db-migrate.sql b/db-migrate.sql[m
[1mindex 391761b..45a6508 100644[m
[1m--- a/db-migrate.sql[m
[1m+++ b/db-migrate.sql[m
[36m@@ -22,3 +22,4 @@[m [mALTER TABLE posts ADD INDEX (issueid);[m
-- Migration from v4 to v5 --[m
ALTER TABLE users ADD COLUMN timezone VARCHAR(40) DEFAULT 'UTC';[m
ALTER TABLE users ADD COLUMN recovery VARCHAR(1000) DEFAULT '';[m
[32m+[m[32mALTER TABLE notifs ADD COLUMN comment INT;[m
[1mdiff --git a/feeds.py b/feeds.py[m
[1mindex 43715d0..864e70f 100644[m
[1m--- a/feeds.py[m
[1m+++ b/feeds.py[m
[36m@@ -184,8 +184,11 @@[m [mdef make_post_page_or_configure_feed(session):[m
post = db.get_post(id=int(arg), draft=False)[m
if not post:[m
return 51, 'Not found'[m
[32m+[m
[32m+[m[32m if post.parent != 0:[m
[32m+[m[32m return make_post_page(session, post)[m
[32m+[m
if post.subspace != session.context.id:[m
[31m- #return 51, 'Not found'[m
# Redirect to the correct subspace.[m
post_sub = db.get_subspace(id=post.subspace)[m
if post_sub.flags & Subspace.ISSUE_TRACKER:[m
[36m@@ -193,11 +196,6 @@[m [mdef make_post_page_or_configure_feed(session):[m
else:[m
return 31, f'{session.path}{post_sub.title()}/{post.id}'[m
[m
[31m- if post.parent != 0:[m
[31m- # Comments cannot be viewed individually.[m
[31m- # TODO: Make this possible.[m
[31m- return 30, db.get_post(id=post.parent).page_url()[m
[31m-[m
if arg2 == '/antenna':[m
# Special viewing mode for Antenna submissions, with the bare minimum.[m
page = f'# {session.feed_title()}\n'[m
[36m@@ -211,9 +209,7 @@[m [mdef make_post_page_or_configure_feed(session):[m
db.get_notifications(session.user, post_id=post.id, clear=True)[m
return 30, post.page_url()[m
[m
[31m- page = make_post_page(session, post)[m
[31m-[m
[31m- return page[m
[32m+[m[32m return make_post_page(session, post)[m
[m
return None[m
[m
[36m@@ -221,8 +217,50 @@[m [mdef make_post_page_or_configure_feed(session):[m
def make_post_page(session, post):[m
db = session.db[m
user = session.user[m
[32m+[m[32m is_comment_page = post.parent != 0[m
[32m+[m[32m display_order_desc = session.user and \[m
[32m+[m[32m session.user.sort_cmt == User.SORT_COMMENT_NEWEST[m
[32m+[m[32m page = ''[m
[32m+[m
[32m+[m[32m if is_comment_page:[m
[32m+[m[32m # Switch to the parent post, but display it in preview mode.[m
[32m+[m[32m focused_cmt = post[m
[32m+[m[32m last_age = focused_cmt.age()[m
[32m+[m[32m post = db.get_post(id=post.parent)[m
[32m+[m[32m page += f'=> {post.page_url()} Comment on: "{post.title if post.title else shorten_text(strip_links(clean_title(post.summary)), 60)}" in {("u/" if post.sub_owner else "s/") + post.sub_name}\n'[m
[32m+[m[32m page += f'=> /u/{focused_cmt.poster_name} {focused_cmt.poster_avatar} {focused_cmt.poster_name}\n'[m
[32m+[m[32m page += f'{last_age}\n\n'[m
[32m+[m[32m page += session.render_post(focused_cmt)[m
[32m+[m
[32m+[m[32m # Comment actions.[m
[32m+[m[32m actions = [][m
[32m+[m[32m if session.is_editable(focused_cmt):[m
[32m+[m[32m actions.append(f'=> /edit/{focused_cmt.id} โ๏ธ Edit comment\n')[m
[32m+[m[32m if session.user and not session.is_context_locked and display_order_desc:[m
[32m+[m[32m actions.append(f'=> /comment/{post.id} ๐ฌ Comment\n')[m
[32m+[m[32m if session.is_thanks_enabled() and focused_cmt.user != user.id:[m
[32m+[m[32m actions.append(f'=> /thanks/{focused_cmt.id} ๐ Give thanks\n')[m
[32m+[m[32m if session.is_deletable(focused_cmt) and not session.is_editable(focused_cmt):[m
[32m+[m[32m actions.append(f'=> /edit/{focused_cmt.id}/delete/{session.get_token()} โ Delete comment\n')[m
[32m+[m[32m actions.append(session.dashboard_link())[m
[32m+[m
[32m+[m[32m if actions:[m
[32m+[m[32m page += '\n' + ''.join(actions)[m
[32m+[m
[32m+[m[32m op_section = '\n## Original Post\n\n' + session.feed_entry(post)[m
[32m+[m[32m if not display_order_desc:[m
[32m+[m[32m page += op_section[m
[32m+[m
[32m+[m[32m else:[m
[32m+[m[32m page += session.render_post(post)[m
[m
[31m- page = session.render_post(post)[m
[32m+[m[32m # Poll options/results.[m
[32m+[m[32m poll = session.render_poll(post, show_results=not session.user)[m
[32m+[m[32m if poll:[m
[32m+[m[32m # Ensure separation.[m
[32m+[m[32m if len(page) and not page.endswith('\n\n'):[m
[32m+[m[32m page += '\n'[m
[32m+[m[32m page += poll[m
[m
commits = [][m
incoming_xrefs = [][m
[36m@@ -250,130 +288,125 @@[m [mdef make_post_page(session, post):[m
else:[m
repo = None[m
[m
[31m- # Poll.[m
[31m- poll = session.render_poll(post, show_results=not session.user)[m
[31m- if poll:[m
[31m- # Ensure separation.[m
[31m- if len(page) and not page.endswith('\n\n'):[m
[32m+[m[32m if not is_comment_page:[m
[32m+[m[32m # Post metadata.[m
[32m+[m[32m if len(page):[m
page += '\n'[m
[31m- page += poll[m
[31m-[m
[31m- # Metadata.[m
[31m- if len(page):[m
[32m+[m[32m if post.tags:[m
[32m+[m[32m page += '### ' + post.tags + '\n'[m
[32m+[m[32m poster_link = f'=> /u/{post.poster_name} {post.poster_avatar} {post.poster_name}\n'[m
[32m+[m[32m if session.is_context_tracker:[m
[32m+[m[32m page += f'=> /{session.context.title()} ๐ Issue #{post.issueid} in {session.context.title()}\n'[m
[32m+[m[32m elif not session.c_user:[m
[32m+[m[32m page += f'=> /{session.context.title()} Posted in: {session.context.title()}\n'[m
[32m+[m[32m page += poster_link[m
[32m+[m[32m last_age = post.age()[m
[32m+[m[32m page += f'{last_age}'[m
[32m+[m[32m if session.is_likes_enabled():[m
[32m+[m[32m liked = [][m
[32m+[m[32m if post.num_likes:[m
[32m+[m[32m liked = db.get_likes(post)[m
[32m+[m[32m page += ' ยท ๐ ' + ', '.join(liked)[m
[32m+[m[32m if session.is_reactions_enabled():[m
[32m+[m[32m reactions = db.get_reactions(post)[m
[32m+[m[32m listed = [][m
[32m+[m[32m for r in reactions:[m
[32m+[m[32m listed.append(f'{reactions[r]} {r}')[m
[32m+[m[32m if listed:[m
[32m+[m[32m page += ' ยท ' + ' '.join(listed)[m
page += '\n'[m
[31m- if post.tags:[m
[31m- page += '### ' + post.tags + '\n'[m
[31m- poster_link = f'=> /u/{post.poster_name} {post.poster_avatar} {post.poster_name}\n'[m
[31m- if session.is_context_tracker:[m
[31m- page += f'=> /{session.context.title()} ๐ Issue #{post.issueid} in {session.context.title()}\n'[m
[31m- elif not session.c_user:[m
[31m- page += f'=> /{session.context.title()} Posted in: {session.context.title()}\n'[m
[31m- page += poster_link[m
[31m- last_age = post.age()[m
[31m- page += f'{last_age}'[m
[31m- if session.is_likes_enabled():[m
[31m- liked = [][m
[31m- if post.num_likes:[m
[31m- liked = db.get_likes(post)[m
[31m- page += ' ยท ๐ ' + ', '.join(liked)[m
[31m- if session.is_reactions_enabled():[m
[31m- reactions = db.get_reactions(post)[m
[31m- listed = [][m
[31m- for r in reactions:[m
[31m- listed.append(f'{reactions[r]} {r}')[m
[31m- if listed:[m
[31m- page += ' ยท ' + ' '.join(listed)[m
[31m- page += '\n'[m
[m
[31m- # Post actions.[m
[31m- kind = 'issue' if session.is_context_tracker else 'post'[m
[31m- if session.user and not session.is_context_locked:[m
[31m- page += '\n## Actions\n'[m
[31m- if session.user.id == post.user or session.is_user_mod:[m
[32m+[m[32m # Post actions.[m
[32m+[m[32m kind = 'issue' if session.is_context_tracker else 'post'[m
[32m+[m[32m if session.user and not session.is_context_locked:[m
[32m+[m[32m page += '\n## Actions\n'[m
if session.is_editable(post):[m
page += f'=> /edit/{post.id} โ๏ธ Edit {kind}\n'[m
[31m- page += f'=> /comment/{post.id} ๐ฌ Comment\n'[m
[32m+[m[32m page += f'=> /comment/{post.id} ๐ฌ Comment\n'[m
[m
[31m- # Reactions.[m
[31m- if session.user.id != post.user:[m
[31m- if session.is_likes_enabled():[m
[31m- if session.user.name not in liked:[m
[31m- page += f'=> /like/{post.id} ๐ Like\n'[m
[31m- else:[m
[31m- page += f'=> /unlike/{post.id} ๐ Undo like\n'[m
[31m- if session.is_reactions_enabled():[m
[31m- reaction = db.get_user_reaction(post, session.user.id)[m
[31m- if reaction:[m
[31m- page += f'=> /react/{post.id} Change reaction: {reaction}\n'[m
[31m- else:[m
[31m- page += f'=> /react/{post.id} {session.bubble.user_reactions[0]} React\n'[m
[31m- if session.is_thanks_enabled():[m
[31m- page += f'=> /thanks/{post.id} ๐ Give thanks\n'[m
[32m+[m[32m # Reactions.[m
[32m+[m[32m if session.user.id != post.user:[m
[32m+[m[32m if session.is_likes_enabled():[m
[32m+[m[32m if session.user.name not in liked:[m
[32m+[m[32m page += f'=> /like/{post.id} ๐ Like\n'[m
[32m+[m[32m else:[m
[32m+[m[32m page += f'=> /unlike/{post.id} ๐ Undo like\n'[m
[32m+[m[32m if session.is_reactions_enabled():[m
[32m+[m[32m reaction = db.get_user_reaction(post, session.user.id)[m
[32m+[m[32m if reaction:[m
[32m+[m[32m page += f'=> /react/{post.id} Change reaction: {reaction}\n'[m
[32m+[m[32m else:[m
[32m+[m[32m page += f'=> /react/{post.id} {session.bubble.user_reactions[0]} React\n'[m
[32m+[m[32m if session.is_thanks_enabled():[m
[32m+[m[32m page += f'=> /thanks/{post.id} ๐ Give thanks\n'[m
[m
[31m- if session.user.id != post.user:[m
[31m- if (FOLLOW_POST, post.id) in session.user_follows:[m
[31m- page += f'=> /unfollow/post/{post.id} โ Unfollow {kind}\n'[m
[32m+[m[32m if session.user.id != post.user:[m
[32m+[m[32m if (FOLLOW_POST, post.id) in session.user_follows:[m
[32m+[m[32m page += f'=> /unfollow/post/{post.id} โ Unfollow {kind}\n'[m
[32m+[m[32m else:[m
[32m+[m[32m if (MUTE_POST, post.id) in session.user_mutes:[m
[32m+[m[32m page += f'=> /unmute/post/{post.id} ๐ Unmute {kind}\n'[m
[32m+[m[32m else:[m
[32m+[m[32m page += f'=> /follow/post/{post.id} โ Follow {kind}\n'[m
[32m+[m[32m page += f'=> /mute/post/{post.id} ๐ Mute {kind}\n'[m
else:[m
[32m+[m[32m # Own posts can be muted.[m
if (MUTE_POST, post.id) in session.user_mutes:[m
page += f'=> /unmute/post/{post.id} ๐ Unmute {kind}\n'[m
else:[m
[31m- page += f'=> /follow/post/{post.id} โ Follow {kind}\n'[m
page += f'=> /mute/post/{post.id} ๐ Mute {kind}\n'[m
[31m- else:[m
[31m- # Own posts can be muted.[m
[31m- if (MUTE_POST, post.id) in session.user_mutes:[m
[31m- page += f'=> /unmute/post/{post.id} ๐ Unmute {kind}\n'[m
[31m- else:[m
[31m- page += f'=> /mute/post/{post.id} ๐ Mute {kind}\n'[m
[m
[31m- # Moderator actions on a post.[m
[31m- mod_actions = [][m
[31m- if session.user.id == post.user or session.is_user_mod:[m
[31m- if session.is_context_tracker:[m
[31m- if 'โ๏ธ' in post.tags:[m
[31m- mod_actions.append(f'=> /edit-tags/{post.id}/open ๐ Reopen issue\n')[m
[31m- else:[m
[31m- mod_actions.append(f'=> /edit-tags/{post.id}/close โ๏ธ Mark as closed\n')[m
[31m- mod_actions.append(f'=> /edit-tags/{post.id} ๐ท๏ธ Add/remove tags\n')[m
[31m- if session.is_title_editable(post) and not session.is_editable(post):[m
[31m- mod_actions.append(f'=> /edit/{post.id}/mod-title โ๏ธ Edit {kind} title\n')[m
[31m- if session.is_movable(post):[m
[31m- mod_actions.append(f'=> /edit/{post.id}/move/{session.get_token()} Move to subspace\n')[m
[31m- if session.is_deletable(post) and not session.is_editable(post):[m
[31m- mod_actions.append(f'=> /edit/{post.id}/delete/{session.get_token()} โ Delete {kind}\n')[m
[31m- if session.user.id == post.user and post.sub_owner == post.user:[m
[31m- antenna_feed = f"gemini://{session.bubble.hostname}{session.path}u/{session.user.name}/{post.id}/antenna"[m
[31m- mod_actions.append(f'=> {session.bubble.antenna_url}?{urlparse.quote(antenna_feed)} Submit post to ๐ก Antenna\n')[m
[31m-[m
[31m- if mod_actions:[m
[31m- page += '\n' + ''.join(mod_actions)[m
[31m-[m
[31m- page += '\n' + session.dashboard_link()[m
[31m-[m
[31m- notifs = db.get_notifications(user=user, post_id=post.id)[m
[31m- if notifs:[m
[31m- page += f'{len(notifs)} notification{plural_s(len(notifs))} on this page:\n'[m
[31m- for notif in notifs:[m
[31m- link, label = notif.entry(with_title=False)[m
[31m- page += f'=> {link} {label}\n'[m
[31m- if len(notifs) > 1:[m
[31m- page += f'=> {post.page_url()}/clear-notif/{session.get_token()} ๐งน Clear\n'[m
[32m+[m[32m # Moderator actions on a post.[m
[32m+[m[32m mod_actions = [][m
[32m+[m[32m if session.user.id == post.user or session.is_user_mod:[m
[32m+[m[32m if session.is_context_tracker:[m
[32m+[m[32m if 'โ๏ธ' in post.tags:[m
[32m+[m[32m mod_actions.append(f'=> /edit-tags/{post.id}/open ๐ Reopen issue\n')[m
[32m+[m[32m else:[m
[32m+[m[32m mod_actions.append(f'=> /edit-tags/{post.id}/close โ๏ธ Mark as closed\n')[m
[32m+[m[32m mod_actions.append(f'=> /edit-tags/{post.id} ๐ท๏ธ Add/remove tags\n')[m
[32m+[m[32m if session.is_title_editable(post) and not session.is_editable(post):[m
[32m+[m[32m mod_actions.append(f'=> /edit/{post.id}/mod-title โ๏ธ Edit {kind} title\n')[m
[32m+[m[32m if session.is_movable(post):[m
[32m+[m[32m mod_actions.append(f'=> /edit/{post.id}/move/{session.get_token()} Move to subspace\n')[m
[32m+[m[32m if session.is_deletable(post) and not session.is_editable(post):[m
[32m+[m[32m mod_actions.append(f'=> /edit/{post.id}/delete/{session.get_token()} โ Delete {kind}\n')[m
[32m+[m[32m if session.user.id == post.user and post.sub_owner == post.user:[m
[32m+[m[32m antenna_feed = f"gemini://{session.bubble.hostname}{session.path}u/{session.user.name}/{post.id}/antenna"[m
[32m+[m[32m mod_actions.append(f'=> {session.bubble.antenna_url}?{urlparse.quote(antenna_feed)} Submit post to ๐ก Antenna\n')[m
[32m+[m
[32m+[m[32m if mod_actions:[m
[32m+[m[32m page += '\n' + ''.join(mod_actions)[m
[32m+[m
[32m+[m[32m page += '\n' + session.dashboard_link()[m
[32m+[m
[32m+[m[32m notifs = db.get_notifications(user=user, post_id=post.id)[m
[32m+[m[32m if notifs:[m
[32m+[m[32m page += f'{len(notifs)} notification{plural_s(len(notifs))} on this page:\n'[m
[32m+[m[32m for notif in notifs:[m
[32m+[m[32m link, label = notif.entry(with_title=False)[m
[32m+[m[32m page += f'=> {link} {label}\n'[m
[32m+[m[32m if len(notifs) > 1:[m
[32m+[m[32m page += f'=> {post.page_url()}/clear-notif/{session.get_token()} ๐งน Clear\n'[m
[m
# Comments, repository commits, and issue cross-references.[m
[31m- display_order_desc = session.user and \[m
[31m- session.user.sort_cmt == User.SORT_COMMENT_NEWEST[m
comments = db.get_posts(parent=post.id,[m
draft=False,[m
sort_descending=False,[m
muted_by_user_id=(user.id if user else 0),[m
limit=None)[m
[32m+[m
[32m+[m[32m if is_comment_page:[m
[32m+[m[32m # Omit comments older than the focused one.[m
[32m+[m[32m comments = list(filter(lambda p: p.ts_created > focused_cmt.ts_created, comments))[m
[32m+[m
n = len(comments)[m
if n > 0 or commits or incoming_xrefs:[m
if n > 1:[m
dir_icon = ' โ' if display_order_desc else ' โ'[m
else:[m
dir_icon = ''[m
[31m- page += f'\n## {n} Comment{plural_s(n)}{dir_icon}'[m
[32m+[m[32m page += f'\n## {n} {"Later " if is_comment_page else ""}Comment{plural_s(n)}{dir_icon}\n'[m
[m
if commits or incoming_xrefs:[m
# Combine commits and commits into one list.[m
[36m@@ -395,7 +428,7 @@[m [mdef make_post_page(session, post):[m
rendered_comments.append(cmt.incoming_entry())[m
continue[m
[m
[31m- src = f'=> /u/{cmt.poster_name} {cmt.poster_avatar} {cmt.poster_name}\n'[m
[32m+[m[32m src = f'=> /u/{cmt.poster_name}/{cmt.id} {cmt.poster_avatar} {cmt.poster_name}\n'[m
comment_body = session.render_post(cmt)[m
src += comment_body[m
[m
[36m@@ -435,10 +468,13 @@[m [mdef make_post_page(session, post):[m
for rendered in rendered_comments:[m
page += '\n' + rendered[m
[m
[32m+[m[32m if is_comment_page and display_order_desc:[m
[32m+[m[32m page += op_section[m
[32m+[m
# Show the Comment action at the appropriate place wrt reading direction.[m
if session.user and not session.is_context_locked and \[m
len(comments) >= 1 and not display_order_desc:[m
[31m- page += f'\n=> /comment/{post.id} ๐ฌ Comment\n'[m
[32m+[m[32m page += f'\n=> /comment/{post.id} ๐ฌ Add comment\n'[m
[m
return page[m
[m
[1mdiff --git a/model.py b/model.py[m
[1mindex c45808d..6c41874 100644[m
[1m--- a/model.py[m
[1m+++ b/model.py[m
[36m@@ -76,7 +76,7 @@[m [mclass Notification:[m
MENTION: 11[m
}[m
[m
[31m- def __init__(self, id, type, dst, src, post, subspace, is_sent, ts,[m
[32m+[m[32m def __init__(self, id, type, dst, src, post, subspace, comment, is_sent, ts,[m
src_name=None, post_title=None, post_issueid=None, post_summary=None,[m
post_subname=None, post_subowner=None, subname=None, reaction=None):[m
self.id = id[m
[36m@@ -85,6 +85,7 @@[m [mclass Notification:[m
self.src = src[m
self.post = post[m
self.subspace = subspace[m
[32m+[m[32m self.comment = comment[m
self.is_sent = is_sent[m
self.ts = ts[m
self.src_name = src_name[m
[36m@@ -503,6 +504,7 @@[m [mclass Database:[m
src INT,[m
post INT,[m
subspace INT,[m
[32m+[m[32m comment INT, -- if not NULL, notification is about a comment (can be linked to)[m
is_sent BOOLEAN DEFAULT FALSE,[m
is_hidden BOOLEAN DEFAULT FALSE,[m
ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP,[m
[36m@@ -1233,18 +1235,19 @@[m [mclass Database:[m
[m
self.notify_followers(user, parent_post.id,[m
Notification.COMMENT_IN_FOLLOWED_SUBSPACE,[m
[31m- FOLLOW_SUBSPACE, parent_post.subspace)[m
[32m+[m[32m FOLLOW_SUBSPACE, parent_post.subspace, comment_id=post.id)[m
self.notify_followers(user, parent_post.id,[m
Notification.COMMENT_BY_FOLLOWED_USER,[m
[31m- FOLLOW_USER, user.id)[m
[32m+[m[32m FOLLOW_USER, user.id, comment_id=post.id)[m
self.notify_followers(user, parent_post.id,[m
Notification.COMMENT_ON_FOLLOWED_POST,[m
[31m- FOLLOW_POST, parent_post.id)[m
[32m+[m[32m FOLLOW_POST, parent_post.id, comment_id=post.id)[m
[m
if parent_post.user != user.id:[m
# Notify post author of a new comment.[m
[31m- cur.execute("INSERT IGNORE INTO notifs (type, dst, src, post) VALUES (?, ?, ?, ?)",[m
[31m- (Notification.COMMENT, parent_post.user, user.id, parent_post.id))[m
[32m+[m[32m cur.execute("INSERT IGNORE INTO notifs (type, dst, src, post, comment) "[m
[32m+[m[32m "VALUES (?, ?, ?, ?, ?)",[m
[32m+[m[32m (Notification.COMMENT, parent_post.user, user.id, parent_post.id, post.id))[m
[m
self.commit()[m
[m
[36m@@ -1746,9 +1749,9 @@[m [mclass Database:[m
notif_post_id = post.parent if post.parent else post.id[m
where_names_cond = f"name IN ({('?,' * len(names))[:-1]})"[m
cur.execute(f"""[m
[31m- INSERT IGNORE INTO notifs (type, dst, src, post)[m
[32m+[m[32m INSERT IGNORE INTO notifs (type, dst, src, post, comment)[m
SELECT[m
[31m- {Notification.MENTION}, id, {post.user}, {notif_post_id}[m
[32m+[m[32m {Notification.MENTION}, id, {post.user}, {notif_post_id}, {post.id if post.parent else "NULL"}[m
FROM users[m
WHERE id!={post.user} AND {where_names_cond}[m
""", names)[m
[36m@@ -1768,24 +1771,27 @@[m [mclass Database:[m
for (i,) in cur: uids.append(i)[m
for uid in uids:[m
cur.execute("""[m
[31m- INSERT IGNORE INTO notifs (type, dst, src, post)[m
[31m- VALUES (?, ?, ?, ?)[m
[31m- """, (Notification.COMMENT_ON_COMMENTED, uid, new_comment.user, new_comment.parent))[m
[32m+[m[32m INSERT IGNORE INTO notifs (type, dst, src, post, comment)[m
[32m+[m[32m VALUES (?, ?, ?, ?, ?)[m
[32m+[m[32m """, (Notification.COMMENT_ON_COMMENTED, uid, new_comment.user, new_comment.parent,[m
[32m+[m[32m new_comment.id))[m
if uids:[m
self.commit()[m
[m
[31m- def notify_followers(self, actor: User, post_id, notif_type, follow_type, target_id):[m
[32m+[m[32m def notify_followers(self, actor: User, post_id, notif_type, follow_type, target_id,[m
[32m+[m[32m comment_id=None):[m
cur = self.conn.cursor()[m
cur.execute(f"""[m
[31m- INSERT IGNORE INTO notifs (type, dst, src, post)[m
[32m+[m[32m INSERT IGNORE INTO notifs (type, dst, src, post, comment)[m
SELECT[m
{notif_type},[m
user,[m
{actor.id},[m
[31m- {post_id}[m
[32m+[m[32m {post_id},[m
[32m+[m[32m ?[m
FROM follow[m
WHERE type={follow_type} AND target={target_id}[m
[31m- """)[m
[32m+[m[32m """, (comment_id,))[m
self.commit()[m
[m
def notify_thanks(self, user: User, post: Post):[m
[36m@@ -1980,8 +1986,12 @@[m [mclass Database:[m
cur = self.conn.cursor()[m
cur.execute(f"""[m
SELECT[m
[31m- n.id, n.type, n.dst, n.src, n.post, n.subspace, n.is_sent, UNIX_TIMESTAMP(n.ts),[m
[31m- u.name, p.title, p.issueid, p.summary, s.name, s.owner, s2.name, r.reaction[m
[32m+[m[32m n.id, n.type, n.dst, n.src, n.post, n.subspace, n.comment, n.is_sent, UNIX_TIMESTAMP(n.ts),[m
[32m+[m[32m u.name,[m
[32m+[m[32m p.title, p.issueid, p.summary,[m
[32m+[m[32m s.name, s.owner,[m
[32m+[m[32m s2.name,[m
[32m+[m[32m r.reaction[m
FROM notifs n[m
JOIN users u ON src=u.id[m
LEFT JOIN posts p ON post=p.id[m
[36m@@ -1996,9 +2006,9 @@[m [mclass Database:[m
WHERE {' AND '.join(cond)}[m
""", tuple(values))[m
notifs = [][m
[31m- for (id, type, dst, src, post, subspace, is_sent, ts, src_name, post_title, post_issueid,[m
[32m+[m[32m for (id, type, dst, src, post, subspace, comment, is_sent, ts, src_name, post_title, post_issueid,[m
post_summary, post_subname, post_subowner, subname, reaction) in cur:[m
[31m- notifs.append(Notification(id, type, dst, src, post, subspace, is_sent, ts,[m
[32m+[m[32m notifs.append(Notification(id, type, dst, src, post, subspace, comment, is_sent, ts,[m
src_name, post_title, post_issueid, post_summary,[m
post_subname, post_subowner, subname, reaction))[m
[m
[1mdiff --git a/user.py b/user.py[m
[1mindex 29490aa..fdea442 100644[m
[1m--- a/user.py[m
[1m+++ b/user.py[m
[36m@@ -174,12 +174,17 @@[m [mdef user_actions(session):[m
notif = db.get_notification(session.user, notif_id, clear=True)[m
if not notif:[m
return 30, '/dashboard'[m
[32m+[m[32m if notif.comment:[m
[32m+[m[32m cmt = db.get_post(id=notif.comment)[m
[32m+[m[32m if not cmt:[m
[32m+[m[32m return 51, 'Not found'[m
[32m+[m[32m return 30, cmt.page_url()[m
if notif.post:[m
post = db.get_post(id=notif.post)[m
if not post:[m
return 51, 'Not found'[m
return 30, post.page_url()[m
[31m- elif notif.subspace:[m
[32m+[m[32m if notif.subspace:[m
subs = db.get_subspace(id=notif.subspace)[m
if not subs:[m
return 51, 'Not found'[m