Skip to content

Conversation

@dee077
Copy link
Member

@dee077 dee077 commented Nov 12, 2025

Checklist

  • I have read the OpenWISP Contributing Guidelines.
  • I have manually tested the changes proposed in this pull request.
  • I have written new test cases for new code and/or updated existing tests for changes to existing code.
  • I have updated the documentation.

Reference to Existing Issue

Closes #1157.

Description of Changes

  • Made a new ws endpoint location/all from base django-loci clases with updated user permissions.

Screen Recording

Screencast.from.2025-11-13.02-20-06.webm

@coveralls
Copy link

Coverage Status

coverage: 98.549% (-0.06%) from 98.607%
when pulling 5a91a30 on feature/1157-new-ws-endpoint-for-all-location
into faec934 on master.

@dee077 dee077 self-assigned this Dec 3, 2025
@dee077 dee077 added the gsoc Part of a Google Summer of Code project label Dec 3, 2025
@pandafy pandafy changed the base branch from master to gsoc25-map December 15, 2025 13:01
@dee077 dee077 force-pushed the feature/1157-new-ws-endpoint-for-all-location branch from 61709be to f843054 Compare December 18, 2025 19:34
Implemented a new websocket endpoint 'location/all/' with updated user permission from base clases from django-loci.

Fixes #1157
@dee077 dee077 force-pushed the feature/1157-new-ws-endpoint-for-all-location branch from f843054 to 75476f6 Compare December 18, 2025 19:36
@dee077 dee077 force-pushed the feature/1157-new-ws-endpoint-for-all-location branch 2 times, most recently from d6a09ed to ade9399 Compare December 23, 2025 12:56
@dee077 dee077 force-pushed the feature/1157-new-ws-endpoint-for-all-location branch from ade9399 to 9697b8b Compare December 23, 2025 13:14
@dee077
Copy link
Member Author

dee077 commented Dec 23, 2025

Updates

  • Added organization specific websocket groups so that authorized users can connect to the common location endpoint while receiving updates only for the organizations they manage unlike, the single-location endpoint enforces stricter authorization by rejecting the connection entirely if the user is not an admin or manager of the location’s organization.
  • Added tests

Build on top of openwisp/django-loci#193

@dee077 dee077 marked this pull request as ready for review December 23, 2025 13:22
@dee077 dee077 force-pushed the feature/1157-new-ws-endpoint-for-all-location branch from 0e91107 to f0f5305 Compare December 25, 2025 10:09
Copy link
Member

@pandafy pandafy left a 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
Comment on lines 6 to 7
# 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
Copy link
Member

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.

Comment on lines 75 to 77
# 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"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO: Remove before merging!

@dee077 dee077 moved this from In progress to In review in [GSoC25] General Map: Indoor, Mobile, Linkable URLs Jan 4, 2026
@nemesifier
Copy link
Member

@coderabbitai review

@coderabbitai
Copy link

coderabbitai bot commented Jan 5, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai
Copy link

coderabbitai bot commented Jan 5, 2026

📝 Walkthrough

Walkthrough

This 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 CommonLocationBroadcast consumer that manages group subscriptions based on user organizational membership, (3) routing configuration for the new broadcast endpoint, and (4) comprehensive tests validating authorization, organization isolation, and permission handling across different user roles.

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
Loading
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
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Description check ✅ Passed The PR description covers key aspects: checklist completion, issue reference (#1157), description of changes, and includes a screencast demonstration.
Linked Issues check ✅ Passed The PR implements a new WebSocket endpoint with organization-based permission logic for the common location broadcast [#1157], matching the linked issue requirements.
Out of Scope Changes check ✅ Passed All changes are scoped to implementing the new WebSocket endpoint: new CommonLocationBroadcast consumer, routing updates, signal handling for location updates, and comprehensive tests.
Title check ✅ Passed The pull request title accurately summarizes the main feature being added: a new WebSocket endpoint for broadcasting location updates to all users.

✏️ 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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a 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

📥 Commits

Reviewing files that changed from the base of the PR and between d153bc1 and 4a1b123.

📒 Files selected for processing (6)
  • .github/workflows/ci.yml
  • openwisp_controller/geo/apps.py
  • openwisp_controller/geo/channels/consumers.py
  • openwisp_controller/geo/channels/routing.py
  • openwisp_controller/geo/tests/pytest.py
  • requirements.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_uid to 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_model for the Group model 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 of TestOrganizationMixin properly enables organization-related test utilities.


42-80: LGTM!

The test thoroughly validates the authorization flow for the specific location endpoint, correctly verifying that:

  1. Staff without permission cannot connect
  2. Staff with permission but without org membership cannot connect
  3. Staff with both permission and org admin status can connect

The async permission lookup using afirst() with codename and app_label filters 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 CommonLocationBroadcast design 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.

@dee077 dee077 force-pushed the feature/1157-new-ws-endpoint-for-all-location branch from 70851ec to cb3583f Compare January 14, 2026 08:46
@dee077 dee077 force-pushed the feature/1157-new-ws-endpoint-for-all-location branch from cb3583f to 998d255 Compare January 14, 2026 08:47
@dee077 dee077 force-pushed the feature/1157-new-ws-endpoint-for-all-location branch from ec450b7 to 90f5ba0 Compare January 14, 2026 17:05
@nemesifier
Copy link
Member

@coderabbitai review

@coderabbitai
Copy link

coderabbitai bot commented Jan 15, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@nemesifier nemesifier changed the title [feature] New ws endpoint for all all Location broadcast [feature] Added WebSocket endpoint which broadcasts all location updates Jan 15, 2026
@nemesifier nemesifier merged commit eabef1e into gsoc25-map Jan 15, 2026
15 checks passed
@nemesifier nemesifier deleted the feature/1157-new-ws-endpoint-for-all-location branch January 15, 2026 22:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement gsoc Part of a Google Summer of Code project

Development

Successfully merging this pull request may close these issues.

[feature] New ws endpoint for all all Location broadcast

5 participants