Skip to content

Commit

Permalink
Merge branch 'develop' into loris-integration-phase-2
Browse files Browse the repository at this point in the history
  • Loading branch information
ChaconC committed Oct 30, 2024
2 parents a74bd23 + 6b158cc commit b0db4e0
Show file tree
Hide file tree
Showing 14 changed files with 926 additions and 810 deletions.
1 change: 1 addition & 0 deletions .github/workflows/run_deploy_dev.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ env:

jobs:


deploy_to_ecs:
runs-on: ubuntu-latest
# needs: run_migration
Expand Down
28 changes: 14 additions & 14 deletions Pipfile
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ name = "pypi"
[packages]
aio-pika = "==9.4.3"
aiofiles = "==24.1.0"
aiohttp = "==3.10.9"
aiohttp = "==3.10.10"
alembic = "==1.13.3"
asyncpg = "==0.29.0"
azure-storage-blob = "==12.22.0"
asyncpg = "==0.30.0"
azure-storage-blob = "==12.23.1"
bcrypt = "==4.2.0"
boto3 = "==1.35.16"
fastapi = "==0.110.3"
boto3 = "==1.35.47"
fastapi = "==0.115.3"
# The latest version of the fastapi is not taken because of the issue
# starlette version for those deps ==0.21.0
# with fastapi-mail that requires 0.21 < starlette < 0.22
Expand Down Expand Up @@ -45,7 +45,7 @@ pyOpenSSL = "==24.2.1"
pydantic = { extras = ["email"], version = "==1.10.18" }
pymongo = "*"
python-multipart = "==0.0.12"
redis = "==5.1.0"
redis = "==5.1.1"
sentry-sdk = "~=2.13"
sqlalchemy = { extras = ["asyncio"], version = "==1.4.53" }
sqlalchemy-utils = "==0.41.2"
Expand All @@ -54,14 +54,14 @@ taskiq-aio-pika = "==0.4.1"
taskiq-fastapi = "==0.3.2"
taskiq-redis = "==1.0.2"
typer = "==0.12.5"
uvicorn = { extras = ["standard"], version = "==0.30.6" }
uvicorn = { extras = ["standard"], version = "==0.32.0" }
pyjwt = "==2.9.0"

[dev-packages]
ipdb = "==0.13.13"
pudb = "==2024.1.2"
pre-commit = "==3.8.0"
ruff = "==0.6.8"
pudb = "==2024.1.3"
pre-commit = "==4.0.1"
ruff = "==0.7.0"
allure-pytest = "==2.13.5"
pydantic-factories = "==1.17.3"
pytest = "==8.3.3"
Expand All @@ -72,11 +72,11 @@ pytest-lazy-fixtures = "==1.1.1"
pytest-mock = "==3.14.0"
nest-asyncio = "==1.6.0"
gevent = "==24.2.1"
mypy = "==1.11.2"
types-python-dateutil = "==2.9.0.20240906"
mypy = "==1.13.0"
types-python-dateutil = "==2.9.0.20241003"
typing-extensions = "==4.12.2"
types-requests = "==2.32.0.20240914"
types-pytz = "==2024.2.0.20240913"
types-requests = "==2.32.0.20241016"
types-pytz = "==2024.2.0.20241003"
types-aiofiles = "==24.1.0.20240626"
types-cachetools = "==5.5.0.20240820"
greenlet = "==3.1.0"
Expand Down
1,531 changes: 759 additions & 772 deletions Pipfile.lock

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,9 @@ env = [
"DATABASE__USER=postgres",
"DATABASE__DB=test",
"ARBITRARY_DB=test_arbitrary",
"TASK_ANSWER_ENCRYPTION__BATCH_LIMIT=1"
"TASK_ANSWER_ENCRYPTION__BATCH_LIMIT=1",
"CDN__LEGACY_REGION=us-east-1",
"CDN__LEGACY_BUCKET=testing"
]

[tool.coverage.run]
Expand Down
1 change: 1 addition & 0 deletions src/apps/activities/domain/custom_validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,7 @@ def validate_phrasal_templates(values: dict):
ResponseType.DATE,
ResponseType.SLIDERROWS,
ResponseType.SINGLESELECTROWS,
ResponseType.PARAGRAPHTEXT,
ResponseType.MULTISELECTROWS,
]:
raise IncorrectPhrasalTemplateItemTypeError()
Expand Down
18 changes: 18 additions & 0 deletions src/apps/activities/tests/fixtures/items.py
Original file line number Diff line number Diff line change
Expand Up @@ -298,3 +298,21 @@ def phrasal_template_with_slider_rows_create(
)

return [slider_rows_item_create, phrasal_item]


@pytest.fixture
def phrasal_template_with_paragraph_create(
phrasal_template_config: PhrasalTemplateConfig,
phrasal_template_with_paragraph_response_values: PhrasalTemplateValues,
base_item_data: BaseItemData,
paragraph_text_item_create,
):
phrasal_item = ActivityItemCreate(
**base_item_data.dict(exclude={"name"}),
name="phrasal_template_paragraph_test",
response_type=ResponseType.PHRASAL_TEMPLATE,
config=phrasal_template_config,
response_values=phrasal_template_with_paragraph_response_values,
)

return [paragraph_text_item_create, phrasal_item]
31 changes: 31 additions & 0 deletions src/apps/activities/tests/fixtures/response_values.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
MultiSelectionRowsValues,
MultiSelectionValues,
NumberSelectionValues,
ParagraphTextValues,
PhrasalTemplateDisplayMode,
PhrasalTemplateField,
PhrasalTemplatePhrase,
Expand Down Expand Up @@ -53,6 +54,13 @@ def single_select_response_values() -> SingleSelectionValues:
)


@pytest.fixture
def paragraph_response_values() -> ParagraphTextValues:
return ParagraphTextValues(
type=ResponseType.PARAGRAPHTEXT,
)


@pytest.fixture
def multi_select_response_values(
single_select_response_values: SingleSelectionValues,
Expand Down Expand Up @@ -202,6 +210,18 @@ def phrasal_template_with_slider_rows_response_fields(slider_rows_item_create) -
]


@pytest.fixture()
def phrasal_template_wiht_paragraph_response_fields(paragraph_text_item_create) -> List[PhrasalTemplateField]:
return [
_PhrasalTemplateSentenceField(text="test sentence"),
_PhrasalTemplateItemResponseField(
item_name=paragraph_text_item_create.name, display_mode=PhrasalTemplateDisplayMode.SENTENCE, item_index=0
),
_PhrasalTemplateLineBreakField(),
_PhrasalTemplateSentenceField(text="test sentence 2"),
]


@pytest.fixture
def phrasal_template_with_slider_rows_response_values(
phrasal_template_with_slider_rows_response_fields,
Expand All @@ -211,3 +231,14 @@ def phrasal_template_with_slider_rows_response_values(
card_title="test card title",
type=ResponseType.PHRASAL_TEMPLATE,
)


@pytest.fixture
def phrasal_template_with_paragraph_response_values(
phrasal_template_wiht_paragraph_response_fields,
) -> PhrasalTemplateValues:
return PhrasalTemplateValues(
phrases=[PhrasalTemplatePhrase(image=None, fields=phrasal_template_wiht_paragraph_response_fields)],
card_title="test paragraph card title",
type=ResponseType.PHRASAL_TEMPLATE,
)
4 changes: 2 additions & 2 deletions src/apps/activity_assignments/tests/test_assignments.py
Original file line number Diff line number Diff line change
Expand Up @@ -819,13 +819,13 @@ async def test_assignment_list_by_applet_with_delete_subject(
assert response.json()["result"]["appletId"] == str(applet_one_with_flow.id)
assignments = response.json()["result"]["assignments"]
assert len(assignments) == 2
assignment = assignments[0]
assignment = [a for a in assignments if a["activityId"] is not None][0]
assert assignment["activityId"] == str(applet_one_with_flow.activities[0].id)
assert assignment["respondentSubjectId"] == str(tom_applet_one_subject.id)
assert assignment["targetSubjectId"] == str(tom_applet_one_subject.id)
assert assignment["activityFlowId"] is None
assert assignment["id"] == assignment_activity["id"]
assignment = assignments[1]
assignment = [a for a in assignments if a["activityFlowId"] is not None][0]
assert assignment["activityId"] is None
assert assignment["respondentSubjectId"] == str(tom_applet_one_subject.id)
assert assignment["targetSubjectId"] == str(lucy_applet_one_subject.id)
Expand Down
2 changes: 1 addition & 1 deletion src/apps/answers/crud/answers.py
Original file line number Diff line number Diff line change
Expand Up @@ -704,7 +704,7 @@ async def get_completed_answers_data_list(

return result_list

async def get_latest_applet_version(self, applet_id: uuid.UUID) -> str:
async def get_latest_applet_version(self, applet_id: uuid.UUID) -> str | None:
query: Query = select(AnswerSchema.applet_history_id)
query = query.where(AnswerSchema.applet_id == applet_id)
query = query.order_by(AnswerSchema.version.desc())
Expand Down
9 changes: 7 additions & 2 deletions src/apps/applets/tests/test_applet_activity_items.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,12 @@ async def test_create_applet_with_each_activity_item(
assert item["responseValues"] == item_create.response_values.dict(by_alias=True)

@pytest.mark.parametrize(
"item_fixture", ("phrasal_template_with_text_create", "phrasal_template_with_slider_rows_create")
"item_fixture",
(
"phrasal_template_with_text_create",
"phrasal_template_with_slider_rows_create",
"phrasal_template_with_paragraph_create",
),
)
async def test_create_applet_with_phrasal_template(
self,
Expand Down Expand Up @@ -552,7 +557,7 @@ async def test_create_applet__activity_with_subscale_settings_and_lookup_table_a
assert resp.status_code == http.HTTPStatus.CREATED
result = resp.json()["result"]
assert result["activities"][0]["subscaleSetting"] == sub_setting.dict(by_alias=True)
assert result["activities"][0]["scoresAndReports"]["reports"][0]["scoringType"] == ScoringType.SCORE.value
assert result["activities"][0]["scoresAndReports"]["reports"][0]["scoringType"] == ScoringType.SCORE
assert result["activities"][0]["scoresAndReports"]["reports"][0]["subscaleName"] == "subscale type score"

async def test_create_applet__activity_with_subscale_settings_with_invalid_subscale_lookup_table_age(
Expand Down
19 changes: 11 additions & 8 deletions src/apps/file/services.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,31 +59,34 @@ async def get_legacy_client(self, info: WorkspaceArbitrary | None) -> CDNClient:
else:
return await self.get_regular_client()

async def _presign(self, url: str | None):
async def _presign(self, url: str | None, legacy_cdn_client: CDNClient, regular_cdn_client: CDNClient):
if not url:
return

if self._is_legacy_file_url_format(url):
if not await self._check_access_to_legacy_url(url):
return url
key = self._get_key(url)
wsp_service = workspace.WorkspaceService(self.session, self.user_id)
arbitrary_info = await wsp_service.get_arbitrary_info_if_use_arbitrary(self.applet_id)
legacy_cdn_client = await self.get_legacy_client(arbitrary_info)
if legacy_cdn_client.is_bucket_public() or await legacy_cdn_client.is_object_public(key):
return await legacy_cdn_client.generate_public_url(key)
return await legacy_cdn_client.generate_presigned_url(key)
elif self._is_regular_file_url_format(url):
if not await self._check_access_to_regular_url(url):
return url
key = self._get_key(url)
client = await self.get_regular_client()
return await client.generate_presigned_url(key)
return await regular_cdn_client.generate_presigned_url(key)
else:
return url

async def presign(self, urls: List[str | None]) -> List[str]:
c_list = []
wsp_service = workspace.WorkspaceService(self.session, self.user_id)
arbitrary_info = await wsp_service.get_arbitrary_info_if_use_arbitrary(self.applet_id)
legacy_cdn_client = await self.get_legacy_client(arbitrary_info)
regular_cdn_client = await self.get_regular_client()

for url in urls:
c_list.append(self._presign(url))
c_list.append(self._presign(url, legacy_cdn_client, regular_cdn_client))
result = await asyncio.gather(*c_list)
return result

Expand Down Expand Up @@ -136,7 +139,7 @@ class GCPPresignService(S3PresignService):
r"gs:\/\/[a-zA-Z0-9.-]+\/[a-zA-Z0-9-]+\/[a-zA-Z0-9-]+\/[a-f0-9-]+\/[a-f0-9-]+\/[a-zA-Z0-9-]+" # noqa
)

async def _presign(self, url: str | None):
async def _presign(self, url: str | None, *kwargs):
regular_cdn_client = await select_storage(applet_id=self.applet_id, session=self.session)

if self._is_legacy_file_url_format(url):
Expand Down
2 changes: 1 addition & 1 deletion src/apps/workspaces/crud/workspaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ async def get_arbitraries_map_by_applet_ids(self, applet_ids: list[uuid.UUID]) -
db_result = await self._execute(query)
res = db_result.scalars().all()

user_arb_uri_map: dict[uuid.UUID, str] = dict()
user_arb_uri_map: dict[uuid.UUID, str | None] = dict()
for user_workspace in res:
user_arb_uri_map[user_workspace.user_id] = (
user_workspace.database_uri if user_workspace.use_arbitrary else None
Expand Down
12 changes: 6 additions & 6 deletions src/infrastructure/utility/cdn_arbitrary.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,16 @@
from typing import BinaryIO

import boto3
import botocore
from azure.storage.blob import BlobSasPermissions, BlobServiceClient, generate_blob_sas
from botocore.config import Config

from infrastructure.utility.cdn_client import CDNClient
from infrastructure.utility.cdn_config import CdnConfig


class ArbitraryS3CdnClient(CDNClient):
def configure_client(self, config: CdnConfig):
client_config = botocore.config.Config(
def configure_client(self, config: CdnConfig, signature_version=None):
client_config = Config(
max_pool_connections=25,
)
return boto3.client(
Expand All @@ -32,8 +32,8 @@ def __init__(self, config: CdnConfig, endpoint_url: str, env: str, *, max_concur
def generate_private_url(self, key):
return f"gs://{self.config.bucket}/{key}"

def configure_client(self, config):
client_config = botocore.config.Config(
def configure_client(self, config, signature_version=None):
client_config = Config(
max_pool_connections=25,
)
return boto3.client(
Expand All @@ -58,7 +58,7 @@ def generate_key(cls, scope, unique, filename):
def generate_private_url(self, key):
return f"https://{self.config.bucket}.blob.core.windows.net/mindlogger/{key}" # noqa

def configure_client(self, _):
def configure_client(self, _, **kwargs):
blob_service_client = BlobServiceClient.from_connection_string(self.sec_key)
with suppress(Exception):
blob_service_client.create_container(self.default_container_name)
Expand Down
Loading

0 comments on commit b0db4e0

Please sign in to comment.