combo/combo/public/views.py

211 lines
7.4 KiB
Python

# 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 <http://www.gnu.org/licenses/>.
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)