Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions aind-sharepoint-service-server/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,10 @@ dynamic = ["version"]

dependencies = [
'pydantic>=2.0',
'pydantic-settings>=2.0',
'aind-settings-utils>=0.1.0',
'fastapi[standard]>=0.114.0',
'fastapi-cache2[redis]>=0.2.2',
'azure-identity>=1.15.0',
'aind-settings-utils>=0.0.3',
'requests',
]

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,12 @@
from typing import ClassVar, Optional
from urllib.parse import urljoin

from aind_settings_utils.aws import (
ParameterStoreAppBaseSettings,
)
from aind_settings_utils.aws import SecretsManagerBaseSettings
from pydantic import Field, RedisDsn, SecretStr
from pydantic_settings import SettingsConfigDict


class Settings(ParameterStoreAppBaseSettings):
class Settings(SecretsManagerBaseSettings):
"""Settings needed to connect to Sharepoint database"""

model_config = SettingsConfigDict(
Expand Down Expand Up @@ -105,6 +103,4 @@ def nsb_present_url(self) -> str:
)


def get_settings() -> Settings:
"""Return a Settings object."""
return Settings()
settings = Settings()
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
from redis.asyncio import from_url # noqa

from aind_sharepoint_service_server import __version__ as service_version
from aind_sharepoint_service_server.configs import get_settings
from aind_sharepoint_service_server.configs import settings
from aind_sharepoint_service_server.route import router

# The log level can be set by adding an environment variable before launch.
Expand All @@ -34,7 +34,6 @@
@asynccontextmanager
async def lifespan(_: FastAPI) -> AsyncIterator[None]:
"""Init cache and add to lifespan of app"""
settings = get_settings()
if settings.redis_url is not None:
redis = from_url(settings.redis_url.unicode_string())
FastAPICache.init(RedisBackend(redis), prefix="fastapi-cache")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -528,9 +528,7 @@ class NSB2023LimsTaskflow(Enum, metaclass=EnumMeta):
"Brain Observatory Transgenic Characterization"
)
BRAIN_OBSERVATORY_V1_DD = "Brain Observatory V1DD"
BRAIN_OBSERVATORY_VISUAL_BEHAVIOR = (
"Brain Observatory Visual Behavior"
)
BRAIN_OBSERVATORY_VISUAL_BEHAVIOR = "Brain Observatory Visual Behavior"
BRAIN_OBSERVATORY_VISUAL_BEHAVIOR_1B = (
"Brain Observatory Visual Behavior 1B"
)
Expand Down Expand Up @@ -746,27 +744,21 @@ class NSB2023Procedure(Enum, metaclass=EnumMeta):
SX_9__GRID_INJ_6_OR_9__MO = "Sx-09 Grid INJ (6 or 9) + Motor Ctx 2P"
SX_11_19_HP__ONLY = "Sx-11&19 HP Only"
SX_11_19_HP__TRANSCRANIAL = "Sx-11&19 HP Transcranial"
SX_12__STEREOTAXIC__INJEC = (
"Sx-12 Stereotaxic Injection (with Headpost)"
)
SX_12__STEREOTAXIC__INJEC = "Sx-12 Stereotaxic Injection (with Headpost)"
SX_14__VISUAL__CTX_NP = "Sx-14 Visual Ctx NP"
SX_15_WHC_NP = "Sx-15 WHC NP"
SX_16_INJ_WHC_NP = "Sx-16 INJ + WHC NP"
SX_17_DHC = "Sx-17 DHC"
SX_18_INJ_DHC = "Sx-18 INJ+DHC"
SX_21__FIBER__OPTIC__IMPL = (
"Sx-21 Fiber Optic Implant (with Headpost)"
)
SX_21__FIBER__OPTIC__IMPL = "Sx-21 Fiber Optic Implant (with Headpost)"
SX_21__INJECTION__FIBER = (
"Sx-21 Injection + Fiber Optic Implant (with Headpost)"
)
SX_24__STEREOTAXIC_INJECT = "Sx-24 Stereotaxic injections: 1 INJ material"
SX_25__STEREOTAXIC_INJECT = (
"Sx-25 Stereotaxic injections: 2+ INJ materials"
)
SX_26_ISI_GUIDED__INJECTI = (
"Sx-26 ISI-guided Injection (with Headpost)"
)
SX_26_ISI_GUIDED__INJECTI = "Sx-26 ISI-guided Injection (with Headpost)"
SX__SPINAL__CORD_INJ = "Sx- Spinal Cord INJ"
SX_EMG__ARRAY = "Sx- EMG Array"
SX__TESTES__INJECTION = "Sx- Testes Injection"
Expand All @@ -779,9 +771,7 @@ class NSB2023Procedure(Enum, metaclass=EnumMeta):
FRONTAL_CTX_2_P = "Frontal Ctx 2P"
HP_ONLY = "HP Only"
HP_TRANSCRANIAL = "HP Transcranial"
INJECTION_FIBER_OPTIC_IMP = (
"Injection+Fiber Optic Implant (with Headpost)"
)
INJECTION_FIBER_OPTIC_IMP = "Injection+Fiber Optic Implant (with Headpost)"
INJ_MOTOR_CTX = "INJ + Motor Ctx"
INJ_VISUAL_CTX_2_P = "INJ + Visual Ctx 2P"
INJ_WHC_NP_1_INJECTION_LO = "INJ + WHC NP (1 Injection Location)"
Expand Down Expand Up @@ -5687,9 +5677,7 @@ class NSB2023List(BaseModel, extra="allow"):
)
craniotomy_type: Annotated[
NSB2023CraniotomyType, WrapValidator(optional_enum)
] = Field(
default=None, alias="CraniotomyType", title="Craniotomy Type"
)
] = Field(default=None, alias="CraniotomyType", title="Craniotomy Type")
created: Optional[datetime] = Field(
default=None, alias="Created", title="Created"
)
Expand Down Expand Up @@ -6163,9 +6151,7 @@ class NSB2023List(BaseModel, extra="allow"):
)
surgery_status: Annotated[
NSB2023SurgeryStatus, WrapValidator(optional_enum)
] = Field(
default=None, alias="SurgeryStatus", title="Surgery Status"
)
] = Field(default=None, alias="SurgeryStatus", title="Surgery Status")
test1: Optional[str] = Field(
default=None, alias="Test1", title="Initial Surgeon"
)
Expand All @@ -6175,9 +6161,7 @@ class NSB2023List(BaseModel, extra="allow"):
title="Follow up Surgeon",
)
thermistor: Annotated[NSB2023Thermistor, WrapValidator(optional_enum)] = (
Field(
default=None, alias="Thermistor", title="Thermistor"
)
Field(default=None, alias="Thermistor", title="Thermistor")
)
title: Optional[str] = Field(default=None, alias="Title", title="Title")
ui_version_string: Optional[str] = Field(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@

from azure.core.credentials import AccessToken
from azure.identity import ClientSecretCredential
from fastapi import APIRouter, Depends, Path, status
from fastapi import APIRouter, Path, status
from fastapi_cache.decorator import cache
from httpx import AsyncClient

from aind_sharepoint_service_server.configs import Settings, get_settings
from aind_sharepoint_service_server.configs import settings
from aind_sharepoint_service_server.handler import SessionHandler
from aind_sharepoint_service_server.models.core import HealthCheck
from aind_sharepoint_service_server.models.las_2020 import Las2020List
Expand All @@ -19,7 +19,7 @@


@cache(expire=3360)
async def get_access_token(settings: Settings) -> str:
async def get_access_token() -> str:
"""
Get access token from either Azure or cache. Token is valid for 60 minutes.
We set cache lifespan to 56 minutes.
Expand All @@ -38,9 +38,9 @@ async def get_access_token(settings: Settings) -> str:


@cache(expire=3600)
async def get_las_2020_list(settings: Settings) -> List[Dict[str, Any]]:
async def get_las_2020_list() -> List[Dict[str, Any]]:
"""Get the LAS_2020 list items"""
bearer_token = await get_access_token(settings=settings)
bearer_token = await get_access_token()
headers = {
"Authorization": f"Bearer {bearer_token}",
"Content-Type": "application/json",
Expand All @@ -58,11 +58,9 @@ async def get_las_2020_list(settings: Settings) -> List[Dict[str, Any]]:


# Not worthwhile to cache results for NSB lists
async def get_nsb_2019_list(
subject_id: str, settings: Settings
) -> List[Dict[str, Any]]:
async def get_nsb_2019_list(subject_id: str) -> List[Dict[str, Any]]:
"""Get the NSB_2019 list items"""
bearer_token = await get_access_token(settings=settings)
bearer_token = await get_access_token()
headers = {
"Authorization": f"Bearer {bearer_token}",
"Content-Type": "application/json",
Expand All @@ -79,11 +77,9 @@ async def get_nsb_2019_list(
return list_items


async def get_nsb_2023_list(
subject_id: str, settings: Settings
) -> List[Dict[str, Any]]:
async def get_nsb_2023_list(subject_id: str) -> List[Dict[str, Any]]:
"""Get the NSB_2023 list items"""
bearer_token = await get_access_token(settings=settings)
bearer_token = await get_access_token()
headers = {
"Authorization": f"Bearer {bearer_token}",
"Content-Type": "application/json",
Expand All @@ -100,11 +96,9 @@ async def get_nsb_2023_list(
return list_items


async def get_nsb_present_list(
subject_id: str, settings: Settings
) -> List[Dict[str, Any]]:
async def get_nsb_present_list(subject_id: str) -> List[Dict[str, Any]]:
"""Get the NSB Present list items"""
bearer_token = await get_access_token(settings=settings)
bearer_token = await get_access_token()
headers = {
"Authorization": f"Bearer {bearer_token}",
"Content-Type": "application/json",
Expand Down Expand Up @@ -153,14 +147,13 @@ async def get_las_2020(
"value": "805811",
}
},
),
settings=Depends(get_settings),
)
):
"""
# LAS 2020 Endpoint
Retrieve information from the LAS 2020 list for a given subject ID.
"""
las_2020_list = await get_las_2020_list(settings=settings)
las_2020_list = await get_las_2020_list()
las_2020_models = [
Las2020List.model_validate(item["fields"])
for item in las_2020_list
Expand All @@ -183,17 +176,14 @@ async def get_nsb_2019(
"value": "656374",
}
},
),
settings=Depends(get_settings),
)
):
"""
# NSB 2019 Endpoint
Retrieve information from the NSB 2019 list for a given subject ID.
"""

nsb_2019_list = await get_nsb_2019_list(
subject_id=subject_id, settings=settings
)
nsb_2019_list = await get_nsb_2019_list(subject_id=subject_id)
nsb_2019_models = [
NSB2019List.model_validate(item["fields"]) for item in nsb_2019_list
]
Expand All @@ -214,17 +204,14 @@ async def get_nsb_2023(
"value": "657849",
}
},
),
settings=Depends(get_settings),
)
):
"""
# NSB 2023 Endpoint
Retrieve information from the NSB 2023-Archive list for a given subject ID.
"""

nsb_2023_list = await get_nsb_2023_list(
subject_id=subject_id, settings=settings
)
nsb_2023_list = await get_nsb_2023_list(subject_id=subject_id)
nsb_2023_models = [
NSB2023List.model_validate(item["fields"]) for item in nsb_2023_list
]
Expand All @@ -245,17 +232,14 @@ async def get_nsb_present(
"value": "790025",
}
},
),
settings=Depends(get_settings),
)
):
"""
# NSB Present Endpoint
Retrieve information from the NSB 2023-Present list for a given subject ID.
"""

nsb_present_list = await get_nsb_present_list(
subject_id=subject_id, settings=settings
)
nsb_present_list = await get_nsb_present_list(subject_id=subject_id)
nsb_present_models = [
NSB2023List.model_validate(item["fields"]) for item in nsb_present_list
]
Expand Down
5 changes: 2 additions & 3 deletions aind-sharepoint-service-server/tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from fastapi.testclient import TestClient
from pydantic import RedisDsn

from aind_sharepoint_service_server.configs import Settings
from aind_sharepoint_service_server.configs import settings

RESOURCES_DIR = Path(os.path.dirname(os.path.realpath(__file__))) / "resources"

Expand Down Expand Up @@ -95,13 +95,12 @@ def client_with_redis() -> Generator[TestClient, Any, None]:
# Import moved to be able to mock cache
from aind_sharepoint_service_server.main import app

settings = Settings()
settings_with_redis = settings.model_copy(
update={"redis_url": RedisDsn("redis://example.com:1234")}, deep=True
)
with (
patch(
"aind_sharepoint_service_server.main.get_settings",
"aind_sharepoint_service_server.main.settings",
return_value=settings_with_redis,
),
patch(
Expand Down
17 changes: 5 additions & 12 deletions aind-sharepoint-service-server/tests/test_route.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
from azure.core.credentials import AccessToken
from fastapi.testclient import TestClient

from aind_sharepoint_service_server.configs import Settings
from aind_sharepoint_service_server.route import (
get_access_token,
get_las_2020_list,
Expand All @@ -33,7 +32,7 @@ async def test_get_access_token(self, mock_azure_credentials: MagicMock):
mock_azure_credentials.return_value.get_token.return_value = (
AccessToken(token="abc", expires_on=100)
)
token = await get_access_token(settings=Settings())
token = await get_access_token()
mock_azure_credentials.assert_has_calls(
[
call(
Expand Down Expand Up @@ -61,7 +60,7 @@ async def test_get_las_2020_list(
"""Tests get_las_2020_list method"""
mock_get_access_token.return_value = "abc"
mock_get_list_items.return_value = mock_get_las_2020_list_items
list_items = await get_las_2020_list(settings=Settings())
list_items = await get_las_2020_list()
mock_client.assert_called_once()
assert 4 == len(list_items)

Expand Down Expand Up @@ -93,9 +92,7 @@ async def test_get_nsb_2023_list(
"""Tests get_nsb_2023_list method"""
mock_get_access_token.return_value = "abc"
mock_get_list_items.return_value = mock_get_nsb_2023_list_items
list_items = await get_nsb_2023_list(
settings=Settings(), subject_id="657849"
)
list_items = await get_nsb_2023_list(subject_id="657849")
mock_client.assert_called_once()
assert 1 == len(list_items)

Expand Down Expand Up @@ -127,9 +124,7 @@ async def test_get_nsb_2019_list(
"""Tests get_nsb_2019_list method"""
mock_get_access_token.return_value = "abc"
mock_get_list_items.return_value = mock_get_nsb_2019_list_items
list_items = await get_nsb_2019_list(
settings=Settings(), subject_id="656374"
)
list_items = await get_nsb_2019_list(subject_id="656374")
mock_client.assert_called_once()
assert 1 == len(list_items)

Expand Down Expand Up @@ -161,9 +156,7 @@ async def test_get_nsb_present_list(
"""Tests get_nsb_present_list method"""
mock_get_access_token.return_value = "abc"
mock_get_list_items.return_value = mock_get_nsb_present_list_items
list_items = await get_nsb_present_list(
settings=Settings(), subject_id="790025"
)
list_items = await get_nsb_present_list(subject_id="790025")
mock_client.assert_called_once()
assert 1 == len(list_items)

Expand Down