diff --git a/djangocms_blog/cms_appconfig.py b/djangocms_blog/cms_appconfig.py index 5c4cdc8..2407968 100644 --- a/djangocms_blog/cms_appconfig.py +++ b/djangocms_blog/cms_appconfig.py @@ -25,21 +25,65 @@ class BlogConfig(TranslatableModel, AppHookConfig): class BlogConfigForm(AppDataForm): - default_published = forms.BooleanField(label=_('Post published by default'), required=False, - initial=get_setting('DEFAULT_PUBLISHED')) - use_placeholder = forms.BooleanField(label=_('Use placeholder and plugins for article body'), - required=False, - initial=get_setting('USE_PLACEHOLDER')) - use_abstract = forms.BooleanField(label=_('Use abstract field'), - required=False, - initial=get_setting('USE_ABSTRACT')) - set_author = forms.BooleanField(label=_('Set author'), - required=False, - help_text=_('Set author by default'), - initial=get_setting('AUTHOR_DEFAULT')) - paginate_by = forms.IntegerField(label=_('Paginate size'), - required=False, - initial=get_setting('PAGINATION'), - help_text=_('When paginating list views, ' - 'how many articles per page?')) + default_published = forms.BooleanField( + label=_('Post published by default'), required=False, + initial=get_setting('DEFAULT_PUBLISHED') + ) + use_placeholder = forms.BooleanField( + label=_('Use placeholder and plugins for article body'), required=False, + initial=get_setting('USE_PLACEHOLDER') + ) + use_abstract = forms.BooleanField( + label=_('Use abstract field'), required=False, + initial=get_setting('USE_ABSTRACT') + ) + set_author = forms.BooleanField( + label=_('Set author'), required=False, help_text=_('Set author by default'), + initial=get_setting('AUTHOR_DEFAULT') + ) + paginate_by = forms.IntegerField( + label=_('Paginate size'), required=False, initial=get_setting('PAGINATION'), + help_text=_('When paginating list views, how many articles per page?') + ) + template_prefix = forms.CharField( + label=_('Template prefix'), required=False, initial='', + help_text=_('Alternative directory to load the blog templates from') + ) + object_type = forms.ChoiceField( + label=_('Object type'), required=False, + choices=get_setting('TYPES'), initial=get_setting('TYPE') + ) + og_type = forms.ChoiceField( + label=_('Facebook type'), required=False, + choices=get_setting('FB_TYPES'), initial=get_setting('FB_TYPES')[0][0] + ) + og_app_id = forms.CharField( + max_length=200, label=_('Facebook application ID'), required=False, + ) + og_profile_id = forms.CharField( + max_length=200, label=_('Facebook profile ID'), required=False, + ) + og_publisher = forms.CharField( + max_length=200, label=_('Facebook page URL'), required=False + ) + og_author_url = forms.CharField( + max_length=200, label=_('Facebook author URL'), required=False + ) + twitter_type = forms.ChoiceField( + label=_('Twitter type'), required=False, + choices=get_setting('TWITTER_TYPES'), initial=get_setting('TWITTER_TYPES')[0][0] + ) + twitter_site = forms.CharField( + max_length=200, label=_('Twitter site handle'), required=False + ) + twitter_author = forms.CharField( + max_length=200, label=_('Twitter author handle'), required=False + ) + gplus_type = forms.ChoiceField( + label=_('Google+ type'), required=False, + choices=get_setting('GPLUS_TYPES'), initial=get_setting('GPLUS_TYPES')[0][0] + ) + gplus_author = forms.CharField( + max_length=200, label=_('Google+ author name'), required=False + ) setup_config(BlogConfigForm, BlogConfig) diff --git a/djangocms_blog/cms_plugins.py b/djangocms_blog/cms_plugins.py index d115b78..aab204a 100644 --- a/djangocms_blog/cms_plugins.py +++ b/djangocms_blog/cms_plugins.py @@ -1,6 +1,8 @@ # -*- coding: utf-8 -*- from __future__ import absolute_import, print_function, unicode_literals +import os.path + from cms.plugin_base import CMSPluginBase from cms.plugin_pool import plugin_pool from django.utils.translation import ugettext_lazy as _ @@ -13,19 +15,25 @@ from .settings import get_setting class BlogPlugin(CMSPluginBase): module = 'Blog' + def get_render_template(self, context, instance, placeholder): + if instance.app_config.template_prefix: + return os.path.join(instance.app_config.template_prefix, self.base_render_template) + else: + return os.path.join('djangocms_blog', self.base_render_template) + class BlogLatestEntriesPlugin(BlogPlugin): """ Non cached plugin which returns the latest posts taking into account the user / toolbar state """ - render_template = 'djangocms_blog/plugins/latest_entries.html' name = _('Latest Blog Articles') model = LatestPostsPlugin form = LatestEntriesForm filter_horizontal = ('categories',) fields = ('latest_posts', 'tags', 'categories') cache = False + base_render_template = 'plugins/latest_entries.html' def render(self, context, instance, placeholder): context = super(BlogLatestEntriesPlugin, self).render(context, instance, placeholder) @@ -38,12 +46,12 @@ class BlogLatestEntriesPluginCached(BlogPlugin): """ Cached plugin which returns the latest published posts """ - render_template = 'djangocms_blog/plugins/latest_entries.html' name = _('Latest Blog Articles') model = LatestPostsPlugin form = LatestEntriesForm filter_horizontal = ('categories',) fields = ('latest_posts', 'tags', 'categories') + base_render_template = 'plugins/latest_entries.html' def render(self, context, instance, placeholder): context = super(BlogLatestEntriesPluginCached, self).render(context, instance, placeholder) @@ -56,7 +64,7 @@ class BlogAuthorPostsPlugin(BlogPlugin): module = _('Blog') name = _('Author Blog Articles') model = AuthorEntriesPlugin - render_template = 'djangocms_blog/plugins/authors.html' + base_render_template = 'plugins/authors.html' filter_horizontal = ['authors'] def render(self, context, instance, placeholder): @@ -69,7 +77,7 @@ class BlogTagsPlugin(BlogPlugin): module = _('Blog') name = _('Tags') model = GenericBlogPlugin - render_template = 'djangocms_blog/plugins/tags.html' + base_render_template = 'plugins/tags.html' def render(self, context, instance, placeholder): context = super(BlogTagsPlugin, self).render(context, instance, placeholder) @@ -85,7 +93,7 @@ class BlogCategoryPlugin(BlogPlugin): module = _('Blog') name = _('Categories') model = GenericBlogPlugin - render_template = 'djangocms_blog/plugins/categories.html' + base_render_template = 'plugins/categories.html' def render(self, context, instance, placeholder): context = super(BlogCategoryPlugin, self).render(context, instance, placeholder) @@ -100,7 +108,7 @@ class BlogArchivePlugin(BlogPlugin): module = _('Blog') name = _('Archive') model = GenericBlogPlugin - render_template = 'djangocms_blog/plugins/archive.html' + base_render_template = 'plugins/archive.html' def render(self, context, instance, placeholder): context = super(BlogArchivePlugin, self).render(context, instance, placeholder) diff --git a/djangocms_blog/models.py b/djangocms_blog/models.py index 54aa6cf..d3dcd8d 100644 --- a/djangocms_blog/models.py +++ b/djangocms_blog/models.py @@ -141,23 +141,23 @@ class Post(ModelMeta, TranslatableModel): _metadata = { 'title': 'get_title', 'description': 'get_description', + 'keywords': 'get_keywords', 'og_description': 'get_description', 'twitter_description': 'get_description', 'gplus_description': 'get_description', - 'keywords': 'get_keywords', 'locale': None, 'image': 'get_image_full_url', - 'object_type': get_setting('TYPE'), - 'og_type': get_setting('FB_TYPE'), - 'og_app_id': get_setting('FB_APPID'), - 'og_profile_id': get_setting('FB_PROFILE_ID'), - 'og_publisher': get_setting('FB_PUBLISHER'), - 'og_author_url': get_setting('FB_AUTHOR_URL'), - 'twitter_type': get_setting('TWITTER_TYPE'), - 'twitter_site': get_setting('TWITTER_SITE'), - 'twitter_author': get_setting('TWITTER_AUTHOR'), - 'gplus_type': get_setting('GPLUS_TYPE'), - 'gplus_author': get_setting('GPLUS_AUTHOR'), + 'object_type': 'get_meta_attribute', + 'og_type': 'get_meta_attribute', + 'og_app_id': 'get_meta_attribute', + 'og_profile_id': 'get_meta_attribute', + 'og_publisher': 'get_meta_attribute', + 'og_author_url': 'get_meta_attribute', + 'twitter_type': 'get_meta_attribute', + 'twitter_site': 'get_meta_attribute', + 'twitter_author': 'get_meta_attribute', + 'gplus_type': 'get_meta_attribute', + 'gplus_author': 'get_meta_attribute', 'published_time': 'date_published', 'modified_time': 'date_modified', 'expiration_time': 'date_published_end', @@ -185,6 +185,13 @@ class Post(ModelMeta, TranslatableModel): any_language=True)} return reverse('%s:post-detail' % self.app_config.namespace, kwargs=kwargs) + def get_meta_attribute(self, param): + """ + Retrieves django-meta attributes from apphook config instance + :param param: django-meta attribute passed as key + """ + return getattr(self.app_config, param) + def save_translation(self, translation, *args, **kwargs): if not translation.slug and translation.title: translation.slug = slugify(translation.title) diff --git a/djangocms_blog/settings.py b/djangocms_blog/settings.py index 40b9dbe..3b25659 100644 --- a/djangocms_blog/settings.py +++ b/djangocms_blog/settings.py @@ -4,8 +4,15 @@ from __future__ import absolute_import, print_function, unicode_literals def get_setting(name): from django.conf import settings + from django.utils.translation import ugettext_lazy as _ from meta_mixin import settings as meta_settings + OBJECT_TYPES = ( + ('Article', _('Article')), + ('Website', _('Website')), + ) + BLOG_TYPES = getattr(settings, 'BLOG_TYPES', OBJECT_TYPES) + default = { 'BLOG_IMAGE_THUMBNAIL_SIZE': getattr(settings, 'BLOG_IMAGE_THUMBNAIL_SIZE', { 'size': '120x120', @@ -23,30 +30,25 @@ def get_setting(name): 'BLOG_TAGCLOUD_MAX': getattr(settings, 'BLOG_TAGCLOUD_MAX', 10), 'BLOG_PAGINATION': getattr(settings, 'BLOG_PAGINATION', 10), 'BLOG_LATEST_POSTS': getattr(settings, 'BLOG_LATEST_POSTS', 5), - 'BLOG_POSTS_LIST_TRUNCWORDS_COUNT': getattr(settings, - 'BLOG_POSTS_LIST_TRUNCWORDS_COUNT', - 100), + 'BLOG_POSTS_LIST_TRUNCWORDS_COUNT': getattr( + settings, 'BLOG_POSTS_LIST_TRUNCWORDS_COUNT', 100 + ), 'BLOG_TYPE': getattr(settings, 'BLOG_TYPE', 'Article'), + 'BLOG_TYPES': BLOG_TYPES, 'BLOG_FB_TYPE': getattr(settings, 'BLOG_FB_TYPE', 'Article'), - 'BLOG_FB_APPID': getattr(settings, 'BLOG_FB_APPID', - meta_settings.FB_APPID), - 'BLOG_FB_PROFILE_ID': getattr(settings, 'BLOG_FB_PROFILE_ID', - meta_settings.FB_PROFILE_ID), - 'BLOG_FB_PUBLISHER': getattr(settings, 'BLOG_FB_PUBLISHER', - meta_settings.FB_PUBLISHER), - 'BLOG_FB_AUTHOR_URL': getattr(settings, 'BLOG_FB_AUTHOR_URL', - 'get_author_url'), - 'BLOG_FB_AUTHOR': getattr(settings, 'BLOG_FB_AUTHOR', - 'get_author_name'), + 'BLOG_FB_TYPES': getattr(settings, 'BLOG_FB_TYPES', BLOG_TYPES), + 'BLOG_FB_APPID': getattr(settings, 'BLOG_FB_APPID', meta_settings.FB_APPID), + 'BLOG_FB_PROFILE_ID': getattr(settings, 'BLOG_FB_PROFILE_ID', meta_settings.FB_PROFILE_ID), + 'BLOG_FB_PUBLISHER': getattr(settings, 'BLOG_FB_PUBLISHER', meta_settings.FB_PUBLISHER), + 'BLOG_FB_AUTHOR_URL': getattr(settings, 'BLOG_FB_AUTHOR_URL', 'get_author_url'), + 'BLOG_FB_AUTHOR': getattr(settings, 'BLOG_FB_AUTHOR', 'get_author_name'), 'BLOG_TWITTER_TYPE': getattr(settings, 'BLOG_TWITTER_TYPE', 'Summary'), - 'BLOG_TWITTER_SITE': getattr(settings, 'BLOG_TWITTER_SITE', - meta_settings.TWITTER_SITE), - 'BLOG_TWITTER_AUTHOR': getattr(settings, 'BLOG_TWITTER_AUTHOR', - 'get_author_twitter'), - 'BLOG_GPLUS_TYPE': getattr(settings, 'BLOG_GPLUS_SCOPE_CATEGORY', - 'Blog'), - 'BLOG_GPLUS_AUTHOR': getattr(settings, 'BLOG_GPLUS_AUTHOR', - 'get_author_gplus'), + 'BLOG_TWITTER_TYPES': getattr(settings, 'BLOG_TWITTER_TYPES', BLOG_TYPES), + 'BLOG_TWITTER_SITE': getattr(settings, 'BLOG_TWITTER_SITE', meta_settings.TWITTER_SITE), + 'BLOG_TWITTER_AUTHOR': getattr(settings, 'BLOG_TWITTER_AUTHOR', 'get_author_twitter'), + 'BLOG_GPLUS_TYPE': getattr(settings, 'BLOG_GPLUS_SCOPE_CATEGORY', 'Blog'), + 'BLOG_GPLUS_TYPES': getattr(settings, 'BLOG_GPLUS_TYPES', BLOG_TYPES), + 'BLOG_GPLUS_AUTHOR': getattr(settings, 'BLOG_GPLUS_AUTHOR', 'get_author_gplus'), 'BLOG_ENABLE_COMMENTS': getattr(settings, 'BLOG_ENABLE_COMMENTS', True), 'BLOG_USE_ABSTRACT': getattr(settings, 'BLOG_USE_ABSTRACT', True), 'BLOG_USE_PLACEHOLDER': getattr(settings, 'BLOG_USE_PLACEHOLDER', True), diff --git a/djangocms_blog/views.py b/djangocms_blog/views.py index 87268d4..d0ec7b5 100644 --- a/djangocms_blog/views.py +++ b/djangocms_blog/views.py @@ -1,6 +1,8 @@ # -*- coding: utf-8 -*- from __future__ import absolute_import, print_function, unicode_literals +import os.path + from aldryn_apphooks_config.mixins import AppConfigMixin from django.contrib.auth import get_user_model from django.utils.timezone import now @@ -27,11 +29,17 @@ class BaseBlogView(AppConfigMixin, ViewUrlMixin): queryset = queryset.published() return queryset + def get_template_names(self): + if self.config.template_prefix: + return os.path.join(self.config.template_prefix, self.base_template_name) + else: + return os.path.join('djangocms_blog', self.base_template_name) + class PostListView(BaseBlogView, ListView): model = Post context_object_name = 'post_list' - template_name = 'djangocms_blog/post_list.html' + base_template_name = 'post_list.html' view_url_name = 'djangocms_blog:posts-latest' def get_context_data(self, **kwargs): @@ -46,7 +54,7 @@ class PostListView(BaseBlogView, ListView): class PostDetailView(TranslatableSlugMixin, BaseBlogView, DetailView): model = Post context_object_name = 'post' - template_name = 'djangocms_blog/post_detail.html' + base_template_name = 'post_detail.html' slug_field = 'slug' view_url_name = 'djangocms_blog:post-detail' @@ -73,7 +81,7 @@ class PostDetailView(TranslatableSlugMixin, BaseBlogView, DetailView): class PostArchiveView(BaseBlogView, ListView): model = Post context_object_name = 'post_list' - template_name = 'djangocms_blog/post_list.html' + base_template_name = 'post_list.html' date_field = 'date_published' allow_empty = True allow_future = True @@ -101,7 +109,7 @@ class PostArchiveView(BaseBlogView, ListView): class TaggedListView(BaseBlogView, ListView): model = Post context_object_name = 'post_list' - template_name = 'djangocms_blog/post_list.html' + base_template_name = 'post_list.html' paginate_by = get_setting('PAGINATION') view_url_name = 'djangocms_blog:posts-tagged' @@ -120,7 +128,7 @@ class TaggedListView(BaseBlogView, ListView): class AuthorEntriesView(BaseBlogView, ListView): model = Post context_object_name = 'post_list' - template_name = 'djangocms_blog/post_list.html' + base_template_name = 'post_list.html' paginate_by = get_setting('PAGINATION') view_url_name = 'djangocms_blog:posts-authors' @@ -140,7 +148,7 @@ class AuthorEntriesView(BaseBlogView, ListView): class CategoryEntriesView(BaseBlogView, ListView): model = Post context_object_name = 'post_list' - template_name = 'djangocms_blog/post_list.html' + base_template_name = 'post_list.html' _category = None paginate_by = get_setting('PAGINATION') view_url_name = 'djangocms_blog:posts-category' diff --git a/tests/__init__.py b/tests/__init__.py index fe9cbfe..6fad4a6 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -127,6 +127,13 @@ class BaseTest(BaseTestCase): cls.category_1.save() cls.site_2 = Site.objects.create(domain='http://example2.com', name='example 2') + @classmethod + def tearDownClass(cls): + super(BaseTest, cls).tearDownClass() + BlogConfig.objects.all().delete() + BlogCategory.objects.all().delete() + ThumbnailOption.objects.all().delete() + def _get_category(self, data, category=None, lang='en'): data = deepcopy(data) for k, v in data.items(): diff --git a/tests/test_plugins.py b/tests/test_plugins.py index 6e8b640..73b0e2a 100644 --- a/tests/test_plugins.py +++ b/tests/test_plugins.py @@ -1,11 +1,13 @@ # -*- coding: utf-8 -*- from __future__ import absolute_import, print_function, unicode_literals +import os.path import re from cms.api import add_plugin from django.core.urlresolvers import reverse from django.utils.timezone import now +from djangocms_helper.utils import get_user_model from taggit.models import Tag from djangocms_blog.models import BlogCategory @@ -67,12 +69,10 @@ class PluginTest(BaseTest): posts[1].save() ph = pages[0].placeholders.get(slot='content') plugin = add_plugin(ph, 'BlogAuthorPostsPlugin', language='en', app_config=self.app_config_1) - plugin.authors.add(self.user) context = self.get_plugin_context(pages[0], 'en', plugin, edit=True) rendered = plugin.render_plugin(context, ph) - self.assertTrue(rendered.find(reverse('djangocms_blog:posts-author', kwargs={'username': self.user.get_username()})) > -1) - self.assertTrue(rendered.find('2 articles') > -1) + self.assertTrue(rendered.find('No article found') > -1) def test_plugin_tags(self): pages = self.get_pages() @@ -132,3 +132,20 @@ class PluginTest(BaseTest): context = plugin_class.render(context, plugin, ph) self.assertEqual(context['dates'][0]['date'].date(), now().replace(year=now().year, month=now().month, day=1).date()) self.assertEqual(context['dates'][0]['count'], 1) + + def test_templates(self): + posts = self.get_posts() + pages = self.get_pages() + + ph = pages[0].placeholders.get(slot='content') + plugin = add_plugin(ph, 'BlogLatestEntriesPlugin', language='en', app_config=self.app_config_1) + + context = self.get_plugin_context(pages[0], 'en', plugin) + plugin_class = plugin.get_plugin_class_instance() + self.assertEqual(plugin_class.get_render_template(context, plugin, ph), os.path.join('djangocms_blog', plugin_class.base_render_template)) + + self.app_config_1.app_data.config.template_prefix = 'whatever' + self.app_config_1.save() + self.assertEqual(plugin_class.get_render_template(context, plugin, ph), os.path.join('whatever', plugin_class.base_render_template)) + self.app_config_1.app_data.config.template_prefix = '' + self.app_config_1.save() diff --git a/tests/test_views.py b/tests/test_views.py index adc716b..818484a 100644 --- a/tests/test_views.py +++ b/tests/test_views.py @@ -1,7 +1,9 @@ # -*- coding: utf-8 -*- from __future__ import absolute_import, print_function, unicode_literals -from aldryn_apphooks_config.utils import get_app_instance +import os.path + +from aldryn_apphooks_config.utils import get_app_instance from django.contrib.auth.models import AnonymousUser from django.http import Http404 from django.utils.timezone import now @@ -299,3 +301,21 @@ class ViewTest(BaseTest): self.assertEqual(sitemap.items().count(), 3) for item in sitemap.items(): self.assertTrue(sitemap.lastmod(item).date(), now().today()) + + def test_templates(self): + posts = self.get_posts() + pages = self.get_pages() + + with smart_override('en'): + request = self.get_page_request(pages[1], self.user, edit=True) + view_obj = PostListView() + view_obj.request = request + view_obj.namespace = self.app_config_1.namespace + view_obj.config = self.app_config_1 + self.assertEqual(view_obj.get_template_names(), os.path.join('djangocms_blog', 'post_list.html')) + + self.app_config_1.app_data.config.template_prefix = 'whatever' + self.app_config_1.save() + self.assertEqual(view_obj.get_template_names(), os.path.join('whatever', 'post_list.html')) + self.app_config_1.app_data.config.template_prefix = '' + self.app_config_1.save() diff --git a/tox.ini b/tox.ini index 2dbc0d7..2887060 100644 --- a/tox.ini +++ b/tox.ini @@ -15,6 +15,7 @@ deps = cms30: https://github.com/divio/django-cms/archive/support/3.0.x.zip cms31: https://github.com/divio/django-cms/archive/support/3.1.x.zip cms32: https://github.com/divio/django-cms/archive/develop.zip + https://github.com/nephila/django-meta-mixin/archive/master.zip https://github.com/nephila/djangocms-helper/archive/develop.zip py26: unittest2 django-parler<1.5