-
-
Notifications
You must be signed in to change notification settings - Fork 251
[feature] Added WebSocket endpoint which broadcasts all location updates #1161
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
[feature] Added WebSocket endpoint which broadcasts all location updates #1161
Conversation
61709be to
f843054
Compare
Implemented a new websocket endpoint 'location/all/' with updated user permission from base clases from django-loci. Fixes #1157
f843054 to
75476f6
Compare
d6a09ed to
ade9399
Compare
ade9399 to
9697b8b
Compare
Updates
Build on top of openwisp/django-loci#193 |
0e91107 to
f0f5305
Compare
pandafy
left a 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.
LGTM! Requires final testing with openwisp-monitoring.
requirements.txt
Outdated
| # Todo: Make path https://github.com/openwisp/django-loci/archive/refs/heads/1.3.tar.gz before merge | ||
| django-loci @ https://github.com/openwisp/django-loci/tarball/feature/191-new-ws-endpoint-for-all-location |
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.
TODO: Remove this when openwisp/django-loci#193 is merged.
.github/workflows/ci.yml
Outdated
| # Todo: Remove before merge | ||
| pip install --no-cache-dir --force-reinstall \ | ||
| "django-loci @ https://github.com/openwisp/django-loci/tarball/feature/191-new-ws-endpoint-for-all-location" |
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.
TODO: Remove before merging!
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
📝 WalkthroughWalkthroughThis pull request introduces a new WebSocket broadcast endpoint for location updates with organization-based access control. The changes include: (1) a signal receiver in the Geo app that sends location updates via WebSocket when Location instances are saved, (2) a new Sequence Diagram(s)sequenceDiagram
participant Location as Location Model
participant Signal as Django Signal
participant WS as WebSocket Layer
participant Group as Channel Group
participant User as Connected User
Location->>Signal: post_save (exclude creation, has geometry)
Signal->>WS: Send message (id, geometry, address, name, type, is_mobile)
WS->>Group: Broadcast to organization groups
Group->>User: Deliver update to subscribed users
sequenceDiagram
participant User as User (Connect)
participant Consumer as CommonLocationBroadcast
participant Auth as Authorization Check
participant Layer as Channel Layer
participant Group as Channel Group
User->>Consumer: WebSocket Connect
Consumer->>Auth: Check if superuser
alt Is Superuser
Auth->>Layer: Subscribe to all locations group
Layer->>Group: Add to loci.common-location
else Is Organization Manager
Auth->>Consumer: Get managed organizations
loop For each organization
Consumer->>Layer: Subscribe to org-specific group
Layer->>Group: Add to loci.mobile-location.organization.{org_id}
end
else No Permission
Consumer->>User: Disconnect
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes 🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. 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: 3
Fix all issues with AI Agents 🤖
In @openwisp_controller/geo/apps.py:
- Around line 131-153: The websocket group naming is inconsistent:
_location_post_save_websocket_receiver sends to groups using
instance.organization_id but consumers join using the Organization object's
string (org) which yields the name; update the consumer join logic in
openwisp_controller/geo/channels/consumers.py (where groups are created/joined,
around the join_group or connect handler at line ~36) to use the organization's
numeric id (e.g., org.id or str(org.id)) so the group key matches the
f"loci.mobile-location.organization.{instance.organization_id}" used in
_location_post_save_websocket_receiver.
In @openwisp_controller/geo/channels/consumers.py:
- Around line 23-38: In CommonLocationBroadcast.join_groups, the group name uses
the Organization instance ({org}) which relies on __str__ and mismatches the
sender that uses numeric organization_id; change the group construction to use
the organization's numeric id (e.g., org.id or org.pk) when building the group
string (variable group) and then add that group to group_names and call
channel_layer.group_add as before so receiver subscribes to the same
"loci.mobile-location.organization.<numeric_id>" groups the sender uses.
In @openwisp_controller/geo/tests/pytest.py:
- Around line 163-164: Update the incomplete test comments that end with
trailing commas by finishing the sentences to clearly state expectations (for
example change the comment above await
self._save_location(str(org1_location.pk)) to "Updating co-ordinates for
org1_location should notify org1_user and admin, but not org2_user." and
similarly complete the other comment around the org2_location test to explicitly
state which users should or should not be notified); locate the comments near
the _save_location calls in the pytest file and replace the dangling commas with
the full clarification text.
♻️ Duplicate comments (2)
requirements.txt (1)
6-7: Temporary dependency change is already tracked.The TODO comment indicates this dependency on the feature branch should be reverted before merge. This has been flagged in previous reviews.
.github/workflows/ci.yml (1)
75-77: Temporary installation step is already tracked.The TODO comment indicates this force-reinstall step should be removed before merge. This has been flagged in previous reviews.
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
.github/workflows/ci.ymlopenwisp_controller/geo/apps.pyopenwisp_controller/geo/channels/consumers.pyopenwisp_controller/geo/channels/routing.pyopenwisp_controller/geo/tests/pytest.pyrequirements.txt
🧰 Additional context used
🧬 Code graph analysis (4)
openwisp_controller/geo/channels/consumers.py (1)
openwisp_controller/geo/models.py (1)
Location(6-9)
openwisp_controller/geo/apps.py (2)
openwisp_controller/config/base/channels_consumer.py (1)
connect(40-50)openwisp_controller/geo/base/models.py (1)
organization_id(64-65)
openwisp_controller/geo/channels/routing.py (2)
openwisp_controller/routing.py (1)
get_routes(11-12)openwisp_controller/geo/channels/consumers.py (2)
CommonLocationBroadcast(23-38)LocationBroadcast(8-20)
openwisp_controller/geo/tests/pytest.py (1)
openwisp_controller/geo/channels/consumers.py (2)
CommonLocationBroadcast(23-38)LocationBroadcast(8-20)
🪛 Ruff (0.14.10)
openwisp_controller/geo/apps.py
132-132: Unused method argument: sender
(ARG002)
132-132: Unused method argument: kwargs
(ARG002)
openwisp_controller/geo/tests/pytest.py
128-128: Possible hardcoded password assigned to argument: "password"
(S106)
134-134: Possible hardcoded password assigned to argument: "password"
(S106)
🔇 Additional comments (10)
openwisp_controller/geo/channels/routing.py (2)
5-8: LGTM!The imports are properly structured and necessary for the new AllLocationChannel route.
Also applies to: 13-13
21-26: LGTM!The new AllLocationChannel route is correctly registered and follows the established pattern. The naming is clear and consistent with the PR objectives.
openwisp_controller/geo/apps.py (2)
1-1: LGTM!All new imports are necessary for the WebSocket receiver functionality implemented in
_location_post_save_websocket_receiver.Also applies to: 3-3, 5-5, 8-8
123-129: LGTM!The signal connection is properly configured with a unique
dispatch_uidto prevent duplicate registrations. The implementation follows Django signal best practices.openwisp_controller/geo/channels/consumers.py (1)
2-3: LGTM!The imports are necessary for the WebSocket consumer implementations and are used correctly throughout the file.
openwisp_controller/geo/tests/pytest.py (5)
1-29: LGTM!The imports are well-organized and appropriate for the async WebSocket tests. Using
load_modelfor theGroupmodel maintains consistency with the existing pattern for swappable models.
32-40: LGTM!The class structure cleanly separates the location-specific consumer (
location_consumer) from the common location consumer (common_location_consumer), and the addition ofTestOrganizationMixinproperly enables organization-related test utilities.
42-80: LGTM!The test thoroughly validates the authorization flow for the specific location endpoint, correctly verifying that:
- Staff without permission cannot connect
- Staff with permission but without org membership cannot connect
- Staff with both permission and org admin status can connect
The async permission lookup using
afirst()withcodenameandapp_labelfilters is the correct pattern.
82-107: LGTM!The test correctly validates that the common location endpoint allows connection with just the change permission, unlike the specific location endpoint which also requires organization membership. This aligns with the
CommonLocationBroadcastdesign where users can connect and then receive updates only for organizations they manage.
109-197: Well-structured organization isolation test.The test comprehensively validates the organization-based filtering in
CommonLocationBroadcast:
- Users only receive updates for locations in their managed organizations
- Superusers (admin) receive all updates
- Cross-organization leakage is prevented
The use of
suppress(asyncio.CancelledError)for communicator cleanup is appropriate for handling the async teardown edge cases.Regarding the static analysis hint about hardcoded passwords at lines 128 and 134: these are test fixture credentials and are acceptable in test code.
70851ec to
cb3583f
Compare
cb3583f to
998d255
Compare
ec450b7 to
90f5ba0
Compare
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
Checklist
Reference to Existing Issue
Closes #1157.
Description of Changes
location/allfrom base django-loci clases with updated user permissions.Screen Recording
Screencast.from.2025-11-13.02-20-06.webm