diff --git a/app/assets/javascripts/preventDuplicateFormSubmissions.js b/app/assets/javascripts/preventDuplicateFormSubmissions.js new file mode 100644 index 000000000..0eca28039 --- /dev/null +++ b/app/assets/javascripts/preventDuplicateFormSubmissions.js @@ -0,0 +1,30 @@ +(function() { + + "use strict"; + + let disableSubmitButtons = function(event) { + + $submitButton = $(this).find(':submit'); + + if ($submitButton.data('clicked') == 'true') { + + event.preventDefault(); + + } else { + + $submitButton.data('clicked', 'true'); + setTimeout(renableSubmitButton($submitButton), 1500); + + } + + }; + + let renableSubmitButton = $submitButton => () => { + + $submitButton.data('clicked', ''); + + }; + + $('form').on('submit', disableSubmitButtons); + +})(); diff --git a/app/assets/stylesheets/app.scss b/app/assets/stylesheets/app.scss index 1e9d32b95..c3a1ba93b 100644 --- a/app/assets/stylesheets/app.scss +++ b/app/assets/stylesheets/app.scss @@ -180,6 +180,7 @@ details summary { th, td { @include core-19; + word-wrap: break-word; } thead { diff --git a/app/main/views/send.py b/app/main/views/send.py index 870fdcb48..757f8cbe0 100644 --- a/app/main/views/send.py +++ b/app/main/views/send.py @@ -459,15 +459,17 @@ def check_messages(service_id, template_type, upload_id): data['recipients'].too_many_rows or not data['count_of_recipients'] or not data['recipients'].has_recipient_columns or - data['recipients'].missing_column_headers or - data['trying_to_send_letters_in_trial_mode'] + data['recipients'].missing_column_headers ): return render_template('views/check/column-errors.html', **data) if data['row_errors']: return render_template('views/check/row-errors.html', **data) - if data['errors']: + if ( + data['errors'] or + data['trying_to_send_letters_in_trial_mode'] + ): return render_template('views/check/column-errors.html', **data) return render_template('views/check/ok.html', **data) diff --git a/app/templates/views/manage-users.html b/app/templates/views/manage-users.html index fb79b3b8a..373c5b3a6 100644 --- a/app/templates/views/manage-users.html +++ b/app/templates/views/manage-users.html @@ -53,7 +53,7 @@ ) }} {{ tick_cross( user.has_permissions(permissions=['manage_templates']), - 'Manage templates' + 'Add and edit templates' ) }} {{ tick_cross( user.has_permissions(permissions=['manage_users', 'manage_settings']), @@ -94,7 +94,7 @@ ) }} {{ tick_cross( user.has_permissions(permissions=['manage_templates']), - 'Edit templates' + 'Add and edit templates' ) }} {{ tick_cross( user.has_permissions(permissions=['manage_users', 'manage_settings']), diff --git a/gulpfile.babel.js b/gulpfile.babel.js index 26dd6c96b..9ecc9c15d 100644 --- a/gulpfile.babel.js +++ b/gulpfile.babel.js @@ -67,6 +67,7 @@ gulp.task('javascripts', () => gulp paths.src + 'javascripts/listEntry.js', paths.src + 'javascripts/liveSearch.js', paths.src + 'javascripts/errorTracking.js', + paths.src + 'javascripts/preventDuplicateFormSubmissions.js', paths.src + 'javascripts/main.js' ]) .pipe(plugins.prettyerror()) diff --git a/requirements.txt b/requirements.txt index 0b1bd52a6..25d4a1360 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,21 +1,18 @@ ago==0.0.9 -cffi==1.10.0 +cffi==1.11.0 Flask==0.12.2 Flask-Script==2.0.5 Flask-WTF==0.14.2 Flask-Login==0.4.0 boto3==1.4.7 -py-gfm==0.1.3 blinker==1.4 -lxml==3.8.0 pyexcel==0.5.3 pyexcel-io==0.5.1 pyexcel-xls==0.5.0 pyexcel-xlsx==0.5.0.1 pyexcel-ods3==0.5.0 pytz==2017.2 -six==1.10.0 gunicorn==19.7.1 whitenoise==3.3.0 #manages static assets diff --git a/requirements_for_test.txt b/requirements_for_test.txt index 9abf5197e..ea72849ef 100644 --- a/requirements_for_test.txt +++ b/requirements_for_test.txt @@ -1,7 +1,7 @@ -r requirements.txt pycodestyle==2.3.1 pytest==3.2.2 -pytest-mock==1.6.2 +pytest-mock==1.6.3 pytest-cov==2.5.1 pytest-xdist==1.20.0 coveralls==1.2.0 diff --git a/tests/app/main/views/test_manage_users.py b/tests/app/main/views/test_manage_users.py index ce97036f0..2766cd032 100644 --- a/tests/app/main/views/test_manage_users.py +++ b/tests/app/main/views/test_manage_users.py @@ -19,21 +19,21 @@ from tests.conftest import ( active_user_with_permissions, ( 'Test User (you) ' - 'Can Send messages Can Manage templates Can Manage service Can Access API keys' + 'Can Send messages Can Add and edit templates Can Manage service Can Access API keys' ), ), ( active_user_view_permissions, ( 'Test User With Permissions (you) ' - 'Can’t Send messages Can’t Manage templates Can’t Manage service Can’t Access API keys' + 'Can’t Send messages Can’t Add and edit templates Can’t Manage service Can’t Access API keys' ), ), ( active_user_manage_template_permission, ( 'Test User With Permissions (you) ' - 'Can’t Send messages Can Manage templates Can’t Manage service Can’t Access API keys' + 'Can’t Send messages Can Add and edit templates Can’t Manage service Can’t Access API keys' ), ), ]) @@ -255,7 +255,7 @@ def test_manage_users_shows_invited_user( assert page.h1.string.strip() == 'Team members' assert normalize_spaces(page.select('.user-list')[1].text) == ( 'invited_user@test.gov.uk ' - 'Can’t Send messages Can’t Edit templates Can’t Manage service Can Access API keys ' + 'Can’t Send messages Can’t Add and edit templates Can’t Manage service Can Access API keys ' 'Cancel invitation' ) diff --git a/tests/app/main/views/test_send.py b/tests/app/main/views/test_send.py index d80548416..45e6b4b44 100644 --- a/tests/app/main/views/test_send.py +++ b/tests/app/main/views/test_send.py @@ -1631,6 +1631,38 @@ def test_check_messages_shows_trial_mode_error_for_letters( assert not error +def test_check_messages_shows_data_errors_before_trial_mode_errors_for_letters( + mocker, + client_request, + mock_get_service_letter_template, + mock_has_permissions, + mock_get_users_by_service, + mock_get_detailed_service_for_today, +): + + mocker.patch('app.main.views.send.s3download', return_value='\n'.join( + ['address_line_1,address_line_2,postcode,'] + + [' , ,11SW1 1AA'] + )) + + with client_request.session_transaction() as session: + session['upload_data'] = {'template_id': '', 'original_file_name': 'example.xlsx'} + + page = client_request.get( + 'main.check_messages', + service_id=SERVICE_ONE_ID, + template_type='letter', + upload_id=uuid.uuid4(), + _test_page_title=False, + ) + + assert normalize_spaces(page.select_one('.banner-dangerous').text) == ( + 'There is a problem with example.xlsx ' + 'You need to enter missing data in 1 row ' + 'Skip to file contents' + ) + + def test_generate_test_letter_doesnt_block_in_trial_mode( client_request, mocker,