Files
BIPMaterialManager/src/main/services/user/session-manager.ts
Misaka_Company 491f2afe3f refactor(auth): remove Guest role from user type system
Remove all references to 'Guest' user type from the codebase, simplifying the role system to only support 'Admin' and 'User' roles.

Changes:
- Update type definitions to exclude 'Guest' from UserType
- Remove isGuest() method from SessionManager
- Remove Guest-specific logic from update services
- Update all type assertions from 'Admin | User | Guest' to 'Admin | User'
- Remove Guest UI styling from UserSelectionDialog
- Replace Guest fallback with ValidationError in settings handler

Error handling:
- Zod schema now rejects 'Guest' as invalid user type
- TypeScript will fail compilation if 'Guest' is referenced
- Runtime errors occur if database contains Guest users

No database migration needed (confirmed: no Guest users exist)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-26 12:50:18 +08:00

201 lines
5.2 KiB
TypeScript

/**
* User Session Manager - Singleton pattern for managing authenticated user session
*
* Mimics the Python SessionManager functionality:
* - Singleton pattern to maintain user state throughout application lifecycle
* - Support for username/password authentication
* - Support for silent login by computer name
* - Admin user can switch to other users
*/
import type { UserInfo } from '../../types/user.types'
/**
* Session Manager Class
*/
export class SessionManager {
private static instance: SessionManager | null = null
private currentUser: UserInfo | null = null
private originalAdminUser: UserInfo | null = null
private initialized: boolean = false
private constructor() {
if (this.initialized) {
return
}
this.initialized = true
}
/**
* Get the singleton instance
*/
public static getInstance(): SessionManager {
if (SessionManager.instance === null) {
SessionManager.instance = new SessionManager()
}
return SessionManager.instance
}
/**
* Authenticate and login a user
* @param username - The username to authenticate
* @param password - The password to verify
* @returns True if login successful, false otherwise
*/
public async login(username: string, password: string): Promise<boolean> {
let dao: InstanceType<(typeof import('./bip-users-dao'))['BIPUsersDAO']> | null = null
try {
const { BIPUsersDAO } = await import('./bip-users-dao')
dao = new BIPUsersDAO()
const userInfo = await dao.authenticate(username, password)
if (userInfo) {
this.currentUser = {
id: userInfo.id,
username: userInfo.username,
userType: userInfo.userType
}
return true
}
return false
} catch (error) {
console.error('[SessionManager] Login error:', error)
return false
} finally {
if (dao) {
await dao.disconnect().catch((error) => {
console.error('[SessionManager] Login disconnect error:', error)
})
}
}
}
/**
* Attempt silent login using computer name
* @returns True if login successful, false otherwise
*/
public async loginByComputerName(): Promise<boolean> {
let dao: InstanceType<(typeof import('./bip-users-dao'))['BIPUsersDAO']> | null = null
try {
const { BIPUsersDAO } = await import('./bip-users-dao')
const { hostname } = await import('os')
dao = new BIPUsersDAO()
const computerName = hostname()
const userInfo = await dao.authenticateByComputerName(computerName)
if (userInfo) {
this.currentUser = {
id: userInfo.id,
username: userInfo.username,
userType: userInfo.userType
}
return true
}
return false
} catch (error) {
console.error('[SessionManager] Silent login error:', error)
return false
} finally {
if (dao) {
await dao.disconnect().catch((error) => {
console.error('[SessionManager] Silent login disconnect error:', error)
})
}
}
}
/**
* Logout the current user and clear session
*/
public logout(): void {
this.currentUser = null
this.originalAdminUser = null
}
/**
* Check if a user is currently authenticated
*/
public isAuthenticated(): boolean {
return this.currentUser !== null
}
/**
* Check if the current user is an admin
*/
public isAdmin(): boolean {
return this.currentUser?.userType === 'Admin'
}
/**
* Get the current username
*/
public getUsername(): string | null {
return this.currentUser?.username ?? null
}
/**
* Get the current user type
*/
public getUserType(): string | null {
return this.currentUser?.userType ?? null
}
/**
* Get all current user information
*/
public getUserInfo(): UserInfo | null {
return this.currentUser
}
/**
* Switch to a different user (Admin only feature)
* @param userInfo - User info to switch to
* @returns True if switch successful
*/
public switchUser(userInfo: UserInfo): boolean {
if (!this.currentUser) {
return false
}
// Store original admin user for reference
if (!this.originalAdminUser) {
this.originalAdminUser = { ...this.currentUser }
}
this.currentUser = {
id: userInfo.id,
username: userInfo.username,
userType: userInfo.userType
}
return true
}
/**
* Get the original Admin user before any user switch
*/
public getOriginalAdmin(): UserInfo | null {
return this.originalAdminUser
}
/**
* Get all users from database (for Admin user selection)
*/
public async getAllUsers(): Promise<UserInfo[]> {
let dao: InstanceType<(typeof import('./bip-users-dao'))['BIPUsersDAO']> | null = null
try {
const { BIPUsersDAO } = await import('./bip-users-dao')
dao = new BIPUsersDAO()
return await dao.getAllUsers()
} catch (error) {
console.error('[SessionManager] Get all users error:', error)
return []
} finally {
if (dao) {
await dao.disconnect().catch((error) => {
console.error('[SessionManager] Get all users disconnect error:', error)
})
}
}
}
}