mirror of
https://github.com/GSA/notifications-admin.git
synced 2026-08-18 21:49:37 -04:00
Merge branch 'master' of github.com:alphagov/notifications-admin
This commit is contained in:
@@ -6,10 +6,12 @@ from flask import (Flask, session, Markup, escape, render_template, make_respons
|
||||
from flask._compat import string_types
|
||||
from flask_login import LoginManager
|
||||
from flask_wtf import CsrfProtect
|
||||
from werkzeug.exceptions import abort
|
||||
from notifications_python_client import HTTPError
|
||||
from pygments import highlight
|
||||
from pygments.lexers import JavascriptLexer
|
||||
from pygments.formatters import HtmlFormatter
|
||||
from werkzeug.exceptions import abort
|
||||
|
||||
from app.notify_client.api_client import NotificationsAdminAPIClient
|
||||
from app.notify_client.api_key_api_client import ApiKeyApiClient
|
||||
from app.notify_client.user_api_client import UserApiClient
|
||||
@@ -176,10 +178,29 @@ def useful_headers_after_request(response):
|
||||
|
||||
|
||||
def register_errorhandlers(application):
|
||||
def render_error(error):
|
||||
# If a HTTPException, pull the `code` attribute; default to 500
|
||||
error_code = getattr(error, 'code', 500)
|
||||
def _error_response(error_code):
|
||||
resp = make_response(render_template("error/{0}.html".format(error_code)), error_code)
|
||||
return useful_headers_after_request(resp)
|
||||
for errcode in [401, 404, 403, 500]:
|
||||
application.errorhandler(errcode)(render_error)
|
||||
|
||||
@application.errorhandler(HTTPError)
|
||||
def render_http_error(error):
|
||||
error_code = error.status_code
|
||||
if error_code not in [401, 404, 403, 500]:
|
||||
error_code = 500
|
||||
return _error_response(error_code)
|
||||
|
||||
@application.errorhandler(404)
|
||||
def handle_not_found(error):
|
||||
return _error_response(404)
|
||||
|
||||
@application.errorhandler(403)
|
||||
def handle_not_authorized(error):
|
||||
return _error_response(403)
|
||||
|
||||
@application.errorhandler(401)
|
||||
def handle_no_permissions(error):
|
||||
return _error_response(401)
|
||||
|
||||
@application.errorhandler(Exception)
|
||||
def handle_bad_request(error):
|
||||
return _error_response(500)
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
};
|
||||
|
||||
this.update = () => this.$backgroundMaskForeground.html(
|
||||
this.$textbox.val().replace(
|
||||
$('<div/>').text(this.$textbox.val()).html().replace(
|
||||
tagPattern, match => `<span class='tag'>${match}</span>`
|
||||
)
|
||||
);
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
@include grid-column(3/4);
|
||||
}
|
||||
|
||||
|
||||
.column-one-eighth {
|
||||
@include grid-column(1/8);
|
||||
}
|
||||
@@ -19,3 +18,11 @@
|
||||
.bottom-gutter-2-3 {
|
||||
margin-bottom: $gutter * 2/3;
|
||||
}
|
||||
|
||||
.align-with-heading {
|
||||
display: block;
|
||||
text-align: center;
|
||||
margin-top: 45px;
|
||||
padding-left: 2px;
|
||||
padding-right: 2px;
|
||||
}
|
||||
|
||||
@@ -9,8 +9,14 @@
|
||||
padding: 10px 0;
|
||||
|
||||
&-label {
|
||||
|
||||
padding-top: 19px;
|
||||
float: left;
|
||||
|
||||
&.error {
|
||||
padding-top: 5px;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
&-fields {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
&-placeholder-hint {
|
||||
display: block;
|
||||
padding-top: 20px;
|
||||
color: $secondary-text-colour;
|
||||
//color: $secondary-text-colour;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,14 +1,6 @@
|
||||
from flask import url_for, abort, current_app
|
||||
from flask import url_for, current_app
|
||||
from app import notifications_api_client
|
||||
from app.utils import BrowsableItem
|
||||
from notifications_python_client.errors import HTTPError
|
||||
|
||||
|
||||
def insert_new_service(service_name, user_id):
|
||||
resp = notifications_api_client.create_service(
|
||||
service_name, False, current_app.config['DEFAULT_SERVICE_LIMIT'], True, user_id)
|
||||
|
||||
return resp['data']['id']
|
||||
|
||||
|
||||
def update_service(service):
|
||||
@@ -26,15 +18,7 @@ def get_service_by_id(id_):
|
||||
|
||||
|
||||
def get_service_by_id_or_404(id_):
|
||||
try:
|
||||
return notifications_api_client.get_service(id_)['data']
|
||||
except KeyError:
|
||||
abort(404)
|
||||
except HTTPError as e:
|
||||
if e.status_code == 404:
|
||||
abort(404)
|
||||
else:
|
||||
raise e
|
||||
return notifications_api_client.get_service(id_)['data']
|
||||
|
||||
|
||||
def get_services(user_id=None):
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
from flask import url_for, abort
|
||||
from flask import url_for
|
||||
from app import notifications_api_client
|
||||
from app.utils import BrowsableItem
|
||||
from notifications_python_client.errors import HTTPError
|
||||
|
||||
|
||||
def insert_service_template(name, type_, content, service_id, subject=None):
|
||||
@@ -19,13 +18,7 @@ def get_service_templates(service_id):
|
||||
|
||||
|
||||
def get_service_template_or_404(service_id, template_id):
|
||||
try:
|
||||
return notifications_api_client.get_service_template(service_id, template_id)
|
||||
except HTTPError as e:
|
||||
if e.status_code == 404:
|
||||
abort(404)
|
||||
else:
|
||||
raise e
|
||||
return notifications_api_client.get_service_template(service_id, template_id)
|
||||
|
||||
|
||||
def delete_service_template(service_id, template_id):
|
||||
|
||||
@@ -1,11 +1,6 @@
|
||||
from datetime import datetime
|
||||
from notifications_python_client import HTTPError
|
||||
|
||||
from sqlalchemy.orm import load_only
|
||||
|
||||
from app import login_manager
|
||||
from app.main.encryption import hashpw
|
||||
|
||||
from app import user_api_client
|
||||
|
||||
#
|
||||
|
||||
@@ -150,6 +150,23 @@ class TwoFactorForm(Form):
|
||||
raise ValidationError(reason)
|
||||
|
||||
|
||||
class VerifySmsForm(Form):
|
||||
def __init__(self, validate_code_func, *args, **kwargs):
|
||||
'''
|
||||
Keyword arguments:
|
||||
validate_code_func -- Validates the code with the API.
|
||||
'''
|
||||
self.validate_code_func = validate_code_func
|
||||
super(VerifySmsForm, self).__init__(*args, **kwargs)
|
||||
|
||||
sms_code = sms_code()
|
||||
|
||||
def validate_sms_code(self, field):
|
||||
is_valid, reason = self.validate_code_func(field.data, 'sms')
|
||||
if not is_valid:
|
||||
raise ValidationError(reason)
|
||||
|
||||
|
||||
class VerifyForm(Form):
|
||||
def __init__(self, validate_code_func, *args, **kwargs):
|
||||
'''
|
||||
@@ -168,10 +185,12 @@ class VerifyForm(Form):
|
||||
raise ValidationError(reason)
|
||||
|
||||
def validate_email_code(self, field):
|
||||
self._validate_code(field.data, 'email')
|
||||
if self.sms_code.data:
|
||||
self._validate_code(field.data, 'email')
|
||||
|
||||
def validate_sms_code(self, field):
|
||||
self._validate_code(field.data, 'sms')
|
||||
if self.email_code.data:
|
||||
self._validate_code(field.data, 'sms')
|
||||
|
||||
|
||||
class EmailNotReceivedForm(Form):
|
||||
@@ -205,7 +224,24 @@ class AddServiceForm(Form):
|
||||
|
||||
|
||||
class ServiceNameForm(Form):
|
||||
name = StringField(u'New name')
|
||||
def __init__(self, names_func, *args, **kwargs):
|
||||
"""
|
||||
Keyword arguments:
|
||||
names_func -- Returns a list of unique service_names already registered
|
||||
on the system.
|
||||
"""
|
||||
self._names_func = names_func
|
||||
super(ServiceNameForm, self).__init__(*args, **kwargs)
|
||||
|
||||
name = StringField(
|
||||
u'New name',
|
||||
validators=[
|
||||
DataRequired(message='Service name can’t be empty')
|
||||
])
|
||||
|
||||
def validate_name(self, a):
|
||||
if a.data in self._names_func():
|
||||
raise ValidationError('This service name is already in use')
|
||||
|
||||
|
||||
class ConfirmPasswordForm(Form):
|
||||
|
||||
@@ -2,8 +2,8 @@ from flask import (
|
||||
render_template,
|
||||
redirect,
|
||||
session,
|
||||
url_for
|
||||
)
|
||||
url_for,
|
||||
current_app)
|
||||
|
||||
from flask_login import login_required
|
||||
|
||||
@@ -14,8 +14,8 @@ from app.notify_client.models import InvitedUser
|
||||
|
||||
from app import (
|
||||
invite_api_client,
|
||||
user_api_client
|
||||
)
|
||||
user_api_client,
|
||||
notifications_api_client)
|
||||
|
||||
|
||||
@main.route("/add-service", methods=['GET', 'POST'])
|
||||
@@ -36,8 +36,9 @@ def add_service():
|
||||
heading = 'Which service do you want to set up notifications for?'
|
||||
if form.validate_on_submit():
|
||||
session['service_name'] = form.name.data
|
||||
user = users_dao.get_user_by_id(session['user_id'])
|
||||
service_id = services_dao.insert_new_service(session['service_name'], user.id)
|
||||
service_id = notifications_api_client.create_service(
|
||||
session['service_name'], False, current_app.config['DEFAULT_SERVICE_LIMIT'], True, session['user_id'])
|
||||
|
||||
return redirect(url_for('main.service_dashboard', service_id=service_id))
|
||||
else:
|
||||
return render_template(
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
from flask import (
|
||||
abort,
|
||||
render_template,
|
||||
session,
|
||||
flash
|
||||
@@ -9,36 +8,25 @@ from flask_login import login_required
|
||||
from app.main import main
|
||||
from app.main.dao.services_dao import get_service_by_id
|
||||
from app.main.dao import templates_dao
|
||||
from notifications_python_client.errors import HTTPError
|
||||
from app import job_api_client
|
||||
|
||||
|
||||
@main.route("/services/<service_id>/dashboard")
|
||||
@login_required
|
||||
def service_dashboard(service_id):
|
||||
try:
|
||||
templates = templates_dao.get_service_templates(service_id)['data']
|
||||
jobs = job_api_client.get_job(service_id)['data']
|
||||
except HTTPError as e:
|
||||
if e.status_code == 404:
|
||||
abort(404)
|
||||
else:
|
||||
raise e
|
||||
try:
|
||||
service = get_service_by_id(service_id)
|
||||
session['service_name'] = service['data']['name']
|
||||
session['service_id'] = service['data']['id']
|
||||
templates = templates_dao.get_service_templates(service_id)['data']
|
||||
jobs = job_api_client.get_job(service_id)['data']
|
||||
|
||||
service = get_service_by_id(service_id)
|
||||
session['service_name'] = service['data']['name']
|
||||
session['service_id'] = service['data']['id']
|
||||
|
||||
if session.get('invited_user'):
|
||||
session.pop('invited_user', None)
|
||||
service_name = service['data']['name']
|
||||
message = 'You have successfully accepted your invitation and been added to {}'.format(service_name)
|
||||
flash(message, 'default_with_tick')
|
||||
|
||||
if session.get('invited_user'):
|
||||
session.pop('invited_user', None)
|
||||
service_name = service['data']['name']
|
||||
message = 'You have sucessfully accepted your invitation and been added to {}'.format(service_name)
|
||||
flash(message, 'default_with_tick')
|
||||
except HTTPError as e:
|
||||
if e.status_code == 404:
|
||||
abort(404)
|
||||
else:
|
||||
raise e
|
||||
return render_template(
|
||||
'views/service_dashboard.html',
|
||||
jobs=jobs[:5],
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
from flask import (
|
||||
render_template,
|
||||
)
|
||||
from notifications_python_client.errors import HTTPError
|
||||
|
||||
from app.main import main
|
||||
from app.main.forms import ForgotPasswordForm
|
||||
@@ -12,11 +11,8 @@ from app import user_api_client
|
||||
def forgot_password():
|
||||
form = ForgotPasswordForm()
|
||||
if form.validate_on_submit():
|
||||
try:
|
||||
user_api_client.send_reset_password_url(form.email_address.data)
|
||||
except HTTPError as e:
|
||||
if e.status_code != 404:
|
||||
raise e
|
||||
user_api_client.send_reset_password_url(form.email_address.data)
|
||||
|
||||
return render_template('views/password-reset-sent.html')
|
||||
|
||||
return render_template('views/forgot-password.html', form=form)
|
||||
|
||||
@@ -2,11 +2,9 @@ from flask import (
|
||||
redirect,
|
||||
url_for,
|
||||
session,
|
||||
abort,
|
||||
render_template
|
||||
)
|
||||
flash,
|
||||
render_template)
|
||||
|
||||
from notifications_python_client.errors import HTTPError
|
||||
|
||||
from app.main import main
|
||||
from app.main.dao.services_dao import get_service_by_id_or_404
|
||||
@@ -18,32 +16,29 @@ from app import (
|
||||
|
||||
@main.route("/invitation/<token>")
|
||||
def accept_invite(token):
|
||||
invited_user = invite_api_client.check_token(token)
|
||||
|
||||
try:
|
||||
if invited_user.status == 'cancelled':
|
||||
from_user = user_api_client.get_user(invited_user.from_user)
|
||||
service = get_service_by_id_or_404(invited_user.service)
|
||||
return render_template('views/cancelled-invitation.html',
|
||||
from_user=from_user.name,
|
||||
service_name=service['name'])
|
||||
|
||||
invited_user = invite_api_client.check_token(token)
|
||||
if invited_user.status == 'cancelled':
|
||||
from_user = user_api_client.get_user(invited_user.from_user)
|
||||
service = get_service_by_id_or_404(invited_user.service)
|
||||
return render_template('views/cancelled-invitation.html',
|
||||
from_user=from_user.name,
|
||||
service_name=service['name'])
|
||||
if invited_user.status == 'accepted':
|
||||
session.pop('invited_user', None)
|
||||
flash('You have already accepted this invitation', 'default')
|
||||
return redirect(url_for('main.service_dashboard', service_id=invited_user.service))
|
||||
|
||||
existing_user = user_api_client.get_user_by_email(invited_user.email_address)
|
||||
session['invited_user'] = invited_user.serialize()
|
||||
existing_user = user_api_client.get_user_by_email(invited_user.email_address)
|
||||
session['invited_user'] = invited_user.serialize()
|
||||
|
||||
if existing_user:
|
||||
if existing_user:
|
||||
|
||||
user_api_client.add_user_to_service(invited_user.service,
|
||||
existing_user.id,
|
||||
invited_user.permissions)
|
||||
invite_api_client.accept_invite(invited_user.service, invited_user.id)
|
||||
return redirect(url_for('main.service_dashboard', service_id=invited_user.service))
|
||||
else:
|
||||
return redirect(url_for('main.register_from_invite'))
|
||||
|
||||
except HTTPError as e:
|
||||
if e.status_code == 404:
|
||||
abort(404)
|
||||
else:
|
||||
raise e
|
||||
user_api_client.add_user_to_service(invited_user.service,
|
||||
existing_user.id,
|
||||
invited_user.permissions)
|
||||
invite_api_client.accept_invite(invited_user.service, invited_user.id)
|
||||
return redirect(url_for('main.service_dashboard', service_id=invited_user.service))
|
||||
else:
|
||||
return redirect(url_for('main.register_from_invite'))
|
||||
|
||||
@@ -8,7 +8,6 @@ from flask import (
|
||||
jsonify
|
||||
)
|
||||
from flask_login import login_required
|
||||
from notifications_python_client.errors import HTTPError
|
||||
from utils.template import Template
|
||||
|
||||
from app import job_api_client, notification_api_client
|
||||
@@ -20,89 +19,71 @@ from app.main.dao import services_dao
|
||||
@main.route("/services/<service_id>/jobs")
|
||||
@login_required
|
||||
def view_jobs(service_id):
|
||||
try:
|
||||
jobs = job_api_client.get_job(service_id)['data']
|
||||
return render_template(
|
||||
'views/jobs/jobs.html',
|
||||
jobs=jobs,
|
||||
service_id=service_id
|
||||
)
|
||||
except HTTPError as e:
|
||||
if e.status_code == 404:
|
||||
abort(404)
|
||||
else:
|
||||
raise e
|
||||
jobs = job_api_client.get_job(service_id)['data']
|
||||
return render_template(
|
||||
'views/jobs/jobs.html',
|
||||
jobs=jobs,
|
||||
service_id=service_id
|
||||
)
|
||||
|
||||
|
||||
@main.route("/services/<service_id>/jobs/<job_id>")
|
||||
@login_required
|
||||
def view_job(service_id, job_id):
|
||||
service = services_dao.get_service_by_id_or_404(service_id)
|
||||
try:
|
||||
job = job_api_client.get_job(service_id, job_id)['data']
|
||||
template = templates_dao.get_service_template_or_404(service_id, job['template'])['data']
|
||||
notifications = notification_api_client.get_notifications_for_service(service_id, job_id)
|
||||
finished = job['status'] == 'finished'
|
||||
return render_template(
|
||||
'views/jobs/job.html',
|
||||
notifications=notifications['notifications'],
|
||||
counts={
|
||||
'queued': 0 if finished else job['notification_count'],
|
||||
'sent': job['notification_count'] if finished else 0,
|
||||
'failed': 0,
|
||||
'cost': u'£0.00'
|
||||
},
|
||||
uploaded_at=job['created_at'],
|
||||
finished_at=job['updated_at'] if finished else None,
|
||||
uploaded_file_name=job['original_file_name'],
|
||||
template=Template(
|
||||
template,
|
||||
prefix=service['name'] if template['template_type'] == 'sms' else ''
|
||||
),
|
||||
service_id=service_id,
|
||||
service=service,
|
||||
job_id=job_id
|
||||
)
|
||||
except HTTPError as e:
|
||||
if e.status_code == 404:
|
||||
abort(404)
|
||||
else:
|
||||
raise e
|
||||
job = job_api_client.get_job(service_id, job_id)['data']
|
||||
template = templates_dao.get_service_template_or_404(service_id, job['template'])['data']
|
||||
notifications = notification_api_client.get_notifications_for_service(service_id, job_id)
|
||||
finished = job['status'] == 'finished'
|
||||
return render_template(
|
||||
'views/jobs/job.html',
|
||||
notifications=notifications['notifications'],
|
||||
counts={
|
||||
'queued': 0 if finished else job['notification_count'],
|
||||
'sent': job['notification_count'] if finished else 0,
|
||||
'failed': 0,
|
||||
'cost': u'£0.00'
|
||||
},
|
||||
uploaded_at=job['created_at'],
|
||||
finished_at=job['updated_at'] if finished else None,
|
||||
uploaded_file_name=job['original_file_name'],
|
||||
template=Template(
|
||||
template,
|
||||
prefix=service['name'] if template['template_type'] == 'sms' else ''
|
||||
),
|
||||
service_id=service_id,
|
||||
service=service,
|
||||
job_id=job_id
|
||||
)
|
||||
|
||||
|
||||
@main.route("/services/<service_id>/jobs/<job_id>.json")
|
||||
@login_required
|
||||
def view_job_updates(service_id, job_id):
|
||||
service = services_dao.get_service_by_id_or_404(service_id)
|
||||
try:
|
||||
job = job_api_client.get_job(service_id, job_id)['data']
|
||||
notifications = notification_api_client.get_notifications_for_service(service_id, job_id)
|
||||
finished = job['status'] == 'finished'
|
||||
return jsonify(**{
|
||||
'counts': render_template(
|
||||
'partials/jobs/count.html',
|
||||
counts={
|
||||
'queued': 0 if finished else job['notification_count'],
|
||||
'sent': job['notification_count'] if finished else 0,
|
||||
'failed': 0,
|
||||
'cost': u'£0.00'
|
||||
}
|
||||
),
|
||||
'notifications': render_template(
|
||||
'partials/jobs/notifications.html',
|
||||
notifications=notifications['notifications']
|
||||
),
|
||||
'status': render_template(
|
||||
'partials/jobs/status.html',
|
||||
uploaded_at=job['created_at'],
|
||||
finished_at=job['updated_at'] if finished else None
|
||||
),
|
||||
})
|
||||
except HTTPError as e:
|
||||
if e.status_code == 404:
|
||||
abort(404)
|
||||
else:
|
||||
raise e
|
||||
job = job_api_client.get_job(service_id, job_id)['data']
|
||||
notifications = notification_api_client.get_notifications_for_service(service_id, job_id)
|
||||
finished = job['status'] == 'finished'
|
||||
return jsonify(**{
|
||||
'counts': render_template(
|
||||
'partials/jobs/count.html',
|
||||
counts={
|
||||
'queued': 0 if finished else job['notification_count'],
|
||||
'sent': job['notification_count'] if finished else 0,
|
||||
'failed': 0,
|
||||
'cost': u'£0.00'
|
||||
}
|
||||
),
|
||||
'notifications': render_template(
|
||||
'partials/jobs/notifications.html',
|
||||
notifications=notifications['notifications']
|
||||
),
|
||||
'status': render_template(
|
||||
'partials/jobs/status.html',
|
||||
uploaded_at=job['created_at'],
|
||||
finished_at=job['updated_at'] if finished else None
|
||||
),
|
||||
})
|
||||
|
||||
|
||||
@main.route("/services/<service_id>/jobs/<job_id>/notification/<string:notification_id>")
|
||||
|
||||
@@ -11,9 +11,6 @@ from flask_login import (
|
||||
current_user
|
||||
)
|
||||
|
||||
from notifications_python_client.errors import HTTPError
|
||||
from app import user_api_client
|
||||
|
||||
from app.main import main
|
||||
from app.main.forms import (
|
||||
InviteUserForm,
|
||||
|
||||
@@ -11,8 +11,6 @@ from flask import (
|
||||
|
||||
from flask.ext.login import current_user
|
||||
|
||||
from notifications_python_client.errors import HTTPError
|
||||
|
||||
from app.main import main
|
||||
from app.main.dao import users_dao
|
||||
from app.main.forms import (
|
||||
@@ -65,17 +63,10 @@ def register_from_invite():
|
||||
|
||||
def _do_registration(form, service=None):
|
||||
if users_dao.is_email_unique(form.email_address.data):
|
||||
try:
|
||||
user = user_api_client.register_user(form.name.data,
|
||||
form.email_address.data,
|
||||
form.mobile_number.data,
|
||||
form.password.data)
|
||||
|
||||
except HTTPError as e:
|
||||
if e.status_code == 404:
|
||||
abort(404)
|
||||
else:
|
||||
raise e
|
||||
user = user_api_client.register_user(form.name.data,
|
||||
form.email_address.data,
|
||||
form.mobile_number.data,
|
||||
form.password.data)
|
||||
|
||||
# TODO possibly there should be some exception handling
|
||||
# for sending sms and email codes.
|
||||
|
||||
@@ -15,7 +15,6 @@ from flask import (
|
||||
)
|
||||
|
||||
from flask_login import login_required, current_user
|
||||
from notifications_python_client.errors import HTTPError
|
||||
from utils.template import Template
|
||||
from utils.recipients import RecipientCSV, first_column_heading
|
||||
|
||||
@@ -38,8 +37,8 @@ send_messages_page_headings = {
|
||||
|
||||
|
||||
manage_templates_page_headings = {
|
||||
'email': 'Manage templates',
|
||||
'sms': 'Manage templates'
|
||||
'email': 'Email templates',
|
||||
'sms': 'Text message templates'
|
||||
}
|
||||
|
||||
|
||||
@@ -80,13 +79,8 @@ def choose_template(service_id, template_type):
|
||||
|
||||
if template_type not in ['email', 'sms']:
|
||||
abort(404)
|
||||
try:
|
||||
jobs = job_api_client.get_job(service_id)['data']
|
||||
except HTTPError as e:
|
||||
if e.status_code == 404:
|
||||
abort(404)
|
||||
else:
|
||||
raise e
|
||||
jobs = job_api_client.get_job(service_id)['data']
|
||||
|
||||
return render_template(
|
||||
'views/choose-template.html',
|
||||
templates=[
|
||||
@@ -166,7 +160,7 @@ def get_example_csv(service_id, template_id):
|
||||
'email': current_user.email_address,
|
||||
'sms': current_user.mobile_number
|
||||
}[template.template_type]
|
||||
] + ["test {}".format(header) for header in template.placeholders])
|
||||
] + _get_fake_personalisation(template.placeholders))
|
||||
return output.getvalue(), 200, {'Content-Type': 'text/csv; charset=utf-8'}
|
||||
|
||||
|
||||
@@ -183,13 +177,11 @@ def send_message_to_self(service_id, template_id):
|
||||
)
|
||||
if template.template_type == 'sms':
|
||||
writer.writerow(
|
||||
[current_user.mobile_number] +
|
||||
["test {}".format(header) for header in template.placeholders]
|
||||
[current_user.mobile_number] + _get_fake_personalisation(template.placeholders)
|
||||
)
|
||||
if template.template_type == 'email':
|
||||
writer.writerow(
|
||||
[current_user.email_address] +
|
||||
["test {}".format(header) for header in template.placeholders]
|
||||
[current_user.email_address] + _get_fake_personalisation(template.placeholders)
|
||||
)
|
||||
|
||||
filedata = {
|
||||
@@ -230,7 +222,8 @@ def check_messages(service_id, upload_id):
|
||||
contents,
|
||||
template_type=template.template_type,
|
||||
placeholders=template.placeholders,
|
||||
max_initial_rows_shown=5
|
||||
max_initial_rows_shown=15,
|
||||
max_errors_shown=15
|
||||
)
|
||||
|
||||
with suppress(StopIteration):
|
||||
@@ -245,8 +238,13 @@ def check_messages(service_id, upload_id):
|
||||
template=template,
|
||||
page_heading=get_page_headings(template.template_type),
|
||||
errors=get_errors_for_csv(recipients, template.template_type),
|
||||
rows_have_errors=any(recipients.rows_with_errors),
|
||||
count_of_recipients=session['upload_data']['notification_count'],
|
||||
count_of_displayed_recipients=len(list(recipients.rows_annotated_and_truncated)),
|
||||
count_of_displayed_recipients=(
|
||||
len(list(recipients.initial_annotated_rows_with_errors))
|
||||
if any(recipients.rows_with_errors) else
|
||||
len(list(recipients.initial_annotated_rows))
|
||||
),
|
||||
original_file_name=session['upload_data'].get('original_file_name'),
|
||||
send_button_text=get_send_button_text(template.template_type, session['upload_data']['notification_count']),
|
||||
service_id=service_id,
|
||||
@@ -280,3 +278,9 @@ def start_job(service_id, upload_id):
|
||||
return redirect(
|
||||
url_for('main.view_job', service_id=service_id, job_id=upload_id)
|
||||
)
|
||||
|
||||
|
||||
def _get_fake_personalisation(placeholders):
|
||||
return [
|
||||
"{} 1".format(header) for header in placeholders
|
||||
]
|
||||
|
||||
@@ -12,13 +12,13 @@ from flask_login import (
|
||||
login_required,
|
||||
current_user
|
||||
)
|
||||
|
||||
from notifications_python_client.errors import HTTPError
|
||||
from notifications_python_client import HTTPError
|
||||
|
||||
from app.main.dao.services_dao import (
|
||||
get_service_by_id,
|
||||
delete_service,
|
||||
update_service
|
||||
update_service,
|
||||
find_all_service_names
|
||||
)
|
||||
|
||||
from app.main import main
|
||||
@@ -31,13 +31,8 @@ from app.main.forms import ConfirmPasswordForm, ServiceNameForm
|
||||
@login_required
|
||||
@user_has_permissions('manage_settings')
|
||||
def service_settings(service_id):
|
||||
try:
|
||||
service = get_service_by_id(service_id)['data']
|
||||
except HTTPError as e:
|
||||
if e.status_code == 404:
|
||||
abort(404)
|
||||
else:
|
||||
raise e
|
||||
service = get_service_by_id(service_id)['data']
|
||||
|
||||
return render_template(
|
||||
'views/service-settings.html',
|
||||
service=service,
|
||||
@@ -49,15 +44,9 @@ def service_settings(service_id):
|
||||
@login_required
|
||||
@user_has_permissions('manage_settings')
|
||||
def service_name_change(service_id):
|
||||
try:
|
||||
service = get_service_by_id(service_id)['data']
|
||||
except HTTPError as e:
|
||||
if e.status_code == 404:
|
||||
abort(404)
|
||||
else:
|
||||
raise e
|
||||
service = get_service_by_id(service_id)['data']
|
||||
|
||||
form = ServiceNameForm()
|
||||
form = ServiceNameForm(find_all_service_names)
|
||||
|
||||
if form.validate_on_submit():
|
||||
session['service_name_change'] = form.name.data
|
||||
@@ -74,13 +63,7 @@ def service_name_change(service_id):
|
||||
@login_required
|
||||
@user_has_permissions('manage_settings')
|
||||
def service_name_change_confirm(service_id):
|
||||
try:
|
||||
service = get_service_by_id(service_id)['data']
|
||||
except HTTPError as e:
|
||||
if e.status_code == 404:
|
||||
abort(404)
|
||||
else:
|
||||
raise e
|
||||
service = get_service_by_id(service_id)['data']
|
||||
|
||||
# Validate password for form
|
||||
def _check_password(pwd):
|
||||
@@ -89,10 +72,20 @@ def service_name_change_confirm(service_id):
|
||||
|
||||
if form.validate_on_submit():
|
||||
service['name'] = session['service_name_change']
|
||||
update_service(service)
|
||||
session['service_name'] = service['name']
|
||||
session.pop('service_name_change')
|
||||
return redirect(url_for('.service_settings', service_id=service_id))
|
||||
try:
|
||||
update_service(service)
|
||||
except HTTPError as e:
|
||||
error_msg = "Duplicate service name '{}'".format(session['service_name_change'])
|
||||
if e.status_code == 400 and error_msg in e.message['name']:
|
||||
# Redirect the user back to the change service name screen
|
||||
flash('This service name is already in use', 'error')
|
||||
return redirect(url_for('main.service_name_change', service_id=service_id))
|
||||
else:
|
||||
raise e
|
||||
else:
|
||||
session['service_name'] = service['name']
|
||||
session.pop('service_name_change')
|
||||
return redirect(url_for('.service_settings', service_id=service_id))
|
||||
return render_template(
|
||||
'views/service-settings/confirm.html',
|
||||
heading='Change your service name',
|
||||
@@ -104,13 +97,7 @@ def service_name_change_confirm(service_id):
|
||||
@login_required
|
||||
@user_has_permissions('manage_settings')
|
||||
def service_request_to_go_live(service_id):
|
||||
try:
|
||||
service = get_service_by_id(service_id)['data']
|
||||
except HTTPError as e:
|
||||
if e.status_code == 404:
|
||||
abort(404)
|
||||
else:
|
||||
raise e
|
||||
service = get_service_by_id(service_id)['data']
|
||||
if request.method == 'GET':
|
||||
return render_template(
|
||||
'views/service-settings/request-to-go-live.html',
|
||||
@@ -127,13 +114,7 @@ def service_request_to_go_live(service_id):
|
||||
@login_required
|
||||
@user_has_permissions('manage_settings')
|
||||
def service_status_change(service_id):
|
||||
try:
|
||||
service = get_service_by_id(service_id)['data']
|
||||
except HTTPError as e:
|
||||
if e.status_code == 404:
|
||||
abort(404)
|
||||
else:
|
||||
raise e
|
||||
service = get_service_by_id(service_id)['data']
|
||||
|
||||
if request.method == 'GET':
|
||||
return render_template(
|
||||
@@ -149,13 +130,7 @@ def service_status_change(service_id):
|
||||
@login_required
|
||||
@user_has_permissions('manage_settings')
|
||||
def service_status_change_confirm(service_id):
|
||||
try:
|
||||
service = get_service_by_id(service_id)['data']
|
||||
except HTTPError as e:
|
||||
if e.status_code == 404:
|
||||
abort(404)
|
||||
else:
|
||||
raise e
|
||||
service = get_service_by_id(service_id)['data']
|
||||
|
||||
# Validate password for form
|
||||
def _check_password(pwd):
|
||||
@@ -178,13 +153,7 @@ def service_status_change_confirm(service_id):
|
||||
@login_required
|
||||
@user_has_permissions('manage_settings')
|
||||
def service_delete(service_id):
|
||||
try:
|
||||
service = get_service_by_id(service_id)['data']
|
||||
except HTTPError as e:
|
||||
if e.status_code == 404:
|
||||
abort(404)
|
||||
else:
|
||||
raise e
|
||||
service = get_service_by_id(service_id)['data']
|
||||
|
||||
if request.method == 'GET':
|
||||
return render_template(
|
||||
@@ -200,13 +169,7 @@ def service_delete(service_id):
|
||||
@login_required
|
||||
@user_has_permissions('manage_settings')
|
||||
def service_delete_confirm(service_id):
|
||||
try:
|
||||
service = get_service_by_id(service_id)['data']
|
||||
except HTTPError as e:
|
||||
if e.status_code == 404:
|
||||
abort(404)
|
||||
else:
|
||||
raise e
|
||||
service = get_service_by_id(service_id)['data']
|
||||
|
||||
# Validate password for form
|
||||
def _check_password(pwd):
|
||||
@@ -214,13 +177,7 @@ def service_delete_confirm(service_id):
|
||||
form = ConfirmPasswordForm(_check_password)
|
||||
|
||||
if form.validate_on_submit():
|
||||
try:
|
||||
service = delete_service(service_id)
|
||||
except HTTPError as e:
|
||||
if e.status_code == 404:
|
||||
abort(404)
|
||||
else:
|
||||
raise e
|
||||
service = delete_service(service_id)
|
||||
return redirect(url_for('.choose_service'))
|
||||
|
||||
return render_template(
|
||||
|
||||
@@ -13,6 +13,11 @@ form_objects = {
|
||||
'sms': SMSTemplateForm
|
||||
}
|
||||
|
||||
page_headings = {
|
||||
'email': 'email',
|
||||
'sms': 'text message'
|
||||
}
|
||||
|
||||
|
||||
@main.route("/services/<service_id>/templates/add-<template_type>", methods=['GET', 'POST'])
|
||||
@login_required
|
||||
@@ -42,7 +47,8 @@ def add_service_template(service_id, template_type):
|
||||
'views/edit-{}-template.html'.format(template_type),
|
||||
form=form,
|
||||
template_type=template_type,
|
||||
service_id=service_id
|
||||
service_id=service_id,
|
||||
heading_action='Add'
|
||||
)
|
||||
|
||||
|
||||
@@ -70,7 +76,8 @@ def edit_service_template(service_id, template_id):
|
||||
form=form,
|
||||
service_id=service_id,
|
||||
template_id=template_id,
|
||||
template_type=template['template_type']
|
||||
template_type=template['template_type'],
|
||||
heading_action='Edit'
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -2,17 +2,17 @@ from flask import (
|
||||
render_template,
|
||||
redirect,
|
||||
session,
|
||||
url_for,
|
||||
abort
|
||||
url_for
|
||||
)
|
||||
|
||||
from notifications_python_client.errors import HTTPError
|
||||
|
||||
from flask_login import login_user
|
||||
|
||||
from app.main import main
|
||||
from app.main.dao import users_dao
|
||||
from app.main.forms import VerifyForm
|
||||
from app.main.forms import (
|
||||
VerifyForm,
|
||||
VerifySmsForm
|
||||
)
|
||||
|
||||
|
||||
@main.route('/verify', methods=['GET', 'POST'])
|
||||
@@ -24,19 +24,19 @@ def verify():
|
||||
|
||||
def _check_code(code, code_type):
|
||||
return users_dao.check_verify_code(user_id, code, code_type)
|
||||
form = VerifyForm(_check_code)
|
||||
|
||||
if session.get('invited_user'):
|
||||
form = VerifySmsForm(_check_code)
|
||||
else:
|
||||
form = VerifyForm(_check_code)
|
||||
|
||||
if form.validate_on_submit():
|
||||
try:
|
||||
user = users_dao.get_user_by_id(user_id)
|
||||
activated_user = users_dao.activate_user(user)
|
||||
login_user(activated_user)
|
||||
return redirect(url_for('main.add_service', first='first'))
|
||||
except HTTPError as e:
|
||||
if e.status_code == 404:
|
||||
abort(404)
|
||||
else:
|
||||
raise e
|
||||
finally:
|
||||
del session['user_details']
|
||||
session.pop('user_details', None)
|
||||
|
||||
return render_template('views/verify.html', form=form)
|
||||
|
||||
@@ -27,7 +27,7 @@ class NotificationsAdminAPIClient(NotificationsAPIClient):
|
||||
"user_id": user_id,
|
||||
"restricted": restricted
|
||||
}
|
||||
return self.post("/service", data)
|
||||
return self.post("/service", data)['data']['id']
|
||||
|
||||
def delete_service(self, service_id):
|
||||
"""
|
||||
|
||||
@@ -10,7 +10,7 @@ class User(UserMixin):
|
||||
self._mobile_number = fields.get('mobile_number')
|
||||
self._password_changed_at = fields.get('password_changed_at')
|
||||
self._permissions = fields.get('permissions')
|
||||
self._failed_login_count = 0
|
||||
self._failed_login_count = fields.get('failed_login_count')
|
||||
self._state = fields.get('state')
|
||||
self.max_failed_login_count = max_failed_login_count
|
||||
|
||||
@@ -129,7 +129,10 @@ class InvitedUser(object):
|
||||
if isinstance(permissions, list):
|
||||
self.permissions = permissions
|
||||
else:
|
||||
self.permissions = permissions.split(',')
|
||||
if permissions:
|
||||
self.permissions = permissions.split(',')
|
||||
else:
|
||||
self.permissions = []
|
||||
self.status = status
|
||||
self.created_at = created_at
|
||||
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
from random import randint
|
||||
from flask import url_for, current_app
|
||||
from itsdangerous import URLSafeTimedSerializer, SignatureExpired
|
||||
from app import notifications_api_client
|
||||
|
||||
|
||||
def send_change_password_email(email):
|
||||
link_to_change_password = url_for('.new_password', token=generate_token(email), _external=True)
|
||||
notifications_api_client.send_email(email_address=email,
|
||||
from_address='notify@digital.cabinet-office.gov.uk',
|
||||
message=link_to_change_password,
|
||||
subject='Reset password for GOV.UK Notify')
|
||||
|
||||
|
||||
def generate_token(email):
|
||||
ser = URLSafeTimedSerializer(current_app.config['SECRET_KEY'])
|
||||
return ser.dumps(email, current_app.config.get('DANGEROUS_SALT'))
|
||||
|
||||
|
||||
def check_token(token):
|
||||
ser = URLSafeTimedSerializer(current_app.config['SECRET_KEY'])
|
||||
try:
|
||||
email = ser.loads(token, max_age=current_app.config['TOKEN_MAX_AGE_SECONDS'],
|
||||
salt=current_app.config.get('DANGEROUS_SALT'))
|
||||
return email
|
||||
except SignatureExpired as e:
|
||||
current_app.logger.info('token expired %s' % e)
|
||||
@@ -1,5 +1,3 @@
|
||||
import json
|
||||
|
||||
from notifications_python_client.notifications import BaseAPIClient
|
||||
from notifications_python_client.errors import HTTPError
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{% macro yes_no(field, current_value=None) %}
|
||||
<fieldset class='yes-no {% if field.errors %} error{% endif %}'>
|
||||
<legend class='yes-no-label'>
|
||||
<fieldset class='yes-no'>
|
||||
<legend class='yes-no-label{% if field.errors %} error{% endif %}'>
|
||||
{{ field.label }}
|
||||
{% if field.errors %}
|
||||
<span class="error-message">
|
||||
|
||||
@@ -10,9 +10,9 @@
|
||||
</ul>
|
||||
{% elif current_user.has_permissions(['manage_templates']) %}
|
||||
<ul>
|
||||
<li><a href="{{ url_for('.choose_template', service_id=service_id, template_type='sms') }}">Message templates</a></li>
|
||||
<li><a href="{{ url_for('.choose_template', service_id=service_id, template_type='sms') }}">Text message templates</a></li>
|
||||
<li><a href="{{ url_for('.choose_template', service_id=service_id, template_type='email') }}">Email templates</a></li>
|
||||
<li><a href="{{ url_for('.letters_stub', service_id=service_id) }}">Send letters</a></li>
|
||||
<li><a href="{{ url_for('.letters_stub', service_id=service_id) }}">Letter templates</a></li>
|
||||
</ul>
|
||||
{% endif %}
|
||||
{% if current_user.has_permissions(['manage_users', 'manage_settings']) %}
|
||||
|
||||
@@ -72,12 +72,12 @@
|
||||
{% endif %}
|
||||
|
||||
{% call(item) list_table(
|
||||
recipients.rows_annotated_and_truncated,
|
||||
recipients.initial_annotated_rows_with_errors if rows_have_errors else recipients.initial_annotated_rows,
|
||||
caption=original_file_name,
|
||||
field_headings=['Row'] + recipients.column_headers_with_placeholders_highlighted
|
||||
field_headings=['1'] + recipients.column_headers_with_placeholders_highlighted
|
||||
) %}
|
||||
{% call field() %}
|
||||
{{ item.index + 1 }}
|
||||
{{ item.index + 2 }}
|
||||
{% endcall %}
|
||||
{% for column in recipients.column_headers %}
|
||||
{% if item[column].error %}
|
||||
@@ -99,7 +99,7 @@
|
||||
|
||||
{% if count_of_displayed_recipients < count_of_recipients %}
|
||||
<p class="table-show-more-link">
|
||||
{{ count_of_recipients - count_of_displayed_recipients }} more {{ "row" if 1 == (count_of_recipients - count_of_displayed_recipients) else "rows"}} not shown
|
||||
{{ count_of_recipients - count_of_displayed_recipients }} {{ "row" if 1 == (count_of_recipients - count_of_displayed_recipients) else "rows"}} not shown
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
|
||||
@@ -10,55 +10,64 @@
|
||||
|
||||
{% block maincolumn_content %}
|
||||
|
||||
<h1 class="heading-large">{{ page_heading }}</h1>
|
||||
{% if not templates %}
|
||||
|
||||
<form method="POST" enctype="multipart/form-data">
|
||||
<h1 class="heading-large">{{ page_heading }}</h1>
|
||||
|
||||
{% if templates %}
|
||||
{% if not has_jobs %}
|
||||
{% if current_user.has_permissions(['send_texts', 'send_emails', 'send_letters'], or_=True) %}
|
||||
{{ banner(
|
||||
"""
|
||||
Send yourself a test message
|
||||
""",
|
||||
subhead='Next step',
|
||||
type="tip"
|
||||
)}}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
<div class="grid-row">
|
||||
{% for template in templates %}
|
||||
<div class="column-two-thirds">
|
||||
{% if 'email' == template_type %}
|
||||
{{ email_message(
|
||||
template.subject,
|
||||
template.formatted_as_markup,
|
||||
name=template.name
|
||||
) }}
|
||||
{% elif 'sms' == template_type %}
|
||||
{{ sms_message(template.formatted_as_markup, name=template.name) }}
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="column-one-third">
|
||||
<div class="sms-message-use-links">
|
||||
{% if current_user.has_permissions(['send_texts', 'send_emails', 'send_letters']) %}
|
||||
<a href="{{ url_for(".send_messages", service_id=service_id, template_id=template.id) }}">Add recipients</a>
|
||||
<a href="{{ url_for(".send_message_to_self", service_id=service_id, template_id=template.id) }}">Send yourself a test</a>
|
||||
{% endif %}
|
||||
{% if current_user.has_permissions(['manage_templates']) %}
|
||||
<a href="{{ url_for(".edit_service_template", service_id=service_id, template_id=template.id) }}">Edit template</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% if current_user.has_permissions(['manage_templates']) %}
|
||||
<a href="{{ url_for('.add_service_template', service_id=service_id, template_type=template_type) }}" class="button">Add a new template</a>
|
||||
{% endif %}
|
||||
|
||||
<p>
|
||||
{% if current_user.has_permissions(['manage_templates']) %}
|
||||
<a href="{{ url_for('.add_service_template', service_id=service_id, template_type=template_type) }}" class="button">Add a new template</a>
|
||||
{% endif %}
|
||||
</p>
|
||||
{% else %}
|
||||
|
||||
<div class="grid-row">
|
||||
<div class="column-two-thirds">
|
||||
<h1 class="heading-large">{{ page_heading }}</h1>
|
||||
</div>
|
||||
{% if current_user.has_permissions(['manage_templates']) %}
|
||||
<div class="column-one-third">
|
||||
<a href="{{ url_for('.add_service_template', service_id=service_id, template_type=template_type) }}" class="button align-with-heading">Add new template</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% if not has_jobs %}
|
||||
{% if current_user.has_permissions(['send_texts', 'send_emails', 'send_letters'], or_=True) %}
|
||||
{{ banner(
|
||||
"""
|
||||
Send yourself a test message
|
||||
""",
|
||||
subhead='Next step',
|
||||
type="tip"
|
||||
)}}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
<div class="grid-row">
|
||||
{% for template in templates %}
|
||||
<div class="column-two-thirds">
|
||||
{% if 'email' == template_type %}
|
||||
{{ email_message(
|
||||
template.subject,
|
||||
template.formatted_as_markup,
|
||||
name=template.name
|
||||
) }}
|
||||
{% elif 'sms' == template_type %}
|
||||
{{ sms_message(template.formatted_as_markup, name=template.name) }}
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="column-one-third">
|
||||
<div class="sms-message-use-links">
|
||||
{% if current_user.has_permissions(['send_texts', 'send_emails', 'send_letters']) %}
|
||||
<a href="{{ url_for(".send_messages", service_id=service_id, template_id=template.id) }}">Add recipients</a>
|
||||
<a href="{{ url_for(".send_message_to_self", service_id=service_id, template_id=template.id) }}">Send yourself a test</a>
|
||||
{% endif %}
|
||||
{% if current_user.has_permissions(['manage_templates']) %}
|
||||
<a href="{{ url_for(".edit_service_template", service_id=service_id, template_id=template.id) }}">Edit template</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
||||
@@ -3,12 +3,14 @@
|
||||
{% from "components/page-footer.html" import page_footer %}
|
||||
|
||||
{% block page_title %}
|
||||
{{ h1 }} – GOV.UK Notify
|
||||
{{ heading_action }} email template – GOV.UK Notify
|
||||
{% endblock %}
|
||||
|
||||
{% block maincolumn_content %}
|
||||
|
||||
<h1 class="heading-large">Edit email template</h1>
|
||||
<h1 class="heading-large">
|
||||
{{ heading_action }} email template
|
||||
</h1>
|
||||
|
||||
<form method="post">
|
||||
<div class="grid-row">
|
||||
@@ -21,17 +23,19 @@
|
||||
</div>
|
||||
<div class="column-one-third">
|
||||
<label for='template_content' class='edit-template-placeholder-hint'>
|
||||
Add placeholders using double brackets, eg Your thing
|
||||
is due on ((date))
|
||||
<p>
|
||||
Add personalisation with double brackets, eg Dear ((name))
|
||||
</p>
|
||||
<p>
|
||||
You’ll fill in the real data when you send a message.
|
||||
</p>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
{{ page_footer(
|
||||
'Save',
|
||||
delete_link=url_for('.delete_service_template', service_id=service_id, template_id=template_id) if template_id or None,
|
||||
delete_link_text='Delete this template',
|
||||
back_link=url_for('.choose_template', template_type=template_type, service_id=service_id),
|
||||
back_link_text='Cancel'
|
||||
delete_link_text='Delete this template'
|
||||
) }}
|
||||
</form>
|
||||
|
||||
|
||||
@@ -3,12 +3,14 @@
|
||||
{% from "components/page-footer.html" import page_footer %}
|
||||
|
||||
{% block page_title %}
|
||||
{{ h1 }} – GOV.UK Notify
|
||||
{{ heading_action }} text message template – GOV.UK Notify
|
||||
{% endblock %}
|
||||
|
||||
{% block maincolumn_content %}
|
||||
|
||||
<h1 class="heading-large">Edit text message template</h1>
|
||||
<h1 class="heading-large">
|
||||
{{ heading_action }} text message template
|
||||
</h1>
|
||||
|
||||
<form method="post">
|
||||
<div class="grid-row">
|
||||
@@ -20,17 +22,19 @@
|
||||
</div>
|
||||
<div class="column-one-third">
|
||||
<label for='template_content' class='edit-template-placeholder-hint'>
|
||||
Add placeholders using double brackets, eg Your thing
|
||||
is due on ((date))
|
||||
<p>
|
||||
Add personalisation with double brackets, eg Dear ((name))
|
||||
</p>
|
||||
<p>
|
||||
You'll have to add the real data when you send a message.
|
||||
</p>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
{{ page_footer(
|
||||
'Save',
|
||||
delete_link=url_for('.delete_service_template', service_id=service_id, template_id=template_id) if template_id or None,
|
||||
delete_link_text='Delete this template',
|
||||
back_link=url_for('.choose_template', service_id=service_id, template_type=template_type),
|
||||
back_link_text='Cancel'
|
||||
delete_link_text='Delete this template'
|
||||
) }}
|
||||
</form>
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ Manage users – GOV.UK Notify
|
||||
{% block maincolumn_content %}
|
||||
|
||||
<h1 class="heading-large">
|
||||
{{ user.name or user.email_localpart or "Add a new team member" }}
|
||||
{{ user.name or user.email_localpart or "Invite a team member" }}
|
||||
</h1>
|
||||
|
||||
<div class="grid-row">
|
||||
|
||||
@@ -7,7 +7,11 @@
|
||||
{% block maincolumn_content %}
|
||||
|
||||
<h1 class="heading-large">
|
||||
Send letters
|
||||
{% if current_user.has_permissions(['send_letters']) %}
|
||||
Send letters
|
||||
{% else %}
|
||||
Letter templates
|
||||
{% endif %}
|
||||
</h1>
|
||||
|
||||
<p>
|
||||
|
||||
@@ -16,11 +16,16 @@ Manage users – GOV.UK Notify
|
||||
|
||||
{% block maincolumn_content %}
|
||||
|
||||
<h1 class="heading-large">
|
||||
Manage team
|
||||
</h1>
|
||||
|
||||
<a href="{{ url_for('.invite_user', service_id=service_id) }}" class="button">Invite a team member</a>
|
||||
<div class="grid-row">
|
||||
<div class="column-two-thirds">
|
||||
<h1 class="heading-large">
|
||||
Manage team
|
||||
</h1>
|
||||
</div>
|
||||
<div class="column-one-third">
|
||||
<a href="{{ url_for('.invite_user', service_id=service_id) }}" class="button align-with-heading">Invite team member</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% call(item) list_table(
|
||||
users, caption='Active', **table_options
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
{% block maincolumn_content %}
|
||||
|
||||
<h1 class="heading-large">Service settings</h1>
|
||||
<h1 class="heading-large">Manage settings</h1>
|
||||
|
||||
{{ browse_list([
|
||||
{
|
||||
|
||||
@@ -29,12 +29,12 @@
|
||||
<ol>
|
||||
{% if current_user.has_permissions(['manage_templates']) %}
|
||||
<li>
|
||||
<a href='url_for(".add_service_template", service_id=service_id, template_type="sms")'>Add a template</a>
|
||||
<a href='{{ url_for(".add_service_template", service_id=service_id, template_type="sms") }}'>Add a template</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if current_user.has_permissions(['send_texts', 'send_emails', 'send_letters']) %}
|
||||
<li>
|
||||
<a href='url_for(".choose_template", service_id=service_id, template_type="sms")'>Send yourself a text message</a>
|
||||
<a href='{{ url_for(".choose_template", service_id=service_id, template_type="sms") }}'>Send yourself a text message</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ol>
|
||||
@@ -42,7 +42,7 @@
|
||||
{% elif not jobs %}
|
||||
{% call banner_wrapper(subhead='Next step', type="tip") %}
|
||||
{% if current_user.has_permissions(['send_texts', 'send_emails', 'send_letters']) %}
|
||||
<a href='url_for(".choose_template", service_id=service_id, template_type="sms")'>Send yourself a text message</a>
|
||||
<a href='{{ url_for(".choose_template", service_id=service_id, template_type="sms") }}'>Send yourself a text message</a>
|
||||
{% endif %}
|
||||
{% endcall %}
|
||||
{% else %}
|
||||
|
||||
@@ -3,30 +3,48 @@
|
||||
{% from "components/page-footer.html" import page_footer %}
|
||||
|
||||
{% block page_title %}
|
||||
Enter the codes we’ve sent you – GOV.UK Notify
|
||||
{% if form.email_code %}
|
||||
Enter the codes we’ve sent you – GOV.UK Notify
|
||||
{% else %}
|
||||
Enter the code we’ve sent you – GOV.UK Notify
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block maincolumn_content %}
|
||||
|
||||
<div class="grid-row">
|
||||
<div class="column-two-thirds">
|
||||
<h1 class="heading-large">Enter the codes we’ve sent you</h1>
|
||||
<p>
|
||||
We’ve sent you confirmation codes by email and text message.
|
||||
</p>
|
||||
{% if form.email_code %}
|
||||
<h1 class="heading-large">Enter the codes we’ve sent you</h1>
|
||||
{% else %}
|
||||
<h1 class="heading-large">Enter the code we’ve sent you</h1>
|
||||
{% endif %}
|
||||
{% if form.email_code %}
|
||||
<p>
|
||||
We’ve sent you confirmation codes by email and text message.
|
||||
</p>
|
||||
{% else %}
|
||||
<p>
|
||||
We’ve sent you a confirmation code by text message.
|
||||
</p>
|
||||
{% endif %}
|
||||
<form autocomplete="off" method="post">
|
||||
{% if form.sms_code %}
|
||||
{{ textbox(
|
||||
form.sms_code,
|
||||
width='5em',
|
||||
help_link=url_for('.check_and_resend_text_code'),
|
||||
help_link_text='I haven’t received a text message'
|
||||
) }}
|
||||
{{ textbox(
|
||||
form.email_code,
|
||||
width='5em',
|
||||
help_link=url_for('.check_and_resend_email_code'),
|
||||
help_link_text='I haven’t received an email'
|
||||
) }}
|
||||
form.sms_code,
|
||||
width='5em',
|
||||
help_link=url_for('.check_and_resend_text_code'),
|
||||
help_link_text='I haven’t received a text message'
|
||||
) }}
|
||||
{% endif %}
|
||||
{% if form.email_code %}
|
||||
{{ textbox(
|
||||
form.email_code,
|
||||
width='5em',
|
||||
help_link=url_for('.check_and_resend_email_code'),
|
||||
help_link_text='I haven’t received an email'
|
||||
) }}
|
||||
{% endif %}
|
||||
{{ page_footer("Continue") }}
|
||||
</form>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user