diff --git a/lib/AppInfo/BeforeTemplateRenderedListener.php b/lib/AppInfo/BeforeTemplateRenderedListener.php index 81618a4..7df16f1 100644 --- a/lib/AppInfo/BeforeTemplateRenderedListener.php +++ b/lib/AppInfo/BeforeTemplateRenderedListener.php @@ -5,11 +5,20 @@ namespace OCA\Zulip\AppInfo; use OCP\AppFramework\Http\Events\BeforeTemplateRenderedEvent; +use OCP\AppFramework\Services\IInitialState; use OCP\EventDispatcher\Event; use OCP\EventDispatcher\IEventListener; +use OCP\IConfig; /** @template-implements IEventListener */ class BeforeTemplateRenderedListener implements IEventListener { + + public function __construct( + private IConfig $config, + private IInitialState $initialStateService, + ) { + } + public function handle(Event $event): void { if (!($event instanceof BeforeTemplateRenderedEvent)) { return; @@ -18,5 +27,13 @@ public function handle(Event $event): void { return; } \OCP\Util::addStyle(Application::APP_ID, 'zulip-search'); + + $adminConfig = [ + 'send_type_enabled_file' => $this->config->getAppValue(Application::APP_ID, 'send_type_enabled_file', '1') === '1', + 'send_type_enabled_public_link' => $this->config->getAppValue(Application::APP_ID, 'send_type_enabled_public_link', '1') === '1', + 'send_type_enabled_internal_link' => $this->config->getAppValue(Application::APP_ID, 'send_type_enabled_internal_link', '1') === '1', + 'send_type_default' => $this->config->getAppValue(Application::APP_ID, 'send_type_default', ''), + ]; + $this->initialStateService->provideInitialState('admin-config', $adminConfig); } } diff --git a/lib/Controller/ConfigController.php b/lib/Controller/ConfigController.php index 21e126d..f3333fa 100644 --- a/lib/Controller/ConfigController.php +++ b/lib/Controller/ConfigController.php @@ -22,6 +22,7 @@ use OCA\Zulip\Service\SecretService; use OCP\AppFramework\Controller; use OCP\AppFramework\Http; +use OCP\AppFramework\Http\Attribute\AuthorizedAdminSetting; use OCP\AppFramework\Http\Attribute\FrontpageRoute; use OCP\AppFramework\Http\Attribute\NoAdminRequired; use OCP\AppFramework\Http\Attribute\PasswordConfirmationRequired; @@ -78,6 +79,22 @@ public function setConfig(array $values): DataResponse { return new DataResponse([]); } + /** + * @return DataResponse + */ + #[AuthorizedAdminSetting(settings: \OCA\Zulip\Settings\Admin::class)] + #[FrontpageRoute(verb: 'PUT', url: '/admin-config')] + public function setAdminConfig(array $values): DataResponse { + $allowedKeys = ['send_type_enabled_file', 'send_type_enabled_public_link', 'send_type_enabled_internal_link', 'send_type_default']; + foreach ($values as $key => $value) { + if (!in_array($key, $allowedKeys, true)) { + return new DataResponse([], Http::STATUS_BAD_REQUEST); + } + $this->config->setAppValue(Application::APP_ID, $key, $value); + } + return new DataResponse([]); + } + /** * set sensitive config values * diff --git a/lib/Settings/Admin.php b/lib/Settings/Admin.php new file mode 100644 index 0000000..f5fa547 --- /dev/null +++ b/lib/Settings/Admin.php @@ -0,0 +1,39 @@ + $this->config->getAppValue(Application::APP_ID, 'send_type_enabled_file', '1') === '1', + 'send_type_enabled_public_link' => $this->config->getAppValue(Application::APP_ID, 'send_type_enabled_public_link', '1') === '1', + 'send_type_enabled_internal_link' => $this->config->getAppValue(Application::APP_ID, 'send_type_enabled_internal_link', '1') === '1', + 'send_type_default' => $this->config->getAppValue(Application::APP_ID, 'send_type_default', ''), + ]; + $this->initialStateService->provideInitialState('admin-config', $adminConfig); + return new TemplateResponse(Application::APP_ID, 'adminSettings'); + } + + public function getSection(): string { + return 'connected-accounts'; + } + + public function getPriority(): int { + return 10; + } +} diff --git a/lib/Settings/AdminSection.php b/lib/Settings/AdminSection.php new file mode 100644 index 0000000..a2842c9 --- /dev/null +++ b/lib/Settings/AdminSection.php @@ -0,0 +1,34 @@ +l->t('Connected accounts'); + } + + public function getPriority(): int { + return 80; + } + + public function getIcon(): string { + return $this->urlGenerator->imagePath('core', 'categories/integration.svg'); + } +} diff --git a/src/adminSettings.js b/src/adminSettings.js new file mode 100644 index 0000000..315abb3 --- /dev/null +++ b/src/adminSettings.js @@ -0,0 +1,6 @@ +import { createApp } from 'vue' +import AdminSettings from './components/AdminSettings.vue' + +const app = createApp(AdminSettings) +app.mixin({ methods: { t, n } }) +app.mount('#zulip_prefs') diff --git a/src/components/AdminSettings.vue b/src/components/AdminSettings.vue new file mode 100644 index 0000000..520e9ef --- /dev/null +++ b/src/components/AdminSettings.vue @@ -0,0 +1,197 @@ + + + + + diff --git a/src/components/SendFilesModal.vue b/src/components/SendFilesModal.vue index a4d6ef4..e335676 100644 --- a/src/components/SendFilesModal.vue +++ b/src/components/SendFilesModal.vue @@ -152,7 +152,7 @@
- ({ + send_type_enabled_file: true, + send_type_enabled_public_link: true, + send_type_enabled_internal_link: true, + send_type_default: '', + }), + }, + }, + data() { return { SEND_TYPE, show: false, loading: false, - sendType: SEND_TYPE.file.id, + sendType: this.resolveDefaultSendType(), comment: '', query: '', files: [], @@ -339,6 +351,11 @@ export default { }, computed: { + availableSendTypes() { + return Object.fromEntries( + Object.entries(SEND_TYPE).filter(([key]) => this.adminConfig[`send_type_enabled_${key}`] !== false), + ) + }, warnAboutSendingDirectories() { return this.sendType === SEND_TYPE.file.id && this.files.findIndex((f) => f.type === 'dir') !== -1 }, @@ -359,7 +376,7 @@ export default { }, watch: { - selectedChannel(newChannel, oldChannel) { + selectedChannel(newChannel) { if (newChannel?.type === 'channel') { this.updateTopics() } @@ -371,6 +388,19 @@ export default { }, methods: { + resolveDefaultSendType() { + const def = this.adminConfig?.send_type_default + if (def && this.adminConfig?.[`send_type_enabled_${def}`] !== false) { + return def + } + // Fall back to first enabled type + for (const key of Object.keys(SEND_TYPE)) { + if (this.adminConfig?.[`send_type_enabled_${key}`] !== false) { + return key + } + } + return SEND_TYPE.file.id + }, reset() { this.selectedChannel = null this.selectedTopic = null @@ -379,7 +409,7 @@ export default { this.channels = undefined this.topics = undefined this.comment = '' - this.sendType = SEND_TYPE.file.id + this.sendType = this.resolveDefaultSendType() this.selectedPermission = 'view' this.expirationEnabled = false this.expirationDate = null diff --git a/src/filesplugin.js b/src/filesplugin.js index 1536e74..d835eba 100644 --- a/src/filesplugin.js +++ b/src/filesplugin.js @@ -18,6 +18,7 @@ import moment from '@nextcloud/moment' import { generateUrl, linkTo } from '@nextcloud/router' import { showSuccess, showError } from '@nextcloud/dialogs' import { translate as t, translatePlural as n } from '@nextcloud/l10n' +import { loadState } from '@nextcloud/initial-state' import { SEND_TYPE } from './utils.js' import { registerFileAction, Permission, FileType, @@ -186,7 +187,19 @@ const modalElement = document.createElement('div') modalElement.id = modalId document.body.append(modalElement) -const modalApp = createApp(SendFilesModal) +let adminConfig = { + send_type_enabled_file: true, + send_type_enabled_public_link: true, + send_type_enabled_internal_link: true, + send_type_default: '', +} +try { + adminConfig = loadState('integration_zulip', 'admin-config', adminConfig) +} catch (e) { + // admin-config not available, use defaults +} + +const modalApp = createApp(SendFilesModal, { adminConfig }) modalApp.mixin({ methods: { t, n } }) OCA.Zulip.ZulipSendModalVue = modalApp.mount(modalElement) diff --git a/webpack.js b/webpack.js index 966fcda..e6761cf 100644 --- a/webpack.js +++ b/webpack.js @@ -14,6 +14,7 @@ webpackConfig.stats = { const appId = 'integration_zulip' webpackConfig.entry = { + adminSettings: { import: path.join(__dirname, 'src', 'adminSettings.js'), filename: appId + '-adminSettings.js' }, personalSettings: { import: path.join(__dirname, 'src', 'personalSettings.js'), filename: appId + '-personalSettings.js' }, filesplugin: { import: path.join(__dirname, 'src', 'filesplugin.js'), filename: appId + '-filesplugin.js' }, popupSuccess: { import: path.join(__dirname, 'src', 'popupSuccess.js'), filename: appId + '-popupSuccess.js' },