- Added management commands to create podcast and video categories in Russian, ensuring a structured categorization system.
- Updated podcast and video playlist creation commands to associate playlists with the newly created categories.
- Enhanced documentation to reflect the new category creation process and its integration into the podcast and video systems.
- Introduced new models for PodcastPlaylist and VideoPlaylist, replacing the outdated PodcastInCollection and VideoInCollection models.
- Updated admin interfaces to manage playlists effectively, including new fields for slug, slogan, description, and thumbnail.
- Enhanced serializers to support playlist data and added methods for calculating total time and retrieving associated videos/podcasts.
- Implemented management commands for creating playlists and cleaning up old data, ensuring a streamlined user experience.
- Adjusted API endpoints to accommodate the new playlist structure while maintaining backward compatibility for existing video endpoints.
- Introduced a new service choice 'Article' to the Bookmark model.
- Updated the database migration to reflect the new service choice in the 'service' field of the Bookmark model.
- Enhanced the service validation logic to include checks for the new 'Article' service type.
- Updated `ArticleCollectionAdminBase` and `PodcastCollectionAdminBase` to include a new `get_display_position` method for better visual distinction between pinned and regular collections.
- Modified verbose names for `PinnedArticleCollection` and `MiddleArticleCollection` to clarify their purpose in the admin interface.
- Added a new README for podcast collections to provide guidance on managing collections and highlight key differences between pinned and regular collections.
- Updated settings to improve sidebar navigation for article and podcast collections, ensuring clear access to both collection types.
- Introduced a new `DownloadedBooksListView` to retrieve books downloaded by the current user.
- Updated `urls.py` to include the new endpoint `/books/downloaded/`.
- Removed the `is_downloaded` parameter from the `BookListView` to streamline the book listing process.
- Simplified the bookmark creation process by using request data directly in the serializer.
- Introduced a new `perform_create` method to save the user context during bookmark creation.
- Enhanced the book listing functionality to filter books by download status for the current user, using a new query parameter `is_downloaded`.
- Introduced a new SerializerMethodField `saved_location` to retrieve the user's last known location from their location history.
- Updated the fields and read_only_fields in UserProfileSerializer to include `saved_location` for enhanced user profile data.
- Adjusted permission classes in CalendarList and AdjustmentConfigView to AllowAny for broader access.
- Introduced UploadChatMedia and UploadChatMediaSerializer to handle permanent file uploads to /media/chat/.
- Updated urls.py to include a new endpoint for chat media uploads.
- Enhanced file handling with thumbnail generation for images and videos.
- Adjusted UploadTmpSerializer to maintain existing temporary upload functionality.
- Add avatar field to ProfessorListSerializer using FileFieldSerializer for better avatar handling.
- Update room ID generation in CourseLiveSessionRoomCreateAPIView to use a consistent format.
- Introduce debug logging in PlugNMeetClient for room creation payload to aid in troubleshooting.
- Introduced `file_attachment` and `image_attachment` fields to the ChatMessage model with appropriate upload paths.
- Updated ChatMessageAdmin to display attachment status and previews in the admin interface.
- Added utility functions for thumbnail generation and video frame extraction.
- Created a migration to add new fields to the database.
- Enhanced UploadTmpSerializer to include thumbnail URL generation for uploaded images and videos.
Extend recording_features in live session room creation to include:
- is_allow_local for enabling local recording
- only_record_admin_webcams to control recording scope
Defaults set to True for local recording and False for admin-only webcams
- add recorded_file FileField to CourseLiveSession with migration
- add serializers for recording upload and metadata
- add PATCH endpoint to create a recording for latest session:
/<int:course_id>/live-sessions/recorded-file/
- enforce can_manage_course permission and return recording metadata
- update urls and views; use FileFieldSerializer for file handling
Change the room ID format in CourseLiveSessionRoomCreateAPIView to use the course ID and a static string instead of a timestamp. This ensures consistent room IDs for live sessions.
Introduce PlugNMeetWebhookAPIView to handle:
- room_finished: close live session and mark users offline
- participant_joined: create/reactivate LiveSessionUser
- participant_left: mark user offline with exit timestamp
- end_recording: fetch info, obtain token, download file, save
LiveSessionRecording, and generate video thumbnails via ffmpeg
Add new PlugNMeetClient methods:
- get_recording_info
- get_recording_download_token
- download_file
Expose webhook route at /api/course/plugnmeet/webhook/ with HMAC
SHA256 signature verification (Hash-Token header).
Deprecate polling-based room status sync in
CourseOnlineClassTokenValidateAPIView in favor of webhooks.
build(docker): add ffmpeg to production image for thumbnail generation
docs: add webhook setup and usage guides (README_WEBHOOK.md,
docs/plugnmeet_webhook.md)
chore(scripts): add create_live_room.sh and scripts/test_webhook.py for
manual testing and workflow support
Return an absolute URI for the avatar in live session token
metadata so external services (e.g., PlugNMeet) can fetch the
image reliably. Add debug logging to PlugNMeet client POST
requests and info logging for the resolved profile picture URL
to aid troubleshooting.
Use avatar.url directly to avoid duplicating the host when the
storage returns an absolute URL. Prevents malformed avatar links
in live session token responses.
- Remove `metadata` from LiveSessionRoomCreateSerializer and ignore any
client-provided `metadata` for security (with warning log)
- Build secured room metadata server-side with explicit default lock
settings (mic/webcam/screen share locked; whiteboard/notepad/chat
unlocked) and comprehensive room features (chat, recording, breakout,
waiting room, etc.)
- Convert all request payload keys to camelCase before calling PlugNMeet
for both room creation and join token to match protocol requirements
- Extend non-admin user lock_settings in join token to include
whiteboard/notepad/chat controls
- Update live-session docs and add comprehensive PlugNMeet API docs
BREAKING CHANGE: Clients must no longer send `metadata` when creating a
room; all room settings are now enforced server-side and cannot be
overridden by the client. The serializer no longer accepts `metadata`.
Poll PlugNMeet for room activity during online class token validation
and close inactive sessions, updating related LiveSessionUser entries.
Add PlugNMeetClient.is_room_active and improve error handling to raise
PlugNMeetError when response status is false. Includes logging and TODO
for future webhook-based sync.
Introduce ExchangeTokenAPIView at /api/account/exchange-token/ to
exchange temporary tokens for a DRF auth token and minimal user
profile (id, fullname, email, avatar). Tokens are one-time use and
validated via OnlineClassTokenManager. Added serializer, view, URL,
and Swagger examples.
Update CourseOnlineClassTokenAPIView to return a fixed join URL:
https://imamjavad.newhorizonco.uk/join-class?token={TOKEN}&slug={SLUG}.
Store course_slug in token payload and remove redirect_path and the
_base_components helper. Examples and docs updated.
Docs: add CHANGELOG_EXCHANGE_TOKEN.md and exchange_token_api.md;
update online_class_entry_flow.md.
BREAKING CHANGE: exchange-token endpoint moved from
/api/courses/auth/exchange-token/ to /api/account/exchange-token/.
Response shape changed: adds token, user.id is numeric, user.name
renamed to user.fullname, user.role and user.is_admin removed.
Online token response now returns a fixed URL and includes course
slug. redirect_path support removed; clients must use the returned
token for subsequent requests.
- add CourseLiveSession.room_id field with unique index
- introduce LiveSessionRoomCreateSerializer and LiveSessionTokenSerializer
- add URLs for room creation and token:
- <slug>/online/room/create
- online/room/token
- enhance token validation metadata with:
- can_create_live_session, can_join_live_session flags
- live session context (active_room_id, timings, details)
- improve logging and token error handling in validation flow
- add PlugNMeet configuration settings (URL, API key/secret, timeout)
This introduces the endpoints and data structures needed to create and
join live sessions, and surfaces richer metadata for frontend usage. A
database migration is required for the new model field and index.
- change URL pattern to use <slug:slug> instead of <int:pk>
- update view signature and swagger parameter to slug
- fetch course by slug to match detail endpoint
- ensures consistent API across course endpoints
BREAKING CHANGE: the online validate endpoint now uses slug instead of pk; clients must update the path parameter from integer pk to string slug
- add route for <int:pk>/online/validate/ to token validate view
- implement authenticated GET returning course, user and metadata
- enforce auth only for GET via get_permissions
- add Swagger docs for the new endpoint
No breaking changes.
Use request.build_absolute_uri('/') to derive the base domain instead
of relying on ONLINE_CLASS_FRONTEND_DOMAIN/SITE_DOMAIN. This produces
correct entry URLs based on the incoming request.
Add ONLINE_CLASS_DEFAULT_PATH (default: 'join-class') as a fallback
when redirect_path is not provided.
Update the view to pass request to _build_base_url.
- create CourseLiveSession, LiveSessionUser, LiveSessionRecording with
indexes and unique constraints
- register new models in admin and add UNFOLD navigation entries
- update token validation to derive is_online and include
livesession_started_at, livesession_ended_at, and can_start_online_class
- extend online class entry flow documentation with new fields
- add migration for new live session tables
- Created a new markdown file for the online class entry flow, detailing the process for obtaining and validating tokens for online classes.
- Added a new HTML file for the prayer times calculation guide, including detailed explanations, code examples, and styling.
- Updated the multilang JSON widget HTML and Python files to include additional spacing for readability.
- Implemented a new `OnlineClassTokenManager` class in the Redis utility module to handle the generation, storage, retrieval, and deletion of temporary tokens for online classes, including methods for building entry URLs.
- Introduced a new endpoint for web user registration at 'web/register/'.
- Created WebUserRegisterSerializer to handle user registration with email and password validation.
- Enhanced UserVerifyView to support password handling during user creation and verification.
- Enhanced UserVerifyView to set user passwords securely during account creation and takeover.
- Removed the use of unusable passwords, ensuring all users have functional passwords upon verification.
- Updated UserProfileSerializer to handle password updates securely by hashing new passwords.
- Modified UserVerifyView to improve user creation and account takeover logic, ensuring unusable passwords are set for new and converted guest accounts.
- Updated UserRegisterSerializer to make device_id write-only and handle its assignment during user creation.
- Implemented email normalization in UserRegisterSerializer, UserVerifySerializer, and UserLoginSerializer to ensure case-insensitive uniqueness.
- Refactored UserRecoverPasswordSerializer to validate email format without checking for database uniqueness.
- Modified the unique_together constraint for the User model to only require uniqueness on the email field, removing device_id from the constraints.
- Added a migration to apply this change to the database schema.
- Changed device_id field in UserRegisterSerializer to be optional.
- Updated UserVerifyView to handle device_id more gracefully, allowing for None values and adjusting user creation logic accordingly.
- Altered the thumbnail field in the Course model to remove null and blank options, making it mandatory.
- Added a migration to reflect this change in the database schema.
- Made thumbnail field required in CourseForm.
- Added validation to prevent clearing existing thumbnail.
- Enforced requirement for uploading a thumbnail on creation or when no existing thumbnail is present.