def wrapper(request, *args, **kwargs): try: callback = getattr(self, view) response = callback(request, *args, **kwargs) varies = getattr(self._meta.cache, "varies", []) if varies: patch_vary_headers(response, varies) if self._meta.cache.cacheable(request, response): if self._meta.cache.cache_control(): patch_cache_control(response, **self._meta.cache.cache_control()) if request.is_ajax(): patch_cache_control(response, no_cache=True) if request.method == "OPTIONS": # response = HttpResponse("") response['Access-Control-Allow-Origin'] = "*" response['Access-Control-Allow-Methods'] = "POST, OPTIONS" response['Access-Control-Allow-Headers'] = "X-Requested-With" response['Access-Control-Max-Age'] = "1800" else: response['Access-Control-Allow-Origin'] = "*" return response except (BadRequest, ApiFieldError), e: return http.HttpBadRequest(json.dumps({"status":False,"code": 400, "message": str(e) }))
def fudge_headers(response, stats): """Alter cache headers. Don't cache content where data could be missing.""" if not stats: add_never_cache_headers(response) else: seven_days = 60 * 60 * 24 * 7 patch_cache_control(response, max_age=seven_days)
def add_shared_cache_control(response, **kwargs): """ Adds a Cache-Control header for shared caches, like CDNs, to the provided response. Default settings (which can be overridden or extended): - max-age=0 - Don't use browser cache without asking if still valid - s-maxage=CACHE_CONTROL_DEFAULT_SHARED_MAX_AGE - Cache in the shared cache for the default perioid of time - public - Allow intermediate proxies to cache response """ nocache = (response.has_header('Cache-Control') and ('no-cache' in response['Cache-Control'] or 'no-store' in response['Cache-Control'])) if nocache: return # Set the default values. cc_kwargs = { 'public': True, 'max_age': 0, 's_maxage': settings.CACHE_CONTROL_DEFAULT_SHARED_MAX_AGE } # Override the default values and/or add new ones. cc_kwargs.update(kwargs) patch_cache_control(response, **cc_kwargs)
def qrcode(req, width): import qr url = req.GET.get('url') if url is None: raise Http404 try: data = url.encode('ascii') except UnicodeError: # only supports URLs properly urlencoded raise Http404 if width == "480": magnify = 8 else: magnify = 4 buf = StringIO() try: qr.qrcode(data, buf, format=qr.GIF, magnify=magnify) except ValueError: # qr module wasn't be compiled with GD library raise Http404 content = buf.getvalue() CACHE_TIMEOUT = 86400 res = HttpResponse(content, content_type='image/gif') res['Content-Length'] = str(len(content)) res['ETag'] = '"%s"' % md5(content).hexdigest() res['Last-Modified'] = http_date() res['Expires'] = http_date(time.time() + CACHE_TIMEOUT) patch_cache_control(res, max_age=CACHE_TIMEOUT) return res
def process_request(self, request): if not MEDIA_DEV_MODE: return # We refresh the dev names only once every 30 seconds, so all # media_url() calls are cached. # This allows for every "page load" to go very quickly, but does not require a # server restart to get new file paths and versions. global _REFRESH_DEV_NAMES_DONE_AT if (_REFRESH_DEV_NAMES_DONE_AT + 15) < time.time(): _refresh_dev_names() _REFRESH_DEV_NAMES_DONE_AT = time.time() if not request.path.startswith(DEV_MEDIA_URL): return filename = request.path[len(DEV_MEDIA_URL) :] try: backend = _backend_mapping[filename] except KeyError: raise Http404('No such media file "%s"' % filename) content, mimetype = backend.get_dev_output(filename) if isinstance(content, unicode): content = content.encode("utf-8") response = HttpResponse(content, content_type=mimetype) response["Content-Length"] = len(content) # Cache manifest files MUST NEVER be cached or you'll be unable to update # your cached app!!! if response["Content-Type"] != "text/cache-manifest" and response.status_code == 200: patch_cache_control(response, public=True, max_age=self.MAX_AGE) response["Expires"] = http_date(time.time() + self.MAX_AGE) return response
def process_response(self, request, response): patch_cache_control(response, no_cache=True, no_store=True, must_revalidate=True, ) return response
def tracker_response(request, template='tracker/index.html', qdict=None, status=200, delegate=None): qdict = tracker_context(request, qdict) try: starttime = time.time() if delegate: resp = delegate(request, template, context=qdict, status=status) else: resp = render(request, template, context=qdict, status=status) render_time = time.time() - starttime if 'queries' in request.GET and request.user.has_perm('tracker.view_queries'): resp = HttpResponse(json.dumps(connection.queries, ensure_ascii=False, indent=1), content_type='application/json;charset=utf-8') cache_control = {} if request.user.is_anonymous(): cache_control['public'] = True else: resp['X-Render-Time'] = render_time cache_control['private'] = True cache_control['max-age'] = 0 patch_cache_control(resp, **cache_control) return resp except Exception, e: if request.user.is_staff and not settings.DEBUG: return HttpResponse(unicode(type(e)) + '\n\n' + unicode(e), content_type='text/plain', status=500) raise
def update_response_headers(request, response): if not getattr(response, "override_serialization", False): serialization = request.serialization if serialization == "xml": response["Content-Type"] = "application/xml; charset=UTF-8" elif serialization == "json": response["Content-Type"] = "application/json; charset=UTF-8" elif serialization == "text": response["Content-Type"] = "text/plain; charset=UTF-8" else: raise ValueError("Unknown serialization format '%s'" % serialization) if settings.DEBUG or getattr(settings, "TEST", False): response["Date"] = format_date_time(time()) if not response.has_header("Content-Length") and \ isinstance(response, HttpResponse): response["Content-Length"] = len(response.content) cache.add_never_cache_headers(response) # Fix Vary and Cache-Control Headers. Issue: #3448 cache.patch_vary_headers(response, ('X-Auth-Token',)) cache.patch_cache_control(response, no_cache=True, no_store=True, must_revalidate=True)
def process_request(self, request): if not MEDIA_DEV_MODE: return # We refresh the dev names only once for the whole request, so all # media_url() calls are cached. _refresh_dev_names() if not request.path.startswith(DEV_MEDIA_URL): return filename = request.path[len(DEV_MEDIA_URL):] try: backend = _backend_mapping[filename] except KeyError: raise Http404('The mediagenerator could not find the media file "%s"' % filename) content, mimetype = backend.get_dev_output(filename) if not mimetype: mimetype = 'application/octet-stream' if isinstance(content, unicode): content = content.encode('utf-8') if mimetype.startswith('text/') or mimetype in TEXT_MIME_TYPES: mimetype += '; charset=utf-8' response = HttpResponse(content, content_type=mimetype) response['Content-Length'] = len(content) # Cache manifest files MUST NEVER be cached or you'll be unable to update # your cached app!!! if response['Content-Type'] != 'text/cache-manifest' and \ response.status_code == 200: patch_cache_control(response, public=True, max_age=self.MAX_AGE) response['Expires'] = http_date(time.time() + self.MAX_AGE) return response
def get(self, request, *args, **kwargs): cache_max_age = 31536000 image_type = kwargs.get('image_type') image_hash = kwargs.get('hash') size = kwargs.get('size') not_found_response = JsonResponse({'detail': 'Not Found.'}, status=status.HTTP_404_NOT_FOUND) try: if image_type == EventImage.IMAGE_TYPE_IN_URL: image_url = EventImage.objects.get(hash=image_hash).get_url() elif image_type == PlaceImage.IMAGE_TYPE_IN_URL: image_url = PlaceImage.objects.get(hash=image_hash).get_url() elif image_type == XeroxMachine.IMAGE_TYPE_IN_URL: image_url = XeroxMachine().get(image_hash) cache_max_age = 604800 except ObjectDoesNotExist: return not_found_response try: image = transform_external_image(image_url, size) response = HttpResponse(content_type='image/jpeg') image.save(response, 'jpeg') except IOError: return not_found_response patch_cache_control(response, max_age=cache_max_age) return response
def update_response_headers(request, response): if not getattr(response, "override_serialization", False): serialization = request.serialization if serialization == "xml": response["Content-Type"] = "application/xml; charset=UTF-8" elif serialization == "json": response["Content-Type"] = "application/json; charset=UTF-8" elif serialization == "text": response["Content-Type"] = "text/plain; charset=UTF-8" else: raise ValueError("Unknown serialization format '%s'" % serialization) if settings.DEBUG or getattr(settings, "TEST", False): response["Date"] = format_date_time(time()) if not response.has_header("Content-Length"): _base_content_is_iter = getattr(response, '_base_content_is_iter', None) if (_base_content_is_iter is not None and not _base_content_is_iter): response["Content-Length"] = len(response.content) else: if not (response.has_header('Content-Type') and response['Content-Type'].startswith( 'multipart/byteranges')): # save response content from been consumed if it is an iterator response._container, data = itertools.tee(response._container) response["Content-Length"] = len(str(data)) cache.add_never_cache_headers(response) # Fix Vary and Cache-Control Headers. Issue: #3448 cache.patch_vary_headers(response, ('X-Auth-Token',)) cache.patch_cache_control(response, no_cache=True, no_store=True, must_revalidate=True)
def msgs(request): "List all messages in json format starting just after the last msg_id" if request.method == 'GET': # Check if form has been submitted form = ListMsgsForm(request.GET) if form.is_valid(): # All validation rules pass (msg_id is int) m_id = form.cleaned_data['msg_id'] # Get 10 latest msgs since ``m_id`` msg_author = Msg.objects.latest_msgs(m_id, 10).values('id', 'msg_text', 'author__name') # Convert msgs to list msg_list = list(msg_author) # Format data into json data_json = json.dumps(msg_list, indent=2) # Output response as json content response = HttpResponse(data_json, content_type='text/json') # Make sure browser doesn't cache this request (not sure if needed) patch_cache_control(response, no_cache=True) return response else: pass else: pass raise Http404
def animated(request, id, extension): image_id = int(id.replace("/", "")) try: image = Image.objects.get(id=image_id) except Image.DoesNotExist: raise Http404 if not image.animated: raise Http404 if check_not_modified(request=request, last_modified=image.last_modified): # Avoid hitting storage backend on cache update resp = HttpResponseNotModified() else: try: image_blob = image.get_animated(extension=extension) except Exception: logger.exception("Animated error") return HttpResponseServerError("Animated error") resp = _image_response(image_blob, extension=extension) patch_cache_control(resp, max_age=settings.BETTY_CACHE_CROP_SEC) return resp
def process_response(self, request, response): if request.is_ajax(): # IE excessively caches XMLHttpRequests, so we're disabling # the browser cache here. # See http://www.enhanceie.com/ie/bugs.asp for details. patch_cache_control(response, no_cache=True) return response
def process_request(self, request): if not MEDIA_DEV_MODE: return # We refresh the dev names only once for the whole request, so all # media_url() calls are cached. _refresh_dev_names() if not request.path.startswith(DEV_MEDIA_URL): return filename = request.path[len(DEV_MEDIA_URL):] try: backend = _backend_mapping[filename] except KeyError: raise Http404('No such media file "%s"' % filename) content, mimetype = backend.get_dev_output(filename) response = HttpResponse(content, content_type=mimetype) response['Content-Length'] = len(content) # Cache manifest files MUST NEVER be cached or you'll be unable to update # your cached app!!! if response['Content-Type'] != 'text/cache-manifest' and \ response.status_code == 200: patch_cache_control(response, public=True, max_age=self.MAX_AGE) response['Expires'] = http_date(time.time() + self.MAX_AGE) return response
def process_request(self, request): # Find locale, app prefixer = urlresolvers.Prefixer(request) if settings.DEBUG: redirect_type = HttpResponseRedirect else: redirect_type = HttpResponsePermanentRedirect urlresolvers.set_url_prefix(prefixer) full_path = prefixer.fix(prefixer.shortened_path) if (prefixer.app == amo.MOBILE.short and request.path.rstrip('/').endswith('/' + amo.MOBILE.short)): return redirect_type(request.path.replace('/mobile', '/android')) if ('lang' in request.GET and not re.match( settings.SUPPORTED_NONAPPS_NONLOCALES_REGEX, prefixer.shortened_path)): # Blank out the locale so that we can set a new one. Remove lang # from query params so we don't have an infinite loop. prefixer.locale = '' new_path = prefixer.fix(prefixer.shortened_path) query = dict((force_bytes(k), request.GET[k]) for k in request.GET) query.pop('lang') return redirect_type(urlparams(new_path, **query)) if full_path != request.path: query_string = request.META.get('QUERY_STRING', '') full_path = urllib.quote(full_path.encode('utf-8')) if query_string: query_string = query_string.decode('utf-8', 'ignore') full_path = u'%s?%s' % (full_path, query_string) response = redirect_type(full_path) # Cache the redirect for a year. if not settings.DEBUG: patch_cache_control(response, max_age=60 * 60 * 24 * 365) # Vary on Accept-Language or User-Agent if we changed the locale or # app. old_app = prefixer.app old_locale = prefixer.locale new_locale, new_app, _ = prefixer.split_path(full_path) if old_locale != new_locale: patch_vary_headers(response, ['Accept-Language']) if old_app != new_app: patch_vary_headers(response, ['User-Agent']) return response request.path_info = '/' + prefixer.shortened_path request.LANG = prefixer.locale or prefixer.get_language() activate(request.LANG) request.APP = amo.APPS.get(prefixer.app, amo.FIREFOX) # Match legacy api requests too - IdentifyAPIRequestMiddleware is v3+ # TODO - remove this when legacy_api goes away # https://github.com/mozilla/addons-server/issues/9274 request.is_legacy_api = request.path_info.startswith('/api/')
def border(req, style, rgb): import gd rgb = tuple(map(lambda x: int(x, 16), (rgb[0:2], rgb[2:4], rgb[4:6]))) try: width = int(req.GET.get('w', 228)) except (ValueError, TypeError): width = 228 try: height = int(req.GET.get('h', 1)) except (ValueError, TypeError): height = 1 if width < 1 or height < 1: raise Http404 if rgb != (0, 0, 0): # if line is black, then use white(#FFFFF) as background color backcolor = (255, 255, 255) else: backcolor = (0, 0, 0) # TODO # check display width img = gd.image((width, height)) back = img.colorAllocate(backcolor) img.colorTransparent(back) color = img.colorAllocate(rgb) if style == 'dotted': pattern = (color, color, back, back) elif style == 'dashed': pattern = (color, color, color, back, back, back) else: # solid pattern = (color,) img.setStyle(pattern) for y in xrange(height): img.line((0, y), (width, y), gd.gdStyled) fp = StringIO() img.writeGif(fp) content = fp.getvalue() fp.close() content_type = 'image/gif' res = HttpResponse(content, content_type=content_type) res['Content-Type'] = content_type res['Content-Length'] = str(len(content)) res['ETag'] = '"%s"' % md5(content).hexdigest() res['Last-Modified'] = http_date() res['Expires'] = http_date(time.time() + CACHE_TIMEOUT) patch_cache_control(res, max_age=CACHE_TIMEOUT) return res
def get(self,request,*args,**kwargs): response=TemplateResponse(request,self.template_name,{'number':1,'number_2':2}) response.__setitem__('x-uuid',uuid.uuid4().hex) #set header explicitly response.__setitem__('status',200) response.__setitem__('page_id',str(uuid.uuid4().hex)) patch_vary_headers(response,['Etag','Cookie','User-Agent']) patch_cache_control(response) return response
def render_listview_to_response(self, request=None): """ Renders the listview to a response, preventing caching in the process. """ response = HttpResponse(unicode(self.render_listview())) patch_cache_control(response, no_cache=True, no_store=True, max_age=0, must_revalidate=True) return response
def wrapper(request, *args, **kwargs): callback = getattr(self, view) response = callback(request, *args, **kwargs) if request.is_ajax(): patch_cache_control(response, no_cache=True) return response
def handle_cache_control(self, request, response): if request.is_ajax() and not response.has_header("Cache-Control"): # IE excessively caches XMLHttpRequests, so we're disabling # the browser cache here. # See http://www.enhanceie.com/ie/bugs.asp for details. patch_cache_control(response, no_cache=True) return response
def process_response(self, request, response): if 'Expires' not in response and \ 'Cache-Control' not in response and \ hasattr(request, 'session') and \ request.user.is_authenticated(): patch_cache_control(response, no_store=True, no_cache=True, must_revalidate=True, max_age=0) return response
def _cache_controlled(request, *args, **kw): response = viewfunc(request, *args, **kw) copied = kwargs if kwargs.get("max_age") and callable(kwargs["max_age"]): max_age = kwargs["max_age"](request, *args, **kw) # Can't re-use, have to create a shallow clone. copied = dict(kwargs, max_age=max_age) patch_cache_control(response, **copied) return response
def process_response(self, request, response): if ( "Expires" not in response and "Cache-Control" not in response and hasattr(request, "session") and request.user.is_authenticated() ): patch_cache_control(response, no_store=True, no_cache=True, must_revalidate=True, max_age=0) return response
def esi(request, app_label=None, model_name=None, object_id=None, timeout=900, template=None): """ Using the app_label, module_name and object_id parameters create an object and render it using `template_name` or `template_dir`. Parameters: :app_label: `Name of a app (i.e. auth)` :model_name: `Name of a model (i.e. user)` :object_id: `This's objects primary key id` :timeout: `Time in secondsfor this objects max_age. [default 900]` :template: `a path to a template directory or a template` Context: `object` The object that was returned `model_name` If you are using a User object `user` will be in the context. Templates: if `template` is a directory: A file called `app_label`.`model_name`.html ,along with any other models' content types that the object extends, will be looked for in the `template` directory falling back to `template`/default.html if none can be found. if `template` is a file: The file `template` will be loaded and rendered. If no template is provided `settings`.ESI_DEFAULT_TEMPLATE and `settings`.ESI_DEFAULT_DIRECTORY will be checked with the same logic as above. """ default_template = getattr(settings, 'ESI_DEFAULT_TEMPLATE', None) default_template_dir = getattr(settings, 'ESI_DEFAULT_DIRECTORY', None) obj, model = get_object(app_label, model_name, object_id) template_list = [] if template is not None: template_list.extend(get_template_list(obj, template)) else: if default_template is not None: temp_t = get_template_list(obj, default_template) if temp_t is not None: template_list.extend(get_template_list(obj, default_template)) if default_template_dir is not None and len(template_list) == 0: temp_t = get_template_list(obj, default_template_dir) if temp_t is not None: template_list.extend(get_template_list(obj, default_template_dir)) if len(template_list) == 0: raise Http404 t = loader.select_template(template_list) context = { 'object': obj, model_name: obj } c = RequestContext(request, context) response = HttpResponse(t.render(c)) populate_xheaders(request, response, model, getattr(obj, model._meta.pk.name)) patch_cache_control(response, max_age=timeout) return response
def create_response(self, request, data, **response_kwargs): response = (super(ClientCachedResource, self) .create_response(request, data, **response_kwargs)) if (request.method == 'GET' and response.status_code == 200 and hasattr(self.Meta, 'cache_control')): patch_cache_control(response, **self.Meta.cache_control) return response
def blocklist_json(request): key = 'blocklist:json' cache.add('blocklist:keyversion', 1) version = cache.get('blocklist:keyversion') response = cache.get(key, version=version) if response is None: response = _blocklist_json(request) cache.set(key, response, 60 * 60, version=version) patch_cache_control(response, max_age=60 * 60) return response
def process_response(self, request, response): if getattr(response, "_unvarying", False): try: del response["Vary"] except KeyError: pass else: from django.utils.cache import patch_cache_control patch_cache_control(response, private=True) return response
def process_request(self, request): # Find locale, app prefixer = urlresolvers.Prefixer(request) if settings.DEBUG: redirect_type = HttpResponseRedirect else: redirect_type = HttpResponsePermanentRedirect urlresolvers.set_url_prefix(prefixer) full_path = prefixer.fix(prefixer.shortened_path) # In mkt, don't vary headers on User-Agent. with_app = not getattr(settings, 'MARKETPLACE', False) if (prefixer.app == amo.MOBILE.short and request.path.rstrip('/').endswith('/' + amo.MOBILE.short)): # TODO: Eventually put MOBILE in RETIRED_APPS, but not yet. return redirect_type(request.path.replace('/mobile', '/android')) if 'lang' in request.GET: # Blank out the locale so that we can set a new one. Remove lang # from query params so we don't have an infinite loop. prefixer.locale = '' new_path = prefixer.fix(prefixer.shortened_path) query = dict((smart_str(k), request.GET[k]) for k in request.GET) query.pop('lang') return redirect_type(urlparams(new_path, **query)) if full_path != request.path: query_string = request.META.get('QUERY_STRING', '') full_path = urllib.quote(full_path.encode('utf-8')) if query_string: full_path = "%s?%s" % (full_path, query_string) response = redirect_type(full_path) # Cache the redirect for a year. if not settings.DEBUG: patch_cache_control(response, max_age=60 * 60 * 24 * 365) # Vary on Accept-Language or User-Agent if we changed the locale or # app. old_app = prefixer.app old_locale = prefixer.locale new_locale, new_app, _ = prefixer.split_path(full_path) if old_locale != new_locale: patch_vary_headers(response, ['Accept-Language']) if with_app and old_app != new_app: patch_vary_headers(response, ['User-Agent']) return response request.path_info = '/' + prefixer.shortened_path tower.activate(prefixer.locale) request.APP = amo.APPS.get(prefixer.app, amo.FIREFOX) request.LANG = prefixer.locale
def process_response(self, request, response): if request.is_ajax() and response.status_code in (301, 302): return HttpResponse(json.dumps({ 'location': response['Location'], 'status_code': response.status_code, 'redirect': True, })) if hasattr(request, "_feincms_page"): patch_cache_control(response, max_age=60) patch_vary_headers(response, ['Accept', 'X-Requested-With']) return response
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 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]] 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'], 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_authentication_methods=register_ret[ 'realm_authentication_methods'], realm_create_stream_by_admins_only=register_ret[ 'realm_create_stream_by_admins_only'], realm_add_emoji_by_admins_only=register_ret[ 'realm_add_emoji_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'], realm_waiting_period_threshold=register_ret[ 'realm_waiting_period_threshold'], 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_bots=list(get_cross_realm_dicts()), use_websockets=settings.USE_WEBSOCKETS, # 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, 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), avatar_source=user_profile.avatar_source, 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 _cache_controlled(request, *args, **kw): response = viewfunc(request, *args, **kw) if hasattr(response, 'has_header'): # check if response is httpresponse patch_cache_control(response, **kwargs) return response
def post(self, request, frmName, target=None): try: if not request.session.get('conUser'): raise SessionError("Session invalid or expired.") if request.path_info.endswith(('.html', '.html/')): template = [ item['html'] for item in self.MENU_ITEMS if item['name'] == frmName ][0] request.session['referer'] = request.META[ 'HTTP_REFERER'] #stash reference from initial page load response = render(request, template, dict(frmName=frmName, pages=self.MENU_ITEMS)) response['Pragma'] = 'no-cache' response['Expires'] = '0' patch_cache_control(response, no_cache=True, no_store=True, must_revalidate=True, max_age=0) return response if not target: return getattr(self, 'ajax_form')(request, frmName) elif target.startswith('fld_'): rc = getattr(self, 'ajax_' + target)(request, frmName, target[4:]) return rc else: return getattr(self, 'ajax_' + target)(request, frmName) except SessionError as e: if 'application/json' in request.META['HTTP_ACCEPT']: return jsonErrorResponse( dict(redirectTo=reverse('capture:sessionErr')), e.message) else: return HttpResponseRedirect(reverse('capture:sessionErr')) except ServerDbError as e: trace = [x for x in e.message.split('\n')] oraErr, oraMsg = trace[0].split(': ') msg = "Database error occurred while processing form ({}/{})\n{}" #logging.debug(msg, exc_info=True) if 'application/json' in request.META['HTTP_ACCEPT']: return jsonErrorResponse( dict(errTitle=e.errTitle, errMsg=oraMsg), msg.format(frmName, target, e.message)) else: request.session['systemError'] = dict(msg=msg.format( frmName, target, oraMsg), trace=trace) return HttpResponseRedirect(reverse('capture:systemErr')) except Exception as e: msg = "AQC-0003: Exception while processing form ({}/{})".format( frmName, target) logging.debug(msg, exc_info=True) request.session['systemError'] = dict(msg=msg, trace=traceback.format_exc()) if 'application/json' in request.META['HTTP_ACCEPT']: return jsonErrorResponse( dict(redirectTo=reverse('capture:systemErr')), msg) else: return HttpResponseRedirect(reverse('capture:systemErr'))
def download_image(request, datafile_id, region, size, rotation, quality, format=None): # @ReservedAssignment # Get datafile (and return an empty response if absent) try: datafile = DataFile.objects.get(pk=datafile_id) except DataFile.DoesNotExist: return HttpResponse('') is_public = datafile.is_public() if not is_public: # Check users has access to datafile if not has_datafile_download_access(request=request, datafile_id=datafile.id): return HttpResponse('') buf = BytesIO() try: file_obj = datafile.get_image_data() if file_obj is None: return HttpResponse('') from contextlib import closing with closing(file_obj) as f: with Image(file=f) as img: if len(img.sequence) > 1: img = Image(img.sequence[0]) # Handle region if region != 'full': x, y, w, h = map(int, region.split(',')) img.crop(x, y, width=w, height=h) # Handle size if size != 'full': # Check the image isn't empty if 0 in (img.height, img.width): return _bad_request('size', 'Cannot resize empty image') # Attempt resize if not _do_resize(img, size): return _bad_request('size', 'Invalid size argument: %s' % size) # Handle rotation if rotation: img.rotate(float(rotation)) # Handle quality (mostly by rejecting it) if quality not in ['native', 'color']: return _get_iiif_error( 'quality', 'This server does not support greyscale or bitonal quality.') # Handle format if format: mimetype = mimetypes.types_map['.%s' % format.lower()] img.format = format if mimetype not in ALLOWED_MIMETYPES: return _invalid_media_response() else: mimetype = datafile.get_mimetype() # If the native format is not allowed, pretend it doesn't exist. if mimetype not in ALLOWED_MIMETYPES: return HttpResponse('') img.save(file=buf) response = HttpResponse(buf.getvalue(), content_type=mimetype) response['Content-Disposition'] = \ 'inline; filename="%s.%s"' % (datafile.filename, format) # Set Cache if is_public: patch_cache_control(response, public=True, max_age=MAX_AGE) else: patch_cache_control(response, private=True, max_age=MAX_AGE) return response except WandException: return HttpResponse('') except ValueError: return HttpResponse('') except IOError: return HttpResponse('')
def wrapper(request, *args, **kwargs): try: callback = getattr(self, view) response = callback(request, *args, **kwargs) # Our response can vary based on a number of factors, use # the cache class to determine what we should ``Vary`` on so # caches won't return the wrong (cached) version. varies = getattr(self._meta.cache, "varies", []) if varies: patch_vary_headers(response, varies) if self._meta.cache.cacheable(request, response): if self._meta.cache.cache_control(): # If the request is cacheable and we have a # ``Cache-Control`` available then patch the header. patch_cache_control(response, **self._meta.cache.cache_control()) if request.is_ajax( ) and not response.has_header("Cache-Control"): # IE excessively caches XMLHttpRequests, so we're disabling # the browser cache here. # See http://www.enhanceie.com/ie/bugs.asp for details. patch_cache_control(response, no_cache=True) return response except (BadRequest, fields.ApiFieldError) as e: data = { "error": sanitize(e.args[0]) if getattr(e, 'args') else '' } return self.error_response(request, data, response_class=http.HttpBadRequest) except ValidationError as e: data = {"error": sanitize(e)} return self.error_response(request, data, response_class=http.HttpBadRequest) except Exception as e: if hasattr(e, 'response'): return e.response # A real, non-expected exception. # Handle the case where the full traceback is more helpful # than the serialized error. if settings.DEBUG and getattr(settings, 'TASTYPIE_FULL_DEBUG', False): raise # Re-raise the error to get a proper traceback when the error # happend during a test case if request.META.get('SERVER_NAME') == 'testserver': raise # Rather than re-raising, we're going to things similar to # what Django does. The difference is returning a serialized # error message. return self._handle_500(request, e)
def details(request, slug): """ The main view of the Django-CMS! Takes a request and a slug, renders the page. """ response_timestamp = now() if get_cms_setting("PAGE_CACHE") and ( not hasattr(request, 'toolbar') or (not request.toolbar.edit_mode_active and not request.toolbar.show_toolbar and not request.user.is_authenticated())): cache_content = get_page_cache(request) if cache_content is not None: content, headers, expires_datetime = cache_content response = HttpResponse(content) response._headers = headers # Recalculate the max-age header for this cached response max_age = int((expires_datetime - response_timestamp).total_seconds() + 0.5) patch_cache_control(response, max_age=max_age) return response # Get a Page model object from the request site = get_current_site() page = get_page_from_request(request, use_path=slug) toolbar = get_toolbar_from_request(request) tree_nodes = TreeNode.objects.get_for_site(site) if not page and not slug and not tree_nodes.exists(): # render the welcome page if the requested path is root "/" # and there's no pages return _render_welcome_page(request) if not page: # raise 404 _handle_no_page(request) request.current_page = page if hasattr(request, 'user') and request.user.is_staff: user_languages = get_language_list(site_id=site.pk) else: user_languages = get_public_languages(site_id=site.pk) request_language = get_language_from_request(request, check_path=True) if not page.is_home and request_language not in user_languages: # The homepage is treated differently because # when a request goes to the root of the site (/) # without a language, Django will redirect to the user's # browser language which might not be a valid cms language, # this means we need to correctly redirect that request. return _handle_no_page(request) # get_published_languages will return all languages in draft mode # and published only in live mode. # These languages are then filtered out by the user allowed languages available_languages = [ language for language in user_languages if language in list(page.get_published_languages()) ] own_urls = [ request.build_absolute_uri(request.path), '/%s' % request.path, request.path, ] try: redirect_on_fallback = get_redirect_on_fallback(request_language, site_id=site.pk) except LanguageError: redirect_on_fallback = False if request_language not in user_languages: # Language is not allowed # Use the default site language default_language = get_default_language_for_site(site.pk) fallbacks = get_fallback_languages(default_language, site_id=site.pk) fallbacks = [default_language] + fallbacks else: fallbacks = get_fallback_languages(request_language, site_id=site.pk) # Only fallback to languages the user is allowed to see fallback_languages = [ language for language in fallbacks if language != request_language and language in available_languages ] language_is_unavailable = request_language not in available_languages if language_is_unavailable and not fallback_languages: # There is no page with the requested language # and there's no configured fallbacks return _handle_no_page(request) elif language_is_unavailable and (redirect_on_fallback or page.is_home): # There is no page with the requested language and # the user has explicitly requested to redirect on fallbacks, # so redirect to the first configured / available fallback language fallback = fallback_languages[0] redirect_url = page.get_absolute_url(fallback, fallback=False) else: page_path = page.get_absolute_url(request_language) page_slug = page.get_path(request_language) or page.get_slug( request_language) if slug and slug != page_slug and request.path[:len(page_path )] != page_path: # The current language does not match its slug. # Redirect to the current language. return HttpResponseRedirect(page_path) # Check if the page has a redirect url defined for this language. redirect_url = page.get_redirect(request_language, fallback=False) or '' redirect_url = _clean_redirect_url(redirect_url, request_language) if redirect_url: if request.user.is_staff and toolbar.edit_mode_active: toolbar.redirect_url = redirect_url elif redirect_url not in own_urls: # prevent redirect to self return HttpResponseRedirect(redirect_url) # permission checks if page.login_required and not request.user.is_authenticated(): return redirect_to_login(urlquote(request.get_full_path()), settings.LOGIN_URL) if hasattr(request, 'toolbar'): request.toolbar.set_object(page) structure_requested = get_cms_setting( 'CMS_TOOLBAR_URL__BUILD') in request.GET if user_can_change_page(request.user, page) and structure_requested: return render_object_structure(request, page) return render_page(request, page, current_language=request_language, slug=slug)
def handler404(request, exception=None, template_name="dpaste/404.html"): context = {} context.update(config.extra_template_context) response = render(request, template_name, context, status=404) patch_cache_control(response, max_age=config.CACHE_TIMEOUT) return response
def _cache_controlled(request, *args, **kw): max_age = calculate_max_age() response = viewfunc(request, *args, **kw) patch_cache_control(response, public=True, max_age=max_age) return response
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 # User is logged in and hence no longer `prefers_web_public_view`. if "prefers_web_public_view" in request.session.keys(): del request.session["prefers_web_public_view"] else: realm = get_valid_realm_from_request(request) # TODO: Ideally, we'd open Zulip directly as a spectator if # the URL had clicked a link to content on a web-public # stream. We could maybe do this by parsing `next`, but it's # not super convenient with Zulip's hash-based URL scheme. # The "Access without an account" button on the login page # submits a POST to this page with this hidden field set. if request.POST.get("prefers_web_public_view") == "true": request.session["prefers_web_public_view"] = True # We serve a redirect here, rather than serving a page, to # avoid browser "Confirm form resubmission" prompts on reload. redirect_to = get_safe_redirect_to(request.POST.get("next"), realm.uri) return redirect(redirect_to) prefers_web_public_view = request.session.get( "prefers_web_public_view") if not prefers_web_public_view: # For users who haven't opted into the spectator # experience, we redirect to the login page. return zulip_redirect_to_login(request, settings.HOME_NOT_LOGGED_IN) # For users who have selected public access, we load the # spectator experience. We fall through to the shared code # for loading the application, with user_profile=None encoding # that we're a spectator, not a logged-in user. user_profile = None 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 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, 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, ) log_data = RequestNotes.get_notes(request).log_data assert log_data is not None log_data["extra"] = f"[{queue_id}]" csp_nonce = secrets.token_hex(24) user_permission_info = get_user_permission_info(user_profile) response = render( request, "zerver/app/index.html", context={ "user_profile": user_profile, "page_params": page_params, "csp_nonce": csp_nonce, "color_scheme": user_permission_info.color_scheme, }, ) patch_cache_control(response, no_cache=True, no_store=True, must_revalidate=True) return response
def make_response_cacheable(response): """ Allow response to be public and cached for an hour """ patch_cache_control(response, public=True, max_age=3600) return response
def details(request, slug): """ The main view of the Django-CMS! Takes a request and a slug, renders the page. """ response_timestamp = now() if get_cms_setting("PAGE_CACHE") and ( not hasattr(request, 'toolbar') or (not request.toolbar.edit_mode and not request.toolbar.show_toolbar and not request.user.is_authenticated())): cache_content = get_page_cache(request) if cache_content is not None: content, headers, expires_datetime = cache_content response = HttpResponse(content) response._headers = headers # Recalculate the max-age header for this cached response max_age = int((expires_datetime - response_timestamp).total_seconds() + 0.5) patch_cache_control(response, max_age=max_age) return response # Get a Page model object from the request page = get_page_from_request(request, use_path=slug) if not page: return _handle_no_page(request, slug) current_language = request.GET.get('language', None) if not current_language: current_language = request.POST.get('language', None) if current_language: current_language = get_language_code(current_language) if current_language not in get_language_list(page.site_id): current_language = None if current_language is None: current_language = get_language_code( getattr(request, 'LANGUAGE_CODE', None)) if current_language: current_language = get_language_code(current_language) if current_language not in get_language_list(page.site_id): current_language = None if current_language is None: current_language = get_language_code(get_language()) # Check that the current page is available in the desired (current) language available_languages = [] # this will return all languages in draft mode, and published only in live mode page_languages = list(page.get_published_languages()) if hasattr(request, 'user') and request.user.is_staff: user_languages = get_language_list() else: user_languages = get_public_languages() for frontend_lang in user_languages: if frontend_lang in page_languages: available_languages.append(frontend_lang) # Check that the language is in FRONTEND_LANGUAGES: own_urls = [ 'http%s://%s%s' % ('s' if request.is_secure() else '', request.get_host(), request.path), '/%s' % request.path, request.path, ] if current_language not in user_languages: #are we on root? if not slug: #redirect to supported language languages = [] for language in available_languages: languages.append((language, language)) if languages: # get supported language new_language = get_language_from_request(request) if new_language in get_public_languages(): with force_language(new_language): pages_root = reverse('pages-root') if (hasattr(request, 'toolbar') and request.user.is_staff and request.toolbar.edit_mode): request.toolbar.redirect_url = pages_root elif pages_root not in own_urls: return HttpResponseRedirect(pages_root) elif not hasattr(request, 'toolbar') or not request.toolbar.redirect_url: _handle_no_page(request, slug) else: return _handle_no_page(request, slug) if current_language not in available_languages: # If we didn't find the required page in the requested (current) # language, let's try to find a fallback found = False for alt_lang in get_fallback_languages(current_language): if alt_lang in available_languages: if get_redirect_on_fallback(current_language) or slug == "": with force_language(alt_lang): path = page.get_absolute_url(language=alt_lang, fallback=True) # In the case where the page is not available in the # preferred language, *redirect* to the fallback page. This # is a design decision (instead of rendering in place)). if (hasattr(request, 'toolbar') and request.user.is_staff and request.toolbar.edit_mode): request.toolbar.redirect_url = path elif path not in own_urls: return HttpResponseRedirect(path) else: found = True if not found and (not hasattr(request, 'toolbar') or not request.toolbar.redirect_url): # There is a page object we can't find a proper language to render it _handle_no_page(request, slug) if apphook_pool.get_apphooks(): # There are apphooks in the pool. Let's see if there is one for the # current page # since we always have a page at this point, applications_page_check is # pointless # page = applications_page_check(request, page, slug) # Check for apphooks! This time for real! app_urls = page.get_application_urls(current_language, False) skip_app = False if (not page.is_published(current_language) and hasattr(request, 'toolbar') and request.toolbar.edit_mode): skip_app = True if app_urls and not skip_app: app = apphook_pool.get_apphook(app_urls) pattern_list = [] if app: for urlpatterns in get_app_urls( app.get_urls(page, current_language)): pattern_list += urlpatterns try: view, args, kwargs = resolve('/', tuple(pattern_list)) return view(request, *args, **kwargs) except Resolver404: pass # Check if the page has a redirect url defined for this language. redirect_url = page.get_redirect(language=current_language) if redirect_url: if (is_language_prefix_patterns_used() and redirect_url[0] == "/" and not redirect_url.startswith('/%s/' % current_language)): # add language prefix to url redirect_url = "/%s/%s" % (current_language, redirect_url.lstrip("/")) # prevent redirect to self if hasattr(request, 'toolbar' ) and request.user.is_staff and request.toolbar.edit_mode: request.toolbar.redirect_url = redirect_url elif redirect_url not in own_urls: return HttpResponseRedirect(redirect_url) # permission checks if page.login_required and not request.user.is_authenticated(): return redirect_to_login(urlquote(request.get_full_path()), settings.LOGIN_URL) if hasattr(request, 'toolbar'): request.toolbar.set_object(page) response = render_page(request, page, current_language=current_language, slug=slug) return response
def test(self): request = RequestFactory().get('/') response = my_view(request) max_age = 3600 patch_cache_control(response, max_age=max_age) self.assertEqual(get_max_age(response), max_age)
def dispatch(self, *args, **kwargs): res = super(PaperListView, self).dispatch(*args, **kwargs) patch_cache_control(res, public=True, max_age=24 * 60 * 60) return res
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 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, 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, ) log_data = RequestNotes.get_notes(request).log_data assert log_data is not None log_data["extra"] = f"[{queue_id}]" csp_nonce = secrets.token_hex(24) user_permission_info = get_user_permission_info(user_profile) response = render( request, "zerver/app/index.html", context={ "user_profile": user_profile, "page_params": page_params, "csp_nonce": csp_nonce, "color_scheme": user_permission_info.color_scheme, }, ) patch_cache_control(response, no_cache=True, no_store=True, must_revalidate=True) return response
def home_real(request: 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[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_rec, 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]) register_ret = do_events_register(user_profile, request.client, apply_markdown=True, client_gravatar=True, notification_settings_null=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: # 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"]) # Brand new users get narrowed to PM with welcome-bot needs_tutorial = user_profile.tutorial_status == UserProfile.TUTORIAL_WAITING 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: latest_read = get_usermessage_by_message_id(user_profile, user_profile.pointer) if latest_read is None: # Don't completely fail if your saved pointer ID is invalid logging.warning("User %s has invalid pointer %s" % (user_profile.id, user_profile.pointer)) # We pick a language for the user as follows: # * First priority is the language in the URL, for debugging. # * If not in the URL, we use the language from the user's settings. request_language = translation.get_language_from_path(request.path_info) if request_language is None: request_language = register_ret['default_language'] translation.activate(request_language) # We also save the language to the user's session, so that # something reasonable will happen in logged-in portico pages. request.session[ translation.LANGUAGE_SESSION_KEY] = translation.get_language() two_fa_enabled = settings.TWO_FACTOR_AUTHENTICATION_ENABLED # Pass parameters to the client-side JavaScript code. # These end up in a global JavaScript Object named 'page_params'. page_params = dict( # Server settings. 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, root_domain_uri=settings.ROOT_DOMAIN_URI, max_file_upload_size=settings.MAX_FILE_UPLOAD_SIZE, max_avatar_file_size=settings.MAX_AVATAR_FILE_SIZE, server_generation=settings.SERVER_GENERATION, save_stacktraces=settings.SAVE_FRONTEND_STACKTRACES, warn_no_email=settings.WARN_NO_EMAIL, server_inline_image_preview=settings.INLINE_IMAGE_PREVIEW, server_inline_url_embed_preview=settings.INLINE_URL_EMBED_PREVIEW, password_min_length=settings.PASSWORD_MIN_LENGTH, password_min_guesses=settings.PASSWORD_MIN_GUESSES, jitsi_server_url=settings.JITSI_SERVER_URL, search_pills_enabled=settings.SEARCH_PILLS_ENABLED, server_avatar_changes_disabled=settings.AVATAR_CHANGES_DISABLED, server_name_changes_disabled=settings.NAME_CHANGES_DISABLED, # 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, furthest_read_time=sent_time_in_epoch_seconds(latest_read), has_mobile_devices=num_push_devices_for_user(user_profile) > 0, bot_types=get_bot_types(user_profile), two_fa_enabled=two_fa_enabled, # Adding two_fa_enabled as condition saves us 3 queries when # 2FA is not enabled. two_fa_enabled_user=two_fa_enabled and bool(default_device(user_profile)), ) undesired_register_ret_fields = [ 'streams', ] for field_name in set( register_ret.keys()) - set(undesired_register_ret_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 = narrow_stream.recipient 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["pointer"] = initial_pointer page_params["have_initial_messages"] = (initial_pointer != -1) page_params["enable_desktop_notifications"] = False statsd.incr('views.home') show_invites, show_add_streams = compute_show_invites_and_add_streams( user_profile) show_billing = False show_plans = False if settings.CORPORATE_ENABLED: from corporate.models import Customer, CustomerPlan if user_profile.is_billing_admin or user_profile.is_realm_admin: customer = Customer.objects.filter( realm=user_profile.realm).first() if customer is not None and CustomerPlan.objects.filter( customer=customer).exists(): show_billing = True if user_profile.realm.plan_type == Realm.LIMITED: show_plans = True request._log_data['extra'] = "[%s]" % (register_ret["queue_id"], ) page_params['translation_data'] = {} if request_language != 'en': page_params['translation_data'] = get_language_translation_data( request_language) csp_nonce = generate_random_token(48) emojiset = user_profile.emojiset if emojiset == UserProfile.TEXT_EMOJISET: # If current emojiset is `TEXT_EMOJISET`, then fallback to # GOOGLE_EMOJISET for picking which spritesheet's CSS to # include (and thus how to display emojis in the emoji picker # and composebox typeahead). emojiset = UserProfile.GOOGLE_BLOB_EMOJISET navbar_logo_url = compute_navbar_logo_url(page_params) response = render( request, 'zerver/app/index.html', context={ 'user_profile': user_profile, 'emojiset': emojiset, 'page_params': page_params, 'csp_nonce': csp_nonce, 'avatar_url': avatar_url(user_profile), 'show_debug': settings.DEBUG and ('show_debug' in request.GET), 'search_pills_enabled': settings.SEARCH_PILLS_ENABLED, 'show_invites': show_invites, 'show_add_streams': show_add_streams, 'show_billing': show_billing, 'show_plans': show_plans, 'is_admin': user_profile.is_realm_admin, 'is_guest': user_profile.is_guest, 'night_mode': user_profile.night_mode, 'navbar_logo_url': navbar_logo_url, 'show_webathena': user_profile.realm.webathena_enabled, 'embedded': narrow_stream is not None, 'invite_as': PreregistrationUser.INVITE_AS, 'max_file_upload_size': settings.MAX_FILE_UPLOAD_SIZE, }, ) patch_cache_control(response, no_cache=True, no_store=True, must_revalidate=True) return response
contents = context.data() for name in names[1:]: name = os.path.join("%s/" % base, name) # TODO: warn if mimetype of names[1:] is different from names[0] try: context = repo_context[name] except KeyError, e: raise Http404("No resource '%s'" % name) contents += context.data() response = HttpResponse(contents, mimetype=mimetype) response["Content-Length"] = len(contents) response["Cache-Control"] = "public" # Cache if revision: # cache for a long time WEEK = 60 * 60 * 24 * 7 ttl = 52 * WEEK else: # do not cache (revision may have been 'tip' or somesuch) ttl = 0 response['ETag'] = '"%s"' % md5_constructor(response.content).hexdigest() response['Expires'] = http_date(time.time() + ttl) cache.patch_cache_control(response, max_age=ttl) return response
def finalize_response(self, request, response, *args, **kwargs): response = super(StaticCategoryView, self).finalize_response(request, response, *args, **kwargs) patch_cache_control(response, max_age=60 * 60 * 6) return response
def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) patch_cache_control(self, public=True, max_age=settings.PERMANENT_REDIRECT_CACHE_TIME)
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 else: # nocoverage # This code path should not be reachable because of zulip_login_required above. user_profile = None # 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) register_ret = do_events_register(user_profile, request.client, apply_markdown=True, client_gravatar=True, slim_presence=True, notification_settings_null=True, narrow=narrow) user_has_messages = (register_ret['max_message_id'] != -1) update_last_reminder(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: # nocoverage first_in_realm = False prompt_for_invites = False # The current tutorial doesn't super make sense for logged-out users. needs_tutorial = False if user_has_messages and user_profile.pointer == -1: # 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'] furthest_read_time = get_furthest_read_time(user_profile) # We pick a language for the user as follows: # * First priority is the language in the URL, for debugging. # * If not in the URL, we use the language from the user's settings. request_language = translation.get_language_from_path(request.path_info) if request_language is None: request_language = register_ret['default_language'] translation.activate(request_language) # We also save the language to the user's session, so that # something reasonable will happen in logged-in portico pages. request.session[translation.LANGUAGE_SESSION_KEY] = translation.get_language() two_fa_enabled = settings.TWO_FACTOR_AUTHENTICATION_ENABLED and user_profile is not None # Pass parameters to the client-side JavaScript code. # These end up in a global JavaScript Object named 'page_params'. page_params = dict( # Server settings. debug_mode = settings.DEBUG, test_suite = settings.TEST_SUITE, poll_timeout = settings.POLL_TIMEOUT, insecure_desktop_app = insecure_desktop_app, login_page = settings.HOME_NOT_LOGGED_IN, root_domain_uri = settings.ROOT_DOMAIN_URI, save_stacktraces = settings.SAVE_FRONTEND_STACKTRACES, warn_no_email = settings.WARN_NO_EMAIL, search_pills_enabled = settings.SEARCH_PILLS_ENABLED, # 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, furthest_read_time = furthest_read_time, has_mobile_devices = user_profile is not None and num_push_devices_for_user(user_profile) > 0, bot_types = get_bot_types(user_profile), two_fa_enabled = two_fa_enabled, # Adding two_fa_enabled as condition saves us 3 queries when # 2FA is not enabled. two_fa_enabled_user = two_fa_enabled and bool(default_device(user_profile)), ) undesired_register_ret_fields = [ 'streams', ] for field_name in set(register_ret.keys()) - set(undesired_register_ret_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 = narrow_stream.recipient 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["pointer"] = initial_pointer page_params["have_initial_messages"] = (initial_pointer != -1) page_params["enable_desktop_notifications"] = False statsd.incr('views.home') show_invites, show_add_streams = compute_show_invites_and_add_streams(user_profile) show_billing = False show_plans = False if settings.CORPORATE_ENABLED and user_profile is not None: from corporate.models import Customer, CustomerPlan if user_profile.is_billing_admin or user_profile.is_realm_admin: customer = Customer.objects.filter(realm=user_profile.realm).first() if customer is not None and CustomerPlan.objects.filter(customer=customer).exists(): show_billing = True if user_profile.realm.plan_type == Realm.LIMITED: show_plans = True request._log_data['extra'] = "[%s]" % (register_ret["queue_id"],) page_params['translation_data'] = {} if request_language != 'en': page_params['translation_data'] = get_language_translation_data(request_language) csp_nonce = generate_random_token(48) if user_profile is not None: night_mode = user_profile.night_mode is_guest = user_profile.is_guest is_realm_admin = user_profile.is_realm_admin show_webathena = user_profile.realm.webathena_enabled else: # nocoverage night_mode = False is_guest = False is_realm_admin = False show_webathena = False 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, 'show_billing': show_billing, 'corporate_enabled': settings.CORPORATE_ENABLED, 'show_plans': show_plans, 'is_admin': is_realm_admin, 'is_guest': is_guest, 'night_mode': night_mode, 'navbar_logo_url': navbar_logo_url, 'show_webathena': 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
def download_file(request, file_id, download_type=None, **kwargs): """ Download the file identified by `file_id` parameter. If the file is disabled or belongs to an unlisted version, requires an add-on developer or appropriate reviewer for the channel. If the file is deleted or belongs to a deleted version or add-on, reviewers can still access but developers can't. """ def is_appropriate_reviewer(addon, channel): return ( acl.is_reviewer(request, addon) if channel == amo.RELEASE_CHANNEL_LISTED else acl.check_unlisted_addons_viewer_or_reviewer(request) ) file_ = get_object_or_404(File.objects, pk=file_id) # Include deleted add-ons in the queryset, we'll check for that below. addon = get_object_or_404( Addon.unfiltered.all().no_transforms(), pk=file_.version.addon_id ) version = file_.version channel = version.channel if version.deleted or addon.is_deleted: # Only the appropriate reviewer can see deleted things. has_permission = is_appropriate_reviewer(addon, channel) apply_georestrictions = False elif ( addon.is_disabled or file_.status == amo.STATUS_DISABLED or channel == amo.RELEASE_CHANNEL_UNLISTED ): # Only the appropriate reviewer or developers of the add-on can see # disabled or unlisted things. has_permission = is_appropriate_reviewer( addon, channel ) or acl.check_addon_ownership( request, addon, allow_developer=True, allow_mozilla_disabled_addon=True, allow_site_permission=True, ) apply_georestrictions = False else: # Public case: we're either directly downloading the file or # redirecting, but in any case we have permission in the general sense, # though georestrictions are in effect. has_permission = True apply_georestrictions = True region_code = request.META.get('HTTP_X_COUNTRY_CODE', None) # Whether to set Content-Disposition: attachment header or not, to force # the file to be downloaded rather than installed (used by admin/reviewer # tools). attachment = download_type == 'attachment' if not has_permission: log.debug( 'download file {file_id}: addon/version/file not public and ' 'user {user_id} does not have relevant permissions.'.format( file_id=file_id, user_id=request.user.pk ) ) response = http.HttpResponseNotFound() elif ( apply_georestrictions and region_code and AddonRegionalRestrictions.objects.filter( addon=addon, excluded_regions__contains=region_code.upper() ).exists() ): response = http.HttpResponse(status=451) url = 'https://www.mozilla.org/about/policy/transparency/' response['Link'] = f'<{url}>; rel="blocked-by"' else: # We're returning a X-Accel-Redirect, we can set # Content-Disposition: attachment ourselves in HttpResponseXSendFile: # nginx won't override it if present. response = HttpResponseXSendFile( request, file_.current_file_path, content_type='application/x-xpinstall', attachment=attachment, ) # Always add a few headers to the response (even errors). patch_cache_control(response, max_age=60 * 60 * 24) patch_vary_headers(response, ['X-Country-Code']) response['Access-Control-Allow-Origin'] = '*' return response
from django.test import RequestFactory, TestCase from django.utils.cache import get_max_age, patch_cache_control from .views import my_view """ https://docs.djangoproject.com/en/dev/ref/utils/#django.utils.cache.patch_cache_control patch_cache_control(response, **kwargs) """ class Test(TestCase): def test(self): request = RequestFactory().get('/') response = my_view(request) max_age = 3600 patch_cache_control(response, max_age=max_age) self.assertEqual(get_max_age(response), max_age)
def _cache_controlled(request, *args, **kw): response = viewfunc(request, *args, **kw) patch_cache_control(response, **kwargs) return response
def fudge_headers(response, stats): """Alter cache headers. Don't cache content where data could be missing.""" if not stats: add_never_cache_headers(response) else: patch_cache_control(response, max_age=seven_days)
def add_paper_cache_control(response): patch_cache_control(response, public=True, max_age=settings.PAPER_CACHE_SECONDS) return response
def esi(request, app_label=None, model_name=None, object_id=None, timeout=900, template=None): """ Using the app_label, module_name and object_id parameters create an object and render it using `template_name` or `template_dir`. Parameters: :app_label: `Name of a app (i.e. auth)` :model_name: `Name of a model (i.e. user)` :object_id: `This's objects primary key id` :timeout: `Time in secondsfor this objects max_age. [default 900]` :template: `a path to a template directory or a template` Context: `object` The object that was returned `model_name` If you are using a User object `user` will be in the context. Templates: if `template` is a directory: A file called `app_label`.`model_name`.html ,along with any other models' content types that the object extends, will be looked for in the `template` directory falling back to `template`/default.html if none can be found. if `template` is a file: The file `template` will be loaded and rendered. If no template is provided `settings`.ESI_DEFAULT_TEMPLATE and `settings`.ESI_DEFAULT_DIRECTORY will be checked with the same logic as above. """ default_template = getattr(settings, 'ESI_DEFAULT_TEMPLATE', None) default_template_dir = getattr(settings, 'ESI_DEFAULT_DIRECTORY', None) obj, model = get_object(app_label, model_name, object_id) template_list = [] if template is not None: template_list.extend(get_template_list(obj, template)) else: if default_template is not None: temp_t = get_template_list(obj, default_template) if temp_t is not None: template_list.extend(get_template_list(obj, default_template)) if default_template_dir is not None and len(template_list) == 0: temp_t = get_template_list(obj, default_template_dir) if temp_t is not None: template_list.extend( get_template_list(obj, default_template_dir)) if len(template_list) == 0: raise Http404 t = loader.select_template(template_list) context = {'object': obj, model_name: obj} c = RequestContext(request, context) response = HttpResponse(t.render(c)) populate_xheaders(request, response, model, getattr(obj, model._meta.pk.name)) patch_cache_control(response, max_age=timeout) return response
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 else: # nocoverage # This code path should not be reachable because of zulip_login_required above. user_profile = None 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: # nocoverage 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, 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, '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, '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
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 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, 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
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 narrowed to PM with welcome-bot needs_tutorial = user_profile.tutorial_status == UserProfile.TUTORIAL_WAITING 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 # 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] = translation.get_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. 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, root_domain_uri = settings.ROOT_DOMAIN_URI, maxfilesize = settings.MAX_FILE_UPLOAD_SIZE, max_avatar_file_size = settings.MAX_AVATAR_FILE_SIZE, server_generation = settings.SERVER_GENERATION, use_websockets = settings.USE_WEBSOCKETS, save_stacktraces = settings.SAVE_FRONTEND_STACKTRACES, server_inline_image_preview = settings.INLINE_IMAGE_PREVIEW, server_inline_url_embed_preview = settings.INLINE_URL_EMBED_PREVIEW, password_min_length = settings.PASSWORD_MIN_LENGTH, password_min_guesses = settings.PASSWORD_MIN_GUESSES, # 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, furthest_read_time = sent_time_in_epoch_seconds(latest_read), has_mobile_devices = num_push_devices_for_user(user_profile) > 0, ) undesired_register_ret_fields = [ 'streams', ] for field_name in set(register_ret.keys()) - set(undesired_register_ret_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["pointer"] = initial_pointer page_params["have_initial_messages"] = (initial_pointer != -1) page_params["enable_desktop_notifications"] = False 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 request._log_data['extra'] = "[%s]" % (register_ret["queue_id"],) response = render(request, 'zerver/index.html', context={'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, },) patch_cache_control(response, no_cache=True, no_store=True, must_revalidate=True) return response
def decorated_function(*args, **kwargs): request = args[0] response = function(*args, **kwargs) cache.patch_response_headers(response, ttl) cache.patch_cache_control(response, public=True) return response
def qsd(request, url): # Extract the 'action' from the supplied URL if there is one url_parts = url.split('/') page_name = url_parts[-1] page_name_parts = page_name.split('.') if len(page_name_parts) > 1: action = page_name_parts[-1] page_name_base = '.'.join(page_name_parts[:-1]) else: action = 'read' page_name_base = page_name base_url = '/'.join(url_parts[:-1] + [page_name_base]) # Detect edit authorizations have_read = True if not have_read and action == 'read': raise Http403, "You do not have permission to access this page." # Fetch the QSD object try: qsd_rec = QuasiStaticData.objects.get_by_url(base_url) if qsd_rec == None: raise QuasiStaticData.DoesNotExist if qsd_rec.disabled: raise QuasiStaticData.DoesNotExist except QuasiStaticData.DoesNotExist: have_edit = Permission.user_can_edit_qsd(request.user, base_url) if have_edit: if action in ('edit','create',): qsd_rec = QuasiStaticData() qsd_rec.url = base_url qsd_rec.nav_category = default_navbarcategory() qsd_rec.title = 'New Page' qsd_rec.content = 'Please insert your text here' qsd_rec.create_date = datetime.now() qsd_rec.keywords = '' qsd_rec.description = '' action = 'edit' if (action == 'read'): edit_link = '/' + base_url + '.edit.html' response = render_to_response('qsd/nopage_create.html', request, {'edit_link': edit_link}, use_request_context=False) response.status_code = 404 # Make sure we actually 404, so that if there is a redirect the middleware can catch it. return response else: if action == 'read': raise Http404, 'This page does not exist.' else: raise Http403, 'Sorry, you can not modify <tt>%s</tt>.' % request.path if action == 'create': action = 'edit' # Detect the standard read verb if action == 'read': if not have_read: raise Http403, 'You do not have permission to read this page.' # Render response response = render_to_response('qsd/qsd.html', request, { 'title': qsd_rec.title, 'nav_category': qsd_rec.nav_category, 'content': qsd_rec.html(), 'settings': settings, 'qsdrec': qsd_rec, 'have_edit': True, ## Edit-ness is determined client-side these days 'edit_url': '/' + base_url + ".edit.html" }, use_request_context=False) # patch_vary_headers(response, ['Cookie']) # if have_edit: # add_never_cache_headers(response) # patch_cache_control(response, no_cache=True, no_store=True) # else: patch_cache_control(response, max_age=3600, public=True) return response # Detect POST if 'post_edit' in request.POST: have_edit = Permission.user_can_edit_qsd(request.user, base_url) if not have_edit: raise Http403, "Sorry, you do not have permission to edit this page." nav_category_target = NavBarCategory.objects.get(id=request.POST['nav_category']) # Since QSD now uses reversion, we want to only modify the data if we've actually changed something # The revision will automatically be created upon calling the save function of the model object copy_map = { 'url': base_url, 'nav_category': nav_category_target, 'content': request.POST['content'], 'title': request.POST['title'], 'description': request.POST['description'], 'keywords': request.POST['keywords'], } diff_found = False for field, new_value in copy_map.items(): if getattr(qsd_rec, field) != new_value: setattr(qsd_rec, field, new_value) diff_found = True if diff_found: qsd_rec.load_cur_user_time(request) qsd_rec.save() # We should also purge the cache purge_page(qsd_rec.url+".html") # Detect the edit verb if action == 'edit': have_edit = Permission.user_can_edit_qsd(request.user, base_url) # Enforce authorizations (FIXME: SHOW A REAL ERROR!) if not have_edit: raise Http403, "You don't have permission to edit this page." # Render an edit form return render_to_response('qsd/qsd_edit.html', request, { 'title' : qsd_rec.title, 'content' : qsd_rec.content, 'keywords' : qsd_rec.keywords, 'description' : qsd_rec.description, 'nav_category' : qsd_rec.nav_category, 'nav_categories': NavBarCategory.objects.all(), 'qsdrec' : qsd_rec, 'qsd' : True, 'target_url' : base_url.split("/")[-1] + ".edit.html", 'return_to_view': base_url.split("/")[-1] + ".html#refresh" }, use_request_context=False) # Operation Complete! raise Http404('Unexpected QSD operation')