admin.py 5.43 KB
Newer Older
1
2
3
4
5
6
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import render
from django.urls import path, reverse
from django.utils.html import format_html
from django.utils.safestring import mark_safe
from django.template.loader import render_to_string
frekk's avatar
frekk committed
7

8
from gms import admin
frekk's avatar
frekk committed
9
10

from memberdb.models import Member, IncAssocMember, Membership
11
12
from memberdb.actions import download_as_csv
from memberdb.approve import MembershipApprovalForm, MembershipApprovalAdminView
Zack Wong's avatar
Zack Wong committed
13
from memberdb.account import AccountForm, AccountView
14
15

def get_model_url(pk, model_name):
Zack Wong's avatar
Zack Wong committed
16
	return reverse('admin:memberdb_%s_change' % model_name, args=[pk])
17

18
19
20
21
"""
helper mixin to make the admin page display only "View" rather than "Change" or "Add"
"""
class ReadOnlyModelAdmin(admin.ModelAdmin):
Zack Wong's avatar
Zack Wong committed
22
23
24
25
26
	def has_add_permission(self, request):
		return False
		
	def has_delete_permission(self, request, obj=None):
		return True
frekk's avatar
frekk committed
27

Zack Wong's avatar
Zack Wong committed
28
29
	def has_change_permission(self, request, obj=None):
		return False
frekk's avatar
frekk committed
30

31
32
33
"""
Define the administrative interface for viewing member details required under the Incorporations Act
"""
34
class IAMemberAdmin(ReadOnlyModelAdmin):
Zack Wong's avatar
Zack Wong committed
35
36
37
38
39
40
41
42
43
44
45
	readonly_fields = ['__str__', 'updated', 'created']
	fields = ['first_name', 'last_name', 'email_address', 'updated', 'created']
	search_fields = ['first_name', 'last_name', 'email_address']
	list_display = readonly_fields
	actions = [download_as_csv]

	# add a "go to member" URL into the template context data
	def change_view(self, request, object_id, form_url='', extra_context={}):
		extra_context['member_edit_url'] = get_model_url(object_id, 'member')
		return super().change_view(request, object_id, form_url, extra_context=extra_context)
		
46
class MembershipInline(admin.TabularInline):
Zack Wong's avatar
Zack Wong committed
47
48
49
50
51
	model = Membership
	readonly_fields = ['member', 'date_submitted']
	radio_fields = {'payment_method': admin.VERTICAL, 'membership_type': admin.VERTICAL}
	extra = 0
	fk_name = 'member'
52

53
class MemberAdmin(admin.ModelAdmin):
Zack Wong's avatar
Zack Wong committed
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
	list_display = ['first_name', 'last_name', 'display_name', 'username']
	list_filter = ['is_guild', 'is_student']
	readonly_fields = ['member_updated', 'updated', 'created']
	search_fields = list_display
	actions = [download_as_csv]
	inlines = [MembershipInline]
	
	# add custom URLs to this model in the admin site
	def get_urls(self):
		urls = super().get_urls()
		custom_urls = [
			path('<object_id>/create/', self.admin_site.admin_view(self.process_account), name='create-account'),
		]
		return custom_urls + urls



	# add a "go to member" URL into the template context data
	def change_view(self, request, object_id, form_url='', extra_context={}):
		extra_context['incassocmember_url'] = get_model_url(object_id, 'incassocmember')
		return super().change_view(request, object_id, form_url, extra_context=extra_context)

	def process_account(self, request, *args, **kwargs):
		return AccountView.as_view(admin=self)(request, *args, **kwargs)


frekk's avatar
frekk committed
80

81
82
83
"""
Define the admin page for viewing normal Member records (all details included) and approving them
"""
84
class MembershipAdmin(admin.ModelAdmin):
Zack Wong's avatar
Zack Wong committed
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
	list_display = ['membership_info', 'membership_type', 'payment_method', 'approved', 'date_submitted', 'member_actions', ]
	list_display_links = None
	list_filter = ['approved']
	readonly_fields = ['date_submitted']
	radio_fields = {'payment_method': admin.VERTICAL, 'membership_type': admin.VERTICAL}

	# make the admin page queryset preload the parent records (Member) 
	def get_queryset(self, request):
		qs = super().get_queryset(request)
		return qs.select_related('member')

	# add custom URLs to this model in the admin site
	def get_urls(self):
		urls = super().get_urls()
		custom_urls = [
			path('<object_id>/approve/', self.admin_site.admin_view(self.process_approve), name='membership-approve'),
		]
		return custom_urls + urls

	# display a short summary of relevant member / membership info for pending memberships
	def membership_info(self, ms):
		context = {
			'ms': ms,
			'member': ms.member,
			'member_url': get_model_url(ms.member.pk, 'member'),
		}
		html = render_to_string('admin/memberdb/membership_summary.html', context)
		return mark_safe(html)
	
	membership_info.short_description = 'Membership info'
	membership_info.allow_tags = True

	# called per record, returns HTML to display under the "Actions" column
	def member_actions(self, ms):
		context = {
			'ms': ms,
			'member': ms.member,
			'member_url': get_model_url(ms.member.pk, 'member'),
			'member_approve': reverse('admin:membership-approve', args=[ms.pk]),
			'create_account': reverse('admin:create-account', args=[ms.member.pk])
		}
		html = render_to_string('admin/memberdb/membership_actions.html', context)
		return mark_safe(html)

	member_actions.short_description = 'Actions'
	member_actions.allow_tags = True

	def process_approve(self, request, *args, **kwargs):
		return MembershipApprovalAdminView.as_view(admin=self)(request, *args, **kwargs)

	"""
frekk's avatar
frekk committed
136
137
138
Register multiple ModelAdmins per model. See https://stackoverflow.com/questions/2223375/multiple-modeladmins-views-for-same-model-in-django-admin/2228821
"""
class ProxyMembership(Membership):
Zack Wong's avatar
Zack Wong committed
139
140
	class Meta:
		proxy = True
frekk's avatar
frekk committed
141
142

class PendingMembershipAdmin(MembershipAdmin):
Zack Wong's avatar
Zack Wong committed
143
144
	def get_queryset(self, request):
		return self.model.objects.filter(approved__exact=False)
frekk's avatar
frekk committed
145
146
147
148

# Register the other models with either default admin site pages or with optional customisations
admin.site.register(Member, MemberAdmin)
admin.site.register(IncAssocMember, IAMemberAdmin)
frekk's avatar
frekk committed
149
150
admin.site.register(Membership, MembershipAdmin)
#admin.site.register(ProxyMembership, PendingMembershipAdmin)