147 lines
6.0 KiB
Python
147 lines
6.0 KiB
Python
|
|
"""
|
|||
|
|
Модуль Хронология - индивидуальные линейки активности
|
|||
|
|
"""
|
|||
|
|
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)}")
|
|||
|
|
|