From 18e80707cfd11618d67010a5ff571acf907bbc18 Mon Sep 17 00:00:00 2001 From: James Southern Date: Mon, 6 Aug 2018 16:09:10 +0100 Subject: [PATCH] Add mark all read button to unread notifications This will only mark notifications upto the timestamp of the last one shown on the unread_notifications page where it was clicked --- .../templates/notifications_unread.jinja2 | 15 ++- tildes/tildes/views/api/web/comment.py | 110 +++++++++++++----- 2 files changed, 93 insertions(+), 32 deletions(-) diff --git a/tildes/tildes/templates/notifications_unread.jinja2 b/tildes/tildes/templates/notifications_unread.jinja2 index b580f1f..e05eece 100644 --- a/tildes/tildes/templates/notifications_unread.jinja2 +++ b/tildes/tildes/templates/notifications_unread.jinja2 @@ -5,7 +5,20 @@ {% block title %}Unread notifications{% endblock %} -{% block main_heading %}Unread notifications{% endblock %} +{% block main_heading %}Unread notifications + {% if notifications and not request.user.auto_mark_notifications_read %} + + {% endif %} + +{% endblock %} {% block content %} {% if notifications %} diff --git a/tildes/tildes/views/api/web/comment.py b/tildes/tildes/views/api/web/comment.py index 412ec33..ad04b09 100644 --- a/tildes/tildes/views/api/web/comment.py +++ b/tildes/tildes/views/api/web/comment.py @@ -1,9 +1,12 @@ """Web API endpoints related to comments.""" +from marshmallow.fields import String +from marshmallow.validate import OneOf from pyramid.request import Request from pyramid.response import Response from sqlalchemy.dialects.postgresql import insert from sqlalchemy.exc import IntegrityError +from sqlalchemy.orm import joinedload from sqlalchemy.orm.exc import FlushError from webargs.pyramidparser import use_kwargs from zope.sqlalchemy import mark_changed @@ -22,6 +25,40 @@ from tildes.views import IC_NOOP from tildes.views.decorators import ic_view_config +def _increment_topic_comments_seen( + request: Request, + comment: Comment, +) -> None: + """If the user has the "track comment visits" feature enabled, we want to + increment the number of comments they've seen in the thread that the + comment came from, so that they don't *both* get a notification as well as + have the thread highlight with "(1 new)". This should only happen if their + last visit was before the comment was posted, however. Below, this is + implemented as a INSERT ... ON CONFLICT DO UPDATE so that it will insert + a new topic visit with 1 comment if they didn't previously have one at + all. """ + if request.user.track_comment_visits: + statement = ( + insert(TopicVisit.__table__) + .values( + user_id=request.user.user_id, + topic_id=comment.topic_id, + visit_time=utc_now(), + num_comments=1, + ) + .on_conflict_do_update( + constraint=TopicVisit.__table__.primary_key, + set_={'num_comments': TopicVisit.num_comments + 1}, + where=TopicVisit.visit_time < comment.created_time, + ) + ) + + request.db_session.execute(statement) + mark_changed(request.db_session) + + return + + @ic_view_config( route_name='topic_comments', request_method='POST', @@ -287,41 +324,52 @@ def untag_comment(request: Request, name: CommentTagOption) -> Response: request_method='PUT', permission='mark_read', ) -def mark_read_comment(request: Request) -> Response: +@use_kwargs({ + 'clear_all_previous': String( + load_from='mark_all_previous', + validate=OneOf(('true', 'false')), + ), +}) +def put_mark_comments_read( + request: Request, + clear_all_previous: str = 'false' +) -> Response: """Mark a comment read (clear all notifications).""" comment = request.context - request.query(CommentNotification).filter( - CommentNotification.user == request.user, - CommentNotification.comment == comment, - ).update( - {CommentNotification.is_unread: False}, synchronize_session=False) - - # If the user has the "track comment visits" feature enabled, we want to - # increment the number of comments they've seen in the thread that the - # comment came from, so that they don't *both* get a notification as well - # as have the thread highlight with "(1 new)". This should only happen if - # their last visit was before the comment was posted, however. - # Below, this is implemented as a INSERT ... ON CONFLICT DO UPDATE so that - # it will insert a new topic visit with 1 comment if they didn't previously - # have one at all. - if request.user.track_comment_visits: - statement = ( - insert(TopicVisit.__table__) - .values( - user_id=request.user.user_id, - topic_id=comment.topic_id, - visit_time=utc_now(), - num_comments=1, - ) - .on_conflict_do_update( - constraint=TopicVisit.__table__.primary_key, - set_={'num_comments': TopicVisit.num_comments + 1}, - where=TopicVisit.visit_time < comment.created_time, + if clear_all_previous == 'true': + + prev_notifications = ( + + request.query(CommentNotification).filter( + CommentNotification.is_unread == True, #noqa + CommentNotification.created_time <= + request.db_session.query(CommentNotification.created_time) + .filter( + CommentNotification.user == request.user, + CommentNotification.comment_id == comment.comment_id, + ) + .as_scalar() ) + .options(joinedload(CommentNotification.comment)) + .all() ) - request.db_session.execute(statement) - mark_changed(request.db_session) + for notification in prev_notifications: + notification.is_unread = False + _increment_topic_comments_seen(request, notification.comment) + + + return Response('Your comment notifications have been cleared.') + + else: + + request.query(CommentNotification).filter( + CommentNotification.user == request.user, + CommentNotification.comment == comment, + ).update( + {CommentNotification.is_unread: False}, synchronize_session=False) + + _increment_topic_comments_seen(request, comment) - return IC_NOOP + return IC_NOOP