Skip to content
Permalink
Browse files

Merge branch 'release/v19.7.3'

  • Loading branch information...
ivan-c committed Jul 8, 2019
2 parents 6d689d9 + b2c6fc2 commit b717515e3e70e64b194a43a4650c185fb5986b7b
Showing with 582 additions and 235 deletions.
  1. +9 −6 bin/docker-build.sh
  2. +1 −1 docker/docker-compose.yaml
  3. +5 −1 docs/source/docker.rst
  4. +28 −0 portal/config/eproms/Organization.json
  5. +130 −0 portal/config/gil/Organization.json
  6. +26 −0 portal/migrations/versions/29ddc9e0f61d_.py
  7. +15 −0 portal/models/auth.py
  8. +2 −1 portal/models/encounter.py
  9. +11 −3 portal/models/user.py
  10. +4 −0 portal/static/js/forceReload.js
  11. +9 −13 portal/static/js/src/accountCreation.js
  12. +58 −0 portal/static/js/src/communications.js
  13. +8 −0 portal/static/js/src/mixins/CurrentUser.js
  14. +24 −0 portal/static/js/src/modules/OrgTool.js
  15. +41 −14 portal/static/js/src/profile.js
  16. +15 −0 portal/static/js/src/shortcutAlias.js
  17. +14 −9 portal/static/less/eproms.less
  18. +32 −10 portal/static/less/portal.less
  19. +5 −53 portal/templates/admin/communications.html
  20. +1 −1 portal/templates/force_reload.html
  21. +0 −4 portal/templates/layout.html
  22. +1 −3 portal/templates/profile/my_profile.html
  23. +15 −16 portal/templates/profile/patient_profile.html
  24. +1 −4 portal/templates/profile/profile_create_base.html
  25. +0 −5 portal/templates/profile/profile_macros.html
  26. +1 −4 portal/templates/profile/staff_profile.html
  27. +0 −3 portal/templates/profile/user_profile.html
  28. +3 −15 portal/templates/shortcut_alias.html
  29. +1 −0 portal/views/auth.py
  30. +1 −3 portal/views/patients.py
  31. +2 −21 portal/views/staff.py
  32. +13 −11 portal/webpack.common.js
  33. +6 −6 requirements.dev.txt
  34. +1 −1 requirements.prod.txt
  35. +5 −5 requirements.txt
  36. +55 −0 tests/test_deploy.sh
  37. +33 −2 tests/test_encounter.py
  38. +5 −0 tests/test_user.py
  39. +1 −20 tox.ini
@@ -34,12 +34,6 @@ if [ "$1" = "-h" ] || [ "$1" = "--help" ]; then
fi


# Create env_file if it doesn't exist
cp \
--no-clobber \
"${repo_path}/docker/portal.env.default" \
"${repo_path}/docker/portal.env"

# Use .gitignore as .dockerignore during build only
# not worth the effort to maintain both, for now
copy_output="$(
@@ -49,12 +43,21 @@ copy_output="$(
"${repo_path}/.gitignore" \
"${repo_path}/.dockerignore"
)"

# "->" will appear in `cp` output if file is sucessfully copied
file_copied="$(echo "$copy_output" | grep "\->" || true)"

# docker-compose commands must be run in the same directory as docker-compose.yaml
docker_compose_directory="${repo_path}/docker"
cd "${docker_compose_directory}"


default_portal_env="${PORTAL_ENV_FILE:-portal.env}"

# Create required env_file if it doesn't exist
cp --no-clobber portal.env.default "$default_portal_env"


# use trap to cleanup generated .dockerignore on early exit
trap 'cleanup_generated_dockerignore "$file_copied"; exit' INT TERM EXIT
echo "Building portal docker image..."
@@ -49,7 +49,7 @@ services:
<<: *service_base
command: bash -c '
(wait-for-it --host=redis --port=6379 --strict -- flask set-celery-beat-healthy) &
wait-for-it --timeout=120 --host=web --port="$$PORT" --strict --
wait-for-it --timeout=120 --host=web --port=$$PORT --strict --
celery beat
--app portal.celery_worker.celery
--loglevel debug
@@ -120,7 +120,11 @@ If you would like to use docker to work on the portal, you can configure ``docke

docker-compose up web

This will mount your checkout into a docker container and use the flask development server instead of the production default (gunicorn).
This will mount your checkout into a docker container and use the flask development server instead of the default (gunicorn).

.. note::
Migrations and static DB values will not be automatically updated. Run ``flask sync`` as needed


Environment Variables
---------------------
@@ -1987,6 +1987,34 @@
},
"resourceType": "Organization"
},
{
"extension": [
{
"timezone": "Europe/London",
"url": "http://hl7.org/fhir/StructureDefinition/user-timezone"
},
{
"research_protocols": [
{"name": "IRONMAN v3"}
],
"url": "http://us.truenth.org/identity-codes/research-protocol"
}
],
"id": 14620,
"identifier": [
{
"system": "http://pcctc.org/",
"use": "secondary",
"value": "146-20"
}
],
"language": "en_GB",
"name": "University Hospital Southampton NHS Foundation Trust",
"partOf": {
"reference": "api/organization/26000"
},
"resourceType": "Organization"
},
{
"id": 30000,
"identifier": [
@@ -1586,6 +1586,136 @@
"reference": "api/organization/40001"
},
"resourceType": "Organization"
},
{
"extension": [
{
"timezone": "America/New_York",
"url": "http://hl7.org/fhir/StructureDefinition/user-timezone"
}
],
"id": 40011,
"identifier": [
{
"system": "http://us.truenth.org/identity-codes/practice-region",
"use": "secondary",
"value": "state:MI"
},
{
"system": "http://us.truenth.org/identity-codes/shortname",
"use": "secondary",
"value": "Urologic Clinic of Southeast Michigan"
}
],
"name": "Urologic Clinic of Southeast Michigan",
"partOf": {
"reference": "api/organization/40001"
},
"resourceType": "Organization"
},
{
"extension": [
{
"timezone": "America/New_York",
"url": "http://hl7.org/fhir/StructureDefinition/user-timezone"
}
],
"id": 40012,
"identifier": [
{
"system": "http://us.truenth.org/identity-codes/practice-region",
"use": "secondary",
"value": "state:MI"
},
{
"system": "http://us.truenth.org/identity-codes/shortname",
"use": "secondary",
"value": "Lansing Institute of Urology"
}
],
"name": "Lansing Institute of Urology",
"partOf": {
"reference": "api/organization/40001"
},
"resourceType": "Organization"
},
{
"extension": [
{
"timezone": "America/New_York",
"url": "http://hl7.org/fhir/StructureDefinition/user-timezone"
}
],
"id": 40013,
"identifier": [
{
"system": "http://us.truenth.org/identity-codes/practice-region",
"use": "secondary",
"value": "state:MI"
},
{
"system": "http://us.truenth.org/identity-codes/shortname",
"use": "secondary",
"value": "Lakeshore Urology"
}
],
"name": "Lakeshore Urology",
"partOf": {
"reference": "api/organization/40001"
},
"resourceType": "Organization"
},
{
"extension": [
{
"timezone": "America/New_York",
"url": "http://hl7.org/fhir/StructureDefinition/user-timezone"
}
],
"id": 40014,
"identifier": [
{
"system": "http://us.truenth.org/identity-codes/practice-region",
"use": "secondary",
"value": "state:MI"
},
{
"system": "http://us.truenth.org/identity-codes/shortname",
"use": "secondary",
"value": "Wayne State University Physicians Group - Urology"
}
],
"name": "Wayne State University Physicians Group - Urology",
"partOf": {
"reference": "api/organization/40001"
},
"resourceType": "Organization"
},
{
"extension": [
{
"timezone": "America/New_York",
"url": "http://hl7.org/fhir/StructureDefinition/user-timezone"
}
],
"id": 40015,
"identifier": [
{
"system": "http://us.truenth.org/identity-codes/practice-region",
"use": "secondary",
"value": "state:MI"
},
{
"system": "http://us.truenth.org/identity-codes/shortname",
"use": "secondary",
"value": "Bay Area Urology"
}
],
"name": "Bay Area Urology",
"partOf": {
"reference": "api/organization/40001"
},
"resourceType": "Organization"
}
],
"id": "SitePersistence v0.2",
@@ -0,0 +1,26 @@
"""add 'failsafe' to encounter auth_methods
Revision ID: 29ddc9e0f61d
Revises: a97e02e09733
Create Date: 2019-06-11 12:16:10.433037
"""
from alembic import op

# revision identifiers, used by Alembic.
revision = '29ddc9e0f61d'
down_revision = 'a97e02e09733'


def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.execute("commit") # get around transaction warnings by faking a commit
op.execute(
"ALTER TYPE auth_methods ADD VALUE IF NOT EXISTS 'failsafe'")
# ### end Alembic commands ###


def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
pass
# ### end Alembic commands ###
@@ -7,6 +7,7 @@
from sqlalchemy import UniqueConstraint
from sqlalchemy.dialects.postgresql import ENUM

from ..audit import auditable_event
from ..database import db
from ..date_tools import FHIR_datetime
from ..extensions import oauth
@@ -47,6 +48,20 @@ def as_fhir(self):
system=TRUENTH_IDENTITY_SYSTEM, provider=self.provider),
'value': self.provider_id}

def reassign_owner(self, target_owner_id):
"""For invited user flows, the auth needs to follow original user
Used specifically when an auth_provider row needs to migrate from
a temporary account (generated during the registration process) is
merged back into the initial account.
"""
auditable_event("reassign {} auth from user {} to user {}".format(
self.provider, self.id, target_owner_id),
user_id=self.user_id, subject_id=target_owner_id,
context='authentication')
self.user_id = target_owner_id


class AuthProviderPersistable(AuthProvider):
"""For persistence to function, need instance serialization
@@ -34,7 +34,7 @@ class EncounterCodings(db.Model):
auth_method_types = ENUM(
'password_authenticated', 'url_authenticated', 'staff_authenticated',
'staff_handed_to_patient', 'service_token_authenticated',
'url_authenticated_and_verified',
'url_authenticated_and_verified', 'failsafe',
name='auth_methods', create_type=False)


@@ -178,6 +178,7 @@ def initiate_encounter(user, auth_method):
start_time=datetime.utcnow(), user_id=user.id)
db.session.add(encounter)
db.session.commit()
return db.session.merge(encounter)


def finish_encounter(user):
@@ -37,7 +37,7 @@
from .audit import Audit
from .codeable_concept import CodeableConcept
from .coding import Coding
from .encounter import Encounter
from .encounter import Encounter, initiate_encounter
from .extension import CCExtension, TimezoneExtension
from .fhir import bundle_results, v_or_first, v_or_n
from .identifier import Identifier, UserIdentifier
@@ -403,15 +403,18 @@ def display_name(self):

@property
def current_encounter(self):
"""Shortcut to current encounter, if present
"""Shortcut to current encounter, generate failsafe if not found
An encounter is typically bound to the logged in user, not
the subject, if a different user is performing the action.
"""
query = Encounter.query.filter(Encounter.user_id == self.id).filter(
Encounter.status == 'in-progress')
if query.count() == 0:
return None
current_app.logger.error(
"Failed to locate in-progress encounter for {}"
"; generate failsafe".format(self))
return initiate_encounter(self, auth_method='failsafe')
if query.count() != 1:
# Not good - we should only have one `active` encounter for
# the current user. Log details for debugging and return the
@@ -1508,6 +1511,11 @@ def merge_with(self, other_id):
for item in append_list:
self_entity.append(item)

# If other user has an external (3rd party) auth_provider, reassign
# to self
for ap in other.auth_providers:
ap.reassign_owner(self.id)

def promote_to_registered(self, registered_user):
"""Promote a weakly authenticated account to a registered one"""
assert self.id != registered_user.id
@@ -0,0 +1,4 @@
window.onload = function() {
window.location.reload(true);
};
window.onload();

0 comments on commit b717515

Please sign in to comment.
You can’t perform that action at this time.