Add gemini key ability

This commit is contained in:
Joey Yakimowich-Payne 2026-01-14 21:04:58 -07:00
commit 73c7d3efed
No known key found for this signature in database
GPG key ID: 6BFE655FA5ABD1E1
11 changed files with 793 additions and 228 deletions

View file

@ -60,6 +60,18 @@ const runMigrations = () => {
db.exec("ALTER TABLE game_sessions ADD COLUMN first_correct_player_id TEXT");
console.log("Migration: Added first_correct_player_id to game_sessions");
}
const userTableInfo2 = db.prepare("PRAGMA table_info(users)").all() as { name: string }[];
const hasColorScheme = userTableInfo2.some(col => col.name === "color_scheme");
if (!hasColorScheme) {
db.exec("ALTER TABLE users ADD COLUMN color_scheme TEXT DEFAULT 'blue'");
console.log("Migration: Added color_scheme to users");
}
const hasGeminiKey = userTableInfo2.some(col => col.name === "gemini_api_key");
if (!hasGeminiKey) {
db.exec("ALTER TABLE users ADD COLUMN gemini_api_key TEXT");
console.log("Migration: Added gemini_api_key to users");
}
};
runMigrations();

View file

@ -5,7 +5,9 @@ CREATE TABLE IF NOT EXISTS users (
display_name TEXT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
last_login DATETIME,
default_game_config TEXT
default_game_config TEXT,
color_scheme TEXT DEFAULT 'blue',
gemini_api_key TEXT
);
CREATE TABLE IF NOT EXISTS quizzes (

View file

@ -34,6 +34,7 @@ export interface AuthenticatedUser {
preferred_username: string;
email?: string;
name?: string;
groups?: string[];
}
export interface AuthenticatedRequest extends Request {
@ -74,6 +75,7 @@ export function requireAuth(
preferred_username: payload.preferred_username || payload.sub!,
email: payload.email,
name: payload.name,
groups: payload.groups || [],
};
next();

View file

@ -8,11 +8,16 @@ router.use(requireAuth);
router.get('/me', (req: AuthenticatedRequest, res: Response) => {
const user = db.prepare(`
SELECT id, username, email, display_name as displayName, default_game_config as defaultGameConfig, created_at as createdAt, last_login as lastLogin
SELECT id, username, email, display_name as displayName, default_game_config as defaultGameConfig,
color_scheme as colorScheme, gemini_api_key as geminiApiKey,
created_at as createdAt, last_login as lastLogin
FROM users
WHERE id = ?
`).get(req.user!.sub) as Record<string, unknown> | undefined;
const groups = req.user!.groups || [];
const hasAIAccess = groups.includes('kaboot-ai-access');
if (!user) {
res.json({
id: req.user!.sub,
@ -20,6 +25,9 @@ router.get('/me', (req: AuthenticatedRequest, res: Response) => {
email: req.user!.email,
displayName: req.user!.name,
defaultGameConfig: null,
colorScheme: 'blue',
geminiApiKey: null,
hasAIAccess,
createdAt: null,
lastLogin: null,
isNew: true,
@ -36,7 +44,12 @@ router.get('/me', (req: AuthenticatedRequest, res: Response) => {
}
}
res.json({ ...user, defaultGameConfig: parsedConfig, isNew: false });
res.json({
...user,
defaultGameConfig: parsedConfig,
hasAIAccess,
isNew: false
});
});
router.put('/me/default-config', (req: AuthenticatedRequest, res: Response) => {
@ -64,4 +77,47 @@ router.put('/me/default-config', (req: AuthenticatedRequest, res: Response) => {
res.json({ success: true });
});
router.get('/me/preferences', (req: AuthenticatedRequest, res: Response) => {
const user = db.prepare(`
SELECT color_scheme as colorScheme, gemini_api_key as geminiApiKey
FROM users
WHERE id = ?
`).get(req.user!.sub) as { colorScheme: string | null; geminiApiKey: string | null } | undefined;
const groups = req.user!.groups || [];
const hasAIAccess = groups.includes('kaboot-ai-access');
res.json({
colorScheme: user?.colorScheme || 'blue',
geminiApiKey: user?.geminiApiKey || null,
hasAIAccess,
});
});
router.put('/me/preferences', (req: AuthenticatedRequest, res: Response) => {
const { colorScheme, geminiApiKey } = req.body;
const upsertUser = db.prepare(`
INSERT INTO users (id, username, email, display_name, color_scheme, gemini_api_key, last_login)
VALUES (?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP)
ON CONFLICT(id) DO UPDATE SET
color_scheme = ?,
gemini_api_key = ?,
last_login = CURRENT_TIMESTAMP
`);
upsertUser.run(
req.user!.sub,
req.user!.preferred_username,
req.user!.email || null,
req.user!.name || null,
colorScheme || 'blue',
geminiApiKey || null,
colorScheme || 'blue',
geminiApiKey || null
);
res.json({ success: true });
});
export default router;