Skip to content

Allow deleting user account with active memberships#11787

Merged
lohanidamodar merged 10 commits into1.9.xfrom
CLO-4175-allow-delete-with-memberships
Apr 16, 2026
Merged

Allow deleting user account with active memberships#11787
lohanidamodar merged 10 commits into1.9.xfrom
CLO-4175-allow-delete-with-memberships

Conversation

@lohanidamodar
Copy link
Copy Markdown
Member

@lohanidamodar lohanidamodar commented Apr 5, 2026

Summary

  • Removes the restriction that blocked account self-deletion (DELETE /v1/account) when the user had team memberships on the console project
  • When a user deletes their account with active memberships, ownership is handled gracefully:
    • Sole owner with other members: ownership is transferred to the most veteran member (orderAsc('$createdAt'))
    • All other cases (sole member, non-owner, multiple owners): no special handling needed — the Deletes worker handles membership cleanup. Orphan teams are left for future cleanup (safer than immediate deletion)
  • Membership cleanup in the Deletes worker decrements team member counts for confirmed members
  • E2E tests validate account deletion succeeds both with and without active memberships

Changes

  • app/controllers/api/account.php — Replaced blanket deletion block with graceful ownership transfer for sole owners
  • src/Appwrite/Platform/Workers/Deletes.php — Cleaned up unused closure variable
  • src/Appwrite/Platform/Modules/Teams/Http/Memberships/Delete.php — Removed confirm filter on primary user transfer (all members eligible)
  • tests/e2e/Services/Account/AccountConsoleClientTest.php — Added tests for deletion with/without memberships

Test plan

  • Verify account deletion succeeds when user is sole owner with other members (ownership transferred to veteran)
  • Verify account deletion succeeds when user is sole member of a team (team left as orphan)
  • Verify account deletion succeeds when user is a regular member
  • Verify account deletion succeeds with no memberships
  • Verify team total counts are correctly decremented
  • Run: docker compose exec appwrite test tests/e2e/Services/Account/AccountConsoleClientTest.php

🤖 Generated with Claude Code

Instead of blocking account deletion when the user has confirmed team
memberships, handle memberships gracefully during deletion:

- Sole owner + sole member: delete the team and queue project cleanup
- Sole owner + other members: transfer ownership to the next member
- Non-owner / multiple owners: no special handling needed (worker cleans up)

Also update the Deletes worker to transfer the team's primary user
reference when removing a deleted user's memberships.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Apr 5, 2026

Greptile Summary

This PR removes the blanket USER_DELETION_PROHIBITED block on DELETE /v1/account for console-project users, allowing self-deletion even with active team memberships. Membership cleanup continues to run asynchronously through the Deletes worker, and a confirm filter is added to Memberships/Delete.php to prevent unconfirmed invitees from being promoted to primary user.

The main concern is that the replacement foreach loop in account.php (lines 485–497) fetches each team document and then discards it — pure dead code that fires N unnecessary DB reads on the deletion hot path. The $authorization injection added alongside it is also never consumed. Both can simply be removed.

Confidence Score: 4/5

Safe to merge after cleaning up the dead loop and unused injection in account.php.

All remaining findings are P2. The dead loop is harmless correctness-wise but wastes a DB round-trip per confirmed membership on the deletion path and will confuse future readers — worth fixing before merge. The confirm fix in Memberships/Delete.php is correct.

app/controllers/api/account.php — dead loop and unused $authorization injection should be removed.

Important Files Changed

Filename Overview
app/controllers/api/account.php Removed the blanket USER_DELETION_PROHIBITED guard; replacement loop fetches team documents but never uses them — dead code with unnecessary DB reads, and $authorization is injected but unused.
src/Appwrite/Platform/Modules/Teams/Http/Memberships/Delete.php Adds Query::equal('confirm', [true]) to the findOne that picks the next primary user when the current primary member is removed — prevents an unconfirmed invitee from being silently promoted.
tests/e2e/Services/Account/AccountConsoleClientTest.php Tests verify account deletion now returns 204 with active memberships, but no assertion on async worker cleanup (team totals, membership removal, session invalidation).

Reviews (9): Last reviewed commit: "Merge remote-tracking branch 'origin/1.9..." | Re-trigger Greptile

Comment thread app/controllers/api/account.php Outdated
Comment thread src/Appwrite/Platform/Workers/Deletes.php Outdated
@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 5, 2026

🔄 PHP-Retry Summary

Flaky tests detected across commits:

Commit cc82b1a - 2 flaky tests
Test Retries Total Time Details
LegacyTransactionsConsoleClientTest::testBulkUpdateWithTransactionAwareQueries 1 240.38s Logs
UsageTest::testVectorsDBStats 1 10.03s Logs
Commit 8442a1e - 2 flaky tests
Test Retries Total Time Details
UsageTest::testVectorsDBStats 1 10.12s Logs
LegacyCustomServerTest::testCreateIndexes 1 242.11s Logs
Commit d6f51a9 - 6 flaky tests
Test Retries Total Time Details
UsageTest::testFunctionsStats 1 10.26s Logs
UsageTest::testPrepareSitesStats 1 9ms Logs
UsageTest::testEmbeddingsTextUsageDoesNotBreakProjectUsage 1 9ms Logs
LegacyConsoleClientTest::testUpsertDocument 1 241.87s Logs
LegacyConsoleClientTest::testOneToManyRelationship 1 240.83s Logs
LegacyCustomClientTest::testCreatedAfter 1 240.37s Logs
Commit c6e3294 - 5 flaky tests
Test Retries Total Time Details
UsageTest::testFunctionsStats 1 10.26s Logs
UsageTest::testPrepareSitesStats 1 7ms Logs
UsageTest::testEmbeddingsTextUsageDoesNotBreakProjectUsage 1 5ms Logs
TablesDBConsoleClientTest::testInvalidDocumentStructure 1 240.57s Logs
TablesDBCustomServerTest::testTimeout 1 240.22s Logs
Commit f78b5c6 - 6 flaky tests
Test Retries Total Time Details
LegacyCustomServerTest::testCreateIndexes 1 243.00s Logs
VectorsDBConsoleClientTest::testGetCollectionLogs 1 7ms Logs
DatabasesConsoleClientTest::testGetCollectionLogs 1 9ms Logs
UsageTest::testFunctionsStats 1 10.19s Logs
UsageTest::testPrepareSitesStats 1 7ms Logs
UsageTest::testEmbeddingsTextUsageDoesNotBreakProjectUsage 1 5ms Logs

Note: Flaky test results are tracked for the last 5 commits

@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 5, 2026

✨ Benchmark results

  • Requests per second: 1,757
  • Requests with 200 status code: 316,372
  • P99 latency: 0.104699077

⚡ Benchmark Comparison

Metric This PR Latest version
RPS 1,757 1,304
200 316,372 234,713
P99 0.104699077 0.15830335

Prevent unconfirmed (pending invite) members from being promoted to
owner or set as the team's primary user during membership/account
deletion by adding a Query::equal('confirm', [true]) filter to the
relevant findOne queries.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@lohanidamodar lohanidamodar requested a review from eldadfux April 5, 2026 02:52
Comment thread app/controllers/api/account.php Outdated
Comment thread src/Appwrite/Platform/Modules/Teams/Http/Memberships/Delete.php
Comment thread src/Appwrite/Platform/Workers/Deletes.php Outdated
Comment thread app/controllers/api/account.php Outdated
…g, deduplicate transfer

- Remove team deletion for sole owner+sole member case; let orphan teams
  be cleaned up by Cloud's inactive project cleanup (safer, avoids
  accidental data loss)
- Add explicit ordering by $createdAt so the most veteran member gets
  ownership transfer, with limit(1) for clarity
- Remove confirm filter on primary user transfer in membership deletion
  so all members (including unconfirmed) are considered
- Remove redundant ownership transfer from Deletes worker since the API
  controller already handles it before queueing

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Comment thread app/controllers/api/account.php Outdated
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Comment thread app/controllers/api/account.php Outdated
@lohanidamodar lohanidamodar requested a review from eldadfux April 5, 2026 06:56
lohanidamodar and others added 2 commits April 5, 2026 07:11
… and primary user transfer

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…d instead

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
deepshekhardas pushed a commit to deepshekhardas/appwrite that referenced this pull request Apr 6, 2026
deepshekhardas pushed a commit to deepshekhardas/appwrite that referenced this pull request Apr 6, 2026
@blacksmith-sh

This comment has been minimized.

@lohanidamodar lohanidamodar merged commit 6e50ed0 into 1.9.x Apr 16, 2026
79 of 81 checks passed
@lohanidamodar lohanidamodar deleted the CLO-4175-allow-delete-with-memberships branch April 16, 2026 02:33
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