From: Radek Czajka Date: Mon, 18 Mar 2019 12:34:02 +0000 (+0100) Subject: Banner groups. X-Git-Url: https://git.mdrn.pl/wolnelektury.git/commitdiff_plain/deb806113c76384876cd4969dc20c1e76ddabfef?ds=inline Banner groups. --- diff --git a/requirements/requirements.txt b/requirements/requirements.txt index 7bd6c0e26..d91672550 100644 --- a/requirements/requirements.txt +++ b/requirements/requirements.txt @@ -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 diff --git a/src/social/admin.py b/src/social/admin.py index c53ff893f..258e522c0 100755 --- a/src/social/admin.py +++ b/src/social/admin.py @@ -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) + diff --git a/src/social/locale/pl/LC_MESSAGES/django.mo b/src/social/locale/pl/LC_MESSAGES/django.mo index 283edb541..455ec071e 100644 Binary files a/src/social/locale/pl/LC_MESSAGES/django.mo and b/src/social/locale/pl/LC_MESSAGES/django.mo differ diff --git a/src/social/locale/pl/LC_MESSAGES/django.po b/src/social/locale/pl/LC_MESSAGES/django.po index bbb49ad1c..d9ef2d4e1 100644 --- a/src/social/locale/pl/LC_MESSAGES/django.po +++ b/src/social/locale/pl/LC_MESSAGES/django.po @@ -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 \n" "Language-Team: LANGUAGE \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 index 000000000..3391fabe5 --- /dev/null +++ b/src/social/migrations/0005_auto_20190318_1309.py @@ -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 index 000000000..f6881a322 --- /dev/null +++ b/src/social/migrations/0006_legacy_group.py @@ -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 + ) + ] diff --git a/src/social/models.py b/src/social/models.py index b9417bae5..c6a1815bf 100644 --- a/src/social/models.py +++ b/src/social/models.py @@ -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.')) diff --git a/src/wolnelektury/settings/apps.py b/src/wolnelektury/settings/apps.py index 344669550..1ddd97907 100644 --- a/src/wolnelektury/settings/apps.py +++ b/src/wolnelektury/settings/apps.py @@ -46,6 +46,7 @@ INSTALLED_APPS_CONTRIB = [ 'django.contrib.admin', 'django.contrib.admindocs', 'django.contrib.staticfiles', + 'admin_ordering', 'rest_framework', 'fnp_django_pagination', 'pipeline',