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 from boto3 import resource
def s3upload(service_id, filedata): def s3upload(upload_id, service_id, filedata):
upload_id = str(uuid.uuid4())
s3 = resource('s3') s3 = resource('s3')
bucket_name = 'service-{}-{}-notify'.format(service_id, upload_id) bucket_name = 'service-{}-{}-notify'.format(service_id, upload_id)
s3.create_bucket(Bucket=bucket_name) s3.create_bucket(Bucket=bucket_name)
contents = '\n'.join(filedata['data']) contents = '\n'.join(filedata['data'])
key = s3.Object(bucket_name, upload_id) key = s3.Object(bucket_name, upload_id)
key.put(Body=contents, ServerSideEncryption='AES256') key.put(Body=contents, ServerSideEncryption='AES256')
return upload_id
def s3download(service_id, upload_id): def s3download(service_id, upload_id):

View File

@@ -4,84 +4,64 @@ import time
from flask import ( from flask import (
render_template, render_template,
session abort
) )
from flask_login import login_required from flask_login import login_required
from client.errors import HTTPError
from app import job_api_client
from app.main import main from app.main import main
from ._jobs import jobs
now = time.strftime('%H:%M') 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") @main.route("/services/<int:service_id>/jobs")
@login_required @login_required
def view_jobs(service_id): def view_jobs(service_id):
return render_template( try:
'views/jobs.html', jobs = job_api_client.get_job(service_id)['data']
jobs=[], # use `jobs` for placeholder data return render_template(
service_id=service_id '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>") @main.route("/services/<int:service_id>/jobs/<job_id>")
@login_required @login_required
def view_job(service_id, job_id): def view_job(service_id, job_id):
try:
# TODO the uploaded file name could be part of job definition job = job_api_client.get_job(service_id, job_id)['data']
# so won't need to be passed on from last view via session messages = []
uploaded_file_name = session.get(job_id) return render_template(
'views/job.html',
return render_template( messages=messages,
'views/job.html', counts={
messages=messages, 'total': len(messages),
counts={ 'delivered': len([
'total': len(messages), message for message in messages if message['status'] == 'Delivered'
'delivered': len([ ]),
message for message in messages if message['status'] == 'Delivered' 'failed': len([
]), message for message in messages if message['status'] == 'Failed'
'failed': len([ ])
message for message in messages if message['status'] == 'Failed' },
]) cost=u'£0.00',
}, uploaded_file_name=job['original_file_name'],
cost=u'£0.00', uploaded_file_time=job['created_at'],
uploaded_file_name=uploaded_file_name, template_used=job['template'],
uploaded_file_time=now, flash_message="Weve accepted {} for processing".format(job['original_file_name']),
template_used='Test message 1', service_id=service_id
flash_message=u'Weve started sending your messages', )
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>") @main.route("/services/<int:service_id>/jobs/<job_id>/notification/<string:notification_id>")

View File

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

View File

@@ -14,8 +14,13 @@ class JobApiClient(BaseAPIClient):
self.client_id = app.config['ADMIN_CLIENT_USER_NAME'] self.client_id = app.config['ADMIN_CLIENT_USER_NAME']
self.secret = app.config['ADMIN_CLIENT_SECRET'] self.secret = app.config['ADMIN_CLIENT_SECRET']
def create_job(self, service_id, template_id, file_name): def get_job(self, service_id, job_id=None):
job_id = str(uuid.uuid4()) 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 = { data = {
"id": job_id, "id": job_id,
"service": service_id, "service": service_id,

View File

@@ -38,7 +38,7 @@ GOV.UK Notify | Notifications activity
</ul> </ul>
<p> <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> </p>
{% call(item) list_table( {% call(item) list_table(

View File

@@ -17,13 +17,13 @@ GOV.UK Notify | Notifications activity
field_headings=['Job', 'File', 'Time', 'Status'] field_headings=['Job', 'File', 'Time', 'Status']
) %} ) %}
{% call field() %} {% 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 %} {% endcall %}
{% call field() %} {% 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 %} {% endcall %}
{% call field() %} {% call field() %}
{{ item.time }} {{ item.created_at | format_datetime}}
{% endcall %} {% endcall %}
{% call field() %} {% call field() %}
{{ item.status }} {{ item.status }}

View File

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

View File

@@ -80,3 +80,21 @@ def create_another_test_user(state):
def get_test_user(): def get_test_user():
from app.main.dao import users_dao from app.main.dao import users_dao
return users_dao.get_user_by_email(TEST_USER_EMAIL) 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 flask import url_for
from bs4 import BeautifulSoup
def test_should_return_list_of_all_jobs(app_, 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, api_user_active,
mock_get_user, mock_get_user,
mock_get_user_by_email, mock_get_user_by_email,
mock_login): mock_login,
mock_get_jobs):
with app_.test_request_context(): with app_.test_request_context():
with app_.test_client() as client: with app_.test_client() as client:
client.login(api_user_active) client.login(api_user_active)
response = client.get(url_for('main.view_jobs', service_id=101)) response = client.get(url_for('main.view_jobs', service_id=101))
assert response.status_code == 200 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_, 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, api_user_active,
mock_login, mock_login,
mock_get_user, mock_get_user,
mock_get_user_by_email): mock_get_user_by_email,
with app_.test_request_context(): job_data,
with app_.test_client() as client: mock_get_job):
# TODO filename will be part of job metadata not in session service_id = job_data['service']
with client.session_transaction() as s: job_id = job_data['id']
s[456] = 'dispatch_20151114.csv' file_name = job_data['original_file_name']
client.login(api_user_active)
response = client.get(url_for('main.view_job', service_id=123, job_id=456))
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_request_context():
with app_.test_client() as client: with app_.test_client() as client:
client.login(api_user_active) client.login(api_user_active)
response = client.get(url_for( response = client.get(url_for('main.view_job', service_id=service_id, job_id=job_id))
'main.view_notification',
service_id=101,
job_id=123,
notification_id=3))
assert response.status_code == 200 assert response.status_code == 200
assert 'Text message' in response.get_data(as_text=True) assert file_name in response.get_data(as_text=True)
assert '+44 7700 900 522' 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_get_user_by_email,
mock_login, mock_login,
job_data, job_data,
mock_create_job): mock_create_job,
mock_get_job):
import uuid
service_id = service_one['id'] service_id = service_one['id']
job_id = job_data['id'] job_id = str(uuid.uuid4())
file_name = job_data['file_name'] file_name = job_data['file_name']
# TODO - template id should come from form but is not wired in yet. # 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) response = client.post(url, data=job_data, follow_redirects=True)
assert response.status_code == 200 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) assert job_data['bucket_name'] == "service-{}-{}-notify".format(service_id, job_id)

View File

@@ -1,17 +1,16 @@
import os import os
from datetime import date from datetime import date
import pytest 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 app import create_app
from . import ( from . import (
create_test_user, service_json, TestClient, service_json,
get_test_user, template_json, api_key_json) TestClient,
template_json,
api_key_json,
job_json
)
@pytest.fixture(scope='session') @pytest.fixture(scope='session')
@@ -422,24 +421,41 @@ def mock_check_verify_code_code_expired(mocker):
@pytest.fixture(scope='function') @pytest.fixture(scope='function')
def job_data(mocker): def job_data():
import uuid return job_json()
job_id = uuid.uuid4()
file_name = 'thisisatest.csv'
data = {
'id': str(job_id),
'file_name': file_name,
}
return data
@pytest.fixture(scope='function') @pytest.fixture(scope='function')
def mock_create_job(mocker, job_data): 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['service'] = service_id
job_data['template'] = template_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['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 job_data
return mocker.patch('app.job_api_client.create_job', side_effect=_create) 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)