diff options
-rw-r--r-- | apps/dav/appinfo/v1/publicwebdav.php | 1 | ||||
-rw-r--r-- | apps/dav/appinfo/v2/publicremote.php | 1 | ||||
-rw-r--r-- | apps/dav/lib/Files/Sharing/FilesDropPlugin.php | 53 | ||||
-rw-r--r-- | apps/dav/tests/unit/Files/Sharing/FilesDropPluginTest.php | 15 | ||||
-rw-r--r-- | apps/files_sharing/composer/composer/autoload_classmap.php | 1 | ||||
-rw-r--r-- | apps/files_sharing/composer/composer/autoload_static.php | 1 | ||||
-rw-r--r-- | apps/files_sharing/js/files_drop.js | 6 | ||||
-rw-r--r-- | apps/files_sharing/lib/AppInfo/Application.php | 7 | ||||
-rw-r--r-- | apps/files_sharing/lib/DefaultPublicShareTemplateProvider.php | 49 | ||||
-rw-r--r-- | apps/files_sharing/lib/Listener/LoadPublicFileRequestAuthListener.php | 59 | ||||
-rw-r--r-- | apps/files_sharing/src/components/NewFileRequestDialog.vue | 14 | ||||
-rw-r--r-- | apps/files_sharing/src/public-file-request.ts | 23 | ||||
-rw-r--r-- | apps/files_sharing/src/views/PublicAuthPrompt.vue | 136 | ||||
-rw-r--r-- | apps/files_sharing/templates/public.php | 12 | ||||
-rw-r--r-- | apps/files_sharing/tests/Controller/ShareControllerTest.php | 14 | ||||
-rw-r--r-- | webpack.modules.js | 1 |
16 files changed, 332 insertions, 61 deletions
diff --git a/apps/dav/appinfo/v1/publicwebdav.php b/apps/dav/appinfo/v1/publicwebdav.php index 5ef383e1dd5..38753374150 100644 --- a/apps/dav/appinfo/v1/publicwebdav.php +++ b/apps/dav/appinfo/v1/publicwebdav.php @@ -87,6 +87,7 @@ $server = $serverFactory->createServer($baseuri, $requestUri, $authPlugin, funct $view = new \OC\Files\View($node->getPath()); $filesDropPlugin->setView($view); + $filesDropPlugin->setShare($share); return $view; }); diff --git a/apps/dav/appinfo/v2/publicremote.php b/apps/dav/appinfo/v2/publicremote.php index bdc4169dd4e..44cf4214505 100644 --- a/apps/dav/appinfo/v2/publicremote.php +++ b/apps/dav/appinfo/v2/publicremote.php @@ -116,6 +116,7 @@ $server = $serverFactory->createServer($baseuri, $requestUri, $authPlugin, funct $view = new View($node->getPath()); $filesDropPlugin->setView($view); + $filesDropPlugin->setShare($share); return $view; }); diff --git a/apps/dav/lib/Files/Sharing/FilesDropPlugin.php b/apps/dav/lib/Files/Sharing/FilesDropPlugin.php index c4d1957c67e..b364c4ebbfc 100644 --- a/apps/dav/lib/Files/Sharing/FilesDropPlugin.php +++ b/apps/dav/lib/Files/Sharing/FilesDropPlugin.php @@ -6,6 +6,7 @@ namespace OCA\DAV\Files\Sharing; use OC\Files\View; +use OCP\Share\IShare; use Sabre\DAV\Exception\MethodNotAllowed; use Sabre\DAV\ServerPlugin; use Sabre\HTTP\RequestInterface; @@ -16,17 +17,19 @@ use Sabre\HTTP\ResponseInterface; */ class FilesDropPlugin extends ServerPlugin { - /** @var View */ - private $view; + private ?View $view = null; + private ?IShare $share = null; + private bool $enabled = false; - /** @var bool */ - private $enabled = false; - - public function setView(View $view) { + public function setView(View $view): void { $this->view = $view; } - public function enable() { + public function setShare(IShare $share): void { + $this->share = $share; + } + + public function enable(): void { $this->enabled = true; } @@ -39,25 +42,53 @@ class FilesDropPlugin extends ServerPlugin { * @return void * @throws MethodNotAllowed */ - public function initialize(\Sabre\DAV\Server $server) { + public function initialize(\Sabre\DAV\Server $server): void { $server->on('beforeMethod:*', [$this, 'beforeMethod'], 999); $this->enabled = false; } - public function beforeMethod(RequestInterface $request, ResponseInterface $response) { - if (!$this->enabled) { + public function beforeMethod(RequestInterface $request, ResponseInterface $response): void { + if (!$this->enabled || $this->share === null || $this->view === null) { return; } - if ($request->getMethod() !== 'PUT' && $request->getMethod() !== 'MKCOL') { + // Only allow file drop + if ($request->getMethod() !== 'PUT') { throw new MethodNotAllowed('Only PUT is allowed on files drop'); } + // Always upload at the root level $path = explode('/', $request->getPath()); $path = array_pop($path); + // Extract the attributes for the file request + $attributes = $this->share->getAttributes(); + if ($attributes === null) { + return; + } + + // Prepare file request + $nickName = $request->getHeader('X-NC-Nickname'); + $isFileRequest = $attributes->getAttribute('fileRequest', 'enabled') === true; + + // We need a valid nickname for file requests + if ($isFileRequest && ($nickName == null || trim($nickName) === '')) { + throw new MethodNotAllowed('Nickname is required for file requests'); + } + + // If this is a file request we need to create a folder for the user + if ($isFileRequest) { + // Check if the folder already exists + if (!($this->view->file_exists($nickName) === true)) { + $this->view->mkdir($nickName); + } + // Put all files in the subfolder + $path = $nickName . '/' . $path; + } + $newName = \OC_Helper::buildNotExistingFileNameForView('/', $path, $this->view); $url = $request->getBaseUrl() . $newName; $request->setUrl($url); } + } diff --git a/apps/dav/tests/unit/Files/Sharing/FilesDropPluginTest.php b/apps/dav/tests/unit/Files/Sharing/FilesDropPluginTest.php index 9a077e35076..7264119f8c6 100644 --- a/apps/dav/tests/unit/Files/Sharing/FilesDropPluginTest.php +++ b/apps/dav/tests/unit/Files/Sharing/FilesDropPluginTest.php @@ -7,6 +7,8 @@ namespace OCA\DAV\Tests\Files\Sharing; use OC\Files\View; use OCA\DAV\Files\Sharing\FilesDropPlugin; +use OCP\Share\IAttributes; +use OCP\Share\IShare; use Sabre\DAV\Exception\MethodNotAllowed; use Sabre\DAV\Server; use Sabre\HTTP\RequestInterface; @@ -18,6 +20,9 @@ class FilesDropPluginTest extends TestCase { /** @var View|\PHPUnit\Framework\MockObject\MockObject */ private $view; + /** @var IShare|\PHPUnit\Framework\MockObject\MockObject */ + private $share; + /** @var Server|\PHPUnit\Framework\MockObject\MockObject */ private $server; @@ -34,6 +39,7 @@ class FilesDropPluginTest extends TestCase { parent::setUp(); $this->view = $this->createMock(View::class); + $this->share = $this->createMock(IShare::class); $this->server = $this->createMock(Server::class); $this->plugin = new FilesDropPlugin(); @@ -42,6 +48,11 @@ class FilesDropPluginTest extends TestCase { $this->response->expects($this->never()) ->method($this->anything()); + + $attributes = $this->createMock(IAttributes::class); + $this->share->expects($this->any()) + ->method('getAttributes') + ->willReturn($attributes); } public function testInitialize(): void { @@ -69,6 +80,7 @@ class FilesDropPluginTest extends TestCase { public function testValid(): void { $this->plugin->enable(); $this->plugin->setView($this->view); + $this->plugin->setShare($this->share); $this->request->method('getMethod') ->willReturn('PUT'); @@ -93,6 +105,7 @@ class FilesDropPluginTest extends TestCase { public function testFileAlreadyExistsValid(): void { $this->plugin->enable(); $this->plugin->setView($this->view); + $this->plugin->setShare($this->share); $this->request->method('getMethod') ->willReturn('PUT'); @@ -122,6 +135,7 @@ class FilesDropPluginTest extends TestCase { public function testNoMKCOL(): void { $this->plugin->enable(); $this->plugin->setView($this->view); + $this->plugin->setShare($this->share); $this->request->method('getMethod') ->willReturn('MKCOL'); @@ -134,6 +148,7 @@ class FilesDropPluginTest extends TestCase { public function testNoSubdirPut(): void { $this->plugin->enable(); $this->plugin->setView($this->view); + $this->plugin->setShare($this->share); $this->request->method('getMethod') ->willReturn('PUT'); diff --git a/apps/files_sharing/composer/composer/autoload_classmap.php b/apps/files_sharing/composer/composer/autoload_classmap.php index e1abddb3a64..b7a931a6228 100644 --- a/apps/files_sharing/composer/composer/autoload_classmap.php +++ b/apps/files_sharing/composer/composer/autoload_classmap.php @@ -59,6 +59,7 @@ return array( 'OCA\\Files_Sharing\\Listener\\BeforeDirectFileDownloadListener' => $baseDir . '/../lib/Listener/BeforeDirectFileDownloadListener.php', 'OCA\\Files_Sharing\\Listener\\BeforeZipCreatedListener' => $baseDir . '/../lib/Listener/BeforeZipCreatedListener.php', 'OCA\\Files_Sharing\\Listener\\LoadAdditionalListener' => $baseDir . '/../lib/Listener/LoadAdditionalListener.php', + 'OCA\\Files_Sharing\\Listener\\LoadPublicFileRequestAuthListener' => $baseDir . '/../lib/Listener/LoadPublicFileRequestAuthListener.php', 'OCA\\Files_Sharing\\Listener\\LoadSidebarListener' => $baseDir . '/../lib/Listener/LoadSidebarListener.php', 'OCA\\Files_Sharing\\Listener\\ShareInteractionListener' => $baseDir . '/../lib/Listener/ShareInteractionListener.php', 'OCA\\Files_Sharing\\Listener\\UserAddedToGroupListener' => $baseDir . '/../lib/Listener/UserAddedToGroupListener.php', diff --git a/apps/files_sharing/composer/composer/autoload_static.php b/apps/files_sharing/composer/composer/autoload_static.php index 5d2fb3bac2a..70dc7be7cdf 100644 --- a/apps/files_sharing/composer/composer/autoload_static.php +++ b/apps/files_sharing/composer/composer/autoload_static.php @@ -74,6 +74,7 @@ class ComposerStaticInitFiles_Sharing 'OCA\\Files_Sharing\\Listener\\BeforeDirectFileDownloadListener' => __DIR__ . '/..' . '/../lib/Listener/BeforeDirectFileDownloadListener.php', 'OCA\\Files_Sharing\\Listener\\BeforeZipCreatedListener' => __DIR__ . '/..' . '/../lib/Listener/BeforeZipCreatedListener.php', 'OCA\\Files_Sharing\\Listener\\LoadAdditionalListener' => __DIR__ . '/..' . '/../lib/Listener/LoadAdditionalListener.php', + 'OCA\\Files_Sharing\\Listener\\LoadPublicFileRequestAuthListener' => __DIR__ . '/..' . '/../lib/Listener/LoadPublicFileRequestAuthListener.php', 'OCA\\Files_Sharing\\Listener\\LoadSidebarListener' => __DIR__ . '/..' . '/../lib/Listener/LoadSidebarListener.php', 'OCA\\Files_Sharing\\Listener\\ShareInteractionListener' => __DIR__ . '/..' . '/../lib/Listener/ShareInteractionListener.php', 'OCA\\Files_Sharing\\Listener\\UserAddedToGroupListener' => __DIR__ . '/..' . '/../lib/Listener/UserAddedToGroupListener.php', diff --git a/apps/files_sharing/js/files_drop.js b/apps/files_sharing/js/files_drop.js index fd9b796ee2c..450af078af2 100644 --- a/apps/files_sharing/js/files_drop.js +++ b/apps/files_sharing/js/files_drop.js @@ -22,7 +22,7 @@ // note: password not be required, the endpoint // will recognize previous validation from the session root: OC.getRootPath() + '/public.php/dav/files/' + $('#sharingToken').val() + '/', - useHTTPS: OC.getProtocol() === 'https' + useHTTPS: OC.getProtocol() === 'https', }); // We only process one file at a time 🤷♀️ @@ -47,6 +47,10 @@ data.headers = {}; } + if (localStorage.getItem('nick') !== null) { + data.headers['X-NC-Nickname'] = localStorage.getItem('nick') + } + $('#drop-upload-done-indicator').addClass('hidden'); $('#drop-upload-progress-indicator').removeClass('hidden'); diff --git a/apps/files_sharing/lib/AppInfo/Application.php b/apps/files_sharing/lib/AppInfo/Application.php index 82a5981febf..98c2d280856 100644 --- a/apps/files_sharing/lib/AppInfo/Application.php +++ b/apps/files_sharing/lib/AppInfo/Application.php @@ -18,6 +18,7 @@ use OCA\Files_Sharing\Helper; use OCA\Files_Sharing\Listener\BeforeDirectFileDownloadListener; use OCA\Files_Sharing\Listener\BeforeZipCreatedListener; use OCA\Files_Sharing\Listener\LoadAdditionalListener; +use OCA\Files_Sharing\Listener\LoadPublicFileRequestAuthListener; use OCA\Files_Sharing\Listener\LoadSidebarListener; use OCA\Files_Sharing\Listener\ShareInteractionListener; use OCA\Files_Sharing\Listener\UserAddedToGroupListener; @@ -34,6 +35,7 @@ use OCP\AppFramework\App; use OCP\AppFramework\Bootstrap\IBootContext; use OCP\AppFramework\Bootstrap\IBootstrap; use OCP\AppFramework\Bootstrap\IRegistrationContext; +use OCP\AppFramework\Http\Events\BeforeTemplateRenderedEvent; use OCP\Collaboration\Resources\LoadAdditionalScriptsEvent as ResourcesLoadAdditionalScriptsEvent; use OCP\EventDispatcher\IEventDispatcher; use OCP\Federation\ICloudIdManager; @@ -85,7 +87,7 @@ class Application extends App implements IBootstrap { $context->registerEventListener(GroupChangedEvent::class, GroupDisplayNameCache::class); $context->registerEventListener(GroupDeletedEvent::class, GroupDisplayNameCache::class); - // sidebar and files scripts + // Sidebar and files scripts $context->registerEventListener(LoadAdditionalScriptsEvent::class, LoadAdditionalListener::class); $context->registerEventListener(LoadSidebar::class, LoadSidebarListener::class); $context->registerEventListener(ShareCreatedEvent::class, ShareInteractionListener::class); @@ -95,6 +97,9 @@ class Application extends App implements IBootstrap { // Handle download events for view only checks $context->registerEventListener(BeforeZipCreatedEvent::class, BeforeZipCreatedListener::class); $context->registerEventListener(BeforeDirectFileDownloadEvent::class, BeforeDirectFileDownloadListener::class); + + // File request auth + $context->registerEventListener(BeforeTemplateRenderedEvent::class, LoadPublicFileRequestAuthListener::class); } public function boot(IBootContext $context): void { diff --git a/apps/files_sharing/lib/DefaultPublicShareTemplateProvider.php b/apps/files_sharing/lib/DefaultPublicShareTemplateProvider.php index e125100eb68..477bc9f82ce 100644 --- a/apps/files_sharing/lib/DefaultPublicShareTemplateProvider.php +++ b/apps/files_sharing/lib/DefaultPublicShareTemplateProvider.php @@ -19,6 +19,7 @@ use OCP\AppFramework\Http\Template\LinkMenuAction; use OCP\AppFramework\Http\Template\PublicTemplateResponse; use OCP\AppFramework\Http\Template\SimpleMenuAction; use OCP\AppFramework\Http\TemplateResponse; +use OCP\AppFramework\Services\IInitialState; use OCP\Constants; use OCP\Defaults; use OCP\EventDispatcher\IEventDispatcher; @@ -37,39 +38,20 @@ use OCP\Template; use OCP\Util; class DefaultPublicShareTemplateProvider implements IPublicShareTemplateProvider { - private IUserManager $userManager; - private IAccountManager $accountManager; - private IPreview $previewManager; - protected FederatedShareProvider $federatedShareProvider; - private IURLGenerator $urlGenerator; - private IEventDispatcher $eventDispatcher; - private IL10N $l10n; - private Defaults $defaults; - private IConfig $config; - private IRequest $request; public function __construct( - IUserManager $userManager, - IAccountManager $accountManager, - IPreview $previewManager, - FederatedShareProvider $federatedShareProvider, - IUrlGenerator $urlGenerator, - IEventDispatcher $eventDispatcher, - IL10N $l10n, - Defaults $defaults, - IConfig $config, - IRequest $request + private IUserManager $userManager, + private IAccountManager $accountManager, + private IPreview $previewManager, + protected FederatedShareProvider $federatedShareProvider, + private IUrlGenerator $urlGenerator, + private IEventDispatcher $eventDispatcher, + private IL10N $l10n, + private Defaults $defaults, + private IConfig $config, + private IRequest $request, + private IInitialState $initialState, ) { - $this->userManager = $userManager; - $this->accountManager = $accountManager; - $this->previewManager = $previewManager; - $this->federatedShareProvider = $federatedShareProvider; - $this->urlGenerator = $urlGenerator; - $this->eventDispatcher = $eventDispatcher; - $this->l10n = $l10n; - $this->defaults = $defaults; - $this->config = $config; - $this->request = $request; } public function shouldRespond(IShare $share): bool { @@ -91,9 +73,16 @@ class DefaultPublicShareTemplateProvider implements IPublicShareTemplateProvider if ($ownerName->getScope() === IAccountManager::SCOPE_PUBLISHED) { $shareTmpl['owner'] = $owner->getUID(); $shareTmpl['shareOwner'] = $owner->getDisplayName(); + $this->initialState->provideInitialState('owner', $shareTmpl['owner']); + $this->initialState->provideInitialState('ownerDisplayName', $shareTmpl['shareOwner']); } } + // Provide initial state + $this->initialState->provideInitialState('label', $share->getLabel()); + $this->initialState->provideInitialState('note', $share->getNote()); + $this->initialState->provideInitialState('filename', $shareNode->getName()); + $shareTmpl['filename'] = $shareNode->getName(); $shareTmpl['directory_path'] = $share->getTarget(); $shareTmpl['label'] = $share->getLabel(); diff --git a/apps/files_sharing/lib/Listener/LoadPublicFileRequestAuthListener.php b/apps/files_sharing/lib/Listener/LoadPublicFileRequestAuthListener.php new file mode 100644 index 00000000000..f1e054c7ee5 --- /dev/null +++ b/apps/files_sharing/lib/Listener/LoadPublicFileRequestAuthListener.php @@ -0,0 +1,59 @@ +<?php + +declare(strict_types=1); +/** + * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +namespace OCA\Files_Sharing\Listener; + +use OCA\Files_Sharing\AppInfo\Application; +use OCP\AppFramework\Http\Events\BeforeTemplateRenderedEvent; +use OCP\AppFramework\Http\TemplateResponse; +use OCP\EventDispatcher\Event; +use OCP\EventDispatcher\IEventListener; +use OCP\Share\IManager; +use OCP\Util; + +/** @template-implements IEventListener<BeforeTemplateRenderedEvent> */ +class LoadPublicFileRequestAuthListener implements IEventListener { + public function __construct( + private IManager $shareManager, + ) { + } + + public function handle(Event $event): void { + if (!$event instanceof BeforeTemplateRenderedEvent) { + return; + } + + // Make sure we are on a public page rendering + if ($event->getResponse()->getRenderAs() !== TemplateResponse::RENDER_AS_PUBLIC) { + return; + } + + $token = $event->getResponse()->getParams()['sharingToken'] ?? null; + if ($token === null || $token === '') { + return; + } + + // Check if the share is a file request + $isFileRequest = false; + try { + $share = $this->shareManager->getShareByToken($token); + $attributes = $share->getAttributes(); + if ($attributes === null) { + return; + } + + $isFileRequest = $attributes->getAttribute('fileRequest', 'enabled') === true; + } catch (\Exception $e) { + // Ignore, this is not a file request or the share does not exist + } + + if ($isFileRequest) { + // Add the script to the public page + Util::addScript(Application::APP_ID, 'public-file-request'); + } + } +} diff --git a/apps/files_sharing/src/components/NewFileRequestDialog.vue b/apps/files_sharing/src/components/NewFileRequestDialog.vue index 398fd976f02..4c476af9bc8 100644 --- a/apps/files_sharing/src/components/NewFileRequestDialog.vue +++ b/apps/files_sharing/src/components/NewFileRequestDialog.vue @@ -107,7 +107,7 @@ @click="onFinish"> <template #icon> <NcLoadingIcon v-if="loading" /> - <IconCheck v-else-if="success" :size="20" /> + <IconCheck v-else :size="20" /> </template> {{ finishButtonLabel }} </NcButton> @@ -193,7 +193,6 @@ export default defineComponent({ return { currentStep: STEP.FIRST, loading: false, - success: false, destination: this.context.path || '/', label: '', @@ -264,11 +263,7 @@ export default defineComponent({ showSuccess(t('files_sharing', 'File request created')) } - // Show success then close - this.success = true - setTimeout(() => { - this.$emit('close') - }, 3000) + this.$emit('close') }, async createShare() { @@ -343,6 +338,11 @@ export default defineComponent({ value: this.emails, key: 'emails', scope: 'shareWith', + }, + { + value: true, + key: 'enabled', + scope: 'fileRequest', }]), }) diff --git a/apps/files_sharing/src/public-file-request.ts b/apps/files_sharing/src/public-file-request.ts new file mode 100644 index 00000000000..763c4f60624 --- /dev/null +++ b/apps/files_sharing/src/public-file-request.ts @@ -0,0 +1,23 @@ +/** + * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +import { spawnDialog } from '@nextcloud/dialogs' +import { defineAsyncComponent } from 'vue' +import logger from './services/logger' + +const nick = localStorage.getItem('nick') +const publicAuthPromptShown = localStorage.getItem('publicAuthPromptShown') + +// If we don't have a nickname or the public auth prompt hasn't been shown yet, show it +// We still show the prompt if the user has a nickname to double check +if (!nick || !publicAuthPromptShown) { + spawnDialog( + defineAsyncComponent(() => import('./views/PublicAuthPrompt.vue')), + {}, + () => localStorage.setItem('publicAuthPromptShown', 'true'), + ) +} else { + logger.debug(`Public auth prompt already shown. Current nickname is '${nick}'`) +} diff --git a/apps/files_sharing/src/views/PublicAuthPrompt.vue b/apps/files_sharing/src/views/PublicAuthPrompt.vue new file mode 100644 index 00000000000..a929afffefb --- /dev/null +++ b/apps/files_sharing/src/views/PublicAuthPrompt.vue @@ -0,0 +1,136 @@ +<!-- + - SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors + - SPDX-License-Identifier: AGPL-3.0-or-later +--> + +<template> + <NcDialog class="public-auth-prompt" + dialog-classes="public-auth-prompt__dialog" + :can-close="false" + :name="dialogName"> + <h3 v-if="owner" class="public-auth-prompt__subtitle"> + {{ t('files_sharing', '{ownerDisplayName} shared a folder with you.', { ownerDisplayName }) }} + </h3> + + <!-- Header --> + <NcNoteCard type="info" class="public-auth-prompt__header"> + <p id="public-auth-prompt-dialog-description" class="public-auth-prompt__description"> + {{ t('files_sharing', 'To upload files, you need to provide your name first.') }} + </p> + </NcNoteCard> + + <!-- Form --> + <form ref="form" + aria-describedby="public-auth-prompt-dialog-description" + class="public-auth-prompt__form" + @submit.prevent.stop=""> + <NcTextField ref="input" + class="public-auth-prompt__input" + :label="t('files_sharing', 'Enter your name')" + name="name" + :required="true" + :minlength="2" + :value.sync="name" /> + </form> + + <!-- Submit --> + <template #actions> + <NcButton ref="submit" + :disabled="name.trim() === ''" + @click="onSubmit"> + {{ t('files_sharing', 'Submit name') }} + </NcButton> + </template> + </NcDialog> +</template> + +<script lang="ts"> +import { defineComponent } from 'vue' +import { t } from '@nextcloud/l10n' + +import NcButton from '@nextcloud/vue/dist/Components/NcButton.js' +import NcDialog from '@nextcloud/vue/dist/Components/NcDialog.js' +import NcNoteCard from '@nextcloud/vue/dist/Components/NcNoteCard.js' +import NcTextField from '@nextcloud/vue/dist/Components/NcTextField.js' +import { loadState } from '@nextcloud/initial-state' + +export default defineComponent({ + name: 'PublicAuthPrompt', + + components: { + NcButton, + NcDialog, + NcNoteCard, + NcTextField, + }, + + setup() { + return { + t, + + owner: loadState('files_sharing', 'owner', ''), + ownerDisplayName: loadState('files_sharing', 'ownerDisplayName', ''), + label: loadState('files_sharing', 'label', ''), + note: loadState('files_sharing', 'note', ''), + filename: loadState('files_sharing', 'filename', ''), + } + }, + + data() { + return { + name: '', + } + }, + + computed: { + dialogName() { + return this.t('files_sharing', 'Upload files to {folder}', { folder: this.label || this.filename }) + }, + }, + + beforeMount() { + // Pre-load the name from local storage if already set by another app + // like Talk, Colabora or Text... + const talkNick = localStorage.getItem('nick') + if (talkNick) { + this.name = talkNick + } + }, + + methods: { + onSubmit() { + const form = this.$refs.form as HTMLFormElement + if (!form.checkValidity()) { + form.reportValidity() + return + } + + if (this.name.trim() === '') { + return + } + + localStorage.setItem('nick', this.name) + this.$emit('close') + }, + }, +}) +</script> +<style lang="scss"> +.public-auth-prompt { + &__subtitle { + // Smaller than dialog title + font-size: 16px; + margin-block: 12px; + } + + &__header { + // Fix extra margin generating an unwanted gap + margin-block: 12px; + } + + &__form { + // Double the margin of the header + margin-block: 24px; + } +} +</style> diff --git a/apps/files_sharing/templates/public.php b/apps/files_sharing/templates/public.php index 109eaf2e9da..7620d309ff6 100644 --- a/apps/files_sharing/templates/public.php +++ b/apps/files_sharing/templates/public.php @@ -27,6 +27,7 @@ <input type="hidden" name="mimetypeIcon" value="<?php p(\OC::$server->getMimeTypeDetector()->mimeTypeIcon($_['mimetype'])); ?>" id="mimetypeIcon"> <input type="hidden" name="hideDownload" value="<?php p($_['hideDownload'] ? 'true' : 'false'); ?>" id="hideDownload"> <input type="hidden" id="disclaimerText" value="<?php p($_['disclaimer']) ?>"> + <?php $upload_max_filesize = OC::$server->get(\bantu\IniGetWrapper\IniGetWrapper::class)->getBytes('upload_max_filesize'); $post_max_size = OC::$server->get(\bantu\IniGetWrapper\IniGetWrapper::class)->getBytes('post_max_size'); @@ -102,14 +103,11 @@ $maxUploadFilesize = min($upload_max_filesize, $post_max_size); class="emptycontent <?php if (!empty($_['note'])) { ?>has-note<?php } ?>"> <?php if ($_['shareOwner']) { ?> <div id="displayavatar"><div class="avatardiv"></div></div> - <h2><?php p($l->t('Upload files to %s', [$_['shareOwner']])) ?></h2> - <p><span class="icon-folder"></span> <?php p($_['filename']) ?></p> - <?php } else if ($_['label']) { ?> - <div id="displayavatar"><span class="icon-folder"></span></div> - <h2><?php p($l->t('Upload files to %s', [$_['label']])) ?></h2> - <?php } else{ ?> + <h2><?php p($l->t('Upload files to %s', [$_['label'] ?: $_['filename']])) ?></h2> + <p><?php p($l->t('%s shared a folder with you.', [$_['shareOwner']])) ?></p> + <?php } else { ?> <div id="displayavatar"><span class="icon-folder"></span></div> - <h2><?php p($l->t('Upload files to %s', [$_['filename']])) ?></h2> + <h2><?php p($l->t('Upload files to %s', [$_['label'] ?: $_['filename']])) ?></h2> <?php } ?> <?php if (empty($_['note']) === false) { ?> diff --git a/apps/files_sharing/tests/Controller/ShareControllerTest.php b/apps/files_sharing/tests/Controller/ShareControllerTest.php index 493ac10a24b..79b90d8a156 100644 --- a/apps/files_sharing/tests/Controller/ShareControllerTest.php +++ b/apps/files_sharing/tests/Controller/ShareControllerTest.php @@ -22,6 +22,7 @@ use OCP\AppFramework\Http\Template\ExternalShareMenuAction; use OCP\AppFramework\Http\Template\LinkMenuAction; use OCP\AppFramework\Http\Template\PublicTemplateResponse; use OCP\AppFramework\Http\Template\SimpleMenuAction; +use OCP\AppFramework\Services\IInitialState; use OCP\Constants; use OCP\Defaults; use OCP\EventDispatcher\IEventDispatcher; @@ -121,6 +122,7 @@ class ShareControllerTest extends \Test\TestCase { $this->defaults, $this->config, $this->createMock(IRequest::class), + $this->createMock(IInitialState::class) ) ); @@ -350,7 +352,8 @@ class ShareControllerTest extends \Test\TestCase { 'previewURL' => 'downloadURL', 'note' => $note, 'hideDownload' => false, - 'showgridview' => false + 'showgridview' => false, + 'label' => '' ]; $csp = new \OCP\AppFramework\Http\ContentSecurityPolicy(); @@ -511,7 +514,8 @@ class ShareControllerTest extends \Test\TestCase { 'previewURL' => 'downloadURL', 'note' => $note, 'hideDownload' => false, - 'showgridview' => false + 'showgridview' => false, + 'label' => '' ]; $csp = new \OCP\AppFramework\Http\ContentSecurityPolicy(); @@ -672,7 +676,8 @@ class ShareControllerTest extends \Test\TestCase { 'previewURL' => 'downloadURL', 'note' => $note, 'hideDownload' => true, - 'showgridview' => false + 'showgridview' => false, + 'label' => '' ]; $csp = new \OCP\AppFramework\Http\ContentSecurityPolicy(); @@ -798,7 +803,8 @@ class ShareControllerTest extends \Test\TestCase { 'previewURL' => '', 'note' => '', 'hideDownload' => false, - 'showgridview' => false + 'showgridview' => false, + 'label' => '' ]; $csp = new \OCP\AppFramework\Http\ContentSecurityPolicy(); diff --git a/webpack.modules.js b/webpack.modules.js index d13ad284bab..887d8dc75a0 100644 --- a/webpack.modules.js +++ b/webpack.modules.js @@ -54,6 +54,7 @@ module.exports = { init: path.join(__dirname, 'apps/files_sharing/src', 'init.ts'), main: path.join(__dirname, 'apps/files_sharing/src', 'main.ts'), 'personal-settings': path.join(__dirname, 'apps/files_sharing/src', 'personal-settings.js'), + 'public-file-request': path.join(__dirname, 'apps/files_sharing/src', 'public-file-request.ts'), }, files_trashbin: { init: path.join(__dirname, 'apps/files_trashbin/src', 'files-init.ts'), |