diff options
22 files changed, 160 insertions, 34 deletions
diff --git a/build/integration/features/bootstrap/BasicStructure.php b/build/integration/features/bootstrap/BasicStructure.php index 8e1fcf86ba1..8961efc6f31 100644 --- a/build/integration/features/bootstrap/BasicStructure.php +++ b/build/integration/features/bootstrap/BasicStructure.php @@ -353,6 +353,30 @@ trait BasicStructure { fclose($file); } + public function createFileWithText($name, $text){ + $file = fopen("work/" . "$name", 'w'); + fwrite($file, $text); + fclose($file); + } + + /** + * @Given file :filename of size :size is created in local storage + * @param string $filename + * @param string $size + */ + public function fileIsCreatedInLocalStorageWithSize($filename, $size) { + $this->createFileSpecificSize("local_storage/$filename", $size); + } + + /** + * @Given file :filename with text :text is created in local storage + * @param string $filename + * @param string $text + */ + public function fileIsCreatedInLocalStorageWithText($filename, $text) { + $this->createFileWithText("local_storage/$filename", $text); + } + /** * @When User :user empties trashbin * @param string $user diff --git a/build/integration/features/bootstrap/WebDav.php b/build/integration/features/bootstrap/WebDav.php index 680d8f96e7c..0a75ff96732 100644 --- a/build/integration/features/bootstrap/WebDav.php +++ b/build/integration/features/bootstrap/WebDav.php @@ -729,4 +729,23 @@ trait WebDav { } } + /** + * @When /^User "([^"]*)" deletes everything from folder "([^"]*)"$/ + * @param string $user + * @param string $folder + */ + public function userDeletesEverythingInFolder($user, $folder) { + $elementList = $this->listFolder($user, $folder, 1); + $elementListKeys = array_keys($elementList); + array_shift($elementListKeys); + $davPrefix = "/" . $this->getDavFilesPath($user); + foreach($elementListKeys as $element) { + if (substr($element, 0, strlen($davPrefix)) == $davPrefix) { + $element = substr($element, strlen($davPrefix)); + } + $this->userDeletesFile($user, "element", $element); + } + } + + } diff --git a/build/integration/features/webdav-related.feature b/build/integration/features/webdav-related.feature index c3aa6145527..775bf2ca882 100644 --- a/build/integration/features/webdav-related.feature +++ b/build/integration/features/webdav-related.feature @@ -479,3 +479,41 @@ Feature: webdav-related When as "user0" gets properties of folder "/test_folder:5" with |{DAV:}resourcetype| Then the single response should contain a property "{DAV:}resourcetype" with value "{DAV:}collection" + + Scenario: Removing everything of a folder + Given using old dav path + And As an "admin" + And user "user0" exists + And As an "user0" + And User "user0" moves file "/welcome.txt" to "/FOLDER/welcome.txt" + And user "user0" created a folder "/FOLDER/SUBFOLDER" + And User "user0" copies file "/textfile0.txt" to "/FOLDER/SUBFOLDER/testfile0.txt" + When User "user0" deletes everything from folder "/FOLDER/" + Then user "user0" should see following elements + | /FOLDER/ | + | /PARENT/ | + | /PARENT/parent.txt | + | /textfile0.txt | + | /textfile1.txt | + | /textfile2.txt | + | /textfile3.txt | + | /textfile4.txt | + + Scenario: Removing everything of a folder using new dav path + Given using new dav path + And As an "admin" + And user "user0" exists + And As an "user0" + And User "user0" moves file "/welcome.txt" to "/FOLDER/welcome.txt" + And user "user0" created a folder "/FOLDER/SUBFOLDER" + And User "user0" copies file "/textfile0.txt" to "/FOLDER/SUBFOLDER/testfile0.txt" + When User "user0" deletes everything from folder "/FOLDER/" + Then user "user0" should see following elements + | /FOLDER/ | + | /PARENT/ | + | /PARENT/parent.txt | + | /textfile0.txt | + | /textfile1.txt | + | /textfile2.txt | + | /textfile3.txt | + | /textfile4.txt | diff --git a/core/Command/Encryption/EncryptAll.php b/core/Command/Encryption/EncryptAll.php index 3a0c88c0798..584bc8a70c7 100644 --- a/core/Command/Encryption/EncryptAll.php +++ b/core/Command/Encryption/EncryptAll.php @@ -109,10 +109,10 @@ class EncryptAll extends Command { } $output->writeln("\n"); - $output->writeln('You are about to start to encrypt all files stored in your ownCloud.'); - $output->writeln('It will depend on the encryption module you use which files get encrypted.'); - $output->writeln('Depending on the number and size of your files this can take some time'); - $output->writeln('Please make sure that no user access his files during this process!'); + $output->writeln('You are about to encrypt all files stored in your Nextcloud installation.'); + $output->writeln('Depending on the number of available files, and their size, this may take quite some time.'); + $output->writeln('Please ensure that no user accesses their files during this time!'); + $output->writeln('Note: The encryption module you use determines which files get encrypted.'); $output->writeln(''); $question = new ConfirmationQuestion('Do you really want to continue? (y/n) ', false); if ($this->questionHelper->ask($input, $output, $question)) { diff --git a/core/Command/User/ResetPassword.php b/core/Command/User/ResetPassword.php index 3388ef6a1bd..56260e9714a 100644 --- a/core/Command/User/ResetPassword.php +++ b/core/Command/User/ResetPassword.php @@ -100,6 +100,11 @@ class ResetPassword extends Command { $question->setHidden(true); $password = $helper->ask($input, $output, $question); + if ($password === null) { + $output->writeln("<error>Password cannot be empty!</error>"); + return 1; + } + $question = new Question('Confirm the new password: '); $question->setHidden(true); $confirm = $helper->ask($input, $output, $question); diff --git a/core/css/header.scss b/core/css/header.scss index 2f0c1522b0b..b158f8b6660 100644 --- a/core/css/header.scss +++ b/core/css/header.scss @@ -324,7 +324,7 @@ nav { } /* Apps management */ -#apps-management { +.apps-management { min-height: initial; height: initial; margin: 0; @@ -399,7 +399,6 @@ nav { /* Profile picture in header */ .avatardiv { - margin-right: 8px; cursor: pointer; height: 32px; width: 32px; @@ -458,9 +457,6 @@ nav { .avatardiv.avatardiv-shown + #expandDisplayName { display: none; } - #expand { - display: block; - } } #appmenu { diff --git a/core/js/sharedialogview.js b/core/js/sharedialogview.js index 58dd706fb1f..47471955563 100644 --- a/core/js/sharedialogview.js +++ b/core/js/sharedialogview.js @@ -120,6 +120,8 @@ '_onSelectRecipient', 'onShareWithFieldChanged' ); + + OC.Plugins.attach('OCA.Share.ShareDialogView', this); }, onShareWithFieldChanged: function() { diff --git a/core/js/tests/specHelper.js b/core/js/tests/specHelper.js index f9bdeae0d64..7897a2f2842 100644 --- a/core/js/tests/specHelper.js +++ b/core/js/tests/specHelper.js @@ -177,6 +177,10 @@ window.isPhantom = /phantom/i.test(navigator.userAgent); delete($.fn.select2); ajaxErrorStub.restore(); + + // reset pop state handlers + OC.Util.History._handlers = []; + }); })(); diff --git a/core/templates/layout.user.php b/core/templates/layout.user.php index 3cfb88bf423..dad5ee1b826 100644 --- a/core/templates/layout.user.php +++ b/core/templates/layout.user.php @@ -81,7 +81,7 @@ </a> </li> <?php if(OC_User::isAdminUser(OC_User::getUser())): ?> - <li id="apps-management" <?php if(count($_['navigation'])>$headerIconCount-1): ?>class="hidden"<?php endif; ?>> + <li <?php if(count($_['navigation'])>$headerIconCount-1): ?> class="hidden apps-management"<?php else: ?> class="apps-management" <?php endif; ?>> <a href="<?php print_unescaped(\OC::$server->getURLGenerator()->linkToRoute('settings.AppSettings.viewApps')); ?>" tabindex="4" <?php if( $_['appsmanagement_active'] ): ?> class="active"<?php endif; ?>> <img src="<?php print_unescaped(image_path('settings', 'apps.svg') . '?v=' . $_['versionHash']); ?>" /> @@ -119,7 +119,7 @@ /* show "More apps" link to app administration directly in app navigation, as last entry */ if(OC_User::isAdminUser(OC_User::getUser())): ?> - <li id="apps-management"> + <li class="apps-management"> <a href="<?php print_unescaped(\OC::$server->getURLGenerator()->linkToRoute('settings.AppSettings.viewApps')); ?>" tabindex="4" <?php if( $_['appsmanagement_active'] ): ?> class="active"<?php endif; ?>> <svg width="32" height="32" viewBox="0 0 32 32" class="app-icon"> diff --git a/lib/private/App/AppManager.php b/lib/private/App/AppManager.php index 6b819ef7ac1..6c1f5ba6940 100644 --- a/lib/private/App/AppManager.php +++ b/lib/private/App/AppManager.php @@ -32,6 +32,7 @@ namespace OC\App; use OCP\App\AppPathNotFoundException; +use OC_App; use OCP\App\IAppManager; use OCP\App\ManagerEvent; use OCP\IAppConfig; @@ -210,8 +211,12 @@ class AppManager implements IAppManager { * Enable an app for every user * * @param string $appId + * @throws \Exception */ public function enableApp($appId) { + if(OC_App::getAppPath($appId) === false) { + throw new \Exception("$appId can't be enabled since it is not installed."); + } $this->installedAppsCache[$appId] = 'yes'; $this->appConfig->setValue($appId, 'enabled', 'yes'); $this->dispatcher->dispatch(ManagerEvent::EVENT_APP_ENABLE, new ManagerEvent( diff --git a/lib/private/Authentication/Token/DefaultTokenProvider.php b/lib/private/Authentication/Token/DefaultTokenProvider.php index 0e1196a9da4..6fd85295e03 100644 --- a/lib/private/Authentication/Token/DefaultTokenProvider.php +++ b/lib/private/Authentication/Token/DefaultTokenProvider.php @@ -253,10 +253,10 @@ class DefaultTokenProvider implements IProvider { */ public function invalidateOldTokens() { $olderThan = $this->time->getTime() - (int) $this->config->getSystemValue('session_lifetime', 60 * 60 * 24); - $this->logger->debug('Invalidating session tokens older than ' . date('c', $olderThan)); + $this->logger->debug('Invalidating session tokens older than ' . date('c', $olderThan), ['app' => 'cron']); $this->mapper->invalidateOld($olderThan, IToken::DO_NOT_REMEMBER); $rememberThreshold = $this->time->getTime() - (int) $this->config->getSystemValue('remember_login_cookie_lifetime', 60 * 60 * 24 * 15); - $this->logger->debug('Invalidating remembered session tokens older than ' . date('c', $rememberThreshold)); + $this->logger->debug('Invalidating remembered session tokens older than ' . date('c', $rememberThreshold), ['app' => 'cron']); $this->mapper->invalidateOld($rememberThreshold, IToken::REMEMBER); } diff --git a/lib/private/Console/Application.php b/lib/private/Console/Application.php index 7d2f03d593e..693381ea2b4 100644 --- a/lib/private/Console/Application.php +++ b/lib/private/Console/Application.php @@ -37,6 +37,7 @@ use Symfony\Component\Console\Application as SymfonyApplication; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Output\ConsoleOutputInterface; use Symfony\Component\EventDispatcher\EventDispatcherInterface; class Application { @@ -97,7 +98,8 @@ class Application { throw new NeedsUpdateException(); } elseif ($this->config->getSystemValue('maintenance', false)) { if ($input->getArgument('command') !== '_completion') { - $output->writeln("Nextcloud is in maintenance mode - no apps have been loaded"); + $errOutput = $output->getErrorOutput(); + $errOutput->writeln('<comment>Nextcloud is in maintenance mode - no app have been loaded</comment>' . PHP_EOL); } } else { OC_App::loadApps(); diff --git a/lib/private/SystemTag/SystemTagManager.php b/lib/private/SystemTag/SystemTagManager.php index 7c21c0e004e..d0854e885eb 100644 --- a/lib/private/SystemTag/SystemTagManager.php +++ b/lib/private/SystemTag/SystemTagManager.php @@ -400,6 +400,9 @@ class SystemTagManager implements ISystemTagManager { 'gid' => $query->createParameter('gid'), ]); foreach ($groupIds as $groupId) { + if ($groupId === '') { + continue; + } $query->setParameter('gid', $groupId); $query->execute(); } diff --git a/lib/private/Template/ResourceLocator.php b/lib/private/Template/ResourceLocator.php index 9015bf5d97c..e82a77ba65f 100755 --- a/lib/private/Template/ResourceLocator.php +++ b/lib/private/Template/ResourceLocator.php @@ -84,7 +84,7 @@ abstract class ResourceLocator { $this->doFindTheme($resource); } catch (ResourceNotFoundException $e) { $resourceApp = substr($resource, 0, strpos($resource, '/')); - $this->logger->debug('Could not find resource file "' . $e->getResourcePath() . '"', ['app' => $resourceApp]); + $this->logger->debug('Could not find resource file in theme "' . $e->getResourcePath() . '"', ['app' => $resourceApp]); } } } diff --git a/lib/private/User/Session.php b/lib/private/User/Session.php index c03cbd5891b..4980318b554 100644 --- a/lib/private/User/Session.php +++ b/lib/private/User/Session.php @@ -14,6 +14,7 @@ * @author Robin McCorkell <robin@mccorkell.me.uk> * @author Thomas Müller <thomas.mueller@tmit.eu> * @author Vincent Petry <pvince81@owncloud.com> + * @author Felix Rupp <kontakt@felixrupp.com> * * @license AGPL-3.0 * @@ -70,6 +71,7 @@ use Symfony\Component\EventDispatcher\GenericEvent; * - preRememberedLogin(string $uid) * - postRememberedLogin(\OC\User\User $user) * - logout() + * - postLogout() * * @package OC\User */ @@ -796,6 +798,7 @@ class Session implements IUserSession, Emitter { $this->setToken(null); $this->unsetMagicInCookie(); $this->session->clear(); + $this->manager->emit('\OC\User', 'postLogout'); } /** diff --git a/lib/private/legacy/files.php b/lib/private/legacy/files.php index ed3aa719409..017691805c9 100644 --- a/lib/private/legacy/files.php +++ b/lib/private/legacy/files.php @@ -264,12 +264,12 @@ class OC_Files { if (\OC\Files\Filesystem::isReadable($filename)) { self::sendHeaders($filename, $name, $rangeArray); } elseif (!\OC\Files\Filesystem::file_exists($filename)) { - header("HTTP/1.0 404 Not Found"); + header("HTTP/1.1 404 Not Found"); $tmpl = new OC_Template('', '404', 'guest'); $tmpl->printPage(); exit(); } else { - header("HTTP/1.0 403 Forbidden"); + header("HTTP/1.1 403 Forbidden"); die('403 Forbidden'); } if (isset($params['head']) && $params['head']) { diff --git a/settings/js/apps.js b/settings/js/apps.js index 8be18c4e9c0..d2f26578a7c 100644 --- a/settings/js/apps.js +++ b/settings/js/apps.js @@ -541,10 +541,10 @@ OC.Settings.Apps = OC.Settings.Apps || { if (navEntries.length > 7) { $('#more-apps').show(); - $('#apps-management').hide(); + $('.apps-management').hide(); } else { $('#more-apps').hide(); - $('#apps-management').show(); + $('.apps-management').show(); } } }); diff --git a/settings/js/personal.js b/settings/js/personal.js index 89491b96657..52ab2f23f87 100644 --- a/settings/js/personal.js +++ b/settings/js/personal.js @@ -20,7 +20,8 @@ OC.Settings = OC.Settings || {}; jQuery.fn.keyUpDelayedOrEnter = function (callback, allowEmptyValue) { var cb = callback; var that = this; - this.keyup(_.debounce(function (event) { + + this.on('input', _.debounce(function (event) { // enter is already handled in keypress if (event.keyCode === 13) { return; @@ -36,14 +37,6 @@ jQuery.fn.keyUpDelayedOrEnter = function (callback, allowEmptyValue) { cb(event); } }); - - this.bind('paste', null, function (event) { - if(!event.keyCode){ - if (allowEmptyValue || that.val() !== '') { - cb(event); - } - } - }); }; function updateAvatar (hidedefault) { diff --git a/settings/personal.php b/settings/personal.php index a1fcd10e0ad..a4449754f64 100644 --- a/settings/personal.php +++ b/settings/personal.php @@ -158,6 +158,7 @@ $userData = $accountManager->getUser($user); $tmpl->assign('total_space', $totalSpace); $tmpl->assign('usage_relative', $storageInfo['relative']); +$tmpl->assign('quota', $storageInfo['quota']); $tmpl->assign('clients', $clients); $tmpl->assign('email', $userData[\OC\Accounts\AccountManager::PROPERTY_EMAIL]['value']); $tmpl->assign('languages', $languages); diff --git a/settings/templates/personal.php b/settings/templates/personal.php index 31aa268f776..b47e2e28ffa 100644 --- a/settings/templates/personal.php +++ b/settings/templates/personal.php @@ -28,8 +28,13 @@ <div style="width:<?php p($_['usage_relative']);?>%" <?php if($_['usage_relative'] > 80): ?> class="quota-warning" <?php endif; ?>> <p id="quotatext"> - <?php print_unescaped($l->t('You are using <strong>%s</strong> of <strong>%s</strong>', - array($_['usage'], $_['total_space'])));?> + <?php if ($_['quota'] === \OCP\Files\FileInfo::SPACE_UNLIMITED): ?> + <?php print_unescaped($l->t('You are using <strong>%s</strong> of <strong>%s</strong>', + [$_['usage'], $_['total_space']]));?> + <?php else: ?> + <?php print_unescaped($l->t('You are using <strong>%s</strong> of <strong>%s</strong> (<strong>%s %%</strong>)', + [$_['usage'], $_['total_space'], $_['usage_relative']]));?> + <?php endif ?> </p> </div> </div> diff --git a/tests/lib/App/ManagerTest.php b/tests/lib/App/ManagerTest.php index e38f72b3d92..8b23168938c 100644 --- a/tests/lib/App/ManagerTest.php +++ b/tests/lib/App/ManagerTest.php @@ -116,16 +116,33 @@ class ManagerTest extends TestCase { public function testEnableApp() { $this->expectClearCache(); - $this->manager->enableApp('test'); - $this->assertEquals('yes', $this->appConfig->getValue('test', 'enabled', 'no')); + // making sure "files_trashbin" is disabled + if ($this->manager->isEnabledForUser('files_trashbin')) { + $this->manager->disableApp('files_trashbin'); + } + $this->manager->enableApp('files_trashbin'); + $this->assertEquals('yes', $this->appConfig->getValue('files_trashbin', 'enabled', 'no')); } public function testDisableApp() { $this->expectClearCache(); - $this->manager->disableApp('test'); - $this->assertEquals('no', $this->appConfig->getValue('test', 'enabled', 'no')); + $this->manager->disableApp('files_trashbin'); + $this->assertEquals('no', $this->appConfig->getValue('files_trashbin', 'enabled', 'no')); } + public function testNotEnableIfNotInstalled() { + try { + $this->manager->enableApp('some_random_name_which_i_hope_is_not_an_app'); + $this->assertFalse(true, 'If this line is reached the expected exception is not thrown.'); + } catch (\Exception $e) { + // excpetion is expected + $this->assertEquals("some_random_name_which_i_hope_is_not_an_app can't be enabled since it is not installed.", $e->getMessage()); + } + $this->assertEquals('no', $this->appConfig->getValue( + 'some_random_name_which_i_hope_is_not_an_app', 'enabled', 'no' + )); + } + public function testEnableAppForGroups() { $groups = array( new Group('group1', array(), null), diff --git a/tests/lib/SystemTag/SystemTagManagerTest.php b/tests/lib/SystemTag/SystemTagManagerTest.php index e697e373465..61fac99ca6c 100644 --- a/tests/lib/SystemTag/SystemTagManagerTest.php +++ b/tests/lib/SystemTag/SystemTagManagerTest.php @@ -517,6 +517,15 @@ class SystemTagManagerTest extends TestCase { } /** + * empty groupIds should be ignored + */ + public function testEmptyTagGroup() { + $tag1 = $this->tagManager->createTag('tag1', true, false); + $this->tagManager->setTagGroups($tag1, ['']); + $this->assertEquals([], $this->tagManager->getTagGroups($tag1)); + } + + /** * @param ISystemTag $tag1 * @param ISystemTag $tag2 */ |