// e2e 数据种子夹具(Node 直跑,Playwright 用例内按需调用)。 // 为什么不用 API 造数:目标照片需要 published/processing_failed 等终态, // 真实链路要 worker 处理流水线;e2e 只验证管理页展示与操作,直插 DB 行 // (uploadedAt 置位即可入管理列表,见 services/api listAlbumPhotos 过滤条件)。 // 依赖经 PHOTO_DB_CN 环境变量注入 @photo/db-cn 绝对路径(apps/admin 不依赖 // 该包,node 从文件位置解析不到;services/api 的 node_modules 里有现成链接)。 // 用法: // node seed-fixture.cjs staff // node seed-fixture.cjs photos // 幂等:账号存在即跳过;照片按 objectKey upsert(同相册重复种不重复建行)。 const db_cn = process.env.PHOTO_DB_CN const databaseUrl = process.env.DATABASE_URL_CN if (!db_cn || !databaseUrl) { console.error('seed-fixture: PHOTO_DB_CN and DATABASE_URL_CN env vars are required') process.exit(1) } // CommonJS(node 直跑,无构建步骤):动态 require 经环境变量注入的包路径 // eslint-disable-next-line @typescript-eslint/no-require-imports const { PrismaClient } = require(db_cn) const prisma = new PrismaClient({ datasources: { db: { url: databaseUrl } } }) async function seedStaff(account, displayName) { const existing = await prisma.users.findUnique({ where: { account } }) if (existing) { console.log(`seed-fixture: staff "${account}" exists, skipping`) return } // passwordHash 占位(不可登录):e2e 只经账号查询邀请该用户,从不登录 await prisma.users.create({ data: { account, passwordHash: 'seeded-no-login', displayName: displayName || account, role: 'staff', credentialStatus: 'active' } }) console.log(`seed-fixture: staff "${account}" created`) } async function seedPhotos(albumId, uploaderAccount) { const uploader = await prisma.users.findUnique({ where: { account: uploaderAccount } }) if (!uploader) { throw new Error(`seed-fixture: uploader "${uploaderAccount}" not found`) } const now = new Date() const rows = [ { suffix: 'published', visibility: 'published', processingState: 'ready', width: 1200, height: 800, publishedAt: now, errorCode: null }, { suffix: 'failed', visibility: 'unpublished', processingState: 'processing_failed', width: null, height: null, publishedAt: null, errorCode: 'DECODE_FAILED' } ] for (const row of rows) { const objectKey = `e2e-seed/albums/${albumId}/${row.suffix}.jpg` await prisma.photos.upsert({ where: { objectKey }, update: {}, create: { albumId, uploaderId: uploader.id, objectKey, bytes: 2048, width: row.width, height: row.height, uploadedAt: now, publishedAt: row.publishedAt, processingState: row.processingState, errorCode: row.errorCode, visibility: row.visibility } }) } console.log(`seed-fixture: 2 photos seeded for album ${albumId}`) } async function main() { const [mode, argA, argB] = process.argv.slice(2) if (mode === 'staff') { await seedStaff(argA, argB) } else if (mode === 'photos') { await seedPhotos(argA, argB) } else { throw new Error(`seed-fixture: unknown mode "${mode}"`) } } main() .catch((error) => { console.error(error) process.exitCode = 1 }) .finally(() => prisma.$disconnect())