diff options
22 files changed, 459 insertions, 92 deletions
diff --git a/.drone.yml b/.drone.yml index d5fdcdd746b..6174937ad24 100644 --- a/.drone.yml +++ b/.drone.yml @@ -338,6 +338,15 @@ pipeline: when: matrix: TESTS: integration-setup-features + integration-filesdrop-features: + image: nextcloudci/integration-php7.0:integration-php7.0-2 + commands: + - ./occ maintenance:install --admin-pass=admin + - cd build/integration + - ./run.sh filesdrop_features/filesdrop.feature + when: + matrix: + TESTS: integration-filesdrop-features nodb-codecov: image: nextcloudci/php7.0:php7.0-6 commands: @@ -382,6 +391,7 @@ matrix: - TESTS: integration-webdav-related - TESTS: integration-sharees-features - TESTS: integration-setup-features + - TESTS: integration-filesdrop-features - TESTS: jsunit - TESTS: check-autoloader - TESTS: app-check-code diff --git a/apps/dav/lib/Files/Sharing/FilesDropPlugin.php b/apps/dav/lib/Files/Sharing/FilesDropPlugin.php index 299427b1634..3485df09d0f 100644 --- a/apps/dav/lib/Files/Sharing/FilesDropPlugin.php +++ b/apps/dav/lib/Files/Sharing/FilesDropPlugin.php @@ -23,6 +23,7 @@ namespace OCA\DAV\Files\Sharing; use OC\Files\View; +use Sabre\DAV\Exception\MethodNotAllowed; use Sabre\DAV\ServerPlugin; use Sabre\HTTP\RequestInterface; use Sabre\HTTP\ResponseInterface; @@ -56,6 +57,7 @@ class FilesDropPlugin extends ServerPlugin { * @param \Sabre\DAV\Server $server Sabre server * * @return void + * @throws MethodNotAllowed */ public function initialize(\Sabre\DAV\Server $server) { $server->on('beforeMethod', [$this, 'beforeMethod'], 999); @@ -64,31 +66,19 @@ class FilesDropPlugin extends ServerPlugin { public function beforeMethod(RequestInterface $request, ResponseInterface $response){ - if (!$this->enabled || $request->getMethod() !== 'PUT') { + if (!$this->enabled) { return; } - $path = $request->getPath(); - - if ($this->view->file_exists($path)) { - $newName = \OC_Helper::buildNotExistingFileNameForView('/', $path, $this->view); - - $url = $request->getBaseUrl() . $newName . '?'; - $parms = $request->getQueryParameters(); - $first = true; - foreach ($parms as $k => $v) { - if ($first) { - $url .= '?'; - $first = false; - } else { - $url .= '&'; - } - $url .= $k . '=' . $v; - } - - $request->setUrl($url); + if ($request->getMethod() !== 'PUT') { + throw new MethodNotAllowed('Only PUT is allowed on files drop'); } + $path = explode('/', $request->getPath()); + $path = array_pop($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 new file mode 100644 index 00000000000..e2990f27b60 --- /dev/null +++ b/apps/dav/tests/unit/Files/Sharing/FilesDropPluginTest.php @@ -0,0 +1,179 @@ +<?php +/** + * @copyright Copyright (c) 2016, Roeland Jago Douma <roeland@famdouma.nl> + * + * @author Roeland Jago Douma <roeland@famdouma.nl> + * + * @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/>. + * + */ +namespace OCA\DAV\Tests\Files\Sharing; + +use OC\Files\View; +use OCA\DAV\Files\Sharing\FilesDropPlugin; +use Sabre\DAV\Exception\MethodNotAllowed; +use Sabre\DAV\Server; +use Sabre\HTTP\RequestInterface; +use Sabre\HTTP\ResponseInterface; +use Test\TestCase; + +class FilesDropPluginTest extends TestCase { + + /** @var View|\PHPUnit_Framework_MockObject_MockObject */ + private $view; + + /** @var Server|\PHPUnit_Framework_MockObject_MockObject */ + private $server; + + /** @var FilesDropPlugin */ + private $plugin; + + /** @var RequestInterface|\PHPUnit_Framework_MockObject_MockObject */ + private $request; + + /** @var ResponseInterface|\PHPUnit_Framework_MockObject_MockObject */ + private $response; + + public function setUp() { + parent::setUp(); + + $this->view = $this->createMock(View::class); + $this->server = $this->createMock(Server::class); + $this->plugin = new FilesDropPlugin(); + + $this->request = $this->createMock(RequestInterface::class); + $this->response = $this->createMock(ResponseInterface::class); + + $this->response->expects($this->never()) + ->method($this->anything()); + } + + public function testInitialize() { + $this->server->expects($this->once()) + ->method('on') + ->with( + $this->equalTo('beforeMethod'), + $this->equalTo([$this->plugin, 'beforeMethod']), + $this->equalTo(999) + ); + + $this->plugin->initialize($this->server); + } + + public function testNotEnabled() { + $this->view->expects($this->never()) + ->method($this->anything()); + + $this->request->expects($this->never()) + ->method($this->anything()); + + $this->plugin->beforeMethod($this->request, $this->response); + } + + public function testValid() { + $this->plugin->enable(); + $this->plugin->setView($this->view); + + $this->request->method('getMethod') + ->willReturn('PUT'); + + $this->request->method('getPath') + ->willReturn('file.txt'); + + $this->request->method('getBaseUrl') + ->willReturn('https://example.com'); + + $this->view->method('file_exists') + ->with('/file.txt') + ->willReturn(false); + + $this->request->expects($this->once()) + ->method('setUrl') + ->with('https://example.com/file.txt'); + + $this->plugin->beforeMethod($this->request, $this->response); + } + + public function testFileAlreadyExistsValid() { + $this->plugin->enable(); + $this->plugin->setView($this->view); + + $this->request->method('getMethod') + ->willReturn('PUT'); + + $this->request->method('getPath') + ->willReturn('file.txt'); + + $this->request->method('getBaseUrl') + ->willReturn('https://example.com'); + + $this->view->method('file_exists') + ->will($this->returnCallback(function($path) { + if ($path === 'file.txt' || $path === '/file.txt') { + return true; + } else { + return false; + } + })); + + $this->request->expects($this->once()) + ->method('setUrl') + ->with($this->equalTo('https://example.com/file (2).txt')); + + $this->plugin->beforeMethod($this->request, $this->response); + } + + public function testNoMKCOL() { + $this->plugin->enable(); + $this->plugin->setView($this->view); + + $this->request->method('getMethod') + ->willReturn('MKCOL'); + + $this->expectException(MethodNotAllowed::class); + + $this->plugin->beforeMethod($this->request, $this->response); + } + + public function testNoSubdirPut() { + $this->plugin->enable(); + $this->plugin->setView($this->view); + + $this->request->method('getMethod') + ->willReturn('PUT'); + + $this->request->method('getPath') + ->willReturn('folder/file.txt'); + + $this->request->method('getBaseUrl') + ->willReturn('https://example.com'); + + $this->view->method('file_exists') + ->will($this->returnCallback(function($path) { + if ($path === 'file.txt' || $path === '/file.txt') { + return true; + } else { + return false; + } + })); + + $this->request->expects($this->once()) + ->method('setUrl') + ->with($this->equalTo('https://example.com/file (2).txt')); + + $this->plugin->beforeMethod($this->request, $this->response); + } +} diff --git a/apps/files/css/detailsView.css b/apps/files/css/detailsView.css index 094f44fdf05..f91fe3319e5 100644 --- a/apps/files/css/detailsView.css +++ b/apps/files/css/detailsView.css @@ -27,11 +27,6 @@ width: 90%; } -#app-sidebar .file-details-container { - display: inline-block; - float: left; -} - #app-sidebar .thumbnailContainer.large { margin-left: -15px; margin-right: -35px; /* 15 + 20 for the close button */ @@ -97,7 +92,7 @@ } #app-sidebar .fileName h3 { - max-width: 300px; + width: calc(100% - 36px); /* 36px is the with of the copy link icon */ display: inline-block; padding: 5px 0; margin: -5px 0; diff --git a/apps/files_sharing/css/sharetabview.css b/apps/files_sharing/css/sharetabview.css index 1ef5ac3fe3c..936e1af246a 100644 --- a/apps/files_sharing/css/sharetabview.css +++ b/apps/files_sharing/css/sharetabview.css @@ -71,7 +71,7 @@ } #shareWithList .unshare { - padding: 4px; + padding: 1px 6px; vertical-align: text-bottom; } #shareWithList .unshare .icon { @@ -81,6 +81,11 @@ #shareWithList .unshare .icon-delete { padding-right: 4px; background-position-x: 0; + display: inline-block; +} + +#shareWithList .sharingOptionsGroup .popovermenu:after { + right: 3px; } #shareWithList label input[type=checkbox] { @@ -104,12 +109,14 @@ .shareTabView .icon-loading-small { display: inline-block; z-index: 1; - padding: 2px 0; + margin-right: 4px; + vertical-align: text-top; } -.shareTabView .shareWithList .icon-loading-small, -.shareTabView .linkShareView .icon-loading-small { - position: absolute; +.shareTabView .shareWithList .icon-loading-small:not(.hidden) + span, +.shareTabView .linkShareView .icon-loading-small:not(.hidden) + input + label:before { + /* Hide if loader is visible */ + display: none !important; } .linkShareView { diff --git a/apps/files_versions/css/versions.css b/apps/files_versions/css/versions.css index cd63a90ab51..e749854a942 100644 --- a/apps/files_versions/css/versions.css +++ b/apps/files_versions/css/versions.css @@ -68,3 +68,7 @@ float: right; margin-right: -10px; } + +.versionsTabView .emptycontent { + margin-top: 10px; +} diff --git a/apps/files_versions/js/versionstabview.js b/apps/files_versions/js/versionstabview.js index a91366fd40a..e5ca115ecfa 100644 --- a/apps/files_versions/js/versionstabview.js +++ b/apps/files_versions/js/versionstabview.js @@ -38,7 +38,11 @@ var TEMPLATE = '<ul class="versions"></ul>' + '<div class="clear-float"></div>' + - '<div class="empty hidden">{{emptyResultLabel}}</div>' + + '<div class="empty hidden">' + + '<div class="emptycontent">' + + '<div class="icon-history"></div>' + + '<p>{{emptyResultLabel}}</p>' + + '</div></div>' + '<input type="button" class="showMoreVersions hidden" value="{{moreVersionsLabel}}"' + ' name="show-more-versions" id="show-more-versions" />' + '<div class="loading hidden" style="height: 50px"></div>'; @@ -225,7 +229,7 @@ */ render: function() { this.$el.html(this.template({ - emptyResultLabel: t('files_versions', 'No other versions available'), + emptyResultLabel: t('files_versions', 'No versions available'), moreVersionsLabel: t('files_versions', 'More versions...') })); this.$el.find('.has-tooltip').tooltip(); diff --git a/apps/updatenotification/appinfo/app.php b/apps/updatenotification/appinfo/app.php index f5bcf345669..e3010d418bb 100644 --- a/apps/updatenotification/appinfo/app.php +++ b/apps/updatenotification/appinfo/app.php @@ -43,10 +43,7 @@ if(\OC::$server->getConfig()->getSystemValue('updatechecker', true) === true) { $manager = \OC::$server->getNotificationManager(); $manager->registerNotifier(function() use ($manager) { - return new \OCA\UpdateNotification\Notification\Notifier( - $manager, - \OC::$server->getL10NFactory() - ); + return \OC::$server->query(\OCA\UpdateNotification\Notification\Notifier::class); }, function() { $l = \OC::$server->getL10N('updatenotification'); return [ diff --git a/apps/updatenotification/img/notification.svg b/apps/updatenotification/img/notification.svg new file mode 100644 index 00000000000..7a3f6270cbd --- /dev/null +++ b/apps/updatenotification/img/notification.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" height="16" width="16" viewbox="0 0 16 16"><path d="M6.938 0A.43.43 0 0 0 6.5.438v1.25a5.818 5.818 0 0 0-1.53.656l-.907-.906a.436.436 0 0 0-.625 0l-1.5 1.5a.436.436 0 0 0 0 .624l.906.907c-.285.48-.514.976-.656 1.53H.938a.43.43 0 0 0-.438.438v2.125C.5 8.81.69 9 .938 9h1.25a5.82 5.82 0 0 0 .656 1.53l-.907.908a.436.436 0 0 0 0 .625l1.5 1.5c.176.176.45.176.625 0l.907-.907c.48.285.976.514 1.53.656v1.25c0 .25.19.438.437.438h2.125a.43.43 0 0 0 .438-.438v-1.25a5.82 5.82 0 0 0 1.53-.657l.907.907c.176.175.45.175.625 0l1.5-1.5a.436.436 0 0 0 0-.625l-.906-.906A5.79 5.79 0 0 0 13.812 9h1.25a.43.43 0 0 0 .438-.438V6.437A.43.43 0 0 0 15.062 6h-1.25a5.79 5.79 0 0 0-.656-1.532l.906-.906a.436.436 0 0 0 0-.625l-1.5-1.5a.436.436 0 0 0-.625 0l-.906.906a5.816 5.816 0 0 0-1.53-.656V.437A.43.43 0 0 0 9.063 0zM8 4.157a3.344 3.344 0 0 1 0 6.686 3.344 3.344 0 0 1 0-6.686z" display="block"/></svg> diff --git a/apps/updatenotification/lib/Notification/Notifier.php b/apps/updatenotification/lib/Notification/Notifier.php index 3e1bc94425f..00cc94095ca 100644 --- a/apps/updatenotification/lib/Notification/Notifier.php +++ b/apps/updatenotification/lib/Notification/Notifier.php @@ -24,6 +24,7 @@ namespace OCA\UpdateNotification\Notification; +use OCP\IURLGenerator; use OCP\L10N\IFactory; use OCP\Notification\IManager; use OCP\Notification\INotification; @@ -31,6 +32,9 @@ use OCP\Notification\INotifier; class Notifier implements INotifier { + /** @var IURLGenerator */ + protected $url; + /** @var IManager */ protected $notificationManager; @@ -43,10 +47,12 @@ class Notifier implements INotifier { /** * Notifier constructor. * + * @param IURLGenerator $url * @param IManager $notificationManager * @param IFactory $l10NFactory */ - public function __construct(IManager $notificationManager, IFactory $l10NFactory) { + public function __construct(IURLGenerator $url, IManager $notificationManager, IFactory $l10NFactory) { + $this->url = $url; $this->notificationManager = $notificationManager; $this->l10NFactory = $l10NFactory; $this->appVersions = $this->getAppVersions(); @@ -78,9 +84,18 @@ class Notifier implements INotifier { $this->updateAlreadyInstalledCheck($notification, $this->appVersions[$notification->getObjectType()]); } - $notification->setParsedSubject($l->t('Update for %1$s to version %2$s is available.', [$appName, $notification->getObjectId()])); + $notification->setParsedSubject($l->t('Update for %1$s to version %2$s is available.', [$appName, $notification->getObjectId()])) + ->setRichSubject($l->t('Update for {app} to version %s is available.', $notification->getObjectId()), [ + 'app' => [ + 'type' => 'app', + 'id' => $notification->getObjectType(), + 'name' => $appName, + ] + ]); } + $notification->setIcon($this->url->getAbsoluteURL($this->url->imagePath('updatenotification', 'notification.svg'))); + return $notification; } diff --git a/apps/updatenotification/tests/Notification/NotifierTest.php b/apps/updatenotification/tests/Notification/NotifierTest.php index e5ccb291b5c..421fcada689 100644 --- a/apps/updatenotification/tests/Notification/NotifierTest.php +++ b/apps/updatenotification/tests/Notification/NotifierTest.php @@ -24,12 +24,16 @@ namespace OCA\UpdateNotification\Tests\Notification; use OCA\UpdateNotification\Notification\Notifier; +use OCP\IURLGenerator; use OCP\L10N\IFactory; use OCP\Notification\IManager; +use OCP\Notification\INotification; use Test\TestCase; class NotifierTest extends TestCase { + /** @var IURLGenerator|\PHPUnit_Framework_MockObject_MockObject */ + protected $urlGenerator; /** @var IManager|\PHPUnit_Framework_MockObject_MockObject */ protected $notificationManager; /** @var IFactory|\PHPUnit_Framework_MockObject_MockObject */ @@ -38,8 +42,9 @@ class NotifierTest extends TestCase { public function setUp() { parent::setUp(); - $this->notificationManager = $this->getMockBuilder('OCP\Notification\IManager')->getMock(); - $this->l10nFactory = $this->getMockBuilder('OCP\L10n\IFactory')->getMock(); + $this->urlGenerator = $this->createMock(IURLGenerator::class); + $this->notificationManager = $this->createMock(IManager::class); + $this->l10nFactory = $this->createMock(IFactory::class); } /** @@ -49,12 +54,14 @@ class NotifierTest extends TestCase { protected function getNotifier(array $methods = []) { if (empty($methods)) { return new Notifier( + $this->urlGenerator, $this->notificationManager, $this->l10nFactory ); } { - return $this->getMockBuilder('OCA\UpdateNotification\Notification\Notifier') + return $this->getMockBuilder(Notifier::class) ->setConstructorArgs([ + $this->urlGenerator, $this->notificationManager, $this->l10nFactory, ]) @@ -81,7 +88,7 @@ class NotifierTest extends TestCase { public function testUpdateAlreadyInstalledCheck($versionNotification, $versionInstalled, $exception) { $notifier = $this->getNotifier(); - $notification = $this->getMockBuilder('OCP\Notification\INotification')->getMock(); + $notification = $this->createMock(INotification::class); $notification->expects($this->once()) ->method('getObjectId') ->willReturn($versionNotification); diff --git a/build/integration/config/behat.yml b/build/integration/config/behat.yml index 3728e5461d8..9ef36f083e9 100644 --- a/build/integration/config/behat.yml +++ b/build/integration/config/behat.yml @@ -62,6 +62,16 @@ default: - admin - admin regular_user_password: 123456 + filesdrop: + paths: + - %paths.base%/../filesdrop_features + contexts: + - FilesDropContext: + baseUrl: http://localhost:8080 + admin: + - admin + - admin + regular_user_password: 123456 diff --git a/build/integration/features/bootstrap/FilesDropContext.php b/build/integration/features/bootstrap/FilesDropContext.php new file mode 100644 index 00000000000..760d76ac5e5 --- /dev/null +++ b/build/integration/features/bootstrap/FilesDropContext.php @@ -0,0 +1,72 @@ +<?php + +use Behat\Behat\Context\Context; +use Behat\Behat\Context\SnippetAcceptingContext; +use Behat\Behat\Tester\Exception\PendingException; +use GuzzleHttp\Client; + +require __DIR__ . '/../../vendor/autoload.php'; + +class FilesDropContext implements Context, SnippetAcceptingContext { + use WebDav; + + /** + * @When Dropping file :path with :content + */ + public function droppingFileWith($path, $content) { + $client = new Client(); + $options = []; + if (count($this->lastShareData->data->element) > 0){ + $token = $this->lastShareData->data[0]->token; + } else { + $token = $this->lastShareData->data[0]->token; + } + + $base = substr($this->baseUrl, 0, -4); + $fullUrl = $base . '/public.php/webdav' . $path; + + $options['auth'] = [$token, '']; + $options['headers'] = [ + 'X-REQUESTED-WITH' => 'XMLHttpRequest' + ]; + + $request = $client->createRequest('PUT', $fullUrl, $options); + $file = \GuzzleHttp\Stream\Stream::factory($content); + $request->setBody($file); + + try { + $this->response = $client->send($request); + } catch (\GuzzleHttp\Exception\ClientException $e) { + $this->response = $e->getResponse(); + } + } + + /** + * @When Creating folder :folder in drop + */ + public function creatingFolderInDrop($folder) { + $client = new Client(); + $options = []; + if (count($this->lastShareData->data->element) > 0){ + $token = $this->lastShareData->data[0]->token; + } else { + $token = $this->lastShareData->data[0]->token; + } + + $base = substr($this->baseUrl, 0, -4); + $fullUrl = $base . '/public.php/webdav/' . $folder; + + $options['auth'] = [$token, '']; + $options['headers'] = [ + 'X-REQUESTED-WITH' => 'XMLHttpRequest' + ]; + + $request = $client->createRequest('MKCOL', $fullUrl, $options); + + try { + $this->response = $client->send($request); + } catch (\GuzzleHttp\Exception\ClientException $e) { + $this->response = $e->getResponse(); + } + } +} diff --git a/build/integration/filesdrop_features/filesdrop.feature b/build/integration/filesdrop_features/filesdrop.feature new file mode 100644 index 00000000000..4a8759e241a --- /dev/null +++ b/build/integration/filesdrop_features/filesdrop.feature @@ -0,0 +1,59 @@ +Feature: FilesDrop + + Scenario: Put file via files drop + Given user "user0" exists + And As an "user0" + And user "user0" created a folder "/drop" + And as "user0" creating a share with + | path | drop | + | shareType | 3 | + | publicUpload | true | + And Updating last share with + | permissions | 4 | + When Dropping file "/a.txt" with "abc" + And Downloading file "/drop/a.txt" + Then Downloaded content should be "abc" + + Scenario: Put file same file multiple times via files drop + Given user "user0" exists + And As an "user0" + And user "user0" created a folder "/drop" + And as "user0" creating a share with + | path | drop | + | shareType | 3 | + | publicUpload | true | + And Updating last share with + | permissions | 4 | + When Dropping file "/a.txt" with "abc" + And Dropping file "/a.txt" with "def" + And Downloading file "/drop/a.txt" + Then Downloaded content should be "abc" + And Downloading file "/drop/a (2).txt" + Then Downloaded content should be "def" + + Scenario: Files drop ignores directory + Given user "user0" exists + And As an "user0" + And user "user0" created a folder "/drop" + And as "user0" creating a share with + | path | drop | + | shareType | 3 | + | publicUpload | true | + And Updating last share with + | permissions | 4 | + When Dropping file "/folder/a.txt" with "abc" + And Downloading file "/drop/a.txt" + Then Downloaded content should be "abc" + + Scenario: Files drop forbis MKCOL + Given user "user0" exists + And As an "user0" + And user "user0" created a folder "/drop" + And as "user0" creating a share with + | path | drop | + | shareType | 3 | + | publicUpload | true | + And Updating last share with + | permissions | 4 | + When Creating folder "folder" in drop + Then the HTTP status code should be "405" diff --git a/core/css/icons.css b/core/css/icons.css index 7618491cf90..a2869dfac1c 100644 --- a/core/css/icons.css +++ b/core/css/icons.css @@ -30,9 +30,9 @@ .icon-loading-small-dark:after { z-index: 2; content: ""; - height: 32px; - width: 32px; - margin: -17px 0 0 -17px; + height: 30px; + width: 30px; + margin: -16px 0 0 -16px; position: absolute; top: 50%; left: 50%; @@ -61,9 +61,9 @@ .icon-loading-small:after, .icon-loading-small-dark:after { - height: 16px; - width: 16px; - margin: -9px 0 0 -9px; + height: 14px; + width: 14px; + margin: -8px 0 0 -8px; } /* Css replaced elements don't have ::after nor ::before */ diff --git a/core/css/share.css b/core/css/share.css index 05b6ca3912a..eba22cf743e 100644 --- a/core/css/share.css +++ b/core/css/share.css @@ -132,7 +132,6 @@ a.unshare { display:inline-block; opacity:.5; padding: 10px; - margin-top: -5px; } #link { diff --git a/core/img/loading-dark.gif b/core/img/loading-dark.gif Binary files differindex bd56aa9e12b..72c66c07d7c 100644 --- a/core/img/loading-dark.gif +++ b/core/img/loading-dark.gif diff --git a/core/img/loading-small-dark.gif b/core/img/loading-small-dark.gif Binary files differindex 50be5bfb2a1..1aa3da80055 100644 --- a/core/img/loading-small-dark.gif +++ b/core/img/loading-small-dark.gif diff --git a/core/img/loading-small.gif b/core/img/loading-small.gif Binary files differindex 90ed449b1f4..83587a634ce 100644 --- a/core/img/loading-small.gif +++ b/core/img/loading-small.gif diff --git a/core/img/loading.gif b/core/img/loading.gif Binary files differindex a4816024d3b..c7abd32611b 100644 --- a/core/img/loading.gif +++ b/core/img/loading.gif diff --git a/lib/private/Files/View.php b/lib/private/Files/View.php index 3ce21a3489b..6facc7b9462 100644 --- a/lib/private/Files/View.php +++ b/lib/private/Files/View.php @@ -1132,13 +1132,13 @@ class View { throw $e; } - if (in_array('delete', $hooks) and $result) { + if ($result && in_array('delete', $hooks) and $result) { $this->removeUpdate($storage, $internalPath); } - if (in_array('write', $hooks) and $operation !== 'fopen') { + if ($result && in_array('write', $hooks) and $operation !== 'fopen') { $this->writeUpdate($storage, $internalPath); } - if (in_array('touch', $hooks)) { + if ($result && in_array('touch', $hooks)) { $this->writeUpdate($storage, $internalPath, $extraParam); } diff --git a/lib/public/RichObjectStrings/Definitions.php b/lib/public/RichObjectStrings/Definitions.php index 2b35f9ceed1..fbde439c47a 100644 --- a/lib/public/RichObjectStrings/Definitions.php +++ b/lib/public/RichObjectStrings/Definitions.php @@ -37,16 +37,16 @@ class Definitions { 'addressbook' => [ 'author' => 'Nextcloud', 'app' => 'dav', - 'since' => '9.2.0', + 'since' => '11.0.0', 'parameters' => [ 'id' => [ - 'since' => '9.2.0', + 'since' => '11.0.0', 'required' => true, 'description' => 'The id used to identify the addressbook on the instance', 'example' => '42', ], 'name' => [ - 'since' => '9.2.0', + 'since' => '11.0.0', 'required' => true, 'description' => 'The display name of the addressbook which should be used in the visual representation', 'example' => 'Contacts', @@ -56,16 +56,16 @@ class Definitions { 'addressbook-contact' => [ 'author' => 'Nextcloud', 'app' => 'dav', - 'since' => '9.2.0', + 'since' => '11.0.0', 'parameters' => [ 'id' => [ - 'since' => '9.2.0', + 'since' => '11.0.0', 'required' => true, 'description' => 'The id used to identify the contact on the instance', 'example' => '42', ], 'name' => [ - 'since' => '9.2.0', + 'since' => '11.0.0', 'required' => true, 'description' => 'The display name of the contact which should be used in the visual representation', 'example' => 'John Doe', @@ -75,40 +75,58 @@ class Definitions { 'announcement' => [ 'author' => 'Joas Schilling', 'app' => 'announcementcenter', - 'since' => '9.2.0', + 'since' => '11.0.0', 'parameters' => [ 'id' => [ - 'since' => '9.2.0', + 'since' => '11.0.0', 'required' => true, 'description' => 'The id used to identify the announcement on the instance', 'example' => '42', ], 'name' => [ - 'since' => '9.2.0', + 'since' => '11.0.0', 'required' => true, 'description' => 'The announcement subject which should be used in the visual representation', 'example' => 'file.txt', ], 'link' => [ - 'since' => '9.2.0', + 'since' => '11.0.0', 'required' => false, 'description' => 'The full URL to the file', 'example' => 'http://localhost/index.php/apps/announcements/#23', ], ], ], + 'app' => [ + 'author' => 'Nextcloud', + 'app' => 'updatenotification', + 'since' => '11.0.0', + 'parameters' => [ + 'id' => [ + 'since' => '11.0.0', + 'required' => true, 'description' => 'The app id', + 'example' => 'updatenotification', + ], + 'name' => [ + 'since' => '11.0.0', + 'required' => true, + 'description' => 'The name of the app which should be used in the visual representation', + 'example' => 'Update notification', + ], + ], + ], 'calendar' => [ 'author' => 'Nextcloud', 'app' => 'dav', - 'since' => '9.2.0', + 'since' => '11.0.0', 'parameters' => [ 'id' => [ - 'since' => '9.2.0', + 'since' => '11.0.0', 'required' => true, 'description' => 'The id used to identify the calendar on the instance', 'example' => '42', ], 'name' => [ - 'since' => '9.2.0', + 'since' => '11.0.0', 'required' => true, 'description' => 'The display name of the calendar which should be used in the visual representation', 'example' => 'Personal', @@ -118,16 +136,16 @@ class Definitions { 'calendar-event' => [ 'author' => 'Nextcloud', 'app' => 'dav', - 'since' => '9.2.0', + 'since' => '11.0.0', 'parameters' => [ 'id' => [ - 'since' => '9.2.0', + 'since' => '11.0.0', 'required' => true, 'description' => 'The id used to identify the event on the instance', 'example' => '42', ], 'name' => [ - 'since' => '9.2.0', + 'since' => '11.0.0', 'required' => true, 'description' => 'The display name of the event which should be used in the visual representation', 'example' => 'Workout', @@ -137,16 +155,16 @@ class Definitions { 'email' => [ 'author' => 'Nextcloud', 'app' => 'sharebymail', - 'since' => '9.2.0', + 'since' => '11.0.0', 'parameters' => [ 'id' => [ - 'since' => '9.2.0', + 'since' => '11.0.0', 'required' => true, 'description' => 'The mail-address used to identify the event on the instance', 'example' => 'test@localhost', ], 'name' => [ - 'since' => '9.2.0', + 'since' => '11.0.0', 'required' => true, 'description' => 'The display name of a matching contact or the email (fallback) which should be used in the visual representation', 'example' => 'Foo Bar', @@ -156,28 +174,28 @@ class Definitions { 'file' => [ 'author' => 'Nextcloud', 'app' => 'dav', - 'since' => '9.2.0', + 'since' => '11.0.0', 'parameters' => [ 'id' => [ - 'since' => '9.2.0', + 'since' => '11.0.0', 'required' => true, 'description' => 'The id used to identify the file on the instance', 'example' => '42', ], 'name' => [ - 'since' => '9.2.0', + 'since' => '11.0.0', 'required' => true, 'description' => 'The file name which should be used in the visual representation', 'example' => 'file.txt', ], 'path' => [ - 'since' => '9.2.0', + 'since' => '11.0.0', 'required' => true, 'description' => 'The full path of the file for the user', 'example' => 'path/to/file.txt', ], 'link' => [ - 'since' => '9.2.0', + 'since' => '11.0.0', 'required' => false, 'description' => 'The full URL to the file', 'example' => 'http://localhost/index.php/f/42', @@ -187,16 +205,16 @@ class Definitions { 'pending-federated-share' => [ 'author' => 'Nextcloud', 'app' => 'dav', - 'since' => '9.2.0', + 'since' => '11.0.0', 'parameters' => [ 'id' => [ - 'since' => '9.2.0', + 'since' => '11.0.0', 'required' => true, 'description' => 'The id used to identify the federated share on the instance', 'example' => '42', ], 'name' => [ - 'since' => '9.2.0', + 'since' => '11.0.0', 'required' => true, 'description' => 'The name of the shared item which should be used in the visual representation', 'example' => 'file.txt', @@ -206,28 +224,28 @@ class Definitions { 'systemtag' => [ 'author' => 'Nextcloud', 'app' => 'core', - 'since' => '9.2.0', + 'since' => '11.0.0', 'parameters' => [ 'id' => [ - 'since' => '9.2.0', + 'since' => '11.0.0', 'required' => true, 'description' => 'The id used to identify the systemtag on the instance', 'example' => '23', ], 'name' => [ - 'since' => '9.2.0', + 'since' => '11.0.0', 'required' => true, 'description' => 'The display name of the systemtag which should be used in the visual representation', 'example' => 'Project 1', ], 'visibility' => [ - 'since' => '9.2.0', + 'since' => '11.0.0', 'required' => true, 'description' => 'If the user can see the systemtag', 'example' => '1', ], 'assignable' => [ - 'since' => '9.2.0', + 'since' => '11.0.0', 'required' => true, 'description' => 'If the user can assign the systemtag', 'example' => '0', @@ -237,22 +255,22 @@ class Definitions { 'user' => [ 'author' => 'Nextcloud', 'app' => 'core', - 'since' => '9.2.0', + 'since' => '11.0.0', 'parameters' => [ 'id' => [ - 'since' => '9.2.0', + 'since' => '11.0.0', 'required' => true, 'description' => 'The id used to identify the user on the instance', 'example' => 'johndoe', ], 'name' => [ - 'since' => '9.2.0', + 'since' => '11.0.0', 'required' => true, 'description' => 'The display name of the user which should be used in the visual representation', 'example' => 'John Doe', ], 'server' => [ - 'since' => '9.2.0', + 'since' => '11.0.0', 'required' => false, 'description' => 'The URL of the instance the user lives on', 'example' => 'localhost', @@ -262,16 +280,16 @@ class Definitions { 'user-group' => [ 'author' => 'Nextcloud', 'app' => 'core', - 'since' => '9.2.0', + 'since' => '11.0.0', 'parameters' => [ 'id' => [ - 'since' => '9.2.0', + 'since' => '11.0.0', 'required' => true, 'description' => 'The id used to identify the group on the instance', 'example' => 'supportteam', ], 'name' => [ - 'since' => '9.2.0', + 'since' => '11.0.0', 'required' => true, 'description' => 'The display name of the group which should be used in the visual representation', 'example' => 'Support Team', |