From 2c2fd6d7ca081c36d62f8a9faa058db4bdb362cd Mon Sep 17 00:00:00 2001 From: Tadas Dailyda Date: Thu, 12 Feb 2015 11:47:19 +0000 Subject: [PATCH 01/19] Attach category menu to CMSApp --- djangocms_blog/cms_app.py | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/djangocms_blog/cms_app.py b/djangocms_blog/cms_app.py index f00c96f..477d7c5 100644 --- a/djangocms_blog/cms_app.py +++ b/djangocms_blog/cms_app.py @@ -1,12 +1,38 @@ # -*- coding: utf-8 -*- from cms.app_base import CMSApp from cms.apphook_pool import apphook_pool -from django.utils.translation import ugettext_lazy as _ +from cms.menu_bases import CMSAttachMenu +from menus.base import NavigationNode +from menus.menu_pool import menu_pool +from django.core.urlresolvers import reverse +from django.utils.translation import ugettext_lazy as _, get_language +from .models import BlogCategory +class BlogCategoryMenu(CMSAttachMenu): + name = _('Blog Category menu') + + def get_nodes(self, request): + nodes = [] + qs = BlogCategory.objects.translated(get_language()) + qs = qs.order_by('parent_id', 'translations__name').distinct() + for category in qs: + kwargs = { 'category': category.slug } + node = NavigationNode( + category.name, + reverse('djangocms_blog:posts-category', kwargs=kwargs), + category.pk, + category.parent_id + ) + nodes.append(node) + return nodes + +menu_pool.register_menu(BlogCategoryMenu) + class BlogApp(CMSApp): name = _('Blog') urls = ['djangocms_blog.urls'] app_name = 'djangocms_blog' + menus = [BlogCategoryMenu] apphook_pool.register(BlogApp) From 2288d816592955f5cf1f17d5e12fe2fa0b2f41ea Mon Sep 17 00:00:00 2001 From: Tadas Dailyda Date: Fri, 13 Feb 2015 17:30:20 +0000 Subject: [PATCH 02/19] add category view url with id instead of slug to make BlogCategory.get_absolute_url() work in any case --- djangocms_blog/cms_app.py | 4 ++-- djangocms_blog/models.py | 10 ++++++++++ djangocms_blog/urls.py | 1 + djangocms_blog/views.py | 13 +++++++++++-- 4 files changed, 24 insertions(+), 4 deletions(-) diff --git a/djangocms_blog/cms_app.py b/djangocms_blog/cms_app.py index 477d7c5..cefe215 100644 --- a/djangocms_blog/cms_app.py +++ b/djangocms_blog/cms_app.py @@ -15,12 +15,12 @@ class BlogCategoryMenu(CMSAttachMenu): def get_nodes(self, request): nodes = [] qs = BlogCategory.objects.translated(get_language()) - qs = qs.order_by('parent_id', 'translations__name').distinct() + qs = qs.order_by('parent_id', 'translations__name') for category in qs: kwargs = { 'category': category.slug } node = NavigationNode( category.name, - reverse('djangocms_blog:posts-category', kwargs=kwargs), + category.get_absolute_url(), category.pk, category.parent_id ) diff --git a/djangocms_blog/models.py b/djangocms_blog/models.py index 125fbe8..1429fae 100644 --- a/djangocms_blog/models.py +++ b/djangocms_blog/models.py @@ -49,6 +49,16 @@ class BlogCategory(TranslatableModel): def count(self): return self.blog_posts.filter(publish=True).count() + def get_absolute_url(self): + slug = None + lang = get_language() + if self.has_translation(lang): + slug = self.safe_translation_getter('slug', language_code=lang) + if slug is not None: + return reverse('djangocms_blog:posts-category', kwargs={'category':slug}) + # fallback to url with id in case there is no translation of slug + return reverse('djangocms_blog:posts-category-id', kwargs={'category_id':self.pk}) + def __str__(self): return self.safe_translation_getter('name') diff --git a/djangocms_blog/urls.py b/djangocms_blog/urls.py index 41cf7a4..2073984 100644 --- a/djangocms_blog/urls.py +++ b/djangocms_blog/urls.py @@ -15,6 +15,7 @@ urlpatterns = patterns( url(r'^(?P\d{4})/(?P\d{1,2})/(?P\d{1,2})/(?P\w[-\w]*)/$', PostDetailView.as_view(), name='post-detail'), url(r'^author/(?P[\w\.@+-]+)/$', AuthorEntriesView.as_view(), name='posts-author'), url(r'^category/(?P[\w\.@+-]+)/$', CategoryEntriesView.as_view(), name='posts-category'), + url(r'^category_id/(?P\d+)/$', CategoryEntriesView.as_view(), name='posts-category-id'), url(r'^tag/(?P[-\w]+)/$', TaggedListView.as_view(), name='posts-tagged'), url(r'^tag/(?P[-\w]+)/feed/$', TagFeed(), name='posts-tagged-feed'), ) diff --git a/djangocms_blog/views.py b/djangocms_blog/views.py index 86885bf..a378308 100644 --- a/djangocms_blog/views.py +++ b/djangocms_blog/views.py @@ -133,12 +133,21 @@ class CategoryEntriesView(BaseBlogView, ListView): @property def category(self): if not self._category: - self._category = BlogCategory.objects.active_translations(get_language(), slug=self.kwargs['category']).latest('pk') + if 'category' in self.kwargs: + self._category = BlogCategory.objects.active_translations(get_language(), slug=self.kwargs['category']).latest('pk') + else: + self._category = BlogCategory.objects.get(pk=self.kwargs['category_id']) return self._category + def get(self, *args, **kwargs): + # submit object to cms toolbar to get correct language switcher behavior + if hasattr(self.request, 'toolbar'): + self.request.toolbar.set_object(self.category) + return super(CategoryEntriesView, self).get(*args, **kwargs) + def get_queryset(self): qs = super(CategoryEntriesView, self).get_queryset() - if 'category' in self.kwargs: + if 'category' in self.kwargs or 'category_id' in self.kwargs: qs = qs.filter(categories=self.category.pk) return qs From 53a6beed0025c82547fed9bbf542a5d9fd631343 Mon Sep 17 00:00:00 2001 From: Tadas Dailyda Date: Sat, 14 Feb 2015 14:23:35 +0000 Subject: [PATCH 03/19] move BlogCategoryMenu to a separate menu.py --- djangocms_blog/cms_app.py | 26 +------------------------- djangocms_blog/menu.py | 28 ++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 25 deletions(-) create mode 100644 djangocms_blog/menu.py diff --git a/djangocms_blog/cms_app.py b/djangocms_blog/cms_app.py index cefe215..fd9a38d 100644 --- a/djangocms_blog/cms_app.py +++ b/djangocms_blog/cms_app.py @@ -1,34 +1,10 @@ # -*- coding: utf-8 -*- from cms.app_base import CMSApp from cms.apphook_pool import apphook_pool -from cms.menu_bases import CMSAttachMenu -from menus.base import NavigationNode -from menus.menu_pool import menu_pool -from django.core.urlresolvers import reverse from django.utils.translation import ugettext_lazy as _, get_language -from .models import BlogCategory +from .menu import BlogCategoryMenu -class BlogCategoryMenu(CMSAttachMenu): - name = _('Blog Category menu') - - def get_nodes(self, request): - nodes = [] - qs = BlogCategory.objects.translated(get_language()) - qs = qs.order_by('parent_id', 'translations__name') - for category in qs: - kwargs = { 'category': category.slug } - node = NavigationNode( - category.name, - category.get_absolute_url(), - category.pk, - category.parent_id - ) - nodes.append(node) - return nodes - -menu_pool.register_menu(BlogCategoryMenu) - class BlogApp(CMSApp): name = _('Blog') urls = ['djangocms_blog.urls'] diff --git a/djangocms_blog/menu.py b/djangocms_blog/menu.py new file mode 100644 index 0000000..f1760c4 --- /dev/null +++ b/djangocms_blog/menu.py @@ -0,0 +1,28 @@ +# -*- coding: utf-8 -*- +from cms.menu_bases import CMSAttachMenu +from menus.base import NavigationNode +from menus.menu_pool import menu_pool +from django.utils.translation import ugettext_lazy as _, get_language +from .models import BlogCategory + + +class BlogCategoryMenu(CMSAttachMenu): + name = _('Blog Category menu') + + def get_nodes(self, request): + nodes = [] + qs = BlogCategory.objects.translated(get_language()) + qs = qs.order_by('parent_id', 'translations__name') + for category in qs: + kwargs = { 'category': category.slug } + node = NavigationNode( + category.name, + category.get_absolute_url(), + category.pk, + category.parent_id + ) + nodes.append(node) + return nodes + +menu_pool.register_menu(BlogCategoryMenu) + From d8906569c96e4df8b6bc8f2d56922d75afd60cc0 Mon Sep 17 00:00:00 2001 From: Tadas Dailyda Date: Sun, 15 Feb 2015 14:45:48 +0000 Subject: [PATCH 04/19] handle menu cache --- djangocms_blog/menu.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/djangocms_blog/menu.py b/djangocms_blog/menu.py index f1760c4..8953e44 100644 --- a/djangocms_blog/menu.py +++ b/djangocms_blog/menu.py @@ -2,6 +2,7 @@ from cms.menu_bases import CMSAttachMenu from menus.base import NavigationNode from menus.menu_pool import menu_pool +from django.db.models.signals import post_save, post_delete from django.utils.translation import ugettext_lazy as _, get_language from .models import BlogCategory @@ -26,3 +27,9 @@ class BlogCategoryMenu(CMSAttachMenu): menu_pool.register_menu(BlogCategoryMenu) + +def clear_menu_cache(**kwargs): + menu_pool.clear(all=True) + +post_save.connect(clear_menu_cache, sender=BlogCategory) +post_delete.connect(clear_menu_cache, sender=BlogCategory) From ba1c46a2fea81546639fc794ae84b606d9cd678c Mon Sep 17 00:00:00 2001 From: Tadas Dailyda Date: Wed, 25 Feb 2015 22:37:58 +0000 Subject: [PATCH 05/19] support language switcher for post detail view, add navigation modifier to select current category in the menu when in post detail view --- djangocms_blog/menu.py | 26 +++++++++++++++++++++++++- djangocms_blog/views.py | 6 ++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/djangocms_blog/menu.py b/djangocms_blog/menu.py index 8953e44..69c990f 100644 --- a/djangocms_blog/menu.py +++ b/djangocms_blog/menu.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- from cms.menu_bases import CMSAttachMenu -from menus.base import NavigationNode +from menus.base import Modifier, NavigationNode from menus.menu_pool import menu_pool from django.db.models.signals import post_save, post_delete from django.utils.translation import ugettext_lazy as _, get_language @@ -28,6 +28,30 @@ class BlogCategoryMenu(CMSAttachMenu): menu_pool.register_menu(BlogCategoryMenu) +class BlogNavModifier(Modifier): + """ + This navigation modifier makes sure that when + a particular blog post is viewed, + a corresponding category is selected in menu + """ + def modify(self, request, nodes, namespace, root_id, post_cut, breadcrumb): + if not post_cut: return nodes + if not hasattr(request, 'toolbar'): + return nodes + if request.toolbar.get_object_model() != 'djangocms_blog.post': + return nodes + cat = request.toolbar.obj.categories.first() + if not cat: return nodes + + for node in nodes: + if (node.namespace == BlogCategoryMenu.__name__ and + cat.pk == node.id): + node.selected = True + break + return nodes + +menu_pool.register_modifier(BlogNavModifier) + def clear_menu_cache(**kwargs): menu_pool.clear(all=True) diff --git a/djangocms_blog/views.py b/djangocms_blog/views.py index a378308..53d1646 100644 --- a/djangocms_blog/views.py +++ b/djangocms_blog/views.py @@ -47,6 +47,12 @@ class PostDetailView(TranslatableSlugMixin, BaseBlogView, DetailView): slug_field = 'slug' view_url_name = 'djangocms_blog:post-detail' + def get(self, *args, **kwargs): + # submit object to cms to get corrent language switcher and selected category behavior + if hasattr(self.request, 'toolbar'): + self.request.toolbar.set_object(self.get_object()) + return super(PostDetailView, self).get(*args, **kwargs) + def get_context_data(self, **kwargs): context = super(PostDetailView, self).get_context_data(**kwargs) context['meta'] = self.get_object().as_meta() From 9b1424e08d23a4aba35f35b2f6a9c9ee53b09caf Mon Sep 17 00:00:00 2001 From: Tadas Dailyda Date: Fri, 27 Feb 2015 00:44:16 +0000 Subject: [PATCH 06/19] django 16 compatibility --- djangocms_blog/menu.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/djangocms_blog/menu.py b/djangocms_blog/menu.py index 69c990f..a6e3b6e 100644 --- a/djangocms_blog/menu.py +++ b/djangocms_blog/menu.py @@ -13,7 +13,7 @@ class BlogCategoryMenu(CMSAttachMenu): def get_nodes(self, request): nodes = [] qs = BlogCategory.objects.translated(get_language()) - qs = qs.order_by('parent_id', 'translations__name') + qs = qs.order_by('parent__id', 'translations__name') for category in qs: kwargs = { 'category': category.slug } node = NavigationNode( From 8bf041d494367df7057a67c9a0d041b98a762ef7 Mon Sep 17 00:00:00 2001 From: Tadas Dailyda Date: Wed, 25 Mar 2015 11:16:22 +0000 Subject: [PATCH 07/19] fix menu modifier for CategoryEntriesView --- djangocms_blog/menu.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/djangocms_blog/menu.py b/djangocms_blog/menu.py index a6e3b6e..9764691 100644 --- a/djangocms_blog/menu.py +++ b/djangocms_blog/menu.py @@ -38,9 +38,14 @@ class BlogNavModifier(Modifier): if not post_cut: return nodes if not hasattr(request, 'toolbar'): return nodes - if request.toolbar.get_object_model() != 'djangocms_blog.post': + models = ('djangocms_blog.post', 'djangocms_blog.blogcategory') + model = request.toolbar.get_object_model() + if model not in models: return nodes - cat = request.toolbar.obj.categories.first() + if model == 'djangocms_blog.blogcategory': + cat = request.toolbar.obj + else: + cat = request.toolbar.obj.categories.first() if not cat: return nodes for node in nodes: From 74a78fc5a48ce834390590031d3d054214609ec0 Mon Sep 17 00:00:00 2001 From: Tadas Dailyda Date: Thu, 12 Feb 2015 11:47:19 +0000 Subject: [PATCH 08/19] Attach category menu to CMSApp --- djangocms_blog/cms_app.py | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/djangocms_blog/cms_app.py b/djangocms_blog/cms_app.py index fd9a38d..477d7c5 100644 --- a/djangocms_blog/cms_app.py +++ b/djangocms_blog/cms_app.py @@ -1,10 +1,34 @@ # -*- coding: utf-8 -*- from cms.app_base import CMSApp from cms.apphook_pool import apphook_pool +from cms.menu_bases import CMSAttachMenu +from menus.base import NavigationNode +from menus.menu_pool import menu_pool +from django.core.urlresolvers import reverse from django.utils.translation import ugettext_lazy as _, get_language -from .menu import BlogCategoryMenu +from .models import BlogCategory +class BlogCategoryMenu(CMSAttachMenu): + name = _('Blog Category menu') + + def get_nodes(self, request): + nodes = [] + qs = BlogCategory.objects.translated(get_language()) + qs = qs.order_by('parent_id', 'translations__name').distinct() + for category in qs: + kwargs = { 'category': category.slug } + node = NavigationNode( + category.name, + reverse('djangocms_blog:posts-category', kwargs=kwargs), + category.pk, + category.parent_id + ) + nodes.append(node) + return nodes + +menu_pool.register_menu(BlogCategoryMenu) + class BlogApp(CMSApp): name = _('Blog') urls = ['djangocms_blog.urls'] From f55af7d036c3d53469dcd6cde18c899a6b58a25e Mon Sep 17 00:00:00 2001 From: Tadas Dailyda Date: Fri, 13 Feb 2015 17:30:20 +0000 Subject: [PATCH 09/19] add category view url with id instead of slug to make BlogCategory.get_absolute_url() work in any case --- djangocms_blog/cms_app.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/djangocms_blog/cms_app.py b/djangocms_blog/cms_app.py index 477d7c5..cefe215 100644 --- a/djangocms_blog/cms_app.py +++ b/djangocms_blog/cms_app.py @@ -15,12 +15,12 @@ class BlogCategoryMenu(CMSAttachMenu): def get_nodes(self, request): nodes = [] qs = BlogCategory.objects.translated(get_language()) - qs = qs.order_by('parent_id', 'translations__name').distinct() + qs = qs.order_by('parent_id', 'translations__name') for category in qs: kwargs = { 'category': category.slug } node = NavigationNode( category.name, - reverse('djangocms_blog:posts-category', kwargs=kwargs), + category.get_absolute_url(), category.pk, category.parent_id ) From a5c1feb6b057dc337bf65fcbb8c0ae5f4e785321 Mon Sep 17 00:00:00 2001 From: Tadas Dailyda Date: Sat, 14 Feb 2015 14:23:35 +0000 Subject: [PATCH 10/19] move BlogCategoryMenu to a separate menu.py --- djangocms_blog/cms_app.py | 26 +------------------------ djangocms_blog/menu.py | 40 ++------------------------------------- 2 files changed, 3 insertions(+), 63 deletions(-) diff --git a/djangocms_blog/cms_app.py b/djangocms_blog/cms_app.py index cefe215..fd9a38d 100644 --- a/djangocms_blog/cms_app.py +++ b/djangocms_blog/cms_app.py @@ -1,34 +1,10 @@ # -*- coding: utf-8 -*- from cms.app_base import CMSApp from cms.apphook_pool import apphook_pool -from cms.menu_bases import CMSAttachMenu -from menus.base import NavigationNode -from menus.menu_pool import menu_pool -from django.core.urlresolvers import reverse from django.utils.translation import ugettext_lazy as _, get_language -from .models import BlogCategory +from .menu import BlogCategoryMenu -class BlogCategoryMenu(CMSAttachMenu): - name = _('Blog Category menu') - - def get_nodes(self, request): - nodes = [] - qs = BlogCategory.objects.translated(get_language()) - qs = qs.order_by('parent_id', 'translations__name') - for category in qs: - kwargs = { 'category': category.slug } - node = NavigationNode( - category.name, - category.get_absolute_url(), - category.pk, - category.parent_id - ) - nodes.append(node) - return nodes - -menu_pool.register_menu(BlogCategoryMenu) - class BlogApp(CMSApp): name = _('Blog') urls = ['djangocms_blog.urls'] diff --git a/djangocms_blog/menu.py b/djangocms_blog/menu.py index 9764691..f1760c4 100644 --- a/djangocms_blog/menu.py +++ b/djangocms_blog/menu.py @@ -1,8 +1,7 @@ # -*- coding: utf-8 -*- from cms.menu_bases import CMSAttachMenu -from menus.base import Modifier, NavigationNode +from menus.base import NavigationNode from menus.menu_pool import menu_pool -from django.db.models.signals import post_save, post_delete from django.utils.translation import ugettext_lazy as _, get_language from .models import BlogCategory @@ -13,7 +12,7 @@ class BlogCategoryMenu(CMSAttachMenu): def get_nodes(self, request): nodes = [] qs = BlogCategory.objects.translated(get_language()) - qs = qs.order_by('parent__id', 'translations__name') + qs = qs.order_by('parent_id', 'translations__name') for category in qs: kwargs = { 'category': category.slug } node = NavigationNode( @@ -27,38 +26,3 @@ class BlogCategoryMenu(CMSAttachMenu): menu_pool.register_menu(BlogCategoryMenu) - -class BlogNavModifier(Modifier): - """ - This navigation modifier makes sure that when - a particular blog post is viewed, - a corresponding category is selected in menu - """ - def modify(self, request, nodes, namespace, root_id, post_cut, breadcrumb): - if not post_cut: return nodes - if not hasattr(request, 'toolbar'): - return nodes - models = ('djangocms_blog.post', 'djangocms_blog.blogcategory') - model = request.toolbar.get_object_model() - if model not in models: - return nodes - if model == 'djangocms_blog.blogcategory': - cat = request.toolbar.obj - else: - cat = request.toolbar.obj.categories.first() - if not cat: return nodes - - for node in nodes: - if (node.namespace == BlogCategoryMenu.__name__ and - cat.pk == node.id): - node.selected = True - break - return nodes - -menu_pool.register_modifier(BlogNavModifier) - -def clear_menu_cache(**kwargs): - menu_pool.clear(all=True) - -post_save.connect(clear_menu_cache, sender=BlogCategory) -post_delete.connect(clear_menu_cache, sender=BlogCategory) From b3a1dc90150f1fc17d4f2d7ef5e0303e99df6325 Mon Sep 17 00:00:00 2001 From: Tadas Dailyda Date: Sun, 15 Feb 2015 14:45:48 +0000 Subject: [PATCH 11/19] handle menu cache --- djangocms_blog/menu.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/djangocms_blog/menu.py b/djangocms_blog/menu.py index f1760c4..8953e44 100644 --- a/djangocms_blog/menu.py +++ b/djangocms_blog/menu.py @@ -2,6 +2,7 @@ from cms.menu_bases import CMSAttachMenu from menus.base import NavigationNode from menus.menu_pool import menu_pool +from django.db.models.signals import post_save, post_delete from django.utils.translation import ugettext_lazy as _, get_language from .models import BlogCategory @@ -26,3 +27,9 @@ class BlogCategoryMenu(CMSAttachMenu): menu_pool.register_menu(BlogCategoryMenu) + +def clear_menu_cache(**kwargs): + menu_pool.clear(all=True) + +post_save.connect(clear_menu_cache, sender=BlogCategory) +post_delete.connect(clear_menu_cache, sender=BlogCategory) From 9c93d7cbf29d241dc4dd309eed5f8971f5f9b4d3 Mon Sep 17 00:00:00 2001 From: Tadas Dailyda Date: Wed, 25 Feb 2015 22:37:58 +0000 Subject: [PATCH 12/19] support language switcher for post detail view, add navigation modifier to select current category in the menu when in post detail view --- djangocms_blog/menu.py | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/djangocms_blog/menu.py b/djangocms_blog/menu.py index 8953e44..69c990f 100644 --- a/djangocms_blog/menu.py +++ b/djangocms_blog/menu.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- from cms.menu_bases import CMSAttachMenu -from menus.base import NavigationNode +from menus.base import Modifier, NavigationNode from menus.menu_pool import menu_pool from django.db.models.signals import post_save, post_delete from django.utils.translation import ugettext_lazy as _, get_language @@ -28,6 +28,30 @@ class BlogCategoryMenu(CMSAttachMenu): menu_pool.register_menu(BlogCategoryMenu) +class BlogNavModifier(Modifier): + """ + This navigation modifier makes sure that when + a particular blog post is viewed, + a corresponding category is selected in menu + """ + def modify(self, request, nodes, namespace, root_id, post_cut, breadcrumb): + if not post_cut: return nodes + if not hasattr(request, 'toolbar'): + return nodes + if request.toolbar.get_object_model() != 'djangocms_blog.post': + return nodes + cat = request.toolbar.obj.categories.first() + if not cat: return nodes + + for node in nodes: + if (node.namespace == BlogCategoryMenu.__name__ and + cat.pk == node.id): + node.selected = True + break + return nodes + +menu_pool.register_modifier(BlogNavModifier) + def clear_menu_cache(**kwargs): menu_pool.clear(all=True) From 204f8268d991dfb0518d8f7942277d328fd6213a Mon Sep 17 00:00:00 2001 From: Tadas Dailyda Date: Fri, 27 Feb 2015 00:44:16 +0000 Subject: [PATCH 13/19] django 16 compatibility --- djangocms_blog/menu.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/djangocms_blog/menu.py b/djangocms_blog/menu.py index 69c990f..a6e3b6e 100644 --- a/djangocms_blog/menu.py +++ b/djangocms_blog/menu.py @@ -13,7 +13,7 @@ class BlogCategoryMenu(CMSAttachMenu): def get_nodes(self, request): nodes = [] qs = BlogCategory.objects.translated(get_language()) - qs = qs.order_by('parent_id', 'translations__name') + qs = qs.order_by('parent__id', 'translations__name') for category in qs: kwargs = { 'category': category.slug } node = NavigationNode( From a414296c510fe7e06acb62d72c9976f779480f4b Mon Sep 17 00:00:00 2001 From: Tadas Dailyda Date: Wed, 25 Mar 2015 11:16:22 +0000 Subject: [PATCH 14/19] fix menu modifier for CategoryEntriesView --- djangocms_blog/menu.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/djangocms_blog/menu.py b/djangocms_blog/menu.py index a6e3b6e..9764691 100644 --- a/djangocms_blog/menu.py +++ b/djangocms_blog/menu.py @@ -38,9 +38,14 @@ class BlogNavModifier(Modifier): if not post_cut: return nodes if not hasattr(request, 'toolbar'): return nodes - if request.toolbar.get_object_model() != 'djangocms_blog.post': + models = ('djangocms_blog.post', 'djangocms_blog.blogcategory') + model = request.toolbar.get_object_model() + if model not in models: return nodes - cat = request.toolbar.obj.categories.first() + if model == 'djangocms_blog.blogcategory': + cat = request.toolbar.obj + else: + cat = request.toolbar.obj.categories.first() if not cat: return nodes for node in nodes: From 65f3086824fb114bda6a38e7721e96444dd8b872 Mon Sep 17 00:00:00 2001 From: Tadas Dailyda Date: Fri, 17 Jul 2015 16:57:30 +0300 Subject: [PATCH 15/19] remove category by id url --- djangocms_blog/models.py | 11 +++++------ djangocms_blog/urls.py | 1 - djangocms_blog/views.py | 7 ++----- 3 files changed, 7 insertions(+), 12 deletions(-) diff --git a/djangocms_blog/models.py b/djangocms_blog/models.py index 1429fae..ec79ac0 100644 --- a/djangocms_blog/models.py +++ b/djangocms_blog/models.py @@ -50,15 +50,14 @@ class BlogCategory(TranslatableModel): return self.blog_posts.filter(publish=True).count() def get_absolute_url(self): - slug = None lang = get_language() if self.has_translation(lang): slug = self.safe_translation_getter('slug', language_code=lang) - if slug is not None: - return reverse('djangocms_blog:posts-category', kwargs={'category':slug}) - # fallback to url with id in case there is no translation of slug - return reverse('djangocms_blog:posts-category-id', kwargs={'category_id':self.pk}) - + return reverse('djangocms_blog:posts-category', kwargs={'category': slug}) + # in case category doesn't exist in this language, gracefully fallback + # to posts-latest + return reverse('djangocms_blog:posts-latest') + def __str__(self): return self.safe_translation_getter('name') diff --git a/djangocms_blog/urls.py b/djangocms_blog/urls.py index 2073984..41cf7a4 100644 --- a/djangocms_blog/urls.py +++ b/djangocms_blog/urls.py @@ -15,7 +15,6 @@ urlpatterns = patterns( url(r'^(?P\d{4})/(?P\d{1,2})/(?P\d{1,2})/(?P\w[-\w]*)/$', PostDetailView.as_view(), name='post-detail'), url(r'^author/(?P[\w\.@+-]+)/$', AuthorEntriesView.as_view(), name='posts-author'), url(r'^category/(?P[\w\.@+-]+)/$', CategoryEntriesView.as_view(), name='posts-category'), - url(r'^category_id/(?P\d+)/$', CategoryEntriesView.as_view(), name='posts-category-id'), url(r'^tag/(?P[-\w]+)/$', TaggedListView.as_view(), name='posts-tagged'), url(r'^tag/(?P[-\w]+)/feed/$', TagFeed(), name='posts-tagged-feed'), ) diff --git a/djangocms_blog/views.py b/djangocms_blog/views.py index 53d1646..fdecf5f 100644 --- a/djangocms_blog/views.py +++ b/djangocms_blog/views.py @@ -139,10 +139,7 @@ class CategoryEntriesView(BaseBlogView, ListView): @property def category(self): if not self._category: - if 'category' in self.kwargs: - self._category = BlogCategory.objects.active_translations(get_language(), slug=self.kwargs['category']).latest('pk') - else: - self._category = BlogCategory.objects.get(pk=self.kwargs['category_id']) + self._category = BlogCategory.objects.active_translations(get_language(), slug=self.kwargs['category']).latest('pk') return self._category def get(self, *args, **kwargs): @@ -153,7 +150,7 @@ class CategoryEntriesView(BaseBlogView, ListView): def get_queryset(self): qs = super(CategoryEntriesView, self).get_queryset() - if 'category' in self.kwargs or 'category_id' in self.kwargs: + if 'category' in self.kwargs: qs = qs.filter(categories=self.category.pk) return qs From f86ca7ad4a1632f7e57a0ca125e37b56f3d72e41 Mon Sep 17 00:00:00 2001 From: Tadas Dailyda Date: Mon, 20 Jul 2015 15:31:59 +0300 Subject: [PATCH 16/19] add menu tests --- djangocms_blog/menu.py | 6 ++-- tests/__init__.py | 32 ++++++++++++++++- tests/test_menu.py | 80 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 114 insertions(+), 4 deletions(-) create mode 100644 tests/test_menu.py diff --git a/djangocms_blog/menu.py b/djangocms_blog/menu.py index 9764691..068ab86 100644 --- a/djangocms_blog/menu.py +++ b/djangocms_blog/menu.py @@ -30,12 +30,12 @@ menu_pool.register_menu(BlogCategoryMenu) class BlogNavModifier(Modifier): """ - This navigation modifier makes sure that when - a particular blog post is viewed, + This navigation modifier makes sure that when + a particular blog post is viewed, a corresponding category is selected in menu """ def modify(self, request, nodes, namespace, root_id, post_cut, breadcrumb): - if not post_cut: return nodes + if post_cut: return nodes if not hasattr(request, 'toolbar'): return nodes models = ('djangocms_blog.post', 'djangocms_blog.blogcategory') diff --git a/tests/__init__.py b/tests/__init__.py index c4e61d0..9bcf31e 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -22,6 +22,9 @@ from djangocms_blog.models import BlogCategory, Post User = get_user_model() +def _get_cat_pk(lang, name): + return lambda: BlogCategory.objects.translated(lang, name=name).get().pk + class BaseTest(TestCase): """ @@ -59,6 +62,22 @@ class BaseTest(TestCase): ] } + cat_data = { + 'it': [ + {'name': u'Fortissimo'}, + {'name': u'Pianississimo'}, + {'name': u'Mezzo'}, + {'name': u'Forte', 'parent_id': _get_cat_pk('it', 'Mezzo')}, + ], + 'en': [ + {'name': u'Very loud'}, + {'name': u'Very very silent'}, + {'name': u'Almost'}, + {'name': u'Loud', 'parent_id': _get_cat_pk('en', 'Almost')}, + {'name': u'Silent', 'parent_id': _get_cat_pk('en', 'Almost')}, + ] + } + @classmethod def setUpClass(cls): cls.request_factory = RequestFactory() @@ -91,6 +110,17 @@ class BaseTest(TestCase): original_filename=self.image_name, file=file_obj) + def _get_category(self, data, category=None, lang='en'): + data = {k: (v() if hasattr(v, '__call__') else v) for k, v in data.items()} + if not category: + category = BlogCategory.objects.create(**data) + else: + category.set_current_language(lang) + for attr, val in data.items(): + setattr(category, attr, val) + category.save() + return category + def _get_post(self, data, post=None, lang='en', sites=None): if not post: post_data = { @@ -117,7 +147,7 @@ class BaseTest(TestCase): @classmethod def tearDownClass(cls): User.objects.all().delete() - + def tearDown(self): for post in Post.objects.all(): post.delete() diff --git a/tests/test_menu.py b/tests/test_menu.py new file mode 100644 index 0000000..4e76c15 --- /dev/null +++ b/tests/test_menu.py @@ -0,0 +1,80 @@ +# -*- coding: utf-8 -*- +import copy +from django.utils.translation import activate +from menus.menu_pool import menu_pool +from parler.utils.context import switch_language +from djangocms_blog.views import PostDetailView, CategoryEntriesView +from . import BaseTest + + +class MenuTest(BaseTest): + def setUp(self): + super(MenuTest, self).setUp() + self.cats = [self.category_1] + for i, cat_data in enumerate(self.cat_data['en']): + cat = self._get_category(cat_data) + if i < len(self.cat_data['it']): + cat = self._get_category(self.cat_data['it'][i], cat, 'it') + self.cats.append(cat) + + activate('en') + menu_pool.discover_menus() + # All cms menu modifiers should be removed from menu_pool.modifiers + # so that they do not interfere with our menu nodes + menu_pool.modifiers = [m for m in menu_pool.modifiers if m.__module__.startswith('djangocms_blog')] + + def test_menu_nodes(self): + """ + Tests if all categories are present in the menu + """ + for lang in ('en', 'it'): + request = self.get_page_request(None, self.user, + r'/%s/blog/' % lang, edit=False) + activate(lang) + nodes = menu_pool.get_nodes(request, namespace='BlogCategoryMenu') + nodes_copy = copy.deepcopy(nodes) + for cat in self.cats: + if not cat.has_translation(lang): + continue + with switch_language(cat, lang): + # find in node list + found = None + for node in nodes_copy: + if node.url == cat.get_absolute_url(): + found = node + break + self.assertIsNotNone(found) + nodes_copy.remove(found) + self.assertEqual(node.id, cat.id) + self.assertEqual(node.title, cat.name) + # check that all categories were found in menu + self.assertEqual(len(nodes_copy), 0) + + def test_modifier(self): + """ + Tests if correct category is selected in the menu + according to context (view object) + """ + post1, post2 = self.get_posts() + tests = ( + # view class, view kwarg, view object, category + (PostDetailView, 'slug', post1, post1.categories.first()), + (CategoryEntriesView, 'category', self.cats[2], self.cats[2]) + ) + for view_cls, kwarg, obj, cat in tests: + request = self.get_page_request(None, self.user, r'/en/blog/', edit=False) + activate('en') + with switch_language(obj, 'en'): + view_obj = view_cls() + view_obj.request = request + view_obj.kwargs = {kwarg: obj.slug} + view_obj.get(request) + # check if selected menu node points to cat + nodes = menu_pool.get_nodes(request, namespace='BlogCategoryMenu') + found = False + for node in nodes: + if node.selected: + self.assertEqual(node.url, cat.get_absolute_url()) + found = True + break + self.assertTrue(found) From 123a25ddb8374d5fcd63a21d69e2b1ece32aedd5 Mon Sep 17 00:00:00 2001 From: Tadas Dailyda Date: Mon, 20 Jul 2015 16:57:00 +0300 Subject: [PATCH 17/19] take into account that cms changes manu node namespaces --- djangocms_blog/menu.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/djangocms_blog/menu.py b/djangocms_blog/menu.py index 068ab86..0c9f60d 100644 --- a/djangocms_blog/menu.py +++ b/djangocms_blog/menu.py @@ -15,7 +15,6 @@ class BlogCategoryMenu(CMSAttachMenu): qs = BlogCategory.objects.translated(get_language()) qs = qs.order_by('parent__id', 'translations__name') for category in qs: - kwargs = { 'category': category.slug } node = NavigationNode( category.name, category.get_absolute_url(), @@ -49,7 +48,7 @@ class BlogNavModifier(Modifier): if not cat: return nodes for node in nodes: - if (node.namespace == BlogCategoryMenu.__name__ and + if (node.namespace.startswith(BlogCategoryMenu.__name__) and cat.pk == node.id): node.selected = True break From 8b69e90e551d92f5046314e25209943c8c6ceeb8 Mon Sep 17 00:00:00 2001 From: Tadas Dailyda Date: Mon, 20 Jul 2015 17:16:52 +0300 Subject: [PATCH 18/19] py2.6 compat --- tests/__init__.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/__init__.py b/tests/__init__.py index 9bcf31e..eae2eda 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -111,7 +111,9 @@ class BaseTest(TestCase): file=file_obj) def _get_category(self, data, category=None, lang='en'): - data = {k: (v() if hasattr(v, '__call__') else v) for k, v in data.items()} + for k, v in data.items(): + if hasattr(v, '__call__'): + data[k] = v() if not category: category = BlogCategory.objects.create(**data) else: From 352383dad9c3aad91311d41111f0515e91697dc1 Mon Sep 17 00:00:00 2001 From: Tadas Dailyda Date: Tue, 21 Jul 2015 00:34:17 +0300 Subject: [PATCH 19/19] modifier must work on two menu structures when run in django-cms apphook context --- djangocms_blog/menu.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/djangocms_blog/menu.py b/djangocms_blog/menu.py index 0c9f60d..3650b27 100644 --- a/djangocms_blog/menu.py +++ b/djangocms_blog/menu.py @@ -51,7 +51,8 @@ class BlogNavModifier(Modifier): if (node.namespace.startswith(BlogCategoryMenu.__name__) and cat.pk == node.id): node.selected = True - break + # no break here because django-cms maintains two menu structures + # for every apphook (attached to published page and draft page) return nodes menu_pool.register_modifier(BlogNavModifier)