Merge branch 'release/0.1.0'

This commit is contained in:
baccenfutter 2013-10-26 20:08:25 +02:00
commit bbdb446b9b
37 changed files with 1300 additions and 85 deletions

3
.gitignore vendored
View file

@ -1,2 +1,5 @@
*.pyc
.idea
local_settings.py
build
*.sqlite3

3
.gitmodules vendored Normal file
View file

@ -0,0 +1,3 @@
[submodule "static/c-base-bootstrap"]
path = static/c-base-bootstrap
url = git://dev.c-base.org/c-portal/c-portal-bootstrap.git

132
account/cbase_members.py Normal file
View file

@ -0,0 +1,132 @@
#!/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_list = self._new.get(key, default)
if value_list:
value = value_list[0]
else:
value = default
# Decode
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
l = ldap.initialize(settings.CBASE_LDAP_URL)
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
l.unbind_s()
def change_password(self, new_password):
"""
Change the password of the member.
You do not need to call save() after calling change_password().
"""
l = ldap.initialize(settings.CBASE_LDAP_URL)
user_dn = self._get_bind_dn()
l.simple_bind_s(user_dn, self._password)
l.passwd_s(user_dn, self._password, new_password)
l.unbind_s()
def to_dict(self):
result = {}
for key, value in self._new.items():
result[key] = self.get(key)
return 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]
session.unbind_s()

Binary file not shown.

View file

@ -0,0 +1,260 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2013-10-25 20:39+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: forms.py:20
msgid "Sorry, that login was invalid. Please try again."
msgstr ""
#: forms.py:39
msgid "PIN must be 4 to 6 digits."
msgstr "Die PIN muss 4 - 6 Ziffern enthalten."
#: forms.py:43
msgid "New Gastro-PIN"
msgstr "Neue Gastro-PIN"
#: forms.py:44
msgid "Repeat Gastro-PIN"
msgstr "Gastro-PIN wiederholen"
#: forms.py:52 forms.py:86
msgid "The PINs entered were not identical."
msgstr "Die beiden eingegeben PINs waren nicht identisch."
#: forms.py:60
msgid "Enable WiFi presence"
msgstr "WLAN-Presence einschalten"
#: forms.py:65
msgid "New password"
msgstr "Neues Passwort"
#: forms.py:67
msgid "Repeat password"
msgstr "Passwort wiederholen"
#: forms.py:71
msgid "Your RFID"
msgstr "Deine RFID"
#: forms.py:72
msgid ""
"Find out your RFID by holding your RFID tag to the reader in the airlock."
msgstr "Du kannst deine RFID herausfinden, in dem du eine nicht registrierte RFID-Karte an die Schleuse hältst."
#: forms.py:77
msgid "Your SIP PIN"
msgstr "Deine SIP-PIN"
#: forms.py:78
msgid "Repeat SIP PIN"
msgstr "SIP-PIN wiederholen"
#: forms.py:92
msgid "NRF24-ID"
msgstr "NRF24-ID"
#: forms.py:93
msgid "Your r0ket's NRF24 identification"
msgstr "Die NRF24-ID deiner r0ket"
#: forms.py:97
msgid "New c-lab PIN"
msgstr "Neue c-lab-PIN"
#: forms.py:98
msgid "Repeat c-lab PIN"
msgstr "c-lab-PIN wiederholen"
#: forms.py:99
msgid "Numerical only, 4 to 6 digits"
msgstr "Nur Zahlen, 4 bis 6 Ziffern lang"
#: views.py:119
msgid "Your changes have been saved. Thank you!"
msgstr "Deine Änderungen wurden gespeichert. Vielen Dank!"
#: templates/clabpin.html:5
msgid "c-lab PIN"
msgstr "c-lab-PIN"
#: templates/clabpin.html:8
msgid "Change your c-lab PIN to access the c-lab in the basement."
msgstr "PIN ändern für den Zugang um c-lab im Keller."
#: templates/clabpin.html:18 templates/gastropin.html:23
#: templates/nrf24.html:19 templates/password.html:19 templates/sippin.html:18
msgid "Save"
msgstr "Speichern"
#: templates/gastropin.html:5
msgid "Gastro PIN"
msgstr "Gastro-PIN"
#: templates/gastropin.html:9
msgid ""
"Change your Gastro PIN to access the vending machines.\n"
" To use unlock member prices, press the <code>A</code> button then "
"enter\n"
" your numeric user ID"
msgstr ""
#: templates/gastropin.html:13
msgid "and your Gastro PIN."
msgstr ""
#: templates/login.html:20
msgid "Login"
msgstr ""
#: templates/member_base.html:9
msgid "Home"
msgstr ""
#: templates/member_base.html:13 templates/password.html:5
msgid "Password"
msgstr ""
#: templates/member_base.html:17
msgid "Gastro-PIN"
msgstr ""
#: templates/member_base.html:21
msgid "WiFi presence"
msgstr "WLAN-Presence"
#: templates/member_base.html:25 templates/rfid.html:5
msgid "RFID"
msgstr ""
#: templates/member_base.html:29
msgid "c-lab-PIN"
msgstr ""
#: templates/member_base.html:33 templates/nrf24.html:5
msgid "NRF24"
msgstr ""
#: templates/member_base.html:37
msgid "SIP-PIN"
msgstr ""
#: templates/nrf24.html:8
msgid ""
"The NRF24 identification is used to interface with the\n"
" CCC's <a href=\"http://r0ket.badge.events.ccc.de/\">r0ket badge</a>."
msgstr ""
#: templates/password.html:8
msgid "You can change your password here."
msgstr ""
#: templates/rfid.html:8
msgid ""
"A Radio Frequency Identification (RFID) tag can be used\n"
" to announce your presence to other c-base members when you arrive.\n"
" Place your RFID tag on the RFID reader in the airlock terminal.\n"
" If you configured your RFID correctly, the airlock terminal will greet\n"
" you and show additional information. If you place your RFID tag in the\n"
" reader again when leaving, you will be logged out."
msgstr ""
#: templates/sippin.html:5
msgid "SIP PIN"
msgstr ""
#: templates/sippin.html:8
msgid ""
"The SIP PIN is your access to the c-base SIP server for voice telephony."
msgstr ""
#: templates/start.html:7
msgid "Welcome to the c-base member interface"
msgstr ""
#: templates/start.html:8
msgid ""
"Here you can change\n"
" some parameters of your c-base member account."
msgstr ""
#: templates/start.html:11
msgid "Basic information about your account"
msgstr ""
#: templates/start.html:15
msgid "Your user ID:"
msgstr ""
#: templates/start.html:17
msgid "Numeric user ID:"
msgstr ""
#: templates/start.html:19
msgid ""
"The numeric user ID can be used to login with\n"
" the vending machines and network connected combination\n"
" locks."
msgstr ""
#: templates/start.html:23
msgid "Your c-base e-mail address:"
msgstr ""
#: templates/start.html:28
msgid "Management information"
msgstr ""
#: templates/start.html:31
msgid "Name:"
msgstr ""
#: templates/start.html:35
msgid "External e-mail address:"
msgstr ""
#: templates/start.html:37
msgid ""
"The external e-mail address is used by the\n"
" board of c-base to reach you in cases where your c-base\n"
" address (see above) is not working. To change your\n"
" externe e-mail address please contact the c-base board\n"
" (<a href=\"mailto:vorstand@c-base.org\">vorstand@c-base."
"org</a>)."
msgstr ""
#: templates/start.html:44
msgid "Your c-base member account balance:"
msgstr ""
#: templates/start.html:45
msgid "Check balance"
msgstr ""
#: templates/wlan_presence.html:5
msgid "WiFi Presence"
msgstr ""
#: templates/wlan_presence.html:8
msgid ""
"The WiFi Presence automatically logs you in\n"
" to the c-base presence system when you connect a device to the Crew-"
"Wifi\n"
" (SSID: c-base-crew) with your username and password."
msgstr ""

View file

@ -1,6 +1,124 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import re
from django import forms
from django.contrib.auth import authenticate
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)
def clean(self):
username = self.cleaned_data.get('username')
password = self.cleaned_data.get('password')
user = authenticate(username=username, password=password)
if not user or not user.is_active:
raise forms.ValidationError(_('Sorry, that login was invalid. '
'Please try again.'), code='invalid_login')
return self.cleaned_data
def login(self, request):
username = self.cleaned_data.get('username')
password = self.cleaned_data.get('password')
user = authenticate(username=username, password=password)
return user
class GastroPinField(forms.CharField):
widget = forms.PasswordInput
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):
gastropin1 = GastroPinField(label=_('New Gastro-PIN'))
gastropin2 = GastroPinField(label=_('Repeat Gastro-PIN'))
def clean(self):
cleaned_data = super(GastroPinForm, self).clean()
gastropin1 = cleaned_data.get("gastropin1")
gastropin2 = cleaned_data.get("gastropin2")
if gastropin1 != gastropin2:
raise forms.ValidationError(
_('The PINs entered were not identical.'),
code='not_identical')
return cleaned_data
class WlanPresenceForm(forms.Form):
# Boolean fields must never be required.
presence = forms.BooleanField(required=False,
label=_('Enable WiFi presence'))
class PasswordForm(forms.Form):
old_password = forms.CharField(max_length=255, widget=forms.PasswordInput,
label=_('Old password'),
help_text=_('Enter your current password here.'))
password1 = forms.CharField(max_length=255, widget=forms.PasswordInput,
label=_('New password'))
password2 = forms.CharField(max_length=255, widget=forms.PasswordInput,
label=_('Repeat password'))
def __init__(self, *args, **kwargs):
self._request = kwargs.pop('request', None)
super(PasswordForm, self).__init__(*args, **kwargs)
def clean(self):
cleaned_data = super(PasswordForm, self).clean()
old_password = cleaned_data.get('old_password')
username = self._request.user.username
user = authenticate(username=username, password=old_password)
if not user or not user.is_active:
raise forms.ValidationError(_('The old password was incorrect.'),
code='old_password_wrong')
password1 = cleaned_data.get('password1')
password2 = cleaned_data.get('password2')
if password1 != password2:
raise forms.ValidationError(
_('The new passwords were not identical.'),
code='not_identical')
return cleaned_data
class RFIDForm(forms.Form):
rfid = forms.CharField(max_length=255, label=_('Your RFID'),
help_text=_('Find out your RFID by holding your RFID tag to the '
'reader in the airlock.'))
class SIPPinForm(forms.Form):
sippin1 = GastroPinField(label=_('Your SIP PIN'))
sippin2 = GastroPinField(label=_('Repeat SIP PIN'))
def clean(self):
cleaned_data = super(SIPPinForm, self).clean()
sippin1 = cleaned_data.get("sippin1")
sippin2 = cleaned_data.get("sippin2")
if sippin1 != sippin2:
raise forms.ValidationError(
_('The PINs entered were not identical.'),
code='not_identical')
class NRF24Form(forms.Form):
nrf24 = forms.CharField(max_length=255,
label = _('NRF24-ID'),
help_text=_("Your r0ket's NRF24 identification"))
class CLabPinForm(forms.Form):
c_lab_pin1 = GastroPinField(label=_('New c-lab PIN'))
c_lab_pin2 = GastroPinField(label=_('Repeat c-lab PIN'),
help_text=_('Numerical only, 4 to 6 digits'))

View file

@ -1,3 +1,6 @@
{% load i18n %}
{% load crispy_forms_tags %}
<!DOCTYPE html>
<html lang="de">
<head>
@ -13,12 +16,22 @@
<meta name="description" content="">
<meta name="author" content="">
<link href="/static/css/bootstrap.css" rel="stylesheet">
<link href="/static/css/bootstrap-responsive.css" rel="stylesheet">
<link href="/static/c-base-bootstrap/css/bootstrap.css" rel="stylesheet">
<link href="/static/c-base-bootstrap/css/bootstrap-responsive.css" rel="stylesheet">
<style>
body {
padding-top: 60px; /* 60px to make the container go all the way to the bottom of the topbar */
}
.asteriskField {
color: #ff1111;
margin-left: 3px;
}
.formRequired {
margin-top: 0px;
}
a.brandtext {
margin-top: 10px;
}
</style>
<!-- link rel="shortcut icon" href="{{ STATIC_URL }}ico/favicon.ico" -->
<!-- link rel="apple-touch-icon-precomposed" sizes="144x144" href="../assets/ico/apple-touch-icon-144-precomposed.png">
@ -35,20 +48,25 @@
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</a>
<!-- a class="brand" href="/">crew.c-base.org</a -->
<span class="brand"><a href="/"><img style="margin-top: -10px;"
src="{{ STATIC_URL }}img/logo.gif" /></a>
<a href="/">{% trans "member interface" %}</a>
</span>
<div class="nav-collapse collapse">
<p class="navbar-text pull-left">
c-base member-interface {% if request.user.is_authenticated %}-&gt; {{ request.user.username }}{% endif %}
</p>
<div class="pull-right">
<ul class="nav">
<ul class="nav nav-collapse collapse pull-right">
{% if request.user.is_authenticated %}
<li><a href="/account/logout/">Logout</a></li>
{% else %}
<li><a href="/account/login/">Login</a></li>
{% endif %}
</ul>
{% if request.user.is_authenticated %}
<p class="navbar-text pull-right">
<i class="icon icon-user icon-white"></i>
{{ user.username }}
</p>
{% endif %}
</div>
</div>
<!--/.nav-collapse -->
@ -63,14 +81,18 @@
<br/>
{% block body %}
<div class="container">
{% block container %}
<div class="row">
<div class="span12">
<div class="span8">
<div class="well">
<h2>c-base member-interface</h2>
Auf dieser Seite kann jedes Member seine LDAP-Daten editieren und u.A. sein Passwort neu setzen.
{% blocktrans %}On this website any member can view and
edit their data stored in the LDAP directory of
c-base.{% endblocktrans %}
</div>
<div class="alert alert-info alert-block">
neumember k&ouml;nnen sich ihr initiales passwort mit einem der folgenden member setzen:
{% blocktrans %}If you are a new member and don't have a
password yet, please contact one of the following people:{% endblocktrans %}
<ul>
{% for admin in admins %}
<li>{{ admin}}</li>
@ -78,12 +100,32 @@
</ul>
</div>
</div>
<div class="span4">
<div class="well">
<h4>Login</h4>
<form class="form" action="/account/login/?next={% url account.views.home %}"
method="post">
{% csrf_token %}
{{ form|crispy }}
<div class="control-group">
<div class="controls">
<button type="submit" class="btn btn-primary">{% trans "Sign in" %}</button>
</div>
</div>
</form>
</div><!-- /.well -->
</div>
</div>
{% endblock container %}
<hr />
<div class="row pull-right">
<small class="muted">Copyright &copy; 2013 by c-base e.V.</small>
</div>
</div><!-- /.container -->
{% endblock body %}
<script src="/static/js/bootstrap.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script>
<script src="/static/js/bootstrap-transitions.js"></script>
<script src="/static/js/bootstrap-dropdown.js"></script>
<script src="/static/c-base-bootstrap/js/bootstrap.js"></script>
<script src="/static/c-base-bootstrap/js/bootstrap-transitions.js"></script>
<script src="/static/c-base-bootstrap/js/bootstrap-dropdown.js"></script>
</body>
</html>

View file

@ -0,0 +1,22 @@
{% extends "form_base.html" %}
{% load i18n %}
{% load crispy_forms_tags %}
{% block form_title %}{% trans "c-lab PIN"%}{% endblock %}
{% block form_description %}
<p>{% blocktrans %}Change your c-lab PIN to access the c-lab in the basement.{% endblocktrans %}</p>
{% endblock %}
{% block form_fields %}
<form action="{% url account.views.clabpin %}" method="post" class="form-horizontal well">
{% csrf_token %}
{{ form|crispy }}
<div class="control-group">
<div class="controls">
<button type="submit" class="btn btn-primary">{% trans "Save"%}</button>
</div>
</div>
</form>
{% endblock form_fields %}

View file

@ -1,32 +1,31 @@
{% extends "base.html" %}
{% block body %}
<div class="container">
{% block container %}
<div class="row">
<div class="span12">
<h2>{{ request.user.username }}</h2>
{% for g in request.user.groups.all %}
{% if g.name == "ceymaster" %}
<a href="/groups/{{ g }}">
<label class="label label-important">{{ g }}</label>
</a>
<badge class="badge badge-important">
{{ g }}
</badge>
{% elif "cey" in g.name %}
<a href="/groups/{{ g }}">
<label class="label label-warning">{{ g }}</label>
</a>
<badge class="badge badge-warning">
{{ g }}
</badge>
{% elif g.name == "ldap_admins" %}
<a href="/groups/{{ g }}">
<label class="label label-success">{{ g }}</label>
</a>
<badge class="badge badge-success">
{{ g }}
</badge>
{% else %}
<a href="/groups/{{ g }}">
<label class="label">{{ g }}</label>
</a>
<badge class="badge">
{{ g }}
</badge>
{% endif %}
<br />
{% empty %}
no groups...
{% endfor %}
</div>
</div>
</div>
{% endblock body %}
{% endblock container %}

View file

@ -0,0 +1,18 @@
{% extends "member_base.html" %}
{% load i18n %}
{% block container %}
<div class="row">
<div class="span12">
<h2>{% block form_title %}{% endblock %}</h2>
{% block form_description %}{% endblock %}
{% if message %}
<div class="alert alert-info">{{ message }}</div>
{% endif %}
{% block form_fields %}{% endblock form_fields %}
</div>
</div>
{% endblock container %}

View file

@ -0,0 +1,27 @@
{% extends "form_base.html" %}
{% load i18n %}
{% load crispy_forms_tags %}
{% block form_title %}{% trans "Gastro PIN"%}{% endblock %}
{% block form_description %}
<p>{% blocktrans %}Change your Gastro PIN to access the vending machines.
To use unlock member prices, press the <code>A</code> button then enter
your numeric user ID{% endblocktrans %}
<code>{{ member.uidNumber }}</code>
{% blocktrans %}and your Gastro PIN.{% endblocktrans %}</p>
{% endblock %}
{% block form_fields %}
<form action="{% url account.views.gastropin %}" method="post" class="form-horizontal well">
{% csrf_token %}
{{ form|crispy }}
<div class="control-group">
<div class="controls">
<button type="submit" class="btn btn-primary">{% trans "Save"%}</button>
</div>
</div>
</form>
{% endblock form_fields %}

View file

@ -1,7 +1,7 @@
{% extends "base.html" %}
{% block body %}
<div class="container">
{% block container %}
BLA
<div class="row">
<div class="span12">
<h2>members of {{ group.name }}</h2>
@ -13,5 +13,4 @@
{% endfor %}
</div>
</div>
</div>
{% endblock %}
{% endblock container %}

View file

@ -0,0 +1,59 @@
{% extends "member_base.html" %}
{% load i18n %}
{% block container %}
<div class="row">
<div class="span12">
<h2>{% trans "Welcome to the c-base member interface" %}</h2>
<p class="lead">{% blocktrans %}Here you can change
some parameters of your c-base member account.{% endblocktrans %}</p>
<h3>{% trans "Basic information about your account" %}</h3>
<ul>
<li>{% trans "Your user ID:" %}
<code>{{ member.uid }}</code></li>
<li>{% trans "Numeric user ID:" %}
<code>{{ member.uidNumber }}</code><br />
<span class="muted">{% blocktrans %}The numeric user ID can be used to login with
the vending machines and network connected combination
locks.{% endblocktrans %}</span></li>
<li>
{% trans "Your c-base e-mail address:" %}
<code>{{ member.mail }}</code>
</li>
</ul>
<h3>{% trans "Your group memberships" %}</h3>
{% trans "You are part of the following LDAP groups:" %}
<ul>
{% for group in groups %}
<li><span class="label label-info">{{ group }}</span></li>
{% endfor %}
</ul>
<h3>{% trans "Management information" %}</h3>
<ul>
<li>{% trans "Name:" %}
{{ member.displayName }}
</li>
<li>
{% trans "External e-mail address:" %}
{{ member.externalEmail }}<br>
<span class="muted">{% blocktrans %}The external e-mail address is used by the
board of c-base to reach you in cases where your c-base
address (see above) is not working. To change your
externe e-mail address please contact the c-base board
(<a href="mailto:vorstand@c-base.org">vorstand@c-base.org</a>).{% endblocktrans %}</span>
</li>
<li>
{% trans "Your c-base member account balance:" %}
<a class="btn btn-small" href="https://vorstand.c-base.org/member/">{% trans "Check balance" %}</a>
</li>
</ul>
</div>
</div>
{% endblock container %}

View file

@ -1,4 +1,6 @@
{% extends "base.html" %}
{% load i18n %}
{% load crispy_forms_tags %}
{% block body %}
<div class="container">
@ -7,13 +9,23 @@
</div>
</div>
<div class="row">
<div class="span">
<form class="form" action="/account/login/?next={{ redirect_to }}" method="post">
<div class="span11 well">
<h3>Login</h3>
<form class="form form-horizontal" action="/account/login/?next={{ redirect_to }}" method="post">
{% csrf_token %}
{{ form.as_p }}
<input class="btn" type="submit" value="login"/>
{{ form|crispy }}
<div class="control-group">
<div class="controls">
<button type="submit" class="btn btn-primary">{% trans "Login" %}</button>
</div>
</div>
</form>
</div>
</div>
<hr />
<div class="row pull-right">
<small class="muted">Copyright &copy; 2013 by c-base e.V.</small>
</div>
</div>
{% endblock body %}

View file

@ -0,0 +1,47 @@
{% extends "base.html" %}
{% load i18n %}
{% block body %}
<div class="container">
<ul class="nav nav-tabs">
{% url account.views.home as home_url %}
<li class="{% if request.path == home_url %}active{% endif %}">
<a href="{{ home_url }}">{% trans "Home" %}</a>
</li>
{% url account.views.password as password_url %}
<li class="{% if request.path == password_url %}active{% endif %}">
<a href="{{ password_url }}">{% trans "Password" %}</a>
</li>
{% url account.views.gastropin as gastro_url %}
<li class="{% if request.path == gastro_url %}active{% endif %}">
<a href="{{ gastro_url }}">{% trans "Gastro-PIN" %}</a>
</li>
{% url account.views.wlan_presence as wlan_presence_url %}
<li class="{% if request.path == wlan_presence_url %}active{% endif %}">
<a href="{{ wlan_presence_url }}">{% trans "WiFi presence" %}</a>
</li>
{% url account.views.rfid as rfid_url %}
<li class="{% if request.path == rfid_url %}active{% endif %}">
<a href="{{ rfid_url }}">{% trans "RFID" %}</a>
</li>
{% url account.views.clabpin as clab_url %}
<li class="{% if request.path == clab_url %}active{% endif %}">
<a href="{{ clab_url }}">{% trans "c-lab-PIN" %}</a>
</li>
{% url account.views.nrf24 as nrf24_url %}
<li class="{% if request.path == nrf24_url %}active{% endif %}">
<a href="{{ nrf24_url }}">{% trans "NRF24" %}</a>
</li>
{% url account.views.sippin as sippin_url %}
<li class="{% if request.path == sippin_url %}active{% endif %}">
<a href="{{ sippin_url }}">{% trans "SIP-PIN" %}</a>
</li>
</ul>
{% block container %}{% endblock container %}
<hr />
<div class="row pull-right">
<small class="muted">Copyright &copy; 2013 by c-base e.V.</small>
</div>
</div><!-- /.container -->
{% endblock body %}

View file

@ -0,0 +1,23 @@
{% extends "form_base.html" %}
{% load i18n %}
{% load crispy_forms_tags %}
{% block form_title %}{% trans "NRF24"%}{% endblock %}
{% block form_description %}
<p>{% blocktrans %}The NRF24 identification is used to interface with the
CCC's <a href="http://r0ket.badge.events.ccc.de/">r0ket badge</a>.{% endblocktrans %}</p>
{% endblock %}
{% block form_fields %}
<form action="{% url account.views.nrf24 %}" method="post" class="form-horizontal well">
{% csrf_token %}
{{ form|crispy }}
<div class="control-group">
<div class="controls">
<button type="submit" class="btn btn-primary">{% trans "Save" %}</button>
</div>
</div>
</form>
{% endblock form_fields %}

View file

@ -0,0 +1,22 @@
{% extends "form_base.html" %}
{% load i18n %}
{% load crispy_forms_tags %}
{% block form_title %}{% trans "Password"%}{% endblock %}
{% block form_description %}
<p>{% blocktrans %}You can change your password here.{% endblocktrans %}</p>
{% endblock %}
{% block form_fields %}
<form action="{% url account.views.password %}" method="post" class="form-horizontal well">
{% csrf_token %}
{{ form|crispy }}
<div class="control-group">
<div class="controls">
<button type="submit" class="btn btn-primary">{% trans "Save"%}</button>
</div>
</div>
</form>
{% endblock form_fields %}

View file

@ -0,0 +1,29 @@
{% extends "form_base.html" %}
{% load i18n %}
{% load crispy_forms_tags %}
{% block form_title %}{% trans "RFID"%}{% endblock %}
{% block form_description %}
<p>{% blocktrans %}A Radio Frequency Identification (RFID) tag can be used
to announce your presence to other c-base members when you arrive.
Place your RFID tag on the RFID reader in the airlock terminal.
If you configured your RFID correctly, the airlock terminal will greet
you and show additional information. If you place your RFID tag in the
reader again when leaving, you will be logged out.{% endblocktrans %}</p>
{% endblock %}
{% block form_fields %}
{{ form.non_field_errors }}
<form action="{% url account.views.rfid %}" method="post"
class="form-horizontal well">
{% csrf_token %}
{{ form|crispy }}
<div class="control-group">
<div class="controls">
<button type="submit" class="btn btn-primary">Speichern</button>
</div>
</div>
</form>
{% endblock form_fields %}

View file

@ -0,0 +1,22 @@
{% extends "form_base.html" %}
{% load i18n %}
{% load crispy_forms_tags %}
{% block form_title %}{% trans "SIP PIN"%}{% endblock %}
{% block form_description %}
<p>{% blocktrans %}The SIP PIN is your access to the c-base SIP server for voice telephony.{% endblocktrans %}</p>
{% endblock %}
{% block form_fields %}
<form action="{% url account.views.sippin %}" method="post" class="form-horizontal well">
{% csrf_token %}
{{ form|crispy }}
<div class="control-group">
<div class="controls">
<button type="submit" class="btn btn-primary">{% trans "Save"%}</button>
</div>
</div>
</form>
{% endblock form_fields %}

View file

@ -0,0 +1,25 @@
{% extends "form_base.html" %}
{% load i18n %}
{% load crispy_forms_tags %}
{% block form_title %}{% trans "WiFi Presence"%}{% endblock %}
{% block form_description %}
<p>{% 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 %}</p>
{% endblock %}
{% block form_fields %}
{{ form.non_field_errors }}
<form action="{% url account.views.wlan_presence %}" method="post" class="form-horizontal well">
{% csrf_token %}
{{ form|crispy }}
<div class="control-group">
<div class="controls">
<button type="submit" class="btn btn-primary">Speichern</button>
</div>
</div>
</form>
{% endblock form_fields %}

View file

@ -3,6 +3,15 @@ from django.conf.urls import patterns, url
urlpatterns = patterns(
'',
url(r'^login/$', 'account.views.auth_login'),
url(r'^logout/$', 'account.views.auth_logout'),
url(r'^login/$', 'account.views.auth_login', name="cbase_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'^nrf24/$', 'account.views.nrf24', name='nrf24'),
url(r'^password/$', 'account.views.password', name='password'),
url(r'^sippin/$', 'account.views.sippin', name='sippin'),
url(r'^clabpin/$', 'account.views.clabpin', name='clabpin'),
url(r'^$', 'account.views.home', name="home"),
url(r'^groups/(?P<group_name>[^/]+)/', 'account.views.groups_list'),
)

View file

@ -1,37 +1,220 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
import base64
import hashlib
from django.conf import settings
from django.http import HttpResponseRedirect
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, PasswordForm, \
RFIDForm, NRF24Form, SIPPinForm, CLabPinForm
from cbase_members import retrieve_member
def landingpage(request):
if request.user.is_authenticated():
return HttpResponseRedirect('/account')
form = LoginForm()
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()
# values = get_user_values(request.user.username, request.session['ldap_password'])
#return render_to_response("dashboard.html", locals())
return render(request, 'base.html', {'form': form, 'admins': admins})
def auth_login(request):
redirect_to = request.REQUEST.get('next', '') or '/'
redirect_to = request.GET.get('next', '') or '/'
if request.method == 'POST':
form = LoginForm(request.POST)
if form.is_valid():
username = form.cleaned_data['username']
password = form.cleaned_data['password']
user = authenticate(username=username, password=password)
user = form.login(request)
if user is not None:
if user.is_active:
login(request, user)
member, created = User.objects.get_or_create(
username=username)
member, created = \
User.objects.get_or_create(username=username)
if created:
member.save()
return HttpResponseRedirect(redirect_to)
# save password in the session for later use with LDAP
request.session['ldap_password'] = password
# TODO: Change the
response = HttpResponseRedirect(redirect_to)
response.set_cookie('sessionkey', 'bla')
return response
else:
print 'user is none'
return render(request, 'login.html', {'form': form})
else:
form = LoginForm()
return render_to_response('login.html',
RequestContext(request, locals()))
@login_required
def home(request):
member = retrieve_member(request)
context = {'member': member.to_dict(), 'groups': request.user.groups.all()}
return render(request, 'home.html', context)
@login_required
def auth_logout(request):
redirect_to = request.REQUEST.get('next', '') or '/'
redirect_to = request.GET.get('next', '') or '/'
logout(request)
return HttpResponseRedirect(redirect_to)
response = HttpResponseRedirect(redirect_to)
response.delete_cookie('sessionkey')
return response
@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 sippin(request):
return set_ldap_field(request, SIPPinForm, [('sippin', 'sippin')],
'sippin.html')
def set_hash_field(request, form_type, in_field, out_field, hash_func,
template_name):
"""
Abstract view for changing LDAP attributes that need to be hashed.
Takes a function that converts the value into the hashed_value.
"""
member = retrieve_member(request)
initial = {}
if request.method == 'POST':
form = form_type(request.POST)
if form.is_valid():
hashed_value = hash_func(form.cleaned_data[in_field])
print 'hashed value: ', hashed_value
member.set(out_field, hashed_value)
member.save()
new_form = form_type(initial=initial)
return render(request, template_name,
{'message': _('Your changes have been saved. Thank you!'),
'form': new_form, 'member': member.to_dict()})
else:
return render(request, template_name,
{'form': form, 'member': member.to_dict()})
else:
form = form_type(initial=initial)
return render(request, template_name,
{'form': form, 'member': member.to_dict()})
@login_required
def gastropin(request):
def calculate_gastro_hash(pin):
key = settings.CBASE_GASTRO_KEY
bla = '%s%s' % (key, pin)
return hashlib.sha256(bla).hexdigest()
return set_hash_field(request, GastroPinForm,
'gastropin1', 'gastroPIN', calculate_gastro_hash, 'gastropin.html')
@login_required
def clabpin(request):
def calculate_clab_hash(pin):
salt = os.urandom(12)
digest = hashlib.sha1(bytearray(pin, 'UTF-8')+salt).digest()
return '{SSHA}' + base64.b64encode(digest + salt)
return set_hash_field(request, CLabPinForm, 'c_lab_pin1', 'c-labPIN',
calculate_clab_hash, 'clabpin.html')
@login_required
def password(request):
"""
"""
member = retrieve_member(request)
if request.method == 'POST':
form = PasswordForm(request.POST, request=request)
if form.is_valid():
new_password = form.cleaned_data['password1']
member.change_password(new_password)
request.session['ldap_password'] = new_password
request.session.save()
new_form = PasswordForm()
return render(request, 'password.html',
{'message': _('Your password was changed. Thank you!'),
'form': new_form, 'member': member.to_dict()})
else:
return render(request, 'password.html',
{'form': form, 'member': member.to_dict()})
else:
form = PasswordForm()
return render(request, 'password.html',
{'form': form, 'member': member.to_dict()})
def set_ldap_field(request, form_type, field_names, template_name):
"""
Abstract view for each of the different forms.
field_names contains the mapping of the field name in the form to
"""
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, 'member': member.to_dict()})
else:
return render(request, template_name,
{'form': form, 'member': member.to_dict()})
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, 'member': member.to_dict()})
@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')
@login_required
def nrf24(request):
return set_ldap_field(request, NRF24Form, [('nrf24', 'nrf24')], 'nrf24.html')

0
cbapi_ldap/__init__.py Normal file
View file

9
cbapi_ldap/urls.py Normal file
View file

@ -0,0 +1,9 @@
from django.conf.urls import patterns, url
from jsonrpc import jsonrpc_site
from cbapi_ldap import views
urlpatterns = patterns(
'',
url(r'^ldap/browse/$', 'jsonrpc.views.browse', name='jsonrpc_browser'),
url(r'^ldap/$', jsonrpc_site.dispatch, name='jsonrpc_mountpoint'),
)

22
cbapi_ldap/views.py Normal file
View file

@ -0,0 +1,22 @@
from jsonrpc import jsonrpc_method
TODO = [
'',
]
@jsonrpc_method("ping", authenticated=True)
def ping(request, username, password):
"""Ping - Echo Request
:returns str: echo_response
"""
echo_response = "PONG"
return echo_response
@jsonrpc_method("todo")
def todo(request):
"""Todo - List ToDo Items
:returns list: todolist
"""
return TODO

0
cbmi/forms.py Normal file
View file

View file

@ -0,0 +1,59 @@
# Django settings for cbmi project.
DEBUG = True
TEMPLATE_DEBUG = DEBUG
ADMINS = (
('Brian Wiborg', 'baccenfutter@c-base.org')
# ('Your Name', 'your_email@example.com'),
)
MANAGERS = ADMINS
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': 'cbmi.sqlite3',
'USER': '',
'PASSWORD': '',
'HOST': '',
'PORT': '',
}
}
# Absolute filesystem path to the directory that will hold user-uploaded files.
# Example: "/home/media/media.lawrence.com/media/"
MEDIA_ROOT = ''
# URL that handles the media served from MEDIA_ROOT. Make sure to use a
# trailing slash.
# Examples: "http://media.lawrence.com/media/", "http://example.com/media/"
MEDIA_URL = ''
# Absolute path to the directory static files should be collected to.
# Don't put anything in this directory yourself; store your static files
# in apps' "static/" subdirectories and in STATICFILES_DIRS.
# Example: "/home/media/media.lawrence.com/static/"
STATIC_ROOT = ''
# URL prefix for static files.
# Example: "http://media.lawrence.com/static/"
STATIC_URL = '/static/'
# Additional locations of static files
STATICFILES_DIRS = (
# Put strings here, like "/home/html/static" or "C:/www/django/static".
# Always use forward slashes, even on Windows.
# Don't forget to use absolute paths, not relative paths.
'/home/smile/projects/cbmi/src/static',
)
TEMPLATE_DIRS = (
# Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
# Always use forward slashes, even on Windows.
# Don't forget to use absolute paths, not relative paths.
)
AUTH_LDAP_START_TLS = False
CBASE_GASTRO_KEY = '12345690askdkadlasjdaj REPLACE ME'

59
cbmi/local_settings.py.uk Normal file
View file

@ -0,0 +1,59 @@
# Django settings for cbmi project.
DEBUG = True
TEMPLATE_DEBUG = DEBUG
ADMINS = (
('Brian Wiborg', 'baccenfutter@c-base.org')
# ('Your Name', 'your_email@example.com'),
)
MANAGERS = ADMINS
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': 'cbmi.sqlite3',
'USER': '',
'PASSWORD': '',
'HOST': '',
'PORT': '',
}
}
# Absolute filesystem path to the directory that will hold user-uploaded files.
# Example: "/home/media/media.lawrence.com/media/"
MEDIA_ROOT = ''
# URL that handles the media served from MEDIA_ROOT. Make sure to use a
# trailing slash.
# Examples: "http://media.lawrence.com/media/", "http://example.com/media/"
MEDIA_URL = ''
# Absolute path to the directory static files should be collected to.
# Don't put anything in this directory yourself; store your static files
# in apps' "static/" subdirectories and in STATICFILES_DIRS.
# Example: "/home/media/media.lawrence.com/static/"
STATIC_ROOT = ''
# URL prefix for static files.
# Example: "http://media.lawrence.com/static/"
STATIC_URL = '/static/'
# Additional locations of static files
STATICFILES_DIRS = (
# Put strings here, like "/home/html/static" or "C:/www/django/static".
# Always use forward slashes, even on Windows.
# Don't forget to use absolute paths, not relative paths.
'/home/smile/projects/cbmi/src/static',
)
TEMPLATE_DIRS = (
# Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
# Always use forward slashes, even on Windows.
# Don't forget to use absolute paths, not relative paths.
)
AUTH_LDAP_START_TLS = False
CBASE_GASTRO_KEY = '12345690askdkadlasjdaj REPLACE ME'

View file

@ -88,6 +88,16 @@ TEMPLATE_LOADERS = (
'django.template.loaders.app_directories.Loader',
# 'django.template.loaders.eggs.Loader',
)
TEMPLATE_CONTEXT_PROCESSORS = (
"django.contrib.auth.context_processors.auth",
"django.core.context_processors.debug",
"django.core.context_processors.i18n",
"django.core.context_processors.media",
"django.core.context_processors.static",
"django.core.context_processors.tz",
"django.contrib.messages.context_processors.messages",
"django.core.context_processors.request"
)
MIDDLEWARE_CLASSES = (
'django.middleware.common.CommonMiddleware',
@ -165,8 +175,11 @@ INSTALLED_APPS = (
'django.contrib.staticfiles',
'django.contrib.admin',
'django.contrib.admindocs',
'cbmi',
'jsonrpc',
'crispy_forms',
# 'cbmi',
'account',
#'cbapi_ldap',
)
# A sample logging configuration. The only tangible logging
@ -197,3 +210,19 @@ LOGGING = {
},
}
}
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'
# Set session cookie timeout to 10 minutes
SESSION_COOKIE_AGE = 600
LOGIN_URL = '/account/login/'
#LOCALE_PATHS =
try:
from local_settings import *
except ImportError, e:
print 'Unable to load local_settings.py:', e

View file

@ -6,7 +6,11 @@ admin.autodiscover()
urlpatterns = patterns('',
url(r'^admin/doc/', include('django.contrib.admindocs.urls')),
url(r'^admin/', include(admin.site.urls)),
url(r'^cbapi/', include("cbapi_ldap.urls")),
url(r'account/', include('account.urls')),
url(r'^groups/(?P<group_name>[^/]+)/', 'cbmi.views.groups_list'),
url(r'^$', 'cbmi.views.landingpage')
url(r'^$', 'account.views.landingpage', name="landingpage"),
)

View file

@ -1,27 +1,5 @@
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
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Create your views here
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():
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())

0
manage.py Normal file → Executable file
View file

View file

@ -1,4 +1,4 @@
Django==1.4.2
MySQL-python==1.2.4
django-auth-ldap==1.1.4
django-auth-ldap==1.1.4
django-json-rpc==0.6.1

@ -0,0 +1 @@
Subproject commit 279f25a00dc1ee300009350a1ddc59963cef0da8

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
static/img/logo.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 564 B

BIN
static/img/logo.xcf Normal file

Binary file not shown.