-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[DA-4616] AwardeeInSite Backend Job & API (#4032)
* Add Awardee InSite API * Add Awardee InSite API tests * Add cloud scheduler to run awardee insite datafeed * Add Awardee InSite Feed * Add datafeed queries for awardee insite * Fix get_id * Update function name * Add awardee insite data feed test * Add enrollment status query * Map enum cols from PS table to strings * Update test * Add test * Update to_client_json * Handle withdrawn participants * Update model * Fix queries & add update withdrawn query * Add awardee insite migration file * Add staticmethod * Disable withdrawn update for testing * Add POST to AwardeeInSiteInputFeed * Fix * Fix table name * Add missing col * Fix * Camel case vals * Add snake_to_camel case func * Fixes * Add ehr cond for testing * Update get_id * Test * Fix bug * Testing * Add logging for debugging * Add logging for debugging * Add logging for debugging * Add logging for debugging * Rm logging/print * Add else unset in query * Debug patient status * Fix * Fixes * Remove patientStatus * Patient Status test * Debug * rdr_service/workflow_management/ppsc/ppsc_data_transfer_input_feed.py * rdr_service/workflow_management/ppsc/ppsc_data_transfer_input_feed.py * Add eval * Add logging, ast * Add patientStatus cond * Fix tests * Improve logging * Fix query * Fix alias * Handle withdrawn participants * Fix * Handle withdrawn pids inside the query * Finalize query * Rm withdrawn col list * Update to_client_json * Update test * Set site default to NULL * Update comment * Correct doc * Update method to use baseclass * Use base dao's method * Update method name * Add awardee insite docs
- Loading branch information
1 parent
716777f
commit 5d53823
Showing
12 changed files
with
1,800 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
8 changes: 8 additions & 0 deletions
8
doc/api_workflows/field_reference/awardee_insite_field_list.rst
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
============================================================ | ||
Awardee InSite Field List | ||
============================================================ | ||
|
||
.. autoclass:: rdr_service.model.awardee_insite.AwardeeInSite | ||
:members: | ||
:undoc-members: | ||
:exclude-members: internal_fields, id, modified, created, create_surrogate_key_sql |
143 changes: 143 additions & 0 deletions
143
rdr_service/alembic/ppsc/versions/ae17f737a2cc_add_awardee_insite.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
"""add_awardee_insite | ||
Revision ID: ae17f737a2cc | ||
Revises: 6e07f138ede8 | ||
Create Date: 2024-12-30 11:44:27.237681 | ||
""" | ||
from alembic import op | ||
import sqlalchemy as sa | ||
import rdr_service.model.utils | ||
from sqlalchemy.dialects import mysql | ||
|
||
|
||
# revision identifiers, used by Alembic. | ||
revision = "ae17f737a2cc" | ||
down_revision = "6e07f138ede8" | ||
branch_labels = None | ||
depends_on = None | ||
|
||
|
||
def upgrade(engine_name): | ||
globals()["upgrade_%s" % engine_name]() | ||
|
||
|
||
def downgrade(engine_name): | ||
globals()["downgrade_%s" % engine_name]() | ||
|
||
|
||
def upgrade_ppsc(): | ||
# ### commands auto generated by Alembic - please adjust! ### | ||
op.create_table( | ||
"awardee_insite", | ||
sa.Column("id", sa.Integer(), autoincrement=True, nullable=False), | ||
sa.Column("created", rdr_service.model.utils.UTCDateTime(), nullable=True), | ||
sa.Column("modified", rdr_service.model.utils.UTCDateTime(), nullable=True), | ||
sa.Column("participant_id", sa.BigInteger(), nullable=False), | ||
sa.Column("first_name", sa.String(length=255), nullable=True), | ||
sa.Column("middle_name", sa.String(length=255), nullable=True), | ||
sa.Column("last_name", sa.String(length=255), nullable=True), | ||
sa.Column("zip_code", sa.String(length=10), nullable=True), | ||
sa.Column("state", sa.String(length=255), nullable=True), | ||
sa.Column("city", sa.String(length=255), nullable=True), | ||
sa.Column("street_address", sa.String(length=255), nullable=True), | ||
sa.Column("street_address2", sa.String(length=255), nullable=True), | ||
sa.Column("phone_number", sa.String(length=80), nullable=True), | ||
sa.Column("email", sa.String(length=255), nullable=True), | ||
sa.Column("date_of_birth", sa.Date(), nullable=True), | ||
sa.Column("organization", sa.String(length=255), nullable=True), | ||
sa.Column("withdrawal_status", sa.String(length=32), nullable=False), | ||
sa.Column( | ||
"withdrawal_time", rdr_service.model.utils.UTCDateTime(), nullable=True | ||
), | ||
sa.Column("deactivation_status", sa.String(length=32), nullable=False), | ||
sa.Column( | ||
"deactivation_time", rdr_service.model.utils.UTCDateTime(), nullable=True | ||
), | ||
sa.Column("deceased_status", sa.String(length=32), nullable=False), | ||
sa.Column( | ||
"deceased_authored", rdr_service.model.utils.UTCDateTime(), nullable=True | ||
), | ||
sa.Column( | ||
"clinic_physical_measurements_status", sa.String(length=32), nullable=False | ||
), | ||
sa.Column( | ||
"clinic_physical_measurements_finalized_time", | ||
rdr_service.model.utils.UTCDateTime(), | ||
nullable=True, | ||
), | ||
sa.Column( | ||
"clinic_physical_measurements_finalized_site", | ||
sa.String(length=255), | ||
nullable=True, | ||
), | ||
sa.Column( | ||
"self_reported_physical_measurements_status", | ||
sa.String(length=32), | ||
nullable=False, | ||
), | ||
sa.Column( | ||
"self_reported_physical_measurements_authored", | ||
rdr_service.model.utils.UTCDateTime(), | ||
nullable=True, | ||
), | ||
sa.Column( | ||
"consent_for_electronic_health_records", | ||
sa.String(length=10), | ||
nullable=False, | ||
), | ||
sa.Column( | ||
"consent_for_electronic_health_records_authored", | ||
rdr_service.model.utils.UTCDateTime(), | ||
nullable=True, | ||
), | ||
sa.Column( | ||
"consent_for_electronic_health_records_first_yes_authored", | ||
rdr_service.model.utils.UTCDateTime(), | ||
nullable=True, | ||
), | ||
sa.Column( | ||
"first_ehr_receipt_time", | ||
rdr_service.model.utils.UTCDateTime(), | ||
nullable=True, | ||
), | ||
sa.Column( | ||
"latest_ehr_receipt_time", | ||
rdr_service.model.utils.UTCDateTime(), | ||
nullable=True, | ||
), | ||
sa.Column("consent_for_study_enrollment", sa.String(length=10), nullable=False), | ||
sa.Column( | ||
"consent_for_study_enrollment_authored", | ||
rdr_service.model.utils.UTCDateTime(), | ||
nullable=True, | ||
), | ||
sa.Column("patient_status", mysql.JSON(), nullable=True), | ||
sa.Column("enrollment_status", sa.String(length=32), nullable=True), | ||
sa.Column("biospecimen_source_site", sa.String(length=255), nullable=True), | ||
sa.Column( | ||
"biospecimen_order_time", | ||
rdr_service.model.utils.UTCDateTime(), | ||
nullable=True, | ||
), | ||
sa.Column("biospecimen_status", sa.String(length=255), nullable=False), | ||
sa.Column( | ||
"sample_1sal2_collection_method", sa.String(length=255), nullable=False | ||
), | ||
sa.Column("sample_status_1sal2", sa.String(length=255), nullable=False), | ||
sa.Column("sample_order_status_1sal2", sa.String(length=255), nullable=False), | ||
sa.Column( | ||
"sample_order_status_1sal2_time", | ||
rdr_service.model.utils.UTCDateTime(), | ||
nullable=True, | ||
), | ||
sa.PrimaryKeyConstraint("id"), | ||
schema="ppsc", | ||
) | ||
# ### end Alembic commands ### | ||
|
||
|
||
def downgrade_ppsc(): | ||
# ### commands auto generated by Alembic - please adjust! ### | ||
op.drop_table("awardee_insite", schema="ppsc") | ||
# ### end Alembic commands ### |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
from flask import request | ||
from werkzeug.exceptions import BadRequest, InternalServerError | ||
|
||
from rdr_service.query import Query, Results | ||
from rdr_service.api.base_api import BaseApi, log_api_request | ||
from rdr_service.app_util import auth_required, get_validated_user_info | ||
from rdr_service.api_util import AWARDEE, RDR | ||
from rdr_service.dao.awardee_insite_dao import AwardeeInSiteDao | ||
|
||
|
||
AWARDEE_INSITE_PAGINATION_MAX_RESULTS = 1000 | ||
|
||
|
||
class AwardeeInSiteApi(BaseApi): | ||
def __init__(self): | ||
super().__init__(AwardeeInSiteDao()) | ||
self.awardee = None | ||
|
||
@auth_required([RDR] + [AWARDEE]) | ||
def get(self, id_=None, participant_id=None): | ||
log_api_request(log=request.log_record) | ||
|
||
_, user_info = get_validated_user_info() | ||
|
||
# Get the "awardee" linked to the user_email from the config | ||
if AWARDEE in user_info["roles"]: | ||
try: | ||
self.awardee = user_info["awardee"] | ||
except KeyError: | ||
raise InternalServerError("Config error for awardee") | ||
|
||
# In case RDR needs to call the API, they can pass an awardee query param with a awardee name to get the data | ||
if RDR in user_info["roles"]: | ||
self.awardee = request.args.get("awardee") | ||
if not self.awardee: | ||
raise BadRequest( | ||
"Awardee not found. Please pass an awardee to the query" | ||
) | ||
|
||
return self._query() | ||
|
||
def _make_query(self, check_invalid: bool = True) -> Query: | ||
""" | ||
Returns a Query object, setting properties like the max_results to be returned | ||
in a page and field filters (awardee name, last modified). | ||
""" | ||
query_definition = super()._make_query(check_invalid) | ||
|
||
field_filters = [] | ||
if self.awardee: | ||
field_filters.append(self.dao.make_query_filter("awardee", self.awardee)) | ||
|
||
if len(request.args) > 0: | ||
for key, value in request.args.items(multi=True): | ||
if key == "updatedSince": | ||
field_filters.append(self.dao.make_query_filter(key, value)) | ||
|
||
query_definition.field_filters = field_filters | ||
query_definition.max_results = AWARDEE_INSITE_PAGINATION_MAX_RESULTS | ||
|
||
return query_definition | ||
|
||
def _query(self) -> dict: | ||
""" | ||
Called in GET function. Creates a Query object and then runs that | ||
query and return the payload. | ||
""" | ||
query_definition: Query = self._make_query() | ||
results: Results = self.dao.query(query_definition) | ||
payload: dict = self._make_bundle(results) | ||
return payload | ||
|
||
def _make_bundle(self, results: Results) -> dict: | ||
""" | ||
Return response in a dict. If pagination token exists (meaning there is a next page), it creates | ||
a URL so that the client can call that URL to retrieve the next page. The URL to get the | ||
next page, and the participants results are added into the dictionary to be sent to the client. | ||
:param results: Result object containing the results of the query in | ||
the item attribute and pagination token in the pagination_token attribute. | ||
:return: Payload that will be sent in the GET request. | ||
""" | ||
|
||
from rdr_service import main | ||
|
||
bundle_dict = {"resourceType": "Bundle", "type": "searchset"} | ||
if results.pagination_token: | ||
query_params = request.args.copy() | ||
query_params["_token"] = results.pagination_token | ||
next_url = main.api.url_for( | ||
self.__class__, _external=True, **query_params.to_dict(flat=False) | ||
) | ||
bundle_dict["link"] = [{"relation": "next", "url": next_url}] | ||
|
||
entries = [] | ||
for item in results.items: | ||
resource = self._make_response(item[0]) # item = [awardee_model, HPO.name] | ||
entries.append({"resource": resource}) | ||
|
||
bundle_dict["entry"] = entries | ||
if results.total is not None: | ||
bundle_dict["total"] = results.total | ||
return bundle_dict |
Oops, something went wrong.