Spaces:
Running
Running
| import { db } from '@/backend/services/firebase'; | |
| export async function checkEligibility(sessionId, toolKey, isOwnKey) { | |
| if (!sessionId) throw new Error("Authentication failed. No session ID provided."); | |
| const now = new Date(); | |
| const today = now.toLocaleDateString('en-CA'); // Robust YYYY-MM-DD | |
| // Map toolKey to prefix-aware usage key | |
| const usageKey = isOwnKey ? `own_${toolKey}` : `app_${toolKey}`; | |
| // 1. Fetch System Tier Settings | |
| const sysSnapshot = await db.ref('system/settings/tiers').once('value'); | |
| const tiers = sysSnapshot.val() || {}; | |
| const toolMapper = { | |
| 'count_transcript': 'transcript', | |
| 'count_translate': 'translate', | |
| 'count_srt_translate': 'srt_translator', | |
| 'count_tts': 'tts', | |
| 'count_subtitle': 'subtitle_gen', | |
| 'count_creator_text': 'content_creator', | |
| 'count_creator_image': 'ai_image' | |
| }; | |
| const tierToolKey = toolMapper[toolKey] || toolKey; | |
| let userKey, userData, userClass; | |
| if (sessionId === 'free_access') { | |
| userClass = 'FREE'; | |
| userData = { Usage: {}, Credits: 0, Class: 'FREE' }; | |
| } else { | |
| const snapshot = await db.ref('users').orderByChild('Active_Session_ID').equalTo(sessionId).once('value'); | |
| if (!snapshot.exists()) throw new Error("Invalid Membership ID. Please login again."); | |
| userKey = Object.keys(snapshot.val())[0]; | |
| userData = snapshot.val()[userKey]; | |
| if (userData.Status !== 'ACTIVE') throw new Error("Account suspended. Please contact admin."); | |
| userClass = userData.Class === 'MEMBER+' ? 'MEMBER_PLUS' : 'MEMBER'; | |
| } | |
| const tierConfig = tiers[userClass] || { tools: {}, ownTools: {}, limits: {}, ownLimits: {}, apiAccess: { app: true, own: true } }; | |
| // 2. CHECK API ACCESS PERMISSIONS | |
| if (isOwnKey && tierConfig.apiAccess?.own === false) { | |
| throw new Error(`OWN_API_RESTRICTED: Your ${userClass} class is not allowed to use private API keys.`); | |
| } | |
| if (!isOwnKey && tierConfig.apiAccess?.app === false) { | |
| throw new Error(`APP_API_RESTRICTED: Shared App API is currently disabled for your class.`); | |
| } | |
| // 3. CHECK SPECIFIC TOOL STATUS FOR TIER (Mode Specific) | |
| const toolMap = isOwnKey ? (tierConfig.ownTools || {}) : (tierConfig.tools || {}); | |
| if (toolMap[tierToolKey] === false) { | |
| throw new Error(`TOOL_DISABLED: This tool is disabled in ${isOwnKey ? 'Own API' : 'App API'} mode for ${userClass} class.`); | |
| } | |
| const usage = (userData.Last_Usage_Date === today) ? (userData.Usage || {}) : {}; | |
| // 4. CHECK LIMITS (Mode Specific) | |
| const limit = isOwnKey ? (tierConfig.ownLimits?.[tierToolKey] ?? -1) : (tierConfig.limits?.[tierToolKey] ?? -1); | |
| if (limit !== -1) { | |
| const currentCount = parseInt(usage[usageKey] || 0); | |
| if (currentCount >= limit) { | |
| throw new Error(`DAILY_QUOTA_REACHED: Your ${userClass} daily limit for ${isOwnKey ? 'Own' : 'App'} API has been reached.`); | |
| } | |
| } | |
| // 5. CHECK CREDITS (Only if using App API) | |
| let cost = 0; | |
| if (!isOwnKey) { | |
| const costMap = { | |
| 'count_transcript': 1, 'count_translate': 1, 'count_srt_translate': 5, | |
| 'count_tts': 3, 'count_subtitle': 1, 'count_creator_text': 1, 'count_creator_image': 5 | |
| }; | |
| cost = costMap[toolKey] || 1; | |
| if (userClass === 'MEMBER_PLUS') { | |
| const freeTools = ['count_transcript', 'count_translate', 'count_subtitle', 'count_creator_text']; | |
| if (freeTools.includes(toolKey)) cost = 0; | |
| } | |
| if (userClass === 'FREE') cost = 0; | |
| const currentCredits = userData.Credits || 0; | |
| if (cost > 0 && currentCredits < cost) { | |
| throw new Error(`INSUFFICIENT_BALANCE: This task costs ${cost} credits. Your balance is ${currentCredits}.`); | |
| } | |
| } | |
| return { userKey, userData, usageKey, cost, today, isGuest: (userClass === 'FREE'), isOwnKey }; | |
| } | |
| export async function commitDeduction(eligibilityData, toolKey) { | |
| if (!eligibilityData) return; | |
| const { userKey, userData, usageKey, cost, today, isGuest } = eligibilityData; | |
| if (isGuest) return; | |
| const updates = {}; | |
| if (cost > 0) { | |
| const newBalance = (userData.Credits || 0) - cost; | |
| updates[`users/${userKey}/Credits`] = newBalance >= 0 ? newBalance : 0; | |
| } | |
| if (userData.Last_Usage_Date !== today) { | |
| updates[`users/${userKey}/Last_Usage_Date`] = today; | |
| updates[`users/${userKey}/Usage`] = { [usageKey]: 1 }; | |
| } else { | |
| const currentUsage = (userData.Usage && userData.Usage[usageKey]) || 0; | |
| updates[`users/${userKey}/Usage/${usageKey}`] = currentUsage + 1; | |
| } | |
| await db.ref().update(updates); | |
| } | |
| export async function processFreePool(toolKey) { | |
| const today = new Date().toLocaleDateString('en-CA'); | |
| const poolPath = `system/daily_pool/${today}/app_${toolKey}`; // Default to app prefix for free pool | |
| const snapshot = await db.ref(poolPath).once('value'); | |
| const current = snapshot.val() || 0; | |
| await db.ref(poolPath).set(current + 1); | |
| } | |