Skip to content

Commit 083008b

Browse files
committed
refactor: update redeem code logic for auto-public and storage constraints
- Only store successful or expired redeems in database (invalid codes not stored) - Auto-make codes public when second user successfully redeems same code - Remove /redeempublic command - public codes redeemed via /redeem - Remove public code auto-redemption from /setup - Add safeguard: explicitly public codes revert to private if they become invalid - Add helper methods: isCodePublic(), isCodeSuccessfullyRedeemedByOther(), markCodeAsPrivate() - Update all documentation and command references
1 parent 5dfc701 commit 083008b

9 files changed

Lines changed: 112 additions & 483 deletions

File tree

.instructions.md

Lines changed: 32 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -211,13 +211,12 @@ export async function execute(interaction: ChatInputCommandInteraction) {
211211

212212
**Credential Management**
213213

214-
- `/setup` - Save Idle Champions credentials (auto-redeems public codes for new users)
214+
- `/setup` - Save Idle Champions credentials
215215

216216
**Code Redemption**
217217

218-
- `/redeem` - Privately redeem a code (private to you)
219-
- `/redeempublic` - Publicly redeem shared codes (shows available codes or redeems specific one)
220-
- `/makepublic` - Share your redeemed code with other users
218+
- `/redeem` - Redeem a code (private by default, becomes public if another user redeems successfully)
219+
- `/makepublic` - Explicitly share your redeemed code with other users
221220

222221
**Account Management**
223222

@@ -318,14 +317,23 @@ const details = await codeManager.getRedeemedCodeDetails(discordId, limit);
318317
**Public Code Management**
319318

320319
```typescript
321-
// Get all public unexpired codes (for /redeempublic)
320+
// Get all public unexpired codes
322321
const publicCodes = await codeManager.getPublicUnexpiredCodes();
323322

323+
// Check if code is public
324+
const isPublic = await codeManager.isCodePublic(code);
325+
326+
// Check if code was successfully redeemed by another user
327+
const redeemedByOther = await codeManager.isCodeSuccessfullyRedeemedByOther(code, userId);
328+
324329
// Mark code as expired (called when server returns "expired" error)
325330
await codeManager.markCodeAsExpired(code);
326331

327332
// Make a code public (called by /makepublic command)
328333
await codeManager.markCodeAsPublic(code);
334+
335+
// Make a code private (called when an explicitly public code becomes invalid on redeem)
336+
await codeManager.markCodeAsPrivate(code);
329337
```
330338

331339
### Adding Data
@@ -335,7 +343,7 @@ await codeManager.markCodeAsPublic(code);
335343
await codeManager.addRedeemedCode(
336344
code,
337345
interaction.user.id,
338-
'success',
346+
'Success',
339347
lootDetails,
340348
false // Private
341349
);
@@ -693,44 +701,39 @@ NODE_ENV=development # Optional
693701

694702
### Public vs Private Codes
695703

696-
The bot now supports sharing codes between users:
704+
The bot supports automatic and manual code sharing between users:
697705

698706
**Private Codes** (Default)
699707

700-
- Redeemed via `/redeem` command
708+
- All codes start as private when redeemed via `/redeem`
701709
- Only the user who redeemed it gets the rewards
702-
- Not shared with other users
703-
- Stored in database for user's history
710+
- Not shared with other users unless explicitly made public
711+
- **Auto-Public on Second User Success**: If a second user successfully redeems the same code, it automatically becomes public for both users
704712

705-
**Public Codes**
713+
**Public Codes** (Explicit or Automatic)
706714

707-
- Made public via `/makepublic` command
708-
- Any user can redeem via `/redeempublic`
709-
- Only unexpired, successful codes can be made public
710-
- When new users run `/setup`, public codes are automatically redeemed for them
715+
- Made public automatically when a second user successfully redeems it
716+
- Made public explicitly via `/makepublic` command
717+
- Any user can redeem public codes via `/redeem` command
718+
- If an explicitly public code becomes invalid on redemption, it's automatically switched back to private (may be a mistake)
719+
- Only unexpired, successful codes show as public
711720

712721
### Workflow Example
713722

714-
1. User A redeems code `XYZ` via `/redeem code:XYZ` (private)
715-
2. User A likes the code and runs `/makepublic code:XYZ` to share it
716-
3. User B joins and runs `/setup` → automatically redeems `XYZ` and gets rewards
717-
4. User C can manually redeem via `/redeempublic code:XYZ` to see and redeem the shared code
718-
5. User D can run `/redeempublic` (no code) to see all available public codes
719-
720-
### Expiration Tracking
721-
722-
Codes can expire on the game server:
723-
724-
- When a code fails to redeem with "expired" error message, bot marks it as `expired`
725-
- Expired codes no longer appear in public code lists
726-
- Each code tracks when it expires via `expires_at` timestamp
723+
1. User A redeems code `XYZ` via `/redeem code:XYZ` (stored as private)
724+
2. User B redeems the same code `XYZ` via `/redeem code:XYZ` → code automatically becomes public
725+
3. User A can see the code is now public in `/codes` command
726+
4. User C can manually redeem via `/redeem code:XYZ` and will also see it as public
727+
5. User A can explicitly make a code public via `/makepublic code:XYZ` (for exclusive codes they want to share)
728+
6. If User D redeems an explicitly public code and it becomes invalid, it switches back to private automatically
727729

728730
### Database Fields
729731

730-
**redeemed_codes table additions:**
732+
**redeemed_codes table fields:**
731733

732734
- `is_public` (integer) - 1 if public, 0 if private
733735
- `expires_at` (datetime) - When code expires (null = never)
736+
- `status` (text) - 'Success' or 'Code Expired' (only successful/expired redeems are stored)
734737

735738
## Code Scanning (Auto-detection)
736739

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ See [docker-compose.example.yml](docker-compose.example.yml) for all available c
6363

6464
## ✨ Features
6565

66-
- 🤖 **Slash Commands** - `/setup`, `/redeem`, `/inventory`, `/open`, `/blacksmith`, `/codes`, `/makepublic`, `/redeempublic`, `/help`
66+
- 🤖 **Slash Commands** - `/setup`, `/redeem`, `/inventory`, `/open`, `/blacksmith`, `/codes`, `/makepublic`, `/help`
6767
- 🔄 **Auto Code Detection** - Scans Discord messages for codes automatically
6868
- 🎁 **Code Redemption** - Submit codes and get rewards
6969
- 📦 **Chest Management** - Open chests and view loot

docs/README.md

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ A Discord bot that automatically scans for and redeems Idle Champions promo code
44

55
## Features
66

7-
- 🤖 **Slash Commands** - `/setup`, `/redeem`, `/inventory`, `/open`, `/blacksmith`, `/codes`, `/makepublic`, `/redeempublic`, `/help`
7+
- 🤖 **Slash Commands** - `/setup`, `/redeem`, `/inventory`, `/open`, `/blacksmith`, `/codes`, `/makepublic`, `/help`
88
- 🔄 **Auto Code Detection** - Scans Discord messages for codes automatically
99
- 🎁 **Code Redemption** - Submit codes and get rewards
1010
- 📦 **Chest Management** - Open chests and view loot
@@ -62,7 +62,6 @@ brew install mise
6262
| `/blacksmith contract_type:<type> hero_id:<id> count:<count>` | Upgrade heroes |
6363
| `/codes [count:<count>]` | Show your redeemed codes history (last 10) |
6464
| `/makepublic code:<code>` | Share one of your redeemed codes with other users |
65-
| `/redeempublic [code:<code>]` | Redeem public codes shared by other users |
6665
| `/help` | Show all commands |
6766

6867
### Setup & Authentication
@@ -88,15 +87,6 @@ Manually redeem a single code and immediately receive rewards.
8887
- **Response:** Shows rewards obtained (gold, rubies, chests, etc.)
8988
- **Example:** `/redeem code:IDLE2024`
9089

91-
#### `/redeempublic [code:<code>]`
92-
93-
Redeem public codes that other users have shared. Leave the code empty to see all available shared codes, or specify a code to redeem it directly.
94-
95-
- **Optional parameters:**
96-
- `code` - Specific code to redeem (if empty, shows available codes)
97-
- **Benefits:** Access codes from community members who used `/makepublic`
98-
- **Example:** `/redeempublic` or `/redeempublic code:SHARED123`
99-
10090
### Inventory & Progress
10191

10292
#### `/inventory`
@@ -144,11 +134,12 @@ View your personal code redemption history.
144134

145135
#### `/makepublic code:<code>`
146136

147-
Share one of your previously redeemed codes with other users. They can then use it with `/redeempublic`.
137+
Share one of your previously redeemed codes with other users. Other users can redeem the same code via `/redeem` and the rewards will be shared.
148138

149139
- **Required parameters:**
150140
- `code` - One of your redeemed codes (must be in your history)
151141
- **Requirement:** You must have already redeemed this code
142+
- **Note:** Codes automatically become public when a second user successfully redeems them
152143
- **Example:** `/makepublic code:SHARED123`
153144

154145
### Help

docs/STRUCTURE.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ idle-code-redeemer/
5656
- **[src/bot/bot.ts](../src/bot/bot.ts)** - Discord client initialization, event handlers, command routing
5757
- **[src/bot/api/idleChampionsApi.ts](../src/bot/api/idleChampionsApi.ts)** - Game server API client with query-parameter format
5858

59-
### Commands (9 slash commands)
59+
### Commands (8 slash commands)
6060

6161
- **[src/bot/commands/setup.ts](../src/bot/commands/setup.ts)** - `/setup user_id:<id> user_hash:<hash>`
6262
- **[src/bot/commands/redeem.ts](../src/bot/commands/redeem.ts)** - `/redeem code:<code>`
@@ -65,7 +65,6 @@ idle-code-redeemer/
6565
- **[src/bot/commands/blacksmith.ts](../src/bot/commands/blacksmith.ts)** - `/blacksmith contract_type:<type> hero_id:<id> count:<count>`
6666
- **[src/bot/commands/codes.ts](../src/bot/commands/codes.ts)** - `/codes [count:<count>]` (view redeemed codes history)
6767
- **[src/bot/commands/makepublic.ts](../src/bot/commands/makepublic.ts)** - `/makepublic code:<code>` (share codes with other users)
68-
- **[src/bot/commands/redeempublic.ts](../src/bot/commands/redeempublic.ts)** - `/redeempublic [code:<code>]` (redeem shared codes)
6968
- **[src/bot/commands/help.ts](../src/bot/commands/help.ts)** - `/help`
7069

7170
### Database

src/bot/commands/makepublic.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ export async function execute(interaction: ChatInputCommandInteraction) {
4040
.setColor(0x00ff00)
4141
.setTitle('✅ Code Shared Successfully')
4242
.setDescription(
43-
`The code \`${code}\` is now public!\n\nOther users can now redeem it using \`/redeempublic code:${code}\``
43+
`The code \`${code}\` is now public!\n\nOther users can now redeem it using \`/redeem code:${code}\``
4444
)
4545
.setFooter({ text: 'Public codes are shared with all server members' });
4646

src/bot/commands/redeem.ts

Lines changed: 42 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -154,22 +154,55 @@ export async function execute(interaction: ChatInputCommandInteraction) {
154154
return;
155155
}
156156

157-
// Save to database (private code)
158157
const codeResponse = response as any;
159158
const statusName = getCodeStatusName(codeResponse.codeStatus);
159+
const isSuccess = codeResponse.codeStatus === 0; // 0 = Success
160+
const isExpiredStatus = codeResponse.codeStatus === 4; // 4 = Code Expired
161+
160162
logger.info(
161163
`[REDEEM] Code ${code} redeemed with status: ${statusName} for user ${interaction.user.tag}`
162164
);
163-
await codeManager.addRedeemedCode(
164-
code,
165-
interaction.user.id,
166-
statusName,
167-
codeResponse.lootDetail,
168-
false // Private code
169-
);
165+
166+
// Only store successful or expired redeems
167+
if (isSuccess || isExpiredStatus) {
168+
let shouldBePublic = false;
169+
170+
// If successful, check if another user already successfully redeemed it
171+
if (isSuccess) {
172+
const wasRedeemedByOther = await codeManager.isCodeSuccessfullyRedeemedByOther(
173+
code,
174+
interaction.user.id
175+
);
176+
if (wasRedeemedByOther) {
177+
// Second user redeeming successfully - make it public
178+
shouldBePublic = true;
179+
logger.info(
180+
`[REDEEM] Code ${code} will be auto-made public (second successful redeem)`
181+
);
182+
}
183+
}
184+
185+
await codeManager.addRedeemedCode(
186+
code,
187+
interaction.user.id,
188+
statusName,
189+
codeResponse.lootDetail,
190+
shouldBePublic // Private by default, public if second user redeems successfully
191+
);
192+
} else {
193+
// For invalid/already redeemed codes - check if the code was explicitly made public
194+
// If so, switch it back to private (might be a mistake)
195+
const codeWasPublic = await codeManager.isCodePublic(code);
196+
197+
if (codeWasPublic) {
198+
logger.warn(
199+
`[REDEEM] Code ${code} was public but is now invalid - switching back to private`
200+
);
201+
await codeManager.markCodeAsPrivate(code);
202+
}
203+
}
170204

171205
// Build response embed
172-
const isSuccess = codeResponse.codeStatus === 0; // 0 = Success
173206
const embed = new EmbedBuilder()
174207
.setColor(isSuccess ? 0x00ff00 : 0xffaa00)
175208
.setTitle(isSuccess ? '✅ Code Redeemed!' : `⚠️ ${statusName}`)

0 commit comments

Comments
 (0)