Skip to content

Commit

Permalink
Merge pull request #95 from ConductionNL/development
Browse files Browse the repository at this point in the history
Related objects dev to main
  • Loading branch information
remko48 authored Dec 9, 2024
2 parents 5799d7a + d01be00 commit 0911769
Show file tree
Hide file tree
Showing 22 changed files with 598 additions and 141 deletions.
1 change: 1 addition & 0 deletions appinfo/routes.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
['name' => 'objects#logs', 'url' => '/api/objects-logs/{id}', 'verb' => 'GET', 'requirements' => ['id' => '[^/]+']],
['name' => 'objects#mappings', 'url' => '/api/objects/mappings', 'verb' => 'GET'],
['name' => 'objects#auditTrails', 'url' => '/api/objects/audit-trails/{id}', 'verb' => 'GET', 'requirements' => ['id' => '[^/]+']],
['name' => 'objects#relations', 'url' => '/api/objects/relations/{id}', 'verb' => 'GET', 'requirements' => ['id' => '[^/]+']],
['name' => 'schemas#upload', 'url' => '/api/schemas/upload', 'verb' => 'POST'],
['name' => 'schemas#uploadUpdate', 'url' => '/api/schemas/{id}/upload', 'verb' => 'PUT', 'requirements' => ['id' => '[^/]+']],
['name' => 'schemas#download', 'url' => '/api/schemas/{id}/download', 'verb' => 'GET', 'requirements' => ['id' => '[^/]+']],
Expand Down
40 changes: 37 additions & 3 deletions lib/Controller/ObjectsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ public function create(ObjectService $objectService): JSONResponse
*
* @return JSONResponse A JSON response containing the updated object details
*/
public function update(int $id): JSONResponse
public function update(int $id, ObjectService $objectService): JSONResponse
{
$data = $this->request->getParams();
$object = $data['object'];
Expand All @@ -204,8 +204,12 @@ public function update(int $id): JSONResponse
}

// save it
$oldObject = $this->objectEntityMapper->find($id);
$objectEntity = $this->objectEntityMapper->updateFromArray(id: $id, object: $data);
try {
$objectEntity = $objectService->saveObject(register: $data['register'], schema: $data['schema'], object: $data['object']);
} catch (ValidationException $exception) {
$formatter = new ErrorFormatter();
return new JSONResponse(['message' => $exception->getMessage(), 'validationErrors' => $formatter->format($exception->getErrors())], 400);
}

$this->auditTrailMapper->createAuditTrail(new: $objectEntity, old: $oldObject);

Expand Down Expand Up @@ -274,6 +278,36 @@ public function contracts(int $id): JSONResponse
return new JSONResponse(['error' => 'Not yet implemented'], 501);
}

/**
* Retrieves all objects that use a object
*
* This method returns all the call logs associated with a object based on its ID.
*
* @NoAdminRequired
* @NoCSRFRequired
*
* @param int $id The ID of the object to retrieve logs for
*
* @return JSONResponse A JSON response containing the call logs
*/
public function relations(int $id): JSONResponse
{
try {
// Lets grap the object to stablish an uri
$object = $this->objectEntityMapper->find($id);
$relations = $this->objectEntityMapper->findByRelationUri($object->getUri());

// We dont want to return the entity, but the object (and kant reley on the normal serilzier)
foreach ($relations as $key => $relation) {
$relations[$key] = $relation->getObjectArray();
}

return new JSONResponse($relations);
} catch (DoesNotExistException $e) {
return new JSONResponse(['error' => 'Relations not found'], 404);
}
}

/**
* Retrieves call logs for an object
*
Expand Down
37 changes: 13 additions & 24 deletions lib/Controller/SchemasController.php
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,8 @@ public function upload(?int $id = null): JSONResponse
return $phpArray;
}

//@todo Maybe check if Schema already exists? If uploaded with url, check if schema with this $phpArray['source'] exists?
// Set default title if not provided or empty
if (empty($phpArray['title']) === true) {
$phpArray['title'] = 'New Schema';
Expand All @@ -236,43 +238,30 @@ public function upload(?int $id = null): JSONResponse

/**
* Creates and return a json file for a Schema.
* @todo move most of this code to DownloadService and make it even more Abstract using Entity->jsonSerialize instead of Schema->jsonSerialize, etc.
*
* @NoAdminRequired
* @NoCSRFRequired
*
* @param int $id The ID of the schema to return json file for
* @return JSONResponse A json Response containing the json
* @throws \Exception
*/
public function download(int $id): JSONResponse
{
try {
$schema = $this->schemaMapper->find($id);
} catch (DoesNotExistException $exception) {
return new JSONResponse(data: ['error' => 'Not Found'], statusCode: 404);
}

$contentType = $this->request->getHeader('Content-Type');
$accept = $this->request->getHeader('Accept');

if (empty($contentType) === true) {
return new JSONResponse(data: ['error' => 'Request is missing header Content-Type'], statusCode: 400);
if (empty($accept) === true) {
return new JSONResponse(data: ['error' => 'Request is missing header Accept'], statusCode: 400);
}

switch ($contentType) {
case 'application/json':
$type = 'json';
$responseData = [
'jsonArray' => $schema->jsonSerialize(),
'jsonString' => json_encode($schema->jsonSerialize())
];
break;
default:
return new JSONResponse(data: ['error' => "The Content-Type $contentType is not supported."], statusCode: 400);
}
$responseData = $this->downloadService->download(objectType: 'schema', id: $id, accept: $accept);

// @todo Create a downloadable json file and return it.
$file = $this->downloadService->download(type: $type);
$statusCode = 200;
if (isset($responseData['statusCode']) === true) {
$statusCode = $responseData['statusCode'];
unset($responseData['statusCode']);
}

return new JSONResponse($responseData);
return new JSONResponse(data: $responseData, statusCode: $statusCode);
}
}
9 changes: 6 additions & 3 deletions lib/Db/ObjectAuditLogMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,12 @@ public function updateFromArray(int $id, array $object): ObjectAuditLog
$obj->hydrate($object);

// Set or update the version
$version = explode('.', $obj->getVersion());
$version[2] = (int)$version[2] + 1;
$obj->setVersion(implode('.', $version));
if (isset($object['version']) === false) {
$version = explode('.', $obj->getVersion());
$version[2] = (int)$version[2] + 1;
$obj->setVersion(implode('.', $version));
}


return $this->update($obj);
}
Expand Down
68 changes: 63 additions & 5 deletions lib/Db/ObjectEntityMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -181,12 +181,36 @@ public function findAll(?int $limit = null, ?int $offset = null, ?array $filters
}
}

// @roto: tody this code up please and make ik monogdb compatible
// Check if _relations filter exists to search in relations column
if (isset($filters['_relations']) === true) {
// Handle both single string and array of relations
$relations = (array) $filters['_relations'];

// Build OR conditions for each relation
$orConditions = [];
foreach ($relations as $relation) {
$orConditions[] = $qb->expr()->isNotNull(
$qb->createFunction(
"JSON_SEARCH(relations, 'one', " .
$qb->createNamedParameter($relation) .
", NULL, '$')"
)
);
}

// Add the combined OR conditions to query
$qb->andWhere($qb->expr()->orX(...$orConditions));

// Remove _relations from filters since it's handled separately
unset($filters['_relations']);
}

// Filter and search the objects
$qb = $this->databaseJsonService->filterJson(builder: $qb, filters: $filters);
$qb = $this->databaseJsonService->searchJson(builder: $qb, search: $search);
$qb = $this->databaseJsonService->orderJson(builder: $qb, order: $sort);

// var_dump($qb->getSQL());

return $this->findEntities(query: $qb);
}

Expand Down Expand Up @@ -219,9 +243,12 @@ public function updateFromArray(int $id, array $object): ObjectEntity
$obj->hydrate($object);

// Set or update the version
$version = explode('.', $obj->getVersion());
$version[2] = (int)$version[2] + 1;
$obj->setVersion(implode('.', $version));
if (isset($object['version']) === false) {
$version = explode('.', $obj->getVersion());
$version[2] = (int)$version[2] + 1;
$obj->setVersion(implode('.', $version));
}


return $this->update($obj);
}
Expand Down Expand Up @@ -265,4 +292,35 @@ public function getFacets(array $filters = [], ?string $search = null)
search: $search
);
}

/**
* Find objects that have a specific URI or UUID in their relations
*
* @param string $search The URI or UUID to search for in relations
* @param bool $partialMatch Whether to search for partial matches (default: false)
* @return array An array of ObjectEntities that have the specified URI/UUID
*/
public function findByRelationUri(string $search, bool $partialMatch = false): array
{
$qb = $this->db->getQueryBuilder();

// For partial matches, we use '%' wildcards and 'all' mode to search anywhere in the JSON
// For exact matches, we use 'one' mode which finds exact string matches
$mode = $partialMatch ? 'all' : 'one';
$searchTerm = $partialMatch ? '%' . $search . '%' : $search;

$qb->select('*')
->from('openregister_objects')
->where(
$qb->expr()->isNotNull(
$qb->createFunction(
"JSON_SEARCH(relations, '" . $mode . "', " .
$qb->createNamedParameter($searchTerm) .
($partialMatch ? ", NULL, '$')" : ")")
)
)
);

return $this->findEntities($qb);
}
}
10 changes: 6 additions & 4 deletions lib/Db/RegisterMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

/**
* The RegisterMapper class
*
*
* @package OCA\OpenRegister\Db
*/
class RegisterMapper extends QBMapper
Expand Down Expand Up @@ -128,9 +128,11 @@ public function updateFromArray(int $id, array $object): Register
$obj->hydrate($object);

// Update the version
$version = explode('.', $obj->getVersion());
$version[2] = (int)$version[2] + 1;
$obj->setVersion(implode('.', $version));
if (isset($object['version']) === false) {
$version = explode('.', $obj->getVersion());
$version[2] = (int)$version[2] + 1;
$obj->setVersion(implode('.', $version));
}

// Update the register and return it
return $this->update($obj);
Expand Down
53 changes: 15 additions & 38 deletions lib/Db/Schema.php
Original file line number Diff line number Diff line change
Expand Up @@ -79,32 +79,17 @@ public function hydrate(array $object): self
*/
public function jsonSerialize(): array
{
$required = $this->required ?? [];
$properties = [];
if (isset($this->properties) === true) {
foreach ($this->properties as $key => $property) {
$properties[$key] = $property;
if (isset($property['type']) === false) {
$properties[$key] = $property;
continue;
foreach ($this->properties as $title => $property) {
$title = $property['title'] ?? $title;
if ($property['required'] === true && in_array($title, $required) === false) {
$required[] = $title;
}
unset($property['title'], $property['required']);

if (isset($property['format']) === true) {
switch ($property['format']) {
case 'string':
// For now array as string
case 'array':
$properties[$key]['default'] = (string) $property;
break;
case 'int':
case 'integer':
case 'number':
$properties[$key]['default'] = (int) $property;
break;
case 'bool':
$properties[$key]['default'] = (bool) $property;
break;
}
}
$properties[$title] = $property;
}
}

Expand All @@ -115,7 +100,7 @@ public function jsonSerialize(): array
'description' => $this->description,
'version' => $this->version,
'summary' => $this->summary,
'required' => $this->required,
'required' => $required,
'properties' => $properties,
'archive' => $this->archive,
'source' => $this->source,
Expand Down Expand Up @@ -143,29 +128,21 @@ public function jsonSerialize(): array
public function getSchemaObject(IURLGenerator $urlGenerator): object
{
$data = $this->jsonSerialize();
$properties = $data['properties'];
unset($data['properties'], $data['id'], $data['uuid'], $data['summary'], $data['archive'], $data['source'],
$data['updated'], $data['created']);

$data['required'] = [];

$data['type'] = 'object';

foreach ($properties as $property) {
$title = $property['title'];
if ($property['required'] === true) {
$data['required'][] = $title;
}
unset($property['title'], $property['required']);

foreach ($data['properties'] as $title => $property) {
// Remove empty fields with array_filter().
$data['properties'][$title] = array_filter($property);
}

unset($data['id'], $data['uuid'], $data['summary'], $data['archive'], $data['source'],
$data['updated'], $data['created']);

$data['type'] = 'object';

// Validator needs this specific $schema
$data['$schema'] = 'https://json-schema.org/draft/2020-12/schema';
$data['$id'] = $urlGenerator->getAbsoluteURL($urlGenerator->linkToRoute('openregister.Schemas.show', ['id' => $this->getUuid()]));


return json_decode(json_encode($data));
}
}
8 changes: 5 additions & 3 deletions lib/Db/SchemaMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -133,9 +133,11 @@ public function updateFromArray(int $id, array $object): Schema
$obj->hydrate($object);

// Set or update the version
$version = explode('.', $obj->getVersion());
$version[2] = (int)$version[2] + 1;
$obj->setVersion(implode('.', $version));
if (isset($object['version']) === false) {
$version = explode('.', $obj->getVersion());
$version[2] = (int)$version[2] + 1;
$obj->setVersion(implode('.', $version));
}

return $this->update($obj);
}
Expand Down
10 changes: 6 additions & 4 deletions lib/Db/SourceMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

/**
* The SourceMapper class
*
*
* @package OCA\OpenRegister\Db
*/
class SourceMapper extends QBMapper
Expand Down Expand Up @@ -116,9 +116,11 @@ public function updateFromArray(int $id, array $object): Source
$obj->hydrate($object);

// Set or update the version
$version = explode('.', $obj->getVersion());
$version[2] = (int)$version[2] + 1;
$obj->setVersion(implode('.', $version));
if (isset($object['version']) === false) {
$version = explode('.', $obj->getVersion());
$version[2] = (int)$version[2] + 1;
$obj->setVersion(implode('.', $version));
}

return $this->update($obj);
}
Expand Down
Loading

0 comments on commit 0911769

Please sign in to comment.