register.py 6.71 KB
Newer Older
1
2
3
4
"""
This file implements the member-facing registration workflow. See ../../README.md
"""

5
from django.http import HttpResponseRedirect
6
7
from django.shortcuts import render
from django.urls import reverse
frekk's avatar
frekk committed
8
from django.contrib.auth.mixins import LoginRequiredMixin
9
from django.utils.safestring import mark_safe
10
from django.utils import timezone
frekk's avatar
frekk committed
11
from django.contrib import messages
12
13
from django import forms

14
15
16
from squarepay.models import MembershipPayment
from squarepay.dispense import get_item_price

17
from .models import Member, Membership, get_membership_choices, make_pending_membership, MEMBERSHIP_TYPES
frekk's avatar
frekk committed
18
19
from .forms import MyModelForm
from .views import MyUpdateView
20
21
22
23
24
25

"""
First step: enter an email address and some details (to fill at least a Member model) to create a pending membership.
see https://docs.djangoproject.com/en/2.1/ref/models/fields/#error-messages
and https://docs.djangoproject.com/en/2.1/ref/forms/fields/#error-messages
"""
Zack Wong's avatar
Zack Wong committed
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
class RegisterRenewForm(MyModelForm):
	confirm_email   = forms.EmailField(label='Confirm your email address', required=False)
	agree_tnc       = forms.BooleanField(label='I agree to the terms & conditions', required=True, help_text=mark_safe(
		"You agree to abide by the UCC Constitution, rulings of the UCC Committee, UCC and "
		"UWA’s Network Usage Guidelines and that you will be subscribed to the UCC Mailing List. <br>"
		'<b>Policies can be found <a href="https://www.ucc.asn.au/infobase/policies.ucc">here</a>.</b>'))
	membership_type = forms.ChoiceField(label='Select your membership type', required=True, choices=get_membership_choices(is_renew=False))

	class Meta:
		model = Member
		fields = ['first_name', 'last_name', 'phone_number', 'is_student', 'is_guild', 'id_number', 'id_desc', 'email_address']
		error_messages = {
			'username': {
				'invalid': 'Please pick a username with only lowercase letters and numbers'
			}
		}

	def clean(self):
		try:
			if (self['email_address'].value() != self['confirm_email'].value()):
				self.add_error('email_address', 'Email addresses must match.')
Zack Wong's avatar
Zack Wong committed
47
			if (self['email_address'].value().lower().split('@')[1] in ["ucc.asn.au", "ucc.gu.uwa.edu.au"]):
48
				self.add_error('email_address', 'Contact address cannot be an UCC address.')
Zack Wong's avatar
Zack Wong committed
49
50
51
52
53
54
55
56
57
58
59
60
61
		except:
			pass
		super().clean();

	def save(self, commit=True):
		# get the Member model instance (ie. a record in the Members table) based on submitted form data
		m = super().save(commit=False)
		if (m.display_name == ""):
			m.display_name = "%s %s" % (m.first_name, m.last_name);
		# must save otherwise membership creation will fail
		m.save()

		ms = make_pending_membership(m)
62
		ms.membership_type = self.cleaned_data['membership_type']
Zack Wong's avatar
Zack Wong committed
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107

		if (commit):
			ms.save();
		return m, ms

class RegisterForm(RegisterRenewForm):
	username = forms.CharField(
		label='Preferred Username (optional)',
		required=False,
		help_text="This will be the username you use to access club systems. You may leave this blank to choose a username later"
	)

	class Meta():
		model = Member
		fields = ['first_name', 'last_name', 'username', 'phone_number', 'is_student', 'is_guild', 'id_number', 'id_desc', 'email_address']


	def clean(self):
		try:
			if (self['email_address'].value() != self['confirm_email'].value()):
				self.add_error('email_address', 'Email addresses must match.')
			if (self['email_address'].value().split('@')[1] in ["ucc.asn.au", "ucc.gu.uwa.edu.au"]):
					self.add_error('email_address', 'Contact address cannot be an UCC address.')
		except:
			pass
		super().clean();


class RenewForm(RegisterRenewForm):
	confirm_email = None
	membership_type = forms.ChoiceField(label='Select your membership type', required=True, choices=get_membership_choices(is_renew=True))

	class Meta:
		model = Member
		fields = ['first_name', 'last_name', 'phone_number', 'is_student', 'is_guild', 'id_number', 'id_desc', 'email_address']
		exclude = ['username']

	def save(self, commit=True):
		m, ms = super().save(commit=False)
		m.username = self.request.user.username
		m.has_account = m.get_uid() != None
		if (commit):
			m.save()
			ms.save()
		return m, ms
frekk's avatar
frekk committed
108

109
"""
frekk's avatar
frekk committed
110
simple FormView which displays registration form and handles template rendering & form submission
111
"""
frekk's avatar
frekk committed
112
class RegisterView(MyUpdateView):
Zack Wong's avatar
Zack Wong committed
113
114
115
116
	template_name = 'register.html'
	form_class = RegisterForm
	model = Member

117
118
119
120
121
122
	def get_context_data(self, **kwargs):
		""" update view context with current renewal year """
		context = super().get_context_data(**kwargs)
		context['year'] = timezone.now().year
		return context

Zack Wong's avatar
Zack Wong committed
123
	def form_valid(self, form):
124
125
126
127
		"""
		called when valid form data has been POSTed
		invalid form data simply redisplays the form with validation errors
		"""
Zack Wong's avatar
Zack Wong committed
128
129
130
131
132
133
		# save the member data and get the Member instance
		m, ms = form.save()
		messages.success(self.request, 'Your registration has been submitted.')

		# don't set the member session info - user can click on the link
		#self.request.session['member_id'] = m.id
134
135
136
137
		if self.request.user.is_staff:
			return HttpResponseRedirect(reverse("admin:membership-approve",args=[ms.pk]))
		else:
			return thanks_view(self.request, m, ms)
138
139

def thanks_view(request, member, ms):
Zack Wong's avatar
Zack Wong committed
140
141
142
143
	""" display a thankyou page after registration is completed """
	context = {
		'member': member,
		'ms': ms,
Zack Wong's avatar
Zack Wong committed
144
		'login_url': reverse('memberdb:login_member', kwargs={'id' : member.id, 'member_token': member.login_token}),
Zack Wong's avatar
Zack Wong committed
145
146
	}
	return render(request, 'thanks.html', context)
147

148
class RenewView(LoginRequiredMixin, RegisterView):
Zack Wong's avatar
Zack Wong committed
149
150
151
152
153
	template_name = 'renew.html'
	form_class = RenewForm
	model = Member

	def get_object(self):
154
		""" try to get a pending renewal for this year (to edit & resubmit) otherwise create a new one """
Zack Wong's avatar
Zack Wong committed
155
		u = self.request.user
156
		m = self.request.member
Zack Wong's avatar
Zack Wong committed
157

158
159
160
161
162
163
164
165
		if m is None:
			# this member is not in the DB yet - make a new Member object and prefill some data
			m = Member(username=u.username)
			m.first_name = u.first_name
			m.last_name = u.last_name
			m.email_address = u.email
			m.login_token = None # renewing members won't need this, make sure it is null for security
		return m
Zack Wong's avatar
Zack Wong committed
166
167
168

	def get_context_data(self, **kwargs):
		context = super().get_context_data(**kwargs)
169
170
171
172
173
174
175
176
177
178
		last_renewal = self.object.get_last_renewal()

		# renew.html says whether a record exists in the DB or not
		context['is_new'] = self.request.member is None

		# let the template check if user has already renewed this year so it displays a warning
		if last_renewal is not None:
			context['last_renewal'] = last_renewal.date_submitted.year
			context['memberships'] = [last_renewal]

Zack Wong's avatar
Zack Wong committed
179
180
181
182
183
		return context

	def form_valid(self, form):
		m, ms = form.save()
		messages.success(self.request, 'Your membership renewal has been submitted.')
184
185
186
187

		# always redirect to member home on renewal - you can't renew for someone else, and it
		# is confusing if you get redirected to the admin site
		return HttpResponseRedirect(reverse("memberdb:home"))