mirror of
https://github.com/nextcloud/server.git
synced 2026-05-28 04:32:30 -04:00
Merge pull request #24080 from owncloud/support-calendar-class-property
Extract CLASS property from calendar object and store it in the database
This commit is contained in:
commit
68c3b23e04
12 changed files with 753 additions and 154 deletions
|
|
@ -272,6 +272,12 @@ CREATE TABLE calendarobjects (
|
|||
<type>text</type>
|
||||
<length>255</length>
|
||||
</field>
|
||||
<field>
|
||||
<comments>0 - public, 1 - private, 2 - confidential</comments>
|
||||
<name>classification</name>
|
||||
<type>integer</type>
|
||||
<default>0</default>
|
||||
</field>
|
||||
<index>
|
||||
<name>calobjects_index</name>
|
||||
<unique>true</unique>
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
<description>ownCloud WebDAV endpoint</description>
|
||||
<licence>AGPL</licence>
|
||||
<author>owncloud.org</author>
|
||||
<version>0.2.4</version>
|
||||
<version>0.2.5</version>
|
||||
<default_enable/>
|
||||
<types>
|
||||
<filesystem/>
|
||||
|
|
@ -20,4 +20,9 @@
|
|||
<background-jobs>
|
||||
<job>OCA\DAV\CardDAV\Sync\SyncJob</job>
|
||||
</background-jobs>
|
||||
<repair-steps>
|
||||
<post-migration>
|
||||
<job>OCA\DAV\Migration\Classification</job>
|
||||
</post-migration>
|
||||
</repair-steps>
|
||||
</info>
|
||||
|
|
|
|||
|
|
@ -31,10 +31,12 @@ use OCA\DAV\CardDAV\SyncService;
|
|||
use OCA\DAV\Connector\Sabre\Principal;
|
||||
use OCA\DAV\DAV\GroupPrincipalBackend;
|
||||
use OCA\DAV\HookManager;
|
||||
use OCA\DAV\Migration\Classification;
|
||||
use \OCP\AppFramework\App;
|
||||
use OCP\AppFramework\IAppContainer;
|
||||
use OCP\Contacts\IManager;
|
||||
use OCP\IUser;
|
||||
use Sabre\VObject\Reader;
|
||||
use Symfony\Component\EventDispatcher\GenericEvent;
|
||||
|
||||
class Application extends App {
|
||||
|
|
@ -106,6 +108,14 @@ class Application extends App {
|
|||
$g
|
||||
);
|
||||
});
|
||||
|
||||
$container->registerService('OCA\DAV\Migration\Classification', function ($c) {
|
||||
/** @var IAppContainer $c */
|
||||
return new Classification(
|
||||
$c->query('CalDavBackend'),
|
||||
$c->getServer()->getUserManager()
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -37,10 +37,11 @@ use Sabre\CalDAV\Xml\Property\ScheduleCalendarTransp;
|
|||
use Sabre\CalDAV\Xml\Property\SupportedCalendarComponentSet;
|
||||
use Sabre\DAV;
|
||||
use Sabre\DAV\Exception\Forbidden;
|
||||
use Sabre\DAV\PropPatch;
|
||||
use Sabre\HTTP\URLUtil;
|
||||
use Sabre\VObject\DateTimeParser;
|
||||
use Sabre\VObject\Reader;
|
||||
use Sabre\VObject\RecurrenceIterator;
|
||||
use Sabre\VObject\Recur\EventIterator;
|
||||
|
||||
/**
|
||||
* Class CalDavBackend
|
||||
|
|
@ -61,6 +62,10 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription
|
|||
*/
|
||||
const MAX_DATE = '2038-01-01';
|
||||
|
||||
const CLASSIFICATION_PUBLIC = 0;
|
||||
const CLASSIFICATION_PRIVATE = 1;
|
||||
const CLASSIFICATION_CONFIDENTIAL = 2;
|
||||
|
||||
/**
|
||||
* List of CalDAV properties, and how they map to database field names
|
||||
* Add your own properties by simply adding on to this array.
|
||||
|
|
@ -395,10 +400,10 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription
|
|||
*
|
||||
* Read the PropPatch documentation for more info and examples.
|
||||
*
|
||||
* @param \Sabre\DAV\PropPatch $propPatch
|
||||
* @param PropPatch $propPatch
|
||||
* @return void
|
||||
*/
|
||||
function updateCalendar($calendarId, \Sabre\DAV\PropPatch $propPatch) {
|
||||
function updateCalendar($calendarId, PropPatch $propPatch) {
|
||||
$supportedProperties = array_keys($this->propertyMap);
|
||||
$supportedProperties[] = '{' . Plugin::NS_CALDAV . '}schedule-calendar-transp';
|
||||
|
||||
|
|
@ -484,7 +489,7 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription
|
|||
*/
|
||||
function getCalendarObjects($calendarId) {
|
||||
$query = $this->db->getQueryBuilder();
|
||||
$query->select(['id', 'uri', 'lastmodified', 'etag', 'calendarid', 'size', 'componenttype'])
|
||||
$query->select(['id', 'uri', 'lastmodified', 'etag', 'calendarid', 'size', 'componenttype', 'classification'])
|
||||
->from('calendarobjects')
|
||||
->where($query->expr()->eq('calendarid', $query->createNamedParameter($calendarId)));
|
||||
$stmt = $query->execute();
|
||||
|
|
@ -499,6 +504,7 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription
|
|||
'calendarid' => $row['calendarid'],
|
||||
'size' => (int)$row['size'],
|
||||
'component' => strtolower($row['componenttype']),
|
||||
'classification'=> (int)$row['classification']
|
||||
];
|
||||
}
|
||||
|
||||
|
|
@ -524,7 +530,7 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription
|
|||
function getCalendarObject($calendarId, $objectUri) {
|
||||
|
||||
$query = $this->db->getQueryBuilder();
|
||||
$query->select(['id', 'uri', 'lastmodified', 'etag', 'calendarid', 'size', 'calendardata', 'componenttype'])
|
||||
$query->select(['id', 'uri', 'lastmodified', 'etag', 'calendarid', 'size', 'calendardata', 'componenttype', 'classification'])
|
||||
->from('calendarobjects')
|
||||
->where($query->expr()->eq('calendarid', $query->createNamedParameter($calendarId)))
|
||||
->andWhere($query->expr()->eq('uri', $query->createNamedParameter($objectUri)));
|
||||
|
|
@ -542,6 +548,7 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription
|
|||
'size' => (int)$row['size'],
|
||||
'calendardata' => $this->readBlob($row['calendardata']),
|
||||
'component' => strtolower($row['componenttype']),
|
||||
'classification'=> (int)$row['classification']
|
||||
];
|
||||
}
|
||||
|
||||
|
|
@ -559,7 +566,7 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription
|
|||
*/
|
||||
function getMultipleCalendarObjects($calendarId, array $uris) {
|
||||
$query = $this->db->getQueryBuilder();
|
||||
$query->select(['id', 'uri', 'lastmodified', 'etag', 'calendarid', 'size', 'calendardata', 'componenttype'])
|
||||
$query->select(['id', 'uri', 'lastmodified', 'etag', 'calendarid', 'size', 'calendardata', 'componenttype', 'classification'])
|
||||
->from('calendarobjects')
|
||||
->where($query->expr()->eq('calendarid', $query->createNamedParameter($calendarId)))
|
||||
->andWhere($query->expr()->in('uri', $query->createParameter('uri')))
|
||||
|
|
@ -579,6 +586,7 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription
|
|||
'size' => (int)$row['size'],
|
||||
'calendardata' => $this->readBlob($row['calendardata']),
|
||||
'component' => strtolower($row['componenttype']),
|
||||
'classification' => (int)$row['classification']
|
||||
];
|
||||
|
||||
}
|
||||
|
|
@ -618,6 +626,7 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription
|
|||
'componenttype' => $query->createNamedParameter($extraData['componentType']),
|
||||
'firstoccurence' => $query->createNamedParameter($extraData['firstOccurence']),
|
||||
'lastoccurence' => $query->createNamedParameter($extraData['lastOccurence']),
|
||||
'classification' => $query->createNamedParameter($extraData['classification']),
|
||||
'uid' => $query->createNamedParameter($extraData['uid']),
|
||||
])
|
||||
->execute();
|
||||
|
|
@ -657,6 +666,7 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription
|
|||
->set('componenttype', $query->createNamedParameter($extraData['componentType']))
|
||||
->set('firstoccurence', $query->createNamedParameter($extraData['firstOccurence']))
|
||||
->set('lastoccurence', $query->createNamedParameter($extraData['lastOccurence']))
|
||||
->set('classification', $query->createNamedParameter($extraData['classification']))
|
||||
->set('uid', $query->createNamedParameter($extraData['uid']))
|
||||
->where($query->expr()->eq('calendarid', $query->createNamedParameter($calendarId)))
|
||||
->andWhere($query->expr()->eq('uri', $query->createNamedParameter($objectUri)))
|
||||
|
|
@ -667,6 +677,23 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription
|
|||
return '"' . $extraData['etag'] . '"';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $calendarObjectId
|
||||
* @param int $classification
|
||||
*/
|
||||
public function setClassification($calendarObjectId, $classification) {
|
||||
if (!in_array($classification, [
|
||||
self::CLASSIFICATION_PUBLIC, self::CLASSIFICATION_PRIVATE, self::CLASSIFICATION_CONFIDENTIAL
|
||||
])) {
|
||||
throw new \InvalidArgumentException();
|
||||
}
|
||||
$query = $this->db->getQueryBuilder();
|
||||
$query->update('calendarobjects')
|
||||
->set('classification', $query->createNamedParameter($classification))
|
||||
->where($query->expr()->eq('id', $query->createNamedParameter($calendarObjectId)))
|
||||
->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes an existing calendar object.
|
||||
*
|
||||
|
|
@ -1086,10 +1113,10 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription
|
|||
* Read the PropPatch documentation for more info and examples.
|
||||
*
|
||||
* @param mixed $subscriptionId
|
||||
* @param \Sabre\DAV\PropPatch $propPatch
|
||||
* @param PropPatch $propPatch
|
||||
* @return void
|
||||
*/
|
||||
function updateSubscription($subscriptionId, DAV\PropPatch $propPatch) {
|
||||
function updateSubscription($subscriptionId, PropPatch $propPatch) {
|
||||
$supportedProperties = array_keys($this->subscriptionPropertyMap);
|
||||
$supportedProperties[] = '{http://calendarserver.org/ns/}source';
|
||||
|
||||
|
|
@ -1280,14 +1307,15 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription
|
|||
* @param string $calendarData
|
||||
* @return array
|
||||
*/
|
||||
protected function getDenormalizedData($calendarData) {
|
||||
public function getDenormalizedData($calendarData) {
|
||||
|
||||
$vObject = Reader::read($calendarData);
|
||||
$componentType = null;
|
||||
$component = null;
|
||||
$firstOccurence = null;
|
||||
$lastOccurence = null;
|
||||
$firstOccurrence = null;
|
||||
$lastOccurrence = null;
|
||||
$uid = null;
|
||||
$classification = self::CLASSIFICATION_PUBLIC;
|
||||
foreach($vObject->getComponents() as $component) {
|
||||
if ($component->name!=='VTIMEZONE') {
|
||||
$componentType = $component->name;
|
||||
|
|
@ -1299,27 +1327,27 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription
|
|||
throw new \Sabre\DAV\Exception\BadRequest('Calendar objects must have a VJOURNAL, VEVENT or VTODO component');
|
||||
}
|
||||
if ($componentType === 'VEVENT' && $component->DTSTART) {
|
||||
$firstOccurence = $component->DTSTART->getDateTime()->getTimeStamp();
|
||||
$firstOccurrence = $component->DTSTART->getDateTime()->getTimeStamp();
|
||||
// Finding the last occurrence is a bit harder
|
||||
if (!isset($component->RRULE)) {
|
||||
if (isset($component->DTEND)) {
|
||||
$lastOccurence = $component->DTEND->getDateTime()->getTimeStamp();
|
||||
$lastOccurrence = $component->DTEND->getDateTime()->getTimeStamp();
|
||||
} elseif (isset($component->DURATION)) {
|
||||
$endDate = clone $component->DTSTART->getDateTime();
|
||||
$endDate->add(DateTimeParser::parse($component->DURATION->getValue()));
|
||||
$lastOccurence = $endDate->getTimeStamp();
|
||||
$lastOccurrence = $endDate->getTimeStamp();
|
||||
} elseif (!$component->DTSTART->hasTime()) {
|
||||
$endDate = clone $component->DTSTART->getDateTime();
|
||||
$endDate->modify('+1 day');
|
||||
$lastOccurence = $endDate->getTimeStamp();
|
||||
$lastOccurrence = $endDate->getTimeStamp();
|
||||
} else {
|
||||
$lastOccurence = $firstOccurence;
|
||||
$lastOccurrence = $firstOccurrence;
|
||||
}
|
||||
} else {
|
||||
$it = new RecurrenceIterator($vObject, (string)$component->UID);
|
||||
$it = new EventIterator($vObject, (string)$component->UID);
|
||||
$maxDate = new \DateTime(self::MAX_DATE);
|
||||
if ($it->isInfinite()) {
|
||||
$lastOccurence = $maxDate->getTimeStamp();
|
||||
$lastOccurrence = $maxDate->getTimeStamp();
|
||||
} else {
|
||||
$end = $it->getDtEnd();
|
||||
while($it->valid() && $end < $maxDate) {
|
||||
|
|
@ -1327,19 +1355,31 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription
|
|||
$it->next();
|
||||
|
||||
}
|
||||
$lastOccurence = $end->getTimeStamp();
|
||||
$lastOccurrence = $end->getTimeStamp();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if ($component->CLASS) {
|
||||
$classification = CalDavBackend::CLASSIFICATION_PRIVATE;
|
||||
switch ($component->CLASS->getValue()) {
|
||||
case 'PUBLIC':
|
||||
$classification = CalDavBackend::CLASSIFICATION_PUBLIC;
|
||||
break;
|
||||
case 'CONFIDENTIAL':
|
||||
$classification = CalDavBackend::CLASSIFICATION_CONFIDENTIAL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return [
|
||||
'etag' => md5($calendarData),
|
||||
'size' => strlen($calendarData),
|
||||
'componentType' => $componentType,
|
||||
'firstOccurence' => is_null($firstOccurence) ? null : max(0, $firstOccurence),
|
||||
'lastOccurence' => $lastOccurence,
|
||||
'uid' => $uid,
|
||||
'etag' => md5($calendarData),
|
||||
'size' => strlen($calendarData),
|
||||
'componentType' => $componentType,
|
||||
'firstOccurence' => is_null($firstOccurrence) ? null : max(0, $firstOccurrence),
|
||||
'lastOccurence' => $lastOccurrence,
|
||||
'uid' => $uid,
|
||||
'classification' => $classification
|
||||
];
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ use OCA\DAV\DAV\Sharing\IShareable;
|
|||
use OCP\IL10N;
|
||||
use Sabre\CalDAV\Backend\BackendInterface;
|
||||
use Sabre\DAV\Exception\Forbidden;
|
||||
use Sabre\DAV\Exception\NotFound;
|
||||
use Sabre\DAV\PropPatch;
|
||||
|
||||
class Calendar extends \Sabre\CalDAV\Calendar implements IShareable {
|
||||
|
|
@ -162,6 +163,78 @@ class Calendar extends \Sabre\CalDAV\Calendar implements IShareable {
|
|||
parent::propPatch($propPatch);
|
||||
}
|
||||
|
||||
function getChild($name) {
|
||||
|
||||
$obj = $this->caldavBackend->getCalendarObject($this->calendarInfo['id'], $name);
|
||||
|
||||
if (!$obj) {
|
||||
throw new NotFound('Calendar object not found');
|
||||
}
|
||||
|
||||
if ($this->isShared() && $obj['classification'] === CalDavBackend::CLASSIFICATION_PRIVATE) {
|
||||
throw new NotFound('Calendar object not found');
|
||||
}
|
||||
|
||||
$obj['acl'] = $this->getChildACL();
|
||||
|
||||
return new CalendarObject($this->caldavBackend, $this->calendarInfo, $obj);
|
||||
|
||||
}
|
||||
|
||||
function getChildren() {
|
||||
|
||||
$objs = $this->caldavBackend->getCalendarObjects($this->calendarInfo['id']);
|
||||
$children = [];
|
||||
foreach ($objs as $obj) {
|
||||
if ($this->isShared() && $obj['classification'] === CalDavBackend::CLASSIFICATION_PRIVATE) {
|
||||
continue;
|
||||
}
|
||||
$obj['acl'] = $this->getChildACL();
|
||||
$children[] = new CalendarObject($this->caldavBackend, $this->calendarInfo, $obj);
|
||||
}
|
||||
return $children;
|
||||
|
||||
}
|
||||
|
||||
function getMultipleChildren(array $paths) {
|
||||
|
||||
$objs = $this->caldavBackend->getMultipleCalendarObjects($this->calendarInfo['id'], $paths);
|
||||
$children = [];
|
||||
foreach ($objs as $obj) {
|
||||
if ($this->isShared() && $obj['classification'] === CalDavBackend::CLASSIFICATION_PRIVATE) {
|
||||
continue;
|
||||
}
|
||||
$obj['acl'] = $this->getChildACL();
|
||||
$children[] = new CalendarObject($this->caldavBackend, $this->calendarInfo, $obj);
|
||||
}
|
||||
return $children;
|
||||
|
||||
}
|
||||
|
||||
function childExists($name) {
|
||||
$obj = $this->caldavBackend->getCalendarObject($this->calendarInfo['id'], $name);
|
||||
if (!$obj) {
|
||||
return false;
|
||||
}
|
||||
if ($this->isShared() && $obj['classification'] === CalDavBackend::CLASSIFICATION_PRIVATE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function calendarQuery(array $filters) {
|
||||
|
||||
$uris = $this->caldavBackend->calendarQuery($this->calendarInfo['id'], $filters);
|
||||
if ($this->isShared()) {
|
||||
return array_filter($uris, function ($uri) {
|
||||
return $this->childExists($uri);
|
||||
});
|
||||
}
|
||||
|
||||
return $uris;
|
||||
}
|
||||
|
||||
private function canWrite() {
|
||||
if (isset($this->calendarInfo['{http://owncloud.org/ns}read-only'])) {
|
||||
return !$this->calendarInfo['{http://owncloud.org/ns}read-only'];
|
||||
|
|
@ -169,4 +242,8 @@ class Calendar extends \Sabre\CalDAV\Calendar implements IShareable {
|
|||
return true;
|
||||
}
|
||||
|
||||
private function isShared() {
|
||||
return isset($this->calendarInfo['{http://owncloud.org/ns}owner-principal']);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
92
apps/dav/lib/CalDAV/CalendarObject.php
Normal file
92
apps/dav/lib/CalDAV/CalendarObject.php
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
<?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\CalDAV;
|
||||
|
||||
|
||||
use Sabre\VObject\Component;
|
||||
use Sabre\VObject\Property;
|
||||
use Sabre\VObject\Reader;
|
||||
|
||||
class CalendarObject extends \Sabre\CalDAV\CalendarObject {
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
function get() {
|
||||
$data = parent::get();
|
||||
if ($this->isShared() && $this->objectData['classification'] === CalDavBackend::CLASSIFICATION_CONFIDENTIAL) {
|
||||
return $this->createConfidentialObject($data);
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
private function isShared() {
|
||||
return isset($this->calendarInfo['{http://owncloud.org/ns}owner-principal']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $calData
|
||||
* @return string
|
||||
*/
|
||||
private static function createConfidentialObject($calData) {
|
||||
|
||||
$vObject = Reader::read($calData);
|
||||
|
||||
/** @var Component $vElement */
|
||||
$vElement = null;
|
||||
if(isset($vObject->VEVENT)) {
|
||||
$vElement = $vObject->VEVENT;
|
||||
}
|
||||
if(isset($vObject->VJOURNAL)) {
|
||||
$vElement = $vObject->VJOURNAL;
|
||||
}
|
||||
if(isset($vObject->VTODO)) {
|
||||
$vElement = $vObject->VTODO;
|
||||
}
|
||||
if(!is_null($vElement)) {
|
||||
foreach ($vElement->children as &$property) {
|
||||
/** @var Property $property */
|
||||
switch($property->name) {
|
||||
case 'CREATED':
|
||||
case 'DTSTART':
|
||||
case 'RRULE':
|
||||
case 'DURATION':
|
||||
case 'DTEND':
|
||||
case 'CLASS':
|
||||
case 'UID':
|
||||
break;
|
||||
case 'SUMMARY':
|
||||
$property->setValue('Busy');
|
||||
break;
|
||||
default:
|
||||
$vElement->__unset($property->name);
|
||||
unset($property);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $vObject->serialize();
|
||||
}
|
||||
|
||||
}
|
||||
93
apps/dav/lib/Migration/Classification.php
Normal file
93
apps/dav/lib/Migration/Classification.php
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
<?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\Migration;
|
||||
|
||||
use OCA\DAV\CalDAV\CalDavBackend;
|
||||
use OCP\IUser;
|
||||
use OCP\IUserManager;
|
||||
use OCP\Migration\IOutput;
|
||||
use OCP\Migration\IRepairStep;
|
||||
|
||||
class Classification implements IRepairStep {
|
||||
|
||||
/** @var CalDavBackend */
|
||||
private $calDavBackend;
|
||||
|
||||
/** @var IUserManager */
|
||||
private $userManager;
|
||||
|
||||
/**
|
||||
* Classification constructor.
|
||||
*
|
||||
* @param CalDavBackend $calDavBackend
|
||||
*/
|
||||
public function __construct(CalDavBackend $calDavBackend, IUserManager $userManager) {
|
||||
$this->calDavBackend = $calDavBackend;
|
||||
$this->userManager = $userManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param IUser $user
|
||||
*/
|
||||
public function runForUser($user) {
|
||||
$principal = 'principals/users/' . $user->getUID();
|
||||
$calendars = $this->calDavBackend->getCalendarsForUser($principal);
|
||||
foreach ($calendars as $calendar) {
|
||||
$objects = $this->calDavBackend->getCalendarObjects($calendar['id']);
|
||||
foreach ($objects as $object) {
|
||||
$calObject = $this->calDavBackend->getCalendarObject($calendar['id'], $object['uri']);
|
||||
$classification = $this->extractClassification($calObject['calendardata']);
|
||||
$this->calDavBackend->setClassification($object['id'], $classification);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $calendarData
|
||||
* @return integer
|
||||
* @throws \Sabre\DAV\Exception\BadRequest
|
||||
*/
|
||||
protected function extractClassification($calendarData) {
|
||||
return $this->calDavBackend->getDenormalizedData($calendarData)['classification'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getName() {
|
||||
return 'Fix classification for calendar objects';
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function run(IOutput $output) {
|
||||
$output->startProgress();
|
||||
$this->userManager->callForAllUsers(function($user) use ($output) {
|
||||
/** @var IUser $user */
|
||||
$output->advance(1, $user->getDisplayName());
|
||||
$this->runForUser($user);
|
||||
});
|
||||
$output->finishProgress();
|
||||
}
|
||||
}
|
||||
163
apps/dav/tests/unit/CalDAV/AbstractCalDavBackendTest.php
Normal file
163
apps/dav/tests/unit/CalDAV/AbstractCalDavBackendTest.php
Normal file
|
|
@ -0,0 +1,163 @@
|
|||
<?php
|
||||
/**
|
||||
* @author Joas Schilling <nickvergessen@owncloud.com>
|
||||
* @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\CalDAV;
|
||||
|
||||
use DateTime;
|
||||
use DateTimeZone;
|
||||
use OCA\DAV\CalDAV\CalDavBackend;
|
||||
use OCA\DAV\CalDAV\Calendar;
|
||||
use OCA\DAV\Connector\Sabre\Principal;
|
||||
use OCP\IL10N;
|
||||
use Sabre\CalDAV\Xml\Property\SupportedCalendarComponentSet;
|
||||
use Sabre\DAV\PropPatch;
|
||||
use Sabre\DAV\Xml\Property\Href;
|
||||
use Sabre\DAVACL\IACL;
|
||||
use Test\TestCase;
|
||||
|
||||
/**
|
||||
* Class CalDavBackendTest
|
||||
*
|
||||
* @group DB
|
||||
*
|
||||
* @package OCA\DAV\Tests\unit\CalDAV
|
||||
*/
|
||||
abstract class AbstractCalDavBackendTest extends TestCase {
|
||||
|
||||
/** @var CalDavBackend */
|
||||
protected $backend;
|
||||
|
||||
/** @var Principal | \PHPUnit_Framework_MockObject_MockObject */
|
||||
protected $principal;
|
||||
|
||||
const UNIT_TEST_USER = 'principals/users/caldav-unit-test';
|
||||
const UNIT_TEST_USER1 = 'principals/users/caldav-unit-test1';
|
||||
const UNIT_TEST_GROUP = 'principals/groups/caldav-unit-test-group';
|
||||
|
||||
public function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->principal = $this->getMockBuilder('OCA\DAV\Connector\Sabre\Principal')
|
||||
->disableOriginalConstructor()
|
||||
->setMethods(['getPrincipalByPath', 'getGroupMembership'])
|
||||
->getMock();
|
||||
$this->principal->expects($this->any())->method('getPrincipalByPath')
|
||||
->willReturn([
|
||||
'uri' => 'principals/best-friend'
|
||||
]);
|
||||
$this->principal->expects($this->any())->method('getGroupMembership')
|
||||
->withAnyParameters()
|
||||
->willReturn([self::UNIT_TEST_GROUP]);
|
||||
|
||||
$db = \OC::$server->getDatabaseConnection();
|
||||
$this->backend = new CalDavBackend($db, $this->principal);
|
||||
|
||||
$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']);
|
||||
}
|
||||
}
|
||||
|
||||
protected function createTestCalendar() {
|
||||
$this->backend->createCalendar(self::UNIT_TEST_USER, 'Example', [
|
||||
'{http://apple.com/ns/ical/}calendar-color' => '#1C4587FF'
|
||||
]);
|
||||
$calendars = $this->backend->getCalendarsForUser(self::UNIT_TEST_USER);
|
||||
$this->assertEquals(1, count($calendars));
|
||||
$this->assertEquals(self::UNIT_TEST_USER, $calendars[0]['principaluri']);
|
||||
/** @var SupportedCalendarComponentSet $components */
|
||||
$components = $calendars[0]['{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set'];
|
||||
$this->assertEquals(['VEVENT','VTODO'], $components->getValue());
|
||||
$color = $calendars[0]['{http://apple.com/ns/ical/}calendar-color'];
|
||||
$this->assertEquals('#1C4587FF', $color);
|
||||
$this->assertEquals('Example', $calendars[0]['uri']);
|
||||
$this->assertEquals('Example', $calendars[0]['{DAV:}displayname']);
|
||||
$calendarId = $calendars[0]['id'];
|
||||
|
||||
return $calendarId;
|
||||
}
|
||||
|
||||
protected function createEvent($calendarId, $start = '20130912T130000Z', $end = '20130912T140000Z') {
|
||||
|
||||
$calData = <<<EOD
|
||||
BEGIN:VCALENDAR
|
||||
VERSION:2.0
|
||||
PRODID:ownCloud Calendar
|
||||
BEGIN:VEVENT
|
||||
CREATED;VALUE=DATE-TIME:20130910T125139Z
|
||||
UID:47d15e3ec8
|
||||
LAST-MODIFIED;VALUE=DATE-TIME:20130910T125139Z
|
||||
DTSTAMP;VALUE=DATE-TIME:20130910T125139Z
|
||||
SUMMARY:Test Event
|
||||
DTSTART;VALUE=DATE-TIME:$start
|
||||
DTEND;VALUE=DATE-TIME:$end
|
||||
CLASS:PUBLIC
|
||||
END:VEVENT
|
||||
END:VCALENDAR
|
||||
EOD;
|
||||
$uri0 = $this->getUniqueID('event');
|
||||
$this->backend->createCalendarObject($calendarId, $uri0, $calData);
|
||||
|
||||
return $uri0;
|
||||
}
|
||||
|
||||
protected function assertAcl($principal, $privilege, $acl) {
|
||||
foreach($acl as $a) {
|
||||
if ($a['principal'] === $principal && $a['privilege'] === $privilege) {
|
||||
$this->assertTrue(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
$this->fail("ACL does not contain $principal / $privilege");
|
||||
}
|
||||
|
||||
protected function assertNotAcl($principal, $privilege, $acl) {
|
||||
foreach($acl as $a) {
|
||||
if ($a['principal'] === $principal && $a['privilege'] === $privilege) {
|
||||
$this->fail("ACL contains $principal / $privilege");
|
||||
return;
|
||||
}
|
||||
}
|
||||
$this->assertTrue(true);
|
||||
}
|
||||
|
||||
protected function assertAccess($shouldHaveAcl, $principal, $privilege, $acl) {
|
||||
if ($shouldHaveAcl) {
|
||||
$this->assertAcl($principal, $privilege, $acl);
|
||||
} else {
|
||||
$this->assertNotAcl($principal, $privilege, $acl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -26,13 +26,10 @@ use DateTime;
|
|||
use DateTimeZone;
|
||||
use OCA\DAV\CalDAV\CalDavBackend;
|
||||
use OCA\DAV\CalDAV\Calendar;
|
||||
use OCA\DAV\Connector\Sabre\Principal;
|
||||
use OCP\IL10N;
|
||||
use Sabre\CalDAV\Xml\Property\SupportedCalendarComponentSet;
|
||||
use Sabre\DAV\PropPatch;
|
||||
use Sabre\DAV\Xml\Property\Href;
|
||||
use Sabre\DAVACL\IACL;
|
||||
use Test\TestCase;
|
||||
|
||||
/**
|
||||
* Class CalDavBackendTest
|
||||
|
|
@ -41,54 +38,7 @@ use Test\TestCase;
|
|||
*
|
||||
* @package OCA\DAV\Tests\unit\CalDAV
|
||||
*/
|
||||
class CalDavBackendTest extends TestCase {
|
||||
|
||||
/** @var CalDavBackend */
|
||||
private $backend;
|
||||
|
||||
/** @var Principal | \PHPUnit_Framework_MockObject_MockObject */
|
||||
private $principal;
|
||||
|
||||
const UNIT_TEST_USER = 'principals/users/caldav-unit-test';
|
||||
const UNIT_TEST_USER1 = 'principals/users/caldav-unit-test1';
|
||||
const UNIT_TEST_GROUP = 'principals/groups/caldav-unit-test-group';
|
||||
|
||||
public function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->principal = $this->getMockBuilder('OCA\DAV\Connector\Sabre\Principal')
|
||||
->disableOriginalConstructor()
|
||||
->setMethods(['getPrincipalByPath', 'getGroupMembership'])
|
||||
->getMock();
|
||||
$this->principal->expects($this->any())->method('getPrincipalByPath')
|
||||
->willReturn([
|
||||
'uri' => 'principals/best-friend'
|
||||
]);
|
||||
$this->principal->expects($this->any())->method('getGroupMembership')
|
||||
->withAnyParameters()
|
||||
->willReturn([self::UNIT_TEST_GROUP]);
|
||||
|
||||
$db = \OC::$server->getDatabaseConnection();
|
||||
$this->backend = new CalDavBackend($db, $this->principal);
|
||||
|
||||
$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']);
|
||||
}
|
||||
}
|
||||
class CalDavBackendTest extends AbstractCalDavBackendTest {
|
||||
|
||||
public function testCalendarOperations() {
|
||||
|
||||
|
|
@ -232,6 +182,7 @@ EOD;
|
|||
$calendarObjects = $this->backend->getCalendarObjects($calendarId);
|
||||
$this->assertEquals(1, count($calendarObjects));
|
||||
$this->assertEquals($calendarId, $calendarObjects[0]['calendarid']);
|
||||
$this->assertArrayHasKey('classification', $calendarObjects[0]);
|
||||
|
||||
// get the cards
|
||||
$calendarObject = $this->backend->getCalendarObject($calendarId, $uri);
|
||||
|
|
@ -241,6 +192,7 @@ EOD;
|
|||
$this->assertArrayHasKey('lastmodified', $calendarObject);
|
||||
$this->assertArrayHasKey('etag', $calendarObject);
|
||||
$this->assertArrayHasKey('size', $calendarObject);
|
||||
$this->assertArrayHasKey('classification', $calendarObject);
|
||||
$this->assertEquals($calData, $calendarObject['calendardata']);
|
||||
|
||||
// update the card
|
||||
|
|
@ -310,6 +262,7 @@ EOD;
|
|||
$this->assertArrayHasKey('lastmodified', $card);
|
||||
$this->assertArrayHasKey('etag', $card);
|
||||
$this->assertArrayHasKey('size', $card);
|
||||
$this->assertArrayHasKey('classification', $card);
|
||||
$this->assertEquals($calData, $card['calendardata']);
|
||||
}
|
||||
|
||||
|
|
@ -363,49 +316,6 @@ EOD;
|
|||
];
|
||||
}
|
||||
|
||||
private function createTestCalendar() {
|
||||
$this->backend->createCalendar(self::UNIT_TEST_USER, 'Example', [
|
||||
'{http://apple.com/ns/ical/}calendar-color' => '#1C4587FF'
|
||||
]);
|
||||
$calendars = $this->backend->getCalendarsForUser(self::UNIT_TEST_USER);
|
||||
$this->assertEquals(1, count($calendars));
|
||||
$this->assertEquals(self::UNIT_TEST_USER, $calendars[0]['principaluri']);
|
||||
/** @var SupportedCalendarComponentSet $components */
|
||||
$components = $calendars[0]['{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set'];
|
||||
$this->assertEquals(['VEVENT','VTODO'], $components->getValue());
|
||||
$color = $calendars[0]['{http://apple.com/ns/ical/}calendar-color'];
|
||||
$this->assertEquals('#1C4587FF', $color);
|
||||
$this->assertEquals('Example', $calendars[0]['uri']);
|
||||
$this->assertEquals('Example', $calendars[0]['{DAV:}displayname']);
|
||||
$calendarId = $calendars[0]['id'];
|
||||
|
||||
return $calendarId;
|
||||
}
|
||||
|
||||
private function createEvent($calendarId, $start = '20130912T130000Z', $end = '20130912T140000Z') {
|
||||
|
||||
$calData = <<<EOD
|
||||
BEGIN:VCALENDAR
|
||||
VERSION:2.0
|
||||
PRODID:ownCloud Calendar
|
||||
BEGIN:VEVENT
|
||||
CREATED;VALUE=DATE-TIME:20130910T125139Z
|
||||
UID:47d15e3ec8
|
||||
LAST-MODIFIED;VALUE=DATE-TIME:20130910T125139Z
|
||||
DTSTAMP;VALUE=DATE-TIME:20130910T125139Z
|
||||
SUMMARY:Test Event
|
||||
DTSTART;VALUE=DATE-TIME:$start
|
||||
DTEND;VALUE=DATE-TIME:$end
|
||||
CLASS:PUBLIC
|
||||
END:VEVENT
|
||||
END:VCALENDAR
|
||||
EOD;
|
||||
$uri0 = $this->getUniqueID('event');
|
||||
$this->backend->createCalendarObject($calendarId, $uri0, $calData);
|
||||
|
||||
return $uri0;
|
||||
}
|
||||
|
||||
public function testSyncSupport() {
|
||||
$calendarId = $this->createTestCalendar();
|
||||
|
||||
|
|
@ -464,43 +374,20 @@ EOD;
|
|||
/**
|
||||
* @dataProvider providesCalDataForGetDenormalizedData
|
||||
*/
|
||||
public function testGetDenormalizedData($expectedFirstOccurance, $calData) {
|
||||
$actual = $this->invokePrivate($this->backend, 'getDenormalizedData', [$calData]);
|
||||
$this->assertEquals($expectedFirstOccurance, $actual['firstOccurence']);
|
||||
public function testGetDenormalizedData($expected, $key, $calData) {
|
||||
$actual = $this->backend->getDenormalizedData($calData);
|
||||
$this->assertEquals($expected, $actual[$key]);
|
||||
}
|
||||
|
||||
public function providesCalDataForGetDenormalizedData() {
|
||||
return [
|
||||
[0, "BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:-//Sabre//Sabre VObject 3.5.0//EN\r\nCALSCALE:GREGORIAN\r\nBEGIN:VEVENT\r\nUID:413F269B-B51B-46B1-AFB6-40055C53A4DC\r\nDTSTAMP:20160309T095056Z\r\nDTSTART;VALUE=DATE:16040222\r\nDTEND;VALUE=DATE:16040223\r\nRRULE:FREQ=YEARLY\r\nSUMMARY:SUMMARY\r\nTRANSP:TRANSPARENT\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"],
|
||||
[null, "BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:-//Sabre//Sabre VObject 3.5.0//EN\r\nCALSCALE:GREGORIAN\r\nBEGIN:VEVENT\r\nUID:413F269B-B51B-46B1-AFB6-40055C53A4DC\r\nDTSTAMP:20160309T095056Z\r\nRRULE:FREQ=YEARLY\r\nSUMMARY:SUMMARY\r\nTRANSP:TRANSPARENT\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"]
|
||||
'first occurrence before unix epoch starts' => [0, 'firstOccurence', "BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:-//Sabre//Sabre VObject 3.5.0//EN\r\nCALSCALE:GREGORIAN\r\nBEGIN:VEVENT\r\nUID:413F269B-B51B-46B1-AFB6-40055C53A4DC\r\nDTSTAMP:20160309T095056Z\r\nDTSTART;VALUE=DATE:16040222\r\nDTEND;VALUE=DATE:16040223\r\nRRULE:FREQ=YEARLY\r\nSUMMARY:SUMMARY\r\nTRANSP:TRANSPARENT\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"],
|
||||
'no first occurrence because yearly' => [null, 'firstOccurence', "BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:-//Sabre//Sabre VObject 3.5.0//EN\r\nCALSCALE:GREGORIAN\r\nBEGIN:VEVENT\r\nUID:413F269B-B51B-46B1-AFB6-40055C53A4DC\r\nDTSTAMP:20160309T095056Z\r\nRRULE:FREQ=YEARLY\r\nSUMMARY:SUMMARY\r\nTRANSP:TRANSPARENT\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"],
|
||||
'CLASS:PRIVATE' => [CalDavBackend::CLASSIFICATION_PRIVATE, 'classification', "BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:-//dmfs.org//mimedir.icalendar//EN\r\nBEGIN:VTIMEZONE\r\nTZID:Europe/Berlin\r\nX-LIC-LOCATION:Europe/Berlin\r\nBEGIN:DAYLIGHT\r\nTZOFFSETFROM:+0100\r\nTZOFFSETTO:+0200\r\nTZNAME:CEST\r\nDTSTART:19700329T020000\r\nRRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU\r\nEND:DAYLIGHT\r\nBEGIN:STANDARD\r\nTZOFFSETFROM:+0200\r\nTZOFFSETTO:+0100\r\nTZNAME:CET\r\nDTSTART:19701025T030000\r\nRRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU\r\nEND:STANDARD\r\nEND:VTIMEZONE\r\nBEGIN:VEVENT\r\nDTSTART;TZID=Europe/Berlin:20160419T130000\r\nSUMMARY:Test\r\nCLASS:PRIVATE\r\nTRANSP:OPAQUE\r\nSTATUS:CONFIRMED\r\nDTEND;TZID=Europe/Berlin:20160419T140000\r\nLAST-MODIFIED:20160419T074202Z\r\nDTSTAMP:20160419T074202Z\r\nCREATED:20160419T074202Z\r\nUID:2e468c48-7860-492e-bc52-92fa0daeeccf.1461051722310\r\nEND:VEVENT\r\nEND:VCALENDAR"],
|
||||
'CLASS:PUBLIC' => [CalDavBackend::CLASSIFICATION_PUBLIC, 'classification', "BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:-//dmfs.org//mimedir.icalendar//EN\r\nBEGIN:VTIMEZONE\r\nTZID:Europe/Berlin\r\nX-LIC-LOCATION:Europe/Berlin\r\nBEGIN:DAYLIGHT\r\nTZOFFSETFROM:+0100\r\nTZOFFSETTO:+0200\r\nTZNAME:CEST\r\nDTSTART:19700329T020000\r\nRRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU\r\nEND:DAYLIGHT\r\nBEGIN:STANDARD\r\nTZOFFSETFROM:+0200\r\nTZOFFSETTO:+0100\r\nTZNAME:CET\r\nDTSTART:19701025T030000\r\nRRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU\r\nEND:STANDARD\r\nEND:VTIMEZONE\r\nBEGIN:VEVENT\r\nDTSTART;TZID=Europe/Berlin:20160419T130000\r\nSUMMARY:Test\r\nCLASS:PUBLIC\r\nTRANSP:OPAQUE\r\nSTATUS:CONFIRMED\r\nDTEND;TZID=Europe/Berlin:20160419T140000\r\nLAST-MODIFIED:20160419T074202Z\r\nDTSTAMP:20160419T074202Z\r\nCREATED:20160419T074202Z\r\nUID:2e468c48-7860-492e-bc52-92fa0daeeccf.1461051722310\r\nEND:VEVENT\r\nEND:VCALENDAR"],
|
||||
'CLASS:CONFIDENTIAL' => [CalDavBackend::CLASSIFICATION_CONFIDENTIAL, 'classification', "BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:-//dmfs.org//mimedir.icalendar//EN\r\nBEGIN:VTIMEZONE\r\nTZID:Europe/Berlin\r\nX-LIC-LOCATION:Europe/Berlin\r\nBEGIN:DAYLIGHT\r\nTZOFFSETFROM:+0100\r\nTZOFFSETTO:+0200\r\nTZNAME:CEST\r\nDTSTART:19700329T020000\r\nRRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU\r\nEND:DAYLIGHT\r\nBEGIN:STANDARD\r\nTZOFFSETFROM:+0200\r\nTZOFFSETTO:+0100\r\nTZNAME:CET\r\nDTSTART:19701025T030000\r\nRRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU\r\nEND:STANDARD\r\nEND:VTIMEZONE\r\nBEGIN:VEVENT\r\nDTSTART;TZID=Europe/Berlin:20160419T130000\r\nSUMMARY:Test\r\nCLASS:CONFIDENTIAL\r\nTRANSP:OPAQUE\r\nSTATUS:CONFIRMED\r\nDTEND;TZID=Europe/Berlin:20160419T140000\r\nLAST-MODIFIED:20160419T074202Z\r\nDTSTAMP:20160419T074202Z\r\nCREATED:20160419T074202Z\r\nUID:2e468c48-7860-492e-bc52-92fa0daeeccf.1461051722310\r\nEND:VEVENT\r\nEND:VCALENDAR"],
|
||||
'no class set -> public' => [CalDavBackend::CLASSIFICATION_PUBLIC, 'classification', "BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:-//dmfs.org//mimedir.icalendar//EN\r\nBEGIN:VTIMEZONE\r\nTZID:Europe/Berlin\r\nX-LIC-LOCATION:Europe/Berlin\r\nBEGIN:DAYLIGHT\r\nTZOFFSETFROM:+0100\r\nTZOFFSETTO:+0200\r\nTZNAME:CEST\r\nDTSTART:19700329T020000\r\nRRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU\r\nEND:DAYLIGHT\r\nBEGIN:STANDARD\r\nTZOFFSETFROM:+0200\r\nTZOFFSETTO:+0100\r\nTZNAME:CET\r\nDTSTART:19701025T030000\r\nRRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU\r\nEND:STANDARD\r\nEND:VTIMEZONE\r\nBEGIN:VEVENT\r\nDTSTART;TZID=Europe/Berlin:20160419T130000\r\nSUMMARY:Test\r\nTRANSP:OPAQUE\r\nDTEND;TZID=Europe/Berlin:20160419T140000\r\nLAST-MODIFIED:20160419T074202Z\r\nDTSTAMP:20160419T074202Z\r\nCREATED:20160419T074202Z\r\nUID:2e468c48-7860-492e-bc52-92fa0daeeccf.1461051722310\r\nEND:VEVENT\r\nEND:VCALENDAR"],
|
||||
'unknown class -> private' => [CalDavBackend::CLASSIFICATION_PRIVATE, 'classification', "BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:-//dmfs.org//mimedir.icalendar//EN\r\nBEGIN:VTIMEZONE\r\nTZID:Europe/Berlin\r\nX-LIC-LOCATION:Europe/Berlin\r\nBEGIN:DAYLIGHT\r\nTZOFFSETFROM:+0100\r\nTZOFFSETTO:+0200\r\nTZNAME:CEST\r\nDTSTART:19700329T020000\r\nRRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU\r\nEND:DAYLIGHT\r\nBEGIN:STANDARD\r\nTZOFFSETFROM:+0200\r\nTZOFFSETTO:+0100\r\nTZNAME:CET\r\nDTSTART:19701025T030000\r\nRRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU\r\nEND:STANDARD\r\nEND:VTIMEZONE\r\nBEGIN:VEVENT\r\nDTSTART;TZID=Europe/Berlin:20160419T130000\r\nSUMMARY:Test\r\nCLASS:VERTRAULICH\r\nTRANSP:OPAQUE\r\nSTATUS:CONFIRMED\r\nDTEND;TZID=Europe/Berlin:20160419T140000\r\nLAST-MODIFIED:20160419T074202Z\r\nDTSTAMP:20160419T074202Z\r\nCREATED:20160419T074202Z\r\nUID:2e468c48-7860-492e-bc52-92fa0daeeccf.1461051722310\r\nEND:VEVENT\r\nEND:VCALENDAR"],
|
||||
];
|
||||
}
|
||||
|
||||
private function assertAcl($principal, $privilege, $acl) {
|
||||
foreach($acl as $a) {
|
||||
if ($a['principal'] === $principal && $a['privilege'] === $privilege) {
|
||||
$this->assertTrue(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
$this->fail("ACL does not contain $principal / $privilege");
|
||||
}
|
||||
|
||||
private function assertNotAcl($principal, $privilege, $acl) {
|
||||
foreach($acl as $a) {
|
||||
if ($a['principal'] === $principal && $a['privilege'] === $privilege) {
|
||||
$this->fail("ACL contains $principal / $privilege");
|
||||
return;
|
||||
}
|
||||
}
|
||||
$this->assertTrue(true);
|
||||
}
|
||||
|
||||
private function assertAccess($shouldHaveAcl, $principal, $privilege, $acl) {
|
||||
if ($shouldHaveAcl) {
|
||||
$this->assertAcl($principal, $privilege, $acl);
|
||||
} else {
|
||||
$this->assertNotAcl($principal, $privilege, $acl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ use OCA\DAV\CalDAV\CalDavBackend;
|
|||
use OCA\DAV\CalDAV\Calendar;
|
||||
use OCP\IL10N;
|
||||
use Sabre\DAV\PropPatch;
|
||||
use Sabre\VObject\Reader;
|
||||
use Test\TestCase;
|
||||
|
||||
class CalendarTest extends TestCase {
|
||||
|
|
@ -189,4 +190,153 @@ class CalendarTest extends TestCase {
|
|||
'birthday calendar' => [false, false, false, BirthdayService::BIRTHDAY_CALENDAR_URI]
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider providesConfidentialClassificationData
|
||||
* @param $expectedChildren
|
||||
* @param $isShared
|
||||
*/
|
||||
public function testPrivateClassification($expectedChildren, $isShared) {
|
||||
|
||||
$calObject0 = ['uri' => 'event-0', 'classification' => CalDavBackend::CLASSIFICATION_PUBLIC];
|
||||
$calObject1 = ['uri' => 'event-1', 'classification' => CalDavBackend::CLASSIFICATION_CONFIDENTIAL];
|
||||
$calObject2 = ['uri' => 'event-2', 'classification' => CalDavBackend::CLASSIFICATION_PRIVATE];
|
||||
|
||||
/** @var \PHPUnit_Framework_MockObject_MockObject | CalDavBackend $backend */
|
||||
$backend = $this->getMockBuilder('OCA\DAV\CalDAV\CalDavBackend')->disableOriginalConstructor()->getMock();
|
||||
$backend->expects($this->any())->method('getCalendarObjects')->willReturn([
|
||||
$calObject0, $calObject1, $calObject2
|
||||
]);
|
||||
$backend->expects($this->any())->method('getMultipleCalendarObjects')
|
||||
->with(666, ['event-0', 'event-1', 'event-2'])
|
||||
->willReturn([
|
||||
$calObject0, $calObject1, $calObject2
|
||||
]);
|
||||
$backend->expects($this->any())->method('getCalendarObject')
|
||||
->willReturn($calObject2)->with(666, 'event-2');
|
||||
|
||||
$calendarInfo = [
|
||||
'principaluri' => 'user2',
|
||||
'id' => 666,
|
||||
'uri' => 'cal',
|
||||
];
|
||||
|
||||
if ($isShared) {
|
||||
$calendarInfo['{http://owncloud.org/ns}owner-principal'] = 'user1';
|
||||
|
||||
}
|
||||
$c = new Calendar($backend, $calendarInfo, $this->l10n);
|
||||
$children = $c->getChildren();
|
||||
$this->assertEquals($expectedChildren, count($children));
|
||||
$children = $c->getMultipleChildren(['event-0', 'event-1', 'event-2']);
|
||||
$this->assertEquals($expectedChildren, count($children));
|
||||
|
||||
$this->assertEquals(!$isShared, $c->childExists('event-2'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider providesConfidentialClassificationData
|
||||
* @param $expectedChildren
|
||||
* @param $isShared
|
||||
*/
|
||||
public function testConfidentialClassification($expectedChildren, $isShared) {
|
||||
$start = '20160609';
|
||||
$end = '20160610';
|
||||
|
||||
$calData = <<<EOD
|
||||
BEGIN:VCALENDAR
|
||||
PRODID:-//ownCloud calendar v1.2.2
|
||||
BEGIN:VEVENT
|
||||
CREATED:20160602T133732
|
||||
DTSTAMP:20160602T133732
|
||||
LAST-MODIFIED:20160602T133732
|
||||
UID:wej2z68l9h
|
||||
SUMMARY:Test Event
|
||||
LOCATION:Somewhere ...
|
||||
ATTENDEE;ROLE=REQ-PARTICIPANT;PARTSTAT=NEEDS-ACTION;CUTYPE=INDIVIDUAL;CN=de
|
||||
epdiver:MAILTO:thomas.mueller@tmit.eu
|
||||
ORGANIZER;CN=deepdiver:MAILTO:thomas.mueller@tmit.eu
|
||||
DESCRIPTION:maybe ....
|
||||
DTSTART;TZID=Europe/Berlin;VALUE=DATE:$start
|
||||
DTEND;TZID=Europe/Berlin;VALUE=DATE:$end
|
||||
RRULE:FREQ=DAILY
|
||||
BEGIN:VALARM
|
||||
ACTION:AUDIO
|
||||
TRIGGER:-PT15M
|
||||
END:VALARM
|
||||
END:VEVENT
|
||||
BEGIN:VTIMEZONE
|
||||
TZID:Europe/Berlin
|
||||
BEGIN:DAYLIGHT
|
||||
DTSTART:19810329T020000
|
||||
RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU
|
||||
TZNAME:MESZ
|
||||
TZOFFSETFROM:+0100
|
||||
TZOFFSETTO:+0200
|
||||
END:DAYLIGHT
|
||||
BEGIN:STANDARD
|
||||
DTSTART:19961027T030000
|
||||
RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU
|
||||
TZNAME:MEZ
|
||||
TZOFFSETFROM:+0200
|
||||
TZOFFSETTO:+0100
|
||||
END:STANDARD
|
||||
END:VTIMEZONE
|
||||
END:VCALENDAR
|
||||
EOD;
|
||||
|
||||
$calObject0 = ['uri' => 'event-0', 'classification' => CalDavBackend::CLASSIFICATION_PUBLIC];
|
||||
$calObject1 = ['uri' => 'event-1', 'classification' => CalDavBackend::CLASSIFICATION_CONFIDENTIAL, 'calendardata' => $calData];
|
||||
$calObject2 = ['uri' => 'event-2', 'classification' => CalDavBackend::CLASSIFICATION_PRIVATE];
|
||||
|
||||
/** @var \PHPUnit_Framework_MockObject_MockObject | CalDavBackend $backend */
|
||||
$backend = $this->getMockBuilder('OCA\DAV\CalDAV\CalDavBackend')->disableOriginalConstructor()->getMock();
|
||||
$backend->expects($this->any())->method('getCalendarObjects')->willReturn([
|
||||
$calObject0, $calObject1, $calObject2
|
||||
]);
|
||||
$backend->expects($this->any())->method('getMultipleCalendarObjects')
|
||||
->with(666, ['event-0', 'event-1', 'event-2'])
|
||||
->willReturn([
|
||||
$calObject0, $calObject1, $calObject2
|
||||
]);
|
||||
$backend->expects($this->any())->method('getCalendarObject')
|
||||
->willReturn($calObject1)->with(666, 'event-1');
|
||||
|
||||
$calendarInfo = [
|
||||
'principaluri' => 'user2',
|
||||
'id' => 666,
|
||||
'uri' => 'cal',
|
||||
];
|
||||
|
||||
if ($isShared) {
|
||||
$calendarInfo['{http://owncloud.org/ns}owner-principal'] = 'user1';
|
||||
|
||||
}
|
||||
$c = new Calendar($backend, $calendarInfo, $this->l10n);
|
||||
|
||||
// test private event
|
||||
$privateEvent = $c->getChild('event-1');
|
||||
$calData = $privateEvent->get();
|
||||
$event = Reader::read($calData);
|
||||
|
||||
$this->assertEquals($start, $event->VEVENT->DTSTART->getValue());
|
||||
$this->assertEquals($end, $event->VEVENT->DTEND->getValue());
|
||||
|
||||
if ($isShared) {
|
||||
$this->assertEquals('Busy', $event->VEVENT->SUMMARY->getValue());
|
||||
$this->assertArrayNotHasKey('ATTENDEE', $event->VEVENT);
|
||||
$this->assertArrayNotHasKey('LOCATION', $event->VEVENT);
|
||||
$this->assertArrayNotHasKey('DESCRIPTION', $event->VEVENT);
|
||||
$this->assertArrayNotHasKey('ORGANIZER', $event->VEVENT);
|
||||
} else {
|
||||
$this->assertEquals('Test Event', $event->VEVENT->SUMMARY->getValue());
|
||||
}
|
||||
}
|
||||
|
||||
public function providesConfidentialClassificationData() {
|
||||
return [
|
||||
[3, false],
|
||||
[2, true]
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
75
apps/dav/tests/unit/Migration/ClassificationTest.php
Normal file
75
apps/dav/tests/unit/Migration/ClassificationTest.php
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
<?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\DAV\Migration;
|
||||
|
||||
use OCA\DAV\CalDAV\CalDavBackend;
|
||||
use OCA\DAV\Migration\Classification;
|
||||
use OCA\DAV\Tests\unit\CalDAV\AbstractCalDavBackendTest;
|
||||
use OCP\IUser;
|
||||
|
||||
/**
|
||||
* Class ClassificationTest
|
||||
*
|
||||
* @group DB
|
||||
*
|
||||
* @package OCA\DAV\Tests\unit\DAV
|
||||
*/
|
||||
class ClassificationTest extends AbstractCalDavBackendTest {
|
||||
|
||||
/** @var \PHPUnit_Framework_MockObject_MockObject | \OCP\IUserManager */
|
||||
private $userManager;
|
||||
|
||||
public function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->userManager = $this->getMockBuilder('OCP\IUserManager')
|
||||
->disableOriginalConstructor()->getMock();
|
||||
}
|
||||
|
||||
public function test() {
|
||||
// setup data
|
||||
$calendarId = $this->createTestCalendar();
|
||||
$eventUri = $this->createEvent($calendarId, '20130912T130000Z', '20130912T140000Z');
|
||||
$object = $this->backend->getCalendarObject($calendarId, $eventUri);
|
||||
|
||||
// assert proper classification
|
||||
$this->assertEquals(CalDavBackend::CLASSIFICATION_PUBLIC, $object['classification']);
|
||||
$this->backend->setClassification($object['id'], CalDavBackend::CLASSIFICATION_CONFIDENTIAL);
|
||||
$object = $this->backend->getCalendarObject($calendarId, $eventUri);
|
||||
$this->assertEquals(CalDavBackend::CLASSIFICATION_CONFIDENTIAL, $object['classification']);
|
||||
|
||||
// run migration
|
||||
$c = new Classification($this->backend, $this->userManager);
|
||||
|
||||
/** @var IUser | \PHPUnit_Framework_MockObject_MockObject $user */
|
||||
$user = $this->getMockBuilder('OCP\IUser')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$user->expects($this->once())->method('getUID')->willReturn('caldav-unit-test');
|
||||
|
||||
$c->runForUser($user);
|
||||
|
||||
// assert classification after migration
|
||||
$object = $this->backend->getCalendarObject($calendarId, $eventUri);
|
||||
$this->assertEquals(CalDavBackend::CLASSIFICATION_PUBLIC, $object['classification']);
|
||||
}
|
||||
}
|
||||
|
|
@ -39,8 +39,9 @@ interface IRepairStep {
|
|||
* Run repair step.
|
||||
* Must throw exception on error.
|
||||
*
|
||||
* @since 9.1.0
|
||||
* @param IOutput $output
|
||||
* @throws \Exception in case of failure
|
||||
* @since 9.1.0
|
||||
*/
|
||||
public function run(IOutput $output);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue