Merge branch 'master' of github.com:alphagov/notifications-admin into deactivate-services-plat-admin

This commit is contained in:
Leo Hemsted
2016-11-14 17:15:05 +00:00
48 changed files with 751 additions and 411 deletions

View File

@@ -27,27 +27,58 @@ from app.main.validators import (Blacklist, CsvFileValidator, ValidGovEmail, NoC
def get_time_value_and_label(future_time):
return (
future_time.replace(tzinfo=None).isoformat(),
get_human_time(future_time.astimezone(pytz.timezone('Europe/London')))
'{} at {}'.format(
get_human_day(future_time.astimezone(pytz.timezone('Europe/London'))),
get_human_time(future_time.astimezone(pytz.timezone('Europe/London')))
)
)
def get_human_time(time):
return {
'0': 'Midnight',
'12': 'Midday'
'0': 'midnight',
'12': 'midday'
}.get(
time.strftime('%-H'),
time.strftime('%-I%p').lower()
)
def get_next_hours_from(now, hours=23):
def get_human_day(time, prefix_today_with='T'):
# Add 1 hour to get midnight today instead of midnight tomorrow
time = (time - timedelta(hours=1)).strftime('%A')
if time == datetime.utcnow().strftime('%A'):
return '{}oday'.format(prefix_today_with)
if time == (datetime.utcnow() + timedelta(days=1)).strftime('%A'):
return 'Tomorrow'
return time
def get_furthest_possible_scheduled_time():
return (datetime.utcnow() + timedelta(days=4)).replace(hour=0)
def get_next_hours_until(until):
now = datetime.utcnow()
hours = int((until - now).total_seconds() / (60 * 60))
return [
(now + timedelta(hours=i)).replace(minute=0, second=0).replace(tzinfo=pytz.utc)
for i in range(1, hours + 1)
]
def get_next_days_until(until):
now = datetime.utcnow()
days = int((until - now).total_seconds() / (60 * 60 * 24))
return [
get_human_day(
(now + timedelta(days=i)).replace(tzinfo=pytz.utc),
prefix_today_with='Later t'
)
for i in range(0, days + 1)
]
def email_address(label='Email address', gov_user=True):
validators = [
Length(min=5, max=255),
@@ -310,8 +341,11 @@ class ChooseTimeForm(Form):
def __init__(self, *args, **kwargs):
super(ChooseTimeForm, self).__init__(*args, **kwargs)
self.scheduled_for.choices = [('', 'Now')] + [
get_time_value_and_label(hour) for hour in get_next_hours_from(datetime.utcnow())
get_time_value_and_label(hour) for hour in get_next_hours_until(
get_furthest_possible_scheduled_time()
)
]
self.scheduled_for.categories = get_next_days_until(get_furthest_possible_scheduled_time())
scheduled_for = RadioField(
'When should Notify send these messages?',
@@ -350,26 +384,47 @@ class Feedback(Form):
class RequestToGoLiveForm(Form):
channel = StringField(
'Are you sending emails or text messages or both?',
validators=[DataRequired(message='Cant be empty')]
mou = RadioField(
(
'Has your organisation accepted the GOV.UK Notify data sharing and financial '
'agreement (Memorandum of Understanding)?'
),
choices=[
('yes', 'Yes'),
('no', 'No'),
('dont know', 'I dont know')
],
validators=[DataRequired()]
)
channel = RadioField(
'What kind of messages will you be sending?',
choices=[
('emails', 'Emails'),
('text messages', 'Text messages'),
('emails and text messages', 'Both')
],
validators=[DataRequired()]
)
start_date = StringField(
'When will you be ready to start sending messages?',
validators=[DataRequired(message='Cant be empty')]
)
start_volume = StringField(
'How many messages do you expect to send per month to start with? Give an estimate in numbers.',
'How many messages do you expect to send to start with?',
validators=[DataRequired(message='Cant be empty')]
)
peak_volume = StringField(
'Will the number of messages a month increase and when will that start? Give an estimate.',
'Will the number of messages increase and when will that start?',
validators=[DataRequired(message='Cant be empty')]
)
upload_or_api = StringField(
'Are you uploading a list of contacts that youre sending your message to, ' +
'or are you integrating your system with ours?',
validators=[DataRequired(message='Cant be empty')]
upload_or_api = RadioField(
'How are you going to send messages?',
choices=[
('File upload', 'Upload a spreadsheet of recipients'),
('API', 'Integrate with the GOV.UK Notify API'),
('API and file upload', 'Both')
],
validators=[DataRequired()]
)

View File

@@ -1,4 +1,4 @@
from flask import request, render_template, redirect, url_for, flash
from flask import request, render_template, redirect, url_for, flash, Markup, abort
from flask_login import login_required
from app.main import main
from app.main.forms import CreateKeyForm, Whitelist
@@ -68,13 +68,22 @@ def create_api_key(service_id):
key['name'] for key in api_key_api_client.get_api_keys(service_id=service_id)['apiKeys']
]
form = CreateKeyForm(key_names)
form.key_type.choices = filter(None, [
(KEY_TYPE_NORMAL, 'Send messages to anyone')
if not current_service['restricted'] else None,
(KEY_TYPE_TEST, 'Simulate sending messages to anyone'),
(KEY_TYPE_TEAM, 'Only send messages to your team or whitelist')
])
form.key_type.choices = [
(KEY_TYPE_NORMAL, 'Send messages to anyone'),
(KEY_TYPE_TEAM, 'Send messages to anyone on my whitelist'),
(KEY_TYPE_TEST, 'Pretend to send messages to anyone'),
]
if current_service['restricted']:
disabled_options = [KEY_TYPE_NORMAL]
option_hints = {KEY_TYPE_NORMAL: Markup(
'This option is not available because your service is in '
'<a href="{}">trial mode</a>'.format(url_for(".trial_mode"))
)}
else:
disabled_options, option_hints = [], {}
if form.validate_on_submit():
if form.key_type.data in disabled_options:
abort(400)
secret = api_key_api_client.create_api_key(
service_id=service_id,
key_name=form.key_name.data,
@@ -88,7 +97,9 @@ def create_api_key(service_id):
)
return render_template(
'views/api/keys/create.html',
form=form
form=form,
disabled_options=disabled_options,
option_hints=option_hints
)

View File

@@ -8,7 +8,6 @@ from app.utils import user_has_permissions
@main.route("/services/<service_id>/letters")
@login_required
@user_has_permissions('manage_templates', 'send_letters', admin_override=True, any_=True)
def letters(service_id):
if not current_service['can_send_letters']:
abort(403)

View File

@@ -1,7 +1,5 @@
import itertools
from datetime import datetime
import pytz
from flask import render_template
from flask_login import login_required
@@ -63,13 +61,10 @@ def create_global_stats(services):
def format_stats_by_service(services):
for service in services:
stats = service['statistics'].values()
yield {
'id': service['id'],
'name': service['name'],
'sending': sum((stat['requested'] - stat['delivered'] - stat['failed']) for stat in stats),
'delivered': sum(stat['delivered'] for stat in stats),
'failed': sum(stat['failed'] for stat in stats),
'stats': service['statistics'],
'restricted': service['restricted'],
'research_mode': service['research_mode'],
'created_at': service['created_at'],

View File

@@ -21,7 +21,7 @@ from notifications_utils.template import Template
from notifications_utils.recipients import RecipientCSV, first_column_heading, validate_and_format_phone_number
from app.main import main
from app.main.forms import CsvUploadForm, ChooseTimeForm
from app.main.forms import CsvUploadForm, ChooseTimeForm, get_next_days_until, get_furthest_possible_scheduled_time
from app.main.uploader import (
s3upload,
s3download

View File

@@ -112,11 +112,13 @@ def service_request_to_go_live(service_id):
'subject': 'Request to go live',
'message': (
'On behalf of {} ({})\n\nExpected usage\n---'
'\nMOU in place: {}'
'\nChannel: {}\nStart date: {}\nStart volume: {}'
'\nPeak volume: {}\nUpload or API: {}'
).format(
current_service['name'],
url_for('main.service_dashboard', service_id=current_service['id'], _external=True),
form.mou.data,
form.channel.data,
form.start_date.data,
form.start_volume.data,

View File

@@ -42,7 +42,8 @@ def view_template(service_id, template_id):
'views/templates/template.html',
template=Template(
service_api_client.get_service_template(service_id, template_id)['data'],
prefix=current_service['name']
prefix=current_service['name'],
sms_sender=current_service['sms_sender']
)
)
@@ -63,7 +64,8 @@ def view_template_version(service_id, template_id, version):
'views/templates/template_history.html',
template=Template(
service_api_client.get_service_template(service_id, template_id, version)['data'],
prefix=current_service['name']
prefix=current_service['name'],
sms_sender=current_service['sms_sender']
)
)
@@ -231,7 +233,8 @@ def view_template_versions(service_id, template_id):
versions=[
Template(
template,
prefix=current_service['name']
prefix=current_service['name'],
sms_sender=current_service['sms_sender']
) for template in service_api_client.get_service_template_versions(service_id, template_id)['data']
]
)

View File

@@ -47,8 +47,8 @@ def user_profile_name():
form = ChangeNameForm(new_name=current_user.name)
if form.validate_on_submit():
current_user.name = form.new_name.data
user_api_client.update_user(current_user)
user_api_client.update_user_attribute(current_user.id,
name=form.new_name.data)
return redirect(url_for('.user_profile'))
return render_template(
@@ -107,7 +107,6 @@ def user_profile_email_authenticate():
@main.route("/user-profile/email/confirm/<token>", methods=['GET'])
@login_required
def user_profile_email_confirm(token):
token_data = check_token(token,
current_app.config['SECRET_KEY'],
current_app.config['DANGEROUS_SALT'],
@@ -115,9 +114,8 @@ def user_profile_email_confirm(token):
token_data = json.loads(token_data)
user_id = token_data['user_id']
new_email = token_data['email']
user = user_api_client.get_user(user_id)
user.email_address = new_email
user_api_client.update_user(user)
user_api_client.update_user_attribute(user_id,
email_address=new_email)
session.pop(NEW_EMAIL, None)
return redirect(url_for('.user_profile'))
@@ -179,10 +177,11 @@ def user_profile_mobile_number_confirm():
form = ConfirmMobileNumberForm(_check_code)
if form.validate_on_submit():
current_user.mobile_number = session[NEW_MOBILE]
mobile_number = session[NEW_MOBILE]
del session[NEW_MOBILE]
del session[NEW_MOBILE_PASSWORD_CONFIRMED]
user_api_client.update_user(current_user)
user_api_client.update_user_attribute(current_user.id,
mobile_number=mobile_number)
return redirect(url_for('.user_profile'))
return render_template(