From 555bfd61d2ee6137db8e2de843f99abaef0e67b6 Mon Sep 17 00:00:00 2001 From: Thijn Date: Tue, 8 Oct 2024 17:11:25 +0200 Subject: [PATCH 1/4] added proper entities, store, views and modals --- src/entities/consumer/consumer.mock.ts | 8 +- src/entities/consumer/consumer.ts | 40 ++-- src/entities/consumer/consumer.types.ts | 10 +- src/entities/consumer/index.js | 1 - src/modals/Consumer/DeleteConsumer.vue | 98 ++++++++++ src/modals/Consumer/EditConsumer.vue | 194 +++++++++++++++++++ src/modals/Modals.vue | 6 + src/store/modules/consumer.js | 235 ++++++++++++------------ src/views/Consumer/ConsumerDetails.vue | 110 +++++++++++ src/views/Consumer/ConsumersIndex.vue | 46 +++++ src/views/Consumer/ConsumersList.vue | 112 +++++++++++ src/views/Views.vue | 3 + 12 files changed, 711 insertions(+), 152 deletions(-) create mode 100644 src/modals/Consumer/DeleteConsumer.vue create mode 100644 src/modals/Consumer/EditConsumer.vue create mode 100644 src/views/Consumer/ConsumerDetails.vue create mode 100644 src/views/Consumer/ConsumersIndex.vue create mode 100644 src/views/Consumer/ConsumersList.vue diff --git a/src/entities/consumer/consumer.mock.ts b/src/entities/consumer/consumer.mock.ts index cac2fd0e..a827ea08 100644 --- a/src/entities/consumer/consumer.mock.ts +++ b/src/entities/consumer/consumer.mock.ts @@ -11,10 +11,10 @@ export const mockConsumerData = (): TConsumer[] => [ version: '1.0.0', domains: ['mobile.example.com'], ips: ['192.168.1.1'], - authorizationType: 'public', + authorizationType: 'basic', authorizationConfiguration: [], created: '2023-02-01T00:00:00Z', - updated: '2023-02-01T00:00:00Z' + updated: '2023-02-01T00:00:00Z', }, { id: '4c3edd34-a90d-4d2a-8894-adb5836ecde8', @@ -25,10 +25,10 @@ export const mockConsumerData = (): TConsumer[] => [ version: '1.1.0', domains: ['dashboard.example.com'], ips: ['192.168.1.2'], - authorizationType: 'api-key', + authorizationType: 'basic', authorizationConfiguration: [['key', '4c3edd34-a90d-4d2a-8894-adb5836ecde8']], created: '2023-02-01T00:00:00Z', - updated: '2023-02-01T00:00:00Z' + updated: '2023-02-01T00:00:00Z', }, ] diff --git a/src/entities/consumer/consumer.ts b/src/entities/consumer/consumer.ts index 94b4b951..9290e3db 100644 --- a/src/entities/consumer/consumer.ts +++ b/src/entities/consumer/consumer.ts @@ -6,45 +6,45 @@ export class Consumer implements TConsumer { public id: string public uuid: string public name: string - public description: string | null - public reference: string | null + public description: string + public reference: string public version: string public domains: string[] public ips: string[] - public authorizationType: string | null + public authorizationType: 'none' | 'basic' | 'bearer' | 'apiKey' | 'oauth2' | 'jwt' public authorizationConfiguration: string[][] - public created: string | null - public updated: string | null + public created: string + public updated: string constructor(consumer: TConsumer) { this.id = consumer.id || '' this.uuid = consumer.id || '' this.name = consumer.name || '' - this.description = consumer.description || null - this.reference = consumer.reference || null - this.version = consumer.version || '0.0.0' + this.description = consumer.description || '' + this.reference = consumer.reference || '' + this.version = consumer.version || '' this.domains = consumer.domains || [] this.ips = consumer.ips || [] - this.authorizationType = consumer.authorizationType || null - this.authorizationConfiguration = consumer.authorizationConfiguration || null - this.created = consumer.created || null - this.updated = consumer.updated || null + this.authorizationType = consumer.authorizationType || 'basic' + this.authorizationConfiguration = consumer.authorizationConfiguration || [] + this.created = consumer.created || '' + this.updated = consumer.updated || '' } public validate(): SafeParseReturnType { const schema = z.object({ - id: z.string().uuid(), - uuid: z.string().uuid(), + id: z.string().optional(), + uuid: z.string().uuid().or(z.literal('')).optional(), name: z.string().max(255), - description: z.string().nullable(), - reference: z.string().nullable(), + description: z.string(), + reference: z.string(), version: z.string(), domains: z.array(z.string()), ips: z.array(z.string()), - authorizationType: z.enum(['none', 'basic', 'bearer', 'apiKey', 'oauth2', 'jwt']).nullable(), - authorizationConfiguration: z.string().nullable(), - created: z.string().nullable(), - updated: z.string().nullable() + authorizationType: z.enum(['none', 'basic', 'bearer', 'apiKey', 'oauth2', 'jwt']), + authorizationConfiguration: z.array(z.array(z.string())), + created: z.string().datetime().or(z.literal('')).optional(), + updated: z.string().datetime().or(z.literal('')).optional(), }) return schema.safeParse({ ...this }) diff --git a/src/entities/consumer/consumer.types.ts b/src/entities/consumer/consumer.types.ts index 7f1fb63f..d839a394 100644 --- a/src/entities/consumer/consumer.types.ts +++ b/src/entities/consumer/consumer.types.ts @@ -2,13 +2,13 @@ export type TConsumer = { id: string uuid: string name: string - description: string | null - reference: string | null + description: string + reference: string version: string domains: string[] ips: string[] - authorizationType: string | null + authorizationType: 'none' | 'basic' | 'bearer' | 'apiKey' | 'oauth2' | 'jwt' authorizationConfiguration: string[][] - created: string | null - updated: string | null + created: string + updated: string } diff --git a/src/entities/consumer/index.js b/src/entities/consumer/index.js index a3d1f6ae..491bf69c 100644 --- a/src/entities/consumer/index.js +++ b/src/entities/consumer/index.js @@ -1,4 +1,3 @@ export * from './consumer.ts' export * from './consumer.types.ts' export * from './consumer.mock.ts' - diff --git a/src/modals/Consumer/DeleteConsumer.vue b/src/modals/Consumer/DeleteConsumer.vue new file mode 100644 index 00000000..5523df13 --- /dev/null +++ b/src/modals/Consumer/DeleteConsumer.vue @@ -0,0 +1,98 @@ + + + + + diff --git a/src/modals/Consumer/EditConsumer.vue b/src/modals/Consumer/EditConsumer.vue new file mode 100644 index 00000000..8737914e --- /dev/null +++ b/src/modals/Consumer/EditConsumer.vue @@ -0,0 +1,194 @@ + + + + + diff --git a/src/modals/Modals.vue b/src/modals/Modals.vue index faef8038..49c39f57 100644 --- a/src/modals/Modals.vue +++ b/src/modals/Modals.vue @@ -2,6 +2,8 @@
+ + @@ -32,6 +34,8 @@ import { navigationStore } from '../store/store.js' import EditEndpoint from './Endpoint/EditEndpoint.vue' import DeleteEndpoint from './Endpoint/DeleteEndpoint.vue' +import EditConsumer from './Consumer/EditConsumer.vue' +import DeleteConsumer from './Consumer/DeleteConsumer.vue' import EditSource from './Source/EditSource.vue' import TestSource from './TestSource/TestSource.vue' import DeleteSource from './Source/DeleteSource.vue' @@ -60,6 +64,8 @@ export default { components: { EditEndpoint, DeleteEndpoint, + EditConsumer, + DeleteConsumer, DeleteSource, EditSource, TestSource, diff --git a/src/store/modules/consumer.js b/src/store/modules/consumer.js index 5379d656..7b2fca0e 100644 --- a/src/store/modules/consumer.js +++ b/src/store/modules/consumer.js @@ -1,129 +1,120 @@ /* eslint-disable no-console */ import { defineStore } from 'pinia' import { Consumer } from '../../entities/index.js' +import { MissingParameterError, ValidationError } from '../../services/errors/index.js' -export const useConsumerStore = defineStore( - 'consumer', { - state: () => ({ - consumerItem: false, - consumerList: [], - }), - actions: { - setConsumerItem(consumerItem) { - this.consumerItem = consumerItem && new Consumer(consumerItem) - console.log('Active consumer item set to ' + consumerItem) - }, - setConsumerList(consumerList) { - this.consumerList = consumerList.map( - (consumerItem) => new Consumer(consumerItem), - ) - console.log('Consumer list set to ' + consumerList.length + ' items') - }, - /* istanbul ignore next */ // ignore this for Jest until moved into a service - async refreshConsumerList(search = null) { - // @todo this might belong in a service? - let consumer = '/index.php/apps/openconnector/api/consumers' - if (search !== null && search !== '') { - consumer = consumer + '?_search=' + search - } - return fetch(consumer, { - method: 'GET', - }) - .then( - (response) => { - response.json().then( - (data) => { - this.setConsumerList(data.results) - }, - ) - }, - ) - .catch( - (err) => { - console.error(err) - }, - ) - }, - // New function to get a single consumer - async getConsumer(id) { - const consumer = `/index.php/apps/openconnector/api/consumers/${id}` - try { - const response = await fetch(consumer, { - method: 'GET', - }) - const data = await response.json() - this.setConsumerItem(data) - return data - } catch (err) { - console.error(err) - throw err - } - }, - // Delete a consumer - deleteConsumer() { - if (!this.consumerItem || !this.consumerItem.id) { - throw new Error('No consumer item to delete') - } - - console.log('Deleting consumer...') - - const consumer = `/index.php/apps/openconnector/api/consumers/${this.consumerItem.id}` - - return fetch(consumer, { - method: 'DELETE', - }) - .then((response) => { - this.refreshConsumerList() - }) - .catch((err) => { - console.error('Error deleting consumer:', err) - throw err - }) - }, - // Create or save a consumer from store - saveConsumer() { - if (!this.consumerItem) { - throw new Error('No consumer item to save') - } - - console.log('Saving consumer...') - - const isNewConsumer = !this.consumerItem.id - const consumer = isNewConsumer - ? '/index.php/apps/openconnector/api/consumers' - : `/index.php/apps/openconnector/api/consumers/${this.consumerItem.id}` - const method = isNewConsumer ? 'POST' : 'PUT' - - // Create a copy of the consumer item and remove empty properties - const consumerToSave = { ...this.consumerItem } - Object.keys(consumerToSave).forEach(key => { - if (consumerToSave[key] === '' || (Array.isArray(consumerToSave[key]) && !consumerToSave[key].length)) { - delete consumerToSave[key] - } - }) - - return fetch( - consumer, - { - method, - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify(consumerToSave), +export const useConsumerStore = defineStore('consumer', { + state: () => ({ + consumerItem: false, + consumerList: [], + }), + actions: { + setConsumerItem(consumerItem) { + this.consumerItem = consumerItem && new Consumer(consumerItem) + console.log('Active consumer item set to ' + consumerItem) + }, + setConsumerList(consumerList) { + this.consumerList = consumerList.map( + (consumerItem) => new Consumer(consumerItem), + ) + console.log('Consumer list set to ' + consumerList.length + ' items') + }, + /* istanbul ignore next */ // ignore this for Jest until moved into a service + async refreshConsumerList(search = null) { + // @todo this might belong in a service? + let endpoint = '/index.php/apps/openconnector/api/consumers' + if (search !== null && search !== '') { + endpoint = endpoint + '?_search=' + search + } + + const response = await fetch(endpoint, { + method: 'GET', + }) + + const data = (await response.json()).results + const entities = data.map(consumerItem => new Consumer(consumerItem)) + + this.setConsumerList(data) + + return { response, data, entities } + }, + // New function to get a single consumer + async getConsumer(id) { + const endpoint = `/index.php/apps/openconnector/api/consumers/${id}` + + const response = await fetch(endpoint, { + method: 'GET', + }) + + const data = await response.json() + const entity = new Consumer(data) + + this.setConsumerItem(data) + + return { response, data, entity } + }, + // Delete a consumer + async deleteConsumer(consumerItem) { + if (!consumerItem) { + throw new MissingParameterError('consumerItem') + } + + console.log('Deleting consumer...') + + const endpoint = `/index.php/apps/openconnector/api/consumers/${this.consumerItem.id}` + + const response = await fetch(endpoint, { + method: 'DELETE', + }) + + response.ok && this.setConsumerItem(null) + this.refreshConsumerList() + + return { response } + }, + // Create or save a consumer from store + async saveConsumer(consumerItem) { + if (!consumerItem) { + throw new MissingParameterError('consumerItem') + } + + // convert to an entity + consumerItem = new Consumer(consumerItem) + + // verify data with Zod + const validationResult = consumerItem.validate() + if (!validationResult.success) { + console.error(validationResult.error) + console.log(validationResult) + throw new ValidationError(validationResult.error) + } + + console.log('Saving consumer...') + + const isNewConsumer = !consumerItem.id + const endpoint = isNewConsumer + ? '/index.php/apps/openconnector/api/consumers' + : `/index.php/apps/openconnector/api/consumers/${consumerItem.id}` + const method = isNewConsumer ? 'POST' : 'PUT' + + const response = await fetch( + endpoint, + { + method, + headers: { + 'Content-Type': 'application/json', }, - ) - .then((response) => response.json()) - .then((data) => { - this.setConsumerItem(data) - console.log('Consumer saved') - // Refresh the consumer list - return this.refreshConsumerList() - }) - .catch((err) => { - console.error('Error saving consumer:', err) - throw err - }) - }, + body: JSON.stringify(consumerItem), + }, + ) + + const data = await response.json() + const entity = new Consumer(data) + + this.setConsumerItem(data) + this.refreshConsumerList() + + return { response, data, entity } }, }, -) +}) diff --git a/src/views/Consumer/ConsumerDetails.vue b/src/views/Consumer/ConsumerDetails.vue new file mode 100644 index 00000000..0a1aa1e4 --- /dev/null +++ b/src/views/Consumer/ConsumerDetails.vue @@ -0,0 +1,110 @@ + + + + + + + diff --git a/src/views/Consumer/ConsumersIndex.vue b/src/views/Consumer/ConsumersIndex.vue new file mode 100644 index 00000000..f65e428d --- /dev/null +++ b/src/views/Consumer/ConsumersIndex.vue @@ -0,0 +1,46 @@ + + + + + diff --git a/src/views/Consumer/ConsumersList.vue b/src/views/Consumer/ConsumersList.vue new file mode 100644 index 00000000..8c92aedf --- /dev/null +++ b/src/views/Consumer/ConsumersList.vue @@ -0,0 +1,112 @@ + + + + + + + diff --git a/src/views/Views.vue b/src/views/Views.vue index e214b194..e5709992 100644 --- a/src/views/Views.vue +++ b/src/views/Views.vue @@ -9,6 +9,7 @@ import { navigationStore } from '../store/store.js' + @@ -22,6 +23,7 @@ import { NcAppContent } from '@nextcloud/vue' import Dashboard from './dashboard/DashboardIndex.vue' import SourcesIndex from './Source/SourcesIndex.vue' import EndpointsIndex from './Endpoint/EndpointsIndex.vue' +import ConsumersIndex from './Consumer/ConsumersIndex.vue' import WebhooksIndex from './Webhook/WebhooksIndex.vue' import JobsIndex from './Job/JobsIndex.vue' import MappingsIndex from './Mapping/MappingsIndex.vue' @@ -34,6 +36,7 @@ export default { NcAppContent, SourcesIndex, EndpointsIndex, + ConsumersIndex, WebhooksIndex, JobsIndex, MappingsIndex, From d0684b34f2b91fe3109952cdeb01842caca9f703 Mon Sep 17 00:00:00 2001 From: Thijn Date: Wed, 9 Oct 2024 13:16:36 +0200 Subject: [PATCH 2/4] attempted to fix backend --- lib/Migration/Version0Date20240826193657.php | 6 +++++- src/modals/Consumer/EditConsumer.vue | 20 +++++++++++++------- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/lib/Migration/Version0Date20240826193657.php b/lib/Migration/Version0Date20240826193657.php index a61b0520..1e7d9ca8 100644 --- a/lib/Migration/Version0Date20240826193657.php +++ b/lib/Migration/Version0Date20240826193657.php @@ -294,8 +294,12 @@ public function changeSchema(IOutput $output, Closure $schemaClosure, array $opt $table->addColumn('name', Types::STRING, ['notnull' => true, 'length' => 255]); $table->addColumn('description', Types::TEXT, ['notnull' => false]); $table->addColumn('reference', Types::STRING, ['notnull' => false, 'length' => 255]); + $table->addColumn('domains', Types::JSON, ['notnull' => false]); + $table->addColumn('ips', Types::JSON, ['notnull' => false]); + $table->addColumn('authorization_type', Types::STRING, ['notnull' => true, 'length' => 255]); + $table->addColumn('authorization_configuration', Types::STRING, ['notnull' => true, 'length' => 255]); $table->addColumn('is_enabled', Types::BOOLEAN, ['notnull' => true, 'default' => true]); - $table->addColumn('type', Types::STRING, ['notnull' => true, 'length' => 50]); + $table->addColumn('type', Types::STRING, ['notnull' => true, 'length' => 50, 'default' => '']); $table->addColumn('configuration', Types::TEXT, ['notnull' => false]); $table->addColumn('status', Types::STRING, ['notnull' => false, 'length' => 255]); $table->addColumn('last_call', Types::DATETIME, ['notnull' => false]); diff --git a/src/modals/Consumer/EditConsumer.vue b/src/modals/Consumer/EditConsumer.vue index 8737914e..b2d1ed27 100644 --- a/src/modals/Consumer/EditConsumer.vue +++ b/src/modals/Consumer/EditConsumer.vue @@ -20,7 +20,7 @@ import { consumerStore, navigationStore } from '../../store/store.js'
-
+
@@ -43,16 +43,12 @@ import { consumerStore, navigationStore } from '../../store/store.js' helper-text="Enter domains separated by commas (e.g. example.com, example.org)." /> - -
@@ -147,7 +143,7 @@ export default { // If the authorizationType of the consumerItem exists on the authorizationTypeOptions, apply it to the value // this is done for future proofing incase we were to change the authorization Types - if (this.authorizationTypeOptions.options.map(i => i.label).indexOf(consumerStore.consumerItem.authorizationType) >= 0) { + if (this.authorizationTypeOptions.options.map(i => i.label).indexOf(consumerStore.consumerItem.authorizationType) !== -1) { this.authorizationTypeOptions.value = { label: consumerStore.consumerItem.authorizationType } } } @@ -192,3 +188,13 @@ export default { }, } + + From 602d68cab8ca951d6ed75590e1ef81a87a5d14af Mon Sep 17 00:00:00 2001 From: Thijn Date: Thu, 10 Oct 2024 12:08:34 +0200 Subject: [PATCH 3/4] fixed consumer pages --- lib/Db/ConsumerMapper.php | 6 ++--- lib/Migration/Version0Date20240826193657.php | 4 +-- src/entities/consumer/consumer.mock.ts | 8 ++---- src/entities/consumer/consumer.ts | 26 +++++++++++--------- src/entities/consumer/consumer.types.ts | 4 +-- src/modals/Consumer/EditConsumer.vue | 18 +++----------- src/store/modules/consumer.js | 7 +++++- src/views/Consumer/ConsumerDetails.vue | 12 ++------- 8 files changed, 34 insertions(+), 51 deletions(-) diff --git a/lib/Db/ConsumerMapper.php b/lib/Db/ConsumerMapper.php index 88a5c5cd..d4bf3235 100644 --- a/lib/Db/ConsumerMapper.php +++ b/lib/Db/ConsumerMapper.php @@ -117,9 +117,9 @@ public function updateFromArray(int $id, array $object): Consumer $obj->hydrate($object); // Set or update the version - $version = explode('.', $obj->getVersion()); - $version[2] = (int)$version[2] + 1; - $obj->setVersion(implode('.', $version)); + // $version = explode('.', $obj->getVersion()); + // $version[2] = (int)$version[2] + 1; + // $obj->setVersion(implode('.', $version)); return $this->update($obj); } diff --git a/lib/Migration/Version0Date20240826193657.php b/lib/Migration/Version0Date20240826193657.php index a0706925..752d7282 100644 --- a/lib/Migration/Version0Date20240826193657.php +++ b/lib/Migration/Version0Date20240826193657.php @@ -226,8 +226,8 @@ public function changeSchema(IOutput $output, Closure $schemaClosure, array $opt $table->addColumn('description', Types::TEXT, ['notnull' => false]); // The description of the consumer $table->addColumn('domains', Types::JSON, ['notnull' => false]); // The domains the consumer is allowed to run from $table->addColumn('ips', Types::JSON, ['notnull' => false]); // The ips the consumer is allowed to run from - $table->addColumn('authorizationType', Types::STRING, ['notnull' => false, 'length' => 255]); // The authorization type of the consumer, should be one of the following: 'none', 'basic', 'bearer', 'apiKey', 'oauth2', 'jwt'. Keep in mind that the consumer needs to be able to handle the authorization type. - $table->addColumn('authorizationConfiguration', Types::TEXT, ['notnull' => false]); // The authorization configuration of the consumer + $table->addColumn('authorization_type', Types::STRING, ['notnull' => false, 'length' => 255]); // The authorization type of the consumer, should be one of the following: 'none', 'basic', 'bearer', 'apiKey', 'oauth2', 'jwt'. Keep in mind that the consumer needs to be able to handle the authorization type. + $table->addColumn('authorization_configuration', Types::TEXT, ['notnull' => false]); // The authorization configuration of the consumer $table->addColumn('created', Types::DATETIME, ['notnull' => true, 'default' => 'CURRENT_TIMESTAMP']); // the date and time the consumer was created $table->addColumn('updated', Types::DATETIME, ['notnull' => true, 'default' => 'CURRENT_TIMESTAMP']); // the date and time the consumer was updated $table->setPrimaryKey(['id']); diff --git a/src/entities/consumer/consumer.mock.ts b/src/entities/consumer/consumer.mock.ts index a827ea08..9cee0d3a 100644 --- a/src/entities/consumer/consumer.mock.ts +++ b/src/entities/consumer/consumer.mock.ts @@ -3,12 +3,10 @@ import { TConsumer } from './consumer.types' export const mockConsumerData = (): TConsumer[] => [ { - id: '5137a1e5-b54d-43ad-abd1-4b5bff5fcd3f', + id: 1, uuid: '5137a1e5-b54d-43ad-abd1-4b5bff5fcd3f', name: 'Mobile App', description: 'Consumer for the mobile application', - reference: 'MOB-001', - version: '1.0.0', domains: ['mobile.example.com'], ips: ['192.168.1.1'], authorizationType: 'basic', @@ -17,12 +15,10 @@ export const mockConsumerData = (): TConsumer[] => [ updated: '2023-02-01T00:00:00Z', }, { - id: '4c3edd34-a90d-4d2a-8894-adb5836ecde8', + id: 2, uuid: '4c3edd34-a90d-4d2a-8894-adb5836ecde8', name: 'Web Dashboard', description: 'Consumer for the web dashboard', - reference: 'WEB-001', - version: '1.1.0', domains: ['dashboard.example.com'], ips: ['192.168.1.2'], authorizationType: 'basic', diff --git a/src/entities/consumer/consumer.ts b/src/entities/consumer/consumer.ts index 9290e3db..b74ced6c 100644 --- a/src/entities/consumer/consumer.ts +++ b/src/entities/consumer/consumer.ts @@ -3,12 +3,10 @@ import { TConsumer } from './consumer.types' export class Consumer implements TConsumer { - public id: string + public id: number public uuid: string public name: string public description: string - public reference: string - public version: string public domains: string[] public ips: string[] public authorizationType: 'none' | 'basic' | 'bearer' | 'apiKey' | 'oauth2' | 'jwt' @@ -17,28 +15,32 @@ export class Consumer implements TConsumer { public updated: string constructor(consumer: TConsumer) { - this.id = consumer.id || '' - this.uuid = consumer.id || '' + this.id = consumer.id || null + this.uuid = consumer.uuid || '' this.name = consumer.name || '' this.description = consumer.description || '' - this.reference = consumer.reference || '' - this.version = consumer.version || '' this.domains = consumer.domains || [] this.ips = consumer.ips || [] this.authorizationType = consumer.authorizationType || 'basic' this.authorizationConfiguration = consumer.authorizationConfiguration || [] - this.created = consumer.created || '' - this.updated = consumer.updated || '' + + /* Convert dates back to valid javascript ISO date strings */ + // @ts-expect-error -- this is valid javascript, Typescript just doesn't recognize it + this.created = !isNaN(new Date(consumer.created)) + ? new Date(consumer.created).toISOString() + : '' + // @ts-expect-error -- this is valid javascript, Typescript just doesn't recognize it + this.updated = !isNaN(new Date(consumer.updated)) + ? new Date(consumer.updated).toISOString() + : '' } public validate(): SafeParseReturnType { const schema = z.object({ - id: z.string().optional(), + id: z.number().optional(), uuid: z.string().uuid().or(z.literal('')).optional(), name: z.string().max(255), description: z.string(), - reference: z.string(), - version: z.string(), domains: z.array(z.string()), ips: z.array(z.string()), authorizationType: z.enum(['none', 'basic', 'bearer', 'apiKey', 'oauth2', 'jwt']), diff --git a/src/entities/consumer/consumer.types.ts b/src/entities/consumer/consumer.types.ts index d839a394..457953bb 100644 --- a/src/entities/consumer/consumer.types.ts +++ b/src/entities/consumer/consumer.types.ts @@ -1,10 +1,8 @@ export type TConsumer = { - id: string + id: number uuid: string name: string description: string - reference: string - version: string domains: string[] ips: string[] authorizationType: 'none' | 'basic' | 'bearer' | 'apiKey' | 'oauth2' | 'jwt' diff --git a/src/modals/Consumer/EditConsumer.vue b/src/modals/Consumer/EditConsumer.vue index b2d1ed27..33a3ab6b 100644 --- a/src/modals/Consumer/EditConsumer.vue +++ b/src/modals/Consumer/EditConsumer.vue @@ -29,14 +29,6 @@ import { consumerStore, navigationStore } from '../../store/store.js' label="Description" :value.sync="consumerItem.description" /> - - - - { this.success = response.ok this.closeTimeoutFunc = setTimeout(this.closeModal, 2000) diff --git a/src/store/modules/consumer.js b/src/store/modules/consumer.js index 7b2fca0e..dff0fb11 100644 --- a/src/store/modules/consumer.js +++ b/src/store/modules/consumer.js @@ -78,6 +78,11 @@ export const useConsumerStore = defineStore('consumer', { throw new MissingParameterError('consumerItem') } + // update "updated" date to current date + if (consumerItem.updated) { + consumerItem.updated = new Date().toISOString() + } + // convert to an entity consumerItem = new Consumer(consumerItem) @@ -85,7 +90,7 @@ export const useConsumerStore = defineStore('consumer', { const validationResult = consumerItem.validate() if (!validationResult.success) { console.error(validationResult.error) - console.log(validationResult) + console.log(consumerItem) throw new ValidationError(validationResult.error) } diff --git a/src/views/Consumer/ConsumerDetails.vue b/src/views/Consumer/ConsumerDetails.vue index 0a1aa1e4..050fe629 100644 --- a/src/views/Consumer/ConsumerDetails.vue +++ b/src/views/Consumer/ConsumerDetails.vue @@ -47,14 +47,6 @@ import { consumerStore, navigationStore } from '../../store/store.js' Description:

{{ consumerStore.consumerItem.description }}

-
- Reference: -

{{ consumerStore.consumerItem.reference }}

-
-
- Version: -

{{ consumerStore.consumerItem.version }}

-
Domains:

{{ consumerStore.consumerItem.domains.join(', ') }}

@@ -74,11 +66,11 @@ import { consumerStore, navigationStore } from '../../store/store.js'
created: -

{{ consumerStore.consumerItem.created }}

+

{{ new Date(consumerStore.consumerItem.created).toLocaleDateString() }}

updated: -

{{ consumerStore.consumerItem.updated }}

+

{{ new Date(consumerStore.consumerItem.updated).toLocaleDateString() }}

From 3bedbe53e7701a42c17df13e3aaa8b4ecafc4986 Mon Sep 17 00:00:00 2001 From: Thijn Date: Wed, 16 Oct 2024 13:33:05 +0200 Subject: [PATCH 4/4] fixed zod error --- src/entities/consumer/consumer.ts | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/entities/consumer/consumer.ts b/src/entities/consumer/consumer.ts index b74ced6c..46fc68b8 100644 --- a/src/entities/consumer/consumer.ts +++ b/src/entities/consumer/consumer.ts @@ -1,5 +1,6 @@ import { SafeParseReturnType, z } from 'zod' import { TConsumer } from './consumer.types' +import getValidISOstring from '../../services/getValidISOstring' export class Consumer implements TConsumer { @@ -25,19 +26,13 @@ export class Consumer implements TConsumer { this.authorizationConfiguration = consumer.authorizationConfiguration || [] /* Convert dates back to valid javascript ISO date strings */ - // @ts-expect-error -- this is valid javascript, Typescript just doesn't recognize it - this.created = !isNaN(new Date(consumer.created)) - ? new Date(consumer.created).toISOString() - : '' - // @ts-expect-error -- this is valid javascript, Typescript just doesn't recognize it - this.updated = !isNaN(new Date(consumer.updated)) - ? new Date(consumer.updated).toISOString() - : '' + this.created = getValidISOstring(consumer.created) + this.updated = getValidISOstring(consumer.updated) } public validate(): SafeParseReturnType { const schema = z.object({ - id: z.number().optional(), + id: z.number().or(z.null()), uuid: z.string().uuid().or(z.literal('')).optional(), name: z.string().max(255), description: z.string(),