Initial commit
This commit is contained in:
1
webservice/apps/synthea/__init__.py
Normal file
1
webservice/apps/synthea/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
default_app_config = 'apps.synthea.apps.SyntheaConfig'
|
3
webservice/apps/synthea/admin.py
Normal file
3
webservice/apps/synthea/admin.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from django.contrib import admin
|
||||
|
||||
# Register your models here.
|
10
webservice/apps/synthea/apps.py
Normal file
10
webservice/apps/synthea/apps.py
Normal file
@@ -0,0 +1,10 @@
|
||||
from django.apps import AppConfig
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from django.conf import settings
|
||||
|
||||
class SyntheaConfig(AppConfig):
|
||||
name = 'apps.synthea'
|
||||
label = 'synthea'
|
||||
verbose_name = _('Synthea')
|
||||
verbose_name_plural = _('Synthea')
|
27
webservice/apps/synthea/forms.py
Normal file
27
webservice/apps/synthea/forms.py
Normal file
@@ -0,0 +1,27 @@
|
||||
from django.forms import ModelForm
|
||||
from django import forms
|
||||
|
||||
from apps.synthea.models import Synthea
|
||||
|
||||
from .lib.utils import available_states, available_modules
|
||||
|
||||
class SyntheaForm(ModelForm):
|
||||
|
||||
class Meta:
|
||||
model = Synthea
|
||||
fields = ['state', 'population', 'gender', 'age', 'module']
|
||||
|
||||
# This is loaded only once during startup. So changing the state data will not be picked up after a restart
|
||||
state_options = [('','Any')]
|
||||
for item in available_states():
|
||||
state_options.append((item,item))
|
||||
|
||||
module_options = [('','Any')]
|
||||
for item in available_modules():
|
||||
module_options.append((item['module'],item['name']))
|
||||
|
||||
widgets = {
|
||||
'state': forms.Select(choices=state_options),
|
||||
'gender': forms.Select(choices=[('','Any'),('m','Male'),('f','Female')]),
|
||||
'module': forms.Select(choices=module_options)
|
||||
}
|
83
webservice/apps/synthea/lib/utils.py
Normal file
83
webservice/apps/synthea/lib/utils.py
Normal file
@@ -0,0 +1,83 @@
|
||||
from pathlib import Path
|
||||
import pandas as pd
|
||||
import shlex
|
||||
import subprocess
|
||||
from zipfile import ZipFile
|
||||
import json
|
||||
|
||||
def available_states():
|
||||
#TODO: Make a setting for this path
|
||||
location = Path('/opt/development/synthea_webservice/synthea/src/main/resources/geography/')
|
||||
|
||||
df = pd.read_csv(location / 'timezones.csv', index_col=False)
|
||||
# The state information is expected in the first column
|
||||
states = df[df.columns[0]].to_list()
|
||||
states.sort()
|
||||
return states
|
||||
|
||||
def available_modules():
|
||||
#TODO: Make a setting for this path
|
||||
location = Path('/opt/development/synthea_webservice/synthea/src/main/resources/modules/')
|
||||
|
||||
# Assumption here: A folder is a single module. And all .json in the main modules folder is a module.
|
||||
modules = []
|
||||
for module in location.iterdir():
|
||||
if module.is_file() and module.suffix == '.json':
|
||||
data = json.loads(module.read_text())
|
||||
modules.append({'module' : module.name.replace('.json',''), 'name' : data['name']})
|
||||
|
||||
modules = sorted(modules, key=lambda k: k['name'].lower())
|
||||
return modules
|
||||
|
||||
def run_synthea(state = None, population = None, gender = None, age = None, module = None):
|
||||
# TODO: Make synthea setting(s)
|
||||
location = '/opt/development/synthea_webservice/synthea/'
|
||||
synthea_cmd = ['/opt/development/synthea_webservice/synthea/run_synthea']
|
||||
zip_file = 'Synthea_'
|
||||
zip_export = location
|
||||
|
||||
if population:
|
||||
synthea_cmd.append('-p')
|
||||
synthea_cmd.append(str(population))
|
||||
zip_file += f'population_{population}_'
|
||||
|
||||
if gender:
|
||||
synthea_cmd.append('-g')
|
||||
synthea_cmd.append(gender.upper())
|
||||
zip_file += f'gender_{gender}_'
|
||||
|
||||
if age:
|
||||
synthea_cmd.append('-a')
|
||||
synthea_cmd.append(age)
|
||||
zip_file += f'age_{age}_'
|
||||
|
||||
if module:
|
||||
synthea_cmd.append('-m')
|
||||
synthea_cmd.append(module)
|
||||
zip_file += f'module_{module}_'
|
||||
|
||||
if state:
|
||||
synthea_cmd.append(state)
|
||||
zip_file += f'state_{state}'
|
||||
|
||||
process_ok = False
|
||||
log = ''
|
||||
with subprocess.Popen(synthea_cmd,cwd=location, stdout=subprocess.PIPE,stderr=subprocess.PIPE) as process:
|
||||
for line in process.stdout:
|
||||
line = line.decode('utf8')
|
||||
log += line
|
||||
if not process_ok:
|
||||
process_ok = line.find('BUILD SUCCESSFUL') >= 0
|
||||
|
||||
if process_ok:
|
||||
with ZipFile(f'{zip_export}/{zip_file}.zip', 'w') as export:
|
||||
for file in Path(location + 'output/fhir_stu3').iterdir():
|
||||
export.write(file,file.name)
|
||||
|
||||
return Path(f'{zip_export}/{zip_file}.zip')
|
||||
else:
|
||||
raise Exception(log)
|
||||
|
||||
|
||||
|
||||
|
32
webservice/apps/synthea/migrations/0001_initial.py
Normal file
32
webservice/apps/synthea/migrations/0001_initial.py
Normal file
@@ -0,0 +1,32 @@
|
||||
# Generated by Django 3.1.3 on 2020-11-13 09:36
|
||||
|
||||
from django.db import migrations, models
|
||||
import uuid
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Synthea',
|
||||
fields=[
|
||||
('created_at', models.DateTimeField(auto_now_add=True, help_text='The date and time this model has been created', verbose_name='Date created')),
|
||||
('updated_at', models.DateTimeField(auto_now=True, help_text='The date and time this model has been updated', verbose_name='Date updated')),
|
||||
('id', models.UUIDField(default=uuid.uuid4, editable=False, help_text='A unique id', primary_key=True, serialize=False, unique=True, verbose_name='ID')),
|
||||
('state', models.CharField(help_text='The state for which synthea generate data.', max_length=200, verbose_name='Stage')),
|
||||
('population', models.PositiveSmallIntegerField(default=50, help_text='The size of the population', verbose_name='Population')),
|
||||
('gender', models.CharField(help_text='Select the gender type', max_length=1, verbose_name='Gender')),
|
||||
('age', models.CharField(help_text='Select the age range', max_length=10, verbose_name='Age range')),
|
||||
('module', models.CharField(help_text='Select the module', max_length=50, verbose_name='Mopdule')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'token',
|
||||
'verbose_name_plural': 'tokens',
|
||||
},
|
||||
),
|
||||
]
|
0
webservice/apps/synthea/migrations/__init__.py
Normal file
0
webservice/apps/synthea/migrations/__init__.py
Normal file
24
webservice/apps/synthea/models.py
Normal file
24
webservice/apps/synthea/models.py
Normal file
@@ -0,0 +1,24 @@
|
||||
from django.contrib.auth.models import User
|
||||
from django.db import models
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from django_cryptography.fields import encrypt
|
||||
|
||||
from lib.utils.general import get_random_string
|
||||
from lib.models.base import MetaDataModel
|
||||
|
||||
import uuid
|
||||
|
||||
# Create your models here.
|
||||
class Synthea(MetaDataModel):
|
||||
|
||||
class Meta:
|
||||
verbose_name = _('token')
|
||||
verbose_name_plural = _('tokens')
|
||||
|
||||
id = models.UUIDField(_('ID'), primary_key=True, unique=True, default=uuid.uuid4, editable=False, help_text=_('A unique id'))
|
||||
state = models.CharField(_('State'), max_length=200, help_text=_('The state for which synthea generate data.'))
|
||||
population = models.PositiveSmallIntegerField(_('Population'), blank=True, default=50, help_text=_('The size of the population'))
|
||||
gender = models.CharField(_('Gender'), blank=True,max_length=1, help_text=_('Select the gender type'))
|
||||
age = models.CharField(_('Age range'), blank=True,max_length=10, help_text=_('Select the age range'))
|
||||
module = models.CharField(_('Module'),blank=True, max_length=50, help_text=_('Select the module'))
|
@@ -0,0 +1,21 @@
|
||||
{% extends 'base.html' %} <!-- Add this for inheritance -->
|
||||
{% load i18n %}
|
||||
|
||||
{% block title %}{% trans "Generate a new Synthea data set" %}{% endblock %}
|
||||
{% block pagetitle %}{% trans "Generate a new Synthea data set" %}{% endblock %}
|
||||
|
||||
{% block menu %}
|
||||
{% include 'synthea/menu.html' %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1>Synthea generartor</h1>
|
||||
<p>Enter the form fields and press submit. <small>U vraagt, wij draaien ;)</small></p>
|
||||
<form method="POST" class="post-form">
|
||||
{% csrf_token %}
|
||||
<table>
|
||||
{{ form.as_table }}
|
||||
</table>
|
||||
<button type="submit" class="save btn btn-default">Save</button>
|
||||
</form>
|
||||
{% endblock %}
|
14
webservice/apps/synthea/templates/synthea/index.html
Normal file
14
webservice/apps/synthea/templates/synthea/index.html
Normal file
@@ -0,0 +1,14 @@
|
||||
{% extends 'base.html' %} <!-- Add this for inheritance -->
|
||||
{% load i18n %}
|
||||
|
||||
{% block title %}{% trans "dHealth Synthea" %}{% endblock %}
|
||||
{% block pagetitle %}{% trans "dHealth Synthea" %}{% endblock %}
|
||||
|
||||
{% block menu %}
|
||||
{% include 'synthea/menu.html' %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1>dHealt Nederland</h1>
|
||||
<p>Onder leiding van UMCG</p>
|
||||
{% endblock %}
|
17
webservice/apps/synthea/templates/synthea/menu.html
Normal file
17
webservice/apps/synthea/templates/synthea/menu.html
Normal file
@@ -0,0 +1,17 @@
|
||||
{% load i18n %}
|
||||
<li class="rug-nav--secondary__item">
|
||||
<a class="rug-nav--secondary__link js--togglable-switch" data-toggle-class="rug-nav--secondary__link--selected" data-toggle-group="submenu" data-toggle-id="menu-2427370b-9435-44d9-bca7-b93ec9d03cc0-33.31" data-toggle-mode="togglable">{% trans "Menu" %}</a>
|
||||
<ul class="rug-nav--secondary__sub rug-nav--secondary__sub--hidden js--togglable-item" data-toggle-class="rug-block" data-toggle-group="submenu" data-toggle-id="menu-2427370b-9435-44d9-bca7-b93ec9d03cc0-33.31">
|
||||
<li class="rug-nav--secondary__sub__item" data-menu-id="b512aa55-f0cb-4588-9054-302caa5fa951-33.34">
|
||||
<a class="rug-nav--secondary__sub__link" href="{% url 'index' %}"><span class="rug-nav--secondary__sub__link-text">{% trans "Informatie" %}</span></a>
|
||||
</li>
|
||||
<li class="rug-nav--secondary__sub__item" data-menu-id="b512aa55-f0cb-4588-9054-302caa5fa951-33.35">
|
||||
<a class="rug-nav--secondary__sub__link" href="{% url 'generator_form' %}"><span class="rug-nav--secondary__sub__link-text">{% trans "Generator" %}</span></a>
|
||||
</li>
|
||||
|
||||
<li class="rug-nav--secondary__sub__item" data-menu-id="b512aa55-f0cb-4588-9054-302caa5fa951-33.36">
|
||||
<a class="rug-nav--secondary__sub__link" href="{% url 'api_info' %}"><span class="rug-nav--secondary__sub__link-text">{% trans "API" %}</span></a>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</li>
|
3
webservice/apps/synthea/tests.py
Normal file
3
webservice/apps/synthea/tests.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
9
webservice/apps/synthea/urls.py
Normal file
9
webservice/apps/synthea/urls.py
Normal file
@@ -0,0 +1,9 @@
|
||||
from django.urls import path, include
|
||||
|
||||
from . import views
|
||||
|
||||
urlpatterns = [
|
||||
path('', views.index, name='index'),
|
||||
path('api/', views.index, name='api_info'),
|
||||
path('generate/', views.show_synthea_form, name='generator_form'),
|
||||
]
|
49
webservice/apps/synthea/views.py
Normal file
49
webservice/apps/synthea/views.py
Normal file
@@ -0,0 +1,49 @@
|
||||
from django.shortcuts import render
|
||||
from django.http import HttpResponse
|
||||
from apps.synthea.forms import SyntheaForm
|
||||
|
||||
from .lib.utils import run_synthea
|
||||
|
||||
import mimetypes
|
||||
# Create your views here.
|
||||
|
||||
def index(request):
|
||||
template_name = 'synthea/index.html'
|
||||
return render(request,template_name,{})
|
||||
|
||||
def show_synthea_form(request):
|
||||
template_name = 'synthea/generator_form.html'
|
||||
|
||||
# if this is a POST request we need to process the form data
|
||||
if request.method == 'POST':
|
||||
# create a form instance and populate it with data from the request:
|
||||
form = SyntheaForm(request.POST)
|
||||
# check whether it's valid:
|
||||
if form.is_valid():
|
||||
# process the data in form.cleaned_data as required
|
||||
|
||||
try:
|
||||
zipfile = run_synthea(
|
||||
form.cleaned_data['state'],
|
||||
form.cleaned_data['population'],
|
||||
form.cleaned_data['gender'],
|
||||
form.cleaned_data['age'],
|
||||
form.cleaned_data['module']
|
||||
)
|
||||
|
||||
mime_type, _ = mimetypes.guess_type(zipfile)
|
||||
response = HttpResponse(zipfile.open('rb'), content_type=mime_type)
|
||||
response['Content-Disposition'] = f'attachment; filename={zipfile.name}'
|
||||
|
||||
return response
|
||||
|
||||
except Exception as ex:
|
||||
print(ex)
|
||||
|
||||
# if a GET (or any other method) we'll create a blank form
|
||||
else:
|
||||
form = SyntheaForm()
|
||||
|
||||
return render(request,template_name,{
|
||||
'form':form
|
||||
})
|
Reference in New Issue
Block a user