feat: 冻结/拒绝的打手账号禁止登录
- loginWorker 仅允许 active 状态登录,rejected(冻结)/pending_review/disabled 均拦截并返回对应错误码 - verifyWorkerSessionToken 对非 active 状态直接失效会话,冻结后已登录会话立即退出 - 补充 assertWorkerLoginAllowed 四种状态的单元测试
This commit is contained in:
@@ -1,8 +1,71 @@
|
|||||||
import assert from 'node:assert/strict'
|
import assert from 'node:assert/strict'
|
||||||
import test from 'node:test'
|
import test from 'node:test'
|
||||||
|
|
||||||
import type { WorkOrderRow } from '../../repositories/worker-platform/index.js'
|
import type { WorkOrderRow, WorkerUserRow } from '../../repositories/worker-platform/index.js'
|
||||||
import { resolveCollectSubmitTargetWorkOrder } from './index.js'
|
import { assertWorkerLoginAllowed, resolveCollectSubmitTargetWorkOrder } from './index.js'
|
||||||
|
|
||||||
|
function buildWorkerUserRow(overrides: Partial<WorkerUserRow> = {}): WorkerUserRow {
|
||||||
|
return {
|
||||||
|
id: 1,
|
||||||
|
username: 'jd01',
|
||||||
|
password_hash: 'scrypt$salt$hash',
|
||||||
|
display_name: '测试打手',
|
||||||
|
phone: '',
|
||||||
|
level_id: 1,
|
||||||
|
status: 'active',
|
||||||
|
review_note: '',
|
||||||
|
session_version: 1,
|
||||||
|
created_at: '2026-07-28T00:00:00.000Z',
|
||||||
|
updated_at: '2026-07-28T00:00:00.000Z',
|
||||||
|
reviewed_at: null,
|
||||||
|
inviter_id: null,
|
||||||
|
invite_code: 'TEST0001',
|
||||||
|
...overrides,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test('assertWorkerLoginAllowed allows active workers', () => {
|
||||||
|
assert.doesNotThrow(() => assertWorkerLoginAllowed(buildWorkerUserRow()))
|
||||||
|
})
|
||||||
|
|
||||||
|
test('assertWorkerLoginAllowed blocks rejected (frozen) workers with worker_rejected', () => {
|
||||||
|
assert.throws(
|
||||||
|
() => assertWorkerLoginAllowed(buildWorkerUserRow({ status: 'rejected' })),
|
||||||
|
(error: unknown) =>
|
||||||
|
Boolean(
|
||||||
|
error &&
|
||||||
|
typeof error === 'object' &&
|
||||||
|
(error as { statusCode?: number }).statusCode === 403 &&
|
||||||
|
(error as { errorCode?: string }).errorCode === 'worker_rejected',
|
||||||
|
),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('assertWorkerLoginAllowed blocks pending review workers with worker_pending_review', () => {
|
||||||
|
assert.throws(
|
||||||
|
() => assertWorkerLoginAllowed(buildWorkerUserRow({ status: 'pending_review' })),
|
||||||
|
(error: unknown) =>
|
||||||
|
Boolean(
|
||||||
|
error &&
|
||||||
|
typeof error === 'object' &&
|
||||||
|
(error as { statusCode?: number }).statusCode === 403 &&
|
||||||
|
(error as { errorCode?: string }).errorCode === 'worker_pending_review',
|
||||||
|
),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('assertWorkerLoginAllowed blocks disabled workers with worker_disabled', () => {
|
||||||
|
assert.throws(
|
||||||
|
() => assertWorkerLoginAllowed(buildWorkerUserRow({ status: 'disabled' })),
|
||||||
|
(error: unknown) =>
|
||||||
|
Boolean(
|
||||||
|
error &&
|
||||||
|
typeof error === 'object' &&
|
||||||
|
(error as { statusCode?: number }).statusCode === 403 &&
|
||||||
|
(error as { errorCode?: string }).errorCode === 'worker_disabled',
|
||||||
|
),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
function buildWorkOrderRow(
|
function buildWorkOrderRow(
|
||||||
overrides: Partial<WorkOrderRow> = {},
|
overrides: Partial<WorkOrderRow> = {},
|
||||||
|
|||||||
@@ -335,16 +335,36 @@ export async function loginWorker(username: unknown, password: unknown) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if (worker.status === 'disabled') {
|
assertWorkerLoginAllowed(worker)
|
||||||
|
|
||||||
|
return createWorkerSession(worker)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function assertWorkerLoginAllowed(worker: WorkerUserRow) {
|
||||||
|
if (worker.status === 'active') {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (worker.status === 'rejected') {
|
||||||
|
throw createHttpError('接单账号已被冻结,无法登录', {
|
||||||
|
statusCode: 403,
|
||||||
|
errorCode: 'worker_rejected',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (worker.status === 'pending_review') {
|
||||||
|
throw createHttpError('接单账号待审核,暂无法登录', {
|
||||||
|
statusCode: 403,
|
||||||
|
errorCode: 'worker_pending_review',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
throw createHttpError('接单账号已停用', {
|
throw createHttpError('接单账号已停用', {
|
||||||
statusCode: 403,
|
statusCode: 403,
|
||||||
errorCode: 'worker_disabled',
|
errorCode: 'worker_disabled',
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return createWorkerSession(worker)
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function logoutWorkerSession(token: unknown) {
|
export async function logoutWorkerSession(token: unknown) {
|
||||||
const normalizedToken = String(token || '').trim()
|
const normalizedToken = String(token || '').trim()
|
||||||
if (!normalizedToken) {
|
if (!normalizedToken) {
|
||||||
@@ -411,7 +431,7 @@ export async function verifyWorkerSessionToken(token: unknown): Promise<WorkerSe
|
|||||||
|
|
||||||
const workerId = Number(payload.uid || 0)
|
const workerId = Number(payload.uid || 0)
|
||||||
const worker = await getWorkerUserById(workerId)
|
const worker = await getWorkerUserById(workerId)
|
||||||
if (!worker || worker.status === 'disabled') {
|
if (!worker || worker.status !== 'active') {
|
||||||
throw createHttpError('接单账号已不可用,请重新登录', {
|
throw createHttpError('接单账号已不可用,请重新登录', {
|
||||||
statusCode: 401,
|
statusCode: 401,
|
||||||
errorCode: 'worker_auth_user_invalid',
|
errorCode: 'worker_auth_user_invalid',
|
||||||
|
|||||||
Reference in New Issue
Block a user