-
-
Notifications
You must be signed in to change notification settings - Fork 319
feat: Implement Slack command handlers for polls, reminders, and huddles #5334
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
|
👋 Hi @arnavkirti! This pull request needs a peer review before it can be merged. Please request a review from a team member who is not:
Once a valid peer review is submitted, this check will pass automatically. Thank you! |
|
Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. WalkthroughAdds Slack polls, reminders, and huddles: six new models + migration, admin registrations, view handlers and block builders, two management commands (scheduler + cleanup) wired into the 10-minute runner, template command entries, and extensive tests for commands, interactions, blocks, and the scheduler. (50 words) Changes
Sequence Diagram(s)sequenceDiagram
participant Cmd as Scheduler (management cmd)
participant DB as Database (Django models)
participant Token as Token Resolver
participant Slack as Slack API (WebClient)
Note over Cmd,DB: Fetch pending reminders/huddles (batched, select_for_update skip_locked)
Cmd->>DB: SELECT ids WHERE pending/scheduled...
DB-->>Cmd: item ids
loop per item
Cmd->>Token: resolve token for workspace_id
Token-->>Cmd: token or default
Cmd->>Slack: users.info (verify user/creator)
alt user exists
Slack-->>Cmd: 200 OK
Cmd->>Slack: conversations.open / resolve channel
alt channel resolved
Slack-->>Cmd: channel id
Cmd->>Slack: chat.postMessage (send/notify)
alt success
Slack-->>Cmd: message_ts
Cmd->>DB: mark sent / update huddle state
DB-->>Cmd: updated
else 429 rate limit
Slack-->>Cmd: 429 (+Retry-After?)
Cmd->>DB: increment retry_count & set error/backoff
DB-->>Cmd: updated
else network error
Slack-->>Cmd: timeout/error
Cmd->>DB: increment retry_count & set error_message
DB-->>Cmd: updated
end
else channel unresolved
Cmd->>DB: mark failed/cancel
DB-->>Cmd: updated
end
else user missing
Slack-->>Cmd: 404 / not_found
Cmd->>DB: mark failed/cancel
DB-->>Cmd: updated
end
end
Note over Cmd,DB: Huddle lifecycle transitions (pre-notify → start → complete) with dry-run guard
Estimated code review effort🎯 5 (Critical) | ⏱️ ~120 minutes
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
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. Comment |
📊 Monthly LeaderboardHi @arnavkirti! Here's how you rank for December 2025:
Leaderboard based on contributions in December 2025. Keep up the great work! 🚀 |
❌ Pre-commit checks failedThe pre-commit hooks found issues that need to be fixed. Please run the following commands locally to fix them: # Install pre-commit if you haven't already
pip install pre-commit
# Run pre-commit on all files
pre-commit run --all-files
# Or run pre-commit on staged files only
pre-commit runAfter running these commands, the pre-commit hooks will automatically fix most issues. 💡 Tip: You can set up pre-commit to run automatically on every commit by running: pre-commit installPre-commit outputFor more information, see the pre-commit documentation. |
website/management/commands/process_slack_reminders_and_huddles.py
Outdated
Show resolved
Hide resolved
website/management/commands/process_slack_reminders_and_huddles.py
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 5
🧹 Nitpick comments (8)
website/templates/slack.html (1)
282-312: Consider documenting list/cancel subcommands for reminders and huddlesThe new command docs for
/blt_poll,/blt_remind, and/blt_huddlelook accurate for the basic create flows. Given that the implementation also supports listing and cancelling reminders/huddles, you might optionally add a brief note or extra examples for those subcommands so this page reflects the full feature set.website/tests/test_slack.py (1)
318-603: Slash command tests cover main happy paths and help flows wellThe new tests around
/blt_poll,/blt_remind, and/blt_huddleexercise both help (no‑text) and standard creation paths, and validate the resulting database state (questions/options, reminder status/target, huddle fields and participants, activity logging). The request construction is consistent with existing Slack command tests and should give good regression protection.If you want to tighten them further later, you could factor out the repeated Slack user/mocking setup into small helpers and add one or two negative‑case tests (e.g., too few poll options, invalid time syntax), but that’s optional.
website/admin.py (1)
1001-1006: Default admin registration is sufficient for initial Slack featuresRegistering the SlackPoll/Option/Vote, SlackReminder, SlackHuddle, and SlackHuddleParticipant models with the default admin is a good starting point. If usage grows, you might later add list filters (e.g., by status/workspace) for easier operations, but nothing is required now.
website/management/commands/process_slack_reminders_and_huddles.py (2)
123-125: Queryingworkspace_namewith a workspace ID appears intentional but is confusing.The field name
workspace_nameis used to store the Slack team/workspace ID (not the human-readable name). This matches existing patterns inslack_handlers.pybut the naming is misleading. Consider renaming the field in a future migration for clarity.
215-221: Redundantdry_runcheck inside the non-dry-run branch.Line 218 checks
not options["dry_run"], but this code is already inside theelseblock (line 215) that only executes whendry_runisFalse. The condition is always true and can be simplified.else: ok_count = 0 ws_token = self._token_for_workspace(huddle.workspace_id, token) - if not ws_token and not options["dry_run"]: + if not ws_token: huddle.reminder_sent = True # avoid infinite loop; no token to send huddle.save(update_fields=["reminder_sent"]) continuewebsite/views/slack_handlers.py (3)
92-104: Sequential API calls in_validate_users_existcould be slow for many users.Each user ID triggers a separate Slack API call. For huddles with many participants, this adds latency. Consider batching if Slack's API supports it, or adding a reasonable limit on participant count.
3169-3192: Poll creation is not transactional with Slack message posting.If
chat_postMessagefails after the poll is created in the database, an orphaned poll (withmessage_ts=None) remains. Consider wrapping the DB operations in a transaction or adding cleanup for polls withoutmessage_ts.
3602-3631: Same transactional concern as polls—orphaned huddles if Slack API fails.If
chat_postMessagefails after huddle creation, an orphaned record withmessage_ts=Noneremains. Consider consistent cleanup or transactional handling across all commands.
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting
📒 Files selected for processing (10)
website/admin.py(2 hunks)website/management/commands/process_slack_reminders_and_huddles.py(1 hunks)website/management/commands/run_ten_minutes.py(1 hunks)website/migrations/0264_slackhuddle_slackpoll_slackpolloption_slackreminder_and_more.py(1 hunks)website/models.py(1 hunks)website/templates/slack.html(1 hunks)website/tests/test_slack.py(1 hunks)website/tests/test_slack_blocks.py(1 hunks)website/tests/test_slack_scheduler.py(1 hunks)website/views/slack_handlers.py(9 hunks)
🧰 Additional context used
🧬 Code graph analysis (4)
website/tests/test_slack_blocks.py (2)
website/models.py (5)
SlackPoll(3650-3685)SlackPollOption(3688-3707)SlackPollVote(3710-3727)SlackHuddle(3785-3843)SlackHuddleParticipant(3846-3880)website/views/slack_handlers.py (2)
build_poll_blocks(3208-3275)build_huddle_blocks(3647-3715)
website/admin.py (1)
website/models.py (6)
SlackHuddle(3785-3843)SlackHuddleParticipant(3846-3880)SlackPoll(3650-3685)SlackPollOption(3688-3707)SlackPollVote(3710-3727)SlackReminder(3730-3782)
website/management/commands/process_slack_reminders_and_huddles.py (1)
website/models.py (3)
SlackHuddle(3785-3843)SlackIntegration(105-126)SlackReminder(3730-3782)
website/tests/test_slack_scheduler.py (1)
website/models.py (5)
Integration(87-102)SlackHuddle(3785-3843)SlackHuddleParticipant(3846-3880)SlackIntegration(105-126)SlackReminder(3730-3782)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: Run Tests
- GitHub Check: Agent
- GitHub Check: CodeQL analysis (python)
- GitHub Check: docker-test
🔇 Additional comments (14)
website/management/commands/run_ten_minutes.py (1)
20-24: Slack scheduler hook integrates cleanly with existing 10‑minute tasksThe new
process_slack_reminders_and_huddlescall follows the same error‑isolation pattern ascron_send_reminders, so a Slack‑specific failure won’t break the entire scheduled run while still being logged with full traceback. No changes needed here.website/tests/test_slack_blocks.py (1)
1-46: Block‑builder tests provide good coverage of key UX elementsThese tests hit the critical behaviors for polls (question/options plus non‑zero bar rendering) and huddles (header plus action buttons). The assertions on the JSON‑serialized blocks are straightforward and should be stable as long as the bar character and action block structure remain part of the design.
website/admin.py (1)
80-87: Slack models correctly wired into adminThe additional imports for the Slack poll/reminder/huddle models are correct and match the model names and relationships in
website.models. No issues here.website/migrations/0264_slackhuddle_slackpoll_slackpolloption_slackreminder_and_more.py (1)
13-204: Migration schema matches Slack model definitions and indexing needsThe migration cleanly defines all six Slack models with the expected fields, status choices, uniqueness constraints, and multi‑column indexes. It’s aligned with the model definitions in
website.modelsand should support the query patterns used by the handlers and scheduler.website/models.py (1)
3650-3880: Slack poll/reminder/huddle models are well‑structured and indexedThe new Slack models are coherent and match the intended workflows:
- Polls:
SlackPoll,SlackPollOption, andSlackPollVotemodel questions, options, and per‑option votes with appropriate uniqueness and indexing, plus an explicitclose_pollhelper.- Reminders:
SlackRemindercaptures target, timing, and status with helper methods for sent/failed/cancelled, and indexes tuned for “due pending reminders” queries.- Huddles:
SlackHuddleandSlackHuddleParticipantrepresent scheduled meetings and participant responses, with small guard‑railed state‑transition helpers and a set‑basedVALID_RESPONSESfor fast validation.The structure looks solid for the scheduler and Slack command handlers; I don’t see any correctness issues here.
website/tests/test_slack_scheduler.py (1)
19-107: Scheduler dry‑run tests exercise key reminder and huddle transitionsThese tests set up realistic SlackIntegration/Organization records, patch outbound HTTP, and verify the crucial behaviors of
process_slack_reminders_and_huddlesin dry‑run mode: due reminders are marked sent, upcoming huddles get their pre‑notification flag set, and past huddles move tostarted. This should give good coverage of the main state transitions without relying on actual Slack API calls.website/management/commands/process_slack_reminders_and_huddles.py (2)
1-16: LGTM on imports and constants.The imports are appropriate for the task. Constants for retry logic (
MAX_RETRIES,BASE_BACKOFF_SECONDS) are well-defined.
127-181: Transaction holds locks during network I/O—acceptable withskip_lockedbut worth monitoring.The design processes reminders atomically within a single transaction, including Slack API calls. With
skip_locked=True, concurrent runs won't deadlock. Monitor for lock contention if batch sizes grow or Slack latency increases.website/views/slack_handlers.py (6)
327-338: LGTM on action routing.The new action handlers follow the established
startswith()pattern and integrate cleanly with the existing dispatch logic.
1355-1380: Good granular error handling for Slack API failures.The specific error code handling (
ratelimited,channel_not_found,invalid_auth, etc.) with appropriate HTTP status codes improves debuggability and user experience.
3278-3413: LGTM on reminder command handler.Good input parsing with multiple format support, user validation before creation, and defensive error handling for channel confirmation posting.
3850-3880: LGTM on poll close handler.Proper authorization check (only creator can close) and status validation before closing.
3718-3778: Good use of annotation for participant counts.Using
.annotate(participants_count=Count("participants"))avoids N+1 queries when listing huddles.
3216-3226: No action required. Thevote_countproperty exists on theSlackPollOptionmodel and is properly implemented as@property def vote_count(self): return self.votes.count(). The fallback in line 3220 is safe and will work correctly as a defensive programming pattern when the annotation is unavailable.Likely an incorrect or invalid review comment.
website/management/commands/process_slack_reminders_and_huddles.py
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR implements three new Slack bot commands (/blt_poll, /blt_remind, /blt_huddle) for the OWASP BLT project, adding interactive polling, reminder scheduling, and meeting coordination functionality. The implementation includes database models, command handlers, interactive button handlers, a background processing system for reminders and notifications, comprehensive test coverage, and documentation updates.
Key Changes
- Database Models: Added 6 new models (SlackPoll, SlackPollOption, SlackPollVote, SlackReminder, SlackHuddle, SlackHuddleParticipant) with appropriate indexes and constraints
- Command Handlers: Implemented command parsing, validation, and Slack Block Kit UI generation for all three commands
- Background Processing: Created a management command with retry logic, rate limiting handling, and transaction safety for processing reminders and huddle notifications
- Tests: Added 20+ tests covering command handlers, block builders, and scheduler functionality
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 12 comments.
Show a summary per file
| File | Description |
|---|---|
| website/models.py | Adds 6 new models for polls, reminders, and huddles with proper relationships, indexes, and helper methods |
| website/views/slack_handlers.py | Implements command handlers, block builders, and action handlers for interactive components; adds helper functions for date formatting, channel restrictions, and user validation |
| website/management/commands/process_slack_reminders_and_huddles.py | Background processor with exponential backoff retry logic, rate limit handling, and transaction safety using select_for_update |
| website/tests/test_slack.py | Tests for command help messages, poll/reminder/huddle creation with proper mocking |
| website/tests/test_slack_scheduler.py | Tests for reminder sending and huddle notification logic in dry-run mode |
| website/tests/test_slack_blocks.py | Tests for Slack Block Kit UI generation |
| website/templates/slack.html | Adds documentation for the three new commands using Tailwind CSS classes |
| website/admin.py | Registers all 6 new models in Django admin |
| website/management/commands/run_ten_minutes.py | Integrates new scheduler into existing 10-minute cron job |
| website/migrations/0264_*.py | Migration file creating all new tables with constraints and indexes |
website/management/commands/process_slack_reminders_and_huddles.py
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
♻️ Duplicate comments (4)
website/models.py (1)
3724-3742: Consider the unique constraint for single-vote enforcement.The
unique_together = ["poll", "voter_id", "option"]constraint allows users to vote for multiple options (one vote per option). However, the PR objectives mention "single-vote enforcement." This constraint only prevents duplicate votes on the same option, not multiple votes across different options.If the intention is to enforce strictly one vote per user per poll (regardless of
allow_multiple_votes), the constraint should be["poll", "voter_id"]. Otherwise, the application logic in the handler must enforce single-vote behavior whenallow_multiple_votes=False.Based on past review comments, this constraint design has been previously discussed. Please verify that the handler logic correctly enforces single-vote behavior when
allow_multiple_votes=False.website/views/slack_handlers.py (3)
3571-3573: Wall-clock time parsing uses UTC, not user's local timezone.When a user says "at 3:00 PM", they likely mean their local time, but
timezone.now()returns UTC. This was flagged in a previous review. Consider documenting that times are in UTC, or fetching the user's timezone from their Slack profile.
3355-3367: Add validation for non-positive time amounts.The regex allows zero or negative values to be entered, which would create confusing or invalid reminders. This was flagged in a previous review.
amount = int(time_match.group(1)) unit = time_match.group(2) + + if amount <= 0: + return JsonResponse( + { + "response_type": "ephemeral", + "text": "❌ Time amount must be greater than 0.", + } + ) # Calculate remind_at time
3548-3555: Add validation for non-positive time amounts in huddle scheduling.The relative time parser allows zero or negative values. This was flagged in a previous review.
if time_match: amount = int(time_match.group(1)) unit = time_match.group(2) + if amount <= 0: + return JsonResponse( + { + "response_type": "ephemeral", + "text": "❌ Please specify a positive number of minutes or hours.", + } + ) now = timezone.now()
🧹 Nitpick comments (3)
website/views/slack_handlers.py (3)
65-69: Overly broad exception handling hides potential bugs.Catching all exceptions and silently falling back to
time.time()can mask unexpected errors. Consider logging a warning so issues are observable.try: ts = int(dt.timestamp()) - except Exception: - # Fallback to current time if something odd happens + except (OSError, OverflowError, ValueError) as e: + logger.warning("Failed to convert datetime %s to timestamp: %s", dt, e) ts = int(time.time())
3169-3178: Poll and options creation should be wrapped in a transaction.If option creation fails partway through the loop, the poll will exist with incomplete options. Use
transaction.atomic()to ensure atomicity.+from django.db import transaction + ... - # Create poll in database - poll = SlackPoll.objects.create( - creator_id=user_id, workspace_id=team_id, channel_id=channel_id, question=question, status="active" - ) - - # Create poll options - for idx, option_text in enumerate(options): - # Sanitize user input to prevent markdown injection - sanitized_option_text = re.sub(r"([*_~`>])", r"\\\1", option_text) - SlackPollOption.objects.create(poll=poll, option_text=sanitized_option_text, option_number=idx) + # Create poll in database atomically + with transaction.atomic(): + poll = SlackPoll.objects.create( + creator_id=user_id, workspace_id=team_id, channel_id=channel_id, question=question, status="active" + ) + + # Create poll options + for idx, option_text in enumerate(options): + # Sanitize user input to prevent markdown injection + sanitized_option_text = re.sub(r"([*_~`>])", r"\\\1", option_text) + SlackPollOption.objects.create(poll=poll, option_text=sanitized_option_text, option_number=idx)
3606-3619: Huddle and participants creation should be wrapped in a transaction.Similar to poll creation, if participant creation fails, the huddle will exist without all invited participants.
+from django.db import transaction + ... - # Create huddle - huddle = SlackHuddle.objects.create( - creator_id=user_id, - workspace_id=team_id, - channel_id=channel_id, - title=title, - description=sanitized_description, - scheduled_at=scheduled_at, - status="scheduled", - ) - - # Add participants - for participant_id in participants: - SlackHuddleParticipant.objects.create(huddle=huddle, user_id=participant_id, response="invited") + # Create huddle atomically + with transaction.atomic(): + huddle = SlackHuddle.objects.create( + creator_id=user_id, + workspace_id=team_id, + channel_id=channel_id, + title=title, + description=sanitized_description, + scheduled_at=scheduled_at, + status="scheduled", + ) + + # Add participants + for participant_id in participants: + SlackHuddleParticipant.objects.create(huddle=huddle, user_id=participant_id, response="invited")
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting
📒 Files selected for processing (8)
website/management/commands/process_slack_reminders_and_huddles.py(1 hunks)website/management/commands/run_ten_minutes.py(1 hunks)website/migrations/0264_slackhuddle_slackpoll_slackpolloption_slackreminder_and_more.py(1 hunks)website/models.py(2 hunks)website/tests/test_slack.py(2 hunks)website/tests/test_slack_blocks.py(1 hunks)website/tests/test_slack_scheduler.py(1 hunks)website/views/slack_handlers.py(9 hunks)
✅ Files skipped from review due to trivial changes (1)
- website/tests/test_slack_blocks.py
🧰 Additional context used
🧬 Code graph analysis (3)
website/tests/test_slack_scheduler.py (1)
website/models.py (5)
Integration(88-103)SlackHuddle(3799-3859)SlackHuddleParticipant(3862-3898)SlackIntegration(106-127)SlackReminder(3744-3796)
website/tests/test_slack.py (2)
website/views/slack_handlers.py (1)
slack_commands(457-1263)website/models.py (4)
SlackPoll(3651-3686)SlackBotActivity(2010-2036)SlackReminder(3744-3796)SlackHuddle(3799-3859)
website/management/commands/process_slack_reminders_and_huddles.py (1)
website/management/commands/run_ten_minutes.py (2)
Command(10-27)handle(13-27)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: Run Tests
- GitHub Check: docker-test
🔇 Additional comments (30)
website/management/commands/run_ten_minutes.py (1)
20-24: LGTM!The integration of the new Slack command follows the same error-handling pattern as the existing
cron_send_reminderscommand, logging errors without propagating exceptions to the outer handler.website/tests/test_slack.py (4)
2-2: LGTM!The
urllib.parseimport is used later in the test file (line 489) for encoding POST data.
319-416: LGTM!The poll command tests follow established patterns from earlier in the file. They correctly mock Slack API interactions and verify both database state (poll creation, options count, status) and activity logging.
419-520: LGTM!The reminder command tests verify both help and creation flows, with appropriate mocking of Slack API and assertions on database state (message, status, target_id) and activity logging.
523-619: LGTM!The huddle command tests cover help responses and creation, including participant tracking. The tests verify database state (title, description, status, participant count) and activity logging as expected.
website/models.py (6)
29-29: LGTM!The
escapeimport is correctly used later in the file at line 3787 in theSlackReminder.mark_as_failedmethod for sanitizing error messages.
3650-3687: LGTM!The
SlackPollmodel is well-structured with appropriate fields, indexes, and theclose_poll()helper method for status transitions.
3689-3722: LGTM!The custom
QuerySetwithwith_vote_count()annotation and thevote_countproperty provide efficient vote counting while avoiding N+1 queries when used correctly.
3744-3797: LGTM!The
SlackRemindermodel includes appropriate status transitions, helper methods (mark_as_sent,mark_as_failed,cancel), and usesescape()at line 3787 for safely storing error messages.
3799-3860: LGTM!The
SlackHuddlemodel provides status lifecycle methods (cancel,start,complete) with appropriate atomic updates usingfilter().update()to handle concurrency.
3862-3897: LGTM!The
SlackHuddleParticipantmodel correctly usesuser_id(notslack_id) and provides anupdate_responsemethod with proper validation againstVALID_RESPONSES.website/tests/test_slack_scheduler.py (4)
18-28: LGTM!The test setup creates appropriate fixtures (Organization, Integration, SlackIntegration) to support the Slack scheduler tests.
29-53: LGTM!The test verifies that a due user reminder is marked as "sent" in dry-run mode. The mock setup for Slack API responses is appropriate.
54-71: LGTM!The test verifies dry-run behavior for channel reminders, including the assertion that no actual API calls are made (
mock_post.assert_not_called()).
72-103: LGTM!The test verifies huddle pre-notifications and status transitions: upcoming huddles get
reminder_sent=Trueand past huddles transition tostatus="started", all in dry-run mode without actual API calls.website/management/commands/process_slack_reminders_and_huddles.py (8)
19-24: LGTM!Token sanitization removes carriage returns and line feeds to prevent header injection attacks.
27-55: LGTM!The function correctly checks for HTTP 429 (rate limit) before attempting JSON parsing, and returns the
Retry-Aftervalue for exponential backoff handling. The logic distinguishes between user IDs (requiring DM channel resolution) and channel IDs (used directly).
58-83: LGTM!The function correctly checks for rate limiting (429) before parsing JSON and returns the retry delay. Thread support via
thread_tsis also properly implemented.
86-102: LGTM!The helper functions for parsing retry counts and formatting error messages support the exponential backoff strategy.
104-127: LGTM!The command structure with configurable arguments (window-minutes, batch-size, dry-run) and per-workspace token resolution is well-designed.
128-188: LGTM!The reminder processing correctly:
- Uses
select_for_update(skip_locked=True)for concurrent safety- Resolves per-workspace tokens
- Escapes message content for Slack (replacing &, <, > with HTML entities as per Slack's requirements)
- Implements exponential backoff capped at MAX_RETRIES with support for Slack's Retry-After header
- Handles dry-run mode appropriately
189-242: LGTM!The huddle processing correctly:
- Uses
prefetch_related("participants")to avoid N+1 queries- Correctly accesses
user_idfrom participants (notslack_id)- Escapes title content for Slack message formatting
- Sends pre-notifications to both participants and channels
- Respects dry-run mode
243-255: LGTM!Huddle status transitions use
select_for_update(skip_locked=True)for safe concurrent processing and correctly mark scheduled huddles as "started" when their time arrives.website/views/slack_handlers.py (7)
3832-3838: Race condition fix looks correct.Using
get_or_createwithdefaultsis the right approach to atomically prevent duplicate votes. The unique constraint on(poll, voter_id)at the model level would provide additional protection.
3927-3931: Action ID parsing fix is correct.The logic now correctly maps
response="accepted"toaction_verb="accept"(and similarly for decline), matching the actual action IDs used inbuild_huddle_blocks.
3674-3675: Single query for participants is acceptable here.While
prefetch_relatedcould be used for batch operations, fetchinghuddle.participants.all()for a single huddle display is already efficient (one query). This is fine as-is.
3730-3734: Good use of annotation to avoid N+1 queries.Using
.annotate(participants_count=Count("participants"))is the right approach to efficiently get participant counts without additional queries per huddle.
1356-1380: Comprehensive Slack API error handling.Good coverage of common Slack API errors (rate limiting, auth issues, channel problems) with appropriate HTTP status codes and user-friendly messages.
3217-3228: Good vote counting optimization with annotation.Using
.annotate(votes_count=Count("votes"))avoids N+1 queries. The bar length calculation withmax(1, math.ceil(...))for non-zero votes ensures small percentages remain visible.
3855-3888: Consistent permission checking pattern across handlers.The
handle_poll_close,handle_reminder_cancel, andhandle_huddle_cancelfunctions all properly verify that only the creator can perform the action before modifying state.
|
@coderabbitai please run a detailed review of this PR and assess whether it completely implements the linked issue’s requirements (polls, reminders, and scheduling huddles), including edge cases, error handling, and test coverage. Highlight any missing functionality, potential bugs, or inconsistencies with the existing BLT Slack bot patterns so we can address them before merge. |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: Length of output: 165204 🏁 Script executed: Length of output: 9164 🏁 Script executed: Length of output: 11488 🏁 Script executed: Length of output: 11289 🏁 Script executed: Length of output: 21831 🏁 Script executed: Length of output: 287 🏁 Script executed: Length of output: 0 🏁 Script executed: Length of output: 389 @arnavkirti, I've completed a detailed review of PR #5334. Here's my assessment: ✅ Implementation Completeness: ~85%The PR successfully implements the core requirements from issue #2183, but there are several critical bugs, missing edge cases, and test coverage gaps that should be addressed before merge. 🐛 Critical Bugs1. Poll Single-Vote Enforcement is BrokenLocation: The Fix needed: # In SlackPollVote model
class Meta:
unique_together = ["poll", "voter_id"] # Prevent any duplicate votes per poll
# OR implement validation in handle_poll_vote to check existing votesIn # Before creating vote, check if user already voted
existing_vote = SlackPollVote.objects.filter(poll=poll, voter_id=user_id).first()
if existing_vote and not poll.allow_multiple_votes:
if existing_vote.option_id == option_id:
return JsonResponse({"response_type": "ephemeral", "text": "✅ You've already voted for this option."})
else:
# Update vote or return error
return JsonResponse({"response_type": "ephemeral", "text": "❌ You've already voted. Close and reopen the poll to change your vote."})2. Unused Model FieldsThe ❌ Missing Functionality1. No Edit/Update Capabilities
2. Limited Huddle Time ParsingReminders support "in X days" but huddles only support "in X hours" or "at HH:MM AM/PM". Should be consistent. 3. No Completion Tracking for HuddlesThe background processor marks huddles as "started" but never marks them as "completed" after 4. No Cross-Channel Reminder/Huddle Listing
5. No Data Cleanup/ArchivalOld polls, reminders, and huddles will accumulate indefinitely. Need a cleanup strategy or auto-archival.
|
| Category | Score | Notes |
|---|---|---|
| Feature Completeness | 85% | Core features work, missing edit/update |
| Error Handling | 70% | Good coverage but needs specificity |
| Test Coverage | 60% | Basic tests exist, missing interactions |
| Edge Case Handling | 50% | Many common edge cases unhandled |
| Code Quality | 80% | Clean, follows patterns, minor issues |
| Documentation | 70% | Good help messages, needs code comments |
Recommendation: Request changes - Fix critical poll voting bug and add interaction tests before merging. Medium/low priority items can be addressed in follow-up PRs.
|
@coderabbitai, please review this pull request and let me know if it is complete and ready to be merged. Specifically, check if all previous review comments have been addressed, if there are any remaining issues or potential regressions, and whether the implementation, tests, and documentation are sufficient for merge. |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: Length of output: 5217 🏁 Script executed: Length of output: 1239 @arnavkirti, I've completed a comprehensive final verification of PR #5334. Here's my assessment: ✅ APPROVED - READY TO MERGE🎯 All Previous Review Comments: 100% ADDRESSEDI've verified that all critical issues from 5 rounds of reviews have been resolved: ✅ Round 1-3 Issues (ALL FIXED)
✅ Round 4 (Nachiket) - ALL 6 CRITICAL SCHEDULER BUGS FIXED@arnavkirti, I've completed a comprehensive final verification of PR #5334 against all previous review comments. Here's my definitive assessment: ✅ APPROVED - READY TO MERGE🎉 All Previous Review Comments: 100% ADDRESSEDI've systematically verified that every critical issue from 5 rounds of reviews has been completely resolved: ✅ Critical Bugs from Rounds 1-3 (ALL FIXED)
✅ Nachiket's 6 Critical Scheduler Bugs (Round 4 - ALL FIXED)1. Dry-run Mutations ✅ FIXEDAll database saves properly guarded: if not options["dry_run"]:
r.save(update_fields=["status", "error_message"])7 guard instances confirmed - dry-run mode is now safe. 2. Transaction Locking with Network Calls ✅ FIXEDImplements 4-step process that releases locks before network calls:
This follows Django best practices where "skip_locked" allows processing to skip locked records and try the next one, preventing lock contention. 3. Unbounded Retry Loops ✅ FIXEDRetries now bounded by creation time: MAX_RETRY_AGE_DAYS = 7
if r.created_at and (timezone.now() - r.created_at).days > MAX_RETRY_AGE_DAYS:
r.status = "failed"Reminders older than 7 days stop retrying automatically. 4. Inconsistent User/Channel Detection ✅ FIXEDNow uses the if not options["dry_run"] and target_type == "user" and reminder.target_id:No more fragile string prefix checks. 5. Overzealous Huddle Cancellation ✅ FIXEDNo longer cancels on temporary failures - the code properly distinguishes between actual user-not-found (404) and rate-limiting/transient errors. 6. Model Methods for Status Transitions ✅ FIXEDConsistently uses model methods: h.cancel()
h.start()
h.complete()3 instances confirmed - maintains business logic consistency. 🧪 Test Coverage: EXCELLENT
Critical failure scenarios tested:
✅ Code Quality: EXCELLENT
📊 Feature Completeness: 100%All requirements from issue #2183 fully implemented: Polls✅ Create with 2-10 options | ✅ Real-time vote tracking | ✅ Single-vote enforcement | ✅ Poll closing | ✅ Progress bars Reminders✅ Create for self/others | ✅ Flexible time parsing | ✅ Paginated listing | ✅ Edit & snooze | ✅ Cancellation | ✅ Status lifecycle Huddles✅ Schedule meetings | ✅ Accept/decline tracking | ✅ 15-min pre-notifications | ✅ Timezone-aware display | ✅ Edit/reschedule | ✅ Completion tracking Background Processing✅ Management command | ✅ Dry-run mode | ✅ Proper lock management | ✅ Exponential backoff | ✅ Rate-limit handling | ✅ Per-workspace tokens Data Lifecycle✅ Cleanup command | ✅ 90-day retention | ✅ Dry-run support 🎯 No Regressions Detected
🚀 Final Recommendation✅ APPROVE AND MERGE IMMEDIATELY This PR is production-ready and has successfully addressed:
The implementation is complete, well-tested, secure, and follows Django best practices. There are no blocking issues remaining. Optional enhancements for future PRs (non-blocking):
Excellent work on this comprehensive implementation! 🎉 |
|
⏰ This issue has been automatically unassigned from coderabbitai[bot] due to 24 hours of inactivity. The issue is now available for anyone to work on again. This comment was generated by OWASP BLT-Action |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 12 out of 12 changed files in this pull request and generated 5 comments.
website/migrations/0264_slackintegration_workspace_id_slackhuddle_slackpoll_and_more.py
Show resolved
Hide resolved
|
@arnavkirti Can you please test it locally, by creating a channel in your own slack worspace, and check if its working fine there. You can also attach the screeshot of response. |
Resolves #2183
Summary: Slack Bot Commands Feature - Complete Implementation ✅
Features Implemented
1. Slack Poll Command (
/blt_poll)2. Slack Reminder Command (
/blt_remind)<!date^...>tokens/blt_remind list [page])3. Slack Huddle Command (
/blt_huddle)4. Background Processing (
process_slack_reminders_and_huddles)Robust Reminder Processing:
select_for_update(skip_locked)Retry-After)SlackIntegrationHuddle Notifications:
Testing Coverage
Created comprehensive test suites:
test_slack.py - Handler tests for commands
test_slack_scheduler.py - Background processor tests
test_slack_blocks.py - Block builder tests
All 20 tests pass successfully! ✅
Code Quality
Key Technical Improvements
Summary by CodeRabbit
New Features
Admin
Background Tasks
Templates
Data Model
Tests
✏️ Tip: You can customize this high-level summary in your review settings.