├── Backend
├── __init__.py
├── accounts
│ ├── __init__.py
│ ├── api
│ │ ├── __init__.py
│ │ ├── views
│ │ │ └── __init__.py
│ │ └── serializers
│ │ │ ├── __init__.py
│ │ │ ├── ProfileSerializer.py
│ │ │ ├── UserProfileSerializer.py
│ │ │ └── UserSerializer.py
│ ├── tests
│ │ ├── __init__.py
│ │ ├── testProfileSerializer.py
│ │ ├── testProfile.py
│ │ └── testUserRecovery.py
│ ├── management
│ │ ├── __init__.py
│ │ └── commands
│ │ │ ├── __init__.py
│ │ │ └── cdsu.py
│ ├── migrations
│ │ └── __init__.py
│ ├── models
│ │ ├── __init__.py
│ │ ├── Profile.py
│ │ └── UserRecovery.py
│ ├── views.py
│ ├── apps.py
│ ├── admin.py
│ └── urls.py
├── history
│ ├── __init__.py
│ ├── api
│ │ ├── __init__.py
│ │ ├── serializers
│ │ │ ├── __init__.py
│ │ │ ├── GenericObjectField.py
│ │ │ └── HistorySerializer.py
│ │ └── views
│ │ │ ├── __init__.py
│ │ │ ├── HistoryViewSet.py
│ │ │ └── FilteredHistoryListView.py
│ ├── tests
│ │ └── __init__.py
│ ├── migrations
│ │ └── __init__.py
│ ├── models
│ │ ├── __init__.py
│ │ └── HistoryRelated.py
│ ├── views.py
│ ├── apps.py
│ └── admin.py
├── patients
│ ├── __init__.py
│ ├── api
│ │ ├── __init__.py
│ │ ├── views
│ │ │ ├── __init__.py
│ │ │ ├── ClinicalVariableViewSet.py
│ │ │ ├── PatientViewSet.py
│ │ │ ├── PatientCVsViewSet.py
│ │ │ └── AdmissionViewSet.py
│ │ └── serializers
│ │ │ ├── __init__.py
│ │ │ ├── CVPatientSerializer.py
│ │ │ ├── ClinicalVariableSerializer.py
│ │ │ ├── CVGroupSerializer.py
│ │ │ ├── PatientSerializer.py
│ │ │ └── AdmissionSerializer.py
│ ├── tests
│ │ └── __init__.py
│ ├── management
│ │ ├── __init__.py
│ │ └── commands
│ │ │ └── __init__.py
│ ├── migrations
│ │ └── __init__.py
│ ├── views.py
│ ├── apps.py
│ ├── models
│ │ ├── __init__.py
│ │ ├── CVOption.py
│ │ ├── CVGroup.py
│ │ ├── CVPatient.py
│ │ ├── Patient.py
│ │ ├── ClinicalVariable.py
│ │ └── Admission.py
│ ├── urls.py
│ └── admin.py
├── protocol
│ ├── __init__.py
│ ├── api
│ │ ├── __init__.py
│ │ ├── views
│ │ │ ├── __init__.py
│ │ │ ├── ScheduleViewSet.py
│ │ │ ├── AssignedProtocolViewSet.py
│ │ │ └── ExecutedProtocolViewSet.py
│ │ └── serializers
│ │ │ ├── __init__.py
│ │ │ ├── ScheduleSerializer.py
│ │ │ ├── AssignedProtocolSerializer.py
│ │ │ ├── ProtocolSerializer.py
│ │ │ └── ExecutedProtocolSerializer.py
│ ├── tests
│ │ └── __init__.py
│ ├── management
│ │ ├── __init__.py
│ │ └── commands
│ │ │ ├── __init__.py
│ │ │ ├── cleanAllProtocols.py
│ │ │ ├── diabeticInpatients.py
│ │ │ ├── surgicalDiabeticInpatient.py
│ │ │ └── continuousIntravenousInfusion.py
│ ├── migrations
│ │ └── __init__.py
│ ├── models
│ │ ├── __init__.py
│ │ ├── Time.py
│ │ ├── Schedule.py
│ │ └── AssignedProtocol.py
│ ├── views.py
│ ├── apps.py
│ ├── urls.py
│ └── admin.py
├── utils
│ ├── __init__.py
│ ├── api
│ │ ├── __init__.py
│ │ └── views
│ │ │ ├── LanguageView.py
│ │ │ ├── __init__.py
│ │ │ ├── FlatPagesView.py
│ │ │ └── ConstanceView.py
│ ├── tests
│ │ └── __init__.py
│ ├── management
│ │ ├── __init__.py
│ │ └── commands
│ │ │ ├── __init__.py
│ │ │ └── populate_flatpages.py
│ ├── migrations
│ │ └── __init__.py
│ ├── models
│ │ ├── __init__.py
│ │ ├── Language.py
│ │ └── Multilingual.py
│ ├── views.py
│ ├── apps.py
│ ├── time.py
│ ├── hashes.py
│ ├── urls.py
│ └── admin.py
├── genericcdss
│ ├── __init__.py
│ ├── wsgi.py
│ └── urls.py
├── protocol_element
│ ├── __init__.py
│ ├── api
│ │ ├── __init__.py
│ │ └── serializers
│ │ │ ├── __init__.py
│ │ │ ├── PENextElementsSerializer.py
│ │ │ ├── PEActionSerializer.py
│ │ │ ├── ProtocolElementSerializer.py
│ │ │ ├── PEInquirySerializer.py
│ │ │ ├── PEDecisionSerializer.py
│ │ │ └── PolymorphicSerializer.py
│ ├── tests
│ │ └── __init__.py
│ ├── management
│ │ ├── __init__.py
│ │ └── commands
│ │ │ └── __init__.py
│ ├── migrations
│ │ └── __init__.py
│ ├── admin.py
│ ├── views.py
│ ├── apps.py
│ └── models
│ │ ├── __init__.py
│ │ ├── PENextElements.py
│ │ ├── PEInquiry.py
│ │ ├── PEAction.py
│ │ └── PEDecision.py
└── manage.py
├── UI
├── public
│ ├── favicon.ico
│ ├── images
│ │ ├── logo.png
│ │ ├── logo_small.png
│ │ └── home_wallpaper.jpg
│ └── index.html
├── src
│ ├── css
│ │ ├── externalImportsConfigs.css
│ │ ├── imports.css
│ │ ├── Table.css
│ │ ├── LoginComponent.css
│ │ ├── Select.css
│ │ └── Texts.css
│ ├── externalImports
│ │ └── mfglabs-iconset
│ │ │ ├── img
│ │ │ └── mfg_logo_r.jpg
│ │ │ ├── css
│ │ │ └── font
│ │ │ │ ├── gibson-webfont.eot
│ │ │ │ ├── gibson-webfont.ttf
│ │ │ │ ├── gibson-webfont.woff
│ │ │ │ ├── mfglabsiconset-webfont.eot
│ │ │ │ ├── mfglabsiconset-webfont.ttf
│ │ │ │ ├── gibson-semibold-webfont.eot
│ │ │ │ ├── gibson-semibold-webfont.ttf
│ │ │ │ ├── gibson-semibold-webfont.woff
│ │ │ │ ├── mfglabsiconset-webfont.woff
│ │ │ │ ├── gibson-light-italic-webfont.eot
│ │ │ │ ├── gibson-light-italic-webfont.ttf
│ │ │ │ └── gibson-light-italic-webfont.woff
│ │ │ ├── bower.json
│ │ │ └── README.md
│ ├── js
│ │ ├── components
│ │ │ ├── globalComponents
│ │ │ │ ├── History.js
│ │ │ │ ├── Language.js
│ │ │ │ ├── Footer.js
│ │ │ │ ├── LoginButton.js
│ │ │ │ ├── Header.js
│ │ │ │ ├── LoginComponent.js
│ │ │ │ └── Routes.js
│ │ │ ├── accountManager
│ │ │ │ ├── Register.js
│ │ │ │ └── ForgotPass.js
│ │ │ ├── errorPages
│ │ │ │ ├── http500.js
│ │ │ │ ├── http404.js
│ │ │ │ └── http0.js
│ │ │ ├── patient
│ │ │ │ ├── PatientStatus.js
│ │ │ │ ├── ShowPatient.js
│ │ │ │ ├── PatientComplementInfo.js
│ │ │ │ ├── AddPatient.js
│ │ │ │ ├── ClinicalVariables.js
│ │ │ │ ├── AllPatients.js
│ │ │ │ └── AdmittedPatients.js
│ │ │ ├── protocol
│ │ │ │ ├── ProtocolType.js
│ │ │ │ ├── ProtocolCostumization.js
│ │ │ │ ├── ExecutedProtocols.js
│ │ │ │ ├── AssignedProtocols.js
│ │ │ │ ├── Schedules.js
│ │ │ │ ├── Protocols.js
│ │ │ │ └── SelectedProtocols.js
│ │ │ ├── reusable
│ │ │ │ ├── MyLink.js
│ │ │ │ └── DisplayField.js
│ │ │ ├── dynamicPages
│ │ │ │ ├── Help.js
│ │ │ │ ├── About.js
│ │ │ │ └── Home.js
│ │ │ ├── buttons
│ │ │ │ └── PatientButtonBar.js
│ │ │ └── protocolElements
│ │ │ │ └── ActionElement.js
│ │ ├── GlobalSettings.js
│ │ ├── reflux
│ │ │ ├── ScheduleReflux.js
│ │ │ ├── ClinicalVariablesReflux.js
│ │ │ ├── PatientClinicalVariablesReflux.js
│ │ │ ├── AdmissionReflux.js
│ │ │ ├── StateReflux.js
│ │ │ ├── PatientReflux.js
│ │ │ └── UserReflux.js
│ │ └── App.js
│ └── index.js
└── package.json
├── Dockerfile
├── .gitignore
├── config
├── requirements.pip
├── nginx
│ └── genericcdss.conf
└── run_docker.sh
├── docker-compose.yml
├── Makefile
└── README.md
/Backend/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Backend/accounts/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Backend/history/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Backend/patients/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Backend/protocol/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Backend/utils/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Backend/accounts/api/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Backend/genericcdss/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Backend/history/api/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Backend/history/tests/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Backend/patients/api/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Backend/protocol/api/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Backend/utils/api/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Backend/utils/tests/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Backend/accounts/tests/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Backend/history/migrations/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Backend/patients/tests/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Backend/protocol/tests/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Backend/protocol_element/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Backend/utils/management/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Backend/utils/migrations/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Backend/accounts/management/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Backend/accounts/migrations/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Backend/patients/management/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Backend/patients/migrations/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Backend/protocol/management/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Backend/protocol/migrations/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Backend/protocol_element/api/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Backend/protocol_element/tests/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Backend/utils/api/views/LanguageView.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Backend/accounts/management/commands/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Backend/patients/management/commands/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Backend/protocol/management/commands/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Backend/protocol_element/management/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Backend/protocol_element/migrations/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Backend/utils/management/commands/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Backend/protocol_element/management/commands/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Backend/accounts/api/views/__init__.py:
--------------------------------------------------------------------------------
1 | from .UserViewSet import UserViewSet
--------------------------------------------------------------------------------
/Backend/accounts/models/__init__.py:
--------------------------------------------------------------------------------
1 | from .Profile import Profile
2 | from .UserRecovery import UserRecovery
--------------------------------------------------------------------------------
/Backend/utils/models/__init__.py:
--------------------------------------------------------------------------------
1 | from .Language import Language
2 | from .Multilingual import Multilingual
--------------------------------------------------------------------------------
/UI/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bioinformatics-ua/GenericCDSS/HEAD/UI/public/favicon.ico
--------------------------------------------------------------------------------
/Backend/history/models/__init__.py:
--------------------------------------------------------------------------------
1 | from .HistoryRelated import HistoryRelated
2 | from .History import History
--------------------------------------------------------------------------------
/UI/public/images/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bioinformatics-ua/GenericCDSS/HEAD/UI/public/images/logo.png
--------------------------------------------------------------------------------
/Backend/utils/api/views/__init__.py:
--------------------------------------------------------------------------------
1 | from .ConstanceView import ConstanceView
2 | from .FlatPagesView import FlatPagesView
--------------------------------------------------------------------------------
/UI/public/images/logo_small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bioinformatics-ua/GenericCDSS/HEAD/UI/public/images/logo_small.png
--------------------------------------------------------------------------------
/UI/public/images/home_wallpaper.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bioinformatics-ua/GenericCDSS/HEAD/UI/public/images/home_wallpaper.jpg
--------------------------------------------------------------------------------
/UI/src/css/externalImportsConfigs.css:
--------------------------------------------------------------------------------
1 | .icon-user_male{
2 | color: #007bff;
3 | }
4 |
5 | .icon-user_female{
6 | color: #f4b5d8;
7 | }
--------------------------------------------------------------------------------
/Backend/history/api/serializers/__init__.py:
--------------------------------------------------------------------------------
1 | from .GenericObjectField import GenericObjectField
2 | from .HistorySerializer import HistorySerializer
--------------------------------------------------------------------------------
/Backend/history/api/views/__init__.py:
--------------------------------------------------------------------------------
1 | from .HistoryViewSet import HistoryViewSet
2 | from .FilteredHistoryListView import FilteredHistoryListView
--------------------------------------------------------------------------------
/Backend/accounts/views.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.shortcuts import render
5 |
6 | # Create your views here.
7 |
--------------------------------------------------------------------------------
/Backend/history/views.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.shortcuts import render
5 |
6 | # Create your views here.
7 |
--------------------------------------------------------------------------------
/Backend/patients/views.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.shortcuts import render
5 |
6 | # Create your views here.
7 |
--------------------------------------------------------------------------------
/Backend/protocol/models/__init__.py:
--------------------------------------------------------------------------------
1 | from .Time import Time
2 | from .Schedule import Schedule
3 | from .Protocol import Protocol
4 | from .ExecutedProtocol import ExecutedProtocol
--------------------------------------------------------------------------------
/Backend/protocol/views.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.shortcuts import render
5 |
6 | # Create your views here.
7 |
--------------------------------------------------------------------------------
/Backend/utils/views.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.shortcuts import render
5 |
6 | # Create your views here.
7 |
--------------------------------------------------------------------------------
/UI/src/externalImports/mfglabs-iconset/img/mfg_logo_r.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bioinformatics-ua/GenericCDSS/HEAD/UI/src/externalImports/mfglabs-iconset/img/mfg_logo_r.jpg
--------------------------------------------------------------------------------
/Backend/protocol_element/admin.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.contrib import admin
5 |
6 | # Register your models here.
7 |
--------------------------------------------------------------------------------
/Backend/protocol_element/views.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.shortcuts import render
5 |
6 | # Create your views here.
7 |
--------------------------------------------------------------------------------
/UI/src/externalImports/mfglabs-iconset/css/font/gibson-webfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bioinformatics-ua/GenericCDSS/HEAD/UI/src/externalImports/mfglabs-iconset/css/font/gibson-webfont.eot
--------------------------------------------------------------------------------
/UI/src/externalImports/mfglabs-iconset/css/font/gibson-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bioinformatics-ua/GenericCDSS/HEAD/UI/src/externalImports/mfglabs-iconset/css/font/gibson-webfont.ttf
--------------------------------------------------------------------------------
/Backend/accounts/api/serializers/__init__.py:
--------------------------------------------------------------------------------
1 | from .ProfileSerializer import ProfileSerializer
2 | from .UserSerializer import UserSerializer
3 | from .UserProfileSerializer import UserProfileSerializer
--------------------------------------------------------------------------------
/Backend/utils/apps.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.apps import AppConfig
5 |
6 |
7 | class UtilsConfig(AppConfig):
8 | name = 'utils'
9 |
--------------------------------------------------------------------------------
/UI/src/externalImports/mfglabs-iconset/css/font/gibson-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bioinformatics-ua/GenericCDSS/HEAD/UI/src/externalImports/mfglabs-iconset/css/font/gibson-webfont.woff
--------------------------------------------------------------------------------
/Backend/accounts/apps.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.apps import AppConfig
5 |
6 |
7 | class AccountsConfig(AppConfig):
8 | name = 'accounts'
9 |
--------------------------------------------------------------------------------
/Backend/history/apps.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.apps import AppConfig
5 |
6 |
7 | class HistoryConfig(AppConfig):
8 | name = 'history'
9 |
--------------------------------------------------------------------------------
/Backend/patients/apps.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.apps import AppConfig
5 |
6 |
7 | class PatientsConfig(AppConfig):
8 | name = 'patients'
9 |
--------------------------------------------------------------------------------
/Backend/protocol/apps.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.apps import AppConfig
5 |
6 |
7 | class ProtocolConfig(AppConfig):
8 | name = 'protocol'
9 |
--------------------------------------------------------------------------------
/UI/src/externalImports/mfglabs-iconset/css/font/mfglabsiconset-webfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bioinformatics-ua/GenericCDSS/HEAD/UI/src/externalImports/mfglabs-iconset/css/font/mfglabsiconset-webfont.eot
--------------------------------------------------------------------------------
/UI/src/externalImports/mfglabs-iconset/css/font/mfglabsiconset-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bioinformatics-ua/GenericCDSS/HEAD/UI/src/externalImports/mfglabs-iconset/css/font/mfglabsiconset-webfont.ttf
--------------------------------------------------------------------------------
/UI/src/externalImports/mfglabs-iconset/css/font/gibson-semibold-webfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bioinformatics-ua/GenericCDSS/HEAD/UI/src/externalImports/mfglabs-iconset/css/font/gibson-semibold-webfont.eot
--------------------------------------------------------------------------------
/UI/src/externalImports/mfglabs-iconset/css/font/gibson-semibold-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bioinformatics-ua/GenericCDSS/HEAD/UI/src/externalImports/mfglabs-iconset/css/font/gibson-semibold-webfont.ttf
--------------------------------------------------------------------------------
/UI/src/externalImports/mfglabs-iconset/css/font/gibson-semibold-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bioinformatics-ua/GenericCDSS/HEAD/UI/src/externalImports/mfglabs-iconset/css/font/gibson-semibold-webfont.woff
--------------------------------------------------------------------------------
/UI/src/externalImports/mfglabs-iconset/css/font/mfglabsiconset-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bioinformatics-ua/GenericCDSS/HEAD/UI/src/externalImports/mfglabs-iconset/css/font/mfglabsiconset-webfont.woff
--------------------------------------------------------------------------------
/UI/src/externalImports/mfglabs-iconset/css/font/gibson-light-italic-webfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bioinformatics-ua/GenericCDSS/HEAD/UI/src/externalImports/mfglabs-iconset/css/font/gibson-light-italic-webfont.eot
--------------------------------------------------------------------------------
/UI/src/externalImports/mfglabs-iconset/css/font/gibson-light-italic-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bioinformatics-ua/GenericCDSS/HEAD/UI/src/externalImports/mfglabs-iconset/css/font/gibson-light-italic-webfont.ttf
--------------------------------------------------------------------------------
/UI/src/externalImports/mfglabs-iconset/css/font/gibson-light-italic-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bioinformatics-ua/GenericCDSS/HEAD/UI/src/externalImports/mfglabs-iconset/css/font/gibson-light-italic-webfont.woff
--------------------------------------------------------------------------------
/Backend/protocol_element/apps.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.apps import AppConfig
5 |
6 |
7 | class ProtocolElementConfig(AppConfig):
8 | name = 'protocol_element'
9 |
--------------------------------------------------------------------------------
/UI/src/js/components/globalComponents/History.js:
--------------------------------------------------------------------------------
1 | import createBrowserHistory from 'history/createBrowserHistory';
2 | import {base_url} from '../../../../package.json';
3 |
4 | export default createBrowserHistory({ basename: base_url });
--------------------------------------------------------------------------------
/Backend/utils/time.py:
--------------------------------------------------------------------------------
1 | from django.utils import timezone
2 |
3 | def nextMonth():
4 | return timezone.now() + timezone.timedelta(days=30)
5 |
6 | def sessionExpiringTime():
7 | return 1296000 # if set to remember, keep for 2 weeks
--------------------------------------------------------------------------------
/Backend/protocol_element/models/__init__.py:
--------------------------------------------------------------------------------
1 | from .ProtocolElement import ProtocolElement
2 | from .PENextElements import PENextElements
3 | from .PEAction import PEAction
4 | from .PEInquiry import PEInquiry
5 | from .PEDecision import PEDecision
--------------------------------------------------------------------------------
/Backend/patients/api/views/__init__.py:
--------------------------------------------------------------------------------
1 | from .PatientViewSet import PatientViewSet
2 | from .PatientCVsViewSet import PatientCVsViewSet
3 | from .AdmissionViewSet import AdmissionViewSet
4 | from .ClinicalVariableViewSet import ClinicalVariableViewSet
--------------------------------------------------------------------------------
/Backend/patients/models/__init__.py:
--------------------------------------------------------------------------------
1 | from .CVGroup import CVGroup
2 | from .ClinicalVariable import ClinicalVariable
3 | from .CVOption import CVOption
4 | from .Patient import Patient
5 | from .CVPatient import CVPatient
6 | from .Admission import Admission
7 |
--------------------------------------------------------------------------------
/Backend/protocol/api/views/__init__.py:
--------------------------------------------------------------------------------
1 | from .AssignedProtocolViewSet import AssignedProtocolViewSet
2 | from .ExecutedProtocolViewSet import ExecutedProtocolViewSet
3 | from .ProtocolViewSet import ProtocolViewSet
4 | from .ScheduleViewSet import ScheduleViewSet
5 |
--------------------------------------------------------------------------------
/UI/src/externalImports/mfglabs-iconset/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "mfglabs-iconset",
3 | "homepage": "https://github.com/MfgLabs/mfglabs-iconset",
4 | "description": "Awesome web font icon by MFG Labs",
5 | "main": "css/mfglabs_iconset.css",
6 | "license": "CC BY-SA"
7 | }
8 |
--------------------------------------------------------------------------------
/Backend/protocol/api/serializers/__init__.py:
--------------------------------------------------------------------------------
1 | from .AssignedProtocolSerializer import AssignedProtocolSerializer
2 | from .ExecutedProtocolSerializer import ExecutedProtocolSerializer
3 | from .ScheduleSerializer import ScheduleSerializer
4 | from .ProtocolSerializer import ProtocolSerializer
--------------------------------------------------------------------------------
/Backend/utils/hashes.py:
--------------------------------------------------------------------------------
1 | from hashids import Hashids
2 | import uuid
3 |
4 | def createHash(identificator):
5 | hashids = Hashids(salt="esh2YTBZesh2YTBZ", min_length=5)
6 |
7 | return hashids.encrypt(identificator)
8 |
9 |
10 | def createUUID():
11 | return uuid.uuid1().hex
12 |
--------------------------------------------------------------------------------
/Backend/protocol/models/Time.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.db import models
5 |
6 | class Time(models.Model):
7 | time = models.TimeField()
8 |
9 | def __unicode__(self):
10 | return self.time.strftime("%H:%M")
--------------------------------------------------------------------------------
/Backend/utils/models/Language.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.db import models
5 |
6 | class Language(models.Model):
7 | language = models.CharField(max_length=2)
8 |
9 | def __unicode__(self):
10 | return u"%s" % self.language
--------------------------------------------------------------------------------
/Backend/patients/api/serializers/__init__.py:
--------------------------------------------------------------------------------
1 | from .PatientSerializer import PatientSerializer
2 | from .AdmissionSerializer import AdmissionSerializer
3 | from .CVPatientSerializer import CVPatientSerializer
4 | from .ClinicalVariableSerializer import ClinicalVariableSerializer
5 | from .CVGroupSerializer import CVGroupSerializer
--------------------------------------------------------------------------------
/UI/src/js/components/accountManager/Register.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react';
2 |
3 | class Register extends Component {
4 | render() {
5 | return (
6 |
7 | Register and login (BUILDING)
8 |
9 | )
10 | }
11 | }
12 |
13 | export default Register;
--------------------------------------------------------------------------------
/UI/src/js/components/accountManager/ForgotPass.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react';
2 |
3 | class ForgotPassword extends Component {
4 | render() {
5 | return (
6 |
7 | Forgot password (BUILDING)
8 |
9 | )
10 | }
11 | }
12 |
13 | export default ForgotPassword;
--------------------------------------------------------------------------------
/Backend/accounts/admin.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.contrib import admin
5 | from models import Profile, UserRecovery
6 |
7 | @admin.register(Profile)
8 | class ProfileAdmin(admin.ModelAdmin):
9 | pass
10 |
11 | @admin.register(UserRecovery)
12 | class RecoveryAdmin(admin.ModelAdmin):
13 | pass
14 |
--------------------------------------------------------------------------------
/Backend/history/admin.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.contrib import admin
5 |
6 |
7 | from models import History, HistoryRelated
8 |
9 | @admin.register(History)
10 | class HistoryAdmin(admin.ModelAdmin):
11 | pass
12 |
13 | @admin.register(HistoryRelated)
14 | class HistoryRelatedAdmin(admin.ModelAdmin):
15 | pass
16 |
--------------------------------------------------------------------------------
/UI/src/css/imports.css:
--------------------------------------------------------------------------------
1 | /*
2 | * Other CSS project files
3 | */
4 | @import url("app.css");
5 | @import url("LoginComponent.css");
6 | @import url("Table.css");
7 | @import url("Texts.css");
8 | @import url("Select.css");
9 | @import url("externalImportsConfigs.css");
10 |
11 | /*
12 | * External libs
13 | */
14 | @import url("../externalImports/mfglabs-iconset/css/mfglabs_iconset.css");
15 |
--------------------------------------------------------------------------------
/UI/src/js/GlobalSettings.js:
--------------------------------------------------------------------------------
1 |
2 | const getPatientTableRows = function(extraSize=0) {
3 | let headerSize = 65;
4 | let footerSize = 70 ;
5 | let tableHeaderSize = 42 + 29 + 39 + 47;
6 | let rowSize = 35;
7 |
8 | return Math.floor((window.innerHeight - headerSize - footerSize - tableHeaderSize - extraSize)/rowSize);
9 | };
10 |
11 |
12 | export default {getPatientTableRows};
--------------------------------------------------------------------------------
/Backend/accounts/urls.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.conf.urls import include, url
5 | from rest_framework import routers
6 |
7 | from api.views import UserViewSet
8 |
9 | router = routers.DefaultRouter()
10 | router.register(r'', UserViewSet, base_name='userview')
11 |
12 | urlpatterns = [
13 | url(r'^', include(router.urls))
14 | ]
15 |
--------------------------------------------------------------------------------
/Backend/protocol_element/api/serializers/__init__.py:
--------------------------------------------------------------------------------
1 | from .PolymorphicSerializer import PolymorphicSerializer
2 | from .PENextElementsSerializer import PENextElementsSerializer
3 | from .PEActionSerializer import PEActionSerializer
4 | from .PEInquirySerializer import PEInquirySerializer
5 | from .PEDecisionSerializer import PEDecisionSerializer
6 | from .ProtocolElementSerializer import ProtocolElementSerializer
--------------------------------------------------------------------------------
/UI/src/js/components/errorPages/http500.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react';
2 |
3 | export default class httpError extends Component {
4 | render() {
5 | return (
6 |
7 |
500 - Service Error
8 |
Oops, we appear to be having problems. Please contact the administrator.
9 |
10 | )
11 | }
12 | }
--------------------------------------------------------------------------------
/Backend/patients/api/views/ClinicalVariableViewSet.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from rest_framework import viewsets, filters
5 |
6 | from patients.api.serializers import ClinicalVariableSerializer
7 | from patients.models import ClinicalVariable
8 |
9 | class ClinicalVariableViewSet(viewsets.ModelViewSet):
10 | queryset = ClinicalVariable.all()
11 | serializer_class = ClinicalVariableSerializer
--------------------------------------------------------------------------------
/UI/src/js/components/errorPages/http404.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react';
2 |
3 | export default class httpError extends Component {
4 | render() {
5 | return (
6 |
7 |
404 - Page not found
8 |
The page does not seem exist, if you think this is a mistake, please contact the administrator.
9 |
10 | )
11 | }
12 | }
--------------------------------------------------------------------------------
/Backend/accounts/api/serializers/ProfileSerializer.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from rest_framework import serializers
5 | from rest_framework import permissions
6 |
7 | from accounts.models import Profile
8 |
9 | class ProfileSerializer(serializers.ModelSerializer):
10 | class Meta:
11 | permission_classes = [permissions.IsAuthenticated]
12 | model = Profile
13 | exclude = ['id']
--------------------------------------------------------------------------------
/UI/src/js/components/patient/PatientStatus.js:
--------------------------------------------------------------------------------
1 | const status = {
2 | ADMITTED:1,
3 | DISCHARGED: 2
4 | };
5 |
6 | status.get = function(value){
7 | return Object.keys(status).find(key => status[key] === value);
8 | };
9 |
10 | status.toString = function(value){
11 | switch (value)
12 | {
13 | case 1: return "Admitted";
14 | case 2: return "";
15 | default: return "";
16 | }
17 | };
18 |
19 | export default status;
--------------------------------------------------------------------------------
/Backend/protocol/api/serializers/ScheduleSerializer.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from rest_framework import serializers
5 | from rest_framework import permissions
6 |
7 | from protocol.models import Schedule
8 |
9 |
10 | class ScheduleSerializer(serializers.ModelSerializer):
11 | class Meta:
12 | permission_classes = [permissions.IsAuthenticated]
13 | model = Schedule
14 | fields = ("id", "title")
--------------------------------------------------------------------------------
/Backend/utils/models/Multilingual.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.db import models
5 | from utils.models import Language
6 |
7 | class Multilingual(models.Model):
8 | key = models.CharField(max_length=150)
9 | content = models.CharField(max_length=500)
10 | language = models.ForeignKey(Language)
11 |
12 | def __unicode__(self):
13 | return u"%s - %s" % (self.key, self.language)
--------------------------------------------------------------------------------
/UI/src/js/components/protocol/ProtocolType.js:
--------------------------------------------------------------------------------
1 | const type = {
2 | SIMPLE:1,
3 | COMPLEX: 2
4 | };
5 |
6 | type.get = function(value){
7 | return Object.keys(status).find(key => status[key] === value);
8 | };
9 |
10 | type.toString = function(value){
11 | switch (value)
12 | {
13 | case 1: return "Simple execution";
14 | case 2: return "Form execution";
15 | default: return "";
16 | }
17 | };
18 |
19 | export default type;
--------------------------------------------------------------------------------
/Backend/genericcdss/wsgi.py:
--------------------------------------------------------------------------------
1 | """
2 | WSGI config for genericcdss project.
3 |
4 | It exposes the WSGI callable as a module-level variable named ``application``.
5 |
6 | For more information on this file, see
7 | https://docs.djangoproject.com/en/1.11/howto/deployment/wsgi/
8 | """
9 |
10 | import os
11 |
12 | from django.core.wsgi import get_wsgi_application
13 |
14 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "genericcdss.settings")
15 |
16 | application = get_wsgi_application()
17 |
--------------------------------------------------------------------------------
/Backend/protocol_element/api/serializers/PENextElementsSerializer.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from rest_framework import serializers
5 | from rest_framework import permissions
6 |
7 | from protocol_element.models import PENextElements
8 |
9 | class PENextElementsSerializer(serializers.ModelSerializer):
10 | class Meta:
11 | permission_classes = [permissions.IsAuthenticated]
12 | model = PENextElements
13 | exclude = ['id']
--------------------------------------------------------------------------------
/Backend/patients/api/serializers/CVPatientSerializer.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from rest_framework import serializers
5 | from rest_framework import permissions
6 |
7 | from patients.models import CVPatient
8 |
9 | class CVPatientSerializer(serializers.ModelSerializer):
10 | class Meta:
11 | permission_classes = [permissions.IsAuthenticated]
12 | model = CVPatient
13 | fields = '__all__'
14 | read_only_fields = ('id',)
15 |
16 |
--------------------------------------------------------------------------------
/Backend/accounts/api/serializers/UserProfileSerializer.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from rest_framework import serializers
5 | from rest_framework import permissions
6 |
7 | from accounts.api.serializers import UserSerializer
8 |
9 | from accounts.models import Profile
10 |
11 | class UserProfileSerializer(serializers.ModelSerializer):
12 | user = UserSerializer()
13 | class Meta:
14 | permission_classes = [permissions.IsAuthenticated]
15 | model = Profile
16 | exclude = ['id']
--------------------------------------------------------------------------------
/Backend/utils/urls.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.conf.urls import include, url
5 |
6 | from utils.api.views import ConstanceView, FlatPagesView
7 |
8 | urlpatterns = [
9 | url(r'^settings', ConstanceView.as_view({'get':'getSettings'}), name='settingsview'),
10 | url(r'^about', FlatPagesView.as_view({'get':'getAbout'}), name='aboutview'),
11 | url(r'^help', FlatPagesView.as_view({'get':'getHelp'}), name='helpview'),
12 | url(r'^home', FlatPagesView.as_view({'get':'getHome'}), name='homeview'),
13 | ]
--------------------------------------------------------------------------------
/Backend/protocol/api/views/ScheduleViewSet.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from rest_framework import viewsets, filters
5 |
6 | from rest_framework.filters import OrderingFilter
7 | from django_filters.rest_framework import DjangoFilterBackend
8 |
9 | from protocol.api.serializers import ScheduleSerializer
10 | from protocol.models import Schedule
11 |
12 | from history.models import History
13 |
14 | class ScheduleViewSet(viewsets.ModelViewSet):
15 | queryset = Schedule.objects.all()
16 | serializer_class = ScheduleSerializer
17 |
--------------------------------------------------------------------------------
/Backend/patients/models/CVOption.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.db import models
5 |
6 | from patients.models import ClinicalVariable
7 |
8 | class CVOption(models.Model):
9 | variable = models.ForeignKey(ClinicalVariable)
10 | option = models.CharField(max_length=30)
11 |
12 | @staticmethod
13 | def getOptions(variable=None):
14 | tmpAll = []
15 | for optionObj in CVOption.objects.filter(variable=variable):
16 | tmpAll += [optionObj.option]
17 | return tmpAll
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM python:2.7
2 | MAINTAINER Joao Almeida
3 |
4 | ADD ./Backend /GenericCDSS/Backend
5 | ADD ./UI /GenericCDSS/UI
6 | ADD ./Makefile /GenericCDSS/Makefile
7 | ADD ./config /GenericCDSS/config
8 |
9 | RUN apt-get update && \
10 | apt-get install -y -q jq vim curl nginx uwsgi-plugin-python
11 |
12 | RUN curl -sL https://deb.nodesource.com/setup_8.x | bash -
13 |
14 | RUN apt-get install -y nodejs
15 |
16 | WORKDIR /GenericCDSS
17 |
18 | RUN cd UI/ && npm install
19 |
20 | RUN mkdir -p /var/log/gunicorn
21 |
22 | RUN pip install -r ./config/requirements.pip --no-cache-dir
23 |
--------------------------------------------------------------------------------
/UI/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import { BrowserRouter } from 'react-router-dom';
4 |
5 | import App from './js/App.js';
6 | import './css/imports.css';
7 |
8 | import 'font-awesome/css/font-awesome.min.css';
9 | import 'react-select/dist/react-select.css';
10 | import 'semantic-ui-css/semantic.min.css';
11 | import 'rc-tabs/assets/index.css';
12 | import 'bootstrap/dist/css/bootstrap.min.css';
13 | import 'bootstrap/dist/js/bootstrap.bundle.js';
14 |
15 | ReactDOM.render(
16 |
17 |
18 | ,
19 | document.getElementById('root')
20 | );
21 |
--------------------------------------------------------------------------------
/UI/src/js/components/errorPages/http0.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react';
2 |
3 | export default class httpError extends Component {
4 | render() {
5 | return (
6 |
7 |
Failed connection
8 |
The connection does not seem to be working.
9 |
It is possible there is no Internet connection, or the web page is currently offline.
10 |
If you believe this page being shown is caused by a system error, please contact the
11 | administrator.
12 |
13 | )
14 | }
15 | }
--------------------------------------------------------------------------------
/UI/src/js/components/reusable/MyLink.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react';
2 | import {Link} from "react-router-dom";
3 |
4 | class MyLink extends Component {
5 | render() {
6 | return (
7 |
8 |
9 | {
10 | this.props.bold ?
11 | {this.props.label}
12 | :
13 | {this.props.label}
14 | }
15 | );
16 | }
17 | }
18 |
19 | export default MyLink;
--------------------------------------------------------------------------------
/Backend/history/api/serializers/GenericObjectField.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from rest_framework import serializers
5 |
6 | class GenericObjectField(serializers.RelatedField):
7 | '''
8 | A custom field to use for the `object` generic relationship.
9 | '''
10 |
11 | def to_representation(self, value):
12 | '''
13 | Serialize objects to a simple textual representation.
14 | '''
15 | try:
16 | return value.rpr()
17 | except:
18 | try:
19 | return str(value.hash)
20 | except:
21 | return "DUMMY"
22 |
--------------------------------------------------------------------------------
/Backend/protocol/models/Schedule.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.db import models
5 |
6 | from protocol.models import Time
7 |
8 | class Schedule(models.Model):
9 | title = models.CharField(max_length=150, unique=True)
10 | time = models.ManyToManyField(Time)
11 | removed = models.BooleanField(default=False)
12 |
13 | def __unicode__(self):
14 | return self.title
15 |
16 | def getAllScheduleTimes(self):
17 | allPossibleTimes = []
18 | for time in self.time.all():
19 | allPossibleTimes += [(time, self.title)]
20 | return allPossibleTimes
--------------------------------------------------------------------------------
/UI/src/js/components/globalComponents/Language.js:
--------------------------------------------------------------------------------
1 | //import React, {Component} from 'react';
2 | //import API from '../../API.js';
3 |
4 |
5 | let Language = {};
6 | /* DOING
7 | API.GET("language")
8 | .then(res => {
9 | Language = res.data["language"];
10 | });
11 |
12 | /*
13 | Language = {
14 | // English
15 | "en": {
16 | 'welcome': 'Welcome',
17 | 'description': 'This app demonstrates how to easily use a multilanguage mechanism with Office UI Fabric',
18 | }
19 | ,
20 | // Deutsch
21 | "de": {
22 | 'welcome': 'Willkommen',
23 | 'description': 'Diese App demonstriert, wie man leicht einen mehrsprachigen Mechanismus mit Office UI Fabric verwendet',
24 | }
25 | };
26 | */
27 |
28 | export default Language;
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .gitignore
2 | .idea/*
3 | UI/node_modules/*
4 | env/*
5 | *.pyc
6 |
7 | #Put this files in somewhere private
8 | !docker-compose.yml
9 |
10 | #Ignore migrations
11 | Backend/accounts/migrations/*
12 | Backend/history/migrations/*
13 | Backend/patients/migrations/*
14 | Backend/protocol/migrations/*
15 | Backend/protocol_element/migrations/*
16 | Backend/utils/migrations/*
17 |
18 | #Don't ignore migrations the __init__.py
19 | !Backend/accounts/migrations/__init__.py
20 | !Backend/history/migrations/__init__.py
21 | !Backend/patients/migrations/__init__.py
22 | !Backend/protocol/migrations/__init__.py
23 | !Backend/protocol_element/migrations/__init__.py
24 | !Backend/utils/migrations/__init__.py
25 |
26 | UI/package-lock.json
27 |
--------------------------------------------------------------------------------
/UI/src/css/Table.css:
--------------------------------------------------------------------------------
1 | .card-heading{
2 | height: 40px;
3 | justify-content: center;
4 | align-items: center;
5 | position:relative;
6 | }
7 |
8 | .card-title {
9 | margin-top: 0;
10 | margin-bottom: 0;
11 | font-size: 16px;
12 | color: inherit;
13 | }
14 |
15 | .card-content{
16 | cursor: pointer;
17 | margin: 0;
18 | }
19 |
20 | .h3-table {
21 | display: inline-block;
22 | position: absolute;
23 | left:0;
24 | right:0;
25 | font-weight: bold;
26 | font-size: 18px;
27 | }
28 |
29 | .h5-table{
30 | font-weight: bold;
31 | font-size: 16px;
32 | }
33 |
34 | .table-button{
35 | margin-left: .3em;
36 | position: absolute;
37 | right: 10px;
38 | top: 8px;
39 | }
40 |
--------------------------------------------------------------------------------
/Backend/protocol/urls.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.conf.urls import include, url
5 | from rest_framework import routers
6 |
7 | from api.views import ProtocolViewSet, ScheduleViewSet, AssignedProtocolViewSet, ExecutedProtocolViewSet
8 |
9 | router = routers.DefaultRouter()
10 | router.register(r'protocol', ProtocolViewSet, base_name='protocolview')
11 | router.register(r'schedule', ScheduleViewSet, base_name='scheduleview')
12 | router.register(r'assignedprotocols', AssignedProtocolViewSet, base_name='assignedprotocolsview')
13 | router.register(r'executedprotocols', ExecutedProtocolViewSet, base_name='executedprotocolsview')
14 |
15 | urlpatterns = [
16 | url(r'^', include(router.urls))
17 | ]
18 |
--------------------------------------------------------------------------------
/Backend/patients/urls.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.conf.urls import include, url
5 | from rest_framework import routers
6 |
7 | from api.views import PatientViewSet, PatientCVsViewSet, AdmissionViewSet, ClinicalVariableViewSet
8 |
9 | router = routers.DefaultRouter()
10 | router.register(r'patient', PatientViewSet, base_name='patientview')
11 | router.register(r'admission', AdmissionViewSet, base_name='admissionview')
12 | router.register(r'patientclinicalvariables', PatientCVsViewSet, base_name='patientclinicalvariablesview')
13 | router.register(r'clinicalvariables', ClinicalVariableViewSet, base_name='clinicalvariablesview')
14 |
15 | urlpatterns = [
16 | url(r'^', include(router.urls))
17 | ]
18 |
--------------------------------------------------------------------------------
/config/requirements.pip:
--------------------------------------------------------------------------------
1 | Django==1.11.10
2 | certifi==2018.1.18
3 | chardet==3.0.4
4 | coreapi==2.3.3
5 | coreschema==0.0.4
6 | coverage==4.5.1
7 | django-constance==2.1.0
8 | django-cors-middleware==1.3.1
9 | django-filter==1.1.0
10 | django-jet==1.0.7
11 | django-model-utils==3.1.2
12 | django-oauth-toolkit==1.0.0
13 | django-picklefield==1.0.0
14 | django-rest-swagger==2.1.2
15 | djangorestframework==3.7.7
16 | enum34==1.1.6
17 | gunicorn==19.6.0
18 | hashids==1.2.0
19 | idna==2.6
20 | itypes==1.1.0
21 | Jinja2==2.10
22 | MarkupSafe==1.0
23 | oauthlib==2.0.6
24 | openapi-codec==1.3.2
25 | psycopg2==2.7.4
26 | psycopg2-binary==2.7.4
27 | python-dateutil==2.7.3
28 | pytz==2018.3
29 | requests==2.18.4
30 | simplejson==3.13.2
31 | six==1.11.0
32 | uritemplate==3.0.0
33 | urllib3==1.22
34 |
--------------------------------------------------------------------------------
/Backend/protocol_element/models/PENextElements.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.db import models
5 |
6 | from protocol_element.models import ProtocolElement
7 |
8 | class PENextElements(models.Model):
9 | option = models.CharField(max_length=50, null=True)
10 | nextElement = models.ForeignKey(ProtocolElement)
11 |
12 | def getNextElementId(self):
13 | return self.nextElement.internalId
14 |
15 | @staticmethod
16 | def new(nextElementId, protocol, option=None):
17 | pe = ProtocolElement.get(internalId=nextElementId, protocol=protocol)
18 | nextElement = PENextElements.objects.create(option=option, nextElement=pe)
19 | nextElement.save()
20 | return nextElement
--------------------------------------------------------------------------------
/Backend/utils/admin.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.contrib import admin
5 | from django.utils.html import format_html
6 | from django.core.urlresolvers import reverse
7 |
8 | from models import Language, Multilingual
9 |
10 | # Register your models here.
11 | @admin.register(Language)
12 | class LanguageAdmin(admin.ModelAdmin):
13 | list_display = ("language", "ckeck_translations")
14 |
15 | def ckeck_translations(self, obj):
16 | return format_html(
17 | 'Check ',
18 | None#reverse('admin:', args=[obj.pk])
19 | )
20 |
21 | @admin.register(Multilingual)
22 | class MultilingualAdmin(admin.ModelAdmin):
23 | list_display = ("key", "content", "language")
24 |
--------------------------------------------------------------------------------
/UI/src/js/components/patient/ShowPatient.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react';
2 | import PatientInfo from './PatientInfo.js';
3 | import PatientComplementInfo from './PatientComplementInfo.js';
4 |
5 | class ShowPatient extends Component {
6 | render() {
7 | let patientID = this.props.match.params.object;
8 |
9 | return (
10 |
11 |
Patient information
12 |
13 | Additional Information
14 |
15 |
16 | );
17 | }
18 | }
19 |
20 | export default ShowPatient;
--------------------------------------------------------------------------------
/UI/src/js/components/dynamicPages/Help.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react';
2 | import API from '../../API.js';
3 | import ReactHtmlParser from 'react-html-parser';
4 |
5 | class Help extends Component {
6 | constructor(props) {
7 | super(props);
8 | this.state = {
9 | help: undefined
10 | };
11 | }
12 |
13 | componentDidMount() {
14 | API.GET("help")
15 | .then(res => {
16 | if(this.refs.help)
17 | this.setState({help:res.data["help"]});
18 | })
19 | }
20 |
21 | render() {
22 | return (
23 |
24 | {ReactHtmlParser(this.state.help)}
25 |
26 | );
27 | }
28 | }
29 |
30 | export default Help;
--------------------------------------------------------------------------------
/Backend/patients/api/serializers/ClinicalVariableSerializer.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from rest_framework import serializers
5 | from rest_framework import permissions
6 |
7 | from patients.models import ClinicalVariable, CVOption
8 |
9 | class ClinicalVariableSerializer(serializers.ModelSerializer):
10 | options = serializers.SerializerMethodField(required=False)
11 |
12 | class Meta:
13 | permission_classes = [permissions.IsAuthenticated]
14 | model = ClinicalVariable
15 | fields = ('variable', 'index_representation', 'type', 'options')
16 | read_only_fields = ('id',)
17 |
18 | def get_options(self, obj):
19 | if obj.type == ClinicalVariable.CONDITIONAL:
20 | return CVOption.getOptions(variable=obj)
21 | return []
--------------------------------------------------------------------------------
/Backend/patients/models/CVGroup.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.db import models
5 |
6 | class CVGroup(models.Model):
7 | title = models.CharField(max_length=30)
8 | description = models.CharField(max_length=100, blank=True)
9 | index_representation = models.IntegerField()
10 | display = models.BooleanField(default=True)
11 |
12 | def __unicode__(self):
13 | return u"CV group - %s" % self.title
14 |
15 | @staticmethod
16 | def all(all=False):
17 | '''
18 | Returns all clinical variable group instances
19 | '''
20 | tmpAll = CVGroup.objects.all()
21 |
22 | if all == False:
23 | tmpAll = tmpAll.filter(display=True)
24 | return tmpAll
--------------------------------------------------------------------------------
/Backend/protocol/api/serializers/AssignedProtocolSerializer.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from rest_framework import serializers
5 | from rest_framework import permissions
6 |
7 | from protocol.models import AssignedProtocol
8 |
9 |
10 | class AssignedProtocolSerializer(serializers.ModelSerializer):
11 | pass
12 | # title = serializers.SerializerMethodField(required=False)
13 | # schedule = serializers.SerializerMethodField(required=False)
14 | #
15 | # class Meta:
16 | # permission_classes = [permissions.IsAuthenticated]
17 | # model = AssignedProtocol
18 | # fields = '__all__'
19 | #
20 | # def get_title(self, obj):
21 | # return obj.protocol.title
22 | #
23 | # def get_schedule(self, obj):
24 | # return obj.schedule.time.strftime("%H:%M")
--------------------------------------------------------------------------------
/Backend/protocol/api/views/AssignedProtocolViewSet.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from rest_framework import viewsets, filters
5 | from rest_framework.decorators import list_route
6 | from rest_framework import generics
7 |
8 | from rest_framework.filters import OrderingFilter
9 | from django_filters.rest_framework import DjangoFilterBackend
10 |
11 | from protocol.api.serializers import ExecutedProtocolSerializer
12 | from protocol.models import ExecutedProtocol
13 |
14 | from patients.models import Patient
15 |
16 | from history.models import History
17 |
18 | class AssignedProtocolViewSet(viewsets.ModelViewSet):
19 | queryset = ExecutedProtocol.all(state=ExecutedProtocol.ASSIGNED)
20 | serializer_class = ExecutedProtocolSerializer
21 |
22 | filter_backends = [DjangoFilterBackend, OrderingFilter]
23 | filter_fields = ["patient"]
24 |
--------------------------------------------------------------------------------
/Backend/protocol/api/views/ExecutedProtocolViewSet.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from rest_framework import viewsets, filters
5 | from rest_framework.decorators import list_route
6 | from rest_framework import generics
7 |
8 | from rest_framework.filters import OrderingFilter
9 | from django_filters.rest_framework import DjangoFilterBackend
10 |
11 | from protocol.api.serializers import ExecutedProtocolSerializer
12 | from protocol.models import ExecutedProtocol
13 |
14 | from patients.models import Patient
15 |
16 | from history.models import History
17 |
18 | class ExecutedProtocolViewSet(viewsets.ModelViewSet):
19 | queryset = ExecutedProtocol.all(state=ExecutedProtocol.EXECUTED)
20 | serializer_class = ExecutedProtocolSerializer
21 |
22 | filter_backends = [DjangoFilterBackend, OrderingFilter]
23 | filter_fields = ["patient"]
24 |
--------------------------------------------------------------------------------
/Backend/manage.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | import os
3 | import sys
4 |
5 | if __name__ == "__main__":
6 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "genericcdss.settings")
7 | try:
8 | from django.core.management import execute_from_command_line
9 | except ImportError:
10 | # The above import may fail for some other reason. Ensure that the
11 | # issue is really that Django is missing to avoid masking other
12 | # exceptions on Python 2.
13 | try:
14 | import django
15 | except ImportError:
16 | raise ImportError(
17 | "Couldn't import Django. Are you sure it's installed and "
18 | "available on your PYTHONPATH environment variable? Did you "
19 | "forget to activate a virtual environment?"
20 | )
21 | raise
22 | execute_from_command_line(sys.argv)
23 |
--------------------------------------------------------------------------------
/Backend/patients/api/serializers/CVGroupSerializer.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from rest_framework import serializers
5 | from rest_framework import permissions
6 |
7 | from patients.models import CVGroup, ClinicalVariable
8 |
9 | from patients.api.serializers import ClinicalVariableSerializer
10 |
11 | class CVGroupSerializer(serializers.ModelSerializer):
12 | clinical_variables = serializers.SerializerMethodField(required=False)
13 | class Meta:
14 | permission_classes = [permissions.IsAuthenticated]
15 | model = CVGroup
16 | fields = ('title', 'index_representation', 'clinical_variables')
17 | read_only_fields = ('id',)
18 |
19 | def get_clinical_variables(self, obj):
20 | clinicalVariables = ClinicalVariable.all(group=obj)
21 | return ClinicalVariableSerializer(clinicalVariables, many=True).data
--------------------------------------------------------------------------------
/Backend/patients/api/serializers/PatientSerializer.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from rest_framework import serializers
5 | from rest_framework import permissions
6 |
7 | from patients.models import Patient
8 |
9 |
10 | class PatientSerializer(serializers.ModelSerializer):
11 | fullname = serializers.SerializerMethodField(required=False)
12 | fullgender = serializers.SerializerMethodField(required=False)
13 |
14 | class Meta:
15 | permission_classes = [permissions.IsAuthenticated]
16 | model = Patient
17 | fields = '__all__'
18 | read_only_fields = ('id', 'fullname', 'fullgender')
19 |
20 | def get_fullname(self, obj):
21 | full_name = obj.get_full_name()
22 |
23 | if full_name == "":
24 | return obj.email
25 | return full_name
26 |
27 | def get_fullgender(self, obj):
28 | return obj.get_full_gender()
--------------------------------------------------------------------------------
/UI/src/js/components/globalComponents/Footer.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react';
2 | import '../../../css/app.css';
3 | import API from '../../API.js';
4 | import ReactHtmlParser from 'react-html-parser';
5 |
6 | class Footer extends Component {
7 | constructor(props) {
8 | super(props);
9 | this.state = {
10 | footer: undefined
11 | };
12 | }
13 |
14 | componentDidMount() {
15 | API.GET("settings")
16 | .then(res => {
17 | if(this.refs.footer)
18 | this.setState({footer:res.data["footer"]});
19 | })
20 | }
21 |
22 | render() {
23 | return (
24 |
29 | );
30 | }
31 | }
32 |
33 | export default Footer;
--------------------------------------------------------------------------------
/config/nginx/genericcdss.conf:
--------------------------------------------------------------------------------
1 | upstream web {
2 | ip_hash;
3 | server web:8000;
4 | }
5 |
6 | server {
7 | error_log /var/log/nginx/error.log error;
8 | root /frontend;
9 | listen 8000;
10 | server_name localhost;
11 |
12 | location = /favicon.ico {
13 | access_log off;
14 | log_not_found off;
15 | }
16 |
17 | location /{BASE_URL}/static2 {
18 | alias /static;
19 | }
20 |
21 | location /{BASE_URL} {
22 | root /frontend;
23 | index index.html;
24 | try_files $uri $uri/ /index.html;
25 | }
26 |
27 | location /{BASE_URL}/static {
28 | alias /frontend/static;
29 | }
30 |
31 | location /{BASE_URL}/images {
32 | alias /frontend/images;
33 | }
34 |
35 | location /{BASE_URL}/api {
36 | proxy_pass http://web/{BASE_URL}/api;
37 | }
38 |
39 | location /{BASE_URL}/admin {
40 | proxy_pass http://web/{BASE_URL}/admin;
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/Backend/protocol/api/serializers/ProtocolSerializer.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from rest_framework import serializers
5 | from rest_framework import permissions
6 |
7 | from protocol.models import Protocol
8 | from protocol.api.serializers import ScheduleSerializer
9 |
10 | from protocol_element.api.serializers import ProtocolElementSerializer
11 | from protocol_element.models import ProtocolElement
12 |
13 | class ProtocolSerializer(serializers.ModelSerializer):
14 | elements = serializers.SerializerMethodField(required=False)
15 | schedules = ScheduleSerializer(many=True)
16 |
17 | class Meta:
18 | permission_classes = [permissions.IsAuthenticated]
19 | model = Protocol
20 | fields = '__all__'
21 |
22 | def get_elements(self, obj):
23 | elements = ProtocolElement.all(protocol=obj)
24 | return ProtocolElementSerializer(elements, many=True).data
25 |
--------------------------------------------------------------------------------
/Backend/protocol_element/api/serializers/PEActionSerializer.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from rest_framework import serializers
5 | from rest_framework import permissions
6 |
7 | from protocol_element.models import PEAction
8 | from protocol_element.api.serializers import PENextElementsSerializer
9 |
10 | class PEActionSerializer(serializers.ModelSerializer):
11 | nextElement = serializers.SerializerMethodField(required=False)
12 | type = serializers.SerializerMethodField(required=False)
13 |
14 | class Meta:
15 | permission_classes = [permissions.IsAuthenticated]
16 | model = PEAction
17 | #exclude = ['id']
18 | fields = '__all__'
19 |
20 | def get_type(self, obj):
21 | return "Action"
22 |
23 | def get_nextElement(self, obj):
24 | if obj.nextElement:
25 | return str(obj.nextElement.nextElement.internalId)
26 | return ""
--------------------------------------------------------------------------------
/Backend/protocol/admin.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.contrib import admin
5 |
6 | from protocol.models import Protocol, Schedule, ExecutedProtocol, Time
7 |
8 | # Register your models here.
9 |
10 | @admin.register(Protocol)
11 | class ProtocolAdmin(admin.ModelAdmin):
12 | list_display = ("title", "description", "created_date", "removed")
13 | #
14 | # @admin.register(AssignedProtocol)
15 | # class AssignedProtocolAdmin(admin.ModelAdmin):
16 | # list_display = ("protocol", "patient", "schedule", "start_date", "end_date", "active")
17 |
18 | @admin.register(ExecutedProtocol)
19 | class ExecutedProtocolAdmin(admin.ModelAdmin):
20 | list_display = ("protocol", "patient", "execution_time", "physician")
21 |
22 | @admin.register(Schedule)
23 | class ScheduleAdmin(admin.ModelAdmin):
24 | list_display = ("title", "removed")
25 |
26 | @admin.register(Time)
27 | class TimeeAdmin(admin.ModelAdmin):
28 | list_display = ("time",)
29 |
--------------------------------------------------------------------------------
/Backend/history/models/HistoryRelated.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.db import models
5 | from django.contrib.contenttypes.fields import GenericForeignKey
6 | from django.contrib.contenttypes.models import ContentType
7 |
8 | class HistoryRelated(models.Model):
9 | '''
10 | Describes an indirect relationship with the object, which makes the history relevant, not directly, but in scope.
11 | An example of related history, is for example, the history about a protocol task, being related with the history
12 | from a Protocol.
13 | It may make sense to see related history when seeing the process, but not the other way around.
14 |
15 | Attributes:
16 | :object (Model): Any model that inherits from :class:`django.models.Model`
17 | '''
18 |
19 | object_type = models.ForeignKey(ContentType)
20 | object_id = models.PositiveIntegerField()
21 | object = GenericForeignKey('object_type', 'object_id')
--------------------------------------------------------------------------------
/Backend/protocol_element/api/serializers/ProtocolElementSerializer.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from enum import Enum
5 |
6 | from rest_framework import serializers
7 | from rest_framework import permissions
8 |
9 | from protocol_element.models import ProtocolElement, PEInquiry, PEAction, PEDecision
10 |
11 | from protocol_element.api.serializers import PolymorphicSerializer, PEInquirySerializer, PEActionSerializer, PEDecisionSerializer
12 |
13 | class ProtocolElementSerializer(PolymorphicSerializer):
14 | class Meta:
15 | permission_classes = [permissions.IsAuthenticated]
16 | model = ProtocolElement
17 | #exclude = ['id']
18 | fields = '__all__'
19 |
20 | def get_serializer_map(self):
21 | return {
22 | 'PEInquiry': PEInquirySerializer,
23 | 'PEAction': PEActionSerializer,
24 | 'PEDecision': PEDecisionSerializer,
25 | }
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/Backend/protocol/management/commands/cleanAllProtocols.py:
--------------------------------------------------------------------------------
1 | # coding=utf-8
2 | from django.core.management.base import BaseCommand
3 | from protocol.models import Protocol, ExecutedProtocol, Schedule, Time
4 | from protocol_element.models import ProtocolElement, PEAction, PEDecision, PEInquiry, PENextElements
5 | from patients.models import CVGroup, ClinicalVariable, Patient, CVPatient, Admission
6 |
7 | class Command(BaseCommand):
8 | help = 'This command will create the hypoglycemia protocol in the database'
9 |
10 | def handle(self, *args, **options):
11 | self.stdout.write("\nClean all protocols in the system\n\n")
12 | for protocol in Protocol.objects.all():
13 | peList = ProtocolElement.objects.filter(protocol=protocol)
14 | for pe in peList:
15 | PENextElements.objects.filter(nextElement=pe).delete()
16 | ProtocolElement.objects.filter(protocol=protocol).delete()
17 | protocol.delete()
18 | Schedule.objects.all().delete()
19 | Time.objects.all().delete()
--------------------------------------------------------------------------------
/Backend/accounts/tests/testProfileSerializer.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.test import TestCase
5 | from django.contrib.auth.models import User
6 |
7 | from accounts.api.serializers import ProfileSerializer
8 | from accounts.models import Profile
9 |
10 | class ProfileTestCase(TestCase):
11 | def setUp(self):
12 | self.user = User.objects.create_user(username='userSerializer',
13 | email='userSerializer@ua.pt',
14 | password='12345',
15 | first_name="user",
16 | last_name="serializer")
17 | self.profile = Profile(user=self.user, role=Profile.ADMINISTRATOR)
18 |
19 |
20 | def test_serializer_composition(self):
21 | result = ProfileSerializer(self.profile)
22 | desiredFormat = {
23 | u'role': Profile.ADMINISTRATOR
24 | }
25 |
26 | self.assertEqual(result.data, desiredFormat)
--------------------------------------------------------------------------------
/UI/src/js/reflux/ScheduleReflux.js:
--------------------------------------------------------------------------------
1 | import Reflux from 'reflux';
2 | import API from '../API.js';
3 |
4 | const ScheduleActions = Reflux.createActions([
5 | 'load'
6 | ]);
7 |
8 | class ScheduleStore extends Reflux.Store {
9 | constructor(props) {
10 | super(props);
11 | this.listenables = ScheduleActions;
12 | this.state = {
13 | schedulesOptions:[],
14 | loading: false
15 | };
16 | }
17 |
18 | onLoad() {
19 | this.setState({loading: true});
20 | API.GET("schedule")
21 | .then(res => {
22 | let scheduleMap = res.data["results"].map(entry => {
23 | return {
24 | value: entry.id,
25 | label: entry.title
26 | }
27 | });
28 |
29 | this.setState({
30 | schedulesOptions: scheduleMap,
31 | loading: false
32 | });
33 | })
34 | }
35 |
36 | }
37 |
38 | export {ScheduleStore, ScheduleActions};
39 |
--------------------------------------------------------------------------------
/Backend/accounts/models/Profile.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.db import models
5 | from django.contrib.auth.models import User
6 |
7 | class Profile(models.Model):
8 | NURSE = 1
9 | PHYSICIAN = 2
10 | ADMINISTRATOR = 3
11 |
12 | ROLES = (
13 | (NURSE, 'This user is a nurse'),
14 | (PHYSICIAN, 'This user is a physician'),
15 | (ADMINISTRATOR, 'This user is a administrator'),
16 | )
17 |
18 | user = models.OneToOneField(User)
19 | role = models.PositiveSmallIntegerField(choices=ROLES, default=NURSE)
20 |
21 | def __unicode__(self):
22 | return u"User profile for %s" % self.user
23 |
24 | def getFullName(self):
25 | if self.user.get_full_name() != "":
26 | return self.user.get_full_name()
27 | return self.user.username
28 |
29 | @staticmethod
30 | def getAllPhysicians():
31 | '''
32 | Returns all the physicians
33 | '''
34 | return Profile.objects.all().filter(role=Profile.PHYSICIAN)
35 |
--------------------------------------------------------------------------------
/UI/src/js/reflux/ClinicalVariablesReflux.js:
--------------------------------------------------------------------------------
1 | import Reflux from 'reflux';
2 | import API from '../API.js';
3 |
4 | const ClinicalVariablesActions = Reflux.createActions(['loadCVHeaders']);
5 |
6 | class ClinicalVariablesStore extends Reflux.Store {
7 | constructor() {
8 | super();
9 | this.listenables = ClinicalVariablesActions;
10 | this.state = {
11 | headers: [],
12 | variablesDetails: []
13 | };
14 | }
15 |
16 | onLoadCVHeaders(){
17 | API.GET("clinicalvariables")
18 | .then(res => {
19 | let headersMap = res.data["results"].map(entry => {
20 | return {
21 | value: entry.variable,
22 | label: entry.variable
23 | }
24 | });
25 |
26 | this.setState({
27 | headers: headersMap,
28 | variablesDetails:res.data["results"]
29 | });
30 | })
31 | }
32 | }
33 |
34 | export {ClinicalVariablesStore, ClinicalVariablesActions};
35 |
--------------------------------------------------------------------------------
/Backend/protocol_element/api/serializers/PEInquirySerializer.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from rest_framework import serializers
5 | from rest_framework import permissions
6 |
7 | from protocol_element.models import PEInquiry
8 | from protocol_element.api.serializers import PENextElementsSerializer
9 |
10 | from patients.api.serializers import ClinicalVariableSerializer
11 |
12 | class PEInquirySerializer(serializers.ModelSerializer):
13 | clinicalVariable = ClinicalVariableSerializer()
14 | nextElement = serializers.SerializerMethodField(required=False)
15 | type = serializers.SerializerMethodField(required=False)
16 |
17 | class Meta:
18 | permission_classes = [permissions.IsAuthenticated]
19 | model = PEInquiry
20 | #exclude = ['id']
21 | fields = '__all__'
22 |
23 | def get_type(self, obj):
24 | return "Inquiry"
25 |
26 | def get_nextElement(self, obj):
27 | if obj.nextElement:
28 | return str(obj.nextElement.nextElement.internalId)
29 | return ""
--------------------------------------------------------------------------------
/Backend/accounts/models/UserRecovery.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.db import models
5 | from django.contrib.auth.models import User
6 | from django.utils import timezone
7 |
8 | from utils.hashes import createUUID
9 | from utils.time import nextMonth
10 |
11 | class UserRecovery(models.Model):
12 | user = models.ForeignKey(User)
13 | validity = models.DateTimeField(default=nextMonth)
14 | hash = models.CharField(max_length=50, default=createUUID)
15 | used = models.BooleanField(default=False)
16 |
17 | def __unicode__(self):
18 | return u"Password Recovery for %s" % self.user
19 |
20 | def setNewPassword(self, new_password):
21 | self.user.set_password(new_password)
22 | self.user.save()
23 | self.used = True
24 | self.save()
25 |
26 | @staticmethod
27 | def getUserRecovery(hash):
28 | try:
29 | return UserRecovery.objects.get(hash=hash, used=False, validity__gt=timezone.now())
30 | except UserRecovery.DoesNotExist as ex:
31 | return None
32 |
--------------------------------------------------------------------------------
/UI/src/js/components/dynamicPages/About.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react';
2 | import API from '../../API.js';
3 | import ReactHtmlParser from 'react-html-parser';
4 | import {version} from '../../../../package.json';
5 |
6 | class About extends Component {
7 | constructor(props) {
8 | super(props);
9 | this.state = {
10 | about: undefined
11 | };
12 | }
13 |
14 | componentDidMount() {
15 | API.GET("about")
16 | .then(res => {
17 | if(this.refs.about)
18 | this.setState({about:res.data["about"]});
19 | })
20 | }
21 |
22 | render() {
23 | return (
24 |
25 |
26 |
Version
27 |
The current system version is {version}
28 |
29 |
30 | {ReactHtmlParser(this.state.about)}
31 |
32 |
33 | );
34 | }
35 | }
36 |
37 | export default About;
--------------------------------------------------------------------------------
/Backend/patients/admin.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.contrib import admin
5 | from models import Patient, ClinicalVariable, CVGroup, CVPatient, Admission, CVOption
6 |
7 | # Register your models here.
8 |
9 | @admin.register(Patient)
10 | class PatientAdmin(admin.ModelAdmin):
11 | list_display = ("id", "first_name", "last_name", "active", "status")
12 |
13 | @admin.register(ClinicalVariable)
14 | class ClinicalVariableAdmin(admin.ModelAdmin):
15 | list_display = ("group", "variable", "type", "description", "index_representation")
16 |
17 | @admin.register(CVGroup)
18 | class CVGroupAdmin(admin.ModelAdmin):
19 | list_display = ("title", "description", "index_representation")
20 |
21 | @admin.register(CVPatient)
22 | class CVPatientAdmin(admin.ModelAdmin):
23 | list_display = ("patient", "variable", "value")
24 |
25 | @admin.register(CVOption)
26 | class CVOptionAdmin(admin.ModelAdmin):
27 | list_display = ("variable", "option")
28 |
29 | @admin.register(Admission)
30 | class AdmissionAdmin(admin.ModelAdmin):
31 | pass#list_display = ("patient", "physician", "variable", "value")
32 |
33 |
--------------------------------------------------------------------------------
/UI/src/css/LoginComponent.css:
--------------------------------------------------------------------------------
1 | .li-login
2 | {
3 | min-width: 300px;
4 | }
5 |
6 | .form-signin .form-control
7 | {
8 | position: relative;
9 | font-size: 16px;
10 | height: auto;
11 | padding: 5px;
12 | -webkit-box-sizing: border-box;
13 | -moz-box-sizing: border-box;
14 | box-sizing: border-box;
15 | }
16 |
17 | .form-signin .form-control:focus
18 | {
19 | z-index: 2;
20 | }
21 |
22 | .form-signin input[type="text"]
23 | {
24 | margin-bottom: -1px;
25 | border-bottom-left-radius: 0;
26 | border-bottom-right-radius: 0;
27 | }
28 |
29 | .form-signin input[type="password"]
30 | {
31 | margin-bottom: 10px;
32 | border-top-left-radius: 0;
33 | border-top-right-radius: 0;
34 | }
35 | .form-signin
36 | {
37 | max-width: 330px;
38 | padding: 15px;
39 | margin: 0 auto;
40 | }
41 | .form-signin .form-signin-heading, .form-signin .checkbox
42 | {
43 | margin-bottom: 10px;
44 | }
45 | .form-signin .checkbox
46 | {
47 | font-weight: normal;
48 | margin-left: 20px;
49 | }
50 | .need-help
51 | {
52 | margin-top: 10px;
53 | }
54 | .new-account
55 | {
56 | display: block;
57 | margin-top: 10px;
58 | }
59 |
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | db:
2 | image: postgres:9.3
3 | environment:
4 | - POSTGRES_USER=genericcdss
5 | - POSTGRES_PASS=12345
6 |
7 | nginx:
8 | image: nginx:1.14.0
9 | ports:
10 | - "9000:8000"
11 | volumes:
12 | - ./Backend:/src
13 | - ./config/nginx:/etc/nginx/conf.d
14 | - ./Backend/static:/static
15 | - ./UI/build:/frontend
16 | links:
17 | - web
18 |
19 | web:
20 | image: bioinformatics-ua/genericcdss:latest
21 | command: bash -c "cd /GenericCDSS/config && sh run_docker.sh"
22 | environment:
23 | - DOCKER_POSTGRES_USER=genericcdss
24 | - DOCKER_POSTGRES_PASS=12345
25 | - DOCKER_POSTGRES_DB=genericcdss
26 | - DOCKER_POSTGRES_HOST=db
27 | - DOCKER_POSTGRES_PORT=5432
28 | - DEPLOY_MODE=demo
29 | - API_URL=http://localhost:9000/genericcdss/api/
30 | - HOMEPAGE=http://localhost:9000/genericcdss
31 | - BASE_URL=genericcdss
32 | - VERSION=0.1
33 | links:
34 | - db
35 | volumes:
36 | - ./Backend:/src
37 | - ./Backend/static:/GenericCDSS/Backend/static
38 | - ./UI/build:/GenericCDSS/UI/build
39 | expose:
40 | - "8000"
41 |
--------------------------------------------------------------------------------
/Backend/protocol_element/api/serializers/PEDecisionSerializer.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from rest_framework import serializers
5 | from rest_framework import permissions
6 |
7 | from patients.api.serializers import ClinicalVariableSerializer
8 |
9 | from protocol_element.api.serializers import PENextElementsSerializer
10 | from protocol_element.models import PEDecision
11 |
12 | class PEDecisionSerializer(serializers.ModelSerializer):
13 | clinicalVariable = ClinicalVariableSerializer()
14 | nextElement = serializers.SerializerMethodField(required=False)
15 | type = serializers.SerializerMethodField(required=False)
16 |
17 | class Meta:
18 | permission_classes = [permissions.IsAuthenticated]
19 | model = PEDecision
20 | #exclude = ['id']
21 | fields = '__all__'
22 |
23 | def get_type(self, obj):
24 | return "Decision"
25 |
26 | def get_nextElement(self, obj):
27 | string = ""
28 | for element in obj.nextElement.all():
29 | string += element.option + ":" + str(element.nextElement.internalId) + ";"
30 | return string[:-1]
31 |
32 |
--------------------------------------------------------------------------------
/UI/src/js/reflux/PatientClinicalVariablesReflux.js:
--------------------------------------------------------------------------------
1 | import Reflux from 'reflux';
2 | import API from '../API.js';
3 |
4 | const PatientClinicalVariablesActions = Reflux.createActions(['load', 'refresh', 'addCVData']);
5 |
6 | class PatientClinicalVariablesStore extends Reflux.Store {
7 | constructor() {
8 | super();
9 | this.listenables = PatientClinicalVariablesActions;
10 | this.state = {
11 | data: [],
12 | headers: []
13 | };
14 | }
15 |
16 | onLoad(id){
17 | API.GET("patientclinicalvariables", id)
18 | .then(res => {
19 | this.setState({
20 | headers: res.data["headers"],
21 | data: res.data["results"]
22 | });
23 | })
24 | }
25 |
26 | onAddCVData(data){
27 | API.POST("patientclinicalvariables", "addVariables", data)
28 | .then(res => {
29 | this.setState({
30 | headers: res.data["headers"],
31 | data: res.data["results"]
32 | });
33 | this.trigger();
34 | });
35 | }
36 | }
37 |
38 | export {PatientClinicalVariablesStore, PatientClinicalVariablesActions};
39 |
--------------------------------------------------------------------------------
/UI/src/js/components/globalComponents/LoginButton.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react';
2 | import LoginComponent from './LoginComponent.js';
3 | import API from '../../API.js';
4 |
5 | class LoginButton extends Component {
6 | constructor(props) {
7 | super(props);
8 | this.state = {
9 | showDefaultHome: false
10 | };
11 | }
12 |
13 | componentDidMount(){
14 | API.GET("settings")
15 | .then(res => {
16 | this.setState({showDefaultHome:res.data["showDefaultHome"]});
17 | });
18 | }
19 |
20 | render() {
21 | if(this.state.showDefaultHome)
22 | return ( );
23 | return (
24 |
33 | );
34 | }
35 | }
36 |
37 | export default LoginButton;
--------------------------------------------------------------------------------
/UI/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "genericcdss",
3 | "version": "0.1.0",
4 | "private": true,
5 | "api_url": "http://127.0.0.1:8000/api/",
6 | "homepage": "http://127.0.0.1:3000",
7 | "base_url": "",
8 | "dependencies": {
9 | "axios": "^0.18.0",
10 | "bootstrap": "^4.1.3",
11 | "font-awesome": "^4.7.0",
12 | "history": "^4.7.2",
13 | "jquery": "^3.3.1",
14 | "rc-tabs": "^9.2.4",
15 | "react": "^16.2.0",
16 | "react-awesome-modal": "^2.0.3",
17 | "react-bootstrap": "^0.32.4",
18 | "react-bootstrap-sweetalert": "^4.4.1",
19 | "react-cookie": "^2.1.4",
20 | "react-date-picker": "^6.10.1",
21 | "react-dom": "^16.2.0",
22 | "react-html-parser": "^2.0.2",
23 | "react-router": "^4.2.0",
24 | "react-router-dom": "^4.2.2",
25 | "react-scripts": "0.9.5",
26 | "react-select": "^1.2.1",
27 | "react-simple-flowchart": "^1.2.2",
28 | "react-table": "^6.7.6",
29 | "reflux": "^6.4.1",
30 | "semantic-ui-css": "^2.3.1",
31 | "semantic-ui-react": "^0.79.1"
32 | },
33 | "devDependencies": {},
34 | "scripts": {
35 | "start": "react-scripts start",
36 | "build": "react-scripts build",
37 | "test": "react-scripts test --env=jsdom",
38 | "eject": "react-scripts eject"
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/UI/src/externalImports/mfglabs-iconset/README.md:
--------------------------------------------------------------------------------
1 | #MFG Labs iconset
2 | ===============
3 |
4 | ##Awesome web font icon by MFG Labs
5 |
6 | How does it work?
7 |
8 | Easy as pie
9 |
10 | Start by downloading the project on this url.
11 |
12 | 1. Copy the font directory into your project
13 | 2. Copy the mfglabs_iconset.css style sheet into your project.
14 | 3. Copy the link of the stylesheet into you header
15 |
16 |
17 | ` `
18 |
19 | ###Drop the markup ` ` anywhere
20 |
21 |
22 | ` `
23 |
24 |
25 | ##Customisation
26 |
27 | Size subclass
28 |
29 | Create bevel and emboss is easy by using custom sub class
30 |
31 |
32 | ###Add the subclass icon2x or icon3x
33 |
34 |
35 | ` `
36 |
37 | ###Customise your css directly in mfglabs_iconset.css
38 |
39 |
40 | `.icon2x { font-size: 2em; }`
41 |
42 | `.icon3x { font-size: 3em; }`
43 |
44 | ##Licenses
45 | All icons are distributed under
46 | [CC BY-SA](http://creativecommons.org/licenses/by/3.0/deed.en) licence.
47 |
48 | Font is distributed under
49 | [SIL](http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=OFL) licence.
50 |
--------------------------------------------------------------------------------
/Backend/history/api/views/HistoryViewSet.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from rest_framework import viewsets, mixins, status
5 | from rest_framework.response import Response
6 |
7 | from history.models import History
8 | from history.api.serilizer import HistorySerializer
9 |
10 | class HistoryViewSet(mixins.ListModelMixin,
11 | viewsets.GenericViewSet):
12 | """
13 | API for History manipulation
14 | """
15 | queryset = History.objects.none()
16 | serializer_class = HistorySerializer
17 |
18 |
19 | def get_queryset(self):
20 | return History.all(user=self.request.user).exclude(event=History.ACCESS)
21 |
22 | def list(self, request, *args, **kwargs):
23 | """
24 | Return a list of user-related history, across all the system.
25 |
26 | """
27 | return super(HistoryViewSet, self).list(request, args, kwargs)
28 |
29 | def __filterHistory(self, Model, pk):
30 | '''Internal class that handles the creation of the History Serializer based on the object type, and its public hash.
31 |
32 | DEPRECATED: In favor of :class:`history.api.FilteredHistory`
33 | '''
34 | serializer = HistorySerializer(many=True, instance=History.type(Model, pk))
35 |
36 | return Response(serializer.data, status=status.HTTP_201_CREATED)
--------------------------------------------------------------------------------
/Backend/utils/api/views/FlatPagesView.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from rest_framework import viewsets
5 | from rest_framework.permissions import AllowAny
6 | from rest_framework.response import Response
7 | from rest_framework.decorators import detail_route
8 |
9 | from django.contrib.flatpages.models import FlatPage
10 |
11 | class FlatPagesView(viewsets.ViewSet):
12 | permission_classes = (AllowAny,)
13 |
14 | @detail_route(methods=['get'])
15 | def getAbout(self, request, *args, **kwargs):
16 | try:
17 | aboutPage = FlatPage.objects.get(title="About")
18 | return Response({"about": aboutPage.content})
19 | except:
20 | return Response({"about": "Error"})
21 |
22 |
23 | @detail_route(methods=['get'])
24 | def getHelp(self, request, *args, **kwargs):
25 | try:
26 | helpPage = FlatPage.objects.get(title="Help")
27 | return Response({"help": helpPage.content})
28 | except:
29 | return Response({"help": "Error"})
30 |
31 |
32 | @detail_route(methods=['get'])
33 | def getHome(self, request, *args, **kwargs):
34 | try:
35 | homePage = FlatPage.objects.get(title="Home")
36 | return Response({"home": homePage.content})
37 | except:
38 | return Response({"home": "Error"})
--------------------------------------------------------------------------------
/UI/src/css/Select.css:
--------------------------------------------------------------------------------
1 | .invalid-feedback-select {
2 | display: block;
3 | width: 100%;
4 | margin-top: .25rem;
5 | font-size: 80%;
6 | color: #dc3545;;
7 | }
8 | .custom-select.is-invalid~.invalid-feedback-select,
9 | .form-control.is-invalid~.invalid-feedback-select{
10 | display: block;
11 | }
12 |
13 | .warning-feedback-select {
14 | display: block;
15 | width: 100%;
16 | margin-top: .25rem;
17 | font-size: 80%;
18 | color: #bba70a;
19 | }
20 | .custom-select.is-warning~.warning-feedback-select,
21 | .form-control.is-warning~.warning-feedback-select{
22 | display: block;
23 | }
24 |
25 | .Select{
26 | z-index: 100;
27 | }
28 |
29 | .Selectx2{
30 | z-index: 200;
31 | }
32 |
33 | .Selectx3{
34 | z-index: 300;
35 | }
36 |
37 |
38 | .Selectx4{
39 | z-index: 400;
40 | }
41 |
42 | .Selectx5{
43 | z-index: 500;
44 | }
45 |
46 | .Selectx6{
47 | z-index: 600;
48 | }
49 |
50 | .Selectx7{
51 | z-index: 700;
52 | }
53 |
54 | .Selectx8{
55 | z-index: 800;
56 | }
57 |
58 | .Selectx9{
59 | z-index: 900;
60 | }
61 |
62 | .Selectx10{
63 | z-index: 1000;
64 | }
65 |
66 | .Selectx11{
67 | z-index: 1100;
68 | }
69 |
70 | .Selectx12{
71 | z-index: 1200;
72 | }
73 |
74 | .Selectx13{
75 | z-index: 1300;
76 | }
77 |
78 | .Selectx14{
79 | z-index: 1400;
80 | }
81 |
82 | .Selectx15{
83 | z-index: 1500;
84 | }
--------------------------------------------------------------------------------
/Backend/protocol_element/models/PEInquiry.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.db import models
5 |
6 | from protocol_element.models import ProtocolElement, PENextElements
7 | from patients.models import ClinicalVariable
8 |
9 | class PEInquiry(ProtocolElement):
10 | clinicalVariable = models.ForeignKey(ClinicalVariable)
11 | nextElement = models.ForeignKey(PENextElements, null=True)
12 |
13 | def getNextElementId(self):
14 | if self.nextElement:
15 | return self.nextElement.getNextElementId()
16 | return None
17 |
18 | @staticmethod
19 | def new(id, clinicalVariable, protocol):
20 | cv = ClinicalVariable.objects.get(variable=clinicalVariable)
21 | return PEInquiry.objects.create(clinicalVariable=cv, internalId=id, protocol=protocol).save()
22 |
23 | @staticmethod
24 | def addNextElement(id, protocol, nextElementId):
25 | pe = ProtocolElement.get(type=ProtocolElement.INQUIRY,internalId=int(id), protocol=protocol)
26 | nextElement = PENextElements.new(nextElementId=int(nextElementId), protocol=protocol)
27 | pe.nextElement = nextElement
28 | pe.save()
29 |
30 | @staticmethod
31 | def all():
32 | '''
33 | Returns all inquiry protocol elements
34 | '''
35 |
36 | tmpAll = PEInquiry.objects.all()
37 |
38 | return tmpAll.order_by('internalId')
--------------------------------------------------------------------------------
/Backend/protocol_element/models/PEAction.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.db import models
5 |
6 | from protocol_element.models import ProtocolElement, PENextElements
7 |
8 | class PEAction(ProtocolElement):
9 | action = models.CharField(max_length=300)
10 | nextElement = models.ForeignKey(PENextElements, null=True)
11 |
12 | def getNextElementId(self):
13 | if self.nextElement:
14 | return self.nextElement.getNextElementId()
15 | return None
16 |
17 | @staticmethod
18 | def new(id, action, protocol):
19 | return PEAction.objects.create(action=action, internalId=id, protocol=protocol).save()
20 |
21 | @staticmethod
22 | def addNextElement(id, protocol, nextElementId):
23 | pe = ProtocolElement.get(type=ProtocolElement.ACTION, internalId=int(id), protocol=protocol)
24 | nextElement = PENextElements.new(nextElementId=int(nextElementId), protocol=protocol)
25 | pe.nextElement = nextElement
26 | pe.save()
27 |
28 | def execute(self):
29 | print "to do"
30 |
31 | if self.nextElement != None:
32 | self.nextElement.nextElement.execute()
33 |
34 | @staticmethod
35 | def all():
36 | '''
37 | Returns all action protocol elements
38 | '''
39 |
40 | tmpAll = PEAction.objects.all()
41 |
42 | return tmpAll.order_by('internalId')
--------------------------------------------------------------------------------
/UI/src/js/reflux/AdmissionReflux.js:
--------------------------------------------------------------------------------
1 | import Reflux from 'reflux';
2 | import API from '../API.js';
3 |
4 | const AdmissionActions = Reflux.createActions([
5 | 'load',
6 | 'admitPatient',
7 | 'dischargePatient'
8 | ]);
9 |
10 | class AdmissionStore extends Reflux.Store {
11 | constructor(props) {
12 | super(props);
13 | this.listenables = AdmissionActions;
14 | this.state = {
15 | patientList: [],
16 | loading: false,
17 | }
18 | }
19 |
20 | onLoad() {
21 | this.setState({loading: true});
22 | API.GET("admission")
23 | .then(res => {
24 | this.setState({
25 | patientList: res.data["results"],
26 | loading: false
27 | });
28 | })
29 | }
30 |
31 | onDischargePatient(id) {
32 | API.POST("admission", "discharge", {patientID: id});
33 | }
34 |
35 | onAdmitPatient(patientID, seletedProtocols, room) {
36 | this.setState({loading: true});
37 | API.POST("admission", "new", {
38 | patientID: patientID,
39 | seletedProtocols: seletedProtocols,
40 | room:room
41 | }).then(res => {
42 | this.setState({
43 | patientList: res.data["results"],
44 | loading: false
45 | });
46 | })
47 | }
48 |
49 | }
50 |
51 | export {AdmissionStore, AdmissionActions};
--------------------------------------------------------------------------------
/UI/src/js/components/protocol/ProtocolCostumization.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Reflux from 'reflux';
3 | import Select from 'react-select';
4 | import "react-table/react-table.css";
5 | import {ProtocolStore, ProtocolActions} from '../../reflux/ProtocolReflux.js';
6 | /**
7 | * NOT USED
8 | * */
9 | class ProtocolCostumization extends Reflux.Component {
10 | constructor(props) {
11 | super(props);
12 | this.store = ProtocolStore;
13 | this.state = [];
14 | }
15 |
16 | componentDidMount() {
17 | ProtocolActions.load();
18 | }
19 |
20 | selectHandleChange = (selectedProtocol) => {
21 | this.setState({selectedProtocol});
22 | this.props.setProtocol({selectedProtocol});
23 | };
24 |
25 | render() {
26 | return (
27 |
28 |
36 | {/*later i can insert new things about the protocol here (costumization for the patient)*/}
37 |
38 | );
39 | }
40 | }
41 |
42 | export default ProtocolCostumization;
43 |
--------------------------------------------------------------------------------
/UI/src/js/components/globalComponents/Header.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react';
2 | import {Link} from "react-router-dom";
3 | import NavigationBar from './NavigationBar.js';
4 | import API from '../../API.js';
5 | import ReactHtmlParser from 'react-html-parser';
6 |
7 | class Header extends Component {
8 | constructor(props) {
9 | super(props);
10 | this.state = {
11 | appSymbol: ""
12 | };
13 | }
14 |
15 | componentDidMount() {
16 | API.GET("settings")
17 | .then(res => {
18 | if (this.refs.header)
19 | this.setState({appSymbol: res.data["appSymbolSmall"]});
20 | })
21 | }
22 |
23 | render() {
24 | return (
25 |
35 | );
36 | }
37 | }
38 |
39 | export default Header;
--------------------------------------------------------------------------------
/Backend/history/api/views/FilteredHistoryListView.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.apps import apps
5 |
6 | from rest_framework import filters, generics
7 | from rest_framework.response import Response
8 |
9 | from django_filters.rest_framework import DjangoFilterBackend
10 |
11 | from history.models import History
12 | from history.api.serializers import HistorySerializer
13 |
14 | class FilteredHistoryListView(generics.ListAPIView):
15 | '''
16 | Listing API view that handles filtering the generic history, based on a set of parameters.
17 | '''
18 | queryset = History.objects.none()
19 | serializer_class = HistorySerializer
20 | filter_backends = [DjangoFilterBackend] #(filters.DjangoFilterBackend, AliasOrderingFilter)
21 | ordering_fields = ('event', 'date', 'actor')
22 | ordering_map = { }
23 |
24 | # map of possible history filters
25 | type_map = {
26 | #'process': 'process.Process',
27 | #'request': 'process.Request',
28 | 'to': 'do',
29 | }
30 |
31 | def get_queryset(self):
32 | """
33 | Retrieves the proper object to filter the history by
34 | """
35 | kwargs = self.request.parser_context['kwargs']
36 |
37 | mdl = kwargs['model']
38 | pk = kwargs['pk']
39 |
40 | try:
41 | ObjModel = apps.get_model(self.type_map[mdl])
42 |
43 | return History.type(ObjModel, pk, related=True).exclude(event=History.ACCESS)
44 |
45 | except KeyError:
46 | return Response({'error': 'No type of object %s' %mdl})
--------------------------------------------------------------------------------
/Backend/protocol/api/serializers/ExecutedProtocolSerializer.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from rest_framework import serializers
5 | from rest_framework import permissions
6 |
7 | from protocol.models import ExecutedProtocol
8 |
9 | from patients.models import Admission
10 |
11 |
12 | class ExecutedProtocolSerializer(serializers.ModelSerializer):
13 | title = serializers.SerializerMethodField(required=False)
14 | description = serializers.SerializerMethodField(required=False)
15 | execution_time = serializers.SerializerMethodField(required=False)
16 | admission_physician = serializers.SerializerMethodField(required=False)
17 | last_measure_physician = serializers.SerializerMethodField(required=False)
18 |
19 | class Meta:
20 | permission_classes = [permissions.IsAuthenticated]
21 | model = ExecutedProtocol
22 | fields = '__all__'
23 |
24 | def get_title(self, obj):
25 | return obj.protocol.title
26 |
27 | def get_description(self, obj):
28 | return obj.protocol.description
29 |
30 | def get_execution_time(self, obj):
31 | if(obj.execution_time):
32 | return obj.execution_time.strftime("%Y-%m-%d %H:%M")
33 | return ""
34 |
35 | def get_admission_physician(self, obj):
36 | return Admission.getLatestAdmission(obj.patient).physician.getFullName()
37 |
38 | def get_last_measure_physician(self, obj):
39 | if(obj.physician):
40 | return obj.physician.getFullName()
41 | return ""
--------------------------------------------------------------------------------
/Backend/accounts/management/commands/cdsu.py:
--------------------------------------------------------------------------------
1 | # coding=utf-8
2 | from django.core.management.base import BaseCommand
3 | from django.contrib.auth.models import User
4 |
5 | from accounts.models import Profile
6 |
7 | class Command(BaseCommand):
8 | help = 'This command will populate the db with random data to create a demo installation'
9 |
10 | def add_arguments(self, parser):
11 | parser.add_argument(
12 | '--force',
13 | action='store_true',
14 | dest='force',
15 | help='Force the deletion and the creation of the super user',
16 | )
17 |
18 | def handle(self, *args, **options):
19 | try:
20 | user = User.objects.get(username="john", email="joao.rafael.almeida@ua.pt")
21 | if options['force']:
22 | self.stdout.write("\nCleaning the old super user!\n\n")
23 | user.delete()
24 | self.stdout.write("\nCreating the new super user!\n\n")
25 | self.create_superUser()
26 | self.stdout.write("Success:The superuser was created with success!\n")
27 | else:
28 | self.stdout.write("\nERROR:The superuser was already created!\n\n")
29 | except:
30 | self.create_superUser()
31 | self.stdout.write("Success:The superuser was created with success!\n")
32 |
33 | def create_superUser(self):
34 | user = User.objects.create_superuser(username="john", email="joao.rafael.almeida@ua.pt", password="12345qwert")
35 | Profile.objects.create(user=user,
36 | role=Profile.PHYSICIAN)#change this
37 |
--------------------------------------------------------------------------------
/UI/src/js/reflux/StateReflux.js:
--------------------------------------------------------------------------------
1 | import Reflux from 'reflux';
2 |
3 | const StateActions = Reflux.createActions(['loadingStart', 'loadingEnd', 'closeModal', 'openModal', 'updateModal']);
4 |
5 | class StateStore extends Reflux.Store {
6 | constructor() {
7 | super();
8 | this.listenables = StateActions;
9 | this.state = {
10 | loading: true,
11 | modalVisible: false,
12 | modalHeader: undefined,
13 | modalContent: undefined,
14 | modalFooter: undefined,
15 | };
16 | }
17 |
18 | onLoadingStart() {
19 | this.setState({loading: true});
20 | this.trigger();
21 | }
22 |
23 | onLoadingEnd() {
24 | this.setState({loading: false});
25 | this.trigger();
26 | }
27 |
28 | onCloseModal() {
29 | this.setState({
30 | modalVisible: false,
31 | modalHeader: undefined,
32 | modalContent: undefined,
33 | modalFooter: undefined,
34 | });
35 | this.trigger();
36 | }
37 |
38 | onOpenModal(modalHeader, modalContent, modalFooter) {
39 | this.setState({
40 | modalVisible: true,
41 | modalHeader:modalHeader,
42 | modalContent: modalContent,
43 | modalFooter:modalFooter
44 | });
45 | this.trigger();
46 | }
47 |
48 | onUpdateModal(modalHeader, modalContent, modalFooter) {
49 | this.setState({
50 | modalHeader:modalHeader,
51 | modalContent: modalContent,
52 | modalFooter:modalFooter
53 | });
54 | this.trigger();
55 | }
56 | }
57 |
58 | export {StateStore, StateActions};
59 |
--------------------------------------------------------------------------------
/Backend/utils/api/views/ConstanceView.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from rest_framework import viewsets
5 | from rest_framework.permissions import AllowAny
6 | from rest_framework.response import Response
7 | from rest_framework.decorators import detail_route
8 |
9 | from constance import config
10 | from django.contrib.flatpages.models import FlatPage
11 |
12 | class ConstanceView(viewsets.ViewSet):
13 | permission_classes = (AllowAny,)
14 |
15 | def __getFooter(self):
16 | try:
17 | return config.footer_extra
18 | except:
19 | return "Error"
20 |
21 | def __getAppSymbol(self):
22 | try:
23 | return config.app_symbol
24 | except:
25 | return "Error"
26 |
27 | def __getAppSymbolSmall(self):
28 | try:
29 | return config.app_symbol_small
30 | except:
31 | return "Error"
32 |
33 | def __getTitle(self):
34 | try:
35 | return config.site_name
36 | except:
37 | return "Error"
38 |
39 | def __getShowDefaultHome(self):
40 | try:
41 | return config.show_default_home
42 | except:
43 | return "Error"
44 |
45 | @detail_route(methods=['get'])
46 | def getSettings(self, request, *args, **kwargs):
47 | response = {}
48 |
49 | response["title"] = self.__getTitle()
50 | response["footer"] = self.__getFooter()
51 | response["appSymbol"] = self.__getAppSymbol()
52 | response["appSymbolSmall"] = self.__getAppSymbolSmall()
53 | response["showDefaultHome"] = self.__getShowDefaultHome()
54 |
55 | return Response(response)
--------------------------------------------------------------------------------
/Backend/patients/api/serializers/AdmissionSerializer.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from rest_framework import serializers
5 | from rest_framework import permissions
6 |
7 | from patients.models import Admission
8 |
9 | from accounts.api.serializers import UserProfileSerializer
10 |
11 | from patients.api.serializers import PatientSerializer
12 |
13 | class AdmissionSerializer(serializers.ModelSerializer):
14 | admission_physician = serializers.SerializerMethodField(required=False)
15 | last_measure_physician = serializers.SerializerMethodField(required=False)
16 | next_measure = serializers.SerializerMethodField(required=False)
17 | last_measure = serializers.SerializerMethodField(required=False)
18 | #protocol_id = serializers.SerializerMethodField(required=False)
19 | patient = PatientSerializer()
20 |
21 | class Meta:
22 | permission_classes = [permissions.IsAuthenticated]
23 | model = Admission
24 | fields = '__all__'
25 |
26 | def get_admission_physician(self, obj):
27 | return obj.physician.getFullName()
28 |
29 | def get_last_measure_physician(self, obj):
30 | if(obj.getLastProtocolAssignedMeasurePhysician() != ""):
31 | return obj.getLastProtocolAssignedMeasurePhysician().getFullName()
32 | return obj.physician.getFullName()
33 |
34 | def get_next_measure(self, obj):
35 | nextExecution, nextScheduleTitle = obj.getNextProtocolAssignedMeasure()
36 | return nextExecution + " - " + nextScheduleTitle
37 |
38 | def get_last_measure(self, obj):
39 | return obj.getLastProtocolAssignedMeasure()
--------------------------------------------------------------------------------
/Backend/genericcdss/urls.py:
--------------------------------------------------------------------------------
1 | """genericcdss URL Configuration
2 |
3 | The `urlpatterns` list routes URLs to views. For more information please see:
4 | https://docs.djangoproject.com/en/1.11/topics/http/urls/
5 | Examples:
6 | Function views
7 | 1. Add an import: from my_app import views
8 | 2. Add a URL to urlpatterns: url(r'^$', views.home, name='home')
9 | Class-based views
10 | 1. Add an import: from other_app.views import Home
11 | 2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home')
12 | Including another URLconf
13 | 1. Import the include() function: from django.conf.urls import url, include
14 | 2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls'))
15 | """
16 | from django.conf.urls import url, include
17 | from django.contrib import admin
18 | from django.conf import settings
19 | import os
20 |
21 | admin.site.site_header = settings.ADMIN_CONSOLE_NAME
22 |
23 | BASE_URL = os.environ.get('BASE_URL', '')
24 |
25 | urls = [
26 | url(r'^jet/', include('jet.urls', 'jet')),
27 | url(r'^jet/dashboard/', include('jet.dashboard.urls', 'jet-dashboard')),
28 |
29 | url(r'^api-auth/', include('rest_framework.urls')),
30 |
31 | url(r'^pages/', include('django.contrib.flatpages.urls')),
32 |
33 | #Api
34 | url(r'^api/accounts/', include('accounts.urls')),
35 | url(r'^api/patients/', include('patients.urls')),
36 | url(r'^api/protocols/', include('protocol.urls')),
37 | url(r'^api/utils/', include('utils.urls')),
38 | #...
39 |
40 | #Admin
41 | url(r'^admin/', admin.site.urls)
42 | ]
43 |
44 | if BASE_URL != '':
45 | urlpatterns = [
46 | url(r'^' + BASE_URL + '/', include(urls)),
47 | ]
48 | else:
49 | urlpatterns = urls
50 |
--------------------------------------------------------------------------------
/Backend/patients/api/views/PatientViewSet.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from rest_framework import viewsets, filters
5 | from rest_framework.filters import OrderingFilter
6 | from rest_framework.decorators import list_route
7 | from rest_framework.response import Response
8 |
9 | from django_filters.rest_framework import DjangoFilterBackend
10 | from django.db import transaction
11 |
12 | from patients.api.serializers import PatientSerializer
13 |
14 | from patients.models import Patient, Admission
15 |
16 | from history.models import History
17 |
18 | class PatientViewSet(viewsets.ModelViewSet):
19 | queryset = Patient.objects.get_queryset().order_by('id')
20 | serializer_class = PatientSerializer
21 |
22 | filter_backends = [DjangoFilterBackend, OrderingFilter]
23 | filter_fields = ["first_name", "last_name"]
24 |
25 | def list(self, request, *args, **kwargs):
26 | '''
27 | Return a list of active patients
28 | '''
29 | return super(PatientViewSet, self).list(request, *args, **kwargs)
30 |
31 | @list_route(methods=['get'])
32 | def listAdmitted(self, request, *args, **kwargs):
33 | '''
34 | Return a list of active patients that are admitted in the hospital
35 | '''
36 | self.queryset = Patient.all(status=Patient.ADMITTED)
37 | return super(PatientViewSet, self).list(request, *args, **kwargs)
38 |
39 | @list_route(methods=['get'])
40 | def listDischarged(self, request, *args, **kwargs):
41 | '''
42 | Return a list of active patients that are discharged from the hospital
43 | '''
44 | self.queryset = Patient.all(status=Patient.DISCHARGED)
45 | return super(PatientViewSet, self).list(request, *args, **kwargs)
46 |
--------------------------------------------------------------------------------
/UI/src/js/components/protocol/ExecutedProtocols.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Reflux from 'reflux';
3 | import ReactTable from 'react-table'
4 | import "react-table/react-table.css";
5 | import {ProtocolStore, ProtocolActions} from '../../reflux/ProtocolReflux.js';
6 |
7 | class ExecutedProtocols extends Reflux.Component {
8 | constructor(props) {
9 | super(props);
10 | this.store = ProtocolStore;
11 | this.state = {};
12 | }
13 |
14 | componentDidMount() {
15 | ProtocolActions.loadExecutedProtocols(this.props.patientID);
16 | }
17 |
18 | render() {
19 | const columns = [{
20 | Header: () => Title ,
21 | id: "title",
22 | accessor: obj => obj.title,
23 | Cell: props => {props.value} // {props.value}
24 | }, {
25 | Header: () => Execution date ,
26 | id: "end_date",
27 | accessor: obj => obj.execution_time,
28 | Cell: props => {props.value}
29 | }, {
30 | Header: () => Physician ,
31 | id: "physician",
32 | accessor: obj => obj.last_measure_physician,
33 | Cell: props => {props.value}
34 | }];
35 |
36 | return (
37 |
38 |
39 |
44 |
45 | );
46 | }
47 | }
48 |
49 | export default ExecutedProtocols;
--------------------------------------------------------------------------------
/UI/src/js/components/protocol/AssignedProtocols.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Reflux from 'reflux';
3 | import ReactTable from 'react-table'
4 | import "react-table/react-table.css";
5 | import {Link} from "react-router-dom";
6 | import {ProtocolStore, ProtocolActions} from '../../reflux/ProtocolReflux.js';
7 |
8 | class SelectedProtocols extends Reflux.Component {
9 | constructor(props) {
10 | super(props);
11 | this.store = ProtocolStore;
12 | this.state = {};
13 | }
14 |
15 | componentDidMount() {
16 | ProtocolActions.loadAssignedProtocols(this.props.patientID);
17 | }
18 |
19 | render() {
20 | const columns = [{
21 | Header: () => Title ,
22 | id: "title",
23 | accessor: obj => obj.title,
24 | Cell: props => {props.value}
25 | }, {
26 | Header: () => Description ,
27 | id: "start_date",
28 | accessor: obj => obj.description,
29 | Cell: props => {props.value}
30 | }, {
31 | Header: () => Physician ,
32 | id: "physician",
33 | accessor: obj => obj.admission_physician,
34 | Cell: props => {props.value}
35 | }];
36 |
37 | return (
38 |
39 |
40 |
45 |
46 | );
47 | }
48 | }
49 |
50 | export default SelectedProtocols;
--------------------------------------------------------------------------------
/Backend/accounts/tests/testProfile.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.test import TestCase
5 | from django.contrib.auth.models import User
6 |
7 | from accounts.models import Profile
8 |
9 | class ProfileTestCase(TestCase):
10 | def setUp(self):
11 | self.user = User.objects.create_user('admin', 'admin@ua.pt', '12345')
12 | self.profile = Profile(user=self.user, role=Profile.ADMINISTRATOR)
13 |
14 | def test_model_can_create_a_profile(self):
15 | old_count = Profile.objects.count()
16 | self.profile.save()
17 | new_count = Profile.objects.count()
18 |
19 | self.assertEqual(old_count + 1, new_count)
20 |
21 | def test_unicode_(self):
22 | self.unicode = u"User profile for %s" % self.user
23 |
24 | self.assertEqual(self.unicode, self.profile.__unicode__())
25 |
26 | def test_model_can_create_a_profile_nurse_type(self):
27 | nurse = User.objects.create_user('Nurse', 'nurse@ua.pt', '12345')
28 | nurse_profile = Profile(user=nurse, role=Profile.NURSE)
29 | old_count = Profile.objects.filter(role=Profile.NURSE).count()
30 | nurse_profile.save()
31 | new_count = Profile.objects.filter(role=Profile.NURSE).count()
32 |
33 | self.assertEqual(old_count + 1, new_count)
34 |
35 | def test_model_can_create_a_profile_physician_type(self):
36 | physician = User.objects.create_user('Doctor', 'doctor@ua.pt', '12345')
37 | physician_profile = Profile(user=physician, role=Profile.PHYSICIAN)
38 | old_count = Profile.objects.filter(role=Profile.PHYSICIAN).count()
39 | physician_profile.save()
40 | new_count = Profile.objects.filter(role=Profile.PHYSICIAN).count()
41 |
42 | self.assertEqual(old_count + 1, new_count)
43 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | #######################################################################
2 | ############## Deploy management ##############
3 | #######################################################################
4 | docker-build:
5 | docker build -t bioinformatics-ua/genericcdss:latest .
6 |
7 | docker-run:
8 | sed -i -e "s:{BASE_URL}:clision:g" ./config/nginx/genericcdss.conf
9 | docker-compose -f docker-compose.yml -p genericcdss up -d --no-recreate
10 |
11 | docker-delete:
12 | docker rm -f genericcdss_db_1 genericcdss_web_1 genericcdss_nginx_1
13 |
14 | run:
15 | cd Backend && python manage.py runserver
16 |
17 | #######################################################################
18 | ############## Data management ##############
19 | #######################################################################
20 | createDB:
21 | cd Backend && python manage.py makemigrations && python manage.py migrate
22 |
23 | createSuperUser:
24 | cd Backend && python manage.py cdsu ${force}
25 |
26 | createProtocols:
27 | cd Backend && \
28 | python manage.py cleanAllProtocols && \
29 | # python manage.py protocolTest && \
30 | # python manage.py continuousIntravenousInfusion && \
31 | # python manage.py diabeticInpatients && \
32 | # python manage.py surgicalDiabeticInpatient && \
33 | python manage.py hypoglycemic
34 |
35 |
36 | populateInitialConfigs:
37 | cd Backend && \
38 | python manage.py populate_flatpages ${force}
39 |
40 | populateDBRandomData:
41 | cd Backend && \
42 | python manage.py populate_db_patients ${patientN} ${force}
43 |
44 | demo: createDB createSuperUser createProtocols populateInitialConfigs populateDBRandomData
45 |
46 | defaultDemo:
47 | make demo force=--force patientN=--patientNumber=20
48 |
49 | setUpSystem: createDB createSuperUser populateInitialConfigs
50 |
51 |
52 |
--------------------------------------------------------------------------------
/UI/src/css/Texts.css:
--------------------------------------------------------------------------------
1 | /*h1, h2, h3, h4, h5, h6, h7{
2 | font-family: opensansbold;
3 | }
4 |
5 | .boldit {
6 | font-family: opensansbold;
7 | }
8 |
9 | strong{
10 | font-family: opensansbold;
11 | }*/
12 |
13 | h1, h2, h3, h4, h5, h6,
14 | .h1, .h2, .h3, .h4, .h5, .h6 {
15 | font-family: "Lato", "Helvetica Neue", Helvetica, Arial, sans-serif;
16 | font-weight: 400;
17 | line-height: 1.1;
18 | color: inherit;
19 | }
20 |
21 | h1 small, h2 small, h3 small, h4 small, h5 small, h6 small,
22 | .h1 small, .h2 small, .h3 small, .h4 small, .h5 small, .h6 small,
23 | h1 .small, h2 .small, h3 .small, h4 .small, h5 .small, h6 .small,
24 | .h1 .small, .h2 .small, .h3 .small, .h4 .small, .h5 .small, .h6 .small {
25 | font-weight: normal;
26 | line-height: 1;
27 | color: #b4bcc2;
28 | }
29 |
30 | h1, .h1, h2, .h2, h3, .h3 {
31 | margin-top: 20px;
32 | margin-bottom: 10px;
33 | }
34 |
35 | h1 small, .h1 small, h1 .small, .h1 .small,
36 | h2 small, .h2 small, h2 .small, .h2 .small,
37 | h3 small, .h3 small, h3 .small, .h3 .small {
38 | font-size: 65%;
39 | }
40 |
41 | h4, .h4, h5, .h5, h6, .h6 {
42 | margin-top: 10px;
43 | margin-bottom: 10px;
44 | }
45 |
46 | h4 small, .h4 small, h4 .small, .h4 .small,
47 | h5 small, .h5 small, h5 .small, .h5 .small,
48 | h6 small, .h6 small, h6 .small, .h6 .small {
49 | font-size: 75%;
50 | }
51 |
52 | h1, .h1 {
53 | font-size: 36px;
54 | }
55 |
56 | h2, .h2 {
57 | font-size: 30px;
58 | }
59 |
60 | h3, .h3 {
61 | font-size: 24px;
62 | }
63 |
64 | h4, .h4 {
65 | font-size: 18px;
66 | }
67 |
68 | h5, .h5 {
69 | font-size: 14px;
70 | }
71 |
72 | h6, .h6 {
73 | font-size: 12px;
74 | }
75 |
76 | .text-left {
77 | text-align: left;
78 | }
79 | .text-right {
80 | text-align: right;
81 | }
82 | .text-center {
83 | text-align: center;
84 | }
85 | .text-justify {
86 | text-align: justify;
87 | }
--------------------------------------------------------------------------------
/Backend/patients/models/CVPatient.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.db import models
5 | from django.utils import timezone
6 |
7 | from patients.models import Patient, ClinicalVariable
8 |
9 | class CVPatient(models.Model):
10 | patient = models.ForeignKey(Patient)
11 | variable = models.ForeignKey(ClinicalVariable)
12 | value = models.CharField(max_length=30)
13 | measure_date = models.DateTimeField()
14 |
15 | @staticmethod
16 | def all(patient=None, group=None):
17 | '''
18 | Returns all clinical variable instances
19 | '''
20 | tmpAll = CVPatient.objects.all()
21 |
22 | if patient != None:
23 | tmpAll = tmpAll.filter(patient=patient)
24 |
25 | if group != None:
26 | tmpAll = tmpAll.filter(variable__group=group)
27 |
28 | return tmpAll
29 |
30 | @staticmethod
31 | def new(patient, group, variable, value, measure_date):
32 | variable = ClinicalVariable.get(variable=variable, group=group)
33 | cvPatient = CVPatient.objects.create(patient=patient,
34 | variable=variable,
35 | value=value,
36 | measure_date=measure_date)
37 | #History to do
38 | cvPatient.save()
39 |
40 | @staticmethod
41 | def addCVSet(cvset, patient):
42 | measure_date = timezone.now()
43 | for cv in cvset:
44 | clinicalVariavel = ClinicalVariable.objects.get(variable=cv)
45 | cvPatient = CVPatient.objects.create(patient=patient,
46 | variable=clinicalVariavel,
47 | value=cvset[cv],
48 | measure_date=measure_date)
49 | cvPatient.save()
--------------------------------------------------------------------------------
/Backend/accounts/tests/testUserRecovery.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.test import TestCase
5 | from django.contrib.auth.models import User
6 | from django.contrib.auth import authenticate
7 | from django.utils import timezone
8 |
9 | from accounts.models import UserRecovery
10 |
11 | class UserRecoveryTestCase(TestCase):
12 | def setUp(self):
13 | self.user = User.objects.create_user('admin', 'admin@ua.pt', '12345')
14 |
15 |
16 | def test_model_can_create_a_UserRecovery(self):
17 | userRecovery = UserRecovery(user=self.user)
18 | old_count = UserRecovery.objects.count()
19 | userRecovery.save()
20 | new_count = UserRecovery.objects.count()
21 |
22 | self.assertEqual(old_count + 1, new_count)
23 |
24 | def test_unicode_(self):
25 | userRecovery = UserRecovery(user=self.user)
26 | self.unicode = u"Password Recovery for %s" % self.user
27 |
28 | self.assertEqual(self.unicode, userRecovery.__unicode__())
29 |
30 | def test_UserRecovery_can_be_used_outdate(self):
31 | outdated = timezone.now() - timezone.timedelta(days=30)
32 | userRecovery = UserRecovery(user=self.user, validity=outdated)
33 | userRecovery.save()
34 |
35 | userRecovery_outdated = UserRecovery.getUserRecovery(userRecovery.hash)
36 |
37 | self.assertIsNone(userRecovery_outdated)
38 |
39 |
40 | def test_UserRecovery_can_be_used_twice(self):
41 | userRecovery = UserRecovery(user=self.user)
42 | userRecovery.save()
43 | new_password = "54321"
44 | hash = userRecovery.hash
45 |
46 | UserRecovery.getUserRecovery(hash=hash).setNewPassword(new_password)
47 | user_authenticated = authenticate(username=self.user.username, password=new_password)
48 |
49 | self.assertIsNotNone(user_authenticated)
50 |
51 | userRecovery_after_use = UserRecovery.getUserRecovery(hash)
52 |
53 | self.assertIsNone(userRecovery_after_use)
--------------------------------------------------------------------------------
/UI/src/js/components/patient/PatientComplementInfo.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react';
2 | import ClinicalVariables from './ClinicalVariables.js';
3 | import AssignedProtocols from '../protocol/AssignedProtocols.js';
4 | import ExecutedProtocols from '../protocol/ExecutedProtocols.js';
5 |
6 | import Tabs, {TabPane} from 'rc-tabs';
7 | import TabContent from 'rc-tabs/lib/TabContent';
8 | import ScrollableInkTabBar from 'rc-tabs/lib/ScrollableInkTabBar';
9 |
10 | class PatientComplementInfo extends Component {
11 | constructor(props) {
12 | super(props);
13 | this.state = {
14 | patientID: this.props.patientID
15 | }
16 | }
17 | componentDidUpdate(prevProps, prevState) {
18 | if (prevProps.patientID !== this.props.patientID)
19 | this.setState({patientID:this.props.patientID});
20 | }
21 |
22 | render() {
23 | return (
24 |
25 |
}
28 | renderTabContent={() => }
29 | >
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 | {/*to do*/}
42 | {/*Histórico de todas as ações (history backend) */}
43 |
44 |
45 | );
46 | }
47 | }
48 |
49 | export default PatientComplementInfo;
50 |
--------------------------------------------------------------------------------
/Backend/history/api/serializers/HistorySerializer.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from rest_framework import serializers
5 | from rest_framework import permissions
6 |
7 | from history.api.serializers import GenericObjectField
8 | from history.models import History
9 |
10 | class HistorySerializer(serializers.ModelSerializer):
11 | '''
12 | Serializer to handle :class:`history.models.History` objects serialization/deserialization.
13 |
14 | This class is used by django-rest-framework to handle all object conversions, to and from json,
15 | while allowing in the future to change this format with any other without losing the abstraction.
16 | '''
17 | object = GenericObjectField(read_only=True)
18 | event = serializers.SerializerMethodField()
19 | object_type = serializers.SerializerMethodField()
20 | object_repr = serializers.SerializerMethodField()
21 | actor_repr = serializers.SerializerMethodField()
22 |
23 | class Meta:
24 | model = History
25 | exclude = ['object_id', 'authorized']
26 | permission_classes = [permissions.IsAuthenticated]#, TokenHasScope]
27 |
28 | def get_object_repr(self, obj):
29 | '''
30 | Polymorphically returns the textual representation(each object decides how to represent itself)
31 | '''
32 | return obj.obj_repr()
33 |
34 | def get_event(self, obj):
35 | '''
36 | Returns a textual representation of the event that ocurred over the object being logged.
37 | '''
38 | return dict(History.EVENTS)[obj.event]
39 |
40 | def get_object_type(self, obj):
41 | '''
42 | Returns a textual representation of the type of object, typically the class name.
43 | '''
44 | return obj.object.__class__.__name__
45 |
46 | def get_actor_repr(self, obj):
47 | '''
48 | Returns a textual representation of the actor playing the action.
49 | '''
50 | return obj.actor.get_full_name() or obj.actor.email
51 |
--------------------------------------------------------------------------------
/Backend/protocol/management/commands/diabeticInpatients.py:
--------------------------------------------------------------------------------
1 | # coding=utf-8
2 | from django.core.management.base import BaseCommand
3 | from protocol.models import Protocol, ExecutedProtocol
4 | from protocol_element.models import ProtocolElement, PEAction, PEDecision, PEInquiry, PENextElements
5 | from patients.models import CVGroup, ClinicalVariable, Patient, CVPatient, Admission
6 |
7 | class Command(BaseCommand):
8 | help = 'This command will create the Diabetic Inpatients protocol in the database'
9 |
10 | def handle(self, *args, **options):
11 | self.stdout.write("\nCleaning the Diabetic Inpatients protocol!\n\n")
12 | self.clean_protocol()
13 | self.stdout.write("\nCreating the Clinical Variables needed by this protocol!\n\n")
14 | self.create_cvs()
15 | self.stdout.write("\nCreating the Diabetic Inpatients protocol!\n\n")
16 | self.create_protocol()
17 | self.stdout.write("\nSuccess:The Diabetic Inpatients protocol was created with success!\n\n")
18 |
19 | def create_cvs(self):
20 | #todo
21 | self.stdout.write("\nTODO\n\n")
22 |
23 | def clean_protocol(self):
24 | try:
25 | protocol = Protocol.objects.get(title="Diabetic Inpatients")
26 | peList = ProtocolElement.objects.filter(protocol=protocol)
27 | for pe in peList:
28 | PENextElements.objects.filter(nextElement=pe).delete()
29 | ProtocolElement.objects.filter(protocol=protocol).delete()
30 | protocol.delete()
31 | except:
32 | self.stdout.write("\nThe Diabetic Inpatients protocol does not exist in the system!\n\n")
33 |
34 | def create_protocol(self):
35 | protocol = Protocol.objects.create(title="Diabetic Inpatients",
36 | description = "It should be applied to inpatients with type two diabetes")
37 | protocol.save()
38 |
39 | #todo
40 | PEAction.new(id=1,
41 | action="In progress",
42 | protocol=protocol)
43 |
--------------------------------------------------------------------------------
/UI/src/js/components/dynamicPages/Home.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Reflux from 'reflux';
3 | import API from '../../API.js';
4 | import ReactHtmlParser from 'react-html-parser';
5 | import LoginButton from '../globalComponents/LoginComponent.js';
6 | import {UserStore} from '../../reflux/UserReflux.js';
7 |
8 | class Home extends Reflux.Component {
9 | constructor(props) {
10 | super(props);
11 | this.store = UserStore;
12 | this.state = {
13 | home: undefined,
14 | showDefaultHome: false,
15 | appSymbol: undefined
16 | };
17 | }
18 |
19 | componentDidMount() {
20 | API.GET("home")
21 | .then(res => {
22 | if (this.refs.home)
23 | this.setState({home: res.data["home"]});
24 | });
25 | API.GET("settings")
26 | .then(res => {
27 | this.setState({
28 | appSymbol: res.data["appSymbol"],
29 | showDefaultHome: res.data["showDefaultHome"]
30 | });
31 | });
32 | }
33 |
34 | render() {
35 | if (!this.state.showDefaultHome || this.state.user.authenticated)
36 | return (
37 |
38 | {ReactHtmlParser(this.state.home)}
39 |
40 | );
41 |
42 | return (
43 |
44 |
45 |
46 |
47 |
48 | {ReactHtmlParser(this.state.appSymbol)}
49 |
50 |
51 |
52 |
53 |
54 |
55 | );
56 | }
57 | }
58 |
59 | export default Home;
--------------------------------------------------------------------------------
/UI/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 | Clision
32 |
33 |
34 |
35 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/Backend/protocol/management/commands/surgicalDiabeticInpatient.py:
--------------------------------------------------------------------------------
1 | # coding=utf-8
2 | from django.core.management.base import BaseCommand
3 | from protocol.models import Protocol, ExecutedProtocol
4 | from protocol_element.models import ProtocolElement, PEAction, PEDecision, PEInquiry, PENextElements
5 | from patients.models import CVGroup, ClinicalVariable, Patient, CVPatient, Admission
6 |
7 | class Command(BaseCommand):
8 | help = 'This command will create the Surgical Diabetic Inpatient protocol in the database'
9 |
10 | def handle(self, *args, **options):
11 | self.stdout.write("\nCleaning the Surgical Diabetic Inpatient protocol!\n\n")
12 | self.clean_protocol()
13 | self.stdout.write("\nCreating the Clinical Variables needed by this protocol!\n\n")
14 | self.create_cvs()
15 | self.stdout.write("\nCreating the Surgical Diabetic Inpatient protocol!\n\n")
16 | self.create_protocol()
17 | self.stdout.write("\nSuccess:The Surgical Diabetic Inpatient protocol was created with success!\n\n")
18 |
19 | def create_cvs(self):
20 | #todo
21 | self.stdout.write("\nTODO\n\n")
22 |
23 | def clean_protocol(self):
24 | try:
25 | protocol = Protocol.objects.get(title="Surgical Diabetic Inpatient")
26 | peList = ProtocolElement.objects.filter(protocol=protocol)
27 | for pe in peList:
28 | PENextElements.objects.filter(nextElement=pe).delete()
29 | ProtocolElement.objects.filter(protocol=protocol).delete()
30 | protocol.delete()
31 | except:
32 | self.stdout.write("\nThe Surgical Diabetic Inpatient protocol does not exist in the system!\n\n")
33 |
34 | def create_protocol(self):
35 | protocol = Protocol.objects.create(title="Surgical Diabetic Inpatient",
36 | description = "It should be applied to the surgical diabetic inpatient")
37 | protocol.save()
38 |
39 | #todo
40 | PEAction.new(id=1,
41 | action="In progress",
42 | protocol=protocol)
43 |
--------------------------------------------------------------------------------
/UI/src/js/components/patient/AddPatient.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Reflux from 'reflux';
3 | import {PatientStore, PatientActions} from '../../reflux/PatientReflux.js';
4 | import PatientInfo from './PatientInfo.js';
5 | import PatientComplementInfo from './PatientComplementInfo.js';
6 | import Select from 'react-select';
7 |
8 | class AddPatient extends Reflux.Component {
9 | constructor(props) {
10 | super(props);
11 | this.store = PatientStore;
12 | this.state = {
13 | selectedPatient: undefined
14 | }
15 | }
16 |
17 | componentDidMount() {
18 | PatientActions.loadDischargedPatients();
19 | }
20 |
21 | handleChange = (selectedPatient) => {
22 | if (selectedPatient === null)
23 | selectedPatient = undefined;
24 | this.setState({selectedPatient});
25 | };
26 |
27 | render() {
28 | let mode = this.state.selectedPatient === undefined ? "add" : "show";
29 | let patientID = this.state.selectedPatient === undefined ? undefined : this.state.selectedPatient.value;
30 |
31 | return (
32 |
33 |
Insert patient
34 |
41 |
42 |
43 | {
44 | this.state.selectedPatient === undefined ? '' :
45 |
46 | Additional information
47 |
48 |
49 | }
50 |
51 | );
52 | }
53 | }
54 |
55 | export default AddPatient;
--------------------------------------------------------------------------------
/Backend/protocol/management/commands/continuousIntravenousInfusion.py:
--------------------------------------------------------------------------------
1 | # coding=utf-8
2 | from django.core.management.base import BaseCommand
3 | from protocol.models import Protocol, ExecutedProtocol
4 | from protocol_element.models import ProtocolElement, PEAction, PEDecision, PEInquiry, PENextElements
5 | from patients.models import CVGroup, ClinicalVariable, Patient, CVPatient, Admission
6 |
7 | class Command(BaseCommand):
8 | help = 'This command will create the Continuous Intravenous Infusion protocol in the database'
9 |
10 | def handle(self, *args, **options):
11 | self.stdout.write("\nCleaning the Continuous Intravenous Infusion protocol!\n\n")
12 | self.clean_protocol()
13 | self.stdout.write("\nCreating the Clinical Variables needed by this protocol!\n\n")
14 | self.create_cvs()
15 | self.stdout.write("\nCreating the Continuous Intravenous Infusion protocol!\n\n")
16 | self.create_protocol()
17 | self.stdout.write("\nSuccess:The Continuous Intravenous Infusion protocol was created with success!\n\n")
18 |
19 | def create_cvs(self):
20 | #todo
21 | self.stdout.write("\nTODO\n\n")
22 |
23 | def clean_protocol(self):
24 | try:
25 | protocol = Protocol.objects.get(title="Continuous Intravenous Infusion")
26 | peList = ProtocolElement.objects.filter(protocol=protocol)
27 | for pe in peList:
28 | PENextElements.objects.filter(nextElement=pe).delete()
29 | ProtocolElement.objects.filter(protocol=protocol).delete()
30 | protocol.delete()
31 | except:
32 | self.stdout.write("\nThe Continuous Intravenous Infusion protocol does not exist in the system!\n\n")
33 |
34 | def create_protocol(self):
35 | protocol = Protocol.objects.create(title="Continuous Intravenous Infusion",
36 | description = "This protocol is intended to be used in hyperglycemic adult patients in the intensive care unit")
37 | protocol.save()
38 |
39 | #todo
40 | PEAction.new(id=1,
41 | action="In progress",
42 | protocol=protocol)
--------------------------------------------------------------------------------
/Backend/protocol/models/AssignedProtocol.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.db import models
5 |
6 | from patients.models import Patient
7 |
8 | from protocol.models import Protocol, Schedule
9 |
10 | # class AssignedProtocol(models.Model):
11 | # protocol = models.ForeignKey(Protocol)
12 | # patient = models.ForeignKey(Patient)
13 | # schedule = models.ForeignKey(Schedule)
14 | # start_date = models.DateField()
15 | # end_date = models.DateField(null=True)
16 | # active = models.BooleanField(default=True)
17 | #
18 | #
19 | # @staticmethod
20 | # def new(protocol, patient, schedule, start_date):
21 | # assignedProtocol = AssignedProtocol.objects.create(protocol=protocol,
22 | # patient=patient,
23 | # schedule=schedule,
24 | # start_date=start_date)
25 | # # History todo
26 | # assignedProtocol.save()
27 | #
28 | # @staticmethod
29 | # def getCurrentAssignment(patient):
30 | # tmpAll = AssignedProtocol.all(patient=patient).filter(end_date__isnull=True)
31 | #
32 | # #Calculate which is the next protocol consedering the schedule
33 | # #todo, only necessary when exist more than one protocol assigned to a patient
34 | #
35 | # return tmpAll.order_by('start_date')[0]
36 | #
37 | # @staticmethod
38 | # def all(active=True, protocol=None, patient=None, schedule=None):
39 | # '''
40 | # Returns all assigned protocol instances
41 | # '''
42 | # tmpAll = AssignedProtocol.objects.all()
43 | #
44 | # if active == True:
45 | # tmpAll = tmpAll.filter(active=True)
46 | #
47 | # if protocol != None:
48 | # tmpAll = tmpAll.filter(protocol=protocol)
49 | #
50 | # if patient != None:
51 | # tmpAll = tmpAll.filter(patient=patient)
52 | #
53 | # if schedule != None:
54 | # tmpAll = tmpAll.filter(schedule=schedule)
55 | #
56 | # return tmpAll.order_by('start_date')
--------------------------------------------------------------------------------
/UI/src/js/components/protocol/Schedules.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import Reflux from 'reflux';
4 | import {StateActions} from '../../reflux/StateReflux.js';
5 |
6 | /**
7 | * Component to manage the protocol schedules
8 | *
9 | * todo finish the creation of this componenet.
10 | * The idea is to show all the schedules for the protocol, i. e.,
11 | * when a task action to schedule the protocol is created, in this modal
12 | * will be shown the decision elements and and the condition that led to the
13 | * new scheduling.
14 | * */
15 | class Schedules extends Reflux.Component {
16 | constructor(props) {
17 | super(props);
18 | this.state = {};
19 | }
20 |
21 | componentDidUpdate(prevProps, prevState) {
22 | if (prevState !== this.state)
23 | StateActions.updateModal(this.modalHeader(), this.modalContent(), this.modalFooter());
24 | }
25 |
26 | modalHeader = () => {
27 | return (
28 |
29 |
Schedules
30 |
31 | );
32 | };
33 |
34 | modalContent = () => {
35 | return (
36 |
37 | Schedules thinking how to solve the problem about the hours vs before bed/meals time
38 |
39 | );
40 | };
41 |
42 | modalFooter = () => {
43 | return (
44 |
45 |
46 | Cancel
47 |
48 |
49 | );
50 | };
51 |
52 | openModal = (event) => {
53 | event.preventDefault();
54 | StateActions.openModal(this.modalHeader(), this.modalContent(), this.modalFooter());
55 | };
56 |
57 | closeModal = () => {
58 | StateActions.closeModal();
59 | };
60 |
61 | render() {
62 | return (
63 |
64 | Show schedules
65 |
66 | );
67 | }
68 |
69 | static propTypes = {};
70 | }
71 |
72 | Schedules.defaultProps = {};
73 |
74 | export default Schedules;
75 |
76 |
77 |
78 |
79 |
--------------------------------------------------------------------------------
/UI/src/js/components/globalComponents/LoginComponent.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Reflux from 'reflux';
3 | //import {Link} from "react-router-dom";
4 | import {UserStore, UserActions} from '../../reflux/UserReflux.js';
5 |
6 | class LoginComponent extends Reflux.Component {
7 | constructor(props) {
8 | super(props);
9 | this.store = UserStore;
10 | }
11 |
12 | login = event => {
13 | event.preventDefault();
14 | if (this.refs.usr !== "" && this.refs.pwd !== "") {
15 | let username = this.refs.usr.value.trim();
16 | let password = this.refs.pwd.value.trim();
17 | let remember = this.refs.rmb.checked;
18 | UserActions.login(username, password, remember);
19 | }
20 | };
21 |
22 | render() {
23 | return (
24 |
25 |
47 |
48 | {/*
Create an account */}
49 |
50 | );
51 | }
52 | }
53 |
54 | export default LoginComponent;
--------------------------------------------------------------------------------
/Backend/patients/models/Patient.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.db import models
5 |
6 | class Patient(models.Model):
7 | ADMITTED = 1
8 | DISCHARGED = 2
9 |
10 | STATUS = (
11 | (ADMITTED, 'This patient was admitted to the hospital'),
12 | (DISCHARGED, 'This patient was discharged from hospital'),
13 | )
14 |
15 | GENDER_OPTIONS = (
16 | ('M', 'Male'),
17 | ('F', 'Female'),
18 | )
19 |
20 | code = models.CharField(max_length=20, blank=True) #To connect in the future to an EHR using HL7
21 | first_name = models.CharField(max_length=50)
22 | last_name = models.CharField(max_length=50)
23 | active = models.BooleanField(default=True)
24 | status = models.PositiveSmallIntegerField(choices=STATUS, default=ADMITTED)
25 | gender = models.CharField(max_length=1, choices=GENDER_OPTIONS)
26 | birthdate = models.DateField()
27 | phone = models.CharField(max_length=20, blank=True)
28 | email = models.CharField(max_length=50, blank=True)
29 | #... maybe more fields to do
30 |
31 | def __unicode__(self):
32 | return u"Patient %s" % self.get_full_name()
33 |
34 | def get_birthdate(self):
35 | return self.birthdate.strftime("%d/%m/%Y")
36 |
37 | def get_full_name(self):
38 | return self.first_name + " " + self.last_name
39 |
40 | def get_full_gender(self): #Change this to be multilingual
41 | if(self.gender.lower() == 'm'):
42 | return "Male"
43 |
44 | if(self.gender.lower() == 'f'):
45 | return "Female"
46 |
47 | def discharge(self):
48 | '''
49 | Discharges the patient from the hospital
50 | '''
51 | # History to do
52 | self.status = Patient.DISCHARGED
53 | self.save()
54 |
55 | def admit(self):
56 | '''
57 | Patient admission in the hospital
58 | '''
59 | # History to do
60 | self.status = Patient.ADMITTED
61 | self.save()
62 |
63 | @staticmethod
64 | def all(active=None, status=None):
65 | '''
66 | Returns all patient instances
67 | '''
68 | tmpAll = Patient.objects.all()
69 |
70 | if active != None:
71 | tmpAll = tmpAll.filter(active=active)
72 | else:
73 | tmpAll = tmpAll.filter(active=True)
74 |
75 | if status != None:
76 | tmpAll = tmpAll.filter(status=status)
77 |
78 | return tmpAll
79 |
--------------------------------------------------------------------------------
/Backend/patients/models/ClinicalVariable.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.db import models
5 | from django.utils import encoding
6 |
7 | from patients.models import Patient, CVGroup
8 |
9 | class ClinicalVariable(models.Model):
10 | STRING = 'String'
11 | NUMERIC = 'Numeric'
12 | CONDITIONAL = 'Conditional'
13 |
14 | TYPES = (
15 | (STRING, 'String - The clinical variable can store string values'),
16 | (NUMERIC, 'Numeric - The clinical variable can store numeric values'),
17 | (CONDITIONAL, 'Conditional - The clinical variable can store one option from a list of values'),
18 | )
19 |
20 | group = models.ForeignKey(CVGroup)
21 | variable = models.CharField(max_length=30)
22 | type = models.CharField(max_length=30, choices=TYPES, default=STRING)
23 | description = models.CharField(max_length=100, blank=True)
24 | index_representation = models.IntegerField()
25 | display = models.BooleanField(default=True)
26 |
27 | def __unicode__(self):
28 | return u"CV Group: %s, Variable: %s" % (self.group.title, self.variable)
29 |
30 | @staticmethod
31 | def new(group, variable, type, description, index_representation, options=None):
32 | from patients.models import CVOption
33 |
34 | cv = ClinicalVariable.objects.create(group=group,
35 | variable=variable,
36 | type=type,
37 | description=description,
38 | index_representation=index_representation)
39 | cv.save()
40 |
41 | if type == ClinicalVariable.CONDITIONAL:
42 | for option in options:
43 | CVOption.objects.create(variable=cv,
44 | option=option).save()
45 |
46 | return cv
47 |
48 | @staticmethod
49 | def all(group=None, all=False):
50 | '''
51 | Returns all clinical variable instances
52 | '''
53 | tmpAll = ClinicalVariable.objects.all()
54 |
55 | if all == False:
56 | tmpAll = tmpAll.filter(display=True)
57 |
58 | if group != None:
59 | tmpAll = tmpAll.filter(group=group)
60 |
61 | return tmpAll
62 |
63 | @staticmethod
64 | def get(variable, group):
65 | return ClinicalVariable.all(group=group).get(variable=variable)
66 |
--------------------------------------------------------------------------------
/UI/src/js/reflux/PatientReflux.js:
--------------------------------------------------------------------------------
1 | import Reflux from 'reflux';
2 | import API from '../API.js';
3 | import History from '../components/globalComponents/History.js';
4 |
5 | const PatientActions = Reflux.createActions([
6 | 'load',
7 | 'loadPatient',
8 | 'loadDischargedPatients',
9 | 'addPatient'
10 | ]);
11 |
12 | class PatientStore extends Reflux.Store {
13 | constructor(props) {
14 | super(props);
15 | this.listenables = PatientActions;
16 | this.state = {
17 | patient: this.getPatientInitialState(),
18 | patientList: [],
19 | patientListKeyValue: [],
20 | loading: false,
21 | };
22 | }
23 |
24 | getPatientInitialState = () => {
25 | return {
26 | first_name: '',
27 | last_name: '',
28 | gender: undefined,
29 | birthdate: '',
30 | phone: '',
31 | email: '',
32 | status: undefined,
33 | fullgender: ''
34 | }
35 | };
36 |
37 | onLoad() {
38 | this.setState({loading: true});
39 | API.GET("patient")
40 | .then(res => {
41 | this.setState({
42 | patientList: res.data["results"],
43 | loading: false
44 | });
45 | })
46 | }
47 |
48 | onLoadDischargedPatients() {
49 | this.setState({loading: true});
50 | API.GET("patient", "listDischarged")
51 | .then(res => {
52 | let patientMap = res.data["results"].map(entry => {
53 | return {
54 | value: entry.id,
55 | label: entry.fullname
56 | }
57 | });
58 | this.setState({
59 | //patientList: res.data["results"],
60 | patientListKeyValue: patientMap,
61 | loading: false
62 | });
63 | })
64 | }
65 |
66 | onLoadPatient(id) {
67 | if (id !== undefined)
68 | API.GET("patient", id)
69 | .then(res => {
70 | this.setState({patient: res.data});
71 | });
72 | else
73 | this.setState({patient: this.getPatientInitialState()});
74 | }
75 |
76 | onAddPatient() {
77 | API.POST("patient", null, this.state.patient)
78 | .then(res => {
79 | History.push('/assignprotocol/' + res.data.id);
80 | });
81 | }
82 |
83 | }
84 |
85 | export {PatientStore, PatientActions};
--------------------------------------------------------------------------------
/Backend/protocol_element/api/serializers/PolymorphicSerializer.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from enum import Enum
5 |
6 | from rest_framework import serializers
7 |
8 | class PolymorphicSerializer(serializers.ModelSerializer):
9 | def get_serializer_map(self):
10 | """
11 | Return a dict to map class names to their respective serializer classes
12 |
13 | To be implemented by all PolymorphicSerializer subclasses
14 | """
15 | raise NotImplementedError
16 |
17 | def to_representation(self, obj):
18 | """
19 | Translate object to internal data representation
20 |
21 | Override to allow polymorphism
22 | """
23 | obj = obj.__class__.objects.get_subclass(id=obj.id)
24 | type_str = obj.__class__.__name__
25 |
26 | try:
27 | serializer = self.get_serializer_map()[type_str]
28 | except KeyError:
29 | raise ValueError('Serializer for "{}" does not exist'.format(type_str), )
30 |
31 | data = serializer(obj, context=self.context).to_representation(obj)
32 |
33 | #data['type'] = type_str
34 | return data
35 |
36 | # def to_internal_value(self, data):
37 | # """
38 | # Validate data and initialize primitive types
39 | #
40 | # Override to allow polymorphism
41 | # """
42 | # try:
43 | # type_str = data['type']
44 | # except KeyError:
45 | # raise serializers.ValidationError({
46 | # 'type': 'This field is required',
47 | # })
48 | #
49 | # try:
50 | # serializer = self.get_serializer_map()[type_str]
51 | # except KeyError:
52 | # raise serializers.ValidationError({
53 | # 'type': 'Serializer for "{}" does not exist'.format(type_str),
54 | # })
55 | #
56 | # validated_data = serializer(context=self.context).to_internal_value(data)
57 | # validated_data['type'] = type_str
58 | # return validated_data
59 | #
60 | # def create(self, validated_data):
61 | # """
62 | # Translate validated data representation to object
63 | #
64 | # Override to allow polymorphism
65 | # """
66 | # serializer = self.get_serializer_map()[validated_data['type']]
67 | # validated_data.pop('type')
68 | # return serializer(context=self.context).create(validated_data)
69 | #
70 | # def update(self, instance, validated_data):
71 | # serializer = self.get_serializer_map()[validated_data['type']]
72 | # validated_data.pop('type')
73 | # return serializer(context=self.context).update(instance, validated_data)
--------------------------------------------------------------------------------
/Backend/protocol_element/models/PEDecision.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.db import models
5 |
6 | from protocol_element.models import ProtocolElement, PENextElements
7 | from patients.models import ClinicalVariable
8 |
9 | import operator
10 |
11 | class PEDecision(ProtocolElement):
12 | clinicalVariable = models.ForeignKey(ClinicalVariable)
13 | condition = models.CharField(max_length=150)
14 | nextElement = models.ManyToManyField(PENextElements)
15 |
16 | operation = {
17 | "<": operator.lt,
18 | ">": operator.gt,
19 | "=": operator.eq
20 | }
21 |
22 | def run(self, inquiryData):
23 | cvData = inquiryData[self.clinicalVariable.variable]
24 | result = self.operation[self.condition[0]](cvData, self.condition[1:])
25 | nextElementOptions = self.nextElement.all()
26 | for nextElement in nextElementOptions:
27 | if nextElement.option == str(result):
28 | return nextElement.getNextElementId()
29 | return None
30 |
31 | @staticmethod
32 | def new(id, clinicalVariable, protocol, condition):
33 | cv = ClinicalVariable.objects.get(variable=clinicalVariable)
34 | decision = PEDecision.objects.create(clinicalVariable=cv, condition=condition, internalId=id, protocol=protocol)
35 | return decision.save()
36 |
37 | @staticmethod
38 | def addNextElements(id, protocol, nextElements):
39 | pe = ProtocolElement.get(type=ProtocolElement.DECISION, internalId=int(id), protocol=protocol)
40 | for option, id in nextElements.iteritems():
41 | nextElement = PENextElements.new(option=option, nextElementId=int(id), protocol=protocol)
42 | pe.nextElement.add(nextElement)
43 | pe.save()
44 |
45 | @staticmethod
46 | def dealWithOptions(conditionString, conditionType):
47 | nextElementOptions = {}
48 | #Condition with true or false output
49 | if(conditionType[0] in PEDecision.operation):
50 | conditions = conditionString.split(";")
51 | for condition in conditions:
52 | splitedCondition = condition.split(":")
53 | if splitedCondition[0] == 'True' or splitedCondition[0] == True:
54 | nextElementOptions[True] = splitedCondition[1]
55 | else:
56 | nextElementOptions[False] = splitedCondition[1]
57 | #elif switch todo
58 | return nextElementOptions
59 |
60 | @staticmethod
61 | def all():
62 | '''
63 | Returns all decision protocol elements
64 | '''
65 |
66 | tmpAll = PEDecision.objects.all()
67 |
68 | return tmpAll.order_by('internalId')
--------------------------------------------------------------------------------
/Backend/patients/api/views/PatientCVsViewSet.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from rest_framework import viewsets, filters
5 | from rest_framework.decorators import list_route
6 | from rest_framework.response import Response
7 |
8 | from django.db import transaction
9 | from django.utils import timezone
10 |
11 | from patients.api.serializers import CVPatientSerializer, CVGroupSerializer, PatientSerializer
12 |
13 | from patients.models import CVPatient, CVGroup, ClinicalVariable, Patient
14 |
15 | from history.models import History
16 |
17 | from itertools import groupby
18 |
19 | class PatientCVsViewSet(viewsets.ModelViewSet):
20 | queryset = Patient.all(active=True)
21 | serializer_class = PatientSerializer
22 |
23 | def retrieve(self, request, *args, **kwargs):
24 | patient = self.get_object()
25 | return self.buildResponse(patient)
26 |
27 | #Refactor this URGENT
28 | def buildResponse(self, patient):
29 | headers = CVGroup.all()
30 | headerSerialized = CVGroupSerializer(headers, many=True)
31 |
32 | results = []
33 | for group in headers:
34 | obj = {"group": group.title}
35 | cvs = CVPatient.all(patient=patient, group=group)
36 | content = []
37 | cvsSplitedByDate = [list(grp) for i, grp in
38 | groupby(sorted(cvs.values()), key=lambda item: item["measure_date"])]
39 |
40 | # These nested fors hurts my soul, but i don't know a better solution
41 | for cvsInThatDate in cvsSplitedByDate:
42 | cvToAddInResponse = {"measure_date": cvsInThatDate[0]["measure_date"].strftime("%Y-%m-%d %H:%M")}
43 | for cv in cvsInThatDate:
44 | cvName = ClinicalVariable.objects.get(id=cv["variable_id"]).variable
45 | cvToAddInResponse[cvName] = cv["value"]
46 | content += [cvToAddInResponse]
47 |
48 | obj["content"] = content
49 | results += [obj]
50 |
51 | return Response({
52 | "headers": headerSerialized.data,
53 | "results": results
54 | })
55 |
56 | @list_route(methods=['post'])
57 | @transaction.atomic
58 | def addVariables(self, request, *args, **kwargs):
59 | measure_date = timezone.now()
60 | group = CVGroup.objects.get(title=request.data["group"])
61 | patient = Patient.objects.get(id=request.data["patient"])
62 |
63 | for cv in request.data:
64 | if(cv != "group" and cv != "patient"):
65 | variable = cv
66 | value = request.data[cv]
67 | CVPatient.new(patient, group, variable, value, measure_date)
68 |
69 | return self.buildResponse(patient)
--------------------------------------------------------------------------------
/UI/src/js/components/patient/ClinicalVariables.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Reflux from 'reflux';
3 | import {PatientClinicalVariablesStore, PatientClinicalVariablesActions} from '../../reflux/PatientClinicalVariablesReflux.js';
4 | import CVRepresentationGroup from './CVRepresentationGroup.js';
5 |
6 | import Tabs, {TabPane} from 'rc-tabs';
7 | import TabContent from 'rc-tabs/lib/TabContent';
8 | import ScrollableInkTabBar from 'rc-tabs/lib/ScrollableInkTabBar';
9 |
10 | class ClinicalVariables extends Reflux.Component {
11 | constructor(props) {
12 | super(props);
13 | this.store = PatientClinicalVariablesStore;
14 | this.state = {
15 | patientID:this.props.patientID
16 | }
17 | }
18 |
19 | componentDidUpdate(prevProps, prevState) {
20 | if (prevProps.patientID !== this.props.patientID) {
21 | PatientClinicalVariablesActions.load(this.props.patientID);
22 | this.setState({patientID: this.props.patientID});
23 | }
24 | }
25 |
26 | buildDataComponents = () => {
27 | let listOfComponents = [];
28 | let receivedList = this.state.headers;
29 | receivedList.sort(function (a, b) {
30 | return a.index_representation - b.index_representation;
31 | });
32 |
33 | for (let index = 0; index < receivedList.length; index++) {
34 | let content = this.state.data.filter(function (obj) {
35 | return obj.group === receivedList[index]["title"];
36 | });
37 | listOfComponents.push(
38 |
43 | );
44 | }
45 |
46 | return listOfComponents;
47 | };
48 |
49 | componentDidMount() {
50 | PatientClinicalVariablesActions.load(this.state.patientID);
51 | }
52 |
53 | render() {
54 | let listOfComponents = this.buildDataComponents();
55 |
56 | return (
57 |
58 | }
61 | renderTabContent={() => }
62 | >
63 | {listOfComponents}
64 |
65 |
66 |
67 | );
68 | }
69 | }
70 |
71 | export default ClinicalVariables;
72 |
--------------------------------------------------------------------------------
/UI/src/js/reflux/UserReflux.js:
--------------------------------------------------------------------------------
1 | import Reflux from 'reflux';
2 | import API from '../API.js';
3 | import History from '../components/globalComponents/History.js';
4 |
5 | const UserActions = Reflux.createActions([
6 | 'login',
7 | 'logout',
8 | 'loginSuccess',
9 | 'loginFailed',
10 | 'getUserData',
11 | 'updateUserData'
12 | ]);
13 |
14 | class UserStore extends Reflux.Store {
15 | constructor() {
16 | super();
17 | this.listenables = UserActions;
18 | this.state = {
19 | authenticated: false,
20 | failed: false,
21 | user: undefined
22 | };
23 | }
24 |
25 | onLogin(user, password, remember) {
26 | API.POST("account", "login", {
27 | "username": user,
28 | "password": password,
29 | "remember": remember
30 | }).then(res => {
31 | UserActions.loginSuccess(res.data, res.data["authenticated"]);
32 | })
33 | }
34 |
35 | onGetUserData() {
36 | API.GET("account", "personalAccountDetails")
37 | .then(res => {
38 | this.setState({
39 | authenticated: res.data["authenticated"],
40 | user: res.data
41 | });
42 | this.trigger();
43 | })
44 | }
45 |
46 | onUpdateUserData() {
47 | let userData = {
48 | "first_name": this.state.user.first_name,
49 | "last_name": this.state.user.last_name,
50 | };
51 |
52 | if(this.state.user.password !== undefined)
53 | userData["password"] = this.state.user.password;
54 |
55 | API.PATCH("account", "personalAccountDetails", userData).then(res => {
56 | this.setState({
57 | authenticated: res.data["authenticated"],
58 | user: res.data
59 | });
60 | History.push('/');
61 | })
62 | }
63 |
64 | onLogout() {
65 | API.GET("account", "logout")
66 | .then(res => {
67 | this.setState({authenticated: res.data["authenticated"]});
68 | History.push('/');
69 | window.location.reload();
70 | })
71 | }
72 |
73 | onLoginSuccess(data, authenticated) {
74 | if (authenticated === false) {
75 | UserActions.loginFailed();
76 | } else {
77 | this.setState({
78 | authenticated: authenticated,
79 | failed: !authenticated,
80 | user: data
81 | });
82 | History.push('/admittedpatients');
83 | }
84 | this.trigger();
85 | }
86 |
87 | onLoginFailed() {
88 | this.setState({failed: true});
89 | this.trigger();
90 | }
91 | }
92 |
93 | export {UserStore, UserActions};
--------------------------------------------------------------------------------
/Backend/patients/api/views/AdmissionViewSet.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from rest_framework import viewsets, filters
5 | from rest_framework.decorators import detail_route, list_route
6 | from rest_framework.response import Response
7 |
8 | from rest_framework.filters import OrderingFilter
9 | from django_filters.rest_framework import DjangoFilterBackend
10 | from django.db import transaction
11 | from django.utils import timezone
12 |
13 | from patients.api.serializers import AdmissionSerializer
14 | from patients.models import Admission, Patient
15 |
16 | from accounts.models import Profile
17 |
18 | from protocol.models import ExecutedProtocol, Protocol, Schedule
19 |
20 | from history.models import History
21 |
22 | import dateutil.parser
23 |
24 | class AdmissionViewSet(viewsets.ModelViewSet):
25 | queryset = Admission.all()
26 | serializer_class = AdmissionSerializer
27 |
28 | filter_backends = [DjangoFilterBackend, OrderingFilter]
29 | filter_fields = ["physician", "patient", "start_date"]
30 |
31 | def list(self, request, *args, **kwargs):
32 | '''
33 | Return a list of patients admited in the hospital and all these informations
34 | '''
35 | self.queryset = Admission.all(active=True)
36 | return super(AdmissionViewSet, self).list(request, *args, **kwargs)
37 |
38 | @list_route(methods=['post'])
39 | @transaction.atomic
40 | def new(self, request, *args, **kwargs):
41 | '''
42 | Admission of a patient registed in the system and all the assigned protocols.
43 | '''
44 | #Create admission
45 | patient = Patient.objects.get(id=request.data.get('patientID'))
46 | physician = Profile.objects.get(user=request.user)
47 | Admission.new(patient=patient,
48 | physician=physician,
49 | room=request.data.get('room'))
50 | #Assign protocols
51 | selectedProtocols = request.data.get('seletedProtocols') #For now it is only one
52 | for selectedProtocol in selectedProtocols:
53 | protocol = Protocol.objects.get(id=selectedProtocol.get("id"))
54 | ExecutedProtocol.new(protocol=protocol, patient=patient, physician=physician)
55 |
56 | self.queryset = Admission.all(active=True)
57 | return super(AdmissionViewSet, self).list(request, *args, **kwargs)
58 |
59 | @list_route(methods=['post'])
60 | @transaction.atomic
61 | def discharge(self, request, *args, **kwargs):
62 | patientID = request.data.get('patientID', None)
63 |
64 | if patientID != None:
65 | patient = Patient.objects.get(id=patientID)
66 | Admission.dischargePatient(patient)
67 |
68 | return Response({
69 | 'success': True
70 | })
71 |
72 | return Response({
73 | 'error': "The patient was not found"
74 | })
--------------------------------------------------------------------------------
/UI/src/js/App.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react';
2 | import Reflux from 'reflux';
3 | import Header from './components/globalComponents/Header.js';
4 | import Footer from './components/globalComponents/Footer.js';
5 | import Routes from './components/globalComponents/Routes.js';
6 | import {Router} from "react-router-dom";
7 | import {UserStore, UserActions} from './reflux/UserReflux.js';
8 | import {StateStore} from './reflux/StateReflux.js';
9 | import History from './components/globalComponents/History.js';
10 | import Modal from 'react-awesome-modal';
11 | import API from './API.js';
12 |
13 | class LoadingBar extends Component {
14 | render() {
15 | return (
16 |
17 |
18 |
Loading, please wait...
19 | );
20 | }
21 | }
22 |
23 | class App extends Reflux.Component {
24 | constructor(props) {
25 | super(props);
26 | this.stores = [StateStore, UserStore];
27 | }
28 |
29 | componentDidMount() {
30 | UserActions.getUserData();
31 | this.setAppTitle();
32 | }
33 |
34 | setAppTitle = () => {
35 | API.GET("settings")
36 | .then(res => {
37 | if(res.data["title"] !== "")
38 | document.title = res.data["title"];
39 | });
40 | };
41 |
42 | closeModal = () => {/*To remove the warning*/};
43 |
44 | render() {
45 | if (this.state.loading && this.state.user === undefined)
46 | return ( );
47 |
48 | return (
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
64 |
65 | {this.state.modalHeader === undefined ? '' : this.state.modalHeader}
66 |
67 |
68 | {this.state.modalContent === undefined ? '' : this.state.modalContent}
69 |
70 |
71 | {this.state.modalFooter === undefined ? '' : this.state.modalFooter}
72 |
73 |
74 |
75 |
76 |
77 | );
78 | }
79 | }
80 |
81 | export default App;
82 |
--------------------------------------------------------------------------------
/config/run_docker.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | echo "------------------------------------------"
4 | echo "-------------- Check DB UP ---------------"
5 | echo "------------------------------------------"
6 |
7 | check_up() {
8 | service=$1
9 | host=$2
10 | port=$3
11 |
12 | max=13 # 1 minute
13 |
14 | counter=1
15 | while true;do
16 | python -c "import socket;s = socket.socket(socket.AF_INET, socket.SOCK_STREAM);s.connect(('$host', $port))" \
17 | >/dev/null 2>/dev/null && break || \
18 | echo "Waiting that $service on $host:${port} is started (sleeping for 5) on counter ${counter}"
19 |
20 | if [ $counter = $max ]; then
21 | echo "Could not connect to ${service} after some time"
22 | echo "Investigate locally the logs with fig logs"
23 | exit 1
24 | fi
25 |
26 | sleep 5
27 |
28 | counter=$(expr "$counter" + "1")
29 | done
30 | }
31 |
32 | check_up "postgres" db 5432
33 |
34 | echo "------------------------------------------"
35 | echo "------------- Backend Deploy -------------"
36 | echo "------------------------------------------"
37 | cd /GenericCDSS
38 |
39 | if [ ${DEPLOY_MODE} = "demo" ]; then
40 | make defaultDemo
41 | else
42 | make setUpSystem
43 | fi
44 |
45 | cd /GenericCDSS/Backend
46 |
47 | python manage.py collectstatic --noinput
48 |
49 | exec gunicorn genericcdss.wsgi:application --bind 0.0.0.0:8000 --workers 3 &
50 |
51 | echo "------------------------------------------"
52 | echo "------------- Frontend Deploy ------------"
53 | echo "------------------------------------------"
54 | cd /GenericCDSS/UI
55 |
56 | echo "Defing api url..."
57 | apiURL=$(echo $API_URL)
58 | if [ -z "$apiURL" ]
59 | then
60 | echo "API_URL not defined"
61 | else
62 | echo "Change API URL in package"
63 | jq -c 'del(.api_url)' package.json > tmp.json && mv tmp.json package.json
64 |
65 | jq -c '. + { "api_url": "'$apiURL'" }' package.json > tmp.json && mv tmp.json package.json
66 | fi
67 |
68 | echo "Defining homepage url..."
69 | homepage=$(echo $HOMEPAGE)
70 | if [ -z "$homepage" ]
71 | then
72 | echo "Homepage url not defined"
73 | else
74 | echo "Change homepage in package"
75 | jq -c 'del(.homepage)' package.json > tmp.json && mv tmp.json package.json
76 | jq -c '. + { "homepage": "'$homepage'" }' package.json > tmp.json && mv tmp.json package.json
77 | fi
78 |
79 | echo "Defining baseurl..."
80 | base_url=$(echo $BASE_URL)
81 | if [ -z "$base_url" ]
82 | then
83 | echo "Homepage url not defined"
84 | else
85 | echo "Change homepage in package"
86 | jq -c 'del(.baseurl)' package.json > tmp.json && mv tmp.json package.json
87 | jq -c '. + { "base_url": "'$base_url'" }' package.json > tmp.json && mv tmp.json package.json
88 | fi
89 |
90 | echo "Defining version..."
91 | version=$(echo $VERSION)
92 | if [ -z "$version" ]
93 | then
94 | echo "Version not defined"
95 | else
96 | echo "Change version in package"
97 | jq -c 'del(.version)' package.json > tmp.json && mv tmp.json package.json
98 | jq -c '. + { "version": "'$version'" }' package.json > tmp.json && mv tmp.json package.json
99 | fi
100 |
101 | npm run build
102 |
103 | tail -f /dev/null
104 |
--------------------------------------------------------------------------------
/UI/src/js/components/protocol/Protocols.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Reflux from 'reflux';
3 | import PropTypes from 'prop-types';
4 | import ReactTable from 'react-table'
5 | import "react-table/react-table.css";
6 | import {Link} from "react-router-dom";
7 | import {ProtocolStore, ProtocolActions} from '../../reflux/ProtocolReflux.js';
8 | import Settings from '../../GlobalSettings.js';
9 |
10 | class Protocols extends Reflux.Component {
11 | constructor(props) {
12 | super(props);
13 | this.store = ProtocolStore;
14 | }
15 |
16 | componentDidMount() {
17 | ProtocolActions.load();
18 | }
19 |
20 | render() {
21 | let columns = [];
22 | if (this.props.selectColumn === true)
23 | columns.push({
24 | Header: () => ,
25 | id: "selection",
26 | maxWidth: 33,
27 | filterable: false,
28 | accessor: obj => obj.id,
29 | Cell: props =>
30 |
31 |
32 | });
33 |
34 | columns.push({
35 | Header: () => Title ,
36 | id: "title",
37 | accessor: obj => obj.title,
38 | Cell: props => {props.value}
39 | });
40 | columns.push({
41 | Header: () => Description ,
42 | id: "description",
43 | accessor: obj => obj.description,
44 | Cell: props => {props.value}
45 | });
46 |
47 | return (
48 |
49 |
50 |
51 |
52 |
Protocols
53 |
54 | Insert new protocol
55 |
56 |
57 |
64 |
65 |
66 |
67 |
68 | );
69 | }
70 |
71 | static propTypes = {
72 | /**
73 | * Number of row in the table
74 | * */
75 | rows: PropTypes.number
76 | };
77 | }
78 |
79 |
80 | Protocols.defaultProps = {
81 | rows: Settings.getPatientTableRows()
82 | };
83 |
84 | export default Protocols;
85 |
--------------------------------------------------------------------------------
/UI/src/js/components/buttons/PatientButtonBar.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react';
2 | import {PatientActions} from '../../reflux/PatientReflux.js';
3 | import {AdmissionActions} from '../../reflux/AdmissionReflux.js';
4 | import History from '../globalComponents/History.js';
5 | import PatientStatus from '../patient/PatientStatus.js';
6 | import ButtonWithMsg from '../reusable/ButtonWithMsg.js';
7 |
8 | class PatientButtonBar extends Component {
9 | addPatient = () => {
10 | if(this.props.patientIsValid())
11 | PatientActions.addPatient();
12 | };
13 |
14 | admitPatient = () => {
15 | History.push('/assignprotocol/' + this.props.patient.id);
16 | };
17 |
18 | dischargePatient = () => {
19 | AdmissionActions.dischargePatient(this.props.patient.id);
20 | };
21 |
22 | render() {
23 | let patientStatus = this.props.patient.status;
24 |
25 | switch (this.props.mode){
26 | case "show":
27 | if(patientStatus === PatientStatus.DISCHARGED)
28 | return(
29 |
30 |
31 |
32 | Admit
33 |
34 |
35 | );
36 | if(patientStatus === PatientStatus.ADMITTED)
37 | return(
38 |
39 |
48 |
49 | );
50 | break;
51 |
52 | case "add":
53 | return(
54 |
55 |
56 |
57 | Add
58 |
59 |
60 | );
61 | //break;
62 |
63 | case "edit":
64 | return(
65 | TO DO
66 |
67 | );
68 | //break;
69 | case "admitting": return(
);
70 |
71 | default: return(
);
72 | }
73 | return(
);
74 | }
75 | }
76 |
77 | export default PatientButtonBar;
78 |
--------------------------------------------------------------------------------
/UI/src/js/components/patient/AllPatients.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Reflux from 'reflux';
3 | import ReactTable from 'react-table'
4 | import "react-table/react-table.css";
5 | import {Link} from "react-router-dom";
6 | import {PatientStore, PatientActions} from '../../reflux/PatientReflux.js';
7 | import Settings from '../../GlobalSettings.js';
8 | import PatientStatus from './PatientStatus.js';
9 |
10 | class AllPatients extends Reflux.Component {
11 | constructor(props) {
12 | super(props);
13 | this.store = PatientStore;
14 | }
15 |
16 | componentDidMount() {
17 | PatientActions.load();
18 | }
19 |
20 | render() {
21 | const columns = [{
22 | Header: () => ,
23 | id: "gender",
24 | maxWidth: 33,
25 | filterable: false,
26 | accessor: obj => obj.gender,
27 | Cell: props => props.value === "M" ? :
28 | },{
29 | Header: () => Name ,
30 | id: "fullname",
31 | accessor: obj => obj.fullname,
32 | Cell: props => {props.value}
33 | },{
34 | Header:() => Condition ,
35 | id: "status",
36 | accessor: obj => obj.status,
37 | Cell: props => {PatientStatus.toString(props.value)}
38 | },{
39 | Header:() => Contact ,
40 | id: "contacto",
41 | accessor: obj => obj.phone,
42 | Cell: props => {props.value}
43 | },{
44 | Header: () => Email ,
45 | id: "email",
46 | accessor: obj => obj.email,
47 | Cell: props => {props.value}
48 | }];
49 |
50 |
51 | return (
52 |
53 |
54 |
55 |
56 |
Patients
57 |
58 |
59 | Insert new patient
60 |
61 |
62 |
73 |
74 |
75 |
76 |
77 | );
78 | }
79 | }
80 |
81 | export default AllPatients;
82 |
--------------------------------------------------------------------------------
/UI/src/js/components/globalComponents/Routes.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react';
2 | import {Route, Switch, Redirect} from "react-router-dom";
3 |
4 | import Home from '../dynamicPages/Home.js';
5 | import Help from '../dynamicPages/Help.js';
6 | import About from '../dynamicPages/About.js';
7 |
8 | import AdmittedPatients from '../patient/AdmittedPatients.js';
9 | import AllPatients from '../patient/AllPatients.js';
10 | import ShowPatient from '../patient/ShowPatient.js';
11 | import AddPatient from '../patient/AddPatient.js';
12 |
13 | import Protocols from '../protocol/Protocols.js';
14 | import AddProtocol from '../protocol/CRUDProtocol.js';
15 | import ShowProtocol from '../protocol/CRUDProtocol.js';
16 | import AssignProtocolToPatient from '../protocol/AssignProtocolToPatient.js';
17 |
18 | import Register from '../accountManager/Register.js';
19 | import Profile from '../accountManager/Profile.js';
20 | import ForgotPassword from '../accountManager/ForgotPass.js';
21 |
22 | import http404 from '../errorPages/http404.js';
23 | import http500 from '../errorPages/http500.js';
24 | import http0 from '../errorPages/http0.js';
25 |
26 |
27 |
28 | const PrivateRoute = ({component: Component, ...rest}) => (
29 | (
30 | rest.authenticated ? (
31 |
32 | ) : (
33 |
37 | )
38 | )}/>
39 | );
40 |
41 | class Routes extends Component {
42 | render() {
43 | if (!this.props.user)
44 | return ( );
45 |
46 | let authenticated = this.props.user.authenticated;
47 | return (
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 | export default Routes;
--------------------------------------------------------------------------------
/Backend/accounts/api/serializers/UserSerializer.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.contrib.auth.models import User
5 | from django.db import transaction
6 | from django.contrib.auth import login
7 |
8 | from rest_framework import serializers
9 | from rest_framework import permissions
10 |
11 | #from oauth2_provider.ext.rest_framework import TokenHasScope
12 |
13 | from accounts.models import Profile
14 | from accounts.api.serializers import ProfileSerializer
15 |
16 | class UserSerializer(serializers.ModelSerializer):
17 | fullname = serializers.SerializerMethodField(required=False)
18 | last_login = serializers.SerializerMethodField(required=False)
19 | profile = ProfileSerializer()
20 |
21 | class Meta:
22 | permission_classes = [permissions.IsAuthenticated, permissions.IsAdminUser]#, TokenHasScope]
23 | model = User
24 | fields = ('username', 'first_name', 'last_name', 'fullname', 'email', 'last_login', 'is_staff', 'id', 'profile')
25 | read_only_fields = ('id', 'fullname', 'last_login', 'is_staff')
26 |
27 | def get_fullname(self, obj):
28 | full_name = obj.get_full_name()
29 |
30 | if full_name == "":
31 | return obj.email
32 | return full_name
33 |
34 | def get_last_login(self, obj):
35 | if isinstance(obj.last_login, basestring):
36 | return obj.last_login
37 | elif obj.last_login:
38 | return obj.last_login.strftime("%Y-%m-%d %H:%M")
39 | return None
40 |
41 | @transaction.atomic
42 | def create(self, validated_data):
43 | '''
44 | This handles the custom user creation, serializating validated data from the web services input
45 | into the proper object, plus also inserting profile information, all in the same serialization.
46 | '''
47 | profile_data = None
48 | validated_data['is_active'] = False
49 |
50 | try:
51 | profile_data = validated_data.pop('profile')
52 | except KeyError:
53 | pass
54 |
55 | user = User.objects.create(**validated_data)
56 |
57 | # create profile data
58 | if profile_data:
59 | try:
60 | profile_instance = user.profile
61 | serializer = ProfileSerializer(profile_instance, partial=True)
62 | serializer.update(profile_instance, profile_data)
63 | except Profile.DoesNotExist:
64 | Profile.objects.create(user=user, **profile_data)
65 |
66 | return user
67 |
68 | @transaction.atomic
69 | def update(self, instance, validated_data):
70 | '''
71 | This handles the custom user update, serializating validated data from the web services input
72 | into the proper object, plus also updating profile information, all in the same serialization.
73 | '''
74 | profile_data = None
75 |
76 | try:
77 | profile_data = validated_data.pop('profile')
78 | except KeyError:
79 | pass
80 |
81 | if profile_data:
82 | p_instance = instance.profile
83 | serializer = ProfileSerializer(p_instance, partial=True)
84 | serializer.update(p_instance, profile_data)
85 |
86 | for attr, value in validated_data.items():
87 | setattr(instance, attr, value)
88 |
89 | instance.save()
90 |
91 | return instance
--------------------------------------------------------------------------------
/Backend/utils/management/commands/populate_flatpages.py:
--------------------------------------------------------------------------------
1 | # coding=utf-8
2 | from django.core.management.base import BaseCommand
3 | from django.contrib.flatpages.models import FlatPage
4 | from django.contrib.sites.models import Site
5 |
6 | class Command(BaseCommand):
7 | help = 'This command will populate the db with random data to create a demo installation'
8 |
9 | def add_arguments(self, parser):
10 | parser.add_argument(
11 | '--force',
12 | action='store_true',
13 | dest='force',
14 | help='Force the deletion and the creation of the flat pages',
15 | )
16 |
17 | def handle(self, *args, **options):
18 | siteDomain = "AutoPages"
19 | if options['force']:
20 | self.stdout.write("\nCleaning the old auto flat pages!\n\n")
21 | self.remove_FlatPages(siteDomain)
22 | self.stdout.write("\nCreating new auto flat pages!\n\n")
23 | self.create_FlatPages(siteDomain)
24 | else:
25 | try:
26 | Site.objects.get(domain=siteDomain)
27 | self.stdout.write("\nERROR:The flat pages are already populated!\n\n")
28 | except:
29 | self.create_FlatPages(siteDomain)
30 |
31 | def remove_FlatPages(self, siteDomain):
32 | try:
33 | site = Site.objects.get(domain=siteDomain)
34 | FlatPage.objects.filter(sites=site).delete()
35 | except:
36 | self.stdout.write("\nThe auto flat pages do not exist in the system!\n\n")
37 |
38 |
39 | def create_FlatPages(self, siteDomain):
40 | try:
41 | site = Site.objects.get(domain=siteDomain)
42 | except:
43 | site = Site.objects.create(domain=siteDomain,
44 | name=siteDomain)
45 | site.save()
46 |
47 | FlatPage.objects.create(url="/home/",
48 | title="Home",
49 | content=' ').sites.add(site)
50 | FlatPage.objects.create(url="/about/",
51 | title="About",
52 | content='About \
53 | \
54 | This system is a web-based application, which provides the main dashboard where professionals (e.g, practitioners, nurses) can follow all the patients that are under their responsibility and some details about the state of each one.\
55 |
\
56 | Available features \
57 | \
58 | Manage all the patient information dynamically \
59 | Create and manage clinical protocols \
60 | Assign protocols to the patients and execute them \
61 | Easly costumize the patient information \
62 | Keep track of all the patient data \
63 | Be reminder about the next measurement for each patient admitted in the system \
64 | ').sites.add(site)
65 | FlatPage.objects.create(url="/help/",
66 | title="Help",
67 | content="TO DO").sites.add(site)
68 |
69 | self.stdout.write("Success: The flat pages populated with success!\n")
--------------------------------------------------------------------------------
/UI/src/js/components/protocolElements/ActionElement.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import Reflux from 'reflux';
4 | import DisplayField from '../reusable/DisplayField.js';
5 |
6 | class ActionElement extends Reflux.Component {
7 | constructor(props) {
8 | super(props);
9 | this.state = {
10 | nextElementId: "",//(this.props.elementID + 1).toString(),
11 | action: ""
12 | };
13 | }
14 |
15 | componentDidMount() {
16 | this.loadingDetails();
17 | }
18 |
19 | loadingDetails = () => {
20 | if(this.props.mode === "edit"){
21 | this.props.addElementConfigurations("action", this.props.elementData.action);
22 | this.props.addElementConfigurations("nextElement", this.props.elementData.nextElement);
23 | this.setState({
24 | action: this.props.elementData.action,
25 | nextElementId: this.props.elementData.nextElement
26 | })
27 | }
28 | };
29 |
30 | isValid = () => {
31 | this.setState({validated: true});
32 | return (this.state.action !== "" && (this.state.nextElementId === "" || this.state.nextElementId > this.props.elementID));
33 | };
34 |
35 | actionHandleChange = (event) => {
36 | event.preventDefault();
37 | this.props.addElementConfigurations("action", event.target.value);
38 | this.setState({action: event.target.value});
39 | };
40 |
41 | nextElementIdHandleChange = (event) => {
42 | event.preventDefault();
43 | this.props.addElementConfigurations("nextElement", event.target.value);
44 | this.setState({nextElementId: event.target.value});
45 | };
46 |
47 | render() {
48 | return (
49 |
50 |
56 |
64 |
65 | );
66 | }
67 |
68 | static propTypes = {
69 | /**
70 | * Next element id
71 | * */
72 | nextElementId: PropTypes.number,
73 | /**
74 | * Send the protocol configurations to the parent
75 | *
76 | * @param key
77 | * @param value
78 | * */
79 | addElementConfigurations: PropTypes.func,
80 | /**
81 | * Object with the element data (important in the edition mode)
82 | * */
83 | elementData: PropTypes.object
84 | };
85 | }
86 |
87 | ActionElement.defaultProps = {
88 | elementID: 1
89 | };
90 |
91 | export default ActionElement;
--------------------------------------------------------------------------------
/Backend/patients/models/Admission.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.db import models
5 | from django.utils import timezone
6 |
7 | from accounts.models import Profile
8 |
9 | from patients.models import Patient
10 |
11 | from protocol.models import AssignedProtocol, ExecutedProtocol
12 |
13 | class Admission(models.Model):
14 | patient = models.ForeignKey(Patient)
15 | physician = models.ForeignKey(Profile, limit_choices_to={'role': Profile.PHYSICIAN})
16 | room = models.CharField(max_length=10, blank=True)
17 | start_date = models.DateTimeField(auto_now_add=True)
18 | end_date = models.DateTimeField(null=True, blank=True)
19 |
20 | def __unicode__(self):
21 | return u"Admission %s - %s" % (self.patient, self.room)
22 |
23 | def discharge(self):
24 | '''
25 | Insert the admission finished date of the patient that was discharged from the hospital
26 | '''
27 | self.patient.discharge()
28 | self.end_date = timezone.now()
29 | self.save()
30 | ExecutedProtocol.cancelAllAssigned(patient=self.patient)
31 |
32 | def getLastProtocolAssignedMeasure(self):
33 | '''
34 | Retrieves when was made the last protocol measurement
35 | :return: datetime in string format
36 | '''
37 | lastProtocolExecution = ExecutedProtocol.getLastExecution(patient=self.patient, admissionDate=self.start_date)
38 | if(lastProtocolExecution):
39 | return lastProtocolExecution.execution_time.strftime("%Y-%m-%d %H:%M")
40 | return ""
41 |
42 | def getLastProtocolAssignedMeasurePhysician(self):
43 | '''
44 | Retrieves who made the last protocol measurement
45 | :return: datetime in string format
46 | '''
47 | lastProtocolExecution = ExecutedProtocol.getLastExecution(patient=self.patient, admissionDate=self.start_date)
48 | if(lastProtocolExecution):
49 | return lastProtocolExecution.physician
50 | return ""
51 |
52 | def getNextProtocolAssignedMeasure(self):
53 | '''
54 | It returns when the patient information should be measured
55 | :return: tuple (datetime, schedule title)
56 | '''
57 | nextExecution = ExecutedProtocol.getNextExecution(patient=self.patient)
58 | return (nextExecution.schedule_time.strftime("%Y-%m-%d %H:%M"), nextExecution.schedule.title)
59 |
60 | @staticmethod
61 | def new(patient, physician, room):
62 | admission = Admission.objects.create(patient=patient,
63 | physician=physician,
64 | room=room)
65 | patient.admit()
66 | # History to do
67 | admission.save()
68 |
69 | @staticmethod
70 | def all(active=None):
71 | '''
72 | Returns all admission instances
73 | '''
74 | tmpAll = Admission.objects.all()
75 |
76 | if active == True:
77 | tmpAll = tmpAll.filter(end_date__isnull=True)
78 |
79 | return tmpAll.order_by('start_date')
80 |
81 | @staticmethod
82 | def dischargePatient(patient):
83 | admission = Admission.getLatestAdmission(patient)
84 | admission.discharge()
85 |
86 | @staticmethod
87 | def getLatestAdmission(patient):
88 | listOfActiveAdmissionsFromPatient = Admission.all(active=True).filter(patient=patient)
89 | #this should be one (TO DO something to ensure that in the future)
90 | return listOfActiveAdmissionsFromPatient[0]
--------------------------------------------------------------------------------
/UI/src/js/components/protocol/SelectedProtocols.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react';
2 | import ReactTable from 'react-table'
3 | import "react-table/react-table.css";
4 | import {Link} from "react-router-dom";
5 | import Settings from '../../GlobalSettings.js';
6 | import $ from 'jquery';
7 |
8 | class SelectedProtocols extends Component {
9 | constructor(props) {
10 | super(props);
11 | this.state = {
12 | selectedProtocols: this.props.selectedProtocols
13 | }
14 | }
15 |
16 | componentDidUpdate(prevProps, prevState) {
17 | if (prevProps.selectedProtocols.length !== this.props.selectedProtocols.length) {
18 | this.setState({selectedProtocols: this.props.selectedProtocols});
19 | }
20 | }
21 |
22 | removeSelectedProtocol = (state, rowInfo, column, instance) => {
23 | return {
24 | onClick: (e, handleOriginal) => {
25 | let temporarySelectedProtocols = this.state.selectedProtocols;
26 | temporarySelectedProtocols.splice(rowInfo.index, 1)
27 | this.setState({selectedProtocols: temporarySelectedProtocols});
28 | }
29 | };
30 | };
31 |
32 |
33 | render() {
34 | const columns = [{
35 | Header: () => ,
36 | id: "selection",
37 | maxWidth: 33,
38 | filterable: false,
39 | accessor: obj => obj.id,
40 | Cell: props =>
41 |
42 | }, {
43 | Header: () => Title ,
44 | id: "title",
45 | accessor: obj => obj.title,
46 | Cell: props => {props.value}
47 | }, {
48 | Header: () => Start ,
49 | id: "start_date",
50 | accessor: obj => obj.start_date,
51 | Cell: props => {props.value}
52 | }, {
53 | Header: () => End ,
54 | id: "end_date",
55 | accessor: obj => obj.end_date,
56 | Cell: props => {props.value}
57 | }, {
58 | Header: () => Schedule ,
59 | id: "schedule",
60 | accessor: obj => obj.schedule,
61 | Cell: props => {props.value}
62 | }];
63 |
64 | return (
65 |
66 |
67 |
68 |
69 |
Selected protocols
70 |
71 |
72 |
79 |
80 |
81 |
82 |
83 | );
84 | }
85 | }
86 |
87 | export default SelectedProtocols;
--------------------------------------------------------------------------------
/UI/src/js/components/patient/AdmittedPatients.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Reflux from 'reflux';
3 | import ReactTable from 'react-table'
4 | import "react-table/react-table.css";
5 | import {Link} from "react-router-dom";
6 | import {AdmissionStore, AdmissionActions} from '../../reflux/AdmissionReflux.js';
7 | import {ProtocolStore} from '../../reflux/ProtocolReflux.js';
8 | import Settings from '../../GlobalSettings.js';
9 | import RunProtocolButton from '../buttons/RunProtocolButton.js';
10 |
11 | class AdmittedPatients extends Reflux.Component {
12 | constructor(props) {
13 | super(props);
14 | this.stores = [AdmissionStore, ProtocolStore];
15 | this.state = {
16 | };
17 | }
18 |
19 | componentDidMount() {
20 | AdmissionActions.load();
21 | }
22 |
23 | render() {
24 | let i = 0;
25 | const columns = [{
26 | Header: () => ,
27 | id: "gender",
28 | maxWidth: 33,
29 | filterable: false,
30 | accessor: obj => obj.patient.gender,
31 | Cell: props => props.value === "M" ? :
32 | },{
33 | Header: () => Name ,
34 | id: "fullname",
35 | accessor: obj => obj.patient.fullname,
36 | Cell: props => {props.value}
37 | }, {
38 | Header: () => Room ,
39 | id: "room",
40 | accessor: obj => obj.room,
41 | Cell: props => {props.value}
42 | }, {
43 | Header: () => Last Measurement ,
44 | id: "last_measure",
45 | accessor: obj => obj.last_measure,
46 | Cell: props => {props.value}
47 | }, {
48 | Header: () => Next Measurement ,
49 | id: "next_measure",
50 | accessor: obj => obj.next_measure,
51 | width: 250,
52 | Cell: props => {props.value}
53 | }, {
54 | Header: () => Physician ,
55 | id: "doctor",
56 | accessor: obj => obj.last_measure_physician,
57 | Cell: props => {props.value}
58 | }, {
59 | Header: () => ,
60 | id: "actions",
61 | filterable: false,
62 | accessor: obj => obj.patient.id,
63 | Cell: props =>
64 | }];
65 |
66 | return (
67 |
68 |
69 |
70 |
71 |
Admitted Patients
72 |
73 |
74 | Insert new patient
75 |
76 |
77 |
84 |
85 |
86 |
87 |
88 |
89 | );
90 | }
91 | }
92 |
93 | export default AdmittedPatients;
94 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # GenericCDSS - Generic Clinical Decision Support System
2 |
3 |
4 | [](https://github.com/bioinformatics-ua/GenericCDSS/tree/master)
5 |
6 | GenericCDSS is a web-based application, which provides the main dashboard where professionals (e.g., practitioners, nurses) can follow all the patients that are under their responsibility and some details about the state of each one.
7 |
8 | # New Features!
9 |
10 | - Manage all the patient information dynamically
11 | - Create and manage clinical protocols
12 | - Assign protocols to the patients and execute them
13 |
14 | You can also:
15 | - Easily customise the patient information
16 | - Keep track of all the patient data
17 | - Be reminder about the next measurement for each patient admitted in the system
18 |
19 | GenericCDSS follows a Client-Server model, in which each side is sub-divided in several layers.
20 |
21 | The Client-side encapsulate most of the presentation part of the system. It is divided into two layers, the presentation, and the controller layer. The presentation layer is responsible for the user interfaces. The controller layer consumes the backend web services and provides the data to the presentation layer.
22 |
23 | The Server, which is mainly the backend core, is subdivided into three sub-layers: 1) business; 2) persistence; and 3) service provider. The persistence layer is responsible for storing and maintaining the system’s data. The business layer contains most of the application’s logic. Finally, the service layer provides a RESTful API with services prepared to interact with all the system’s functions with or without the client. This layer will be used by the client to access all the core features.
24 |
25 | ### Tech
26 |
27 | GenericCDSS uses a number of open source projects to work properly:
28 |
29 |
30 | * [ReactJS] - HTML enhanced for web apps!
31 | * [NPM] - The frontend package manager
32 | * [Django] - Web framework python-based
33 | * [Django Rest Framework] - Toolkit for building Web APIs in Django projects
34 | * [PostgreSQL] - The object-relational database management system
35 | * [Docker] - The computer program that performs operating-system-level virtualization
36 | * [Make] - Utility for building and maintaining groups of programs
37 |
38 |
39 | ### Installation
40 |
41 | GenericCDSS requires Docker, Docker-compose and Make to run.
42 |
43 | Install Docker
44 |
45 |
46 | * Full instructions here https://docs.docker.com/install/
47 |
48 |
49 | Install docker-compose
50 |
51 |
52 | * Full instructions here https://docs.docker.com/compose/install/
53 |
54 |
55 | Edit docker-compose.yml with deploy specific details. The variables that should be configured are the following:
56 |
57 | ```sh
58 | 4 - POSTGRES_USER= user used in the PostgreSQL. This user should match with the user used in row 23
59 | 5 - POSTGRES_PASS= password used in the PostgreSQL. This password should match with the user used in row 23
60 | ...
61 | 10 - "xxxx:8000" change the xxxx for the port to access the container
62 | ...
63 | 23 - DOCKER_POSTGRES_USER= user used in the PostgreSQL.
64 | 24 - DOCKER_POSTGRES_PASS= password used in the PostgreSQL.
65 | 25 - DOCKER_POSTGRES_DB= database name
66 | 26 - DOCKER_POSTGRES_HOST= hostname, the default configuration is the container defined in the docker-compose file
67 | 27 - DOCKER_POSTGRES_PORT= DB container port
68 | 28 - DEPLOY_MODE= the execution mode, if demo the database will be fulfilled with random data
69 | 29 - API_URL= the API URL, that ends with api/
70 | 30 - HOMEPAGE= the system homepage URL
71 | 31 - BASE_URL= the base URL is used when existing a prefix in the homepage URL. For instance, www.page.com/genericcdss, in this case, it is necessary to define the genericcdss in this variable
72 | ```
73 |
74 | After the customisation of the docker-compose file, it is only necessary to perform the following commands to have the installation running. (This process can take a few minutes)
75 |
76 | ```sh
77 | $ make build
78 | $ make docker-run
79 | ```
80 |
81 |
82 |
83 | ----
84 |
--------------------------------------------------------------------------------
/UI/src/js/components/reusable/DisplayField.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | /**
5 | * Input/output data component
6 | * */
7 | class DisplayField extends Component {
8 | render() {
9 | let validation = this.props.isWarning ? "is-warning": this.props.isInvalid ? "is-invalid": "";
10 | let readOnly = typeof this.props.readOnly === "boolean" ? this.props.readOnly : this.props.readOnly();
11 | return (
12 |
13 |
14 |
15 | {this.props.label}
16 |
17 |
18 | {
19 | readOnly ?
20 |
21 | :
22 |
29 | }
30 | {
31 | this.props.isInvalid ?
32 |
33 | {this.props.invalidMessage}
34 |
: ''
35 | }
36 | {
37 | this.props.isWarning ?
38 |
39 | {this.props.invalidMessage}
40 |
: ''
41 | }
42 |
43 | );
44 | }
45 |
46 | static propTypes = {
47 | /**
48 | * Label of the grey box
49 | * */
50 | label: PropTypes.string.isRequired,
51 | /**
52 | * Value to be shown
53 | * */
54 | value: PropTypes.oneOfType([
55 | PropTypes.string,
56 | PropTypes.object
57 | ]),
58 | /**
59 | * Key data to help the input identification when data is changed
60 | * */
61 | keydata: PropTypes.string,
62 | /**
63 | * Function comming for the parent component to handle with the selecting change
64 | *
65 | * @param event
66 | * */
67 | onChange: PropTypes.func,
68 | /**
69 | * Boolean to block the display to only show data (as a normal input)
70 | * */
71 | readOnly: PropTypes.oneOfType([
72 | PropTypes.func,
73 | PropTypes.bool
74 | ]),
75 | /**
76 | * Input type
77 | * */
78 | type: PropTypes.string,
79 | /**
80 | * Input min when number
81 | * */
82 | min: PropTypes.string,
83 | /**
84 | * Input max when number
85 | * */
86 | max: PropTypes.string,
87 | /**
88 | * Class for the component in general
89 | * */
90 | className: PropTypes.string,
91 | /**
92 | * Message to show if the message is valid
93 | * */
94 | invalidMessage: PropTypes.string,
95 | /**
96 | * Boolean to trigger the invalid message
97 | * */
98 | isInvalid: PropTypes.bool,
99 | /**
100 | * Boolean to trigger the warning message
101 | * */
102 | isWarning: PropTypes.bool,
103 | };
104 |
105 | }
106 |
107 | DisplayField.defaultProps = {
108 | readOnly: false,
109 | type: "text",
110 | className: "",
111 | invalidMessage: "",
112 | isInvalid: false,
113 | isWarning: false
114 | };
115 |
116 | export default DisplayField;
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
--------------------------------------------------------------------------------