server/laf-cloud/functions/goldMiner/postman/gold-miner-test-period.postman_collection.json
2026-09-24 17:59:52 +08:00

125 lines
7.1 KiB
JSON
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{
"info": {
"name": "黄金矿工 - 临时期发布(test-period)",
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
"description": "POST /goldMiner/admin,action=publish_test_period。仅测试环境可用。配合 gold-miner-test-period.postman_environment.json 使用。填写 baseUrl/adminToken 后默认立即开启 30 分钟;时间与期 ID 自动保存,重复 Send 保持同一期。自定义时间、奖励和下一期见 gold-miner-test-period.README.md。请求会真实发布测试活动;不会模拟支付或发放奖励。"
},
"auth": {
"type": "noauth"
},
"item": [
{
"name": "发布临时期(默认立即开启 30 分钟)",
"event": [
{
"listen": "prerequest",
"script": {
"type": "text/javascript",
"exec": [
"function stop(message) { console.error(message); pm.execution.skipRequest(); throw new Error(message); }",
"const get = key => String(pm.environment.get(key) ?? '').trim();",
"const baseUrl = get('baseUrl');",
"if (!/^https?:\\/\\/[^\\s/?#]+(?::\\d+)?(?:\\/[^\\s?#]*)?$/.test(baseUrl) || baseUrl.endsWith('/') || /[<>]/.test(baseUrl)) stop('请填写 baseUrl(部署域名,无末尾 /)');",
"const adminToken = pm.environment.get('adminToken');",
"if (typeof adminToken !== 'string' || !adminToken.trim()) stop('请填写测试服 ADMIN_TOKEN 对应的 adminToken');",
"function timestamp(value, label) {",
" if (!/^\\d+$/.test(value) || !Number.isSafeInteger(Number(value)) || Number(value) <= 0 || !Number.isFinite(new Date(Number(value)).getTime())) stop(label + ' 必须为有效的 Unix 毫秒整数');",
" return Number(value);",
"}",
"let config;",
"try { config = JSON.parse(get('tempConfig')); } catch { stop('tempConfig 必须为 JSON 配置对象'); }",
"if (!config || typeof config !== 'object' || Array.isArray(config)) stop('tempConfig 必须为 JSON 配置对象');",
"let periodId = get('tempPeriodId');",
"if (periodId && !/^goldMiner:test:[A-Za-z0-9_-]{1,60}$/.test(periodId)) stop('tempPeriodId 格式为 goldMiner:test:自定义标识');",
"const startsAt = get('tempStartsAt') ? timestamp(get('tempStartsAt'), 'tempStartsAt') : Date.now();",
"let endsAt;",
"if (get('tempEndsAt')) endsAt = timestamp(get('tempEndsAt'), 'tempEndsAt');",
"else {",
" const minutes = Number(get('tempDurationMinutes'));",
" if (!Number.isSafeInteger(minutes) || minutes <= 0) stop('tempDurationMinutes 必须为正整数分钟');",
" endsAt = timestamp(String(startsAt + minutes * 60000), '计算出的结束时间');",
"}",
"if (endsAt <= startsAt) stop('tempEndsAt 必须晚于 tempStartsAt');",
"const nextPeriodId = get('tempNextPeriodId');",
"if (nextPeriodId && !/^goldMiner:(?:test:[A-Za-z0-9_-]{1,60}|\\d{4}-\\d{2}-\\d{2})$/.test(nextPeriodId)) stop('tempNextPeriodId 格式错误');",
"const previousBase = get('tempDraftBaseUrl');",
"if (previousBase && previousBase !== baseUrl) stop('baseUrl 已切换,请使用另一份环境,或清空 tempDraftBaseUrl/tempPeriodId/tempStartsAt/tempEndsAt 后重新生成');",
"if (!periodId) periodId = 'goldMiner:test:' + pm.variables.replaceIn('{{$guid}}');",
"// Only non-secret identifiers/times are persisted. Retrying Send reuses the same period.",
"pm.environment.set('tempPeriodId', periodId);",
"pm.environment.set('tempStartsAt', String(startsAt));",
"pm.environment.set('tempEndsAt', String(endsAt));",
"pm.environment.set('tempDraftBaseUrl', baseUrl);",
"const body = { action: 'publish_test_period', adminToken, periodId, startsAt, endsAt, config };",
"if (nextPeriodId) body.nextPeriodId = nextPeriodId;",
"// Local scope avoids storing a second copy of the administrator secret in the environment.",
"pm.variables.set('testPeriodRequestBody', JSON.stringify(body));"
]
}
},
{
"listen": "test",
"script": {
"type": "text/javascript",
"exec": [
"pm.test('HTTP 200', function () { pm.response.to.have.status(200); });",
"const response = pm.response.json();",
"const sent = JSON.parse(pm.variables.get('testPeriodRequestBody'));",
"pm.test('临时期发布成功(失败时查看响应 errorCode/msg)', function () { pm.expect(response.code).to.eql(1); });",
"if (response.code === 1 && response.data) {",
" const data = response.data;",
" pm.test('期 ID、开始和结束时间与请求一致', function () {",
" pm.expect(data.periodId).to.eql(sent.periodId);",
" pm.expect(data.startsAt).to.eql(sent.startsAt);",
" pm.expect(data.endsAt).to.eql(sent.endsAt);",
" });",
" pm.test('奖励配置和商品快照与请求一致', function () {",
" for (const key of ['configVersion', 'unlockPassedLevel', 'timezone', 'currency', ...(sent.config.vipTiers ? ['vipTiers'] : ['productId', 'priceFen', 'tasks'])]) {",
" pm.expect(data.configSnapshot[key]).to.eql(sent.config[key]);",
" }",
" pm.expect(data.configSnapshot.effectiveFromPeriodId).to.eql(sent.periodId);",
" pm.expect(typeof data.configHash).to.eql('string');",
" });",
" pm.test('顺延目标不早于本期结束', function () {",
" pm.expect(Number.isSafeInteger(data.nextStartsAt) && data.nextStartsAt >= sent.endsAt).to.eql(true);",
" if (sent.nextPeriodId) pm.expect(data.nextPeriodId).to.eql(sent.nextPeriodId);",
" });",
"}"
]
}
}
],
"request": {
"method": "POST",
"header": [
{
"key": "Content-Type",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"raw": "{{testPeriodRequestBody}}",
"options": {
"raw": {
"language": "json"
}
}
},
"url": {
"raw": "{{baseUrl}}/goldMiner/admin",
"host": [
"{{baseUrl}}"
],
"path": [
"goldMiner",
"admin"
]
},
"description": "参数在配套 Environment 中配置。tempPeriodId/tempStartsAt/tempEndsAt 留空时首次自动生成并保存。tempConfig 为完整业务配置 JSON,可修改门槛、价格及任务。tempNextPeriodId 可留空。已发布期不可修改;新建期时使用新的期 ID 及不重叠的时间。接口对应服务端 publish_test_period 动作,没有单独的 /test-period 路由。"
},
"response": []
}
]
}