mirror of
https://github.com/Hopiu/wagtail.git
synced 2026-04-15 04:21:07 +00:00
Merge branch 'master' into tests-changes2
This commit is contained in:
commit
e76785d96d
8 changed files with 126 additions and 62 deletions
|
|
@ -8,6 +8,7 @@ Changelog
|
|||
* Snippets are now ordered alphabetically
|
||||
* Removed the "More" section from the admin menu
|
||||
* Added pagination to page listings in admin
|
||||
* Support for setting a subpage_types property on page models, to define which page types are allowed as subpages
|
||||
* Fix: Animated GIFs are now coalesced before resizing
|
||||
* Fix: Wand backend clones images before modifying them
|
||||
* Fix: Admin breadcrumb now positioned correctly on mobile
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ Contributors
|
|||
* Ben Margolis
|
||||
* Tom Talbot
|
||||
* Jeffrey Hearn
|
||||
* Robert Clark
|
||||
|
||||
Translators
|
||||
===========
|
||||
|
|
|
|||
|
|
@ -294,3 +294,16 @@ class ZuluSnippet(models.Model):
|
|||
|
||||
def __unicode__(self):
|
||||
return self.text
|
||||
|
||||
|
||||
class StandardIndex(Page):
|
||||
pass
|
||||
|
||||
class StandardChild(Page):
|
||||
pass
|
||||
|
||||
class BusinessIndex(Page):
|
||||
subpage_types = ['tests.BusinessChild']
|
||||
|
||||
class BusinessChild(Page):
|
||||
subpage_types = []
|
||||
|
|
|
|||
|
|
@ -12,9 +12,9 @@
|
|||
<div class="nice-padding">
|
||||
<p>{% trans "Choose which type of page you'd like to create." %}</p>
|
||||
|
||||
{% if all_page_types %}
|
||||
{% if page_types %}
|
||||
<ul class="listing">
|
||||
{% for content_type in all_page_types %}
|
||||
{% for content_type in page_types %}
|
||||
<li>
|
||||
<div class="row row-flush">
|
||||
<div class="col6">
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
from django.test import TestCase
|
||||
from wagtail.tests.models import SimplePage, EventPage
|
||||
from wagtail.tests.models import SimplePage, EventPage, StandardIndex, StandardChild, BusinessIndex, BusinessChild
|
||||
from wagtail.tests.utils import unittest, WagtailTestUtils
|
||||
from wagtail.wagtailcore.models import Page, PageRevision
|
||||
from django.core.urlresolvers import reverse
|
||||
|
|
@ -262,6 +262,11 @@ class TestPageCreation(TestCase, WagtailTestUtils):
|
|||
self.assertTemplateUsed(response, 'tests/simple_page.html')
|
||||
self.assertContains(response, "New page!")
|
||||
|
||||
# Check that the treebeard attributes were set correctly on the page object
|
||||
self.assertEqual(response.context['self'].depth, self.root_page.depth + 1)
|
||||
self.assertTrue(response.context['self'].path.startswith(self.root_page.path))
|
||||
self.assertEqual(response.context['self'].get_parent(), self.root_page)
|
||||
|
||||
|
||||
class TestPageEdit(TestCase, WagtailTestUtils):
|
||||
def setUp(self):
|
||||
|
|
@ -759,3 +764,48 @@ class TestContentTypeUse(TestCase, WagtailTestUtils):
|
|||
self.assertEqual(response.status_code, 200)
|
||||
self.assertTemplateUsed(response, 'wagtailadmin/pages/content_type_use.html')
|
||||
self.assertContains(response, "Christmas")
|
||||
|
||||
|
||||
class TestSubpageBusinessRules(TestCase, WagtailTestUtils):
|
||||
def setUp(self):
|
||||
# Find root page
|
||||
self.root_page = Page.objects.get(id=2)
|
||||
|
||||
# Add standard page
|
||||
self.standard_index = StandardIndex()
|
||||
self.standard_index.title = "Standard Index"
|
||||
self.standard_index.slug = "standard-index"
|
||||
self.root_page.add_child(instance=self.standard_index)
|
||||
|
||||
# Add business page
|
||||
self.business_index = BusinessIndex()
|
||||
self.business_index.title = "Business Index"
|
||||
self.business_index.slug = "business-index"
|
||||
self.root_page.add_child(instance=self.business_index)
|
||||
|
||||
# Add business child
|
||||
self.business_child = BusinessChild()
|
||||
self.business_child.title = "Business Child"
|
||||
self.business_child.slug = "business-child"
|
||||
self.business_index.add_child(instance=self.business_child)
|
||||
|
||||
# Login
|
||||
self.login()
|
||||
|
||||
def test_standard_subpage(self):
|
||||
response = self.client.get(reverse('wagtailadmin_pages_add_subpage', args=(self.standard_index.id, )))
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertContains(response, 'Standard Child')
|
||||
self.assertContains(response, 'Business Child')
|
||||
|
||||
def test_business_subpage(self):
|
||||
response = self.client.get(reverse('wagtailadmin_pages_add_subpage', args=(self.business_index.id, )))
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertNotContains(response, 'Standard Child')
|
||||
self.assertContains(response, 'Business Child')
|
||||
|
||||
def test_business_child_subpage(self):
|
||||
response = self.client.get(reverse('wagtailadmin_pages_add_subpage', args=(self.business_child.id, )))
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertNotContains(response, 'Standard Child')
|
||||
self.assertEqual(0, len(response.context['page_types']))
|
||||
|
|
|
|||
|
|
@ -55,13 +55,11 @@ def add_subpage(request, parent_page_id):
|
|||
if not parent_page.permissions_for_user(request.user).can_add_subpage():
|
||||
raise PermissionDenied
|
||||
|
||||
page_types = sorted([ContentType.objects.get_for_model(model_class) for model_class in parent_page.clean_subpage_types()], key=lambda pagetype: pagetype.name.lower())
|
||||
all_page_types = sorted(get_page_types(), key=lambda pagetype: pagetype.name.lower())
|
||||
page_types = sorted(parent_page.clean_subpage_types(), key=lambda pagetype: pagetype.name.lower())
|
||||
|
||||
return render(request, 'wagtailadmin/pages/add_subpage.html', {
|
||||
'parent_page': parent_page,
|
||||
'page_types': page_types,
|
||||
'all_page_types': all_page_types,
|
||||
})
|
||||
|
||||
|
||||
|
|
@ -364,6 +362,10 @@ def preview_on_create(request, content_type_app_name, content_type_model_name, p
|
|||
parent_page = get_object_or_404(Page, id=parent_page_id).specific
|
||||
page.set_url_path(parent_page)
|
||||
|
||||
# Set treebeard attributes
|
||||
page.depth = parent_page.depth + 1
|
||||
page.path = Page._get_children_path_interval(parent_page.path)[1]
|
||||
|
||||
# This view will generally be invoked as an AJAX request; as such, in the case of
|
||||
# an error Django will return a plaintext response. This isn't what we want, since
|
||||
# we will be writing the response back to an HTML page regardless of success or
|
||||
|
|
|
|||
|
|
@ -1,9 +1,13 @@
|
|||
from django.shortcuts import render
|
||||
from django.contrib.auth.decorators import permission_required
|
||||
|
||||
from wagtail.wagtailadmin.userbar import EditPageItem, AddPageItem, ApproveModerationEditPageItem, RejectModerationEditPageItem
|
||||
from wagtail.wagtailadmin import hooks
|
||||
from wagtail.wagtailcore.models import Page, PageRevision
|
||||
|
||||
|
||||
|
||||
@permission_required('wagtailadmin.access_admin')
|
||||
def for_frontend(request, page_id):
|
||||
items = [
|
||||
EditPageItem(Page.objects.get(id=page_id)),
|
||||
|
|
@ -24,6 +28,8 @@ def for_frontend(request, page_id):
|
|||
'items': rendered_items,
|
||||
})
|
||||
|
||||
|
||||
@permission_required('wagtailadmin.access_admin')
|
||||
def for_moderation(request, revision_id):
|
||||
items = [
|
||||
EditPageItem(PageRevision.objects.get(id=revision_id).page),
|
||||
|
|
@ -44,4 +50,4 @@ def for_moderation(request, revision_id):
|
|||
# Render the edit bird
|
||||
return render(request, 'wagtailadmin/userbar/base.html', {
|
||||
'items': rendered_items,
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import sys
|
||||
import os
|
||||
from StringIO import StringIO
|
||||
from urlparse import urlparse
|
||||
import warnings
|
||||
|
||||
from modelcluster.models import ClusterableModel
|
||||
|
||||
|
|
@ -101,30 +100,29 @@ def get_page_types():
|
|||
return _PAGE_CONTENT_TYPES
|
||||
|
||||
|
||||
LEAF_PAGE_MODEL_CLASSES = []
|
||||
_LEAF_PAGE_CONTENT_TYPE_IDS = []
|
||||
|
||||
|
||||
def get_leaf_page_content_type_ids():
|
||||
global _LEAF_PAGE_CONTENT_TYPE_IDS
|
||||
if len(_LEAF_PAGE_CONTENT_TYPE_IDS) != len(LEAF_PAGE_MODEL_CLASSES):
|
||||
_LEAF_PAGE_CONTENT_TYPE_IDS = [
|
||||
ContentType.objects.get_for_model(cls).id for cls in LEAF_PAGE_MODEL_CLASSES
|
||||
]
|
||||
return _LEAF_PAGE_CONTENT_TYPE_IDS
|
||||
|
||||
|
||||
NAVIGABLE_PAGE_MODEL_CLASSES = []
|
||||
_NAVIGABLE_PAGE_CONTENT_TYPE_IDS = []
|
||||
|
||||
warnings.warn("""
|
||||
get_leaf_page_content_type_ids is deprecated, as it treats pages without an explicit subpage_types
|
||||
setting as 'leaf' pages. Code that calls get_leaf_page_content_type_ids must be rewritten to avoid
|
||||
this incorrect assumption.
|
||||
""", DeprecationWarning)
|
||||
return [
|
||||
content_type.id
|
||||
for content_type in get_page_types()
|
||||
if not getattr(content_type.model_class(), 'subpage_types', None)
|
||||
]
|
||||
|
||||
def get_navigable_page_content_type_ids():
|
||||
global _NAVIGABLE_PAGE_CONTENT_TYPE_IDS
|
||||
if len(_NAVIGABLE_PAGE_CONTENT_TYPE_IDS) != len(NAVIGABLE_PAGE_MODEL_CLASSES):
|
||||
_NAVIGABLE_PAGE_CONTENT_TYPE_IDS = [
|
||||
ContentType.objects.get_for_model(cls).id for cls in NAVIGABLE_PAGE_MODEL_CLASSES
|
||||
]
|
||||
return _NAVIGABLE_PAGE_CONTENT_TYPE_IDS
|
||||
warnings.warn("""
|
||||
get_navigable_page_content_type_ids is deprecated, as it treats pages without an explicit subpage_types
|
||||
setting as 'leaf' pages. Code that calls get_navigable_page_content_type_ids must be rewritten to avoid
|
||||
this incorrect assumption.
|
||||
""", DeprecationWarning)
|
||||
return [
|
||||
content_type.id
|
||||
for content_type in get_page_types()
|
||||
if getattr(content_type.model_class(), 'subpage_types', None)
|
||||
]
|
||||
|
||||
|
||||
class PageManager(models.Manager):
|
||||
|
|
@ -209,10 +207,6 @@ class PageBase(models.base.ModelBase):
|
|||
if not cls.is_abstract:
|
||||
# register this type in the list of page content types
|
||||
PAGE_MODEL_CLASSES.append(cls)
|
||||
if cls.subpage_types:
|
||||
NAVIGABLE_PAGE_MODEL_CLASSES.append(cls)
|
||||
else:
|
||||
LEAF_PAGE_MODEL_CLASSES.append(cls)
|
||||
|
||||
|
||||
class Page(MP_Node, ClusterableModel, Indexed):
|
||||
|
|
@ -259,9 +253,6 @@ class Page(MP_Node, ClusterableModel, Indexed):
|
|||
def __unicode__(self):
|
||||
return self.title
|
||||
|
||||
# by default pages do not allow any kind of subpages
|
||||
subpage_types = []
|
||||
|
||||
is_abstract = True # don't offer Page in the list of page types a superuser can create
|
||||
|
||||
def set_url_path(self, parent):
|
||||
|
|
@ -416,10 +407,10 @@ class Page(MP_Node, ClusterableModel, Indexed):
|
|||
def is_navigable(self):
|
||||
"""
|
||||
Return true if it's meaningful to browse subpages of this page -
|
||||
i.e. it currently has subpages, or its page type indicates that sub-pages are supported,
|
||||
i.e. it currently has subpages,
|
||||
or it's at the top level (this rule necessary for empty out-of-the-box sites to have working navigation)
|
||||
"""
|
||||
return (not self.is_leaf()) or (self.content_type_id not in get_leaf_page_content_type_ids()) or self.depth == 2
|
||||
return (not self.is_leaf()) or self.depth == 2
|
||||
|
||||
def get_other_siblings(self):
|
||||
# get sibling pages excluding self
|
||||
|
|
@ -484,25 +475,30 @@ class Page(MP_Node, ClusterableModel, Indexed):
|
|||
where required
|
||||
"""
|
||||
if cls._clean_subpage_types is None:
|
||||
res = []
|
||||
for page_type in cls.subpage_types:
|
||||
if isinstance(page_type, basestring):
|
||||
try:
|
||||
app_label, model_name = page_type.split(".")
|
||||
except ValueError:
|
||||
# If we can't split, assume a model in current app
|
||||
app_label = cls._meta.app_label
|
||||
model_name = page_type
|
||||
subpage_types = getattr(cls, 'subpage_types', None)
|
||||
if subpage_types is None:
|
||||
# if subpage_types is not specified on the Page class, allow all page types as subpages
|
||||
res = get_page_types()
|
||||
else:
|
||||
res = []
|
||||
for page_type in cls.subpage_types:
|
||||
if isinstance(page_type, basestring):
|
||||
try:
|
||||
app_label, model_name = page_type.split(".")
|
||||
except ValueError:
|
||||
# If we can't split, assume a model in current app
|
||||
app_label = cls._meta.app_label
|
||||
model_name = page_type
|
||||
|
||||
model = get_model(app_label, model_name)
|
||||
if model:
|
||||
res.append(ContentType.objects.get_for_model(model))
|
||||
else:
|
||||
raise NameError(_("name '{0}' (used in subpage_types list) is not defined.").format(page_type))
|
||||
|
||||
model = get_model(app_label, model_name)
|
||||
if model:
|
||||
res.append(model)
|
||||
else:
|
||||
raise NameError(_("name '{0}' (used in subpage_types list) is not defined.").format(page_type))
|
||||
|
||||
else:
|
||||
# assume it's already a model class
|
||||
res.append(page_type)
|
||||
# assume it's already a model class
|
||||
res.append(ContentType.objects.get_for_model(page_type))
|
||||
|
||||
cls._clean_subpage_types = res
|
||||
|
||||
|
|
@ -652,13 +648,8 @@ class Page(MP_Node, ClusterableModel, Indexed):
|
|||
|
||||
def get_navigation_menu_items():
|
||||
# Get all pages that appear in the navigation menu: ones which have children,
|
||||
# or are a non-leaf type (indicating that they *could* have children),
|
||||
# or are at the top-level (this rule required so that an empty site out-of-the-box has a working menu)
|
||||
navigable_content_type_ids = get_navigable_page_content_type_ids()
|
||||
if navigable_content_type_ids:
|
||||
pages = Page.objects.filter(Q(content_type__in=navigable_content_type_ids)|Q(depth=2)|Q(numchild__gt=0)).order_by('path')
|
||||
else:
|
||||
pages = Page.objects.filter(Q(depth=2)|Q(numchild__gt=0)).order_by('path')
|
||||
pages = Page.objects.filter(Q(depth=2)|Q(numchild__gt=0)).order_by('path')
|
||||
|
||||
# Turn this into a tree structure:
|
||||
# tree_node = (page, children)
|
||||
|
|
|
|||
Loading…
Reference in a new issue