def upload_contact_list(service_id): form = CsvUploadForm() if form.validate_on_submit(): try: upload_id = ContactList.upload( current_service.id, Spreadsheet.from_file_form(form).as_dict, ) file_name_metadata = unicode_truncate( SanitiseASCII.encode(form.file.data.filename), 1600) ContactList.set_metadata(current_service.id, upload_id, original_file_name=file_name_metadata) return redirect( url_for( '.check_contact_list', service_id=service_id, upload_id=upload_id, )) except (UnicodeDecodeError, BadZipFile, XLRDError): flash( 'Could not read {}. Try using a different file format.'.format( form.file.data.filename)) except (XLDateError): flash(( '{} contains numbers or dates that Notify cannot understand. ' 'Try formatting all columns as ‘text’ or export your file as CSV.' ).format(form.file.data.filename)) return render_template( 'views/uploads/contact-list/upload.html', form=form, allowed_file_extensions=Spreadsheet.ALLOWED_FILE_EXTENSIONS, )
def send_messages(service_id, template_id): session['sender_id'] = None db_template = service_api_client.get_service_template(service_id, template_id)['data'] if email_or_sms_not_enabled(db_template['template_type'], current_service['permissions']): return redirect(url_for( '.action_blocked', service_id=service_id, notification_type=db_template['template_type'], return_to='view_template', template_id=template_id )) template = get_template( db_template, current_service, show_recipient=True, expand_emails=True, letter_preview_url=url_for( '.view_letter_template_preview', service_id=service_id, template_id=template_id, filetype='png', page_count=get_page_count_for_letter(db_template), ), ) form = CsvUploadForm() if form.validate_on_submit(): try: upload_id = s3upload( service_id, Spreadsheet.from_file(form.file.data, filename=form.file.data.filename).as_dict, current_app.config['AWS_REGION'] ) session['upload_data'] = { "template_id": template_id, "original_file_name": form.file.data.filename } return redirect(url_for('.check_messages', service_id=service_id, upload_id=upload_id, template_type=template.template_type)) except (UnicodeDecodeError, BadZipFile, XLRDError): flash('Couldn’t read {}. Try using a different file format.'.format( form.file.data.filename )) column_headings = first_column_headings[template.template_type] + list(template.placeholders) return render_template( 'views/send.html', template=template, column_headings=list(ascii_uppercase[:len(column_headings)]), example=[column_headings, get_example_csv_rows(template)], form=form )
def send_messages(service_id, template_id): template = Template( service_api_client.get_service_template(service_id, template_id)['data'], prefix=current_service['name'] ) form = CsvUploadForm() if form.validate_on_submit(): try: upload_id = s3upload( service_id, Spreadsheet.from_file(form.file.data, filename=form.file.data.filename).as_dict, current_app.config['AWS_REGION'] ) session['upload_data'] = { "template_id": template_id, "original_file_name": form.file.data.filename } return redirect(url_for('.check_messages', service_id=service_id, upload_id=upload_id, template_type=template.template_type)) except (UnicodeDecodeError, BadZipFile, XLRDError): flash('Couldn’t read {}. Try using a different file format.'.format( form.file.data.filename )) return render_template( 'views/send.html', template=template, column_headings=list(ascii_uppercase[:len(template.placeholders) + 1]), example=[ [first_column_heading[template.template_type]] + list(template.placeholders), get_example_csv_rows(template) ], form=form )
def send_messages(service_id, template_id): template = Template(service_api_client.get_service_template( service_id, template_id)['data'], prefix=current_service['name'], sms_sender=current_service['sms_sender']) form = CsvUploadForm() if form.validate_on_submit(): try: upload_id = s3upload( service_id, Spreadsheet.from_file( form.file.data, filename=form.file.data.filename).as_dict, current_app.config['AWS_REGION']) session['upload_data'] = { "template_id": template_id, "original_file_name": form.file.data.filename } return redirect( url_for('.check_messages', service_id=service_id, upload_id=upload_id, template_type=template.template_type)) except (UnicodeDecodeError, BadZipFile, XLRDError): flash( 'Couldn’t read {}. Try using a different file format.'.format( form.file.data.filename)) return render_template( 'views/send.html', template=template, column_headings=list(ascii_uppercase[:len(template.placeholders) + 1]), example=[[first_column_heading[template.template_type]] + list(template.placeholders), get_example_csv_rows(template)], form=form)
def _check_messages(service_id, template_id, upload_id, preview_row, letters_as_pdf=False): try: # The happy path is that the job doesn’t already exist, so the # API will return a 404 and the client will raise HTTPError. job_api_client.get_job(service_id, upload_id) # the job exists already - so go back to the templates page # If we just return a `redirect` (302) object here, we'll get # errors when we try and unpack in the check_messages route. # Rasing a werkzeug.routing redirect means that doesn't happen. raise PermanentRedirect( url_for('.send_messages', service_id=service_id, template_id=template_id)) except HTTPError as e: if e.status_code != 404: raise statistics = service_api_client.get_service_statistics(service_id, today_only=True) remaining_messages = (current_service.message_limit - sum(stat['requested'] for stat in statistics.values())) contents = s3download(service_id, upload_id) db_template = current_service.get_template_with_user_permission_or_403( template_id, current_user) email_reply_to = None sms_sender = None if db_template['template_type'] == 'email': email_reply_to = get_email_reply_to_address_from_session() elif db_template['template_type'] == 'sms': sms_sender = get_sms_sender_from_session() template = get_template( db_template, current_service, show_recipient=True, letter_preview_url=url_for( '.check_messages_preview', service_id=service_id, template_id=template_id, upload_id=upload_id, filetype='png', row_index=preview_row, ) if not letters_as_pdf else None, email_reply_to=email_reply_to, sms_sender=sms_sender, page_count=get_page_count_for_letter(db_template), ) recipients = RecipientCSV( contents, template_type=template.template_type, placeholders=template.placeholders, max_initial_rows_shown=50, max_errors_shown=50, whitelist=itertools.chain.from_iterable( [user.name, user.mobile_number, user.email_address] for user in Users(service_id)) if current_service.trial_mode else None, remaining_messages=remaining_messages, international_sms=current_service.has_permission('international_sms'), ) if request.args.get('from_test'): # only happens if generating a letter preview test back_link = url_for('.send_test', service_id=service_id, template_id=template.id) choose_time_form = None else: back_link = url_for('.send_messages', service_id=service_id, template_id=template.id) choose_time_form = ChooseTimeForm() if preview_row < 2: abort(404) if preview_row < len(recipients) + 2: template.values = recipients[preview_row - 2].recipient_and_personalisation elif preview_row > 2: abort(404) return dict( recipients=recipients, template=template, errors=recipients.has_errors, row_errors=get_errors_for_csv(recipients, template.template_type), count_of_recipients=len(recipients), count_of_displayed_recipients=len(list(recipients.displayed_rows)), original_file_name=request.args.get('original_file_name', ''), upload_id=upload_id, form=CsvUploadForm(), remaining_messages=remaining_messages, choose_time_form=choose_time_form, back_link=back_link, help=get_help_argument(), trying_to_send_letters_in_trial_mode=all(( current_service.trial_mode, template.template_type == 'letter', )), required_recipient_columns=OrderedSet( recipients.recipient_column_headers) - optional_address_columns, preview_row=preview_row, sent_previously=job_api_client.has_sent_previously( service_id, template.id, db_template['version'], request.args.get('original_file_name', '')))
def send_messages(service_id, template_id): # if there's lots of data in the session, lets log it for debugging purposes # TODO: Remove this once we're confident we have session size under control if len(session.get('file_uploads', {}).keys()) > 2: current_app.logger.info( 'session contains large file_uploads - json_len {}, keys: {}'. format(len(json.dumps(session['file_uploads'])), session['file_uploads'].keys())) db_template = current_service.get_template_with_user_permission_or_403( template_id, current_user) email_reply_to = None sms_sender = None if db_template['template_type'] == 'email': email_reply_to = get_email_reply_to_address_from_session() elif db_template['template_type'] == 'sms': sms_sender = get_sms_sender_from_session() if email_or_sms_not_enabled(db_template['template_type'], current_service.permissions): return redirect( url_for('.action_blocked', service_id=service_id, notification_type=db_template['template_type'], return_to='view_template', template_id=template_id)) template = get_template( db_template, current_service, show_recipient=True, letter_preview_url=url_for( '.view_letter_template_preview', service_id=service_id, template_id=template_id, filetype='png', page_count=get_page_count_for_letter(db_template), ), email_reply_to=email_reply_to, sms_sender=sms_sender, ) form = CsvUploadForm() if form.validate_on_submit(): try: upload_id = s3upload( service_id, Spreadsheet.from_file( form.file.data, filename=form.file.data.filename).as_dict, current_app.config['AWS_REGION']) return redirect( url_for( '.check_messages', service_id=service_id, upload_id=upload_id, template_id=template.id, original_file_name=form.file.data.filename, )) except (UnicodeDecodeError, BadZipFile, XLRDError): flash( 'Couldn’t read {}. Try using a different file format.'.format( form.file.data.filename)) except (XLDateError): flash(( '{} contains numbers or dates that Notification can’t understand. ' 'Try formatting all columns as ‘text’ or export your file as CSV.' ).format(form.file.data.filename)) column_headings = get_spreadsheet_column_headings_from_template(template) return render_template( 'views/send.html', template=template, column_headings=list(ascii_uppercase[:len(column_headings)]), example=[column_headings, get_example_csv_rows(template)], form=form)
def check_messages(service_id, template_type, upload_id): if not session.get('upload_data'): return redirect( url_for('main.choose_template', service_id=service_id, template_type=template_type)) users = user_api_client.get_users_for_service(service_id=service_id) statistics = service_api_client.get_detailed_service_for_today( service_id)['data']['statistics'] remaining_messages = (current_service['message_limit'] - sum(stat['requested'] for stat in statistics.values())) contents = s3download(service_id, upload_id) if not contents: flash('There was a problem reading your upload file') template = Template(service_api_client.get_service_template( service_id, session['upload_data'].get('template_id'))['data'], prefix=current_service['name'], sms_sender=current_service['sms_sender']) recipients = RecipientCSV( contents, template_type=template.template_type, placeholders=template.placeholders, max_initial_rows_shown=50, max_errors_shown=50, whitelist=itertools.chain.from_iterable( [user.mobile_number, user.email_address] for user in users) if current_service['restricted'] else None, remaining_messages=remaining_messages) if request.args.get('from_test'): extra_args = { 'help': 1 } if request.args.get('help', '0') != '0' else {} if len(template.placeholders): back_link = url_for('.send_test', service_id=service_id, template_id=template.id, **extra_args) else: back_link = url_for('.choose_template', service_id=service_id, template_type=template.template_type, **extra_args) choose_time_form = None else: back_link = url_for('.send_messages', service_id=service_id, template_id=template.id) choose_time_form = ChooseTimeForm() with suppress(StopIteration): template.values = next(recipients.rows) first_recipient = template.values.get( recipients.recipient_column_header, '') session['upload_data']['notification_count'] = len(list(recipients.rows)) session['upload_data']['valid'] = not recipients.has_errors return render_template( 'views/check.html', recipients=recipients, first_recipient=first_recipient, template=template, errors=recipients.has_errors, row_errors=get_errors_for_csv(recipients, template.template_type), count_of_recipients=session['upload_data']['notification_count'], count_of_displayed_recipients=( len(list(recipients.initial_annotated_rows_with_errors)) if any(recipients.rows_with_errors) and not recipients.missing_column_headers else len( list(recipients.initial_annotated_rows))), original_file_name=session['upload_data'].get('original_file_name'), upload_id=upload_id, form=CsvUploadForm(), remaining_messages=remaining_messages, choose_time_form=choose_time_form, back_link=back_link, help=get_help_argument())
def send_messages(service_id, template_id): db_template = current_service.get_template_with_user_permission_or_403( template_id, current_user) email_reply_to = None sms_sender = None if db_template['template_type'] == 'email': email_reply_to = get_email_reply_to_address_from_session() elif db_template['template_type'] == 'sms': sms_sender = get_sms_sender_from_session() if db_template[ 'template_type'] not in current_service.available_template_types: return redirect( url_for('.action_blocked', service_id=service_id, notification_type=db_template['template_type'], return_to='view_template', template_id=template_id)) template = get_template( db_template, current_service, show_recipient=True, letter_preview_url=url_for( 'no_cookie.view_letter_template_preview', service_id=service_id, template_id=template_id, filetype='png', page_count=get_page_count_for_letter(db_template), ), email_reply_to=email_reply_to, sms_sender=sms_sender, ) form = CsvUploadForm() if form.validate_on_submit(): try: upload_id = s3upload(service_id, Spreadsheet.from_file_form(form).as_dict, current_app.config['AWS_REGION']) file_name_metadata = unicode_truncate( SanitiseASCII.encode(form.file.data.filename), 1600) set_metadata_on_csv_upload(service_id, upload_id, original_file_name=file_name_metadata) return redirect( url_for( '.check_messages', service_id=service_id, upload_id=upload_id, template_id=template.id, )) except (UnicodeDecodeError, BadZipFile, XLRDError): flash( 'Could not read {}. Try using a different file format.'.format( form.file.data.filename)) except (XLDateError): flash(( '{} contains numbers or dates that Notify cannot understand. ' 'Try formatting all columns as ‘text’ or export your file as CSV.' ).format(form.file.data.filename)) column_headings = get_spreadsheet_column_headings_from_template(template) return render_template( 'views/send.html', template=template, column_headings=list(ascii_uppercase[:len(column_headings)]), example=[column_headings, get_example_csv_rows(template)], form=form, allowed_file_extensions=Spreadsheet.ALLOWED_FILE_EXTENSIONS)
def _check_messages(service_id, template_type, upload_id, preview_row, letters_as_pdf=False): if not session.get('upload_data'): # if we just return a `redirect` (302) object here, we'll get errors when we try and unpack in the # check_messages route - so raise a werkzeug.routing redirect to ensure that doesn't happen. # NOTE: this is a 301 MOVED PERMANENTLY (httpstatus.es/301), so the browser will cache this redirect, and it'll # *always* happen for that browser. _check_messages is only used by endpoints that contain `upload_id`, which # is a one-time-use id (that ties to a given file in S3 that is already deleted if it's not in the session) raise RequestRedirect(url_for('main.choose_template', service_id=service_id)) users = user_api_client.get_users_for_service(service_id=service_id) statistics = service_api_client.get_detailed_service_for_today(service_id)['data']['statistics'] remaining_messages = (current_service['message_limit'] - sum(stat['requested'] for stat in statistics.values())) contents = s3download(service_id, upload_id) email_reply_to = None sms_sender = None if template_type == 'email': email_reply_to = get_email_reply_to_address_from_session(service_id) elif template_type == 'sms': sms_sender = get_sms_sender_from_session(service_id) template = get_template( service_api_client.get_service_template( service_id, session['upload_data'].get('template_id') )['data'], current_service, show_recipient=True, letter_preview_url=url_for( '.check_messages_preview', service_id=service_id, template_type=template_type, upload_id=upload_id, filetype='png', row_index=preview_row, ) if not letters_as_pdf else None, email_reply_to=email_reply_to, sms_sender=sms_sender ) recipients = RecipientCSV( contents, template_type=template.template_type, placeholders=template.placeholders, max_initial_rows_shown=50, max_errors_shown=50, whitelist=itertools.chain.from_iterable( [user.name, user.mobile_number, user.email_address] for user in users ) if current_service['restricted'] else None, remaining_messages=remaining_messages, international_sms='international_sms' in current_service['permissions'], ) if request.args.get('from_test'): # only happens if generating a letter preview test back_link = url_for('.send_test', service_id=service_id, template_id=template.id) choose_time_form = None else: back_link = url_for('.send_messages', service_id=service_id, template_id=template.id) choose_time_form = ChooseTimeForm() count_of_recipients = len(list(recipients.rows)) if preview_row < 2: abort(404) if preview_row < count_of_recipients + 2: template.values = recipients[preview_row - 2] elif preview_row > 2: abort(404) session['upload_data']['notification_count'] = count_of_recipients session['upload_data']['valid'] = not recipients.has_errors return dict( recipients=recipients, template=template, errors=recipients.has_errors, row_errors=get_errors_for_csv(recipients, template.template_type), count_of_recipients=count_of_recipients, count_of_displayed_recipients=( len(list(recipients.initial_annotated_rows_with_errors)) if any(recipients.rows_with_errors) and not recipients.missing_column_headers else len(list(recipients.initial_annotated_rows)) ), original_file_name=session['upload_data'].get('original_file_name'), upload_id=upload_id, form=CsvUploadForm(), remaining_messages=remaining_messages, choose_time_form=choose_time_form, back_link=back_link, help=get_help_argument(), trying_to_send_letters_in_trial_mode=all(( current_service['restricted'], template.template_type == 'letter', not request.args.get('from_test'), )), required_recipient_columns=OrderedSet(recipients.recipient_column_headers) - optional_address_columns, preview_row=preview_row, )
def check_contact_list(service_id, upload_id): form = CsvUploadForm() contents = ContactList.download(service_id, upload_id) first_row = contents.splitlines()[0].strip().rstrip( ',') if contents else '' original_file_name = ContactList.get_metadata(service_id, upload_id).get( 'original_file_name', '') template_type = { 'emailaddress': 'email', 'phonenumber': 'sms', }.get(Columns.make_key(first_row)) recipients = RecipientCSV( contents, template=get_sample_template(template_type or 'sms'), whitelist=itertools.chain.from_iterable( [user.name, user.mobile_number, user.email_address] for user in current_service.active_users) if current_service.trial_mode else None, allow_international_sms=current_service.has_permission( 'international_sms'), max_initial_rows_shown=50, max_errors_shown=50, ) non_empty_column_headers = list(filter(None, recipients.column_headers)) if len(non_empty_column_headers ) > 1 or not template_type or not recipients: return render_template( 'views/uploads/contact-list/too-many-columns.html', recipients=recipients, original_file_name=original_file_name, template_type=template_type, form=form, allowed_file_extensions=Spreadsheet.ALLOWED_FILE_EXTENSIONS) if recipients.too_many_rows or not len(recipients): return render_template( 'views/uploads/contact-list/column-errors.html', recipients=recipients, original_file_name=original_file_name, form=form, allowed_file_extensions=Spreadsheet.ALLOWED_FILE_EXTENSIONS) row_errors = get_errors_for_csv(recipients, template_type) if row_errors: return render_template( 'views/uploads/contact-list/row-errors.html', recipients=recipients, original_file_name=original_file_name, row_errors=row_errors, form=form, allowed_file_extensions=Spreadsheet.ALLOWED_FILE_EXTENSIONS) if recipients.has_errors: return render_template( 'views/uploads/contact-list/column-errors.html', recipients=recipients, original_file_name=original_file_name, form=form, allowed_file_extensions=Spreadsheet.ALLOWED_FILE_EXTENSIONS) metadata_kwargs = { 'row_count': len(recipients), 'valid': True, 'original_file_name': original_file_name, 'template_type': template_type } ContactList.set_metadata(service_id, upload_id, **metadata_kwargs) return render_template( 'views/uploads/contact-list/ok.html', recipients=recipients, original_file_name=original_file_name, upload_id=upload_id, )
def _check_messages(service_id, template_id, upload_id, preview_row, letters_as_pdf=False): users = user_api_client.get_users_for_service(service_id=service_id) statistics = service_api_client.get_detailed_service_for_today(service_id)['data']['statistics'] remaining_messages = (current_service['message_limit'] - sum(stat['requested'] for stat in statistics.values())) contents = s3download(service_id, upload_id) db_template = service_api_client.get_service_template( service_id, str(template_id), )['data'] email_reply_to = None sms_sender = None if db_template['template_type'] == 'email': email_reply_to = get_email_reply_to_address_from_session(service_id) elif db_template['template_type'] == 'sms': sms_sender = get_sms_sender_from_session(service_id) template = get_template( service_api_client.get_service_template( service_id, str(template_id), )['data'], current_service, show_recipient=True, letter_preview_url=url_for( '.check_messages_preview', service_id=service_id, template_id=template_id, upload_id=upload_id, filetype='png', row_index=preview_row, ) if not letters_as_pdf else None, email_reply_to=email_reply_to, sms_sender=sms_sender, ) recipients = RecipientCSV( contents, template_type=template.template_type, placeholders=template.placeholders, max_initial_rows_shown=50, max_errors_shown=50, whitelist=itertools.chain.from_iterable( [user.name, user.mobile_number, user.email_address] for user in users ) if current_service['restricted'] else None, remaining_messages=remaining_messages, international_sms='international_sms' in current_service['permissions'], ) if request.args.get('from_test'): # only happens if generating a letter preview test back_link = url_for('.send_test', service_id=service_id, template_id=template.id) choose_time_form = None else: back_link = url_for('.send_messages', service_id=service_id, template_id=template.id) choose_time_form = ChooseTimeForm() if preview_row < 2: abort(404) if preview_row < len(recipients) + 2: template.values = recipients[preview_row - 2].recipient_and_personalisation elif preview_row > 2: abort(404) if 'file_uploads' not in session: session['file_uploads'] = {} session['file_uploads'][upload_id] = {} if any(recipients) and not recipients.has_errors: session['file_uploads'][upload_id]['notification_count'] = len(recipients) session['file_uploads'][upload_id]['template_id'] = str(template_id) session['file_uploads'][upload_id]['valid'] = True else: session['file_uploads'].pop(upload_id) return dict( recipients=recipients, template=template, errors=recipients.has_errors, row_errors=get_errors_for_csv(recipients, template.template_type), count_of_recipients=len(recipients), count_of_displayed_recipients=len(list(recipients.displayed_rows)), original_file_name=request.args.get('original_file_name'), upload_id=upload_id, form=CsvUploadForm(), remaining_messages=remaining_messages, choose_time_form=choose_time_form, back_link=back_link, help=get_help_argument(), trying_to_send_letters_in_trial_mode=all(( current_service['restricted'], template.template_type == 'letter', not request.args.get('from_test'), )), required_recipient_columns=OrderedSet(recipients.recipient_column_headers) - optional_address_columns, preview_row=preview_row, )