Fix approved filtered comments not notifying.
Moves behavior in api_comment that updates stateful counters and generates notifications into a function which can also be called if a filtered comment is approved. Fixes #272. Incidentally, also fixes #278 by adding another filter to the post subscribers query during general clean-up/refactoring. Originally was going to move this function into the Comments model, since assurances about state (even with side effects) should probably be made there, but I couldn't find a sane way to untangle the imports.
This commit is contained in:
parent
0ec522d897
commit
f5f2c008ad
3 changed files with 84 additions and 58 deletions
|
@ -13,6 +13,7 @@ from files.classes import *
|
||||||
from flask import *
|
from flask import *
|
||||||
from files.__main__ import app, cache, limiter
|
from files.__main__ import app, cache, limiter
|
||||||
from .front import frontlist
|
from .front import frontlist
|
||||||
|
from files.routes.comments import comment_on_publish
|
||||||
from files.helpers.discord import add_role
|
from files.helpers.discord import add_role
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
import requests
|
import requests
|
||||||
|
@ -426,13 +427,25 @@ def update_filter_status(v):
|
||||||
return { 'result': f'Status of {new_status} is not permitted' }
|
return { 'result': f'Status of {new_status} is not permitted' }
|
||||||
|
|
||||||
if post_id:
|
if post_id:
|
||||||
rows_updated = g.db.query(Submission).where(Submission.id == post_id).update({Submission.filter_state: new_status})
|
p = g.db.query(Submission).get(post_id)
|
||||||
|
old_status = p.filter_state
|
||||||
|
rows_updated = g.db.query(Submission).where(Submission.id == post_id) \
|
||||||
|
.update({Submission.filter_state: new_status})
|
||||||
elif comment_id:
|
elif comment_id:
|
||||||
rows_updated = g.db.query(Comment).where(Comment.id == comment_id).update({Comment.filter_state: new_status})
|
c = g.db.query(Comment).get(comment_id)
|
||||||
|
old_status = c.filter_state
|
||||||
|
rows_updated = g.db.query(Comment).where(Comment.id == comment_id) \
|
||||||
|
.update({Comment.filter_state: new_status})
|
||||||
else:
|
else:
|
||||||
return { 'result': f'No valid item ID provided' }
|
return { 'result': f'No valid item ID provided' }
|
||||||
|
|
||||||
if rows_updated == 1:
|
if rows_updated == 1:
|
||||||
|
# If comment now visible, update state to reflect publication.
|
||||||
|
if (comment_id
|
||||||
|
and old_status in ['filtered', 'removed']
|
||||||
|
and new_status in ['normal', 'ignored']):
|
||||||
|
comment_on_publish(c)
|
||||||
|
|
||||||
g.db.commit()
|
g.db.commit()
|
||||||
return { 'result': 'Update successful' }
|
return { 'result': 'Update successful' }
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -3,7 +3,6 @@ from files.helpers.alerts import *
|
||||||
from files.helpers.images import *
|
from files.helpers.images import *
|
||||||
from files.helpers.const import *
|
from files.helpers.const import *
|
||||||
from files.classes import *
|
from files.classes import *
|
||||||
from files.routes.front import comment_idlist
|
|
||||||
from pusher_push_notifications import PushNotifications
|
from pusher_push_notifications import PushNotifications
|
||||||
from flask import *
|
from flask import *
|
||||||
from files.__main__ import app, limiter
|
from files.__main__ import app, limiter
|
||||||
|
@ -317,37 +316,14 @@ def api_comment(v):
|
||||||
if c.level == 1: c.top_comment_id = c.id
|
if c.level == 1: c.top_comment_id = c.id
|
||||||
else: c.top_comment_id = parent.top_comment_id
|
else: c.top_comment_id = parent.top_comment_id
|
||||||
|
|
||||||
if parent_post.id not in ADMINISTRATORS:
|
if not v.shadowbanned and not is_filtered:
|
||||||
if not v.shadowbanned and not is_filtered:
|
comment_on_publish(c)
|
||||||
notify_users = NOTIFY_USERS(body, v)
|
|
||||||
|
|
||||||
for x in g.db.query(Subscription.user_id).filter_by(submission_id=c.parent_submission).all(): notify_users.add(x[0])
|
|
||||||
|
|
||||||
if parent.author.id not in (v.id, BASEDBOT_ID, AUTOJANNY_ID, SNAPPY_ID, LONGPOSTBOT_ID, ZOZBOT_ID):
|
|
||||||
notify_users.add(parent.author.id)
|
|
||||||
|
|
||||||
for x in notify_users:
|
|
||||||
n = Notification(comment_id=c.id, user_id=x)
|
|
||||||
g.db.add(n)
|
|
||||||
|
|
||||||
if parent.author.id != v.id and PUSHER_ID != 'blahblahblah' and not v.shadowbanned:
|
|
||||||
try: gevent.spawn(pusher_thread, f'{request.host}{parent.author.id}', c, c.author_name)
|
|
||||||
except: pass
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
vote = CommentVote(user_id=v.id,
|
vote = CommentVote(user_id=v.id,
|
||||||
comment_id=c.id,
|
comment_id=c.id,
|
||||||
vote_type=1,
|
vote_type=1,
|
||||||
)
|
)
|
||||||
|
|
||||||
g.db.add(vote)
|
g.db.add(vote)
|
||||||
|
|
||||||
|
|
||||||
cache.delete_memoized(comment_idlist)
|
|
||||||
|
|
||||||
v.comment_count = g.db.query(Comment.id).filter(Comment.author_id == v.id, Comment.parent_submission != None).filter_by(is_banned=False, deleted_utc=0).count()
|
|
||||||
g.db.add(v)
|
|
||||||
|
|
||||||
c.voted = 1
|
c.voted = 1
|
||||||
|
|
||||||
|
@ -364,15 +340,68 @@ def api_comment(v):
|
||||||
if v.marseyawarded and parent_post.id not in ADMINISTRATORS and marseyaward_body_regex.search(body_html):
|
if v.marseyawarded and parent_post.id not in ADMINISTRATORS and marseyaward_body_regex.search(body_html):
|
||||||
return {"error":"You can only type marseys!"}, 403
|
return {"error":"You can only type marseys!"}, 403
|
||||||
|
|
||||||
parent_post.comment_count += 1
|
|
||||||
g.db.add(parent_post)
|
|
||||||
|
|
||||||
g.db.commit()
|
g.db.commit()
|
||||||
|
|
||||||
if request.headers.get("Authorization"): return c.json
|
if request.headers.get("Authorization"): return c.json
|
||||||
return {"comment": render_template("comments.html", v=v, comments=[c], ajax=True)}
|
return {"comment": render_template("comments.html", v=v, comments=[c], ajax=True)}
|
||||||
|
|
||||||
|
|
||||||
|
def comment_on_publish(comment):
|
||||||
|
"""
|
||||||
|
Run when comment becomes visible: immediately for non-filtered comments,
|
||||||
|
or on approval for previously filtered comments.
|
||||||
|
Should be used to update stateful counters, notifications, etc. that
|
||||||
|
reflect the comments users will actually see.
|
||||||
|
"""
|
||||||
|
# TODO: Get this out of the routes and into a model eventually...
|
||||||
|
|
||||||
|
# Shadowbanned users are invisible. This may lead to inconsistencies if
|
||||||
|
# a user comments while shadowed and is later unshadowed. (TODO?)
|
||||||
|
if comment.author.shadowbanned:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Comment instances used for purposes other than actual comments (notifs,
|
||||||
|
# DMs) shouldn't be considered published.
|
||||||
|
if not comment.parent_submission:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Generate notifs for: mentions, post subscribers, parent post/comment
|
||||||
|
to_notify = NOTIFY_USERS(comment.body, comment.author)
|
||||||
|
|
||||||
|
post_subscribers = g.db.query(Subscription.user_id).filter(
|
||||||
|
Subscription.submission_id == comment.parent_submission,
|
||||||
|
Subscription.user_id != comment.author_id,
|
||||||
|
).all()
|
||||||
|
to_notify.update([x[0] for x in post_subscribers])
|
||||||
|
|
||||||
|
parent = comment.parent
|
||||||
|
if parent and parent.author_id != comment.author_id:
|
||||||
|
to_notify.add(parent.author_id)
|
||||||
|
|
||||||
|
for uid in to_notify:
|
||||||
|
notif = Notification(comment_id=comment.id, user_id=uid)
|
||||||
|
g.db.add(notif)
|
||||||
|
|
||||||
|
# Comment counter for parent submission
|
||||||
|
comment.post.comment_count += 1
|
||||||
|
g.db.add(comment.post)
|
||||||
|
|
||||||
|
# Comment counter for author's profile
|
||||||
|
comment.author.comment_count = g.db.query(Comment).filter(
|
||||||
|
Comment.author_id == comment.author_id,
|
||||||
|
Comment.parent_submission != None,
|
||||||
|
Comment.is_banned == False,
|
||||||
|
Comment.deleted_utc == 0,
|
||||||
|
).count()
|
||||||
|
g.db.add(comment.author)
|
||||||
|
|
||||||
|
# Generate push notifications if enabled.
|
||||||
|
if PUSHER_ID != 'blahblahblah' and comment.author_id != parent.author_id:
|
||||||
|
try:
|
||||||
|
gevent.spawn(pusher_thread, f'{request.host}{parent.author.id}',
|
||||||
|
comment, comment.author_name)
|
||||||
|
except: pass
|
||||||
|
|
||||||
|
|
||||||
@app.post("/edit_comment/<cid>")
|
@app.post("/edit_comment/<cid>")
|
||||||
@limiter.limit("1/second;30/minute;200/hour;1000/day")
|
@limiter.limit("1/second;30/minute;200/hour;1000/day")
|
||||||
|
@ -467,13 +496,15 @@ def edit_comment(cid, v):
|
||||||
|
|
||||||
g.db.add(c)
|
g.db.add(c)
|
||||||
|
|
||||||
notify_users = NOTIFY_USERS(body, v)
|
if c.filter_state != 'filtered':
|
||||||
|
notify_users = NOTIFY_USERS(body, v)
|
||||||
for x in notify_users:
|
|
||||||
notif = g.db.query(Notification).filter_by(comment_id=c.id, user_id=x).one_or_none()
|
for x in notify_users:
|
||||||
if not notif:
|
notif = g.db.query(Notification) \
|
||||||
n = Notification(comment_id=c.id, user_id=x)
|
.filter_by(comment_id=c.id, user_id=x).one_or_none()
|
||||||
g.db.add(n)
|
if not notif:
|
||||||
|
n = Notification(comment_id=c.id, user_id=x)
|
||||||
|
g.db.add(n)
|
||||||
|
|
||||||
g.db.commit()
|
g.db.commit()
|
||||||
|
|
||||||
|
@ -494,9 +525,6 @@ def delete_comment(cid, v):
|
||||||
c.deleted_utc = int(time.time())
|
c.deleted_utc = int(time.time())
|
||||||
|
|
||||||
g.db.add(c)
|
g.db.add(c)
|
||||||
|
|
||||||
cache.delete_memoized(comment_idlist)
|
|
||||||
|
|
||||||
g.db.commit()
|
g.db.commit()
|
||||||
|
|
||||||
return {"message": "Comment deleted!"}
|
return {"message": "Comment deleted!"}
|
||||||
|
@ -514,9 +542,6 @@ def undelete_comment(cid, v):
|
||||||
c.deleted_utc = 0
|
c.deleted_utc = 0
|
||||||
|
|
||||||
g.db.add(c)
|
g.db.add(c)
|
||||||
|
|
||||||
cache.delete_memoized(comment_idlist)
|
|
||||||
|
|
||||||
g.db.commit()
|
g.db.commit()
|
||||||
|
|
||||||
return {"message": "Comment undeleted!"}
|
return {"message": "Comment undeleted!"}
|
||||||
|
|
|
@ -490,8 +490,6 @@ def random_user(v):
|
||||||
@app.get("/comments")
|
@app.get("/comments")
|
||||||
@auth_required
|
@auth_required
|
||||||
def all_comments(v):
|
def all_comments(v):
|
||||||
|
|
||||||
|
|
||||||
try: page = max(int(request.values.get("page", 1)), 1)
|
try: page = max(int(request.values.get("page", 1)), 1)
|
||||||
except: page = 1
|
except: page = 1
|
||||||
|
|
||||||
|
@ -504,15 +502,7 @@ def all_comments(v):
|
||||||
try: lt=int(request.values.get("before", 0))
|
try: lt=int(request.values.get("before", 0))
|
||||||
except: lt=0
|
except: lt=0
|
||||||
|
|
||||||
idlist = comment_idlist(v=v,
|
idlist = get_comments_idlist(v=v, page=page, sort=sort, t=t, gt=gt, lt=lt)
|
||||||
page=page,
|
|
||||||
sort=sort,
|
|
||||||
t=t,
|
|
||||||
gt=gt,
|
|
||||||
lt=lt,
|
|
||||||
site=SITE
|
|
||||||
)
|
|
||||||
|
|
||||||
comments = get_comments(idlist, v=v)
|
comments = get_comments(idlist, v=v)
|
||||||
|
|
||||||
next_exists = len(idlist) > 25
|
next_exists = len(idlist) > 25
|
||||||
|
@ -523,9 +513,7 @@ def all_comments(v):
|
||||||
return render_template("home_comments.html", v=v, sort=sort, t=t, page=page, comments=comments, standalone=True, next_exists=next_exists)
|
return render_template("home_comments.html", v=v, sort=sort, t=t, page=page, comments=comments, standalone=True, next_exists=next_exists)
|
||||||
|
|
||||||
|
|
||||||
|
def get_comments_idlist(page=1, v=None, sort="new", t="all", gt=0, lt=0):
|
||||||
@cache.memoize(timeout=86400)
|
|
||||||
def comment_idlist(page=1, v=None, nsfw=False, sort="new", t="all", gt=0, lt=0, site=None):
|
|
||||||
comments = g.db.query(Comment.id) \
|
comments = g.db.query(Comment.id) \
|
||||||
.join(Comment.post) \
|
.join(Comment.post) \
|
||||||
.join(Comment.author) \
|
.join(Comment.author) \
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue