import csv from django import forms from django.conf import settings from django.contrib.auth import get_user_model from django.utils.translation import ugettext_lazy as _ from .utils import TextIOWrapper User = get_user_model() class UserForm(forms.ModelForm): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) for name, field in self.fields.items(): if isinstance(field, forms.DateField): # Force date format on load, so date picker doesn't mess it up # because of i10n. field.widget = forms.DateInput(format='%Y-%m-%d') if name == 'extra': field.label = getattr( settings, 'USER_EXTRA_FIELD_LABEL', _('Additional data')) class Meta: model = User exclude = ['password', 'last_login', 'is_staff'] class CreateStaffForm(forms.ModelForm): serial = forms.CharField(label=_('Username'), help_text="Spaces are not allowed") password = forms.CharField(label=_("Password"), help_text=_('To create a strong password, ' 'forget about passwords, and think ' 'rather about a passphrase. For ' 'instance: "The boat is flowing on ' 'the water" is a strong and easy to' ' remember passphrase. Now choose ' 'your own passphrase!'), widget=forms.PasswordInput) password_confirm = forms.CharField(label=_("Confirm password"), widget=forms.PasswordInput) class Meta: model = get_user_model() fields = ['serial', 'password'] def clean_password_confirm(self): password1 = self.cleaned_data.get('password') password2 = self.cleaned_data.get('password_confirm') if password1 and password2: if password1 != password2: raise forms.ValidationError('The two passwords do not match') return password2 def save(self, *args, **kwargs): user = super().save(*args, **kwargs) password = self.cleaned_data['password'] user.set_password(password) user.is_staff = True user.save() return user class UserImportForm(forms.Form): source = forms.FileField(required=True) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) formats = getattr(settings, 'USER_IMPORT_FORMATS', None) if formats is None: self.fields['format'] = forms.CharField( required=True, initial='ideascube', widget=forms.HiddenInput) else: self.fields['format'] = forms.ChoiceField( required=True, initial=formats[0][0], choices=formats) def _get_ideascube_reader(self, source): return csv.DictReader(source) def _get_ideascube_mapping(self, data): return data def _get_llavedelsaber_reader(self, source): return csv.DictReader(source, delimiter=';', quoting=csv.QUOTE_ALL) def _get_llavedelsaber_mapping(self, data): # TODO: Implement the rest, once we hear back from Sergio return { 'serial': data['serial'], } def save(self): format = self.cleaned_data['format'] source = TextIOWrapper(self.cleaned_data['source'].file) qs = User.objects.all() mapper = getattr(self, '_get_%s_mapping' % format) reader = getattr(self, '_get_%s_reader' % format) users = [] errors = [] for idx, row in enumerate(reader(source), start=1): try: row = mapper(row) except KeyError as e: msg = _('Invalid row at line {id}: {field} missing') errors.append(msg.format(id=idx, field=e.args[0])) continue try: instance = qs.get(serial=row['serial']) except (User.DoesNotExist, KeyError): instance = None form = UserForm(data=row, instance=instance) if form.is_valid(): user = form.save() users.append(user) else: reason = ', '.join('{}: {}'.format(k, v.as_text()) for k, v in form.errors.items()) errors.append(_('Invalid row at line {id}: {reason}').format( id=idx, reason=reason)) return users, errors[:10]