def get_auth_backends_data(request): # type: (HttpRequest) -> Dict[str, Any] """Returns which authentication methods are enabled on the server""" if settings.REALMS_HAVE_SUBDOMAINS: subdomain = get_subdomain(request) try: realm = Realm.objects.get(string_id=subdomain) except Realm.DoesNotExist: # If not the root subdomain, this is an error if subdomain != "": raise JsonableError(_("Invalid subdomain")) # With the root subdomain, it's an error or not depending # whether SUBDOMAINS_HOMEPAGE (which indicates whether # there are some realms without subdomains on this server) # is set. if settings.SUBDOMAINS_HOMEPAGE: raise JsonableError(_("Subdomain required")) else: realm = None else: # Without subdomains, we just have to report what the server # supports, since we don't know the realm. realm = None return {"password": password_auth_enabled(realm), "dev": dev_auth_enabled(realm), "github": github_auth_enabled(realm), "google": google_auth_enabled(realm)}
def add_settings(request): realm = request.user.realm if hasattr(request.user, "realm") else None return { # We use the not_voyager variable name so that templates # will render even if the appropriate context is not provided # to the template 'not_voyager': not settings.VOYAGER, 'zulip_com': settings.ZULIP_COM, 'custom_logo_url': settings.CUSTOM_LOGO_URL, 'register_link_disabled': settings.REGISTER_LINK_DISABLED, 'show_oss_announcement': settings.SHOW_OSS_ANNOUNCEMENT, 'zulip_admin': settings.ZULIP_ADMINISTRATOR, 'login_url': settings.HOME_NOT_LOGGED_IN, 'only_sso': settings.ONLY_SSO, 'external_api_path': settings.EXTERNAL_API_PATH, 'external_api_uri': settings.EXTERNAL_API_URI, 'external_uri_scheme': settings.EXTERNAL_URI_SCHEME, 'api_site_required': settings.EXTERNAL_API_PATH != "api.zulip.com", 'email_integration_enabled': settings.EMAIL_GATEWAY_BOT != "", 'email_gateway_example': settings.EMAIL_GATEWAY_EXAMPLE, 'open_realm_creation': settings.OPEN_REALM_CREATION, 'password_auth_enabled': password_auth_enabled(realm), 'dev_auth_enabled': dev_auth_enabled(), 'google_auth_enabled': google_auth_enabled(), 'development_environment': settings.DEVELOPMENT, }
def get_auth_backends_data(request: HttpRequest) -> Dict[str, Any]: """Returns which authentication methods are enabled on the server""" subdomain = get_subdomain(request) try: realm = Realm.objects.get(string_id=subdomain) except Realm.DoesNotExist: # If not the root subdomain, this is an error if subdomain != Realm.SUBDOMAIN_FOR_ROOT_DOMAIN: raise JsonableError(_("Invalid subdomain")) # With the root subdomain, it's an error or not depending # whether ROOT_DOMAIN_LANDING_PAGE (which indicates whether # there are some realms without subdomains on this server) # is set. if settings.ROOT_DOMAIN_LANDING_PAGE: raise JsonableError(_("Subdomain required")) else: realm = None return { "password": password_auth_enabled(realm), "dev": dev_auth_enabled(realm), "email": email_auth_enabled(realm), "github": github_auth_enabled(realm), "google": google_auth_enabled(realm), "ldap": ldap_auth_enabled(realm), }
def json_fetch_api_key(request, user_profile, password=REQ(default='')): # type: (HttpRequest, UserProfile, str) -> HttpResponse if password_auth_enabled(user_profile.realm): if not authenticate(username=user_profile.email, password=password, realm_subdomain=get_subdomain(request)): return json_error(_("Your username or password is incorrect.")) return json_success({"api_key": user_profile.api_key})
def add_settings(request): # type: (HttpRequest) -> Dict[str, Any] if hasattr(request.user, "realm"): realm = request.user.realm realm_uri = realm.uri else: realm = None # TODO: Figure out how to add an assertion that this is not used realm_uri = settings.SERVER_URI return { 'custom_logo_url': settings.CUSTOM_LOGO_URL, 'register_link_disabled': settings.REGISTER_LINK_DISABLED, 'show_oss_announcement': settings.SHOW_OSS_ANNOUNCEMENT, 'zulip_admin': settings.ZULIP_ADMINISTRATOR, 'terms_of_service': settings.TERMS_OF_SERVICE, 'login_url': settings.HOME_NOT_LOGGED_IN, 'only_sso': settings.ONLY_SSO, 'external_api_path': settings.EXTERNAL_API_PATH, 'external_api_uri': settings.EXTERNAL_API_URI, 'external_host': settings.EXTERNAL_HOST, 'external_uri_scheme': settings.EXTERNAL_URI_SCHEME, 'realm_uri': realm_uri, 'server_uri': settings.SERVER_URI, 'api_site_required': settings.EXTERNAL_API_PATH != "api.zulip.com", 'email_integration_enabled': settings.EMAIL_GATEWAY_BOT != "", 'email_gateway_example': settings.EMAIL_GATEWAY_EXAMPLE, 'open_realm_creation': settings.OPEN_REALM_CREATION, 'password_auth_enabled': password_auth_enabled(realm), 'dev_auth_enabled': dev_auth_enabled(), 'google_auth_enabled': google_auth_enabled(), 'github_auth_enabled': github_auth_enabled(), 'development_environment': settings.DEVELOPMENT, 'support_email': settings.ZULIP_ADMINISTRATOR, }
def api_get_auth_backends(request): # type: (HttpRequest) -> HttpResponse # May return a false positive for password auth if it's been disabled # for a specific realm. Currently only happens for zulip.com on prod return json_success({"password": password_auth_enabled(None), "dev": dev_auth_enabled(), "google": google_auth_enabled(), })
def json_fetch_api_key(request: HttpRequest, user_profile: UserProfile, password: str=REQ(default='')) -> HttpResponse: subdomain = get_subdomain(request) realm = get_realm(subdomain) if password_auth_enabled(user_profile.realm): if not authenticate(username=user_profile.email, password=password, realm=realm): return json_error(_("Your username or password is incorrect.")) api_key = get_api_key(user_profile) return json_success({"api_key": api_key})
def add_settings(request): # type: (HttpRequest) -> Dict[str, Any] realm = None if hasattr(request.user, "realm"): realm = request.user.realm elif settings.REALMS_HAVE_SUBDOMAINS: subdomain = get_subdomain(request) realm = get_realm(subdomain) if realm is not None: realm_uri = realm.uri else: realm_uri = settings.SERVER_URI return { 'custom_logo_url': settings.CUSTOM_LOGO_URL, 'register_link_disabled': settings.REGISTER_LINK_DISABLED, 'login_link_disabled': settings.LOGIN_LINK_DISABLED, 'about_link_disabled': settings.ABOUT_LINK_DISABLED, 'show_oss_announcement': settings.SHOW_OSS_ANNOUNCEMENT, 'zulip_admin': settings.ZULIP_ADMINISTRATOR, 'terms_of_service': settings.TERMS_OF_SERVICE, 'login_url': settings.HOME_NOT_LOGGED_IN, 'only_sso': settings.ONLY_SSO, 'external_api_path': settings.EXTERNAL_API_PATH, 'external_api_uri': settings.EXTERNAL_API_URI, 'external_host': settings.EXTERNAL_HOST, 'external_uri_scheme': settings.EXTERNAL_URI_SCHEME, 'realm_uri': realm_uri, 'server_uri': settings.SERVER_URI, 'api_site_required': settings.EXTERNAL_API_PATH != "api.zulip.com", 'email_integration_enabled': settings.EMAIL_GATEWAY_BOT != "", 'email_gateway_example': settings.EMAIL_GATEWAY_EXAMPLE, 'open_realm_creation': settings.OPEN_REALM_CREATION, 'password_auth_enabled': password_auth_enabled(realm), 'dev_auth_enabled': dev_auth_enabled(realm), 'google_auth_enabled': google_auth_enabled(realm), 'github_auth_enabled': github_auth_enabled(realm), 'development_environment': settings.DEVELOPMENT, 'support_email': settings.ZULIP_ADMINISTRATOR, 'find_team_link_disabled': settings.FIND_TEAM_LINK_DISABLED, 'password_min_length': settings.PASSWORD_MIN_LENGTH, 'password_min_quality': settings.PASSWORD_MIN_ZXCVBN_QUALITY, 'zulip_version': ZULIP_VERSION, }
def add_settings(request): realm = request.user.realm if hasattr(request.user, "realm") else None return { # We use the not_voyager variable name so that templates # will render even if the appropriate context is not provided # to the template 'not_voyager': not settings.VOYAGER, 'zulip_com': settings.ZULIP_COM, 'zulip_admin': settings.ZULIP_ADMINISTRATOR, 'login_url': settings.HOME_NOT_LOGGED_IN, 'only_sso': settings.ONLY_SSO, 'external_api_path': settings.EXTERNAL_API_PATH, 'external_api_uri': settings.EXTERNAL_API_URI, 'external_uri_scheme': settings.EXTERNAL_URI_SCHEME, 'api_site_required': settings.EXTERNAL_API_PATH != "api.zulip.com", 'email_integration_enabled': settings.EMAIL_GATEWAY_BOT != "", 'email_gateway_example': settings.EMAIL_GATEWAY_EXAMPLE, 'password_auth_enabled': password_auth_enabled(realm), 'dev_auth_enabled': dev_auth_enabled(), 'google_auth_enabled': google_auth_enabled(), }
def get_auth_backends_data(request: HttpRequest) -> Dict[str, Any]: """Returns which authentication methods are enabled on the server""" subdomain = get_subdomain(request) try: realm = Realm.objects.get(string_id=subdomain) except Realm.DoesNotExist: # If not the root subdomain, this is an error if subdomain != Realm.SUBDOMAIN_FOR_ROOT_DOMAIN: raise JsonableError(_("Invalid subdomain")) # With the root subdomain, it's an error or not depending # whether ROOT_DOMAIN_LANDING_PAGE (which indicates whether # there are some realms without subdomains on this server) # is set. if settings.ROOT_DOMAIN_LANDING_PAGE: raise JsonableError(_("Subdomain required")) else: realm = None result = { "password": password_auth_enabled(realm), } for auth_backend_name in AUTH_BACKEND_NAME_MAP: key = auth_backend_name.lower() result[key] = auth_enabled_helper([auth_backend_name], realm) return result
def get_auth_backends_data(request): # type: (HttpRequest) -> Dict[str, Any] """Returns which authentication methods are enabled on the server""" subdomain = get_subdomain(request) try: realm = Realm.objects.get(string_id=subdomain) except Realm.DoesNotExist: # If not the root subdomain, this is an error if subdomain != "": raise JsonableError(_("Invalid subdomain")) # With the root subdomain, it's an error or not depending # whether ROOT_DOMAIN_LANDING_PAGE (which indicates whether # there are some realms without subdomains on this server) # is set. if settings.ROOT_DOMAIN_LANDING_PAGE: raise JsonableError(_("Subdomain required")) else: realm = None return { "password": password_auth_enabled(realm), "dev": dev_auth_enabled(realm), "github": github_auth_enabled(realm), "google": google_auth_enabled(realm) }
def accounts_register(request): # type: (HttpRequest) -> HttpResponse key = request.POST['key'] confirmation = Confirmation.objects.get(confirmation_key=key) prereg_user = confirmation.content_object email = prereg_user.email realm_creation = prereg_user.realm_creation password_required = prereg_user.password_required validators.validate_email(email) if prereg_user.referred_by: # If someone invited you, you are joining their realm regardless # of your e-mail address. realm = prereg_user.referred_by.realm elif realm_creation: # For creating a new realm, there is no existing realm or domain realm = None else: realm = get_realm(get_subdomain(request)) if realm and not email_allowed_for_realm(email, realm): return render(request, "zerver/closed_realm.html", context={"closed_domain_name": realm.name}) if realm and realm.deactivated: # The user is trying to register for a deactivated realm. Advise them to # contact support. return redirect_to_deactivation_notice() try: validate_email_for_realm(realm, email) except ValidationError: return HttpResponseRedirect( reverse('django.contrib.auth.views.login') + '?email=' + urllib.parse.quote_plus(email)) name_validated = False full_name = None if request.POST.get('from_confirmation'): try: del request.session['authenticated_full_name'] except KeyError: pass if realm is not None and realm.is_zephyr_mirror_realm: # For MIT users, we can get an authoritative name from Hesiod. # Technically we should check that this is actually an MIT # realm, but we can cross that bridge if we ever get a non-MIT # zephyr mirroring realm. hesiod_name = compute_mit_user_fullname(email) form = RegistrationForm(initial={ 'full_name': hesiod_name if "@" not in hesiod_name else "" }, realm_creation=realm_creation) name_validated = True elif settings.POPULATE_PROFILE_VIA_LDAP: for backend in get_backends(): if isinstance(backend, LDAPBackend): ldap_attrs = _LDAPUser( backend, backend.django_to_ldap_username(email)).attrs try: ldap_full_name = ldap_attrs[ settings.AUTH_LDAP_USER_ATTR_MAP['full_name']][0] request.session[ 'authenticated_full_name'] = ldap_full_name name_validated = True # We don't use initial= here, because if the form is # complete (that is, no additional fields need to be # filled out by the user) we want the form to validate, # so they can be directly registered without having to # go through this interstitial. form = RegistrationForm({'full_name': ldap_full_name}, realm_creation=realm_creation) # FIXME: This will result in the user getting # validation errors if they have to enter a password. # Not relevant for ONLY_SSO, though. break except TypeError: # Let the user fill out a name and/or try another backend form = RegistrationForm(realm_creation=realm_creation) elif 'full_name' in request.POST: form = RegistrationForm( initial={'full_name': request.POST.get('full_name')}, realm_creation=realm_creation) else: form = RegistrationForm(realm_creation=realm_creation) else: postdata = request.POST.copy() if name_changes_disabled(realm): # If we populate profile information via LDAP and we have a # verified name from you on file, use that. Otherwise, fall # back to the full name in the request. try: postdata.update( {'full_name': request.session['authenticated_full_name']}) name_validated = True except KeyError: pass form = RegistrationForm(postdata, realm_creation=realm_creation) if not (password_auth_enabled(realm) and password_required): form['password'].field.required = False if form.is_valid(): if password_auth_enabled(realm): password = form.cleaned_data['password'] else: # SSO users don't need no passwords password = None if realm_creation: string_id = form.cleaned_data['realm_subdomain'] realm_name = form.cleaned_data['realm_name'] realm = do_create_realm(string_id, realm_name) setup_initial_streams(realm) assert (realm is not None) full_name = form.cleaned_data['full_name'] short_name = email_to_username(email) default_stream_group_names = request.POST.getlist( 'default_stream_group') default_stream_groups = lookup_default_stream_groups( default_stream_group_names, realm) timezone = u"" if 'timezone' in request.POST and request.POST[ 'timezone'] in get_all_timezones(): timezone = request.POST['timezone'] try: existing_user_profile = get_user_profile_by_email(email) except UserProfile.DoesNotExist: existing_user_profile = None return_data = {} # type: Dict[str, bool] if ldap_auth_enabled(realm): # If the user was authenticated using an external SSO # mechanism like Google or GitHub auth, then authentication # will have already been done before creating the # PreregistrationUser object with password_required=False, and # so we don't need to worry about passwords. # # If instead the realm is using EmailAuthBackend, we will # set their password above. # # But if the realm is using LDAPAuthBackend, we need to verify # their LDAP password (which will, as a side effect, create # the user account) here using authenticate. auth_result = authenticate(request, username=email, password=password, realm_subdomain=realm.subdomain, return_data=return_data) if auth_result is None: # TODO: This probably isn't going to give a # user-friendly error message, but it doesn't # particularly matter, because the registration form # is hidden for most users. return HttpResponseRedirect( reverse('django.contrib.auth.views.login') + '?email=' + urllib.parse.quote_plus(email)) # Since we'll have created a user, we now just log them in. return login_and_go_to_home(request, auth_result) elif existing_user_profile is not None and existing_user_profile.is_mirror_dummy: user_profile = existing_user_profile do_activate_user(user_profile) do_change_password(user_profile, password) do_change_full_name(user_profile, full_name, user_profile) do_set_user_display_setting(user_profile, 'timezone', timezone) else: user_profile = do_create_user( email, password, realm, full_name, short_name, prereg_user=prereg_user, is_realm_admin=realm_creation, tos_version=settings.TOS_VERSION, timezone=timezone, newsletter_data={"IP": request.META['REMOTE_ADDR']}, default_stream_groups=default_stream_groups) if realm_creation: setup_initial_private_stream(user_profile) send_initial_realm_messages(realm) if realm_creation: # Because for realm creation, registration happens on the # root domain, we need to log them into the subdomain for # their new realm. return redirect_and_log_into_subdomain(realm, full_name, email) # This dummy_backend check below confirms the user is # authenticating to the correct subdomain. auth_result = authenticate(username=user_profile.email, realm_subdomain=realm.subdomain, return_data=return_data, use_dummy_backend=True) if return_data.get('invalid_subdomain'): # By construction, this should never happen. logging.error("Subdomain mismatch in registration %s: %s" % ( realm.subdomain, user_profile.email, )) return redirect('/') return login_and_go_to_home(request, auth_result) return render( request, 'zerver/register.html', context={ 'form': form, 'email': email, 'key': key, 'full_name': request.session.get('authenticated_full_name', None), 'lock_name': name_validated and name_changes_disabled(realm), # password_auth_enabled is normally set via our context processor, # but for the registration form, there is no logged in user yet, so # we have to set it here. 'creating_new_team': realm_creation, 'password_required': password_auth_enabled(realm) and password_required, 'password_auth_enabled': password_auth_enabled(realm), 'root_domain_available': is_root_domain_available(), 'default_stream_groups': get_default_stream_groups(realm), 'MAX_REALM_NAME_LENGTH': str(Realm.MAX_REALM_NAME_LENGTH), 'MAX_NAME_LENGTH': str(UserProfile.MAX_NAME_LENGTH), 'MAX_PASSWORD_LENGTH': str(form.MAX_PASSWORD_LENGTH), 'MAX_REALM_SUBDOMAIN_LENGTH': str(Realm.MAX_REALM_SUBDOMAIN_LENGTH) })
def accounts_register(request): # type: (HttpRequest) -> HttpResponse key = request.POST['key'] confirmation = Confirmation.objects.get(confirmation_key=key) prereg_user = confirmation.content_object email = prereg_user.email realm_creation = prereg_user.realm_creation try: existing_user_profile = get_user_profile_by_email(email) except UserProfile.DoesNotExist: existing_user_profile = None validators.validate_email(email) # If OPEN_REALM_CREATION is enabled all user sign ups should go through the # special URL with domain name so that REALM can be identified if multiple realms exist unique_open_realm = get_unique_open_realm() if unique_open_realm is not None: realm = unique_open_realm elif prereg_user.referred_by: # If someone invited you, you are joining their realm regardless # of your e-mail address. realm = prereg_user.referred_by.realm elif prereg_user.realm: # You have a realm set, even though nobody referred you. This # happens if you sign up through a special URL for an open realm. realm = prereg_user.realm elif realm_creation: # For creating a new realm, there is no existing realm or domain realm = None elif settings.REALMS_HAVE_SUBDOMAINS: realm = get_realm(get_subdomain(request)) else: realm = get_realm_by_email_domain(email) if realm and not email_allowed_for_realm(email, realm): return render(request, "zerver/closed_realm.html", context={"closed_domain_name": realm.name}) if realm and realm.deactivated: # The user is trying to register for a deactivated realm. Advise them to # contact support. return render(request, "zerver/deactivated.html", context={ "deactivated_domain_name": realm.name, "zulip_administrator": settings.ZULIP_ADMINISTRATOR }) try: if existing_user_profile is not None and existing_user_profile.is_mirror_dummy: # Mirror dummy users to be activated must be inactive is_inactive(email) else: # Other users should not already exist at all. user_email_is_unique(email) except ValidationError: return HttpResponseRedirect( reverse('django.contrib.auth.views.login') + '?email=' + urllib.parse.quote_plus(email)) name_validated = False full_name = None if request.POST.get('from_confirmation'): try: del request.session['authenticated_full_name'] except KeyError: pass if realm is not None and realm.is_zephyr_mirror_realm: # For MIT users, we can get an authoritative name from Hesiod. # Technically we should check that this is actually an MIT # realm, but we can cross that bridge if we ever get a non-MIT # zephyr mirroring realm. hesiod_name = compute_mit_user_fullname(email) form = RegistrationForm( initial={ 'full_name': hesiod_name if "@" not in hesiod_name else "" }) name_validated = True elif settings.POPULATE_PROFILE_VIA_LDAP: for backend in get_backends(): if isinstance(backend, LDAPBackend): ldap_attrs = _LDAPUser( backend, backend.django_to_ldap_username(email)).attrs try: ldap_full_name = ldap_attrs[ settings.AUTH_LDAP_USER_ATTR_MAP['full_name']][0] request.session[ 'authenticated_full_name'] = ldap_full_name name_validated = True # We don't use initial= here, because if the form is # complete (that is, no additional fields need to be # filled out by the user) we want the form to validate, # so they can be directly registered without having to # go through this interstitial. form = RegistrationForm({'full_name': ldap_full_name}) # FIXME: This will result in the user getting # validation errors if they have to enter a password. # Not relevant for ONLY_SSO, though. break except TypeError: # Let the user fill out a name and/or try another backend form = RegistrationForm() elif 'full_name' in request.POST: form = RegistrationForm( initial={'full_name': request.POST.get('full_name')}) else: form = RegistrationForm() else: postdata = request.POST.copy() if name_changes_disabled(realm): # If we populate profile information via LDAP and we have a # verified name from you on file, use that. Otherwise, fall # back to the full name in the request. try: postdata.update( {'full_name': request.session['authenticated_full_name']}) name_validated = True except KeyError: pass form = RegistrationForm(postdata) if not password_auth_enabled(realm): form['password'].field.required = False if form.is_valid(): if password_auth_enabled(realm): password = form.cleaned_data['password'] else: # SSO users don't need no passwords password = None if realm_creation: string_id = form.cleaned_data['realm_subdomain'] realm_name = form.cleaned_data['realm_name'] org_type = int(form.cleaned_data['realm_org_type']) realm = do_create_realm(string_id, realm_name, org_type=org_type)[0] set_default_streams(realm, settings.DEFAULT_NEW_REALM_STREAMS) full_name = form.cleaned_data['full_name'] short_name = email_to_username(email) first_in_realm = len( UserProfile.objects.filter(realm=realm, is_bot=False)) == 0 # FIXME: sanitize email addresses and fullname if existing_user_profile is not None and existing_user_profile.is_mirror_dummy: user_profile = existing_user_profile do_activate_user(user_profile) do_change_password(user_profile, password) do_change_full_name(user_profile, full_name) else: user_profile = do_create_user( email, password, realm, full_name, short_name, prereg_user=prereg_user, tos_version=settings.TOS_VERSION, newsletter_data={"IP": request.META['REMOTE_ADDR']}) if first_in_realm: do_change_is_admin(user_profile, True) if realm_creation and settings.REALMS_HAVE_SUBDOMAINS: # Because for realm creation, registration happens on the # root domain, we need to log them into the subdomain for # their new realm. return redirect_and_log_into_subdomain(realm, full_name, email) # This dummy_backend check below confirms the user is # authenticating to the correct subdomain. return_data = {} # type: Dict[str, bool] auth_result = authenticate(username=user_profile.email, realm_subdomain=realm.subdomain, return_data=return_data, use_dummy_backend=True) if return_data.get('invalid_subdomain'): # By construction, this should never happen. logging.error("Subdomain mismatch in registration %s: %s" % ( realm.subdomain, user_profile.email, )) return redirect('/') login(request, auth_result) return HttpResponseRedirect(realm.uri + reverse('zerver.views.home.home')) return render( request, 'zerver/register.html', context={ 'form': form, 'email': email, 'key': key, 'full_name': request.session.get('authenticated_full_name', None), 'lock_name': name_validated and name_changes_disabled(realm), # password_auth_enabled is normally set via our context processor, # but for the registration form, there is no logged in user yet, so # we have to set it here. 'creating_new_team': realm_creation, 'realms_have_subdomains': settings.REALMS_HAVE_SUBDOMAINS, 'password_auth_enabled': password_auth_enabled(realm), 'MAX_REALM_NAME_LENGTH': str(Realm.MAX_REALM_NAME_LENGTH), 'MAX_NAME_LENGTH': str(UserProfile.MAX_NAME_LENGTH), 'MAX_PASSWORD_LENGTH': str(form.MAX_PASSWORD_LENGTH), 'MAX_REALM_SUBDOMAIN_LENGTH': str(Realm.MAX_REALM_SUBDOMAIN_LENGTH) })
def accounts_register(request: HttpRequest) -> HttpResponse: key = request.POST['key'] confirmation = Confirmation.objects.get(confirmation_key=key) prereg_user = confirmation.content_object email = prereg_user.email realm_creation = prereg_user.realm_creation password_required = prereg_user.password_required is_realm_admin = prereg_user.invited_as_admin or realm_creation try: validators.validate_email(email) except ValidationError: return render(request, "zerver/invalid_email.html", context={"invalid_email": True}) if realm_creation: # For creating a new realm, there is no existing realm or domain realm = None else: realm = get_realm(get_subdomain(request)) if realm is None or realm != prereg_user.realm: return render_confirmation_key_error( request, ConfirmationKeyException(ConfirmationKeyException.DOES_NOT_EXIST)) try: email_allowed_for_realm(email, realm) except DomainNotAllowedForRealmError: return render(request, "zerver/invalid_email.html", context={"realm_name": realm.name, "closed_domain": True}) except DisposableEmailError: return render(request, "zerver/invalid_email.html", context={"realm_name": realm.name, "disposable_emails_not_allowed": True}) except EmailContainsPlusError: return render(request, "zerver/invalid_email.html", context={"realm_name": realm.name, "email_contains_plus": True}) if realm.deactivated: # The user is trying to register for a deactivated realm. Advise them to # contact support. return redirect_to_deactivation_notice() try: validate_email_for_realm(realm, email) except ValidationError: # nocoverage # We need to add a test for this. return HttpResponseRedirect(reverse('django.contrib.auth.views.login') + '?email=' + urllib.parse.quote_plus(email)) name_validated = False full_name = None if request.POST.get('from_confirmation'): try: del request.session['authenticated_full_name'] except KeyError: pass if realm is not None and realm.is_zephyr_mirror_realm: # For MIT users, we can get an authoritative name from Hesiod. # Technically we should check that this is actually an MIT # realm, but we can cross that bridge if we ever get a non-MIT # zephyr mirroring realm. hesiod_name = compute_mit_user_fullname(email) form = RegistrationForm( initial={'full_name': hesiod_name if "@" not in hesiod_name else ""}, realm_creation=realm_creation) name_validated = True elif settings.POPULATE_PROFILE_VIA_LDAP: for backend in get_backends(): if isinstance(backend, LDAPBackend): try: ldap_username = backend.django_to_ldap_username(email) except ZulipLDAPException: logging.warning("New account email %s could not be found in LDAP" % (email,)) form = RegistrationForm(realm_creation=realm_creation) break ldap_attrs = _LDAPUser(backend, ldap_username).attrs try: ldap_full_name = ldap_attrs[settings.AUTH_LDAP_USER_ATTR_MAP['full_name']][0] request.session['authenticated_full_name'] = ldap_full_name name_validated = True # We don't use initial= here, because if the form is # complete (that is, no additional fields need to be # filled out by the user) we want the form to validate, # so they can be directly registered without having to # go through this interstitial. form = RegistrationForm({'full_name': ldap_full_name}, realm_creation=realm_creation) # FIXME: This will result in the user getting # validation errors if they have to enter a password. # Not relevant for ONLY_SSO, though. break except TypeError: # Let the user fill out a name and/or try another backend form = RegistrationForm(realm_creation=realm_creation) elif 'full_name' in request.POST: form = RegistrationForm( initial={'full_name': request.POST.get('full_name')}, realm_creation=realm_creation ) else: form = RegistrationForm(realm_creation=realm_creation) else: postdata = request.POST.copy() if name_changes_disabled(realm): # If we populate profile information via LDAP and we have a # verified name from you on file, use that. Otherwise, fall # back to the full name in the request. try: postdata.update({'full_name': request.session['authenticated_full_name']}) name_validated = True except KeyError: pass form = RegistrationForm(postdata, realm_creation=realm_creation) if not (password_auth_enabled(realm) and password_required): form['password'].field.required = False if form.is_valid(): if password_auth_enabled(realm): password = form.cleaned_data['password'] else: # SSO users don't need no passwords password = None if realm_creation: string_id = form.cleaned_data['realm_subdomain'] realm_name = form.cleaned_data['realm_name'] realm = do_create_realm(string_id, realm_name) setup_initial_streams(realm) setup_realm_internal_bots(realm) assert(realm is not None) full_name = form.cleaned_data['full_name'] short_name = email_to_username(email) default_stream_group_names = request.POST.getlist('default_stream_group') default_stream_groups = lookup_default_stream_groups(default_stream_group_names, realm) timezone = "" if 'timezone' in request.POST and request.POST['timezone'] in get_all_timezones(): timezone = request.POST['timezone'] if 'source_realm' in request.POST and request.POST["source_realm"] != "on": source_profile = get_source_profile(email, request.POST["source_realm"]) else: source_profile = None if not realm_creation: try: existing_user_profile = get_user(email, realm) # type: Optional[UserProfile] except UserProfile.DoesNotExist: existing_user_profile = None else: existing_user_profile = None return_data = {} # type: Dict[str, bool] if ldap_auth_enabled(realm): # If the user was authenticated using an external SSO # mechanism like Google or GitHub auth, then authentication # will have already been done before creating the # PreregistrationUser object with password_required=False, and # so we don't need to worry about passwords. # # If instead the realm is using EmailAuthBackend, we will # set their password above. # # But if the realm is using LDAPAuthBackend, we need to verify # their LDAP password (which will, as a side effect, create # the user account) here using authenticate. auth_result = authenticate(request, username=email, password=password, realm=realm, return_data=return_data) if auth_result is not None: # Since we'll have created a user, we now just log them in. return login_and_go_to_home(request, auth_result) if return_data.get("outside_ldap_domain") and email_auth_enabled(realm): # If both the LDAP and Email auth backends are # enabled, and the user's email is outside the LDAP # domain, then the intent is to create a user in the # realm with their email outside the LDAP organization # (with e.g. a password stored in the Zulip database, # not LDAP). So we fall through and create the new # account. # # It's likely that we can extend this block to the # Google and GitHub auth backends with no code changes # other than here. pass else: # TODO: This probably isn't going to give a # user-friendly error message, but it doesn't # particularly matter, because the registration form # is hidden for most users. return HttpResponseRedirect(reverse('django.contrib.auth.views.login') + '?email=' + urllib.parse.quote_plus(email)) if existing_user_profile is not None and existing_user_profile.is_mirror_dummy: user_profile = existing_user_profile do_activate_user(user_profile) do_change_password(user_profile, password) do_change_full_name(user_profile, full_name, user_profile) do_set_user_display_setting(user_profile, 'timezone', timezone) # TODO: When we clean up the `do_activate_user` code path, # make it respect invited_as_admin / is_realm_admin. else: user_profile = do_create_user(email, password, realm, full_name, short_name, prereg_user=prereg_user, is_realm_admin=is_realm_admin, tos_version=settings.TOS_VERSION, timezone=timezone, newsletter_data={"IP": request.META['REMOTE_ADDR']}, default_stream_groups=default_stream_groups, source_profile=source_profile) if realm_creation: bulk_add_subscriptions([realm.signup_notifications_stream], [user_profile]) send_initial_realm_messages(realm) # Because for realm creation, registration happens on the # root domain, we need to log them into the subdomain for # their new realm. return redirect_and_log_into_subdomain(realm, full_name, email) # This dummy_backend check below confirms the user is # authenticating to the correct subdomain. auth_result = authenticate(username=user_profile.email, realm=realm, return_data=return_data, use_dummy_backend=True) if return_data.get('invalid_subdomain'): # By construction, this should never happen. logging.error("Subdomain mismatch in registration %s: %s" % ( realm.subdomain, user_profile.email,)) return redirect('/') return login_and_go_to_home(request, auth_result) return render( request, 'zerver/register.html', context={'form': form, 'email': email, 'key': key, 'full_name': request.session.get('authenticated_full_name', None), 'lock_name': name_validated and name_changes_disabled(realm), # password_auth_enabled is normally set via our context processor, # but for the registration form, there is no logged in user yet, so # we have to set it here. 'creating_new_team': realm_creation, 'password_required': password_auth_enabled(realm) and password_required, 'password_auth_enabled': password_auth_enabled(realm), 'root_domain_available': is_root_domain_available(), 'default_stream_groups': get_default_stream_groups(realm), 'accounts': get_accounts_for_email(email), 'MAX_REALM_NAME_LENGTH': str(Realm.MAX_REALM_NAME_LENGTH), 'MAX_NAME_LENGTH': str(UserProfile.MAX_NAME_LENGTH), 'MAX_PASSWORD_LENGTH': str(form.MAX_PASSWORD_LENGTH), 'MAX_REALM_SUBDOMAIN_LENGTH': str(Realm.MAX_REALM_SUBDOMAIN_LENGTH) } )
def accounts_register(request): # type: (HttpRequest) -> HttpResponse key = request.POST['key'] confirmation = Confirmation.objects.get(confirmation_key=key) prereg_user = confirmation.content_object email = prereg_user.email realm_creation = prereg_user.realm_creation try: existing_user_profile = get_user_profile_by_email(email) except UserProfile.DoesNotExist: existing_user_profile = None validators.validate_email(email) # If OPEN_REALM_CREATION is enabled all user sign ups should go through the # special URL with domain name so that REALM can be identified if multiple realms exist unique_open_realm = get_unique_open_realm() if unique_open_realm is not None: realm = unique_open_realm domain = realm.domain elif prereg_user.referred_by: # If someone invited you, you are joining their realm regardless # of your e-mail address. realm = prereg_user.referred_by.realm domain = realm.domain if not email_allowed_for_realm(email, realm): return render_to_response("zerver/closed_realm.html", {"closed_domain_name": realm.name}) elif prereg_user.realm: # You have a realm set, even though nobody referred you. This # happens if you sign up through a special URL for an open # realm. domain = prereg_user.realm.domain realm = get_realm(domain) else: domain = resolve_email_to_domain(email) realm = get_realm(domain) if realm and realm.deactivated: # The user is trying to register for a deactivated realm. Advise them to # contact support. return render_to_response("zerver/deactivated.html", {"deactivated_domain_name": realm.name, "zulip_administrator": settings.ZULIP_ADMINISTRATOR}) try: if existing_user_profile is not None and existing_user_profile.is_mirror_dummy: # Mirror dummy users to be activated must be inactive is_inactive(email) else: # Other users should not already exist at all. user_email_is_unique(email) except ValidationError: return HttpResponseRedirect(reverse('django.contrib.auth.views.login') + '?email=' + urllib.parse.quote_plus(email)) name_validated = False full_name = None if request.POST.get('from_confirmation'): try: del request.session['authenticated_full_name'] except KeyError: pass if realm is not None and realm.is_zephyr_mirror_realm and domain == "mit.edu": # for MIT users, we can get an authoritative name from Hesiod hesiod_name = compute_mit_user_fullname(email) form = RegistrationForm( initial={'full_name': hesiod_name if "@" not in hesiod_name else ""}) name_validated = True elif settings.POPULATE_PROFILE_VIA_LDAP: for backend in get_backends(): if isinstance(backend, LDAPBackend): ldap_attrs = _LDAPUser(backend, backend.django_to_ldap_username(email)).attrs try: ldap_full_name = ldap_attrs[settings.AUTH_LDAP_USER_ATTR_MAP['full_name']][0] request.session['authenticated_full_name'] = ldap_full_name name_validated = True # We don't use initial= here, because if the form is # complete (that is, no additional fields need to be # filled out by the user) we want the form to validate, # so they can be directly registered without having to # go through this interstitial. form = RegistrationForm({'full_name': ldap_full_name}) # FIXME: This will result in the user getting # validation errors if they have to enter a password. # Not relevant for ONLY_SSO, though. break except TypeError: # Let the user fill out a name and/or try another backend form = RegistrationForm() elif 'full_name' in request.POST: form = RegistrationForm( initial={'full_name': request.POST.get('full_name')} ) else: form = RegistrationForm() else: postdata = request.POST.copy() if name_changes_disabled(realm): # If we populate profile information via LDAP and we have a # verified name from you on file, use that. Otherwise, fall # back to the full name in the request. try: postdata.update({'full_name': request.session['authenticated_full_name']}) name_validated = True except KeyError: pass form = RegistrationForm(postdata) if not password_auth_enabled(realm): form['password'].field.required = False if form.is_valid(): if password_auth_enabled(realm): password = form.cleaned_data['password'] else: # SSO users don't need no passwords password = None if realm_creation: string_id = form.cleaned_data['realm_subdomain'] realm_name = form.cleaned_data['realm_name'] org_type = int(form.cleaned_data['realm_org_type']) domain = split_email_to_domain(email) realm = do_create_realm(string_id, realm_name, org_type=org_type, domain=domain)[0] set_default_streams(realm, settings.DEFAULT_NEW_REALM_STREAMS) full_name = form.cleaned_data['full_name'] short_name = email_to_username(email) first_in_realm = len(UserProfile.objects.filter(realm=realm, is_bot=False)) == 0 # FIXME: sanitize email addresses and fullname if existing_user_profile is not None and existing_user_profile.is_mirror_dummy: try: user_profile = existing_user_profile do_activate_user(user_profile) do_change_password(user_profile, password) do_change_full_name(user_profile, full_name) except UserProfile.DoesNotExist: user_profile = do_create_user(email, password, realm, full_name, short_name, prereg_user=prereg_user, tos_version=settings.TOS_VERSION, newsletter_data={"IP": request.META['REMOTE_ADDR']}) else: user_profile = do_create_user(email, password, realm, full_name, short_name, prereg_user=prereg_user, tos_version=settings.TOS_VERSION, newsletter_data={"IP": request.META['REMOTE_ADDR']}) if first_in_realm: do_change_is_admin(user_profile, True) if realm_creation and settings.REALMS_HAVE_SUBDOMAINS: # Because for realm creation, registration happens on the # root domain, we need to log them into the subdomain for # their new realm. return redirect_and_log_into_subdomain(realm, full_name, email) # This dummy_backend check below confirms the user is # authenticating to the correct subdomain. return_data = {} # type: Dict[str, bool] auth_result = authenticate(username=user_profile.email, realm_subdomain=realm.subdomain, return_data=return_data, use_dummy_backend=True) if return_data.get('invalid_subdomain'): # By construction, this should never happen. logging.error("Subdomain mismatch in registration %s: %s" % ( realm.subdomain, user_profile.email,)) return redirect('/') login(request, auth_result) return HttpResponseRedirect(realm.uri + reverse('zerver.views.home')) return render_to_response('zerver/register.html', {'form': form, 'company_name': domain, 'email': email, 'key': key, 'full_name': request.session.get('authenticated_full_name', None), 'lock_name': name_validated and name_changes_disabled(realm), # password_auth_enabled is normally set via our context processor, # but for the registration form, there is no logged in user yet, so # we have to set it here. 'creating_new_team': realm_creation, 'realms_have_subdomains': settings.REALMS_HAVE_SUBDOMAINS, 'password_auth_enabled': password_auth_enabled(realm), }, request=request)
def zulip_default_context(request: HttpRequest) -> Dict[str, Any]: """Context available to all Zulip Jinja2 templates that have a request passed in. Designed to provide the long list of variables at the bottom of this function in a wide range of situations: logged-in or logged-out, subdomains or not, etc. The main variable in the below is whether we know what realm the user is trying to interact with. """ realm = get_realm_from_request(request) if realm is None: realm_uri = settings.ROOT_DOMAIN_URI realm_name = None realm_icon = None realm_description = None realm_invite_required = False else: realm_uri = realm.uri realm_name = realm.name realm_icon = get_realm_icon_url(realm) realm_description_raw = realm.description or "The coolest place in the universe." realm_description = convert(realm_description_raw, message_realm=realm) realm_invite_required = realm.invite_required register_link_disabled = settings.REGISTER_LINK_DISABLED login_link_disabled = settings.LOGIN_LINK_DISABLED find_team_link_disabled = settings.FIND_TEAM_LINK_DISABLED allow_search_engine_indexing = False if (settings.ROOT_DOMAIN_LANDING_PAGE and get_subdomain(request) == Realm.SUBDOMAIN_FOR_ROOT_DOMAIN): register_link_disabled = True login_link_disabled = True find_team_link_disabled = False allow_search_engine_indexing = True apps_page_url = 'https://zulipchat.com/apps/' if settings.ZILENCER_ENABLED: apps_page_url = '/apps/' user_is_authenticated = False if hasattr(request, 'user') and hasattr(request.user, 'is_authenticated'): user_is_authenticated = request.user.is_authenticated.value if settings.DEVELOPMENT: secrets_path = "zproject/dev-secrets.conf" settings_path = "zproject/dev_settings.py" settings_comments_path = "zproject/prod_settings_template.py" else: secrets_path = "/etc/zulip/zulip-secrets.conf" settings_path = "/etc/zulip/settings.py" settings_comments_path = "/etc/zulip/settings.py" if hasattr(request, "client") and request.client.name == "ZulipElectron": platform = "ZulipElectron" # nocoverage else: platform = "ZulipWeb" return { 'root_domain_landing_page': settings.ROOT_DOMAIN_LANDING_PAGE, 'custom_logo_url': settings.CUSTOM_LOGO_URL, 'register_link_disabled': register_link_disabled, 'login_link_disabled': login_link_disabled, 'terms_of_service': settings.TERMS_OF_SERVICE, 'privacy_policy': settings.PRIVACY_POLICY, 'login_url': settings.HOME_NOT_LOGGED_IN, 'only_sso': settings.ONLY_SSO, 'custom_profile_fields_enabled': settings.DEVELOPMENT, 'external_host': settings.EXTERNAL_HOST, 'external_uri_scheme': settings.EXTERNAL_URI_SCHEME, 'realm_invite_required': realm_invite_required, 'realm_uri': realm_uri, 'realm_name': realm_name, 'realm_icon': realm_icon, 'realm_description': realm_description, 'root_domain_uri': settings.ROOT_DOMAIN_URI, 'apps_page_url': apps_page_url, 'open_realm_creation': settings.OPEN_REALM_CREATION, 'password_auth_enabled': password_auth_enabled(realm), 'dev_auth_enabled': dev_auth_enabled(realm), 'google_auth_enabled': google_auth_enabled(realm), 'github_auth_enabled': github_auth_enabled(realm), 'email_auth_enabled': email_auth_enabled(realm), 'require_email_format_usernames': require_email_format_usernames(realm), 'any_oauth_backend_enabled': any_oauth_backend_enabled(realm), 'no_auth_enabled': not auth_enabled_helper(list(AUTH_BACKEND_NAME_MAP.keys()), realm), 'development_environment': settings.DEVELOPMENT, 'support_email': FromAddress.SUPPORT, 'find_team_link_disabled': find_team_link_disabled, 'password_min_length': settings.PASSWORD_MIN_LENGTH, 'password_min_guesses': settings.PASSWORD_MIN_GUESSES, 'jitsi_server_url': settings.JITSI_SERVER_URL, 'two_factor_authentication_enabled': settings.TWO_FACTOR_AUTHENTICATION_ENABLED, 'zulip_version': ZULIP_VERSION, 'user_is_authenticated': user_is_authenticated, 'settings_path': settings_path, 'secrets_path': secrets_path, 'settings_comments_path': settings_comments_path, 'platform': platform, 'allow_search_engine_indexing': allow_search_engine_indexing, }
def accounts_register( request: HttpRequest, key: str = REQ(default=""), timezone: str = REQ(default="", converter=to_timezone_or_empty), from_confirmation: Optional[str] = REQ(default=None), form_full_name: Optional[str] = REQ("full_name", default=None), source_realm_id: Optional[int] = REQ( default=None, converter=to_converted_or_fallback(to_non_negative_int, None) ), ) -> HttpResponse: try: prereg_user = check_prereg_key(request, key) except ConfirmationKeyException as e: return render_confirmation_key_error(request, e) email = prereg_user.email realm_creation = prereg_user.realm_creation password_required = prereg_user.password_required role = prereg_user.invited_as if realm_creation: role = UserProfile.ROLE_REALM_OWNER try: validators.validate_email(email) except ValidationError: return render(request, "zerver/invalid_email.html", context={"invalid_email": True}) if realm_creation: # For creating a new realm, there is no existing realm or domain realm = None else: assert prereg_user.realm is not None if get_subdomain(request) != prereg_user.realm.string_id: return render_confirmation_key_error( request, ConfirmationKeyException(ConfirmationKeyException.DOES_NOT_EXIST) ) realm = prereg_user.realm try: email_allowed_for_realm(email, realm) except DomainNotAllowedForRealmError: return render( request, "zerver/invalid_email.html", context={"realm_name": realm.name, "closed_domain": True}, ) except DisposableEmailError: return render( request, "zerver/invalid_email.html", context={"realm_name": realm.name, "disposable_emails_not_allowed": True}, ) except EmailContainsPlusError: return render( request, "zerver/invalid_email.html", context={"realm_name": realm.name, "email_contains_plus": True}, ) if realm.deactivated: # The user is trying to register for a deactivated realm. Advise them to # contact support. return redirect_to_deactivation_notice() try: validate_email_not_already_in_realm(realm, email) except ValidationError: return redirect_to_email_login_url(email) if settings.BILLING_ENABLED: try: check_spare_licenses_available_for_registering_new_user(realm, email) except LicenseLimitError: return render(request, "zerver/no_spare_licenses.html") name_validated = False require_ldap_password = False if from_confirmation: try: del request.session["authenticated_full_name"] except KeyError: pass ldap_full_name = None if settings.POPULATE_PROFILE_VIA_LDAP: # If the user can be found in LDAP, we'll take the full name from the directory, # and further down create a form pre-filled with it. for backend in get_backends(): if isinstance(backend, LDAPBackend): try: ldap_username = backend.django_to_ldap_username(email) except ZulipLDAPExceptionNoMatchingLDAPUser: logging.warning("New account email %s could not be found in LDAP", email) break # Note that this `ldap_user` object is not a # `ZulipLDAPUser` with a `Realm` attached, so # calling `.populate_user()` on it will crash. # This is OK, since we're just accessing this user # to extract its name. # # TODO: We should potentially be accessing this # user to sync its initial avatar and custom # profile fields as well, if we indeed end up # creating a user account through this flow, # rather than waiting until `manage.py # sync_ldap_user_data` runs to populate it. ldap_user = _LDAPUser(backend, ldap_username) try: ldap_full_name = backend.get_mapped_name(ldap_user) except TypeError: break # Check whether this is ZulipLDAPAuthBackend, # which is responsible for authentication and # requires that LDAP accounts enter their LDAP # password to register, or ZulipLDAPUserPopulator, # which just populates UserProfile fields (no auth). require_ldap_password = isinstance(backend, ZulipLDAPAuthBackend) break if ldap_full_name: # We don't use initial= here, because if the form is # complete (that is, no additional fields need to be # filled out by the user) we want the form to validate, # so they can be directly registered without having to # go through this interstitial. form = RegistrationForm({"full_name": ldap_full_name}, realm_creation=realm_creation) request.session["authenticated_full_name"] = ldap_full_name name_validated = True elif realm is not None and realm.is_zephyr_mirror_realm: # For MIT users, we can get an authoritative name from Hesiod. # Technically we should check that this is actually an MIT # realm, but we can cross that bridge if we ever get a non-MIT # zephyr mirroring realm. hesiod_name = compute_mit_user_fullname(email) form = RegistrationForm( initial={"full_name": hesiod_name if "@" not in hesiod_name else ""}, realm_creation=realm_creation, ) name_validated = True elif prereg_user.full_name: if prereg_user.full_name_validated: request.session["authenticated_full_name"] = prereg_user.full_name name_validated = True form = RegistrationForm( {"full_name": prereg_user.full_name}, realm_creation=realm_creation ) else: form = RegistrationForm( initial={"full_name": prereg_user.full_name}, realm_creation=realm_creation ) elif form_full_name is not None: form = RegistrationForm( initial={"full_name": form_full_name}, realm_creation=realm_creation, ) else: form = RegistrationForm(realm_creation=realm_creation) else: postdata = request.POST.copy() if name_changes_disabled(realm): # If we populate profile information via LDAP and we have a # verified name from you on file, use that. Otherwise, fall # back to the full name in the request. try: postdata.update(full_name=request.session["authenticated_full_name"]) name_validated = True except KeyError: pass form = RegistrationForm(postdata, realm_creation=realm_creation) if not (password_auth_enabled(realm) and password_required): form["password"].field.required = False if form.is_valid(): if password_auth_enabled(realm) and form["password"].field.required: password = form.cleaned_data["password"] else: # If the user wasn't prompted for a password when # completing the authentication form (because they're # signing up with SSO and no password is required), set # the password field to `None` (Which causes Django to # create an unusable password). password = None if realm_creation: string_id = form.cleaned_data["realm_subdomain"] realm_name = form.cleaned_data["realm_name"] realm_type = form.cleaned_data["realm_type"] is_demo_org = form.cleaned_data["is_demo_organization"] realm = do_create_realm( string_id, realm_name, org_type=realm_type, is_demo_organization=is_demo_org ) setup_realm_internal_bots(realm) assert realm is not None full_name = form.cleaned_data["full_name"] enable_marketing_emails = form.cleaned_data["enable_marketing_emails"] default_stream_group_names = request.POST.getlist("default_stream_group") default_stream_groups = lookup_default_stream_groups(default_stream_group_names, realm) if source_realm_id is not None: # Non-integer realm_id values like "string" are treated # like the "Do not import" value of "". source_profile: Optional[UserProfile] = get_source_profile(email, source_realm_id) else: source_profile = None if not realm_creation: try: existing_user_profile: Optional[UserProfile] = get_user_by_delivery_email( email, realm ) except UserProfile.DoesNotExist: existing_user_profile = None else: existing_user_profile = None user_profile: Optional[UserProfile] = None return_data: Dict[str, bool] = {} if ldap_auth_enabled(realm): # If the user was authenticated using an external SSO # mechanism like Google or GitHub auth, then authentication # will have already been done before creating the # PreregistrationUser object with password_required=False, and # so we don't need to worry about passwords. # # If instead the realm is using EmailAuthBackend, we will # set their password above. # # But if the realm is using LDAPAuthBackend, we need to verify # their LDAP password (which will, as a side effect, create # the user account) here using authenticate. # pregeg_user.realm_creation carries the information about whether # we're in realm creation mode, and the ldap flow will handle # that and create the user with the appropriate parameters. user_profile = authenticate( request=request, username=email, password=password, realm=realm, prereg_user=prereg_user, return_data=return_data, ) if user_profile is None: can_use_different_backend = email_auth_enabled(realm) or ( len(get_external_method_dicts(realm)) > 0 ) if settings.LDAP_APPEND_DOMAIN: # In LDAP_APPEND_DOMAIN configurations, we don't allow making a non-LDAP account # if the email matches the ldap domain. can_use_different_backend = can_use_different_backend and ( not email_belongs_to_ldap(realm, email) ) if return_data.get("no_matching_ldap_user") and can_use_different_backend: # If both the LDAP and Email or Social auth backends are # enabled, and there's no matching user in the LDAP # directory then the intent is to create a user in the # realm with their email outside the LDAP organization # (with e.g. a password stored in the Zulip database, # not LDAP). So we fall through and create the new # account. pass else: # TODO: This probably isn't going to give a # user-friendly error message, but it doesn't # particularly matter, because the registration form # is hidden for most users. view_url = reverse("login") query = urlencode({"email": email}) redirect_url = append_url_query_string(view_url, query) return HttpResponseRedirect(redirect_url) elif not realm_creation: # Since we'll have created a user, we now just log them in. return login_and_go_to_home(request, user_profile) else: # With realm_creation=True, we're going to return further down, # after finishing up the creation process. pass if existing_user_profile is not None and existing_user_profile.is_mirror_dummy: user_profile = existing_user_profile do_activate_mirror_dummy_user(user_profile, acting_user=user_profile) do_change_password(user_profile, password) do_change_full_name(user_profile, full_name, user_profile) do_change_user_setting(user_profile, "timezone", timezone, acting_user=user_profile) # TODO: When we clean up the `do_activate_mirror_dummy_user` code path, # make it respect invited_as_admin / is_realm_admin. if user_profile is None: user_profile = do_create_user( email, password, realm, full_name, prereg_user=prereg_user, role=role, tos_version=settings.TOS_VERSION, timezone=timezone, default_stream_groups=default_stream_groups, source_profile=source_profile, realm_creation=realm_creation, acting_user=None, enable_marketing_emails=enable_marketing_emails, ) if realm_creation: assert realm.signup_notifications_stream is not None bulk_add_subscriptions( realm, [realm.signup_notifications_stream], [user_profile], acting_user=None ) send_initial_realm_messages(realm) # Because for realm creation, registration happens on the # root domain, we need to log them into the subdomain for # their new realm. return redirect_and_log_into_subdomain( ExternalAuthResult(user_profile=user_profile, data_dict={"is_realm_creation": True}) ) # This dummy_backend check below confirms the user is # authenticating to the correct subdomain. auth_result = authenticate( username=user_profile.delivery_email, realm=realm, return_data=return_data, use_dummy_backend=True, ) if return_data.get("invalid_subdomain"): # By construction, this should never happen. logging.error( "Subdomain mismatch in registration %s: %s", realm.subdomain, user_profile.delivery_email, ) return redirect("/") return login_and_go_to_home(request, auth_result) return render( request, "zerver/register.html", context={ "form": form, "email": email, "key": key, "full_name": request.session.get("authenticated_full_name", None), "lock_name": name_validated and name_changes_disabled(realm), # password_auth_enabled is normally set via our context processor, # but for the registration form, there is no logged in user yet, so # we have to set it here. "creating_new_team": realm_creation, "password_required": password_auth_enabled(realm) and password_required, "require_ldap_password": require_ldap_password, "password_auth_enabled": password_auth_enabled(realm), "root_domain_available": is_root_domain_available(), "default_stream_groups": [] if realm is None else get_default_stream_groups(realm), "accounts": get_accounts_for_email(email), "MAX_REALM_NAME_LENGTH": str(Realm.MAX_REALM_NAME_LENGTH), "MAX_NAME_LENGTH": str(UserProfile.MAX_NAME_LENGTH), "MAX_PASSWORD_LENGTH": str(form.MAX_PASSWORD_LENGTH), "MAX_REALM_SUBDOMAIN_LENGTH": str(Realm.MAX_REALM_SUBDOMAIN_LENGTH), "sorted_realm_types": sorted( Realm.ORG_TYPES.values(), key=lambda d: d["display_order"] ), }, )
def fetch_initial_state_data( user_profile: UserProfile, event_types: Optional[Iterable[str]], queue_id: str, client_gravatar: bool, user_avatar_url_field_optional: bool, slim_presence: bool = False, include_subscribers: bool = True) -> Dict[str, Any]: state: Dict[str, Any] = {'queue_id': queue_id} realm = user_profile.realm if event_types is None: # return True always want: Callable[[str], bool] = always_want else: want = set(event_types).__contains__ # Show the version info unconditionally. state['zulip_version'] = ZULIP_VERSION state['zulip_feature_level'] = API_FEATURE_LEVEL if want('alert_words'): state['alert_words'] = user_alert_words(user_profile) if want('custom_profile_fields'): fields = custom_profile_fields_for_realm(realm.id) state['custom_profile_fields'] = [f.as_dict() for f in fields] state[ 'custom_profile_field_types'] = CustomProfileField.FIELD_TYPE_CHOICES_DICT if want('hotspots'): state['hotspots'] = get_next_hotspots(user_profile) if want('message'): # The client should use get_messages() to fetch messages # starting with the max_message_id. They will get messages # newer than that ID via get_events() user_messages = UserMessage.objects \ .filter(user_profile=user_profile) \ .order_by('-message_id') \ .values('message_id')[:1] if user_messages: state['max_message_id'] = user_messages[0]['message_id'] else: state['max_message_id'] = -1 if want('muted_topics'): state['muted_topics'] = get_topic_mutes(user_profile) if want('presence'): state['presences'] = get_presences_for_realm(realm, user_profile, slim_presence) if want('realm'): for property_name in Realm.property_types: state['realm_' + property_name] = getattr(realm, property_name) # Most state is handled via the property_types framework; # these manual entries are for those realm settings that don't # fit into that framework. state[ 'realm_authentication_methods'] = realm.authentication_methods_dict( ) state['realm_allow_message_editing'] = realm.allow_message_editing state[ 'realm_allow_community_topic_editing'] = realm.allow_community_topic_editing state['realm_allow_message_deleting'] = realm.allow_message_deleting state[ 'realm_message_content_edit_limit_seconds'] = realm.message_content_edit_limit_seconds state[ 'realm_message_content_delete_limit_seconds'] = realm.message_content_delete_limit_seconds state['realm_community_topic_editing_limit_seconds'] = \ Realm.DEFAULT_COMMUNITY_TOPIC_EDITING_LIMIT_SECONDS state['realm_icon_url'] = realm_icon_url(realm) state['realm_icon_source'] = realm.icon_source state['max_icon_file_size'] = settings.MAX_ICON_FILE_SIZE add_realm_logo_fields(state, realm) state['realm_bot_domain'] = realm.get_bot_domain() state['realm_uri'] = realm.uri state[ 'realm_available_video_chat_providers'] = realm.VIDEO_CHAT_PROVIDERS state['realm_presence_disabled'] = realm.presence_disabled state['settings_send_digest_emails'] = settings.SEND_DIGEST_EMAILS state[ 'realm_digest_emails_enabled'] = realm.digest_emails_enabled and settings.SEND_DIGEST_EMAILS state['realm_is_zephyr_mirror_realm'] = realm.is_zephyr_mirror_realm state['realm_email_auth_enabled'] = email_auth_enabled(realm) state['realm_password_auth_enabled'] = password_auth_enabled(realm) state['realm_push_notifications_enabled'] = push_notifications_enabled( ) state['realm_upload_quota'] = realm.upload_quota_bytes() state['realm_plan_type'] = realm.plan_type state['zulip_plan_is_not_limited'] = realm.plan_type != Realm.LIMITED state['upgrade_text_for_wide_organization_logo'] = str( Realm.UPGRADE_TEXT_STANDARD) state['realm_default_external_accounts'] = DEFAULT_EXTERNAL_ACCOUNTS state['jitsi_server_url'] = settings.JITSI_SERVER_URL state['development_environment'] = settings.DEVELOPMENT state['server_generation'] = settings.SERVER_GENERATION state['password_min_length'] = settings.PASSWORD_MIN_LENGTH state['password_min_guesses'] = settings.PASSWORD_MIN_GUESSES state['max_file_upload_size_mib'] = settings.MAX_FILE_UPLOAD_SIZE state['max_avatar_file_size_mib'] = settings.MAX_AVATAR_FILE_SIZE state['server_inline_image_preview'] = settings.INLINE_IMAGE_PREVIEW state[ 'server_inline_url_embed_preview'] = settings.INLINE_URL_EMBED_PREVIEW state[ 'server_avatar_changes_disabled'] = settings.AVATAR_CHANGES_DISABLED state['server_name_changes_disabled'] = settings.NAME_CHANGES_DISABLED if realm.notifications_stream and not realm.notifications_stream.deactivated: notifications_stream = realm.notifications_stream state['realm_notifications_stream_id'] = notifications_stream.id else: state['realm_notifications_stream_id'] = -1 signup_notifications_stream = realm.get_signup_notifications_stream() if signup_notifications_stream: state[ 'realm_signup_notifications_stream_id'] = signup_notifications_stream.id else: state['realm_signup_notifications_stream_id'] = -1 if want('realm_domains'): state['realm_domains'] = get_realm_domains(realm) if want('realm_emoji'): state['realm_emoji'] = realm.get_emoji() if want('realm_filters'): state['realm_filters'] = realm_filters_for_realm(realm.id) if want('realm_user_groups'): state['realm_user_groups'] = user_groups_in_realm_serialized(realm) if want('realm_filtered_user'): state['filtered_users'] = get_filtered_user_data( realm, user_profile, client_gravatar=client_gravatar, user_avatar_url_field_optional=user_avatar_url_field_optional) # For the user's own avatar URL, we force # client_gravatar=False, since that saves some unnecessary # client-side code for handing medium-size avatars. See #8253 # for details. state['avatar_source'] = user_profile.avatar_source state['avatar_url_medium'] = avatar_url( user_profile, medium=True, client_gravatar=False, ) state['avatar_url'] = avatar_url( user_profile, medium=False, client_gravatar=False, ) state['can_create_streams'] = user_profile.can_create_streams() state[ 'can_subscribe_other_users'] = user_profile.can_subscribe_other_users( ) state['cross_realm_bots'] = list(get_cross_realm_dicts()) state['is_admin'] = user_profile.is_realm_admin state['is_owner'] = user_profile.is_realm_owner state['is_guest'] = user_profile.is_guest state['user_id'] = user_profile.id state['enter_sends'] = user_profile.enter_sends state['email'] = user_profile.email state['delivery_email'] = user_profile.delivery_email state['full_name'] = user_profile.full_name if want('realm_user'): state['raw_users'] = get_raw_user_data( realm, user_profile, client_gravatar=client_gravatar, user_avatar_url_field_optional=user_avatar_url_field_optional) # For the user's own avatar URL, we force # client_gravatar=False, since that saves some unnecessary # client-side code for handing medium-size avatars. See #8253 # for details. state['avatar_source'] = user_profile.avatar_source state['avatar_url_medium'] = avatar_url( user_profile, medium=True, client_gravatar=False, ) state['avatar_url'] = avatar_url( user_profile, medium=False, client_gravatar=False, ) state['can_create_streams'] = user_profile.can_create_streams() state[ 'can_subscribe_other_users'] = user_profile.can_subscribe_other_users( ) state['cross_realm_bots'] = list(get_cross_realm_dicts()) state['is_admin'] = user_profile.is_realm_admin state['is_owner'] = user_profile.is_realm_owner state['is_guest'] = user_profile.is_guest state['user_id'] = user_profile.id state['enter_sends'] = user_profile.enter_sends state['email'] = user_profile.email state['delivery_email'] = user_profile.delivery_email state['full_name'] = user_profile.full_name if want('realm_bot'): state['realm_bots'] = get_owned_bot_dicts(user_profile) # This does not yet have an apply_event counterpart, since currently, # new entries for EMBEDDED_BOTS can only be added directly in the codebase. if want('realm_embedded_bots'): realm_embedded_bots = [] for bot in EMBEDDED_BOTS: realm_embedded_bots.append({ 'name': bot.name, 'config': load_bot_config_template(bot.name) }) state['realm_embedded_bots'] = realm_embedded_bots # This does not have an apply_events counterpart either since # this data is mostly static. if want('realm_incoming_webhook_bots'): realm_incoming_webhook_bots = [] for integration in WEBHOOK_INTEGRATIONS: realm_incoming_webhook_bots.append({ 'name': integration.name, 'config': {c[1]: c[0] for c in integration.config_options}, }) state['realm_incoming_webhook_bots'] = realm_incoming_webhook_bots if want('recent_private_conversations'): # A data structure containing records of this form: # # [{'max_message_id': 700175, 'user_ids': [801]}] # # for all recent private message conversations, ordered by the # highest message ID in the conversation. The user_ids list # is the list of users other than the current user in the # private message conversation (so it is [] for PMs to self). # Note that raw_recent_private_conversations is an # intermediate form as a dictionary keyed by recipient_id, # which is more efficient to update, and is rewritten to the # final format in post_process_state. state[ 'raw_recent_private_conversations'] = get_recent_private_conversations( user_profile) if want('subscription'): subscriptions, unsubscribed, never_subscribed = gather_subscriptions_helper( user_profile, include_subscribers=include_subscribers) state['subscriptions'] = subscriptions state['unsubscribed'] = unsubscribed state['never_subscribed'] = never_subscribed if want('update_message_flags') and want('message'): # Keeping unread_msgs updated requires both message flag updates and # message updates. This is due to the fact that new messages will not # generate a flag update so we need to use the flags field in the # message event. state['raw_unread_msgs'] = get_raw_unread_data(user_profile) if want('starred_messages'): state['starred_messages'] = get_starred_message_ids(user_profile) if want('stream'): state['streams'] = do_get_streams(user_profile) state['stream_name_max_length'] = Stream.MAX_NAME_LENGTH state['stream_description_max_length'] = Stream.MAX_DESCRIPTION_LENGTH if want('default_streams'): if user_profile.is_guest: state['realm_default_streams'] = [] else: state['realm_default_streams'] = streams_to_dicts_sorted( get_default_streams_for_realm(realm.id)) if want('default_stream_groups'): if user_profile.is_guest: state['realm_default_stream_groups'] = [] else: state[ 'realm_default_stream_groups'] = default_stream_groups_to_dicts_sorted( get_default_stream_groups(realm)) if want('stop_words'): state['stop_words'] = read_stop_words() if want('update_display_settings'): for prop in UserProfile.property_types: state[prop] = getattr(user_profile, prop) state['emojiset_choices'] = user_profile.emojiset_choices() if want('update_global_notifications'): for notification in UserProfile.notification_setting_types: state[notification] = getattr(user_profile, notification) state[ 'available_notification_sounds'] = get_available_notification_sounds( ) if want('user_status'): state['user_status'] = get_user_info_dict(realm_id=realm.id) if want('video_calls'): state['has_zoom_token'] = user_profile.zoom_token is not None return state
def fetch_initial_state_data( user_profile: Optional[UserProfile], *, realm: Optional[Realm] = None, event_types: Optional[Iterable[str]] = None, queue_id: Optional[str] = "", client_gravatar: bool = False, user_avatar_url_field_optional: bool = False, slim_presence: bool = False, include_subscribers: bool = True, include_streams: bool = True, ) -> Dict[str, Any]: """When `event_types` is None, fetches the core data powering the webapp's `page_params` and `/api/v1/register` (for mobile/terminal apps). Can also fetch a subset as determined by `event_types`. The user_profile=None code path is used for logged-out public access to streams with is_web_public=True. Whenever you add new code to this function, you should also add corresponding events for changes in the data structures and new code to apply_events (and add a test in test_events.py). """ if realm is None: assert user_profile is not None realm = user_profile.realm state: Dict[str, Any] = {'queue_id': queue_id} if event_types is None: # return True always want: Callable[[str], bool] = always_want else: want = set(event_types).__contains__ # Show the version info unconditionally. state['zulip_version'] = ZULIP_VERSION state['zulip_feature_level'] = API_FEATURE_LEVEL if want('alert_words'): state['alert_words'] = [] if user_profile is None else user_alert_words(user_profile) if want('custom_profile_fields'): fields = custom_profile_fields_for_realm(realm.id) state['custom_profile_fields'] = [f.as_dict() for f in fields] state['custom_profile_field_types'] = { item[4]: {"id": item[0], "name": str(item[1])} for item in CustomProfileField.ALL_FIELD_TYPES } if want('hotspots'): # Even if we offered special hotspots for guests without an # account, we'd maybe need to store their state using cookies # or local storage, rather than in the database. state['hotspots'] = [] if user_profile is None else get_next_hotspots(user_profile) if want('message'): # Since the introduction of `anchor="latest"` in the API, # `max_message_id` is primarily used for generating `local_id` # values that are higher than this. We likely can eventually # remove this parameter from the API. user_messages = [] if user_profile is not None: user_messages = UserMessage.objects \ .filter(user_profile=user_profile) \ .order_by('-message_id') \ .values('message_id')[:1] if user_messages: state['max_message_id'] = user_messages[0]['message_id'] else: state['max_message_id'] = -1 if want('muted_topics'): state['muted_topics'] = [] if user_profile is None else get_topic_mutes(user_profile) if want('presence'): state['presences'] = {} if user_profile is None else get_presences_for_realm(realm, slim_presence) if want('realm'): for property_name in Realm.property_types: state['realm_' + property_name] = getattr(realm, property_name) # Most state is handled via the property_types framework; # these manual entries are for those realm settings that don't # fit into that framework. state['realm_authentication_methods'] = realm.authentication_methods_dict() # We pretend these features are disabled because guests can't # access them. In the future, we may want to move this logic # to the frontends, so that we can correctly display what # these fields are in the settings. state['realm_allow_message_editing'] = False if user_profile is None else realm.allow_message_editing state['realm_allow_community_topic_editing'] = False if user_profile is None else realm.allow_community_topic_editing state['realm_allow_message_deleting'] = False if user_profile is None else realm.allow_message_deleting state['realm_message_content_edit_limit_seconds'] = realm.message_content_edit_limit_seconds state['realm_message_content_delete_limit_seconds'] = realm.message_content_delete_limit_seconds state['realm_community_topic_editing_limit_seconds'] = \ Realm.DEFAULT_COMMUNITY_TOPIC_EDITING_LIMIT_SECONDS # This setting determines whether to send presence and also # whether to display of users list in the right sidebar; we # want both behaviors for logged-out users. We may in the # future choose to move this logic to the frontend. state['realm_presence_disabled'] = True if user_profile is None else realm.presence_disabled state['realm_icon_url'] = realm_icon_url(realm) state['realm_icon_source'] = realm.icon_source state['max_icon_file_size'] = settings.MAX_ICON_FILE_SIZE add_realm_logo_fields(state, realm) state['realm_bot_domain'] = realm.get_bot_domain() state['realm_uri'] = realm.uri state['realm_available_video_chat_providers'] = realm.VIDEO_CHAT_PROVIDERS state['settings_send_digest_emails'] = settings.SEND_DIGEST_EMAILS state['realm_digest_emails_enabled'] = realm.digest_emails_enabled and settings.SEND_DIGEST_EMAILS state['realm_is_zephyr_mirror_realm'] = realm.is_zephyr_mirror_realm state['realm_email_auth_enabled'] = email_auth_enabled(realm) state['realm_password_auth_enabled'] = password_auth_enabled(realm) state['realm_push_notifications_enabled'] = push_notifications_enabled() state['realm_upload_quota'] = realm.upload_quota_bytes() state['realm_plan_type'] = realm.plan_type state['zulip_plan_is_not_limited'] = realm.plan_type != Realm.LIMITED state['upgrade_text_for_wide_organization_logo'] = str(Realm.UPGRADE_TEXT_STANDARD) state['realm_default_external_accounts'] = DEFAULT_EXTERNAL_ACCOUNTS state['jitsi_server_url'] = settings.JITSI_SERVER_URL.rstrip('/') state['development_environment'] = settings.DEVELOPMENT state['server_generation'] = settings.SERVER_GENERATION state['password_min_length'] = settings.PASSWORD_MIN_LENGTH state['password_min_guesses'] = settings.PASSWORD_MIN_GUESSES state['max_file_upload_size_mib'] = settings.MAX_FILE_UPLOAD_SIZE state['max_avatar_file_size_mib'] = settings.MAX_AVATAR_FILE_SIZE state['server_inline_image_preview'] = settings.INLINE_IMAGE_PREVIEW state['server_inline_url_embed_preview'] = settings.INLINE_URL_EMBED_PREVIEW state['server_avatar_changes_disabled'] = settings.AVATAR_CHANGES_DISABLED state['server_name_changes_disabled'] = settings.NAME_CHANGES_DISABLED if realm.notifications_stream and not realm.notifications_stream.deactivated: notifications_stream = realm.notifications_stream state['realm_notifications_stream_id'] = notifications_stream.id else: state['realm_notifications_stream_id'] = -1 signup_notifications_stream = realm.get_signup_notifications_stream() if signup_notifications_stream: state['realm_signup_notifications_stream_id'] = signup_notifications_stream.id else: state['realm_signup_notifications_stream_id'] = -1 if want('realm_domains'): state['realm_domains'] = get_realm_domains(realm) if want('realm_emoji'): state['realm_emoji'] = realm.get_emoji() if want('realm_filters'): state['realm_filters'] = realm_filters_for_realm(realm.id) if want('realm_user_groups'): state['realm_user_groups'] = user_groups_in_realm_serialized(realm) if user_profile is not None: settings_user = user_profile else: # When UserProfile=None, we want to serve the values for various # settings as the defaults. Instead of copying the default values # from models.py here, we access these default values from a # temporary UserProfile object that will not be saved to the database. # # We also can set various fields to avoid duplicating code # unnecessarily. settings_user = UserProfile( full_name="Anonymous User", email="*****@*****.**", delivery_email="*****@*****.**", realm=realm, # We tag logged-out users as guests because most guest # restrictions apply to these users as well, and it lets # us avoid unnecessary conditionals. role=UserProfile.ROLE_GUEST, avatar_source=UserProfile.AVATAR_FROM_GRAVATAR, # ID=0 is not used in real Zulip databases, ensuring this is unique. id=0, ) if want('realm_user'): state['raw_users'] = get_raw_user_data(realm, user_profile, client_gravatar=client_gravatar, user_avatar_url_field_optional=user_avatar_url_field_optional) state['cross_realm_bots'] = list(get_cross_realm_dicts()) # For the user's own avatar URL, we force # client_gravatar=False, since that saves some unnecessary # client-side code for handing medium-size avatars. See #8253 # for details. state['avatar_source'] = settings_user.avatar_source state['avatar_url_medium'] = avatar_url( settings_user, medium=True, client_gravatar=False, ) state['avatar_url'] = avatar_url( settings_user, medium=False, client_gravatar=False, ) state['can_create_streams'] = settings_user.can_create_streams() state['can_subscribe_other_users'] = settings_user.can_subscribe_other_users() state['is_admin'] = settings_user.is_realm_admin state['is_owner'] = settings_user.is_realm_owner state['is_guest'] = settings_user.is_guest state['user_id'] = settings_user.id state['enter_sends'] = settings_user.enter_sends state['email'] = settings_user.email state['delivery_email'] = settings_user.delivery_email state['full_name'] = settings_user.full_name if want('realm_bot'): state['realm_bots'] = [] if user_profile is None else get_owned_bot_dicts(user_profile) # This does not yet have an apply_event counterpart, since currently, # new entries for EMBEDDED_BOTS can only be added directly in the codebase. if want('realm_embedded_bots'): realm_embedded_bots = [] for bot in EMBEDDED_BOTS: realm_embedded_bots.append({'name': bot.name, 'config': load_bot_config_template(bot.name)}) state['realm_embedded_bots'] = realm_embedded_bots # This does not have an apply_events counterpart either since # this data is mostly static. if want('realm_incoming_webhook_bots'): realm_incoming_webhook_bots = [] for integration in WEBHOOK_INTEGRATIONS: realm_incoming_webhook_bots.append({ 'name': integration.name, 'config': {c[1]: c[0] for c in integration.config_options}, }) state['realm_incoming_webhook_bots'] = realm_incoming_webhook_bots if want('recent_private_conversations'): # A data structure containing records of this form: # # [{'max_message_id': 700175, 'user_ids': [801]}] # # for all recent private message conversations, ordered by the # highest message ID in the conversation. The user_ids list # is the list of users other than the current user in the # private message conversation (so it is [] for PMs to self). # Note that raw_recent_private_conversations is an # intermediate form as a dictionary keyed by recipient_id, # which is more efficient to update, and is rewritten to the # final format in post_process_state. state['raw_recent_private_conversations'] = {} if user_profile is None else get_recent_private_conversations(user_profile) if want('subscription'): if user_profile is not None: sub_info = gather_subscriptions_helper( user_profile, include_subscribers=include_subscribers, ) else: sub_info = get_web_public_subs(realm) state['subscriptions'] = sub_info.subscriptions state['unsubscribed'] = sub_info.unsubscribed state['never_subscribed'] = sub_info.never_subscribed if want('update_message_flags') and want('message'): # Keeping unread_msgs updated requires both message flag updates and # message updates. This is due to the fact that new messages will not # generate a flag update so we need to use the flags field in the # message event. if user_profile is not None: state['raw_unread_msgs'] = get_raw_unread_data(user_profile) else: # For logged-out visitors, we treat all messages as read; # calling this helper lets us return empty objects in the # appropriate format. state['raw_unread_msgs'] = extract_unread_data_from_um_rows([], user_profile) if want('starred_messages'): state['starred_messages'] = [] if user_profile is None else get_starred_message_ids(user_profile) if want('stream'): if include_streams: # The webapp doesn't use the data from here; instead, # it uses data from state["subscriptions"] and other # places. if user_profile is not None: state['streams'] = do_get_streams(user_profile) else: # TODO: This line isn't used by the webapp because it # gets these data via the `subscriptions` key; it will # be used when the mobile apps support logged-out # access. state['streams'] = get_web_public_streams(realm) # nocoverage state['stream_name_max_length'] = Stream.MAX_NAME_LENGTH state['stream_description_max_length'] = Stream.MAX_DESCRIPTION_LENGTH if want('default_streams'): if settings_user.is_guest: # Guest users and logged-out users don't have access to # all default streams, so we pretend the organization # doesn't have any. state['realm_default_streams'] = [] else: state['realm_default_streams'] = streams_to_dicts_sorted( get_default_streams_for_realm(realm.id)) if want('default_stream_groups'): if settings_user.is_guest: state['realm_default_stream_groups'] = [] else: state['realm_default_stream_groups'] = default_stream_groups_to_dicts_sorted( get_default_stream_groups(realm)) if want('stop_words'): state['stop_words'] = read_stop_words() if want('update_display_settings'): for prop in UserProfile.property_types: state[prop] = getattr(settings_user, prop) state['emojiset_choices'] = UserProfile.emojiset_choices() if want('update_global_notifications'): for notification in UserProfile.notification_setting_types: state[notification] = getattr(settings_user, notification) state['available_notification_sounds'] = get_available_notification_sounds() if want('user_status'): # We require creating an account to access statuses. state['user_status'] = {} if user_profile is None else get_user_info_dict(realm_id=realm.id) if want('video_calls'): state['has_zoom_token'] = settings_user.zoom_token is not None return state
def login_context(request: HttpRequest) -> Dict[str, Any]: realm = get_realm_from_request(request) if realm is None: realm_description = None realm_invite_required = False else: realm_description = get_realm_rendered_description(realm) realm_invite_required = realm.invite_required context = { 'realm_invite_required': realm_invite_required, 'realm_description': realm_description, 'require_email_format_usernames': require_email_format_usernames(realm), 'password_auth_enabled': password_auth_enabled(realm), 'any_oauth_backend_enabled': any_oauth_backend_enabled(realm), 'two_factor_authentication_enabled': settings.TWO_FACTOR_AUTHENTICATION_ENABLED, } # type: Dict[str, Any] if realm is not None and realm.description: context['OPEN_GRAPH_TITLE'] = realm.name context['OPEN_GRAPH_DESCRIPTION'] = get_realm_text_description(realm) # Add the keys for our standard authentication backends. no_auth_enabled = True social_backends = [] for auth_backend_name in AUTH_BACKEND_NAME_MAP: name_lower = auth_backend_name.lower() key = "%s_auth_enabled" % (name_lower, ) is_enabled = auth_enabled_helper([auth_backend_name], realm) context[key] = is_enabled if is_enabled: no_auth_enabled = False # Now add the enabled social backends to the social_backends # list used to generate buttons for login/register pages. backend = AUTH_BACKEND_NAME_MAP[auth_backend_name] if not is_enabled or backend not in SOCIAL_AUTH_BACKENDS: continue social_backends.append({ 'name': backend.name, 'display_name': backend.auth_backend_name, 'login_url': reverse('login-social', args=(backend.name, )), 'signup_url': reverse('signup-social', args=(backend.name, )), 'sort_order': backend.sort_order, }) context['social_backends'] = sorted(social_backends, key=lambda x: x['sort_order'], reverse=True) context['no_auth_enabled'] = no_auth_enabled return context
def fetch_initial_state_data(user_profile, event_types, queue_id, include_subscribers=True): # type: (UserProfile, Optional[Iterable[str]], str, bool) -> Dict[str, Any] state = {'queue_id': queue_id} # type: Dict[str, Any] if event_types is None: want = lambda msg_type: True else: want = set(event_types).__contains__ if want('alert_words'): state['alert_words'] = user_alert_words(user_profile) if want('custom_profile_fields'): fields = custom_profile_fields_for_realm(user_profile.realm.id) state['custom_profile_fields'] = [f.as_dict() for f in fields] if want('attachments'): state['attachments'] = user_attachments(user_profile) if want('hotspots'): state['hotspots'] = get_next_hotspots(user_profile) if want('message'): # The client should use get_messages() to fetch messages # starting with the max_message_id. They will get messages # newer than that ID via get_events() messages = Message.objects.filter(usermessage__user_profile=user_profile).order_by('-id')[:1] if messages: state['max_message_id'] = messages[0].id else: state['max_message_id'] = -1 if want('muted_topics'): state['muted_topics'] = ujson.loads(user_profile.muted_topics) if want('pointer'): state['pointer'] = user_profile.pointer if want('presence'): state['presences'] = get_status_dict(user_profile) if want('realm'): for property_name in Realm.property_types: state['realm_' + property_name] = getattr(user_profile.realm, property_name) state['realm_authentication_methods'] = user_profile.realm.authentication_methods_dict() state['realm_allow_message_editing'] = user_profile.realm.allow_message_editing state['realm_message_content_edit_limit_seconds'] = user_profile.realm.message_content_edit_limit_seconds state['realm_icon_url'] = realm_icon_url(user_profile.realm) state['realm_icon_source'] = user_profile.realm.icon_source state['max_icon_file_size'] = settings.MAX_ICON_FILE_SIZE state['realm_bot_domain'] = user_profile.realm.get_bot_domain() state['realm_uri'] = user_profile.realm.uri state['realm_presence_disabled'] = user_profile.realm.presence_disabled state['realm_mandatory_topics'] = user_profile.realm.mandatory_topics state['realm_show_digest_email'] = user_profile.realm.show_digest_email state['realm_is_zephyr_mirror_realm'] = user_profile.realm.is_zephyr_mirror_realm state['realm_password_auth_enabled'] = password_auth_enabled(user_profile.realm) if user_profile.realm.notifications_stream and not user_profile.realm.notifications_stream.deactivated: notifications_stream = user_profile.realm.notifications_stream state['realm_notifications_stream_id'] = notifications_stream.id else: state['realm_notifications_stream_id'] = -1 if want('realm_domains'): state['realm_domains'] = get_realm_domains(user_profile.realm) if want('realm_emoji'): state['realm_emoji'] = user_profile.realm.get_emoji() if want('realm_filters'): state['realm_filters'] = realm_filters_for_realm(user_profile.realm_id) if want('realm_user'): state['realm_users'] = get_realm_user_dicts(user_profile) state['avatar_source'] = user_profile.avatar_source state['avatar_url_medium'] = avatar_url(user_profile, medium=True) state['avatar_url'] = avatar_url(user_profile) state['can_create_streams'] = user_profile.can_create_streams() state['cross_realm_bots'] = list(get_cross_realm_dicts()) state['is_admin'] = user_profile.is_realm_admin state['user_id'] = user_profile.id state['enter_sends'] = user_profile.enter_sends state['email'] = user_profile.email state['full_name'] = user_profile.full_name if want('realm_bot'): state['realm_bots'] = get_owned_bot_dicts(user_profile) if want('referral'): state['referrals'] = {'granted': user_profile.invites_granted, 'used': user_profile.invites_used} if want('subscription'): subscriptions, unsubscribed, never_subscribed = gather_subscriptions_helper( user_profile, include_subscribers=include_subscribers) state['subscriptions'] = subscriptions state['unsubscribed'] = unsubscribed state['never_subscribed'] = never_subscribed if want('update_message_flags'): # There's no initial data for message flag updates, client will # get any updates during a session from get_events() pass if want('stream'): state['streams'] = do_get_streams(user_profile) if want('default_streams'): state['realm_default_streams'] = streams_to_dicts_sorted(get_default_streams_for_realm(user_profile.realm)) if want('update_display_settings'): state['twenty_four_hour_time'] = user_profile.twenty_four_hour_time state['left_side_userlist'] = user_profile.left_side_userlist state['emoji_alt_code'] = user_profile.emoji_alt_code state['emojiset'] = user_profile.emojiset state['emojiset_choices'] = user_profile.emojiset_choices() state['timezone'] = user_profile.timezone state['default_language'] = user_profile.default_language state['autoscroll_forever'] = user_profile.autoscroll_forever if want('update_global_notifications'): state['default_desktop_notifications'] = user_profile.default_desktop_notifications state['enable_stream_desktop_notifications'] = user_profile.enable_stream_desktop_notifications state['enable_stream_sounds'] = user_profile.enable_stream_sounds state['enable_desktop_notifications'] = user_profile.enable_desktop_notifications state['enable_sounds'] = user_profile.enable_sounds state['enable_offline_email_notifications'] = user_profile.enable_offline_email_notifications state['enable_offline_push_notifications'] = user_profile.enable_offline_push_notifications state['enable_online_push_notifications'] = user_profile.enable_online_push_notifications state['enable_digest_emails'] = user_profile.enable_digest_emails state['pm_content_in_desktop_notifications'] = user_profile.pm_content_in_desktop_notifications if want('zulip_version'): state['zulip_version'] = ZULIP_VERSION return state
def fetch_initial_state_data(user_profile, event_types, queue_id, include_subscribers=True): # type: (UserProfile, Optional[Iterable[str]], str, bool) -> Dict[str, Any] state = {'queue_id': queue_id} # type: Dict[str, Any] if event_types is None: want = lambda msg_type: True else: want = set(event_types).__contains__ if want('alert_words'): state['alert_words'] = user_alert_words(user_profile) if want('custom_profile_fields'): fields = custom_profile_fields_for_realm(user_profile.realm.id) state['custom_profile_fields'] = [f.as_dict() for f in fields] if want('attachments'): state['attachments'] = user_attachments(user_profile) if want('hotspots'): state['hotspots'] = get_next_hotspots(user_profile) if want('message'): # The client should use get_messages() to fetch messages # starting with the max_message_id. They will get messages # newer than that ID via get_events() messages = Message.objects.filter( usermessage__user_profile=user_profile).order_by('-id')[:1] if messages: state['max_message_id'] = messages[0].id else: state['max_message_id'] = -1 if want('muted_topics'): state['muted_topics'] = ujson.loads(user_profile.muted_topics) if want('pointer'): state['pointer'] = user_profile.pointer if want('presence'): state['presences'] = get_status_dict(user_profile) if want('realm'): for property_name in Realm.property_types: state['realm_' + property_name] = getattr(user_profile.realm, property_name) # Most state is handled via the property_types framework; # these manual entries are for those realm settings that don't # fit into that framework. state[ 'realm_authentication_methods'] = user_profile.realm.authentication_methods_dict( ) state[ 'realm_allow_message_editing'] = user_profile.realm.allow_message_editing state[ 'realm_message_content_edit_limit_seconds'] = user_profile.realm.message_content_edit_limit_seconds state['realm_icon_url'] = realm_icon_url(user_profile.realm) state['realm_icon_source'] = user_profile.realm.icon_source state['max_icon_file_size'] = settings.MAX_ICON_FILE_SIZE state['realm_bot_domain'] = user_profile.realm.get_bot_domain() state['realm_uri'] = user_profile.realm.uri state['realm_presence_disabled'] = user_profile.realm.presence_disabled state['realm_show_digest_email'] = user_profile.realm.show_digest_email state[ 'realm_is_zephyr_mirror_realm'] = user_profile.realm.is_zephyr_mirror_realm state['realm_password_auth_enabled'] = password_auth_enabled( user_profile.realm) if user_profile.realm.notifications_stream and not user_profile.realm.notifications_stream.deactivated: notifications_stream = user_profile.realm.notifications_stream state['realm_notifications_stream_id'] = notifications_stream.id else: state['realm_notifications_stream_id'] = -1 if want('realm_domains'): state['realm_domains'] = get_realm_domains(user_profile.realm) if want('realm_emoji'): state['realm_emoji'] = user_profile.realm.get_emoji() if want('realm_filters'): state['realm_filters'] = realm_filters_for_realm(user_profile.realm_id) if want('realm_user'): state['realm_users'] = get_realm_user_dicts(user_profile) state['avatar_source'] = user_profile.avatar_source state['avatar_url_medium'] = avatar_url(user_profile, medium=True) state['avatar_url'] = avatar_url(user_profile) state['can_create_streams'] = user_profile.can_create_streams() state['cross_realm_bots'] = list(get_cross_realm_dicts()) state['is_admin'] = user_profile.is_realm_admin state['user_id'] = user_profile.id state['enter_sends'] = user_profile.enter_sends state['email'] = user_profile.email state['full_name'] = user_profile.full_name if want('realm_bot'): state['realm_bots'] = get_owned_bot_dicts(user_profile) if want('subscription'): subscriptions, unsubscribed, never_subscribed = gather_subscriptions_helper( user_profile, include_subscribers=include_subscribers) state['subscriptions'] = subscriptions state['unsubscribed'] = unsubscribed state['never_subscribed'] = never_subscribed if want('update_message_flags') and want('message'): # Keeping unread_msgs updated requires both message flag updates and # message updates. This is due to the fact that new messages will not # generate a flag update so we need to use the flags field in the # message event. state['unread_msgs'] = get_unread_message_ids_per_recipient( user_profile) if want('stream'): state['streams'] = do_get_streams(user_profile) if want('default_streams'): state['realm_default_streams'] = streams_to_dicts_sorted( get_default_streams_for_realm(user_profile.realm)) if want('update_display_settings'): for prop in UserProfile.property_types: state[prop] = getattr(user_profile, prop) state['emojiset_choices'] = user_profile.emojiset_choices() state['autoscroll_forever'] = user_profile.autoscroll_forever if want('update_global_notifications'): for notification in UserProfile.notification_setting_types: state[notification] = getattr(user_profile, notification) state[ 'default_desktop_notifications'] = user_profile.default_desktop_notifications if want('zulip_version'): state['zulip_version'] = ZULIP_VERSION return state
def fetch_initial_state_data(user_profile: UserProfile, event_types: Optional[Iterable[str]], queue_id: str, client_gravatar: bool, include_subscribers: bool = True) -> Dict[str, Any]: state = {'queue_id': queue_id} # type: Dict[str, Any] realm = user_profile.realm if event_types is None: # return True always want = always_want # type: Callable[[str], bool] else: want = set(event_types).__contains__ if want('alert_words'): state['alert_words'] = user_alert_words(user_profile) if want('custom_profile_fields'): fields = custom_profile_fields_for_realm(realm.id) state['custom_profile_fields'] = [f.as_dict() for f in fields] state['custom_profile_field_types'] = CustomProfileField.FIELD_TYPE_CHOICES_DICT if want('hotspots'): state['hotspots'] = get_next_hotspots(user_profile) if want('message'): # The client should use get_messages() to fetch messages # starting with the max_message_id. They will get messages # newer than that ID via get_events() messages = Message.objects.filter(usermessage__user_profile=user_profile).order_by('-id')[:1] if messages: state['max_message_id'] = messages[0].id else: state['max_message_id'] = -1 if want('muted_topics'): state['muted_topics'] = get_topic_mutes(user_profile) if want('pointer'): state['pointer'] = user_profile.pointer if want('presence'): state['presences'] = get_status_dict(user_profile) if want('realm'): for property_name in Realm.property_types: state['realm_' + property_name] = getattr(realm, property_name) # Most state is handled via the property_types framework; # these manual entries are for those realm settings that don't # fit into that framework. state['realm_authentication_methods'] = realm.authentication_methods_dict() state['realm_allow_message_editing'] = realm.allow_message_editing state['realm_allow_community_topic_editing'] = realm.allow_community_topic_editing state['realm_allow_message_deleting'] = realm.allow_message_deleting state['realm_message_content_edit_limit_seconds'] = realm.message_content_edit_limit_seconds state['realm_message_content_delete_limit_seconds'] = realm.message_content_delete_limit_seconds state['realm_icon_url'] = realm_icon_url(realm) state['realm_icon_source'] = realm.icon_source state['max_icon_file_size'] = settings.MAX_ICON_FILE_SIZE state['realm_logo_url'] = realm_logo_url(realm) state['realm_logo_source'] = realm.logo_source state['max_logo_file_size'] = settings.MAX_LOGO_FILE_SIZE state['realm_bot_domain'] = realm.get_bot_domain() state['realm_uri'] = realm.uri state['realm_available_video_chat_providers'] = realm.VIDEO_CHAT_PROVIDERS state['realm_presence_disabled'] = realm.presence_disabled state['realm_digest_emails_enabled'] = realm.digest_emails_enabled and settings.SEND_DIGEST_EMAILS state['realm_is_zephyr_mirror_realm'] = realm.is_zephyr_mirror_realm state['realm_email_auth_enabled'] = email_auth_enabled(realm) state['realm_password_auth_enabled'] = password_auth_enabled(realm) state['realm_push_notifications_enabled'] = push_notifications_enabled() if realm.notifications_stream and not realm.notifications_stream.deactivated: notifications_stream = realm.notifications_stream state['realm_notifications_stream_id'] = notifications_stream.id else: state['realm_notifications_stream_id'] = -1 signup_notifications_stream = realm.get_signup_notifications_stream() if signup_notifications_stream: state['realm_signup_notifications_stream_id'] = signup_notifications_stream.id else: state['realm_signup_notifications_stream_id'] = -1 if want('realm_domains'): state['realm_domains'] = get_realm_domains(realm) if want('realm_emoji'): state['realm_emoji'] = realm.get_emoji() if want('realm_filters'): state['realm_filters'] = realm_filters_for_realm(realm.id) if want('realm_user_groups'): state['realm_user_groups'] = user_groups_in_realm_serialized(realm) if want('realm_user'): state['raw_users'] = get_raw_user_data( realm_id=realm.id, client_gravatar=client_gravatar, ) # For the user's own avatar URL, we force # client_gravatar=False, since that saves some unnecessary # client-side code for handing medium-size avatars. See #8253 # for details. state['avatar_source'] = user_profile.avatar_source state['avatar_url_medium'] = avatar_url( user_profile, medium=True, client_gravatar=False, ) state['avatar_url'] = avatar_url( user_profile, medium=False, client_gravatar=False, ) state['can_create_streams'] = user_profile.can_create_streams() state['can_subscribe_other_users'] = user_profile.can_subscribe_other_users() state['cross_realm_bots'] = list(get_cross_realm_dicts()) state['is_admin'] = user_profile.is_realm_admin state['is_guest'] = user_profile.is_guest state['user_id'] = user_profile.id state['enter_sends'] = user_profile.enter_sends state['email'] = user_profile.email state['delivery_email'] = user_profile.delivery_email state['full_name'] = user_profile.full_name if want('realm_bot'): state['realm_bots'] = get_owned_bot_dicts(user_profile) # This does not yet have an apply_event counterpart, since currently, # new entries for EMBEDDED_BOTS can only be added directly in the codebase. if want('realm_embedded_bots'): realm_embedded_bots = [] for bot in EMBEDDED_BOTS: realm_embedded_bots.append({'name': bot.name, 'config': load_bot_config_template(bot.name)}) state['realm_embedded_bots'] = realm_embedded_bots if want('subscription'): subscriptions, unsubscribed, never_subscribed = gather_subscriptions_helper( user_profile, include_subscribers=include_subscribers) state['subscriptions'] = subscriptions state['unsubscribed'] = unsubscribed state['never_subscribed'] = never_subscribed if want('update_message_flags') and want('message'): # Keeping unread_msgs updated requires both message flag updates and # message updates. This is due to the fact that new messages will not # generate a flag update so we need to use the flags field in the # message event. state['raw_unread_msgs'] = get_raw_unread_data(user_profile) if want('starred_messages'): state['starred_messages'] = get_starred_message_ids(user_profile) if want('stream'): state['streams'] = do_get_streams(user_profile) state['stream_name_max_length'] = Stream.MAX_NAME_LENGTH state['stream_description_max_length'] = Stream.MAX_DESCRIPTION_LENGTH if want('default_streams'): state['realm_default_streams'] = streams_to_dicts_sorted( get_default_streams_for_realm(realm.id)) if want('default_stream_groups'): state['realm_default_stream_groups'] = default_stream_groups_to_dicts_sorted( get_default_stream_groups(realm)) if want('update_display_settings'): for prop in UserProfile.property_types: state[prop] = getattr(user_profile, prop) state['emojiset_choices'] = user_profile.emojiset_choices() if want('update_global_notifications'): for notification in UserProfile.notification_setting_types: state[notification] = getattr(user_profile, notification) state['available_notification_sounds'] = get_available_notification_sounds() if want('user_status'): state['away_user_ids'] = sorted(list(get_away_user_ids(realm_id=realm.id))) if want('zulip_version'): state['zulip_version'] = ZULIP_VERSION return state
def zulip_default_context(request): # type: (HttpRequest) -> Dict[str, Any] """Context available to all Zulip Jinja2 templates that have a request passed in. Designed to provide the long list of variables at the bottom of this function in a wide range of situations: logged-in or logged-out, subdomains or not, etc. The main variable in the below is whether we know what realm the user is trying to interact with. """ realm = get_realm_from_request(request) if realm is None: realm_uri = settings.ROOT_DOMAIN_URI realm_name = None realm_icon = None realm_description = None realm_invite_required = False else: realm_uri = realm.uri realm_name = realm.name realm_icon = get_realm_icon_url(realm) realm_description_raw = realm.description or "The coolest place in the universe." realm_description = convert(realm_description_raw, message_realm=realm) realm_invite_required = realm.invite_required register_link_disabled = settings.REGISTER_LINK_DISABLED login_link_disabled = settings.LOGIN_LINK_DISABLED about_link_disabled = settings.ABOUT_LINK_DISABLED find_team_link_disabled = settings.FIND_TEAM_LINK_DISABLED if settings.ROOT_DOMAIN_LANDING_PAGE and get_subdomain(request) == "": register_link_disabled = True login_link_disabled = True about_link_disabled = True find_team_link_disabled = False apps_page_url = 'https://zulipchat.com/apps/' if settings.ZILENCER_ENABLED: apps_page_url = '/apps/' user_is_authenticated = False if hasattr(request, 'user') and hasattr(request.user, 'is_authenticated'): user_is_authenticated = request.user.is_authenticated.value if settings.DEVELOPMENT: secrets_path = "zproject/dev-secrets.conf" settings_path = "zproject/dev_settings.py" settings_comments_path = "zproject/prod_settings_template.py" else: secrets_path = "/etc/zulip/zulip-secrets.conf" settings_path = "/etc/zulip/settings.py" settings_comments_path = "/etc/zulip/settings.py" if hasattr(request, "client") and request.client.name == "ZulipElectron": platform = "ZulipElectron" # nocoverage else: platform = "ZulipWeb" return { 'root_domain_landing_page': settings.ROOT_DOMAIN_LANDING_PAGE, 'custom_logo_url': settings.CUSTOM_LOGO_URL, 'register_link_disabled': register_link_disabled, 'login_link_disabled': login_link_disabled, 'about_link_disabled': about_link_disabled, 'terms_of_service': settings.TERMS_OF_SERVICE, 'privacy_policy': settings.PRIVACY_POLICY, 'login_url': settings.HOME_NOT_LOGGED_IN, 'only_sso': settings.ONLY_SSO, 'external_api_path': settings.EXTERNAL_API_PATH, 'external_api_uri': settings.EXTERNAL_API_URI, 'external_host': settings.EXTERNAL_HOST, 'external_uri_scheme': settings.EXTERNAL_URI_SCHEME, 'realm_invite_required': realm_invite_required, 'realm_uri': realm_uri, 'realm_name': realm_name, 'realm_icon': realm_icon, 'realm_description': realm_description, 'root_domain_uri': settings.ROOT_DOMAIN_URI, 'api_site_required': settings.EXTERNAL_API_PATH != "api.zulip.com", 'email_gateway_example': settings.EMAIL_GATEWAY_EXAMPLE, 'apps_page_url': apps_page_url, 'open_realm_creation': settings.OPEN_REALM_CREATION, 'password_auth_enabled': password_auth_enabled(realm), 'dev_auth_enabled': dev_auth_enabled(realm), 'google_auth_enabled': google_auth_enabled(realm), 'github_auth_enabled': github_auth_enabled(realm), 'email_auth_enabled': email_auth_enabled(realm), 'require_email_format_usernames': require_email_format_usernames(realm), 'any_oauth_backend_enabled': any_oauth_backend_enabled(realm), 'no_auth_enabled': not auth_enabled_helper(list(AUTH_BACKEND_NAME_MAP.keys()), realm), 'development_environment': settings.DEVELOPMENT, 'support_email': FromAddress.SUPPORT, 'find_team_link_disabled': find_team_link_disabled, 'password_min_length': settings.PASSWORD_MIN_LENGTH, 'password_min_guesses': settings.PASSWORD_MIN_GUESSES, 'zulip_version': ZULIP_VERSION, 'user_is_authenticated': user_is_authenticated, 'settings_path': settings_path, 'secrets_path': secrets_path, 'settings_comments_path': settings_comments_path, 'platform': platform, }
def accounts_register(request: HttpRequest) -> HttpResponse: key = request.POST['key'] confirmation = Confirmation.objects.get(confirmation_key=key) prereg_user = confirmation.content_object email = prereg_user.email realm_creation = prereg_user.realm_creation password_required = prereg_user.password_required is_realm_admin = prereg_user.invited_as == PreregistrationUser.INVITE_AS[ 'REALM_ADMIN'] or realm_creation is_guest = prereg_user.invited_as == PreregistrationUser.INVITE_AS[ 'GUEST_USER'] try: validators.validate_email(email) except ValidationError: return render(request, "zerver/invalid_email.html", context={"invalid_email": True}) if realm_creation: # For creating a new realm, there is no existing realm or domain realm = None else: if get_subdomain(request) != prereg_user.realm.string_id: return render_confirmation_key_error( request, ConfirmationKeyException( ConfirmationKeyException.DOES_NOT_EXIST)) realm = prereg_user.realm try: email_allowed_for_realm(email, realm) except DomainNotAllowedForRealmError: return render(request, "zerver/invalid_email.html", context={ "realm_name": realm.name, "closed_domain": True }) except DisposableEmailError: return render(request, "zerver/invalid_email.html", context={ "realm_name": realm.name, "disposable_emails_not_allowed": True }) except EmailContainsPlusError: return render(request, "zerver/invalid_email.html", context={ "realm_name": realm.name, "email_contains_plus": True }) if realm.deactivated: # The user is trying to register for a deactivated realm. Advise them to # contact support. return redirect_to_deactivation_notice() try: validate_email_for_realm(realm, email) except ValidationError: return HttpResponseRedirect( reverse('django.contrib.auth.views.login') + '?email=' + urllib.parse.quote_plus(email)) name_validated = False full_name = None require_ldap_password = False if request.POST.get('from_confirmation'): try: del request.session['authenticated_full_name'] except KeyError: pass ldap_full_name = None if settings.POPULATE_PROFILE_VIA_LDAP: # If the user can be found in LDAP, we'll take the full name from the directory, # and further down create a form pre-filled with it. for backend in get_backends(): if isinstance(backend, LDAPBackend): try: ldap_username = backend.django_to_ldap_username(email) except ZulipLDAPExceptionNoMatchingLDAPUser: logging.warning( "New account email %s could not be found in LDAP" % (email, )) break # Note that this `ldap_user` object is not a # `ZulipLDAPUser` with a `Realm` attached, so # calling `.populate_user()` on it will crash. # This is OK, since we're just accessing this user # to extract its name. # # TODO: We should potentially be accessing this # user to sync its initial avatar and custom # profile fields as well, if we indeed end up # creating a user account through this flow, # rather than waiting until `manage.py # sync_ldap_user_data` runs to populate it. ldap_user = _LDAPUser(backend, ldap_username) try: ldap_full_name, _ = backend.get_mapped_name(ldap_user) except TypeError: break # Check whether this is ZulipLDAPAuthBackend, # which is responsible for authentication and # requires that LDAP accounts enter their LDAP # password to register, or ZulipLDAPUserPopulator, # which just populates UserProfile fields (no auth). require_ldap_password = isinstance(backend, ZulipLDAPAuthBackend) break if ldap_full_name: # We don't use initial= here, because if the form is # complete (that is, no additional fields need to be # filled out by the user) we want the form to validate, # so they can be directly registered without having to # go through this interstitial. form = RegistrationForm({'full_name': ldap_full_name}, realm_creation=realm_creation) request.session['authenticated_full_name'] = ldap_full_name name_validated = True elif realm is not None and realm.is_zephyr_mirror_realm: # For MIT users, we can get an authoritative name from Hesiod. # Technically we should check that this is actually an MIT # realm, but we can cross that bridge if we ever get a non-MIT # zephyr mirroring realm. hesiod_name = compute_mit_user_fullname(email) form = RegistrationForm(initial={ 'full_name': hesiod_name if "@" not in hesiod_name else "" }, realm_creation=realm_creation) name_validated = True elif prereg_user.full_name: if prereg_user.full_name_validated: request.session[ 'authenticated_full_name'] = prereg_user.full_name name_validated = True form = RegistrationForm({'full_name': prereg_user.full_name}, realm_creation=realm_creation) else: form = RegistrationForm( initial={'full_name': prereg_user.full_name}, realm_creation=realm_creation) elif 'full_name' in request.POST: form = RegistrationForm( initial={'full_name': request.POST.get('full_name')}, realm_creation=realm_creation) else: form = RegistrationForm(realm_creation=realm_creation) else: postdata = request.POST.copy() if name_changes_disabled(realm): # If we populate profile information via LDAP and we have a # verified name from you on file, use that. Otherwise, fall # back to the full name in the request. try: postdata.update( {'full_name': request.session['authenticated_full_name']}) name_validated = True except KeyError: pass form = RegistrationForm(postdata, realm_creation=realm_creation) if not (password_auth_enabled(realm) and password_required): form['password'].field.required = False if form.is_valid(): if password_auth_enabled(realm) and form['password'].field.required: password = form.cleaned_data['password'] else: # If the user wasn't prompted for a password when # completing the authentication form (because they're # signing up with SSO and no password is required), set # the password field to `None` (Which causes Django to # create an unusable password). password = None if realm_creation: string_id = form.cleaned_data['realm_subdomain'] realm_name = form.cleaned_data['realm_name'] realm = do_create_realm(string_id, realm_name) setup_realm_internal_bots(realm) assert (realm is not None) full_name = form.cleaned_data['full_name'] short_name = email_to_username(email) default_stream_group_names = request.POST.getlist( 'default_stream_group') default_stream_groups = lookup_default_stream_groups( default_stream_group_names, realm) timezone = "" if 'timezone' in request.POST and request.POST[ 'timezone'] in get_all_timezones(): timezone = request.POST['timezone'] if 'source_realm' in request.POST and request.POST[ "source_realm"] != "on": source_profile = get_source_profile(email, request.POST["source_realm"]) else: source_profile = None if not realm_creation: try: existing_user_profile = get_user_by_delivery_email( email, realm) # type: Optional[UserProfile] except UserProfile.DoesNotExist: existing_user_profile = None else: existing_user_profile = None user_profile = None # type: Optional[UserProfile] return_data = {} # type: Dict[str, bool] if ldap_auth_enabled(realm): # If the user was authenticated using an external SSO # mechanism like Google or GitHub auth, then authentication # will have already been done before creating the # PreregistrationUser object with password_required=False, and # so we don't need to worry about passwords. # # If instead the realm is using EmailAuthBackend, we will # set their password above. # # But if the realm is using LDAPAuthBackend, we need to verify # their LDAP password (which will, as a side effect, create # the user account) here using authenticate. # pregeg_user.realm_creation carries the information about whether # we're in realm creation mode, and the ldap flow will handle # that and create the user with the appropriate parameters. user_profile = authenticate(request, username=email, password=password, realm=realm, prereg_user=prereg_user, return_data=return_data) if user_profile is None: can_use_different_backend = email_auth_enabled( realm) or any_social_backend_enabled(realm) if settings.LDAP_APPEND_DOMAIN: # In LDAP_APPEND_DOMAIN configurations, we don't allow making a non-ldap account # if the email matches the ldap domain. can_use_different_backend = can_use_different_backend and ( not email_belongs_to_ldap(realm, email)) if return_data.get( "no_matching_ldap_user") and can_use_different_backend: # If both the LDAP and Email or Social auth backends are # enabled, and there's no matching user in the LDAP # directory then the intent is to create a user in the # realm with their email outside the LDAP organization # (with e.g. a password stored in the Zulip database, # not LDAP). So we fall through and create the new # account. pass else: # TODO: This probably isn't going to give a # user-friendly error message, but it doesn't # particularly matter, because the registration form # is hidden for most users. return HttpResponseRedirect( reverse('django.contrib.auth.views.login') + '?email=' + urllib.parse.quote_plus(email)) elif not realm_creation: # Since we'll have created a user, we now just log them in. return login_and_go_to_home(request, user_profile) else: # With realm_creation=True, we're going to return further down, # after finishing up the creation process. pass if existing_user_profile is not None and existing_user_profile.is_mirror_dummy: user_profile = existing_user_profile do_activate_user(user_profile) do_change_password(user_profile, password) do_change_full_name(user_profile, full_name, user_profile) do_set_user_display_setting(user_profile, 'timezone', timezone) # TODO: When we clean up the `do_activate_user` code path, # make it respect invited_as_admin / is_realm_admin. if user_profile is None: user_profile = do_create_user( email, password, realm, full_name, short_name, prereg_user=prereg_user, is_realm_admin=is_realm_admin, is_guest=is_guest, tos_version=settings.TOS_VERSION, timezone=timezone, newsletter_data={"IP": request.META['REMOTE_ADDR']}, default_stream_groups=default_stream_groups, source_profile=source_profile, realm_creation=realm_creation) if realm_creation: bulk_add_subscriptions([realm.signup_notifications_stream], [user_profile]) send_initial_realm_messages(realm) # Because for realm creation, registration happens on the # root domain, we need to log them into the subdomain for # their new realm. return redirect_and_log_into_subdomain(realm, full_name, email) # This dummy_backend check below confirms the user is # authenticating to the correct subdomain. auth_result = authenticate(username=user_profile.delivery_email, realm=realm, return_data=return_data, use_dummy_backend=True) if return_data.get('invalid_subdomain'): # By construction, this should never happen. logging.error("Subdomain mismatch in registration %s: %s" % ( realm.subdomain, user_profile.delivery_email, )) return redirect('/') return login_and_go_to_home(request, auth_result) return render( request, 'zerver/register.html', context={ 'form': form, 'email': email, 'key': key, 'full_name': request.session.get('authenticated_full_name', None), 'lock_name': name_validated and name_changes_disabled(realm), # password_auth_enabled is normally set via our context processor, # but for the registration form, there is no logged in user yet, so # we have to set it here. 'creating_new_team': realm_creation, 'password_required': password_auth_enabled(realm) and password_required, 'require_ldap_password': require_ldap_password, 'password_auth_enabled': password_auth_enabled(realm), 'root_domain_available': is_root_domain_available(), 'default_stream_groups': get_default_stream_groups(realm), 'accounts': get_accounts_for_email(email), 'MAX_REALM_NAME_LENGTH': str(Realm.MAX_REALM_NAME_LENGTH), 'MAX_NAME_LENGTH': str(UserProfile.MAX_NAME_LENGTH), 'MAX_PASSWORD_LENGTH': str(form.MAX_PASSWORD_LENGTH), 'MAX_REALM_SUBDOMAIN_LENGTH': str(Realm.MAX_REALM_SUBDOMAIN_LENGTH) })
def home(request): # type: (HttpRequest) -> HttpResponse # 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 # session alive. request.session.modified = True user_profile = request.user request._email = request.user.email request.client = get_client("website") # If a user hasn't signed the current Terms of Service, send them there if settings.TERMS_OF_SERVICE is not None and settings.TOS_VERSION is not None and \ int(settings.TOS_VERSION.split('.')[0]) > user_profile.major_tos_version(): return accounts_accept_terms(request) narrow = [] # type: List[List[text_type]] narrow_stream = None narrow_topic = request.GET.get("topic") if request.GET.get("stream"): try: narrow_stream = get_stream(request.GET.get("stream"), user_profile.realm) assert(narrow_stream is not None) assert(narrow_stream.is_public()) narrow = [["stream", narrow_stream.name]] except Exception: logging.exception("Narrow parsing") if narrow_topic is not None: narrow.append(["topic", narrow_topic]) register_ret = do_events_register(user_profile, request.client, apply_markdown=True, narrow=narrow) user_has_messages = (register_ret['max_message_id'] != -1) # Reset our don't-spam-users-with-email counter since the # user has since logged in if not user_profile.last_reminder is None: user_profile.last_reminder = None user_profile.save(update_fields=["last_reminder"]) # Brand new users get the tutorial needs_tutorial = settings.TUTORIAL_ENABLED and \ user_profile.tutorial_status != UserProfile.TUTORIAL_FINISHED first_in_realm = realm_user_count(user_profile.realm) == 1 # If you are the only person in the realm and you didn't invite # anyone, we'll continue to encourage you to do so on the frontend. prompt_for_invites = first_in_realm and \ not PreregistrationUser.objects.filter(referred_by=user_profile).count() if user_profile.pointer == -1 and user_has_messages: # Put the new user's pointer at the bottom # # This improves performance, because we limit backfilling of messages # before the pointer. It's also likely that someone joining an # organization is interested in recent messages more than the very # first messages on the system. register_ret['pointer'] = register_ret['max_message_id'] user_profile.last_pointer_updater = request.session.session_key if user_profile.pointer == -1: latest_read = None else: try: latest_read = UserMessage.objects.get(user_profile=user_profile, message__id=user_profile.pointer) except UserMessage.DoesNotExist: # Don't completely fail if your saved pointer ID is invalid logging.warning("%s has invalid pointer %s" % (user_profile.email, user_profile.pointer)) latest_read = None desktop_notifications_enabled = user_profile.enable_desktop_notifications if narrow_stream is not None: desktop_notifications_enabled = False if user_profile.realm.notifications_stream: notifications_stream = user_profile.realm.notifications_stream.name else: notifications_stream = "" # Set default language and make it persist default_language = register_ret['default_language'] url_lang = '/{}'.format(request.LANGUAGE_CODE) if not request.path.startswith(url_lang): translation.activate(default_language) request.session[translation.LANGUAGE_SESSION_KEY] = default_language # Pass parameters to the client-side JavaScript code. # These end up in a global JavaScript Object named 'page_params'. page_params = dict( zulip_version = ZULIP_VERSION, share_the_love = settings.SHARE_THE_LOVE, development_environment = settings.DEVELOPMENT, debug_mode = settings.DEBUG, test_suite = settings.TEST_SUITE, poll_timeout = settings.POLL_TIMEOUT, login_page = settings.HOME_NOT_LOGGED_IN, server_uri = settings.SERVER_URI, realm_uri = user_profile.realm.uri, maxfilesize = settings.MAX_FILE_UPLOAD_SIZE, server_generation = settings.SERVER_GENERATION, password_auth_enabled = password_auth_enabled(user_profile.realm), have_initial_messages = user_has_messages, subbed_info = register_ret['subscriptions'], unsubbed_info = register_ret['unsubscribed'], neversubbed_info = register_ret['never_subscribed'], email_dict = register_ret['email_dict'], people_list = register_ret['realm_users'], bot_list = register_ret['realm_bots'], initial_pointer = register_ret['pointer'], initial_presences = register_ret['presences'], initial_servertime = time.time(), # Used for calculating relative presence age fullname = user_profile.full_name, email = user_profile.email, domain = user_profile.realm.domain, domains = list_of_domains_for_realm(user_profile.realm), realm_name = register_ret['realm_name'], realm_invite_required = register_ret['realm_invite_required'], realm_invite_by_admins_only = register_ret['realm_invite_by_admins_only'], realm_create_stream_by_admins_only = register_ret['realm_create_stream_by_admins_only'], realm_allow_message_editing = register_ret['realm_allow_message_editing'], realm_message_content_edit_limit_seconds = register_ret['realm_message_content_edit_limit_seconds'], realm_restricted_to_domain = register_ret['realm_restricted_to_domain'], realm_default_language = register_ret['realm_default_language'], enter_sends = user_profile.enter_sends, user_id = user_profile.id, left_side_userlist = register_ret['left_side_userlist'], default_language = register_ret['default_language'], default_language_name = get_language_name(register_ret['default_language']), language_list_dbl_col = get_language_list_for_templates(register_ret['default_language']), language_list = get_language_list(), referrals = register_ret['referrals'], realm_emoji = register_ret['realm_emoji'], needs_tutorial = needs_tutorial, first_in_realm = first_in_realm, prompt_for_invites = prompt_for_invites, notifications_stream = notifications_stream, cross_realm_user_emails = list(get_cross_realm_users()), # Stream message notification settings: stream_desktop_notifications_enabled = user_profile.enable_stream_desktop_notifications, stream_sounds_enabled = user_profile.enable_stream_sounds, # Private message and @-mention notification settings: desktop_notifications_enabled = desktop_notifications_enabled, sounds_enabled = user_profile.enable_sounds, enable_offline_email_notifications = user_profile.enable_offline_email_notifications, enable_offline_push_notifications = user_profile.enable_offline_push_notifications, enable_online_push_notifications = user_profile.enable_online_push_notifications, twenty_four_hour_time = register_ret['twenty_four_hour_time'], enable_digest_emails = user_profile.enable_digest_emails, event_queue_id = register_ret['queue_id'], last_event_id = register_ret['last_event_id'], max_message_id = register_ret['max_message_id'], unread_count = approximate_unread_count(user_profile), furthest_read_time = sent_time_in_epoch_seconds(latest_read), save_stacktraces = settings.SAVE_FRONTEND_STACKTRACES, alert_words = register_ret['alert_words'], muted_topics = register_ret['muted_topics'], realm_filters = register_ret['realm_filters'], realm_default_streams = register_ret['realm_default_streams'], is_admin = user_profile.is_realm_admin, can_create_streams = user_profile.can_create_streams(), name_changes_disabled = name_changes_disabled(user_profile.realm), has_mobile_devices = num_push_devices_for_user(user_profile) > 0, autoscroll_forever = user_profile.autoscroll_forever, default_desktop_notifications = user_profile.default_desktop_notifications, avatar_url = avatar_url(user_profile), avatar_url_medium = avatar_url(user_profile, medium=True), mandatory_topics = user_profile.realm.mandatory_topics, show_digest_email = user_profile.realm.show_digest_email, presence_disabled = user_profile.realm.presence_disabled, is_zephyr_mirror_realm = user_profile.realm.is_zephyr_mirror_realm, ) if narrow_stream is not None: # In narrow_stream context, initial pointer is just latest message recipient = get_recipient(Recipient.STREAM, narrow_stream.id) try: initial_pointer = Message.objects.filter(recipient=recipient).order_by('id').reverse()[0].id except IndexError: initial_pointer = -1 page_params["narrow_stream"] = narrow_stream.name if narrow_topic is not None: page_params["narrow_topic"] = narrow_topic page_params["narrow"] = [dict(operator=term[0], operand=term[1]) for term in narrow] page_params["max_message_id"] = initial_pointer page_params["initial_pointer"] = initial_pointer page_params["have_initial_messages"] = (initial_pointer != -1) statsd.incr('views.home') show_invites = True # Some realms only allow admins to invite users if user_profile.realm.invite_by_admins_only and not user_profile.is_realm_admin: show_invites = False product_name = "Zulip" page_params['product_name'] = product_name request._log_data['extra'] = "[%s]" % (register_ret["queue_id"],) response = render_to_response('zerver/index.html', {'user_profile': user_profile, 'page_params' : simplejson.encoder.JSONEncoderForHTML().encode(page_params), 'nofontface': is_buggy_ua(request.META.get("HTTP_USER_AGENT", "Unspecified")), 'avatar_url': avatar_url(user_profile), 'show_debug': settings.DEBUG and ('show_debug' in request.GET), 'pipeline': settings.PIPELINE_ENABLED, 'show_invites': show_invites, 'is_admin': user_profile.is_realm_admin, 'show_webathena': user_profile.realm.webathena_enabled, 'enable_feedback': settings.ENABLE_FEEDBACK, 'embedded': narrow_stream is not None, 'product_name': product_name }, request=request) patch_cache_control(response, no_cache=True, no_store=True, must_revalidate=True) return response
def zulip_default_context(request: HttpRequest) -> Dict[str, Any]: """Context available to all Zulip Jinja2 templates that have a request passed in. Designed to provide the long list of variables at the bottom of this function in a wide range of situations: logged-in or logged-out, subdomains or not, etc. The main variable in the below is whether we know what realm the user is trying to interact with. """ realm = get_realm_from_request(request) if realm is None: realm_uri = settings.ROOT_DOMAIN_URI realm_name = None realm_icon = None realm_logo = None realm_description = None realm_invite_required = False realm_plan_type = 0 else: realm_uri = realm.uri realm_name = realm.name realm_icon = get_realm_icon_url(realm) realm_logo = get_realm_logo_url(realm) realm_description_raw = realm.description or "The coolest place in the universe." realm_description = bugdown_convert(realm_description_raw, message_realm=realm) realm_invite_required = realm.invite_required realm_plan_type = realm.plan_type register_link_disabled = settings.REGISTER_LINK_DISABLED login_link_disabled = settings.LOGIN_LINK_DISABLED find_team_link_disabled = settings.FIND_TEAM_LINK_DISABLED allow_search_engine_indexing = False if (settings.ROOT_DOMAIN_LANDING_PAGE and get_subdomain(request) == Realm.SUBDOMAIN_FOR_ROOT_DOMAIN): register_link_disabled = True login_link_disabled = True find_team_link_disabled = False allow_search_engine_indexing = True apps_page_url = 'https://zulipchat.com/apps/' if settings.ZILENCER_ENABLED: apps_page_url = '/apps/' user_is_authenticated = False if hasattr(request, 'user') and hasattr(request.user, 'is_authenticated'): user_is_authenticated = request.user.is_authenticated.value if settings.DEVELOPMENT: secrets_path = "zproject/dev-secrets.conf" settings_path = "zproject/dev_settings.py" settings_comments_path = "zproject/prod_settings_template.py" else: secrets_path = "/etc/zulip/zulip-secrets.conf" settings_path = "/etc/zulip/settings.py" settings_comments_path = "/etc/zulip/settings.py" if hasattr(request, "client") and request.client.name == "ZulipElectron": platform = "ZulipElectron" # nocoverage else: platform = "ZulipWeb" context = { 'root_domain_landing_page': settings.ROOT_DOMAIN_LANDING_PAGE, 'custom_logo_url': settings.CUSTOM_LOGO_URL, 'register_link_disabled': register_link_disabled, 'login_link_disabled': login_link_disabled, 'terms_of_service': settings.TERMS_OF_SERVICE, 'privacy_policy': settings.PRIVACY_POLICY, 'login_url': settings.HOME_NOT_LOGGED_IN, 'only_sso': settings.ONLY_SSO, 'external_host': settings.EXTERNAL_HOST, 'external_uri_scheme': settings.EXTERNAL_URI_SCHEME, 'realm_invite_required': realm_invite_required, 'realm_uri': realm_uri, 'realm_name': realm_name, 'realm_icon': realm_icon, 'realm_logo': realm_logo, 'realm_description': realm_description, 'realm_plan_type': realm_plan_type, 'root_domain_uri': settings.ROOT_DOMAIN_URI, 'apps_page_url': apps_page_url, 'open_realm_creation': settings.OPEN_REALM_CREATION, 'password_auth_enabled': password_auth_enabled(realm), 'require_email_format_usernames': require_email_format_usernames(realm), 'any_oauth_backend_enabled': any_oauth_backend_enabled(realm), 'no_auth_enabled': not auth_enabled_helper(list(AUTH_BACKEND_NAME_MAP.keys()), realm), 'development_environment': settings.DEVELOPMENT, 'support_email': FromAddress.SUPPORT, 'find_team_link_disabled': find_team_link_disabled, 'password_min_length': settings.PASSWORD_MIN_LENGTH, 'password_min_guesses': settings.PASSWORD_MIN_GUESSES, 'jitsi_server_url': settings.JITSI_SERVER_URL, 'two_factor_authentication_enabled': settings.TWO_FACTOR_AUTHENTICATION_ENABLED, 'zulip_version': ZULIP_VERSION, 'latest_release_version': LATEST_RELEASE_VERSION, 'latest_major_version': LATEST_MAJOR_VERSION, 'latest_release_announcement': LATEST_RELEASE_ANNOUNCEMENT, 'user_is_authenticated': user_is_authenticated, 'settings_path': settings_path, 'secrets_path': secrets_path, 'settings_comments_path': settings_comments_path, 'platform': platform, 'allow_search_engine_indexing': allow_search_engine_indexing, } # Add the keys for our standard authentication backends. for auth_backend_name in AUTH_BACKEND_NAME_MAP: name_lower = auth_backend_name.lower() key = "%s_auth_enabled" % (name_lower, ) context[key] = auth_enabled_helper([auth_backend_name], realm) return context
def zulip_default_context(request): # type: (HttpRequest) -> Dict[str, Any] """Context available to all Zulip Jinja2 templates that have a request passed in. Designed to provide the long list of variables at the bottom of this function in a wide range of situations: logged-in or logged-out, subdomains or not, etc. The main variable in the below is whether we know the realm, which is the case if there is only one realm, or we're on a REALMS_HAVE_SUBDOMAINS subdomain, or the user is logged in. """ realm = get_realm_from_request(request) if realm is not None: realm_uri = realm.uri realm_name = realm.name realm_icon = get_realm_icon_url(realm) realm_description_raw = realm.description or "The coolest place in the universe." realm_description = convert(realm_description_raw, message_realm=realm) else: realm_uri = settings.SERVER_URI realm_name = None realm_icon = None realm_description = None register_link_disabled = settings.REGISTER_LINK_DISABLED login_link_disabled = settings.LOGIN_LINK_DISABLED about_link_disabled = settings.ABOUT_LINK_DISABLED find_team_link_disabled = settings.FIND_TEAM_LINK_DISABLED if settings.SUBDOMAINS_HOMEPAGE and get_subdomain(request) == "": register_link_disabled = True login_link_disabled = True about_link_disabled = True find_team_link_disabled = False apps_page_url = 'https://zulipchat.com/apps/' if settings.ZILENCER_ENABLED: apps_page_url = '/apps/' return { 'realms_have_subdomains': settings.REALMS_HAVE_SUBDOMAINS, 'custom_logo_url': settings.CUSTOM_LOGO_URL, 'register_link_disabled': register_link_disabled, 'login_link_disabled': login_link_disabled, 'about_link_disabled': about_link_disabled, 'terms_of_service': settings.TERMS_OF_SERVICE, 'privacy_policy': settings.PRIVACY_POLICY, 'login_url': settings.HOME_NOT_LOGGED_IN, 'only_sso': settings.ONLY_SSO, 'external_api_path': settings.EXTERNAL_API_PATH, 'external_api_uri': settings.EXTERNAL_API_URI, 'external_host': settings.EXTERNAL_HOST, 'external_uri_scheme': settings.EXTERNAL_URI_SCHEME, 'realm_uri': realm_uri, 'realm_name': realm_name, 'realm_icon': realm_icon, 'realm_description': realm_description, 'server_uri': settings.SERVER_URI, 'api_site_required': settings.EXTERNAL_API_PATH != "api.zulip.com", 'email_gateway_example': settings.EMAIL_GATEWAY_EXAMPLE, 'apps_page_url': apps_page_url, 'open_realm_creation': settings.OPEN_REALM_CREATION, 'password_auth_enabled': password_auth_enabled(realm), 'dev_auth_enabled': dev_auth_enabled(realm), 'google_auth_enabled': google_auth_enabled(realm), 'github_auth_enabled': github_auth_enabled(realm), 'any_oauth_backend_enabled': any_oauth_backend_enabled(realm), 'no_auth_enabled': not auth_enabled_helper(list(AUTH_BACKEND_NAME_MAP.keys()), realm), 'development_environment': settings.DEVELOPMENT, 'support_email': FromAddress.SUPPORT, 'find_team_link_disabled': find_team_link_disabled, 'password_min_length': settings.PASSWORD_MIN_LENGTH, 'password_min_quality': settings.PASSWORD_MIN_ZXCVBN_QUALITY, 'zulip_version': ZULIP_VERSION, }
def home_real(request): # type: (HttpRequest) -> HttpResponse # 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 # session alive. request.session.modified = True user_profile = request.user # If a user hasn't signed the current Terms of Service, send them there if settings.TERMS_OF_SERVICE is not None and settings.TOS_VERSION is not None and \ int(settings.TOS_VERSION.split('.')[0]) > user_profile.major_tos_version(): return accounts_accept_terms(request) narrow = [] # type: List[List[Text]] narrow_stream = None narrow_topic = request.GET.get("topic") if request.GET.get("stream"): try: narrow_stream_name = request.GET.get("stream") (narrow_stream, ignored_rec, ignored_sub) = access_stream_by_name(user_profile, narrow_stream_name) narrow = [["stream", narrow_stream.name]] except Exception: logging.exception("Narrow parsing") if narrow_stream is not None and narrow_topic is not None: narrow.append(["topic", narrow_topic]) register_ret = do_events_register(user_profile, request.client, apply_markdown=True, narrow=narrow) user_has_messages = (register_ret['max_message_id'] != -1) # Reset our don't-spam-users-with-email counter since the # user has since logged in if user_profile.last_reminder is not None: user_profile.last_reminder = None user_profile.save(update_fields=["last_reminder"]) # Brand new users get the tutorial needs_tutorial = settings.TUTORIAL_ENABLED and \ user_profile.tutorial_status != UserProfile.TUTORIAL_FINISHED first_in_realm = realm_user_count(user_profile.realm) == 1 # If you are the only person in the realm and you didn't invite # anyone, we'll continue to encourage you to do so on the frontend. prompt_for_invites = first_in_realm and \ not PreregistrationUser.objects.filter(referred_by=user_profile).count() if user_profile.pointer == -1 and user_has_messages: # Put the new user's pointer at the bottom # # This improves performance, because we limit backfilling of messages # before the pointer. It's also likely that someone joining an # organization is interested in recent messages more than the very # first messages on the system. register_ret['pointer'] = register_ret['max_message_id'] user_profile.last_pointer_updater = request.session.session_key if user_profile.pointer == -1: latest_read = None else: try: latest_read = UserMessage.objects.get( user_profile=user_profile, message__id=user_profile.pointer) except UserMessage.DoesNotExist: # Don't completely fail if your saved pointer ID is invalid logging.warning("%s has invalid pointer %s" % (user_profile.email, user_profile.pointer)) latest_read = None desktop_notifications_enabled = user_profile.enable_desktop_notifications if narrow_stream is not None: desktop_notifications_enabled = False if user_profile.realm.notifications_stream: notifications_stream = user_profile.realm.notifications_stream.name else: notifications_stream = "" # Set default language and make it persist default_language = register_ret['default_language'] url_lang = '/{}'.format(request.LANGUAGE_CODE) if not request.path.startswith(url_lang): translation.activate(default_language) request.session[translation.LANGUAGE_SESSION_KEY] = default_language # Pass parameters to the client-side JavaScript code. # These end up in a global JavaScript Object named 'page_params'. page_params = dict( # Server settings. share_the_love=settings.SHARE_THE_LOVE, development_environment=settings.DEVELOPMENT, debug_mode=settings.DEBUG, test_suite=settings.TEST_SUITE, poll_timeout=settings.POLL_TIMEOUT, login_page=settings.HOME_NOT_LOGGED_IN, server_uri=settings.SERVER_URI, maxfilesize=settings.MAX_FILE_UPLOAD_SIZE, server_generation=settings.SERVER_GENERATION, use_websockets=settings.USE_WEBSOCKETS, save_stacktraces=settings.SAVE_FRONTEND_STACKTRACES, # realm data. # TODO: Move all of these data to register_ret and pull from there realm_uri=user_profile.realm.uri, password_auth_enabled=password_auth_enabled(user_profile.realm), domain=user_profile.realm.domain, domains=list_of_domains_for_realm(user_profile.realm), realm_icon_url=realm_icon_url(user_profile.realm), realm_icon_source=user_profile.realm.icon_source, name_changes_disabled=name_changes_disabled(user_profile.realm), mandatory_topics=user_profile.realm.mandatory_topics, show_digest_email=user_profile.realm.show_digest_email, realm_presence_disabled=user_profile.realm.presence_disabled, is_zephyr_mirror_realm=user_profile.realm.is_zephyr_mirror_realm, # user_profile data. # TODO: Move all of these data to register_ret and pull from there fullname=user_profile.full_name, email=user_profile.email, enter_sends=user_profile.enter_sends, user_id=user_profile.id, is_admin=user_profile.is_realm_admin, can_create_streams=user_profile.can_create_streams(), autoscroll_forever=user_profile.autoscroll_forever, default_desktop_notifications=user_profile. default_desktop_notifications, avatar_url=avatar_url(user_profile), avatar_url_medium=avatar_url(user_profile, medium=True), avatar_source=user_profile.avatar_source, # Stream message notification settings: stream_desktop_notifications_enabled=user_profile. enable_stream_desktop_notifications, stream_sounds_enabled=user_profile.enable_stream_sounds, # Private message and @-mention notification settings: desktop_notifications_enabled=desktop_notifications_enabled, sounds_enabled=user_profile.enable_sounds, enable_offline_email_notifications=user_profile. enable_offline_email_notifications, pm_content_in_desktop_notifications=user_profile. pm_content_in_desktop_notifications, enable_offline_push_notifications=user_profile. enable_offline_push_notifications, enable_online_push_notifications=user_profile. enable_online_push_notifications, enable_digest_emails=user_profile.enable_digest_emails, # Realm foreign key data from register_ret. # TODO: Rename these to match register_ret values. subbed_info=register_ret['subscriptions'], unsubbed_info=register_ret['unsubscribed'], neversubbed_info=register_ret['never_subscribed'], people_list=register_ret['realm_users'], bot_list=register_ret['realm_bots'], initial_pointer=register_ret['pointer'], initial_presences=register_ret['presences'], event_queue_id=register_ret['queue_id'], # Misc. extra data. have_initial_messages=user_has_messages, initial_servertime=time.time( ), # Used for calculating relative presence age default_language_name=get_language_name( register_ret['default_language']), language_list_dbl_col=get_language_list_for_templates( register_ret['default_language']), language_list=get_language_list(), needs_tutorial=needs_tutorial, first_in_realm=first_in_realm, prompt_for_invites=prompt_for_invites, notifications_stream=notifications_stream, cross_realm_bots=list(get_cross_realm_dicts()), unread_count=approximate_unread_count(user_profile), furthest_read_time=sent_time_in_epoch_seconds(latest_read), has_mobile_devices=num_push_devices_for_user(user_profile) > 0, ) # These fields will be automatically copied from register_ret into # page_params. It is a goal to move more of the page_params list # into this sort of cleaner structure. page_params_core_fields = [ 'alert_words', 'attachments', 'default_language', 'last_event_id', 'left_side_userlist', 'max_message_id', 'muted_topics', 'realm_add_emoji_by_admins_only', 'realm_allow_message_editing', 'realm_authentication_methods', 'realm_create_stream_by_admins_only', 'realm_default_language', 'realm_default_streams', 'realm_emoji', 'realm_message_content_edit_limit_seconds', 'realm_name', 'realm_invite_by_admins_only', 'realm_invite_required', 'realm_filters', 'realm_restricted_to_domain', 'realm_waiting_period_threshold', 'referrals', 'twenty_four_hour_time', 'zulip_version', ] for field_name in page_params_core_fields: page_params[field_name] = register_ret[field_name] if narrow_stream is not None: # In narrow_stream context, initial pointer is just latest message recipient = get_recipient(Recipient.STREAM, narrow_stream.id) try: initial_pointer = Message.objects.filter( recipient=recipient).order_by('id').reverse()[0].id except IndexError: initial_pointer = -1 page_params["narrow_stream"] = narrow_stream.name if narrow_topic is not None: page_params["narrow_topic"] = narrow_topic page_params["narrow"] = [ dict(operator=term[0], operand=term[1]) for term in narrow ] page_params["max_message_id"] = initial_pointer page_params["initial_pointer"] = initial_pointer page_params["have_initial_messages"] = (initial_pointer != -1) statsd.incr('views.home') show_invites = True # Some realms only allow admins to invite users if user_profile.realm.invite_by_admins_only and not user_profile.is_realm_admin: show_invites = False product_name = "Zulip" page_params['product_name'] = product_name request._log_data['extra'] = "[%s]" % (register_ret["queue_id"], ) response = render_to_response('zerver/index.html', { 'user_profile': user_profile, 'page_params': simplejson.encoder.JSONEncoderForHTML().encode(page_params), 'nofontface': is_buggy_ua(request.META.get("HTTP_USER_AGENT", "Unspecified")), 'avatar_url': avatar_url(user_profile), 'show_debug': settings.DEBUG and ('show_debug' in request.GET), 'pipeline': settings.PIPELINE_ENABLED, 'show_invites': show_invites, 'is_admin': user_profile.is_realm_admin, 'show_webathena': user_profile.realm.webathena_enabled, 'enable_feedback': settings.ENABLE_FEEDBACK, 'embedded': narrow_stream is not None, 'product_name': product_name }, request=request) patch_cache_control(response, no_cache=True, no_store=True, must_revalidate=True) return response
def fetch_initial_state_data(user_profile, event_types, queue_id, include_subscribers=True): # type: (UserProfile, Optional[Iterable[str]], str, bool) -> Dict[str, Any] state = {'queue_id': queue_id} # type: Dict[str, Any] if event_types is None: want = lambda msg_type: True else: want = set(event_types).__contains__ if want('alert_words'): state['alert_words'] = user_alert_words(user_profile) if want('custom_profile_fields'): fields = custom_profile_fields_for_realm(user_profile.realm.id) state['custom_profile_fields'] = [f.as_dict() for f in fields] if want('attachments'): state['attachments'] = user_attachments(user_profile) if want('hotspots'): state['hotspots'] = get_next_hotspots(user_profile) if want('message'): # The client should use get_messages() to fetch messages # starting with the max_message_id. They will get messages # newer than that ID via get_events() messages = Message.objects.filter(usermessage__user_profile=user_profile).order_by('-id')[:1] if messages: state['max_message_id'] = messages[0].id else: state['max_message_id'] = -1 if want('muted_topics'): state['muted_topics'] = ujson.loads(user_profile.muted_topics) if want('pointer'): state['pointer'] = user_profile.pointer if want('presence'): state['presences'] = get_status_dict(user_profile) if want('realm'): for property_name in Realm.property_types: state['realm_' + property_name] = getattr(user_profile.realm, property_name) # Most state is handled via the property_types framework; # these manual entries are for those realm settings that don't # fit into that framework. state['realm_authentication_methods'] = user_profile.realm.authentication_methods_dict() state['realm_allow_message_editing'] = user_profile.realm.allow_message_editing state['realm_message_content_edit_limit_seconds'] = user_profile.realm.message_content_edit_limit_seconds state['realm_icon_url'] = realm_icon_url(user_profile.realm) state['realm_icon_source'] = user_profile.realm.icon_source state['max_icon_file_size'] = settings.MAX_ICON_FILE_SIZE state['realm_bot_domain'] = user_profile.realm.get_bot_domain() state['realm_uri'] = user_profile.realm.uri state['realm_presence_disabled'] = user_profile.realm.presence_disabled state['realm_show_digest_email'] = user_profile.realm.show_digest_email state['realm_is_zephyr_mirror_realm'] = user_profile.realm.is_zephyr_mirror_realm state['realm_password_auth_enabled'] = password_auth_enabled(user_profile.realm) if user_profile.realm.notifications_stream and not user_profile.realm.notifications_stream.deactivated: notifications_stream = user_profile.realm.notifications_stream state['realm_notifications_stream_id'] = notifications_stream.id else: state['realm_notifications_stream_id'] = -1 if want('realm_domains'): state['realm_domains'] = get_realm_domains(user_profile.realm) if want('realm_emoji'): state['realm_emoji'] = user_profile.realm.get_emoji() if want('realm_filters'): state['realm_filters'] = realm_filters_for_realm(user_profile.realm_id) if want('realm_user'): state['realm_users'] = get_realm_user_dicts(user_profile) state['avatar_source'] = user_profile.avatar_source state['avatar_url_medium'] = avatar_url(user_profile, medium=True) state['avatar_url'] = avatar_url(user_profile) state['can_create_streams'] = user_profile.can_create_streams() state['cross_realm_bots'] = list(get_cross_realm_dicts()) state['is_admin'] = user_profile.is_realm_admin state['user_id'] = user_profile.id state['enter_sends'] = user_profile.enter_sends state['email'] = user_profile.email state['full_name'] = user_profile.full_name if want('realm_bot'): state['realm_bots'] = get_owned_bot_dicts(user_profile) if want('subscription'): subscriptions, unsubscribed, never_subscribed = gather_subscriptions_helper( user_profile, include_subscribers=include_subscribers) state['subscriptions'] = subscriptions state['unsubscribed'] = unsubscribed state['never_subscribed'] = never_subscribed if want('update_message_flags') and want('message'): # Keeping unread_msgs updated requires both message flag updates and # message updates. This is due to the fact that new messages will not # generate a flag update so we need to use the flags field in the # message event. state['unread_msgs'] = get_unread_message_ids_per_recipient(user_profile) if want('stream'): state['streams'] = do_get_streams(user_profile) if want('default_streams'): state['realm_default_streams'] = streams_to_dicts_sorted(get_default_streams_for_realm(user_profile.realm)) if want('update_display_settings'): for prop in UserProfile.property_types: state[prop] = getattr(user_profile, prop) state['emojiset_choices'] = user_profile.emojiset_choices() state['autoscroll_forever'] = user_profile.autoscroll_forever if want('update_global_notifications'): for notification in UserProfile.notification_setting_types: state[notification] = getattr(user_profile, notification) state['default_desktop_notifications'] = user_profile.default_desktop_notifications if want('zulip_version'): state['zulip_version'] = ZULIP_VERSION return state
def fetch_initial_state_data( user_profile: UserProfile, event_types: Optional[Iterable[str]], queue_id: str, client_gravatar: bool, include_subscribers: bool = True) -> Dict[str, Any]: state = {'queue_id': queue_id} # type: Dict[str, Any] realm = user_profile.realm if event_types is None: # return True always want = always_want # type: Callable[[str], bool] else: want = set(event_types).__contains__ if want('alert_words'): state['alert_words'] = user_alert_words(user_profile) if want('custom_profile_fields'): fields = custom_profile_fields_for_realm(realm.id) state['custom_profile_fields'] = [f.as_dict() for f in fields] state[ 'custom_profile_field_types'] = CustomProfileField.FIELD_TYPE_CHOICES if want('hotspots'): state['hotspots'] = get_next_hotspots(user_profile) if want('message'): # The client should use get_messages() to fetch messages # starting with the max_message_id. They will get messages # newer than that ID via get_events() messages = Message.objects.filter( usermessage__user_profile=user_profile).order_by('-id')[:1] if messages: state['max_message_id'] = messages[0].id else: state['max_message_id'] = -1 if want('muted_topics'): state['muted_topics'] = get_topic_mutes(user_profile) if want('pointer'): state['pointer'] = user_profile.pointer if want('presence'): state['presences'] = get_status_dict(user_profile) if want('realm'): for property_name in Realm.property_types: state['realm_' + property_name] = getattr(realm, property_name) # Most state is handled via the property_types framework; # these manual entries are for those realm settings that don't # fit into that framework. state[ 'realm_authentication_methods'] = realm.authentication_methods_dict( ) state['realm_allow_message_editing'] = realm.allow_message_editing state[ 'realm_allow_community_topic_editing'] = realm.allow_community_topic_editing state['realm_allow_message_deleting'] = realm.allow_message_deleting state[ 'realm_message_content_edit_limit_seconds'] = realm.message_content_edit_limit_seconds state[ 'realm_message_content_delete_limit_seconds'] = realm.message_content_delete_limit_seconds state['realm_icon_url'] = realm_icon_url(realm) state['realm_icon_source'] = realm.icon_source state['max_icon_file_size'] = settings.MAX_ICON_FILE_SIZE state['realm_bot_domain'] = realm.get_bot_domain() state['realm_uri'] = realm.uri state[ 'realm_available_video_chat_providers'] = realm.VIDEO_CHAT_PROVIDERS state['realm_presence_disabled'] = realm.presence_disabled state[ 'realm_digest_emails_enabled'] = realm.digest_emails_enabled and settings.SEND_DIGEST_EMAILS state['realm_is_zephyr_mirror_realm'] = realm.is_zephyr_mirror_realm state['realm_email_auth_enabled'] = email_auth_enabled(realm) state['realm_password_auth_enabled'] = password_auth_enabled(realm) state['realm_push_notifications_enabled'] = push_notifications_enabled( ) if realm.notifications_stream and not realm.notifications_stream.deactivated: notifications_stream = realm.notifications_stream state['realm_notifications_stream_id'] = notifications_stream.id else: state['realm_notifications_stream_id'] = -1 signup_notifications_stream = realm.get_signup_notifications_stream() if signup_notifications_stream: state[ 'realm_signup_notifications_stream_id'] = signup_notifications_stream.id else: state['realm_signup_notifications_stream_id'] = -1 if want('realm_domains'): state['realm_domains'] = get_realm_domains(realm) if want('realm_emoji'): state['realm_emoji'] = realm.get_emoji() if want('realm_filters'): state['realm_filters'] = realm_filters_for_realm(realm.id) if want('realm_user_groups'): state['realm_user_groups'] = user_groups_in_realm_serialized(realm) if want('realm_user'): state['raw_users'] = get_raw_user_data( realm_id=realm.id, client_gravatar=client_gravatar, ) # For the user's own avatar URL, we force # client_gravatar=False, since that saves some unnecessary # client-side code for handing medium-size avatars. See #8253 # for details. state['avatar_source'] = user_profile.avatar_source state['avatar_url_medium'] = avatar_url( user_profile, medium=True, client_gravatar=False, ) state['avatar_url'] = avatar_url( user_profile, medium=False, client_gravatar=False, ) state['can_create_streams'] = user_profile.can_create_streams() state['cross_realm_bots'] = list(get_cross_realm_dicts()) state['is_admin'] = user_profile.is_realm_admin state['is_guest'] = user_profile.is_guest state['user_id'] = user_profile.id state['enter_sends'] = user_profile.enter_sends state['email'] = user_profile.email state['delivery_email'] = user_profile.delivery_email state['full_name'] = user_profile.full_name if want('realm_bot'): state['realm_bots'] = get_owned_bot_dicts(user_profile) # This does not yet have an apply_event counterpart, since currently, # new entries for EMBEDDED_BOTS can only be added directly in the codebase. if want('realm_embedded_bots'): realm_embedded_bots = [] for bot in EMBEDDED_BOTS: realm_embedded_bots.append({ 'name': bot.name, 'config': load_bot_config_template(bot.name) }) state['realm_embedded_bots'] = realm_embedded_bots if want('subscription'): subscriptions, unsubscribed, never_subscribed = gather_subscriptions_helper( user_profile, include_subscribers=include_subscribers) state['subscriptions'] = subscriptions state['unsubscribed'] = unsubscribed state['never_subscribed'] = never_subscribed if want('update_message_flags') and want('message'): # Keeping unread_msgs updated requires both message flag updates and # message updates. This is due to the fact that new messages will not # generate a flag update so we need to use the flags field in the # message event. state['raw_unread_msgs'] = get_raw_unread_data(user_profile) if want('stream'): state['streams'] = do_get_streams(user_profile) state['stream_name_max_length'] = Stream.MAX_NAME_LENGTH state['stream_description_max_length'] = Stream.MAX_DESCRIPTION_LENGTH if want('default_streams'): state['realm_default_streams'] = streams_to_dicts_sorted( get_default_streams_for_realm(realm.id)) if want('default_stream_groups'): state[ 'realm_default_stream_groups'] = default_stream_groups_to_dicts_sorted( get_default_stream_groups(realm)) if want('update_display_settings'): for prop in UserProfile.property_types: state[prop] = getattr(user_profile, prop) state['emojiset_choices'] = user_profile.emojiset_choices() if want('update_global_notifications'): for notification in UserProfile.notification_setting_types: state[notification] = getattr(user_profile, notification) if want('zulip_version'): state['zulip_version'] = ZULIP_VERSION return state
def zulip_default_context(request: HttpRequest) -> Dict[str, Any]: """Context available to all Zulip Jinja2 templates that have a request passed in. Designed to provide the long list of variables at the bottom of this function in a wide range of situations: logged-in or logged-out, subdomains or not, etc. The main variable in the below is whether we know what realm the user is trying to interact with. """ realm = get_realm_from_request(request) if realm is None: realm_uri = settings.ROOT_DOMAIN_URI realm_name = None realm_icon = None realm_description = None realm_invite_required = False realm_plan_type = 0 else: realm_uri = realm.uri realm_name = realm.name realm_icon = get_realm_icon_url(realm) realm_description_raw = realm.description or "The coolest place in the universe." realm_description = bugdown_convert(realm_description_raw, message_realm=realm) realm_invite_required = realm.invite_required realm_plan_type = realm.plan_type register_link_disabled = settings.REGISTER_LINK_DISABLED login_link_disabled = settings.LOGIN_LINK_DISABLED find_team_link_disabled = settings.FIND_TEAM_LINK_DISABLED allow_search_engine_indexing = False if (settings.ROOT_DOMAIN_LANDING_PAGE and get_subdomain(request) == Realm.SUBDOMAIN_FOR_ROOT_DOMAIN): register_link_disabled = True login_link_disabled = True find_team_link_disabled = False allow_search_engine_indexing = True apps_page_url = 'https://zulipchat.com/apps/' if settings.ZILENCER_ENABLED: apps_page_url = '/apps/' user_is_authenticated = False if hasattr(request, 'user') and hasattr(request.user, 'is_authenticated'): user_is_authenticated = request.user.is_authenticated.value if settings.DEVELOPMENT: secrets_path = "zproject/dev-secrets.conf" settings_path = "zproject/dev_settings.py" settings_comments_path = "zproject/prod_settings_template.py" else: secrets_path = "/etc/zulip/zulip-secrets.conf" settings_path = "/etc/zulip/settings.py" settings_comments_path = "/etc/zulip/settings.py" # We can't use request.client here because we might not be using # an auth decorator that sets it, but we can call its helper to # get the same result. platform = get_client_name(request, True) context = { 'root_domain_landing_page': settings.ROOT_DOMAIN_LANDING_PAGE, 'custom_logo_url': settings.CUSTOM_LOGO_URL, 'register_link_disabled': register_link_disabled, 'login_link_disabled': login_link_disabled, 'terms_of_service': settings.TERMS_OF_SERVICE, 'privacy_policy': settings.PRIVACY_POLICY, 'login_url': settings.HOME_NOT_LOGGED_IN, 'only_sso': settings.ONLY_SSO, 'external_host': settings.EXTERNAL_HOST, 'external_uri_scheme': settings.EXTERNAL_URI_SCHEME, 'realm_invite_required': realm_invite_required, 'realm_uri': realm_uri, 'realm_name': realm_name, 'realm_icon': realm_icon, 'realm_description': realm_description, 'realm_plan_type': realm_plan_type, 'root_domain_uri': settings.ROOT_DOMAIN_URI, 'apps_page_url': apps_page_url, 'open_realm_creation': settings.OPEN_REALM_CREATION, 'password_auth_enabled': password_auth_enabled(realm), 'require_email_format_usernames': require_email_format_usernames(realm), 'any_oauth_backend_enabled': any_oauth_backend_enabled(realm), 'no_auth_enabled': not auth_enabled_helper(list(AUTH_BACKEND_NAME_MAP.keys()), realm), 'development_environment': settings.DEVELOPMENT, 'support_email': FromAddress.SUPPORT, 'find_team_link_disabled': find_team_link_disabled, 'password_min_length': settings.PASSWORD_MIN_LENGTH, 'password_min_guesses': settings.PASSWORD_MIN_GUESSES, 'jitsi_server_url': settings.JITSI_SERVER_URL, 'two_factor_authentication_enabled': settings.TWO_FACTOR_AUTHENTICATION_ENABLED, 'zulip_version': ZULIP_VERSION, 'latest_release_version': LATEST_RELEASE_VERSION, 'latest_major_version': LATEST_MAJOR_VERSION, 'latest_release_announcement': LATEST_RELEASE_ANNOUNCEMENT, 'user_is_authenticated': user_is_authenticated, 'settings_path': settings_path, 'secrets_path': secrets_path, 'settings_comments_path': settings_comments_path, 'platform': platform, 'allow_search_engine_indexing': allow_search_engine_indexing, } # Add the keys for our standard authentication backends. for auth_backend_name in AUTH_BACKEND_NAME_MAP: name_lower = auth_backend_name.lower() key = "%s_auth_enabled" % (name_lower,) context[key] = auth_enabled_helper([auth_backend_name], realm) social_backends = [] for backend in SOCIAL_AUTH_BACKENDS: if not auth_enabled_helper([backend.auth_backend_name], realm): continue social_backends.append({ 'name': backend.name, 'display_name': backend.auth_backend_name, 'login_url': reverse('login-social', args=(backend.name,)), 'signup_url': reverse('signup-social', args=(backend.name,)), 'sort_order': backend.sort_order, }) context['social_backends'] = sorted(social_backends, key=lambda x: x['sort_order']) return context
def zulip_default_context(request): # type: (HttpRequest) -> Dict[str, Any] """Context available to all Zulip Jinja2 templates that have a request passed in. Designed to provide the long list of variables at the bottom of this function in a wide range of situations: logged-in or logged-out, subdomains or not, etc. The main variable in the below is whether we know the realm, which is the case if there is only one realm, or we're on a REALMS_HAVE_SUBDOMAINS subdomain, or the user is logged in. """ realm = get_realm_from_request(request) if realm is not None: realm_uri = realm.uri realm_name = realm.name realm_icon = get_realm_icon_url(realm) realm_description = realm.description or "The coolest place in the universe." else: realm_uri = settings.SERVER_URI realm_name = None realm_icon = None realm_description = None return { 'realms_have_subdomains': settings.REALMS_HAVE_SUBDOMAINS, 'custom_logo_url': settings.CUSTOM_LOGO_URL, 'register_link_disabled': settings.REGISTER_LINK_DISABLED, 'login_link_disabled': settings.LOGIN_LINK_DISABLED, 'about_link_disabled': settings.ABOUT_LINK_DISABLED, 'show_oss_announcement': settings.SHOW_OSS_ANNOUNCEMENT, 'zulip_admin': settings.ZULIP_ADMINISTRATOR, 'terms_of_service': settings.TERMS_OF_SERVICE, 'privacy_policy': settings.PRIVACY_POLICY, 'login_url': settings.HOME_NOT_LOGGED_IN, 'only_sso': settings.ONLY_SSO, 'external_api_path': settings.EXTERNAL_API_PATH, 'external_api_uri': settings.EXTERNAL_API_URI, 'external_host': settings.EXTERNAL_HOST, 'external_uri_scheme': settings.EXTERNAL_URI_SCHEME, 'realm_uri': realm_uri, 'realm_name': realm_name, 'realm_icon': realm_icon, 'realm_description': realm_description, 'server_uri': settings.SERVER_URI, 'api_site_required': settings.EXTERNAL_API_PATH != "api.zulip.com", 'email_integration_enabled': settings.EMAIL_GATEWAY_BOT != "", 'email_gateway_example': settings.EMAIL_GATEWAY_EXAMPLE, 'open_realm_creation': settings.OPEN_REALM_CREATION, 'password_auth_enabled': password_auth_enabled(realm), 'dev_auth_enabled': dev_auth_enabled(realm), 'google_auth_enabled': google_auth_enabled(realm), 'github_auth_enabled': github_auth_enabled(realm), 'any_oauth_backend_enabled': any_oauth_backend_enabled(realm), 'no_auth_enabled': not auth_enabled_helper(list(AUTH_BACKEND_NAME_MAP.keys()), realm), 'development_environment': settings.DEVELOPMENT, 'support_email': settings.ZULIP_ADMINISTRATOR, 'find_team_link_disabled': settings.FIND_TEAM_LINK_DISABLED, 'password_min_length': settings.PASSWORD_MIN_LENGTH, 'password_min_quality': settings.PASSWORD_MIN_ZXCVBN_QUALITY, 'zulip_version': ZULIP_VERSION, }
def zulip_default_context(request: HttpRequest) -> Dict[str, Any]: """Context available to all Zulip Jinja2 templates that have a request passed in. Designed to provide the long list of variables at the bottom of this function in a wide range of situations: logged-in or logged-out, subdomains or not, etc. The main variable in the below is whether we know what realm the user is trying to interact with. """ realm = get_realm_from_request(request) if realm is None: realm_uri = settings.ROOT_DOMAIN_URI realm_name = None realm_icon = None realm_description = None realm_invite_required = False realm_plan_type = 0 else: realm_uri = realm.uri realm_name = realm.name realm_icon = get_realm_icon_url(realm) realm_description = get_realm_rendered_description(realm) realm_invite_required = realm.invite_required realm_plan_type = realm.plan_type register_link_disabled = settings.REGISTER_LINK_DISABLED login_link_disabled = settings.LOGIN_LINK_DISABLED find_team_link_disabled = settings.FIND_TEAM_LINK_DISABLED allow_search_engine_indexing = False if (settings.ROOT_DOMAIN_LANDING_PAGE and get_subdomain(request) == Realm.SUBDOMAIN_FOR_ROOT_DOMAIN): register_link_disabled = True login_link_disabled = True find_team_link_disabled = False allow_search_engine_indexing = True apps_page_url = 'https://zulipchat.com/apps/' if settings.ZILENCER_ENABLED: apps_page_url = '/apps/' user_is_authenticated = False if hasattr(request, 'user') and hasattr(request.user, 'is_authenticated'): user_is_authenticated = request.user.is_authenticated.value if settings.DEVELOPMENT: secrets_path = "zproject/dev-secrets.conf" settings_path = "zproject/dev_settings.py" settings_comments_path = "zproject/prod_settings_template.py" else: secrets_path = "/etc/zulip/zulip-secrets.conf" settings_path = "/etc/zulip/settings.py" settings_comments_path = "/etc/zulip/settings.py" # We can't use request.client here because we might not be using # an auth decorator that sets it, but we can call its helper to # get the same result. platform = get_client_name(request, True) context = { 'root_domain_landing_page': settings.ROOT_DOMAIN_LANDING_PAGE, 'custom_logo_url': settings.CUSTOM_LOGO_URL, 'register_link_disabled': register_link_disabled, 'login_link_disabled': login_link_disabled, 'terms_of_service': settings.TERMS_OF_SERVICE, 'privacy_policy': settings.PRIVACY_POLICY, 'login_url': settings.HOME_NOT_LOGGED_IN, 'only_sso': settings.ONLY_SSO, 'external_host': settings.EXTERNAL_HOST, 'external_uri_scheme': settings.EXTERNAL_URI_SCHEME, 'realm_invite_required': realm_invite_required, 'realm_uri': realm_uri, 'realm_name': realm_name, 'realm_icon': realm_icon, 'realm_description': realm_description, 'realm_plan_type': realm_plan_type, 'root_domain_uri': settings.ROOT_DOMAIN_URI, 'apps_page_url': apps_page_url, 'open_realm_creation': settings.OPEN_REALM_CREATION, 'password_auth_enabled': password_auth_enabled(realm), 'require_email_format_usernames': require_email_format_usernames(realm), 'any_oauth_backend_enabled': any_oauth_backend_enabled(realm), 'development_environment': settings.DEVELOPMENT, 'support_email': FromAddress.SUPPORT, 'find_team_link_disabled': find_team_link_disabled, 'password_min_length': settings.PASSWORD_MIN_LENGTH, 'password_min_guesses': settings.PASSWORD_MIN_GUESSES, 'jitsi_server_url': settings.JITSI_SERVER_URL, 'two_factor_authentication_enabled': settings.TWO_FACTOR_AUTHENTICATION_ENABLED, 'zulip_version': ZULIP_VERSION, 'latest_release_version': LATEST_RELEASE_VERSION, 'latest_major_version': LATEST_MAJOR_VERSION, 'latest_release_announcement': LATEST_RELEASE_ANNOUNCEMENT, 'user_is_authenticated': user_is_authenticated, 'settings_path': settings_path, 'secrets_path': secrets_path, 'settings_comments_path': settings_comments_path, 'platform': platform, 'allow_search_engine_indexing': allow_search_engine_indexing, } # Add the keys for our standard authentication backends. no_auth_enabled = True social_backends = [] for auth_backend_name in AUTH_BACKEND_NAME_MAP: name_lower = auth_backend_name.lower() key = "%s_auth_enabled" % (name_lower, ) is_enabled = auth_enabled_helper([auth_backend_name], realm) context[key] = is_enabled if is_enabled: no_auth_enabled = False # Now add the enabled social backends to the social_backends # list used to generate buttons for login/register pages. backend = AUTH_BACKEND_NAME_MAP[auth_backend_name] if not is_enabled or backend not in SOCIAL_AUTH_BACKENDS: continue social_backends.append({ 'name': backend.name, 'display_name': backend.auth_backend_name, 'login_url': reverse('login-social', args=(backend.name, )), 'signup_url': reverse('signup-social', args=(backend.name, )), 'sort_order': backend.sort_order, }) context['social_backends'] = sorted(social_backends, key=lambda x: x['sort_order'], reverse=True) context["no_auth_enabled"] = no_auth_enabled return context