Skip to content
Snippets Groups Projects
Commit e5d6ab1b authored by frekk's avatar frekk
Browse files

validate usernames: preferably unique or null in memberdb/AD

parent 0586e66b
No related merge requests found
......@@ -78,9 +78,9 @@ class MembershipInline(admin.TabularInline):
fk_name = 'member'
class MemberAdmin(admin.ModelAdmin):
list_display = ['first_name', 'last_name', 'display_name', 'username']
list_filter = ['is_guild', 'is_student', MembershipRenewalFilter]
readonly_fields = ['member_updated', 'updated', 'created']
list_display = ['first_name', 'last_name', 'display_name', 'username', 'has_account']
list_filter = ['is_guild', 'is_student', MembershipRenewalFilter, 'has_account']
readonly_fields = ['id', 'has_account', 'email_confirm', 'studnt_confirm', 'guild_confirm', 'member_updated', 'updated', 'created', ]
search_fields = list_display
actions = [download_as_csv]
inlines = [MembershipInline]
......@@ -112,7 +112,7 @@ class MembershipAdmin(admin.ModelAdmin):
"""
list_display = ['membership_info', 'membership_type', 'payment_method', 'approved', 'date_submitted', 'member_actions']
list_display_links = None
list_filter = ['approved', 'payment_method', 'membership_type', 'member__is_student', 'member__is_guild']
list_filter = ['approved', 'payment_method', 'membership_type', 'member__is_student', 'member__is_guild', 'member__has_account']
readonly_fields = ['date_submitted']
radio_fields = {'payment_method': admin.VERTICAL, 'membership_type': admin.VERTICAL}
actions = [refresh_dispense_payment]
......
......@@ -185,6 +185,7 @@ class Member (IncAssocMember):
studnt_confirm = models.BooleanField ('Student status confirmed', null=False, editable=False, default=False)
guild_confirm = models.BooleanField ('Guild status confirmed', null=False, editable=False, default=False)
# stuff which is updated via admin commands
has_account = models.BooleanField ('Has AD account', null=False, editable=False, default=False)
def get_last_renewal(self):
......@@ -193,12 +194,14 @@ class Member (IncAssocMember):
# account info
def get_uid(self):
if self.username is None or self.username == '':
return None
result, uid = subprocess.getstatusoutput(["id", "-u", self.username])
if (result == 0):
return uid;
else:
return None;
def __str__ (self):
if (self.display_name != "%s %s" % (self.first_name, self.last_name)):
name = "%s (%s %s)" % (self.display_name, self.first_name, self.last_name)
......
......@@ -22,6 +22,7 @@ from squarepay.dispense import get_item_price
from .models import Member, Membership, get_membership_choices, make_pending_membership
from .forms import MyModelForm
from .views import MyUpdateView
from .account_backend import validate_username
"""
First step: enter an email address and some details (to fill at least a Member model) to create a pending membership.
......@@ -39,11 +40,6 @@ class RegisterRenewForm(MyModelForm):
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:
......@@ -60,7 +56,6 @@ class RegisterRenewForm(MyModelForm):
m = super().save(commit=False)
if (m.display_name == ""):
m.display_name = "%s %s" % (m.first_name, m.last_name);
m.has_account = m.get_uid() != None
# must save otherwise membership creation will fail
m.save()
......@@ -76,20 +71,28 @@ 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"
help_text="This will be the username you use to access club systems. You may leave this blank to choose a username later",
error_messages={
'invalid': 'Please pick a username with only lowercase letters and numbers'
},
validators=[validate_username]
)
class Meta():
model = Member
fields = ['first_name', 'last_name', 'username', 'phone_number', 'is_student', 'is_guild', 'id_number', 'id_desc', 'email_address']
def clean_username(self):
""" store empty string usernames as NULL in the database to avoid violating unique constraint """
u = self.cleaned_data['username']
return None if u == '' else u
def clean(self):
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.')
self.add_error('email_address', 'Contact address cannot be an UCC address.')
except:
pass
super().clean();
......
......@@ -8,6 +8,7 @@ from django.contrib import messages
from django.views.generic.base import View
from django.views.generic.edit import UpdateView
from django.contrib.auth.mixins import AccessMixin
from django.contrib.auth import logout
from django.utils import timezone
from formtools.wizard.views import SessionWizardView
......@@ -32,12 +33,21 @@ class MemberMiddleware:
if request.user.is_authenticated:
# get the username only when a user is logged in
# note that request.user will still exist even when the user isn't logged in
request.member = Member.objects.filter(username__exact=request.user.username).first()
try:
request.member = Member.objects.get(username=request.user.username)
except Member.MultipleObjectsReturned:
messages.warning(request, "You are logged in, but someone has registered with your username more than once! Please ask an admin to fix this.")
except Member.DoesNotExist:
# the homepage will tell people to register properly, no need to do anything
pass
if request.member is not None:
# clean the member's auth token because they now have a working login
request.member.token = None
request.member.save()
if request.member.login_token is not None:
request.member.login_token = None
request.member.has_account = True
request.member.save()
if request.user.ldap_user is not None:
# copy the LDAP groups so templates can access them
......@@ -136,18 +146,17 @@ class MemberHomeView(MemberAccessMixin, MyUpdateView):
class MemberTokenView(View):
""" allow a user to login using a unique (secure) member token """
def get(self, request, **kwargs):
if not request.user.is_authenticated:
# look up the member using exact match for token and username, and registered < 7 days ago
week_ago = timezone.now() - timedelta(days=7)
# look up the member using exact match for token and username, and registered < 32 days ago
week_ago = timezone.now() - timedelta(days=32)
try:
member = Member.objects.get(
login_token=kwargs['member_token'],
id=kwargs['id'],
created__gte=week_ago
)
except Member.DoesNotExist:
raise Http404()
try:
member = Member.objects.get(
login_token=kwargs['member_token'],
id=kwargs['id'],
created__gte=week_ago
)
except Member.DoesNotExist:
raise Http404()
request.session['member_id'] = member.id
return HttpResponseRedirect(reverse('memberdb:home'))
......@@ -156,6 +165,9 @@ class EmailConfirmView(View):
""" process email confirmations """
def get(self, request, **kwargs):
if request.user.is_authenticated:
logout(request)
week_ago = timezone.now() - timedelta(days=7)
try:
c = TokenConfirmation.objects.get(
......
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment