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)
Exemple #2
0
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
Exemple #3
0
def internal_request(request):
    """
    Sets a context variable to check if a request is an internal request
    """
    return {'INTERNAL_REQUEST': is_internal(request)}
Exemple #4
0
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)
Exemple #5
0
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)