fix(api): add the documented work item relation removal endpoint - #9585
fix(api): add the documented work item relation removal endpoint#9585mggarofalo wants to merge 2 commits into
Conversation
The API reference documents
POST /api/v1/workspaces/{slug}/projects/{project_id}/work-items/{id}/relations/remove/
but the route was never registered, so it returned 404 everywhere.
Relations could be created and listed through the public API but never
removed, leaving integrations unable to correct a dependency graph. The
only working path was the internal app API, which uses session auth and
rejects an API key.
Register the documented route against a new IssueRelationRemoveAPIEndpoint,
which consumes the already-written but unreferenced
IssueRelationRemoveSerializer. The relation is matched in either direction
and scoped to the workspace, since relations may cross projects. The work
item in the path must belong to the project in the path, so membership of
that project actually authorizes the removal.
A relation that does not exist is a 404 rather than an AttributeError on
None -> 500. Fix the same latent crash in
IssueRelationViewSet.remove_relation on the app API.
Removal dispatches issue_relation.activity.deleted with notification=True,
reporting the relation type as seen from the work item in the path so the
activity feed on both work items reads the right way round.
Closes makeplane#9584
ApiKeyRateThrottle counts requests per API key in the shared cache, and every contract test authenticates with the same token, so the history accumulated across the session. Once the suite crossed 60 requests inside a minute, whichever tests happened to run next were rate limited into 429s regardless of what they asserted -- so adding tests anywhere could break tests elsewhere. Clear the token's throttle history in the api_key_client fixture so each test starts with the full budget.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (7)
📝 WalkthroughWalkthroughThe PR adds the documented public API endpoint for removing work-item relations. It validates scope and input, supports relations stored in either direction, records deletion activity, handles missing relations with 404 responses, and adds contract coverage. ChangesWork-item relation removal
Estimated code review effort: 3 (Moderate) | ~25 minutes Sequence Diagram(s)sequenceDiagram
participant APIClient
participant IssueRelationRemoveAPIEndpoint
participant IssueRelationViewSet
participant ActivityService
APIClient->>IssueRelationRemoveAPIEndpoint: POST related_issue
IssueRelationRemoveAPIEndpoint->>IssueRelationViewSet: Locate and remove relation
IssueRelationViewSet-->>IssueRelationRemoveAPIEndpoint: Return deletion result
IssueRelationRemoveAPIEndpoint->>ActivityService: Record deletion activity
IssueRelationRemoveAPIEndpoint-->>APIClient: Return 204
Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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 Warning |
Description
The API reference documents a work-item relation removal endpoint:
but that route was never registered, so it returns 404 on every instance. Relations can be created and listed through the public API and never removed, which leaves an integration able to build a dependency graph but unable to correct it. The only working path is the internal app API (
POST /api/workspaces/.../issues/{id}/remove-relation/), which usesBaseSessionAuthenticationand so rejects anX-API-Key— unusable server-to-server.This registers the documented route so the docs page and the code agree.
What changed
apps/api/plane/api/views/issue.py— newIssueRelationRemoveAPIEndpoint. It consumesIssueRelationRemoveSerializer, which was already written with the exact request shape from the docs page but was never imported or referenced by anything.apps/api/plane/api/urls/work_item.py— registers.../work-items/<issue_id>/relations/remove/under thework-itemsprefix the docs advertise, next to the existingrelations/list/create route.apps/api/plane/api/serializers/__init__.py,apps/api/plane/api/views/__init__.py— export the serializer and the endpoint.apps/api/plane/app/views/issue/relation.py—IssueRelationViewSet.remove_relationcalled.first()and then.delete()with noNonecheck, so removing a relation that does not exist raisedAttributeError→ HTTP 500. It now returns 404. The new public endpoint does not share this code path, but the bug is real on the app API and is fixed here rather than left behind.apps/api/plane/tests/conftest.py(second commit) —ApiKeyRateThrottlecounts requests per API key in the shared cache, and every contract test authenticates with the same token, so the history accumulated across the whole session. Once the suite crossed 60 requests inside a minute, whichever tests ran next were rate limited into 429s regardless of what they asserted — adding tests anywhere could break tests elsewhere, which is exactly what happened when the tests below were added. Theapi_key_clientfixture now clears the token's throttle history so each test starts with the full budget.Behaviour of the new endpoint
blocked_byis stored once, so a work item on theblockingside has to match onrelated_issue_idrather thanissue_id; the same request body works from either end.issue_relation.activity.deletedwithnotification=True, matching what the web app does. The stored relation is directional, so the relation type is reported as seen from the work item in the path (a storedblocked_bywhoserelated_issueis the path item is reported asblocking) — otherwise the activity entries on the two work items read the wrong way round.204 No Contentwith an empty body, as documented.The OpenAPI schema is generated from the views, so the endpoint now appears in the generated reference under Work Item Relations with operation id
remove_work_item_relation.Type of Change
Test Scenarios
New contract tests in
apps/api/plane/tests/contract/api/test_work_item_relations.py(9 tests, all passing):.first()→.delete()crash)related_issuereturns 400related_issuereturns 400issue_relation.activity.deletedwithnotification=Trueand the relation type as seen from the path work itemRun with:
The full suite passes — 525 tests, run twice back to back to confirm the throttle history no longer leaks between tests:
The generated OpenAPI schema was checked too (
ENABLE_DRF_SPECTACULAR=1 python manage.py spectacular): the endpoint appears at the documented path under the Work Item Relations tag withoperationId: remove_work_item_relation, anIssueRelationRemoveRequestbody and 204/400/401/403/404 responses, and adds no new schema warnings.ruff checkandruff formatare clean on every file touched.References
Closes #9584
Summary by CodeRabbit
New Features
Bug Fixes