70492d9eba
Simplify asset upload temp paths, refresh deploy docs for Aliyun DNS topology, and ship MindSpace content-scan and auth improvements. Co-authored-by: Cursor <cursoragent@cursor.com>
115 lines
3.7 KiB
JavaScript
115 lines
3.7 KiB
JavaScript
#!/usr/bin/env node
|
|
/**
|
|
* 删除 Plaza 演示/种子内容(seed-plaza-demo.mjs 写入的数据),保留真实用户发布。
|
|
* 识别规则:发布 slug 以 demo- 开头,或内容资产 checksum = demo-seed。
|
|
*
|
|
* 用法:node scripts/purge-plaza-demo.mjs [--dry-run]
|
|
*/
|
|
import fs from 'node:fs';
|
|
import path from 'node:path';
|
|
import { fileURLToPath } from 'node:url';
|
|
import { createDbPool } from '../db.mjs';
|
|
|
|
const root = path.join(path.dirname(fileURLToPath(import.meta.url)), '..');
|
|
const dryRun = process.argv.includes('--dry-run');
|
|
|
|
function loadEnvFile(filePath) {
|
|
if (!fs.existsSync(filePath)) return;
|
|
for (const line of fs.readFileSync(filePath, 'utf8').split('\n')) {
|
|
const trimmed = line.trim();
|
|
if (!trimmed || trimmed.startsWith('#')) continue;
|
|
const eq = trimmed.indexOf('=');
|
|
if (eq < 0) continue;
|
|
const key = trimmed.slice(0, eq).trim();
|
|
const value = trimmed.slice(eq + 1).trim();
|
|
if (!process.env[key]) process.env[key] = value;
|
|
}
|
|
}
|
|
|
|
loadEnvFile(path.join(root, '../../.env.local'));
|
|
loadEnvFile(path.join(root, '.env'));
|
|
|
|
const pool = createDbPool();
|
|
const conn = await pool.getConnection();
|
|
|
|
try {
|
|
const [rows] = await conn.query(
|
|
`SELECT pp.id AS post_id, pp.title, pp.status AS post_status,
|
|
pr.id AS publication_id, pr.page_id, pr.page_version_id, pr.url_slug, pr.security_scan_id,
|
|
u.username
|
|
FROM plaza_posts pp
|
|
JOIN h5_publish_records pr ON pr.id = pp.publication_id
|
|
JOIN h5_page_versions pv ON pv.id = pr.page_version_id
|
|
JOIN h5_assets a ON a.id = pv.content_asset_id
|
|
JOIN h5_users u ON u.id = pp.user_id
|
|
WHERE pr.url_slug LIKE 'demo-%' OR a.checksum = 'demo-seed'
|
|
ORDER BY pp.published_at DESC`,
|
|
);
|
|
|
|
if (rows.length === 0) {
|
|
console.log('未发现演示内容,无需清理。');
|
|
process.exit(0);
|
|
}
|
|
|
|
console.log(`${dryRun ? '[dry-run] ' : ''}将删除 ${rows.length} 条演示广场帖:`);
|
|
for (const row of rows) {
|
|
console.log(` - [${row.username}] ${row.title} (${row.url_slug})`);
|
|
}
|
|
|
|
if (dryRun) {
|
|
process.exit(0);
|
|
}
|
|
|
|
await conn.beginTransaction();
|
|
|
|
const publicationIds = [...new Set(rows.map((row) => row.publication_id))];
|
|
const pageIds = [...new Set(rows.map((row) => row.page_id))];
|
|
const scanIds = [...new Set(rows.map((row) => row.security_scan_id).filter(Boolean))];
|
|
const postIds = rows.map((row) => row.post_id);
|
|
|
|
const [postResult] = await conn.query(
|
|
`DELETE FROM plaza_posts WHERE id IN (${postIds.map(() => '?').join(',')})`,
|
|
postIds,
|
|
);
|
|
|
|
const [pubResult] = await conn.query(
|
|
`DELETE FROM h5_publish_records WHERE id IN (${publicationIds.map(() => '?').join(',')})`,
|
|
publicationIds,
|
|
);
|
|
|
|
if (pageIds.length > 0) {
|
|
await conn.query(
|
|
`UPDATE h5_page_records SET current_publish_id = NULL WHERE id IN (${pageIds.map(() => '?').join(',')})`,
|
|
pageIds,
|
|
);
|
|
await conn.query(
|
|
`DELETE FROM h5_page_records WHERE id IN (${pageIds.map(() => '?').join(',')})`,
|
|
pageIds,
|
|
);
|
|
}
|
|
|
|
if (scanIds.length > 0) {
|
|
await conn.query(
|
|
`DELETE FROM h5_security_scans WHERE id IN (${scanIds.map(() => '?').join(',')})`,
|
|
scanIds,
|
|
);
|
|
}
|
|
|
|
const [assetResult] = await conn.query(
|
|
`DELETE FROM h5_assets WHERE checksum = 'demo-seed'`,
|
|
);
|
|
|
|
await conn.commit();
|
|
|
|
const [remaining] = await pool.query(`SELECT COUNT(*) AS cnt FROM plaza_posts`);
|
|
console.log(`\n完成:删除 ${postResult.affectedRows} 条广场帖、${pubResult.affectedRows} 条发布记录、${assetResult.affectedRows} 个演示资产。`);
|
|
console.log(`剩余广场帖:${remaining[0]?.cnt ?? 0} 条。`);
|
|
} catch (error) {
|
|
await conn.rollback();
|
|
console.error('清理失败:', error);
|
|
process.exitCode = 1;
|
|
} finally {
|
|
conn.release();
|
|
await pool.end();
|
|
}
|