cms.appresolver: 130 total statements, 0.0% covered

Generated: Wed 2013-03-13 10:33 CET

Source file: /media/Envs/Envs/filer-gallery/lib/python2.7/site-packages/cms/appresolver.py

Stats: 0 executed, 120 missed, 10 excluded, 79 ignored

  1. # -*- coding: utf-8 -*-
  2. from cms.apphook_pool import apphook_pool
  3. from cms.utils.moderator import get_page_queryset
  4. from django.conf import settings
  5. from django.conf.urls.defaults import patterns
  6. from django.contrib.sites.models import Site
  7. from django.core.exceptions import ImproperlyConfigured
  8. from django.core.urlresolvers import RegexURLResolver, Resolver404, reverse, \
  9. RegexURLPattern
  10. from django.db.models import Q
  11. from django.utils.importlib import import_module
  12. APP_RESOLVERS = []
  13. def clear_app_resolvers():
  14. global APP_RESOLVERS
  15. APP_RESOLVERS = []
  16. def applications_page_check(request, current_page=None, path=None):
  17. """Tries to find if given path was resolved over application.
  18. Applications have higher priority than other cms pages.
  19. """
  20. if current_page:
  21. return current_page
  22. if path is None:
  23. # We should get in this branch only if an apphook is active on /
  24. # This removes the non-CMS part of the URL.
  25. path = request.path.replace(reverse('pages-root'), '', 1)
  26. # check if application resolver can resolve this
  27. for resolver in APP_RESOLVERS:
  28. try:
  29. page_id = resolver.resolve_page_id(path)
  30. # yes, it is application page
  31. if settings.CMS_MODERATOR:
  32. page = get_page_queryset(request).get(Q(id=page_id) | Q(publisher_draft=page_id))
  33. else:
  34. page = get_page_queryset(request).get(id=page_id)
  35. # If current page was matched, then we have some override for content
  36. # from cms, but keep current page. Otherwise return page to which was application assigned.
  37. return page
  38. except Resolver404:
  39. # Raised if the page is not managed by an apphook
  40. pass
  41. return None
  42. class AppRegexURLResolver(RegexURLResolver):
  43. page_id = None
  44. url_patterns = None
  45. def resolve_page_id(self, path):
  46. """Resolves requested path similar way how resolve does, but instead
  47. of return callback,.. returns page_id to which was application
  48. assigned.
  49. """
  50. tried = []
  51. match = self.regex.search(path)
  52. if match:
  53. new_path = path[match.end():]
  54. for pattern in self.url_patterns:
  55. try:
  56. sub_match = pattern.resolve(new_path)
  57. except Resolver404, e:
  58. if 'tried' in e.args[0]:
  59. tried.extend([(pattern.regex.pattern + ' ' + t) for t in e.args[0]['tried']])
  60. elif 'path' in e.args[0]:
  61. tried.extend([(pattern.regex.pattern + ' ' + t) for t in e.args[0]['path']])
  62. else:
  63. if sub_match:
  64. return pattern.page_id
  65. tried.append(pattern.regex.pattern)
  66. raise Resolver404, {'tried': tried, 'path': new_path}
  67. def recurse_patterns(path, pattern_list, page_id):
  68. """
  69. Recurse over a list of to-be-hooked patterns for a given path prefix
  70. """
  71. newpatterns = []
  72. for pattern in pattern_list:
  73. app_pat = pattern.regex.pattern
  74. # make sure we don't get patterns that start with more than one '^'!
  75. app_pat = app_pat.lstrip('^')
  76. path = path.lstrip('^')
  77. regex = r'^%s%s' % (path, app_pat)
  78. if isinstance(pattern, RegexURLResolver):
  79. # this is an 'include', recurse!
  80. resolver = RegexURLResolver(regex, 'cms_appresolver',
  81. pattern.default_kwargs, pattern.app_name, pattern.namespace)
  82. resolver.page_id = page_id
  83. # see lines 243 and 236 of urlresolvers.py to understand the next line
  84. resolver._urlconf_module = recurse_patterns(regex, pattern.url_patterns, page_id)
  85. else:
  86. # Re-do the RegexURLPattern with the new regular expression
  87. resolver = RegexURLPattern(regex, pattern.callback,
  88. pattern.default_args, pattern.name)
  89. resolver.page_id = page_id
  90. newpatterns.append(resolver)
  91. return newpatterns
  92. def _flatten_patterns(patterns):
  93. flat = []
  94. for pattern in patterns:
  95. if isinstance(pattern, RegexURLResolver):
  96. flat += _flatten_patterns(pattern.url_patterns)
  97. else:
  98. flat.append(pattern)
  99. return flat
  100. def get_app_urls(urls):
  101. for urlconf in urls:
  102. if isinstance(urlconf, basestring):
  103. mod = import_module(urlconf)
  104. if not hasattr(mod, 'urlpatterns'):
  105. raise ImproperlyConfigured(
  106. "URLConf `%s` has no urlpatterns attribute" % urlconf)
  107. yield getattr(mod, 'urlpatterns')
  108. else:
  109. yield urlconf
  110. def get_patterns_for_title(path, title):
  111. """
  112. Resolve the urlconf module for a path+title combination
  113. Returns a list of url objects.
  114. """
  115. app = apphook_pool.get_apphook(title.application_urls)
  116. patterns = []
  117. for pattern_list in get_app_urls(app.urls):
  118. if path and not path.endswith('/'):
  119. path += '/'
  120. page_id = title.page.id
  121. patterns += recurse_patterns(path, pattern_list, page_id)
  122. patterns = _flatten_patterns(patterns)
  123. return patterns
  124. def get_app_patterns():
  125. """
  126. Get a list of patterns for all hooked apps.
  127. How this works:
  128. By looking through all titles with an app hook (application_urls) we find all
  129. urlconf modules we have to hook into titles.
  130. If we use the ML URL Middleware, we namespace those patterns with the title
  131. language.
  132. All 'normal' patterns from the urlconf get re-written by prefixing them with
  133. the title path and then included into the cms url patterns.
  134. """
  135. from cms.models import Title
  136. try:
  137. current_site = Site.objects.get_current()
  138. except Site.DoesNotExist:
  139. current_site = None
  140. included = []
  141. # we don't have a request here so get_page_queryset() can't be used,
  142. # so, if CMS_MODERATOR, use, public() queryset, otherwise
  143. # use draft(). This can be done, because url patterns are used just
  144. # in frontend
  145. is_draft = not settings.CMS_MODERATOR
  146. title_qs = Title.objects.filter(page__publisher_is_draft=is_draft, page__site=current_site)
  147. if 'cms.middleware.multilingual.MultilingualURLMiddleware' in settings.MIDDLEWARE_CLASSES:
  148. use_namespaces = True
  149. hooked_applications = {}
  150. else:
  151. use_namespaces = False
  152. hooked_applications = []
  153. # Loop over all titles with an application hooked to them
  154. for title in title_qs.exclude(application_urls=None).exclude(application_urls='').select_related():
  155. path = title.path
  156. if use_namespaces:
  157. mixid = "%s:%s:%s" % (path + "/", title.application_urls, title.language)
  158. else:
  159. mixid = "%s:%s" % (path + "/", title.application_urls)
  160. if mixid in included:
  161. # don't add the same thing twice
  162. continue
  163. if not settings.APPEND_SLASH:
  164. path += '/'
  165. if use_namespaces:
  166. if title.language not in hooked_applications:
  167. hooked_applications[title.language] = []
  168. hooked_applications[title.language] += get_patterns_for_title(path, title)
  169. else:
  170. hooked_applications += get_patterns_for_title(path, title)
  171. included.append(mixid)
  172. # Build the app patterns to be included in the cms urlconfs
  173. app_patterns = []
  174. if use_namespaces:
  175. for ns, currentpatterns in hooked_applications.items():
  176. extra_patterns = patterns('', *currentpatterns)
  177. resolver = AppRegexURLResolver(r'', 'app_resolver', namespace=ns)
  178. resolver.url_patterns = extra_patterns
  179. app_patterns.append(resolver)
  180. APP_RESOLVERS.append(resolver)
  181. else:
  182. extra_patterns = patterns('', *hooked_applications)
  183. resolver = AppRegexURLResolver(r'', 'app_resolver')
  184. resolver.url_patterns = extra_patterns
  185. app_patterns.append(resolver)
  186. APP_RESOLVERS.append(resolver)
  187. return app_patterns