HotTRDealsBackend/prisma/seed.js
2026-01-25 17:50:56 +00:00

361 lines
11 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// prisma/seed.js
const { PrismaClient, DealStatus, SaleType, AffiliateType } = require("@prisma/client")
const bcrypt = require("bcryptjs")
const fs = require("fs")
const path = require("path")
const prisma = new PrismaClient()
function randInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min
}
// Stabil gerçek foto linkleri (redirect yok, hotlink derdi az)
function realImage(seed, w = 1200, h = 900) {
return `https://picsum.photos/seed/${encodeURIComponent(seed)}/${w}/${h}`
}
// Son N gün içinde random tarih
function randomDateWithinLastDays(days = 5) {
const now = Date.now()
const maxBack = days * 24 * 60 * 60 * 1000
const offset = randInt(0, maxBack)
return new Date(now - offset)
}
function normalizeSlug(s) {
return String(s ?? "").trim().toLowerCase()
}
async function upsertTagBySlug(slug, name) {
const s = normalizeSlug(slug)
return prisma.tag.upsert({
where: { slug: s },
update: { name },
create: { slug: s, name },
})
}
async function attachTagsToDeal(dealId, tagSlugs) {
const unique = [...new Set((tagSlugs ?? []).map(normalizeSlug).filter(Boolean))]
if (!unique.length) return
const tags = await prisma.$transaction(
unique.map((slug) =>
prisma.tag.upsert({
where: { slug },
update: {},
create: { slug, name: slug },
})
)
)
await prisma.dealTag.createMany({
data: tags.map((t) => ({ dealId, tagId: t.id })),
skipDuplicates: true,
})
}
function loadCategoriesJson(filePath) {
const raw = fs.readFileSync(filePath, "utf-8")
const arr = JSON.parse(raw)
if (!Array.isArray(arr)) throw new Error("categories.json array olmalı")
const cats = arr.map((c) => ({
id: Number(c.id),
name: String(c.name ?? "").trim(),
slug: normalizeSlug(c.slug),
parentId: c.parentId === null || c.parentId === undefined ? null : Number(c.parentId),
}))
for (const c of cats) {
if (!Number.isInteger(c.id)) throw new Error(`Category id invalid: ${c.id}`)
if (!c.name) throw new Error(`Category name boş olamaz (id=${c.id})`)
if (!c.slug) throw new Error(`Category slug boş olamaz (id=${c.id})`)
}
const has0 = cats.some((c) => c.id === 0)
if (!has0) {
cats.unshift({ id: 0, name: "Undefined", slug: "undefined", parentId: null })
}
const idSet = new Set()
const slugSet = new Set()
for (const c of cats) {
if (idSet.has(c.id)) throw new Error(`categories.json duplicate id: ${c.id}`)
idSet.add(c.id)
if (slugSet.has(c.slug)) throw new Error(`categories.json duplicate slug: ${c.slug}`)
slugSet.add(c.slug)
}
return cats
}
async function seedCategoriesFromJson(categoriesFilePath) {
const categories = loadCategoriesJson(categoriesFilePath)
await prisma.$transaction(
categories.map((c) =>
prisma.category.upsert({
where: { id: c.id },
update: {
name: c.name,
slug: c.slug,
},
create: {
id: c.id,
name: c.name,
slug: c.slug,
parentId: null,
},
})
),
{ timeout: 60_000 }
)
await prisma.$transaction(
categories.map((c) =>
prisma.category.update({
where: { id: c.id },
data: { parentId: c.parentId },
})
),
{ timeout: 60_000 }
)
await prisma.$executeRawUnsafe(`
SELECT setval(
pg_get_serial_sequence('"Category"', 'id'),
COALESCE((SELECT MAX(id) FROM "Category"), 0) + 1,
false
);
`)
return { count: categories.length }
}
// 30 deal seed + her deal'a 3 foto + score 0-200 + tarih dağılımı:
// - %70: son 5 gün
// - %30: 10 gün önce civarı (9-11 gün arası)
async function seedDeals30({ userId, sellerId, categoryId }) {
const baseItems = [
{ title: "Samsung 990 PRO 1TB NVMe SSD", price: 3299.99, url: "https://example.com/samsung-990pro-1tb", q: "nvme ssd" },
{ title: "Logitech MX Master 3S Mouse", price: 2499.9, url: "https://example.com/mx-master-3s", q: "wireless mouse" },
{ title: "Sony WH-1000XM5 Kulaklık", price: 9999.0, url: "https://example.com/sony-xm5", q: "headphones" },
{ title: "Apple AirPods Pro 2", price: 8499.0, url: "https://example.com/airpods-pro-2", q: "earbuds" },
{ title: "Anker 65W GaN Şarj Aleti", price: 899.0, url: "https://example.com/anker-65w-gan", q: "charger" },
{ title: "Kindle Paperwhite 16GB", price: 5199.0, url: "https://example.com/kindle-paperwhite", q: "ebook reader" },
{ title: 'Dell 27" 144Hz Monitör', price: 7999.0, url: "https://example.com/dell-27-144hz", q: "gaming monitor" },
{ title: "TP-Link Wi-Fi 6 Router", price: 1999.0, url: "https://example.com/tplink-wifi6", q: "wifi router" },
{ title: "Razer Huntsman Mini Klavye", price: 3499.0, url: "https://example.com/huntsman-mini", q: "mechanical keyboard" },
{ title: "WD Elements 2TB Harici Disk", price: 2399.0, url: "https://example.com/wd-elements-2tb", q: "external hard drive" },
{ title: "Samsung T7 Shield 1TB SSD", price: 2799.0, url: "https://example.com/samsung-t7-shield", q: "portable ssd" },
{ title: "Xiaomi Mi Band 8", price: 1399.0, url: "https://example.com/mi-band-8", q: "smart band" },
{ title: "Philips Airfryer 6.2L", price: 5999.0, url: "https://example.com/philips-airfryer", q: "air fryer" },
{ title: "Dyson V12 Detect Slim", price: 21999.0, url: "https://example.com/dyson-v12", q: "vacuum cleaner" },
{ title: "Nespresso Vertuo Kahve Makinesi", price: 6999.0, url: "https://example.com/nespresso-vertuo", q: "coffee machine" },
]
// 30'a tamamlamak için ikinci bir set üret (title/url benzersiz olsun)
const items = []
for (let i = 0; i < 30; i++) {
const base = baseItems[i % baseItems.length]
const n = i + 1
items.push({
title: `${base.title} #${n}`,
price: Number((base.price * (0.9 + (randInt(0, 30) / 100))).toFixed(2)),
url: `${base.url}?seed=${n}`,
q: base.q,
})
}
for (let i = 0; i < items.length; i++) {
const it = items[i]
// %30'u 9-11 gün önce, %70'i son 5 gün
const older = Math.random() < 0.3
const createdAt = older
? new Date(Date.now() - randInt(9, 11) * 24 * 60 * 60 * 1000 - randInt(0, 12) * 60 * 60 * 1000)
: randomDateWithinLastDays(5)
// Not: modelinde score yoksa score satırını sil
const dealData = {
title: it.title,
description: "Seed test deal açıklaması (otomatik üretim).",
url: it.url,
price: it.price,
status: DealStatus.ACTIVE,
saletype: SaleType.ONLINE,
affiliateType: AffiliateType.NON_AFFILIATE,
commentCount: randInt(0, 25),
userId,
sellerId,
categoryId,
score: randInt(0, 200),
createdAt,
}
const existing = await prisma.deal.findFirst({
where: { url: it.url },
select: { id: true },
})
const deal = existing
? await prisma.deal.update({ where: { id: existing.id }, data: dealData })
: await prisma.deal.create({ data: dealData })
await prisma.dealImage.deleteMany({ where: { dealId: deal.id } })
await prisma.dealImage.createMany({
data: [
{ dealId: deal.id, imageUrl: realImage(`${it.q}-${i}-1`), order: 0 },
{ dealId: deal.id, imageUrl: realImage(`${it.q}-${i}-2`), order: 1 },
{ dealId: deal.id, imageUrl: realImage(`${it.q}-${i}-3`), order: 2 },
],
})
}
}
async function main() {
const hashedPassword = "$2b$10$PVfLq2NmcGmKbhE5VK3yNeVj46O/1w2p/2BNu4h1CYacqSgkCcoCW"
// ---------- USERS ----------
const admin = await prisma.user.upsert({
where: { email: "test" },
update: {},
create: {
username: "test",
email: "test",
passwordHash: hashedPassword,
role: "ADMIN",
},
})
const user = await prisma.user.upsert({
where: { email: "test2" },
update: {},
create: {
username: "test2",
email: "test2",
passwordHash: hashedPassword,
role: "USER",
},
})
// ---------- SELLER ----------
const amazon = await prisma.seller.upsert({
where: { name: "Amazon" },
update: { isActive: true },
create: {
name: "Amazon",
url: "https://www.amazon.com.tr",
isActive: true,
createdById: admin.id,
},
})
// ---------- SELLER DOMAINS ----------
const domains = ["amazon.com", "amazon.com.tr"]
for (const domain of domains) {
await prisma.sellerDomain.upsert({
where: { domain },
update: { sellerId: amazon.id },
create: {
domain,
sellerId: amazon.id,
createdById: admin.id,
},
})
}
// ---------- CATEGORIES (FROM JSON) ----------
const categoriesFilePath = path.join(__dirname, "", "categories.json")
const { count } = await seedCategoriesFromJson(categoriesFilePath)
const catSSD = await prisma.category.findUnique({
where: { slug: "pc-ssd" },
select: { id: true },
})
// ---------- TAGS ----------
await upsertTagBySlug("ssd", "SSD")
await upsertTagBySlug("nvme", "NVMe")
await upsertTagBySlug("1tb", "1TB")
// ---------- DEAL (tek örnek) ----------
const dealUrl = "https://www.amazon.com.tr/dp/test"
const existing = await prisma.deal.findFirst({
where: { url: dealUrl },
select: { id: true },
})
const dealData = {
title: "Samsung SSD 1TB",
description: "Test deal açıklaması",
url: dealUrl,
price: 1299.99,
status: DealStatus.ACTIVE,
saletype: SaleType.ONLINE,
affiliateType: AffiliateType.NON_AFFILIATE,
commentCount: 1,
userId: user.id,
sellerId: amazon.id,
categoryId: catSSD?.id ?? 0,
// score: randInt(0, 200), // modelinde varsa aç
}
const deal = existing
? await prisma.deal.update({ where: { id: existing.id }, data: dealData })
: await prisma.deal.create({ data: dealData })
// ---------- DEAL TAGS ----------
await attachTagsToDeal(deal.id, ["ssd", "nvme", "1tb"])
// ---------- DEAL IMAGES (tek örnek) ----------
await prisma.dealImage.deleteMany({ where: { dealId: deal.id } })
await prisma.dealImage.createMany({
data: [
{ dealId: deal.id, imageUrl: realImage("nvme-ssd-single-1"), order: 0 },
{ dealId: deal.id, imageUrl: realImage("nvme-ssd-single-2"), order: 1 },
{ dealId: deal.id, imageUrl: realImage("nvme-ssd-single-3"), order: 2 },
],
})
// ✅ ---------- 30 DEAL ÜRET ----------
await seedDeals30({
userId: user.id,
sellerId: amazon.id,
categoryId: catSSD?.id ?? 0,
})
// ---------- VOTE ----------
await prisma.dealVote.upsert({
where: { dealId_userId: { dealId: deal.id, userId: admin.id } },
update: { voteType: 1, lastVotedAt: new Date() },
create: { dealId: deal.id, userId: admin.id, voteType: 1 },
})
// ---------- COMMENT ----------
const hasComment = await prisma.comment.findFirst({
where: { dealId: deal.id, userId: admin.id, text: "Gerçekten iyi fırsat" },
select: { id: true },
})
if (!hasComment) {
await prisma.comment.create({
data: { text: "Gerçekten iyi fırsat", userId: admin.id, dealId: deal.id },
})
}
console.log(`✅ Seed tamamlandı (categories.json yüklendi: ${count} kategori)`)
console.log("✅ 30 adet test deal + 3'er görsel + score(0-200) + tarih dağılımı eklendi/güncellendi")
}
main()
.catch((err) => {
console.error(err)
process.exit(1)
})
.finally(async () => {
await prisma.$disconnect()
})