50c59ca9d4
Co-Authored-By: Claude Code <noreply@anthropic.com>
108 lines
3.5 KiB
JavaScript
108 lines
3.5 KiB
JavaScript
// 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 <account> <displayName>
|
||
// node seed-fixture.cjs photos <albumId> <uploaderAccount>
|
||
// 幂等:账号存在即跳过;照片按 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())
|