Skip to content

[CSM Portal] Replace project-scoped search endpoints with flat POST /cases/search and POST /deployments/search - #835

Merged
Rashmika998 merged 3 commits into
wso2-open-operations:v2from
Rashmika998:task/csm-portal-cases-search
Jun 9, 2026
Merged

Rashmika998 merged 3 commits into
wso2-open-operations:v2from
Rashmika998:task/csm-portal-cases-search

Conversation

@Rashmika998

@Rashmika998 Rashmika998 commented Jun 9, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Flattens two project-scoped search endpoints so callers supply filter IDs directly in the request body instead of the URL path.

POST /cases/search (replaces POST /projects/{id}/cases/search)

  • Removes injectProjectID helper — body forwarded as-is (raw passthrough)
  • Renames ProjectCaseSearchPayload → CaseSearchPayload; adds optional projectIds filter field
  • Adds 404 response (missing from old spec; mapUpstreamError can return it)

POST /deployments/search (replaces POST /projects/{id}/deployments/search)

  • Removes the unused path param extraction — DeploymentSearchPayload already had projectIds
  • Adds 403 and 404 responses (both missing from old spec)

Test plan

  • make test passes
  • POST /cases/search with {"projectIds":["<uuid>"]} returns matching cases
  • POST /cases/search with no projectIds returns all accessible cases
  • POST /deployments/search with {"projectIds":["<uuid>"]} returns matching deployments
  • Old project-scoped paths return 404

🤖 Generated with Claude Code

@coderabbitai

coderabbitai Bot commented Jun 9, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The PR migrates the CSM Portal backend case search from a project-scoped endpoint (POST /projects/{id}/cases/search) to a unified endpoint (POST /cases/search). The request body now includes an optional projectIds array for filtering. The injectProjectID helper and SearchProjectCases method are removed; the new SearchCases handler enforces authentication and logs user context instead of project context.

Changes

Unified Case Search Endpoint

Layer / File(s) Summary
API contract and schemas
apps/csm-portal/backend/openapi.yaml
OpenAPI spec adds POST /cases/search (operationId postCasesSearch) with CaseSearchPayload schema that includes optional projectIds array filtering, replacing the removed /projects/{id}/cases/search endpoint and ProjectCaseSearchPayload.
Handler implementation
apps/csm-portal/backend/internal/handler/cases.go
Removes injectProjectID helper that previously injected project ID into request bodies. Replaces SearchProjectCases with SearchCases method that enforces authentication via UserInfoFromContext, forwards unified search requests without path extraction, and updates error logging to capture userID instead of projectID.
Route registration
apps/csm-portal/backend/cmd/server/main.go
Registers POST /cases/search to caseHandler.SearchCases, replacing the prior project-scoped route registration.
Test coverage
apps/csm-portal/backend/internal/handler/cases_test.go
Introduces TestSearchCases covering the new endpoint with cases for missing authentication, exceeding request body size limits, invalid JSON, and successful upstream forwarding. Updates projectIds assertions to use concrete ["proj-1"] values and migrates upstream error-mapping tests to exercise the new SearchCases handler.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • wso2-open-operations/cs-tools#778: Adds the matching entity-service POST /cases/search endpoint wired to CaseHandler.SearchCases, providing the upstream service that this PR's frontend handler forwards requests to.
  • wso2-open-operations/cs-tools#779: Modifies the same case-search routing and projectIds injection logic in the handler, suggesting related refactoring of the same feature.
  • wso2-open-operations/cs-tools#824: Updates CaseSearchResponse schema in openapi.yaml for the project-scoped endpoint, while this PR replaces that endpoint with the unified version.

Suggested labels

Type/Improvement, Area/Backend, App/CSM Portal

Suggested reviewers

  • cloby99
  • shayanmalinda

Poem

🐰 A search once bound to projects alone,
Now spreads its wings with filters shown,
The injectProjectID helper's gone,
As unified search carries on! 🔍

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 75.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ❓ Inconclusive The PR description provides a clear summary of changes but omits most required sections from the repository template. Complete missing template sections including Purpose/Goals/Approach with linked issues, Release notes, Documentation/Training/Certification links, and confirm security/testing requirements.
✅ Passed checks (3 passed)
Check name Status Explanation
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.
Title check ✅ Passed The title clearly describes the main change: replacing project-scoped search endpoints with flat POST endpoints that accept filter IDs in the request body.

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

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/csm-portal/backend/openapi.yaml (1)

324-353: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

/cases/search response contract is missing 404, but handler behavior still returns it.

SearchCases still maps upstream 404 via mapUpstreamError, and TestSearchCases explicitly asserts this mapping. That makes the OpenAPI response set incomplete for current runtime behavior.

📄 Suggested OpenAPI fix
       responses:
         "200":
           description: Ok
@@
         "403":
           description: Forbidden
           content:
             application/json:
               schema:
                 $ref: '`#/components/schemas/ErrorPayload`'
+        "404":
+          description: NotFound
+          content:
+            application/json:
+              schema:
+                $ref: '`#/components/schemas/ErrorPayload`'
         "413":
           description: RequestEntityTooLarge
🤖 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 `@apps/csm-portal/backend/openapi.yaml` around lines 324 - 353, The OpenAPI
spec for the /cases/search endpoint is missing a 404 response even though the
runtime handler SearchCases (and its test TestSearchCases) maps upstream 404 via
mapUpstreamError and asserts that behavior; update the responses block in
openapi.yaml for /cases/search to include a "404" response with description
(e.g., NotFound) and the same ErrorPayload schema used by 400/401/403/413/500 so
the contract matches runtime behavior and tests.
🧹 Nitpick comments (1)
apps/csm-portal/backend/internal/handler/cases_test.go (1)

196-257: ⚡ Quick win

Add an explicit test for search requests without projectIds.

The new contract’s key behavior is “no projectIds => all accessible cases”; this path is not directly asserted yet.

🧪 Suggested test addition
 func TestSearchCases(t *testing.T) {
+	t.Run("forwards body without projectIds filter", func(t *testing.T) {
+		var capturedBody []byte
+		client := &mockEntityCaseClient{
+			searchCasesFn: func(_ context.Context, body []byte) ([]byte, error) {
+				capturedBody = body
+				return []byte(`{"cases":[],"total":0}`), nil
+			},
+		}
+		h := NewCaseHandler(client)
+		r := withUser(httptest.NewRequest(http.MethodPost, "/cases/search",
+			strings.NewReader(`{"stateKeys":["open"],"pagination":{"limit":10,"offset":0}}`)))
+		w := httptest.NewRecorder()
+		h.SearchCases(w, r)
+
+		assertStatus(t, w, http.StatusOK)
+		var sent map[string]json.RawMessage
+		if err := json.Unmarshal(capturedBody, &sent); err != nil {
+			t.Fatalf("upstream received invalid JSON: %v", err)
+		}
+		if _, exists := sent["projectIds"]; exists {
+			t.Errorf("upstream body unexpectedly contains projectIds: %s", string(sent["projectIds"]))
+		}
+	})
🤖 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 `@apps/csm-portal/backend/internal/handler/cases_test.go` around lines 196 -
257, Add a new subtest in TestSearchCases that verifies the "no projectIds =>
all accessible cases" path: create a mockEntityCaseClient with searchCasesFn
capturing the forwarded body, call NewCaseHandler(...).SearchCases with a
request body that omits projectIds (e.g.,
{"stateKeys":["open"],"pagination":{"limit":10}}), assert the handler returns
http.StatusOK and "application/json", unmarshal the capturedBody and assert the
"projectIds" key is absent (or not present) in the JSON sent upstream; use the
existing decodeJSON helper and assertions consistent with the other subtests.
🤖 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.

Inline comments:
In `@apps/csm-portal/backend/internal/handler/cases.go`:
- Around line 189-193: The handler currently forwards the incoming request body
(variable body) directly to h.entity.SearchCases, allowing client-controlled
projectIds; update the handler in cases.go to enforce authorization by
validating or replacing body.ProjectIds with the authenticated user's allowed
project IDs (derive allowed IDs from the authenticated user context or an
authorization helper) before calling h.entity.SearchCases, or remove projectIds
from body and pass only the server-determined project scope; ensure you modify
the call site that references h.entity.SearchCases and use user (e.g.,
user.UserID or an auth helper) to compute the permitted projects and inject
those into the request payload sent to the entity.

---

Outside diff comments:
In `@apps/csm-portal/backend/openapi.yaml`:
- Around line 324-353: The OpenAPI spec for the /cases/search endpoint is
missing a 404 response even though the runtime handler SearchCases (and its test
TestSearchCases) maps upstream 404 via mapUpstreamError and asserts that
behavior; update the responses block in openapi.yaml for /cases/search to
include a "404" response with description (e.g., NotFound) and the same
ErrorPayload schema used by 400/401/403/413/500 so the contract matches runtime
behavior and tests.

---

Nitpick comments:
In `@apps/csm-portal/backend/internal/handler/cases_test.go`:
- Around line 196-257: Add a new subtest in TestSearchCases that verifies the
"no projectIds => all accessible cases" path: create a mockEntityCaseClient with
searchCasesFn capturing the forwarded body, call NewCaseHandler(...).SearchCases
with a request body that omits projectIds (e.g.,
{"stateKeys":["open"],"pagination":{"limit":10}}), assert the handler returns
http.StatusOK and "application/json", unmarshal the capturedBody and assert the
"projectIds" key is absent (or not present) in the JSON sent upstream; use the
existing decodeJSON helper and assertions consistent with the other subtests.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 06784521-6fb5-4aa9-bd5d-d796438eb31f

📥 Commits

Reviewing files that changed from the base of the PR and between 5dbd1ca and c939d48.

📒 Files selected for processing (4)
  • apps/csm-portal/backend/cmd/server/main.go
  • apps/csm-portal/backend/internal/handler/cases.go
  • apps/csm-portal/backend/internal/handler/cases_test.go
  • apps/csm-portal/backend/openapi.yaml

Comment thread apps/csm-portal/backend/internal/handler/cases.go
…s/search

Callers now pass projectIds directly in the request body instead of the
URL path. The handler is a raw passthrough — no server-side injection is
needed, so injectProjectID is removed. The OpenAPI schema is renamed
from ProjectCaseSearchPayload to CaseSearchPayload and gains a projectIds
filter field.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@Rashmika998
Rashmika998 force-pushed the task/csm-portal-cases-search branch from c939d48 to 5d3f3ec Compare June 9, 2026 16:07
@Rashmika998 Rashmika998 self-assigned this Jun 9, 2026
@Rashmika998 Rashmika998 added Type/Improvement Marks enhancements or improvements to existing features Area/Backend App/CSM Portal labels Jun 9, 2026
Rashmika998 and others added 2 commits June 9, 2026 21:38
- Add 404 response to /cases/search OpenAPI spec; mapUpstreamError can
  return it and the upstream error test table asserts this mapping
- Add TestSearchCases subtest verifying that a body without projectIds
  is forwarded unchanged (projectIds key absent upstream)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… /deployments/search

Project IDs are now passed in the request body via the existing
projectIds field in DeploymentSearchPayload. Removes the unused path
param extraction from the handler and adds 403/404 responses to
the spec (mapUpstreamError can return both).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@Rashmika998 Rashmika998 changed the title [CSM Portal] Replace POST /projects/{id}/cases/search with POST /cases/search [CSM Portal] Replace project-scoped search endpoints with flat POST /cases/search and POST /deployments/search Jun 9, 2026
@Rashmika998
Rashmika998 merged commit 532de88 into wso2-open-operations:v2 Jun 9, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

App/CSM Portal Area/Backend Type/Improvement Marks enhancements or improvements to existing features

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants