Skip to content

[Customer Portal][BE] Add APIs to Fetch Project Deployments and Deployed Products for Case Creation - #108

Merged
shayanmalinda merged 10 commits into
wso2-open-operations:customer-portal-milestone-1from
Rashmika998:customer-portal-milestone-1-case-creation
Feb 10, 2026
Merged

shayanmalinda merged 10 commits into
wso2-open-operations:customer-portal-milestone-1from
Rashmika998:customer-portal-milestone-1-case-creation

Conversation

@Rashmika998

@Rashmika998 Rashmika998 commented Feb 10, 2026 •

Copy link
Copy Markdown
Contributor

Description

This PR adds new backend endpoints to fetch project deployments and deployed products, which are required for the Case Creation flow in the Customer Portal.

These APIs allow users to select the relevant deployment and product when creating a case, ensuring accurate case association.

The implementation follows existing API standards for validation, security, and response handling.

Endpoints Added

  • GET /projects/{projectId}/deployments
  • GET projects/{projectId}/deployments/{deploymentId}/products

Changes Introduced

  • Implemented APIs to retrieve deployments for a given project.
  • Implemented APIs to retrieve deployed products under a deployment.
  • Applied authentication and authorization checks.
  • Added input validation for request parameters.
  • Standardized response formats.
  • Improved error handling and logging.

Scope

  • Supports Case Creation workflow.
  • Enables selection of deployment and deployed product.
  • Enforces access control.
  • Ensures reliable data retrieval.

Testing

  • Verified fetching deployments for valid projects.
  • Verified fetching deployed products for valid deployments.
  • Tested invalid project/deployment IDs.
  • Tested unauthorized access scenarios.
  • Validated error handling behavior.

Related Issues

Related PRs

Summary by CodeRabbit

  • New Features
    • Added endpoints to list project deployments and deployed products for a deployment.
    • Responses now include structured deployment and deployed-product details and mapped fields for easier consumption.
  • Bug Fixes / Reliability
    • Added input validation, consistent error handling, and improved logging for both endpoints.

@coderabbitai

coderabbitai Bot commented Feb 10, 2026 •

Copy link
Copy Markdown
Contributor

Warning

Rate limit exceeded

@Rashmika998 has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 0 minutes and 7 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📝 Walkthrough

Walkthrough

Added entity client functions and DTOs plus mapping utilities, and exposed two HTTP GET endpoints to fetch project deployments and deployed products; endpoints validate input, extract user info, call entity functions, and return mapped responses or HTTP errors.

Changes

Cohort / File(s) Summary
Entity module
apps/customer-portal/backend/modules/entity/entity.bal, apps/customer-portal/backend/modules/entity/types.bal
Added getDeployments(idToken, projectId) and getDeployedProducts(idToken, deploymentId) client functions and new record types: Deployment, DeploymentsResponse, DeployedProduct, DeployedProductsResponse.
Service API endpoints & types
apps/customer-portal/backend/service.bal, apps/customer-portal/backend/types.bal
Added GET resources projects/[id]/deployments and deployments/[id]/products with user-info extraction, input validation, entity calls, mapping, and explicit BAD_REQUEST/FORBIDDEN/INTERNAL_SERVER_ERROR responses; added corresponding response types.
Mapping utilities
apps/customer-portal/backend/utils.bal
Added mapDeployments and mapDeployedProducts functions to transform entity responses into service-layer response shapes (map nested reference fields).

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Service as Customer-Portal Service
    participant Entity as Entity Module
    participant API as Entity Backend API

    Client->>Service: GET /projects/{id}/deployments
    Service->>Service: extract user-info, validate id
    Service->>Entity: getDeployments(idToken, projectId)
    Entity->>API: POST /deployments/search (filters: {projectIds: [projectId]})
    API-->>Entity: DeploymentsResponse
    Entity-->>Service: DeploymentsResponse
    Service->>Service: mapDeployments(...)
    Service-->>Client: 200 DeploymentsResponse

    Client->>Service: GET /deployments/{id}/products
    Service->>Service: extract user-info, validate id
    Service->>Entity: getDeployedProducts(idToken, deploymentId)
    Entity->>API: POST /deployed_products/search (payload: {deploymentId})
    API-->>Entity: DeployedProductsResponse
    Entity-->>Service: DeployedProductsResponse
    Service->>Service: mapDeployedProducts(...)
    Service-->>Client: 200 DeployedProductsResponse
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related issues

  • Issue #107: Implements the backend functions, types, and endpoints to fetch project deployments and deployed products described in the issue.

Possibly related PRs

  • PR #68: Introduced similar service endpoint patterns and FORBIDDEN handling conventions used by these new endpoints.

Suggested labels

Type/Improvement

Suggested reviewers

  • cloby99
  • shayanmalinda
  • yuk7hi

Poem

🐰 Hopping through the tree of code tonight,

I fetch deployments with a joyful bite,
DTOs in order, endpoints in line,
Mapped responses shining, tidy and fine,
A little rabbit cheers — the APIs take flight!

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Description check ❓ Inconclusive The PR description covers key sections including purpose, endpoints added, changes introduced, scope, testing, and related issues/PRs, but omits several required template sections like Goals, Approach, Release notes, Documentation, and others. Consider adding or clarifying missing sections from the template: Goals (explicit problem-solution mapping), Approach (implementation details), Release notes, Documentation impact, and others as applicable to the PR scope.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main change: adding APIs to fetch project deployments and deployed products for case creation in the customer portal backend.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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: 2

🤖 Fix all issues with AI agents
In `@apps/customer-portal/backend/service.bal`:
- Around line 309-349: The deployments endpoint resource function get
projects/[string id]/deployments currently returns
DeploymentsResponse|http:BadRequest|http:Forbidden|http:InternalServerError but
does not handle http:STATUS_UNAUTHORIZED from entity:getDeployments; update the
function signature to include http:Unauthorized and add a branch after the
forbidden check that uses getStatusCode(deploymentsResponse) ==
http:STATUS_UNAUTHORIZED to log the unauthorized case (similar to
logForbiddenProjectAccess pattern or other endpoints) and return an
<http:Unauthorized> response with an appropriate message constant (e.g.,
ERR_MSG_PROJECT_ACCESS_UNAUTHORIZED) so 401s are handled explicitly rather than
falling through to InternalServerError.
- Around line 356-397: The endpoint currently calls
entity:getDeployedProducts(deploymentId) without scoping to projectId — fix by
first calling a deployment lookup (e.g., entity:getDeployment(deploymentId) or
an equivalent service) and verify the returned deployment.projectId matches the
route projectId; if it doesn't, call logForbiddenProjectAccess(projectId,
userInfo.userId) and return <http:Forbidden> with
ERR_MSG_PROJECT_ACCESS_FORBIDDEN. Alternatively, update
entity:getDeployedProducts to accept projectId and enforce the scope there. Also
handle authorization errors from entity calls by checking getStatusCode(...) ==
http:STATUS_UNAUTHORIZED and returning <http:Unauthorized> where appropriate.
Ensure you reference entity:getDeployedProducts, entity:getDeployment (or the
service that validates ownership), logForbiddenProjectAccess,
mapDeployedProducts, and getStatusCode in your changes.
🧹 Nitpick comments (1)
apps/customer-portal/backend/utils.bal (1)

224-225: Unnecessary .toString() on deployment.id — it's already a string.

entity:ReferenceTableItem.id is typed as string, so .toString() is redundant. Compare with line 202 where project.id (same type) is used directly without .toString(). This should be consistent.

Suggested fix
-            deployment: deployment != () ? {id: deployment.id.toString(), label: deployment.name} : ()
+            deployment: deployment != () ? {id: deployment.id, label: deployment.name} : ()

Comment thread apps/customer-portal/backend/service.bal
Comment thread apps/customer-portal/backend/service.bal Outdated
@Rashmika998
Rashmika998 requested a review from cloby99 February 10, 2026 06:46
@Rashmika998
Rashmika998 force-pushed the customer-portal-milestone-1-case-creation branch from 791f9c1 to 2495fa7 Compare February 10, 2026 08:18

@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: 2

🤖 Fix all issues with AI agents
In `@apps/customer-portal/backend/service.bal`:
- Around line 954-955: Rename the misspelled variable customeErr to customError
and update all usages accordingly (e.g., change log:printWarn(customeErr) to
log:printWarn(customError)) so the naming is consistent with other endpoints;
make sure the string interpolation stays the same and no other references to
customeErr remain.
- Around line 930-931: Update the resource function get deployments/[string
id]/products to include http:Unauthorized in its return union and add a branch
that checks for ctx.request.httpStatus == STATUS_UNAUTHORIZED (or equivalent
constant) that returns http:Unauthorized before the existing STATUS_FORBIDDEN
handling; modify the signature
(DeployedProductsResponse|http:BadRequest|http:Forbidden|http:InternalServerError
-> include http:Unauthorized) and add the corresponding STATUS_UNAUTHORIZED case
in the same authorization/error-check sequence used by the deployments endpoint
to keep behavior consistent.
🧹 Nitpick comments (2)
apps/customer-portal/backend/service.bal (2)

942-948: Use a named constant for the deployment ID validation message.

Line 945 uses a hardcoded string "Deployment ID cannot be empty!" while sibling endpoints use constants like ERR_MSG_PROJECT_ID_EMPTY and ERR_MSG_CASE_ID_EMPTY. Define and use an ERR_MSG_DEPLOYMENT_ID_EMPTY constant for consistency.

Suggested fix
         if isEmptyId(id) {
             return <http:BadRequest>{
                 body: {
-                    message: "Deployment ID cannot be empty!"
+                    message: ERR_MSG_DEPLOYMENT_ID_EMPTY
                 }
             };
         }

956-961: Use a named constant for the forbidden-access message.

Line 958's "Access to the requested deployment is forbidden!" is an inline string. Other endpoints use constants like ERR_MSG_PROJECT_ACCESS_FORBIDDEN and ERR_MSG_CASE_ACCESS_FORBIDDEN. Consider introducing ERR_MSG_DEPLOYMENT_ACCESS_FORBIDDEN for consistency and easier maintenance.

Comment thread apps/customer-portal/backend/service.bal Outdated
Comment thread apps/customer-portal/backend/service.bal Outdated
@Rashmika998
Rashmika998 force-pushed the customer-portal-milestone-1-case-creation branch from 1c3fdff to dff0331 Compare February 10, 2026 08:23
@Rashmika998 Rashmika998 moved this from Todo to In Progress in Customer Portal Development Feb 10, 2026

@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

🤖 Fix all issues with AI agents
In `@apps/customer-portal/backend/utils.bal`:
- Around line 211-226: In mapDeployedProducts (returning
DeployedProductsResponse) remove the redundant .toString() call on deployment.id
so the mapping uses deployment.id directly (ReferenceTableItem.id is already a
string); update the select block where deployment is constructed to use {id:
deployment.id, label: deployment.name} to match the productModel mapping and
other ReferenceTableItem usages.
🧹 Nitpick comments (1)
apps/customer-portal/backend/service.bal (1)

942-960: Inline error strings break consistency with sibling endpoints.

Other endpoints use named constants for error messages (e.g., ERR_MSG_PROJECT_ID_EMPTY, ERR_MSG_CASE_ID_EMPTY, ERR_MSG_PROJECT_ACCESS_FORBIDDEN). This endpoint uses inline string literals at lines 945 and 957. Extract these into constants for consistency and maintainability.

Suggested approach

Define constants (in the same location as the existing ones):

const string ERR_MSG_DEPLOYMENT_ID_EMPTY = "Deployment ID cannot be empty!";
const string ERR_MSG_DEPLOYMENT_ACCESS_FORBIDDEN = "Access to the requested deployment is forbidden!";

Then reference them in this endpoint:

-                    message: "Deployment ID cannot be empty!"
+                    message: ERR_MSG_DEPLOYMENT_ID_EMPTY
-                    message: "Access to the requested deployment is forbidden!"
+                    message: ERR_MSG_DEPLOYMENT_ACCESS_FORBIDDEN

Comment thread apps/customer-portal/backend/utils.bal
Comment thread apps/customer-portal/backend/service.bal
@Rashmika998
Rashmika998 force-pushed the customer-portal-milestone-1-case-creation branch from f2ebfe8 to a8efcb9 Compare February 10, 2026 17:57
Comment thread apps/customer-portal/backend/service.bal Outdated
Comment thread apps/customer-portal/backend/utils.bal Outdated
Comment thread apps/customer-portal/backend/utils.bal Outdated
Comment thread apps/customer-portal/backend/types.bal Outdated
Comment thread apps/customer-portal/backend/types.bal Outdated
Comment thread apps/customer-portal/backend/types.bal Outdated
@Rashmika998
Rashmika998 force-pushed the customer-portal-milestone-1-case-creation branch from 512968d to 8892128 Compare February 10, 2026 18:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

App/Customer Portal Area/Backend Type/Task General task that does not fit into other categories

Projects

Status: Staging Deployed

Development

Successfully merging this pull request may close these issues.

2 participants