Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add backend changes for organization based subscription policies #12812

Open
wants to merge 6 commits into
base: org_visibility
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.LinkedHashSet;
Expand Down Expand Up @@ -74,6 +75,7 @@ public class API implements Serializable {
private Date lastUpdated;
private String updatedBy;
private Set<Tier> availableTiers = new LinkedHashSet<Tier>();
private Set<OrganizationTiers> availableTiersForOrganizations = new LinkedHashSet<>();
private Set<Policy> availableSubscriptionLevelPolicies = new LinkedHashSet<Policy>();
private String apiLevelPolicy;
private AuthorizationPolicy authorizationPolicy;
Expand Down Expand Up @@ -766,8 +768,47 @@ public void removeAllPolicies() {
availableSubscriptionLevelPolicies.clear();
}

public void removeAvailableTiers(Set<Tier> availableTiers) {
this.availableTiers.removeAll(availableTiers);
public Set<OrganizationTiers> getAvailableTiersForOrganizations() {
return availableTiersForOrganizations;
}

public void setAvailableTiersForOrganizations(Set<OrganizationTiers> availableTiersForOrganizations) {
this.availableTiersForOrganizations = availableTiersForOrganizations;
}

public void removeAllTiersForOrganizations() {
availableTiersForOrganizations.clear();
}

public void setAvailableTiersForOrganizationsFromString(String tiersString) {

if (tiersString == null || tiersString.isEmpty()) {
return;
}
try {
ObjectMapper objectMapper = new ObjectMapper();
OrganizationTiers[] tiersArray = objectMapper.readValue(tiersString, OrganizationTiers[].class);
availableTiersForOrganizations = new LinkedHashSet<>(Arrays.asList(tiersArray));
} catch (Exception e) {
log.error("Error while converting string to availableTiersForOrganizations object for API : " + getUUID(),
e);
}
}

public String getAvailableTiersForOrganizationsAsString() {
if (availableTiersForOrganizations == null || availableTiersForOrganizations.isEmpty()) {
return null;
}
try {
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.writeValueAsString(availableTiersForOrganizations);
} catch (JsonProcessingException e) {
log.error("Error while converting availableTiersForOrganizations to string for API : " + getUUID(), e);
return null;
} catch (Exception e) {
log.error("Unexpected error while processing availableTiersForOrganizations for API : " + getUUID(), e);
return null;
}
}

public Set<URITemplate> getUriTemplates() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
* Copyright (c) 2025, WSO2 LLC. (http://www.wso2.com) All Rights Reserved.
*
* WSO2 LLC. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.wso2.carbon.apimgt.api.model;

import java.util.Set;

/**
* This class represent Organization Tiers
*/
public class OrganizationTiers {

private String organizationID;
private String organizationName;
private Set<Tier> tiers;

public String getOrganizationID() {
return organizationID;
}

public void setOrganizationID(String organizationID) {
this.organizationID = organizationID;
}

public String getOrganizationName() {
return organizationName;
}

public void setOrganizationName(String organizationName) {
this.organizationName = organizationName;
}

public Set<Tier> getTiers() {
return tiers;
}

public void setTiers(Set<Tier> tiers) {
this.tiers = tiers;
}

public void removeAllTiers() {
tiers.clear();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ public void setMonetizationAttributes(Map<String, String> monetizationAttributes
this.monetizationAttributes = monetizationAttributes;
}

public Tier() {}

public Tier(String name) {
this.name = name;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,7 @@ public final class APIConstants {
public static final String API_OVERVIEW_THUMBNAIL_URL = "overview_thumbnail";
public static final String API_OVERVIEW_STATUS = "overview_status";
public static final String API_OVERVIEW_TIER = "overview_tier";
public static final String API_OVERVIEW_ORGANIZATION_TIERS = "overview_organizationTiers";
public static final String API_OVERVIEW_SUB_POLICY = "overview_subPolicy";
public static final String API_OVERVIEW_API_POLICY = "overview_apiPolicy";
public static final String API_OVERVIEW_IS_LATEST = "overview_isLatest";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@
import org.wso2.carbon.apimgt.api.model.OAuthAppRequest;
import org.wso2.carbon.apimgt.api.model.OAuthApplicationInfo;
import org.wso2.carbon.apimgt.api.model.OrganizationInfo;
import org.wso2.carbon.apimgt.api.model.OrganizationTiers;
import org.wso2.carbon.apimgt.api.model.ResourceFile;
import org.wso2.carbon.apimgt.api.model.Scope;
import org.wso2.carbon.apimgt.api.model.SubscribedAPI;
Expand Down Expand Up @@ -3854,7 +3855,7 @@ public Map<String, Object> searchPaginatedAPIs(String searchQuery, String organi
Map<String, Object> properties = APIUtil.getUserProperties(userName);
UserContext userCtx = new UserContext(userNameWithoutChange, org, properties, roles);

return searchPaginatedAPIs(searchQuery, start, end, org, userCtx);
return searchPaginatedAPIs(searchQuery, start, end, org, userCtx, null);
}

@Override
Expand All @@ -3867,15 +3868,20 @@ public Map<String, Object> searchPaginatedAPIs(String searchQuery, OrganizationI
UserContext userCtx = new UserContext(userNameWithoutChange,
new Organization(organizationInfo.getOrganizationId()), properties, roles);

return searchPaginatedAPIs(searchQuery, start, end, org, userCtx);
return searchPaginatedAPIs(searchQuery, start, end, org, userCtx, organizationInfo);
}

private Map<String, Object> searchPaginatedAPIs(String searchQuery, int start, int end, Organization org,
UserContext userCtx) throws APIManagementException {
UserContext userCtx, OrganizationInfo orgInfo) throws APIManagementException {
Map<String, Object> result = new HashMap<String, Object>();
if (log.isDebugEnabled()) {
log.debug("Original search query received : " + searchQuery);
}
String organizationID = null;
if (orgInfo != null) {
organizationID = APIUtil.getOrganizationIdFromExternalReference(orgInfo.getOrganizationId(),
orgInfo.getName(), tenantDomain);
}

try {
DevPortalAPISearchResult searchAPIs = apiPersistenceInstance.searchAPIsForDevPortal(org, searchQuery,
Expand All @@ -3889,6 +3895,7 @@ private Map<String, Object> searchPaginatedAPIs(String searchQuery, int start, i
List<Object> apiList = new ArrayList<>();
for (DevPortalAPIInfo devPortalAPIInfo : list) {
API mappedAPI = APIMapper.INSTANCE.toApi(devPortalAPIInfo);
APIUtil.updateAvailableTiersByOrganization(devPortalAPIInfo, organizationID);
try {
mappedAPI.setRating(APIUtil.getAverageRating(mappedAPI.getUuid()));
Set<String> tierNameSet = devPortalAPIInfo.getAvailableTierNames();
Expand Down Expand Up @@ -4034,22 +4041,37 @@ private API addTiersToAPI(API api, String organization) throws APIManagementExce
int tenantId = APIUtil.getInternalIdFromTenantDomainOrOrganization(organization);
Set<Tier> tierNames = api.getAvailableTiers();
Map<String, Tier> definedTiers = APIUtil.getTiers(tenantId);

Set<Tier> availableTiers = new HashSet<Tier>();
Set<String> deniedTiers = getDeniedTiers(tenantId);
Set<Tier> availableTiers = getAvailableTiers(tierNames, deniedTiers, definedTiers);
api.removeAllTiers();
api.addAvailableTiers(availableTiers);

if (APIUtil.isOrganizationAccessControlEnabled() && api.getAvailableTiersForOrganizations() != null) {
Set<OrganizationTiers> organizationTiersSet = api.getAvailableTiersForOrganizations();
for (OrganizationTiers organizationTiers : organizationTiersSet) {
Set<Tier> tierNamesForOrganization = organizationTiers.getTiers();
Set<Tier> availableTiersForOrganization = getAvailableTiers(tierNamesForOrganization, deniedTiers,
definedTiers);
organizationTiers.removeAllTiers();
organizationTiers.setTiers(availableTiersForOrganization);
}
}
return api;
}

private Set<Tier> getAvailableTiers(Set<Tier> tierNames, Set<String> deniedTiers, Map<String, Tier> definedTiers) {

Set<Tier> availableTiers = new HashSet<Tier>();
for (Tier tierName : tierNames) {
Tier definedTier = definedTiers.get(tierName.getName());
if (definedTier != null && (!deniedTiers.contains(definedTier.getName()))) {
availableTiers.add(definedTier);
} else {
log.warn("Unknown tier: " + tierName + " found on API: ");
log.warn("Unknown tier: " + tierName + " found");
}
}
availableTiers.removeIf(tier -> deniedTiers.contains(tier.getName()));
api.removeAllTiers();
api.addAvailableTiers(availableTiers);
return api;
return availableTiers;
}

private APIProduct addTiersToAPI(APIProduct apiProduct, String organization) throws APIManagementException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,8 @@
import org.wso2.carbon.apimgt.impl.notifier.exceptions.NotifierException;
import org.wso2.carbon.apimgt.impl.recommendationmgt.RecommendationEnvironment;
import org.wso2.carbon.apimgt.impl.resolver.OnPremResolver;
import org.wso2.carbon.apimgt.persistence.dto.DevPortalAPIInfo;
import org.wso2.carbon.apimgt.persistence.dto.OrganizationTiers;
import org.wso2.carbon.base.MultitenantConstants;
import org.wso2.carbon.base.ServerConfiguration;
import org.wso2.carbon.context.CarbonContext;
Expand Down Expand Up @@ -691,6 +693,10 @@ public static API getAPI(GovernanceArtifact artifact)
}
}

// Set available tiers for organizations
String organizationTiers = artifact.getAttribute(APIConstants.API_OVERVIEW_ORGANIZATION_TIERS);
api.setAvailableTiersForOrganizationsFromString(organizationTiers);

api.addAvailableTiers(availablePolicy);
String tenantDomainName = MultitenantUtils.getTenantDomain(replaceEmailDomainBack(providerName));
api.setMonetizationCategory(getAPIMonetizationCategory(availablePolicy, tenantDomainName));
Expand Down Expand Up @@ -815,6 +821,11 @@ public static API getLightWeightAPI(GovernanceArtifact artifact)
}
}
api.addAvailableTiers(availablePolicy);

// Set available tiers for organizations
String organizationTiers = artifact.getAttribute(APIConstants.API_OVERVIEW_ORGANIZATION_TIERS);
api.setAvailableTiersForOrganizationsFromString(organizationTiers);

String tenantDomainName = MultitenantUtils.getTenantDomain(replaceEmailDomainBack(providerName));
api.setMonetizationCategory(getAPIMonetizationCategory(availablePolicy, tenantDomainName));

Expand Down Expand Up @@ -994,6 +1005,11 @@ public static GenericArtifact createAPIArtifactContent(GenericArtifact artifact,
artifact.setAttribute(APIConstants.API_OVERVIEW_TIER, tiers);
}

if (api.getAvailableTiersForOrganizationsAsString() != null) {
artifact.setAttribute(APIConstants.API_OVERVIEW_ORGANIZATION_TIERS,
api.getAvailableTiersForOrganizationsAsString());
}

if (APIConstants.PUBLISHED.equals(apiStatus)) {
artifact.setAttribute(APIConstants.API_OVERVIEW_IS_LATEST, "true");
}
Expand Down Expand Up @@ -1050,6 +1066,7 @@ public static GenericArtifact createAPIArtifactContent(GenericArtifact artifact,
if (apiSecurity != null && !apiSecurity.contains(APIConstants.DEFAULT_API_SECURITY_OAUTH2) &&
!apiSecurity.contains(APIConstants.API_SECURITY_API_KEY)) {
artifact.setAttribute(APIConstants.API_OVERVIEW_TIER, "");
artifact.setAttribute(APIConstants.API_OVERVIEW_ORGANIZATION_TIERS, "");
}
} catch (GovernanceException e) {
String msg = "Failed to create API for : " + api.getId().getApiName();
Expand Down Expand Up @@ -2705,6 +2722,10 @@ public static API getAPI(GovernanceArtifact artifact, Registry registry, APIIden
Set<Tier> availableTier = getAvailableTiers(definedTiers, tiers, apiName);
api.addAvailableTiers(availableTier);

// Set available tiers for organizations
String organizationTiers = artifact.getAttribute(APIConstants.API_OVERVIEW_ORGANIZATION_TIERS);
api.setAvailableTiersForOrganizationsFromString(organizationTiers);

api.setContext(artifact.getAttribute(APIConstants.API_OVERVIEW_CONTEXT));
api.setContextTemplate(artifact.getAttribute(APIConstants.API_OVERVIEW_CONTEXT_TEMPLATE));
api.setLatest(Boolean.parseBoolean(artifact.getAttribute(APIConstants.API_OVERVIEW_IS_LATEST)));
Expand Down Expand Up @@ -3577,6 +3598,27 @@ public static float getAverageRating(int apiId) throws APIManagementException {
return ApiMgtDAO.getInstance().getAverageRating(apiId);
}

/**
* Update available tiers in the DevPortalAPIInfo according to the organization.
* @param devPortalAPIInfo DevPortalAPIInfo object
* @param organization Organization ID
*/
public static void updateAvailableTiersByOrganization(DevPortalAPIInfo devPortalAPIInfo, String organization) {

Set<String> availableTiers = devPortalAPIInfo.getAvailableTierNames();
Set<OrganizationTiers> availableTiersForOrganizations = devPortalAPIInfo.getAvailableTiersForOrganizations();
if (organization != null) {
for (OrganizationTiers organizationTiers : availableTiersForOrganizations) {
String orgID = organizationTiers.getOrganizationID();
if (organization.equals(orgID)) {
availableTiers = organizationTiers.getTiers();
break;
}
}
}
devPortalAPIInfo.setAvailableTierNames(availableTiers);
}

public static List<Tenant> getAllTenantsWithSuperTenant() throws UserStoreException {

Tenant[] tenants = ServiceReferenceHolder.getInstance().getRealmService().getTenantManager().getAllTenants();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ public final class APIConstants {
public static final String API_OVERVIEW_THUMBNAIL_URL = "overview_thumbnail";
public static final String API_OVERVIEW_STATUS = "overview_status";
public static final String API_OVERVIEW_TIER = "overview_tier";
public static final String API_OVERVIEW_ORGANIZATION_TIERS = "overview_organizationTiers";
public static final String API_OVERVIEW_SUB_POLICY = "overview_subPolicy";
public static final String API_OVERVIEW_API_POLICY = "overview_apiPolicy";
public static final String API_OVERVIEW_IS_LATEST = "overview_isLatest";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1292,6 +1292,9 @@ private DevPortalAPISearchResult searchPaginatedDevPortalAPIs(Registry userRegis
}
}
apiInfo.setAvailableTierNames(availableTiers);
// Set available tiers for organizations
String organizationTiers = artifact.getAttribute(APIConstants.API_OVERVIEW_ORGANIZATION_TIERS);
apiInfo.setAvailableTiersForOrganizationsFromString(organizationTiers);
apiInfo.setSubscriptionAvailability(
artifact.getAttribute(APIConstants.API_OVERVIEW_SUBSCRIPTION_AVAILABILITY));
apiInfo.setSubscriptionAvailableOrgs(
Expand Down
Loading