Commit d8b73fde authored by Thomas Müller's avatar Thomas Müller
Browse files

Merge pull request #20371 from owncloud/add-caldav-2

Introducing CalDAV into core
parents 90bd53c9 e4568234
......@@ -183,4 +183,391 @@ CREATE TABLE addressbookchanges (
</declaration>
</table>
<!--
CREATE TABLE calendarobjects (
id INT(11) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
calendardata MEDIUMBLOB,
uri VARBINARY(200),
calendarid INTEGER UNSIGNED NOT NULL,
lastmodified INT(11) UNSIGNED,
etag VARBINARY(32),
size INT(11) UNSIGNED NOT NULL,
componenttype VARBINARY(8),
firstoccurence INT(11) UNSIGNED,
lastoccurence INT(11) UNSIGNED,
uid VARBINARY(200),
UNIQUE(calendarid, uri)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-->
<table>
<name>*dbprefix*calendarobjects</name>
<declaration>
<field>
<name>id</name>
<type>integer</type>
<default>0</default>
<notnull>true</notnull>
<autoincrement>1</autoincrement>
<unsigned>true</unsigned>
<length>11</length>
</field>
<field>
<name>calendardata</name>
<type>blob</type>
</field>
<field>
<name>uri</name>
<type>text</type>
</field>
<field>
<name>calendarid</name>
<type>integer</type>
<unsigned>true</unsigned>
<notnull>true</notnull>
</field>
<field>
<name>lastmodified</name>
<type>integer</type>
<unsigned>true</unsigned>
</field>
<field>
<name>etag</name>
<type>text</type>
<length>32</length>
</field>
<field>
<name>size</name>
<type>integer</type>
<notnull>true</notnull>
<unsigned>true</unsigned>
<length>11</length>
</field>
<field>
<name>componenttype</name>
<type>text</type>
</field>
<field>
<name>firstoccurence</name>
<type>integer</type>
<unsigned>true</unsigned>
</field>
<field>
<name>lastoccurence</name>
<type>integer</type>
<unsigned>true</unsigned>
</field>
<field>
<name>uid</name>
<type>text</type>
</field>
<index>
<name>calobjects_index</name>
<unique>true</unique>
<field>
<name>calendarid</name>
</field>
<field>
<name>uri</name>
</field>
</index>
</declaration>
</table>
<!--
CREATE TABLE calendars (
id INTEGER UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
principaluri VARBINARY(100),
displayname VARCHAR(100),
uri VARBINARY(200),
synctoken INTEGER UNSIGNED NOT NULL DEFAULT '1',
description TEXT,
calendarorder INT(11) UNSIGNED NOT NULL DEFAULT '0',
calendarcolor VARBINARY(10),
timezone TEXT,
components VARBINARY(20),
transparent TINYINT(1) NOT NULL DEFAULT '0',
UNIQUE(principaluri, uri)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-->
<table>
<name>*dbprefix*calendars</name>
<declaration>
<field>
<name>id</name>
<type>integer</type>
<default>0</default>
<notnull>true</notnull>
<autoincrement>1</autoincrement>
<unsigned>true</unsigned>
<length>11</length>
</field>
<field>
<name>principaluri</name>
<type>text</type>
</field>
<field>
<name>displayname</name>
<type>text</type>
</field>
<field>
<name>uri</name>
<type>text</type>
</field>
<field>
<name>synctoken</name>
<type>integer</type>
<default>1</default>
<notnull>true</notnull>
<unsigned>true</unsigned>
</field>
<field>
<name>description</name>
<type>text</type>
</field>
<field>
<name>calendarorder</name>
<type>integer</type>
<default>0</default>
<notnull>true</notnull>
<unsigned>true</unsigned>
</field>
<field>
<name>calendarcolor</name>
<type>text</type>
</field>
<field>
<name>timezone</name>
<type>text</type>
</field>
<field>
<name>components</name>
<type>text</type>
</field>
<field>
<name>transparent</name>
<type>integer</type>
<length>1</length>
<notnull>true</notnull>
<default>0</default>
</field>
<index>
<name>calendars_index</name>
<unique>true</unique>
<field>
<name>principaluri</name>
</field>
<field>
<name>uri</name>
</field>
</index>
</declaration>
</table>
<!--
CREATE TABLE calendarchanges (
id INT(11) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
uri VARBINARY(200) NOT NULL,
synctoken INT(11) UNSIGNED NOT NULL,
calendarid INT(11) UNSIGNED NOT NULL,
operation TINYINT(1) NOT NULL,
INDEX calendarid_synctoken (calendarid, synctoken)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-->
<table>
<name>*dbprefix*calendarchanges</name>
<declaration>
<field>
<name>id</name>
<type>integer</type>
<default>0</default>
<notnull>true</notnull>
<autoincrement>1</autoincrement>
<unsigned>true</unsigned>
<length>11</length>
</field>
<field>
<name>uri</name>
<type>text</type>
</field>
<field>
<name>synctoken</name>
<type>integer</type>
<default>1</default>
<notnull>true</notnull>
<unsigned>true</unsigned>
</field>
<field>
<name>calendarid</name>
<type>integer</type>
<notnull>true</notnull>
</field>
<field>
<name>operation</name>
<type>integer</type>
<notnull>true</notnull>
<length>1</length>
</field>
<index>
<name>calendarid_synctoken</name>
<field>
<name>calendarid</name>
</field>
<field>
<name>synctoken</name>
</field>
</index>
</declaration>
</table>
<!--
CREATE TABLE calendarsubscriptions (
id INT(11) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
uri VARBINARY(200) NOT NULL,
principaluri VARBINARY(100) NOT NULL,
source TEXT,
displayname VARCHAR(100),
refreshrate VARCHAR(10),
calendarorder INT(11) UNSIGNED NOT NULL DEFAULT '0',
calendarcolor VARBINARY(10),
striptodos TINYINT(1) NULL,
stripalarms TINYINT(1) NULL,
stripattachments TINYINT(1) NULL,
lastmodified INT(11) UNSIGNED,
UNIQUE(principaluri, uri)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-->
<table>
<name>*dbprefix*calendarsubscriptions</name>
<declaration>
<field>
<name>id</name>
<type>integer</type>
<default>0</default>
<notnull>true</notnull>
<autoincrement>1</autoincrement>
<unsigned>true</unsigned>
<length>11</length>
</field>
<field>
<name>uri</name>
<type>text</type>
</field>
<field>
<name>principaluri</name>
<type>text</type>
</field>
<field>
<name>source</name>
<type>text</type>
</field>
<field>
<name>displayname</name>
<type>text</type>
<length>100</length>
</field>
<field>
<name>refreshrate</name>
<type>text</type>
<length>10</length>
</field>
<field>
<name>calendarorder</name>
<type>integer</type>
<default>0</default>
<notnull>true</notnull>
<unsigned>true</unsigned>
</field>
<field>
<name>calendarcolor</name>
<type>text</type>
</field>
<field>
<name>striptodos</name>
<type>integer</type>
<length>1</length>
</field>
<field>
<name>stripalarms</name>
<type>integer</type>
<length>1</length>
</field>
<field>
<name>stripattachments</name>
<type>integer</type>
<length>1</length>
</field>
<field>
<name>lastmodified</name>
<type>integer</type>
<unsigned>true</unsigned>
</field>
<index>
<name>calsub_index</name>
<unique>true</unique>
<field>
<name>principaluri</name>
</field>
<field>
<name>uri</name>
</field>
</index>
</declaration>
</table>
<!--
CREATE TABLE schedulingobjects (
id INT(11) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
principaluri VARBINARY(255),
calendardata MEDIUMBLOB,
uri VARBINARY(200),
lastmodified INT(11) UNSIGNED,
etag VARBINARY(32),
size INT(11) UNSIGNED NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-->
<table>
<name>*dbprefix*schedulingobjects</name>
<declaration>
<field>
<name>id</name>
<type>integer</type>
<default>0</default>
<notnull>true</notnull>
<autoincrement>1</autoincrement>
<unsigned>true</unsigned>
<length>11</length>
</field>
<field>
<name>principaluri</name>
<type>text</type>
</field>
<field>
<name>calendardata</name>
<type>blob</type>
</field>
<field>
<name>uri</name>
<type>text</type>
</field>
<field>
<name>lastmodified</name>
<type>integer</type>
<unsigned>true</unsigned>
</field>
<field>
<name>etag</name>
<type>text</type>
<length>32</length>
</field>
<field>
<name>size</name>
<type>integer</type>
<notnull>true</notnull>
<unsigned>true</unsigned>
<length>11</length>
</field>
</declaration>
</table>
</database>
......@@ -5,7 +5,7 @@
<description>ownCloud WebDAV endpoint</description>
<licence>AGPL</licence>
<author>owncloud.org</author>
<version>0.1.2</version>
<version>0.1.3</version>
<requiremin>9.0</requiremin>
<shipped>true</shipped>
<standalone/>
......
<?php
use OCA\DAV\Command\CreateAddressBook;
use OCA\DAV\Command\CreateCalendar;
$dbConnection = \OC::$server->getDatabaseConnection();
$userManager = OC::$server->getUserManager();
/** @var Symfony\Component\Console\Application $application */
$application->add(new CreateAddressBook($userManager, $dbConnection));
$application->add(new CreateCalendar($userManager, $dbConnection));
<?php
namespace OCA\DAV\Command;
use OCA\DAV\CalDAV\CalDavBackend;
use OCP\IDBConnection;
use OCP\IUserManager;
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 CreateCalendar extends Command {
/** @var IUserManager */
protected $userManager;
/** @var \OCP\IDBConnection */
protected $dbConnection;
/**
* @param IUserManager $userManager
* @param IDBConnection $dbConnection
*/
function __construct(IUserManager $userManager, IDBConnection $dbConnection) {
parent::__construct();
$this->userManager = $userManager;
$this->dbConnection = $dbConnection;
}
protected function configure() {
$this
->setName('dav:create-calendar')
->setDescription('Create a dav calendar')
->addArgument('user',
InputArgument::REQUIRED,
'User for whom the calendar will be created')
->addArgument('name',
InputArgument::REQUIRED,
'Name of the calendar');
}
protected function execute(InputInterface $input, OutputInterface $output) {
$user = $input->getArgument('user');
if (!$this->userManager->userExists($user)) {
throw new \InvalidArgumentException("User <$user> in unknown.");
}
$name = $input->getArgument('name');
$caldav = new CalDavBackend($this->dbConnection);
$caldav->createCalendar("principals/$user", $name, []);
}
}
This diff is collapsed.
......@@ -2,8 +2,10 @@
namespace OCA\DAV;
use OCA\DAV\CalDAV\CalDavBackend;
use OCA\DAV\CardDAV\CardDavBackend;
use OCA\DAV\Connector\Sabre\Principal;
use Sabre\CalDAV\CalendarRoot;
use Sabre\CalDAV\Principal\Collection;
use Sabre\CardDAV\AddressBookRoot;
use Sabre\DAV\SimpleCollection;
......@@ -12,9 +14,10 @@ class RootCollection extends SimpleCollection {
public function __construct() {
$config = \OC::$server->getConfig();
$db = \OC::$server->getDatabaseConnection();
$principalBackend = new Principal(
$config,
\OC::$server->getUserManager()
$config,
\OC::$server->getUserManager()
);
// as soon as debug mode is enabled we allow listing of principals
$disableListing = !$config->getSystemValue('debug', false);
......@@ -24,14 +27,18 @@ class RootCollection extends SimpleCollection {
$principalCollection->disableListing = $disableListing;
$filesCollection = new Files\RootCollection($principalBackend);
$filesCollection->disableListing = $disableListing;
$cardDavBackend = new CardDavBackend(\OC::$server->getDatabaseConnection());
$caldavBackend = new CalDavBackend($db);
$calendarRoot = new CalendarRoot($principalBackend, $caldavBackend);
$calendarRoot->disableListing = $disableListing;
$cardDavBackend = new CardDavBackend($db);
$addressBookRoot = new AddressBookRoot($principalBackend, $cardDavBackend);
$addressBookRoot->disableListing = $disableListing;
$children = [
$principalCollection,
$filesCollection,
$addressBookRoot,
$principalCollection,
$filesCollection,
$calendarRoot,
$addressBookRoot,
];
parent::__construct('root', $children);
......
......@@ -33,8 +33,18 @@ class Server {
$this->server->addPlugin(new BlockLegacyClientPlugin(\OC::$server->getConfig()));
$this->server->addPlugin(new Plugin($authBackend, 'ownCloud'));
// calendar plugins
$this->server->addPlugin(new \Sabre\CalDAV\Plugin());
$this->server->addPlugin(new \Sabre\DAVACL\Plugin());
$this->server->addPlugin(new \Sabre\CalDAV\ICSExportPlugin());
$senderEmail = \OCP\Util::getDefaultEmailAddress('no-reply');
$this->server->addPlugin(new \Sabre\CalDAV\Schedule\Plugin());
$this->server->addPlugin(new \Sabre\CalDAV\Schedule\IMipPlugin($senderEmail));
$this->server->addPlugin(new \Sabre\CalDAV\SharingPlugin());
$this->server->addPlugin(new \Sabre\CalDAV\Subscriptions\Plugin());
$this->server->addPlugin(new \Sabre\CalDAV\Notifications\Plugin());
// addressbook plugins
$this->server->addPlugin(new \Sabre\CardDAV\Plugin());
// Finder on OS X requires Class 2 WebDAV support (locking), since we do
......
<?php
/**
* @author Lukas Reschke <lukas@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 Tests\Connector\Sabre;
use DateTime;
use DateTimeZone;
use OCA\DAV\CalDAV\CalDavBackend;
use Sabre\CalDAV\Property\SupportedCalendarComponentSet;
use Sabre\DAV\Property\Href;
use Sabre\DAV\PropPatch;
use Test\TestCase;
/**
* Class CalDavBackendTest
*
* @group DB
*
* @package Tests\Connector\Sabre
*/
class CalDavBackendTest extends TestCase {
/** @var CalDavBackend */
private $backend;
const UNIT_TEST_USER = 'caldav-unit-test';
public function setUp() {
parent::setUp();
$db = \OC::$server->getDatabaseConnection();
$this->backend = new CalDavBackend($db);
$this->tearDown();
}
public function tearDown() {
parent::tearDown();
if (is_null($this->backend)) {
return;
}
$books = $this->backend->getCalendarsForUser(self::UNIT_TEST_USER);
foreach ($books as $book) {
$this->backend->deleteCalendar($book['id']);
}
$subscriptions = $this->backend->getSubscriptionsForUser(self::UNIT_TEST_USER);
foreach ($subscriptions as $subscription) {
$this->backend->deleteSubscription($subscription['id']);
}
}
public function testCalendarOperations() {
$calendarId = $this->createTestCalendar();
// update it's display name
$patch = new PropPatch([
'{DAV:}displayname' => 'Unit test',
'{urn:ietf:params:xml:ns:caldav}calendar-description' => 'Calendar used for unit testing'
]);
$this->backend->updateCalendar($calendarId, $patch);
$patch->commit();
$books = $this->backend->getCalendarsForUser(self::UNIT_TEST_USER);
$this->assertEquals(1, count($books));
$this->assertEquals('Unit test', $books[0]['{DAV:}displayname']);
$this->assertEquals('Calendar used for unit testing', $books[0]['{urn:ietf:params:xml:ns:caldav}calendar-description']);
// delete the address book
$this->backend->deleteCalendar($books[0]['id']);
$books = $this->backend->getCalendarsForUser(self::UNIT_TEST_USER);