manager: implement csv import of role emails (#72462) #260

Open
bdauvergne wants to merge 2 commits from wip/72462-BO-inclure-courriels-dans-l-impo into main
3 changed files with 50 additions and 7 deletions

View File

@ -859,13 +859,12 @@ class RolesCsvImportForm(LimitQuerysetFormMixin, forms.Form):
roles_by_names[role.ou][role.name] = role
self.roles = []
errors = []
for i, csvline in enumerate(csv.reader(StringIO(content), dialect=dialect, delimiter=',')):
if not csvline:
continue
if i == 0:
if csvline != ['name', 'slug', 'ou'][: len(csvline)]:
if csvline != ['name', 'slug', 'ou', 'emails', 'emails_to_members'][: len(csvline)]:
header = ','.join(csvline)
raise ValidationError(_('Invalid file header "%s", expected "name,slug,ou".') % header)
continue
@ -892,6 +891,27 @@ class RolesCsvImportForm(LimitQuerysetFormMixin, forms.Form):
self.add_line_error(_('Organizational Unit %s does not exist.') % csvline[2], i)
continue
emails = []
if len(csvline) > 3:
for email in csvline[3].split():
email = email.strip()
try:
EmailValidator()(email)
except ValidationError as e:
self.add_line_error(
_('Invalid email "%(email)s": %(error)s') % {'email': email, 'error': e},
i,
)
else:
emails.append(email)
emails_to_members = None
if len(csvline) > 4:
if csvline[4].strip().lower() in ('yes', 'true', '1', 'on'):
emails_to_members = True
if csvline[4].strip().lower() in ('no', 'false', '0', 'off'):
emails_to_members = False
if name in roles_by_names.get(ou, {}):
role = roles_by_names[ou][name]
role.slug = slug or role.slug
@ -904,13 +924,17 @@ class RolesCsvImportForm(LimitQuerysetFormMixin, forms.Form):
if not role.slug:
role.slug = generate_slug(role.name, seen_slugs=roles_by_slugs[ou])
if emails:
role.emails = emails
if emails_to_members is not None:
role.emails_to_members = emails_to_members
roles_by_slugs[ou][role.slug] = role
roles_by_names[ou][role.name] = role
role.ou = ou
self.roles.append(role)
if errors:
raise ValidationError(errors)
def add_line_error(self, error, line):
error = _('%(error)s (line %(number)d)') % {'error': error, 'number': line + 1}

View File

@ -71,7 +71,7 @@ class RoleResource(ModelResource):
class Meta:
model = Role
fields = ('name', 'slug', 'members', 'ou')
fields = ('name', 'slug', 'members', 'ou', 'emails', 'emails_to_members')
export_order = fields
widgets = {
'ou': {

View File

@ -48,7 +48,7 @@ def test_manager_role_export(app, admin, ou1, role_ou1, ou2, role_ou2):
)
rows = [row for row in reader]
assert rows[0] == ['name', 'slug', 'members', 'ou']
assert rows[0] == ['name', 'slug', 'members', 'ou', 'emails', 'emails_to_members']
assert len(rows) - 2 == 2 # csv header and last EOL
assert {row[1] for row in rows[1:3]} == {'role_ou1', 'role_ou2'}
assert {row[3] for row in rows[1:3]} == {'OU1', 'OU2'}
@ -69,7 +69,7 @@ def test_manager_role_export(app, admin, ou1, role_ou1, ou2, role_ou2):
)
rows = [row for row in reader]
assert rows[0] == ['name', 'slug', 'members', 'ou']
assert rows[0] == ['name', 'slug', 'members', 'ou', 'emails', 'emails_to_members']
assert len(rows) - 2 == 1 # csv header and last EOL
assert rows[1][1] == 'role_ou1'
@ -379,6 +379,25 @@ def test_manager_role_csv_import(app, admin, ou1, ou2):
resp = resp.form.submit()
assert 'Invalid slug "invalid slug". (line 2)' in resp.pyquery('.error').text()
csv_header = b'name,slug,ou,emails,emails_to_members\n'
csv_content = f'''Role Name,role_slug,{ou1.slug},foo@example.net bar@example.net,false
Other role,other,{ou1.slug},foo@example.net bar@example.net,yes'''
resp.form['import_file'] = Upload('t.csv', csv_header + csv_content.encode(), 'text/csv')
resp.form.submit(status=302)
assert set(Role.objects.get(name='Role Name', slug='role_slug', ou=ou1).emails) == {
'foo@example.net',
'bar@example.net',
}
assert not Role.objects.get(name='Role Name', slug='role_slug', ou=ou1).emails_to_members
assert set(Role.objects.get(name='Other role').emails) == {'foo@example.net', 'bar@example.net'}
assert Role.objects.get(slug='other').emails_to_members
csv_header = b'name,slug,ou,emails,emails_to_members\n'
csv_content = f'''Role Name,role_slug,{ou1.slug},foo#@example.net xyz'''
resp.form['import_file'] = Upload('t.csv', csv_header + csv_content.encode(), 'text/csv')
resp = resp.form.submit()
assert str(resp).count('Invalid email') == 2
resp = app.get('/manage/roles/csv-import/')
resp = resp.click('Download sample')
assert 'name,slug,ou' in resp.text