From add25e221ab3e4373fc0f93d9cde3d842341dd96 Mon Sep 17 00:00:00 2001 From: ikethecoder Date: Mon, 3 Jul 2023 17:05:41 -0700 Subject: [PATCH] add namespace creation --- src/controllers/v2/NamespaceController.ts | 40 +++++++++++++++++++++++ src/lists/extensions/Namespace.ts | 12 ++++--- src/services/identifiers.ts | 10 ++++-- src/services/utils.ts | 1 - src/test/services/identifiers.test.js | 11 +++++++ 5 files changed, 65 insertions(+), 9 deletions(-) create mode 100644 src/test/services/identifiers.test.js diff --git a/src/controllers/v2/NamespaceController.ts b/src/controllers/v2/NamespaceController.ts index 5a1007aff..758e47cfd 100644 --- a/src/controllers/v2/NamespaceController.ts +++ b/src/controllers/v2/NamespaceController.ts @@ -9,6 +9,7 @@ import { Tags, Delete, Query, + Post, } from 'tsoa'; import { ValidateError, FieldErrors } from 'tsoa'; import { KeystoneService } from '../ioc/keystoneInjector'; @@ -136,6 +137,37 @@ export class NamespaceController extends Controller { return result.data.namespace; } + /** + * Create a namespace + * + * @summary Create Namespace + * @param ns + * @param request + * @returns + */ + @Post() + @OperationId('create-namespace') + @Security('jwt', []) + public async create( + @Query() name: String, + @Request() request: any + ): Promise { + const result = await this.keystone.executeGraphQL({ + context: this.keystone.createContext(request), + query: createNS, + variables: { name }, + }); + logger.debug('Result %j', result); + if (result.errors) { + const errors: FieldErrors = {}; + result.errors.forEach((err: any, ind: number) => { + errors[`d${ind}`] = { message: err.message }; + }); + throw new ValidateError(errors, 'Unable to create namespace'); + } + return result.data.createNamespace.name; + } + /** * Delete the namespace * > `Required Scope:` Namespace.Manage @@ -234,3 +266,11 @@ const deleteNS = gql` forceDeleteNamespace(namespace: $ns, force: $force) } `; + +const createNS = gql` + mutation CreateNamespace($name: String) { + createNamespace(name: $name) { + name + } + } +`; diff --git a/src/lists/extensions/Namespace.ts b/src/lists/extensions/Namespace.ts index 9bb8b4e7c..007954bf1 100644 --- a/src/lists/extensions/Namespace.ts +++ b/src/lists/extensions/Namespace.ts @@ -34,6 +34,7 @@ import { import { GWAService } from '../../services/gwaapi'; import { camelCaseAttributes, + regExprValidation, transformSingleValueAttributes, } from '../../services/utils'; import getSubjectToken from '../../auth/auth-token'; @@ -54,6 +55,7 @@ import { getResource, transformOrgAndOrgUnit, } from '../../services/keycloak/namespace-details'; +import { newNamespaceID } from '@/services/identifiers'; const logger = Logger('ext.Namespace'); @@ -422,7 +424,7 @@ module.exports = { }, }, { - schema: 'createNamespace(namespace: String!): Namespace', + schema: 'createNamespace(namespace: String): Namespace', resolver: async ( item: any, args: any, @@ -431,10 +433,10 @@ module.exports = { { query, access }: any ) => { const namespaceValidationRule = '^[a-z][a-z0-9-]{4,14}$'; - const re = new RegExp(namespaceValidationRule); - assert.strictEqual( - re.test(args.namespace), - true, + + regExprValidation( + namespaceValidationRule, + args.namespace ? args.namespace : newNamespaceID(), 'Namespace name must be between 5 and 15 alpha-numeric lowercase characters and begin with an alphabet.' ); diff --git a/src/services/identifiers.ts b/src/services/identifiers.ts index ab3f01f97..24af1f39b 100644 --- a/src/services/identifiers.ts +++ b/src/services/identifiers.ts @@ -11,11 +11,15 @@ export function isEnvironmentID(id: string): boolean { } export function newProductID(): string { - return uuidv4().replace(/-/g, '').toUpperCase().substr(0, 12); + return uuidv4().replace(/-/g, '').toUpperCase().substring(0, 12); } export function newApplicationID(): string { - return uuidv4().replace(/-/g, '').toUpperCase().substr(0, 11); + return uuidv4().replace(/-/g, '').toUpperCase().substring(0, 11); } export function newEnvironmentID(): string { - return uuidv4().replace(/-/g, '').toUpperCase().substr(0, 8); + return uuidv4().replace(/-/g, '').toUpperCase().substring(0, 8); +} + +export function newNamespaceID(): string { + return 'gw-' + uuidv4().replace(/-/g, '').toLowerCase().substring(0, 5); } diff --git a/src/services/utils.ts b/src/services/utils.ts index 278f42367..ee8b8e195 100644 --- a/src/services/utils.ts +++ b/src/services/utils.ts @@ -57,7 +57,6 @@ export function regExprValidation( value: string, errorMessage: string ) { - const namespaceValidationRule = '^[a-z][a-z0-9-]{4,14}$'; const re = new RegExp(rule); assert.strictEqual(re.test(value), true, errorMessage); } diff --git a/src/test/services/identifiers.test.js b/src/test/services/identifiers.test.js new file mode 100644 index 000000000..c288d9c84 --- /dev/null +++ b/src/test/services/identifiers.test.js @@ -0,0 +1,11 @@ +import fetch from 'node-fetch'; +import { newNamespaceID } from '../../services/identifiers'; + +describe('Identifiers', function () { + it('it should be a valid namespace', async function () { + const result = newNamespaceID(); + expect(result).toHaveLength(8); + expect(result.startsWith('gw-')).toBeTruthy(); + console.log(result); + }); +});