| from fastapi import APIRouter, HTTPException, Query |
| from typing import Optional |
| import uuid |
| from ...models.schemas import UserStatus |
| from ...core.database import db_manager |
| import logging |
| import time |
|
|
| router = APIRouter(prefix="/user", tags=["users"]) |
| logger = logging.getLogger("api.users") |
|
|
| @router.post("/init", response_model=UserStatus) |
| async def init_user(user_id: Optional[str] = None, referrer_id: Optional[str] = None): |
| async with db_manager.get_connection() as db: |
| if not user_id: |
| user_id = str(uuid.uuid4()) |
| |
| |
| cursor = await db.execute("SELECT * FROM users WHERE id = ?", (user_id,)) |
| user_row = await cursor.fetchone() |
| |
| if not user_row: |
| |
| cursor = await db.execute("SELECT COUNT(*) FROM users") |
| count = (await cursor.fetchone())[0] |
| |
| welcome_points = 100 |
| is_rewarded = 0 |
| if count < 200: |
| welcome_points = 10000 |
| is_rewarded = 1 |
| logger.info(f"New User {user_id} awarded 10,000 pts (Count: {count})") |
|
|
| await db.execute( |
| "INSERT INTO users (id, referrer_id, points, is_rewarded) VALUES (?, ?, ?, ?)", |
| (user_id, referrer_id, welcome_points, is_rewarded) |
| ) |
| if referrer_id: |
| await db.execute( |
| "INSERT OR IGNORE INTO referrals (referrer_id, referred_id, status) VALUES (?, ?, 'joined')", |
| (referrer_id, user_id) |
| ) |
| await db.execute("UPDATE users SET points = points + 50 WHERE id = ?", (referrer_id,)) |
| await db.commit() |
| else: |
| |
| user = dict(user_row) |
| if not user.get('is_rewarded'): |
| cursor = await db.execute("SELECT COUNT(*) FROM users") |
| count = (await cursor.fetchone())[0] |
| if count < 200: |
| await db.execute( |
| "UPDATE users SET points = points + 10000, is_rewarded = 1 WHERE id = ?", |
| (user_id,) |
| ) |
| await db.commit() |
| logger.info(f"Existing User {user_id} awarded 10,000 pts (Count: {count})") |
| |
| cursor = await db.execute("SELECT * FROM users WHERE id = ?", (user_id,)) |
| user = await cursor.fetchone() |
| return dict(user) |
|
|
| @router.get("/status/{user_id}", response_model=UserStatus) |
| async def get_user_status(user_id: str): |
| async with db_manager.get_connection() as db: |
| cursor = await db.execute("SELECT * FROM users WHERE id = ?", (user_id,)) |
| user = await cursor.fetchone() |
| if not user: |
| return await init_user(user_id) |
| return dict(user) |
|
|
| @router.post("/watch") |
| async def track_watch(user_id: str, minutes: int = 5): |
| """Real system: 1 Hour = 120 Points (2 points per minute)""" |
| points_per_min = 2 |
| pts_to_add = minutes * points_per_min |
| |
| async with db_manager.get_connection() as db: |
| await db.execute( |
| "UPDATE users SET watch_time_total = watch_time_total + ?, points = points + ? WHERE id = ?", |
| (minutes * 60, pts_to_add, user_id) |
| ) |
| |
| |
| cursor = await db.execute("SELECT watch_time_total, last_watch_reward_time, points FROM users WHERE id = ?", (user_id,)) |
| user_at = await cursor.fetchone() |
| |
| milestone = 2 * 3600 |
| if user_at["watch_time_total"] // milestone > user_at["last_watch_reward_time"] // milestone: |
| await db.execute( |
| "UPDATE users SET points = points + 200, last_watch_reward_time = ? WHERE id = ?", |
| (user_at["watch_time_total"], user_id) |
| ) |
| |
| await db.commit() |
| return {"status": "success", "added": pts_to_add, "total_points": user_at["points"] + pts_to_add} |
|
|
| @router.post("/share-click") |
| async def register_share_click(referrer_id: str): |
| """Award points for just clicks on shared links""" |
| async with db_manager.get_connection() as db: |
| await db.execute( |
| "UPDATE users SET points = points + 5 WHERE id = ?", |
| (referrer_id,) |
| ) |
| await db.commit() |
| return {"status": "success"} |
|
|
| @router.post("/redeem") |
| async def redeem_reward(user_id: str, reward_type: str): |
| """Redemption logic: Daily, Weekly, Monthly ad-free subscriptions""" |
| costs = { |
| "ad_free_1d": 700, |
| "ad_free_1w": 3000, |
| "ad_free_1m": 10000, |
| "fan_badge": 100000 |
| } |
| durations = { |
| "ad_free_1d": 1 * 24 * 3600, |
| "ad_free_1w": 7 * 24 * 3600, |
| "ad_free_1m": 30 * 24 * 3600 |
| } |
| |
| cost = costs.get(reward_type) |
| if not cost: |
| raise HTTPException(status_code=400, detail="Invalid reward type") |
| |
| async with db_manager.get_connection() as db: |
| cursor = await db.execute("SELECT points, ad_free_until FROM users WHERE id = ?", (user_id,)) |
| user = await cursor.fetchone() |
| |
| if not user or user["points"] < cost: |
| raise HTTPException(status_code=403, detail="Insufficient points") |
| |
| if reward_type.startswith("ad_free"): |
| now = int(time.time()) |
| base_time = max(now, user["ad_free_until"] or 0) |
| new_expiry = base_time + durations[reward_type] |
| |
| await db.execute( |
| "UPDATE users SET points = points - ?, ad_free_until = ? WHERE id = ?", |
| (cost, new_expiry, user_id) |
| ) |
| elif reward_type == "fan_badge": |
| await db.execute( |
| "UPDATE users SET points = points - ?, is_fan = 1 WHERE id = ?", |
| (cost, user_id) |
| ) |
| |
| await db.commit() |
| return {"status": "success", "reward": reward_type, "new_points": user["points"] - cost} |
|
|
| @router.post("/redeem-promo") |
| async def redeem_promo(user_id: str, code: str): |
| """Redeem a promo code for ad-free subscription""" |
| code = code.strip() |
| now = int(time.time()) |
| |
| |
| if code == "movidovip1": |
| |
| lifetime_expiry = 2147483647 |
| async with db_manager.get_connection() as db: |
| await db.execute("UPDATE users SET ad_free_until = ? WHERE id = ?", (lifetime_expiry, user_id)) |
| await db.commit() |
| return {"status": "success", "reward": "lifetime", "new_until": lifetime_expiry} |
| |
| if code == "vip-movido34": |
| |
| async with db_manager.get_connection() as db: |
| |
| cursor = await db.execute("SELECT * FROM user_promos WHERE user_id = ? AND code = ?", (user_id, code)) |
| if await cursor.fetchone(): |
| raise HTTPException(status_code=400, detail="لقد استخدمت هذا الكود بالفعل") |
| |
| |
| cursor = await db.execute("SELECT COUNT(*) FROM user_promos WHERE code = ?", (code,)) |
| usage_count = (await cursor.fetchone())[0] |
| if usage_count >= 300: |
| raise HTTPException(status_code=400, detail="عذراً، وصل هذا الكود للحد الأقصى من الاستخدام") |
| |
| |
| cursor = await db.execute("SELECT ad_free_until FROM users WHERE id = ?", (user_id,)) |
| user = await cursor.fetchone() |
| current_until = max(user["ad_free_until"] or 0, now) |
| new_until = current_until + (90 * 24 * 3600) |
| |
| await db.execute("INSERT INTO user_promos (user_id, code) VALUES (?, ?)", (user_id, code)) |
| await db.execute("UPDATE users SET ad_free_until = ? WHERE id = ?", (new_until, user_id)) |
| await db.commit() |
| return {"status": "success", "reward": "90_days", "new_until": new_until} |
|
|
| |
| async with db_manager.get_connection() as db: |
| cursor = await db.execute("SELECT * FROM promo_codes WHERE code = ? AND is_active = 1", (code,)) |
| promo = await cursor.fetchone() |
| |
| if not promo: |
| raise HTTPException(status_code=404, detail="كود غير صالح") |
| |
| if promo["current_uses"] >= promo["max_uses"]: |
| raise HTTPException(status_code=400, detail="انتهت صلاحية هذا الكود") |
| |
| |
| cursor = await db.execute("SELECT * FROM user_promos WHERE user_id = ? AND code = ?", (user_id, code)) |
| if await cursor.fetchone(): |
| raise HTTPException(status_code=400, detail="لقد استخدمت هذا الكود بالفعل") |
| |
| duration = (promo["duration_days"] or 30) * 24 * 3600 |
| |
| cursor = await db.execute("SELECT ad_free_until FROM users WHERE id = ?", (user_id,)) |
| user = await cursor.fetchone() |
| current_until = max(user["ad_free_until"] or 0, now) |
| new_until = current_until + duration |
| |
| await db.execute("INSERT INTO user_promos (user_id, code) VALUES (?, ?)", (user_id, code)) |
| await db.execute("UPDATE promo_codes SET current_uses = current_uses + 1 WHERE code = ?", (code,)) |
| await db.execute("UPDATE users SET ad_free_until = ? WHERE id = ?", (new_until, user_id)) |
| await db.commit() |
| |
| return {"status": "success", "reward": promo["reward_type"], "new_until": new_until} |
|
|
|
|
| @router.post("/history") |
| async def save_history(user_id: str, content_id: str, content_type: str, episode_id: Optional[str] = None, progress: int = 0): |
| async with db_manager.get_connection() as db: |
| |
| |
| |
| |
| |
| await db.execute( |
| """INSERT INTO watch_history (user_id, content_id, content_type, episode_id, progress) |
| VALUES (?, ?, ?, ?, ?)""", |
| (user_id, content_id, content_type, episode_id, progress) |
| ) |
| await db.commit() |
| return {"status": "saved"} |
|
|
| @router.get("/history/{user_id}") |
| async def get_history(user_id: str): |
| async with db_manager.get_connection() as db: |
| cursor = await db.execute( |
| """SELECT h.*, s.title, s.poster |
| FROM watch_history h |
| LEFT JOIN series s ON h.content_id = s.id AND h.content_type = 'series' |
| -- Join movies if we had a movies table populated similarly |
| WHERE h.user_id = ? |
| ORDER BY h.watched_at DESC LIMIT 50""", |
| (user_id,) |
| ) |
| history = await cursor.fetchall() |
| return [dict(row) for row in history] |
|
|