Repository: django-cms/django-cms

Issue:
clash between homepage slug and apphook results in wrong URLs
I have  this setup:
- a homepage with the slug "home". 
- a page /topics/summer/gardening-at-home/lists/, which has an apphook with an URL 'list-trees'

When I reverse 'list-trees', the wrong URL is returned: /lists/list-trees/

This is because of https://github.com/divio/django-cms/blob/develop/cms/appresolver.py#L192, where the code falsely detects "home" in "gardening-at-home" and mistakes it as the home page.

clash between homepage slug and apphook results in wrong URLs
I have  this setup:
- a homepage with the slug "home". 
- a page /topics/summer/gardening-at-home/lists/, which has an apphook with an URL 'list-trees'

When I reverse 'list-trees', the wrong URL is returned: /lists/list-trees/

This is because of https://github.com/divio/django-cms/blob/develop/cms/appresolver.py#L192, where the code falsely detects "home" in "gardening-at-home" and mistakes it as the home page.



Discussion:
aka `get_app_patterns` is broked since the 'title-path-refactor' (aka `get_absolute_url` speedup). The solution is to use `title.path` in `get_app_patterns` instead of trying to magically remove the home slug from that path (which is no longer in path)

aka `get_app_patterns` is broked since the 'title-path-refactor' (aka `get_absolute_url` speedup). The solution is to use `title.path` in `get_app_patterns` instead of trying to magically remove the home slug from that path (which is no longer in path)


Resolving patch:
diff --git a/cms/appresolver.py b/cms/appresolver.py
--- a/cms/appresolver.py
+++ b/cms/appresolver.py
@@ -147,7 +147,6 @@ def get_app_patterns():
     the title path and then included into the cms url patterns.
     """
     from cms.models import Title
-    from cms.models.pagemodel import Page
     try:
         current_site = Site.objects.get_current()
     except Site.DoesNotExist:
@@ -159,14 +158,7 @@ def get_app_patterns():
     # use draft(). This can be done, because url patterns are used just 
     # in frontend
     is_draft = not settings.CMS_MODERATOR
-    try:
-        home = Page.objects.get_home()
-        home_titles = home.title_set.all()
-    except NoHomeFound:
-        home_titles = []
-    home_slugs = {}
-    for title in home_titles:
-        home_slugs[title.language] = title.slug
+
     title_qs = Title.objects.filter(page__publisher_is_draft=is_draft, page__site=current_site)
     
     if 'cms.middleware.multilingual.MultilingualURLMiddleware' in settings.MIDDLEWARE_CLASSES:
@@ -178,24 +170,11 @@ def get_app_patterns():
     
     # Loop over all titles with an application hooked to them
     for title in title_qs.exclude(application_urls=None).exclude(application_urls='').select_related():
-        if settings.CMS_FLAT_URLS:
-            if title.language in home_slugs:
-                path = title.slug.split(home_slugs[title.language] + "/", 1)[-1]
-            else:
-                path = title.slug
-            if use_namespaces:
-                mixid = "%s:%s:%s" % (path + "/", title.application_urls, title.language)
-            else:
-                mixid = "%s:%s" % (path + "/", title.application_urls)
+        path = title.path
+        if use_namespaces:
+            mixid = "%s:%s:%s" % (path + "/", title.application_urls, title.language)
         else:
-            if title.language in home_slugs:
-                path = title.path.split(home_slugs[title.language] + "/", 1)[-1]
-            else:
-                path = title.path
-            if use_namespaces:
-                mixid = "%s:%s:%s" % (path + "/", title.application_urls, title.language)
-            else:
-                mixid = "%s:%s" % (path + "/", title.application_urls)
+            mixid = "%s:%s" % (path + "/", title.application_urls)
         if mixid in included:
             # don't add the same thing twice
             continue  


Test patch:
diff --git a/cms/tests/apphooks.py b/cms/tests/apphooks.py
--- a/cms/tests/apphooks.py
+++ b/cms/tests/apphooks.py
@@ -2,7 +2,8 @@
 from __future__ import with_statement
 from cms.api import create_page, create_title
 from cms.apphook_pool import apphook_pool
-from cms.appresolver import applications_page_check, clear_app_resolvers
+from cms.appresolver import (applications_page_check, clear_app_resolvers, 
+    get_app_patterns)
 from cms.test_utils.testcases import CMSTestCase
 from cms.test_utils.util.context_managers import SettingsOverride
 from django.contrib.auth.models import User
@@ -135,3 +136,15 @@ def test_get_page_for_apphook(self):
             self.assertContains(response, de_title.title)
             
             apphook_pool.clear()
+
+    def test_apphook_breaking_under_home_with_new_path_caching(self):
+        with SettingsOverride(CMS_MODERATOR=False, CMS_PERMISSION=False):
+            home = create_page("home", "nav_playground.html", "en", published=True)
+            child = create_page("child", "nav_playground.html", "en", published=True, parent=home)
+            # not-home is what breaks stuff, because it contains the slug of the home page
+            not_home = create_page("not-home", "nav_playground.html", "en", published=True, parent=child)
+            create_page("subchild", "nav_playground.html", "en", published=True, parent=not_home, apphook='SampleApp')
+            urlpatterns = get_app_patterns()
+            resolver = urlpatterns[0]
+            url = resolver.reverse('sample-root')
+            self.assertEqual(url, 'child/not-home/subchild/')