Added Imported Files Page

This commit is contained in:
Nile Walker 2021-01-11 10:43:36 -05:00
parent 46ddf269e1
commit 9c7df39fe8
14 changed files with 237 additions and 187 deletions

View File

@ -161,9 +161,8 @@ def index():
graph = GraphService()
if request.method == "POST": session["index_filter"] = {} # Clear out the session if it is invalid.
if "index_filter" not in session: session["index_filter"] = {}
if form.validate():
session["index_filter"] = {}
if form.dateRange.data:
start, end = form.dateRange.data.split("-")
session["index_filter"]["start_date"] = datetime.strptime(start.strip(), "%m/%d/%Y").date()
@ -176,7 +175,13 @@ def index():
session["index_filter"]["compute_id"] = form.compute_id.data
if form.include_tests.data:
session["index_filter"]["include_tests"] = form.include_tests.data
graph.update_search_filters(session["index_filter"])
if type(session["index_filter"]["start_date"]) == str:
session["index_filter"]["start_date"] = datetime.strptime(session["index_filter"]["start_date"].strip(), "%Y-%m-%d").date()
if type(session["index_filter"]["end_date"]) == str:
session["index_filter"]["end_date"] = datetime.strptime(session["index_filter"]["end_date"].strip(), "%Y-%m-%d").date()
graph.update_search_filters(session["index_filter"])
samples = db.session.query(Sample).order_by(Sample.date.desc())
filtered_samples = graph.apply_filters(samples)
@ -189,21 +194,14 @@ def index():
"hourly":{},
"weekday":{}
}
important_dates = {}
overall_totals_data = {
"one_week_ago":0,
"two_week_ago":0,
"search":0,
}
location_stats_data = {}
chart_ticks = []
timeFormat = "%m/%d"
# Count by Day
bounds = daterange(graph.start_date, graph.end_date, days=1, hours=0)
for i in range(len(bounds) - 1):
chart_ticks.append(f"{bounds[i].strftime(timeFormat)}")
@ -236,7 +234,6 @@ def index():
table = SampleTable(group_columns(filtered_samples[(page - 1) * 10:((page - 1) * 10) + 10]))
return render_template('layouts/default.html',
base_href=BASE_HREF,
content=render_template(
@ -354,15 +351,17 @@ def list_imported_files_from_ivy():
page = request.args.get(get_page_parameter(), type=int, default=1)
files = db.session.query(IvyFile).order_by(IvyFile.date_added.desc())
pagination = Pagination(page=page, total=files.count(),
search=False, record_name='samples')
search=False, record_name='samples', css_framework='bootstrap4')
table = IvyFileTable(files.paginate(page, 10, error_out=False).items)
return render_template(
'imported_files.html',
table=table,
pagination=pagination,
base_href=BASE_HREF
)
return render_template('layouts/default.html',
base_href=BASE_HREF,
content=render_template(
'pages/imported_files.html',
table=table,
pagination=pagination,
base_href=BASE_HREF
))
@app.route('/sso')

View File

@ -16,7 +16,7 @@ class InvitationForm(FlaskForm):
def validate_emails(form, field):
all_emails = field.data.splitlines()
EMAIL_REGEX = re.compile('^[a-z0-9]+[._a-z0-9]+[@]\w+[.]\w{2,3}$')
EMAIL_REGEX = re.compile(r'^[a-z0-9]+[._a-z0-9]+[@]\w+[.]\w{2,3}$')
for email in all_emails:
if not re.search(EMAIL_REGEX, email):
raise ValidationError(f'Invalid email \'{email}\', Emails must each be on a seperate line.')

View File

@ -10,17 +10,20 @@ import datetime as dt
from sqlalchemy import func, and_, case
def dow_count(start, end):
# Sunday, Monday, ...
counts = [0 for _ in range(7)]
curr = start
curr = start
while curr <= end:
counts[(1 + curr.weekday()) % 7] += 1
curr += dt.timedelta(1)
curr += dt.timedelta(1)
return counts
def date2datetime(_date):
return dt.datetime.combine(_date, dt.datetime.min.time())
def daterange(start, stop, days = 1, hours = 0):
def daterange(start, stop, days=1, hours=0):
if (type(start) == dt.date):
start = date2datetime(start)
if (type(stop) == dt.date):
@ -29,41 +32,44 @@ def daterange(start, stop, days = 1, hours = 0):
date_list = []
while time <= stop:
date_list.append(time)
time += dt.timedelta(days=days,hours=hours)
time += dt.timedelta(days=days, hours=hours)
return date_list
class GraphService(object):
def __init__(self):
self.filters = dict()
self.filters["start_date"] = Sample.date >= dt.date.today()
self.start_date = dt.date.today()
self.filters["end_date"] = Sample.date <= dt.date.today() + dt.timedelta(1)
self.filters["end_date"] = Sample.date <= dt.date.today() + \
dt.timedelta(1)
self.end_date = dt.date.today() + dt.timedelta(1)
def apply_filters(self, query, ignore_dates = False):
def apply_filters(self, query, ignore_dates=False):
for key in self.filters:
if ignore_dates and "date" in key:
continue
query = query.filter(self.filters[key])
return query
"""Handles the collection and syncing of data from various sources. """
def get_totals_last_week(self):
location_stats_data = dict()
# Count by range
cases = [func.count(case([(and_(Sample.date >= self.start_date - dt.timedelta(14), Sample.date <= self.end_date - dt.timedelta(14)), 1)])),
func.count(case([(and_(Sample.date >= self.start_date - dt.timedelta(7), Sample.date <= self.end_date - dt.timedelta(7)), 1)])),
func.count(case([(and_(Sample.date >= self.start_date, Sample.date <= self.end_date), 1)]))]
func.count(case([(and_(Sample.date >= self.start_date - dt.timedelta(
7), Sample.date <= self.end_date - dt.timedelta(7)), 1)])),
func.count(case([(and_(Sample.date >= self.start_date, Sample.date <= self.end_date), 1)]))]
q = db.session.query(Sample.location,
*cases\
).group_by(Sample.location)
*cases
).group_by(Sample.location)
q = self.apply_filters(q, ignore_dates=True)
for result in q:
location = result[0]
if location not in location_stats_data: location_stats_data[location] = dict()
if location not in location_stats_data:
location_stats_data[location] = dict()
location_stats_data[location]["two_week_ago"] = result[1]
location_stats_data[location]["one_week_ago"] = result[2]
location_stats_data[location]["search"] = result[3]
@ -72,84 +78,102 @@ class GraphService(object):
def get_totals_by_hour(self):
hourly_charts_data = dict()
days_in_search = (self.end_date - self.start_date).days
cases = [ ]
cases = []
for i in range(24):
cases.append(func.count(case([(func.extract('hour', Sample.date) == i, 1)])))
cases.append(func.count(
case([(func.extract('hour', Sample.date) == i, 1)])))
q = db.session.query(Sample.location, Sample.station,
*cases\
).group_by(Sample.location, Sample.station)
*cases
).group_by(Sample.location, Sample.station)
q = self.apply_filters(q)
for result in q:
location, station = result[0], result[1]
if location not in hourly_charts_data: hourly_charts_data[location] = dict()
# Here I'm accounting for the difference in UTC and GMT time zones
# by moving the five results from the start to the end.
offset = 6
if location not in hourly_charts_data:
hourly_charts_data[location] = dict()
# Here I'm accounting for the difference in UTC and GMT time zones
# by moving the five results from the start to the end.
offset = 6
counts = result[2:]
counts = counts[offset:] + counts[:offset]
hourly_charts_data[location][station] = [round(i/days_in_search + .4) for i in counts]
hourly_charts_data[location][station] = [
round(i/days_in_search + .4) for i in counts]
return hourly_charts_data
def get_totals_by_day(self):
daily_charts_data = dict()
bounds = daterange(self.start_date, self.end_date, days=1, hours=0)
cases = [ ]
cases = []
for i in range(len(bounds) - 1):
cases.append(func.count(case([(and_(Sample.date >= bounds[i], Sample.date <= bounds[i+1]), 1)])))
cases.append(func.count(
case([(and_(Sample.date >= bounds[i], Sample.date <= bounds[i+1]), 1)])))
q = db.session.query(Sample.location, Sample.station,
*cases\
).group_by(Sample.location, Sample.station)
*cases
).group_by(Sample.location, Sample.station)
q = self.apply_filters(q)
for result in q:
location, station = result[0], result[1]
if location not in daily_charts_data: daily_charts_data[location] = dict()
if location not in daily_charts_data:
daily_charts_data[location] = dict()
daily_charts_data[location][station] = result[2:]
return daily_charts_data
def get_totals_by_weekday(self):
weekday_charts_data = dict()
dow_counts = dow_count(self.start_date, self.end_date - dt.timedelta(1))
cases = [ ]
dow_counts = dow_count(
self.start_date, self.end_date - dt.timedelta(1))
cases = []
for i in range(7):
cases.append(func.count(case([(func.extract('dow', Sample.date) == i, 1)])))
cases.append(func.count(
case([(func.extract('dow', Sample.date) == i, 1)])))
q = db.session.query(Sample.location, Sample.station,
*cases\
).group_by(Sample.location, Sample.station)
*cases
).group_by(Sample.location, Sample.station)
q = self.apply_filters(q)
for result in q:
location, station = result[0], result[1]
if location not in weekday_charts_data: weekday_charts_data[location] = dict()
if location not in weekday_charts_data:
weekday_charts_data[location] = dict()
weekday_charts_data[location][station] = []
for dow, total in zip(range(7),result[2:]):
for dow, total in zip(range(7), result[2:]):
if dow_counts[dow] > 0:
weekday_charts_data[location][station].append(round(total/dow_counts[dow] + .4))
weekday_charts_data[location][station].append(
round(total/dow_counts[dow] + .4))
else:
weekday_charts_data[location][station].append(total)
return weekday_charts_data
def update_search_filters(self, filters):
try:
if "student_id" in filters: self.filters["student_id"] = Sample.student_id.in_(filters["student_id"].split())
if "location" in filters: self.filters["location"] = Sample.location.in_(filters["location"].split())
if "station" in filters: self.filters["station"] = Sample.station.in_(filters["station"].split())
if "compute_id" in filters: self.filters["compute_id"] = Sample.computing_id.in_(filters["compute_id"].split())
if "start_date" in filters:
if "student_id" in filters:
self.filters["student_id"] = Sample.student_id.in_(
filters["student_id"].split())
if "location" in filters:
self.filters["location"] = Sample.location.in_(
filters["location"].split())
if "station" in filters:
self.filters["station"] = Sample.station.in_(
filters["station"].split())
if "compute_id" in filters:
self.filters["compute_id"] = Sample.computing_id.in_(
filters["compute_id"].split())
if "start_date" in filters:
self.filters["start_date"] = Sample.date >= filters["start_date"]
self.start_date = filters["start_date"]
if "end_date" in filters:
self.filters["end_date"] = Sample.date <= filters["end_date"]
self.end_date = filters["end_date"]
if not "include_tests" in filters:
if "end_date" in filters:
self.filters["end_date"] = Sample.date <= filters["end_date"]
self.end_date = filters["end_date"]
if not "include_tests" in filters:
self.filters["include_tests"] = Sample.student_id != 0
else:
del self.filters["include_tests"]
del self.filters["include_tests"]
except Exception as e:
logging.error(

View File

@ -45,12 +45,14 @@ class SampleTable(Table):
class IvyFileTable(Table):
def sort_url(self, col_id, reverse=False):
pass
classes = ["table","align-items-center","table-flush"]
file_name = Col('File Name')
date_added = BetterDatetimeCol('Date', "medium", tzinfo=get_timezone('US/Eastern'), locale='en')
sample_count = Col('Total Records')
class InvitationTable(Table):
classes = ["table","align-items-center","table-flush"]
def sort_url(self, col_id, reverse=False):
pass
date_sent = BetterDatetimeCol('Date Sent', "medium", tzinfo=get_timezone('US/Eastern'), locale='en')

View File

@ -25,8 +25,15 @@
<a class="nav-link" href="/">
<em class="ni ni-tv-2 text-primary"></em> Dashboard
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/imported_files">
<em class="ni ni-tv-2 text-primary"></em> Imported Files
</a>
</li>
</ul>
<!-- Divider -->
<hr class="my-3">
<!-- Heading -->

View File

@ -2,14 +2,15 @@
<div class="container-fluid">
<div class="header-body">
<!-- Card stats -->
{% if dates %}
<div class="row">
<div class="col-xl-3 col-lg-6">
<div class="card card-stats mb-4 mb-xl-0">
<div class="card-body">
<div class="row">
<div class="col">
<h5 class="card-title text-uppercase text-muted mb-0">Total Samples within {{dates.search}}</h5>
<span id="stats_today" class="h2 font-weight-bold mb-0">{{overall_totals_data.search}}</span>
<h5 class="card-title text-uppercase text-muted mb-0">Total Samples within {{dates.search | safe }}</h5>
<span id="stats_today" class="h2 font-weight-bold mb-0">{{overall_totals_data.search| safe }}</span>
</div>
<div class="col-auto">
@ -26,9 +27,9 @@
<div class="card-body">
<div class="row">
<div class="col">
<h5 class="card-title text-uppercase text-muted mb-0">(1 Week Back) {{dates.one_week_ago}}</h5>
<h5 class="card-title text-uppercase text-muted mb-0">(1 Week Back) {{dates.one_week_ago| safe }}</h5>
<span id="stats_one_week" class="h2 font-weight-bold mb-0">{{overall_totals_data.one_week_ago}}</span>
<span id="stats_one_week" class="h2 font-weight-bold mb-0">{{overall_totals_data.one_week_ago| safe }}</span>
</div>
<div class="col-auto">
@ -45,10 +46,10 @@
<div class="card-body">
<div class="row">
<div class="col">
<h5 class="card-title text-uppercase text-muted mb-0">(2 Weeks Back) {{dates.two_weeks_ago}}
<h5 class="card-title text-uppercase text-muted mb-0">(2 Weeks Back) {{dates.two_weeks_ago| safe }}
</h5>
<span id="stats_two_weeks" class="h2 font-weight-bold mb-0">{{overall_totals_data.two_week_ago}}</span>
<span id="stats_two_weeks" class="h2 font-weight-bold mb-0">{{overall_totals_data.two_week_ago| safe }}</span>
</div>
<div class="col-auto">
@ -61,6 +62,7 @@
</div>
</div>
</div>
{% endif %}
</div>
</div>
</div>

View File

@ -17,8 +17,20 @@
<body>
{% include 'includes/sidenav.html' %}
<div class="main-content">
<!-- Top navbar -->
<nav class="navbar navbar-top navbar-expand-md navbar-dark" id="navbar-main">
<div class="container-fluid">
<!-- Brand -->
<a class="h4 mb-0 text-white text-uppercase d-none d-lg-inline-block" href="./index.html">UVA Communicator
Dashboard</a>
</div>
</nav>
{{ content | safe }}
</div>
<!-- % include 'includes/footer.html' % -->
</body>

View File

@ -1,25 +1,24 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>UVA Be Safe Communicator</title>
<base href="/">
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<link rel="stylesheet" href="https://use.typekit.net/kwp6dli.css">
<link rel="shortcut icon" href="{{ base_href + url_for('static', filename='favicon.ico') }}">
{% assets 'app_scss' %}
<link href="{{ base_href + ASSET_URL }}" rel="stylesheet" type="text/css">
{% endassets %}
<link rel="shortcut icon" href="{{ base_href + url_for('static', filename='favicon.ico') }}">
</head>
<body>
<a href="{{base_href}}"><< Home</a>
{% include 'includes/top-stats.html' %}
<div class="container-fluid mt--7">
<div class="row mt-4">
<div class="col mb-5 mb-xl-0">
<div class="card shadow">
<div class="card-header border-0">
<div class="row align-items-center">
<div class="col">
<h3 class="mb-0">The following files were imported from IVY</h3>{{ pagination.info }}
</div>
</div>
</div>
<h2>UVA Be Safe Communicator</h2>
<h3>The following files were imported from IVY</h3>
{{ pagination.info }}
{{ pagination.links }}
{{ table }}
{{ pagination.links }}
</body>
</html>
<div class="table-responsive">
<!-- Projects table -->
{{ table }}
</div>
<div class="row justify-content-center">
{{ pagination.links }}
</div>
</div>
</div>
</div>
</div>

View File

@ -1,16 +1,3 @@
<!-- Main content -->
<div class="main-content">
<!-- Top navbar -->
<nav class="navbar navbar-top navbar-expand-md navbar-dark" id="navbar-main">
<div class="container-fluid">
<!-- Brand -->
<a class="h4 mb-0 text-white text-uppercase d-none d-lg-inline-block" href="./index.html">UVA Communicator
Dashboard</a>
</div>
</nav>
<!-- Header -->
{% include 'includes/top-stats.html' %}
@ -123,7 +110,7 @@
<div class="card-header border-0">
<div class="row align-items-center">
<div class="col">
<h3 class="mb-0">Records to be processed</h3>
<h3 class="mb-0">Records to be processed</h3>{{pagination.info}}
</div>
<div class="col text-right">
<a href="{{ url_for('index') }}?download=true" class="btn btn-sm btn-primary">Download all</a>
@ -144,7 +131,6 @@
</div>
</div>
</div>
</div>
</form>

View File

@ -1,43 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>UVA Be Safe Communicator</title>
<base href="/">
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<link rel="stylesheet" href="https://use.typekit.net/kwp6dli.css">
<link rel="shortcut icon" href="{{ base_href + url_for('static', filename='favicon.ico') }}">
{% assets 'app_scss' %}
<link href="{{ base_href + ASSET_URL }}" rel="stylesheet" type="text/css">
{% endassets %}
<link rel="shortcut icon" href="{{ base_href + url_for('static', filename='favicon.ico') }}">
</head>
<body>
<h2>UVA Communicator Be Safe </h2>
<a href="{{base_href + '/invitation'}}">Send Invitations</a> | <a href="{{base_href + '/imported_files'}}">View imported files</a>
<h3>Records to be processed</h3>
{{ pagination.info }}
{{ pagination.links }}
{{ table }}
{{ pagination.links }}
<form action="{{ action }}" method="post">
{{ form.csrf_token() }}
{% for field in form if field.name != "csrf_token" %}
<div class="form-field {{ field.widget.input_type }}">
<div class="form-field-label">{{ field.label() }}:</div>
<div class="form-field-input">{{ field }}</div>
<div class="form-field-help">{{ description_map[field.name] }}</div>
{% for error in field.errors %}
<div class="form-field-error">{{ error }}</div>
{% endfor %}
</div>
{% endfor %}
<button class="btn btn-primary" type="submit">Submit</button>
<a href="{{ url_for('index') }}?cancel=true" class="btn btn-default">Cancel</a>
</form>
</body>
</html>

View File

@ -0,0 +1,62 @@
import datetime
import pytz
from tests.base_test import BaseTest
from communicator import app
from communicator.models import Sample
from communicator.services.graph_service import GraphService
class TestGraphService(BaseTest):
def test_get_totals_last_week(self):
graph = GraphService()
graph.update_search_filters({
"start_date": datetime.date(2020,11,1),
"end_date": datetime.date(2020,11,1),
})
result = graph.get_totals_last_week()
for location in result:
for station in location:
self.assertEqual(result[location][station], 0)
def test_get_totals_by_hour(self):
graph = GraphService()
graph.update_search_filters({
"start_date": datetime.date(2020,11,1),
"end_date": datetime.date(2020,11,1),
})
result = graph.get_totals_by_hour()
for location in result:
for station in location:
self.assertEqual(result[location][station], 0)
def test_get_totals_by_day(self):
graph = GraphService()
graph.update_search_filters({
"start_date": datetime.date(2020,11,1),
"end_date": datetime.date(2020,11,1),
})
result = graph.get_totals_by_day()
for location in result:
for station in location:
self.assertEqual(result[location][station], 0)
def test_get_totals_by_weekday(self):
graph = GraphService()
graph.update_search_filters({
"start_date": datetime.date(2020,11,1),
"end_date": datetime.date(2020,11,14),
"location": "50"
})
result = graph.get_totals_by_weekday()
self.assertEqual(result[50][00][1],17)
self.assertEqual(result[50][10][1],16)
self.assertEqual(result[50][20][1],14)
self.assertEqual(result[50][30][1],17)
self.assertEqual(result[50][40][1],20)
self.assertEqual(result[50][50][1],14)

View File

@ -3,10 +3,10 @@ import os
import unittest
import globus_sdk
from communicator.models.ivy_file import IvyFile
from communicator import app, db
from communicator.models.ivy_file import IvyFile
from communicator.errors import CommError
from communicator.services.ivy_service import IvyService
@ -25,9 +25,9 @@ class IvyServiceTest(BaseTest):
IvyService.samples_from_ivy_file(ivy_incorrect_file)
def test_load_directory(self):
self.assertEquals(0, db.session.query(IvyFile).count())
self.assertEqual(0, db.session.query(IvyFile).count())
app.config['IVY_IMPORT_DIR'] = os.path.join(app.root_path, '..', 'tests', 'data', 'import_directory')
files, records = IvyService().load_directory()
self.assertEquals(4, len(files))
files, _ = IvyService().load_directory()
self.assertEqual(4, len(files))

View File

@ -20,28 +20,28 @@ class TestSampleEndpoint(BaseTest):
def test_create_sample(self):
# Test add sample
samples = db.session.query(Sample).all()
self.assertEquals(0, len(samples))
self.assertEqual(0, len(samples))
rv = self.app.post('/v1.0/sample',
content_type="application/json",
data=json.dumps(self.sample_json))
samples = db.session.query(Sample).all()
self.assertEquals(1, len(samples))
self.assertEqual(1, len(samples))
def test_create_sample_gets_correct_location_and_station(self):
# Test add sample
samples = db.session.query(Sample).all()
self.assertEquals(0, len(samples))
self.assertEqual(0, len(samples))
rv = self.app.post('/v1.0/sample',
content_type="application/json",
data=json.dumps(self.sample_json))
samples = db.session.query(Sample).all()
self.assertEquals(1, len(samples))
self.assertEquals(1, samples[0].location)
self.assertEquals(2, samples[0].station)
self.assertEqual(1, len(samples))
self.assertEqual(1, samples[0].location)
self.assertEqual(2, samples[0].station)
def test_create_sample_has_last_updated(self):
rv = self.app.post('/v1.0/sample',
@ -49,13 +49,13 @@ class TestSampleEndpoint(BaseTest):
data=json.dumps(self.sample_json))
samples = db.session.query(Sample).all()
self.assertEquals(1, len(samples))
self.assertEqual(1, len(samples))
self.assertIsNotNone(samples[0].last_modified)
def test_create_duplicate_sample_does_not_raise_error(self):
# Test add sample
samples = db.session.query(Sample).all()
self.assertEquals(0, len(samples))
self.assertEqual(0, len(samples))
rv = self.app.post('/v1.0/sample', content_type="application/json", data=json.dumps(self.sample_json))
rv = self.app.post('/v1.0/sample', content_type="application/json", data=json.dumps(self.sample_json))
@ -63,7 +63,7 @@ class TestSampleEndpoint(BaseTest):
rv = self.app.post('/v1.0/sample', content_type="application/json", data=json.dumps(self.sample_json))
samples = db.session.query(Sample).all()
self.assertEquals(1, len(samples))
self.assertEqual(1, len(samples))
def test_notify_by_email_by_file_name(self):
db.session.add(Sample(barcode="000000111-202009091449-4321",
@ -83,12 +83,12 @@ class TestSampleEndpoint(BaseTest):
db.session.commit()
admin._notify_by_email('xxx')
samples = db.session.query(Sample).filter(Sample.email_notified == True).all()
self.assertEquals(1, len(samples))
self.assertEqual(1, len(samples))
samples = db.session.query(Sample).filter(Sample.email_notified != True).all()
self.assertEquals(1, len(samples))
self.assertEqual(1, len(samples))
admin._notify_by_email()
samples = db.session.query(Sample).filter(Sample.email_notified == True).all()
self.assertEquals(2, len(samples))
self.assertEqual(2, len(samples))
def test_get_all_samples(self):
s1 = Sample(barcode="000000111-202009091449-4321",
@ -164,17 +164,17 @@ class TestSampleEndpoint(BaseTest):
rv = self.app.get(f'/v1.0/sample', content_type="application/json",
headers={'X-CR-API-KEY': app.config.get('API_TOKEN')})
data = json.loads(rv.get_data(as_text=True))
self.assertEquals(2, len(data))
self.assertEqual(2, len(data))
last_modified_arg = d1.isoformat()
rv = self.app.get(f'/v1.0/sample?last_modified={last_modified_arg}', content_type="application/json",
headers={'X-CR-API-KEY': app.config.get('API_TOKEN')})
data = json.loads(rv.get_data(as_text=True))
self.assertEquals(1, len(data))
self.assertEquals(s2.barcode, data[0]['barcode'])
self.assertEqual(1, len(data))
self.assertEqual(s2.barcode, data[0]['barcode'])
last_modified_arg = d2.isoformat()
rv = self.app.get(f'/v1.0/sample?last_modified={last_modified_arg}', content_type="application/json",
headers={'X-CR-API-KEY': app.config.get('API_TOKEN')})
data = json.loads(rv.get_data(as_text=True))
self.assertEquals(0, len(data))
self.assertEqual(0, len(data))

View File

@ -94,15 +94,15 @@ class IvyServiceTest(BaseTest):
delta = datetime.now() - s1.last_modified
self.assertGreater(delta.days, 1) # Last modified is in the past.
self.assertEquals(2, len(db.session.query(Sample).all()))
self.assertEqual(2, len(db.session.query(Sample).all()))
service.merge_similar_records()
self.assertEquals(1, len(db.session.query(Sample).all()))
self.assertEqual(1, len(db.session.query(Sample).all()))
sample = db.session.query(Sample).first()
self.assertEquals("dan@sartography.com", sample.email)
self.assertEquals("111111111-AAA-202010050000-0000", sample.barcode)
self.assertEquals(1, len(sample.notifications))
self.assertEqual("dan@sartography.com", sample.email)
self.assertEqual("111111111-AAA-202010050000-0000", sample.barcode)
self.assertEqual(1, len(sample.notifications))
delta = datetime.now() - sample.last_modified
self.assertEquals(0, delta.days) # Last modified is updated on merge.
self.assertEqual(0, delta.days) # Last modified is updated on merge.
def test_merge_non_similar_records(self):
service = SampleService()
@ -117,7 +117,7 @@ class IvyServiceTest(BaseTest):
email="dan@sartography.com",
phone="555-555-5555"))
service.merge_similar_records()
self.assertEquals(2, len(db.session.query(Sample).all()))
self.assertEqual(2, len(db.session.query(Sample).all()))
def test_correct_computing_id(self):