import users view(#7065)

This commit is contained in:
Serghei Mihai 2015-04-28 15:43:46 +02:00
parent 7b4999305a
commit 64438aee02
7 changed files with 112 additions and 5 deletions

View File

@ -27,3 +27,7 @@ class LocalAccountForm(forms.ModelForm):
class LocalAccountCreateForm(LocalAccountForm):
accounts_number = forms.IntegerField(_('Number of accounts to create'), required=False)
accounts_number_start = forms.IntegerField(_('First number of multiple accounts'), required=False)
class UsersImportForm(forms.Form):
users_file = forms.FileField(_('Users file'))

View File

@ -0,0 +1,28 @@
{% extends 'uauth/base.html' %}
{% load i18n %}
{% block content %}
<form method="post" action="{% url "import-users" organization.slug %}" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<h3>{% trans "Expected file format" %}: CSV</h3>
<ul>
<li>{% trans "5 columns: login, first name, last name, expiration date, password" %}</li>
<li>{% trans "date format: YYYY-MM-DD" %}</li>
<li>{% trans "if empty password, it will be generated" %}</li>
<li>{% trans "if user exists, it will be updated" %}</li>
<li>{% trans "separator: comma" %}</li>
<li>{% trans "encoding: utf-8" %}</li>
<li>{% trans "first line is ignored" %}</li>
</ul>
<p>Example:
<div class="example">
"login", "first name", "last name", "expiration", "password"<br />
"foo", "Foo", "User", "2015-12-31", "secret" <br />
"bar", "User", "Bar", "2015-04-30", ""<br />
"test", "", "", "", ""<br />
</div>
</p>
<p><button name="upload">{% trans "Import" %}</button>
</form>
{% endblock %}

View File

@ -7,6 +7,7 @@
{% block appbar %}
<h2>{% trans "Local users" %}</h2>
<a href="{% url "import-users" organization.slug %}" rel="popup">{% trans "Import users" %}</a>
<a href="{% url "create-users" organization.slug %}" rel="popup">{% trans "Create users" %}</a>
{% endblock %}

View File

@ -6,6 +6,7 @@ urlpatterns = patterns('',
url(r'^$', manage, name='manage'),
url(r'^users/?$', users, name='manage-users'),
url(r'^users/create$', create_users, name='create-users'),
url(r'^users/import$', import_users, name='import-users'),
url(r'^users/(?P<pk>[\w]+)/$', view_user, name='view-user'),
url(r'^users/(?P<pk>[\w]+)/edit$', edit_user, name='edit-user'),
)

View File

@ -18,3 +18,19 @@ def create_user(data):
return user
except:
return False
def create_or_update_users(data):
created = 0
updated = 0
for user in data:
try:
account = LocalAccount.objects.get(username=user['username'])
if not user['password']:
del user['password']
account.__dict__.update(user)
account.save()
updated += 1
except LocalAccount.DoesNotExist:
if create_user(user):
created += 1
return created, updated

View File

@ -1,18 +1,21 @@
import csv
import datetime
from django.utils.translation import ugettext as _
from django.core.urlresolvers import reverse_lazy
from django.http import HttpResponseRedirect
from django.shortcuts import render, redirect
from django.views.generic.base import TemplateView
from django.views.generic.list import ListView
from django.views.generic.edit import FormView, UpdateView
from django.views.generic import DetailView
from django.views.generic import DetailView, View
from django.contrib import messages
from django_tables2 import RequestConfig
from .utils import create_user
from .utils import create_user, create_or_update_users
from .models import LocalAccount, Organization
from .forms import LocalAccountCreateForm, LocalAccountForm
from .forms import LocalAccountCreateForm, LocalAccountForm, UsersImportForm
from .tables import AccountTable
@ -96,9 +99,57 @@ class UserEditView(OrganizationMixin, UpdateView):
if 'delete' in self.request.POST:
self.object.delete()
messages.info(self.request, _('Account "%s" successfully deleted' % username))
return HttpResponseRedirect(self.get_success_url())
return redirect(self.get_success_url())
else:
messages.info(self.request, _('Account "%s" successfully updated' % username))
return super(UserEditView, self).form_valid(form)
edit_user = UserEditView.as_view()
class ImportUsersView(OrganizationMixin, TemplateView):
form_class = UsersImportForm
template_name = 'organization/import_users.html'
def get_context_data(self, **kwargs):
ctx = super(ImportUsersView, self).get_context_data(**kwargs)
ctx['form'] = self.form_class()
return ctx
def post(self, request, *args, **kwargs):
form = self.form_class(request.POST, request.FILES)
context = self.get_context_data(**kwargs)
context['form'] = form
if form.is_valid():
data = form.cleaned_data['users_file']
dialect = csv.Sniffer().sniff(data.read(1024))
data.seek(0)
reader = csv.reader(data, dialect)
reader.next()
users = []
for row in reader:
try:
user = {'username': row[0].strip(),
'first_name': row[1].strip(),
'last_name': row[2].strip(),
'password': row[4].strip(),
'organization': context['organization']
}
except IndexError:
# ignore wrong lines
continue
try:
user['expiration_date'] = datetime.datetime.strptime(row[3], '%Y-%m-%d')
except ValueError:
pass
users.append(user)
created, updated = create_or_update_users(users)
if created:
messages.info(request, _('%s accounts added' % created))
if updated:
messages.info(request, _('%s accounts updated' % updated))
return redirect(self.get_success_url())
else:
return self.render_to_response(context)
import_users = ImportUsersView.as_view()

View File

@ -61,4 +61,10 @@ ul.login li, #guest-login ul li, #voucher-login ul li, .loginbox li {
.icon-delete:before {
content: '\f1f8';
margin: 0 3px;
}
div.example {
background: #eee;
border: 1px solid #bbb;
font-family: Monospace;
}