抽离后台平台配置写入归一化逻辑
This commit is contained in:
@@ -99,7 +99,11 @@ import {
|
|||||||
validateAdminFulfillmentBindingConfigs,
|
validateAdminFulfillmentBindingConfigs,
|
||||||
} from './validation.js'
|
} from './validation.js'
|
||||||
import {
|
import {
|
||||||
applyOptionalStringField,
|
buildAdminAgisoMessagingSavePayload,
|
||||||
|
normalizeAdminCloudtentaclesSourceConfigPayload,
|
||||||
|
normalizeAdminKhhaoSourceConfigPayload,
|
||||||
|
} from './writes.js'
|
||||||
|
import {
|
||||||
mapAdminAgisoMessagingDefaults,
|
mapAdminAgisoMessagingDefaults,
|
||||||
mapAdminAgisoShopConfigItem,
|
mapAdminAgisoShopConfigItem,
|
||||||
mapAdminFulfillmentBindingConfigItem,
|
mapAdminFulfillmentBindingConfigItem,
|
||||||
@@ -173,73 +177,10 @@ export async function getAdminAgisoShopConfigs() {
|
|||||||
|
|
||||||
/** @param {AdminAgisoShopConfigSaveInput} [payload] */
|
/** @param {AdminAgisoShopConfigSaveInput} [payload] */
|
||||||
export function updateAdminAgisoShopConfigs(payload = /** @type {AdminAgisoShopConfigSaveInput} */ ({})) {
|
export function updateAdminAgisoShopConfigs(payload = /** @type {AdminAgisoShopConfigSaveInput} */ ({})) {
|
||||||
const rawItems = Array.isArray(payload.shops) ? payload.shops : []
|
const saved = saveAgisoMessagingConfig(buildAdminAgisoMessagingSavePayload(payload, {
|
||||||
const currentDefaults = getAgisoMessagingDefaults()
|
currentDefaults: getAgisoMessagingDefaults(),
|
||||||
const currentMap = getAgisoShopConfigMap()
|
currentMap: getAgisoShopConfigMap(),
|
||||||
const nextDefaults = { ...currentDefaults }
|
}))
|
||||||
const nextMap = {}
|
|
||||||
|
|
||||||
applyOptionalStringField(nextDefaults, 'messageTemplate', payload.defaults)
|
|
||||||
applyOptionalStringField(nextDefaults, 'autoDeliveryMessageTemplate', payload.defaults)
|
|
||||||
|
|
||||||
for (const item of rawItems) {
|
|
||||||
const shopId = String(item?.shopId || '').trim()
|
|
||||||
if (!shopId) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
const current = currentMap[shopId] || {}
|
|
||||||
const next = { ...current }
|
|
||||||
const shopName = String(item?.shopName || '').trim()
|
|
||||||
const accessToken = String(item?.accessToken || '').trim()
|
|
||||||
const messageTemplate = String(item?.messageTemplate || '').trim()
|
|
||||||
const autoDeliveryMessageTemplate = String(item?.autoDeliveryMessageTemplate || '').trim()
|
|
||||||
const appSecret = String(item?.appSecret || '').trim()
|
|
||||||
const apiVersion = String(item?.apiVersion || '').trim()
|
|
||||||
const sendMessageEndpoint = String(item?.sendMessageEndpoint || '').trim()
|
|
||||||
|
|
||||||
if (shopName) {
|
|
||||||
next.shopName = shopName
|
|
||||||
} else {
|
|
||||||
delete next.shopName
|
|
||||||
}
|
|
||||||
if (accessToken) {
|
|
||||||
next.accessToken = accessToken
|
|
||||||
}
|
|
||||||
if (messageTemplate) {
|
|
||||||
next.messageTemplate = messageTemplate
|
|
||||||
} else if (typeof item?.messageTemplate === 'string') {
|
|
||||||
delete next.messageTemplate
|
|
||||||
}
|
|
||||||
if (autoDeliveryMessageTemplate) {
|
|
||||||
next.autoDeliveryMessageTemplate = autoDeliveryMessageTemplate
|
|
||||||
} else if (typeof item?.autoDeliveryMessageTemplate === 'string') {
|
|
||||||
delete next.autoDeliveryMessageTemplate
|
|
||||||
}
|
|
||||||
if (appSecret) {
|
|
||||||
next.appSecret = appSecret
|
|
||||||
}
|
|
||||||
if (apiVersion) {
|
|
||||||
next.apiVersion = apiVersion
|
|
||||||
}
|
|
||||||
if (sendMessageEndpoint) {
|
|
||||||
next.sendMessageEndpoint = sendMessageEndpoint
|
|
||||||
}
|
|
||||||
if (typeof item?.enabled === 'boolean') {
|
|
||||||
next.enabled = item.enabled
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!next.accessToken) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
nextMap[shopId] = next
|
|
||||||
}
|
|
||||||
|
|
||||||
const saved = saveAgisoMessagingConfig({
|
|
||||||
defaults: nextDefaults,
|
|
||||||
shops: nextMap,
|
|
||||||
})
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
filePath: getAgisoShopsFilePath(),
|
filePath: getAgisoShopsFilePath(),
|
||||||
@@ -287,19 +228,7 @@ export function updateAdminKuaishouEticketSourceConfig(payload = /** @type {Admi
|
|||||||
|
|
||||||
/** @param {AdminKhhaoSourceConfigInput} [payload] */
|
/** @param {AdminKhhaoSourceConfigInput} [payload] */
|
||||||
export function updateAdminKhhaoSourceConfig(payload = /** @type {AdminKhhaoSourceConfigInput} */ ({})) {
|
export function updateAdminKhhaoSourceConfig(payload = /** @type {AdminKhhaoSourceConfigInput} */ ({})) {
|
||||||
const saved = saveKhhaoSourceConfig({
|
const saved = saveKhhaoSourceConfig(normalizeAdminKhhaoSourceConfigPayload(payload))
|
||||||
enabled: payload.enabled !== false,
|
|
||||||
baseUrl: String(payload.baseUrl || '').trim() || 'https://admin.khhao.com',
|
|
||||||
username: String(payload.username || '').trim(),
|
|
||||||
password: String(payload.password || '').trim(),
|
|
||||||
maxCaptchaAttempts: Number(payload.maxCaptchaAttempts || 3) || 3,
|
|
||||||
autoSync: {
|
|
||||||
enabled: payload.autoSync?.enabled === true,
|
|
||||||
intervalMinutes: Number(payload.autoSync?.intervalMinutes || 3) || 3,
|
|
||||||
pages: Number(payload.autoSync?.pages || 2) || 2,
|
|
||||||
pageSize: Number(payload.autoSync?.pageSize || 20) || 20,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
const syncState = saved.autoSync?.enabled ? ensureKhhaoSyncBaseline() : getKhhaoSyncState()
|
const syncState = saved.autoSync?.enabled ? ensureKhhaoSyncBaseline() : getKhhaoSyncState()
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -444,15 +373,7 @@ export function getAdminCloudtentaclesSourceConfig() {
|
|||||||
/** @param {AdminCloudtentaclesSourceConfigInput} [payload] */
|
/** @param {AdminCloudtentaclesSourceConfigInput} [payload] */
|
||||||
export function updateAdminCloudtentaclesSourceConfig(payload = /** @type {AdminCloudtentaclesSourceConfigInput} */ ({})) {
|
export function updateAdminCloudtentaclesSourceConfig(payload = /** @type {AdminCloudtentaclesSourceConfigInput} */ ({})) {
|
||||||
const current = getCloudtentaclesSourceConfig()
|
const current = getCloudtentaclesSourceConfig()
|
||||||
const saved = saveCloudtentaclesSourceConfig({
|
const saved = saveCloudtentaclesSourceConfig(normalizeAdminCloudtentaclesSourceConfigPayload(payload))
|
||||||
enabled: payload.enabled !== false,
|
|
||||||
baseUrl: String(payload.baseUrl || '').trim() || 'https://123.207.217.176',
|
|
||||||
username: String(payload.username || '').trim(),
|
|
||||||
password: String(payload.password || '').trim(),
|
|
||||||
phone: String(payload.phone || '').trim(),
|
|
||||||
deviceId: String(payload.deviceId || '-').trim() || '-',
|
|
||||||
deviceType: Number(payload.deviceType || 0),
|
|
||||||
})
|
|
||||||
const shouldClearSession = hasCloudtentaclesCredentialContextChanged(current, saved)
|
const shouldClearSession = hasCloudtentaclesCredentialContextChanged(current, saved)
|
||||||
const session = shouldClearSession ? clearCloudtentaclesSessionState() : getCloudtentaclesSessionState()
|
const session = shouldClearSession ? clearCloudtentaclesSessionState() : getCloudtentaclesSessionState()
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,117 @@
|
|||||||
|
// @ts-check
|
||||||
|
|
||||||
|
import { applyOptionalStringField } from './domain.js'
|
||||||
|
|
||||||
|
export function buildAdminAgisoShopConfigUpdate(item, current = {}) {
|
||||||
|
const shopId = String(item?.shopId || '').trim()
|
||||||
|
if (!shopId) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const next = /** @type {Record<string, unknown>} */ ({ ...current })
|
||||||
|
const shopName = String(item?.shopName || '').trim()
|
||||||
|
const accessToken = String(item?.accessToken || '').trim()
|
||||||
|
const messageTemplate = String(item?.messageTemplate || '').trim()
|
||||||
|
const autoDeliveryMessageTemplate = String(item?.autoDeliveryMessageTemplate || '').trim()
|
||||||
|
const appSecret = String(item?.appSecret || '').trim()
|
||||||
|
const apiVersion = String(item?.apiVersion || '').trim()
|
||||||
|
const sendMessageEndpoint = String(item?.sendMessageEndpoint || '').trim()
|
||||||
|
|
||||||
|
if (shopName) {
|
||||||
|
next.shopName = shopName
|
||||||
|
} else {
|
||||||
|
delete next.shopName
|
||||||
|
}
|
||||||
|
if (accessToken) {
|
||||||
|
next.accessToken = accessToken
|
||||||
|
}
|
||||||
|
if (messageTemplate) {
|
||||||
|
next.messageTemplate = messageTemplate
|
||||||
|
} else if (typeof item?.messageTemplate === 'string') {
|
||||||
|
delete next.messageTemplate
|
||||||
|
}
|
||||||
|
if (autoDeliveryMessageTemplate) {
|
||||||
|
next.autoDeliveryMessageTemplate = autoDeliveryMessageTemplate
|
||||||
|
} else if (typeof item?.autoDeliveryMessageTemplate === 'string') {
|
||||||
|
delete next.autoDeliveryMessageTemplate
|
||||||
|
}
|
||||||
|
if (appSecret) {
|
||||||
|
next.appSecret = appSecret
|
||||||
|
}
|
||||||
|
if (apiVersion) {
|
||||||
|
next.apiVersion = apiVersion
|
||||||
|
}
|
||||||
|
if (sendMessageEndpoint) {
|
||||||
|
next.sendMessageEndpoint = sendMessageEndpoint
|
||||||
|
}
|
||||||
|
if (typeof item?.enabled === 'boolean') {
|
||||||
|
next.enabled = item.enabled
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!next.accessToken) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return { shopId, config: next }
|
||||||
|
}
|
||||||
|
|
||||||
|
export function buildAdminAgisoMessagingSavePayload(
|
||||||
|
payload = {},
|
||||||
|
options = {},
|
||||||
|
) {
|
||||||
|
const rawItems = Array.isArray(payload.shops) ? payload.shops : []
|
||||||
|
const currentDefaults = /** @type {Record<string, unknown>} */ (options.currentDefaults || {})
|
||||||
|
const currentMap = /** @type {Record<string, Record<string, unknown>>} */ (options.currentMap || {})
|
||||||
|
const nextDefaults = /** @type {Record<string, unknown>} */ ({ ...currentDefaults })
|
||||||
|
const nextMap = /** @type {Record<string, Record<string, unknown>>} */ ({})
|
||||||
|
|
||||||
|
applyOptionalStringField(nextDefaults, 'messageTemplate', payload.defaults)
|
||||||
|
applyOptionalStringField(nextDefaults, 'autoDeliveryMessageTemplate', payload.defaults)
|
||||||
|
|
||||||
|
for (const item of rawItems) {
|
||||||
|
const shopId = String(item?.shopId || '').trim()
|
||||||
|
if (!shopId) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
const updated = buildAdminAgisoShopConfigUpdate(item, currentMap[shopId] || {})
|
||||||
|
if (!updated) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
nextMap[updated.shopId] = updated.config
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
defaults: nextDefaults,
|
||||||
|
shops: nextMap,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function normalizeAdminKhhaoSourceConfigPayload(payload = {}) {
|
||||||
|
return {
|
||||||
|
enabled: payload.enabled !== false,
|
||||||
|
baseUrl: String(payload.baseUrl || '').trim() || 'https://admin.khhao.com',
|
||||||
|
username: String(payload.username || '').trim(),
|
||||||
|
password: String(payload.password || '').trim(),
|
||||||
|
maxCaptchaAttempts: Number(payload.maxCaptchaAttempts || 3) || 3,
|
||||||
|
autoSync: {
|
||||||
|
enabled: payload.autoSync?.enabled === true,
|
||||||
|
intervalMinutes: Number(payload.autoSync?.intervalMinutes || 3) || 3,
|
||||||
|
pages: Number(payload.autoSync?.pages || 2) || 2,
|
||||||
|
pageSize: Number(payload.autoSync?.pageSize || 20) || 20,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function normalizeAdminCloudtentaclesSourceConfigPayload(payload = {}) {
|
||||||
|
return {
|
||||||
|
enabled: payload.enabled !== false,
|
||||||
|
baseUrl: String(payload.baseUrl || '').trim() || 'https://123.207.217.176',
|
||||||
|
username: String(payload.username || '').trim(),
|
||||||
|
password: String(payload.password || '').trim(),
|
||||||
|
phone: String(payload.phone || '').trim(),
|
||||||
|
deviceId: String(payload.deviceId || '-').trim() || '-',
|
||||||
|
deviceType: Number(payload.deviceType || 0),
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,157 @@
|
|||||||
|
import test from 'node:test'
|
||||||
|
import assert from 'node:assert/strict'
|
||||||
|
|
||||||
|
import {
|
||||||
|
buildAdminAgisoMessagingSavePayload,
|
||||||
|
buildAdminAgisoShopConfigUpdate,
|
||||||
|
normalizeAdminCloudtentaclesSourceConfigPayload,
|
||||||
|
normalizeAdminKhhaoSourceConfigPayload,
|
||||||
|
} from './writes.js'
|
||||||
|
|
||||||
|
test('buildAdminAgisoShopConfigUpdate merges item fields and drops explicit empty templates', () => {
|
||||||
|
assert.deepEqual(
|
||||||
|
buildAdminAgisoShopConfigUpdate(
|
||||||
|
{
|
||||||
|
shopId: ' shop-1 ',
|
||||||
|
shopName: ' ',
|
||||||
|
accessToken: ' new-token ',
|
||||||
|
messageTemplate: ' ',
|
||||||
|
autoDeliveryMessageTemplate: ' done ',
|
||||||
|
enabled: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
shopName: '旧店铺',
|
||||||
|
accessToken: 'old-token',
|
||||||
|
messageTemplate: 'old-template',
|
||||||
|
autoDeliveryMessageTemplate: 'old-auto',
|
||||||
|
appSecret: 'keep-secret',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
{
|
||||||
|
shopId: 'shop-1',
|
||||||
|
config: {
|
||||||
|
accessToken: 'new-token',
|
||||||
|
autoDeliveryMessageTemplate: 'done',
|
||||||
|
appSecret: 'keep-secret',
|
||||||
|
enabled: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('buildAdminAgisoMessagingSavePayload updates defaults and keeps only shops with resulting access token', () => {
|
||||||
|
assert.deepEqual(
|
||||||
|
buildAdminAgisoMessagingSavePayload(
|
||||||
|
{
|
||||||
|
defaults: {
|
||||||
|
messageTemplate: ' next\\nline ',
|
||||||
|
autoDeliveryMessageTemplate: ' ',
|
||||||
|
},
|
||||||
|
shops: [
|
||||||
|
{
|
||||||
|
shopId: ' shop-1 ',
|
||||||
|
shopName: '店铺一',
|
||||||
|
accessToken: '',
|
||||||
|
enabled: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
shopId: 'shop-2',
|
||||||
|
shopName: ' 店铺二 ',
|
||||||
|
accessToken: ' token-2 ',
|
||||||
|
messageTemplate: ' hi ',
|
||||||
|
apiVersion: ' v2 ',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
shopId: '',
|
||||||
|
accessToken: 'skip',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
currentDefaults: {
|
||||||
|
messageTemplate: 'old',
|
||||||
|
autoDeliveryMessageTemplate: 'old-auto',
|
||||||
|
},
|
||||||
|
currentMap: {
|
||||||
|
'shop-1': {
|
||||||
|
accessToken: 'token-1',
|
||||||
|
autoDeliveryMessageTemplate: 'keep-auto',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
),
|
||||||
|
{
|
||||||
|
defaults: {
|
||||||
|
messageTemplate: 'next\nline',
|
||||||
|
},
|
||||||
|
shops: {
|
||||||
|
'shop-1': {
|
||||||
|
accessToken: 'token-1',
|
||||||
|
autoDeliveryMessageTemplate: 'keep-auto',
|
||||||
|
enabled: true,
|
||||||
|
shopName: '店铺一',
|
||||||
|
},
|
||||||
|
'shop-2': {
|
||||||
|
accessToken: 'token-2',
|
||||||
|
apiVersion: 'v2',
|
||||||
|
messageTemplate: 'hi',
|
||||||
|
shopName: '店铺二',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('normalizeAdminKhhaoSourceConfigPayload applies defaults and numeric fallbacks', () => {
|
||||||
|
assert.deepEqual(
|
||||||
|
normalizeAdminKhhaoSourceConfigPayload({
|
||||||
|
enabled: true,
|
||||||
|
baseUrl: ' https://admin.khhao.com ',
|
||||||
|
username: ' user ',
|
||||||
|
password: ' pass ',
|
||||||
|
maxCaptchaAttempts: 0,
|
||||||
|
autoSync: {
|
||||||
|
enabled: true,
|
||||||
|
intervalMinutes: '',
|
||||||
|
pages: '0',
|
||||||
|
pageSize: '50',
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
enabled: true,
|
||||||
|
baseUrl: 'https://admin.khhao.com',
|
||||||
|
username: 'user',
|
||||||
|
password: 'pass',
|
||||||
|
maxCaptchaAttempts: 3,
|
||||||
|
autoSync: {
|
||||||
|
enabled: true,
|
||||||
|
intervalMinutes: 3,
|
||||||
|
pages: 2,
|
||||||
|
pageSize: 50,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('normalizeAdminCloudtentaclesSourceConfigPayload applies defaults', () => {
|
||||||
|
assert.deepEqual(
|
||||||
|
normalizeAdminCloudtentaclesSourceConfigPayload({
|
||||||
|
enabled: false,
|
||||||
|
baseUrl: ' ',
|
||||||
|
username: ' user ',
|
||||||
|
password: ' pass ',
|
||||||
|
phone: ' 13800138000 ',
|
||||||
|
deviceId: ' ',
|
||||||
|
deviceType: '2',
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
enabled: false,
|
||||||
|
baseUrl: 'https://123.207.217.176',
|
||||||
|
username: 'user',
|
||||||
|
password: 'pass',
|
||||||
|
phone: '13800138000',
|
||||||
|
deviceId: '-',
|
||||||
|
deviceType: 2,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
})
|
||||||
Reference in New Issue
Block a user