Add option to notify users of their own web activity

Ref: ~sircmpwn/todo.sr.ht#94
This commit is contained in:
наб 2020-09-28 21:28:50 +02:00 committed by Drew DeVault
parent 68e1a17b2a
commit bb5a0a8ccf
9 changed files with 109 additions and 17 deletions

View File

@ -239,3 +239,29 @@ select.form-control {
flex-grow: 1;
}
}
// TODO: move me into core.sr.ht
details {
padding: 0 1rem;
margin: 0 -1rem 1rem;
summary {
background: $gray-300;
padding: 0 1rem;
margin: 0 -1rem;
}
&[open] {
padding: 0 1rem;
margin-left: calc(-1rem - 4px);
border-left: 4px solid $gray-300;
}
}
.prefs {
padding: 0.5rem 0;
.form-check {
padding-left: 0;
}
}

View File

@ -236,7 +236,7 @@ class MailHandler:
return "550 Comment must be between 3 and 16384 characters."
event = add_comment(sender, ticket, text=body,
resolution=resolution, resolve=resolve, reopen=reopen)
resolution=resolution, resolve=resolve, reopen=reopen, from_email=True)
TicketWebhook.deliver(TicketWebhook.Events.event_create,
event.to_dict(),
TicketWebhook.Subscription.ticket_id == ticket.id)

View File

@ -0,0 +1,23 @@
"""Add User.notify_self
Revision ID: 3a9cb6757f59
Revises: 6c714f704591
Create Date: 2020-09-28 19:11:22.221191
"""
# revision identifiers, used by Alembic.
revision = '3a9cb6757f59'
down_revision = '6c714f704591'
from alembic import op
import sqlalchemy as sa
def upgrade():
op.add_column('user', sa.Column('notify_self', sa.Boolean,
nullable=False, server_default='FALSE'))
def downgrade():
op.drop_column('user', 'notify_self')

View File

@ -1,12 +1,14 @@
from flask import Blueprint, render_template, request, abort
from flask import Blueprint, render_template, request, abort, redirect, url_for
from todosrht.access import get_tracker, get_access
from todosrht.tickets import get_participant_for_user
from todosrht.types import Tracker, Ticket, TicketAccess
from todosrht.types import Event, EventNotification, EventType
from todosrht.types import User, Participant
from srht.config import cfg
from srht.oauth import current_user
from srht.database import db
from srht.oauth import current_user, loginrequired
from srht.flask import paginate_query, session
from srht.validation import Validation
from sqlalchemy import and_, or_
html = Blueprint('html', __name__)
@ -51,7 +53,7 @@ def filter_authorized_events(events):
return events
@html.route("/")
def index():
def index_GET():
if not current_user:
return render_template("index.html")
trackers = (Tracker.query
@ -68,15 +70,25 @@ def index():
.order_by(Event.created.desc()))
events = events.limit(10).all()
notice = session.get("notice")
if notice:
del session["notice"]
notice = session.pop("notice", None)
prefs_updated = session.pop("prefs_updated", None)
return render_template("dashboard.html",
trackers=trackers, notice=notice,
tracker_list_msg="Your Trackers",
more_trackers=total_trackers > limit_trackers,
events=events, EventType=EventType)
events=events, EventType=EventType,
prefs_updated=prefs_updated)
@html.route("/", methods=["POST"])
@loginrequired
def index_POST():
valid = Validation(request)
notify_self = valid.require("notify-self")
current_user.notify_self = notify_self == "on"
db.session.commit()
session["prefs_updated"] = True
return redirect(url_for("html.index_GET"))
@html.route("/~<username>")
def user_GET(username):

View File

@ -214,7 +214,7 @@ def delete_POST(owner, name):
{ "id": tracker_id },
UserWebhook.Subscription.user_id == owner_id)
return redirect(url_for("html.index"))
return redirect(url_for("html.index_GET"))
@settings.route("/<owner>/<name>/settings/import-export")
@loginrequired

View File

@ -51,6 +51,28 @@
>
Create new tracker {{icon("caret-right")}}
</a>
<details
style="margin: -0.5rem 0 0.5rem 0"
{% if prefs_updated %}
open
{% endif %}
>
<summary>User preferences</summary>
<form method="POST" class="prefs">
{{csrf_token()}}
<label class="form-check">
<input
type="checkbox"
name="notify-self"
id="notify-self"
{{ "checked" if current_user.notify_self }} />
Notify me of my own activity
</label>
<button class="btn btn-primary" type="submit">
Apply {{icon("caret-right")}}
</button>
</form>
</details>
{% endif %}
{% if len(trackers) > 0 %}
<h3>{{ tracker_list_msg }}</h3>

View File

@ -211,7 +211,7 @@ def _change_ticket_status(ticket, resolve, resolution, reopen):
old_resolution, ticket.resolution)
def _send_comment_notifications(
participant, ticket, event, comment, resolution):
participant, ticket, event, comment, resolution, from_email):
"""
Notify users subscribed to the ticket or tracker.
Returns a list of notified users.
@ -230,7 +230,7 @@ def _send_comment_notifications(
for subscriber, subscription in subscriptions.items():
_create_event_notification(subscriber, event)
if subscriber != participant:
if (participant.notify_self and not from_email) or subscriber != participant:
_send_comment_notification(
subscription, ticket, participant, event, comment, resolution)
@ -295,7 +295,8 @@ def _handle_mentions(ticket, submitter, text, notified_users, comment=None):
def add_comment(submitter, ticket,
text=None, resolve=False, resolution=None, reopen=False):
text=None, resolve=False, resolution=None, reopen=False,
from_email=False):
"""
Comment on a ticket, optionally resolve or reopen the ticket.
"""
@ -311,7 +312,7 @@ def add_comment(submitter, ticket,
return None
event = _create_comment_event(ticket, submitter, comment, status_change)
notified_participants = _send_comment_notifications(
submitter, ticket, event, comment, resolution)
submitter, ticket, event, comment, resolution, from_email)
if comment and comment.text:
_handle_mentions(
@ -406,7 +407,7 @@ def assign(ticket, assignee, assigner):
assigner_participant = get_participant_for_user(assigner)
subscription = get_or_create_subscription(ticket, assignee_participant)
if assigner != assignee:
if assigner.notify_self or assigner != assignee:
notify_assignee(subscription, ticket, assigner, assignee)
event = Event()
@ -500,8 +501,8 @@ def submit_ticket(tracker, submitter, title, description,
# Send notifications
for sub in all_subscriptions.values():
_create_event_notification(sub.participant, event)
# Notify submitter for tickets created by email
if from_email or sub.participant != submitter:
# Always notify submitter for tickets created by email
if from_email or submitter.notify_self or sub.participant != submitter:
_send_new_ticket_notification(sub, ticket, from_email_id)
_handle_mentions(

View File

@ -1,9 +1,10 @@
from srht.database import Base
from srht.oauth import ExternalUserMixin
from srht.oauth import ExternalOAuthTokenMixin
import sqlalchemy as sa
class User(Base, ExternalUserMixin):
pass
notify_self = sa.Column(sa.Boolean, nullable=False, server_default="FALSE")
class OAuthToken(Base, ExternalOAuthTokenMixin):
pass

View File

@ -52,6 +52,13 @@ class Participant(Base):
return self.external_id
assert False
@property
def notify_self(self):
if self.participant_type == ParticipantType.user:
return self.user.notify_self
else:
return False
def __str__(self):
return self.name