pfidp/users_admin: multiple users creation & filter

This commit is contained in:
Thomas NOËL 2014-01-09 17:38:29 +01:00
parent 0cc4ff6fd5
commit 3c6b139db3
6 changed files with 99 additions and 42 deletions

View File

@ -10,7 +10,7 @@
<link href="{% static "bootstrap/css/bootstrap.css" %}" rel="stylesheet">
<style>
body { padding-top: 60px; }
th { text-align: right; padding-right: 20px; }
th { text-align: right; padding-right: 20px; vertical-align: top; }
.disabled { color: #ccc; }
ul.errorlist { list-style-type: none; margin: 0; }
ul.errorlist li { color: #f00; }

View File

@ -2,11 +2,12 @@
{% load i18n %}
{% load staticfiles %}
{% block title %}Créer un utilisateur{% endblock %}
{% block title %}Création d'utilisateur{% endblock %}
{% block content %}
<h1>Créer un utilisateur</h1>
<h1>Créer un utilisateur <em>login</em><h1>
<h3>ou un ensemble d'utilisateurs <em>login-N</em></h2>
<br />
@ -16,7 +17,7 @@
{{ form.as_table }}
</table>
<div class="form-actions">
<input type="submit" value="Créer cet utilisateur" class="btn btn-primary" />
<input type="submit" value="Créer" class="btn btn-primary" />
<a href="." class="btn"><i class="icon-remove"></i> Annuler</a>
</div>
</form>

View File

@ -5,11 +5,20 @@
{% block title %}Accueil{% endblock %}
{% block nav %}
<li><a href="create">Créer un utilisateur</a></li>
<li><a href="create">Créer des utilisateurs</a></li>
{% endblock %}
{% block title_content %}
<div class="row">
<div class="span8">
<h1>Liste des utilisateurs</h1>
</div>
<div class="span4">
<form method="get" action="">
<input type="text" name="filter" value="{{ filter }}" placeholder="Filtre (avec * et ?)" class="pull-right" />
</form>
</div>
</div>
{% endblock %}
{% block content %}
@ -61,7 +70,8 @@
</table>
<div class="form-actions">
<a href="create" class="btn">Créer un utilisateur</a>
<a href="create" class="btn">Créer des utilisateurs</a>
<div class=" pull-right">
<input type="submit" value="Ok" class="btn pull-right" />
<select name="action" class="pull-right">
@ -69,6 +79,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="expire">Changer la date d'expiration des utilisateurs choisis</option -->
</select>
</div>
</div>

View File

@ -36,22 +36,37 @@ class UserForm(forms.Form):
class NewUserForm(UserForm):
name = forms.RegexField(label=u"Nom d'utilisateur (login)", regex='^[a-z0-9\.\-_]+$', min_length=3, max_length=16, required=True,
widget=forms.TextInput(attrs={'size':'16', 'autocomplete':'off', 'class':'span2'}),
help_text="Uniquement lettres, chiffres, point, trait d'union et «_»")
# force password and expire fields
password = forms.CharField(label=u"Mot de passe", min_length=3, max_length=64, required=True,
widget=forms.PasswordInput(attrs={'size':'32', 'autocomplete':'off', 'class':'span3'}))
password2 = forms.CharField(label=u"Mot de passe (vérification)", min_length=3, max_length=64, required=True,
help_text="""Uniquement lettres, chiffres, point, trait d'union et «_».
Si création de plusieurs utilisateurs (voir plus bas), leur login sera de la forme login-N.""")
# password and expire fields
password = forms.CharField(label=u"Mot de passe", min_length=3, max_length=64, required=False,
help_text="""Si vous n'indiquez pas de mot de passe, un mot de passe aléatoire sera
attribué à chaque utilisateur""",
widget=forms.PasswordInput(attrs={'size':'32', 'autocomplete':'off', 'class':'span3'}))
expires = forms.DateField(label=u"Date d'expiration", required=(settings.IDP_UA_MAX_EXPIRES > 0),
widget=forms.TextInput(attrs={'size':'16', 'class':'span2 datepicker'}))
userset_number = forms.IntegerField(label=u"Nombre d'utilisateur(s) à créer (login-N)",
widget=forms.TextInput(attrs={'size':'5', 'class':'span1'}),
required=True, min_value=1)
userset_start = forms.IntegerField(label=u"""En cas de création de plusieurs utilisateurs (login-N),
indiquer le premier numéro N""",
widget=forms.TextInput(attrs={'size':'5', 'class':'span1'}),
required=True)
def is_valid(self):
valid = super(NewUserForm, self).is_valid()
if valid:
name = self.cleaned_data.get('name')
all_pfusers = pfusers.get_all_pfusers()
if all_pfusers.get(name, None) is not None:
userset_number = int(self.cleaned_data.get('userset_number'))
if userset_number == 1 and all_pfusers.get(name, None) is not None:
self.errors['name'] = [u'Un utilisateur avec ce login existe déjà.']
valid = False
return False
if userset_number > 1:
userset_start = int(self.cleaned_data.get('userset_start'))
for n in range(userset_start, userset_start + userset_number):
if all_pfusers.get('%s-%d' % (name, n), None) is not None:
self.errors['name'] = [u"L'utilisateur %s-%d existe déjà." % (name, n)]
return False
return valid

View File

@ -9,6 +9,8 @@ import syslog
import htmlentitydefs
import re
import random
import fnmatch
pattern = re.compile("&(\w+?);")
@ -31,7 +33,7 @@ def configxml():
f.close()
return root
def get_all_pfusers():
def get_all_pfusers(filter=None):
xml_users = configxml().findall('system/user')
if xml_users is None:
return {}
@ -45,6 +47,9 @@ def get_all_pfusers():
user = dict([(tag, xml_user.findtext(tag))
for tag in ('uid', 'name', 'expires', 'descr')])
if filter and not fnmatch.fnmatch(user['name'], filter+'*'):
continue
user['descr'] = html_entity_decode(user['descr']).decode('iso-8859-1')
user['priv'] = set([priv.text for priv in xml_user.findall('priv')])
@ -130,6 +135,9 @@ def create(username, password, expires, disabled=False, descr='', multiple=False
privs = 'univnautes-idp'
if multiple:
privs += ',univnautes-idp-multiple'
if not password:
password = ''.join([random.choice('23456789ABCDEFGHJLMNPQRSTUVWXZabcdefghjkmnpqrstuvwxyz')
for x in range(random.randint(6,9))])
return call('create', name=username, password=password,
expires=expires_str,
disabled=disabled_str,

View File

@ -13,7 +13,9 @@ import datetime
@user_passes_test(lambda user: user.is_staff, login_url='/logout')
def index(request):
context = { 'users': pfusers.get_all_pfusers(), }
filter = request.GET.get('filter')
context = { 'users': pfusers.get_all_pfusers(filter),
'filter': filter or '' }
return render_to_response('users_admin/index.html',
context,
context_instance=RequestContext(request))
@ -42,15 +44,33 @@ def create(request):
descr = form.cleaned_data.get('descr')
disabled = form.cleaned_data.get('disabled')
multiple = form.cleaned_data.get('multiple')
ret, log = pfusers.create(name, password=password, descr=descr,
expires=expires, disabled=disabled, multiple=multiple)
if ret:
messages.success(request, u'Utilisateur <%s> ajouté.' % name)
else:
messages.error(request, u'Erreur lors de la création <%s>: %s' % (name, log))
userset_number = int(form.cleaned_data.get('userset_number'))
if userset_number == 1:
ret, log = pfusers.create(name, password=password, descr=descr,
expires=expires, disabled=disabled, multiple=multiple)
if ret:
messages.success(request, u'Utilisateur <%s> ajouté.' % name)
else:
messages.error(request, u'Erreur lors de la création <%s>: %s' % (name, log))
else: # (multiple users creation)
userset_start = int(form.cleaned_data.get('userset_start'))
for n in range(userset_start, userset_start+userset_number):
username = '%s-%d' % (name, n)
ret, log = pfusers.create(username, password=password, descr=descr,
expires=expires, disabled=disabled, multiple=multiple)
if not ret:
messages.error(request, u'Erreur lors de la création <%s>: %s' % (username, log))
break
messages.success(request, u'Utilisateurs <%s-%d> à <%s-%d> ajoutés.' % \
(name, userset_start, name, userset_start+userset_number-1))
return redirect('.')
else:
initial={'name':''}
initial = {
'name': '',
'userset_number': 1,
'userset_start': 1,
}
if settings.IDP_UA_MAX_EXPIRES > 0:
dt = datetime.date.today() + datetime.timedelta(settings.IDP_UA_MAX_EXPIRES)
else:
@ -179,21 +199,24 @@ def activate(request, name=None):
'title': u"Activer le compte <%s> ?" % name },
context_instance=RequestContext(request))
ACTION_NAME = {
'delete': u'Suppression',
'desactivate': u'Désactivation',
'activate': u'Activation',
}
@user_passes_test(lambda user: user.is_staff, login_url='/logout')
def multiple(request):
if request.method == 'POST':
action = request.POST.get('action')
if action:
# we need a confirmation
if action == 'delete':
title = 'Supprimer ces comptes ?'
elif action == 'desactivate':
title = 'Désactiver ces comptes ?'
elif action == 'activate':
title = 'Activer ces comptes ?'
else:
if not action in ACTION_NAME:
messages.warning(request, u'Choisissez une action...')
return redirect('.')
else:
title = '%s de ces comptes ?' % ACTION_NAME[action]
names = request.POST.getlist('users')
if len(names) == 0:
messages.warning(request, u'Sélectionnez au moins un utilisateur.')
@ -222,22 +245,21 @@ def multiple(request):
except KeyError:
messages.error(request, u'Erreur dans la session !')
return redirect('.')
if not action in ACTION_NAME:
messages.error(request, u'Action invalide')
return redirect('.')
success = []
errors = []
for name in names:
if action == 'delete':
ret, log = pfusers.delete(name)
action_name = u'supprimé'
elif action == 'desactivate':
ret, log = pfusers.desactivate(name)
action_name = u'désactivé'
elif action == 'activate':
ret, log = pfusers.activate(name)
action_name = u'activé'
else:
raise 'invalid action'
ret, log = getattr(pfusers, action)(name)
if ret:
messages.success(request, u'Utilisateur <%s> %s.' % (name, action_name))
success.append(name)
else:
messages.error(request, u'Erreur lors "<%s> %s": %s' % (name, action_name, log))
errors.append('%s (%s)' % (name, log))
if success:
messages.success(request, u'%s: %s' % (ACTION_NAME[action], ', '.join(success)))
if errors:
messages.error(request, u'ERREUR %s: %s' % (ACTION_NAME[action], ', '.join(errors)))
del request.session['univnautes_idpua_names']
del request.session['univnautes_idpua_action']
else: