Merge with master.

This commit is contained in:
Nicholas Staples
2016-01-19 09:49:01 +00:00
48 changed files with 686 additions and 327 deletions

View File

@@ -0,0 +1,39 @@
templates = [
{
'type': 'sms',
'name': 'Confirmation',
'body': 'Lasting power of attorney: Weve received your application. Applications take between 8 and 10 weeks to process.' # noqa
},
{
'type': 'sms',
'name': 'Reminder',
'body': 'Vehicle tax: Your vehicle tax for ((registration number)) expires on ((date)). Tax your vehicle at www.gov.uk/vehicle-tax' # noqa
},
{
'type': 'sms',
'name': 'Warning',
'body': 'Vehicle tax: Your vehicle tax for ((registration number)) has expired. Tax your vehicle at www.gov.uk/vehicle-tax' # noqa
},
{
'type': 'email',
'name': 'Application alert 06/2016',
'subject': 'Your lasting power of attorney application',
'body': """Dear ((name)),
When youve made your lasting power of attorney (LPA), you need to register it \
with the Office of the Public Guardian (OPG).
You can apply to register your LPA yourself if youre able to make your own decisions.
Your attorney can also register it for you. Youll be told if they do and you can \
object to the registration.
It takes between 8 and 10 weeks to register an LPA if there are no mistakes in the application.
"""
},
{
'type': 'sms',
'name': 'Air quality alert',
'body': 'Air pollution levels will be ((level)) in ((region)) tomorrow.'
},
]

View File

@@ -1,4 +1,4 @@
from flask import render_template, jsonify, redirect, session, url_for
from flask import request, render_template, jsonify, redirect, session, url_for, abort
from flask_login import login_required
from app.main import main
from app.main.dao import services_dao, users_dao
@@ -8,11 +8,19 @@ from app.main.forms import AddServiceForm
@main.route("/add-service", methods=['GET', 'POST'])
@login_required
def add_service():
# TODO fix up this
form = AddServiceForm(services_dao.find_all_service_names)
services = services_dao.get_services()
if len(services) > 0:
heading = 'Set up notifications for your service'
else:
heading = 'Add a new service'
if form.validate_on_submit():
user = users_dao.get_user_by_id(session['user_id'])
service_id = services_dao.insert_new_service(form.name.data, user)
return redirect(url_for('main.service_dashboard', service_id=service_id))
else:
return render_template('views/add-service.html', form=form)
return render_template(
'views/add-service.html',
form=form,
heading=heading
)

View File

@@ -0,0 +1,9 @@
from flask import render_template
from flask_login import login_required
from app.main import main
@main.route("/services/<int:service_id>/api-keys")
@login_required
def api_keys(service_id):
return render_template('views/api-keys.html', service_id=service_id)

View File

@@ -36,9 +36,3 @@ def check_email(service_id):
@login_required
def manage_users(service_id):
return render_template('views/manage-users.html', service_id=service_id)
@main.route("/services/<int:service_id>/api-keys")
@login_required
def apikeys(service_id):
return render_template('views/api-keys.html', service_id=service_id)

View File

@@ -20,24 +20,15 @@ from werkzeug import secure_filename
from app.main import main
from app.main.forms import CsvUploadForm
from app.main.uploader import s3upload
from app.main.uploader import (
s3upload,
s3download
)
# TODO move this to the templates directory
message_templates = [
{
'name': 'Reminder',
'body': """
Vehicle tax: Your vehicle tax for ((registration number)) expires on ((date)).
Tax your vehicle at www.gov.uk/vehicle-tax
"""
},
{
'name': 'Warning',
'body': """
Vehicle tax: Your vehicle tax for ((registration number)) has expired.
Tax your vehicle at www.gov.uk/vehicle-tax
"""
},
from ._templates import templates
sms_templates = [
template for template in templates if template['type'] == 'sms'
]
@@ -48,68 +39,52 @@ def send_sms(service_id):
if form.validate_on_submit():
try:
csv_file = form.file.data
filename = _format_filename(csv_file.filename)
filepath = os.path.join(current_app.config['UPLOAD_FOLDER'],
filename)
csv_file.save(filepath)
_check_file(csv_file.filename, filepath)
filedata = _get_filedata(csv_file)
upload_id = s3upload(service_id, filedata)
return redirect(url_for('.check_sms',
service_id=service_id,
recipients=filename))
except (IOError, ValueError) as e:
upload_id=upload_id))
except ValueError as e:
message = 'There was a problem uploading: {}'.format(
csv_file.filename)
flash(message)
if isinstance(e, ValueError):
flash(str(e))
os.remove(filepath)
flash(str(e))
return redirect(url_for('.send_sms', service_id=service_id))
return render_template('views/send-sms.html',
message_templates=message_templates,
message_templates=sms_templates,
form=form,
service_id=service_id)
@main.route("/services/<int:service_id>/sms/check", methods=['GET', 'POST'])
@main.route("/services/<int:service_id>/sms/check/<upload_id>",
methods=['GET', 'POST'])
@login_required
def check_sms(service_id):
def check_sms(service_id, upload_id):
if request.method == 'GET':
filename = request.args.get('recipients')
if not filename:
abort(400)
filepath = os.path.join(current_app.config['UPLOAD_FOLDER'],
filename)
upload_result = _build_upload_result(filepath)
if upload_result.get('rejects'):
flash('There was a problem with some of the numbers')
contents = s3download(service_id, upload_id)
upload_result = _get_numbers(contents)
# TODO get original file name
return render_template(
'views/check-sms.html',
upload_result=upload_result,
filename=filename,
message_template=message_templates[0]['body'],
filename='someupload_file_name.csv',
message_template=sms_templates[0]['body'],
service_id=service_id
)
elif request.method == 'POST':
filename = request.form['recipients']
filepath = os.path.join(current_app.config['UPLOAD_FOLDER'],
filename)
try:
upload_id = s3upload(filepath)
# TODO when job is created record filename in job itself
# so downstream pages can get the original filename that way
session[upload_id] = filename
return redirect(url_for('main.view_job', service_id=service_id, job_id=upload_id))
except:
flash('There as a problem saving the file')
return redirect(url_for('.check_sms', recipients=filename))
# TODO create the job with template, file location etc.
return redirect(url_for('main.view_job',
service_id=service_id,
job_id=upload_id))
def _check_file(filename, filepath):
if os.stat(filepath).st_size == 0:
message = 'The file {} contained no data'.format(filename)
def _get_filedata(file):
lines = file.read().decode('utf-8').splitlines()
if len(lines) < 2: # must be at least header and one line
message = 'The file {} contained no data'.format(file.filename)
raise ValueError(message)
return {'filename': file.filename, 'data': lines}
def _format_filename(filename):
@@ -119,24 +94,16 @@ def _format_filename(filename):
return secure_filename(formatted_name)
def _open(file):
return open(file, 'r')
def _build_upload_result(csv_file):
try:
file = _open(csv_file, 'r')
pattern = re.compile(r'^\+44\s?\d{4}\s?\d{6}$')
reader = csv.DictReader(
file.read().splitlines(),
lineterminator='\n',
quoting=csv.QUOTE_NONE)
valid, rejects = [], []
for i, row in enumerate(reader):
if pattern.match(row['phone']):
valid.append(row)
else:
rejects.append({"line_number": i+2, "phone": row['phone']})
return {"valid": valid, "rejects": rejects}
finally:
file.close()
def _get_numbers(contents):
pattern = re.compile(r'^\+44\s?\d{4}\s?\d{6}$') # need better validation
reader = csv.DictReader(
contents.split('\n'),
lineterminator='\n',
quoting=csv.QUOTE_NONE)
valid, rejects = [], []
for i, row in enumerate(reader):
if pattern.match(row['phone']):
valid.append(row)
else:
rejects.append({"line_number": i+2, "phone": row['phone']})
return {"valid": valid, "rejects": rejects}

View File

@@ -1,16 +1,19 @@
from flask import request, render_template, redirect, url_for
from flask import request, render_template, redirect, url_for, flash
from flask_login import login_required
from app.main import main
from app.main.forms import TemplateForm
from ._templates import templates
@main.route("/services/<int:service_id>/templates")
@login_required
def manage_templates(service_id):
return render_template(
'views/manage-templates.html',
service_id=service_id
service_id=service_id,
templates=templates,
)
@@ -31,21 +34,49 @@ def add_template(service_id):
return redirect(url_for('.manage_templates', service_id=service_id))
@main.route("/services/<int:service_id>/templates/<template_id>", methods=['GET', 'POST'])
@main.route("/services/<int:service_id>/templates/<int:template_id>", methods=['GET', 'POST'])
@login_required
def edit_template(service_id, template_id):
form = TemplateForm()
form.template_name.data = 'Reminder'
form.template_body.data = 'Vehicle tax: Your vehicle tax for ((registration number)) expires on ((date)). Tax your vehicle at www.gov.uk/vehicle-tax' # noqa
form.template_name.data = templates[template_id - 1]['name']
form.template_body.data = templates[template_id - 1]['body']
if request.method == 'GET':
return render_template(
'views/edit-template.html',
h1='Edit template',
form=form,
service_id=service_id
service_id=service_id,
template_id=template_id
)
elif request.method == 'POST':
return redirect(url_for('.manage_templates', service_id=service_id))
@main.route("/services/<int:service_id>/templates/<int:template_id>/delete", methods=['GET', 'POST'])
@login_required
def delete_template(service_id, template_id):
form = TemplateForm()
form.template_name.data = templates[template_id - 1]['name']
form.template_body.data = templates[template_id - 1]['body']
if request.method == 'GET':
flash('Are you sure you want to delete {}?'.format(form.template_name.data), 'delete')
return render_template(
'views/edit-template.html',
h1='Edit template',
form=form,
service_id=service_id,
template_id=template_id
)
elif request.method == 'POST':
if request.form.get('delete'):
return redirect(url_for('.manage_templates', service_id=service_id))
else:
return redirect(url_for('.manage_templates', service_id=service_id))

View File

@@ -20,5 +20,5 @@ def verify():
verify_codes_dao.use_code_for_user_and_type(user_id=user.id, code_type='sms')
users_dao.activate_user(user.id)
login_user(user)
return redirect(url_for('.add_service'))
return redirect(url_for('.add_service', first='first'))
return render_template('views/verify.html', form=form)