Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions appinfo/routes.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@

declare(strict_types=1);

// Routes are declared via #[FrontpageRoute] attributes on the controllers.
return [
'routes' => [
['name' => 'AdminConfiguration#depositConfiguration', 'url' => '/admin-configuration', 'verb' => 'PUT'],
]
'routes' => [],
];
2 changes: 2 additions & 0 deletions lib/Controller/AdminConfigurationController.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

use OCA\DAVC\Service\ConfigurationService;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http\Attribute\FrontpageRoute;
use OCP\AppFramework\Http\DataResponse;
use OCP\IRequest;

Expand All @@ -33,6 +34,7 @@ public function __construct(string $appName, IRequest $request, ConfigurationSer
*
* @return DataResponse
*/
#[FrontpageRoute(verb: 'POST', url: '/admin-configuration')]
public function depositConfiguration(array $values): DataResponse {

$this->ConfigurationService->depositSystem($values);
Expand Down
101 changes: 101 additions & 0 deletions lib/Controller/AdminTemplateController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
<?php

declare(strict_types=1);

/**
* SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

namespace OCA\DAVC\Controller;

use OCA\DAVC\Service\ServicesTemplateService;
use OCA\DAVC\Utile\Validator;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\Attribute\FrontpageRoute;
use OCP\AppFramework\Http\DataResponse;
use OCP\IRequest;

class AdminTemplateController extends Controller {

public function __construct(
string $appName,
IRequest $request,
private ServicesTemplateService $templateService,
) {
parent::__construct($appName, $request);
}

/**
* list all service discovery templates
*
* @return DataResponse
*/
#[FrontpageRoute(verb: 'GET', url: '/admin/templates')]
public function list(): DataResponse {

return new DataResponse($this->templateService->list());
}

/**
* create a service discovery template
*
* @param string $domain email domain the template applies to
* @param array $connection connection settings
*
* @return DataResponse
*/
#[FrontpageRoute(verb: 'POST', url: '/admin/templates/create')]
public function create(string $domain, array $connection = []): DataResponse {

$domain = trim($domain);
if (!Validator::fqdn($domain)) {
return new DataResponse('Invalid domain provided.', Http::STATUS_BAD_REQUEST);
}
if (!$this->templateService->create($domain, $connection)) {
return new DataResponse('Failed to create service template.', Http::STATUS_INTERNAL_SERVER_ERROR);
}
return new DataResponse($this->templateService->list());
}

/**
* modify a service discovery template
*
* @param string $id service template id
* @param string $domain email domain the template applies to
* @param array $connection connection settings
*
* @return DataResponse
*/
#[FrontpageRoute(verb: 'POST', url: '/admin/templates/modify')]
public function modify(string $id, string $domain, array $connection = []): DataResponse {

$domain = trim($domain);
if ($id === '') {
return new DataResponse('Invalid template id.', Http::STATUS_BAD_REQUEST);
}
if (!Validator::fqdn($domain)) {
return new DataResponse('Invalid domain provided.', Http::STATUS_BAD_REQUEST);
}
$this->templateService->modify($id, $domain, $connection);
return new DataResponse($this->templateService->list());
}

/**
* delete a service discovery template
*
* @param string $id service template id
*
* @return DataResponse
*/
#[FrontpageRoute(verb: 'POST', url: '/admin/templates/delete')]
public function destroy(string $id): DataResponse {

if ($id === '') {
return new DataResponse('Invalid template id.', Http::STATUS_BAD_REQUEST);
}
$this->templateService->delete($id);
return new DataResponse($this->templateService->list());
}
}
4 changes: 2 additions & 2 deletions lib/Migration/Version0010Date20260501000002.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ public function changeSchema(IOutput $output, Closure $schemaClosure, array $opt
'length' => 255,
'notnull' => true
]);
// connection
$table->addColumn('connection', Types::BLOB, [
// connection (JSON document)
$table->addColumn('connection', Types::TEXT, [
'length' => 16777215, // 16MB
'notnull' => true
]);
Expand Down
61 changes: 61 additions & 0 deletions lib/Service/ServicesTemplateService.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
namespace OCA\DAVC\Service;

use OCA\DAVC\Store\Local\ServicesTemplateStore;
use OCA\DAVC\Utile\UUID;

class ServicesTemplateService {
private ServicesTemplateStore $_Store;
Expand All @@ -25,4 +26,64 @@ public function findByDomain(string $domain): array {
return $this->_Store->fetchByDomain($domain);
}

/**
* list all service templates with decoded connection settings
*
* @since Release 1.0.0
*
* @return array
*/
public function list(): array {

return array_map(static function (array $template): array {
$template['connection'] = json_decode((string)$template['connection'], true) ?: [];
return $template;
}, $this->_Store->list());
}

/**
* create a new service template
*
* @since Release 1.0.0
*
* @param string $domain service domain
* @param array $connection connection settings
*
* @return bool
*/
public function create(string $domain, array $connection): bool {

return $this->_Store->create(UUID::v4(), $domain, $connection);
}

/**
* modify an existing service template
*
* @since Release 1.0.0
*
* @param string $id service template id
* @param string $domain service domain
* @param array $connection connection settings
*
* @return bool
*/
public function modify(string $id, string $domain, array $connection): bool {

return $this->_Store->modify($id, $domain, $connection);
}

/**
* delete a service template
*
* @since Release 1.0.0
*
* @param string $id service template id
*
* @return bool
*/
public function delete(string $id): bool {

return $this->_Store->delete($id);
}

}
43 changes: 41 additions & 2 deletions lib/Store/Local/ServicesTemplateStore.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,25 @@ public function __construct(IDBConnection $store) {
$this->_Store = $store;
}

/**
* normalise blob columns to strings
*
* On PostgreSQL (and Oracle) text/blob columns can be returned as stream
* resources rather than strings, so decode them before returning rows.
*
* @param array $rows
*
* @return array
*/
private function decodeRows(array $rows): array {
foreach ($rows as &$row) {
if (isset($row['connection']) && is_resource($row['connection'])) {
$row['connection'] = stream_get_contents($row['connection']);
}
}
return $rows;
}

/**
* retrieve service templates
*
Expand All @@ -36,12 +55,32 @@ public function fetchById(string $id): array {
$cmd->executeQuery()->closeCursor();
// return result or null
if (is_array($rs) && count($rs) > 0) {
return $rs;
return $this->decodeRows($rs);
} else {
return [];
}
}

/**
* retrieve all service templates from data store
*
* @since Release 1.0.0
*
* @return array
*/
public function list(): array {
// construct data store command
$cmd = $this->_Store->getQueryBuilder();
$cmd->select('*')
->from($this->_EntityTable);
// execute command
$result = $cmd->executeQuery();
$rs = $result->fetchAll();
$result->closeCursor();
// return result
return is_array($rs) ? $this->decodeRows($rs) : [];
}

/**
* retrieve service templates for specific domain from data store
*
Expand All @@ -62,7 +101,7 @@ public function fetchByDomain(string $domain): array {
$cmd->executeQuery()->closeCursor();
// return result or null
if (is_array($rs) && count($rs) > 0) {
return $rs;
return $this->decodeRows($rs);
} else {
return [];
}
Expand Down
Loading
Loading