Initial commit: Базовая структура сайта

This commit is contained in:
2026-02-11 12:06:30 +05:00
parent b41f161e8f
commit d9a2ad7f15
62 changed files with 3901 additions and 0 deletions

146
backend/app/api/v1/timeline.py Executable file
View File

@@ -0,0 +1,146 @@
"""
Модуль Хронология - индивидуальные линейки активности
"""
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)}")