抽离后台平台配置写入归一化逻辑
This commit is contained in:
@@ -99,7 +99,11 @@ import {
|
||||
validateAdminFulfillmentBindingConfigs,
|
||||
} from './validation.js'
|
||||
import {
|
||||
applyOptionalStringField,
|
||||
buildAdminAgisoMessagingSavePayload,
|
||||
normalizeAdminCloudtentaclesSourceConfigPayload,
|
||||
normalizeAdminKhhaoSourceConfigPayload,
|
||||
} from './writes.js'
|
||||
import {
|
||||
mapAdminAgisoMessagingDefaults,
|
||||
mapAdminAgisoShopConfigItem,
|
||||
mapAdminFulfillmentBindingConfigItem,
|
||||
@@ -173,73 +177,10 @@ export async function getAdminAgisoShopConfigs() {
|
||||
|
||||
/** @param {AdminAgisoShopConfigSaveInput} [payload] */
|
||||
export function updateAdminAgisoShopConfigs(payload = /** @type {AdminAgisoShopConfigSaveInput} */ ({})) {
|
||||
const rawItems = Array.isArray(payload.shops) ? payload.shops : []
|
||||
const currentDefaults = getAgisoMessagingDefaults()
|
||||
const 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,
|
||||
})
|
||||
const saved = saveAgisoMessagingConfig(buildAdminAgisoMessagingSavePayload(payload, {
|
||||
currentDefaults: getAgisoMessagingDefaults(),
|
||||
currentMap: getAgisoShopConfigMap(),
|
||||
}))
|
||||
|
||||
return {
|
||||
filePath: getAgisoShopsFilePath(),
|
||||
@@ -287,19 +228,7 @@ export function updateAdminKuaishouEticketSourceConfig(payload = /** @type {Admi
|
||||
|
||||
/** @param {AdminKhhaoSourceConfigInput} [payload] */
|
||||
export function updateAdminKhhaoSourceConfig(payload = /** @type {AdminKhhaoSourceConfigInput} */ ({})) {
|
||||
const saved = saveKhhaoSourceConfig({
|
||||
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 saved = saveKhhaoSourceConfig(normalizeAdminKhhaoSourceConfigPayload(payload))
|
||||
const syncState = saved.autoSync?.enabled ? ensureKhhaoSyncBaseline() : getKhhaoSyncState()
|
||||
|
||||
return {
|
||||
@@ -444,15 +373,7 @@ export function getAdminCloudtentaclesSourceConfig() {
|
||||
/** @param {AdminCloudtentaclesSourceConfigInput} [payload] */
|
||||
export function updateAdminCloudtentaclesSourceConfig(payload = /** @type {AdminCloudtentaclesSourceConfigInput} */ ({})) {
|
||||
const current = getCloudtentaclesSourceConfig()
|
||||
const saved = saveCloudtentaclesSourceConfig({
|
||||
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 saved = saveCloudtentaclesSourceConfig(normalizeAdminCloudtentaclesSourceConfigPayload(payload))
|
||||
const shouldClearSession = hasCloudtentaclesCredentialContextChanged(current, saved)
|
||||
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