AddressBook.php 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. <?php
  2. /**
  3. * @copyright Copyright (c) 2016, ownCloud, Inc.
  4. *
  5. * @author Joas Schilling <coding@schilljs.com>
  6. * @author Thomas Müller <thomas.mueller@tmit.eu>
  7. *
  8. * @license AGPL-3.0
  9. *
  10. * This code is free software: you can redistribute it and/or modify
  11. * it under the terms of the GNU Affero General Public License, version 3,
  12. * as published by the Free Software Foundation.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU Affero General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Affero General Public License, version 3,
  20. * along with this program. If not, see <http://www.gnu.org/licenses/>
  21. *
  22. */
  23. namespace OCA\DAV\CardDAV;
  24. use OCA\DAV\DAV\Sharing\IShareable;
  25. use OCP\IL10N;
  26. use Sabre\CardDAV\Backend\BackendInterface;
  27. use Sabre\CardDAV\Card;
  28. use Sabre\DAV\Exception\Forbidden;
  29. use Sabre\DAV\Exception\NotFound;
  30. use Sabre\DAV\PropPatch;
  31. /**
  32. * Class AddressBook
  33. *
  34. * @package OCA\DAV\CardDAV
  35. * @property BackendInterface|CardDavBackend $carddavBackend
  36. */
  37. class AddressBook extends \Sabre\CardDAV\AddressBook implements IShareable {
  38. /**
  39. * AddressBook constructor.
  40. *
  41. * @param BackendInterface $carddavBackend
  42. * @param array $addressBookInfo
  43. * @param IL10N $l10n
  44. */
  45. public function __construct(BackendInterface $carddavBackend, array $addressBookInfo, IL10N $l10n) {
  46. parent::__construct($carddavBackend, $addressBookInfo);
  47. if ($this->addressBookInfo['{DAV:}displayname'] === CardDavBackend::PERSONAL_ADDRESSBOOK_NAME &&
  48. $this->getName() === CardDavBackend::PERSONAL_ADDRESSBOOK_URI) {
  49. $this->addressBookInfo['{DAV:}displayname'] = $l10n->t('Contacts');
  50. }
  51. }
  52. /**
  53. * Updates the list of shares.
  54. *
  55. * The first array is a list of people that are to be added to the
  56. * addressbook.
  57. *
  58. * Every element in the add array has the following properties:
  59. * * href - A url. Usually a mailto: address
  60. * * commonName - Usually a first and last name, or false
  61. * * summary - A description of the share, can also be false
  62. * * readOnly - A boolean value
  63. *
  64. * Every element in the remove array is just the address string.
  65. *
  66. * @param array $add
  67. * @param array $remove
  68. * @return void
  69. * @throws Forbidden
  70. */
  71. public function updateShares(array $add, array $remove) {
  72. if ($this->isShared()) {
  73. throw new Forbidden();
  74. }
  75. $this->carddavBackend->updateShares($this, $add, $remove);
  76. }
  77. /**
  78. * Returns the list of people whom this addressbook is shared with.
  79. *
  80. * Every element in this array should have the following properties:
  81. * * href - Often a mailto: address
  82. * * commonName - Optional, for example a first + last name
  83. * * status - See the Sabre\CalDAV\SharingPlugin::STATUS_ constants.
  84. * * readOnly - boolean
  85. * * summary - Optional, a description for the share
  86. *
  87. * @return array
  88. */
  89. public function getShares() {
  90. if ($this->isShared()) {
  91. return [];
  92. }
  93. return $this->carddavBackend->getShares($this->getResourceId());
  94. }
  95. public function getACL() {
  96. $acl = [
  97. [
  98. 'privilege' => '{DAV:}read',
  99. 'principal' => $this->getOwner(),
  100. 'protected' => true,
  101. ],[
  102. 'privilege' => '{DAV:}write',
  103. 'principal' => $this->getOwner(),
  104. 'protected' => true,
  105. ]
  106. ];
  107. if ($this->getOwner() === 'principals/system/system') {
  108. $acl[] = [
  109. 'privilege' => '{DAV:}read',
  110. 'principal' => '{DAV:}authenticated',
  111. 'protected' => true,
  112. ];
  113. }
  114. if (!$this->isShared()) {
  115. return $acl;
  116. }
  117. if ($this->getOwner() !== parent::getOwner()) {
  118. $acl[] = [
  119. 'privilege' => '{DAV:}read',
  120. 'principal' => parent::getOwner(),
  121. 'protected' => true,
  122. ];
  123. if ($this->canWrite()) {
  124. $acl[] = [
  125. 'privilege' => '{DAV:}write',
  126. 'principal' => parent::getOwner(),
  127. 'protected' => true,
  128. ];
  129. }
  130. }
  131. $acl = $this->carddavBackend->applyShareAcl($this->getResourceId(), $acl);
  132. $allowedPrincipals = [$this->getOwner(), parent::getOwner(), 'principals/system/system'];
  133. return array_filter($acl, function($rule) use ($allowedPrincipals) {
  134. return \in_array($rule['principal'], $allowedPrincipals, true);
  135. });
  136. }
  137. public function getChildACL() {
  138. return $this->getACL();
  139. }
  140. public function getChild($name) {
  141. $obj = $this->carddavBackend->getCard($this->addressBookInfo['id'], $name);
  142. if (!$obj) {
  143. throw new NotFound('Card not found');
  144. }
  145. $obj['acl'] = $this->getChildACL();
  146. return new Card($this->carddavBackend, $this->addressBookInfo, $obj);
  147. }
  148. /**
  149. * @return int
  150. */
  151. public function getResourceId() {
  152. return $this->addressBookInfo['id'];
  153. }
  154. public function getOwner() {
  155. if (isset($this->addressBookInfo['{http://owncloud.org/ns}owner-principal'])) {
  156. return $this->addressBookInfo['{http://owncloud.org/ns}owner-principal'];
  157. }
  158. return parent::getOwner();
  159. }
  160. public function delete() {
  161. if (isset($this->addressBookInfo['{http://owncloud.org/ns}owner-principal'])) {
  162. $principal = 'principal:' . parent::getOwner();
  163. $shares = $this->carddavBackend->getShares($this->getResourceId());
  164. $shares = array_filter($shares, function($share) use ($principal){
  165. return $share['href'] === $principal;
  166. });
  167. if (empty($shares)) {
  168. throw new Forbidden();
  169. }
  170. $this->carddavBackend->updateShares($this, [], [
  171. $principal
  172. ]);
  173. return;
  174. }
  175. parent::delete();
  176. }
  177. public function propPatch(PropPatch $propPatch) {
  178. if (isset($this->addressBookInfo['{http://owncloud.org/ns}owner-principal'])) {
  179. throw new Forbidden();
  180. }
  181. parent::propPatch($propPatch);
  182. }
  183. public function getContactsGroups() {
  184. return $this->carddavBackend->collectCardProperties($this->getResourceId(), 'CATEGORIES');
  185. }
  186. private function isShared() {
  187. if (!isset($this->addressBookInfo['{http://owncloud.org/ns}owner-principal'])) {
  188. return false;
  189. }
  190. return $this->addressBookInfo['{http://owncloud.org/ns}owner-principal'] !== $this->addressBookInfo['principaluri'];
  191. }
  192. private function canWrite() {
  193. if (isset($this->addressBookInfo['{http://owncloud.org/ns}read-only'])) {
  194. return !$this->addressBookInfo['{http://owncloud.org/ns}read-only'];
  195. }
  196. return true;
  197. }
  198. }