Skip to content

feat: new commands#165

Open
Clintonrocha98 wants to merge 6 commits into3.xfrom
feat/new-commands
Open

feat: new commands#165
Clintonrocha98 wants to merge 6 commits into3.xfrom
feat/new-commands

Conversation

@Clintonrocha98
Copy link
Collaborator

@Clintonrocha98 Clintonrocha98 commented Jan 24, 2026

This pull request introduces a multi-step flow for the /apresentar (Introduction) command and adds a new /delas slash command to manage community roles in the Discord bot. The main improvements are the addition of a technology selection step during user introduction, the assignment of technology roles, and a dedicated command for managing the "He4rt Delas" role.

Major enhancements:

Introduction Command Improvements

  • Refactored the introduction flow to a multi-step process: after submitting personal information, users are prompted to select their technology interests from a list, or skip this step. Selected technologies are displayed in the welcome embed and corresponding roles are assigned to the user. [1] [2] [3] [4] [5]
  • Added a comprehensive list of technology roles and their metadata (labels, descriptions, emojis), and loaded their IDs from configuration for assignment. [1] [2]

New Slash Command: /delas

  • Implemented the DelasCommand, a new slash command that allows eligible users to assign the "He4rt Delas" role to other members, with proper permission and validation checks (e.g., cannot assign to self, both users must have presented, etc.).

Supporting Changes

  • Updated configuration to include IDs for all technology roles, enabling dynamic assignment.
  • Minor cleanup: removed unused imports and added necessary dependencies for caching and other features. [1] [2]

Summary by CodeRabbit

  • New Features
    • Added '/delas' slash command to assign the He4rt Delas role with validation and user feedback.
    • Redesigned introduction into a two-step flow: personal info modal then optional technology selection.
    • Added session-based persistence for presentation data during the flow.
    • Added technology-based role assignments during introduction.
    • Added a new technology roles configuration block mapping tech choices to roles.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Jan 24, 2026

📝 Walkthrough

Walkthrough

Adds a nested roles.technologies mapping to bot config, introduces a new /delas slash command to assign the He4rt Delas role with validations, and refactors the Introduction flow into a two-step personal-info → technology-selection flow with session caching, expanded embed fields, and technology-based role assignment.

Changes

Cohort / File(s) Summary
Role Configuration
app-modules/bot-discord/config/bot-discord.php
Added a new roles.technologies nested block mapping technology keys (e.g., basic_english, javascript, python, he4rt_delas, etc.) to role IDs.
New Delas Command
app-modules/bot-discord/src/SlashCommands/DelasCommand.php
New DelasCommand class implementing /delas: validates executor permissions, validates target (exists, not bot, presented, not already assigned), appends He4rt Delas role to target, and sends contextual responses with error handling.
Introduction Command (flow, persistence, roles)
app-modules/bot-discord/src/SlashCommands/IntroductionCommand.php
Reworked into two-step flow: personal-info modal → technology selection (with skip); added technologyOptions and technologyRoles wiring from config, session caching via Cache (600s), updated persistData signature, updated embed fields to include technologies, and assigns corresponding technology roles alongside presentation role.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Discord
    participant IntroCommand as IntroductionCommand
    participant Cache
    participant Guild
    participant Channel

    User->>Discord: Trigger /introduction
    Discord->>IntroCommand: handle(Interaction)
    IntroCommand->>Discord: showPersonalInfoModal()
    Discord->>User: Display personal-info modal

    User->>Discord: Submit personal info
    Discord->>IntroCommand: savePersonalInfoAndShowTechSelection()
    IntroCommand->>Cache: Save personal data (presentation_data_<user_id>, 600s)
    IntroCommand->>Discord: showTechnologySelection()
    Discord->>User: Display technology selection / skip

    User->>Discord: Select technologies or skip
    Discord->>IntroCommand: finalizePresentation()
    IntroCommand->>Cache: Retrieve personal data
    IntroCommand->>Guild: Assign presentation role
    IntroCommand->>Guild: Assign selected technology roles
    IntroCommand->>Channel: Post presentation embed (includes technologies)
    IntroCommand->>Cache: Clear session
    Discord->>User: Confirm presentation success
Loading
sequenceDiagram
    participant Executor as User
    participant Discord
    participant DelasCommand
    participant Guild
    participant TargetUser

    Executor->>Discord: /delas target_user
    Discord->>DelasCommand: handle(Interaction)
    DelasCommand->>DelasCommand: validateExecutor()
    DelasCommand->>Guild: Fetch target member
    DelasCommand->>DelasCommand: validateTarget()
    DelasCommand->>Guild: Aggregate current roles + He4rt Delas role
    Guild->>TargetUser: Update member roles
    DelasCommand->>Discord: respondWithMessage() success
    Discord->>Executor: Display success notification
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • gvieira18
  • danielhe4rt

Poem

🐰 I hopped through configs, roles in a row,
Picked techs with little emojis that glow,
Delas nudged the order with a gentle paw,
Sessions saved briefly to keep things in awe,
Welcome, new members — the rabbit applauds! 🎉

🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'feat: new commands' is overly vague and doesn't clearly communicate the specific changes made. The PR introduces both a multi-step introduction flow refactor and a new delas command, but the title uses a generic term that could apply to any feature addition. Consider a more specific title like 'feat: add multi-step introduction flow and delas command' to better describe the main changes and help reviewers understand the changeset at a glance.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Fix all issues with AI agents
In `@app-modules/bot-discord/src/SlashCommands/DelasCommand.php`:
- Around line 74-80: The error log message uses the wrong class name; update the
Log::error call inside the catch (Throwable $throwable) block to reference
"DelasCommand" instead of "MulherCommand" so logs correctly identify the failing
class (keep the surrounding context: the catch block, $throwable, and existing
metadata keys like 'executor_id' and 'target_id' unchanged).
- Around line 150-167: The addHe4rtDelasRole function currently calls
targetMember->setRoles($currentRoles) but responds immediately; change it to
handle the returned Promise from setRoles() (on the targetMember object) and
only call $interaction->respondWithMessage in the success callback, and call
$interaction->respondWithMessage with an error/ephemeral flag in the rejection
callback; reference the addHe4rtDelasRole method, the setRoles call,
$targetMember, $interaction, $targetUserId and $this->he4rtDelasRoleId when
locating and updating the code so the response is sent after the role assignment
completes (and failures are reported).

In `@app-modules/bot-discord/src/SlashCommands/IntroductionCommand.php`:
- Around line 243-248: The mapping that builds $techList assumes every key in
$selectedTechnologies exists in $this->technologyOptions, which can raise
undefined index notices; update the logic that constructs $techList (the
array_map/implode block referencing $selectedTechnologies and
$this->technologyOptions) to first filter $selectedTechnologies to only keys
present in $this->technologyOptions (e.g. array_filter with
isset($this->technologyOptions[$key])) and then map those validated keys to
emoji+label; keep the existing fallback to 'Nenhuma selecionada' when the
filtered list is empty.
- Around line 188-205: Update the cache session key to include the guild ID to
avoid cross-guild collisions: in savePersonalInfoAndShowTechSelection build the
key using both $interaction->user->id and $interaction->guild_id (e.g.
'presentation_data_{userId}_{guildId}') and store using that key; apply the
identical change in finalizePresentation so it reads and deletes the same
guild-aware cache key (ensure references to the $sessionKey variable and
Cache::put/Cache::get/Cache::forget calls are adjusted to use the new key
format).
🧹 Nitpick comments (3)
app-modules/bot-discord/config/bot-discord.php (1)

13-30: Consider using environment variables for technology role IDs.

The existing configuration values (lines 7-8, 11) use env() with fallback defaults, but these technology role IDs are hardcoded. This inconsistency could make deploying to different environments (dev/staging/prod) more difficult if the role IDs differ.

If these IDs are intentionally constant across all environments, this is fine. Otherwise, consider using environment variables for consistency:

♻️ Example refactor using env()
 'technologies' => [
-    'basic_english' => '546148708077666315',
-    'intermediate_english' => '546148711416332298',
+    'basic_english' => env('HE4RT_ROLE_BASIC_ENGLISH', '546148708077666315'),
+    'intermediate_english' => env('HE4RT_ROLE_INTERMEDIATE_ENGLISH', '546148711416332298'),
     // ... and so on for other roles
 ],
app-modules/bot-discord/src/SlashCommands/IntroductionCommand.php (1)

207-225: Minor simplification possible for select options.

The loop rebuilds the same structure that already exists in $this->technologyOptions. This works fine but could be simplified.

♻️ Optional simplification
 private function showTechnologySelection(Interaction $interaction): void
 {
-    $selectOptions = [];
-    foreach ($this->technologyOptions as $key => $tech) {
-        $selectOptions[$key] = [
-            'label' => $tech['label'],
-            'description' => $tech['description'],
-            'emoji' => $tech['emoji'],
-        ];
-    }
-
     $this->message('Selecione suas tecnologias')
         ->title('Etapa 2: Suas Tecnologias')
         ->content('Selecione as tecnologias que você conhece ou tem interesse. Esta etapa é **opcional** - você pode pular clicando em "Finalizar sem tecnologias".')
-        ->select($selectOptions, placeholder: 'Selecione suas tecnologias (opcional)', minValues: 0, maxValues: 16,
+        ->select($this->technologyOptions, placeholder: 'Selecione suas tecnologias (opcional)', minValues: 0, maxValues: 16,
             route: 'tech_selection')
         ->button(label: 'Finalizar sem tecnologias', style: 'secondary', route: 'skip_tech')
         ->reply($interaction, ephemeral: true);
 }
app-modules/bot-discord/src/SlashCommands/DelasCommand.php (1)

111-148: Add return type hint for better type safety.

The method returns either the target member object or null, but lacks a return type annotation.

♻️ Proposed improvement
-private function validateTarget(Interaction $interaction, string $targetUserId)
+private function validateTarget(Interaction $interaction, string $targetUserId): ?object

Or if you know the specific member class type from DiscordPHP:

+use Discord\Parts\User\Member;
 // ...
-private function validateTarget(Interaction $interaction, string $targetUserId)
+private function validateTarget(Interaction $interaction, string $targetUserId): ?Member

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@app-modules/bot-discord/src/SlashCommands/IntroductionCommand.php`:
- Around line 341-344: The loop that maps $selectedTechnologies to $roles
currently allows the 'he4rt_delas' role to be self-assigned; update the mapping
logic in the foreach over $selectedTechnologies so that when $tech equals
'he4rt_delas' you do not push the role blindly—either skip it entirely or gate
it behind an explicit eligibility check (e.g., call an existing DelasCommand
eligibility method or verify the current user's permissions) before adding
$this->technologyRoles[$tech] to $roles, ensuring only authorized users can
receive that role.
♻️ Duplicate comments (2)
app-modules/bot-discord/src/SlashCommands/IntroductionCommand.php (2)

188-203: Cache key should include guild ID to avoid cross-guild collisions.
Using only user ID (Line 190/229) risks overwriting data if the bot serves multiple guilds.

🐛 Proposed fix
-$sessionKey = 'presentation_data_'.$interaction->user->id;
+$sessionKey = 'presentation_data_'.$interaction->guild_id.'_'.$interaction->user->id;

Apply the same change where the key is read/forgotten.

Also applies to: 227-230


243-247: Guard against unknown tech keys when building the summary.
Direct indexing (Line 246) can throw undefined array key notices if values are unexpected.

🐛 Proposed fix
-$techList = $techCount > 0
-    ? implode(', ', array_map(fn ($tech
-) => $this->technologyOptions[$tech]['emoji'].' '.$this->technologyOptions[$tech]['label'],
-        $selectedTechnologies))
-    : 'Nenhuma selecionada';
+$techList = $techCount > 0
+    ? implode(', ', array_map(fn ($tech) => isset($this->technologyOptions[$tech])
+        ? $this->technologyOptions[$tech]['emoji'].' '.$this->technologyOptions[$tech]['label']
+        : $tech,
+        $selectedTechnologies))
+    : 'Nenhuma selecionada';

Comment on lines +341 to +344
foreach ($selectedTechnologies as $tech) {
if (isset($this->technologyRoles[$tech])) {
$roles[] = $this->technologyRoles[$tech];
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Potential bypass: He4rt Delas role can be self-assigned via tech selection.
Because he4rt_delas is selectable (Line 118) and roles are auto-assigned here, any user can grant themselves the role, undermining the DelasCommand eligibility checks. Confirm intended policy; if restricted, exclude/gate this role here.

🔒 Suggested guard
 foreach ($selectedTechnologies as $tech) {
+    if ($tech === 'he4rt_delas') {
+        continue; // keep selection for display, but don't auto-assign restricted role
+    }
     if (isset($this->technologyRoles[$tech])) {
         $roles[] = $this->technologyRoles[$tech];
     }
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
foreach ($selectedTechnologies as $tech) {
if (isset($this->technologyRoles[$tech])) {
$roles[] = $this->technologyRoles[$tech];
}
foreach ($selectedTechnologies as $tech) {
if ($tech === 'he4rt_delas') {
continue; // keep selection for display, but don't auto-assign restricted role
}
if (isset($this->technologyRoles[$tech])) {
$roles[] = $this->technologyRoles[$tech];
}
🤖 Prompt for AI Agents
In `@app-modules/bot-discord/src/SlashCommands/IntroductionCommand.php` around
lines 341 - 344, The loop that maps $selectedTechnologies to $roles currently
allows the 'he4rt_delas' role to be self-assigned; update the mapping logic in
the foreach over $selectedTechnologies so that when $tech equals 'he4rt_delas'
you do not push the role blindly—either skip it entirely or gate it behind an
explicit eligibility check (e.g., call an existing DelasCommand eligibility
method or verify the current user's permissions) before adding
$this->technologyRoles[$tech] to $roles, ensuring only authorized users can
receive that role.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@app-modules/bot-discord/src/SlashCommands/DelasCommand.php`:
- Around line 72-74: The catch block that currently swallows exceptions in
DelasCommand (catch (Throwable) { $interaction->respondWithMessage(...) })
should log the exception before responding; add the import use
Illuminate\Support\Facades\Log; and inside the catch capture the Throwable
(e.g., catch (Throwable $e)) then call Log::error with a descriptive message and
the exception/error details (message and stack) before calling
$interaction->respondWithMessage('❌ Erro ao processar comando. Tente
novamente.', true).
♻️ Duplicate comments (1)
app-modules/bot-discord/src/SlashCommands/DelasCommand.php (1)

152-157: Handle async promise from setRoles() before responding.

setRoles() returns a Promise that resolves when the Discord API call completes. The current code sends the success message immediately without waiting, risking a success announcement even if the role assignment fails.

🧹 Nitpick comments (1)
app-modules/bot-discord/src/SlashCommands/DelasCommand.php (1)

102-102: Add return type hint for better type safety.

The method returns either a Member or null, but lacks a return type declaration.

♻️ Suggested improvement
-    private function validateTarget(Interaction $interaction, string $targetUserId)
+    private function validateTarget(Interaction $interaction, string $targetUserId): ?\Discord\Parts\Guild\Member

Alternatively, add the import and use the short name:

use Discord\Parts\Guild\Member;
-    private function validateTarget(Interaction $interaction, string $targetUserId)
+    private function validateTarget(Interaction $interaction, string $targetUserId): ?Member

Comment on lines +72 to +74
} catch (Throwable) {
$interaction->respondWithMessage('❌ Erro ao processar comando. Tente novamente.', true);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Add error logging before responding.

The catch block swallows all exceptions without logging, making production debugging difficult. While the previous version had a typo in the log class name, removing logging entirely is not the solution.

🐛 Proposed fix to restore logging with correct class name
-        } catch (Throwable) {
+        } catch (Throwable $throwable) {
+            Log::error('Error in DelasCommand', [
+                'executor_id' => $interaction->user->id,
+                'target_id' => $targetUserId ?? 'unknown',
+                'error' => $throwable->getMessage(),
+                'trace' => $throwable->getTraceAsString(),
+            ]);
             $interaction->respondWithMessage('❌ Erro ao processar comando. Tente novamente.', true);
         }

Don't forget to add the import at the top:

use Illuminate\Support\Facades\Log;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
} catch (Throwable) {
$interaction->respondWithMessage('❌ Erro ao processar comando. Tente novamente.', true);
}
} catch (Throwable $throwable) {
Log::error('Error in DelasCommand', [
'executor_id' => $interaction->user->id,
'target_id' => $targetUserId ?? 'unknown',
'error' => $throwable->getMessage(),
'trace' => $throwable->getTraceAsString(),
]);
$interaction->respondWithMessage('❌ Erro ao processar comando. Tente novamente.', true);
}
🤖 Prompt for AI Agents
In `@app-modules/bot-discord/src/SlashCommands/DelasCommand.php` around lines 72 -
74, The catch block that currently swallows exceptions in DelasCommand (catch
(Throwable) { $interaction->respondWithMessage(...) }) should log the exception
before responding; add the import use Illuminate\Support\Facades\Log; and inside
the catch capture the Throwable (e.g., catch (Throwable $e)) then call
Log::error with a descriptive message and the exception/error details (message
and stack) before calling $interaction->respondWithMessage('❌ Erro ao processar
comando. Tente novamente.', true).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

Comments