lomavuokraus/prisma/seed.js
Tero Halla-aho cb92a17f1d
Some checks failed
CI / checks (push) Has been cancelled
CI / checks (pull_request) Has been cancelled
Add on-site EV charging amenity
2025-12-17 13:40:47 +02:00

742 lines
27 KiB
JavaScript

/* eslint-disable no-console */
const path = require('path');
const fs = require('fs');
require('dotenv').config({ path: path.join(__dirname, '..', '.env') });
if (fs.existsSync(path.join(__dirname, '..', 'creds', '.env'))) {
require('dotenv').config({ path: path.join(__dirname, '..', 'creds', '.env') });
}
const bcrypt = require('bcryptjs');
const { PrismaClient, Role, UserStatus, ListingStatus } = require('@prisma/client');
const { PrismaPg } = require('@prisma/adapter-pg');
const { Pool } = require('pg');
if (!process.env.DATABASE_URL) {
console.error('DATABASE_URL is not set; cannot seed.');
process.exit(1);
}
const prisma = new PrismaClient({
adapter: new PrismaPg(new Pool({ connectionString: process.env.DATABASE_URL })),
});
const SAMPLE_SLUG = 'saimaa-lakeside-cabin';
const DEFAULT_LOCALE = 'en';
const SAMPLE_EMAIL = 'host@lomavuokraus.fi';
const SAMPLE_IMAGE_DIR = path.join(__dirname, '..', 'sampleimages');
function detectMimeType(fileName) {
const ext = path.extname(fileName).toLowerCase();
if (ext === '.png') return 'image/png';
if (ext === '.webp') return 'image/webp';
if (ext === '.gif') return 'image/gif';
return 'image/jpeg';
}
function loadSampleImage(fileName) {
if (!fileName) return null;
const filePath = path.join(SAMPLE_IMAGE_DIR, fileName);
if (!fs.existsSync(filePath)) {
console.warn(`Sample image missing: ${filePath}`);
return null;
}
const data = fs.readFileSync(filePath);
return {
data,
size: data.length,
mimeType: detectMimeType(fileName),
};
}
async function main() {
const adminEmail = process.env.ADMIN_EMAIL;
const adminPassword = process.env.ADMIN_INITIAL_PASSWORD;
function buildImageCreates(item) {
const results = [];
const coverFile = loadSampleImage(item.cover.file);
if (coverFile || item.cover.url) {
results.push({
data: coverFile?.data,
mimeType: coverFile?.mimeType || (item.cover.url ? null : undefined),
size: coverFile?.size ?? null,
url: coverFile ? null : item.cover.url ?? null,
altText: item.cover.altText ?? null,
order: 1,
isCover: true,
});
}
item.images.forEach((img) => {
const file = loadSampleImage(img.file);
const hasSource = file || img.url;
if (!hasSource) return;
results.push({
data: file?.data,
mimeType: file?.mimeType || (img.url ? null : undefined),
size: file?.size ?? null,
url: file ? null : img.url ?? null,
altText: img.altText ?? null,
order: results.length + 1,
isCover: false,
});
});
return results;
}
if (!adminEmail || !adminPassword) {
console.warn('ADMIN_EMAIL or ADMIN_INITIAL_PASSWORD missing; admin user will not be seeded.');
}
let adminUser = null;
if (adminEmail && adminPassword) {
const adminHash = await bcrypt.hash(adminPassword, 12);
adminUser = await prisma.user.upsert({
where: { email: adminEmail },
update: {
passwordHash: adminHash,
role: Role.ADMIN,
status: UserStatus.ACTIVE,
emailVerifiedAt: new Date(),
approvedAt: new Date(),
},
create: {
email: adminEmail,
passwordHash: adminHash,
role: Role.ADMIN,
status: UserStatus.ACTIVE,
emailVerifiedAt: new Date(),
approvedAt: new Date(),
},
});
}
const sampleHostHash = await bcrypt.hash('changeme-sample', 12);
const owner = await prisma.user.upsert({
where: { email: SAMPLE_EMAIL },
update: {
name: 'Sample Host',
phone: '+358401234567',
role: 'USER',
passwordHash: sampleHostHash,
status: UserStatus.ACTIVE,
emailVerifiedAt: new Date(),
approvedAt: new Date(),
},
create: {
email: SAMPLE_EMAIL,
name: 'Sample Host',
phone: '+358401234567',
role: 'USER',
passwordHash: sampleHostHash,
status: UserStatus.ACTIVE,
emailVerifiedAt: new Date(),
approvedAt: new Date(),
},
});
let listings = [
{
slug: SAMPLE_SLUG,
isSample: true,
city: 'Punkaharju',
region: 'South Karelia',
country: 'Finland',
streetAddress: 'Saimaan rantatie 12',
addressNote: 'Lakeside trail, 5 min from main road',
latitude: 61.756,
longitude: 29.328,
maxGuests: 6,
bedrooms: 3,
beds: 4,
bathrooms: 1,
hasSauna: true,
hasFireplace: true,
hasWifi: true,
hasAirConditioning: false,
hasKitchen: true,
hasDishwasher: false,
hasWashingMachine: false,
hasBarbecue: false,
hasMicrowave: true,
hasFreeParking: true,
petsAllowed: false,
byTheLake: true,
evChargingAvailable: true,
hasSkiPass: false,
priceWeekdayEuros: 145,
priceWeekendEuros: 165,
cover: {
file: 'saimaa-lakeside-cabin-cover.jpg',
url: 'https://images.unsplash.com/photo-1505691938895-1758d7feb511?auto=format&fit=crop&w=1600&q=80',
altText: 'Lakeside cabin with sauna',
},
images: [
{ file: 'saimaa-lakeside-cabin-sauna.jpg', url: 'https://images.unsplash.com/photo-1505693416388-ac5ce068fe85?auto=format&fit=crop&w=1600&q=80', altText: 'Wood-fired sauna by the lake' },
{ file: 'saimaa-lakeside-cabin-lounge.jpg', url: 'https://images.unsplash.com/photo-1470246973918-29a93221c455?auto=format&fit=crop&w=1600&q=80', altText: 'Living area with fireplace' },
],
titleEn: 'Saimaa lakeside cabin with sauna',
teaserEn: 'Sauna, lake view, private dock, and cozy fireplace.',
descEn:
'Classic timber cabin right on Lake Saimaa. Wood-fired sauna, private dock, and a short forest walk to the nearest village. Perfect for slow weekends and midsummer gatherings.',
titleFi: 'Saimaan rantamökki saunalla',
teaserFi: 'Puusauna, järvinäköala, oma laituri ja takka.',
descFi:
'Perinteinen hirsimökki Saimaan rannalla. Puusauna, oma laituri ja lyhyt metsäreitti kylään. Sopii täydellisesti viikonloppuihin ja juhannukseen.',
},
{
slug: 'helsinki-design-loft',
isSample: true,
city: 'Helsinki',
region: 'Uusimaa',
country: 'Finland',
streetAddress: 'Katajanokanranta 4',
addressNote: 'Buzz 12B, elevator to 5th floor',
latitude: 60.1675,
longitude: 24.9529,
maxGuests: 4,
bedrooms: 1,
beds: 2,
bathrooms: 1,
hasSauna: false,
hasFireplace: false,
hasWifi: true,
hasAirConditioning: true,
hasKitchen: true,
hasDishwasher: false,
hasWashingMachine: false,
hasBarbecue: false,
hasMicrowave: true,
hasFreeParking: false,
petsAllowed: false,
byTheLake: false,
evChargingAvailable: true,
hasSkiPass: false,
priceWeekdayEuros: 165,
priceWeekendEuros: 185,
cover: {
file: 'helsinki-design-loft-cover.jpg',
url: 'https://images.unsplash.com/photo-1505693415763-3bd1620f58c3?auto=format&fit=crop&w=1600&q=80',
altText: 'Modern loft living room',
},
images: [
{ file: 'helsinki-design-loft-balcony.jpg', url: 'https://images.unsplash.com/photo-1505691938895-1758d7feb511?auto=format&fit=crop&w=1600&q=80', altText: 'Balcony view' },
{ file: 'helsinki-design-loft-bedroom.jpg', url: 'https://images.unsplash.com/photo-1505691938895-1758d7feb511?auto=format&fit=crop&w=1600&q=80', altText: 'Cozy bedroom' },
],
titleEn: 'Helsinki design loft with AC',
teaserEn: 'Top-floor loft, AC, fast Wi-Fi, tram at the door.',
descEn: 'Bright design loft near the harbor. Air conditioning, fiber Wi-Fi, and views over Katajanokka. Perfect city break base.',
titleFi: 'Helsingin design-lofti ilmastoinnilla',
teaserFi: 'Ylimmän kerroksen loft, ilmastointi ja nopea netti.',
descFi: 'Valoisa loft Katajanokalla. Ilmastointi, kuitunetti ja näkymä merelle. Täydellinen kaupunkiloma.',
},
{
slug: 'turku-riverside-apartment',
isSample: true,
city: 'Turku',
region: 'Varsinais-Suomi',
country: 'Finland',
streetAddress: 'Läntinen Rantakatu 10',
addressNote: 'Self check-in lockbox',
latitude: 60.4518,
longitude: 22.2666,
maxGuests: 3,
bedrooms: 1,
beds: 2,
bathrooms: 1,
hasSauna: false,
hasFireplace: false,
hasWifi: true,
hasAirConditioning: false,
hasKitchen: true,
hasDishwasher: false,
hasWashingMachine: false,
hasBarbecue: false,
hasMicrowave: true,
hasFreeParking: true,
petsAllowed: true,
byTheLake: false,
evChargingAvailable: false,
hasSkiPass: false,
priceWeekdayEuros: 110,
priceWeekendEuros: 125,
cover: {
file: 'turku-riverside-apartment-cover.jpg',
url: 'https://images.unsplash.com/photo-1522708323590-d24dbb6b0267?auto=format&fit=crop&w=1600&q=80',
altText: 'Apartment living room',
},
images: [
{ file: 'turku-riverside-apartment-kitchen.jpg', url: 'https://images.unsplash.com/photo-1505691938895-1758d7feb511?auto=format&fit=crop&w=1600&q=80', altText: 'Kitchen area' },
],
titleEn: 'Riverside apartment in Turku',
teaserEn: 'By the Aura river, pet-friendly, cozy base.',
descEn: 'Compact one-bedroom next to the Aura river. Cafés outside, pet-friendly, fiber internet for workations.',
titleFi: 'Aurajoen varrella, lemmikkiystävällinen',
teaserFi: 'Aurajoen kupeessa, lemmikit sallittu.',
descFi: 'Kompakti yksiö Aurajoen varrella. Kahvilat vieressä, lemmikit sallittu, kuitunetti etätöihin.',
},
{
slug: 'rovaniemi-aurora-cabin',
isSample: true,
city: 'Rovaniemi',
region: 'Lapland',
country: 'Finland',
streetAddress: 'Ounasjoenkuja 8',
addressNote: 'Snow tires required in winter',
latitude: 66.5039,
longitude: 25.7294,
maxGuests: 5,
bedrooms: 2,
beds: 4,
bathrooms: 1,
hasSauna: true,
hasFireplace: true,
hasWifi: true,
hasAirConditioning: false,
hasKitchen: true,
hasDishwasher: false,
hasWashingMachine: false,
hasBarbecue: false,
hasMicrowave: false,
hasFreeParking: true,
petsAllowed: false,
byTheLake: true,
evChargingAvailable: true,
evChargingOnSite: true,
hasSkiPass: true,
priceWeekdayEuros: 189,
priceWeekendEuros: 215,
cover: {
file: 'rovaniemi-aurora-cabin-cover.jpg',
url: 'https://images.unsplash.com/photo-1505693416388-ac5ce068fe85?auto=format&fit=crop&w=1600&q=80',
altText: 'Aurora cabin by the river',
},
images: [
{ file: 'rovaniemi-aurora-cabin-lounge.jpg', url: 'https://images.unsplash.com/photo-1470246973918-29a93221c455?auto=format&fit=crop&w=1600&q=80', altText: 'Fireplace lounge' },
],
titleEn: 'Aurora riverside cabin',
teaserEn: 'Sauna, fireplace, river views, EV charging.',
descEn: 'Timber cabin on the Ounasjoki riverside. Wood sauna, fireplace, glass lounge for auroras, free EV charging.',
titleFi: 'Revontulikämppä joen rannalla',
teaserFi: 'Sauna, takka, jokinäkymä ja ilmainen lataus.',
descFi: 'Hirsimökki Ounasjoen rannalla. Puusauna, takka ja lasikuisti revontulien katseluun, ilmainen sähköauton lataus.',
},
{
slug: 'tampere-sauna-studio',
isSample: true,
city: 'Tampere',
region: 'Pirkanmaa',
country: 'Finland',
streetAddress: 'Hämeenkatu 25',
addressNote: 'Key pickup from lobby',
latitude: 61.4981,
longitude: 23.7608,
maxGuests: 2,
bedrooms: 0,
beds: 1,
bathrooms: 1,
hasSauna: true,
hasFireplace: false,
hasWifi: true,
hasAirConditioning: true,
hasKitchen: true,
hasDishwasher: false,
hasWashingMachine: false,
hasBarbecue: false,
hasMicrowave: true,
hasFreeParking: false,
petsAllowed: false,
byTheLake: false,
evChargingAvailable: false,
hasSkiPass: false,
priceWeekdayEuros: 95,
priceWeekendEuros: 110,
cover: {
file: 'tampere-sauna-studio-cover.jpg',
url: 'https://images.unsplash.com/photo-1505691938895-1758d7feb511?auto=format&fit=crop&w=1600&q=80',
altText: 'Studio interior',
},
images: [{ file: 'tampere-sauna-studio-sauna.jpg', url: 'https://images.unsplash.com/photo-1505691938895-1758d7feb511?auto=format&fit=crop&w=1600&q=80', altText: 'Private sauna' }],
titleEn: 'Tampere studio with private sauna',
teaserEn: 'City center, private sauna, AC and fiber.',
descEn: 'Compact studio on Hämeenkatu with private electric sauna, air conditioning, and fiber internet. Steps from tram.',
titleFi: 'Tampereen keskustastudio saunalla',
teaserFi: 'Yksityinen sauna, ilmastointi, kuitu.',
descFi: 'Kompakti studio Hämeenkadulla. Oma sähkösauna, ilmastointi ja kuitunetti. Ratikka vieressä.',
},
{
slug: 'vaasa-seaside-villa',
isSample: true,
city: 'Vaasa',
region: 'Ostrobothnia',
country: 'Finland',
streetAddress: 'Rantakatu 3',
addressNote: 'Parking for 3 cars',
latitude: 63.096,
longitude: 21.6158,
maxGuests: 8,
bedrooms: 4,
beds: 6,
bathrooms: 2,
hasSauna: true,
hasFireplace: true,
hasWifi: true,
hasAirConditioning: false,
hasKitchen: true,
hasDishwasher: false,
hasWashingMachine: false,
hasBarbecue: false,
hasMicrowave: true,
hasFreeParking: true,
petsAllowed: true,
byTheLake: true,
evChargingAvailable: true,
evChargingOnSite: true,
hasSkiPass: true,
priceWeekdayEuros: 245,
priceWeekendEuros: 275,
cover: {
file: 'vaasa-seaside-villa-cover.jpg',
url: 'https://images.unsplash.com/photo-1505691938895-1758d7feb511?auto=format&fit=crop&w=1600&q=80',
altText: 'Seaside villa deck',
},
images: [{ file: 'vaasa-seaside-villa-lounge.jpg', url: 'https://images.unsplash.com/photo-1505691938895-1758d7feb511?auto=format&fit=crop&w=1600&q=80', altText: 'Seaside villa lounge' }],
titleEn: 'Seaside villa in Vaasa',
teaserEn: 'Deck, sauna, pet-friendly, paid EV charging.',
descEn: 'Spacious villa on the coast with large deck, wood sauna, fireplace lounge. Pets welcome; paid EV charger on site.',
titleFi: 'Rantahuvila Vaasassa',
teaserFi: 'Terassi, sauna, lemmikit ok, maksullinen lataus.',
descFi: 'Tilava huvila meren rannalla, iso terassi, puusauna ja takkahuone. Lemmikit sallittu; maksullinen latauspiste.',
},
{
slug: 'kuopio-lakeside-apartment',
isSample: true,
city: 'Kuopio',
region: 'Northern Savonia',
country: 'Finland',
streetAddress: 'Satamakatu 7',
addressNote: 'Underground parking',
latitude: 62.8924,
longitude: 27.6783,
maxGuests: 4,
bedrooms: 2,
beds: 3,
bathrooms: 1,
hasSauna: true,
hasFireplace: false,
hasWifi: true,
hasAirConditioning: false,
hasKitchen: true,
hasDishwasher: false,
hasWashingMachine: false,
hasBarbecue: false,
hasMicrowave: true,
hasFreeParking: true,
petsAllowed: false,
byTheLake: true,
evChargingAvailable: true,
evChargingOnSite: true,
hasSkiPass: true,
priceWeekdayEuros: 129,
priceWeekendEuros: 149,
cover: {
file: 'kuopio-lakeside-apartment-cover.jpg',
url: 'https://images.unsplash.com/photo-1470246973918-29a93221c455?auto=format&fit=crop&w=1600&q=80',
altText: 'Lake view balcony',
},
images: [{ file: 'kuopio-lakeside-apartment-sauna.jpg', url: 'https://images.unsplash.com/photo-1470246973918-29a93221c455?auto=format&fit=crop&w=1600&q=80', altText: 'Apartment sauna' }],
titleEn: 'Kuopio lakeside apartment with sauna',
teaserEn: 'Balcony to Kallavesi, sauna, free EV charging.',
descEn: 'Two-bedroom apartment overlooking Lake Kallavesi. Glass balcony, electric sauna, underground parking with free EV charging.',
titleFi: 'Kuopion järvinäkymä ja sauna',
teaserFi: 'Parveke Kallavedelle, sauna, ilmainen lataus.',
descFi: 'Kaksio Kallaveden rannalla. Lasitettu parveke, sähkösauna, hallipaikka ja ilmainen sähköauton lataus.',
},
{
slug: 'porvoo-river-loft',
isSample: true,
city: 'Porvoo',
region: 'Uusimaa',
country: 'Finland',
streetAddress: 'Mannerheiminkatu 12',
addressNote: 'Historic building, stairs only',
latitude: 60.3943,
longitude: 25.6659,
maxGuests: 2,
bedrooms: 1,
beds: 1,
bathrooms: 1,
hasSauna: false,
hasFireplace: true,
hasWifi: true,
hasAirConditioning: false,
hasKitchen: true,
hasDishwasher: false,
hasWashingMachine: false,
hasBarbecue: false,
hasMicrowave: true,
hasFreeParking: false,
petsAllowed: false,
byTheLake: false,
evChargingAvailable: false,
hasSkiPass: false,
priceWeekdayEuros: 99,
priceWeekendEuros: 115,
cover: {
file: 'porvoo-river-loft-cover.jpg',
url: 'https://images.unsplash.com/photo-1505691938895-1758d7feb511?auto=format&fit=crop&w=1600&q=80',
altText: 'Loft interior',
},
images: [{ file: 'porvoo-river-loft-fireplace.jpg', url: 'https://images.unsplash.com/photo-1505691938895-1758d7feb511?auto=format&fit=crop&w=1600&q=80', altText: 'Fireplace corner' }],
titleEn: 'Porvoo old town river loft',
teaserEn: 'Historic charm, fireplace, steps from river.',
descEn: 'Cozy loft in Porvoo old town. Brick walls, fireplace, and views toward the riverside warehouses.',
titleFi: 'Porvoon jokilofti',
teaserFi: 'Takka ja vanhan kaupungin tunnelma.',
descFi: 'Kotoisa loft Porvoon vanhassa kaupungissa. Tiiliseinät, takka ja näkymä jokirantaan.',
},
{
slug: 'oulu-tech-apartment',
isSample: true,
city: 'Oulu',
region: 'Northern Ostrobothnia',
country: 'Finland',
streetAddress: 'Technopolis 2',
addressNote: 'Smart lock entry',
latitude: 65.0121,
longitude: 25.4651,
maxGuests: 2,
bedrooms: 1,
beds: 1,
bathrooms: 1,
hasSauna: false,
hasFireplace: false,
hasWifi: true,
hasAirConditioning: true,
hasKitchen: true,
hasDishwasher: false,
hasWashingMachine: false,
hasBarbecue: false,
hasMicrowave: true,
hasFreeParking: true,
petsAllowed: false,
byTheLake: false,
evChargingAvailable: true,
evChargingOnSite: true,
priceWeekdayEuros: 105,
priceWeekendEuros: 120,
cover: {
file: 'oulu-tech-apartment-cover.jpg',
url: 'https://images.unsplash.com/photo-1522708323590-d24dbb6b0267?auto=format&fit=crop&w=1600&q=80',
altText: 'Modern apartment',
},
images: [{ file: 'oulu-tech-apartment-desk.jpg', url: 'https://images.unsplash.com/photo-1522708323590-d24dbb6b0267?auto=format&fit=crop&w=1600&q=80', altText: 'Work desk in apartment' }],
titleEn: 'Smart apartment in Oulu',
teaserEn: 'AC, smart lock, free EV charging in garage.',
descEn: 'Modern one-bedroom near Technopolis. Air conditioning, smart lock, desk for work, garage with free EV chargers.',
titleFi: 'Moderni Oulun yksiö',
teaserFi: 'Ilmastointi, älylukko, ilmainen lataus.',
descFi: 'Moderni yksiö Technopoliksen lähellä. Ilmastointi, älylukko, työpiste ja ilmaiset latauspaikat hallissa.',
},
{
slug: 'mariehamn-harbor-flat',
isSample: true,
city: 'Mariehamn',
region: 'Åland',
country: 'Finland',
streetAddress: 'Hamngatan 5',
addressNote: 'Ferry terminal 10 min walk',
latitude: 60.0973,
longitude: 19.9348,
maxGuests: 3,
bedrooms: 1,
beds: 2,
bathrooms: 1,
hasSauna: false,
hasFireplace: false,
hasWifi: true,
hasAirConditioning: false,
hasKitchen: true,
hasDishwasher: false,
hasWashingMachine: false,
hasBarbecue: false,
hasMicrowave: true,
hasFreeParking: true,
petsAllowed: false,
byTheLake: true,
evChargingAvailable: true,
hasSkiPass: true,
priceWeekdayEuros: 115,
priceWeekendEuros: 130,
cover: {
file: 'mariehamn-harbor-flat-cover.jpg',
url: 'https://images.unsplash.com/photo-1470246973918-29a93221c455?auto=format&fit=crop&w=1600&q=80',
altText: 'Harbor view',
},
images: [{ file: 'mariehamn-harbor-flat-living.jpg', url: 'https://images.unsplash.com/photo-1470246973918-29a93221c455?auto=format&fit=crop&w=1600&q=80', altText: 'Harbor-facing living room' }],
titleEn: 'Harbor flat in Mariehamn',
teaserEn: 'Walk to ferries, harbor views, paid EV nearby.',
descEn: 'Bright flat near the harbor. Walk to ferries and restaurants, harbor-facing balcony, paid EV charging at the public lot.',
titleFi: 'Satamahuoneisto Maarianhaminassa',
teaserFi: 'Satamanäkymä, kävely lautoille.',
descFi: 'Valoisa huoneisto sataman tuntumassa. Parveke satamaan, ravintolat lähellä, maksullinen lataus viereisellä parkkipaikalla.',
},
];
// Fill in any missing amenities/prices with reasonable defaults
const randBool = (p = 0.5) => Math.random() < p;
listings = listings.map((item) => {
const weekdayPrice = item.priceWeekdayEuros ?? Math.round(Math.random() * (220 - 90) + 90);
const evChargingOnSite = item.evChargingOnSite ?? randBool(0.15);
const evChargingAvailable = item.evChargingAvailable ?? evChargingOnSite ?? randBool(0.4);
return {
...item,
priceWeekdayEuros: weekdayPrice,
priceWeekendEuros: item.priceWeekendEuros ?? (weekdayPrice ? weekdayPrice + 15 : null),
hasKitchen: item.hasKitchen ?? randBool(0.9),
hasDishwasher: item.hasDishwasher ?? randBool(0.6),
hasWashingMachine: item.hasWashingMachine ?? randBool(0.6),
hasBarbecue: item.hasBarbecue ?? randBool(0.5),
hasMicrowave: item.hasMicrowave ?? randBool(0.7),
hasFreeParking: item.hasFreeParking ?? randBool(0.6),
evChargingOnSite,
evChargingAvailable,
wheelchairAccessible: item.wheelchairAccessible ?? randBool(0.25),
hasSkiPass: item.hasSkiPass ?? randBool(0.2),
};
});
for (const item of listings) {
const existing = await prisma.listingTranslation.findFirst({ where: { slug: item.slug }, select: { listingId: true } });
const imageCreates = buildImageCreates(item);
if (!existing) {
const created = await prisma.listing.create({
data: {
ownerId: owner.id,
status: ListingStatus.PUBLISHED,
approvedAt: new Date(),
approvedById: adminUser ? adminUser.id : owner.id,
isSample: item.isSample ?? false,
country: item.country,
region: item.region,
city: item.city,
streetAddress: item.streetAddress,
addressNote: item.addressNote,
latitude: item.latitude,
longitude: item.longitude,
maxGuests: item.maxGuests,
bedrooms: item.bedrooms,
beds: item.beds,
bathrooms: item.bathrooms,
hasSauna: item.hasSauna,
hasFireplace: item.hasFireplace,
hasWifi: item.hasWifi,
hasAirConditioning: item.hasAirConditioning,
hasKitchen: item.hasKitchen ?? false,
hasDishwasher: item.hasDishwasher ?? false,
hasWashingMachine: item.hasWashingMachine ?? false,
hasBarbecue: item.hasBarbecue ?? false,
hasMicrowave: item.hasMicrowave ?? false,
hasFreeParking: item.hasFreeParking ?? false,
petsAllowed: item.petsAllowed,
byTheLake: item.byTheLake,
evChargingAvailable: item.evChargingAvailable ?? item.evChargingOnSite ?? false,
evChargingOnSite: item.evChargingOnSite ?? false,
wheelchairAccessible: item.wheelchairAccessible ?? false,
priceWeekdayEuros: item.priceWeekdayEuros,
priceWeekendEuros: item.priceWeekendEuros,
contactName: 'Sample Host',
contactEmail: SAMPLE_EMAIL,
contactPhone: owner.phone,
published: true,
translations: {
createMany: {
data: [
{ locale: 'en', slug: item.slug, title: item.titleEn, teaser: item.teaserEn, description: item.descEn },
{ locale: 'fi', slug: item.slug, title: item.titleFi, teaser: item.teaserFi, description: item.descFi },
],
},
},
images: imageCreates.length ? { create: imageCreates } : undefined,
},
});
console.log('Seeded listing:', created.id, item.slug);
continue;
}
const listingId = existing.listingId;
await prisma.listing.update({
where: { id: listingId },
data: {
isSample: item.isSample ?? false,
country: item.country,
region: item.region,
city: item.city,
streetAddress: item.streetAddress,
addressNote: item.addressNote,
latitude: item.latitude,
longitude: item.longitude,
maxGuests: item.maxGuests,
bedrooms: item.bedrooms,
beds: item.beds,
bathrooms: item.bathrooms,
hasSauna: item.hasSauna,
hasFireplace: item.hasFireplace,
hasWifi: item.hasWifi,
hasAirConditioning: item.hasAirConditioning,
hasKitchen: item.hasKitchen ?? false,
hasDishwasher: item.hasDishwasher ?? false,
hasWashingMachine: item.hasWashingMachine ?? false,
hasBarbecue: item.hasBarbecue ?? false,
hasMicrowave: item.hasMicrowave ?? false,
hasFreeParking: item.hasFreeParking ?? false,
petsAllowed: item.petsAllowed,
byTheLake: item.byTheLake,
evChargingAvailable: item.evChargingAvailable ?? item.evChargingOnSite ?? false,
evChargingOnSite: item.evChargingOnSite ?? false,
wheelchairAccessible: item.wheelchairAccessible ?? false,
priceWeekdayEuros: item.priceWeekdayEuros,
priceWeekendEuros: item.priceWeekendEuros,
contactName: 'Sample Host',
contactEmail: SAMPLE_EMAIL,
contactPhone: owner.phone,
published: true,
status: ListingStatus.PUBLISHED,
approvedAt: new Date(),
},
});
await prisma.listingTranslation.upsert({
where: { slug_locale: { slug: item.slug, locale: 'en' } },
create: { listingId, locale: 'en', slug: item.slug, title: item.titleEn, teaser: item.teaserEn, description: item.descEn },
update: { title: item.titleEn, teaser: item.teaserEn, description: item.descEn },
});
await prisma.listingTranslation.upsert({
where: { slug_locale: { slug: item.slug, locale: 'fi' } },
create: { listingId, locale: 'fi', slug: item.slug, title: item.titleFi, teaser: item.teaserFi, description: item.descFi },
update: { title: item.titleFi, teaser: item.teaserFi, description: item.descFi },
});
await prisma.listingImage.deleteMany({ where: { listingId } });
if (imageCreates.length) {
await prisma.listingImage.createMany({
data: imageCreates.map((img) => ({
...img,
listingId,
})),
});
}
console.log('Updated listing:', item.slug);
}
console.log('Seed completed for sample listings.');
}
main()
.catch((e) => {
console.error(e);
process.exit(1);
})
.finally(async () => {
await prisma.$disconnect();
});