commit
07593e5d3d
21 changed files with 802 additions and 44 deletions
27
.coveragerc
Normal file
27
.coveragerc
Normal file
|
@ -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
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -43,4 +43,3 @@ lokalize*
|
|||
|
||||
.idea
|
||||
docs
|
||||
tests
|
||||
|
|
32
.travis.yml
32
.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
|
||||
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'
|
|
@ -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
|
||||
-------------
|
||||
|
||||
|
|
|
@ -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)
|
|
@ -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)
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
106
runtests.py
106
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):
|
||||
|
|
2
setup.py
2
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",
|
||||
|
|
125
tests/__init__.py
Normal file
125
tests/__init__.py
Normal file
|
@ -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'<p>prima riga</p>',
|
||||
'description': u'Questa è la descrizione', 'keywords': u'keyword1, keyword2',
|
||||
'text': u'Testo del post',},
|
||||
{'title': u'Secondo post', 'abstract': u'<p>prima riga del secondo post</p>',
|
||||
'description': u'Descrizione del secondo post', 'keywords': u'keyword3, keyword4',
|
||||
'text': u'Testo del secondo post'},
|
||||
],
|
||||
'en': [
|
||||
{'title': u'First post', 'abstract': u'<p>first line</p>',
|
||||
'description': u'This is the description', 'keywords': u'keyword1, keyword2',
|
||||
'text': u'Post text'},
|
||||
{'title': u'Second post', 'abstract': u'<p>second post first line</p>',
|
||||
'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
|
203
tests/test_models.py
Normal file
203
tests/test_models.py
Normal file
|
@ -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]))
|
72
tests/test_plugins.py
Normal file
72
tests/test_plugins.py
Normal file
|
@ -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('<p>first line</p>') > -1)
|
||||
self.assertTrue(rendered.find('<article id="post-first-post"') > -1)
|
||||
self.assertTrue(rendered.find(post_1.get_absolute_url()) > -1)
|
||||
|
||||
def test_plugin_authors(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.publish = True
|
||||
post_1.save()
|
||||
post_2.publish = True
|
||||
post_2.save()
|
||||
ph = page1.placeholders.get(slot='placeholder')
|
||||
plugin = add_plugin(ph, 'BlogAuthorPostsPlugin', language='en')
|
||||
plugin.authors.add(self.user)
|
||||
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(reverse('djangocms_blog:posts-author', kwargs={'username': self.user.username})) > -1)
|
||||
self.assertTrue(rendered.find('2 articles') > -1)
|
||||
|
||||
def test_plugin_tags(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', 'tag 2', 'test tag')
|
||||
post_1.publish = True
|
||||
post_1.save()
|
||||
post_2.tags.add('test tag', 'another tag')
|
||||
post_2.publish = True
|
||||
post_2.save()
|
||||
ph = page1.placeholders.get(slot='placeholder')
|
||||
plugin = add_plugin(ph, 'BlogTagsPlugin', language='en')
|
||||
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).replace("\n", "")
|
||||
for tag in Tag.objects.all():
|
||||
self.assertTrue(rendered.find(reverse('djangocms_blog:posts-tagged', kwargs={'tag': tag.slug})) > -1)
|
||||
if tag.slug == 'test-tag':
|
||||
rf = '\s+%s\s+<span>\(\s+%s articles' % (tag.name, 2)
|
||||
else:
|
||||
rf = '\s+%s\s+<span>\(\s+%s article' % (tag.name, 1)
|
||||
rx = re.compile(rf)
|
||||
self.assertEqual(len(rx.findall(rendered)), 1)
|
27
tests/test_toolbar.py
Normal file
27
tests/test_toolbar.py
Normal file
|
@ -0,0 +1,27 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from cms.toolbar.items import ModalItem
|
||||
from django.core.urlresolvers import reverse
|
||||
from djangocms_blog.models import BLOG_CURRENT_POST_IDENTIFIER
|
||||
|
||||
|
||||
from . import BaseTest
|
||||
|
||||
|
||||
class ToolbarTest(BaseTest):
|
||||
|
||||
def test_toolbar_with_items(self):
|
||||
"""
|
||||
Test that Blog toolbar is present and contains all items
|
||||
"""
|
||||
from cms.toolbar.toolbar import CMSToolbar
|
||||
post = self._get_post(self.data['en'][0])
|
||||
page1, page2 = self.get_pages()
|
||||
request = self.get_page_request(page1, self.user, r'/en/blog/', edit=True)
|
||||
setattr(request, BLOG_CURRENT_POST_IDENTIFIER, post)
|
||||
toolbar = CMSToolbar(request)
|
||||
toolbar.get_left_items()
|
||||
blog_menu = toolbar.menus['djangocms_blog']
|
||||
self.assertEqual(len(blog_menu.find_items(ModalItem, url=reverse('admin:djangocms_blog_post_changelist'))), 1)
|
||||
self.assertEqual(len(blog_menu.find_items(ModalItem, url=reverse('admin:djangocms_blog_post_add'))), 1)
|
||||
self.assertEqual(len(blog_menu.find_items(ModalItem, url=reverse('admin:djangocms_blog_post_change', args=(post.pk,)))), 1)
|
||||
|
2
tests/test_utils/__init__.py
Normal file
2
tests/test_utils/__init__.py
Normal file
|
@ -0,0 +1,2 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from django.utils.translation import ugettext_lazy as _
|
6
tests/test_utils/templates/base.html
Normal file
6
tests/test_utils/templates/base.html
Normal file
|
@ -0,0 +1,6 @@
|
|||
{% include "page.html" %}
|
||||
{% block content %}
|
||||
<div class="app app-blog span8">
|
||||
{% block content_blog %}{% endblock %}
|
||||
</div>
|
||||
{% endblock content %}
|
9
tests/test_utils/templates/page.html
Normal file
9
tests/test_utils/templates/page.html
Normal file
|
@ -0,0 +1,9 @@
|
|||
{% load cms_tags sekizai_tags %}
|
||||
{% render_block "css" %}
|
||||
{% cms_toolbar %}
|
||||
|
||||
{% block content %}
|
||||
{% placeholder "placeholder" %}
|
||||
{% endblock content %}
|
||||
|
||||
{% render_block "js" %}
|
27
tests/test_utils/urls.py
Normal file
27
tests/test_utils/urls.py
Normal file
|
@ -0,0 +1,27 @@
|
|||
from cms.utils.conf import get_cms_setting
|
||||
from django.conf import settings
|
||||
from django.conf.urls import patterns, include, url
|
||||
from django.contrib import admin
|
||||
from django.conf.urls.i18n import i18n_patterns
|
||||
|
||||
|
||||
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
|
||||
|
||||
admin.autodiscover()
|
||||
|
||||
urlpatterns = patterns('',
|
||||
#(r'', include('django.contrib.staticfiles.urls')),
|
||||
url(r'^media/(?P<path>.*)$', 'django.views.static.serve',
|
||||
{'document_root': settings.MEDIA_ROOT, 'show_indexes': True}),
|
||||
url(r'^media/cms/(?P<path>.*)$', 'django.views.static.serve',
|
||||
{'document_root': get_cms_setting('MEDIA_ROOT'), 'show_indexes': True}),
|
||||
url(r'^jsi18n/(?P<packages>\S+?)/$', 'django.views.i18n.javascript_catalog'),
|
||||
)
|
||||
|
||||
urlpatterns += staticfiles_urlpatterns()
|
||||
|
||||
urlpatterns += i18n_patterns('',
|
||||
url(r'^admin/', include(admin.site.urls)),
|
||||
url(r'^blog/', include('djangocms_blog.urls', namespace='djangocms_blog')),
|
||||
url(r'^', include('cms.urls')),
|
||||
)
|
117
tests/test_views.py
Normal file
117
tests/test_views.py
Normal file
|
@ -0,0 +1,117 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from datetime import date
|
||||
from django.contrib.auth.models import AnonymousUser
|
||||
from django.http import Http404
|
||||
from django.utils.translation import activate
|
||||
from djangocms_blog.views import PostListView, PostDetailView, PostArchiveView
|
||||
|
||||
from . import BaseTest
|
||||
|
||||
|
||||
class ViewTest(BaseTest):
|
||||
|
||||
def test_post_list_view(self):
|
||||
page1, page2 = self.get_pages()
|
||||
post_1 = self._get_post(self.data['en'][0])
|
||||
post_1 = self._get_post(self.data['it'][0], post_1, 'it')
|
||||
post_1.publish = True
|
||||
post_1.save()
|
||||
post_1.set_current_language('en')
|
||||
post_2 = self._get_post(self.data['en'][1])
|
||||
post_2 = self._get_post(self.data['it'][1], post_2, 'it')
|
||||
post_2.set_current_language('en')
|
||||
|
||||
request = self.get_page_request(page1, AnonymousUser(), r'/en/blog/', edit=False)
|
||||
activate('en')
|
||||
view_obj = PostListView()
|
||||
view_obj.request = request
|
||||
|
||||
self.assertEqual(list(view_obj.get_queryset()), [post_1])
|
||||
|
||||
request = self.get_page_request(page1, self.user, r'/en/blog/', edit=False)
|
||||
view_obj.request = request
|
||||
self.assertEqual(set(view_obj.get_queryset()), set([post_1, post_2]))
|
||||
|
||||
view_obj.kwargs = {}
|
||||
view_obj.object_list = view_obj.get_queryset()
|
||||
view_obj.paginate_by = 1
|
||||
context = view_obj.get_context_data(object_list=view_obj.object_list)
|
||||
self.assertTrue(context['is_paginated'])
|
||||
self.assertEqual(list(context['post_list']), [post_2])
|
||||
self.assertEqual(context['paginator'].count, 2)
|
||||
self.assertEqual(context['post_list'][0].title, 'Second post')
|
||||
response = view_obj.render_to_response(context)
|
||||
self.assertContains(response, context['post_list'][0].get_absolute_url())
|
||||
|
||||
request = self.get_page_request(page1, self.user, r'/it/blog/', lang_code='it', edit=False)
|
||||
activate('it')
|
||||
view_obj.request = request
|
||||
view_obj.object_list = view_obj.get_queryset()
|
||||
context = view_obj.get_context_data(object_list=view_obj.object_list)
|
||||
self.assertEqual(context['post_list'][0].title, 'Secondo post')
|
||||
response = view_obj.render_to_response(context)
|
||||
self.assertContains(response, context['post_list'][0].get_absolute_url())
|
||||
|
||||
def test_post_detail_view(self):
|
||||
page1, page2 = self.get_pages()
|
||||
post_1 = self._get_post(self.data['en'][0])
|
||||
post_1 = self._get_post(self.data['it'][0], post_1, 'it')
|
||||
post_1.publish = True
|
||||
post_1.save()
|
||||
post_1.set_current_language('en')
|
||||
post_2 = self._get_post(self.data['en'][1])
|
||||
post_2 = self._get_post(self.data['it'][1], post_2, 'it')
|
||||
post_2.set_current_language('en')
|
||||
|
||||
request = self.get_page_request(page1, AnonymousUser(), r'/en/blog/', edit=False)
|
||||
activate('en')
|
||||
view_obj = PostDetailView()
|
||||
view_obj.request = request
|
||||
|
||||
with self.assertRaises(Http404):
|
||||
view_obj.kwargs = {'slug': 'not-existing'}
|
||||
post_obj = view_obj.get_object()
|
||||
|
||||
view_obj.kwargs = {'slug': post_1.slug}
|
||||
post_obj = view_obj.get_object()
|
||||
self.assertEqual(post_obj, post_1)
|
||||
self.assertEqual(post_obj.language_code, 'en')
|
||||
|
||||
request = self.get_page_request(page1, AnonymousUser(), r'/it/blog/', lang_code='it', edit=False)
|
||||
activate('it')
|
||||
view_obj.request = request
|
||||
post_obj = view_obj.get_object()
|
||||
self.assertEqual(post_obj, post_1)
|
||||
self.assertEqual(post_obj.language_code, 'it')
|
||||
|
||||
view_obj.object = post_obj
|
||||
context = view_obj.get_context_data()
|
||||
self.assertEqual(context['post'], post_1)
|
||||
self.assertEqual(context['post'].language_code, 'it')
|
||||
self.assertTrue(context['meta'])
|
||||
|
||||
def test_post_archive_view(self):
|
||||
page1, page2 = self.get_pages()
|
||||
post_1 = self._get_post(self.data['en'][0])
|
||||
post_1 = self._get_post(self.data['it'][0], post_1, 'it')
|
||||
post_1.publish = True
|
||||
post_1.save()
|
||||
post_1.set_current_language('en')
|
||||
post_2 = self._get_post(self.data['en'][1])
|
||||
post_2 = self._get_post(self.data['it'][1], post_2, 'it')
|
||||
post_2.set_current_language('en')
|
||||
|
||||
request = self.get_page_request(page1, AnonymousUser(), r'/en/blog/', edit=False)
|
||||
activate('en')
|
||||
view_obj = PostArchiveView()
|
||||
view_obj.request = request
|
||||
view_obj.kwargs = {'year': date.today().year, 'month': date.today().month}
|
||||
|
||||
# One post only, anonymous request
|
||||
qs = view_obj.get_queryset()
|
||||
self.assertEqual(qs.count(), 1)
|
||||
self.assertEqual(list(qs), [post_1])
|
||||
|
||||
view_obj.object_list = qs
|
||||
context = view_obj.get_context_data(object_list=view_obj.object_list)
|
||||
self.assertEqual(context['archive_date'], date(year=date.today().year, month=date.today().month, day=1))
|
30
tox.ini
30
tox.ini
|
@ -1,10 +1,28 @@
|
|||
[tox]
|
||||
envlist = py26, py27, py33
|
||||
envlist = py26dj15, py26dj16, py27dj15, py27dj16
|
||||
|
||||
[testenv]
|
||||
setenv =
|
||||
PYTHONPATH = {toxinidir}:{toxinidir}/djangocms_blog
|
||||
commands = python setup.py test
|
||||
commands = python runtests.py
|
||||
deps =
|
||||
-r{toxinidir}/requirements-dev.txt
|
||||
-r{toxinidir}/requirements.txt
|
||||
-r{toxinidir}/requirements-test.txt
|
||||
|
||||
[testenv:py26dj15]
|
||||
deps =
|
||||
django<1.6
|
||||
{[testenv]deps}
|
||||
|
||||
[testenv:py26dj16]
|
||||
deps =
|
||||
django<1.7
|
||||
{[testenv]deps}
|
||||
|
||||
[testenv:py27dj15]
|
||||
deps =
|
||||
django<1.6
|
||||
{[testenv]deps}
|
||||
|
||||
[testenv:py27dj16]
|
||||
deps =
|
||||
django<1.7
|
||||
{[testenv]deps}
|
||||
|
||||
|
|
Loading…
Reference in a new issue