From 64fcf9d0ab6babb640b0fe6f9695f90475007afe Mon Sep 17 00:00:00 2001 From: James Elson Date: Mon, 11 Mar 2024 13:44:44 -0700 Subject: [PATCH 1/9] Added Application and Application Owner as metadata to the Consumer record --- src/services/kong/consumer-service.ts | 13 +++++++++---- src/services/workflow/create-service-account.ts | 6 +++++- src/services/workflow/generate-credential.ts | 8 ++++++-- src/services/workflow/kong-api-key.ts | 5 +++-- src/services/workflow/link-consumer-to-namespace.ts | 1 + 5 files changed, 24 insertions(+), 9 deletions(-) diff --git a/src/services/kong/consumer-service.ts b/src/services/kong/consumer-service.ts index 194f786ab..3a2008921 100644 --- a/src/services/kong/consumer-service.ts +++ b/src/services/kong/consumer-service.ts @@ -41,7 +41,8 @@ export class KongConsumerService { public async createOrGetConsumer( username: string, - customId: string + customId: string, + app: any ): Promise { logger.debug('createOrGetConsumer'); try { @@ -51,16 +52,20 @@ export class KongConsumerService { return { created: false, consumer: result }; } catch (err) { logger.debug('createOrGetConsumer - CATCH ERROR %s', err); - const result = await this.createKongConsumer(username, customId); + const result = await this.createKongConsumer(username, customId, app); logger.debug('createOrGetConsumer - CATCH RESULT %j', result); return { created: false, consumer: result }; } } - public async createKongConsumer(username: string, customId: string) { + public async createKongConsumer( + username: string, + customId: string, + app: any + ) { let body: KongConsumer = { username: username, - tags: ['aps-portal'], + tags: ['aps-portal', `app:${app.name}`, `owner:${app.owner.name}`], }; if (customId) { body['custom_id'] = customId; diff --git a/src/services/workflow/create-service-account.ts b/src/services/workflow/create-service-account.ts index 474396e75..dc0b21846 100644 --- a/src/services/workflow/create-service-account.ts +++ b/src/services/workflow/create-service-account.ts @@ -79,7 +79,11 @@ export const CreateServiceAccount = async ( const nickname = client.client.clientId; const kongApi = new KongConsumerService(process.env.KONG_URL); - const consumer = await kongApi.createKongConsumer(nickname, clientId); + const consumer = await kongApi.createKongConsumer( + nickname, + clientId, + application + ); const consumerPK = await AddClientConsumer( context, nickname, diff --git a/src/services/workflow/generate-credential.ts b/src/services/workflow/generate-credential.ts index bbe605709..ca4082389 100644 --- a/src/services/workflow/generate-credential.ts +++ b/src/services/workflow/generate-credential.ts @@ -53,7 +53,7 @@ export const generateCredential = async ( const nickname = clientId; - const newApiKey = await registerApiKey(context, clientId, nickname); + const newApiKey = await registerApiKey(context, clientId, nickname, application); logger.debug('new-api-key CREATED FOR %s', clientId); @@ -138,7 +138,11 @@ export const generateCredential = async ( logger.debug('new-client %j', newClient); const kongApi = new KongConsumerService(process.env.KONG_URL); - const consumer = await kongApi.createKongConsumer(nickname, clientId); + const consumer = await kongApi.createKongConsumer( + nickname, + clientId, + application + ); const consumerPK = await AddClientConsumer( context, nickname, diff --git a/src/services/workflow/kong-api-key.ts b/src/services/workflow/kong-api-key.ts index 0c9285bfc..3aac74ea9 100644 --- a/src/services/workflow/kong-api-key.ts +++ b/src/services/workflow/kong-api-key.ts @@ -14,11 +14,12 @@ import { KongConsumerService } from '../kong'; export async function registerApiKey( context: any, newClientId: string, - nickname: string + nickname: string, + app: any ) { const kongApi = new KongConsumerService(process.env.KONG_URL); - const consumer = await kongApi.createKongConsumer(nickname, newClientId); + const consumer = await kongApi.createKongConsumer(nickname, newClientId, app); const apiKey = await kongApi.addKeyAuthToConsumer(consumer.id); diff --git a/src/services/workflow/link-consumer-to-namespace.ts b/src/services/workflow/link-consumer-to-namespace.ts index 95d604d0e..8e18e98e1 100644 --- a/src/services/workflow/link-consumer-to-namespace.ts +++ b/src/services/workflow/link-consumer-to-namespace.ts @@ -30,6 +30,7 @@ export const LinkConsumerToNamespace = async ( const kongApi = new KongConsumerService(process.env.KONG_URL); const consumerResult = await kongApi.createOrGetConsumer( consumerUsername, + null, null ); const consumerPK: any = { id: null }; From 351ea2afaabaa10cdd3bc78b3916d1d3879f5afe Mon Sep 17 00:00:00 2001 From: James Elson Date: Wed, 13 Mar 2024 12:49:50 -0700 Subject: [PATCH 2/9] Minor fixes from code review suggestions --- src/services/kong/consumer-service.ts | 13 +++++++++---- src/services/workflow/generate-credential.ts | 7 ++++++- src/services/workflow/kong-api-key.ts | 3 ++- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/services/kong/consumer-service.ts b/src/services/kong/consumer-service.ts index 3a2008921..4994c2e61 100644 --- a/src/services/kong/consumer-service.ts +++ b/src/services/kong/consumer-service.ts @@ -10,6 +10,7 @@ import { KeyAuthResponse, KongConsumer, } from './types'; +import { Application } from '../keystone/types'; const logger = Logger('kong.consumer'); @@ -42,7 +43,7 @@ export class KongConsumerService { public async createOrGetConsumer( username: string, customId: string, - app: any + app: Application ): Promise { logger.debug('createOrGetConsumer'); try { @@ -54,22 +55,26 @@ export class KongConsumerService { logger.debug('createOrGetConsumer - CATCH ERROR %s', err); const result = await this.createKongConsumer(username, customId, app); logger.debug('createOrGetConsumer - CATCH RESULT %j', result); - return { created: false, consumer: result }; + return { created: true, consumer: result }; } } public async createKongConsumer( username: string, customId: string, - app: any + app: Application ) { let body: KongConsumer = { username: username, - tags: ['aps-portal', `app:${app.name}`, `owner:${app.owner.name}`], + tags: ['aps-portal'], }; if (customId) { body['custom_id'] = customId; } + if (app) { + body.tags.push(`app:${app.name}`); + body.tags.push(`owner:${app.owner.name}`); + } logger.debug('[createKongConsumer] %s', `${this.kongUrl}/consumers`); try { let response = await fetch(`${this.kongUrl}/consumers`, { diff --git a/src/services/workflow/generate-credential.ts b/src/services/workflow/generate-credential.ts index ca4082389..3fb2466bd 100644 --- a/src/services/workflow/generate-credential.ts +++ b/src/services/workflow/generate-credential.ts @@ -53,7 +53,12 @@ export const generateCredential = async ( const nickname = clientId; - const newApiKey = await registerApiKey(context, clientId, nickname, application); + const newApiKey = await registerApiKey( + context, + clientId, + nickname, + application + ); logger.debug('new-api-key CREATED FOR %s', clientId); diff --git a/src/services/workflow/kong-api-key.ts b/src/services/workflow/kong-api-key.ts index 3aac74ea9..92d4d65b9 100644 --- a/src/services/workflow/kong-api-key.ts +++ b/src/services/workflow/kong-api-key.ts @@ -1,5 +1,6 @@ const { addKongConsumer } = require('../../services/keystone'); +import { Application } from '../keystone/types'; import { KongConsumerService } from '../kong'; /** @@ -15,7 +16,7 @@ export async function registerApiKey( context: any, newClientId: string, nickname: string, - app: any + app: Application ) { const kongApi = new KongConsumerService(process.env.KONG_URL); From d52aa93d49f9cee83759b79e412eee7169132e02 Mon Sep 17 00:00:00 2001 From: ike thecoder Date: Tue, 26 Mar 2024 12:01:49 -0700 Subject: [PATCH 3/9] Dataset formatting fix (#1016) * add a nextapp-dev script * improve the format of the dataset * upd mock for dataset and upd css --- src/mocks/resolvers/api-directory.js | 73 +++++++++++++++++++ .../pages/devportal/api-directory/[id].tsx | 27 ++++--- src/nextapp/shared/styles/markdown.module.css | 72 ++++++++++++++++++ src/package.json | 1 + 4 files changed, 164 insertions(+), 9 deletions(-) create mode 100644 src/nextapp/shared/styles/markdown.module.css diff --git a/src/mocks/resolvers/api-directory.js b/src/mocks/resolvers/api-directory.js index 610852f4e..6d1b06346 100644 --- a/src/mocks/resolvers/api-directory.js +++ b/src/mocks/resolvers/api-directory.js @@ -1,4 +1,77 @@ +import YAML from 'js-yaml'; + +const markdown = YAML.load(` +notes: | + Here is some markdown. + # Heading 1 + ## Heading 2 + ### Heading 3 + #### Heading 4 + Then I will do **bold**, _italics_ and ~~strikethrough~~. + + #### Heading 4 + + And some text. + + How about a table? + | Col1 | Col2 | + | ---- | ---- | + | Val1 | Val2 | + + How about a new line. + + And another line. + + Try a list: + - one + - two + - three + + Or an ordered list: + 1. one + 1. two + 1. three + + Then there are images + + ![image](http://localhost:3000/images/bc_logo_header.svg) + + And links [my docs](https://github.com). + + Here are some block quotes + + > A block quote about something. + + What about a bit of code - \`alert("hi")\`. + + Code block? + \`\`\` + function (a) { + // comment + } + \`\`\` + +`); + const directories = [ + { + id: 'api1', + name: 'markdown-test', + title: 'Testing Markdown on Dataset', + notes: markdown.notes, + sector: 'Natural Resources', + license_title: 'Access Only', + view_audience: 'Named users', + security_class: 'LOW-PUBLIC', + record_publish_date: '2020-04-28', + tags: '["API","CDOGS","Document","Document Generation"]', + organization: { + title: 'Ministry of Environment and Climate Change Strategy', + }, + organizationUnit: { + title: 'Information Innovation and Technology', + }, + }, { id: 'api1', name: 'common-service-api', diff --git a/src/nextapp/pages/devportal/api-directory/[id].tsx b/src/nextapp/pages/devportal/api-directory/[id].tsx index 9a8475efb..a1a752859 100644 --- a/src/nextapp/pages/devportal/api-directory/[id].tsx +++ b/src/nextapp/pages/devportal/api-directory/[id].tsx @@ -26,6 +26,7 @@ import ReactMarkdownWithHtml from 'react-markdown/with-html'; import gfm from 'remark-gfm'; import { uid } from 'react-uid'; import { useAuth } from '@/shared/services/auth'; +import style from '@/shared/styles/markdown.module.css'; const renderers = { link: InternalLink, @@ -144,20 +145,28 @@ const ApiPage: React.FC< About This Dataset - + {data?.notes} - {data?.products?.sort((a,b) => (a.name > b.name) ? 1 : ((b.name > a.name) ? -1 : 0)).map((p) => ( - - ))} + {data?.products + ?.sort((a, b) => + a.name > b.name ? 1 : b.name > a.name ? -1 : 0 + ) + .map((p) => ( + + ))} diff --git a/src/nextapp/shared/styles/markdown.module.css b/src/nextapp/shared/styles/markdown.module.css new file mode 100644 index 000000000..a6e77eb52 --- /dev/null +++ b/src/nextapp/shared/styles/markdown.module.css @@ -0,0 +1,72 @@ +.markdown { +} + +.markdown h1 { + margin-bottom: 1em; +} + +.markdown h2 { + margin-bottom: 1em; +} + +.markdown h3 { + margin-bottom: 1em; +} + +.markdown h4 { + margin-bottom: 1em; +} + +.markdown ul { + margin-top: 1em; + margin-bottom: 1em; + list-style: disc outside none; +} + +.markdown ul li { + margin-left: 2em; + display: list-item; + text-align: -webkit-match-parent; +} + +.markdown ol { + margin-top: 1em; + margin-bottom: 1em; +} + +.markdown ol li { + margin-left: 2em; + display: list-item; + text-align: -webkit-match-parent; +} + +.markdown img { + display: none; +} + +.markdown table { + margin-top: 1em; + margin-bottom: 1em; + width: 100%; + border-collapse: collapse; +} + +.markdown td { + padding: 8px; + border: 1px solid #cccccc; +} + +.markdown th { + padding: 8px; + text-align: left; + border: 1px solid #cccccc; +} + +.markdown blockquote { + margin-top: 1em; + margin-bottom: 1em; + padding-top: 5px; + padding-bottom: 5px; + padding-left: 5px; + border-left: 10px solid #cccccc; +} diff --git a/src/package.json b/src/package.json index 5ab4e899e..d3bf15ed6 100644 --- a/src/package.json +++ b/src/package.json @@ -33,6 +33,7 @@ "copy-keystone-admin-assets": "ts-node tools/copyKeystoneAdminAssets", "x-prestart": "npm run build", "x-dev": "nodemon", + "nextapp-dev": "cross-env NEXT_PUBLIC_MOCKS=on NODE_ENV=development NODE_OPTIONS='--openssl-legacy-provider --no-experimental-fetch --dns-result-order=ipv4first' next dev ./nextapp", "batch": "cross-env NODE_ENV=development node dist/server-batch.js", "intg-build": "cross-env NODE_ENV=development npm-run-all delete-assets copy-assets ts-build", "dev": "cross-env NODE_ENV=development NODE_OPTIONS='--openssl-legacy-provider --no-experimental-fetch --dns-result-order=ipv4first' npm-run-all delete-assets copy-assets tsoa-gen-types tsoa-build-v1 tsoa-build-v2 ts-build ks-dev", From 0b2bf3dd73774c6081c5c11b6f86401491213922 Mon Sep 17 00:00:00 2001 From: Elson9 Date: Tue, 2 Apr 2024 15:14:08 -0700 Subject: [PATCH 4/9] =?UTF-8?q?Added=20Application=20and=20Application=20O?= =?UTF-8?q?wner=20as=20metadata=20to=20the=20Consumer=20r=E2=80=A6=20(#101?= =?UTF-8?q?1)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Added Application and Application Owner as metadata to the Consumer record * Minor fixes from code review suggestions --- src/services/kong/consumer-service.ts | 18 ++++++++++++++---- .../workflow/create-service-account.ts | 6 +++++- src/services/workflow/generate-credential.ts | 13 +++++++++++-- src/services/workflow/kong-api-key.ts | 6 ++++-- .../workflow/link-consumer-to-namespace.ts | 1 + 5 files changed, 35 insertions(+), 9 deletions(-) diff --git a/src/services/kong/consumer-service.ts b/src/services/kong/consumer-service.ts index 194f786ab..4994c2e61 100644 --- a/src/services/kong/consumer-service.ts +++ b/src/services/kong/consumer-service.ts @@ -10,6 +10,7 @@ import { KeyAuthResponse, KongConsumer, } from './types'; +import { Application } from '../keystone/types'; const logger = Logger('kong.consumer'); @@ -41,7 +42,8 @@ export class KongConsumerService { public async createOrGetConsumer( username: string, - customId: string + customId: string, + app: Application ): Promise { logger.debug('createOrGetConsumer'); try { @@ -51,13 +53,17 @@ export class KongConsumerService { return { created: false, consumer: result }; } catch (err) { logger.debug('createOrGetConsumer - CATCH ERROR %s', err); - const result = await this.createKongConsumer(username, customId); + const result = await this.createKongConsumer(username, customId, app); logger.debug('createOrGetConsumer - CATCH RESULT %j', result); - return { created: false, consumer: result }; + return { created: true, consumer: result }; } } - public async createKongConsumer(username: string, customId: string) { + public async createKongConsumer( + username: string, + customId: string, + app: Application + ) { let body: KongConsumer = { username: username, tags: ['aps-portal'], @@ -65,6 +71,10 @@ export class KongConsumerService { if (customId) { body['custom_id'] = customId; } + if (app) { + body.tags.push(`app:${app.name}`); + body.tags.push(`owner:${app.owner.name}`); + } logger.debug('[createKongConsumer] %s', `${this.kongUrl}/consumers`); try { let response = await fetch(`${this.kongUrl}/consumers`, { diff --git a/src/services/workflow/create-service-account.ts b/src/services/workflow/create-service-account.ts index 474396e75..dc0b21846 100644 --- a/src/services/workflow/create-service-account.ts +++ b/src/services/workflow/create-service-account.ts @@ -79,7 +79,11 @@ export const CreateServiceAccount = async ( const nickname = client.client.clientId; const kongApi = new KongConsumerService(process.env.KONG_URL); - const consumer = await kongApi.createKongConsumer(nickname, clientId); + const consumer = await kongApi.createKongConsumer( + nickname, + clientId, + application + ); const consumerPK = await AddClientConsumer( context, nickname, diff --git a/src/services/workflow/generate-credential.ts b/src/services/workflow/generate-credential.ts index bbe605709..3fb2466bd 100644 --- a/src/services/workflow/generate-credential.ts +++ b/src/services/workflow/generate-credential.ts @@ -53,7 +53,12 @@ export const generateCredential = async ( const nickname = clientId; - const newApiKey = await registerApiKey(context, clientId, nickname); + const newApiKey = await registerApiKey( + context, + clientId, + nickname, + application + ); logger.debug('new-api-key CREATED FOR %s', clientId); @@ -138,7 +143,11 @@ export const generateCredential = async ( logger.debug('new-client %j', newClient); const kongApi = new KongConsumerService(process.env.KONG_URL); - const consumer = await kongApi.createKongConsumer(nickname, clientId); + const consumer = await kongApi.createKongConsumer( + nickname, + clientId, + application + ); const consumerPK = await AddClientConsumer( context, nickname, diff --git a/src/services/workflow/kong-api-key.ts b/src/services/workflow/kong-api-key.ts index 0c9285bfc..92d4d65b9 100644 --- a/src/services/workflow/kong-api-key.ts +++ b/src/services/workflow/kong-api-key.ts @@ -1,5 +1,6 @@ const { addKongConsumer } = require('../../services/keystone'); +import { Application } from '../keystone/types'; import { KongConsumerService } from '../kong'; /** @@ -14,11 +15,12 @@ import { KongConsumerService } from '../kong'; export async function registerApiKey( context: any, newClientId: string, - nickname: string + nickname: string, + app: Application ) { const kongApi = new KongConsumerService(process.env.KONG_URL); - const consumer = await kongApi.createKongConsumer(nickname, newClientId); + const consumer = await kongApi.createKongConsumer(nickname, newClientId, app); const apiKey = await kongApi.addKeyAuthToConsumer(consumer.id); diff --git a/src/services/workflow/link-consumer-to-namespace.ts b/src/services/workflow/link-consumer-to-namespace.ts index 95d604d0e..8e18e98e1 100644 --- a/src/services/workflow/link-consumer-to-namespace.ts +++ b/src/services/workflow/link-consumer-to-namespace.ts @@ -30,6 +30,7 @@ export const LinkConsumerToNamespace = async ( const kongApi = new KongConsumerService(process.env.KONG_URL); const consumerResult = await kongApi.createOrGetConsumer( consumerUsername, + null, null ); const consumerPK: any = { id: null }; From 601c9e48809dfe69ec5c8741cad827b557a2ae75 Mon Sep 17 00:00:00 2001 From: Russell Vinegar <38586679+rustyjux@users.noreply.github.com> Date: Tue, 2 Apr 2024 15:14:43 -0700 Subject: [PATCH 5/9] remove profile from local deploy instructions (#1024) --- README.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index fbbeaf8bc..cdaf84002 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ The repo is setup to create a local deployment of the Portal along with required docker build -t gwa-api:e2e . ``` -1. Build: Back in `api-services-portal`, run `docker compose --profile testsuite build`. +1. Build: Back in `api-services-portal`, run `docker compose build`. 1. Run: `docker compose up`. Wait for startup to complete - look for `Swagger UI registered`. 1. The Portal is now live at http://oauth2proxy.localtest.me:4180 1. To login, use username `janis@idir` and password `awsummer` (or username `local` and password `local`). @@ -35,7 +35,12 @@ The repo is setup to create a local deployment of the Portal along with required ### Cypress testing -To run the Cypress test automation suite, run `docker compose --profile testsuite up`. +To run the Cypress test automation suite, run + +```sh +docker compose --profile testsuite build +docker compose --profile testsuite up +``` ### gwa CLI configuration From 249ded166cae9a5a26785d7f6217928806af6bd9 Mon Sep 17 00:00:00 2001 From: ike thecoder Date: Tue, 2 Apr 2024 15:17:04 -0700 Subject: [PATCH 6/9] fix ref to keycloak for docker compose (#1027) --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index f8a230546..d75a52715 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -9,7 +9,7 @@ x-common-variables: &common-variables services: keycloak: - image: jboss/keycloak:15.1.1 + image: quay.io/keycloak/keycloak:15.1.1 container_name: keycloak hostname: keycloak depends_on: From d5bd5039073f591c8e91051a7bf331b7746ef61a Mon Sep 17 00:00:00 2001 From: James Elson Date: Wed, 3 Apr 2024 15:26:45 -0700 Subject: [PATCH 7/9] Fix unable to generate keys error --- src/services/keystone/application.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/services/keystone/application.ts b/src/services/keystone/application.ts index d09b507d7..d985f162c 100644 --- a/src/services/keystone/application.ts +++ b/src/services/keystone/application.ts @@ -12,6 +12,8 @@ export async function lookupApplication( allApplications(where: {id: $id}) { id appId + name + owner } }`, variables: { id }, From fa58198e4bb6d024012c8a772a24346e9696ce2c Mon Sep 17 00:00:00 2001 From: James Elson Date: Thu, 4 Apr 2024 09:08:10 -0700 Subject: [PATCH 8/9] Fixed schema violation --- src/services/keystone/application.ts | 4 +++- src/services/kong/consumer-service.ts | 12 ++++++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/services/keystone/application.ts b/src/services/keystone/application.ts index d985f162c..ac9f7142c 100644 --- a/src/services/keystone/application.ts +++ b/src/services/keystone/application.ts @@ -13,7 +13,9 @@ export async function lookupApplication( id appId name - owner + owner { + name + } } }`, variables: { id }, diff --git a/src/services/kong/consumer-service.ts b/src/services/kong/consumer-service.ts index 4994c2e61..b9dc5b812 100644 --- a/src/services/kong/consumer-service.ts +++ b/src/services/kong/consumer-service.ts @@ -72,8 +72,16 @@ export class KongConsumerService { body['custom_id'] = customId; } if (app) { - body.tags.push(`app:${app.name}`); - body.tags.push(`owner:${app.owner.name}`); + body.tags.push( + `app:${app.name + .replace(/[^A-Za-z0-9:-]/gim, '') + .replace(/[:]/gim, '-')}` + ); + body.tags.push( + `owner:${app.owner.name + .replace(/[^A-Za-z0-9:-]/gim, '') + .replace(/[:]/gim, '-')}` + ); } logger.debug('[createKongConsumer] %s', `${this.kongUrl}/consumers`); try { From 2e90d021411c9cd1750a392744140d7355967017 Mon Sep 17 00:00:00 2001 From: James Elson Date: Thu, 11 Apr 2024 08:54:58 -0700 Subject: [PATCH 9/9] Code fixes + unit tests --- src/services/kong/consumer-service.ts | 11 +++--- src/services/utils.ts | 4 +++ src/test/services/utils.test.js | 51 +++++++++++++++++++++++++++ 3 files changed, 59 insertions(+), 7 deletions(-) create mode 100644 src/test/services/utils.test.js diff --git a/src/services/kong/consumer-service.ts b/src/services/kong/consumer-service.ts index b9dc5b812..41e6dfa5e 100644 --- a/src/services/kong/consumer-service.ts +++ b/src/services/kong/consumer-service.ts @@ -11,6 +11,7 @@ import { KongConsumer, } from './types'; import { Application } from '../keystone/types'; +import { alphanumericNoSpaces } from '../utils'; const logger = Logger('kong.consumer'); @@ -66,21 +67,17 @@ export class KongConsumerService { ) { let body: KongConsumer = { username: username, - tags: ['aps-portal'], + tags: [], }; if (customId) { body['custom_id'] = customId; } if (app) { body.tags.push( - `app:${app.name - .replace(/[^A-Za-z0-9:-]/gim, '') - .replace(/[:]/gim, '-')}` + `app:${alphanumericNoSpaces(app.name)}` ); body.tags.push( - `owner:${app.owner.name - .replace(/[^A-Za-z0-9:-]/gim, '') - .replace(/[:]/gim, '-')}` + `owner:${alphanumericNoSpaces(app.owner.name)}` ); } logger.debug('[createKongConsumer] %s', `${this.kongUrl}/consumers`); diff --git a/src/services/utils.ts b/src/services/utils.ts index ee8b8e195..f6411473a 100644 --- a/src/services/utils.ts +++ b/src/services/utils.ts @@ -75,3 +75,7 @@ export async function fetchWithTimeout(resource: string, options: any = {}) { return response; } + +export function alphanumericNoSpaces(str: string) { + return str.replace(/[^A-Za-z0-9:-]/gim, '').replace(/[:]/gim, '-'); +} diff --git a/src/test/services/utils.test.js b/src/test/services/utils.test.js new file mode 100644 index 000000000..9aa7fe164 --- /dev/null +++ b/src/test/services/utils.test.js @@ -0,0 +1,51 @@ +import { alphanumericNoSpaces } from '../../services/utils'; + +describe('alphanumericNoSpaces tests', () => { + it('should remove spaces from the string', () => { + const input = 'hello world'; + const expectedOutput = 'helloworld'; + expect(alphanumericNoSpaces(input)).toEqual(expectedOutput); + }); + + it('should remove special characters', () => { + const input = 'hello@world!how%^&*are you?'; + const expectedOutput = 'helloworldhowareyou'; + expect(alphanumericNoSpaces(input)).toEqual(expectedOutput); + }); + + it('should replace colons with hyphens', () => { + const input = 'this:is:a:test'; + const expectedOutput = 'this-is-a-test'; + expect(alphanumericNoSpaces(input)).toEqual(expectedOutput); + }); + + it('should handle empty string', () => { + const input = ''; + const expectedOutput = ''; + expect(alphanumericNoSpaces(input)).toEqual(expectedOutput); + }); + + it('should handle string with only special characters', () => { + const input = '@#$%^&*()'; + const expectedOutput = ''; + expect(alphanumericNoSpaces(input)).toEqual(expectedOutput); + }); + + it('should handle string with only colons', () => { + const input = ':::'; + const expectedOutput = '---'; + expect(alphanumericNoSpaces(input)).toEqual(expectedOutput); + }); + + it('should handle string with only alphanumeric characters', () => { + const input = 'abcdef12345'; + const expectedOutput = 'abcdef12345'; + expect(alphanumericNoSpaces(input)).toEqual(expectedOutput); + }); + + it('should handle string with mixed characters', () => { + const input = 'hello!-world, how:are?you'; + const expectedOutput = 'hello-worldhow-areyou'; + expect(alphanumericNoSpaces(input)).toEqual(expectedOutput); + }); +});