diff --git a/lib/DAV/Calendar.php b/lib/DAV/Calendar.php index 8563c3679..6c97e8446 100644 --- a/lib/DAV/Calendar.php +++ b/lib/DAV/Calendar.php @@ -24,72 +24,44 @@ namespace OCA\Deck\DAV; use OCA\DAV\CalDAV\Integration\ExternalCalendar; use OCA\DAV\CalDAV\Plugin; -use OCA\DAV\DAV\Sharing\IShareable; +use OCA\Deck\Db\Acl; use OCA\Deck\Db\Board; -use OCA\Deck\Db\Card; -use OCA\Deck\Db\Stack; -use OCA\Deck\Service\CardService; -use OCA\Deck\Service\StackService; use Sabre\CalDAV\Xml\Property\SupportedCalendarComponentSet; +use Sabre\DAV\Exception\Forbidden; use Sabre\DAV\PropPatch; -class Calendar extends ExternalCalendar implements IShareable { +class Calendar extends ExternalCalendar { /** @var string */ private $principalUri; - - /** @var string */ - private $calendarUri; - /** @var string[] */ private $children; - /** - * @var \stdClass - */ - private $cardService; + /** @var DeckCalendarBackend */ + private $backend; + /** @var Board */ + private $board; - /** - * Calendar constructor. - * - * @param string $principalUri - * @param string $calendarUri - */ - public function __construct(string $principalUri, string $calendarUri, Board $board = null) { + public function __construct(string $principalUri, string $calendarUri, Board $board, DeckCalendarBackend $backend) { parent::__construct('deck', $calendarUri); + $this->backend = $backend; $this->board = $board; $this->principalUri = $principalUri; - $this->calendarUri = $calendarUri; - if ($board) { - /** @var CardService $cardService */ - $cardService = \OC::$server->query(CardService::class); - /** @var StackService $stackService */ - $stackService = \OC::$server->query(StackService::class); - $this->children = array_merge( - $cardService->findCalendarEntries($board->getId()), - $stackService->findCalendarEntries($board->getId()) - ); + $this->children = $this->backend->getChildren($board->getId()); } else { $this->children = []; } } - - /** - * @inheritDoc - */ - function getOwner() { + public function getOwner() { return $this->principalUri; } - /** - * @inheritDoc - */ - function getACL() { - return [ + public function getACL() { + $acl = [ [ 'privilege' => '{DAV:}read', 'principal' => $this->getOwner(), @@ -106,43 +78,41 @@ class Calendar extends ExternalCalendar implements IShareable { 'protected' => true, ], ]; + if ($this->backend->checkBoardPermission($this->board->getId(), Acl::PERMISSION_EDIT)) { + $acl[] = [ + 'privilege' => '{DAV:}write', + 'principal' => $this->getOwner(), + 'protected' => true, + ]; + $acl[] = [ + 'privilege' => '{DAV:}write-properties', + 'principal' => $this->getOwner(), + 'protected' => true, + ]; + } + return $acl; } - /** - * @inheritDoc - */ - function setACL(array $acl) { - throw new \Sabre\DAV\Exception\Forbidden('Setting ACL is not supported on this node'); + public function setACL(array $acl) { + throw new Forbidden('Setting ACL is not supported on this node'); } - /** - * @inheritDoc - */ - function getSupportedPrivilegeSet() { + public function getSupportedPrivilegeSet() { return null; } - /** - * @inheritDoc - */ - function calendarQuery(array $filters) { - // In a real implementation this should actually filter + public function calendarQuery(array $filters) { + // FIXME: In a real implementation this should actually filter return array_map(function ($card) { return $card->getCalendarPrefix() . '-' . $card->getId() . '.ics'; }, $this->children); } - /** - * @inheritDoc - */ - function createFile($name, $data = null) { - return null; + public function createFile($name, $data = null) { + throw new \Sabre\DAV\Exception\Forbidden('Creating a new entry is not implemented'); } - /** - * @inheritDoc - */ - function getChild($name) { + public function getChild($name) { if ($this->childExists($name)) { $card = array_values(array_filter( $this->children, @@ -151,15 +121,12 @@ class Calendar extends ExternalCalendar implements IShareable { } )); if (count($card) > 0) { - return new CalendarObject($this, $name, $card[0]); + return new CalendarObject($this, $name, $card[0], $this->backend); } } } - /** - * @inheritDoc - */ - function getChildren() { + public function getChildren() { $childNames = array_map(function ($card) { return $card->getCalendarPrefix() . '-' . $card->getId() . '.ics'; }, $this->children); @@ -173,10 +140,7 @@ class Calendar extends ExternalCalendar implements IShareable { return $children; } - /** - * @inheritDoc - */ - function childExists($name) { + public function childExists($name) { return count(array_filter( $this->children, function ($card) use (&$name) { @@ -185,64 +149,51 @@ class Calendar extends ExternalCalendar implements IShareable { )) > 0; } - /** - * @inheritDoc - */ - function delete() { + + public function delete() { return null; } - /** - * @inheritDoc - */ - function getLastModified() { + public function getLastModified() { return $this->board->getLastModified(); } - /** - * @inheritDoc - */ - function getGroup() { + public function getGroup() { return []; } - /** - * @inheritDoc - */ - function propPatch(PropPatch $propPatch) { + public function propPatch(PropPatch $propPatch) { + $properties = [ + '{DAV:}displayname', + '{http://apple.com/ns/ical/}calendar-color' + ]; + $propPatch->handle($properties, function ($properties) { + foreach ($properties as $key => $value) { + switch ($key) { + case '{DAV:}displayname': + if (mb_substr($value, 0, strlen('Deck: '))) { + $value = mb_substr($value, strlen('Deck: ')); + } + $this->board->setTitle($value); + break; + case '{http://apple.com/ns/ical/}calendar-color': + $this->board->setColor(substr($value, 1)); + break; + } + } + return $this->backend->updateBoard($this->board); + }); // We can just return here and let oc_properties handle everything } /** * @inheritDoc */ - function getProperties($properties) { - // A backend should provide at least minimum properties + public function getProperties($properties) { return [ '{DAV:}displayname' => 'Deck: ' . ($this->board ? $this->board->getTitle() : 'no board object provided'), '{http://apple.com/ns/ical/}calendar-color' => '#' . $this->board->getColor(), - '{' . Plugin::NS_CALDAV . '}supported-calendar-component-set' => new SupportedCalendarComponentSet(['VTODO', 'VEVENT']), + '{' . Plugin::NS_CALDAV . '}supported-calendar-component-set' => new SupportedCalendarComponentSet(['VTODO']), ]; } - - /** - * @inheritDoc - */ - function updateShares(array $add, array $remove) { - // TODO: Implement updateShares() method. - } - - /** - * @inheritDoc - */ - function getShares() { - return []; - } - - /** - * @inheritDoc - */ - public function getResourceId() { - // TODO: Implement getResourceId() method. - } } diff --git a/lib/DAV/CalendarObject.php b/lib/DAV/CalendarObject.php index 82633dd30..2a4d3e041 100644 --- a/lib/DAV/CalendarObject.php +++ b/lib/DAV/CalendarObject.php @@ -23,130 +23,88 @@ namespace OCA\Deck\DAV; use OCA\Deck\Db\Card; -use OCA\Deck\Service\CardService; +use OCA\Deck\Db\Stack; +use Sabre\CalDAV\ICalendarObject; +use Sabre\DAV\Exception\Forbidden; +use Sabre\DAVACL\IACL; use Sabre\VObject\Component\VCalendar; -class CalendarObject implements \Sabre\CalDAV\ICalendarObject, \Sabre\DAVACL\IACL { +class CalendarObject implements ICalendarObject, IACL { /** @var Calendar */ private $calendar; - /** @var string */ private $name; - /** - * @var Card - */ + /** @var Card|Stack */ private $sourceItem; + /** @var DeckCalendarBackend */ + private $backend; + /** @var VCalendar */ + private $calendarObject; - /** - * CalendarObject constructor. - * - * @param Calendar $calendar - * @param string $name - */ - public function __construct(Calendar $calendar, string $name, $sourceItem = null) { + public function __construct(Calendar $calendar, string $name, $sourceItem = null, DeckCalendarBackend $backend) { $this->calendar = $calendar; $this->name = $name; $this->sourceItem = $sourceItem; + $this->backend = $backend; + $this->calendarObject = $this->sourceItem->getCalendarObject(); } - /** - * @inheritDoc - */ - function getOwner() { + public function getOwner() { return null; } - /** - * @inheritDoc - */ - function getGroup() { + public function getGroup() { return null; } - /** - * @inheritDoc - */ - function getACL() { + public function getACL() { return $this->calendar->getACL(); } - /** - * @inheritDoc - */ - function setACL(array $acl) { - throw new \Sabre\DAV\Exception\Forbidden('Setting ACL is not supported on this node'); + public function setACL(array $acl) { + throw new Forbidden('Setting ACL is not supported on this node'); } - /** - * @inheritDoc - */ - function getSupportedPrivilegeSet() { + public function getSupportedPrivilegeSet() { return null; } - /** - * @inheritDoc - */ - function put($data) { - throw new \Sabre\DAV\Exception\Forbidden('This calendar-object is read-only'); + public function put($data) { + throw new Forbidden('This calendar-object is read-only'); } - /** - * @inheritDoc - */ - function get() { + public function get() { if ($this->sourceItem) { - return $this->sourceItem->getCalendarObject()->serialize(); + return $this->calendarObject->serialize(); } } - /** - * @inheritDoc - */ - function getContentType() { + public function getContentType() { return 'text/calendar; charset=utf-8'; } - /** - * @inheritDoc - */ - function getETag() { - return '"' . md5($this->get()) . '"'; + public function getETag() { + return '"' . md5($this->sourceItem->getLastModified()) . '"'; } - /** - * @inheritDoc - */ - function getSize() { - return strlen($this->get()); + public function getSize() { + return mb_strlen($this->calendarObject->serialize()); } - /** - * @inheritDoc - */ - function delete() { - throw new \Sabre\DAV\Exception\Forbidden('This calendar-object is read-only'); + public function delete() { + throw new Forbidden('This calendar-object is read-only'); } - /** - * @inheritDoc - */ - function getName() { + public function getName() { return $this->name; } - /** - * @inheritDoc - */ - function setName($name) { - throw new \Sabre\DAV\Exception\Forbidden('This calendar-object is read-only'); + public function setName($name) { + throw new Forbidden('This calendar-object is read-only'); } - /** - * @inheritDoc - */ - function getLastModified() { + public function getLastModified() { return $this->sourceItem->getLastModified(); } } diff --git a/lib/DAV/CalendarPlugin.php b/lib/DAV/CalendarPlugin.php index ba5226827..e0f614995 100644 --- a/lib/DAV/CalendarPlugin.php +++ b/lib/DAV/CalendarPlugin.php @@ -26,53 +26,37 @@ namespace OCA\Deck\DAV; use OCA\DAV\CalDAV\Integration\ExternalCalendar; use OCA\DAV\CalDAV\Integration\ICalendarProvider; use OCA\Deck\Db\Board; -use OCA\Deck\Service\BoardService; class CalendarPlugin implements ICalendarProvider { - /** - * @var BoardService - */ - private $boardService; + /** @var DeckCalendarBackend */ + private $backend; - public function __construct(BoardService $boardService) { - $this->boardService = $boardService; + public function __construct(DeckCalendarBackend $backend) { + $this->backend = $backend; } - /** - * @inheritDoc - */ public function getAppId(): string { return 'deck'; } - /** - * @inheritDoc - */ public function fetchAllForCalendarHome(string $principalUri): array { - $boards = $this->boardService->findAll(); return array_map(function (Board $board) use ($principalUri) { - return new Calendar($principalUri, 'board-' . $board->getId(), $board); - }, $boards); + return new Calendar($principalUri, 'board-' . $board->getId(), $board, $this->backend); + }, $this->backend->getBoards()); } - /** - * @inheritDoc - */ public function hasCalendarInCalendarHome(string $principalUri, string $calendarUri): bool { - $boards = array_map(function(Board $board) { + $boards = array_map(static function (Board $board) { return 'board-' . $board->getId(); - }, $this->boardService->findAll()); + }, $this->backend->getBoards()); return in_array($calendarUri, $boards, true); } - /** - * @inheritDoc - */ public function getCalendarInCalendarHome(string $principalUri, string $calendarUri): ?ExternalCalendar { if ($this->hasCalendarInCalendarHome($principalUri, $calendarUri)) { - $board = $this->boardService->find(str_replace('board-', '', $calendarUri)); - return new Calendar($principalUri, $calendarUri, $board); + $board = $this->backend->getBoard((int)str_replace('board-', '', $calendarUri)); + return new Calendar($principalUri, $calendarUri, $board, $this->backend); } return null; diff --git a/lib/DAV/DeckCalendarBackend.php b/lib/DAV/DeckCalendarBackend.php new file mode 100644 index 000000000..2e001cc08 --- /dev/null +++ b/lib/DAV/DeckCalendarBackend.php @@ -0,0 +1,84 @@ + + * + * @author Julius Härtl + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +declare(strict_types=1); + + +namespace OCA\Deck\DAV; + +use OCA\Deck\Db\Board; +use OCA\Deck\Db\BoardMapper; +use OCA\Deck\Service\BoardService; +use OCA\Deck\Service\CardService; +use OCA\Deck\Service\PermissionService; +use OCA\Deck\Service\StackService; + +class DeckCalendarBackend { + + /** @var BoardService */ + private $boardService; + /** @var StackService */ + private $stackService; + /** @var CardService */ + private $cardService; + /** @var PermissionService */ + private $permissionService; + /** @var BoardMapper */ + private $boardMapper; + + public function __construct( + BoardService $boardService, StackService $stackService, CardService $cardService, PermissionService $permissionService, + BoardMapper $boardMapper + ) { + $this->boardService = $boardService; + $this->stackService = $stackService; + $this->cardService = $cardService; + $this->permissionService = $permissionService; + $this->boardMapper = $boardMapper; + } + + public function getBoards(): array { + return $this->boardService->findAll(); + } + + public function getBoard(int $id): Board { + return $this->boardService->find($id); + } + + public function checkBoardPermission(int $id, int $permission): bool { + $permissions = $this->permissionService->getPermissions($id); + return isset($permissions[$permission]) ? $permissions[$permission] : false; + } + + public function updateBoard(Board $board): bool { + $this->boardMapper->update($board); + return true; + } + + public function getChildren(int $id): array { + return array_merge( + $this->cardService->findCalendarEntries($id), + $this->stackService->findCalendarEntries($id) + ); + } +} diff --git a/lib/Db/Card.php b/lib/Db/Card.php index 0b157fd56..1bb927d41 100644 --- a/lib/Db/Card.php +++ b/lib/Db/Card.php @@ -159,5 +159,4 @@ class Card extends RelationalEntity { public function getCalendarPrefix(): string { return 'card'; } - } diff --git a/lib/Db/Stack.php b/lib/Db/Stack.php index 7dc9310ba..1cc679240 100644 --- a/lib/Db/Stack.php +++ b/lib/Db/Stack.php @@ -65,5 +65,4 @@ class Stack extends RelationalEntity { public function getCalendarPrefix(): string { return 'stack'; } - }