Skip to content

fix: exclude soft-deleted profile assignees#8869

Open
GLDRoger wants to merge 2 commits intomakeplane:previewfrom
GLDRoger:fix/profile-assigned-count-soft-delete
Open

fix: exclude soft-deleted profile assignees#8869
GLDRoger wants to merge 2 commits intomakeplane:previewfrom
GLDRoger:fix/profile-assigned-count-soft-delete

Conversation

@GLDRoger
Copy link
Copy Markdown

@GLDRoger GLDRoger commented Apr 8, 2026

Summary

Fixes a profile-count mismatch where the project sidebar on a user profile could include stale soft-deleted assignee relations.

Closes #8868.

Problem

WorkspaceUserProfileEndpoint was aggregating project counts with project_issue__assignees__in=[user_id].
That could still count historical IssueAssignee rows after the assignment had been soft-deleted, causing the sidebar/project breakdown to drift from the overview cards and assigned work-item list.

Minimal reproduction

  1. Create a user and assign them to 3 work items in the same project.
  2. Remove the user from 2 of those work items so the corresponding IssueAssignee rows are soft-deleted.
  3. Open the user profile overview and assigned tab.
  4. Observe the mismatch:
    • overview cards show 1 assigned work item
    • project sidebar breakdown still shows 3

Fix

  • count assigned-related aggregates via active IssueAssignee rows
  • require project_issue__issue_assignee__deleted_at__isnull=True
  • use distinct=True on the profile project aggregations to avoid overcounting
  • add regression coverage for one active assignment plus two soft-deleted historical assignments

Verification

  • python3 -m py_compile apps/api/plane/app/views/workspace/user.py apps/api/plane/tests/contract/app/test_workspace_user_profile_app.py
  • git diff --check

I did not run the full Django test suite locally because this environment did not have the upstream repo's full database/runtime test setup bootstrapped.

Summary by CodeRabbit

  • Bug Fixes
    • Corrected workspace user profile project counts to exclude archived projects and soft-deleted task assignments, and to avoid duplicate counting so issue counters are accurate.
  • Tests
    • Added a contract test validating that project issue counters only reflect active (non-deleted, non-archived) assignments.

Copilot AI review requested due to automatic review settings April 8, 2026 10:31
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 8, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b1e720aa-36ba-4b06-b964-c55f3b499811

📥 Commits

Reviewing files that changed from the base of the PR and between f51b2a1 and 8c13a0e.

📒 Files selected for processing (1)
  • apps/api/plane/tests/contract/app/test_workspace_user_profile_app.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/api/plane/tests/contract/app/test_workspace_user_profile_app.py

📝 Walkthrough

Walkthrough

Updates WorkspaceUserProfileEndpoint to count project issue metrics using active IssueAssignee joins and shared Q filters (archived_at__isnull=True, is_draft=False, issue_assignee__deleted_at__isnull=True), and adds distinct=True to relevant Count() aggregations. Adds a regression test ensuring soft-deleted assignments are excluded.

Changes

Cohort / File(s) Summary
Profile Endpoint Query Logic
apps/api/plane/app/views/workspace/user.py
Introduced reusable Q filters visible_project_issue_filter and active_project_assignment_filter. Replaced project_issue__assignees__in=[user_id] predicates with issue_assignee__assignee_id=user_id + issue_assignee__deleted_at__isnull=True. Applied distinct=True to all affected Count() aggregations to avoid duplicates from joins.
Regression Test
apps/api/plane/tests/contract/app/test_workspace_user_profile_app.py
Added test_workspace_user_profile_excludes_soft_deleted_assignments_from_project_counts verifying one active assignment and two soft-deleted IssueAssignee rows produce assigned_issues == 1 in the profile sidebar response.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 I hopped through queries, chased ghosts away,
Soft-deleted shadows no longer stay,
Filters stitched neatly, counts now true,
Distinct footsteps show just one or two,
A carrot for tidy data—hip hooray! 🥕

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'fix: exclude soft-deleted profile assignees' clearly and concisely describes the main change—fixing the profile count mismatch by excluding soft-deleted assignee relations.
Description check ✅ Passed The PR description provides a clear summary, problem statement, minimal reproduction, fix details, and verification steps. All critical sections are well-documented.
Linked Issues check ✅ Passed The code changes directly address all coding requirements from issue #8868: filtering active IssueAssignee rows, excluding soft-deleted assignments, adding distinct=True, and regression test coverage.
Out of Scope Changes check ✅ Passed All changes are directly scoped to fixing the profile count mismatch—updating the WorkspaceUserProfileEndpoint aggregations and adding regression test coverage. No unrelated changes detected.

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

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Fixes a mismatch in user profile sidebar project counts by ensuring assigned-related aggregates only consider active IssueAssignee rows (excluding soft-deleted assignments), aligning sidebar counts with other profile views.

Changes:

  • Update WorkspaceUserProfileEndpoint project aggregates to filter through IssueAssignee with deleted_at IS NULL.
  • Add distinct=True to project issue count aggregations to prevent overcounting due to join multiplicity.
  • Add a regression contract test covering active vs soft-deleted historical assignments.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
apps/api/plane/app/views/workspace/user.py Adjusts project-level profile aggregates to exclude soft-deleted assignee relations and avoid overcounting via distinct=True.
apps/api/plane/tests/contract/app/test_workspace_user_profile_app.py Adds regression coverage to ensure sidebar assigned counts ignore soft-deleted IssueAssignee rows.

assert len(response.data["project_data"]) == 1
assert response.data["project_data"][0]["assigned_issues"] == 1
assert response.data["project_data"][0]["completed_issues"] == 0
assert response.data["project_data"][0]["pending_issues"] == 0
Copy link

Copilot AI Apr 8, 2026

Choose a reason for hiding this comment

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

This test’s pending_issues expectation is likely not representative of real workspaces/projects. Issue.save() only assigns a default state if State rows exist for the project; ProjectFactory doesn’t seed DEFAULT_STATES, so active_issue.state stays NULL and pending_issues becomes 0. In the actual app flow, project creation seeds default states, so an active assigned issue would typically yield pending_issues == 1. Consider seeding the project’s states in the test (e.g., create the default backlog state for the project) and assert the corresponding pending_issues, or drop the pending_issues assertion to keep the regression focused on excluding soft-deleted assignees.

Suggested change
assert response.data["project_data"][0]["pending_issues"] == 0

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor

@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.

🧹 Nitpick comments (1)
apps/api/plane/tests/contract/app/test_workspace_user_profile_app.py (1)

13-73: Well-structured regression test.

The test correctly:

  • Creates the workspace/project membership hierarchy with appropriate roles
  • Uses IssueAssignee.all_objects.create() to create soft-deleted assignment records with deleted_at set
  • Verifies that only the single active assignment is counted

One minor suggestion: consider also asserting created_issues count to ensure the visible filter works independently of the assignment filter. Since create_user creates all issues but isn't the profiled user, created_issues should be 0.

💡 Optional: Add created_issues assertion
     assert response.data["project_data"][0]["assigned_issues"] == 1
     assert response.data["project_data"][0]["completed_issues"] == 0
     assert response.data["project_data"][0]["pending_issues"] == 0
+    assert response.data["project_data"][0]["created_issues"] == 0
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/api/plane/tests/contract/app/test_workspace_user_profile_app.py` around
lines 13 - 73, Add an assertion to the
test_workspace_user_profile_excludes_soft_deleted_assignments_from_project_counts
function verifying that the profiled user has zero created issues: after the
existing response checks, assert
response.data["project_data"][0]["created_issues"] == 0 to ensure the
created_issues filter is working independently of assignment filtering.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@apps/api/plane/tests/contract/app/test_workspace_user_profile_app.py`:
- Around line 13-73: Add an assertion to the
test_workspace_user_profile_excludes_soft_deleted_assignments_from_project_counts
function verifying that the profiled user has zero created issues: after the
existing response checks, assert
response.data["project_data"][0]["created_issues"] == 0 to ensure the
created_issues filter is working independently of assignment filtering.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c5d42be8-6658-49b9-8d27-bae35c81ed79

📥 Commits

Reviewing files that changed from the base of the PR and between 8a2579c and f51b2a1.

📒 Files selected for processing (2)
  • apps/api/plane/app/views/workspace/user.py
  • apps/api/plane/tests/contract/app/test_workspace_user_profile_app.py

@CLAassistant
Copy link
Copy Markdown

CLAassistant commented Apr 8, 2026

CLA assistant check
All committers have signed the CLA.

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.

🐛 Bug: Profile sidebar assigned count includes stale soft-deleted assignees

3 participants