7 lines
3.4 KiB
JavaScript
7 lines
3.4 KiB
JavaScript
/* Read-only audit of live business references; obsolete admin configuration backups stay intact. */
|
|
const fs=require('fs'),path=require('path');const root=process.env.MIGRATION_APP_ROOT||process.cwd(),dir=process.env.MIGRATION_RUN_DIR||'/var/lib/ai-chatbot/aliyun-qiniu-20261014';const {urlsIn}=require('./migrate-aliyun-to-qiniu.cjs');require(path.join(root,'node_modules/dotenv')).config({path:path.join(root,'.env.local')});const sql=require(path.join(root,'node_modules/postgres'))(process.env.POSTGRES_URL,{max:1,prepare:false,connection:{statement_timeout:600000}});const host='demo-sparkai.oss-cn-shanghai.aliyuncs.com',quote=s=>'"'+s.replaceAll('"','""')+'"';
|
|
(async()=>{try{const verified=new Set(fs.readFileSync(path.join(dir,'verified.jsonl'),'utf8').split('\n').filter(Boolean).map(s=>JSON.parse(s).id)),unavailable=new Set(fs.existsSync(path.join(dir,'unavailable-source.json'))?JSON.parse(fs.readFileSync(path.join(dir,'unavailable-source.json'))).map(r=>r.id):[]),remaining=new Map(),tables=new Map(),excluded=new Set(['StorageConfig','StorageMigrationTask','ImageArchiveJob','__drizzle_migrations','SystemSettingHistory','SystemSettingSnapshot']);
|
|
const columns=await sql`select c.table_name as "tableName",c.column_name as "columnName" from information_schema.columns c join information_schema.tables t on c.table_schema=t.table_schema and c.table_name=t.table_name where c.table_schema='public' and t.table_type='BASE TABLE' and c.data_type in ('text','character varying','json','jsonb') order by c.table_name,c.ordinal_position`;
|
|
for(const c of columns)if(!excluded.has(c.tableName)){if(!tables.has(c.tableName))tables.set(c.tableName,[]);tables.get(c.tableName).push(c.columnName);}const tableCounts={};for(const [table,cols] of tables){const where=cols.map(c=>'('+quote(c)+'::text like $1'+(table==='ImageArchiveTask'&&c==='sourceUrl'?" and coalesce(metadata->>'legacyOssMigrationRun','') <> '20261014'":'')+')').join(' or ');let matched=0;for await(const rows of sql.unsafe('select '+cols.map(quote).join(',')+' from '+quote(table)+' where '+where,['%'+host+'/%']).cursor(50))for(const row of rows){matched++;for(const [column,value]of Object.entries(row)){if(table==='ImageArchiveTask'&&column==='sourceUrl'&&row.metadata?.legacyOssMigrationRun==='20261014')continue;for(const r of urlsIn(value))if(r.sourceHost===host){if(!remaining.has(r.id))remaining.set(r.id,{...r,verified:verified.has(r.id),knownUnavailable:unavailable.has(r.id),locations:{}});const item=remaining.get(r.id),key=table+'.'+column;item.locations[key]=(item.locations[key]||0)+1;}}}if(matched){tableCounts[table]=matched;console.log('remaining_reference_rows',JSON.stringify({table,rows:matched}));}}
|
|
const resources=[...remaining.values()],summary={auditedAt:new Date().toISOString(),remainingUniqueResources:resources.length,verifiedPendingRewrite:resources.filter(r=>r.verified).length,knownUnavailable:resources.filter(r=>r.knownUnavailable&&!r.verified).length,unclassified:resources.filter(r=>!r.knownUnavailable&&!r.verified).length,tableCounts};fs.writeFileSync(path.join(dir,'reference-audit-resources.json'),JSON.stringify(resources),{mode:0o600});fs.writeFileSync(path.join(dir,'reference-audit-summary.json'),JSON.stringify(summary,null,2),{mode:0o600});console.log('reference_audit',JSON.stringify(summary));}finally{await sql.end()}})().catch(e=>{console.error('audit_failed',e.name,String(e.message).replace(/https?:\/\/\S+/g,'[URL]').slice(0,180));process.exitCode=1});
|