From 8c1013627423494ab60a58e3a93bf805d9c33477 Mon Sep 17 00:00:00 2001 From: Robert Zondervan Date: Tue, 22 Oct 2024 13:09:10 +0200 Subject: [PATCH 1/6] Fix objects controller --- lib/Controller/ObjectsController.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/Controller/ObjectsController.php b/lib/Controller/ObjectsController.php index d375eb0..1ca7665 100644 --- a/lib/Controller/ObjectsController.php +++ b/lib/Controller/ObjectsController.php @@ -79,7 +79,7 @@ public function index(ObjectService $objectService, SearchService $searchService foreach ($results as $key => $result) { $results[$key] = $result->getObjectArray(); } - + return new JSONResponse(['results' => $results]); } @@ -97,7 +97,7 @@ public function index(ObjectService $objectService, SearchService $searchService public function show(string $id): JSONResponse { try { - return new JSONResponse($this->objectEntityMapper->find(id: (int) $id)); + return new JSONResponse($this->objectEntityMapper->find(idOrUuid: (int) $id)->getObjectArray()); } catch (DoesNotExistException $exception) { return new JSONResponse(data: ['error' => 'Not Found'], statusCode: 404); } @@ -127,7 +127,7 @@ public function create(): JSONResponse unset($data['id']); } - return new JSONResponse($this->objectEntityMapper->createFromArray(object: $data)); + return new JSONResponse($this->objectEntityMapper->createFromArray(object: $data)->getObjectArray()); } /** @@ -153,7 +153,7 @@ public function update(int $id): JSONResponse if (isset($data['id'])) { unset($data['id']); } - return new JSONResponse($this->objectEntityMapper->updateFromArray(id: (int) $id, object: $data)); + return new JSONResponse($this->objectEntityMapper->updateFromArray(id: (int) $id, object: $data)->getObjectArray()); } /** @@ -178,7 +178,7 @@ public function destroy(int $id): JSONResponse * Retrieves a list of logs for an object * * This method returns a JSON response containing the logs for a specific object. - * + * * @NoAdminRequired * @NoCSRFRequired * From e2c151468395e919fb663b6379287a2298d7b4bd Mon Sep 17 00:00:00 2001 From: Ruben van der Linde Date: Tue, 22 Oct 2024 14:31:41 +0200 Subject: [PATCH 2/6] AuditTrail cleanup --- lib/Controller/ObjectsController.php | 30 +++++++++- lib/Db/AuditTrailMapper.php | 63 ++++++++++++++++++++ lib/Migration/Version1Date20241022135300.php | 57 ++++++++++++++++++ lib/Service/ObjectService.php | 44 +------------- 4 files changed, 149 insertions(+), 45 deletions(-) create mode 100755 lib/Migration/Version1Date20241022135300.php diff --git a/lib/Controller/ObjectsController.php b/lib/Controller/ObjectsController.php index d375eb0..31aa280 100644 --- a/lib/Controller/ObjectsController.php +++ b/lib/Controller/ObjectsController.php @@ -6,15 +6,19 @@ use OCA\OpenRegister\Service\SearchService; use OCA\OpenRegister\Db\ObjectEntity; use OCA\OpenRegister\Db\ObjectEntityMapper; +use OCA\OpenRegister\Db\AuditTrail; use OCA\OpenRegister\Db\AuditTrailMapper; use OCP\AppFramework\Controller; use OCP\AppFramework\Http\TemplateResponse; use OCP\AppFramework\Http\JSONResponse; use OCP\IAppConfig; use OCP\IRequest; +use Symfony\Component\Uid\Uuid; class ObjectsController extends Controller { + + /** * Constructor for the ObjectsController * @@ -116,6 +120,7 @@ public function show(string $id): JSONResponse public function create(): JSONResponse { $data = $this->request->getParams(); + $object = $data['object']; foreach ($data as $key => $value) { if (str_starts_with($key, '_')) { @@ -125,13 +130,19 @@ public function create(): JSONResponse if (isset($data['id'])) { unset($data['id']); + } + + // save it + $objectEntity = $this->objectEntityMapper->createFromArray(object: $data); + + $this->auditTrailMapper->createAuditTrail(new: $objectEntity); - return new JSONResponse($this->objectEntityMapper->createFromArray(object: $data)); + return new JSONResponse($objectEntity); } /** - * Updates an existing object + * Updates an existing object * * This method updates an existing object based on its ID. * @@ -144,6 +155,7 @@ public function create(): JSONResponse public function update(int $id): JSONResponse { $data = $this->request->getParams(); + $object = $data['object']; foreach ($data as $key => $value) { if (str_starts_with($key, '_')) { @@ -153,7 +165,14 @@ public function update(int $id): JSONResponse if (isset($data['id'])) { unset($data['id']); } - return new JSONResponse($this->objectEntityMapper->updateFromArray(id: (int) $id, object: $data)); + + // save it + $oldObject = $this->objectEntityMapper->find($id); + $objectEntity = $this->objectEntityMapper->updateFromArray(id: $id, object: $data); + + $this->auditTrailMapper->createAuditTrail(new: $objectEntity, old: $oldObject); + + return new JSONResponse($objectEntity); } /** @@ -169,6 +188,10 @@ public function update(int $id): JSONResponse */ public function destroy(int $id): JSONResponse { + // Create a log entry + $oldObject = $this->objectEntityMapper->find($id); + $this->auditTrailMapper->createAuditTrail(old: $oldObject); + $this->objectEntityMapper->delete($this->objectEntityMapper->find((int) $id)); return new JSONResponse([]); @@ -187,6 +210,7 @@ public function destroy(int $id): JSONResponse */ public function auditTrails(int $id): JSONResponse { + //return new JSONResponse($this->auditTrailMapper->findAll()); return new JSONResponse($this->auditTrailMapper->findAll(filters: ['object' => $id])); } } diff --git a/lib/Db/AuditTrailMapper.php b/lib/Db/AuditTrailMapper.php index 3f10f99..4331197 100644 --- a/lib/Db/AuditTrailMapper.php +++ b/lib/Db/AuditTrailMapper.php @@ -70,6 +70,69 @@ public function createFromArray(array $object): Log return $this->insert(entity: $log); } + + /** + * Creates an audit trail for object changes + * + * @param ObjectEntity|null $old The old state of the object + * @param ObjectEntity|null $new The new state of the object + * @return AuditTrail The created audit trail + */ + public function createAuditTrail(?ObjectEntity $old = null, ?ObjectEntity $new = null): AuditTrail + { + $action = 'update'; + if ($new === null) { + $action = 'delete'; + $objectEntity = $old; + } elseif ($old === null) { + $action = 'create'; + $objectEntity = $new; + } else { + $objectEntity = $new; + } + + $changed = []; + if ($action !== 'delete') { + $oldArray = $old ? $old->jsonSerialize() : []; + $newArray = $new->jsonSerialize(); + foreach ($newArray as $key => $value) { + if (!isset($oldArray[$key]) || $oldArray[$key] !== $value) { + $changed[$key] = [ + 'old' => $oldArray[$key] ?? null, + 'new' => $value + ]; + } + } + if ($action === 'update') { + foreach ($oldArray as $key => $value) { + if (!isset($newArray[$key])) { + $changed[$key] = [ + 'old' => $value, + 'new' => null + ]; + } + } + } + } + + $user = \OC::$server->getUserSession()->getUser(); + + $auditTrail = new AuditTrail(); + $auditTrail->setUuid(Uuid::v4()); + $auditTrail->setObject($objectEntity->getId()); + $auditTrail->setAction($action); + $auditTrail->setChanged($changed); + $auditTrail->setUser($user->getUID()); + $auditTrail->setUserName($user->getDisplayName()); + $auditTrail->setSession(session_id()); + $auditTrail->setRequest(\OC::$server->getRequest()->getId()); + $auditTrail->setIpAddress(\OC::$server->getRequest()->getRemoteAddress()); + $auditTrail->setCreated(new \DateTime()); + $auditTrail->setRegister($objectEntity->getRegister()); + $auditTrail->setSchema($objectEntity->getSchema()); + + return $this->insert(entity: $auditTrail); + } // We dont need update as we dont change the log } diff --git a/lib/Migration/Version1Date20241022135300.php b/lib/Migration/Version1Date20241022135300.php new file mode 100755 index 0000000..7c47f75 --- /dev/null +++ b/lib/Migration/Version1Date20241022135300.php @@ -0,0 +1,57 @@ +getTable('openregister_audit_trails'); + if (!$table->hasColumn('register')) { + $table->addColumn('register', Types::INTEGER, ['notnull' => false]); + } + if ($table->hasColumn('regsiter')) { + $table->dropColumn('regsiter', 'register'); + } + + return $schema; + } + + /** + * @param IOutput $output + * @param Closure(): ISchemaWrapper $schemaClosure + * @param array $options + */ + public function postSchemaChange(IOutput $output, Closure $schemaClosure, array $options): void { + } +} diff --git a/lib/Service/ObjectService.php b/lib/Service/ObjectService.php index 11f021c..8b9d168 100755 --- a/lib/Service/ObjectService.php +++ b/lib/Service/ObjectService.php @@ -205,30 +205,6 @@ public function saveObject(int $register, int $schema, array $object): ObjectEnt $oldObject = $objectEntity->getObject(); $objectEntity->setObject($object); - $changed = []; - - foreach ($object as $key => $value) { - if (!isset($oldObject[$key]) || $oldObject[$key] !== $value) { - $changed[$key] = [ - 'old' => $oldObject[$key] ?? null, - 'new' => $value - ]; - } - } - - // Check for removed properties - foreach ($oldObject as $key => $value) { - if (!isset($object[$key])) { - $changed[$key] = [ - 'old' => $value, - 'new' => null - ]; - } - } - - // Normal loging - //$changed = $objectEntity->getUpdatedFields(); - // If the object has no uuid, create a new one if (empty($objectEntity->getUuid())) { @@ -237,29 +213,13 @@ public function saveObject(int $register, int $schema, array $object): ObjectEnt if($objectEntity->getId()){ $objectEntity = $this->objectEntityMapper->update($objectEntity); - $action = 'update'; + $this->auditTrailMapper->createAuditTrail(new: $objectEntity, old: $oldObject); } else { $objectEntity = $this->objectEntityMapper->insert($objectEntity); - $action = 'create'; + $this->auditTrailMapper->createAuditTrail(new: $objectEntity); } - // Create a log entry - $user = \OC::$server->getUserSession()->getUser(); - - $log = new AuditTrail(); - $log->setUuid(Uuid::v4()); - $log->setObject($objectEntity->getId()); - $log->setAction($action); - $log->setChanged($changed); - $log->setUser($user->getUID()); - $log->setUserName($user->getDisplayName()); - $log->setSession(session_id()); - $log->setRequest(\OC::$server->getRequest()->getId()); - $log->setIpAddress(\OC::$server->getRequest()->getRemoteAddress()); - $log->setCreated(new \DateTime()); - $this->auditTrailMapper->insert($log); - return $objectEntity; } From 16085b5a1ffb2e11bad0824da86c8138f93aa0de Mon Sep 17 00:00:00 2001 From: Ruben van der Linde Date: Tue, 22 Oct 2024 14:36:10 +0200 Subject: [PATCH 3/6] Bit of context --- lib/Controller/ObjectsController.php | 1 - lib/Db/AuditTrailMapper.php | 9 +++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/Controller/ObjectsController.php b/lib/Controller/ObjectsController.php index 31aa280..aa15c91 100644 --- a/lib/Controller/ObjectsController.php +++ b/lib/Controller/ObjectsController.php @@ -210,7 +210,6 @@ public function destroy(int $id): JSONResponse */ public function auditTrails(int $id): JSONResponse { - //return new JSONResponse($this->auditTrailMapper->findAll()); return new JSONResponse($this->auditTrailMapper->findAll(filters: ['object' => $id])); } } diff --git a/lib/Db/AuditTrailMapper.php b/lib/Db/AuditTrailMapper.php index 4331197..aa103fd 100644 --- a/lib/Db/AuditTrailMapper.php +++ b/lib/Db/AuditTrailMapper.php @@ -80,6 +80,7 @@ public function createFromArray(array $object): Log */ public function createAuditTrail(?ObjectEntity $old = null, ?ObjectEntity $new = null): AuditTrail { + // Determine the action based on the presence of old and new objects $action = 'update'; if ($new === null) { $action = 'delete'; @@ -91,10 +92,13 @@ public function createAuditTrail(?ObjectEntity $old = null, ?ObjectEntity $new = $objectEntity = $new; } + // Initialize an array to store changed fields $changed = []; if ($action !== 'delete') { $oldArray = $old ? $old->jsonSerialize() : []; $newArray = $new->jsonSerialize(); + + // Compare old and new values to detect changes foreach ($newArray as $key => $value) { if (!isset($oldArray[$key]) || $oldArray[$key] !== $value) { $changed[$key] = [ @@ -103,6 +107,8 @@ public function createAuditTrail(?ObjectEntity $old = null, ?ObjectEntity $new = ]; } } + + // For updates, check for removed fields if ($action === 'update') { foreach ($oldArray as $key => $value) { if (!isset($newArray[$key])) { @@ -115,8 +121,10 @@ public function createAuditTrail(?ObjectEntity $old = null, ?ObjectEntity $new = } } + // Get the current user $user = \OC::$server->getUserSession()->getUser(); + // Create and populate a new AuditTrail object $auditTrail = new AuditTrail(); $auditTrail->setUuid(Uuid::v4()); $auditTrail->setObject($objectEntity->getId()); @@ -131,6 +139,7 @@ public function createAuditTrail(?ObjectEntity $old = null, ?ObjectEntity $new = $auditTrail->setRegister($objectEntity->getRegister()); $auditTrail->setSchema($objectEntity->getSchema()); + // Insert the new AuditTrail into the database and return it return $this->insert(entity: $auditTrail); } From bf57d23b03a3140355d10a5c70bfa063ffe00876 Mon Sep 17 00:00:00 2001 From: Thijn Date: Tue, 22 Oct 2024 15:18:23 +0200 Subject: [PATCH 4/6] WIP. auditTrail --- src/entities/auditTrail/auditTrail.mock.ts | 39 ++++++++++++++ src/entities/auditTrail/auditTrail.spec.ts | 45 ++++++++++++++++ src/entities/auditTrail/auditTrail.ts | 59 +++++++++++++++++++++ src/entities/auditTrail/auditTrail.types.ts | 16 ++++++ src/entities/auditTrail/index.js | 4 ++ src/entities/index.js | 1 + src/store/modules/object.js | 24 +++++++-- src/views/object/ObjectDetails.vue | 15 +++--- 8 files changed, 192 insertions(+), 11 deletions(-) create mode 100644 src/entities/auditTrail/auditTrail.mock.ts create mode 100644 src/entities/auditTrail/auditTrail.spec.ts create mode 100644 src/entities/auditTrail/auditTrail.ts create mode 100644 src/entities/auditTrail/auditTrail.types.ts create mode 100644 src/entities/auditTrail/index.js diff --git a/src/entities/auditTrail/auditTrail.mock.ts b/src/entities/auditTrail/auditTrail.mock.ts new file mode 100644 index 0000000..5b99e30 --- /dev/null +++ b/src/entities/auditTrail/auditTrail.mock.ts @@ -0,0 +1,39 @@ +import { AuditTrail } from './auditTrail' +import { TAuditTrail } from './auditTrail.types' + +export const mockAuditTrailData = (): TAuditTrail[] => [ + { + id: '1234a1e5-b54d-43ad-abd1-4b5bff5fcd3f', + uuid: 'uuid-1234a1e5-b54d-43ad-abd1-4b5bff5fcd3f', + schema: 1, + register: 1, + object: 1, + action: 'create', + changed: JSON.stringify({ key: 'value' }), + user: 'user1', + userName: 'User One', + session: 'session1', + request: 'request1', + ipAddress: '127.0.0.1', + version: '1.0', + created: new Date().toISOString(), + }, + { + id: '5678a1e5-b54d-43ad-abd1-4b5bff5fcd3f', + uuid: 'uuid-5678a1e5-b54d-43ad-abd1-4b5bff5fcd3f', + schema: 2, + register: 2, + object: 2, + action: 'update', + changed: JSON.stringify({ key: 'value' }), + user: 'user2', + userName: 'User Two', + session: 'session2', + request: 'request2', + ipAddress: '127.0.0.2', + version: '1.1', + created: new Date().toISOString(), + }, +] + +export const mockAuditTrail = (data: TAuditTrail[] = mockAuditTrailData()): TAuditTrail[] => data.map(item => new AuditTrail(item)) diff --git a/src/entities/auditTrail/auditTrail.spec.ts b/src/entities/auditTrail/auditTrail.spec.ts new file mode 100644 index 0000000..ae52468 --- /dev/null +++ b/src/entities/auditTrail/auditTrail.spec.ts @@ -0,0 +1,45 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { AuditTrail } from './auditTrail' +import { mockAuditTrailData } from './auditTrail.mock' + +describe('AuditTrail Entity', () => { + it('should create an AuditTrail entity with full data', () => { + const auditTrail = new AuditTrail(mockAuditTrailData()[0]) + + expect(auditTrail).toBeInstanceOf(AuditTrail) + expect(auditTrail).toEqual(mockAuditTrailData()[0]) + expect(auditTrail.validate().success).toBe(true) + }) + + it('should create an AuditTrail entity with partial data', () => { + const auditTrail = new AuditTrail(mockAuditTrailData()[0]) + + expect(auditTrail).toBeInstanceOf(AuditTrail) + expect(auditTrail.id).toBe(null) + expect(auditTrail.uuid).toBe(mockAuditTrailData()[0].uuid) + expect(auditTrail.register).toBe(mockAuditTrailData()[0].register) + expect(auditTrail.schema).toBe(mockAuditTrailData()[0].schema) + expect(auditTrail.object).toBe(mockAuditTrailData()[0].object) + expect(auditTrail.action).toBe(mockAuditTrailData()[0].action) + expect(auditTrail.changed).toBe(mockAuditTrailData()[0].changed) + expect(auditTrail.user).toBe(mockAuditTrailData()[0].user) + expect(auditTrail.userName).toBe(mockAuditTrailData()[0].userName) + expect(auditTrail.session).toBe(mockAuditTrailData()[0].session) + expect(auditTrail.request).toBe(mockAuditTrailData()[0].request) + expect(auditTrail.ipAddress).toBe(mockAuditTrailData()[0].ipAddress) + expect(auditTrail.version).toBe(mockAuditTrailData()[0].version) + expect(auditTrail.created).toBe(mockAuditTrailData()[0].created) + expect(auditTrail.validate().success).toBe(true) + }) + + it('should fail validation with invalid data', () => { + const auditTrail = new AuditTrail(mockAuditTrailData()[1]) + + expect(auditTrail).toBeInstanceOf(AuditTrail) + expect(auditTrail.validate().success).toBe(false) + expect(auditTrail.validate().error?.issues).toContainEqual(expect.objectContaining({ + path: ['id'], + message: 'Expected string, received null', + })) + }) +}) diff --git a/src/entities/auditTrail/auditTrail.ts b/src/entities/auditTrail/auditTrail.ts new file mode 100644 index 0000000..0d24c6d --- /dev/null +++ b/src/entities/auditTrail/auditTrail.ts @@ -0,0 +1,59 @@ +import { SafeParseReturnType, z } from 'zod' +import { TAuditTrail } from './auditTrail.types' + +export class AuditTrail implements TAuditTrail { + + public id: string + public uuid: string + public schema: number + public register: number + public object: number + public action: string + public changed: string + public user: string + public userName: string + public session: string + public request: string + public ipAddress: string + public version: string + public created: string + + constructor(auditTrail: TAuditTrail) { + this.id = auditTrail.id || null + this.uuid = auditTrail.uuid || null + this.schema = auditTrail.schema || 0 + this.register = auditTrail.register || 0 + this.object = auditTrail.object || 0 + this.action = auditTrail.action || '' + this.changed = auditTrail.changed || '' + this.user = auditTrail.user || '' + this.userName = auditTrail.userName || '' + this.session = auditTrail.session || '' + this.request = auditTrail.request || '' + this.ipAddress = auditTrail.ipAddress || '' + this.version = auditTrail.version || '' + this.created = auditTrail.created || '' + } + + public validate(): SafeParseReturnType { + const schema = z.object({ + id: z.string().nullable(), + uuid: z.string().uuid().nullable(), + schema: z.number(), + register: z.number(), + object: z.number(), + action: z.string(), + changed: z.string(), + user: z.string(), + userName: z.string(), + session: z.string(), + request: z.string(), + ipAddress: z.string(), + version: z.string(), + created: z.string(), + }) + + return schema.safeParse(this) + } + +} diff --git a/src/entities/auditTrail/auditTrail.types.ts b/src/entities/auditTrail/auditTrail.types.ts new file mode 100644 index 0000000..a600169 --- /dev/null +++ b/src/entities/auditTrail/auditTrail.types.ts @@ -0,0 +1,16 @@ +export type TAuditTrail = { + id: string + uuid: string + schema: number // schema ID + register: number // register ID + object: number // object ID + action: string + changed: string // JSON object + user: string + userName: string + session: string + request: string + ipAddress: string + version: string + created: string +} diff --git a/src/entities/auditTrail/index.js b/src/entities/auditTrail/index.js new file mode 100644 index 0000000..98de241 --- /dev/null +++ b/src/entities/auditTrail/index.js @@ -0,0 +1,4 @@ +export * from './auditTrail.ts' +export * from './auditTrail.types.ts' +export * from './auditTrail.mock.ts' + diff --git a/src/entities/index.js b/src/entities/index.js index 5bda5a3..6082526 100755 --- a/src/entities/index.js +++ b/src/entities/index.js @@ -3,3 +3,4 @@ export * from './schema/index.js' export * from './register/index.js' export * from './source/index.js' export * from './object/index.js' +export * from './auditTrail/index.js' diff --git a/src/store/modules/object.js b/src/store/modules/object.js index 8ef2d29..30563d0 100644 --- a/src/store/modules/object.js +++ b/src/store/modules/object.js @@ -1,13 +1,13 @@ /* eslint-disable no-console */ import { defineStore } from 'pinia' -import { ObjectEntity } from '../../entities/index.js' +import { AuditTrail, ObjectEntity } from '../../entities/index.js' export const useObjectStore = defineStore('object', { state: () => ({ objectItem: false, objectList: [], auditTrailItem: false, - auditTrails: [], + auditTrails: [], }), actions: { setObjectItem(objectItem) { @@ -137,14 +137,16 @@ export const useObjectStore = defineStore('object', { const responseData = await response.json() + console.log(responseData) + if (!responseData || typeof responseData !== 'object') { throw new Error('Invalid response data') } const data = new ObjectEntity(responseData) - this.setObjectItem(data) this.refreshObjectList() + this.setObjectItem(data) return { response, data } } catch (error) { @@ -152,5 +154,21 @@ export const useObjectStore = defineStore('object', { throw new Error(`Failed to save object: ${error.message}`) } }, + // AUDIT TRAILS + // New function to get a single object + async getAuditTrails(id) { + const endpoint = `/index.php/apps/openregister/api/audit-trails/${id}` + try { + const response = await fetch(endpoint, { + method: 'GET', + }) + const data = await response.json() + this.setAuditTrails(data) + return data + } catch (err) { + console.error(err) + throw err + } + }, }, }) diff --git a/src/views/object/ObjectDetails.vue b/src/views/object/ObjectDetails.vue index 463c721..a580351 100644 --- a/src/views/object/ObjectDetails.vue +++ b/src/views/object/ObjectDetails.vue @@ -52,9 +52,9 @@ import { objectStore, navigationStore } from '../../store/store.js'
-
-								{{ JSON.stringify(objectStore.objectItem.object, null, 2) }}
-							
+
{{ JSON.stringify(objectStore.objectItem.object, null, 2) }}
+                            
@@ -78,8 +78,7 @@ import { objectStore, navigationStore } from '../../store/store.js'
- - +
@@ -136,9 +135,9 @@ export default { } }, mounted() { - this.getAuditTrails(); + this.getAuditTrails() }, - methods: { + methods: { getAuditTrails() { this.syncLoading = true fetch( @@ -163,7 +162,7 @@ export default { this.auditTrailLoading = false }) }, - } + }, } From c1d8ca49ad43f4cb02fae68e8545f972d55280e5 Mon Sep 17 00:00:00 2001 From: Thijn Date: Tue, 22 Oct 2024 17:46:11 +0200 Subject: [PATCH 5/6] WIP - view audit trail --- src/modals/Modals.vue | 7 ++ .../objectAuditTrail/ViewObjectAuditTrail.vue | 98 +++++++++++++++++++ src/store/modules/object.js | 72 ++++++-------- src/views/object/ObjectDetails.vue | 92 ++++++++--------- src/views/object/ObjectsList.vue | 2 +- 5 files changed, 179 insertions(+), 92 deletions(-) create mode 100644 src/modals/objectAuditTrail/ViewObjectAuditTrail.vue diff --git a/src/modals/Modals.vue b/src/modals/Modals.vue index 5841d55..a2d5cf3 100755 --- a/src/modals/Modals.vue +++ b/src/modals/Modals.vue @@ -1,3 +1,7 @@ + + @@ -25,6 +30,7 @@ import EditSource from './source/EditSource.vue' import DeleteSource from './source/DeleteSource.vue' import EditObject from './object/EditObject.vue' import DeleteObject from './object/DeleteObject.vue' +import ViewObjectAuditTrail from './objectAuditTrail/ViewObjectAuditTrail.vue' export default { name: 'Modals', @@ -39,6 +45,7 @@ export default { DeleteSource, EditObject, DeleteObject, + ViewObjectAuditTrail, }, } diff --git a/src/modals/objectAuditTrail/ViewObjectAuditTrail.vue b/src/modals/objectAuditTrail/ViewObjectAuditTrail.vue new file mode 100644 index 0000000..229a393 --- /dev/null +++ b/src/modals/objectAuditTrail/ViewObjectAuditTrail.vue @@ -0,0 +1,98 @@ + + + + + + + diff --git a/src/store/modules/object.js b/src/store/modules/object.js index 30563d0..20fbff0 100644 --- a/src/store/modules/object.js +++ b/src/store/modules/object.js @@ -119,56 +119,46 @@ export const useObjectStore = defineStore('object', { // change updated to current date as a singular iso date string objectItem.updated = new Date().toISOString() - try { - const response = await fetch( - endpoint, - { - method, - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify(objectItem), + const response = await fetch( + endpoint, + { + method, + headers: { + 'Content-Type': 'application/json', }, - ) - - if (!response.ok) { - throw new Error(`HTTP error! status: ${response.status}`) - } - - const responseData = await response.json() - - console.log(responseData) + body: JSON.stringify(objectItem), + }, + ) - if (!responseData || typeof responseData !== 'object') { - throw new Error('Invalid response data') - } + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`) + } - const data = new ObjectEntity(responseData) + const data = new ObjectEntity(await response.json()) - this.refreshObjectList() - this.setObjectItem(data) + this.refreshObjectList() + this.setObjectItem(data) - return { response, data } - } catch (error) { - console.error('Error saving object:', error) - throw new Error(`Failed to save object: ${error.message}`) - } + return { response, data } }, // AUDIT TRAILS - // New function to get a single object async getAuditTrails(id) { - const endpoint = `/index.php/apps/openregister/api/audit-trails/${id}` - try { - const response = await fetch(endpoint, { - method: 'GET', - }) - const data = await response.json() - this.setAuditTrails(data) - return data - } catch (err) { - console.error(err) - throw err + if (!id) { + throw new Error('No object id to get audit trails for') } + + const endpoint = `/index.php/apps/openregister/api/audit-trails/${id}` + + const response = await fetch(endpoint, { + method: 'GET', + }) + + const responseData = await response.json() + const data = responseData.map((auditTrail) => new AuditTrail(auditTrail)) + + this.setAuditTrails(data) + + return { response, data } }, }, }) diff --git a/src/views/object/ObjectDetails.vue b/src/views/object/ObjectDetails.vue index a580351..98083f7 100644 --- a/src/views/object/ObjectDetails.vue +++ b/src/views/object/ObjectDetails.vue @@ -61,44 +61,34 @@ import { objectStore, navigationStore } from '../../store/store.js' No synchronizations found - -
- +
+ +
-
-
Tijdstip Gebruiker
- - - - - - - - - - - - -
TijdstipGebruikerActieDetails
{{ new Date(auditTrail.created).toLocaleString() }}{{ auditTrail.userName }}{{ auditTrail.action }} - - - Bekijk details - -
+
+ No audit trails found
@@ -109,12 +99,19 @@ import { objectStore, navigationStore } from '../../store/store.js'