Skip to content

Commit

Permalink
Merge pull request #1760 from ChildMindInstitute/release/2025.02.3
Browse files Browse the repository at this point in the history
Release/2025.02.3 [main]
  • Loading branch information
mbanting authored Feb 27, 2025
2 parents 05a845f + c9d231d commit 9425460
Show file tree
Hide file tree
Showing 21 changed files with 1,381 additions and 1,507 deletions.
12 changes: 6 additions & 6 deletions Pipfile
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ more-itertools = "==10.6.0"
nh3 = "==0.2.20"
pydantic = { extras = ["email"], version = "==1.10.18" }
pyjwt = "==2.10.1"
pymongo = "==4.10.*"
pyOpenSSL = "==24.3.*"
pymongo = "==4.11.*"
pyOpenSSL = "==25.0.*"
python-multipart = "==0.0.20"
redis = "==5.2.*"
sentry-sdk = "~=2.13"
Expand All @@ -43,10 +43,10 @@ asgi-correlation-id = "==4.3.4"
[dev-packages]
allure-pytest = "==2.13.5"
cachetools = "==5.3.0"
gevent = "==24.2.1"
greenlet = "==3.1.0"
gevent = "==24.11.*"
greenlet = "==3.1.*"
ipdb = "==0.13.13"
mypy = "==1.14.*"
mypy = "==1.15.*"
nest-asyncio = "==1.6.0"
pre-commit = "==4.1.*"
pudb = "==2024.1.3"
Expand All @@ -63,7 +63,7 @@ ruff = "==0.9.*"
types-aiofiles = "==24.1.0.*"
types-cachetools = "==5.5.0.*"
types-python-dateutil = "==2.9.0.*"
types-pytz = "==2024.2.0.*"
types-pytz = "==2025.1.0.*"
types-requests = "==2.32.0.*"
typing-extensions = "==4.12.2"

Expand Down
1,173 changes: 586 additions & 587 deletions Pipfile.lock

Large diffs are not rendered by default.

16 changes: 11 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -229,11 +229,8 @@ set -o allexport; source .env; set +o allexport

> 🛑 **NOTE 2:** Please do not forget about environment variables! Now all environment variables for the Postgres Database which runs in docker are already passed to docker-compose.yaml from the .env file.
> 🛑 **NOTE 3:** If you get an error running `pipenv sync --dev` related to the dependency `greenlet`, install it by running:
```bash
pipenv install greenlet
```
> 🛑 **NOTE 4:** If the application can't find the `RabbitMQ` service even though it's running normally, change your `RABBITMQ__URL` to your local ip address instead of `localhost`
> 🛑 **NOTE 3:** If the application can't find the `RabbitMQ` service even though it's running normally, change your
`RABBITMQ__URL` to your local ip address instead of `localhost`

## Run the migrations
```bash
Expand Down Expand Up @@ -329,6 +326,9 @@ make run
# Check the code quality
make cq

# Check and fix code quality
make cqf

# Check tests passing
make test

Expand Down Expand Up @@ -479,6 +479,12 @@ delete from alembic_version;
alembic -c alembic_arbitrary.ini upgrade head
```

### Update gender_screen and age_screen activity items strings to greek for an applet

```bash
python src/cli.py patch exec M2-8568 -a <applet_id>
```

#### Database relation structure

```mermaid
Expand Down
1 change: 1 addition & 0 deletions src/apps/activities/domain/response_type_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ class _SelectionConfig(_ScreenConfig, PublicModel):
class SingleSelectionConfig(_SelectionConfig, PublicModel):
type: Literal[ResponseType.SINGLESELECT] | None
auto_advance: bool = False
response_data_identifier: bool = False


class MultiSelectionConfig(_SelectionConfig, PublicModel):
Expand Down
18 changes: 15 additions & 3 deletions src/apps/activities/services/activity.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,11 @@
from apps.activity_assignments.service import ActivityAssignmentService
from apps.activity_flows.crud import FlowsCRUD
from apps.applets.crud import AppletsCRUD, UserAppletAccessCRUD
from apps.schedule.crud.events import ActivityEventsCRUD, EventCRUD
from apps.schedule.crud.events import EventCRUD
from apps.schedule.domain.constants import EventType
from apps.schedule.service.schedule import ScheduleService
from apps.workspaces.domain.constants import Role
from infrastructure.logger import logger


class ActivityService:
Expand Down Expand Up @@ -114,9 +116,9 @@ async def update_create(self, applet_id: uuid.UUID, activities_create: list[Acti
activity_id_key_map: dict[uuid.UUID, uuid.UUID] = dict()
prepared_activity_items = list()

all_activities = await ActivityEventsCRUD(self.session).get_by_applet_id(applet_id)
activity_events = await EventCRUD(self.session).get_by_type_and_applet_id(applet_id, EventType.ACTIVITY)

all_activity_ids = [activity.activity_id for activity in all_activities]
all_activity_ids = [activity.activity_id for activity in activity_events if activity.activity_id is not None]

# Save new activity ids
new_activities = []
Expand Down Expand Up @@ -157,6 +159,16 @@ async def update_create(self, applet_id: uuid.UUID, activities_create: list[Acti
)

for item in activity_data.items:
if item.name in ["age_screen", "gender_screen"] and item.id is None:
# Implement logging for the age_screen and gender_screen items to trigger alerts
# in Datadog for the Greek version of the applet after translations were rolled back.
# TODO: Remove when full Greek support is available in Admin Panel [M2-8678](https://mindlogger.atlassian.net/browse/M2-8678)
logger.info( # type: ignore
f"Creating {item.name} item for activity {activity_id} in applet_id {applet_id}",
applet_id=str(applet_id),
operation=f"update_{item.name}",
)

prepared_activity_items.append(
PreparedActivityItemUpdate(
id=item.id or uuid.uuid4(),
Expand Down
1 change: 1 addition & 0 deletions src/apps/activities/tests/fixtures/configs.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ def single_select_config(default_config: DefaultConfig) -> SingleSelectionConfig
set_alerts=False,
add_tooltip=False,
set_palette=False,
response_data_identifier=False,
**default_config.dict(),
type=ResponseType.SINGLESELECT,
)
Expand Down
2 changes: 2 additions & 0 deletions src/apps/activities/tests/unit/test_activity_item_change.py
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,7 @@ def test_initial_single_selection_config_change(
"Add Text Input Option was disabled",
"Input Required was disabled",
"Auto Advance was disabled",
"Response Data Identifier was disabled",
]
assert changes == exp_changes

Expand Down Expand Up @@ -488,6 +489,7 @@ def test_initial_version_changes(
"Add Text Input Option was disabled",
"Input Required was disabled",
"Auto Advance was disabled",
"Response Data Identifier was disabled",
]
changes = item_change_service.get_changes_insert(new_item)
assert changes == single_select_exp_changes
Expand Down
7 changes: 5 additions & 2 deletions src/apps/activity_flows/service/flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
from apps.activity_flows.service.flow_item import FlowItemService
from apps.applets.crud import UserAppletAccessCRUD
from apps.applets.domain.applet_history import Version
from apps.schedule.crud.events import EventCRUD, FlowEventsCRUD
from apps.schedule.crud.events import EventCRUD
from apps.schedule.domain.constants import EventType
from apps.schedule.service.schedule import ScheduleService
from apps.workspaces.domain.constants import Role

Expand Down Expand Up @@ -89,7 +90,9 @@ async def update_create(
schemas = list()
prepared_flow_items = list()

all_flows = [flow.flow_id for flow in await FlowEventsCRUD(self.session).get_by_applet_id(applet_id)]
flow_events = await EventCRUD(self.session).get_by_type_and_applet_id(applet_id, EventType.FLOW)

all_flows = [flow_event.activity_flow_id for flow_event in flow_events if flow_event.activity_flow_id]

# Save new flow ids
new_flows = []
Expand Down
78 changes: 28 additions & 50 deletions src/apps/applets/commands/applet_ema.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,7 @@
from apps.job.constants import JobStatus
from apps.job.errors import JobStatusError
from apps.job.service import JobService
from apps.schedule.db.schemas import (
ActivityEventsSchema,
EventSchema,
FlowEventsSchema,
PeriodicitySchema,
UserEventsSchema,
)
from apps.schedule.db.schemas import EventSchema
from apps.schedule.domain.constants import PeriodicityType
from apps.shared.domain.base import PublicModel
from apps.subjects.db.schemas import SubjectSchema
Expand Down Expand Up @@ -239,27 +233,24 @@ async def get_user_flow_events(
select(
EventSchema.applet_id,
EventSchema.id.label("event_id"),
UserEventsSchema.user_id,
FlowEventsSchema.flow_id,
PeriodicitySchema.type.label("event_type"),
EventSchema.user_id,
EventSchema.activity_flow_id.label("flow_id"),
EventSchema.periodicity.label("event_type"),
case(
(
PeriodicitySchema.type.in_(("WEEKDAYS", "DAILY")),
EventSchema.periodicity.in_(("WEEKDAYS", "DAILY")),
scheduled_date,
),
(PeriodicitySchema.type.in_(("WEEKLY", "MONTHLY")), PeriodicitySchema.start_date),
else_=PeriodicitySchema.selected_date,
(EventSchema.periodicity.in_(("WEEKLY", "MONTHLY")), EventSchema.start_date),
else_=EventSchema.selected_date,
).label("selected_date"),
PeriodicitySchema.start_date,
PeriodicitySchema.end_date,
EventSchema.start_date,
EventSchema.end_date,
EventSchema.start_time,
EventSchema.end_time,
)
.select_from(EventSchema)
.join(UserEventsSchema, UserEventsSchema.event_id == EventSchema.id)
.join(PeriodicitySchema, PeriodicitySchema.id == EventSchema.periodicity_id)
.join(FlowEventsSchema, FlowEventsSchema.event_id == EventSchema.id)
.where(EventSchema.is_deleted == false(), PeriodicitySchema.type != PeriodicityType.ALWAYS)
.where(EventSchema.is_deleted == false(), EventSchema.periodicity != PeriodicityType.ALWAYS)
).cte("user_flow_events")

query = (
Expand Down Expand Up @@ -327,26 +318,22 @@ def filter_events(raw_events_rows: list[TRawRow], schedule_date: datetime.date)
case PeriodicityType.DAILY:
if row.is_crossday_event:
row.end_date += datetime.timedelta(days=1)
if schedule_date >= row.start_date and schedule_date <= row.end_date:
if row.start_date <= schedule_date <= row.end_date:
filtered.append(row)
case PeriodicityType.ONCE:
schedule_start_date = row.selected_date
row.end_date = row.selected_date
if row.is_crossday_event:
row.end_date += datetime.timedelta(days=1)
if schedule_date >= schedule_start_date and schedule_date <= row.end_date:
if schedule_start_date <= schedule_date <= row.end_date:
filtered.append(row)
case PeriodicityType.WEEKDAYS:
last_weekday = FRIDAY_WEEKDAY
if row.is_crossday_event:
last_weekday = SATURDAY_WEEKDAY
if row.end_date.weekday() == FRIDAY_WEEKDAY:
row.end_date += datetime.timedelta(days=1)
if (
schedule_date.weekday() <= last_weekday
and schedule_date >= row.start_date
and schedule_date <= row.end_date
):
if schedule_date.weekday() <= last_weekday and row.start_date <= schedule_date <= row.end_date:
filtered.append(row)
case PeriodicityType.WEEKLY:
scheduled_weekday = row.start_date.weekday()
Expand All @@ -362,10 +349,8 @@ def filter_events(raw_events_rows: list[TRawRow], schedule_date: datetime.date)
if row.start_date.weekday() == row.end_date.weekday():
row.end_date += datetime.timedelta(days=1)
if (
(schedule_date.weekday() == scheduled_weekday or schedule_date.weekday() == following_weekday)
and schedule_date >= row.start_date
and schedule_date <= row.end_date
):
schedule_date.weekday() == scheduled_weekday or schedule_date.weekday() == following_weekday
) and row.start_date <= schedule_date <= row.end_date:
filtered.append(row)
case PeriodicityType.MONTHLY:
scheduled_monthday = row.start_date.day
Expand All @@ -382,14 +367,10 @@ def filter_events(raw_events_rows: list[TRawRow], schedule_date: datetime.date)
):
row.end_date += datetime.timedelta(days=1)
if (
(
schedule_date.day == scheduled_monthday
or schedule_date.day == following_monthday
or (is_last_day_of_month(schedule_date) and row.start_date)
)
and schedule_date >= row.start_date
and schedule_date <= row.end_date
):
schedule_date.day == scheduled_monthday
or schedule_date.day == following_monthday
or (is_last_day_of_month(schedule_date) and row.start_date)
) and row.start_date <= schedule_date <= row.end_date:
filtered.append(row)
return filtered

Expand Down Expand Up @@ -505,27 +486,24 @@ async def get_user_activity_events(
select(
EventSchema.applet_id,
EventSchema.id.label("event_id"),
UserEventsSchema.user_id,
ActivityEventsSchema.activity_id,
PeriodicitySchema.type.label("event_type"),
EventSchema.user_id,
EventSchema.activity_id,
EventSchema.periodicity.label("event_type"),
case(
(
PeriodicitySchema.type.in_(("WEEKDAYS", "DAILY")),
EventSchema.periodicity.in_(("WEEKDAYS", "DAILY")),
scheduled_date,
),
(PeriodicitySchema.type.in_(("WEEKLY", "MONTHLY")), PeriodicitySchema.start_date),
else_=PeriodicitySchema.selected_date,
(EventSchema.periodicity.in_(("WEEKLY", "MONTHLY")), EventSchema.start_date),
else_=EventSchema.selected_date,
).label("selected_date"),
PeriodicitySchema.start_date,
PeriodicitySchema.end_date,
EventSchema.start_date,
EventSchema.end_date,
EventSchema.start_time,
EventSchema.end_time,
)
.select_from(EventSchema)
.join(UserEventsSchema, UserEventsSchema.event_id == EventSchema.id)
.join(PeriodicitySchema, PeriodicitySchema.id == EventSchema.periodicity_id)
.join(ActivityEventsSchema, ActivityEventsSchema.event_id == EventSchema.id)
.where(EventSchema.is_deleted == false(), PeriodicitySchema.type != PeriodicityType.ALWAYS)
.where(EventSchema.is_deleted == false(), EventSchema.periodicity != PeriodicityType.ALWAYS)
).cte("user_activity_events")

query = (
Expand Down
6 changes: 5 additions & 1 deletion src/apps/jsonld_converter/service/document/field.py
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,7 @@ class ReproFieldRadio(ReproFieldBase):
ld_randomize_options: bool | None = None
ld_scoring: bool | None = None
ld_response_alert: bool | None = None
ld_is_response_identifier: bool | None = None

is_multiple: bool = False
choices: list[dict] | None = None
Expand All @@ -357,7 +358,9 @@ async def _process_ld_response_options(self, options_doc: dict, drop=False):
self.ld_randomize_options = self.attr_processor.get_attr_value(options_doc, "reproschema:randomizeOptions")
self.ld_scoring = self.attr_processor.get_attr_value(options_doc, "reproschema:scoring")
self.ld_response_alert = self.attr_processor.get_attr_value(options_doc, "reproschema:responseAlert")

self.ld_is_response_identifier = self.attr_processor.get_attr_value(
options_doc, "reproschema:isResponseIdentifier"
)
self.choices = self._get_ld_choices_formatted(options_doc)

def _build_config(self, _cls: Type | None, **attrs):
Expand All @@ -367,6 +370,7 @@ def _build_config(self, _cls: Type | None, **attrs):
set_alerts=bool(self.ld_response_alert),
add_tooltip=False, # TODO
set_palette=bool(self.ld_color_palette), # TODO
response_data_identifier=bool(self.ld_is_response_identifier) if not self.is_multiple else None,
)
cfg_cls = MultiSelectionConfig if self.is_multiple else SingleSelectionConfig

Expand Down
1 change: 1 addition & 0 deletions src/apps/jsonld_converter/service/export/activity_item.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ def _build_response_options_prop(self, model: ActivityItemFull) -> dict:
"valueType": "xsd:anyURI", # todo tokens
"randomizeOptions": config.randomize_options,
"scoring": config.add_scores,
"isResponseIdentifier": config.response_data_identifier,
"responseAlert": config.set_alerts,
"colorPalette": config.set_palette,
"multipleChoice": False,
Expand Down
Loading

0 comments on commit 9425460

Please sign in to comment.