mirror of https://github.com/zulip/zulip.git
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:
parent
06f33a2bde
commit
4173862833
|
@ -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" />
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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":
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
@ -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.
|
# any push notification on a branch that is not in our whitelist.
|
||||||
if short_ref not in re.split('[\s,;|]+', branches):
|
if short_ref not in re.split('[\s,;|]+', branches):
|
||||||
return json_success()
|
return json_success()
|
||||||
|
|
||||||
|
|
||||||
subject, content = build_message_from_gitlog(user_profile, repository['name'],
|
subject, content = build_message_from_gitlog(user_profile, repository['name'],
|
||||||
payload['ref'], payload['commits'],
|
payload['ref'], payload['commits'],
|
||||||
|
|
Loading…
Reference in New Issue