def get_form(self, request, obj=None, **kwargs): """Get a :class:`Page <pages.admin.forms.PageForm>` for the :class:`Page <pages.models.Page>` and modify its fields depending on the request.""" #form = super(PageAdmin, self).get_form(request, obj, **kwargs) template = get_template_from_request(request, obj) form = make_form(self.model, get_placeholders(template)) language = get_language_from_request(request) form.base_fields['language'].initial = language if obj: initial_slug = obj.slug(language=language, fallback=False) initial_title = obj.title(language=language, fallback=False) form.base_fields['slug'].initial = initial_slug form.base_fields['title'].initial = initial_title form.base_fields['slug'].label = _('Slug') template = get_template_from_request(request, obj) page_templates = settings.get_page_templates() if len(page_templates) > 0: template_choices = list(page_templates) template_choices.insert( 0, (settings.PAGE_DEFAULT_TEMPLATE, _('Default template'))) form.base_fields['template'].choices = template_choices form.base_fields['template'].initial = force_text(template) for placeholder in get_placeholders(template): name = placeholder.name if obj: initial = placeholder.get_content(obj, language, name) else: initial = None form.base_fields[name] = placeholder.get_field(obj, language, initial=initial) for placeholder in self.metadata_fields: name = placeholder['name'] initial = None if obj: try: initial = Content.objects.get(page=obj, language=language, type=name).body except Content.DoesNotExist: pass form.base_fields[name] = placeholder['field'] form.base_fields[name].initial = initial return form
def get_form(self, request, obj=None, **kwargs): """Get a :class:`Page <pages.admin.forms.PageForm>` for the :class:`Page <pages.models.Page>` and modify its fields depending on the request.""" #form = super(PageAdmin, self).get_form(request, obj, **kwargs) template = get_template_from_request(request, obj) form = make_form(self.model, get_placeholders(template)) language = get_language_from_request(request) form.base_fields['language'].initial = language if obj: initial_slug = obj.slug(language=language, fallback=False) initial_title = obj.title(language=language, fallback=False) form.base_fields['slug'].initial = initial_slug form.base_fields['title'].initial = initial_title form.base_fields['slug'].label = _('Slug') template = get_template_from_request(request, obj) page_templates = settings.get_page_templates() if len(page_templates) > 0: template_choices = list(page_templates) template_choices.insert(0, (settings.PAGE_DEFAULT_TEMPLATE, _('Default template'))) form.base_fields['template'].choices = template_choices form.base_fields['template'].initial = force_text(template) for placeholder in get_placeholders(template): name = placeholder.name if obj: initial = placeholder.get_content(obj, language, name) else: initial = None form.base_fields[name] = placeholder.get_field(obj, language, initial=initial) for placeholder in self.metadata_fields: name = placeholder['name'] initial = None if obj: try: initial = Content.objects.get(page=obj, language=language, type=name).body except Content.DoesNotExist: pass form.base_fields[name] = placeholder['field'] form.base_fields[name].initial = initial return form
class PageForm(SlugFormMixin): """Form for page creation""" err_dict = { 'another_page_error': _('Another page with this slug already exists'), 'sibling_position_error': _('A sibling with this slug already exists at the targeted position'), 'child_error': _('A child with this slug already exists at the targeted position'), 'sibling_error': _('A sibling with this slug already exists'), 'sibling_root_error': _('A sibling with this slug already exists at the root level'), } language = forms.ChoiceField( label=_('Language'), choices=settings.PAGE_LANGUAGES, widget=LanguageChoiceWidget() ) template = forms.ChoiceField( required=False, label=_('Template'), choices=settings.get_page_templates(), ) delegate_to = forms.ChoiceField( required=False, label=_('Delegate to application'), choices=get_choices(), ) freeze_date = forms.DateTimeField( required=False, label=_('Freeze'), help_text=_("Don't publish any content after this date. Format is 'Y-m-d H:M:S'") # those make tests fail miserably #widget=widgets.AdminSplitDateTime() #widget=widgets.AdminTimeWidget() ) target = forms.IntegerField(required=False, widget=forms.HiddenInput) position = forms.CharField(required=False, widget=forms.HiddenInput) class Meta: model = model_ exclude = ('author', 'last_modification_date', 'parent') def clean_slug(self): """Handle move action on the pages""" slug = slugify(self.cleaned_data['slug']) target = self.data.get('target', None) position = self.data.get('position', None) # this enforce a unique slug for every page if settings.PAGE_AUTOMATIC_SLUG_RENAMING: def is_slug_safe(slug): content = Content.objects.get_content_slug_by_slug(slug) if content is None: return True if self.instance.id: if content.page.id == self.instance.id: return True else: return False return self._clean_page_automatic_slug_renaming(slug, is_slug_safe) if settings.PAGE_UNIQUE_SLUG_REQUIRED: return self._clean_page_unique_slug_required(slug) if settings.PAGE_USE_SITE_ID: if settings.PAGE_HIDE_SITES: site_ids = [global_settings.SITE_ID] else: site_ids = [int(x) for x in self.data.getlist('sites')] def intersects_sites(sibling): return sibling.sites.filter(id__in=site_ids).count() > 0 else: def intersects_sites(sibling): return True if not settings.PAGE_UNIQUE_SLUG_REQUIRED: if target and position: target = Page.objects.get(pk=target) if position in ['right', 'left']: slugs = [sibling.slug() for sibling in target.get_siblings() if intersects_sites(sibling)] slugs.append(target.slug()) if slug in slugs: raise forms.ValidationError(self.err_dict['sibling_position_error']) if position == 'first-child': if slug in [sibling.slug() for sibling in target.get_children() if intersects_sites(sibling)]: raise forms.ValidationError(self.err_dict['child_error']) else: if self.instance.id: if (slug in [sibling.slug() for sibling in self.instance.get_siblings().exclude( id=self.instance.id ) if intersects_sites(sibling)]): raise forms.ValidationError(self.err_dict['sibling_error']) else: if slug in [sibling.slug() for sibling in Page.objects.root() if intersects_sites(sibling)]: raise forms.ValidationError(self.err_dict['sibling_root_error']) return slug
class PageAdmin(admin.ModelAdmin): """Page Admin class.""" exclude = ['author', 'parent'] # these mandatory fields are not versioned mandatory_placeholders = ('title', 'slug') general_fields = [ 'title', 'slug', 'status', 'target', 'position', 'freeze_date' ] if settings.PAGE_USE_SITE_ID and not settings.PAGE_HIDE_SITES: general_fields.append('sites') insert_point = general_fields.index('status') + 1 # Strange django behavior. If not provided, django will try to find # 'page' foreign key in all registered models inlines = [] general_fields.insert(insert_point, 'tags') # Add support for future dating and expiration based on settings. if settings.PAGE_SHOW_END_DATE: general_fields.insert(insert_point, 'publication_end_date') if settings.PAGE_SHOW_START_DATE: general_fields.insert(insert_point, 'publication_date') from basic_cms.urlconf_registry import registry if (len(registry)): general_fields.append('delegate_to') insert_point = general_fields.index('status') + 1 normal_fields = ['language'] page_templates = settings.get_page_templates() if len(page_templates) > 0: normal_fields.append('template') normal_fields.append('redirect_to') normal_fields.append('redirect_to_url') fieldsets = ( [ _('General'), { 'fields': general_fields, 'classes': ('module-general', ), } ], (_('Options'), { 'fields': normal_fields, 'classes': ('module-options', ), }), ) actions = [export_pages_as_json] metadata_fields = [ { 'name': 'meta_title', 'field': forms.fields.CharField(required=False) }, { 'name': 'meta_description', 'field': forms.fields.CharField(required=False, widget=forms.widgets.Textarea()), }, { 'name': 'meta_keywords', 'field': forms.fields.CharField(required=False, widget=forms.widgets.Textarea()), }, { 'name': 'meta_author', 'field': forms.fields.CharField(required=False), }, { 'name': 'fb_page_type', 'field': forms.fields.CharField(required=False), }, { 'name': 'fb_image', 'field': forms.fields.CharField(required=False), }, ] class Media: css = { 'all': [ join(settings.PAGES_MEDIA_URL, path) for path in ('css/rte.css', 'css/pages.css') ] } js = [ join(settings.PAGES_MEDIA_URL, path) for path in ( 'javascript/jquery.js', 'javascript/jquery.rte.js', 'javascript/pages.js', 'javascript/pages_list.js', 'javascript/pages_form.js', 'javascript/jquery.query-2.1.7.js', ) ] def urls(self): from django.conf.urls import patterns, url # Admin-site-wide views. urlpatterns = patterns( '', url(r'^$', self.list_pages, name='page-index'), url(r'^(?P<page_id>[0-9]+)/traduction/(?P<language_id>[-\w]+)/$', traduction, name='page-traduction'), url(r'^(?P<page_id>[0-9]+)/get-content/(?P<content_id>[0-9]+)/$', get_content, name='page-get-content'), url(r'^(?P<page_id>[0-9]+)/modify-content/(?P<content_type>[-\w]+)/(?P<language_id>[-\w]+)/$', modify_content, name='page-modify-content'), url(r'^(?P<page_id>[0-9]+)/delete-content/(?P<language_id>[-\w]+)/$', delete_content, name='page-delete-content'), url(r'^(?P<page_id>[0-9]+)/sub-menu/$', sub_menu, name='page-sub-menu'), url(r'^(?P<page_id>[0-9]+)/move-page/$', move_page, name='page-move-page'), url(r'^(?P<page_id>[0-9]+)/change-status/$', change_status, name='page-change-status'), url(r'^import-json/$', self.import_pages, name='import-pages-from-json'), ) urlpatterns += super(PageAdmin, self).urls return urlpatterns urls = property(urls) def i18n_javascript(self, request): """Displays the i18n JavaScript that the Django admin requires. This takes into account the ``USE_I18N`` setting. If it's set to False, the generated JavaScript will be leaner and faster. """ return javascript_catalog(request, packages='pages') def save_model(self, request, page, form, change): """Move the page in the tree if necessary and save every placeholder :class:`Content <pages.models.Content>`. """ language = form.cleaned_data['language'] target = form.data.get('target', None) position = form.data.get('position', None) page.save() # if True, we need to move the page if target and position: try: target = self.model.objects.get(pk=target) except self.model.DoesNotExist: pass else: target.invalidate() page.move_to(target, position) for name in self.mandatory_placeholders: data = form.cleaned_data[name] placeholder = PlaceholderNode(name) extra_data = placeholder.get_extra_data(form.data) placeholder.save(page, language, data, change, extra_data=extra_data) for placeholder in get_placeholders(page.get_template()): if (placeholder.name in form.cleaned_data and placeholder.name not in self.mandatory_placeholders): data = form.cleaned_data[placeholder.name] extra_data = placeholder.get_extra_data(form.data) placeholder.save(page, language, data, change, extra_data=extra_data) for placeholder in self.metadata_fields: data = form.cleaned_data[placeholder['name']] Content.objects.set_or_create_content(page, language, placeholder['name'], data) page.invalidate() def get_fieldsets(self, request, obj=None): """ Add fieldsets of placeholders to the list of already existing fieldsets. """ # some ugly business to remove freeze_date # from the field list general_module = { 'fields': list(self.general_fields), 'classes': ('module-general', ), } default_fieldsets = list(self.fieldsets) if not request.user.has_perm('pages.can_freeze'): general_module['fields'].remove('freeze_date') if not request.user.has_perm('pages.can_publish'): general_module['fields'].remove('status') default_fieldsets[0][1] = general_module placeholder_fieldsets = [] template = get_template_from_request(request, obj) for placeholder in get_placeholders(template): if placeholder.name not in self.mandatory_placeholders: placeholder_fieldsets.append(placeholder.name) additional_fieldsets = [] # meta fields metadata_fieldsets = [f['name'] for f in self.metadata_fields] additional_fieldsets.append((_('Metadata'), { 'fields': metadata_fieldsets, 'classes': ('module-content', 'grp-collapse grp-closed'), })) additional_fieldsets.append((_('Content'), { 'fields': placeholder_fieldsets, 'classes': ('module-content', ), })) return default_fieldsets + additional_fieldsets def save_form(self, request, form, change): """Given a ModelForm return an unsaved instance. ``change`` is True if the object is being changed, and False if it's being added.""" instance = super(PageAdmin, self).save_form(request, form, change) instance.template = form.cleaned_data['template'] if not change: instance.author = request.user return instance def get_form(self, request, obj=None, **kwargs): """Get a :class:`Page <pages.admin.forms.PageForm>` for the :class:`Page <pages.models.Page>` and modify its fields depending on the request.""" #form = super(PageAdmin, self).get_form(request, obj, **kwargs) template = get_template_from_request(request, obj) form = make_form(self.model, get_placeholders(template)) language = get_language_from_request(request) form.base_fields['language'].initial = language if obj: initial_slug = obj.slug(language=language, fallback=False) initial_title = obj.title(language=language, fallback=False) form.base_fields['slug'].initial = initial_slug form.base_fields['title'].initial = initial_title form.base_fields['slug'].label = _('Slug') template = get_template_from_request(request, obj) page_templates = settings.get_page_templates() if len(page_templates) > 0: template_choices = list(page_templates) template_choices.insert( 0, (settings.PAGE_DEFAULT_TEMPLATE, _('Default template'))) form.base_fields['template'].choices = template_choices form.base_fields['template'].initial = force_text(template) for placeholder in get_placeholders(template): name = placeholder.name if obj: initial = placeholder.get_content(obj, language, name) else: initial = None form.base_fields[name] = placeholder.get_field(obj, language, initial=initial) for placeholder in self.metadata_fields: name = placeholder['name'] initial = None if obj: try: initial = Content.objects.get(page=obj, language=language, type=name).body except Content.DoesNotExist: pass form.base_fields[name] = placeholder['field'] form.base_fields[name].initial = initial return form def change_view(self, request, object_id, extra_context=None): """The ``change`` admin view for the :class:`Page <pages.models.Page>`.""" language = get_language_from_request(request) extra_context = { 'language': language, # don't see where it's used #'lang': current_lang, 'page_languages': settings.PAGE_LANGUAGES, } try: int(object_id) except ValueError: raise Http404('The "%s" part of the location is invalid.' % str(object_id)) try: obj = self.model.objects.get(pk=object_id) except self.model.DoesNotExist: # Don't raise Http404 just yet, because we haven't checked # permissions yet. We don't want an unauthenticated user to be able # to determine whether a given object exists. obj = None else: template = get_template_from_request(request, obj) extra_context['placeholders'] = get_placeholders(template) extra_context['traduction_languages'] = [ l for l in settings.PAGE_LANGUAGES if Content.objects.get_content(obj, l[0], "title") and l[0] != language ] extra_context['page'] = obj return super(PageAdmin, self).change_view(request, object_id, extra_context=extra_context) def add_view(self, request, form_url='', extra_context=None): """The ``add`` admin view for the :class:`Page <pages.models.Page>`.""" extra_context = { 'language': get_language_from_request(request), 'page_languages': settings.PAGE_LANGUAGES, } return super(PageAdmin, self).add_view(request, form_url, extra_context) def has_add_permission(self, request): """Return ``True`` if the current user has permission to add a new page.""" return request.user.has_perm('pages.add_page') def has_change_permission(self, request, obj=None): """Return ``True`` if the current user has permission to change the page.""" return request.user.has_perm('pages.change_page') def has_delete_permission(self, request, obj=None): """Return ``True`` if the current user has permission on the page.""" return request.user.has_perm('pages.delete_page') def list_pages(self, request, template_name=None, extra_context=None): """List root pages""" if not self.admin_site.has_permission(request): return self.admin_site.login(request) language = get_language_from_request(request) query = request.POST.get('q', '').strip() if query: page_ids = list( set([ c.page.pk for c in Content.objects.filter(body__icontains=query) ])) pages = Page.objects.filter(pk__in=page_ids) else: pages = Page.objects.root() if settings.PAGE_HIDE_SITES: pages = pages.filter(sites=settings.SITE_ID) context = { 'can_publish': request.user.has_perm('pages.can_publish'), 'language': language, 'name': _("page"), 'pages': pages, 'opts': self.model._meta, 'q': query } context.update(extra_context or {}) change_list = self.changelist_view(request, context) return change_list def import_pages(self, request): if not self.has_add_permission(request): return admin.site.login(request) return import_pages_from_json(request)
def validate_pages_json_data(d, preferred_lang): """ Check if an import of d will succeed, and return errors. errors is a list of strings. The import should proceed only if errors is empty. """ from .models import Page errors = [] seen_complete_slugs = dict( (lang[0], set()) for lang in settings.PAGE_LANGUAGES) valid_templates = set(t[0] for t in settings.get_page_templates()) valid_templates.add(settings.PAGE_DEFAULT_TEMPLATE) if d[JSON_PAGE_EXPORT_NAME] != JSON_PAGE_EXPORT_VERSION: return [_('Unsupported file version: %s') % repr( d[JSON_PAGE_EXPORT_NAME])], [] pages = d['pages'] for p in pages: # use the complete slug as a way to identify pages in errors slug = p['complete_slug'].get(preferred_lang, None) seen_parent = False for lang, s in p['complete_slug'].items(): if lang not in seen_complete_slugs: continue seen_complete_slugs[lang].add(s) if '/' not in s: # root level, no parent req'd seen_parent = True if not seen_parent: parent_slug, ignore = s.rsplit('/', 1) if parent_slug in seen_complete_slugs[lang]: seen_parent = True else: parent = Page.objects.from_path(parent_slug, lang, exclude_drafts=False) if parent and parent.get_complete_slug(lang) == parent_slug: # parent not included, but exists on site seen_parent = True if not slug: slug = s if not slug: errors.append(_("%s has no common language with this site") % (p['complete_slug'].values()[0],)) continue if not seen_parent: errors.append(_("%s did not include its parent page and a matching" " one was not found on this site") % (slug,)) if p['template'] not in valid_templates: errors.append(_("%s uses a template not found on this site: %s") % (slug, p['template'])) continue import_fields = set(p['content'].keys()) import_fields |= set(('meta_title', 'meta_description', 'meta_keywords', 'meta_author', 'fb_page_type', 'fb_image')) template_fields = set(p.name for p in get_placeholders(p['template']) if p.name not in ('title', 'slug')) template_fields |= set(('meta_title', 'meta_description', 'meta_keywords', 'meta_author', 'fb_page_type', 'fb_image')) if template_fields != import_fields: errors.append(_("%s template contents are different than our " "template: %s") % (slug, p['template'])) continue return errors