SurfSense/surfsense_backend/app/routes/incentive_tasks_routes.py
2026-01-26 23:32:30 -08:00

131 lines
4 KiB
Python

"""
Incentive Tasks API routes.
Allows users to complete tasks (like starring GitHub repo) to earn free pages.
Each task can only be completed once per user.
"""
from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from app.db import (
INCENTIVE_TASKS_CONFIG,
IncentiveTaskType,
User,
UserIncentiveTask,
get_async_session,
)
from app.schemas.incentive_tasks import (
CompleteTaskResponse,
IncentiveTaskInfo,
IncentiveTasksResponse,
TaskAlreadyCompletedResponse,
)
from app.users import current_active_user
router = APIRouter(prefix="/incentive-tasks", tags=["incentive-tasks"])
@router.get("", response_model=IncentiveTasksResponse)
async def get_incentive_tasks(
user: User = Depends(current_active_user),
session: AsyncSession = Depends(get_async_session),
) -> IncentiveTasksResponse:
"""
Get all available incentive tasks with the user's completion status.
"""
# Get all completed tasks for this user
result = await session.execute(
select(UserIncentiveTask).where(UserIncentiveTask.user_id == user.id)
)
completed_tasks = {task.task_type: task for task in result.scalars().all()}
# Build task list with completion status
tasks = []
total_pages_earned = 0
for task_type, config in INCENTIVE_TASKS_CONFIG.items():
completed_task = completed_tasks.get(task_type)
is_completed = completed_task is not None
if is_completed:
total_pages_earned += completed_task.pages_awarded
tasks.append(
IncentiveTaskInfo(
task_type=task_type,
title=config["title"],
description=config["description"],
pages_reward=config["pages_reward"],
action_url=config["action_url"],
completed=is_completed,
completed_at=completed_task.completed_at if completed_task else None,
)
)
return IncentiveTasksResponse(
tasks=tasks,
total_pages_earned=total_pages_earned,
)
@router.post(
"/{task_type}/complete",
response_model=CompleteTaskResponse | TaskAlreadyCompletedResponse,
)
async def complete_task(
task_type: IncentiveTaskType,
user: User = Depends(current_active_user),
session: AsyncSession = Depends(get_async_session),
) -> CompleteTaskResponse | TaskAlreadyCompletedResponse:
"""
Mark an incentive task as completed and award pages to the user.
Each task can only be completed once. If the task was already completed,
returns the existing completion information without awarding additional pages.
"""
# Validate task type exists in config
task_config = INCENTIVE_TASKS_CONFIG.get(task_type)
if not task_config:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=f"Unknown task type: {task_type}",
)
# Check if task was already completed
existing_task = await session.execute(
select(UserIncentiveTask).where(
UserIncentiveTask.user_id == user.id,
UserIncentiveTask.task_type == task_type,
)
)
existing = existing_task.scalar_one_or_none()
if existing:
return TaskAlreadyCompletedResponse(
success=False,
message="Task already completed",
completed_at=existing.completed_at,
)
# Create the task completion record
pages_reward = task_config["pages_reward"]
new_task = UserIncentiveTask(
user_id=user.id,
task_type=task_type,
pages_awarded=pages_reward,
)
session.add(new_task)
# Update user's pages_limit
user.pages_limit += pages_reward
await session.commit()
await session.refresh(user)
return CompleteTaskResponse(
success=True,
message=f"Task completed! You earned {pages_reward} pages.",
pages_awarded=pages_reward,
new_pages_limit=user.pages_limit,
)