def __init__(self, *args, **kwargs): super(AdvancedSettingsForm, self).__init__(*args, **kwargs) self.fields['language'].widget = HiddenInput() self.fields['site'].widget = HiddenInput() site_id = self.fields['site'].initial languages = get_language_tuple(site_id) self.fields['language'].choices = languages if not self.fields['language'].initial: self.fields['language'].initial = get_language() if 'navigation_extenders' in self.fields: self.fields['navigation_extenders'].widget = forms.Select( {}, [('', "---------")] + menu_pool.get_menus_by_attribute("cms_enabled", True)) if 'application_urls' in self.fields: # Prepare a dict mapping the apps by class name ('PollApp') to # their app_name attribute ('polls'), if any. app_namespaces = {} app_configs = {} for hook in apphook_pool.get_apphooks(): app = apphook_pool.get_apphook(hook[0]) if app.app_name: app_namespaces[hook[0]] = app.app_name if app.app_config: app_configs[hook[0]] = app self.fields['application_urls'].widget = AppHookSelect( attrs={'id': 'application_urls'}, app_namespaces=app_namespaces ) self.fields['application_urls'].choices = [('', "---------")] + apphook_pool.get_apphooks() page_data = self.data if self.data else self.initial if app_configs: self.fields['application_configs'].widget = ApplicationConfigSelect( attrs={'id': 'application_configs'}, app_configs=app_configs) if page_data.get('application_urls', False) and page_data['application_urls'] in app_configs: self.fields['application_configs'].choices = [(config.pk, force_text(config)) for config in app_configs[page_data['application_urls']].get_configs()] apphook = page_data.get('application_urls', False) try: config = apphook_pool.get_apphook(apphook).get_configs().get(namespace=self.initial['application_namespace']) self.fields['application_configs'].initial = config.pk except ObjectDoesNotExist: # Provided apphook configuration doesn't exist (anymore), # just skip it # The user will choose another value anyway pass else: # If app_config apphook is not selected, drop any value # for application_configs to avoid the field data from # being validated by the field itself try: del self.data['application_configs'] except KeyError: pass if 'redirect' in self.fields: self.fields['redirect'].widget.language = self.fields['language'].initial
def clean(self): cleaned_data = super(AdvancedSettingsForm, self).clean() if 'reverse_id' in self.fields: id = cleaned_data['reverse_id'] site_id = cleaned_data['site'] if id: if Page.objects.filter(reverse_id=id, site=site_id, publisher_is_draft=True).exclude( pk=self.instance.pk).count(): self._errors['reverse_id'] = self.error_class( [_('A page with this reverse URL id exists already.')]) apphook = cleaned_data.get('application_urls', None) # The field 'application_namespace' is a misnomer. It should be # 'instance_namespace'. instance_namespace = cleaned_data.get('application_namespace', None) application_config = cleaned_data.get('application_configs', None) if apphook: # application_config wins over application_namespace if application_config: # the value of the application config namespace is saved in # the 'usual' namespace field to be backward compatible # with existing apphooks config = apphook_pool.get_apphook(apphook).get_configs().get( pk=int(application_config)) self.cleaned_data['application_namespace'] = config.namespace else: # The attribute on the apps 'app_name' is a misnomer, it should be # 'application_namespace'. application_namespace = apphook_pool.get_apphook( apphook).app_name if application_namespace and not instance_namespace: if Page.objects.filter( publisher_is_draft=True, application_urls=apphook, application_namespace=application_namespace ).exclude(pk=self.instance.pk).count(): # Looks like there's already one with the default instance # namespace defined. self._errors['application_urls'] = ErrorList([ _('''You selected an apphook with an "app_name". You must enter a unique instance name.''') ]) else: # OK, there are zero instances of THIS app that use the # default instance namespace, so, since the user didn't # provide one, we'll use the default. NOTE: The following # line is really setting the "instance namespace" of the # new app to the app’s "application namespace", which is # the default instance namespace. self.cleaned_data[ 'application_namespace'] = application_namespace if instance_namespace and not apphook: self.cleaned_data['application_namespace'] = None if application_config and not apphook: self.cleaned_data['application_configs'] = None return cleaned_data
def clean(self): cleaned_data = super(AdvancedSettingsForm, self).clean() if 'reverse_id' in self.fields: id = cleaned_data['reverse_id'] site_id = cleaned_data['site'] if id: if Page.objects.filter(reverse_id=id, site=site_id, publisher_is_draft=True).exclude( pk=self.instance.pk).count(): self._errors['reverse_id'] = self.error_class( [_('A page with this reverse URL id exists already.')]) apphook = cleaned_data.get('application_urls', None) # The field 'application_namespace' is a misnomer. It should be # 'instance_namespace'. instance_namespace = cleaned_data.get('application_namespace', None) application_config = cleaned_data.get('application_configs', None) if apphook: # application_config wins over application_namespace if application_config: # the value of the application config namespace is saved in # the 'usual' namespace field to be backward compatible # with existing apphooks config = apphook_pool.get_apphook(apphook).get_configs().get(pk=int(application_config)) self.cleaned_data['application_namespace'] = config.namespace else: # The attribute on the apps 'app_name' is a misnomer, it should be # 'application_namespace'. application_namespace = apphook_pool.get_apphook(apphook).app_name if application_namespace and not instance_namespace: if Page.objects.filter( publisher_is_draft=True, application_urls=apphook, application_namespace=application_namespace ).exclude(pk=self.instance.pk).count(): # Looks like there's already one with the default instance # namespace defined. self._errors['application_urls'] = ErrorList([ _('''You selected an apphook with an "app_name". You must enter a unique instance name.''') ]) else: # OK, there are zero instances of THIS app that use the # default instance namespace, so, since the user didn't # provide one, we'll use the default. NOTE: The following # line is really setting the "instance namespace" of the # new app to the app’s "application namespace", which is # the default instance namespace. self.cleaned_data['application_namespace'] = application_namespace if instance_namespace and not apphook: self.cleaned_data['application_namespace'] = None if application_config and not apphook: self.cleaned_data['application_configs'] = None return cleaned_data
def modify(self, request, nodes, namespace, root_id, post_cut, breadcrumb): """ Actual modifier function :param request: request :param nodes: complete list of nodes :param namespace: Menu namespace :param root_id: eventual root_id :param post_cut: flag for modifier stage :param breadcrumb: flag for modifier stage :return: nodeslist """ app = None config = None if getattr(request, 'current_page', None) and request.current_page.application_urls: app = apphook_pool.get_apphook(request.current_page.application_urls) if app and app.app_config: namespace = resolve(request.path).namespace config = app.get_config(namespace) if config and config.menu_structure != MENU_TYPE_CATEGORIES: return nodes if post_cut: return nodes current_post = getattr(request, get_setting('CURRENT_POST_IDENTIFIER'), None) category = None if current_post and current_post.__class__ == Post: category = current_post.categories.first() if not category: return nodes for node in nodes: if '{0}-{1}'.format(category.__class__.__name__, category.pk) == node.id: node.selected = True return nodes
def get_nodes(self, request): nodes = [] language = get_language_from_request(request, check_path=True) # NOTE: It is important that we only get objects that have an active # translation, otherwise, object.get_absolute_url() may return # NoReverseMatch exceptions that we will have to catch, if we want to # prevent errors from appearing on-screen. things = (Thing.objects.published() .language(language) .active_translations(language)) if hasattr(self, 'instance') and self.instance: # pragma: no cover # If self has a property `instance`, then we're using django CMS # 3.0.12 or later, which supports using CMSAttachMenus on multiple, # apphook'ed pages, each with their own apphook configuration. So, # here we modify the queryset to reflect this. app = apphook_pool.get_apphook(self.instance.application_urls) if app: things = things.namespace(self.instance.application_namespace) for thing in things: # This try/except seems like overkill here, but if this fails for # any reason, this **and any further menus, even from other apps** # may not get loaded, so we're extra careful. try: url = thing.get_absolute_url(language=language) node = NavigationNode(thing.name, url, thing.pk) nodes.append(node) except NoReverseMatch: # pragma: no cover pass return nodes
def page_to_node(page, home, cut): parent_id = page.parent_id if home and page.parent_id == home.pk and cut: parent_id = None # possible fix for a possible problem # if parent_id and not page.parent.get_calculated_status(): # parent_id = None # ???? attr = {"soft_root": page.soft_root, "auth_required": page.login_required, "reverse_id": page.reverse_id} if page.limit_visibility_in_menu == None: attr["visible_for_authenticated"] = True attr["visible_for_anonymous"] = True else: attr["visible_for_authenticated"] = page.limit_visibility_in_menu == 1 attr["visible_for_anonymous"] = page.limit_visibility_in_menu == 2 if page.pk == home.pk: attr["is_home"] = True extenders = [] if page.navigation_extenders: extenders.append(page.navigation_extenders) try: app_name = page.get_application_urls(fallback=False) except Title.DoesNotExist: app_name = None if app_name: app = apphook_pool.get_apphook(app_name) for menu in app.menus: extenders.append(menu.__name__) attr["redirect_url"] = page.get_redirect() # save redirect URL is any if extenders: attr["navigation_extenders"] = extenders n = NavigationNode( page.get_menu_title(), page.get_absolute_url(), page.pk, parent_id, attr=attr, visible=page.in_navigation ) return n
def get_nodes(self, request): nodes = [] language = get_language_from_request(request, check_path=True) articles = self.get_queryset(request).active_translations(language) if hasattr(self, 'instance') and self.instance: app = apphook_pool.get_apphook(self.instance.application_urls) if app: config = app.get_config(self.instance.application_namespace) if config: articles = articles.filter(app_config=config) for article in articles: try: url = article.get_absolute_url(language=language) except NoReverseMatch: url = None if url: node = NavigationNode(article.safe_translation_getter( 'title', language_code=language), url, article.pk) nodes.append(node) return nodes
def __init__(self, *args, **kwargs): super(AdvancedSettingsForm, self).__init__(*args, **kwargs) self.fields['language'].widget = HiddenInput() self.fields['site'].widget = HiddenInput() site_id = self.fields['site'].initial languages = get_language_tuple(site_id) self.fields['language'].choices = languages if not self.fields['language'].initial: self.fields['language'].initial = get_language() if 'navigation_extenders' in self.fields: self.fields['navigation_extenders'].widget = forms.Select({}, [('', "---------")] + menu_pool.get_menus_by_attribute("cms_enabled", True)) if 'application_urls' in self.fields: # Prepare a dict mapping the apps by class name ('PollApp') to # their app_name attribute ('polls'), if any. app_namespaces = {} for hook in apphook_pool.get_apphooks(): app = apphook_pool.get_apphook(hook[0]) if app.app_name: app_namespaces[hook[0]] = app.app_name self.fields['application_urls'].widget = AppHookSelect( attrs={'id':'application_urls'}, app_namespaces=app_namespaces, ) self.fields['application_urls'].choices = [('', "---------")] + apphook_pool.get_apphooks() if 'redirect' in self.fields: self.fields['redirect'].widget.language = self.fields['language'].initial
def get_use_cache(self, context, instance, placeholder): try: app = apphook_pool.get_apphook(instance.page.application_urls) return app.cache_placeholders except (AttributeError, ImproperlyConfigured): return super(BreadcrumbPlugin, self).get_use_cache(context, instance, placeholder)
def page_to_node(page, home, cut): parent_id = page.parent_id if home and page.parent_id == home.pk and cut: parent_id = None # possible fix for a possible problem #if parent_id and not page.parent.get_calculated_status(): # parent_id = None # ???? attr = {'soft_root':page.soft_root, 'auth_required':page.login_required, 'reverse_id':page.reverse_id,} if page.pk == home.pk: attr['is_home'] = True extenders = [] if page.navigation_extenders: extenders.append(page.navigation_extenders) try: app_name = page.get_application_urls(fallback=False) except Title.DoesNotExist: app_name = None if app_name: app = apphook_pool.get_apphook(app_name) for menu in app.menus: extenders.append(menu.__name__) if extenders: attr['navigation_extenders'] = extenders n = NavigationNode( page.get_menu_title(), page.get_absolute_url(), page.pk, parent_id, attr=attr, visible=page.in_navigation, ) return n
def get_nodes(self, request): nodes = [] language = get_language_from_request(request, check_path=True) events = (Event.objects.published() .language(language) .active_translations(language)) if hasattr(self, 'instance') and self.instance: # If self has a property `instance`, then we're using django CMS # 3.0.12 or later, which supports using CMSAttachMenus on multiple, # apphook'ed pages, each with their own apphook configuration. So, # here we modify the queryset to reflect this. app = apphook_pool.get_apphook(self.instance.application_urls) if app: events = events.namespace(self.instance.application_namespace) for event in events: try: url = event.get_absolute_url(language=language) except NoReverseMatch: url = None if url: node = NavigationNode( event.title, event.get_absolute_url(language=language), event.pk, ) nodes.append(node) return nodes
def __get__(self, request, obj_type=None): if not hasattr(request, '_current_app_cache'): page = request.current_page app_urls = page.get_application_urls() if app_urls: app = apphook_pool.get_apphook(app_urls) request._current_app_cache = page.reverse_id if page.reverse_id else app.app_name return request._current_app_cache
def test_admin_url(self): app = apphook_pool.get_apphook(self.page_1.application_urls) url = app.get_config_add_url() try: self.assertEqual(url, reverse('admin:%s_%s_add' % (ExampleConfig._meta.app_label, ExampleConfig._meta.model_name))) except AttributeError: #NOQA self.assertEqual(url, reverse('admin:%s_%s_add' % (ExampleConfig._meta.app_label, ExampleConfig._meta.module_name)))
def __init__(self, *args, **kwargs): super(AdvancedSettingsForm, self).__init__(*args, **kwargs) self.title_obj = self.instance.get_title_obj( language=self._language, fallback=False, force_reload=True, ) if 'navigation_extenders' in self.fields: navigation_extenders = self.get_navigation_extenders() self.fields['navigation_extenders'].widget = forms.Select( {}, [('', "---------")] + navigation_extenders) if 'application_urls' in self.fields: # Prepare a dict mapping the apps by class name ('PollApp') to # their app_name attribute ('polls'), if any. app_namespaces = {} app_configs = {} for hook in apphook_pool.get_apphooks(): app = apphook_pool.get_apphook(hook[0]) if app.app_name: app_namespaces[hook[0]] = app.app_name if app.app_config: app_configs[hook[0]] = app self.fields['application_urls'].widget = AppHookSelect( attrs={'id': 'application_urls'}, app_namespaces=app_namespaces ) self.fields['application_urls'].choices = [('', "---------")] + apphook_pool.get_apphooks() page_data = self.data if self.data else self.initial if app_configs: self.fields['application_configs'].widget = ApplicationConfigSelect( attrs={'id': 'application_configs'}, app_configs=app_configs, ) if page_data.get('application_urls', False) and page_data['application_urls'] in app_configs: configs = app_configs[page_data['application_urls']].get_configs() self.fields['application_configs'].widget.choices = [(config.pk, force_text(config)) for config in configs] try: config = configs.get(namespace=self.initial['application_namespace']) self.fields['application_configs'].initial = config.pk except ObjectDoesNotExist: # Provided apphook configuration doesn't exist (anymore), # just skip it # The user will choose another value anyway pass if 'redirect' in self.fields: self.fields['redirect'].widget.language = self._language self.fields['redirect'].initial = self.title_obj.redirect if 'overwrite_url' in self.fields and self.title_obj.has_url_overwrite: self.fields['overwrite_url'].initial = self.title_obj.path
def test_apphook_by_class(self): if APP_MODULE in sys.modules: del sys.modules[APP_MODULE] apphooks = ("%s.%s" % (APP_MODULE, APP_NAME),) with self.settings(CMS_APPHOOKS=apphooks): apphook_pool.clear() apphook = apphook_pool.get_apphook(APP_NAME) page = create_page(apphook=apphook, **self._get_default_create_page_arguments()) self.assertEqual(page.get_application_urls("en"), APP_NAME)
def test_apphook_by_class(self): if APP_MODULE in sys.modules: del sys.modules[APP_MODULE] apphooks = ('%s.%s' % (APP_MODULE, APP_NAME), ) with self.settings(CMS_APPHOOKS=apphooks): apphook_pool.clear() apphook = apphook_pool.get_apphook(APP_NAME) page = create_page(apphook=apphook, **self._get_default_create_page_arguments()) self.assertEqual(page.get_application_urls('en'), APP_NAME)
def get_installed_apphook(cls, base_apphook_name): from cms.apphook_pool import apphook_pool base_apphook = import_string('shop.cms_apphooks.' + base_apphook_name) for apphook, _ in apphook_pool.get_apphooks(): apphook = apphook_pool.get_apphook(apphook) if isinstance(apphook, base_apphook): return apphook else: msg = "The project must register an AppHook inheriting from '{apphook_name}'" raise MissingAppHook(msg.format(apphook_name=base_apphook_name))
def _get_attrs_for_node(renderer, page_content): page = page_content.page language = renderer.request_language attr = { 'is_page': True, 'soft_root': page_content.soft_root, 'auth_required': page.login_required, 'reverse_id': page.reverse_id, } limit_visibility_in_menu = page_content.limit_visibility_in_menu if limit_visibility_in_menu is cms_constants.VISIBILITY_ALL: attr['visible_for_authenticated'] = True attr['visible_for_anonymous'] = True else: attr['visible_for_authenticated'] = ( limit_visibility_in_menu == cms_constants.VISIBILITY_USERS) attr['visible_for_anonymous'] = ( limit_visibility_in_menu == cms_constants.VISIBILITY_ANONYMOUS) attr['is_home'] = page.is_home extenders = [] if page.navigation_extenders: if page.navigation_extenders in renderer.menus: extenders.append(page.navigation_extenders) elif '{0}:{1}'.format(page.navigation_extenders, page.pk) in renderer.menus: extenders.append('{0}:{1}'.format(page.navigation_extenders, page.pk)) if page.application_urls: app = apphook_pool.get_apphook(page.application_urls) if app: extenders += app.get_menus(page, language) exts = [] for ext in extenders: if hasattr(ext, 'get_instances'): exts.append('{0}:{1}'.format(ext.__name__, page.pk)) elif hasattr(ext, '__name__'): exts.append(ext.__name__) else: exts.append(ext) if exts: attr['navigation_extenders'] = exts attr['redirect_url'] = page_content.redirect return attr
def get_apphooks(cls): """ Returns a list of apphooks to which this CMSAttachMenu is attached. Calling this does NOT produce DB queries. """ apps = [] for key, _ in apphook_pool.get_apphooks(): app = apphook_pool.get_apphook(key) if cls in app.menus: apps.append(app) return apps
def _get_attrs_for_node(renderer, page_content): page = page_content.page language = renderer.request_language attr = { "is_page": True, "soft_root": page_content.soft_root, "auth_required": page.login_required, "reverse_id": page.reverse_id, } limit_visibility_in_menu = page_content.limit_visibility_in_menu if limit_visibility_in_menu is cms_constants.VISIBILITY_ALL: attr["visible_for_authenticated"] = True attr["visible_for_anonymous"] = True else: attr["visible_for_authenticated"] = ( limit_visibility_in_menu == cms_constants.VISIBILITY_USERS) attr["visible_for_anonymous"] = ( limit_visibility_in_menu == cms_constants.VISIBILITY_ANONYMOUS) attr["is_home"] = page.is_home extenders = [] if page.navigation_extenders: if page.navigation_extenders in renderer.menus: extenders.append(page.navigation_extenders) elif "{0}:{1}".format(page.navigation_extenders, page.pk) in renderer.menus: extenders.append("{0}:{1}".format(page.navigation_extenders, page.pk)) if page.application_urls: app = apphook_pool.get_apphook(page.application_urls) if app: extenders += app.get_menus(page, language) exts = [] for ext in extenders: if hasattr(ext, "get_instances"): exts.append("{0}:{1}".format(ext.__name__, page.pk)) elif hasattr(ext, "__name__"): exts.append(ext.__name__) else: exts.append(ext) if exts: attr["navigation_extenders"] = exts attr["redirect_url"] = page_content.redirect return attr
def page_to_node(page, home, cut): parent_id = page.parent_id if home and page.parent_id == home.pk and cut: parent_id = None # possible fix for a possible problem #if parent_id and not page.parent.get_calculated_status(): # parent_id = None # ???? attr = {'soft_root':page.soft_root, 'auth_required':page.login_required, 'reverse_id':page.reverse_id,} if page.limit_visibility_in_menu == None: attr['visible_for_authenticated'] = True attr['visible_for_anonymous'] = True else: attr['visible_for_authenticated'] = page.limit_visibility_in_menu == 1 attr['visible_for_anonymous'] = page.limit_visibility_in_menu == 2 if page.pk == home.pk: attr['is_home'] = True # add various times and (maybe) excerpts attr['creation_date'] = page.creation_date attr['publication_date'] = page.publication_date attr['thumbnail'] = None # extracting excerpt... # XXX EXPENSIVE OPERATION!!! attr['excerpt'] = page.get_text_excerpt() extenders = [] if page.navigation_extenders: extenders.append(page.navigation_extenders) try: app_name = page.get_application_urls(fallback=False) except Title.DoesNotExist: app_name = None if app_name: app = apphook_pool.get_apphook(app_name) for menu in app.menus: extenders.append(menu.__name__) attr['redirect_url'] = page.get_redirect() # save redirect URL is any if extenders: attr['navigation_extenders'] = extenders ret_node = NavigationNode( page.get_menu_title(), page.get_absolute_url(), page.pk, parent_id, attr=attr, visible=page.in_navigation, ) return ret_node
def get_patterns_for_title(path, title): """ Resolve the urlconf module for a path+title combination Returns a list of url objects. """ app = apphook_pool.get_apphook(title.page.application_urls) url_patterns = [] for pattern_list in get_app_urls(app.get_urls(title.page, title.language)): if path and not path.endswith('/'): path += '/' page_id = title.page.id url_patterns += recurse_patterns(path, pattern_list, page_id) return url_patterns
def get_nodes(self, request): nodes = [] language = get_language_from_request(request, check_path=True) # don't bother with categories that don't have appconfig. categories = Category.objects.active_translations( language_code=language).exclude(appconfig__isnull=True).distinct() if hasattr(self, 'instance') and self.instance: # # If self has a property `instance` # then we're using django CMS 3.0.12 or later, # which supports using CMSAttachMenus on multiple, # apphook'ed pages, each with their own apphook configuration. So, # here we modify the queryset to reflect this. # app = apphook_pool.get_apphook(self.instance.application_urls) config = app.get_config(self.instance.application_namespace) if config: categories = categories.filter(appconfig=config) for category in categories: try: url = category.get_absolute_url(language=language) except NoReverseMatch: url = None if url: node = NavigationNode( category.safe_translation_getter( 'name', language_code=language), url, category.pk, ) nodes.append(node) for question in category.questions.all(): try: q_url = question.get_absolute_url(language=language) except NoReverseMatch: q_url = None if q_url: node = NavigationNode( question.safe_translation_getter( 'title', language_code=language), q_url, # NOTE: We're adding 1 million here to avoid # clashing with the category IDs. category.pk * 1000000 + question.pk, category.pk, ) nodes.append(node) return nodes
def get_nodes(self, request): nodes = [] language = get_language_from_request(request, check_path=True) # don't bother with categories that don't have appconfig. categories = Category.objects.active_translations( language_code=language).exclude(appconfig__isnull=True).distinct() if hasattr(self, 'instance') and self.instance: # # If self has a property `instance` # then we're using django CMS 3.0.12 or later, # which supports using CMSAttachMenus on multiple, # apphook'ed pages, each with their own apphook configuration. So, # here we modify the queryset to reflect this. # app = apphook_pool.get_apphook(self.instance.application_urls) config = app.get_config(self.instance.application_namespace) if config: categories = categories.filter(appconfig=config) for category in categories: try: url = category.get_absolute_url(language=language) except NoReverseMatch: url = None if url: node = NavigationNode( category.safe_translation_getter('name', language_code=language), url, category.pk, ) nodes.append(node) for question in category.questions.all(): try: q_url = question.get_absolute_url(language=language) except NoReverseMatch: q_url = None if q_url: node = NavigationNode( question.safe_translation_getter( 'title', language_code=language), q_url, # NOTE: We're adding 1 million here to avoid # clashing with the category IDs. category.pk * 1000000 + question.pk, category.pk, ) nodes.append(node) return nodes
def check_page(self, title, apphook=None, reverse_id=None, **kwargs): from cms.models.pagemodel import Page from cms.apphook_pool import apphook_pool page = Page.objects.public().filter(reverse_id=reverse_id).first() if not page: msg = "There should be a published CMS page with a reference ID: '{reverse_id}'." raise MissingPage(msg.format(reverse_id=reverse_id)) if apphook: if not page.application_urls or apphook_pool.get_apphook(page.application_urls) is not apphook: msg = "Page on URL '{url}' must be configured to use CMSApp inheriting from '{apphook}'." raise MissingAppHook(msg.format(url=page.get_absolute_url(), apphook=apphook.__class__)) return page
def modify(self, request, nodes, namespace, root_id, post_cut, breadcrumb): """ Actual modifier function :param request: request :param nodes: complete list of nodes :param namespace: Menu namespace :param root_id: eventual root_id :param post_cut: flag for modifier stage :param breadcrumb: flag for modifier stage :return: nodeslist """ app = None config = None if getattr(request, 'current_page', None) and request.current_page.application_urls: app = apphook_pool.get_apphook( request.current_page.application_urls) if app and app.app_config: namespace = resolve(request.path).namespace if not self._config.get(namespace, False): self._config[namespace] = app.get_config(namespace) config = self._config[namespace] try: if config and (not isinstance(config, BlogConfig) or config.menu_structure != MENU_TYPE_CATEGORIES): return nodes except AttributeError: # pragma: no cover # in case `menu_structure` is not present in config return nodes if post_cut: return nodes current_post = getattr(request, get_setting('CURRENT_POST_IDENTIFIER'), None) category = None if current_post and current_post.__class__ == Post: category = current_post.categories.first() if not category: return nodes for node in nodes: if '{0}-{1}'.format(category.__class__.__name__, category.pk) == node.id: node.selected = True return nodes
def get_patterns_for_title(path, title): """ Resolve the urlconf module for a path+title combination Returns a list of url objects. """ app = apphook_pool.get_apphook(title.application_urls) patterns = [] for urlconf_name in app.urls: mod = import_module(urlconf_name) if not hasattr(mod, 'urlpatterns'): raise ImproperlyConfigured("URLConf `%s` has no urlpatterns attribute" % urlconf_name) pattern_list = getattr(mod, 'urlpatterns') if not path.endswith('/'): path += '/' page_id = title.page.id patterns += recurse_patterns(path, pattern_list, page_id) return patterns
def page_to_node(page, home, cut): parent_id = page.parent_id if home and page.parent_id == home.pk and cut: parent_id = None # possible fix for a possible problem #if parent_id and not page.parent.get_calculated_status(): # parent_id = None # ???? attr = { 'soft_root': page.soft_root, 'auth_required': page.login_required, 'reverse_id': page.reverse_id, } if page.limit_visibility_in_menu == None: attr['visible_for_authenticated'] = True attr['visible_for_anonymous'] = True else: attr['visible_for_authenticated'] = page.limit_visibility_in_menu == 1 attr['visible_for_anonymous'] = page.limit_visibility_in_menu == 2 if page.pk == home.pk: attr['is_home'] = True extenders = [] if page.navigation_extenders: extenders.append(page.navigation_extenders) try: app_name = page.get_application_urls(fallback=False) except Title.DoesNotExist: app_name = None if app_name: app = apphook_pool.get_apphook(app_name) for menu in app.menus: extenders.append(menu.__name__) attr['redirect_url'] = page.get_redirect() # save redirect URL is any if extenders: attr['navigation_extenders'] = extenders ret_node = NavigationNode( page.get_menu_title(), page.get_absolute_url(), page.pk, parent_id, attr=attr, visible=page.in_navigation, ) return ret_node
def get_app_instance(request): """ Returns a tuple containing the current namespace and the AppHookConfig instance :param request: request object :return: namespace, config """ app = None if getattr(request, 'current_page', None) and request.current_page.application_urls: app = apphook_pool.get_apphook(request.current_page.application_urls) if app and app.app_config: try: config = None with override(get_language_from_request(request, check_path=True)): namespace = resolve(request.path_info).namespace config = app.get_config(namespace) return namespace, config except Resolver404: pass return '', None
def get_patterns_for_title(path, title): """ Resolve the urlconf module for a path+title combination Returns a list of url objects. """ app = apphook_pool.get_apphook(title.application_urls) patterns = [] for urlconf in app.urls: pattern_list = None if isinstance(urlconf, (str)): mod = import_module(urlconf) if not hasattr(mod, 'urlpatterns'): raise ImproperlyConfigured( "URLConf `%s` has no urlpatterns attribute" % urlconf) pattern_list = getattr(mod, 'urlpatterns') else: pattern_list = urlconf if not path.endswith('/'): path += '/' page_id = title.page.id patterns += recurse_patterns(path, pattern_list, page_id) patterns = _flatten_patterns(patterns) return patterns
def details(request, slug): """ The main view of the Django-CMS! Takes a request and a slug, renders the page. """ from django.core.cache import cache if get_cms_setting("PAGE_CACHE") and ( not hasattr(request, 'toolbar') or ( not request.toolbar.edit_mode and not request.toolbar.show_toolbar and not request.user.is_authenticated() ) ): cache_content = cache.get( _get_cache_key(request), version=_get_cache_version() ) if not cache_content is None: content, headers = cache_content response = HttpResponse(content) response._headers = headers return response # Get a Page model object from the request page = get_page_from_request(request, use_path=slug) if not page: return _handle_no_page(request, slug) current_language = request.REQUEST.get('language', None) if current_language: current_language = get_language_code(current_language) if not current_language in get_language_list(page.site_id): current_language = None if current_language is None: current_language = get_language_code(getattr(request, 'LANGUAGE_CODE', None)) if current_language: current_language = get_language_code(current_language) if not current_language in get_language_list(page.site_id): current_language = None if current_language is None: current_language = get_language_code(get_language()) # Check that the current page is available in the desired (current) language available_languages = [] page_languages = list(page.get_languages()) if hasattr(request, 'user') and request.user.is_staff: user_languages = get_language_list() else: user_languages = get_public_languages() for frontend_lang in user_languages: if frontend_lang in page_languages: available_languages.append(frontend_lang) # Check that the language is in FRONTEND_LANGUAGES: own_urls = [ 'http%s://%s%s' % ('s' if request.is_secure() else '', request.get_host(), request.path), '/%s' % request.path, request.path, ] if not current_language in user_languages: #are we on root? if not slug: #redirect to supported language languages = [] for language in available_languages: languages.append((language, language)) if languages: with SettingsOverride(LANGUAGES=languages, LANGUAGE_CODE=languages[0][0]): #get supported language new_language = get_language_from_request(request) if new_language in get_public_languages(): with force_language(new_language): pages_root = reverse('pages-root') if hasattr(request, 'toolbar') and request.user.is_staff and request.toolbar.edit_mode: request.toolbar.redirect_url = pages_root elif pages_root not in own_urls: return HttpResponseRedirect(pages_root) elif not hasattr(request, 'toolbar') or not request.toolbar.redirect_url: _handle_no_page(request, slug) else: return _handle_no_page(request, slug) if current_language not in available_languages: # If we didn't find the required page in the requested (current) # language, let's try to find a fallback found = False for alt_lang in get_fallback_languages(current_language): if alt_lang in available_languages: if get_redirect_on_fallback(current_language) or slug == "": with force_language(alt_lang): path = page.get_absolute_url(language=alt_lang, fallback=True) # In the case where the page is not available in the # preferred language, *redirect* to the fallback page. This # is a design decision (instead of rendering in place)). if hasattr(request, 'toolbar') and request.user.is_staff and request.toolbar.edit_mode: request.toolbar.redirect_url = path elif path not in own_urls: return HttpResponseRedirect(path) else: found = True if not found and (not hasattr(request, 'toolbar') or not request.toolbar.redirect_url): # There is a page object we can't find a proper language to render it _handle_no_page(request, slug) if apphook_pool.get_apphooks(): # There are apphooks in the pool. Let's see if there is one for the # current page # since we always have a page at this point, applications_page_check is # pointless # page = applications_page_check(request, page, slug) # Check for apphooks! This time for real! app_urls = page.get_application_urls(current_language, False) skip_app = False if not page.is_published(current_language) and hasattr(request, 'toolbar') and request.toolbar.edit_mode: skip_app = True if app_urls and not skip_app: app = apphook_pool.get_apphook(app_urls) pattern_list = [] for urlpatterns in get_app_urls(app.urls): pattern_list += urlpatterns urlpatterns = patterns('', *pattern_list) try: view, args, kwargs = resolve('/', tuple(urlpatterns)) return view(request, *args, **kwargs) except Resolver404: pass # Check if the page has a redirect url defined for this language. redirect_url = page.get_redirect(language=current_language) if redirect_url: if (is_language_prefix_patterns_used() and redirect_url[0] == "/" and not redirect_url.startswith( '/%s/' % current_language)): # add language prefix to url redirect_url = "/%s/%s" % (current_language, redirect_url.lstrip("/")) # prevent redirect to self if hasattr(request, 'toolbar') and request.user.is_staff and request.toolbar.edit_mode: request.toolbar.redirect_url = redirect_url elif redirect_url not in own_urls: return HttpResponseRedirect(redirect_url) # permission checks if page.login_required and not request.user.is_authenticated(): return redirect_to_login(urlquote(request.get_full_path()), settings.LOGIN_URL) if hasattr(request, 'toolbar'): request.toolbar.set_object(page) template_name = get_template_from_request(request, page, no_current_page=True) # fill the context context = RequestContext(request) context['lang'] = current_language context['current_page'] = page context['has_change_permissions'] = page.has_change_permission(request) context['has_view_permissions'] = page.has_view_permission(request) if not context['has_view_permissions']: return _handle_no_page(request, slug) response = TemplateResponse(request, template_name, context) response.add_post_render_callback(_cache_page) # Add headers for X Frame Options - this really should be changed upon moving to class based views xframe_options = page.get_xframe_options() if xframe_options == Page.X_FRAME_OPTIONS_INHERIT: # This is when we defer to django's own clickjacking handling return response # We want to prevent django setting this in their middlewear response.xframe_options_exempt = True if xframe_options == Page.X_FRAME_OPTIONS_ALLOW: # Do nothing, allowed is no header. return response elif xframe_options == Page.X_FRAME_OPTIONS_SAMEORIGIN: response['X-Frame-Options'] = 'SAMEORIGIN' elif xframe_options == Page.X_FRAME_OPTIONS_DENY: response['X-Frame-Options'] = 'DENY' return response
def test_config_str(self): app = apphook_pool.get_apphook(self.page_1.application_urls) self.assertEqual('%s / %s' % (force_text(app.name), self.ns_app_1.namespace), force_text(self.ns_app_1))
def page_to_node(page, home, cut): """ Transform a CMS page into a navigation node. :param page: the page you wish to transform :param home: a reference to the "home" page (the page with path="0001) :param cut: Should we cut page from its parent pages? This means the node will not have a parent anymore. """ # Theses are simple to port over, since they are not calculated. # Other attributes will be added conditionnally later. attr = {'soft_root': page.soft_root, 'auth_required': page.login_required, 'reverse_id': page.reverse_id, } parent_id = page.parent_id # Should we cut the Node from its parents? if home and page.parent_id == home.pk and cut: parent_id = None # possible fix for a possible problem # if parent_id and not page.parent.get_calculated_status(): # parent_id = None # ???? if page.limit_visibility_in_menu is constants.VISIBILITY_ALL: attr['visible_for_authenticated'] = True attr['visible_for_anonymous'] = True else: attr['visible_for_authenticated'] = page.limit_visibility_in_menu == constants.VISIBILITY_USERS attr['visible_for_anonymous'] = page.limit_visibility_in_menu == constants.VISIBILITY_ANONYMOUS attr['is_home'] = page.is_home # Extenders can be either navigation extenders or from apphooks. extenders = [] if page.navigation_extenders: extenders.append(page.navigation_extenders) # Is this page an apphook? If so, we need to handle the apphooks's nodes lang = get_language() # Only run this if we have a translation in the requested language for this # object. The title cache should have been prepopulated in CMSMenu.get_nodes # but otherwise, just request the title normally if not hasattr(page, 'title_cache') or lang in page.title_cache: app_name = page.get_application_urls(fallback=False) if app_name: # it means it is an apphook app = apphook_pool.get_apphook(app_name) extenders += app.menus exts = [] for ext in extenders: if hasattr(ext, "get_instances"): # CMSAttachMenus are treated a bit differently to allow them to be # able to be attached to multiple points in the navigation. exts.append("{0}:{1}".format(ext.__name__, page.pk)) elif hasattr(ext, '__name__'): exts.append(ext.__name__) else: exts.append(ext) if exts: attr['navigation_extenders'] = exts # Do we have a redirectURL? attr['redirect_url'] = page.get_redirect() # save redirect URL if any # Now finally, build the NavigationNode object and return it. ret_node = NavigationNode( page.get_menu_title(), page.get_absolute_url(), page.pk, parent_id, attr=attr, visible=page.in_navigation, ) return ret_node
def test_configs(self): app = apphook_pool.get_apphook(self.page_1.application_urls) self.assertEqual(app.get_configs().count(), 2)
def test_wrong_ns(self): app = apphook_pool.get_apphook(self.page_1.application_urls) self.assertIsNone(app.get_config('no_app'))
def details(request, slug): """ The main view of the Django-CMS! Takes a request and a slug, renders the page. """ # get the right model context = RequestContext(request) # Get a Page model object from the request page = get_page_from_request(request, use_path=slug) if not page: return _handle_no_page(request, slug) current_language = get_language_from_request(request) # Check that the current page is available in the desired (current) language available_languages = page.get_languages() # We resolve an alternate language for the page if it's not available. # Since the "old" details view had an exception for the root page, it is # ported here. So no resolution if the slug is ''. if (current_language not in available_languages) and (slug != ''): if settings.CMS_LANGUAGE_FALLBACK: # If we didn't find the required page in the requested (current) # language, let's try to find a suitable fallback in the list of # fallback languages (CMS_LANGUAGE_CONF) for alt_lang in get_fallback_languages(current_language): if alt_lang in available_languages: alt_url = page.get_absolute_url(language=alt_lang, fallback=True) path = '/%s%s' % (alt_lang, alt_url) # In the case where the page is not available in the # preferred language, *redirect* to the fallback page. This # is a design decision (instead of rendering in place)). return HttpResponseRedirect(path) # There is a page object we can't find a proper language to render it _handle_no_page(request, slug) if apphook_pool.get_apphooks(): # There are apphooks in the pool. Let's see if there is one for the # current page # since we always have a page at this point, applications_page_check is # pointless # page = applications_page_check(request, page, slug) # Check for apphooks! This time for real! app_urls = page.get_application_urls(current_language, False) if app_urls: app = apphook_pool.get_apphook(app_urls) pattern_list = [] for urlpatterns in get_app_urls(app.urls): pattern_list += urlpatterns urlpatterns = patterns('', *pattern_list) try: view, args, kwargs = resolve('/', tuple(urlpatterns)) return view(request, *args, **kwargs) except Resolver404: pass # Check if the page has a redirect url defined for this language. redirect_url = page.get_redirect(language=current_language) if redirect_url: if settings.i18n_installed and redirect_url[0] == "/": redirect_url = "/%s/%s" % (current_language, redirect_url.lstrip("/")) # add language prefix to url return HttpResponseRedirect(redirect_url) # permission checks if page.login_required and not request.user.is_authenticated(): if settings.i18n_installed: path = urlquote("/%s%s" % (request.LANGUAGE_CODE, request.get_full_path())) else: path = urlquote(request.get_full_path()) tup = django_settings.LOGIN_URL , "next", path return HttpResponseRedirect('%s?%s=%s' % tup) if page.login_required and not page.has_view_permission(request): return HttpResponseForbidden("You don't have the rights to access this resource") template_name = get_template_from_request(request, page, no_current_page=True) # fill the context context['lang'] = current_language context['current_page'] = page context['has_change_permissions'] = page.has_change_permission(request) return render_to_response(template_name, context)
def details(request, slug): """ The main view of the Django-CMS! Takes a request and a slug, renders the page. """ response_timestamp = now() if get_cms_setting("PAGE_CACHE") and ( not hasattr(request, 'toolbar') or (not request.toolbar.edit_mode and not request.toolbar.show_toolbar and not request.user.is_authenticated())): cache_content = get_page_cache(request) if cache_content is not None: content, headers, expires_datetime = cache_content response = HttpResponse(content) response._headers = headers # Recalculate the max-age header for this cached response max_age = int((expires_datetime - response_timestamp).total_seconds() + 0.5) patch_cache_control(response, max_age=max_age) return response # Get a Page model object from the request page = get_page_from_request(request, use_path=slug) if not page: return _handle_no_page(request, slug) current_language = request.GET.get('language', None) if not current_language: current_language = request.POST.get('language', None) if current_language: current_language = get_language_code(current_language) if current_language not in get_language_list(page.site_id): current_language = None if current_language is None: current_language = get_language_code( getattr(request, 'LANGUAGE_CODE', None)) if current_language: current_language = get_language_code(current_language) if current_language not in get_language_list(page.site_id): current_language = None if current_language is None: current_language = get_language_code(get_language()) # Check that the current page is available in the desired (current) language available_languages = [] # this will return all languages in draft mode, and published only in live mode page_languages = list(page.get_published_languages()) if hasattr(request, 'user') and request.user.is_staff: user_languages = get_language_list() else: user_languages = get_public_languages() for frontend_lang in user_languages: if frontend_lang in page_languages: available_languages.append(frontend_lang) # Check that the language is in FRONTEND_LANGUAGES: own_urls = [ 'http%s://%s%s' % ('s' if request.is_secure() else '', request.get_host(), request.path), '/%s' % request.path, request.path, ] if current_language not in user_languages: #are we on root? if not slug: #redirect to supported language languages = [] for language in available_languages: languages.append((language, language)) if languages: # get supported language new_language = get_language_from_request(request) if new_language in get_public_languages(): with force_language(new_language): pages_root = reverse('pages-root') if (hasattr(request, 'toolbar') and request.user.is_staff and request.toolbar.edit_mode): request.toolbar.redirect_url = pages_root elif pages_root not in own_urls: return HttpResponseRedirect(pages_root) elif not hasattr(request, 'toolbar') or not request.toolbar.redirect_url: _handle_no_page(request, slug) else: return _handle_no_page(request, slug) if current_language not in available_languages: # If we didn't find the required page in the requested (current) # language, let's try to find a fallback found = False for alt_lang in get_fallback_languages(current_language): if alt_lang in available_languages: if get_redirect_on_fallback(current_language) or slug == "": with force_language(alt_lang): path = page.get_absolute_url(language=alt_lang, fallback=True) # In the case where the page is not available in the # preferred language, *redirect* to the fallback page. This # is a design decision (instead of rendering in place)). if (hasattr(request, 'toolbar') and request.user.is_staff and request.toolbar.edit_mode): request.toolbar.redirect_url = path elif path not in own_urls: return HttpResponseRedirect(path) else: found = True if not found and (not hasattr(request, 'toolbar') or not request.toolbar.redirect_url): # There is a page object we can't find a proper language to render it _handle_no_page(request, slug) else: page_path = page.get_absolute_url(language=current_language) page_slug = page.get_path(language=current_language) or page.get_slug( language=current_language) if slug and slug != page_slug and request.path[:len(page_path )] != page_path: # The current language does not match it's slug. # Redirect to the current language. if hasattr( request, 'toolbar' ) and request.user.is_staff and request.toolbar.edit_mode: request.toolbar.redirect_url = page_path else: return HttpResponseRedirect(page_path) if apphook_pool.get_apphooks(): # There are apphooks in the pool. Let's see if there is one for the # current page # since we always have a page at this point, applications_page_check is # pointless # page = applications_page_check(request, page, slug) # Check for apphooks! This time for real! app_urls = page.get_application_urls(current_language, False) skip_app = False if (not page.is_published(current_language) and hasattr(request, 'toolbar') and request.toolbar.edit_mode): skip_app = True if app_urls and not skip_app: app = apphook_pool.get_apphook(app_urls) pattern_list = [] if app: for urlpatterns in get_app_urls( app.get_urls(page, current_language)): pattern_list += urlpatterns try: view, args, kwargs = resolve('/', tuple(pattern_list)) return view(request, *args, **kwargs) except Resolver404: pass # Check if the page has a redirect url defined for this language. redirect_url = page.get_redirect(language=current_language) if redirect_url: if (is_language_prefix_patterns_used() and redirect_url[0] == "/" and not redirect_url.startswith('/%s/' % current_language)): # add language prefix to url redirect_url = "/%s/%s" % (current_language, redirect_url.lstrip("/")) # prevent redirect to self if hasattr(request, 'toolbar' ) and request.user.is_staff and request.toolbar.edit_mode: request.toolbar.redirect_url = redirect_url elif redirect_url not in own_urls: return HttpResponseRedirect(redirect_url) # permission checks if page.login_required and not request.user.is_authenticated(): return redirect_to_login(urlquote(request.get_full_path()), settings.LOGIN_URL) if hasattr(request, 'toolbar'): request.toolbar.set_object(page) response = render_page(request, page, current_language=current_language, slug=slug) return response
def _get_app_patterns(): """ Get a list of patterns for all hooked apps. How this works: By looking through all titles with an app hook (application_urls) we find all urlconf modules we have to hook into titles. If we use the ML URL Middleware, we namespace those patterns with the title language. All 'normal' patterns from the urlconf get re-written by prefixing them with the title path and then included into the cms url patterns. If the app is still configured, but is no longer installed/available, then this method returns a degenerate patterns object: patterns('') """ from cms.models import Title try: current_site = Site.objects.get_current() except Site.DoesNotExist: current_site = None included = [] # we don't have a request here so get_page_queryset() can't be used, # so use public() queryset. # This can be done because url patterns are used just in frontend title_qs = Title.objects.public().filter(page__site=current_site) hooked_applications = OrderedDict() # Loop over all titles with an application hooked to them titles = (title_qs.exclude(page__application_urls=None) .exclude(page__application_urls='') .order_by('-page__path').select_related()) # TODO: Need to be fixed for django-treebeard when forward ported to 3.1 for title in titles: path = title.path mix_id = "%s:%s:%s" % ( path + "/", title.page.application_urls, title.language) if mix_id in included: # don't add the same thing twice continue if not settings.APPEND_SLASH: path += '/' app = apphook_pool.get_apphook(title.page.application_urls) if not app: continue if title.page_id not in hooked_applications: hooked_applications[title.page_id] = {} app_ns = app.app_name, title.page.application_namespace with override(title.language): hooked_applications[title.page_id][title.language] = ( app_ns, get_patterns_for_title(path, title), app) included.append(mix_id) # Build the app patterns to be included in the cms urlconfs app_patterns = [] for page_id in hooked_applications.keys(): resolver = None for lang in hooked_applications[page_id].keys(): (app_ns, inst_ns), current_patterns, app = hooked_applications[page_id][lang] # nopyflakes if not resolver: resolver = AppRegexURLResolver( r'', 'app_resolver', app_name=app_ns, namespace=inst_ns) resolver.page_id = page_id if app.permissions: _set_permissions(current_patterns, app.exclude_permissions) resolver.url_patterns_dict[lang] = current_patterns app_patterns.append(resolver) APP_RESOLVERS.append(resolver) return app_patterns
def page_to_node(page, home, cut): """ Transform a CMS page into a navigation node. :param page: the page you wish to transform :param home: a reference to the "home" page (the page with tree_id=1) :param cut: Should we cut page from its parent pages? This means the node will not have a parent anymore. """ # Theses are simple to port over, since they are not calculated. # Other attributes will be added conditionnally later. attr = {'soft_root': page.soft_root, 'auth_required': page.login_required, 'reverse_id': page.reverse_id, } parent_id = page.parent_id # Should we cut the Node from its parents? if home and page.parent_id == home.pk and cut: parent_id = None # possible fix for a possible problem #if parent_id and not page.parent.get_calculated_status(): # parent_id = None # ???? if page.limit_visibility_in_menu == None: attr['visible_for_authenticated'] = True attr['visible_for_anonymous'] = True else: attr['visible_for_authenticated'] = page.limit_visibility_in_menu == 1 attr['visible_for_anonymous'] = page.limit_visibility_in_menu == 2 if page.pk == home.pk: attr['is_home'] = True # Extenders can be either navigation extenders or from apphooks. extenders = [] if page.navigation_extenders: extenders.append(page.navigation_extenders) # Is this page an apphook? If so, we need to handle the apphooks's nodes lang = get_language() # Only run this if we have a translation in the requested language for this # object. The title cache should have been prepopulated in CMSMenu.get_nodes # but otherwise, just request the title normally if not hasattr(page, 'title_cache') or lang in page.title_cache: try: app_name = page.get_application_urls(fallback=False) except Title.DoesNotExist: app_name = None if app_name: # it means it is an apphook app = apphook_pool.get_apphook(app_name) for menu in app.menus: extenders.append(menu.__name__) if extenders: attr['navigation_extenders'] = extenders # Do we have a redirectURL? attr['redirect_url'] = page.get_redirect() # save redirect URL if any # Now finally, build the NavigationNode object and return it. # Fixed by kisele _lang = lang.split("-")[0] ## ret_node = NavigationNode( page.get_menu_title(_lang), page.get_absolute_url(_lang), page.pk, parent_id, attr=attr, visible=page.in_navigation, ) return ret_node
def _get_app_patterns(site): """ Get a list of patterns for all hooked apps. How this works: By looking through all titles with an app hook (application_urls) we find all urlconf modules we have to hook into titles. If we use the ML URL Middleware, we namespace those patterns with the title language. All 'normal' patterns from the urlconf get re-written by prefixing them with the title path and then included into the cms url patterns. If the app is still configured, but is no longer installed/available, then this method returns a degenerate patterns object: patterns('') """ from cms.models import Title included = [] # we don't have a request here so get_page_queryset() can't be used, # so use public() queryset. # This can be done because url patterns are used just in frontend title_qs = Title.objects.public().filter(page__node__site=site) hooked_applications = OrderedDict() # Loop over all titles with an application hooked to them titles = (title_qs.exclude(page__application_urls=None) .exclude(page__application_urls='') .order_by('-page__node__path').select_related()) # TODO: Need to be fixed for django-treebeard when forward ported to 3.1 for title in titles: path = title.path mix_id = "%s:%s:%s" % ( path + "/", title.page.application_urls, title.language) if mix_id in included: # don't add the same thing twice continue if not settings.APPEND_SLASH: path += '/' app = apphook_pool.get_apphook(title.page.application_urls) if not app: continue if title.page_id not in hooked_applications: hooked_applications[title.page_id] = {} app_ns = app.app_name, title.page.application_namespace with override(title.language): hooked_applications[title.page_id][title.language] = ( app_ns, get_patterns_for_title(path, title), app) included.append(mix_id) # Build the app patterns to be included in the cms urlconfs app_patterns = [] for page_id in hooked_applications.keys(): resolver = None for lang in hooked_applications[page_id].keys(): (app_ns, inst_ns), current_patterns, app = hooked_applications[page_id][lang] # nopyflakes if not resolver: regex_pattern = RegexPattern(r'') if not DJANGO_1_11 else r'' resolver = AppRegexURLResolver( regex_pattern, 'app_resolver', app_name=app_ns, namespace=inst_ns) resolver.page_id = page_id if app.permissions: _set_permissions(current_patterns, app.exclude_permissions) resolver.url_patterns_dict[lang] = current_patterns app_patterns.append(resolver) APP_RESOLVERS.append(resolver) return app_patterns
def __init__(self, *args, **kwargs): super(AdvancedSettingsForm, self).__init__(*args, **kwargs) self.fields['language'].widget = HiddenInput() self.fields['site'].widget = HiddenInput() site_id = self.fields['site'].initial languages = get_language_tuple(site_id) self.fields['language'].choices = languages if not self.fields['language'].initial: self.fields['language'].initial = get_language() if 'navigation_extenders' in self.fields: navigation_extenders = self.get_navigation_extenders() self.fields['navigation_extenders'].widget = forms.Select( {}, [('', "---------")] + navigation_extenders) if 'application_urls' in self.fields: # Prepare a dict mapping the apps by class name ('PollApp') to # their app_name attribute ('polls'), if any. app_namespaces = {} app_configs = {} for hook in apphook_pool.get_apphooks(): app = apphook_pool.get_apphook(hook[0]) if app.app_name: app_namespaces[hook[0]] = app.app_name if app.app_config: app_configs[hook[0]] = app self.fields['application_urls'].widget = AppHookSelect( attrs={'id': 'application_urls'}, app_namespaces=app_namespaces) self.fields['application_urls'].choices = [ ('', "---------") ] + apphook_pool.get_apphooks() page_data = self.data if self.data else self.initial if app_configs: self.fields[ 'application_configs'].widget = ApplicationConfigSelect( attrs={'id': 'application_configs'}, app_configs=app_configs) if page_data.get( 'application_urls', False ) and page_data['application_urls'] in app_configs: self.fields['application_configs'].choices = [ (config.pk, force_text(config)) for config in app_configs[ page_data['application_urls']].get_configs() ] apphook = page_data.get('application_urls', False) try: config = apphook_pool.get_apphook(apphook).get_configs( ).get(namespace=self.initial['application_namespace']) self.fields['application_configs'].initial = config.pk except ObjectDoesNotExist: # Provided apphook configuration doesn't exist (anymore), # just skip it # The user will choose another value anyway pass else: # If app_config apphook is not selected, drop any value # for application_configs to avoid the field data from # being validated by the field itself try: del self.data['application_configs'] except KeyError: pass if 'redirect' in self.fields: self.fields['redirect'].widget.language = self.fields[ 'language'].initial
def clean(self): cleaned_data = super(AdvancedSettingsForm, self).clean() if self._errors: # Fail fast if there's errors in the form return cleaned_data # Language has been validated already # so we know it exists. language_name = get_language_object( self._language, site_id=self._site.pk, )['name'] if not self.title_obj.slug: # This covers all cases where users try to edit # page advanced settings without setting a title slug # for page titles that already exist. message = _("Please set the %(language)s slug " "before editing its advanced settings.") raise ValidationError(message % {'language': language_name}) if 'reverse_id' in self.fields: reverse_id = cleaned_data['reverse_id'] if reverse_id: lookup = Page.objects.drafts().on_site( self._site).filter(reverse_id=reverse_id) if lookup.exclude(pk=self.instance.pk).exists(): self._errors['reverse_id'] = self.error_class( [_('A page with this reverse URL id exists already.')]) apphook = cleaned_data.get('application_urls', None) # The field 'application_namespace' is a misnomer. It should be # 'instance_namespace'. instance_namespace = cleaned_data.get('application_namespace', None) application_config = cleaned_data.get('application_configs', None) if apphook: apphooks_with_config = self.get_apphooks_with_config() # application_config wins over application_namespace if apphook in apphooks_with_config and application_config: # the value of the application config namespace is saved in # the 'usual' namespace field to be backward compatible # with existing apphooks try: appconfig_pk = forms.IntegerField( required=True).to_python(application_config) except ValidationError: self._errors['application_configs'] = ErrorList( [_('Invalid application config value')]) return self.cleaned_data try: config = apphooks_with_config[apphook].get_configs().get( pk=appconfig_pk) except ObjectDoesNotExist: self._errors['application_configs'] = ErrorList( [_('Invalid application config value')]) return self.cleaned_data if self._check_unique_namespace_instance(config.namespace): # Looks like there's already one with the default instance # namespace defined. self._errors['application_configs'] = ErrorList([ _('An application instance using this configuration already exists.' ) ]) else: self.cleaned_data[ 'application_namespace'] = config.namespace else: if instance_namespace: if self._check_unique_namespace_instance( instance_namespace): self._errors['application_namespace'] = ErrorList([ _('An application instance with this name already exists.' ) ]) else: # The attribute on the apps 'app_name' is a misnomer, it should be # 'application_namespace'. application_namespace = apphook_pool.get_apphook( apphook).app_name if application_namespace and not instance_namespace: if self._check_unique_namespace_instance( application_namespace): # Looks like there's already one with the default instance # namespace defined. self._errors['application_namespace'] = ErrorList([ _('An application instance with this name already exists.' ) ]) else: # OK, there are zero instances of THIS app that use the # default instance namespace, so, since the user didn't # provide one, we'll use the default. NOTE: The following # line is really setting the "instance namespace" of the # new app to the app’s "application namespace", which is # the default instance namespace. self.cleaned_data[ 'application_namespace'] = application_namespace if instance_namespace and not apphook: self.cleaned_data['application_namespace'] = None if application_config and not apphook: self.cleaned_data['application_configs'] = None return self.cleaned_data
def get_apphooks(self): for hook in apphook_pool.get_apphooks(): yield (hook[0], apphook_pool.get_apphook(hook[0]))
def clean(self): cleaned_data = super(AdvancedSettingsForm, self).clean() if self._errors: # Fail fast if there's errors in the form return cleaned_data language = cleaned_data['language'] # Language has been validated already # so we know it exists. language_name = get_language_object( language, site_id=cleaned_data['site'].pk)['name'] try: title = self.instance.title_set.get(language=language) except Title.DoesNotExist: # This covers all cases where users try to edit # page advanced settings without creating the page title. message = _("Please create the %(language)s page " "translation before editing its advanced settings.") raise ValidationError(message % {'language': language_name}) if not title.slug: # This covers all cases where users try to edit # page advanced settings without setting a title slug # for page titles that already exist. message = _("Please set the %(language)s slug " "before editing its advanced settings.") raise ValidationError(message % {'language': language_name}) if 'reverse_id' in self.fields: id = cleaned_data['reverse_id'] site_id = cleaned_data['site'] if id: if Page.objects.filter(reverse_id=id, site=site_id, publisher_is_draft=True).exclude( pk=self.instance.pk).exists(): self._errors['reverse_id'] = self.error_class( [_('A page with this reverse URL id exists already.')]) apphook = cleaned_data.get('application_urls', None) # The field 'application_namespace' is a misnomer. It should be # 'instance_namespace'. instance_namespace = cleaned_data.get('application_namespace', None) application_config = cleaned_data.get('application_configs', None) if apphook: # application_config wins over application_namespace if application_config: # the value of the application config namespace is saved in # the 'usual' namespace field to be backward compatible # with existing apphooks config = apphook_pool.get_apphook(apphook).get_configs().get( pk=int(application_config)) if self._check_unique_namespace_instance(config.namespace): # Looks like there's already one with the default instance # namespace defined. self._errors['application_configs'] = ErrorList([ _('An application instance using this configuration already exists.' ) ]) else: self.cleaned_data[ 'application_namespace'] = config.namespace else: if instance_namespace: if self._check_unique_namespace_instance( instance_namespace): self._errors['application_namespace'] = ErrorList([ _('An application instance with this name already exists.' ) ]) else: # The attribute on the apps 'app_name' is a misnomer, it should be # 'application_namespace'. application_namespace = apphook_pool.get_apphook( apphook).app_name if application_namespace and not instance_namespace: if self._check_unique_namespace_instance( application_namespace): # Looks like there's already one with the default instance # namespace defined. self._errors['application_namespace'] = ErrorList([ _('An application instance with this name already exists.' ) ]) else: # OK, there are zero instances of THIS app that use the # default instance namespace, so, since the user didn't # provide one, we'll use the default. NOTE: The following # line is really setting the "instance namespace" of the # new app to the app’s "application namespace", which is # the default instance namespace. self.cleaned_data[ 'application_namespace'] = application_namespace if instance_namespace and not apphook: self.cleaned_data['application_namespace'] = None if application_config and not apphook: self.cleaned_data['application_configs'] = None return self.cleaned_data
def clean(self): cleaned_data = super(AdvancedSettingsForm, self).clean() language = cleaned_data.get('language') if not language: # Fail fast if no language is provided return cleaned_data # Language has been validated already # so we know it exists. language_name = get_language_object( language, site_id=cleaned_data['site'].pk )['name'] try: title = self.instance.title_set.get(language=language) except Title.DoesNotExist: # This covers all cases where users try to edit # page advanced settings without creating the page title. message = _("Please create the %(language)s page " "translation before editing its advanced settings.") raise ValidationError(message % {'language': language_name}) if not title.slug: # This covers all cases where users try to edit # page advanced settings without setting a title slug # for page titles that already exist. message = _("Please set the %(language)s slug " "before editing its advanced settings.") raise ValidationError(message % {'language': language_name}) if 'reverse_id' in self.fields: id = cleaned_data['reverse_id'] site_id = cleaned_data['site'] if id: if Page.objects.filter(reverse_id=id, site=site_id, publisher_is_draft=True).exclude( pk=self.instance.pk).count(): self._errors['reverse_id'] = self.error_class( [_('A page with this reverse URL id exists already.')]) apphook = cleaned_data.get('application_urls', None) # The field 'application_namespace' is a misnomer. It should be # 'instance_namespace'. instance_namespace = cleaned_data.get('application_namespace', None) application_config = cleaned_data.get('application_configs', None) if apphook: # application_config wins over application_namespace if application_config: # the value of the application config namespace is saved in # the 'usual' namespace field to be backward compatible # with existing apphooks config = apphook_pool.get_apphook(apphook).get_configs().get(pk=int(application_config)) if self._check_unique_namespace_instance(config.namespace): # Looks like there's already one with the default instance # namespace defined. self._errors['application_configs'] = ErrorList([ _('An application instance using this configuration already exists.') ]) else: self.cleaned_data['application_namespace'] = config.namespace else: if instance_namespace: if self._check_unique_namespace_instance(instance_namespace): self._errors['application_namespace'] = ErrorList([ _('An application instance with this name already exists.') ]) else: # The attribute on the apps 'app_name' is a misnomer, it should be # 'application_namespace'. application_namespace = apphook_pool.get_apphook(apphook).app_name if application_namespace and not instance_namespace: if self._check_unique_namespace_instance(application_namespace): # Looks like there's already one with the default instance # namespace defined. self._errors['application_namespace'] = ErrorList([ _('An application instance with this name already exists.') ]) else: # OK, there are zero instances of THIS app that use the # default instance namespace, so, since the user didn't # provide one, we'll use the default. NOTE: The following # line is really setting the "instance namespace" of the # new app to the app’s "application namespace", which is # the default instance namespace. self.cleaned_data['application_namespace'] = application_namespace if instance_namespace and not apphook: self.cleaned_data['application_namespace'] = None if application_config and not apphook: self.cleaned_data['application_configs'] = None return self.cleaned_data
def details(request, slug): """ The main view of the Django-CMS! Takes a request and a slug, renders the page. """ from cms.apphook_pool import apphook_pool from cms.appresolver import get_app_urls from cms.utils import get_template_from_request, get_language_from_request from cms.utils.i18n import get_fallback_languages from cms.utils.django_load import load_object from cms.utils.page_resolver import get_page_from_request from cms.views import _handle_no_page from django.conf import settings from django.conf.urls import patterns from django.core.urlresolvers import resolve, Resolver404 from django.http import Http404, HttpResponseRedirect from django.shortcuts import render_to_response from django.template.context import RequestContext from django.utils.http import urlquote # get the right model context = RequestContext(request) # Get a Page model object from the request page = get_page_from_request(request, use_path=slug) if not page: return _handle_no_page(request, slug) current_language = get_language_from_request(request) # Check that the current page is available in the desired (current) language available_languages = page.get_languages() # We resolve an alternate language for the page if it's not available. # Since the "old" details view had an exception for the root page, it is # ported here. So no resolution if the slug is ''. if (current_language not in available_languages): if settings.CMS_LANGUAGE_FALLBACK: # If we didn't find the required page in the requested (current) # language, let's try to find a suitable fallback in the list of # fallback languages (CMS_LANGUAGE_CONF) for alt_lang in get_fallback_languages(current_language): if alt_lang in available_languages: alt_url = page.get_absolute_url(language=alt_lang, fallback=True) path = '/%s%s' % (alt_lang, alt_url) # In the case where the page is not available in the # preferred language, *redirect* to the fallback page. This # is a design decision (instead of rendering in place)). return HttpResponseRedirect(path) # There is a page object we can't find a proper language to render it _handle_no_page(request, slug) if apphook_pool.get_apphooks(): # There are apphooks in the pool. Let's see if there is one for the # current page # since we always have a page at this point, applications_page_check is # pointless # page = applications_page_check(request, page, slug) # Check for apphooks! This time for real! app_urls = page.get_application_urls(current_language, False) if app_urls: app = apphook_pool.get_apphook(app_urls) pattern_list = [] for urlpatterns in get_app_urls(app.urls): pattern_list += urlpatterns urlpatterns = patterns('', *pattern_list) try: view, args, kwargs = resolve('/', tuple(urlpatterns)) return view(request, *args, **kwargs) except Resolver404: pass if page.view_path: view = load_object(page.view_path) args, kwargs = view.extract_args_kwargs(slug) return view(request, *args, **kwargs) # Check if the page has a redirect url defined for this language. redirect_url = page.get_redirect(language=current_language) if redirect_url: if (settings.i18n_installed and redirect_url[0] == "/" and not redirect_url.startswith('/%s/' % current_language)): # add language prefix to url redirect_url = "/%s/%s" % (current_language, redirect_url.lstrip("/")) # prevent redirect to self own_urls = [ 'http%s://%s%s' % ('s' if request.is_secure() else '', request.get_host(), request.path), '/%s%s' % (current_language, request.path), request.path, ] if redirect_url not in own_urls: return HttpResponseRedirect(redirect_url) # permission checks if page.login_required and not request.user.is_authenticated(): if settings.i18n_installed: path = urlquote("/%s%s" % (request.LANGUAGE_CODE, request.get_full_path())) else: path = urlquote(request.get_full_path()) tup = settings.LOGIN_URL , "next", path return HttpResponseRedirect('%s?%s=%s' % tup) template_name = get_template_from_request(request, page, no_current_page=True) # fill the context context['lang'] = current_language context['current_page'] = page context['has_change_permissions'] = page.has_change_permission(request) context['has_view_permissions'] = page.has_view_permission(request) if not context['has_view_permissions']: return _handle_no_page(request, slug) return render_to_response(template_name, context)
def details(request, slug): """ The main view of the Django-CMS! Takes a request and a slug, renders the page. """ # get the right model context = RequestContext(request) # Get a Page model object from the request page = get_page_from_request(request, use_path=slug) if not page: return _handle_no_page(request, slug) current_language = get_language_from_request(request) # Check that the current page is available in the desired (current) language available_languages = [] page_languages = list(page.get_languages()) if hasattr(request, 'user') and request.user.is_staff: user_languages = get_language_list() else: user_languages = get_public_languages() for frontend_lang in user_languages: if frontend_lang in page_languages: available_languages.append(frontend_lang) attrs = '' if 'edit' in request.GET: attrs = '?edit=1' elif 'preview' in request.GET: attrs = '?preview=1' if 'draft' in request.GET: attrs += '&draft=1' # Check that the language is in FRONTEND_LANGUAGES: if not current_language in user_languages: #are we on root? if not slug: #redirect to supported language languages = [] for language in available_languages: languages.append((language, language)) if languages: with SettingsOverride(LANGUAGES=languages, LANGUAGE_CODE=languages[0][0]): #get supported language new_language = get_language_from_request(request) if new_language in get_public_languages(): with force_language(new_language): pages_root = reverse('pages-root') return HttpResponseRedirect(pages_root + attrs) else: _handle_no_page(request, slug) else: return _handle_no_page(request, slug) if current_language not in available_languages: # If we didn't find the required page in the requested (current) # language, let's try to find a fallback found = False for alt_lang in get_fallback_languages(current_language): if alt_lang in available_languages: if get_redirect_on_fallback(current_language): with force_language(alt_lang): path = page.get_absolute_url(language=alt_lang, fallback=True) # In the case where the page is not available in the # preferred language, *redirect* to the fallback page. This # is a design decision (instead of rendering in place)). return HttpResponseRedirect(path + attrs) else: found = True if not found: # There is a page object we can't find a proper language to render it _handle_no_page(request, slug) if apphook_pool.get_apphooks(): # There are apphooks in the pool. Let's see if there is one for the # current page # since we always have a page at this point, applications_page_check is # pointless # page = applications_page_check(request, page, slug) # Check for apphooks! This time for real! try: app_urls = page.get_application_urls(current_language, False) except Title.DoesNotExist: app_urls = [] if app_urls: app = apphook_pool.get_apphook(app_urls) pattern_list = [] for urlpatterns in get_app_urls(app.urls): pattern_list += urlpatterns urlpatterns = patterns('', *pattern_list) try: view, args, kwargs = resolve('/', tuple(urlpatterns)) return view(request, *args, **kwargs) except Resolver404: pass # Check if the page has a redirect url defined for this language. redirect_url = page.get_redirect(language=current_language) if redirect_url: if (is_language_prefix_patterns_used() and redirect_url[0] == "/" and not redirect_url.startswith('/%s/' % current_language)): # add language prefix to url redirect_url = "/%s/%s" % (current_language, redirect_url.lstrip("/")) # prevent redirect to self own_urls = [ 'http%s://%s%s' % ('s' if request.is_secure() else '', request.get_host(), request.path), '/%s' % request.path, request.path, ] if redirect_url not in own_urls: return HttpResponseRedirect(redirect_url + attrs) # permission checks if page.login_required and not request.user.is_authenticated(): return redirect_to_login(urlquote(request.get_full_path()), settings.LOGIN_URL) template_name = get_template_from_request(request, page, no_current_page=True) # fill the context context['lang'] = current_language context['current_page'] = page context['has_change_permissions'] = page.has_change_permission(request) context['has_view_permissions'] = page.has_view_permission(request) if not context['has_view_permissions']: return _handle_no_page(request, slug) return TemplateResponse(request, template_name, context)
def get_app_patterns(): """ Get a list of patterns for all hooked apps. How this works: By looking through all titles with an app hook (application_urls) we find all urlconf modules we have to hook into titles. If we use the ML URL Middleware, we namespace those patterns with the title language. All 'normal' patterns from the urlconf get re-written by prefixing them with the title path and then included into the cms url patterns. """ from cms.models import Title try: current_site = Site.objects.get_current() except Site.DoesNotExist: current_site = None included = [] # we don't have a request here so get_page_queryset() can't be used, # so use public() queryset. # This can be done because url patterns are used just in frontend title_qs = Title.objects.public().filter(page__site=current_site) hooked_applications = {} # Loop over all titles with an application hooked to them for title in title_qs.exclude(page__application_urls=None).exclude(page__application_urls='').select_related(): path = title.path mix_id = "%s:%s:%s" % (path + "/", title.page.application_urls, title.language) if mix_id in included: # don't add the same thing twice continue if not settings.APPEND_SLASH: path += '/' if title.page_id not in hooked_applications: hooked_applications[title.page_id] = {} app = apphook_pool.get_apphook(title.page.application_urls) app_ns = app.app_name, title.page.application_namespace with force_language(title.language): hooked_applications[title.page_id][title.language] = (app_ns, get_patterns_for_title(path, title)) included.append(mix_id) # Build the app patterns to be included in the cms urlconfs app_patterns = [] for page_id in hooked_applications.keys(): resolver = None for lang in hooked_applications[page_id].keys(): (app_ns, inst_ns), current_patterns = hooked_applications[page_id][lang] if not resolver: resolver = AppRegexURLResolver(r'', 'app_resolver', app_name=app_ns, namespace=inst_ns) resolver.page_id = page_id extra_patterns = patterns('', *current_patterns) resolver.url_patterns_dict[lang] = extra_patterns app_patterns.append(resolver) APP_RESOLVERS.append(resolver) return app_patterns