From 73352e80cd8f23fc190cba7927163e02a371b443 Mon Sep 17 00:00:00 2001 From: Kirill Makan Date: Thu, 27 Jul 2023 10:37:40 +0200 Subject: [PATCH 1/5] add prototype for announcement messages --- daiquiri/contact/admin.py | 16 +++++++++- .../migrations/0007_announcementmessage.py | 29 ++++++++++++++++++ daiquiri/contact/models.py | 30 +++++++++++++++++++ .../templates/contact/announcements.html | 8 +++++ daiquiri/contact/templatetags/__init__.py | 0 .../contact/templatetags/announcement_tags.py | 12 ++++++++ daiquiri/core/templates/core/page.html | 2 ++ daiquiri/core/templates/core/wide.html | 3 +- 8 files changed, 98 insertions(+), 2 deletions(-) create mode 100644 daiquiri/contact/migrations/0007_announcementmessage.py create mode 100644 daiquiri/contact/templates/contact/announcements.html create mode 100644 daiquiri/contact/templatetags/__init__.py create mode 100644 daiquiri/contact/templatetags/announcement_tags.py diff --git a/daiquiri/contact/admin.py b/daiquiri/contact/admin.py index eaaf6000..bb29a3f0 100644 --- a/daiquiri/contact/admin.py +++ b/daiquiri/contact/admin.py @@ -1,11 +1,25 @@ from django.contrib import admin -from .models import ContactMessage +from .models import ContactMessage, AnnouncementMessage + + +@admin.action(description="Make selected messages visible") +def make_visible(modeladmin, request, queryset): + queryset.update(visible=True) + +@admin.action(description="Make selected messages invisible") +def make_invisible(modeladmin, request, queryset): + queryset.update(visible=False) class ContactMessageAdmin(admin.ModelAdmin): search_fields = ("subject", "email", "author", "status", "user__username") list_display = ("subject", "email", "author", "status") +class AnnouncementMessageAdmin(admin.ModelAdmin): + search_fields = ("title", "announcement") + list_display = ("title", "visible", "announcement", "announcement_type", "updated") + actions = [make_visible, make_invisible] admin.site.register(ContactMessage, ContactMessageAdmin) +admin.site.register(AnnouncementMessage, AnnouncementMessageAdmin) diff --git a/daiquiri/contact/migrations/0007_announcementmessage.py b/daiquiri/contact/migrations/0007_announcementmessage.py new file mode 100644 index 00000000..8d9c5ab5 --- /dev/null +++ b/daiquiri/contact/migrations/0007_announcementmessage.py @@ -0,0 +1,29 @@ +# Generated by Django 4.2.4 on 2023-08-08 09:57 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('daiquiri_contact', '0006_alter_contactmessage_id'), + ] + + operations = [ + migrations.CreateModel( + name='AnnouncementMessage', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('title', models.CharField(blank=True, max_length=100, null=True)), + ('announcement', models.TextField()), + ('announcement_type', models.CharField(choices=[('info', 'info'), ('warning', 'warning'), ('danger', 'urgent')], default='info', max_length=8)), + ('updated', models.DateTimeField(auto_now=True)), + ('visible', models.BooleanField(default=False)), + ], + options={ + 'verbose_name': 'Announcement message', + 'verbose_name_plural': 'Announcement messages', + 'ordering': ('-updated', 'title'), + }, + ), + ] diff --git a/daiquiri/contact/models.py b/daiquiri/contact/models.py index b7a18187..c666a597 100644 --- a/daiquiri/contact/models.py +++ b/daiquiri/contact/models.py @@ -44,3 +44,33 @@ def set_status_active(self): def set_status_spam(self): self.status = self.STATUS_SPAM self.save() + + +class AnnouncementMessage(models.Model): + + # alert types must correspond to the bootstrap alert types + ALERT_TYPE_INFO = "info" + ALERT_TYPE_WARNING = "warning" + ALERT_TYPE_ERROR = "danger" + + ANNOUNCEMENT_TYPE_CHOICES = ( + (ALERT_TYPE_INFO, "info"), + (ALERT_TYPE_WARNING, "warning"), + (ALERT_TYPE_ERROR, "urgent"), + ) + + title = models.CharField(max_length=100, blank=True, null=True) + announcement = models.TextField() + announcement_type = models.CharField(max_length=8, choices=ANNOUNCEMENT_TYPE_CHOICES, default=ALERT_TYPE_INFO) + updated = models.DateTimeField(auto_now=True) + visible = models.BooleanField(default=False) + + class Meta: + ordering = ('-updated', 'title') + + verbose_name = _('Announcement message') + verbose_name_plural = _('Announcement messages') + + def __str__(self): + return f"{self.title}: '{self.announcement}'" + diff --git a/daiquiri/contact/templates/contact/announcements.html b/daiquiri/contact/templates/contact/announcements.html new file mode 100644 index 00000000..6b650064 --- /dev/null +++ b/daiquiri/contact/templates/contact/announcements.html @@ -0,0 +1,8 @@ +{% if announcements %} + {% for msg in announcements %} + + {% endfor %} +{% endif %} diff --git a/daiquiri/contact/templatetags/__init__.py b/daiquiri/contact/templatetags/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/daiquiri/contact/templatetags/announcement_tags.py b/daiquiri/contact/templatetags/announcement_tags.py new file mode 100644 index 00000000..605af6ba --- /dev/null +++ b/daiquiri/contact/templatetags/announcement_tags.py @@ -0,0 +1,12 @@ +from django import template +from daiquiri.contact.models import AnnouncementMessage + +register = template.Library() + + +@register.inclusion_tag("contact/announcements.html") +def show_announcements(): + announcements = AnnouncementMessage.objects.filter(visible=True) + return { + "announcements": announcements, + } diff --git a/daiquiri/core/templates/core/page.html b/daiquiri/core/templates/core/page.html index 05c922de..733d78ae 100644 --- a/daiquiri/core/templates/core/page.html +++ b/daiquiri/core/templates/core/page.html @@ -1,8 +1,10 @@ {% extends 'core/base.html' %} +{% load announcement_tags %} {% block content %}
+ {% show_announcements %}
{% block page %}{% endblock %} diff --git a/daiquiri/core/templates/core/wide.html b/daiquiri/core/templates/core/wide.html index f14410ea..497a2299 100644 --- a/daiquiri/core/templates/core/wide.html +++ b/daiquiri/core/templates/core/wide.html @@ -1,9 +1,10 @@ {% extends 'core/base.html' %} - +{% load announcement_tags %} {% block content %}
+ {% show_announcements %} {% block wide %}{% endblock %}
From 40de99b46ce3b0926ac0afaee4ff6c6bca4fc555 Mon Sep 17 00:00:00 2001 From: Kirill Makan Date: Tue, 8 Aug 2023 12:40:57 +0200 Subject: [PATCH 2/5] remove announcement tags from the core templates --- daiquiri/core/templates/core/page.html | 2 -- daiquiri/core/templates/core/wide.html | 2 -- 2 files changed, 4 deletions(-) diff --git a/daiquiri/core/templates/core/page.html b/daiquiri/core/templates/core/page.html index 733d78ae..05c922de 100644 --- a/daiquiri/core/templates/core/page.html +++ b/daiquiri/core/templates/core/page.html @@ -1,10 +1,8 @@ {% extends 'core/base.html' %} -{% load announcement_tags %} {% block content %}
- {% show_announcements %}
{% block page %}{% endblock %} diff --git a/daiquiri/core/templates/core/wide.html b/daiquiri/core/templates/core/wide.html index 497a2299..80da0589 100644 --- a/daiquiri/core/templates/core/wide.html +++ b/daiquiri/core/templates/core/wide.html @@ -1,10 +1,8 @@ {% extends 'core/base.html' %} -{% load announcement_tags %} {% block content %}
- {% show_announcements %} {% block wide %}{% endblock %}
From b4fd9d3b6b8ca6b8cfc39112d1a4dbb207ca9f47 Mon Sep 17 00:00:00 2001 From: kimakan <45099849+kimakan@users.noreply.github.com> Date: Tue, 19 Sep 2023 11:17:29 +0200 Subject: [PATCH 3/5] add visibility conditions to the announcement messages and refactor --- daiquiri/contact/admin.py | 11 ++++- daiquiri/contact/filters.py | 33 +++++++++++++- .../migrations/0007_announcementmessage.py | 13 +++--- daiquiri/contact/models.py | 45 ++++++++++++++++--- daiquiri/contact/settings.py | 1 + .../templates/contact/announcements.html | 2 +- .../contact/templatetags/announcement_tags.py | 6 ++- 7 files changed, 92 insertions(+), 19 deletions(-) create mode 100644 daiquiri/contact/settings.py diff --git a/daiquiri/contact/admin.py b/daiquiri/contact/admin.py index bb29a3f0..d87e8561 100644 --- a/daiquiri/contact/admin.py +++ b/daiquiri/contact/admin.py @@ -1,12 +1,18 @@ +from django import forms from django.contrib import admin -from .models import ContactMessage, AnnouncementMessage +from .models import ContactMessage, AnnouncementMessage, MessageFilter + + +class AnnouncementMessageAdminForm(forms.ModelForm): + visibility_filter = forms.ChoiceField(choices=MessageFilter().CHOICES) @admin.action(description="Make selected messages visible") def make_visible(modeladmin, request, queryset): queryset.update(visible=True) + @admin.action(description="Make selected messages invisible") def make_invisible(modeladmin, request, queryset): queryset.update(visible=False) @@ -16,7 +22,10 @@ class ContactMessageAdmin(admin.ModelAdmin): search_fields = ("subject", "email", "author", "status", "user__username") list_display = ("subject", "email", "author", "status") + class AnnouncementMessageAdmin(admin.ModelAdmin): + form = AnnouncementMessageAdminForm + search_fields = ("title", "announcement") list_display = ("title", "visible", "announcement", "announcement_type", "updated") actions = [make_visible, make_invisible] diff --git a/daiquiri/contact/filters.py b/daiquiri/contact/filters.py index 04947c56..147fedcc 100644 --- a/daiquiri/contact/filters.py +++ b/daiquiri/contact/filters.py @@ -1,11 +1,13 @@ from rest_framework import filters -from .models import ContactMessage - class SpamBackend(filters.BaseFilterBackend): + def filter_queryset(self, request, queryset, view): + + from daiquiri.contact.models import ContactMessage + spam = request.GET.get('spam') if spam is not None: @@ -15,3 +17,30 @@ def filter_queryset(self, request, queryset, view): queryset = queryset.exclude(status=ContactMessage.STATUS_SPAM) return queryset + + + +class DefaultMessageFilter(object): + + CHOICES = ( + ("no_filter", "Show to all users"), + ("logged_in_users", "Show to the logged in users only"), + ("user_has_not_consented", "Show to user who has not consented yet"), + ) + + def no_filter(request): + return True + + def logged_in_users(request): + if request.user.is_authenticated: + return True + return False + + def user_has_not_consented(request): + if request.user.is_authenticated: + if not request.user.profile.consent: + return True + return False + + + diff --git a/daiquiri/contact/migrations/0007_announcementmessage.py b/daiquiri/contact/migrations/0007_announcementmessage.py index 8d9c5ab5..37d9610a 100644 --- a/daiquiri/contact/migrations/0007_announcementmessage.py +++ b/daiquiri/contact/migrations/0007_announcementmessage.py @@ -1,4 +1,4 @@ -# Generated by Django 4.2.4 on 2023-08-08 09:57 +# Generated by Django 4.2.5 on 2023-09-20 07:37 from django.db import migrations, models @@ -14,11 +14,12 @@ class Migration(migrations.Migration): name='AnnouncementMessage', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('title', models.CharField(blank=True, max_length=100, null=True)), - ('announcement', models.TextField()), - ('announcement_type', models.CharField(choices=[('info', 'info'), ('warning', 'warning'), ('danger', 'urgent')], default='info', max_length=8)), - ('updated', models.DateTimeField(auto_now=True)), - ('visible', models.BooleanField(default=False)), + ('title', models.CharField(blank=True, max_length=100, null=True, verbose_name='Title')), + ('announcement', models.TextField(verbose_name='Announcement')), + ('announcement_type', models.CharField(choices=[('info', 'info'), ('warning', 'warning'), ('danger', 'urgent')], default='info', max_length=8, verbose_name='Announcement type')), + ('updated', models.DateTimeField(auto_now=True, verbose_name='Updated')), + ('visible', models.BooleanField(default=False, verbose_name='Visible')), + ('visibility_filter', models.CharField(default='no_filter', max_length=50, verbose_name='Visibility filter')), ], options={ 'verbose_name': 'Announcement message', diff --git a/daiquiri/contact/models.py b/daiquiri/contact/models.py index c666a597..18612bc5 100644 --- a/daiquiri/contact/models.py +++ b/daiquiri/contact/models.py @@ -1,10 +1,14 @@ +from django.conf import settings from django.contrib.auth.models import User from django.db import models from django.utils.translation import gettext_lazy as _ +from daiquiri.core.utils import import_class + class ContactMessage(models.Model): + STATUS_ACTIVE = 'ACTIVE' STATUS_CLOSED = 'CLOSED' STATUS_SPAM = 'SPAM' @@ -46,24 +50,48 @@ def set_status_spam(self): self.save() + +def MessageFilter(): + return import_class(settings.ANNOUNCEMENT_MESSAGE_FILTER) + class AnnouncementMessage(models.Model): # alert types must correspond to the bootstrap alert types ALERT_TYPE_INFO = "info" ALERT_TYPE_WARNING = "warning" - ALERT_TYPE_ERROR = "danger" + ALERT_TYPE_URGENT = "danger" ANNOUNCEMENT_TYPE_CHOICES = ( (ALERT_TYPE_INFO, "info"), (ALERT_TYPE_WARNING, "warning"), - (ALERT_TYPE_ERROR, "urgent"), + (ALERT_TYPE_URGENT, "urgent"), ) - title = models.CharField(max_length=100, blank=True, null=True) - announcement = models.TextField() - announcement_type = models.CharField(max_length=8, choices=ANNOUNCEMENT_TYPE_CHOICES, default=ALERT_TYPE_INFO) - updated = models.DateTimeField(auto_now=True) - visible = models.BooleanField(default=False) + title = models.CharField( + max_length=100, blank=True, null=True, + verbose_name=_("Title") + ) + announcement = models.TextField( + verbose_name=_("Announcement") + ) + announcement_type = models.CharField( + max_length=8, + choices=ANNOUNCEMENT_TYPE_CHOICES, + default=ALERT_TYPE_INFO, + verbose_name=_("Announcement type") + ) + updated = models.DateTimeField( + auto_now=True, + verbose_name=_("Updated") + ) + visible = models.BooleanField( + default=False, + verbose_name=_("Visible") + ) + visibility_filter = models.CharField( + max_length=50, default="no_filter", + verbose_name="Visibility filter" + ) class Meta: ordering = ('-updated', 'title') @@ -74,3 +102,6 @@ class Meta: def __str__(self): return f"{self.title}: '{self.announcement}'" + def get_filter(self): + return getattr(MessageFilter(), str(self.visibility_filter)) + diff --git a/daiquiri/contact/settings.py b/daiquiri/contact/settings.py new file mode 100644 index 00000000..3654671d --- /dev/null +++ b/daiquiri/contact/settings.py @@ -0,0 +1 @@ +ANNOUNCEMENT_MESSAGE_FILTER = 'daiquiri.contact.filters.DefaultMessageFilter' diff --git a/daiquiri/contact/templates/contact/announcements.html b/daiquiri/contact/templates/contact/announcements.html index 6b650064..f85417b8 100644 --- a/daiquiri/contact/templates/contact/announcements.html +++ b/daiquiri/contact/templates/contact/announcements.html @@ -2,7 +2,7 @@ {% for msg in announcements %} {% endfor %} {% endif %} diff --git a/daiquiri/contact/templatetags/announcement_tags.py b/daiquiri/contact/templatetags/announcement_tags.py index 605af6ba..7d42bd4b 100644 --- a/daiquiri/contact/templatetags/announcement_tags.py +++ b/daiquiri/contact/templatetags/announcement_tags.py @@ -4,9 +4,11 @@ register = template.Library() -@register.inclusion_tag("contact/announcements.html") -def show_announcements(): +@register.inclusion_tag("contact/announcements.html", takes_context=True) +def show_announcements(context): + request = context["request"] announcements = AnnouncementMessage.objects.filter(visible=True) + announcements = [msg for msg in announcements if msg.get_filter()(request) is True] return { "announcements": announcements, } From 6ec8cac152cf26c9b59df0adf9af4bfa32705d62 Mon Sep 17 00:00:00 2001 From: kimakan <45099849+kimakan@users.noreply.github.com> Date: Fri, 22 Sep 2023 15:51:46 +0200 Subject: [PATCH 4/5] add a new filter to the announcement messages --- daiquiri/contact/filters.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/daiquiri/contact/filters.py b/daiquiri/contact/filters.py index 147fedcc..2a57a604 100644 --- a/daiquiri/contact/filters.py +++ b/daiquiri/contact/filters.py @@ -1,4 +1,6 @@ +from django.core.exceptions import ValidationError from rest_framework import filters +from daiquiri.auth.validators import DaiquiriUsernameValidator class SpamBackend(filters.BaseFilterBackend): @@ -26,6 +28,7 @@ class DefaultMessageFilter(object): ("no_filter", "Show to all users"), ("logged_in_users", "Show to the logged in users only"), ("user_has_not_consented", "Show to user who has not consented yet"), + ("user_has_invalid_username", "Show to user with an invalid username"), ) def no_filter(request): @@ -42,5 +45,10 @@ def user_has_not_consented(request): return True return False - - + def user_has_invalid_username(request): + if request.user.is_authenticated: + try: + DaiquiriUsernameValidator()(request.user.username) + except ValidationError: + return True + return False From 999d9741133d3ebd714803a95b7fb87c1dfa0480 Mon Sep 17 00:00:00 2001 From: kimakan <45099849+kimakan@users.noreply.github.com> Date: Fri, 29 Sep 2023 16:52:09 +0200 Subject: [PATCH 5/5] Update __init__.py --- testing/config/settings/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/testing/config/settings/__init__.py b/testing/config/settings/__init__.py index 744f875a..0d78d831 100644 --- a/testing/config/settings/__init__.py +++ b/testing/config/settings/__init__.py @@ -6,6 +6,7 @@ from daiquiri.auth.settings import * from daiquiri.conesearch.settings import * +from daiquiri.contact.settings import * from daiquiri.cutout.settings import * from daiquiri.datalink.settings import * from daiquiri.files.settings import *