From a7d7fef8ea2237f0859901a9ab3c03d38f6b849d Mon Sep 17 00:00:00 2001 From: chashikajw Date: Mon, 9 Oct 2023 17:47:19 +0530 Subject: [PATCH] Fix issues with revamp swagger --- .../ballerina/tests/apiTests.bal | 2 +- .../ballerina/tests/internalAPITests.bal | 5 +- .../ballerina/apiDAO.bal | 12 +-- .../ballerina/apiImpl.bal | 21 +++-- .../ballerina/applicationDAO.bal | 6 +- .../ballerina/applicationImpl.bal | 28 +++---- .../ballerina/devportal-api_service.bal | 80 +------------------ .../ballerina/resources/devportal-api.yaml | 3 + .../ballerina/subscriptionImpl.bal | 5 +- .../ballerina/types.bal | 5 +- 10 files changed, 50 insertions(+), 117 deletions(-) diff --git a/backoffice/backoffice-domain-service/ballerina/tests/apiTests.bal b/backoffice/backoffice-domain-service/ballerina/tests/apiTests.bal index f2777ff882..11a4f341b9 100644 --- a/backoffice/backoffice-domain-service/ballerina/tests/apiTests.bal +++ b/backoffice/backoffice-domain-service/ballerina/tests/apiTests.bal @@ -47,7 +47,7 @@ function getAPIByIdTest() { @test:Config {dependsOn: [createAPITest]} function getAPIDefinitionTest() { APIDefinition|commons:APKError getAPIDef = getAPIDefinition("01ed75e2-b30b-18c8-wwf2-25da7edd2231"); - if getAPIDef is API { + if getAPIDef is APIDefinition { test:assertTrue(true, "Successfully retrieve API Definition"); log:printInfo(getAPIDef.toString()); } else if getAPIDef is commons:APKError { diff --git a/backoffice/backoffice-domain-service/ballerina/tests/internalAPITests.bal b/backoffice/backoffice-domain-service/ballerina/tests/internalAPITests.bal index 63a48a6ebe..2a979195c0 100644 --- a/backoffice/backoffice-domain-service/ballerina/tests/internalAPITests.bal +++ b/backoffice/backoffice-domain-service/ballerina/tests/internalAPITests.bal @@ -116,6 +116,8 @@ public function getApiDataProvider() returns map<[string, string, anydata]> { "context": "pizzssa", "version": "1.0.0", "organization": "1111-1111-1111-1111", + "lifeCycleStatus" : (), + "provider": (), "type": "HTTP", "state": "CREATED", "status": "CREATED" @@ -135,7 +137,8 @@ function updateInternalAPITest() { "version":"1.0.0", "lifeCycleStatus":"CREATED", "organization":"1111-1111-1111-1111", - "type":"HTTP" + "type":"HTTP", + "provider":"admin" }, "Definition" : { "openapi": "3.0.0", diff --git a/devportal/devportal-domain-service/ballerina/apiDAO.bal b/devportal/devportal-domain-service/ballerina/apiDAO.bal index 9de3af9491..a18f7e2d63 100644 --- a/devportal/devportal-domain-service/ballerina/apiDAO.bal +++ b/devportal/devportal-domain-service/ballerina/apiDAO.bal @@ -50,7 +50,7 @@ isolated function getAPIByIdDAO(string apiId) returns API|commons:APKError|NotFo } } -isolated function getAPIsDAO(string org) returns API[]|commons:APKError { +isolated function getAPIsDAO(string org) returns APIInfo[]|commons:APKError { postgresql:Client | error dbClient = getConnection(); if dbClient is error { string message = "Error while retrieving connection"; @@ -61,8 +61,8 @@ isolated function getAPIsDAO(string org) returns API[]|commons:APKError { API_NAME as NAME, API_VERSION as VERSION,CONTEXT, ORGANIZATION,STATUS, API_TYPE as TYPE, ARTIFACT as ARTIFACT FROM API WHERE ORGANIZATION =${org} AND STATUS IN (${PUBLISHED},${PROTOTYPED},${DEPRECATED})`; - stream apisStream = dbClient->query(query); - API[] apis = check from API api in apisStream select api; + stream apisStream = dbClient->query(query); + APIInfo[] apis = check from APIInfo api in apisStream select api; check apisStream.close(); return apis; } on fail var e { @@ -72,7 +72,7 @@ isolated function getAPIsDAO(string org) returns API[]|commons:APKError { } } -isolated function getAPIsByQueryDAO(string payload, string org) returns API[]|commons:APKError { +isolated function getAPIsByQueryDAO(string payload, string org) returns APIInfo[]|commons:APKError { postgresql:Client | error dbClient = getConnection(); if dbClient is error { string message = "Error while retrieving connection"; @@ -84,8 +84,8 @@ isolated function getAPIsByQueryDAO(string payload, string org) returns API[]|co API_TYPE as TYPE, ARTIFACT as ARTIFACT FROM API JOIN JSONB_EACH_TEXT(ARTIFACT) e ON true WHERE ORGANIZATION =${org} AND e.value LIKE ${payload} AND STATUS IN (${PUBLISHED},${PROTOTYPED},${DEPRECATED})`; - stream apisStream = dbClient->query(query); - API[] apis = check from API api in apisStream select api; + stream apisStream = dbClient->query(query); + APIInfo[] apis = check from APIInfo api in apisStream select api; check apisStream.close(); return apis; } on fail var e { diff --git a/devportal/devportal-domain-service/ballerina/apiImpl.bal b/devportal/devportal-domain-service/ballerina/apiImpl.bal index 628caa18a5..24db3e02b6 100644 --- a/devportal/devportal-domain-service/ballerina/apiImpl.bal +++ b/devportal/devportal-domain-service/ballerina/apiImpl.bal @@ -30,9 +30,9 @@ isolated function getAPIByAPIId(string apiId) returns API|NotFoundError|commons: isolated function getAPIList(int 'limit, int offset, string? query, commons:Organization organization) returns APIList|commons:APKError { if query !is string { - API[]|commons:APKError apis = getAPIsDAO(organization.uuid); - if apis is API[] { - API[] limitSet = []; + APIInfo[]|commons:APKError apis = getAPIsDAO(organization.uuid); + if apis is APIInfo[] { + APIInfo[] limitSet = []; if apis.length() > offset { foreach int i in offset ... (apis.length() - 1) { if limitSet.length() < 'limit { @@ -51,9 +51,9 @@ isolated function getAPIList(int 'limit, int offset, string? query, commons:Orga int? index = query.indexOf(":"); if index is int { string modifiedQuery = "%" + query.substring(index + 1) + "%"; - API[]|commons:APKError apis = getAPIsByQueryDAO(modifiedQuery, organization.uuid); - if apis is API[] { - API[] limitSet = []; + APIInfo[]|commons:APKError apis = getAPIsByQueryDAO(modifiedQuery, organization.uuid); + if apis is APIInfo[] { + APIInfo[] limitSet = []; if apis.length() > offset { foreach int i in offset ... (apis.length() - 1) { if limitSet.length() < 'limit { @@ -181,9 +181,9 @@ isolated function getDocumentMetaData(string apiId, string documentId) returns D documentId: getDocumentMetaData.documentId, name: getDocumentMetaData.name, summary: getDocumentMetaData.summary, - sourceType: getDocumentMetaData.sourceType, + sourceType: <"INLINE"|"MARKDOWN"|"URL"|"FILE">getDocumentMetaData.sourceType, sourceUrl: getDocumentMetaData.sourceUrl, - documentType: getDocumentMetaData.documentType, + documentType: <"HOWTO"|"SAMPLES"|"PUBLIC_FORUM"|"SUPPORT_FORUM"|"API_MESSAGE_FORMAT"|"SWAGGER_DOC"|"OTHER">getDocumentMetaData.documentType, otherTypeName: getDocumentMetaData.otherTypeName }; return document; @@ -241,8 +241,7 @@ isolated function getDocumentList(string apiId, int 'limit, int offset) returns } else { return documents; } - } else { - string message = "Internal Error occured while retrieving API for Docuements retieval"; - return error(message, message = message, description = message, code = 909001, statusCode = 500); + } else if api is NotFoundError|commons:APKError { + return api; } } diff --git a/devportal/devportal-domain-service/ballerina/applicationDAO.bal b/devportal/devportal-domain-service/ballerina/applicationDAO.bal index a25d9df3aa..e24aa1a75e 100644 --- a/devportal/devportal-domain-service/ballerina/applicationDAO.bal +++ b/devportal/devportal-domain-service/ballerina/applicationDAO.bal @@ -110,7 +110,7 @@ isolated function getApplicationByIdDAO(string appId, string org) returns Applic } } -isolated function getApplicationsDAO(string org) returns Application[]|commons:APKError { +isolated function getApplicationsDAO(string org) returns ApplicationInfo[]|commons:APKError { postgresql:Client|error dbClient = getConnection(); if dbClient is error { string message = "Error while retrieving connection"; @@ -119,8 +119,8 @@ isolated function getApplicationsDAO(string org) returns Application[]|commons:A do { sql:ParameterizedQuery query = `SELECT NAME, UUID as APPLICATIONID, DESCRIPTION, APPLICATION_TIER as THROTTLINGPOLICY, TOKEN_TYPE as TOKENTYPE, ORGANIZATION, APPLICATION_STATUS as STATUS FROM APPLICATION WHERE ORGANIZATION =${org}`; - stream applicationStream = dbClient->query(query); - Application[] applications = check from Application application in applicationStream + stream applicationStream = dbClient->query(query); + ApplicationInfo[] applications = check from ApplicationInfo application in applicationStream select application; check applicationStream.close(); return applications; diff --git a/devportal/devportal-domain-service/ballerina/applicationImpl.bal b/devportal/devportal-domain-service/ballerina/applicationImpl.bal index 2f4f2386de..9612bdab1c 100644 --- a/devportal/devportal-domain-service/ballerina/applicationImpl.bal +++ b/devportal/devportal-domain-service/ballerina/applicationImpl.bal @@ -15,14 +15,14 @@ // specific language governing permissions and limitations // under the License. // - import ballerina/log; +import ballerina/time; import ballerina/uuid; + import wso2/apk_common_lib as commons; import wso2/notification_grpc_client; import devportal_service.types; import devportal_service.kmclient; -import ballerina/time; isolated function addApplication(Application application, commons:Organization org, string user) returns NotFoundError|Application|commons:APKError { string applicationId = uuid:createType1AsString(); @@ -98,8 +98,8 @@ isolated function getApplicationById(string appId, commons:Organization org) ret } isolated function getApplicationList(string? sortBy, string? groupId, string? query, string? sortOrder, int 'limit, int offset, commons:Organization org) returns ApplicationList|commons:APKError { - Application[]|commons:APKError applications = getApplicationsDAO(org.uuid); - if applications is Application[] { + ApplicationInfo[]|commons:APKError applications = getApplicationsDAO(org.uuid); + if applications is ApplicationInfo[] { int count = applications.length(); ApplicationList applicationsList = {count: count, list: applications}; return applicationsList; @@ -199,9 +199,8 @@ isolated function deleteOauthApps(string appId, commons:Organization organizatio isolated function generateAPIKey(APIKeyGenerateRequest payload, string appId, string keyType, string user, commons:Organization org) returns APIKey|commons:APKError|NotFoundError { Application|NotFoundError application = check getApplicationById(appId, org); - if application !is Application { - string message = "Internal Error occured while retrieving Application Info for API Key"; - return error(message, message = message, description = message, code = 909001, statusCode = 500); + if application is NotFoundError { + return application; } else { boolean userAllowed = checkUserAccessAllowedForApplication(application, user); if userAllowed { @@ -245,7 +244,7 @@ isolated function generateAPIKey(APIKeyGenerateRequest payload, string appId, st } } } - APIKey|commons:APKError apiKey = generateAPIKeyForApplication(user, application, apiList, keyType, validityPeriod, addProperties); + APIKey|commons:APKError apiKey = generateAPIKeyForApplication(user, application, apiList, keyType, validityPeriod, addProperties); return apiKey; } else { string message = "User:" + user + " doesn't have permission to Application with application id:" + appId; @@ -295,7 +294,7 @@ isolated function retrieveManagementServerHostsList() returns string[]|commons:A public isolated function generateKeysForApplication(Application application, ApplicationKeyGenerateRequest applicationKeyGenRequest, commons:Organization organization) returns OkApplicationKey|commons:APKError { string? keyManager = applicationKeyGenRequest.keyManager; if keyManager is string { - if check isKeyMappingEntryByApplicationAndKeyManagerExist(application.applicationId, keyManager,applicationKeyGenRequest.keyType) { + if check isKeyMappingEntryByApplicationAndKeyManagerExist(application.applicationId, keyManager, applicationKeyGenRequest.keyType) { return error("Key Mapping Entry already exists for application " + application.name + " and keyManager " + keyManager, message = "Key Mapping Entry already exists for application " + application.name + " and keyManager " + keyManager, description = "Key Mapping Entry already exists for application " + application.name + " and keyManager " + keyManager, code = 900950, statusCode = 400); } KeyManagerDaoEntry keyManagerById = check getKeyManagerById(keyManager, organization); @@ -439,8 +438,8 @@ isolated function fromKeyMappingDaoEntryToApplicationKey(types:KeyMappingDaoEntr keyMappingId: item.uuid, consumerKey: item.consumer_key, keyManager: item.key_manager_uuid, - keyType: item.key_type, - mode: item.create_mode, + keyType: <"PRODUCTION"|"SANDBOX">item.key_type, + mode: <"MAPPED"|"CREATED">item.create_mode, keyState: "CREATED" }; if oauthAppResponse is kmclient:ClientRegistrationResponse { @@ -527,18 +526,19 @@ public isolated function updateOauthApp(Application application, string keyMappi types:KeyMappingDaoEntry updatedKeyMappingentry = keyMappingEntry.clone(); updatedKeyMappingentry.app_info = oauthApplicationByClientId.toJsonString().toBytes(); check updateKeyMappingEntry(updatedKeyMappingentry); - return { + ApplicationKey applicationKey = { keyMappingId: keyMappingEntry.uuid, consumerKey: oauthApplicationByClientId.client_id, consumerSecret: oauthApplicationByClientId.client_secret, keyManager: keyMappingEntry.key_manager_uuid, - keyType: keyMappingEntry.key_type, - mode: keyMappingEntry.create_mode, + keyType: <"PRODUCTION"|"SANDBOX">keyMappingEntry.key_type, + mode: <"MAPPED"|"CREATED">keyMappingEntry.create_mode, keyState: "CREATED", callbackUrls: oauthApplicationByClientId.redirect_uris, supportedGrantTypes: oauthApplicationByClientId.grant_types, additionalProperties: oauthApplicationByClientId.additional_properties }; + return applicationKey; } else { return error("Key Manager is disabled", message = "Key Manager is disabled", description = "Key Manager is disabled", code = 900951, statusCode = 400); } diff --git a/devportal/devportal-domain-service/ballerina/devportal-api_service.bal b/devportal/devportal-domain-service/ballerina/devportal-api_service.bal index 207cbae728..0495ae8f26 100644 --- a/devportal/devportal-domain-service/ballerina/devportal-api_service.bal +++ b/devportal/devportal-domain-service/ballerina/devportal-api_service.bal @@ -757,89 +757,17 @@ isolated service http:InterceptableService /api/devportal on ep0 { string|json sdkLanguages = check getSDKLanguages(); return sdkLanguages; } - # Get available web hook subscriptions for a given application. - # - # + applicationId - **Application Identifier** consisting of the UUID of the Application. - # + apiId - **API ID** consisting of the **UUID** of the API. - # + 'x\-wso2\-tenant - For cross-tenant invocations, this is used to specify the tenant/organization domain, where the resource need to be retrieved from. - # + return - returns can be any of following types - # WebhookSubscriptionList (OK. Topic list returned.) - # NotFoundError (Not Found. The specified resource does not exist.) - # InternalServerErrorError (Internal Server Error.) - // resource function get webhooks/subscriptions(string? applicationId, string? apiId, @http:Header string? 'x\-wso2\-tenant) returns WebhookSubscriptionList|NotFoundError|InternalServerErrorError { - // } - # Retrieve Developer Portal settings - # - # + 'x\-wso2\-tenant - For cross-tenant invocations, this is used to specify the tenant/organization domain, where the resource need to be retrieved from. - # + return - returns can be any of following types - # Settings (OK. Settings returned) - # NotFoundError (Not Found. The specified resource does not exist.) - // resource function get settings(@http:Header string? 'x\-wso2\-tenant) returns Settings|NotFoundError { - // } - # Get All Application Attributes from Configuration - # - # + 'if\-none\-match - Validator for conditional requests; based on the ETag of the formerly retrieved variant of the resource. - # + return - returns can be any of following types - # ApplicationAttributeList (OK. Application attributes returned.) - # NotFoundError (Not Found. The specified resource does not exist.) - # NotAcceptableError (Not Acceptable. The requested media type is not supported.) - // resource function get settings/'application\-attributes(@http:Header string? 'if\-none\-match) returns ApplicationAttributeList|NotFoundError|NotAcceptableError { - // } - # Get Tenants by State - # - # + state - The state represents the current state of the tenant - # + 'limit - Maximum size of resource array to return. - # + offset - Starting point within the complete list of items qualified. - # + return - returns can be any of following types - # TenantList (OK. Tenant names returned.) - # NotFoundError (Not Found. The specified resource does not exist.) - # NotAcceptableError (Not Acceptable. The requested media type is not supported.) - // resource function get tenants(string state = "active", int 'limit = 25, int offset = 0) returns TenantList|NotFoundError|NotAcceptableError { - // } - # Give API Recommendations for a User - # - # + return - returns can be any of following types - # Recommendations (OK. Requested recommendations are returned) - # NotFoundError (Not Found. The specified resource does not exist.) - // resource function get recommendations() returns Recommendations|NotFoundError { - // } # Get All API Categories # # + 'x\-wso2\-tenant - For cross-tenant invocations, this is used to specify the tenant/organization domain, where the resource need to be retrieved from. # + return - OK. Categories returned - // resource function get 'api\-categories(@http:Header string? 'x\-wso2\-tenant) returns APICategoryList { - // } + resource function get 'api\-categories(@http:Header string? 'x\-wso2\-tenant) returns APICategoryList { + } + # Get All Key Managers # # + 'x\-wso2\-tenant - For cross-tenant invocations, this is used to specify the tenant/organization domain, where the resource need to be retrieved from. # + return - OK. Key Manager list returned - // resource function get 'key\-managers(@http:Header string? 'x\-wso2\-tenant) returns KeyManagerList { - // } - # Get the Complexity Related Details of an API - # - # + apiId - **API ID** consisting of the **UUID** of the API. - # + return - returns can be any of following types - # GraphQLQueryComplexityInfo (OK. Requested complexity details returned.) - # http:NotFound (Not Found. Requested API does not contain any complexity details.) - // resource function get apis/[string apiId]/'graphql\-policies/complexity() returns GraphQLQueryComplexityInfo|http:NotFound { - // } - # Retrieve Types and Fields of a GraphQL Schema - # - # + apiId - **API ID** consisting of the **UUID** of the API. - # + return - returns can be any of following types - # GraphQLSchemaTypeList (OK. Types and fields returned successfully.) - # http:NotFound (Not Found. Retrieving types and fields failed.) - // resource function get apis/[string apiId]/'graphql\-policies/complexity/types() returns GraphQLSchemaTypeList|http:NotFound { - // } - # Change the Password of the user - # - # + payload - Current and new password of the user - # + return - returns can be any of following types - # http:Ok (OK. User password changed successfully) - # BadRequestError (Bad Request. Invalid request or validation error.) - isolated resource function post me/'change\-password(@http:Payload CurrentAndNewPasswords payload) returns http:Ok|BadRequestError { - BadRequestError badRequest = {body: {code: 400, message: "Invalid request or validation error."}}; - return badRequest; + resource function get 'key\-managers(@http:Header string? 'x\-wso2\-tenant) returns KeyManagerList { } - } diff --git a/devportal/devportal-domain-service/ballerina/resources/devportal-api.yaml b/devportal/devportal-domain-service/ballerina/resources/devportal-api.yaml index d9a5cff3b5..15b460460f 100644 --- a/devportal/devportal-domain-service/ballerina/resources/devportal-api.yaml +++ b/devportal/devportal-domain-service/ballerina/resources/devportal-api.yaml @@ -2883,6 +2883,9 @@ components: - REJECTED - TIER_UPDATE_PENDING - DELETE_PENDING + subscriptionCreateState: + type: string + example: CREATED redirectionParams: type: string description: A url and other parameters the subscriber can be redirected. diff --git a/devportal/devportal-domain-service/ballerina/subscriptionImpl.bal b/devportal/devportal-domain-service/ballerina/subscriptionImpl.bal index 67d7ed4c2b..1a5567153c 100644 --- a/devportal/devportal-domain-service/ballerina/subscriptionImpl.bal +++ b/devportal/devportal-domain-service/ballerina/subscriptionImpl.bal @@ -250,9 +250,8 @@ isolated function getSubscriptions(string? apiId, string? applicationId, string? int count = subs.length(); SubscriptionList subList = {count: count, list: subs}; return subList; - } else { - string message = "Internal Error occured while retrieving Subscription"; - return error(message, message = message, description = message, code = 909001, statusCode = 500); + } else if subscription is NotFoundError { + return subscription; } } else if apiId is string { // Retrieve Subscriptions per given API Id diff --git a/devportal/devportal-domain-service/ballerina/types.bal b/devportal/devportal-domain-service/ballerina/types.bal index 5cf670c2ab..1fbf782c18 100644 --- a/devportal/devportal-domain-service/ballerina/types.bal +++ b/devportal/devportal-domain-service/ballerina/types.bal @@ -196,7 +196,7 @@ public type ScopeList record { public type APIList record { # Number of APIs returned. int count?; - API[] list?; + APIInfo[] list?; Pagination pagination?; }; @@ -229,6 +229,7 @@ public type Subscription record { APIInfo apiInfo?; ApplicationInfo applicationInfo?; "BLOCKED"|"PROD_ONLY_BLOCKED"|"UNBLOCKED"|"ON_HOLD"|"REJECTED"|"TIER_UPDATE_PENDING"|"DELETE_PENDING" status?; + string subscriptionCreateState?; # A url and other parameters the subscriber can be redirected. string redirectionParams?; }; @@ -517,7 +518,7 @@ public type KeyManagerApplicationConfiguration record { public type ApplicationList record { # Number of applications returned. int count?; - Application[] list?; + ApplicationInfo[] list?; Pagination pagination?; };