feat: BILLmanager API на уровне хостера, миграция со старых аккаунтов
Docker / build (push) Failing after 18s
Docker / build (push) Failing after 18s
Made-with: Cursor
This commit is contained in:
@@ -4,6 +4,60 @@
|
||||
|
||||
import { randomUUID } from 'node:crypto'
|
||||
|
||||
/**
|
||||
* Перенос apiType/apiBaseUrl с аккаунтов на хостера (idempotent).
|
||||
* Вызывается из миграции и после импорта бэкапа / старого migrate API.
|
||||
* @param {import('sql.js').Database} db
|
||||
*/
|
||||
function selectAllObjects(db, sql, params = []) {
|
||||
const prepared = db.prepare(sql)
|
||||
if (typeof prepared.all === 'function') {
|
||||
return prepared.all(...params)
|
||||
}
|
||||
const stmt = prepared
|
||||
stmt.bind(params)
|
||||
const rows = []
|
||||
while (stmt.step()) {
|
||||
rows.push(stmt.getAsObject())
|
||||
}
|
||||
stmt.free()
|
||||
return rows
|
||||
}
|
||||
|
||||
export function consolidateProviderApiFromAccounts(db) {
|
||||
const provRows = selectAllObjects(db, 'SELECT id, apiType, apiBaseUrl FROM providers')
|
||||
for (const prov of provRows) {
|
||||
const pid = prov.id
|
||||
if (String(prov.apiType || '').trim() || String(prov.apiBaseUrl || '').trim()) {
|
||||
continue
|
||||
}
|
||||
const accRows = selectAllObjects(
|
||||
db,
|
||||
`SELECT apiBaseUrl FROM provider_accounts
|
||||
WHERE providerId = ?
|
||||
AND lower(trim(COALESCE(apiType, ''))) = 'billmanager'
|
||||
AND length(trim(COALESCE(apiBaseUrl, ''))) > 0
|
||||
ORDER BY id`,
|
||||
[pid],
|
||||
)
|
||||
if (!accRows.length) continue
|
||||
const urls = [...new Set(accRows.map((r) => String(r.apiBaseUrl || '').trim()).filter(Boolean))]
|
||||
if (urls.length > 1) {
|
||||
console.warn(
|
||||
`[vps-tracker] У хостера ${pid} у нескольких аккаунтов разный URL BILLmanager — в настройках хостера взят первый.`,
|
||||
)
|
||||
}
|
||||
const apiBaseUrl = urls[0]
|
||||
db.run(`UPDATE providers SET apiType = ?, apiBaseUrl = ? WHERE id = ?`, 'billmanager', apiBaseUrl, pid)
|
||||
db.run(
|
||||
`UPDATE provider_accounts SET apiType = '', apiBaseUrl = ''
|
||||
WHERE providerId = ? AND lower(trim(COALESCE(apiType, ''))) = 'billmanager'
|
||||
AND length(trim(COALESCE(apiBaseUrl, ''))) > 0`,
|
||||
pid,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export const MIGRATIONS = [
|
||||
{
|
||||
name: 'provider_accounts_api',
|
||||
@@ -266,4 +320,20 @@ export const MIGRATIONS = [
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'providers_api_integration',
|
||||
run(db) {
|
||||
try {
|
||||
db.exec('ALTER TABLE providers ADD COLUMN apiType TEXT')
|
||||
} catch (e) {
|
||||
if (!String(e.message || e).includes('duplicate column')) throw e
|
||||
}
|
||||
try {
|
||||
db.exec('ALTER TABLE providers ADD COLUMN apiBaseUrl TEXT')
|
||||
} catch (e) {
|
||||
if (!String(e.message || e).includes('duplicate column')) throw e
|
||||
}
|
||||
consolidateProviderApiFromAccounts(db)
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
+3
-1
@@ -11,7 +11,9 @@ CREATE TABLE IF NOT EXISTS providers (
|
||||
baseCurrency TEXT,
|
||||
usdRate TEXT,
|
||||
eurRate TEXT,
|
||||
notes TEXT
|
||||
notes TEXT,
|
||||
apiType TEXT,
|
||||
apiBaseUrl TEXT
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS provider_accounts (
|
||||
|
||||
+23
-3
@@ -31,17 +31,37 @@ export function seed(db, seedDir) {
|
||||
const run = db.run.bind(db)
|
||||
for (const r of providers) {
|
||||
run(
|
||||
'INSERT OR IGNORE INTO providers (id, name, website, contact, baseCurrency, usdRate, eurRate, notes) VALUES (?, ?, ?, ?, ?, ?, ?, ?)',
|
||||
[r.id, r.name ?? '', r.website ?? '', r.contact ?? '', r.baseCurrency ?? '', r.usdRate ?? '', r.eurRate ?? '', r.notes ?? ''],
|
||||
'INSERT OR IGNORE INTO providers (id, name, website, contact, baseCurrency, usdRate, eurRate, notes, apiType, apiBaseUrl) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)',
|
||||
[
|
||||
r.id,
|
||||
r.name ?? '',
|
||||
r.website ?? '',
|
||||
r.contact ?? '',
|
||||
r.baseCurrency ?? '',
|
||||
r.usdRate ?? '',
|
||||
r.eurRate ?? '',
|
||||
r.notes ?? '',
|
||||
r.apiType ?? '',
|
||||
r.apiBaseUrl ?? '',
|
||||
],
|
||||
)
|
||||
}
|
||||
|
||||
const providerAccounts = loadJson(join(seedDir, 'provider-accounts.json'))
|
||||
for (const r of providerAccounts) {
|
||||
const legacyType = r.apiType ?? ''
|
||||
const legacyUrl = r.apiBaseUrl ?? ''
|
||||
run(
|
||||
'INSERT OR IGNORE INTO provider_accounts (id, providerId, name, panelUrl, currency, billingMode, notes, apiType, apiBaseUrl, apiCredentials) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)',
|
||||
[r.id, r.providerId ?? '', r.name ?? '', r.panelUrl ?? '', r.currency ?? '', r.billingMode ?? '', r.notes ?? '', r.apiType ?? '', r.apiBaseUrl ?? '', r.apiCredentials ?? ''],
|
||||
[r.id, r.providerId ?? '', r.name ?? '', r.panelUrl ?? '', r.currency ?? '', r.billingMode ?? '', r.notes ?? '', '', '', r.apiCredentials ?? ''],
|
||||
)
|
||||
if (legacyType === 'billmanager' && String(legacyUrl).trim()) {
|
||||
run(
|
||||
`UPDATE providers SET apiType = 'billmanager', apiBaseUrl = ? WHERE id = ? AND length(trim(COALESCE(apiBaseUrl,''))) = 0`,
|
||||
String(legacyUrl).trim(),
|
||||
r.providerId ?? '',
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const vpsList = loadJson(join(seedDir, 'vps.json'))
|
||||
|
||||
Reference in New Issue
Block a user