mirror of
https://github.com/siteboon/claudecodeui.git
synced 2026-05-02 02:38:38 +00:00
- Implemented githubTokensDb for managing GitHub tokens with CRUD operations. - Created otificationPreferencesDb to handle user notification preferences. - Added projectsDb for project path management and related operations. - Introduced pushSubscriptionsDb for managing browser push subscriptions. - Developed scanStateDb to track the last scanned timestamp. - Established sessionsDb for session management with CRUD functionalities. - Created userDb for user management, including authentication and onboarding. - Implemented apidKeysDb for storing and managing VAPID keys. feat(database): define schema for new database tables - Added SQL schema definitions for users, API keys, user credentials, notification preferences, VAPID keys, push subscriptions, projects, sessions, scan state, and app configuration. - Included necessary indexes for performance optimization. refactor(shared): enhance type definitions and utility functions - Updated shared types and interfaces for improved clarity and consistency. - Added new types for credential management and provider-specific operations. - Refined utility functions for better error handling and message normalization.
141 lines
4.2 KiB
TypeScript
141 lines
4.2 KiB
TypeScript
/**
|
|
* User repository.
|
|
*
|
|
* Provides typed CRUD operations for the `users` table.
|
|
* This is a single-user system, but the schema supports multiple
|
|
* users for forward compatibility.
|
|
*/
|
|
|
|
import { getConnection } from '@/modules/database/connection.js';
|
|
|
|
type UserRow = {
|
|
id: number;
|
|
username: string;
|
|
password_hash: string;
|
|
created_at: string;
|
|
last_login: string | null;
|
|
is_active: number;
|
|
git_name: string | null;
|
|
git_email: string | null;
|
|
has_completed_onboarding: number;
|
|
};
|
|
|
|
type UserPublicRow = Pick<UserRow, 'id' | 'username' | 'created_at' | 'last_login'>;
|
|
|
|
type UserGitConfig = {
|
|
git_name: string | null;
|
|
git_email: string | null;
|
|
};
|
|
|
|
type CreateUserResult = {
|
|
id: number | bigint;
|
|
username: string;
|
|
};
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Queries
|
|
// ---------------------------------------------------------------------------
|
|
|
|
export const userDb = {
|
|
/** Returns true if at least one user exists in the database. */
|
|
hasUsers(): boolean {
|
|
const db = getConnection();
|
|
const row = db.prepare('SELECT COUNT(*) as count FROM users').get() as {
|
|
count: number;
|
|
};
|
|
return row.count > 0;
|
|
},
|
|
|
|
/** Inserts a new user and returns the created ID + username. */
|
|
createUser(username: string, passwordHash: string): CreateUserResult {
|
|
const db = getConnection();
|
|
const result = db
|
|
.prepare('INSERT INTO users (username, password_hash) VALUES (?, ?)')
|
|
.run(username, passwordHash);
|
|
return { id: result.lastInsertRowid, username };
|
|
},
|
|
|
|
/**
|
|
* Looks up an active user by username.
|
|
* Returns the full row (including password hash) for auth verification.
|
|
*/
|
|
getUserByUsername(username: string): UserRow | undefined {
|
|
const db = getConnection();
|
|
return db
|
|
.prepare('SELECT * FROM users WHERE username = ? AND is_active = 1')
|
|
.get(username) as UserRow | undefined;
|
|
},
|
|
|
|
/** Updates the last_login timestamp. Non-fatal — logs but does not throw. */
|
|
updateLastLogin(userId: number): void {
|
|
try {
|
|
const db = getConnection();
|
|
db.prepare(
|
|
'UPDATE users SET last_login = CURRENT_TIMESTAMP WHERE id = ?'
|
|
).run(userId);
|
|
} catch (err) {
|
|
const message = err instanceof Error ? err.message : String(err);
|
|
console.error('Failed to update last login', { error: message });
|
|
}
|
|
},
|
|
|
|
/** Returns public user fields by ID (no password hash). */
|
|
getUserById(userId: number): UserPublicRow | undefined {
|
|
const db = getConnection();
|
|
return db
|
|
.prepare(
|
|
'SELECT id, username, created_at, last_login FROM users WHERE id = ? AND is_active = 1'
|
|
)
|
|
.get(userId) as UserPublicRow | undefined;
|
|
},
|
|
|
|
/** Returns the first active user. Used for single-user mode lookups. */
|
|
getFirstUser(): UserPublicRow | undefined {
|
|
const db = getConnection();
|
|
return db
|
|
.prepare(
|
|
'SELECT id, username, created_at, last_login FROM users WHERE is_active = 1 LIMIT 1'
|
|
)
|
|
.get() as UserPublicRow | undefined;
|
|
},
|
|
|
|
/** Stores the user's preferred git name and email. */
|
|
updateGitConfig(
|
|
userId: number,
|
|
gitName: string,
|
|
gitEmail: string
|
|
): void {
|
|
const db = getConnection();
|
|
db.prepare('UPDATE users SET git_name = ?, git_email = ? WHERE id = ?').run(
|
|
gitName,
|
|
gitEmail,
|
|
userId
|
|
);
|
|
},
|
|
|
|
/** Retrieves the user's git identity (name + email). */
|
|
getGitConfig(userId: number): UserGitConfig | undefined {
|
|
const db = getConnection();
|
|
return db
|
|
.prepare('SELECT git_name, git_email FROM users WHERE id = ?')
|
|
.get(userId) as UserGitConfig | undefined;
|
|
},
|
|
|
|
/** Marks onboarding as complete for the given user. */
|
|
completeOnboarding(userId: number): void {
|
|
const db = getConnection();
|
|
db.prepare(
|
|
'UPDATE users SET has_completed_onboarding = 1 WHERE id = ?'
|
|
).run(userId);
|
|
},
|
|
|
|
/** Returns true if the user has finished the onboarding flow. */
|
|
hasCompletedOnboarding(userId: number): boolean {
|
|
const db = getConnection();
|
|
const row = db
|
|
.prepare('SELECT has_completed_onboarding FROM users WHERE id = ?')
|
|
.get(userId) as { has_completed_onboarding: number } | undefined;
|
|
return row?.has_completed_onboarding === 1;
|
|
},
|
|
};
|