mirror of
https://github.com/GSA/notifications-admin.git
synced 2026-07-31 20:00:00 -04:00
Added Multiple SMS sender functionality
This commit is contained in:
@@ -505,6 +505,7 @@ class ServiceSmsSender(Form):
|
||||
Length(max=11, message="Enter 11 characters or fewer")
|
||||
]
|
||||
)
|
||||
is_default = BooleanField("Make this text message sender the default")
|
||||
|
||||
def validate_sms_sender(self, field):
|
||||
if field.data and not re.match(r'^[a-zA-Z0-9\s]+$', field.data):
|
||||
@@ -674,6 +675,19 @@ class PasswordFieldShowHasContent(StringField):
|
||||
widget = widgets.PasswordInput(hide_value=False)
|
||||
|
||||
|
||||
class ServiceInboundNumberForm(Form):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.inbound_number.choices = kwargs['inbound_number_choices']
|
||||
|
||||
inbound_number = RadioField(
|
||||
"Select your inbound number",
|
||||
validators=[
|
||||
DataRequired("Option must be selected")
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
class ServiceInboundApiForm(Form):
|
||||
url = StringField("Inbound sms url",
|
||||
validators=[DataRequired(message='Can’t be empty'),
|
||||
|
||||
@@ -28,6 +28,7 @@ from app.main.forms import (
|
||||
RenameServiceForm,
|
||||
RequestToGoLiveForm,
|
||||
ServiceReplyToEmailForm,
|
||||
ServiceInboundNumberForm,
|
||||
ServiceSmsSender,
|
||||
ServiceLetterContactBlockForm,
|
||||
ServiceBrandingOrg,
|
||||
@@ -82,6 +83,11 @@ def service_settings(service_id):
|
||||
default_letter_contact_block = next(
|
||||
(Field(x['contact_block'], html='escape') for x in letter_contact_details if x['is_default']), "Not set"
|
||||
)
|
||||
sms_senders = service_api_client.get_sms_senders(service_id)
|
||||
sms_sender_count = len(sms_senders)
|
||||
default_sms_sender = next(
|
||||
(Field(x['sms_sender'], html='escape') for x in sms_senders if x['is_default']), "None"
|
||||
)
|
||||
return render_template(
|
||||
'views/service-settings.html',
|
||||
organisation=organisation,
|
||||
@@ -94,7 +100,9 @@ def service_settings(service_id):
|
||||
default_reply_to_email_address=default_reply_to_email_address,
|
||||
reply_to_email_address_count=reply_to_email_address_count,
|
||||
default_letter_contact_block=default_letter_contact_block,
|
||||
letter_contact_details_count=letter_contact_details_count
|
||||
letter_contact_details_count=letter_contact_details_count,
|
||||
default_sms_sender=default_sms_sender,
|
||||
sms_sender_count=sms_sender_count
|
||||
)
|
||||
|
||||
|
||||
@@ -438,22 +446,34 @@ def service_set_sms_sender(service_id):
|
||||
form=form)
|
||||
|
||||
|
||||
@main.route("/services/<service_id>/service-settings/set-inbound-number", methods=['GET'])
|
||||
@main.route("/services/<service_id>/service-settings/set-inbound-number", methods=['GET', 'POST'])
|
||||
@login_required
|
||||
@user_has_permissions('manage_settings', admin_override=True)
|
||||
def service_set_inbound_number(service_id):
|
||||
switch_service_permissions(current_service['id'], 'inbound_sms')
|
||||
set_inbound_sms = request.args.get('set_inbound_sms', False)
|
||||
try:
|
||||
if set_inbound_sms == 'True':
|
||||
inbound_number_client.activate_inbound_sms_service(service_id)
|
||||
return redirect(url_for('.service_settings', service_id=service_id))
|
||||
else:
|
||||
inbound_number_client.deactivate_inbound_sms_permission(service_id=service_id)
|
||||
return redirect(url_for('.service_set_sms_sender', service_id=service_id))
|
||||
except HTTPError as e:
|
||||
available_inbound_numbers = inbound_number_client.get_available_inbound_sms_numbers()
|
||||
service_has_inbound_number = inbound_number_client.get_inbound_sms_number_for_service(service_id)['data'] != {}
|
||||
inbound_numbers_value_and_label = [
|
||||
(number['id'], number['number']) for number in available_inbound_numbers['data']
|
||||
]
|
||||
no_available_numbers = available_inbound_numbers['data'] == []
|
||||
form = ServiceInboundNumberForm(
|
||||
inbound_number_choices=inbound_numbers_value_and_label
|
||||
)
|
||||
if form.validate_on_submit():
|
||||
service_api_client.add_sms_sender(
|
||||
current_service['id'],
|
||||
sms_sender=form.inbound_number.data,
|
||||
is_default=True,
|
||||
inbound_number_id=form.inbound_number.data
|
||||
)
|
||||
switch_service_permissions(current_service['id'], 'inbound_sms')
|
||||
raise e
|
||||
return redirect(url_for('.service_settings', service_id=service_id))
|
||||
return render_template(
|
||||
'views/service-settings/set-inbound-number.html',
|
||||
form=form,
|
||||
no_available_numbers=no_available_numbers,
|
||||
service_has_inbound_number=service_has_inbound_number
|
||||
)
|
||||
|
||||
|
||||
@main.route("/services/<service_id>/service-settings/set-sms", methods=['GET'])
|
||||
@@ -559,6 +579,76 @@ def service_edit_letter_contact(service_id, letter_contact_id):
|
||||
letter_contact_id=letter_contact_block['id'])
|
||||
|
||||
|
||||
@main.route("/services/<service_id>/service-settings/sms-sender", methods=['GET'])
|
||||
@login_required
|
||||
@user_has_permissions('manage_settings', admin_override=True)
|
||||
def service_sms_senders(service_id):
|
||||
|
||||
def attach_hint(sender):
|
||||
hints = []
|
||||
if sender['is_default']:
|
||||
hints += ["default"]
|
||||
if sender['inbound_number_id']:
|
||||
hints += ["recieves replies"]
|
||||
if hints:
|
||||
sender['hint'] = "(" + " and ".join(hints) + ")"
|
||||
|
||||
sms_senders = service_api_client.get_sms_senders(service_id)
|
||||
|
||||
for sender in sms_senders:
|
||||
attach_hint(sender)
|
||||
|
||||
return render_template(
|
||||
'views/service-settings/sms-senders.html',
|
||||
sms_senders=sms_senders
|
||||
)
|
||||
|
||||
|
||||
@main.route("/services/<service_id>/service-settings/sms-sender/add", methods=['GET', 'POST'])
|
||||
@login_required
|
||||
@user_has_permissions('manage_settings', admin_override=True)
|
||||
def service_add_sms_sender(service_id):
|
||||
form = ServiceSmsSender()
|
||||
sms_sender_count = len(service_api_client.get_sms_senders(service_id))
|
||||
first_sms_sender = sms_sender_count == 0
|
||||
if form.validate_on_submit():
|
||||
service_api_client.add_sms_sender(
|
||||
current_service['id'],
|
||||
sms_sender=form.sms_sender.data.replace('\r', '') or None,
|
||||
is_default=first_sms_sender if first_sms_sender else form.is_default.data
|
||||
)
|
||||
return redirect(url_for('.service_sms_senders', service_id=service_id))
|
||||
return render_template(
|
||||
'views/service-settings/sms-sender/add.html',
|
||||
form=form,
|
||||
first_sms_sender=first_sms_sender)
|
||||
|
||||
|
||||
@main.route("/services/<service_id>/service-settings/sms-sender/<sms_sender_id>/edit", methods=['GET', 'POST'])
|
||||
@login_required
|
||||
@user_has_permissions('manage_settings', admin_override=True)
|
||||
def service_edit_sms_sender(service_id, sms_sender_id):
|
||||
sms_sender = service_api_client.get_sms_sender(service_id, sms_sender_id)
|
||||
form = ServiceSmsSender()
|
||||
form.sms_sender.data = sms_sender['sms_sender']
|
||||
is_inbound_number = True if sms_sender['inbound_number_id'] else False
|
||||
if request.method == 'GET':
|
||||
form.is_default.data = sms_sender['is_default']
|
||||
if form.validate_on_submit():
|
||||
service_api_client.update_sms_sender(
|
||||
current_service['id'],
|
||||
sms_sender_id=sms_sender_id,
|
||||
sms_sender=form.sms_sender.data.replace('\r', ''),
|
||||
is_default=True if sms_sender['is_default'] else form.is_default.data
|
||||
)
|
||||
return redirect(url_for('.service_sms_senders', service_id=service_id))
|
||||
return render_template(
|
||||
'views/service-settings/sms-sender/edit.html',
|
||||
form=form,
|
||||
sms_sender_id=sms_sender['id'],
|
||||
is_inbound_number=is_inbound_number)
|
||||
|
||||
|
||||
@main.route("/services/<service_id>/service-settings/set-letter-contact-block", methods=['GET', 'POST'])
|
||||
@login_required
|
||||
@user_has_permissions('manage_settings', admin_override=True)
|
||||
|
||||
@@ -11,6 +11,9 @@ class InboundNumberClient(NotifyAdminAPIClient):
|
||||
self.service_id = app.config['ADMIN_CLIENT_USER_NAME']
|
||||
self.api_key = app.config['ADMIN_CLIENT_SECRET']
|
||||
|
||||
def get_available_inbound_sms_numbers(self):
|
||||
return self.get(url='/inbound-number/available')
|
||||
|
||||
def get_all_inbound_sms_number_service(self):
|
||||
return self.get('/inbound-number')
|
||||
|
||||
@@ -19,6 +22,3 @@ class InboundNumberClient(NotifyAdminAPIClient):
|
||||
|
||||
def activate_inbound_sms_service(self, service_id):
|
||||
return self.post(url='/inbound-number/service/{}'.format(service_id), data={})
|
||||
|
||||
def deactivate_inbound_sms_permission(self, service_id):
|
||||
return self.post(url='/inbound-number/service/{}/off'.format(service_id), data={})
|
||||
|
||||
@@ -331,19 +331,10 @@ class ServiceAPIClient(NotifyAdminAPIClient):
|
||||
)
|
||||
|
||||
def get_letter_contacts(self, service_id):
|
||||
return self.get(
|
||||
"/service/{}/letter-contact".format(
|
||||
service_id
|
||||
)
|
||||
)
|
||||
return self.get("/service/{}/letter-contact".format(service_id))
|
||||
|
||||
def get_letter_contact(self, service_id, letter_contact_id):
|
||||
return self.get(
|
||||
"/service/{}/letter-contact/{}".format(
|
||||
service_id,
|
||||
letter_contact_id
|
||||
)
|
||||
)
|
||||
return self.get("/service/{}/letter-contact/{}".format(service_id, letter_contact_id))
|
||||
|
||||
def add_letter_contact(self, service_id, contact_block, is_default=False):
|
||||
return self.post(
|
||||
@@ -369,6 +360,34 @@ class ServiceAPIClient(NotifyAdminAPIClient):
|
||||
def get_aggregate_platform_stats(self, params_dict=None):
|
||||
return self.get("/service/platform-stats", params=params_dict)
|
||||
|
||||
def get_sms_senders(self, service_id):
|
||||
return self.get(
|
||||
"/service/{}/sms-sender".format(service_id)
|
||||
)
|
||||
|
||||
def get_sms_sender(self, service_id, sms_sender_id):
|
||||
return self.get(
|
||||
"/service/{}/sms-sender/{}".format(service_id, sms_sender_id)
|
||||
)
|
||||
|
||||
def add_sms_sender(self, service_id, sms_sender, is_default=False, inbound_number_id=None):
|
||||
data = {
|
||||
"sms_sender": sms_sender,
|
||||
"is_default": is_default
|
||||
}
|
||||
if inbound_number_id:
|
||||
data["inbound_number_id"] = inbound_number_id
|
||||
return self.post("/service/{}/sms-sender".format(service_id), data=data)
|
||||
|
||||
def update_sms_sender(self, service_id, sms_sender_id, sms_sender, is_default=False):
|
||||
return self.post(
|
||||
"/service/{}/sms-sender/{}".format(service_id, sms_sender_id),
|
||||
data={
|
||||
"sms_sender": sms_sender,
|
||||
"is_default": is_default
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
class ServicesBrowsableItem(BrowsableItem):
|
||||
@property
|
||||
|
||||
@@ -80,19 +80,16 @@
|
||||
{% if 'sms' in current_service.permissions %}
|
||||
|
||||
{% call row() %}
|
||||
|
||||
{{ text_field('Text message sender') }}
|
||||
{% if can_receive_inbound %}
|
||||
{{ text_field(inbound_number) }}
|
||||
{% else %}
|
||||
{{ text_field(current_service.sms_sender) }}
|
||||
{% endif %}
|
||||
{% if (current_user.has_permissions([], admin_override=True) or not can_receive_inbound) and not can_receive_inbound %}
|
||||
{{ edit_field('Change', url_for('.service_set_sms_sender', service_id=current_service.id, set_inbound_sms=False)) }}
|
||||
{% else %}
|
||||
{{ text_field('') }}
|
||||
{% endif %}
|
||||
|
||||
{% call field(status='default' if default_sms_sender == "None" else '') %}
|
||||
{{ default_sms_sender | string | nl2br | safe if default_sms_sender else 'None'}}
|
||||
{% if sms_sender_count > 1 %}
|
||||
<div class="hint">
|
||||
{{ '…and %d more' | format(sms_sender_count - 1) }}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endcall %}
|
||||
{{ edit_field('Manage' if sms_sender_count else 'Change', url_for('.service_sms_senders', service_id=current_service.id)) }}
|
||||
{% endcall %}
|
||||
|
||||
{% call row() %}
|
||||
@@ -250,11 +247,7 @@
|
||||
</li>
|
||||
{% if 'sms' in current_service.permissions %}
|
||||
<li class="bottom-gutter">
|
||||
{% if can_receive_inbound %}
|
||||
<a href="{{ url_for('.service_set_inbound_number', service_id=current_service.id, set_inbound_sms=False) }}" class="button">
|
||||
Stop inbound sms
|
||||
</a>
|
||||
{% else %}
|
||||
{% if not can_receive_inbound %}
|
||||
<a href="{{ url_for('.service_set_inbound_number', service_id=current_service.id, set_inbound_sms=True) }}" class="button">
|
||||
Allow inbound sms
|
||||
</a>
|
||||
|
||||
35
app/templates/views/service-settings/set-inbound-number.html
Normal file
35
app/templates/views/service-settings/set-inbound-number.html
Normal file
@@ -0,0 +1,35 @@
|
||||
{% extends "withnav_template.html" %}
|
||||
{% from "components/textbox.html" import textbox %}
|
||||
{% from "components/page-footer.html" import page_footer %}
|
||||
{% from "components/radios.html" import radios%}
|
||||
|
||||
{% block service_page_title %}
|
||||
Set Inbound Number
|
||||
{% endblock %}
|
||||
|
||||
{% block maincolumn_content %}
|
||||
<h1 class="heading-large">Set Inbound Number</h1>
|
||||
{% if service_has_inbound_number %}
|
||||
<p> This service already has an inbound number </p>
|
||||
{{ page_footer(
|
||||
back_link=url_for('.service_settings', service_id=current_service.id),
|
||||
back_link_text='Back to settings'
|
||||
) }}
|
||||
{% elif no_available_numbers %}
|
||||
<p> No available inbound numbers </p>
|
||||
{{ page_footer(
|
||||
back_link=url_for('.service_settings', service_id=current_service.id),
|
||||
back_link_text='Back to settings'
|
||||
) }}
|
||||
{% else %}
|
||||
<form method="post">
|
||||
{{ radios(form.inbound_number) }}
|
||||
{{ page_footer(
|
||||
'Save',
|
||||
back_link=url_for('.service_settings', service_id=current_service.id),
|
||||
back_link_text='Back'
|
||||
) }}
|
||||
</form>
|
||||
{% endif %}
|
||||
|
||||
{% endblock %}
|
||||
31
app/templates/views/service-settings/sms-sender/add.html
Normal file
31
app/templates/views/service-settings/sms-sender/add.html
Normal file
@@ -0,0 +1,31 @@
|
||||
{% extends "withnav_template.html" %}
|
||||
{% from "components/textbox.html" import textbox %}
|
||||
{% from "components/checkbox.html" import checkbox %}
|
||||
{% from "components/page-footer.html" import page_footer %}
|
||||
|
||||
{% block service_page_title %}
|
||||
Add text message sender
|
||||
{% endblock %}
|
||||
|
||||
{% block maincolumn_content %}
|
||||
|
||||
<h1 class="heading-large">Add text message sender</h1>
|
||||
<form method="post">
|
||||
{{ textbox(
|
||||
form.sms_sender,
|
||||
width='1-4',
|
||||
hint='Up to 11 characters, letters, numbers and spaces only'
|
||||
) }}
|
||||
{% if not first_sms_sender %}
|
||||
<div class="form-group">
|
||||
{{ checkbox(form.is_default) }}
|
||||
</div>
|
||||
{% endif %}
|
||||
{{ page_footer(
|
||||
'Save',
|
||||
back_link=url_for('.service_sms_senders', service_id=current_service.id),
|
||||
back_link_text='Back'
|
||||
) }}
|
||||
</form>
|
||||
|
||||
{% endblock %}
|
||||
44
app/templates/views/service-settings/sms-sender/edit.html
Normal file
44
app/templates/views/service-settings/sms-sender/edit.html
Normal file
@@ -0,0 +1,44 @@
|
||||
{% extends "withnav_template.html" %}
|
||||
{% from "components/textbox.html" import textbox %}
|
||||
{% from "components/checkbox.html" import checkbox %}
|
||||
{% from "components/page-footer.html" import page_footer %}
|
||||
|
||||
{% block service_page_title %}
|
||||
Edit text message sender
|
||||
{% endblock %}
|
||||
|
||||
{% block maincolumn_content %}
|
||||
|
||||
<h1 class="heading-large">
|
||||
Edit text message sender
|
||||
</h1>
|
||||
<form method="post">
|
||||
{% if is_inbound_number %}
|
||||
<p>
|
||||
<span class="bottom-gutter-1-3"> {{ form.sms_sender.data }} </span>
|
||||
<span class="hint"> This phone number receives replies and can’t be changed </span>
|
||||
</p>
|
||||
{% else %}
|
||||
{{ textbox(
|
||||
form.sms_sender,
|
||||
width='1-4',
|
||||
hint='Up to 11 characters, letters, numbers and spaces only'
|
||||
) }}
|
||||
{% endif %}
|
||||
{% if form.is_default.data %}
|
||||
<p class="form-group">
|
||||
This is currently your text message sender for {{ current_service.name }}
|
||||
</p>
|
||||
{% else %}
|
||||
<div class="form-group">
|
||||
{{ checkbox(form.is_default) }}
|
||||
</div>
|
||||
{% endif %}
|
||||
{{ page_footer(
|
||||
'Save',
|
||||
back_link=None if request.args.get('from_template') else url_for('.service_sms_senders', service_id=current_service.id),
|
||||
back_link_text='Back'
|
||||
) }}
|
||||
</form>
|
||||
|
||||
{% endblock %}
|
||||
49
app/templates/views/service-settings/sms-senders.html
Normal file
49
app/templates/views/service-settings/sms-senders.html
Normal file
@@ -0,0 +1,49 @@
|
||||
{% extends "withnav_template.html" %}
|
||||
{% from "components/api-key.html" import api_key %}
|
||||
{% from "components/page-footer.html" import page_footer %}
|
||||
{% from "components/table.html" import row_group, row, text_field, edit_field, field, boolean_field, list_table %}
|
||||
|
||||
{% block service_page_title %}
|
||||
Text message senders
|
||||
{% endblock %}
|
||||
|
||||
{% block maincolumn_content %}
|
||||
<div class="grid-row bottom-gutter">
|
||||
<div class="column-two-thirds">
|
||||
<h1 class="heading-large">
|
||||
Text message senders
|
||||
</h1>
|
||||
</div>
|
||||
<div class="column-one-third">
|
||||
<a href="{{ url_for('.service_add_sms_sender', service_id=current_service.id) }}" class="button align-with-heading">Add text message sender</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="user-list">
|
||||
{% if not sms_senders %}
|
||||
<div class="user-list-item">
|
||||
<span class="hint">You haven’t added any sms senders yet</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% for item in sms_senders %}
|
||||
<div class="user-list-item">
|
||||
<h3>
|
||||
<span class="heading-small">{{ item.sms_sender }}</span>
|
||||
{% if item.hint %}
|
||||
 
|
||||
<span class="hint">
|
||||
{{ item.hint }}
|
||||
</span>
|
||||
{% endif %}
|
||||
</h3>
|
||||
<ul class="tick-cross-list">
|
||||
<li class="tick-cross-list-edit-link">
|
||||
<a href="{{ url_for('.service_edit_sms_sender', service_id=current_service.id, sms_sender_id = item.id) }}">Change</a>
|
||||
</li>
|
||||
</ul>
|
||||
{% if sms_senders|length > 1 %}
|
||||
{{ api_key(item.id, thing="ID") }}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user