pfidp/users_admin: show a user; csv export

This commit is contained in:
Thomas NOËL 2014-01-16 17:07:15 +01:00
parent 64413a3041
commit 782ed58f9b
7 changed files with 129 additions and 17 deletions

View File

@ -321,6 +321,9 @@ PF_CONFIG_XML = '/conf/config.xml'
# user_admins params
# store generated password here
CLEAR_PASSWORD_DIR = '/var/db/univnautes/pfidp/passwords'
# maximum expiration (0 to disable)
IDP_UA_MAX_EXPIRES = 7

View File

@ -16,8 +16,8 @@
<div class="span4">
<form method="get" action="" class="form-inline pull-right">
<div class="input-prepend input-append">
<span class="add-on"><a href="./"><i class="icon-remove-circle"></i></a></span>
<input id="filter" type="text" name="filter" value="{{ filter }}" placeholder="Filtre (avec * et ?)"/>
<span class="add-on"><a href="./?filter="><i class="icon-remove-circle"></i></a></span>
<input id="filter" type="text" name="filter" value="{{ filter }}" style="color: red; font-weight: bold;" placeholder="Filtre (avec * et ?)"/>
<input type="submit" value="Filtrer" class="btn" />
</div>
</form>
@ -52,7 +52,7 @@
{% for user in users.values|dictsort:"name" %}
<tr {% if user.disabled or user.ttl == 0 %} class="disabled"{% endif %}>
<td data-order-by="{{ user.name }}">
<a href="update/{{ user.name }}" {% if user.disabled or user.ttl == 0 %} class="disabled"{% endif %}>{{ user.name }}</a>
<a href="read/{{ user.name }}" {% if user.disabled or user.ttl == 0 %} class="disabled"{% endif %}>{{ user.name }}</a>
{% if 'univnautes-idp-multiple' in user.priv %} &mdash; multiple{% endif %}
{% if user.disabled %} &mdash; désactivé{% endif %}
{% if user.ttl == 0 %} &mdash; expiré{% endif %}
@ -84,6 +84,7 @@
<option value="desactivate">Désactiver les utilisateurs choisis</option>
<option value="activate">Activer les utilisateurs choisis</option>
<option value="delete">Supprimer les utilisateurs choisis</option>
<option value="csv">Exporter la liste en CSV</option>
<!-- option value="expire">Changer la date d'expiration des utilisateurs choisis</option -->
</select>
</div>

View File

@ -0,0 +1,44 @@
{% extends "users_admin/base.html" %}
{% load i18n %}
{% load staticfiles %}
{% block title %}Utilisateur {{ user.name}}{% endblock %}
{% block content %}
<h1>Utilisateur &lt;{{ user.name }}&gt;</h1>
<span style="font-size: 1.2em;">
<dl class="dl-horizontal">
<dt>Login</dt> <dd>{{ user.name }}
{% if user.disabled %}
&mdash; <strong>désactivé</strong>
{% endif %}
</dd>
<dt>Nom complet</dt> <dd>{{ user.descr }}&nbsp;</dd>
<dt>Expiration</dt> <dd>{{ user.expires }} &mdash;
{% if user.ttl %}{{user.ttl}} jour{% if user.ttl > 1 %}s{% endif %}{% else %}<strong>expiré</strong>{% endif %}</dd>
{% if user.password %}
<dt>Mot de passe</dt> <dd><span id="hidepass" style="display: none;">{{ user.password }}</span>
<span id="showpass">(cliquer ici pour l'afficher)</span>
<script>
$('#showpass').click(function() {$('#hidepass').show(); $('#showpass').hide();});
$('#hidepass').click(function() {$('#showpass').show(); $('#hidepass').hide();});
</script>
</dd>
{% endif %}
</dl>
</span>
<div class="form-actions">
<a href=".." class="btn btn-primary"><i class="icon-list"></i> Retour à la liste</a>
<a href="../update/{{ user.name }}" class="btn"><i class="icon-edit"></i> Modifier l'utilisateur</a>
{% if user.disabled %}
<a href="../activate/{{ user.name }}" class="btn"><i class="icon-play"></i> Activer l'utilisateur</a>
{% else %}
<a href="../desactivate/{{ user.name }}" class="btn"><i class="icon-pause"></i> Désactiver l'utilisateur</a>
{% endif %}
<a href="../delete/{{ user.name }}" class="btn btn-danger pull-right"><i class="icon-trash"></i> Supprimer l'utilisateur</a>
</div>
{% endblock %}

View File

@ -0,0 +1,2 @@
"login","nom complet","expiration","mot de passe"{% for user in users %}
"{{ user.name|addslashes }}","{{ user.descr|safe|addslashes }} ","{{ user.expires|date:"c" }}","{{ user.password|default_if_none:"-"|safe|addslashes }} "{% endfor %}
Can't render this file because it contains an unexpected character in line 1 and column 49.

View File

@ -1,8 +1,12 @@
import xml.etree.ElementTree as ET
try:
from django.conf import settings
PF_CONFIG_XML = settings.PF_CONFIG_XML
CLEAR_PASSWORD_DIR = settings.CLEAR_PASSWORD_DIR
except ImportError:
settings = None
PF_CONFIG_XML = '/conf/config.xml'
CLEAR_PASSWORD_DIR = '/var/db/univnautes/pfidp/passwords'
import datetime
import subprocess
import syslog
@ -11,6 +15,7 @@ import htmlentitydefs
import re
import random
import fnmatch
import os
pattern = re.compile("&(\w+?);")
@ -25,15 +30,41 @@ def html_entity_decode(string):
def configxml():
if settings:
f = open(settings.PF_CONFIG_XML,'r')
else:
f = open('/conf/config.xml','r')
f = open(PF_CONFIG_XML,'r')
root = ET.fromstring(f.read())
f.close()
return root
def get_all_pfusers(filter=None):
def create_password(username):
if not os.path.exists(CLEAR_PASSWORD_DIR):
os.makedirs(CLEAR_PASSWORD_DIR)
password = ''.join([random.choice('23456789ABCDEFGHJLMNPQRSTUVWXZabcdefghjkmnpqrstuvwxyz')
for x in range(random.randint(6,9))])
filename = os.path.join(CLEAR_PASSWORD_DIR, 'user-%s' % username)
f = open(filename, 'wb')
f.write(password)
f.close()
return password
def read_password(username):
filename = os.path.join(CLEAR_PASSWORD_DIR, 'user-%s' % username)
try:
f = open(filename, 'rb')
password = f.read()
f.close()
return password
except:
return None
def delete_password(username):
filename = os.path.join(CLEAR_PASSWORD_DIR, 'user-%s' % username)
try:
os.unlink(filename)
except:
pass
def get_all_pfusers(filter=None, with_password=False):
xml_users = configxml().findall('system/user')
if xml_users is None:
return {}
@ -54,6 +85,9 @@ def get_all_pfusers(filter=None):
user['priv'] = set([priv.text for priv in xml_user.findall('priv')])
if with_password:
user['password'] = read_password(user['name'])
expires = user.get('expires')
if expires:
try:
@ -136,8 +170,7 @@ def create(username, password, expires, disabled=False, descr='', multiple=False
if multiple:
privs += ',univnautes-idp-multiple'
if not password:
password = ''.join([random.choice('23456789ABCDEFGHJLMNPQRSTUVWXZabcdefghjkmnpqrstuvwxyz')
for x in range(random.randint(6,9))])
password = create_password(username)
return call('create', name=username, password=password,
expires=expires_str,
disabled=disabled_str,
@ -166,6 +199,7 @@ def update(username, password, expires, disabled, descr, multiple):
if multiple:
privs += ',univnautes-idp-multiple'
if password:
delete_password(username)
return call('update', name=username, password=password,
expires=expires_str,
disabled=disabled_str,

View File

@ -6,6 +6,7 @@ import views
urlpatterns = patterns('',
(r'^$', login_required(views.index)),
(r'^create$', login_required(views.create)),
(r'^read/(?P<name>[a-z0-9\.\-_]+)$', login_required(views.read)),
(r'^update/(?P<name>[a-z0-9\.\-_]+)$', login_required(views.update)),
(r'^delete/(?P<name>[a-z0-9\.\-_]+)$', login_required(views.delete)),
(r'^desactivate/(?P<name>[a-z0-9\.\-_]+)$', login_required(views.desactivate)),

View File

@ -4,8 +4,9 @@
from django.conf import settings
from django.shortcuts import render_to_response, redirect
from django.contrib.auth.decorators import user_passes_test
from django.template import RequestContext
from django.template import RequestContext, loader, Context
from django.contrib import messages
from django.http import HttpResponse
import pfusers
from forms import UserForm, NewUserForm, ConfirmForm
@ -13,12 +14,17 @@ import datetime
@user_passes_test(lambda user: user.is_staff, login_url='/logout')
def index(request):
filter = request.GET.get('filter')
filter = request.GET.get('filter', None)
if filter is None:
filter = request.COOKIES.get('filter', None)
context = { 'users': pfusers.get_all_pfusers(filter),
'filter': filter or '' }
return render_to_response('users_admin/index.html',
context,
context_instance=RequestContext(request))
response = render_to_response('users_admin/index.html',
context,
context_instance=RequestContext(request))
if filter is not None:
response.set_cookie('filter', filter)
return response
@user_passes_test(lambda user: user.is_staff, login_url='/logout')
def create(request):
@ -81,6 +87,16 @@ def create(request):
{ 'form': form, },
context_instance=RequestContext(request))
@user_passes_test(lambda user: user.is_staff, login_url='/logout')
def read(request, name=None):
user = pfusers.get_all_pfusers(with_password=True).get(name, None)
if user == None:
messages.error(request, u'Utilisateur <%s> inconnu.' % name)
return redirect('..')
return render_to_response('users_admin/read.html',
{ 'user': user, },
context_instance=RequestContext(request))
@user_passes_test(lambda user: user.is_staff, login_url='/logout')
def update(request, name=None):
user = pfusers.get_all_pfusers().get(name, None)
@ -204,6 +220,7 @@ ACTION_NAME = {
'delete': u'Suppression',
'desactivate': u'Désactivation',
'activate': u'Activation',
'csv': u'Export CSV',
}
@user_passes_test(lambda user: user.is_staff, login_url='/logout')
@ -221,12 +238,14 @@ def multiple(request):
if len(names) == 0:
messages.warning(request, u'Sélectionnez au moins un utilisateur.')
return redirect('.')
all_pfusers = pfusers.get_all_pfusers()
all_pfusers = pfusers.get_all_pfusers(with_password=(action=="csv"))
try:
users = [ all_pfusers[name] for name in names ]
except KeyError:
messages.error(request, u'Au moins un utilisateur inconnu dans la liste.')
return redirect('.')
if action == "csv":
return csv(users)
request.session['univnautes_idpua_action'] = action
request.session['univnautes_idpua_names'] = names
form = ConfirmForm()
@ -267,3 +286,11 @@ def multiple(request):
return redirect('.')
def csv(users):
response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = 'attachment; filename="users.csv"'
t = loader.get_template('users_admin/users.csv')
c = Context({ 'users': users, })
response.write(t.render(c))
return response