Banner groups.
authorRadek Czajka <rczajka@rczajka.pl>
Mon, 18 Mar 2019 12:34:02 +0000 (13:34 +0100)
committerRadek Czajka <rczajka@rczajka.pl>
Mon, 18 Mar 2019 12:35:34 +0000 (13:35 +0100)
requirements/requirements.txt
src/social/admin.py
src/social/locale/pl/LC_MESSAGES/django.mo
src/social/locale/pl/LC_MESSAGES/django.po
src/social/migrations/0005_auto_20190318_1309.py [new file with mode: 0644]
src/social/migrations/0006_legacy_group.py [new file with mode: 0644]
src/social/models.py
src/wolnelektury/settings/apps.py

index 7bd6c0e..d916725 100644 (file)
@@ -14,6 +14,8 @@ django-allauth==0.38.0
 django-extensions==1.7.8
 djangorestframework==3.9.1
 djangorestframework-xml
+django-admin-ordering==0.10.0
+
 oauthlib>=3.0.1,<3.1
 
 # contact
index c53ff89..258e522 100755 (executable)
@@ -1,17 +1,18 @@
-# -*- coding: utf-8 -*-
 # This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
 # Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
 #
 from django.contrib import admin
 from django.utils.translation import ugettext_lazy as _
-
-from social.models import Cite
+from admin_ordering.admin import OrderableAdmin
+from social.models import Cite, BannerGroup, Carousel, CarouselItem
 
 
 class CiteAdmin(admin.ModelAdmin):
-    list_display = ['nonempty_text', 'sticky', 'vip', 'small', 'has_image']
+    list_display = ['nonempty_text', 'created_at', 'sticky', 'vip', 'small', 'has_image']
+    list_filter = ['group']
     fieldsets = (
-        (None, {'fields': ('book', 'text', 'small', 'vip', 'link', 'sticky', 'banner')}),
+        (None, {'fields': ('group', 'sticky')}),
+        (_('Content'), {'fields': ('book', 'text', 'small', 'vip', 'link', 'video', 'picture', 'banner')}),
         (
             _('Background'),
             {'fields': (
@@ -33,3 +34,18 @@ class CiteAdmin(admin.ModelAdmin):
 
 
 admin.site.register(Cite, CiteAdmin)
+
+admin.site.register(BannerGroup)
+
+
+class CarouselItemInline(OrderableAdmin, admin.TabularInline):
+    model = CarouselItem
+    ordering_field = 'order'
+
+
+class CarouselAdmin(admin.ModelAdmin):
+    inlines = [CarouselItemInline]
+
+
+admin.site.register(Carousel, CarouselAdmin)
+
index 283edb5..455ec07 100644 (file)
Binary files a/src/social/locale/pl/LC_MESSAGES/django.mo and b/src/social/locale/pl/LC_MESSAGES/django.mo differ
index bbb49ad..d9ef2d4 100644 (file)
@@ -7,7 +7,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2016-09-14 12:34+0200\n"
+"POT-Creation-Date: 2019-03-18 13:30+0100\n"
 "PO-Revision-Date: 2014-01-24 10:06+0100\n"
 "Last-Translator: Radek Czajka <radoslaw.czajka@nowoczesnapolska.org.pl>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -19,15 +19,19 @@ msgstr ""
 "|| n%100>=20) ? 1 : 2);\n"
 "X-Generator: Poedit 1.5.4\n"
 
-#: admin.py:16
+#: admin.py:15
+msgid "Content"
+msgstr "Zawartość"
+
+#: admin.py:17
 msgid "Background"
 msgstr "Obraz tła"
 
-#: admin.py:27 models.py:15
+#: admin.py:28 models.py:32
 msgid "text"
 msgstr "tekst"
 
-#: admin.py:31 models.py:23
+#: admin.py:32 models.py:44
 msgid "image"
 msgstr "obraz"
 
@@ -40,77 +44,137 @@ msgid "Name of the new shelf"
 msgstr "Nazwa nowej półki"
 
 #: models.py:14
+msgid "name"
+msgstr ""
+
+#: models.py:15 models.py:55
+msgid "created at"
+msgstr "utworzone"
+
+#: models.py:19
+msgid "banner group"
+msgstr "grupa bannerów"
+
+#: models.py:20
+msgid "banner groups"
+msgstr "grupy bannerów"
+
+#: models.py:31
 msgid "book"
 msgstr "książka"
 
-#: models.py:16
+#: models.py:33
 msgid "small"
 msgstr "mały"
 
-#: models.py:16
+#: models.py:33
 msgid "Make this cite display smaller."
 msgstr "Sprawia, że cytat wyświetla się mniejszym fontem."
 
-#: models.py:17
+#: models.py:34
 msgid "VIP"
 msgstr "VIP"
 
-#: models.py:18 models.py:30
+#: models.py:35 models.py:51
 msgid "link"
 msgstr "odnośnik"
 
-#: models.py:19
+#: models.py:36
+msgid "video"
+msgstr "wideo"
+
+#: models.py:37
+msgid "picture"
+msgstr "ilustracja"
+
+#: models.py:39
 msgid "sticky"
 msgstr "przyklejony"
 
-#: models.py:20
+#: models.py:40
 msgid "Sticky cites will take precedense."
 msgstr "Przyklejone cytaty mają pierwszeństwo."
 
-#: models.py:24
+#: models.py:41
+msgid "banner"
+msgstr "banner"
+
+#: models.py:41
+msgid "Adjust size to image, ignore the text"
+msgstr "Dostosuj wielkość do obrazu tła, zignoruj tekst."
+
+#: models.py:45
 msgid "Best image is exactly 975px wide and weights under 100kB."
 msgstr "Najlepszy obraz ma szerokość 975px i waży poniżej 100kB."
 
-#: models.py:26
+#: models.py:47
 msgid "shift"
 msgstr "przesunięcie"
 
-#: models.py:27
+#: models.py:48
 msgid ""
 "Vertical shift, in percents. 0 means top, 100 is bottom. Default is 50%."
 msgstr ""
 "Przesunięcie w pionie, w procentach. 0 to wyrównanie do górnej krawędzi, 100 "
 "do dolnej. Domyślne jest 50%."
 
-#: models.py:28
+#: models.py:49
 msgid "title"
 msgstr "tytuł"
 
-#: models.py:29
+#: models.py:50
 msgid "author"
 msgstr "autor"
 
-#: models.py:31
+#: models.py:52
 msgid "license name"
 msgstr "nazwa licencji"
 
-#: models.py:32
+#: models.py:53
 msgid "license link"
 msgstr "adres licencji"
 
-#: models.py:36
+#: models.py:56
+msgid "group"
+msgstr "grupa"
+
+#: models.py:60
 msgid "cite"
 msgstr "cytat"
 
-#: models.py:37
+#: models.py:61
 msgid "cites"
 msgstr "cytaty"
 
-#: templates/social/cite_promo.html:11
+#: models.py:87
+msgid "slug"
+msgstr "slug"
+
+#: models.py:91
+msgid "carousel"
+msgstr "karuzela"
+
+#: models.py:92
+msgid "carousels"
+msgstr "karuzele"
+
+#: models.py:104
+msgid "carousel item"
+msgstr "element karuzeli"
+
+#: models.py:105
+msgid "carousel items"
+msgstr "elementy karuzeli"
+
+#: models.py:109 models.py:111
+msgid "Either banner or banner group is required."
+msgstr "Proszę wskazać banner albo grupę bannerów."
+
+#: templates/social/cite_promo.html:14
 msgid "recommends"
 msgstr "poleca"
 
-#: templates/social/my_shelf.html:5 templates/social/my_shelf.html.py:10
+#: templates/social/my_shelf.html:5 templates/social/my_shelf.html:10
 msgid "My shelf"
 msgstr "Moja półka"
 
diff --git a/src/social/migrations/0005_auto_20190318_1309.py b/src/social/migrations/0005_auto_20190318_1309.py
new file mode 100644 (file)
index 0000000..3391fab
--- /dev/null
@@ -0,0 +1,93 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.20 on 2019-03-18 12:09
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('social', '0004_auto_20170725_1204'),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='BannerGroup',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('name', models.CharField(max_length=255, unique=True, verbose_name='name')),
+                ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='created at')),
+            ],
+            options={
+                'verbose_name': 'banner group',
+                'verbose_name_plural': 'banner groups',
+                'ordering': ('name',),
+            },
+        ),
+        migrations.CreateModel(
+            name='Carousel',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('slug', models.SlugField(unique=True, verbose_name='slug')),
+            ],
+            options={
+                'verbose_name': 'carousel',
+                'verbose_name_plural': 'carousels',
+                'ordering': ('slug',),
+            },
+        ),
+        migrations.CreateModel(
+            name='CarouselItem',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('order', models.PositiveSmallIntegerField(unique=True)),
+            ],
+            options={
+                'verbose_name': 'carousel item',
+                'verbose_name_plural': 'carousel items',
+                'ordering': ('order',),
+            },
+        ),
+        migrations.AddField(
+            model_name='cite',
+            name='created_at',
+            field=models.DateTimeField(auto_now_add=True, default='2007-09-17 12:00+00', verbose_name='created at'),
+            preserve_default=False,
+        ),
+        migrations.AddField(
+            model_name='cite',
+            name='picture',
+            field=models.ImageField(blank=True, upload_to='', verbose_name='picture'),
+        ),
+        migrations.AddField(
+            model_name='cite',
+            name='video',
+            field=models.URLField(blank=True, verbose_name='video'),
+        ),
+        migrations.AddField(
+            model_name='carouselitem',
+            name='banner',
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='social.Cite'),
+        ),
+        migrations.AddField(
+            model_name='carouselitem',
+            name='banner_group',
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='social.BannerGroup'),
+        ),
+        migrations.AddField(
+            model_name='carouselitem',
+            name='carousel',
+            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='social.Carousel'),
+        ),
+        migrations.AddField(
+            model_name='cite',
+            name='group',
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='social.BannerGroup', verbose_name='group'),
+        ),
+        migrations.AlterUniqueTogether(
+            name='carouselitem',
+            unique_together=set([('carousel', 'order')]),
+        ),
+    ]
diff --git a/src/social/migrations/0006_legacy_group.py b/src/social/migrations/0006_legacy_group.py
new file mode 100644 (file)
index 0000000..f6881a3
--- /dev/null
@@ -0,0 +1,26 @@
+from django.db import migrations
+
+
+def legacy_group(apps, schema_editor):
+    Cite = apps.get_model('social', 'Cite')
+    BannerGroup = apps.get_model('social', 'BannerGroup')
+
+    traditional = BannerGroup.objects.create(name='Tradycyjne cytaty')
+    banners = BannerGroup.objects.create(name='Bannery')
+
+    Cite.objects.exclude(book=None).update(group=traditional)
+    Cite.objects.filter(book=None).update(group=banners)
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('social', '0005_auto_20190318_1309'),
+    ]
+
+    operations = [
+        migrations.RunPython(
+            legacy_group,
+            migrations.RunPython.noop
+        )
+    ]
index b9417ba..c6a1815 100644 (file)
@@ -1,21 +1,41 @@
-# -*- coding: utf-8 -*-
 # This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
 # Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
 #
 from django.db import models
-from django.utils.translation import ugettext_lazy as _
 from django.conf import settings
+from django.core.exceptions import ValidationError
 from django.core.urlresolvers import reverse
+from django.utils.translation import ugettext_lazy as _
 from ssify import flush_ssi_includes
 from catalogue.models import Book
 
 
+class BannerGroup(models.Model):
+    name = models.CharField(_('name'), max_length=255, unique=True)
+    created_at = models.DateTimeField(_('created at'), auto_now_add=True)
+
+    class Meta:
+        ordering = ('name',)
+        verbose_name = _('banner group')
+        verbose_name_plural = _('banner groups')
+
+    def __str__(self):
+        return self.name
+
+    def get_absolute_url(self):
+        """This is used for testing."""
+        return "%s?banner_group=%d" % (reverse('main_page'), self.id)
+
+
 class Cite(models.Model):
     book = models.ForeignKey(Book, verbose_name=_('book'), null=True, blank=True)
     text = models.TextField(_('text'), blank=True)
     small = models.BooleanField(_('small'), default=False, help_text=_('Make this cite display smaller.'))
     vip = models.CharField(_('VIP'), max_length=128, null=True, blank=True)
     link = models.URLField(_('link'))
+    video = models.URLField(_('video'), blank=True)
+    picture = models.ImageField(_('picture'), blank=True)
+
     sticky = models.BooleanField(_('sticky'), default=False, db_index=True,
                                  help_text=_('Sticky cites will take precedense.'))
     banner = models.BooleanField(_('banner'), default=False, help_text=_('Adjust size to image, ignore the text'))
@@ -32,6 +52,9 @@ class Cite(models.Model):
     image_license = models.CharField(_('license name'), max_length=255, blank=True, null=True)
     image_license_link = models.URLField(_('license link'), blank=True, null=True)
 
+    created_at = models.DateTimeField(_('created at'), auto_now_add=True)
+    group = models.ForeignKey(BannerGroup, verbose_name=_('group'), null=True, blank=True, on_delete=models.SET_NULL)
+
     class Meta:
         ordering = ('vip', 'text')
         verbose_name = _('cite')
@@ -58,3 +81,36 @@ class Cite(models.Model):
             ]
             for lang in [lc for (lc, _ln) in settings.LANGUAGES]] +
             ['/ludzie/cite_info/%s.html' % self.pk])
+
+
+class Carousel(models.Model):
+    slug = models.SlugField(_('slug'), unique=True)
+
+    class Meta:
+        ordering = ('slug',)
+        verbose_name = _('carousel')
+        verbose_name_plural = _('carousels')
+
+    def __str__(self):
+        return self.slug
+
+class CarouselItem(models.Model):
+    order = models.PositiveSmallIntegerField(unique=True)
+    carousel = models.ForeignKey(Carousel, models.CASCADE)
+    banner = models.ForeignKey(Cite, models.CASCADE, null=True, blank=True)
+    banner_group = models.ForeignKey(BannerGroup, models.CASCADE, null=True, blank=True)
+
+    class Meta:
+        ordering = ('order',)
+        unique_together = [('carousel', 'order')]
+        verbose_name = _('carousel item')
+        verbose_name_plural = _('carousel items')
+
+    def __str__(self):
+        return str(self.banner or self.banner_group)
+
+    def clean(self):
+        if not self.banner and not self.banner_group:
+            raise ValidationError(_('Either banner or banner group is required.'))
+        elif self.banner and self.banner_group:
+            raise ValidationError(_('Either banner or banner group is required.'))
index 3446695..1ddd979 100644 (file)
@@ -46,6 +46,7 @@ INSTALLED_APPS_CONTRIB = [
     'django.contrib.admin',
     'django.contrib.admindocs',
     'django.contrib.staticfiles',
+    'admin_ordering',
     'rest_framework',
     'fnp_django_pagination',
     'pipeline',