Commit 676825d4 authored by Luko van der Maas's avatar Luko van der Maas

Merge branch 'feature/admin-fields-search-etc' into 'master'

Add useful features to model admins

See merge request !1286
parents 0a7f54e9 b8c7dddd
...@@ -176,7 +176,7 @@ class MemberGroupMembershipAdmin(TranslatedModelAdmin): ...@@ -176,7 +176,7 @@ class MemberGroupMembershipAdmin(TranslatedModelAdmin):
list_select_related = ('member', 'group',) list_select_related = ('member', 'group',)
search_fields = ('member__first_name', 'member__last_name', search_fields = ('member__first_name', 'member__last_name',
'member__email') 'member__email')
date_hierarchy = 'since'
actions = ('export',) actions = ('export',)
def changelist_view(self, request, extra_context=None): def changelist_view(self, request, extra_context=None):
...@@ -222,4 +222,6 @@ class MemberGroupMembershipAdmin(TranslatedModelAdmin): ...@@ -222,4 +222,6 @@ class MemberGroupMembershipAdmin(TranslatedModelAdmin):
@admin.register(models.Mentorship) @admin.register(models.Mentorship)
class MentorshipAdmin(admin.ModelAdmin): class MentorshipAdmin(admin.ModelAdmin):
"""Manage the mentorships""" """Manage the mentorships"""
list_select_related = ('member',) autocomplete_fields = ('member',)
search_fields = ('member__first_name', 'member__last_name')
list_filter = ('year',)
...@@ -6,7 +6,7 @@ import datetime ...@@ -6,7 +6,7 @@ import datetime
from django.contrib import admin, messages from django.contrib import admin, messages
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.db.models import Q from django.db.models import Q, Count
from django.http import HttpResponse from django.http import HttpResponse
from django.utils import timezone from django.utils import timezone
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
...@@ -87,6 +87,29 @@ class AgeListFilter(admin.SimpleListFilter): ...@@ -87,6 +87,29 @@ class AgeListFilter(admin.SimpleListFilter):
return queryset return queryset
class HasPermissionsFilter(admin.SimpleListFilter):
title = _('Has individual permissions')
parameter_name = 'permissions'
def lookups(self, request, model_admin):
return (
('yes', _('Yes')),
('no', _('No')),
)
def queryset(self, request, queryset):
if not self.value():
return queryset
queryset = queryset.annotate(
permission_count=Count('user_permissions'))
if self.value() == 'yes':
return queryset.filter(permission_count__gt=0)
return queryset.filter(permission_count=0)
class UserAdmin(BaseUserAdmin): class UserAdmin(BaseUserAdmin):
change_list_template = 'admin/members/change_list.html' change_list_template = 'admin/members/change_list.html'
form = forms.UserChangeForm form = forms.UserChangeForm
...@@ -98,10 +121,12 @@ class UserAdmin(BaseUserAdmin): ...@@ -98,10 +121,12 @@ class UserAdmin(BaseUserAdmin):
inlines = (ProfileInline, MembershipInline,) inlines = (ProfileInline, MembershipInline,)
list_filter = (MembershipTypeListFilter, list_filter = (MembershipTypeListFilter,
'is_superuser', 'is_superuser',
HasPermissionsFilter,
'groups',
AgeListFilter, AgeListFilter,
'profile__event_permissions', 'profile__event_permissions',
'profile__starting_year', 'profile__starting_year',
'profile__auto_renew') 'profile__auto_renew',)
add_fieldsets = ( add_fieldsets = (
(None, { (None, {
......
This diff was suppressed by a .gitattributes entry.
...@@ -7,8 +7,8 @@ msgid "" ...@@ -7,8 +7,8 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: \n" "Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-04-09 21:17+0200\n" "POT-Creation-Date: 2019-06-07 16:35+0200\n"
"PO-Revision-Date: 2019-04-09 21:18+0200\n" "PO-Revision-Date: 2019-06-07 16:37+0200\n"
"Last-Translator: Thom Wiggers <thom@thomwiggers.nl>\n" "Last-Translator: Thom Wiggers <thom@thomwiggers.nl>\n"
"Language-Team: \n" "Language-Team: \n"
"Language: nl\n" "Language: nl\n"
...@@ -42,6 +42,18 @@ msgstr "< 18" ...@@ -42,6 +42,18 @@ msgstr "< 18"
msgid "Unknown" msgid "Unknown"
msgstr "Onbekend" msgstr "Onbekend"
#: admin.py
msgid "Has individual permissions"
msgstr "Heeft individuele permissies"
#: admin.py
msgid "Yes"
msgstr "Ja"
#: admin.py
msgid "No"
msgstr "Nee"
#: admin.py forms.py #: admin.py forms.py
msgid "First name" msgid "First name"
msgstr "Voornaam" msgstr "Voornaam"
...@@ -148,10 +160,6 @@ msgstr "Verifieer je nieuwe e-mailadres" ...@@ -148,10 +160,6 @@ msgstr "Verifieer je nieuwe e-mailadres"
msgid "Your email address has been changed" msgid "Your email address has been changed"
msgstr "Je e-mailadres is aangepast" msgstr "Je e-mailadres is aangepast"
#: forms.py
msgid "Please enter a bank account"
msgstr "Voer een bankrekening in"
#: forms.py #: forms.py
msgid "Send welcome email" msgid "Send welcome email"
msgstr "Stuur welkomste-mails" msgstr "Stuur welkomste-mails"
...@@ -164,10 +172,6 @@ msgstr "Deze e-mail zal het gegenereerde wachtwoord bevatten" ...@@ -164,10 +172,6 @@ msgstr "Deze e-mail zal het gegenereerde wachtwoord bevatten"
msgid "Email address" msgid "Email address"
msgstr "E-mailadres" msgstr "E-mailadres"
#: models.py
msgid "Access the Sentry backend"
msgstr "Toegang tot the Sentry backend"
#: models.py #: models.py
msgid "Access NextCloud as admin" msgid "Access NextCloud as admin"
msgstr "Toegang tot NextCloud als admin" msgstr "Toegang tot NextCloud als admin"
...@@ -357,33 +361,16 @@ msgid "Receive the Thalia Newsletter" ...@@ -357,33 +361,16 @@ msgid "Receive the Thalia Newsletter"
msgstr "Ontvang de Thalia nieuwsbrief" msgstr "Ontvang de Thalia nieuwsbrief"
#: models.py #: models.py
msgid "" msgid "Yes, enable auto renewal."
"Yes, I want Thalia to take the membership fees from my bank account through " msgstr "Ja, verleng automatisch."
"direct debit for each year."
msgstr ""
"Ja, ik wil dat Thalia verschuldigde lidmaatschapsgelden elk jaar van mijn "
"bankrekening afschrijft."
#: models.py #: models.py
msgid "No, I will pay the contribution myself" msgid "No, manual renewal required."
msgstr "Nee, ik zal de contributie zelf betalen" msgstr "Nee, handmatige verlenging vereist."
#: models.py #: models.py
msgid "Direct debit" msgid "Automatically renew membership"
msgstr "Automatische afschijving" msgstr "Lidmaatschap automatisch verlengen"
#: models.py
msgid "Each year, have Thalia take the membership fees from my bank account"
msgstr ""
"Laat Thalia elk jaar het lidmaatschapsgeld van mijn bankrekening afschrijven"
#: models.py
msgid "Bank account"
msgstr "Bankrekening"
#: models.py
msgid "Bank account for direct debit"
msgstr "Bankrekening voor automatische afschrijving"
#: models.py #: models.py
msgid "Display name" msgid "Display name"
...@@ -503,64 +490,18 @@ msgstr "Ouder" ...@@ -503,64 +490,18 @@ msgstr "Ouder"
msgid "Export IBANs for Direct Debit" msgid "Export IBANs for Direct Debit"
msgstr "Exporteer IBANs voor automatische incasso" msgstr "Exporteer IBANs voor automatische incasso"
#: templates/members/account.html templates/members/edit_profile.html #: templates/members/edit_profile.html templates/members/user.html
#: templates/members/email_change.html msgid "edit profile"
msgstr "profiel bewerken"
#: templates/members/edit_profile.html templates/members/email_change.html
#: templates/members/email_change_confirmed.html #: templates/members/email_change_confirmed.html
#: templates/members/email_change_requested.html #: templates/members/email_change_requested.html
#: templates/members/email_change_verified.html templates/members/index.html #: templates/members/email_change_verified.html templates/members/index.html
#: templates/members/profile.html #: templates/members/profile.html templates/members/user.html
msgid "members" msgid "members"
msgstr "leden" msgstr "leden"
#: templates/members/account.html
msgid "Account"
msgstr "Account"
#: templates/members/account.html
#, python-format
msgid "You’re currently logged in as <strong>%(user)s</strong>"
msgstr "U bent momenteel ingelogd als <strong>%(user)s</strong>"
#: templates/members/account.html
msgid "show public profile"
msgstr "bekijk publieke profielpagina"
#: templates/members/account.html
msgid "Take a look at your own profile."
msgstr "Bekijk je eigen profielpagina."
#: templates/members/account.html
msgid "manage membership"
msgstr "lidmaatschap beheren"
#: templates/members/account.html
msgid "Get information about your membership or renew it."
msgstr "Bekijk je lidmaatschap of vernieuw deze indien nodig."
#: templates/members/account.html templates/members/edit_profile.html
msgid "edit profile"
msgstr "profiel bewerken"
#: templates/members/account.html
msgid "Edit your profile and avatar."
msgstr "Bewerk je profiel en profielafbeelding."
#: templates/members/account.html
msgid "change password"
msgstr "wachtwoord wijzigen"
#: templates/members/account.html
msgid "Change your accounts' password."
msgstr "Wijzig het wachtwoord van je account."
#: templates/members/account.html
msgid "logout"
msgstr "uitloggen"
#: templates/members/account.html
msgid "Leave the restricted area of the website."
msgstr "Verlaat het beveiligde gedeelte van de website."
#: templates/members/edit_profile.html #: templates/members/edit_profile.html
msgid "Your profile has been updated successfully." msgid "Your profile has been updated successfully."
msgstr "Je profiel is succesvol opgeslagen." msgstr "Je profiel is succesvol opgeslagen."
...@@ -1048,6 +989,59 @@ msgstr "Statistieken" ...@@ -1048,6 +989,59 @@ msgstr "Statistieken"
msgid "Total amount of Thalia members" msgid "Total amount of Thalia members"
msgstr "Totaal aantal Thalialeden" msgstr "Totaal aantal Thalialeden"
#: templates/members/user.html
msgid "Account"
msgstr "Account"
#: templates/members/user.html
#, python-format
msgid "You’re currently logged in as <strong>%(user)s</strong>"
msgstr "U bent momenteel ingelogd als <strong>%(user)s</strong>"
#: templates/members/user.html
msgid "show public profile"
msgstr "bekijk publieke profielpagina"
#: templates/members/user.html
msgid "Take a look at your own profile."
msgstr "Bekijk je eigen profielpagina."
#: templates/members/user.html
msgid "manage membership"
msgstr "lidmaatschap beheren"
#: templates/members/user.html
msgid "Get information about your membership or renew it."
msgstr "Bekijk je lidmaatschap of vernieuw deze indien nodig."
#: templates/members/user.html
msgid "Edit your profile and avatar."
msgstr "Bewerk je profiel en profielafbeelding."
#: templates/members/user.html
msgid "manage bank account(s)"
msgstr "bankrekening(en) beheren"
#: templates/members/user.html
msgid "Change the financial information known to Thalia."
msgstr "Verander de financiële informatie bekend bij Thalia."
#: templates/members/user.html
msgid "change password"
msgstr "wachtwoord wijzigen"
#: templates/members/user.html
msgid "Change your accounts' password."
msgstr "Wijzig het wachtwoord van je account."
#: templates/members/user.html
msgid "logout"
msgstr "uitloggen"
#: templates/members/user.html
msgid "Leave the restricted area of the website."
msgstr "Verlaat het beveiligde gedeelte van de website."
#: views.py #: views.py
msgid "Unknown membership history" msgid "Unknown membership history"
msgstr "Onbekende lidmaatschap geschiedenis" msgstr "Onbekende lidmaatschap geschiedenis"
......
...@@ -24,7 +24,7 @@ class NewsletterEventInline(NewsletterItemInline): ...@@ -24,7 +24,7 @@ class NewsletterEventInline(NewsletterItemInline):
class NewsletterAdmin(TranslatedModelAdmin): class NewsletterAdmin(TranslatedModelAdmin):
"""Manage the newsletters""" """Manage the newsletters"""
#: available fields in the admin overview list #: available fields in the admin overview list
list_display = ('title', 'date', 'sent',) list_display = ('title', 'date', 'send_date', 'sent',)
#: available inlines in the admin change form #: available inlines in the admin change form
inlines = (NewsletterItemInline, NewsletterEventInline,) inlines = (NewsletterItemInline, NewsletterEventInline,)
#: available fieldsets in the admin change form #: available fieldsets in the admin change form
...@@ -35,6 +35,10 @@ class NewsletterAdmin(TranslatedModelAdmin): ...@@ -35,6 +35,10 @@ class NewsletterAdmin(TranslatedModelAdmin):
) )
}), }),
) )
#: available fields for searching
search_fields = ('title', 'description')
#: field to use for date filtering
date_hierarchy = 'date'
def change_view(self, request, object_id, form_url=''): def change_view(self, request, object_id, form_url=''):
""" """
......
...@@ -17,6 +17,7 @@ class PartnerAdmin(admin.ModelAdmin): ...@@ -17,6 +17,7 @@ class PartnerAdmin(admin.ModelAdmin):
prepopulated_fields = {"slug": ("name",)} prepopulated_fields = {"slug": ("name",)}
list_display = ('name', 'is_active', 'is_main_partner',) list_display = ('name', 'is_active', 'is_main_partner',)
search_fields = ('name', 'city')
inlines = (PartnerImageInline,) inlines = (PartnerImageInline,)
fieldsets = ( fieldsets = (
...@@ -46,7 +47,7 @@ class VacancyAdmin(admin.ModelAdmin): ...@@ -46,7 +47,7 @@ class VacancyAdmin(admin.ModelAdmin):
"""Class to show vacancies in the admin.""" """Class to show vacancies in the admin."""
list_display = ('title', 'partner', 'company_name', 'expiration_date') list_display = ('title', 'partner', 'company_name', 'expiration_date')
search_fields = ('title', 'partner__name', 'company_name',)
fieldsets = ( fieldsets = (
(None, { (None, {
'fields': ('title', 'description', 'link',) 'fields': ('title', 'description', 'link',)
...@@ -70,8 +71,9 @@ class VacancyAdmin(admin.ModelAdmin): ...@@ -70,8 +71,9 @@ class VacancyAdmin(admin.ModelAdmin):
class PartnerEventAdmin(TranslatedModelAdmin): class PartnerEventAdmin(TranslatedModelAdmin):
"""Class to show partner events in the admin.""" """Class to show partner events in the admin."""
fields = ['partner', 'other_partner', 'title', 'description', 'location', fields = ('partner', 'other_partner', 'title', 'description', 'location',
'start', 'end', 'url', 'published'] 'start', 'end', 'url', 'published')
list_display = ('title', 'start', 'end', list_display = ('title', 'start', 'end',
'partner', 'published') 'partner', 'published')
list_filter = ('start', 'published') list_filter = ('start', 'published')
search_fields = ('title', 'partner__name')
...@@ -224,13 +224,14 @@ class BankAccountAdmin(admin.ModelAdmin): ...@@ -224,13 +224,14 @@ class BankAccountAdmin(admin.ModelAdmin):
list_display = ('iban', 'owner_link', 'last_used', list_display = ('iban', 'owner_link', 'last_used',
'valid_from', 'valid_until') 'valid_from', 'valid_until')
list_filter = (ValidAccountFilter,) list_filter = (ValidAccountFilter, 'owner__profile__auto_renew')
fields = ('created_at', 'last_used', 'owner', 'iban', 'bic', 'initials', fields = ('created_at', 'last_used', 'owner', 'iban', 'bic', 'initials',
'last_name', 'mandate_no', 'valid_from', 'valid_until', 'last_name', 'mandate_no', 'valid_from', 'valid_until',
'signature') 'signature')
readonly_fields = ('created_at',) readonly_fields = ('created_at',)
search_fields = ('owner__username', 'owner__first_name', search_fields = ('owner__username', 'owner__first_name',
'owner__last_name', 'iban') 'owner__last_name', 'iban')
autocomplete_fields = ('owner',)
actions = ['set_last_used'] actions = ['set_last_used']
form = BankAccountAdminForm form = BankAccountAdminForm
......
...@@ -8,6 +8,7 @@ from django.contrib import admin ...@@ -8,6 +8,7 @@ from django.contrib import admin
from django.contrib import messages from django.contrib import messages
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.core.files.base import File from django.core.files.base import File
from django.db.models import Count
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from utils.translation import TranslatedModelAdmin from utils.translation import TranslatedModelAdmin
...@@ -82,7 +83,7 @@ def save_photo(request, archive_file, photo, album): ...@@ -82,7 +83,7 @@ def save_photo(request, archive_file, photo, album):
class AlbumAdmin(TranslatedModelAdmin): class AlbumAdmin(TranslatedModelAdmin):
list_display = ('title', 'date', 'hidden', 'shareable') list_display = ('title', 'date', 'num_photos', 'hidden', 'shareable')
fields = ('title', 'slug', 'date', 'hidden', 'shareable', 'album_archive', fields = ('title', 'slug', 'date', 'hidden', 'shareable', 'album_archive',
'_cover') '_cover')
search_fields = ('title', 'date') search_fields = ('title', 'date')
...@@ -91,6 +92,15 @@ class AlbumAdmin(TranslatedModelAdmin): ...@@ -91,6 +92,15 @@ class AlbumAdmin(TranslatedModelAdmin):
prepopulated_fields = {'slug': ('date', 'title_en',)} prepopulated_fields = {'slug': ('date', 'title_en',)}
form = AlbumForm form = AlbumForm
def get_queryset(self, request):
return Album.objects.annotate(photos_count=Count('photo'))
def num_photos(self, obj):
"""Pretty-print the number of photos"""
return obj.photos_count
num_photos.short_description = _('Number of photos')
num_photos.admin_order_field = 'photos_count'
def save_model(self, request, obj, form, change): def save_model(self, request, obj, form, change):
obj.save() obj.save()
......
from django.conf import settings
from django.contrib import admin from django.contrib import admin
from django.core.exceptions import PermissionDenied from django.core.exceptions import PermissionDenied
from django.urls import reverse, path from django.urls import reverse, path
...@@ -16,12 +17,21 @@ from events.services import is_organiser ...@@ -16,12 +17,21 @@ from events.services import is_organiser
class ProductAdmin(admin.ModelAdmin): class ProductAdmin(admin.ModelAdmin):
list_display = ('name', 'price', 'available') list_display = ('name', 'price', 'available')
list_filter = ('available', 'restricted') list_filter = ('available', 'restricted')
search_fields = ('name',)
@admin.register(PizzaEvent) @admin.register(PizzaEvent)
class PizzaEventAdmin(admin.ModelAdmin): class PizzaEventAdmin(admin.ModelAdmin):
list_display = ('title', 'orders') list_display = ('title', 'start', 'end', 'notification_enabled', 'orders')
date_hierarchy = 'start'
exclude = ('end_reminder',) exclude = ('end_reminder',)
search_fields = [f'event__title_{l[0]}' for l in settings.LANGUAGES]
def notification_enabled(self, obj):
return obj.send_notification
notification_enabled.short_description = _('reminder')
notification_enabled.admin_order_field = 'send_notification'
notification_enabled.boolean = True
def orders(self, obj): def orders(self, obj):
url = reverse('admin:pizzas_pizzaevent_details', kwargs={'pk': obj.pk}) url = reverse('admin:pizzas_pizzaevent_details', kwargs={'pk': obj.pk})
......
...@@ -25,7 +25,7 @@ class PizzaOrderSummary(TemplateView): ...@@ -25,7 +25,7 @@ class PizzaOrderSummary(TemplateView):
'is_popup': False, 'is_popup': False,
'save_as': False, 'save_as': False,
'save_on_top': False, 'save_on_top': False,
'title': capfirst(_('pizza order summary')), 'title': capfirst(_('order summary')),
'original': capfirst(_('summary')), 'original': capfirst(_('summary')),
'pizza_event': event 'pizza_event': event
}) })
...@@ -74,7 +74,7 @@ class PizzaOrderDetails(TemplateView): ...@@ -74,7 +74,7 @@ class PizzaOrderDetails(TemplateView):
'is_popup': False, 'is_popup': False,
'save_as': False, 'save_as': False,
'save_on_top': False, 'save_on_top': False,
'title': capfirst(_('pizza order overview')), 'title': capfirst(_('order overview')),
'original': str(event), 'original': str(event),
'pizza_event': event 'pizza_event': event
}) })
......
This diff was suppressed by a .gitattributes entry.
...@@ -7,8 +7,8 @@ msgid "" ...@@ -7,8 +7,8 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: \n" "Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-03-02 16:51+0100\n" "POT-Creation-Date: 2019-06-07 16:41+0200\n"
"PO-Revision-Date: 2019-03-02 16:51+0100\n" "PO-Revision-Date: 2019-06-07 16:41+0200\n"
"Last-Translator: Thom Wiggers <thom@thomwiggers.nl>\n" "Last-Translator: Thom Wiggers <thom@thomwiggers.nl>\n"
"Language-Team: \n" "Language-Team: \n"
"Language: nl\n" "Language: nl\n"
...@@ -16,12 +16,27 @@ msgstr "" ...@@ -16,12 +16,27 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Generator: Poedit 2.2.1\n" "X-Generator: Poedit 2.2.3\n"
#: admin.py #: admin.py
#, python-brace-format msgid "reminder"
msgid "<strong><a href=\"{link}\">Orders</a></strong>" msgstr "herinnering"
msgstr "<strong><a href=\"{link}\">Bestellingen</a></strong>"
#: admin.py templates/pizzas/admin/summary.html
msgid "Orders"
msgstr "Bestellingen"
#: admin_views.py
msgid "order summary"
msgstr "bestellingssamenvatting"
#: admin_views.py
msgid "summary"
msgstr "samenvatting"
#: admin_views.py
msgid "order overview"
msgstr "bestellingsoverzicht"
#: api/serializers.py models.py #: api/serializers.py models.py
msgid "Either specify a member or a name" msgid "Either specify a member or a name"
...@@ -67,51 +82,95 @@ msgstr "" ...@@ -67,51 +82,95 @@ msgstr ""
msgid "Order restricted products" msgid "Order restricted products"
msgstr "Bestel beperkte producten" msgstr "Bestel beperkte producten"
#: models.py
msgid "name"
msgstr "naam"
#: models.py #: models.py
msgid "Use this for non-members" msgid "Use this for non-members"
msgstr "Vul dit in voor niet-leden" msgstr "Vul dit in voor niet-leden"
#: models.py templates/pizzas/admin/orders.html
msgid "payment"
msgstr "betaling"
#: models.py templates/pizzas/admin/orders.html
#: templates/pizzas/admin/summary.html
msgid "product"
msgstr "product"
#: models.py
msgid "event"
msgstr "evenement"
#: models.py #: models.py
#, python-brace-format #, python-brace-format
msgid "Order by {member_name}: {product}" msgid "Order by {member_name}: {product}"