diff --git a/.coveragerc b/.coveragerc new file mode 100644 index 0000000..a443013 --- /dev/null +++ b/.coveragerc @@ -0,0 +1,27 @@ +[run] +branch = True +source = djangocms_blog + +[report] +omit = ../*migrations*,../*tests*,../*compat.* +# Regexes for lines to exclude from consideration +exclude_lines = + # Have to re-enable the standard pragma + pragma: no cover + + # Don't complain about missing debug-only code: + def __repr__ + if self\.debug + + # Don't complain if tests don't hit defensive assertion code: + raise AssertionError + raise NotImplementedError + + # Don't complain if non-runnable code isn't run: + if 0: + if __name__ == .__main__.: + +ignore_errors = True + +[html] +directory = coverage_html diff --git a/.gitignore b/.gitignore index 571424e..614369c 100644 --- a/.gitignore +++ b/.gitignore @@ -43,4 +43,3 @@ lokalize* .idea docs -tests diff --git a/.travis.yml b/.travis.yml index 3a1a73b..3980152 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,12 +3,34 @@ language: python python: - - "3.3" - - "2.7" - - "2.6" + - 3.3 + - 3.4 + - 2.7 + - 2.6 + +env: + matrix: + - DJANGO='django>=1.5,<1.6' + - DJANGO='django>=1.6,<1.7' # command to install dependencies, e.g. pip install -r requirements.txt --use-mirrors -install: pip install -r requirements-test.txt +install: + - pip install $DJANGO + - pip install -r requirements-test.txt # command to run tests, e.g. python setup.py test -script: python runtests.py \ No newline at end of file +script: coverage run runtests.py + +after_success: coveralls + +matrix: + + allow_failures: + - python: 3.3 + env: DJANGO='django>=1.5,<1.6' + - python: 3.3 + env: DJANGO='django>=1.6,<1.7' + - python: 3.4 + env: DJANGO='django>=1.5,<1.6' + - python: 3.4 + env: DJANGO='django>=1.6,<1.7' \ No newline at end of file diff --git a/README.rst b/README.rst index 31386ab..590236f 100644 --- a/README.rst +++ b/README.rst @@ -14,6 +14,15 @@ A djangoCMS 3 blog application. Still experimental and untested. You are welcome if you want to try it; if you encounter any issue, please open an issue. +Supported Django versions: + +* Django 1.5 +* Django 1.6 + +Supported django CMS versions: + +* django CMS 3.0 + Documentation ------------- diff --git a/djangocms_blog/cms_toolbar.py b/djangocms_blog/cms_toolbar.py index 83f091b..a35c4bc 100644 --- a/djangocms_blog/cms_toolbar.py +++ b/djangocms_blog/cms_toolbar.py @@ -13,7 +13,7 @@ class BlogToolbar(CMSToolbar): def populate(self): if not (self.is_current_app and self.request.user.has_perm('djangocms_blog.add_post')): - return + return # pragma: no cover admin_menu = self.toolbar.get_or_create_menu("djangocms_blog", _('Blog')) url = reverse('admin:djangocms_blog_post_changelist') admin_menu.add_modal_item(_('Post list'), url=url) @@ -21,7 +21,7 @@ class BlogToolbar(CMSToolbar): admin_menu.add_modal_item(_('Add post'), url=url) current_post = getattr(self.request, BLOG_CURRENT_POST_IDENTIFIER, None) - if current_post and self.request.user.has_perm('djangocms_blog.change_post'): + if current_post and self.request.user.has_perm('djangocms_blog.change_post'): # pragma: no cover admin_menu.add_modal_item(_('Edit Post'),reverse( 'admin:djangocms_blog_post_change', args=(current_post.pk,)), active=True) \ No newline at end of file diff --git a/djangocms_blog/managers.py b/djangocms_blog/managers.py index 149126b..db5dac8 100644 --- a/djangocms_blog/managers.py +++ b/djangocms_blog/managers.py @@ -17,7 +17,7 @@ class TaggedFilterItem(object): o con gli stessi tag di un model o un queryset """ tags = self._taglist(other_model, queryset) - return self.get_query_set().filter(taglist__in=tags) + return self.get_queryset().filter(taglist__in=tags) def _taglist(self, other_model=None, queryset=None): """ @@ -74,6 +74,12 @@ class GenericDateTaggedManager(TaggedFilterItem, TranslationManager): end_date_field = "date_published_end" publish_field = "publish" + def get_queryset(self, *args, **kwargs): + try: + return super(GenericDateTaggedManager, self).get_queryset(*args, **kwargs) + except AttributeError: + return super(GenericDateTaggedManager, self).get_query_set(*args, **kwargs) + def published(self, queryset=None): queryset = self.published_future(queryset) if self.start_date_field: @@ -84,7 +90,7 @@ class GenericDateTaggedManager(TaggedFilterItem, TranslationManager): def published_future(self, queryset=None): if queryset is None: - queryset = self.get_query_set().all() + queryset = self.get_queryset().all() if self.end_date_field: qfilter = ( models.Q(**{"%s__gte" % self.end_date_field: datetime.datetime.now()}) @@ -95,7 +101,7 @@ class GenericDateTaggedManager(TaggedFilterItem, TranslationManager): def archived(self, queryset=None): if queryset is None: - queryset = self.get_query_set().all() + queryset = self.get_queryset().all() if self.end_date_field: qfilter = ( models.Q(**{"%s__lte" % self.end_date_field: datetime.datetime.now()}) @@ -106,17 +112,16 @@ class GenericDateTaggedManager(TaggedFilterItem, TranslationManager): def available(self, queryset=None): if queryset is None: - queryset = self.get_query_set().all() + queryset = self.get_queryset().all() return queryset.filter(**{self.publish_field: True}) def filter_by_language(self, language): - queryset = self.get_query_set() - return queryset.filter(models.Q(language__isnull=True) | models.Q(language=language)) + return self.get_queryset().active_translations(language_code=language) def get_months(self, queryset=None): - """Get months with aggregatet count (how much posts is in the month). Results are ordered by date.""" + """Get months with aggregate count (how much posts is in the month). Results are ordered by date.""" if queryset is None: - queryset = self.get_query_set() + queryset = self.get_queryset() dates = queryset.values_list(self.start_date_field, flat=True) dates = [(x.year, x.month) for x in dates] date_counter = Counter(dates) diff --git a/djangocms_blog/models.py b/djangocms_blog/models.py index 93270bd..54a6d22 100644 --- a/djangocms_blog/models.py +++ b/djangocms_blog/models.py @@ -6,8 +6,9 @@ from django.contrib.sites.models import Site from django.core.urlresolvers import reverse from django.db import models from django.utils import timezone +from django.utils.encoding import force_text from django.utils.text import slugify -from django.utils.translation import ugettext_lazy as _, get_language +from django.utils.translation import ugettext_lazy as _ from djangocms_text_ckeditor.fields import HTMLField from filer.fields.image import FilerImageField from parler.models import TranslatableModel, TranslatedFields @@ -54,7 +55,7 @@ class BlogCategory(TranslatableModel): for lang in self.get_available_languages(): self.set_current_language(lang) if not self.slug and self.name: - self.slug = slugify(self.name) + self.slug = slugify(force_text(self.name)) self.save_translations() @@ -85,7 +86,7 @@ class Post(ModelMeta, TranslatableModel): related_name='djangocms_blog_post_full', blank=True, null=True) enable_comments = models.BooleanField( - verbose_name = _(u'Enable comments on post'), + verbose_name=_(u'Enable comments on post'), default=settings.BLOG_ENABLE_COMMENTS ) @@ -133,12 +134,12 @@ class Post(ModelMeta, TranslatableModel): } def get_keywords(self): - return self.safe_translation_getter('meta_keywords', language_code=get_language()).strip().split(",") + return self.safe_translation_getter('meta_keywords').strip().split(",") def get_description(self): - description = self.safe_translation_getter('meta_description', language_code=get_language()) + description = self.safe_translation_getter('meta_description', any_language=True) if not description: - description = self.safe_translation_getter('abstract', language_code=get_language()) + description = self.safe_translation_getter('abstract', any_language=True) return description.strip() def get_image_url(self): @@ -172,7 +173,7 @@ class Post(ModelMeta, TranslatableModel): kwargs = {'year': self.date_published.year, 'month': self.date_published.month, 'day': self.date_published.day, - 'slug': self.safe_translation_getter('slug', language_code=get_language())} + 'slug': self.safe_translation_getter('slug', any_language=True)} return reverse('djangocms_blog:post-detail', kwargs=kwargs) def thumbnail_options(self): @@ -182,7 +183,7 @@ class Post(ModelMeta, TranslatableModel): return settings.BLOG_IMAGE_THUMBNAIL_SIZE def full_image_options(self): - if self.main_image_fulll_id: + if self.main_image_full_id: return self.main_image_full.as_dict else: return settings.BLOG_IMAGE_FULL_SIZE @@ -238,6 +239,7 @@ class AuthorEntriesPlugin(CMSPlugin): def get_authors(self): authors = self.authors.all() for author in authors: + author.count = 0 if author.djangocms_blog_post_author.filter(publish=True).exists(): author.count = author.djangocms_blog_post_author.filter(publish=True).count() return authors diff --git a/djangocms_blog/views.py b/djangocms_blog/views.py index 21e49ab..913b5ed 100644 --- a/djangocms_blog/views.py +++ b/djangocms_blog/views.py @@ -17,7 +17,7 @@ class BaseBlogView(ViewUrlMixin): def get_queryset(self): language = get_language() - manager = self.model._default_manager.language(language) + manager = self.model._default_manager.active_translations(language_code=language) if not self.request.user.is_staff: manager = manager.filter(publish=True) return manager diff --git a/requirements-test.txt b/requirements-test.txt index 46e7fdc..1a04794 100644 --- a/requirements-test.txt +++ b/requirements-test.txt @@ -1,8 +1,6 @@ -django>=1.5.1 -https://github.com/divio/django-cms/archive/develop.zip +-r requirements.txt coverage +coveralls mock>=1.0.1 nose>=1.3.0 django-nose>=1.2 - -# Additional test requirements go here \ No newline at end of file diff --git a/runtests.py b/runtests.py index 7dbf593..d2e44b9 100644 --- a/runtests.py +++ b/runtests.py @@ -1,31 +1,119 @@ import sys from optparse import OptionParser +gettext = lambda s: s try: from django.conf import settings settings.configure( DEBUG=True, + THUMBNAIL_DEBUG=True, + TEMPLATE_DEBUG=True, USE_TZ=True, DATABASES={ - "default": { - "ENGINE": "django.db.backends.sqlite3", + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', } }, - ROOT_URLCONF="djangocms_blog.urls", - INSTALLED_APPS=[ - "django.contrib.auth", - "django.contrib.contenttypes", - "django.contrib.sites", - "djangocms_blog", + TEMPLATE_CONTEXT_PROCESSORS=[ + 'django.contrib.auth.context_processors.auth', + 'django.contrib.messages.context_processors.messages', + 'django.core.context_processors.i18n', + 'django.core.context_processors.debug', + 'django.core.context_processors.request', + 'django.core.context_processors.media', + 'django.core.context_processors.csrf', + 'cms.context_processors.cms_settings', + 'sekizai.context_processors.sekizai', + 'django.core.context_processors.static', ], + MIDDLEWARE_CLASSES=[ + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.middleware.locale.LocaleMiddleware', + 'django.middleware.doc.XViewMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.middleware.cache.FetchFromCacheMiddleware', + 'cms.middleware.language.LanguageCookieMiddleware', + 'cms.middleware.user.CurrentUserMiddleware', + 'cms.middleware.page.CurrentPageMiddleware', + 'cms.middleware.toolbar.ToolbarMiddleware', + ], + ROOT_URLCONF='tests.test_utils.urls', + INSTALLED_APPS=[ + 'django.contrib.auth', + 'django.contrib.admin', + 'django.contrib.contenttypes', + 'django.contrib.sites', + 'cms', + 'django_nose', + 'menus', + 'mptt', + 'sekizai', + 'filer', + 'parler', + 'taggit', + 'meta', + 'meta_mixin', + 'easy_thumbnails', + 'djangocms_text_ckeditor', + 'cmsplugin_filer_image', + 'django_select2', + 'taggit_autosuggest', + 'djangocms_blog', + 'tests.test_utils', + ], + LANGUAGE_CODE='en', + LANGUAGES=( + ('en', gettext('English')), + ('fr', gettext('French')), + ('it', gettext('Italiano')), + ), + CMS_LANGUAGES={ + 1: [ + { + 'code': 'en', + 'name': gettext('English'), + 'public': True, + }, + { + 'code': 'it', + 'name': gettext('Italiano'), + 'public': True, + }, + { + 'code': 'fr', + 'name': gettext('French'), + 'public': True, + }, + ], + 'default': { + 'hide_untranslated': False, + }, + }, + CMS_TEMPLATES=( + ('page.html', 'page'), + ), SITE_ID=1, NOSE_ARGS=['-s'], + META_SITE_PROTOCOL='http', + META_SITE_DOMAIN='example.com', + META_USE_OG_PROPERTIES=True, + META_USE_TWITTER_PROPERTIES=True, + META_USE_GOOGLEPLUS_PROPERTIES=True, + THUMBNAIL_PROCESSORS=( + 'easy_thumbnails.processors.colorspace', + 'easy_thumbnails.processors.autocrop', + 'filer.thumbnail_processors.scale_and_crop_with_subject_location', + 'easy_thumbnails.processors.filters', + ) ) from django_nose import NoseTestSuiteRunner except ImportError: - raise ImportError("To fix this error, run: pip install -r requirements-test.txt") + raise ImportError('To fix this error, run: pip install -r requirements-test.txt') def run_tests(*test_args): diff --git a/setup.py b/setup.py index b50e1f8..8291693 100755 --- a/setup.py +++ b/setup.py @@ -45,6 +45,8 @@ setup( 'django-taggit-templatetags', 'django-taggit-autosuggest', 'django-admin-enhancer', + 'djangocms-text-ckeditor', + 'cmsplugin-filer', 'django-meta-mixin', ], license="BSD", diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..a311d6b --- /dev/null +++ b/tests/__init__.py @@ -0,0 +1,125 @@ +# -*- coding: utf-8 -*- +""" +Tests for `djangocms_blog` module. +""" +from cms.utils.i18n import get_language_list +from cmsplugin_filer_image.models import ThumbnailOption +from django.contrib.auth.models import User +from django.http import SimpleCookie +from django.test import TestCase, RequestFactory +from django.utils.translation import activate +from six import StringIO + +from djangocms_blog.models import BlogCategory, Post + + +class BaseTest(TestCase): + """ + Base class with utility function + """ + request_factory = None + user = None + languages = get_language_list() + category_1 = None + thumb_1 = None + thumb_2 = None + + data = { + 'it': [ + {'title': u'Primo post', 'abstract': u'
prima riga
', + 'description': u'Questa รจ la descrizione', 'keywords': u'keyword1, keyword2', + 'text': u'Testo del post',}, + {'title': u'Secondo post', 'abstract': u'prima riga del secondo post
', + 'description': u'Descrizione del secondo post', 'keywords': u'keyword3, keyword4', + 'text': u'Testo del secondo post'}, + ], + 'en': [ + {'title': u'First post', 'abstract': u'first line
', + 'description': u'This is the description', 'keywords': u'keyword1, keyword2', + 'text': u'Post text'}, + {'title': u'Second post', 'abstract': u'second post first line
', + 'description': u'Second post description', 'keywords': u'keyword3, keyword4', + 'text': u'Second post text'} + ] + } + + @classmethod + def setUpClass(cls): + cls.request_factory = RequestFactory() + cls.user = User.objects.create(username='admin', is_staff=True, is_superuser=True) + cls.user_staff = User.objects.create(username='staff', is_staff=True) + cls.user_normal = User.objects.create(username='normal') + + def setUp(self): + activate('en') + super(BaseTest, self).setUp() + self.category_1 = BlogCategory.objects.create() + self.category_1.name = u'category 1' + self.category_1.save() + self.category_1.set_current_language('it') + self.category_1.name = u'categoria 1' + self.category_1.save() + self.category_1.set_current_language('en') + self.thumb_1 = ThumbnailOption.objects.create( + name='base', width=100, height=100, crop=True, upscale=False + ) + self.thumb_2 = ThumbnailOption.objects.create( + name='main', width=200, height=200, crop=False, upscale=False + ) + + def _get_post(self, data, post=None, lang='en'): + if not post: + post = Post() + post.set_current_language(lang) + post.author = self.user + post.title = data['title'] + post.abstract = data['abstract'] + post.meta_description = data['description'] + post.meta_keywords = data['keywords'] + post.save() + post.categories.add(self.category_1) + post.save() + return post + + + @classmethod + def tearDownClass(cls): + User.objects.all().delete() + + def get_pages(self): + from cms.api import create_page, create_title + page = create_page(u'page one', 'page.html', language='en') + page_2 = create_page(u'page two', 'page.html', language='en') + create_title(language='fr', title=u'page un', page=page) + create_title(language='it', title=u'pagina uno', page=page) + for lang in self.languages: + page.publish(lang) + page_2.publish('en') + return page.get_draft_object(), page_2.get_draft_object() + + def get_request(self, page, lang): + request = self.request_factory.get(page.get_path(lang)) + request.current_page = page + request.user = self.user + request.session = {} + request.cookies = SimpleCookie() + request.errors = StringIO() + return request + + def get_page_request(self, page, user, path=None, edit=False, lang_code='en'): + from cms.middleware.toolbar import ToolbarMiddleware + path = path or page and page.get_absolute_url() + if edit: + path += '?edit' + request = RequestFactory().get(path) + request.session = {} + request.user = user + request.LANGUAGE_CODE = lang_code + if edit: + request.GET = {'edit': None} + else: + request.GET = {'edit_off': None} + request.current_page = page + mid = ToolbarMiddleware() + mid.process_request(request) + return request diff --git a/tests/test_models.py b/tests/test_models.py new file mode 100644 index 0000000..8aa79d6 --- /dev/null +++ b/tests/test_models.py @@ -0,0 +1,203 @@ +# -*- coding: utf-8 -*- +from cms.api import add_plugin +from cms.utils.copy_plugins import copy_plugins_to +from cms.utils.plugins import downcast_plugins +from datetime import date +from django.core.urlresolvers import reverse +import parler +from taggit.models import Tag + +from djangocms_blog.models import Post +from djangocms_blog import settings + + +from . import BaseTest + + +class ModelsTest(BaseTest): + + def test_model_attributes(self): + post = self._get_post(self.data['en'][0]) + post = self._get_post(self.data['it'][0], post, 'it') + post.set_current_language('en') + meta_en = post.as_meta() + self.assertEqual(meta_en.og_type, settings.BLOG_FB_TYPE) + self.assertEqual(meta_en.title, post.title) + self.assertTrue(meta_en.url.endswith(post.get_absolute_url())) + self.assertEqual(meta_en.description, post.meta_description) + self.assertEqual(meta_en.keywords, post.meta_keywords.split(',')) + self.assertEqual(meta_en.published_time, post.date_published) + post.set_current_language('it') + meta_it = post.as_meta() + self.assertEqual(meta_it.title, post.title) + self.assertTrue(meta_it.url.endswith(post.get_absolute_url())) + self.assertNotEqual(meta_it.title, meta_en.title) + self.assertEqual(meta_it.description, post.meta_description) + + post.set_current_language('en') + kwargs = {'year': post.date_published.year, + 'month': post.date_published.month, + 'day': post.date_published.day, + 'slug': post.safe_translation_getter('slug', any_language=True)} + url_en = reverse('djangocms_blog:post-detail', kwargs=kwargs) + self.assertEqual(url_en, post.get_absolute_url()) + post.set_current_language('it') + kwargs = {'year': post.date_published.year, + 'month': post.date_published.month, + 'day': post.date_published.day, + 'slug': post.safe_translation_getter('slug', any_language=True)} + url_it = reverse('djangocms_blog:post-detail', kwargs=kwargs) + self.assertEqual(url_it, post.get_absolute_url()) + self.assertNotEqual(url_it, url_en) + + self.assertEqual(post.get_full_url(), 'http://example.com%s' % url_it) + + self.assertEqual(post.thumbnail_options(), settings.BLOG_IMAGE_THUMBNAIL_SIZE) + self.assertEqual(post.full_image_options(), settings.BLOG_IMAGE_FULL_SIZE) + + post.main_image_thumbnail = self.thumb_1 + post.main_image_full = self.thumb_2 + self.assertEqual(post.thumbnail_options(), { + 'size': (100, 100), + 'width': 100, 'height': 100, + 'crop': True, + 'upscale': False + }) + self.assertEqual(post.full_image_options(), { + 'size': (200, 200), + 'width': 200, 'height': 200, + 'crop': False, + 'upscale': False + }) + + def test_manager(self): + post_1 = self._get_post(self.data['en'][0]) + post_2 = self._get_post(self.data['en'][1]) + + # default queryset, published and unpublished posts + months = Post.objects.get_months() + for data in months: + self.assertEqual(data['date'], date(year=date.today().year, month=date.today().month, day=1)) + self.assertEqual(data['count'], 2) + + # custom queryset, only published + post_1.publish = True + post_1.save() + months = Post.objects.get_months(Post.objects.published()) + for data in months: + self.assertEqual(data['date'], date(year=date.today().year, month=date.today().month, day=1)) + self.assertEqual(data['count'], 1) + + self.assertEqual(len(Post.objects.available()), 1) + + # If post is published but publishing date is in the future + post_2.date_published = date(year=date.today().year+1, month=date.today().month, day=1) + post_2.publish = True + post_2.save() + self.assertEqual(len(Post.objects.available()), 2) + self.assertEqual(len(Post.objects.published()), 1) + self.assertEqual(len(Post.objects.archived()), 0) + + # If post is published but end publishing date is in the past + post_2.date_published = date(year=date.today().year-2, month=date.today().month, day=1) + post_2.date_published_end = date(year=date.today().year-1, month=date.today().month, day=1) + post_2.save() + self.assertEqual(len(Post.objects.available()), 2) + self.assertEqual(len(Post.objects.published()), 1) + self.assertEqual(len(Post.objects.archived()), 1) + + # counting with language fallback enabled + post = self._get_post(self.data['it'][0], post_1, 'it') + self.assertEqual(len(Post.objects.filter_by_language('it')), 2) + + # No fallback + parler.appsettings.PARLER_LANGUAGES['default']['hide_untranslated'] = True + self.assertEqual(len(Post.objects.filter_by_language('it')), 1) + parler.appsettings.PARLER_LANGUAGES['default']['hide_untranslated'] = False + + def test_tag_cloud(self): + post_1 = self._get_post(self.data['en'][0]) + post_2 = self._get_post(self.data['en'][1]) + post_1.tags.add('tag 1', 'tag 2', 'tag 3', 'tag 4') + post_1.save() + post_2.tags.add('tag 6', 'tag 2', 'tag 5', 'tag 8') + post_2.save() + + self.assertEqual(len(Post.objects.tag_cloud()), 0) + + tags = [] + for tag in Tag.objects.all(): + if tag.slug == 'tag-2': + tag.count = 2 + else: + tag.count = 1 + tags.append(tag) + + self.assertEqual(Post.objects.tag_cloud(published=True), []) + self.assertEqual(set(Post.objects.tag_cloud(published=False)), set(tags)) + + tags_1 = [] + for tag in Tag.objects.all(): + if tag.slug == 'tag-2': + tag.count = 2 + tags_1.append(tag) + elif tag.slug in ('tag-1', 'tag-3', 'tag-4'): + tag.count = 1 + tags_1.append(tag) + + post_1.publish = True + post_1.save() + self.assertEqual(set(Post.objects.tag_cloud()), set(tags_1)) + self.assertEqual(set(Post.objects.tag_cloud(published=False)), set(tags)) + + def test_plugin_latest(self): + post_1 = self._get_post(self.data['en'][0]) + post_2 = self._get_post(self.data['en'][1]) + post_1.tags.add('tag 1') + post_1.save() + plugin = add_plugin(post_1.content, 'BlogLatestEntriesPlugin', language='en') + tag = Tag.objects.get(slug='tag-1') + plugin.tags.add(tag) + self.assertEqual(len(plugin.get_posts()), 0) + post_1.publish = True + post_1.save() + self.assertEqual(len(plugin.get_posts()), 1) + + def test_copy_plugin_latest(self): + post_1 = self._get_post(self.data['en'][0]) + post_2 = self._get_post(self.data['en'][1]) + tag = Tag.objects.create(name='tag 1') + plugin = add_plugin(post_1.content, 'BlogLatestEntriesPlugin', language='en') + plugin.tags.add(tag) + plugins = list(post_1.content.cmsplugin_set.filter(language='en').order_by('tree_id', 'level', 'position')) + copy_plugins_to(plugins, post_2.content) + new = downcast_plugins(post_2.content.cmsplugin_set.all()) + self.assertEqual(set(new[0].tags.all()), set([tag])) + + def test_plugin_author(self): + post_1 = self._get_post(self.data['en'][0]) + post_2 = self._get_post(self.data['en'][1]) + plugin = add_plugin(post_1.content, 'BlogAuthorPostsPlugin', language='en') + plugin.authors.add(self.user) + self.assertEqual(len(plugin.get_posts()), 0) + self.assertEqual(plugin.get_authors()[0].count, 0) + + post_1.publish = True + post_1.save() + self.assertEqual(len(plugin.get_posts()), 1) + self.assertEqual(plugin.get_authors()[0].count, 1) + + post_2.publish = True + post_2.save() + self.assertEqual(len(plugin.get_posts()), 2) + self.assertEqual(plugin.get_authors()[0].count, 2) + + def test_copy_plugin_author(self): + post_1 = self._get_post(self.data['en'][0]) + post_2 = self._get_post(self.data['en'][1]) + plugin = add_plugin(post_1.content, 'BlogAuthorPostsPlugin', language='en') + plugin.authors.add(self.user) + plugins = list(post_1.content.cmsplugin_set.filter(language='en').order_by('tree_id', 'level', 'position')) + copy_plugins_to(plugins, post_2.content) + new = downcast_plugins(post_2.content.cmsplugin_set.all()) + self.assertEqual(set(new[0].authors.all()), set([self.user])) diff --git a/tests/test_plugins.py b/tests/test_plugins.py new file mode 100644 index 0000000..07fd1ee --- /dev/null +++ b/tests/test_plugins.py @@ -0,0 +1,72 @@ +# -*- coding: utf-8 -*- +import re +from cms.api import add_plugin +from django.core.urlresolvers import reverse +from django.template import RequestContext +from taggit.models import Tag + +from . import BaseTest + + +class PluginTest(BaseTest): + + def test_plugin_latest(self): + page1, page2 = self.get_pages() + post_1 = self._get_post(self.data['en'][0]) + post_2 = self._get_post(self.data['en'][1]) + post_1.tags.add('tag 1') + post_1.publish = True + post_1.save() + ph = page1.placeholders.get(slot='placeholder') + plugin = add_plugin(ph, 'BlogLatestEntriesPlugin', language='en') + tag = Tag.objects.get(slug='tag-1') + plugin.tags.add(tag) + request = self.get_page_request(page1, self.user, r'/en/blog/', lang_code='en', edit=True) + context = RequestContext(request, {}) + rendered = plugin.render_plugin(context, ph) + self.assertTrue(rendered.find('cms_plugin-djangocms_blog-post-abstract-1') > -1) + self.assertTrue(rendered.find(reverse('djangocms_blog:posts-tagged', kwargs={'tag': tag.slug})) > -1) + self.assertTrue(rendered.find('first line
') > -1) + self.assertTrue(rendered.find('