Merge pull request #147 from nephila/feature/appcnfig
Add aldryn-apphooks config
This commit is contained in:
commit
134b1e0484
36 changed files with 2771 additions and 801 deletions
42
.travis.yml
42
.travis.yml
|
@ -5,6 +5,7 @@ language: python
|
|||
sudo: false
|
||||
|
||||
python:
|
||||
- 3.5
|
||||
- 3.4
|
||||
- 3.3
|
||||
- 2.7
|
||||
|
@ -12,16 +13,16 @@ python:
|
|||
|
||||
env:
|
||||
matrix:
|
||||
- DJANGO='django16' CMS='cms30'
|
||||
- DJANGO='django16' CMS='cms31'
|
||||
- DJANGO='django16' CMS='cms32'
|
||||
- DJANGO='django17' CMS='cms30'
|
||||
- DJANGO='django17' CMS='cms31'
|
||||
- DJANGO='django17' CMS='cms32'
|
||||
- DJANGO='django18' CMS='cms31'
|
||||
- DJANGO='django18' CMS='cms32'
|
||||
- TOXENV='pep8'
|
||||
- TOXENV='isort'
|
||||
- DJANGO='django18' CMS='cms32'
|
||||
- DJANGO='django18' CMS='cms31'
|
||||
- DJANGO='django17' CMS='cms32'
|
||||
- DJANGO='django17' CMS='cms31'
|
||||
- DJANGO='django17' CMS='cms30'
|
||||
- DJANGO='django16' CMS='cms32'
|
||||
- DJANGO='django16' CMS='cms31'
|
||||
- DJANGO='django16' CMS='cms30'
|
||||
|
||||
|
||||
# command to install dependencies, e.g. pip install -r requirements.txt --use-mirrors
|
||||
|
@ -31,12 +32,17 @@ install:
|
|||
- "if [[ $TRAVIS_PYTHON_VERSION == '2.7' ]]; then export PYVER=py27; fi"
|
||||
- "if [[ $TRAVIS_PYTHON_VERSION == '3.3' ]]; then export PYVER=py33; fi"
|
||||
- "if [[ $TRAVIS_PYTHON_VERSION == '3.4' ]]; then export PYVER=py34; fi"
|
||||
- "if [[ $TRAVIS_PYTHON_VERSION == '3.5' ]]; then export PYVER=py35; fi"
|
||||
- "if [[ ${DJANGO}z != 'z' ]]; then export TOXENV=$PYVER-$DJANGO-$CMS; fi"
|
||||
|
||||
# command to run tests, e.g. python setup.py test
|
||||
script: COMMAND='coverage run' tox -e$TOXENV
|
||||
|
||||
after_success: coveralls
|
||||
before_install:
|
||||
- pip install codecov
|
||||
after_success:
|
||||
- codecov
|
||||
- coveralls
|
||||
|
||||
matrix:
|
||||
exclude:
|
||||
|
@ -52,6 +58,10 @@ matrix:
|
|||
env: TOXENV='pep8'
|
||||
- python: 3.3
|
||||
env: TOXENV='isort'
|
||||
- python: 3.4
|
||||
env: TOXENV='pep8'
|
||||
- python: 3.4
|
||||
env: TOXENV='isort'
|
||||
- python: 2.6
|
||||
env: DJANGO='django17' CMS='cms30'
|
||||
- python: 2.6
|
||||
|
@ -62,6 +72,18 @@ matrix:
|
|||
env: DJANGO='django18' CMS='cms31'
|
||||
- python: 2.6
|
||||
env: DJANGO='django18' CMS='cms32'
|
||||
- python: 3.5
|
||||
env: DJANGO='django16' CMS='cms30'
|
||||
- python: 3.5
|
||||
env: DJANGO='django16' CMS='cms31'
|
||||
- python: 3.5
|
||||
env: DJANGO='django16' CMS='cms32'
|
||||
- python: 3.5
|
||||
env: DJANGO='django17' CMS='cms30'
|
||||
- python: 3.5
|
||||
env: DJANGO='django17' CMS='cms31'
|
||||
- python: 3.5
|
||||
env: DJANGO='django17' CMS='cms32'
|
||||
|
||||
allow_failures:
|
||||
- python: 2.6
|
||||
|
@ -84,3 +106,5 @@ matrix:
|
|||
env: DJANGO='django17' CMS='cms32'
|
||||
- python: 3.4
|
||||
env: DJANGO='django18' CMS='cms32'
|
||||
- python: 3.5
|
||||
env: DJANGO='django18' CMS='cms32'
|
||||
|
|
272
README.rst
272
README.rst
|
@ -2,28 +2,34 @@
|
|||
djangocms-blog
|
||||
==============
|
||||
|
||||
.. image:: https://img.shields.io/pypi/v/djangocms-blog.svg?style=flat-square
|
||||
:target: https://pypi.python.org/pypi/djangocms-blog
|
||||
:alt: Latest PyPI version
|
||||
|
||||
.. image:: https://img.shields.io/pypi/v/djangocms-blog.svg
|
||||
:target: https://pypi.python.org/pypi/djangocms-blog
|
||||
:alt: Latest PyPI version
|
||||
.. image:: https://img.shields.io/pypi/dm/djangocms-blog.svg?style=flat-square
|
||||
:target: https://pypi.python.org/pypi/djangocms-blog
|
||||
:alt: Monthly downloads
|
||||
|
||||
.. image:: https://img.shields.io/travis/nephila/djangocms-blog.svg
|
||||
:target: https://travis-ci.org/nephila/djangocms-blog
|
||||
:alt: Latest Travis CI build status
|
||||
.. image:: https://img.shields.io/pypi/pyversions/djangocms-blog.svg?style=flat-square
|
||||
:target: https://pypi.python.org/pypi/djangocms-blog
|
||||
:alt: Python versions
|
||||
|
||||
.. image:: https://img.shields.io/pypi/dm/djangocms-blog.svg
|
||||
:target: https://pypi.python.org/pypi/djangocms-blog
|
||||
:alt: Monthly downloads
|
||||
.. image:: https://img.shields.io/travis/nephila/djangocms-blog.svg?style=flat-square
|
||||
:target: https://travis-ci.org/nephila/djangocms-blog
|
||||
:alt: Latest Travis CI build status
|
||||
|
||||
.. image:: https://coveralls.io/repos/nephila/djangocms-blog/badge.png
|
||||
:target: https://coveralls.io/r/nephila/djangocms-blog
|
||||
:alt: Test coverage
|
||||
.. image:: https://img.shields.io/coveralls/nephila/djangocms-blog/master.svg?style=flat-square
|
||||
:target: https://coveralls.io/r/nephila/djangocms-blog?branch=master
|
||||
:alt: Test coverage
|
||||
|
||||
.. image:: https://codeclimate.com/github/nephila/djangocms-blog/badges/gpa.svg
|
||||
.. image:: https://img.shields.io/codecov/c/github/nephila/djangocms-blog/master.svg?style=flat-square
|
||||
:target: https://codecov.io/github/nephila/djangocms-blog
|
||||
:alt: Test coverage
|
||||
|
||||
.. image:: https://codeclimate.com/github/nephila/djangocms-blog/badges/gpa.svg?style=flat-square
|
||||
:target: https://codeclimate.com/github/nephila/djangocms-blog
|
||||
:alt: Code Climate
|
||||
|
||||
|
||||
A djangoCMS 3 blog application.
|
||||
|
||||
Supported Django versions:
|
||||
|
@ -46,6 +52,19 @@ Supported django CMS versions:
|
|||
on South anymore; please install it separately if using this
|
||||
application on Django 1.6.
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
* Placeholder content editing
|
||||
* Frontend editing using django CMS 3.0 frontend editor
|
||||
* Multilingual support using django-parler
|
||||
* Support for Twitter cards, Open Graph and Google+ snippets meta tags
|
||||
* Optional support for simpler TextField-based content editing
|
||||
* Multisite support (posts can be visible in one or more Django sites on the
|
||||
same project)
|
||||
* Per-Apphook configuration
|
||||
* Per-Apphook templates set
|
||||
* Auto Apphook setup
|
||||
|
||||
Quickstart
|
||||
----------
|
||||
|
@ -85,6 +104,7 @@ Please, refer to each application documentation on details.
|
|||
|
||||
* django-filer: http://django-filer.readthedocs.org
|
||||
* django-meta: https://github.com/nephila/django-meta#installation
|
||||
* django-meta-mixin: https://github.com/nephila/django-meta-mixin#installation
|
||||
* django-parler: http://django-parler.readthedocs.org/en/latest/quickstart.html#configuration
|
||||
* django-taggit-autosuggest: https://bitbucket.org/fabian/django-taggit-autosuggest
|
||||
|
||||
|
@ -109,13 +129,14 @@ suited for your deployment.
|
|||
META_SITE_PROTOCOL = 'http'
|
||||
META_USE_SITES = True
|
||||
|
||||
* If you are using Django 1.7+, be aware than ``filer`` < 0.9.10, ``cmsplugin_filer``
|
||||
and ``django-cms`` < 3.1 currently requires you to setup ``MIGRATION_MODULES`` in settings::
|
||||
* If you are using Django 1.7+, be aware than ``filer`` < 0.9.10,
|
||||
``cmsplugin_filer`` and ``django-cms`` < 3.1 currently requires you to
|
||||
setup ``MIGRATION_MODULES`` in settings::
|
||||
|
||||
MIGRATION_MODULES = {
|
||||
'cms': 'cms.migrations_django', # only for django CMS 3.0
|
||||
'menus': 'menus.migrations_django', # only for django CMS 3.0
|
||||
'filer': 'filer.migrations_django', # only for django filer 0.9.9 and below
|
||||
'filer': 'filer.migrations_django', # only for django filer up to 0.9.9
|
||||
'cmsplugin_filer_image': 'cmsplugin_filer_image.migrations_django',
|
||||
}
|
||||
|
||||
|
@ -139,10 +160,12 @@ suited for your deployment.
|
|||
url(r'^taggit_autosuggest/', include('taggit_autosuggest.urls')),
|
||||
|
||||
* To start your blog you need to use `AppHooks from django CMS <http://django-cms.readthedocs.org/en/support-3.0.x/how_to/apphooks.html>`_
|
||||
to add the blog to a django CMS page:
|
||||
to add the blog to a django CMS page; this step is not required when using
|
||||
**Auto setup** (see below):
|
||||
|
||||
* Create a new django CMS page
|
||||
* Go to Advanced settings and select Blog from the Application selector;
|
||||
* Go to Advanced settings and select Blog from the Application selector and
|
||||
create an application configuration;
|
||||
* Eventually customise the Application instance name;
|
||||
* Publish the page
|
||||
* Restart the project instance to properly load blog urls.
|
||||
|
@ -154,26 +177,165 @@ suited for your deployment.
|
|||
* Create a new blog entry in django admin backend or from the toolbar
|
||||
* Click on "view on site" button to view the post detail page
|
||||
* Edit the post via djangocms frontend by adding / editing plugins
|
||||
* Publish the blog post by flagging the "Publish" switch in the blog post admin
|
||||
* Publish the blog post by flagging the "Publish" switch in the blog post
|
||||
admin
|
||||
|
||||
Configurable permalinks
|
||||
+++++++++++++++++++++++
|
||||
|
||||
Blog comes with four different styles of permalinks styles:
|
||||
|
||||
* Full date: ``YYYY/MM/DD/SLUG``
|
||||
* Year / Month: ``YYYY/MM/SLUG``
|
||||
* Category: ``CATEGORY/SLUG``
|
||||
* Just slug: ``SLUG``
|
||||
|
||||
As all the styles are loaded in the urlconf, the latter two does not allow
|
||||
to have CMS pages beneath the page the blog is attached to. If you want to
|
||||
do this, you have to override the default urlconfs by setting something
|
||||
like the following in the project settings::
|
||||
|
||||
BLOG_PERMALINK_URLS = {
|
||||
'full_date': r'^(?P<year>\d{4})/(?P<month>\d{1,2})/(?P<day>\d{1,2})/(?P<slug>\w[-\w]*)/$',
|
||||
'short_date': r'^(?P<year>\d{4})/(?P<month>\d{1,2})/(?P<slug>\w[-\w]*)/$',
|
||||
'category': r'^post/(?P<category>\w[-\w]*)/(?P<slug>\w[-\w]*)/$',
|
||||
'slug': r'^post/(?P<slug>\w[-\w]*)/$',
|
||||
}
|
||||
|
||||
And change ``post/`` with the desired prefix.
|
||||
|
||||
Templates
|
||||
+++++++++
|
||||
|
||||
To ease the template customisations a ``djangocms_blog/base.html`` template is used by all the blog templates;
|
||||
the templates itself extends a ``base.html`` template; content is pulled in the ``content`` block.
|
||||
If you need to define a different base template, or if your base template does not defines a ``content`` block,
|
||||
copy in your template directory ``djangocms_blog/base.html`` and customise it according to your
|
||||
needs; the other application templates will use the newly created template and will ignore the bundled one.
|
||||
To ease the template customisations a ``djangocms_blog/base.html`` template is
|
||||
used by all the blog templates; the templates itself extends a ``base.html``
|
||||
template; content is pulled in the ``content`` block.
|
||||
If you need to define a different base template, or if your base template does
|
||||
not defines a ``content`` block, copy in your template directory
|
||||
``djangocms_blog/base.html`` and customise it according to your needs; the
|
||||
other application templates will use the newly created base template and
|
||||
will ignore the bundled one.
|
||||
|
||||
Features
|
||||
--------
|
||||
Templates set
|
||||
+++++++++++++
|
||||
|
||||
By using **Apphook configuration** you can define a different templates set.
|
||||
To use this feature provide a directory name in **Template prefix** field in
|
||||
the **Apphook configuration** admin (in *Layout* section): it will be the
|
||||
root of your custom templates set.
|
||||
|
||||
Auto setup
|
||||
++++++++++
|
||||
|
||||
``djangocms_blog`` can install and configue itself if it does not find any
|
||||
attached instance of itself.
|
||||
This feature is enable by default and will create:
|
||||
|
||||
* a ``BlogConfig`` with default values
|
||||
* a ``Blog`` CMS page and will attach ``djangocms_blog`` instance to it
|
||||
* a **home page** is no, home is found.
|
||||
|
||||
All the items will be created in every language configured for the website
|
||||
and the pages will be published. If not using **aldryn-apphook-reload** or
|
||||
**django CMS 3.2** auto-reload middleware you are required to reload the
|
||||
project instance after this.
|
||||
This will only work for the current website as detected by
|
||||
``Site.objects.get_current()``.
|
||||
|
||||
|
||||
The auto setup is execute once for each server start but it will skip any
|
||||
action if a ``BlogConfig`` instance is found.
|
||||
|
||||
|
||||
Global Settings
|
||||
---------------
|
||||
* BLOG_IMAGE_THUMBNAIL_SIZE: Size of the main image when shown on the post
|
||||
lists; it's a dictionary with ``size``, ``crop`` and ``upscale`` keys;
|
||||
(default: ``{'size': '120x120', 'crop': True,'upscale': False}``)
|
||||
* BLOG_IMAGE_FULL_SIZE: Size of the main image when shown on the post
|
||||
detail; it's a dictionary with ``size``, ``crop`` and ``upscale`` keys;
|
||||
(default: ``{'size': '640x120', 'crop': True,'upscale': False}``)
|
||||
* BLOG_PAGINATION: Number of post per page; (default: ``10``)
|
||||
* BLOG_LATEST_POSTS: Default number of post in the **Latest post** plugin;
|
||||
(default: ``5'')
|
||||
* BLOG_POSTS_LIST_TRUNCWORDS_COUNT: Default number of words shown for
|
||||
abstract in the post list; (default: ``100``)
|
||||
* BLOG_TYPE: Generic type for the post object; (default: ``Article``)
|
||||
* BLOG_TYPES: Choices of available blog types;
|
||||
(default: to ``META_OBJECT_TYPES`` defined in `django-meta-mixin settings`_)
|
||||
* BLOG_FB_TYPE: Open Graph type for the post object; (default: ``Article``)
|
||||
* BLOG_FB_TYPES: Choices of available blog types;
|
||||
(default: to ``META_FB_TYPES`` defined in `django-meta-mixin settings`_)
|
||||
* BLOG_FB_APPID: Facebook Application ID
|
||||
* BLOG_FB_PROFILE_ID: Facebook profile ID of the post author
|
||||
* BLOG_FB_PUBLISHER: Facebook URL of the blog publisher
|
||||
* BLOG_FB_AUTHOR_URL: Facebook profile URL of the post author
|
||||
* BLOG_FB_AUTHOR: Facebook profile URL of the post author
|
||||
* BLOG_TWITTER_TYPE: Twitter Card type for the post object;
|
||||
(default: ``Summary``)
|
||||
* BLOG_TWITTER_TYPES: Choices of available blog types for twitter;
|
||||
(default: to ``META_TWITTER_TYPES`` defined in `django-meta-mixin settings`_)
|
||||
* BLOG_TWITTER_SITE: Twitter account of the site
|
||||
* BLOG_TWITTER_AUTHOR: Twitter account of the post author
|
||||
* BLOG_GPLUS_TYPE: Google+ Snippet type for the post object;
|
||||
(default: ``Blog``)
|
||||
* BLOG_GPLUS_TYPES: Choices of available blog types for twitter;
|
||||
(default: to ``META_GPLUS_TYPES`` defined in `django-meta-mixin settings`_)
|
||||
* BLOG_GPLUS_AUTHOR: Google+ account of the post author
|
||||
* BLOG_ENABLE_COMMENTS: Whether to enable comments by default on posts;
|
||||
while ``djangocms_blog`` does not ship any comment system, this flag
|
||||
can be used to control the chosen comments framework; (default: ``True``)
|
||||
* BLOG_USE_ABSTRACT: Use an abstract field for the post; if ``False``
|
||||
no abstract field is available for every post; (default: ``True``)
|
||||
* BLOG_USE_PLACEHOLDER: Post content is managed via placeholder;
|
||||
if ``False`` a simple HTMLField is used; (default: ``True``)
|
||||
* BLOG_MULTISITE: Add support for multisite setup; (default: ``True``)
|
||||
* BLOG_MENU_TYPE: Structure of the Blog menu;
|
||||
(default: ``Posts and Categories``)
|
||||
* BLOG_AUTHOR_DEFAULT: Use a default if not specified; if set to ``True`` the
|
||||
current user is set as the default author, if set to ``False`` no default
|
||||
author is set, if set to a string the user with the provided username is
|
||||
used; (default: ``True``)
|
||||
* BLOG_DEFAULT_PUBLISHED: If posts are marked as published by default;
|
||||
(default: ``False``)
|
||||
* BLOG_AVAILABLE_PERMALINK_STYLES: Choices of permalinks styles;
|
||||
* BLOG_PERMALINK_URLS: URLConf corresponding to
|
||||
BLOG_AVAILABLE_PERMALINK_STYLES;
|
||||
* BLOG_AUTO_SETUP: Enable the blog **Auto setup** feature; (default: ``True``)
|
||||
* BLOG_AUTO_HOME_TITLE: Title of the home page created by **Auto setup**;
|
||||
(default: ``Home``)
|
||||
* BLOG_AUTO_BLOG_TITLE: Title of the blog page created by **Auto setup**;
|
||||
(default: ``Blog``)
|
||||
* BLOG_AUTO_APP_TITLE: Title of the ``BlogConfig`` instance created by
|
||||
**Auto setup**; (default: ``Blog``)
|
||||
|
||||
Per-Apphook settings
|
||||
--------------------
|
||||
|
||||
* application title: Free text title that can be used as title in templates;
|
||||
* Post published by default: Per-Apphook setting for BLOG_DEFAULT_PUBLISHED;
|
||||
* Permalink structure: Per-Apphook setting for
|
||||
BLOG_AVAILABLE_PERMALINK_STYLES;
|
||||
* Use placeholder and plugins for article body: Per-Apphook setting for
|
||||
BLOG_USE_PLACEHOLDER;
|
||||
* Use abstract field: Per-Apphook setting for BLOG_USE_ABSTRACT;
|
||||
* Set author: Per-Apphook setting for BLOG_AUTHOR_DEFAULT;
|
||||
* Paginate sizePer-Apphook setting for BLOG_PAGINATION;
|
||||
* Template prefix: Alternative directory to load the blog templates from;
|
||||
* Menu structure: Per-Apphook setting for BLOG_MENU_TYPE
|
||||
* Object type: Per-Apphook setting for BLOG_TYPE
|
||||
* Facebook type: Per-Apphook setting for BLOG_FB_TYPE
|
||||
* Facebook application ID: Per-Apphook setting for BLOG_FB_APP_ID
|
||||
* Facebook profile ID: Per-Apphook setting for BLOG_FB_PROFILE_ID
|
||||
* Facebook page URL: Per-Apphook setting for BLOG_FB_PUBLISHER
|
||||
* Facebook author URL: Per-Apphook setting for BLOG_AUTHOR_URL
|
||||
* Facebook author: Per-Apphook setting for BLOG_AUTHOR
|
||||
* Twitter type: Per-Apphook setting for BLOG_TWITTER_TYPE
|
||||
* Twitter site handle: Per-Apphook setting for BLOG_TWITTER_SITE
|
||||
* Twitter author handle: Per-Apphook setting for BLOG_TWITTER_AUTHOR
|
||||
* Google+ type: Per-Apphook setting for BLOG_GPLUS_TYPE
|
||||
* Google+ author name: Per-Apphook setting for BLOG_GPLUS_AUTHOR
|
||||
|
||||
* Placeholder content editing
|
||||
* Frontend editing using django CMS 3.0 frontend editor
|
||||
* Multilingual support using django-parler
|
||||
* Support for Twitter cards, Open Graph and Google+ snippets meta tags
|
||||
* Optional support for simpler TextField-based content editing
|
||||
* Multisite support (posts can be visible in one or more Django sites on the same project)
|
||||
|
||||
Import from Wordpress
|
||||
+++++++++++++++++++++
|
||||
|
@ -182,49 +344,11 @@ If you want to import content from existing wordpress blog, check
|
|||
https://pypi.python.org/pypi/the-real-django-wordpress and
|
||||
this gist https://gist.github.com/yakky/11336204 as a base.
|
||||
|
||||
|
||||
Settings
|
||||
--------
|
||||
* BLOG_ENABLE_COMMENTS: Whether to enable comments by default on posts;
|
||||
while ``djangocms_blog`` does not ship any comment system, this flag can be used
|
||||
to control the chosen comments framework; (default: True)
|
||||
* BLOG_USE_PLACEHOLDER: Post content is managed via placeholder; if ``False`` a
|
||||
simple HTMLField is used; (default: True)
|
||||
* BLOG_USE_ABSTRACT: Use an abstract field for the post; if ``False`` no abstract field
|
||||
is available for every post; (default: True)
|
||||
* BLOG_IMAGE_THUMBNAIL_SIZE: Size of the main image when shown on the post lists;
|
||||
it's a dictionary with ``size``, ``crop`` and ``upscale`` keys;
|
||||
(default: ``{'size': '120x120', 'crop': True,'upscale': False}``)
|
||||
* BLOG_IMAGE_FULL_SIZE: Size of the main image when shown on the post detail;
|
||||
it's a dictionary with ``size``, ``crop`` and ``upscale`` keys;
|
||||
(default: ``{'size': '640x120', 'crop': True,'upscale': False}``)
|
||||
* BLOG_PAGINATION: Number of post per page; (default: 10)
|
||||
* BLOG_LATEST_POSTS: Default number of post in the **Latest post** plugin; (default: 5)
|
||||
* BLOG_POSTS_LIST_TRUNCWORDS_COUNT: Default number of words shown for abstract in the post list; (default: 100)
|
||||
* BLOG_MULTISITE: Add support for multisite setup
|
||||
* BLOG_AUTHOR_DEFAULT: Use a default if not specified; if set to ``True`` the
|
||||
current user is set as the default author, if set to ``False`` no default
|
||||
author is set, if set to a string the user with the provided username is
|
||||
used; (default: True)
|
||||
|
||||
Social media tags settings
|
||||
++++++++++++++++++++++++++
|
||||
* BLOG_TYPE: Generic type for the post object; (default: Article)
|
||||
* BLOG_FB_TYPE: Open Graph type for the post object; (default: Article)
|
||||
* BLOG_FB_APPID: Facebook Application ID
|
||||
* BLOG_FB_PROFILE_ID: Facebook profile ID of the post author
|
||||
* BLOG_FB_PUBLISHER: Facebook URL of the blog publisher
|
||||
* BLOG_FB_AUTHOR_URL: Facebook profile URL of the post author
|
||||
* BLOG_FB_AUTHOR: Facebook profile URL of the post author
|
||||
* BLOG_TWITTER_TYPE: Twitter Card type for the post object; (default: Summary)
|
||||
* BLOG_TWITTER_SITE: Twitter account of the site
|
||||
* BLOG_TWITTER_AUTHOR: Twitter account of the post author
|
||||
* BLOG_GPLUS_TYPE: Google+ Snippet type for the post object; (default: Blog)
|
||||
* BLOG_GPLUS_AUTHOR: Google+ account of the post author
|
||||
|
||||
|
||||
Known djangocms-blog websites
|
||||
+++++++++++++++++++++++++++++
|
||||
|
||||
* http://nephila.co.uk/blog
|
||||
* https://blog.ungleich.ch/
|
||||
|
||||
|
||||
.. _django-meta-mixin settings: https://github.com/nephila/django-meta-mixin#settings
|
||||
|
|
|
@ -18,6 +18,8 @@ HELPER_SETTINGS = dict(
|
|||
'cmsplugin_filer_image',
|
||||
'taggit',
|
||||
'taggit_autosuggest',
|
||||
'aldryn_apphooks_config',
|
||||
'tests.test_utils',
|
||||
],
|
||||
LANGUAGE_CODE='en',
|
||||
LANGUAGES=(
|
||||
|
@ -71,6 +73,9 @@ HELPER_SETTINGS = dict(
|
|||
MIGRATION_MODULES={
|
||||
'cmsplugin_filer_image': 'cmsplugin_filer_image.migrations_django',
|
||||
},
|
||||
CMS_TEMPLATES=(
|
||||
('blog.html', 'Blog template'),
|
||||
),
|
||||
META_SITE_PROTOCOL='http',
|
||||
META_SITE_DOMAIN='example.com',
|
||||
META_USE_OG_PROPERTIES=True,
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
__author__ = 'Iacopo Spalletti'
|
||||
__email__ = 'i.spalletti@nephila.it'
|
||||
__version__ = '0.5.1.dev1'
|
||||
__version__ = '0.6.0.dev1'
|
||||
|
||||
default_app_config = 'djangocms_blog.apps.BlogAppConfig'
|
||||
|
|
|
@ -3,13 +3,17 @@ from __future__ import absolute_import, print_function, unicode_literals
|
|||
|
||||
from copy import deepcopy
|
||||
|
||||
from aldryn_apphooks_config.admin import BaseAppHookConfig, ModelAppHookConfig
|
||||
from cms.admin.placeholderadmin import FrontendEditableAdminMixin, PlaceholderAdminMixin
|
||||
from django import forms
|
||||
from django.conf import settings
|
||||
from django.contrib import admin
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from parler.admin import TranslatableAdmin
|
||||
|
||||
from .cms_appconfig import BlogConfig
|
||||
from .forms import PostAdminForm
|
||||
from .models import BlogCategory, Post
|
||||
from .settings import get_setting
|
||||
|
||||
|
@ -20,27 +24,33 @@ except ImportError:
|
|||
pass
|
||||
|
||||
|
||||
class BlogCategoryAdmin(EnhancedModelAdminMixin, TranslatableAdmin):
|
||||
class BlogCategoryAdmin(EnhancedModelAdminMixin, ModelAppHookConfig, TranslatableAdmin):
|
||||
def get_prepopulated_fields(self, request, obj=None):
|
||||
app_config_default = self._app_config_select(request, obj)
|
||||
if app_config_default is None and request.method == 'GET':
|
||||
return {}
|
||||
return {'slug': ('name',)}
|
||||
|
||||
class Media:
|
||||
css = {
|
||||
'all': ('%sdjangocms_blog/css/%s' % (settings.STATIC_URL,
|
||||
'djangocms_blog_admin.css'),)
|
||||
'all': ('%sdjangocms_blog/css/%s' % (settings.STATIC_URL, 'djangocms_blog_admin.css'),)
|
||||
}
|
||||
|
||||
|
||||
class PostAdmin(EnhancedModelAdminMixin, FrontendEditableAdminMixin,
|
||||
PlaceholderAdminMixin, TranslatableAdmin):
|
||||
list_display = ['title', 'author', 'date_published', 'date_published_end']
|
||||
class PostAdmin(PlaceholderAdminMixin, FrontendEditableAdminMixin,
|
||||
ModelAppHookConfig, TranslatableAdmin):
|
||||
form = PostAdminForm
|
||||
list_display = [
|
||||
'title', 'author', 'date_published', 'app_config', 'languages', 'date_published_end'
|
||||
]
|
||||
list_filter = ('app_config',)
|
||||
date_hierarchy = 'date_published'
|
||||
raw_id_fields = ['author']
|
||||
frontend_editable_fields = ('title', 'abstract', 'post_text')
|
||||
enhance_exclude = ('main_image', 'tags')
|
||||
_fieldsets = [
|
||||
(None, {
|
||||
'fields': [('title', 'categories', 'publish')]
|
||||
'fields': [('title', 'categories', 'publish', 'app_config')]
|
||||
}),
|
||||
('Info', {
|
||||
'fields': (['slug', 'tags'],
|
||||
|
@ -57,6 +67,13 @@ class PostAdmin(EnhancedModelAdminMixin, FrontendEditableAdminMixin,
|
|||
}),
|
||||
]
|
||||
|
||||
app_config_values = {
|
||||
'default_published': 'publish'
|
||||
}
|
||||
|
||||
def languages(self, obj):
|
||||
return ','.join(obj.get_available_languages())
|
||||
|
||||
def formfield_for_dbfield(self, db_field, **kwargs):
|
||||
field = super(PostAdmin, self).formfield_for_dbfield(db_field, **kwargs)
|
||||
if db_field.name == 'meta_description':
|
||||
|
@ -68,11 +85,25 @@ class PostAdmin(EnhancedModelAdminMixin, FrontendEditableAdminMixin,
|
|||
return field
|
||||
|
||||
def get_fieldsets(self, request, obj=None):
|
||||
app_config_default = self._app_config_select(request, obj)
|
||||
if app_config_default is None and request.method == 'GET':
|
||||
return super(PostAdmin, self).get_fieldsets(request, obj)
|
||||
if not obj:
|
||||
config = app_config_default
|
||||
else:
|
||||
config = obj.app_config
|
||||
|
||||
fsets = deepcopy(self._fieldsets)
|
||||
if get_setting('USE_ABSTRACT'):
|
||||
fsets[0][1]['fields'].append('abstract')
|
||||
if not get_setting('USE_PLACEHOLDER'):
|
||||
fsets[0][1]['fields'].append('post_text')
|
||||
if config:
|
||||
if config.use_abstract:
|
||||
fsets[0][1]['fields'].append('abstract')
|
||||
if not config.use_placeholder:
|
||||
fsets[0][1]['fields'].append('post_text')
|
||||
else:
|
||||
if get_setting('USE_ABSTRACT'):
|
||||
fsets[0][1]['fields'].append('abstract')
|
||||
if not get_setting('USE_PLACEHOLDER'):
|
||||
fsets[0][1]['fields'].append('post_text')
|
||||
if get_setting('MULTISITE'):
|
||||
fsets[1][1]['fields'][0].append('sites')
|
||||
if request.user.is_superuser:
|
||||
|
@ -83,7 +114,7 @@ class PostAdmin(EnhancedModelAdminMixin, FrontendEditableAdminMixin,
|
|||
return {'slug': ('title',)}
|
||||
|
||||
def save_model(self, request, obj, form, change):
|
||||
if not obj.author_id and get_setting('AUTHOR_DEFAULT'):
|
||||
if not obj.author_id and obj.app_config.set_author:
|
||||
if get_setting('AUTHOR_DEFAULT') is True:
|
||||
user = request.user
|
||||
else:
|
||||
|
@ -93,10 +124,63 @@ class PostAdmin(EnhancedModelAdminMixin, FrontendEditableAdminMixin,
|
|||
|
||||
class Media:
|
||||
css = {
|
||||
'all': ('%sdjangocms_blog/css/%s' % (settings.STATIC_URL,
|
||||
'djangocms_blog_admin.css'),)
|
||||
'all': ('%sdjangocms_blog/css/%s' % (settings.STATIC_URL, 'djangocms_blog_admin.css'),)
|
||||
}
|
||||
|
||||
|
||||
class BlogConfigAdmin(BaseAppHookConfig, TranslatableAdmin):
|
||||
|
||||
@property
|
||||
def declared_fieldsets(self):
|
||||
return [
|
||||
(None, {
|
||||
'fields': ('type', 'namespace', 'app_title')
|
||||
}),
|
||||
('Generic', {
|
||||
'fields': (
|
||||
'config.default_published', 'config.use_placeholder', 'config.use_abstract',
|
||||
'config.set_author',
|
||||
)
|
||||
}),
|
||||
('Layout', {
|
||||
'fields': (
|
||||
'config.paginate_by', 'config.url_patterns', 'config.template_prefix',
|
||||
'config.menu_structure',
|
||||
),
|
||||
'classes': ('collapse',)
|
||||
}),
|
||||
('Meta', {
|
||||
'fields': (
|
||||
'config.object_type',
|
||||
)
|
||||
}),
|
||||
('Open Graph', {
|
||||
'fields': (
|
||||
'config.og_type', 'config.og_app_id', 'config.og_profile_id',
|
||||
'config.og_publisher', 'config.og_author_url', 'config.og_author',
|
||||
),
|
||||
'description': _(
|
||||
'You can provide plain strings, Post model attribute or method names'
|
||||
)
|
||||
}),
|
||||
('Twitter', {
|
||||
'fields': (
|
||||
'config.twitter_type', 'config.twitter_site', 'config.twitter_author',
|
||||
),
|
||||
'description': _(
|
||||
'You can provide plain strings, Post model attribute or method names'
|
||||
)
|
||||
}),
|
||||
('Google+', {
|
||||
'fields': (
|
||||
'config.gplus_type', 'config.gplus_author',
|
||||
),
|
||||
'description': _(
|
||||
'You can provide plain strings, Post model attribute or method names'
|
||||
)
|
||||
}),
|
||||
]
|
||||
|
||||
admin.site.register(BlogCategory, BlogCategoryAdmin)
|
||||
admin.site.register(Post, PostAdmin)
|
||||
admin.site.register(BlogConfig, BlogConfigAdmin)
|
||||
|
|
65
djangocms_blog/apps.py
Normal file
65
djangocms_blog/apps.py
Normal file
|
@ -0,0 +1,65 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import absolute_import, print_function, unicode_literals
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
try:
|
||||
from django.apps import AppConfig
|
||||
except ImportError:
|
||||
class AppConfig(object):
|
||||
pass
|
||||
|
||||
|
||||
class BlogAppConfig(AppConfig):
|
||||
name = 'djangocms_blog'
|
||||
verbose_name = _('django CMS Blog')
|
||||
|
||||
@staticmethod
|
||||
def setup():
|
||||
from cms.api import create_page, create_title
|
||||
from cms.exceptions import NoHomeFound
|
||||
from cms.models import Page
|
||||
from cms.utils import get_language_list
|
||||
from cms.utils.conf import get_templates
|
||||
from django.utils.translation import override
|
||||
|
||||
from .cms_appconfig import BlogConfig
|
||||
from .settings import get_setting
|
||||
|
||||
if get_setting('AUTO_SETUP'):
|
||||
configs = BlogConfig.objects.all()
|
||||
if not configs.exists():
|
||||
config = BlogConfig.objects.create(namespace='Blog')
|
||||
langs = get_language_list()
|
||||
blog = None
|
||||
for lang in langs:
|
||||
with override(lang):
|
||||
config.set_current_language(lang)
|
||||
config.app_title = get_setting('AUTO_APP_TITLE')
|
||||
config.save()
|
||||
default_template = get_templates()[0][0]
|
||||
try:
|
||||
home = Page.objects.get_home()
|
||||
except NoHomeFound:
|
||||
home = None
|
||||
if not home:
|
||||
home = create_page(
|
||||
get_setting('AUTO_HOME_TITLE'), language=lang,
|
||||
template=default_template, in_navigation=True, published=True
|
||||
)
|
||||
elif lang not in home.get_languages():
|
||||
create_title(
|
||||
language=lang, title=get_setting('AUTO_HOME_TITLE'), page=home
|
||||
)
|
||||
home.publish(lang)
|
||||
if not blog:
|
||||
blog = create_page(
|
||||
get_setting('AUTO_BLOG_TITLE'), language=lang, apphook='BlogApp',
|
||||
apphook_namespace=config.namespace, parent=home,
|
||||
template=default_template, in_navigation=True, published=True
|
||||
)
|
||||
else:
|
||||
create_title(
|
||||
language=lang, title=get_setting('AUTO_BLOG_TITLE'), page=blog
|
||||
)
|
||||
blog.publish(lang)
|
|
@ -1,17 +1,19 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import absolute_import, print_function, unicode_literals
|
||||
|
||||
from cms.app_base import CMSApp
|
||||
from aldryn_apphooks_config.app_base import CMSConfigApp
|
||||
from cms.apphook_pool import apphook_pool
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from .cms_appconfig import BlogConfig
|
||||
from .menu import BlogCategoryMenu
|
||||
|
||||
|
||||
class BlogApp(CMSApp):
|
||||
class BlogApp(CMSConfigApp):
|
||||
name = _('Blog')
|
||||
urls = ['djangocms_blog.urls']
|
||||
app_name = 'djangocms_blog'
|
||||
app_config = BlogConfig
|
||||
menus = [BlogCategoryMenu]
|
||||
|
||||
apphook_pool.register(BlogApp)
|
||||
|
|
110
djangocms_blog/cms_appconfig.py
Normal file
110
djangocms_blog/cms_appconfig.py
Normal file
|
@ -0,0 +1,110 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import absolute_import, print_function, unicode_literals
|
||||
|
||||
from aldryn_apphooks_config.models import AppHookConfig
|
||||
from aldryn_apphooks_config.utils import setup_config
|
||||
from app_data import AppDataForm
|
||||
from django import forms
|
||||
from django.db import models
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from parler.models import TranslatableModel, TranslatedFields
|
||||
|
||||
from .settings import MENU_TYPE_COMPLETE, get_setting
|
||||
|
||||
|
||||
class BlogConfig(TranslatableModel, AppHookConfig):
|
||||
"""
|
||||
Adds some translatable, per-app-instance fields.
|
||||
"""
|
||||
translations = TranslatedFields(
|
||||
app_title=models.CharField(_('application title'), max_length=234),
|
||||
)
|
||||
|
||||
def get_app_title(self):
|
||||
return getattr(self, 'app_title', _('untitled'))
|
||||
|
||||
|
||||
class BlogConfigForm(AppDataForm):
|
||||
default_published = forms.BooleanField(
|
||||
label=_('Post published by default'), required=False,
|
||||
initial=get_setting('DEFAULT_PUBLISHED')
|
||||
)
|
||||
url_patterns = forms.ChoiceField(
|
||||
label=_('Permalink structure'), required=False,
|
||||
initial=get_setting('AVAILABLE_PERMALINK_STYLES')[0][0],
|
||||
choices=get_setting('AVAILABLE_PERMALINK_STYLES')
|
||||
)
|
||||
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')
|
||||
)
|
||||
menu_structure = forms.ChoiceField(
|
||||
label=_('Menu structure'), required=True,
|
||||
choices=get_setting('MENU_TYPES'), initial=MENU_TYPE_COMPLETE,
|
||||
help_text=_('Structure of the django CMS menu')
|
||||
)
|
||||
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_TYPE')
|
||||
)
|
||||
og_app_id = forms.CharField(
|
||||
max_length=200, label=_('Facebook application ID'), required=False,
|
||||
initial=get_setting('FB_PROFILE_ID')
|
||||
)
|
||||
og_profile_id = forms.CharField(
|
||||
max_length=200, label=_('Facebook profile ID'), required=False,
|
||||
initial=get_setting('FB_PROFILE_ID')
|
||||
)
|
||||
og_publisher = forms.CharField(
|
||||
max_length=200, label=_('Facebook page URL'), required=False,
|
||||
initial=get_setting('FB_PUBLISHER')
|
||||
)
|
||||
og_author_url = forms.CharField(
|
||||
max_length=200, label=_('Facebook author URL'), required=False,
|
||||
initial=get_setting('FB_AUTHOR_URL')
|
||||
)
|
||||
og_author = forms.CharField(
|
||||
max_length=200, label=_('Facebook author'), required=False,
|
||||
initial=get_setting('FB_AUTHOR')
|
||||
)
|
||||
twitter_type = forms.ChoiceField(
|
||||
label=_('Twitter type'), required=False,
|
||||
choices=get_setting('TWITTER_TYPES'), initial=get_setting('TWITTER_TYPE')
|
||||
)
|
||||
twitter_site = forms.CharField(
|
||||
max_length=200, label=_('Twitter site handle'), required=False,
|
||||
initial=get_setting('TWITTER_SITE')
|
||||
)
|
||||
twitter_author = forms.CharField(
|
||||
max_length=200, label=_('Twitter author handle'), required=False,
|
||||
initial=get_setting('TWITTER_AUTHOR')
|
||||
)
|
||||
gplus_type = forms.ChoiceField(
|
||||
label=_('Google+ type'), required=False,
|
||||
choices=get_setting('GPLUS_TYPES'), initial=get_setting('GPLUS_TYPE')
|
||||
)
|
||||
gplus_author = forms.CharField(
|
||||
max_length=200, label=_('Google+ author name'), required=False,
|
||||
initial=get_setting('GPLUS_AUTHOR')
|
||||
)
|
||||
setup_config(BlogConfigForm, BlogConfig)
|
|
@ -1,32 +1,39 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import absolute_import, print_function, unicode_literals
|
||||
|
||||
from cms.models.pluginmodel import CMSPlugin
|
||||
import os.path
|
||||
|
||||
from cms.plugin_base import CMSPluginBase
|
||||
from cms.plugin_pool import plugin_pool
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from .forms import LatestEntriesForm
|
||||
from .models import AuthorEntriesPlugin, BlogCategory, LatestPostsPlugin, Post
|
||||
from .models import AuthorEntriesPlugin, BlogCategory, GenericBlogPlugin, LatestPostsPlugin, Post
|
||||
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)
|
||||
|
@ -39,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)
|
||||
|
@ -57,8 +64,7 @@ class BlogAuthorPostsPlugin(BlogPlugin):
|
|||
module = _('Blog')
|
||||
name = _('Author Blog Articles')
|
||||
model = AuthorEntriesPlugin
|
||||
form = LatestEntriesForm
|
||||
render_template = 'djangocms_blog/plugins/authors.html'
|
||||
base_render_template = 'plugins/authors.html'
|
||||
filter_horizontal = ['authors']
|
||||
|
||||
def render(self, context, instance, placeholder):
|
||||
|
@ -70,36 +76,47 @@ class BlogAuthorPostsPlugin(BlogPlugin):
|
|||
class BlogTagsPlugin(BlogPlugin):
|
||||
module = _('Blog')
|
||||
name = _('Tags')
|
||||
model = CMSPlugin
|
||||
render_template = 'djangocms_blog/plugins/tags.html'
|
||||
model = GenericBlogPlugin
|
||||
base_render_template = 'plugins/tags.html'
|
||||
|
||||
def render(self, context, instance, placeholder):
|
||||
context = super(BlogTagsPlugin, self).render(context, instance, placeholder)
|
||||
context['tags'] = Post.objects.tag_cloud(queryset=Post.objects.published())
|
||||
qs = Post._default_manager
|
||||
qs_post = qs
|
||||
if instance.app_config:
|
||||
qs_post = qs_post.namespace(instance.app_config.namespace)
|
||||
context['tags'] = qs.tag_cloud(queryset=qs_post.published())
|
||||
return context
|
||||
|
||||
|
||||
class BlogCategoryPlugin(BlogPlugin):
|
||||
module = _('Blog')
|
||||
name = _('Categories')
|
||||
model = CMSPlugin
|
||||
render_template = 'djangocms_blog/plugins/categories.html'
|
||||
model = GenericBlogPlugin
|
||||
base_render_template = 'plugins/categories.html'
|
||||
|
||||
def render(self, context, instance, placeholder):
|
||||
context = super(BlogCategoryPlugin, self).render(context, instance, placeholder)
|
||||
context['categories'] = BlogCategory.objects.all()
|
||||
qs = BlogCategory._default_manager
|
||||
if instance.app_config:
|
||||
qs = qs.namespace(instance.app_config.namespace)
|
||||
context['categories'] = qs
|
||||
return context
|
||||
|
||||
|
||||
class BlogArchivePlugin(BlogPlugin):
|
||||
module = _('Blog')
|
||||
name = _('Archive')
|
||||
model = CMSPlugin
|
||||
render_template = 'djangocms_blog/plugins/archive.html'
|
||||
model = GenericBlogPlugin
|
||||
base_render_template = 'plugins/archive.html'
|
||||
|
||||
def render(self, context, instance, placeholder):
|
||||
context = super(BlogArchivePlugin, self).render(context, instance, placeholder)
|
||||
context['dates'] = Post.objects.get_months(queryset=Post.objects.published())
|
||||
qs = Post._default_manager
|
||||
qs_post = qs
|
||||
if instance.app_config:
|
||||
qs_post = qs.namespace(instance.app_config.namespace)
|
||||
context['dates'] = qs.get_months(queryset=qs_post.published())
|
||||
return context
|
||||
|
||||
|
||||
|
|
|
@ -4,9 +4,9 @@ from __future__ import absolute_import, print_function, unicode_literals
|
|||
from cms.toolbar_base import CMSToolbar
|
||||
from cms.toolbar_pool import toolbar_pool
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.utils.translation import override, ugettext_lazy as _
|
||||
|
||||
from .models import BLOG_CURRENT_POST_IDENTIFIER
|
||||
from .models import BLOG_CURRENT_NAMESPACE, BLOG_CURRENT_POST_IDENTIFIER
|
||||
|
||||
|
||||
@toolbar_pool.register
|
||||
|
@ -17,16 +17,21 @@ class BlogToolbar(CMSToolbar):
|
|||
if not self.request.user.has_perm('djangocms_blog.add_post'):
|
||||
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)
|
||||
url = reverse('admin:djangocms_blog_post_add')
|
||||
admin_menu.add_modal_item(_('Add post'), url=url)
|
||||
with override(self.current_lang):
|
||||
url = reverse('admin:djangocms_blog_post_changelist')
|
||||
admin_menu.add_modal_item(_('Post list'), url=url)
|
||||
url = reverse('admin:djangocms_blog_post_add')
|
||||
admin_menu.add_modal_item(_('Add post'), url=url)
|
||||
current_config = getattr(self.request, BLOG_CURRENT_NAMESPACE, None)
|
||||
if current_config:
|
||||
url = reverse('admin:djangocms_blog_blogconfig_change', args=(current_config.pk,))
|
||||
admin_menu.add_modal_item(_('Edit configuration'), 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'): # pragma: no cover # NOQA
|
||||
admin_menu.add_modal_item(_('Edit Post'), reverse(
|
||||
'admin:djangocms_blog_post_change', args=(current_post.pk,)),
|
||||
active=True)
|
||||
current_post = getattr(self.request, BLOG_CURRENT_POST_IDENTIFIER, None)
|
||||
if current_post and self.request.user.has_perm('djangocms_blog.change_post'): # pragma: no cover # NOQA
|
||||
admin_menu.add_modal_item(_('Edit Post'), reverse(
|
||||
'admin:djangocms_blog_post_change', args=(current_post.pk,)),
|
||||
active=True)
|
||||
|
||||
def post_template_populate(self):
|
||||
current_post = getattr(self.request, BLOG_CURRENT_POST_IDENTIFIER, None)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import absolute_import, print_function, unicode_literals
|
||||
|
||||
from aldryn_apphooks_config.utils import get_app_instance
|
||||
from django.contrib.sites.models import Site
|
||||
from django.contrib.syndication.views import Feed
|
||||
from django.core.urlresolvers import reverse
|
||||
|
@ -12,14 +13,18 @@ from .settings import get_setting
|
|||
|
||||
class LatestEntriesFeed(Feed):
|
||||
|
||||
def __call__(self, request, *args, **kwargs):
|
||||
self.namespace, self.config = get_app_instance(request)
|
||||
return super(LatestEntriesFeed, self).__call__(request, *args, **kwargs)
|
||||
|
||||
def link(self):
|
||||
return reverse('djangocms_blog:posts-latest')
|
||||
return reverse('%s:posts-latest' % self.namespace, current_app=self.namespace)
|
||||
|
||||
def title(self):
|
||||
return _('Blog articles on %(site_name)s') % {'site_name': Site.objects.get_current().name}
|
||||
|
||||
def items(self, obj=None):
|
||||
return Post.objects.published().order_by('-date_published')[:10]
|
||||
return Post.objects.namespace(self.namespace).published().order_by('-date_published')[:10]
|
||||
|
||||
def item_title(self, item):
|
||||
return item.safe_translation_getter('title')
|
||||
|
|
|
@ -3,8 +3,11 @@ from __future__ import absolute_import, print_function, unicode_literals
|
|||
|
||||
from django import forms
|
||||
from django.conf import settings
|
||||
from parler.forms import TranslatableModelForm
|
||||
from taggit_autosuggest.widgets import TagAutoSuggest
|
||||
|
||||
from .models import BlogCategory, BlogConfig, Post
|
||||
|
||||
|
||||
class LatestEntriesForm(forms.ModelForm):
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
@ -16,3 +19,29 @@ class LatestEntriesForm(forms.ModelForm):
|
|||
'all': ('%sdjangocms_blog/css/%s' % (settings.STATIC_URL,
|
||||
'djangocms_blog_admin.css'),)
|
||||
}
|
||||
|
||||
|
||||
class PostAdminForm(TranslatableModelForm):
|
||||
|
||||
class Meta:
|
||||
model = Post
|
||||
fields = '__all__'
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(PostAdminForm, self).__init__(*args, **kwargs)
|
||||
|
||||
qs = BlogCategory.objects
|
||||
|
||||
if getattr(self.instance, 'app_config_id', None):
|
||||
qs = qs.namespace(self.instance.app_config.namespace)
|
||||
elif 'initial' in kwargs and 'app_config' in kwargs['initial']:
|
||||
config = BlogConfig.objects.get(pk=kwargs['initial']['app_config'])
|
||||
qs = qs.namespace(config.namespace)
|
||||
|
||||
if 'categories' in self.fields:
|
||||
self.fields['categories'].queryset = qs
|
||||
|
||||
if 'app_config' in self.fields:
|
||||
# Don't allow app_configs to be added here. The correct way to add an
|
||||
# apphook-config is to create an apphook on a cms Page.
|
||||
self.fields['app_config'].widget.can_add_related = False
|
||||
|
|
|
@ -6,7 +6,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2014-11-30 12:50+0100\n"
|
||||
"POT-Creation-Date: 2015-09-30 09:56+0200\n"
|
||||
"PO-Revision-Date: 2014-03-05 18:09+0100\n"
|
||||
"Last-Translator: Iacopo Spalletti\n"
|
||||
"Language-Team: Italian <i.spalletti@nephila.it>\n"
|
||||
|
@ -17,189 +17,361 @@ msgstr ""
|
|||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"X-Generator: Lokalize 1.5\n"
|
||||
|
||||
#: cms_app.py:8 cms_plugins.py:32 cms_plugins.py:45 cms_plugins.py:56
|
||||
#: cms_plugins.py:67 cms_toolbar.py:18
|
||||
#: cms_app.py:13 cms_plugins.py:64 cms_plugins.py:77 cms_plugins.py:93
|
||||
#: cms_plugins.py:108 cms_toolbar.py:19
|
||||
msgid "Blog"
|
||||
msgstr "Blog"
|
||||
|
||||
#: cms_plugins.py:20
|
||||
#: cms_appconfig.py:20
|
||||
msgid "application title"
|
||||
msgstr ""
|
||||
|
||||
#: cms_appconfig.py:24
|
||||
#, fuzzy
|
||||
msgid "untitled"
|
||||
msgstr "Title"
|
||||
|
||||
#: cms_appconfig.py:29
|
||||
msgid "Post published by default"
|
||||
msgstr ""
|
||||
|
||||
#: cms_appconfig.py:33
|
||||
msgid "Permalink structure"
|
||||
msgstr ""
|
||||
|
||||
#: cms_appconfig.py:38
|
||||
msgid "Use placeholder and plugins for article body"
|
||||
msgstr ""
|
||||
|
||||
#: cms_appconfig.py:42
|
||||
msgid "Use abstract field"
|
||||
msgstr ""
|
||||
|
||||
#: cms_appconfig.py:46
|
||||
#, fuzzy
|
||||
msgid "Set author"
|
||||
msgstr "Author"
|
||||
|
||||
#: cms_appconfig.py:46
|
||||
msgid "Set author by default"
|
||||
msgstr ""
|
||||
|
||||
#: cms_appconfig.py:50
|
||||
msgid "Paginate size"
|
||||
msgstr ""
|
||||
|
||||
#: cms_appconfig.py:51
|
||||
msgid "When paginating list views, how many articles per page?"
|
||||
msgstr ""
|
||||
|
||||
#: cms_appconfig.py:54
|
||||
msgid "Template prefix"
|
||||
msgstr ""
|
||||
|
||||
#: cms_appconfig.py:55
|
||||
msgid "Alternative directory to load the blog templates from"
|
||||
msgstr ""
|
||||
|
||||
#: cms_appconfig.py:58
|
||||
msgid "Object type"
|
||||
msgstr ""
|
||||
|
||||
#: cms_appconfig.py:62
|
||||
msgid "Facebook type"
|
||||
msgstr ""
|
||||
|
||||
#: cms_appconfig.py:66
|
||||
msgid "Facebook application ID"
|
||||
msgstr ""
|
||||
|
||||
#: cms_appconfig.py:69
|
||||
msgid "Facebook profile ID"
|
||||
msgstr ""
|
||||
|
||||
#: cms_appconfig.py:72
|
||||
msgid "Facebook page URL"
|
||||
msgstr ""
|
||||
|
||||
#: cms_appconfig.py:75
|
||||
msgid "Facebook author URL"
|
||||
msgstr ""
|
||||
|
||||
#: cms_appconfig.py:78
|
||||
msgid "Twitter type"
|
||||
msgstr ""
|
||||
|
||||
#: cms_appconfig.py:82
|
||||
msgid "Twitter site handle"
|
||||
msgstr ""
|
||||
|
||||
#: cms_appconfig.py:85
|
||||
msgid "Twitter author handle"
|
||||
msgstr ""
|
||||
|
||||
#: cms_appconfig.py:88
|
||||
msgid "Google+ type"
|
||||
msgstr ""
|
||||
|
||||
#: cms_appconfig.py:92
|
||||
msgid "Google+ author name"
|
||||
msgstr ""
|
||||
|
||||
#: cms_plugins.py:30 cms_plugins.py:49
|
||||
msgid "Latest Blog Articles"
|
||||
msgstr "Latest Blog Articles"
|
||||
|
||||
#: cms_plugins.py:33
|
||||
#: cms_plugins.py:65
|
||||
msgid "Author Blog Articles"
|
||||
msgstr "Author Blog Articles"
|
||||
|
||||
#: cms_plugins.py:46 templates/djangocms_blog/plugins/tags.html:4
|
||||
#: cms_plugins.py:78 templates/djangocms_blog/plugins/tags.html:3
|
||||
msgid "Tags"
|
||||
msgstr "Tags"
|
||||
|
||||
#: cms_plugins.py:57 templates/djangocms_blog/plugins/categories.html:4
|
||||
#: cms_plugins.py:94 templates/djangocms_blog/plugins/categories.html:3
|
||||
msgid "Categories"
|
||||
msgstr "Categories"
|
||||
|
||||
#: cms_plugins.py:68 templates/djangocms_blog/post_list.html:12
|
||||
#: templates/djangocms_blog/plugins/archive.html:4
|
||||
#: cms_plugins.py:109 templates/djangocms_blog/post_list.html:12
|
||||
#: templates/djangocms_blog/plugins/archive.html:3
|
||||
msgid "Archive"
|
||||
msgstr "Archive"
|
||||
|
||||
#: cms_toolbar.py:20
|
||||
#: cms_toolbar.py:22
|
||||
msgid "Post list"
|
||||
msgstr "Post list"
|
||||
|
||||
#: cms_toolbar.py:22
|
||||
#: cms_toolbar.py:24
|
||||
msgid "Add post"
|
||||
msgstr "Add post"
|
||||
|
||||
#: cms_toolbar.py:26
|
||||
#: cms_toolbar.py:28
|
||||
msgid "Edit configuration"
|
||||
msgstr ""
|
||||
|
||||
#: cms_toolbar.py:32
|
||||
msgid "Edit Post"
|
||||
msgstr ""
|
||||
|
||||
#: feeds.py:16
|
||||
#: feeds.py:24
|
||||
#, python-format
|
||||
msgid "Blog articles on %(site_name)s"
|
||||
msgstr "Blog articles on %(site_name)s"
|
||||
|
||||
#: models.py:31
|
||||
#: menu.py:14
|
||||
#, fuzzy
|
||||
msgid "Blog Category menu"
|
||||
msgstr "blog category"
|
||||
|
||||
#: models.py:34
|
||||
msgid "parent"
|
||||
msgstr "parent"
|
||||
|
||||
#: models.py:33
|
||||
#: models.py:35
|
||||
msgid "created at"
|
||||
msgstr "created at"
|
||||
|
||||
#: models.py:34
|
||||
#: models.py:36
|
||||
msgid "modified at"
|
||||
msgstr "modified at"
|
||||
|
||||
#: models.py:37
|
||||
#: models.py:37 models.py:120 models.py:253
|
||||
msgid "app. config"
|
||||
msgstr ""
|
||||
|
||||
#: models.py:40
|
||||
msgid "name"
|
||||
msgstr "name"
|
||||
|
||||
#: models.py:38 models.py:105
|
||||
#: models.py:41 models.py:124
|
||||
msgid "slug"
|
||||
msgstr "slug"
|
||||
|
||||
#: models.py:45
|
||||
#: models.py:48
|
||||
msgid "blog category"
|
||||
msgstr "blog category"
|
||||
|
||||
#: models.py:46
|
||||
#: models.py:49
|
||||
msgid "blog categories"
|
||||
msgstr "blog categories"
|
||||
|
||||
#: models.py:70
|
||||
msgid "Author"
|
||||
#: models.py:89
|
||||
#, fuzzy
|
||||
msgid "author"
|
||||
msgstr "Author"
|
||||
|
||||
#: models.py:75
|
||||
msgid "Published Since"
|
||||
#: models.py:92
|
||||
#, fuzzy
|
||||
msgid "created"
|
||||
msgstr "created at"
|
||||
|
||||
#: models.py:93
|
||||
#, fuzzy
|
||||
msgid "last modified"
|
||||
msgstr "modified at"
|
||||
|
||||
#: models.py:94
|
||||
#, fuzzy
|
||||
msgid "published since"
|
||||
msgstr "Published Since"
|
||||
|
||||
#: models.py:77
|
||||
msgid "Published Until"
|
||||
#: models.py:96
|
||||
#, fuzzy
|
||||
msgid "published until"
|
||||
msgstr "Published Until"
|
||||
|
||||
#: models.py:79
|
||||
msgid "Publish"
|
||||
#: models.py:98
|
||||
#, fuzzy
|
||||
msgid "publish"
|
||||
msgstr "Publish"
|
||||
|
||||
#: models.py:80
|
||||
#: models.py:99
|
||||
msgid "category"
|
||||
msgstr "category"
|
||||
|
||||
#: models.py:82
|
||||
msgid "Main image"
|
||||
#: models.py:101
|
||||
#, fuzzy
|
||||
msgid "main image"
|
||||
msgstr "Main image"
|
||||
|
||||
#: models.py:85
|
||||
msgid "Main image thumbnail"
|
||||
#: models.py:105
|
||||
#, fuzzy
|
||||
msgid "main image thumbnail"
|
||||
msgstr "Main image thumbnail"
|
||||
|
||||
#: models.py:89
|
||||
msgid "Main image full"
|
||||
#: models.py:110
|
||||
#, fuzzy
|
||||
msgid "main image full"
|
||||
msgstr "Main image full"
|
||||
|
||||
#: models.py:93
|
||||
msgid "Enable comments on post"
|
||||
#: models.py:114
|
||||
msgid "enable comments on post"
|
||||
msgstr ""
|
||||
|
||||
#: models.py:96
|
||||
#: models.py:116
|
||||
msgid "Site(s)"
|
||||
msgstr ""
|
||||
|
||||
#: models.py:98
|
||||
#: models.py:117
|
||||
msgid ""
|
||||
"Select sites in which to show the post. If none is set it will be visible in "
|
||||
"all the configured sites."
|
||||
msgstr ""
|
||||
|
||||
#: models.py:104
|
||||
msgid "Title"
|
||||
#: models.py:123
|
||||
#, fuzzy
|
||||
msgid "title"
|
||||
msgstr "Title"
|
||||
|
||||
#: models.py:106
|
||||
msgid "Abstract"
|
||||
#: models.py:125
|
||||
msgid "abstract"
|
||||
msgstr ""
|
||||
|
||||
#: models.py:107
|
||||
msgid "Post meta description"
|
||||
msgstr "Post meta description"
|
||||
|
||||
#: models.py:109
|
||||
#: models.py:126
|
||||
#, fuzzy
|
||||
msgid "Post meta keywords"
|
||||
msgid "post meta description"
|
||||
msgstr "Post meta description"
|
||||
|
||||
#: models.py:111
|
||||
#: models.py:128
|
||||
#, fuzzy
|
||||
msgid "Post meta title"
|
||||
msgid "post meta keywords"
|
||||
msgstr "Post meta description"
|
||||
|
||||
#: models.py:112
|
||||
#: models.py:130
|
||||
#, fuzzy
|
||||
msgid "post meta title"
|
||||
msgstr "Post meta description"
|
||||
|
||||
#: models.py:131
|
||||
msgid "used in title tag and social sharing"
|
||||
msgstr ""
|
||||
|
||||
#: models.py:115
|
||||
msgid "Text"
|
||||
msgstr "Text"
|
||||
#: models.py:134
|
||||
msgid "text"
|
||||
msgstr ""
|
||||
|
||||
#: models.py:178
|
||||
#: models.py:170
|
||||
msgid "blog article"
|
||||
msgstr "blog article"
|
||||
|
||||
#: models.py:179
|
||||
#: models.py:171
|
||||
msgid "blog articles"
|
||||
msgstr "blog articles"
|
||||
|
||||
#: models.py:222 models.py:250
|
||||
msgid "Articles"
|
||||
msgstr "Articles"
|
||||
#: models.py:269
|
||||
msgid "generic blog plugin"
|
||||
msgstr ""
|
||||
|
||||
#: models.py:223
|
||||
#: models.py:273 models.py:306
|
||||
#, fuzzy
|
||||
msgid "articles"
|
||||
msgstr "0 articles"
|
||||
|
||||
#: models.py:274
|
||||
msgid "The number of latests articles to be displayed."
|
||||
msgstr "The number of latests articles to be displayed."
|
||||
|
||||
#: models.py:225
|
||||
#: models.py:276
|
||||
msgid "filter by tag"
|
||||
msgstr ""
|
||||
|
||||
#: models.py:277
|
||||
msgid "Show only the blog articles tagged with chosen tags."
|
||||
msgstr "Show only the blog articles tagged with chosen tags."
|
||||
|
||||
#: models.py:227
|
||||
#: models.py:280
|
||||
#, fuzzy
|
||||
msgid "filter by category"
|
||||
msgstr "blog category"
|
||||
|
||||
#: models.py:281
|
||||
msgid "Show only the blog articles tagged with chosen categories."
|
||||
msgstr "Show only the blog articles tagged with chosen categories."
|
||||
|
||||
#: models.py:246 templates/djangocms_blog/plugins/authors.html:3
|
||||
msgid "Authors"
|
||||
#: models.py:285
|
||||
#, python-format
|
||||
msgid "%s latest articles by tag"
|
||||
msgstr ""
|
||||
|
||||
#: models.py:302
|
||||
#, fuzzy
|
||||
msgid "authors"
|
||||
msgstr "Authors"
|
||||
|
||||
#: models.py:251
|
||||
#: models.py:307
|
||||
msgid "The number of author articles to be displayed."
|
||||
msgstr "The number of author articles to be displayed."
|
||||
|
||||
#: templates/djangocms_blog/post_detail.html:18
|
||||
#: templates/djangocms_blog/includes/blog_item.html:11
|
||||
msgid "by"
|
||||
msgstr "by"
|
||||
#: models.py:311
|
||||
#, python-format
|
||||
msgid "%s latest articles by author"
|
||||
msgstr ""
|
||||
|
||||
#: settings.py:11
|
||||
#, fuzzy
|
||||
msgid "Article"
|
||||
msgstr "Articles"
|
||||
|
||||
#: settings.py:12
|
||||
msgid "Website"
|
||||
msgstr ""
|
||||
|
||||
#: settings.py:17
|
||||
msgid "Full date"
|
||||
msgstr ""
|
||||
|
||||
#: settings.py:18
|
||||
msgid "Year / Month"
|
||||
msgstr ""
|
||||
|
||||
#: settings.py:19 templates/djangocms_blog/post_list.html:14
|
||||
msgid "Category"
|
||||
msgstr "Category"
|
||||
|
||||
#: settings.py:20
|
||||
#, fuzzy
|
||||
msgid "Just slug"
|
||||
msgstr "slug"
|
||||
|
||||
#: templates/djangocms_blog/post_list.html:11
|
||||
msgid "Articles by"
|
||||
|
@ -209,16 +381,11 @@ msgstr "Articles by"
|
|||
msgid "Tag"
|
||||
msgstr "Tag"
|
||||
|
||||
#: templates/djangocms_blog/post_list.html:14
|
||||
msgid "Category"
|
||||
msgstr "Category"
|
||||
|
||||
#: templates/djangocms_blog/post_list.html:21
|
||||
#: templates/djangocms_blog/plugins/archive.html:27
|
||||
#: templates/djangocms_blog/plugins/archive.html:26
|
||||
#: templates/djangocms_blog/plugins/authors.html:15
|
||||
#: templates/djangocms_blog/plugins/categories.html:16
|
||||
#: templates/djangocms_blog/plugins/latest_entries.html:7
|
||||
#: templates/djangocms_blog/plugins/tags.html:16
|
||||
#: templates/djangocms_blog/plugins/tags.html:15
|
||||
msgid "No article found."
|
||||
msgstr "No article found."
|
||||
|
||||
|
@ -226,43 +393,59 @@ msgstr "No article found."
|
|||
msgid "Back"
|
||||
msgstr "Back"
|
||||
|
||||
#: templates/djangocms_blog/post_list.html:30
|
||||
#: templates/djangocms_blog/post_list.html:29
|
||||
msgid "previous"
|
||||
msgstr "previous"
|
||||
|
||||
#: templates/djangocms_blog/post_list.html:33
|
||||
#: templates/djangocms_blog/post_list.html:32
|
||||
msgid "Page"
|
||||
msgstr "Page"
|
||||
|
||||
#: templates/djangocms_blog/post_list.html:33
|
||||
#: templates/djangocms_blog/post_list.html:32
|
||||
msgid "of"
|
||||
msgstr "of"
|
||||
|
||||
#: templates/djangocms_blog/post_list.html:36
|
||||
#: templates/djangocms_blog/post_list.html:35
|
||||
msgid "next"
|
||||
msgstr "next"
|
||||
|
||||
#: templates/djangocms_blog/includes/blog_item.html:46
|
||||
#: templates/djangocms_blog/includes/blog_item.html:24
|
||||
msgid "read more"
|
||||
msgstr "read more"
|
||||
|
||||
#: templates/djangocms_blog/plugins/archive.html:18
|
||||
#: templates/djangocms_blog/includes/blog_meta.html:6
|
||||
msgid "by"
|
||||
msgstr "by"
|
||||
|
||||
#: templates/djangocms_blog/plugins/archive.html:17
|
||||
#: templates/djangocms_blog/plugins/authors.html:10
|
||||
#: templates/djangocms_blog/plugins/categories.html:11
|
||||
#: templates/djangocms_blog/plugins/tags.html:11
|
||||
#: templates/djangocms_blog/plugins/categories.html:10
|
||||
#: templates/djangocms_blog/plugins/tags.html:10
|
||||
#, python-format
|
||||
msgid "1 article"
|
||||
msgid_plural "%(articles)s articles"
|
||||
msgstr[0] "1 article"
|
||||
msgstr[1] "%(articles)s articles"
|
||||
|
||||
#: templates/djangocms_blog/plugins/archive.html:19
|
||||
#: templates/djangocms_blog/plugins/archive.html:18
|
||||
#: templates/djangocms_blog/plugins/authors.html:11
|
||||
#: templates/djangocms_blog/plugins/categories.html:12
|
||||
#: templates/djangocms_blog/plugins/tags.html:12
|
||||
#: templates/djangocms_blog/plugins/categories.html:11
|
||||
#: templates/djangocms_blog/plugins/tags.html:11
|
||||
msgid "0 articles"
|
||||
msgstr "0 articles"
|
||||
|
||||
#: templates/djangocms_blog/plugins/authors.html:3
|
||||
msgid "Authors"
|
||||
msgstr "Authors"
|
||||
|
||||
#: templates/djangocms_blog/plugins/categories.html:15
|
||||
#, fuzzy
|
||||
msgid "No categories found."
|
||||
msgstr "No article found."
|
||||
|
||||
#~ msgid "Text"
|
||||
#~ msgstr "Text"
|
||||
|
||||
#~ msgid "blog post"
|
||||
#~ msgstr "blog post"
|
||||
|
||||
|
|
|
@ -2,10 +2,12 @@
|
|||
from __future__ import absolute_import, print_function, unicode_literals
|
||||
|
||||
import django
|
||||
from aldryn_apphooks_config.managers.parler import (
|
||||
AppHookConfigTranslatableManager, AppHookConfigTranslatableQueryset,
|
||||
)
|
||||
from django.contrib.sites.models import Site
|
||||
from django.db import models
|
||||
from django.utils.timezone import now
|
||||
from parler.managers import TranslatableQuerySet, TranslationManager
|
||||
|
||||
try:
|
||||
from collections import Counter
|
||||
|
@ -21,7 +23,7 @@ class TaggedFilterItem(object):
|
|||
o con gli stessi tag di un model o un queryset
|
||||
"""
|
||||
tags = self._taglist(other_model, queryset)
|
||||
return self.get_queryset().filter(taglist__in=tags)
|
||||
return self.get_queryset().filter(tags__in=tags).distinct()
|
||||
|
||||
def _taglist(self, other_model=None, queryset=None):
|
||||
"""
|
||||
|
@ -29,21 +31,21 @@ class TaggedFilterItem(object):
|
|||
o queryset passati come argomento
|
||||
"""
|
||||
from taggit.models import TaggedItem
|
||||
filtro = None
|
||||
filter = None
|
||||
if queryset is not None:
|
||||
filtro = set()
|
||||
filter = set()
|
||||
for item in queryset.all():
|
||||
filtro.update(item.tags.all())
|
||||
filtro = set([tag.id for tag in filtro])
|
||||
filter.update(item.tags.all())
|
||||
filter = set([tag.id for tag in filter])
|
||||
elif other_model is not None:
|
||||
filtro = set(TaggedItem.objects.filter(
|
||||
filter = set(TaggedItem.objects.filter(
|
||||
content_type__model=other_model.__name__.lower()
|
||||
).values_list('tag_id', flat=True))
|
||||
tags = set(TaggedItem.objects.filter(
|
||||
content_type__model=self.model.__name__.lower()
|
||||
).values_list('tag_id', flat=True))
|
||||
if filtro is not None:
|
||||
tags = tags.intersection(filtro)
|
||||
if filter is not None:
|
||||
tags = tags.intersection(filter)
|
||||
return list(tags)
|
||||
|
||||
def tag_list(self, other_model=None, queryset=None):
|
||||
|
@ -76,7 +78,7 @@ class TaggedFilterItem(object):
|
|||
return sorted(tags, key=lambda x: -x.count)
|
||||
|
||||
|
||||
class GenericDateQuerySet(TranslatableQuerySet):
|
||||
class GenericDateQuerySet(AppHookConfigTranslatableQueryset):
|
||||
start_date_field = 'date_published'
|
||||
end_date_field = 'date_published_end'
|
||||
publish_field = 'publish'
|
||||
|
@ -120,7 +122,7 @@ class GenericDateQuerySet(TranslatableQuerySet):
|
|||
return self.active_translations(language_code=language).on_site()
|
||||
|
||||
|
||||
class GenericDateTaggedManager(TaggedFilterItem, TranslationManager):
|
||||
class GenericDateTaggedManager(TaggedFilterItem, AppHookConfigTranslatableManager):
|
||||
use_for_related_fields = True
|
||||
|
||||
queryset_class = GenericDateQuerySet
|
||||
|
|
|
@ -3,66 +3,75 @@ from __future__ import absolute_import, print_function, unicode_literals
|
|||
|
||||
from cms.menu_bases import CMSAttachMenu
|
||||
from django.db.models.signals import post_delete, post_save
|
||||
from django.utils.translation import get_language, ugettext_lazy as _
|
||||
from menus.base import Modifier, NavigationNode
|
||||
from django.utils.translation import get_language_from_request, ugettext_lazy as _
|
||||
from menus.base import NavigationNode
|
||||
from menus.menu_pool import menu_pool
|
||||
|
||||
from .models import BlogCategory
|
||||
from .cms_appconfig import BlogConfig
|
||||
from .models import BlogCategory, Post
|
||||
from .settings import MENU_TYPE_CATEGORIES, MENU_TYPE_COMPLETE, MENU_TYPE_POSTS
|
||||
|
||||
|
||||
class BlogCategoryMenu(CMSAttachMenu):
|
||||
name = _('Blog Category menu')
|
||||
name = _('Blog 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:
|
||||
node = NavigationNode(
|
||||
category.name,
|
||||
category.get_absolute_url(),
|
||||
category.pk,
|
||||
category.parent_id
|
||||
)
|
||||
nodes.append(node)
|
||||
|
||||
language = get_language_from_request(request, check_path=True)
|
||||
|
||||
categories_menu = False
|
||||
posts_menu = False
|
||||
config = False
|
||||
if hasattr(self, 'instance') and self.instance:
|
||||
config = BlogConfig.objects.get(namespace=self.instance.application_namespace)
|
||||
if config.menu_structure in (MENU_TYPE_COMPLETE, MENU_TYPE_CATEGORIES):
|
||||
categories_menu = True
|
||||
if config.menu_structure in (MENU_TYPE_COMPLETE, MENU_TYPE_POSTS):
|
||||
posts_menu = True
|
||||
|
||||
if categories_menu:
|
||||
categories = BlogCategory.objects
|
||||
if config:
|
||||
categories = categories.namespace(self.instance.application_namespace)
|
||||
categories = categories.active_translations(language).distinct()
|
||||
categories = categories.order_by('parent__id', 'translations__name')
|
||||
for category in categories:
|
||||
node = NavigationNode(
|
||||
category.name,
|
||||
category.get_absolute_url(),
|
||||
'%s-%s' % (category.__class__.__name__, category.pk),
|
||||
('%s-%s' % (category.__class__.__name__, category.parent.id) if category.parent
|
||||
else None)
|
||||
)
|
||||
nodes.append(node)
|
||||
|
||||
if posts_menu:
|
||||
posts = Post.objects
|
||||
if hasattr(self, 'instance') and self.instance:
|
||||
posts = posts.namespace(self.instance.application_namespace)
|
||||
posts = posts.active_translations(language).distinct()
|
||||
for post in posts:
|
||||
if categories_menu:
|
||||
category = post.categories.first()
|
||||
parent = '%s-%s' % (category.__class__.__name__, category.pk)
|
||||
post_id = '%s-%s' % (post.__class__.__name__, post.pk),
|
||||
else:
|
||||
parent = None
|
||||
post_id = '%s-%s' % (post.__class__.__name__, post.pk),
|
||||
node = NavigationNode(
|
||||
post.get_title(),
|
||||
post.get_absolute_url(language),
|
||||
post_id,
|
||||
parent
|
||||
)
|
||||
nodes.append(node)
|
||||
|
||||
return nodes
|
||||
|
||||
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 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.startswith(BlogCategoryMenu.__name__) and
|
||||
cat.pk == node.id):
|
||||
node.selected = True
|
||||
# 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)
|
||||
|
||||
|
||||
def clear_menu_cache(**kwargs):
|
||||
menu_pool.clear(all=True)
|
||||
|
||||
|
|
124
djangocms_blog/migrations/0010_auto_20150923_1151.py
Normal file
124
djangocms_blog/migrations/0010_auto_20150923_1151.py
Normal file
|
@ -0,0 +1,124 @@
|
|||
#-*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import aldryn_apphooks_config.fields
|
||||
import app_data.fields
|
||||
import djangocms_text_ckeditor.fields
|
||||
from cms.models import Page
|
||||
from cms.utils.i18n import get_language_list
|
||||
from django.db import models, migrations
|
||||
|
||||
|
||||
def forwards(apps, schema_editor):
|
||||
BlogConfig = apps.get_model('djangocms_blog', 'BlogConfig')
|
||||
BlogConfigTranslation = apps.get_model('djangocms_blog', 'BlogConfigTranslation')
|
||||
Post = apps.get_model('djangocms_blog', 'Post')
|
||||
BlogCategory = apps.get_model('djangocms_blog', 'BlogCategory')
|
||||
GenericBlogPlugin = apps.get_model('djangocms_blog', 'GenericBlogPlugin')
|
||||
LatestPostsPlugin = apps.get_model('djangocms_blog', 'LatestPostsPlugin')
|
||||
AuthorEntriesPlugin = apps.get_model('djangocms_blog', 'AuthorEntriesPlugin')
|
||||
config = None
|
||||
for page in Page.objects.drafts().filter(application_urls='BlogApp'):
|
||||
config = BlogConfig.objects.create(namespace=page.application_namespace)
|
||||
for lang in get_language_list():
|
||||
title = page.get_title(lang)
|
||||
translation = BlogConfigTranslation.objects.create(language_code=lang, master_id=config.pk, app_title=title)
|
||||
if config:
|
||||
for model in (Post, BlogCategory, GenericBlogPlugin, LatestPostsPlugin, AuthorEntriesPlugin):
|
||||
for item in model.objects.all():
|
||||
item.app_config = config
|
||||
item.save()
|
||||
|
||||
|
||||
def backwards(apps, schema_editor):
|
||||
# No need for backward data migration
|
||||
pass
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('cms', '__latest__'),
|
||||
('djangocms_blog', '0009_latestpostsplugin_tags_new'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='BlogConfig',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, verbose_name='ID', serialize=False, primary_key=True)),
|
||||
('type', models.CharField(verbose_name='type', max_length=100)),
|
||||
('namespace', models.CharField(default=None, verbose_name='instance namespace', unique=True, max_length=100)),
|
||||
('app_data', app_data.fields.AppDataField(editable=False, default='{}')),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='BlogConfigTranslation',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, verbose_name='ID', serialize=False, primary_key=True)),
|
||||
('language_code', models.CharField(db_index=True, verbose_name='Language', max_length=15)),
|
||||
('app_title', models.CharField(verbose_name='application title', max_length=234)),
|
||||
('master', models.ForeignKey(editable=False, to='djangocms_blog.BlogConfig', related_name='translations', null=True)),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'blog config Translation',
|
||||
'db_table': 'djangocms_blog_blogconfig_translation',
|
||||
'default_permissions': (),
|
||||
'db_tablespace': '',
|
||||
'managed': True,
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='GenericBlogPlugin',
|
||||
fields=[
|
||||
('cmsplugin_ptr', models.OneToOneField(parent_link=True, serialize=False, primary_key=True, auto_created=True, to='cms.CMSPlugin')),
|
||||
('app_config', aldryn_apphooks_config.fields.AppHookConfigField(verbose_name='app. config', blank=True, to='djangocms_blog.BlogConfig', help_text='When selecting a value, the form is reloaded to get the updated default')),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
bases=('cms.cmsplugin',),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='posttranslation',
|
||||
name='abstract',
|
||||
field=djangocms_text_ckeditor.fields.HTMLField(default='', verbose_name='abstract', blank=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='authorentriesplugin',
|
||||
name='app_config',
|
||||
field=aldryn_apphooks_config.fields.AppHookConfigField(default=None, blank=True, verbose_name='app. config', to='djangocms_blog.BlogConfig', help_text='When selecting a value, the form is reloaded to get the updated default'),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='blogcategory',
|
||||
name='app_config',
|
||||
field=aldryn_apphooks_config.fields.AppHookConfigField(default=None, verbose_name='app. config', to='djangocms_blog.BlogConfig', help_text='When selecting a value, the form is reloaded to get the updated default'),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='latestpostsplugin',
|
||||
name='app_config',
|
||||
field=aldryn_apphooks_config.fields.AppHookConfigField(default=None, blank=True, verbose_name='app. config', to='djangocms_blog.BlogConfig', help_text='When selecting a value, the form is reloaded to get the updated default'),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='post',
|
||||
name='app_config',
|
||||
field=aldryn_apphooks_config.fields.AppHookConfigField(default=None, verbose_name='app. config', to='djangocms_blog.BlogConfig', help_text='When selecting a value, the form is reloaded to get the updated default'),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='blogconfigtranslation',
|
||||
unique_together=set([('language_code', 'master')]),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='post',
|
||||
name='sites',
|
||||
field=models.ManyToManyField(to='sites.Site', help_text='Select sites in which to show the post. If none is set it will be visible in all the configured sites.', blank=True, verbose_name='Site(s)'),
|
||||
),
|
||||
migrations.RunPython(forwards, backwards)
|
||||
]
|
|
@ -1,6 +1,8 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import absolute_import, print_function, unicode_literals
|
||||
|
||||
from aldryn_apphooks_config.fields import AppHookConfigField
|
||||
from aldryn_apphooks_config.managers.parler import AppHookConfigTranslatableManager
|
||||
from cms.models import CMSPlugin, PlaceholderField
|
||||
from django.conf import settings as dj_settings
|
||||
from django.core.urlresolvers import reverse
|
||||
|
@ -13,14 +15,15 @@ from django.utils.translation import get_language, ugettext_lazy as _
|
|||
from djangocms_text_ckeditor.fields import HTMLField
|
||||
from filer.fields.image import FilerImageField
|
||||
from meta_mixin.models import ModelMeta
|
||||
from parler.managers import TranslationManager
|
||||
from parler.models import TranslatableModel, TranslatedFields
|
||||
from taggit_autosuggest.managers import TaggableManager
|
||||
|
||||
from .cms_appconfig import BlogConfig
|
||||
from .managers import GenericDateTaggedManager
|
||||
from .settings import get_setting
|
||||
|
||||
BLOG_CURRENT_POST_IDENTIFIER = 'djangocms_post_current'
|
||||
BLOG_CURRENT_NAMESPACE = 'djangocms_post_current_config'
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
|
@ -28,10 +31,12 @@ class BlogCategory(TranslatableModel):
|
|||
"""
|
||||
Blog category
|
||||
"""
|
||||
parent = models.ForeignKey('self', verbose_name=_('parent'), null=True,
|
||||
blank=True)
|
||||
parent = models.ForeignKey('self', verbose_name=_('parent'), null=True, blank=True)
|
||||
date_created = models.DateTimeField(_('created at'), auto_now_add=True)
|
||||
date_modified = models.DateTimeField(_('modified at'), auto_now=True)
|
||||
app_config = AppHookConfigField(
|
||||
BlogConfig, null=True, verbose_name=_('app. config')
|
||||
)
|
||||
|
||||
translations = TranslatedFields(
|
||||
name=models.CharField(_('name'), max_length=255),
|
||||
|
@ -39,7 +44,7 @@ class BlogCategory(TranslatableModel):
|
|||
meta={'unique_together': (('language_code', 'slug'),)}
|
||||
)
|
||||
|
||||
objects = TranslationManager()
|
||||
objects = AppHookConfigTranslatableManager()
|
||||
|
||||
class Meta:
|
||||
verbose_name = _('blog category')
|
||||
|
@ -47,16 +52,23 @@ class BlogCategory(TranslatableModel):
|
|||
|
||||
@property
|
||||
def count(self):
|
||||
return self.blog_posts.published().count()
|
||||
return self.blog_posts.namespace(self.app_config.namespace).published().count()
|
||||
|
||||
def get_absolute_url(self):
|
||||
lang = get_language()
|
||||
if self.has_translation(lang):
|
||||
def get_absolute_url(self, lang=None):
|
||||
if not lang:
|
||||
lang = get_language()
|
||||
if self.has_translation(lang, ):
|
||||
slug = self.safe_translation_getter('slug', language_code=lang)
|
||||
return reverse('djangocms_blog:posts-category', kwargs={'category': slug})
|
||||
return reverse(
|
||||
'%s:posts-category' % self.app_config.namespace,
|
||||
kwargs={'category': slug},
|
||||
current_app=self.app_config.namespace
|
||||
)
|
||||
# in case category doesn't exist in this language, gracefully fallback
|
||||
# to posts-latest
|
||||
return reverse('djangocms_blog:posts-latest')
|
||||
return reverse(
|
||||
'%s:posts-latest' % self.app_config.namespace, current_app=self.app_config.namespace
|
||||
)
|
||||
|
||||
def __str__(self):
|
||||
return self.safe_translation_getter('name')
|
||||
|
@ -81,9 +93,9 @@ class Post(ModelMeta, TranslatableModel):
|
|||
|
||||
date_created = models.DateTimeField(_('created'), auto_now_add=True)
|
||||
date_modified = models.DateTimeField(_('last modified'), auto_now=True)
|
||||
date_published = models.DateTimeField(_('published Since'),
|
||||
date_published = models.DateTimeField(_('published since'),
|
||||
default=timezone.now)
|
||||
date_published_end = models.DateTimeField(_('published Until'), null=True,
|
||||
date_published_end = models.DateTimeField(_('published until'), null=True,
|
||||
blank=True)
|
||||
publish = models.BooleanField(_('publish'), default=False)
|
||||
categories = models.ManyToManyField('djangocms_blog.BlogCategory', verbose_name=_('category'),
|
||||
|
@ -104,10 +116,12 @@ class Post(ModelMeta, TranslatableModel):
|
|||
enable_comments = models.BooleanField(verbose_name=_('enable comments on post'),
|
||||
default=get_setting('ENABLE_COMMENTS'))
|
||||
sites = models.ManyToManyField('sites.Site', verbose_name=_('Site(s)'), blank=True,
|
||||
null=True,
|
||||
help_text=_('Select sites in which to show the post. '
|
||||
u'If none is set it will be '
|
||||
u'visible in all the configured sites.'))
|
||||
'If none is set it will be '
|
||||
'visible in all the configured sites.'))
|
||||
app_config = AppHookConfigField(
|
||||
BlogConfig, null=True, verbose_name=_('app. config')
|
||||
)
|
||||
|
||||
translations = TranslatedFields(
|
||||
title=models.CharField(_('title'), max_length=255),
|
||||
|
@ -132,23 +146,24 @@ 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,
|
||||
'locale': 'get_locale',
|
||||
'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',
|
||||
'og_author': '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',
|
||||
|
@ -165,19 +180,49 @@ class Post(ModelMeta, TranslatableModel):
|
|||
def __str__(self):
|
||||
return self.safe_translation_getter('title')
|
||||
|
||||
def get_absolute_url(self):
|
||||
kwargs = {'year': self.date_published.year,
|
||||
'month': '%02d' % self.date_published.month,
|
||||
'day': '%02d' % self.date_published.day,
|
||||
'slug': self.safe_translation_getter('slug',
|
||||
language_code=get_language(),
|
||||
any_language=True)}
|
||||
return reverse('djangocms_blog:post-detail', kwargs=kwargs)
|
||||
def get_absolute_url(self, lang=None):
|
||||
if not lang:
|
||||
lang = get_language()
|
||||
category = self.categories.first()
|
||||
kwargs = {}
|
||||
urlconf = get_setting('PERMALINK_URLS')[self.app_config.url_patterns]
|
||||
if '<year>' in urlconf:
|
||||
kwargs['year'] = self.date_published.year
|
||||
if '<month>' in urlconf:
|
||||
kwargs['month'] = '%02d' % self.date_published.month
|
||||
if '<day>' in urlconf:
|
||||
kwargs['day'] = '%02d' % self.date_published.day
|
||||
if '<slug>' in urlconf:
|
||||
kwargs['slug'] = self.safe_translation_getter('slug', language_code=lang, any_language=True) # NOQA
|
||||
if '<category>' in urlconf:
|
||||
kwargs['category'] = category.safe_translation_getter('slug', language_code=lang, any_language=True) # NOQA
|
||||
return reverse('%s:post-detail' % self.app_config.namespace, kwargs=kwargs)
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
if not self.slug and self.title:
|
||||
self.slug = slugify(self.title)
|
||||
super(Post, self).save(*args, **kwargs)
|
||||
def get_meta_attribute(self, param):
|
||||
"""
|
||||
Retrieves django-meta attributes from apphook config instance
|
||||
:param param: django-meta attribute passed as key
|
||||
"""
|
||||
attr = None
|
||||
value = getattr(self.app_config, param)
|
||||
if value:
|
||||
attr = getattr(self, value, None)
|
||||
if attr is not None:
|
||||
if callable(attr):
|
||||
try:
|
||||
data = attr(param)
|
||||
except TypeError:
|
||||
data = attr()
|
||||
else:
|
||||
data = attr
|
||||
else:
|
||||
data = value
|
||||
return data
|
||||
|
||||
def save_translation(self, translation, *args, **kwargs):
|
||||
if not translation.slug and translation.title:
|
||||
translation.slug = slugify(translation.title)
|
||||
super(Post, self).save_translation(translation, *args, **kwargs)
|
||||
|
||||
def get_title(self):
|
||||
title = self.safe_translation_getter('meta_title', any_language=True)
|
||||
|
@ -188,6 +233,9 @@ class Post(ModelMeta, TranslatableModel):
|
|||
def get_keywords(self):
|
||||
return self.safe_translation_getter('meta_keywords').strip().split(',')
|
||||
|
||||
def get_locale(self):
|
||||
return self.get_current_language()
|
||||
|
||||
def get_description(self):
|
||||
description = self.safe_translation_getter('meta_description', any_language=True)
|
||||
if not description:
|
||||
|
@ -224,23 +272,28 @@ class Post(ModelMeta, TranslatableModel):
|
|||
|
||||
@python_2_unicode_compatible
|
||||
class BasePostPlugin(CMSPlugin):
|
||||
app_config = AppHookConfigField(
|
||||
BlogConfig, null=True, verbose_name=_('app. config'), blank=True
|
||||
)
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
||||
def post_queryset(self, request=None):
|
||||
language = get_language()
|
||||
posts = Post._default_manager.active_translations(language_code=language)
|
||||
posts = Post._default_manager
|
||||
if self.app_config:
|
||||
posts = posts.namespace(self.app_config.namespace)
|
||||
posts = posts.active_translations(language_code=language)
|
||||
if not request or not getattr(request, 'toolbar', False) or not request.toolbar.edit_mode:
|
||||
posts = posts.published()
|
||||
return posts
|
||||
|
||||
def __str__(self):
|
||||
return force_text(self.latest_posts)
|
||||
return _('generic blog plugin')
|
||||
|
||||
|
||||
class LatestPostsPlugin(BasePostPlugin):
|
||||
|
||||
latest_posts = models.IntegerField(_('articles'), default=get_setting('LATEST_POSTS'),
|
||||
help_text=_('The number of latests '
|
||||
u'articles to be displayed.'))
|
||||
|
@ -292,6 +345,16 @@ class AuthorEntriesPlugin(BasePostPlugin):
|
|||
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()
|
||||
qs = author.djangocms_blog_post_author
|
||||
if self.app_config:
|
||||
qs = qs.namespace(self.app_config.namespace)
|
||||
count = qs.filter(publish=True).count()
|
||||
if count:
|
||||
author.count = count
|
||||
return authors
|
||||
|
||||
|
||||
class GenericBlogPlugin(BasePostPlugin):
|
||||
|
||||
class Meta:
|
||||
abstract = False
|
||||
|
|
|
@ -1,11 +1,35 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import absolute_import, print_function, unicode_literals
|
||||
|
||||
MENU_TYPE_COMPLETE = 'complete'
|
||||
MENU_TYPE_CATEGORIES = 'categories'
|
||||
MENU_TYPE_POSTS = 'posts'
|
||||
MENU_TYPE_NONE = 'none'
|
||||
|
||||
|
||||
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
|
||||
|
||||
PERMALINKS = (
|
||||
('full_date', _('Full date')),
|
||||
('short_date', _('Year / Month')),
|
||||
('category', _('Category')),
|
||||
('slug', _('Just slug')),
|
||||
)
|
||||
PERMALINKS_URLS = {
|
||||
'full_date': r'^(?P<year>\d{4})/(?P<month>\d{1,2})/(?P<day>\d{1,2})/(?P<slug>\w[-\w]*)/$',
|
||||
'short_date': r'^(?P<year>\d{4})/(?P<month>\d{1,2})/(?P<slug>\w[-\w]*)/$',
|
||||
'category': r'^(?P<category>\w[-\w]*)/(?P<slug>\w[-\w]*)/$',
|
||||
'slug': r'^(?P<slug>\w[-\w]*)/$',
|
||||
}
|
||||
MENU_TYPES = (
|
||||
(MENU_TYPE_COMPLETE, _('Categories and posts')),
|
||||
(MENU_TYPE_CATEGORIES, _('Categories only')),
|
||||
(MENU_TYPE_POSTS, _('Posts only')),
|
||||
(MENU_TYPE_NONE, _('None')),
|
||||
)
|
||||
default = {
|
||||
'BLOG_IMAGE_THUMBNAIL_SIZE': getattr(settings, 'BLOG_IMAGE_THUMBNAIL_SIZE', {
|
||||
'size': '120x120',
|
||||
|
@ -19,38 +43,41 @@ def get_setting(name):
|
|||
'upscale': False
|
||||
}),
|
||||
|
||||
'BLOG_TAGCLOUD_MIN': getattr(settings, 'BLOG_TAGCLOUD_MIN', 1),
|
||||
'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_MENU_TYPE': MENU_TYPES,
|
||||
'BLOG_MENU_TYPES': MENU_TYPES,
|
||||
'BLOG_TYPE': getattr(settings, 'BLOG_TYPE', 'Article'),
|
||||
'BLOG_TYPES': meta_settings.OBJECT_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_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_FB_TYPES': getattr(settings, 'BLOG_FB_TYPES', meta_settings.FB_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_TYPES': getattr(settings, 'BLOG_TWITTER_TYPES', meta_settings.TWITTER_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_TYPE', 'Blog'),
|
||||
'BLOG_GPLUS_TYPES': getattr(settings, 'BLOG_GPLUS_TYPES', meta_settings.GPLUS_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),
|
||||
'BLOG_MULTISITE': getattr(settings, 'BLOG_MULTISITE', True),
|
||||
'BLOG_AUTHOR_DEFAULT': getattr(settings, 'BLOG_AUTHOR_DEFAULT', True),
|
||||
'BLOG_DEFAULT_PUBLISHED': getattr(settings, 'BLOG_DEFAULT_PUBLISHED', False),
|
||||
'BLOG_AVAILABLE_PERMALINK_STYLES': getattr(settings, 'BLOG_AVAILABLE_PERMALINK_STYLES', PERMALINKS), # NOQA
|
||||
'BLOG_PERMALINK_URLS': getattr(settings, 'BLOG_PERMALINK_URLS', PERMALINKS_URLS),
|
||||
|
||||
'BLOG_AUTO_SETUP': getattr(settings, 'BLOG_AUTO_SETUP', True),
|
||||
'BLOG_AUTO_HOME_TITLE': getattr(settings, 'BLOG_AUTO_HOME_TITLE', 'Home'),
|
||||
'BLOG_AUTO_BLOG_TITLE': getattr(settings, 'BLOG_AUTO_BLOG_TITLE', 'Blog'),
|
||||
'BLOG_AUTO_APP_TITLE': getattr(settings, 'BLOG_AUTO_APP_TITLE', 'Blog'),
|
||||
}
|
||||
return default['BLOG_%s' % name]
|
||||
|
|
|
@ -0,0 +1,285 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from south.utils import datetime_utils as datetime
|
||||
from south.db import db
|
||||
from south.v2 import SchemaMigration
|
||||
from django.db import models
|
||||
|
||||
|
||||
class Migration(SchemaMigration):
|
||||
|
||||
def forwards(self, orm):
|
||||
# Adding model 'GenericBlogPlugin'
|
||||
db.create_table(u'djangocms_blog_genericblogplugin', (
|
||||
(u'cmsplugin_ptr', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['cms.CMSPlugin'], unique=True, primary_key=True)),
|
||||
('app_config', self.gf('aldryn_apphooks_config.fields.AppHookConfigField')(to=orm['djangocms_blog.BlogConfig'], null=True, blank=True)),
|
||||
))
|
||||
db.send_create_signal(u'djangocms_blog', ['GenericBlogPlugin'])
|
||||
|
||||
# Adding model 'BlogConfig'
|
||||
db.create_table(u'djangocms_blog_blogconfig', (
|
||||
(u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||
('type', self.gf('django.db.models.fields.CharField')(max_length=100)),
|
||||
('namespace', self.gf('django.db.models.fields.CharField')(default=None, unique=True, max_length=100)),
|
||||
('app_data', self.gf('app_data.fields.AppDataField')(default='{}')),
|
||||
))
|
||||
db.send_create_signal(u'djangocms_blog', ['BlogConfig'])
|
||||
|
||||
# Adding model 'BlogConfigTranslation'
|
||||
db.create_table(u'djangocms_blog_blogconfig_translation', (
|
||||
(u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||
('language_code', self.gf('django.db.models.fields.CharField')(max_length=15, db_index=True)),
|
||||
('app_title', self.gf('django.db.models.fields.CharField')(max_length=234)),
|
||||
(u'master', self.gf('django.db.models.fields.related.ForeignKey')(related_name='translations', null=True, to=orm['djangocms_blog.BlogConfig'])),
|
||||
))
|
||||
db.send_create_signal(u'djangocms_blog', ['BlogConfigTranslation'])
|
||||
|
||||
# Adding unique constraint on 'BlogConfigTranslation', fields ['language_code', u'master']
|
||||
db.create_unique(u'djangocms_blog_blogconfig_translation', ['language_code', u'master_id'])
|
||||
|
||||
# Adding field 'BlogCategory.app_config'
|
||||
db.add_column(u'djangocms_blog_blogcategory', 'app_config',
|
||||
self.gf('aldryn_apphooks_config.fields.AppHookConfigField')(to=orm['djangocms_blog.BlogConfig'], null=True),
|
||||
keep_default=False)
|
||||
|
||||
# Adding field 'Post.app_config'
|
||||
db.add_column(u'djangocms_blog_post', 'app_config',
|
||||
self.gf('aldryn_apphooks_config.fields.AppHookConfigField')(to=orm['djangocms_blog.BlogConfig'], null=True),
|
||||
keep_default=False)
|
||||
|
||||
# Adding field 'LatestPostsPlugin.app_config'
|
||||
db.add_column(u'djangocms_blog_latestpostsplugin', 'app_config',
|
||||
self.gf('aldryn_apphooks_config.fields.AppHookConfigField')(to=orm['djangocms_blog.BlogConfig'], null=True, blank=True),
|
||||
keep_default=False)
|
||||
|
||||
# Adding field 'AuthorEntriesPlugin.app_config'
|
||||
db.add_column(u'djangocms_blog_authorentriesplugin', 'app_config',
|
||||
self.gf('aldryn_apphooks_config.fields.AppHookConfigField')(to=orm['djangocms_blog.BlogConfig'], null=True, blank=True),
|
||||
keep_default=False)
|
||||
|
||||
|
||||
def backwards(self, orm):
|
||||
# Removing unique constraint on 'BlogConfigTranslation', fields ['language_code', u'master']
|
||||
db.delete_unique(u'djangocms_blog_blogconfig_translation', ['language_code', u'master_id'])
|
||||
|
||||
# Deleting model 'GenericBlogPlugin'
|
||||
db.delete_table(u'djangocms_blog_genericblogplugin')
|
||||
|
||||
# Deleting model 'BlogConfig'
|
||||
db.delete_table(u'djangocms_blog_blogconfig')
|
||||
|
||||
# Deleting model 'BlogConfigTranslation'
|
||||
db.delete_table(u'djangocms_blog_blogconfig_translation')
|
||||
|
||||
# Deleting field 'BlogCategory.app_config'
|
||||
db.delete_column(u'djangocms_blog_blogcategory', 'app_config_id')
|
||||
|
||||
# Deleting field 'Post.app_config'
|
||||
db.delete_column(u'djangocms_blog_post', 'app_config_id')
|
||||
|
||||
# Deleting field 'LatestPostsPlugin.app_config'
|
||||
db.delete_column(u'djangocms_blog_latestpostsplugin', 'app_config_id')
|
||||
|
||||
# Deleting field 'AuthorEntriesPlugin.app_config'
|
||||
db.delete_column(u'djangocms_blog_authorentriesplugin', 'app_config_id')
|
||||
|
||||
|
||||
models = {
|
||||
u'auth.group': {
|
||||
'Meta': {'object_name': 'Group'},
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
|
||||
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
|
||||
},
|
||||
u'auth.permission': {
|
||||
'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'},
|
||||
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
|
||||
},
|
||||
u'auth.user': {
|
||||
'Meta': {'object_name': 'User'},
|
||||
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
|
||||
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Group']"}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
|
||||
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Permission']"}),
|
||||
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
|
||||
},
|
||||
'cms.cmsplugin': {
|
||||
'Meta': {'object_name': 'CMSPlugin'},
|
||||
'changed_date': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
|
||||
'creation_date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'depth': ('django.db.models.fields.PositiveIntegerField', [], {}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'language': ('django.db.models.fields.CharField', [], {'max_length': '15', 'db_index': 'True'}),
|
||||
'numchild': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
|
||||
'parent': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['cms.CMSPlugin']", 'null': 'True', 'blank': 'True'}),
|
||||
'path': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
|
||||
'placeholder': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['cms.Placeholder']", 'null': 'True'}),
|
||||
'plugin_type': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}),
|
||||
'position': ('django.db.models.fields.PositiveSmallIntegerField', [], {'null': 'True', 'blank': 'True'})
|
||||
},
|
||||
'cms.placeholder': {
|
||||
'Meta': {'object_name': 'Placeholder'},
|
||||
'default_width': ('django.db.models.fields.PositiveSmallIntegerField', [], {'null': 'True'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'slot': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'})
|
||||
},
|
||||
u'cmsplugin_filer_image.thumbnailoption': {
|
||||
'Meta': {'ordering': "(u'width', u'height')", 'object_name': 'ThumbnailOption'},
|
||||
'crop': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'height': ('django.db.models.fields.IntegerField', [], {}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'upscale': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'width': ('django.db.models.fields.IntegerField', [], {})
|
||||
},
|
||||
u'contenttypes.contenttype': {
|
||||
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
|
||||
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
|
||||
},
|
||||
u'djangocms_blog.authorentriesplugin': {
|
||||
'Meta': {'object_name': 'AuthorEntriesPlugin'},
|
||||
'app_config': ('aldryn_apphooks_config.fields.AppHookConfigField', [], {'to': u"orm['djangocms_blog.BlogConfig']", 'null': 'True', 'blank': 'True'}),
|
||||
'authors': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.User']", 'symmetrical': 'False'}),
|
||||
u'cmsplugin_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['cms.CMSPlugin']", 'unique': 'True', 'primary_key': 'True'}),
|
||||
'latest_posts': ('django.db.models.fields.IntegerField', [], {'default': '5'})
|
||||
},
|
||||
u'djangocms_blog.blogcategory': {
|
||||
'Meta': {'object_name': 'BlogCategory'},
|
||||
'app_config': ('aldryn_apphooks_config.fields.AppHookConfigField', [], {'to': u"orm['djangocms_blog.BlogConfig']", 'null': 'True'}),
|
||||
'date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'date_modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'parent': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['djangocms_blog.BlogCategory']", 'null': 'True', 'blank': 'True'})
|
||||
},
|
||||
u'djangocms_blog.blogcategorytranslation': {
|
||||
'Meta': {'unique_together': "[(u'language_code', u'slug'), (u'language_code', u'master')]", 'object_name': 'BlogCategoryTranslation', 'db_table': "u'djangocms_blog_blogcategory_translation'"},
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'language_code': ('django.db.models.fields.CharField', [], {'max_length': '15', 'db_index': 'True'}),
|
||||
u'master': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'translations'", 'null': 'True', 'to': u"orm['djangocms_blog.BlogCategory']"}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50', 'blank': 'True'})
|
||||
},
|
||||
u'djangocms_blog.blogconfig': {
|
||||
'Meta': {'object_name': 'BlogConfig'},
|
||||
'app_data': ('app_data.fields.AppDataField', [], {'default': "'{}'"}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'namespace': ('django.db.models.fields.CharField', [], {'default': 'None', 'unique': 'True', 'max_length': '100'}),
|
||||
'type': ('django.db.models.fields.CharField', [], {'max_length': '100'})
|
||||
},
|
||||
u'djangocms_blog.blogconfigtranslation': {
|
||||
'Meta': {'unique_together': "[(u'language_code', u'master')]", 'object_name': 'BlogConfigTranslation', 'db_table': "u'djangocms_blog_blogconfig_translation'"},
|
||||
'app_title': ('django.db.models.fields.CharField', [], {'max_length': '234'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'language_code': ('django.db.models.fields.CharField', [], {'max_length': '15', 'db_index': 'True'}),
|
||||
u'master': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'translations'", 'null': 'True', 'to': u"orm['djangocms_blog.BlogConfig']"})
|
||||
},
|
||||
u'djangocms_blog.genericblogplugin': {
|
||||
'Meta': {'object_name': 'GenericBlogPlugin'},
|
||||
'app_config': ('aldryn_apphooks_config.fields.AppHookConfigField', [], {'to': u"orm['djangocms_blog.BlogConfig']", 'null': 'True', 'blank': 'True'}),
|
||||
u'cmsplugin_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['cms.CMSPlugin']", 'unique': 'True', 'primary_key': 'True'})
|
||||
},
|
||||
u'djangocms_blog.latestpostsplugin': {
|
||||
'Meta': {'object_name': 'LatestPostsPlugin'},
|
||||
'app_config': ('aldryn_apphooks_config.fields.AppHookConfigField', [], {'to': u"orm['djangocms_blog.BlogConfig']", 'null': 'True', 'blank': 'True'}),
|
||||
'categories': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['djangocms_blog.BlogCategory']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
u'cmsplugin_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['cms.CMSPlugin']", 'unique': 'True', 'primary_key': 'True'}),
|
||||
'latest_posts': ('django.db.models.fields.IntegerField', [], {'default': '5'})
|
||||
},
|
||||
u'djangocms_blog.post': {
|
||||
'Meta': {'ordering': "(u'-date_published', u'-date_created')", 'object_name': 'Post'},
|
||||
'app_config': ('aldryn_apphooks_config.fields.AppHookConfigField', [], {'to': u"orm['djangocms_blog.BlogConfig']", 'null': 'True'}),
|
||||
'author': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "u'djangocms_blog_post_author'", 'null': 'True', 'to': u"orm['auth.User']"}),
|
||||
'categories': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "u'blog_posts'", 'symmetrical': 'False', 'to': u"orm['djangocms_blog.BlogCategory']"}),
|
||||
'content': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "u'post_content'", 'null': 'True', 'to': "orm['cms.Placeholder']"}),
|
||||
'date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'date_modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
|
||||
'date_published': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'date_published_end': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'enable_comments': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'main_image': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "u'djangocms_blog_post_image'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['filer.Image']"}),
|
||||
'main_image_full': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "u'djangocms_blog_post_full'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['cmsplugin_filer_image.ThumbnailOption']"}),
|
||||
'main_image_thumbnail': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "u'djangocms_blog_post_thumbnail'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['cmsplugin_filer_image.ThumbnailOption']"}),
|
||||
'publish': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'sites': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['sites.Site']", 'symmetrical': 'False', 'blank': 'True'})
|
||||
},
|
||||
u'djangocms_blog.posttranslation': {
|
||||
'Meta': {'unique_together': "[(u'language_code', u'slug'), (u'language_code', u'master')]", 'object_name': 'PostTranslation', 'db_table': "u'djangocms_blog_post_translation'"},
|
||||
'abstract': ('djangocms_text_ckeditor.fields.HTMLField', [], {'default': "u''", 'blank': 'True'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'language_code': ('django.db.models.fields.CharField', [], {'max_length': '15', 'db_index': 'True'}),
|
||||
u'master': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'translations'", 'null': 'True', 'to': u"orm['djangocms_blog.Post']"}),
|
||||
'meta_description': ('django.db.models.fields.TextField', [], {'default': "u''", 'blank': 'True'}),
|
||||
'meta_keywords': ('django.db.models.fields.TextField', [], {'default': "u''", 'blank': 'True'}),
|
||||
'meta_title': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '255', 'blank': 'True'}),
|
||||
'post_text': ('djangocms_text_ckeditor.fields.HTMLField', [], {'default': "u''", 'blank': 'True'}),
|
||||
'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50', 'blank': 'True'}),
|
||||
'title': ('django.db.models.fields.CharField', [], {'max_length': '255'})
|
||||
},
|
||||
u'filer.file': {
|
||||
'Meta': {'object_name': 'File'},
|
||||
'_file_size': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'file': ('django.db.models.fields.files.FileField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
|
||||
'folder': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "u'all_files'", 'null': 'True', 'to': u"orm['filer.Folder']"}),
|
||||
'has_all_mandatory_data': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'is_public': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'modified_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '255', 'blank': 'True'}),
|
||||
'original_filename': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
|
||||
'owner': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "u'owned_files'", 'null': 'True', 'to': u"orm['auth.User']"}),
|
||||
'polymorphic_ctype': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "u'polymorphic_filer.file_set+'", 'null': 'True', 'to': u"orm['contenttypes.ContentType']"}),
|
||||
'sha1': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '40', 'blank': 'True'}),
|
||||
'uploaded_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'})
|
||||
},
|
||||
u'filer.folder': {
|
||||
'Meta': {'ordering': "(u'name',)", 'unique_together': "((u'parent', u'name'),)", 'object_name': 'Folder'},
|
||||
'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
u'level': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
|
||||
u'lft': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
|
||||
'modified_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'owner': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "u'filer_owned_folders'", 'null': 'True', 'to': u"orm['auth.User']"}),
|
||||
'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "u'children'", 'null': 'True', 'to': u"orm['filer.Folder']"}),
|
||||
u'rght': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
|
||||
u'tree_id': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
|
||||
'uploaded_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'})
|
||||
},
|
||||
'filer.image': {
|
||||
'Meta': {'object_name': 'Image'},
|
||||
'_height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'_width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'author': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
|
||||
'date_taken': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'default_alt_text': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
|
||||
'default_caption': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
|
||||
u'file_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['filer.File']", 'unique': 'True', 'primary_key': 'True'}),
|
||||
'must_always_publish_author_credit': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'must_always_publish_copyright': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'related_url': ('django.db.models.fields.CharField', [], {'max_length': '250', 'null': 'True', 'blank': 'True'}),
|
||||
'subject_location': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '64', 'null': 'True', 'blank': 'True'})
|
||||
},
|
||||
u'sites.site': {
|
||||
'Meta': {'ordering': "(u'domain',)", 'object_name': 'Site', 'db_table': "u'django_site'"},
|
||||
'domain': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'})
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['djangocms_blog']
|
236
djangocms_blog/south_migrations/0015_create_appconfig.py
Normal file
236
djangocms_blog/south_migrations/0015_create_appconfig.py
Normal file
|
@ -0,0 +1,236 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from south.utils import datetime_utils as datetime
|
||||
from south.db import db
|
||||
from south.v2 import DataMigration
|
||||
from django.db import models
|
||||
from cms.models import Page
|
||||
from cms.utils.i18n import get_language_list
|
||||
|
||||
|
||||
class Migration(DataMigration):
|
||||
|
||||
def forwards(self, orm):
|
||||
BlogConfig = orm['djangocms_blog.BlogConfig']
|
||||
BlogConfigTranslation = orm['djangocms_blog.BlogConfigTranslation']
|
||||
Post = orm['djangocms_blog.Post']
|
||||
BlogCategory = orm['djangocms_blog.BlogCategory']
|
||||
GenericBlogPlugin = orm['djangocms_blog.GenericBlogPlugin']
|
||||
LatestPostsPlugin = orm['djangocms_blog.LatestPostsPlugin']
|
||||
AuthorEntriesPlugin = orm['djangocms_blog.AuthorEntriesPlugin']
|
||||
config = None
|
||||
for page in Page.objects.drafts().filter(application_urls='BlogApp'):
|
||||
config = BlogConfig.objects.create(namespace=page.application_namespace)
|
||||
for lang in get_language_list():
|
||||
title = page.get_title(lang)
|
||||
translation = BlogConfigTranslation.objects.create(language_code=lang, master_id=config.pk, app_title=title)
|
||||
if config:
|
||||
for model in (Post, BlogCategory, GenericBlogPlugin, LatestPostsPlugin, AuthorEntriesPlugin):
|
||||
for item in model.objects.all():
|
||||
item.app_config = config
|
||||
item.save()
|
||||
|
||||
def backwards(self, orm):
|
||||
# No need for backward data migration
|
||||
pass
|
||||
|
||||
|
||||
models = {
|
||||
u'auth.group': {
|
||||
'Meta': {'object_name': 'Group'},
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
|
||||
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
|
||||
},
|
||||
u'auth.permission': {
|
||||
'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'},
|
||||
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
|
||||
},
|
||||
u'auth.user': {
|
||||
'Meta': {'object_name': 'User'},
|
||||
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
|
||||
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Group']"}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
|
||||
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Permission']"}),
|
||||
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
|
||||
},
|
||||
'cms.cmsplugin': {
|
||||
'Meta': {'object_name': 'CMSPlugin'},
|
||||
'changed_date': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
|
||||
'creation_date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'depth': ('django.db.models.fields.PositiveIntegerField', [], {}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'language': ('django.db.models.fields.CharField', [], {'max_length': '15', 'db_index': 'True'}),
|
||||
'numchild': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
|
||||
'parent': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['cms.CMSPlugin']", 'null': 'True', 'blank': 'True'}),
|
||||
'path': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
|
||||
'placeholder': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['cms.Placeholder']", 'null': 'True'}),
|
||||
'plugin_type': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}),
|
||||
'position': ('django.db.models.fields.PositiveSmallIntegerField', [], {'null': 'True', 'blank': 'True'})
|
||||
},
|
||||
'cms.placeholder': {
|
||||
'Meta': {'object_name': 'Placeholder'},
|
||||
'default_width': ('django.db.models.fields.PositiveSmallIntegerField', [], {'null': 'True'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'slot': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'})
|
||||
},
|
||||
u'cmsplugin_filer_image.thumbnailoption': {
|
||||
'Meta': {'ordering': "(u'width', u'height')", 'object_name': 'ThumbnailOption'},
|
||||
'crop': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'height': ('django.db.models.fields.IntegerField', [], {}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'upscale': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'width': ('django.db.models.fields.IntegerField', [], {})
|
||||
},
|
||||
u'contenttypes.contenttype': {
|
||||
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
|
||||
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
|
||||
},
|
||||
u'djangocms_blog.authorentriesplugin': {
|
||||
'Meta': {'object_name': 'AuthorEntriesPlugin'},
|
||||
'app_config': ('aldryn_apphooks_config.fields.AppHookConfigField', [], {'to': u"orm['djangocms_blog.BlogConfig']", 'null': 'True', 'blank': 'True'}),
|
||||
'authors': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.User']", 'symmetrical': 'False'}),
|
||||
u'cmsplugin_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['cms.CMSPlugin']", 'unique': 'True', 'primary_key': 'True'}),
|
||||
'latest_posts': ('django.db.models.fields.IntegerField', [], {'default': '5'})
|
||||
},
|
||||
u'djangocms_blog.blogcategory': {
|
||||
'Meta': {'object_name': 'BlogCategory'},
|
||||
'app_config': ('aldryn_apphooks_config.fields.AppHookConfigField', [], {'to': u"orm['djangocms_blog.BlogConfig']", 'null': 'True'}),
|
||||
'date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'date_modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'parent': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['djangocms_blog.BlogCategory']", 'null': 'True', 'blank': 'True'})
|
||||
},
|
||||
u'djangocms_blog.blogcategorytranslation': {
|
||||
'Meta': {'unique_together': "[(u'language_code', u'slug'), (u'language_code', u'master')]", 'object_name': 'BlogCategoryTranslation', 'db_table': "u'djangocms_blog_blogcategory_translation'"},
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'language_code': ('django.db.models.fields.CharField', [], {'max_length': '15', 'db_index': 'True'}),
|
||||
u'master': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'translations'", 'null': 'True', 'to': u"orm['djangocms_blog.BlogCategory']"}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50', 'blank': 'True'})
|
||||
},
|
||||
u'djangocms_blog.blogconfig': {
|
||||
'Meta': {'object_name': 'BlogConfig'},
|
||||
'app_data': ('app_data.fields.AppDataField', [], {'default': "'{}'"}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'namespace': ('django.db.models.fields.CharField', [], {'default': 'None', 'unique': 'True', 'max_length': '100'}),
|
||||
'type': ('django.db.models.fields.CharField', [], {'max_length': '100'})
|
||||
},
|
||||
u'djangocms_blog.blogconfigtranslation': {
|
||||
'Meta': {'unique_together': "[(u'language_code', u'master')]", 'object_name': 'BlogConfigTranslation', 'db_table': "u'djangocms_blog_blogconfig_translation'"},
|
||||
'app_title': ('django.db.models.fields.CharField', [], {'max_length': '234'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'language_code': ('django.db.models.fields.CharField', [], {'max_length': '15', 'db_index': 'True'}),
|
||||
u'master': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'translations'", 'null': 'True', 'to': u"orm['djangocms_blog.BlogConfig']"})
|
||||
},
|
||||
u'djangocms_blog.genericblogplugin': {
|
||||
'Meta': {'object_name': 'GenericBlogPlugin'},
|
||||
'app_config': ('aldryn_apphooks_config.fields.AppHookConfigField', [], {'to': u"orm['djangocms_blog.BlogConfig']", 'null': 'True', 'blank': 'True'}),
|
||||
u'cmsplugin_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['cms.CMSPlugin']", 'unique': 'True', 'primary_key': 'True'})
|
||||
},
|
||||
u'djangocms_blog.latestpostsplugin': {
|
||||
'Meta': {'object_name': 'LatestPostsPlugin'},
|
||||
'app_config': ('aldryn_apphooks_config.fields.AppHookConfigField', [], {'to': u"orm['djangocms_blog.BlogConfig']", 'null': 'True', 'blank': 'True'}),
|
||||
'categories': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['djangocms_blog.BlogCategory']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
u'cmsplugin_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['cms.CMSPlugin']", 'unique': 'True', 'primary_key': 'True'}),
|
||||
'latest_posts': ('django.db.models.fields.IntegerField', [], {'default': '5'})
|
||||
},
|
||||
u'djangocms_blog.post': {
|
||||
'Meta': {'ordering': "(u'-date_published', u'-date_created')", 'object_name': 'Post'},
|
||||
'app_config': ('aldryn_apphooks_config.fields.AppHookConfigField', [], {'to': u"orm['djangocms_blog.BlogConfig']", 'null': 'True'}),
|
||||
'author': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "u'djangocms_blog_post_author'", 'null': 'True', 'to': u"orm['auth.User']"}),
|
||||
'categories': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "u'blog_posts'", 'symmetrical': 'False', 'to': u"orm['djangocms_blog.BlogCategory']"}),
|
||||
'content': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "u'post_content'", 'null': 'True', 'to': "orm['cms.Placeholder']"}),
|
||||
'date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'date_modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
|
||||
'date_published': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'date_published_end': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'enable_comments': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'main_image': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "u'djangocms_blog_post_image'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['filer.Image']"}),
|
||||
'main_image_full': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "u'djangocms_blog_post_full'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['cmsplugin_filer_image.ThumbnailOption']"}),
|
||||
'main_image_thumbnail': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "u'djangocms_blog_post_thumbnail'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['cmsplugin_filer_image.ThumbnailOption']"}),
|
||||
'publish': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'sites': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['sites.Site']", 'symmetrical': 'False', 'blank': 'True'})
|
||||
},
|
||||
u'djangocms_blog.posttranslation': {
|
||||
'Meta': {'unique_together': "[(u'language_code', u'slug'), (u'language_code', u'master')]", 'object_name': 'PostTranslation', 'db_table': "u'djangocms_blog_post_translation'"},
|
||||
'abstract': ('djangocms_text_ckeditor.fields.HTMLField', [], {'default': "u''", 'blank': 'True'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'language_code': ('django.db.models.fields.CharField', [], {'max_length': '15', 'db_index': 'True'}),
|
||||
u'master': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'translations'", 'null': 'True', 'to': u"orm['djangocms_blog.Post']"}),
|
||||
'meta_description': ('django.db.models.fields.TextField', [], {'default': "u''", 'blank': 'True'}),
|
||||
'meta_keywords': ('django.db.models.fields.TextField', [], {'default': "u''", 'blank': 'True'}),
|
||||
'meta_title': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '255', 'blank': 'True'}),
|
||||
'post_text': ('djangocms_text_ckeditor.fields.HTMLField', [], {'default': "u''", 'blank': 'True'}),
|
||||
'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50', 'blank': 'True'}),
|
||||
'title': ('django.db.models.fields.CharField', [], {'max_length': '255'})
|
||||
},
|
||||
u'filer.file': {
|
||||
'Meta': {'object_name': 'File'},
|
||||
'_file_size': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'file': ('django.db.models.fields.files.FileField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
|
||||
'folder': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "u'all_files'", 'null': 'True', 'to': u"orm['filer.Folder']"}),
|
||||
'has_all_mandatory_data': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'is_public': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'modified_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '255', 'blank': 'True'}),
|
||||
'original_filename': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
|
||||
'owner': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "u'owned_files'", 'null': 'True', 'to': u"orm['auth.User']"}),
|
||||
'polymorphic_ctype': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "u'polymorphic_filer.file_set+'", 'null': 'True', 'to': u"orm['contenttypes.ContentType']"}),
|
||||
'sha1': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '40', 'blank': 'True'}),
|
||||
'uploaded_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'})
|
||||
},
|
||||
u'filer.folder': {
|
||||
'Meta': {'ordering': "(u'name',)", 'unique_together': "((u'parent', u'name'),)", 'object_name': 'Folder'},
|
||||
'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
u'level': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
|
||||
u'lft': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
|
||||
'modified_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'owner': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "u'filer_owned_folders'", 'null': 'True', 'to': u"orm['auth.User']"}),
|
||||
'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "u'children'", 'null': 'True', 'to': u"orm['filer.Folder']"}),
|
||||
u'rght': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
|
||||
u'tree_id': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
|
||||
'uploaded_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'})
|
||||
},
|
||||
'filer.image': {
|
||||
'Meta': {'object_name': 'Image'},
|
||||
'_height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'_width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'author': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
|
||||
'date_taken': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'default_alt_text': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
|
||||
'default_caption': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
|
||||
u'file_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['filer.File']", 'unique': 'True', 'primary_key': 'True'}),
|
||||
'must_always_publish_author_credit': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'must_always_publish_copyright': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'related_url': ('django.db.models.fields.CharField', [], {'max_length': '250', 'null': 'True', 'blank': 'True'}),
|
||||
'subject_location': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '64', 'null': 'True', 'blank': 'True'})
|
||||
},
|
||||
u'sites.site': {
|
||||
'Meta': {'ordering': "(u'domain',)", 'object_name': 'Site', 'db_table': "u'django_site'"},
|
||||
'domain': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'})
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['djangocms_blog']
|
|
@ -21,7 +21,7 @@
|
|||
</div>
|
||||
{% endif %}
|
||||
{% endspaceless %}
|
||||
{% if use_placeholder %}
|
||||
{% if post.app_config.use_placeholder %}
|
||||
<div class="blog-content">{% render_placeholder post.content %}</div>
|
||||
{% else %}
|
||||
<div class="blog-content">{% render_model post "post_text" "post_text" %}</div>
|
||||
|
|
|
@ -3,12 +3,26 @@ from __future__ import absolute_import, print_function, unicode_literals
|
|||
|
||||
from django.conf.urls import patterns, url
|
||||
|
||||
from .apps import BlogAppConfig
|
||||
from .feeds import LatestEntriesFeed, TagFeed
|
||||
from .settings import get_setting
|
||||
from .views import (
|
||||
AuthorEntriesView, CategoryEntriesView, PostArchiveView, PostDetailView, PostListView,
|
||||
TaggedListView,
|
||||
)
|
||||
|
||||
|
||||
def get_urls():
|
||||
urls = get_setting('PERMALINK_URLS')
|
||||
details = []
|
||||
for urlconf in urls.values():
|
||||
details.append(
|
||||
url(urlconf, PostDetailView.as_view(), name='post-detail'),
|
||||
)
|
||||
return details
|
||||
|
||||
detail_urls = get_urls()
|
||||
|
||||
urlpatterns = patterns(
|
||||
'',
|
||||
url(r'^$',
|
||||
|
@ -19,8 +33,7 @@ urlpatterns = patterns(
|
|||
PostArchiveView.as_view(), name='posts-archive'),
|
||||
url(r'^(?P<year>\d{4})/(?P<month>\d{1,2})/$',
|
||||
PostArchiveView.as_view(), name='posts-archive'),
|
||||
url(r'^(?P<year>\d{4})/(?P<month>\d{1,2})/(?P<day>\d{1,2})/(?P<slug>\w[-\w]*)/$',
|
||||
PostDetailView.as_view(), name='post-detail'),
|
||||
) + detail_urls + [
|
||||
url(r'^author/(?P<username>[\w\.@+-]+)/$',
|
||||
AuthorEntriesView.as_view(), name='posts-author'),
|
||||
url(r'^category/(?P<category>[\w\.@+-]+)/$',
|
||||
|
@ -29,4 +42,6 @@ urlpatterns = patterns(
|
|||
TaggedListView.as_view(), name='posts-tagged'),
|
||||
url(r'^tag/(?P<tag>[-\w]+)/feed/$',
|
||||
TagFeed(), name='posts-tagged-feed'),
|
||||
)
|
||||
]
|
||||
|
||||
BlogAppConfig.setup()
|
||||
|
|
|
@ -1,38 +1,61 @@
|
|||
# -*- 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.core.urlresolvers import resolve
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.utils.timezone import now
|
||||
from django.utils.translation import get_language
|
||||
from django.views.generic import DetailView, ListView
|
||||
from parler.views import TranslatableSlugMixin, ViewUrlMixin
|
||||
|
||||
from .models import BLOG_CURRENT_POST_IDENTIFIER, BlogCategory, Post
|
||||
from .models import BLOG_CURRENT_NAMESPACE, BLOG_CURRENT_POST_IDENTIFIER, BlogCategory, Post
|
||||
from .settings import get_setting
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
|
||||
class BaseBlogView(ViewUrlMixin):
|
||||
class BaseBlogView(AppConfigMixin, ViewUrlMixin):
|
||||
|
||||
def get_view_url(self):
|
||||
if not self.view_url_name:
|
||||
raise ImproperlyConfigured(
|
||||
'Missing `view_url_name` attribute on {0}'.format(self.__class__.__name__)
|
||||
)
|
||||
|
||||
return reverse(
|
||||
self.view_url_name,
|
||||
args=self.args,
|
||||
kwargs=self.kwargs,
|
||||
current_app=self.namespace
|
||||
)
|
||||
|
||||
def get_queryset(self):
|
||||
language = get_language()
|
||||
queryset = self.model._default_manager.all().active_translations(language_code=language)
|
||||
queryset = self.model._default_manager.namespace(
|
||||
self.namespace
|
||||
).active_translations(
|
||||
language_code=language
|
||||
)
|
||||
if not getattr(self.request, 'toolbar', False) or not self.request.toolbar.edit_mode:
|
||||
queryset = queryset.published()
|
||||
setattr(self.request, BLOG_CURRENT_NAMESPACE, self.config)
|
||||
return queryset
|
||||
|
||||
def render_to_response(self, context, **response_kwargs):
|
||||
response_kwargs['current_app'] = resolve(self.request.path).namespace
|
||||
return super(BaseBlogView, self).render_to_response(context, **response_kwargs)
|
||||
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'
|
||||
paginate_by = get_setting('PAGINATION')
|
||||
base_template_name = 'post_list.html'
|
||||
view_url_name = 'djangocms_blog:posts-latest'
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
|
@ -40,11 +63,17 @@ class PostListView(BaseBlogView, ListView):
|
|||
context['TRUNCWORDS_COUNT'] = get_setting('POSTS_LIST_TRUNCWORDS_COUNT')
|
||||
return context
|
||||
|
||||
def get_paginate_by(self, queryset):
|
||||
if self.config.paginate_by:
|
||||
return self.config.paginate_by
|
||||
else:
|
||||
return get_setting('PAGINATION')
|
||||
|
||||
|
||||
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'
|
||||
|
||||
|
@ -71,7 +100,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
|
||||
|
@ -99,7 +128,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'
|
||||
|
||||
|
@ -118,7 +147,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'
|
||||
|
||||
|
@ -138,7 +167,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'
|
||||
|
|
4
setup.py
4
setup.py
|
@ -47,7 +47,8 @@ setup(
|
|||
'djangocms-text-ckeditor',
|
||||
'cmsplugin-filer',
|
||||
'django-meta>=0.2',
|
||||
'django-meta-mixin>=0.1.1',
|
||||
'django-meta-mixin>=0.2.1',
|
||||
'aldryn-apphooks-config>=0.2.6',
|
||||
],
|
||||
license='BSD',
|
||||
zip_safe=False,
|
||||
|
@ -73,5 +74,6 @@ setup(
|
|||
'Programming Language :: Python :: 3',
|
||||
'Programming Language :: Python :: 3.3',
|
||||
'Programming Language :: Python :: 3.4',
|
||||
'Programming Language :: Python :: 3.5',
|
||||
],
|
||||
)
|
||||
|
|
|
@ -1,151 +1 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Tests for `djangocms_blog` module.
|
||||
"""
|
||||
from __future__ import absolute_import, print_function, unicode_literals
|
||||
|
||||
from cmsplugin_filer_image.models import ThumbnailOption
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.contrib.sites.models import Site
|
||||
from django.utils.translation import activate
|
||||
from djangocms_helper.base_test import BaseTestCase
|
||||
|
||||
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(BaseTestCase):
|
||||
"""
|
||||
Base class with utility function
|
||||
"""
|
||||
category_1 = None
|
||||
thumb_1 = None
|
||||
thumb_2 = None
|
||||
|
||||
_pages_data = (
|
||||
{'en': {'title': 'page one', 'template': 'page.html', 'publish': True},
|
||||
'fr': {'title': 'page un', 'publish': True},
|
||||
'it': {'title': 'pagina uno', 'publish': True}},
|
||||
{'en': {'title': 'page two', 'template': 'page.html', 'publish': True},
|
||||
'fr': {'title': 'page deux', 'publish': True},
|
||||
'it': {'title': 'pagina due', 'publish': True}},
|
||||
)
|
||||
|
||||
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'},
|
||||
{'title': u'Terzo post', 'abstract': u'<p>prima riga del terzo post</p>',
|
||||
'description': u'Descrizione del terzo post', 'keywords': u'keyword5, keyword6',
|
||||
'text': u'Testo del terzo 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'},
|
||||
{'title': u'Third post', 'abstract': u'<p>third post first line</p>',
|
||||
'description': u'third post description', 'keywords': u'keyword5, keyword6',
|
||||
'text': u'Third post text'}
|
||||
]
|
||||
}
|
||||
|
||||
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):
|
||||
super(BaseTest, cls).setUpClass()
|
||||
cls.site_2 = Site.objects.create(domain='http://example2.com', name='example 2')
|
||||
|
||||
def setUp(self):
|
||||
activate('en')
|
||||
super(BaseTest, self).setUp()
|
||||
self.category_1 = BlogCategory.objects.create(name=u'category 1')
|
||||
self.category_1.set_current_language('it', initialize=True)
|
||||
self.category_1.name = u'categoria 1'
|
||||
self.category_1.save()
|
||||
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
|
||||
)
|
||||
self.img = self.create_filer_image_object()
|
||||
|
||||
def tearDown(self):
|
||||
for post in Post.objects.all():
|
||||
post.delete()
|
||||
super(BaseTest, self).tearDown()
|
||||
|
||||
def _get_category(self, data, category=None, lang='en'):
|
||||
for k, v in data.items():
|
||||
if hasattr(v, '__call__'):
|
||||
data[k] = v()
|
||||
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 = {
|
||||
'author': self.user,
|
||||
'title': data['title'],
|
||||
'abstract': data['abstract'],
|
||||
'meta_description': data['description'],
|
||||
'meta_keywords': data['keywords'],
|
||||
}
|
||||
post = Post.objects.create(**post_data)
|
||||
else:
|
||||
post.set_current_language(lang)
|
||||
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)
|
||||
if sites:
|
||||
for site in sites:
|
||||
post.sites.add(site)
|
||||
return post
|
||||
|
||||
def get_posts(self, sites=None):
|
||||
post1 = self._get_post(self.data['en'][0], sites=sites)
|
||||
post1 = self._get_post(self.data['it'][0], post1, 'it')
|
||||
post1.publish = True
|
||||
post1.main_image = self.img
|
||||
post1.save()
|
||||
post2 = self._get_post(self.data['en'][1], sites=sites)
|
||||
post2 = self._get_post(self.data['it'][1], post2, 'it')
|
||||
post2.main_image = self.img
|
||||
post2.save()
|
||||
return post1, post2
|
||||
|
|
185
tests/base.py
Normal file
185
tests/base.py
Normal file
|
@ -0,0 +1,185 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import absolute_import, print_function, unicode_literals
|
||||
|
||||
from copy import deepcopy
|
||||
|
||||
from cmsplugin_filer_image.models import ThumbnailOption
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.contrib.sites.models import Site
|
||||
from djangocms_helper.base_test import BaseTestCase
|
||||
from parler.utils.context import smart_override
|
||||
|
||||
from djangocms_blog.cms_appconfig import BlogConfig
|
||||
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(BaseTestCase):
|
||||
"""
|
||||
Base class with utility function
|
||||
"""
|
||||
category_1 = None
|
||||
thumb_1 = None
|
||||
thumb_2 = None
|
||||
|
||||
_pages_data = (
|
||||
{'en': {'title': 'page one', 'template': 'blog.html', 'publish': True},
|
||||
'fr': {'title': 'page un', 'publish': True},
|
||||
'it': {'title': 'pagina uno', 'publish': True}},
|
||||
{'en': {'title': 'page two', 'template': 'blog.html', 'publish': True,
|
||||
'apphook': 'BlogApp', 'apphook_namespace': 'sample_app'},
|
||||
'fr': {'title': 'page deux', 'publish': True},
|
||||
'it': {'title': 'pagina due', 'publish': True}},
|
||||
{'en': {'title': 'page three', 'template': 'blog.html', 'publish': True,
|
||||
'apphook': 'BlogApp', 'apphook_namespace': 'sample_app2'},
|
||||
'fr': {'title': 'page trois', 'publish': True},
|
||||
'it': {'title': 'pagina tre', 'publish': True}},
|
||||
)
|
||||
|
||||
_post_data = (
|
||||
{'en': {'title': 'First post', 'abstract': '<p>first line</p>',
|
||||
'description': 'This is the description', 'keywords': 'keyword1, keyword2',
|
||||
'text': 'Post text', 'app_config': 'sample_app', 'publish': True},
|
||||
'it': {'title': 'Primo post', 'abstract': '<p>prima riga</p>',
|
||||
'description': 'Questa è la descrizione', 'keywords': 'keyword1, keyword2',
|
||||
'text': 'Testo del post'},
|
||||
},
|
||||
{'en': {'title': 'Second post', 'abstract': '<p>second post first line</p>',
|
||||
'description': 'Second post description', 'keywords': 'keyword3, keyword4',
|
||||
'text': 'Second post text', 'app_config': 'sample_app', 'publish': False},
|
||||
'it': {'title': 'Secondo post', 'abstract': '<p>prima riga del secondo post</p>',
|
||||
'description': 'Descrizione del secondo post', 'keywords': 'keyword3, keyword4',
|
||||
'text': 'Testo del secondo post', 'app_config': 'sample_app'},
|
||||
},
|
||||
{'en': {'title': 'Third post', 'abstract': '<p>third post first line</p>',
|
||||
'description': 'third post description', 'keywords': 'keyword5, keyword6',
|
||||
'text': 'Third post text', 'app_config': 'sample_app', 'publish': False},
|
||||
'it': {'title': 'Terzo post', 'abstract': '<p>prima riga del terzo post</p>',
|
||||
'description': 'Descrizione del terzo post', 'keywords': 'keyword5, keyword6',
|
||||
'text': 'Testo del terzo post'},
|
||||
},
|
||||
{'en': {'title': 'Different appconfig', 'abstract': '<p>Different appconfig first line</p>',
|
||||
'description': 'Different appconfig description', 'keywords': 'keyword5, keyword6',
|
||||
'text': 'Different appconfig text', 'app_config': 'sample_app2', 'publish': True},
|
||||
'it': {'title': 'Altro appconfig', 'abstract': '<p>prima riga del Altro appconfig</p>',
|
||||
'description': 'Descrizione Altro appconfig', 'keywords': 'keyword5, keyword6',
|
||||
'text': 'Testo del Altro appconfig'},
|
||||
},
|
||||
)
|
||||
|
||||
_categories_data = (
|
||||
{'en': {'name': 'Very loud', 'app_config': 'sample_app'},
|
||||
'it': {'name': 'Fortissimo'},
|
||||
},
|
||||
{'en': {'name': 'Very very silent', 'app_config': 'sample_app'},
|
||||
'it': {'name': 'Pianississimo'},
|
||||
},
|
||||
{'en': {'name': 'Almost', 'app_config': 'sample_app'},
|
||||
'it': {'name': 'Mezzo'},
|
||||
},
|
||||
{'en': {'name': 'Loud', 'parent_id': _get_cat_pk('en', 'Almost'), 'app_config': 'sample_app'},
|
||||
'it': {'name': 'Forte', 'parent_id': _get_cat_pk('it', 'Mezzo')},
|
||||
},
|
||||
{'en': {'name': 'Silent', 'parent_id': _get_cat_pk('en', 'Almost'), 'app_config': 'sample_app'},
|
||||
},
|
||||
{'en': {'name': 'Drums', 'app_config': 'sample_app2'},
|
||||
'it': {'name': 'Tamburi'},
|
||||
},
|
||||
{'en': {'name': 'Guitars', 'app_config': 'sample_app2'},
|
||||
'it': {'name': 'Chitarre'},
|
||||
},
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super(BaseTest, cls).setUpClass()
|
||||
cls.thumb_1 = ThumbnailOption.objects.create(
|
||||
name='base', width=100, height=100, crop=True, upscale=False
|
||||
)
|
||||
cls.thumb_2 = ThumbnailOption.objects.create(
|
||||
name='main', width=200, height=200, crop=False, upscale=False
|
||||
)
|
||||
cls.app_config_1 = BlogConfig.objects.create(
|
||||
namespace='sample_app', app_title='app1'
|
||||
)
|
||||
cls.app_config_2 = BlogConfig.objects.create(
|
||||
namespace='sample_app2', app_title='app2'
|
||||
)
|
||||
cls.app_config_1.app_data.config.paginate_by = 1
|
||||
cls.app_config_1.save()
|
||||
cls.app_config_2.app_data.config.paginate_by = 2
|
||||
cls.app_config_2.save()
|
||||
cls.app_configs = {
|
||||
'sample_app': cls.app_config_1,
|
||||
'sample_app2': cls.app_config_2,
|
||||
}
|
||||
cls.category_1 = BlogCategory.objects.create(name='category 1', app_config=cls.app_config_1)
|
||||
cls.category_1.set_current_language('it', initialize=True)
|
||||
cls.category_1.name = 'categoria 1'
|
||||
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():
|
||||
if hasattr(v, '__call__'):
|
||||
data[k] = v()
|
||||
if not category:
|
||||
with smart_override(lang):
|
||||
data['app_config'] = self.app_configs[data['app_config']]
|
||||
category = BlogCategory.objects.create(**data)
|
||||
else:
|
||||
category.set_current_language(lang, initialize=True)
|
||||
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 = {
|
||||
'author': self.user,
|
||||
'title': data['title'],
|
||||
'abstract': data['abstract'],
|
||||
'meta_description': data['description'],
|
||||
'meta_keywords': data['keywords'],
|
||||
'app_config': self.app_configs[data['app_config']]
|
||||
}
|
||||
post = Post.objects.create(**post_data)
|
||||
else:
|
||||
post.create_translation(
|
||||
lang,
|
||||
title=data['title'],
|
||||
abstract=data['abstract'],
|
||||
meta_description=data['description'],
|
||||
meta_keywords=data['keywords']
|
||||
)
|
||||
post = self.reload_model(post)
|
||||
post.categories.add(self.category_1)
|
||||
if sites:
|
||||
for site in sites:
|
||||
post.sites.add(site)
|
||||
return post
|
||||
|
||||
def get_posts(self, sites=None):
|
||||
posts = []
|
||||
for post in self._post_data:
|
||||
post1 = self._get_post(post['en'], sites=sites)
|
||||
post1 = self._get_post(post['it'], post=post1, lang='it')
|
||||
post1.publish = post['en']['publish']
|
||||
post1.main_image = self.create_filer_image_object()
|
||||
post1.save()
|
||||
posts.append(post1)
|
||||
return posts
|
|
@ -1,25 +1,30 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import absolute_import, print_function, unicode_literals
|
||||
|
||||
import copy
|
||||
|
||||
from aldryn_apphooks_config.utils import get_app_instance
|
||||
from django.core.cache import cache
|
||||
from django.utils.translation import activate
|
||||
from menus.menu_pool import menu_pool
|
||||
from parler.utils.context import switch_language
|
||||
from parler.utils.context import smart_override, switch_language
|
||||
|
||||
from djangocms_blog.settings import (
|
||||
MENU_TYPE_CATEGORIES, MENU_TYPE_COMPLETE, MENU_TYPE_NONE, MENU_TYPE_POSTS,
|
||||
)
|
||||
from djangocms_blog.views import CategoryEntriesView, PostDetailView
|
||||
|
||||
from . import BaseTest
|
||||
from .base import BaseTest
|
||||
|
||||
|
||||
class MenuTest(BaseTest):
|
||||
cats = []
|
||||
|
||||
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')
|
||||
for i, lang_data in enumerate(self._categories_data):
|
||||
cat = self._get_category(lang_data['en'])
|
||||
if 'it' in lang_data:
|
||||
cat = self._get_category(lang_data['it'], cat, 'it')
|
||||
self.cats.append(cat)
|
||||
|
||||
activate('en')
|
||||
|
@ -32,54 +37,111 @@ class MenuTest(BaseTest):
|
|||
"""
|
||||
Tests if all categories are present in the menu
|
||||
"""
|
||||
self.get_posts()
|
||||
self.get_pages()
|
||||
|
||||
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)
|
||||
request = self.get_page_request(None, self.user, r'/%s/page-two/' % lang)
|
||||
with smart_override(lang):
|
||||
nodes = menu_pool.get_nodes(request, namespace='BlogCategoryMenu')
|
||||
nodes_url = set([node.url for node in nodes])
|
||||
cats_url = set([cat.get_absolute_url() for cat in self.cats if cat.has_translation(lang)])
|
||||
self.assertTrue(cats_url.issubset(nodes_url))
|
||||
|
||||
def test_menu_options(self):
|
||||
"""
|
||||
Tests menu structure based on menu_structure configuration
|
||||
"""
|
||||
posts = self.get_posts()
|
||||
self.get_pages()
|
||||
|
||||
cats_url = {}
|
||||
posts_url = {}
|
||||
|
||||
languages = ('en', 'it')
|
||||
|
||||
for lang in languages:
|
||||
with smart_override(lang):
|
||||
cats_url[lang] = set([cat.get_absolute_url() for cat in self.cats if cat.has_translation(lang)])
|
||||
posts_url[lang] = set([post.get_absolute_url() for post in posts if post.has_translation(lang) and post.app_config == self.app_config_1])
|
||||
|
||||
# No item in the menu
|
||||
self.app_config_1.app_data.config.menu_structure = MENU_TYPE_NONE
|
||||
self.app_config_1.save()
|
||||
cache.clear()
|
||||
for lang in languages:
|
||||
request = self.get_page_request(None, self.user, r'/%s/page-two/' % lang)
|
||||
with smart_override(lang):
|
||||
nodes = menu_pool.get_nodes(request, namespace='BlogCategoryMenu')
|
||||
nodes_url = set([node.url for node in nodes])
|
||||
self.assertFalse(cats_url[lang].issubset(nodes_url))
|
||||
self.assertFalse(posts_url[lang].issubset(nodes_url))
|
||||
|
||||
# Only posts in the menu
|
||||
self.app_config_1.app_data.config.menu_structure = MENU_TYPE_POSTS
|
||||
self.app_config_1.save()
|
||||
cache.clear()
|
||||
for lang in languages:
|
||||
request = self.get_page_request(None, self.user, r'/%s/page-two/' % lang)
|
||||
with smart_override(lang):
|
||||
nodes = menu_pool.get_nodes(request, namespace='BlogCategoryMenu')
|
||||
nodes_url = set([node.url for node in nodes])
|
||||
self.assertFalse(cats_url[lang].issubset(nodes_url))
|
||||
self.assertTrue(posts_url[lang].issubset(nodes_url))
|
||||
|
||||
# Only categories in the menu
|
||||
self.app_config_1.app_data.config.menu_structure = MENU_TYPE_CATEGORIES
|
||||
self.app_config_1.save()
|
||||
cache.clear()
|
||||
for lang in languages:
|
||||
request = self.get_page_request(None, self.user, r'/%s/page-two/' % lang)
|
||||
with smart_override(lang):
|
||||
nodes = menu_pool.get_nodes(request, namespace='BlogCategoryMenu')
|
||||
nodes_url = set([node.url for node in nodes])
|
||||
self.assertTrue(cats_url[lang].issubset(nodes_url))
|
||||
self.assertFalse(posts_url[lang].issubset(nodes_url))
|
||||
|
||||
# Both types in the menu
|
||||
self.app_config_1.app_data.config.menu_structure = MENU_TYPE_COMPLETE
|
||||
self.app_config_1.save()
|
||||
cache.clear()
|
||||
for lang in languages:
|
||||
request = self.get_page_request(None, self.user, r'/%s/page-two/' % lang)
|
||||
with smart_override(lang):
|
||||
nodes = menu_pool.get_nodes(request, namespace='BlogCategoryMenu')
|
||||
nodes_url = set([node.url for node in nodes])
|
||||
self.assertTrue(cats_url[lang].issubset(nodes_url))
|
||||
self.assertTrue(posts_url[lang].issubset(nodes_url))
|
||||
|
||||
def test_modifier(self):
|
||||
"""
|
||||
Tests if correct category is selected in the menu
|
||||
according to context (view object)
|
||||
"""
|
||||
post1, post2 = self.get_posts()
|
||||
posts = self.get_posts()
|
||||
pages = self.get_pages()
|
||||
|
||||
tests = (
|
||||
# view class, view kwarg, view object, category
|
||||
(PostDetailView, 'slug', post1, post1.categories.first()),
|
||||
(PostDetailView, 'slug', posts[0], posts[0].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)
|
||||
request = self.get_page_request(pages[1], self.user, path=obj.get_absolute_url())
|
||||
with smart_override('en'):
|
||||
with switch_language(obj, 'en'):
|
||||
view_obj = view_cls()
|
||||
view_obj.request = request
|
||||
view_obj.namespace, view_obj.config = get_app_instance(request)
|
||||
view_obj.app_config = self.app_config_1
|
||||
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, obj.get_absolute_url())
|
||||
found = True
|
||||
break
|
||||
self.assertTrue(found)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import absolute_import, print_function, unicode_literals
|
||||
|
||||
import re
|
||||
from copy import deepcopy
|
||||
|
||||
import parler
|
||||
|
@ -12,37 +13,109 @@ from django.contrib.auth.models import AnonymousUser
|
|||
from django.contrib.messages.middleware import MessageMiddleware
|
||||
from django.contrib.sites.models import Site
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.utils.encoding import force_text
|
||||
from django.utils.html import strip_tags
|
||||
from django.utils.timezone import now
|
||||
from django.utils.translation import get_language, override
|
||||
from djangocms_helper.utils import CMS_30
|
||||
from taggit.models import Tag
|
||||
|
||||
from djangocms_blog.models import Post
|
||||
from djangocms_blog.cms_appconfig import BlogConfig, BlogConfigForm
|
||||
from djangocms_blog.models import BlogCategory, Post
|
||||
from djangocms_blog.settings import get_setting
|
||||
|
||||
from . import BaseTest
|
||||
from .base import BaseTest
|
||||
|
||||
|
||||
class AdminTest(BaseTest):
|
||||
|
||||
def test_admin_fieldsets(self):
|
||||
request = self.get_page_request('/', self.user_staff, r'/en/blog/', edit=False)
|
||||
def setUp(self):
|
||||
super(AdminTest, self).setUp()
|
||||
admin.autodiscover()
|
||||
|
||||
def test_admin_post_views(self):
|
||||
post_admin = admin.site._registry[Post]
|
||||
request = self.get_page_request('/', self.user, r'/en/blog/', edit=False)
|
||||
|
||||
with self.settings(BLOG_USE_PLACEHOLDER=True):
|
||||
fsets = post_admin.get_fieldsets(request)
|
||||
self.assertFalse('post_text' in fsets[0][1]['fields'])
|
||||
post = self._get_post(self._post_data[0]['en'])
|
||||
post = self._get_post(self._post_data[0]['it'], post, 'it')
|
||||
|
||||
with self.settings(BLOG_USE_PLACEHOLDER=False):
|
||||
fsets = post_admin.get_fieldsets(request)
|
||||
self.assertTrue('post_text' in fsets[0][1]['fields'])
|
||||
# Add view only contains the apphook selection widget
|
||||
response = post_admin.add_view(request)
|
||||
self.assertNotContains(response, '<input id="id_slug" maxlength="50" name="slug" type="text"')
|
||||
self.assertContains(response, '<option value="%s">Blog / sample_app</option>' % self.app_config_1.pk)
|
||||
|
||||
with self.settings(BLOG_USE_ABSTRACT=True):
|
||||
fsets = post_admin.get_fieldsets(request)
|
||||
self.assertTrue('abstract' in fsets[0][1]['fields'])
|
||||
with self.settings(BLOG_USE_ABSTRACT=False):
|
||||
fsets = post_admin.get_fieldsets(request)
|
||||
self.assertFalse('abstract' in fsets[0][1]['fields'])
|
||||
# Changeview is 'normal'
|
||||
response = post_admin.change_view(request, str(post.pk))
|
||||
self.assertContains(response, '<input id="id_slug" maxlength="50" name="slug" type="text" value="first-post" />')
|
||||
self.assertContains(response, '<option value="%s" selected="selected">Blog / sample_app</option>' % self.app_config_1.pk)
|
||||
|
||||
def test_admin_blogconfig_views(self):
|
||||
post_admin = admin.site._registry[BlogConfig]
|
||||
request = self.get_page_request('/', self.user, r'/en/blog/', edit=False)
|
||||
|
||||
# Add view only has an empty form - no type
|
||||
response = post_admin.add_view(request)
|
||||
self.assertNotContains(response, 'djangocms_blog.cms_appconfig.BlogConfig')
|
||||
self.assertContains(response, '<input class="vTextField" id="id_namespace" maxlength="100" name="namespace" type="text" />')
|
||||
|
||||
# Changeview is 'normal', with a few preselected items
|
||||
response = post_admin.change_view(request, str(self.app_config_1.pk))
|
||||
self.assertContains(response, 'djangocms_blog.cms_appconfig.BlogConfig')
|
||||
self.assertContains(response, '<option value="Article" selected="selected">Article</option>')
|
||||
# check that all the form fields are visible in the admin
|
||||
for fieldname in BlogConfigForm.base_fields:
|
||||
self.assertContains(response, 'id="id_config-%s"' % fieldname)
|
||||
self.assertContains(response, '<input id="id_config-og_app_id" maxlength="200" name="config-og_app_id" type="text" />')
|
||||
self.assertContains(response, '<input class="vTextField" id="id_namespace" maxlength="100" name="namespace" type="text" value="sample_app" />')
|
||||
|
||||
def test_admin_category_views(self):
|
||||
post_admin = admin.site._registry[BlogCategory]
|
||||
request = self.get_page_request('/', self.user, r'/en/blog/', edit=False)
|
||||
|
||||
# Add view only has an empty form - no type
|
||||
response = post_admin.add_view(request)
|
||||
self.assertNotContains(response, '<input class="vTextField" id="id_name" maxlength="255" name="name" type="text" value="category 1" />')
|
||||
self.assertContains(response, '<option value="%s">Blog / sample_app</option>' % self.app_config_1.pk)
|
||||
|
||||
# Changeview is 'normal', with a few preselected items
|
||||
response = post_admin.change_view(request, str(self.category_1.pk))
|
||||
# response.render()
|
||||
# print(response.content.decode('utf-8'))
|
||||
self.assertContains(response, '<input class="vTextField" id="id_name" maxlength="255" name="name" type="text" value="category 1" />')
|
||||
self.assertContains(response, '<option value="%s" selected="selected">Blog / sample_app</option>' % self.app_config_1.pk)
|
||||
|
||||
def test_admin_fieldsets(self):
|
||||
post_admin = admin.site._registry[Post]
|
||||
request = self.get_page_request('/', self.user_staff, r'/en/blog/?app_config=%s' % self.app_config_1.pk, edit=False)
|
||||
|
||||
# Use placeholder
|
||||
self.app_config_1.app_data.config.use_placeholder = True
|
||||
self.app_config_1.save()
|
||||
fsets = post_admin.get_fieldsets(request)
|
||||
self.assertFalse('post_text' in fsets[0][1]['fields'])
|
||||
|
||||
self.app_config_1.app_data.config.use_placeholder = False
|
||||
self.app_config_1.save()
|
||||
fsets = post_admin.get_fieldsets(request)
|
||||
self.assertTrue('post_text' in fsets[0][1]['fields'])
|
||||
|
||||
self.app_config_1.app_data.config.use_placeholder = True
|
||||
self.app_config_1.save()
|
||||
|
||||
# Use abstract
|
||||
self.app_config_1.app_data.config.use_abstract = True
|
||||
self.app_config_1.save()
|
||||
fsets = post_admin.get_fieldsets(request)
|
||||
self.assertTrue('abstract' in fsets[0][1]['fields'])
|
||||
|
||||
self.app_config_1.app_data.config.use_abstract = False
|
||||
self.app_config_1.save()
|
||||
fsets = post_admin.get_fieldsets(request)
|
||||
self.assertFalse('abstract' in fsets[0][1]['fields'])
|
||||
|
||||
self.app_config_1.app_data.config.use_abstract = True
|
||||
self.app_config_1.save()
|
||||
|
||||
with self.settings(BLOG_MULTISITE=True):
|
||||
fsets = post_admin.get_fieldsets(request)
|
||||
|
@ -51,49 +124,65 @@ class AdminTest(BaseTest):
|
|||
fsets = post_admin.get_fieldsets(request)
|
||||
self.assertFalse('sites' in fsets[1][1]['fields'][0])
|
||||
|
||||
request = self.get_page_request('/', self.user, r'/en/blog/', edit=False)
|
||||
request = self.get_page_request('/', self.user, r'/en/blog/?app_config=%s' % self.app_config_1.pk, edit=False)
|
||||
fsets = post_admin.get_fieldsets(request)
|
||||
self.assertTrue('author' in fsets[1][1]['fields'][0])
|
||||
|
||||
with self.login_user_context(self.user):
|
||||
request = self.get_request('/', 'en', user=self.user, path=r'/en/blog/?app_config=%s' % self.app_config_1.pk)
|
||||
msg_mid = MessageMiddleware()
|
||||
msg_mid.process_request(request)
|
||||
post_admin = admin.site._registry[Post]
|
||||
response = post_admin.add_view(request)
|
||||
self.assertContains(response, '<option value="%s">%s</option>' % (
|
||||
self.category_1.pk, self.category_1.safe_translation_getter('name', language_code='en')
|
||||
))
|
||||
|
||||
def test_admin_auto_author(self):
|
||||
page1, page2 = self.get_pages()
|
||||
data = deepcopy(self.data['en'][0])
|
||||
pages = self.get_pages()
|
||||
data = deepcopy(self._post_data[0]['en'])
|
||||
|
||||
with self.login_user_context(self.user):
|
||||
with self.settings(BLOG_AUTHOR_DEFAULT=True):
|
||||
data['date_published_0'] = now().strftime('%Y-%m-%d')
|
||||
data['date_published_1'] = now().strftime('%H:%M:%S')
|
||||
data['categories'] = self.category_1.pk
|
||||
request = self.post_request(page1, 'en', user=self.user, data=data, path='/en/?edit_fields=post_text')
|
||||
msg_mid = MessageMiddleware()
|
||||
msg_mid.process_request(request)
|
||||
post_admin = admin.site._registry[Post]
|
||||
response = post_admin.add_view(request)
|
||||
self.assertEqual(response.status_code, 302)
|
||||
self.assertEqual(Post.objects.count(), 1)
|
||||
self.assertEqual(Post.objects.get(translations__slug='first-post').author_id,
|
||||
request.user.pk)
|
||||
self.app_config_1.app_data.config.set_author = True
|
||||
self.app_config_1.save()
|
||||
data['date_published_0'] = now().strftime('%Y-%m-%d')
|
||||
data['date_published_1'] = now().strftime('%H:%M:%S')
|
||||
data['categories'] = self.category_1.pk
|
||||
data['app_config'] = self.app_config_1.pk
|
||||
request = self.post_request(pages[0], 'en', user=self.user, data=data, path=r'/en/blog/?app_config=%s' % self.app_config_1.pk)
|
||||
msg_mid = MessageMiddleware()
|
||||
msg_mid.process_request(request)
|
||||
post_admin = admin.site._registry[Post]
|
||||
response = post_admin.add_view(request)
|
||||
self.assertEqual(response.status_code, 302)
|
||||
self.assertEqual(Post.objects.count(), 1)
|
||||
self.assertEqual(Post.objects.get(translations__slug='first-post').author_id, request.user.pk)
|
||||
|
||||
with self.settings(BLOG_AUTHOR_DEFAULT=False):
|
||||
data = deepcopy(self.data['en'][1])
|
||||
data['date_published_0'] = now().strftime('%Y-%m-%d')
|
||||
data['date_published_1'] = now().strftime('%H:%M:%S')
|
||||
data['categories'] = self.category_1.pk
|
||||
request = self.post_request(page1, 'en', user=self.user, data=data, path='/en/?edit_fields=post_text')
|
||||
msg_mid = MessageMiddleware()
|
||||
msg_mid.process_request(request)
|
||||
post_admin = admin.site._registry[Post]
|
||||
response = post_admin.add_view(request)
|
||||
self.assertEqual(response.status_code, 302)
|
||||
self.assertEqual(Post.objects.count(), 2)
|
||||
self.assertEqual(Post.objects.get(translations__slug='second-post').author_id, None)
|
||||
self.app_config_1.app_data.config.set_author = False
|
||||
self.app_config_1.save()
|
||||
data = deepcopy(self._post_data[1]['en'])
|
||||
data['date_published_0'] = now().strftime('%Y-%m-%d')
|
||||
data['date_published_1'] = now().strftime('%H:%M:%S')
|
||||
data['categories'] = self.category_1.pk
|
||||
data['app_config'] = self.app_config_1.pk
|
||||
request = self.post_request(pages[0], 'en', user=self.user, data=data, path=r'/en/blog/?app_config=%s' % self.app_config_1.pk)
|
||||
msg_mid = MessageMiddleware()
|
||||
msg_mid.process_request(request)
|
||||
post_admin = admin.site._registry[Post]
|
||||
response = post_admin.add_view(request)
|
||||
self.assertEqual(response.status_code, 302)
|
||||
self.assertEqual(Post.objects.count(), 2)
|
||||
self.assertEqual(Post.objects.get(translations__slug='second-post').author_id, None)
|
||||
|
||||
with self.settings(BLOG_AUTHOR_DEFAULT='staff'):
|
||||
data = deepcopy(self.data['en'][2])
|
||||
self.app_config_1.app_data.config.set_author = True
|
||||
self.app_config_1.save()
|
||||
data = deepcopy(self._post_data[2]['en'])
|
||||
data['date_published_0'] = now().strftime('%Y-%m-%d')
|
||||
data['date_published_1'] = now().strftime('%H:%M:%S')
|
||||
data['categories'] = self.category_1.pk
|
||||
request = self.post_request(page1, 'en', user=self.user, data=data, path='/en/?edit_fields=post_text')
|
||||
data['app_config'] = self.app_config_1.pk
|
||||
request = self.post_request(pages[0], 'en', user=self.user, data=data, path=r'/en/blog/?app_config=%s' % self.app_config_1.pk)
|
||||
msg_mid = MessageMiddleware()
|
||||
msg_mid.process_request(request)
|
||||
post_admin = admin.site._registry[Post]
|
||||
|
@ -103,13 +192,13 @@ class AdminTest(BaseTest):
|
|||
self.assertEqual(Post.objects.get(translations__slug='third-post').author.username, 'staff')
|
||||
|
||||
def test_admin_post_text(self):
|
||||
page1, page2 = self.get_pages()
|
||||
post = self._get_post(self.data['en'][0])
|
||||
pages = self.get_pages()
|
||||
post = self._get_post(self._post_data[0]['en'])
|
||||
|
||||
with self.login_user_context(self.user):
|
||||
with self.settings(BLOG_USE_PLACEHOLDER=False):
|
||||
data = {'post_text': 'ehi text'}
|
||||
request = self.post_request(page1, 'en', user=self.user, data=data, path='/en/?edit_fields=post_text')
|
||||
data = {'post_text': 'ehi text', 'title': 'some title'}
|
||||
request = self.post_request(pages[0], 'en', user=self.user, data=data, path='/en/?edit_fields=post_text')
|
||||
msg_mid = MessageMiddleware()
|
||||
msg_mid.process_request(request)
|
||||
post_admin = admin.site._registry[Post]
|
||||
|
@ -122,9 +211,14 @@ class AdminTest(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.main_image = self.img
|
||||
self.get_pages()
|
||||
|
||||
self.app_config_1.app_data.config.gplus_author = 'RandomJoe'
|
||||
self.app_config_1.save()
|
||||
|
||||
post = self._get_post(self._post_data[0]['en'])
|
||||
post = self._get_post(self._post_data[0]['it'], post, 'it')
|
||||
post.main_image = self.create_filer_image_object()
|
||||
post.save()
|
||||
post.set_current_language('en')
|
||||
meta_en = post.as_meta()
|
||||
|
@ -134,6 +228,14 @@ class ModelsTest(BaseTest):
|
|||
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)
|
||||
self.assertEqual(meta_en.locale, 'en')
|
||||
self.assertEqual(meta_en.twitter_site, '')
|
||||
self.assertEqual(meta_en.twitter_author, '')
|
||||
self.assertEqual(meta_en.twitter_type, 'summary')
|
||||
self.assertEqual(meta_en.gplus_author, 'RandomJoe')
|
||||
self.assertEqual(meta_en.gplus_type, 'Blog')
|
||||
self.assertEqual(meta_en.og_type, 'Article')
|
||||
self.assertEqual(meta_en.facebook_app_id, None)
|
||||
post.set_current_language('it')
|
||||
meta_it = post.as_meta()
|
||||
self.assertEqual(meta_it.title, post.title)
|
||||
|
@ -147,7 +249,11 @@ class ModelsTest(BaseTest):
|
|||
'month': '%02d' % post.date_published.month,
|
||||
'day': '%02d' % post.date_published.day,
|
||||
'slug': post.safe_translation_getter('slug', any_language=get_language())}
|
||||
url_en = reverse('djangocms_blog:post-detail', kwargs=kwargs)
|
||||
url_en = reverse(
|
||||
'%s:post-detail' % self.app_config_1.namespace,
|
||||
kwargs=kwargs,
|
||||
current_app=self.app_config_1
|
||||
)
|
||||
self.assertEqual(url_en, post.get_absolute_url())
|
||||
|
||||
with override('it'):
|
||||
|
@ -156,7 +262,11 @@ class ModelsTest(BaseTest):
|
|||
'month': '%02d' % post.date_published.month,
|
||||
'day': '%02d' % post.date_published.day,
|
||||
'slug': post.safe_translation_getter('slug', any_language=get_language())}
|
||||
url_it = reverse('djangocms_blog:post-detail', kwargs=kwargs)
|
||||
url_it = reverse(
|
||||
'%s:post-detail' % self.app_config_1.namespace,
|
||||
kwargs=kwargs,
|
||||
current_app=self.app_config_1
|
||||
)
|
||||
self.assertEqual(url_it, post.get_absolute_url())
|
||||
self.assertNotEqual(url_it, url_en)
|
||||
|
||||
|
@ -185,9 +295,47 @@ class ModelsTest(BaseTest):
|
|||
post.meta_title = 'meta title'
|
||||
self.assertEqual(post.get_title(), 'meta title')
|
||||
|
||||
def test_urls(self):
|
||||
self.get_pages()
|
||||
post = self._get_post(self._post_data[0]['en'])
|
||||
post = self._get_post(self._post_data[0]['it'], post, 'it')
|
||||
|
||||
# default
|
||||
self.assertTrue(re.match(r'.*\d{4}/\d{2}/\d{2}/%s/$' % post.slug, post.get_absolute_url()))
|
||||
|
||||
# full date
|
||||
self.app_config_1.app_data.config.url_patterns = 'full_date'
|
||||
self.app_config_1.save()
|
||||
post.app_config = self.app_config_1
|
||||
self.assertTrue(re.match(r'.*\d{4}/\d{2}/\d{2}/%s/$' % post.slug, post.get_absolute_url()))
|
||||
|
||||
# short date
|
||||
self.app_config_1.app_data.config.url_patterns = 'short_date'
|
||||
self.app_config_1.save()
|
||||
post.app_config = self.app_config_1
|
||||
self.assertTrue(re.match(r'.*\d{4}/\d{2}/%s/$' % post.slug, post.get_absolute_url()))
|
||||
|
||||
# category
|
||||
self.app_config_1.app_data.config.url_patterns = 'category'
|
||||
self.app_config_1.save()
|
||||
post.app_config = self.app_config_1
|
||||
self.assertTrue(re.match(r'.*/\w[-\w]*/%s/$' % post.slug, post.get_absolute_url()))
|
||||
self.assertTrue(
|
||||
re.match(
|
||||
r'.*%s/%s/$' % (post.categories.first().slug, post.slug),
|
||||
post.get_absolute_url()
|
||||
)
|
||||
)
|
||||
|
||||
# slug only
|
||||
self.app_config_1.app_data.config.url_patterns = 'category'
|
||||
self.app_config_1.save()
|
||||
post.app_config = self.app_config_1
|
||||
self.assertTrue(re.match(r'.*/%s/$' % post.slug, post.get_absolute_url()))
|
||||
|
||||
def test_manager(self):
|
||||
post1 = self._get_post(self.data['en'][0])
|
||||
post2 = self._get_post(self.data['en'][1])
|
||||
post1 = self._get_post(self._post_data[0]['en'])
|
||||
post2 = self._get_post(self._post_data[1]['en'])
|
||||
|
||||
# default queryset, published and unpublished posts
|
||||
months = Post.objects.get_months()
|
||||
|
@ -211,6 +359,7 @@ class ModelsTest(BaseTest):
|
|||
post2.save()
|
||||
self.assertEqual(len(Post.objects.available()), 2)
|
||||
self.assertEqual(len(Post.objects.published()), 1)
|
||||
self.assertEqual(len(Post.objects.published_future()), 2)
|
||||
self.assertEqual(len(Post.objects.archived()), 0)
|
||||
|
||||
# If post is published but end publishing date is in the past
|
||||
|
@ -222,7 +371,7 @@ class ModelsTest(BaseTest):
|
|||
self.assertEqual(len(Post.objects.archived()), 1)
|
||||
|
||||
# counting with language fallback enabled
|
||||
self._get_post(self.data['it'][0], post1, 'it')
|
||||
self._get_post(self._post_data[0]['it'], post1, 'it')
|
||||
self.assertEqual(len(Post.objects.filter_by_language('it')), 2)
|
||||
|
||||
# No fallback
|
||||
|
@ -235,8 +384,8 @@ class ModelsTest(BaseTest):
|
|||
parler.appsettings.PARLER_LANGUAGES[Site.objects.get_current().pk][index]['hide_untranslated'] = False
|
||||
|
||||
def test_tag_cloud(self):
|
||||
post1 = self._get_post(self.data['en'][0])
|
||||
post2 = self._get_post(self.data['en'][1])
|
||||
post1 = self._get_post(self._post_data[0]['en'])
|
||||
post2 = self._get_post(self._post_data[1]['en'])
|
||||
post1.tags.add('tag 1', 'tag 2', 'tag 3', 'tag 4')
|
||||
post1.save()
|
||||
post2.tags.add('tag 6', 'tag 2', 'tag 5', 'tag 8')
|
||||
|
@ -269,15 +418,24 @@ class ModelsTest(BaseTest):
|
|||
self.assertEqual(set(Post.objects.tag_cloud()), set(tags_1))
|
||||
self.assertEqual(set(Post.objects.tag_cloud(published=False)), set(tags))
|
||||
|
||||
tags1 = set(Post.objects.tag_list(Post))
|
||||
tags2 = set(Tag.objects.all())
|
||||
self.assertEqual(tags1, tags2)
|
||||
|
||||
self.assertEqual(
|
||||
list(Post.objects.tagged(queryset=Post.objects.filter(pk=post1.pk)).order_by('pk').values_list('pk')),
|
||||
list(Post.objects.filter(pk__in=(post1.pk, post2.pk)).order_by('pk').values_list('pk'))
|
||||
)
|
||||
|
||||
def test_plugin_latest(self):
|
||||
post1 = self._get_post(self.data['en'][0])
|
||||
self._get_post(self.data['en'][1])
|
||||
post1 = self._get_post(self._post_data[0]['en'])
|
||||
self._get_post(self._post_data[1]['en'])
|
||||
post1.tags.add('tag 1')
|
||||
post1.save()
|
||||
request = self.get_page_request('/', AnonymousUser(), r'/en/blog/', edit=False)
|
||||
request_auth = self.get_page_request('/', self.user_staff, r'/en/blog/', edit=False)
|
||||
request_edit = self.get_page_request('/', self.user_staff, r'/en/blog/', edit=True)
|
||||
plugin = add_plugin(post1.content, 'BlogLatestEntriesPlugin', language='en')
|
||||
plugin = add_plugin(post1.content, 'BlogLatestEntriesPlugin', language='en', app_config=self.app_config_1)
|
||||
tag = Tag.objects.get(slug='tag-1')
|
||||
plugin.tags.add(tag)
|
||||
# unauthenticated users get no post
|
||||
|
@ -292,11 +450,11 @@ class ModelsTest(BaseTest):
|
|||
self.assertEqual(len(plugin.get_posts(request)), 1)
|
||||
|
||||
def test_copy_plugin_latest(self):
|
||||
post1 = self._get_post(self.data['en'][0])
|
||||
post2 = self._get_post(self.data['en'][1])
|
||||
post1 = self._get_post(self._post_data[0]['en'])
|
||||
post2 = self._get_post(self._post_data[1]['en'])
|
||||
tag1 = Tag.objects.create(name='tag 1')
|
||||
tag2 = Tag.objects.create(name='tag 2')
|
||||
plugin = add_plugin(post1.content, 'BlogLatestEntriesPlugin', language='en')
|
||||
plugin = add_plugin(post1.content, 'BlogLatestEntriesPlugin', language='en', app_config=self.app_config_1)
|
||||
plugin.tags.add(tag1)
|
||||
plugin.tags.add(tag2)
|
||||
if CMS_30:
|
||||
|
@ -309,10 +467,10 @@ class ModelsTest(BaseTest):
|
|||
self.assertEqual(set(new[0].tags.all()), set(plugin.tags.all()))
|
||||
|
||||
def test_plugin_author(self):
|
||||
post1 = self._get_post(self.data['en'][0])
|
||||
post2 = self._get_post(self.data['en'][1])
|
||||
post1 = self._get_post(self._post_data[0]['en'])
|
||||
post2 = self._get_post(self._post_data[1]['en'])
|
||||
request = self.get_page_request('/', AnonymousUser(), r'/en/blog/', edit=False)
|
||||
plugin = add_plugin(post1.content, 'BlogAuthorPostsPlugin', language='en')
|
||||
plugin = add_plugin(post1.content, 'BlogAuthorPostsPlugin', language='en', app_config=self.app_config_1)
|
||||
plugin.authors.add(self.user)
|
||||
self.assertEqual(len(plugin.get_posts(request)), 0)
|
||||
self.assertEqual(plugin.get_authors()[0].count, 0)
|
||||
|
@ -328,9 +486,9 @@ class ModelsTest(BaseTest):
|
|||
self.assertEqual(plugin.get_authors()[0].count, 2)
|
||||
|
||||
def test_copy_plugin_author(self):
|
||||
post1 = self._get_post(self.data['en'][0])
|
||||
post2 = self._get_post(self.data['en'][1])
|
||||
plugin = add_plugin(post1.content, 'BlogAuthorPostsPlugin', language='en')
|
||||
post1 = self._get_post(self._post_data[0]['en'])
|
||||
post2 = self._get_post(self._post_data[1]['en'])
|
||||
plugin = add_plugin(post1.content, 'BlogAuthorPostsPlugin', language='en', app_config=self.app_config_1)
|
||||
plugin.authors.add(self.user)
|
||||
if CMS_30:
|
||||
plugins = list(post1.content.cmsplugin_set.filter(language='en').order_by('tree_id', 'level', 'position'))
|
||||
|
@ -342,9 +500,9 @@ class ModelsTest(BaseTest):
|
|||
|
||||
def test_multisite(self):
|
||||
with override('en'):
|
||||
post1 = self._get_post(self.data['en'][0], sites=(self.site_1,))
|
||||
post2 = self._get_post(self.data['en'][1], sites=(self.site_2,))
|
||||
post3 = self._get_post(self.data['en'][2], sites=(self.site_2, self.site_1))
|
||||
post1 = self._get_post(self._post_data[0]['en'], sites=(self.site_1,))
|
||||
post2 = self._get_post(self._post_data[1]['en'], sites=(self.site_2,))
|
||||
post3 = self._get_post(self._post_data[2]['en'], sites=(self.site_2, self.site_1))
|
||||
|
||||
self.assertEqual(len(Post.objects.all()), 3)
|
||||
with self.settings(**{'SITE_ID': self.site_1.pk}):
|
||||
|
@ -353,3 +511,25 @@ class ModelsTest(BaseTest):
|
|||
with self.settings(**{'SITE_ID': self.site_2.pk}):
|
||||
self.assertEqual(len(Post.objects.all().on_site()), 2)
|
||||
self.assertEqual(set(list(Post.objects.all().on_site())), set([post2, post3]))
|
||||
|
||||
def test_str_repr(self):
|
||||
post1 = self._get_post(self._post_data[0]['en'])
|
||||
post1.meta_description = ''
|
||||
post1.main_image = None
|
||||
post1.save()
|
||||
|
||||
self.assertEqual(force_text(post1), post1.title)
|
||||
self.assertEqual(post1.get_description(), strip_tags(post1.abstract))
|
||||
self.assertEqual(post1.get_image_full_url(), '')
|
||||
self.assertEqual(post1.get_author(), self.user)
|
||||
|
||||
self.assertEqual(force_text(post1.categories.first()), 'category 1')
|
||||
|
||||
plugin = add_plugin(post1.content, 'BlogAuthorPostsPlugin', language='en', app_config=self.app_config_1)
|
||||
self.assertEqual(force_text(plugin.__str__()), '5 latest articles by author')
|
||||
|
||||
plugin = add_plugin(post1.content, 'BlogLatestEntriesPlugin', language='en', app_config=self.app_config_1)
|
||||
self.assertEqual(force_text(plugin.__str__()), '5 latest articles by tag')
|
||||
|
||||
plugin = add_plugin(post1.content, 'BlogArchivePlugin', language='en', app_config=self.app_config_1)
|
||||
self.assertEqual(force_text(plugin.__str__()), 'generic blog plugin')
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import absolute_import, print_function, unicode_literals
|
||||
|
||||
import os.path
|
||||
import re
|
||||
|
||||
from cms.api import add_plugin
|
||||
|
@ -10,79 +11,80 @@ from taggit.models import Tag
|
|||
|
||||
from djangocms_blog.models import BlogCategory
|
||||
|
||||
from . import BaseTest
|
||||
from .base import BaseTest
|
||||
|
||||
|
||||
class PluginTest(BaseTest):
|
||||
|
||||
def test_plugin_latest(self):
|
||||
page1, page2 = self.get_pages()
|
||||
post1 = self._get_post(self.data['en'][0])
|
||||
post2 = self._get_post(self.data['en'][1])
|
||||
post1.tags.add('tag 1')
|
||||
post1.publish = True
|
||||
post1.save()
|
||||
ph = page1.placeholders.get(slot='content')
|
||||
pages = self.get_pages()
|
||||
posts = self.get_posts()
|
||||
posts[0].tags.add('tag 1')
|
||||
posts[0].publish = True
|
||||
posts[0].save()
|
||||
ph = pages[0].placeholders.get(slot='content')
|
||||
|
||||
plugin = add_plugin(ph, 'BlogLatestEntriesPlugin', language='en')
|
||||
plugin = add_plugin(ph, 'BlogLatestEntriesPlugin', language='en', app_config=self.app_config_1)
|
||||
tag = Tag.objects.get(slug='tag-1')
|
||||
plugin.tags.add(tag)
|
||||
|
||||
context = self.get_plugin_context(page1, 'en', plugin, edit=True)
|
||||
context = self.get_plugin_context(pages[0], 'en', plugin, edit=True)
|
||||
rendered = plugin.render_plugin(context, ph)
|
||||
self.assertTrue(rendered.find('cms_plugin-djangocms_blog-post-abstract-1') > -1)
|
||||
try:
|
||||
self.assertTrue(rendered.find('cms_plugin-djangocms_blog-post-abstract-1') > -1)
|
||||
except AssertionError:
|
||||
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(post1.get_absolute_url()) > -1)
|
||||
self.assertTrue(rendered.find(posts[0].get_absolute_url()) > -1)
|
||||
|
||||
category_2 = BlogCategory.objects.create(name=u'category 2')
|
||||
category_2 = BlogCategory.objects.create(name='category 2', app_config=self.app_config_1)
|
||||
category_2.set_current_language('it', initialize=True)
|
||||
category_2.name = u'categoria 2'
|
||||
category_2.name = 'categoria 2'
|
||||
category_2.save()
|
||||
category_2.set_current_language('en')
|
||||
post2.categories.add(category_2)
|
||||
plugin = add_plugin(ph, 'BlogLatestEntriesPlugin', language='en')
|
||||
posts[1].categories.add(category_2)
|
||||
plugin = add_plugin(ph, 'BlogLatestEntriesPlugin', language='en', app_config=self.app_config_1)
|
||||
plugin.categories.add(category_2)
|
||||
|
||||
context = self.get_plugin_context(page1, 'en', plugin, edit=True)
|
||||
context = self.get_plugin_context(pages[0], 'en', plugin, edit=True)
|
||||
rendered = plugin.render_plugin(context, ph)
|
||||
self.assertTrue(rendered.find('cms_plugin-djangocms_blog-post-abstract-2') > -1)
|
||||
try:
|
||||
self.assertTrue(rendered.find('cms_plugin-djangocms_blog-post-abstract-2') > -1)
|
||||
except AssertionError:
|
||||
self.assertTrue(rendered.find('cms-plugin-djangocms_blog-post-abstract-2') > -1)
|
||||
self.assertTrue(rendered.find(reverse('djangocms_blog:posts-category', kwargs={'category': category_2.slug})) > -1)
|
||||
self.assertTrue(rendered.find('<p>second post first line</p>') > -1)
|
||||
self.assertTrue(rendered.find('<article id="post-second-post"') > -1)
|
||||
self.assertTrue(rendered.find(post2.get_absolute_url()) > -1)
|
||||
self.assertTrue(rendered.find(posts[1].get_absolute_url()) > -1)
|
||||
|
||||
def test_plugin_authors(self):
|
||||
page1, page2 = self.get_pages()
|
||||
post1 = self._get_post(self.data['en'][0])
|
||||
post2 = self._get_post(self.data['en'][1])
|
||||
post1.publish = True
|
||||
post1.save()
|
||||
post2.publish = True
|
||||
post2.save()
|
||||
ph = page1.placeholders.get(slot='content')
|
||||
plugin = add_plugin(ph, 'BlogAuthorPostsPlugin', language='en')
|
||||
plugin.authors.add(self.user)
|
||||
pages = self.get_pages()
|
||||
posts = self.get_posts()
|
||||
posts[0].publish = True
|
||||
posts[0].save()
|
||||
posts[1].publish = True
|
||||
posts[1].save()
|
||||
ph = pages[0].placeholders.get(slot='content')
|
||||
plugin = add_plugin(ph, 'BlogAuthorPostsPlugin', language='en', app_config=self.app_config_1)
|
||||
|
||||
context = self.get_plugin_context(page1, 'en', plugin, edit=True)
|
||||
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):
|
||||
page1, page2 = self.get_pages()
|
||||
post1 = self._get_post(self.data['en'][0])
|
||||
post2 = self._get_post(self.data['en'][1])
|
||||
post1.tags.add('tag 1', 'tag 2', 'test tag')
|
||||
post1.publish = True
|
||||
post1.save()
|
||||
post2.tags.add('test tag', 'another tag')
|
||||
post2.publish = True
|
||||
post2.save()
|
||||
ph = page1.placeholders.get(slot='content')
|
||||
plugin = add_plugin(ph, 'BlogTagsPlugin', language='en')
|
||||
context = self.get_plugin_context(page1, 'en', plugin, edit=True)
|
||||
pages = self.get_pages()
|
||||
posts = self.get_posts()
|
||||
posts[0].tags.add('tag 1', 'tag 2', 'test tag')
|
||||
posts[0].publish = True
|
||||
posts[0].save()
|
||||
posts[1].tags.add('test tag', 'another tag')
|
||||
posts[1].publish = True
|
||||
posts[1].save()
|
||||
ph = pages[0].placeholders.get(slot='content')
|
||||
plugin = add_plugin(ph, 'BlogTagsPlugin', language='en', app_config=self.app_config_1)
|
||||
context = self.get_plugin_context(pages[0], 'en', plugin, edit=True)
|
||||
rendered = plugin.render_plugin(context, ph)
|
||||
for tag in Tag.objects.all():
|
||||
self.assertTrue(rendered.find(reverse('djangocms_blog:posts-tagged', kwargs={'tag': tag.slug})) > -1)
|
||||
|
@ -94,38 +96,55 @@ class PluginTest(BaseTest):
|
|||
self.assertEqual(len(rx.findall(rendered)), 1)
|
||||
|
||||
def test_blog_category_plugin(self):
|
||||
page1, page2 = self.get_pages()
|
||||
post1, post2 = self.get_posts()
|
||||
post1.publish = True
|
||||
post1.save()
|
||||
post2.publish = True
|
||||
post2.save()
|
||||
ph = page1.placeholders.get(slot='content')
|
||||
plugin = add_plugin(ph, 'BlogCategoryPlugin', language='en')
|
||||
pages = self.get_pages()
|
||||
posts = self.get_posts()
|
||||
posts[0].publish = True
|
||||
posts[0].save()
|
||||
posts[1].publish = True
|
||||
posts[1].save()
|
||||
ph = pages[0].placeholders.get(slot='content')
|
||||
plugin = add_plugin(ph, 'BlogCategoryPlugin', language='en', app_config=self.app_config_1)
|
||||
plugin_class = plugin.get_plugin_class_instance()
|
||||
context = self.get_plugin_context(page1, 'en', plugin, edit=True)
|
||||
context = self.get_plugin_context(pages[0], 'en', plugin, edit=True)
|
||||
context = plugin_class.render(context, plugin, ph)
|
||||
self.assertTrue(context['categories'])
|
||||
self.assertEqual(list(context['categories']), [self.category_1])
|
||||
|
||||
def test_blog_archive_plugin(self):
|
||||
page1, page2 = self.get_pages()
|
||||
post1, post2 = self.get_posts()
|
||||
post1.publish = True
|
||||
post1.save()
|
||||
post2.publish = True
|
||||
post2.save()
|
||||
ph = page1.placeholders.get(slot='content')
|
||||
plugin = add_plugin(ph, 'BlogArchivePlugin', language='en')
|
||||
pages = self.get_pages()
|
||||
posts = self.get_posts()
|
||||
posts[0].publish = True
|
||||
posts[0].save()
|
||||
posts[1].publish = True
|
||||
posts[1].save()
|
||||
ph = pages[0].placeholders.get(slot='content')
|
||||
plugin = add_plugin(ph, 'BlogArchivePlugin', language='en', app_config=self.app_config_1)
|
||||
plugin_class = plugin.get_plugin_class_instance()
|
||||
|
||||
context = self.get_plugin_context(page1, 'en', plugin, edit=True)
|
||||
context = self.get_plugin_context(pages[0], 'en', plugin, edit=True)
|
||||
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'], 2)
|
||||
|
||||
post2.publish = False
|
||||
post2.save()
|
||||
posts[1].publish = False
|
||||
posts[1].save()
|
||||
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()
|
||||
|
|
74
tests/test_setup.py
Normal file
74
tests/test_setup.py
Normal file
|
@ -0,0 +1,74 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import absolute_import, print_function, unicode_literals
|
||||
|
||||
import sys
|
||||
|
||||
from cms.api import create_page, create_title
|
||||
from cms.models import Page
|
||||
from cms.utils import get_language_list
|
||||
from django.utils.translation import override
|
||||
|
||||
from djangocms_blog.cms_appconfig import BlogConfig
|
||||
|
||||
from .base import BaseTest
|
||||
|
||||
|
||||
class SetupTest(BaseTest):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super(BaseTest, cls).setUpClass()
|
||||
|
||||
def test_setup_from_url(self):
|
||||
|
||||
# Tests starts with no page and no config
|
||||
self.assertFalse(Page.objects.exists())
|
||||
self.assertFalse(BlogConfig.objects.exists())
|
||||
|
||||
# importing urls triggers the auto setup
|
||||
from djangocms_blog import urls # NOQA
|
||||
|
||||
# Home and blog, published and draft
|
||||
self.assertEqual(Page.objects.count(), 4)
|
||||
self.assertEqual(BlogConfig.objects.count(), 1)
|
||||
|
||||
def setUp(self):
|
||||
self.reload_urlconf()
|
||||
delete = [
|
||||
'djangocms_blog',
|
||||
'djangocms_blog.urls',
|
||||
]
|
||||
for module in delete:
|
||||
del sys.modules[module]
|
||||
|
||||
def test_setup_filled(self):
|
||||
|
||||
# Tests starts with no page and no config
|
||||
self.assertFalse(Page.objects.exists())
|
||||
self.assertFalse(BlogConfig.objects.exists())
|
||||
|
||||
langs = get_language_list()
|
||||
home = None
|
||||
for lang in langs:
|
||||
with override(lang):
|
||||
if not home:
|
||||
home = create_page(
|
||||
'a new home', language=lang,
|
||||
template='blog.html', in_navigation=True, published=True
|
||||
)
|
||||
else:
|
||||
create_title(
|
||||
language=lang, title='a new home', page=home
|
||||
)
|
||||
home.publish(lang)
|
||||
|
||||
# importing urls triggers the auto setup
|
||||
from djangocms_blog import urls # NOQA
|
||||
|
||||
# Home and blog, published and draft
|
||||
self.assertEqual(Page.objects.count(), 4)
|
||||
self.assertEqual(BlogConfig.objects.count(), 1)
|
||||
|
||||
home = Page.objects.get_home()
|
||||
for lang in langs:
|
||||
self.assertEqual(home.get_title(lang), 'a new home')
|
|
@ -6,7 +6,7 @@ from django.core.urlresolvers import reverse
|
|||
|
||||
from djangocms_blog.models import BLOG_CURRENT_POST_IDENTIFIER
|
||||
|
||||
from . import BaseTest
|
||||
from .base import BaseTest
|
||||
|
||||
|
||||
class ToolbarTest(BaseTest):
|
||||
|
@ -16,13 +16,13 @@ class ToolbarTest(BaseTest):
|
|||
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)
|
||||
posts = self.get_posts()
|
||||
pages = self.get_pages()
|
||||
request = self.get_page_request(pages[0], self.user, r'/en/blog/', edit=True)
|
||||
setattr(request, BLOG_CURRENT_POST_IDENTIFIER, posts[0])
|
||||
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)
|
||||
self.assertEqual(len(blog_menu.find_items(ModalItem, url=reverse('admin:djangocms_blog_post_change', args=(posts[0].pk,)))), 1)
|
||||
|
|
1
tests/test_utils/models.py
Normal file
1
tests/test_utils/models.py
Normal file
|
@ -0,0 +1 @@
|
|||
# -*- coding: utf-8 -*-
|
35
tests/test_utils/templates/blog.html
Normal file
35
tests/test_utils/templates/blog.html
Normal file
|
@ -0,0 +1,35 @@
|
|||
{% load cms_tags static menu_tags sekizai_tags %}
|
||||
<!DOCTYPE html {% render_block 'html_extra' %}>
|
||||
<html>
|
||||
<head>
|
||||
<title>{% block title %}{% page_attribute 'title' %}{% endblock title %}</title>
|
||||
{% render_block "css" %}
|
||||
{% include "meta_mixin/meta.html" %}
|
||||
<style type="text/css">
|
||||
.nav {
|
||||
padding-left: 0;
|
||||
}
|
||||
.nav li {
|
||||
display: inline;
|
||||
list-style-type: none;
|
||||
padding-right: 20px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
{% cms_toolbar %}
|
||||
<div style="width: 940px; margin:0 auto">
|
||||
<ul class="nav">
|
||||
{% show_menu 0 100 100 100 %}
|
||||
</ul>
|
||||
{% block content %}
|
||||
{% placeholder "content" %}
|
||||
{% endblock content %}
|
||||
</div>
|
||||
{% render_block "js" %}
|
||||
{% with_data "js-script" as jsset %}
|
||||
{% for js in jsset %}<script type="text/javascript" src="{% static js %}"></script>{% endfor %}
|
||||
{% end_with_data %}
|
||||
{% render_block "js_end" %}
|
||||
</body>
|
||||
</html>
|
|
@ -1,6 +1,8 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import absolute_import, print_function, unicode_literals
|
||||
|
||||
import sys
|
||||
|
||||
from cms.utils.conf import get_cms_setting
|
||||
from django.conf import settings
|
||||
from django.conf.urls import include, patterns, url
|
||||
|
@ -22,9 +24,15 @@ urlpatterns = patterns(
|
|||
|
||||
urlpatterns += staticfiles_urlpatterns()
|
||||
|
||||
if 'server' not in sys.argv:
|
||||
urlpatterns += i18n_patterns(
|
||||
'',
|
||||
url(r'^blog/', include(
|
||||
'djangocms_blog.urls', namespace='djangocms_blog', app_name='djangocms_blog'
|
||||
)),
|
||||
)
|
||||
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')),
|
||||
)
|
||||
|
|
|
@ -1,71 +1,127 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import absolute_import, print_function, unicode_literals
|
||||
|
||||
import os.path
|
||||
|
||||
from aldryn_apphooks_config.utils import get_app_instance
|
||||
from cms.toolbar.items import ModalItem
|
||||
from django.contrib.auth.models import AnonymousUser
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.http import Http404
|
||||
from django.utils.timezone import now
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from parler.tests.utils import override_parler_settings
|
||||
from parler.utils.conf import add_default_language_settings
|
||||
from parler.utils.context import smart_override, switch_language
|
||||
|
||||
from djangocms_blog.feeds import LatestEntriesFeed, TagFeed
|
||||
from djangocms_blog.models import BLOG_CURRENT_NAMESPACE
|
||||
from djangocms_blog.sitemaps import BlogSitemap
|
||||
from djangocms_blog.views import (
|
||||
AuthorEntriesView, CategoryEntriesView, PostArchiveView, PostDetailView, PostListView,
|
||||
TaggedListView,
|
||||
)
|
||||
|
||||
from . import BaseTest
|
||||
from .base import BaseTest
|
||||
|
||||
|
||||
class ViewTest(BaseTest):
|
||||
|
||||
def test_post_list_view(self):
|
||||
page1, page2 = self.get_pages()
|
||||
post1, post2 = self.get_posts()
|
||||
posts = self.get_posts()
|
||||
pages = self.get_pages()
|
||||
|
||||
request = self.get_page_request(page1, AnonymousUser(), r'/en/blog/', edit=False)
|
||||
request = self.get_request(pages[1], 'en', AnonymousUser())
|
||||
|
||||
with smart_override('en'):
|
||||
view_obj = PostListView()
|
||||
view_obj.request = request
|
||||
view_obj.namespace, view_obj.config = get_app_instance(request)
|
||||
self.assertEqual(getattr(request, BLOG_CURRENT_NAMESPACE, None), None)
|
||||
|
||||
self.assertEqual(list(view_obj.get_queryset()), [post1])
|
||||
self.assertEqual(list(view_obj.get_queryset()), [posts[0]])
|
||||
self.assertEqual(getattr(request, BLOG_CURRENT_NAMESPACE), self.app_config_1)
|
||||
|
||||
request = self.get_page_request(page1, self.user, r'/en/blog/', edit=False)
|
||||
request = self.get_page_request(pages[1], self.user, lang='en', edit=False)
|
||||
view_obj.namespace, view_obj.config = get_app_instance(request)
|
||||
view_obj.request = request
|
||||
view_obj.kwargs = {}
|
||||
qs = view_obj.get_queryset()
|
||||
self.assertEqual(qs.count(), 1)
|
||||
self.assertEqual(set(qs), set([post1]))
|
||||
self.assertEqual(set(qs), set([posts[0]]))
|
||||
|
||||
request = self.get_page_request(page1, self.user, r'/en/blog/', edit=True)
|
||||
request = self.get_page_request(pages[1], self.user, lang='en', edit=True)
|
||||
view_obj.namespace, view_obj.config = get_app_instance(request)
|
||||
view_obj.request = request
|
||||
self.assertEqual(set(view_obj.get_queryset()), set([post1, post2]))
|
||||
self.assertEqual(set(view_obj.get_queryset()), set([posts[0], posts[1], posts[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']), [post2])
|
||||
self.assertEqual(context['paginator'].count, 2)
|
||||
self.assertEqual(context['post_list'][0].title, 'Second post')
|
||||
self.assertEqual(list(context['post_list']), [posts[2]])
|
||||
self.assertEqual(context['paginator'].count, 3)
|
||||
self.assertEqual(context['post_list'][0].title, 'Third post')
|
||||
response = view_obj.render_to_response(context)
|
||||
self.assertContains(response, context['post_list'][0].get_absolute_url())
|
||||
self.assertEqual(getattr(request, BLOG_CURRENT_NAMESPACE), self.app_config_1)
|
||||
|
||||
with smart_override('it'):
|
||||
request = self.get_page_request(page1, self.user, r'/it/blog/', lang='it', edit=True)
|
||||
request = self.get_page_request(pages[1], self.user, lang='it', edit=True)
|
||||
view_obj = PostListView()
|
||||
view_obj.namespace, view_obj.config = get_app_instance(request)
|
||||
view_obj.request = request
|
||||
view_obj.kwargs = {}
|
||||
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')
|
||||
self.assertEqual(context['post_list'][0].title, 'Terzo post')
|
||||
response = view_obj.render_to_response(context)
|
||||
self.assertContains(response, context['post_list'][0].get_absolute_url())
|
||||
blog_menu = request.toolbar.get_or_create_menu('djangocms_blog', _('Blog'))
|
||||
|
||||
self.assertEqual(len(blog_menu.items), 3)
|
||||
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_blogconfig_change', args=(self.app_config_1.pk,)
|
||||
)
|
||||
)), 1)
|
||||
|
||||
def test_get_view_url(self):
|
||||
posts = self.get_posts()
|
||||
pages = self.get_pages()
|
||||
|
||||
# Test the custom version of get_view_url against the different namespaces
|
||||
request = self.get_request(pages[1], 'en', AnonymousUser())
|
||||
view_obj_1 = PostListView()
|
||||
view_obj_1.request = request
|
||||
view_obj_1.args = ()
|
||||
view_obj_1.kwargs = {}
|
||||
view_obj_1.namespace, view_obj_1.config = get_app_instance(request)
|
||||
self.assertEqual(view_obj_1.get_view_url(), pages[1].get_absolute_url())
|
||||
|
||||
request = self.get_request(pages[2], 'en', AnonymousUser())
|
||||
view_obj_2 = PostListView()
|
||||
view_obj_2.request = request
|
||||
view_obj_2.args = ()
|
||||
view_obj_2.kwargs = {}
|
||||
view_obj_2.namespace, view_obj_2.config = get_app_instance(request)
|
||||
self.assertEqual(view_obj_2.get_view_url(), pages[2].get_absolute_url())
|
||||
|
||||
view_obj_2.view_url_name = None
|
||||
with self.assertRaises(ImproperlyConfigured):
|
||||
view_obj_2.get_view_url()
|
||||
|
||||
def test_post_list_view_fallback(self):
|
||||
page1, page2 = self.get_pages()
|
||||
post1, post2 = self.get_posts()
|
||||
posts = self.get_posts()
|
||||
pages = self.get_pages()
|
||||
|
||||
PARLER_FALLBACK = {
|
||||
1: (
|
||||
|
@ -81,89 +137,97 @@ class ViewTest(BaseTest):
|
|||
|
||||
with smart_override('fr'):
|
||||
view_obj = PostListView()
|
||||
request = self.get_page_request(page1, self.user, r'/fr/blog/', lang='fr', edit=True)
|
||||
request = self.get_page_request(pages[1], self.user, lang='fr', edit=True)
|
||||
view_obj.request = request
|
||||
view_obj.namespace, view_obj.config = get_app_instance(request)
|
||||
view_obj.kwargs = {}
|
||||
view_obj.object_list = view_obj.get_queryset()
|
||||
view_obj.get_context_data(object_list=view_obj.object_list)
|
||||
self.assertEqual(view_obj.get_queryset().count(), 2)
|
||||
self.assertEqual(view_obj.get_queryset().count(), 3)
|
||||
|
||||
PARLER_FALLBACK = add_default_language_settings(PARLER_FALLBACK)
|
||||
with override_parler_settings(PARLER_LANGUAGES=PARLER_FALLBACK):
|
||||
|
||||
view_obj = PostListView()
|
||||
request = self.get_page_request(page1, self.user, r'/fr/blog/', lang='fr', edit=True)
|
||||
request = self.get_page_request(pages[1], self.user, lang='fr', edit=True)
|
||||
view_obj.request = request
|
||||
view_obj.namespace, view_obj.config = get_app_instance(request)
|
||||
view_obj.kwargs = {}
|
||||
view_obj.object_list = view_obj.get_queryset()
|
||||
view_obj.get_context_data(object_list=view_obj.object_list)
|
||||
self.assertEqual(view_obj.get_queryset().count(), 0)
|
||||
|
||||
def test_post_detail_view(self):
|
||||
page1, page2 = self.get_pages()
|
||||
post1, post2 = self.get_posts()
|
||||
posts = self.get_posts()
|
||||
pages = self.get_pages()
|
||||
|
||||
with smart_override('en'):
|
||||
with switch_language(post1, 'en'):
|
||||
request = self.get_page_request(page1, AnonymousUser(), r'/en/blog/', edit=False)
|
||||
with switch_language(posts[0], 'en'):
|
||||
request = self.get_page_request(pages[1], AnonymousUser(), lang='en', edit=False)
|
||||
view_obj = PostDetailView()
|
||||
view_obj.request = request
|
||||
view_obj.namespace, view_obj.config = get_app_instance(request)
|
||||
|
||||
with self.assertRaises(Http404):
|
||||
view_obj.kwargs = {'slug': 'not-existing'}
|
||||
post_obj = view_obj.get_object()
|
||||
|
||||
view_obj.kwargs = {'slug': post1.slug}
|
||||
view_obj.kwargs = {'slug': posts[0].slug}
|
||||
post_obj = view_obj.get_object()
|
||||
self.assertEqual(post_obj, post1)
|
||||
self.assertEqual(post_obj, posts[0])
|
||||
self.assertEqual(post_obj.language_code, 'en')
|
||||
|
||||
with smart_override('it'):
|
||||
with switch_language(post1, 'it'):
|
||||
request = self.get_page_request(page1, AnonymousUser(), r'/it/blog/', lang='it', edit=False)
|
||||
with switch_language(posts[0], 'it'):
|
||||
request = self.get_page_request(pages[1], AnonymousUser(), lang='it', edit=False)
|
||||
view_obj = PostDetailView()
|
||||
view_obj.request = request
|
||||
view_obj.kwargs = {'slug': post1.slug}
|
||||
view_obj.namespace, view_obj.config = get_app_instance(request)
|
||||
|
||||
view_obj.kwargs = {'slug': posts[0].slug}
|
||||
post_obj = view_obj.get_object()
|
||||
self.assertEqual(post_obj, post1)
|
||||
self.assertEqual(post_obj, posts[0])
|
||||
self.assertEqual(post_obj.language_code, 'it')
|
||||
|
||||
view_obj.object = post_obj
|
||||
context = view_obj.get_context_data()
|
||||
self.assertEqual(context['post'], post1)
|
||||
self.assertEqual(context['post'], posts[0])
|
||||
self.assertEqual(context['post'].language_code, 'it')
|
||||
self.assertTrue(context['meta'])
|
||||
|
||||
def test_post_archive_view(self):
|
||||
page1, page2 = self.get_pages()
|
||||
post1, post2 = self.get_posts()
|
||||
posts = self.get_posts()
|
||||
pages = self.get_pages()
|
||||
|
||||
with smart_override('en'):
|
||||
request = self.get_page_request(page1, AnonymousUser(), r'/en/blog/', edit=False)
|
||||
request = self.get_page_request(pages[1], AnonymousUser(), lang='en', edit=False)
|
||||
view_obj = PostArchiveView()
|
||||
view_obj.request = request
|
||||
view_obj.namespace, view_obj.config = get_app_instance(request)
|
||||
view_obj.kwargs = {'year': now().year, 'month': now().month}
|
||||
|
||||
# One post only, anonymous request
|
||||
qs = view_obj.get_queryset()
|
||||
self.assertEqual(qs.count(), 1)
|
||||
self.assertEqual(list(qs), [post1])
|
||||
self.assertEqual(list(qs), [posts[0]])
|
||||
|
||||
view_obj.object_list = qs
|
||||
context = view_obj.get_context_data(object_list=view_obj.object_list)
|
||||
self.assertEqual(context['archive_date'].date(), now().replace(year=now().year, month=now().month, day=1).date())
|
||||
|
||||
def test_category_entries_view(self):
|
||||
page1, page2 = self.get_pages()
|
||||
post1, post2 = self.get_posts()
|
||||
posts = self.get_posts()
|
||||
pages = self.get_pages()
|
||||
|
||||
with smart_override('en'):
|
||||
request = self.get_page_request(page1, self.user, r'/en/blog/', edit=True)
|
||||
request = self.get_page_request(pages[1], self.user, lang='en', edit=True)
|
||||
view_obj = CategoryEntriesView()
|
||||
view_obj.request = request
|
||||
view_obj.namespace, view_obj.config = get_app_instance(request)
|
||||
view_obj.kwargs = {'category': 'category-1'}
|
||||
qs = view_obj.get_queryset()
|
||||
self.assertEqual(qs.count(), 2)
|
||||
self.assertEqual(set(qs), set([post1, post2]))
|
||||
self.assertEqual(qs.count(), 3)
|
||||
self.assertEqual(set(qs), set([posts[0], posts[1], posts[2]]))
|
||||
|
||||
view_obj.paginate_by = 1
|
||||
view_obj.object_list = qs
|
||||
|
@ -171,22 +235,28 @@ class ViewTest(BaseTest):
|
|||
self.assertTrue(context['category'])
|
||||
self.assertEqual(context['category'], self.category_1)
|
||||
self.assertTrue(context['is_paginated'])
|
||||
self.assertEqual(list(context['post_list']), [post2])
|
||||
self.assertEqual(context['paginator'].count, 2)
|
||||
self.assertEqual(context['post_list'][0].title, 'Second post')
|
||||
self.assertEqual(list(context['post_list']), [posts[2]])
|
||||
self.assertEqual(context['paginator'].count, 3)
|
||||
self.assertEqual(context['post_list'][0].title, 'Third post')
|
||||
|
||||
request = self.get_page_request(pages[1], self.user, edit=False)
|
||||
view_obj.request = request
|
||||
qs = view_obj.get_queryset()
|
||||
self.assertEqual(qs.count(), 1)
|
||||
|
||||
def test_author_entries_view(self):
|
||||
page1, page2 = self.get_pages()
|
||||
post1, post2 = self.get_posts()
|
||||
posts = self.get_posts()
|
||||
pages = self.get_pages()
|
||||
|
||||
with smart_override('en'):
|
||||
request = self.get_page_request(page1, self.user, r'/en/blog/', edit=True)
|
||||
request = self.get_page_request(pages[1], self.user, lang='en', edit=True)
|
||||
view_obj = AuthorEntriesView()
|
||||
view_obj.namespace, view_obj.config = get_app_instance(request)
|
||||
view_obj.request = request
|
||||
view_obj.kwargs = {'username': self.user.get_username()}
|
||||
qs = view_obj.get_queryset()
|
||||
self.assertEqual(qs.count(), 2)
|
||||
self.assertEqual(set(qs), set([post1, post2]))
|
||||
self.assertEqual(qs.count(), 3)
|
||||
self.assertEqual(set(qs), set([posts[0], posts[1], posts[2]]))
|
||||
|
||||
view_obj.paginate_by = 1
|
||||
view_obj.object_list = qs
|
||||
|
@ -194,74 +264,107 @@ class ViewTest(BaseTest):
|
|||
self.assertTrue(context['author'])
|
||||
self.assertEqual(context['author'], self.user)
|
||||
self.assertTrue(context['is_paginated'])
|
||||
self.assertEqual(list(context['post_list']), [post2])
|
||||
self.assertEqual(context['paginator'].count, 2)
|
||||
self.assertEqual(context['post_list'][0].title, 'Second post')
|
||||
self.assertEqual(list(context['post_list']), [posts[2]])
|
||||
self.assertEqual(context['paginator'].count, 3)
|
||||
self.assertEqual(context['post_list'][0].title, 'Third post')
|
||||
|
||||
request = self.get_page_request(pages[1], self.user, edit=False)
|
||||
view_obj.request = request
|
||||
qs = view_obj.get_queryset()
|
||||
self.assertEqual(qs.count(), 1)
|
||||
|
||||
def test_taggedlist_view(self):
|
||||
page1, page2 = self.get_pages()
|
||||
post1, post2 = self.get_posts()
|
||||
post1.tags.add('tag 1', 'tag 2', 'tag 3', 'tag 4')
|
||||
post1.save()
|
||||
post2.tags.add('tag 6', 'tag 2', 'tag 5', 'tag 8')
|
||||
post2.save()
|
||||
pages = self.get_pages()
|
||||
posts = self.get_posts()
|
||||
posts[0].tags.add('tag 1', 'tag 2', 'tag 3', 'tag 4')
|
||||
posts[0].save()
|
||||
posts[1].tags.add('tag 6', 'tag 2', 'tag 5', 'tag 8')
|
||||
posts[1].save()
|
||||
|
||||
with smart_override('en'):
|
||||
request = self.get_page_request(page1, self.user, r'/en/blog/', edit=True)
|
||||
request = self.get_page_request(pages[1], self.user, lang='en', edit=True)
|
||||
view_obj = TaggedListView()
|
||||
view_obj.request = request
|
||||
view_obj.namespace, view_obj.config = get_app_instance(request)
|
||||
view_obj.kwargs = {'tag': 'tag-2'}
|
||||
qs = view_obj.get_queryset()
|
||||
self.assertEqual(qs.count(), 2)
|
||||
self.assertEqual(set(qs), set([post1, post2]))
|
||||
self.assertEqual(set(qs), set([posts[0], posts[1]]))
|
||||
|
||||
view_obj.paginate_by = 1
|
||||
view_obj.object_list = qs
|
||||
context = view_obj.get_context_data(object_list=view_obj.object_list)
|
||||
self.assertTrue(context['tagged_entries'], 'tag-2')
|
||||
self.assertTrue(context['is_paginated'])
|
||||
self.assertEqual(list(context['post_list']), [post2])
|
||||
self.assertEqual(list(context['post_list']), [posts[1]])
|
||||
self.assertEqual(context['paginator'].count, 2)
|
||||
self.assertEqual(context['post_list'][0].title, 'Second post')
|
||||
|
||||
def test_feed(self):
|
||||
page1, page2 = self.get_pages()
|
||||
post1, post2 = self.get_posts()
|
||||
post1.tags.add('tag 1', 'tag 2', 'tag 3', 'tag 4')
|
||||
post1.save()
|
||||
post2.tags.add('tag 6', 'tag 2', 'tag 5', 'tag 8')
|
||||
post2.save()
|
||||
post1.set_current_language('en')
|
||||
posts = self.get_posts()
|
||||
pages = self.get_pages()
|
||||
posts[0].tags.add('tag 1', 'tag 2', 'tag 3', 'tag 4')
|
||||
posts[0].save()
|
||||
posts[1].tags.add('tag 6', 'tag 2', 'tag 5', 'tag 8')
|
||||
posts[1].save()
|
||||
posts[0].set_current_language('en')
|
||||
|
||||
feed = LatestEntriesFeed()
|
||||
self.assertEqual(list(feed.items()), [post1])
|
||||
request = self.get_page_request(page1, self.user, r'/en/blog/', lang='en', edit=False)
|
||||
xml = feed(request)
|
||||
self.assertContains(xml, post1.get_absolute_url())
|
||||
self.assertContains(xml, 'Blog articles on example.com')
|
||||
with smart_override('en'):
|
||||
with switch_language(posts[0], 'en'):
|
||||
|
||||
request = self.get_page_request(pages[1], self.user, path=posts[0].get_absolute_url())
|
||||
|
||||
feed = LatestEntriesFeed()
|
||||
feed.namespace, feed.config = get_app_instance(request)
|
||||
self.assertEqual(list(feed.items()), [posts[0]])
|
||||
self.reload_urlconf()
|
||||
xml = feed(request)
|
||||
self.assertContains(xml, posts[0].get_absolute_url())
|
||||
self.assertContains(xml, 'Blog articles on example.com')
|
||||
|
||||
with smart_override('it'):
|
||||
with switch_language(post1, 'it'):
|
||||
with switch_language(posts[0], 'it'):
|
||||
feed = LatestEntriesFeed()
|
||||
self.assertEqual(list(feed.items()), [post1])
|
||||
request = self.get_page_request(page1, self.user, r'/it/blog/', lang='it', edit=False)
|
||||
feed.namespace, feed.config = get_app_instance(request)
|
||||
self.assertEqual(list(feed.items()), [posts[0]])
|
||||
request = self.get_page_request(pages[1], self.user, path=posts[0].get_absolute_url())
|
||||
xml = feed(request)
|
||||
self.assertContains(xml, post1.get_absolute_url())
|
||||
self.assertContains(xml, posts[0].get_absolute_url())
|
||||
self.assertContains(xml, 'Articoli del blog su example.com')
|
||||
|
||||
feed = TagFeed()
|
||||
self.assertEqual(list(feed.items('tag-2')), [post1])
|
||||
feed.namespace = self.app_config_1.namespace
|
||||
feed.config = self.app_config_1
|
||||
self.assertEqual(list(feed.items('tag-2')), [posts[0]])
|
||||
|
||||
def test_sitemap(self):
|
||||
post1, post2 = self.get_posts()
|
||||
post1.tags.add('tag 1', 'tag 2', 'tag 3', 'tag 4')
|
||||
post1.save()
|
||||
post2.tags.add('tag 6', 'tag 2', 'tag 5', 'tag 8')
|
||||
post2.publish = True
|
||||
post2.save()
|
||||
post1.set_current_language('en')
|
||||
posts = self.get_posts()
|
||||
posts[0].tags.add('tag 1', 'tag 2', 'tag 3', 'tag 4')
|
||||
posts[0].save()
|
||||
posts[1].tags.add('tag 6', 'tag 2', 'tag 5', 'tag 8')
|
||||
posts[1].publish = True
|
||||
posts[1].save()
|
||||
posts[0].set_current_language('en')
|
||||
|
||||
sitemap = BlogSitemap()
|
||||
self.assertEqual(sitemap.items().count(), 2)
|
||||
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()
|
||||
|
|
11
tox.ini
11
tox.ini
|
@ -1,18 +1,25 @@
|
|||
[tox]
|
||||
envlist = py{26}-django16-cms{30,31},py{27,33,34}-django{16,17}-cms{30,31,32},py{27,33,34}-django{18}-cms{31,32},pep8,isort
|
||||
envlist = pep8,isort,py{35,34,33,27}-django{19,18}-cms{32,31},py{34,33,27}-django{17,16}-cms{32,31,30},py{26}-django16-cms{31,30}
|
||||
|
||||
[testenv]
|
||||
commands = {env:COMMAND:python} setup.py test
|
||||
commands = {env:COMMAND:python} cms_helper.py test djangocms_blog --no-migrate
|
||||
deps =
|
||||
django16: Django>=1.6,<1.7
|
||||
django17: Django>=1.7,<1.8
|
||||
django18: Django>=1.7,<1.9
|
||||
django18: https://github.com/stefanfoulis/django-filer/archive/develop.zip
|
||||
django18: https://github.com/nephila/cmsplugin-filer/archive/fix/static_filer.zip
|
||||
django19: Django==1.9a1
|
||||
django19: https://github.com/stefanfoulis/django-filer/archive/develop.zip
|
||||
django19: https://github.com/nephila/cmsplugin-filer/archive/fix/static_filer.zip
|
||||
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
|
||||
https://github.com/aldryn/aldryn-apphooks-config/archive/master.zip
|
||||
-r{toxinidir}/requirements-test.txt
|
||||
|
||||
[testenv:isort]
|
||||
|
|
Loading…
Reference in a new issue