Commit ad20e053 authored by Zack Wong's avatar Zack Wong
Browse files

added account creation form

parent 0f7c7dac
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import render
from django.urls import reverse
from django.utils import timezone
from django import forms
from .models import Member
from .forms import MyModelForm
from .views import MyUpdateView
from memberdb.account_backend import validate_username
class AccountForm(MyModelForm):
# form fields
user= forms.SlugField(
validators=[validate_username]
)
forward_email = forms.EmailField(
label='Forwarding address(optional)',
required=False,
help_text="Your club email will be forwarded to this address. Leave blank if email forwarding is not required"
)
password = forms.CharField(
min_length=10,
max_length=127,
widget=forms.PasswordInput,
strip=False,
help_text="Password must be between 10 and 127 characters long")
confirm_password = forms.CharField(
min_length=10,
max_length=127,
widget=forms.PasswordInput,
strip=False,
)
class Meta:
model = Member
fields = ['first_name']
error_messages = {
'username': {
'unique': 'This username is already taken, please pick another one.',
'invalid': 'Please pick a username with only lowercase letters and numbers'
}
}
def clean(self):
try:
user.clean()
if (self['password'].value() != self['confirm_password'].value()):
self.add_error('confirm_password', 'Passwords must match.')
if (self['forward_email'].value().split('@')[1] in ["ucc.asn.au", "ucc.gu.uwa.edu.au"]):
self.add_error('forward_email', 'Forwarding address cannot be the same as your account address.')
except:
pass
super().clean();
def save(self):
return
class AccountView(MyUpdateView):
template_name = 'admin/memberdb/account_create.html'
form_class = AccountForm
model = Member
pk_url_kwarg = 'object_id'
admin = None
def get_context_data(self, **kwargs):
m = self.get_object()
context = super().get_context_data(**kwargs)
context.update(self.admin.admin_site.each_context(self.request))
context.update({
'opts': self.admin.model._meta,
'member': m,
})
return context
def form_valid(self, form):
m, ms = form.save()
messages.success(self.request, 'Your membership renewal has been submitted.')
return HttpResponseRedirect(reverse("admin:memberdb_membership_summary"))
......@@ -2,7 +2,8 @@
import logging
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
from django.core.exceptions import ImproperlyConfigured, ValidationError
from django.utils.translation import gettext_lazy as _
import ldap
import re
......@@ -15,9 +16,9 @@ log = logging.getLogger('ldap')
# load config
ldap_uri = getattr(settings, 'AUTH_LDAP_SERVER_URI')
ldap_search_dn = getattr(settings, 'REPLACE_ME')
ldap_bind_dn = getattr()
ldap_bind_secret = getattr()
ldap_search_dn = getattr(settings, 'AUTH_LDAP_USER_DN_TEMPLATE')
#ldap_bind_dn = getattr()
#ldap_bind_secret = getattr()
#initalise ldap instace
......@@ -40,6 +41,9 @@ def get_user_attrs(username, attrs):
return None
return result[0];
except:
return None
def get_account_lock_status(username):
ld = get_ldap_instance()
try:
......@@ -49,6 +53,17 @@ def get_account_lock_status(username):
ld.unbind()
return bool(result[1]['userAccountControl'] & 0x002)
def validate_username(value):
# usernames can't begin with a numeric
if re.match(r"^\d.*", value):
log.info("test")
raise ValidationError(
_('Username cannot begin with a number'),
params={'value': value}
)
else:
return value
# locks the specified User Account by performing the following actions:
# 1. set UAC ACCOUNTDISABLE flag (0x002) via ldap
# 2. set user shell to `/etc/locked20xx` via ldap
......@@ -104,7 +119,7 @@ def unlock_account(username):
# Account creation steps:
#
def create_account(member):
username =
username = "changeme";
log.info("I: creating new account for %s (%s %s)")
# prepend student numbers with 'sn'
......
......@@ -10,122 +10,138 @@ from gms import admin
from memberdb.models import Member, IncAssocMember, Membership
from memberdb.actions import download_as_csv
from memberdb.approve import MembershipApprovalForm, MembershipApprovalAdminView
from memberdb.account import AccountForm, AccountView
def get_model_url(pk, model_name):
return reverse('admin:memberdb_%s_change' % model_name, args=[pk])
return reverse('admin:memberdb_%s_change' % model_name, args=[pk])
"""
helper mixin to make the admin page display only "View" rather than "Change" or "Add"
"""
class ReadOnlyModelAdmin(admin.ModelAdmin):
def has_add_permission(self, request):
return False
def has_delete_permission(self, request, obj=None):
return True
def has_add_permission(self, request):
return False
def has_delete_permission(self, request, obj=None):
return True
def has_change_permission(self, request, obj=None):
return False
def has_change_permission(self, request, obj=None):
return False
"""
Define the administrative interface for viewing member details required under the Incorporations Act
"""
class IAMemberAdmin(ReadOnlyModelAdmin):
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)
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)
class MembershipInline(admin.TabularInline):
model = Membership
readonly_fields = ['member', 'date_submitted']
radio_fields = {'payment_method': admin.VERTICAL, 'membership_type': admin.VERTICAL}
extra = 0
fk_name = 'member'
model = Membership
readonly_fields = ['member', 'date_submitted']
radio_fields = {'payment_method': admin.VERTICAL, 'membership_type': admin.VERTICAL}
extra = 0
fk_name = 'member'
class MemberAdmin(admin.ModelAdmin):
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 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)
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)
"""
Define the admin page for viewing normal Member records (all details included) and approving them
"""
class MembershipAdmin(admin.ModelAdmin):
list_display = ['membership_info', 'member_actions', 'membership_type', 'payment_method', 'approved', 'date_submitted', ]
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])
}
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)
"""
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)
"""
Register multiple ModelAdmins per model. See https://stackoverflow.com/questions/2223375/multiple-modeladmins-views-for-same-model-in-django-admin/2228821
"""
class ProxyMembership(Membership):
class Meta:
proxy = True
class Meta:
proxy = True
class PendingMembershipAdmin(MembershipAdmin):
def get_queryset(self, request):
return self.model.objects.filter(approved__exact=False)
def get_queryset(self, request):
return self.model.objects.filter(approved__exact=False)
# Register the other models with either default admin site pages or with optional customisations
admin.site.register(Member, MemberAdmin)
......
var conditional_fields = $("div");
\ No newline at end of file
......@@ -34,6 +34,7 @@
overflow: auto;
}
.button {
display: inline-block;
}
......
{% extends "admin/change_form.html" %}
{% load i18n admin_static admin_modify %}
{% block content %}
<div id="content-main">
<h1>Create Account for <i>{{ member.first_name }} {{ member.last_name }}</i></h1>
<div class="ms-approve-summary">
{% include "admin/memberdb/membership_summary.html" %}
</div>
<form action="" method="POST">
{% csrf_token %}
{% if form.non_field_errors|length > 0 %}
<p class="errornote">
Please correct the errors below.
</p>
{{ form.non_field_errors }}
{% endif %}
<fieldset class="module aligned">
{% for field in form %}
<div class="form-row">
{{ field.label_tag }}
{{ field }}
{{ field.errors }}
{% if field.field.help_text %}
<p class="help">
{{ field.field.help_text|safe }}
</p>
{% endif %}
</div>
{% endfor %}
</fieldset>
<div class="submit-row">
<input type="submit" class="default" value="Create">
</div>
</form>
</div>
{% endblock %}
\ No newline at end of file
......@@ -4,5 +4,5 @@
{% if not ms.approved %}
<a class="button" href="{{ member_approve }}">Approve</a>&nbsp;
{% endif %}
<a class="button" href="{{ account_create }}">Create Account</a>&nbsp;
<a class="button" href="{{ create_account }}">Create Account</a>&nbsp;
</div>
Supports Markdown
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