拆分打手会话仓储
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
export * from './types.js'
|
export * from './types.js'
|
||||||
export * from './shared.js'
|
export * from './shared.js'
|
||||||
export * from './worker-repo.js'
|
export * from './worker-repo.js'
|
||||||
|
export * from './worker-session-repo.js'
|
||||||
export * from './work-order-repo.js'
|
export * from './work-order-repo.js'
|
||||||
export * from './work-order-event-repo.js'
|
export * from './work-order-event-repo.js'
|
||||||
export * from './work-order-share-repo.js'
|
export * from './work-order-share-repo.js'
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import type {
|
|||||||
WorkerFinanceRequestRow,
|
WorkerFinanceRequestRow,
|
||||||
WorkerLevelRow,
|
WorkerLevelRow,
|
||||||
WorkerUserRow,
|
WorkerUserRow,
|
||||||
WorkerSessionRow,
|
|
||||||
WorkerWithdrawalAccountRow,
|
WorkerWithdrawalAccountRow,
|
||||||
WorkerWalletLedgerRow,
|
WorkerWalletLedgerRow,
|
||||||
WorkerWalletRow,
|
WorkerWalletRow,
|
||||||
@@ -58,164 +57,16 @@ const WORKER_FINANCE_REQUEST_SELECT = `
|
|||||||
) withdraw_stats ON TRUE
|
) withdraw_stats ON TRUE
|
||||||
`
|
`
|
||||||
|
|
||||||
export type CreateWorkerSessionInput = {
|
export {
|
||||||
sessionId: string
|
createWorkerSessionRecord,
|
||||||
workerId: number
|
getWorkerSessionBySessionId,
|
||||||
deviceId: string
|
listWorkerSessions,
|
||||||
deviceType: string
|
revokeAllWorkerSessions,
|
||||||
deviceName: string
|
revokeWorkerSession,
|
||||||
userAgent: string
|
touchWorkerSession,
|
||||||
ipAddress: string
|
type CreateWorkerSessionInput,
|
||||||
issuedAt: string
|
type CreateWorkerSessionResult,
|
||||||
expiresAt: string
|
} from './worker-session-repo.js'
|
||||||
now: string
|
|
||||||
maxDevices: number
|
|
||||||
}
|
|
||||||
|
|
||||||
export type CreateWorkerSessionResult = {
|
|
||||||
created: boolean
|
|
||||||
activeSessions: WorkerSessionRow[]
|
|
||||||
session: WorkerSessionRow | null
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function createWorkerSessionRecord(
|
|
||||||
input: CreateWorkerSessionInput,
|
|
||||||
): Promise<CreateWorkerSessionResult> {
|
|
||||||
return withTransaction(async (client) => {
|
|
||||||
// 对账号加行锁,避免并发登录同时绕过设备数量限制。
|
|
||||||
await client.query('SELECT id FROM worker_users WHERE id = $1 FOR UPDATE', [input.workerId])
|
|
||||||
await client.query(
|
|
||||||
`
|
|
||||||
UPDATE worker_sessions
|
|
||||||
SET status = 'revoked', revoked_at = $2, updated_at = $2
|
|
||||||
WHERE worker_id = $1 AND status = 'active' AND expires_at <= $2
|
|
||||||
`,
|
|
||||||
[input.workerId, input.now],
|
|
||||||
)
|
|
||||||
|
|
||||||
await client.query(
|
|
||||||
`
|
|
||||||
UPDATE worker_sessions
|
|
||||||
SET status = 'revoked', revoked_at = $3, updated_at = $3
|
|
||||||
WHERE worker_id = $1 AND device_id = $2 AND status = 'active'
|
|
||||||
`,
|
|
||||||
[input.workerId, input.deviceId, input.now],
|
|
||||||
)
|
|
||||||
|
|
||||||
const activeResult = await client.query<WorkerSessionRow>(
|
|
||||||
`
|
|
||||||
SELECT * FROM worker_sessions
|
|
||||||
WHERE worker_id = $1 AND status = 'active' AND expires_at > $2
|
|
||||||
ORDER BY last_seen_at DESC, id DESC
|
|
||||||
`,
|
|
||||||
[input.workerId, input.now],
|
|
||||||
)
|
|
||||||
const activeSessions = activeResult.rows
|
|
||||||
if (activeSessions.length >= input.maxDevices) {
|
|
||||||
return { created: false, activeSessions, session: null }
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = await client.query<WorkerSessionRow>(
|
|
||||||
`
|
|
||||||
INSERT INTO worker_sessions (
|
|
||||||
session_id, worker_id, device_id, device_type, device_name,
|
|
||||||
user_agent, ip_address, status, issued_at, last_seen_at,
|
|
||||||
expires_at, created_at, updated_at
|
|
||||||
) VALUES ($1, $2, $3, $4, $5, $6, $7, 'active', $8, $8, $9, $10, $10)
|
|
||||||
RETURNING *
|
|
||||||
`,
|
|
||||||
[
|
|
||||||
input.sessionId,
|
|
||||||
input.workerId,
|
|
||||||
input.deviceId,
|
|
||||||
input.deviceType,
|
|
||||||
input.deviceName,
|
|
||||||
input.userAgent,
|
|
||||||
input.ipAddress,
|
|
||||||
input.issuedAt,
|
|
||||||
input.expiresAt,
|
|
||||||
input.now,
|
|
||||||
],
|
|
||||||
)
|
|
||||||
return { created: true, activeSessions, session: result.rows[0] || null }
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function getWorkerSessionBySessionId(
|
|
||||||
sessionId: string,
|
|
||||||
): Promise<WorkerSessionRow | null> {
|
|
||||||
const result = await query<WorkerSessionRow>(
|
|
||||||
'SELECT * FROM worker_sessions WHERE session_id = $1 LIMIT 1',
|
|
||||||
[String(sessionId || '').trim()],
|
|
||||||
)
|
|
||||||
return result.rows[0] || null
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function touchWorkerSession(sessionId: string, now: string): Promise<boolean> {
|
|
||||||
const result = await query(
|
|
||||||
`
|
|
||||||
UPDATE worker_sessions
|
|
||||||
SET last_seen_at = $2, updated_at = $2
|
|
||||||
WHERE session_id = $1 AND status = 'active' AND expires_at > $2
|
|
||||||
`,
|
|
||||||
[String(sessionId || '').trim(), now],
|
|
||||||
)
|
|
||||||
return (result.rowCount || 0) > 0
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function revokeWorkerSession(
|
|
||||||
workerId: number | string,
|
|
||||||
sessionId: string,
|
|
||||||
now: string,
|
|
||||||
): Promise<boolean> {
|
|
||||||
const result = await query(
|
|
||||||
`
|
|
||||||
UPDATE worker_sessions
|
|
||||||
SET status = 'revoked', revoked_at = $3, updated_at = $3
|
|
||||||
WHERE worker_id = $1 AND session_id = $2 AND status = 'active'
|
|
||||||
`,
|
|
||||||
[Number(workerId), String(sessionId || '').trim(), now],
|
|
||||||
)
|
|
||||||
return (result.rowCount || 0) > 0
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function revokeAllWorkerSessions(
|
|
||||||
workerId: number | string,
|
|
||||||
now: string,
|
|
||||||
): Promise<number> {
|
|
||||||
const result = await query(
|
|
||||||
`
|
|
||||||
UPDATE worker_sessions
|
|
||||||
SET status = 'revoked', revoked_at = $2, updated_at = $2
|
|
||||||
WHERE worker_id = $1 AND status = 'active'
|
|
||||||
`,
|
|
||||||
[Number(workerId), now],
|
|
||||||
)
|
|
||||||
return result.rowCount || 0
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function listWorkerSessions(
|
|
||||||
workerId: number | string,
|
|
||||||
now: string,
|
|
||||||
): Promise<WorkerSessionRow[]> {
|
|
||||||
await query(
|
|
||||||
`
|
|
||||||
UPDATE worker_sessions
|
|
||||||
SET status = 'revoked', revoked_at = $2, updated_at = $2
|
|
||||||
WHERE worker_id = $1 AND status = 'active' AND expires_at <= $2
|
|
||||||
`,
|
|
||||||
[Number(workerId), now],
|
|
||||||
)
|
|
||||||
const result = await query<WorkerSessionRow>(
|
|
||||||
`
|
|
||||||
SELECT * FROM worker_sessions
|
|
||||||
WHERE worker_id = $1 AND status = 'active' AND expires_at > $2
|
|
||||||
ORDER BY device_type ASC, last_seen_at DESC, id DESC
|
|
||||||
`,
|
|
||||||
[Number(workerId), now],
|
|
||||||
)
|
|
||||||
return result.rows
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function getWorkerLevelByKey(levelKey: string): Promise<WorkerLevelRow | null> {
|
export async function getWorkerLevelByKey(levelKey: string): Promise<WorkerLevelRow | null> {
|
||||||
const result = await query<WorkerLevelRow>(
|
const result = await query<WorkerLevelRow>(
|
||||||
|
|||||||
@@ -0,0 +1,140 @@
|
|||||||
|
import { query, withTransaction } from '../../db/client.js'
|
||||||
|
import type { WorkerSessionRow } from './types.js'
|
||||||
|
|
||||||
|
export type CreateWorkerSessionInput = {
|
||||||
|
sessionId: string
|
||||||
|
workerId: number
|
||||||
|
deviceId: string
|
||||||
|
deviceType: string
|
||||||
|
deviceName: string
|
||||||
|
userAgent: string
|
||||||
|
ipAddress: string
|
||||||
|
issuedAt: string
|
||||||
|
expiresAt: string
|
||||||
|
now: string
|
||||||
|
maxDevices: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CreateWorkerSessionResult = {
|
||||||
|
created: boolean
|
||||||
|
activeSessions: WorkerSessionRow[]
|
||||||
|
session: WorkerSessionRow | null
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function createWorkerSessionRecord(
|
||||||
|
input: CreateWorkerSessionInput,
|
||||||
|
): Promise<CreateWorkerSessionResult> {
|
||||||
|
return withTransaction(async (client) => {
|
||||||
|
// 对账号加行锁,避免并发登录同时绕过设备数量限制。
|
||||||
|
await client.query('SELECT id FROM worker_users WHERE id = $1 FOR UPDATE', [input.workerId])
|
||||||
|
await client.query(
|
||||||
|
`UPDATE worker_sessions
|
||||||
|
SET status = 'revoked', revoked_at = $2, updated_at = $2
|
||||||
|
WHERE worker_id = $1 AND status = 'active' AND expires_at <= $2`,
|
||||||
|
[input.workerId, input.now],
|
||||||
|
)
|
||||||
|
await client.query(
|
||||||
|
`UPDATE worker_sessions
|
||||||
|
SET status = 'revoked', revoked_at = $3, updated_at = $3
|
||||||
|
WHERE worker_id = $1 AND device_id = $2 AND status = 'active'`,
|
||||||
|
[input.workerId, input.deviceId, input.now],
|
||||||
|
)
|
||||||
|
const activeResult = await client.query<WorkerSessionRow>(
|
||||||
|
`SELECT * FROM worker_sessions
|
||||||
|
WHERE worker_id = $1 AND status = 'active' AND expires_at > $2
|
||||||
|
ORDER BY last_seen_at DESC, id DESC`,
|
||||||
|
[input.workerId, input.now],
|
||||||
|
)
|
||||||
|
const activeSessions = activeResult.rows
|
||||||
|
if (activeSessions.length >= input.maxDevices) {
|
||||||
|
return { created: false, activeSessions, session: null }
|
||||||
|
}
|
||||||
|
const result = await client.query<WorkerSessionRow>(
|
||||||
|
`INSERT INTO worker_sessions (
|
||||||
|
session_id, worker_id, device_id, device_type, device_name,
|
||||||
|
user_agent, ip_address, status, issued_at, last_seen_at,
|
||||||
|
expires_at, created_at, updated_at
|
||||||
|
) VALUES ($1, $2, $3, $4, $5, $6, $7, 'active', $8, $8, $9, $10, $10)
|
||||||
|
RETURNING *`,
|
||||||
|
[
|
||||||
|
input.sessionId,
|
||||||
|
input.workerId,
|
||||||
|
input.deviceId,
|
||||||
|
input.deviceType,
|
||||||
|
input.deviceName,
|
||||||
|
input.userAgent,
|
||||||
|
input.ipAddress,
|
||||||
|
input.issuedAt,
|
||||||
|
input.expiresAt,
|
||||||
|
input.now,
|
||||||
|
],
|
||||||
|
)
|
||||||
|
return { created: true, activeSessions, session: result.rows[0] || null }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getWorkerSessionBySessionId(
|
||||||
|
sessionId: string,
|
||||||
|
): Promise<WorkerSessionRow | null> {
|
||||||
|
const result = await query<WorkerSessionRow>(
|
||||||
|
'SELECT * FROM worker_sessions WHERE session_id = $1 LIMIT 1',
|
||||||
|
[String(sessionId || '').trim()],
|
||||||
|
)
|
||||||
|
return result.rows[0] || null
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function touchWorkerSession(sessionId: string, now: string): Promise<boolean> {
|
||||||
|
const result = await query(
|
||||||
|
`UPDATE worker_sessions
|
||||||
|
SET last_seen_at = $2, updated_at = $2
|
||||||
|
WHERE session_id = $1 AND status = 'active' AND expires_at > $2`,
|
||||||
|
[String(sessionId || '').trim(), now],
|
||||||
|
)
|
||||||
|
return (result.rowCount || 0) > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function revokeWorkerSession(
|
||||||
|
workerId: number | string,
|
||||||
|
sessionId: string,
|
||||||
|
now: string,
|
||||||
|
): Promise<boolean> {
|
||||||
|
const result = await query(
|
||||||
|
`UPDATE worker_sessions
|
||||||
|
SET status = 'revoked', revoked_at = $3, updated_at = $3
|
||||||
|
WHERE worker_id = $1 AND session_id = $2 AND status = 'active'`,
|
||||||
|
[Number(workerId), String(sessionId || '').trim(), now],
|
||||||
|
)
|
||||||
|
return (result.rowCount || 0) > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function revokeAllWorkerSessions(
|
||||||
|
workerId: number | string,
|
||||||
|
now: string,
|
||||||
|
): Promise<number> {
|
||||||
|
const result = await query(
|
||||||
|
`UPDATE worker_sessions
|
||||||
|
SET status = 'revoked', revoked_at = $2, updated_at = $2
|
||||||
|
WHERE worker_id = $1 AND status = 'active'`,
|
||||||
|
[Number(workerId), now],
|
||||||
|
)
|
||||||
|
return result.rowCount || 0
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function listWorkerSessions(
|
||||||
|
workerId: number | string,
|
||||||
|
now: string,
|
||||||
|
): Promise<WorkerSessionRow[]> {
|
||||||
|
await query(
|
||||||
|
`UPDATE worker_sessions
|
||||||
|
SET status = 'revoked', revoked_at = $2, updated_at = $2
|
||||||
|
WHERE worker_id = $1 AND status = 'active' AND expires_at <= $2`,
|
||||||
|
[Number(workerId), now],
|
||||||
|
)
|
||||||
|
const result = await query<WorkerSessionRow>(
|
||||||
|
`SELECT * FROM worker_sessions
|
||||||
|
WHERE worker_id = $1 AND status = 'active' AND expires_at > $2
|
||||||
|
ORDER BY device_type ASC, last_seen_at DESC, id DESC`,
|
||||||
|
[Number(workerId), now],
|
||||||
|
)
|
||||||
|
return result.rows
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user