Exemple #1
0
    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
Exemple #3
0
    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
Exemple #4
0
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