Skip to content

Commit

Permalink
Merge pull request #421 from noharm-ai/develop
Browse files Browse the repository at this point in the history
v4.17-beta
  • Loading branch information
marceloarocha authored Dec 10, 2024
2 parents ac25959 + 893d078 commit 9cb7594
Show file tree
Hide file tree
Showing 10 changed files with 143 additions and 51 deletions.
5 changes: 3 additions & 2 deletions config.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@


class Config:
VERSION = "v4.16-beta"
FRONTEND_VERSION = "4.0.10"
VERSION = "v4.17-beta"
FRONTEND_VERSION = "4.0.13"
ENV = getenv("ENV") or NoHarmENV.DEVELOPMENT.value
SECRET_KEY = getenv("SECRET_KEY") or "secret_key"
API_KEY = getenv("API_KEY") or ""
Expand All @@ -32,6 +32,7 @@ class Config:
MAIL_HOST = getenv("MAIL_HOST") or "localhost"

NIFI_BUCKET_NAME = getenv("NIFI_BUCKET_NAME") or ""
NIFI_SQS_QUEUE_REGION = getenv("NIFI_SQS_QUEUE_REGION") or ""

CACHE_BUCKET_NAME = getenv("CACHE_BUCKET_NAME") or ""
CACHE_BUCKET_ID = getenv("CACHE_BUCKET_ID") or ""
Expand Down
3 changes: 3 additions & 0 deletions models/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ class FeatureEnum(Enum):
CONCILIATION_EDIT = "CONCILIATION_EDIT"
DISABLE_CPOE = "DISABLE_CPOE"
STAGING_ACCESS = "STAGING_ACCESS"
AUTOMATIC_CHECK_IF_NOT_VALIDATED_ITENS = "AUTOMATIC_CHECK_IF_NOT_VALIDATED_ITENS"


class PrescriptionAuditTypeEnum(Enum):
Expand All @@ -65,11 +66,13 @@ class PrescriptionAuditTypeEnum(Enum):
INTEGRATION_PRESCRIPTION_RELEASE = 6
UPSERT_CLINICAL_NOTES = 7
CREATE_AGG = 8
ERROR_INTEGRATION_PRESCRIPTION_RELEASE = 9


class PrescriptionDrugAuditTypeEnum(Enum):
PROCESSED = 1
UPSERT = 2
INTEGRATION_PRESCRIPTION_DRUG_RELEASE = 3


class PrescriptionReviewTypeEnum(Enum):
Expand Down
2 changes: 2 additions & 0 deletions routes/static.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ def create_aggregated_by_prescription(schema, id_prescription):
force = request.args.get("force", False)

user_context = User()
user_context.id = 0
user_context.schema = schema
user_context.config = {"roles": ["STATIC_USER"]}
g.user_context = user_context
Expand Down Expand Up @@ -64,6 +65,7 @@ def create_aggregated_prescription_by_date(schema, admission_number):
)

user_context = User()
user_context.id = 0
user_context.schema = schema
user_context.config = {"roles": ["STATIC_USER"]}
g.user_context = user_context
Expand Down
1 change: 1 addition & 0 deletions security/permission.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ class Permission(Enum):
RUN_AS = "RUN_AS" # "permission to service users"

READ_STATIC = "READ_STATIC" # "read static permission"
CHECK_STATIC = "CHECK_STATIC" # check from static context

MULTI_SCHEMA = "MULTI_SCHEMA" # "grants multi schema access"
MAINTAINER = "MAINTAINER" # "grants access to closed contracts"
Expand Down
2 changes: 1 addition & 1 deletion security/role.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ def __init__(self, id: str, permissions: List[Permission]):

REGULATOR = "REGULATOR", [Permission.READ_REGULATION, Permission.WRITE_REGULATION]

STATIC_USER = "STATIC_USER", [Permission.READ_STATIC]
STATIC_USER = "STATIC_USER", [Permission.READ_STATIC, Permission.CHECK_STATIC]

ORGANIZATION_MANAGER = "ORGANIZATION_MANAGER", [Permission.MULTI_SCHEMA]

Expand Down
108 changes: 85 additions & 23 deletions services/admin/admin_integration_remote_service.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
import re
import boto3
import json
import dateutil as pydateutil
from utils import status
from markupsafe import escape
from datetime import datetime, timedelta
from sqlalchemy import desc
from sqlalchemy.orm import Session
from botocore.exceptions import ClientError
from botocore.config import Config as BotoConfig

from models.main import db, User
from models.appendix import NifiStatus, NifiQueue
from models.appendix import NifiQueue
from utils import dateutils
from models.enums import NifiQueueActionTypeEnum
from exception.validation_error import ValidationError
Expand Down Expand Up @@ -64,12 +67,12 @@ def _get_cache_data(client, schema, filename="current"):
@has_permission(Permission.ADMIN_INTEGRATION_REMOTE)
def get_template_date(user_context: User):
client = boto3.client("s3")
url, metadata = _get_cache_data(
cache_data = _get_cache_data(
client=client, schema=user_context.schema, filename="template"
)

if metadata != None:
return {"updatedAt": metadata["updatedAt"]}
if cache_data != None:
return {"updatedAt": cache_data["updatedAt"]}

return {"updatedAt": None}

Expand Down Expand Up @@ -129,7 +132,9 @@ def get_template(user_context: User):


@has_permission(Permission.ADMIN_INTEGRATION_REMOTE)
def push_queue_request(id_processor: str, action_type: str, data: dict):
def push_queue_request(
id_processor: str, action_type: str, data: dict, user_context: User
):
if id_processor == None and (
action_type != NifiQueueActionTypeEnum.CUSTOM_CALLBACK.value
and action_type != NifiQueueActionTypeEnum.REFRESH_TEMPLATE.value
Expand Down Expand Up @@ -177,13 +182,47 @@ def push_queue_request(id_processor: str, action_type: str, data: dict):
db.session.add(queue)
db.session.flush()

_send_to_sqs(queue=queue, schema=user_context.schema)

return {
"id": queue.id,
"extra": queue.extra,
"createdAt": queue.createdAt.isoformat(),
}


def _send_to_sqs(queue: NifiQueue, schema: str):
sqs = boto3.client(
"sqs",
config=BotoConfig(
region_name=Config.NIFI_SQS_QUEUE_REGION,
),
)
response = sqs.get_queue_url(
QueueName=schema,
)
queue_url = response["QueueUrl"]
body_data = {
"schema": schema,
"id": queue.id,
"url": queue.url,
"method": queue.method,
"runStatus": queue.runStatus,
"body": queue.body if queue.body else {"empty": True},
"type": queue.extra.get("type", "default"),
}

sqs.send_message(
QueueUrl=queue_url,
DelaySeconds=10,
MessageAttributes={
"schema": {"DataType": "String", "StringValue": schema},
"type": {"DataType": "String", "StringValue": "request"},
},
MessageBody=json.dumps(body_data),
)


def _get_new_queue(id_processor: str, action_type: str, data: dict):
queue = NifiQueue()
queue.runStatus = False
Expand Down Expand Up @@ -225,27 +264,50 @@ def _get_new_queue(id_processor: str, action_type: str, data: dict):


@has_permission(Permission.ADMIN_INTEGRATION_REMOTE)
def get_queue_status(id_queue_list):
queue_list = (
db.session.query(NifiQueue).filter(NifiQueue.id.in_(id_queue_list)).all()
)
def get_queue_status(id_queue_list, user_context: User):
queue_results = []
for q in queue_list:
queue_results.append(
{
"id": q.id,
"url": q.url,
"body": q.body,
"method": q.method,
"extra": q.extra,
"responseCode": q.responseCode,
"response": q.response,
"responseAt": dateutils.to_iso(q.responseAt),
"createdAt": dateutils.to_iso(q.createdAt),
}
update_status = False

engine = db.engines["report"]
with Session(engine) as session:
session.connection(
execution_options={"schema_translate_map": {None: user_context.schema}}
)
queue_list = (
session.query(NifiQueue).filter(NifiQueue.id.in_(id_queue_list)).all()
)

for q in queue_list:
if q.responseCode == status.HTTP_200_OK:
update_status = True

queue_results.append(
{
"id": q.id,
"url": q.url,
"body": q.body,
"method": q.method,
"extra": q.extra,
"responseCode": q.responseCode,
"response": q.response,
"responseAt": dateutils.to_iso(q.responseAt),
"createdAt": dateutils.to_iso(q.createdAt),
}
)

status_url = None
status_updated_at = None
if update_status:
status_url, status_updated_at = get_file_url(
schema=user_context.schema, filename="status"
)

return queue_results
return {
"queue": queue_results,
"updateStatus": update_status,
"statusUrl": status_url,
"statusUpdatedAt": status_updated_at,
}


def _validate_custom_endpoint(endpoint: str):
Expand Down
2 changes: 1 addition & 1 deletion services/data_authorization_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ def has_segment_authorization(id_segment: int, user: User):
return True

permissions = Role.get_permissions_from_user(user=user)
if Permission.MAINTAINER in permissions:
if Permission.MAINTAINER in permissions or Permission.CHECK_STATIC in permissions:
return True

if memory_service.has_feature(FeatureEnum.AUTHORIZATION_SEGMENT.value):
Expand Down
20 changes: 20 additions & 0 deletions services/feature_service.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,25 @@
from flask import g

from models.main import db
from models.appendix import Memory
from models.enums import MemoryEnum, FeatureEnum


def is_cpoe():
return g.get("is_cpoe", False)


def has_feature(user_feature: FeatureEnum):
features = g.get("features", [])

if not features:
features_memory = (
db.session.query(Memory)
.filter(Memory.kind == MemoryEnum.FEATURES.value)
.first()
)
if features_memory:
features = features_memory.value
g.features = features

return user_feature.value in features
22 changes: 22 additions & 0 deletions services/prescription_agg_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
PrescriptionDrugAuditTypeEnum,
DrugTypeEnum,
PatientConciliationStatusEnum,
FeatureEnum,
)
from services import (
prescription_drug_service,
Expand Down Expand Up @@ -228,6 +229,7 @@ def create_agg_prescription_by_date(
)

_log_processed_date(id_prescription_array=internal_prescription_ids, schema=schema)
_automatic_check(prescription=agg_p, features=features, user_context=user_context)


def _log_processed_date(id_prescription_array, schema):
Expand Down Expand Up @@ -409,3 +411,23 @@ def _audit_create(prescription: Prescription):
a.createdBy = 0

db.session.add(a)


def _automatic_check(prescription: Prescription, features: dict, user_context: User):
# automatic check prescription if there are no items with validation (drugs, solutions, procedures)
if (
features.get("totalItens") == 0
and prescription.status != "s"
and feature_service.has_feature(
FeatureEnum.AUTOMATIC_CHECK_IF_NOT_VALIDATED_ITENS
)
):
prescription_check_service.check_prescription(
idPrescription=prescription.id,
p_status="s",
user_context=user_context,
evaluation_time=0,
alerts=[],
service_user=False,
fast_check=True,
)
29 changes: 5 additions & 24 deletions services/prioritization_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,9 @@ def get_prioritization_list(
Patient,
Department.name.label("department"),
func.count().over(),
(
Prescription.features["prescriptionScore"].astext.cast(Integer)
+ Prescription.features["av"].astext.cast(Integer)
+ Prescription.features["am"].astext.cast(Integer)
+ Prescription.features["alertExams"].astext.cast(Integer)
+ Prescription.features["alerts"].astext.cast(Integer)
+ Prescription.features["diff"].astext.cast(Integer)
).label("globalScore"),
(Prescription.features["globalScore"].astext.cast(Integer)).label(
"globalScore"
),
)
.outerjoin(Patient, Patient.admissionNumber == Prescription.admissionNumber)
.outerjoin(
Expand Down Expand Up @@ -262,27 +257,13 @@ def get_prioritization_list(

if global_score_min != None:
q = q.filter(
(
Prescription.features["prescriptionScore"].astext.cast(Integer)
+ Prescription.features["av"].astext.cast(Integer)
+ Prescription.features["am"].astext.cast(Integer)
+ Prescription.features["alertExams"].astext.cast(Integer)
+ Prescription.features["alerts"].astext.cast(Integer)
+ Prescription.features["diff"].astext.cast(Integer)
)
(Prescription.features["globalScore"].astext.cast(Integer))
>= global_score_min
)

if global_score_max != None:
q = q.filter(
(
Prescription.features["prescriptionScore"].astext.cast(Integer)
+ Prescription.features["av"].astext.cast(Integer)
+ Prescription.features["am"].astext.cast(Integer)
+ Prescription.features["alertExams"].astext.cast(Integer)
+ Prescription.features["alerts"].astext.cast(Integer)
+ Prescription.features["diff"].astext.cast(Integer)
)
(Prescription.features["globalScore"].astext.cast(Integer))
<= global_score_max
)

Expand Down

0 comments on commit 9cb7594

Please sign in to comment.