Files
scriptshare-cursor/temp_api_backup/api/analytics.ts

275 lines
7.9 KiB
TypeScript
Raw Normal View History

import { db } from '@/lib/db';
import { scriptAnalytics, scripts } from '@/lib/db/schema';
import { eq, and, gte, lte, desc, count, sql } from 'drizzle-orm';
import { generateId, ApiError } from './index';
export interface TrackEventData {
scriptId: string;
eventType: 'view' | 'download' | 'share';
userId?: string;
userAgent?: string;
ipAddress?: string;
referrer?: string;
}
export interface AnalyticsFilters {
scriptId?: string;
eventType?: string;
startDate?: Date;
endDate?: Date;
userId?: string;
}
// Track an analytics event
export async function trackEvent(data: TrackEventData) {
try {
await db.insert(scriptAnalytics).values({
id: generateId(),
scriptId: data.scriptId,
eventType: data.eventType,
userId: data.userId,
userAgent: data.userAgent,
ipAddress: data.ipAddress,
referrer: data.referrer,
createdAt: new Date(),
});
// Update script counters based on event type
if (data.eventType === 'view') {
await db
.update(scripts)
.set({
viewCount: sql`${scripts.viewCount} + 1`,
})
.where(eq(scripts.id, data.scriptId));
} else if (data.eventType === 'download') {
await db
.update(scripts)
.set({
downloadCount: sql`${scripts.downloadCount} + 1`,
})
.where(eq(scripts.id, data.scriptId));
}
return { success: true };
} catch (error) {
throw new ApiError(`Failed to track event: ${error}`, 500);
}
}
// Get analytics events with filters
export async function getAnalyticsEvents(filters: AnalyticsFilters = {}) {
try {
let query = db.select().from(scriptAnalytics);
let conditions: any[] = [];
if (filters.scriptId) {
conditions.push(eq(scriptAnalytics.scriptId, filters.scriptId));
}
if (filters.eventType) {
conditions.push(eq(scriptAnalytics.eventType, filters.eventType));
}
if (filters.userId) {
conditions.push(eq(scriptAnalytics.userId, filters.userId));
}
if (filters.startDate) {
conditions.push(gte(scriptAnalytics.createdAt, filters.startDate));
}
if (filters.endDate) {
conditions.push(lte(scriptAnalytics.createdAt, filters.endDate));
}
if (conditions.length > 0) {
query = query.where(and(...conditions)) as any;
}
const events = await query.orderBy(desc(scriptAnalytics.createdAt));
return events;
} catch (error) {
throw new ApiError(`Failed to get analytics events: ${error}`, 500);
}
}
// Get analytics summary for a script
export async function getScriptAnalytics(scriptId: string, days: number = 30) {
try {
const startDate = new Date();
startDate.setDate(startDate.getDate() - days);
// Get event counts by type
const eventCounts = await db
.select({
eventType: scriptAnalytics.eventType,
count: count(scriptAnalytics.id),
})
.from(scriptAnalytics)
.where(
and(
eq(scriptAnalytics.scriptId, scriptId),
gte(scriptAnalytics.createdAt, startDate)
)
)
.groupBy(scriptAnalytics.eventType);
// Get daily activity
const dailyActivity = await db
.select({
date: sql<string>`DATE(${scriptAnalytics.createdAt})`,
eventType: scriptAnalytics.eventType,
count: count(scriptAnalytics.id),
})
.from(scriptAnalytics)
.where(
and(
eq(scriptAnalytics.scriptId, scriptId),
gte(scriptAnalytics.createdAt, startDate)
)
)
.groupBy(sql`DATE(${scriptAnalytics.createdAt})`, scriptAnalytics.eventType);
// Get referrer statistics
const referrers = await db
.select({
referrer: scriptAnalytics.referrer,
count: count(scriptAnalytics.id),
})
.from(scriptAnalytics)
.where(
and(
eq(scriptAnalytics.scriptId, scriptId),
gte(scriptAnalytics.createdAt, startDate)
)
)
.groupBy(scriptAnalytics.referrer)
.orderBy(desc(count(scriptAnalytics.id)))
.limit(10);
return {
eventCounts,
dailyActivity,
referrers,
periodDays: days,
};
} catch (error) {
throw new ApiError(`Failed to get script analytics: ${error}`, 500);
}
}
// Get platform-wide analytics (admin only)
export async function getPlatformAnalytics(days: number = 30) {
try {
const startDate = new Date();
startDate.setDate(startDate.getDate() - days);
// Total scripts and activity
const [totals] = await db
.select({
totalScripts: count(scripts.id),
approvedScripts: sql<number>`SUM(CASE WHEN ${scripts.isApproved} = 1 THEN 1 ELSE 0 END)`,
pendingScripts: sql<number>`SUM(CASE WHEN ${scripts.isApproved} = 0 THEN 1 ELSE 0 END)`,
})
.from(scripts);
// Activity by event type
const activityByType = await db
.select({
eventType: scriptAnalytics.eventType,
count: count(scriptAnalytics.id),
})
.from(scriptAnalytics)
.where(gte(scriptAnalytics.createdAt, startDate))
.groupBy(scriptAnalytics.eventType);
// Most popular scripts
const popularScripts = await db
.select({
scriptId: scriptAnalytics.scriptId,
scriptName: scripts.name,
views: count(scriptAnalytics.id),
})
.from(scriptAnalytics)
.innerJoin(scripts, eq(scriptAnalytics.scriptId, scripts.id))
.where(
and(
eq(scriptAnalytics.eventType, 'view'),
gte(scriptAnalytics.createdAt, startDate)
)
)
.groupBy(scriptAnalytics.scriptId, scripts.name)
.orderBy(desc(count(scriptAnalytics.id)))
.limit(10);
// Daily activity trends
const dailyTrends = await db
.select({
date: sql<string>`DATE(${scriptAnalytics.createdAt})`,
views: sql<number>`SUM(CASE WHEN ${scriptAnalytics.eventType} = 'view' THEN 1 ELSE 0 END)`,
downloads: sql<number>`SUM(CASE WHEN ${scriptAnalytics.eventType} = 'download' THEN 1 ELSE 0 END)`,
})
.from(scriptAnalytics)
.where(gte(scriptAnalytics.createdAt, startDate))
.groupBy(sql`DATE(${scriptAnalytics.createdAt})`)
.orderBy(sql`DATE(${scriptAnalytics.createdAt})`);
return {
totals,
activityByType,
popularScripts,
dailyTrends,
periodDays: days,
};
} catch (error) {
throw new ApiError(`Failed to get platform analytics: ${error}`, 500);
}
}
// Get user analytics
export async function getUserAnalytics(userId: string, days: number = 30) {
try {
const startDate = new Date();
startDate.setDate(startDate.getDate() - days);
// User's scripts performance
const userScriptsAnalytics = await db
.select({
scriptId: scripts.id,
scriptName: scripts.name,
views: scripts.viewCount,
downloads: scripts.downloadCount,
rating: scripts.rating,
ratingCount: scripts.ratingCount,
})
.from(scripts)
.where(eq(scripts.authorId, userId))
.orderBy(desc(scripts.viewCount));
// Recent activity on user's scripts
const recentActivity = await db
.select({
eventType: scriptAnalytics.eventType,
count: count(scriptAnalytics.id),
})
.from(scriptAnalytics)
.innerJoin(scripts, eq(scriptAnalytics.scriptId, scripts.id))
.where(
and(
eq(scripts.authorId, userId),
gte(scriptAnalytics.createdAt, startDate)
)
)
.groupBy(scriptAnalytics.eventType);
return {
userScripts: userScriptsAnalytics,
recentActivity,
periodDays: days,
};
} catch (error) {
throw new ApiError(`Failed to get user analytics: ${error}`, 500);
}
}