mirror of
https://github.com/GSA/notifications-admin.git
synced 2026-08-19 05:59:44 -04:00
Merge branch 'master' of github.com:alphagov/notifications-admin into deactivate-services-plat-admin
This commit is contained in:
@@ -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='Can’t 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'),
|
||||
('don’t know', 'I don’t 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='Can’t 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='Can’t 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='Can’t be empty')]
|
||||
)
|
||||
upload_or_api = StringField(
|
||||
'Are you uploading a list of contacts that you’re sending your message to, ' +
|
||||
'or are you integrating your system with ours?',
|
||||
validators=[DataRequired(message='Can’t 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()]
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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'],
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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']
|
||||
]
|
||||
)
|
||||
|
||||
@@ -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(
|
||||
|
||||
Reference in New Issue
Block a user