Skip to content

Commit

Permalink
Enhance device and event validation logic
Browse files Browse the repository at this point in the history
- Updated device retrieval to check both device_id and user_id.
- Enhanced event history lookup with activity or flow ID validation.
- Modified test data for consistency with new logic.
- Added SQLAlchemy case statement for conditional queries.
  • Loading branch information
rcmerlo committed Feb 26, 2025
1 parent a1f763f commit 82736c6
Show file tree
Hide file tree
Showing 6 changed files with 51 additions and 12 deletions.
9 changes: 6 additions & 3 deletions src/apps/answers/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,13 +87,16 @@ async def create_answer(
raise InvalidVersionError()

if device_id:
device = await UserDeviceService(session, user.id).get_by_device_id(device_id)
device = await UserDeviceService(session, user.id).get_by_device_id_and_user_id(device_id)
if device is None:
raise NotFoundError("Invalid device_id provided")

if schema.event_history_id:
event = await ScheduleHistoryService(session).get_by_id(schema.event_history_id)
if not event:
event = await ScheduleHistoryService(session).get_by_id_version_and_activity_or_flow(
id_version=schema.event_history_id,
activity_or_flow_id=schema.activity_id or schema.flow_id,
)
if event is None:
raise NotFoundError("Invalid event_history_id provided")

service = AnswerService(session, user.id, answer_session)
Expand Down
5 changes: 3 additions & 2 deletions src/apps/answers/tests/test_answers.py
Original file line number Diff line number Diff line change
Expand Up @@ -685,7 +685,7 @@ async def applet_default_events(session: AsyncSession, applet: AppletFull) -> li

@pytest.fixture
def device_create_data() -> UserDeviceCreate:
return UserDeviceCreate(os=AppInfoOS(name="os1", version="1.0.0"), app_version="1.1.1", device_id="device#id")
return UserDeviceCreate(os=AppInfoOS(name="os1", version="1.0.0"), app_version="51.0.0", device_id="device_id")


@pytest.mark.usefixtures("mock_kiq_report")
Expand Down Expand Up @@ -843,7 +843,8 @@ async def test_create_answer__with_device_id_and_event_history_id(
assert response.status_code == http.HTTPStatus.OK

data = answer_create.copy(deep=True)
event = applet_default_events[0]
event = next((event for event in applet_default_events if event.activity_id == answer_create.activity_id), None)
assert event
data.event_history_id = f"{event.id}_{event.version}"
response = await client.post(self.answer_url, data=data, headers={"Device-Id": device_create_data.device_id})

Expand Down
20 changes: 19 additions & 1 deletion src/apps/schedule/crud/schedule_history.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import asyncio
import uuid

from sqlalchemy import update
from sqlalchemy import case, select, update

from apps.schedule.db.schemas import (
AppletEventsSchema,
Expand Down Expand Up @@ -36,6 +36,24 @@ async def mark_as_deleted(self, events: list[tuple[uuid.UUID, str]]):
ReminderHistoryCRUD(self.session).mark_as_deleted(events),
)

async def get_by_id_version_and_activity_or_flow(
self, id_version: str, activity_or_flow_id: uuid.UUID
) -> EventHistorySchema:
query = select(EventHistorySchema).where(
EventHistorySchema.id_version == id_version,
case(
(
EventHistorySchema.activity_flow_id.isnot(None),
EventHistorySchema.activity_flow_id == activity_or_flow_id,
),
else_=EventHistorySchema.activity_id == activity_or_flow_id,
),
)

result = await self._execute(query)

return result.scalars().first()


class AppletEventsCRUD(BaseCRUD[AppletEventsSchema]):
async def add(self, applet_event: AppletEventsSchema) -> AppletEventsSchema:
Expand Down
10 changes: 10 additions & 0 deletions src/apps/schedule/service/schedule_history.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,16 @@ def __init__(self, session):
async def get_by_id(self, id_version: str) -> EventHistorySchema | None:
return await ScheduleHistoryCRUD(self.session).get_by_id(id_version)

async def get_by_id_version_and_activity_or_flow(
self, id_version: str, activity_or_flow_id: uuid.UUID | None
) -> EventHistorySchema | None:
if activity_or_flow_id is None:
return None

return await ScheduleHistoryCRUD(self.session).get_by_id_version_and_activity_or_flow(
id_version, activity_or_flow_id
)

async def add_history(self, applet_id: uuid.UUID, event: ScheduleEvent):
applet = await AppletsCRUD(self.session).get_by_id(applet_id)

Expand Down
11 changes: 9 additions & 2 deletions src/apps/users/cruds/user_device.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import datetime
import uuid

from sqlalchemy import select
from sqlalchemy.dialects.postgresql import insert

from apps.users.db.schemas import UserDeviceSchema
Expand All @@ -10,8 +11,14 @@
class UserDevicesCRUD(BaseCRUD[UserDeviceSchema]):
schema_class = UserDeviceSchema

async def get_by_device_id(self, device_id: str) -> UserDeviceSchema | None:
return await self._get(key="device_id", value=device_id)
async def get_by_device_id_and_user_id(self, device_id: str, user_id: uuid.UUID) -> UserDeviceSchema | None:
query = select(UserDeviceSchema).where(
UserDeviceSchema.device_id == device_id,
UserDeviceSchema.user_id == user_id,
)
result = await self._execute(query)

return result.scalars().first()

async def add_device(self, user_id: uuid.UUID, device_id: str) -> None:
await self._delete(user_id=user_id, device_id=device_id)
Expand Down
8 changes: 4 additions & 4 deletions src/apps/users/services/user_device.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ def __init__(self, session, user_id: uuid.UUID) -> None:
self.session = session
self.user_id = user_id

async def get_by_device_id(self, device_id: str) -> UserDevice:
schema = await UserDevicesCRUD(self.session).get_by_device_id(device_id)
if schema:
return UserDevice.from_schema(schema)
async def get_by_device_id_and_user_id(self, device_id: str) -> UserDevice | None:
schema = await UserDevicesCRUD(self.session).get_by_device_id_and_user_id(device_id, self.user_id)

return UserDevice.from_schema(schema) if schema else None

async def add_device(self, data: UserDeviceCreate) -> UserDevice:
app_data = dict(
Expand Down

0 comments on commit 82736c6

Please sign in to comment.