cards: extend "update cards" checkbox to CSV imports (#88294)
gitea/wcs/pipeline/head Build queued... Details

This commit is contained in:
Frédéric Péters 2024-03-20 16:34:25 +01:00
parent 69249df789
commit 520e52d1a7
2 changed files with 81 additions and 9 deletions

View File

@ -681,6 +681,58 @@ def test_backoffice_cards_import_data_csv_no_backoffice_fields(pub):
assert carddef.data_class().count() == 2
def test_backoffice_cards_import_data_csv_custom_id_no_update(pub):
user = create_user(pub)
user.name_identifiers = [str(uuid.uuid4())]
user.store()
Workflow.wipe()
workflow = Workflow(name='form-title')
workflow.backoffice_fields_formdef = WorkflowBackofficeFieldsFormDef(workflow)
workflow.backoffice_fields_formdef.fields = [
fields.StringField(id='bo0', varname='foo_bovar', label='bo variable'),
]
workflow.add_status('st0')
workflow.store()
CardDef.wipe()
carddef = CardDef()
carddef.name = 'test'
carddef.fields = [
fields.StringField(id='1', label='String', varname='custom_id'),
fields.ItemField(id='2', label='List', items=['item1', 'item2']),
]
carddef.backoffice_submission_roles = user.roles
carddef.id_template = '{{form_var_custom_id}}'
carddef.workflow = workflow
carddef.store()
carddef.data_class().wipe()
card = carddef.data_class()()
card.data = {'1': 'plop', '2': 'test', '2_display': 'test', 'bo0': 'xxx'}
card.just_created()
card.store()
app = login(get_app(pub))
data = b'''\
"String","List"
"plop","item1"
"test","item2"
'''
resp = app.get('/backoffice/data/test/import-file')
resp.forms[0]['file'] = Upload('test.csv', data, 'text/csv')
resp.form['update_existing_cards'].checked = False
resp = resp.forms[0].submit().follow()
assert carddef.data_class().count() == 2
card.refresh_from_storage()
assert card.data == {'1': 'plop', '2': 'test', '2_display': 'test', 'bo0': 'xxx'} # no change
other_card = carddef.data_class().select(order_by='-receipt_time')[0]
assert other_card.data == {'1': 'test', '2': 'item2', '2_display': 'item2', 'bo0': None}
assert other_card.id_display == 'test'
def test_backoffice_cards_import_data_csv_custom_id_update(pub):
user = create_user(pub)
user.name_identifiers = [str(uuid.uuid4())]
@ -721,6 +773,7 @@ def test_backoffice_cards_import_data_csv_custom_id_update(pub):
'''
resp = app.get('/backoffice/data/test/import-file')
resp.forms[0]['file'] = Upload('test.csv', data, 'text/csv')
resp.form['update_existing_cards'].checked = True
resp = resp.forms[0].submit().follow()
assert carddef.data_class().count() == 2

View File

@ -228,10 +228,16 @@ class CardPage(FormPage):
form.add(
CheckboxWidget,
'update_existing_cards',
title=_('Update existing cards (only for JSON imports)'),
title=_('Update existing cards (only for JSON imports)')
if not self.formdef.id_template
else _('Update existing cards'),
hint=_('Cards will be matched using their unique identifier ("uuid" property).')
if not self.formdef.id_template
else _('Cards will be matched using their custom identifier ("id" property).'),
else _(
'Cards will be matched using their custom identifier ("id" property). '
'If this option is enabled cards with the same identifiers will be updated, '
'otherwise they will be skipped.'
),
value=False,
)
form.add_submit('submit', _('Submit'))
@ -241,19 +247,22 @@ class CardPage(FormPage):
if form.is_submitted() and not form.has_errors():
file_content = form.get_widget('file').parse().fp.read()
update_existing_cards = form.get_widget('update_existing_cards').parse()
try:
json_content = json.loads(file_content)
except ValueError:
# not json -> CSV
try:
return self.import_csv_submit(file_content, submission_agent_id=get_request().user.id)
return self.import_csv_submit(
file_content,
update_existing_cards=update_existing_cards,
submission_agent_id=get_request().user.id,
)
except ValueError as e:
form.set_error('file', e)
else:
try:
return self.import_json_submit(
json_content, update_existing_cards=form.get_widget('update_existing_cards').parse()
)
return self.import_json_submit(json_content, update_existing_cards=update_existing_cards)
except ValueError as e:
form.set_error('file', e)
@ -275,7 +284,9 @@ class CardPage(FormPage):
impossible_fields.append(field.label)
return impossible_fields
def import_csv_submit(self, content, afterjob=True, api=False, submission_agent_id=None):
def import_csv_submit(
self, content, afterjob=True, api=False, update_existing_cards=False, submission_agent_id=None
):
if b'\0' in content:
raise ValueError(_('Invalid file format.'))
@ -328,7 +339,10 @@ class CardPage(FormPage):
raise ValueError(error_message)
job = ImportFromCsvAfterJob(
carddef=self.formdef, data_lines=data_lines, submission_agent_id=submission_agent_id
carddef=self.formdef,
data_lines=data_lines,
update_existing_cards=update_existing_cards,
submission_agent_id=submission_agent_id,
)
if afterjob:
get_response().add_after_job(job)
@ -432,12 +446,13 @@ class CardBackOfficeStatusPage(FormBackOfficeStatusPage):
class ImportFromCsvAfterJob(AfterJob):
def __init__(self, carddef, data_lines, submission_agent_id):
def __init__(self, carddef, data_lines, update_existing_cards, submission_agent_id):
super().__init__(
label=_('Importing data into cards'),
carddef_class=carddef.__class__,
carddef_id=carddef.id,
data_lines=data_lines,
update_existing_cards=update_existing_cards,
submission_agent_id=submission_agent_id,
)
@ -448,6 +463,7 @@ class ImportFromCsvAfterJob(AfterJob):
def execute(self):
self.carddef = self.kwargs['carddef_class'].get(self.kwargs['carddef_id'])
update_existing_cards = self.kwargs['update_existing_cards']
carddata_class = self.carddef.data_class()
self.submission_agent_id = self.kwargs['submission_agent_id']
self.total_count = len(self.kwargs['data_lines'])
@ -507,6 +523,9 @@ class ImportFromCsvAfterJob(AfterJob):
except KeyError:
pass # unique id, fine
else:
if not update_existing_cards:
self.increment_count()
continue
# overwrite (only fields from CSV columns, not unsupported or backoffice fields)
new_card = False
orig_data = copy.copy(carddata_with_same_id.data)