Refine user profile access and chat sync
This commit is contained in:
@@ -3,6 +3,7 @@ import { createHmac, timingSafeEqual } from 'crypto'
|
||||
import { getToken } from '../services/auth'
|
||||
import {
|
||||
findUserById,
|
||||
listUserProfiles,
|
||||
touchUserLogin,
|
||||
userCanAccessProfile,
|
||||
type UserRecord,
|
||||
@@ -13,6 +14,7 @@ export interface AuthenticatedUser {
|
||||
id: number
|
||||
username: string
|
||||
role: UserRole
|
||||
profiles?: string[]
|
||||
}
|
||||
|
||||
export interface RequestProfile {
|
||||
@@ -110,11 +112,15 @@ export async function issueUserJwt(user: Pick<UserRecord, 'id' | 'username' | 'r
|
||||
}
|
||||
|
||||
export function toAuthenticatedUser(user: Pick<UserRecord, 'id' | 'username' | 'role'>): AuthenticatedUser {
|
||||
return {
|
||||
const authenticated: AuthenticatedUser = {
|
||||
id: user.id,
|
||||
username: user.username,
|
||||
role: user.role,
|
||||
}
|
||||
if (user.role !== 'super_admin') {
|
||||
authenticated.profiles = listUserProfiles(user.id).map(profile => profile.profile_name)
|
||||
}
|
||||
return authenticated
|
||||
}
|
||||
|
||||
export async function authenticateUserToken(token: string): Promise<AuthenticatedUser | null> {
|
||||
|
||||
@@ -196,7 +196,11 @@ groupChatRoutes.get('/api/hermes/group-chat/rooms', async (ctx) => {
|
||||
return
|
||||
}
|
||||
|
||||
const rooms = chatServer.getStorage().getAllRooms()
|
||||
const user = ctx.state.user
|
||||
const storage = chatServer.getStorage()
|
||||
const rooms = !user || user.role === 'super_admin'
|
||||
? storage.getAllRooms()
|
||||
: storage.getRoomsForProfiles(user.profiles || [])
|
||||
ctx.body = { rooms }
|
||||
})
|
||||
|
||||
|
||||
@@ -72,6 +72,17 @@ interface RoomAgent {
|
||||
invited: number
|
||||
}
|
||||
|
||||
interface RoomInfo {
|
||||
id: string
|
||||
name: string
|
||||
inviteCode: string | null
|
||||
triggerTokens: number
|
||||
maxHistoryTokens: number
|
||||
tailMessageCount: number
|
||||
totalTokens: number
|
||||
sessionSeed: string
|
||||
}
|
||||
|
||||
interface Member {
|
||||
id: string
|
||||
userId: string
|
||||
@@ -278,18 +289,31 @@ class ChatStorage {
|
||||
|
||||
// ─── Rooms ────────────────────────────────────────────────
|
||||
|
||||
getRoom(roomId: string): { id: string; name: string; inviteCode: string | null; triggerTokens: number; maxHistoryTokens: number; tailMessageCount: number; totalTokens: number; sessionSeed: string } | undefined {
|
||||
getRoom(roomId: string): RoomInfo | undefined {
|
||||
return this.db()?.prepare('SELECT id, name, inviteCode, triggerTokens, maxHistoryTokens, tailMessageCount, totalTokens, sessionSeed FROM gc_rooms WHERE id = ?').get(roomId) as any
|
||||
}
|
||||
|
||||
getRoomByInviteCode(code: string): { id: string; name: string; inviteCode: string | null; triggerTokens: number; maxHistoryTokens: number; tailMessageCount: number; totalTokens: number; sessionSeed: string } | undefined {
|
||||
getRoomByInviteCode(code: string): RoomInfo | undefined {
|
||||
return this.db()?.prepare('SELECT id, name, inviteCode, triggerTokens, maxHistoryTokens, tailMessageCount, totalTokens, sessionSeed FROM gc_rooms WHERE inviteCode = ?').get(code) as any
|
||||
}
|
||||
|
||||
getAllRooms(): { id: string; name: string; inviteCode: string | null; triggerTokens: number; maxHistoryTokens: number; tailMessageCount: number; totalTokens: number; sessionSeed: string }[] {
|
||||
getAllRooms(): RoomInfo[] {
|
||||
return (this.db()?.prepare('SELECT id, name, inviteCode, triggerTokens, maxHistoryTokens, tailMessageCount, totalTokens, sessionSeed FROM gc_rooms ORDER BY id').all() || []) as any[]
|
||||
}
|
||||
|
||||
getRoomsForProfiles(profiles: string[]): RoomInfo[] {
|
||||
const uniqueProfiles = [...new Set(profiles.map(profile => profile.trim()).filter(Boolean))]
|
||||
if (!uniqueProfiles.length) return []
|
||||
const placeholders = uniqueProfiles.map(() => '?').join(', ')
|
||||
return (this.db()?.prepare(
|
||||
`SELECT DISTINCT r.id, r.name, r.inviteCode, r.triggerTokens, r.maxHistoryTokens, r.tailMessageCount, r.totalTokens, r.sessionSeed
|
||||
FROM gc_rooms r
|
||||
INNER JOIN gc_room_agents a ON a.roomId = r.id
|
||||
WHERE a.profile IN (${placeholders})
|
||||
ORDER BY r.id`
|
||||
).all(...uniqueProfiles) || []) as any[]
|
||||
}
|
||||
|
||||
saveRoom(id: string, name: string, inviteCode?: string, config?: { triggerTokens?: number; maxHistoryTokens?: number; tailMessageCount?: number }): void {
|
||||
this.db()?.prepare(
|
||||
'INSERT OR IGNORE INTO gc_rooms (id, name, inviteCode, triggerTokens, maxHistoryTokens, tailMessageCount) VALUES (?, ?, ?, ?, ?, ?)'
|
||||
|
||||
@@ -109,6 +109,7 @@ export async function handleApiRun(
|
||||
state.source = 'api_server'
|
||||
state.activeRunMarker = runMarker
|
||||
|
||||
let peerUserMessage: { id?: number; role: 'user'; content: string; timestamp: number } | null = null
|
||||
if (!skipUserMessage) {
|
||||
const inputStr = contentBlocksToString(input)
|
||||
state.messages.push({
|
||||
@@ -126,12 +127,13 @@ export async function handleApiRun(
|
||||
createSession({ id: session_id, profile, source: 'api_server', model, provider, title: preview })
|
||||
}
|
||||
|
||||
addMessage({
|
||||
const messageId = addMessage({
|
||||
session_id,
|
||||
role: 'user',
|
||||
content: inputStr,
|
||||
timestamp: now,
|
||||
})
|
||||
peerUserMessage = { id: messageId, role: 'user', content: inputStr, timestamp: now }
|
||||
} else {
|
||||
const inputStr = contentBlocksToString(input)
|
||||
state.messages.push({
|
||||
@@ -147,15 +149,23 @@ export async function handleApiRun(
|
||||
const preview = previewText.replace(/[\r\n]/g, ' ').substring(0, 100)
|
||||
createSession({ id: session_id, profile, source: 'api_server', model, provider, title: preview })
|
||||
}
|
||||
addMessage({
|
||||
const messageId = addMessage({
|
||||
session_id,
|
||||
role: 'user',
|
||||
content: inputStr,
|
||||
timestamp: now,
|
||||
})
|
||||
peerUserMessage = { id: messageId, role: 'user', content: inputStr, timestamp: now }
|
||||
}
|
||||
|
||||
socket.join(`session:${session_id}`)
|
||||
if (peerUserMessage) {
|
||||
socket.to(`session:${session_id}`).emit('run.peer_user_message', {
|
||||
event: 'run.peer_user_message',
|
||||
session_id,
|
||||
message: peerUserMessage,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const emit = (event: string, payload: any) => {
|
||||
|
||||
@@ -173,7 +173,7 @@ export async function handleBridgeRun(
|
||||
const preview = previewText.replace(/[\r\n]/g, ' ').substring(0, 100)
|
||||
createSession({ id: session_id, profile, source: 'cli', model: resolvedModel, provider: resolvedProvider, title: preview })
|
||||
}
|
||||
addMessage({
|
||||
const messageId = addMessage({
|
||||
session_id,
|
||||
role: 'user',
|
||||
content: inputStr,
|
||||
@@ -181,6 +181,16 @@ export async function handleBridgeRun(
|
||||
})
|
||||
|
||||
socket.join(`session:${session_id}`)
|
||||
socket.to(`session:${session_id}`).emit('run.peer_user_message', {
|
||||
event: 'run.peer_user_message',
|
||||
session_id,
|
||||
message: {
|
||||
id: messageId,
|
||||
role: 'user',
|
||||
content: inputStr,
|
||||
timestamp: now,
|
||||
},
|
||||
})
|
||||
const emit = (event: string, payload: any) => {
|
||||
const tagged = { ...payload, session_id }
|
||||
nsp.to(`session:${session_id}`).emit(event, tagged)
|
||||
|
||||
Reference in New Issue
Block a user