From 9a5234a66325f1a43d3582b8e87e914bbeaaa094 Mon Sep 17 00:00:00 2001 From: Benjamin Dauvergne Date: Tue, 18 Jun 2019 20:51:28 +0200 Subject: [PATCH 5/6] check self referene in keys (to rebase) --- src/authentic2/csv_import.py | 26 ++++++++++++++++++++++---- tests/test_csv_import.py | 18 ++++++++++++++++++ 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/src/authentic2/csv_import.py b/src/authentic2/csv_import.py index 9b2f18f3..8e060efc 100644 --- a/src/authentic2/csv_import.py +++ b/src/authentic2/csv_import.py @@ -276,10 +276,12 @@ class UserCsvImporter(object): self.add_error(self.csv_importer.error) def do_import(): + unique_map = {} + try: with atomic(): for row in self.rows: - if not self.do_import_row(row): + if not self.do_import_row(row, unique_map): self.rows_with_errors += 1 if simulate: raise Simulate @@ -446,13 +448,29 @@ class UserCsvImporter(object): def username_is_unique(self): return app_settings.A2_USERNAME_IS_UNIQUE or self.ou.username_is_unique - def check_unique_constraints(self, row, user=None): + def check_unique_constraints(self, row, unique_map, user=None): ou_users = User.objects.filter(ou=self.ou) users = User.objects.all() if user: users = users.exclude(pk=user.pk) ou_users = ou_users.exclude(pk=user.pk) errors = [] + for cell in row: + header = cell.header + if header.name == SOURCE_ID: + unique_key = (SOURCE_ID, row[SOURCE_NAME].value, cell.value) + elif header.key or header.globally_unique or header.unique: + unique_key = (header.name, cell.value) + else: + continue + if unique_key in unique_map: + errors.append( + Error('unique-constraint-failed', + _('Unique constraint on column "%s" failed: ' + 'value already appear on line %d') % (header.name, row.line))) + else: + unique_map[unique_key] = row.line + for cell in row: if (not cell.header.globally_unique and not cell.header.unique) or (user and not cell.header.update): continue @@ -472,7 +490,7 @@ class UserCsvImporter(object): return not bool(errors) @atomic - def do_import_row(self, row): + def do_import_row(self, row, unique_map): if not row.is_valid: return False @@ -516,7 +534,7 @@ class UserCsvImporter(object): if users: user = users[0] - if not self.check_unique_constraints(row, user=user): + if not self.check_unique_constraints(row, unique_map, user=user): return False if not user: diff --git a/tests/test_csv_import.py b/tests/test_csv_import.py index 5a7aa411..a6cb07f5 100644 --- a/tests/test_csv_import.py +++ b/tests/test_csv_import.py @@ -263,6 +263,24 @@ tnoel@entrouvert.com,Thomas,Noël,1234''' assert importer.rows[0].errors == [Error('unique-constraint-failed')] +def test_create_key_self_reference_error(profile, user_csv_importer_factory): + content = '''email key,first_name,last_name,phone +tnoel@entrouvert.com,Thomas,Noël,1234 +tnoel@entrouvert.com,Frédéric,Péters,1234''' + importer = user_csv_importer_factory(content) + + assert importer.run() + + assert importer.created == 1 + assert importer.updated == 0 + assert len(importer.rows) == 2 + assert importer.rows[0].is_valid + assert importer.rows[0].action == 'create' + assert not importer.rows[1].is_valid + assert importer.rows[1].action == 'update' + assert importer.rows[1].errors == [Error('unique-constraint-failed')] + + def test_update_unique_error(profile, user_csv_importer_factory): content = '''email key verified,first_name,last_name,phone unique update tnoel@entrouvert.com,Thomas,Noël,1234''' -- 2.20.1