# combo - content management system # Copyright (C) 2014 Entr'ouvert # # This program is free software: you can redistribute it and/or modify it # under the terms of the GNU Affero General Public License as published # by the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . import urllib import urlparse from django.conf import settings from django.contrib.auth import logout as auth_logout from django.contrib.auth import views as auth_views from django.core.exceptions import ObjectDoesNotExist, PermissionDenied from django.http import (Http404, HttpResponse, HttpResponseRedirect, HttpResponsePermanentRedirect) from django.shortcuts import render, resolve_url from django.template import RequestContext try: from mellon.utils import get_idps except ImportError: get_idps = lambda: [] from combo.data.models import CellBase, Page def login(request, *args, **kwargs): if any(get_idps()): if not 'next' in request.GET: return HttpResponseRedirect(resolve_url('mellon_login')) return HttpResponseRedirect(resolve_url('mellon_login') + '?next=' + urllib.quote(request.GET.get('next'))) return auth_views.login(request, *args, **kwargs) def logout(request, next_page=None): if any(get_idps()): return HttpResponseRedirect(resolve_url('mellon_logout')) auth_logout(request) if next_page is not None: next_page = resolve_url(next_page) else: next_page = '/' return HttpResponseRedirect(next_page) def ajax_page_cell(request, page_pk, cell_reference): try: page = Page.objects.get(id=page_pk) except Page.DoesNotExist: raise Http404() if not page.is_visible(request.user): raise PermissionDenied() try: cell = CellBase.get_cell(cell_reference, page_id=page_pk) except ObjectDoesNotExist: raise Http404() context = RequestContext(request, { 'page': page, 'request': request, 'ajax': True, 'site_base': request.build_absolute_uri('/')[:-1], }) return HttpResponse(cell.render(context), content_type='text/html') def extend_with_locked_placeholders_cells(cells, page, pages): locked_placeholders = page.get_locked_placeholders(cells) if locked_placeholders: # there are some acquired placeholders, look in parent pages for # appropriate content. try: # add the site index page as ultimate parent pages.insert(0, Page.objects.get(slug='index')) except Page.DoesNotExist: pass unlocker_cells = CellBase.get_cells(page_id__in=[x.id for x in pages]) found_placeholders = {} for parent_page in reversed(pages[:-1]): for placeholder in parent_page.get_unlocked_placeholders(unlocker_cells): if not placeholder in locked_placeholders: continue if not placeholder in found_placeholders: found_placeholders[placeholder] = parent_page.id if len(found_placeholders) == len(locked_placeholders): break # add found cells to the page cells for placeholder_key, page_id in found_placeholders.items(): cells.extend([x for x in unlocker_cells if x.page_id == page_id and x.placeholder == placeholder_key]) def skeleton(request): # Skeleton rendering is used to dynamically produce base templates to use # in other applications, based on configured combo cells. # # It takes a ?source= parameter that should contain the URL we want a # template for; it will be used to match the corresponding page, and thus # the corresponding content. If there's no matching page, an error will be # raised. (403 Access Forbidden) # # While placeholders holding cells will get their cells rendered, empty # placeholders will get themself outputted as template blocks, named # placeholder-$name, and with a default content of a block named $name. # # ex: # {% block placeholder-content %} # {% block content %} # {% endblock %} # {% endblock %} if 'source' not in request.GET: raise PermissionDenied() source = request.GET['source'] selected_page = None # look in redirect pages after the best match for the source redirect_pages = Page.objects.exclude(redirect_url__isnull=True).exclude(redirect_url='') for page in redirect_pages: if source.startswith(page.redirect_url): if selected_page is None or len(page.redirect_url) > len(selected_page.redirect_url): selected_page = page if selected_page is None: # if there was no page found, look for a domain match netloc = urlparse.urlparse(source).netloc for page in redirect_pages: if urlparse.urlparse(page.redirect_url).netloc == netloc: selected_page = page break else: raise PermissionDenied() pages = list(page.get_parents_and_self()) cells = CellBase.get_cells(page_id=page.id) extend_with_locked_placeholders_cells(cells, page, pages) combo_template = settings.COMBO_PUBLIC_TEMPLATES[page.template_name] ctx = { 'page': selected_page, 'page_cells': cells, 'request': request, 'render_skeleton': True, 'site_base': request.build_absolute_uri('/')[:-1], } template_name = combo_template['template'] return render(request, template_name, ctx) def empty_site(request): return render(request, 'combo/empty_site.html', {}) def page(request): url = request.path_info parts = [x for x in request.path_info.strip('/').split('/') if x] if not parts: parts = ['index'] try: pages = [Page.objects.get(slug=x) for x in parts] except Page.DoesNotExist: if not url.endswith('/') and settings.APPEND_SLASH: return HttpResponsePermanentRedirect(url + '/') if Page.objects.count() == 0 and parts == ['index']: return empty_site(request) else: raise Http404() for i, page in enumerate(pages[1:]): if page.parent_id != pages[i].id: raise Http404() page = pages[-1] if not page.is_visible(request.user): if not request.user.is_authenticated(): from django.contrib.auth.views import redirect_to_login return redirect_to_login(request.path) raise PermissionDenied() if page.redirect_url: return HttpResponseRedirect(page.redirect_url) combo_template = settings.COMBO_PUBLIC_TEMPLATES[page.template_name] cells = CellBase.get_cells(page_id=page.id) extend_with_locked_placeholders_cells(cells, page, pages) cells = [x for x in cells if x.is_visible(user=request.user)] ctx = { 'page': page, 'page_cells': cells, 'request': request, } template_name = combo_template['template'] return render(request, template_name, ctx)