2016-04-04 14:28:52 +01:00
|
|
|
|
import itertools
|
2023-12-14 13:24:34 -08:00
|
|
|
|
import time
|
|
|
|
|
|
import uuid
|
2023-12-15 10:29:42 -08:00
|
|
|
|
from string import ascii_uppercase
|
2016-05-13 21:25:59 +01:00
|
|
|
|
from zipfile import BadZipFile
|
2016-01-11 15:00:51 +00:00
|
|
|
|
|
2023-12-18 12:31:40 -08:00
|
|
|
|
from flask import abort, flash, redirect, render_template, request, session, url_for
|
2019-07-01 15:22:08 +01:00
|
|
|
|
from flask_login import current_user
|
2024-03-06 11:49:19 -08:00
|
|
|
|
from markupsafe import Markup
|
2017-06-29 15:31:44 +01:00
|
|
|
|
from notifications_python_client.errors import HTTPError
|
2022-12-05 15:33:44 -05:00
|
|
|
|
from notifications_utils import SMS_CHAR_COUNT_LIMIT
|
2022-02-04 10:43:36 +00:00
|
|
|
|
from notifications_utils.insensitive_dict import InsensitiveDict
|
2020-04-19 22:46:13 +01:00
|
|
|
|
from notifications_utils.recipients import RecipientCSV, first_column_headings
|
2018-07-12 15:14:58 +01:00
|
|
|
|
from notifications_utils.sanitise_text import SanitiseASCII
|
2018-02-20 11:22:17 +00:00
|
|
|
|
from xlrd.biffh import XLRDError
|
2018-02-28 14:45:57 +00:00
|
|
|
|
from xlrd.xldate import XLDateError
|
2015-12-10 21:15:20 +00:00
|
|
|
|
|
2018-02-20 11:22:17 +00:00
|
|
|
|
from app import (
|
|
|
|
|
|
current_service,
|
|
|
|
|
|
job_api_client,
|
2020-01-22 16:13:25 +00:00
|
|
|
|
nl2br,
|
2018-02-20 11:22:17 +00:00
|
|
|
|
notification_api_client,
|
|
|
|
|
|
service_api_client,
|
|
|
|
|
|
)
|
2022-12-05 16:35:46 -05:00
|
|
|
|
from app.main import main
|
2017-05-04 09:30:55 +01:00
|
|
|
|
from app.main.forms import (
|
|
|
|
|
|
ChooseTimeForm,
|
2018-02-20 11:22:17 +00:00
|
|
|
|
CsvUploadForm,
|
2017-10-16 16:35:35 +01:00
|
|
|
|
SetSenderForm,
|
2018-02-20 11:22:17 +00:00
|
|
|
|
get_placeholder_form_instance,
|
2017-05-04 09:30:55 +01:00
|
|
|
|
)
|
2019-05-23 15:27:35 +01:00
|
|
|
|
from app.models.user import Users
|
2019-01-30 09:42:15 +00:00
|
|
|
|
from app.s3_client.s3_csv_client import (
|
2020-10-21 13:07:59 +01:00
|
|
|
|
get_csv_metadata,
|
2019-01-30 09:42:15 +00:00
|
|
|
|
s3download,
|
|
|
|
|
|
s3upload,
|
|
|
|
|
|
set_metadata_on_csv_upload,
|
|
|
|
|
|
)
|
2023-12-15 10:29:42 -08:00
|
|
|
|
from app.utils import PermanentRedirect, should_skip_template_page, unicode_truncate
|
2021-06-09 15:15:35 +01:00
|
|
|
|
from app.utils.csv import Spreadsheet, get_errors_for_csv
|
|
|
|
|
|
from app.utils.templates import get_template
|
2021-06-09 13:19:05 +01:00
|
|
|
|
from app.utils.user import user_has_permissions
|
2024-02-16 11:54:59 -08:00
|
|
|
|
|
2016-03-01 15:53:58 +00:00
|
|
|
|
|
2016-05-05 08:39:36 +01:00
|
|
|
|
def get_example_csv_fields(column_headers, use_example_as_example, submitted_fields):
|
|
|
|
|
|
if use_example_as_example:
|
|
|
|
|
|
return ["example" for header in column_headers]
|
|
|
|
|
|
elif submitted_fields:
|
|
|
|
|
|
return [submitted_fields.get(header) for header in column_headers]
|
|
|
|
|
|
else:
|
|
|
|
|
|
return list(column_headers)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_example_csv_rows(template, use_example_as_example=True, submitted_fields=False):
|
2016-11-10 13:39:05 +00:00
|
|
|
|
return {
|
2024-02-29 08:24:53 -08:00
|
|
|
|
"email": (
|
|
|
|
|
|
["test@example.com"]
|
|
|
|
|
|
if use_example_as_example
|
|
|
|
|
|
else [current_user.email_address]
|
|
|
|
|
|
),
|
|
|
|
|
|
"sms": (
|
|
|
|
|
|
["12223334444"] if use_example_as_example else [current_user.mobile_number]
|
|
|
|
|
|
),
|
2018-06-08 12:49:29 +01:00
|
|
|
|
}[template.template_type] + get_example_csv_fields(
|
|
|
|
|
|
(
|
2023-08-25 09:12:23 -07:00
|
|
|
|
placeholder
|
|
|
|
|
|
for placeholder in template.placeholders
|
|
|
|
|
|
if placeholder
|
|
|
|
|
|
not in InsensitiveDict.from_keys(
|
2018-06-08 12:49:29 +01:00
|
|
|
|
first_column_headings[template.template_type]
|
|
|
|
|
|
)
|
|
|
|
|
|
),
|
|
|
|
|
|
use_example_as_example,
|
2023-08-25 09:12:23 -07:00
|
|
|
|
submitted_fields,
|
2018-06-08 12:49:29 +01:00
|
|
|
|
)
|
2016-04-01 14:31:28 +01:00
|
|
|
|
|
|
|
|
|
|
|
2023-08-25 09:12:23 -07:00
|
|
|
|
@main.route(
|
|
|
|
|
|
"/services/<uuid:service_id>/send/<uuid:template_id>/csv", methods=["GET", "POST"]
|
|
|
|
|
|
)
|
|
|
|
|
|
@user_has_permissions("send_messages", restrict_admin_usage=True)
|
2016-02-22 17:17:18 +00:00
|
|
|
|
def send_messages(service_id, template_id):
|
2023-05-15 14:37:05 -06:00
|
|
|
|
notification_count = service_api_client.get_notification_count(service_id)
|
2023-06-01 15:40:50 -06:00
|
|
|
|
remaining_messages = current_service.message_limit - notification_count
|
2023-05-15 14:37:05 -06:00
|
|
|
|
|
2023-08-25 09:12:23 -07:00
|
|
|
|
db_template = current_service.get_template_with_user_permission_or_403(
|
|
|
|
|
|
template_id, current_user
|
|
|
|
|
|
)
|
2017-05-11 12:01:51 +01:00
|
|
|
|
|
2018-11-06 14:22:22 +00:00
|
|
|
|
email_reply_to = None
|
|
|
|
|
|
sms_sender = None
|
|
|
|
|
|
|
2023-08-25 09:12:23 -07:00
|
|
|
|
if db_template["template_type"] == "email":
|
2018-11-06 14:22:22 +00:00
|
|
|
|
email_reply_to = get_email_reply_to_address_from_session()
|
2023-08-25 09:12:23 -07:00
|
|
|
|
elif db_template["template_type"] == "sms":
|
2018-11-06 14:22:22 +00:00
|
|
|
|
sms_sender = get_sms_sender_from_session()
|
|
|
|
|
|
|
2023-08-25 09:12:23 -07:00
|
|
|
|
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,
|
|
|
|
|
|
)
|
|
|
|
|
|
)
|
2017-06-30 10:55:59 +01:00
|
|
|
|
|
2016-12-08 11:50:59 +00:00
|
|
|
|
template = get_template(
|
2017-06-22 16:00:14 +01:00
|
|
|
|
db_template,
|
2016-12-08 11:50:59 +00:00
|
|
|
|
current_service,
|
2016-12-20 14:38:34 +00:00
|
|
|
|
show_recipient=True,
|
2018-11-06 14:22:22 +00:00
|
|
|
|
email_reply_to=email_reply_to,
|
|
|
|
|
|
sms_sender=sms_sender,
|
2016-03-29 15:59:53 +01:00
|
|
|
|
)
|
|
|
|
|
|
|
2016-01-11 15:00:51 +00:00
|
|
|
|
form = CsvUploadForm()
|
2016-01-13 17:32:40 +00:00
|
|
|
|
if form.validate_on_submit():
|
2016-01-11 15:00:51 +00:00
|
|
|
|
try:
|
2016-05-15 07:47:50 +01:00
|
|
|
|
upload_id = s3upload(
|
2016-03-07 18:47:05 +00:00
|
|
|
|
service_id,
|
2020-03-13 13:53:18 +00:00
|
|
|
|
Spreadsheet.from_file_form(form).as_dict,
|
2016-03-07 18:47:05 +00:00
|
|
|
|
)
|
2020-10-23 16:10:03 +01:00
|
|
|
|
file_name_metadata = unicode_truncate(
|
2023-08-25 09:12:23 -07:00
|
|
|
|
SanitiseASCII.encode(form.file.data.filename), 1600
|
2020-10-23 16:10:03 +01:00
|
|
|
|
)
|
|
|
|
|
|
set_metadata_on_csv_upload(
|
2023-08-25 09:12:23 -07:00
|
|
|
|
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,
|
|
|
|
|
|
)
|
2020-10-23 16:10:03 +01:00
|
|
|
|
)
|
2016-05-13 21:25:59 +01:00
|
|
|
|
except (UnicodeDecodeError, BadZipFile, XLRDError):
|
2023-08-25 09:12:23 -07:00
|
|
|
|
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)
|
|
|
|
|
|
)
|
2021-12-03 18:14:02 +00:00
|
|
|
|
elif form.errors:
|
|
|
|
|
|
# just show the first error, as we don't expect the form to have more
|
|
|
|
|
|
# than one, since it only has one field
|
|
|
|
|
|
first_field_errors = list(form.errors.values())[0]
|
2024-03-06 11:49:19 -08:00
|
|
|
|
error_message = '<span class="usa-error-message">'
|
|
|
|
|
|
error_message = f"{error_message}{first_field_errors[0]}"
|
|
|
|
|
|
error_message = f"{error_message}</span>"
|
|
|
|
|
|
error_message = Markup(error_message)
|
|
|
|
|
|
flash(error_message)
|
2018-06-08 12:49:29 +01:00
|
|
|
|
column_headings = get_spreadsheet_column_headings_from_template(template)
|
2016-11-10 13:39:05 +00:00
|
|
|
|
|
2016-02-08 16:36:53 +00:00
|
|
|
|
return render_template(
|
2023-08-25 09:12:23 -07:00
|
|
|
|
"views/send.html",
|
2016-02-08 16:36:53 +00:00
|
|
|
|
template=template,
|
2023-08-25 09:12:23 -07:00
|
|
|
|
column_headings=list(ascii_uppercase[: len(column_headings)]),
|
2016-11-10 13:39:05 +00:00
|
|
|
|
example=[column_headings, get_example_csv_rows(template)],
|
2020-12-16 11:05:19 +00:00
|
|
|
|
form=form,
|
2023-05-15 14:37:05 -06:00
|
|
|
|
allowed_file_extensions=Spreadsheet.ALLOWED_FILE_EXTENSIONS,
|
2023-08-25 09:12:23 -07:00
|
|
|
|
remaining_messages=remaining_messages,
|
2016-02-08 16:36:53 +00:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
2023-08-25 09:12:23 -07:00
|
|
|
|
@main.route("/services/<uuid:service_id>/send/<uuid:template_id>.csv", methods=["GET"])
|
|
|
|
|
|
@user_has_permissions("send_messages", "manage_templates")
|
2016-05-05 08:39:36 +01:00
|
|
|
|
def get_example_csv(service_id, template_id):
|
2016-12-08 11:50:59 +00:00
|
|
|
|
template = get_template(
|
2023-08-25 09:12:23 -07:00
|
|
|
|
service_api_client.get_service_template(service_id, template_id)["data"],
|
|
|
|
|
|
current_service,
|
|
|
|
|
|
)
|
|
|
|
|
|
return (
|
|
|
|
|
|
Spreadsheet.from_rows(
|
|
|
|
|
|
[
|
|
|
|
|
|
get_spreadsheet_column_headings_from_template(template),
|
|
|
|
|
|
get_example_csv_rows(template),
|
|
|
|
|
|
]
|
|
|
|
|
|
).as_csv_data,
|
|
|
|
|
|
200,
|
|
|
|
|
|
{
|
|
|
|
|
|
"Content-Type": "text/csv; charset=utf-8",
|
|
|
|
|
|
"Content-Disposition": 'inline; filename="{}.csv"'.format(template.name),
|
|
|
|
|
|
},
|
2016-12-08 11:50:59 +00:00
|
|
|
|
)
|
2015-12-10 21:15:20 +00:00
|
|
|
|
|
|
|
|
|
|
|
2023-08-25 09:12:23 -07:00
|
|
|
|
@main.route(
|
|
|
|
|
|
"/services/<uuid:service_id>/send/<uuid:template_id>/set-sender",
|
|
|
|
|
|
methods=["GET", "POST"],
|
|
|
|
|
|
)
|
|
|
|
|
|
@user_has_permissions("send_messages", restrict_admin_usage=True)
|
2017-10-16 16:35:35 +01:00
|
|
|
|
def set_sender(service_id, template_id):
|
2023-08-25 09:12:23 -07:00
|
|
|
|
session["sender_id"] = None
|
2017-10-16 16:35:35 +01:00
|
|
|
|
redirect_to_one_off = redirect(
|
2023-08-25 09:12:23 -07:00
|
|
|
|
url_for(".send_one_off", service_id=service_id, template_id=template_id)
|
2017-10-16 16:35:35 +01:00
|
|
|
|
)
|
|
|
|
|
|
|
2023-08-25 09:12:23 -07:00
|
|
|
|
template = current_service.get_template_with_user_permission_or_403(
|
|
|
|
|
|
template_id, current_user
|
|
|
|
|
|
)
|
2017-10-16 16:35:35 +01:00
|
|
|
|
|
2023-08-25 09:12:23 -07:00
|
|
|
|
sender_details = get_sender_details(service_id, template["template_type"])
|
2021-02-08 17:23:47 +00:00
|
|
|
|
|
2023-10-06 11:41:43 -06:00
|
|
|
|
sender_details = remove_notify_from_sender_options(sender_details)
|
|
|
|
|
|
|
2021-02-08 17:23:47 +00:00
|
|
|
|
if len(sender_details) == 1:
|
2023-08-25 09:12:23 -07:00
|
|
|
|
session["sender_id"] = sender_details[0]["id"]
|
2021-02-08 17:23:47 +00:00
|
|
|
|
|
2017-10-16 16:35:35 +01:00
|
|
|
|
if len(sender_details) <= 1:
|
|
|
|
|
|
return redirect_to_one_off
|
|
|
|
|
|
|
2023-08-25 09:12:23 -07:00
|
|
|
|
sender_context = get_sender_context(sender_details, template["template_type"])
|
2017-10-16 16:35:35 +01:00
|
|
|
|
|
|
|
|
|
|
form = SetSenderForm(
|
2023-08-25 09:12:23 -07:00
|
|
|
|
sender=sender_context["default_id"],
|
|
|
|
|
|
sender_choices=sender_context["value_and_label"],
|
|
|
|
|
|
sender_label=sender_context["description"],
|
2017-10-16 16:35:35 +01:00
|
|
|
|
)
|
2023-08-25 09:12:23 -07:00
|
|
|
|
option_hints = {sender_context["default_id"]: "(Default)"}
|
|
|
|
|
|
if sender_context.get("receives_text_message", None):
|
|
|
|
|
|
option_hints.update(
|
|
|
|
|
|
{sender_context["receives_text_message"]: "(Receives replies)"}
|
|
|
|
|
|
)
|
|
|
|
|
|
if sender_context.get("default_and_receives", None):
|
|
|
|
|
|
option_hints = {
|
|
|
|
|
|
sender_context["default_and_receives"]: "(Default and receives replies)"
|
|
|
|
|
|
}
|
2017-10-16 16:35:35 +01:00
|
|
|
|
|
2021-01-13 10:31:07 +00:00
|
|
|
|
# extend all radios that need hint text
|
2023-08-25 09:12:23 -07:00
|
|
|
|
form.sender.param_extensions = {"items": []}
|
2021-01-13 10:31:07 +00:00
|
|
|
|
for item_id, _item_value in form.sender.choices:
|
|
|
|
|
|
if item_id in option_hints:
|
2023-08-25 09:12:23 -07:00
|
|
|
|
extensions = {"hint": {"text": option_hints[item_id]}}
|
2021-01-13 10:31:07 +00:00
|
|
|
|
else:
|
2023-08-25 09:12:23 -07:00
|
|
|
|
extensions = (
|
|
|
|
|
|
{}
|
|
|
|
|
|
) # if no extensions needed, send an empty dict to preserve order of items
|
|
|
|
|
|
form.sender.param_extensions["items"].append(extensions)
|
2021-01-13 10:31:07 +00:00
|
|
|
|
|
2017-10-16 16:35:35 +01:00
|
|
|
|
if form.validate_on_submit():
|
2023-08-25 09:12:23 -07:00
|
|
|
|
session["sender_id"] = form.sender.data
|
|
|
|
|
|
return redirect(
|
|
|
|
|
|
url_for(".send_one_off", service_id=service_id, template_id=template_id)
|
|
|
|
|
|
)
|
2017-10-16 16:35:35 +01:00
|
|
|
|
|
|
|
|
|
|
return render_template(
|
2023-08-25 09:12:23 -07:00
|
|
|
|
"views/templates/set-sender.html",
|
2017-10-16 16:35:35 +01:00
|
|
|
|
form=form,
|
|
|
|
|
|
template_id=template_id,
|
2023-08-25 09:12:23 -07:00
|
|
|
|
sender_context={
|
|
|
|
|
|
"title": sender_context["title"],
|
|
|
|
|
|
"description": sender_context["description"],
|
|
|
|
|
|
},
|
|
|
|
|
|
option_hints=option_hints,
|
2017-10-16 16:35:35 +01:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
2023-10-06 11:41:43 -06:00
|
|
|
|
def remove_notify_from_sender_options(sender_details):
|
2023-11-17 11:19:26 -07:00
|
|
|
|
# Remove US Notify/Notify.gov from users list of sender
|
|
|
|
|
|
# options during message send flow
|
|
|
|
|
|
sender_details = [
|
2023-11-20 10:39:39 -07:00
|
|
|
|
sender for sender in sender_details if verify_sender_options(sender)
|
2023-11-17 11:19:26 -07:00
|
|
|
|
]
|
|
|
|
|
|
|
2023-10-06 11:41:43 -06:00
|
|
|
|
return sender_details
|
|
|
|
|
|
|
|
|
|
|
|
|
2023-11-20 10:39:39 -07:00
|
|
|
|
def verify_sender_options(sender):
|
2023-11-22 11:55:40 -07:00
|
|
|
|
if sender.get("sms_sender") in ["Notify.gov", "US Notify"] and sender["is_default"]:
|
|
|
|
|
|
return True
|
2023-11-22 11:06:15 -07:00
|
|
|
|
if sender.get("sms_sender") not in ["Notify.gov", "US Notify"]:
|
2023-11-20 10:39:39 -07:00
|
|
|
|
return True
|
|
|
|
|
|
|
2023-11-22 11:06:15 -07:00
|
|
|
|
return False
|
|
|
|
|
|
|
2023-11-20 10:39:39 -07:00
|
|
|
|
|
2017-10-16 16:35:35 +01:00
|
|
|
|
def get_sender_context(sender_details, template_type):
|
|
|
|
|
|
context = {
|
2023-08-25 09:12:23 -07:00
|
|
|
|
"email": {
|
|
|
|
|
|
"title": "Where should replies come back to?",
|
|
|
|
|
|
"description": "Where should replies come back to?",
|
|
|
|
|
|
"field_name": "email_address",
|
|
|
|
|
|
},
|
|
|
|
|
|
"sms": {
|
|
|
|
|
|
"title": "Who should the message come from?",
|
|
|
|
|
|
"description": "Who should the message come from?",
|
|
|
|
|
|
"field_name": "sms_sender",
|
2017-10-16 16:35:35 +01:00
|
|
|
|
},
|
|
|
|
|
|
}[template_type]
|
|
|
|
|
|
|
2023-08-25 09:12:23 -07:00
|
|
|
|
sender_format = context["field_name"]
|
2017-10-16 16:35:35 +01:00
|
|
|
|
|
2023-08-25 09:12:23 -07:00
|
|
|
|
context["default_id"] = next(
|
|
|
|
|
|
sender["id"] for sender in sender_details if sender["is_default"]
|
|
|
|
|
|
)
|
|
|
|
|
|
if template_type == "sms":
|
|
|
|
|
|
inbound = [
|
|
|
|
|
|
sender["id"] for sender in sender_details if sender["inbound_number_id"]
|
|
|
|
|
|
]
|
2017-11-02 15:48:19 +00:00
|
|
|
|
if inbound:
|
2023-08-25 09:12:23 -07:00
|
|
|
|
context["receives_text_message"] = next(iter(inbound))
|
|
|
|
|
|
if context["default_id"] == context.get("receives_text_message", None):
|
|
|
|
|
|
context["default_and_receives"] = context["default_id"]
|
2017-11-02 15:48:19 +00:00
|
|
|
|
|
2023-08-25 09:12:23 -07:00
|
|
|
|
context["value_and_label"] = [
|
|
|
|
|
|
(sender["id"], nl2br(sender[sender_format])) for sender in sender_details
|
|
|
|
|
|
]
|
2017-10-16 16:35:35 +01:00
|
|
|
|
return context
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_sender_details(service_id, template_type):
|
|
|
|
|
|
api_call = {
|
2023-08-25 09:12:23 -07:00
|
|
|
|
"email": service_api_client.get_reply_to_email_addresses,
|
|
|
|
|
|
"sms": service_api_client.get_sms_senders,
|
2017-10-16 16:35:35 +01:00
|
|
|
|
}[template_type]
|
|
|
|
|
|
return api_call(service_id)
|
|
|
|
|
|
|
|
|
|
|
|
|
2020-10-07 14:51:18 +01:00
|
|
|
|
@main.route("/services/<uuid:service_id>/send/<uuid:template_id>/one-off")
|
2023-08-25 09:12:23 -07:00
|
|
|
|
@user_has_permissions("send_messages", restrict_admin_usage=True)
|
2020-10-07 14:51:18 +01:00
|
|
|
|
def send_one_off(service_id, template_id):
|
2023-08-25 09:12:23 -07:00
|
|
|
|
session["recipient"] = None
|
|
|
|
|
|
session["placeholders"] = {}
|
2017-06-30 10:55:59 +01:00
|
|
|
|
|
2023-08-25 09:12:23 -07:00
|
|
|
|
db_template = current_service.get_template_with_user_permission_or_403(
|
|
|
|
|
|
template_id, current_user
|
|
|
|
|
|
)
|
2017-06-30 10:55:59 +01:00
|
|
|
|
|
2023-08-25 09:12:23 -07:00
|
|
|
|
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,
|
|
|
|
|
|
)
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
return redirect(
|
|
|
|
|
|
url_for(
|
|
|
|
|
|
".send_one_off_step",
|
2017-06-30 10:55:59 +01:00
|
|
|
|
service_id=service_id,
|
2023-08-25 09:12:23 -07:00
|
|
|
|
template_id=template_id,
|
|
|
|
|
|
step_index=0,
|
|
|
|
|
|
)
|
|
|
|
|
|
)
|
2016-03-02 17:02:41 +00:00
|
|
|
|
|
2017-05-04 09:30:55 +01:00
|
|
|
|
|
2017-06-23 17:30:34 +01:00
|
|
|
|
def get_notification_check_endpoint(service_id, template):
|
2023-08-25 09:12:23 -07:00
|
|
|
|
return redirect(
|
|
|
|
|
|
url_for(
|
|
|
|
|
|
"main.check_notification",
|
|
|
|
|
|
service_id=service_id,
|
|
|
|
|
|
template_id=template.id,
|
|
|
|
|
|
)
|
|
|
|
|
|
)
|
2017-06-23 17:30:34 +01:00
|
|
|
|
|
|
|
|
|
|
|
2017-05-25 08:55:05 +01:00
|
|
|
|
@main.route(
|
2019-11-04 11:07:55 +00:00
|
|
|
|
"/services/<uuid:service_id>/send/<uuid:template_id>/one-off/step-<int:step_index>",
|
2023-08-25 09:12:23 -07:00
|
|
|
|
methods=["GET", "POST"],
|
2017-05-25 08:55:05 +01:00
|
|
|
|
)
|
2023-08-25 09:12:23 -07:00
|
|
|
|
@user_has_permissions("send_messages", restrict_admin_usage=True)
|
2020-10-07 14:51:18 +01:00
|
|
|
|
def send_one_off_step(service_id, template_id, step_index):
|
2023-08-25 09:12:23 -07:00
|
|
|
|
if {"recipient", "placeholders"} - set(session.keys()):
|
|
|
|
|
|
return redirect(
|
|
|
|
|
|
url_for(
|
|
|
|
|
|
".send_one_off",
|
|
|
|
|
|
service_id=service_id,
|
|
|
|
|
|
template_id=template_id,
|
|
|
|
|
|
)
|
|
|
|
|
|
)
|
2017-05-22 11:49:15 +01:00
|
|
|
|
|
2023-08-25 09:12:23 -07:00
|
|
|
|
db_template = current_service.get_template_with_user_permission_or_403(
|
|
|
|
|
|
template_id, current_user
|
|
|
|
|
|
)
|
2017-05-11 12:01:51 +01:00
|
|
|
|
|
2017-11-02 12:07:46 +00:00
|
|
|
|
email_reply_to = None
|
|
|
|
|
|
sms_sender = None
|
2023-08-25 09:12:23 -07:00
|
|
|
|
if db_template["template_type"] == "email":
|
2018-10-26 17:31:49 +01:00
|
|
|
|
email_reply_to = get_email_reply_to_address_from_session()
|
2023-08-25 09:12:23 -07:00
|
|
|
|
elif db_template["template_type"] == "sms":
|
|
|
|
|
|
sms_sender = (
|
|
|
|
|
|
get_sms_sender_from_session()
|
2023-08-31 08:21:28 -07:00
|
|
|
|
) # TODO: verify default sender is Notify.gov
|
2020-07-21 16:06:33 +01:00
|
|
|
|
|
2023-08-25 09:12:23 -07:00
|
|
|
|
template_values = get_recipient_and_placeholders_from_session(
|
|
|
|
|
|
db_template["template_type"]
|
|
|
|
|
|
)
|
2020-07-21 16:06:33 +01:00
|
|
|
|
|
2016-12-08 11:50:59 +00:00
|
|
|
|
template = get_template(
|
2017-06-22 16:00:14 +01:00
|
|
|
|
db_template,
|
2016-12-08 11:50:59 +00:00
|
|
|
|
current_service,
|
2016-12-20 14:38:34 +00:00
|
|
|
|
show_recipient=True,
|
2017-11-02 12:07:46 +00:00
|
|
|
|
email_reply_to=email_reply_to,
|
2023-08-25 09:12:23 -07:00
|
|
|
|
sms_sender=sms_sender,
|
2016-05-05 08:39:36 +01:00
|
|
|
|
)
|
2016-04-03 11:30:23 +01:00
|
|
|
|
|
2020-10-07 14:51:18 +01:00
|
|
|
|
placeholders = fields_to_fill_in(template)
|
2017-05-04 09:30:55 +01:00
|
|
|
|
|
2017-05-22 11:49:15 +01:00
|
|
|
|
try:
|
2019-06-06 12:24:02 +01:00
|
|
|
|
current_placeholder = placeholders[step_index]
|
2017-05-22 11:49:15 +01:00
|
|
|
|
except IndexError:
|
2017-05-25 09:18:26 +01:00
|
|
|
|
if all_placeholders_in_session(placeholders):
|
2017-06-23 17:30:34 +01:00
|
|
|
|
return get_notification_check_endpoint(service_id, template)
|
2023-08-25 09:12:23 -07:00
|
|
|
|
return redirect(
|
|
|
|
|
|
url_for(
|
|
|
|
|
|
".send_one_off",
|
|
|
|
|
|
service_id=service_id,
|
|
|
|
|
|
template_id=template_id,
|
|
|
|
|
|
)
|
|
|
|
|
|
)
|
2017-06-22 16:00:14 +01:00
|
|
|
|
|
2017-05-04 09:30:55 +01:00
|
|
|
|
form = get_placeholder_form_instance(
|
|
|
|
|
|
current_placeholder,
|
2017-06-23 17:30:34 +01:00
|
|
|
|
dict_to_populate_from=get_normalised_placeholders_from_session(),
|
2018-03-16 14:17:43 +00:00
|
|
|
|
template_type=template.template_type,
|
2023-08-25 09:12:23 -07:00
|
|
|
|
allow_international_phone_numbers=current_service.has_permission(
|
|
|
|
|
|
"international_sms"
|
|
|
|
|
|
),
|
2017-05-04 09:30:55 +01:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
if form.validate_on_submit():
|
2017-06-26 10:58:43 +01:00
|
|
|
|
# if it's the first input (phone/email), we store against `recipient` as well, for easier extraction.
|
2022-12-05 15:33:44 -05:00
|
|
|
|
# Only if we're not on the test route, since that will already have the user's own number set
|
|
|
|
|
|
if step_index == 0:
|
2023-08-25 09:12:23 -07:00
|
|
|
|
session["recipient"] = form.placeholder_value.data
|
2017-05-04 09:30:55 +01:00
|
|
|
|
|
2023-08-25 09:12:23 -07:00
|
|
|
|
session["placeholders"][current_placeholder] = form.placeholder_value.data
|
2017-05-04 09:30:55 +01:00
|
|
|
|
|
2017-05-25 09:18:26 +01:00
|
|
|
|
if all_placeholders_in_session(placeholders):
|
2017-06-23 17:30:34 +01:00
|
|
|
|
return get_notification_check_endpoint(service_id, template)
|
2017-05-04 09:30:55 +01:00
|
|
|
|
|
2023-08-25 09:12:23 -07:00
|
|
|
|
return redirect(
|
|
|
|
|
|
url_for(
|
|
|
|
|
|
request.endpoint,
|
|
|
|
|
|
service_id=service_id,
|
|
|
|
|
|
template_id=template_id,
|
|
|
|
|
|
step_index=step_index + 1,
|
|
|
|
|
|
)
|
|
|
|
|
|
)
|
2016-03-29 15:59:53 +01:00
|
|
|
|
|
2020-04-09 16:25:48 +01:00
|
|
|
|
back_link = get_back_link(service_id, template, step_index, placeholders)
|
2017-05-04 09:30:55 +01:00
|
|
|
|
|
2020-07-21 16:06:33 +01:00
|
|
|
|
template.values = template_values
|
2017-05-16 17:17:11 +01:00
|
|
|
|
template.values[current_placeholder] = None
|
2017-05-04 09:30:55 +01:00
|
|
|
|
|
2016-05-05 08:39:36 +01:00
|
|
|
|
return render_template(
|
2023-08-25 09:12:23 -07:00
|
|
|
|
"views/send-test.html",
|
2017-11-20 16:45:59 +00:00
|
|
|
|
page_title=get_send_test_page_title(
|
|
|
|
|
|
template.template_type,
|
2023-08-25 09:12:23 -07:00
|
|
|
|
entering_recipient=not session["recipient"],
|
2018-08-06 11:20:50 +01:00
|
|
|
|
name=template.name,
|
2017-11-20 16:45:59 +00:00
|
|
|
|
),
|
2016-05-05 08:39:36 +01:00
|
|
|
|
template=template,
|
2017-05-04 09:30:55 +01:00
|
|
|
|
form=form,
|
2020-04-09 16:37:38 +01:00
|
|
|
|
skip_link=get_skip_link(step_index, template),
|
2017-05-04 09:30:55 +01:00
|
|
|
|
back_link=back_link,
|
2018-07-18 09:48:19 +01:00
|
|
|
|
link_to_upload=(
|
2023-08-25 09:12:23 -07:00
|
|
|
|
request.endpoint == "main.send_one_off_step" and step_index == 0
|
2018-07-18 09:48:19 +01:00
|
|
|
|
),
|
2016-05-05 08:39:36 +01:00
|
|
|
|
)
|
2016-02-12 10:55:21 +00:00
|
|
|
|
|
|
|
|
|
|
|
2022-12-05 15:33:44 -05:00
|
|
|
|
def _check_messages(service_id, template_id, upload_id, preview_row):
|
2018-05-03 13:35:59 +01:00
|
|
|
|
try:
|
2018-04-30 12:55:56 +01:00
|
|
|
|
# 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)
|
2022-08-05 00:25:03 -07:00
|
|
|
|
|
2018-05-03 13:35:59 +01:00
|
|
|
|
# the job exists already - so go back to the templates page
|
2018-04-30 12:55:56 +01:00
|
|
|
|
# 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.
|
2023-08-25 09:12:23 -07:00
|
|
|
|
raise PermanentRedirect(
|
|
|
|
|
|
url_for(
|
|
|
|
|
|
"main.send_messages", service_id=service_id, template_id=template_id
|
|
|
|
|
|
)
|
|
|
|
|
|
)
|
2018-05-03 13:35:59 +01:00
|
|
|
|
except HTTPError as e:
|
|
|
|
|
|
if e.status_code != 404:
|
|
|
|
|
|
raise
|
2018-04-30 12:55:56 +01:00
|
|
|
|
|
2021-06-23 15:56:05 +01:00
|
|
|
|
notification_count = service_api_client.get_notification_count(service_id)
|
2023-08-25 09:12:23 -07:00
|
|
|
|
remaining_messages = current_service.message_limit - notification_count
|
2016-04-04 14:28:52 +01:00
|
|
|
|
|
2016-03-07 18:47:05 +00:00
|
|
|
|
contents = s3download(service_id, upload_id)
|
2023-08-25 09:12:23 -07:00
|
|
|
|
db_template = current_service.get_template_with_user_permission_or_403(
|
|
|
|
|
|
template_id, current_user
|
|
|
|
|
|
)
|
2018-03-29 17:01:35 +01:00
|
|
|
|
|
2017-11-02 12:07:46 +00:00
|
|
|
|
email_reply_to = None
|
|
|
|
|
|
sms_sender = None
|
2023-08-25 09:12:23 -07:00
|
|
|
|
if db_template["template_type"] == "email":
|
2018-10-26 17:31:49 +01:00
|
|
|
|
email_reply_to = get_email_reply_to_address_from_session()
|
2023-08-25 09:12:23 -07:00
|
|
|
|
elif db_template["template_type"] == "sms":
|
2018-10-26 17:31:49 +01:00
|
|
|
|
sms_sender = get_sms_sender_from_session()
|
2019-10-08 14:56:00 +01:00
|
|
|
|
|
2016-12-08 11:50:59 +00:00
|
|
|
|
template = get_template(
|
2018-05-10 17:00:41 +01:00
|
|
|
|
db_template,
|
2016-12-08 11:50:59 +00:00
|
|
|
|
current_service,
|
2024-02-13 16:18:50 -08:00
|
|
|
|
show_recipient=False,
|
2017-11-02 12:07:46 +00:00
|
|
|
|
email_reply_to=email_reply_to,
|
2018-03-29 17:01:35 +01:00
|
|
|
|
sms_sender=sms_sender,
|
2016-02-26 10:54:06 +00:00
|
|
|
|
)
|
2024-02-16 17:19:03 -08:00
|
|
|
|
simplifed_template = get_template(
|
|
|
|
|
|
db_template,
|
|
|
|
|
|
current_service,
|
|
|
|
|
|
show_recipient=False,
|
|
|
|
|
|
)
|
2016-03-07 18:47:05 +00:00
|
|
|
|
recipients = RecipientCSV(
|
|
|
|
|
|
contents,
|
2024-02-16 17:19:03 -08:00
|
|
|
|
template=template or simplifed_template,
|
2016-04-07 14:30:51 +01:00
|
|
|
|
max_initial_rows_shown=50,
|
|
|
|
|
|
max_errors_shown=50,
|
2024-02-29 08:24:53 -08:00
|
|
|
|
guestlist=(
|
|
|
|
|
|
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
|
|
|
|
|
|
),
|
2017-04-26 16:19:49 +01:00
|
|
|
|
remaining_messages=remaining_messages,
|
2023-08-25 09:12:23 -07:00
|
|
|
|
allow_international_sms=current_service.has_permission("international_sms"),
|
2016-03-07 18:47:05 +00:00
|
|
|
|
)
|
2016-02-26 10:54:06 +00:00
|
|
|
|
|
2023-08-25 09:12:23 -07:00
|
|
|
|
if request.args.get("from_test"):
|
2022-12-05 15:33:44 -05:00
|
|
|
|
# TODO: may not be required after letters code removed
|
2023-08-25 09:12:23 -07:00
|
|
|
|
back_link = url_for(
|
|
|
|
|
|
"main.send_one_off", service_id=service_id, template_id=template.id
|
|
|
|
|
|
)
|
2024-02-06 16:08:14 -08:00
|
|
|
|
back_link_from_preview = url_for(
|
|
|
|
|
|
"main.send_one_off", service_id=service_id, template_id=template.id
|
|
|
|
|
|
)
|
2016-08-30 09:27:24 +01:00
|
|
|
|
choose_time_form = None
|
2016-05-05 08:39:36 +01:00
|
|
|
|
else:
|
2023-08-25 09:12:23 -07:00
|
|
|
|
back_link = url_for(
|
|
|
|
|
|
"main.send_messages", service_id=service_id, template_id=template.id
|
|
|
|
|
|
)
|
2024-02-06 16:08:14 -08:00
|
|
|
|
back_link_from_preview = url_for(
|
2024-02-08 18:43:17 -08:00
|
|
|
|
"main.check_messages",
|
|
|
|
|
|
service_id=service_id,
|
|
|
|
|
|
template_id=template.id,
|
|
|
|
|
|
upload_id=upload_id,
|
2024-02-06 16:08:14 -08:00
|
|
|
|
)
|
2016-08-30 09:27:24 +01:00
|
|
|
|
choose_time_form = ChooseTimeForm()
|
2016-05-05 08:39:36 +01:00
|
|
|
|
|
2018-01-15 11:35:45 +00:00
|
|
|
|
if preview_row < 2:
|
|
|
|
|
|
abort(404)
|
|
|
|
|
|
|
2018-03-05 15:57:10 +00:00
|
|
|
|
if preview_row < len(recipients) + 2:
|
|
|
|
|
|
template.values = recipients[preview_row - 2].recipient_and_personalisation
|
2024-02-16 17:19:03 -08:00
|
|
|
|
simplifed_template.values = recipients[preview_row - 2].recipient_and_personalisation
|
2018-01-15 11:35:45 +00:00
|
|
|
|
elif preview_row > 2:
|
2017-12-20 11:48:30 +00:00
|
|
|
|
abort(404)
|
|
|
|
|
|
|
2023-08-25 09:12:23 -07:00
|
|
|
|
original_file_name = get_csv_metadata(service_id, upload_id).get(
|
|
|
|
|
|
"original_file_name", ""
|
|
|
|
|
|
)
|
2019-10-08 14:56:00 +01:00
|
|
|
|
|
2016-12-20 11:56:22 +00:00
|
|
|
|
return dict(
|
2016-03-07 18:47:05 +00:00
|
|
|
|
recipients=recipients,
|
|
|
|
|
|
template=template,
|
2016-06-03 13:52:15 +01:00
|
|
|
|
errors=recipients.has_errors,
|
|
|
|
|
|
row_errors=get_errors_for_csv(recipients, template.template_type),
|
2018-03-05 15:57:10 +00:00
|
|
|
|
count_of_recipients=len(recipients),
|
|
|
|
|
|
count_of_displayed_recipients=len(list(recipients.displayed_rows)),
|
2020-10-21 13:07:59 +01:00
|
|
|
|
original_file_name=original_file_name,
|
2016-03-29 15:59:53 +01:00
|
|
|
|
upload_id=upload_id,
|
2016-04-22 09:36:42 +01:00
|
|
|
|
form=CsvUploadForm(),
|
2016-07-25 14:16:34 +01:00
|
|
|
|
remaining_messages=remaining_messages,
|
2016-08-30 09:27:24 +01:00
|
|
|
|
choose_time_form=choose_time_form,
|
2016-07-05 11:39:07 +01:00
|
|
|
|
back_link=back_link,
|
2024-02-06 16:08:14 -08:00
|
|
|
|
back_link_from_preview=back_link_from_preview,
|
2020-04-19 22:46:13 +01:00
|
|
|
|
first_recipient_column=recipients.recipient_column_headers[0],
|
2018-01-15 11:25:11 +00:00
|
|
|
|
preview_row=preview_row,
|
2019-02-04 14:08:11 +00:00
|
|
|
|
sent_previously=job_api_client.has_sent_previously(
|
2023-08-25 09:12:23 -07:00
|
|
|
|
service_id, template.id, db_template["version"], original_file_name
|
2019-10-01 15:34:46 +01:00
|
|
|
|
),
|
2024-02-08 18:43:17 -08:00
|
|
|
|
template_id=template_id,
|
2024-02-16 17:19:03 -08:00
|
|
|
|
simplifed_template=simplifed_template,
|
2016-03-07 18:47:05 +00:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
2023-08-25 09:12:23 -07:00
|
|
|
|
@main.route(
|
|
|
|
|
|
"/services/<uuid:service_id>/<uuid:template_id>/check/<uuid:upload_id>",
|
|
|
|
|
|
methods=["GET"],
|
|
|
|
|
|
)
|
2019-11-29 13:03:23 +00:00
|
|
|
|
@main.route(
|
|
|
|
|
|
"/services/<uuid:service_id>/<uuid:template_id>/check/<uuid:upload_id>/row-<int:row_index>",
|
2023-08-25 09:12:23 -07:00
|
|
|
|
methods=["GET"],
|
2019-11-29 13:03:23 +00:00
|
|
|
|
)
|
2023-08-25 09:12:23 -07:00
|
|
|
|
@user_has_permissions("send_messages", restrict_admin_usage=True)
|
2018-03-29 17:01:35 +01:00
|
|
|
|
def check_messages(service_id, template_id, upload_id, row_index=2):
|
2018-05-11 08:46:42 +01:00
|
|
|
|
data = _check_messages(service_id, template_id, upload_id, row_index)
|
2023-08-25 09:12:23 -07:00
|
|
|
|
data["allowed_file_extensions"] = Spreadsheet.ALLOWED_FILE_EXTENSIONS
|
2017-07-20 08:59:49 +01:00
|
|
|
|
|
2017-07-20 09:10:23 +01:00
|
|
|
|
if (
|
2023-08-25 09:12:23 -07:00
|
|
|
|
data["recipients"].too_many_rows
|
|
|
|
|
|
or not data["count_of_recipients"]
|
|
|
|
|
|
or not data["recipients"].has_recipient_columns
|
|
|
|
|
|
or data["recipients"].duplicate_recipient_column_headers
|
|
|
|
|
|
or data["recipients"].missing_column_headers
|
|
|
|
|
|
or data["sent_previously"]
|
2017-07-20 09:10:23 +01:00
|
|
|
|
):
|
2023-08-25 09:12:23 -07:00
|
|
|
|
return render_template("views/check/column-errors.html", **data)
|
2017-07-20 09:10:23 +01:00
|
|
|
|
|
2023-08-25 09:12:23 -07:00
|
|
|
|
if data["row_errors"]:
|
|
|
|
|
|
return render_template("views/check/row-errors.html", **data)
|
2017-07-20 08:59:49 +01:00
|
|
|
|
|
2023-08-25 09:12:23 -07:00
|
|
|
|
if data["errors"]:
|
|
|
|
|
|
return render_template("views/check/column-errors.html", **data)
|
2017-07-20 08:59:49 +01:00
|
|
|
|
|
2018-11-06 14:22:22 +00:00
|
|
|
|
metadata_kwargs = {
|
2023-08-25 09:12:23 -07:00
|
|
|
|
"notification_count": data["count_of_recipients"],
|
|
|
|
|
|
"template_id": template_id,
|
|
|
|
|
|
"valid": True,
|
|
|
|
|
|
"original_file_name": data.get("original_file_name", ""),
|
2018-11-06 14:22:22 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2023-08-25 09:12:23 -07:00
|
|
|
|
if session.get("sender_id"):
|
|
|
|
|
|
metadata_kwargs["sender_id"] = session["sender_id"]
|
2018-11-06 14:22:22 +00:00
|
|
|
|
|
|
|
|
|
|
set_metadata_on_csv_upload(service_id, upload_id, **metadata_kwargs)
|
2024-02-16 11:44:25 -08:00
|
|
|
|
|
2023-08-25 09:12:23 -07:00
|
|
|
|
return render_template("views/check/ok.html", **data)
|
2016-12-20 11:56:22 +00:00
|
|
|
|
|
|
|
|
|
|
|
2024-02-06 16:08:14 -08:00
|
|
|
|
@main.route(
|
|
|
|
|
|
"/services/<uuid:service_id>/<uuid:template_id>/check/<uuid:upload_id>/preview",
|
2024-03-08 15:05:44 -08:00
|
|
|
|
methods=["POST"],
|
2024-02-08 18:43:17 -08:00
|
|
|
|
)
|
|
|
|
|
|
@main.route(
|
|
|
|
|
|
"/services/<uuid:service_id>/<uuid:template_id>/check/<uuid:upload_id>/preview/row-<int:row_index>",
|
2024-03-08 15:05:44 -08:00
|
|
|
|
methods=["POST"],
|
2024-02-06 16:08:14 -08:00
|
|
|
|
)
|
|
|
|
|
|
@user_has_permissions("send_messages", restrict_admin_usage=True)
|
|
|
|
|
|
def preview_job(service_id, template_id, upload_id, row_index=2):
|
2024-03-08 15:05:44 -08:00
|
|
|
|
session["scheduled_for"] = request.form.get("scheduled_for", "")
|
2024-02-06 16:08:14 -08:00
|
|
|
|
data = _check_messages(service_id, template_id, upload_id, row_index)
|
|
|
|
|
|
|
2024-02-08 18:43:17 -08:00
|
|
|
|
return render_template(
|
2024-02-16 17:19:03 -08:00
|
|
|
|
"views/check/preview.html",
|
|
|
|
|
|
scheduled_for=session["scheduled_for"],
|
|
|
|
|
|
**data,
|
2024-02-08 18:43:17 -08:00
|
|
|
|
)
|
2024-02-06 17:06:18 -08:00
|
|
|
|
|
2024-02-06 16:08:14 -08:00
|
|
|
|
|
2023-08-25 09:12:23 -07:00
|
|
|
|
@main.route("/services/<uuid:service_id>/start-job/<uuid:upload_id>", methods=["POST"])
|
|
|
|
|
|
@user_has_permissions("send_messages", restrict_admin_usage=True)
|
2016-03-07 18:47:05 +00:00
|
|
|
|
def start_job(service_id, upload_id):
|
2024-02-08 18:43:17 -08:00
|
|
|
|
scheduled_for = session.pop("scheduled_for", None)
|
2016-03-08 17:50:18 +00:00
|
|
|
|
job_api_client.create_job(
|
|
|
|
|
|
upload_id,
|
|
|
|
|
|
service_id,
|
2024-02-02 14:52:48 -08:00
|
|
|
|
scheduled_for=scheduled_for,
|
2016-03-08 17:50:18 +00:00
|
|
|
|
)
|
2016-03-07 18:47:05 +00:00
|
|
|
|
|
2023-08-25 09:12:23 -07:00
|
|
|
|
session.pop("sender_id", None)
|
2018-11-06 14:22:22 +00:00
|
|
|
|
|
2016-03-07 18:47:05 +00:00
|
|
|
|
return redirect(
|
2017-07-13 11:28:37 +01:00
|
|
|
|
url_for(
|
2023-08-25 09:12:23 -07:00
|
|
|
|
"main.view_job",
|
2017-07-13 11:28:37 +01:00
|
|
|
|
job_id=upload_id,
|
|
|
|
|
|
service_id=service_id,
|
|
|
|
|
|
)
|
2016-02-17 15:49:07 +00:00
|
|
|
|
)
|
2016-07-01 10:49:54 +01:00
|
|
|
|
|
|
|
|
|
|
|
2017-05-25 09:18:26 +01:00
|
|
|
|
def fields_to_fill_in(template, prefill_current_user=False):
|
2020-04-27 10:57:25 +01:00
|
|
|
|
if not prefill_current_user:
|
2023-08-25 09:12:23 -07:00
|
|
|
|
return first_column_headings[template.template_type] + list(
|
|
|
|
|
|
template.placeholders
|
|
|
|
|
|
)
|
2017-05-04 09:30:55 +01:00
|
|
|
|
|
2023-08-25 09:12:23 -07:00
|
|
|
|
if template.template_type == "sms":
|
|
|
|
|
|
session["recipient"] = current_user.mobile_number
|
|
|
|
|
|
session["placeholders"]["phone number"] = current_user.mobile_number
|
2019-06-04 16:12:09 +01:00
|
|
|
|
else:
|
2023-08-25 09:12:23 -07:00
|
|
|
|
session["recipient"] = current_user.email_address
|
|
|
|
|
|
session["placeholders"]["email address"] = current_user.email_address
|
2017-05-04 09:30:55 +01:00
|
|
|
|
|
|
|
|
|
|
return list(template.placeholders)
|
|
|
|
|
|
|
|
|
|
|
|
|
2017-06-23 17:30:34 +01:00
|
|
|
|
def get_normalised_placeholders_from_session():
|
2023-08-25 09:12:23 -07:00
|
|
|
|
return InsensitiveDict(session.get("placeholders", {}))
|
2017-05-04 09:30:55 +01:00
|
|
|
|
|
|
|
|
|
|
|
2017-06-29 15:31:44 +01:00
|
|
|
|
def get_recipient_and_placeholders_from_session(template_type):
|
2017-06-26 14:56:14 +01:00
|
|
|
|
placeholders = get_normalised_placeholders_from_session()
|
|
|
|
|
|
|
2023-08-25 09:12:23 -07:00
|
|
|
|
if template_type == "sms":
|
|
|
|
|
|
placeholders["phone_number"] = session["recipient"]
|
2017-06-26 14:56:14 +01:00
|
|
|
|
else:
|
2023-08-25 09:12:23 -07:00
|
|
|
|
placeholders["email_address"] = session["recipient"]
|
2017-06-26 14:56:14 +01:00
|
|
|
|
|
|
|
|
|
|
return placeholders
|
|
|
|
|
|
|
|
|
|
|
|
|
2017-05-25 09:18:26 +01:00
|
|
|
|
def all_placeholders_in_session(placeholders):
|
|
|
|
|
|
return all(
|
2023-08-25 09:12:23 -07:00
|
|
|
|
get_normalised_placeholders_from_session().get(placeholder, False)
|
|
|
|
|
|
not in (False, None)
|
2017-05-25 09:18:26 +01:00
|
|
|
|
for placeholder in placeholders
|
|
|
|
|
|
)
|
2017-05-25 13:31:23 +01:00
|
|
|
|
|
|
|
|
|
|
|
2020-10-05 11:55:15 +01:00
|
|
|
|
def get_send_test_page_title(template_type, entering_recipient, name=None):
|
2017-11-20 16:45:59 +00:00
|
|
|
|
if entering_recipient:
|
2023-08-25 09:12:23 -07:00
|
|
|
|
return "Send ‘{}’".format(name)
|
|
|
|
|
|
return "Personalize this message"
|
2017-06-22 16:00:14 +01:00
|
|
|
|
|
|
|
|
|
|
|
2024-02-08 18:43:17 -08:00
|
|
|
|
def get_back_link(
|
|
|
|
|
|
service_id,
|
|
|
|
|
|
template,
|
|
|
|
|
|
step_index,
|
|
|
|
|
|
placeholders=None,
|
|
|
|
|
|
preview=False,
|
|
|
|
|
|
):
|
2024-02-06 16:08:14 -08:00
|
|
|
|
if preview:
|
|
|
|
|
|
return url_for(
|
|
|
|
|
|
"main.check_notification",
|
|
|
|
|
|
service_id=service_id,
|
|
|
|
|
|
template_id=template.id,
|
|
|
|
|
|
)
|
|
|
|
|
|
|
2020-10-05 11:55:15 +01:00
|
|
|
|
if step_index == 0:
|
2021-07-21 16:06:23 +01:00
|
|
|
|
if should_skip_template_page(template._template):
|
2018-06-13 14:32:52 +01:00
|
|
|
|
return url_for(
|
2023-08-25 09:12:23 -07:00
|
|
|
|
".choose_template",
|
2018-06-13 14:32:52 +01:00
|
|
|
|
service_id=service_id,
|
|
|
|
|
|
)
|
2018-08-09 16:29:51 +01:00
|
|
|
|
else:
|
|
|
|
|
|
return url_for(
|
2023-08-25 09:12:23 -07:00
|
|
|
|
".view_template",
|
2018-08-09 16:29:51 +01:00
|
|
|
|
service_id=service_id,
|
|
|
|
|
|
template_id=template.id,
|
|
|
|
|
|
)
|
|
|
|
|
|
|
2020-04-09 16:25:48 +01:00
|
|
|
|
return url_for(
|
2023-08-25 09:12:23 -07:00
|
|
|
|
"main.send_one_off_step",
|
2020-04-09 16:25:48 +01:00
|
|
|
|
service_id=service_id,
|
|
|
|
|
|
template_id=template.id,
|
|
|
|
|
|
step_index=step_index - 1,
|
|
|
|
|
|
)
|
2017-06-23 15:02:20 +01:00
|
|
|
|
|
|
|
|
|
|
|
2020-04-09 16:37:38 +01:00
|
|
|
|
def get_skip_link(step_index, template):
|
|
|
|
|
|
if (
|
2023-08-25 09:12:23 -07:00
|
|
|
|
request.endpoint == "main.send_one_off_step"
|
2020-04-09 16:37:38 +01:00
|
|
|
|
and step_index == 0
|
2020-10-05 16:16:11 +01:00
|
|
|
|
and template.template_type in ("sms", "email")
|
2023-08-25 09:12:23 -07:00
|
|
|
|
and not (template.template_type == "sms" and current_user.mobile_number is None)
|
|
|
|
|
|
and current_user.has_permissions("manage_templates", "manage_service")
|
2020-04-09 16:37:38 +01:00
|
|
|
|
):
|
|
|
|
|
|
return (
|
2023-08-25 09:12:23 -07:00
|
|
|
|
"Use my {}".format(first_column_headings[template.template_type][0]),
|
|
|
|
|
|
url_for(
|
|
|
|
|
|
".send_one_off_to_myself",
|
|
|
|
|
|
service_id=current_service.id,
|
|
|
|
|
|
template_id=template.id,
|
|
|
|
|
|
),
|
2020-04-09 16:37:38 +01:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
2023-08-25 09:12:23 -07:00
|
|
|
|
@main.route(
|
|
|
|
|
|
"/services/<uuid:service_id>/template/<uuid:template_id>/one-off/send-to-myself",
|
|
|
|
|
|
methods=["GET"],
|
|
|
|
|
|
)
|
|
|
|
|
|
@user_has_permissions("send_messages", restrict_admin_usage=True)
|
2020-10-05 16:16:11 +01:00
|
|
|
|
def send_one_off_to_myself(service_id, template_id):
|
2023-08-25 09:12:23 -07:00
|
|
|
|
db_template = current_service.get_template_with_user_permission_or_403(
|
|
|
|
|
|
template_id, current_user
|
|
|
|
|
|
)
|
2020-10-05 16:16:11 +01:00
|
|
|
|
|
2023-08-25 09:12:23 -07:00
|
|
|
|
if db_template["template_type"] not in ("sms", "email"):
|
2020-10-05 16:16:11 +01:00
|
|
|
|
abort(404)
|
|
|
|
|
|
|
|
|
|
|
|
# We aren't concerned with creating the exact template (for example adding recipient and sender names)
|
|
|
|
|
|
# we just want to create enough to use `fields_to_fill_in`
|
|
|
|
|
|
template = get_template(
|
|
|
|
|
|
db_template,
|
|
|
|
|
|
current_service,
|
|
|
|
|
|
)
|
|
|
|
|
|
fields_to_fill_in(template, prefill_current_user=True)
|
|
|
|
|
|
|
2023-08-25 09:12:23 -07:00
|
|
|
|
return redirect(
|
|
|
|
|
|
url_for(
|
|
|
|
|
|
"main.send_one_off_step",
|
|
|
|
|
|
service_id=service_id,
|
|
|
|
|
|
template_id=template_id,
|
|
|
|
|
|
step_index=1,
|
|
|
|
|
|
)
|
|
|
|
|
|
)
|
2020-10-05 16:16:11 +01:00
|
|
|
|
|
|
|
|
|
|
|
2023-08-25 09:12:23 -07:00
|
|
|
|
@main.route(
|
|
|
|
|
|
"/services/<uuid:service_id>/template/<uuid:template_id>/notification/check",
|
|
|
|
|
|
methods=["GET"],
|
|
|
|
|
|
)
|
|
|
|
|
|
@user_has_permissions("send_messages", restrict_admin_usage=True)
|
2017-06-23 15:02:20 +01:00
|
|
|
|
def check_notification(service_id, template_id):
|
2018-10-30 14:24:50 +00:00
|
|
|
|
return render_template(
|
2023-08-25 09:12:23 -07:00
|
|
|
|
"views/notifications/check.html",
|
2018-10-30 14:24:50 +00:00
|
|
|
|
**_check_notification(service_id, template_id),
|
|
|
|
|
|
)
|
2017-06-29 15:31:44 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _check_notification(service_id, template_id, exception=None):
|
2023-08-25 09:12:23 -07:00
|
|
|
|
db_template = current_service.get_template_with_user_permission_or_403(
|
|
|
|
|
|
template_id, current_user
|
|
|
|
|
|
)
|
2017-11-02 12:07:46 +00:00
|
|
|
|
email_reply_to = None
|
|
|
|
|
|
sms_sender = None
|
2023-08-25 09:12:23 -07:00
|
|
|
|
if db_template["template_type"] == "email":
|
2018-10-26 17:31:49 +01:00
|
|
|
|
email_reply_to = get_email_reply_to_address_from_session()
|
2023-08-25 09:12:23 -07:00
|
|
|
|
elif db_template["template_type"] == "sms":
|
2018-10-26 17:31:49 +01:00
|
|
|
|
sms_sender = get_sms_sender_from_session()
|
2017-06-23 15:02:20 +01:00
|
|
|
|
template = get_template(
|
|
|
|
|
|
db_template,
|
|
|
|
|
|
current_service,
|
2017-10-17 16:06:15 +01:00
|
|
|
|
show_recipient=True,
|
2017-11-02 12:07:46 +00:00
|
|
|
|
email_reply_to=email_reply_to,
|
2018-10-30 14:24:50 +00:00
|
|
|
|
sms_sender=sms_sender,
|
2017-06-23 15:02:20 +01:00
|
|
|
|
)
|
2024-02-16 17:19:03 -08:00
|
|
|
|
simplifed_template = get_template(
|
|
|
|
|
|
db_template,
|
|
|
|
|
|
current_service,
|
|
|
|
|
|
)
|
2020-04-15 15:42:25 +01:00
|
|
|
|
placeholders = fields_to_fill_in(template)
|
|
|
|
|
|
|
|
|
|
|
|
back_link = get_back_link(service_id, template, len(placeholders), placeholders)
|
2017-06-26 17:09:51 +01:00
|
|
|
|
|
2024-02-08 18:43:17 -08:00
|
|
|
|
back_link_from_preview = get_back_link(
|
|
|
|
|
|
service_id, template, len(placeholders), placeholders, preview=True
|
|
|
|
|
|
)
|
2024-02-06 16:08:14 -08:00
|
|
|
|
|
2024-01-16 15:37:56 -08:00
|
|
|
|
choose_time_form = ChooseTimeForm()
|
|
|
|
|
|
|
2023-08-25 09:12:23 -07:00
|
|
|
|
if (not session.get("recipient")) or not all_placeholders_in_session(
|
|
|
|
|
|
template.placeholders
|
2017-06-26 17:09:51 +01:00
|
|
|
|
):
|
2019-03-21 16:41:22 +00:00
|
|
|
|
raise PermanentRedirect(back_link)
|
2017-06-26 17:09:51 +01:00
|
|
|
|
|
2023-08-25 09:12:23 -07:00
|
|
|
|
template.values = get_recipient_and_placeholders_from_session(
|
|
|
|
|
|
template.template_type
|
|
|
|
|
|
)
|
2018-10-30 14:24:50 +00:00
|
|
|
|
return dict(
|
2017-06-23 15:02:20 +01:00
|
|
|
|
template=template,
|
|
|
|
|
|
back_link=back_link,
|
2024-02-06 16:08:14 -08:00
|
|
|
|
back_link_from_preview=back_link_from_preview,
|
2024-01-16 15:37:56 -08:00
|
|
|
|
choose_time_form=choose_time_form,
|
2018-10-30 14:24:50 +00:00
|
|
|
|
**(get_template_error_dict(exception) if exception else {}),
|
2024-02-16 17:19:03 -08:00
|
|
|
|
simplifed_template=simplifed_template
|
2017-06-23 15:02:20 +01:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
2017-06-29 15:31:44 +01:00
|
|
|
|
def get_template_error_dict(exception):
|
2017-06-29 16:06:36 +01:00
|
|
|
|
# TODO: Make API return some computer-friendly identifier as well as the end user error messages
|
2023-08-25 09:12:23 -07:00
|
|
|
|
if "service is in trial mode" in exception.message:
|
|
|
|
|
|
error = "not-allowed-to-send-to"
|
|
|
|
|
|
elif "Exceeded send limits" in exception.message:
|
|
|
|
|
|
error = "too-many-messages"
|
2020-03-09 17:03:22 +00:00
|
|
|
|
# the error from the api is changing for message-too-long, but we need both until the api is deployed.
|
2023-08-25 09:12:23 -07:00
|
|
|
|
elif (
|
|
|
|
|
|
"Content for template has a character count greater than the limit of"
|
|
|
|
|
|
in exception.message
|
|
|
|
|
|
):
|
|
|
|
|
|
error = "message-too-long"
|
|
|
|
|
|
elif "Text messages cannot be longer than" in exception.message:
|
|
|
|
|
|
error = "message-too-long"
|
2017-06-29 15:31:44 +01:00
|
|
|
|
else:
|
|
|
|
|
|
raise exception
|
|
|
|
|
|
|
|
|
|
|
|
return {
|
2023-08-25 09:12:23 -07:00
|
|
|
|
"error": error,
|
|
|
|
|
|
"SMS_CHAR_COUNT_LIMIT": SMS_CHAR_COUNT_LIMIT,
|
|
|
|
|
|
"current_service": current_service,
|
2017-06-29 16:06:36 +01:00
|
|
|
|
# used to trigger CSV specific err msg content, so not needed for single notification errors.
|
2023-08-25 09:12:23 -07:00
|
|
|
|
"original_file_name": False,
|
2017-06-29 15:31:44 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-02-06 17:06:18 -08:00
|
|
|
|
|
2024-02-06 16:08:14 -08:00
|
|
|
|
@main.route(
|
|
|
|
|
|
"/services/<uuid:service_id>/template/<uuid:template_id>/notification/check/preview",
|
2024-03-08 15:05:44 -08:00
|
|
|
|
methods=["POST"],
|
2024-02-06 16:08:14 -08:00
|
|
|
|
)
|
|
|
|
|
|
@user_has_permissions("send_messages", restrict_admin_usage=True)
|
|
|
|
|
|
def preview_notification(service_id, template_id):
|
|
|
|
|
|
recipient = get_recipient()
|
|
|
|
|
|
if not recipient:
|
|
|
|
|
|
return redirect(
|
|
|
|
|
|
url_for(
|
|
|
|
|
|
".send_one_off",
|
|
|
|
|
|
service_id=service_id,
|
|
|
|
|
|
template_id=template_id,
|
|
|
|
|
|
)
|
|
|
|
|
|
)
|
|
|
|
|
|
|
2024-03-08 15:05:44 -08:00
|
|
|
|
session["scheduled_for"] = request.form.get("scheduled_for", "")
|
2024-02-06 16:08:14 -08:00
|
|
|
|
|
|
|
|
|
|
return render_template(
|
|
|
|
|
|
"views/notifications/preview.html",
|
2024-02-16 17:19:03 -08:00
|
|
|
|
**_check_notification(service_id, template_id),
|
2024-02-08 18:43:17 -08:00
|
|
|
|
scheduled_for=session["scheduled_for"],
|
2024-02-16 11:44:25 -08:00
|
|
|
|
recipient=recipient,
|
2024-02-06 16:08:14 -08:00
|
|
|
|
)
|
|
|
|
|
|
|
2017-06-29 15:31:44 +01:00
|
|
|
|
|
2023-08-25 09:12:23 -07:00
|
|
|
|
@main.route(
|
|
|
|
|
|
"/services/<uuid:service_id>/template/<uuid:template_id>/notification/check",
|
|
|
|
|
|
methods=["POST"],
|
|
|
|
|
|
)
|
|
|
|
|
|
@user_has_permissions("send_messages", restrict_admin_usage=True)
|
2017-06-23 15:02:20 +01:00
|
|
|
|
def send_notification(service_id, template_id):
|
2024-02-08 18:43:17 -08:00
|
|
|
|
scheduled_for = session.pop("scheduled_for", "")
|
2022-02-18 12:38:02 +00:00
|
|
|
|
recipient = get_recipient()
|
|
|
|
|
|
if not recipient:
|
2023-08-25 09:12:23 -07:00
|
|
|
|
return redirect(
|
|
|
|
|
|
url_for(
|
|
|
|
|
|
".send_one_off",
|
|
|
|
|
|
service_id=service_id,
|
|
|
|
|
|
template_id=template_id,
|
|
|
|
|
|
)
|
|
|
|
|
|
)
|
2019-03-19 16:25:44 +00:00
|
|
|
|
|
2023-12-14 13:24:34 -08:00
|
|
|
|
keys = []
|
|
|
|
|
|
values = []
|
|
|
|
|
|
for k, v in session["placeholders"].items():
|
|
|
|
|
|
keys.append(k)
|
|
|
|
|
|
values.append(v)
|
|
|
|
|
|
|
|
|
|
|
|
data = ",".join(keys)
|
|
|
|
|
|
vals = ",".join(values)
|
|
|
|
|
|
data = f"{data}\r\n{vals}"
|
|
|
|
|
|
|
2023-12-20 10:26:14 -08:00
|
|
|
|
filename = f"one-off-{current_user.name}-{uuid.uuid4()}.csv"
|
2023-12-18 12:31:40 -08:00
|
|
|
|
my_data = {"filename": filename, "template_id": template_id, "data": data}
|
2023-12-14 13:24:34 -08:00
|
|
|
|
upload_id = s3upload(service_id, my_data)
|
|
|
|
|
|
form = CsvUploadForm()
|
|
|
|
|
|
form.file.data = my_data
|
|
|
|
|
|
form.file.name = filename
|
2023-12-18 12:31:40 -08:00
|
|
|
|
|
|
|
|
|
|
check_message_output = check_messages(service_id, template_id, upload_id, 2)
|
|
|
|
|
|
if "You cannot send to" in check_message_output:
|
|
|
|
|
|
return check_messages(service_id, template_id, upload_id, 2)
|
2023-12-19 08:08:02 -08:00
|
|
|
|
|
2023-12-18 12:31:40 -08:00
|
|
|
|
job_api_client.create_job(
|
|
|
|
|
|
upload_id,
|
|
|
|
|
|
service_id,
|
2024-02-06 16:08:14 -08:00
|
|
|
|
scheduled_for=scheduled_for,
|
2023-12-18 12:31:40 -08:00
|
|
|
|
template_id=template_id,
|
|
|
|
|
|
original_file_name=filename,
|
|
|
|
|
|
notification_count=1,
|
|
|
|
|
|
valid="True",
|
|
|
|
|
|
)
|
2023-12-14 13:24:34 -08:00
|
|
|
|
|
2023-12-15 10:29:42 -08:00
|
|
|
|
session.pop("recipient")
|
|
|
|
|
|
session.pop("placeholders")
|
2023-12-14 13:24:34 -08:00
|
|
|
|
|
2023-12-15 10:29:42 -08:00
|
|
|
|
# We have to wait for the job to run and create the notification in the database
|
|
|
|
|
|
time.sleep(0.1)
|
2023-12-20 10:26:14 -08:00
|
|
|
|
notifications = notification_api_client.get_notifications_for_service(
|
2023-12-15 10:29:42 -08:00
|
|
|
|
service_id, job_id=upload_id, include_one_off=True
|
|
|
|
|
|
)
|
|
|
|
|
|
attempts = 0
|
2024-01-29 13:17:50 -08:00
|
|
|
|
|
|
|
|
|
|
# The response can come back in different forms of incompleteness
|
|
|
|
|
|
while (
|
|
|
|
|
|
notifications["total"] == 0
|
|
|
|
|
|
and notifications["notifications"] == []
|
|
|
|
|
|
and attempts < 50
|
|
|
|
|
|
):
|
2023-12-20 10:26:14 -08:00
|
|
|
|
notifications = notification_api_client.get_notifications_for_service(
|
2023-12-15 10:29:42 -08:00
|
|
|
|
service_id, job_id=upload_id, include_one_off=True
|
|
|
|
|
|
)
|
|
|
|
|
|
time.sleep(0.1)
|
|
|
|
|
|
attempts = attempts + 1
|
2023-12-20 10:26:14 -08:00
|
|
|
|
|
2024-01-29 13:17:50 -08:00
|
|
|
|
if notifications["total"] == 0 and attempts == 50:
|
2023-12-18 12:31:40 -08:00
|
|
|
|
# This shows the job we auto-generated for the user
|
|
|
|
|
|
return redirect(
|
|
|
|
|
|
url_for(
|
|
|
|
|
|
"main.view_job",
|
|
|
|
|
|
service_id=service_id,
|
|
|
|
|
|
job_id=upload_id,
|
|
|
|
|
|
)
|
2023-12-15 10:29:42 -08:00
|
|
|
|
)
|
2017-06-23 15:02:20 +01:00
|
|
|
|
|
2023-08-25 09:12:23 -07:00
|
|
|
|
return redirect(
|
|
|
|
|
|
url_for(
|
|
|
|
|
|
".view_notification",
|
|
|
|
|
|
service_id=service_id,
|
2023-12-15 10:29:42 -08:00
|
|
|
|
from_job=upload_id,
|
2023-12-20 10:26:14 -08:00
|
|
|
|
notification_id=notifications["notifications"][0]["id"],
|
2023-08-25 09:12:23 -07:00
|
|
|
|
# used to show the final step of the tour (help=3) or not show
|
|
|
|
|
|
# a back link on a just sent one off notification (help=0)
|
|
|
|
|
|
help=request.args.get("help"),
|
|
|
|
|
|
)
|
|
|
|
|
|
)
|
2017-10-17 16:06:15 +01:00
|
|
|
|
|
|
|
|
|
|
|
2018-10-26 17:31:49 +01:00
|
|
|
|
def get_email_reply_to_address_from_session():
|
2023-08-25 09:12:23 -07:00
|
|
|
|
if session.get("sender_id"):
|
|
|
|
|
|
return current_service.get_email_reply_to_address(session["sender_id"])[
|
|
|
|
|
|
"email_address"
|
|
|
|
|
|
]
|
2017-11-02 12:07:46 +00:00
|
|
|
|
|
|
|
|
|
|
|
2018-10-26 17:31:49 +01:00
|
|
|
|
def get_sms_sender_from_session():
|
2023-08-25 09:12:23 -07:00
|
|
|
|
if session.get("sender_id"):
|
|
|
|
|
|
return current_service.get_sms_sender(session["sender_id"])["sms_sender"]
|
2018-06-08 12:49:29 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_spreadsheet_column_headings_from_template(template):
|
|
|
|
|
|
column_headings = []
|
|
|
|
|
|
|
2022-12-05 15:33:44 -05:00
|
|
|
|
recipient_columns = first_column_headings[template.template_type]
|
2020-04-27 10:57:25 +01:00
|
|
|
|
|
2023-08-25 09:12:23 -07:00
|
|
|
|
for column_heading in recipient_columns + list(template.placeholders):
|
2022-02-04 10:43:36 +00:00
|
|
|
|
if column_heading not in InsensitiveDict.from_keys(column_headings):
|
2018-06-08 12:49:29 +01:00
|
|
|
|
column_headings.append(column_heading)
|
|
|
|
|
|
|
|
|
|
|
|
return column_headings
|
2022-02-18 12:38:02 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_recipient():
|
2023-08-25 09:12:23 -07:00
|
|
|
|
if {"recipient", "placeholders"} - set(session.keys()):
|
2022-02-18 12:38:02 +00:00
|
|
|
|
return None
|
|
|
|
|
|
|
2023-08-25 09:12:23 -07:00
|
|
|
|
return session["recipient"] or InsensitiveDict(session["placeholders"]).get(
|
|
|
|
|
|
"address line 1"
|
2022-02-18 12:38:02 +00:00
|
|
|
|
)
|