Skip to content

refactor(Servergroup): Refactor server group access and shared-group handling#10077

Open
lkmatsumura wants to merge 3 commits into
pgadmin-org:masterfrom
lkmatsumura:servergroup_refactor
Open

refactor(Servergroup): Refactor server group access and shared-group handling#10077
lkmatsumura wants to merge 3 commits into
pgadmin-org:masterfrom
lkmatsumura:servergroup_refactor

Conversation

@lkmatsumura

@lkmatsumura lkmatsumura commented Jun 10, 2026

Copy link
Copy Markdown

Summary

Refactor server group access and shared-group handling in pgAdmin4 to centralize visibility logic and simplify browser rendering.

What changed

  • Updated web/pgadmin/utils/server_access.py

    • Added get_server_groups_for_user() and get_server_groups_for_user_query()
    • Simplified get_server_group() to reuse shared access logic
    • Added is_shared_group metadata on returned groups
    • Consolidated shared-group filtering, ownership checks, and ordering
  • Updated web/pgadmin/browser/server_groups/__init__.py

    • Replaced ad hoc shared-server checks with centralized access helpers
    • Removed redundant ServerGroupModule.has_shared_server() logic
    • Ensured shared server groups are rendered with the correct icon
    • Prevented deletion of shared server groups
    • Improved deletion error messages for shared groups and first group restrictions

Notes

  • This PR focuses on server group refactor work.

Summary by CodeRabbit

  • Bug Fixes

    • Improved error messages when deleting server groups with shared servers or attempting to delete the first server group
  • Improvements

    • Enhanced server group listing and visibility handling for shared server groups
    • Optimized server group retrieval operations

Luiz K Matsumura added 3 commits June 10, 2026 12:34
…s a shared group.

- Added is_shared_group property to the result to simplify
  the identificantion of shared group- Added is_shared_group property
  to the result to simplify the identification of shared group

- rules centralized in get_server_groups_for_user_query() function
…and shared group logic

- change to call get_server_groups_for_user() to retrive the servergroups
  when possible
- same for get_server_group()
- Simplifying the method of detecting whether the group is shared or not
  using the information now returned by get_server_groups_for_user() and get_server_group().
- A shared group is not allowed to be deleted.
- Only the owner can do it.
@coderabbitai

coderabbitai Bot commented Jun 10, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

Refactored server-group access and icon selection: introduced new query helpers to compute is_shared_group visibility, updated icon selection to accept shared status directly, and revised view operations (delete, update, create, nodes) to use the new access layer with more specific error messages.

Changes

Server Group Access and Icon Refactoring

Layer / File(s) Summary
Data access helpers and query construction
web/pgadmin/utils/server_access.py
Added get_server_group(gid) and refactored get_server_groups_for_user() to accept hide_shared and servergroup_id filters; introduced get_server_groups_for_user_query() for visibility queries with is_shared_group annotation and ownership-based ordering; updated SQLAlchemy imports to include case and exists.
Icon selection refactor
web/pgadmin/browser/server_groups/__init__.py
Updated get_icon_css_class(is_shared_group, default_val) to accept shared-group status directly instead of group id/user id pair.
Server group node generation
web/pgadmin/browser/server_groups/__init__.py
Refactored ServerGroupModule.get_nodes() and ServerGroupView.nodes() endpoints to derive shared state and icon from group.is_shared_group; updated get_all_server_groups() to delegate to new access helpers with hide_shared_server filtering.
Server group view operations
web/pgadmin/browser/server_groups/__init__.py
Updated ServerGroupView.delete error messages for shared-server and first-group cases; refactored ServerGroupView.update to fetch via get_server_group(gid); updated ServerGroupView.create to refresh created group via get_server_group(sg.id) before response generation; adjusted exception handling structure while preserving rollback semantics.

Sequence Diagram

sequenceDiagram
  participant ServerGroupView
  participant get_server_group
  participant get_server_groups_for_user
  participant get_server_groups_for_user_query
  participant Database
  
  ServerGroupView->>get_server_group: get_server_group(gid)
  get_server_group->>get_server_groups_for_user: servergroup_id=gid
  get_server_groups_for_user->>get_server_groups_for_user_query: build visibility query
  get_server_groups_for_user_query->>Database: SELECT with is_shared_group logic
  Database-->>get_server_groups_for_user_query: groups with is_shared_group
  get_server_groups_for_user-->>get_server_group: annotated results
  get_server_group-->>ServerGroupView: single group or None
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • pgadmin-org/pgadmin4#10006: Overlapping refactoring of get_server_group() and get_server_groups_for_user*() helpers in web/pgadmin/utils/server_access.py to modify visibility logic and is_shared_group computation.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main objective of the pull request: refactoring server group access and shared-group handling logic across multiple modules.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
web/pgadmin/utils/server_access.py (1)

133-133: ⚡ Quick win

Use Server.shared instead of Server.shared == True in SQLAlchemy filter.

In SQLAlchemy, boolean columns can be used directly in filter expressions. Using == True is redundant and flagged by linters.

♻️ Proposed fix
             .filter(
                 Server.servergroup_id == ServerGroup.id,
-                Server.shared == True
+                Server.shared
             )
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web/pgadmin/utils/server_access.py` at line 133, The SQLAlchemy filter
currently uses the redundant comparison Server.shared == True; replace that
expression with the boolean column itself (Server.shared) wherever used in the
query/filter (e.g., in the function or method that constructs the query
referencing Server.shared) so the filter reads simply Server.shared to satisfy
linters and follow SQLAlchemy conventions.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@web/pgadmin/utils/server_access.py`:
- Line 133: The SQLAlchemy filter currently uses the redundant comparison
Server.shared == True; replace that expression with the boolean column itself
(Server.shared) wherever used in the query/filter (e.g., in the function or
method that constructs the query referencing Server.shared) so the filter reads
simply Server.shared to satisfy linters and follow SQLAlchemy conventions.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 66b9468b-6998-4f8c-b411-8278e08db886

📥 Commits

Reviewing files that changed from the base of the PR and between 04fa05c and 6dd0f01.

📒 Files selected for processing (2)
  • web/pgadmin/browser/server_groups/__init__.py
  • web/pgadmin/utils/server_access.py

@dpage dpage left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks for taking this on — centralizing the visibility logic in server_access.py and replacing the per-server has_shared_server() loop with a single SQL EXISTS is a nice direction. A few things need addressing before this is mergeable:

1. Desktop mode is broken — (0).label('is_shared_group') raises AttributeError.
In get_server_groups_for_user_query(), the non-SERVER_MODE branch does:

ServerGroup.query.add_columns((0).label('is_shared_group'))

int has no .label() method, so this throws at query-build time (verified locally). Since get_nodes() was also changed to always route through get_all_server_groups(), the server-group tree fails to render in desktop mode — the default deployment. Use from sqlalchemy import literal and literal(0).label('is_shared_group').

2. Access regression in update().
update() previously fetched ServerGroup.query.filter_by(user_id=current_user.id, id=gid). It now uses get_server_group(gid), which in SERVER_MODE returns groups the user does not own as long as they contain a shared server. The method then does servergroup.name = data['name']; db.session.commit() with no ownership guard, so a user can rename another user's group. Deletion is correctly gated against shared groups (can_delete), but rename needs the same owner check.

3. Style checks will fail CI.

  • Server.shared == True → E712 (use Server.shared.is_(True) or just Server.shared).
  • Only one blank line between the two new top-level functions → E302.
  • A couple of lines exceed 79 chars (the .all() call and a docstring line) → E501.
  • for group, is_shared in sg: has a double space.

4. No tests, no changelog entry. A refactor touching access control should have a test for the owned / shared / desktop paths, and docs/en_US/release_notes_*.rst needs a line.

Since this isn't tied to a reported issue, it'd also help to note what user-facing problem it's solving — the diff reads as pure cleanup, so the bar is "demonstrably no behaviour change," and right now #1/#2 are behaviour changes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants