2015-11-23 17:09:21 +01:00
|
|
|
from __future__ import absolute_import
|
2016-06-05 02:15:26 +02:00
|
|
|
from typing import Optional
|
|
|
|
from six import text_type
|
2015-11-23 17:09:21 +01:00
|
|
|
|
2016-05-25 15:02:02 +02:00
|
|
|
from django.utils.translation import ugettext as _
|
2015-11-23 17:09:21 +01:00
|
|
|
from django.conf import settings
|
2016-11-17 08:56:01 +01:00
|
|
|
from django.contrib.auth import authenticate, update_session_auth_hash
|
2016-06-05 02:15:26 +02:00
|
|
|
from django.http import HttpRequest, HttpResponse
|
2015-11-23 17:09:21 +01:00
|
|
|
|
|
|
|
from zerver.decorator import authenticated_json_post_view, has_request_variables, REQ
|
|
|
|
from zerver.lib.actions import do_change_password, \
|
|
|
|
do_change_full_name, do_change_enable_desktop_notifications, \
|
|
|
|
do_change_enter_sends, do_change_enable_sounds, \
|
|
|
|
do_change_enable_offline_email_notifications, do_change_enable_digest_emails, \
|
2016-09-19 22:55:18 +02:00
|
|
|
do_change_enable_offline_push_notifications, do_change_enable_online_push_notifications, \
|
|
|
|
do_change_default_desktop_notifications, do_change_autoscroll_forever, \
|
2015-11-23 17:09:21 +01:00
|
|
|
do_change_enable_stream_desktop_notifications, do_change_enable_stream_sounds, \
|
2016-06-23 11:32:45 +02:00
|
|
|
do_regenerate_api_key, do_change_avatar_source, do_change_twenty_four_hour_time, \
|
|
|
|
do_change_left_side_userlist, do_change_default_language
|
2015-11-23 17:09:21 +01:00
|
|
|
from zerver.lib.avatar import avatar_url
|
2016-08-05 22:28:25 +02:00
|
|
|
from zerver.lib.i18n import get_available_language_codes
|
2015-11-23 17:09:21 +01:00
|
|
|
from zerver.lib.response import json_success, json_error
|
|
|
|
from zerver.lib.upload import upload_avatar_image
|
2016-06-23 11:32:45 +02:00
|
|
|
from zerver.lib.validator import check_bool, check_string
|
2016-07-31 10:02:42 +02:00
|
|
|
from zerver.lib.request import JsonableError
|
2016-10-06 09:18:51 +02:00
|
|
|
from zerver.models import UserProfile, Realm, name_changes_disabled
|
2015-11-23 17:09:21 +01:00
|
|
|
|
|
|
|
@authenticated_json_post_view
|
|
|
|
@has_request_variables
|
|
|
|
def json_change_ui_settings(request, user_profile,
|
|
|
|
autoscroll_forever=REQ(validator=check_bool,
|
|
|
|
default=None),
|
|
|
|
default_desktop_notifications=REQ(validator=check_bool,
|
|
|
|
default=None)):
|
2016-06-05 02:15:26 +02:00
|
|
|
# type: (HttpRequest, UserProfile, Optional[bool], Optional[bool]) -> HttpResponse
|
2015-11-23 17:09:21 +01:00
|
|
|
|
|
|
|
result = {}
|
|
|
|
|
|
|
|
if autoscroll_forever is not None and \
|
|
|
|
user_profile.autoscroll_forever != autoscroll_forever:
|
|
|
|
do_change_autoscroll_forever(user_profile, autoscroll_forever)
|
|
|
|
result['autoscroll_forever'] = autoscroll_forever
|
|
|
|
|
|
|
|
if default_desktop_notifications is not None and \
|
|
|
|
user_profile.default_desktop_notifications != default_desktop_notifications:
|
|
|
|
do_change_default_desktop_notifications(user_profile, default_desktop_notifications)
|
|
|
|
result['default_desktop_notifications'] = default_desktop_notifications
|
|
|
|
|
|
|
|
return json_success(result)
|
|
|
|
|
|
|
|
@authenticated_json_post_view
|
|
|
|
@has_request_variables
|
|
|
|
def json_change_settings(request, user_profile,
|
2016-07-23 22:13:53 +02:00
|
|
|
full_name=REQ(default=""),
|
2015-11-23 17:09:21 +01:00
|
|
|
old_password=REQ(default=""),
|
|
|
|
new_password=REQ(default=""),
|
|
|
|
confirm_password=REQ(default="")):
|
2016-06-05 02:15:26 +02:00
|
|
|
# type: (HttpRequest, UserProfile, text_type, text_type, text_type, text_type) -> HttpResponse
|
2016-07-23 22:22:25 +02:00
|
|
|
if not (full_name or new_password):
|
|
|
|
return json_error(_("No new data supplied"))
|
|
|
|
|
2015-11-23 17:09:21 +01:00
|
|
|
if new_password != "" or confirm_password != "":
|
|
|
|
if new_password != confirm_password:
|
2016-05-25 15:02:02 +02:00
|
|
|
return json_error(_("New password must match confirmation password!"))
|
2015-11-23 17:09:21 +01:00
|
|
|
if not authenticate(username=user_profile.email, password=old_password):
|
2016-05-25 15:02:02 +02:00
|
|
|
return json_error(_("Wrong password!"))
|
2015-11-23 17:09:21 +01:00
|
|
|
do_change_password(user_profile, new_password)
|
2016-11-17 08:56:01 +01:00
|
|
|
# In Django 1.10, password changes invalidates sessions, see
|
|
|
|
# https://docs.djangoproject.com/en/1.10/topics/auth/default/#session-invalidation-on-password-change
|
|
|
|
# for details. To avoid this logging the user out of his own
|
|
|
|
# session (which would provide a confusing UX at best), we
|
|
|
|
# update the session hash here.
|
|
|
|
update_session_auth_hash(request, user_profile)
|
2016-12-16 11:38:21 +01:00
|
|
|
# We also save the session to the DB immediately to mitigate
|
|
|
|
# race conditions. In theory, there is still a race condition
|
|
|
|
# and to completely avoid it we will have to use some kind of
|
|
|
|
# mutex lock in `django.contrib.auth.get_user` where session
|
|
|
|
# is verified. To make that lock work we will have to control
|
|
|
|
# the AuthenticationMiddleware which is currently controlled
|
|
|
|
# by Django,
|
|
|
|
request.session.save()
|
2015-11-23 17:09:21 +01:00
|
|
|
|
|
|
|
result = {}
|
|
|
|
if user_profile.full_name != full_name and full_name.strip() != "":
|
|
|
|
if name_changes_disabled(user_profile.realm):
|
|
|
|
# Failingly silently is fine -- they can't do it through the UI, so
|
|
|
|
# they'd have to be trying to break the rules.
|
|
|
|
pass
|
|
|
|
else:
|
|
|
|
new_full_name = full_name.strip()
|
|
|
|
if len(new_full_name) > UserProfile.MAX_NAME_LENGTH:
|
2016-05-25 15:02:02 +02:00
|
|
|
return json_error(_("Name too long!"))
|
2015-11-23 17:09:21 +01:00
|
|
|
do_change_full_name(user_profile, new_full_name)
|
|
|
|
result['full_name'] = new_full_name
|
|
|
|
|
|
|
|
return json_success(result)
|
|
|
|
|
|
|
|
@authenticated_json_post_view
|
|
|
|
@has_request_variables
|
|
|
|
def json_time_setting(request, user_profile, twenty_four_hour_time=REQ(validator=check_bool, default=None)):
|
2016-06-05 02:15:26 +02:00
|
|
|
# type: (HttpRequest, UserProfile, Optional[bool]) -> HttpResponse
|
2015-11-23 17:09:21 +01:00
|
|
|
result = {}
|
|
|
|
if twenty_four_hour_time is not None and \
|
2016-11-30 21:54:51 +01:00
|
|
|
user_profile.twenty_four_hour_time != twenty_four_hour_time:
|
2015-11-23 17:09:21 +01:00
|
|
|
do_change_twenty_four_hour_time(user_profile, twenty_four_hour_time)
|
|
|
|
|
|
|
|
result['twenty_four_hour_time'] = twenty_four_hour_time
|
|
|
|
|
|
|
|
return json_success(result)
|
|
|
|
|
|
|
|
@authenticated_json_post_view
|
|
|
|
@has_request_variables
|
|
|
|
def json_left_side_userlist(request, user_profile, left_side_userlist=REQ(validator=check_bool, default=None)):
|
2016-06-05 02:15:26 +02:00
|
|
|
# type: (HttpRequest, UserProfile, Optional[bool]) -> HttpResponse
|
2015-11-23 17:09:21 +01:00
|
|
|
result = {}
|
2016-12-03 18:07:49 +01:00
|
|
|
if (left_side_userlist is not None and
|
2016-12-03 18:19:09 +01:00
|
|
|
user_profile.left_side_userlist != left_side_userlist):
|
2016-11-30 21:54:51 +01:00
|
|
|
|
2015-11-23 17:09:21 +01:00
|
|
|
do_change_left_side_userlist(user_profile, left_side_userlist)
|
|
|
|
|
|
|
|
result['left_side_userlist'] = left_side_userlist
|
|
|
|
|
|
|
|
return json_success(result)
|
|
|
|
|
2016-12-22 15:57:06 +01:00
|
|
|
# TODO: Merge json_left_side_userlist and json_time_setting endpoints
|
|
|
|
# into this one; it should be straightforward
|
2016-06-23 11:32:45 +02:00
|
|
|
@has_request_variables
|
2016-12-22 15:57:06 +01:00
|
|
|
def update_display_settings_backend(request, user_profile,
|
|
|
|
default_language=REQ(validator=check_string, default=None)):
|
2016-06-23 11:32:45 +02:00
|
|
|
# type: (HttpRequest, UserProfile, Optional[str]) -> HttpResponse
|
2016-12-22 15:58:18 +01:00
|
|
|
if (default_language is not None and
|
|
|
|
default_language not in get_available_language_codes()):
|
|
|
|
raise JsonableError(_("Invalid language '%s'" % (default_language,)))
|
|
|
|
|
2016-06-23 11:32:45 +02:00
|
|
|
result = {}
|
|
|
|
if (default_language is not None and
|
|
|
|
user_profile.default_language != default_language):
|
2016-12-22 15:58:18 +01:00
|
|
|
do_change_default_language(user_profile, default_language)
|
|
|
|
result['default_language'] = default_language
|
2016-06-23 11:32:45 +02:00
|
|
|
|
|
|
|
return json_success(result)
|
|
|
|
|
2015-11-23 17:09:21 +01:00
|
|
|
@authenticated_json_post_view
|
|
|
|
@has_request_variables
|
|
|
|
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),
|
2016-09-19 22:55:18 +02:00
|
|
|
enable_online_push_notifications=REQ(validator=check_bool,
|
|
|
|
default=None),
|
2015-11-23 17:09:21 +01:00
|
|
|
enable_digest_emails=REQ(validator=check_bool,
|
|
|
|
default=None)):
|
2016-09-19 22:55:18 +02:00
|
|
|
# type: (HttpRequest, UserProfile, Optional[bool], Optional[bool], Optional[bool], Optional[bool], Optional[bool], Optional[bool], Optional[bool], Optional[bool]) -> HttpResponse
|
2015-11-23 17:09:21 +01:00
|
|
|
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
|
|
|
|
|
2016-09-19 22:55:18 +02:00
|
|
|
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
|
|
|
|
|
2015-11-23 17:09:21 +01:00
|
|
|
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)
|
|
|
|
|
2016-12-21 21:29:46 +01:00
|
|
|
def set_avatar_backend(request, user_profile):
|
2016-06-05 02:15:26 +02:00
|
|
|
# type: (HttpRequest, UserProfile) -> HttpResponse
|
2015-11-23 17:09:21 +01:00
|
|
|
if len(request.FILES) != 1:
|
2016-05-25 15:02:02 +02:00
|
|
|
return json_error(_("You must upload exactly one avatar."))
|
2015-11-23 17:09:21 +01:00
|
|
|
|
2016-01-25 01:27:18 +01:00
|
|
|
user_file = list(request.FILES.values())[0]
|
2015-11-23 17:09:21 +01:00
|
|
|
upload_avatar_image(user_file, user_profile, user_profile.email)
|
|
|
|
do_change_avatar_source(user_profile, UserProfile.AVATAR_FROM_USER)
|
|
|
|
user_avatar_url = avatar_url(user_profile)
|
|
|
|
|
|
|
|
json_result = dict(
|
|
|
|
avatar_url = user_avatar_url
|
|
|
|
)
|
|
|
|
return json_success(json_result)
|
|
|
|
|
2016-12-21 18:34:03 +01:00
|
|
|
def delete_avatar_backend(request, user_profile):
|
|
|
|
# type: (HttpRequest, UserProfile) -> HttpResponse
|
|
|
|
do_change_avatar_source(user_profile, UserProfile.AVATAR_FROM_GRAVATAR)
|
|
|
|
gravatar_url = avatar_url(user_profile)
|
|
|
|
|
|
|
|
json_result = dict(
|
|
|
|
avatar_url = gravatar_url
|
|
|
|
)
|
|
|
|
return json_success(json_result)
|
|
|
|
|
2015-11-23 17:09:21 +01:00
|
|
|
@has_request_variables
|
|
|
|
def regenerate_api_key(request, user_profile):
|
2016-06-05 02:15:26 +02:00
|
|
|
# type: (HttpRequest, UserProfile) -> HttpResponse
|
2015-11-23 17:09:21 +01:00
|
|
|
do_regenerate_api_key(user_profile)
|
|
|
|
json_result = dict(
|
|
|
|
api_key = user_profile.api_key
|
|
|
|
)
|
|
|
|
return json_success(json_result)
|
|
|
|
|
|
|
|
@has_request_variables
|
2016-04-08 21:39:00 +02:00
|
|
|
def change_enter_sends(request, user_profile,
|
2016-06-16 09:40:25 +02:00
|
|
|
enter_sends=REQ(validator=check_bool)):
|
2016-06-05 02:15:26 +02:00
|
|
|
# type: (HttpRequest, UserProfile, bool) -> HttpResponse
|
2015-11-23 17:09:21 +01:00
|
|
|
do_change_enter_sends(user_profile, enter_sends)
|
|
|
|
return json_success()
|