diff --git a/prisma/seed-admin.ts b/prisma/seed-admin.ts new file mode 100644 index 0000000..31f0dd3 --- /dev/null +++ b/prisma/seed-admin.ts @@ -0,0 +1,117 @@ +import { PrismaClient } from '@prisma/client'; +import * as bcrypt from 'bcrypt'; + +/** + * Admin Seed Script + * + * Admin hesabı ve sınırsız kredi ataması: + * - Email: admin@contentgen.ai + * - Şifre: Admin123! + * - Rol: admin (sınırsız erişim) + * - Kredi: 999999 + */ + +const prisma = new PrismaClient(); + +async function main() { + console.log('🌱 Admin seed başlatılıyor...'); + + // 1. Admin rolü oluştur/bul + const adminRole = await prisma.role.upsert({ + where: { name: 'admin' }, + update: {}, + create: { + name: 'admin', + description: 'Sistem yöneticisi — sınırsız erişim', + isSystem: true, + }, + }); + console.log(`✅ Admin rolü: ${adminRole.id}`); + + // 2. User rolü oluştur/bul (her kullanıcıda olmalı) + const userRole = await prisma.role.upsert({ + where: { name: 'user' }, + update: {}, + create: { + name: 'user', + description: 'Standart kullanıcı', + isSystem: true, + }, + }); + + // 3. Admin kullanıcısı oluştur + const hashedPassword = await bcrypt.hash('Admin123!', 12); + + const adminUser = await prisma.user.upsert({ + where: { email: 'admin@contentgen.ai' }, + update: { + password: hashedPassword, + firstName: 'Admin', + lastName: 'ContentGen', + isActive: true, + }, + create: { + email: 'admin@contentgen.ai', + password: hashedPassword, + firstName: 'Admin', + lastName: 'ContentGen', + isActive: true, + }, + }); + console.log(`✅ Admin kullanıcısı: ${adminUser.id} (${adminUser.email})`); + + // 4. Rolleri ata (upsert ile — varsa atlama) + for (const role of [adminRole, userRole]) { + await prisma.userRole.upsert({ + where: { + userId_roleId: { + userId: adminUser.id, + roleId: role.id, + }, + }, + update: {}, + create: { + userId: adminUser.id, + roleId: role.id, + }, + }); + } + console.log('✅ Roller atandı: admin + user'); + + // 5. Sınırsız kredi yükle (mevcut bakiye kontrol et) + const existingTransactions = await prisma.creditTransaction.findMany({ + where: { userId: adminUser.id }, + }); + const currentBalance = existingTransactions.reduce((sum, tx) => sum + tx.amount, 0); + + if (currentBalance < 1000) { + const creditAmount = 999999 - currentBalance; + await prisma.creditTransaction.create({ + data: { + userId: adminUser.id, + amount: creditAmount, + type: 'grant', + description: 'Admin hesabı — sınırsız kredi', + balanceAfter: 999999, + }, + }); + console.log(`✅ Kredi yüklendi: +${creditAmount} (toplam: 999,999)`); + } else { + console.log(`ℹ️ Yeterli kredi mevcut: ${currentBalance}`); + } + + console.log('\n═══════════════════════════════════════'); + console.log('🔑 Admin Giriş Bilgileri:'); + console.log(' Email: admin@contentgen.ai'); + console.log(' Şifre: Admin123!'); + console.log('═══════════════════════════════════════\n'); +} + +main() + .catch((e) => { + console.error('❌ Seed hatası:', e); + process.exit(1); + }) + .finally(async () => { + await prisma.$disconnect(); + }); diff --git a/src/modules/admin/admin.service.ts b/src/modules/admin/admin.service.ts index 1ca96da..5c14cdc 100644 --- a/src/modules/admin/admin.service.ts +++ b/src/modules/admin/admin.service.ts @@ -122,26 +122,61 @@ export class AdminService { // ── Proje ve Render Yönetimi ────────────────────────────────────── - async getAllProjects() { - return this.prisma.project.findMany({ - include: { user: { select: { email: true, firstName: true, lastName: true } } }, - orderBy: { createdAt: 'desc' }, - }); + async getAllProjects(params: { page: number; limit: number; status?: string; userId?: string }) { + const { page, limit, status, userId } = params; + + // Status filtresini prisma tarafında idari bir kontrole dönüştürmek gerek + const whereCondition: any = { deletedAt: null }; + if (status) whereCondition.status = status; + if (userId) whereCondition.userId = userId; + + const [data, total] = await Promise.all([ + this.prisma.project.findMany({ + where: whereCondition, + include: { user: { select: { email: true, firstName: true, lastName: true } } }, + orderBy: { createdAt: 'desc' }, + skip: (page - 1) * limit, + take: limit, + }), + this.prisma.project.count({ where: whereCondition }), + ]); + + return { data, total, page, limit, totalPages: Math.ceil(total / limit) }; } - async getAllRenderJobs() { - return this.prisma.renderJob.findMany({ - include: { project: { select: { name: true } } }, - orderBy: { createdAt: 'desc' }, + async getAllRenderJobs(params: { page: number; limit: number; status?: string }) { + const { page, limit, status } = params; + + const whereCondition: any = {}; + if (status) whereCondition.status = status; + + const [data, total] = await Promise.all([ + this.prisma.renderJob.findMany({ + where: whereCondition, + include: { project: { select: { title: true } } }, + orderBy: { createdAt: 'desc' }, + skip: (page - 1) * limit, + take: limit, + }), + this.prisma.renderJob.count({ where: whereCondition }), + ]); + + return { data, total, page, limit, totalPages: Math.ceil(total / limit) }; + } + + async adminDeleteProject(projectId: string) { + return this.prisma.project.update({ + where: { id: projectId }, + data: { deletedAt: new Date() }, }); } // ── Kullanıcı Yönetimi ──────────────────────────────────────────── - async banUser(userId: string, isBanned: boolean) { + async setUserActive(userId: string, isActive: boolean) { return this.prisma.user.update({ where: { id: userId }, - data: { isActive: !isBanned }, + data: { isActive }, }); } diff --git a/src/modules/billing/billing.service.ts b/src/modules/billing/billing.service.ts index f555abd..00552f9 100644 --- a/src/modules/billing/billing.service.ts +++ b/src/modules/billing/billing.service.ts @@ -149,10 +149,35 @@ export class BillingService { return plans; } + /** + * Kullanıcının admin rolü olup olmadığını kontrol et + */ + private async isAdmin(userId: string): Promise { + const userRoles = await this.db.userRole.findMany({ + where: { userId }, + include: { role: true }, + }); + return userRoles.some((ur) => ur.role.name === 'admin' || ur.role.name === 'superadmin'); + } + /** * Kullanıcı kredi bakiyesi */ async getCreditBalance(userId: string) { + // Admin kullanıcılar için sınırsız kredi + const admin = await this.isAdmin(userId); + if (admin) { + return { + balance: 999999, + monthlyUsed: 0, + monthlyLimit: 999999, + plan: 'Admin', + remaining: 999999, + total: 999999, + isAdmin: true, + }; + } + const transactions = await this.db.creditTransaction.findMany({ where: { userId }, orderBy: { createdAt: 'desc' }, @@ -182,6 +207,10 @@ export class BillingService { balance, monthlyUsed, monthlyLimit, + plan: subscription?.plan?.displayName || 'Free', + remaining: balance, + total: monthlyLimit, + isAdmin: false, }; } @@ -189,6 +218,13 @@ export class BillingService { * Kredi harca (video üretimi için) */ async spendCredits(userId: string, amount: number, projectId: string, description: string) { + // Admin bypass — sınırsız kredi + const admin = await this.isAdmin(userId); + if (admin) { + this.logger.log(`🛡️ Admin kredi bypass: ${amount} — User: ${userId}, Project: ${projectId}`); + return { id: 'admin-bypass', amount: -amount, type: 'usage', description }; + } + const balance = await this.getCreditBalance(userId); if (balance.balance < amount) {