mirror of
https://github.com/zulip/zulip.git
synced 2025-11-05 06:23:38 +00:00
Annotate zerver/views/__init__.py.
Also fix typing errors in a few related files. [with tweaks from tabbott]
This commit is contained in:
committed by
Tim Abbott
parent
c9bb93b0d2
commit
a261a6bbac
@@ -2842,7 +2842,7 @@ def apply_events(state, events, user_profile):
|
|||||||
def do_events_register(user_profile, user_client, apply_markdown=True,
|
def do_events_register(user_profile, user_client, apply_markdown=True,
|
||||||
event_types=None, queue_lifespan_secs=0, all_public_streams=False,
|
event_types=None, queue_lifespan_secs=0, all_public_streams=False,
|
||||||
narrow=[]):
|
narrow=[]):
|
||||||
# type: (UserProfile, Client, bool, Optional[Iterable[str]], int, bool, Iterable[Sequence[str]]) -> Dict[str, Any]
|
# type: (UserProfile, Client, bool, Optional[Iterable[str]], int, bool, Iterable[Sequence[text_type]]) -> Dict[str, Any]
|
||||||
# Technically we don't need to check this here because
|
# Technically we don't need to check this here because
|
||||||
# build_narrow_filter will check it, but it's nicer from an error
|
# build_narrow_filter will check it, but it's nicer from an error
|
||||||
# handling perspective to do it before contacting Tornado
|
# handling perspective to do it before contacting Tornado
|
||||||
@@ -3113,7 +3113,7 @@ def do_set_alert_words(user_profile, alert_words):
|
|||||||
notify_alert_words(user_profile, alert_words)
|
notify_alert_words(user_profile, alert_words)
|
||||||
|
|
||||||
def do_set_muted_topics(user_profile, muted_topics):
|
def do_set_muted_topics(user_profile, muted_topics):
|
||||||
# type: (UserProfile, List[Union[List[text_type], Tuple[text_type, text_type]]]) -> None
|
# type: (UserProfile, Union[List[List[text_type]], List[Tuple[text_type, text_type]]]) -> None
|
||||||
user_profile.muted_topics = ujson.dumps(muted_topics)
|
user_profile.muted_topics = ujson.dumps(muted_topics)
|
||||||
user_profile.save(update_fields=['muted_topics'])
|
user_profile.save(update_fields=['muted_topics'])
|
||||||
event = dict(type="muted_topics", muted_topics=muted_topics)
|
event = dict(type="muted_topics", muted_topics=muted_topics)
|
||||||
|
|||||||
@@ -383,7 +383,7 @@ class EventsRegisterTest(AuthedTestCase):
|
|||||||
('type', equals('muted_topics')),
|
('type', equals('muted_topics')),
|
||||||
('muted_topics', check_list(check_list(check_string, 2))),
|
('muted_topics', check_list(check_list(check_string, 2))),
|
||||||
])
|
])
|
||||||
events = self.do_test(lambda: do_set_muted_topics(self.user_profile, [["Denmark", "topic"]]))
|
events = self.do_test(lambda: do_set_muted_topics(self.user_profile, [[u"Denmark", u"topic"]]))
|
||||||
error = muted_topics_checker('events[0]', events[0])
|
error = muted_topics_checker('events[0]', events[0])
|
||||||
self.assert_on_error(error)
|
self.assert_on_error(error)
|
||||||
|
|
||||||
@@ -958,22 +958,22 @@ class TestEventsRegisterNarrowDefaults(TestCase):
|
|||||||
# type: () -> None
|
# type: () -> None
|
||||||
self.user_profile.default_events_register_stream_id = None
|
self.user_profile.default_events_register_stream_id = None
|
||||||
self.user_profile.save()
|
self.user_profile.save()
|
||||||
result = _default_narrow(self.user_profile, [('stream', 'my_stream')])
|
result = _default_narrow(self.user_profile, [[u'stream', u'my_stream']])
|
||||||
self.assertEqual(result, [('stream', 'my_stream')])
|
self.assertEqual(result, [[u'stream', u'my_stream']])
|
||||||
|
|
||||||
def test_use_passed_narrow_with_default(self):
|
def test_use_passed_narrow_with_default(self):
|
||||||
# type: () -> None
|
# type: () -> None
|
||||||
self.user_profile.default_events_register_stream_id = self.stream.id
|
self.user_profile.default_events_register_stream_id = self.stream.id
|
||||||
self.user_profile.save()
|
self.user_profile.save()
|
||||||
result = _default_narrow(self.user_profile, [('stream', 'my_stream')])
|
result = _default_narrow(self.user_profile, [[u'stream', u'my_stream']])
|
||||||
self.assertEqual(result, [('stream', 'my_stream')])
|
self.assertEqual(result, [[u'stream', u'my_stream']])
|
||||||
|
|
||||||
def test_use_default_if_narrow_is_empty(self):
|
def test_use_default_if_narrow_is_empty(self):
|
||||||
# type: () -> None
|
# type: () -> None
|
||||||
self.user_profile.default_events_register_stream_id = self.stream.id
|
self.user_profile.default_events_register_stream_id = self.stream.id
|
||||||
self.user_profile.save()
|
self.user_profile.save()
|
||||||
result = _default_narrow(self.user_profile, [])
|
result = _default_narrow(self.user_profile, [])
|
||||||
self.assertEqual(result, [('stream', 'Verona')])
|
self.assertEqual(result, [[u'stream', u'Verona']])
|
||||||
|
|
||||||
def test_use_narrow_if_default_is_none(self):
|
def test_use_narrow_if_default_is_none(self):
|
||||||
# type: () -> None
|
# type: () -> None
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
from __future__ import absolute_import
|
from __future__ import absolute_import
|
||||||
from typing import Any
|
from typing import Any, List, Dict, Optional, Callable, Tuple
|
||||||
|
|
||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.auth import authenticate, login, get_backends
|
from django.contrib.auth import authenticate, login, get_backends
|
||||||
from django.core.urlresolvers import reverse
|
from django.core.urlresolvers import reverse
|
||||||
from django.http import HttpResponseRedirect, HttpResponseForbidden, HttpResponse
|
from django.http import HttpResponseRedirect, HttpResponseForbidden, HttpResponse, HttpRequest
|
||||||
from django.shortcuts import redirect
|
from django.shortcuts import redirect
|
||||||
from django.template import RequestContext, loader
|
from django.template import RequestContext, loader
|
||||||
from django.utils.timezone import now
|
from django.utils.timezone import now
|
||||||
@@ -61,6 +61,7 @@ import datetime
|
|||||||
import ujson
|
import ujson
|
||||||
import simplejson
|
import simplejson
|
||||||
import re
|
import re
|
||||||
|
from six import text_type
|
||||||
from six.moves import urllib
|
from six.moves import urllib
|
||||||
import base64
|
import base64
|
||||||
import time
|
import time
|
||||||
@@ -74,10 +75,12 @@ from zerver.lib.rest import rest_dispatch as _rest_dispatch
|
|||||||
rest_dispatch = csrf_exempt((lambda request, *args, **kwargs: _rest_dispatch(request, globals(), *args, **kwargs)))
|
rest_dispatch = csrf_exempt((lambda request, *args, **kwargs: _rest_dispatch(request, globals(), *args, **kwargs)))
|
||||||
|
|
||||||
def name_changes_disabled(realm):
|
def name_changes_disabled(realm):
|
||||||
|
# type: (Realm) -> bool
|
||||||
return settings.NAME_CHANGES_DISABLED or realm.name_changes_disabled
|
return settings.NAME_CHANGES_DISABLED or realm.name_changes_disabled
|
||||||
|
|
||||||
@require_post
|
@require_post
|
||||||
def accounts_register(request):
|
def accounts_register(request):
|
||||||
|
# type: (HttpRequest) -> HttpResponse
|
||||||
key = request.POST['key']
|
key = request.POST['key']
|
||||||
confirmation = Confirmation.objects.get(confirmation_key=key)
|
confirmation = Confirmation.objects.get(confirmation_key=key)
|
||||||
prereg_user = confirmation.content_object
|
prereg_user = confirmation.content_object
|
||||||
@@ -267,6 +270,7 @@ from zerver.lib.ccache import make_ccache
|
|||||||
@has_request_variables
|
@has_request_variables
|
||||||
def webathena_kerberos_login(request, user_profile,
|
def webathena_kerberos_login(request, user_profile,
|
||||||
cred=REQ(default=None)):
|
cred=REQ(default=None)):
|
||||||
|
# type (HttpRequest, UserProfile, str) -> HttpResponse
|
||||||
if cred is None:
|
if cred is None:
|
||||||
return json_error(_("Could not find Kerberos credential"))
|
return json_error(_("Could not find Kerberos credential"))
|
||||||
if not user_profile.realm.domain == "mit.edu":
|
if not user_profile.realm.domain == "mit.edu":
|
||||||
@@ -298,6 +302,7 @@ def webathena_kerberos_login(request, user_profile,
|
|||||||
return json_success()
|
return json_success()
|
||||||
|
|
||||||
def api_endpoint_docs(request):
|
def api_endpoint_docs(request):
|
||||||
|
# type: (HttpRequest) -> HttpResponse
|
||||||
raw_calls = open('templates/zerver/api_content.json', 'r').read()
|
raw_calls = open('templates/zerver/api_content.json', 'r').read()
|
||||||
calls = ujson.loads(raw_calls)
|
calls = ujson.loads(raw_calls)
|
||||||
langs = set()
|
langs = set()
|
||||||
@@ -323,11 +328,12 @@ def api_endpoint_docs(request):
|
|||||||
|
|
||||||
@authenticated_json_post_view
|
@authenticated_json_post_view
|
||||||
@has_request_variables
|
@has_request_variables
|
||||||
def json_invite_users(request, user_profile, invitee_emails=REQ()):
|
def json_invite_users(request, user_profile, invitee_emails_raw=REQ("invitee_emails")):
|
||||||
if not invitee_emails:
|
# type: (HttpRequest, UserProfile, str) -> HttpResponse
|
||||||
|
if not invitee_emails_raw:
|
||||||
return json_error(_("You must specify at least one email address."))
|
return json_error(_("You must specify at least one email address."))
|
||||||
|
|
||||||
invitee_emails = set(re.split(r'[, \n]', invitee_emails))
|
invitee_emails = set(re.split(r'[, \n]', invitee_emails_raw))
|
||||||
|
|
||||||
stream_names = request.POST.getlist('stream')
|
stream_names = request.POST.getlist('stream')
|
||||||
if not stream_names:
|
if not stream_names:
|
||||||
@@ -354,6 +360,7 @@ def json_invite_users(request, user_profile, invitee_emails=REQ()):
|
|||||||
return json_success()
|
return json_success()
|
||||||
|
|
||||||
def create_homepage_form(request, user_info=None):
|
def create_homepage_form(request, user_info=None):
|
||||||
|
# type: (HttpRequest, Optional[Dict[str, Any]]) -> HomepageForm
|
||||||
if user_info:
|
if user_info:
|
||||||
return HomepageForm(user_info, domain=request.session.get("domain"))
|
return HomepageForm(user_info, domain=request.session.get("domain"))
|
||||||
# An empty fields dict is not treated the same way as not
|
# An empty fields dict is not treated the same way as not
|
||||||
@@ -361,6 +368,7 @@ def create_homepage_form(request, user_info=None):
|
|||||||
return HomepageForm(domain=request.session.get("domain"))
|
return HomepageForm(domain=request.session.get("domain"))
|
||||||
|
|
||||||
def maybe_send_to_registration(request, email, full_name=''):
|
def maybe_send_to_registration(request, email, full_name=''):
|
||||||
|
# type: (HttpRequest, text_type, text_type) -> HttpResponse
|
||||||
form = create_homepage_form(request, user_info={'email': email})
|
form = create_homepage_form(request, user_info={'email': email})
|
||||||
request.verified_email = None
|
request.verified_email = None
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
@@ -390,6 +398,7 @@ def maybe_send_to_registration(request, email, full_name=''):
|
|||||||
request=request)
|
request=request)
|
||||||
|
|
||||||
def login_or_register_remote_user(request, remote_username, user_profile, full_name=''):
|
def login_or_register_remote_user(request, remote_username, user_profile, full_name=''):
|
||||||
|
# type: (HttpRequest, str, UserProfile, text_type) -> HttpResponse
|
||||||
if user_profile is None or user_profile.is_mirror_dummy:
|
if user_profile is None or user_profile.is_mirror_dummy:
|
||||||
# Since execution has reached here, the client specified a remote user
|
# Since execution has reached here, the client specified a remote user
|
||||||
# but no associated user account exists. Send them over to the
|
# but no associated user account exists. Send them over to the
|
||||||
@@ -401,6 +410,7 @@ def login_or_register_remote_user(request, remote_username, user_profile, full_n
|
|||||||
request.get_host()))
|
request.get_host()))
|
||||||
|
|
||||||
def remote_user_sso(request):
|
def remote_user_sso(request):
|
||||||
|
# type: (HttpRequest) -> HttpResponse
|
||||||
try:
|
try:
|
||||||
remote_user = request.META["REMOTE_USER"]
|
remote_user = request.META["REMOTE_USER"]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
@@ -411,6 +421,7 @@ def remote_user_sso(request):
|
|||||||
|
|
||||||
@csrf_exempt
|
@csrf_exempt
|
||||||
def remote_user_jwt(request):
|
def remote_user_jwt(request):
|
||||||
|
# type: (HttpRequest) -> HttpResponse
|
||||||
try:
|
try:
|
||||||
json_web_token = request.POST["json_web_token"]
|
json_web_token = request.POST["json_web_token"]
|
||||||
payload, signing_input, header, signature = jwt.load(json_web_token)
|
payload, signing_input, header, signature = jwt.load(json_web_token)
|
||||||
@@ -445,9 +456,11 @@ def remote_user_jwt(request):
|
|||||||
return login_or_register_remote_user(request, email, user_profile, remote_user)
|
return login_or_register_remote_user(request, email, user_profile, remote_user)
|
||||||
|
|
||||||
def google_oauth2_csrf(request, value):
|
def google_oauth2_csrf(request, value):
|
||||||
|
# type: (HttpRequest, str) -> HttpResponse
|
||||||
return hmac.new(get_token(request).encode('utf-8'), value, hashlib.sha256).hexdigest()
|
return hmac.new(get_token(request).encode('utf-8'), value, hashlib.sha256).hexdigest()
|
||||||
|
|
||||||
def start_google_oauth2(request):
|
def start_google_oauth2(request):
|
||||||
|
# type: (HttpRequest) -> HttpResponse
|
||||||
uri = 'https://accounts.google.com/o/oauth2/auth?'
|
uri = 'https://accounts.google.com/o/oauth2/auth?'
|
||||||
cur_time = str(int(time.time()))
|
cur_time = str(int(time.time()))
|
||||||
csrf_state = '{}:{}'.format(
|
csrf_state = '{}:{}'.format(
|
||||||
@@ -471,12 +484,14 @@ def start_google_oauth2(request):
|
|||||||
# from a property to a function
|
# from a property to a function
|
||||||
requests_json_is_function = callable(requests.Response.json)
|
requests_json_is_function = callable(requests.Response.json)
|
||||||
def extract_json_response(resp):
|
def extract_json_response(resp):
|
||||||
|
# type: (HttpResponse) -> Dict[str, Any]
|
||||||
if requests_json_is_function:
|
if requests_json_is_function:
|
||||||
return resp.json()
|
return resp.json()
|
||||||
else:
|
else:
|
||||||
return resp.json
|
return resp.json
|
||||||
|
|
||||||
def finish_google_oauth2(request):
|
def finish_google_oauth2(request):
|
||||||
|
# type: (HttpRequest) -> HttpResponse
|
||||||
error = request.GET.get('error')
|
error = request.GET.get('error')
|
||||||
if error == 'access_denied':
|
if error == 'access_denied':
|
||||||
return redirect('/')
|
return redirect('/')
|
||||||
@@ -538,6 +553,7 @@ def finish_google_oauth2(request):
|
|||||||
return login_or_register_remote_user(request, email_address, user_profile, full_name)
|
return login_or_register_remote_user(request, email_address, user_profile, full_name)
|
||||||
|
|
||||||
def login_page(request, **kwargs):
|
def login_page(request, **kwargs):
|
||||||
|
# type: (HttpRequest, **Any) -> HttpResponse
|
||||||
extra_context = kwargs.pop('extra_context', {})
|
extra_context = kwargs.pop('extra_context', {})
|
||||||
if dev_auth_enabled():
|
if dev_auth_enabled():
|
||||||
# Development environments usually have only a few users, but
|
# Development environments usually have only a few users, but
|
||||||
@@ -559,6 +575,7 @@ def login_page(request, **kwargs):
|
|||||||
return template_response
|
return template_response
|
||||||
|
|
||||||
def dev_direct_login(request, **kwargs):
|
def dev_direct_login(request, **kwargs):
|
||||||
|
# type: (HttpRequest, **Any) -> HttpResponse
|
||||||
# This function allows logging in without a password and should only be called in development environments.
|
# This function allows logging in without a password and should only be called in development environments.
|
||||||
# It may be called if the DevAuthBackend is included in settings.AUTHENTICATION_BACKENDS
|
# It may be called if the DevAuthBackend is included in settings.AUTHENTICATION_BACKENDS
|
||||||
if (not dev_auth_enabled()) or settings.PRODUCTION:
|
if (not dev_auth_enabled()) or settings.PRODUCTION:
|
||||||
@@ -575,8 +592,10 @@ def dev_direct_login(request, **kwargs):
|
|||||||
@authenticated_json_post_view
|
@authenticated_json_post_view
|
||||||
@has_request_variables
|
@has_request_variables
|
||||||
def json_bulk_invite_users(request, user_profile,
|
def json_bulk_invite_users(request, user_profile,
|
||||||
invitee_emails=REQ(validator=check_list(check_string))):
|
invitee_emails_list=REQ('invitee_emails',
|
||||||
invitee_emails = set(invitee_emails)
|
validator=check_list(check_string))):
|
||||||
|
# type: (HttpRequest, UserProfile, List[str]) -> HttpResponse
|
||||||
|
invitee_emails = set(invitee_emails_list)
|
||||||
streams = get_default_subs(user_profile)
|
streams = get_default_subs(user_profile)
|
||||||
|
|
||||||
ret_error, error_data = do_invite_users(user_profile, invitee_emails, streams)
|
ret_error, error_data = do_invite_users(user_profile, invitee_emails, streams)
|
||||||
@@ -594,6 +613,7 @@ def json_bulk_invite_users(request, user_profile,
|
|||||||
|
|
||||||
@zulip_login_required
|
@zulip_login_required
|
||||||
def initial_invite_page(request):
|
def initial_invite_page(request):
|
||||||
|
# type: (HttpRequest) -> HttpResponse
|
||||||
user = request.user
|
user = request.user
|
||||||
# Only show the bulk-invite page for the first user in a realm
|
# Only show the bulk-invite page for the first user in a realm
|
||||||
domain_count = len(UserProfile.objects.filter(realm=user.realm))
|
domain_count = len(UserProfile.objects.filter(realm=user.realm))
|
||||||
@@ -610,9 +630,11 @@ def initial_invite_page(request):
|
|||||||
|
|
||||||
@require_post
|
@require_post
|
||||||
def logout_then_login(request, **kwargs):
|
def logout_then_login(request, **kwargs):
|
||||||
|
# type: (HttpRequest, **Any) -> HttpResponse
|
||||||
return django_logout_then_login(request, kwargs)
|
return django_logout_then_login(request, kwargs)
|
||||||
|
|
||||||
def create_preregistration_user(email, request):
|
def create_preregistration_user(email, request):
|
||||||
|
# type: (text_type, HttpRequest) -> HttpResponse
|
||||||
domain = request.session.get("domain")
|
domain = request.session.get("domain")
|
||||||
if completely_open(domain):
|
if completely_open(domain):
|
||||||
# Clear the "domain" from the session object; it's no longer needed
|
# Clear the "domain" from the session object; it's no longer needed
|
||||||
@@ -631,6 +653,7 @@ def create_preregistration_user(email, request):
|
|||||||
return PreregistrationUser.objects.create(email=email)
|
return PreregistrationUser.objects.create(email=email)
|
||||||
|
|
||||||
def accounts_home_with_domain(request, domain):
|
def accounts_home_with_domain(request, domain):
|
||||||
|
# type: (HttpRequest, str) -> HttpResponse
|
||||||
if completely_open(domain):
|
if completely_open(domain):
|
||||||
# You can sign up for a completely open realm through a
|
# You can sign up for a completely open realm through a
|
||||||
# special registration path that contains the domain in the
|
# special registration path that contains the domain in the
|
||||||
@@ -643,6 +666,7 @@ def accounts_home_with_domain(request, domain):
|
|||||||
return HttpResponseRedirect(reverse('zerver.views.accounts_home'))
|
return HttpResponseRedirect(reverse('zerver.views.accounts_home'))
|
||||||
|
|
||||||
def send_registration_completion_email(email, request):
|
def send_registration_completion_email(email, request):
|
||||||
|
# type: (str, HttpRequest) -> HttpResponse
|
||||||
"""
|
"""
|
||||||
Send an email with a confirmation link to the provided e-mail so the user
|
Send an email with a confirmation link to the provided e-mail so the user
|
||||||
can complete their registration.
|
can complete their registration.
|
||||||
@@ -654,6 +678,7 @@ def send_registration_completion_email(email, request):
|
|||||||
additional_context=context)
|
additional_context=context)
|
||||||
|
|
||||||
def accounts_home(request):
|
def accounts_home(request):
|
||||||
|
# type: (HttpRequest) -> HttpResponse
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
form = create_homepage_form(request, user_info=request.POST)
|
form = create_homepage_form(request, user_info=request.POST)
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
@@ -673,6 +698,7 @@ def accounts_home(request):
|
|||||||
request=request)
|
request=request)
|
||||||
|
|
||||||
def approximate_unread_count(user_profile):
|
def approximate_unread_count(user_profile):
|
||||||
|
# type: (UserProfile) -> int
|
||||||
not_in_home_view_recipients = [sub.recipient.id for sub in \
|
not_in_home_view_recipients = [sub.recipient.id for sub in \
|
||||||
Subscription.objects.filter(
|
Subscription.objects.filter(
|
||||||
user_profile=user_profile, in_home_view=False)]
|
user_profile=user_profile, in_home_view=False)]
|
||||||
@@ -692,6 +718,7 @@ def approximate_unread_count(user_profile):
|
|||||||
flags=UserMessage.flags.read).count()
|
flags=UserMessage.flags.read).count()
|
||||||
|
|
||||||
def sent_time_in_epoch_seconds(user_message):
|
def sent_time_in_epoch_seconds(user_message):
|
||||||
|
# type: (UserMessage) -> float
|
||||||
# user_message is a UserMessage object.
|
# user_message is a UserMessage object.
|
||||||
if not user_message:
|
if not user_message:
|
||||||
return None
|
return None
|
||||||
@@ -701,6 +728,7 @@ def sent_time_in_epoch_seconds(user_message):
|
|||||||
|
|
||||||
@zulip_login_required
|
@zulip_login_required
|
||||||
def home(request):
|
def home(request):
|
||||||
|
# type: (HttpRequest) -> HttpResponse
|
||||||
# We need to modify the session object every two weeks or it will expire.
|
# We need to modify the session object every two weeks or it will expire.
|
||||||
# This line makes reloading the page a sufficient action to keep the
|
# This line makes reloading the page a sufficient action to keep the
|
||||||
# session alive.
|
# session alive.
|
||||||
@@ -892,9 +920,11 @@ def home(request):
|
|||||||
|
|
||||||
@zulip_login_required
|
@zulip_login_required
|
||||||
def desktop_home(request):
|
def desktop_home(request):
|
||||||
|
# type: (HttpRequest) -> HttpResponse
|
||||||
return HttpResponseRedirect(reverse('zerver.views.home'))
|
return HttpResponseRedirect(reverse('zerver.views.home'))
|
||||||
|
|
||||||
def is_buggy_ua(agent):
|
def is_buggy_ua(agent):
|
||||||
|
# type: (str) -> bool
|
||||||
"""Discrimiate CSS served to clients based on User Agent
|
"""Discrimiate CSS served to clients based on User Agent
|
||||||
|
|
||||||
Due to QTBUG-3467, @font-face is not supported in QtWebKit.
|
Due to QTBUG-3467, @font-face is not supported in QtWebKit.
|
||||||
@@ -905,11 +935,13 @@ def is_buggy_ua(agent):
|
|||||||
"Mac" not in agent
|
"Mac" not in agent
|
||||||
|
|
||||||
def get_pointer_backend(request, user_profile):
|
def get_pointer_backend(request, user_profile):
|
||||||
|
# type: (HttpRequest, UserProfile) -> HttpResponse
|
||||||
return json_success({'pointer': user_profile.pointer})
|
return json_success({'pointer': user_profile.pointer})
|
||||||
|
|
||||||
@has_request_variables
|
@has_request_variables
|
||||||
def update_pointer_backend(request, user_profile,
|
def update_pointer_backend(request, user_profile,
|
||||||
pointer=REQ(converter=to_non_negative_int)):
|
pointer=REQ(converter=to_non_negative_int)):
|
||||||
|
# type: (HttpRequest, UserProfile, int) -> HttpResponse
|
||||||
if pointer <= user_profile.pointer:
|
if pointer <= user_profile.pointer:
|
||||||
return json_success()
|
return json_success()
|
||||||
|
|
||||||
@@ -928,12 +960,14 @@ def update_pointer_backend(request, user_profile,
|
|||||||
return json_success()
|
return json_success()
|
||||||
|
|
||||||
def generate_client_id():
|
def generate_client_id():
|
||||||
|
# type: () -> str
|
||||||
return generate_random_token(32)
|
return generate_random_token(32)
|
||||||
|
|
||||||
# The order of creation of the various dictionaries are important.
|
# The order of creation of the various dictionaries are important.
|
||||||
# We filter on {userprofile,stream,subscription_recipient}_ids.
|
# We filter on {userprofile,stream,subscription_recipient}_ids.
|
||||||
@require_realm_admin
|
@require_realm_admin
|
||||||
def export(request, user_profile):
|
def export(request, user_profile):
|
||||||
|
# type: (HttpRequest, UserProfile) -> HttpResponse
|
||||||
if (Message.objects.filter(sender__realm=user_profile.realm).count() > 1000000 or
|
if (Message.objects.filter(sender__realm=user_profile.realm).count() > 1000000 or
|
||||||
UserMessage.objects.filter(user_profile__realm=user_profile.realm).count() > 3000000):
|
UserMessage.objects.filter(user_profile__realm=user_profile.realm).count() > 3000000):
|
||||||
return json_error(_("Realm has too much data for non-batched export."))
|
return json_error(_("Realm has too much data for non-batched export."))
|
||||||
@@ -1000,6 +1034,7 @@ def export(request, user_profile):
|
|||||||
return json_success(response)
|
return json_success(response)
|
||||||
|
|
||||||
def get_profile_backend(request, user_profile):
|
def get_profile_backend(request, user_profile):
|
||||||
|
# type: (HttpRequest, UserProfile) -> HttpResponse
|
||||||
result = dict(pointer = user_profile.pointer,
|
result = dict(pointer = user_profile.pointer,
|
||||||
client_id = generate_client_id(),
|
client_id = generate_client_id(),
|
||||||
max_message_id = -1)
|
max_message_id = -1)
|
||||||
@@ -1017,8 +1052,9 @@ def update_realm(request, user_profile, name=REQ(validator=check_string, default
|
|||||||
invite_required=REQ(validator=check_bool, default=None),
|
invite_required=REQ(validator=check_bool, default=None),
|
||||||
invite_by_admins_only=REQ(validator=check_bool, default=None),
|
invite_by_admins_only=REQ(validator=check_bool, default=None),
|
||||||
create_stream_by_admins_only=REQ(validator=check_bool, default=None)):
|
create_stream_by_admins_only=REQ(validator=check_bool, default=None)):
|
||||||
|
# type: (HttpRequest, UserProfile, Optional[str], Optional[bool], Optional[bool], Optional[bool], Optional[bool]) -> HttpResponse
|
||||||
realm = user_profile.realm
|
realm = user_profile.realm
|
||||||
data = {}
|
data = {} # type: Dict[str, Any]
|
||||||
if name is not None and realm.name != name:
|
if name is not None and realm.name != name:
|
||||||
do_set_realm_name(realm, name)
|
do_set_realm_name(realm, name)
|
||||||
data['name'] = 'updated'
|
data['name'] = 'updated'
|
||||||
@@ -1039,6 +1075,7 @@ def update_realm(request, user_profile, name=REQ(validator=check_string, default
|
|||||||
@authenticated_json_post_view
|
@authenticated_json_post_view
|
||||||
@has_request_variables
|
@has_request_variables
|
||||||
def json_upload_file(request, user_profile):
|
def json_upload_file(request, user_profile):
|
||||||
|
# type: (HttpRequest, UserProfile) -> HttpResponse
|
||||||
if len(request.FILES) == 0:
|
if len(request.FILES) == 0:
|
||||||
return json_error(_("You must specify a file to upload"))
|
return json_error(_("You must specify a file to upload"))
|
||||||
if len(request.FILES) != 1:
|
if len(request.FILES) != 1:
|
||||||
@@ -1053,15 +1090,16 @@ def json_upload_file(request, user_profile):
|
|||||||
|
|
||||||
@zulip_login_required
|
@zulip_login_required
|
||||||
@has_request_variables
|
@has_request_variables
|
||||||
def get_uploaded_file(request, realm_id, filename,
|
def get_uploaded_file(request, realm_id_str, filename,
|
||||||
redir=REQ(validator=check_bool, default=True)):
|
redir=REQ(validator=check_bool, default=True)):
|
||||||
|
# type: (HttpRequest, str, str, bool) -> HttpResponse
|
||||||
if settings.LOCAL_UPLOADS_DIR is not None:
|
if settings.LOCAL_UPLOADS_DIR is not None:
|
||||||
return HttpResponseForbidden() # Should have been served by nginx
|
return HttpResponseForbidden() # Should have been served by nginx
|
||||||
|
|
||||||
user_profile = request.user
|
user_profile = request.user
|
||||||
url_path = "%s/%s" % (realm_id, filename)
|
url_path = "%s/%s" % (realm_id_str, filename)
|
||||||
|
|
||||||
if realm_id == "unk":
|
if realm_id_str == "unk":
|
||||||
realm_id = get_realm_for_filename(url_path)
|
realm_id = get_realm_for_filename(url_path)
|
||||||
if realm_id is None:
|
if realm_id is None:
|
||||||
# File does not exist
|
# File does not exist
|
||||||
@@ -1081,7 +1119,7 @@ def get_uploaded_file(request, realm_id, filename,
|
|||||||
@require_post
|
@require_post
|
||||||
@has_request_variables
|
@has_request_variables
|
||||||
def api_fetch_api_key(request, username=REQ(), password=REQ()):
|
def api_fetch_api_key(request, username=REQ(), password=REQ()):
|
||||||
# type: (Any, Any, Any) -> Any
|
# type: (HttpRequest, str, str) -> HttpResponse
|
||||||
return_data = {} # type: Dict[str, bool]
|
return_data = {} # type: Dict[str, bool]
|
||||||
if username == "google-oauth2-token":
|
if username == "google-oauth2-token":
|
||||||
user_profile = authenticate(google_oauth2_token=password, return_data=return_data)
|
user_profile = authenticate(google_oauth2_token=password, return_data=return_data)
|
||||||
@@ -1103,23 +1141,27 @@ def api_fetch_api_key(request, username=REQ(), password=REQ()):
|
|||||||
@authenticated_json_post_view
|
@authenticated_json_post_view
|
||||||
@has_request_variables
|
@has_request_variables
|
||||||
def json_fetch_api_key(request, user_profile, password=REQ(default='')):
|
def json_fetch_api_key(request, user_profile, password=REQ(default='')):
|
||||||
|
# type: (HttpRequest, UserProfile, str) -> HttpResponse
|
||||||
if password_auth_enabled(user_profile.realm) and not user_profile.check_password(password):
|
if password_auth_enabled(user_profile.realm) and not user_profile.check_password(password):
|
||||||
return json_error(_("Your username or password is incorrect."))
|
return json_error(_("Your username or password is incorrect."))
|
||||||
return json_success({"api_key": user_profile.api_key})
|
return json_success({"api_key": user_profile.api_key})
|
||||||
|
|
||||||
@csrf_exempt
|
@csrf_exempt
|
||||||
def api_fetch_google_client_id(request):
|
def api_fetch_google_client_id(request):
|
||||||
|
# type: (HttpRequest) -> HttpResponse
|
||||||
if not settings.GOOGLE_CLIENT_ID:
|
if not settings.GOOGLE_CLIENT_ID:
|
||||||
return json_error(_("GOOGLE_CLIENT_ID is not configured"), status=400)
|
return json_error(_("GOOGLE_CLIENT_ID is not configured"), status=400)
|
||||||
return json_success({"google_client_id": settings.GOOGLE_CLIENT_ID})
|
return json_success({"google_client_id": settings.GOOGLE_CLIENT_ID})
|
||||||
|
|
||||||
def get_status_list(requesting_user_profile):
|
def get_status_list(requesting_user_profile):
|
||||||
|
# type: (UserProfile) -> Dict[str, Any]
|
||||||
return {'presences': get_status_dict(requesting_user_profile),
|
return {'presences': get_status_dict(requesting_user_profile),
|
||||||
'server_timestamp': time.time()}
|
'server_timestamp': time.time()}
|
||||||
|
|
||||||
@has_request_variables
|
@has_request_variables
|
||||||
def update_active_status_backend(request, user_profile, status=REQ(),
|
def update_active_status_backend(request, user_profile, status=REQ(),
|
||||||
new_user_input=REQ(validator=check_bool, default=False)):
|
new_user_input=REQ(validator=check_bool, default=False)):
|
||||||
|
# type: (HttpRequest, UserProfile, str, bool) -> HttpResponse
|
||||||
status_val = UserPresence.status_from_string(status)
|
status_val = UserPresence.status_from_string(status)
|
||||||
if status_val is None:
|
if status_val is None:
|
||||||
raise JsonableError(_("Invalid presence status: %s") % (status,))
|
raise JsonableError(_("Invalid presence status: %s") % (status,))
|
||||||
@@ -1144,6 +1186,7 @@ def update_active_status_backend(request, user_profile, status=REQ(),
|
|||||||
|
|
||||||
@authenticated_json_post_view
|
@authenticated_json_post_view
|
||||||
def json_get_active_statuses(request, user_profile):
|
def json_get_active_statuses(request, user_profile):
|
||||||
|
# type: (HttpRequest, UserProfile) -> HttpResponse
|
||||||
return json_success(get_status_list(user_profile))
|
return json_success(get_status_list(user_profile))
|
||||||
|
|
||||||
# Does not need to be authenticated because it's called from rest_dispatch
|
# Does not need to be authenticated because it's called from rest_dispatch
|
||||||
@@ -1151,20 +1194,23 @@ def json_get_active_statuses(request, user_profile):
|
|||||||
def api_events_register(request, user_profile,
|
def api_events_register(request, user_profile,
|
||||||
apply_markdown=REQ(default=False, validator=check_bool),
|
apply_markdown=REQ(default=False, validator=check_bool),
|
||||||
all_public_streams=REQ(default=None, validator=check_bool)):
|
all_public_streams=REQ(default=None, validator=check_bool)):
|
||||||
|
# type: (HttpRequest, UserProfile, bool, Optional[bool]) -> HttpResponse
|
||||||
return events_register_backend(request, user_profile,
|
return events_register_backend(request, user_profile,
|
||||||
apply_markdown=apply_markdown,
|
apply_markdown=apply_markdown,
|
||||||
all_public_streams=all_public_streams)
|
all_public_streams=all_public_streams)
|
||||||
|
|
||||||
def _default_all_public_streams(user_profile, all_public_streams):
|
def _default_all_public_streams(user_profile, all_public_streams):
|
||||||
|
# type: (UserProfile, Optional[bool]) -> bool
|
||||||
if all_public_streams is not None:
|
if all_public_streams is not None:
|
||||||
return all_public_streams
|
return all_public_streams
|
||||||
else:
|
else:
|
||||||
return user_profile.default_all_public_streams
|
return user_profile.default_all_public_streams
|
||||||
|
|
||||||
def _default_narrow(user_profile, narrow):
|
def _default_narrow(user_profile, narrow):
|
||||||
|
# type: (UserProfile, List[List[text_type]]) -> List[List[text_type]]
|
||||||
default_stream = user_profile.default_events_register_stream
|
default_stream = user_profile.default_events_register_stream
|
||||||
if not narrow and user_profile.default_events_register_stream is not None:
|
if not narrow and user_profile.default_events_register_stream is not None:
|
||||||
narrow = [('stream', default_stream.name)]
|
narrow = [['stream', default_stream.name]]
|
||||||
return narrow
|
return narrow
|
||||||
|
|
||||||
@has_request_variables
|
@has_request_variables
|
||||||
@@ -1173,7 +1219,7 @@ def events_register_backend(request, user_profile, apply_markdown=True,
|
|||||||
event_types=REQ(validator=check_list(check_string), default=None),
|
event_types=REQ(validator=check_list(check_string), default=None),
|
||||||
narrow=REQ(validator=check_list(check_list(check_string, length=2)), default=[]),
|
narrow=REQ(validator=check_list(check_list(check_string, length=2)), default=[]),
|
||||||
queue_lifespan_secs=REQ(converter=int, default=0)):
|
queue_lifespan_secs=REQ(converter=int, default=0)):
|
||||||
|
# type: (HttpRequest, UserProfile, bool, Optional[bool], Optional[List[str]], List[List[text_type]], int) -> HttpResponse
|
||||||
all_public_streams = _default_all_public_streams(user_profile, all_public_streams)
|
all_public_streams = _default_all_public_streams(user_profile, all_public_streams)
|
||||||
narrow = _default_narrow(user_profile, narrow)
|
narrow = _default_narrow(user_profile, narrow)
|
||||||
|
|
||||||
@@ -1186,6 +1232,7 @@ def events_register_backend(request, user_profile, apply_markdown=True,
|
|||||||
@authenticated_json_post_view
|
@authenticated_json_post_view
|
||||||
@has_request_variables
|
@has_request_variables
|
||||||
def json_refer_friend(request, user_profile, email=REQ()):
|
def json_refer_friend(request, user_profile, email=REQ()):
|
||||||
|
# type: (HttpRequest, UserProfile, str) -> HttpResponse
|
||||||
if not email:
|
if not email:
|
||||||
return json_error(_("No email address specified"))
|
return json_error(_("No email address specified"))
|
||||||
if user_profile.invites_granted - user_profile.invites_used <= 0:
|
if user_profile.invites_granted - user_profile.invites_used <= 0:
|
||||||
@@ -1199,20 +1246,22 @@ def json_refer_friend(request, user_profile, email=REQ()):
|
|||||||
@has_request_variables
|
@has_request_variables
|
||||||
def json_set_muted_topics(request, user_profile,
|
def json_set_muted_topics(request, user_profile,
|
||||||
muted_topics=REQ(validator=check_list(check_list(check_string, length=2)), default=[])):
|
muted_topics=REQ(validator=check_list(check_list(check_string, length=2)), default=[])):
|
||||||
|
# type: (HttpRequest, UserProfile, List[List[text_type]]) -> HttpResponse
|
||||||
do_set_muted_topics(user_profile, muted_topics)
|
do_set_muted_topics(user_profile, muted_topics)
|
||||||
return json_success()
|
return json_success()
|
||||||
|
|
||||||
def add_push_device_token(request, user_profile, token, kind, ios_app_id=None):
|
def add_push_device_token(request, user_profile, token_str, kind, ios_app_id=None):
|
||||||
if token == '' or len(token) > 4096:
|
# type: (HttpRequest, UserProfile, str, int, Optional[str]) -> HttpResponse
|
||||||
|
if token_str == '' or len(token_str) > 4096:
|
||||||
return json_error(_('Empty or invalid length token'))
|
return json_error(_('Empty or invalid length token'))
|
||||||
|
|
||||||
# If another user was previously logged in on the same device and didn't
|
# If another user was previously logged in on the same device and didn't
|
||||||
# properly log out, the token will still be registered to the wrong account
|
# properly log out, the token will still be registered to the wrong account
|
||||||
PushDeviceToken.objects.filter(token=token).delete()
|
PushDeviceToken.objects.filter(token=token_str).delete()
|
||||||
|
|
||||||
# Overwrite with the latest value
|
# Overwrite with the latest value
|
||||||
token, created = PushDeviceToken.objects.get_or_create(user=user_profile,
|
token, created = PushDeviceToken.objects.get_or_create(user=user_profile,
|
||||||
token=token,
|
token=token_str,
|
||||||
kind=kind,
|
kind=kind,
|
||||||
ios_app_id=ios_app_id)
|
ios_app_id=ios_app_id)
|
||||||
if not created:
|
if not created:
|
||||||
@@ -1223,18 +1272,21 @@ def add_push_device_token(request, user_profile, token, kind, ios_app_id=None):
|
|||||||
|
|
||||||
@has_request_variables
|
@has_request_variables
|
||||||
def add_apns_device_token(request, user_profile, token=REQ(), appid=REQ(default=settings.ZULIP_IOS_APP_ID)):
|
def add_apns_device_token(request, user_profile, token=REQ(), appid=REQ(default=settings.ZULIP_IOS_APP_ID)):
|
||||||
|
# type: (HttpRequest, UserProfile, str, str) -> HttpResponse
|
||||||
return add_push_device_token(request, user_profile, token, PushDeviceToken.APNS, ios_app_id=appid)
|
return add_push_device_token(request, user_profile, token, PushDeviceToken.APNS, ios_app_id=appid)
|
||||||
|
|
||||||
@has_request_variables
|
@has_request_variables
|
||||||
def add_android_reg_id(request, user_profile, token=REQ()):
|
def add_android_reg_id(request, user_profile, token_str=REQ("token")):
|
||||||
return add_push_device_token(request, user_profile, token, PushDeviceToken.GCM)
|
# type: (HttpRequest, UserProfile, str) -> HttpResponse
|
||||||
|
return add_push_device_token(request, user_profile, token_str, PushDeviceToken.GCM)
|
||||||
|
|
||||||
def remove_push_device_token(request, user_profile, token, kind):
|
def remove_push_device_token(request, user_profile, token_str, kind):
|
||||||
if token == '' or len(token) > 4096:
|
# type: (HttpRequest, UserProfile, str, int) -> HttpResponse
|
||||||
|
if token_str == '' or len(token_str) > 4096:
|
||||||
return json_error(_('Empty or invalid length token'))
|
return json_error(_('Empty or invalid length token'))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
token = PushDeviceToken.objects.get(token=token, kind=kind)
|
token = PushDeviceToken.objects.get(token=token_str, kind=kind)
|
||||||
token.delete()
|
token.delete()
|
||||||
except PushDeviceToken.DoesNotExist:
|
except PushDeviceToken.DoesNotExist:
|
||||||
return json_error(_("Token does not exist"))
|
return json_error(_("Token does not exist"))
|
||||||
@@ -1243,17 +1295,21 @@ def remove_push_device_token(request, user_profile, token, kind):
|
|||||||
|
|
||||||
@has_request_variables
|
@has_request_variables
|
||||||
def remove_apns_device_token(request, user_profile, token=REQ()):
|
def remove_apns_device_token(request, user_profile, token=REQ()):
|
||||||
|
# type: (HttpRequest, UserProfile, str) -> HttpResponse
|
||||||
return remove_push_device_token(request, user_profile, token, PushDeviceToken.APNS)
|
return remove_push_device_token(request, user_profile, token, PushDeviceToken.APNS)
|
||||||
|
|
||||||
@has_request_variables
|
@has_request_variables
|
||||||
def remove_android_reg_id(request, user_profile, token=REQ()):
|
def remove_android_reg_id(request, user_profile, token=REQ()):
|
||||||
|
# type: (HttpRequest, UserProfile, str) -> HttpResponse
|
||||||
return remove_push_device_token(request, user_profile, token, PushDeviceToken.GCM)
|
return remove_push_device_token(request, user_profile, token, PushDeviceToken.GCM)
|
||||||
|
|
||||||
|
|
||||||
def generate_204(request):
|
def generate_204(request):
|
||||||
|
# type: (HttpRequest) -> HttpResponse
|
||||||
return HttpResponse(content=None, status=204)
|
return HttpResponse(content=None, status=204)
|
||||||
|
|
||||||
def process_unsubscribe(token, type, unsubscribe_function):
|
def process_unsubscribe(token, subscription_type, unsubscribe_function):
|
||||||
|
# type: (HttpRequest, str, Callable[[UserProfile], None]) -> HttpResponse
|
||||||
try:
|
try:
|
||||||
confirmation = Confirmation.objects.get(confirmation_key=token)
|
confirmation = Confirmation.objects.get(confirmation_key=token)
|
||||||
except Confirmation.DoesNotExist:
|
except Confirmation.DoesNotExist:
|
||||||
@@ -1262,19 +1318,22 @@ def process_unsubscribe(token, type, unsubscribe_function):
|
|||||||
user_profile = confirmation.content_object
|
user_profile = confirmation.content_object
|
||||||
unsubscribe_function(user_profile)
|
unsubscribe_function(user_profile)
|
||||||
return render_to_response('zerver/unsubscribe_success.html',
|
return render_to_response('zerver/unsubscribe_success.html',
|
||||||
{"subscription_type": type,
|
{"subscription_type": subscription_type,
|
||||||
"external_host": settings.EXTERNAL_HOST})
|
"external_host": settings.EXTERNAL_HOST})
|
||||||
|
|
||||||
# Email unsubscribe functions. All have the function signature
|
# Email unsubscribe functions. All have the function signature
|
||||||
# processor(user_profile).
|
# processor(user_profile).
|
||||||
|
|
||||||
def do_missedmessage_unsubscribe(user_profile):
|
def do_missedmessage_unsubscribe(user_profile):
|
||||||
|
# type: (UserProfile) -> None
|
||||||
do_change_enable_offline_email_notifications(user_profile, False)
|
do_change_enable_offline_email_notifications(user_profile, False)
|
||||||
|
|
||||||
def do_welcome_unsubscribe(user_profile):
|
def do_welcome_unsubscribe(user_profile):
|
||||||
|
# type: (UserProfile) -> None
|
||||||
clear_followup_emails_queue(user_profile.email)
|
clear_followup_emails_queue(user_profile.email)
|
||||||
|
|
||||||
def do_digest_unsubscribe(user_profile):
|
def do_digest_unsubscribe(user_profile):
|
||||||
|
# type: (UserProfile) -> None
|
||||||
do_change_enable_digest_emails(user_profile, False)
|
do_change_enable_digest_emails(user_profile, False)
|
||||||
|
|
||||||
# The keys are part of the URL for the unsubscribe link and must be valid
|
# The keys are part of the URL for the unsubscribe link and must be valid
|
||||||
@@ -1289,6 +1348,7 @@ email_unsubscribers = {
|
|||||||
|
|
||||||
# Login NOT required. These are for one-click unsubscribes.
|
# Login NOT required. These are for one-click unsubscribes.
|
||||||
def email_unsubscribe(request, type, token):
|
def email_unsubscribe(request, type, token):
|
||||||
|
# type: (HttpRequest, str, str) -> HttpResponse
|
||||||
if type in email_unsubscribers:
|
if type in email_unsubscribers:
|
||||||
display_name, unsubscribe_function = email_unsubscribers[type]
|
display_name, unsubscribe_function = email_unsubscribers[type]
|
||||||
return process_unsubscribe(token, display_name, unsubscribe_function)
|
return process_unsubscribe(token, display_name, unsubscribe_function)
|
||||||
|
|||||||
Reference in New Issue
Block a user