diff --git a/locale/de/LC_MESSAGES/django.po b/locale/de/LC_MESSAGES/django.po index 8648c9a..afd206c 100644 --- a/locale/de/LC_MESSAGES/django.po +++ b/locale/de/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2025-02-06 17:08+0100\n" +"POT-Creation-Date: 2025-02-09 17:31+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -56,7 +56,6 @@ msgid "content" msgstr "Inhalt" #: mpicms/base/blocks.py:56 mpicms/base/blocks.py:59 mpicms/base/models.py:74 -#: mpicms/templates/personal/list.html:92 #: venv0/lib/python3.7/site-packages/wagtailvideos/templates/wagtailvideos/videos/usage.html:16 msgid "Title" msgstr "Titel" @@ -83,7 +82,7 @@ msgstr "Generiere Inhaltsverzeichnis" msgid "Page not available in %s" msgstr "Seite auf %s nicht vorhanden" -#: mpicms/base/mixins.py:94 mpicms/personal/wagtail_hooks.py:99 +#: mpicms/base/mixins.py:94 mpicms/personal/wagtail_hooks.py:98 msgid "Contacts" msgstr "Kontakte" @@ -91,8 +90,8 @@ msgstr "Kontakte" msgid "Sidebar Content" msgstr "Inhalt der Seitenleiste" -#: mpicms/base/models.py:46 mpicms/personal/models.py:68 -#: mpicms/personal/models.py:120 mpicms/publications/models.py:26 +#: mpicms/base/models.py:46 mpicms/personal/models.py:27 +#: mpicms/personal/models.py:95 mpicms/publications/models.py:26 #: venv0/lib/python3.7/site-packages/wagtailvideos/models.py:84 msgid "title" msgstr "Titel" @@ -190,7 +189,7 @@ msgstr "Anfangszeit" msgid "end time" msgstr "Endzeit" -#: mpicms/events/models.py:22 mpicms/templates/personal/list.html:97 +#: mpicms/events/models.py:22 mpicms/templates/personal/list.html:95 msgid "Room" msgstr "Raum" @@ -234,106 +233,82 @@ msgstr "Neuigkeit" msgid "news entries" msgstr "Neuigkeiten" -#: mpicms/personal/models.py:25 mpicms/publications/models.py:27 -msgid "groups" -msgstr "Gruppen" - -#: mpicms/personal/models.py:31 -msgid "group" -msgstr "Gruppe" - -#: mpicms/personal/models.py:44 -msgid "positions" -msgstr "Positionen" - -#: mpicms/personal/models.py:50 -msgid "position" -msgstr "Position" - -#: mpicms/personal/models.py:83 +#: mpicms/personal/models.py:45 msgid "status" -msgstr "" +msgstr "Status" -#: mpicms/personal/models.py:97 +#: mpicms/personal/models.py:60 msgid "special function" -msgstr "" +msgstr "Sonderfunktion" -#: mpicms/personal/models.py:121 +#: mpicms/personal/models.py:74 +msgid "name" +msgstr "Name" + +#: mpicms/personal/models.py:96 msgid "first name" msgstr "Vorname" -#: mpicms/personal/models.py:122 +#: mpicms/personal/models.py:97 msgid "last name" msgstr "Nachname" -#: mpicms/personal/models.py:123 +#: mpicms/personal/models.py:98 msgid "academic_suffix" msgstr "" -#: mpicms/personal/models.py:124 +#: mpicms/personal/models.py:99 msgid "email" msgstr "Email-Adresse" -#: mpicms/personal/models.py:125 +#: mpicms/personal/models.py:100 msgid "phone number" msgstr "Telefonnummer" -#: mpicms/personal/models.py:126 +#: mpicms/personal/models.py:101 msgid "room" msgstr "Raum" -#: mpicms/personal/models.py:127 +#: mpicms/personal/models.py:102 msgid "is active" msgstr "ist aktiv" -#: mpicms/personal/models.py:129 mpicms/personal/models.py:191 -msgid "priority" -msgstr "Priorität" - -#: mpicms/personal/models.py:130 -msgid "Priority from 0-999 to determine the sorting order." -msgstr "Priorität von 0-999 zur Bestimmung der Reihenfolge." - -#: mpicms/personal/models.py:132 +#: mpicms/personal/models.py:104 msgid "special functions" -msgstr "" - -#: mpicms/personal/models.py:188 -msgid "slug" -msgstr "Kürzel" +msgstr "Sonderfunktionen" -#: mpicms/personal/models.py:189 -msgid "name" -msgstr "Name" +#: mpicms/personal/models.py:105 +msgid "positions" +msgstr "Positionen" -#: mpicms/personal/models.py:192 -msgid "Priority from 0-99 to determine the sorting order." -msgstr "Priorität von 0-99 zur Bestimmung der Reihenfolge." +#: mpicms/personal/models.py:106 mpicms/publications/models.py:27 +msgid "groups" +msgstr "Gruppen" -#: mpicms/personal/models.py:220 +#: mpicms/personal/models.py:167 msgid "valid" -msgstr "" +msgstr "gültig" #: mpicms/personal/wagtail_hooks.py:40 msgid "Persons" msgstr "Personen" -#: mpicms/personal/wagtail_hooks.py:52 mpicms/personal/wagtail_hooks.py:69 -#: mpicms/templates/personal/list.html:98 +#: mpicms/personal/wagtail_hooks.py:52 mpicms/personal/wagtail_hooks.py:68 +#: mpicms/templates/personal/list.html:96 #: mpicms/templates/wagtailusers/users/list.html:28 msgid "Groups" msgstr "Gruppen" -#: mpicms/personal/wagtail_hooks.py:57 mpicms/personal/wagtail_hooks.py:76 -#: mpicms/templates/personal/list.html:99 +#: mpicms/personal/wagtail_hooks.py:56 mpicms/personal/wagtail_hooks.py:75 +#: mpicms/templates/personal/list.html:97 msgid "Positions" msgstr "Positionen" -#: mpicms/personal/wagtail_hooks.py:88 mpicms/templates/personal/list.html:100 +#: mpicms/personal/wagtail_hooks.py:87 mpicms/templates/personal/list.html:98 msgid "Special Functions" msgstr "Sonderfunktionen" -#: mpicms/personal/wagtail_hooks.py:94 +#: mpicms/personal/wagtail_hooks.py:93 msgid "Written Consents" msgstr "Einwilligungen" @@ -466,19 +441,17 @@ msgstr "Position" msgid "Special Function" msgstr "Sonderfunktion" -#: mpicms/templates/personal/list.html:93 -msgid "First Name" -msgstr "Vorname" - -#: mpicms/templates/personal/list.html:94 -msgid "Last Name" +#: mpicms/templates/personal/list.html:92 +#: mpicms/templates/wagtailusers/users/list.html:8 +#: mpicms/templates/wagtailusers/users/list.html:12 +msgid "Name" msgstr "Nachname" -#: mpicms/templates/personal/list.html:95 +#: mpicms/templates/personal/list.html:93 msgid "Email" msgstr "Email-Adresse" -#: mpicms/templates/personal/list.html:96 +#: mpicms/templates/personal/list.html:94 msgid "Phone" msgstr "Telefon" @@ -516,12 +489,7 @@ msgstr "Nicht Abonniert" #: mpicms/templates/wagtailusers/users/index.html:5 msgid "Users" -msgstr "" - -#: mpicms/templates/wagtailusers/users/list.html:8 -#: mpicms/templates/wagtailusers/users/list.html:12 -msgid "Name" -msgstr "Nachname" +msgstr "Benutzer" #: mpicms/templates/wagtailusers/users/list.html:19 #: mpicms/templates/wagtailusers/users/list.html:23 @@ -2220,5 +2188,29 @@ msgstr "" msgid "Edit this video" msgstr "" +#~ msgid "group" +#~ msgstr "Gruppe" + +#~ msgid "position" +#~ msgstr "Position" + +#~ msgid "priority" +#~ msgstr "Priorität" + +#~ msgid "Priority from 0-999 to determine the sorting order." +#~ msgstr "Priorität von 0-999 zur Bestimmung der Reihenfolge." + +#~ msgid "slug" +#~ msgstr "Kürzel" + +#~ msgid "Priority from 0-99 to determine the sorting order." +#~ msgstr "Priorität von 0-99 zur Bestimmung der Reihenfolge." + +#~ msgid "First Name" +#~ msgstr "Vorname" + +#~ msgid "Last Name" +#~ msgstr "Nachname" + #~ msgid "Filter by group" #~ msgstr "Gruppen" diff --git a/mpicms/personal/migrations/0028_auto_20250208_2003.py b/mpicms/personal/migrations/0028_auto_20250208_2003.py new file mode 100644 index 0000000..e5a6461 --- /dev/null +++ b/mpicms/personal/migrations/0028_auto_20250208_2003.py @@ -0,0 +1,29 @@ +# Generated by Django 3.1.7 on 2025-02-08 19:03 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('personal', '0027_auto_20250115_1509'), + ] + + operations = [ + migrations.AlterModelOptions( + name='group', + options={'ordering': ['name'], 'verbose_name': 'Group', 'verbose_name_plural': 'Groups'}, + ), + migrations.AlterModelOptions( + name='position', + options={'ordering': ['title']}, + ), + migrations.AlterModelOptions( + name='specialfunction', + options={'ordering': ['title']}, + ), + migrations.AlterModelOptions( + name='status', + options={'ordering': ['title'], 'verbose_name_plural': 'status'}, + ), + ] diff --git a/mpicms/personal/migrations/0029_auto_20250209_1010.py b/mpicms/personal/migrations/0029_auto_20250209_1010.py new file mode 100644 index 0000000..944728e --- /dev/null +++ b/mpicms/personal/migrations/0029_auto_20250209_1010.py @@ -0,0 +1,22 @@ +# Generated by Django 3.1.7 on 2025-02-09 09:10 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('personal', '0028_auto_20250208_2003'), + ] + + operations = [ + migrations.AddField( + model_name='contact', + name='positions', + field=models.ManyToManyField(blank=True, related_name='contacts', to='personal.Position', verbose_name='positions'), + ), + migrations.RunSQL("INSERT INTO personal_contact_positions(id, contact_id, position_id) SELECT id, contact_id, position_id FROM personal_contactpositions"), + migrations.DeleteModel( + name='ContactPositions', + ), + ] diff --git a/mpicms/personal/migrations/0030_auto_20250209_1143.py b/mpicms/personal/migrations/0030_auto_20250209_1143.py new file mode 100644 index 0000000..85f6c1a --- /dev/null +++ b/mpicms/personal/migrations/0030_auto_20250209_1143.py @@ -0,0 +1,22 @@ +# Generated by Django 3.1.7 on 2025-02-09 10:43 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('personal', '0029_auto_20250209_1010'), + ] + + operations = [ + migrations.AddField( + model_name='contact', + name='groups', + field=models.ManyToManyField(blank=True, related_name='contacts', to='personal.Group', verbose_name='groups'), + ), + migrations.RunSQL("INSERT INTO personal_contact_groups(id, contact_id, group_id) SELECT id, contact_id, group_id FROM personal_contactgroups"), + migrations.DeleteModel( + name='ContactGroups', + ), + ] diff --git a/mpicms/personal/migrations/0031_auto_20250209_1358.py b/mpicms/personal/migrations/0031_auto_20250209_1358.py new file mode 100644 index 0000000..a5093d6 --- /dev/null +++ b/mpicms/personal/migrations/0031_auto_20250209_1358.py @@ -0,0 +1,25 @@ +# Generated by Django 3.1.7 on 2025-02-09 12:58 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('personal', '0030_auto_20250209_1143'), + ] + + operations = [ + migrations.RemoveField( + model_name='contact', + name='priority', + ), + migrations.RemoveField( + model_name='group', + name='priority', + ), + migrations.RemoveField( + model_name='group', + name='slug', + ), + ] diff --git a/mpicms/personal/models.py b/mpicms/personal/models.py index 27d77ca..c42e213 100644 --- a/mpicms/personal/models.py +++ b/mpicms/personal/models.py @@ -2,59 +2,19 @@ from django.utils.translation import gettext_lazy as _ from django.core.validators import MaxValueValidator -from wagtail.core.models import Orderable -from wagtail.admin.edit_handlers import FieldPanel, MultiFieldPanel, InlinePanel +from wagtail.admin.edit_handlers import FieldPanel, MultiFieldPanel from wagtail.snippets.models import register_snippet from wagtail.search import index -from wagtail.snippets.edit_handlers import SnippetChooserPanel -from modelcluster.models import ClusterableModel from modelcluster.fields import ParentalKey +# still used in migrations class FilterableParentalKey(ParentalKey): def get_related_field(self): return self.remote_field -class ContactGroups(Orderable, models.Model): - """ - This defines the relationship between the `Group` within the `Contact` model below. - """ - contact = FilterableParentalKey( - 'Contact', related_name=_('groups'), on_delete=models.CASCADE - ) - group = models.ForeignKey( - 'personal.Group', - related_name='contacts', - on_delete=models.CASCADE, - verbose_name=_('group') - ) - - panels = [ - SnippetChooserPanel('group'), - ] - - -class ContactPositions(Orderable, models.Model): - """ - This defines the relationship between the `Position` within the `Contact` model below. - """ - contact = FilterableParentalKey( - 'Contact', related_name=_('positions'), on_delete=models.CASCADE - ) - position = models.ForeignKey( - 'personal.Position', - related_name='contacts', - on_delete=models.CASCADE, - verbose_name=_('position') - ) - - panels = [ - SnippetChooserPanel('position'), - ] - - class ContactManager(models.Manager): def get_queryset(self): return super().get_queryset().filter(is_active=True) @@ -63,7 +23,6 @@ def include_inactive(self): return super().get_queryset() -@register_snippet class Position(models.Model): title = models.CharField(_("title"), max_length=50) @@ -78,6 +37,9 @@ class Position(models.Model): def __str__(self): return self.title + class Meta: + ordering = ["title"] + class Status(models.Model): title = models.CharField(_("status"), max_length=50) @@ -91,6 +53,7 @@ def __str__(self): class Meta: verbose_name_plural = "status" + ordering = ["title"] class SpecialFunction(models.Model): @@ -103,20 +66,32 @@ class SpecialFunction(models.Model): def __str__(self): return self.title + class Meta: + ordering = ["title"] + + +class Group(index.Indexed, models.Model): + name = models.CharField(_("name"), max_length=254, blank=True) + + panels = [ + FieldPanel('name'), + ] + + search_fields = [ + index.SearchField('name', partial_match=True), + ] + + def __str__(self): + return self.name + + class Meta: # noqa + verbose_name = 'Group' + verbose_name_plural = 'Groups' + ordering = ['name'] + @register_snippet -class Contact(index.Indexed, ClusterableModel): - """ - A Django model to store People objects. - It uses the `@register_snippet` decorator to allow it to be accessible - via the Snippets UI (e.g. /admin/snippets/base/people/) - `People` uses the `ClusterableModel`, which allows the relationship with - another model to be stored locally to the 'parent' model (e.g. a PageModel) - until the parent is explicitly saved. This allows the editor to use the - 'Preview' button, to preview the content, without saving the relationships - to the database. - https://github.com/wagtail/django-modelcluster - """ +class Contact(index.Indexed, models.Model): title = models.CharField(_("title"), max_length=15, blank=True) first_name = models.CharField(_("first name"), max_length=50, blank=True) last_name = models.CharField(_("last name"), max_length=50, blank=True) @@ -125,11 +100,10 @@ class Contact(index.Indexed, ClusterableModel): phone = models.CharField(_("phone number"), blank=True, max_length=50) room = models.CharField(_("room"), max_length=50, blank=True) is_active = models.BooleanField(_("is active"), default=True) - priority = models.PositiveSmallIntegerField( - _("priority"), blank=True, default=0, validators=[MaxValueValidator(999)], - help_text=_("Priority from 0-999 to determine the sorting order.")) status = models.ForeignKey(Status, on_delete=models.SET_NULL, blank=True, null=True) special_functions = models.ManyToManyField(SpecialFunction, verbose_name=_('special functions'), blank=True) + positions = models.ManyToManyField(Position, related_name="contacts", blank=True, verbose_name=_('positions')) + groups = models.ManyToManyField(Group, related_name="contacts", blank=True, verbose_name=_('groups')) objects = ContactManager() @@ -139,21 +113,14 @@ class Contact(index.Indexed, ClusterableModel): FieldPanel('first_name'), FieldPanel('last_name'), FieldPanel('academic_suffix'), - ], heading='Name'), - FieldPanel('status'), - InlinePanel( - 'positions', label="Positions", - panels=None - ), - FieldPanel('special_functions'), - FieldPanel('email'), - FieldPanel('phone'), - FieldPanel('room'), - InlinePanel( - 'groups', label="Groups", - panels=None), - FieldPanel('is_active'), - FieldPanel('priority'), + FieldPanel('is_active'), + FieldPanel('email'), + FieldPanel('phone'), + FieldPanel('room'), + FieldPanel('groups'), + FieldPanel('positions'), + FieldPanel('special_functions'), + ]), ] search_fields = [ @@ -169,9 +136,21 @@ class Contact(index.Indexed, ClusterableModel): # index.SearchField('groups'), ] + @property + def name(self): + return ", ".join(filter(None, (self.last_name, self.first_name))) + + @property + def name_and_title(self): + return ", ".join(filter(None, ( + self.last_name, + " ".join(filter(None, (self.title, self.first_name))), + self.academic_suffix, + ))) + def __str__(self): if self.first_name or self.last_name: - return " ".join(filter(None, (self.title, self.first_name, self.last_name))) + return ", ".join(filter(None, (self.last_name, self.first_name))) else: return self.email @@ -179,41 +158,9 @@ def __str__(self): class Meta: # noqa verbose_name = 'Contact' verbose_name_plural = 'Contacts' - # ordering = ['groups__group', '-priority', 'last_name'] ordering = ['last_name'] -@register_snippet -class Group(index.Indexed, ClusterableModel): - slug = models.CharField(_("slug"), max_length=254) - name = models.CharField(_("name"), max_length=254, blank=True) - priority = models.PositiveSmallIntegerField( - _("priority"), blank=True, default=0, validators=[MaxValueValidator(99)], - help_text=_("Priority from 0-99 to determine the sorting order.")) - - panels = [ - FieldPanel('name'), - FieldPanel('priority'), - ] - - search_fields = [ - index.SearchField('name', partial_match=True), - index.SearchField('slug'), - ] - - @property - def members(self): - return [relation.contact for relation in self.contacts.select_related('contact')] - - def __str__(self): - return self.name or self.slug - - class Meta: # noqa - verbose_name = 'Group' - verbose_name_plural = 'Groups' - ordering = ['-priority'] - - class WrittenConsent(models.Model): ref = models.CharField("ID", max_length=10, unique=True) comment = models.TextField("comment", blank=True) diff --git a/mpicms/personal/views.py b/mpicms/personal/views.py index 8ccea1e..312ad8c 100644 --- a/mpicms/personal/views.py +++ b/mpicms/personal/views.py @@ -11,12 +11,12 @@ def get_queryset(self): group_pk = self.request.GET.get('group') position_pk = self.request.GET.get('position') special_function_pk = self.request.GET.get('special_function') - qs = super().get_queryset(); + qs = super().get_queryset() if group_pk is not None and group_pk != "": - qs = qs.filter(groups__group_id=group_pk) + qs = qs.filter(groups=group_pk) if position_pk is not None and position_pk != "": - qs = qs.filter(positions__position_id=position_pk) + qs = qs.filter(positions=position_pk) if special_function_pk is not None and special_function_pk != "": qs = qs.filter(special_functions=special_function_pk) diff --git a/mpicms/personal/wagtail_hooks.py b/mpicms/personal/wagtail_hooks.py index 225e7d0..d9bdf4e 100644 --- a/mpicms/personal/wagtail_hooks.py +++ b/mpicms/personal/wagtail_hooks.py @@ -39,22 +39,21 @@ class ContactAdmin(ModelAdmin): model = Contact menu_label = _('Persons') menu_icon = 'user' - list_display = ['title', 'first_name', 'last_name', 'get_positions', 'email', 'phone', 'room', 'get_groups'] - list_filter = ['groups__group', 'is_active', 'positions__position'] - search_fields = ['title', 'first_name', 'last_name', 'email', 'phone', 'room'] + list_display = ['last_name', 'first_name', 'email', 'phone', 'room', 'get_groups', 'get_positions' ] + list_filter = ['is_active', 'groups'] + search_fields = ['first_name', 'last_name', 'email', 'phone', 'room'] edit_view_class = ContactEditView inspect_view_class = ContactInspectView delete_view_class = ContactDeleteView def get_groups(self, obj): - return ", ".join([group.__str__() for group in Group.objects.filter(contacts__in=obj.groups.all()).distinct()]) + return ", ".join([group.__str__() for group in obj.groups.all()]) get_groups.short_description = _('Groups') def get_positions(self, obj): - return ", ".join([position.__str__() for position in - Position.objects.filter(contacts__in=obj.positions.all()).distinct()]) - get_groups.short_description = _('Positions') + return ", ".join([position.__str__() for position in obj.positions.all()]) + get_positions.short_description = _('Positions') def get_queryset(self, request): qs = self.model._default_manager.include_inactive() @@ -68,7 +67,7 @@ class GroupAdmin(ModelAdmin): model = Group menu_label = _('Groups') menu_icon = 'group' - search_fields = ['name', 'slug'] + search_fields = ['name'] class PositionAdmin(ModelAdmin): diff --git a/mpicms/templates/personal/list.html b/mpicms/templates/personal/list.html index 0cab0cf..0cac3dd 100644 --- a/mpicms/templates/personal/list.html +++ b/mpicms/templates/personal/list.html @@ -89,9 +89,7 @@

{% trans 'Contact List' %}

- - - + @@ -103,14 +101,12 @@

{% trans 'Contact List' %}

{% for contact in object_list %} - - - + - - + + {% endfor %} @@ -120,7 +116,7 @@

{% trans 'Contact List' %}

{% trans 'Title' %}{% trans 'First Name' %}{% trans 'Last Name' %}{% trans 'Name' %} {% trans 'Email' %} {% trans 'Phone' %} {% trans 'Room' %}
{{ contact.title }}{{ contact.first_name }}{{ contact.last_name }}{{ contact.name_and_title }} {{ contact.phone }} {{ contact.room | add_room_links }}{% for contactgroup in contact.groups.all %}{{ contactgroup.group }}
{% endfor %}
{% for contactposition in contact.positions.all %}{{ contactposition.position }}
{% endfor %}
{% for group in contact.groups.all %}{{ group }}
{% endfor %}
{% for position in contact.positions.all %}{{ position }}
{% endfor %}
{% for specialfunction in contact.special_functions.all %}{{ specialfunction.title }}
{% endfor %}