From 8fdc6064fa0954d39b9a9ca25f11b3848edd19d5 Mon Sep 17 00:00:00 2001 From: Uwe Kamper Date: Thu, 24 Oct 2013 21:27:15 +0200 Subject: [PATCH] forms work and are saved to ldap correctly, added RFID form --- account/cbase_members.py | 109 ++++++++++++++ account/forms.py | 38 +++++ account/templates/form_base.html | 18 +++ {cbmi => account}/templates/gastropin.html | 0 account/templates/rfid.html | 23 +++ account/templates/wlan_presence.html | 25 ++++ account/urls.py | 4 + account/views.py | 88 ++++++++++- cbmi/forms.py | 26 ---- cbmi/settings.py | 7 +- cbmi/templates/base.html | 6 +- cbmi/templates/wlan_presence.html | 43 ------ cbmi/urls.py | 5 +- cbmi/views.py | 165 +-------------------- 14 files changed, 317 insertions(+), 240 deletions(-) create mode 100644 account/cbase_members.py create mode 100644 account/templates/form_base.html rename {cbmi => account}/templates/gastropin.html (100%) create mode 100644 account/templates/rfid.html create mode 100644 account/templates/wlan_presence.html delete mode 100644 cbmi/templates/wlan_presence.html diff --git a/account/cbase_members.py b/account/cbase_members.py new file mode 100644 index 0000000..eddbebd --- /dev/null +++ b/account/cbase_members.py @@ -0,0 +1,109 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import ldap +import copy + +from django.conf import settings + +""" +Example configuration: + +CBASE_LDAP_URL = 'ldap://lea.cbrp3.c-base.org:389/' +CBASE_BASE_DN = 'ou=crew,dc=c-base,dc=org' +""" + +def retrieve_member(request): + # TODO: Put password in encrypted session storage + return MemberValues(request.user.username, request.session['ldap_password']) + + +class MemberValues(object): + """ + Dictionary-like abstraction of the c-base member attributes. + """ + def __init__(self, username, password): + self._username = username + self._password = password + self._old = self._get_user_values() + + # Make a complete copy of the old values so we can later check + # which + self._new = copy.deepcopy(self._old) + + def get(self, key, default=None): + value = self._new.get(key, default)[0] + if value == 'TRUE': + return True + elif value == 'FALSE': + return False + else: + return value + + def set(self, key, value): + converted_value = value + if isinstance(value, bool): + if value == True: + converted_value = 'TRUE' + else: + converted_value = 'FALSE' + self._new[key] = [converted_value.encode('latin-1')] + + def save(self): + """ + Save the values back to the LDAP server. + """ + dn = "uid=%s,ou=crew,dc=c-base,dc=org" % self._username + print 'setting dn=', dn + + # TODO: Use settings for url + l = ldap.initialize("ldap://lea.cbrp3.c-base.org:389/") + l.simple_bind_s(dn, self._password) + + mod_attrs = [] + for new_key, new_value in self._new.items(): + # Replace is the default. + action = ldap.MOD_REPLACE + if new_key not in self._old.keys(): + action = ldap.MOD_ADD + mod_attrs.append((action, '%s' % new_key, new_value )) + continue + # Set the attribute and wait for the LDAP server to complete. + if self._old[new_key][0] != new_value[0]: + action = ldap.MOD_REPLACE + mod_attrs.append((action, '%s' % new_key, new_value )) + continue + + print "modattrs: ",mod_attrs + result = l.modify_s(dn, mod_attrs) + print "result is: ", result + + def _get_bind_dn(self): + """ + Adds the uid=userid, to the base dn and returns that. + """ + bind_dn = 'uid=%s,' % self._username + bind_dn += settings.CBASE_BASE_DN + return bind_dn + + def _get_user_values(self): + """ + Get an attribute from the ldap storage. + """ + # Create a new LDAP bind (aka connection or session) + session = ldap.initialize(settings.CBASE_LDAP_URL) + session.simple_bind_s(self._get_bind_dn(), self._password) + + # Set the attribute and wait for the LDAP server to complete. + searchScope = ldap.SCOPE_SUBTREE + + # retrieve all attributes + retrieveAttributes = None + searchFilter = "uid=%s" % self._username + + dn = settings.CBASE_BASE_DN + result = session.search_s(dn, searchScope, searchFilter, retrieveAttributes) + # TODO: latin1 + print "result is: ", result + # TODO: if len(result)==0 + return result[0][1] diff --git a/account/forms.py b/account/forms.py index b6a3650..d51623d 100644 --- a/account/forms.py +++ b/account/forms.py @@ -1,7 +1,45 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import re + from django import forms +from django.utils.translation import ugettext as _ + class LoginForm(forms.Form): username = forms.CharField(max_length=255) password = forms.CharField(max_length=255, widget=forms.PasswordInput) +class GastroPinField(forms.CharField): + def validate(self, value): + """ + Check if the value is all numeric and 4 - 6 chars long. + """ + match = re.match(r'^\d{4,6}$', value) + if not match: + raise forms.ValidationError(_('PIN must be 4 to 6 digits.')) + + +class GastroPinForm(forms.Form): + gastropin = GastroPinField() + + +class WlanPresenceForm(forms.Form): + # Boolean fields must never be required. + presence = forms.BooleanField(required=False, + help_text=_('Enable WiFi presence?')) + + +class PaswordForm(forms.Form): + password1 = forms.CharField(max_length=255, widget=forms.PasswordInput, + help_text=_('New password')) + password2 = forms.CharField(max_length=255, widget=forms.PasswordInput, + help_text=_('Repeat password')) + + +class RFIDForm(forms.Form): + rfid = forms.CharField(max_length=255, help_text=_('Your RFID')) + + diff --git a/account/templates/form_base.html b/account/templates/form_base.html new file mode 100644 index 0000000..1000011 --- /dev/null +++ b/account/templates/form_base.html @@ -0,0 +1,18 @@ +{% extends "base.html" %} +{% load i18n %} + +{% block container %} +
+
+

{% block form_title %}{% endblock %}

+ {% block form_description %}{% endblock %} + + {% if message %} +
{{ message }}
+ {% endif %} + + {% block form_fields %}{% endblock form_fields %} + +
+
+{% endblock container %} diff --git a/cbmi/templates/gastropin.html b/account/templates/gastropin.html similarity index 100% rename from cbmi/templates/gastropin.html rename to account/templates/gastropin.html diff --git a/account/templates/rfid.html b/account/templates/rfid.html new file mode 100644 index 0000000..40e4636 --- /dev/null +++ b/account/templates/rfid.html @@ -0,0 +1,23 @@ +{% extends "form_base.html" %} +{% load i18n %} +{% load crispy_forms_tags %} + +{% block form_title %}{% trans "RFID"%}{% endblock %} + +{% block form_description %} +

{% blocktrans %}Blabla testblab bla bla blub{% endblocktrans %}

+{% endblock %} + +{% block form_fields %} + {{ form.non_field_errors }} +
+ {% csrf_token %} + {{ form|crispy }} + +
+
+ +
+
+
+{% endblock form_fields %} \ No newline at end of file diff --git a/account/templates/wlan_presence.html b/account/templates/wlan_presence.html new file mode 100644 index 0000000..d26df1e --- /dev/null +++ b/account/templates/wlan_presence.html @@ -0,0 +1,25 @@ +{% extends "form_base.html" %} +{% load i18n %} +{% load crispy_forms_tags %} + +{% block form_title %}{% trans "WiFi Presence"%}{% endblock %} + +{% block form_description %} +

{% blocktrans %}The WiFi Presence automatically logs you in + to the c-base presence system when you connect a device to the Crew-Wifi + (SSID: c-base-crew) with your username and password.{% endblocktrans %}

+{% endblock %} + +{% block form_fields %} + {{ form.non_field_errors }} +
+ {% csrf_token %} + {{ form|crispy }} + +
+
+ +
+
+
+{% endblock form_fields %} diff --git a/account/urls.py b/account/urls.py index 8370e0f..0f3d722 100644 --- a/account/urls.py +++ b/account/urls.py @@ -5,4 +5,8 @@ urlpatterns = patterns( '', url(r'^login/$', 'account.views.auth_login', name="auth_login"), url(r'^logout/$', 'account.views.auth_logout', name="auth_logout"), + url(r'^gastropin/$', 'account.views.gastropin', name='gastropin'), + url(r'^wlan_presence/$', 'account.views.wlan_presence', name='wlan_presence'), + url(r'^rfid/$', 'account.views.rfid', name='rfid'), + url(r'^groups/(?P[^/]+)/', 'account.views.groups_list'), ) \ No newline at end of file diff --git a/account/views.py b/account/views.py index a13ebf8..90f8c64 100644 --- a/account/views.py +++ b/account/views.py @@ -6,8 +6,14 @@ from django.shortcuts import render_to_response from django.template.context import RequestContext from django.contrib.auth import login, logout, authenticate from django.contrib.auth.models import User +from django.shortcuts import get_object_or_404 +from django.contrib.auth.decorators import login_required +from django.contrib.auth.models import Group +from django.shortcuts import render +from django.utils.translation import ugettext as _ -from account.forms import LoginForm +from forms import GastroPinForm, WlanPresenceForm, LoginForm, PaswordForm, RFIDForm +from cbase_members import MemberValues, retrieve_member def auth_login(request): redirect_to = request.GET.get('next', '') or '/' @@ -43,3 +49,83 @@ def auth_logout(request): response = HttpResponseRedirect(redirect_to) response.delete_cookie('sessionkey') return response + +def landingpage(request): + is_ceymaster = is_admin = False + if 'ceymaster' in [g.name for g in request.user.groups.all()]: + is_ceymaster = True + if 'ldap_admins' in [g.name for g in request.user.groups.all()]: + is_admin = True + groups = Group.objects.all() + admins = Group.objects.get(name="ldap_admins").user_set.all() + if request.user.is_authenticated(): + # values = get_user_values(request.user.username, request.session['ldap_password']) + return render_to_response("dashboard.html", locals()) + return render_to_response("base.html", locals()) + +@login_required(redirect_field_name="/" ,login_url="/account/login/") +def groups_list(request, group_name): + group = get_object_or_404(Group, name=group_name) + groups = Group.objects.all() + if 'ceymaster' in [g.name for g in request.user.groups.all()]: + is_ceymaster = True + if 'ldap_admins' in [g.name for g in request.user.groups.all()]: + is_admin = True + return render_to_response("group_list.html", locals()) + +@login_required +def gastropin(request): + if request.method == 'POST': + form = GastroPinForm(request.POST) + if form.is_valid(): + user = request.user + user_profile = user.get_profile() + user_profile.gastropin = form.cleaned_data['gastropin'] + user_profile.save() + return render(request, 'gastropin.html', + {'message': _('Your Gastro-PIN was changed. Thank you!'), + 'form:': form}) + else: + return render(request, 'gastropin.html', {'form:': form}) + + else: + form = GastroPinForm() + + return render(request, 'gastropin.html', {'form': form}) + + +def set_ldap_field(request, form_type, field_names, template_name): + member = retrieve_member(request) + initial = {} + + if request.method == 'POST': + form = form_type(request.POST) + if form.is_valid(): + + for form_field, ldap_field in field_names: + member.set(ldap_field, form.cleaned_data[form_field]) + initial[form_field] = member.get(ldap_field) + member.save() + new_form = form_type(initial=initial) + return render(request, template_name, + {'message': _('Your changes have been saved. Thank you!'), + 'form': new_form}) + else: + return render(request, template_name, {'form:': form}) + else: + for form_field, ldap_field in field_names: + initial[form_field] = member.get(ldap_field) + form = form_type(initial=initial) + return render(request, template_name, {'form': form}) + + +@login_required +def wlan_presence(request): + return set_ldap_field(request, WlanPresenceForm, + [('presence', 'wlanPresence')], 'wlan_presence.html') + +@login_required +def rfid(request): + return set_ldap_field(request, RFIDForm, [('rfid', 'rfid')], 'rfid.html') + + diff --git a/cbmi/forms.py b/cbmi/forms.py index d06bbe6..e69de29 100644 --- a/cbmi/forms.py +++ b/cbmi/forms.py @@ -1,26 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -import re - -from django import forms -from django.utils.translation import ugettext as _ - - -class GastroPinField(forms.CharField): - def validate(self, value): - """ - Check if the value is all numeric and 4 - 6 chars long. - """ - match = re.match(r'^\d{4,6}$', value) - if not match: - raise forms.ValidationError(_('PIN must be 4 to 6 digits.')) - - -class GastroPinForm(forms.Form): - gastropin = GastroPinField() - - -class WlanPresenceForm(forms.Form): - # Boolean fields must never be required. - presence = forms.BooleanField(required=False) \ No newline at end of file diff --git a/cbmi/settings.py b/cbmi/settings.py index 8db3812..94431ba 100644 --- a/cbmi/settings.py +++ b/cbmi/settings.py @@ -176,6 +176,7 @@ INSTALLED_APPS = ( 'django.contrib.admin', 'django.contrib.admindocs', 'jsonrpc', + 'crispy_forms', 'cbmi', 'account', 'cbapi_ldap', @@ -210,7 +211,11 @@ LOGGING = { } } -# LOGIN_URL = '/account/login' +CRISPY_TEMPLATE_PACK = 'bootstrap' + +# c-base specific settings +CBASE_LDAP_URL = 'ldap://lea.cbrp3.c-base.org:389/' +CBASE_BASE_DN = 'ou=crew,dc=c-base,dc=org' try: from local_settings import * diff --git a/cbmi/templates/base.html b/cbmi/templates/base.html index 2d43373..25e2e0d 100644 --- a/cbmi/templates/base.html +++ b/cbmi/templates/base.html @@ -69,10 +69,14 @@
  • {% trans "Home" %}
  • - {% url cbmi.views.wlan_presence as wlan_presence_url %} + {% url account.views.wlan_presence as wlan_presence_url %}
  • {% trans "WLAN Presence" %}
  • + {% url account.views.rfid as rfid_url %} +
  • + {% trans "RFID" %} +
  • {% block container %}
    diff --git a/cbmi/templates/wlan_presence.html b/cbmi/templates/wlan_presence.html deleted file mode 100644 index ea201db..0000000 --- a/cbmi/templates/wlan_presence.html +++ /dev/null @@ -1,43 +0,0 @@ -{% extends "base.html" %} -{% load i18n %} -{% block container %} -
    -
    -

    {% trans "WiFi Presence"%}

    -

    {% blocktrans %}The WiFi Presence automatically logs you in - to the c-base presence system when you connect a device to the Crew-Wifi - (SSID: c-base-crew) with your username and password.{% endblocktrans %}

    - - {% if message %} -
    {{ message }}
    - {% endif %} - - {{ form.non_field_errors }} - -
    - - {% csrf_token %} -
    - -
    - {{ form.presence.errors }} -
    -
    - - - -
    -
    -
    -
    - -
    -
    -
    -
    -
    -{% endblock container %} diff --git a/cbmi/urls.py b/cbmi/urls.py index 1b9e252..b6efca6 100644 --- a/cbmi/urls.py +++ b/cbmi/urls.py @@ -10,10 +10,7 @@ urlpatterns = patterns('', url(r'^cbapi/', include("cbapi_ldap.urls")), url(r'account/', include('account.urls')), - url(r'^groups/(?P[^/]+)/', 'cbmi.views.groups_list'), - url(r'^$', 'cbmi.views.landingpage'), - url(r'^gastropin/$', 'cbmi.views.gastropin', name='gastropin'), - url(r'^wlan_presence/$', 'cbmi.views.wlan_presence', name='wlan_presence'), + url(r'^$', 'cbmi.views.landingpage'), ) diff --git a/cbmi/views.py b/cbmi/views.py index f187c8a..2360549 100644 --- a/cbmi/views.py +++ b/cbmi/views.py @@ -1,167 +1,4 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -import ldap -import copy - -from django.shortcuts import render_to_response, get_object_or_404 -from django.contrib.auth.decorators import login_required -from django.contrib.auth.models import Group -from django.shortcuts import render -from django.utils.translation import ugettext as _ - -from forms import GastroPinForm, WlanPresenceForm - -def landingpage(request): - is_ceymaster = is_admin = False - if 'ceymaster' in [g.name for g in request.user.groups.all()]: - is_ceymaster = True - if 'ldap_admins' in [g.name for g in request.user.groups.all()]: - is_admin = True - groups = Group.objects.all() - admins = Group.objects.get(name="ldap_admins").user_set.all() - if request.user.is_authenticated(): - # values = get_user_values(request.user.username, request.session['ldap_password']) - return render_to_response("dashboard.html", locals()) - return render_to_response("base.html", locals()) - - -@login_required(redirect_field_name="/" ,login_url="/account/login/") -def groups_list(request, group_name): - group = get_object_or_404(Group, name=group_name) - groups = Group.objects.all() - if 'ceymaster' in [g.name for g in request.user.groups.all()]: - is_ceymaster = True - if 'ldap_admins' in [g.name for g in request.user.groups.all()]: - is_admin = True - return render_to_response("group_list.html", locals()) - -@login_required -def gastropin(request): - if request.method == 'POST': - form = GastroPinForm(request.POST) - if form.is_valid(): - user = request.user - user_profile = user.get_profile() - user_profile.gastropin = form.cleaned_data['gastropin'] - user_profile.save() - return render(request, 'gastropin.html', - {'message': _('Your Gastro-PIN was changed. Thank you!'), - 'form:': form}) - else: - return render(request, 'gastropin.html', {'form:': form}) - - else: - form = GastroPinForm() - - return render(request, 'gastropin.html', {'form': form}) - -@login_required -def wlan_presence(request): - uv = UserValues(request.user.username, request.session['ldap_password']) - print "presence ist: ", uv.get_bool("wlanPresence") - - if request.method == 'POST': - form = WlanPresenceForm(request.POST) - if form.is_valid(): - - p = 'FALSE' - if form.cleaned_data['presence'] == True: - p = 'TRUE' - uv.set('wlanPresence', p) - uv.save() - new_form = WlanPresenceForm(initial={'presence': uv.get_bool("wlanPresence")}) - return render(request, 'wlan_presence.html', - {'message': _('Your Wifi Presenc has been set. Thank you!'), - 'form': new_form}) - else: - return render(request, 'wlan_presence.html', {'form:': form}) - else: - form = WlanPresenceForm(initial={'presence': uv.get_bool("wlanPresence")}) - - return render(request, 'wlan_presence.html', {'form': form}) - - -#def set_wlan_presence(request, value): -# """ -# -# """ -# set_boolean_value('wlanPresence', value, -# request.user.username, request.session['ldap_password']) - - -class UserValues(object): - """ - - """ - - def __init__(self, username, password): - self._username = username - self._password = password - self._old = self.get_user_values() - self._new = copy.deepcopy(self._old) - - def get(self, key, default=None): - return self._new.get(key, default)[0] - - def set(self, key, value): - self._new[key] = [value] - - def get_bool(self, key): - return self.get(key) == 'TRUE' - - def save(self): - """ - - """ - dn = "uid=%s,ou=crew,dc=c-base,dc=org" % self._username - print 'setting dn=', dn - - # TODO: Use settings for url - l = ldap.initialize("ldap://lea.cbrp3.c-base.org:389/") - l.simple_bind_s(dn, self._password) - - mod_attrs = [] - for new_key, new_value in self._new.items(): - # Replace is the default. - action = ldap.MOD_REPLACE - if new_key not in self._old.keys(): - action = ldap.MOD_ADD - mod_attrs.append((action, '%s' % new_key, new_value )) - continue - # Set the attribute and wait for the LDAP server to complete. - if self._old[new_key][0] != new_value[0]: - action = ldap.MOD_REPLACE - mod_attrs.append((action, '%s' % new_key, new_value )) - continue - - print "modattrs: ",mod_attrs - result = l.modify_s(dn, mod_attrs) - print "result is: ", result - - - def get_user_values(self): - """ - - """ - - dn = "ou=crew,dc=c-base,dc=org" - bind_dn = "uid=%s,ou=crew,dc=c-base,dc=org" % self._username - print('setting dn=', dn) - - # TODO: Use settings for url - l = ldap.initialize("ldap://lea.cbrp3.c-base.org:389/") - l.simple_bind_s(bind_dn, self._password) - - # Set the attribute and wait for the LDAP server to complete. - searchScope = ldap.SCOPE_SUBTREE - ## retrieve all attributes - again adjust to your needs - see documentation for more options - retrieveAttributes = None - searchFilter = "uid=%s" % self._username - - # get_attrs = [( ldap., 'wlanPresence', set_value )] - result = l.search_s(dn, searchScope, searchFilter, retrieveAttributes) - # TODO: latin1 - print "result is: ", result - # TODO: if len(result)==0 - return result[0][1] +# Create your views here \ No newline at end of file