Skip to content

Commit 13fa999

Browse files
committed
feat(api-key): enable direct api key updates
The `/update_api_key` command now accepts the API key directly as an argument. Refactors API key validation and update logic into a shared helper function. Improves error messages, authorization, and conversation handling for API keys.
1 parent 578ba1b commit 13fa999

File tree

2 files changed

+273
-86
lines changed

2 files changed

+273
-86
lines changed

src/bot/commands.ts

Lines changed: 92 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -499,9 +499,11 @@ export class Commands {
499499
'<i>Complete a pending group setup with API key</i>\n\n' +
500500
'<b>/list_groups</b>\n' +
501501
'<i>List all your configured groups</i>\n\n' +
502-
'<b>/update_api_key &lt;chat_id&gt;</b>\n' +
502+
'<b>/update_api_key &lt;chat_id&gt; [api_key]</b>\n' +
503503
'<i>Update API key for a group</i>\n' +
504-
'<i>Example: /update_api_key -123456789</i>\n\n' +
504+
'<i>Examples:</i>\n' +
505+
'<code>/update_api_key -123456789</code> - Interactive mode\n' +
506+
'<code>/update_api_key -123456789 AIza...</code> - Direct update\n\n' +
505507
'<b>/remove_group &lt;chat_id&gt;</b>\n' +
506508
'<i>Remove a group configuration</i>\n' +
507509
'<i>Example: /remove_group -123456789</i>\n\n' +
@@ -645,8 +647,10 @@ export class Commands {
645647
if (isNaN(chatId)) {
646648
await ctx.reply(
647649
'❌ Invalid group ID format.\n\n' +
648-
'Usage: `/update_api_key <chat_id>`\n\n' +
649-
'Example: `/update_api_key -123456789`\n\n' +
650+
'Usage: `/update_api_key <chat_id> [api_key]`\n\n' +
651+
'Examples:\n' +
652+
'• `/update_api_key -123456789` - Interactive mode\n' +
653+
'• `/update_api_key -123456789 AIza...` - Direct update\n\n' +
650654
'Run `/list_groups` to see your groups and their IDs.',
651655
{ parse_mode: 'HTML' }
652656
);
@@ -656,11 +660,21 @@ export class Commands {
656660
// Verify the group belongs to this user and is configured
657661
const group = configuredGroups.find(g => g.telegram_chat_id === chatId);
658662
if (!group) {
659-
await ctx.reply(
660-
'❌ Group not found or not configured.\n\n' +
661-
'Run `/list_groups` to see your configured groups.',
662-
{ parse_mode: 'HTML' }
663-
);
663+
// Check if group exists but doesn't have API key
664+
const groupExists = allGroups.find(g => g.telegram_chat_id === chatId);
665+
if (groupExists) {
666+
await ctx.reply(
667+
'❌ Group found but not configured with an API key.\n\n' +
668+
'Please complete the setup first using /setup_group or /setup.',
669+
{ parse_mode: 'HTML' }
670+
);
671+
} else {
672+
await ctx.reply(
673+
'❌ Group not found.\n\n' +
674+
'Run `/list_groups` to see your configured groups.',
675+
{ parse_mode: 'HTML' }
676+
);
677+
}
664678
return;
665679
}
666680

@@ -685,9 +699,46 @@ export class Commands {
685699
return;
686700
}
687701

688-
// Store the group ID for the conversation
702+
// Check if API key was provided as second argument
703+
if (args.length >= 3) {
704+
// Direct update mode - API key provided as argument
705+
const apiKey = args.slice(2).join(' ').trim();
706+
707+
// Import the validation function (we'll need to export it or move it)
708+
// For now, let's do the validation inline
709+
if (!GeminiService.validateApiKey(apiKey)) {
710+
await ctx.reply('❌ Invalid API key format. Please check your key and try again.');
711+
return;
712+
}
713+
714+
// Test and update the API key
715+
try {
716+
const gemini = new GeminiService(apiKey);
717+
await gemini.summarizeMessages([{ content: 'test', timestamp: new Date().toISOString() }]);
718+
719+
const encryptedKey = this.encryption.encrypt(apiKey);
720+
await this.db.updateGroupApiKey(chatId, encryptedKey);
721+
722+
await ctx.reply('✅ API key updated successfully! The bot will now use the new key for summaries.');
723+
} catch (error: any) {
724+
const errorMessage = error.message || 'Unknown error';
725+
if (errorMessage.includes('Invalid API key') || errorMessage.includes('API_KEY_INVALID') || errorMessage.includes('401')) {
726+
await ctx.reply('❌ Invalid API key. Please check your key and try again.\n\n💡 Get a new key from: https://makersuite.google.com/app/apikey');
727+
} else if (errorMessage.includes('quota') || errorMessage.includes('QUOTA_EXCEEDED') || errorMessage.includes('429')) {
728+
await ctx.reply('❌ API quota exceeded. Please try again later or check your API usage.');
729+
} else {
730+
await ctx.reply(`❌ Failed to validate API key: ${errorMessage}. Please check your key and try again.`);
731+
}
732+
}
733+
return;
734+
}
735+
736+
// Interactive mode - no API key provided, enter conversation
689737
setUpdateState(chat.id, chatId);
690738

739+
// Send prompt message before entering conversation
740+
await ctx.reply('Please paste your new Gemini API key:');
741+
691742
// Enter update conversation
692743
await ctx.conversation.enter('updateApiKey', { overwrite: true });
693744
return;
@@ -1378,13 +1429,38 @@ export class Commands {
13781429
}
13791430

13801431
try {
1381-
// Verify the group belongs to this user and is configured
1382-
const groups = await this.db.listGroupsForUser(chat.id);
1383-
const group = groups.find(g => g.telegram_chat_id === chatId && g.gemini_api_key_encrypted);
1384-
1385-
if (!group) {
1432+
const userId = ctx.from?.id;
1433+
if (!userId) {
1434+
await ctx.editMessageText('❌ Could not identify user.');
1435+
return;
1436+
}
1437+
1438+
// First, verify the group exists in the database
1439+
const groupFromDb = await this.db.getGroup(chatId);
1440+
if (!groupFromDb) {
1441+
await ctx.editMessageText(
1442+
'❌ Group not found in database.\n\n' +
1443+
'The group may not be set up yet. Run /setup in the group or /setup_group in private chat.'
1444+
);
1445+
return;
1446+
}
1447+
1448+
// Verify the group belongs to this user
1449+
// Compare as numbers to avoid type mismatch issues
1450+
const setupUserId = groupFromDb.setup_by_user_id ? Number(groupFromDb.setup_by_user_id) : null;
1451+
if (setupUserId !== userId) {
1452+
await ctx.editMessageText(
1453+
'❌ You are not authorized to update this group.\n\n' +
1454+
'Only the user who set up the group can update its API key.'
1455+
);
1456+
return;
1457+
}
1458+
1459+
// Verify the group has an API key configured
1460+
if (!groupFromDb.gemini_api_key_encrypted || groupFromDb.gemini_api_key_encrypted.trim().length === 0) {
13861461
await ctx.editMessageText(
1387-
'❌ Group not found or not configured.'
1462+
'❌ Group found but not configured with an API key.\n\n' +
1463+
'Please complete the setup first using /setup_group or /setup.'
13881464
);
13891465
return;
13901466
}

0 commit comments

Comments
 (0)