Send notification with missed message to users if they received a PM while offline

This is configurable in the user's settings on Humbug

(imported from commit 80bf6d7a6f0dc3811117548e2225865db8b533d9)
This commit is contained in:
Leo Franchi 2013-05-07 17:19:52 -04:00 committed by Tim Abbott
parent 06f33a2bde
commit 4173862833
6 changed files with 59 additions and 14 deletions

View File

@ -132,6 +132,17 @@
</div> </div>
</div> </div>
<div class="control-group">
<label for="enable_offline_email_notifications" class="control-label">
Notify on receiving PMs when offline</label>
<div class="controls">
<input type="checkbox" name="enable_offline_email_notifications" id="enable_offline_email_notifications"
{% if user_profile.enable_offline_email_notifications %}
checked="yes"
{% endif %} />
</div>
</div>
<div class="control-group"> <div class="control-group">
<div class="controls"> <div class="controls">
<input type="submit" name="change_settings" value="Save changes" class="btn btn-big btn-primary" /> <input type="submit" name="change_settings" value="Save changes" class="btn btn-big btn-primary" />

View File

@ -559,6 +559,14 @@ def do_change_enable_sounds(user_profile, enable_sounds, log=True):
'user': user_profile.email, 'user': user_profile.email,
'enable_sounds': enable_sounds}) 'enable_sounds': enable_sounds})
def do_change_enable_offline_email_notifications(user_profile, offline_email_notifications, log=True):
user_profile.enable_offline_email_notifications = offline_email_notifications
user_profile.save(update_fields=["enable_offline_email_notifications"])
if log:
log_event({'type': 'enable_offline_email_notifications_changed',
'user': user_profile.email,
'enable_offline_email_notifications': offline_email_notifications})
def do_change_enter_sends(user_profile, enter_sends): def do_change_enter_sends(user_profile, enter_sends):
user_profile.enter_sends = enter_sends user_profile.enter_sends = enter_sends
user_profile.save(update_fields=["enter_sends"]) user_profile.save(update_fields=["enter_sends"])
@ -887,6 +895,7 @@ def do_send_confirmation_email(invitee, referrer):
subject_template_path='confirmation/invite_email_subject.txt', subject_template_path='confirmation/invite_email_subject.txt',
body_template_path='confirmation/invite_email_body.txt') body_template_path='confirmation/invite_email_body.txt')
@statsd_increment("missed_message_reminders")
def do_send_missedmessage_email(user_profile, missed_messages): def do_send_missedmessage_email(user_profile, missed_messages):
""" """
Send a reminder email to a user if she's missed some PMs by being offline Send a reminder email to a user if she's missed some PMs by being offline
@ -920,19 +929,12 @@ def do_send_missedmessage_email(user_profile, missed_messages):
user_profile.last_reminder = datetime.datetime.now() user_profile.last_reminder = datetime.datetime.now()
user_profile.save(update_fields=['last_reminder']) user_profile.save(update_fields=['last_reminder'])
statsd.incr('missed_message_reminders')
def handle_missedmessage_emails(user_profile_id, missed_email_events): def handle_missedmessage_emails(user_profile_id, missed_email_events):
message_ids = [event.get('message_id') for event in missed_email_events] message_ids = [event.get('message_id') for event in missed_email_events]
timestamp = timestamp_to_datetime(event.get('timestamp')) timestamp = timestamp_to_datetime(event.get('timestamp'))
try: user_profile = UserProfile.objects.get(id=user_profile_id)
user_profile = UserProfile.objects.get(id=user_profile_id) messages = Message.objects.filter(id__in=message_ids, usermessage__flags=~UserMessage.flags.read)
messages = Message.objects.filter(id__in=message_ids, usermessage__flags=~UserMessage.flags.read)
except (UserProfile.DoesNotExist, Message.DoesNotExist) as e:
import logging
logging.warning("Failed to send missed message email, failed to look up: %s %s %e" % \
(user_profile_id, message_ids, e))
if len(messages) == 0 or timestamp - user_profile.last_reminder < datetime.timedelta(days=1): if len(messages) == 0 or timestamp - user_profile.last_reminder < datetime.timedelta(days=1):
# Don't spam the user, if we've sent an email in the last day # Don't spam the user, if we've sent an email in the last day

View File

@ -553,6 +553,9 @@ def restore_saved_messages():
elif message_type == "enable_sounds_changed": elif message_type == "enable_sounds_changed":
user_profile = users[old_message["user"]] user_profile = users[old_message["user"]]
user_profile.enable_sounds = (old_message["enable_sounds"] != "false") user_profile.enable_sounds = (old_message["enable_sounds"] != "false")
elif message_type == "enable_offline_email_notifications_changed":
user_profile = users[old_message["user"]]
user_profile.enable_offline_email_notifications = (old_message["enable_offline_email_notifications"] != "false")
user_profile.save() user_profile.save()
continue continue
elif message_type == "default_streams": elif message_type == "default_streams":

View File

@ -776,6 +776,10 @@ $(function () {
page_params.sounds_enabled = result.enable_sounds; page_params.sounds_enabled = result.enable_sounds;
} }
if (result.enable_offline_email_notifications !== undefined) {
page_params.enable_offline_email_notifications = result.enable_offline_email_notifications;
}
settings_status.removeClass(status_classes) settings_status.removeClass(status_classes)
.addClass('alert-success') .addClass('alert-success')
.text(message).stop(true).fadeTo(0,1); .text(message).stop(true).fadeTo(0,1);

View File

@ -2,7 +2,7 @@ from __future__ import absolute_import
from django.conf import settings from django.conf import settings
from zephyr.models import Message, UserProfile, UserMessage, \ from zephyr.models import Message, UserProfile, UserMessage, \
Recipient, Stream, get_stream Recipient, Stream, get_stream, get_user_profile_by_id
from zephyr.decorator import JsonableError from zephyr.decorator import JsonableError
from zephyr.lib.cache_helpers import cache_get_message from zephyr.lib.cache_helpers import cache_get_message
@ -11,6 +11,7 @@ from zephyr.lib.event_queue import get_client_descriptors_for_user
import os import os
import sys import sys
import time
import logging import logging
import requests import requests
import simplejson import simplejson
@ -267,6 +268,23 @@ def process_new_message(data):
event = dict(type='message', message=message_dict) event = dict(type='message', message=message_dict)
client.add_event(event) client.add_event(event)
# If the recipient was offline and the message was a single or group PM,
# potentially notify more immediately
if message.recipient.type in (Recipient.PERSONAL, Recipient.HUDDLE) and \
user_profile_id != message.sender.id and \
len(get_client_descriptors_for_user(user_profile_id)) == 0:
user_profile = get_user_profile_by_id(user_profile_id)
if user_profile.enable_offline_email_notifications:
event = {"user_profile_id": user_profile_id,
"message_id": message.id,
"timestamp": time.time()}
# We require RabbitMQ to do this, as we can't call the email handler
# from the Tornado process. So if there's no rabbitmq support do nothing
queue_json_publish("missedmessage_emails", event, lambda event: None)
if 'stream_name' in data: if 'stream_name' in data:
stream_receive_message(data['realm_id'], data['stream_name'], message) stream_receive_message(data['realm_id'], data['stream_name'], message)

View File

@ -29,7 +29,7 @@ from zephyr.lib.actions import do_add_subscription, do_remove_subscription, \
create_stream_if_needed, gather_subscriptions, subscribed_to_stream, \ create_stream_if_needed, gather_subscriptions, subscribed_to_stream, \
update_user_presence, set_stream_color, get_stream_colors, update_message_flags, \ update_user_presence, set_stream_color, get_stream_colors, update_message_flags, \
recipient_for_emails, extract_recipients, do_events_register, do_finish_tutorial, \ recipient_for_emails, extract_recipients, do_events_register, do_finish_tutorial, \
get_status_dict get_status_dict, do_change_enable_offline_email_notifications
from zephyr.forms import RegistrationForm, HomepageForm, ToSForm, is_unique, \ from zephyr.forms import RegistrationForm, HomepageForm, ToSForm, is_unique, \
is_inactive, isnt_mit is_inactive, isnt_mit
from django.views.decorators.csrf import csrf_exempt from django.views.decorators.csrf import csrf_exempt
@ -521,6 +521,8 @@ def home(request):
user_profile.enable_desktop_notifications, user_profile.enable_desktop_notifications,
sounds_enabled = sounds_enabled =
user_profile.enable_sounds, user_profile.enable_sounds,
enable_offline_email_notifications =
user_profile.enable_offline_email_notifications,
event_queue_id = register_ret['queue_id'], event_queue_id = register_ret['queue_id'],
last_event_id = register_ret['last_event_id'], last_event_id = register_ret['last_event_id'],
max_message_id = register_ret['max_message_id'] max_message_id = register_ret['max_message_id']
@ -1283,8 +1285,9 @@ def json_change_settings(request, user_profile, full_name=POST,
# because browsers POST nothing for an unchecked checkbox # because browsers POST nothing for an unchecked checkbox
enable_desktop_notifications=POST(converter=lambda x: x == "on", enable_desktop_notifications=POST(converter=lambda x: x == "on",
default=False), default=False),
enable_sounds=POST(converter=lambda x: x == "on", enable_sounds=POST(converter=lambda x: x == "on"),
default=False)): enable_offline_email_notifications=POST(converter=lambda x: x == "on",
default=False)):
if new_password != "" or confirm_password != "": if new_password != "" or confirm_password != "":
if new_password != confirm_password: if new_password != confirm_password:
return json_error("New password must match confirmation password!") return json_error("New password must match confirmation password!")
@ -1305,6 +1308,10 @@ def json_change_settings(request, user_profile, full_name=POST,
do_change_enable_sounds(user_profile, enable_sounds) do_change_enable_sounds(user_profile, enable_sounds)
result['enable_sounds'] = enable_sounds result['enable_sounds'] = enable_sounds
if user_profile.enable_offline_email_notifications != enable_offline_email_notifications:
do_change_enable_offline_email_notifications(user_profile, enable_offline_email_notifications)
result['enable_offline_email_notifications'] = enable_offline_email_notifications
return json_success(result) return json_success(result)
@authenticated_json_post_view @authenticated_json_post_view