combo/combo/manager/views.py

334 lines
11 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 json
import ckeditor
from django.conf import settings
from django.contrib.contenttypes.models import ContentType
from django.core.files.storage import default_storage
from django.core.exceptions import ObjectDoesNotExist, PermissionDenied
from django.core.urlresolvers import reverse, reverse_lazy
from django.http import HttpResponse, Http404
from django.shortcuts import redirect
from django.utils.translation import ugettext_lazy as _
from django.utils.encoding import force_text
from django.views.decorators.csrf import requires_csrf_token
from django.views.generic import (TemplateView, RedirectView, DetailView,
CreateView, UpdateView, ListView, DeleteView, FormView)
from combo.data.models import Page, CellBase, UnlockMarkerCell
from combo import plugins
from .forms import PageForm, PageEditForm, PageVisibilityForm, SiteImportForm
class HomepageView(ListView):
model = Page
template_name = 'combo/manager_home.html'
def get_context_data(self, **kwargs):
self.object_list = Page.get_as_reordered_flat_hierarchy(self.object_list)
context = super(HomepageView, self).get_context_data(**kwargs)
context['extra_actions'] = plugins.get_extra_manager_actions()
return context
homepage = HomepageView.as_view()
class SiteExportView(ListView):
model = Page
def render_to_response(self, context, **response_kwargs):
response = HttpResponse(content_type='application/json')
json.dump([x.get_serialized_page() for x in self.object_list],
response, indent=2)
return response
site_export = SiteExportView.as_view()
class SiteImportView(FormView):
form_class = SiteImportForm
template_name = 'combo/site_import.html'
success_url = reverse_lazy('combo-manager-homepage')
def form_valid(self, form):
json_site = json.load(self.request.FILES['site_json'])
Page.load_serialized_pages(json_site)
return super(SiteImportView, self).form_valid(form)
site_import = SiteImportView.as_view()
class PageAddView(CreateView):
model = Page
template_name = 'combo/page_add.html'
form_class = PageForm
def get_initial(self):
initial = super(PageAddView, self).get_initial()
if Page.objects.count() == 0:
# first page
initial['title'] = _('Home')
initial['slug'] = 'index'
return initial
def get_success_url(self):
return reverse('combo-manager-page-view', kwargs={'pk': self.object.id})
page_add = PageAddView.as_view()
class PageEditView(UpdateView):
model = Page
template_name = 'combo/page_add.html'
form_class = PageEditForm
def get_success_url(self):
return reverse('combo-manager-page-view', kwargs={'pk': self.object.id})
page_edit = PageEditView.as_view()
class PageVisibilityView(PageEditView):
form_class = PageVisibilityForm
page_visibility = PageVisibilityView.as_view()
class PageView(DetailView):
model = Page
template_name = 'combo/page_view.html'
def get_context_data(self, **kwargs):
context = super(PageView, self).get_context_data(**kwargs)
context['cell_types'] = CellBase.get_cell_content_types()
cells = CellBase.get_cells(page_id=self.object.id)
template = self.object.template_name
placeholders = []
extra_placeholders = []
combo_template = settings.COMBO_PUBLIC_TEMPLATES.get(template)
unlocked_placeholders = self.object.get_unlocked_placeholders(cells)
for placeholder_key, placeholder in combo_template['placeholders'].items():
placeholder_dict = {
'key': placeholder_key,
'name': placeholder['name'],
}
if placeholder.get('acquired') and not placeholder_key in unlocked_placeholders:
extra_placeholders.append(placeholder_dict)
else:
placeholder_dict['cells'] = [x for x in cells if (
x.placeholder == placeholder_key)]
placeholders.append(placeholder_dict)
context['unlock'] = UnlockMarkerCell.get_content_types()[0]
context['placeholders'] = placeholders
context['extra_placeholders'] = extra_placeholders
return context
page_view = requires_csrf_token(PageView.as_view())
class PageDeleteView(DeleteView):
model = Page
template_name = 'combo/generic_confirm_delete.html'
def get_success_url(self):
return reverse('combo-manager-homepage')
page_delete = PageDeleteView.as_view()
class PageExportView(DetailView):
model = Page
def render_to_response(self, context, **response_kwargs):
response = HttpResponse(content_type='application/json')
json.dump(self.object.get_serialized_page(), response, indent=2)
return response
page_export = PageExportView.as_view()
class PageAddCellView(RedirectView):
permanent = False
def get_redirect_url(self, page_pk, cell_type, variant, ph_key):
cell_class = ContentType.objects.get(id=cell_type).model_class()
cell = cell_class(page_id=page_pk, placeholder=ph_key)
cell.set_variant(variant)
orders = [x.order for x in CellBase.get_cells(page_id=page_pk)]
if orders:
cell.order = max(orders)+1
else:
cell.order = 1
cell.save()
return reverse('combo-manager-page-view', kwargs={'pk': page_pk})
page_add_cell = PageAddCellView.as_view()
class PageEditCellView(UpdateView):
def get_object(self, queryset=None):
page_pk = self.kwargs.get('page_pk')
cell_reference = self.kwargs.get('cell_reference')
try:
return CellBase.get_cell(cell_reference, page_id=page_pk)
except ObjectDoesNotExist:
raise Http404()
def get_prefix(self):
return 'c%s' % self.kwargs.get('cell_reference')
def get_form_class(self):
return self.object.get_default_form_class()
def get_success_url(self):
return reverse('combo-manager-page-view', kwargs={'pk': self.kwargs.get('page_pk')})
page_edit_cell = PageEditCellView.as_view()
class PageDeleteCellView(DeleteView):
template_name = 'combo/generic_confirm_delete.html'
def get_object(self, queryset=None):
page_pk = self.kwargs.get('page_pk')
cell_reference = self.kwargs.get('cell_reference')
try:
return CellBase.get_cell(cell_reference, page_id=page_pk)
except ObjectDoesNotExist:
raise Http404()
def get_success_url(self):
return reverse('combo-manager-page-view', kwargs={'pk': self.kwargs.get('page_pk')})
page_delete_cell = PageDeleteCellView.as_view()
class PageCellVisibilityView(PageEditCellView):
template_name = 'combo/cell_visibility.html'
def get_form_class(self):
return self.object.get_visibility_form_class()
page_cell_visibility = PageCellVisibilityView.as_view()
class PageCellOptionsView(PageEditCellView):
template_name = 'combo/cell_options.html'
def get_form_class(self):
return self.object.get_options_form_class()
page_cell_options = PageCellOptionsView.as_view()
def cell_order(request, page_pk):
for cell in CellBase.get_cells(page_id=page_pk):
old_order = cell.order
old_placeholder = cell.placeholder
key_suffix = cell.get_reference()
try:
new_order = int(request.GET.get('pos_' + key_suffix))
except TypeError:
# the cell is not present in the query string, most probably
# because it's in a different placeholder
continue
new_placeholder = request.GET.get('ph_' + key_suffix)
if new_order != old_order or new_placeholder != old_placeholder:
cell.order = new_order
cell.placeholder = new_placeholder
cell.save()
return HttpResponse(status=206)
def page_order(request):
new_order = [int(x) for x in request.GET['new-order'].split(',')]
moved_page = Page.objects.get(id=request.GET['moved-page-id'])
if request.GET['moved-page-new-parent']:
moved_page.parent_id = request.GET['moved-page-new-parent']
else:
moved_page.parent_id = None
moved_page.save()
for page in Page.objects.filter(parent_id=moved_page.parent_id):
page.order = new_order.index(page.id)+1
page.save()
return redirect(reverse('combo-manager-homepage'))
def page_get_additional_label(request, page_pk, cell_reference):
cell = CellBase.get_cell(cell_reference, page_id=page_pk)
response = HttpResponse(content_type='application/json')
json.dump({'label': cell.get_additional_label() or ''}, response)
return response
class Assets(TemplateView):
template_name = 'combo/manager_assets.html'
def get_context_data(self, **kwargs):
context = super(Assets, self).get_context_data(**kwargs)
context['files'] = []
for filename in ckeditor.views.get_image_files(self.request.user):
src = ckeditor.utils.get_media_url(filename)
if getattr(settings, 'CKEDITOR_IMAGE_BACKEND', None):
thumb = ckeditor.utils.get_media_url(
ckeditor.utils.get_thumb_filename(filename))
else:
thumb = src
context['files'].append({
'thumb': thumb,
'src': src,
'is_image': ckeditor.views.is_image(src),
'orig': filename,
})
return context
assets = Assets.as_view()
def asset_delete(request):
img_orig = request.GET['img_orig']
if '..' in img_orig:
raise PermissionDenied() # better safe than sorry
base_path = settings.CKEDITOR_UPLOAD_PATH
if getattr(settings, 'CKEDITOR_RESTRICT_BY_USER', False):
base_path = os.path.join(base_path, user.username)
if not img_orig.startswith(base_path):
raise PermissionDenied()
default_storage.delete(img_orig)
return HttpResponse(status=204)
def menu_json(request):
response = HttpResponse(content_type='application/json')
if getattr(settings, 'TEMPLATE_VARS', {}).get('site_title'):
label = _('Editing %(site_title)s') % getattr(settings, 'TEMPLATE_VARS')
else:
label = _('Content Management')
json_str = json.dumps([{'label': force_text(label),
'slug': 'portal',
'url': request.build_absolute_uri(reverse('combo-manager-homepage'))
}])
for variable in ('jsonpCallback', 'callback'):
if variable in request.GET:
json_str = '%s(%s);' % (request.GET[variable], json_str)
break
response.write(json_str)
return response