def process_request(self, request): """ Checks if a request is an internal request and set a META variable with the state. Normally this middleware should be installed together with the context processor: djangoplicity.archives.context_processors.internal_request """ request.META['INTERNAL_REQUEST'] = is_internal(request)
def _authorize_internal(request, kwargs): ''' Check if the archive page is restricted to internal access only ''' if 'internal' in kwargs and kwargs['internal']: # Check if InternalRequestMiddleware has already verified if the # client's IP was internal: try: internal = request.META['INTERNAL_REQUEST'] except KeyError: internal = is_internal(request) if not internal: raise Http404
def internal_request(request): """ Sets a context variable to check if a request is an internal request """ return {'INTERNAL_REQUEST': is_internal(request)}
def archive_list(request, model=None, options=None, query_name=None, query=None, page=1, viewmode_name=None, **kwargs): """ List view for archives """ # Check if the view is restricted to internal access: _authorize_internal(request, kwargs) # # Initial error checking - make sure we have a query # # options and model classes required if options is None or model is None: raise ImproperlyConfigured( "Generic archive list view must be installed in the URL conf with model and options parameters." ) # query name or a query required if not (query_name or query): raise Http404 if query_name: query = getattr(options.Queries, query_name, None) if not (query is not None and isinstance(query, ArchiveQuery)): raise Http404 # Check if request is internal and generate cache key if is_internal(request): key = '%s_archive_list_internal_%s' % (model.get_cache_key_prefix(), str(request.path.__hash__())) else: key = '%s_archive_list_external_%s' % (model.get_cache_key_prefix(), str(request.path.__hash__())) # # Determine archive browser # if viewmode_name is None: if query.viewmode_param is not None: viewmode_name = request.GET.get(query.viewmode_param, query.default_browser) else: viewmode_name = query.default_browser if not query.has_browser(viewmode_name): raise Http404 try: browser = getattr(options.Browsers, viewmode_name) except AttributeError: raise Http404 # Check if view in cache: ca = model.cache_get(key) # # Authorize view # if not query.has_permissions(request): if request.user.is_authenticated(): return HttpResponseForbidden( render_to_string('403.html', request=request)) else: return redirect_to_login(next=request.get_full_path()) # Check parameters and redirect if necessary: redirect_url = query.check_parameters(model, options, request) if redirect_url: return redirect(redirect_url) # We don't used cached view if we have GET data (to prevent # caching search queries) if ca and not request.GET: return browser.response(ca) # # Get Query Set # (qs, query_data) = query.queryset(model, options, request, **kwargs) # Exclude all non-published archive items (if archive uses published attribute) # FIXME: this results in duplicates "published=1" in the SQL. Really this # should be done in the query, like in AllPublicQuery, however some queries # such as SubjectCategoryNamePublicQuery need to be updated (SubjectCategoryNameQuery should for example # inherit from AllPublicQuery instead of SubjectCategoryNameQuery) if model.Archive.Meta.published: if hasattr(qs, 'filter'): qs = qs.filter(**{model.Archive.Meta.published_fieldname: True}) if options.select_related: qs = qs.select_related(*options.select_related) if options.prefetch_related: qs = qs.prefetch_related(*options.prefetch_related) if options.archive_list_only_fields: qs = qs.only(*options.archive_list_only_fields) # # Search in query set if query is searchable. # search_str = request.GET.get(SEARCH_VAR, '').strip() search_str = query_data.get('adv_search_str', search_str) if search_str and '\0' in urlunquote(search_str): # Tell Nginx to drop connection if someone is passing null bytes # to the query return HttpResponse(status=444) if query.searchable and search_str and not query_data.get( 'adv_search_str', False): qs = options.search(request, qs, search_str) # # Render results # kwargs.update({'page': page, 'viewmode_name': viewmode_name}) # Temp hack content = browser.render(request, model, options, query, query_name, qs, query_data, search_str, **kwargs) if not request.GET: model.cache_set(key, content) return browser.response(content)
def view_page(request, url): """ View for rendering pages. The view can either be called through the PageFallbackMiddleware or add the following line as the last entry in urls.py (a catch all pattern): {{{ ( r'^(?P<url>.*)', iaumemberdb.views.test_view ) }}} The difference between the middleware and the URL matching method, is that the with the URL method it wall always be this view that returns a 404 response, while with the fallback middleware, the middleware will return the original 404 response in case no page was found. The view has the following features: * Authentication:: * Staff users with pages.can_view_inactive permissions can see all pages (inactive as well as login protected) * Pages can be require login/authentication * Caching:: * For static pages the entire HTML document is cached. * For dynamic pages the compiled template is cached. * Dynamic content:: * By default only MEDIA_URL is available as variable, beside the normal template markup. * Pages can be embedded cannot be viewed through this view, but should use the embed_page view. * URL lookup is done through a cached URL index, if possible. """ if not url.startswith('/'): url = "/" + url if settings.USE_I18N: lang = translation.get_language() else: lang = None # Generate cache key if request.user.is_staff and request.user.has_perm( 'pages.can_view_inactive') and 'preview' in request.GET: # We don't cache if user has permissions and in preview mode cache_key = None else: cache_key = '%s_%s' % (CACHE_KEY['pages'], str(url.__hash__())) if lang: cache_key += '_%s' % lang if is_internal(request): cache_key += '_internal' else: cache_key += '_external' if cache_key: page_cache = cache.get(cache_key) else: page_cache = None if page_cache is not None: page = page_cache['page'] else: # Use precompiled index of urls for the site. index = cache.get(CACHE_KEY['urlindex']) if index is None: index = build_urlindex() if url in index: page = Page.objects.get(embedded__exact=0, pk=index[url]) elif settings.USE_I18N and request.path in index: # If we use translations let's check if the page exists with a full # URL, e.g.: /public/chile/about-eso/ page = Page.objects.filter(embedded__exact=0, pk=index[request.path]).get() else: # If the URL doesn't exist let's check if it does exist with # a trailing / if not url.endswith('/') and url + '/' in index: return redirect(request.path + '/') raise Http404 # The current preferred language is different than the page's, # If the page was not originally accessed through the "translated" # URL then we redirect the user: language_path = get_path_for_language(lang, request.path_info) if request.path != language_path: querystring = get_querystring_from_request(request) if querystring: # Add query string to redirect path if any language_path += '?' + querystring return redirect(language_path) if settings.USE_I18N and lang != page.lang: # Next we check if we have a translation for the page, in which # case we use it, othewise we use the original version but set # a variable to be used in the template try: trans = page.translations.get(lang=lang) if trans.published and trans.translation_ready: page = trans else: request.NO_TRANSLATION = True except Page.DoesNotExist: # There are not translations in the preferred language, next we # check if the source is in the same language family, if not # we display a sorry message if lang[:2] != page.lang[:2]: request.NO_TRANSLATION = True # Page Protection # --------------- # Authentication and active pages. # - Staff users with 'pages.can_view_inactive' permissions can view pages online # even if they are inactive (this is a preview functionality). try: _authorize_pageview(request, page) except PageNotFoundError: raise Http404 except PageAuthorizationError: from django.contrib.auth.views import redirect_to_login return redirect_to_login(request.path) # If the page has a redirect_url set we return a HTTP 301 permanent redirection if page.redirect_url: return HttpResponsePermanentRedirect(page.redirect_url) # # Rendering # htmlkey = 'html%s' % '-admin' if request.user.is_superuser else '' ctpl = None # We don't want to cache the page with the link to the admin page # so if the user has edit access we don't use the cache if page_cache is not None and not request.user.has_perm( 'pages.change_page'): # Cache if htmlkey in page_cache: # We already have a fully rendered page so return it. return HttpResponse(page_cache[htmlkey]) elif 'template' in page_cache: # We only have a compiled template, so we need to render the page ctpl = page_cache['template'] if ctpl is None: # No cache ctpl = engines['django'].from_string(page.content) # Render content page.title = mark_safe(page.title) page.content = mark_safe(ctpl.render({}, request)) # Render entire page template_names = (page.template_name, page.section.template) template = select_template([x for x in template_names if x]) html = template.render( { 'page': page, 'translations': page.get_translations(), 'admin_edit': admin_edit_for_site('admin_site', translation_proxy=PageProxy)(page), }, request) # Cache page (either entire page, or only compiled content template) # Note: Inactive pages and pages viewed by users with admin access # are never cached if cache_key: if page.is_online() and not request.user.has_perm('pages.change_page'): if page.dynamic and page_cache is None: cache.set(cache_key, {'page': page, 'template': ctpl}) else: if not page_cache: page_cache = {'page': page} page_cache[htmlkey] = html cache.set(cache_key, page_cache) return HttpResponse(html)