formdata: move submission agent id to a dedicated attribute/column (#45072)

This commit is contained in:
Frédéric Péters 2020-07-13 15:33:39 +02:00
parent 2f030fd345
commit eef24c155c
12 changed files with 87 additions and 36 deletions

View File

@ -713,7 +713,7 @@ def test_formdef_submit(pub, local_user):
assert data_class.get(resp.json['data']['id']).status == 'wf-new'
assert data_class.get(resp.json['data']['id']).backoffice_submission is True
assert data_class.get(resp.json['data']['id']).user_id is None
assert data_class.get(resp.json['data']['id']).submission_context.get('agent_id') == local_user.id
assert data_class.get(resp.json['data']['id']).submission_agent_id == str(local_user.id)
formdef.enable_tracking_codes = True
formdef.store()
@ -729,7 +729,7 @@ def test_formdef_submit(pub, local_user):
assert data_class.get(resp.json['data']['id']).backoffice_submission is True
assert data_class.get(resp.json['data']['id']).user_id is None
assert data_class.get(resp.json['data']['id']).submission_context == {
'comments': 'blah', 'agent_id': local_user.id}
'comments': 'blah'}
assert data_class.get(resp.json['data']['id']).submission_channel == 'mail'
data_class.wipe()

View File

@ -613,7 +613,7 @@ def test_backoffice_submission_agent_column(pub):
assert not ',agent,' in resp.text
for formdata in formdef.data_class().select():
formdata.submission_context = {'agent_id': agent.id}
formdata.submission_agent_id = str(agent.id)
formdata.store()
resp = app.get('/backoffice/management/form-title/')
@ -1902,8 +1902,8 @@ def test_backoffice_submission_context(pub):
'thumbnail_url': 'http://www.example.com/thumbnail.png',
'comments': 'test_backoffice_submission_context',
'summary_url': 'http://www.example.com/summary',
'agent_id': user.id,
}
number31.submission_agent_id = str(user.id)
number31.store()
resp = app.get('/backoffice/management/form-title/')
resp = resp.click(href='%s/' % number31.id)
@ -2288,14 +2288,14 @@ def test_backoffice_submission_with_tracking_code(pub):
assert formdata.tracking_code in resp.text
# check access by different user
formdata.submission_context = {'agent_id': '10000'}
formdata.submission_agent_id = '10000'
formdata.store()
resp = app.get(formdata_location)
assert 'test submission' in resp.text
assert not formdata.tracking_code in resp.text
# restore user
formdata.submission_context = {'agent_id': user.id}
formdata.submission_agent_id = str(user.id)
formdata.store()
resp = app.get(formdata_location)
assert formdata.tracking_code in resp.text
@ -2331,7 +2331,7 @@ def test_backoffice_submission_welco(pub, welco_url):
formdata.data = {}
formdata.status = 'draft'
formdata.backoffice_submission = True
formdata.submission_context = {'agent_id': user.id}
formdata.submission_agent_id = str(user.id)
formdata.store()
resp = app.get('/backoffice/')
@ -2451,7 +2451,7 @@ def test_backoffice_parallel_submission(pub):
formdata.data = {}
formdata.status = 'draft'
formdata.backoffice_submission = True
formdata.submission_context = {'agent_id': user.id}
formdata.submission_agent_id = str(user.id)
formdata.store()
resp = app.get('/backoffice/submission/')
@ -5958,7 +5958,7 @@ def test_carddata_management(pub, studio):
carddata = carddef.data_class().select()[0]
assert carddata.data == {'1': 'ok', '2': 'blah'}
assert carddata.user_id is None
assert carddata.submission_context == {'agent_id': user.id}
assert carddata.submission_agent_id == str(user.id)
assert carddata.evolution[0].who == str(user.id)
assert 'Original Submitter' not in resp.text
@ -6416,11 +6416,11 @@ def test_backoffice_create_formdata_backoffice_submission(create_formdata):
target_formdata = target_data_class.select()[0]
assert target_formdata.submission_context == {
'agent_id': str(create_formdata['admin'].id),
'orig_object_type': 'formdef',
'orig_formdata_id': '1',
'orig_formdef_id': '1'
}
assert target_formdata.submission_agent_id == str(create_formdata['admin'].id)
assert target_formdata.user.id == user.id
assert target_formdata.status == 'draft'
assert resp.location == 'http://example.net/backoffice/management/target-form/%s/' % target_formdata.id
@ -6533,11 +6533,11 @@ def test_backoffice_create_formdata_map_fields_by_varname(create_formdata):
target_formdata = target_data_class.select()[0]
assert target_formdata.submission_context == {
'agent_id': str(create_formdata['admin'].id),
'orig_object_type': 'formdef',
'orig_formdata_id': '1',
'orig_formdef_id': '1'
}
assert target_formdata.submission_agent_id == str(create_formdata['admin'].id)
assert target_formdata.user.id == user.id
assert target_formdata.status == 'draft'
assert resp.location == 'http://example.net/backoffice/management/target-form/%s/' % target_formdata.id

View File

@ -116,9 +116,9 @@ def test_submission_context(pub, local_user):
formdata = formdef.data_class()()
formdata.backoffice_submission = True
formdata.submission_channel = 'mail'
formdata.submission_agent_id = str(local_user.id)
formdata.submission_context = {
'mail_url': 'http://www.example.com/test.pdf',
'agent_id': local_user.id,
}
substvars = formdata.get_substitution_variables()
assert substvars.get('form_submission_backoffice') is True

View File

@ -15,7 +15,7 @@ from django.core.management import call_command
from quixote import cleanup
from wcs.qommon import force_str
from wcs import formdef, publisher, fields
from wcs import publisher, fields
from wcs.formdef import FormDef
from wcs.formdata import Evolution
from wcs.roles import Role
@ -43,7 +43,7 @@ def setup_module(module):
pub = create_temporary_pub(sql_mode=True)
formdef = formdef.FormDef()
formdef = FormDef()
formdef.name = 'tests'
formdef.fields = [
fields.StringField(id='0', label='string'),
@ -1966,3 +1966,41 @@ def test_migration_31_user_label():
conn.commit()
cur.close()
@postgresql
def test_migration_38_submission_agent_id():
for formdef in FormDef.select():
formdef.data_class().wipe()
data_class = formdef.data_class(mode='sql')
formdata = data_class()
formdata.data = {}
formdata.status = 'wf-0'
formdata.submission_context = {'agent_id': 12}
formdata.store()
conn, cur = sql.get_connection_and_cursor()
cur.execute('UPDATE wcs_meta SET value = 37 WHERE key = %s', ('sql_level',))
cur.execute('DROP VIEW wcs_all_forms CASCADE')
cur.execute('DROP VIEW wcs_view_1_tests')
cur.execute('ALTER TABLE formdata_1_tests DROP COLUMN submission_agent_id')
sql.drop_views(formdef, conn, cur)
assert not column_exists_in_table(cur, 'formdata_1_tests', 'submission_agent_id')
sql.migrate()
assert sql.is_reindex_needed('formdata', conn=conn, cur=cur) is True
assert column_exists_in_table(cur, 'formdata_1_tests', 'submission_agent_id')
assert column_exists_in_table(cur, 'wcs_view_1_tests', 'submission_agent_id')
assert column_exists_in_table(cur, 'wcs_all_forms', 'submission_agent_id')
assert migration_level(cur) >= 38
sql.reindex()
cur.execute('''SELECT submission_agent_id FROM wcs_all_forms WHERE id = %s ''', (formdata.id,))
assert cur.fetchone()[0] == '12'
conn.commit()
cur.close()

View File

@ -419,9 +419,7 @@ class ApiFormdefDirectory(Directory):
if meta.get('backoffice-submission'):
# keep track of the agent that did the submit
if not formdata.submission_context:
formdata.submission_context = {}
formdata.submission_context['agent_id'] = user.id
formdata.submission_agent_id = str(user.id)
formdata.store()
if self.formdef.enable_tracking_codes:

View File

@ -2587,8 +2587,8 @@ class FormBackOfficeStatusPage(FormStatusPage):
if not formdata.is_draft():
r += htmltext('<div class="extra-context">')
if (formdata.backoffice_submission and formdata.submission_context and
formdata.submission_context.get('agent_id') == get_request().user.id and
if (formdata.backoffice_submission and
formdata.submission_agent_id == str(get_request().user.id) and
formdata.tracking_code and
time.time() - time.mktime(formdata.receipt_time) < 30*60):
# keep displaying tracking code to submission agent for 30
@ -2600,9 +2600,9 @@ class FormBackOfficeStatusPage(FormStatusPage):
r += htmltext('<p>')
tm = misc.localstrftime(formdata.receipt_time)
agent_user = None
if formdata.submission_context and 'agent_id' in formdata.submission_context:
if formdata.submission_agent_id:
agent_user = get_publisher().user_class.get(
formdata.submission_context['agent_id'], ignore_errors=True)
formdata.submission_agent_id, ignore_errors=True)
if agent_user:
r += _(self.sidebar_recorded_by_agent_message) % {

View File

@ -108,7 +108,8 @@ class FormFillPage(PublicFormFillPage):
formdata.data = {}
formdata.backoffice_submission = True
formdata.submission_channel = submission_channel or ''
formdata.submission_context = {'agent_id': get_request().user.id}
formdata.submission_agent_id = str(get_request().user.id)
formdata.submission_context = {}
formdata.status = 'draft'
formdata.receipt_time = time.localtime()
if name_id:
@ -227,7 +228,7 @@ class FormFillPage(PublicFormFillPage):
filled.submission_context = {}
if self.selected_submission_channel:
filled.submission_channel = self.selected_submission_channel
filled.submission_context['agent_id'] = get_request().user.id
filled.submission_agent_id = str(get_request().user.id)
filled.store()
self.set_tracking_code(filled)
@ -264,7 +265,7 @@ class FormFillPage(PublicFormFillPage):
formdata.backoffice_submission = True
if not formdata.submission_context:
formdata.submission_context = {}
formdata.submission_context['agent_id'] = get_request().user.id
formdata.submission_agent_id = str(get_request().user.id)
formdata.store()
return formdata
@ -390,9 +391,9 @@ class SubmissionDirectory(Directory):
label = '%s ' % formdata.get_submission_channel_label()
label += _('#%(id)s, %(time)s') % {'id': formdata.id,
'time': misc.localstrftime(formdata.receipt_time)}
if formdata.submission_context and 'agent_id' in formdata.submission_context:
if formdata.submission_agent_id:
agent_user = get_publisher().user_class.get(
formdata.submission_context['agent_id'], ignore_errors=True)
formdata.submission_agent_id, ignore_errors=True)
if agent_user:
label += ' (%s)' % agent_user.display_name
r += htmltext('<a href="%s/%s/">%s</a>') % (

View File

@ -53,5 +53,5 @@ class CardData(FormData):
def just_created(self):
super(CardData, self).just_created()
if self.submission_context and 'agent_id' in self.submission_context:
self.evolution[0].who = self.submission_context['agent_id']
if self.submission_agent_id:
self.evolution[0].who = self.submission_agent_id

View File

@ -238,6 +238,7 @@ class FormData(StorableObject):
editable_by = None
tracking_code = None
backoffice_submission = False
submission_agent_id = None
submission_context = None
submission_channel = None
criticality_level = 0
@ -274,6 +275,10 @@ class FormData(StorableObject):
if evo.status and not evo.status.startswith('wf-'):
evo.status = 'wf-%s' % evo.status
changed = True
if not self.submission_agent_id and self.submission_context and self.submission_context.get('agent_id'):
self.submission_agent_id = str(self.submission_context.get('agent_id'))
changed = True
if changed:
self.store()
@ -658,7 +663,7 @@ class FormData(StorableObject):
return self.get_submission_channel_label()
if field.type == 'submission_agent':
try:
agent_user = self.submission_context['agent_id']
agent_user = self.submission_agent_id
return get_publisher().user_class.get(agent_user).display_name
except (KeyError, TypeError):
return '-'

View File

@ -480,7 +480,7 @@ def do_formdef_tables(formdef, conn=None, cur=None, rebuild_views=False, rebuild
'anonymised', 'workflow_roles', 'workflow_roles_array',
'concerned_roles_array', 'tracking_code',
'actions_roles_array', 'backoffice_submission',
'submission_context', 'submission_channel',
'submission_context', 'submission_agent_id', 'submission_channel',
'criticality_level', 'last_update_time',
'digest', 'user_label'])
@ -514,6 +514,9 @@ def do_formdef_tables(formdef, conn=None, cur=None, rebuild_views=False, rebuild
if not 'submission_context' in existing_fields:
cur.execute('''ALTER TABLE %s ADD COLUMN submission_context bytea''' % table_name)
if 'submission_agent_id' not in existing_fields:
cur.execute('''ALTER TABLE %s ADD COLUMN submission_agent_id varchar''' % table_name)
if not 'submission_channel' in existing_fields:
cur.execute('''ALTER TABLE %s ADD COLUMN submission_channel varchar''' % table_name)
@ -871,7 +874,7 @@ def get_view_fields(formdef):
view_fields.append(("int '%s'" % (formdef.category_id or 0), 'category_id'))
view_fields.append(("int '%s'" % (formdef.id or 0), 'formdef_id'))
for field in ('id', 'user_id', 'receipt_time', 'status',
'id_display', 'submission_channel', 'backoffice_submission',
'id_display', 'submission_agent_id', 'submission_channel', 'backoffice_submission',
'last_update_time', 'digest', 'user_label'):
view_fields.append((field, field))
return view_fields
@ -1403,6 +1406,7 @@ class SqlDataMixin(SqlMixin):
('tracking_code', 'varchar'),
('backoffice_submission', 'boolean'),
('submission_context', 'bytea'),
('submission_agent_id', 'varchar'),
('submission_channel', 'varchar'),
('criticality_level', 'int'),
('last_update_time', 'timestamp'),
@ -1502,6 +1506,7 @@ class SqlDataMixin(SqlMixin):
'tracking_code': self.tracking_code,
'backoffice_submission': self.backoffice_submission,
'submission_context': self.submission_context,
'submission_agent_id': self.submission_agent_id,
'submission_channel': self.submission_channel,
'criticality_level': self.criticality_level,
}
@ -2491,7 +2496,7 @@ def get_yearly_totals(period_start=None, period_end=None, criterias=None):
return result
SQL_LEVEL = 37
SQL_LEVEL = 38
def migrate_global_views(conn, cur):
@ -2565,7 +2570,7 @@ def migrate():
raise RuntimeError()
if sql_level < 1: # 1: introduction of tracking_code table
do_tracking_code_table()
if sql_level < 33:
if sql_level < 38:
# 2: introduction of formdef_id in views
# 5: add concerned_roles_array, is_at_endpoint and fts to views
# 7: add backoffice_submission to tables
@ -2583,6 +2588,7 @@ def migrate():
# 27: add last_jump_datetime in evolutions tables
# 31: add user_label to formdata
# 33: add anonymised field to global view
# 38: extract submission_agent_id to its own column
migrate_views(conn, cur)
if sql_level < 21:
# 3: introduction of _structured for user fields
@ -2602,7 +2608,7 @@ def migrate():
# 21: (second part), store ascii_name of users
# 23: (first part), use misc.simplify() over full text queries
set_reindex('user', 'needed', conn=conn, cur=cur)
if sql_level < 31:
if sql_level < 38:
# 17: store last_update_time in tables
# 18: add user name to full-text search index
# 21: (third part), add user ascii_names to full-text index
@ -2610,6 +2616,7 @@ def migrate():
# 28: add display id and formdef name to full-text index
# 29: add evolution parts to full-text index
# 31: add user_label to formdata
# 38: extract submission_agent_id to its own column
set_reindex('formdata', 'needed', conn=conn, cur=cur)
if sql_level < 36:
from wcs.formdef import FormDef
@ -2656,6 +2663,7 @@ def reindex():
# load and store all formdatas
for formdef in FormDef.select():
for formdata in formdef.data_class().select(iterator=True):
formdata.migrate()
formdata.store()
set_reindex('formdata', 'done', conn=conn, cur=cur)

View File

@ -288,7 +288,7 @@ class LazyFormData(LazyFormDef):
@property
def submission_agent(self):
try:
return LazyUser(get_publisher().user_class.get(self._formdata.submission_context['agent_id']))
return LazyUser(get_publisher().user_class.get(self._formdata.submission_agent_id))
except (TypeError, KeyError):
return None

View File

@ -327,12 +327,13 @@ class CreateFormdataWorkflowStatusItem(WorkflowStatusItem):
if self.keep_submission_context and self.keep_user:
new_formdata.submission_context = formdata.submission_context or {}
new_formdata.submission_channel = formdata.submission_channel
new_formdata.submission_agent_id = formdata.submission_agent_id
else:
new_formdata.submission_context = {}
new_formdata.backoffice_submission = self.backoffice_submission
if self.backoffice_submission and get_request() and get_request().user is not None:
new_formdata.submission_context['agent_id'] = str(get_request().user.id)
new_formdata.submission_agent_id = str(get_request().user.id)
new_formdata.submission_context['orig_object_type'] = formdata.formdef.xml_root_node
new_formdata.submission_context['orig_formdef_id'] = str(formdata.formdef.id)