aboutsummaryrefslogtreecommitdiffstats
path: root/apps/testing/lib
diff options
context:
space:
mode:
Diffstat (limited to 'apps/testing/lib')
-rw-r--r--apps/testing/lib/AlternativeHomeUserBackend.php29
-rw-r--r--apps/testing/lib/AppInfo/Application.php72
-rw-r--r--apps/testing/lib/Controller/ConfigController.php35
-rw-r--r--apps/testing/lib/Controller/LockingController.php62
-rw-r--r--apps/testing/lib/Controller/RateLimitTestController.php44
-rw-r--r--apps/testing/lib/Conversion/ConversionProvider.php47
-rw-r--r--apps/testing/lib/HiddenGroupBackend.php44
-rw-r--r--apps/testing/lib/Listener/GetDeclarativeSettingsValueListener.php37
-rw-r--r--apps/testing/lib/Listener/RegisterDeclarativeSettingsListener.php71
-rw-r--r--apps/testing/lib/Listener/SetDeclarativeSettingsValueListener.php37
-rw-r--r--apps/testing/lib/Locking/FakeDBLockingProvider.php29
-rw-r--r--apps/testing/lib/Migration/Version30000Date20240102030405.php41
-rw-r--r--apps/testing/lib/Provider/FakeText2ImageProvider.php33
-rw-r--r--apps/testing/lib/Provider/FakeTextProcessingProvider.php39
-rw-r--r--apps/testing/lib/Provider/FakeTextProcessingProviderSync.php45
-rw-r--r--apps/testing/lib/Provider/FakeTranslationProvider.php29
-rw-r--r--apps/testing/lib/Settings/DeclarativeSettingsForm.php205
-rw-r--r--apps/testing/lib/TaskProcessing/FakeContextWriteProvider.php130
-rw-r--r--apps/testing/lib/TaskProcessing/FakeTextToImageProvider.php108
-rw-r--r--apps/testing/lib/TaskProcessing/FakeTextToTextProvider.php122
-rw-r--r--apps/testing/lib/TaskProcessing/FakeTextToTextSummaryProvider.php122
-rw-r--r--apps/testing/lib/TaskProcessing/FakeTranscribeProvider.php88
-rw-r--r--apps/testing/lib/TaskProcessing/FakeTranslateProvider.php154
23 files changed, 1453 insertions, 170 deletions
diff --git a/apps/testing/lib/AlternativeHomeUserBackend.php b/apps/testing/lib/AlternativeHomeUserBackend.php
index b6d39cf6b99..0524ebe110d 100644
--- a/apps/testing/lib/AlternativeHomeUserBackend.php
+++ b/apps/testing/lib/AlternativeHomeUserBackend.php
@@ -1,26 +1,15 @@
<?php
+
/**
- * @copyright Copyright (c) 2016, ownCloud GmbH.
- *
- * @author Vincent Petry <vincent@nextcloud.com>
- *
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
+ * SPDX-FileCopyrightText: 2016 ownCloud GmbH.
+ * SPDX-License-Identifier: AGPL-3.0-only
*/
namespace OCA\Testing;
+use OC\User\Database;
+use OCP\IConfig;
+use OCP\Server;
+
/**
* Alternative home user backend.
*
@@ -33,7 +22,7 @@ namespace OCA\Testing;
* ],
* ]
*/
-class AlternativeHomeUserBackend extends \OC\User\Database {
+class AlternativeHomeUserBackend extends Database {
public function __construct() {
parent::__construct();
}
@@ -48,7 +37,7 @@ class AlternativeHomeUserBackend extends \OC\User\Database {
if ($uid !== 'admin') {
$uid = md5($uid);
}
- return \OC::$server->getConfig()->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data') . '/' . $uid;
+ return Server::get(IConfig::class)->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data') . '/' . $uid;
}
return false;
diff --git a/apps/testing/lib/AppInfo/Application.php b/apps/testing/lib/AppInfo/Application.php
index 4bf4b5cb470..2add318f327 100644
--- a/apps/testing/lib/AppInfo/Application.php
+++ b/apps/testing/lib/AppInfo/Application.php
@@ -1,52 +1,78 @@
<?php
+
/**
- * @copyright Copyright (c) 2016, ownCloud GmbH
- *
- * @author Christoph Wurst <christoph@winzerhof-wurst.at>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Roeland Jago Douma <roeland@famdouma.nl>
- * @author Vincent Petry <vincent@nextcloud.com>
- *
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
+ * SPDX-FileCopyrightText: 2017-2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-FileCopyrightText: 2016 ownCloud GmbH
+ * SPDX-License-Identifier: AGPL-3.0-only
*/
namespace OCA\Testing\AppInfo;
use OCA\Testing\AlternativeHomeUserBackend;
+use OCA\Testing\Conversion\ConversionProvider;
+use OCA\Testing\HiddenGroupBackend;
+use OCA\Testing\Listener\GetDeclarativeSettingsValueListener;
+use OCA\Testing\Listener\RegisterDeclarativeSettingsListener;
+use OCA\Testing\Listener\SetDeclarativeSettingsValueListener;
+use OCA\Testing\Provider\FakeText2ImageProvider;
+use OCA\Testing\Provider\FakeTextProcessingProvider;
+use OCA\Testing\Provider\FakeTextProcessingProviderSync;
+use OCA\Testing\Provider\FakeTranslationProvider;
+use OCA\Testing\Settings\DeclarativeSettingsForm;
+use OCA\Testing\TaskProcessing\FakeContextWriteProvider;
+use OCA\Testing\TaskProcessing\FakeTextToImageProvider;
+use OCA\Testing\TaskProcessing\FakeTextToTextProvider;
+use OCA\Testing\TaskProcessing\FakeTextToTextSummaryProvider;
+use OCA\Testing\TaskProcessing\FakeTranscribeProvider;
+use OCA\Testing\TaskProcessing\FakeTranslateProvider;
use OCP\AppFramework\App;
use OCP\AppFramework\Bootstrap\IBootContext;
use OCP\AppFramework\Bootstrap\IBootstrap;
use OCP\AppFramework\Bootstrap\IRegistrationContext;
+use OCP\IGroupManager;
+use OCP\Settings\Events\DeclarativeSettingsGetValueEvent;
+use OCP\Settings\Events\DeclarativeSettingsRegisterFormEvent;
+use OCP\Settings\Events\DeclarativeSettingsSetValueEvent;
class Application extends App implements IBootstrap {
+ public const APP_ID = 'testing';
+
public function __construct(array $urlParams = []) {
- parent::__construct('testing', $urlParams);
+ parent::__construct(self::APP_ID, $urlParams);
}
public function register(IRegistrationContext $context): void {
+ $context->registerTranslationProvider(FakeTranslationProvider::class);
+ $context->registerTextProcessingProvider(FakeTextProcessingProvider::class);
+ $context->registerTextProcessingProvider(FakeTextProcessingProviderSync::class);
+ $context->registerTextToImageProvider(FakeText2ImageProvider::class);
+
+ $context->registerTaskProcessingProvider(FakeTextToTextProvider::class);
+ $context->registerTaskProcessingProvider(FakeTextToTextSummaryProvider::class);
+ $context->registerTaskProcessingProvider(FakeTextToImageProvider::class);
+ $context->registerTaskProcessingProvider(FakeTranslateProvider::class);
+ $context->registerTaskProcessingProvider(FakeTranscribeProvider::class);
+ $context->registerTaskProcessingProvider(FakeContextWriteProvider::class);
+
+ $context->registerFileConversionProvider(ConversionProvider::class);
+
+ $context->registerDeclarativeSettings(DeclarativeSettingsForm::class);
+ $context->registerEventListener(DeclarativeSettingsRegisterFormEvent::class, RegisterDeclarativeSettingsListener::class);
+ $context->registerEventListener(DeclarativeSettingsGetValueEvent::class, GetDeclarativeSettingsValueListener::class);
+ $context->registerEventListener(DeclarativeSettingsSetValueEvent::class, SetDeclarativeSettingsValueListener::class);
}
public function boot(IBootContext $context): void {
$server = $context->getServerContainer();
$config = $server->getConfig();
- if ($config->getAppValue('testing', 'enable_alt_user_backend', 'no') === 'yes') {
+ if ($config->getAppValue(self::APP_ID, 'enable_alt_user_backend', 'no') === 'yes') {
$userManager = $server->getUserManager();
// replace all user backends with this one
$userManager->clearBackends();
$userManager->registerBackend($context->getAppContainer()->get(AlternativeHomeUserBackend::class));
}
+
+ $groupManager = $server->get(IGroupManager::class);
+ $groupManager->addBackend($server->get(HiddenGroupBackend::class));
}
}
diff --git a/apps/testing/lib/Controller/ConfigController.php b/apps/testing/lib/Controller/ConfigController.php
index 76f1e1a1ee1..1b38666e51c 100644
--- a/apps/testing/lib/Controller/ConfigController.php
+++ b/apps/testing/lib/Controller/ConfigController.php
@@ -1,24 +1,9 @@
<?php
+
/**
- * @copyright Copyright (c) 2016, ownCloud, Inc.
- *
- * @author Joas Schilling <coding@schilljs.com>
- * @author Roeland Jago Douma <roeland@famdouma.nl>
- *
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
+ * SPDX-FileCopyrightText: 2017-2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
+ * SPDX-License-Identifier: AGPL-3.0-only
*/
namespace OCA\Testing\Controller;
@@ -29,19 +14,17 @@ use OCP\IRequest;
class ConfigController extends OCSController {
- /** @var IConfig */
- private $config;
-
/**
* @param string $appName
* @param IRequest $request
* @param IConfig $config
*/
- public function __construct($appName,
- IRequest $request,
- IConfig $config) {
+ public function __construct(
+ $appName,
+ IRequest $request,
+ private IConfig $config,
+ ) {
parent::__construct($appName, $request);
- $this->config = $config;
}
/**
diff --git a/apps/testing/lib/Controller/LockingController.php b/apps/testing/lib/Controller/LockingController.php
index c01ad218c84..edc66d012ee 100644
--- a/apps/testing/lib/Controller/LockingController.php
+++ b/apps/testing/lib/Controller/LockingController.php
@@ -1,24 +1,9 @@
<?php
+
/**
- * @copyright Copyright (c) 2016, ownCloud, Inc.
- *
- * @author Christoph Wurst <christoph@winzerhof-wurst.at>
- * @author Roeland Jago Douma <roeland@famdouma.nl>
- *
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
+ * SPDX-FileCopyrightText: 2017-2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
+ * SPDX-License-Identifier: AGPL-3.0-only
*/
namespace OCA\Testing\Controller;
@@ -39,21 +24,6 @@ use OCP\Lock\LockedException;
class LockingController extends OCSController {
- /** @var ILockingProvider */
- protected $lockingProvider;
-
- /** @var FakeDBLockingProvider */
- protected $fakeDBLockingProvider;
-
- /** @var IDBConnection */
- protected $connection;
-
- /** @var IConfig */
- protected $config;
-
- /** @var IRootFolder */
- protected $rootFolder;
-
/**
* @param string $appName
* @param IRequest $request
@@ -63,20 +33,16 @@ class LockingController extends OCSController {
* @param IConfig $config
* @param IRootFolder $rootFolder
*/
- public function __construct($appName,
- IRequest $request,
- ILockingProvider $lockingProvider,
- FakeDBLockingProvider $fakeDBLockingProvider,
- IDBConnection $connection,
- IConfig $config,
- IRootFolder $rootFolder) {
+ public function __construct(
+ $appName,
+ IRequest $request,
+ protected ILockingProvider $lockingProvider,
+ protected FakeDBLockingProvider $fakeDBLockingProvider,
+ protected IDBConnection $connection,
+ protected IConfig $config,
+ protected IRootFolder $rootFolder,
+ ) {
parent::__construct($appName, $request);
-
- $this->lockingProvider = $lockingProvider;
- $this->fakeDBLockingProvider = $fakeDBLockingProvider;
- $this->connection = $connection;
- $this->config = $config;
- $this->rootFolder = $rootFolder;
}
/**
@@ -199,7 +165,7 @@ class LockingController extends OCSController {
throw new OCSException('', Http::STATUS_LOCKED);
}
- public function releaseAll(int $type = null): DataResponse {
+ public function releaseAll(?int $type = null): DataResponse {
$lockingProvider = $this->getLockingProvider();
foreach ($this->config->getAppKeys('testing') as $lock) {
diff --git a/apps/testing/lib/Controller/RateLimitTestController.php b/apps/testing/lib/Controller/RateLimitTestController.php
index d9a8fde5c0d..d3700b69858 100644
--- a/apps/testing/lib/Controller/RateLimitTestController.php
+++ b/apps/testing/lib/Controller/RateLimitTestController.php
@@ -1,52 +1,36 @@
<?php
+
/**
- * @copyright Copyright (c) 2017 Lukas Reschke <lukas@statuscode.ch>
- *
- * @author Lukas Reschke <lukas@statuscode.ch>
- *
- * @license GNU AGPL version 3 or any later version
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
+ * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace OCA\Testing\Controller;
use OCP\AppFramework\Controller;
+use OCP\AppFramework\Http\Attribute\AnonRateLimit;
+use OCP\AppFramework\Http\Attribute\NoCSRFRequired;
+use OCP\AppFramework\Http\Attribute\PublicPage;
+use OCP\AppFramework\Http\Attribute\UserRateLimit;
use OCP\AppFramework\Http\JSONResponse;
class RateLimitTestController extends Controller {
/**
- * @PublicPage
- * @NoCSRFRequired
- *
- * @UserRateThrottle(limit=5, period=100)
- * @AnonRateThrottle(limit=1, period=100)
- *
* @return JSONResponse
*/
+ #[PublicPage]
+ #[NoCSRFRequired]
+ #[UserRateLimit(limit: 5, period: 100)]
+ #[AnonRateLimit(limit: 1, period: 100)]
public function userAndAnonProtected() {
return new JSONResponse();
}
/**
- * @PublicPage
- * @NoCSRFRequired
- *
- * @AnonRateThrottle(limit=1, period=10)
- *
* @return JSONResponse
*/
+ #[PublicPage]
+ #[NoCSRFRequired]
+ #[AnonRateLimit(limit: 1, period: 10)]
public function onlyAnonProtected() {
return new JSONResponse();
}
diff --git a/apps/testing/lib/Conversion/ConversionProvider.php b/apps/testing/lib/Conversion/ConversionProvider.php
new file mode 100644
index 00000000000..b8d93428694
--- /dev/null
+++ b/apps/testing/lib/Conversion/ConversionProvider.php
@@ -0,0 +1,47 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+namespace OCA\Testing\Conversion;
+
+use OCP\Files\Conversion\ConversionMimeProvider;
+use OCP\Files\Conversion\IConversionProvider;
+use OCP\Files\File;
+use OCP\IL10N;
+
+class ConversionProvider implements IConversionProvider {
+ public function __construct(
+ private IL10N $l10n,
+ ) {
+ }
+
+ public function getSupportedMimeTypes(): array {
+ return [
+ new ConversionMimeProvider('image/jpeg', 'image/png', 'png', $this->l10n->t('Image (.png)')),
+ new ConversionMimeProvider('image/jpeg', 'image/gif', 'gif', $this->l10n->t('Image (.gif)')),
+ ];
+ }
+
+ public function convertFile(File $file, string $targetMimeType): mixed {
+ $image = imagecreatefromstring($file->getContent());
+ imagepalettetotruecolor($image);
+
+ // Start output buffering
+ ob_start();
+
+ // Convert the image to the target format
+ if ($targetMimeType === 'image/gif') {
+ imagegif($image);
+ } else {
+ imagepng($image);
+ }
+
+ // End and return the output buffer
+ return ob_get_clean();
+ }
+}
diff --git a/apps/testing/lib/HiddenGroupBackend.php b/apps/testing/lib/HiddenGroupBackend.php
new file mode 100644
index 00000000000..96ead46c06e
--- /dev/null
+++ b/apps/testing/lib/HiddenGroupBackend.php
@@ -0,0 +1,44 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+namespace OCA\Testing;
+
+use OCP\Group\Backend\ABackend;
+use OCP\Group\Backend\IHideFromCollaborationBackend;
+
+class HiddenGroupBackend extends ABackend implements IHideFromCollaborationBackend {
+ public function __construct(
+ private string $groupName = 'hidden_group',
+ ) {
+ }
+
+ public function inGroup($uid, $gid): bool {
+ return false;
+ }
+
+ public function getUserGroups($uid): array {
+ return [];
+ }
+
+ public function getGroups($search = '', $limit = -1, $offset = 0): array {
+ return $offset === 0 ? [$this->groupName] : [];
+ }
+
+ public function groupExists($gid): bool {
+ return $gid === $this->groupName;
+ }
+
+ public function usersInGroup($gid, $search = '', $limit = -1, $offset = 0): array {
+ return [];
+ }
+
+ public function hideGroup(string $groupId): bool {
+ return true;
+ }
+}
diff --git a/apps/testing/lib/Listener/GetDeclarativeSettingsValueListener.php b/apps/testing/lib/Listener/GetDeclarativeSettingsValueListener.php
new file mode 100644
index 00000000000..0df58168007
--- /dev/null
+++ b/apps/testing/lib/Listener/GetDeclarativeSettingsValueListener.php
@@ -0,0 +1,37 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace OCA\Testing\Listener;
+
+use OCP\EventDispatcher\Event;
+use OCP\EventDispatcher\IEventListener;
+use OCP\IConfig;
+use OCP\Settings\Events\DeclarativeSettingsGetValueEvent;
+
+/**
+ * @template-implements IEventListener<DeclarativeSettingsGetValueEvent>
+ */
+class GetDeclarativeSettingsValueListener implements IEventListener {
+
+ public function __construct(
+ private IConfig $config,
+ ) {
+ }
+
+ public function handle(Event $event): void {
+ if (!$event instanceof DeclarativeSettingsGetValueEvent) {
+ return;
+ }
+
+ if ($event->getApp() !== 'testing') {
+ return;
+ }
+
+ $value = $this->config->getUserValue($event->getUser()->getUID(), $event->getApp(), $event->getFieldId());
+ $event->setValue($value);
+ }
+}
diff --git a/apps/testing/lib/Listener/RegisterDeclarativeSettingsListener.php b/apps/testing/lib/Listener/RegisterDeclarativeSettingsListener.php
new file mode 100644
index 00000000000..aab39b78d76
--- /dev/null
+++ b/apps/testing/lib/Listener/RegisterDeclarativeSettingsListener.php
@@ -0,0 +1,71 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace OCA\Testing\Listener;
+
+use OCP\EventDispatcher\Event;
+use OCP\EventDispatcher\IEventListener;
+use OCP\Settings\DeclarativeSettingsTypes;
+use OCP\Settings\Events\DeclarativeSettingsRegisterFormEvent;
+
+/**
+ * @template-implements IEventListener<DeclarativeSettingsRegisterFormEvent>
+ */
+class RegisterDeclarativeSettingsListener implements IEventListener {
+
+ public function __construct() {
+ }
+
+ public function handle(Event $event): void {
+ if (!($event instanceof DeclarativeSettingsRegisterFormEvent)) {
+ // Unrelated
+ return;
+ }
+
+ $event->registerSchema('testing', [
+ 'id' => 'test_declarative_form_event',
+ 'priority' => 20,
+ 'section_type' => DeclarativeSettingsTypes::SECTION_TYPE_ADMIN,
+ 'section_id' => 'additional',
+ 'storage_type' => DeclarativeSettingsTypes::STORAGE_TYPE_INTERNAL,
+ 'title' => 'Test declarative settings event', // NcSettingsSection name
+ 'description' => 'This form is registered via the RegisterDeclarativeSettingsFormEvent', // NcSettingsSection description
+ 'fields' => [
+ [
+ 'id' => 'event_field_1',
+ 'title' => 'Why is 42 this answer to all questions?',
+ 'description' => 'Hint: It\'s not',
+ 'type' => DeclarativeSettingsTypes::TEXT,
+ 'placeholder' => 'Enter your answer',
+ 'default' => 'Because it is',
+ ],
+ [
+ 'id' => 'feature_rating',
+ 'title' => 'How would you rate this feature?',
+ 'description' => 'Your vote is not anonymous',
+ 'type' => DeclarativeSettingsTypes::RADIO, // radio, radio-button (NcCheckboxRadioSwitch button-variant)
+ 'label' => 'Select single toggle',
+ 'default' => '3',
+ 'options' => [
+ [
+ 'name' => 'Awesome', // NcCheckboxRadioSwitch display name
+ 'value' => '1' // NcCheckboxRadioSwitch value
+ ],
+ [
+ 'name' => 'Very awesome',
+ 'value' => '2'
+ ],
+ [
+ 'name' => 'Super awesome',
+ 'value' => '3'
+ ],
+ ],
+ ],
+ ],
+ ]);
+ }
+}
diff --git a/apps/testing/lib/Listener/SetDeclarativeSettingsValueListener.php b/apps/testing/lib/Listener/SetDeclarativeSettingsValueListener.php
new file mode 100644
index 00000000000..0058e7df43e
--- /dev/null
+++ b/apps/testing/lib/Listener/SetDeclarativeSettingsValueListener.php
@@ -0,0 +1,37 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace OCA\Testing\Listener;
+
+use OCP\EventDispatcher\Event;
+use OCP\EventDispatcher\IEventListener;
+use OCP\IConfig;
+use OCP\Settings\Events\DeclarativeSettingsSetValueEvent;
+
+/**
+ * @template-implements IEventListener<DeclarativeSettingsSetValueEvent>
+ */
+class SetDeclarativeSettingsValueListener implements IEventListener {
+
+ public function __construct(
+ private IConfig $config,
+ ) {
+ }
+
+ public function handle(Event $event): void {
+ if (!$event instanceof DeclarativeSettingsSetValueEvent) {
+ return;
+ }
+
+ if ($event->getApp() !== 'testing') {
+ return;
+ }
+
+ error_log('Testing app wants to store ' . $event->getValue() . ' for field ' . $event->getFieldId() . ' for user ' . $event->getUser()->getUID());
+ $this->config->setUserValue($event->getUser()->getUID(), $event->getApp(), $event->getFieldId(), $event->getValue());
+ }
+}
diff --git a/apps/testing/lib/Locking/FakeDBLockingProvider.php b/apps/testing/lib/Locking/FakeDBLockingProvider.php
index 2556ba29a64..f77bacc7a63 100644
--- a/apps/testing/lib/Locking/FakeDBLockingProvider.php
+++ b/apps/testing/lib/Locking/FakeDBLockingProvider.php
@@ -1,32 +1,15 @@
<?php
+
/**
- * @copyright Copyright (c) 2016, ownCloud, Inc.
- *
- * @author Christoph Wurst <christoph@winzerhof-wurst.at>
- * @author Joas Schilling <coding@schilljs.com>
- * @author Roeland Jago Douma <roeland@famdouma.nl>
- *
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
+ * SPDX-FileCopyrightText: 2017-2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
+ * SPDX-License-Identifier: AGPL-3.0-only
*/
namespace OCA\Testing\Locking;
+use OC\Lock\DBLockingProvider;
use OCP\AppFramework\Utility\ITimeFactory;
use OCP\IDBConnection;
-use Psr\Log\LoggerInterface;
-use OC\Lock\DBLockingProvider;
class FakeDBLockingProvider extends DBLockingProvider {
// Lock for 10 hours just to be sure
@@ -39,7 +22,7 @@ class FakeDBLockingProvider extends DBLockingProvider {
public function __construct(
IDBConnection $connection,
- ITimeFactory $timeFactory
+ ITimeFactory $timeFactory,
) {
parent::__construct($connection, $timeFactory);
$this->db = $connection;
diff --git a/apps/testing/lib/Migration/Version30000Date20240102030405.php b/apps/testing/lib/Migration/Version30000Date20240102030405.php
new file mode 100644
index 00000000000..e7b6bdcd618
--- /dev/null
+++ b/apps/testing/lib/Migration/Version30000Date20240102030405.php
@@ -0,0 +1,41 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+namespace OCA\Testing\Migration;
+
+use Closure;
+use OCP\Migration\Attributes\AddColumn;
+use OCP\Migration\Attributes\AddIndex;
+use OCP\Migration\Attributes\ColumnType;
+use OCP\Migration\Attributes\CreateTable;
+use OCP\Migration\Attributes\DropColumn;
+use OCP\Migration\Attributes\DropIndex;
+use OCP\Migration\Attributes\DropTable;
+use OCP\Migration\Attributes\IndexType;
+use OCP\Migration\Attributes\ModifyColumn;
+use OCP\Migration\IOutput;
+use OCP\Migration\SimpleMigrationStep;
+
+#[DropTable(table: 'old_table')]
+#[CreateTable(table: 'new_table', description: 'Table is used to store things, but also to get more things', notes: ['this is a notice', 'and another one, if really needed'])]
+#[AddColumn(table: 'my_table')]
+#[AddColumn(table: 'my_table', name: 'another_field')]
+#[AddColumn(table: 'other_table', name: 'last_one', type: ColumnType::DATE)]
+#[AddIndex(table: 'my_table')]
+#[AddIndex(table: 'my_table', type: IndexType::PRIMARY)]
+#[DropColumn(table: 'other_table')]
+#[DropColumn(table: 'other_table', name: 'old_column', description: 'field is not used anymore and replaced by \'last_one\'')]
+#[DropIndex(table: 'other_table')]
+#[ModifyColumn(table: 'other_table')]
+#[ModifyColumn(table: 'other_table', name: 'this_field')]
+#[ModifyColumn(table: 'other_table', name: 'this_field', type: ColumnType::BIGINT)]
+class Version30000Date20240102030405 extends SimpleMigrationStep {
+ public function changeSchema(IOutput $output, Closure $schemaClosure, array $options) {
+ return null;
+ }
+}
diff --git a/apps/testing/lib/Provider/FakeText2ImageProvider.php b/apps/testing/lib/Provider/FakeText2ImageProvider.php
new file mode 100644
index 00000000000..6b607f23347
--- /dev/null
+++ b/apps/testing/lib/Provider/FakeText2ImageProvider.php
@@ -0,0 +1,33 @@
+<?php
+
+/**
+ * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+namespace OCA\Testing\Provider;
+
+use OCP\TextToImage\IProvider;
+
+class FakeText2ImageProvider implements IProvider {
+
+ public function getName(): string {
+ return 'Fake Text2Image provider';
+ }
+
+ public function generate(string $prompt, array $resources): void {
+ foreach ($resources as $resource) {
+ $read = fopen(__DIR__ . '/../../img/logo.png', 'r');
+ stream_copy_to_stream($read, $resource);
+ fclose($read);
+ }
+ }
+
+ public function getExpectedRuntime(): int {
+ return 1;
+ }
+
+ public function getId(): string {
+ return 'testing-fake-text2image-provider';
+ }
+}
diff --git a/apps/testing/lib/Provider/FakeTextProcessingProvider.php b/apps/testing/lib/Provider/FakeTextProcessingProvider.php
new file mode 100644
index 00000000000..d3b16c55c67
--- /dev/null
+++ b/apps/testing/lib/Provider/FakeTextProcessingProvider.php
@@ -0,0 +1,39 @@
+<?php
+
+/**
+ * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+namespace OCA\Testing\Provider;
+
+use OCP\TextProcessing\FreePromptTaskType;
+use OCP\TextProcessing\IProvider;
+use OCP\TextProcessing\ITaskType;
+
+/** @template-implements IProvider<FreePromptTaskType|ITaskType> */
+class FakeTextProcessingProvider implements IProvider {
+
+ public function getName(): string {
+ return 'Fake text processing provider (asynchronous)';
+ }
+
+ public function process(string $prompt): string {
+ return $this->mb_strrev($prompt) . ' (done with FakeTextProcessingProvider)';
+ }
+
+ public function getTaskType(): string {
+ return FreePromptTaskType::class;
+ }
+
+ /**
+ * Reverse a miltibyte string.
+ *
+ * @param string $string The string to be reversed.
+ * @return string The reversed string
+ */
+ private function mb_strrev(string $string): string {
+ $chars = mb_str_split($string, 1);
+ return implode('', array_reverse($chars));
+ }
+}
diff --git a/apps/testing/lib/Provider/FakeTextProcessingProviderSync.php b/apps/testing/lib/Provider/FakeTextProcessingProviderSync.php
new file mode 100644
index 00000000000..ea822199109
--- /dev/null
+++ b/apps/testing/lib/Provider/FakeTextProcessingProviderSync.php
@@ -0,0 +1,45 @@
+<?php
+
+/**
+ * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+namespace OCA\Testing\Provider;
+
+use OCP\TextProcessing\FreePromptTaskType;
+use OCP\TextProcessing\IProviderWithExpectedRuntime;
+use OCP\TextProcessing\ITaskType;
+
+/**
+ * @template-implements IProviderWithExpectedRuntime<FreePromptTaskType|ITaskType>
+ */
+class FakeTextProcessingProviderSync implements IProviderWithExpectedRuntime {
+
+ public function getName(): string {
+ return 'Fake text processing provider (synchronous)';
+ }
+
+ public function process(string $prompt): string {
+ return $this->mb_strrev($prompt) . ' (done with FakeTextProcessingProviderSync)';
+ }
+
+ public function getTaskType(): string {
+ return FreePromptTaskType::class;
+ }
+
+ public function getExpectedRuntime(): int {
+ return 1;
+ }
+
+ /**
+ * Reverse a miltibyte string.
+ *
+ * @param string $string The string to be reversed.
+ * @return string The reversed string
+ */
+ private function mb_strrev(string $string): string {
+ $chars = mb_str_split($string, 1);
+ return implode('', array_reverse($chars));
+ }
+}
diff --git a/apps/testing/lib/Provider/FakeTranslationProvider.php b/apps/testing/lib/Provider/FakeTranslationProvider.php
new file mode 100644
index 00000000000..cc2d13db646
--- /dev/null
+++ b/apps/testing/lib/Provider/FakeTranslationProvider.php
@@ -0,0 +1,29 @@
+<?php
+
+/**
+ * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+namespace OCA\Testing\Provider;
+
+use OCP\Translation\ITranslationProvider;
+use OCP\Translation\LanguageTuple;
+
+class FakeTranslationProvider implements ITranslationProvider {
+
+ public function getName(): string {
+ return 'Fake translation';
+ }
+
+ public function getAvailableLanguages(): array {
+ return [
+ new LanguageTuple('de', 'German', 'en', 'English'),
+ new LanguageTuple('en', 'English', 'de', 'German'),
+ ];
+ }
+
+ public function translate(?string $fromLanguage, string $toLanguage, string $text): string {
+ return strrev($text);
+ }
+}
diff --git a/apps/testing/lib/Settings/DeclarativeSettingsForm.php b/apps/testing/lib/Settings/DeclarativeSettingsForm.php
new file mode 100644
index 00000000000..55e44cbcbea
--- /dev/null
+++ b/apps/testing/lib/Settings/DeclarativeSettingsForm.php
@@ -0,0 +1,205 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace OCA\Testing\Settings;
+
+use OCP\Settings\DeclarativeSettingsTypes;
+use OCP\Settings\IDeclarativeSettingsForm;
+
+class DeclarativeSettingsForm implements IDeclarativeSettingsForm {
+ public function getSchema(): array {
+ return [
+ 'id' => 'test_declarative_form',
+ 'priority' => 10,
+ 'section_type' => DeclarativeSettingsTypes::SECTION_TYPE_ADMIN, // admin, personal
+ 'section_id' => 'additional',
+ 'storage_type' => DeclarativeSettingsTypes::STORAGE_TYPE_INTERNAL, // external, internal (handled by core to store in appconfig and preferences)
+ 'title' => 'Test declarative settings class', // NcSettingsSection name
+ 'description' => 'This form is registered with a DeclarativeSettingsForm class', // NcSettingsSection description
+ 'doc_url' => '', // NcSettingsSection doc_url for documentation or help page, empty string if not needed
+ 'fields' => [
+ [
+ 'id' => 'test_ex_app_field_7', // configkey
+ 'title' => 'Multi-selection', // name or label
+ 'description' => 'Select some option setting', // hint
+ 'type' => DeclarativeSettingsTypes::MULTI_SELECT, // select, radio, multi-select
+ 'options' => ['foo', 'bar', 'baz'], // simple options for select, radio, multi-select
+ 'placeholder' => 'Select some multiple options', // input placeholder
+ 'default' => ['foo', 'bar'],
+ ],
+ [
+ 'id' => 'some_real_setting',
+ 'title' => 'Choose init status check background job interval',
+ 'description' => 'How often AppAPI should check for initialization status',
+ 'type' => DeclarativeSettingsTypes::RADIO, // radio (NcCheckboxRadioSwitch type radio)
+ 'placeholder' => 'Choose init status check background job interval',
+ 'default' => '40m',
+ 'options' => [
+ [
+ 'name' => 'Each 40 minutes', // NcCheckboxRadioSwitch display name
+ 'value' => '40m' // NcCheckboxRadioSwitch value
+ ],
+ [
+ 'name' => 'Each 60 minutes',
+ 'value' => '60m'
+ ],
+ [
+ 'name' => 'Each 120 minutes',
+ 'value' => '120m'
+ ],
+ [
+ 'name' => 'Each day',
+ 'value' => 60 * 24 . 'm'
+ ],
+ ],
+ ],
+ [
+ 'id' => 'test_ex_app_field_1', // configkey
+ 'title' => 'Default text field', // label
+ 'description' => 'Set some simple text setting', // hint
+ 'type' => DeclarativeSettingsTypes::TEXT, // text, password, email, tel, url, number
+ 'placeholder' => 'Enter text setting', // placeholder
+ 'default' => 'foo',
+ ],
+ [
+ 'id' => 'test_ex_app_field_1_1',
+ 'title' => 'Email field',
+ 'description' => 'Set email config',
+ 'type' => DeclarativeSettingsTypes::EMAIL,
+ 'placeholder' => 'Enter email',
+ 'default' => '',
+ ],
+ [
+ 'id' => 'test_ex_app_field_1_2',
+ 'title' => 'Tel field',
+ 'description' => 'Set tel config',
+ 'type' => DeclarativeSettingsTypes::TEL,
+ 'placeholder' => 'Enter your tel',
+ 'default' => '',
+ ],
+ [
+ 'id' => 'test_ex_app_field_1_3',
+ 'title' => 'Url (website) field',
+ 'description' => 'Set url config',
+ 'type' => 'url',
+ 'placeholder' => 'Enter url',
+ 'default' => '',
+ ],
+ [
+ 'id' => 'test_ex_app_field_1_4',
+ 'title' => 'Number field',
+ 'description' => 'Set number config',
+ 'type' => DeclarativeSettingsTypes::NUMBER,
+ 'placeholder' => 'Enter number value',
+ 'default' => 0,
+ ],
+ [
+ 'id' => 'test_ex_app_field_2',
+ 'title' => 'Password',
+ 'description' => 'Set some secure value setting',
+ 'type' => 'password',
+ 'placeholder' => 'Set secure value',
+ 'default' => '',
+ ],
+ [
+ 'id' => 'test_ex_app_field_3',
+ 'title' => 'Selection',
+ 'description' => 'Select some option setting',
+ 'type' => DeclarativeSettingsTypes::SELECT, // select, radio, multi-select
+ 'options' => ['foo', 'bar', 'baz'],
+ 'placeholder' => 'Select some option setting',
+ 'default' => 'foo',
+ ],
+ [
+ 'id' => 'test_ex_app_field_4',
+ 'title' => 'Toggle something',
+ 'description' => 'Select checkbox option setting',
+ 'type' => DeclarativeSettingsTypes::CHECKBOX, // checkbox, multiple-checkbox
+ 'label' => 'Verify something if enabled',
+ 'default' => false,
+ ],
+ [
+ 'id' => 'test_ex_app_field_5',
+ 'title' => 'Multiple checkbox toggles, describing one setting, checked options are saved as an JSON object {foo: true, bar: false}',
+ 'description' => 'Select checkbox option setting',
+ 'type' => DeclarativeSettingsTypes::MULTI_CHECKBOX, // checkbox, multi-checkbox
+ 'default' => ['foo' => true, 'bar' => true, 'baz' => true],
+ 'options' => [
+ [
+ 'name' => 'Foo',
+ 'value' => 'foo', // multiple-checkbox configkey
+ ],
+ [
+ 'name' => 'Bar',
+ 'value' => 'bar',
+ ],
+ [
+ 'name' => 'Baz',
+ 'value' => 'baz',
+ ],
+ [
+ 'name' => 'Qux',
+ 'value' => 'qux',
+ ],
+ ],
+ ],
+ [
+ 'id' => 'test_ex_app_field_6',
+ 'title' => 'Radio toggles, describing one setting like single select',
+ 'description' => 'Select radio option setting',
+ 'type' => DeclarativeSettingsTypes::RADIO, // radio (NcCheckboxRadioSwitch type radio)
+ 'label' => 'Select single toggle',
+ 'default' => 'foo',
+ 'options' => [
+ [
+ 'name' => 'First radio', // NcCheckboxRadioSwitch display name
+ 'value' => 'foo' // NcCheckboxRadioSwitch value
+ ],
+ [
+ 'name' => 'Second radio',
+ 'value' => 'bar'
+ ],
+ [
+ 'name' => 'Third radio',
+ 'value' => 'baz'
+ ],
+ ],
+ ],
+ [
+ 'id' => 'test_sensitive_field',
+ 'title' => 'Sensitive text field',
+ 'description' => 'Set some secure value setting that is stored encrypted',
+ 'type' => DeclarativeSettingsTypes::TEXT,
+ 'label' => 'Sensitive field',
+ 'placeholder' => 'Set secure value',
+ 'default' => '',
+ 'sensitive' => true, // only for TEXT, PASSWORD types
+ ],
+ [
+ 'id' => 'test_sensitive_field_2',
+ 'title' => 'Sensitive password field',
+ 'description' => 'Set some password setting that is stored encrypted',
+ 'type' => DeclarativeSettingsTypes::PASSWORD,
+ 'label' => 'Sensitive field',
+ 'placeholder' => 'Set secure value',
+ 'default' => '',
+ 'sensitive' => true, // only for TEXT, PASSWORD types
+ ],
+ [
+ 'id' => 'test_non_sensitive_field',
+ 'title' => 'Password field',
+ 'description' => 'Set some password setting',
+ 'type' => DeclarativeSettingsTypes::PASSWORD,
+ 'label' => 'Password field',
+ 'placeholder' => 'Set secure value',
+ 'default' => '',
+ 'sensitive' => false,
+ ],
+ ],
+ ];
+ }
+}
diff --git a/apps/testing/lib/TaskProcessing/FakeContextWriteProvider.php b/apps/testing/lib/TaskProcessing/FakeContextWriteProvider.php
new file mode 100644
index 00000000000..9a5574f5147
--- /dev/null
+++ b/apps/testing/lib/TaskProcessing/FakeContextWriteProvider.php
@@ -0,0 +1,130 @@
+<?php
+
+/**
+ * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+declare(strict_types=1);
+
+namespace OCA\Testing\TaskProcessing;
+
+use OCA\Testing\AppInfo\Application;
+use OCP\AppFramework\Services\IAppConfig;
+use OCP\TaskProcessing\EShapeType;
+use OCP\TaskProcessing\Exception\ProcessingException;
+use OCP\TaskProcessing\ISynchronousProvider;
+use OCP\TaskProcessing\ShapeDescriptor;
+use OCP\TaskProcessing\ShapeEnumValue;
+use OCP\TaskProcessing\TaskTypes\ContextWrite;
+use RuntimeException;
+
+class FakeContextWriteProvider implements ISynchronousProvider {
+
+ public function __construct(
+ protected IAppConfig $appConfig,
+ ) {
+ }
+
+ public function getId(): string {
+ return Application::APP_ID . '-contextwrite';
+ }
+
+ public function getName(): string {
+ return 'Fake context write task processing provider';
+ }
+
+ public function getTaskTypeId(): string {
+ return ContextWrite::ID;
+ }
+
+ public function getExpectedRuntime(): int {
+ return 1;
+ }
+
+ public function getInputShapeEnumValues(): array {
+ return [];
+ }
+
+ public function getInputShapeDefaults(): array {
+ return [];
+ }
+
+ public function getOptionalInputShape(): array {
+ return [
+ 'max_tokens' => new ShapeDescriptor(
+ 'Maximum output words',
+ 'The maximum number of words/tokens that can be generated in the completion.',
+ EShapeType::Number
+ ),
+ 'model' => new ShapeDescriptor(
+ 'Model',
+ 'The model used to generate the completion',
+ EShapeType::Enum
+ ),
+ ];
+ }
+
+ public function getOptionalInputShapeEnumValues(): array {
+ return [
+ 'model' => [
+ new ShapeEnumValue('Model 1', 'model_1'),
+ new ShapeEnumValue('Model 2', 'model_2'),
+ new ShapeEnumValue('Model 3', 'model_3'),
+ ],
+ ];
+ }
+
+ public function getOptionalInputShapeDefaults(): array {
+ return [
+ 'max_tokens' => 4321,
+ 'model' => 'model_2',
+ ];
+ }
+
+ public function getOutputShapeEnumValues(): array {
+ return [];
+ }
+
+ public function getOptionalOutputShape(): array {
+ return [];
+ }
+
+ public function getOptionalOutputShapeEnumValues(): array {
+ return [];
+ }
+
+ public function process(?string $userId, array $input, callable $reportProgress): array {
+ if ($this->appConfig->getAppValueBool('fail-' . $this->getId())) {
+ throw new ProcessingException('Failing as set by AppConfig');
+ }
+
+ if (
+ !isset($input['style_input']) || !is_string($input['style_input'])
+ || !isset($input['source_input']) || !is_string($input['source_input'])
+ ) {
+ throw new RuntimeException('Invalid inputs');
+ }
+ $writingStyle = $input['style_input'];
+ $sourceMaterial = $input['source_input'];
+
+ if (isset($input['model']) && is_string($input['model'])) {
+ $model = $input['model'];
+ } else {
+ $model = 'unknown model';
+ }
+
+ $maxTokens = null;
+ if (isset($input['max_tokens']) && is_int($input['max_tokens'])) {
+ $maxTokens = $input['max_tokens'];
+ }
+
+ $fakeResult = 'This is a fake result: '
+ . "\n\n- Style input: " . $writingStyle
+ . "\n- Source input: " . $sourceMaterial
+ . "\n- Model: " . $model
+ . "\n- Maximum number of words: " . $maxTokens;
+
+ return ['output' => $fakeResult];
+ }
+}
diff --git a/apps/testing/lib/TaskProcessing/FakeTextToImageProvider.php b/apps/testing/lib/TaskProcessing/FakeTextToImageProvider.php
new file mode 100644
index 00000000000..455d6c0b518
--- /dev/null
+++ b/apps/testing/lib/TaskProcessing/FakeTextToImageProvider.php
@@ -0,0 +1,108 @@
+<?php
+
+/**
+ * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+declare(strict_types=1);
+
+namespace OCA\Testing\TaskProcessing;
+
+use OCA\Testing\AppInfo\Application;
+use OCP\AppFramework\Services\IAppConfig;
+use OCP\TaskProcessing\EShapeType;
+use OCP\TaskProcessing\Exception\ProcessingException;
+use OCP\TaskProcessing\ISynchronousProvider;
+use OCP\TaskProcessing\ShapeDescriptor;
+use OCP\TaskProcessing\TaskTypes\TextToImage;
+use RuntimeException;
+
+class FakeTextToImageProvider implements ISynchronousProvider {
+
+ public function __construct(
+ protected IAppConfig $appConfig,
+ ) {
+ }
+
+ public function getId(): string {
+ return Application::APP_ID . '-text2image';
+ }
+
+ public function getName(): string {
+ return 'Fake text2image task processing provider';
+ }
+
+ public function getTaskTypeId(): string {
+ return TextToImage::ID;
+ }
+
+ public function getExpectedRuntime(): int {
+ return 1;
+ }
+
+ public function getInputShapeEnumValues(): array {
+ return [];
+ }
+
+ public function getInputShapeDefaults(): array {
+ return [
+ 'numberOfImages' => 1,
+ ];
+ }
+
+ public function getOptionalInputShape(): array {
+ return [
+ 'size' => new ShapeDescriptor(
+ 'Size',
+ 'Optional. The size of the generated images. Must be in 256x256 format.',
+ EShapeType::Text
+ ),
+ ];
+ }
+
+ public function getOptionalInputShapeEnumValues(): array {
+ return [];
+ }
+
+ public function getOptionalInputShapeDefaults(): array {
+ return [];
+ }
+
+ public function getOutputShapeEnumValues(): array {
+ return [];
+ }
+
+ public function getOptionalOutputShape(): array {
+ return [];
+ }
+
+ public function getOptionalOutputShapeEnumValues(): array {
+ return [];
+ }
+
+ public function process(?string $userId, array $input, callable $reportProgress): array {
+ if ($this->appConfig->getAppValueBool('fail-' . $this->getId())) {
+ throw new ProcessingException('Failing as set by AppConfig');
+ }
+
+ if (!isset($input['input']) || !is_string($input['input'])) {
+ throw new RuntimeException('Invalid prompt');
+ }
+ $prompt = $input['input'];
+
+ $nbImages = 1;
+ if (isset($input['numberOfImages']) && is_int($input['numberOfImages'])) {
+ $nbImages = $input['numberOfImages'];
+ }
+
+ $fakeContent = file_get_contents(__DIR__ . '/../../img/logo.png');
+
+ $output = ['images' => []];
+ foreach (range(1, $nbImages) as $i) {
+ $output['images'][] = $fakeContent;
+ }
+ /** @var array<string, list<numeric|string>|numeric|string> $output */
+ return $output;
+ }
+}
diff --git a/apps/testing/lib/TaskProcessing/FakeTextToTextProvider.php b/apps/testing/lib/TaskProcessing/FakeTextToTextProvider.php
new file mode 100644
index 00000000000..5012823024e
--- /dev/null
+++ b/apps/testing/lib/TaskProcessing/FakeTextToTextProvider.php
@@ -0,0 +1,122 @@
+<?php
+
+/**
+ * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+declare(strict_types=1);
+
+namespace OCA\Testing\TaskProcessing;
+
+use OCA\Testing\AppInfo\Application;
+use OCP\AppFramework\Services\IAppConfig;
+use OCP\TaskProcessing\EShapeType;
+use OCP\TaskProcessing\Exception\ProcessingException;
+use OCP\TaskProcessing\ISynchronousProvider;
+use OCP\TaskProcessing\ShapeDescriptor;
+use OCP\TaskProcessing\ShapeEnumValue;
+use OCP\TaskProcessing\TaskTypes\TextToText;
+use RuntimeException;
+
+class FakeTextToTextProvider implements ISynchronousProvider {
+
+ public function __construct(
+ protected IAppConfig $appConfig,
+ ) {
+ }
+
+ public function getId(): string {
+ return Application::APP_ID . '-text2text';
+ }
+
+ public function getName(): string {
+ return 'Fake text2text task processing provider';
+ }
+
+ public function getTaskTypeId(): string {
+ return TextToText::ID;
+ }
+
+ public function getExpectedRuntime(): int {
+ return 1;
+ }
+
+ public function getInputShapeEnumValues(): array {
+ return [];
+ }
+
+ public function getInputShapeDefaults(): array {
+ return [];
+ }
+
+ public function getOptionalInputShape(): array {
+ return [
+ 'max_tokens' => new ShapeDescriptor(
+ 'Maximum output words',
+ 'The maximum number of words/tokens that can be generated in the completion.',
+ EShapeType::Number
+ ),
+ 'model' => new ShapeDescriptor(
+ 'Model',
+ 'The model used to generate the completion',
+ EShapeType::Enum
+ ),
+ ];
+ }
+
+ public function getOptionalInputShapeEnumValues(): array {
+ return [
+ 'model' => [
+ new ShapeEnumValue('Model 1', 'model_1'),
+ new ShapeEnumValue('Model 2', 'model_2'),
+ new ShapeEnumValue('Model 3', 'model_3'),
+ ],
+ ];
+ }
+
+ public function getOptionalInputShapeDefaults(): array {
+ return [
+ 'max_tokens' => 1234,
+ 'model' => 'model_2',
+ ];
+ }
+
+ public function getOptionalOutputShape(): array {
+ return [];
+ }
+
+ public function getOutputShapeEnumValues(): array {
+ return [];
+ }
+
+ public function getOptionalOutputShapeEnumValues(): array {
+ return [];
+ }
+
+ public function process(?string $userId, array $input, callable $reportProgress): array {
+ if ($this->appConfig->getAppValueBool('fail-' . $this->getId())) {
+ throw new ProcessingException('Failing as set by AppConfig');
+ }
+
+ if (isset($input['model']) && is_string($input['model'])) {
+ $model = $input['model'];
+ } else {
+ $model = 'unknown model';
+ }
+
+ if (!isset($input['input']) || !is_string($input['input'])) {
+ throw new RuntimeException('Invalid prompt');
+ }
+ $prompt = $input['input'];
+
+ $maxTokens = null;
+ if (isset($input['max_tokens']) && is_int($input['max_tokens'])) {
+ $maxTokens = $input['max_tokens'];
+ }
+
+ return [
+ 'output' => 'This is a fake result: ' . "\n\n- Prompt: " . $prompt . "\n- Model: " . $model . "\n- Maximum number of words: " . $maxTokens,
+ ];
+ }
+}
diff --git a/apps/testing/lib/TaskProcessing/FakeTextToTextSummaryProvider.php b/apps/testing/lib/TaskProcessing/FakeTextToTextSummaryProvider.php
new file mode 100644
index 00000000000..58816d8a0df
--- /dev/null
+++ b/apps/testing/lib/TaskProcessing/FakeTextToTextSummaryProvider.php
@@ -0,0 +1,122 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+
+namespace OCA\Testing\TaskProcessing;
+
+use OCA\Testing\AppInfo\Application;
+use OCP\AppFramework\Services\IAppConfig;
+use OCP\TaskProcessing\EShapeType;
+use OCP\TaskProcessing\Exception\ProcessingException;
+use OCP\TaskProcessing\ISynchronousProvider;
+use OCP\TaskProcessing\ShapeDescriptor;
+use OCP\TaskProcessing\ShapeEnumValue;
+use OCP\TaskProcessing\TaskTypes\TextToTextSummary;
+use RuntimeException;
+
+class FakeTextToTextSummaryProvider implements ISynchronousProvider {
+
+ public function __construct(
+ protected IAppConfig $appConfig,
+ ) {
+ }
+
+ public function getId(): string {
+ return Application::APP_ID . '-text2text-summary';
+ }
+
+ public function getName(): string {
+ return 'Fake text2text summary task processing provider';
+ }
+
+ public function getTaskTypeId(): string {
+ return TextToTextSummary::ID;
+ }
+
+ public function getExpectedRuntime(): int {
+ return 1;
+ }
+
+ public function getInputShapeEnumValues(): array {
+ return [];
+ }
+
+ public function getInputShapeDefaults(): array {
+ return [];
+ }
+
+ public function getOptionalInputShape(): array {
+ return [
+ 'max_tokens' => new ShapeDescriptor(
+ 'Maximum output words',
+ 'The maximum number of words/tokens that can be generated in the completion.',
+ EShapeType::Number
+ ),
+ 'model' => new ShapeDescriptor(
+ 'Model',
+ 'The model used to generate the completion',
+ EShapeType::Enum
+ ),
+ ];
+ }
+
+ public function getOptionalInputShapeEnumValues(): array {
+ return [
+ 'model' => [
+ new ShapeEnumValue('Model 1', 'model_1'),
+ new ShapeEnumValue('Model 2', 'model_2'),
+ new ShapeEnumValue('Model 3', 'model_3'),
+ ],
+ ];
+ }
+
+ public function getOptionalInputShapeDefaults(): array {
+ return [
+ 'max_tokens' => 1234,
+ 'model' => 'model_2',
+ ];
+ }
+
+ public function getOptionalOutputShape(): array {
+ return [];
+ }
+
+ public function getOutputShapeEnumValues(): array {
+ return [];
+ }
+
+ public function getOptionalOutputShapeEnumValues(): array {
+ return [];
+ }
+
+ public function process(?string $userId, array $input, callable $reportProgress): array {
+ if ($this->appConfig->getAppValueBool('fail-' . $this->getId())) {
+ throw new ProcessingException('Failing as set by AppConfig');
+ }
+
+ if (isset($input['model']) && is_string($input['model'])) {
+ $model = $input['model'];
+ } else {
+ $model = 'unknown model';
+ }
+
+ if (!isset($input['input']) || !is_string($input['input'])) {
+ throw new RuntimeException('Invalid prompt');
+ }
+ $prompt = $input['input'];
+
+ $maxTokens = null;
+ if (isset($input['max_tokens']) && is_int($input['max_tokens'])) {
+ $maxTokens = $input['max_tokens'];
+ }
+
+ return [
+ 'output' => 'This is a fake summary: ',// . "\n\n- Prompt: " . $prompt . "\n- Model: " . $model . "\n- Maximum number of words: " . $maxTokens,
+ ];
+ }
+}
diff --git a/apps/testing/lib/TaskProcessing/FakeTranscribeProvider.php b/apps/testing/lib/TaskProcessing/FakeTranscribeProvider.php
new file mode 100644
index 00000000000..4827a07037a
--- /dev/null
+++ b/apps/testing/lib/TaskProcessing/FakeTranscribeProvider.php
@@ -0,0 +1,88 @@
+<?php
+
+/**
+ * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+declare(strict_types=1);
+
+namespace OCA\Testing\TaskProcessing;
+
+use OCA\Testing\AppInfo\Application;
+use OCP\AppFramework\Services\IAppConfig;
+use OCP\Files\File;
+use OCP\TaskProcessing\Exception\ProcessingException;
+use OCP\TaskProcessing\ISynchronousProvider;
+use OCP\TaskProcessing\TaskTypes\AudioToText;
+use RuntimeException;
+
+class FakeTranscribeProvider implements ISynchronousProvider {
+
+ public function __construct(
+ protected IAppConfig $appConfig,
+ ) {
+ }
+
+ public function getId(): string {
+ return Application::APP_ID . '-audio2text';
+ }
+
+ public function getName(): string {
+ return 'Fake audio2text task processing provider';
+ }
+
+ public function getTaskTypeId(): string {
+ return AudioToText::ID;
+ }
+
+ public function getExpectedRuntime(): int {
+ return 1;
+ }
+
+ public function getInputShapeEnumValues(): array {
+ return [];
+ }
+
+ public function getInputShapeDefaults(): array {
+ return [];
+ }
+
+ public function getOptionalInputShape(): array {
+ return [];
+ }
+
+ public function getOptionalInputShapeEnumValues(): array {
+ return [];
+ }
+
+ public function getOptionalInputShapeDefaults(): array {
+ return [];
+ }
+
+ public function getOutputShapeEnumValues(): array {
+ return [];
+ }
+
+ public function getOptionalOutputShape(): array {
+ return [];
+ }
+
+ public function getOptionalOutputShapeEnumValues(): array {
+ return [];
+ }
+
+ public function process(?string $userId, array $input, callable $reportProgress): array {
+ if (!isset($input['input']) || !$input['input'] instanceof File || !$input['input']->isReadable()) {
+ throw new RuntimeException('Invalid input file');
+ }
+ if ($this->appConfig->getAppValueBool('fail-' . $this->getId())) {
+ throw new ProcessingException('Failing as set by AppConfig');
+ }
+
+ $inputFile = $input['input'];
+ $transcription = 'Fake transcription result';
+
+ return ['output' => $transcription];
+ }
+}
diff --git a/apps/testing/lib/TaskProcessing/FakeTranslateProvider.php b/apps/testing/lib/TaskProcessing/FakeTranslateProvider.php
new file mode 100644
index 00000000000..22be8e83049
--- /dev/null
+++ b/apps/testing/lib/TaskProcessing/FakeTranslateProvider.php
@@ -0,0 +1,154 @@
+<?php
+
+/**
+ * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+declare(strict_types=1);
+
+namespace OCA\Testing\TaskProcessing;
+
+use OCA\Testing\AppInfo\Application;
+use OCP\AppFramework\Services\IAppConfig;
+use OCP\L10N\IFactory;
+use OCP\TaskProcessing\EShapeType;
+use OCP\TaskProcessing\Exception\ProcessingException;
+use OCP\TaskProcessing\ISynchronousProvider;
+use OCP\TaskProcessing\ShapeDescriptor;
+use OCP\TaskProcessing\ShapeEnumValue;
+use OCP\TaskProcessing\TaskTypes\TextToTextTranslate;
+use RuntimeException;
+
+class FakeTranslateProvider implements ISynchronousProvider {
+
+ public function __construct(
+ private IFactory $l10nFactory,
+ protected IAppConfig $appConfig,
+ ) {
+ }
+
+ public function getId(): string {
+ return Application::APP_ID . '-translate';
+ }
+
+ public function getName(): string {
+ return 'Fake translate task processing provider';
+ }
+
+ public function getTaskTypeId(): string {
+ return TextToTextTranslate::ID;
+ }
+
+ public function getExpectedRuntime(): int {
+ return 1;
+ }
+
+ public function getInputShapeEnumValues(): array {
+ $coreL = $this->l10nFactory->getLanguages();
+ $languages = array_merge($coreL['commonLanguages'], $coreL['otherLanguages']);
+ $languageEnumValues = array_map(static function (array $language) {
+ return new ShapeEnumValue($language['name'], $language['code']);
+ }, $languages);
+ $detectLanguageEnumValue = new ShapeEnumValue('Detect language', 'detect_language');
+ return [
+ 'origin_language' => array_merge([$detectLanguageEnumValue], $languageEnumValues),
+ 'target_language' => $languageEnumValues,
+ ];
+ }
+
+ public function getInputShapeDefaults(): array {
+ return [
+ 'origin_language' => 'detect_language',
+ ];
+ }
+
+ public function getOptionalInputShape(): array {
+ return [
+ 'max_tokens' => new ShapeDescriptor(
+ 'Maximum output words',
+ 'The maximum number of words/tokens that can be generated in the completion.',
+ EShapeType::Number
+ ),
+ 'model' => new ShapeDescriptor(
+ 'Model',
+ 'The model used to generate the completion',
+ EShapeType::Enum
+ ),
+ ];
+ }
+
+ public function getOptionalInputShapeEnumValues(): array {
+ return [
+ 'model' => [
+ new ShapeEnumValue('Model 1', 'model_1'),
+ new ShapeEnumValue('Model 2', 'model_2'),
+ new ShapeEnumValue('Model 3', 'model_3'),
+ ],
+ ];
+ }
+
+ public function getOptionalInputShapeDefaults(): array {
+ return [
+ 'max_tokens' => 200,
+ 'model' => 'model_3',
+ ];
+ }
+
+ public function getOptionalOutputShape(): array {
+ return [];
+ }
+
+ public function getOutputShapeEnumValues(): array {
+ return [];
+ }
+
+ public function getOptionalOutputShapeEnumValues(): array {
+ return [];
+ }
+
+ private function getCoreLanguagesByCode(): array {
+ $coreL = $this->l10nFactory->getLanguages();
+ $coreLanguages = array_reduce(array_merge($coreL['commonLanguages'], $coreL['otherLanguages']), function ($carry, $val) {
+ $carry[$val['code']] = $val['name'];
+ return $carry;
+ });
+ return $coreLanguages;
+ }
+
+ public function process(?string $userId, array $input, callable $reportProgress): array {
+ if ($this->appConfig->getAppValueBool('fail-' . $this->getId())) {
+ throw new ProcessingException('Failing as set by AppConfig');
+ }
+
+ if (isset($input['model']) && is_string($input['model'])) {
+ $model = $input['model'];
+ } else {
+ $model = 'model_3';
+ }
+
+ if (!isset($input['input']) || !is_string($input['input'])) {
+ throw new RuntimeException('Invalid input text');
+ }
+ $inputText = $input['input'];
+
+ $maxTokens = null;
+ if (isset($input['max_tokens']) && is_int($input['max_tokens'])) {
+ $maxTokens = $input['max_tokens'];
+ }
+
+ $coreLanguages = $this->getCoreLanguagesByCode();
+
+ $toLanguage = $coreLanguages[$input['target_language']] ?? $input['target_language'];
+ if ($input['origin_language'] !== 'detect_language') {
+ $fromLanguage = $coreLanguages[$input['origin_language']] ?? $input['origin_language'];
+ $prompt = 'Fake translation from ' . $fromLanguage . ' to ' . $toLanguage . ': ' . $inputText;
+ } else {
+ $prompt = 'Fake Translation to ' . $toLanguage . ': ' . $inputText;
+ }
+
+ $fakeResult = $prompt . "\n\nModel: " . $model . "\nMax tokens: " . $maxTokens;
+
+ return ['output' => $fakeResult];
+ }
+}