mirror of
https://github.com/GSA/notifications-admin.git
synced 2026-02-04 18:32:33 -05:00
List and individual job pages now fetch data from api.
Few bug fixes around job uuid.
This commit is contained in:
@@ -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):
|
||||
|
||||
@@ -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'We’ve 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="We’ve 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>")
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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 }}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 haven’t 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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user