mirror of
				https://github.com/zulip/zulip.git
				synced 2025-10-31 03:53:50 +00:00 
			
		
		
		
	We record Git details about the merge-base with upstream branches in the zulip-git-version file, if the upstream repository is available. Note that the first Git upgrade after merging the parent commit will not include the merge-base details, since the upstream repository will not have been available. Co-authored-by: Tim Abbott <tabbott@zulip.com> Signed-off-by: Anders Kaseorg <anders@zulip.com>
		
			
				
	
	
		
			260 lines
		
	
	
		
			9.3 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			260 lines
		
	
	
		
			9.3 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| import logging
 | |
| import secrets
 | |
| from typing import Any, Dict, List, Optional, Tuple
 | |
| 
 | |
| from django.conf import settings
 | |
| from django.http import HttpRequest, HttpResponse, HttpResponseRedirect
 | |
| from django.shortcuts import redirect, render
 | |
| from django.urls import reverse
 | |
| from django.utils.cache import patch_cache_control
 | |
| 
 | |
| from version import ZULIP_MERGE_BASE, ZULIP_VERSION
 | |
| from zerver.context_processors import get_valid_realm_from_request
 | |
| from zerver.decorator import web_public_view, zulip_login_required
 | |
| from zerver.forms import ToSForm
 | |
| from zerver.lib.actions import do_change_tos_version, realm_user_count
 | |
| from zerver.lib.home import (
 | |
|     build_page_params_for_home_page_load,
 | |
|     get_billing_info,
 | |
|     get_user_permission_info,
 | |
|     promote_sponsoring_zulip_in_realm,
 | |
| )
 | |
| from zerver.lib.push_notifications import num_push_devices_for_user
 | |
| from zerver.lib.streams import access_stream_by_name
 | |
| from zerver.lib.subdomains import get_subdomain
 | |
| from zerver.lib.users import compute_show_invites_and_add_streams
 | |
| from zerver.lib.utils import statsd
 | |
| from zerver.models import PreregistrationUser, Realm, Stream, UserProfile
 | |
| from zerver.views.compatibility import is_outdated_desktop_app, is_unsupported_browser
 | |
| from zerver.views.portico import hello_view
 | |
| 
 | |
| 
 | |
| def need_accept_tos(user_profile: Optional[UserProfile]) -> bool:
 | |
|     if user_profile is None:
 | |
|         return False
 | |
| 
 | |
|     if settings.TERMS_OF_SERVICE is None:  # nocoverage
 | |
|         return False
 | |
| 
 | |
|     if settings.TOS_VERSION is None:
 | |
|         return False
 | |
| 
 | |
|     return int(settings.TOS_VERSION.split(".")[0]) > user_profile.major_tos_version()
 | |
| 
 | |
| 
 | |
| @zulip_login_required
 | |
| def accounts_accept_terms(request: HttpRequest) -> HttpResponse:
 | |
|     if request.method == "POST":
 | |
|         form = ToSForm(request.POST)
 | |
|         if form.is_valid():
 | |
|             do_change_tos_version(request.user, settings.TOS_VERSION)
 | |
|             return redirect(home)
 | |
|     else:
 | |
|         form = ToSForm()
 | |
| 
 | |
|     email = request.user.delivery_email
 | |
|     special_message_template = None
 | |
|     if request.user.tos_version is None and settings.FIRST_TIME_TOS_TEMPLATE is not None:
 | |
|         special_message_template = "zerver/" + settings.FIRST_TIME_TOS_TEMPLATE
 | |
|     return render(
 | |
|         request,
 | |
|         "zerver/accounts_accept_terms.html",
 | |
|         context={
 | |
|             "form": form,
 | |
|             "email": email,
 | |
|             "special_message_template": special_message_template,
 | |
|         },
 | |
|     )
 | |
| 
 | |
| 
 | |
| def detect_narrowed_window(
 | |
|     request: HttpRequest, user_profile: Optional[UserProfile]
 | |
| ) -> Tuple[List[List[str]], Optional[Stream], Optional[str]]:
 | |
|     """This function implements Zulip's support for a mini Zulip window
 | |
|     that just handles messages from a single narrow"""
 | |
|     if user_profile is None:
 | |
|         return [], None, None
 | |
| 
 | |
|     narrow: List[List[str]] = []
 | |
|     narrow_stream = None
 | |
|     narrow_topic = request.GET.get("topic")
 | |
| 
 | |
|     if request.GET.get("stream"):
 | |
|         try:
 | |
|             # TODO: We should support stream IDs and PMs here as well.
 | |
|             narrow_stream_name = request.GET.get("stream")
 | |
|             (narrow_stream, ignored_sub) = access_stream_by_name(user_profile, narrow_stream_name)
 | |
|             narrow = [["stream", narrow_stream.name]]
 | |
|         except Exception:
 | |
|             logging.warning("Invalid narrow requested, ignoring", extra=dict(request=request))
 | |
|         if narrow_stream is not None and narrow_topic is not None:
 | |
|             narrow.append(["topic", narrow_topic])
 | |
|     return narrow, narrow_stream, narrow_topic
 | |
| 
 | |
| 
 | |
| def update_last_reminder(user_profile: Optional[UserProfile]) -> None:
 | |
|     """Reset our don't-spam-users-with-email counter since the
 | |
|     user has since logged in
 | |
|     """
 | |
|     if user_profile is None:
 | |
|         return
 | |
| 
 | |
|     if user_profile.last_reminder is not None:  # nocoverage
 | |
|         # TODO: Look into the history of last_reminder; we may have
 | |
|         # eliminated that as a useful concept for non-bot users.
 | |
|         user_profile.last_reminder = None
 | |
|         user_profile.save(update_fields=["last_reminder"])
 | |
| 
 | |
| 
 | |
| def compute_navbar_logo_url(page_params: Dict[str, Any]) -> str:
 | |
|     if (
 | |
|         page_params["color_scheme"] == 2
 | |
|         and page_params["realm_night_logo_source"] != Realm.LOGO_DEFAULT
 | |
|     ):
 | |
|         navbar_logo_url = page_params["realm_night_logo_url"]
 | |
|     else:
 | |
|         navbar_logo_url = page_params["realm_logo_url"]
 | |
|     return navbar_logo_url
 | |
| 
 | |
| 
 | |
| def home(request: HttpRequest) -> HttpResponse:
 | |
|     if not settings.ROOT_DOMAIN_LANDING_PAGE:
 | |
|         return home_real(request)
 | |
| 
 | |
|     # If settings.ROOT_DOMAIN_LANDING_PAGE, sends the user the landing
 | |
|     # page, not the login form, on the root domain
 | |
| 
 | |
|     subdomain = get_subdomain(request)
 | |
|     if subdomain != Realm.SUBDOMAIN_FOR_ROOT_DOMAIN:
 | |
|         return home_real(request)
 | |
| 
 | |
|     return hello_view(request)
 | |
| 
 | |
| 
 | |
| @web_public_view
 | |
| def home_real(request: HttpRequest) -> HttpResponse:
 | |
|     # Before we do any real work, check if the app is banned.
 | |
|     client_user_agent = request.META.get("HTTP_USER_AGENT", "")
 | |
|     (insecure_desktop_app, banned_desktop_app, auto_update_broken) = is_outdated_desktop_app(
 | |
|         client_user_agent
 | |
|     )
 | |
|     if banned_desktop_app:
 | |
|         return render(
 | |
|             request,
 | |
|             "zerver/insecure_desktop_app.html",
 | |
|             context={
 | |
|                 "auto_update_broken": auto_update_broken,
 | |
|             },
 | |
|         )
 | |
|     (unsupported_browser, browser_name) = is_unsupported_browser(client_user_agent)
 | |
|     if unsupported_browser:
 | |
|         return render(
 | |
|             request,
 | |
|             "zerver/unsupported_browser.html",
 | |
|             context={
 | |
|                 "browser_name": browser_name,
 | |
|             },
 | |
|         )
 | |
| 
 | |
|     # 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
 | |
| 
 | |
|     if request.user.is_authenticated:
 | |
|         user_profile = request.user
 | |
|         realm = user_profile.realm
 | |
|     else:
 | |
|         # user_profile=None corresponds to the logged-out "web_public" visitor case.
 | |
|         user_profile = None
 | |
|         realm = get_valid_realm_from_request(request)
 | |
| 
 | |
|     update_last_reminder(user_profile)
 | |
| 
 | |
|     statsd.incr("views.home")
 | |
| 
 | |
|     # If a user hasn't signed the current Terms of Service, send them there
 | |
|     if need_accept_tos(user_profile):
 | |
|         return accounts_accept_terms(request)
 | |
| 
 | |
|     narrow, narrow_stream, narrow_topic = detect_narrowed_window(request, user_profile)
 | |
| 
 | |
|     if user_profile is not None:
 | |
|         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()
 | |
|         )
 | |
|         needs_tutorial = user_profile.tutorial_status == UserProfile.TUTORIAL_WAITING
 | |
| 
 | |
|     else:
 | |
|         first_in_realm = False
 | |
|         prompt_for_invites = False
 | |
|         # The current tutorial doesn't super make sense for logged-out users.
 | |
|         needs_tutorial = False
 | |
| 
 | |
|     has_mobile_devices = user_profile is not None and num_push_devices_for_user(user_profile) > 0
 | |
| 
 | |
|     queue_id, page_params = build_page_params_for_home_page_load(
 | |
|         request=request,
 | |
|         user_profile=user_profile,
 | |
|         realm=realm,
 | |
|         insecure_desktop_app=insecure_desktop_app,
 | |
|         has_mobile_devices=has_mobile_devices,
 | |
|         narrow=narrow,
 | |
|         narrow_stream=narrow_stream,
 | |
|         narrow_topic=narrow_topic,
 | |
|         first_in_realm=first_in_realm,
 | |
|         prompt_for_invites=prompt_for_invites,
 | |
|         needs_tutorial=needs_tutorial,
 | |
|     )
 | |
| 
 | |
|     show_invites, show_add_streams = compute_show_invites_and_add_streams(user_profile)
 | |
| 
 | |
|     billing_info = get_billing_info(user_profile)
 | |
| 
 | |
|     request._log_data["extra"] = "[{}]".format(queue_id)
 | |
| 
 | |
|     csp_nonce = secrets.token_hex(24)
 | |
| 
 | |
|     user_permission_info = get_user_permission_info(user_profile)
 | |
| 
 | |
|     navbar_logo_url = compute_navbar_logo_url(page_params)
 | |
| 
 | |
|     response = render(
 | |
|         request,
 | |
|         "zerver/app/index.html",
 | |
|         context={
 | |
|             "user_profile": user_profile,
 | |
|             "page_params": page_params,
 | |
|             "csp_nonce": csp_nonce,
 | |
|             "search_pills_enabled": settings.SEARCH_PILLS_ENABLED,
 | |
|             "show_invites": show_invites,
 | |
|             "show_add_streams": show_add_streams,
 | |
|             "promote_sponsoring_zulip": promote_sponsoring_zulip_in_realm(realm),
 | |
|             "show_billing": billing_info.show_billing,
 | |
|             "corporate_enabled": settings.CORPORATE_ENABLED,
 | |
|             "show_plans": billing_info.show_plans,
 | |
|             "is_owner": user_permission_info.is_realm_owner,
 | |
|             "is_admin": user_permission_info.is_realm_admin,
 | |
|             "is_guest": user_permission_info.is_guest,
 | |
|             "color_scheme": user_permission_info.color_scheme,
 | |
|             "zulip_version": ZULIP_VERSION,
 | |
|             "zulip_merge_base": ZULIP_MERGE_BASE,
 | |
|             "navbar_logo_url": navbar_logo_url,
 | |
|             "show_webathena": user_permission_info.show_webathena,
 | |
|             "embedded": narrow_stream is not None,
 | |
|             "invite_as": PreregistrationUser.INVITE_AS,
 | |
|             "max_file_upload_size_mib": settings.MAX_FILE_UPLOAD_SIZE,
 | |
|         },
 | |
|     )
 | |
|     patch_cache_control(response, no_cache=True, no_store=True, must_revalidate=True)
 | |
|     return response
 | |
| 
 | |
| 
 | |
| @zulip_login_required
 | |
| def desktop_home(request: HttpRequest) -> HttpResponse:
 | |
|     return HttpResponseRedirect(reverse(home))
 |