From 2f6ad234f322fbf29af67e92d73a7b43bdf16d0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jannes=20H=C3=B6ke?= Date: Thu, 19 Mar 2020 14:03:03 +0100 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20Add=20subtype=20support=20for=20bre?= =?UTF-8?q?aking?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/api/views/subtypes.py | 2 +- app/cms/admin/report.py | 28 +++++++---- app/cms/admin/subtype.py | 13 ++++++ app/cms/migrations/0062_auto_20200319_1125.py | 46 +++++++++++++++++++ app/cms/models/report.py | 5 +- app/cms/models/subtype.py | 12 +++++ app/cms/static/cms/js/toggle_subtype.js | 40 +++++++++++++--- 7 files changed, 127 insertions(+), 19 deletions(-) create mode 100644 app/cms/migrations/0062_auto_20200319_1125.py diff --git a/app/api/views/subtypes.py b/app/api/views/subtypes.py index afa2644..8b71669 100644 --- a/app/api/views/subtypes.py +++ b/app/api/views/subtypes.py @@ -5,4 +5,4 @@ class SubtypeSerializer(serializers.ModelSerializer): class Meta: model = Subtype - fields = ('emoji', 'title', ) + fields = ('id', 'emoji', 'title', 'type', ) diff --git a/app/cms/admin/report.py b/app/cms/admin/report.py index fefa5d4..e2cb9a9 100644 --- a/app/cms/admin/report.py +++ b/app/cms/admin/report.py @@ -15,6 +15,7 @@ from crum import get_current_request from ..models.report import Report, ReportFragment, ReportQuiz +from ..models.subtype import Subtype from .attachment import trigger_attachments from .fragment import FragmentModelForm, FragmentAdminInline from .quiz import QuizModelForm, QuizAdminInline @@ -112,12 +113,22 @@ def get_initial_for_field(self, field, field_name): def clean(self): # Check for subtype setting - if self.cleaned_data['type'] == 'last' and self.cleaned_data['subtype'] is None: - raise ValidationError({ - 'subtype': 'Wenn der Meldungstyp auf "🎨 Letzte Meldung" gesetzt ist, ' - 'muss der Subtyp ausgefüllt werden.', - }) - elif self.cleaned_data['type'] != 'last' and self.cleaned_data['subtype'] is not None: + has_subtypes = ['last', 'breaking'] + the_type = self.cleaned_data['type'] + the_subtype = self.cleaned_data.get('subtype') + + if the_type in has_subtypes: + if the_subtype is None: + raise ValidationError({ + 'subtype': 'Wenn der Meldungstyp auf "🎨 Letzte Meldung" gesetzt ist, ' + 'muss der Subtyp ausgefüllt werden.', + }) + else: + if the_subtype.type != the_type: + raise ValidationError({ + 'subtype': 'Ungültiger Subtyp für den gewählten Meldungstyp', + }) + elif the_subtype is not None: self.cleaned_data['subtype'] = None return self.cleaned_data @@ -126,8 +137,9 @@ class ReportAdmin(ModelAdminObjectActionsMixin, NewsBaseAdmin): form = ReportModelForm change_form_template = "admin/cms/change_form_report.html" date_hierarchy = 'created' - list_filter = ['published', 'type'] + list_filter = ['published', 'type', 'subtype'] search_fields = ['headline'] + autocomplete_fields = NewsBaseAdmin.autocomplete_fields + ['subtype'] list_display = ( 'report_type', 'status', @@ -254,7 +266,7 @@ def send_breaking(self, obj, form): def report_type(self, obj): if Report.Type(obj.type) == Report.Type.BREAKING: - display = '🚨' + display = f'🚨{obj.subtype.emoji}' elif Report.Type(obj.type) == Report.Type.REGULAR: display = '📰' elif Report.Type(obj.type) == Report.Type.LAST: diff --git a/app/cms/admin/subtype.py b/app/cms/admin/subtype.py index a664f14..041801b 100644 --- a/app/cms/admin/subtype.py +++ b/app/cms/admin/subtype.py @@ -3,9 +3,22 @@ from ..models.subtype import Subtype class SubtypeAdmin(admin.ModelAdmin): + search_fields = ['title'] + list_display = ['title', 'emoji', 'type'] + class Meta: model = Subtype fields = "__all__" + def get_search_results(self, request, queryset, search_term): + ''' + Custom search results function that allows the autocomplete field in the ReportModelForm + to filter for specific reports (facilitated by the toggle_subtype.js script). + ''' + if 'report_type' in request.GET: + queryset = queryset.filter(type=request.GET['report_type']) + return super().get_search_results(request, queryset, search_term) + + # Register your model here admin.site.register(Subtype, SubtypeAdmin) diff --git a/app/cms/migrations/0062_auto_20200319_1125.py b/app/cms/migrations/0062_auto_20200319_1125.py new file mode 100644 index 0000000..7b21194 --- /dev/null +++ b/app/cms/migrations/0062_auto_20200319_1125.py @@ -0,0 +1,46 @@ +# Generated by Django 3.0.4 on 2020-03-19 11:25 + +from django.db import migrations, models +import django.db.models.deletion + + +def set_default_breaking_subtype(apps, schema_editor): + Report = apps.get_model("cms", "Report") + Subtype = apps.get_model("cms", "Subtype") + + default_subtype = Subtype(emoji='🚨', title='Eilmeldung', type='breaking') + default_subtype.save() + + for report in Report.objects.filter(type='breaking'): + report.subtype = default_subtype + report.save() + +class Migration(migrations.Migration): + + dependencies = [ + ('cms', '0061_auto_20200317_1436'), + ] + + operations = [ + migrations.AddField( + model_name='subtype', + name='type', + field=models.CharField(choices=[('regular', '📰 Reguläre Meldung'), ('last', '🎨 Letzte Meldung'), ('breaking', '🚨 Breaking')], default='last', help_text='Hier kannst du wählen, zu welchem Meldungstyp dieser Subtyp gehört.', max_length=20, verbose_name='Meldungstyp'), + ), + migrations.AlterField( + model_name='push', + name='link', + field=models.URLField(blank=True, default=None, help_text='Der PromoLink wird am Ende am Ende des Push-Outro angehangen. Der Button-Text lautet: "🔗 {Schlagwort PromoLink}".Damit bietet das Outro die Möglichkeit der Cross-Promo von WDR-Inhalten.', max_length=500, null=True, verbose_name='PromoLink'), + ), + migrations.AlterField( + model_name='push', + name='link_name', + field=models.CharField(blank=True, max_length=17, null=True, verbose_name='Schlagwort PromoLink'), + ), + migrations.AlterField( + model_name='report', + name='subtype', + field=models.ForeignKey(blank=True, help_text='Derzeit nur relevant für Meldungen vom Typ "🎨 Letzte Meldung" und "🚨 Breaking".', null=True, on_delete=django.db.models.deletion.CASCADE, related_name='reports', related_query_name='report', to='cms.Subtype', verbose_name='Subtyp'), + ), + migrations.RunPython(set_default_breaking_subtype), + ] diff --git a/app/cms/models/report.py b/app/cms/models/report.py index 91494d8..9b706f7 100644 --- a/app/cms/models/report.py +++ b/app/cms/models/report.py @@ -7,7 +7,6 @@ from .news_base import NewsBaseModel from .fragment import Fragment from .quiz import Quiz -from .subtype import Subtype class Report(NewsBaseModel): @@ -43,14 +42,14 @@ class DeliveryStatus(Enum): default=Type.REGULAR.value) subtype = models.ForeignKey( - Subtype, + 'Subtype', models.CASCADE, null=True, blank=True, verbose_name='Subtyp', related_name='reports', related_query_name='report', - help_text='Derzeit nur relevant für Meldungen vom Typ "🎨 Letzte Meldung".', + help_text='Derzeit nur relevant für Meldungen vom Typ "🎨 Letzte Meldung" und "🚨 Breaking".', ) headline = models.CharField('Überschrift', max_length=200, null=False) diff --git a/app/cms/models/subtype.py b/app/cms/models/subtype.py index 5fa5f4f..d6f3df0 100644 --- a/app/cms/models/subtype.py +++ b/app/cms/models/subtype.py @@ -1,5 +1,7 @@ from django.db import models +from .report import Report + class Subtype(models.Model): """ @@ -12,6 +14,16 @@ class Meta: verbose_name = 'Meldungs-Subtyp' verbose_name_plural = 'Meldungs-Subtypen' + type = models.CharField( + 'Meldungstyp', + null=False, + blank=False, + max_length=20, + choices=[(Report.Type.REGULAR.value, '📰 Reguläre Meldung'), + (Report.Type.LAST.value, '🎨 Letzte Meldung'), + (Report.Type.BREAKING.value, '🚨 Breaking')], + help_text='Hier kannst du wählen, zu welchem Meldungstyp dieser Subtyp gehört.', + default=Report.Type.LAST.value) emoji = models.CharField('Emoji', max_length=3, null=False, blank=False) title = models.CharField('Titel', max_length=17, null=False, blank=False) diff --git a/app/cms/static/cms/js/toggle_subtype.js b/app/cms/static/cms/js/toggle_subtype.js index abc1e3d..6e1f645 100644 --- a/app/cms/static/cms/js/toggle_subtype.js +++ b/app/cms/static/cms/js/toggle_subtype.js @@ -1,18 +1,44 @@ const typeSelector = '#id_type'; -const subtypeSelector = '.field-subtype'; +const subtypeSelector = '#id_subtype'; +const subtypeRowSelector = '.field-subtype'; +const HAS_SUBTYPES = ['last', 'breaking']; + +const updateTargetUrl = (type) => { + django.jQuery.fn.select2.amd.require( + ["select2/utils"], + function (Utils) { + const elem = django.jQuery(subtypeSelector); + const s2data = Utils.GetData(elem[0]); + const baseUrl = window.location.origin; + const targetUrl = new URL(s2data.select2.dataAdapter.ajaxOptions.url, baseUrl); + targetUrl.searchParams.set('report_type', type); + s2data.select2.dataAdapter.ajaxOptions.url = targetUrl.pathname + targetUrl.search; + }); +}; django.jQuery(document).ready(function(){ - if (django.jQuery(typeSelector)[0].value === 'last') { - django.jQuery(subtypeSelector).show(); + let select2ref; + const initialValue = django.jQuery(typeSelector)[0].value; + if (HAS_SUBTYPES.includes(initialValue)) { + updateTargetUrl(initialValue); } else { - django.jQuery(subtypeSelector).hide(); + django.jQuery(subtypeRowSelector).hide(); } + django.jQuery(typeSelector).change(function(){ - const visible = this.value === 'last'; + const visible = HAS_SUBTYPES.includes(this.value); if (visible) { - django.jQuery(subtypeSelector).show(); + django.jQuery(subtypeRowSelector).show(); + updateTargetUrl(this.value); + + // Re-init s2 field, reset the value and open the selection + select2ref = django.jQuery(subtypeSelector).select2(); + setTimeout(() => { + select2ref.val(null).trigger('change'); + select2ref.select2('open'); + }); } else { - django.jQuery(subtypeSelector).hide(); + django.jQuery(subtypeRowSelector).hide(); } }) });