diff --git a/templates/zephyr/settings.html b/templates/zephyr/settings.html index 8c0c886955..b5e9e73510 100644 --- a/templates/zephyr/settings.html +++ b/templates/zephyr/settings.html @@ -132,6 +132,17 @@ +
+ +
+ +
+
+
diff --git a/zephyr/lib/actions.py b/zephyr/lib/actions.py index 1e233a018f..d1cb467447 100644 --- a/zephyr/lib/actions.py +++ b/zephyr/lib/actions.py @@ -559,6 +559,14 @@ def do_change_enable_sounds(user_profile, enable_sounds, log=True): 'user': user_profile.email, '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): user_profile.enter_sends = 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', body_template_path='confirmation/invite_email_body.txt') +@statsd_increment("missed_message_reminders") 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 @@ -920,19 +929,12 @@ def do_send_missedmessage_email(user_profile, missed_messages): user_profile.last_reminder = datetime.datetime.now() user_profile.save(update_fields=['last_reminder']) - statsd.incr('missed_message_reminders') - def handle_missedmessage_emails(user_profile_id, missed_email_events): message_ids = [event.get('message_id') for event in missed_email_events] timestamp = timestamp_to_datetime(event.get('timestamp')) - try: - user_profile = UserProfile.objects.get(id=user_profile_id) - 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)) + user_profile = UserProfile.objects.get(id=user_profile_id) + messages = Message.objects.filter(id__in=message_ids, usermessage__flags=~UserMessage.flags.read) 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 diff --git a/zephyr/management/commands/populate_db.py b/zephyr/management/commands/populate_db.py index b11eef3b77..72f7ad5230 100644 --- a/zephyr/management/commands/populate_db.py +++ b/zephyr/management/commands/populate_db.py @@ -553,6 +553,9 @@ def restore_saved_messages(): elif message_type == "enable_sounds_changed": user_profile = users[old_message["user"]] 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() continue elif message_type == "default_streams": diff --git a/zephyr/static/js/ui.js b/zephyr/static/js/ui.js index 03663453ad..656846e86b 100644 --- a/zephyr/static/js/ui.js +++ b/zephyr/static/js/ui.js @@ -776,6 +776,10 @@ $(function () { 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) .addClass('alert-success') .text(message).stop(true).fadeTo(0,1); diff --git a/zephyr/tornado_callbacks.py b/zephyr/tornado_callbacks.py index 69e2f751f1..0eb4f93d32 100644 --- a/zephyr/tornado_callbacks.py +++ b/zephyr/tornado_callbacks.py @@ -2,7 +2,7 @@ from __future__ import absolute_import from django.conf import settings 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.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 sys +import time import logging import requests import simplejson @@ -267,6 +268,23 @@ def process_new_message(data): event = dict(type='message', message=message_dict) 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: stream_receive_message(data['realm_id'], data['stream_name'], message) diff --git a/zephyr/views.py b/zephyr/views.py index e131eb79ee..ddbeb7d430 100644 --- a/zephyr/views.py +++ b/zephyr/views.py @@ -29,7 +29,7 @@ from zephyr.lib.actions import do_add_subscription, do_remove_subscription, \ create_stream_if_needed, gather_subscriptions, subscribed_to_stream, \ update_user_presence, set_stream_color, get_stream_colors, update_message_flags, \ 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, \ is_inactive, isnt_mit from django.views.decorators.csrf import csrf_exempt @@ -521,6 +521,8 @@ def home(request): user_profile.enable_desktop_notifications, sounds_enabled = user_profile.enable_sounds, + enable_offline_email_notifications = + user_profile.enable_offline_email_notifications, event_queue_id = register_ret['queue_id'], last_event_id = register_ret['last_event_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 enable_desktop_notifications=POST(converter=lambda x: x == "on", default=False), - enable_sounds=POST(converter=lambda x: x == "on", - default=False)): + enable_sounds=POST(converter=lambda x: x == "on"), + enable_offline_email_notifications=POST(converter=lambda x: x == "on", + default=False)): if new_password != "" or confirm_password != "": if new_password != confirm_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) 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) @authenticated_json_post_view @@ -1521,7 +1528,7 @@ def api_github_landing(request, user_profile, event=POST, # any push notification on a branch that is not in our whitelist. if short_ref not in re.split('[\s,;|]+', branches): return json_success() - + subject, content = build_message_from_gitlog(user_profile, repository['name'], payload['ref'], payload['commits'],