From adfd5ee56e9d075d5c5d7c488e050285d3c94473 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20P=C3=A9ters?= Date: Sun, 8 Nov 2015 19:44:08 +0100 Subject: [PATCH] formdata: move submission channel to its own attribute (#8888) --- tests/test_api.py | 5 ++-- tests/test_backoffice_pages.py | 10 ++++---- tests/test_sql.py | 54 ++++++++++++++++++++++++++++++++++++++++++ wcs/api.py | 1 + wcs/backoffice/management.py | 9 +++---- wcs/backoffice/submission.py | 8 ++----- wcs/formdata.py | 7 ++++++ wcs/sql.py | 15 ++++++++---- 8 files changed, 87 insertions(+), 22 deletions(-) diff --git a/tests/test_api.py b/tests/test_api.py index 3d681e4..c98c988 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -348,11 +348,12 @@ def test_formdef_submit(pub, local_user): assert data_class.get(resp.json['data']['id']).status == 'draft' resp = get_app(pub).post_json(url, {'meta': {'backoffice-submission': True}, 'data': {}, - 'context': {'channel': 'mail'} }) + 'context': {'channel': 'mail', 'comments': 'blah'} }) 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 == {'channel': 'mail'} + assert data_class.get(resp.json['data']['id']).submission_context == {'comments': 'blah'} + assert data_class.get(resp.json['data']['id']).submission_channel == 'mail' data_class.wipe() diff --git a/tests/test_backoffice_pages.py b/tests/test_backoffice_pages.py index f0768aa..4730088 100644 --- a/tests/test_backoffice_pages.py +++ b/tests/test_backoffice_pages.py @@ -458,8 +458,8 @@ def test_backoffice_submission_context(pub): # check there's nothing in the sidebar assert not 'Channel' in resp.body + number31.submission_channel = 'mail' number31.submission_context = { - 'channel': 'mail', 'mail_url': 'http://www.example.com/test.pdf', 'thumbnail_url': 'http://www.example.com/thumbnail.png', 'user_id': user.id, @@ -746,7 +746,7 @@ def test_backoffice_submission_drafts(pub): resp = app.get('/backoffice/submission/') assert '%s/%s' % (formdef.url_name, formdata_no) in resp.body assert '>#%s' % formdata_no in resp.body - formdata.submission_context = {'channel': 'mail'} + formdata.submission_channel = 'mail' formdata.store() resp = app.get('/backoffice/submission/') assert '>Mail #%s' % formdata_no in resp.body @@ -816,14 +816,16 @@ def test_backoffice_submission_prefill_user_via_formula(pub): formdata.backoffice_submission = True formdata.status = 'draft' formdata.data = {} - formdata.submission_context = {'channel': 'mail', 'user_id': other_user.id} + formdata.submission_channel = 'mail' + formdata.submission_context = {'user_id': other_user.id} formdata.store() formdata2 = formdef.data_class()() formdata2.backoffice_submission = True formdata2.status = 'draft' formdata2.data = {} - formdata2.submission_context = {'channel': 'mail'} + formdata.submission_channel = 'mail' + formdata2.submission_context = {} formdata2.store() app = login(get_app(pub)) diff --git a/tests/test_sql.py b/tests/test_sql.py index 0b1e020..a112ce9 100644 --- a/tests/test_sql.py +++ b/tests/test_sql.py @@ -110,6 +110,22 @@ def test_sql_get(): formdata = data_class.get(id) assert formdata.user_id == '5' + assert formdata.status == 'wf-0' + +@postgresql +def test_sql_store_channel(): + data_class = formdef.data_class(mode='sql') + formdata = data_class() + formdata.status = 'wf-0' + formdata.user_id = '5' + formdata.submission_channel = 'mail' + formdata.store() + + assert data_class.get(formdata.id).submission_channel == 'mail' + + formdata.submission_channel = None + formdata.store() + assert data_class.get(formdata.id).submission_channel is None @postgresql def test_sql_get_missing(): @@ -721,6 +737,11 @@ def test_sql_level(): conn.commit() cur.close() +def migration_level(cur): + cur.execute('SELECT value FROM wcs_meta WHERE key = %s', ('sql_level',)) + row = cur.fetchone() + return int(row[0]) + @postgresql def test_migration_1_tracking_code(): conn, cur = sql.get_connection_and_cursor() @@ -729,6 +750,7 @@ def test_migration_1_tracking_code(): sql.migrate() assert table_exists(cur, 'tracking_codes') assert table_exists(cur, 'wcs_meta') + assert migration_level(cur) >= 1 conn.commit() cur.close() @@ -770,6 +792,7 @@ def test_migration_2_formdef_id_in_views(): sql.migrate() assert column_exists_in_table(cur, 'wcs_all_forms', 'formdef_id') + assert migration_level(cur) >= 2 conn.commit() cur.close() @@ -794,6 +817,32 @@ def test_migration_6_actions_roles(): assert column_exists_in_table(cur, 'formdata_1_tests', 'actions_roles_array') assert column_exists_in_table(cur, 'wcs_view_1_tests', 'actions_roles_array') assert column_exists_in_table(cur, 'wcs_all_forms', 'actions_roles_array') + assert migration_level(cur) >= 6 + + conn.commit() + cur.close() + +@postgresql +def test_migration_10_submission_channel(): + conn, cur = sql.get_connection_and_cursor() + cur.execute('UPDATE wcs_meta SET value = 9 WHERE key = %s', ('sql_level',)) + cur.execute('DROP VIEW wcs_all_forms') + + # hack a formdef table the wrong way, to check it is reconstructed + # properly before the views are created + formdef.fields[4] = fields.StringField(id='4', label='item') + cur.execute('DROP VIEW wcs_view_1_tests') + cur.execute('ALTER TABLE formdata_1_tests DROP COLUMN submission_channel') + sql.drop_views(formdef, conn, cur) + formdef.fields[4] = fields.ItemField(id='4', label='item', items=('apple', 'pear', 'peach', 'apricot')), + assert not column_exists_in_table(cur, 'formdata_1_tests', 'submission_channel') + + sql.migrate() + + assert column_exists_in_table(cur, 'formdata_1_tests', 'submission_channel') + assert column_exists_in_table(cur, 'wcs_view_1_tests', 'submission_channel') + assert column_exists_in_table(cur, 'wcs_all_forms', 'submission_channel') + assert migration_level(cur) >= 10 conn.commit() cur.close() @@ -910,6 +959,8 @@ def test_select_any_formdata(): # set receipt_time to make sure all entries are unique. formdata.receipt_time = (now + datetime.timedelta(seconds=cnt)).timetuple() formdata.status = ['wf-new', 'wf-accepted', 'wf-rejected', 'wf-finished'][(i+j)%4] + if j < 5: + formdata.submission_channel = 'mail' formdata.store() cnt += 1 @@ -936,6 +987,9 @@ def test_select_any_formdata(): objects2 = sql.AnyFormData.select([st.Equal('is_at_endpoint', True)]) assert len(objects2) == len([x for x in objects if x.status in ('wf-rejected', 'wf-finished')]) + objects2 = sql.AnyFormData.select([st.Equal('submission_channel', 'mail')]) + assert len(objects2) == len([x for x in objects if x.submission_channel == 'mail']) + # test offset/limit objects2 = sql.AnyFormData.select(order_by='receipt_time', limit=10, offset=0) assert [(x.formdef_id, x.id) for x in objects2] == [(x.formdef_id, x.id) for x in objects][:10] diff --git a/wcs/api.py b/wcs/api.py index 9b8ca2a..94d512c 100644 --- a/wcs/api.py +++ b/wcs/api.py @@ -234,6 +234,7 @@ class ApiFormdefDirectory(Directory): formdata.user_id = user.id if json_input.get('context'): formdata.submission_context = json_input['context'] + formdata.submission_channel = formdata.submission_context.pop('channel') formdata.store() if self.formdef.enable_tracking_codes: code = get_publisher().tracking_code_class() diff --git a/wcs/backoffice/management.py b/wcs/backoffice/management.py index c8e919a..a5ae881 100644 --- a/wcs/backoffice/management.py +++ b/wcs/backoffice/management.py @@ -1291,15 +1291,12 @@ class FormBackOfficeStatusPage(FormStatusPage): formdata = self.filled r = TemplateIO(html=True) - if formdata.submission_context: + if formdata.submission_context or formdata.submission_channel: extra_context = formdata.submission_context or {} r += htmltext('
') - if extra_context.get('channel'): - channel_labels = { - 'mail': _('Mail'), - } + if formdata.submission_channel: r += htmltext('

%s

') % '%s: %s' % ( - _('Channel'), channel_labels.get(extra_context.get('channel'), '?')) + _('Channel'), formdata.get_submission_channel_label()) if extra_context.get('thumbnail_url'): r += htmltext('

' ) % extra_context.get('thumbnail_url') diff --git a/wcs/backoffice/submission.py b/wcs/backoffice/submission.py index 64586b8..ba433be 100644 --- a/wcs/backoffice/submission.py +++ b/wcs/backoffice/submission.py @@ -206,12 +206,8 @@ class SubmissionDirectory(Directory): for formdata in formdatas: r += htmltext('
  • ') label = '' - if formdata.submission_context and formdata.submission_context.get('channel'): - label = { - 'mail': _('Mail'), - }.get(formdata.submission_context['channel']) or '' - if label: - label += ' ' + if formdata.submission_channel: + label = '%s ' % formdata.get_submission_channel_label() label += _('#%s, %s') % (formdata.id, misc.localstrftime(formdata.receipt_time)) r += htmltext('%s') % ( diff --git a/wcs/formdata.py b/wcs/formdata.py index 1c7ab23..f48b860 100644 --- a/wcs/formdata.py +++ b/wcs/formdata.py @@ -162,6 +162,7 @@ class FormData(StorableObject): tracking_code = None backoffice_submission = False submission_context = None + submission_channel = None workflow_data = None workflow_roles = None @@ -228,6 +229,12 @@ class FormData(StorableObject): empty &= (self.data.get(key) is None) return empty + def get_submission_channel_label(self): + channel_labels = { + 'mail': _('Mail'), + } + return channel_labels.get(self.submission_channel, _('Unknown')) + def just_created(self): self.receipt_time = time.localtime() self.status = 'wf-%s' % self.formdef.workflow.possible_status[0].id diff --git a/wcs/sql.py b/wcs/sql.py index 8d30e0d..e331bbf 100644 --- a/wcs/sql.py +++ b/wcs/sql.py @@ -309,7 +309,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_context', 'submission_channel']) # migrations if not 'fts' in existing_fields: @@ -341,6 +341,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 not 'submission_channel' in existing_fields: + cur.execute('''ALTER TABLE %s ADD COLUMN submission_channel varchar''' % table_name) + # add new fields for field in formdef.fields: assert field.id is not None @@ -538,7 +541,8 @@ def get_view_fields(formdef): view_fields = [] 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', 'user_hash', 'receipt_time', 'status', 'id_display'): + for field in ('id', 'user_id', 'user_hash', 'receipt_time', 'status', + 'id_display', 'submission_channel'): view_fields.append((field, field)) return view_fields @@ -938,6 +942,7 @@ class SqlFormData(SqlMixin, wcs.formdata.FormData): ('tracking_code', 'varchar'), ('backoffice_submission', 'boolean'), ('submission_context', 'bytea'), + ('submission_channel', 'varchar'), ] def __init__(self, id=None): @@ -1031,6 +1036,7 @@ class SqlFormData(SqlMixin, wcs.formdata.FormData): 'tracking_code': self.tracking_code, 'backoffice_submission': self.backoffice_submission, 'submission_context': self.submission_context, + 'submission_channel': self.submission_channel, } if self.receipt_time: sql_dict['receipt_time'] = datetime.datetime.fromtimestamp(time.mktime(self.receipt_time)), @@ -1679,7 +1685,7 @@ def get_yearly_totals(period_start=None, period_end=None, criterias=None): return result -SQL_LEVEL = 8 +SQL_LEVEL = 10 def migrate_global_views(conn, cur): cur.execute('''SELECT COUNT(*) FROM information_schema.tables @@ -1728,10 +1734,11 @@ def migrate(): migrate_views(conn, cur) for formdef in FormDef.select(): formdef.data_class().rebuild_security() - if sql_level < 9: + if sql_level < 10: # 7: add backoffice_submission to tables and views # 8: add submission_context to tables # 9: add last_update_time to views + # 10: add submission_channel to tables migrate_views(conn, cur) cur.execute('''UPDATE wcs_meta SET value = %s WHERE key = %s''', ( -- 2.6.2