rewrote user csv import

The import does not delete the existing users anymore, but append the users as new users.
This commit is contained in:
Oskar Hahn 2012-08-10 19:49:46 +02:00
parent bb00eb3eb4
commit 1f2f7cc73a
4 changed files with 84 additions and 186 deletions

View File

@ -10,12 +10,19 @@
:license: GNU GPL, see LICENSE for more details.
"""
# for python 2.5 support
from __future__ import with_statement
from random import choice
import string
import csv
from django.contrib.auth.models import User
from django.db import transaction
from openslides.utils import csv_ext
from openslides.utils.person import get_person
from openslides.participant.models import OpenSlidesUser
@ -47,3 +54,42 @@ def gen_username(first_name, last_name):
User.objects.get(username=testname)
except User.DoesNotExist:
return testname
def import_users(csv_file):
error_messages = []
count_success = 0
try:
# check for valid encoding (will raise UnicodeDecodeError if not)
csv_file.read().decode('utf-8')
csv_file.seek(0)
with transaction.commit_on_success():
dialect = csv.Sniffer().sniff(csv_file.readline())
dialect = csv_ext.patchup(dialect)
csv_file.seek(0)
for (line_no, line) in enumerate(csv.reader(csv_file, dialect=dialect)):
if line_no:
try:
(first_name, last_name, gender, category, type, committee, comment) = line[:7]
except ValueError:
error_messages.append(_('Ignoring malformed line %d in import file.') % line_no + 1)
continue
user = OpenSlidesUser()
user.last_name = last_name
user.first_name = first_name
user.username = gen_username(first_name, last_name)
user.gender = gender
user.category = category
user.type = type
user.committee = committee
user.comment = comment
user.firstpassword = gen_password()
user.save()
user.reset_password()
count_success += 1
except csv.Error:
error_messages.appen(_('Import aborted because of severe errors in the input file.'))
except UnicodeDecodeError:
error_messages.appen(_('Import file has wrong character encoding, only UTF-8 is supported!'))
return (count_success, error_messages)

View File

@ -90,9 +90,6 @@ class UsersettingsForm(forms.ModelForm, CssClassMixin):
class UserImportForm(forms.Form, CssClassMixin):
csvfile = forms.FileField(widget=forms.FileInput(attrs={'size': '50'}),
label=_("CSV File"))
application_handling = forms.ChoiceField(
required=True, choices=USER_APPLICATION_IMPORT_OPTIONS,
label=_("For existing applications"))
class ConfigForm(forms.Form, CssClassMixin):

View File

@ -15,7 +15,7 @@ from django.core.urlresolvers import reverse
from openslides.participant.views import (
ParticipantsListPDF, ParticipantsPasswordsPDF, Overview, UserCreateView,
UserUpdateView, UserDeleteView, SetUserStatusView)
UserUpdateView, UserDeleteView, SetUserStatusView, UserImportView)
urlpatterns = patterns('openslides.participant.views',
url(r'^$',
@ -62,7 +62,7 @@ urlpatterns = patterns('openslides.participant.views',
),
url(r'^import/$',
'user_import',
UserImportView.as_view(),
name='user_import',
),

View File

@ -50,7 +50,7 @@ from openslides.utils.views import (
from openslides.config.models import config
from openslides.participant.models import OpenSlidesUser, OpenSlidesGroup
from openslides.participant.api import gen_username, gen_password
from openslides.participant.api import gen_username, gen_password, import_users
from openslides.participant.forms import (
UserCreateForm, UserUpdateForm, OpenSlidesUserForm, UsersettingsForm,
UserImportForm, GroupForm, AdminPasswordChangeForm, ConfigForm)
@ -300,6 +300,41 @@ class ParticipantsPasswordsPDF(PDFView):
story.append(t)
class UserImportView(FormView):
"""
Import Users via csv.
"""
permission_required = 'participant.can_manage_participant'
template_name = 'participant/import.html'
form_class = UserImportForm
def form_valid(self, form):
# check for valid encoding (will raise UnicodeDecodeError if not)
success, error_messages = import_users(self.request.FILES['csvfile'])
for message in error_messages:
messages.error(self.request, message)
if success:
messages.success(self.request, _('%d new participants were successfully imported.') % success)
return super(UserImportView, self).form_valid(form)
@permission_required('participant.can_manage_participant')
def reset_password(request, user_id):
"""
Reset the Password.
"""
user = User.objects.get(pk=user_id)
if request.method == 'POST':
user.profile.reset_password()
messages.success(request,
_('The Password for <b>%s</b> was successfully reset.') % user)
else:
gen_confirm_form(request,
_('Do you really want to reset the password for <b>%s</b>?') % user,
reverse('user_reset_password', args=[user_id]))
return redirect(reverse('user_edit', args=[user_id]))
@login_required
@template('participant/settings.html')
def user_settings(request):
@ -344,186 +379,6 @@ def user_settings_password(request):
}
@permission_required('participant.can_manage_participant')
@template('participant/import.html')
def user_import(request):
"""
Import Users via csv.
"""
from openslides.application.models import Application
try:
request.user.profile
messages.error(request, _('The import function is available for the admin (without user profile) only.'))
return redirect(reverse('user_overview'))
except Profile.DoesNotExist:
pass
except AttributeError:
# AnonymousUser
pass
if request.method == 'POST':
form = UserImportForm(request.POST, request.FILES)
if form.is_valid():
try:
# check for valid encoding (will raise UnicodeDecodeError if not)
request.FILES['csvfile'].read().decode('utf-8')
request.FILES['csvfile'].seek(0)
with transaction.commit_on_success():
old_users = {}
applications_mapped = 0
applications_review = 0
applications_removed = 0
try:
janitor = User.objects.get(username='__system__.janitor')
except User.DoesNotExist:
janitor = User()
janitor.first_name = ''
janitor.last_name = ''
janitor.username = '__system__.janitor'
janitor.save()
applications = Application.objects.all()
for application in applications:
if form.cleaned_data['application_handling'] == 'DISCARD':
# need to do this explicit since some applications may belong
# to __system__.janitor which is a permanent user
application.delete(force=True)
applications_removed += 1
else:
# collect all applications and map them to their submitters
submitter = application.submitter
skey = '%s_%s' % (submitter.first_name, submitter.last_name)
if not skey in old_users:
old_users[skey] = []
old_users[skey].append(application.id)
application.submitter = janitor
application.save()
if application.supporter.all():
application.writelog(_('Supporters removed after user import.'), user=request.user)
profiles = Profile.objects.all()
for profile in profiles:
profile.user.delete()
profile.delete()
i = -1
dialect = csv.Sniffer().sniff(request.FILES['csvfile'].readline())
dialect = csv_ext.patchup(dialect)
request.FILES['csvfile'].seek(0)
for (lno, line) in enumerate(csv.reader(request.FILES['csvfile'], dialect=dialect)):
i += 1
if i > 0:
try:
(first_name, last_name, gender, group, type, committee, comment) = line[:7]
except ValueError:
messages.error(request, _('Ignoring malformed line %d in import file.') % (lno + 1))
i -= 1
continue
user = User()
user.last_name = last_name
user.first_name = first_name
user.username = gen_username(first_name, last_name)
#user.email = email
user.save()
profile = Profile()
profile.user = user
profile.gender = gender
profile.group = group
profile.type = type
profile.committee = committee
profile.comment = comment
profile.firstpassword = gen_password()
profile.user.set_password(profile.firstpassword)
profile.user.save()
profile.save()
if type == 'delegate':
delegate = Group.objects.get(name='Delegierter')
user.groups.add(delegate)
else:
observer = Group.objects.get(name='Beobachter')
user.groups.add(observer)
if form.cleaned_data['application_handling'] == 'REASSIGN':
# live remap
skey = '%s_%s' % (user.first_name, user.last_name)
if skey in old_users:
for appid in old_users[skey]:
try:
application = Application.objects.get(id=appid)
application.submitter = user
application.save()
application.writelog(_('Reassigned to "%s" after (re)importing users.') % ("%s %s" % (user.first_name, user.last_name)), user=request.user)
applications_mapped += 1
except Application.DoesNotExist:
messages.error(request, _('Could not reassing application %d - object not found!') % appid)
del old_users[skey]
if old_users:
# mark all applications without a valid user as 'needs review'
# this will account for *all* applications if application_mode == 'INREVIEW'
for skey in old_users:
for appid in old_users[skey]:
try:
application = Application.objects.get(id=appid)
if application.status != 'rev':
application.set_status(user=request.user, status='rev', force=True)
applications_review += 1
except Application.DoesNotExist:
messages.error(request, _('Could not reassing application %d - object not found!') % appid)
if applications_review:
messages.warning(request, ungettext('%d application could not be reassigned and needs a review!',
'%d applications could not be reassigned and need a review!', applications_review) % applications_review)
if applications_mapped:
messages.success(request, ungettext('%d application was successfully reassigned.',
'%d applications were successfully reassigned.', applications_mapped) % applications_mapped)
if applications_removed:
messages.warning(request, ungettext('%d application was discarded.',
'%d applications were discarded.', applications_removed) % applications_removed)
if i > 0:
messages.success(request, _('%d new participants were successfully imported.') % i)
return redirect(reverse('user_overview'))
except csv.Error:
message.error(request, _('Import aborted because of severe errors in the input file.'))
except UnicodeDecodeError:
messages.error(request, _('Import file has wrong character encoding, only UTF-8 is supported!'))
else:
messages.error(request, _('Please check the form for errors.'))
else:
messages.warning(request, _("Attention: All existing participants will be removed if you import new participants."))
if Application.objects.all():
messages.warning(request, _("Attention: Supporters from all existing applications will be removed."))
messages.warning(request, _("Attention: Applications which can't be mapped to new users will be set to 'Needs Review'."))
form = UserImportForm()
return {
'form': form,
}
@permission_required('participant.can_manage_participant')
def reset_password(request, user_id):
"""
Reset the Password.
"""
user = User.objects.get(pk=user_id)
if request.method == 'POST':
user.profile.reset_password()
messages.success(request,
_('The Password for <b>%s</b> was successfully reset.') % user)
else:
gen_confirm_form(request,
_('Do you really want to reset the password for <b>%s</b>?') % user,
reverse('user_reset_password', args=[user_id]))
return redirect(reverse('user_edit', args=[user_id]))
def login(request):
extra_content = {}