initial commit

This commit is contained in:
Kar k1
2025-08-30 18:18:57 +05:30
commit 7219108342
270 changed files with 70221 additions and 0 deletions

View File

@@ -0,0 +1,183 @@
import { NextRequest, NextResponse } from 'next/server'
import { withAdminAuth } from '@/lib/admin-middleware'
import { connectDB } from '@/lib/mongodb'
import { Billing } from '@/models/billing'
import { Transaction } from '@/models/transaction'
import { z } from 'zod'
const BillingUpdateSchema = z.object({
payment_status: z.enum(['pending', 'completed', 'failed', 'refunded']).optional(),
service_status: z.enum(['active', 'inactive', 'suspended', 'cancelled']).optional(),
amount: z.number().min(0).optional(),
notes: z.string().optional(),
})
export async function GET(request: NextRequest) {
return withAdminAuth(request, async (req, admin) => {
try {
await connectDB()
const { searchParams } = new URL(request.url)
const page = parseInt(searchParams.get('page') || '1')
const limit = parseInt(searchParams.get('limit') || '20')
const search = searchParams.get('search') || ''
const serviceType = searchParams.get('serviceType') || ''
const paymentStatus = searchParams.get('paymentStatus') || ''
const dateFrom = searchParams.get('dateFrom')
const dateTo = searchParams.get('dateTo')
const skip = (page - 1) * limit
// Build filter query
const filter: any = {}
if (search) {
filter.$or = [
{ user_email: { $regex: search, $options: 'i' } },
{ silicon_id: { $regex: search, $options: 'i' } },
{ service_name: { $regex: search, $options: 'i' } },
]
}
if (serviceType && serviceType !== 'all') {
filter.service_type = serviceType
}
if (paymentStatus && paymentStatus !== 'all') {
filter.payment_status = paymentStatus
}
if (dateFrom || dateTo) {
filter.created_at = {}
if (dateFrom) filter.created_at.$gte = new Date(dateFrom)
if (dateTo) filter.created_at.$lte = new Date(dateTo)
}
const [billings, totalBillings] = await Promise.all([
Billing.find(filter).sort({ created_at: -1 }).skip(skip).limit(limit),
Billing.countDocuments(filter),
])
const totalPages = Math.ceil(totalBillings / limit)
// Calculate summary statistics for current filter
const summaryStats = await Billing.aggregate([
{ $match: filter },
{
$group: {
_id: null,
totalAmount: { $sum: '$amount' },
totalTax: { $sum: '$tax_amount' },
totalDiscount: { $sum: '$discount_applied' },
completedCount: {
$sum: { $cond: [{ $eq: ['$payment_status', 'completed'] }, 1, 0] },
},
pendingCount: {
$sum: { $cond: [{ $eq: ['$payment_status', 'pending'] }, 1, 0] },
},
failedCount: {
$sum: { $cond: [{ $eq: ['$payment_status', 'failed'] }, 1, 0] },
},
},
},
])
return NextResponse.json({
billings,
pagination: {
currentPage: page,
totalPages,
totalBillings,
hasNext: page < totalPages,
hasPrev: page > 1,
},
summary: summaryStats[0] || {
totalAmount: 0,
totalTax: 0,
totalDiscount: 0,
completedCount: 0,
pendingCount: 0,
failedCount: 0,
},
})
} catch (error) {
console.error('Admin billing fetch error:', error)
return NextResponse.json({ error: 'Failed to fetch billing data' }, { status: 500 })
}
})
}
export async function POST(request: NextRequest) {
return withAdminAuth(request, async (req, admin) => {
try {
await connectDB()
const body = await request.json()
const { action, billingId, data } = body
if (action === 'update') {
const validatedData = BillingUpdateSchema.parse(data)
const billing = await Billing.findByIdAndUpdate(
billingId,
{
...validatedData,
updated_at: new Date(),
},
{ new: true, runValidators: true }
)
if (!billing) {
return NextResponse.json({ error: 'Billing record not found' }, { status: 404 })
}
return NextResponse.json({ billing })
}
if (action === 'refund') {
const billing = await Billing.findById(billingId)
if (!billing) {
return NextResponse.json({ error: 'Billing record not found' }, { status: 404 })
}
if (billing.payment_status !== 'paid') {
return NextResponse.json({ error: 'Can only refund paid payments' }, { status: 400 })
}
// Update billing status
billing.payment_status = 'refunded'
billing.status = 'cancelled'
await billing.save()
// Create refund transaction
const refundTransaction = new Transaction({
userId: billing.user_id,
type: 'credit',
amount: billing.amount,
description: `Refund for ${billing.service_name}`,
status: 'completed',
reference: `refund_${billing._id}`,
metadata: {
originalBillingId: billing._id,
refundedBy: admin.id,
refundReason: data.refundReason || 'Admin refund',
},
})
await refundTransaction.save()
return NextResponse.json({
billing,
transaction: refundTransaction,
message: 'Refund processed successfully',
})
}
return NextResponse.json({ error: 'Invalid action' }, { status: 400 })
} catch (error) {
console.error('Admin billing action error:', error)
return NextResponse.json({ error: 'Failed to perform billing action' }, { status: 500 })
}
})
}

View File

@@ -0,0 +1,155 @@
import { NextRequest, NextResponse } from 'next/server'
import { withAdminAuth } from '@/lib/admin-middleware'
import { connectDB } from '@/lib/mongodb'
import { User } from '@/models/user'
import { Transaction } from '@/models/transaction'
import { Billing } from '@/models/billing'
import { DeveloperRequest } from '@/models/developer-request'
export async function GET(request: NextRequest) {
return withAdminAuth(request, async (req, admin) => {
try {
await connectDB()
// Get current date for time-based queries
const now = new Date()
const startOfMonth = new Date(now.getFullYear(), now.getMonth(), 1)
const startOfWeek = new Date(now.setDate(now.getDate() - now.getDay()))
const startOfDay = new Date(now.getFullYear(), now.getMonth(), now.getDate())
// User statistics
const totalUsers = await User.countDocuments()
const activeUsers = await User.countDocuments({ lastLogin: { $gte: startOfMonth } })
const newUsersThisMonth = await User.countDocuments({ createdAt: { $gte: startOfMonth } })
const verifiedUsers = await User.countDocuments({ isVerified: true })
// Financial statistics
const totalRevenue = await Billing.aggregate([
{ $group: { _id: null, total: { $sum: '$amount' } } },
])
const monthlyRevenue = await Billing.aggregate([
{ $match: { created_at: { $gte: startOfMonth } } },
{ $group: { _id: null, total: { $sum: '$amount' } } },
])
const weeklyRevenue = await Billing.aggregate([
{ $match: { created_at: { $gte: startOfWeek } } },
{ $group: { _id: null, total: { $sum: '$amount' } } },
])
// Transaction statistics
const totalTransactions = await Transaction.countDocuments()
const monthlyTransactions = await Transaction.countDocuments({
createdAt: { $gte: startOfMonth },
})
// Service statistics
const totalServices = await Billing.countDocuments()
const activeServices = await Billing.countDocuments({
payment_status: 'paid',
service_status: 1, // 1 = active
})
// Developer requests
const totalDeveloperRequests = await DeveloperRequest.countDocuments()
const pendingDeveloperRequests = await DeveloperRequest.countDocuments({
status: 'pending',
})
// Recent activity (last 7 days)
const recentUsers = await User.find({ createdAt: { $gte: startOfWeek } })
.select('name email siliconId createdAt')
.sort({ createdAt: -1 })
.limit(10)
const recentTransactions = await Transaction.find({ createdAt: { $gte: startOfWeek } })
.populate('userId', 'name email siliconId')
.sort({ createdAt: -1 })
.limit(10)
// Service breakdown
const serviceBreakdown = await Billing.aggregate([
{
$group: {
_id: '$service_type',
count: { $sum: 1 },
revenue: { $sum: '$amount' },
},
},
{ $sort: { count: -1 } },
])
// Monthly growth data (last 6 months)
const sixMonthsAgo = new Date()
sixMonthsAgo.setMonth(sixMonthsAgo.getMonth() - 6)
const monthlyGrowth = await User.aggregate([
{ $match: { createdAt: { $gte: sixMonthsAgo } } },
{
$group: {
_id: {
year: { $year: '$createdAt' },
month: { $month: '$createdAt' },
},
count: { $sum: 1 },
},
},
{ $sort: { '_id.year': 1, '_id.month': 1 } },
])
const revenueGrowth = await Billing.aggregate([
{ $match: { created_at: { $gte: sixMonthsAgo } } },
{
$group: {
_id: {
year: { $year: '$created_at' },
month: { $month: '$created_at' },
},
revenue: { $sum: '$amount' },
},
},
{ $sort: { '_id.year': 1, '_id.month': 1 } },
])
return NextResponse.json({
users: {
total: totalUsers,
active: activeUsers,
newThisMonth: newUsersThisMonth,
verified: verifiedUsers,
verificationRate: totalUsers > 0 ? ((verifiedUsers / totalUsers) * 100).toFixed(1) : 0,
},
revenue: {
total: totalRevenue[0]?.total || 0,
monthly: monthlyRevenue[0]?.total || 0,
weekly: weeklyRevenue[0]?.total || 0,
},
transactions: {
total: totalTransactions,
monthly: monthlyTransactions,
},
services: {
total: totalServices,
active: activeServices,
breakdown: serviceBreakdown,
},
developerRequests: {
total: totalDeveloperRequests,
pending: pendingDeveloperRequests,
},
recentActivity: {
users: recentUsers,
transactions: recentTransactions,
},
growth: {
users: monthlyGrowth,
revenue: revenueGrowth,
},
})
} catch (error) {
console.error('Admin dashboard error:', error)
return NextResponse.json({ error: 'Failed to fetch dashboard data' }, { status: 500 })
}
})
}

View File

@@ -0,0 +1,187 @@
import { NextRequest, NextResponse } from 'next/server'
import { withAdminAuth } from '@/lib/admin-middleware'
import { connectDB } from '@/lib/mongodb'
import { User } from '@/models/user'
import { Transaction } from '@/models/transaction'
import { Billing } from '@/models/billing'
import { DeveloperRequest } from '@/models/developer-request'
export async function GET(request: NextRequest) {
return withAdminAuth(request, async (req, admin) => {
try {
await connectDB()
const { searchParams } = new URL(request.url)
const reportType = searchParams.get('type')
const format = searchParams.get('format') || 'json'
const dateFrom = searchParams.get('dateFrom')
const dateTo = searchParams.get('dateTo')
// Build date filter
const dateFilter: any = {}
if (dateFrom || dateTo) {
dateFilter.createdAt = {}
if (dateFrom) dateFilter.createdAt.$gte = new Date(dateFrom)
if (dateTo) dateFilter.createdAt.$lte = new Date(dateTo)
}
let data: any = {}
switch (reportType) {
case 'users':
data = await User.find(dateFilter)
.select('-password -refreshToken')
.sort({ createdAt: -1 })
break
case 'transactions':
data = await Transaction.find(dateFilter)
.populate('userId', 'name email siliconId')
.sort({ createdAt: -1 })
break
case 'billing':
data = await Billing.find(
dateFilter.createdAt ? { created_at: dateFilter.createdAt } : {}
).sort({ created_at: -1 })
break
case 'developer-requests':
const devFilter = dateFilter.createdAt ? { createdAt: dateFilter.createdAt } : {}
data = await (DeveloperRequest as any)
.find(devFilter)
.populate('userId', 'name email siliconId')
.sort({ createdAt: -1 })
break
case 'summary':
// Generate comprehensive summary report
const [users, transactions, billings, developerRequests] = await Promise.all([
User.find(dateFilter).select('-password -refreshToken'),
Transaction.find(dateFilter).populate('userId', 'name email siliconId'),
Billing.find(dateFilter.createdAt ? { created_at: dateFilter.createdAt } : {}),
(DeveloperRequest as any)
.find(dateFilter.createdAt ? { createdAt: dateFilter.createdAt } : {})
.populate('userId', 'name email siliconId'),
])
// Calculate summary statistics
const userStats = {
total: users.length,
verified: users.filter((u) => u.isVerified).length,
admins: users.filter((u) => u.role === 'admin').length,
totalBalance: users.reduce((sum, u) => sum + (u.balance || 0), 0),
}
const transactionStats = {
total: transactions.length,
totalAmount: transactions.reduce((sum, t) => sum + t.amount, 0),
credits: transactions.filter((t) => t.type === 'credit').length,
debits: transactions.filter((t) => t.type === 'debit').length,
}
const billingStats = {
total: billings.length,
totalRevenue: billings.reduce((sum, b) => sum + b.amount, 0),
completed: billings.filter((b) => b.payment_status === 'paid').length,
pending: billings.filter((b) => b.payment_status === 'pending').length,
}
const developerStats = {
total: developerRequests.length,
pending: developerRequests.filter((d) => d.status === 'pending').length,
inProgress: developerRequests.filter((d) => d.status === 'in_progress').length,
completed: developerRequests.filter((d) => d.status === 'completed').length,
}
data = {
summary: {
users: userStats,
transactions: transactionStats,
billing: billingStats,
developerRequests: developerStats,
},
users: users.slice(0, 100), // Limit for performance
transactions: transactions.slice(0, 100),
billings: billings.slice(0, 100),
developerRequests: developerRequests.slice(0, 100),
}
break
default:
return NextResponse.json({ error: 'Invalid report type' }, { status: 400 })
}
if (format === 'csv') {
// Convert to CSV format
const csv = convertToCSV(data, reportType)
return new NextResponse(csv, {
headers: {
'Content-Type': 'text/csv',
'Content-Disposition': `attachment; filename="${reportType}_report_${new Date().toISOString().split('T')[0]}.csv"`,
},
})
}
return NextResponse.json({
reportType,
generatedAt: new Date().toISOString(),
generatedBy: admin.name,
dateRange: { from: dateFrom, to: dateTo },
data,
})
} catch (error) {
console.error('Admin reports error:', error)
return NextResponse.json({ error: 'Failed to generate report' }, { status: 500 })
}
})
}
function convertToCSV(data: any, reportType: string): string {
if (!Array.isArray(data)) {
if (reportType === 'summary' && data.summary) {
// For summary reports, create a simple CSV with key metrics
const lines = [
'Metric,Value',
`Total Users,${data.summary.users.total}`,
`Verified Users,${data.summary.users.verified}`,
`Admin Users,${data.summary.users.admins}`,
`Total Balance,${data.summary.users.totalBalance}`,
`Total Transactions,${data.summary.transactions.total}`,
`Transaction Amount,${data.summary.transactions.totalAmount}`,
`Total Billing Records,${data.summary.billing.total}`,
`Total Revenue,${data.summary.billing.totalRevenue}`,
`Developer Requests,${data.summary.developerRequests.total}`,
]
return lines.join('\n')
}
return 'No data available'
}
if (data.length === 0) {
return 'No data available'
}
// Get headers from first object
const headers = Object.keys(data[0]).filter(
(key) => typeof data[0][key] !== 'object' || data[0][key] === null
)
// Create CSV content
const csvHeaders = headers.join(',')
const csvRows = data.map((row) =>
headers
.map((header) => {
const value = row[header]
if (value === null || value === undefined) return ''
if (typeof value === 'string' && value.includes(',')) {
return `"${value.replace(/"/g, '""')}"`
}
return value
})
.join(',')
)
return [csvHeaders, ...csvRows].join('\n')
}

View File

@@ -0,0 +1,200 @@
import { NextRequest, NextResponse } from 'next/server'
import { withAdminAuth } from '@/lib/admin-middleware'
import { connectDB } from '@/lib/mongodb'
import { Billing } from '@/models/billing'
import { DeveloperRequest } from '@/models/developer-request'
export async function GET(request: NextRequest) {
return withAdminAuth(request, async (req, admin) => {
try {
await connectDB()
const { searchParams } = new URL(request.url)
const page = parseInt(searchParams.get('page') || '1')
const limit = parseInt(searchParams.get('limit') || '20')
const serviceType = searchParams.get('serviceType') || ''
const status = searchParams.get('status') || ''
const dateFrom = searchParams.get('dateFrom')
const dateTo = searchParams.get('dateTo')
const skip = (page - 1) * limit
// Build filter query for billing services
const billingFilter: any = {}
if (serviceType && serviceType !== 'all') {
billingFilter.service_type = serviceType
}
if (status && status !== 'all') {
billingFilter.service_status = status
}
if (dateFrom || dateTo) {
billingFilter.created_at = {}
if (dateFrom) billingFilter.created_at.$gte = new Date(dateFrom)
if (dateTo) billingFilter.created_at.$lte = new Date(dateTo)
}
// Fetch billing services
const [billingServices, totalBillingServices] = await Promise.all([
Billing.find(billingFilter).sort({ created_at: -1 }).skip(skip).limit(limit),
Billing.countDocuments(billingFilter),
])
// Build filter for developer requests
const devRequestFilter: any = {}
if (status && status !== 'all') {
devRequestFilter.status = status
}
if (dateFrom || dateTo) {
devRequestFilter.createdAt = {}
if (dateFrom) devRequestFilter.createdAt.$gte = new Date(dateFrom)
if (dateTo) devRequestFilter.createdAt.$lte = new Date(dateTo)
}
// Fetch developer requests
const [developerRequests, totalDeveloperRequests] = await Promise.all([
(DeveloperRequest as any)
.find(devRequestFilter)
.populate('userId', 'name email siliconId')
.sort({ createdAt: -1 })
.skip(skip)
.limit(limit),
(DeveloperRequest as any).countDocuments(devRequestFilter),
])
// Service statistics
const serviceStats = await Billing.aggregate([
{
$group: {
_id: '$service_type',
count: { $sum: 1 },
revenue: { $sum: '$amount' },
activeServices: {
$sum: { $cond: [{ $eq: ['$service_status', 'active'] }, 1, 0] },
},
},
},
{ $sort: { count: -1 } },
])
// Status breakdown
const statusBreakdown = await Billing.aggregate([
{
$group: {
_id: '$service_status',
count: { $sum: 1 },
},
},
])
const totalPages = Math.ceil(Math.max(totalBillingServices, totalDeveloperRequests) / limit)
return NextResponse.json({
billingServices,
developerRequests,
serviceStats,
statusBreakdown,
pagination: {
currentPage: page,
totalPages,
totalBillingServices,
totalDeveloperRequests,
hasNext: page < totalPages,
hasPrev: page > 1,
},
})
} catch (error) {
console.error('Admin services fetch error:', error)
return NextResponse.json({ error: 'Failed to fetch services data' }, { status: 500 })
}
})
}
export async function POST(request: NextRequest) {
return withAdminAuth(request, async (req, admin) => {
try {
await connectDB()
const body = await request.json()
const { action, serviceId, serviceType, data } = body
if (action === 'updateBilling') {
const billing = await Billing.findByIdAndUpdate(
serviceId,
{
service_status: data.service_status,
updated_at: new Date(),
},
{ new: true }
)
if (!billing) {
return NextResponse.json({ error: 'Service not found' }, { status: 404 })
}
return NextResponse.json({ service: billing })
}
if (action === 'updateDeveloperRequest') {
const developerRequest = await (DeveloperRequest as any)
.findByIdAndUpdate(
serviceId,
{
status: data.status,
assignedDeveloper: data.assignedDeveloper,
estimatedCompletionDate: data.estimatedCompletionDate,
notes: data.notes,
updatedAt: new Date(),
},
{ new: true }
)
.populate('userId', 'name email siliconId')
if (!developerRequest) {
return NextResponse.json({ error: 'Developer request not found' }, { status: 404 })
}
return NextResponse.json({ service: developerRequest })
}
if (action === 'cancelService') {
if (serviceType === 'billing') {
const billing = await Billing.findByIdAndUpdate(
serviceId,
{
service_status: 'cancelled',
updated_at: new Date(),
},
{ new: true }
)
return NextResponse.json({ service: billing })
}
if (serviceType === 'developer') {
const updatedDeveloperRequest = await (DeveloperRequest as any)
.findByIdAndUpdate(
serviceId,
{
status: 'cancelled',
updatedAt: new Date(),
},
{ new: true }
)
.populate('userId', 'name email siliconId')
return NextResponse.json({ service: updatedDeveloperRequest })
}
}
return NextResponse.json({ error: 'Invalid action or service type' }, { status: 400 })
} catch (error) {
console.error('Admin service action error:', error)
return NextResponse.json({ error: 'Failed to perform service action' }, { status: 500 })
}
})
}

View File

@@ -0,0 +1,117 @@
import { NextRequest, NextResponse } from 'next/server'
import { withAdminAuth } from '@/lib/admin-middleware'
import { connectDB } from '@/lib/mongodb'
import { User } from '@/models/user'
import { z } from 'zod'
import { getSystemSettings, updateSystemSettings } from '@/lib/system-settings'
const SystemSettingsSchema = z.object({
maintenanceMode: z.boolean().optional(),
registrationEnabled: z.boolean().optional(),
emailVerificationRequired: z.boolean().optional(),
maxUserBalance: z.number().min(0).optional(),
defaultUserRole: z.enum(['user', 'admin']).optional(),
systemMessage: z.string().optional(),
paymentGatewayEnabled: z.boolean().optional(),
developerHireEnabled: z.boolean().optional(),
vpsDeploymentEnabled: z.boolean().optional(),
kubernetesDeploymentEnabled: z.boolean().optional(),
vpnServiceEnabled: z.boolean().optional(),
})
// System settings are now managed by the system-settings service
export async function GET(request: NextRequest) {
return withAdminAuth(request, async (req, admin) => {
try {
await connectDB()
// Get system statistics
const totalUsers = await User.countDocuments()
const adminUsers = await User.countDocuments({ role: 'admin' })
const verifiedUsers = await User.countDocuments({ isVerified: true })
const unverifiedUsers = await User.countDocuments({ isVerified: false })
// Get recent admin activities (mock data for now)
const recentActivities = [
{
id: '1',
action: 'User role updated',
details: 'Changed user role from user to admin',
timestamp: new Date().toISOString(),
adminName: admin.name,
},
]
return NextResponse.json({
settings: await getSystemSettings(),
statistics: {
totalUsers,
adminUsers,
verifiedUsers,
unverifiedUsers,
},
recentActivities,
})
} catch (error) {
console.error('Admin settings fetch error:', error)
return NextResponse.json({ error: 'Failed to fetch system settings' }, { status: 500 })
}
})
}
export async function POST(request: NextRequest) {
return withAdminAuth(request, async (req, admin) => {
try {
const body = await request.json()
const { action, settings } = body
if (action === 'updateSettings') {
const validatedSettings = SystemSettingsSchema.parse(settings)
// Update system settings
const updatedSettings = {
...validatedSettings,
lastUpdated: new Date().toISOString(),
updatedBy: admin.name,
}
await updateSystemSettings(updatedSettings)
return NextResponse.json({
settings: await getSystemSettings(),
message: 'Settings updated successfully',
})
}
if (action === 'clearCache') {
// Mock cache clearing - in a real app, this would clear Redis/memory cache
return NextResponse.json({
message: 'System cache cleared successfully',
})
}
if (action === 'backupDatabase') {
// Mock database backup - in a real app, this would trigger a backup process
return NextResponse.json({
message: 'Database backup initiated successfully',
backupId: `backup_${Date.now()}`,
})
}
if (action === 'sendSystemNotification') {
const { message, targetUsers } = body
// Mock system notification - in a real app, this would send notifications
return NextResponse.json({
message: `System notification sent to ${targetUsers} users`,
notificationId: `notif_${Date.now()}`,
})
}
return NextResponse.json({ error: 'Invalid action' }, { status: 400 })
} catch (error) {
console.error('Admin settings update error:', error)
return NextResponse.json({ error: 'Failed to update system settings' }, { status: 500 })
}
})
}

View File

@@ -0,0 +1,163 @@
import { NextRequest, NextResponse } from 'next/server'
import { withAdminAuth } from '@/lib/admin-middleware'
import { connectDB } from '@/lib/mongodb'
import { User } from '@/models/user'
import { z } from 'zod'
const UserUpdateSchema = z.object({
name: z.string().min(1).optional(),
email: z.string().email().optional(),
role: z.enum(['user', 'admin']).optional(),
isVerified: z.boolean().optional(),
balance: z.number().min(0).optional(),
})
const UserCreateSchema = z.object({
name: z.string().min(1),
email: z.string().email(),
password: z.string().min(6),
role: z.enum(['user', 'admin']).default('user'),
isVerified: z.boolean().default(false),
balance: z.number().min(0).default(0),
})
export async function GET(request: NextRequest) {
return withAdminAuth(request, async (req, admin) => {
try {
await connectDB()
const { searchParams } = new URL(request.url)
const page = parseInt(searchParams.get('page') || '1')
const limit = parseInt(searchParams.get('limit') || '20')
const search = searchParams.get('search') || ''
const role = searchParams.get('role') || ''
const verified = searchParams.get('verified') || ''
const skip = (page - 1) * limit
// Build filter query
const filter: any = {}
if (search) {
filter.$or = [
{ name: { $regex: search, $options: 'i' } },
{ email: { $regex: search, $options: 'i' } },
{ siliconId: { $regex: search, $options: 'i' } },
]
}
if (role && role !== 'all') {
filter.role = role
}
if (verified && verified !== 'all') {
filter.isVerified = verified === 'true'
}
const [users, totalUsers] = await Promise.all([
User.find(filter)
.select('-password -refreshToken')
.sort({ createdAt: -1 })
.skip(skip)
.limit(limit),
User.countDocuments(filter),
])
const totalPages = Math.ceil(totalUsers / limit)
return NextResponse.json({
users,
pagination: {
currentPage: page,
totalPages,
totalUsers,
hasNext: page < totalPages,
hasPrev: page > 1,
},
})
} catch (error) {
console.error('Admin users fetch error:', error)
return NextResponse.json({ error: 'Failed to fetch users' }, { status: 500 })
}
})
}
export async function POST(request: NextRequest) {
return withAdminAuth(request, async (req, admin) => {
try {
await connectDB()
const body = await request.json()
const { action, userId, data } = body
if (action === 'update') {
const validatedData = UserUpdateSchema.parse(data)
const user = await User.findByIdAndUpdate(userId, validatedData, {
new: true,
runValidators: true,
}).select('-password -refreshToken')
if (!user) {
return NextResponse.json({ error: 'User not found' }, { status: 404 })
}
return NextResponse.json({ user })
}
if (action === 'create') {
const validatedData = UserCreateSchema.parse(data)
// Check if user already exists
const existingUser = await User.findOne({ email: validatedData.email })
if (existingUser) {
return NextResponse.json(
{ error: 'User with this email already exists' },
{ status: 400 }
)
}
// Generate unique Silicon ID
const generateSiliconId = () => {
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
let result = 'SP'
for (let i = 0; i < 8; i++) {
result += chars.charAt(Math.floor(Math.random() * chars.length))
}
return result
}
let siliconId = generateSiliconId()
while (await User.findOne({ siliconId })) {
siliconId = generateSiliconId()
}
const user = new User({
...validatedData,
siliconId,
provider: 'local',
})
await user.save()
const userResponse = await User.findById(user._id).select('-password -refreshToken')
return NextResponse.json({ user: userResponse })
}
if (action === 'delete') {
const user = await User.findByIdAndDelete(userId)
if (!user) {
return NextResponse.json({ error: 'User not found' }, { status: 404 })
}
return NextResponse.json({ message: 'User deleted successfully' })
}
return NextResponse.json({ error: 'Invalid action' }, { status: 400 })
} catch (error) {
console.error('Admin user action error:', error)
return NextResponse.json({ error: 'Failed to perform user action' }, { status: 500 })
}
})
}