diff --git a/.circleci/config.yml b/.circleci/config.yml index 8711a35..b4e9d94 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -2,7 +2,7 @@ version: 2 jobs: build: docker: - - image: circleci/python:2.7.15-jessie-browsers + - image: circleci/python:3.6.8-stretch-browsers steps: - checkout - run: mkdir test-reports diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..68dd48d --- /dev/null +++ b/Dockerfile @@ -0,0 +1,15 @@ +FROM python:3.7-buster + +RUN apt-get update && apt-get upgrade -y && \ + apt-get install -y git + +COPY . /home/gunicorn_user/osler +WORKDIR /home/gunicorn_user/osler + +RUN pip install --upgrade pip --trusted-host pypi.python.org +RUN pip install --trusted-host pypi.python.org -r requirements-prod.txt + +EXPOSE 8000 + +CMD ["gunicorn", "--chdir", "osler", "--bind", "0.0.0.0:8000", \ + "osler.gunicorn_wsgi:application", "--log-file", "-", "--log-level", "debug"] diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..5c6dc84 --- /dev/null +++ b/Makefile @@ -0,0 +1,33 @@ +# makefile + +start-dev: + docker-compose up + +start-prod: + docker-compose -f docker-compose.yml -f docker-compose.prod.yml up + +stop-compose: + @eval docker stop $$(docker ps -a -q) + docker-compose down + +ssh-nginx: + docker exec -it nginx_server bash + +ssh-django-web: + docker exec -it osler_app bash + +ssh-db: + docker exec -it osler_db bash + +build: + docker-compose build + +rebuild: + docker-compose build --no-cache + docker-compose up + +test: + docker-compose run osler_app python osler/manage.py test + +cleanup: + docker system prune diff --git a/config/nginx.conf b/config/nginx.conf new file mode 100644 index 0000000..dd47ae0 --- /dev/null +++ b/config/nginx.conf @@ -0,0 +1,51 @@ +user nginx; +worker_processes 1; + +pid /var/run/nginx.pid; +error_log /var/log/nginx/error.log warn; + +events { + worker_connections 1024; ## Default: 1024, increase if you have lots of clients +} + +http { + include /etc/nginx/mime.types; + # fallback in case we can't determine a type + default_type application/octet-stream; + + sendfile on; + #tcp_nopush on; + + upstream osler_server { + server osler_app:8000; + } + + server { + + listen 80; + # charset utf-8; + server_name localhost; + + location = /favicon.ico { access_log off; log_not_found off; } + + location / { + proxy_redirect off; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Host $server_name; + + proxy_pass http://osler_server; + proxy_redirect off; + } + + location /static/ { + alias /opt/services/osler/static/; + } + + location /media/ { + internal; + alias /opt/services/osler/media/; + } + } +} diff --git a/media/.gitignore b/config/secrets/.gitignore similarity index 100% rename from media/.gitignore rename to config/secrets/.gitignore diff --git a/docker-compose.yaml b/docker-compose.yaml new file mode 100644 index 0000000..00f42e7 --- /dev/null +++ b/docker-compose.yaml @@ -0,0 +1,81 @@ +version: "3.2" + +services: + web: + container_name: osler_app + build: + context: . + dockerfile: Dockerfile + image: osler + stop_signal: SIGINT + volumes: + - static:/home/gunicorn_user/osler/osler/static + - media:/home/gunicorn_user/osler/osler/media + - ./logs:/home/gunicorn_user/logs + networks: + - nginx_network + - database_network + depends_on: + - db + environment: + DJANGO_DEBUG: 0 + DJANGO_SETTINGS_MODULE: osler.docker_settings + DJANGO_SENDFILE_BACKEND: sendfile.backends.nginx + DJANGO_SENDFILE_ROOT: /opt/services/osler/media + DJANGO_SENDFILE_URL: /media + DJANGO_SECRET_KEY_FILE: /run/secrets/django_secret_key + DJANGO_DEBUG_LOG_FILE: /home/gunicorn_user/logs/osler.log + DATABASE_PASSWORD_FILE: /run/secrets/database_password + DATABASE_BACKEND: django.db.backends.postgresql_psycopg2 + DATABASE_NAME: osler + DATABASE_USER: django + DATABASE_PORT: 5432 + DATABASE_HOST: db + secrets: + - database_password + - django_secret_key + db: + container_name: osler_db + image: postgres + restart: always + environment: + POSTGRES_DB: osler + POSTGRES_PASSWORD_FILE: /run/secrets/database_password + POSTGRES_USER: django + networks: + - database_network + secrets: + - database_password + nginx: + image: nginx:latest + container_name: nginx_server + restart: always + ports: + # - "0.0.0.0:80:80" + - 8000:80 + volumes: + - db_data:/var/lib/postgresql/data + - ./config/nginx.conf:/etc/nginx/nginx.conf + - static:/opt/services/osler/static/ + - media:/opt/services/osler/media/ + depends_on: + - web + networks: + - nginx_network + +volumes: + static: + media: + db_data: + +secrets: + database_password: + file: config/secrets/database_password.txt + django_secret_key: + file: config/secrets/django_secret_key.txt + +networks: + nginx_network: + driver: bridge + database_network: # <-- add the bridge + driver: bridge diff --git a/media/test.jpg b/media/test.jpg deleted file mode 100644 index cb79b90..0000000 Binary files a/media/test.jpg and /dev/null differ diff --git a/api/__init__.py b/osler/api/__init__.py similarity index 100% rename from api/__init__.py rename to osler/api/__init__.py diff --git a/api/fixtures/api.json b/osler/api/fixtures/api.json similarity index 100% rename from api/fixtures/api.json rename to osler/api/fixtures/api.json diff --git a/api/serializers.py b/osler/api/serializers.py similarity index 100% rename from api/serializers.py rename to osler/api/serializers.py diff --git a/api/test.py b/osler/api/test.py similarity index 79% rename from api/test.py rename to osler/api/test.py index 2c989be..86d8a1a 100644 --- a/api/test.py +++ b/osler/api/test.py @@ -18,14 +18,15 @@ class APITest(APITestCase): def setUp(self): workupModels.ClinicType.objects.create(name="Basic Care Clinic") workupModels.ClinicDate.objects.create( - clinic_type=workupModels.ClinicType.objects.all()[0], + clinic_type=workupModels.ClinicType.objects.first(), clinic_date=now().date() + datetime.timedelta(days=1)) workupModels.ClinicDate.objects.create( - clinic_type=workupModels.ClinicType.objects.all()[0], + clinic_type=workupModels.ClinicType.objects.first(), clinic_date=now().date() - datetime.timedelta(days=1)) workupModels.ClinicDate.objects.create( - clinic_type=workupModels.ClinicType.objects.all()[0], + clinic_type=workupModels.ClinicType.objects.first(), clinic_date=now().date() - datetime.timedelta(days=5)) + log_in_provider(self.client, build_provider(["Attending"])) pt1 = models.Patient.objects.get(pk=1) @@ -41,9 +42,9 @@ def setUp(self): state='BA', zip_code='63108', pcp_preferred_zip='63018', - date_of_birth=datetime.date(1990, 01, 01), + date_of_birth=datetime.date(1990, 1, 1), patient_comfortable_with_english=False, - preferred_contact_method=models.ContactMethod.objects.all()[0], + preferred_contact_method=models.ContactMethod.objects.first(), ) pt3 = models.Patient.objects.create( @@ -51,15 +52,15 @@ def setUp(self): last_name="Lkjh", middle_name="Bayer", phone='+49 178 236 5288', - gender=models.Gender.objects.all()[0], + gender=models.Gender.objects.first(), address='Schulstrasse 9', city='Munich', state='BA', zip_code='63108', pcp_preferred_zip='63018', - date_of_birth=datetime.date(1990, 01, 01), + date_of_birth=datetime.date(1990, 1, 1), patient_comfortable_with_english=False, - preferred_contact_method=models.ContactMethod.objects.all()[0], + preferred_contact_method=models.ContactMethod.objects.first(), ) pt4 = models.Patient.objects.create( @@ -67,26 +68,26 @@ def setUp(self): last_name="Action", middle_name="Item", phone='+12 345 678 9000', - gender=models.Gender.objects.all()[0], + gender=models.Gender.objects.first(), address='Schulstrasse 9', city='Munich', state='BA', zip_code='63108', pcp_preferred_zip='63018', - date_of_birth=datetime.date(1990, 01, 01), + date_of_birth=datetime.date(1990, 1, 1), patient_comfortable_with_english=False, - preferred_contact_method=models.ContactMethod.objects.all()[0], + preferred_contact_method=models.ContactMethod.objects.first(), ) # Give pt2 a workup one day later. workupModels.Workup.objects.create( - clinic_day=workupModels.ClinicDate.objects.all()[0], # one day later + clinic_day=workupModels.ClinicDate.objects.first(), # one day later chief_complaint="SOB", diagnosis="MI", HPI="", PMH_PSH="", meds="", allergies="", fam_hx="", soc_hx="", ros="", pe="", A_and_P="", - author=models.Provider.objects.all()[0], - author_type=models.ProviderType.objects.all()[0], + author=models.Provider.objects.first(), + author_type=models.ProviderType.objects.first(), patient=pt2) # Give pt3 a workup one day ago. @@ -96,8 +97,8 @@ def setUp(self): diagnosis="MI", HPI="", PMH_PSH="", meds="", allergies="", fam_hx="", soc_hx="", ros="", pe="", A_and_P="", - author=models.Provider.objects.all()[0], - author_type=models.ProviderType.objects.all()[0], + author=models.Provider.objects.first(), + author_type=models.ProviderType.objects.first(), patient=pt3) @@ -108,8 +109,8 @@ def setUp(self): diagnosis="MI", HPI="", PMH_PSH="", meds="", allergies="", fam_hx="", soc_hx="", ros="", pe="", A_and_P="", - author=models.Provider.objects.all()[0], - author_type=models.ProviderType.objects.all()[0], + author=models.Provider.objects.first(), + author_type=models.ProviderType.objects.first(), patient=pt1, signer=models.Provider.objects.all().filter( clinical_roles=models.ProviderType.objects.all().filter( @@ -117,9 +118,9 @@ def setUp(self): # make pt1 have and AI due tomorrow pt1_ai = models.ActionItem.objects.create( - author=models.Provider.objects.all()[0], - author_type=models.ProviderType.objects.all()[0], - instruction=models.ActionInstruction.objects.all()[0], + author=models.Provider.objects.first(), + author_type=models.ProviderType.objects.first(), + instruction=models.ActionInstruction.objects.first(), due_date=now().date()+datetime.timedelta(days=1), comments="", priority=True, @@ -127,9 +128,9 @@ def setUp(self): # make pt2 have an AI due yesterday pt2_ai = models.ActionItem.objects.create( - author=models.Provider.objects.all()[0], - author_type=models.ProviderType.objects.all()[0], - instruction=models.ActionInstruction.objects.all()[0], + author=models.Provider.objects.first(), + author_type=models.ProviderType.objects.first(), + instruction=models.ActionInstruction.objects.first(), due_date=now().date()-datetime.timedelta(days=1), comments="", priority=True, @@ -137,9 +138,9 @@ def setUp(self): # make pt3 have an AI that during the test will be marked done pt3_ai = models.ActionItem.objects.create( - author=models.Provider.objects.all()[0], - author_type=models.ProviderType.objects.all()[0], - instruction=models.ActionInstruction.objects.all()[0], + author=models.Provider.objects.first(), + author_type=models.ProviderType.objects.first(), + instruction=models.ActionInstruction.objects.first(), due_date=now().date()-datetime.timedelta(days=15), comments="", patient=pt3) @@ -149,16 +150,19 @@ def test_api_list_patients_by_last_name(self): url = reverse("pt_list_api") # Way to have this here and not repeat this line? Reverse is called in every test now # Test last_name ordering - data = {'sort':'last_name'} + data = {'sort': 'last_name'} response = self.client.get(reverse("pt_list_api"), data, format='json') self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertLessEqual(response.data[0]['last_name'],response.data[1]['last_name']) - self.assertLessEqual(response.data[1]['last_name'],response.data[2]['last_name']) - self.assertLessEqual(response.data[2]['last_name'],response.data[3]['last_name']) + self.assertLessEqual(response.data[0]['last_name'], + response.data[1]['last_name']) + self.assertLessEqual(response.data[1]['last_name'], + response.data[2]['last_name']) + self.assertLessEqual(response.data[2]['last_name'], + response.data[3]['last_name']) def test_api_list_patients_by_latest_activity(self): # Test workup/intake ordering. - data = {'sort':'latest_workup'} + data = {'sort': 'latest_workup'} response = self.client.get(reverse("pt_list_api"), data, format='json') self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertNotEqual(response.data[0]['latest_workup'], None) # pt2, workup date now()+1day @@ -167,9 +171,15 @@ def test_api_list_patients_by_latest_activity(self): self.assertNotEqual(response.data[3]['latest_workup'], None) # pt1, workup date now()-5days # Check that dates are correcly sorted - self.assertGreaterEqual(response.data[0]['latest_workup']['clinic_day']['clinic_date'],response.data[1]['history']['last']['history_date']) - self.assertGreaterEqual(response.data[1]['history']['last']['history_date'],response.data[2]['latest_workup']['clinic_day']['clinic_date']) - self.assertGreaterEqual(response.data[2]['latest_workup']['clinic_day']['clinic_date'],response.data[3]['latest_workup']['clinic_day']['clinic_date']) + self.assertGreaterEqual( + response.data[0]['latest_workup']['clinic_day']['clinic_date'], + response.data[1]['history']['last']['history_date']) + self.assertGreaterEqual( + response.data[1]['history']['last']['history_date'], + response.data[2]['latest_workup']['clinic_day']['clinic_date']) + self.assertGreaterEqual( + response.data[2]['latest_workup']['clinic_day']['clinic_date'], + response.data[3]['latest_workup']['clinic_day']['clinic_date']) def test_api_list_patients_with_unsigned_workup(self): # Test for unsigned_workup @@ -225,7 +235,7 @@ def test_api_list_patients_with_inactive_action_item(self): self.assertEqual(len(response.data), 1) self.assertEqual(response.data[0]['id'], pt1.id) - pt3_ai.mark_done(models.Provider.objects.all()[0]) + pt3_ai.mark_done(models.Provider.objects.first()) pt3_ai.save() # Test now only has pt2 diff --git a/api/urls.py b/osler/api/urls.py similarity index 100% rename from api/urls.py rename to osler/api/urls.py diff --git a/api/views.py b/osler/api/views.py similarity index 100% rename from api/views.py rename to osler/api/views.py diff --git a/appointment/__init__.py b/osler/appointment/__init__.py similarity index 100% rename from appointment/__init__.py rename to osler/appointment/__init__.py diff --git a/appointment/admin.py b/osler/appointment/admin.py similarity index 100% rename from appointment/admin.py rename to osler/appointment/admin.py diff --git a/appointment/forms.py b/osler/appointment/forms.py similarity index 100% rename from appointment/forms.py rename to osler/appointment/forms.py diff --git a/appointment/migrations/0001_initial.py b/osler/appointment/migrations/0001_initial.py similarity index 100% rename from appointment/migrations/0001_initial.py rename to osler/appointment/migrations/0001_initial.py diff --git a/appointment/migrations/0002_vaccineappointment_20181031_1852.py b/osler/appointment/migrations/0002_vaccineappointment_20181031_1852.py similarity index 100% rename from appointment/migrations/0002_vaccineappointment_20181031_1852.py rename to osler/appointment/migrations/0002_vaccineappointment_20181031_1852.py diff --git a/appointment/migrations/0003_pt_showed_and_default_time_function_20181103_1414.py b/osler/appointment/migrations/0003_pt_showed_and_default_time_function_20181103_1414.py similarity index 100% rename from appointment/migrations/0003_pt_showed_and_default_time_function_20181103_1414.py rename to osler/appointment/migrations/0003_pt_showed_and_default_time_function_20181103_1414.py diff --git a/appointment/migrations/0004_update_appointment_ordering_20190902_2116.py b/osler/appointment/migrations/0004_update_appointment_ordering_20190902_2116.py similarity index 100% rename from appointment/migrations/0004_update_appointment_ordering_20190902_2116.py rename to osler/appointment/migrations/0004_update_appointment_ordering_20190902_2116.py diff --git a/appointment/migrations/__init__.py b/osler/appointment/migrations/__init__.py similarity index 100% rename from appointment/migrations/__init__.py rename to osler/appointment/migrations/__init__.py diff --git a/appointment/models.py b/osler/appointment/models.py similarity index 98% rename from appointment/models.py rename to osler/appointment/models.py index 9c55cca..6c89d40 100644 --- a/appointment/models.py +++ b/osler/appointment/models.py @@ -47,7 +47,7 @@ class Meta: history = HistoricalRecords() - def __unicode__(self): + def __str__(self): return "Appointment ({type}) for {name} on {date}".format( type=self.verbose_appointment_type(), name=self.patient.name(), diff --git a/appointment/templates/appointment/appointment_list.html b/osler/appointment/templates/appointment/appointment_list.html similarity index 98% rename from appointment/templates/appointment/appointment_list.html rename to osler/appointment/templates/appointment/appointment_list.html index f81c749..a6da3b9 100644 --- a/appointment/templates/appointment/appointment_list.html +++ b/osler/appointment/templates/appointment/appointment_list.html @@ -15,7 +15,7 @@

Appointment List

{% block content %}
- {% for date, app_list in appointments_by_date.iteritems %} + {% for date, app_list in appointments_by_date.items %}
'''), - dewhitespace(response.content)) + dewhitespace(response.content.decode('ascii'))) # since there's only one page, the "forward" pagination button # should be disabled self.assertIn( @@ -167,7 +167,7 @@ def test_dashboard_pagination(self):
  • '''), - dewhitespace(response.content)) + dewhitespace(response.content.decode('ascii'))) # since there's only one page, only one page marker should be shown self.assertContains( @@ -206,7 +206,7 @@ def test_dashboard_pagination(self):
  • '''), - dewhitespace(response.content)) + dewhitespace(response.content.decode('ascii'))) # since there's only one page, the "forward" pagination button # should be disabled self.assertIn( @@ -214,7 +214,7 @@ def test_dashboard_pagination(self):
  • '''), - dewhitespace(response.content)) + dewhitespace(response.content.decode('ascii'))) @override_settings(OSLER_CLINIC_DAYS_PER_PAGE=3) def test_dashboard_page_out_of_range(self): @@ -253,7 +253,7 @@ def test_dashboard_page_out_of_range(self):
  • '''), - dewhitespace(response.content)) + dewhitespace(response.content.decode('ascii'))) diff --git a/dashboard/urls.py b/osler/dashboard/urls.py similarity index 100% rename from dashboard/urls.py rename to osler/dashboard/urls.py diff --git a/dashboard/views.py b/osler/dashboard/views.py similarity index 100% rename from dashboard/views.py rename to osler/dashboard/views.py diff --git a/demographics/__init__.py b/osler/demographics/__init__.py similarity index 100% rename from demographics/__init__.py rename to osler/demographics/__init__.py diff --git a/demographics/admin.py b/osler/demographics/admin.py similarity index 100% rename from demographics/admin.py rename to osler/demographics/admin.py diff --git a/demographics/forms.py b/osler/demographics/forms.py similarity index 100% rename from demographics/forms.py rename to osler/demographics/forms.py diff --git a/demographics/migrations/0001_squashed_0003_auto_20170623_1048.py b/osler/demographics/migrations/0001_squashed_0003_auto_20170623_1048.py similarity index 92% rename from demographics/migrations/0001_squashed_0003_auto_20170623_1048.py rename to osler/demographics/migrations/0001_squashed_0003_auto_20170623_1048.py index 360ba78..9647b14 100644 --- a/demographics/migrations/0001_squashed_0003_auto_20170623_1048.py +++ b/osler/demographics/migrations/0001_squashed_0003_auto_20170623_1048.py @@ -6,7 +6,9 @@ class Migration(migrations.Migration): - replaces = [(b'demographics', '0001_initial'), (b'demographics', '0002_auto_20160328_1425'), (b'demographics', '0003_auto_20170623_1048')] + replaces = [('demographics', '0001_initial'), + ('demographics', '0002_auto_20160328_1425'), + ('demographics', '0003_auto_20170623_1048')] dependencies = [ ('pttrack', '0001_squashed_0010_auto_20170623_1300'), @@ -70,7 +72,7 @@ class Migration(migrations.Migration): migrations.AddField( model_name='demographics', name='chronic_condition', - field=models.ManyToManyField(to=b'demographics.ChronicCondition', blank=True), + field=models.ManyToManyField(to='demographics.ChronicCondition', blank=True), ), migrations.AddField( model_name='demographics', @@ -85,7 +87,7 @@ class Migration(migrations.Migration): migrations.AddField( model_name='demographics', name='resource_access', - field=models.ManyToManyField(to=b'demographics.ResourceAccess', verbose_name=b'Access to Resources', blank=True), + field=models.ManyToManyField(to='demographics.ResourceAccess', verbose_name=b'Access to Resources', blank=True), ), migrations.AddField( model_name='demographics', diff --git a/demographics/migrations/0002_historicalrecords_and_nullboolean_20171119_1818.py b/osler/demographics/migrations/0002_historicalrecords_and_nullboolean_20171119_1818.py similarity index 100% rename from demographics/migrations/0002_historicalrecords_and_nullboolean_20171119_1818.py rename to osler/demographics/migrations/0002_historicalrecords_and_nullboolean_20171119_1818.py diff --git a/demographics/migrations/0003_simplehistory_add_change_reason.py b/osler/demographics/migrations/0003_simplehistory_add_change_reason.py similarity index 100% rename from demographics/migrations/0003_simplehistory_add_change_reason.py rename to osler/demographics/migrations/0003_simplehistory_add_change_reason.py diff --git a/demographics/migrations/0004_add_proper_plurals_20190902_2116.py b/osler/demographics/migrations/0004_add_proper_plurals_20190902_2116.py similarity index 100% rename from demographics/migrations/0004_add_proper_plurals_20190902_2116.py rename to osler/demographics/migrations/0004_add_proper_plurals_20190902_2116.py diff --git a/demographics/migrations/__init__.py b/osler/demographics/migrations/__init__.py similarity index 100% rename from demographics/migrations/__init__.py rename to osler/demographics/migrations/__init__.py diff --git a/demographics/models.py b/osler/demographics/models.py similarity index 93% rename from demographics/models.py rename to osler/demographics/models.py index 57a81d9..6c636c7 100644 --- a/demographics/models.py +++ b/osler/demographics/models.py @@ -9,14 +9,14 @@ class IncomeRange(models.Model): name = models.CharField(max_length=50, primary_key=True) - def __unicode__(self): + def __str__(self): return self.name class EducationLevel(models.Model): name = models.CharField(max_length=50, primary_key=True) - def __unicode__(self): + def __str__(self): return self.name @@ -27,7 +27,7 @@ class Meta: name = models.CharField(max_length=50, primary_key=True) - def __unicode__(self): + def __str__(self): return self.name @@ -38,21 +38,21 @@ class Meta: name = models.CharField(max_length=50, primary_key=True) - def __unicode__(self): + def __str__(self): return self.name class ChronicCondition(models.Model): name = models.CharField(max_length=50, primary_key=True) - def __unicode__(self): + def __str__(self): return self.name class TransportationOption(models.Model): name = models.CharField(max_length=50, primary_key=True) - def __unicode__(self): + def __str__(self): return self.name diff --git a/demographics/templates/demographics/demographics-create.html b/osler/demographics/templates/demographics/demographics-create.html similarity index 100% rename from demographics/templates/demographics/demographics-create.html rename to osler/demographics/templates/demographics/demographics-create.html diff --git a/demographics/templates/demographics/demographics-resolve.html b/osler/demographics/templates/demographics/demographics-resolve.html similarity index 100% rename from demographics/templates/demographics/demographics-resolve.html rename to osler/demographics/templates/demographics/demographics-resolve.html diff --git a/demographics/templates/demographics/demographics_detail.html b/osler/demographics/templates/demographics/demographics_detail.html similarity index 100% rename from demographics/templates/demographics/demographics_detail.html rename to osler/demographics/templates/demographics/demographics_detail.html diff --git a/demographics/tests.py b/osler/demographics/tests.py similarity index 100% rename from demographics/tests.py rename to osler/demographics/tests.py diff --git a/demographics/urls.py b/osler/demographics/urls.py similarity index 98% rename from demographics/urls.py rename to osler/demographics/urls.py index 45a67ef..5e9d90a 100644 --- a/demographics/urls.py +++ b/osler/demographics/urls.py @@ -18,4 +18,4 @@ ] wrap_config = {} -urlpatterns = [wrap_url(url, **wrap_config) for url in unwrapped_urlconf] \ No newline at end of file +urlpatterns = [wrap_url(url, **wrap_config) for url in unwrapped_urlconf] diff --git a/demographics/views.py b/osler/demographics/views.py similarity index 100% rename from demographics/views.py rename to osler/demographics/views.py diff --git a/followup/__init__.py b/osler/followup/__init__.py similarity index 100% rename from followup/__init__.py rename to osler/followup/__init__.py diff --git a/followup/admin.py b/osler/followup/admin.py similarity index 100% rename from followup/admin.py rename to osler/followup/admin.py diff --git a/followup/fixtures/followup.json b/osler/followup/fixtures/followup.json similarity index 100% rename from followup/fixtures/followup.json rename to osler/followup/fixtures/followup.json diff --git a/followup/forms.py b/osler/followup/forms.py similarity index 100% rename from followup/forms.py rename to osler/followup/forms.py diff --git a/followup/migrations/0001_initial.py b/osler/followup/migrations/0001_initial.py similarity index 100% rename from followup/migrations/0001_initial.py rename to osler/followup/migrations/0001_initial.py diff --git a/followup/migrations/0002_simplehistory_add_change_reason.py b/osler/followup/migrations/0002_simplehistory_add_change_reason.py similarity index 100% rename from followup/migrations/0002_simplehistory_add_change_reason.py rename to osler/followup/migrations/0002_simplehistory_add_change_reason.py diff --git a/followup/migrations/0003_simplehistory_add_v2_migrations_20190324_1133.py b/osler/followup/migrations/0003_simplehistory_add_v2_migrations_20190324_1133.py similarity index 100% rename from followup/migrations/0003_simplehistory_add_v2_migrations_20190324_1133.py rename to osler/followup/migrations/0003_simplehistory_add_v2_migrations_20190324_1133.py diff --git a/followup/migrations/0004_simplehistory_add_v2_migrations_2_20190813_2018.py b/osler/followup/migrations/0004_simplehistory_add_v2_migrations_2_20190813_2018.py similarity index 100% rename from followup/migrations/0004_simplehistory_add_v2_migrations_2_20190813_2018.py rename to osler/followup/migrations/0004_simplehistory_add_v2_migrations_2_20190813_2018.py diff --git a/followup/migrations/0005_db_do_nothings_20190902_2116.py b/osler/followup/migrations/0005_db_do_nothings_20190902_2116.py similarity index 100% rename from followup/migrations/0005_db_do_nothings_20190902_2116.py rename to osler/followup/migrations/0005_db_do_nothings_20190902_2116.py diff --git a/followup/migrations/__init__.py b/osler/followup/migrations/__init__.py similarity index 100% rename from followup/migrations/__init__.py rename to osler/followup/migrations/__init__.py diff --git a/followup/models.py b/osler/followup/models.py similarity index 98% rename from followup/models.py rename to osler/followup/models.py index f08d538..82ee7b3 100644 --- a/followup/models.py +++ b/osler/followup/models.py @@ -12,7 +12,7 @@ class NoShowReason(models.Model): name = models.CharField(max_length=100, primary_key=True) - def __unicode__(self): + def __str__(self): return self.name @@ -22,7 +22,7 @@ class NoAptReason(models.Model): name = models.CharField(max_length=100, primary_key=True) - def __unicode__(self): + def __str__(self): return self.name @@ -38,7 +38,7 @@ class ContactResult(models.Model): default=True, help_text="True if outcome means they reached the patient") - def __unicode__(self): + def __str__(self): return self.name @@ -83,7 +83,7 @@ def written_date(self): '''Returns a python date object for when this followup was written.''' return self.written_datetime.date() - def __unicode__(self): + def __str__(self): return " ".join(["Followup for ", self.patient.name(), " on ", str(self.written_date())]) diff --git a/followup/templates/followup/referral-followup-create.html b/osler/followup/templates/followup/referral-followup-create.html similarity index 100% rename from followup/templates/followup/referral-followup-create.html rename to osler/followup/templates/followup/referral-followup-create.html diff --git a/followup/tests.py b/osler/followup/tests.py similarity index 99% rename from followup/tests.py rename to osler/followup/tests.py index 80c53d4..d2710ac 100644 --- a/followup/tests.py +++ b/osler/followup/tests.py @@ -208,7 +208,7 @@ def setUp(self): state='BA', zip_code='63108', pcp_preferred_zip='63018', - date_of_birth=datetime.date(1990, 01, 01), + date_of_birth=datetime.date(1990, 1, 1), patient_comfortable_with_english=False, preferred_contact_method=self.contact_method, ) diff --git a/followup/urls.py b/osler/followup/urls.py similarity index 99% rename from followup/urls.py rename to osler/followup/urls.py index 7cbf373..334d6ba 100644 --- a/followup/urls.py +++ b/osler/followup/urls.py @@ -32,4 +32,4 @@ ] wrap_config = {} -urlpatterns = [wrap_url(url, **wrap_config) for url in unwrapped_urlconf] \ No newline at end of file +urlpatterns = [wrap_url(url, **wrap_config) for url in unwrapped_urlconf] diff --git a/followup/views.py b/osler/followup/views.py similarity index 100% rename from followup/views.py rename to osler/followup/views.py diff --git a/manage.py b/osler/manage.py similarity index 100% rename from manage.py rename to osler/manage.py diff --git a/secrets/.gitignore b/osler/media/.gitignore similarity index 100% rename from secrets/.gitignore rename to osler/media/.gitignore diff --git a/osler/__init__.py b/osler/osler/__init__.py similarity index 100% rename from osler/__init__.py rename to osler/osler/__init__.py diff --git a/osler/base_settings.py b/osler/osler/base_settings.py similarity index 98% rename from osler/base_settings.py rename to osler/osler/base_settings.py index 3039b54..d5c6c76 100644 --- a/osler/base_settings.py +++ b/osler/osler/base_settings.py @@ -100,14 +100,12 @@ STATIC_URL = '/static/' STATIC_ROOT = os.path.join(BASE_DIR, 'static/') -MEDIA_URL = '/media/' -MEDIA_ROOT = os.path.join(BASE_DIR, 'media/') - # for crispy_forms CRISPY_TEMPLATE_PACK = 'bootstrap3' INTERNAL_IPS = ('127.0.0.1',) # used for debug toolbar + # Medical Settings OSLER_MAX_SYSTOLIC = 400 OSLER_MIN_DIASTOLIC = 40 diff --git a/osler/debug_settings.py b/osler/osler/debug_settings.py similarity index 69% rename from osler/debug_settings.py rename to osler/osler/debug_settings.py index a5b0a3a..a9a49d7 100644 --- a/osler/debug_settings.py +++ b/osler/osler/debug_settings.py @@ -6,6 +6,11 @@ CRISPY_FAIL_SILENTLY = not DEBUG ALLOWED_HOSTS = [] +INTERNAL_IPS = ('127.0.0.1',) # used for debug toolbar + +MEDIA_URL = '/media/' +MEDIA_ROOT = os.path.join(BASE_DIR, 'media/') + SECRET_KEY = "^**4$36%t29#6+q4j9d3r$7da=i4*v398h%4k*mwc43pd1y#)u" EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' @@ -17,7 +22,8 @@ } } -MIDDLEWARE = MIDDLEWARE + ('debug_toolbar.middleware.DebugToolbarMiddleware',) +MIDDLEWARE_CLASSES = MIDDLEWARE_CLASSES + ( + 'debug_toolbar.middleware.DebugToolbarMiddleware',) PASSWORD_HASHERS = ( 'django.contrib.auth.hashers.MD5PasswordHasher', diff --git a/osler/deploy_settings.py b/osler/osler/deploy_settings.py similarity index 100% rename from osler/deploy_settings.py rename to osler/osler/deploy_settings.py diff --git a/osler/osler/docker_settings.py b/osler/osler/docker_settings.py new file mode 100644 index 0000000..1d8017c --- /dev/null +++ b/osler/osler/docker_settings.py @@ -0,0 +1,101 @@ +from .base_settings import * + +DEBUG = TEMPLATE_DEBUG = os.environ.get('DJANGO_DEBUG', False) +CRISPY_FAIL_SILENTLY = not DEBUG + +if not DEBUG: + ALLOWED_HOSTS = ['localhost'] + + SECURE_CONTENT_TYPE_NOSNIFF = True + SECURE_BROWSER_XSS_FILTER = True + SESSION_COOKIE_SECURE = True + CSRF_COOKIE_SECURE = True + CSRF_COOKIE_HTTPONLY = True + X_FRAME_OPTIONS = 'DENY' +else: + ALLOWED_HOSTS = ['*'] + +with open(os.environ.get('DJANGO_SECRET_KEY_FILE')) as f: + SECRET_KEY = f.read().strip() + +SENDFILE_BACKEND = os.environ.get('DJANGO_SENDFILE_BACKEND') +SENDFILE_URL = os.environ.get('DJANGO_SENDFILE_URL') +SENDFILE_ROOT = os.environ.get('DJANGO_SENDFILE_ROOT') + +MEDIA_URL = '/media_auth/' +MEDIA_ROOT = SENDFILE_ROOT + + +# one day in seconds +SESSION_COOKIE_AGE = 86400 + +# it would be nice to enable this, but we go w/o SSL from the WashU load +# balancer, meaning infinite redirects if we enable this :( +# SECURE_SSL_REDIRECT = True + + +LOGGING = { + 'version': 1, + 'disable_existing_loggers': False, + 'filters': { + 'require_debug_false': { + '()': 'django.utils.log.RequireDebugFalse' + } + }, + 'handlers': { + 'mail_admins': { + 'level': 'ERROR', + 'filters': ['require_debug_false'], + 'class': 'django.utils.log.AdminEmailHandler' + }, + 'osler_logger': { + 'level': 'DEBUG', + 'class': 'logging.handlers.RotatingFileHandler', + 'filename': os.environ.get('DJANGO_DEBUG_LOG_FILE'), + 'maxBytes': 1024 * 1024 * 30, # 15MB + 'backupCount': 10, + }, + }, + 'loggers': { + 'django.request': { + 'handlers': ['osler_logger'], + 'level': 'DEBUG', + 'propagate': True, + }, + 'django': { + 'handlers': ['mail_admins'], + 'level': 'ERROR', + 'propagate': True, + }, + 'osler': { + 'handlers': ['osler_logger'], + 'level': 'DEBUG', + 'propagate': True, + }, + } +} + +# DEFAULT_FROM_EMAIL = "webmaster@osler.wustl.edu" +# SERVER_EMAIL = "admin@osler.wustl.edu" +# EMAIL_HOST = "irony.wusm.wustl.edu" +# ADMINS = ( +# ('Artur Meller', 'ameller@wustl.edu'), +# ('Justin Porter', 'jrporter@wustl.edu'), +# ('Nicolas Ledru', 'nicolas.ledru@wustl.edu'), +# ('Arjav Shah', 'arjav.shah@wustl.edu'), +# ('Benji Katz','benjamin.katz@wustl.edu') +# ) + +with open(os.environ.get('DATABASE_PASSWORD_FILE')) as f: + DATABASE_PASSWORD = f.read().strip() + +DATABASES = { + 'default': { + 'ENGINE': os.environ.get('DATABASE_BACKEND'), + 'NAME': os.environ.get('DATABASE_NAME'), + 'USER': os.environ.get('DATABASE_USER'), + 'PASSWORD': DATABASE_PASSWORD, + 'HOST': os.environ.get('DATABASE_HOST'), + 'PORT': os.environ.get('DATABASE_PORT'), + } +} diff --git a/osler/osler/gunicorn_wsgi.py b/osler/osler/gunicorn_wsgi.py new file mode 100644 index 0000000..d1ded25 --- /dev/null +++ b/osler/osler/gunicorn_wsgi.py @@ -0,0 +1,15 @@ +""" +WSGI config for osler when DJANGO_SETTINGS_MODULE is an environment var. + +It exposes the WSGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/1.9/howto/deployment/wsgi/ +""" + +import os + +from django.core.wsgi import get_wsgi_application + +os.environ.get("DJANGO_SETTINGS_MODULE") +application = get_wsgi_application() diff --git a/osler/urls.py b/osler/osler/urls.py similarity index 51% rename from osler/urls.py rename to osler/osler/urls.py index f72b0a9..a283f67 100644 --- a/osler/urls.py +++ b/osler/osler/urls.py @@ -1,30 +1,47 @@ +import os +import logging + from django.conf.urls import include, url from django.contrib import admin from django.views.generic.base import RedirectView -from django.conf.urls.static import static +from django.contrib.auth.decorators import login_required from django.conf import settings +from sendfile import sendfile + +logger = logging.getLogger(__name__) + + +@login_required +def send_media_file(request, filename): + fq_filename = os.path.join(settings.SENDFILE_ROOT, filename) + logger.debug("Serving file %s with sendfile.", fq_filename) + return sendfile(request, fq_filename) + urlpatterns = [ url(r'^pttrack/', include('pttrack.urls')), url(r'^accounts/', include('pttrack.auth_urls')), url(r'^followup/', include('followup.urls')), url(r'^workup/', include('workup.urls')), - url(r'^dashboard/', include('dashboard.urls')), url(r'^demographics/', include('demographics.urls')), url(r'^appointment/', include('appointment.urls')), url(r'^admin/', include(admin.site.urls)), url(r'^accounts/', include('django.contrib.auth.urls')), url(r'^api/', include('api.urls')), - url(r'^referral/', include('referral.urls')), + url(r'^media_auth/(?P.*)$', send_media_file), url(r'^$', RedirectView.as_view(pattern_name="dashboard-dispatch", permanent=False), name='root'), -] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) +] if settings.DEBUG: - import debug_toolbar - urlpatterns = [ - url(r'^__debug__/', include(debug_toolbar.urls)), - ] + urlpatterns + try: + import debug_toolbar + urlpatterns = [ + url(r'^__debug__/', include(debug_toolbar.urls)), + ] + urlpatterns + except ImportError: + logger.warning('Failed to load django-debug-toolbar. Are you ' + 'running with DEBUG = True in production?') diff --git a/osler/wsgi.py b/osler/osler/wsgi.py similarity index 100% rename from osler/wsgi.py rename to osler/osler/wsgi.py diff --git a/pttrack/__init__.py b/osler/pttrack/__init__.py similarity index 100% rename from pttrack/__init__.py rename to osler/pttrack/__init__.py diff --git a/pttrack/admin.py b/osler/pttrack/admin.py similarity index 85% rename from pttrack/admin.py rename to osler/pttrack/admin.py index 3a55a3c..5e555bd 100644 --- a/pttrack/admin.py +++ b/osler/pttrack/admin.py @@ -6,6 +6,13 @@ from . import models +class NoteAdmin(SimpleHistoryAdmin): + readonly_fields = ('written_datetime', 'last_modified', 'author', + 'author_type') + list_display = ('__str__', 'written_datetime', 'patient', 'author', + 'last_modified') + + class CompletionFilter(SimpleListFilter): title = _('Completion') parameter_name = 'completion_status' @@ -23,12 +30,6 @@ def queryset(self, request, queryset): return queryset.filter(completion_date=None) -class NoteAdmin(SimpleHistoryAdmin): - readonly_fields = ('written_datetime', 'last_modified') - list_display = ('__str__', 'written_datetime', 'patient', 'author', - 'last_modified') - - class ActionItemAdmin(SimpleHistoryAdmin): readonly_fields = ('written_datetime', 'last_modified') date_hierarchy = 'due_date' @@ -38,8 +39,8 @@ class ActionItemAdmin(SimpleHistoryAdmin): for model in [models.Language, models.Patient, models.Provider, - models.ActionInstruction, models.Ethnicity, - models.ReferralType, models.ReferralLocation, + models.ProviderType, models.ActionInstruction, models.Ethnicity, + models.Gender, models.ReferralType, models.ReferralLocation, models.ContactMethod, models.DocumentType, models.Outcome]: if hasattr(model, "history"): admin.site.register(model, SimpleHistoryAdmin) diff --git a/pttrack/auth_urls.py b/osler/pttrack/auth_urls.py similarity index 100% rename from pttrack/auth_urls.py rename to osler/pttrack/auth_urls.py diff --git a/pttrack/decorators.py b/osler/pttrack/decorators.py similarity index 100% rename from pttrack/decorators.py rename to osler/pttrack/decorators.py diff --git a/pttrack/fixtures/pttrack.json b/osler/pttrack/fixtures/pttrack.json similarity index 100% rename from pttrack/fixtures/pttrack.json rename to osler/pttrack/fixtures/pttrack.json diff --git a/pttrack/forms.py b/osler/pttrack/forms.py similarity index 100% rename from pttrack/forms.py rename to osler/pttrack/forms.py diff --git a/pttrack/management/__init__.py b/osler/pttrack/management/__init__.py similarity index 100% rename from pttrack/management/__init__.py rename to osler/pttrack/management/__init__.py diff --git a/pttrack/management/commands/__init__.py b/osler/pttrack/management/commands/__init__.py similarity index 100% rename from pttrack/management/commands/__init__.py rename to osler/pttrack/management/commands/__init__.py diff --git a/pttrack/management/commands/action_item_spam.py b/osler/pttrack/management/commands/action_item_spam.py similarity index 100% rename from pttrack/management/commands/action_item_spam.py rename to osler/pttrack/management/commands/action_item_spam.py diff --git a/pttrack/migrations/0001_squashed_0010_auto_20170623_1300.py b/osler/pttrack/migrations/0001_squashed_0010_auto_20170623_1300.py similarity index 96% rename from pttrack/migrations/0001_squashed_0010_auto_20170623_1300.py rename to osler/pttrack/migrations/0001_squashed_0010_auto_20170623_1300.py index 9ab3456..6e46d5e 100644 --- a/pttrack/migrations/0001_squashed_0010_auto_20170623_1300.py +++ b/osler/pttrack/migrations/0001_squashed_0010_auto_20170623_1300.py @@ -10,7 +10,16 @@ class Migration(migrations.Migration): - replaces = [(b'pttrack', '0001_initial'), (b'pttrack', '0002_providertype_is_staff'), (b'pttrack', '0003_auto_20160119_1459'), (b'pttrack', '0004_auto_20160328_1425'), (b'pttrack', '0005_auto_20160628_1852'), (b'pttrack', '0006_rm_ssn'), (b'pttrack', '0007_needs_workup_default_true'), (b'pttrack', '0008_add_case_manager'), (b'pttrack', '0009_auto_20170502_1103'), (b'pttrack', '0010_auto_20170623_1300')] + replaces = [('pttrack', '0001_initial'), + ('pttrack', '0002_providertype_is_staff'), + ('pttrack', '0003_auto_20160119_1459'), + ('pttrack', '0004_auto_20160328_1425'), + ('pttrack', '0005_auto_20160628_1852'), + ('pttrack', '0006_rm_ssn'), + ('pttrack', '0007_needs_workup_default_true'), + ('pttrack', '0008_add_case_manager'), + ('pttrack', '0009_auto_20170502_1103'), + ('pttrack', '0010_auto_20170623_1300')] dependencies = [ migrations.swappable_dependency(settings.AUTH_USER_MODEL), @@ -206,9 +215,9 @@ class Migration(migrations.Migration): ('alternate_phone_4_owner', models.CharField(max_length=40, null=True, blank=True)), ('alternate_phone_4', models.CharField(max_length=40, null=True, blank=True)), ('needs_workup', models.BooleanField(default=True)), - ('ethnicities', models.ManyToManyField(to=b'pttrack.Ethnicity')), + ('ethnicities', models.ManyToManyField(to='pttrack.Ethnicity')), ('gender', models.ForeignKey(to='pttrack.Gender')), - ('languages', models.ManyToManyField(help_text=b'Specify here languages that are spoken at a level sufficient to be used for medical communication.', to=b'pttrack.Language')), + ('languages', models.ManyToManyField(help_text=b'Specify here languages that are spoken at a level sufficient to be used for medical communication.', to='pttrack.Language')), ('preferred_contact_method', models.ForeignKey(blank=True, to='pttrack.ContactMethod', null=True)), ('email', models.EmailField(max_length=254, null=True, blank=True)), ], @@ -256,7 +265,7 @@ class Migration(migrations.Migration): migrations.AddField( model_name='provider', name='clinical_roles', - field=models.ManyToManyField(to=b'pttrack.ProviderType'), + field=models.ManyToManyField(to='pttrack.ProviderType'), ), migrations.AddField( model_name='provider', @@ -266,7 +275,7 @@ class Migration(migrations.Migration): migrations.AddField( model_name='provider', name='languages', - field=models.ManyToManyField(help_text=b'Specify here languages that are spoken at a level sufficient to be used for medical communication.', to=b'pttrack.Language'), + field=models.ManyToManyField(help_text=b'Specify here languages that are spoken at a level sufficient to be used for medical communication.', to='pttrack.Language'), ), migrations.AddField( model_name='historicaldocument', diff --git a/pttrack/migrations/0002_auto_20171007_1533.py b/osler/pttrack/migrations/0002_auto_20171007_1533.py similarity index 100% rename from pttrack/migrations/0002_auto_20171007_1533.py rename to osler/pttrack/migrations/0002_auto_20171007_1533.py diff --git a/pttrack/migrations/0003_auto_20171014_1843.py b/osler/pttrack/migrations/0003_auto_20171014_1843.py similarity index 100% rename from pttrack/migrations/0003_auto_20171014_1843.py rename to osler/pttrack/migrations/0003_auto_20171014_1843.py diff --git a/pttrack/migrations/0004_auto_20171016_1646.py b/osler/pttrack/migrations/0004_auto_20171016_1646.py similarity index 100% rename from pttrack/migrations/0004_auto_20171016_1646.py rename to osler/pttrack/migrations/0004_auto_20171016_1646.py diff --git a/pttrack/migrations/0005_simplehistory_add_change_reason.py b/osler/pttrack/migrations/0005_simplehistory_add_change_reason.py similarity index 100% rename from pttrack/migrations/0005_simplehistory_add_change_reason.py rename to osler/pttrack/migrations/0005_simplehistory_add_change_reason.py diff --git a/pttrack/migrations/0006_referral_additional_fields_20180826.py b/osler/pttrack/migrations/0006_referral_additional_fields_20180826.py similarity index 100% rename from pttrack/migrations/0006_referral_additional_fields_20180826.py rename to osler/pttrack/migrations/0006_referral_additional_fields_20180826.py diff --git a/pttrack/migrations/0007_referraltype_is_active.py b/osler/pttrack/migrations/0007_referraltype_is_active.py similarity index 100% rename from pttrack/migrations/0007_referraltype_is_active.py rename to osler/pttrack/migrations/0007_referraltype_is_active.py diff --git a/pttrack/migrations/0008_actioninstruction_active.py b/osler/pttrack/migrations/0008_actioninstruction_active.py similarity index 100% rename from pttrack/migrations/0008_actioninstruction_active.py rename to osler/pttrack/migrations/0008_actioninstruction_active.py diff --git a/pttrack/migrations/0009_set_orderings_20190902_2116.py b/osler/pttrack/migrations/0009_set_orderings_20190902_2116.py similarity index 100% rename from pttrack/migrations/0009_set_orderings_20190902_2116.py rename to osler/pttrack/migrations/0009_set_orderings_20190902_2116.py diff --git a/pttrack/migrations/__init__.py b/osler/pttrack/migrations/__init__.py similarity index 100% rename from pttrack/migrations/__init__.py rename to osler/pttrack/migrations/__init__.py diff --git a/pttrack/models.py b/osler/pttrack/models.py similarity index 93% rename from pttrack/models.py rename to osler/pttrack/models.py index 2519188..d7cc92c 100644 --- a/pttrack/models.py +++ b/osler/pttrack/models.py @@ -15,27 +15,25 @@ # pylint: disable=I0011,missing-docstring,E1305 + def make_filepath(instance, filename): - ''' - Produces a unique file path for the upload_to of a FileField. This is + """Produces a unique file path for the upload_to of a FileField. This is important because any URL is 1) transmitted unencrypted and 2) automatically referred to any libraries we include (i.e. Bootstrap, AngularJS). - The produced path is of the form: - "[model name]/[field name]/[random name].[filename extension]". - Copypasta from https://djangosnippets.org/snippets/2819/ - ''' + The produced path is of the form: + "[model name]/[field name]/[random name].[filename extension]". + + Copypasta from https://djangosnippets.org/snippets/2819/ + """ - field_name = 'image' carry_on = True while carry_on: new_filename = "%s.%s" % (User.objects.make_random_password(48), filename.split('.')[-1]) - #path = '/'.join([instance.__class__.__name__.lower(),field_name, new_filename]) - path = new_filename # if the file already exists, try again to generate a new filename @@ -50,7 +48,7 @@ class ContactMethod(models.Model): name = models.CharField(max_length=50, primary_key=True) - def __unicode__(self): + def __str__(self): return self.name @@ -61,7 +59,7 @@ class ReferralType(models.Model): is_fqhc = models.BooleanField(default=False) is_active = models.BooleanField(default=True) - def __unicode__(self): + def __str__(self): return self.name def slugify(self): @@ -75,7 +73,7 @@ class ReferralLocation(models.Model): address = models.TextField() care_availiable = models.ManyToManyField(ReferralType) - def __unicode__(self): + def __str__(self): if self.address: return self.name + " (" + self.address.splitlines()[0] + ")" else: @@ -85,18 +83,17 @@ def __unicode__(self): class Language(models.Model): name = models.CharField(max_length=50, primary_key=True) - def __unicode__(self): + def __str__(self): return self.name class Ethnicity(models.Model): - class Meta: - verbose_name_plural = "ethnicities" + verbose_name_plural = 'ethnicities' name = models.CharField(max_length=50, primary_key=True) - def __unicode__(self): + def __str__(self): return self.name @@ -104,7 +101,7 @@ class ActionInstruction(models.Model): instruction = models.CharField(max_length=50, primary_key=True) active = models.BooleanField(default=True) - def __unicode__(self): + def __str__(self): return self.instruction @@ -114,21 +111,22 @@ class ProviderType(models.Model): signs_charts = models.BooleanField(default=False) staff_view = models.BooleanField(default=False) - def __unicode__(self): + def __str__(self): return self.short_name class Gender(models.Model): - long_name = models.CharField(max_length=30, primary_key=True) + long_name = models.CharField( + max_length=30, primary_key=True, ) short_name = models.CharField(max_length=1) - def __unicode__(self): + def __str__(self): return self.long_name class Outcome(models.Model): name = models.CharField(max_length=50, primary_key=True) - def __unicode__(self): + def __str__(self): return self.name @@ -184,7 +182,7 @@ class Provider(Person): def username(self): return self.associated_user.username - def __unicode__(self): + def __str__(self): return self.name() @@ -205,13 +203,13 @@ class Patient(Person): country = models.CharField(max_length=100, default="USA") - pcp_preferred_zip = models.CharField(max_length=5, validators=[validators.validate_zip], blank=True, null=True) - date_of_birth = models.DateField(help_text='MM/DD/YYYY', + date_of_birth = models.DateField( + help_text='MM/DD/YYYY', validators=[validators.validate_birth_date]) patient_comfortable_with_english = models.BooleanField(default=True) @@ -248,9 +246,9 @@ class Patient(Person): history = HistoricalRecords() def age(self): - return (now().date() - self.date_of_birth).days//365 + return (now().date() - self.date_of_birth).days // 365 - def __unicode__(self): + def __str__(self): return self.name() def active_action_items(self): @@ -261,7 +259,7 @@ def active_action_items(self): ActionItem.objects.filter(patient=self.pk)\ .filter(completion_author=None)\ .filter(due_date__lte=now().date()), - key=lambda(ai): ai.due_date) + key=lambda ai: ai.due_date) def done_action_items(self): '''return the set of action items that are done, sorted @@ -270,7 +268,7 @@ def done_action_items(self): return sorted( ActionItem.objects.filter(patient=self.pk)\ .exclude(completion_author=None), - key=lambda(ai): ai.completion_date) + key=lambda ai: ai.completion_date) def inactive_action_items(self): '''return a list of action items that aren't done, but aren't @@ -280,7 +278,7 @@ def inactive_action_items(self): ActionItem.objects.filter(patient=self.pk)\ .filter(completion_author=None)\ .filter(due_date__gt=now().date()), - key=lambda(ai): ai.due_date) + key=lambda ai: ai.due_date) def status(self): # The active_action_items, done_action_items, and inactive_action_items @@ -341,7 +339,7 @@ def notes(self): note_list.extend(self.followup_set()) note_list.extend(self.document_set.all()) - return sorted(note_list, key=lambda(k): k.written_datetime) + return sorted(note_list, key=lambda k: k.written_datetime) def all_phones(self): '''Returns a list of tuples of the form (phone, owner) of all the @@ -396,7 +394,7 @@ class Meta: class DocumentType(models.Model): name = models.CharField(max_length=50, primary_key=True) - def __unicode__(self): + def __str__(self): return self.name @@ -528,6 +526,6 @@ def admin_url(self): return reverse('admin:pttrack_actionitem_change', args=(self.id,)) - def __unicode__(self): - return " ".join(["AI for", str(self.patient)+":", + def __str__(self): + return " ".join(["AI for", str(self.patient) + ":", str(self.instruction), "due on", str(self.due_date)]) diff --git a/pttrack/static/apple-touch-icon.png b/osler/pttrack/static/apple-touch-icon.png similarity index 100% rename from pttrack/static/apple-touch-icon.png rename to osler/pttrack/static/apple-touch-icon.png diff --git a/pttrack/static/favicon.ico b/osler/pttrack/static/favicon.ico similarity index 100% rename from pttrack/static/favicon.ico rename to osler/pttrack/static/favicon.ico diff --git a/pttrack/static/pttrack/css/bootstrap-theme.min.css b/osler/pttrack/static/pttrack/css/bootstrap-theme.min.css similarity index 100% rename from pttrack/static/pttrack/css/bootstrap-theme.min.css rename to osler/pttrack/static/pttrack/css/bootstrap-theme.min.css diff --git a/pttrack/static/pttrack/css/bootstrap.min.css b/osler/pttrack/static/pttrack/css/bootstrap.min.css similarity index 100% rename from pttrack/static/pttrack/css/bootstrap.min.css rename to osler/pttrack/static/pttrack/css/bootstrap.min.css diff --git a/pttrack/static/pttrack/fonts/glyphicons-halflings-regular.eot b/osler/pttrack/static/pttrack/fonts/glyphicons-halflings-regular.eot similarity index 100% rename from pttrack/static/pttrack/fonts/glyphicons-halflings-regular.eot rename to osler/pttrack/static/pttrack/fonts/glyphicons-halflings-regular.eot diff --git a/pttrack/static/pttrack/fonts/glyphicons-halflings-regular.svg b/osler/pttrack/static/pttrack/fonts/glyphicons-halflings-regular.svg similarity index 100% rename from pttrack/static/pttrack/fonts/glyphicons-halflings-regular.svg rename to osler/pttrack/static/pttrack/fonts/glyphicons-halflings-regular.svg diff --git a/pttrack/static/pttrack/fonts/glyphicons-halflings-regular.ttf b/osler/pttrack/static/pttrack/fonts/glyphicons-halflings-regular.ttf similarity index 100% rename from pttrack/static/pttrack/fonts/glyphicons-halflings-regular.ttf rename to osler/pttrack/static/pttrack/fonts/glyphicons-halflings-regular.ttf diff --git a/pttrack/static/pttrack/fonts/glyphicons-halflings-regular.woff b/osler/pttrack/static/pttrack/fonts/glyphicons-halflings-regular.woff similarity index 100% rename from pttrack/static/pttrack/fonts/glyphicons-halflings-regular.woff rename to osler/pttrack/static/pttrack/fonts/glyphicons-halflings-regular.woff diff --git a/pttrack/static/pttrack/js/bootstrap.min.js b/osler/pttrack/static/pttrack/js/bootstrap.min.js similarity index 100% rename from pttrack/static/pttrack/js/bootstrap.min.js rename to osler/pttrack/static/pttrack/js/bootstrap.min.js diff --git a/pttrack/static/pttrack/js/jquery-1.11.2.min.js b/osler/pttrack/static/pttrack/js/jquery-1.11.2.min.js similarity index 100% rename from pttrack/static/pttrack/js/jquery-1.11.2.min.js rename to osler/pttrack/static/pttrack/js/jquery-1.11.2.min.js diff --git a/pttrack/static/tile-wide.png b/osler/pttrack/static/tile-wide.png similarity index 100% rename from pttrack/static/tile-wide.png rename to osler/pttrack/static/tile-wide.png diff --git a/pttrack/static/tile.png b/osler/pttrack/static/tile.png similarity index 100% rename from pttrack/static/tile.png rename to osler/pttrack/static/tile.png diff --git a/pttrack/templates/pttrack/about.html b/osler/pttrack/templates/pttrack/about.html similarity index 100% rename from pttrack/templates/pttrack/about.html rename to osler/pttrack/templates/pttrack/about.html diff --git a/pttrack/templates/pttrack/all_patients.html b/osler/pttrack/templates/pttrack/all_patients.html similarity index 100% rename from pttrack/templates/pttrack/all_patients.html rename to osler/pttrack/templates/pttrack/all_patients.html diff --git a/pttrack/templates/pttrack/base-form.html b/osler/pttrack/templates/pttrack/base-form.html similarity index 100% rename from pttrack/templates/pttrack/base-form.html rename to osler/pttrack/templates/pttrack/base-form.html diff --git a/pttrack/templates/pttrack/base.html b/osler/pttrack/templates/pttrack/base.html similarity index 100% rename from pttrack/templates/pttrack/base.html rename to osler/pttrack/templates/pttrack/base.html diff --git a/pttrack/templates/pttrack/blurbs/action-item-blurb-active.html b/osler/pttrack/templates/pttrack/blurbs/action-item-blurb-active.html similarity index 100% rename from pttrack/templates/pttrack/blurbs/action-item-blurb-active.html rename to osler/pttrack/templates/pttrack/blurbs/action-item-blurb-active.html diff --git a/pttrack/templates/pttrack/blurbs/base-completable-blurb.html b/osler/pttrack/templates/pttrack/blurbs/base-completable-blurb.html similarity index 100% rename from pttrack/templates/pttrack/blurbs/base-completable-blurb.html rename to osler/pttrack/templates/pttrack/blurbs/base-completable-blurb.html diff --git a/pttrack/templates/pttrack/clindate.html b/osler/pttrack/templates/pttrack/clindate.html similarity index 100% rename from pttrack/templates/pttrack/clindate.html rename to osler/pttrack/templates/pttrack/clindate.html diff --git a/pttrack/templates/pttrack/document_detail.html b/osler/pttrack/templates/pttrack/document_detail.html similarity index 100% rename from pttrack/templates/pttrack/document_detail.html rename to osler/pttrack/templates/pttrack/document_detail.html diff --git a/pttrack/templates/pttrack/followup-choice.html b/osler/pttrack/templates/pttrack/followup-choice.html similarity index 100% rename from pttrack/templates/pttrack/followup-choice.html rename to osler/pttrack/templates/pttrack/followup-choice.html diff --git a/pttrack/templates/pttrack/form-update.html b/osler/pttrack/templates/pttrack/form-update.html similarity index 100% rename from pttrack/templates/pttrack/form-update.html rename to osler/pttrack/templates/pttrack/form-update.html diff --git a/pttrack/templates/pttrack/form_submission.html b/osler/pttrack/templates/pttrack/form_submission.html similarity index 100% rename from pttrack/templates/pttrack/form_submission.html rename to osler/pttrack/templates/pttrack/form_submission.html diff --git a/pttrack/templates/pttrack/intake.html b/osler/pttrack/templates/pttrack/intake.html similarity index 100% rename from pttrack/templates/pttrack/intake.html rename to osler/pttrack/templates/pttrack/intake.html diff --git a/pttrack/templates/pttrack/new-provider.html b/osler/pttrack/templates/pttrack/new-provider.html similarity index 100% rename from pttrack/templates/pttrack/new-provider.html rename to osler/pttrack/templates/pttrack/new-provider.html diff --git a/pttrack/templates/pttrack/patient-update.html b/osler/pttrack/templates/pttrack/patient-update.html similarity index 100% rename from pttrack/templates/pttrack/patient-update.html rename to osler/pttrack/templates/pttrack/patient-update.html diff --git a/pttrack/templates/pttrack/patient_detail.html b/osler/pttrack/templates/pttrack/patient_detail.html similarity index 100% rename from pttrack/templates/pttrack/patient_detail.html rename to osler/pttrack/templates/pttrack/patient_detail.html diff --git a/pttrack/templates/pttrack/patient_list.html b/osler/pttrack/templates/pttrack/patient_list.html similarity index 100% rename from pttrack/templates/pttrack/patient_list.html rename to osler/pttrack/templates/pttrack/patient_list.html diff --git a/pttrack/templates/pttrack/preintake-select.html b/osler/pttrack/templates/pttrack/preintake-select.html similarity index 100% rename from pttrack/templates/pttrack/preintake-select.html rename to osler/pttrack/templates/pttrack/preintake-select.html diff --git a/pttrack/templates/pttrack/preintake.html b/osler/pttrack/templates/pttrack/preintake.html similarity index 100% rename from pttrack/templates/pttrack/preintake.html rename to osler/pttrack/templates/pttrack/preintake.html diff --git a/pttrack/templates/pttrack/provider-update.html b/osler/pttrack/templates/pttrack/provider-update.html similarity index 100% rename from pttrack/templates/pttrack/provider-update.html rename to osler/pttrack/templates/pttrack/provider-update.html diff --git a/pttrack/templates/pttrack/role-choice.html b/osler/pttrack/templates/pttrack/role-choice.html similarity index 100% rename from pttrack/templates/pttrack/role-choice.html rename to osler/pttrack/templates/pttrack/role-choice.html diff --git a/pttrack/templates/pttrack/workup-choice.html b/osler/pttrack/templates/pttrack/workup-choice.html similarity index 100% rename from pttrack/templates/pttrack/workup-choice.html rename to osler/pttrack/templates/pttrack/workup-choice.html diff --git a/pttrack/templates/pttrack/workup_error.html b/osler/pttrack/templates/pttrack/workup_error.html similarity index 100% rename from pttrack/templates/pttrack/workup_error.html rename to osler/pttrack/templates/pttrack/workup_error.html diff --git a/pttrack/templates/registration/logged_out.html b/osler/pttrack/templates/registration/logged_out.html similarity index 100% rename from pttrack/templates/registration/logged_out.html rename to osler/pttrack/templates/registration/logged_out.html diff --git a/pttrack/templates/registration/login.html b/osler/pttrack/templates/registration/login.html similarity index 100% rename from pttrack/templates/registration/login.html rename to osler/pttrack/templates/registration/login.html diff --git a/pttrack/test.py b/osler/pttrack/test.py similarity index 87% rename from pttrack/test.py rename to osler/pttrack/test.py index b76bcc7..43438cb 100644 --- a/pttrack/test.py +++ b/osler/pttrack/test.py @@ -1,6 +1,6 @@ from django.contrib.staticfiles.testing import StaticLiveServerTestCase -from selenium.webdriver.chrome.webdriver import WebDriver +from selenium.webdriver.chrome import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC @@ -13,7 +13,12 @@ class SeleniumLiveTestCase(StaticLiveServerTestCase): @classmethod def setUpClass(cls): super(SeleniumLiveTestCase, cls).setUpClass() - cls.selenium = WebDriver() + + opt = webdriver.ChromeOptions() + opt.add_experimental_option('w3c', False) + cls.selenium = webdriver.Chrome(chrome_options=opt) + + # cls.selenium = WebDriver() cls.selenium.implicitly_wait(cls.DEFAULT_WAIT_TIME) cls.selenium.set_page_load_timeout(cls.DEFAULT_WAIT_TIME) diff --git a/pttrack/test_forms.py b/osler/pttrack/test_forms.py similarity index 99% rename from pttrack/test_forms.py rename to osler/pttrack/test_forms.py index 355e7ee..c210a6d 100644 --- a/pttrack/test_forms.py +++ b/osler/pttrack/test_forms.py @@ -69,7 +69,7 @@ def setUp(self): 'country': 'Germany', 'zip_code': '63108', 'pcp_preferred_zip': '63018', - 'date_of_birth': datetime.date(1990, 01, 01), + 'date_of_birth': datetime.date(1990, 1, 1), 'patient_comfortable_with_english': False, 'ethnicities': [Ethnicity.objects.create(name="Klingon")], 'preferred_contact_method': diff --git a/pttrack/test_utils.py b/osler/pttrack/test_utils.py similarity index 99% rename from pttrack/test_utils.py rename to osler/pttrack/test_utils.py index 07332b5..9c83dd1 100644 --- a/pttrack/test_utils.py +++ b/osler/pttrack/test_utils.py @@ -83,7 +83,7 @@ def create_pts(): 'zip_code': '63108', 'gender': models.Gender(long_name="Male", short_name="m"), 'pcp_preferred_zip': '63018', - 'date_of_birth': datetime.date(1990, 01, 01), + 'date_of_birth': datetime.date(1990, 1, 1), 'patient_comfortable_with_english': False, 'preferred_contact_method': models.ContactMethod.objects.first(), } diff --git a/pttrack/test_validators.py b/osler/pttrack/test_validators.py similarity index 99% rename from pttrack/test_validators.py rename to osler/pttrack/test_validators.py index c7aa7a2..8d9a56e 100644 --- a/pttrack/test_validators.py +++ b/osler/pttrack/test_validators.py @@ -66,4 +66,4 @@ def test_validate_name(self): with self.assertRaises(ValidationError): validators.validate_name(" Name ") # tab then space with self.assertRaises(ValidationError): - validators.validate_name(" Name ") # space then tab \ No newline at end of file + validators.validate_name(" Name ") # space then tab diff --git a/pttrack/test_views.py b/osler/pttrack/test_views.py similarity index 99% rename from pttrack/test_views.py rename to osler/pttrack/test_views.py index 866205b..2652ba1 100644 --- a/pttrack/test_views.py +++ b/osler/pttrack/test_views.py @@ -1,5 +1,3 @@ -from __future__ import print_function, division - import datetime import json @@ -407,7 +405,7 @@ def setUp(self): 'state': 'BA', 'zip_code': '63108', 'pcp_preferred_zip': '63018', - 'date_of_birth': datetime.date(1990, 01, 01), + 'date_of_birth': datetime.date(1990, 1, 1), 'patient_comfortable_with_english': False, 'preferred_contact_method': models.ContactMethod.objects.first(), } @@ -755,7 +753,7 @@ def test_document_urls(self): title="who done it?", comments="Pictured: silliness", document_type=dtype, - image=File(open(self.test_img)), + image=File(file=open(self.test_img, 'rb')), patient=models.Patient.objects.get(id=1), author=models.Provider.objects.get(id=1), author_type=models.ProviderType.objects.first()) @@ -767,8 +765,8 @@ def test_document_urls(self): self.assertEqual(doc.image.path, p) self.assertTrue(os.path.isfile(p)) - # Checking to make sure the path is 48 characters (the length of the random password - + # Checking to make sure the path is 48 characters (the length of + # the random password self.assertEqual(len(random_name), 48) url = reverse('document-detail', args=(1,)) @@ -778,10 +776,10 @@ def test_document_urls(self): # test the creation of many documents, just in case. for i in range(101): doc = models.Document.objects.create( - title="who done it? "+str(i), + title="who done it? %s" % i, comments="Pictured: silliness", document_type=dtype, - image=File(open(self.test_img)), + image=File(open(self.test_img, 'rb')), patient=models.Patient.objects.get(id=1), author=models.Provider.objects.get(id=1), author_type=models.ProviderType.objects.first()) @@ -793,7 +791,8 @@ def test_document_urls(self): self.assertEqual(doc.image.path, p) self.assertTrue(os.path.isfile(p)) - # Checking to make sure the path is 48 characters (the length of the random password + # Checking to make sure the path is 48 characters (the length + # of the random password self.assertEqual(len(random_name), 48) @@ -941,7 +940,7 @@ def setUp(self): 'country': 'Germany', 'zip_code': '63108', 'pcp_preferred_zip': '63018', - 'date_of_birth': datetime.date(1990, 01, 01), + 'date_of_birth': datetime.date(1990, 1, 1), 'patient_comfortable_with_english': False, 'ethnicities': [models.Ethnicity.objects.first()], 'preferred_contact_method': @@ -1217,7 +1216,7 @@ def setUp(self): state='BA', zip_code='63108', pcp_preferred_zip='63018', - date_of_birth=datetime.date(1990, 01, 01), + date_of_birth=datetime.date(1990, 1, 1), patient_comfortable_with_english=False, preferred_contact_method=self.contact_method, ) @@ -1379,9 +1378,6 @@ def test_patient_detail(self): response = self.client.get(url) self.assertEqual(response.status_code, 200) - with open('tmp.html', 'w') as f: - f.write(response.content) - expected_status = "Action items 1, 0, 0 days past due" self.assertContains(response, expected_status) diff --git a/pttrack/urls.py b/osler/pttrack/urls.py similarity index 94% rename from pttrack/urls.py rename to osler/pttrack/urls.py index 4e8bfd3..7541790 100644 --- a/pttrack/urls.py +++ b/osler/pttrack/urls.py @@ -1,3 +1,5 @@ +import logging + from django.conf.urls import url from django.views.generic import DetailView from django.views.generic.base import TemplateView @@ -8,6 +10,9 @@ from . import models from . import views + +logger = logging.getLogger(__name__) + # pylint: disable=I0011 unwrapped_urlpatterns = [ # pylint: disable=invalid-name @@ -84,9 +89,12 @@ def wrap_url(url, no_wrap=[], login_only=[], provider_only=[], updated_provider_only=[]): - ''' - Wrap URL in decorators as appropriate. - ''' + """Wrap URL in decorators as specified. Handles forcing login to + access pages. + """ + + logger.info('wrap_url intercepted attempt to access %s', url) + if url.name in no_wrap: # do not wrap at all, fully public pass diff --git a/pttrack/utils.py b/osler/pttrack/utils.py similarity index 100% rename from pttrack/utils.py rename to osler/pttrack/utils.py diff --git a/pttrack/validators.py b/osler/pttrack/validators.py similarity index 100% rename from pttrack/validators.py rename to osler/pttrack/validators.py diff --git a/pttrack/views.py b/osler/pttrack/views.py similarity index 99% rename from pttrack/views.py rename to osler/pttrack/views.py index e4f86b8..cb7ffd6 100644 --- a/pttrack/views.py +++ b/osler/pttrack/views.py @@ -22,6 +22,7 @@ from . import utils + def get_current_provider_type(request): ''' Given the request, produce the ProviderType of the logged in user. This is @@ -501,7 +502,6 @@ def all_patients(request): {'object_list': patient_list}) - def patient_activate_detail(request, pk): pt = get_object_or_404(mymodels.Patient, pk=pk) @@ -511,6 +511,7 @@ def patient_activate_detail(request, pk): return HttpResponseRedirect(reverse("patient-detail", args=(pt.id,))) + def patient_activate_home(request, pk): pt = get_object_or_404(mymodels.Patient, pk=pk) @@ -520,6 +521,7 @@ def patient_activate_home(request, pk): return HttpResponseRedirect(reverse("home")) + def done_action_item(request, ai_id): ai = get_object_or_404(mymodels.ActionItem, pk=ai_id) ai.mark_done(request.user.provider) @@ -528,10 +530,10 @@ def done_action_item(request, ai_id): return HttpResponseRedirect(reverse("followup-choice", args=(ai.patient.pk,))) + def reset_action_item(request, ai_id): ai = get_object_or_404(mymodels.ActionItem, pk=ai_id) ai.clear_done() ai.save() return HttpResponseRedirect(reverse("patient-detail", args=(ai.patient.id,))) - diff --git a/referral/__init__.py b/osler/referral/__init__.py similarity index 100% rename from referral/__init__.py rename to osler/referral/__init__.py diff --git a/referral/admin.py b/osler/referral/admin.py similarity index 100% rename from referral/admin.py rename to osler/referral/admin.py diff --git a/referral/forms.py b/osler/referral/forms.py similarity index 99% rename from referral/forms.py rename to osler/referral/forms.py index ef95ed1..75db133 100644 --- a/referral/forms.py +++ b/osler/referral/forms.py @@ -167,7 +167,7 @@ def clean(self): "pt_showed": "patient showed", "has_appointment": "has appointment"} - for param, param_verbose in detail_params.iteritems(): + for param, param_verbose in detail_params.items(): if cleaned_data.get(param): self.add_error( param, diff --git a/referral/migrations/0001_initial.py b/osler/referral/migrations/0001_initial.py similarity index 100% rename from referral/migrations/0001_initial.py rename to osler/referral/migrations/0001_initial.py diff --git a/referral/migrations/0002_auto_20190902_2116.py b/osler/referral/migrations/0002_auto_20190902_2116.py similarity index 100% rename from referral/migrations/0002_auto_20190902_2116.py rename to osler/referral/migrations/0002_auto_20190902_2116.py diff --git a/referral/migrations/__init__.py b/osler/referral/migrations/__init__.py similarity index 100% rename from referral/migrations/__init__.py rename to osler/referral/migrations/__init__.py diff --git a/referral/models.py b/osler/referral/models.py similarity index 99% rename from referral/models.py rename to osler/referral/models.py index 92fd4bf..eb122f8 100644 --- a/referral/models.py +++ b/osler/referral/models.py @@ -33,7 +33,7 @@ class Referral(Note): help_text="The kind of care the patient should recieve at the " "referral location.") - def __unicode__(self): + def __str__(self): """Provides string to display on front end for referral. For FQHC referrals, returns referral kind and date. @@ -96,7 +96,7 @@ def admin_url(self): args=(self.id,) ) - def __unicode__(self): + def __str__(self): formatted_date = self.due_date.strftime("%D") return 'Followup with %s on %s about %s' % (self.patient, formatted_date, diff --git a/referral/templates/referral/new-FQHC-referral.html b/osler/referral/templates/referral/new-FQHC-referral.html similarity index 100% rename from referral/templates/referral/new-FQHC-referral.html rename to osler/referral/templates/referral/new-FQHC-referral.html diff --git a/referral/templates/referral/new-followup-request.html b/osler/referral/templates/referral/new-followup-request.html similarity index 100% rename from referral/templates/referral/new-followup-request.html rename to osler/referral/templates/referral/new-followup-request.html diff --git a/referral/templates/referral/new-patient-contact.html b/osler/referral/templates/referral/new-patient-contact.html similarity index 100% rename from referral/templates/referral/new-patient-contact.html rename to osler/referral/templates/referral/new-patient-contact.html diff --git a/referral/templates/referral/new-referral.html b/osler/referral/templates/referral/new-referral.html similarity index 100% rename from referral/templates/referral/new-referral.html rename to osler/referral/templates/referral/new-referral.html diff --git a/referral/templates/referral/new-specialty-referral.html b/osler/referral/templates/referral/new-specialty-referral.html similarity index 100% rename from referral/templates/referral/new-specialty-referral.html rename to osler/referral/templates/referral/new-specialty-referral.html diff --git a/referral/templates/referral/select-referral-type.html b/osler/referral/templates/referral/select-referral-type.html similarity index 100% rename from referral/templates/referral/select-referral-type.html rename to osler/referral/templates/referral/select-referral-type.html diff --git a/referral/templates/referral/select-referral.html b/osler/referral/templates/referral/select-referral.html similarity index 100% rename from referral/templates/referral/select-referral.html rename to osler/referral/templates/referral/select-referral.html diff --git a/referral/tests.py b/osler/referral/tests.py similarity index 98% rename from referral/tests.py rename to osler/referral/tests.py index cf28a80..1fc054b 100644 --- a/referral/tests.py +++ b/osler/referral/tests.py @@ -42,7 +42,7 @@ def setUp(self): state='BA', zip_code='63108', pcp_preferred_zip='63018', - date_of_birth=datetime.date(1990, 01, 01), + date_of_birth=datetime.date(1990, 1, 1), patient_comfortable_with_english=False, preferred_contact_method=self.contact_method, ) @@ -66,7 +66,7 @@ def setUp(self): self.followup_request = models.FollowupRequest.objects.create( referral=self.referral, contact_instructions="Call him", - due_date=datetime.date(2018, 9, 01), + due_date=datetime.date(2018, 9, 1), author=Provider.objects.first(), author_type=ProviderType.objects.first(), patient=self.pt @@ -333,7 +333,7 @@ def setUp(self): state='BA', zip_code='63108', pcp_preferred_zip='63018', - date_of_birth=datetime.date(1990, 01, 01), + date_of_birth=datetime.date(1990, 1, 1), patient_comfortable_with_english=False, preferred_contact_method=self.contact_method, ) @@ -396,7 +396,7 @@ def setUp(self): state='BA', zip_code='63108', pcp_preferred_zip='63018', - date_of_birth=datetime.date(1990, 01, 01), + date_of_birth=datetime.date(1990, 1, 1), patient_comfortable_with_english=False, preferred_contact_method=self.contact_method, ) @@ -494,7 +494,7 @@ def setUp(self): state='BA', zip_code='63108', pcp_preferred_zip='63018', - date_of_birth=datetime.date(1990, 01, 01), + date_of_birth=datetime.date(1990, 1, 1), patient_comfortable_with_english=False, preferred_contact_method=self.contact_method, ) @@ -524,7 +524,7 @@ def test_referral_list(self): models.FollowupRequest.objects.create( referral=referral1, contact_instructions="Call him", - due_date=datetime.date(2018, 11, 01), + due_date=datetime.date(2018, 11, 1), author=Provider.objects.first(), author_type=ProviderType.objects.first(), patient=self.pt @@ -558,7 +558,7 @@ def test_referral_list(self): state='BA', zip_code='63108', pcp_preferred_zip='63018', - date_of_birth=datetime.date(1994, 01, 22), + date_of_birth=datetime.date(1994, 1, 22), patient_comfortable_with_english=False, preferred_contact_method=self.contact_method, ) @@ -582,7 +582,7 @@ def test_referral_list(self): models.FollowupRequest.objects.create( referral=referral3, contact_instructions="Call him", - due_date=datetime.date(2018, 11, 01), + due_date=datetime.date(2018, 11, 1), author=Provider.objects.first(), author_type=ProviderType.objects.first(), patient=pt2 @@ -694,7 +694,7 @@ def setUp(self): state='BA', zip_code='63108', pcp_preferred_zip='63018', - date_of_birth=datetime.date(1990, 01, 01), + date_of_birth=datetime.date(1990, 1, 1), patient_comfortable_with_english=False, preferred_contact_method=self.contact_method, ) @@ -724,7 +724,7 @@ def test_valid_input(self): followup_request1 = models.FollowupRequest.objects.create( referral=referral1, contact_instructions="Call him", - due_date=datetime.date(2018, 11, 01), + due_date=datetime.date(2018, 11, 1), author=Provider.objects.first(), author_type=ProviderType.objects.first(), patient=self.pt diff --git a/referral/urls.py b/osler/referral/urls.py similarity index 99% rename from referral/urls.py rename to osler/referral/urls.py index d9d1c84..ea5b847 100644 --- a/referral/urls.py +++ b/osler/referral/urls.py @@ -24,4 +24,5 @@ ] wrap_config = {} + urlpatterns = [wrap_url(u, **wrap_config) for u in unwrapped_urlconf] diff --git a/referral/views.py b/osler/referral/views.py similarity index 100% rename from referral/views.py rename to osler/referral/views.py diff --git a/scripts/check_unsigned.py b/osler/scripts/check_unsigned.py similarity index 100% rename from scripts/check_unsigned.py rename to osler/scripts/check_unsigned.py diff --git a/scripts/debug_init_db.py b/osler/scripts/debug_init_db.py similarity index 99% rename from scripts/debug_init_db.py rename to osler/scripts/debug_init_db.py index df38488..f3b3684 100755 --- a/scripts/debug_init_db.py +++ b/osler/scripts/debug_init_db.py @@ -49,4 +49,4 @@ p.languages.add(models.Language.objects.all()[0]) p.ethnicities.add(models.Ethnicity.objects.all()[0]) -print "Done!" +print("Done!") diff --git a/scripts/deploy_migrate.sh b/osler/scripts/deploy_migrate.sh similarity index 100% rename from scripts/deploy_migrate.sh rename to osler/scripts/deploy_migrate.sh diff --git a/scripts/init_db.py b/osler/scripts/init_db.py similarity index 77% rename from scripts/init_db.py rename to osler/scripts/init_db.py index 4a267fa..6e3e826 100755 --- a/scripts/init_db.py +++ b/osler/scripts/init_db.py @@ -76,37 +76,37 @@ d.save() for referral_location in [ - "Back to SNHC", "SNHC Depression and Anxiety Specialty Night", - "SNHC Dermatology Specialty Night", "SNHC OB/GYN Specialty Night", - "Barnes Jewish Center for Outpatient Health (COH)", - "BJC Behavioral Health (for Psych)", - "St. Louis Dental Education and Oral Health Clinic", - "St. Louis County Department of Health: South County Health Center", - "Other"]: + "Back to SNHC", "SNHC Depression and Anxiety Specialty Night", + "SNHC Dermatology Specialty Night", "SNHC OB/GYN Specialty Night", + "Barnes Jewish Center for Outpatient Health (COH)", + "BJC Behavioral Health (for Psych)", + "St. Louis Dental Education and Oral Health Clinic", + "St. Louis County Department of Health: South County Health Center", + "Other"]: f = core.ReferralLocation(name=referral_location) f.save() for noapt_reason in [ - "Not interested in further medical care at this time", - "Too busy/forgot to contact provider", - "Lost provider contact information", - "Cannot reach provider", - "Contacted provider but did not successfully schedule appointment", - "Appointment wait time is too long", - "No transportation to get to appointment", - "Appointment times do not work with patient's schedule", - "Cannot afford appointment", "Other"]: + "Not interested in further medical care at this time", + "Too busy/forgot to contact provider", + "Lost provider contact information", + "Cannot reach provider", + "Contacted provider but did not successfully schedule appointment", + "Appointment wait time is too long", + "No transportation to get to appointment", + "Appointment times do not work with patient's schedule", + "Cannot afford appointment", "Other"]: s = followup.NoAptReason(name=noapt_reason) s.save() for noshow_reason in [ - "Schedule changed in conflict with appointment", - "Didn't have transportation to appointment", - "Worried about cost of appointment", - "Too sick to go to appointment", - "Felt better and decided didn't need appointment", - "Someone counseled patient against appointment", - "Forgot about appointment"]: + "Schedule changed in conflict with appointment", + "Didn't have transportation to appointment", + "Worried about cost of appointment", + "Too sick to go to appointment", + "Felt better and decided didn't need appointment", + "Someone counseled patient against appointment", + "Forgot about appointment"]: s = followup.NoShowReason(name=noshow_reason) s.save() @@ -128,4 +128,4 @@ core.DocumentType.objects.create(name="Silly picture") -print "done!" +print("done!") diff --git a/scripts/reset_db.bat b/osler/scripts/reset_db.bat similarity index 100% rename from scripts/reset_db.bat rename to osler/scripts/reset_db.bat diff --git a/scripts/reset_db.sh b/osler/scripts/reset_db.sh similarity index 100% rename from scripts/reset_db.sh rename to osler/scripts/reset_db.sh diff --git a/osler/scripts/wait_for_postgres.sh b/osler/scripts/wait_for_postgres.sh new file mode 100644 index 0000000..b7aaff1 --- /dev/null +++ b/osler/scripts/wait_for_postgres.sh @@ -0,0 +1,16 @@ +#!/bin/bash +# wait-for-postgres.sh + +set -e + +host="$1" +shift +cmd="$@" + +until PGPASSWORD=$POSTGRES_PASSWORD psql -h "$host" -U "postgres" -c '\q'; do + >&2 echo "Postgres is unavailable - sleeping" + sleep 1 +done + +>&2 echo "Postgres is up - executing command" +exec $cmd diff --git a/static/.gitignore b/osler/static/.gitignore similarity index 100% rename from static/.gitignore rename to osler/static/.gitignore diff --git a/workup/__init__.py b/osler/workup/__init__.py similarity index 100% rename from workup/__init__.py rename to osler/workup/__init__.py diff --git a/workup/admin.py b/osler/workup/admin.py similarity index 100% rename from workup/admin.py rename to osler/workup/admin.py diff --git a/workup/fixtures/workup.json b/osler/workup/fixtures/workup.json similarity index 100% rename from workup/fixtures/workup.json rename to osler/workup/fixtures/workup.json diff --git a/workup/forms.py b/osler/workup/forms.py similarity index 99% rename from workup/forms.py rename to osler/workup/forms.py index 13b03fd..eef463d 100644 --- a/workup/forms.py +++ b/osler/workup/forms.py @@ -8,7 +8,8 @@ from crispy_forms.layout import Submit, Layout, Div, Row, HTML from crispy_forms.layout import Field as CrispyField from crispy_forms.bootstrap import ( - InlineCheckboxes, AppendedText, PrependedText) + InlineCheckboxes, AppendedText, PrependedText +) from crispy_forms.utils import TEMPLATE_PACK, render_field from pttrack.models import Provider, ProviderType diff --git a/workup/management/__init__.py b/osler/workup/management/__init__.py similarity index 100% rename from workup/management/__init__.py rename to osler/workup/management/__init__.py diff --git a/workup/management/commands/__init__.py b/osler/workup/management/commands/__init__.py similarity index 100% rename from workup/management/commands/__init__.py rename to osler/workup/management/commands/__init__.py diff --git a/workup/management/commands/unsigned_wu_notify.py b/osler/workup/management/commands/unsigned_wu_notify.py similarity index 100% rename from workup/management/commands/unsigned_wu_notify.py rename to osler/workup/management/commands/unsigned_wu_notify.py diff --git a/workup/migrations/0001_initial.py b/osler/workup/migrations/0001_initial.py similarity index 96% rename from workup/migrations/0001_initial.py rename to osler/workup/migrations/0001_initial.py index 705bc06..a0b179f 100644 --- a/workup/migrations/0001_initial.py +++ b/osler/workup/migrations/0001_initial.py @@ -12,15 +12,15 @@ class Migration(migrations.Migration): replaces = [ - (b'workup', '0002_add_verbose_names'), - (b'workup', '0003_auto_20160122_1631'), - (b'workup', '0004_auto_20160328_1425'), - (b'workup', '0005_auto_20160826_0620'), - (b'workup', '0007_auto_20170502_1107'), - (b'workup', '0008_auto_20170623_1048'), - (b'workup', '0009_vitals_to_numeric_type'), - (b'workup', '0010_decimal_fields_and_validation'), - (b'workup', '0011_historicalprogressnote_progressnote')] + ('workup', '0002_add_verbose_names'), + ('workup', '0003_auto_20160122_1631'), + ('workup', '0004_auto_20160328_1425'), + ('workup', '0005_auto_20160826_0620'), + ('workup', '0007_auto_20170502_1107'), + ('workup', '0008_auto_20170623_1048'), + ('workup', '0009_vitals_to_numeric_type'), + ('workup', '0010_decimal_fields_and_validation'), + ('workup', '0011_historicalprogressnote_progressnote')] dependencies = [ ('pttrack', '0001_squashed_0010_auto_20170623_1300'), diff --git a/workup/migrations/0002_simplehistory_add_change_reason.py b/osler/workup/migrations/0002_simplehistory_add_change_reason.py similarity index 100% rename from workup/migrations/0002_simplehistory_add_change_reason.py rename to osler/workup/migrations/0002_simplehistory_add_change_reason.py diff --git a/workup/migrations/0003_historicalworkup_add_attending_validator_20190324_1133.py b/osler/workup/migrations/0003_historicalworkup_add_attending_validator_20190324_1133.py similarity index 100% rename from workup/migrations/0003_historicalworkup_add_attending_validator_20190324_1133.py rename to osler/workup/migrations/0003_historicalworkup_add_attending_validator_20190324_1133.py diff --git a/workup/migrations/0004_add_progressnote_signing_20190813_2018.py b/osler/workup/migrations/0004_add_progressnote_signing_20190813_2018.py similarity index 100% rename from workup/migrations/0004_add_progressnote_signing_20190813_2018.py rename to osler/workup/migrations/0004_add_progressnote_signing_20190813_2018.py diff --git a/workup/migrations/0005_set_orderings_and_db_do_nothing_20190902_2116.py b/osler/workup/migrations/0005_set_orderings_and_db_do_nothing_20190902_2116.py similarity index 100% rename from workup/migrations/0005_set_orderings_and_db_do_nothing_20190902_2116.py rename to osler/workup/migrations/0005_set_orderings_and_db_do_nothing_20190902_2116.py diff --git a/workup/migrations/0006_remove_clinicdate_gcal_id.py b/osler/workup/migrations/0006_remove_clinicdate_gcal_id.py similarity index 100% rename from workup/migrations/0006_remove_clinicdate_gcal_id.py rename to osler/workup/migrations/0006_remove_clinicdate_gcal_id.py diff --git a/workup/migrations/__init__.py b/osler/workup/migrations/__init__.py similarity index 100% rename from workup/migrations/__init__.py rename to osler/workup/migrations/__init__.py diff --git a/workup/models.py b/osler/workup/models.py similarity index 98% rename from workup/models.py rename to osler/workup/models.py index 51962a8..b04a3fa 100644 --- a/workup/models.py +++ b/osler/workup/models.py @@ -23,7 +23,7 @@ class Meta: name = models.CharField(max_length=100, primary_key=True) - def __unicode__(self): + def __str__(self): return self.name @@ -34,7 +34,7 @@ class Meta: name = models.CharField(max_length=50) - def __unicode__(self): + def __str__(self): return self.name @@ -47,7 +47,7 @@ class Meta: clinic_date = models.DateField() - def __unicode__(self): + def __str__(self): return (str(self.clinic_type) + " on " + datetime.datetime.strftime(self.clinic_date, '%A, %B %d, %Y')) @@ -109,6 +109,7 @@ def sign(self, user, active_role=None): "Provider {p} doesn't have role {r}!".format( p=user.provider, r=active_role)) + if active_role.signs_charts: assert active_role in user.provider.clinical_roles.all() @@ -269,5 +270,5 @@ def written_date(self): def url(self): return reverse('workup', args=(self.pk,)) - def __unicode__(self): + def __str__(self): return self.patient.name() + " on " + str(self.clinic_day.clinic_date) diff --git a/workup/templates/workup/appended_radios.html b/osler/workup/templates/workup/appended_radios.html similarity index 100% rename from workup/templates/workup/appended_radios.html rename to osler/workup/templates/workup/appended_radios.html diff --git a/workup/templates/workup/clindate-list.html b/osler/workup/templates/workup/clindate-list.html similarity index 100% rename from workup/templates/workup/clindate-list.html rename to osler/workup/templates/workup/clindate-list.html diff --git a/workup/templates/workup/new-note-dispatch.html b/osler/workup/templates/workup/new-note-dispatch.html similarity index 100% rename from workup/templates/workup/new-note-dispatch.html rename to osler/workup/templates/workup/new-note-dispatch.html diff --git a/workup/templates/workup/progressnote_detail.html b/osler/workup/templates/workup/progressnote_detail.html similarity index 100% rename from workup/templates/workup/progressnote_detail.html rename to osler/workup/templates/workup/progressnote_detail.html diff --git a/workup/templates/workup/workup-create.html b/osler/workup/templates/workup/workup-create.html similarity index 100% rename from workup/templates/workup/workup-create.html rename to osler/workup/templates/workup/workup-create.html diff --git a/workup/templates/workup/workup_body.html b/osler/workup/templates/workup/workup_body.html similarity index 100% rename from workup/templates/workup/workup_body.html rename to osler/workup/templates/workup/workup_body.html diff --git a/workup/templates/workup/workup_detail.html b/osler/workup/templates/workup/workup_detail.html similarity index 100% rename from workup/templates/workup/workup_detail.html rename to osler/workup/templates/workup/workup_detail.html diff --git a/workup/test_forms.py b/osler/workup/test_forms.py similarity index 100% rename from workup/test_forms.py rename to osler/workup/test_forms.py diff --git a/workup/test_models.py b/osler/workup/test_models.py similarity index 100% rename from workup/test_models.py rename to osler/workup/test_models.py diff --git a/workup/test_views.py b/osler/workup/test_views.py similarity index 100% rename from workup/test_views.py rename to osler/workup/test_views.py diff --git a/workup/tests.py b/osler/workup/tests.py similarity index 99% rename from workup/tests.py rename to osler/workup/tests.py index f4c29cf..e8402ab 100644 --- a/workup/tests.py +++ b/osler/workup/tests.py @@ -104,9 +104,6 @@ def test_create_clindate(self): reverse('new-clindate', args=(pt.id,)), {'clinic_type': models.ClinicType.objects.first().pk}) - with open('tmp.html', 'w') as f: - f.write(r.content) - self.assertRedirects(r, reverse('new-workup', args=(pt.id,))) self.assertEqual(models.ClinicDate.objects.count(), 1) diff --git a/workup/urls.py b/osler/workup/urls.py similarity index 100% rename from workup/urls.py rename to osler/workup/urls.py diff --git a/workup/validators.py b/osler/workup/validators.py similarity index 100% rename from workup/validators.py rename to osler/workup/validators.py diff --git a/workup/views.py b/osler/workup/views.py similarity index 99% rename from workup/views.py rename to osler/workup/views.py index 84b5a17..2530007 100644 --- a/workup/views.py +++ b/osler/workup/views.py @@ -4,7 +4,6 @@ from django.core.urlresolvers import reverse from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger - from django.template.loader import get_template from django.utils.timezone import now from django.views.generic.edit import FormView @@ -161,7 +160,7 @@ def form_valid(self, form): if pnote.author_type.signs_charts: pnote.sign(self.request.user, active_provider_type) pnote.save() - + form.save_m2m() return HttpResponseRedirect(reverse("patient-detail", args=(pt.id,))) @@ -246,7 +245,7 @@ def sign_progress_note(request, pk): pass return HttpResponseRedirect(reverse("progress-note-detail", args=(wu.id,))) - + def error_workup(request, pk): wu = get_object_or_404(models.Workup, pk=pk) diff --git a/requirements-prod.txt b/requirements-prod.txt new file mode 100644 index 0000000..c509fb1 --- /dev/null +++ b/requirements-prod.txt @@ -0,0 +1,3 @@ +-r requirements.txt +gunicorn==19.9.0 +psycopg2-binary==2.7.5 diff --git a/requirements.txt b/requirements.txt index 035d0e2..3cb8d2a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,4 @@ +django-sendfile2==0.4.2 Django==1.11.23 django-bootstrap3==11.0.0 git+https://github.com/inducer/django-bootstrap3-datetimepicker.git @@ -7,7 +8,7 @@ djangorestframework==3.4.0 ecdsa==0.13 html5lib==1.0.1 httplib2==0.11.3 -Pillow==5.1.0 +Pillow==6.2.1 PyPDF2==1.26.0 reportlab==3.4.0 six==1.11.0 diff --git a/static/media/.gitignore b/static/media/.gitignore deleted file mode 100644 index d6b7ef3..0000000 --- a/static/media/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -* -!.gitignore