Skip to content

Commit

Permalink
Merge pull request #5122 from czpython/merge/sane-add-plugin-2
Browse files Browse the repository at this point in the history
Merge develop into sane-add-plugin #2
  • Loading branch information
czpython committed Apr 1, 2016
2 parents d18b844 + 2c8fd6c commit 7a0c61f
Show file tree
Hide file tree
Showing 140 changed files with 32,197 additions and 8,460 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ share/
!.jshintrc
cms/static/cms/compass_app_log.txt
!cms/static/cms/js/dist
cms/tests/frontend/coverage
node_modules
.idea
.better_test.db
77 changes: 64 additions & 13 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,20 @@ addons:

env:
global:
- secure: NWiSBCHFB6LbTMget2qLIdqZlx0zeu3j+Y7Lsqb8kuYXyT2IUBGFVedcGWuGv/9Mzypb80EQWtVTokA3/3QIbesqr29uG95pMPHiYWLdnTO6UHcLMcNXiSzhBGdRDZ40iHSVv2dDHs4GNwGOH5+UCA0z3j7SWmChuFbNXh+Vsqw=
# coveralls
- secure: GzxbqfktWQkf6QQvz0OMk4zHbGI8QWcThTLUzEtktheInxwivOHnoJ1kQu2jVVrk0ZVPbOedE+Cn3QMfi6Wj+y6CREwIhfyzqZV+BIgYu/MpW7vT1BQGiN2suHjFOt/TJ90G41DlBRDc7FxGLqL1Mq8hsEdE0W+/Yszo3aMbp2w=
# sauce labs username
- secure: RotktnZ0AqeTDYfh2O472pPiolQJ2ZDRPUKGDajYWgnG2n94K7hBd4pnA1H/cd42sOyReC3lmmweWNSbG0DLD9+X+s0fwaqKcWGnYsLAcjOWaNXPMwvvgaivadT34JmS9Wv29zNudPL2A6zNw0CB+YVxUZIA4Cm9984AxbYJGSk=
# sauce labs access token
- secure: CbPfysSncBB2Ue+VOtLDa8xJvwKl73nJO647zt/9UvZ/3PilnZN9aZv2jHxGvCiFXcez+2AddKptMCcx/5EW5UfRkrWUDHrfLCULU2TfOjmufEGM1eOIXhiAun8WQ85LBzTAYy1r9D514cbU3Yzn3xGZwJljPE8JE4cx3MNN/qQ=
# temporary solution until https://github.com/ariya/phantomjs/issues/13953 is resolved
- PHANTOMJS_CDNURL=https://s3.amazonaws.com/aldryn-local-assets
matrix:
- FRONTEND=1 UNIT=1
- FRONTEND=1 LINT=1
- FRONTEND=1 INTEGRATION=1 INTEGRATION_TESTS_BUCKET=1 DJANGO=1.8 DATABASE_URL='sqlite://localhost/testdb.sqlite' MIGRATE_OPTION='--migrate'
- FRONTEND=1 INTEGRATION=1 INTEGRATION_TESTS_BUCKET=2 DJANGO=1.8 DATABASE_URL='sqlite://localhost/testdb.sqlite' MIGRATE_OPTION='--migrate'
- FRONTEND=1 INTEGRATION=1 INTEGRATION_TESTS_BUCKET=3 DJANGO=1.8 DATABASE_URL='sqlite://localhost/testdb.sqlite' MIGRATE_OPTION='--migrate'
- DJANGO=1.9 DATABASE_URL='sqlite://localhost/:memory:' SELENIUM=0 MIGRATE_OPTION='--migrate'
- DJANGO=1.9 DATABASE_URL='mysql://root@127.0.0.1/djangocms_test' SELENIUM=0
- DJANGO=1.9 DATABASE_URL='postgres://postgres@127.0.0.1/djangocms_test' SELENIUM=0 MIGRATE_OPTION='--migrate'
Expand All @@ -30,27 +42,32 @@ env:

before_script:
- pip freeze
- sh -c "if [ '$DATABASE_URL' = 'postgres://postgres@127.0.0.1/djangocms_test' ];
then psql -c 'DROP DATABASE IF EXISTS djangocms_test;' -U postgres; fi"
- sh -c "if [ '$DATABASE_URL' = 'postgres://postgres@127.0.0.1/djangocms_test' ];
then psql -c 'create database djangocms_test;' -U postgres; fi"
- sh -c "if [ '$DATABASE_URL' = 'mysql://root@127.0.0.1/djangocms_test' ]; then mysql
-e 'create database IF NOT EXISTS djangocms_test CHARACTER SET utf8 COLLATE utf8_general_ci;';
fi"
- if [ "$DATABASE_URL" == "postgres://postgres@127.0.0.1/djangocms_test" ]; then psql -c "DROP DATABASE IF EXISTS djangocms_test;" -U postgres; fi
- if [ "$DATABASE_URL" == "postgres://postgres@127.0.0.1/djangocms_test" ]; then psql -c "create database djangocms_test;" -U postgres; fi
- if [ "$DATABASE_URL" == "mysql://root@127.0.0.1/djangocms_test" ]; then mysql -e 'create database IF NOT EXISTS djangocms_test CHARACTER SET utf8 COLLATE utf8_general_ci;'; fi

before_install:
- "export DISPLAY=:99.0"
# xvfb is started in this way to ensure the screen size is 1280x1024x8
- "/sbin/start-stop-daemon --start --quiet --pidfile /tmp/cucumber_xvfb_99.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :99 -ac -screen 0 1280x1024x8"
- "export TRAVIS_COMMIT_MSG=\"$(git log --format=%B --no-merges -n 1)\""
- echo "$TRAVIS_COMMIT_MSG" | grep '\[skip saucelabs\]'; export USE_SAUCE_LABS=$?; true

install:
- pip install -r "test_requirements/django-$DJANGO.txt"
- if [ $DATABASE_URL == 'postgres://postgres@127.0.0.1/djangocms_test' ]; then pip install psycopg2 ; fi
- if [ $DATABASE_URL == 'mysql://root@127.0.0.1/djangocms_test' ]; then pip install mysqlclient ; fi
- if [ "$UNIT" != 1 ] && [ "$LINT" != 1 ]; then pip install -r "test_requirements/django-$DJANGO.txt"; pip freeze; fi
- if [ "$FRONTEND" == 1 ]; then nvm install 0.12.7 && nvm use 0.12.7; fi
- if [ "$FRONTEND" == 1 ]; then npm install -g npm@2; fi
- if [ "$FRONTEND" == 1 ]; then npm install -g gulp@3.9.0; fi
- if [ "$FRONTEND" == 1 ]; then npm install; fi
- if [ "$UNIT" != 1 ] && [ "$LINT" != 1 ] && [ "$DATABASE_URL" == 'postgres://postgres@127.0.0.1/djangocms_test' ]; then pip install psycopg2 ; fi
- if [ "$UNIT" != 1 ] && [ "$LINT" != 1 ] && [ "$DATABASE_URL" == 'mysql://root@127.0.0.1/djangocms_test' ]; then pip install mysqlclient ; fi

script:
- coverage run --parallel-mode manage.py test $MIGRATE_OPTION
- coverage combine
- if [ "$FRONTEND" == 1 ] && [ "$UNIT" == 1 ]; then gulp tests:unit; fi;
- if [ "$FRONTEND" == 1 ] && [ "$LINT" == 1 ]; then gulp lint; fi;
- if [ "$FRONTEND" == 1 ] && [ "$INTEGRATION" == 1 ]; then pip install -e .; pip freeze; sh cms/tests/frontend/integration/run_testserver.sh; sleep 60; gulp tests:integration; fi;
- if [ "$FRONTEND" != 1 ]; then coverage run --parallel-mode manage.py test $MIGRATE_OPTION; fi;
- if [ "$FRONTEND" != 1 ]; then coverage combine; fi;

after_success: coveralls

Expand Down Expand Up @@ -84,6 +101,40 @@ matrix:
- python: 3.3
env: DJANGO=1.8 DATABASE_URL='postgres://postgres@127.0.0.1/djangocms_test' SELENIUM=1 AUTH_USER_MODEL='customuserapp.User'

- python: 3.3
env: FRONTEND=1 UNIT=1
- python: 3.3
env: FRONTEND=1 LINT=1
- python: 3.4
env: FRONTEND=1 UNIT=1
- python: 3.4
env: FRONTEND=1 LINT=1
- python: 3.5
env: FRONTEND=1 UNIT=1
- python: 3.5
env: FRONTEND=1 LINT=1

- python: 3.3
env: FRONTEND=1 INTEGRATION=1 INTEGRATION_TESTS_BUCKET=1 DJANGO=1.8 DATABASE_URL='sqlite://localhost/testdb.sqlite' MIGRATE_OPTION='--migrate'
- python: 3.4
env: FRONTEND=1 INTEGRATION=1 INTEGRATION_TESTS_BUCKET=1 DJANGO=1.8 DATABASE_URL='sqlite://localhost/testdb.sqlite' MIGRATE_OPTION='--migrate'
- python: 3.5
env: FRONTEND=1 INTEGRATION=1 INTEGRATION_TESTS_BUCKET=1 DJANGO=1.8 DATABASE_URL='sqlite://localhost/testdb.sqlite' MIGRATE_OPTION='--migrate'

- python: 3.3
env: FRONTEND=1 INTEGRATION=1 INTEGRATION_TESTS_BUCKET=2 DJANGO=1.8 DATABASE_URL='sqlite://localhost/testdb.sqlite' MIGRATE_OPTION='--migrate'
- python: 3.4
env: FRONTEND=1 INTEGRATION=1 INTEGRATION_TESTS_BUCKET=2 DJANGO=1.8 DATABASE_URL='sqlite://localhost/testdb.sqlite' MIGRATE_OPTION='--migrate'
- python: 3.5
env: FRONTEND=1 INTEGRATION=1 INTEGRATION_TESTS_BUCKET=2 DJANGO=1.8 DATABASE_URL='sqlite://localhost/testdb.sqlite' MIGRATE_OPTION='--migrate'

- python: 3.3
env: FRONTEND=1 INTEGRATION=1 INTEGRATION_TESTS_BUCKET=3 DJANGO=1.8 DATABASE_URL='sqlite://localhost/testdb.sqlite' MIGRATE_OPTION='--migrate'
- python: 3.4
env: FRONTEND=1 INTEGRATION=1 INTEGRATION_TESTS_BUCKET=3 DJANGO=1.8 DATABASE_URL='sqlite://localhost/testdb.sqlite' MIGRATE_OPTION='--migrate'
- python: 3.5
env: FRONTEND=1 INTEGRATION=1 INTEGRATION_TESTS_BUCKET=3 DJANGO=1.8 DATABASE_URL='sqlite://localhost/testdb.sqlite' MIGRATE_OPTION='--migrate'

allow_failures:
- python: 2.7
env: DJANGO=1.8 DATABASE_URL='mysql://root@127.0.0.1/djangocms_test' SELENIUM=0
Expand Down
14 changes: 13 additions & 1 deletion CHANGELOG.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,19 @@
* Set the default value of CMSPlugin.position to 0 instead of null
* Refactor language menu to allow for better integration with many languages
* Management commands has been completely refactored for better consistency

* Fix "failed to load resource" for favicon on welcome screen
* ``cms-toolbar-expanded`` class is only added now when toolbar is fully
expanded and not at the beginning of the animation. ``cms-toolbar-expanding``
and ``cms-toolbar-collapsing`` classes are added at the beginning of their
respective animations.
* Added unit tests for CMS JavaScript files
* Added frontend integration tests (written with Casper JS)
* Provides the ability to declare cache expiration periods on a per-plugin basis

=== 3.2.3 (2016-03-09) ===

- Fix the display of hyphenated language codes in the page tree
- Fix a family of issues relating to unescaped translations in the page tree


=== 3.2.2 (2016-03-02) ===
Expand Down
2 changes: 2 additions & 0 deletions browserslist
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
last 2 versions
> 5%
2 changes: 1 addition & 1 deletion cms/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-

__version__ = '3.3.0.dev3'
__version__ = '3.3.0.dev4'

default_app_config = 'cms.apps.CMSConfig'
96 changes: 64 additions & 32 deletions cms/cache/page.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
# -*- coding: utf-8 -*-

import hashlib

from datetime import timedelta

from django.conf import settings
from django.utils.cache import add_never_cache_headers
from django.utils.cache import add_never_cache_headers, patch_response_headers
from django.utils.encoding import iri_to_uri, force_text
from django.utils.timezone import get_current_timezone_name
from django.utils.timezone import now, get_current_timezone_name

from cms.cache import _get_cache_version, _set_cache_version, _get_cache_key
from cms.constants import EXPIRE_NOW, MAX_EXPIRATION_TTL
from cms.utils import get_cms_setting


Expand All @@ -29,41 +34,68 @@ def _page_cache_key(request):
def set_page_cache(response):
from django.core.cache import cache

if not get_cms_setting('PAGE_CACHE'):
return response
request = response._request
save_cache = True
for placeholder in getattr(request, 'placeholders', []):
if not placeholder.cache_placeholder:
save_cache = False
break
if hasattr(request, 'toolbar'):
if request.toolbar.edit_mode or request.toolbar.show_toolbar:
save_cache = False
if request.user.is_authenticated():
save_cache = False
if not save_cache:
add_never_cache_headers(response)
return response
else:
version = _get_cache_version()
ttl = get_cms_setting('CACHE_DURATIONS')['content']

cache.set(
_page_cache_key(request),
(response.content, response._headers),
ttl,
version=version
)
# See note in invalidate_cms_page_cache()
_set_cache_version(version)

if get_cms_setting("PAGE_CACHE") and (
not hasattr(request, 'toolbar') or (
not request.toolbar.edit_mode and
not request.toolbar.show_toolbar and
not request.user.is_authenticated()
)):

# This *must* be TZ-aware
timestamp = now()

placeholders = [ph for ph, __ in getattr(request, 'placeholders', {}).values()]

# Checks if there's a plugin using the legacy "cache = False"
if all(ph.cache_placeholder for ph in placeholders):
placeholder_ttl_list = [
# get_cache_expiration() always returns:
# EXPIRE_NOW <= int <= MAX_EXPIRATION_IN_SECONDS
ph.get_cache_expiration(request, timestamp)
for ph in placeholders
]

if EXPIRE_NOW not in placeholder_ttl_list:
if placeholder_ttl_list:
min_placeholder_ttl = min(x for x in placeholder_ttl_list)
else:
# Should only happen when there are no placeholders at all
min_placeholder_ttl = MAX_EXPIRATION_TTL
ttl = min(
get_cms_setting('CACHE_DURATIONS')['content'],
min_placeholder_ttl
)

if ttl > 0:
# Adds expiration, etc. to headers
patch_response_headers(response, cache_timeout=ttl)
version = _get_cache_version()
# We also store the absolute expiration timestamp to avoid
# recomputing it on cache-reads.
expires_datetime = timestamp + timedelta(seconds=ttl)
cache.set(
_page_cache_key(request),
(
response.content,
response._headers,
expires_datetime,
),
ttl,
version=version
)
# See note in invalidate_cms_page_cache()
_set_cache_version(version)
return response

add_never_cache_headers(response)
return response


def get_page_cache(request):
from django.core.cache import cache

return cache.get(_page_cache_key(request),
version=_get_cache_version())
return cache.get(_page_cache_key(request), version=_get_cache_version())


def get_xframe_cache(page):
Expand Down
10 changes: 7 additions & 3 deletions cms/cache/placeholder.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
from django.conf import settings
from django.utils.encoding import force_text
from django.utils.timezone import get_current_timezone_name
from django.utils.timezone import get_current_timezone_name, now
from cms.cache import _get_cache_version, _set_cache_version, _clean_key, _get_cache_key
from cms.utils import get_cms_setting

Expand All @@ -14,14 +14,18 @@ def _placeholder_cache_key(placeholder, lang):
return cache_key


def set_placeholder_cache(placeholder, lang, content):
def set_placeholder_cache(placeholder, lang, content, request):
"""
Caches the rendering of a placeholder
"""
from django.core.cache import cache

cache.set(_placeholder_cache_key(placeholder, lang),
content,
get_cms_setting('CACHE_DURATIONS')['content'],
min(
get_cms_setting('CACHE_DURATIONS')['content'],
placeholder.get_cache_expiration(request, now())
),
version=_get_cache_version())
_set_cache_version(_get_cache_version())

Expand Down
3 changes: 2 additions & 1 deletion cms/cms_plugins.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,13 @@ class AliasPlugin(CMSPluginBase):

def render(self, context, instance, placeholder):
from cms.utils.plugins import downcast_plugins, build_plugin_tree
request = context.get('request', None)
context['instance'] = instance
context['placeholder'] = placeholder
if instance.plugin_id:
plugins = instance.plugin.get_descendants().order_by('placeholder', 'path')
plugins = [instance.plugin] + list(plugins)
plugins = downcast_plugins(plugins)
plugins = downcast_plugins(plugins, request=request)
plugins[0].parent_id = None
plugins = build_plugin_tree(plugins)
context['plugins'] = plugins
Expand Down
4 changes: 2 additions & 2 deletions cms/cms_toolbars.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ def init_from_request(self):
self.page = get_page_draft(self.request.current_page)

def init_placeholders_from_request(self):
self.placeholders = getattr(self.request, 'placeholders', [])
self.placeholders = getattr(self.request, 'placeholders', {})
self.statics = getattr(self.request, 'static_placeholders', [])

def populate(self):
Expand All @@ -78,7 +78,7 @@ def add_structure_mode(self):
if self.page.has_change_permission(self.request):
return self.add_structure_mode_item()

elif self.placeholders:
elif any([ph for ph, perms in self.placeholders.values() if perms]):
return self.add_structure_mode_item()

for sp in self.statics:
Expand Down
5 changes: 4 additions & 1 deletion cms/constants.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
# -*- coding: utf-8 -*-


TEMPLATE_INHERITANCE_MAGIC = 'INHERIT'
REFRESH_PAGE = 'REFRESH_PAGE'
URL_CHANGE = 'URL_CHANGE'
Expand All @@ -27,3 +26,7 @@
REVISION_INITIAL_COMMENT = "Initial version."

SLUG_REGEXP = '[0-9A-Za-z-_.//]+'

EXPIRE_NOW = 0
# HTTP Specification says max caching should only be up to one year.
MAX_EXPIRATION_TTL = 365 * 24 * 3600

0 comments on commit 7a0c61f

Please sign in to comment.