Addressbook sharing added based on a simplified approach which is based on calendar sharing standard
This commit is contained in:
parent
58eaeb267c
commit
4eb15885c9
|
@ -570,4 +570,55 @@ CREATE TABLE calendarobjects (
|
||||||
|
|
||||||
</declaration>
|
</declaration>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<name>*dbprefix*dav_shares</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>type</name>
|
||||||
|
<type>text</type>
|
||||||
|
</field>
|
||||||
|
<field>
|
||||||
|
<name>access</name>
|
||||||
|
<type>integer</type>
|
||||||
|
<length>1</length>
|
||||||
|
</field>
|
||||||
|
<field>
|
||||||
|
<name>resourceid</name>
|
||||||
|
<type>integer</type>
|
||||||
|
<notnull>true</notnull>
|
||||||
|
<unsigned>true</unsigned>
|
||||||
|
</field>
|
||||||
|
<index>
|
||||||
|
<name>dav_shares_index</name>
|
||||||
|
<unique>true</unique>
|
||||||
|
<field>
|
||||||
|
<name>principaluri</name>
|
||||||
|
</field>
|
||||||
|
<field>
|
||||||
|
<name>uri</name>
|
||||||
|
</field>
|
||||||
|
<field>
|
||||||
|
<name>type</name>
|
||||||
|
</field>
|
||||||
|
</index>
|
||||||
|
</declaration>
|
||||||
|
</table>
|
||||||
</database>
|
</database>
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace OCA\DAV\CardDAV;
|
||||||
|
|
||||||
|
use OCA\DAV\CardDAV\Sharing\IShareableAddressBook;
|
||||||
|
use OCP\IUserManager;
|
||||||
|
|
||||||
|
class AddressBook extends \Sabre\CardDAV\AddressBook implements IShareableAddressBook {
|
||||||
|
|
||||||
|
/** @var IUserManager */
|
||||||
|
private $userManager;
|
||||||
|
|
||||||
|
public function __construct(CardDavBackend $carddavBackend, array $addressBookInfo) {
|
||||||
|
parent::__construct($carddavBackend, $addressBookInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the list of shares.
|
||||||
|
*
|
||||||
|
* The first array is a list of people that are to be added to the
|
||||||
|
* addressbook.
|
||||||
|
*
|
||||||
|
* Every element in the add array has the following properties:
|
||||||
|
* * href - A url. Usually a mailto: address
|
||||||
|
* * commonName - Usually a first and last name, or false
|
||||||
|
* * summary - A description of the share, can also be false
|
||||||
|
* * readOnly - A boolean value
|
||||||
|
*
|
||||||
|
* Every element in the remove array is just the address string.
|
||||||
|
*
|
||||||
|
* @param array $add
|
||||||
|
* @param array $remove
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function updateShares(array $add, array $remove) {
|
||||||
|
/** @var CardDavBackend $carddavBackend */
|
||||||
|
$carddavBackend = $this->carddavBackend;
|
||||||
|
$carddavBackend->updateShares($this->getName(), $add, $remove);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the list of people whom this addressbook is shared with.
|
||||||
|
*
|
||||||
|
* Every element in this array should have the following properties:
|
||||||
|
* * href - Often a mailto: address
|
||||||
|
* * commonName - Optional, for example a first + last name
|
||||||
|
* * status - See the Sabre\CalDAV\SharingPlugin::STATUS_ constants.
|
||||||
|
* * readOnly - boolean
|
||||||
|
* * summary - Optional, a description for the share
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
function getShares() {
|
||||||
|
/** @var CardDavBackend $carddavBackend */
|
||||||
|
$carddavBackend = $this->carddavBackend;
|
||||||
|
$carddavBackend->getShares($this->getName());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace OCA\DAV\CardDAV;
|
||||||
|
|
||||||
|
class AddressBookRoot extends \Sabre\CardDAV\AddressBookRoot {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns a node for a principal.
|
||||||
|
*
|
||||||
|
* The passed array contains principal information, and is guaranteed to
|
||||||
|
* at least contain a uri item. Other properties may or may not be
|
||||||
|
* supplied by the authentication backend.
|
||||||
|
*
|
||||||
|
* @param array $principal
|
||||||
|
* @return \Sabre\DAV\INode
|
||||||
|
*/
|
||||||
|
function getChildForPrincipal(array $principal) {
|
||||||
|
|
||||||
|
return new UserAddressBooks($this->carddavBackend, $principal['uri']);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -22,6 +22,7 @@
|
||||||
|
|
||||||
namespace OCA\DAV\CardDAV;
|
namespace OCA\DAV\CardDAV;
|
||||||
|
|
||||||
|
use OCA\DAV\Connector\Sabre\Principal;
|
||||||
use Sabre\CardDAV\Backend\BackendInterface;
|
use Sabre\CardDAV\Backend\BackendInterface;
|
||||||
use Sabre\CardDAV\Backend\SyncSupport;
|
use Sabre\CardDAV\Backend\SyncSupport;
|
||||||
use Sabre\CardDAV\Plugin;
|
use Sabre\CardDAV\Plugin;
|
||||||
|
@ -29,8 +30,12 @@ use Sabre\DAV\Exception\BadRequest;
|
||||||
|
|
||||||
class CardDavBackend implements BackendInterface, SyncSupport {
|
class CardDavBackend implements BackendInterface, SyncSupport {
|
||||||
|
|
||||||
public function __construct(\OCP\IDBConnection $db) {
|
/** @var Principal */
|
||||||
|
private $principalBackend;
|
||||||
|
|
||||||
|
public function __construct(\OCP\IDBConnection $db, Principal $principalBackend) {
|
||||||
$this->db = $db;
|
$this->db = $db;
|
||||||
|
$this->principalBackend = $principalBackend;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -73,9 +78,61 @@ class CardDavBackend implements BackendInterface, SyncSupport {
|
||||||
}
|
}
|
||||||
$result->closeCursor();
|
$result->closeCursor();
|
||||||
|
|
||||||
|
// query for shared calendars
|
||||||
|
$query = $this->db->getQueryBuilder();
|
||||||
|
$query2 = $this->db->getQueryBuilder();
|
||||||
|
$query2->select(['resourceid'])
|
||||||
|
->from('dav_shares')
|
||||||
|
->where($query2->expr()->eq('principaluri', $query2->createParameter('principaluri')))
|
||||||
|
->andWhere($query2->expr()->eq('type', $query2->createParameter('type')));
|
||||||
|
$result = $query->select(['id', 'uri', 'displayname', 'principaluri', 'description', 'synctoken'])
|
||||||
|
->from('addressbooks')
|
||||||
|
->where($query->expr()->in('id', $query->createFunction($query2->getSQL())))
|
||||||
|
->setParameter('type', 'addressbook')
|
||||||
|
->setParameter('principaluri', $principalUri)
|
||||||
|
->execute();
|
||||||
|
|
||||||
|
while($row = $result->fetch()) {
|
||||||
|
$addressBooks[] = [
|
||||||
|
'id' => $row['id'],
|
||||||
|
'uri' => $row['uri'],
|
||||||
|
'principaluri' => $row['principaluri'],
|
||||||
|
'{DAV:}displayname' => $row['displayname'],
|
||||||
|
'{' . Plugin::NS_CARDDAV . '}addressbook-description' => $row['description'],
|
||||||
|
'{http://calendarserver.org/ns/}getctag' => $row['synctoken'],
|
||||||
|
'{http://sabredav.org/ns}sync-token' => $row['synctoken']?$row['synctoken']:'0',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
$result->closeCursor();
|
||||||
|
|
||||||
return $addressBooks;
|
return $addressBooks;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function getAddressBooksByUri($addressBookUri) {
|
||||||
|
$query = $this->db->getQueryBuilder();
|
||||||
|
$result = $query->select(['id', 'uri', 'displayname', 'principaluri', 'description', 'synctoken'])
|
||||||
|
->from('addressbooks')
|
||||||
|
->where($query->expr()->eq('uri', $query->createNamedParameter($addressBookUri)))
|
||||||
|
->setMaxResults(1)
|
||||||
|
->execute();
|
||||||
|
|
||||||
|
$row = $result->fetch();
|
||||||
|
if (is_null($row)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
$result->closeCursor();
|
||||||
|
|
||||||
|
return [
|
||||||
|
'id' => $row['id'],
|
||||||
|
'uri' => $row['uri'],
|
||||||
|
'principaluri' => $row['principaluri'],
|
||||||
|
'{DAV:}displayname' => $row['displayname'],
|
||||||
|
'{' . Plugin::NS_CARDDAV . '}addressbook-description' => $row['description'],
|
||||||
|
'{http://calendarserver.org/ns/}getctag' => $row['synctoken'],
|
||||||
|
'{http://sabredav.org/ns}sync-token' => $row['synctoken']?$row['synctoken']:'0',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates properties for an address book.
|
* Updates properties for an address book.
|
||||||
*
|
*
|
||||||
|
@ -201,6 +258,11 @@ class CardDavBackend implements BackendInterface, SyncSupport {
|
||||||
->where($query->expr()->eq('id', $query->createParameter('id')))
|
->where($query->expr()->eq('id', $query->createParameter('id')))
|
||||||
->setParameter('id', $addressBookId)
|
->setParameter('id', $addressBookId)
|
||||||
->execute();
|
->execute();
|
||||||
|
|
||||||
|
$query->delete('dav_shares')
|
||||||
|
->where($query->expr()->eq('resourceid', $query->createNamedParameter($addressBookId)))
|
||||||
|
->andWhere($query->expr()->eq('type', $query->createNamedParameter('addressbook')))
|
||||||
|
->execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -561,4 +623,99 @@ class CardDavBackend implements BackendInterface, SyncSupport {
|
||||||
return $cardData;
|
return $cardData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function updateShares($path, $add, $remove) {
|
||||||
|
foreach($add as $element) {
|
||||||
|
$this->shareWith($path, $element);
|
||||||
|
}
|
||||||
|
foreach($remove as $element) {
|
||||||
|
$this->unshare($path, $element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function shareWith($addressBookUri, $element) {
|
||||||
|
$user = $element['href'];
|
||||||
|
$parts = explode(':', $user, 2);
|
||||||
|
if ($parts[0] !== 'principal') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$p = $this->principalBackend->getPrincipalByPath($parts[1]);
|
||||||
|
if (is_null($p)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$addressbook = $this->getAddressBooksByUri($addressBookUri);
|
||||||
|
if (is_null($addressbook)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$query = $this->db->getQueryBuilder();
|
||||||
|
$query->insert('dav_shares')
|
||||||
|
->values([
|
||||||
|
'principaluri' => $query->createNamedParameter($parts[1]),
|
||||||
|
'uri' => $query->createNamedParameter($addressBookUri),
|
||||||
|
'type' => $query->createNamedParameter('addressbook'),
|
||||||
|
'access' => $query->createNamedParameter(0),
|
||||||
|
'resourceid' => $query->createNamedParameter($addressbook['id'])
|
||||||
|
]);
|
||||||
|
$query->execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function unshare($addressBookUri, $element) {
|
||||||
|
$user = $element['href'];
|
||||||
|
$parts = explode(':', $user, 2);
|
||||||
|
if ($parts[0] !== 'principal') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$p = $this->principalBackend->getPrincipalByPath($parts[1]);
|
||||||
|
if (is_null($p)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$addressbook = $this->getAddressBooksByUri($addressBookUri);
|
||||||
|
if (is_null($addressbook)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$query = $this->db->getQueryBuilder();
|
||||||
|
$query->delete('dav_shares')
|
||||||
|
->where($query->expr()->eq('resourceid', $query->createNamedParameter($addressbook['id'])))
|
||||||
|
->andWhere($query->expr()->eq('type', $query->createNamedParameter('addressbook')))
|
||||||
|
->andWhere($query->expr()->eq('principaluri', $query->createNamedParameter($parts[1])))
|
||||||
|
;
|
||||||
|
$query->execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the list of people whom this addressbook is shared with.
|
||||||
|
*
|
||||||
|
* Every element in this array should have the following properties:
|
||||||
|
* * href - Often a mailto: address
|
||||||
|
* * commonName - Optional, for example a first + last name
|
||||||
|
* * status - See the Sabre\CalDAV\SharingPlugin::STATUS_ constants.
|
||||||
|
* * readOnly - boolean
|
||||||
|
* * summary - Optional, a description for the share
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getShares($addressBookUri) {
|
||||||
|
$query = $this->db->getQueryBuilder();
|
||||||
|
$result = $query->select(['principaluri', 'access'])
|
||||||
|
->from('dav_shares')
|
||||||
|
->where($query->expr()->eq('uri', $query->createNamedParameter($addressBookUri)))
|
||||||
|
->andWhere($query->expr()->eq('type', $query->createNamedParameter('addressbook')))
|
||||||
|
->execute();
|
||||||
|
|
||||||
|
$shares = [];
|
||||||
|
while($row = $result->fetch()) {
|
||||||
|
$p = $this->principalBackend->getPrincipalByPath($row['principaluri']);
|
||||||
|
$shares[]= [
|
||||||
|
'href' => "principal:${p['uri']}",
|
||||||
|
'commonName' => isset($p['{DAV:}displayname']) ? $p['{DAV:}displayname'] : '',
|
||||||
|
'status' => 1,
|
||||||
|
'readOnly' => ($row['access'] === 1)
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $shares;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace OCA\DAV\CardDAV\Sharing;
|
||||||
|
use Sabre\CardDAV\IAddressBook;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This interface represents a Calendar that can be shared with other users.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
interface IShareableAddressBook extends IAddressBook {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the list of shares.
|
||||||
|
*
|
||||||
|
* The first array is a list of people that are to be added to the
|
||||||
|
* addressbook.
|
||||||
|
*
|
||||||
|
* Every element in the add array has the following properties:
|
||||||
|
* * href - A url. Usually a mailto: address
|
||||||
|
* * commonName - Usually a first and last name, or false
|
||||||
|
* * summary - A description of the share, can also be false
|
||||||
|
* * readOnly - A boolean value
|
||||||
|
*
|
||||||
|
* Every element in the remove array is just the address string.
|
||||||
|
*
|
||||||
|
* @param array $add
|
||||||
|
* @param array $remove
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function updateShares(array $add, array $remove);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the list of people whom this addressbook is shared with.
|
||||||
|
*
|
||||||
|
* Every element in this array should have the following properties:
|
||||||
|
* * href - Often a mailto: address
|
||||||
|
* * commonName - Optional, for example a first + last name
|
||||||
|
* * status - See the Sabre\CalDAV\SharingPlugin::STATUS_ constants.
|
||||||
|
* * readOnly - boolean
|
||||||
|
* * summary - Optional, a description for the share
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
function getShares();
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,194 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace OCA\DAV\CardDAV\Sharing;
|
||||||
|
|
||||||
|
use Sabre\DAV\Exception\NotFound;
|
||||||
|
use Sabre\DAV\Server;
|
||||||
|
use Sabre\DAV\ServerPlugin;
|
||||||
|
use Sabre\DAV\XMLUtil;
|
||||||
|
use Sabre\HTTP\RequestInterface;
|
||||||
|
use Sabre\HTTP\ResponseInterface;
|
||||||
|
|
||||||
|
class Plugin extends ServerPlugin {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reference to SabreDAV server object.
|
||||||
|
*
|
||||||
|
* @var \Sabre\DAV\Server
|
||||||
|
*/
|
||||||
|
protected $server;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method should return a list of server-features.
|
||||||
|
*
|
||||||
|
* This is for example 'versioning' and is added to the DAV: header
|
||||||
|
* in an OPTIONS response.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
function getFeatures() {
|
||||||
|
|
||||||
|
return ['oc-addressbook-sharing'];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a plugin name.
|
||||||
|
*
|
||||||
|
* Using this name other plugins will be able to access other plugins
|
||||||
|
* using Sabre\DAV\Server::getPlugin
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
function getPluginName() {
|
||||||
|
|
||||||
|
return 'carddav-sharing';
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 Server $server
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function initialize(Server $server) {
|
||||||
|
$this->server = $server;
|
||||||
|
$server->resourceTypeMapping['OCA\\DAV\CardDAV\\ISharedAddressbook'] = '{' . \Sabre\CardDAV\Plugin::NS_CARDDAV . '}shared';
|
||||||
|
|
||||||
|
$this->server->on('method:POST', [$this, 'httpPost']);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We intercept this to handle POST requests on calendars.
|
||||||
|
*
|
||||||
|
* @param RequestInterface $request
|
||||||
|
* @param ResponseInterface $response
|
||||||
|
* @return null|bool
|
||||||
|
*/
|
||||||
|
function httpPost(RequestInterface $request, ResponseInterface $response) {
|
||||||
|
|
||||||
|
$path = $request->getPath();
|
||||||
|
|
||||||
|
// Only handling xml
|
||||||
|
$contentType = $request->getHeader('Content-Type');
|
||||||
|
if (strpos($contentType, 'application/xml') === false && strpos($contentType, 'text/xml') === false)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Making sure the node exists
|
||||||
|
try {
|
||||||
|
$node = $this->server->tree->getNodeForPath($path);
|
||||||
|
} catch (NotFound $e) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$requestBody = $request->getBodyAsString();
|
||||||
|
|
||||||
|
// If this request handler could not deal with this POST request, it
|
||||||
|
// will return 'null' and other plugins get a chance to handle the
|
||||||
|
// request.
|
||||||
|
//
|
||||||
|
// However, we already requested the full body. This is a problem,
|
||||||
|
// because a body can only be read once. This is why we preemptively
|
||||||
|
// re-populated the request body with the existing data.
|
||||||
|
$request->setBody($requestBody);
|
||||||
|
|
||||||
|
$dom = XMLUtil::loadDOMDocument($requestBody);
|
||||||
|
|
||||||
|
$documentType = XMLUtil::toClarkNotation($dom->firstChild);
|
||||||
|
|
||||||
|
switch ($documentType) {
|
||||||
|
|
||||||
|
// Dealing with the 'share' document, which modified invitees on a
|
||||||
|
// calendar.
|
||||||
|
case '{' . \Sabre\CardDAV\Plugin::NS_CARDDAV . '}share' :
|
||||||
|
|
||||||
|
// We can only deal with IShareableCalendar objects
|
||||||
|
if (!$node instanceof IShareableAddressBook) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->server->transactionType = 'post-calendar-share';
|
||||||
|
|
||||||
|
// Getting ACL info
|
||||||
|
$acl = $this->server->getPlugin('acl');
|
||||||
|
|
||||||
|
// If there's no ACL support, we allow everything
|
||||||
|
if ($acl) {
|
||||||
|
$acl->checkPrivileges($path, '{DAV:}write');
|
||||||
|
}
|
||||||
|
|
||||||
|
$mutations = $this->parseShareRequest($dom);
|
||||||
|
|
||||||
|
$node->updateShares($mutations[0], $mutations[1]);
|
||||||
|
|
||||||
|
$response->setStatus(200);
|
||||||
|
// Adding this because sending a response body may cause issues,
|
||||||
|
// and I wanted some type of indicator the response was handled.
|
||||||
|
$response->setHeader('X-Sabre-Status', 'everything-went-well');
|
||||||
|
|
||||||
|
// Breaking the event chain
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses the 'share' POST request.
|
||||||
|
*
|
||||||
|
* This method returns an array, containing two arrays.
|
||||||
|
* The first array is a list of new sharees. Every element is a struct
|
||||||
|
* containing a:
|
||||||
|
* * href element. (usually a mailto: address)
|
||||||
|
* * commonName element (often a first and lastname, but can also be
|
||||||
|
* false)
|
||||||
|
* * readOnly (true or false)
|
||||||
|
* * summary (A description of the share, can also be false)
|
||||||
|
*
|
||||||
|
* The second array is a list of sharees that are to be removed. This is
|
||||||
|
* just a simple array with 'hrefs'.
|
||||||
|
*
|
||||||
|
* @param \DOMDocument $dom
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
function parseShareRequest(\DOMDocument $dom) {
|
||||||
|
|
||||||
|
$xpath = new \DOMXPath($dom);
|
||||||
|
$xpath->registerNamespace('cs', \Sabre\CardDAV\Plugin::NS_CARDDAV);
|
||||||
|
$xpath->registerNamespace('d', 'urn:DAV');
|
||||||
|
|
||||||
|
$set = [];
|
||||||
|
$elems = $xpath->query('cs:set');
|
||||||
|
|
||||||
|
for ($i = 0; $i < $elems->length; $i++) {
|
||||||
|
|
||||||
|
$xset = $elems->item($i);
|
||||||
|
$set[] = [
|
||||||
|
'href' => $xpath->evaluate('string(d:href)', $xset),
|
||||||
|
'commonName' => $xpath->evaluate('string(cs:common-name)', $xset),
|
||||||
|
'summary' => $xpath->evaluate('string(cs:summary)', $xset),
|
||||||
|
'readOnly' => $xpath->evaluate('boolean(cs:read)', $xset) !== false
|
||||||
|
];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
$remove = [];
|
||||||
|
$elems = $xpath->query('cs:remove');
|
||||||
|
|
||||||
|
for ($i = 0; $i < $elems->length; $i++) {
|
||||||
|
|
||||||
|
$xremove = $elems->item($i);
|
||||||
|
$remove[] = $xpath->evaluate('string(d:href)', $xremove);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return [$set, $remove];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace OCA\DAV\CardDAV;
|
||||||
|
|
||||||
|
class UserAddressBooks extends \Sabre\CardDAV\UserAddressBooks {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list of addressbooks
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
function getChildren() {
|
||||||
|
|
||||||
|
$addressbooks = $this->carddavBackend->getAddressBooksForUser($this->principalUri);
|
||||||
|
$objs = [];
|
||||||
|
foreach($addressbooks as $addressbook) {
|
||||||
|
$objs[] = new AddressBook($this->carddavBackend, $addressbook);
|
||||||
|
}
|
||||||
|
return $objs;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -3,11 +3,11 @@
|
||||||
namespace OCA\DAV;
|
namespace OCA\DAV;
|
||||||
|
|
||||||
use OCA\DAV\CalDAV\CalDavBackend;
|
use OCA\DAV\CalDAV\CalDavBackend;
|
||||||
|
use OCA\DAV\CardDAV\AddressBookRoot;
|
||||||
use OCA\DAV\CardDAV\CardDavBackend;
|
use OCA\DAV\CardDAV\CardDavBackend;
|
||||||
use OCA\DAV\Connector\Sabre\Principal;
|
use OCA\DAV\Connector\Sabre\Principal;
|
||||||
use Sabre\CalDAV\CalendarRoot;
|
use Sabre\CalDAV\CalendarRoot;
|
||||||
use Sabre\CalDAV\Principal\Collection;
|
use Sabre\CalDAV\Principal\Collection;
|
||||||
use Sabre\CardDAV\AddressBookRoot;
|
|
||||||
use Sabre\DAV\SimpleCollection;
|
use Sabre\DAV\SimpleCollection;
|
||||||
|
|
||||||
class RootCollection extends SimpleCollection {
|
class RootCollection extends SimpleCollection {
|
||||||
|
@ -30,7 +30,9 @@ class RootCollection extends SimpleCollection {
|
||||||
$caldavBackend = new CalDavBackend($db);
|
$caldavBackend = new CalDavBackend($db);
|
||||||
$calendarRoot = new CalendarRoot($principalBackend, $caldavBackend);
|
$calendarRoot = new CalendarRoot($principalBackend, $caldavBackend);
|
||||||
$calendarRoot->disableListing = $disableListing;
|
$calendarRoot->disableListing = $disableListing;
|
||||||
$cardDavBackend = new CardDavBackend($db);
|
|
||||||
|
$cardDavBackend = new CardDavBackend(\OC::$server->getDatabaseConnection(), $principalBackend);
|
||||||
|
|
||||||
$addressBookRoot = new AddressBookRoot($principalBackend, $cardDavBackend);
|
$addressBookRoot = new AddressBookRoot($principalBackend, $cardDavBackend);
|
||||||
$addressBookRoot->disableListing = $disableListing;
|
$addressBookRoot->disableListing = $disableListing;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<CS:share xmlns:D="DAV:" xmlns:CS="urn:ietf:params:xml:ns:carddav">
|
||||||
|
<CS:set>
|
||||||
|
<D:href>principal:principals/admin</D:href>
|
||||||
|
<CS:read-write />
|
||||||
|
</CS:set>
|
||||||
|
</CS:share>
|
|
@ -24,6 +24,13 @@ use OCA\DAV\CardDAV\CardDavBackend;
|
||||||
use Sabre\DAV\PropPatch;
|
use Sabre\DAV\PropPatch;
|
||||||
use Test\TestCase;
|
use Test\TestCase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class CardDavBackendTest
|
||||||
|
*
|
||||||
|
* @group DB
|
||||||
|
*
|
||||||
|
* @package OCA\DAV\Tests\Unit\CardDAV
|
||||||
|
*/
|
||||||
class CardDavBackendTest extends TestCase {
|
class CardDavBackendTest extends TestCase {
|
||||||
|
|
||||||
/** @var CardDavBackend */
|
/** @var CardDavBackend */
|
||||||
|
@ -31,12 +38,20 @@ class CardDavBackendTest extends TestCase {
|
||||||
|
|
||||||
const UNIT_TEST_USER = 'carddav-unit-test';
|
const UNIT_TEST_USER = 'carddav-unit-test';
|
||||||
|
|
||||||
|
|
||||||
public function setUp() {
|
public function setUp() {
|
||||||
parent::setUp();
|
parent::setUp();
|
||||||
|
|
||||||
|
$principal = $this->getMockBuilder('OCA\DAV\Connector\Sabre\Principal')
|
||||||
|
->disableOriginalConstructor()
|
||||||
|
->setMethods(['getPrincipalByPath'])
|
||||||
|
->getMock();
|
||||||
|
$principal->method('getPrincipalByPath')
|
||||||
|
->willReturn([
|
||||||
|
'uri' => 'principals/best-friend'
|
||||||
|
]);
|
||||||
|
|
||||||
$db = \OC::$server->getDatabaseConnection();
|
$db = \OC::$server->getDatabaseConnection();
|
||||||
$this->backend = new CardDavBackend($db);
|
$this->backend = new CardDavBackend($db, $principal);
|
||||||
|
|
||||||
$this->tearDown();
|
$this->tearDown();
|
||||||
}
|
}
|
||||||
|
@ -178,4 +193,28 @@ class CardDavBackendTest extends TestCase {
|
||||||
$changes = $this->backend->getChangesForAddressBook($bookId, $syncToken, 1);
|
$changes = $this->backend->getChangesForAddressBook($bookId, $syncToken, 1);
|
||||||
$this->assertEquals($uri0, $changes['added'][0]);
|
$this->assertEquals($uri0, $changes['added'][0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testSharing() {
|
||||||
|
$this->backend->createAddressBook(self::UNIT_TEST_USER, 'Example', []);
|
||||||
|
$books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER);
|
||||||
|
$this->assertEquals(1, count($books));
|
||||||
|
|
||||||
|
$this->backend->updateShares('Example', [['href' => 'principal:principals/best-friend']], []);
|
||||||
|
|
||||||
|
$shares = $this->backend->getShares('Example');
|
||||||
|
$this->assertEquals(1, count($shares));
|
||||||
|
|
||||||
|
$books = $this->backend->getAddressBooksForUser('principals/best-friend');
|
||||||
|
$this->assertEquals(1, count($books));
|
||||||
|
|
||||||
|
$this->backend->updateShares('Example', [], [['href' => 'principal:principals/best-friend']]);
|
||||||
|
|
||||||
|
$shares = $this->backend->getShares('Example');
|
||||||
|
$this->assertEquals(0, count($shares));
|
||||||
|
|
||||||
|
$books = $this->backend->getAddressBooksForUser('principals/best-friend');
|
||||||
|
$this->assertEquals(0, count($books));
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue