# 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 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