Skip to content

[BACKEND] Notification API endpoints + course invitation signal #279

Description

@smattymatty

Claiming This Task

Before you start working, check the Assignees section. If no one is assigned, leave a comment claiming the issue and assign it to yourself. This prevents duplicate work.

See the Community Wiki for contributing guidelines and git workflow.

Problem

The notification system has a model (notifications/models.py) and signals for friend requests and chat invitations, but:

  1. No API endpoints — there are no views or URLs registered for notifications, so the frontend cannot list, read, or manage notifications
  2. No course invitation notification — when a teacher invites a user to a course (creating a CourseMembership with status="invited"), no notification is created. The invited user has no way to know they were invited unless they happen to visit the course page
  3. Missing notification typeCOURSE_INVITATION is not in NOTIFICATION_TYPE_CHOICES (only FRIEND_REQUEST, CHAT_INVITE, NEW_MESSAGE, SYSTEM_ANNOUNCEMENT exist)

Requirements

1. Add COURSE_INVITATION notification type

  • Add ("COURSE_INVITATION", "Course Invitation") to NOTIFICATION_TYPE_CHOICES in notifications/models_choices.py
  • Generate and apply migration

2. Create course invitation signal

  • Add a post_save signal on CourseMembership (or hook into the invite view) that creates a notification when a membership is created with status="invited"
  • Notification fields:
    • recipient: the invited user
    • actor: the teacher who sent the invite
    • verb: e.g. "invited you to the course '{course.title}'"
    • notification_type: "COURSE_INVITATION"
    • target: the CourseMembership instance (via GenericForeignKey)
  • Follow the same defensive pattern as users/signals.py (try/except to prevent signal from breaking the main operation)

3. Build notification API endpoints

Following existing DRF patterns (users/views.py as reference):

Method URL Description
GET /api/notifications/ List current user's notifications (paginated, newest first)
GET /api/notifications/unread-count/ Return { "count": N } for the navbar badge
PATCH /api/notifications/<id>/ Mark a single notification as read ({ "is_read": true })
POST /api/notifications/mark-all-read/ Mark all of the current user's notifications as read
DELETE /api/notifications/<id>/ Delete a single notification
  • All endpoints require authentication (IsAuthenticated)
  • Users can only access their own notifications
  • List endpoint should support filtering by is_read and notification_type query params

4. Register URLs

  • Add path("notifications/", include("notifications.urls")) to EduLite/urls.py

Architecture Context

  • Existing pattern: users/signals.py lines 47-100 show how friend request notifications are created via post_save signal with defensive error handling
  • Existing pattern: chat/signals.py lines 1-11 show the chat invitation notification signal
  • Notification model: notifications/models.py — already has recipient, actor, verb, notification_type, is_read, target (GenericForeignKey), description, created_at
  • Serializer: notifications/serializers.pyNotificationSerializer is already built (read-only), includes target_details method for the GenericForeignKey
  • Views file: notifications/views.py exists but is empty
  • Course invite view: courses/views.py CourseMembershipListInviteView.post() (line ~705) creates the membership — this is where the signal would fire from

Files to be Altered

File Change
notifications/models_choices.py Add COURSE_INVITATION type
notifications/views.py Build all API views
notifications/urls.py Define URL patterns
notifications/serializers.py May need a write serializer for mark-as-read
notifications/permissions.py Create IsNotificationOwner permission (optional, can check in view)
courses/signals.py New file — post_save signal for course invitation notification
courses/apps.py Register signal import in ready()
EduLite/urls.py Register notifications/ URL include
Migration New migration for COURSE_INVITATION choice addition

Testing Requirements

Unit tests (notifications/tests/)

  • Signal tests: Verify notification is created when CourseMembership is saved with status="invited", verify it is NOT created for status="enrolled" or status="pending"
  • List endpoint: Verify pagination, ordering (newest first), filtering by is_read and notification_type, verify users only see their own notifications
  • Unread count endpoint: Verify correct count, verify it updates after marking as read
  • Mark as read: Verify single notification, verify mark-all-read
  • Delete: Verify deletion, verify users cannot delete other users' notifications
  • Permissions: Verify 401 for unauthenticated, verify users cannot access others' notifications

Additional Context (Optional)

  • The frontend notification bell icon already links to /notifications but the page is empty — frontend work depends on this issue being completed first
  • The EnrollmentActions component already detects status="invited" and renders accept/decline buttons (currently disabled) — those buttons are a separate frontend issue and don't depend on this one
  • Existing notification tests are in notifications/tests/test_Notifications.py (model-only tests)

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions