List and individual job pages now fetch data from api.

Few bug fixes around job uuid.
This commit is contained in:
Adam Shimali
2016-01-29 15:35:35 +00:00
parent 5f7b9fed3a
commit 4ea50499c3
11 changed files with 132 additions and 125 deletions

View File

@@ -1,17 +1,13 @@
import uuid
from boto3 import resource
def s3upload(service_id, filedata):
upload_id = str(uuid.uuid4())
def s3upload(upload_id, service_id, filedata):
s3 = resource('s3')
bucket_name = 'service-{}-{}-notify'.format(service_id, upload_id)
s3.create_bucket(Bucket=bucket_name)
contents = '\n'.join(filedata['data'])
key = s3.Object(bucket_name, upload_id)
key.put(Body=contents, ServerSideEncryption='AES256')
return upload_id
def s3download(service_id, upload_id):

View File

@@ -4,84 +4,64 @@ import time
from flask import (
render_template,
session
abort
)
from flask_login import login_required
from client.errors import HTTPError
from app import job_api_client
from app.main import main
from ._jobs import jobs
now = time.strftime('%H:%M')
messages = [
{
'phone': '+44 7700 900 579',
'message': 'Vehicle tax: Your vehicle tax for LV75 TDG expires on 18 January 2016. Renew at www.gov.uk/vehicletax', # noqa
'status': 'Delivered',
'time': now,
'id': '0'
},
{
'phone': '+44 7700 900 306',
'message': 'Vehicle tax: Your vehicle tax for PL53 GBD expires on 18 January 2016. Renew at www.gov.uk/vehicletax', # noqa
'status': 'Delivered',
'time': now,
'id': '1'
},
{
'phone': '+44 7700 900 454',
'message': 'Vehicle tax: Your vehicle tax for LV75 TDG expires on 18 January 2016. Renew at www.gov.uk/vehicletax', # noqa
'status': 'Delivered',
'time': now,
'id': '2'
},
{
'phone': '+44 7700 900 522',
'message': 'Vehicle tax: Your vehicle tax for RE67 PLM expires on 18 January 2016. Renew at www.gov.uk/vehicletax', # noqa
'status': 'Failed',
'time': now,
'id': '3'
}
]
@main.route("/services/<int:service_id>/jobs")
@login_required
def view_jobs(service_id):
return render_template(
'views/jobs.html',
jobs=[], # use `jobs` for placeholder data
service_id=service_id
)
try:
jobs = job_api_client.get_job(service_id)['data']
return render_template(
'views/jobs.html',
jobs=jobs,
service_id=service_id
)
except HTTPError as e:
if e.status_code == 404:
abort(404)
else:
raise e
@main.route("/services/<int:service_id>/jobs/<job_id>")
@login_required
def view_job(service_id, job_id):
# TODO the uploaded file name could be part of job definition
# so won't need to be passed on from last view via session
uploaded_file_name = session.get(job_id)
return render_template(
'views/job.html',
messages=messages,
counts={
'total': len(messages),
'delivered': len([
message for message in messages if message['status'] == 'Delivered'
]),
'failed': len([
message for message in messages if message['status'] == 'Failed'
])
},
cost=u'£0.00',
uploaded_file_name=uploaded_file_name,
uploaded_file_time=now,
template_used='Test message 1',
flash_message=u'Weve started sending your messages',
service_id=service_id
)
try:
job = job_api_client.get_job(service_id, job_id)['data']
messages = []
return render_template(
'views/job.html',
messages=messages,
counts={
'total': len(messages),
'delivered': len([
message for message in messages if message['status'] == 'Delivered'
]),
'failed': len([
message for message in messages if message['status'] == 'Failed'
])
},
cost=u'£0.00',
uploaded_file_name=job['original_file_name'],
uploaded_file_time=job['created_at'],
template_used=job['template'],
flash_message="Weve accepted {} for processing".format(job['original_file_name']),
service_id=service_id
)
except HTTPError as e:
if e.status_code == 404:
abort(404)
else:
raise e
@main.route("/services/<int:service_id>/jobs/<job_id>/notification/<string:notification_id>")

View File

@@ -1,5 +1,6 @@
import csv
import re
import uuid
from datetime import date
@@ -34,7 +35,8 @@ def send_sms(service_id):
try:
csv_file = form.file.data
filedata = _get_filedata(csv_file)
upload_id = s3upload(service_id, filedata)
upload_id = str(uuid.uuid4())
s3upload(upload_id, service_id, filedata)
return redirect(url_for('.check_sms',
service_id=service_id,
upload_id=upload_id,
@@ -85,7 +87,7 @@ def check_sms(service_id, upload_id):
# that will be done in another story
template_id = 1
job_api_client.create_job(service_id, template_id, file_name)
job_api_client.create_job(upload_id, service_id, template_id, file_name)
return redirect(url_for('main.view_job',
service_id=service_id,
job_id=upload_id))

View File

@@ -14,8 +14,13 @@ class JobApiClient(BaseAPIClient):
self.client_id = app.config['ADMIN_CLIENT_USER_NAME']
self.secret = app.config['ADMIN_CLIENT_SECRET']
def create_job(self, service_id, template_id, file_name):
job_id = str(uuid.uuid4())
def get_job(self, service_id, job_id=None):
if job_id:
return self.get(url='/service/{}/job/{}'.format(service_id, job_id))
else:
return self.get(url='/service/{}/job'.format(service_id))
def create_job(self, job_id, service_id, template_id, file_name):
data = {
"id": job_id,
"service": service_id,

View File

@@ -38,7 +38,7 @@ GOV.UK Notify | Notifications activity
</ul>
<p>
Sent with template <a href="{{ url_for('.edit_service_template', service_id=service_id, template_id=1) }}">{{ template_used }}</a> at {{ uploaded_file_time }}
Sent with template <a href="{{ url_for('.edit_service_template', service_id=service_id, template_id=1) }}">{{ template_used }}</a> on {{ uploaded_file_time | format_datetime}}
</p>
{% call(item) list_table(

View File

@@ -17,13 +17,13 @@ GOV.UK Notify | Notifications activity
field_headings=['Job', 'File', 'Time', 'Status']
) %}
{% call field() %}
<a href="{{ url_for('.view_job', service_id=service_id, job_id=456) }}">{{ item.file }}</a>
<a href="{{ url_for('.view_job', service_id=service_id, job_id=item.id) }}">{{ item.id }}</a>
{% endcall %}
{% call field() %}
<a href="{{ url_for('.view_job', service_id=service_id, job_id=456) }}">{{ item.job }}</a>
<a href="{{ url_for('.view_job', service_id=service_id, job_id=item.id) }}">{{ item.original_file_name }}</a>
{% endcall %}
{% call field() %}
{{ item.time }}
{{ item.created_at | format_datetime}}
{% endcall %}
{% call field() %}
{{ item.status }}

View File

@@ -4,3 +4,4 @@ pytest==2.8.1
pytest-mock==0.8.1
moto==0.4.19
httpretty==0.8.10
beautifulsoup4==4.4.1

View File

@@ -80,3 +80,21 @@ def create_another_test_user(state):
def get_test_user():
from app.main.dao import users_dao
return users_dao.get_user_by_email(TEST_USER_EMAIL)
def job_json():
import uuid
import datetime
uuid.uuid4()
job_id = str(uuid.uuid4())
created_at = str(datetime.datetime.now().time())
data = {
'id': str(job_id),
'service': 1,
'template': 1,
'original_file_name': 'thisisatest.csv',
'bucket_name': 'service-1-{}-notify'.format(job_id),
'file_name': '{}.csv'.format(job_id),
'created_at': created_at
}
return data

View File

@@ -1,4 +1,5 @@
from flask import url_for
from bs4 import BeautifulSoup
def test_should_return_list_of_all_jobs(app_,
@@ -6,14 +7,18 @@ def test_should_return_list_of_all_jobs(app_,
api_user_active,
mock_get_user,
mock_get_user_by_email,
mock_login):
mock_login,
mock_get_jobs):
with app_.test_request_context():
with app_.test_client() as client:
client.login(api_user_active)
response = client.get(url_for('main.view_jobs', service_id=101))
assert response.status_code == 200
assert 'You havent sent any notifications yet' in response.get_data(as_text=True)
page = BeautifulSoup(response.data.decode('utf-8'), 'html.parser')
assert page.h1.string == 'Notifications activity'
jobs = page.tbody.find_all('tr')
assert len(jobs) == 5
def test_should_show_page_for_one_job(app_,
@@ -21,35 +26,17 @@ def test_should_show_page_for_one_job(app_,
api_user_active,
mock_login,
mock_get_user,
mock_get_user_by_email):
with app_.test_request_context():
with app_.test_client() as client:
# TODO filename will be part of job metadata not in session
with client.session_transaction() as s:
s[456] = 'dispatch_20151114.csv'
client.login(api_user_active)
response = client.get(url_for('main.view_job', service_id=123, job_id=456))
mock_get_user_by_email,
job_data,
mock_get_job):
service_id = job_data['service']
job_id = job_data['id']
file_name = job_data['original_file_name']
assert response.status_code == 200
assert 'dispatch_20151114.csv' in response.get_data(as_text=True)
assert 'Test message 1' in response.get_data(as_text=True)
def test_should_show_page_for_one_notification(app_,
service_one,
api_user_active,
mock_get_user,
mock_get_user_by_email,
mock_login):
with app_.test_request_context():
with app_.test_client() as client:
client.login(api_user_active)
response = client.get(url_for(
'main.view_notification',
service_id=101,
job_id=123,
notification_id=3))
response = client.get(url_for('main.view_job', service_id=service_id, job_id=job_id))
assert response.status_code == 200
assert 'Text message' in response.get_data(as_text=True)
assert '+44 7700 900 522' in response.get_data(as_text=True)
assert file_name in response.get_data(as_text=True)

View File

@@ -124,10 +124,12 @@ def test_create_job_should_call_api(app_,
mock_get_user_by_email,
mock_login,
job_data,
mock_create_job):
mock_create_job,
mock_get_job):
import uuid
service_id = service_one['id']
job_id = job_data['id']
job_id = str(uuid.uuid4())
file_name = job_data['file_name']
# TODO - template id should come from form but is not wired in yet.
@@ -141,5 +143,5 @@ def test_create_job_should_call_api(app_,
response = client.post(url, data=job_data, follow_redirects=True)
assert response.status_code == 200
mock_create_job.assert_called_with(service_id, template_id, file_name)
mock_create_job.assert_called_with(job_id, service_id, template_id, file_name)
assert job_data['bucket_name'] == "service-{}-{}-notify".format(service_id, job_id)

View File

@@ -1,17 +1,16 @@
import os
from datetime import date
import pytest
from alembic.command import upgrade
from alembic.config import Config
from flask.ext.migrate import Migrate, MigrateCommand
from flask.ext.script import Manager
from sqlalchemy.schema import MetaData
from app import create_app
from . import (
create_test_user, service_json, TestClient,
get_test_user, template_json, api_key_json)
service_json,
TestClient,
template_json,
api_key_json,
job_json
)
@pytest.fixture(scope='session')
@@ -422,24 +421,41 @@ def mock_check_verify_code_code_expired(mocker):
@pytest.fixture(scope='function')
def job_data(mocker):
import uuid
job_id = uuid.uuid4()
file_name = 'thisisatest.csv'
data = {
'id': str(job_id),
'file_name': file_name,
}
return data
def job_data():
return job_json()
@pytest.fixture(scope='function')
def mock_create_job(mocker, job_data):
def _create(service_id, template_id, file_name):
def _create(job_id, service_id, template_id, file_name):
job_data['id'] = job_id
job_data['service'] = service_id
job_data['template'] = template_id
job_data['bucket_name'] = 'service-{}-{}-notify'.format(service_id, job_data['id'])
job_data['bucket_name'] = 'service-{}-{}-notify'.format(service_id, job_id)
job_data['original_file_name'] = file_name
job_data['file_name'] = '{}.csv'.format(job_data['id'])
job_data['file_name'] = '{}.csv'.format(job_id)
return job_data
return mocker.patch('app.job_api_client.create_job', side_effect=_create)
@pytest.fixture(scope='function')
def mock_get_job(mocker, job_data):
def _get_job(service_id, job_id):
job_data['id'] = job_id
job_data['service'] = service_id
return {"data": job_data}
return mocker.patch('app.job_api_client.get_job', side_effect=_get_job)
@pytest.fixture(scope='function')
def mock_get_jobs(mocker):
def _get_jobs(service_id):
import uuid
data = []
for i in range(5):
job_data = job_json()
job_data['id'] = str(uuid.uuid4())
job_data['service'] = service_id
data.append(job_data)
return {"data": data}
return mocker.patch('app.job_api_client.get_job', side_effect=_get_jobs)