summaryrefslogtreecommitdiffstats
path: root/apps/dav
diff options
context:
space:
mode:
Diffstat (limited to 'apps/dav')
-rw-r--r--apps/dav/appinfo/application.php42
-rw-r--r--apps/dav/appinfo/install.php1
-rw-r--r--apps/dav/appinfo/register_command.php3
-rw-r--r--apps/dav/appinfo/v1/publicwebdav.php8
-rw-r--r--apps/dav/command/migrateaddressbooks.php1
-rw-r--r--apps/dav/command/migratecalendars.php66
-rw-r--r--apps/dav/lib/caldav/caldavbackend.php124
-rw-r--r--apps/dav/lib/comments/commentnode.php7
-rw-r--r--apps/dav/lib/comments/commentsplugin.php3
-rw-r--r--apps/dav/lib/connector/sabre/checksumlist.php71
-rw-r--r--apps/dav/lib/connector/sabre/filesplugin.php12
-rw-r--r--apps/dav/lib/connector/sabre/filesreportplugin.php332
-rw-r--r--apps/dav/lib/connector/sabre/principal.php18
-rw-r--r--apps/dav/lib/connector/sabre/serverfactory.php13
-rw-r--r--apps/dav/lib/files/sharing/publiclinkcheckplugin.php63
-rw-r--r--apps/dav/lib/migration/calendaradapter.php83
-rw-r--r--apps/dav/lib/migration/migratecalendars.php94
-rw-r--r--apps/dav/tests/unit/comments/commentnode.php39
-rw-r--r--apps/dav/tests/unit/comments/commentsplugin.php93
-rw-r--r--apps/dav/tests/unit/connector/sabre/filesreportplugin.php602
-rw-r--r--apps/dav/tests/unit/connector/sabre/principal.php14
-rw-r--r--apps/dav/tests/unit/migration/calendar_schema.xml191
-rw-r--r--apps/dav/tests/unit/migration/calendaradaptertest.php131
-rw-r--r--apps/dav/tests/unit/migration/migratecalendartest.php76
24 files changed, 2057 insertions, 30 deletions
diff --git a/apps/dav/appinfo/application.php b/apps/dav/appinfo/application.php
index 07905db7368..11ab384d75d 100644
--- a/apps/dav/appinfo/application.php
+++ b/apps/dav/appinfo/application.php
@@ -20,12 +20,16 @@
*/
namespace OCA\Dav\AppInfo;
+use OCA\DAV\CalDAV\CalDavBackend;
+use OCA\DAV\CardDAV\CardDavBackend;
use OCA\DAV\CardDAV\ContactsManager;
use OCA\DAV\CardDAV\SyncJob;
use OCA\DAV\CardDAV\SyncService;
use OCA\DAV\HookManager;
use OCA\Dav\Migration\AddressBookAdapter;
+use OCA\Dav\Migration\CalendarAdapter;
use OCA\Dav\Migration\MigrateAddressbooks;
+use OCA\Dav\Migration\MigrateCalendars;
use \OCP\AppFramework\App;
use OCP\AppFramework\IAppContainer;
use OCP\Contacts\IManager;
@@ -73,7 +77,17 @@ class Application extends App {
$c->getServer()->getUserManager(),
$c->getServer()->getGroupManager()
);
- return new \OCA\DAV\CardDAV\CardDavBackend($db, $principal, $logger);
+ return new CardDavBackend($db, $principal, $logger);
+ });
+
+ $container->registerService('CalDavBackend', function($c) {
+ /** @var IAppContainer $c */
+ $db = $c->getServer()->getDatabaseConnection();
+ $principal = new \OCA\DAV\Connector\Sabre\Principal(
+ $c->getServer()->getUserManager(),
+ $c->getServer()->getGroupManager()
+ );
+ return new CalDavBackend($db, $principal);
});
$container->registerService('MigrateAddressbooks', function($c) {
@@ -84,6 +98,15 @@ class Application extends App {
$c->query('CardDavBackend')
);
});
+
+ $container->registerService('MigrateCalendars', function($c) {
+ /** @var IAppContainer $c */
+ $db = $c->getServer()->getDatabaseConnection();
+ return new MigrateCalendars(
+ new CalendarAdapter($db),
+ $c->query('CalDavBackend')
+ );
+ });
}
/**
@@ -112,8 +135,8 @@ class Application extends App {
}
public function migrateAddressbooks() {
-
try {
+ /** @var MigrateAddressbooks $migration */
$migration = $this->getContainer()->query('MigrateAddressbooks');
$migration->setup();
$userManager = $this->getContainer()->getServer()->getUserManager();
@@ -127,4 +150,19 @@ class Application extends App {
}
}
+ public function migrateCalendars() {
+ try {
+ /** @var MigrateCalendars $migration */
+ $migration = $this->getContainer()->query('MigrateCalendars');
+ $migration->setup();
+ $userManager = $this->getContainer()->getServer()->getUserManager();
+
+ $userManager->callForAllUsers(function($user) use($migration) {
+ /** @var IUser $user */
+ $migration->migrateForUser($user->getUID());
+ });
+ } catch (\Exception $ex) {
+ $this->getContainer()->getServer()->getLogger()->logException($ex);
+ }
+ }
}
diff --git a/apps/dav/appinfo/install.php b/apps/dav/appinfo/install.php
index f6ef533958e..a7a3220b90f 100644
--- a/apps/dav/appinfo/install.php
+++ b/apps/dav/appinfo/install.php
@@ -24,3 +24,4 @@ use OCA\Dav\AppInfo\Application;
$app = new Application();
$app->setupCron();
$app->migrateAddressbooks();
+$app->migrateCalendars();
diff --git a/apps/dav/appinfo/register_command.php b/apps/dav/appinfo/register_command.php
index e8ca370f84f..4981cab9264 100644
--- a/apps/dav/appinfo/register_command.php
+++ b/apps/dav/appinfo/register_command.php
@@ -23,6 +23,7 @@ use OCA\Dav\AppInfo\Application;
use OCA\DAV\Command\CreateAddressBook;
use OCA\DAV\Command\CreateCalendar;
use OCA\Dav\Command\MigrateAddressbooks;
+use OCA\Dav\Command\MigrateCalendars;
use OCA\DAV\Command\SyncSystemAddressBook;
$config = \OC::$server->getConfig();
@@ -44,4 +45,6 @@ if ($config->getSystemValue('debug', false)){
$app = new \OCA\Dav\AppInfo\Application();
$migration = $app->getContainer()->query('MigrateAddressbooks');
$application->add(new MigrateAddressbooks($userManager, $migration));
+ $migration = $app->getContainer()->query('MigrateCalendars');
+ $application->add(new MigrateCalendars($userManager, $migration));
}
diff --git a/apps/dav/appinfo/v1/publicwebdav.php b/apps/dav/appinfo/v1/publicwebdav.php
index 6ddb570aca8..b0ee264aac3 100644
--- a/apps/dav/appinfo/v1/publicwebdav.php
+++ b/apps/dav/appinfo/v1/publicwebdav.php
@@ -46,7 +46,9 @@ $serverFactory = new OCA\DAV\Connector\Sabre\ServerFactory(
$requestUri = \OC::$server->getRequest()->getRequestUri();
-$server = $serverFactory->createServer($baseuri, $requestUri, $authBackend, function () use ($authBackend) {
+$linkCheckPlugin = new \OCA\DAV\Files\Sharing\PublicLinkCheckPlugin();
+
+$server = $serverFactory->createServer($baseuri, $requestUri, $authBackend, function (\Sabre\DAV\Server $server) use ($authBackend, $linkCheckPlugin) {
$isAjax = (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] === 'XMLHttpRequest');
if (OCA\Files_Sharing\Helper::isOutgoingServer2serverShareEnabled() === false && !$isAjax) {
// this is what is thrown when trying to access a non-existing share
@@ -68,9 +70,13 @@ $server = $serverFactory->createServer($baseuri, $requestUri, $authBackend, func
OC_Util::setupFS($owner);
$ownerView = \OC\Files\Filesystem::getView();
$path = $ownerView->getPath($fileId);
+ $fileInfo = $ownerView->getFileInfo($path);
+ $linkCheckPlugin->setFileInfo($fileInfo);
return new \OC\Files\View($ownerView->getAbsolutePath($path));
});
+$server->addPlugin($linkCheckPlugin);
+
// And off we go!
$server->exec();
diff --git a/apps/dav/command/migrateaddressbooks.php b/apps/dav/command/migrateaddressbooks.php
index 2ab7113ab1f..f37c29e7ab3 100644
--- a/apps/dav/command/migrateaddressbooks.php
+++ b/apps/dav/command/migrateaddressbooks.php
@@ -68,6 +68,7 @@ class MigrateAddressbooks extends Command {
}
$output->writeln("Start migration for $user");
$this->service->migrateForUser($user);
+ return;
}
$output->writeln("Start migration of all known users ...");
$p = new ProgressBar($output);
diff --git a/apps/dav/command/migratecalendars.php b/apps/dav/command/migratecalendars.php
new file mode 100644
index 00000000000..eda4f5fb417
--- /dev/null
+++ b/apps/dav/command/migratecalendars.php
@@ -0,0 +1,66 @@
+<?php
+
+namespace OCA\Dav\Command;
+
+use OCP\IUser;
+use OCP\IUserManager;
+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 MigrateCalendars extends Command {
+
+ /** @var IUserManager */
+ protected $userManager;
+
+ /** @var \OCA\Dav\Migration\MigrateCalendars */
+ private $service;
+
+ /**
+ * @param IUserManager $userManager
+ * @param \OCA\Dav\Migration\MigrateCalendars $service
+ */
+ function __construct(IUserManager $userManager,
+ \OCA\Dav\Migration\MigrateCalendars $service
+ ) {
+ parent::__construct();
+ $this->userManager = $userManager;
+ $this->service = $service;
+ }
+
+ protected function configure() {
+ $this
+ ->setName('dav:migrate-calendars')
+ ->setDescription('Migrate calendars from the calendar app to core')
+ ->addArgument('user',
+ InputArgument::OPTIONAL,
+ 'User for whom all calendars will be migrated');
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output) {
+ $this->service->setup();
+
+ if ($input->hasArgument('user')) {
+ $user = $input->getArgument('user');
+ if (!$this->userManager->userExists($user)) {
+ throw new \InvalidArgumentException("User <$user> in unknown.");
+ }
+ $output->writeln("Start migration for $user");
+ $this->service->migrateForUser($user);
+ return;
+ }
+ $output->writeln("Start migration of all known users ...");
+ $p = new ProgressBar($output);
+ $p->start();
+ $this->userManager->callForAllUsers(function($user) use ($p) {
+ $p->advance();
+ /** @var IUser $user */
+ $this->service->migrateForUser($user->getUID());
+ });
+
+ $p->finish();
+ $output->writeln('');
+ }
+}
diff --git a/apps/dav/lib/caldav/caldavbackend.php b/apps/dav/lib/caldav/caldavbackend.php
index 52b4812b05b..775612487f9 100644
--- a/apps/dav/lib/caldav/caldavbackend.php
+++ b/apps/dav/lib/caldav/caldavbackend.php
@@ -22,9 +22,11 @@
namespace OCA\DAV\CalDAV;
+use OCA\DAV\DAV\Sharing\IShareable;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCA\DAV\Connector\Sabre\Principal;
use OCA\DAV\DAV\Sharing\Backend;
+use OCP\IDBConnection;
use Sabre\CalDAV\Backend\AbstractBackend;
use Sabre\CalDAV\Backend\SchedulingSupport;
use Sabre\CalDAV\Backend\SubscriptionSupport;
@@ -59,7 +61,7 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription
const MAX_DATE = '2038-01-01';
/**
- * List of CalDAV properties, and how they map to database fieldnames
+ * List of CalDAV properties, and how they map to database field names
* Add your own properties by simply adding on to this array.
*
* Note that only string-based properties are supported here.
@@ -75,7 +77,7 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription
];
/**
- * List of subscription properties, and how they map to database fieldnames.
+ * List of subscription properties, and how they map to database field names.
*
* @var array
*/
@@ -89,7 +91,7 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription
'{http://calendarserver.org/ns/}subscribed-strip-attachments' => 'stripattachments',
];
- /** @var \OCP\IDBConnection */
+ /** @var IDBConnection */
private $db;
/** @var Backend */
@@ -101,9 +103,10 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription
/**
* CalDavBackend constructor.
*
- * @param \OCP\IDBConnection $db
+ * @param IDBConnection $db
+ * @param Principal $principalBackend
*/
- public function __construct(\OCP\IDBConnection $db, Principal $principalBackend) {
+ public function __construct(IDBConnection $db, Principal $principalBackend) {
$this->db = $db;
$this->principalBackend = $principalBackend;
$this->sharingBackend = new Backend($this->db, $principalBackend, 'calendar');
@@ -232,6 +235,95 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription
return array_values($calendars);
}
+ public function getCalendarByUri($principal, $uri) {
+ $fields = array_values($this->propertyMap);
+ $fields[] = 'id';
+ $fields[] = 'uri';
+ $fields[] = 'synctoken';
+ $fields[] = 'components';
+ $fields[] = 'principaluri';
+ $fields[] = 'transparent';
+
+ // Making fields a comma-delimited list
+ $query = $this->db->getQueryBuilder();
+ $query->select($fields)->from('calendars')
+ ->where($query->expr()->eq('uri', $query->createNamedParameter($uri)))
+ ->andWhere($query->expr()->eq('principaluri', $query->createNamedParameter($principal)))
+ ->setMaxResults(1);
+ $stmt = $query->execute();
+
+ $row = $stmt->fetch(\PDO::FETCH_ASSOC);
+ $stmt->closeCursor();
+ if ($row === false) {
+ return null;
+ }
+
+ $components = [];
+ if ($row['components']) {
+ $components = explode(',',$row['components']);
+ }
+
+ $calendar = [
+ 'id' => $row['id'],
+ 'uri' => $row['uri'],
+ 'principaluri' => $row['principaluri'],
+ '{' . Plugin::NS_CALENDARSERVER . '}getctag' => 'http://sabre.io/ns/sync/' . ($row['synctoken']?$row['synctoken']:'0'),
+ '{http://sabredav.org/ns}sync-token' => $row['synctoken']?$row['synctoken']:'0',
+ '{' . Plugin::NS_CALDAV . '}supported-calendar-component-set' => new SupportedCalendarComponentSet($components),
+ '{' . Plugin::NS_CALDAV . '}schedule-calendar-transp' => new ScheduleCalendarTransp($row['transparent']?'transparent':'opaque'),
+ ];
+
+ foreach($this->propertyMap as $xmlName=>$dbName) {
+ $calendar[$xmlName] = $row[$dbName];
+ }
+
+ return $calendar;
+ }
+
+ public function getCalendarById($calendarId) {
+ $fields = array_values($this->propertyMap);
+ $fields[] = 'id';
+ $fields[] = 'uri';
+ $fields[] = 'synctoken';
+ $fields[] = 'components';
+ $fields[] = 'principaluri';
+ $fields[] = 'transparent';
+
+ // Making fields a comma-delimited list
+ $query = $this->db->getQueryBuilder();
+ $query->select($fields)->from('calendars')
+ ->where($query->expr()->eq('id', $query->createNamedParameter($calendarId)))
+ ->setMaxResults(1);
+ $stmt = $query->execute();
+
+ $row = $stmt->fetch(\PDO::FETCH_ASSOC);
+ $stmt->closeCursor();
+ if ($row === false) {
+ return null;
+ }
+
+ $components = [];
+ if ($row['components']) {
+ $components = explode(',',$row['components']);
+ }
+
+ $calendar = [
+ 'id' => $row['id'],
+ 'uri' => $row['uri'],
+ 'principaluri' => $row['principaluri'],
+ '{' . Plugin::NS_CALENDARSERVER . '}getctag' => 'http://sabre.io/ns/sync/' . ($row['synctoken']?$row['synctoken']:'0'),
+ '{http://sabredav.org/ns}sync-token' => $row['synctoken']?$row['synctoken']:'0',
+ '{' . Plugin::NS_CALDAV . '}supported-calendar-component-set' => new SupportedCalendarComponentSet($components),
+ '{' . Plugin::NS_CALDAV . '}schedule-calendar-transp' => new ScheduleCalendarTransp($row['transparent']?'transparent':'opaque'),
+ ];
+
+ foreach($this->propertyMap as $xmlName=>$dbName) {
+ $calendar[$xmlName] = $row[$dbName];
+ }
+
+ return $calendar;
+ }
+
/**
* Creates a new calendar for a principal.
*
@@ -241,7 +333,7 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription
* @param string $principalUri
* @param string $calendarUri
* @param array $properties
- * @return void
+ * @return int
*/
function createCalendar($principalUri, $calendarUri, array $properties) {
$values = [
@@ -278,6 +370,7 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription
$query->setValue($column, $query->createNamedParameter($value));
}
$query->execute();
+ return $query->getLastInsertId();
}
/**
@@ -1249,16 +1342,29 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription
return $cardData;
}
+ /**
+ * @param IShareable $shareable
+ * @param array $add
+ * @param array $remove
+ */
public function updateShares($shareable, $add, $remove) {
$this->sharingBackend->updateShares($shareable, $add, $remove);
}
+ /**
+ * @param int $resourceId
+ * @return array
+ */
public function getShares($resourceId) {
return $this->sharingBackend->getShares($resourceId);
}
- public function applyShareAcl($addressBookId, $acl) {
- return $this->sharingBackend->applyShareAcl($addressBookId, $acl);
+ /**
+ * @param int $resourceId
+ * @param array $acl
+ * @return array
+ */
+ public function applyShareAcl($resourceId, $acl) {
+ return $this->sharingBackend->applyShareAcl($resourceId, $acl);
}
-
}
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/lib/connector/sabre/checksumlist.php b/apps/dav/lib/connector/sabre/checksumlist.php
new file mode 100644
index 00000000000..f137222acca
--- /dev/null
+++ b/apps/dav/lib/connector/sabre/checksumlist.php
@@ -0,0 +1,71 @@
+<?php
+/**
+ * @author Roeland Jago Douma <rullzer@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\DAV\Connector\Sabre;
+
+use Sabre\Xml\XmlSerializable;
+use Sabre\Xml\Element;
+use Sabre\Xml\Writer;
+
+/**
+ * Checksumlist property
+ *
+ * This property contains multiple "checksum" elements, each containing a
+ * checksum name.
+ */
+class ChecksumList implements XmlSerializable {
+ const NS_OWNCLOUD = 'http://owncloud.org/ns';
+
+ /** @var string[] of TYPE:CHECKSUM */
+ private $checksums;
+
+ /**
+ * @param string $checksum
+ */
+ public function __construct($checksum) {
+ $this->checksums = explode(',', $checksum);
+ }
+
+ /**
+ * The xmlSerialize metod is called during xml writing.
+ *
+ * Use the $writer argument to write its own xml serialization.
+ *
+ * An important note: do _not_ create a parent element. Any element
+ * implementing XmlSerializble should only ever write what's considered
+ * its 'inner xml'.
+ *
+ * The parent of the current element is responsible for writing a
+ * containing element.
+ *
+ * This allows serializers to be re-used for different element names.
+ *
+ * If you are opening new elements, you must also close them again.
+ *
+ * @param Writer $writer
+ * @return void
+ */
+ function xmlSerialize(Writer $writer) {
+
+ foreach ($this->checksums as $checksum) {
+ $writer->writeElement('{' . self::NS_OWNCLOUD . '}checksum', $checksum);
+ }
+ }
+}
diff --git a/apps/dav/lib/connector/sabre/filesplugin.php b/apps/dav/lib/connector/sabre/filesplugin.php
index 82d00014905..2e913ee1077 100644
--- a/apps/dav/lib/connector/sabre/filesplugin.php
+++ b/apps/dav/lib/connector/sabre/filesplugin.php
@@ -47,7 +47,7 @@ class FilesPlugin extends \Sabre\DAV\ServerPlugin {
const LASTMODIFIED_PROPERTYNAME = '{DAV:}lastmodified';
const OWNER_ID_PROPERTYNAME = '{http://owncloud.org/ns}owner-id';
const OWNER_DISPLAY_NAME_PROPERTYNAME = '{http://owncloud.org/ns}owner-display-name';
- const CHECKSUM_PROPERTYNAME = '{http://owncloud.org/ns}checksum';
+ const CHECKSUMS_PROPERTYNAME = '{http://owncloud.org/ns}checksums';
/**
* Reference to main server object
@@ -108,7 +108,7 @@ class FilesPlugin extends \Sabre\DAV\ServerPlugin {
$server->protectedProperties[] = self::DOWNLOADURL_PROPERTYNAME;
$server->protectedProperties[] = self::OWNER_ID_PROPERTYNAME;
$server->protectedProperties[] = self::OWNER_DISPLAY_NAME_PROPERTYNAME;
- $server->protectedProperties[] = self::CHECKSUM_PROPERTYNAME;
+ $server->protectedProperties[] = self::CHECKSUMS_PROPERTYNAME;
// normally these cannot be changed (RFC4918), but we want them modifiable through PROPPATCH
$allowedProperties = ['{DAV:}getetag'];
@@ -248,13 +248,9 @@ class FilesPlugin extends \Sabre\DAV\ServerPlugin {
return false;
});
- $propFind->handle(self::CHECKSUM_PROPERTYNAME, function() use ($node) {
+ $propFind->handle(self::CHECKSUMS_PROPERTYNAME, function() use ($node) {
$checksum = $node->getChecksum();
-
- if ($checksum === null) {
- return '';
- }
- return $checksum;
+ return new ChecksumList($checksum);
});
}
diff --git a/apps/dav/lib/connector/sabre/filesreportplugin.php b/apps/dav/lib/connector/sabre/filesreportplugin.php
new file mode 100644
index 00000000000..141b684360e
--- /dev/null
+++ b/apps/dav/lib/connector/sabre/filesreportplugin.php
@@ -0,0 +1,332 @@
+<?php
+/**
+ * @author Vincent Petry <pvince81@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\DAV\Connector\Sabre;
+
+use OC\Files\View;
+use Sabre\DAV\Exception\NotFound;
+use Sabre\DAV\Exception\PreconditionFailed;
+use Sabre\DAV\Exception\ReportNotSupported;
+use Sabre\DAV\Exception\BadRequest;
+use Sabre\DAV\ServerPlugin;
+use Sabre\DAV\Tree;
+use Sabre\DAV\Xml\Element\Response;
+use Sabre\DAV\Xml\Response\MultiStatus;
+use Sabre\DAV\PropFind;
+use OCP\SystemTag\ISystemTagObjectMapper;
+use OCP\IUserSession;
+use OCP\Files\Folder;
+use OCP\IGroupManager;
+use OCP\SystemTag\ISystemTagManager;
+use OCP\SystemTag\TagNotFoundException;
+
+class FilesReportPlugin extends ServerPlugin {
+
+ // namespace
+ const NS_OWNCLOUD = 'http://owncloud.org/ns';
+ const REPORT_NAME = '{http://owncloud.org/ns}filter-files';
+ const SYSTEMTAG_PROPERTYNAME = '{http://owncloud.org/ns}systemtag';
+
+ /**
+ * Reference to main server object
+ *
+ * @var \Sabre\DAV\Server
+ */
+ private $server;
+
+ /**
+ * @var Tree
+ */
+ private $tree;
+
+ /**
+ * @var View
+ */
+ private $fileView;
+
+ /**
+ * @var ISystemTagManager
+ */
+ private $tagManager;
+
+ /**
+ * @var ISystemTagObjectMapper
+ */
+ private $tagMapper;
+
+ /**
+ * @var IUserSession
+ */
+ private $userSession;
+
+ /**
+ * @var IGroupManager
+ */
+ private $groupManager;
+
+ /**
+ * @var Folder
+ */
+ private $userFolder;
+
+ /**
+ * @param Tree $tree
+ * @param View $view
+ */
+ public function __construct(Tree $tree,
+ View $view,
+ ISystemTagManager $tagManager,
+ ISystemTagObjectMapper $tagMapper,
+ IUserSession $userSession,
+ IGroupManager $groupManager,
+ Folder $userFolder
+ ) {
+ $this->tree = $tree;
+ $this->fileView = $view;
+ $this->tagManager = $tagManager;
+ $this->tagMapper = $tagMapper;
+ $this->userSession = $userSession;
+ $this->groupManager = $groupManager;
+ $this->userFolder = $userFolder;
+ }
+
+ /**
+ * This initializes the plugin.
+ *
+ * This function is called by \Sabre\DAV\Server, after
+ * addPlugin is called.
+ *
+ * This method should set up the required event subscriptions.
+ *
+ * @param \Sabre\DAV\Server $server
+ * @return void
+ */
+ public function initialize(\Sabre\DAV\Server $server) {
+
+ $server->xml->namespaceMap[self::NS_OWNCLOUD] = 'oc';
+
+ $this->server = $server;
+ $this->server->on('report', array($this, 'onReport'));
+ }
+
+ /**
+ * Returns a list of reports this plugin supports.
+ *
+ * This will be used in the {DAV:}supported-report-set property.
+ *
+ * @param string $uri
+ * @return array
+ */
+ public function getSupportedReportSet($uri) {
+ return [self::REPORT_NAME];
+ }
+
+ /**
+ * REPORT operations to look for files
+ *
+ * @param string $reportName
+ * @param [] $report
+ * @param string $uri
+ * @return bool
+ * @throws NotFound
+ * @throws ReportNotSupported
+ */
+ public function onReport($reportName, $report, $uri) {
+ $reportTargetNode = $this->server->tree->getNodeForPath($uri);
+ if (!$reportTargetNode instanceof Directory || $reportName !== self::REPORT_NAME) {
+ throw new ReportNotSupported();
+ }
+
+ $ns = '{' . $this::NS_OWNCLOUD . '}';
+ $requestedProps = [];
+ $filterRules = [];
+
+ // parse report properties and gather filter info
+ foreach ($report as $reportProps) {
+ $name = $reportProps['name'];
+ if ($name === $ns . 'filter-rules') {
+ $filterRules = $reportProps['value'];
+ } else if ($name === '{DAV:}prop') {
+ // propfind properties
+ foreach ($reportProps['value'] as $propVal) {
+ $requestedProps[] = $propVal['name'];
+ }
+ }
+ }
+
+ if (empty($filterRules)) {
+ // an empty filter would return all existing files which would be slow
+ throw new BadRequest('Missing filter-rule block in request');
+ }
+
+ // gather all file ids matching filter
+ try {
+ $resultFileIds = $this->processFilterRules($filterRules);
+ } catch (TagNotFoundException $e) {
+ throw new PreconditionFailed('Cannot filter by non-existing tag', 0, $e);
+ }
+
+ // find sabre nodes by file id, restricted to the root node path
+ $results = $this->findNodesByFileIds($reportTargetNode, $resultFileIds);
+
+ $responses = $this->prepareResponses($requestedProps, $results);
+
+ $xml = $this->server->xml->write(
+ '{DAV:}multistatus',
+ new MultiStatus($responses)
+ );
+
+ $this->server->httpResponse->setStatus(207);
+ $this->server->httpResponse->setHeader('Content-Type', 'application/xml; charset=utf-8');
+ $this->server->httpResponse->setBody($xml);
+
+ return false;
+ }
+
+ /**
+ * Find file ids matching the given filter rules
+ *
+ * @param array $filterRules
+ * @return array array of unique file id results
+ *
+ * @throws TagNotFoundException whenever a tag was not found
+ */
+ public function processFilterRules($filterRules) {
+ $ns = '{' . $this::NS_OWNCLOUD . '}';
+ $resultFileIds = null;
+ $systemTagIds = [];
+ foreach ($filterRules as $filterRule) {
+ if ($filterRule['name'] === $ns . 'systemtag') {
+ $systemTagIds[] = $filterRule['value'];
+ }
+ }
+
+ // check user permissions, if applicable
+ if (!$this->isAdmin()) {
+ // check visibility/permission
+ $tags = $this->tagManager->getTagsByIds($systemTagIds);
+ $unknownTagIds = [];
+ foreach ($tags as $tag) {
+ if (!$tag->isUserVisible()) {
+ $unknownTagIds[] = $tag->getId();
+ }
+ }
+
+ if (!empty($unknownTagIds)) {
+ throw new TagNotFoundException('Tag with ids ' . implode(', ', $unknownTagIds) . ' not found');
+ }
+ }
+
+ // fetch all file ids and intersect them
+ foreach ($systemTagIds as $systemTagId) {
+ $fileIds = $this->tagMapper->getObjectIdsForTags($systemTagId, 'files');
+
+ if (empty($fileIds)) {
+ // This tag has no files, nothing can ever show up
+ return [];
+ }
+
+ // first run ?
+ if ($resultFileIds === null) {
+ $resultFileIds = $fileIds;
+ } else {
+ $resultFileIds = array_intersect($resultFileIds, $fileIds);
+ }
+
+ if (empty($resultFileIds)) {
+ // Empty intersection, nothing can show up anymore
+ return [];
+ }
+ }
+ return $resultFileIds;
+ }
+
+ /**
+ * Prepare propfind response for the given nodes
+ *
+ * @param string[] $requestedProps requested properties
+ * @param Node[] nodes nodes for which to fetch and prepare responses
+ * @return Response[]
+ */
+ public function prepareResponses($requestedProps, $nodes) {
+ $responses = [];
+ foreach ($nodes as $node) {
+ $propFind = new PropFind($node->getPath(), $requestedProps);
+
+ $this->server->getPropertiesByNode($propFind, $node);
+ // copied from Sabre Server's getPropertiesForPath
+ $result = $propFind->getResultForMultiStatus();
+ $result['href'] = $propFind->getPath();
+
+ $resourceType = $this->server->getResourceTypeForNode($node);
+ if (in_array('{DAV:}collection', $resourceType) || in_array('{DAV:}principal', $resourceType)) {
+ $result['href'] .= '/';
+ }
+
+ $responses[] = new Response(
+ rtrim($this->server->getBaseUri(), '/') . $node->getPath(),
+ $result,
+ 200
+ );
+ }
+ return $responses;
+ }
+
+ /**
+ * Find Sabre nodes by file ids
+ *
+ * @param Node $rootNode root node for search
+ * @param array $fileIds file ids
+ * @return Node[] array of Sabre nodes
+ */
+ public function findNodesByFileIds($rootNode, $fileIds) {
+ $folder = $this->userFolder;
+ if (trim($rootNode->getPath(), '/') !== '') {
+ $folder = $folder->get($rootNode->getPath());
+ }
+
+ $results = [];
+ foreach ($fileIds as $fileId) {
+ $entry = $folder->getById($fileId);
+ if ($entry) {
+ $entry = current($entry);
+ if ($entry instanceof \OCP\Files\File) {
+ $results[] = new File($this->fileView, $entry);
+ } else if ($entry instanceof \OCP\Files\Folder) {
+ $results[] = new Directory($this->fileView, $entry);
+ }
+ }
+ }
+
+ return $results;
+ }
+
+ /**
+ * Returns whether the currently logged in user is an administrator
+ */
+ private function isAdmin() {
+ $user = $this->userSession->getUser();
+ if ($user !== null) {
+ return $this->groupManager->isAdmin($user->getUID());
+ }
+ return false;
+ }
+}
diff --git a/apps/dav/lib/connector/sabre/principal.php b/apps/dav/lib/connector/sabre/principal.php
index 4f26390e3cc..a573124007d 100644
--- a/apps/dav/lib/connector/sabre/principal.php
+++ b/apps/dav/lib/connector/sabre/principal.php
@@ -49,6 +49,9 @@ class Principal implements BackendInterface {
/** @var string */
private $principalPrefix;
+ /** @var bool */
+ private $hasGroups;
+
/**
* @param IUserManager $userManager
* @param IGroupManager $groupManager
@@ -60,6 +63,7 @@ class Principal implements BackendInterface {
$this->userManager = $userManager;
$this->groupManager = $groupManager;
$this->principalPrefix = trim($principalPrefix, '/');
+ $this->hasGroups = ($principalPrefix === 'principals/users/');
}
/**
@@ -141,13 +145,15 @@ class Principal implements BackendInterface {
throw new Exception('Principal not found');
}
- $groups = $this->groupManager->getUserGroups($user);
- $groups = array_map(function($group) {
- /** @var IGroup $group */
- return $this->principalPrefix . '/' . $group->getGID();
- }, $groups);
+ if ($this->hasGroups) {
+ $groups = $this->groupManager->getUserGroups($user);
+ $groups = array_map(function($group) {
+ /** @var IGroup $group */
+ return 'principals/groups/' . $group->getGID();
+ }, $groups);
- return $groups;
+ return $groups;
+ }
}
return [];
}
diff --git a/apps/dav/lib/connector/sabre/serverfactory.php b/apps/dav/lib/connector/sabre/serverfactory.php
index fa4fda46870..8253948d96f 100644
--- a/apps/dav/lib/connector/sabre/serverfactory.php
+++ b/apps/dav/lib/connector/sabre/serverfactory.php
@@ -115,10 +115,10 @@ class ServerFactory {
// wait with registering these until auth is handled and the filesystem is setup
$server->on('beforeMethod', function () use ($server, $objectTree, $viewCallBack) {
// ensure the skeleton is copied
- \OC::$server->getUserFolder();
+ $userFolder = \OC::$server->getUserFolder();
/** @var \OC\Files\View $view */
- $view = $viewCallBack();
+ $view = $viewCallBack($server);
$rootInfo = $view->getFileInfo('');
// Create ownCloud Dir
@@ -135,6 +135,15 @@ class ServerFactory {
if($this->userSession->isLoggedIn()) {
$server->addPlugin(new \OCA\DAV\Connector\Sabre\TagsPlugin($objectTree, $this->tagManager));
$server->addPlugin(new \OCA\DAV\Connector\Sabre\CommentPropertiesPlugin(\OC::$server->getCommentsManager(), $this->userSession));
+ $server->addPlugin(new \OCA\DAV\Connector\Sabre\FilesReportPlugin(
+ $objectTree,
+ $view,
+ \OC::$server->getSystemTagManager(),
+ \OC::$server->getSystemTagObjectMapper(),
+ $this->userSession,
+ \OC::$server->getGroupManager(),
+ $userFolder
+ ));
// custom properties plugin must be the last one
$server->addPlugin(
new \Sabre\DAV\PropertyStorage\Plugin(
diff --git a/apps/dav/lib/files/sharing/publiclinkcheckplugin.php b/apps/dav/lib/files/sharing/publiclinkcheckplugin.php
new file mode 100644
index 00000000000..bbb5c611204
--- /dev/null
+++ b/apps/dav/lib/files/sharing/publiclinkcheckplugin.php
@@ -0,0 +1,63 @@
+<?php
+/**
+ * @author Robin Appelman <icewind@owncloud.com>
+ *
+ * @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\DAV\Files\Sharing;
+
+use OCP\Files\FileInfo;
+use Sabre\DAV\Exception\NotFound;
+use Sabre\DAV\ServerPlugin;
+use Sabre\HTTP\RequestInterface;
+use Sabre\HTTP\ResponseInterface;
+
+/**
+ * Verify that the public link share is valid
+ */
+class PublicLinkCheckPlugin extends ServerPlugin {
+ /**
+ * @var FileInfo
+ */
+ private $fileInfo;
+
+ /**
+ * @param FileInfo $fileInfo
+ */
+ public function setFileInfo($fileInfo) {
+ $this->fileInfo = $fileInfo;
+ }
+
+ /**
+ * This initializes the plugin.
+ *
+ * @param \Sabre\DAV\Server $server Sabre server
+ *
+ * @return void
+ */
+ public function initialize(\Sabre\DAV\Server $server) {
+ $server->on('beforeMethod', [$this, 'beforeMethod']);
+ }
+
+ public function beforeMethod(RequestInterface $request, ResponseInterface $response){
+ // verify that the owner didn't have his share permissions revoked
+ if ($this->fileInfo && !$this->fileInfo->isShareable()) {
+ throw new NotFound();
+ }
+ }
+}
diff --git a/apps/dav/lib/migration/calendaradapter.php b/apps/dav/lib/migration/calendaradapter.php
new file mode 100644
index 00000000000..39faf2cec37
--- /dev/null
+++ b/apps/dav/lib/migration/calendaradapter.php
@@ -0,0 +1,83 @@
+<?php
+
+namespace OCA\Dav\Migration;
+
+use OCP\IDBConnection;
+
+class CalendarAdapter {
+
+ /** @var \OCP\IDBConnection */
+ protected $dbConnection;
+
+ /** @var string */
+ private $sourceCalendarTable;
+
+ /** @var string */
+ private $sourceCalObjTable;
+
+ /**
+ * @param IDBConnection $dbConnection
+ * @param string $sourceCalendarTable
+ * @param string $sourceCalObjTable
+ */
+ function __construct(IDBConnection $dbConnection,
+ $sourceCalendarTable = 'clndr_calendars',
+ $sourceCalObjTable = 'clndr_objects') {
+ $this->dbConnection = $dbConnection;
+ $this->sourceCalendarTable = $sourceCalendarTable;
+ $this->sourceCalObjTable = $sourceCalObjTable;
+ }
+
+ /**
+ * @param string $user
+ * @param \Closure $callBack
+ */
+ public function foreachCalendar($user, \Closure $callBack) {
+ // get all calendars of that user
+ $query = $this->dbConnection->getQueryBuilder();
+ $stmt = $query->select('*')->from($this->sourceCalendarTable)
+ ->where($query->expr()->eq('userid', $query->createNamedParameter($user)))
+ ->execute();
+
+ while($row = $stmt->fetch()) {
+ $callBack($row);
+ }
+ }
+
+ public function setup() {
+ if (!$this->dbConnection->tableExists($this->sourceCalendarTable)) {
+ throw new \DomainException('Calendar tables are missing. Nothing to do.');
+ }
+ }
+
+ /**
+ * @param int $calendarId
+ * @param \Closure $callBack
+ */
+ public function foreachCalendarObject($calendarId, \Closure $callBack) {
+ $query = $this->dbConnection->getQueryBuilder();
+ $stmt = $query->select('*')->from($this->sourceCalObjTable)
+ ->where($query->expr()->eq('calendarid', $query->createNamedParameter($calendarId)))
+ ->execute();
+
+ while($row = $stmt->fetch()) {
+ $callBack($row);
+ }
+ }
+
+ /**
+ * @param int $addressBookId
+ * @return array
+ */
+ public function getShares($addressBookId) {
+ $query = $this->dbConnection->getQueryBuilder();
+ $shares = $query->select('*')->from('share')
+ ->where($query->expr()->eq('item_source', $query->createNamedParameter($addressBookId)))
+ ->andWhere($query->expr()->eq('item_type', $query->expr()->literal('calendar')))
+ ->andWhere($query->expr()->in('share_type', [ $query->expr()->literal(0), $query->expr()->literal(1)]))
+ ->execute()
+ ->fetchAll();
+
+ return $shares;
+ }
+}
diff --git a/apps/dav/lib/migration/migratecalendars.php b/apps/dav/lib/migration/migratecalendars.php
new file mode 100644
index 00000000000..33f8a105180
--- /dev/null
+++ b/apps/dav/lib/migration/migratecalendars.php
@@ -0,0 +1,94 @@
+<?php
+
+namespace OCA\Dav\Migration;
+
+use OCA\DAV\CalDAV\CalDavBackend;
+use OCA\DAV\CalDAV\Calendar;
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+
+class MigrateCalendars {
+
+ /** @var CalendarAdapter */
+ protected $adapter;
+
+ /** @var CalDavBackend */
+ private $backend;
+
+ /**
+ * @param CalendarAdapter $adapter
+ * @param CalDavBackend $backend
+ */
+ function __construct(CalendarAdapter $adapter,
+ CalDavBackend $backend
+ ) {
+ $this->adapter = $adapter;
+ $this->backend = $backend;
+ }
+
+ /**
+ * @param string $user
+ */
+ public function migrateForUser($user) {
+
+ $this->adapter->foreachCalendar($user, function($calendar) use ($user) {
+ $principal = "principals/users/$user";
+ $calendarByUri = $this->backend->getCalendarByUri($principal, $calendar['uri']);
+ if (!is_null($calendarByUri)) {
+ return;
+ }
+
+ $newId = $this->backend->createCalendar($principal, $calendar['uri'], [
+ '{DAV:}displayname' => $calendar['displayname'],
+ '{urn:ietf:params:xml:ns:caldav}calendar-description' => $calendar['displayname'],
+ '{urn:ietf:params:xml:ns:caldav}calendar-timezone' => $calendar['timezone'],
+ '{http://apple.com/ns/ical/}calendar-order' => $calendar['calendarorder'],
+ '{http://apple.com/ns/ical/}calendar-color' => $calendar['calendarcolor'],
+ ]);
+
+ $this->migrateCalendar($calendar['id'], $newId);
+ $this->migrateShares($calendar['id'], $newId);
+ });
+ }
+
+ public function setup() {
+ $this->adapter->setup();
+ }
+
+ /**
+ * @param int $calendarId
+ * @param int $newCalendarId
+ */
+ private function migrateCalendar($calendarId, $newCalendarId) {
+ $this->adapter->foreachCalendarObject($calendarId, function($calObject) use ($newCalendarId) {
+ $this->backend->createCalendarObject($newCalendarId, $calObject['uri'], $calObject['calendardata']);
+ });
+ }
+
+ /**
+ * @param int $calendarId
+ * @param int $newCalendarId
+ */
+ private function migrateShares($calendarId, $newCalendarId) {
+ $shares =$this->adapter->getShares($calendarId);
+ if (empty($shares)) {
+ return;
+ }
+
+ $add = array_map(function($s) {
+ $prefix = 'principal:principals/users/';
+ if ($s['share_type'] === 1) {
+ $prefix = 'principal:principals/groups/';
+ }
+ return [
+ 'href' => $prefix . $s['share_with']
+ ];
+ }, $shares);
+
+ $newCalendar = $this->backend->getCalendarById($newCalendarId);
+ $calendar = new Calendar($this->backend, $newCalendar);
+ $this->backend->updateShares($calendar, $add, []);
+ }
+}
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/dav/tests/unit/connector/sabre/filesreportplugin.php b/apps/dav/tests/unit/connector/sabre/filesreportplugin.php
new file mode 100644
index 00000000000..b528e2d2427
--- /dev/null
+++ b/apps/dav/tests/unit/connector/sabre/filesreportplugin.php
@@ -0,0 +1,602 @@
+<?php
+/**
+ * @author Vincent Petry <pvince81@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\DAV\Tests\Unit\Sabre\Connector;
+
+use OCA\DAV\Connector\Sabre\FilesReportPlugin as FilesReportPluginImplementation;
+use Sabre\DAV\Exception\NotFound;
+use OCP\SystemTag\ISystemTagObjectMapper;
+use OC\Files\View;
+use OCP\Files\Folder;
+use OCP\IGroupManager;
+use OCP\SystemTag\ISystemTagManager;
+
+class FilesReportPlugin extends \Test\TestCase {
+ /** @var \Sabre\DAV\Server|\PHPUnit_Framework_MockObject_MockObject */
+ private $server;
+
+ /** @var \Sabre\DAV\Tree|\PHPUnit_Framework_MockObject_MockObject */
+ private $tree;
+
+ /** @var ISystemTagObjectMapper|\PHPUnit_Framework_MockObject_MockObject */
+ private $tagMapper;
+
+ /** @var ISystemTagManager|\PHPUnit_Framework_MockObject_MockObject */
+ private $tagManager;
+
+ /** @var \OCP\IUserSession */
+ private $userSession;
+
+ /** @var FilesReportPluginImplementation */
+ private $plugin;
+
+ /** @var View|\PHPUnit_Framework_MockObject_MockObject **/
+ private $view;
+
+ /** @var IGroupManager|\PHPUnit_Framework_MockObject_MockObject **/
+ private $groupManager;
+
+ /** @var Folder|\PHPUnit_Framework_MockObject_MockObject **/
+ private $userFolder;
+
+ public function setUp() {
+ parent::setUp();
+ $this->tree = $this->getMockBuilder('\Sabre\DAV\Tree')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $this->view = $this->getMockBuilder('\OC\Files\View')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $this->server = $this->getMockBuilder('\Sabre\DAV\Server')
+ ->setConstructorArgs([$this->tree])
+ ->setMethods(['getRequestUri'])
+ ->getMock();
+
+ $this->groupManager = $this->getMockBuilder('\OCP\IGroupManager')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $this->userFolder = $this->getMockBuilder('\OCP\Files\Folder')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $this->tagManager = $this->getMock('\OCP\SystemTag\ISystemTagManager');
+ $this->tagMapper = $this->getMock('\OCP\SystemTag\ISystemTagObjectMapper');
+ $this->userSession = $this->getMock('\OCP\IUserSession');
+
+ $user = $this->getMock('\OCP\IUser');
+ $user->expects($this->any())
+ ->method('getUID')
+ ->will($this->returnValue('testuser'));
+ $this->userSession->expects($this->any())
+ ->method('getUser')
+ ->will($this->returnValue($user));
+
+ $this->plugin = new FilesReportPluginImplementation(
+ $this->tree,
+ $this->view,
+ $this->tagManager,
+ $this->tagMapper,
+ $this->userSession,
+ $this->groupManager,
+ $this->userFolder
+ );
+ }
+
+ /**
+ * @expectedException \Sabre\DAV\Exception\ReportNotSupported
+ */
+ public function testOnReportInvalidNode() {
+ $path = 'totally/unrelated/13';
+
+ $this->tree->expects($this->any())
+ ->method('getNodeForPath')
+ ->with('/' . $path)
+ ->will($this->returnValue($this->getMock('\Sabre\DAV\INode')));
+
+ $this->server->expects($this->any())
+ ->method('getRequestUri')
+ ->will($this->returnValue($path));
+ $this->plugin->initialize($this->server);
+
+ $this->plugin->onReport(FilesReportPluginImplementation::REPORT_NAME, [], '/' . $path);
+ }
+
+ /**
+ * @expectedException \Sabre\DAV\Exception\ReportNotSupported
+ */
+ public function testOnReportInvalidReportName() {
+ $path = 'test';
+
+ $this->tree->expects($this->any())
+ ->method('getNodeForPath')
+ ->with('/' . $path)
+ ->will($this->returnValue($this->getMock('\Sabre\DAV\INode')));
+
+ $this->server->expects($this->any())
+ ->method('getRequestUri')
+ ->will($this->returnValue($path));
+ $this->plugin->initialize($this->server);
+
+ $this->plugin->onReport('{whoever}whatever', [], '/' . $path);
+ }
+
+ public function testOnReport() {
+ $path = 'test';
+
+ $parameters = [
+ [
+ 'name' => '{DAV:}prop',
+ 'value' => [
+ ['name' => '{DAV:}getcontentlength', 'value' => ''],
+ ['name' => '{http://owncloud.org/ns}size', 'value' => ''],
+ ],
+ ],
+ [
+ 'name' => '{http://owncloud.org/ns}filter-rules',
+ 'value' => [
+ ['name' => '{http://owncloud.org/ns}systemtag', 'value' => '123'],
+ ['name' => '{http://owncloud.org/ns}systemtag', 'value' => '456'],
+ ],
+ ],
+ ];
+
+ $this->groupManager->expects($this->any())
+ ->method('isAdmin')
+ ->will($this->returnValue(true));
+
+ $this->tagMapper->expects($this->at(0))
+ ->method('getObjectIdsForTags')
+ ->with('123', 'files')
+ ->will($this->returnValue(['111', '222']));
+ $this->tagMapper->expects($this->at(1))
+ ->method('getObjectIdsForTags')
+ ->with('456', 'files')
+ ->will($this->returnValue(['111', '222', '333']));
+
+ $reportTargetNode = $this->getMockBuilder('\OCA\DAV\Connector\Sabre\Directory')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $response = $this->getMockBuilder('Sabre\HTTP\ResponseInterface')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $response->expects($this->once())
+ ->method('setHeader')
+ ->with('Content-Type', 'application/xml; charset=utf-8');
+
+ $response->expects($this->once())
+ ->method('setStatus')
+ ->with(207);
+
+ $response->expects($this->once())
+ ->method('setBody');
+
+ $this->tree->expects($this->any())
+ ->method('getNodeForPath')
+ ->with('/' . $path)
+ ->will($this->returnValue($reportTargetNode));
+
+ $filesNode1 = $this->getMockBuilder('\OCP\Files\Folder')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $filesNode2 = $this->getMockBuilder('\OCP\Files\File')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $this->userFolder->expects($this->at(0))
+ ->method('getById')
+ ->with('111')
+ ->will($this->returnValue([$filesNode1]));
+ $this->userFolder->expects($this->at(1))
+ ->method('getById')
+ ->with('222')
+ ->will($this->returnValue([$filesNode2]));
+
+ $this->server->expects($this->any())
+ ->method('getRequestUri')
+ ->will($this->returnValue($path));
+ $this->server->httpResponse = $response;
+ $this->plugin->initialize($this->server);
+
+ $this->plugin->onReport(FilesReportPluginImplementation::REPORT_NAME, $parameters, '/' . $path);
+ }
+
+ public function testFindNodesByFileIdsRoot() {
+ $filesNode1 = $this->getMockBuilder('\OCP\Files\Folder')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $filesNode1->expects($this->once())
+ ->method('getName')
+ ->will($this->returnValue('first node'));
+
+ $filesNode2 = $this->getMockBuilder('\OCP\Files\File')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $filesNode2->expects($this->once())
+ ->method('getName')
+ ->will($this->returnValue('second node'));
+
+ $reportTargetNode = $this->getMockBuilder('\OCA\DAV\Connector\Sabre\Directory')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $reportTargetNode->expects($this->any())
+ ->method('getPath')
+ ->will($this->returnValue('/'));
+
+ $this->userFolder->expects($this->at(0))
+ ->method('getById')
+ ->with('111')
+ ->will($this->returnValue([$filesNode1]));
+ $this->userFolder->expects($this->at(1))
+ ->method('getById')
+ ->with('222')
+ ->will($this->returnValue([$filesNode2]));
+
+ /** @var \OCA\DAV\Connector\Sabre\Directory|\PHPUnit_Framework_MockObject_MockObject $reportTargetNode */
+ $result = $this->plugin->findNodesByFileIds($reportTargetNode, ['111', '222']);
+
+ $this->assertCount(2, $result);
+ $this->assertInstanceOf('\OCA\DAV\Connector\Sabre\Directory', $result[0]);
+ $this->assertEquals('first node', $result[0]->getName());
+ $this->assertInstanceOf('\OCA\DAV\Connector\Sabre\File', $result[1]);
+ $this->assertEquals('second node', $result[1]->getName());
+ }
+
+ public function testFindNodesByFileIdsSubDir() {
+ $filesNode1 = $this->getMockBuilder('\OCP\Files\Folder')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $filesNode1->expects($this->once())
+ ->method('getName')
+ ->will($this->returnValue('first node'));
+
+ $filesNode2 = $this->getMockBuilder('\OCP\Files\File')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $filesNode2->expects($this->once())
+ ->method('getName')
+ ->will($this->returnValue('second node'));
+
+ $reportTargetNode = $this->getMockBuilder('\OCA\DAV\Connector\Sabre\Directory')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $reportTargetNode->expects($this->any())
+ ->method('getPath')
+ ->will($this->returnValue('/sub1/sub2'));
+
+
+ $subNode = $this->getMockBuilder('\OCP\Files\Folder')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $this->userFolder->expects($this->at(0))
+ ->method('get')
+ ->with('/sub1/sub2')
+ ->will($this->returnValue($subNode));
+
+ $subNode->expects($this->at(0))
+ ->method('getById')
+ ->with('111')
+ ->will($this->returnValue([$filesNode1]));
+ $subNode->expects($this->at(1))
+ ->method('getById')
+ ->with('222')
+ ->will($this->returnValue([$filesNode2]));
+
+ /** @var \OCA\DAV\Connector\Sabre\Directory|\PHPUnit_Framework_MockObject_MockObject $reportTargetNode */
+ $result = $this->plugin->findNodesByFileIds($reportTargetNode, ['111', '222']);
+
+ $this->assertCount(2, $result);
+ $this->assertInstanceOf('\OCA\DAV\Connector\Sabre\Directory', $result[0]);
+ $this->assertEquals('first node', $result[0]->getName());
+ $this->assertInstanceOf('\OCA\DAV\Connector\Sabre\File', $result[1]);
+ $this->assertEquals('second node', $result[1]->getName());
+ }
+
+ public function testPrepareResponses() {
+ $requestedProps = ['{DAV:}getcontentlength', '{http://owncloud.org/ns}fileid', '{DAV:}resourcetype'];
+
+ $node1 = $this->getMockBuilder('\OCA\DAV\Connector\Sabre\Directory')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $node2 = $this->getMockBuilder('\OCA\DAV\Connector\Sabre\File')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $node1->expects($this->once())
+ ->method('getInternalFileId')
+ ->will($this->returnValue('111'));
+ $node2->expects($this->once())
+ ->method('getInternalFileId')
+ ->will($this->returnValue('222'));
+ $node2->expects($this->once())
+ ->method('getSize')
+ ->will($this->returnValue(1024));
+
+ $this->server->addPlugin(new \OCA\DAV\Connector\Sabre\FilesPlugin($this->tree, $this->view));
+ $this->plugin->initialize($this->server);
+ $responses = $this->plugin->prepareResponses($requestedProps, [$node1, $node2]);
+
+ $this->assertCount(2, $responses);
+
+ $this->assertEquals(200, $responses[0]->getHttpStatus());
+ $this->assertEquals(200, $responses[1]->getHttpStatus());
+
+ $props1 = $responses[0]->getResponseProperties();
+ $this->assertEquals('111', $props1[200]['{http://owncloud.org/ns}fileid']);
+ $this->assertNull($props1[404]['{DAV:}getcontentlength']);
+ $this->assertInstanceOf('\Sabre\DAV\Xml\Property\ResourceType', $props1[200]['{DAV:}resourcetype']);
+ $resourceType1 = $props1[200]['{DAV:}resourcetype']->getValue();
+ $this->assertEquals('{DAV:}collection', $resourceType1[0]);
+
+ $props2 = $responses[1]->getResponseProperties();
+ $this->assertEquals('1024', $props2[200]['{DAV:}getcontentlength']);
+ $this->assertEquals('222', $props2[200]['{http://owncloud.org/ns}fileid']);
+ $this->assertInstanceOf('\Sabre\DAV\Xml\Property\ResourceType', $props2[200]['{DAV:}resourcetype']);
+ $this->assertCount(0, $props2[200]['{DAV:}resourcetype']->getValue());
+ }
+
+ public function testProcessFilterRulesSingle() {
+ $this->groupManager->expects($this->any())
+ ->method('isAdmin')
+ ->will($this->returnValue(true));
+
+ $this->tagMapper->expects($this->exactly(1))
+ ->method('getObjectIdsForTags')
+ ->withConsecutive(
+ ['123', 'files']
+ )
+ ->willReturnMap([
+ ['123', 'files', ['111', '222']],
+ ]);
+
+ $rules = [
+ ['name' => '{http://owncloud.org/ns}systemtag', 'value' => '123'],
+ ];
+
+ $this->assertEquals(['111', '222'], $this->plugin->processFilterRules($rules));
+ }
+
+ public function testProcessFilterRulesAndCondition() {
+ $this->groupManager->expects($this->any())
+ ->method('isAdmin')
+ ->will($this->returnValue(true));
+
+ $this->tagMapper->expects($this->exactly(2))
+ ->method('getObjectIdsForTags')
+ ->withConsecutive(
+ ['123', 'files'],
+ ['456', 'files']
+ )
+ ->willReturnMap([
+ ['123', 'files', ['111', '222']],
+ ['456', 'files', ['222', '333']],
+ ]);
+
+ $rules = [
+ ['name' => '{http://owncloud.org/ns}systemtag', 'value' => '123'],
+ ['name' => '{http://owncloud.org/ns}systemtag', 'value' => '456'],
+ ];
+
+ $this->assertEquals(['222'], array_values($this->plugin->processFilterRules($rules)));
+ }
+
+ public function testProcessFilterRulesAndConditionWithOneEmptyResult() {
+ $this->groupManager->expects($this->any())
+ ->method('isAdmin')
+ ->will($this->returnValue(true));
+
+ $this->tagMapper->expects($this->exactly(2))
+ ->method('getObjectIdsForTags')
+ ->withConsecutive(
+ ['123', 'files'],
+ ['456', 'files']
+ )
+ ->willReturnMap([
+ ['123', 'files', ['111', '222']],
+ ['456', 'files', []],
+ ]);
+
+ $rules = [
+ ['name' => '{http://owncloud.org/ns}systemtag', 'value' => '123'],
+ ['name' => '{http://owncloud.org/ns}systemtag', 'value' => '456'],
+ ];
+
+ $this->assertEquals([], array_values($this->plugin->processFilterRules($rules)));
+ }
+
+ public function testProcessFilterRulesAndConditionWithFirstEmptyResult() {
+ $this->groupManager->expects($this->any())
+ ->method('isAdmin')
+ ->will($this->returnValue(true));
+
+ $this->tagMapper->expects($this->exactly(1))
+ ->method('getObjectIdsForTags')
+ ->withConsecutive(
+ ['123', 'files'],
+ ['456', 'files']
+ )
+ ->willReturnMap([
+ ['123', 'files', []],
+ ['456', 'files', ['111', '222']],
+ ]);
+
+ $rules = [
+ ['name' => '{http://owncloud.org/ns}systemtag', 'value' => '123'],
+ ['name' => '{http://owncloud.org/ns}systemtag', 'value' => '456'],
+ ];
+
+ $this->assertEquals([], array_values($this->plugin->processFilterRules($rules)));
+ }
+
+ public function testProcessFilterRulesAndConditionWithEmptyMidResult() {
+ $this->groupManager->expects($this->any())
+ ->method('isAdmin')
+ ->will($this->returnValue(true));
+
+ $this->tagMapper->expects($this->exactly(2))
+ ->method('getObjectIdsForTags')
+ ->withConsecutive(
+ ['123', 'files'],
+ ['456', 'files'],
+ ['789', 'files']
+ )
+ ->willReturnMap([
+ ['123', 'files', ['111', '222']],
+ ['456', 'files', ['333']],
+ ['789', 'files', ['111', '222']],
+ ]);
+
+ $rules = [
+ ['name' => '{http://owncloud.org/ns}systemtag', 'value' => '123'],
+ ['name' => '{http://owncloud.org/ns}systemtag', 'value' => '456'],
+ ['name' => '{http://owncloud.org/ns}systemtag', 'value' => '789'],
+ ];
+
+ $this->assertEquals([], array_values($this->plugin->processFilterRules($rules)));
+ }
+
+ public function testProcessFilterRulesInvisibleTagAsAdmin() {
+ $this->groupManager->expects($this->any())
+ ->method('isAdmin')
+ ->will($this->returnValue(true));
+
+ $tag1 = $this->getMock('\OCP\SystemTag\ISystemTag');
+ $tag1->expects($this->any())
+ ->method('getId')
+ ->will($this->returnValue('123'));
+ $tag1->expects($this->any())
+ ->method('isUserVisible')
+ ->will($this->returnValue(true));
+
+ $tag2 = $this->getMock('\OCP\SystemTag\ISystemTag');
+ $tag2->expects($this->any())
+ ->method('getId')
+ ->will($this->returnValue('123'));
+ $tag2->expects($this->any())
+ ->method('isUserVisible')
+ ->will($this->returnValue(false));
+
+ // no need to fetch tags to check permissions
+ $this->tagManager->expects($this->never())
+ ->method('getTagsByIds');
+
+ $this->tagMapper->expects($this->at(0))
+ ->method('getObjectIdsForTags')
+ ->with('123')
+ ->will($this->returnValue(['111', '222']));
+ $this->tagMapper->expects($this->at(1))
+ ->method('getObjectIdsForTags')
+ ->with('456')
+ ->will($this->returnValue(['222', '333']));
+
+ $rules = [
+ ['name' => '{http://owncloud.org/ns}systemtag', 'value' => '123'],
+ ['name' => '{http://owncloud.org/ns}systemtag', 'value' => '456'],
+ ];
+
+ $this->assertEquals(['222'], array_values($this->plugin->processFilterRules($rules)));
+ }
+
+ /**
+ * @expectedException \OCP\SystemTag\TagNotFoundException
+ */
+ public function testProcessFilterRulesInvisibleTagAsUser() {
+ $this->groupManager->expects($this->any())
+ ->method('isAdmin')
+ ->will($this->returnValue(false));
+
+ $tag1 = $this->getMock('\OCP\SystemTag\ISystemTag');
+ $tag1->expects($this->any())
+ ->method('getId')
+ ->will($this->returnValue('123'));
+ $tag1->expects($this->any())
+ ->method('isUserVisible')
+ ->will($this->returnValue(true));
+
+ $tag2 = $this->getMock('\OCP\SystemTag\ISystemTag');
+ $tag2->expects($this->any())
+ ->method('getId')
+ ->will($this->returnValue('123'));
+ $tag2->expects($this->any())
+ ->method('isUserVisible')
+ ->will($this->returnValue(false)); // invisible
+
+ $this->tagManager->expects($this->once())
+ ->method('getTagsByIds')
+ ->with(['123', '456'])
+ ->will($this->returnValue([$tag1, $tag2]));
+
+ $rules = [
+ ['name' => '{http://owncloud.org/ns}systemtag', 'value' => '123'],
+ ['name' => '{http://owncloud.org/ns}systemtag', 'value' => '456'],
+ ];
+
+ $this->plugin->processFilterRules($rules);
+ }
+
+ public function testProcessFilterRulesVisibleTagAsUser() {
+ $this->groupManager->expects($this->any())
+ ->method('isAdmin')
+ ->will($this->returnValue(false));
+
+ $tag1 = $this->getMock('\OCP\SystemTag\ISystemTag');
+ $tag1->expects($this->any())
+ ->method('getId')
+ ->will($this->returnValue('123'));
+ $tag1->expects($this->any())
+ ->method('isUserVisible')
+ ->will($this->returnValue(true));
+
+ $tag2 = $this->getMock('\OCP\SystemTag\ISystemTag');
+ $tag2->expects($this->any())
+ ->method('getId')
+ ->will($this->returnValue('123'));
+ $tag2->expects($this->any())
+ ->method('isUserVisible')
+ ->will($this->returnValue(true));
+
+ $this->tagManager->expects($this->once())
+ ->method('getTagsByIds')
+ ->with(['123', '456'])
+ ->will($this->returnValue([$tag1, $tag2]));
+
+ $this->tagMapper->expects($this->at(0))
+ ->method('getObjectIdsForTags')
+ ->with('123')
+ ->will($this->returnValue(['111', '222']));
+ $this->tagMapper->expects($this->at(1))
+ ->method('getObjectIdsForTags')
+ ->with('456')
+ ->will($this->returnValue(['222', '333']));
+
+ $rules = [
+ ['name' => '{http://owncloud.org/ns}systemtag', 'value' => '123'],
+ ['name' => '{http://owncloud.org/ns}systemtag', 'value' => '456'],
+ ];
+
+ $this->assertEquals(['222'], array_values($this->plugin->processFilterRules($rules)));
+ }
+}
diff --git a/apps/dav/tests/unit/connector/sabre/principal.php b/apps/dav/tests/unit/connector/sabre/principal.php
index 07bfd5d263b..1747885240a 100644
--- a/apps/dav/tests/unit/connector/sabre/principal.php
+++ b/apps/dav/tests/unit/connector/sabre/principal.php
@@ -202,16 +202,26 @@ class Principal extends TestCase {
public function testGetGroupMembership() {
$fooUser = $this->getMockBuilder('\OC\User\User')
->disableOriginalConstructor()->getMock();
+ $group = $this->getMockBuilder('\OCP\IGroup')
+ ->disableOriginalConstructor()->getMock();
+ $group->expects($this->once())
+ ->method('getGID')
+ ->willReturn('group1');
$this->userManager
->expects($this->once())
->method('get')
->with('foo')
->willReturn($fooUser);
$this->groupManager
+ ->expects($this->once())
->method('getUserGroups')
- ->willReturn([]);
+ ->willReturn([
+ $group
+ ]);
- $expectedResponse = [];
+ $expectedResponse = [
+ 'principals/groups/group1'
+ ];
$response = $this->connector->getGroupMembership('principals/users/foo');
$this->assertSame($expectedResponse, $response);
}
diff --git a/apps/dav/tests/unit/migration/calendar_schema.xml b/apps/dav/tests/unit/migration/calendar_schema.xml
new file mode 100644
index 00000000000..6c88b596a3f
--- /dev/null
+++ b/apps/dav/tests/unit/migration/calendar_schema.xml
@@ -0,0 +1,191 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<database>
+
+ <name>*dbname*</name>
+ <create>true</create>
+ <overwrite>false</overwrite>
+
+ <charset>utf8</charset>
+
+ <table>
+
+ <name>*dbprefix*clndr_objects</name>
+
+ <declaration>
+
+ <field>
+ <name>id</name>
+ <type>integer</type>
+ <default>0</default>
+ <notnull>true</notnull>
+ <autoincrement>1</autoincrement>
+ <unsigned>true</unsigned>
+ <length>4</length>
+ </field>
+
+ <field>
+ <name>calendarid</name>
+ <type>integer</type>
+ <default></default>
+ <notnull>true</notnull>
+ <unsigned>true</unsigned>
+ <length>4</length>
+ </field>
+
+ <field>
+ <name>objecttype</name>
+ <type>text</type>
+ <default></default>
+ <notnull>true</notnull>
+ <length>40</length>
+ </field>
+
+ <field>
+ <name>startdate</name>
+ <type>timestamp</type>
+ <default>1970-01-01 00:00:00</default>
+ <notnull>false</notnull>
+ </field>
+
+ <field>
+ <name>enddate</name>
+ <type>timestamp</type>
+ <default>1970-01-01 00:00:00</default>
+ <notnull>false</notnull>
+ </field>
+
+ <field>
+ <name>repeating</name>
+ <type>integer</type>
+ <default></default>
+ <notnull>false</notnull>
+ <length>4</length>
+ </field>
+
+ <field>
+ <name>summary</name>
+ <type>text</type>
+ <default></default>
+ <notnull>false</notnull>
+ <length>255</length>
+ </field>
+
+ <field>
+ <name>calendardata</name>
+ <type>clob</type>
+ <notnull>false</notnull>
+ </field>
+
+ <field>
+ <name>uri</name>
+ <type>text</type>
+ <default></default>
+ <notnull>false</notnull>
+ <length>255</length>
+ </field>
+
+ <field>
+ <name>lastmodified</name>
+ <type>integer</type>
+ <default></default>
+ <notnull>false</notnull>
+ <length>4</length>
+ </field>
+
+ </declaration>
+
+ </table>
+
+ <table>
+
+ <name>*dbprefix*clndr_calendars</name>
+
+ <declaration>
+
+ <field>
+ <name>id</name>
+ <type>integer</type>
+ <default>0</default>
+ <notnull>true</notnull>
+ <autoincrement>1</autoincrement>
+ <unsigned>true</unsigned>
+ <length>4</length>
+ </field>
+
+ <field>
+ <name>userid</name>
+ <type>text</type>
+ <default></default>
+ <notnull>false</notnull>
+ <length>255</length>
+ </field>
+
+ <field>
+ <name>displayname</name>
+ <type>text</type>
+ <default></default>
+ <notnull>false</notnull>
+ <length>100</length>
+ </field>
+
+ <field>
+ <name>uri</name>
+ <type>text</type>
+ <default></default>
+ <notnull>false</notnull>
+ <length>255</length>
+ </field>
+
+ <field>
+ <name>active</name>
+ <type>integer</type>
+ <default>1</default>
+ <notnull>true</notnull>
+ <length>4</length>
+ </field>
+
+ <field>
+ <name>ctag</name>
+ <type>integer</type>
+ <default>0</default>
+ <notnull>true</notnull>
+ <unsigned>true</unsigned>
+ <length>4</length>
+ </field>
+
+ <field>
+ <name>calendarorder</name>
+ <type>integer</type>
+ <default>0</default>
+ <notnull>true</notnull>
+ <unsigned>true</unsigned>
+ <length>4</length>
+ </field>
+
+ <field>
+ <name>calendarcolor</name>
+ <type>text</type>
+ <default></default>
+ <notnull>false</notnull>
+ <length>10</length>
+ </field>
+
+ <field>
+ <name>timezone</name>
+ <type>clob</type>
+ <notnull>false</notnull>
+ </field>
+
+ <field>
+ <name>components</name>
+ <type>text</type>
+ <default></default>
+ <notnull>false</notnull>
+ <length>100</length>
+ </field>
+
+ </declaration>
+
+ </table>
+
+</database>
diff --git a/apps/dav/tests/unit/migration/calendaradaptertest.php b/apps/dav/tests/unit/migration/calendaradaptertest.php
new file mode 100644
index 00000000000..f92774ef6ad
--- /dev/null
+++ b/apps/dav/tests/unit/migration/calendaradaptertest.php
@@ -0,0 +1,131 @@
+<?php
+/**
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @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\DAV\Tests\Unit\Migration;
+
+use DomainException;
+use OCA\Dav\Migration\AddressBookAdapter;
+use OCA\Dav\Migration\CalendarAdapter;
+use OCP\IDBConnection;
+use Test\TestCase;
+
+/**
+ * Class CalendarAdapterTest
+ *
+ * @group DB
+ *
+ * @package OCA\DAV\Tests\Unit\Migration
+ */
+class CalendarAdapterTest extends TestCase {
+
+ /** @var IDBConnection */
+ private $db;
+ /** @var CalendarAdapter */
+ private $adapter;
+ /** @var array */
+ private $cals = [];
+ /** @var array */
+ private $calObjs = [];
+
+ public function setUp() {
+ parent::setUp();
+ $this->db = \OC::$server->getDatabaseConnection();
+
+ $manager = new \OC\DB\MDB2SchemaManager($this->db);
+ $manager->createDbFromStructure(__DIR__ . '/calendar_schema.xml');
+
+ $this->adapter = new CalendarAdapter($this->db);
+ }
+
+ public function tearDown() {
+ $this->db->dropTable('clndr_calendars');
+ $this->db->dropTable('clndr_objects');
+ parent::tearDown();
+ }
+
+ /**
+ * @expectedException DomainException
+ */
+ public function testOldTablesDoNotExist() {
+ $adapter = new AddressBookAdapter(\OC::$server->getDatabaseConnection(), 'crazy_table_that_does_no_exist');
+ $adapter->setup();
+ }
+
+ public function test() {
+
+ // insert test data
+ $builder = $this->db->getQueryBuilder();
+ $builder->insert('clndr_calendars')
+ ->values([
+ 'userid' => $builder->createNamedParameter('test-user-666'),
+ 'displayname' => $builder->createNamedParameter('Display Name'),
+ 'uri' => $builder->createNamedParameter('events'),
+ 'ctag' => $builder->createNamedParameter('112233'),
+ 'active' => $builder->createNamedParameter('1')
+ ])
+ ->execute();
+ $builder = $this->db->getQueryBuilder();
+ $builder->insert('clndr_objects')
+ ->values([
+ 'calendarid' => $builder->createNamedParameter(6666),
+ 'objecttype' => $builder->createNamedParameter('VEVENT'),
+ 'startdate' => $builder->createNamedParameter(new \DateTime(), 'datetime'),
+ 'enddate' => $builder->createNamedParameter(new \DateTime(), 'datetime'),
+ 'repeating' => $builder->createNamedParameter(0),
+ 'summary' => $builder->createNamedParameter('Something crazy will happen'),
+ 'uri' => $builder->createNamedParameter('event.ics'),
+ 'lastmodified' => $builder->createNamedParameter('112233'),
+ ])
+ ->execute();
+ $builder = $this->db->getQueryBuilder();
+ $builder->insert('share')
+ ->values([
+ 'share_type' => $builder->createNamedParameter(1),
+ 'share_with' => $builder->createNamedParameter('user01'),
+ 'uid_owner' => $builder->createNamedParameter('user02'),
+ 'item_type' => $builder->createNamedParameter('calendar'),
+ 'item_source' => $builder->createNamedParameter(6666),
+ 'item_target' => $builder->createNamedParameter('Contacts (user02)'),
+ ])
+ ->execute();
+
+ // test the adapter
+ $this->adapter->foreachCalendar('test-user-666', function($row) {
+ $this->cals[] = $row;
+ });
+ $this->assertArrayHasKey('id', $this->cals[0]);
+ $this->assertEquals('test-user-666', $this->cals[0]['userid']);
+ $this->assertEquals('Display Name', $this->cals[0]['displayname']);
+ $this->assertEquals('events', $this->cals[0]['uri']);
+ $this->assertEquals('112233', $this->cals[0]['ctag']);
+
+ $this->adapter->foreachCalendarObject(6666, function($row) {
+ $this->calObjs[]= $row;
+ });
+ $this->assertArrayHasKey('id', $this->calObjs[0]);
+ $this->assertEquals(6666, $this->calObjs[0]['calendarid']);
+
+ // test getShares
+ $shares = $this->adapter->getShares(6666);
+ $this->assertEquals(1, count($shares));
+
+ }
+
+}
diff --git a/apps/dav/tests/unit/migration/migratecalendartest.php b/apps/dav/tests/unit/migration/migratecalendartest.php
new file mode 100644
index 00000000000..1058773ffff
--- /dev/null
+++ b/apps/dav/tests/unit/migration/migratecalendartest.php
@@ -0,0 +1,76 @@
+<?php
+/**
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @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\DAV\Tests\Unit\Migration;
+
+use OCA\DAV\CalDAV\CalDavBackend;
+use OCA\Dav\Migration\CalendarAdapter;
+use Test\TestCase;
+
+class MigrateCalendarTest extends TestCase {
+
+ public function testMigration() {
+ /** @var CalendarAdapter | \PHPUnit_Framework_MockObject_MockObject $adapter */
+ $adapter = $this->mockAdapter();
+
+ /** @var CalDavBackend | \PHPUnit_Framework_MockObject_MockObject $cardDav */
+ $cardDav = $this->getMockBuilder('\OCA\Dav\CalDAV\CalDAVBackend')->disableOriginalConstructor()->getMock();
+ $cardDav->method('createCalendar')->willReturn(666);
+ $cardDav->expects($this->once())->method('createCalendar')->with('principals/users/test01', 'test_contacts');
+ $cardDav->expects($this->once())->method('createCalendarObject')->with(666, '63f0dd6c-39d5-44be-9d34-34e7a7441fc2.ics', 'BEGIN:VCARD');
+
+ $m = new \OCA\Dav\Migration\MigrateCalendars($adapter, $cardDav);
+ $m->migrateForUser('test01');
+ }
+
+ /**
+ * @return \PHPUnit_Framework_MockObject_MockObject
+ */
+ private function mockAdapter($shares = []) {
+ $adapter = $this->getMockBuilder('\OCA\Dav\Migration\CalendarAdapter')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $adapter->method('foreachCalendar')->willReturnCallback(function ($user, \Closure $callBack) {
+ $callBack([
+ // calendarorder | calendarcolor | timezone | components
+ 'id' => 0,
+ 'userid' => $user,
+ 'displayname' => 'Test Contacts',
+ 'uri' => 'test_contacts',
+ 'ctag' => 1234567890,
+ 'active' => 1,
+ 'calendarorder' => '0',
+ 'calendarcolor' => '#b3dc6c',
+ 'timezone' => null,
+ 'components' => 'VEVENT,VTODO,VJOURNAL'
+ ]);
+ });
+ $adapter->method('foreachCalendarObject')->willReturnCallback(function ($addressBookId, \Closure $callBack) {
+ $callBack([
+ 'userid' => $addressBookId,
+ 'uri' => '63f0dd6c-39d5-44be-9d34-34e7a7441fc2.ics',
+ 'calendardata' => 'BEGIN:VCARD'
+ ]);
+ });
+ $adapter->method('getShares')->willReturn($shares);
+ return $adapter;
+ }
+
+}