mirror of
https://github.com/Hopiu/wagtail.git
synced 2026-04-15 20:41:01 +00:00
Merge branch 'master' into more-unit-tests
Conflicts: wagtail/wagtailembeds/embeds.py
This commit is contained in:
commit
504bc1c4f6
24 changed files with 1293 additions and 959 deletions
|
|
@ -190,6 +190,32 @@ Only fields using ``RichTextField`` need this applied in the template.
|
|||
.. Note::
|
||||
Note that the template tag loaded differs from the name of the filter.
|
||||
|
||||
Responsive Embeds
|
||||
-----------------
|
||||
|
||||
Wagtail embeds and images are included at their full width, which may overflow the bounds of the content container you've defined in your templates. To make images and embeds responsive -- meaning they'll resize to fit their container -- include the following CSS.
|
||||
|
||||
.. code-block:: css
|
||||
|
||||
.rich-text img {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.responsive-object {
|
||||
position: relative;
|
||||
}
|
||||
.responsive-object iframe,
|
||||
.responsive-object object,
|
||||
.responsive-object embed {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
|
||||
Internal links (tag)
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
|
|
|||
|
|
@ -211,7 +211,7 @@ You can explicitly link ``Page``-derived models together using the ``Page`` mode
|
|||
Snippets
|
||||
--------
|
||||
|
||||
Snippets are not subclasses, so you must include the model class directly. A chooser is provided which takes the field name snippet class.
|
||||
Snippets are vanilla Django models you create yourself without a Wagtail-provided base class. So using them as a field in a page requires specifying your own ``appname.modelname``. A chooser, ``SnippetChooserPanel``, is provided which takes the field name and snippet class.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
|
|
@ -248,6 +248,12 @@ Full-Width Input
|
|||
Use ``classname="full"`` to make a field (input element) stretch the full width of the Wagtail page editor. This will not work if the field is encapsulated in a ``MultiFieldPanel``, which places its child fields into a formset.
|
||||
|
||||
|
||||
Titles
|
||||
------
|
||||
|
||||
Use ``classname="title"`` to make Page's built-in title field stand out with more vertical padding.
|
||||
|
||||
|
||||
Required Fields
|
||||
---------------
|
||||
|
||||
|
|
@ -264,19 +270,11 @@ Without a panel definition, a default form field (without label) will be used to
|
|||
.. _Django model field reference (editable): https://docs.djangoproject.com/en/dev/ref/models/fields/#editable
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
MultiFieldPanel
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
The ``MultiFieldPanel`` groups a list of child fields into a fieldset, which can also be collapsed into a heading bar to save space.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
BOOK_FIELD_COLLECTION = [
|
||||
|
|
@ -294,8 +292,7 @@ MultiFieldPanel
|
|||
# ...
|
||||
]
|
||||
|
||||
|
||||
|
||||
By default, ``MultiFieldPanel`` s are expanded and not collapsible. Adding the classname ``collapsible`` will enable the collapse control. Adding both ``collapsible`` and ``collapsed`` to the classname parameter will load the editor page with the ``MultiFieldPanel`` collapsed under its heading.
|
||||
|
||||
|
||||
.. _inline_panels:
|
||||
|
|
@ -303,7 +300,55 @@ MultiFieldPanel
|
|||
Inline Panels and Model Clusters
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The ``django-modelcluster`` module allows for streamlined relation of extra models to a Wagtail page.
|
||||
The ``django-modelcluster`` module allows for streamlined relation of extra models to a Wagtail page. For instance, you can create objects related through a ``ForeignKey`` relationship on the fly and save them to a draft revision of a ``Page`` object. Normally, your related objects "cluster" would need to be created beforehand (or asynchronously) before linking them to a Page.
|
||||
|
||||
Let's look at the example of adding related links to a ``Page``-derived model. We want to be able to add as many as we like, assign an order, and do all of this without leaving the page editing screen.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from wagtail.wagtailcore.models import Orderable, Page
|
||||
from modelcluster.fields import ParentalKey
|
||||
|
||||
# The abstract model for related links, complete with panels
|
||||
class RelatedLink(models.Model):
|
||||
title = models.CharField(max_length=255)
|
||||
link_external = models.URLField("External link", blank=True)
|
||||
|
||||
panels = [
|
||||
FieldPanel('title'),
|
||||
FieldPanel('link_external'),
|
||||
]
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
||||
# The real model which combines the abstract model, an
|
||||
# Orderable helper class, and what amounts to a ForeignKey link
|
||||
# to the model we want to add related links to (BookPage)
|
||||
class BookPageRelatedLinks(Orderable, RelatedLink):
|
||||
page = ParentalKey('demo.BookPage', related_name='related_links')
|
||||
|
||||
class BookPage( Page ):
|
||||
# ...
|
||||
|
||||
BookPage.content_panels = [
|
||||
# ...
|
||||
InlinePanel( BookPage, 'related_links', label="Related Links" ),
|
||||
]
|
||||
|
||||
The ``RelatedLink`` class is a vanilla Django abstract model. The ``BookPageRelatedLinks`` model extends it with capability for being ordered in the Wagtail interface via the ``Orderable`` class as well as adding a ``page`` property which links the model to the ``BookPage`` model we're adding the related links objects to. Finally, in the panel definitions for ``BookPage``, we'll add an ``InlinePanel`` to provide an interface for it all. Let's look again at the parameters that ``InlinePanel`` accepts:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
InlinePanel( base_model, relation_name, panels=None, label='', help_text='' )
|
||||
|
||||
``base_model`` is the model you're extending with the cluster. The ``relation_name`` is the ``related_name`` label given to the cluster's ``ParentalKey`` relation. You can add the ``panels`` manually or make them part of the cluster model. Finally, ``label`` and ``help_text`` provide a heading and caption, respectively, for the Wagtail editor.
|
||||
|
||||
For another example of using model clusters, see :ref:`tagging`
|
||||
|
||||
For more on ``django-modelcluster``, visit `the django-modelcluster github project page`_ ).
|
||||
|
||||
.. _the django-modelcluster github page: https://github.com/torchbox/django-modelcluster
|
||||
|
||||
|
||||
.. _extending_wysiwyg:
|
||||
|
|
@ -311,12 +356,205 @@ The ``django-modelcluster`` module allows for streamlined relation of extra mode
|
|||
Extending the WYSIWYG Editor (hallo.js)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Adding hallo.js plugins:
|
||||
https://github.com/torchbox/wagtail/commit/1ecc215759142e6cafdacb185bbfd3f8e9cd3185
|
||||
To inject javascript into the Wagtail page editor, see the :ref:`insert_editor_js` hook. Once you have the hook in place and your hallo.js plugin loads into the Wagtail page editor, use the following Javascript to register the plugin with hallo.js.
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
registerHalloPlugin(name, opts);
|
||||
|
||||
hallo.js plugin names are prefixed with the ``"IKS."`` namespace, but the ``name`` you pass into ``registerHalloPlugin()`` should be without the prefix. ``opts`` is an object passed into the plugin.
|
||||
|
||||
For information on developing custom hallo.js plugins, see the project's page: https://github.com/bergie/hallo
|
||||
|
||||
|
||||
Edit Handler API
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
Hooks
|
||||
-----
|
||||
|
||||
On loading, Wagtail will search for any app with the file ``wagtail_hooks.py`` and execute the contents. This provides a way to register your own functions to execute at certain points in Wagtail's execution, such as when a ``Page`` object is saved or when the main menu is constructed.
|
||||
|
||||
Registering functions with a Wagtail hook follows the following pattern:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from wagtail.wagtailadmin import hooks
|
||||
|
||||
hooks.register('hook', function)
|
||||
|
||||
Where ``'hook'`` is one of the following hook strings and ``function`` is a function you've defined to handle the hook.
|
||||
|
||||
.. _construct_wagtail_edit_bird:
|
||||
|
||||
``construct_wagtail_edit_bird``
|
||||
Add or remove items from the wagtail userbar. Add, edit, and moderation tools are provided by default. The callable passed into the hook must take the ``request`` object and a list of menu objects, ``items``. The menu item objects must have a ``render`` method which can take a ``request`` object and return the HTML string representing the menu item. See the userbar templates and menu item classes for more information.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from wagtail.wagtailadmin import hooks
|
||||
|
||||
class UserbarPuppyLinkItem(object):
|
||||
def render(self, request):
|
||||
return '<li><a href="http://cuteoverload.com/tag/puppehs/" ' \
|
||||
+ 'target="_parent" class="action icon icon-wagtail">Puppies!</a></li>'
|
||||
|
||||
def add_puppy_link_item(request, items):
|
||||
return items.append( UserbarPuppyLinkItem() )
|
||||
|
||||
hooks.register('construct_wagtail_edit_bird', add_puppy_link_item)
|
||||
|
||||
.. _construct_homepage_panels:
|
||||
|
||||
``construct_homepage_panels``
|
||||
Add or remove panels from the Wagtail admin homepage. The callable passed into this hook should take a ``request`` object and a list of ``panels``, objects which have a ``render()`` method returning a string. The objects also have an ``order`` property, an integer used for ordering the panels. The default panels use integers between ``100`` and ``300``.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from django.utils.safestring import mark_safe
|
||||
|
||||
from wagtail.wagtailadmin import hooks
|
||||
|
||||
class WelcomePanel(object):
|
||||
order = 50
|
||||
|
||||
def render(self):
|
||||
return mark_safe("""
|
||||
<section class="panel summary nice-padding">
|
||||
<h3>No, but seriously -- welcome to the admin homepage.</h3>
|
||||
</section>
|
||||
""")
|
||||
|
||||
def add_another_welcome_panel(request, panels):
|
||||
return panels.append( WelcomePanel() )
|
||||
|
||||
hooks.register('construct_homepage_panels', add_another_welcome_panel)
|
||||
|
||||
.. _after_create_page:
|
||||
|
||||
``after_create_page``
|
||||
Do something with a ``Page`` object after it has been saved to the database (as a published page or a revision). The callable passed to this hook should take a ``request`` object and a ``page`` object. The function does not have to return anything, but if an object with a ``status_code`` property is returned, Wagtail will use it as a response object. By default, Wagtail will instead redirect to the Explorer page for the new page's parent.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from django.http import HttpResponse
|
||||
|
||||
from wagtail.wagtailadmin import hooks
|
||||
|
||||
def do_after_page_create(request, page):
|
||||
return HttpResponse("Congrats on making content!", content_type="text/plain")
|
||||
hooks.register('after_create_page', do_after_page_create)
|
||||
|
||||
.. _after_edit_page:
|
||||
|
||||
``after_edit_page``
|
||||
Do something with a ``Page`` object after it has been updated. Uses the same behavior as ``after_create_page``.
|
||||
|
||||
.. _after_delete_page:
|
||||
|
||||
``after_delete_page``
|
||||
Do something after a ``Page`` object is deleted. Uses the same behavior as ``after_create_page``.
|
||||
|
||||
.. _register_admin_urls:
|
||||
|
||||
``register_admin_urls``
|
||||
Register additional admin page URLs. The callable fed into this hook should return a list of Django URL patterns which define the structure of the pages and endpoints of your extension to the Wagtail admin. For more about vanilla Django URLconfs and views, see `url dispatcher`_.
|
||||
|
||||
.. _url dispatcher: https://docs.djangoproject.com/en/dev/topics/http/urls/
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from django.http import HttpResponse
|
||||
from django.conf.urls import url
|
||||
|
||||
from wagtail.wagtailadmin import hooks
|
||||
|
||||
def admin_view( request ):
|
||||
return HttpResponse( \
|
||||
"I have approximate knowledge of many things!", \
|
||||
content_type="text/plain")
|
||||
|
||||
def urlconf_time():
|
||||
return [
|
||||
url(r'^how_did_you_almost_know_my_name/$', admin_view, name='frank' ),
|
||||
]
|
||||
hooks.register('register_admin_urls', urlconf_time)
|
||||
|
||||
.. _construct_main_menu:
|
||||
|
||||
``construct_main_menu``
|
||||
Add, remove, or alter ``MenuItem`` objects from the Wagtail admin menu. The callable passed to this hook must take a ``request`` object and a list of ``menu_items``; it must return a list of menu items. New items can be constructed from the ``MenuItem`` class by passing in: a ``label`` which will be the text in the menu item, the URL of the admin page you want the menu item to link to (usually by calling ``reverse()`` on the admin view you've set up), CSS class ``name`` applied to the wrapping ``<li>`` of the menu item as ``"menu-{name}"``, CSS ``classnames`` which are used to give the link an icon, and an ``order`` integer which determine's the item's place in the menu.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from django.core.urlresolvers import reverse
|
||||
|
||||
from wagtail.wagtailadmin import hooks
|
||||
from wagtail.wagtailadmin.menu import MenuItem
|
||||
|
||||
def construct_main_menu(request, menu_items):
|
||||
menu_items.append(
|
||||
MenuItem( 'Frank', reverse('frank'), classnames='icon icon-folder-inverse', order=10000)
|
||||
)
|
||||
hooks.register('construct_main_menu', construct_main_menu)
|
||||
|
||||
|
||||
.. _insert_editor_js:
|
||||
|
||||
``insert_editor_js``
|
||||
Add additional Javascript files or code snippets to the page editor. Output must be compatible with ``compress``, as local static includes or string.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from django.utils.html import format_html, format_html_join
|
||||
from django.conf import settings
|
||||
|
||||
from wagtail.wagtailadmin import hooks
|
||||
|
||||
def editor_js():
|
||||
js_files = [
|
||||
'demo/js/hallo-plugins/hallo-demo-plugin.js',
|
||||
]
|
||||
js_includes = format_html_join('\n', '<script src="{0}{1}"></script>',
|
||||
((settings.STATIC_URL, filename) for filename in js_files)
|
||||
)
|
||||
return js_includes + format_html(
|
||||
"""
|
||||
<script>
|
||||
registerHalloPlugin('demoeditor');
|
||||
</script>
|
||||
"""
|
||||
)
|
||||
hooks.register('insert_editor_js', editor_js)
|
||||
|
||||
.. _insert_editor_css:
|
||||
|
||||
``insert_editor_css``
|
||||
Add additional CSS or SCSS files or snippets to the page editor. Output must be compatible with ``compress``, as local static includes or string.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from django.utils.html import format_html
|
||||
from django.conf import settings
|
||||
|
||||
from wagtail.wagtailadmin import hooks
|
||||
|
||||
def editor_css():
|
||||
return format_html('<link rel="stylesheet" href="' \
|
||||
+ settings.STATIC_URL \
|
||||
+ 'demo/css/vendor/font-awesome/css/font-awesome.min.css">')
|
||||
hooks.register('insert_editor_css', editor_css)
|
||||
|
||||
|
||||
Content Index Pages (CRUD)
|
||||
--------------------------
|
||||
|
||||
|
||||
Custom Choosers
|
||||
---------------
|
||||
|
||||
|
||||
Tests
|
||||
-----
|
||||
|
||||
|
|
|
|||
|
|
@ -118,6 +118,8 @@ Will return::
|
|||
tauntaun kennel bed and breakfast
|
||||
|
||||
|
||||
.. _tagging:
|
||||
|
||||
Tagging
|
||||
-------
|
||||
|
||||
|
|
|
|||
|
|
@ -255,18 +255,42 @@ FormPage.content_panels = [
|
|||
]
|
||||
|
||||
|
||||
# Snippets
|
||||
|
||||
# Snippets
|
||||
|
||||
class Advert(models.Model):
|
||||
url = models.URLField(null=True, blank=True)
|
||||
text = models.CharField(max_length=255)
|
||||
url = models.URLField(null=True, blank=True)
|
||||
text = models.CharField(max_length=255)
|
||||
|
||||
panels = [
|
||||
FieldPanel('url'),
|
||||
FieldPanel('text'),
|
||||
]
|
||||
panels = [
|
||||
FieldPanel('url'),
|
||||
FieldPanel('text'),
|
||||
]
|
||||
|
||||
def __unicode__(self):
|
||||
return self.text
|
||||
|
||||
def __unicode__(self):
|
||||
return self.text
|
||||
|
||||
register_snippet(Advert)
|
||||
|
||||
|
||||
# AlphaSnippet and ZuluSnippet are for testing ordering of
|
||||
# snippets when registering. They are named as such to ensure
|
||||
# thier ordering is clear. They are registered during testing
|
||||
# to ensure specific [in]correct register ordering
|
||||
|
||||
# AlphaSnippet is registered during TestSnippetOrdering
|
||||
class AlphaSnippet(models.Model):
|
||||
text = models.CharField(max_length=255)
|
||||
|
||||
def __unicode__(self):
|
||||
return self.text
|
||||
|
||||
|
||||
# ZuluSnippet is registered during TestSnippetOrdering
|
||||
class ZuluSnippet(models.Model):
|
||||
text = models.CharField(max_length=255)
|
||||
|
||||
def __unicode__(self):
|
||||
return self.text
|
||||
|
|
|
|||
|
|
@ -93,17 +93,6 @@ $(function(){
|
|||
});
|
||||
});
|
||||
|
||||
$(".nav-main .more > a").bind('click keydown', function(){
|
||||
var currentAlt = $(this).data('altstate');
|
||||
var newAlt = $(this).html();
|
||||
|
||||
$(this).html(currentAlt);
|
||||
$(this).data('altstate', newAlt);
|
||||
$(this).toggleClass('icon-arrow-up icon-arrow-down');
|
||||
$(this).parent().find('ul').toggle('fast');
|
||||
return false;
|
||||
});
|
||||
|
||||
$('#menu-search input').bind('focus', function(){
|
||||
$('#menu-search').addClass('focussed');
|
||||
}).bind('blur', function(){
|
||||
|
|
|
|||
|
|
@ -226,19 +226,6 @@ img{
|
|||
}
|
||||
}
|
||||
|
||||
.more{
|
||||
border:0;
|
||||
|
||||
> a{
|
||||
&:before{
|
||||
margin-right:0.4em;
|
||||
}
|
||||
font-size:0.8em;
|
||||
padding:0.2em 1.2em;
|
||||
background-color:$color-grey-1-1;
|
||||
}
|
||||
}
|
||||
|
||||
.avatar{
|
||||
display:none;
|
||||
}
|
||||
|
|
@ -312,10 +299,6 @@ img{
|
|||
}
|
||||
}
|
||||
|
||||
.js .nav-main .more ul{
|
||||
display:none;
|
||||
}
|
||||
|
||||
.explorer{
|
||||
position:absolute;
|
||||
margin-top:70px;
|
||||
|
|
@ -626,7 +609,7 @@ footer, .logo{
|
|||
padding-right:$desktop-nice-padding;
|
||||
}
|
||||
|
||||
body{
|
||||
.wrapper{
|
||||
margin-left:$menu-width;
|
||||
}
|
||||
|
||||
|
|
@ -645,7 +628,7 @@ footer, .logo{
|
|||
left:0;
|
||||
height:100%;
|
||||
width:$menu-width;
|
||||
margin-left: -$menu-width;
|
||||
margin-left: 0;
|
||||
|
||||
.inner{
|
||||
height:100%;
|
||||
|
|
|
|||
|
|
@ -3,14 +3,13 @@
|
|||
|
||||
.hallotoolbar{
|
||||
position:absolute;
|
||||
left:50px;
|
||||
left:$mobile-nice-padding;
|
||||
z-index:5;
|
||||
margin-top:4em;
|
||||
margin-left:0em;
|
||||
}
|
||||
.hallotoolbar.affixed{
|
||||
position:fixed;
|
||||
margin-left:140px;
|
||||
margin-top:0;
|
||||
}
|
||||
.hallotoolbar button{
|
||||
|
|
@ -148,18 +147,8 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: $breakpoint-desktop-larger){
|
||||
/* .hallotoolbar{
|
||||
margin:0 auto;
|
||||
position:absolute;
|
||||
left:-$menu-width;
|
||||
right:0;
|
||||
z-index:5;
|
||||
margin-top:3em;
|
||||
@media screen and (min-width: $breakpoint-mobile){
|
||||
.hallotoolbar{
|
||||
left:$menu-width + $desktop-nice-padding;
|
||||
}
|
||||
.hallotoolbar.affixed{
|
||||
position:fixed;
|
||||
margin:0 auto;
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
|
@ -229,4 +229,24 @@
|
|||
<tr><td colspan="3" class="no-results-message"><p>{% trans "No pages have been created." %}{% if parent_page and parent_page_perms.can_add_subpage %} {% blocktrans %}Why not <a href="{{ add_page_url }}">add one</a>?{% endblocktrans %}{% endif %}</td></tr>
|
||||
{% endif %}
|
||||
</tbody>
|
||||
</table>
|
||||
</table>
|
||||
|
||||
{% if parent_page and pages and pages.paginator %}
|
||||
<div class="pagination">
|
||||
<p>{% blocktrans with page_number=pages.number num_pages=pages.paginator.num_pages%}
|
||||
Page {{ page_number }} of {{ num_pages }}.
|
||||
{% endblocktrans %}</p>
|
||||
<ul>
|
||||
<li class="prev">
|
||||
{% if pages.has_previous %}
|
||||
<a href="{% url 'wagtailadmin_explore' parent_page.id %}?p={{ pages.previous_page_number }}{% if ordering %}&ordering={{ ordering }}{% endif %}" class="icon icon-arrow-left">{% trans "Previous" %}</a>
|
||||
{% endif %}
|
||||
</li>
|
||||
<li class="next">
|
||||
{% if pages.has_next %}
|
||||
<a href="{% url 'wagtailadmin_explore' parent_page.id %}?p={{ pages.next_page_number }}{% if ordering %}&ordering={{ ordering }}{% endif %}" class="icon icon-arrow-right-after">{% trans 'Next' %}</a>
|
||||
{% endif %}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
|
@ -10,19 +10,5 @@
|
|||
<div class="avatar icon icon-user"><a href="{% url 'wagtailadmin_account' %}" title="{% trans 'Account settings' %}">{% if request.user.email %}<img src="{% gravatar_url request.user.email %}" />{% endif %}</a></div>
|
||||
<a href="{% url 'wagtailadmin_logout' %}">{% trans "Log out" %}</a>
|
||||
</li>
|
||||
{% if request.user.is_superuser %} {# for now, 'More' links will be superuser-only #}
|
||||
<li class="more">
|
||||
<a href="#" class="icon icon-arrow-down" data-altstate="{% trans 'Less' %}">{% trans 'More' %}</a>
|
||||
<ul>
|
||||
<li class="menu-redirects"><a href="{% url 'wagtailredirects_index' %}" class="icon icon-redirect">{% trans 'Redirects' %}</a></li>
|
||||
<li class="menu-editorspicks"><a href="{% url 'wagtailsearch_editorspicks_index' %}" class="icon icon-pick">{% trans 'Editors Picks' %}</a></li>
|
||||
{% get_wagtailadmin_tab_urls as wagtailadmin_tab_urls %}
|
||||
{% for name, title in wagtailadmin_tab_urls %}
|
||||
<li class="menu-{{ title|slugify }}"><a href="{% url name %}" class="icon icon-{{name}}">{{ title }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
|
|
|
|||
|
|
@ -26,17 +26,6 @@ def explorer_subnav(nodes):
|
|||
}
|
||||
|
||||
|
||||
@register.assignment_tag
|
||||
def get_wagtailadmin_tab_urls():
|
||||
resolver = urlresolvers.get_resolver(None)
|
||||
return [
|
||||
(key, value[2].get("title", key))
|
||||
for key, value
|
||||
in resolver.reverse_dict.items()
|
||||
if isinstance(key, basestring) and key.startswith('wagtailadmin_tab_')
|
||||
]
|
||||
|
||||
|
||||
@register.inclusion_tag('wagtailadmin/shared/main_nav.html', takes_context=True)
|
||||
def main_nav(context):
|
||||
menu_items = [
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ class TestPageExplorer(TestCase):
|
|||
response = self.client.get(reverse('wagtailadmin_explore', args=(self.root_page.id, )))
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(self.root_page, response.context['parent_page'])
|
||||
self.assertTrue(response.context['pages'].filter(id=self.child_page.id).exists())
|
||||
self.assertTrue(response.context['pages'].paginator.object_list.filter(id=self.child_page.id).exists())
|
||||
|
||||
|
||||
class TestPageCreation(TestCase):
|
||||
|
|
|
|||
|
|
@ -33,6 +33,17 @@ def index(request, parent_page_id=None):
|
|||
else:
|
||||
ordering = 'title'
|
||||
|
||||
# Pagination
|
||||
if ordering != 'ord':
|
||||
p = request.GET.get('p', 1)
|
||||
paginator = Paginator(pages, 50)
|
||||
try:
|
||||
pages = paginator.page(p)
|
||||
except PageNotAnInteger:
|
||||
pages = paginator.page(1)
|
||||
except EmptyPage:
|
||||
pages = paginator.page(paginator.num_pages)
|
||||
|
||||
return render(request, 'wagtailadmin/pages/index.html', {
|
||||
'parent_page': parent_page,
|
||||
'ordering': ordering,
|
||||
|
|
|
|||
|
|
@ -1,860 +0,0 @@
|
|||
from django.test import TestCase, Client
|
||||
from django.http import HttpRequest, Http404
|
||||
from django.core import management
|
||||
from StringIO import StringIO
|
||||
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
from wagtail.wagtailcore.models import Page, Site, UserPagePermissionsProxy
|
||||
from wagtail.tests.models import EventPage, EventIndex, SimplePage
|
||||
|
||||
|
||||
class TestRouting(TestCase):
|
||||
fixtures = ['test.json']
|
||||
|
||||
def test_find_site_for_request(self):
|
||||
default_site = Site.objects.get(is_default_site=True)
|
||||
events_page = Page.objects.get(url_path='/home/events/')
|
||||
events_site = Site.objects.create(hostname='events.example.com', root_page=events_page)
|
||||
|
||||
# requests without a Host: header should be directed to the default site
|
||||
request = HttpRequest()
|
||||
request.path = '/'
|
||||
self.assertEqual(Site.find_for_request(request), default_site)
|
||||
|
||||
# requests with a known Host: header should be directed to the specific site
|
||||
request = HttpRequest()
|
||||
request.path = '/'
|
||||
request.META['HTTP_HOST'] = 'events.example.com'
|
||||
self.assertEqual(Site.find_for_request(request), events_site)
|
||||
|
||||
# requests with an unrecognised Host: header should be directed to the default site
|
||||
request = HttpRequest()
|
||||
request.path = '/'
|
||||
request.META['HTTP_HOST'] = 'unknown.example.com'
|
||||
self.assertEqual(Site.find_for_request(request), default_site)
|
||||
|
||||
def test_urls(self):
|
||||
default_site = Site.objects.get(is_default_site=True)
|
||||
homepage = Page.objects.get(url_path='/home/')
|
||||
christmas_page = Page.objects.get(url_path='/home/events/christmas/')
|
||||
|
||||
# Basic installation only has one site configured, so page.url will return local URLs
|
||||
self.assertEqual(homepage.full_url, 'http://localhost/')
|
||||
self.assertEqual(homepage.url, '/')
|
||||
self.assertEqual(homepage.relative_url(default_site), '/')
|
||||
|
||||
self.assertEqual(christmas_page.full_url, 'http://localhost/events/christmas/')
|
||||
self.assertEqual(christmas_page.url, '/events/christmas/')
|
||||
self.assertEqual(christmas_page.relative_url(default_site), '/events/christmas/')
|
||||
|
||||
def test_urls_with_multiple_sites(self):
|
||||
events_page = Page.objects.get(url_path='/home/events/')
|
||||
events_site = Site.objects.create(hostname='events.example.com', root_page=events_page)
|
||||
|
||||
default_site = Site.objects.get(is_default_site=True)
|
||||
homepage = Page.objects.get(url_path='/home/')
|
||||
christmas_page = Page.objects.get(url_path='/home/events/christmas/')
|
||||
|
||||
# with multiple sites, page.url will return full URLs to ensure that
|
||||
# they work across sites
|
||||
self.assertEqual(homepage.full_url, 'http://localhost/')
|
||||
self.assertEqual(homepage.url, 'http://localhost/')
|
||||
self.assertEqual(homepage.relative_url(default_site), '/')
|
||||
self.assertEqual(homepage.relative_url(events_site), 'http://localhost/')
|
||||
|
||||
self.assertEqual(christmas_page.full_url, 'http://events.example.com/christmas/')
|
||||
self.assertEqual(christmas_page.url, 'http://events.example.com/christmas/')
|
||||
self.assertEqual(christmas_page.relative_url(default_site), 'http://events.example.com/christmas/')
|
||||
self.assertEqual(christmas_page.relative_url(events_site), '/christmas/')
|
||||
|
||||
def test_request_routing(self):
|
||||
homepage = Page.objects.get(url_path='/home/')
|
||||
christmas_page = EventPage.objects.get(url_path='/home/events/christmas/')
|
||||
|
||||
request = HttpRequest()
|
||||
request.path = '/events/christmas/'
|
||||
response = homepage.route(request, ['events', 'christmas'])
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(response.context_data['self'], christmas_page)
|
||||
used_template = response.resolve_template(response.template_name)
|
||||
self.assertEqual(used_template.name, 'tests/event_page.html')
|
||||
|
||||
def test_route_to_unknown_page_returns_404(self):
|
||||
homepage = Page.objects.get(url_path='/home/')
|
||||
|
||||
request = HttpRequest()
|
||||
request.path = '/events/quinquagesima/'
|
||||
with self.assertRaises(Http404):
|
||||
homepage.route(request, ['events', 'quinquagesima'])
|
||||
|
||||
def test_route_to_unpublished_page_returns_404(self):
|
||||
homepage = Page.objects.get(url_path='/home/')
|
||||
|
||||
request = HttpRequest()
|
||||
request.path = '/events/tentative-unpublished-event/'
|
||||
with self.assertRaises(Http404):
|
||||
homepage.route(request, ['events', 'tentative-unpublished-event'])
|
||||
|
||||
|
||||
class TestServeView(TestCase):
|
||||
fixtures = ['test.json']
|
||||
|
||||
def setUp(self):
|
||||
# Explicitly clear the cache of site root paths. Normally this would be kept
|
||||
# in sync by the Site.save logic, but this is bypassed when the database is
|
||||
# rolled back between tests using transactions.
|
||||
from django.core.cache import cache
|
||||
cache.delete('wagtail_site_root_paths')
|
||||
|
||||
def test_serve(self):
|
||||
response = self.client.get('/events/christmas/')
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(response.templates[0].name, 'tests/event_page.html')
|
||||
christmas_page = EventPage.objects.get(url_path='/home/events/christmas/')
|
||||
self.assertEqual(response.context['self'], christmas_page)
|
||||
|
||||
self.assertContains(response, '<h1>Christmas</h1>')
|
||||
self.assertContains(response, '<h2>Event</h2>')
|
||||
|
||||
def test_serve_unknown_page_returns_404(self):
|
||||
response = self.client.get('/events/quinquagesima/')
|
||||
self.assertEqual(response.status_code, 404)
|
||||
|
||||
def test_serve_unpublished_page_returns_404(self):
|
||||
response = self.client.get('/events/tentative-unpublished-event/')
|
||||
self.assertEqual(response.status_code, 404)
|
||||
|
||||
def test_serve_with_multiple_sites(self):
|
||||
events_page = Page.objects.get(url_path='/home/events/')
|
||||
Site.objects.create(hostname='events.example.com', root_page=events_page)
|
||||
|
||||
response = self.client.get('/christmas/', HTTP_HOST='events.example.com')
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(response.templates[0].name, 'tests/event_page.html')
|
||||
christmas_page = EventPage.objects.get(url_path='/home/events/christmas/')
|
||||
self.assertEqual(response.context['self'], christmas_page)
|
||||
|
||||
self.assertContains(response, '<h1>Christmas</h1>')
|
||||
self.assertContains(response, '<h2>Event</h2>')
|
||||
|
||||
# same request to the default host should return a 404
|
||||
c = Client()
|
||||
response = c.get('/christmas/', HTTP_HOST='localhost')
|
||||
self.assertEqual(response.status_code, 404)
|
||||
|
||||
def test_serve_with_custom_context(self):
|
||||
response = self.client.get('/events/')
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
# should render the whole page
|
||||
self.assertContains(response, '<h1>Events</h1>')
|
||||
|
||||
# response should contain data from the custom 'events' context variable
|
||||
self.assertContains(response, '<a href="/events/christmas/">Christmas</a>')
|
||||
|
||||
def test_ajax_response(self):
|
||||
response = self.client.get('/events/', HTTP_X_REQUESTED_WITH='XMLHttpRequest')
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
# should only render the content of includes/event_listing.html, not the whole page
|
||||
self.assertNotContains(response, '<h1>Events</h1>')
|
||||
self.assertContains(response, '<a href="/events/christmas/">Christmas</a>')
|
||||
|
||||
|
||||
class TestStaticSitePaths(TestCase):
|
||||
def setUp(self):
|
||||
self.root_page = Page.objects.get(id=1)
|
||||
|
||||
# For simple tests
|
||||
self.home_page = self.root_page.add_child(instance=SimplePage(title="Homepage", slug="home"))
|
||||
self.about_page = self.home_page.add_child(instance=SimplePage(title="About us", slug="about"))
|
||||
self.contact_page = self.home_page.add_child(instance=SimplePage(title="Contact", slug="contact"))
|
||||
|
||||
# For custom tests
|
||||
self.event_index = self.root_page.add_child(instance=EventIndex(title="Events", slug="events"))
|
||||
for i in range(20):
|
||||
self.event_index.add_child(instance=EventPage(title="Event " + str(i), slug="event" + str(i)))
|
||||
|
||||
def test_local_static_site_paths(self):
|
||||
paths = list(self.about_page.get_static_site_paths())
|
||||
|
||||
self.assertEqual(paths, ['/'])
|
||||
|
||||
def test_child_static_site_paths(self):
|
||||
paths = list(self.home_page.get_static_site_paths())
|
||||
|
||||
self.assertEqual(paths, ['/', '/about/', '/contact/'])
|
||||
|
||||
def test_custom_static_site_paths(self):
|
||||
paths = list(self.event_index.get_static_site_paths())
|
||||
|
||||
# Event index path
|
||||
expected_paths = ['/']
|
||||
|
||||
# One path for each page of results
|
||||
expected_paths.extend(['/' + str(i + 1) + '/' for i in range(5)])
|
||||
|
||||
# One path for each event page
|
||||
expected_paths.extend(['/event' + str(i) + '/' for i in range(20)])
|
||||
|
||||
paths.sort()
|
||||
expected_paths.sort()
|
||||
self.assertEqual(paths, expected_paths)
|
||||
|
||||
|
||||
class TestPageUrlTags(TestCase):
|
||||
fixtures = ['test.json']
|
||||
|
||||
def test_pageurl_tag(self):
|
||||
response = self.client.get('/events/')
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertContains(response, '<a href="/events/christmas/">Christmas</a>')
|
||||
|
||||
def test_slugurl_tag(self):
|
||||
response = self.client.get('/events/christmas/')
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertContains(response, '<a href="/events/">Back to events index</a>')
|
||||
|
||||
|
||||
class TestPagePermission(TestCase):
|
||||
fixtures = ['test.json']
|
||||
|
||||
def test_nonpublisher_page_permissions(self):
|
||||
event_editor = User.objects.get(username='eventeditor')
|
||||
homepage = Page.objects.get(url_path='/home/')
|
||||
christmas_page = EventPage.objects.get(url_path='/home/events/christmas/')
|
||||
unpublished_event_page = EventPage.objects.get(url_path='/home/events/tentative-unpublished-event/')
|
||||
someone_elses_event_page = EventPage.objects.get(url_path='/home/events/someone-elses-event/')
|
||||
|
||||
homepage_perms = homepage.permissions_for_user(event_editor)
|
||||
christmas_page_perms = christmas_page.permissions_for_user(event_editor)
|
||||
unpub_perms = unpublished_event_page.permissions_for_user(event_editor)
|
||||
someone_elses_event_perms = someone_elses_event_page.permissions_for_user(event_editor)
|
||||
|
||||
self.assertFalse(homepage_perms.can_add_subpage())
|
||||
self.assertTrue(christmas_page_perms.can_add_subpage())
|
||||
self.assertTrue(unpub_perms.can_add_subpage())
|
||||
self.assertTrue(someone_elses_event_perms.can_add_subpage())
|
||||
|
||||
self.assertFalse(homepage_perms.can_edit())
|
||||
self.assertTrue(christmas_page_perms.can_edit())
|
||||
self.assertTrue(unpub_perms.can_edit())
|
||||
self.assertFalse(someone_elses_event_perms.can_edit()) # basic 'add' permission doesn't allow editing pages owned by someone else
|
||||
|
||||
self.assertFalse(homepage_perms.can_delete())
|
||||
self.assertFalse(christmas_page_perms.can_delete()) # cannot delete because it is published
|
||||
self.assertTrue(unpub_perms.can_delete())
|
||||
self.assertFalse(someone_elses_event_perms.can_delete())
|
||||
|
||||
self.assertFalse(homepage_perms.can_publish())
|
||||
self.assertFalse(christmas_page_perms.can_publish())
|
||||
self.assertFalse(unpub_perms.can_publish())
|
||||
|
||||
self.assertFalse(homepage_perms.can_unpublish())
|
||||
self.assertFalse(christmas_page_perms.can_unpublish())
|
||||
self.assertFalse(unpub_perms.can_unpublish())
|
||||
|
||||
self.assertFalse(homepage_perms.can_publish_subpage())
|
||||
self.assertFalse(christmas_page_perms.can_publish_subpage())
|
||||
self.assertFalse(unpub_perms.can_publish_subpage())
|
||||
|
||||
self.assertFalse(homepage_perms.can_reorder_children())
|
||||
self.assertFalse(christmas_page_perms.can_reorder_children())
|
||||
self.assertFalse(unpub_perms.can_reorder_children())
|
||||
|
||||
self.assertFalse(homepage_perms.can_move())
|
||||
self.assertFalse(christmas_page_perms.can_move()) # cannot move because this would involve unpublishing from its current location
|
||||
self.assertTrue(unpub_perms.can_move())
|
||||
self.assertFalse(someone_elses_event_perms.can_move())
|
||||
|
||||
self.assertFalse(christmas_page_perms.can_move_to(unpublished_event_page)) # cannot move because this would involve unpublishing from its current location
|
||||
self.assertTrue(unpub_perms.can_move_to(christmas_page))
|
||||
self.assertFalse(unpub_perms.can_move_to(homepage)) # no permission to create pages at destination
|
||||
self.assertFalse(unpub_perms.can_move_to(unpublished_event_page)) # cannot make page a child of itself
|
||||
|
||||
|
||||
def test_publisher_page_permissions(self):
|
||||
event_moderator = User.objects.get(username='eventmoderator')
|
||||
homepage = Page.objects.get(url_path='/home/')
|
||||
christmas_page = EventPage.objects.get(url_path='/home/events/christmas/')
|
||||
unpublished_event_page = EventPage.objects.get(url_path='/home/events/tentative-unpublished-event/')
|
||||
|
||||
homepage_perms = homepage.permissions_for_user(event_moderator)
|
||||
christmas_page_perms = christmas_page.permissions_for_user(event_moderator)
|
||||
unpub_perms = unpublished_event_page.permissions_for_user(event_moderator)
|
||||
|
||||
self.assertFalse(homepage_perms.can_add_subpage())
|
||||
self.assertTrue(christmas_page_perms.can_add_subpage())
|
||||
self.assertTrue(unpub_perms.can_add_subpage())
|
||||
|
||||
self.assertFalse(homepage_perms.can_edit())
|
||||
self.assertTrue(christmas_page_perms.can_edit())
|
||||
self.assertTrue(unpub_perms.can_edit())
|
||||
|
||||
self.assertFalse(homepage_perms.can_delete())
|
||||
self.assertTrue(christmas_page_perms.can_delete()) # cannot delete because it is published
|
||||
self.assertTrue(unpub_perms.can_delete())
|
||||
|
||||
self.assertFalse(homepage_perms.can_publish())
|
||||
self.assertTrue(christmas_page_perms.can_publish())
|
||||
self.assertTrue(unpub_perms.can_publish())
|
||||
|
||||
self.assertFalse(homepage_perms.can_unpublish())
|
||||
self.assertTrue(christmas_page_perms.can_unpublish())
|
||||
self.assertFalse(unpub_perms.can_unpublish()) # cannot unpublish a page that isn't published
|
||||
|
||||
self.assertFalse(homepage_perms.can_publish_subpage())
|
||||
self.assertTrue(christmas_page_perms.can_publish_subpage())
|
||||
self.assertTrue(unpub_perms.can_publish_subpage())
|
||||
|
||||
self.assertFalse(homepage_perms.can_reorder_children())
|
||||
self.assertTrue(christmas_page_perms.can_reorder_children())
|
||||
self.assertTrue(unpub_perms.can_reorder_children())
|
||||
|
||||
self.assertFalse(homepage_perms.can_move())
|
||||
self.assertTrue(christmas_page_perms.can_move())
|
||||
self.assertTrue(unpub_perms.can_move())
|
||||
|
||||
self.assertTrue(christmas_page_perms.can_move_to(unpublished_event_page))
|
||||
self.assertTrue(unpub_perms.can_move_to(christmas_page))
|
||||
self.assertFalse(unpub_perms.can_move_to(homepage)) # no permission to create pages at destination
|
||||
self.assertFalse(unpub_perms.can_move_to(unpublished_event_page)) # cannot make page a child of itself
|
||||
|
||||
def test_inactive_user_has_no_permissions(self):
|
||||
user = User.objects.get(username='inactiveuser')
|
||||
christmas_page = EventPage.objects.get(url_path='/home/events/christmas/')
|
||||
unpublished_event_page = EventPage.objects.get(url_path='/home/events/tentative-unpublished-event/')
|
||||
|
||||
christmas_page_perms = christmas_page.permissions_for_user(user)
|
||||
unpub_perms = unpublished_event_page.permissions_for_user(user)
|
||||
|
||||
self.assertFalse(unpub_perms.can_add_subpage())
|
||||
self.assertFalse(unpub_perms.can_edit())
|
||||
self.assertFalse(unpub_perms.can_delete())
|
||||
self.assertFalse(unpub_perms.can_publish())
|
||||
self.assertFalse(christmas_page_perms.can_unpublish())
|
||||
self.assertFalse(unpub_perms.can_publish_subpage())
|
||||
self.assertFalse(unpub_perms.can_reorder_children())
|
||||
self.assertFalse(unpub_perms.can_move())
|
||||
self.assertFalse(unpub_perms.can_move_to(christmas_page))
|
||||
|
||||
def test_superuser_has_full_permissions(self):
|
||||
user = User.objects.get(username='superuser')
|
||||
homepage = Page.objects.get(url_path='/home/')
|
||||
root = Page.objects.get(url_path='/')
|
||||
unpublished_event_page = EventPage.objects.get(url_path='/home/events/tentative-unpublished-event/')
|
||||
|
||||
homepage_perms = homepage.permissions_for_user(user)
|
||||
root_perms = root.permissions_for_user(user)
|
||||
unpub_perms = unpublished_event_page.permissions_for_user(user)
|
||||
|
||||
self.assertTrue(homepage_perms.can_add_subpage())
|
||||
self.assertTrue(root_perms.can_add_subpage())
|
||||
|
||||
self.assertTrue(homepage_perms.can_edit())
|
||||
self.assertFalse(root_perms.can_edit()) # root is not a real editable page, even to superusers
|
||||
|
||||
self.assertTrue(homepage_perms.can_delete())
|
||||
self.assertFalse(root_perms.can_delete())
|
||||
|
||||
self.assertTrue(homepage_perms.can_publish())
|
||||
self.assertFalse(root_perms.can_publish())
|
||||
|
||||
self.assertTrue(homepage_perms.can_unpublish())
|
||||
self.assertFalse(root_perms.can_unpublish())
|
||||
self.assertFalse(unpub_perms.can_unpublish())
|
||||
|
||||
self.assertTrue(homepage_perms.can_publish_subpage())
|
||||
self.assertTrue(root_perms.can_publish_subpage())
|
||||
|
||||
self.assertTrue(homepage_perms.can_reorder_children())
|
||||
self.assertTrue(root_perms.can_reorder_children())
|
||||
|
||||
self.assertTrue(homepage_perms.can_move())
|
||||
self.assertFalse(root_perms.can_move())
|
||||
|
||||
self.assertTrue(homepage_perms.can_move_to(root))
|
||||
self.assertFalse(homepage_perms.can_move_to(unpublished_event_page))
|
||||
|
||||
def test_editable_pages_for_user_with_add_permission(self):
|
||||
event_editor = User.objects.get(username='eventeditor')
|
||||
homepage = Page.objects.get(url_path='/home/')
|
||||
christmas_page = EventPage.objects.get(url_path='/home/events/christmas/')
|
||||
unpublished_event_page = EventPage.objects.get(url_path='/home/events/tentative-unpublished-event/')
|
||||
someone_elses_event_page = EventPage.objects.get(url_path='/home/events/someone-elses-event/')
|
||||
|
||||
editable_pages = UserPagePermissionsProxy(event_editor).editable_pages()
|
||||
|
||||
self.assertFalse(editable_pages.filter(id=homepage.id).exists())
|
||||
self.assertTrue(editable_pages.filter(id=christmas_page.id).exists())
|
||||
self.assertTrue(editable_pages.filter(id=unpublished_event_page.id).exists())
|
||||
self.assertFalse(editable_pages.filter(id=someone_elses_event_page.id).exists())
|
||||
|
||||
def test_editable_pages_for_user_with_edit_permission(self):
|
||||
event_moderator = User.objects.get(username='eventmoderator')
|
||||
homepage = Page.objects.get(url_path='/home/')
|
||||
christmas_page = EventPage.objects.get(url_path='/home/events/christmas/')
|
||||
unpublished_event_page = EventPage.objects.get(url_path='/home/events/tentative-unpublished-event/')
|
||||
someone_elses_event_page = EventPage.objects.get(url_path='/home/events/someone-elses-event/')
|
||||
|
||||
editable_pages = UserPagePermissionsProxy(event_moderator).editable_pages()
|
||||
|
||||
self.assertFalse(editable_pages.filter(id=homepage.id).exists())
|
||||
self.assertTrue(editable_pages.filter(id=christmas_page.id).exists())
|
||||
self.assertTrue(editable_pages.filter(id=unpublished_event_page.id).exists())
|
||||
self.assertTrue(editable_pages.filter(id=someone_elses_event_page.id).exists())
|
||||
|
||||
def test_editable_pages_for_inactive_user(self):
|
||||
user = User.objects.get(username='inactiveuser')
|
||||
homepage = Page.objects.get(url_path='/home/')
|
||||
christmas_page = EventPage.objects.get(url_path='/home/events/christmas/')
|
||||
unpublished_event_page = EventPage.objects.get(url_path='/home/events/tentative-unpublished-event/')
|
||||
someone_elses_event_page = EventPage.objects.get(url_path='/home/events/someone-elses-event/')
|
||||
|
||||
editable_pages = UserPagePermissionsProxy(user).editable_pages()
|
||||
|
||||
self.assertFalse(editable_pages.filter(id=homepage.id).exists())
|
||||
self.assertFalse(editable_pages.filter(id=christmas_page.id).exists())
|
||||
self.assertFalse(editable_pages.filter(id=unpublished_event_page.id).exists())
|
||||
self.assertFalse(editable_pages.filter(id=someone_elses_event_page.id).exists())
|
||||
|
||||
def test_editable_pages_for_superuser(self):
|
||||
user = User.objects.get(username='superuser')
|
||||
homepage = Page.objects.get(url_path='/home/')
|
||||
christmas_page = EventPage.objects.get(url_path='/home/events/christmas/')
|
||||
unpublished_event_page = EventPage.objects.get(url_path='/home/events/tentative-unpublished-event/')
|
||||
someone_elses_event_page = EventPage.objects.get(url_path='/home/events/someone-elses-event/')
|
||||
|
||||
editable_pages = UserPagePermissionsProxy(user).editable_pages()
|
||||
|
||||
self.assertTrue(editable_pages.filter(id=homepage.id).exists())
|
||||
self.assertTrue(editable_pages.filter(id=christmas_page.id).exists())
|
||||
self.assertTrue(editable_pages.filter(id=unpublished_event_page.id).exists())
|
||||
self.assertTrue(editable_pages.filter(id=someone_elses_event_page.id).exists())
|
||||
|
||||
|
||||
class TestPageQuerySet(TestCase):
|
||||
fixtures = ['test.json']
|
||||
|
||||
def test_live(self):
|
||||
pages = Page.objects.live()
|
||||
|
||||
# All pages must be live
|
||||
for page in pages:
|
||||
self.assertTrue(page.live)
|
||||
|
||||
# Check that the homepage is in the results
|
||||
homepage = Page.objects.get(url_path='/home/')
|
||||
self.assertTrue(pages.filter(id=homepage.id).exists())
|
||||
|
||||
def test_not_live(self):
|
||||
pages = Page.objects.not_live()
|
||||
|
||||
# All pages must not be live
|
||||
for page in pages:
|
||||
self.assertFalse(page.live)
|
||||
|
||||
# Check that "someone elses event" is in the results
|
||||
event = Page.objects.get(url_path='/home/events/someone-elses-event/')
|
||||
self.assertTrue(pages.filter(id=event.id).exists())
|
||||
|
||||
def test_page(self):
|
||||
homepage = Page.objects.get(url_path='/home/')
|
||||
pages = Page.objects.page(homepage)
|
||||
|
||||
# Should only select the homepage
|
||||
self.assertEqual(pages.count(), 1)
|
||||
self.assertEqual(pages.first(), homepage)
|
||||
|
||||
def test_not_page(self):
|
||||
homepage = Page.objects.get(url_path='/home/')
|
||||
pages = Page.objects.not_page(homepage)
|
||||
|
||||
# Should select everything except for the homepage
|
||||
self.assertEqual(pages.count(), Page.objects.all().count() - 1)
|
||||
for page in pages:
|
||||
self.assertNotEqual(page, homepage)
|
||||
|
||||
def test_descendant_of(self):
|
||||
events_index = Page.objects.get(url_path='/home/events/')
|
||||
pages = Page.objects.descendant_of(events_index)
|
||||
|
||||
# Check that all pages descend from events index
|
||||
for page in pages:
|
||||
self.assertTrue(page.get_ancestors().filter(id=events_index.id).exists())
|
||||
|
||||
def test_descendant_of_inclusive(self):
|
||||
events_index = Page.objects.get(url_path='/home/events/')
|
||||
pages = Page.objects.descendant_of(events_index, inclusive=True)
|
||||
|
||||
# Check that all pages descend from events index, includes event index
|
||||
for page in pages:
|
||||
self.assertTrue(page == events_index or page.get_ancestors().filter(id=events_index.id).exists())
|
||||
|
||||
# Check that event index was included
|
||||
self.assertTrue(pages.filter(id=events_index.id).exists())
|
||||
|
||||
def test_not_descendant_of(self):
|
||||
homepage = Page.objects.get(url_path='/home/')
|
||||
events_index = Page.objects.get(url_path='/home/events/')
|
||||
pages = Page.objects.not_descendant_of(events_index)
|
||||
|
||||
# Check that no pages descend from events_index
|
||||
for page in pages:
|
||||
self.assertFalse(page.get_ancestors().filter(id=events_index.id).exists())
|
||||
|
||||
# As this is not inclusive, events index should be in the results
|
||||
self.assertTrue(pages.filter(id=events_index.id).exists())
|
||||
|
||||
def test_not_descendant_of_inclusive(self):
|
||||
homepage = Page.objects.get(url_path='/home/')
|
||||
events_index = Page.objects.get(url_path='/home/events/')
|
||||
pages = Page.objects.not_descendant_of(events_index, inclusive=True)
|
||||
|
||||
# Check that all pages descend from homepage but not events index
|
||||
for page in pages:
|
||||
self.assertFalse(page.get_ancestors().filter(id=events_index.id).exists())
|
||||
|
||||
# As this is inclusive, events index should not be in the results
|
||||
self.assertFalse(pages.filter(id=events_index.id).exists())
|
||||
|
||||
def test_child_of(self):
|
||||
homepage = Page.objects.get(url_path='/home/')
|
||||
pages = Page.objects.child_of(homepage)
|
||||
|
||||
# Check that all pages are children of homepage
|
||||
for page in pages:
|
||||
self.assertEqual(page.get_parent(), homepage)
|
||||
|
||||
def test_not_child_of(self):
|
||||
events_index = Page.objects.get(url_path='/home/events/')
|
||||
pages = Page.objects.not_child_of(events_index)
|
||||
|
||||
# Check that all pages are not children of events_index
|
||||
for page in pages:
|
||||
self.assertNotEqual(page.get_parent(), events_index)
|
||||
|
||||
def test_ancestor_of(self):
|
||||
root_page = Page.objects.get(id=1)
|
||||
homepage = Page.objects.get(url_path='/home/')
|
||||
events_index = Page.objects.get(url_path='/home/events/')
|
||||
pages = Page.objects.ancestor_of(events_index)
|
||||
|
||||
self.assertEqual(pages.count(), 2)
|
||||
self.assertEqual(pages[0], root_page)
|
||||
self.assertEqual(pages[1], homepage)
|
||||
|
||||
def test_ancestor_of_inclusive(self):
|
||||
root_page = Page.objects.get(id=1)
|
||||
homepage = Page.objects.get(url_path='/home/')
|
||||
events_index = Page.objects.get(url_path='/home/events/')
|
||||
pages = Page.objects.ancestor_of(events_index, inclusive=True)
|
||||
|
||||
self.assertEqual(pages.count(), 3)
|
||||
self.assertEqual(pages[0], root_page)
|
||||
self.assertEqual(pages[1], homepage)
|
||||
self.assertEqual(pages[2], events_index)
|
||||
|
||||
def test_not_ancestor_of(self):
|
||||
root_page = Page.objects.get(id=1)
|
||||
homepage = Page.objects.get(url_path='/home/')
|
||||
events_index = Page.objects.get(url_path='/home/events/')
|
||||
pages = Page.objects.not_ancestor_of(events_index)
|
||||
|
||||
# Test that none of the ancestors are in pages
|
||||
for page in pages:
|
||||
self.assertNotEqual(page, root_page)
|
||||
self.assertNotEqual(page, homepage)
|
||||
|
||||
# Test that events index is in pages
|
||||
self.assertTrue(pages.filter(id=events_index.id).exists())
|
||||
|
||||
def test_not_ancestor_of_inclusive(self):
|
||||
root_page = Page.objects.get(id=1)
|
||||
homepage = Page.objects.get(url_path='/home/')
|
||||
events_index = Page.objects.get(url_path='/home/events/')
|
||||
pages = Page.objects.not_ancestor_of(events_index, inclusive=True)
|
||||
|
||||
# Test that none of the ancestors or the events_index are in pages
|
||||
for page in pages:
|
||||
self.assertNotEqual(page, root_page)
|
||||
self.assertNotEqual(page, homepage)
|
||||
self.assertNotEqual(page, events_index)
|
||||
|
||||
def test_parent_of(self):
|
||||
homepage = Page.objects.get(url_path='/home/')
|
||||
events_index = Page.objects.get(url_path='/home/events/')
|
||||
pages = Page.objects.parent_of(events_index)
|
||||
|
||||
# Pages must only contain homepage
|
||||
self.assertEqual(pages.count(), 1)
|
||||
self.assertEqual(pages[0], homepage)
|
||||
|
||||
def test_not_parent_of(self):
|
||||
homepage = Page.objects.get(url_path='/home/')
|
||||
events_index = Page.objects.get(url_path='/home/events/')
|
||||
pages = Page.objects.not_parent_of(events_index)
|
||||
|
||||
# Pages must not contain homepage
|
||||
for page in pages:
|
||||
self.assertNotEqual(page, homepage)
|
||||
|
||||
# Test that events index is in pages
|
||||
self.assertTrue(pages.filter(id=events_index.id).exists())
|
||||
|
||||
def test_sibling_of(self):
|
||||
events_index = Page.objects.get(url_path='/home/events/')
|
||||
event = Page.objects.get(url_path='/home/events/christmas/')
|
||||
pages = Page.objects.sibling_of(event)
|
||||
|
||||
# Check that all pages are children of events_index
|
||||
for page in pages:
|
||||
self.assertEqual(page.get_parent(), events_index)
|
||||
|
||||
# Check that the event is not included
|
||||
self.assertFalse(pages.filter(id=event.id).exists())
|
||||
|
||||
def test_sibling_of_inclusive(self):
|
||||
events_index = Page.objects.get(url_path='/home/events/')
|
||||
event = Page.objects.get(url_path='/home/events/christmas/')
|
||||
pages = Page.objects.sibling_of(event, inclusive=True)
|
||||
|
||||
# Check that all pages are children of events_index
|
||||
for page in pages:
|
||||
self.assertEqual(page.get_parent(), events_index)
|
||||
|
||||
# Check that the event is included
|
||||
self.assertTrue(pages.filter(id=event.id).exists())
|
||||
|
||||
def test_not_sibling_of(self):
|
||||
events_index = Page.objects.get(url_path='/home/events/')
|
||||
event = Page.objects.get(url_path='/home/events/christmas/')
|
||||
pages = Page.objects.not_sibling_of(event)
|
||||
|
||||
# Check that all pages are not children of events_index
|
||||
for page in pages:
|
||||
if page != event:
|
||||
self.assertNotEqual(page.get_parent(), events_index)
|
||||
|
||||
# Check that the event is included
|
||||
self.assertTrue(pages.filter(id=event.id).exists())
|
||||
|
||||
# Test that events index is in pages
|
||||
self.assertTrue(pages.filter(id=events_index.id).exists())
|
||||
|
||||
def test_not_sibling_of_inclusive(self):
|
||||
events_index = Page.objects.get(url_path='/home/events/')
|
||||
event = Page.objects.get(url_path='/home/events/christmas/')
|
||||
pages = Page.objects.not_sibling_of(event, inclusive=True)
|
||||
|
||||
# Check that all pages are not children of events_index
|
||||
for page in pages:
|
||||
self.assertNotEqual(page.get_parent(), events_index)
|
||||
|
||||
# Check that the event is not included
|
||||
self.assertFalse(pages.filter(id=event.id).exists())
|
||||
|
||||
# Test that events index is in pages
|
||||
self.assertTrue(pages.filter(id=events_index.id).exists())
|
||||
|
||||
def test_type(self):
|
||||
pages = Page.objects.type(EventPage)
|
||||
|
||||
# Check that all objects are EventPages
|
||||
for page in pages:
|
||||
self.assertIsInstance(page.specific, EventPage)
|
||||
|
||||
# Check that "someone elses event" is in the results
|
||||
event = Page.objects.get(url_path='/home/events/someone-elses-event/')
|
||||
self.assertTrue(pages.filter(id=event.id).exists())
|
||||
|
||||
def test_not_type(self):
|
||||
pages = Page.objects.not_type(EventPage)
|
||||
|
||||
# Check that no objects are EventPages
|
||||
for page in pages:
|
||||
self.assertNotIsInstance(page.specific, EventPage)
|
||||
|
||||
# Check that the homepage is in the results
|
||||
homepage = Page.objects.get(url_path='/home/')
|
||||
self.assertTrue(pages.filter(id=homepage.id).exists())
|
||||
|
||||
|
||||
class TestMovePage(TestCase):
|
||||
fixtures = ['test.json']
|
||||
|
||||
def test_move_page(self):
|
||||
about_us_page = SimplePage.objects.get(url_path='/home/about-us/')
|
||||
events_index = EventIndex.objects.get(url_path='/home/events/')
|
||||
|
||||
events_index.move(about_us_page, pos='last-child')
|
||||
|
||||
# re-fetch events index to confirm that db fields have been updated
|
||||
events_index = EventIndex.objects.get(id=events_index.id)
|
||||
self.assertEqual(events_index.url_path, '/home/about-us/events/')
|
||||
self.assertEqual(events_index.depth, 4)
|
||||
self.assertEqual(events_index.get_parent().id, about_us_page.id)
|
||||
|
||||
# children of events_index should also have been updated
|
||||
christmas = events_index.get_children().get(slug='christmas')
|
||||
self.assertEqual(christmas.depth, 5)
|
||||
self.assertEqual(christmas.url_path, '/home/about-us/events/christmas/')
|
||||
|
||||
|
||||
class TestIssue7(TestCase):
|
||||
"""
|
||||
This tests for an issue where if a site root page was moved, all the page
|
||||
urls in that site would change to None.
|
||||
|
||||
The issue was caused by the 'wagtail_site_root_paths' cache variable not being
|
||||
cleared when a site root page was moved. Which left all the child pages
|
||||
thinking that they are no longer in the site and return None as their url.
|
||||
|
||||
Fix: d6cce69a397d08d5ee81a8cbc1977ab2c9db2682
|
||||
Discussion: https://github.com/torchbox/wagtail/issues/7
|
||||
"""
|
||||
|
||||
fixtures = ['test.json']
|
||||
|
||||
def test_issue7(self):
|
||||
# Get homepage, root page and site
|
||||
root_page = Page.objects.get(id=1)
|
||||
homepage = Page.objects.get(url_path='/home/')
|
||||
default_site = Site.objects.get(is_default_site=True)
|
||||
|
||||
# Create a new homepage under current homepage
|
||||
new_homepage = SimplePage(title="New Homepage", slug="new-homepage")
|
||||
homepage.add_child(instance=new_homepage)
|
||||
|
||||
# Set new homepage as the site root page
|
||||
default_site.root_page = new_homepage
|
||||
default_site.save()
|
||||
|
||||
# Warm up the cache by getting the url
|
||||
_ = homepage.url
|
||||
|
||||
# Move new homepage to root
|
||||
new_homepage.move(root_page, pos='last-child')
|
||||
|
||||
# Get fresh instance of new_homepage
|
||||
new_homepage = Page.objects.get(id=new_homepage.id)
|
||||
|
||||
# Check url
|
||||
self.assertEqual(new_homepage.url, '/')
|
||||
|
||||
|
||||
class TestIssue157(TestCase):
|
||||
"""
|
||||
This tests for an issue where if a site root pages slug was changed, all the page
|
||||
urls in that site would change to None.
|
||||
|
||||
The issue was caused by the 'wagtail_site_root_paths' cache variable not being
|
||||
cleared when a site root page was changed. Which left all the child pages
|
||||
thinking that they are no longer in the site and return None as their url.
|
||||
|
||||
Fix: d6cce69a397d08d5ee81a8cbc1977ab2c9db2682
|
||||
Discussion: https://github.com/torchbox/wagtail/issues/157
|
||||
"""
|
||||
|
||||
fixtures = ['test.json']
|
||||
|
||||
def test_issue157(self):
|
||||
# Get homepage
|
||||
homepage = Page.objects.get(url_path='/home/')
|
||||
|
||||
# Warm up the cache by getting the url
|
||||
_ = homepage.url
|
||||
|
||||
# Change homepage title and slug
|
||||
homepage.title = "New home"
|
||||
homepage.slug = "new-home"
|
||||
homepage.save()
|
||||
|
||||
# Get fresh instance of homepage
|
||||
homepage = Page.objects.get(id=homepage.id)
|
||||
|
||||
# Check url
|
||||
self.assertEqual(homepage.url, '/')
|
||||
|
||||
|
||||
class TestFixTreeCommand(TestCase):
|
||||
fixtures = ['test.json']
|
||||
|
||||
def run_command(self):
|
||||
management.call_command('fixtree', interactive=False, stdout=StringIO())
|
||||
|
||||
def test_fixes_numchild(self):
|
||||
# Get homepage and save old value
|
||||
homepage = Page.objects.get(url_path='/home/')
|
||||
old_numchild = homepage.numchild
|
||||
|
||||
# Break it
|
||||
homepage.numchild = 12345
|
||||
homepage.save()
|
||||
|
||||
# Check that its broken
|
||||
self.assertEqual(Page.objects.get(url_path='/home/').numchild, 12345)
|
||||
|
||||
# Call command
|
||||
self.run_command()
|
||||
|
||||
# Check if its fixed
|
||||
self.assertEqual(Page.objects.get(url_path='/home/').numchild, old_numchild)
|
||||
|
||||
def test_fixes_depth(self):
|
||||
# Get homepage and save old value
|
||||
homepage = Page.objects.get(url_path='/home/')
|
||||
old_depth = homepage.depth
|
||||
|
||||
# Break it
|
||||
homepage.depth = 12345
|
||||
homepage.save()
|
||||
|
||||
# Check that its broken
|
||||
self.assertEqual(Page.objects.get(url_path='/home/').depth, 12345)
|
||||
|
||||
# Call command
|
||||
self.run_command()
|
||||
|
||||
# Check if its fixed
|
||||
self.assertEqual(Page.objects.get(url_path='/home/').depth, old_depth)
|
||||
|
||||
|
||||
class TestMovePagesCommand(TestCase):
|
||||
fixtures = ['test.json']
|
||||
|
||||
def run_command(self, from_, to):
|
||||
management.call_command('move_pages', str(from_), str(to), interactive=False, stdout=StringIO())
|
||||
|
||||
def test_move_pages(self):
|
||||
# Get pages
|
||||
events_index = Page.objects.get(url_path='/home/events/')
|
||||
about_us = Page.objects.get(url_path='/home/about-us/')
|
||||
page_ids = events_index.get_children().values_list('id', flat=True)
|
||||
|
||||
# Move all events into "about us"
|
||||
self.run_command(events_index.id, about_us.id)
|
||||
|
||||
# Check that all pages moved
|
||||
for page_id in page_ids:
|
||||
self.assertEqual(Page.objects.get(id=page_id).get_parent(), about_us)
|
||||
|
||||
|
||||
class TestReplaceTextCommand(TestCase):
|
||||
fixtures = ['test.json']
|
||||
|
||||
def run_command(self, from_text, to_text):
|
||||
management.call_command('replace_text', from_text, to_text, interactive=False, stdout=StringIO())
|
||||
|
||||
def test_replace_text(self):
|
||||
# Check that the christmas page is definitely about christmas
|
||||
self.assertEqual(Page.objects.get(url_path='/home/events/christmas/').title, "Christmas")
|
||||
|
||||
# Make it about easter
|
||||
self.run_command("Christmas", "Easter")
|
||||
|
||||
# Check that its now about easter
|
||||
self.assertEqual(Page.objects.get(url_path='/home/events/christmas/').title, "Easter")
|
||||
0
wagtail/wagtailcore/tests/__init__.py
Normal file
0
wagtail/wagtailcore/tests/__init__.py
Normal file
89
wagtail/wagtailcore/tests/test_management_commands.py
Normal file
89
wagtail/wagtailcore/tests/test_management_commands.py
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
from StringIO import StringIO
|
||||
|
||||
from django.test import TestCase, Client
|
||||
from django.http import HttpRequest, Http404
|
||||
from django.core import management
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
from wagtail.wagtailcore.models import Page, Site, UserPagePermissionsProxy
|
||||
from wagtail.tests.models import EventPage, EventIndex, SimplePage
|
||||
|
||||
|
||||
class TestFixTreeCommand(TestCase):
|
||||
fixtures = ['test.json']
|
||||
|
||||
def run_command(self):
|
||||
management.call_command('fixtree', interactive=False, stdout=StringIO())
|
||||
|
||||
def test_fixes_numchild(self):
|
||||
# Get homepage and save old value
|
||||
homepage = Page.objects.get(url_path='/home/')
|
||||
old_numchild = homepage.numchild
|
||||
|
||||
# Break it
|
||||
homepage.numchild = 12345
|
||||
homepage.save()
|
||||
|
||||
# Check that its broken
|
||||
self.assertEqual(Page.objects.get(url_path='/home/').numchild, 12345)
|
||||
|
||||
# Call command
|
||||
self.run_command()
|
||||
|
||||
# Check if its fixed
|
||||
self.assertEqual(Page.objects.get(url_path='/home/').numchild, old_numchild)
|
||||
|
||||
def test_fixes_depth(self):
|
||||
# Get homepage and save old value
|
||||
homepage = Page.objects.get(url_path='/home/')
|
||||
old_depth = homepage.depth
|
||||
|
||||
# Break it
|
||||
homepage.depth = 12345
|
||||
homepage.save()
|
||||
|
||||
# Check that its broken
|
||||
self.assertEqual(Page.objects.get(url_path='/home/').depth, 12345)
|
||||
|
||||
# Call command
|
||||
self.run_command()
|
||||
|
||||
# Check if its fixed
|
||||
self.assertEqual(Page.objects.get(url_path='/home/').depth, old_depth)
|
||||
|
||||
|
||||
class TestMovePagesCommand(TestCase):
|
||||
fixtures = ['test.json']
|
||||
|
||||
def run_command(self, from_, to):
|
||||
management.call_command('move_pages', str(from_), str(to), interactive=False, stdout=StringIO())
|
||||
|
||||
def test_move_pages(self):
|
||||
# Get pages
|
||||
events_index = Page.objects.get(url_path='/home/events/')
|
||||
about_us = Page.objects.get(url_path='/home/about-us/')
|
||||
page_ids = events_index.get_children().values_list('id', flat=True)
|
||||
|
||||
# Move all events into "about us"
|
||||
self.run_command(events_index.id, about_us.id)
|
||||
|
||||
# Check that all pages moved
|
||||
for page_id in page_ids:
|
||||
self.assertEqual(Page.objects.get(id=page_id).get_parent(), about_us)
|
||||
|
||||
|
||||
class TestReplaceTextCommand(TestCase):
|
||||
fixtures = ['test.json']
|
||||
|
||||
def run_command(self, from_text, to_text):
|
||||
management.call_command('replace_text', from_text, to_text, interactive=False, stdout=StringIO())
|
||||
|
||||
def test_replace_text(self):
|
||||
# Check that the christmas page is definitely about christmas
|
||||
self.assertEqual(Page.objects.get(url_path='/home/events/christmas/').title, "Christmas")
|
||||
|
||||
# Make it about easter
|
||||
self.run_command("Christmas", "Easter")
|
||||
|
||||
# Check that its now about easter
|
||||
self.assertEqual(Page.objects.get(url_path='/home/events/christmas/').title, "Easter")
|
||||
226
wagtail/wagtailcore/tests/test_page_model.py
Normal file
226
wagtail/wagtailcore/tests/test_page_model.py
Normal file
|
|
@ -0,0 +1,226 @@
|
|||
from StringIO import StringIO
|
||||
|
||||
from django.test import TestCase, Client
|
||||
from django.http import HttpRequest, Http404
|
||||
from django.core import management
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
from wagtail.wagtailcore.models import Page, Site, UserPagePermissionsProxy
|
||||
from wagtail.tests.models import EventPage, EventIndex, SimplePage
|
||||
|
||||
|
||||
class TestRouting(TestCase):
|
||||
fixtures = ['test.json']
|
||||
|
||||
def test_find_site_for_request(self):
|
||||
default_site = Site.objects.get(is_default_site=True)
|
||||
events_page = Page.objects.get(url_path='/home/events/')
|
||||
events_site = Site.objects.create(hostname='events.example.com', root_page=events_page)
|
||||
|
||||
# requests without a Host: header should be directed to the default site
|
||||
request = HttpRequest()
|
||||
request.path = '/'
|
||||
self.assertEqual(Site.find_for_request(request), default_site)
|
||||
|
||||
# requests with a known Host: header should be directed to the specific site
|
||||
request = HttpRequest()
|
||||
request.path = '/'
|
||||
request.META['HTTP_HOST'] = 'events.example.com'
|
||||
self.assertEqual(Site.find_for_request(request), events_site)
|
||||
|
||||
# requests with an unrecognised Host: header should be directed to the default site
|
||||
request = HttpRequest()
|
||||
request.path = '/'
|
||||
request.META['HTTP_HOST'] = 'unknown.example.com'
|
||||
self.assertEqual(Site.find_for_request(request), default_site)
|
||||
|
||||
def test_urls(self):
|
||||
default_site = Site.objects.get(is_default_site=True)
|
||||
homepage = Page.objects.get(url_path='/home/')
|
||||
christmas_page = Page.objects.get(url_path='/home/events/christmas/')
|
||||
|
||||
# Basic installation only has one site configured, so page.url will return local URLs
|
||||
self.assertEqual(homepage.full_url, 'http://localhost/')
|
||||
self.assertEqual(homepage.url, '/')
|
||||
self.assertEqual(homepage.relative_url(default_site), '/')
|
||||
|
||||
self.assertEqual(christmas_page.full_url, 'http://localhost/events/christmas/')
|
||||
self.assertEqual(christmas_page.url, '/events/christmas/')
|
||||
self.assertEqual(christmas_page.relative_url(default_site), '/events/christmas/')
|
||||
|
||||
def test_urls_with_multiple_sites(self):
|
||||
events_page = Page.objects.get(url_path='/home/events/')
|
||||
events_site = Site.objects.create(hostname='events.example.com', root_page=events_page)
|
||||
|
||||
default_site = Site.objects.get(is_default_site=True)
|
||||
homepage = Page.objects.get(url_path='/home/')
|
||||
christmas_page = Page.objects.get(url_path='/home/events/christmas/')
|
||||
|
||||
# with multiple sites, page.url will return full URLs to ensure that
|
||||
# they work across sites
|
||||
self.assertEqual(homepage.full_url, 'http://localhost/')
|
||||
self.assertEqual(homepage.url, 'http://localhost/')
|
||||
self.assertEqual(homepage.relative_url(default_site), '/')
|
||||
self.assertEqual(homepage.relative_url(events_site), 'http://localhost/')
|
||||
|
||||
self.assertEqual(christmas_page.full_url, 'http://events.example.com/christmas/')
|
||||
self.assertEqual(christmas_page.url, 'http://events.example.com/christmas/')
|
||||
self.assertEqual(christmas_page.relative_url(default_site), 'http://events.example.com/christmas/')
|
||||
self.assertEqual(christmas_page.relative_url(events_site), '/christmas/')
|
||||
|
||||
def test_request_routing(self):
|
||||
homepage = Page.objects.get(url_path='/home/')
|
||||
christmas_page = EventPage.objects.get(url_path='/home/events/christmas/')
|
||||
|
||||
request = HttpRequest()
|
||||
request.path = '/events/christmas/'
|
||||
response = homepage.route(request, ['events', 'christmas'])
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(response.context_data['self'], christmas_page)
|
||||
used_template = response.resolve_template(response.template_name)
|
||||
self.assertEqual(used_template.name, 'tests/event_page.html')
|
||||
|
||||
def test_route_to_unknown_page_returns_404(self):
|
||||
homepage = Page.objects.get(url_path='/home/')
|
||||
|
||||
request = HttpRequest()
|
||||
request.path = '/events/quinquagesima/'
|
||||
with self.assertRaises(Http404):
|
||||
homepage.route(request, ['events', 'quinquagesima'])
|
||||
|
||||
def test_route_to_unpublished_page_returns_404(self):
|
||||
homepage = Page.objects.get(url_path='/home/')
|
||||
|
||||
request = HttpRequest()
|
||||
request.path = '/events/tentative-unpublished-event/'
|
||||
with self.assertRaises(Http404):
|
||||
homepage.route(request, ['events', 'tentative-unpublished-event'])
|
||||
|
||||
|
||||
class TestServeView(TestCase):
|
||||
fixtures = ['test.json']
|
||||
|
||||
def setUp(self):
|
||||
# Explicitly clear the cache of site root paths. Normally this would be kept
|
||||
# in sync by the Site.save logic, but this is bypassed when the database is
|
||||
# rolled back between tests using transactions.
|
||||
from django.core.cache import cache
|
||||
cache.delete('wagtail_site_root_paths')
|
||||
|
||||
def test_serve(self):
|
||||
response = self.client.get('/events/christmas/')
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(response.templates[0].name, 'tests/event_page.html')
|
||||
christmas_page = EventPage.objects.get(url_path='/home/events/christmas/')
|
||||
self.assertEqual(response.context['self'], christmas_page)
|
||||
|
||||
self.assertContains(response, '<h1>Christmas</h1>')
|
||||
self.assertContains(response, '<h2>Event</h2>')
|
||||
|
||||
def test_serve_unknown_page_returns_404(self):
|
||||
response = self.client.get('/events/quinquagesima/')
|
||||
self.assertEqual(response.status_code, 404)
|
||||
|
||||
def test_serve_unpublished_page_returns_404(self):
|
||||
response = self.client.get('/events/tentative-unpublished-event/')
|
||||
self.assertEqual(response.status_code, 404)
|
||||
|
||||
def test_serve_with_multiple_sites(self):
|
||||
events_page = Page.objects.get(url_path='/home/events/')
|
||||
Site.objects.create(hostname='events.example.com', root_page=events_page)
|
||||
|
||||
response = self.client.get('/christmas/', HTTP_HOST='events.example.com')
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(response.templates[0].name, 'tests/event_page.html')
|
||||
christmas_page = EventPage.objects.get(url_path='/home/events/christmas/')
|
||||
self.assertEqual(response.context['self'], christmas_page)
|
||||
|
||||
self.assertContains(response, '<h1>Christmas</h1>')
|
||||
self.assertContains(response, '<h2>Event</h2>')
|
||||
|
||||
# same request to the default host should return a 404
|
||||
c = Client()
|
||||
response = c.get('/christmas/', HTTP_HOST='localhost')
|
||||
self.assertEqual(response.status_code, 404)
|
||||
|
||||
def test_serve_with_custom_context(self):
|
||||
response = self.client.get('/events/')
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
# should render the whole page
|
||||
self.assertContains(response, '<h1>Events</h1>')
|
||||
|
||||
# response should contain data from the custom 'events' context variable
|
||||
self.assertContains(response, '<a href="/events/christmas/">Christmas</a>')
|
||||
|
||||
def test_ajax_response(self):
|
||||
response = self.client.get('/events/', HTTP_X_REQUESTED_WITH='XMLHttpRequest')
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
# should only render the content of includes/event_listing.html, not the whole page
|
||||
self.assertNotContains(response, '<h1>Events</h1>')
|
||||
self.assertContains(response, '<a href="/events/christmas/">Christmas</a>')
|
||||
|
||||
|
||||
class TestStaticSitePaths(TestCase):
|
||||
def setUp(self):
|
||||
self.root_page = Page.objects.get(id=1)
|
||||
|
||||
# For simple tests
|
||||
self.home_page = self.root_page.add_child(instance=SimplePage(title="Homepage", slug="home"))
|
||||
self.about_page = self.home_page.add_child(instance=SimplePage(title="About us", slug="about"))
|
||||
self.contact_page = self.home_page.add_child(instance=SimplePage(title="Contact", slug="contact"))
|
||||
|
||||
# For custom tests
|
||||
self.event_index = self.root_page.add_child(instance=EventIndex(title="Events", slug="events"))
|
||||
for i in range(20):
|
||||
self.event_index.add_child(instance=EventPage(title="Event " + str(i), slug="event" + str(i)))
|
||||
|
||||
def test_local_static_site_paths(self):
|
||||
paths = list(self.about_page.get_static_site_paths())
|
||||
|
||||
self.assertEqual(paths, ['/'])
|
||||
|
||||
def test_child_static_site_paths(self):
|
||||
paths = list(self.home_page.get_static_site_paths())
|
||||
|
||||
self.assertEqual(paths, ['/', '/about/', '/contact/'])
|
||||
|
||||
def test_custom_static_site_paths(self):
|
||||
paths = list(self.event_index.get_static_site_paths())
|
||||
|
||||
# Event index path
|
||||
expected_paths = ['/']
|
||||
|
||||
# One path for each page of results
|
||||
expected_paths.extend(['/' + str(i + 1) + '/' for i in range(5)])
|
||||
|
||||
# One path for each event page
|
||||
expected_paths.extend(['/event' + str(i) + '/' for i in range(20)])
|
||||
|
||||
paths.sort()
|
||||
expected_paths.sort()
|
||||
self.assertEqual(paths, expected_paths)
|
||||
|
||||
|
||||
class TestMovePage(TestCase):
|
||||
fixtures = ['test.json']
|
||||
|
||||
def test_move_page(self):
|
||||
about_us_page = SimplePage.objects.get(url_path='/home/about-us/')
|
||||
events_index = EventIndex.objects.get(url_path='/home/events/')
|
||||
|
||||
events_index.move(about_us_page, pos='last-child')
|
||||
|
||||
# re-fetch events index to confirm that db fields have been updated
|
||||
events_index = EventIndex.objects.get(id=events_index.id)
|
||||
self.assertEqual(events_index.url_path, '/home/about-us/events/')
|
||||
self.assertEqual(events_index.depth, 4)
|
||||
self.assertEqual(events_index.get_parent().id, about_us_page.id)
|
||||
|
||||
# children of events_index should also have been updated
|
||||
christmas = events_index.get_children().get(slug='christmas')
|
||||
self.assertEqual(christmas.depth, 5)
|
||||
self.assertEqual(christmas.url_path, '/home/about-us/events/christmas/')
|
||||
226
wagtail/wagtailcore/tests/test_page_permissions.py
Normal file
226
wagtail/wagtailcore/tests/test_page_permissions.py
Normal file
|
|
@ -0,0 +1,226 @@
|
|||
from StringIO import StringIO
|
||||
|
||||
from django.test import TestCase, Client
|
||||
from django.http import HttpRequest, Http404
|
||||
from django.core import management
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
from wagtail.wagtailcore.models import Page, Site, UserPagePermissionsProxy
|
||||
from wagtail.tests.models import EventPage, EventIndex, SimplePage
|
||||
|
||||
|
||||
class TestPagePermission(TestCase):
|
||||
fixtures = ['test.json']
|
||||
|
||||
def test_nonpublisher_page_permissions(self):
|
||||
event_editor = User.objects.get(username='eventeditor')
|
||||
homepage = Page.objects.get(url_path='/home/')
|
||||
christmas_page = EventPage.objects.get(url_path='/home/events/christmas/')
|
||||
unpublished_event_page = EventPage.objects.get(url_path='/home/events/tentative-unpublished-event/')
|
||||
someone_elses_event_page = EventPage.objects.get(url_path='/home/events/someone-elses-event/')
|
||||
|
||||
homepage_perms = homepage.permissions_for_user(event_editor)
|
||||
christmas_page_perms = christmas_page.permissions_for_user(event_editor)
|
||||
unpub_perms = unpublished_event_page.permissions_for_user(event_editor)
|
||||
someone_elses_event_perms = someone_elses_event_page.permissions_for_user(event_editor)
|
||||
|
||||
self.assertFalse(homepage_perms.can_add_subpage())
|
||||
self.assertTrue(christmas_page_perms.can_add_subpage())
|
||||
self.assertTrue(unpub_perms.can_add_subpage())
|
||||
self.assertTrue(someone_elses_event_perms.can_add_subpage())
|
||||
|
||||
self.assertFalse(homepage_perms.can_edit())
|
||||
self.assertTrue(christmas_page_perms.can_edit())
|
||||
self.assertTrue(unpub_perms.can_edit())
|
||||
self.assertFalse(someone_elses_event_perms.can_edit()) # basic 'add' permission doesn't allow editing pages owned by someone else
|
||||
|
||||
self.assertFalse(homepage_perms.can_delete())
|
||||
self.assertFalse(christmas_page_perms.can_delete()) # cannot delete because it is published
|
||||
self.assertTrue(unpub_perms.can_delete())
|
||||
self.assertFalse(someone_elses_event_perms.can_delete())
|
||||
|
||||
self.assertFalse(homepage_perms.can_publish())
|
||||
self.assertFalse(christmas_page_perms.can_publish())
|
||||
self.assertFalse(unpub_perms.can_publish())
|
||||
|
||||
self.assertFalse(homepage_perms.can_unpublish())
|
||||
self.assertFalse(christmas_page_perms.can_unpublish())
|
||||
self.assertFalse(unpub_perms.can_unpublish())
|
||||
|
||||
self.assertFalse(homepage_perms.can_publish_subpage())
|
||||
self.assertFalse(christmas_page_perms.can_publish_subpage())
|
||||
self.assertFalse(unpub_perms.can_publish_subpage())
|
||||
|
||||
self.assertFalse(homepage_perms.can_reorder_children())
|
||||
self.assertFalse(christmas_page_perms.can_reorder_children())
|
||||
self.assertFalse(unpub_perms.can_reorder_children())
|
||||
|
||||
self.assertFalse(homepage_perms.can_move())
|
||||
self.assertFalse(christmas_page_perms.can_move()) # cannot move because this would involve unpublishing from its current location
|
||||
self.assertTrue(unpub_perms.can_move())
|
||||
self.assertFalse(someone_elses_event_perms.can_move())
|
||||
|
||||
self.assertFalse(christmas_page_perms.can_move_to(unpublished_event_page)) # cannot move because this would involve unpublishing from its current location
|
||||
self.assertTrue(unpub_perms.can_move_to(christmas_page))
|
||||
self.assertFalse(unpub_perms.can_move_to(homepage)) # no permission to create pages at destination
|
||||
self.assertFalse(unpub_perms.can_move_to(unpublished_event_page)) # cannot make page a child of itself
|
||||
|
||||
|
||||
def test_publisher_page_permissions(self):
|
||||
event_moderator = User.objects.get(username='eventmoderator')
|
||||
homepage = Page.objects.get(url_path='/home/')
|
||||
christmas_page = EventPage.objects.get(url_path='/home/events/christmas/')
|
||||
unpublished_event_page = EventPage.objects.get(url_path='/home/events/tentative-unpublished-event/')
|
||||
|
||||
homepage_perms = homepage.permissions_for_user(event_moderator)
|
||||
christmas_page_perms = christmas_page.permissions_for_user(event_moderator)
|
||||
unpub_perms = unpublished_event_page.permissions_for_user(event_moderator)
|
||||
|
||||
self.assertFalse(homepage_perms.can_add_subpage())
|
||||
self.assertTrue(christmas_page_perms.can_add_subpage())
|
||||
self.assertTrue(unpub_perms.can_add_subpage())
|
||||
|
||||
self.assertFalse(homepage_perms.can_edit())
|
||||
self.assertTrue(christmas_page_perms.can_edit())
|
||||
self.assertTrue(unpub_perms.can_edit())
|
||||
|
||||
self.assertFalse(homepage_perms.can_delete())
|
||||
self.assertTrue(christmas_page_perms.can_delete()) # cannot delete because it is published
|
||||
self.assertTrue(unpub_perms.can_delete())
|
||||
|
||||
self.assertFalse(homepage_perms.can_publish())
|
||||
self.assertTrue(christmas_page_perms.can_publish())
|
||||
self.assertTrue(unpub_perms.can_publish())
|
||||
|
||||
self.assertFalse(homepage_perms.can_unpublish())
|
||||
self.assertTrue(christmas_page_perms.can_unpublish())
|
||||
self.assertFalse(unpub_perms.can_unpublish()) # cannot unpublish a page that isn't published
|
||||
|
||||
self.assertFalse(homepage_perms.can_publish_subpage())
|
||||
self.assertTrue(christmas_page_perms.can_publish_subpage())
|
||||
self.assertTrue(unpub_perms.can_publish_subpage())
|
||||
|
||||
self.assertFalse(homepage_perms.can_reorder_children())
|
||||
self.assertTrue(christmas_page_perms.can_reorder_children())
|
||||
self.assertTrue(unpub_perms.can_reorder_children())
|
||||
|
||||
self.assertFalse(homepage_perms.can_move())
|
||||
self.assertTrue(christmas_page_perms.can_move())
|
||||
self.assertTrue(unpub_perms.can_move())
|
||||
|
||||
self.assertTrue(christmas_page_perms.can_move_to(unpublished_event_page))
|
||||
self.assertTrue(unpub_perms.can_move_to(christmas_page))
|
||||
self.assertFalse(unpub_perms.can_move_to(homepage)) # no permission to create pages at destination
|
||||
self.assertFalse(unpub_perms.can_move_to(unpublished_event_page)) # cannot make page a child of itself
|
||||
|
||||
def test_inactive_user_has_no_permissions(self):
|
||||
user = User.objects.get(username='inactiveuser')
|
||||
christmas_page = EventPage.objects.get(url_path='/home/events/christmas/')
|
||||
unpublished_event_page = EventPage.objects.get(url_path='/home/events/tentative-unpublished-event/')
|
||||
|
||||
christmas_page_perms = christmas_page.permissions_for_user(user)
|
||||
unpub_perms = unpublished_event_page.permissions_for_user(user)
|
||||
|
||||
self.assertFalse(unpub_perms.can_add_subpage())
|
||||
self.assertFalse(unpub_perms.can_edit())
|
||||
self.assertFalse(unpub_perms.can_delete())
|
||||
self.assertFalse(unpub_perms.can_publish())
|
||||
self.assertFalse(christmas_page_perms.can_unpublish())
|
||||
self.assertFalse(unpub_perms.can_publish_subpage())
|
||||
self.assertFalse(unpub_perms.can_reorder_children())
|
||||
self.assertFalse(unpub_perms.can_move())
|
||||
self.assertFalse(unpub_perms.can_move_to(christmas_page))
|
||||
|
||||
def test_superuser_has_full_permissions(self):
|
||||
user = User.objects.get(username='superuser')
|
||||
homepage = Page.objects.get(url_path='/home/')
|
||||
root = Page.objects.get(url_path='/')
|
||||
unpublished_event_page = EventPage.objects.get(url_path='/home/events/tentative-unpublished-event/')
|
||||
|
||||
homepage_perms = homepage.permissions_for_user(user)
|
||||
root_perms = root.permissions_for_user(user)
|
||||
unpub_perms = unpublished_event_page.permissions_for_user(user)
|
||||
|
||||
self.assertTrue(homepage_perms.can_add_subpage())
|
||||
self.assertTrue(root_perms.can_add_subpage())
|
||||
|
||||
self.assertTrue(homepage_perms.can_edit())
|
||||
self.assertFalse(root_perms.can_edit()) # root is not a real editable page, even to superusers
|
||||
|
||||
self.assertTrue(homepage_perms.can_delete())
|
||||
self.assertFalse(root_perms.can_delete())
|
||||
|
||||
self.assertTrue(homepage_perms.can_publish())
|
||||
self.assertFalse(root_perms.can_publish())
|
||||
|
||||
self.assertTrue(homepage_perms.can_unpublish())
|
||||
self.assertFalse(root_perms.can_unpublish())
|
||||
self.assertFalse(unpub_perms.can_unpublish())
|
||||
|
||||
self.assertTrue(homepage_perms.can_publish_subpage())
|
||||
self.assertTrue(root_perms.can_publish_subpage())
|
||||
|
||||
self.assertTrue(homepage_perms.can_reorder_children())
|
||||
self.assertTrue(root_perms.can_reorder_children())
|
||||
|
||||
self.assertTrue(homepage_perms.can_move())
|
||||
self.assertFalse(root_perms.can_move())
|
||||
|
||||
self.assertTrue(homepage_perms.can_move_to(root))
|
||||
self.assertFalse(homepage_perms.can_move_to(unpublished_event_page))
|
||||
|
||||
def test_editable_pages_for_user_with_add_permission(self):
|
||||
event_editor = User.objects.get(username='eventeditor')
|
||||
homepage = Page.objects.get(url_path='/home/')
|
||||
christmas_page = EventPage.objects.get(url_path='/home/events/christmas/')
|
||||
unpublished_event_page = EventPage.objects.get(url_path='/home/events/tentative-unpublished-event/')
|
||||
someone_elses_event_page = EventPage.objects.get(url_path='/home/events/someone-elses-event/')
|
||||
|
||||
editable_pages = UserPagePermissionsProxy(event_editor).editable_pages()
|
||||
|
||||
self.assertFalse(editable_pages.filter(id=homepage.id).exists())
|
||||
self.assertTrue(editable_pages.filter(id=christmas_page.id).exists())
|
||||
self.assertTrue(editable_pages.filter(id=unpublished_event_page.id).exists())
|
||||
self.assertFalse(editable_pages.filter(id=someone_elses_event_page.id).exists())
|
||||
|
||||
def test_editable_pages_for_user_with_edit_permission(self):
|
||||
event_moderator = User.objects.get(username='eventmoderator')
|
||||
homepage = Page.objects.get(url_path='/home/')
|
||||
christmas_page = EventPage.objects.get(url_path='/home/events/christmas/')
|
||||
unpublished_event_page = EventPage.objects.get(url_path='/home/events/tentative-unpublished-event/')
|
||||
someone_elses_event_page = EventPage.objects.get(url_path='/home/events/someone-elses-event/')
|
||||
|
||||
editable_pages = UserPagePermissionsProxy(event_moderator).editable_pages()
|
||||
|
||||
self.assertFalse(editable_pages.filter(id=homepage.id).exists())
|
||||
self.assertTrue(editable_pages.filter(id=christmas_page.id).exists())
|
||||
self.assertTrue(editable_pages.filter(id=unpublished_event_page.id).exists())
|
||||
self.assertTrue(editable_pages.filter(id=someone_elses_event_page.id).exists())
|
||||
|
||||
def test_editable_pages_for_inactive_user(self):
|
||||
user = User.objects.get(username='inactiveuser')
|
||||
homepage = Page.objects.get(url_path='/home/')
|
||||
christmas_page = EventPage.objects.get(url_path='/home/events/christmas/')
|
||||
unpublished_event_page = EventPage.objects.get(url_path='/home/events/tentative-unpublished-event/')
|
||||
someone_elses_event_page = EventPage.objects.get(url_path='/home/events/someone-elses-event/')
|
||||
|
||||
editable_pages = UserPagePermissionsProxy(user).editable_pages()
|
||||
|
||||
self.assertFalse(editable_pages.filter(id=homepage.id).exists())
|
||||
self.assertFalse(editable_pages.filter(id=christmas_page.id).exists())
|
||||
self.assertFalse(editable_pages.filter(id=unpublished_event_page.id).exists())
|
||||
self.assertFalse(editable_pages.filter(id=someone_elses_event_page.id).exists())
|
||||
|
||||
def test_editable_pages_for_superuser(self):
|
||||
user = User.objects.get(username='superuser')
|
||||
homepage = Page.objects.get(url_path='/home/')
|
||||
christmas_page = EventPage.objects.get(url_path='/home/events/christmas/')
|
||||
unpublished_event_page = EventPage.objects.get(url_path='/home/events/tentative-unpublished-event/')
|
||||
someone_elses_event_page = EventPage.objects.get(url_path='/home/events/someone-elses-event/')
|
||||
|
||||
editable_pages = UserPagePermissionsProxy(user).editable_pages()
|
||||
|
||||
self.assertTrue(editable_pages.filter(id=homepage.id).exists())
|
||||
self.assertTrue(editable_pages.filter(id=christmas_page.id).exists())
|
||||
self.assertTrue(editable_pages.filter(id=unpublished_event_page.id).exists())
|
||||
self.assertTrue(editable_pages.filter(id=someone_elses_event_page.id).exists())
|
||||
256
wagtail/wagtailcore/tests/test_page_queryset.py
Normal file
256
wagtail/wagtailcore/tests/test_page_queryset.py
Normal file
|
|
@ -0,0 +1,256 @@
|
|||
from StringIO import StringIO
|
||||
|
||||
from django.test import TestCase, Client
|
||||
from django.http import HttpRequest, Http404
|
||||
from django.core import management
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
from wagtail.wagtailcore.models import Page, Site, UserPagePermissionsProxy
|
||||
from wagtail.tests.models import EventPage, EventIndex, SimplePage
|
||||
|
||||
|
||||
class TestPageQuerySet(TestCase):
|
||||
fixtures = ['test.json']
|
||||
|
||||
def test_live(self):
|
||||
pages = Page.objects.live()
|
||||
|
||||
# All pages must be live
|
||||
for page in pages:
|
||||
self.assertTrue(page.live)
|
||||
|
||||
# Check that the homepage is in the results
|
||||
homepage = Page.objects.get(url_path='/home/')
|
||||
self.assertTrue(pages.filter(id=homepage.id).exists())
|
||||
|
||||
def test_not_live(self):
|
||||
pages = Page.objects.not_live()
|
||||
|
||||
# All pages must not be live
|
||||
for page in pages:
|
||||
self.assertFalse(page.live)
|
||||
|
||||
# Check that "someone elses event" is in the results
|
||||
event = Page.objects.get(url_path='/home/events/someone-elses-event/')
|
||||
self.assertTrue(pages.filter(id=event.id).exists())
|
||||
|
||||
def test_page(self):
|
||||
homepage = Page.objects.get(url_path='/home/')
|
||||
pages = Page.objects.page(homepage)
|
||||
|
||||
# Should only select the homepage
|
||||
self.assertEqual(pages.count(), 1)
|
||||
self.assertEqual(pages.first(), homepage)
|
||||
|
||||
def test_not_page(self):
|
||||
homepage = Page.objects.get(url_path='/home/')
|
||||
pages = Page.objects.not_page(homepage)
|
||||
|
||||
# Should select everything except for the homepage
|
||||
self.assertEqual(pages.count(), Page.objects.all().count() - 1)
|
||||
for page in pages:
|
||||
self.assertNotEqual(page, homepage)
|
||||
|
||||
def test_descendant_of(self):
|
||||
events_index = Page.objects.get(url_path='/home/events/')
|
||||
pages = Page.objects.descendant_of(events_index)
|
||||
|
||||
# Check that all pages descend from events index
|
||||
for page in pages:
|
||||
self.assertTrue(page.get_ancestors().filter(id=events_index.id).exists())
|
||||
|
||||
def test_descendant_of_inclusive(self):
|
||||
events_index = Page.objects.get(url_path='/home/events/')
|
||||
pages = Page.objects.descendant_of(events_index, inclusive=True)
|
||||
|
||||
# Check that all pages descend from events index, includes event index
|
||||
for page in pages:
|
||||
self.assertTrue(page == events_index or page.get_ancestors().filter(id=events_index.id).exists())
|
||||
|
||||
# Check that event index was included
|
||||
self.assertTrue(pages.filter(id=events_index.id).exists())
|
||||
|
||||
def test_not_descendant_of(self):
|
||||
homepage = Page.objects.get(url_path='/home/')
|
||||
events_index = Page.objects.get(url_path='/home/events/')
|
||||
pages = Page.objects.not_descendant_of(events_index)
|
||||
|
||||
# Check that no pages descend from events_index
|
||||
for page in pages:
|
||||
self.assertFalse(page.get_ancestors().filter(id=events_index.id).exists())
|
||||
|
||||
# As this is not inclusive, events index should be in the results
|
||||
self.assertTrue(pages.filter(id=events_index.id).exists())
|
||||
|
||||
def test_not_descendant_of_inclusive(self):
|
||||
homepage = Page.objects.get(url_path='/home/')
|
||||
events_index = Page.objects.get(url_path='/home/events/')
|
||||
pages = Page.objects.not_descendant_of(events_index, inclusive=True)
|
||||
|
||||
# Check that all pages descend from homepage but not events index
|
||||
for page in pages:
|
||||
self.assertFalse(page.get_ancestors().filter(id=events_index.id).exists())
|
||||
|
||||
# As this is inclusive, events index should not be in the results
|
||||
self.assertFalse(pages.filter(id=events_index.id).exists())
|
||||
|
||||
def test_child_of(self):
|
||||
homepage = Page.objects.get(url_path='/home/')
|
||||
pages = Page.objects.child_of(homepage)
|
||||
|
||||
# Check that all pages are children of homepage
|
||||
for page in pages:
|
||||
self.assertEqual(page.get_parent(), homepage)
|
||||
|
||||
def test_not_child_of(self):
|
||||
events_index = Page.objects.get(url_path='/home/events/')
|
||||
pages = Page.objects.not_child_of(events_index)
|
||||
|
||||
# Check that all pages are not children of events_index
|
||||
for page in pages:
|
||||
self.assertNotEqual(page.get_parent(), events_index)
|
||||
|
||||
def test_ancestor_of(self):
|
||||
root_page = Page.objects.get(id=1)
|
||||
homepage = Page.objects.get(url_path='/home/')
|
||||
events_index = Page.objects.get(url_path='/home/events/')
|
||||
pages = Page.objects.ancestor_of(events_index)
|
||||
|
||||
self.assertEqual(pages.count(), 2)
|
||||
self.assertEqual(pages[0], root_page)
|
||||
self.assertEqual(pages[1], homepage)
|
||||
|
||||
def test_ancestor_of_inclusive(self):
|
||||
root_page = Page.objects.get(id=1)
|
||||
homepage = Page.objects.get(url_path='/home/')
|
||||
events_index = Page.objects.get(url_path='/home/events/')
|
||||
pages = Page.objects.ancestor_of(events_index, inclusive=True)
|
||||
|
||||
self.assertEqual(pages.count(), 3)
|
||||
self.assertEqual(pages[0], root_page)
|
||||
self.assertEqual(pages[1], homepage)
|
||||
self.assertEqual(pages[2], events_index)
|
||||
|
||||
def test_not_ancestor_of(self):
|
||||
root_page = Page.objects.get(id=1)
|
||||
homepage = Page.objects.get(url_path='/home/')
|
||||
events_index = Page.objects.get(url_path='/home/events/')
|
||||
pages = Page.objects.not_ancestor_of(events_index)
|
||||
|
||||
# Test that none of the ancestors are in pages
|
||||
for page in pages:
|
||||
self.assertNotEqual(page, root_page)
|
||||
self.assertNotEqual(page, homepage)
|
||||
|
||||
# Test that events index is in pages
|
||||
self.assertTrue(pages.filter(id=events_index.id).exists())
|
||||
|
||||
def test_not_ancestor_of_inclusive(self):
|
||||
root_page = Page.objects.get(id=1)
|
||||
homepage = Page.objects.get(url_path='/home/')
|
||||
events_index = Page.objects.get(url_path='/home/events/')
|
||||
pages = Page.objects.not_ancestor_of(events_index, inclusive=True)
|
||||
|
||||
# Test that none of the ancestors or the events_index are in pages
|
||||
for page in pages:
|
||||
self.assertNotEqual(page, root_page)
|
||||
self.assertNotEqual(page, homepage)
|
||||
self.assertNotEqual(page, events_index)
|
||||
|
||||
def test_parent_of(self):
|
||||
homepage = Page.objects.get(url_path='/home/')
|
||||
events_index = Page.objects.get(url_path='/home/events/')
|
||||
pages = Page.objects.parent_of(events_index)
|
||||
|
||||
# Pages must only contain homepage
|
||||
self.assertEqual(pages.count(), 1)
|
||||
self.assertEqual(pages[0], homepage)
|
||||
|
||||
def test_not_parent_of(self):
|
||||
homepage = Page.objects.get(url_path='/home/')
|
||||
events_index = Page.objects.get(url_path='/home/events/')
|
||||
pages = Page.objects.not_parent_of(events_index)
|
||||
|
||||
# Pages must not contain homepage
|
||||
for page in pages:
|
||||
self.assertNotEqual(page, homepage)
|
||||
|
||||
# Test that events index is in pages
|
||||
self.assertTrue(pages.filter(id=events_index.id).exists())
|
||||
|
||||
def test_sibling_of(self):
|
||||
events_index = Page.objects.get(url_path='/home/events/')
|
||||
event = Page.objects.get(url_path='/home/events/christmas/')
|
||||
pages = Page.objects.sibling_of(event)
|
||||
|
||||
# Check that all pages are children of events_index
|
||||
for page in pages:
|
||||
self.assertEqual(page.get_parent(), events_index)
|
||||
|
||||
# Check that the event is not included
|
||||
self.assertFalse(pages.filter(id=event.id).exists())
|
||||
|
||||
def test_sibling_of_inclusive(self):
|
||||
events_index = Page.objects.get(url_path='/home/events/')
|
||||
event = Page.objects.get(url_path='/home/events/christmas/')
|
||||
pages = Page.objects.sibling_of(event, inclusive=True)
|
||||
|
||||
# Check that all pages are children of events_index
|
||||
for page in pages:
|
||||
self.assertEqual(page.get_parent(), events_index)
|
||||
|
||||
# Check that the event is included
|
||||
self.assertTrue(pages.filter(id=event.id).exists())
|
||||
|
||||
def test_not_sibling_of(self):
|
||||
events_index = Page.objects.get(url_path='/home/events/')
|
||||
event = Page.objects.get(url_path='/home/events/christmas/')
|
||||
pages = Page.objects.not_sibling_of(event)
|
||||
|
||||
# Check that all pages are not children of events_index
|
||||
for page in pages:
|
||||
if page != event:
|
||||
self.assertNotEqual(page.get_parent(), events_index)
|
||||
|
||||
# Check that the event is included
|
||||
self.assertTrue(pages.filter(id=event.id).exists())
|
||||
|
||||
# Test that events index is in pages
|
||||
self.assertTrue(pages.filter(id=events_index.id).exists())
|
||||
|
||||
def test_not_sibling_of_inclusive(self):
|
||||
events_index = Page.objects.get(url_path='/home/events/')
|
||||
event = Page.objects.get(url_path='/home/events/christmas/')
|
||||
pages = Page.objects.not_sibling_of(event, inclusive=True)
|
||||
|
||||
# Check that all pages are not children of events_index
|
||||
for page in pages:
|
||||
self.assertNotEqual(page.get_parent(), events_index)
|
||||
|
||||
# Check that the event is not included
|
||||
self.assertFalse(pages.filter(id=event.id).exists())
|
||||
|
||||
# Test that events index is in pages
|
||||
self.assertTrue(pages.filter(id=events_index.id).exists())
|
||||
|
||||
def test_type(self):
|
||||
pages = Page.objects.type(EventPage)
|
||||
|
||||
# Check that all objects are EventPages
|
||||
for page in pages:
|
||||
self.assertIsInstance(page.specific, EventPage)
|
||||
|
||||
# Check that "someone elses event" is in the results
|
||||
event = Page.objects.get(url_path='/home/events/someone-elses-event/')
|
||||
self.assertTrue(pages.filter(id=event.id).exists())
|
||||
|
||||
def test_not_type(self):
|
||||
pages = Page.objects.not_type(EventPage)
|
||||
|
||||
# Check that no objects are EventPages
|
||||
for page in pages:
|
||||
self.assertNotIsInstance(page.specific, EventPage)
|
||||
|
||||
# Check that the homepage is in the results
|
||||
homepage = Page.objects.get(url_path='/home/')
|
||||
self.assertTrue(pages.filter(id=homepage.id).exists())
|
||||
99
wagtail/wagtailcore/tests/tests.py
Normal file
99
wagtail/wagtailcore/tests/tests.py
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
from StringIO import StringIO
|
||||
|
||||
from django.test import TestCase, Client
|
||||
from django.http import HttpRequest, Http404
|
||||
from django.core import management
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
from wagtail.wagtailcore.models import Page, Site, UserPagePermissionsProxy
|
||||
from wagtail.tests.models import EventPage, EventIndex, SimplePage
|
||||
|
||||
|
||||
class TestPageUrlTags(TestCase):
|
||||
fixtures = ['test.json']
|
||||
|
||||
def test_pageurl_tag(self):
|
||||
response = self.client.get('/events/')
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertContains(response, '<a href="/events/christmas/">Christmas</a>')
|
||||
|
||||
def test_slugurl_tag(self):
|
||||
response = self.client.get('/events/christmas/')
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertContains(response, '<a href="/events/">Back to events index</a>')
|
||||
|
||||
|
||||
class TestIssue7(TestCase):
|
||||
"""
|
||||
This tests for an issue where if a site root page was moved, all the page
|
||||
urls in that site would change to None.
|
||||
|
||||
The issue was caused by the 'wagtail_site_root_paths' cache variable not being
|
||||
cleared when a site root page was moved. Which left all the child pages
|
||||
thinking that they are no longer in the site and return None as their url.
|
||||
|
||||
Fix: d6cce69a397d08d5ee81a8cbc1977ab2c9db2682
|
||||
Discussion: https://github.com/torchbox/wagtail/issues/7
|
||||
"""
|
||||
|
||||
fixtures = ['test.json']
|
||||
|
||||
def test_issue7(self):
|
||||
# Get homepage, root page and site
|
||||
root_page = Page.objects.get(id=1)
|
||||
homepage = Page.objects.get(url_path='/home/')
|
||||
default_site = Site.objects.get(is_default_site=True)
|
||||
|
||||
# Create a new homepage under current homepage
|
||||
new_homepage = SimplePage(title="New Homepage", slug="new-homepage")
|
||||
homepage.add_child(instance=new_homepage)
|
||||
|
||||
# Set new homepage as the site root page
|
||||
default_site.root_page = new_homepage
|
||||
default_site.save()
|
||||
|
||||
# Warm up the cache by getting the url
|
||||
_ = homepage.url
|
||||
|
||||
# Move new homepage to root
|
||||
new_homepage.move(root_page, pos='last-child')
|
||||
|
||||
# Get fresh instance of new_homepage
|
||||
new_homepage = Page.objects.get(id=new_homepage.id)
|
||||
|
||||
# Check url
|
||||
self.assertEqual(new_homepage.url, '/')
|
||||
|
||||
|
||||
class TestIssue157(TestCase):
|
||||
"""
|
||||
This tests for an issue where if a site root pages slug was changed, all the page
|
||||
urls in that site would change to None.
|
||||
|
||||
The issue was caused by the 'wagtail_site_root_paths' cache variable not being
|
||||
cleared when a site root page was changed. Which left all the child pages
|
||||
thinking that they are no longer in the site and return None as their url.
|
||||
|
||||
Fix: d6cce69a397d08d5ee81a8cbc1977ab2c9db2682
|
||||
Discussion: https://github.com/torchbox/wagtail/issues/157
|
||||
"""
|
||||
|
||||
fixtures = ['test.json']
|
||||
|
||||
def test_issue157(self):
|
||||
# Get homepage
|
||||
homepage = Page.objects.get(url_path='/home/')
|
||||
|
||||
# Warm up the cache by getting the url
|
||||
_ = homepage.url
|
||||
|
||||
# Change homepage title and slug
|
||||
homepage.title = "New home"
|
||||
homepage.slug = "new-home"
|
||||
homepage.save()
|
||||
|
||||
# Get fresh instance of homepage
|
||||
homepage = Page.objects.get(id=homepage.id)
|
||||
|
||||
# Check url
|
||||
self.assertEqual(homepage.url, '/')
|
||||
|
|
@ -56,7 +56,7 @@ def embedly(url, max_width=None, key=None):
|
|||
try:
|
||||
from embedly import Embedly
|
||||
# Get embedly client
|
||||
client = Embedly(key)
|
||||
client = Embedly(key=key)
|
||||
except ImportError:
|
||||
client = MockEmbedly()
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,24 @@
|
|||
from django.core import urlresolvers
|
||||
from django.conf.urls import include, url
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from wagtail.wagtailadmin import hooks
|
||||
from wagtail.wagtailredirects import urls
|
||||
|
||||
from wagtail.wagtailadmin.menu import MenuItem
|
||||
|
||||
|
||||
def register_admin_urls():
|
||||
return [
|
||||
url(r'^redirects/', include(urls)),
|
||||
]
|
||||
hooks.register('register_admin_urls', register_admin_urls)
|
||||
|
||||
|
||||
def construct_main_menu(request, menu_items):
|
||||
# TEMPORARY: Only show if the user is a superuser
|
||||
if request.user.is_superuser:
|
||||
menu_items.append(
|
||||
MenuItem(_('Redirects'), urlresolvers.reverse('wagtailredirects_index'), classnames='icon icon-redirect', order=800)
|
||||
)
|
||||
hooks.register('construct_main_menu', construct_main_menu)
|
||||
|
|
|
|||
|
|
@ -1,11 +1,24 @@
|
|||
from django.core import urlresolvers
|
||||
from django.conf.urls import include, url
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from wagtail.wagtailadmin import hooks
|
||||
from wagtail.wagtailsearch.urls import admin as admin_urls
|
||||
|
||||
from wagtail.wagtailadmin.menu import MenuItem
|
||||
|
||||
|
||||
def register_admin_urls():
|
||||
return [
|
||||
url(r'^search/', include(admin_urls)),
|
||||
]
|
||||
hooks.register('register_admin_urls', register_admin_urls)
|
||||
|
||||
|
||||
def construct_main_menu(request, menu_items):
|
||||
# TEMPORARY: Only show if the user is a superuser
|
||||
if request.user.is_superuser:
|
||||
menu_items.append(
|
||||
MenuItem(_('Editors picks'), urlresolvers.reverse('wagtailsearch_editorspicks_index'), classnames='icon icon-pick', order=900)
|
||||
)
|
||||
hooks.register('construct_main_menu', construct_main_menu)
|
||||
|
|
|
|||
|
|
@ -19,3 +19,4 @@ def get_snippet_content_types():
|
|||
def register_snippet(model):
|
||||
if model not in SNIPPET_MODELS:
|
||||
SNIPPET_MODELS.append(model)
|
||||
SNIPPET_MODELS.sort(key=lambda x: x._meta.verbose_name)
|
||||
|
|
|
|||
|
|
@ -3,7 +3,8 @@ from django.core.urlresolvers import reverse
|
|||
from django.contrib.auth.models import User
|
||||
|
||||
from wagtail.tests.utils import login, unittest
|
||||
from wagtail.tests.models import Advert
|
||||
from wagtail.tests.models import Advert, AlphaSnippet, ZuluSnippet
|
||||
from wagtail.wagtailsnippets.models import register_snippet, SNIPPET_MODELS
|
||||
|
||||
from wagtail.wagtailsnippets.views.snippets import get_content_type_from_url_params, get_snippet_edit_handler
|
||||
from wagtail.wagtailsnippets.edit_handlers import SnippetChooserPanel
|
||||
|
|
@ -168,3 +169,16 @@ class TestSnippetChooserPanel(TestCase):
|
|||
def test_render_js(self):
|
||||
self.assertTrue("createSnippetChooser(fixPrefix('id_text'), 'contenttypes/contenttype');"
|
||||
in self.snippet_chooser_panel.render_js())
|
||||
|
||||
|
||||
class TestSnippetOrdering(TestCase):
|
||||
def setUp(self):
|
||||
register_snippet(ZuluSnippet)
|
||||
register_snippet(AlphaSnippet)
|
||||
|
||||
def test_snippets_ordering(self):
|
||||
# Ensure AlphaSnippet is before ZuluSnippet
|
||||
# Cannot check first and last position as other snippets
|
||||
# may get registered elsewhere during test
|
||||
self.assertLess(SNIPPET_MODELS.index(AlphaSnippet),
|
||||
SNIPPET_MODELS.index(ZuluSnippet))
|
||||
|
|
|
|||
Loading…
Reference in a new issue