Skip to content

Commit

Permalink
Merge branch 'develop' into multidb_test
Browse files Browse the repository at this point in the history
Conflicts:
	cms/tests/page.py
  • Loading branch information
digi604 committed Dec 17, 2012
2 parents 9de0131 + 4f4e6c7 commit 2cb2e29
Show file tree
Hide file tree
Showing 42 changed files with 1,037 additions and 300 deletions.
1 change: 1 addition & 0 deletions AUTHORS
Expand Up @@ -46,6 +46,7 @@ Contributors (in alphabetical order):
* Bernd Zeimetz
* Bertrand Bordage
* beshrkayali
* Bjorn Sandberg
* Bob Karreman
* Bouke Haarsma
* Braden MacDonald
Expand Down
3 changes: 2 additions & 1 deletion CHANGELOG.txt
Expand Up @@ -131,4 +131,5 @@ Please see Install/2.4 release notes *before* attempting to upgrade to version 2
- MultilingualMiddleware has been removed
- CMS_FLAT_URLS has been removed


==== NEXT ====
- Fixed #1543: Nasty empty line in cms/plugins/link.html
56 changes: 25 additions & 31 deletions CONTRIBUTING.rst
Expand Up @@ -3,9 +3,23 @@ Contributing to django CMS
##########################

Like every open-source project, django CMS is always looking for motivated
individuals to contribute to its source code.
However, to ensure the highest code quality and keep the repository nice and
tidy, everybody has to follow a few rules (nothing major, I promise :) )
individuals to contribute to its source code. However, to ensure the highest
code quality and keep the repository nice and tidy, everybody has to follow a
few rules (nothing major, I promise :) )


.. ATTENTION::

If you think you have discovered a security issue in our code, please report
it **privately**, by emailing us at `security@django-cms.org`_.

Please don't raise it on:

* IRC
* GitHub
* either of our email lists

or in any other public forum until we have had a chance to deal with it.


*********
Expand Down Expand Up @@ -84,39 +98,18 @@ This is how you fix a bug or add a feature:

#. `fork`_ us on GitHub.
#. Checkout your fork.
#. Hack hack hack, test test test, commit commit commit, test again.
#. *Hack hack hack*, *test test test*, *commit commit commit*, test again.
#. Push to your fork.
#. Open a pull request.

And at any point in that process, you can add: *discuss discuss discuss*,
because it's always useful for everyone to pass ideas around and look at thngs
together.

Tests
=====

Having a wide and comprehensive library of unit-tests and integration tests is
of exceeding importance. Contributing tests is widely regarded as a very
prestigious contribution (you're making everybody's future work much easier by
doing so). Good karma for you. Cookie points. Maybe even a beer if we meet in
person :)

Generally tests should be:

- Unitary (as much as possible). I.E. should test as much as possible only one
function/method/class. That's the
very definition of unit tests. Integration tests are interesting too
obviously, but require more time to maintain since they have a higher
probability of breaking.
- Short running. No hard numbers here, but if your one test doubles the time it
takes for everybody to run them, it's probably an indication that you're doing
it wrong.

In a similar way to code, pull requests will be reviewed before pulling
(obviously), and we encourage discussion via code review (everybody learns
something this way) or IRC discussions.

Running the tests
-----------------
:ref:`testing` is really important.

To run the tests simply execute ``python setup.py test`` from your shell.
We have an IRC channel, our `django-cms-developers`_ email list,
and of course the code reviews mechanism on GitHub - do use them.


**************************
Expand Down Expand Up @@ -184,6 +177,7 @@ contribute. All changes there will be automatically sent to the project.



.. _security@django-cms.org: mailto:security@django-cms.org
.. _fork: http://github.com/divio/django-cms
.. _Sphinx: http://sphinx.pocoo.org/
.. _PEP8: http://www.python.org/dev/peps/pep-0008/
Expand Down
2 changes: 1 addition & 1 deletion cms/__init__.py
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
__version__ = '2.3.4.post0'
__version__ = '2.3.5.post0'

# patch settings
try:
Expand Down
74 changes: 31 additions & 43 deletions cms/admin/change_list.py
@@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
import bisect
from collections import defaultdict
from cms.exceptions import NoHomeFound
from cms.models import Title, Page, PageModeratorState
Expand All @@ -18,38 +19,30 @@ def cache_tree_children(queryset):
list. This attribute is in turn used by the 'get_children' method on the
item, which would otherwise (if '_cached_children' is not set) cause a
database query.
The queryset MUST BE ORDERED BY 'lft', 'tree_id'! Otherwise this function
will raise a ValueError.
The queryset must be ordered by 'lft', or the function will put the children
in the wrong order.
"""
parents_dict = {}
lastleft = -1 # integrity check
lasttree = -1 # integrity check
# Loop through the queryset twice, so that the function works even if the
# mptt tree is broken. Since django caches querysets internally, the extra
# computation time is minimal.
for obj in queryset:
parents_dict[obj.pk] = obj
if obj.tree_id == lasttree and obj.lft < lastleft: # integrity check
raise ValueError('Objects passed in the wrong order, must be ordered by the mptt left attribute and tree id')
lastleft = obj.lft # integrity check
lasttree = obj.tree_id # integrity check
# set the '_cached_children' attribute
obj._cached_children = []
# get the parent of this object (if available) via parent_id
parent = parents_dict.get(obj.parent_id, None)
for obj in queryset:
parent = parents_dict.get(obj.parent_id)
if parent:
# if there is a parent, append the current object to the _cached_children
# list of the parent. Since the objects are ordered by lft, tree_id
# the _cached_children attribute will always have been set by this
# function already.
parent._cached_children.append(obj)


class CMSChangeList(ChangeList):
'''
"""
Renders a Changelist - In our case it looks like a tree - it's the list of
*instances* in the Admin.
It is usually responsible for pagination (not here though, we have a
It is usually responsible for pagination (not here though, we have a
treeview)
'''
"""
real_queryset = False

def __init__(self, request, *args, **kwargs):
Expand All @@ -74,7 +67,7 @@ def get_query_set(self, request=None):
else:
qs = super(CMSChangeList, self).get_query_set().drafts()
if request:
site = self._current_site
site = self.current_site()
permissions = Page.permissions.get_change_id_list(request.user, site)

if permissions != Page.permissions.GRANT_ALL:
Expand Down Expand Up @@ -103,7 +96,7 @@ def get_results(self, request):
self.full_result_count = self.root_query_set.count()

def set_items(self, request):
site = self._current_site
site = self.current_site()
# Get all the pages, ordered by tree ID (it's convenient to build the
# tree using a stack now)
pages = self.get_query_set(request).drafts().order_by('tree_id', 'lft').select_related()
Expand All @@ -120,12 +113,11 @@ def set_items(self, request):
pages = pages.filter(pk__in=perm_edit_ids)
#pages = pages.filter(pk__in=perm_change_list_ids)

ids = []
root_pages = []
pages = list(pages)
all_pages = pages[:] # That is, basically, a copy.
try:
home_pk = Page.objects.drafts().get_home(self.current_site()).pk
home_pk = Page.objects.drafts().get_home(site).pk
except NoHomeFound:
home_pk = 0

Expand All @@ -142,21 +134,17 @@ def set_items(self, request):
# the children here, because MPTT expects the tree to be 'complete'
# and otherwise complaints about 'invalid item order'
cache_tree_children(pages)

ids = dict((page.id, page) for page in pages)

for page in pages:

children = list(page.get_children())

# note: We are using change_list permission here, because we must
# display also pages which user must not edit, but he haves a
# permission for adding a child under this page. Otherwise he would
# not be able to add anything under page which he can't change.
if not page.parent_id or (perm_change_list_ids != Page.permissions.GRANT_ALL and not int(page.parent_id) in perm_change_list_ids):
page.root_node = True
else:
page.root_node = False
ids.append(page.pk)

# If the parent page is not among the nodes shown, this node should
# be a "root node". The filtering for this has already been made, so
# using the ids dictionary means this check is constant time
page.root_node = page.parent_id not in ids

if settings.CMS_PERMISSION:
# caching the permissions
page.permission_edit_cache = perm_edit_ids == Page.permissions.GRANT_ALL or page.pk in perm_edit_ids
Expand Down Expand Up @@ -196,17 +184,17 @@ def set_items(self, request):
else:
page.childrens = children

# TODO: OPTIMIZE!!
titles = Title.objects.filter(page__in=ids)
for page in all_pages:# add the title and slugs and some meta data
for page in all_pages:
page.title_cache = {}
page.all_languages = []
for title in titles:
if title.page_id == page.pk:
page.title_cache[title.language] = title
if not title.language in page.all_languages:
page.all_languages.append(title.language)
page.all_languages.sort()

titles = Title.objects.filter(page__in=ids)
insort = bisect.insort # local copy to avoid globals lookup in the loop
for title in titles:
page = ids[title.page_id]
page.title_cache[title.language] = title
if not title.language in page.all_languages:
insort(page.all_languages, title.language)
self.root_pages = root_pages

def get_items(self):
Expand Down
26 changes: 13 additions & 13 deletions cms/api.py
Expand Up @@ -125,9 +125,15 @@ def create_page(title, template, language, menu_title=None, slug=None,

# validate template
assert template in [tpl[0] for tpl in settings.CMS_TEMPLATES]


# validate site
if not site:
site = Site.objects.get_current()
else:
assert isinstance(site, Site)

# validate language:
assert language in get_language_list()
assert language in get_language_list(site), settings.CMS_LANGUAGES.get(site.pk)

# set default slug:
if not slug:
Expand All @@ -142,7 +148,7 @@ def create_page(title, template, language, menu_title=None, slug=None,
# validate parent
if parent:
assert isinstance(parent, Page)

# validate publication date
if publication_date:
assert isinstance(publication_date, datetime.date)
Expand All @@ -154,12 +160,6 @@ def create_page(title, template, language, menu_title=None, slug=None,
# validate softroot
assert settings.CMS_SOFTROOT or not soft_root

# validate site
if not site:
site = Site.objects.get_current()
else:
assert isinstance(site, Site)

if navigation_extenders:
raw_menus = menu_pool.get_menus_by_attribute("cms_enabled", True)
menus = [menu[0] for menu in raw_menus]
Expand Down Expand Up @@ -221,12 +221,12 @@ def create_title(language, title, page, menu_title=None, slug=None,
See docs/extending_cms/api_reference.rst for more info
"""
# validate language:
assert language in get_language_list()

# validate page
assert isinstance(page, Page)


# validate language:
assert language in get_language_list(page.site_id)

# set default slug:
if not slug:
slug = _generate_valid_slug(title, parent, language)
Expand Down
7 changes: 5 additions & 2 deletions cms/appresolver.py
Expand Up @@ -48,8 +48,11 @@ def applications_page_check(request, current_page=None, path=None):
return None

class AppRegexURLResolver(RegexURLResolver):
page_id = None
url_patterns_dict = {}

def __init__(self, *args, **kwargs):
self.page_id = None
self.url_patterns_dict = {}
super(AppRegexURLResolver, self).__init__(*args, **kwargs)

@property
def url_patterns(self):
Expand Down

0 comments on commit 2cb2e29

Please sign in to comment.