| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149 |
- /**
- * 探测 DMS 删除内容的**正确姿势**(OpenAPI 与 Apifox 对 delContentById 的参数都未文档化)。
- *
- * 背景:Step-0 用 `DELETE /content/delContentById?id=<uuid>` 得 code=-1,行未删。
- * 线索:OpenAPI 里另有 `POST /content/updateAudit`(修改内容状态),
- * 而 DMS 的 states 语义是 0草稿 1待审 2审完 3发布 4销毁 5退回
- * —— “删除”很可能是把 state 改成 4,而不是物理删除。
- *
- * 本脚本会:造测试行 → 逐一试候选形态 → 校验行是否真的消失 → 清理残留。
- * 用法:node harness/tools/dms-delete-probe.mjs <DMS_TOKEN>
- */
- const HOST = process.env.DMS_HOST || '121.43.55.7:10081';
- const BASE = `http://${HOST}/dms`;
- const TOKEN = process.argv[2] || '';
- const COL = '1887';
- const MODEL = '2034';
- const TAG = `deltest_${Date.now().toString(36)}`;
- if (!TOKEN) {
- console.error('用法:node harness/tools/dms-delete-probe.mjs <DMS_TOKEN>');
- process.exit(2);
- }
- const call = async (method, path, form, jsonBody) => {
- const init = { method, headers: { token: TOKEN } };
- if (jsonBody !== undefined) {
- init.headers['Content-Type'] = 'application/json';
- init.body = JSON.stringify(jsonBody);
- } else if (form) {
- init.headers['Content-Type'] = 'application/x-www-form-urlencoded';
- init.body = new URLSearchParams(form).toString();
- }
- try {
- const res = await fetch(`${BASE}${path}`, init);
- const text = await res.text();
- let json = null;
- try {
- json = JSON.parse(text);
- } catch {
- /* 非 JSON */
- }
- return { status: res.status, json, text };
- } catch (err) {
- return { status: 0, json: null, text: String(err) };
- }
- };
- /** 该 column 下用 c_credit_code 标记的所有行 */
- const rowsWithTag = async (columnId, tag) => {
- const r = await call('POST', '/content/selectContentList', {
- columnId: String(columnId),
- page: '0',
- pageSize: '100',
- search: JSON.stringify([{ field: 'c_credit_code', searchType: 1, content: { value: tag } }]),
- });
- return r.json?.content?.data || [];
- };
- const mkRow = async () => {
- const sid = `${TAG}_${Math.random().toString(36).slice(2, 8)}`;
- const r = await call('POST', '/content/addContent', {
- columnId: COL,
- modelId: MODEL,
- content: JSON.stringify({ c_credit_code: TAG, c_session_id: sid, c_title: 'deltest' }),
- });
- return typeof r.json?.content === 'string' ? { uuid: r.json.content, sid } : null;
- };
- const run = async () => {
- console.log(`\nDMS 删除姿势探测 ${BASE}\n`);
- const candidates = [
- ['POST /content/delContentById form{columnId,contentId}', (u) => call('POST', '/content/delContentById', { columnId: COL, contentId: u })],
- ['DELETE /content/delContentById json{columnId,contentId}', (u) => call('DELETE', '/content/delContentById', null, { columnId: Number(COL), contentId: u })],
- ['DELETE /content/delContentById json{id}', (u) => call('DELETE', '/content/delContentById', null, { id: u })],
- ['DELETE form body{columnId,contentId}', (u) => call('DELETE', '/content/delContentById', { columnId: COL, contentId: u })],
- ['POST /content/updateAudit form{columnId,contentId,state=4}', (u) => call('POST', '/content/updateAudit', { columnId: COL, contentId: u, state: '4' })],
- ['POST /content/updateAudit form{columnId,ids,state=4}', (u) => call('POST', '/content/updateAudit', { columnId: COL, ids: u, state: '4' })],
- ['POST /content/updateAudit form{columnId,contentIds,state=4}', (u) => call('POST', '/content/updateAudit', { columnId: COL, contentIds: u, state: '4' })],
- ['POST /content/updateAudit form{columnId,id,state=4}', (u) => call('POST', '/content/updateAudit', { columnId: COL, id: u, state: '4' })],
- ['POST /content/updateAudit json{columnId,contentIds:[uuid],state:4}', (u) => call('POST', '/content/updateAudit', null, { columnId: Number(COL), contentIds: [u], state: 4 })],
- ];
- const winners = [];
- for (const [label, fn] of candidates) {
- const row = await mkRow();
- if (!row) {
- console.log(` ?? ${label} —— 造行失败`);
- continue;
- }
- let resp;
- try {
- resp = await fn(row.uuid);
- } catch (err) {
- console.log(` xx ${label} —— 异常 ${err.message}`);
- continue;
- }
- // 判定:默认查询里还能不能看到这一行
- const still = (await rowsWithTag(COL, TAG)).some((r) => r.id === row.uuid);
- const code = resp.json?.code ?? resp.status;
- const ok = !still && code === 200;
- console.log(` ${ok ? 'ok ' : 'xx '} ${label}\n → code=${code}${still ? '(行仍在)' : '(行已消失)'} ${String(resp.text).slice(0, 120)}`);
- if (ok) winners.push({ label, fn });
- }
- console.log(`\n可用姿势:${winners.length ? winners.map((w) => w.label).join(' / ') : '(都不行)'}`);
- // ── 清理:用可用的姿势删掉所有 deltest_* 与 step0_* 残留 ──────────────
- console.log('\n【清理残留】');
- const targets = [
- ...(await rowsWithTag(COL, TAG)),
- ...(await rowsWithTag('1889', TAG)),
- ...(await rowsWithTag(COL, 'step0_credit_code')),
- ...(await rowsWithTag('1889', 'step0_credit_code')),
- ...(await rowsWithTag(COL, 'probe_cc')),
- ...(await rowsWithTag('1889', 'probe_cc')),
- ];
- console.log(` 待清理 ${targets.length} 行`);
- if (!winners.length) {
- console.log(' ⚠️ 没有可用姿势,残留无法自动清理(需人工在 DMS 后台处理)');
- console.log(' 残留 id:', targets.map((t) => `${t.id}(col ${t.column_id})`).join(', '));
- return;
- }
- for (const row of targets) {
- for (const w of winners) {
- try {
- await w.fn(row.id);
- if (!(await rowsWithTag(String(row.column_id), row.c_credit_code)).some((r) => r.id === row.id)) break;
- } catch {
- /* 换下一种 */
- }
- }
- }
- const left = [
- ...(await rowsWithTag(COL, TAG)),
- ...(await rowsWithTag('1889', TAG)),
- ...(await rowsWithTag(COL, 'step0_credit_code')),
- ...(await rowsWithTag('1889', 'step0_credit_code')),
- ...(await rowsWithTag(COL, 'probe_cc')),
- ...(await rowsWithTag('1889', 'probe_cc')),
- ];
- console.log(` 清理后剩余 ${left.length} 行${left.length ? '(' + left.map((r) => r.id).join(', ') + ')' : ' ✅'}`);
- };
- run().catch((e) => {
- console.error('脚本异常:', e);
- process.exit(1);
- });
|