diff --git a/css/main.css b/css/main.css
index 1e75f17d..a3db6830 100644
--- a/css/main.css
+++ b/css/main.css
@@ -168,3 +168,47 @@
margin-left: 16px;
color: inherit;
}
+
+/* CodeMirror */
+.codeMirrorContainer {
+ margin-block-start: 6px;
+ text-align: left;
+}
+
+.prettifyButton {
+ margin-block-start: 10px;
+}
+
+.codeMirrorContainer * .cm-content {
+ border-radius: 0 !important;
+ border: none !important;
+}
+.codeMirrorContainer * .cm-editor {
+ outline: none !important;
+}
+.codeMirrorContainer.light > .vue-codemirror {
+ border: 1px dotted silver;
+}
+.codeMirrorContainer.dark > .vue-codemirror {
+ border: 1px dotted grey;
+}
+
+/* value text color */
+.codeMirrorContainer.light * .cm-content *::selection {
+ color: inherit !important;
+ background-color: #add6ff80 !important;
+}
+.codeMirrorContainer.dark * .cm-content *::selection {
+ color: inherit !important;
+ background-color: #add6ff26 !important;
+}
+
+/* value text color */
+.codeMirrorContainer.dark :deep(.ͼ2 .cm-activeLine) {
+ background-color: #add6ff26;
+}
+
+/* text cursor */
+.codeMirrorContainer :deep(.cm-content) * {
+ cursor: text !important;
+}
diff --git a/lib/Controller/AttachmentsController.php b/lib/Controller/AttachmentsController.php
index d692f5ff..ffb8160a 100644
--- a/lib/Controller/AttachmentsController.php
+++ b/lib/Controller/AttachmentsController.php
@@ -16,6 +16,7 @@
use OCP\IAppConfig;
use OCP\IRequest;
use OCP\IUserSession;
+use OCP\IURLGenerator;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
use Symfony\Component\Uid\Uuid;
@@ -37,6 +38,7 @@ class AttachmentsController extends Controller
* @param FileService $fileService The file service
* @param IUserSession $userSession The user session
* @param ObjectService $objectService The object service
+ * @param IURLGenerator $urlGenerator The URL generator
*/
public function __construct
(
@@ -46,7 +48,8 @@ public function __construct
private readonly AttachmentMapper $attachmentMapper,
private readonly FileService $fileService,
private readonly IUserSession $userSession,
- private readonly ObjectService $objectService
+ private readonly ObjectService $objectService,
+ private readonly IURLGenerator $urlGenerator
)
{
parent::__construct($appName, $request);
@@ -129,6 +132,17 @@ public function create(ObjectService $objectService): JSONResponse
// Save the new attachment object.
$object = $this->objectService->saveObject('attachment', $data);
+ // If object is a class change it to array
+ if (is_object($object) === true) {
+ $object = $object->jsonSerialize();
+ }
+
+ // If we do not have an uri, we need to generate one
+ if (isset($object['uri']) === false) {
+ $object['uri'] = $this->urlGenerator->getAbsoluteURL($this->urlGenerator->linkToRoute('openCatalogi.attachments.show', ['id' => $object['id']]));
+ $object = $this->objectService->saveObject('attachment', $object);
+ }
+
// Return the created object as a JSON response.
return new JSONResponse($object);
}
@@ -153,6 +167,9 @@ public function update(string|int $id, ObjectService $objectService): JSONRespon
// Ensure the ID in the data matches the ID in the URL
$data['id'] = $id;
+ // If we do not have an uri, we need to generate one
+ $data['uri'] = $this->urlGenerator->getAbsoluteURL($this->urlGenerator->linkToRoute('openCatalogi.attachments.show', ['id' => $data['id']]));
+
// Save the updated attachment object
$object = $this->objectService->saveObject('attachment', $data);
diff --git a/lib/Controller/CatalogiController.php b/lib/Controller/CatalogiController.php
index 002e7fea..23d43adf 100644
--- a/lib/Controller/CatalogiController.php
+++ b/lib/Controller/CatalogiController.php
@@ -13,6 +13,7 @@
use OCP\AppFramework\Http\JSONResponse;
use OCP\IAppConfig;
use OCP\IRequest;
+use OCP\IURLGenerator;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
@@ -33,6 +34,7 @@ class CatalogiController extends Controller
* @param ObjectService $objectService The object service
* @param DirectoryService $directoryService The directory service
* @param BroadcastService $broadcastService The broadcast service
+ * @param IURLGenerator $urlGenerator The URL generator
*/
public function __construct(
$appName,
@@ -41,7 +43,8 @@ public function __construct(
private readonly CatalogMapper $catalogMapper,
private readonly ObjectService $objectService,
private readonly DirectoryService $directoryService,
- private readonly BroadcastService $broadcastService
+ private readonly BroadcastService $broadcastService,
+ private readonly IURLGenerator $urlGenerator
)
{
parent::__construct($appName, $request);
@@ -114,6 +117,17 @@ public function create(ObjectService $objectService): JSONResponse
// Save the new catalog object
$object = $this->objectService->saveObject('catalog', $data);
+ // If object is a class change it to array
+ if (is_object($object) === true) {
+ $object = $object->jsonSerialize();
+ }
+
+ // If we do not have an uri, we need to generate one
+ if (isset($object['uri']) === false) {
+ $object['uri'] = $this->urlGenerator->getAbsoluteURL($this->urlGenerator->linkToRoute('openCatalogi.catalogs.show', ['id' => $object['id']]));
+ $object = $this->objectService->saveObject('catalog', $object);
+ }
+
// Update all external directories
$this->broadcastService->broadcast();
@@ -142,6 +156,9 @@ public function update(string|int $id, ObjectService $objectService): JSONRespon
// Ensure the ID in the data matches the ID in the URL
$data['id'] = $id;
+ // If we do not have an uri, we need to generate one
+ $data['uri'] = $this->urlGenerator->getAbsoluteURL($this->urlGenerator->linkToRoute('openCatalogi.catalogs.show', ['id' => $data['id']]));
+
// Save the updated catalog object
$object = $this->objectService->saveObject('catalog', $data);
diff --git a/lib/Controller/OrganizationsController.php b/lib/Controller/OrganizationsController.php
index e4865f42..9ee1f6c1 100644
--- a/lib/Controller/OrganizationsController.php
+++ b/lib/Controller/OrganizationsController.php
@@ -10,7 +10,7 @@
use OCP\AppFramework\Http\JSONResponse;
use OCP\IAppConfig;
use OCP\IRequest;
-
+use OCP\IURLGenerator;
/**
* Class OrganizationsController
*
@@ -26,13 +26,15 @@ class OrganizationsController extends Controller
* @param IAppConfig $config The app configuration
* @param OrganizationMapper $organizationMapper The organization mapper
* @param ObjectService $objectService The object service
+ * @param IURLGenerator $urlGenerator The URL generator
*/
public function __construct(
$appName,
IRequest $request,
private readonly IAppConfig $config,
private readonly OrganizationMapper $organizationMapper,
- private readonly ObjectService $objectService
+ private readonly ObjectService $objectService,
+ private readonly IURLGenerator $urlGenerator
)
{
parent::__construct($appName, $request);
@@ -109,6 +111,17 @@ public function create(): JSONResponse
// Save the new organization object
$object = $this->objectService->saveObject('organization', $data);
+ // If object is a class change it to array
+ if (is_object($object) === true) {
+ $object = $object->jsonSerialize();
+ }
+
+ // If we do not have an uri, we need to generate one
+ if (isset($object['uri']) === false) {
+ $object['uri'] = $this->urlGenerator->getAbsoluteURL($this->urlGenerator->linkToRoute('openCatalogi.organizations.show', ['id' => $object['id']]));
+ $object = $this->objectService->saveObject('organization', $object);
+ }
+
// Return the created object as a JSON response
return new JSONResponse($object);
}
@@ -130,6 +143,9 @@ public function update(string|int $id): JSONResponse
// Ensure the ID in the data matches the ID in the URL
$data['id'] = $id;
+ // If we do not have an uri, we need to generate one
+ $data['uri'] = $this->urlGenerator->getAbsoluteURL($this->urlGenerator->linkToRoute('openCatalogi.organizations.show', ['id' => $data['id']]));
+
// Save the updated organization object
$object = $this->objectService->saveObject('organization', $data);
diff --git a/lib/Controller/PublicationTypesController.php b/lib/Controller/PublicationTypesController.php
index eba92db1..ee90e82f 100644
--- a/lib/Controller/PublicationTypesController.php
+++ b/lib/Controller/PublicationTypesController.php
@@ -11,7 +11,7 @@
use OCP\AppFramework\Http\JSONResponse;
use OCP\IAppConfig;
use OCP\IRequest;
-
+use OCP\IURLGenerator;
/**
* Class PublicationTypesController
*
@@ -29,6 +29,7 @@ class PublicationTypesController extends Controller
* @param ObjectService $objectService The object service
* @param DirectoryService $directoryService The directory service
* @param BroadcastService $broadcastService The broadcast service
+ * @param IURLGenerator $urlGenerator The URL generator
*/
public function __construct(
$appName,
@@ -37,7 +38,8 @@ public function __construct(
private readonly PublicationTypeMapper $publicationTypeMapper,
private readonly ObjectService $objectService,
private readonly DirectoryService $directoryService,
- private readonly BroadcastService $broadcastService
+ private readonly BroadcastService $broadcastService,
+ private readonly IURLGenerator $urlGenerator
)
{
parent::__construct($appName, $request);
@@ -118,6 +120,17 @@ public function create(): JSONResponse
// Save the new publication type object
$object = $this->objectService->saveObject('publicationType', $data);
+ // If object is a class change it to array
+ if (is_object($object) === true) {
+ $object = $object->jsonSerialize();
+ }
+
+ // If we do not have an uri, we need to generate one
+ if (isset($object['uri']) === false) {
+ $object['uri'] = $this->urlGenerator->getAbsoluteURL($this->urlGenerator->linkToRoute('openCatalogi.publicationTypes.show', ['id' => $object['id']]));
+ $object = $this->objectService->saveObject('publicationType', $object);
+ }
+
// Update all external directories
$this->broadcastService->broadcast();
@@ -142,6 +155,10 @@ public function update(string|int $id): JSONResponse
// Ensure the ID in the data matches the ID in the URL
$data['id'] = $id;
+ // If we do not have an uri, we need to generate one
+ $data['uri'] = $this->urlGenerator->getAbsoluteURL($this->urlGenerator->linkToRoute('openCatalogi.publicationTypes.show', ['id' => $data['id']]));
+
+
// Save the updated publication type object
$object = $this->objectService->saveObject('publicationType', $data);
@@ -169,7 +186,7 @@ public function destroy(string|int $id): JSONResponse
// Return the result as a JSON response
return new JSONResponse(['success' => $result], $result === true ? '200' : '404');
}
-
+
/**
* Synchronize or delete a publication type based on listing status
*
diff --git a/lib/Controller/PublicationsController.php b/lib/Controller/PublicationsController.php
index 47a1c8de..5a770793 100644
--- a/lib/Controller/PublicationsController.php
+++ b/lib/Controller/PublicationsController.php
@@ -24,6 +24,7 @@
use OCP\AppFramework\OCS\OCSNotFoundException;
use OCP\IAppConfig;
use OCP\IRequest;
+use OCP\IURLGenerator;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
use Symfony\Component\Uid\Uuid;
@@ -49,6 +50,8 @@ class PublicationsController extends Controller
* @param FileService $fileService The file service
* @param DownloadService $downloadService The download service
* @param ObjectService $objectService The object service
+ * @param IURLGenerator $urlGenerator The URL generator
+ *
*/
public function __construct
(
@@ -59,7 +62,8 @@ public function __construct
private readonly IAppConfig $config,
private readonly FileService $fileService,
private readonly DownloadService $downloadService,
- private ObjectService $objectService
+ private readonly ObjectService $objectService,
+ private readonly IURLGenerator $urlGenerator
)
{
parent::__construct($appName, $request);
@@ -197,6 +201,17 @@ public function create(ObjectService $objectService): JSONResponse
// Save the new publication object
$object = $this->objectService->saveObject('publication', $data);
+ // If object is a class change it to array
+ if (is_object($object) === true) {
+ $object = $object->jsonSerialize();
+ }
+
+ // If we do not have an uri, we need to generate one
+ if (isset($object['uri']) === false) {
+ $object['uri'] = $this->urlGenerator->getAbsoluteURL($this->urlGenerator->linkToRoute('openCatalogi.publications.show', ['id' => $object['id']]));
+ $object = $this->objectService->saveObject('publication', $object);
+ }
+
// Return the created object as a JSON response
return new JSONResponse($object);
}
@@ -221,6 +236,9 @@ public function update(string|int $id, ObjectService $objectService): JSONRespon
// Ensure the ID in the data matches the ID in the URL
$data['id'] = $id;
+ // If we do not have an uri, we need to generate one
+ $data['uri'] = $this->urlGenerator->getAbsoluteURL($this->urlGenerator->linkToRoute('openCatalogi.publications.show', ['id' => $data['id']]));
+
// Save the updated publication object
$object = $this->objectService->saveObject('publication', $data);
diff --git a/lib/Controller/ThemesController.php b/lib/Controller/ThemesController.php
index 341d5292..b5233943 100644
--- a/lib/Controller/ThemesController.php
+++ b/lib/Controller/ThemesController.php
@@ -11,7 +11,7 @@
use OCP\AppFramework\Http\JSONResponse;
use OCP\IAppConfig;
use OCP\IRequest;
-
+use OCP\IURLGenerator;
/**
* Class ThemesController
*
@@ -27,6 +27,7 @@ class ThemesController extends Controller
* @param ThemeMapper $themeMapper The theme mapper for database operations
* @param IAppConfig $config The app configuration
* @param ObjectService $objectService The service for handling object operations
+ * @param IURLGenerator $urlGenerator The URL generator
*/
public function __construct
(
@@ -34,7 +35,8 @@ public function __construct
IRequest $request,
private readonly ThemeMapper $themeMapper,
private readonly IAppConfig $config,
- private readonly ObjectService $objectService
+ private readonly ObjectService $objectService,
+ private readonly IURLGenerator $urlGenerator
)
{
parent::__construct($appName, $request);
@@ -97,6 +99,17 @@ public function create(): JSONResponse
// Save the new theme object
$object = $this->objectService->saveObject('theme', $data);
+ // If object is a class change it to array
+ if (is_object($object) === true) {
+ $object = $object->jsonSerialize();
+ }
+
+ // If we do not have an uri, we need to generate one
+ if (isset($object['uri']) === false) {
+ $object['uri'] = $this->urlGenerator->getAbsoluteURL($$this->urlGenerator->linkToRoute('openCatalogi.themes.show', ['id' => $object['id']]));
+ $object = $this->objectService->saveObject('theme', $object);
+ }
+
// Return the created object as a JSON response
return new JSONResponse($object);
}
@@ -118,6 +131,9 @@ public function update(string|int $id): JSONResponse
// Ensure the ID in the data matches the ID in the URL
$data['id'] = $id;
+ // If we do not have an uri, we need to generate one
+ $data['uri'] = $this->urlGenerator->getAbsoluteURL($this->urlGenerator->linkToRoute('openCatalogi.themes.show', ['id' => $data['id']]));
+
// Save the updated theme object
$object = $this->objectService->saveObject('theme', $data);
diff --git a/lib/Db/Attachment.php b/lib/Db/Attachment.php
index dd55e64a..5aa72062 100644
--- a/lib/Db/Attachment.php
+++ b/lib/Db/Attachment.php
@@ -9,6 +9,7 @@
class Attachment extends Entity implements JsonSerializable
{
protected ?string $uuid = null;
+ protected ?string $uri = null;
protected ?string $version = '0.0.1';
protected ?string $reference = null;
protected ?string $title = null;
@@ -32,6 +33,7 @@ class Attachment extends Entity implements JsonSerializable
public function __construct() {
$this->addType(fieldName: 'uuid', type: 'string');
+ $this->addType(fieldName: 'uri', type: 'string');
$this->addType(fieldName: 'version', type: 'string');
$this->addType(fieldName: 'reference', type: 'string');
$this->addType(fieldName: 'title', type: 'string');
@@ -96,6 +98,7 @@ public function jsonSerialize(): array
$array = [
'id' => $this->id,
'uuid' => $this->uuid,
+ 'uri' => $this->uri,
'version' => $this->version,
'reference' => $this->reference,
'title' => $this->title,
diff --git a/lib/Db/AttachmentMapper.php b/lib/Db/AttachmentMapper.php
index 0832eaaf..9ecd4b8a 100644
--- a/lib/Db/AttachmentMapper.php
+++ b/lib/Db/AttachmentMapper.php
@@ -9,6 +9,7 @@
use OCP\AppFramework\Db\QBMapper;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\IDBConnection;
+use OCP\IURLGenerator;
use Symfony\Component\Uid\Uuid;
/**
@@ -25,8 +26,9 @@ class AttachmentMapper extends QBMapper
* Constructor for AttachmentMapper
*
* @param IDBConnection $db The database connection
+ * @param IURLGenerator $urlGenerator The URL generator
*/
- public function __construct(IDBConnection $db)
+ public function __construct(IDBConnection $db, IURLGenerator $urlGenerator)
{
parent::__construct($db, tableName: 'ocat_attachments');
}
@@ -105,6 +107,8 @@ public function findAll(int $limit = null, int $offset = null, array $filters =
public function createFromArray(array $object): Attachment
{
$attachment = new Attachment();
+
+ // Hydrate the attachment with the new data
$attachment->hydrate(object: $object);
// Set uuid if not provided
@@ -112,6 +116,9 @@ public function createFromArray(array $object): Attachment
$attachment->setUuid(Uuid::v4());
}
+ // Set the uri
+ $attachment->setUri($this->urlGenerator->getAbsoluteURL($this->urlGenerator->linkToRoute('opencatalogi.attachments.show', ['id' => $attachment->getUuid()])));
+
return $this->insert(entity: $attachment);
}
@@ -135,8 +142,12 @@ public function updateFromArray(int $id, array $object, bool $updateVersion = tr
return $this->createFromArray($object);
}
+ // Hydrate the attachment with the new data
$attachment->hydrate($object);
+ // Set the uri
+ $attachment->setUri($this->urlGenerator->getAbsoluteURL($this->urlGenerator->linkToRoute('opencatalogi.attachments.show', ['id' => $attachment->getUuid()])));
+
if ($updateVersion === true) {
// Update the version
$version = explode('.', $attachment->getVersion());
diff --git a/lib/Db/Catalog.php b/lib/Db/Catalog.php
index bc24ca9d..20aed8db 100644
--- a/lib/Db/Catalog.php
+++ b/lib/Db/Catalog.php
@@ -9,6 +9,7 @@
class Catalog extends Entity implements JsonSerializable
{
protected ?string $uuid = null;
+ protected ?string $uri = null;
protected ?string $version = '0.0.1';
protected ?string $title = null;
protected ?string $summary = null;
@@ -23,6 +24,7 @@ class Catalog extends Entity implements JsonSerializable
public function __construct() {
$this->addType(fieldName: 'uuid', type: 'string');
+ $this->addType(fieldName: 'uri', type: 'string');
$this->addType(fieldName: 'version', type: 'string');
$this->addType(fieldName: 'title', type: 'string');
$this->addType(fieldName: 'summary', type: 'string');
@@ -78,6 +80,7 @@ public function jsonSerialize(): array
{
$array = [
'id' => $this->id,
+ 'uri' => $this->uri,
'uuid' => $this->uuid,
'version' => $this->version,
'title' => $this->title,
diff --git a/lib/Db/CatalogMapper.php b/lib/Db/CatalogMapper.php
index 6bb66f91..6e924fe0 100644
--- a/lib/Db/CatalogMapper.php
+++ b/lib/Db/CatalogMapper.php
@@ -7,6 +7,7 @@
use OCP\AppFramework\Db\QBMapper;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\IDBConnection;
+use OCP\IURLGenerator;
use Symfony\Component\Uid\Uuid;
/**
@@ -23,8 +24,9 @@ class CatalogMapper extends QBMapper
* Constructor for CatalogMapper
*
* @param IDBConnection $db The database connection
+ * @param IURLGenerator $urlGenerator The URL generator
*/
- public function __construct(IDBConnection $db)
+ public function __construct(IDBConnection $db, IURLGenerator $urlGenerator)
{
parent::__construct($db, tableName: 'ocat_catalogi');
}
@@ -128,6 +130,9 @@ public function createFromArray(array $object): Catalog
$catalog->setUuid(Uuid::v4());
}
+ // Set the uri
+ $catalog->setUri($this->urlGenerator->getAbsoluteURL($this->urlGenerator->linkToRoute('opencatalogi.catalogs.show', ['id' => $catalog->getUuid()])));
+
return $this->insert(entity: $catalog);
}
@@ -149,8 +154,12 @@ public function updateFromArray(int $id, array $object, bool $updateVersion = tr
return $this->createFromArray($object);
}
+ // Hydrate the catalog with the new data
$catalog->hydrate($object);
+ // Set the uri
+ $catalog->setUri($this->urlGenerator->getAbsoluteURL($this->urlGenerator->linkToRoute('opencatalogi.catalogs.show', ['id' => $catalog->getUuid()])));
+
if ($updateVersion === true) {
// Update the version
$version = explode('.', $catalog->getVersion());
diff --git a/lib/Db/Organization.php b/lib/Db/Organization.php
index 8d227c7a..9e46735e 100644
--- a/lib/Db/Organization.php
+++ b/lib/Db/Organization.php
@@ -9,6 +9,7 @@
class Organization extends Entity implements JsonSerializable
{
protected ?string $uuid = null;
+ protected ?string $uri = null;
protected ?string $version = '0.0.1';
protected ?string $title = null;
protected ?string $summary = null;
@@ -24,6 +25,7 @@ class Organization extends Entity implements JsonSerializable
public function __construct() {
$this->addType(fieldName: 'uuid', type: 'string');
+ $this->addType(fieldName: 'uri', type: 'string');
$this->addType(fieldName: 'version', type: 'string');
$this->addType(fieldName: 'title', type: 'string');
$this->addType(fieldName: 'summary', type: 'string');
@@ -79,6 +81,7 @@ public function jsonSerialize(): array
$array = [
'id' => $this->id,
'uuid' => $this->uuid,
+ 'uri' => $this->uri,
'version' => $this->version,
'title' => $this->title,
'summary' => $this->summary,
diff --git a/lib/Db/OrganizationMapper.php b/lib/Db/OrganizationMapper.php
index 3c605d4c..ee2b638b 100644
--- a/lib/Db/OrganizationMapper.php
+++ b/lib/Db/OrganizationMapper.php
@@ -7,6 +7,7 @@
use OCP\AppFramework\Db\QBMapper;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\IDBConnection;
+use OCP\IURLGenerator;
use Symfony\Component\Uid\Uuid;
/**
@@ -23,6 +24,7 @@ class OrganizationMapper extends QBMapper
* Constructor for OrganizationMapper
*
* @param IDBConnection $db The database connection
+ * @param IURLGenerator $urlGenerator The URL generator
*/
public function __construct(IDBConnection $db)
{
@@ -123,6 +125,10 @@ public function createFromArray(array $object): Organization
if ($organization->getUuid() === null) {
$organization->setUuid(Uuid::v4());
}
+
+ // Set the uri
+ $organization->setUri($this->urlGenerator->getAbsoluteURL($this->urlGenerator->linkToRoute('opencatalogi.organizations.show', ['id' => $organization->getUuid()])));
+
return $this->insert(entity: $organization);
}
@@ -144,8 +150,12 @@ public function updateFromArray(int $id, array $object, bool $updateVersion = tr
return $this->createFromArray($object);
}
+ // Hydrate the organization with the new data
$organization->hydrate($object);
+ // Set the uri
+ $organization->setUri($this->urlGenerator->getAbsoluteURL($this->urlGenerator->linkToRoute('opencatalogi.organizations.show', ['id' => $organization->getUuid()])));
+
if ($updateVersion === true) {
// Update the version
$version = explode('.', $organization->getVersion());
diff --git a/lib/Db/Publication.php b/lib/Db/Publication.php
index 4b3d3e49..f82a17ec 100644
--- a/lib/Db/Publication.php
+++ b/lib/Db/Publication.php
@@ -9,6 +9,7 @@
class Publication extends Entity implements JsonSerializable
{
protected ?string $uuid = null;
+ protected ?string $uri = null;
protected ?string $version = '0.0.1';
protected ?string $title = null;
protected ?string $reference = null;
@@ -39,6 +40,7 @@ class Publication extends Entity implements JsonSerializable
public function __construct() {
$this->addType(fieldName: 'uuid', type: 'string');
+ $this->addType(fieldName: 'uri', type: 'string');
$this->addType(fieldName: 'version', type: 'string');
$this->addType(fieldName: 'title', type: 'string');
$this->addType(fieldName: 'reference', type: 'string');
@@ -125,6 +127,7 @@ public function jsonSerialize(): array
{
$array = [
'id' => $this->id,
+ 'uri' => $this->uri,
'uuid' => $this->uuid,
'version' => $this->version,
'title' => $this->title,
diff --git a/lib/Db/PublicationMapper.php b/lib/Db/PublicationMapper.php
index 56363f96..47c48d2f 100644
--- a/lib/Db/PublicationMapper.php
+++ b/lib/Db/PublicationMapper.php
@@ -8,6 +8,7 @@
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\DB\Types;
use OCP\IDBConnection;
+use OCP\IURLGenerator;
use Symfony\Component\Uid\Uuid;
/**
@@ -24,8 +25,9 @@ class PublicationMapper extends QBMapper
* Constructor for PublicationMapper
*
* @param IDBConnection $db The database connection
+ * @param IURLGenerator $urlGenerator The URL generator
*/
- public function __construct(IDBConnection $db)
+ public function __construct(IDBConnection $db, IURLGenerator $urlGenerator)
{
parent::__construct($db, tableName: 'ocat_publications');
}
@@ -212,6 +214,9 @@ public function createFromArray(array $object): Publication
$publication->setUuid(Uuid::v4());
}
+ // Set the uri
+ $publication->setUri($this->urlGenerator->getAbsoluteURL($this->urlGenerator->linkToRoute('opencatalogi.publications.show', ['id' => $publication->getUuid()])));
+
return $this->insert(entity: $publication);
}
@@ -233,8 +238,12 @@ public function updateFromArray(int $id, array $object, bool $updateVersion = tr
return $this->createFromArray($object);
}
+ // Hydrate the publication with the new data
$publication->hydrate(object: $object);
+ // Set the uri
+ $publication->setUri($this->urlGenerator->getAbsoluteURL($this->urlGenerator->linkToRoute('opencatalogi.publications.show', ['id' => $publication->getUuid()])));
+
if ($updateVersion === true) {
// Update the version
$version = explode('.', $publication->getVersion());
diff --git a/lib/Db/PublicationType.php b/lib/Db/PublicationType.php
index cfc9885d..dd729b82 100644
--- a/lib/Db/PublicationType.php
+++ b/lib/Db/PublicationType.php
@@ -10,6 +10,7 @@
class PublicationType extends Entity implements JsonSerializable
{
protected ?string $uuid = null;
+ protected ?string $uri = null;
protected ?string $version = '0.0.1';
protected ?string $title = null;
protected ?string $description = null;
@@ -23,6 +24,7 @@ class PublicationType extends Entity implements JsonSerializable
public function __construct() {
$this->addType(fieldName: 'uuid', type: 'string');
+ $this->addType(fieldName: 'uri', type: 'string');
$this->addType(fieldName: 'version', type: 'string');
$this->addType(fieldName: 'title', type: 'string');
$this->addType(fieldName: 'description', type: 'string');
@@ -87,6 +89,7 @@ public function jsonSerialize(): array
$array = [
'id' => $this->id,
+ 'uri' => $this->uri,
'uuid' => $this->uuid,
'version' => $this->version,
'title' => $this->title,
diff --git a/lib/Db/PublicationTypeMapper.php b/lib/Db/PublicationTypeMapper.php
index 1474130d..1e1e5fc4 100644
--- a/lib/Db/PublicationTypeMapper.php
+++ b/lib/Db/PublicationTypeMapper.php
@@ -9,6 +9,7 @@
use OCP\AppFramework\Db\QBMapper;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\IDBConnection;
+use OCP\IURLGenerator;
use Symfony\Component\Uid\Uuid;
/**
@@ -23,8 +24,9 @@ class PublicationTypeMapper extends QBMapper
* Constructor for PublicationTypeMapper
*
* @param IDBConnection $db The database connection
+ * @param IURLGenerator $urlGenerator The URL generator
*/
- public function __construct(IDBConnection $db)
+ public function __construct(IDBConnection $db, IURLGenerator $urlGenerator)
{
parent::__construct($db, tableName: 'ocat_publication_types');
}
@@ -141,6 +143,10 @@ public function createFromArray(array $object): PublicationType
if ($publicationType->getUuid() === null) {
$publicationType->setUuid(Uuid::v4());
}
+
+ // Set the uri
+ $publicationType->setUri($this->urlGenerator->getAbsoluteURL($this->urlGenerator->linkToRoute('opencatalogi.publication_types.show', ['id' => $publicationType->getUuid()])));
+
return $this->insert(entity: $publicationType);
}
@@ -164,8 +170,12 @@ public function updateFromArray(int $id, array $object, bool $updateVersion = tr
return $this->createFromArray($object);
}
+ // Hydrate the publication type with the new data
$publicationType->hydrate($object);
+ // Set the uri
+ $publicationType->setUri($this->urlGenerator->getAbsoluteURL($this->urlGenerator->linkToRoute('opencatalogi.publication_types.show', ['id' => $publicationType->getUuid()])));
+
if ($updateVersion === true) {
// Update the version
$version = explode('.', $publicationType->getVersion());
diff --git a/lib/Db/Theme.php b/lib/Db/Theme.php
index 881fdf95..8451c217 100644
--- a/lib/Db/Theme.php
+++ b/lib/Db/Theme.php
@@ -9,6 +9,7 @@
class Theme extends Entity implements JsonSerializable
{
protected ?string $uuid = null;
+ protected ?string $uri = null;
protected ?string $version = '0.0.1';
protected ?string $title = null;
protected ?string $summary = null;
@@ -19,6 +20,7 @@ class Theme extends Entity implements JsonSerializable
public function __construct() {
$this->addType(fieldName: 'uuid', type: 'string');
+ $this->addType(fieldName: 'uri', type: 'string');
$this->addType(fieldName: 'version', type: 'string');
$this->addType(fieldName: 'title', type: 'string');
$this->addType(fieldName: 'summary', type: 'string');
@@ -70,6 +72,7 @@ public function jsonSerialize(): array
{
$array = [
'id' => $this->id,
+ 'uri' => $this->uri,
'uuid' => $this->uuid,
'version' => $this->version,
'title' => $this->title,
diff --git a/lib/Db/ThemeMapper.php b/lib/Db/ThemeMapper.php
index 8b0b239b..d1aa975a 100644
--- a/lib/Db/ThemeMapper.php
+++ b/lib/Db/ThemeMapper.php
@@ -9,6 +9,7 @@
use OCP\AppFramework\Db\QBMapper;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\IDBConnection;
+use OCP\IURLGenerator;
use Symfony\Component\Uid\Uuid;
/**
@@ -25,8 +26,9 @@ class ThemeMapper extends QBMapper
* Constructor for ThemeMapper
*
* @param IDBConnection $db The database connection
+ * @param IURLGenerator $urlGenerator The URL generator
*/
- public function __construct(IDBConnection $db)
+ public function __construct(IDBConnection $db, IURLGenerator $urlGenerator)
{
parent::__construct($db, tableName: 'ocat_themes');
}
@@ -127,6 +129,10 @@ public function createFromArray(array $object): Theme
if ($theme->getUuid() === null) {
$theme->setUuid(Uuid::v4());
}
+
+ // Set the uri
+ $theme->setUri($this->urlGenerator->getAbsoluteURL($this->urlGenerator->linkToRoute('opencatalogi.themes.show', ['id' => $theme->getUuid()])));
+
return $this->insert(entity: $theme);
}
@@ -150,7 +156,12 @@ public function updateFromArray(int $id, array $object, bool $updateVersion = tr
return $this->createFromArray($object);
}
+ // Hydrate the theme with the new data
$theme->hydrate($object);
+
+ // Set the uri
+ $theme->setUri($this->urlGenerator->getAbsoluteURL($this->urlGenerator->linkToRoute('opencatalogi.themes.show', ['id' => $theme->getUuid()])));
+
if ($updateVersion === true) {
// Update the version
diff --git a/lib/Migration/Version6Date20241208222530.php b/lib/Migration/Version6Date20241208222530.php
new file mode 100644
index 00000000..33ecb6c5
--- /dev/null
+++ b/lib/Migration/Version6Date20241208222530.php
@@ -0,0 +1,139 @@
+getTable('ocat_attachments');
+ if ($table->hasColumn('uri') === false) {
+ $table->addColumn(
+ name: 'uri',
+ typeName: Types::STRING,
+ options: [
+ 'notnull' => true,
+ 'length' => 255
+ ]
+ )->setDefault('');
+ }
+
+ // Update catalogi table
+ $table = $schema->getTable('ocat_catalogi');
+ if ($table->hasColumn('uri') === false) {
+ $table->addColumn(
+ name: 'uri',
+ typeName: Types::STRING,
+ options: [
+ 'notnull' => true,
+ 'length' => 255
+ ]
+ )->setDefault('');
+ }
+
+ // Update organizations table
+ $table = $schema->getTable('ocat_organizations');
+ if ($table->hasColumn('uri') === false) {
+ $table->addColumn(
+ name: 'uri',
+ typeName: Types::STRING,
+ options: [
+ 'notnull' => true,
+ 'length' => 255
+ ]
+ )->setDefault('');
+ }
+
+ // Update publications table
+ $table = $schema->getTable('ocat_publications');
+ if ($table->hasColumn('uri') === false) {
+ $table->addColumn(
+ name: 'uri',
+ typeName: Types::STRING,
+ options: [
+ 'notnull' => true,
+ 'length' => 255
+ ]
+ )->setDefault('');
+ }
+
+ // Update publication types table
+ $table = $schema->getTable('ocat_publication_types');
+ if ($table->hasColumn('uri') === false) {
+ $table->addColumn(
+ name: 'uri',
+ typeName: Types::STRING,
+ options: [
+ 'notnull' => true,
+ 'length' => 255
+ ]
+ )->setDefault('');
+ if (!$table->hasIndex('ocat_publication_uuid_index')) {
+ $table->addIndex(['uuid'], 'ocat_publication_uuid_index');
+ }
+ }
+
+ // Update themes table
+ $table = $schema->getTable('ocat_themes');
+ if ($table->hasColumn('uri') === false) {
+ $table->addColumn(
+ name: 'uri',
+ typeName: Types::STRING,
+ options: [
+ 'notnull' => true,
+ 'length' => 255
+ ]
+ )->setDefault('');
+ if (!$table->hasIndex('ocat_themes_uuid_index')) {
+ $table->addIndex(['uuid'], 'ocat_themes_uuid_index');
+ }
+ }
+
+ 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/BroadcastService.php b/lib/Service/BroadcastService.php
index f39b6f29..95b3ac11 100644
--- a/lib/Service/BroadcastService.php
+++ b/lib/Service/BroadcastService.php
@@ -15,7 +15,10 @@
use OCA\OpenCatalogi\Service\ObjectService;
/**
- * Service class for handling directory-related operations
+ * Service for broadcasting this OpenCatalogi directory to other instances.
+ *
+ * Provides functionality to notify external instances about this directory
+ * through HTTP POST requests, either to a specific URL or to all known directories.
*/
class BroadcastService
{
@@ -73,10 +76,10 @@ public function broadcast(?string $url = null): void {
'directory' => $directoryUrl
]
]);
-
+
// Log successful broadcast
\OC::$server->getLogger()->info('Successfully broadcasted to ' . $hook);
-
+
} catch (\Exception $e) {
// Throw a warning since broadcasting failure shouldn't break the application flow
// but we still want to notify about the issue
diff --git a/lib/Service/DirectoryService.php b/lib/Service/DirectoryService.php
index 09286299..05521f3f 100644
--- a/lib/Service/DirectoryService.php
+++ b/lib/Service/DirectoryService.php
@@ -25,7 +25,11 @@
use Symfony\Component\Uid\Uuid;
/**
- * Service class for handling directory-related operations
+ * Service for managing and synchronizing directories and listings.
+ *
+ * This service facilitates operations related to directories, catalogs, and listings.
+ * It supports synchronization with external directories, validation and updates
+ * of listings, and integration with publication types.
*/
class DirectoryService
{
@@ -93,7 +97,7 @@ private function getDirectoryFromListing(Listing|array $listing): array
// $listing['id'] = $listing['uuid'];
// Remove unneeded fields
- unset($listing['status'], $listing['lastSync'], $listing['default'], $listing['available'], $listing['catalog'], $listing['statusCode'],
+ unset($listing['status'], $listing['lastSync'], $listing['default'], $listing['available'], $listing['statusCode'],
// $listing['uuid'], //@todo this breaks stuff when trying to find and update a listing
$listing['hash']);
@@ -159,6 +163,7 @@ private function getDirectoryFromCatalog(Catalog|array $catalog): array
// Add the search and directory urls
$catalog['search'] = $this->urlGenerator->getAbsoluteURL($this->urlGenerator->linkToRoute("opencatalogi.search.index"));
$catalog['directory'] = $this->urlGenerator->getAbsoluteURL($this->urlGenerator->linkToRoute("opencatalogi.directory.index"));
+ $catalog['catalog'] = $catalog['id'];
// Process publication types
if (isset($catalog['publicationTypes']) && is_array($catalog['publicationTypes'])) {
@@ -262,7 +267,7 @@ public function doCronSync(): array {
*/
public function validateExternalListing(array $listing): bool
{
- if (empty($listing['id']) || !Uuid::isValid($listing['id'])) {
+ if (empty($listing['catalog']) === true || Uuid::isValid($listing['catalog']) === false) {
return false;
}
@@ -368,14 +373,9 @@ public function syncExternalDirectory(string $url): array
// Get all current listings for this directory
$currentListings = $this->objectService->getObjects(
- objectType: 'listing',
- filters: [
- 'directory'=>$checkUrls,
- ]
+ objectType: 'listing'
);
-
-
// Remove any listings without a catalog ID from the database
foreach ($currentListings as $listing) {
if (empty($listing['catalog'])) {
@@ -395,12 +395,15 @@ public function syncExternalDirectory(string $url): array
'catalog' // Index by catalog ID
);
+ $oldListingDirectories = array_unique(array: array_column(array: $currentListings, column_key: 'directory'));
+
// Initialize arrays to store results
$addedListings = [];
$updatedListings = [];
$invalidListings = [];
$foundDirectories = [];
$removedListings = [];
+ $discoveredDirectories = [];
// Process each new listing
foreach ($newListings as $listing) {
@@ -410,13 +413,22 @@ public function syncExternalDirectory(string $url): array
continue;
}
+ if (in_array(needle: $listing['directory'], haystack: $checkUrls) === false
+ && in_array(needle: $listing['directory'], haystack: $oldListingDirectories) === false
+ ) {
+ $discoveredDirectories[] = $listing['directory'];
+
+ continue;
+ } else if (in_array(needle: $listing['directory'], haystack: $checkUrls) === false) {
+ continue;
+ }
+
// Check if we already have this listing by looking up its catalog ID in the oldListings array
- $oldListing = $oldListings[$listing['id']] ?? null;
+ $oldListing = $oldListings[$listing['catalog']] ?? null;
// If no existing listing found, prepare the new listing data
if ($oldListing === null) {
$listing['hash'] = hash('sha256', json_encode($listing));
- $listing['catalog'] = $listing['id'];
unset($listing['id']);
} else {
// Update existing listing
@@ -442,10 +454,14 @@ public function syncExternalDirectory(string $url): array
}
// Lets inform our new friends that we exist
- foreach($foundDirectories as $foundDirectory){
+ foreach ($foundDirectories as $foundDirectory){
$this->broadcastService->broadcast($foundDirectory);
}
+ foreach ($discoveredDirectories as $discoveredDirectory) {
+ $this->syncExternalDirectory($discoveredDirectory);
+ }
+
// Return the results
return [
'invalidListings' => $invalidListings,
diff --git a/lib/Service/DownloadService.php b/lib/Service/DownloadService.php
index 7d582b9a..6376e3b7 100644
--- a/lib/Service/DownloadService.php
+++ b/lib/Service/DownloadService.php
@@ -17,7 +17,11 @@
use Exception;
/**
- * Service class for handling download-related operations
+ * Service for managing download-related operations.
+ *
+ * Provides functionality to create and manage publication files and archives, including
+ * generating PDFs and ZIP files containing metadata and attachments, and storing files
+ * in NextCloud.
*/
class DownloadService
{
diff --git a/lib/Service/ElasticSearchClientAdapter.php b/lib/Service/ElasticSearchClientAdapter.php
index 83efcb6c..1ef01041 100644
--- a/lib/Service/ElasticSearchClientAdapter.php
+++ b/lib/Service/ElasticSearchClientAdapter.php
@@ -5,7 +5,10 @@
use Elastic\Elasticsearch\Client;
/**
- * Adapter class for Elasticsearch client operations
+ * Adapter for Elasticsearch client operations.
+ *
+ * Provides a wrapper around the Elasticsearch client to facilitate search, indexing,
+ * retrieval, updating, and deletion of documents.
*/
class ElasticSearchClientAdapter
{
@@ -83,4 +86,4 @@ public function delete(array $params)
// Delete the document and return the response
return $this->client->delete($params);
}
-}
\ No newline at end of file
+}
diff --git a/lib/Service/ElasticSearchService.php b/lib/Service/ElasticSearchService.php
index 73afa1fe..d721e670 100644
--- a/lib/Service/ElasticSearchService.php
+++ b/lib/Service/ElasticSearchService.php
@@ -8,6 +8,13 @@
use Elastic\Elasticsearch\ClientBuilder;
use Symfony\Component\Uid\Uuid;
+/**
+ * Service for managing interactions with Elasticsearch.
+ *
+ * Provides functionality for indexing, updating, deleting, and searching objects in Elasticsearch,
+ * as well as processing and formatting query results and aggregations.
+ */
+
class ElasticSearchService
{
diff --git a/lib/Service/FileService.php b/lib/Service/FileService.php
index 4d2fe177..70ec13e2 100644
--- a/lib/Service/FileService.php
+++ b/lib/Service/FileService.php
@@ -29,8 +29,12 @@
use ZipArchive;
/**
- * Service class for handling file operations in OpenCatalogi
+ * Service for handling file operations in OpenCatalogi.
+ *
+ * Provides functionalities for managing files and folders in NextCloud, creating and managing
+ * share links, handling uploaded files, generating PDF and ZIP files, and managing temporary files.
*/
+
class FileService
{
/**
diff --git a/lib/Service/ObjectService.php b/lib/Service/ObjectService.php
index 1ffe4a6c..d237e181 100644
--- a/lib/Service/ObjectService.php
+++ b/lib/Service/ObjectService.php
@@ -29,8 +29,12 @@
use OCA\OpenCatalogi\Db\ThemeMapper;
/**
- * Service class for handling object-related operations
+ * Service for handling object-related operations.
+ *
+ * Provides functionality for retrieving, saving, updating, and deleting objects,
+ * as well as extending entities with related data and managing object mappings.
*/
+
class ObjectService
{
/** @var string $appName The name of the app */
diff --git a/lib/Service/SearchService.php b/lib/Service/SearchService.php
index 9ecfdafd..0a0b6704 100644
--- a/lib/Service/SearchService.php
+++ b/lib/Service/SearchService.php
@@ -8,10 +8,13 @@
use Symfony\Component\Uid\Uuid;
/**
- * Class SearchService
- *
- * This service handles search operations and related functionalities.
+ * Service for managing search operations and related functionalities.
+ *
+ * Provides methods for performing search queries, merging search results and aggregations,
+ * and creating database-specific filters and sort parameters. Handles both local and
+ * distributed search queries across multiple directories.
*/
+
class SearchService
{
/** @var Client */
@@ -25,7 +28,7 @@ class SearchService
/**
* SearchService constructor.
- *
+ *
* @param ElasticSearchService $elasticService
* @param DirectoryService $directoryService
* @param IURLGenerator $urlGenerator
@@ -40,7 +43,7 @@ public function __construct(
/**
* Merge facets from existing and new aggregations.
- *
+ *
* @param array $existingAggregation
* @param array $newAggregation
* @return array Merged facets
@@ -75,7 +78,7 @@ public function mergeFacets(array $existingAggregation, array $newAggregation):
/**
* Merge existing and new aggregations.
- *
+ *
* @param array|null $existingAggregations
* @param array|null $newAggregations
* @return array Merged aggregations
@@ -98,7 +101,7 @@ private function mergeAggregations(?array $existingAggregations, ?array $newAggr
/**
* Comparison function for sorting result arrays.
- *
+ *
* @param array $a
* @param array $b
* @return int
@@ -110,7 +113,7 @@ public function sortResultArray(array $a, array $b): int
/**
* Perform a search operation.
- *
+ *
* @param array $parameters Search parameters
* @param array $elasticConfig Elasticsearch configuration
* @param array $dbConfig Database configuration
diff --git a/lib/Service/ValidationService.php b/lib/Service/ValidationService.php
index 9ce35df0..8c36e6b7 100644
--- a/lib/Service/ValidationService.php
+++ b/lib/Service/ValidationService.php
@@ -18,10 +18,13 @@
use Symfony\Component\Uid\Uuid;
/**
- * Class ValidationService
+ * Service for validating catalogs and publications.
*
- * This service handles validation of catalogs and publications.
+ * Provides methods to validate publications against the schema defined in their associated
+ * publication types, ensuring data consistency and integrity. Handles default values and
+ * reports validation errors.
*/
+
class ValidationService
{
diff --git a/lib/Templates/publication.html.twig b/lib/Templates/publication.html.twig
new file mode 100644
index 00000000..cd43ad73
--- /dev/null
+++ b/lib/Templates/publication.html.twig
@@ -0,0 +1,163 @@
+
Publicatie {{ publication.title }}
+
+
+
+{% if publication.catalogi|default %}
+ Catalogi
+
+
+ Titel: |
+ {{ publication.catalogi.title }} |
+
+ {% if publication.catalogi.summary|default %}
+
+ Samenvatting: |
+ {{ publication.catalogi.summary }} |
+
+ {% endif %}
+ {% if publication.catalogi.description|default %}
+
+ Beschrijving: |
+ {{ publication.catalogi.description }} |
+
+ {% endif %}
+ {# {% if publication.catalogi.organisation|default %}#}
+ {# #}
+ {# Organisatie: | #}
+ {# {{ publication.catalogi.organisation }} | #}
+ {#
#}
+ {# {% endif %}#}
+
+{% endif %}
+
+{% if publication.metaData|default %}
+ Publicatie Type
+
+
+ Titel: |
+ {{ publication.metaData.title }} |
+
+ {% if publication.metaData.version|default %}
+
+ Versie: |
+ {{ publication.metaData.version }} |
+
+ {% endif %}
+ {% if publication.metaData.description|default %}
+
+ Beschrijving: |
+ {{ publication.metaData.description }} |
+
+ {% endif %}
+ {# {% if publication.metaData.required|default %}#}
+ {# #}
+ {# Vereisten: | #}
+ {# {{ publication.metaData.required }} | #}
+ {#
#}
+ {# {% endif %}#}
+
+{% endif %}
+
+
+
+
+ {% if publication.reference|default %}
+
+ Referentie: |
+ {{ publication.reference }} |
+
+ {% endif %}
+ {% if publication.summary|default %}
+
+ Samenvatting: |
+ {{ publication.summary }} |
+
+ {% endif %}
+ {% if publication.description|default %}
+
+ Beschrijving: |
+ {{ publication.description }} |
+
+ {% endif %}
+ {% if publication.category|default %}
+
+ Categorie: |
+ {{ publication.category }} |
+
+ {% endif %}
+ {% if publication.portal|default %}
+
+ Portal: |
+ {{ publication.portal }} |
+
+ {% endif %}
+ {% if publication.image|default %}
+
+ Foto: |
+ {{ publication.image }} |
+
+ {% endif %}
+ {# {% if publication.themes|default %}#}
+ {# #}
+ {# Thema's: | #}
+ {# {{ publication.themes }} | #}
+ {#
#}
+ {# {% endif %}#}
+ {% if publication.featured is defined %}
+
+ Uitgelicht: |
+ {% if publication.featured == true %}Ja{% else %}Nee{% endif %} |
+
+ {% endif %}
+ {% if publication.license|default %}
+
+ Licentie: |
+ {{ publication.license }} |
+
+ {% endif %}
+ {% if publication.status|default %}
+
+ Status: |
+ {{ publication.status }} |
+
+ {% endif %}
+ {% if publication.published|default %}
+
+ Gepubliceerd: |
+ {{ publication.published | date("d-m-Y H:i") }} |
+
+ {% endif %}
+ {% if publication.modified|default %}
+
+ Gewijzigd: |
+ {{ publication.modified | date("d-m-Y H:i") }} |
+
+ {% endif %}
+
+
+{% if publication.data|default %}
+
+ Eigenschappen
+
+
+ Naam |
+ Data |
+
+ {% for key, value in publication.data %}
+
+ {{ key }} |
+ {{ value }} |
+
+ {% endfor %}
+
+{% endif %}
diff --git a/package-lock.json b/package-lock.json
index 13151b64..3842f7fa 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -9,6 +9,7 @@
"version": "1.0.0",
"license": "AGPL-3.0-or-later",
"dependencies": {
+ "@codemirror/lang-json": "^6.0.1",
"@fortawesome/fontawesome-svg-core": "^6.6.0",
"@fortawesome/free-solid-svg-icons": "^6.6.0",
"@nextcloud/axios": "^2.5.0",
@@ -17,6 +18,7 @@
"@nextcloud/l10n": "^3.1.0",
"@nextcloud/router": "^3.0.1",
"@nextcloud/vue": "^8.17.0",
+ "@uiw/codemirror-theme-vscode": "^4.23.6",
"@vueuse/core": "^11.0.1",
"apexcharts": "^3.52.0",
"axios": "^1.7.4",
@@ -32,6 +34,7 @@
"validator": "^13.12.0",
"vue": "^2.7.14",
"vue-apexcharts": "^1.6.2",
+ "vue-codemirror6": "^1.3.8",
"vue-loader": "^15.11.1 <16.0.0",
"vue-loading-overlay": "^3.4.3",
"vue-material-design-icons": "^5.3.0",
@@ -1942,6 +1945,99 @@
"url": "https://opencollective.com/node-fetch"
}
},
+ "node_modules/@codemirror/autocomplete": {
+ "version": "6.18.3",
+ "resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.18.3.tgz",
+ "integrity": "sha512-1dNIOmiM0z4BIBwxmxEfA1yoxh1MF/6KPBbh20a5vphGV0ictKlgQsbJs6D6SkR6iJpGbpwRsa6PFMNlg9T9pQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@codemirror/language": "^6.0.0",
+ "@codemirror/state": "^6.0.0",
+ "@codemirror/view": "^6.17.0",
+ "@lezer/common": "^1.0.0"
+ },
+ "peerDependencies": {
+ "@codemirror/language": "^6.0.0",
+ "@codemirror/state": "^6.0.0",
+ "@codemirror/view": "^6.0.0",
+ "@lezer/common": "^1.0.0"
+ }
+ },
+ "node_modules/@codemirror/commands": {
+ "version": "6.7.1",
+ "resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.7.1.tgz",
+ "integrity": "sha512-llTrboQYw5H4THfhN4U3qCnSZ1SOJ60ohhz+SzU0ADGtwlc533DtklQP0vSFaQuCPDn3BPpOd1GbbnUtwNjsrw==",
+ "license": "MIT",
+ "dependencies": {
+ "@codemirror/language": "^6.0.0",
+ "@codemirror/state": "^6.4.0",
+ "@codemirror/view": "^6.27.0",
+ "@lezer/common": "^1.1.0"
+ }
+ },
+ "node_modules/@codemirror/lang-json": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/@codemirror/lang-json/-/lang-json-6.0.1.tgz",
+ "integrity": "sha512-+T1flHdgpqDDlJZ2Lkil/rLiRy684WMLc74xUnjJH48GQdfJo/pudlTRreZmKwzP8/tGdKf83wlbAdOCzlJOGQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@codemirror/language": "^6.0.0",
+ "@lezer/json": "^1.0.0"
+ }
+ },
+ "node_modules/@codemirror/language": {
+ "version": "6.10.6",
+ "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.10.6.tgz",
+ "integrity": "sha512-KrsbdCnxEztLVbB5PycWXFxas4EOyk/fPAfruSOnDDppevQgid2XZ+KbJ9u+fDikP/e7MW7HPBTvTb8JlZK9vA==",
+ "license": "MIT",
+ "dependencies": {
+ "@codemirror/state": "^6.0.0",
+ "@codemirror/view": "^6.23.0",
+ "@lezer/common": "^1.1.0",
+ "@lezer/highlight": "^1.0.0",
+ "@lezer/lr": "^1.0.0",
+ "style-mod": "^4.0.0"
+ }
+ },
+ "node_modules/@codemirror/lint": {
+ "version": "6.8.4",
+ "resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-6.8.4.tgz",
+ "integrity": "sha512-u4q7PnZlJUojeRe8FJa/njJcMctISGgPQ4PnWsd9268R4ZTtU+tfFYmwkBvgcrK2+QQ8tYFVALVb5fVJykKc5A==",
+ "license": "MIT",
+ "dependencies": {
+ "@codemirror/state": "^6.0.0",
+ "@codemirror/view": "^6.35.0",
+ "crelt": "^1.0.5"
+ }
+ },
+ "node_modules/@codemirror/search": {
+ "version": "6.5.8",
+ "resolved": "https://registry.npmjs.org/@codemirror/search/-/search-6.5.8.tgz",
+ "integrity": "sha512-PoWtZvo7c1XFeZWmmyaOp2G0XVbOnm+fJzvghqGAktBW3cufwJUWvSCcNG0ppXiBEM05mZu6RhMtXPv2hpllig==",
+ "license": "MIT",
+ "dependencies": {
+ "@codemirror/state": "^6.0.0",
+ "@codemirror/view": "^6.0.0",
+ "crelt": "^1.0.5"
+ }
+ },
+ "node_modules/@codemirror/state": {
+ "version": "6.4.1",
+ "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.4.1.tgz",
+ "integrity": "sha512-QkEyUiLhsJoZkbumGZlswmAhA7CBU02Wrz7zvH4SrcifbsqwlXShVXg65f3v/ts57W3dqyamEriMhij1Z3Zz4A==",
+ "license": "MIT"
+ },
+ "node_modules/@codemirror/view": {
+ "version": "6.35.0",
+ "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.35.0.tgz",
+ "integrity": "sha512-I0tYy63q5XkaWsJ8QRv5h6ves7kvtrBWjBcnf/bzohFJQc5c14a1AQRdE8QpPF9eMp5Mq2FMm59TCj1gDfE7kw==",
+ "license": "MIT",
+ "dependencies": {
+ "@codemirror/state": "^6.4.0",
+ "style-mod": "^4.1.0",
+ "w3c-keyname": "^2.2.4"
+ }
+ },
"node_modules/@csstools/css-parser-algorithms": {
"version": "2.7.1",
"resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-2.7.1.tgz",
@@ -3295,6 +3391,41 @@
"license": "MIT",
"peer": true
},
+ "node_modules/@lezer/common": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.2.3.tgz",
+ "integrity": "sha512-w7ojc8ejBqr2REPsWxJjrMFsA/ysDCFICn8zEOR9mrqzOu2amhITYuLD8ag6XZf0CFXDrhKqw7+tW8cX66NaDA==",
+ "license": "MIT"
+ },
+ "node_modules/@lezer/highlight": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.2.1.tgz",
+ "integrity": "sha512-Z5duk4RN/3zuVO7Jq0pGLJ3qynpxUVsh7IbUbGj88+uV2ApSAn6kWg2au3iJb+0Zi7kKtqffIESgNcRXWZWmSA==",
+ "license": "MIT",
+ "dependencies": {
+ "@lezer/common": "^1.0.0"
+ }
+ },
+ "node_modules/@lezer/json": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/@lezer/json/-/json-1.0.2.tgz",
+ "integrity": "sha512-xHT2P4S5eeCYECyKNPhr4cbEL9tc8w83SPwRC373o9uEdrvGKTZoJVAGxpOsZckMlEh9W23Pc72ew918RWQOBQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@lezer/common": "^1.2.0",
+ "@lezer/highlight": "^1.0.0",
+ "@lezer/lr": "^1.0.0"
+ }
+ },
+ "node_modules/@lezer/lr": {
+ "version": "1.4.2",
+ "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.4.2.tgz",
+ "integrity": "sha512-pu0K1jCIdnQ12aWNaAVU5bzi7Bd1w54J3ECgANPmYLtQKP0HBj2cE/5coBD66MT10xbtIuUr7tg0Shbsvk0mDA==",
+ "license": "MIT",
+ "dependencies": {
+ "@lezer/common": "^1.0.0"
+ }
+ },
"node_modules/@linusborg/vue-simple-portal": {
"version": "0.1.5",
"resolved": "https://registry.npmjs.org/@linusborg/vue-simple-portal/-/vue-simple-portal-0.1.5.tgz",
@@ -5186,6 +5317,37 @@
"url": "https://opencollective.com/eslint"
}
},
+ "node_modules/@uiw/codemirror-theme-vscode": {
+ "version": "4.23.6",
+ "resolved": "https://registry.npmjs.org/@uiw/codemirror-theme-vscode/-/codemirror-theme-vscode-4.23.6.tgz",
+ "integrity": "sha512-xUo1ic+Kk5hnv5gy+cXU12GZVSnDjic8s8weKq8loPHF1dSR1e6gkKVIKZRnvoOZ302taKRk7phWpBUaWIuKQg==",
+ "license": "MIT",
+ "dependencies": {
+ "@uiw/codemirror-themes": "4.23.6"
+ },
+ "funding": {
+ "url": "https://jaywcjlove.github.io/#/sponsor"
+ }
+ },
+ "node_modules/@uiw/codemirror-themes": {
+ "version": "4.23.6",
+ "resolved": "https://registry.npmjs.org/@uiw/codemirror-themes/-/codemirror-themes-4.23.6.tgz",
+ "integrity": "sha512-0dpuLQW+V6zrKvfvor/eo71V3tpr2L2Hsu8QZAdtSzksjWABxTOzH3ShaBRxCEsrz6sU9sa9o7ShwBMMDz59bQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@codemirror/language": "^6.0.0",
+ "@codemirror/state": "^6.0.0",
+ "@codemirror/view": "^6.0.0"
+ },
+ "funding": {
+ "url": "https://jaywcjlove.github.io/#/sponsor"
+ },
+ "peerDependencies": {
+ "@codemirror/language": ">=6.0.0",
+ "@codemirror/state": ">=6.0.0",
+ "@codemirror/view": ">=6.0.0"
+ }
+ },
"node_modules/@ungap/structured-clone": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz",
@@ -7634,6 +7796,21 @@
"node": ">= 0.12.0"
}
},
+ "node_modules/codemirror": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-6.0.1.tgz",
+ "integrity": "sha512-J8j+nZ+CdWmIeFIGXEFbFPtpiYacFMDR8GlHK3IyHQJMCaVRfGx9NT+Hxivv1ckLWPvNdZqndbr/7lVhrf/Svg==",
+ "license": "MIT",
+ "dependencies": {
+ "@codemirror/autocomplete": "^6.0.0",
+ "@codemirror/commands": "^6.0.0",
+ "@codemirror/language": "^6.0.0",
+ "@codemirror/lint": "^6.0.0",
+ "@codemirror/search": "^6.0.0",
+ "@codemirror/state": "^6.0.0",
+ "@codemirror/view": "^6.0.0"
+ }
+ },
"node_modules/collapse-white-space": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-2.1.0.tgz",
@@ -8169,6 +8346,12 @@
"node": ">=8"
}
},
+ "node_modules/crelt": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.6.tgz",
+ "integrity": "sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==",
+ "license": "MIT"
+ },
"node_modules/cross-spawn": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
@@ -20729,6 +20912,12 @@
"webpack": "^5.0.0"
}
},
+ "node_modules/style-mod": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.1.2.tgz",
+ "integrity": "sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw==",
+ "license": "MIT"
+ },
"node_modules/style-search": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/style-search/-/style-search-0.1.0.tgz",
@@ -22884,6 +23073,54 @@
"apexcharts": "^3.26.0"
}
},
+ "node_modules/vue-codemirror6": {
+ "version": "1.3.8",
+ "resolved": "https://registry.npmjs.org/vue-codemirror6/-/vue-codemirror6-1.3.8.tgz",
+ "integrity": "sha512-pCOzKzBBSFKi/SjUg+XGranV1vt+8S22z56BES/OeZtmyuj2M0CE0aczYS8qbTWNnKcuJcI5FRDHzVXy2v2Htg==",
+ "license": "MIT",
+ "dependencies": {
+ "@codemirror/commands": "^6.7.1",
+ "@codemirror/language": "^6.10.3",
+ "@codemirror/lint": "^6.8.3",
+ "@codemirror/state": "^6.4.1",
+ "@codemirror/view": "^6.35.0",
+ "codemirror": "^6.0.1",
+ "style-mod": "^4.1.2",
+ "vue-demi": "latest"
+ },
+ "engines": {
+ "pnpm": ">=9.14.2"
+ },
+ "peerDependencies": {
+ "vue": "^2.7.14 || ^3.4"
+ }
+ },
+ "node_modules/vue-codemirror6/node_modules/vue-demi": {
+ "version": "0.14.10",
+ "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.10.tgz",
+ "integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==",
+ "hasInstallScript": true,
+ "license": "MIT",
+ "bin": {
+ "vue-demi-fix": "bin/vue-demi-fix.js",
+ "vue-demi-switch": "bin/vue-demi-switch.js"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/antfu"
+ },
+ "peerDependencies": {
+ "@vue/composition-api": "^1.0.0-rc.1",
+ "vue": "^3.0.0-0 || ^2.6.0"
+ },
+ "peerDependenciesMeta": {
+ "@vue/composition-api": {
+ "optional": true
+ }
+ }
+ },
"node_modules/vue-color": {
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/vue-color/-/vue-color-2.8.1.tgz",
@@ -23137,6 +23374,12 @@
"vue": "^2.5.0"
}
},
+ "node_modules/w3c-keyname": {
+ "version": "2.2.8",
+ "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz",
+ "integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==",
+ "license": "MIT"
+ },
"node_modules/w3c-xmlserializer": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz",
diff --git a/package.json b/package.json
index fdccad01..f7809035 100644
--- a/package.json
+++ b/package.json
@@ -20,6 +20,7 @@
"extends @nextcloud/browserslist-config"
],
"dependencies": {
+ "@codemirror/lang-json": "^6.0.1",
"@fortawesome/fontawesome-svg-core": "^6.6.0",
"@fortawesome/free-solid-svg-icons": "^6.6.0",
"@nextcloud/axios": "^2.5.0",
@@ -28,6 +29,7 @@
"@nextcloud/l10n": "^3.1.0",
"@nextcloud/router": "^3.0.1",
"@nextcloud/vue": "^8.17.0",
+ "@uiw/codemirror-theme-vscode": "^4.23.6",
"@vueuse/core": "^11.0.1",
"apexcharts": "^3.52.0",
"axios": "^1.7.4",
@@ -43,6 +45,7 @@
"validator": "^13.12.0",
"vue": "^2.7.14",
"vue-apexcharts": "^1.6.2",
+ "vue-codemirror6": "^1.3.8",
"vue-loader": "^15.11.1 <16.0.0",
"vue-loading-overlay": "^3.4.3",
"vue-material-design-icons": "^5.3.0",
diff --git a/src/entities/page/page.ts b/src/entities/page/page.ts
index 1a510c98..a58e1d78 100644
--- a/src/entities/page/page.ts
+++ b/src/entities/page/page.ts
@@ -41,7 +41,7 @@ export class Page implements TPage {
/* istanbul ignore next */
/**
* Validates the page data against a schema
- * @returns SafeParseReturnType containing validation result
+ * @return SafeParseReturnType containing validation result
*/
public validate(): SafeParseReturnType {
// Schema validation for page data
diff --git a/src/modals/page/AddPageModal.vue b/src/modals/page/AddPageModal.vue
index 8f50fd34..3b7b2fc8 100644
--- a/src/modals/page/AddPageModal.vue
+++ b/src/modals/page/AddPageModal.vue
@@ -1,6 +1,8 @@
+
-
+
+
diff --git a/src/modals/page/EditPageModal.vue b/src/modals/page/EditPageModal.vue
index d5cc5a6b..c1d45ce3 100644
--- a/src/modals/page/EditPageModal.vue
+++ b/src/modals/page/EditPageModal.vue
@@ -1,5 +1,6 @@
-
+
* {
margin-block-end: 10px;
}
-
-.selectGrid {
- display: grid;
- grid-gap: 5px;
- grid-template-columns: 1fr 1fr;
-}
-
-.zaakDetailsContainer {
- margin-block-start: var(--OC-margin-20);
- margin-inline-start: var(--OC-margin-20);
- margin-inline-end: var(--OC-margin-20);
-}
-
.success {
color: green;
}
-
-.APM-horizontal {
- display: flex;
- gap: 4px;
- flex-direction: row;
- align-items: center;
-}
diff --git a/src/modals/publicationData/AddPublicationDataModal.vue b/src/modals/publicationData/AddPublicationDataModal.vue
index 8074c1b9..89a7dbf2 100644
--- a/src/modals/publicationData/AddPublicationDataModal.vue
+++ b/src/modals/publicationData/AddPublicationDataModal.vue
@@ -1,5 +1,7 @@
-
+
import { navigationStore, publicationStore } from '../../store/store.js'
+import { getTheme } from '../../services/getTheme.js'
+
-
+
-
+
Installeer Open Registers
-
+
Het lijkt erop dat je een open register hebt geselecteerd maar dat deze nog niet geïnstalleerd is. Dit kan problemen geven. Wil je de instelling resetten?
diff --git a/src/views/pages/PageDetail.vue b/src/views/pages/PageDetail.vue
index a6d07cab..2debbbd3 100644
--- a/src/views/pages/PageDetail.vue
+++ b/src/views/pages/PageDetail.vue
@@ -1,5 +1,7 @@
@@ -70,9 +72,14 @@ import { navigationStore, pageStore } from '../../store/store.js'
- {{ JSON.stringify(page.contents, null, 2) }}
-
+
+
+
@@ -83,6 +90,8 @@ import { navigationStore, pageStore } from '../../store/store.js'
// Components
import { NcActionButton, NcActions, NcLoadingIcon } from '@nextcloud/vue'
import { BTabs, BTab } from 'bootstrap-vue'
+import CodeMirror from 'vue-codemirror6'
+import { json } from '@codemirror/lang-json'
// Icons
import ContentCopy from 'vue-material-design-icons/ContentCopy.vue'
@@ -90,7 +99,6 @@ import Delete from 'vue-material-design-icons/Delete.vue'
import DotsHorizontal from 'vue-material-design-icons/DotsHorizontal.vue'
import HelpCircleOutline from 'vue-material-design-icons/HelpCircleOutline.vue'
import Pencil from 'vue-material-design-icons/Pencil.vue'
-import Web from 'vue-material-design-icons/Web.vue'
/**
* Component for displaying and managing page details
@@ -102,6 +110,7 @@ export default {
NcLoadingIcon,
NcActionButton,
NcActions,
+ CodeMirror,
// Bootstrap
BTabs,
BTab,
@@ -111,7 +120,6 @@ export default {
Delete,
ContentCopy,
HelpCircleOutline,
- Web,
},
props: {
pageItem: {
@@ -141,7 +149,10 @@ export default {
},
},
mounted() {
- this.page = pageStore.pageItem
+ this.page = {
+ ...pageStore.pageItem,
+ contents: JSON.stringify(JSON.parse(pageStore.pageItem.contents), null, 2),
+ }
pageStore.pageItem && this.fetchData(pageStore.pageItem.id)
},
methods: {
@@ -151,7 +162,10 @@ export default {
})
.then((response) => {
response.json().then((data) => {
- this.page = data
+ this.page = {
+ ...data,
+ contents: JSON.stringify(JSON.parse(data.contents), null, 2),
+ }
})
})
.catch((err) => {