summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--apps/dav/lib/comments/commentnode.php7
-rw-r--r--apps/dav/lib/comments/commentsplugin.php3
-rw-r--r--apps/dav/tests/unit/comments/commentnode.php39
-rw-r--r--apps/dav/tests/unit/comments/commentsplugin.php93
-rw-r--r--apps/federatedfilesharing/lib/federatedshareprovider.php2
-rw-r--r--apps/federation/controller/settingscontroller.php1
-rw-r--r--apps/federation/lib/trustedservers.php36
-rw-r--r--apps/federation/middleware/addservermiddleware.php2
-rw-r--r--apps/federation/tests/lib/trustedserverstest.php40
-rw-r--r--apps/federation/tests/middleware/addservermiddlewaretest.php3
-rw-r--r--apps/files/appinfo/register_command.php10
-rw-r--r--apps/files/command/transferownership.php225
-rw-r--r--apps/updatenotification/appinfo/app.php39
-rw-r--r--apps/updatenotification/appinfo/info.xml13
-rw-r--r--apps/updatenotification/js/notification.js (renamed from core/js/update-notification.js)4
-rw-r--r--apps/updatenotification/lib/updatechecker.php67
-rw-r--r--apps/updatenotification/tests/UpdateCheckerTest.php86
-rw-r--r--build/integration/features/provisioning-v1.feature1
-rw-r--r--core/shipped.json2
-rw-r--r--core/templates/layout.user.php6
-rw-r--r--lib/private/comments/comment.php8
-rw-r--r--lib/private/templatelayout.php25
-rw-r--r--lib/public/comments/icomment.php5
-rw-r--r--lib/public/comments/messagetoolongexception.php27
-rw-r--r--tests/lib/comments/comment.php10
25 files changed, 682 insertions, 72 deletions
diff --git a/apps/dav/lib/comments/commentnode.php b/apps/dav/lib/comments/commentnode.php
index d3cd53bceb1..339abc6382d 100644
--- a/apps/dav/lib/comments/commentnode.php
+++ b/apps/dav/lib/comments/commentnode.php
@@ -24,9 +24,11 @@ namespace OCA\DAV\Comments;
use OCP\Comments\IComment;
use OCP\Comments\ICommentsManager;
+use OCP\Comments\MessageTooLongException;
use OCP\ILogger;
use OCP\IUserManager;
use OCP\IUserSession;
+use Sabre\DAV\Exception\BadRequest;
use Sabre\DAV\Exception\Forbidden;
use Sabre\DAV\Exception\MethodNotAllowed;
use Sabre\DAV\PropPatch;
@@ -168,6 +170,7 @@ class CommentNode implements \Sabre\DAV\INode, \Sabre\DAV\IProperties {
*
* @param $propertyValue
* @return bool
+ * @throws BadRequest
* @throws Forbidden
*/
public function updateComment($propertyValue) {
@@ -178,6 +181,10 @@ class CommentNode implements \Sabre\DAV\INode, \Sabre\DAV\IProperties {
return true;
} catch (\Exception $e) {
$this->logger->logException($e, ['app' => 'dav/comments']);
+ if($e instanceof MessageTooLongException) {
+ $msg = 'Message exceeds allowed character limit of ';
+ throw new BadRequest($msg . IComment::MAX_MESSAGE_LENGTH, 0, $e);
+ }
return false;
}
}
diff --git a/apps/dav/lib/comments/commentsplugin.php b/apps/dav/lib/comments/commentsplugin.php
index 56d94cc33e9..7abf6e71ee5 100644
--- a/apps/dav/lib/comments/commentsplugin.php
+++ b/apps/dav/lib/comments/commentsplugin.php
@@ -242,6 +242,9 @@ class CommentsPlugin extends ServerPlugin {
return $comment;
} catch (\InvalidArgumentException $e) {
throw new BadRequest('Invalid input values', 0, $e);
+ } catch (\OCP\Comments\MessageTooLongException $e) {
+ $msg = 'Message exceeds allowed character limit of ';
+ throw new BadRequest($msg . \OCP\Comments\IComment::MAX_MESSAGE_LENGTH, 0, $e);
}
}
diff --git a/apps/dav/tests/unit/comments/commentnode.php b/apps/dav/tests/unit/comments/commentnode.php
index 8d1bf06ab60..8ebc5c2ff2c 100644
--- a/apps/dav/tests/unit/comments/commentnode.php
+++ b/apps/dav/tests/unit/comments/commentnode.php
@@ -22,6 +22,8 @@
namespace OCA\DAV\Tests\Unit\Comments;
use OCA\DAV\Comments\CommentNode;
+use OCP\Comments\IComment;
+use OCP\Comments\MessageTooLongException;
class CommentsNode extends \Test\TestCase {
@@ -199,6 +201,43 @@ class CommentsNode extends \Test\TestCase {
}
/**
+ * @expectedException \Sabre\DAV\Exception\BadRequest
+ * @expectedExceptionMessage Message exceeds allowed character limit of
+ */
+ public function testUpdateCommentMessageTooLongException() {
+ $user = $this->getMock('\OCP\IUser');
+
+ $user->expects($this->once())
+ ->method('getUID')
+ ->will($this->returnValue('alice'));
+
+ $this->userSession->expects($this->once())
+ ->method('getUser')
+ ->will($this->returnValue($user));
+
+ $this->comment->expects($this->once())
+ ->method('setMessage')
+ ->will($this->throwException(new MessageTooLongException()));
+
+ $this->comment->expects($this->any())
+ ->method('getActorType')
+ ->will($this->returnValue('users'));
+
+ $this->comment->expects($this->any())
+ ->method('getActorId')
+ ->will($this->returnValue('alice'));
+
+ $this->commentsManager->expects($this->never())
+ ->method('save');
+
+ $this->logger->expects($this->once())
+ ->method('logException');
+
+ // imagine 'foo' has >1k characters. comment is mocked anyway.
+ $this->node->updateComment('foo');
+ }
+
+ /**
* @expectedException \Sabre\DAV\Exception\Forbidden
*/
public function testUpdateForbiddenByUser() {
diff --git a/apps/dav/tests/unit/comments/commentsplugin.php b/apps/dav/tests/unit/comments/commentsplugin.php
index 9822137bbea..d6f489f5e80 100644
--- a/apps/dav/tests/unit/comments/commentsplugin.php
+++ b/apps/dav/tests/unit/comments/commentsplugin.php
@@ -23,6 +23,7 @@ namespace OCA\DAV\Tests\Unit\Comments;
use OC\Comments\Comment;
use OCA\DAV\Comments\CommentsPlugin as CommentsPluginImplementation;
+use OCP\Comments\IComment;
use Sabre\DAV\Exception\NotFound;
class CommentsPlugin extends \Test\TestCase {
@@ -506,6 +507,98 @@ class CommentsPlugin extends \Test\TestCase {
}
/**
+ * @expectedException \Sabre\DAV\Exception\BadRequest
+ * @expectedExceptionMessage Message exceeds allowed character limit of
+ */
+ public function testCreateCommentMessageTooLong() {
+ $commentData = [
+ 'actorType' => 'users',
+ 'verb' => 'comment',
+ 'message' => str_pad('', IComment::MAX_MESSAGE_LENGTH + 1, 'x'),
+ ];
+
+ $comment = new Comment([
+ 'objectType' => 'files',
+ 'objectId' => '42',
+ 'actorType' => 'users',
+ 'actorId' => 'alice',
+ 'verb' => 'comment',
+ ]);
+ $comment->setId('23');
+
+ $path = 'comments/files/42';
+
+ $requestData = json_encode($commentData);
+
+ $user = $this->getMock('OCP\IUser');
+ $user->expects($this->once())
+ ->method('getUID')
+ ->will($this->returnValue('alice'));
+
+ $node = $this->getMockBuilder('\OCA\DAV\Comments\EntityCollection')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $node->expects($this->once())
+ ->method('getName')
+ ->will($this->returnValue('files'));
+ $node->expects($this->once())
+ ->method('getId')
+ ->will($this->returnValue('42'));
+
+ $node->expects($this->never())
+ ->method('setReadMarker');
+
+ $this->commentsManager->expects($this->once())
+ ->method('create')
+ ->with('users', 'alice', 'files', '42')
+ ->will($this->returnValue($comment));
+
+ $this->userSession->expects($this->once())
+ ->method('getUser')
+ ->will($this->returnValue($user));
+
+ // technically, this is a shortcut. Inbetween EntityTypeCollection would
+ // be returned, but doing it exactly right would not be really
+ // unit-testing like, as it would require to haul in a lot of other
+ // things.
+ $this->tree->expects($this->any())
+ ->method('getNodeForPath')
+ ->with('/' . $path)
+ ->will($this->returnValue($node));
+
+ $request = $this->getMockBuilder('Sabre\HTTP\RequestInterface')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $response = $this->getMockBuilder('Sabre\HTTP\ResponseInterface')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $request->expects($this->once())
+ ->method('getPath')
+ ->will($this->returnValue('/' . $path));
+
+ $request->expects($this->once())
+ ->method('getBodyAsString')
+ ->will($this->returnValue($requestData));
+
+ $request->expects($this->once())
+ ->method('getHeader')
+ ->with('Content-Type')
+ ->will($this->returnValue('application/json'));
+
+ $response->expects($this->never())
+ ->method('setHeader');
+
+ $this->server->expects($this->any())
+ ->method('getRequestUri')
+ ->will($this->returnValue($path));
+ $this->plugin->initialize($this->server);
+
+ $this->plugin->httpPost($request, $response);
+ }
+
+ /**
* @expectedException \Sabre\DAV\Exception\ReportNotSupported
*/
public function testOnReportInvalidNode() {
diff --git a/apps/federatedfilesharing/lib/federatedshareprovider.php b/apps/federatedfilesharing/lib/federatedshareprovider.php
index 0825a0e69bc..0e6089bde07 100644
--- a/apps/federatedfilesharing/lib/federatedshareprovider.php
+++ b/apps/federatedfilesharing/lib/federatedshareprovider.php
@@ -220,6 +220,8 @@ class FederatedShareProvider implements IShareProvider {
$qb->update('share')
->where($qb->expr()->eq('id', $qb->createNamedParameter($share->getId())))
->set('permissions', $qb->createNamedParameter($share->getPermissions()))
+ ->set('uid_owner', $qb->createNamedParameter($share->getShareOwner()))
+ ->set('uid_initiator', $qb->createNamedParameter($share->getSharedBy()))
->execute();
return $share;
diff --git a/apps/federation/controller/settingscontroller.php b/apps/federation/controller/settingscontroller.php
index e5e46606f12..3adb6fced66 100644
--- a/apps/federation/controller/settingscontroller.php
+++ b/apps/federation/controller/settingscontroller.php
@@ -26,7 +26,6 @@ use OCA\Federation\TrustedServers;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\DataResponse;
-use OCP\IConfig;
use OCP\IL10N;
use OCP\IRequest;
diff --git a/apps/federation/lib/trustedservers.php b/apps/federation/lib/trustedservers.php
index e3ce8228cc3..340accfdbdf 100644
--- a/apps/federation/lib/trustedservers.php
+++ b/apps/federation/lib/trustedservers.php
@@ -23,6 +23,7 @@
namespace OCA\Federation;
+use OC\HintException;
use OCP\AppFramework\Http;
use OCP\BackgroundJob\IJobList;
use OCP\Http\Client\IClientService;
@@ -202,34 +203,33 @@ class TrustedServers {
public function isOwnCloudServer($url) {
$isValidOwnCloud = false;
$client = $this->httpClientService->newClient();
- try {
- $result = $client->get(
- $url . '/status.php',
- [
- 'timeout' => 3,
- 'connect_timeout' => 3,
- ]
- );
- if ($result->getStatusCode() === Http::STATUS_OK) {
- $isValidOwnCloud = $this->checkOwnCloudVersion($result->getBody());
- }
- } catch (\Exception $e) {
- $this->logger->error($e->getMessage(), ['app' => 'federation']);
- return false;
+ $result = $client->get(
+ $url . '/status.php',
+ [
+ 'timeout' => 3,
+ 'connect_timeout' => 3,
+ ]
+ );
+ if ($result->getStatusCode() === Http::STATUS_OK) {
+ $isValidOwnCloud = $this->checkOwnCloudVersion($result->getBody());
}
+
return $isValidOwnCloud;
}
/**
* check if ownCloud version is >= 9.0
*
- * @param $statusphp
+ * @param $status
* @return bool
*/
- protected function checkOwnCloudVersion($statusphp) {
- $decoded = json_decode($statusphp, true);
+ protected function checkOwnCloudVersion($status) {
+ $decoded = json_decode($status, true);
if (!empty($decoded) && isset($decoded['version'])) {
- return version_compare($decoded['version'], '9.0.0', '>=');
+ if (!version_compare($decoded['version'], '9.0.0', '>=')) {
+ throw new HintException('Remote server version is too low. ownCloud 9.0 is required.');
+ }
+ return true;
}
return false;
}
diff --git a/apps/federation/middleware/addservermiddleware.php b/apps/federation/middleware/addservermiddleware.php
index cd9ccff4403..10abd9db704 100644
--- a/apps/federation/middleware/addservermiddleware.php
+++ b/apps/federation/middleware/addservermiddleware.php
@@ -58,7 +58,7 @@ class AddServerMiddleware extends Middleware {
if ($exception instanceof HintException) {
$message = $exception->getHint();
} else {
- $message = $this->l->t('Unknown error');
+ $message = $exception->getMessage();
}
return new JSONResponse(
diff --git a/apps/federation/tests/lib/trustedserverstest.php b/apps/federation/tests/lib/trustedserverstest.php
index e57391ed198..130a0e3bb22 100644
--- a/apps/federation/tests/lib/trustedserverstest.php
+++ b/apps/federation/tests/lib/trustedserverstest.php
@@ -23,6 +23,7 @@
namespace OCA\Federation\Tests\lib;
+use OC\HintException;
use OCA\Federation\DbHandler;
use OCA\Federation\TrustedServers;
use OCP\BackgroundJob\IJobList;
@@ -282,41 +283,50 @@ class TrustedServersTest extends TestCase {
];
}
+ /**
+ * @expectedException \Exception
+ * @expectedExceptionMessage simulated exception
+ */
public function testIsOwnCloudServerFail() {
$server = 'server1';
$this->httpClientService->expects($this->once())->method('newClient')
->willReturn($this->httpClient);
- $this->logger->expects($this->once())->method('error')
- ->with('simulated exception', ['app' => 'federation']);
-
$this->httpClient->expects($this->once())->method('get')->with($server . '/status.php')
->willReturnCallback(function () {
throw new \Exception('simulated exception');
});
- $this->assertFalse($this->trustedServers->isOwnCloudServer($server));
-
+ $this->trustedServers->isOwnCloudServer($server);
}
/**
* @dataProvider dataTestCheckOwnCloudVersion
- *
- * @param $statusphp
- * @param $expected
*/
- public function testCheckOwnCloudVersion($statusphp, $expected) {
- $this->assertSame($expected,
- $this->invokePrivate($this->trustedServers, 'checkOwnCloudVersion', [$statusphp])
- );
+ public function testCheckOwnCloudVersion($status) {
+ $this->assertTrue($this->invokePrivate($this->trustedServers, 'checkOwnCloudVersion', [$status]));
}
public function dataTestCheckOwnCloudVersion() {
return [
- ['{"version":"8.4.0"}', false],
- ['{"version":"9.0.0"}', true],
- ['{"version":"9.1.0"}', true]
+ ['{"version":"9.0.0"}'],
+ ['{"version":"9.1.0"}']
+ ];
+ }
+
+ /**
+ * @dataProvider dataTestCheckOwnCloudVersionTooLow
+ * @expectedException \OC\HintException
+ * @expectedExceptionMessage Remote server version is too low. ownCloud 9.0 is required.
+ */
+ public function testCheckOwnCloudVersionTooLow($status) {
+ $this->invokePrivate($this->trustedServers, 'checkOwnCloudVersion', [$status]);
+ }
+
+ public function dataTestCheckOwnCloudVersionTooLow() {
+ return [
+ ['{"version":"8.2.3"}'],
];
}
diff --git a/apps/federation/tests/middleware/addservermiddlewaretest.php b/apps/federation/tests/middleware/addservermiddlewaretest.php
index a94d907ae76..49e34cc73d6 100644
--- a/apps/federation/tests/middleware/addservermiddlewaretest.php
+++ b/apps/federation/tests/middleware/addservermiddlewaretest.php
@@ -27,6 +27,7 @@ use OC\HintException;
use OCA\Federation\Middleware\AddServerMiddleware;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http;
+use OCP\ILogger;
use Test\TestCase;
class AddServerMiddlewareTest extends TestCase {
@@ -93,7 +94,7 @@ class AddServerMiddlewareTest extends TestCase {
public function dataTestAfterException() {
return [
[new HintException('message', 'hint'), 'message', 'hint'],
- [new \Exception('message'), 'message', 'Unknown error'],
+ [new \Exception('message'), 'message', 'message'],
];
}
diff --git a/apps/files/appinfo/register_command.php b/apps/files/appinfo/register_command.php
index 4aaf49df9e2..0ec2fe1a584 100644
--- a/apps/files/appinfo/register_command.php
+++ b/apps/files/appinfo/register_command.php
@@ -21,5 +21,11 @@
*
*/
-$application->add(new OCA\Files\Command\Scan(\OC::$server->getUserManager()));
-$application->add(new OCA\Files\Command\DeleteOrphanedFiles(\OC::$server->getDatabaseConnection()));
+$dbConnection = \OC::$server->getDatabaseConnection();
+$userManager = OC::$server->getUserManager();
+$shareManager = \OC::$server->getShareManager();
+
+/** @var Symfony\Component\Console\Application $application */
+$application->add(new OCA\Files\Command\Scan($userManager));
+$application->add(new OCA\Files\Command\DeleteOrphanedFiles($dbConnection));
+$application->add(new OCA\Files\Command\TransferOwnership($userManager, $shareManager));
diff --git a/apps/files/command/transferownership.php b/apps/files/command/transferownership.php
new file mode 100644
index 00000000000..4cc2f34c3a3
--- /dev/null
+++ b/apps/files/command/transferownership.php
@@ -0,0 +1,225 @@
+<?php
+/**
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @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/>
+ *
+ */
+
+namespace OCA\Files\Command;
+
+use OC\Files\Filesystem;
+use OC\Files\View;
+use OCP\Files\FileInfo;
+use OCP\Files\Folder;
+use OCP\IUserManager;
+use OCP\Share\IManager;
+use OCP\Share\IShare;
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Helper\ProgressBar;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+
+class TransferOwnership extends Command {
+
+ /** @var IUserManager $userManager */
+ private $userManager;
+
+ /** @var IManager */
+ private $shareManager;
+
+ /** @var FileInfo[] */
+ private $allFiles = [];
+
+ /** @var FileInfo[] */
+ private $encryptedFiles = [];
+
+ /** @var IShare[] */
+ private $shares = [];
+
+ /** @var string */
+ private $sourceUser;
+
+ /** @var string */
+ private $destinationUser;
+
+ /** @var string */
+ private $finalTarget;
+
+ public function __construct(IUserManager $userManager, IManager $shareManager) {
+ $this->userManager = $userManager;
+ $this->shareManager = $shareManager;
+ parent::__construct();
+ }
+
+ protected function configure() {
+ $this
+ ->setName('files:transfer-ownership')
+ ->setDescription('All files and folders are move to another user - shares are moved as well.')
+ ->addArgument(
+ 'source-user',
+ InputArgument::REQUIRED,
+ 'owner of files which shall be moved'
+ )
+ ->addArgument(
+ 'destination-user',
+ InputArgument::REQUIRED,
+ 'user who will be the new owner of the files'
+ );
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output) {
+ $this->sourceUser = $input->getArgument('source-user');
+ $this->destinationUser = $input->getArgument('destination-user');
+ if (!$this->userManager->userExists($this->sourceUser)) {
+ $output->writeln("<error>Unknown source user $this->sourceUser</error>");
+ return;
+ }
+ if (!$this->userManager->userExists($this->destinationUser)) {
+ $output->writeln("<error>Unknown destination user $this->destinationUser</error>");
+ return;
+ }
+
+ $date = date('c');
+ $this->finalTarget = "$this->destinationUser/files/transferred from $this->sourceUser on $date";
+
+ // setup filesystem
+ Filesystem::initMountPoints($this->sourceUser);
+ Filesystem::initMountPoints($this->destinationUser);
+
+ // analyse source folder
+ $this->analyse($output);
+
+ // collect all the shares
+ $this->collectUsersShares($output);
+
+ // transfer the files
+ $this->transfer($output);
+
+ // restore the shares
+ $this->restoreShares($output);
+ }
+
+ private function walkFiles(View $view, $path, \Closure $callBack) {
+ foreach ($view->getDirectoryContent($path) as $fileInfo) {
+ if (!$callBack($fileInfo)) {
+ return;
+ }
+ if ($fileInfo->getType() === FileInfo::TYPE_FOLDER) {
+ $this->walkFiles($view, $fileInfo->getPath(), $callBack);
+ }
+ }
+ }
+
+ /**
+ * @param OutputInterface $output
+ * @throws \Exception
+ */
+ protected function analyse(OutputInterface $output) {
+ $view = new View();
+ $output->writeln("Analysing files of $this->sourceUser ...");
+ $progress = new ProgressBar($output);
+ $progress->start();
+ $self = $this;
+ $this->walkFiles($view, "$this->sourceUser/files",
+ function (FileInfo $fileInfo) use ($progress, $self) {
+ if ($fileInfo->getType() === FileInfo::TYPE_FOLDER) {
+ return true;
+ }
+ $progress->advance();
+ $this->allFiles[] = $fileInfo;
+ if ($fileInfo->isEncrypted()) {
+ $this->encryptedFiles[] = $fileInfo;
+ }
+ return true;
+ });
+ $progress->finish();
+ $output->writeln('');
+
+ // no file is allowed to be encrypted
+ if (!empty($this->encryptedFiles)) {
+ $output->writeln("<error>Some files are encrypted - please decrypt them first</error>");
+ foreach($this->encryptedFiles as $encryptedFile) {
+ /** @var FileInfo $encryptedFile */
+ $output->writeln(" " . $encryptedFile->getPath());
+ }
+ throw new \Exception('Execution terminated.');
+ }
+
+ }
+
+ /**
+ * @param OutputInterface $output
+ */
+ private function collectUsersShares(OutputInterface $output) {
+ $output->writeln("Collecting all share information for files and folder of $this->sourceUser ...");
+
+ $progress = new ProgressBar($output, count($this->shares));
+ foreach([\OCP\Share::SHARE_TYPE_USER, \OCP\Share::SHARE_TYPE_GROUP, \OCP\Share::SHARE_TYPE_LINK, \OCP\Share::SHARE_TYPE_REMOTE] as $shareType) {
+ $offset = 0;
+ while (true) {
+ $sharePage = $this->shareManager->getSharesBy($this->sourceUser, $shareType, null, true, 50, $offset);
+ $progress->advance(count($sharePage));
+ if (empty($sharePage)) {
+ break;
+ }
+ $this->shares = array_merge($this->shares, $sharePage);
+ $offset += 50;
+ }
+ }
+
+ $progress->finish();
+ $output->writeln('');
+ }
+
+ /**
+ * @param OutputInterface $output
+ */
+ protected function transfer(OutputInterface $output) {
+ $view = new View();
+ $output->writeln("Transferring files to $this->finalTarget ...");
+ $view->rename("$this->sourceUser/files", $this->finalTarget);
+ // because the files folder is moved away we need to recreate it
+ $view->mkdir("$this->sourceUser/files");
+ }
+
+ /**
+ * @param OutputInterface $output
+ */
+ private function restoreShares(OutputInterface $output) {
+ $output->writeln("Restoring shares ...");
+ $progress = new ProgressBar($output, count($this->shares));
+
+ foreach($this->shares as $share) {
+ if ($share->getSharedWith() === $this->destinationUser) {
+ $this->shareManager->deleteShare($share);
+ } else {
+ if ($share->getShareOwner() === $this->sourceUser) {
+ $share->setShareOwner($this->destinationUser);
+ }
+ if ($share->getSharedBy() === $this->sourceUser) {
+ $share->setSharedBy($this->destinationUser);
+ }
+
+ $this->shareManager->updateShare($share);
+ }
+ $progress->advance();
+ }
+ $progress->finish();
+ $output->writeln('');
+ }
+}
diff --git a/apps/updatenotification/appinfo/app.php b/apps/updatenotification/appinfo/app.php
new file mode 100644
index 00000000000..d5e973be528
--- /dev/null
+++ b/apps/updatenotification/appinfo/app.php
@@ -0,0 +1,39 @@
+<?php
+/**
+ * @author Lukas Reschke <lukas@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @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/>
+ *
+ */
+
+if(\OC::$server->getConfig()->getSystemValue('updatechecker', true) === true) {
+ $updater = new \OC\Updater(
+ \OC::$server->getHTTPHelper(),
+ \OC::$server->getConfig(),
+ \OC::$server->getIntegrityCodeChecker()
+ );
+ $updateChecker = new \OCA\UpdateNotification\UpdateChecker(
+ $updater
+ );
+
+ $userObject = \OC::$server->getUserSession()->getUser();
+ if($userObject !== null) {
+ if(\OC::$server->getGroupManager()->isAdmin($userObject->getUID()) && $updateChecker->getUpdateState() !== []) {
+ \OCP\Util::addScript('updatenotification', 'notification');
+ OC_Hook::connect('\OCP\Config', 'js', $updateChecker, 'getJavaScript');
+ }
+ }
+}
diff --git a/apps/updatenotification/appinfo/info.xml b/apps/updatenotification/appinfo/info.xml
new file mode 100644
index 00000000000..0bfdd861a2f
--- /dev/null
+++ b/apps/updatenotification/appinfo/info.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0"?>
+<info>
+ <id>updatenotification</id>
+ <name>Update notification</name>
+ <description>Displays update notifications for ownCloud.</description>
+ <licence>AGPL</licence>
+ <author>Lukas Reschke</author>
+ <version>0.1.0</version>
+ <default_enable/>
+ <dependencies>
+ <owncloud min-version="9.0" max-version="9.0" />
+ </dependencies>
+</info>
diff --git a/core/js/update-notification.js b/apps/updatenotification/js/notification.js
index 42baa7f4c28..9d22bcb2309 100644
--- a/core/js/update-notification.js
+++ b/apps/updatenotification/js/notification.js
@@ -15,8 +15,8 @@
*/
$(document).ready(function(){
var head = $('html > head'),
- version = head.data('update-version'),
- docLink = head.data('update-link'),
+ version = oc_updateState.updateVersion,
+ docLink = oc_updateState.updateLink,
text = t('core', '{version} is available. Get more information on how to update.', {version: version}),
element = $('<a>').attr('href', docLink).text(text);
diff --git a/apps/updatenotification/lib/updatechecker.php b/apps/updatenotification/lib/updatechecker.php
new file mode 100644
index 00000000000..965e21617e7
--- /dev/null
+++ b/apps/updatenotification/lib/updatechecker.php
@@ -0,0 +1,67 @@
+<?php
+/**
+ * @author Lukas Reschke <lukas@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @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/>
+ *
+ */
+
+namespace OCA\UpdateNotification;
+
+use OC\Updater;
+
+class UpdateChecker {
+ /** @var Updater */
+ private $updater;
+
+ /**
+ * @param Updater $updater
+ */
+ public function __construct(Updater $updater) {
+ $this->updater = $updater;
+ }
+
+ /**
+ * @return array
+ */
+ public function getUpdateState() {
+ $data = $this->updater->check();
+ $result = [];
+
+ if(isset($data['version']) && $data['version'] !== '' && $data['version'] !== []) {
+ $result['updateAvailable'] = true;
+ $result['updateVersion'] = $data['versionstring'];
+ if(substr($data['web'], 0, 8) === 'https://') {
+ $result['updateLink'] = $data['web'];
+ }
+
+ return $result;
+ }
+
+ return [];
+ }
+
+ /**
+ * @param array $data
+ */
+ public function getJavaScript(array $data) {
+ $data['array']['oc_updateState'] = json_encode([
+ 'updateAvailable' => true,
+ 'updateVersion' => $this->getUpdateState()['updateVersion'],
+ 'updateLink' => isset($this->getUpdateState()['updateLink']) ? $this->getUpdateState()['updateLink'] : '',
+ ]);
+ }
+}
diff --git a/apps/updatenotification/tests/UpdateCheckerTest.php b/apps/updatenotification/tests/UpdateCheckerTest.php
new file mode 100644
index 00000000000..9591758c4c9
--- /dev/null
+++ b/apps/updatenotification/tests/UpdateCheckerTest.php
@@ -0,0 +1,86 @@
+<?php
+/**
+ * @author Lukas Reschke <lukas@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @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/>
+ *
+ */
+
+namespace OCA\UpdateNotification\Tests;
+
+use OC\Updater;
+use OCA\UpdateNotification\UpdateChecker;
+use Test\TestCase;
+
+class UpdateCheckerTest extends TestCase {
+ /** @var Updater */
+ private $updater;
+ /** @var UpdateChecker */
+ private $updateChecker;
+
+ public function setUp() {
+ parent::setUp();
+
+ $this->updater = $this->getMockBuilder('\OC\Updater')
+ ->disableOriginalConstructor()->getMock();
+ $this->updateChecker = new UpdateChecker($this->updater);
+ }
+
+ public function testGetUpdateStateWithUpdateAndInvalidLink() {
+ $this->updater
+ ->expects($this->once())
+ ->method('check')
+ ->willReturn([
+ 'version' => 123,
+ 'versionstring' => 'ownCloud 123',
+ 'web'=> 'javascript:alert(1)',
+ ]);
+
+ $expected = [
+ 'updateAvailable' => true,
+ 'updateVersion' => 'ownCloud 123',
+ ];
+ $this->assertSame($expected, $this->updateChecker->getUpdateState());
+ }
+
+ public function testGetUpdateStateWithUpdateAndValidLink() {
+ $this->updater
+ ->expects($this->once())
+ ->method('check')
+ ->willReturn([
+ 'version' => 123,
+ 'versionstring' => 'ownCloud 123',
+ 'web'=> 'https://owncloud.org/myUrl',
+ ]);
+
+ $expected = [
+ 'updateAvailable' => true,
+ 'updateVersion' => 'ownCloud 123',
+ 'updateLink' => 'https://owncloud.org/myUrl',
+ ];
+ $this->assertSame($expected, $this->updateChecker->getUpdateState());
+ }
+
+ public function testGetUpdateStateWithoutUpdate() {
+ $this->updater
+ ->expects($this->once())
+ ->method('check')
+ ->willReturn([]);
+
+ $expected = [];
+ $this->assertSame($expected, $this->updateChecker->getUpdateState());
+ }
+}
diff --git a/build/integration/features/provisioning-v1.feature b/build/integration/features/provisioning-v1.feature
index af177b713dd..04a706f387b 100644
--- a/build/integration/features/provisioning-v1.feature
+++ b/build/integration/features/provisioning-v1.feature
@@ -291,6 +291,7 @@ Feature: provisioning
| files_versions |
| provisioning_api |
| systemtags |
+ | updatenotification |
Scenario: get app info
Given As an "admin"
diff --git a/core/shipped.json b/core/shipped.json
index b74f2f28c47..d15f3ba3ca3 100644
--- a/core/shipped.json
+++ b/core/shipped.json
@@ -31,7 +31,7 @@
"sharepoint",
"systemtags",
"templateeditor",
- "updater",
+ "updatenotification",
"user_external",
"user_ldap",
"user_shibboleth",
diff --git a/core/templates/layout.user.php b/core/templates/layout.user.php
index 7905f5b7f3a..f79defe100e 100644
--- a/core/templates/layout.user.php
+++ b/core/templates/layout.user.php
@@ -2,11 +2,7 @@
<!--[if lte IE 8]><html class="ng-csp ie ie8 lte9 lte8" data-placeholder-focus="false" lang="<?php p($_['language']); ?>" ><![endif]-->
<!--[if IE 9]><html class="ng-csp ie ie9 lte9" data-placeholder-focus="false" lang="<?php p($_['language']); ?>" ><![endif]-->
<!--[if (gt IE 9)|!(IE)]><!--><html class="ng-csp" data-placeholder-focus="false" lang="<?php p($_['language']); ?>" ><!--<![endif]-->
- <head data-user="<?php p($_['user_uid']); ?>" data-user-displayname="<?php p($_['user_displayname']); ?>" data-requesttoken="<?php p($_['requesttoken']); ?>"
- <?php if ($_['updateAvailable']): ?>
- data-update-version="<?php p($_['updateVersion']); ?>" data-update-link="<?php p($_['updateLink']); ?>"
- <?php endif; ?>
- >
+ <head data-user="<?php p($_['user_uid']); ?>" data-user-displayname="<?php p($_['user_displayname']); ?>" data-requesttoken="<?php p($_['requesttoken']); ?>">
<meta charset="utf-8">
<title>
<?php
diff --git a/lib/private/comments/comment.php b/lib/private/comments/comment.php
index 36189d9523b..27e63c98555 100644
--- a/lib/private/comments/comment.php
+++ b/lib/private/comments/comment.php
@@ -22,6 +22,7 @@ namespace OC\Comments;
use OCP\Comments\IComment;
use OCP\Comments\IllegalIDChangeException;
+use OCP\Comments\MessageTooLongException;
class Comment implements IComment {
@@ -184,13 +185,18 @@ class Comment implements IComment {
*
* @param string $message
* @return IComment
+ * @throws MessageTooLongException
* @since 9.0.0
*/
public function setMessage($message) {
if(!is_string($message)) {
throw new \InvalidArgumentException('String expected.');
}
- $this->data['message'] = trim($message);
+ $message = trim($message);
+ if(mb_strlen($message, 'UTF-8') > IComment::MAX_MESSAGE_LENGTH) {
+ throw new MessageTooLongException('Comment message must not exceed ' . IComment::MAX_MESSAGE_LENGTH . ' characters');
+ }
+ $this->data['message'] = $message;
return $this;
}
diff --git a/lib/private/templatelayout.php b/lib/private/templatelayout.php
index bc66c0dfb1e..7166b23d4c2 100644
--- a/lib/private/templatelayout.php
+++ b/lib/private/templatelayout.php
@@ -70,31 +70,6 @@ class TemplateLayout extends \OC_Template {
$this->assign('bodyid', 'body-user');
}
- // Update notification
- if($this->config->getSystemValue('updatechecker', true) === true &&
- \OC_User::isAdminUser(\OC_User::getUser())) {
- $updater = new \OC\Updater(
- \OC::$server->getHTTPHelper(),
- \OC::$server->getConfig(),
- \OC::$server->getIntegrityCodeChecker(),
- \OC::$server->getLogger()
- );
- $data = $updater->check();
-
- if(isset($data['version']) && $data['version'] != '' and $data['version'] !== Array()) {
- $this->assign('updateAvailable', true);
- $this->assign('updateVersion', $data['versionstring']);
- if(substr($data['web'], 0, 8) === 'https://') {
- $this->assign('updateLink', $data['web']);
- }
- \OCP\Util::addScript('core', 'update-notification');
- } else {
- $this->assign('updateAvailable', false); // No update available or not an admin user
- }
- } else {
- $this->assign('updateAvailable', false); // Update check is disabled
- }
-
// Code integrity notification
$integrityChecker = \OC::$server->getIntegrityCodeChecker();
if(!$integrityChecker->hasPassedCheck()) {
diff --git a/lib/public/comments/icomment.php b/lib/public/comments/icomment.php
index e695b5193f2..a7f4b4c6171 100644
--- a/lib/public/comments/icomment.php
+++ b/lib/public/comments/icomment.php
@@ -29,6 +29,7 @@ namespace OCP\Comments;
* @since 9.0.0
*/
interface IComment {
+ const MAX_MESSAGE_LENGTH = 1000;
/**
* returns the ID of the comment
@@ -119,8 +120,12 @@ interface IComment {
/**
* sets the message of the comment and returns itself
*
+ * When the given message length exceeds MAX_MESSAGE_LENGTH an
+ * MessageTooLongException shall be thrown.
+ *
* @param string $message
* @return IComment
+ * @throws MessageTooLongException
* @since 9.0.0
*/
public function setMessage($message);
diff --git a/lib/public/comments/messagetoolongexception.php b/lib/public/comments/messagetoolongexception.php
new file mode 100644
index 00000000000..054cecf320f
--- /dev/null
+++ b/lib/public/comments/messagetoolongexception.php
@@ -0,0 +1,27 @@
+<?php
+/**
+ * @author Arthur Schiwon <blizzz@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @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/>
+ *
+ */
+namespace OCP\Comments;
+
+/**
+ * Exception thrown when a comment message exceeds the allowed character limit
+ * @since 9.0.0
+ */
+class MessageTooLongException extends \OverflowException {}
diff --git a/tests/lib/comments/comment.php b/tests/lib/comments/comment.php
index e6f9c941c96..9b3f2ab166e 100644
--- a/tests/lib/comments/comment.php
+++ b/tests/lib/comments/comment.php
@@ -2,6 +2,7 @@
namespace Test\Comments;
+use OCP\Comments\IComment;
use Test\TestCase;
class Test_Comments_Comment extends TestCase
@@ -107,6 +108,15 @@ class Test_Comments_Comment extends TestCase
$comment->$setter($type, $id);
}
+ /**
+ * @expectedException \OCP\Comments\MessageTooLongException
+ */
+ public function testSetUberlongMessage() {
+ $comment = new \OC\Comments\Comment();
+ $msg = str_pad('', IComment::MAX_MESSAGE_LENGTH + 1, 'x');
+ $comment->setMessage($msg);
+ }
+
}