OpenREM 1.0.0b2__py3-none-any.whl → 1.0.0b3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- openrem/locale/de/LC_MESSAGES/django.po +1060 -1059
- openrem/locale/django.pot +973 -972
- openrem/locale/es_MX/LC_MESSAGES/django.po +1049 -1048
- openrem/locale/it/LC_MESSAGES/django.po +1044 -1043
- openrem/locale/lt/LC_MESSAGES/django.po +989 -988
- openrem/locale/nb_NO/LC_MESSAGES/django.po +985 -984
- openrem/locale/pt_BR/LC_MESSAGES/django.po +1003 -1002
- openrem/manage.py +10 -10
- openrem/openremproject/__init__.py +1 -1
- openrem/openremproject/local_settings.py.linux +128 -128
- openrem/openremproject/local_settings.py.windows +144 -144
- openrem/openremproject/local_settings.py.windows-sqlite3 +129 -129
- openrem/openremproject/settings.py +278 -278
- openrem/openremproject/urls.py +32 -32
- openrem/openremproject/wsgi.py.example +28 -28
- openrem/remapp/__init__.py +2 -2
- openrem/remapp/admin.py +31 -31
- openrem/remapp/exports/ct_export.py +780 -753
- openrem/remapp/exports/dx_export.py +817 -805
- openrem/remapp/exports/export_common.py +931 -951
- openrem/remapp/exports/export_common_pandas.py +2422 -0
- openrem/remapp/exports/exportviews.py +815 -860
- openrem/remapp/exports/mg_csv_nhsbsp.py +292 -292
- openrem/remapp/exports/mg_export.py +673 -510
- openrem/remapp/exports/nm_export.py +796 -575
- openrem/remapp/exports/rf_export.py +1418 -1431
- openrem/remapp/extractors/ct_philips.py +424 -414
- openrem/remapp/extractors/ct_toshiba.py +2116 -2108
- openrem/remapp/extractors/dx.py +1033 -952
- openrem/remapp/extractors/extract_common.py +817 -817
- openrem/remapp/extractors/import_views.py +426 -426
- openrem/remapp/extractors/mam.py +685 -672
- openrem/remapp/extractors/nm_image.py +439 -431
- openrem/remapp/extractors/ptsizecsv2db.py +368 -368
- openrem/remapp/extractors/rdsr.py +667 -654
- openrem/remapp/extractors/rdsr_methods.py +1771 -1768
- openrem/remapp/extractors/rrdsr_methods.py +630 -622
- openrem/remapp/fixtures/openskin_safelist.json +11 -11
- openrem/remapp/forms.py +2286 -2277
- openrem/remapp/interface/chart_functions.py +2412 -2393
- openrem/remapp/interface/mod_filters.py +1241 -1243
- openrem/remapp/migrations/0001_initial.py.1-0-upgrade +1043 -1043
- openrem/remapp/models.py +3418 -3407
- openrem/remapp/netdicom/dicomviews.py +681 -683
- openrem/remapp/netdicom/qrscu.py +2646 -2646
- openrem/remapp/netdicom/tools.py +134 -134
- openrem/remapp/static/css/bootstrap-theme.css +587 -587
- openrem/remapp/static/css/bootstrap-theme.min.css +4 -4
- openrem/remapp/static/css/bootstrap.css +6800 -6800
- openrem/remapp/static/css/bootstrap.min.css +4 -4
- openrem/remapp/static/css/datepicker3.css +790 -790
- openrem/remapp/static/css/jquery.qtip.min.css +2 -2
- openrem/remapp/static/css/openrem-extra.css +442 -442
- openrem/remapp/static/css/openrem.css +96 -96
- openrem/remapp/static/css/registration.css +34 -34
- openrem/remapp/static/fonts/glyphicons-halflings-regular.svg +287 -287
- openrem/remapp/static/js/bootstrap-datepicker.js +1671 -1671
- openrem/remapp/static/js/bootstrap.js +2363 -2363
- openrem/remapp/static/js/bootstrap.min.js +6 -6
- openrem/remapp/static/js/charts/chartCommonFunctions.js +75 -75
- openrem/remapp/static/js/charts/chartFullScreen.js +41 -41
- openrem/remapp/static/js/charts/ctChartAjax.js +331 -331
- openrem/remapp/static/js/charts/dxChartAjax.js +290 -290
- openrem/remapp/static/js/charts/mgChartAjax.js +144 -144
- openrem/remapp/static/js/charts/nmChartAjax.js +64 -64
- openrem/remapp/static/js/charts/plotly-2.35.2.min.js +8 -0
- openrem/remapp/static/js/charts/rfChartAjax.js +128 -128
- openrem/remapp/static/js/chroma.min.js +32 -32
- openrem/remapp/static/js/datepicker.js +5 -5
- openrem/remapp/static/js/dicom.js +115 -115
- openrem/remapp/static/js/django_reverse/reverse.js +13 -13
- openrem/remapp/static/js/formatDate.js +7 -7
- openrem/remapp/static/js/html5shiv.min.js +8 -8
- openrem/remapp/static/js/jquery-1.11.0.min.js +4 -4
- openrem/remapp/static/js/npm.js +12 -12
- openrem/remapp/static/js/respond.min.js +4 -4
- openrem/remapp/static/js/skin-dose-maps/jquery.qtip.min.js +4 -4
- openrem/remapp/static/js/skin-dose-maps/rfSkinDoseMap3dHUDObject.js +112 -112
- openrem/remapp/static/js/skin-dose-maps/rfSkinDoseMap3dObject.js +367 -367
- openrem/remapp/static/js/skin-dose-maps/rfSkinDoseMap3dPersonObject.js +158 -158
- openrem/remapp/static/js/skin-dose-maps/rfSkinDoseMapColourScaleObject.js +153 -153
- openrem/remapp/static/js/skin-dose-maps/rfSkinDoseMapObject.js +367 -367
- openrem/remapp/static/js/skin-dose-maps/rfSkinDoseMapping.js +584 -584
- openrem/remapp/static/js/skin-dose-maps/rfSkinDoseMapping3d.js +255 -255
- openrem/remapp/static/js/skin-dose-maps/rfSkinDoseMappingAjax.js +267 -212
- openrem/remapp/static/js/skin-dose-maps/three.min.js +835 -835
- openrem/remapp/static/js/sorttable.js +495 -495
- openrem/remapp/templates/base.html +253 -253
- openrem/remapp/templates/registration/changepassword.html +25 -25
- openrem/remapp/templates/registration/changepassworddone.html +12 -12
- openrem/remapp/templates/registration/login.html +42 -42
- openrem/remapp/templates/remapp/backgroundtaskmaximumrows_form.html +29 -29
- openrem/remapp/templates/remapp/base.html +1 -1
- openrem/remapp/templates/remapp/ctdetail.html +235 -235
- openrem/remapp/templates/remapp/ctfiltered.html +310 -310
- openrem/remapp/templates/remapp/dicomdeletesettings_form.html +31 -31
- openrem/remapp/templates/remapp/dicomqr.html +147 -147
- openrem/remapp/templates/remapp/dicomquerydetails.html +83 -83
- openrem/remapp/templates/remapp/dicomqueryimages.html +49 -49
- openrem/remapp/templates/remapp/dicomqueryseries.html +109 -109
- openrem/remapp/templates/remapp/dicomquerysummary.html +48 -48
- openrem/remapp/templates/remapp/dicomremoteqr_confirm_delete.html +60 -60
- openrem/remapp/templates/remapp/dicomremoteqr_form.html +32 -32
- openrem/remapp/templates/remapp/dicomstorescp_confirm_delete.html +53 -53
- openrem/remapp/templates/remapp/dicomstorescp_form.html +48 -48
- openrem/remapp/templates/remapp/dicomsummary.html +257 -257
- openrem/remapp/templates/remapp/displaychartoptions.html +184 -184
- openrem/remapp/templates/remapp/displayhomepageoptions.html +57 -57
- openrem/remapp/templates/remapp/displayname-count.html +6 -6
- openrem/remapp/templates/remapp/displayname-last-date.html +3 -3
- openrem/remapp/templates/remapp/displayname-modality.html +86 -105
- openrem/remapp/templates/remapp/displayname-skinmap.html +18 -18
- openrem/remapp/templates/remapp/displaynameupdate.html +100 -100
- openrem/remapp/templates/remapp/displaynameview.html +222 -219
- openrem/remapp/templates/remapp/dxdetail.html +176 -176
- openrem/remapp/templates/remapp/dxfiltered.html +324 -324
- openrem/remapp/templates/remapp/exports-active.html +25 -25
- openrem/remapp/templates/remapp/exports-complete.html +35 -35
- openrem/remapp/templates/remapp/exports-error.html +26 -26
- openrem/remapp/templates/remapp/exports-queue.html +18 -18
- openrem/remapp/templates/remapp/exports.html +191 -191
- openrem/remapp/templates/remapp/failed_summary_list.html +27 -27
- openrem/remapp/templates/remapp/filteredbase.html +162 -162
- openrem/remapp/templates/remapp/highdosemetricalertsettings_form.html +76 -76
- openrem/remapp/templates/remapp/home-list-modalities.html +94 -94
- openrem/remapp/templates/remapp/home.html +202 -202
- openrem/remapp/templates/remapp/list_filters.html +24 -24
- openrem/remapp/templates/remapp/mgdetail.html +160 -138
- openrem/remapp/templates/remapp/mgfiltered.html +311 -311
- openrem/remapp/templates/remapp/nmdetail.html +300 -300
- openrem/remapp/templates/remapp/nmfiltered.html +255 -255
- openrem/remapp/templates/remapp/notpatient.html +190 -190
- openrem/remapp/templates/remapp/notpatientindicators_form_base.html +81 -81
- openrem/remapp/templates/remapp/notpatientindicatorsid_confirm_delete.html +54 -54
- openrem/remapp/templates/remapp/notpatientindicatorsid_form.html +23 -23
- openrem/remapp/templates/remapp/notpatientindicatorsname_confirm_delete.html +54 -54
- openrem/remapp/templates/remapp/notpatientindicatorsname_form.html +23 -23
- openrem/remapp/templates/remapp/notpatientindicatorsname_form_base.html +85 -85
- openrem/remapp/templates/remapp/openskinsafelist_add.html +130 -130
- openrem/remapp/templates/remapp/openskinsafelist_confirm_delete.html +100 -100
- openrem/remapp/templates/remapp/openskinsafelist_form.html +207 -207
- openrem/remapp/templates/remapp/patientidsettings_form.html +83 -83
- openrem/remapp/templates/remapp/populate_summary_progress.html +83 -83
- openrem/remapp/templates/remapp/populate_summary_progress_error.html +36 -36
- openrem/remapp/templates/remapp/review_failed_imports.html +157 -157
- openrem/remapp/templates/remapp/review_failed_study.html +41 -41
- openrem/remapp/templates/remapp/review_studies_delete_button.html +20 -20
- openrem/remapp/templates/remapp/review_study.html +19 -19
- openrem/remapp/templates/remapp/review_summary_list.html +245 -245
- openrem/remapp/templates/remapp/rf_dose_alert_email_template.html +14 -1
- openrem/remapp/templates/remapp/rfalertnotificationsview.html +59 -59
- openrem/remapp/templates/remapp/rfdetail.html +547 -543
- openrem/remapp/templates/remapp/rfdetailbase.html +18 -18
- openrem/remapp/templates/remapp/rffiltered.html +404 -404
- openrem/remapp/templates/remapp/sizeimports.html +119 -119
- openrem/remapp/templates/remapp/sizeprocess.html +96 -96
- openrem/remapp/templates/remapp/sizeupload.html +110 -110
- openrem/remapp/templates/remapp/skindosemapcalcsettings_form.html +28 -28
- openrem/remapp/templates/remapp/standardname-modality.html +69 -69
- openrem/remapp/templates/remapp/standardnames_confirm_delete.html +71 -71
- openrem/remapp/templates/remapp/standardnames_form.html +87 -87
- openrem/remapp/templates/remapp/standardnamesettings_form.html +41 -41
- openrem/remapp/templates/remapp/standardnamesrefreshall.html +92 -92
- openrem/remapp/templates/remapp/standardnameview.html +103 -103
- openrem/remapp/templates/remapp/study_confirm_delete.html +147 -147
- openrem/remapp/templates/remapp/task_admin.html +265 -265
- openrem/remapp/templates/remapp/tasks.html +76 -76
- openrem/remapp/templatetags/formfilters.py +13 -13
- openrem/remapp/templatetags/proper_paginate.py +38 -38
- openrem/remapp/templatetags/remappduration.py +36 -36
- openrem/remapp/templatetags/sigdig.py +38 -38
- openrem/remapp/templatetags/sort_class_property_value.py +15 -15
- openrem/remapp/templatetags/update_variable.py +20 -20
- openrem/remapp/templatetags/url_replace.py +25 -25
- openrem/remapp/tests/test_charts_common.py +202 -202
- openrem/remapp/tests/test_charts_ct.py +7111 -7111
- openrem/remapp/tests/test_charts_dx.py +3513 -3513
- openrem/remapp/tests/test_charts_mg.py +1116 -1115
- openrem/remapp/tests/test_dcmdatetime.py +189 -189
- openrem/remapp/tests/test_dicom_qr.py +2580 -2580
- openrem/remapp/tests/test_display_name.py +274 -274
- openrem/remapp/tests/test_export_ct_xlsx.py +272 -248
- openrem/remapp/tests/test_export_dx_xlsx.py +137 -134
- openrem/remapp/tests/test_export_mammo_csv.py +242 -242
- openrem/remapp/tests/test_export_rf_xlsx.py +246 -246
- openrem/remapp/tests/test_files/DX-Im-DRGEM.dcm +0 -0
- openrem/remapp/tests/test_files/MG-RDSR-GEPristina-2D.dcm +0 -0
- openrem/remapp/tests/test_files/MG-RDSR-GEPristina-DBT.dcm +0 -0
- openrem/remapp/tests/test_files/MG-RDSR-Giotto-DBT.dcm +0 -0
- openrem/remapp/tests/test_files/skin_map_alphenix.py +590 -590
- openrem/remapp/tests/test_files/skin_map_zee.py +354 -354
- openrem/remapp/tests/test_filters_ct.py +321 -321
- openrem/remapp/tests/test_filters_dx.py +92 -92
- openrem/remapp/tests/test_filters_mammo.py +183 -183
- openrem/remapp/tests/test_filters_rf.py +118 -118
- openrem/remapp/tests/test_get_values.py +72 -72
- openrem/remapp/tests/test_hash_id.py +65 -65
- openrem/remapp/tests/test_import_ct_esr_ge.py +3034 -3034
- openrem/remapp/tests/test_import_ct_philips_rdsr.py +42 -42
- openrem/remapp/tests/test_import_ct_rdsr_multiple.py +256 -256
- openrem/remapp/tests/test_import_ct_rdsr_siemens.py +827 -827
- openrem/remapp/tests/test_import_ct_rdsr_spectrumdynamics.py +91 -91
- openrem/remapp/tests/test_import_ct_rdsr_toshiba_dosecheck.py +67 -67
- openrem/remapp/tests/test_import_ct_rdsr_toshiba_multivaluesd.py +33 -33
- openrem/remapp/tests/test_import_ct_rdsr_toshiba_pixelmed.py +118 -118
- openrem/remapp/tests/test_import_ct_sc_philips.py +44 -44
- openrem/remapp/tests/test_import_dual_rdsr.py +110 -110
- openrem/remapp/tests/test_import_dx.py +1267 -1191
- openrem/remapp/tests/test_import_dx_rdsr.py +1250 -1253
- openrem/remapp/tests/test_import_mam.py +438 -438
- openrem/remapp/tests/test_import_mg_im_hol_proj.py +46 -46
- openrem/remapp/tests/test_import_mg_rdsr.py +586 -586
- openrem/remapp/tests/test_import_nm_image.py +420 -420
- openrem/remapp/tests/test_import_nm_siemens_rdsr.py +396 -396
- openrem/remapp/tests/test_import_px.py +161 -161
- openrem/remapp/tests/test_import_rf_rdsr.py +420 -418
- openrem/remapp/tests/test_missing_date.py +42 -42
- openrem/remapp/tests/test_not_patient.py +60 -60
- openrem/remapp/tests/test_openskin.py +272 -272
- openrem/remapp/tests/test_patient_id_settings.py +72 -72
- openrem/remapp/tests/test_pt_size_import.py +232 -232
- openrem/remapp/tests/test_rf_detail.py +113 -113
- openrem/remapp/tests/test_rf_high_dose_alert.py +361 -361
- openrem/remapp/tools/background.py +361 -361
- openrem/remapp/tools/check_standard_name_status.py +47 -0
- openrem/remapp/tools/check_uid.py +70 -70
- openrem/remapp/tools/dcmdatetime.py +248 -248
- openrem/remapp/tools/default_import.py +44 -47
- openrem/remapp/tools/get_values.py +230 -230
- openrem/remapp/tools/hash_id.py +58 -58
- openrem/remapp/tools/make_skin_map.py +448 -406
- openrem/remapp/tools/not_patient_indicators.py +72 -72
- openrem/remapp/tools/openskin/calc_exp_map.py +173 -173
- openrem/remapp/tools/openskin/geomclass.py +475 -475
- openrem/remapp/tools/openskin/geomfunc.py +433 -432
- openrem/remapp/tools/openskin/skinmap.py +417 -417
- openrem/remapp/tools/populate_summary.py +185 -193
- openrem/remapp/tools/save_skin_map_structure.py +73 -73
- openrem/remapp/tools/send_high_dose_alert_emails.py +238 -207
- openrem/remapp/urls.py +456 -448
- openrem/remapp/version.py +11 -11
- openrem/remapp/views.py +1147 -1052
- openrem/remapp/views_admin.py +3876 -3936
- openrem/remapp/views_charts_ct.py +2110 -2058
- openrem/remapp/views_charts_dx.py +1906 -1836
- openrem/remapp/views_charts_mg.py +1349 -1196
- openrem/remapp/views_charts_nm.py +535 -535
- openrem/remapp/views_charts_rf.py +1219 -1241
- openrem/remapp/views_openskin.py +379 -384
- openrem/sample-config/openrem-consumer.service +12 -12
- openrem/sample-config/openrem-gunicorn.service +13 -13
- openrem/sample-config/openrem-server +14 -13
- openrem/sample-config/openrem_orthanc_config_linux.lua +454 -454
- openrem/sample-config/openrem_orthanc_config_windows.lua +455 -455
- openrem/sample-config/queue-init.bat +73 -73
- openrem/scripts/openrem_ctphilips.py +25 -25
- openrem/scripts/openrem_cttoshiba.py +28 -28
- openrem/scripts/openrem_dx.py +22 -22
- openrem/scripts/openrem_mg.py +22 -22
- openrem/scripts/openrem_nm.py +22 -22
- openrem/scripts/openrem_ptsizecsv.py +17 -17
- openrem/scripts/openrem_qr.py +12 -12
- openrem/scripts/openrem_rdsr.py +25 -25
- {OpenREM-1.0.0b2.dist-info → openrem-1.0.0b3.dist-info}/METADATA +39 -29
- openrem-1.0.0b3.dist-info/RECORD +379 -0
- {OpenREM-1.0.0b2.dist-info → openrem-1.0.0b3.dist-info}/WHEEL +1 -1
- {OpenREM-1.0.0b2.dist-info → openrem-1.0.0b3.dist-info/licenses}/COPYING-GPLv3 +674 -674
- {OpenREM-1.0.0b2.dist-info → openrem-1.0.0b3.dist-info/licenses}/LICENSE +22 -22
- OpenREM-1.0.0b2.dist-info/RECORD +0 -373
- openrem/remapp/static/js/charts/plotly-2.17.1.min.js +0 -8
- {OpenREM-1.0.0b2.data → openrem-1.0.0b3.data}/scripts/openrem_ctphilips.py +0 -0
- {OpenREM-1.0.0b2.data → openrem-1.0.0b3.data}/scripts/openrem_cttoshiba.py +0 -0
- {OpenREM-1.0.0b2.data → openrem-1.0.0b3.data}/scripts/openrem_dx.py +0 -0
- {OpenREM-1.0.0b2.data → openrem-1.0.0b3.data}/scripts/openrem_mg.py +0 -0
- {OpenREM-1.0.0b2.data → openrem-1.0.0b3.data}/scripts/openrem_nm.py +0 -0
- {OpenREM-1.0.0b2.data → openrem-1.0.0b3.data}/scripts/openrem_ptsizecsv.py +0 -0
- {OpenREM-1.0.0b2.data → openrem-1.0.0b3.data}/scripts/openrem_qr.py +0 -0
- {OpenREM-1.0.0b2.data → openrem-1.0.0b3.data}/scripts/openrem_rdsr.py +0 -0
- {OpenREM-1.0.0b2.dist-info → openrem-1.0.0b3.dist-info}/top_level.txt +0 -0
|
@@ -1,860 +1,815 @@
|
|
|
1
|
-
# OpenREM - Radiation Exposure Monitoring tools for the physicist
|
|
2
|
-
# Copyright (C) 2012,2013 The Royal Marsden NHS Foundation Trust
|
|
3
|
-
#
|
|
4
|
-
# This program is free software: you can redistribute it and/or modify
|
|
5
|
-
# it under the terms of the GNU General Public License as published by
|
|
6
|
-
# the Free Software Foundation, either version 3 of the License, or
|
|
7
|
-
# (at your option) any later version.
|
|
8
|
-
#
|
|
9
|
-
# This program is distributed in the hope that it will be useful,
|
|
10
|
-
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
-
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
-
# GNU General Public License for more details.
|
|
13
|
-
#
|
|
14
|
-
# Additional permission under section 7 of GPLv3:
|
|
15
|
-
# You shall not make any use of the name of The Royal Marsden NHS
|
|
16
|
-
# Foundation trust in connection with this Program in any press or
|
|
17
|
-
# other public announcement without the prior written consent of
|
|
18
|
-
# The Royal Marsden NHS Foundation Trust.
|
|
19
|
-
#
|
|
20
|
-
# You should have received a copy of the GNU General Public License
|
|
21
|
-
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
22
|
-
|
|
23
|
-
"""
|
|
24
|
-
.. module:: exportviews.py
|
|
25
|
-
:synopsis: Module to render appropriate content according to request, specific to the exports.
|
|
26
|
-
|
|
27
|
-
.. moduleauthor:: Ed McDonagh
|
|
28
|
-
|
|
29
|
-
"""
|
|
30
|
-
|
|
31
|
-
# Following two lines added so that sphinx autodocumentation works.
|
|
32
|
-
import os
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
from
|
|
39
|
-
|
|
40
|
-
from django.
|
|
41
|
-
from django.
|
|
42
|
-
from django.
|
|
43
|
-
import
|
|
44
|
-
from
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
)
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
if
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
request.
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
if
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
"""
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
"
|
|
338
|
-
"
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
request.
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
)
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
"
|
|
363
|
-
"
|
|
364
|
-
"
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
"
|
|
373
|
-
"
|
|
374
|
-
"
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
request.
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
)
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
@
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
:param
|
|
415
|
-
:param
|
|
416
|
-
:
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
"
|
|
428
|
-
request.
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
""
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
""
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
""
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
"
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
for
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
return
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
"""
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
@csrf_exempt
|
|
817
|
-
@login_required
|
|
818
|
-
def update_error(request):
|
|
819
|
-
"""
|
|
820
|
-
AJAX function to return exports in error state
|
|
821
|
-
|
|
822
|
-
:param request: Request object
|
|
823
|
-
:return: HTML table of exports in error state
|
|
824
|
-
"""
|
|
825
|
-
from remapp.models import Exports
|
|
826
|
-
|
|
827
|
-
if request.is_ajax():
|
|
828
|
-
error_export_tasks = Exports.objects.filter(status__contains="ERROR").order_by(
|
|
829
|
-
"-export_date"
|
|
830
|
-
)
|
|
831
|
-
template = "remapp/exports-error.html"
|
|
832
|
-
|
|
833
|
-
return render(request, template, {"errors": error_export_tasks})
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
@csrf_exempt
|
|
837
|
-
@login_required
|
|
838
|
-
def update_complete(request):
|
|
839
|
-
"""
|
|
840
|
-
AJAX function to return recently completed exports
|
|
841
|
-
|
|
842
|
-
:param request: Request object, including pk of latest complete export at initial page load
|
|
843
|
-
:return: HTML table of completed exports
|
|
844
|
-
"""
|
|
845
|
-
from remapp.models import Exports
|
|
846
|
-
|
|
847
|
-
if request.is_ajax():
|
|
848
|
-
data = request.POST
|
|
849
|
-
latest_complete_pk = data.get("latest_complete_pk")
|
|
850
|
-
in_pid_group = data.get("in_pid_group")
|
|
851
|
-
complete_export_tasks = Exports.objects.filter(
|
|
852
|
-
status__contains="COMPLETE"
|
|
853
|
-
).filter(pk__gt=latest_complete_pk)
|
|
854
|
-
template = "remapp/exports-complete.html"
|
|
855
|
-
|
|
856
|
-
return render(
|
|
857
|
-
request,
|
|
858
|
-
template,
|
|
859
|
-
{"complete": complete_export_tasks, "in_pid_group": in_pid_group},
|
|
860
|
-
)
|
|
1
|
+
# OpenREM - Radiation Exposure Monitoring tools for the physicist
|
|
2
|
+
# Copyright (C) 2012,2013 The Royal Marsden NHS Foundation Trust
|
|
3
|
+
#
|
|
4
|
+
# This program is free software: you can redistribute it and/or modify
|
|
5
|
+
# it under the terms of the GNU General Public License as published by
|
|
6
|
+
# the Free Software Foundation, either version 3 of the License, or
|
|
7
|
+
# (at your option) any later version.
|
|
8
|
+
#
|
|
9
|
+
# This program is distributed in the hope that it will be useful,
|
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
+
# GNU General Public License for more details.
|
|
13
|
+
#
|
|
14
|
+
# Additional permission under section 7 of GPLv3:
|
|
15
|
+
# You shall not make any use of the name of The Royal Marsden NHS
|
|
16
|
+
# Foundation trust in connection with this Program in any press or
|
|
17
|
+
# other public announcement without the prior written consent of
|
|
18
|
+
# The Royal Marsden NHS Foundation Trust.
|
|
19
|
+
#
|
|
20
|
+
# You should have received a copy of the GNU General Public License
|
|
21
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
22
|
+
|
|
23
|
+
"""
|
|
24
|
+
.. module:: exportviews.py
|
|
25
|
+
:synopsis: Module to render appropriate content according to request, specific to the exports.
|
|
26
|
+
|
|
27
|
+
.. moduleauthor:: Ed McDonagh
|
|
28
|
+
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
# Following two lines added so that sphinx autodocumentation works.
|
|
32
|
+
import os
|
|
33
|
+
import sys
|
|
34
|
+
import mimetypes
|
|
35
|
+
import urllib
|
|
36
|
+
|
|
37
|
+
import logging
|
|
38
|
+
from wsgiref.util import FileWrapper
|
|
39
|
+
|
|
40
|
+
from django.views.decorators.csrf import csrf_exempt
|
|
41
|
+
from django.contrib import messages
|
|
42
|
+
from django.contrib.auth.decorators import login_required
|
|
43
|
+
from django.http import HttpResponse, HttpResponseRedirect
|
|
44
|
+
from django.shortcuts import render, get_object_or_404, redirect
|
|
45
|
+
from django.urls import reverse_lazy, reverse
|
|
46
|
+
from django.conf import settings
|
|
47
|
+
from django.core.exceptions import ObjectDoesNotExist
|
|
48
|
+
from django.utils.encoding import smart_str
|
|
49
|
+
from django.db.models import Max
|
|
50
|
+
|
|
51
|
+
from ..models import Exports, BackgroundTask, GeneralStudyModuleAttr
|
|
52
|
+
from ..interface.mod_filters import dx_acq_filter
|
|
53
|
+
|
|
54
|
+
from .ct_export import ct_phe_2019, ctxlsx, ct_csv
|
|
55
|
+
from .dx_export import dx_phe_2019, dxxlsx, exportDX2excel
|
|
56
|
+
from .mg_csv_nhsbsp import mg_csv_nhsbsp
|
|
57
|
+
from .mg_export import mgxlsx, exportMG2csv
|
|
58
|
+
from .nm_export import nmxlsx, exportNM2csv
|
|
59
|
+
from .rf_export import rf_phe_2019, rfopenskin_csv, rfxlsx, exportFL2excel
|
|
60
|
+
|
|
61
|
+
from ..tools.background import ( # pylint: disable=wrong-import-position
|
|
62
|
+
run_in_background,
|
|
63
|
+
terminate_background,
|
|
64
|
+
get_queued_tasks,
|
|
65
|
+
remove_task_from_queue,
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
from ..version import __version__, __docs_version__
|
|
69
|
+
|
|
70
|
+
os.environ["DJANGO_SETTINGS_MODULE"] = "openremproject.settings"
|
|
71
|
+
|
|
72
|
+
logger = logging.getLogger(__name__)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def include_pid(request, name, pat_id):
|
|
76
|
+
"""
|
|
77
|
+
Check if user is allowed to export PID, then check if they have asked to.
|
|
78
|
+
:param request: request so we can determine the user and therefore groups
|
|
79
|
+
:param name: string, 0 or 1 from URL indicating if names should be exported
|
|
80
|
+
:param pat_id: string, 0 or 1 from URL indicating if patient ID should be exported
|
|
81
|
+
:return: dict, with pidgroup, include_names and include_pat_id as bools
|
|
82
|
+
"""
|
|
83
|
+
pid = bool(request.user.groups.filter(name="pidgroup"))
|
|
84
|
+
|
|
85
|
+
include_names = False
|
|
86
|
+
include_pat_id = False
|
|
87
|
+
if pid:
|
|
88
|
+
try:
|
|
89
|
+
if int(name): # Will be unicode from URL
|
|
90
|
+
include_names = True
|
|
91
|
+
except ValueError: # If anything else comes in, just don't export that column
|
|
92
|
+
pass
|
|
93
|
+
try:
|
|
94
|
+
if int(pat_id):
|
|
95
|
+
include_pat_id = True
|
|
96
|
+
except ValueError:
|
|
97
|
+
pass
|
|
98
|
+
|
|
99
|
+
return {
|
|
100
|
+
"pidgroup": pid,
|
|
101
|
+
"include_names": include_names,
|
|
102
|
+
"include_pat_id": include_pat_id,
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
@csrf_exempt
|
|
107
|
+
@login_required
|
|
108
|
+
def ctcsv1(request, name=None, pat_id=None):
|
|
109
|
+
"""
|
|
110
|
+
View to launch task to export CT studies to csv file
|
|
111
|
+
|
|
112
|
+
:param request: Contains the database filtering parameters. Also used to get user group.
|
|
113
|
+
:param name: string, 0 or 1 from URL indicating if names should be exported
|
|
114
|
+
:param pat_id: string, 0 or 1 from URL indicating if patient ID should be exported
|
|
115
|
+
:type request: GET
|
|
116
|
+
"""
|
|
117
|
+
pid = include_pid(request, name, pat_id)
|
|
118
|
+
|
|
119
|
+
if request.user.groups.filter(name="exportgroup"):
|
|
120
|
+
# The 'ct_acquisition_type' filter values must be passed to ct_csv as a list, so convert the GET to a dict and
|
|
121
|
+
# then update the 'ct_acquisition_type' value with a list.
|
|
122
|
+
filter_dict = request.GET.dict()
|
|
123
|
+
if "ct_acquisition_type" in filter_dict:
|
|
124
|
+
filter_dict["ct_acquisition_type"] = request.GET.getlist(
|
|
125
|
+
"ct_acquisition_type"
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
job = run_in_background(
|
|
129
|
+
ct_csv,
|
|
130
|
+
"export_ct",
|
|
131
|
+
filter_dict,
|
|
132
|
+
pid["pidgroup"],
|
|
133
|
+
pid["include_names"],
|
|
134
|
+
pid["include_pat_id"],
|
|
135
|
+
request.user.id,
|
|
136
|
+
)
|
|
137
|
+
logger.debug(f"Export CT to CSV job is {job.id}")
|
|
138
|
+
return redirect(reverse_lazy("export"))
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
@csrf_exempt
|
|
142
|
+
@login_required
|
|
143
|
+
def ctxlsx1(request, name=None, pat_id=None):
|
|
144
|
+
"""
|
|
145
|
+
View to launch task to export CT studies to xlsx file
|
|
146
|
+
|
|
147
|
+
:param request: Contains the database filtering parameters. Also used to get user group.
|
|
148
|
+
:param name: string, 0 or 1 from URL indicating if names should be exported
|
|
149
|
+
:param pat_id: string, 0 or 1 from URL indicating if patient ID should be exported
|
|
150
|
+
:type request: GET
|
|
151
|
+
"""
|
|
152
|
+
pid = include_pid(request, name, pat_id)
|
|
153
|
+
|
|
154
|
+
if request.user.groups.filter(name="exportgroup"):
|
|
155
|
+
# The 'ct_acquisition_type' filter values must be passed to ctxlsx as a list, so convert the GET to a dict and
|
|
156
|
+
# then update the 'ct_acquisition_type' value with a list.
|
|
157
|
+
filter_dict = request.GET.dict()
|
|
158
|
+
if "ct_acquisition_type" in filter_dict:
|
|
159
|
+
filter_dict["ct_acquisition_type"] = request.GET.getlist(
|
|
160
|
+
"ct_acquisition_type"
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
job = run_in_background(
|
|
164
|
+
ctxlsx,
|
|
165
|
+
"export_ct",
|
|
166
|
+
filter_dict,
|
|
167
|
+
pid["pidgroup"],
|
|
168
|
+
pid["include_names"],
|
|
169
|
+
pid["include_pat_id"],
|
|
170
|
+
request.user.id,
|
|
171
|
+
)
|
|
172
|
+
logger.debug("Export CT to XLSX job is {0}".format(job.id))
|
|
173
|
+
|
|
174
|
+
return redirect(reverse_lazy("export"))
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
@csrf_exempt
|
|
178
|
+
@login_required
|
|
179
|
+
def ct_xlsx_phe2019(request):
|
|
180
|
+
"""
|
|
181
|
+
View to launch task to export CT studies to xlsx file in PHE 2019 CT survey format
|
|
182
|
+
|
|
183
|
+
:param request: Contains the database filtering parameters and user details.
|
|
184
|
+
"""
|
|
185
|
+
if request.user.groups.filter(name="exportgroup"):
|
|
186
|
+
job = run_in_background(ct_phe_2019, "export_ct", request.GET, request.user.id)
|
|
187
|
+
logger.debug("Export CT to XLSX job is {0}".format(job.id))
|
|
188
|
+
return redirect(reverse_lazy("export"))
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
@csrf_exempt
|
|
192
|
+
@login_required
|
|
193
|
+
def nmcsv1(request, name=None, pat_id=None):
|
|
194
|
+
"""
|
|
195
|
+
View to launch task to export NM studies to csv file
|
|
196
|
+
|
|
197
|
+
:param request: Contains the database filtering parameters. Also used to get user group.
|
|
198
|
+
:param name: string, 0 or 1 from URL indicating if names should be exported
|
|
199
|
+
:param pat_id: string, 0 or 1 from URL indicating if patient ID should be exported
|
|
200
|
+
:type request: GET
|
|
201
|
+
"""
|
|
202
|
+
pid = include_pid(request, name, pat_id)
|
|
203
|
+
|
|
204
|
+
if request.user.groups.filter(name="exportgroup"):
|
|
205
|
+
job = run_in_background(
|
|
206
|
+
exportNM2csv,
|
|
207
|
+
"export_nm",
|
|
208
|
+
request.GET,
|
|
209
|
+
pid["pidgroup"],
|
|
210
|
+
pid["include_names"],
|
|
211
|
+
pid["include_pat_id"],
|
|
212
|
+
request.user.id,
|
|
213
|
+
)
|
|
214
|
+
logger.debug(f"Export NM to CSV job is {job.id}")
|
|
215
|
+
|
|
216
|
+
return redirect(reverse_lazy("export"))
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
@csrf_exempt
|
|
220
|
+
@login_required
|
|
221
|
+
def nmxlsx1(request, name=None, pat_id=None):
|
|
222
|
+
"""
|
|
223
|
+
View to launch celery task to export NM studies to excel file
|
|
224
|
+
|
|
225
|
+
:param request: Contains the database filtering parameters. Also used to get user group.
|
|
226
|
+
:param name: string, 0 or 1 from URL indicating if names should be exported
|
|
227
|
+
:param pat_id: string, 0 or 1 from URL indicating if patient ID should be exported
|
|
228
|
+
:type request: GET
|
|
229
|
+
"""
|
|
230
|
+
pid = include_pid(request, name, pat_id)
|
|
231
|
+
|
|
232
|
+
if request.user.groups.filter(name="exportgroup"):
|
|
233
|
+
filter_dict = request.GET.dict()
|
|
234
|
+
if "nm_acquisition_type" in filter_dict:
|
|
235
|
+
filter_dict["nm_acquisition_type"] = request.GET.getlist(
|
|
236
|
+
"nm_acquisition_type"
|
|
237
|
+
)
|
|
238
|
+
|
|
239
|
+
job = run_in_background(
|
|
240
|
+
nmxlsx,
|
|
241
|
+
"export_nm",
|
|
242
|
+
filter_dict,
|
|
243
|
+
pid["pidgroup"],
|
|
244
|
+
pid["include_names"],
|
|
245
|
+
pid["include_pat_id"],
|
|
246
|
+
request.user.id,
|
|
247
|
+
)
|
|
248
|
+
logger.debug(f"Exprt NM to Excel job is {job.id}")
|
|
249
|
+
|
|
250
|
+
return redirect(reverse_lazy("export"))
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
@csrf_exempt
|
|
254
|
+
@login_required
|
|
255
|
+
def dxcsv1(request, name=None, pat_id=None):
|
|
256
|
+
"""
|
|
257
|
+
View to launch task to export DX and CR studies to csv file
|
|
258
|
+
|
|
259
|
+
:param request: Contains the database filtering parameters. Also used to get user group.
|
|
260
|
+
:param name: string, 0 or 1 from URL indicating if names should be exported
|
|
261
|
+
:param pat_id: string, 0 or 1 from URL indicating if patient ID should be exported
|
|
262
|
+
:type request: GET
|
|
263
|
+
"""
|
|
264
|
+
pid = include_pid(request, name, pat_id)
|
|
265
|
+
|
|
266
|
+
if request.user.groups.filter(name="exportgroup"):
|
|
267
|
+
job = run_in_background(
|
|
268
|
+
exportDX2excel,
|
|
269
|
+
"export_dx",
|
|
270
|
+
request.GET,
|
|
271
|
+
pid["pidgroup"],
|
|
272
|
+
pid["include_names"],
|
|
273
|
+
pid["include_pat_id"],
|
|
274
|
+
request.user.id,
|
|
275
|
+
)
|
|
276
|
+
logger.debug("Export DX to CSV job is {0}".format(job.id))
|
|
277
|
+
|
|
278
|
+
return redirect(reverse_lazy("export"))
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
@csrf_exempt
|
|
282
|
+
@login_required
|
|
283
|
+
def dxxlsx1(request, name=None, pat_id=None):
|
|
284
|
+
"""
|
|
285
|
+
View to launch task to export DX and CR studies to xlsx file
|
|
286
|
+
|
|
287
|
+
:param request: Contains the database filtering parameters. Also used to get user group.
|
|
288
|
+
:param name: string, 0 or 1 from URL indicating if names should be exported
|
|
289
|
+
:param pat_id: string, 0 or 1 from URL indicating if patient ID should be exported
|
|
290
|
+
:type request: GET
|
|
291
|
+
"""
|
|
292
|
+
pid = include_pid(request, name, pat_id)
|
|
293
|
+
|
|
294
|
+
if request.user.groups.filter(name="exportgroup"):
|
|
295
|
+
job = run_in_background(
|
|
296
|
+
dxxlsx,
|
|
297
|
+
"export_dx",
|
|
298
|
+
request.GET,
|
|
299
|
+
pid["pidgroup"],
|
|
300
|
+
pid["include_names"],
|
|
301
|
+
pid["include_pat_id"],
|
|
302
|
+
request.user.id,
|
|
303
|
+
)
|
|
304
|
+
logger.debug("Export DX to XLSX job is {0}".format(job.id))
|
|
305
|
+
|
|
306
|
+
return redirect(reverse_lazy("export"))
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
@csrf_exempt
|
|
310
|
+
@login_required
|
|
311
|
+
def dx_xlsx_phe2019(request, export_type=None):
|
|
312
|
+
"""
|
|
313
|
+
View to launch task to export DX studies to xlsx file in PHE 2019 DX survey format
|
|
314
|
+
|
|
315
|
+
:param request: Contains the database filtering parameters and user details.
|
|
316
|
+
:param export_type: string, 'projection' or 'exam'
|
|
317
|
+
"""
|
|
318
|
+
if request.user.groups.filter(name="exportgroup"):
|
|
319
|
+
if export_type in ("exam", "projection"):
|
|
320
|
+
bespoke = False
|
|
321
|
+
exams = dx_acq_filter(request.GET, pid=False).qs
|
|
322
|
+
if not exams.count():
|
|
323
|
+
messages.error(request, "No studies in export, nothing to do!")
|
|
324
|
+
return redirect(
|
|
325
|
+
"{0}?{1}".format(
|
|
326
|
+
reverse_lazy("dx_summary_list_filter"),
|
|
327
|
+
urllib.urlencode(request.GET),
|
|
328
|
+
)
|
|
329
|
+
)
|
|
330
|
+
max_events_dict = exams.aggregate(Max("number_of_events"))
|
|
331
|
+
max_events = max_events_dict["number_of_events__max"]
|
|
332
|
+
if "projection" in export_type:
|
|
333
|
+
if max_events > 1:
|
|
334
|
+
messages.warning(
|
|
335
|
+
request,
|
|
336
|
+
"PHE 2019 DX Projection export is expecting one exposure per study - "
|
|
337
|
+
"some studies selected have more than one. Only the first exposure will "
|
|
338
|
+
"be considered.",
|
|
339
|
+
)
|
|
340
|
+
else:
|
|
341
|
+
messages.info(
|
|
342
|
+
request, "PHE 2019 DX single projection export started."
|
|
343
|
+
)
|
|
344
|
+
job = run_in_background(
|
|
345
|
+
dx_phe_2019,
|
|
346
|
+
"export_dx",
|
|
347
|
+
request.GET,
|
|
348
|
+
request.user.id,
|
|
349
|
+
projection=True,
|
|
350
|
+
)
|
|
351
|
+
logger.debug(
|
|
352
|
+
"Export PHE 2019 DX survey format job is {0}".format(job.id)
|
|
353
|
+
)
|
|
354
|
+
return redirect(reverse_lazy("export"))
|
|
355
|
+
elif "exam" in export_type:
|
|
356
|
+
if max_events > 6:
|
|
357
|
+
bespoke = True
|
|
358
|
+
if max_events > 20:
|
|
359
|
+
messages.warning(
|
|
360
|
+
request,
|
|
361
|
+
"PHE 2019 DX Study sheets expect a maximum of six projections. You "
|
|
362
|
+
"need to request a bespoke workbook from PHE. This export has a "
|
|
363
|
+
"maximum of {0} projections, but only the first 20 will be included "
|
|
364
|
+
"in the main columns of the bespoke worksheet.".format(
|
|
365
|
+
max_events
|
|
366
|
+
),
|
|
367
|
+
)
|
|
368
|
+
else:
|
|
369
|
+
messages.warning(
|
|
370
|
+
request,
|
|
371
|
+
"PHE 2019 DX Study sheets expect a maximum of six projections. This "
|
|
372
|
+
"export has a maximum of {0} projections so you will need to request"
|
|
373
|
+
" a bespoke workbook from PHE. This has space for 20 "
|
|
374
|
+
"projections.".format(max_events),
|
|
375
|
+
)
|
|
376
|
+
else:
|
|
377
|
+
messages.info(request, "PHE 2019 DX Study export started.")
|
|
378
|
+
job = run_in_background(
|
|
379
|
+
dx_phe_2019,
|
|
380
|
+
"export_dx",
|
|
381
|
+
request.GET,
|
|
382
|
+
request.user.id,
|
|
383
|
+
projection=False,
|
|
384
|
+
bespoke=bespoke,
|
|
385
|
+
)
|
|
386
|
+
logger.debug(
|
|
387
|
+
"Export PHE 2019 DX survey format job is {0}".format(job.id)
|
|
388
|
+
)
|
|
389
|
+
return redirect(reverse_lazy("export"))
|
|
390
|
+
else:
|
|
391
|
+
messages.error(request, "Malformed export URL {0}".format(type))
|
|
392
|
+
return redirect(
|
|
393
|
+
"{0}?{1}".format(
|
|
394
|
+
reverse_lazy("dx_summary_list_filter"),
|
|
395
|
+
urllib.urlencode(request.GET),
|
|
396
|
+
)
|
|
397
|
+
)
|
|
398
|
+
else:
|
|
399
|
+
messages.error(request, "Only users in the Export group can launch exports")
|
|
400
|
+
return redirect(
|
|
401
|
+
"{0}?{1}".format(
|
|
402
|
+
reverse_lazy("dx_summary_list_filter"), urllib.urlencode(request.GET)
|
|
403
|
+
)
|
|
404
|
+
)
|
|
405
|
+
|
|
406
|
+
|
|
407
|
+
@csrf_exempt
|
|
408
|
+
@login_required
|
|
409
|
+
def flcsv1(request, name=None, pat_id=None):
|
|
410
|
+
"""
|
|
411
|
+
View to launch task to export fluoroscopy studies to csv file
|
|
412
|
+
|
|
413
|
+
:param request: Contains the database filtering parameters. Also used to get user group.
|
|
414
|
+
:param name: string, 0 or 1 from URL indicating if names should be exported
|
|
415
|
+
:param pat_id: string, 0 or 1 from URL indicating if patient ID should be exported
|
|
416
|
+
:type request: GET
|
|
417
|
+
"""
|
|
418
|
+
pid = include_pid(request, name, pat_id)
|
|
419
|
+
|
|
420
|
+
if request.user.groups.filter(name="exportgroup"):
|
|
421
|
+
job = run_in_background(
|
|
422
|
+
exportFL2excel,
|
|
423
|
+
"export_fl",
|
|
424
|
+
request.GET,
|
|
425
|
+
pid["pidgroup"],
|
|
426
|
+
pid["include_names"],
|
|
427
|
+
pid["include_pat_id"],
|
|
428
|
+
request.user.id,
|
|
429
|
+
)
|
|
430
|
+
logger.debug("Export Fluoro to CSV job is {0}".format(job.id))
|
|
431
|
+
|
|
432
|
+
return redirect(reverse_lazy("export"))
|
|
433
|
+
|
|
434
|
+
|
|
435
|
+
@csrf_exempt
|
|
436
|
+
@login_required
|
|
437
|
+
def rfxlsx1(request, name=None, pat_id=None):
|
|
438
|
+
"""
|
|
439
|
+
View to launch task to export fluoroscopy studies to xlsx file
|
|
440
|
+
|
|
441
|
+
:param request: Contains the database filtering parameters. Also used to get user group.
|
|
442
|
+
:param name: string, 0 or 1 from URL indicating if names should be exported
|
|
443
|
+
:param pat_id: string, 0 or 1 from URL indicating if patient ID should be exported
|
|
444
|
+
:type request: GET
|
|
445
|
+
"""
|
|
446
|
+
pid = include_pid(request, name, pat_id)
|
|
447
|
+
|
|
448
|
+
if request.user.groups.filter(name="exportgroup"):
|
|
449
|
+
job = run_in_background(
|
|
450
|
+
rfxlsx,
|
|
451
|
+
"export_rf",
|
|
452
|
+
request.GET,
|
|
453
|
+
pid["pidgroup"],
|
|
454
|
+
pid["include_names"],
|
|
455
|
+
pid["include_pat_id"],
|
|
456
|
+
request.user.id,
|
|
457
|
+
)
|
|
458
|
+
logger.debug("Export Fluoro to XLSX job is {0}".format(job.id))
|
|
459
|
+
|
|
460
|
+
return redirect(reverse_lazy("export"))
|
|
461
|
+
|
|
462
|
+
|
|
463
|
+
@csrf_exempt
|
|
464
|
+
@login_required
|
|
465
|
+
def rfopenskin(request, pk):
|
|
466
|
+
"""
|
|
467
|
+
Create csv export suitable for import to standalone openSkin
|
|
468
|
+
:param request: request object
|
|
469
|
+
:param pk: primary key of study in GeneralStudyModuleAttr table
|
|
470
|
+
"""
|
|
471
|
+
export = get_object_or_404(GeneralStudyModuleAttr, pk=pk)
|
|
472
|
+
|
|
473
|
+
if request.user.groups.filter(name="exportgroup"):
|
|
474
|
+
job = run_in_background(rfopenskin_csv, "export_rf", export.pk)
|
|
475
|
+
logger.debug("Export Fluoro to openSkin CSV job is {0}".format(job.id))
|
|
476
|
+
|
|
477
|
+
return redirect(reverse_lazy("export"))
|
|
478
|
+
|
|
479
|
+
|
|
480
|
+
@csrf_exempt
|
|
481
|
+
@login_required
|
|
482
|
+
def rf_xlsx_phe2019(request):
|
|
483
|
+
"""
|
|
484
|
+
View to launch task to export fluoro studies to xlsx file in PHE 2019 IR/fluoro survey format
|
|
485
|
+
|
|
486
|
+
:param request: Contains the database filtering parameters and user details.
|
|
487
|
+
"""
|
|
488
|
+
if request.user.groups.filter(name="exportgroup"):
|
|
489
|
+
job = run_in_background(rf_phe_2019, "export_rf", request.GET, request.user.id)
|
|
490
|
+
logger.debug(
|
|
491
|
+
"Export PHE 2019 IR/fluoro survey format job is {0}.".format(job.id)
|
|
492
|
+
)
|
|
493
|
+
return redirect(reverse_lazy("export"))
|
|
494
|
+
else:
|
|
495
|
+
messages.error(request, "Only users in the Export group can launch exports")
|
|
496
|
+
return redirect(
|
|
497
|
+
"{0}?{1}".format(
|
|
498
|
+
reverse_lazy("rf_summary_list_filter"), urllib.urlencode(request.GET)
|
|
499
|
+
)
|
|
500
|
+
)
|
|
501
|
+
|
|
502
|
+
|
|
503
|
+
@csrf_exempt
|
|
504
|
+
@login_required
|
|
505
|
+
def mgcsv1(request, name=None, pat_id=None):
|
|
506
|
+
"""
|
|
507
|
+
Launches export of mammo data to CSV
|
|
508
|
+
:param request: Contains the database filtering parameters. Also used to get user group.
|
|
509
|
+
:param name: string, 0 or 1 from URL indicating if names should be exported
|
|
510
|
+
:param pat_id: string, 0 or 1 from URL indicating if patient ID should be exported
|
|
511
|
+
:return:
|
|
512
|
+
"""
|
|
513
|
+
pid = include_pid(request, name, pat_id)
|
|
514
|
+
|
|
515
|
+
if request.user.groups.filter(name="exportgroup"):
|
|
516
|
+
job = run_in_background(
|
|
517
|
+
exportMG2csv,
|
|
518
|
+
"export_mg",
|
|
519
|
+
request.GET,
|
|
520
|
+
pid["pidgroup"],
|
|
521
|
+
pid["include_names"],
|
|
522
|
+
pid["include_pat_id"],
|
|
523
|
+
request.user.id,
|
|
524
|
+
)
|
|
525
|
+
logger.debug("Export MG to CSV job is {0}".format(job.id))
|
|
526
|
+
|
|
527
|
+
return redirect(reverse_lazy("export"))
|
|
528
|
+
|
|
529
|
+
|
|
530
|
+
@csrf_exempt
|
|
531
|
+
@login_required
|
|
532
|
+
def mgxlsx1(request, name=None, pat_id=None):
|
|
533
|
+
"""
|
|
534
|
+
Launches export of mammo data to xlsx
|
|
535
|
+
:param request: Contains the database filtering parameters. Also used to get user group.
|
|
536
|
+
:param name: string, 0 or 1 from URL indicating if names should be exported
|
|
537
|
+
:param pat_id: string, 0 or 1 from URL indicating if patient ID should be exported
|
|
538
|
+
:return:
|
|
539
|
+
"""
|
|
540
|
+
pid = include_pid(request, name, pat_id)
|
|
541
|
+
|
|
542
|
+
if request.user.groups.filter(name="exportgroup"):
|
|
543
|
+
|
|
544
|
+
filter_dict = request.GET.dict()
|
|
545
|
+
if "mg_acquisition_type" in filter_dict:
|
|
546
|
+
filter_dict["mg_acquisition_type"] = request.GET.getlist(
|
|
547
|
+
"mg_acquisition_type"
|
|
548
|
+
)
|
|
549
|
+
|
|
550
|
+
job = run_in_background(
|
|
551
|
+
mgxlsx,
|
|
552
|
+
"export_mg",
|
|
553
|
+
filter_dict,
|
|
554
|
+
pid["pidgroup"],
|
|
555
|
+
pid["include_names"],
|
|
556
|
+
pid["include_pat_id"],
|
|
557
|
+
request.user.id,
|
|
558
|
+
)
|
|
559
|
+
logger.debug("Export MG to xlsx job is {0}".format(job.id))
|
|
560
|
+
|
|
561
|
+
return redirect(reverse_lazy("export"))
|
|
562
|
+
|
|
563
|
+
|
|
564
|
+
@csrf_exempt
|
|
565
|
+
@login_required
|
|
566
|
+
def mgnhsbsp(request):
|
|
567
|
+
"""
|
|
568
|
+
View to launch task to export mammography studies to csv file using a NHSBSP template
|
|
569
|
+
|
|
570
|
+
:param request: Contains the database filtering parameters. Also used to get user group.
|
|
571
|
+
:type request: GET
|
|
572
|
+
"""
|
|
573
|
+
if request.user.groups.filter(name="exportgroup"):
|
|
574
|
+
job = run_in_background(
|
|
575
|
+
mg_csv_nhsbsp, "export_mg", request.GET, request.user.id
|
|
576
|
+
)
|
|
577
|
+
logger.debug("Export MG to CSV NHSBSP job is {0}".format(job.id))
|
|
578
|
+
|
|
579
|
+
return redirect(reverse_lazy("export"))
|
|
580
|
+
|
|
581
|
+
|
|
582
|
+
@csrf_exempt
|
|
583
|
+
@login_required
|
|
584
|
+
def export(request):
|
|
585
|
+
"""
|
|
586
|
+
View to list current and completed exports to track progress, download and delete
|
|
587
|
+
|
|
588
|
+
:param request: Used to get user group.
|
|
589
|
+
"""
|
|
590
|
+
try:
|
|
591
|
+
complete = Exports.objects.filter(status__contains="COMPLETE").order_by(
|
|
592
|
+
"-export_date"
|
|
593
|
+
)
|
|
594
|
+
latest_complete_pk = complete[0].pk
|
|
595
|
+
except IndexError:
|
|
596
|
+
complete = None
|
|
597
|
+
latest_complete_pk = 0
|
|
598
|
+
|
|
599
|
+
admin = {
|
|
600
|
+
"openremversion": __version__,
|
|
601
|
+
"docsversion": __docs_version__,
|
|
602
|
+
}
|
|
603
|
+
for group in request.user.groups.all():
|
|
604
|
+
admin[group.name] = True
|
|
605
|
+
template = "remapp/exports.html"
|
|
606
|
+
|
|
607
|
+
return render(
|
|
608
|
+
request,
|
|
609
|
+
template,
|
|
610
|
+
{
|
|
611
|
+
"admin": admin,
|
|
612
|
+
"latest_complete_pk": latest_complete_pk,
|
|
613
|
+
"complete": complete,
|
|
614
|
+
},
|
|
615
|
+
)
|
|
616
|
+
|
|
617
|
+
|
|
618
|
+
@login_required
|
|
619
|
+
def download(request, task_id):
|
|
620
|
+
"""
|
|
621
|
+
View to handle downloads of files from the server
|
|
622
|
+
|
|
623
|
+
Originally used for download of the export spreadsheets, now also used
|
|
624
|
+
for downloading the patient size import logfiles.
|
|
625
|
+
|
|
626
|
+
:param request: Used to get user group.
|
|
627
|
+
:param task_id: ID of the export or logfile
|
|
628
|
+
|
|
629
|
+
"""
|
|
630
|
+
exportperm = False
|
|
631
|
+
pidperm = False
|
|
632
|
+
if request.user.groups.filter(name="exportgroup"):
|
|
633
|
+
exportperm = True
|
|
634
|
+
if request.user.groups.filter(name="pidgroup"):
|
|
635
|
+
pidperm = True
|
|
636
|
+
try:
|
|
637
|
+
exp = Exports.objects.get(task_id__exact=task_id)
|
|
638
|
+
except ObjectDoesNotExist:
|
|
639
|
+
messages.error(request, "Can't match the task ID, download aborted")
|
|
640
|
+
return redirect(reverse_lazy("export"))
|
|
641
|
+
|
|
642
|
+
if not exportperm:
|
|
643
|
+
messages.error(request, "You don't have permission to download exported data")
|
|
644
|
+
return redirect(reverse_lazy("export"))
|
|
645
|
+
|
|
646
|
+
if exp.includes_pid and not pidperm:
|
|
647
|
+
messages.error(
|
|
648
|
+
request,
|
|
649
|
+
"You don't have permission to download export data that includes patient identifiable information",
|
|
650
|
+
)
|
|
651
|
+
return redirect(reverse_lazy("export"))
|
|
652
|
+
|
|
653
|
+
file_path = os.path.join(settings.MEDIA_ROOT, exp.filename.name)
|
|
654
|
+
with open(file_path, mode="rb") as f:
|
|
655
|
+
file_wrapper = FileWrapper(f)
|
|
656
|
+
file_mimetype = mimetypes.guess_type(file_path)
|
|
657
|
+
response = HttpResponse(file_wrapper, content_type=file_mimetype)
|
|
658
|
+
response["X-Sendfile"] = file_path
|
|
659
|
+
response["Content-Length"] = os.stat(file_path).st_size
|
|
660
|
+
response["Content-Disposition"] = "attachment; filename=%s" % smart_str(
|
|
661
|
+
exp.filename
|
|
662
|
+
) # pylint: disable=consider-using-f-string
|
|
663
|
+
return response
|
|
664
|
+
|
|
665
|
+
|
|
666
|
+
@csrf_exempt
|
|
667
|
+
@login_required
|
|
668
|
+
def deletefile(request):
|
|
669
|
+
"""
|
|
670
|
+
View to delete export files from the server
|
|
671
|
+
|
|
672
|
+
:param request: Contains the task ID
|
|
673
|
+
:type request: POST
|
|
674
|
+
"""
|
|
675
|
+
for task in request.POST:
|
|
676
|
+
exports = Exports.objects.filter(task_id__exact=request.POST[task])
|
|
677
|
+
for export_object in exports:
|
|
678
|
+
try:
|
|
679
|
+
export_object.filename.delete()
|
|
680
|
+
export_object.delete()
|
|
681
|
+
messages.success(
|
|
682
|
+
request, "Export file and database entry deleted successfully."
|
|
683
|
+
)
|
|
684
|
+
except OSError as e:
|
|
685
|
+
messages.error(
|
|
686
|
+
request,
|
|
687
|
+
f"Export file delete failed - please contact an administrator. Error({e.errno}): {e.strerror}", # pylint: disable=line-too-long
|
|
688
|
+
)
|
|
689
|
+
except Exception:
|
|
690
|
+
messages.error(
|
|
691
|
+
request,
|
|
692
|
+
f"Unexpected error - please contact an administrator: {sys.exc_info()[0]}",
|
|
693
|
+
)
|
|
694
|
+
|
|
695
|
+
return HttpResponseRedirect(reverse(export))
|
|
696
|
+
|
|
697
|
+
|
|
698
|
+
@login_required
|
|
699
|
+
def export_abort(request, pk):
|
|
700
|
+
"""
|
|
701
|
+
View to abort current export job
|
|
702
|
+
|
|
703
|
+
:param request: Contains the task primary key
|
|
704
|
+
:type request: POST
|
|
705
|
+
"""
|
|
706
|
+
if pk and request.user.groups.filter(name="exportgroup"):
|
|
707
|
+
export_task = get_object_or_404(Exports, pk=pk)
|
|
708
|
+
try:
|
|
709
|
+
task = BackgroundTask.objects.get(uuid=export_task.task_id)
|
|
710
|
+
terminate_background(task)
|
|
711
|
+
except ObjectDoesNotExist:
|
|
712
|
+
pass
|
|
713
|
+
export_task.delete()
|
|
714
|
+
logger.info(
|
|
715
|
+
f"Export task {export_task.task_id} terminated from the Exports interface"
|
|
716
|
+
)
|
|
717
|
+
return HttpResponseRedirect(reverse_lazy("export"))
|
|
718
|
+
|
|
719
|
+
|
|
720
|
+
@login_required
|
|
721
|
+
def export_remove(request, task_id=None):
|
|
722
|
+
"""
|
|
723
|
+
Function to remove export task from queue
|
|
724
|
+
|
|
725
|
+
:param request: Contains the task primary key
|
|
726
|
+
:param task_id: UUID of task in question
|
|
727
|
+
:type request: POST
|
|
728
|
+
"""
|
|
729
|
+
if task_id and request.user.groups.filter(name="exportgroup"):
|
|
730
|
+
remove_task_from_queue(task_id)
|
|
731
|
+
logger.info(f"Export task {task_id} removed from queue")
|
|
732
|
+
|
|
733
|
+
return HttpResponseRedirect(reverse_lazy("export"))
|
|
734
|
+
|
|
735
|
+
|
|
736
|
+
@csrf_exempt
|
|
737
|
+
@login_required
|
|
738
|
+
def update_queue(request):
|
|
739
|
+
"""
|
|
740
|
+
AJAX function to return queued exports
|
|
741
|
+
|
|
742
|
+
:param request: Request object
|
|
743
|
+
:return: HTML table of active exports
|
|
744
|
+
"""
|
|
745
|
+
template = "remapp/exports-queue.html"
|
|
746
|
+
if request.is_ajax():
|
|
747
|
+
queued_export_tasks = get_queued_tasks(task_type="export")
|
|
748
|
+
return render(request, template, {"queued": queued_export_tasks})
|
|
749
|
+
|
|
750
|
+
return render(request, template)
|
|
751
|
+
|
|
752
|
+
|
|
753
|
+
@csrf_exempt
|
|
754
|
+
@login_required
|
|
755
|
+
def update_active(request):
|
|
756
|
+
"""
|
|
757
|
+
AJAX function to return active exports
|
|
758
|
+
|
|
759
|
+
:param request: Request object
|
|
760
|
+
:return: HTML table of active exports
|
|
761
|
+
"""
|
|
762
|
+
template = "remapp/exports-active.html"
|
|
763
|
+
if request.is_ajax():
|
|
764
|
+
current_export_tasks = Exports.objects.filter(
|
|
765
|
+
status__contains="CURRENT"
|
|
766
|
+
).order_by("-export_date")
|
|
767
|
+
return render(request, template, {"current": current_export_tasks})
|
|
768
|
+
|
|
769
|
+
return render(request, template)
|
|
770
|
+
|
|
771
|
+
|
|
772
|
+
@csrf_exempt
|
|
773
|
+
@login_required
|
|
774
|
+
def update_error(request):
|
|
775
|
+
"""
|
|
776
|
+
AJAX function to return exports in error state
|
|
777
|
+
|
|
778
|
+
:param request: Request object
|
|
779
|
+
:return: HTML table of exports in error state
|
|
780
|
+
"""
|
|
781
|
+
template = "remapp/exports-error.html"
|
|
782
|
+
if request.is_ajax():
|
|
783
|
+
error_export_tasks = Exports.objects.filter(status__contains="ERROR").order_by(
|
|
784
|
+
"-export_date"
|
|
785
|
+
)
|
|
786
|
+
return render(request, template, {"errors": error_export_tasks})
|
|
787
|
+
|
|
788
|
+
return render(request, template)
|
|
789
|
+
|
|
790
|
+
|
|
791
|
+
@csrf_exempt
|
|
792
|
+
@login_required
|
|
793
|
+
def update_complete(request):
|
|
794
|
+
"""
|
|
795
|
+
AJAX function to return recently completed exports
|
|
796
|
+
|
|
797
|
+
:param request: Request object, including pk of latest complete export at initial page load
|
|
798
|
+
:return: HTML table of completed exports
|
|
799
|
+
"""
|
|
800
|
+
template = "remapp/exports-complete.html"
|
|
801
|
+
if request.is_ajax():
|
|
802
|
+
data = request.POST
|
|
803
|
+
latest_complete_pk = data.get("latest_complete_pk")
|
|
804
|
+
in_pid_group = data.get("in_pid_group")
|
|
805
|
+
complete_export_tasks = Exports.objects.filter(
|
|
806
|
+
status__contains="COMPLETE"
|
|
807
|
+
).filter(pk__gt=latest_complete_pk)
|
|
808
|
+
|
|
809
|
+
return render(
|
|
810
|
+
request,
|
|
811
|
+
template,
|
|
812
|
+
{"complete": complete_export_tasks, "in_pid_group": in_pid_group},
|
|
813
|
+
)
|
|
814
|
+
|
|
815
|
+
return render(request, template)
|