-
-
Notifications
You must be signed in to change notification settings - Fork 231
Add entity_channel field to Reminder model and remove channel_id #2399
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: feature/nestbot-calendar-events
Are you sure you want to change the base?
Add entity_channel field to Reminder model and remove channel_id #2399
Conversation
Summary by CodeRabbit
WalkthroughRefactors reminder/calendar flow to use EntityChannel and GoogleCalendarClient: replaces Reminder.channel_id with entity_channel, updates scheduler APIs to use entity_channel PKs, changes Slack handlers/commands to be workspace-aware, adds migrations, and updates tests and admin UI accordingly. Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Pre-merge checks and finishing touches❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (3 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 |
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: 6
🧹 Nitpick comments (1)
backend/apps/slack/common/handlers/calendar_events.py (1)
121-154
: Consider using get_or_create for EntityChannel.The current implementation uses
EntityChannel.objects.get()
which will raiseDoesNotExist
if the channel association doesn't exist. The error message "is not linked to your account" suggests users should link channels first, but it's unclear how users perform this linking.Consider whether
EntityChannel.objects.get_or_create()
would be more appropriate to automatically establish the link when a user sets a reminder for a channel they have access to:channel, created = EntityChannel.objects.get_or_create( channel_id=conversation.pk, channel_type=content_type_conversation, entity_id=member.pk, entity_type=content_type_member, defaults={ 'platform': EntityChannel.Platform.SLACK, 'is_active': True, } )If manual linking is required, ensure documentation or UI guidance explains the linking process.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
backend/poetry.lock
is excluded by!**/*.lock
📒 Files selected for processing (10)
backend/apps/nest/handlers/calendar_events.py
(3 hunks)backend/apps/nest/migrations/0014_remove_reminder_channel_id_reminder_entity_channel.py
(1 hunks)backend/apps/nest/models/reminder.py
(2 hunks)backend/apps/nest/schedulers/calendar_events/base.py
(3 hunks)backend/apps/nest/schedulers/calendar_events/slack.py
(1 hunks)backend/apps/owasp/migrations/0055_merge_20251008_1253.py
(1 hunks)backend/apps/slack/admin/entity_channel.py
(0 hunks)backend/apps/slack/commands/command.py
(1 hunks)backend/apps/slack/commands/nestbot.py
(1 hunks)backend/apps/slack/common/handlers/calendar_events.py
(2 hunks)
💤 Files with no reviewable changes (1)
- backend/apps/slack/admin/entity_channel.py
🧰 Additional context used
🧬 Code graph analysis (5)
backend/apps/slack/commands/nestbot.py (2)
backend/apps/slack/common/handlers/calendar_events.py (1)
get_setting_reminder_blocks
(107-181)backend/apps/slack/commands/command.py (2)
get_user_id
(78-88)get_workspace_id
(90-100)
backend/apps/nest/handlers/calendar_events.py (3)
backend/apps/owasp/models/entity_channel.py (1)
EntityChannel
(8-66)backend/apps/owasp/models/event.py (1)
Event
(25-378)backend/apps/nest/clients/google_calendar.py (1)
GoogleCalendarClient
(9-42)
backend/apps/nest/schedulers/calendar_events/base.py (1)
backend/apps/nest/schedulers/calendar_events/slack.py (2)
send_message
(13-21)send_and_update
(24-27)
backend/apps/slack/common/handlers/calendar_events.py (7)
backend/apps/nest/clients/google_calendar.py (1)
GoogleCalendarClient
(9-42)backend/apps/nest/handlers/calendar_events.py (2)
get_calendar_id
(15-22)set_reminder
(44-86)backend/apps/nest/models/google_account_authorization.py (2)
GoogleAccountAuthorization
(28-225)authorize
(55-93)backend/apps/nest/schedulers/calendar_events/slack.py (1)
SlackScheduler
(9-27)backend/apps/owasp/models/entity_channel.py (1)
EntityChannel
(8-66)backend/apps/slack/models/conversation.py (1)
Conversation
(15-104)backend/apps/slack/blocks.py (1)
markdown
(21-34)
backend/apps/nest/schedulers/calendar_events/slack.py (3)
backend/apps/owasp/models/entity_channel.py (1)
EntityChannel
(8-66)backend/apps/slack/apps.py (1)
SlackConfig
(13-26)backend/apps/nest/schedulers/calendar_events/base.py (3)
BaseScheduler
(9-64)send_message
(55-58)send_and_update
(61-64)
⏰ 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 frontend e2e tests
- GitHub Check: Run frontend unit tests
- GitHub Check: Run backend tests
- GitHub Check: CodeQL (python)
🔇 Additional comments (13)
backend/apps/owasp/migrations/0055_merge_20251008_1253.py (2)
1-1
: Ignore Django version discrepancy. Migrations are generated with Django 5.2.x, and the project’s pyproject.toml and lock file specify Django ^5.2 (currently 5.2.7), so the metadata aligns.Likely an incorrect or invalid review comment.
6-12
: Merge migration verified — parent migrations exist. Both dependencies (0053_merge_20250918_1659 and 0054_event_event_end_date_desc_idx) are present; no further action required.backend/apps/nest/schedulers/calendar_events/base.py (1)
55-61
: LGTM!The parameter type change from
str
toint
forchannel_id
is correct and aligns with the migration to useEntityChannel.pk
.backend/apps/slack/commands/command.py (1)
90-100
: LGTM!The new
get_workspace_id
method follows the same pattern asget_user_id
and correctly extracts the workspace ID from the Slack command payload.backend/apps/slack/commands/nestbot.py (1)
33-35
: LGTM!The updated call correctly passes the workspace ID using the newly added
get_workspace_id
method, aligning with the expanded function signature.backend/apps/nest/schedulers/calendar_events/slack.py (2)
5-5
: LGTM!The import of
EntityChannel
is necessary for the new implementation.
24-27
: LGTM!The updated signature correctly accepts
channel_id: int
and delegates to the updatedsend_message
method.backend/apps/slack/common/handlers/calendar_events.py (3)
107-118
: LGTM!The updated function signature and new imports correctly support the EntityChannel-based flow and Google Calendar integration.
156-166
: LGTM!The exception handling provides clear, user-friendly error messages for various failure scenarios.
167-181
: LGTM!The return logic correctly prioritizes error messages and provides a comprehensive success message with all reminder details.
backend/apps/nest/handlers/calendar_events.py (3)
15-22
: LGTM!The
get_calendar_id
function correctly retrieves and validates the cached Google Calendar ID, raising an appropriate error for invalid or expired event numbers.
44-52
: LGTM!The updated function signature correctly reflects the shift to EntityChannel-based channels and direct client/member passing, removing the need for internal lookups.
54-86
: LGTM!The validation logic and reminder creation flow correctly use the new
entity_channel
parameter. Theget_or_create
call properly usesentity_channel=channel
instead of the oldchannel_id
.
backend/apps/nest/migrations/0014_remove_reminder_channel_id_reminder_entity_channel.py
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
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
backend/apps/slack/common/handlers/calendar_events.py (1)
107-181
: Fix conversation lookup before landing.
Conversation.objects.get(name=args.channel.lstrip("#"), workspace__slack_workspace_id=workspace_id)
assumes the CLI is passing a channel name. The previous flow worked withchannel_id
, and Slack slash commands typically deliver the stable channel ID (e.g.,C12345
). If a user supplies the ID—as they do today—this query will raiseConversation.DoesNotExist
, and the reminder flow always fails with "Channel 'C12345' does not exist in this workspace." We should keep resolving by the Slack ID (and still trim a leading#
for name input as a fallback) to avoid breaking the existing command.Apply something along these lines to restore ID support:
- conversation = Conversation.objects.get( - name=args.channel.lstrip("#"), - workspace__slack_workspace_id=workspace_id, - ) + channel_lookup = args.channel.lstrip("#") + conversation = Conversation.objects.filter( + workspace__slack_workspace_id=workspace_id, + ).filter( + models.Q(slack_channel_id=channel_lookup) + | models.Q(name__iexact=channel_lookup) + ).first() + if not conversation: + raise Conversation.DoesNotExist(You can still tighten the fallback, but we need to honor the Slack ID path before merging.)
♻️ Duplicate comments (1)
backend/apps/nest/schedulers/calendar_events/slack.py (1)
3-31
: Handle missing EntityChannel rows so jobs don’t crash.If the channel is deleted after scheduling, Line 15 raises
EntityChannel.DoesNotExist
, causing the RQ job to fail and the reminder never to be cleaned up. Please guard the lookup and log before returning so the worker keeps running.+import logging + from apps.nest.schedulers.calendar_events.base import BaseScheduler from apps.nest.utils.calendar_events import update_reminder_schedule_date from apps.owasp.models.entity_channel import EntityChannel from apps.slack.apps import SlackConfig + +logger = logging.getLogger(__name__) @staticmethod def send_message(message: str, channel_id: int): """Send message to the specified Slack channel.""" - entity_channel = EntityChannel.objects.get(pk=channel_id) + try: + entity_channel = EntityChannel.objects.get(pk=channel_id) + except EntityChannel.DoesNotExist: + logger.warning("EntityChannel pk=%s not found; skipping send.", channel_id) + return
🧹 Nitpick comments (2)
backend/tests/apps/slack/common/handlers/calendar_events_test.py (1)
173-241
: Consider adding a Slack-ID case after the fix.Once the handler resolves channels by Slack ID again, it’d be great to extend this suite with an argument like
channel="C12345"
to lock in that regression guard.backend/tests/apps/nest/schedulers/calendar_events/slack_test.py (1)
27-38
: Align test inputs with integer channel IDs.Production code now calls
SlackScheduler.send_and_delete()
with anEntityChannel
primary key (int). Keeping"C123456"
here masks type mismatches and would let the test pass even if we regressed back to string IDs. Please swap both the invocation and the expectation to use an int (e.g.,5
) so the test exercises the real contract.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (11)
backend/apps/nest/migrations/0015_alter_reminder_entity_channel.py
(1 hunks)backend/apps/nest/models/reminder.py
(2 hunks)backend/apps/nest/schedulers/calendar_events/base.py
(2 hunks)backend/apps/nest/schedulers/calendar_events/slack.py
(1 hunks)backend/apps/slack/common/handlers/calendar_events.py
(4 hunks)backend/tests/apps/nest/handlers/calendar_events_test.py
(9 hunks)backend/tests/apps/nest/models/reminder_schedule_test.py
(4 hunks)backend/tests/apps/nest/models/reminder_test.py
(2 hunks)backend/tests/apps/nest/schedulers/calendar_events/base_test.py
(5 hunks)backend/tests/apps/nest/schedulers/calendar_events/slack_test.py
(1 hunks)backend/tests/apps/slack/common/handlers/calendar_events_test.py
(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- backend/apps/nest/models/reminder.py
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-09-10T15:32:12.688Z
Learnt from: ahmedxgouda
PR: OWASP/Nest#2211
File: backend/apps/nest/controllers/calendar_events.py:0-0
Timestamp: 2025-09-10T15:32:12.688Z
Learning: In the backend/apps/nest/controllers/calendar_events.py file, the scheduled_time parameter in the schedule_reminder function is guaranteed to be timezone-aware, so explicit timezone awareness validation is not needed.
Applied to files:
backend/apps/nest/schedulers/calendar_events/base.py
🧬 Code graph analysis (9)
backend/tests/apps/nest/models/reminder_test.py (2)
backend/apps/owasp/models/entity_channel.py (1)
EntityChannel
(8-66)backend/apps/nest/models/reminder.py (1)
Reminder
(6-38)
backend/tests/apps/nest/schedulers/calendar_events/slack_test.py (1)
backend/apps/nest/schedulers/calendar_events/slack.py (3)
SlackScheduler
(9-37)send_message
(13-21)send_and_delete
(24-31)
backend/tests/apps/nest/handlers/calendar_events_test.py (6)
backend/apps/nest/handlers/calendar_events.py (3)
get_calendar_id
(15-22)schedule_reminder
(25-41)set_reminder
(44-86)backend/apps/nest/models/reminder.py (1)
Reminder
(6-38)backend/apps/nest/models/reminder_schedule.py (1)
ReminderSchedule
(6-66)backend/apps/owasp/models/entity_channel.py (1)
EntityChannel
(8-66)backend/apps/owasp/models/event.py (1)
Event
(25-378)backend/apps/nest/clients/google_calendar.py (1)
get_event
(38-42)
backend/apps/nest/schedulers/calendar_events/base.py (1)
backend/apps/nest/schedulers/calendar_events/slack.py (3)
send_and_delete
(24-31)send_and_update
(34-37)send_message
(13-21)
backend/apps/slack/common/handlers/calendar_events.py (7)
backend/apps/nest/clients/google_calendar.py (1)
GoogleCalendarClient
(9-42)backend/apps/nest/handlers/calendar_events.py (2)
get_calendar_id
(15-22)set_reminder
(44-86)backend/apps/nest/models/google_account_authorization.py (2)
GoogleAccountAuthorization
(28-225)authorize
(55-93)backend/apps/nest/schedulers/calendar_events/slack.py (1)
SlackScheduler
(9-37)backend/apps/owasp/models/entity_channel.py (1)
EntityChannel
(8-66)backend/apps/slack/models/conversation.py (1)
Conversation
(15-104)backend/apps/slack/blocks.py (1)
markdown
(21-34)
backend/tests/apps/nest/models/reminder_schedule_test.py (2)
backend/apps/owasp/models/entity_channel.py (1)
EntityChannel
(8-66)backend/apps/nest/models/reminder.py (1)
Reminder
(6-38)
backend/tests/apps/nest/schedulers/calendar_events/base_test.py (2)
backend/apps/nest/schedulers/calendar_events/base.py (3)
BaseScheduler
(8-64)send_and_delete
(55-58)send_and_update
(61-64)backend/apps/nest/schedulers/calendar_events/slack.py (2)
send_and_delete
(24-31)send_and_update
(34-37)
backend/tests/apps/slack/common/handlers/calendar_events_test.py (4)
backend/apps/nest/models/reminder_schedule.py (1)
ReminderSchedule
(6-66)backend/apps/nest/models/google_account_authorization.py (1)
GoogleAccountAuthorization
(28-225)backend/tests/apps/slack/commands/slack_sync_messages_test.py (2)
mock_member
(58-62)mock_conversation
(49-55)backend/apps/slack/common/handlers/calendar_events.py (1)
get_setting_reminder_blocks
(107-181)
backend/apps/nest/schedulers/calendar_events/slack.py (4)
backend/apps/owasp/models/entity_channel.py (1)
EntityChannel
(8-66)backend/apps/slack/apps.py (1)
SlackConfig
(13-26)backend/apps/nest/schedulers/calendar_events/base.py (4)
BaseScheduler
(8-64)send_message
(49-52)send_and_delete
(55-58)send_and_update
(61-64)backend/apps/nest/models/reminder_schedule.py (1)
ReminderSchedule
(6-66)
⏰ 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). (1)
- GitHub Check: Run frontend e2e tests
🔇 Additional comments (10)
backend/tests/apps/nest/handlers/calendar_events_test.py (4)
24-40
: Cache interactions covered well.Happy to see the cache-hit/miss paths asserted with the exact key format and error messaging.
41-101
: Comprehensive happy-path exercise.The stacked patches model the transactional flow end-to-end and assert each critical call, which gives strong coverage of the new EntityChannel path.
102-200
: Input validation scenarios look solid.Great job capturing each failure mode (minutes_before, missing event, past reminder, bad recurrence) and asserting on the raised messages.
201-284
: schedule_reminder coverage remains tight.The success path and both guard-rail checks (past time, invalid recurrence) are exercised cleanly with the updated Reminder payload.
backend/apps/slack/common/handlers/calendar_events.py (2)
12-30
: Nice UX refinement.Referencing
entity_channel.channel.name
makes the cancellation message far clearer than surfacing a raw identifier.
83-104
: Reminder listings read better.Surfacing the resolved channel name keeps the Slack copy human-friendly—good polish.
backend/tests/apps/slack/common/handlers/calendar_events_test.py (2)
130-159
: 👍 Reminder listing test stays meaningful.The MagicMock scaffolding keeps the assertions on channel names and ordering intact after the entity_channel switch.
242-377
: Error handling coverage looks thorough.Each of the raised exception paths (ValidationError, ValueError, ServerNotFoundError) now has a focused test, which keeps the Slack copy stable.
backend/apps/nest/migrations/0015_alter_reminder_entity_channel.py (1)
1-24
: Migration aligns with model.The AlterField mirrors the model definition (CASCADE + related_name) and depends on the right upstream migrations.
backend/tests/apps/nest/models/reminder_test.py (1)
1-35
: Model tests keep pace.Switching to the EntityChannel fixture keeps the string/verbose-name assertions relevant after the model change.
Proposed change
Resolves #2390
Add the PR description here.
Checklist
make check-test
locally; all checks and tests passed.