mirror of
https://github.com/Wei-Shaw/sub2api.git
synced 2026-10-14 03:52:26 +08:00
fix(usage): export missing reasoning effort cleanly
This commit is contained in:
@@ -626,6 +626,7 @@ const escapeCSVValue = (value: unknown): string => {
|
||||
if (value == null) return ''
|
||||
const str = String(value)
|
||||
const escaped = str.replace(/"/g, '""')
|
||||
if (str === '-') return str
|
||||
if (/^[=+\-@\t\r]/.test(str)) return `"\'${escaped}"`
|
||||
if (/[,"\n\r]/.test(str)) return `"${escaped}"`
|
||||
return str
|
||||
|
||||
@@ -399,7 +399,7 @@ describe('user UsageView', () => {
|
||||
expect(csvContent.startsWith('\uFEFF')).toBe(true)
|
||||
expect(csvContent.slice(1)).toBe([
|
||||
'Time,API Key Name,Model,Reasoning Effort,Inbound Endpoint,IP Address,Type,Billing Mode,Input Tokens,Output Tokens,Cache Read Tokens,Cache Creation Tokens,Rate Multiplier,Billed Cost,Original Cost,First Token (ms),Duration (ms)',
|
||||
'2026-03-08T00:00:00Z,demo-key,gpt-5.4,"\'-",,203.0.113.10,Sync,Token,4057,101,278272,4,1,0.09288300,0.09288300,12,345',
|
||||
'2026-03-08T00:00:00Z,demo-key,gpt-5.4,-,,203.0.113.10,Sync,Token,4057,101,278272,4,1,0.09288300,0.09288300,12,345',
|
||||
].join('\n'))
|
||||
expect(csvContent).toContain('IP Address')
|
||||
expect(csvContent).toContain('203.0.113.10')
|
||||
@@ -415,6 +415,39 @@ describe('user UsageView', () => {
|
||||
clickSpy.mockRestore()
|
||||
})
|
||||
|
||||
it('keeps formula-injection protection for dangerous exported values', async () => {
|
||||
query.mockResolvedValue({
|
||||
items: [{ ...usageLog, api_key: { name: '-1+1' } }],
|
||||
total: 1,
|
||||
pages: 1,
|
||||
})
|
||||
const wrapper = mountUsageView()
|
||||
await flushPromises()
|
||||
|
||||
let csvContent = ''
|
||||
const OriginalBlob = globalThis.Blob
|
||||
vi.stubGlobal('Blob', vi.fn((parts: BlobPart[], options?: BlobPropertyBag) => {
|
||||
csvContent = parts.map((part) => String(part)).join('')
|
||||
return new OriginalBlob(parts, options)
|
||||
}))
|
||||
const originalCreateObjectURL = window.URL.createObjectURL
|
||||
const originalRevokeObjectURL = window.URL.revokeObjectURL
|
||||
window.URL.createObjectURL = vi.fn(() => 'blob:usage-export') as typeof window.URL.createObjectURL
|
||||
window.URL.revokeObjectURL = vi.fn(() => {}) as typeof window.URL.revokeObjectURL
|
||||
const clickSpy = vi.spyOn(HTMLAnchorElement.prototype, 'click').mockImplementation(() => {})
|
||||
|
||||
await (wrapper.vm as any).exportToCSV()
|
||||
|
||||
expect(csvContent).toContain(',"\'-1+1",gpt-5.4,-,')
|
||||
expect(showSuccess).toHaveBeenCalled()
|
||||
|
||||
window.URL.createObjectURL = originalCreateObjectURL
|
||||
window.URL.revokeObjectURL = originalRevokeObjectURL
|
||||
vi.unstubAllGlobals()
|
||||
clickSpy.mockRestore()
|
||||
wrapper.unmount()
|
||||
})
|
||||
|
||||
it('keeps the initial filters, sort, and filename while exporting multiple pages', async () => {
|
||||
const pageResponse = { items: [usageLog], total: 101, pages: 2 }
|
||||
query.mockResolvedValue(pageResponse)
|
||||
|
||||
Reference in New Issue
Block a user