""" Модуль Хронология - индивидуальные линейки активности """ from fastapi import APIRouter, Depends, Query, HTTPException from sqlalchemy.orm import Session from sqlalchemy import text from typing import List from datetime import datetime from app.core.database import get_manictime_db from app.core.security import get_current_user from app.models.service_db import AppUser from app.schemas.timeline import TimelineActivityResponse, UserActivity, ActivitySegment router = APIRouter() @router.get("/user-activity", response_model=TimelineActivityResponse) async def get_user_activity( date: str = Query(..., description="Дата (YYYY-MM-DD)"), user_ids: List[int] = Query(..., description="Список ID пользователей"), current_user: AppUser = Depends(get_current_user), manictime_db: Session = Depends(get_manictime_db) ): """ Получение активности пользователей за указанную дату для построения линеек """ try: # Валидация даты date_dt = datetime.strptime(date, "%Y-%m-%d") date_start = date_dt.strftime("%Y-%m-%d 00:00:00") date_end = date_dt.strftime("%Y-%m-%d 23:59:59") if not user_ids: raise HTTPException(status_code=400, detail="Необходимо указать хотя бы одного пользователя") # Получение информации о пользователях users_query = text(""" SELECT "UserId", "DisplayName" FROM "Ar_User" WHERE "UserId" = ANY(:user_ids) """) users_result = manictime_db.execute(users_query, {"user_ids": user_ids}) users_map = {row.UserId: row.DisplayName for row in users_result} if not users_map: raise HTTPException(status_code=404, detail="Пользователи не найдены") # Получение активности с шкалы Computer usage activity_query = text(""" SELECT t."OwnerId", a."Name", a."StartLocalTime", a."EndLocalTime" FROM "Ar_Activity" a JOIN "Ar_Timeline" t ON a."ReportId" = t."ReportId" WHERE t."SchemaName" = 'ManicTime/Computer usage' AND t."OwnerId" = ANY(:user_ids) AND a."StartLocalTime" >= :date_start AND a."EndLocalTime" <= :date_end ORDER BY t."OwnerId", a."StartLocalTime" """) activity_result = manictime_db.execute( activity_query, {"user_ids": user_ids, "date_start": date_start, "date_end": date_end} ) # Получение продуктивного времени productive_query = text(""" SELECT t."OwnerId", a."StartLocalTime", a."EndLocalTime" FROM "Ar_Activity" a JOIN "Ar_Timeline" t ON a."ReportId" = t."ReportId" JOIN "Ar_CommonGroup" cg ON a."CommonGroupId" = cg."CommonId" JOIN "Ar_CategoryGroup" cag ON cg."CommonId" = cag."CommonGroupId" JOIN "Ar_Category" c ON cag."CategoryId" = c."CategoryId" WHERE c."Name" = 'Productive' AND t."OwnerId" = ANY(:user_ids) AND a."StartLocalTime" >= :date_start AND a."EndLocalTime" <= :date_end ORDER BY t."OwnerId", a."StartLocalTime" """) productive_result = manictime_db.execute( productive_query, {"user_ids": user_ids, "date_start": date_start, "date_end": date_end} ) # Группировка по пользователям user_activities = {} for row in activity_result: user_id = row.OwnerId if user_id not in user_activities: user_activities[user_id] = { "user_id": user_id, "display_name": users_map.get(user_id, f"User {user_id}"), "segments": [] } # Определение типа сегмента segment_type = "Active" if row.Name == "Away": segment_type = "Away" elif row.Name == "Session Locked": segment_type = "Session Locked" elif row.Name == "Power Off": segment_type = "Power Off" user_activities[user_id]["segments"].append( { "type": segment_type, "start": row.StartLocalTime.isoformat(), "end": row.EndLocalTime.isoformat() } ) # Добавление продуктивного времени for row in productive_result: user_id = row.OwnerId if user_id in user_activities: user_activities[user_id]["segments"].append( { "type": "Productive", "start": row.StartLocalTime.isoformat(), "end": row.EndLocalTime.isoformat() } ) # Формирование ответа activities = [] for user_id in user_ids: if user_id in user_activities: activities.append(UserActivity(**user_activities[user_id])) return TimelineActivityResponse(date=date, activities=activities) except ValueError as e: raise HTTPException(status_code=400, detail=f"Неверный формат даты: {str(e)}") except Exception as e: raise HTTPException(status_code=500, detail=f"Ошибка при получении данных: {str(e)}")