Skip to content

Commit

Permalink
Merge pull request #420 from noharm-ai/develop
Browse files Browse the repository at this point in the history
v4.16-beta
  • Loading branch information
marceloarocha authored Dec 8, 2024
2 parents c4940c1 + 8f9ff2c commit ac25959
Show file tree
Hide file tree
Showing 14 changed files with 404 additions and 118 deletions.
4 changes: 3 additions & 1 deletion config.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@


class Config:
VERSION = "v4.15-beta"
VERSION = "v4.16-beta"
FRONTEND_VERSION = "4.0.10"
ENV = getenv("ENV") or NoHarmENV.DEVELOPMENT.value
SECRET_KEY = getenv("SECRET_KEY") or "secret_key"
Expand All @@ -31,6 +31,8 @@ class Config:
MAIL_SENDER = getenv("MAIL_SENDER") or "[email protected]"
MAIL_HOST = getenv("MAIL_HOST") or "localhost"

NIFI_BUCKET_NAME = getenv("NIFI_BUCKET_NAME") or ""

CACHE_BUCKET_NAME = getenv("CACHE_BUCKET_NAME") or ""
CACHE_BUCKET_ID = getenv("CACHE_BUCKET_ID") or ""
CACHE_BUCKET_KEY = getenv("CACHE_BUCKET_KEY") or ""
Expand Down
21 changes: 10 additions & 11 deletions models/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,17 +50,6 @@ def find(id):
user.config = claims["config"]
return user

def authenticate(email, password):
return (
User.query.filter(func.lower(User.email) == email.lower())
.filter(User.password == func.crypt(password, User.password))
.filter(User.active == True)
.first()
)

def findByEmail(email):
return User.query.filter_by(email=email).first()


class UserAudit(db.Model):
__tablename__ = "usuario_audit"
Expand Down Expand Up @@ -88,6 +77,16 @@ class UserAuthorization(db.Model):
createdBy = db.Column("created_by", db.BigInteger, nullable=False)


class UserExtra(db.Model):
__tablename__ = "usuario_extra"
__table_args__ = {"schema": "public"}

idUser = db.Column("idusuario", db.BigInteger, primary_key=True)
config = db.Column("config", postgresql.JSON, nullable=False)
createdAt = db.Column("created_at", db.DateTime, nullable=False)
createdBy = db.Column("created_by", db.BigInteger, nullable=False)


class Substance(db.Model):
__tablename__ = "substancia"
__table_args__ = {"schema": "public"}
Expand Down
1 change: 1 addition & 0 deletions models/requests/regulation_prioritization_request.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ class RegulationPrioritizationRequest(BaseModel):
riskList: Optional[list[int]] = None
typeList: Optional[list[str]] = []
stageList: Optional[list[int]] = []
idPatientList: Optional[list[int]] = []
limit: int
offset: int
order: list[Order]
4 changes: 4 additions & 0 deletions repository/regulation/reg_solicitation_repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ def get_prioritization(request_data: RegulationPrioritizationRequest):
if request_data.riskList:
query = query.filter(RegSolicitation.risk.in_(request_data.riskList))

if request_data.idPatientList:
query = query.filter(RegSolicitation.id_patient.in_(request_data.idPatientList))

if request_data.idDepartmentList:
query = query.filter(
RegSolicitation.id_department.in_(request_data.idDepartmentList)
Expand All @@ -85,6 +88,7 @@ def get_prioritization(request_data: RegulationPrioritizationRequest):
)

if order.field in ["birthdate"]:
direction = asc if order.direction == "desc" else desc
query = query.order_by(nullslast(direction(getattr(Patient, order.field))))

query = query.limit(request_data.limit).offset(request_data.offset)
Expand Down
59 changes: 59 additions & 0 deletions repository/user_repository.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
from sqlalchemy import func, or_, desc, asc

from models.main import db, User, UserAuthorization, UserExtra
from security.role import Role


def get_user_by_credentials(email: str, password: str) -> User:
return (
db.session.query(User)
.filter(func.lower(User.email) == email.lower())
.filter(User.password == func.crypt(password, User.password))
.filter(User.active == True)
.first()
)


def get_user_by_email(email: str) -> User:
return (
db.session.query(User).filter(func.lower(User.email) == email.lower()).first()
)


def get_admin_users_list(schema: str):
segments_query = db.session.query(
func.array_agg(UserAuthorization.idSegment)
).filter(User.id == UserAuthorization.idUser)

extra_roles_query = (
db.session.query(UserExtra)
.filter(UserExtra.idUser == User.id)
.filter(
or_(
UserExtra.config["roles"].astext.contains(Role.ADMIN.value),
UserExtra.config["roles"].astext.contains(Role.CURATOR.value),
UserExtra.config["roles"].astext.contains(Role.RESEARCHER.value),
UserExtra.config["roles"].astext.contains(
Role.SERVICE_INTEGRATOR.value
),
UserExtra.config["roles"].astext.contains(Role.STATIC_USER.value),
)
)
)

users = (
db.session.query(User, segments_query.scalar_subquery())
.filter(User.schema == schema)
.filter(
~User.config["roles"].astext.contains(Role.ADMIN.value),
~User.config["roles"].astext.contains(Role.CURATOR.value),
~User.config["roles"].astext.contains(Role.RESEARCHER.value),
~User.config["roles"].astext.contains(Role.SERVICE_INTEGRATOR.value),
~User.config["roles"].astext.contains(Role.STATIC_USER.value),
)
.filter(~extra_roles_query.exists())
.order_by(desc(User.active), asc(User.name))
.all()
)

return users
53 changes: 53 additions & 0 deletions routes/names.py
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,59 @@ def auth_token():
return {"status": "success", "data": token}


@app_names.route("/names/search/<string:term>", methods=["GET"])
@jwt_required()
def search_name(term):
user = User.find(get_jwt_identity())
dbSession.setSchema(user.schema)

config = _get_config(user)
token = _get_token(config)

url = (
config["getname"]["urlDev"]
if Config.ENV == NoHarmENV.DEVELOPMENT.value
else config["getname"]["url"]
)

url = url.replace("/patient-name/{idPatient}", f"/search-name/{term}")
params = dict(config["getname"]["params"])

try:
response = requests.get(
url,
headers={"Authorization": f"Bearer {token}"},
params=params,
)

if response.status_code == status.HTTP_200_OK:
data = response.json()
results = []
for p in data["results"]:
results.append({"name": p["name"], "idPatient": p["idPatient"]})

return {
"status": "success",
"data": sorted(results, key=lambda d: d["name"]),
}, status.HTTP_200_OK

logging.basicConfig()
logger = logging.getLogger("noharm.backend")
logger.error(f"Service names ERROR: {response.status_code}")
logger.error(url)
logger.error(params)
logger.error(response.json())
except Exception as e:
logging.basicConfig()
logger = logging.getLogger("noharm.backend")
logger.error("Service names ERROR (exception)")
logger.error(url)
logger.error(params)
logger.exception(e)

return {"status": "error", "data": []}, status.HTTP_400_BAD_REQUEST


def _get_token(config):
token_url = config["getname"]["token"]["url"]
params = config["getname"]["token"]["params"]
Expand Down
12 changes: 12 additions & 0 deletions security/role.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,8 @@ def __init__(self, id: str, permissions: List[Permission]):

STATIC_USER = "STATIC_USER", [Permission.READ_STATIC]

ORGANIZATION_MANAGER = "ORGANIZATION_MANAGER", [Permission.MULTI_SCHEMA]

@staticmethod
def get_permissions_from_user(user: User) -> List[Permission]:
roles = user.config["roles"] if user.config and "roles" in user.config else []
Expand All @@ -166,3 +168,13 @@ def get_permissions_from_user(user: User) -> List[Permission]:
pass

return user_permissions

@staticmethod
def get_special_roles():
return [
Role.ADMIN.value,
Role.CURATOR.value,
Role.ORGANIZATION_MANAGER.value,
Role.STATIC_USER.value,
Role.SERVICE_INTEGRATOR.value,
]
106 changes: 80 additions & 26 deletions services/admin/admin_integration_remote_service.py
Original file line number Diff line number Diff line change
@@ -1,47 +1,101 @@
import re
import boto3
import dateutil as pydateutil
from utils import status
from markupsafe import escape
from datetime import datetime
from datetime import datetime, timedelta
from sqlalchemy import desc
from botocore.exceptions import ClientError

from models.main import db
from models.main import db, User
from models.appendix import NifiStatus, NifiQueue
from utils.dateutils import to_iso
from utils import dateutils
from models.enums import NifiQueueActionTypeEnum
from exception.validation_error import ValidationError
from decorators.has_permission_decorator import has_permission, Permission
from config import Config


@has_permission(Permission.ADMIN_INTEGRATION_REMOTE)
def get_template_date():
result = (
db.session.query(NifiStatus.updatedAt)
.filter(NifiStatus.nifi_diagnostics != None)
.filter(NifiStatus.nifi_template != None)
.filter(NifiStatus.nifi_status != None)
.first()
def get_file_url(schema: str, filename="template") -> tuple[str, str]:
client = boto3.client("s3")

cache_data = _get_cache_data(client=client, schema=schema, filename=filename)

if cache_data["exists"]:
return (
client.generate_presigned_url(
"get_object",
Params={
"Bucket": Config.NIFI_BUCKET_NAME,
"Key": _get_resource_name(schema=schema, filename=filename),
},
ExpiresIn=3600,
),
cache_data["updatedAt"],
)

return None, None


def _get_resource_name(schema, filename="current"):
return f"{schema}/{filename}.json"


def _get_cache_data(client, schema, filename="current"):
try:
resource_info = client.head_object(
Bucket=Config.NIFI_BUCKET_NAME,
Key=_get_resource_name(schema=schema, filename=filename),
)

resource_date = pydateutil.parser.parse(
resource_info["ResponseMetadata"]["HTTPHeaders"]["last-modified"],
) - timedelta(hours=3)

return {
"exists": True,
"updatedAt": resource_date.replace(tzinfo=None).isoformat(),
}
except ClientError:
return {"exists": False, "updatedAt": None}


@has_permission(Permission.ADMIN_INTEGRATION_REMOTE)
def get_template_date(user_context: User):
client = boto3.client("s3")
url, metadata = _get_cache_data(
client=client, schema=user_context.schema, filename="template"
)

if result != None:
return {"updatedAt": result.updatedAt.isoformat()}
if metadata != None:
return {"updatedAt": metadata["updatedAt"]}

return {"updatedAt": None}


@has_permission(Permission.ADMIN_INTEGRATION_REMOTE)
def get_template():
config: NifiStatus = db.session.query(NifiStatus).first()
def get_template(user_context: User):
template_url, template_updated_at = get_file_url(
schema=user_context.schema, filename="template"
)
status_url, status_updated_at = get_file_url(
schema=user_context.schema, filename="status"
)
diagnostics_url, diagnostics_updated_at = get_file_url(
schema=user_context.schema, filename="diagnostics"
)

if config == None:
if not template_url:
raise ValidationError(
"Registro não encontrado",
"Template encontrado",
"errors.businessRule",
status.HTTP_400_BAD_REQUEST,
)

if config.nifi_status == None or config.nifi_template == None:
if not status_url:
raise ValidationError(
"Template/Status não encontrado",
"Status não encontrado",
"errors.businessRule",
status.HTTP_400_BAD_REQUEST,
)
Expand All @@ -60,16 +114,16 @@ def get_template():
"responseCode": q.responseCode,
"response": q.response,
"extra": q.extra,
"responseAt": to_iso(q.responseAt),
"createdAt": to_iso(q.createdAt),
"responseAt": dateutils.to_iso(q.responseAt),
"createdAt": dateutils.to_iso(q.createdAt),
}
)

return {
"template": config.nifi_template,
"status": config.nifi_status,
"diagnostics": config.nifi_diagnostics,
"updatedAt": to_iso(config.updatedAt),
"template": template_url,
"status": status_url,
"diagnostics": diagnostics_url,
"updatedAt": dateutils.to_iso(template_updated_at),
"queue": queue_results,
}

Expand Down Expand Up @@ -186,8 +240,8 @@ def get_queue_status(id_queue_list):
"extra": q.extra,
"responseCode": q.responseCode,
"response": q.response,
"responseAt": to_iso(q.responseAt),
"createdAt": to_iso(q.createdAt),
"responseAt": dateutils.to_iso(q.responseAt),
"createdAt": dateutils.to_iso(q.createdAt),
}
)

Expand Down
Loading

0 comments on commit ac25959

Please sign in to comment.