feat(admin): 重构管理控制台布局并完善管理功能
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
import assert from 'node:assert/strict'
|
||||
import { afterEach, mock, test } from 'node:test'
|
||||
import { createUser, reviewClouds } from '../src/features/admin/api.ts'
|
||||
import { serializeCsv, visibilityLabel } from '../src/features/admin/models.ts'
|
||||
|
||||
afterEach(() => mock.restoreAll())
|
||||
|
||||
test('admin review preserves completed batches when a later batch fails', async () => {
|
||||
const completed = []
|
||||
let call = 0
|
||||
mock.method(globalThis, 'fetch', async (url, options) => {
|
||||
assert.equal(new URL(url).pathname, '/admin/clouds/review')
|
||||
assert.equal(options.credentials, 'include')
|
||||
const body = JSON.parse(options.body)
|
||||
assert.equal(body.review_status, 'approved')
|
||||
assert.ok(body.cloud_ids.length <= 100)
|
||||
return ++call === 1
|
||||
? Response.json({ message: '成功' })
|
||||
: Response.json({ message: '服务暂不可用' }, { status: 503 })
|
||||
})
|
||||
const ids = Array.from({ length: 101 }, (_, index) => `cloud-${index}`)
|
||||
await assert.rejects(
|
||||
reviewClouds(ids, 'approved', batch => completed.push(...batch)),
|
||||
/服务暂不可用/,
|
||||
)
|
||||
assert.deepEqual(completed, ids.slice(0, 100))
|
||||
assert.equal(call, 2)
|
||||
})
|
||||
|
||||
test('admin account creation returns email delivery status without retrying creation', async () => {
|
||||
const body = {
|
||||
username: '观云者',
|
||||
email: 'observer@example.test',
|
||||
password: 'test-password',
|
||||
role: 'user',
|
||||
}
|
||||
const fetch = mock.method(globalThis, 'fetch', async (url, options) => {
|
||||
assert.equal(new URL(url).pathname, '/admin/users')
|
||||
assert.equal(options.method, 'POST')
|
||||
assert.equal(options.credentials, 'include')
|
||||
assert.deepEqual(JSON.parse(options.body), body)
|
||||
return Response.json(
|
||||
{ message: '已创建,邮件发送失败', user_id: 'new-user', email_sent: false },
|
||||
{ status: 201 },
|
||||
)
|
||||
})
|
||||
assert.equal((await createUser(body)).email_sent, false)
|
||||
assert.equal(fetch.mock.callCount(), 1)
|
||||
})
|
||||
|
||||
test('CSV exports escape untrusted text, formulas, quotes and multiline descriptions', () => {
|
||||
const csv = serializeCsv(
|
||||
['用户名', '说明'],
|
||||
[
|
||||
['=HYPERLINK("test")', '第一行\n第二行'],
|
||||
[' @SUM(1)', '云,"雨"'],
|
||||
['-1+2', '\t=1'],
|
||||
],
|
||||
)
|
||||
assert.ok(csv.startsWith('\uFEFF'))
|
||||
assert.ok(csv.includes('"\'=HYPERLINK(""test"")"'))
|
||||
assert.ok(csv.includes('"\' @SUM(1)"'))
|
||||
assert.ok(csv.includes('"\'-1+2"'))
|
||||
assert.ok(csv.includes('"\'\t=1"'))
|
||||
assert.ok(csv.includes('"云,""雨"""'))
|
||||
assert.ok(csv.includes('"第一行\n第二行"'))
|
||||
})
|
||||
|
||||
test('pending and rejected images are never labeled publicly visible', () => {
|
||||
for (const status of ['pending', 'rejected']) {
|
||||
assert.equal(visibilityLabel({ status, is_hidden: false }), '尚未公开')
|
||||
}
|
||||
assert.equal(visibilityLabel({ status: 'approved', is_hidden: false }), '公开可见')
|
||||
assert.equal(visibilityLabel({ status: 'approved', is_hidden: true }), '用户隐藏')
|
||||
})
|
||||
Reference in New Issue
Block a user