mitlist/be/app/crud/activity.py
mohamad 229f6b7b1c feat: Introduce activity tracking and management features
This commit adds new functionality for tracking user activities within the application, including:

- Implementation of a new activity service to fetch and manage group activities.
- Creation of a dedicated activity store to handle state management for activities.
- Introduction of new API endpoints for retrieving paginated activity data.
- Enhancements to the UI with new components for displaying activity feeds and items.
- Refactoring of existing components to utilize the new activity features, improving user engagement and interaction.

These changes aim to enhance the application's activity tracking capabilities and provide users with a comprehensive view of their interactions.
2025-06-28 19:14:51 +02:00

81 lines
3.5 KiB
Python

from datetime import datetime
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.future import select
from sqlalchemy.orm import selectinload
from sqlalchemy import func, text
from app.models import ChoreHistory, FinancialAuditLog, Item, UserGroup, User
from app.schemas.activity import Activity, ActivityEventType, ActivityUser
async def get_group_activity(db: AsyncSession, group_id: int, limit: int, cursor: int = None) -> list[Activity]:
queries = []
chore_history_stmt = (
select(ChoreHistory)
.where(ChoreHistory.group_id == group_id)
.options(selectinload(ChoreHistory.changed_by_user))
)
if cursor:
chore_history_stmt = chore_history_stmt.where(ChoreHistory.timestamp < datetime.fromtimestamp(cursor))
queries.append(chore_history_stmt)
# FinancialAuditLog has group_id through joins, which is complex. For now, we assume a direct or easy link.
# This might need refinement based on actual relationships.
# This is a placeholder as FinancialAuditLog doesn't have a direct group_id.
# We will need to join through expenses/settlements, etc.
# For now, this part will return empty.
items_stmt = (
select(Item)
.join(Item.list)
.where(text("lists.group_id = :group_id"))
.params(group_id=group_id)
.options(selectinload(Item.added_by_user), selectinload(Item.completed_by_user))
)
if cursor:
items_stmt = items_stmt.where(Item.created_at < datetime.fromtimestamp(cursor))
queries.append(items_stmt)
results = []
for q in queries:
res = await db.execute(q)
results.extend(res.scalars().all())
activities = []
for item in results:
if isinstance(item, ChoreHistory):
if item.event_type.value == 'completed':
user = item.changed_by_user
activities.append(Activity(
id=f"chore_history-{item.id}",
event_type=ActivityEventType.CHORE_COMPLETED,
timestamp=item.timestamp,
user=ActivityUser(id=user.id, name=user.name),
details={"chore_name": item.event_data.get("name", "Unknown chore")},
message=f"{user.name or 'User'} completed '{item.event_data.get('name', 'a chore')}'."
))
elif isinstance(item, Item):
user = item.added_by_user
activities.append(Activity(
id=f"item-added-{item.id}",
event_type=ActivityEventType.ITEM_ADDED,
timestamp=item.created_at,
user=ActivityUser(id=user.id, name=user.name),
details={"item_name": item.name, "list_id": item.list_id},
message=f"{user.name or 'User'} added '{item.name}' to a list."
))
if item.is_complete and item.completed_by_user:
c_user = item.completed_by_user
activities.append(Activity(
id=f"item-completed-{item.id}",
event_type=ActivityEventType.ITEM_COMPLETED,
timestamp=item.updated_at, # This is an approximation
user=ActivityUser(id=c_user.id, name=c_user.name),
details={"item_name": item.name, "list_id": item.list_id},
message=f"{c_user.name or 'User'} purchased '{item.name}'."
))
activities.sort(key=lambda x: x.timestamp, reverse=True)
return activities[:limit]