pfidp/users_admin: multiple users creation & filter
This commit is contained in:
parent
0cc4ff6fd5
commit
3c6b139db3
|
@ -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; }
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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:
|
||||
|
|
Reference in New Issue