|
|
@@ -114,6 +114,8 @@ let storeStyleRestore = null;
|
|
|
let temporaryStoreApplicationId = '';
|
|
|
let temporaryStoreStyleId = '';
|
|
|
let contentTagsRestore = null;
|
|
|
+let userLevelRestore = null;
|
|
|
+let temporaryUserLevelId = '';
|
|
|
const temporaryLessonIds = [];
|
|
|
try {
|
|
|
const sample = await jsonRequest(`${PARSE_URL}/classes/Company?limit=1&keys=objectId`, {}, true);
|
|
|
@@ -345,6 +347,12 @@ try {
|
|
|
const contentTagPage = await callFunction('xiaoshu/admin/gateway', login.sessionToken, { operation: 'contentTagKeys', className: 'ContentTagKey', page: 1, pageSize: 20, search: '' }); const originalContentTags = Array.isArray(contentTagPage.results?.[0]?.tags) ? contentTagPage.results[0].tags.map(String) : []; contentTagsRestore = originalContentTags; const tagProbe = `angular-smoke-${Date.now()}`; const probeContentTags = originalContentTags.length >= 1000 ? [...originalContentTags.slice(0, 999), tagProbe] : [...originalContentTags, tagProbe]; const savedContentTags = await callFunction('xiaoshu/admin/gateway', login.sessionToken, { operation: 'saveContentTagKeys', className: 'ContentTagKey', objectId: 'global-content-tags', tags: probeContentTags }); if (savedContentTags.count !== probeContentTags.length || savedContentTags.tags?.at(-1) !== tagProbe) throw new Error('内容标签 Parse Config 保存异常'); const readContentTags = await callFunction('xiaoshu/admin/gateway', login.sessionToken, { operation: 'getContentTagKeys', className: 'ContentTagKey', objectId: 'global-content-tags' }); if (readContentTags.tags?.at(-1) !== tagProbe) throw new Error('内容标签 Parse Config 写后读失败'); await callFunction('xiaoshu/admin/gateway', login.sessionToken, { operation: 'saveContentTagKeys', className: 'ContentTagKey', objectId: 'global-content-tags', tags: originalContentTags }); contentTagsRestore = null;
|
|
|
for (const action of ['Comment','Commont_API','ConAudit_API','ConAudit_SJ_API','ConAudit','ConAuditDetail','VerBak','VerBak_Del']) { const blocked = await callFunctionError('xiaoshu/admin/gateway', login.sessionToken, { operation: 'legacyContentAddonBlocker', action }, 501); if (!String(blocked.message).startsWith('migration_blocked:')) throw new Error(`内容附加动作 ${action} 未返回明确数据阻塞`); }
|
|
|
for (const action of ['Vendor','Vendor_API','VendorAdd','VendorAdd_Submit']) { const blocked = await callFunctionError('xiaoshu/admin/gateway', login.sessionToken, { operation: 'legacyShopVendorBlocker', action }, 501); if (!String(blocked.message).startsWith('migration_blocked:')) throw new Error(`旧供应商动作 ${action} 未返回明确数据阻塞`); }
|
|
|
+ const userLevelSchema = await callFunction('xiaoshu/admin/gateway', login.sessionToken, { operation: 'schema', className: 'UserLevel' }); const userLevelFieldMap = Object.fromEntries((userLevelSchema.fields || []).map((field) => [field.name, field])); if (userLevelSchema.creatable !== false || ['id','cdate','ztype','addon1','addon2','addon3','addon4','addon5','orderId','storeId','zstatus','sourceKey','discountRate'].some((name) => userLevelFieldMap[name]?.writable !== false) || ['alias','pointRate','image','remark'].some((name) => userLevelFieldMap[name]?.writable !== true)) throw new Error('积分等级 Schema 字段隔离异常');
|
|
|
+ const userLevels = await callFunction('xiaoshu/admin/gateway', login.sessionToken, { operation: 'userLevels', className: 'UserLevel', page: 1, pageSize: 100, search: '' }); const sampleUserLevel = userLevels.results?.[0]; if (userLevels.total < 1 || !sampleUserLevel?.objectId || !Number(sampleUserLevel.id) || !sampleUserLevel.alias) throw new Error('积分等级历史数据读取异常');
|
|
|
+ const userLevelCreateBlocked = await callFunctionError('xiaoshu/admin/gateway', login.sessionToken, { operation: 'saveUserLevel', className: 'UserLevel', fields: {} }, 501); if (!String(userLevelCreateBlocked.message).includes('UserLevel.id')) throw new Error('积分等级新增未返回旧 ID 阻塞原因'); userLevelRestore = { objectId: sampleUserLevel.objectId, fields: { alias: sampleUserLevel.alias, pointRate: Number(sampleUserLevel.pointRate || 0), image: sampleUserLevel.image, remark: sampleUserLevel.remark } }; const levelProbeRemark = `${String(sampleUserLevel.remark || '')} [angular-smoke]`.trim(); const savedUserLevel = await callFunction('xiaoshu/admin/gateway', login.sessionToken, { operation: 'saveUserLevel', className: 'UserLevel', objectId: sampleUserLevel.objectId, fields: { ...sampleUserLevel, pointRate: Number(sampleUserLevel.pointRate || 0), remark: levelProbeRemark } }); if (savedUserLevel.remark !== levelProbeRemark || Number(savedUserLevel.id) !== Number(sampleUserLevel.id)) throw new Error('积分等级专用编辑失败'); await jsonRequest(`${PARSE_URL}/classes/UserLevel/${userLevelRestore.objectId}`, { method: 'PUT', body: JSON.stringify(userLevelRestore.fields) }, true); userLevelRestore = null;
|
|
|
+ const directUserLevel = await jsonRequest(`${PARSE_URL}/classes/UserLevel`, { method: 'POST', body: JSON.stringify({ alias: '__user_level_delete_smoke__', pointRate: 999999, image: '', remark: 'temporary', sourceKey: `smoke-user-level-${Date.now()}`, company }) }, true); temporaryUserLevelId = directUserLevel.objectId; const readDirectUserLevel = await jsonRequest(`${PARSE_URL}/classes/UserLevel/${temporaryUserLevelId}`, {}, true); if (readDirectUserLevel.id != null) throw new Error('积分等级省略 id 的创建探测意外生成了旧编号'); const deletedUserLevel = await callFunction('xiaoshu/admin/gateway', login.sessionToken, { operation: 'userLevelBatch', className: 'UserLevel', action: 'delete', objectIds: [temporaryUserLevelId] }); if (deletedUserLevel.updated !== 1) throw new Error('积分等级批量删除失败'); temporaryUserLevelId = '';
|
|
|
+ const userMoneySchema = await callFunction('xiaoshu/admin/gateway', login.sessionToken, { operation: 'schema', className: 'UserMoneyLog' }); if (userMoneySchema.writable !== false || userMoneySchema.creatable !== false || userMoneySchema.fields?.some((field) => field.writable)) throw new Error('资金积分流水虚拟 Schema 应全部只读'); const moneyPage = await callFunction('xiaoshu/admin/gateway', login.sessionToken, { operation: 'userMoneyLogs', className: 'UserMoneyLog', type: 1, page: 1, pageSize: 20, search: '', startDate: '', endDate: '' }); const sampleMoneyLog = moneyPage.results?.[0]; if (moneyPage.total < 1 || !String(sampleMoneyLog?.objectId || '').startsWith('UserExpDomP:') || sampleMoneyLog.moneyTypeLabel !== '余额') throw new Error('余额流水规范化聚合异常'); const moneyDetail = await callFunction('xiaoshu/admin/gateway', login.sessionToken, { operation: 'getUserMoneyLog', className: 'UserMoneyLog', objectId: sampleMoneyLog.objectId }); if (moneyDetail.objectId !== sampleMoneyLog.objectId || moneyDetail.recordObjectId !== sampleMoneyLog.recordObjectId) throw new Error('资金流水详情读取异常'); const moneyDate = String(sampleMoneyLog.hisTime?.iso || sampleMoneyLog.hisTime || '').slice(0,10); const filteredMoney = await callFunction('xiaoshu/admin/gateway', login.sessionToken, { operation: 'userMoneyLogs', className: 'UserMoneyLog', type: 1, page: 1, pageSize: 20, search: String(sampleMoneyLog.userId || ''), startDate: moneyDate, endDate: moneyDate }); if (filteredMoney.total < 1) throw new Error('资金流水用户/日期筛选失败'); for (const type of [2,3,4,5,6]) { const ledger = await callFunction('xiaoshu/admin/gateway', login.sessionToken, { operation: 'userMoneyLogs', className: 'UserMoneyLog', type, page: 1, pageSize: 1, search: '', startDate: '', endDate: '' }); if (ledger.className !== 'UserMoneyLog') throw new Error(`资金流水类型 ${type} 未正确路由`); }
|
|
|
+ for (const action of ['ThirdInfo','ThirdInfo_Submit','SigninList','RealNameAuth','RealNameAuthAdd','RealNameAuth_API']) { const blocked = await callFunctionError('xiaoshu/admin/gateway', login.sessionToken, { operation: 'legacyUserAddonBlocker', action }, 501); if (!String(blocked.message).startsWith('migration_blocked:')) throw new Error(`旧用户附加动作 ${action} 未返回明确阻塞原因`); }
|
|
|
await callFunctionError('xiaoshu/admin/gateway', login.sessionToken, { operation: 'save', className: 'Node', fields: { nodeName: '禁止通用新增' } }, 400);
|
|
|
const nodeSuffix = Date.now().toString(36);
|
|
|
const rootNode = await callFunction('xiaoshu/admin/gateway', login.sessionToken, { operation: 'saveNode', className: 'Node', parentId: 0, fields: { nodeName: `云函数冒烟栏目-${nodeSuffix}`, nodeDir: `smoke-${nodeSuffix}`, nodeType: 1, contentModel: '54' } });
|
|
|
@@ -780,7 +788,7 @@ try {
|
|
|
const productBlocked = await callLegacyFunction('', { action: 'product_list' }, 501);
|
|
|
if (!String(productBlocked.retmsg).includes('ZL_Commodities')) throw new Error('缺商品主表的读取接口未明确阻塞');
|
|
|
|
|
|
- console.log('Cloud smoke passed: admin auth/tenant/account lifecycle/group sync/node/special/guest-category/bar/exam-class/exam-point/knowledge/exam-teacher/dictionary/grade-dictionary/currency/holiday/search-navigation/advertising/font-shapes/surveys/customer-service/stores/content-tags/shop-vendor-blockers/api-catalog/config-blockers/model/guestbook lifecycle/content workflow/CRUD reads, CMS projections, normalized learning joins, app action coverage, public content, session scope, explicit blocked APIs.');
|
|
|
+ console.log('Cloud smoke passed: admin auth/tenant/account lifecycle/group sync/node/special/guest-category/bar/exam-class/exam-point/knowledge/exam-teacher/dictionary/grade-dictionary/currency/holiday/search-navigation/advertising/font-shapes/surveys/customer-service/stores/content-tags/shop-vendor-blockers/user-level/money-ledgers/user-addon-blockers/api-catalog/config-blockers/model/guestbook lifecycle/content workflow/CRUD reads, CMS projections, normalized learning joins, app action coverage, public content, session scope, explicit blocked APIs.');
|
|
|
} finally {
|
|
|
if (adZoneRestore) await jsonRequest(`${PARSE_URL}/classes/AdZone/${adZoneRestore.objectId}`, { method: 'PUT', body: JSON.stringify({ remind: adZoneRestore.remind, zstatus: adZoneRestore.zstatus }) }, true).catch((error) => { console.error(`广告位冒烟数据恢复失败:${error.message}`); process.exitCode = 1; });
|
|
|
if (adInfoRestore) await jsonRequest(`${PARSE_URL}/classes/AdInfo/${adInfoRestore.objectId}`, { method: 'PUT', body: JSON.stringify({ remind: adInfoRestore.remind, zstatus: adInfoRestore.zstatus }) }, true).catch((error) => { console.error(`广告内容冒烟数据恢复失败:${error.message}`); process.exitCode = 1; });
|
|
|
@@ -801,6 +809,8 @@ try {
|
|
|
if (temporaryStoreApplicationId) await jsonRequest(`${PARSE_URL}/classes/StoreApplication/${temporaryStoreApplicationId}`, { method: 'DELETE' }, true).catch((error) => { console.error(`临时店铺清理失败:${error.message}`); process.exitCode = 1; });
|
|
|
if (temporaryStoreStyleId) await jsonRequest(`${PARSE_URL}/classes/StoreStyle/${temporaryStoreStyleId}`, { method: 'DELETE' }, true).catch((error) => { console.error(`临时店铺样式清理失败:${error.message}`); process.exitCode = 1; });
|
|
|
if (contentTagsRestore) await jsonRequest(`${PARSE_URL}/config`, { method: 'PUT', body: JSON.stringify({ params: { legacyContentTags: contentTagsRestore } }) }, true).catch((error) => { console.error(`内容标签冒烟数据恢复失败:${error.message}`); process.exitCode = 1; });
|
|
|
+ if (userLevelRestore) await jsonRequest(`${PARSE_URL}/classes/UserLevel/${userLevelRestore.objectId}`, { method: 'PUT', body: JSON.stringify(userLevelRestore.fields) }, true).catch((error) => { console.error(`积分等级冒烟数据恢复失败:${error.message}`); process.exitCode = 1; });
|
|
|
+ if (temporaryUserLevelId) await jsonRequest(`${PARSE_URL}/classes/UserLevel/${temporaryUserLevelId}`, { method: 'DELETE' }, true).catch((error) => { console.error(`临时积分等级清理失败:${error.message}`); process.exitCode = 1; });
|
|
|
if (contentHitObjectId) await jsonRequest(`${PARSE_URL}/classes/CommonModel/${contentHitObjectId}`, { method: 'PUT', body: JSON.stringify({ hits: contentHitOriginal }) }, true).catch((error) => {
|
|
|
console.error(`公开内容浏览量恢复失败:${error.message}`);
|
|
|
process.exitCode = 1;
|