def handle(self, **options): # type: (**str) -> None if options["domain"] is None and options["users"] is None: self.print_help("python manage.py", "turn_off_digests") exit(1) if options["domain"]: realm = get_realm(options["domain"]) user_profiles = UserProfile.objects.filter(realm=realm) else: emails = set( [email.strip() for email in options["users"].split(",")]) user_profiles = [] for email in emails: user_profiles.append(get_user_profile_by_email(email)) print("Turned off digest emails for:") for user_profile in user_profiles: already_disabled_prefix = "" if user_profile.enable_digest_emails: do_change_enable_digest_emails(user_profile, False) else: already_disabled_prefix = "(already off) " print("%s%s <%s>" % (already_disabled_prefix, user_profile.full_name, user_profile.email))
def json_change_notify_settings(request, user_profile, enable_stream_desktop_notifications=REQ(validator=check_bool, default=None), enable_stream_sounds=REQ(validator=check_bool, default=None), enable_desktop_notifications=REQ(validator=check_bool, default=None), enable_sounds=REQ(validator=check_bool, default=None), enable_offline_email_notifications=REQ(validator=check_bool, default=None), enable_offline_push_notifications=REQ(validator=check_bool, default=None), enable_digest_emails=REQ(validator=check_bool, default=None)): # type: (HttpRequest, UserProfile, Optional[bool], Optional[bool], Optional[bool], Optional[bool], Optional[bool], Optional[bool], Optional[bool]) -> HttpResponse result = {} # Stream notification settings. if enable_stream_desktop_notifications is not None and \ user_profile.enable_stream_desktop_notifications != enable_stream_desktop_notifications: do_change_enable_stream_desktop_notifications( user_profile, enable_stream_desktop_notifications) result['enable_stream_desktop_notifications'] = enable_stream_desktop_notifications if enable_stream_sounds is not None and \ user_profile.enable_stream_sounds != enable_stream_sounds: do_change_enable_stream_sounds(user_profile, enable_stream_sounds) result['enable_stream_sounds'] = enable_stream_sounds # PM and @-mention settings. if enable_desktop_notifications is not None and \ user_profile.enable_desktop_notifications != enable_desktop_notifications: do_change_enable_desktop_notifications(user_profile, enable_desktop_notifications) result['enable_desktop_notifications'] = enable_desktop_notifications if enable_sounds is not None and \ user_profile.enable_sounds != enable_sounds: do_change_enable_sounds(user_profile, enable_sounds) result['enable_sounds'] = enable_sounds if enable_offline_email_notifications is not None and \ 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 if enable_offline_push_notifications is not None and \ user_profile.enable_offline_push_notifications != enable_offline_push_notifications: do_change_enable_offline_push_notifications(user_profile, enable_offline_push_notifications) result['enable_offline_push_notifications'] = enable_offline_push_notifications if enable_digest_emails is not None and \ user_profile.enable_digest_emails != enable_digest_emails: do_change_enable_digest_emails(user_profile, enable_digest_emails) result['enable_digest_emails'] = enable_digest_emails return json_success(result)
def json_change_notify_settings(request, user_profile, enable_stream_desktop_notifications=REQ(validator=check_bool, default=None), enable_stream_sounds=REQ(validator=check_bool, default=None), enable_desktop_notifications=REQ(validator=check_bool, default=None), enable_sounds=REQ(validator=check_bool, default=None), enable_offline_email_notifications=REQ(validator=check_bool, default=None), enable_offline_push_notifications=REQ(validator=check_bool, default=None), enable_digest_emails=REQ(validator=check_bool, default=None)): result = {} # Stream notification settings. if enable_stream_desktop_notifications is not None and \ user_profile.enable_stream_desktop_notifications != enable_stream_desktop_notifications: do_change_enable_stream_desktop_notifications( user_profile, enable_stream_desktop_notifications) result['enable_stream_desktop_notifications'] = enable_stream_desktop_notifications if enable_stream_sounds is not None and \ user_profile.enable_stream_sounds != enable_stream_sounds: do_change_enable_stream_sounds(user_profile, enable_stream_sounds) result['enable_stream_sounds'] = enable_stream_sounds # PM and @-mention settings. if enable_desktop_notifications is not None and \ user_profile.enable_desktop_notifications != enable_desktop_notifications: do_change_enable_desktop_notifications(user_profile, enable_desktop_notifications) result['enable_desktop_notifications'] = enable_desktop_notifications if enable_sounds is not None and \ user_profile.enable_sounds != enable_sounds: do_change_enable_sounds(user_profile, enable_sounds) result['enable_sounds'] = enable_sounds if enable_offline_email_notifications is not None and \ 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 if enable_offline_push_notifications is not None and \ user_profile.enable_offline_push_notifications != enable_offline_push_notifications: do_change_enable_offline_push_notifications(user_profile, enable_offline_push_notifications) result['enable_offline_push_notifications'] = enable_offline_push_notifications if enable_digest_emails is not None and \ user_profile.enable_digest_emails != enable_digest_emails: do_change_enable_digest_emails(user_profile, enable_digest_emails) result['enable_digest_emails'] = enable_digest_emails return json_success(result)
def handle(self, **options): if options["domain"] is None and options["users"] is None: self.print_help("python manage.py", "turn_off_digests") exit(1) if options["domain"]: realm = get_realm(options["domain"]) user_profiles = UserProfile.objects.filter(realm=realm) else: emails = set([email.strip() for email in options["users"].split(",")]) user_profiles = [] for email in emails: user_profiles.append(get_user_profile_by_email(email)) print("Turned off digest emails for:") for user_profile in user_profiles: already_disabled_prefix = "" if user_profile.enable_digest_emails: do_change_enable_digest_emails(user_profile, False) else: already_disabled_prefix = "(already off) " print("%s%s <%s>" % (already_disabled_prefix, user_profile.full_name, user_profile.email))
def json_change_notify_settings( request, user_profile, enable_stream_desktop_notifications=REQ(validator=check_bool, default=None), enable_stream_sounds=REQ(validator=check_bool, default=None), enable_desktop_notifications=REQ(validator=check_bool, default=None), enable_sounds=REQ(validator=check_bool, default=None), enable_offline_email_notifications=REQ(validator=check_bool, default=None), enable_offline_push_notifications=REQ(validator=check_bool, default=None), enable_online_push_notifications=REQ(validator=check_bool, default=None), enable_digest_emails=REQ(validator=check_bool, default=None), pm_content_in_desktop_notifications=REQ(validator=check_bool, default=None)): # type: (HttpRequest, UserProfile, Optional[bool], Optional[bool], Optional[bool], Optional[bool], Optional[bool], Optional[bool], Optional[bool], Optional[bool], Optional[bool]) -> HttpResponse result = {} # Stream notification settings. if enable_stream_desktop_notifications is not None and \ user_profile.enable_stream_desktop_notifications != enable_stream_desktop_notifications: do_change_enable_stream_desktop_notifications( user_profile, enable_stream_desktop_notifications) result[ 'enable_stream_desktop_notifications'] = enable_stream_desktop_notifications if enable_stream_sounds is not None and \ user_profile.enable_stream_sounds != enable_stream_sounds: do_change_enable_stream_sounds(user_profile, enable_stream_sounds) result['enable_stream_sounds'] = enable_stream_sounds # PM and @-mention settings. if enable_desktop_notifications is not None and \ user_profile.enable_desktop_notifications != enable_desktop_notifications: do_change_enable_desktop_notifications(user_profile, enable_desktop_notifications) result['enable_desktop_notifications'] = enable_desktop_notifications if enable_sounds is not None and \ user_profile.enable_sounds != enable_sounds: do_change_enable_sounds(user_profile, enable_sounds) result['enable_sounds'] = enable_sounds if enable_offline_email_notifications is not None and \ 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 if enable_offline_push_notifications is not None and \ user_profile.enable_offline_push_notifications != enable_offline_push_notifications: do_change_enable_offline_push_notifications( user_profile, enable_offline_push_notifications) result[ 'enable_offline_push_notifications'] = enable_offline_push_notifications if enable_online_push_notifications is not None and \ user_profile.enable_online_push_notifications != enable_online_push_notifications: do_change_enable_online_push_notifications( user_profile, enable_online_push_notifications) result[ 'enable_online_push_notifications'] = enable_online_push_notifications if enable_digest_emails is not None and \ user_profile.enable_digest_emails != enable_digest_emails: do_change_enable_digest_emails(user_profile, enable_digest_emails) result['enable_digest_emails'] = enable_digest_emails if pm_content_in_desktop_notifications is not None and \ user_profile.pm_content_in_desktop_notifications != pm_content_in_desktop_notifications: do_change_pm_content_in_desktop_notifications( user_profile, pm_content_in_desktop_notifications) result[ 'pm_content_in_desktop_notifications'] = pm_content_in_desktop_notifications return json_success(result)
def send_future_email(recipients, email_html, email_text, subject, delay=datetime.timedelta(0), sender=None, tags=[], mail_client=None): # type: (List[Dict[str, Any]], Text, Text, Text, datetime.timedelta, Optional[Dict[str, Text]], Iterable[Text], Optional[mandrill.Mandrill]) -> None """ Sends email via Mandrill, with optional delay 'mail_client' is filled in by the decorator """ # When sending real emails while testing locally, don't accidentally send # emails to non-zulip.com users. if settings.DEVELOPMENT and \ settings.EMAIL_BACKEND != 'django.core.mail.backends.console.EmailBackend': for recipient in recipients: email = recipient.get("email") if get_user_profile_by_email(email).realm.string_id != "zulip": raise ValueError( "digest: refusing to send emails to non-zulip.com users.") # message = {"from_email": "*****@*****.**", # "from_name": "Othello", # "html": "<p>hello</p> there", # "tags": ["signup-reminders"], # "to": [{'email':"*****@*****.**", 'name': "thingamajig"}] # } # SMTP mail delivery implementation if not mail_client: if sender is None: # This may likely overridden by settings.DEFAULT_FROM_EMAIL sender = {'email': settings.NOREPLY_EMAIL_ADDRESS, 'name': 'Zulip'} for recipient in recipients: email_fields = { 'email_html': email_html, 'email_subject': subject, 'email_text': email_text, 'recipient_email': recipient.get('email'), 'recipient_name': recipient.get('name'), 'sender_email': sender['email'], 'sender_name': sender['name'] } ScheduledJob.objects.create(type=ScheduledJob.EMAIL, filter_string=recipient.get('email'), data=ujson.dumps(email_fields), scheduled_timestamp=timezone.now() + delay) return # Mandrill implementation if sender is None: sender = {'email': settings.NOREPLY_EMAIL_ADDRESS, 'name': 'Zulip'} message = { 'from_email': sender['email'], 'from_name': sender['name'], 'to': recipients, 'subject': subject, 'html': email_html, 'text': email_text, 'tags': tags, } # ignore any delays smaller than 1-minute because it's cheaper just to sent them immediately if not isinstance(delay, datetime.timedelta): raise TypeError("specified delay is of the wrong type: %s" % (type(delay), )) # Note: In the next section we hackishly use **{"async": False} to # work around https://github.com/python/mypy/issues/2959 "# type: ignore" doesn't work if delay < datetime.timedelta(minutes=1): results = mail_client.messages.send(message=message, ip_pool="Main Pool", **{"async": False}) else: send_time = (timezone.now() + delay).__format__("%Y-%m-%d %H:%M:%S") results = mail_client.messages.send(message=message, ip_pool="Main Pool", send_at=send_time, **{"async": False}) problems = [ result for result in results if (result['status'] in ('rejected', 'invalid')) ] if problems: for problem in problems: if problem["status"] == "rejected": if problem["reject_reason"] == "hard-bounce": # A hard bounce means the address doesn't exist or the # recipient mail server is completely blocking # delivery. Don't try to send further emails. if "digest-emails" in tags: from zerver.lib.actions import do_change_enable_digest_emails bounce_email = problem["email"] user_profile = get_user_profile_by_email(bounce_email) do_change_enable_digest_emails(user_profile, False) log_digest_event( "%s\nTurned off digest emails for %s" % (str(problems), bounce_email)) continue elif problem["reject_reason"] == "soft-bounce": # A soft bounce is temporary; let it try to resolve itself. continue raise Exception( "While sending email (%s), encountered problems with these recipients: %r" % (subject, problems)) return
def send_future_email(recipients, email_html, email_text, subject, delay=datetime.timedelta(0), sender=None, tags=[], mail_client=None): """ Sends email via Mandrill, with optional delay 'mail_client' is filled in by the decorator """ # When sending real emails while testing locally, don't accidentally send # emails to non-zulip.com users. if settings.DEVELOPMENT and \ settings.EMAIL_BACKEND != 'django.core.mail.backends.console.EmailBackend': for recipient in recipients: email = recipient.get("email") if get_user_profile_by_email(email).realm.domain != "zulip.com": raise ValueError("digest: refusing to send emails to non-zulip.com users.") # message = {"from_email": "*****@*****.**", # "from_name": "Othello", # "html": "<p>hello</p> there", # "tags": ["signup-reminders"], # "to": [{'email':"*****@*****.**", 'name': "thingamajig"}] # } # SMTP mail delivery implementation if not mail_client: if sender is None: # This may likely overridden by settings.DEFAULT_FROM_EMAIL sender = {'email': settings.NOREPLY_EMAIL_ADDRESS, 'name': 'Zulip'} for recipient in recipients: email_fields = {'email_html': email_html, 'email_subject': subject, 'email_text': email_text, 'recipient_email': recipient.get('email'), 'recipient_name': recipient.get('name'), 'sender_email': sender['email'], 'sender_name': sender['name']} ScheduledJob.objects.create(type=ScheduledJob.EMAIL, filter_string=recipient.get('email'), data=ujson.dumps(email_fields), scheduled_timestamp=datetime.datetime.utcnow() + delay) return # Mandrill implementation if sender is None: sender = {'email': settings.NOREPLY_EMAIL_ADDRESS, 'name': 'Zulip'} message = {'from_email': sender['email'], 'from_name': sender['name'], 'to': recipients, 'subject': subject, 'html': email_html, 'text': email_text, 'tags': tags, } # ignore any delays smaller than 1-minute because it's cheaper just to sent them immediately if type(delay) is not datetime.timedelta: raise TypeError("specified delay is of the wrong type: %s" % (type(delay),)) if delay < datetime.timedelta(minutes=1): results = mail_client.messages.send(message=message, async=False, ip_pool="Main Pool") else: send_time = (datetime.datetime.utcnow() + delay).__format__("%Y-%m-%d %H:%M:%S") results = mail_client.messages.send(message=message, async=False, ip_pool="Main Pool", send_at=send_time) problems = [result for result in results if (result['status'] in ('rejected', 'invalid'))] if problems: for problem in problems: if problem["status"] == "rejected": if problem["reject_reason"] == "hard-bounce": # A hard bounce means the address doesn't exist or the # recipient mail server is completely blocking # delivery. Don't try to send further emails. if "digest-emails" in tags: from zerver.lib.actions import do_change_enable_digest_emails bounce_email = problem["email"] user_profile = get_user_profile_by_email(bounce_email) do_change_enable_digest_emails(user_profile, False) log_digest_event("%s\nTurned off digest emails for %s" % ( str(problems), bounce_email)) continue elif problem["reject_reason"] == "soft-bounce": # A soft bounce is temporary; let it try to resolve itself. continue raise Exception( "While sending email (%s), encountered problems with these recipients: %r" % (subject, problems)) return
def do_digest_unsubscribe(user_profile): # type: (UserProfile) -> None do_change_enable_digest_emails(user_profile, False)