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:
parent
bb00eb3eb4
commit
1f2f7cc73a
@ -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)
|
||||
|
@ -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):
|
||||
|
@ -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',
|
||||
),
|
||||
|
||||
|
@ -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 = {}
|
||||
|
Loading…
Reference in New Issue
Block a user