feat: 完成分类、worksheet 接口开发,资源迁移到七牛
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
import 'reflect-metadata';
|
||||
import { createHash, randomUUID } from 'node:crypto';
|
||||
import {
|
||||
closeSync,
|
||||
openSync,
|
||||
readFileSync,
|
||||
statSync,
|
||||
unlinkSync,
|
||||
writeFileSync,
|
||||
} from 'node:fs';
|
||||
import { basename, resolve } from 'node:path';
|
||||
import { createRequire } from 'node:module';
|
||||
import { parseArgs, parseEnv } from 'node:util';
|
||||
|
||||
const require = createRequire(import.meta.url);
|
||||
const { PrismaService } = require('../dist/database/prisma.service.js');
|
||||
const { WorksheetImporter } = require('../dist/imports/worksheet-import.js');
|
||||
const { HttpException } = require('@nestjs/common');
|
||||
let database;
|
||||
let reportFd;
|
||||
let reportPath;
|
||||
let reportWritten = false;
|
||||
let committed = false;
|
||||
|
||||
try {
|
||||
const { values } = parseArgs({
|
||||
options: {
|
||||
file: { type: 'string' },
|
||||
apply: { type: 'boolean', default: false },
|
||||
'metadata-only': { type: 'boolean', default: false },
|
||||
report: { type: 'string' },
|
||||
},
|
||||
});
|
||||
if (!values.file)
|
||||
throw new Error('请用 --file 指定题型导出;默认预演,--apply 才写库');
|
||||
const file = resolve(values.file);
|
||||
if (statSync(file).size > 10 * 1024 * 1024)
|
||||
throw new Error('题型文件不能超过 10 MiB');
|
||||
const source = readFileSync(file, 'utf8');
|
||||
const sourceSha256 = createHash('sha256').update(source).digest('hex');
|
||||
const local = parseEnv(
|
||||
readFileSync(new URL('../.env', import.meta.url), 'utf8'),
|
||||
);
|
||||
const url = new URL(process.env.DATABASE_URL ?? local.DATABASE_URL);
|
||||
// 元数据暂存仅限本地开发库,不能带着未就绪的预览图导入到生产。
|
||||
if (
|
||||
!['127.0.0.1', 'localhost'].includes(url.hostname) ||
|
||||
url.pathname !== '/doodle_dev'
|
||||
)
|
||||
throw new Error('题型导入工具只允许本机 doodle_dev');
|
||||
if (values.report) {
|
||||
reportPath = resolve(values.report);
|
||||
reportFd = openSync(reportPath, 'wx');
|
||||
}
|
||||
database = new PrismaService({ databaseUrl: url.toString() });
|
||||
const requestId = `worksheets-import-${randomUUID()}`;
|
||||
const result = await new WorksheetImporter(database).importExport(source, {
|
||||
dryRun: !values.apply,
|
||||
metadataOnly: values['metadata-only'],
|
||||
requestId,
|
||||
sourceSha256,
|
||||
});
|
||||
committed = !result.dryRun;
|
||||
const report = {
|
||||
source: basename(file),
|
||||
sourceSha256,
|
||||
requestId,
|
||||
...result,
|
||||
};
|
||||
const output = `${JSON.stringify(report, null, 4)}\n`;
|
||||
process.stdout.write(output);
|
||||
if (reportFd !== undefined) {
|
||||
writeFileSync(reportFd, output);
|
||||
reportWritten = true;
|
||||
}
|
||||
} catch (error) {
|
||||
const message =
|
||||
error instanceof HttpException
|
||||
? error.message
|
||||
: error instanceof Error &&
|
||||
!/(postgres|password|connection|prisma|\/\/)/i.test(
|
||||
error.message,
|
||||
)
|
||||
? error.message
|
||||
: '题型导入失败,请检查本地数据库配置和文件';
|
||||
process.stderr.write(`${message}\n`);
|
||||
if (committed)
|
||||
process.stderr.write(
|
||||
'数据库事务已提交;报告保存失败,批次见上方输出及审计。\n',
|
||||
);
|
||||
process.exitCode = 1;
|
||||
} finally {
|
||||
if (reportFd !== undefined) {
|
||||
closeSync(reportFd);
|
||||
if (!reportWritten) unlinkSync(reportPath);
|
||||
}
|
||||
await database?.onModuleDestroy();
|
||||
}
|
||||
Reference in New Issue
Block a user