def post_comment_reply(request: Request, markdown: str) -> dict: """Post a reply to a comment with Intercooler.""" parent_comment = request.context new_comment = Comment( topic=parent_comment.topic, author=request.user, markdown=markdown, parent_comment=parent_comment, ) request.db_session.add(new_comment) request.db_session.add( LogComment(LogEventType.COMMENT_POST, request, new_comment)) if CommentNotification.should_create_reply_notification(new_comment): notification = CommentNotification( parent_comment.user, new_comment, CommentNotificationType.COMMENT_REPLY) request.db_session.add(notification) _mark_comment_read_from_interaction(request, parent_comment) # commit and then re-query the new comment to get complete data request.tm.commit() new_comment = (request.query(Comment).join_all_relationships().filter_by( comment_id=new_comment.comment_id).one()) return {"comment": new_comment}
def post_toplevel_comment(request: Request, markdown: str) -> dict: """Post a new top-level comment on a topic with Intercooler.""" topic = request.context new_comment = Comment(topic=topic, author=request.user, markdown=markdown) request.db_session.add(new_comment) request.db_session.add(LogComment(LogEventType.COMMENT_POST, request, new_comment)) if CommentNotification.should_create_reply_notification(new_comment): notification = CommentNotification( topic.user, new_comment, CommentNotificationType.TOPIC_REPLY ) request.db_session.add(notification) # commit and then re-query the new comment to get complete data request.tm.commit() new_comment = ( request.query(Comment) .join_all_relationships() .filter_by(comment_id=new_comment.comment_id) .one() ) return {"comment": new_comment, "topic": topic}
def test_prevent_duplicate_notifications(db, user_list, topic): """Test that notifications are cleaned up for edits. Flow: 1. A comment is created by user A that mentions user B. Notifications are generated, and yield A mentioning B. 2. The comment is edited to mention C and not B. 3. The comment is edited to mention B and C. 4. The comment is deleted. """ # 1 comment = Comment(topic, user_list[0], f"@{user_list[1].username}") db.add(comment) db.commit() mentions = CommentNotification.get_mentions_for_comment(db, comment) assert len(mentions) == 1 assert mentions[0].user == user_list[1] db.add_all(mentions) db.commit() # 2 comment.markdown = f"@{user_list[2].username}" db.commit() mentions = CommentNotification.get_mentions_for_comment(db, comment) assert len(mentions) == 1 to_delete, to_add = CommentNotification.prevent_duplicate_notifications( db, comment, mentions) assert len(to_delete) == 1 assert mentions == to_add assert to_delete[0].user.username == user_list[1].username # 3 comment.markdown = f"@{user_list[1].username} @{user_list[2].username}" db.commit() mentions = CommentNotification.get_mentions_for_comment(db, comment) assert len(mentions) == 2 to_delete, to_add = CommentNotification.prevent_duplicate_notifications( db, comment, mentions) assert not to_delete assert len(to_add) == 1 # 4 comment.is_deleted = True db.commit() notifications = (db.query(CommentNotification.user_id).filter( and_( CommentNotification.comment_id == comment.comment_id, CommentNotification.notification_type == CommentNotificationType.USER_MENTION, )).all()) assert not notifications
def post_comment_on_topic(request: Request, markdown: str) -> HTTPFound: """Post a new top-level comment on a topic.""" topic = request.context new_comment = Comment(topic=topic, author=request.user, markdown=markdown) request.db_session.add(new_comment) request.db_session.add( LogComment(LogEventType.COMMENT_POST, request, new_comment)) if CommentNotification.should_create_reply_notification(new_comment): notification = CommentNotification(topic.user, new_comment, CommentNotificationType.TOPIC_REPLY) request.db_session.add(notification) raise HTTPFound(location=topic.permalink)
def test_mention_filtering_top_level(db, user_list, session_group): """Test notification filtering for top-level comments.""" topic = Topic.create_text_topic(session_group, user_list[0], "Some title", "some text") comment = Comment(topic, user_list[1], f"@{user_list[0].username}") mentions = CommentNotification.get_mentions_for_comment(db, comment) assert not mentions
def test_mention_filtering_parent_comment(db, topic, user_list): """Test notification filtering for parent comments.""" parent_comment = Comment(topic, user_list[0], "Comment content.") comment = Comment(topic, user_list[1], f"@{user_list[0].username}", parent_comment) mentions = CommentNotification.get_mentions_for_comment(db, comment) assert not mentions
def test_get_mentions_for_comment_escapes_with_backslash( db, user_list, comment): """Test that backslash escaped mentions are ignored.""" comment.markdown = "@foo @bar. \@baz!" mentions = CommentNotification.get_mentions_for_comment(db, comment) assert len(mentions) == 2 assert "baz" not in [mention.user for mention in mentions]
def test_get_mentions_for_comment(db, user_list, comment): """Test that notifications are generated and returned.""" comment.markdown = "@foo @bar. @baz!" mentions = CommentNotification.get_mentions_for_comment(db, comment) assert len(mentions) == 3 for index, user in enumerate(user_list): assert mentions[index].user == user
def post_comment_reply(request: Request, markdown: str) -> dict: """Post a reply to a comment with Intercooler.""" parent_comment = request.context new_comment = Comment( topic=parent_comment.topic, author=request.user, markdown=markdown, parent_comment=parent_comment, ) request.db_session.add(new_comment) if parent_comment.user != request.user: notification = CommentNotification( parent_comment.user, new_comment, CommentNotificationType.COMMENT_REPLY, ) request.db_session.add(notification) # commit and then re-query the new comment to get complete data request.tm.commit() new_comment = (request.query(Comment).join_all_relationships().filter_by( comment_id=new_comment.comment_id).one()) return {'comment': new_comment}
def post_toplevel_comment(request: Request, markdown: str) -> dict: """Post a new top-level comment on a topic with Intercooler.""" topic = request.context new_comment = Comment( topic=topic, author=request.user, markdown=markdown, ) request.db_session.add(new_comment) if topic.user != request.user and not topic.is_deleted: notification = CommentNotification( topic.user, new_comment, CommentNotificationType.TOPIC_REPLY, ) request.db_session.add(notification) # commit and then re-query the new comment to get complete data request.tm.commit() new_comment = (request.query(Comment).join_all_relationships().filter_by( comment_id=new_comment.comment_id).one()) return {'comment': new_comment, 'topic': topic}
def test_mention_filtering_parent_comment(mocker, db, topic, user_list): """Test notification filtering for parent comments.""" parent_comment = Comment(topic, user_list[0], "Comment content.") parent_comment.user_id = user_list[0].user_id comment = mocker.Mock( user_id=user_list[1].user_id, markdown=f"@{user_list[0].username}", parent_comment=parent_comment, ) mentions = CommentNotification.get_mentions_for_comment(db, comment) assert not mentions
def post_comment_reply(request: Request, markdown: str) -> dict: """Post a reply to a comment with Intercooler.""" parent_comment = request.context wait_mins = _reply_wait_minutes(request, request.user, parent_comment.user) if wait_mins: incr_counter("comment_back_and_forth_warnings") raise HTTPUnprocessableEntity( f"You can't reply to this user yet. Please wait {wait_mins} minutes." ) new_comment = Comment( topic=parent_comment.topic, author=request.user, markdown=markdown, parent_comment=parent_comment, ) request.db_session.add(new_comment) request.db_session.add( LogComment(LogEventType.COMMENT_POST, request, new_comment)) if CommentNotification.should_create_reply_notification(new_comment): notification = CommentNotification( parent_comment.user, new_comment, CommentNotificationType.COMMENT_REPLY) request.db_session.add(notification) _mark_comment_read_from_interaction(request, parent_comment) # commit and then re-query the new comment to get complete data request.tm.commit() new_comment = (request.query(Comment).join_all_relationships().filter_by( comment_id=new_comment.comment_id).one()) return {"comment": new_comment}
def process_message(self, message: Message) -> None: """Process a message from the stream.""" comment = (self.db_session.query(Comment).filter_by( comment_id=message.fields["comment_id"]).one()) # don't generate mentions for deleted/removed comments if comment.is_deleted or comment.is_removed: return new_mentions = CommentNotification.get_mentions_for_comment( self.db_session, comment) if message.stream == "comments.insert": for user_mention in new_mentions: self.db_session.add(user_mention) elif message.stream == "comments.update.markdown": to_delete, to_add = CommentNotification.prevent_duplicate_notifications( self.db_session, comment, new_mentions) for user_mention in to_delete: self.db_session.delete(user_mention) for user_mention in to_add: self.db_session.add(user_mention)
def run(self, msg: Message) -> None: """Process a delivered message.""" comment = (self.db_session.query(Comment).filter_by( comment_id=msg.body["comment_id"]).one()) # don't generate mentions for deleted/removed comments if comment.is_deleted or comment.is_removed: return new_mentions = CommentNotification.get_mentions_for_comment( self.db_session, comment) if msg.delivery_info["routing_key"] == "comment.created": for user_mention in new_mentions: self.db_session.add(user_mention) elif msg.delivery_info["routing_key"] == "comment.edited": to_delete, to_add = CommentNotification.prevent_duplicate_notifications( self.db_session, comment, new_mentions) for user_mention in to_delete: self.db_session.delete(user_mention) for user_mention in to_add: self.db_session.add(user_mention)
def post_comment_on_topic(request: Request, markdown: str) -> HTTPFound: """Post a new top-level comment on a topic.""" topic = request.context new_comment = Comment( topic=topic, author=request.user, markdown=markdown, ) request.db_session.add(new_comment) if topic.user != request.user and not topic.is_deleted: notification = CommentNotification( topic.user, new_comment, CommentNotificationType.TOPIC_REPLY, ) request.db_session.add(notification) raise HTTPFound(location=topic.permalink)
def test_mention_filtering_self_mention(db, user_list, topic): """Test notification filtering for self-mentions.""" comment = Comment(topic, user_list[0], f"@{user_list[0]}") mentions = CommentNotification.get_mentions_for_comment(db, comment) assert not mentions