from pusher_push_notifications import PushNotifications from files.classes import Comment, Notification, Subscription from files.helpers.alerts import NOTIFY_USERS from files.helpers.const import PUSHER_ID, PUSHER_KEY, SITE_ID, SITE_FULL from files.helpers.assetcache import assetcache_path from flask import g from sys import stdout import gevent if PUSHER_ID != 'blahblahblah': beams_client = PushNotifications(instance_id=PUSHER_ID, secret_key=PUSHER_KEY) def pusher_thread(interests, c, username): if len(c.body) > 500: notifbody = c.body[:500] + '...' else: notifbody = c.body beams_client.publish_to_interests( interests=[interests], publish_body={ 'web': { 'notification': { 'title': f'New reply by @{username}', 'body': notifbody, 'deep_link': f'{SITE_FULL}/comment/{c.id}?context=8&read=true#context', 'icon': SITE_FULL + assetcache_path(f'images/{SITE_ID}/icon.webp'), } }, 'fcm': { 'notification': { 'title': f'New reply by @{username}', 'body': notifbody, }, 'data': { 'url': f'/comment/{c.id}?context=8&read=true#context', } } }, ) stdout.flush() def update_stateful_counters(comment, delta): """ When a comment changes publish status, we need to update all affected stateful comment counters (e.g. author comment count, post comment count) """ update_post_comment_count(comment, delta) update_author_comment_count(comment, delta) update_ancestor_descendant_counts(comment, delta) def update_post_comment_count(comment, delta): author = comment.author comment.post.comment_count += delta g.db.add(comment.post) def update_author_comment_count(comment, delta): author = comment.author 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) def update_ancestor_descendant_counts(comment, delta): parent = comment.parent_comment_writable if parent is None: return parent.descendant_count += delta g.db.add(parent) update_ancestor_descendant_counts(parent, delta) def comment_on_publish(comment: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... author = comment.author # Shadowbanned users are invisible. This may lead to inconsistencies if # a user comments while shadowed and is later unshadowed. (TODO?) if 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 and not parent.author.is_blocking(author): to_notify.add(parent.author_id) for uid in to_notify: notif = Notification(comment_id=comment.id, user_id=uid) g.db.add(notif) update_stateful_counters(comment, +1) # 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 def comment_on_unpublish(comment:Comment): """ Run when a comment becomes invisible: when a moderator makes the comment non-visible by changing the filter_state to "removed", or when the user deletes the comment. Should be used to update stateful counters, notifications, etc. that reflect the comments users will actually see. """ update_stateful_counters(comment, -1)