0002-csv_import-allow-setting-user-password-and-sending-m.patch
src/authentic2/csv_import.py | ||
---|---|---|
36 | 36 |
from authentic2.a2_rbac.utils import get_default_ou |
37 | 37 |
from authentic2.custom_user.models import User |
38 | 38 |
from authentic2.forms.profile import modelform_factory, BaseUserForm |
39 |
from authentic2.models import Attribute, AttributeValue, UserExternalId |
|
39 |
from authentic2.models import Attribute, AttributeValue, UserExternalId, PasswordReset |
|
40 |
from authentic2.utils import (send_password_reset_mail, generate_password, |
|
41 |
send_templated_mail) |
|
40 | 42 | |
41 | 43 |
Role = get_role_model() |
42 | 44 | |
... | ... | |
197 | 199 |
SOURCE_COLUMNS = set([SOURCE_NAME, SOURCE_ID]) |
198 | 200 |
ROLE_NAME = '_role_name' |
199 | 201 |
ROLE_SLUG = '_role_slug' |
200 |
SPECIAL_COLUMNS = SOURCE_COLUMNS | {ROLE_NAME, ROLE_SLUG} |
|
202 |
REGISTRATION = '@registration' |
|
203 |
REGISTRATION_RESET_EMAIL = 'send-set-password-link' |
|
204 |
REGISTRATION_PASSWORD_EMAIL = 'send-password' |
|
205 |
SPECIAL_COLUMNS = SOURCE_COLUMNS | {ROLE_NAME, ROLE_SLUG, REGISTRATION} |
|
201 | 206 | |
202 | 207 | |
203 | 208 |
class ImportUserForm(BaseUserForm): |
... | ... | |
207 | 212 |
locals()[ROLE_SLUG] = forms.CharField( |
208 | 213 |
label=_('Role slug'), |
209 | 214 |
required=False) |
215 |
choices = [ |
|
216 |
(REGISTRATION_RESET_EMAIL, _('Email user so they can set a password')), |
|
217 |
(REGISTRATION_PASSWORD_EMAIL, _('Email user with a password they will have to change')), |
|
218 |
] |
|
219 |
locals()[REGISTRATION] = forms.ChoiceField( |
|
220 |
choices, |
|
221 |
label=_('Registration option'), |
|
222 |
required=False) |
|
210 | 223 | |
211 | 224 |
def clean(self): |
212 | 225 |
super(BaseUserForm, self).clean() |
... | ... | |
593 | 606 | |
594 | 607 |
if not user: |
595 | 608 |
user = User(ou=self.ou) |
609 |
user.set_password(generate_password()) |
|
596 | 610 | |
597 | 611 |
for cell in row.cells: |
598 | 612 |
if not cell.header.field: |
... | ... | |
639 | 653 |
continue |
640 | 654 |
if cell.header.name in {ROLE_NAME, ROLE_SLUG}: |
641 | 655 |
success &= self.add_role(cell, user, do_clear=True) |
656 |
elif cell.header.name == REGISTRATION and row.action == 'create': |
|
657 |
success &= self.registration_option(cell, user) |
|
642 | 658 | |
643 | 659 |
setattr(self, row.action + 'd', getattr(self, row.action + 'd') + 1) |
644 | 660 |
return success |
... | ... | |
664 | 680 |
user.roles.add(role) |
665 | 681 |
cell.action = 'updated' |
666 | 682 |
return True |
683 | ||
684 |
def registration_option(self, cell, user): |
|
685 |
if cell.value == REGISTRATION_RESET_EMAIL: |
|
686 |
send_password_reset_mail( |
|
687 |
user, |
|
688 |
template_names=['authentic2/manager/user_create_registration_email', |
|
689 |
'authentic2/password_reset'], |
|
690 |
next_url='/accounts/', |
|
691 |
context={'user': user}) |
|
692 |
elif cell.value == REGISTRATION_PASSWORD_EMAIL: |
|
693 |
new_password = generate_password() |
|
694 |
user.set_password(new_password) |
|
695 |
user.save() |
|
696 |
PasswordReset.objects.get_or_create(user=user) |
|
697 |
send_templated_mail( |
|
698 |
user, |
|
699 |
'authentic2/manager/new-account-notification', |
|
700 |
context={'new_password': new_password, 'user': user}) |
|
701 |
return True |
tests/test_csv_import.py | ||
---|---|---|
21 | 21 | |
22 | 22 |
import io |
23 | 23 | |
24 |
from django.core import mail |
|
25 | ||
24 | 26 |
from django_rbac.utils import get_role_model |
25 | 27 | |
26 | 28 |
from authentic2.custom_user.models import User |
27 |
from authentic2.models import Attribute |
|
29 |
from authentic2.models import Attribute, PasswordReset
|
|
28 | 30 |
from authentic2.a2_rbac.utils import get_default_ou |
29 | 31 | |
30 | 32 |
from authentic2.csv_import import CsvImporter, UserCsvImporter, CsvHeader, Error, LineError |
... | ... | |
164 | 166 |
assert thomas.last_name == 'Noël' |
165 | 167 |
assert thomas.attributes.last_name == 'Noël' |
166 | 168 |
assert thomas.attributes.phone == '1234' |
169 |
assert thomas.password |
|
167 | 170 | |
168 | 171 |
fpeters = User.objects.get(email='fpeters@entrouvert.com') |
169 | 172 |
assert fpeters.ou == get_default_ou() |
... | ... | |
476 | 479 |
assert not importer.run() |
477 | 480 |
assert importer.has_errors |
478 | 481 |
assert importer.errors[0].code == 'invalid-role-column' |
482 | ||
483 | ||
484 |
def test_csv_registration_options(profile, user_csv_importer_factory): |
|
485 |
content = '''email key,first_name,last_name,@registration |
|
486 |
tnoel@entrouvert.com,Thomas,Noël,''' |
|
487 | ||
488 |
importer = user_csv_importer_factory(content + 'send-password') |
|
489 |
assert importer.run() |
|
490 |
thomas = User.objects.get(email='tnoel@entrouvert.com') |
|
491 |
assert len(mail.outbox) == 1 |
|
492 |
assert PasswordReset.objects.get(user=thomas) |
|
493 | ||
494 |
del mail.outbox[0] |
|
495 |
password = thomas.password |
|
496 |
importer = user_csv_importer_factory(content + 'send-password') |
|
497 |
assert importer.run() |
|
498 |
thomas.refresh_from_db() |
|
499 |
assert thomas.password == password |
|
500 |
assert not mail.outbox |
|
501 | ||
502 |
thomas.delete() |
|
503 |
assert not mail.outbox |
|
504 |
importer = user_csv_importer_factory(content + 'send-set-password-link') |
|
505 |
assert importer.run() |
|
506 |
thomas = User.objects.get(email='tnoel@entrouvert.com') |
|
507 |
assert len(mail.outbox) == 1 |
|
508 | ||
509 |
password = thomas.password |
|
510 |
del mail.outbox[0] |
|
511 |
importer = user_csv_importer_factory(content + 'send-set-password-link') |
|
512 |
assert importer.run() |
|
513 |
thomas.refresh_from_db() |
|
514 |
assert thomas.password == password |
|
515 |
assert not mail.outbox |
|
516 | ||
517 |
importer = user_csv_importer_factory(content + 'invalid-option') |
|
518 |
assert importer.run() |
|
519 |
assert importer.has_errors |
|
520 |
assert importer.rows[0].cells[-1].errors[0].code == 'data-error' |
|
479 |
- |