diff --git a/.travis.yml b/.travis.yml index 2245157e7..f54d1392e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,29 +1,38 @@ language: python -# Test matrix -python: - - 2.7 - - 3.2 - - 3.4 env: - - DJANGO_VERSION=Django==1.6.5 - #- DJANGO_VERSION=Django==1.7.0 +# - TOXENV=py26-dj16-postgres + - TOXENV=py26-dj16-sqlite + - TOXENV=py27-dj16-postgres +# - TOXENV=py27-dj16-sqlite + - TOXENV=py32-dj16-postgres +# - TOXENV=py33-dj16-postgres + - TOXENV=py34-dj16-postgres + - TOXENV=py27-dj17-postgres +# - TOXENV=py27-dj17-sqlite +# - TOXENV=py32-dj17-postgres +# - TOXENV=py33-dj17-postgres + - TOXENV=py34-dj17-postgres + # Services services: - redis-server - elasticsearch + # Package installation install: - - python setup.py install - - pip install psycopg2 elasticsearch wand embedly mock python-dateutil - - pip install coveralls + - pip install tox coveralls + # Pre-test configuration before_script: - psql -c 'create database wagtaildemo;' -U postgres + # Run the tests script: - coverage run runtests.py + tox + after_success: coveralls + # Who to notify about build results notifications: email: diff --git a/runtests.py b/runtests.py index 3a7399233..7961d2e19 100755 --- a/runtests.py +++ b/runtests.py @@ -2,6 +2,7 @@ import sys import os import shutil +import warnings from django.core.management import execute_from_command_line @@ -12,6 +13,9 @@ os.environ['DJANGO_SETTINGS_MODULE'] = 'wagtail.tests.settings' def runtests(): + # Don't ignore DeprecationWarnings + warnings.simplefilter('default', DeprecationWarning) + argv = sys.argv[:1] + ['test'] + sys.argv[1:] try: execute_from_command_line(argv) diff --git a/setup.py b/setup.py index 4d22021ed..c722911ad 100644 --- a/setup.py +++ b/setup.py @@ -23,12 +23,12 @@ PY3 = sys.version_info[0] == 3 install_requires = [ - "Django>=1.6.2,<1.7", + "Django>=1.6.2,<1.8", "South==1.0.0", "django-compressor>=1.4", "django-libsass>=0.2", "django-modelcluster>=0.3", - "django-taggit==0.12.0", + "django-taggit==0.12.1", "django-treebeard==2.0", "Pillow>=2.3.0", "beautifulsoup4>=4.3.2", diff --git a/tox.ini b/tox.ini index 5e68ac99a..a3a691f2d 100644 --- a/tox.ini +++ b/tox.ini @@ -1,11 +1,40 @@ [deps] -dj16= - Django>=1.6,<1.7 +base = + South==1.0.0 + django-compressor>=1.4 + django-libsass>=0.2 + django-modelcluster>=0.3 + django-taggit==0.12.1 + django-treebeard==2.0 + Pillow>=2.3.0 + beautifulsoup4>=4.3.2 + html5lib==0.999 + Unidecode>=0.04.14 + six==1.7.3 + requests==2.3.0 elasticsearch==1.1.0 mock==1.0.1 python-dateutil==2.2 + Embedly + coverage + +dj16 = + Django>=1.6,<1.7 + + +dj17 = + https://github.com/django/django/archive/stable/1.7.x.zip#egg=django + +py2 = + unicodecsv>=0.9.4 + +py3 = + [tox] +skipsdist = True +usedevelop = True + envlist = py26-dj16-postgres, py26-dj16-sqlite, @@ -13,7 +42,16 @@ envlist = py27-dj16-sqlite, py32-dj16-postgres, py33-dj16-postgres, - py34-dj16-postgres + py34-dj16-postgres, + + py27-dj17-postgres, + py27-dj17-sqlite, + py32-dj17-postgres, + py32-dj17-sqlite, + py33-dj17-postgres, + py33-dj17-sqlite, + py34-dj17-postgres, + py34-dj17-sqlite # mysql not currently supported # (wagtail.wagtailimages.tests.TestImageEditView currently fails with a @@ -28,11 +66,13 @@ envlist = [testenv] -commands=./runtests.py +commands=coverage run runtests.py [testenv:py26-dj16-postgres] basepython=python2.6 deps = + {[deps]base} + {[deps]py2} {[deps]dj16} psycopg2==2.5.3 setenv = @@ -41,6 +81,8 @@ setenv = [testenv:py26-dj16-sqlite] basepython=python2.6 deps = + {[deps]base} + {[deps]py2} {[deps]dj16} setenv = DATABASE_ENGINE=django.db.backends.sqlite3 @@ -48,6 +90,8 @@ setenv = [testenv:py26-dj16-mysql] basepython=python2.6 deps = + {[deps]base} + {[deps]py2} {[deps]dj16} MySQL-python==1.2.5 setenv = @@ -57,6 +101,8 @@ setenv = [testenv:py27-dj16-postgres] basepython=python2.7 deps = + {[deps]base} + {[deps]py2} {[deps]dj16} psycopg2==2.5.3 setenv = @@ -65,6 +111,8 @@ setenv = [testenv:py27-dj16-sqlite] basepython=python2.7 deps = + {[deps]base} + {[deps]py2} {[deps]dj16} setenv = DATABASE_ENGINE=django.db.backends.sqlite3 @@ -72,6 +120,8 @@ setenv = [testenv:py27-dj16-mysql] basepython=python2.7 deps = + {[deps]base} + {[deps]py2} {[deps]dj16} MySQL-python==1.2.5 setenv = @@ -81,6 +131,8 @@ setenv = [testenv:py32-dj16-postgres] basepython=python3.2 deps = + {[deps]base} + {[deps]py3} {[deps]dj16} psycopg2==2.5.3 setenv = @@ -89,6 +141,8 @@ setenv = [testenv:py32-dj16-sqlite] basepython=python3.2 deps = + {[deps]base} + {[deps]py3} {[deps]dj16} setenv = DATABASE_ENGINE=django.db.backends.sqlite3 @@ -96,6 +150,8 @@ setenv = [testenv:py33-dj16-postgres] basepython=python3.3 deps = + {[deps]base} + {[deps]py3} {[deps]dj16} psycopg2==2.5.3 setenv = @@ -104,6 +160,8 @@ setenv = [testenv:py33-dj16-sqlite] basepython=python3.3 deps = + {[deps]base} + {[deps]py3} {[deps]dj16} setenv = DATABASE_ENGINE=django.db.backends.sqlite3 @@ -111,6 +169,8 @@ setenv = [testenv:py34-dj16-postgres] basepython=python3.4 deps = + {[deps]base} + {[deps]py3} {[deps]dj16} psycopg2==2.5.3 setenv = @@ -119,6 +179,95 @@ setenv = [testenv:py34-dj16-sqlite] basepython=python3.4 deps = + {[deps]base} + {[deps]py3} {[deps]dj16} setenv = DATABASE_ENGINE=django.db.backends.sqlite3 + +[testenv:py27-dj17-postgres] +basepython=python2.7 +deps = + {[deps]base} + {[deps]py2} + {[deps]dj17} + psycopg2==2.5.3 +setenv = + DATABASE_ENGINE=django.db.backends.postgresql_psycopg2 + +[testenv:py27-dj17-sqlite] +basepython=python2.7 +deps = + {[deps]base} + {[deps]py2} + {[deps]dj17} +setenv = + DATABASE_ENGINE=django.db.backends.sqlite3 + +[testenv:py27-dj17-mysql] +basepython=python2.7 +deps = + {[deps]base} + {[deps]py2} + {[deps]dj17} + MySQL-python==1.2.5 +setenv = + DATABASE_ENGINE=django.db.backends.mysql + DATABASE_USER=wagtail + +[testenv:py32-dj17-postgres] +basepython=python3.2 +deps = + {[deps]base} + {[deps]py3} + {[deps]dj17} + psycopg2==2.5.3 +setenv = + DATABASE_ENGINE=django.db.backends.postgresql_psycopg2 + +[testenv:py32-dj17-sqlite] +basepython=python3.2 +deps = + {[deps]base} + {[deps]py3} + {[deps]dj17} +setenv = + DATABASE_ENGINE=django.db.backends.sqlite3 + +[testenv:py33-dj17-postgres] +basepython=python3.3 +deps = + {[deps]base} + {[deps]py3} + {[deps]dj17} + psycopg2==2.5.3 +setenv = + DATABASE_ENGINE=django.db.backends.postgresql_psycopg2 + +[testenv:py33-dj17-sqlite] +basepython=python3.3 +deps = + {[deps]base} + {[deps]py3} + {[deps]dj17} +setenv = + DATABASE_ENGINE=django.db.backends.sqlite3 + +[testenv:py34-dj17-postgres] +basepython=python3.4 +deps = + {[deps]base} + {[deps]py3} + {[deps]dj17} + psycopg2==2.5.3 +setenv = + DATABASE_ENGINE=django.db.backends.postgresql_psycopg2 + +[testenv:py34-dj17-sqlite] +basepython=python3.4 +deps = + {[deps]base} + {[deps]py3} + {[deps]dj17} +setenv = + DATABASE_ENGINE=django.db.backends.sqlite3 diff --git a/wagtail/contrib/wagtailfrontendcache/__init__.py b/wagtail/contrib/wagtailfrontendcache/__init__.py index e69de29bb..2cd2d60cb 100644 --- a/wagtail/contrib/wagtailfrontendcache/__init__.py +++ b/wagtail/contrib/wagtailfrontendcache/__init__.py @@ -0,0 +1 @@ +default_app_config = 'wagtail.contrib.wagtailfrontendcache.apps.WagtailFrontendCacheAppConfig' diff --git a/wagtail/contrib/wagtailfrontendcache/apps.py b/wagtail/contrib/wagtailfrontendcache/apps.py new file mode 100644 index 000000000..2fa34a0da --- /dev/null +++ b/wagtail/contrib/wagtailfrontendcache/apps.py @@ -0,0 +1,7 @@ +from django.apps import AppConfig + + +class WagtailFrontendCacheAppConfig(AppConfig): + name = 'wagtail.contrib.wagtailfrontendcache' + label = 'wagtailfrontendcache' + verbose_name = "Wagtail frontend cache" diff --git a/wagtail/contrib/wagtailmedusa/__init__.py b/wagtail/contrib/wagtailmedusa/__init__.py index e69de29bb..5d5f8ce96 100644 --- a/wagtail/contrib/wagtailmedusa/__init__.py +++ b/wagtail/contrib/wagtailmedusa/__init__.py @@ -0,0 +1 @@ +default_app_config = 'wagtail.contrib.wagtailmedusa.apps.WagtailMedusaAppConfig' diff --git a/wagtail/contrib/wagtailmedusa/apps.py b/wagtail/contrib/wagtailmedusa/apps.py new file mode 100644 index 000000000..46143d137 --- /dev/null +++ b/wagtail/contrib/wagtailmedusa/apps.py @@ -0,0 +1,7 @@ +from django.apps import AppConfig + + +class WagtailMedusaAppConfig(AppConfig): + name = 'wagtail.contrib.wagtailmedusa' + label = 'wagtailmedusa' + verbose_name = "Wagtail medusa" diff --git a/wagtail/contrib/wagtailroutablepage/__init__.py b/wagtail/contrib/wagtailroutablepage/__init__.py index e69de29bb..286151ff0 100644 --- a/wagtail/contrib/wagtailroutablepage/__init__.py +++ b/wagtail/contrib/wagtailroutablepage/__init__.py @@ -0,0 +1 @@ +default_app_config = 'wagtail.contrib.wagtailroutablepage.apps.WagtailRoutablePageAppConfig' diff --git a/wagtail/contrib/wagtailroutablepage/apps.py b/wagtail/contrib/wagtailroutablepage/apps.py new file mode 100644 index 000000000..c3b9c9573 --- /dev/null +++ b/wagtail/contrib/wagtailroutablepage/apps.py @@ -0,0 +1,7 @@ +from django.apps import AppConfig + + +class WagtailRoutablePageAppConfig(AppConfig): + name = 'wagtail.contrib.wagtailroutablepage' + label = 'wagtailroutablepage' + verbose_name = "Wagtail routablepage" diff --git a/wagtail/contrib/wagtailsitemaps/__init__.py b/wagtail/contrib/wagtailsitemaps/__init__.py index e69de29bb..e647b7be1 100644 --- a/wagtail/contrib/wagtailsitemaps/__init__.py +++ b/wagtail/contrib/wagtailsitemaps/__init__.py @@ -0,0 +1 @@ +default_app_config = 'wagtail.contrib.wagtailsitemaps.apps.WagtailSitemapsAppConfig' diff --git a/wagtail/contrib/wagtailsitemaps/apps.py b/wagtail/contrib/wagtailsitemaps/apps.py new file mode 100644 index 000000000..d8b249a2a --- /dev/null +++ b/wagtail/contrib/wagtailsitemaps/apps.py @@ -0,0 +1,7 @@ +from django.apps import AppConfig + + +class WagtailSitemapsAppConfig(AppConfig): + name = 'wagtail.contrib.wagtailsitemaps' + label = 'wagtailsitemaps' + verbose_name = "Wagtail sitemaps" diff --git a/wagtail/contrib/wagtailstyleguide/__init__.py b/wagtail/contrib/wagtailstyleguide/__init__.py index e69de29bb..18ff63cfe 100644 --- a/wagtail/contrib/wagtailstyleguide/__init__.py +++ b/wagtail/contrib/wagtailstyleguide/__init__.py @@ -0,0 +1 @@ +default_app_config = 'wagtail.contrib.wagtailstyleguide.apps.WagtailStyleGuideAppConfig' diff --git a/wagtail/contrib/wagtailstyleguide/apps.py b/wagtail/contrib/wagtailstyleguide/apps.py new file mode 100644 index 000000000..093003ac8 --- /dev/null +++ b/wagtail/contrib/wagtailstyleguide/apps.py @@ -0,0 +1,7 @@ +from django.apps import AppConfig + + +class WagtailStyleGuideAppConfig(AppConfig): + name = 'wagtail.contrib.wagtailstyleguide' + label = 'wagtailstyleguide' + verbose_name = "Wagtail style guide" diff --git a/wagtail/tests/migrations/0001_initial.py b/wagtail/tests/migrations/0001_initial.py new file mode 100644 index 000000000..c1dd942f5 --- /dev/null +++ b/wagtail/tests/migrations/0001_initial.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations +import django.utils.timezone + + +class Migration(migrations.Migration): + + dependencies = [ + ('auth', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='CustomUser', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('password', models.CharField(max_length=128, verbose_name='password')), + ('last_login', models.DateTimeField(default=django.utils.timezone.now, verbose_name='last login')), + ('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')), + ('username', models.CharField(unique=True, max_length=100)), + ('email', models.EmailField(max_length=255, blank=True)), + ('is_staff', models.BooleanField(default=True)), + ('is_active', models.BooleanField(default=True)), + ('first_name', models.CharField(max_length=50, blank=True)), + ('last_name', models.CharField(max_length=50, blank=True)), + ('groups', models.ManyToManyField(to='auth.Group', verbose_name='groups', blank=True)), + ('user_permissions', models.ManyToManyField(to='auth.Permission', verbose_name='user permissions', blank=True)), + ], + options={ + 'abstract': False, + }, + bases=(models.Model,), + ), + ] diff --git a/wagtail/tests/migrations/0002_auto_20140827_0908.py b/wagtail/tests/migrations/0002_auto_20140827_0908.py new file mode 100644 index 000000000..66c85ffb0 --- /dev/null +++ b/wagtail/tests/migrations/0002_auto_20140827_0908.py @@ -0,0 +1,386 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations +import django.db.models.deletion +import modelcluster.fields +import wagtail.contrib.wagtailroutablepage.models +import wagtail.wagtailcore.fields +import wagtail.wagtailsearch.index +import modelcluster.tags + + +class Migration(migrations.Migration): + + dependencies = [ + ('wagtailcore', '0002_initial_data'), + ('wagtaildocs', '0002_initial_data'), + ('taggit', '0001_initial'), + ('wagtailimages', '0002_initial_data'), + ('tests', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='Advert', + fields=[ + ('id', models.AutoField(auto_created=True, verbose_name='ID', primary_key=True, serialize=False)), + ('url', models.URLField(null=True, blank=True)), + ('text', models.CharField(max_length=255)), + ], + options={ + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='AdvertPlacement', + fields=[ + ('id', models.AutoField(auto_created=True, verbose_name='ID', primary_key=True, serialize=False)), + ('advert', models.ForeignKey(to='tests.Advert', related_name='+')), + ], + options={ + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='AlphaSnippet', + fields=[ + ('id', models.AutoField(auto_created=True, verbose_name='ID', primary_key=True, serialize=False)), + ('text', models.CharField(max_length=255)), + ], + options={ + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='BusinessChild', + fields=[ + ('page_ptr', models.OneToOneField(parent_link=True, to='wagtailcore.Page', serialize=False, auto_created=True, primary_key=True)), + ], + options={ + 'abstract': False, + }, + bases=('wagtailcore.page',), + ), + migrations.CreateModel( + name='BusinessIndex', + fields=[ + ('page_ptr', models.OneToOneField(parent_link=True, to='wagtailcore.Page', serialize=False, auto_created=True, primary_key=True)), + ], + options={ + 'abstract': False, + }, + bases=('wagtailcore.page',), + ), + migrations.CreateModel( + name='BusinessSubIndex', + fields=[ + ('page_ptr', models.OneToOneField(parent_link=True, to='wagtailcore.Page', serialize=False, auto_created=True, primary_key=True)), + ], + options={ + 'abstract': False, + }, + bases=('wagtailcore.page',), + ), + migrations.CreateModel( + name='EventIndex', + fields=[ + ('page_ptr', models.OneToOneField(parent_link=True, to='wagtailcore.Page', serialize=False, auto_created=True, primary_key=True)), + ('intro', wagtail.wagtailcore.fields.RichTextField(blank=True)), + ], + options={ + 'abstract': False, + }, + bases=('wagtailcore.page',), + ), + migrations.CreateModel( + name='EventPage', + fields=[ + ('page_ptr', models.OneToOneField(parent_link=True, to='wagtailcore.Page', serialize=False, auto_created=True, primary_key=True)), + ('date_from', models.DateField(null=True, verbose_name='Start date')), + ('date_to', models.DateField(null=True, help_text='Not required if event is on a single day', blank=True, verbose_name='End date')), + ('time_from', models.TimeField(null=True, blank=True, verbose_name='Start time')), + ('time_to', models.TimeField(null=True, blank=True, verbose_name='End time')), + ('audience', models.CharField(choices=[('public', 'Public'), ('private', 'Private')], max_length=255)), + ('location', models.CharField(max_length=255)), + ('body', wagtail.wagtailcore.fields.RichTextField(blank=True)), + ('cost', models.CharField(max_length=255)), + ('signup_link', models.URLField(blank=True)), + ('feed_image', models.ForeignKey(related_name='+', blank=True, to='wagtailimages.Image', on_delete=django.db.models.deletion.SET_NULL, null=True)), + ], + options={ + 'abstract': False, + }, + bases=('wagtailcore.page',), + ), + migrations.CreateModel( + name='EventPageCarouselItem', + fields=[ + ('id', models.AutoField(auto_created=True, verbose_name='ID', primary_key=True, serialize=False)), + ('sort_order', models.IntegerField(null=True, blank=True, editable=False)), + ('link_external', models.URLField(blank=True, verbose_name='External link')), + ('embed_url', models.URLField(blank=True, verbose_name='Embed URL')), + ('caption', models.CharField(blank=True, max_length=255)), + ('image', models.ForeignKey(related_name='+', blank=True, to='wagtailimages.Image', on_delete=django.db.models.deletion.SET_NULL, null=True)), + ('link_document', models.ForeignKey(related_name='+', blank=True, to='wagtaildocs.Document', null=True)), + ], + options={ + 'abstract': False, + 'ordering': ['sort_order'], + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='EventPageRelatedLink', + fields=[ + ('id', models.AutoField(auto_created=True, verbose_name='ID', primary_key=True, serialize=False)), + ('sort_order', models.IntegerField(null=True, blank=True, editable=False)), + ('link_external', models.URLField(blank=True, verbose_name='External link')), + ('title', models.CharField(help_text='Link title', max_length=255)), + ('link_document', models.ForeignKey(related_name='+', blank=True, to='wagtaildocs.Document', null=True)), + ], + options={ + 'abstract': False, + 'ordering': ['sort_order'], + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='EventPageSpeaker', + fields=[ + ('id', models.AutoField(auto_created=True, verbose_name='ID', primary_key=True, serialize=False)), + ('sort_order', models.IntegerField(null=True, blank=True, editable=False)), + ('link_external', models.URLField(blank=True, verbose_name='External link')), + ('first_name', models.CharField(blank=True, verbose_name='Name', max_length=255)), + ('last_name', models.CharField(blank=True, verbose_name='Surname', max_length=255)), + ('image', models.ForeignKey(related_name='+', blank=True, to='wagtailimages.Image', on_delete=django.db.models.deletion.SET_NULL, null=True)), + ('link_document', models.ForeignKey(related_name='+', blank=True, to='wagtaildocs.Document', null=True)), + ], + options={ + 'abstract': False, + 'ordering': ['sort_order'], + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='FormField', + fields=[ + ('id', models.AutoField(auto_created=True, verbose_name='ID', primary_key=True, serialize=False)), + ('sort_order', models.IntegerField(null=True, blank=True, editable=False)), + ('label', models.CharField(help_text='The label of the form field', max_length=255)), + ('field_type', models.CharField(choices=[('singleline', 'Single line text'), ('multiline', 'Multi-line text'), ('email', 'Email'), ('number', 'Number'), ('url', 'URL'), ('checkbox', 'Checkbox'), ('checkboxes', 'Checkboxes'), ('dropdown', 'Drop down'), ('radio', 'Radio buttons'), ('date', 'Date'), ('datetime', 'Date/time')], max_length=16)), + ('required', models.BooleanField(default=True)), + ('choices', models.CharField(blank=True, help_text='Comma seperated list of choices. Only applicable in checkboxes, radio and dropdown.', max_length=512)), + ('default_value', models.CharField(blank=True, help_text='Default value. Comma seperated values supported for checkboxes.', max_length=255)), + ('help_text', models.CharField(blank=True, max_length=255)), + ], + options={ + 'abstract': False, + 'ordering': ['sort_order'], + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='FormPage', + fields=[ + ('page_ptr', models.OneToOneField(parent_link=True, to='wagtailcore.Page', serialize=False, auto_created=True, primary_key=True)), + ('to_address', models.CharField(blank=True, help_text='Optional - form submissions will be emailed to this address', max_length=255)), + ('from_address', models.CharField(blank=True, max_length=255)), + ('subject', models.CharField(blank=True, max_length=255)), + ], + options={ + 'abstract': False, + }, + bases=('wagtailcore.page',), + ), + migrations.CreateModel( + name='PageWithOldStyleRouteMethod', + fields=[ + ('page_ptr', models.OneToOneField(parent_link=True, to='wagtailcore.Page', serialize=False, auto_created=True, primary_key=True)), + ('content', models.TextField()), + ], + options={ + 'abstract': False, + }, + bases=('wagtailcore.page',), + ), + migrations.CreateModel( + name='RoutablePageTest', + fields=[ + ('page_ptr', models.OneToOneField(parent_link=True, to='wagtailcore.Page', serialize=False, auto_created=True, primary_key=True)), + ], + options={ + 'abstract': False, + }, + bases=(wagtail.contrib.wagtailroutablepage.models.RoutablePageMixin, 'wagtailcore.page'), + ), + migrations.CreateModel( + name='SearchTest', + fields=[ + ('id', models.AutoField(auto_created=True, verbose_name='ID', primary_key=True, serialize=False)), + ('title', models.CharField(max_length=255)), + ('content', models.TextField()), + ('live', models.BooleanField(default=False)), + ('published_date', models.DateField(null=True)), + ], + options={ + }, + bases=(models.Model, wagtail.wagtailsearch.index.Indexed), + ), + migrations.CreateModel( + name='SearchTestChild', + fields=[ + ('searchtest_ptr', models.OneToOneField(parent_link=True, to='tests.SearchTest', serialize=False, auto_created=True, primary_key=True)), + ('subtitle', models.CharField(null=True, blank=True, max_length=255)), + ('extra_content', models.TextField()), + ], + options={ + }, + bases=('tests.searchtest',), + ), + migrations.CreateModel( + name='SearchTestOldConfig', + fields=[ + ('id', models.AutoField(auto_created=True, verbose_name='ID', primary_key=True, serialize=False)), + ], + options={ + }, + bases=(models.Model, wagtail.wagtailsearch.index.Indexed), + ), + migrations.CreateModel( + name='SearchTestOldConfigList', + fields=[ + ('id', models.AutoField(auto_created=True, verbose_name='ID', primary_key=True, serialize=False)), + ], + options={ + }, + bases=(models.Model, wagtail.wagtailsearch.index.Indexed), + ), + migrations.CreateModel( + name='SimplePage', + fields=[ + ('page_ptr', models.OneToOneField(parent_link=True, to='wagtailcore.Page', serialize=False, auto_created=True, primary_key=True)), + ('content', models.TextField()), + ], + options={ + 'abstract': False, + }, + bases=('wagtailcore.page',), + ), + migrations.CreateModel( + name='StandardChild', + fields=[ + ('page_ptr', models.OneToOneField(parent_link=True, to='wagtailcore.Page', serialize=False, auto_created=True, primary_key=True)), + ], + options={ + 'abstract': False, + }, + bases=('wagtailcore.page',), + ), + migrations.CreateModel( + name='StandardIndex', + fields=[ + ('page_ptr', models.OneToOneField(parent_link=True, to='wagtailcore.Page', serialize=False, auto_created=True, primary_key=True)), + ], + options={ + 'abstract': False, + }, + bases=('wagtailcore.page',), + ), + migrations.CreateModel( + name='TaggedPage', + fields=[ + ('page_ptr', models.OneToOneField(parent_link=True, to='wagtailcore.Page', serialize=False, auto_created=True, primary_key=True)), + ], + options={ + 'abstract': False, + }, + bases=('wagtailcore.page',), + ), + migrations.CreateModel( + name='TaggedPageTag', + fields=[ + ('id', models.AutoField(auto_created=True, verbose_name='ID', primary_key=True, serialize=False)), + ('content_object', modelcluster.fields.ParentalKey(to='tests.TaggedPage', related_name='tagged_items')), + ('tag', models.ForeignKey(to='taggit.Tag', related_name='tests_taggedpagetag_items')), + ], + options={ + 'abstract': False, + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='ZuluSnippet', + fields=[ + ('id', models.AutoField(auto_created=True, verbose_name='ID', primary_key=True, serialize=False)), + ('text', models.CharField(max_length=255)), + ], + options={ + }, + bases=(models.Model,), + ), + migrations.AddField( + model_name='taggedpage', + name='tags', + field=modelcluster.tags.ClusterTaggableManager(through='tests.TaggedPageTag', blank=True, verbose_name='Tags', to='taggit.Tag', help_text='A comma-separated list of tags.'), + preserve_default=True, + ), + migrations.AddField( + model_name='formfield', + name='page', + field=modelcluster.fields.ParentalKey(to='tests.FormPage', related_name='form_fields'), + preserve_default=True, + ), + migrations.AddField( + model_name='eventpagespeaker', + name='link_page', + field=models.ForeignKey(related_name='+', blank=True, to='wagtailcore.Page', null=True), + preserve_default=True, + ), + migrations.AddField( + model_name='eventpagespeaker', + name='page', + field=modelcluster.fields.ParentalKey(to='tests.EventPage', related_name='speakers'), + preserve_default=True, + ), + migrations.AddField( + model_name='eventpagerelatedlink', + name='link_page', + field=models.ForeignKey(related_name='+', blank=True, to='wagtailcore.Page', null=True), + preserve_default=True, + ), + migrations.AddField( + model_name='eventpagerelatedlink', + name='page', + field=modelcluster.fields.ParentalKey(to='tests.EventPage', related_name='related_links'), + preserve_default=True, + ), + migrations.AddField( + model_name='eventpagecarouselitem', + name='link_page', + field=models.ForeignKey(related_name='+', blank=True, to='wagtailcore.Page', null=True), + preserve_default=True, + ), + migrations.AddField( + model_name='eventpagecarouselitem', + name='page', + field=modelcluster.fields.ParentalKey(to='tests.EventPage', related_name='carousel_items'), + preserve_default=True, + ), + migrations.AddField( + model_name='advertplacement', + name='page', + field=modelcluster.fields.ParentalKey(to='wagtailcore.Page', related_name='advert_placements'), + preserve_default=True, + ), + migrations.AlterField( + model_name='customuser', + name='groups', + field=models.ManyToManyField(related_name='user_set', blank=True, verbose_name='groups', to='auth.Group', related_query_name='user', help_text='The groups this user belongs to. A user will get all permissions granted to each of his/her group.'), + ), + migrations.AlterField( + model_name='customuser', + name='user_permissions', + field=models.ManyToManyField(related_name='user_set', blank=True, verbose_name='user permissions', to='auth.Permission', related_query_name='user', help_text='Specific permissions for this user.'), + ), + ] diff --git a/wagtail/tests/migrations/__init__.py b/wagtail/tests/migrations/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/wagtail/tests/settings.py b/wagtail/tests/settings.py index 1ef1c5ab1..e9c1172b4 100644 --- a/wagtail/tests/settings.py +++ b/wagtail/tests/settings.py @@ -1,5 +1,6 @@ import os +import django from django.conf import global_settings @@ -57,7 +58,6 @@ INSTALLED_APPS = [ 'django.contrib.admin', 'taggit', - 'south', 'compressor', 'wagtail.wagtailcore', @@ -68,7 +68,6 @@ INSTALLED_APPS = [ 'wagtail.wagtailimages', 'wagtail.wagtailembeds', 'wagtail.wagtailsearch', - 'wagtail.wagtailredirects', 'wagtail.wagtailforms', 'wagtail.contrib.wagtailstyleguide', 'wagtail.contrib.wagtailsitemaps', @@ -76,6 +75,27 @@ INSTALLED_APPS = [ 'wagtail.tests', ] +# If we are using Django 1.6, add South to INSTALLED_APPS +if django.VERSION < (1, 7): + INSTALLED_APPS.append('south') + + +# If we are using Django 1.7 install wagtailredirects with its appconfig +# Theres nothing special about wagtailredirects, we just need to have one +# app which uses AppConfigs to test that hooks load properly + +if django.VERSION < (1, 7): + INSTALLED_APPS.append('wagtail.wagtailredirects') +else: + INSTALLED_APPS.append('wagtail.wagtailredirects.apps.WagtailRedirectsAppConfig') + +# As we don't have south migrations for tests, South thinks +# the Django 1.7 migrations are South migrations. +SOUTH_MIGRATION_MODULES = { + 'tests': 'ignore', +} + + # Using DatabaseCache to make sure that the cache is cleared between tests. # This prevents false-positives in some wagtail core tests where we are # changing the 'wagtail_root_paths' key which may cause future tests to fail. diff --git a/wagtail/utils/apps.py b/wagtail/utils/apps.py new file mode 100644 index 000000000..2bee7484e --- /dev/null +++ b/wagtail/utils/apps.py @@ -0,0 +1,35 @@ +try: + from importlib import import_module +except ImportError: + # for Python 2.6, fall back on django.utils.importlib (deprecated as of Django 1.7) + from django.utils.importlib import import_module + +import django +from django.conf import settings +from django.utils.module_loading import module_has_submodule + + +def get_app_modules(): + """ + Generator function that yields a module object for each installed app + yields tuples of (app_name, module) + """ + if django.VERSION < (1, 7): + # Django 1.6 + for app in settings.INSTALLED_APPS: + yield app, import_module(app) + else: + # Django 1.7+ + from django.apps import apps + for app in apps.get_app_configs(): + yield app.name, app.module + + +def get_app_submodules(submodule_name): + """ + Searches each app module for the specified submodule + yields tuples of (app_name, module) + """ + for name, module in get_app_modules(): + if module_has_submodule(module, submodule_name): + yield name, import_module('%s.%s' % (name, submodule_name)) diff --git a/wagtail/wagtailadmin/__init__.py b/wagtail/wagtailadmin/__init__.py index e69de29bb..c0779fd93 100644 --- a/wagtail/wagtailadmin/__init__.py +++ b/wagtail/wagtailadmin/__init__.py @@ -0,0 +1 @@ +default_app_config = 'wagtail.wagtailadmin.apps.WagtailAdminAppConfig' diff --git a/wagtail/wagtailadmin/apps.py b/wagtail/wagtailadmin/apps.py new file mode 100644 index 000000000..c963dadef --- /dev/null +++ b/wagtail/wagtailadmin/apps.py @@ -0,0 +1,7 @@ +from django.apps import AppConfig + + +class WagtailAdminAppConfig(AppConfig): + name = 'wagtail.wagtailadmin' + label = 'wagtailadmin' + verbose_name = "Wagtail admin" diff --git a/wagtail/wagtailadmin/edit_handlers.py b/wagtail/wagtailadmin/edit_handlers.py index d2eb181c3..3e463523d 100644 --- a/wagtail/wagtailadmin/edit_handlers.py +++ b/wagtail/wagtailadmin/edit_handlers.py @@ -491,7 +491,11 @@ class BasePageChooserPanel(BaseChooserPanel): except ValueError: raise ImproperlyConfigured("The page_type passed to PageChooserPanel must be of the form 'app_label.model_name'") - page_type = get_model(app_label, model_name) + try: + page_type = get_model(app_label, model_name) + except LookupError: + page_type = None + if page_type is None: raise ImproperlyConfigured("PageChooserPanel refers to model '%s' that has not been installed" % cls.page_type) else: diff --git a/wagtail/wagtailadmin/migrations/0001_create_admin_access_permissions.py b/wagtail/wagtailadmin/migrations/0001_create_admin_access_permissions.py new file mode 100644 index 000000000..5f198a01d --- /dev/null +++ b/wagtail/wagtailadmin/migrations/0001_create_admin_access_permissions.py @@ -0,0 +1,41 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations + + +def create_admin_access_permissions(apps, schema_editor): + ContentType = apps.get_model('contenttypes.ContentType') + Permission = apps.get_model('auth.Permission') + Group = apps.get_model('auth.Group') + + # Add a fake content type to hang the 'can access Wagtail admin' permission off. + # The fact that this doesn't correspond to an actual defined model shouldn't matter, I hope... + wagtailadmin_content_type = ContentType.objects.create( + app_label='wagtailadmin', + model='admin', + name='Wagtail admin' + ) + + # Create admin permission + admin_permission = Permission.objects.create( + content_type=wagtailadmin_content_type, + codename='access_admin', + name='Can access Wagtail admin' + ) + + # Assign it to Editors and Moderators groups + for group in Group.objects.filter(name__in=['Editors', 'Moderators']): + group.permissions.add(admin_permission) + + +class Migration(migrations.Migration): + + dependencies = [ + # Need to run wagtailcores initial data migration to make sure the groups are created + ('wagtailcore', '0002_initial_data'), + ] + + operations = [ + migrations.RunPython(create_admin_access_permissions), + ] diff --git a/wagtail/wagtailadmin/migrations/__init__.py b/wagtail/wagtailadmin/migrations/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/wagtail/wagtailadmin/tests/test_edit_handlers.py b/wagtail/wagtailadmin/tests/test_edit_handlers.py index 8b499378c..eaedccc2c 100644 --- a/wagtail/wagtailadmin/tests/test_edit_handlers.py +++ b/wagtail/wagtailadmin/tests/test_edit_handlers.py @@ -43,9 +43,6 @@ class TestGetFormForModel(TestCase): class TestExtractPanelDefinitionsFromModelClass(TestCase): - class FakePage(Page): - pass - def test_can_extract_panels(self): mock = MagicMock() mock.panels = 'foo' @@ -58,7 +55,7 @@ class TestExtractPanelDefinitionsFromModelClass(TestCase): self.assertNotEqual(panel.field_name, 'hostname') def test_extracted_objects_are_panels(self): - panels = extract_panel_definitions_from_model_class(self.FakePage) + panels = extract_panel_definitions_from_model_class(Page) for panel in panels: self.assertTrue(issubclass(panel, BaseFieldPanel)) @@ -346,11 +343,27 @@ class TestInlinePanel(TestCase): fake_page = self.FakePage() self.barbecue = fake_page + class FakePanel(object): + name = 'mock panel' + + class FakeChild(object): + def render_js(self): + return "rendered js" + + def rendered_fields(self): + return ["rendered fields"] + + def init(*args, **kwargs): + pass + + def __call__(self, *args, **kwargs): + fake_child = self.FakeChild() + return fake_child + def setUp(self): self.fake_field = self.FakeField() self.fake_instance = self.FakeInstance() - self.mock_panel = MagicMock() - self.mock_panel.name = 'mock panel' + self.mock_panel = self.FakePanel() self.mock_model = MagicMock() self.mock_model.formset.related.model.panels = [self.mock_panel] diff --git a/wagtail/wagtailcore/__init__.py b/wagtail/wagtailcore/__init__.py index e69de29bb..160f57430 100644 --- a/wagtail/wagtailcore/__init__.py +++ b/wagtail/wagtailcore/__init__.py @@ -0,0 +1 @@ +default_app_config = 'wagtail.wagtailcore.apps.WagtailCoreAppConfig' diff --git a/wagtail/wagtailcore/apps.py b/wagtail/wagtailcore/apps.py new file mode 100644 index 000000000..b4ef506dc --- /dev/null +++ b/wagtail/wagtailcore/apps.py @@ -0,0 +1,7 @@ +from django.apps import AppConfig + + +class WagtailCoreAppConfig(AppConfig): + name = 'wagtail.wagtailcore' + label = 'wagtailcore' + verbose_name = "Wagtail core" diff --git a/wagtail/wagtailcore/hooks.py b/wagtail/wagtailcore/hooks.py index 958675b97..41955b9d3 100644 --- a/wagtail/wagtailcore/hooks.py +++ b/wagtail/wagtailcore/hooks.py @@ -1,9 +1,5 @@ -from django.conf import settings -try: - from importlib import import_module -except ImportError: - # for Python 2.6, fall back on django.utils.importlib (deprecated as of Django 1.7) - from django.utils.importlib import import_module +from wagtail.utils.apps import get_app_submodules + _hooks = {} @@ -40,12 +36,7 @@ _searched_for_hooks = False def search_for_hooks(): global _searched_for_hooks if not _searched_for_hooks: - for app_module in settings.INSTALLED_APPS: - try: - import_module('%s.wagtail_hooks' % app_module) - except ImportError: - continue - + list(get_app_submodules('wagtail_hooks')) _searched_for_hooks = True diff --git a/wagtail/wagtailcore/migrations/0001_initial.py b/wagtail/wagtailcore/migrations/0001_initial.py new file mode 100644 index 000000000..304d53322 --- /dev/null +++ b/wagtail/wagtailcore/migrations/0001_initial.py @@ -0,0 +1,104 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations +from django.conf import settings +import wagtail.wagtailsearch.index + + +class Migration(migrations.Migration): + + dependencies = [ + ('auth', '0001_initial'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('contenttypes', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='GroupPagePermission', + fields=[ + ('id', models.AutoField(serialize=False, verbose_name='ID', primary_key=True, auto_created=True)), + ('permission_type', models.CharField(choices=[('add', 'Add'), ('edit', 'Edit'), ('publish', 'Publish')], max_length=20)), + ('group', models.ForeignKey(to='auth.Group', related_name='page_permissions')), + ], + options={ + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='Page', + fields=[ + ('id', models.AutoField(serialize=False, verbose_name='ID', primary_key=True, auto_created=True)), + ('path', models.CharField(max_length=255, unique=True)), + ('depth', models.PositiveIntegerField()), + ('numchild', models.PositiveIntegerField(default=0)), + ('title', models.CharField(max_length=255, help_text="The page title as you'd like it to be seen by the public")), + ('slug', models.SlugField(help_text='The name of the page as it will appear in URLs e.g http://domain.com/blog/[my-slug]/')), + ('live', models.BooleanField(default=True, editable=False)), + ('has_unpublished_changes', models.BooleanField(default=False, editable=False)), + ('url_path', models.CharField(blank=True, max_length=255, editable=False)), + ('seo_title', models.CharField(blank=True, max_length=255, help_text="Optional. 'Search Engine Friendly' title. This will appear at the top of the browser window.", verbose_name='Page title')), + ('show_in_menus', models.BooleanField(default=False, help_text='Whether a link to this page will appear in automatically generated menus')), + ('search_description', models.TextField(blank=True)), + ('go_live_at', models.DateTimeField(blank=True, verbose_name='Go live date/time', null=True, help_text='Please add a date-time in the form YYYY-MM-DD hh:mm:ss.')), + ('expire_at', models.DateTimeField(blank=True, verbose_name='Expiry date/time', null=True, help_text='Please add a date-time in the form YYYY-MM-DD hh:mm:ss.')), + ('expired', models.BooleanField(default=False, editable=False)), + ('content_type', models.ForeignKey(to='contenttypes.ContentType', related_name='pages')), + ('owner', models.ForeignKey(blank=True, null=True, to=settings.AUTH_USER_MODEL, editable=False, related_name='owned_pages')), + ], + options={ + 'abstract': False, + }, + bases=(models.Model, wagtail.wagtailsearch.index.Indexed), + ), + migrations.CreateModel( + name='PageRevision', + fields=[ + ('id', models.AutoField(serialize=False, verbose_name='ID', primary_key=True, auto_created=True)), + ('submitted_for_moderation', models.BooleanField(default=False)), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('content_json', models.TextField()), + ('approved_go_live_at', models.DateTimeField(blank=True, null=True)), + ('page', models.ForeignKey(to='wagtailcore.Page', related_name='revisions')), + ('user', models.ForeignKey(blank=True, null=True, to=settings.AUTH_USER_MODEL)), + ], + options={ + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='PageViewRestriction', + fields=[ + ('id', models.AutoField(serialize=False, verbose_name='ID', primary_key=True, auto_created=True)), + ('password', models.CharField(max_length=255)), + ('page', models.ForeignKey(to='wagtailcore.Page', related_name='view_restrictions')), + ], + options={ + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='Site', + fields=[ + ('id', models.AutoField(serialize=False, verbose_name='ID', primary_key=True, auto_created=True)), + ('hostname', models.CharField(max_length=255, db_index=True)), + ('port', models.IntegerField(default=80, help_text='Set this to something other than 80 if you need a specific port number to appear in URLs (e.g. development on port 8000). Does not affect request handling (so port forwarding still works).')), + ('is_default_site', models.BooleanField(default=False, help_text='If true, this site will handle requests for all other hostnames that do not have a site entry of their own')), + ('root_page', models.ForeignKey(to='wagtailcore.Page', related_name='sites_rooted_here')), + ], + options={ + }, + bases=(models.Model,), + ), + migrations.AlterUniqueTogether( + name='site', + unique_together=set([('hostname', 'port')]), + ), + migrations.AddField( + model_name='grouppagepermission', + name='page', + field=models.ForeignKey(to='wagtailcore.Page', related_name='group_permissions'), + preserve_default=True, + ), + ] diff --git a/wagtail/wagtailcore/migrations/0002_initial_data.py b/wagtail/wagtailcore/migrations/0002_initial_data.py new file mode 100644 index 000000000..10244c24c --- /dev/null +++ b/wagtail/wagtailcore/migrations/0002_initial_data.py @@ -0,0 +1,91 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations + + +def initial_data(apps, schema_editor): + ContentType = apps.get_model('contenttypes.ContentType') + Group = apps.get_model('auth.Group') + Page = apps.get_model('wagtailcore.Page') + Site = apps.get_model('wagtailcore.Site') + GroupPagePermission = apps.get_model('wagtailcore.GroupPagePermission') + + # Create page content type + page_content_type, created = ContentType.objects.get_or_create( + model='page', + app_label='wagtailcore', + defaults={'name': 'page'} + ) + + # Create root page + root = Page.objects.create( + title="Root", + slug='root', + content_type=page_content_type, + path='0001', + depth=1, + numchild=1, + url_path='/', + ) + + # Create homepage + homepage = Page.objects.create( + title="Welcome to your new Wagtail site!", + slug='home', + content_type=page_content_type, + path='00010001', + depth=2, + numchild=0, + url_path='/home/', + ) + + # Create default site + Site.objects.create( + hostname='localhost', + root_page_id=homepage.id, + is_default_site=True + ) + + # Create auth groups + moderators_group = Group.objects.create(name='Moderators') + editors_group = Group.objects.create(name='Editors') + + # Create group permissions + GroupPagePermission.objects.create( + group=moderators_group, + page=root, + permission_type='add', + ) + GroupPagePermission.objects.create( + group=moderators_group, + page=root, + permission_type='edit', + ) + GroupPagePermission.objects.create( + group=moderators_group, + page=root, + permission_type='publish', + ) + + GroupPagePermission.objects.create( + group=editors_group, + page=root, + permission_type='add', + ) + GroupPagePermission.objects.create( + group=editors_group, + page=root, + permission_type='edit', + ) + + +class Migration(migrations.Migration): + + dependencies = [ + ('wagtailcore', '0001_initial'), + ] + + operations = [ + migrations.RunPython(initial_data), + ] diff --git a/wagtail/wagtailcore/migrations/__init__.py b/wagtail/wagtailcore/migrations/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/wagtail/wagtaildocs/__init__.py b/wagtail/wagtaildocs/__init__.py index e69de29bb..9c5f85240 100644 --- a/wagtail/wagtaildocs/__init__.py +++ b/wagtail/wagtaildocs/__init__.py @@ -0,0 +1 @@ +default_app_config = 'wagtail.wagtaildocs.apps.WagtailDocsAppConfig' diff --git a/wagtail/wagtaildocs/apps.py b/wagtail/wagtaildocs/apps.py new file mode 100644 index 000000000..eef820d18 --- /dev/null +++ b/wagtail/wagtaildocs/apps.py @@ -0,0 +1,7 @@ +from django.apps import AppConfig + + +class WagtailDocsAppConfig(AppConfig): + name = 'wagtail.wagtaildocs' + label = 'wagtaildocs' + verbose_name = "Wagtail documents" diff --git a/wagtail/wagtaildocs/migrations/0001_initial.py b/wagtail/wagtaildocs/migrations/0001_initial.py new file mode 100644 index 000000000..dd8e4ac62 --- /dev/null +++ b/wagtail/wagtaildocs/migrations/0001_initial.py @@ -0,0 +1,32 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations +import taggit.managers +from django.conf import settings +import wagtail.wagtailadmin.taggable + + +class Migration(migrations.Migration): + + dependencies = [ + ('taggit', '__latest__'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='Document', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('title', models.CharField(max_length=255, verbose_name='Title')), + ('file', models.FileField(upload_to='documents', verbose_name='File')), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('tags', taggit.managers.TaggableManager(to='taggit.Tag', verbose_name='Tags', help_text=None, blank=True, through='taggit.TaggedItem')), + ('uploaded_by_user', models.ForeignKey(editable=False, null=True, blank=True, to=settings.AUTH_USER_MODEL)), + ], + options={ + }, + bases=(models.Model, wagtail.wagtailadmin.taggable.TagSearchable), + ), + ] diff --git a/wagtail/wagtaildocs/migrations/0002_initial_data.py b/wagtail/wagtaildocs/migrations/0002_initial_data.py new file mode 100644 index 000000000..6ca3a0fbd --- /dev/null +++ b/wagtail/wagtaildocs/migrations/0002_initial_data.py @@ -0,0 +1,52 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations + + +def add_document_permissions_to_admin_groups(apps, schema_editor): + ContentType = apps.get_model('contenttypes.ContentType') + Permission = apps.get_model('auth.Permission') + Group = apps.get_model('auth.Group') + Document = apps.get_model('wagtaildocs.Document') + + # Get document permissions + document_content_type, _created = ContentType.objects.get_or_create( + model='document', + app_label='wagtaildocs', + defaults={'name': 'document'} + ) + + add_document_permission, _created = Permission.objects.get_or_create( + content_type=document_content_type, + codename='add_document', + defaults={'name': 'Can add document'} + ) + change_document_permission, _created = Permission.objects.get_or_create( + content_type=document_content_type, + codename='change_document', + defaults={'name': 'Can change document'} + ) + delete_document_permission, _created = Permission.objects.get_or_create( + content_type=document_content_type, + codename='delete_document', + defaults={'name': 'Can delete document'} + ) + + # Assign it to Editors and Moderators groups + for group in Group.objects.filter(name__in=['Editors', 'Moderators']): + group.permissions.add(add_document_permission, change_document_permission, delete_document_permission) + + +class Migration(migrations.Migration): + + dependencies = [ + ('wagtaildocs', '0001_initial'), + + # Need to run wagtailcores initial data migration to make sure the groups are created + ('wagtailcore', '0002_initial_data'), + ] + + operations = [ + migrations.RunPython(add_document_permissions_to_admin_groups), + ] diff --git a/wagtail/wagtaildocs/migrations/__init__.py b/wagtail/wagtaildocs/migrations/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/wagtail/wagtailembeds/__init__.py b/wagtail/wagtailembeds/__init__.py index b75cbc491..54d955608 100644 --- a/wagtail/wagtailembeds/__init__.py +++ b/wagtail/wagtailembeds/__init__.py @@ -1,2 +1,4 @@ from .models import Embed from .embeds import get_embed + +default_app_config = 'wagtail.wagtailembeds.apps.WagtailEmbedsAppConfig' diff --git a/wagtail/wagtailembeds/apps.py b/wagtail/wagtailembeds/apps.py new file mode 100644 index 000000000..ecbaf6cb5 --- /dev/null +++ b/wagtail/wagtailembeds/apps.py @@ -0,0 +1,7 @@ +from django.apps import AppConfig + + +class WagtailEmbedsAppConfig(AppConfig): + name = 'wagtail.wagtailembeds' + label = 'wagtailembeds' + verbose_name = "Wagtail embeds" diff --git a/wagtail/wagtailembeds/migrations/0001_initial.py b/wagtail/wagtailembeds/migrations/0001_initial.py new file mode 100644 index 000000000..86b9e8d4b --- /dev/null +++ b/wagtail/wagtailembeds/migrations/0001_initial.py @@ -0,0 +1,37 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='Embed', + fields=[ + ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True, serialize=False)), + ('url', models.URLField()), + ('max_width', models.SmallIntegerField(null=True, blank=True)), + ('type', models.CharField(max_length=10, choices=[('video', 'Video'), ('photo', 'Photo'), ('link', 'Link'), ('rich', 'Rich')])), + ('html', models.TextField(blank=True)), + ('title', models.TextField(blank=True)), + ('author_name', models.TextField(blank=True)), + ('provider_name', models.TextField(blank=True)), + ('thumbnail_url', models.URLField(null=True, blank=True)), + ('width', models.IntegerField(null=True, blank=True)), + ('height', models.IntegerField(null=True, blank=True)), + ('last_updated', models.DateTimeField(auto_now=True)), + ], + options={ + }, + bases=(models.Model,), + ), + migrations.AlterUniqueTogether( + name='embed', + unique_together=set([('url', 'max_width')]), + ), + ] diff --git a/wagtail/wagtailembeds/migrations/__init__.py b/wagtail/wagtailembeds/migrations/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/wagtail/wagtailforms/__init__.py b/wagtail/wagtailforms/__init__.py index e69de29bb..7be37b5f1 100644 --- a/wagtail/wagtailforms/__init__.py +++ b/wagtail/wagtailforms/__init__.py @@ -0,0 +1 @@ +default_app_config = 'wagtail.wagtailforms.apps.WagtailFormsAppConfig' diff --git a/wagtail/wagtailforms/apps.py b/wagtail/wagtailforms/apps.py new file mode 100644 index 000000000..7336f20e0 --- /dev/null +++ b/wagtail/wagtailforms/apps.py @@ -0,0 +1,7 @@ +from django.apps import AppConfig + + +class WagtailFormsAppConfig(AppConfig): + name = 'wagtail.wagtailforms' + label = 'wagtailforms' + verbose_name = "Wagtail forms" diff --git a/wagtail/wagtailforms/migrations/0001_initial.py b/wagtail/wagtailforms/migrations/0001_initial.py new file mode 100644 index 000000000..4b28f0ddf --- /dev/null +++ b/wagtail/wagtailforms/migrations/0001_initial.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('wagtailcore', '0002_initial_data'), + ] + + operations = [ + migrations.CreateModel( + name='FormSubmission', + fields=[ + ('id', models.AutoField(serialize=False, verbose_name='ID', primary_key=True, auto_created=True)), + ('form_data', models.TextField()), + ('submit_time', models.DateTimeField(auto_now_add=True)), + ('page', models.ForeignKey(to='wagtailcore.Page')), + ], + options={ + }, + bases=(models.Model,), + ), + ] diff --git a/wagtail/wagtailforms/migrations/__init__.py b/wagtail/wagtailforms/migrations/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/wagtail/wagtailimages/__init__.py b/wagtail/wagtailimages/__init__.py index e69de29bb..61397a911 100644 --- a/wagtail/wagtailimages/__init__.py +++ b/wagtail/wagtailimages/__init__.py @@ -0,0 +1 @@ +default_app_config = 'wagtail.wagtailimages.apps.WagtailImagesAppConfig' diff --git a/wagtail/wagtailimages/apps.py b/wagtail/wagtailimages/apps.py new file mode 100644 index 000000000..88cd6e3f0 --- /dev/null +++ b/wagtail/wagtailimages/apps.py @@ -0,0 +1,7 @@ +from django.apps import AppConfig + + +class WagtailImagesAppConfig(AppConfig): + name = 'wagtail.wagtailimages' + label = 'wagtailimages' + verbose_name = "Wagtail images" diff --git a/wagtail/wagtailimages/formats.py b/wagtail/wagtailimages/formats.py index d00b65b44..3c5644a07 100644 --- a/wagtail/wagtailimages/formats.py +++ b/wagtail/wagtailimages/formats.py @@ -1,11 +1,6 @@ -from django.conf import settings from django.utils.html import escape -try: - from importlib import import_module -except ImportError: - # for Python 2.6, fall back on django.utils.importlib (deprecated as of Django 1.7) - from django.utils.importlib import import_module +from wagtail.utils.apps import get_app_submodules class Format(object): @@ -85,12 +80,7 @@ _searched_for_image_formats = False def search_for_image_formats(): global _searched_for_image_formats if not _searched_for_image_formats: - for app_module in settings.INSTALLED_APPS: - try: - import_module('%s.image_formats' % app_module) - except ImportError: - continue - + list(get_app_submodules('image_formats')) _searched_for_image_formats = True diff --git a/wagtail/wagtailimages/migrations/0001_initial.py b/wagtail/wagtailimages/migrations/0001_initial.py new file mode 100644 index 000000000..64bb96257 --- /dev/null +++ b/wagtail/wagtailimages/migrations/0001_initial.py @@ -0,0 +1,70 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations +import wagtail.wagtailimages.utils.validators +import wagtail.wagtailimages.models +import taggit.managers +from django.conf import settings +import wagtail.wagtailadmin.taggable + + +class Migration(migrations.Migration): + + dependencies = [ + ('taggit', '__latest__'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='Filter', + fields=[ + ('id', models.AutoField(primary_key=True, serialize=False, auto_created=True, verbose_name='ID')), + ('spec', models.CharField(db_index=True, max_length=255)), + ], + options={ + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='Image', + fields=[ + ('id', models.AutoField(primary_key=True, serialize=False, auto_created=True, verbose_name='ID')), + ('title', models.CharField(verbose_name='Title', max_length=255)), + ('file', models.ImageField(width_field='width', upload_to=wagtail.wagtailimages.models.get_upload_to, verbose_name='File', height_field='height', validators=[wagtail.wagtailimages.utils.validators.validate_image_format])), + ('width', models.IntegerField(editable=False)), + ('height', models.IntegerField(editable=False)), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('focal_point_x', models.PositiveIntegerField(editable=False, null=True)), + ('focal_point_y', models.PositiveIntegerField(editable=False, null=True)), + ('focal_point_width', models.PositiveIntegerField(editable=False, null=True)), + ('focal_point_height', models.PositiveIntegerField(editable=False, null=True)), + ('tags', taggit.managers.TaggableManager(verbose_name='Tags', blank=True, help_text=None, to='taggit.Tag', through='taggit.TaggedItem')), + ('uploaded_by_user', models.ForeignKey(editable=False, blank=True, null=True, to=settings.AUTH_USER_MODEL)), + ], + options={ + 'abstract': False, + }, + bases=(models.Model, wagtail.wagtailadmin.taggable.TagSearchable), + ), + migrations.CreateModel( + name='Rendition', + fields=[ + ('id', models.AutoField(primary_key=True, serialize=False, auto_created=True, verbose_name='ID')), + ('file', models.ImageField(width_field='width', upload_to='images', height_field='height')), + ('width', models.IntegerField(editable=False)), + ('height', models.IntegerField(editable=False)), + ('focal_point_key', models.CharField(editable=False, max_length=255, null=True)), + ('filter', models.ForeignKey(related_name='+', to='wagtailimages.Filter')), + ('image', models.ForeignKey(related_name='renditions', to='wagtailimages.Image')), + ], + options={ + }, + bases=(models.Model,), + ), + migrations.AlterUniqueTogether( + name='rendition', + unique_together=set([('image', 'filter', 'focal_point_key')]), + ), + ] diff --git a/wagtail/wagtailimages/migrations/0002_initial_data.py b/wagtail/wagtailimages/migrations/0002_initial_data.py new file mode 100644 index 000000000..7451ba7d7 --- /dev/null +++ b/wagtail/wagtailimages/migrations/0002_initial_data.py @@ -0,0 +1,52 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations + + +def add_image_permissions_to_admin_groups(apps, schema_editor): + ContentType = apps.get_model('contenttypes.ContentType') + Permission = apps.get_model('auth.Permission') + Group = apps.get_model('auth.Group') + Image = apps.get_model('wagtailimages.Image') + + # Get image permissions + image_content_type, _created = ContentType.objects.get_or_create( + model='image', + app_label='wagtailimages', + defaults={'name': 'image'} + ) + + add_image_permission, _created = Permission.objects.get_or_create( + content_type=image_content_type, + codename='add_image', + defaults={'name': 'Can add image'} + ) + change_image_permission, _created = Permission.objects.get_or_create( + content_type=image_content_type, + codename='change_image', + defaults={'name': 'Can change image'} + ) + delete_image_permission, _created = Permission.objects.get_or_create( + content_type=image_content_type, + codename='delete_image', + defaults={'name': 'Can delete image'} + ) + + # Assign it to Editors and Moderators groups + for group in Group.objects.filter(name__in=['Editors', 'Moderators']): + group.permissions.add(add_image_permission, change_image_permission, delete_image_permission) + + +class Migration(migrations.Migration): + + dependencies = [ + ('wagtailimages', '0001_initial'), + + # Need to run wagtailcores initial data migration to make sure the groups are created + ('wagtailcore', '0002_initial_data'), + ] + + operations = [ + migrations.RunPython(add_image_permissions_to_admin_groups), + ] diff --git a/wagtail/wagtailimages/migrations/__init__.py b/wagtail/wagtailimages/migrations/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/wagtail/wagtailimages/models.py b/wagtail/wagtailimages/models.py index 63151b602..04ae37ad0 100644 --- a/wagtail/wagtailimages/models.py +++ b/wagtail/wagtailimages/models.py @@ -29,23 +29,23 @@ from wagtail.wagtailimages.utils.feature_detection import FeatureDetector, openc from wagtail.wagtailadmin.utils import get_object_usage +def get_upload_to(instance, filename): + folder_name = 'original_images' + filename = instance.file.field.storage.get_valid_name(filename) + + # do a unidecode in the filename and then + # replace non-ascii characters in filename with _ , to sidestep issues with filesystem encoding + filename = "".join((i if ord(i) < 128 else '_') for i in unidecode(filename)) + + while len(os.path.join(folder_name, filename)) >= 95: + prefix, dot, extension = filename.rpartition('.') + filename = prefix[:-1] + dot + extension + return os.path.join(folder_name, filename) + + @python_2_unicode_compatible class AbstractImage(models.Model, TagSearchable): title = models.CharField(max_length=255, verbose_name=_('Title') ) - - def get_upload_to(self, filename): - folder_name = 'original_images' - filename = self.file.field.storage.get_valid_name(filename) - - # do a unidecode in the filename and then - # replace non-ascii characters in filename with _ , to sidestep issues with filesystem encoding - filename = "".join((i if ord(i) < 128 else '_') for i in unidecode(filename)) - - while len(os.path.join(folder_name, filename)) >= 95: - prefix, dot, extension = filename.rpartition('.') - filename = prefix[:-1] + dot + extension - return os.path.join(folder_name, filename) - file = models.ImageField(verbose_name=_('File'), upload_to=get_upload_to, width_field='width', height_field='height', validators=[validate_image_format]) width = models.IntegerField(editable=False) height = models.IntegerField(editable=False) diff --git a/wagtail/wagtailredirects/__init__.py b/wagtail/wagtailredirects/__init__.py index e69de29bb..b192b1b24 100644 --- a/wagtail/wagtailredirects/__init__.py +++ b/wagtail/wagtailredirects/__init__.py @@ -0,0 +1 @@ +default_app_config = 'wagtail.wagtailredirects.apps.WagtailRedirectsAppConfig' diff --git a/wagtail/wagtailredirects/apps.py b/wagtail/wagtailredirects/apps.py new file mode 100644 index 000000000..400299f02 --- /dev/null +++ b/wagtail/wagtailredirects/apps.py @@ -0,0 +1,7 @@ +from django.apps import AppConfig + + +class WagtailRedirectsAppConfig(AppConfig): + name = 'wagtail.wagtailredirects' + label = 'wagtailredirects' + verbose_name = "Wagtail redirects" diff --git a/wagtail/wagtailredirects/migrations/0001_initial.py b/wagtail/wagtailredirects/migrations/0001_initial.py new file mode 100644 index 000000000..98289544d --- /dev/null +++ b/wagtail/wagtailredirects/migrations/0001_initial.py @@ -0,0 +1,28 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('wagtailcore', '0002_initial_data'), + ] + + operations = [ + migrations.CreateModel( + name='Redirect', + fields=[ + ('id', models.AutoField(verbose_name='ID', auto_created=True, serialize=False, primary_key=True)), + ('old_path', models.CharField(verbose_name='Redirect from', max_length=255, unique=True, db_index=True)), + ('is_permanent', models.BooleanField(verbose_name='Permanent', default=True, help_text="Recommended. Permanent redirects ensure search engines forget the old page (the 'Redirect from') and index the new page instead.")), + ('redirect_link', models.URLField(blank=True, verbose_name='Redirect to any URL')), + ('redirect_page', models.ForeignKey(blank=True, null=True, verbose_name='Redirect to a page', to='wagtailcore.Page')), + ('site', models.ForeignKey(blank=True, to='wagtailcore.Site', editable=False, null=True, related_name='redirects')), + ], + options={ + }, + bases=(models.Model,), + ), + ] diff --git a/wagtail/wagtailredirects/migrations/__init__.py b/wagtail/wagtailredirects/migrations/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/wagtail/wagtailsearch/__init__.py b/wagtail/wagtailsearch/__init__.py index 71cc69f06..0e24694be 100644 --- a/wagtail/wagtailsearch/__init__.py +++ b/wagtail/wagtailsearch/__init__.py @@ -1,3 +1,5 @@ from wagtail.wagtailsearch.index import Indexed from wagtail.wagtailsearch.signal_handlers import register_signal_handlers -from wagtail.wagtailsearch.backends import get_search_backend \ No newline at end of file +from wagtail.wagtailsearch.backends import get_search_backend + +default_app_config = 'wagtail.wagtailsearch.apps.WagtailSearchAppConfig' diff --git a/wagtail/wagtailsearch/apps.py b/wagtail/wagtailsearch/apps.py new file mode 100644 index 000000000..e3b07c721 --- /dev/null +++ b/wagtail/wagtailsearch/apps.py @@ -0,0 +1,7 @@ +from django.apps import AppConfig + + +class WagtailSearchAppConfig(AppConfig): + name = 'wagtail.wagtailsearch' + label = 'wagtailsearch' + verbose_name = "Wagtail search" diff --git a/wagtail/wagtailsearch/backends/elasticsearch.py b/wagtail/wagtailsearch/backends/elasticsearch.py index 9e82fe66a..341cc342e 100644 --- a/wagtail/wagtailsearch/backends/elasticsearch.py +++ b/wagtail/wagtailsearch/backends/elasticsearch.py @@ -5,7 +5,13 @@ import json from six.moves.urllib.parse import urlparse from django.db import models -from django.db.models.sql.where import SubqueryConstraint +from django.db.models.sql.where import SubqueryConstraint, WhereNode + +# Django 1.7 lookups +try: + from django.db.models.lookups import Lookup +except ImportError: + Lookup = None from elasticsearch import Elasticsearch, NotFoundError, RequestError from elasticsearch.helpers import bulk @@ -125,118 +131,133 @@ class ElasticSearchQuery(object): self.query_string = query_string self.fields = fields + def _process_lookup(self, field_attname, lookup, value): + # Get field + field = dict( + (field.get_attname(self.queryset.model), field) + for field in self.queryset.model.get_filterable_search_fields() + ).get(field_attname, None) + + # Give error if the field doesn't exist + if field is None: + raise FieldError('Cannot filter ElasticSearch results with field "' + field_name + '". Please add FilterField(\'' + field_name + '\') to ' + self.queryset.model.__name__ + '.search_fields.') + + # Get the name of the field in the index + field_index_name = field.get_index_name(self.queryset.model) + + if lookup == 'exact': + if value is None: + return { + 'missing': { + 'field': field_index_name, + } + } + else: + return { + 'term': { + field_index_name: value, + } + } + + if lookup == 'isnull': + if value: + return { + 'missing': { + 'field': field_index_name, + } + } + else: + return { + 'not': { + 'missing': { + 'field': field_index_name, + } + } + } + + if lookup in ['startswith', 'prefix']: + return { + 'prefix': { + field_index_name: value, + } + } + + if lookup in ['gt', 'gte', 'lt', 'lte']: + return { + 'range': { + field_index_name: { + lookup: value, + } + } + } + + if lookup == 'range': + lower, upper = value + + return { + 'range': { + field_index_name: { + 'gte': lower, + 'lte': upper, + } + } + } + + if lookup == 'in': + return { + 'terms': { + field_index_name: value, + } + } + + raise FilterError('Could not apply filter on ElasticSearch results: "' + field_name + '__' + lookup + ' = ' + unicode(value) + '". Lookup "' + lookup + '"" not recognosed.') + def _get_filters_from_where(self, where_node): # Check if this is a leaf node - if isinstance(where_node, tuple): - field_name = where_node[0].col + if isinstance(where_node, tuple): # Django 1.6 and below + field_attname = where_node[0].col lookup = where_node[1] value = where_node[3] - # Get field - field = dict( - (field.get_attname(self.queryset.model), field) - for field in self.queryset.model.get_filterable_search_fields() - ).get(field_name, None) + # Process the filter + return self._process_lookup(field_attname, lookup, value) - # Give error if the field doesn't exist - if field is None: - raise FieldError('Cannot filter ElasticSearch results with field "' + field_name + '". Please add FilterField(\'' + field_name + '\') to ' + self.queryset.model.__name__ + '.search_fields.') + elif Lookup is not None and isinstance(where_node, Lookup): # Django 1.7 and above + field_attname = where_node.lhs.target.attname + lookup = where_node.lookup_name + value = where_node.rhs - # Get the name of the field in the index - field_index_name = field.get_index_name(self.queryset.model) + # Process the filter + return self._process_lookup(field_attname, lookup, value) - # Find lookup - if lookup == 'exact': - if value is None: - return { - 'missing': { - 'field': field_index_name, - } - } - else: - return { - 'term': { - field_index_name: value, - } - } - - if lookup == 'isnull': - if value: - return { - 'missing': { - 'field': field_index_name, - } - } - else: - return { - 'not': { - 'missing': { - 'field': field_index_name, - } - } - } - - if lookup in ['startswith', 'prefix']: - return { - 'prefix': { - field_index_name: value, - } - } - - if lookup in ['gt', 'gte', 'lt', 'lte']: - return { - 'range': { - field_index_name: { - lookup: value, - } - } - } - - if lookup == 'range': - lower, upper = value - - return { - 'range': { - field_index_name: { - 'gte': lower, - 'lte': upper, - } - } - } - - if lookup == 'in': - return { - 'terms': { - field_index_name: value, - } - } - - raise FilterError('Could not apply filter on ElasticSearch results: "' + field_name + '__' + lookup + ' = ' + unicode(value) + '". Lookup "' + lookup + '"" not recognosed.') elif isinstance(where_node, SubqueryConstraint): raise FilterError('Could not apply filter on ElasticSearch results: Subqueries are not allowed.') - # Get child filters - connector = where_node.connector - child_filters = [self._get_filters_from_where(child) for child in where_node.children] - child_filters = [child_filter for child_filter in child_filters if child_filter] + elif isinstance(where_node, WhereNode): + # Get child filters + connector = where_node.connector + child_filters = [self._get_filters_from_where(child) for child in where_node.children] + child_filters = [child_filter for child_filter in child_filters if child_filter] - # Connect them - if child_filters: - if len(child_filters) == 1: - filter_out = child_filters[0] - else: - filter_out = { - connector.lower(): [ - fil for fil in child_filters if fil is not None - ] - } + # Connect them + if child_filters: + if len(child_filters) == 1: + filter_out = child_filters[0] + else: + filter_out = { + connector.lower(): [ + fil for fil in child_filters if fil is not None + ] + } - if where_node.negated: - filter_out = { - 'not': filter_out - } + if where_node.negated: + filter_out = { + 'not': filter_out + } - return filter_out + return filter_out + else: + raise FilterError('Could not apply filter on ElasticSearch results: Unknown where node: ' + str(type(where_node))) def _get_filters(self): # Filters diff --git a/wagtail/wagtailsearch/migrations/0001_initial.py b/wagtail/wagtailsearch/migrations/0001_initial.py new file mode 100644 index 000000000..eebd11a6a --- /dev/null +++ b/wagtail/wagtailsearch/migrations/0001_initial.py @@ -0,0 +1,59 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('wagtailcore', '0002_initial_data'), + ] + + operations = [ + migrations.CreateModel( + name='EditorsPick', + fields=[ + ('id', models.AutoField(serialize=False, auto_created=True, verbose_name='ID', primary_key=True)), + ('sort_order', models.IntegerField(blank=True, null=True, editable=False)), + ('description', models.TextField(blank=True)), + ('page', models.ForeignKey(to='wagtailcore.Page')), + ], + options={ + 'ordering': ('sort_order',), + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='Query', + fields=[ + ('id', models.AutoField(serialize=False, auto_created=True, verbose_name='ID', primary_key=True)), + ('query_string', models.CharField(unique=True, max_length=255)), + ], + options={ + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='QueryDailyHits', + fields=[ + ('id', models.AutoField(serialize=False, auto_created=True, verbose_name='ID', primary_key=True)), + ('date', models.DateField()), + ('hits', models.IntegerField(default=0)), + ('query', models.ForeignKey(to='wagtailsearch.Query', related_name='daily_hits')), + ], + options={ + }, + bases=(models.Model,), + ), + migrations.AlterUniqueTogether( + name='querydailyhits', + unique_together=set([('query', 'date')]), + ), + migrations.AddField( + model_name='editorspick', + name='query', + field=models.ForeignKey(to='wagtailsearch.Query', related_name='editors_picks'), + preserve_default=True, + ), + ] diff --git a/wagtail/wagtailsearch/migrations/__init__.py b/wagtail/wagtailsearch/migrations/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/wagtail/wagtailsnippets/__init__.py b/wagtail/wagtailsnippets/__init__.py index e69de29bb..4b8d21cd7 100644 --- a/wagtail/wagtailsnippets/__init__.py +++ b/wagtail/wagtailsnippets/__init__.py @@ -0,0 +1 @@ +default_app_config = 'wagtail.wagtailsnippets.apps.WagtailSnippetsAppConfig' diff --git a/wagtail/wagtailsnippets/apps.py b/wagtail/wagtailsnippets/apps.py new file mode 100644 index 000000000..f63d40759 --- /dev/null +++ b/wagtail/wagtailsnippets/apps.py @@ -0,0 +1,7 @@ +from django.apps import AppConfig + + +class WagtailSnippetsAppConfig(AppConfig): + name = 'wagtail.wagtailsnippets' + label = 'wagtailsnippets' + verbose_name = "Wagtail snippets" diff --git a/wagtail/wagtailusers/__init__.py b/wagtail/wagtailusers/__init__.py index e69de29bb..088b3cb69 100644 --- a/wagtail/wagtailusers/__init__.py +++ b/wagtail/wagtailusers/__init__.py @@ -0,0 +1 @@ +default_app_config = 'wagtail.wagtailusers.apps.WagtailUsersAppConfig' diff --git a/wagtail/wagtailusers/apps.py b/wagtail/wagtailusers/apps.py new file mode 100644 index 000000000..055e18d99 --- /dev/null +++ b/wagtail/wagtailusers/apps.py @@ -0,0 +1,7 @@ +from django.apps import AppConfig + + +class WagtailUsersAppConfig(AppConfig): + name = 'wagtail.wagtailusers' + label = 'wagtailusers' + verbose_name = "Wagtail users" diff --git a/wagtail/wagtailusers/migrations/0001_initial.py b/wagtail/wagtailusers/migrations/0001_initial.py new file mode 100644 index 000000000..e1968c0f1 --- /dev/null +++ b/wagtail/wagtailusers/migrations/0001_initial.py @@ -0,0 +1,28 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations +from django.conf import settings + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='UserProfile', + fields=[ + ('id', models.AutoField(serialize=False, verbose_name='ID', auto_created=True, primary_key=True)), + ('submitted_notifications', models.BooleanField(default=True, help_text='Receive notification when a page is submitted for moderation')), + ('approved_notifications', models.BooleanField(default=True, help_text='Receive notification when your page edit is approved')), + ('rejected_notifications', models.BooleanField(default=True, help_text='Receive notification when your page edit is rejected')), + ('user', models.OneToOneField(to=settings.AUTH_USER_MODEL)), + ], + options={ + }, + bases=(models.Model,), + ), + ] diff --git a/wagtail/wagtailusers/migrations/__init__.py b/wagtail/wagtailusers/migrations/__init__.py new file mode 100644 index 000000000..e69de29bb