@@ -16,16 +16,16 @@ |
||
| 16 | 16 | */ |
| 17 | 17 | class AceConflict extends DAV\Exception\Conflict |
| 18 | 18 | { |
| 19 | - /** |
|
| 20 | - * Adds in extra information in the xml response. |
|
| 21 | - * |
|
| 22 | - * This method adds the {DAV:}no-ace-conflict element as defined in rfc3744 |
|
| 23 | - */ |
|
| 24 | - public function serialize(DAV\Server $server, \DOMElement $errorNode) |
|
| 25 | - { |
|
| 26 | - $doc = $errorNode->ownerDocument; |
|
| 19 | + /** |
|
| 20 | + * Adds in extra information in the xml response. |
|
| 21 | + * |
|
| 22 | + * This method adds the {DAV:}no-ace-conflict element as defined in rfc3744 |
|
| 23 | + */ |
|
| 24 | + public function serialize(DAV\Server $server, \DOMElement $errorNode) |
|
| 25 | + { |
|
| 26 | + $doc = $errorNode->ownerDocument; |
|
| 27 | 27 | |
| 28 | - $np = $doc->createElementNS('DAV:', 'd:no-ace-conflict'); |
|
| 29 | - $errorNode->appendChild($np); |
|
| 30 | - } |
|
| 28 | + $np = $doc->createElementNS('DAV:', 'd:no-ace-conflict'); |
|
| 29 | + $errorNode->appendChild($np); |
|
| 30 | + } |
|
| 31 | 31 | } |
@@ -16,16 +16,16 @@ |
||
| 16 | 16 | */ |
| 17 | 17 | class NotRecognizedPrincipal extends DAV\Exception\PreconditionFailed |
| 18 | 18 | { |
| 19 | - /** |
|
| 20 | - * Adds in extra information in the xml response. |
|
| 21 | - * |
|
| 22 | - * This method adds the {DAV:}recognized-principal element as defined in rfc3744 |
|
| 23 | - */ |
|
| 24 | - public function serialize(DAV\Server $server, \DOMElement $errorNode) |
|
| 25 | - { |
|
| 26 | - $doc = $errorNode->ownerDocument; |
|
| 19 | + /** |
|
| 20 | + * Adds in extra information in the xml response. |
|
| 21 | + * |
|
| 22 | + * This method adds the {DAV:}recognized-principal element as defined in rfc3744 |
|
| 23 | + */ |
|
| 24 | + public function serialize(DAV\Server $server, \DOMElement $errorNode) |
|
| 25 | + { |
|
| 26 | + $doc = $errorNode->ownerDocument; |
|
| 27 | 27 | |
| 28 | - $np = $doc->createElementNS('DAV:', 'd:recognized-principal'); |
|
| 29 | - $errorNode->appendChild($np); |
|
| 30 | - } |
|
| 28 | + $np = $doc->createElementNS('DAV:', 'd:recognized-principal'); |
|
| 29 | + $errorNode->appendChild($np); |
|
| 30 | + } |
|
| 31 | 31 | } |
@@ -16,16 +16,16 @@ |
||
| 16 | 16 | */ |
| 17 | 17 | class NoAbstract extends DAV\Exception\PreconditionFailed |
| 18 | 18 | { |
| 19 | - /** |
|
| 20 | - * Adds in extra information in the xml response. |
|
| 21 | - * |
|
| 22 | - * This method adds the {DAV:}no-abstract element as defined in rfc3744 |
|
| 23 | - */ |
|
| 24 | - public function serialize(DAV\Server $server, \DOMElement $errorNode) |
|
| 25 | - { |
|
| 26 | - $doc = $errorNode->ownerDocument; |
|
| 19 | + /** |
|
| 20 | + * Adds in extra information in the xml response. |
|
| 21 | + * |
|
| 22 | + * This method adds the {DAV:}no-abstract element as defined in rfc3744 |
|
| 23 | + */ |
|
| 24 | + public function serialize(DAV\Server $server, \DOMElement $errorNode) |
|
| 25 | + { |
|
| 26 | + $doc = $errorNode->ownerDocument; |
|
| 27 | 27 | |
| 28 | - $np = $doc->createElementNS('DAV:', 'd:no-abstract'); |
|
| 29 | - $errorNode->appendChild($np); |
|
| 30 | - } |
|
| 28 | + $np = $doc->createElementNS('DAV:', 'd:no-abstract'); |
|
| 29 | + $errorNode->appendChild($np); |
|
| 30 | + } |
|
| 31 | 31 | } |
@@ -16,16 +16,16 @@ |
||
| 16 | 16 | */ |
| 17 | 17 | class NotSupportedPrivilege extends DAV\Exception\PreconditionFailed |
| 18 | 18 | { |
| 19 | - /** |
|
| 20 | - * Adds in extra information in the xml response. |
|
| 21 | - * |
|
| 22 | - * This method adds the {DAV:}not-supported-privilege element as defined in rfc3744 |
|
| 23 | - */ |
|
| 24 | - public function serialize(DAV\Server $server, \DOMElement $errorNode) |
|
| 25 | - { |
|
| 26 | - $doc = $errorNode->ownerDocument; |
|
| 19 | + /** |
|
| 20 | + * Adds in extra information in the xml response. |
|
| 21 | + * |
|
| 22 | + * This method adds the {DAV:}not-supported-privilege element as defined in rfc3744 |
|
| 23 | + */ |
|
| 24 | + public function serialize(DAV\Server $server, \DOMElement $errorNode) |
|
| 25 | + { |
|
| 26 | + $doc = $errorNode->ownerDocument; |
|
| 27 | 27 | |
| 28 | - $np = $doc->createElementNS('DAV:', 'd:not-supported-privilege'); |
|
| 29 | - $errorNode->appendChild($np); |
|
| 30 | - } |
|
| 28 | + $np = $doc->createElementNS('DAV:', 'd:not-supported-privilege'); |
|
| 29 | + $errorNode->appendChild($np); |
|
| 30 | + } |
|
| 31 | 31 | } |
@@ -18,56 +18,56 @@ |
||
| 18 | 18 | */ |
| 19 | 19 | class NeedPrivileges extends DAV\Exception\Forbidden |
| 20 | 20 | { |
| 21 | - /** |
|
| 22 | - * The relevant uri. |
|
| 23 | - * |
|
| 24 | - * @var string |
|
| 25 | - */ |
|
| 26 | - protected $uri; |
|
| 21 | + /** |
|
| 22 | + * The relevant uri. |
|
| 23 | + * |
|
| 24 | + * @var string |
|
| 25 | + */ |
|
| 26 | + protected $uri; |
|
| 27 | 27 | |
| 28 | - /** |
|
| 29 | - * The privileges the user didn't have. |
|
| 30 | - * |
|
| 31 | - * @var array |
|
| 32 | - */ |
|
| 33 | - protected $privileges; |
|
| 28 | + /** |
|
| 29 | + * The privileges the user didn't have. |
|
| 30 | + * |
|
| 31 | + * @var array |
|
| 32 | + */ |
|
| 33 | + protected $privileges; |
|
| 34 | 34 | |
| 35 | - /** |
|
| 36 | - * Constructor. |
|
| 37 | - * |
|
| 38 | - * @param string $uri |
|
| 39 | - */ |
|
| 40 | - public function __construct($uri, array $privileges) |
|
| 41 | - { |
|
| 42 | - $this->uri = $uri; |
|
| 43 | - $this->privileges = $privileges; |
|
| 35 | + /** |
|
| 36 | + * Constructor. |
|
| 37 | + * |
|
| 38 | + * @param string $uri |
|
| 39 | + */ |
|
| 40 | + public function __construct($uri, array $privileges) |
|
| 41 | + { |
|
| 42 | + $this->uri = $uri; |
|
| 43 | + $this->privileges = $privileges; |
|
| 44 | 44 | |
| 45 | - parent::__construct('User did not have the required privileges ('.implode(',', $privileges).') for path "'.$uri.'"'); |
|
| 46 | - } |
|
| 45 | + parent::__construct('User did not have the required privileges ('.implode(',', $privileges).') for path "'.$uri.'"'); |
|
| 46 | + } |
|
| 47 | 47 | |
| 48 | - /** |
|
| 49 | - * Adds in extra information in the xml response. |
|
| 50 | - * |
|
| 51 | - * This method adds the {DAV:}need-privileges element as defined in rfc3744 |
|
| 52 | - */ |
|
| 53 | - public function serialize(DAV\Server $server, \DOMElement $errorNode) |
|
| 54 | - { |
|
| 55 | - $doc = $errorNode->ownerDocument; |
|
| 48 | + /** |
|
| 49 | + * Adds in extra information in the xml response. |
|
| 50 | + * |
|
| 51 | + * This method adds the {DAV:}need-privileges element as defined in rfc3744 |
|
| 52 | + */ |
|
| 53 | + public function serialize(DAV\Server $server, \DOMElement $errorNode) |
|
| 54 | + { |
|
| 55 | + $doc = $errorNode->ownerDocument; |
|
| 56 | 56 | |
| 57 | - $np = $doc->createElementNS('DAV:', 'd:need-privileges'); |
|
| 58 | - $errorNode->appendChild($np); |
|
| 57 | + $np = $doc->createElementNS('DAV:', 'd:need-privileges'); |
|
| 58 | + $errorNode->appendChild($np); |
|
| 59 | 59 | |
| 60 | - foreach ($this->privileges as $privilege) { |
|
| 61 | - $resource = $doc->createElementNS('DAV:', 'd:resource'); |
|
| 62 | - $np->appendChild($resource); |
|
| 60 | + foreach ($this->privileges as $privilege) { |
|
| 61 | + $resource = $doc->createElementNS('DAV:', 'd:resource'); |
|
| 62 | + $np->appendChild($resource); |
|
| 63 | 63 | |
| 64 | - $resource->appendChild($doc->createElementNS('DAV:', 'd:href', $server->getBaseUri().$this->uri)); |
|
| 64 | + $resource->appendChild($doc->createElementNS('DAV:', 'd:href', $server->getBaseUri().$this->uri)); |
|
| 65 | 65 | |
| 66 | - $priv = $doc->createElementNS('DAV:', 'd:privilege'); |
|
| 67 | - $resource->appendChild($priv); |
|
| 66 | + $priv = $doc->createElementNS('DAV:', 'd:privilege'); |
|
| 67 | + $resource->appendChild($priv); |
|
| 68 | 68 | |
| 69 | - preg_match('/^{([^}]*)}(.*)$/', $privilege, $privilegeParts); |
|
| 70 | - $priv->appendChild($doc->createElementNS($privilegeParts[1], 'd:'.$privilegeParts[2])); |
|
| 71 | - } |
|
| 72 | - } |
|
| 69 | + preg_match('/^{([^}]*)}(.*)$/', $privilege, $privilegeParts); |
|
| 70 | + $priv->appendChild($doc->createElementNS($privilegeParts[1], 'd:'.$privilegeParts[2])); |
|
| 71 | + } |
|
| 72 | + } |
|
| 73 | 73 | } |
@@ -18,47 +18,47 @@ |
||
| 18 | 18 | */ |
| 19 | 19 | interface IPrincipalCollection extends DAV\ICollection |
| 20 | 20 | { |
| 21 | - /** |
|
| 22 | - * This method is used to search for principals matching a set of |
|
| 23 | - * properties. |
|
| 24 | - * |
|
| 25 | - * This search is specifically used by RFC3744's principal-property-search |
|
| 26 | - * REPORT. You should at least allow searching on |
|
| 27 | - * http://sabredav.org/ns}email-address. |
|
| 28 | - * |
|
| 29 | - * The actual search should be a unicode-non-case-sensitive search. The |
|
| 30 | - * keys in searchProperties are the WebDAV property names, while the values |
|
| 31 | - * are the property values to search on. |
|
| 32 | - * |
|
| 33 | - * By default, if multiple properties are submitted to this method, the |
|
| 34 | - * various properties should be combined with 'AND'. If $test is set to |
|
| 35 | - * 'anyof', it should be combined using 'OR'. |
|
| 36 | - * |
|
| 37 | - * This method should simply return a list of 'child names', which may be |
|
| 38 | - * used to call $this->getChild in the future. |
|
| 39 | - * |
|
| 40 | - * @param string $test |
|
| 41 | - * |
|
| 42 | - * @return array |
|
| 43 | - */ |
|
| 44 | - public function searchPrincipals(array $searchProperties, $test = 'allof'); |
|
| 21 | + /** |
|
| 22 | + * This method is used to search for principals matching a set of |
|
| 23 | + * properties. |
|
| 24 | + * |
|
| 25 | + * This search is specifically used by RFC3744's principal-property-search |
|
| 26 | + * REPORT. You should at least allow searching on |
|
| 27 | + * http://sabredav.org/ns}email-address. |
|
| 28 | + * |
|
| 29 | + * The actual search should be a unicode-non-case-sensitive search. The |
|
| 30 | + * keys in searchProperties are the WebDAV property names, while the values |
|
| 31 | + * are the property values to search on. |
|
| 32 | + * |
|
| 33 | + * By default, if multiple properties are submitted to this method, the |
|
| 34 | + * various properties should be combined with 'AND'. If $test is set to |
|
| 35 | + * 'anyof', it should be combined using 'OR'. |
|
| 36 | + * |
|
| 37 | + * This method should simply return a list of 'child names', which may be |
|
| 38 | + * used to call $this->getChild in the future. |
|
| 39 | + * |
|
| 40 | + * @param string $test |
|
| 41 | + * |
|
| 42 | + * @return array |
|
| 43 | + */ |
|
| 44 | + public function searchPrincipals(array $searchProperties, $test = 'allof'); |
|
| 45 | 45 | |
| 46 | - /** |
|
| 47 | - * Finds a principal by its URI. |
|
| 48 | - * |
|
| 49 | - * This method may receive any type of uri, but mailto: addresses will be |
|
| 50 | - * the most common. |
|
| 51 | - * |
|
| 52 | - * Implementation of this API is optional. It is currently used by the |
|
| 53 | - * CalDAV system to find principals based on their email addresses. If this |
|
| 54 | - * API is not implemented, some features may not work correctly. |
|
| 55 | - * |
|
| 56 | - * This method must return a relative principal path, or null, if the |
|
| 57 | - * principal was not found or you refuse to find it. |
|
| 58 | - * |
|
| 59 | - * @param string $uri |
|
| 60 | - * |
|
| 61 | - * @return string |
|
| 62 | - */ |
|
| 63 | - public function findByUri($uri); |
|
| 46 | + /** |
|
| 47 | + * Finds a principal by its URI. |
|
| 48 | + * |
|
| 49 | + * This method may receive any type of uri, but mailto: addresses will be |
|
| 50 | + * the most common. |
|
| 51 | + * |
|
| 52 | + * Implementation of this API is optional. It is currently used by the |
|
| 53 | + * CalDAV system to find principals based on their email addresses. If this |
|
| 54 | + * API is not implemented, some features may not work correctly. |
|
| 55 | + * |
|
| 56 | + * This method must return a relative principal path, or null, if the |
|
| 57 | + * principal was not found or you refuse to find it. |
|
| 58 | + * |
|
| 59 | + * @param string $uri |
|
| 60 | + * |
|
| 61 | + * @return string |
|
| 62 | + */ |
|
| 63 | + public function findByUri($uri); |
|
| 64 | 64 | } |
@@ -16,14 +16,14 @@ |
||
| 16 | 16 | */ |
| 17 | 17 | interface CreatePrincipalSupport extends BackendInterface |
| 18 | 18 | { |
| 19 | - /** |
|
| 20 | - * Creates a new principal. |
|
| 21 | - * |
|
| 22 | - * This method receives a full path for the new principal. The mkCol object |
|
| 23 | - * contains any additional webdav properties specified during the creation |
|
| 24 | - * of the principal. |
|
| 25 | - * |
|
| 26 | - * @param string $path |
|
| 27 | - */ |
|
| 28 | - public function createPrincipal($path, MkCol $mkCol); |
|
| 19 | + /** |
|
| 20 | + * Creates a new principal. |
|
| 21 | + * |
|
| 22 | + * This method receives a full path for the new principal. The mkCol object |
|
| 23 | + * contains any additional webdav properties specified during the creation |
|
| 24 | + * of the principal. |
|
| 25 | + * |
|
| 26 | + * @param string $path |
|
| 27 | + */ |
|
| 28 | + public function createPrincipal($path, MkCol $mkCol); |
|
| 29 | 29 | } |
@@ -17,38 +17,38 @@ |
||
| 17 | 17 | */ |
| 18 | 18 | abstract class AbstractBackend implements BackendInterface |
| 19 | 19 | { |
| 20 | - /** |
|
| 21 | - * Finds a principal by its URI. |
|
| 22 | - * |
|
| 23 | - * This method may receive any type of uri, but mailto: addresses will be |
|
| 24 | - * the most common. |
|
| 25 | - * |
|
| 26 | - * Implementation of this API is optional. It is currently used by the |
|
| 27 | - * CalDAV system to find principals based on their email addresses. If this |
|
| 28 | - * API is not implemented, some features may not work correctly. |
|
| 29 | - * |
|
| 30 | - * This method must return a relative principal path, or null, if the |
|
| 31 | - * principal was not found or you refuse to find it. |
|
| 32 | - * |
|
| 33 | - * @param string $uri |
|
| 34 | - * @param string $principalPrefix |
|
| 35 | - * |
|
| 36 | - * @return string|null |
|
| 37 | - */ |
|
| 38 | - public function findByUri($uri, $principalPrefix) |
|
| 39 | - { |
|
| 40 | - // Note that the default implementation here is a bit slow and could |
|
| 41 | - // likely be optimized. |
|
| 42 | - if ('mailto:' !== substr($uri, 0, 7)) { |
|
| 43 | - return; |
|
| 44 | - } |
|
| 45 | - $result = $this->searchPrincipals( |
|
| 46 | - $principalPrefix, |
|
| 47 | - ['{http://sabredav.org/ns}email-address' => substr($uri, 7)] |
|
| 48 | - ); |
|
| 20 | + /** |
|
| 21 | + * Finds a principal by its URI. |
|
| 22 | + * |
|
| 23 | + * This method may receive any type of uri, but mailto: addresses will be |
|
| 24 | + * the most common. |
|
| 25 | + * |
|
| 26 | + * Implementation of this API is optional. It is currently used by the |
|
| 27 | + * CalDAV system to find principals based on their email addresses. If this |
|
| 28 | + * API is not implemented, some features may not work correctly. |
|
| 29 | + * |
|
| 30 | + * This method must return a relative principal path, or null, if the |
|
| 31 | + * principal was not found or you refuse to find it. |
|
| 32 | + * |
|
| 33 | + * @param string $uri |
|
| 34 | + * @param string $principalPrefix |
|
| 35 | + * |
|
| 36 | + * @return string|null |
|
| 37 | + */ |
|
| 38 | + public function findByUri($uri, $principalPrefix) |
|
| 39 | + { |
|
| 40 | + // Note that the default implementation here is a bit slow and could |
|
| 41 | + // likely be optimized. |
|
| 42 | + if ('mailto:' !== substr($uri, 0, 7)) { |
|
| 43 | + return; |
|
| 44 | + } |
|
| 45 | + $result = $this->searchPrincipals( |
|
| 46 | + $principalPrefix, |
|
| 47 | + ['{http://sabredav.org/ns}email-address' => substr($uri, 7)] |
|
| 48 | + ); |
|
| 49 | 49 | |
| 50 | - if ($result) { |
|
| 51 | - return $result[0]; |
|
| 52 | - } |
|
| 53 | - } |
|
| 50 | + if ($result) { |
|
| 51 | + return $result[0]; |
|
| 52 | + } |
|
| 53 | + } |
|
| 54 | 54 | } |
@@ -20,424 +20,424 @@ |
||
| 20 | 20 | */ |
| 21 | 21 | class PDO extends AbstractBackend implements CreatePrincipalSupport |
| 22 | 22 | { |
| 23 | - /** |
|
| 24 | - * PDO table name for 'principals'. |
|
| 25 | - * |
|
| 26 | - * @var string |
|
| 27 | - */ |
|
| 28 | - public $tableName = 'principals'; |
|
| 29 | - |
|
| 30 | - /** |
|
| 31 | - * PDO table name for 'group members'. |
|
| 32 | - * |
|
| 33 | - * @var string |
|
| 34 | - */ |
|
| 35 | - public $groupMembersTableName = 'groupmembers'; |
|
| 36 | - |
|
| 37 | - /** |
|
| 38 | - * pdo. |
|
| 39 | - * |
|
| 40 | - * @var PDO |
|
| 41 | - */ |
|
| 42 | - protected $pdo; |
|
| 43 | - |
|
| 44 | - /** |
|
| 45 | - * A list of additional fields to support. |
|
| 46 | - * |
|
| 47 | - * @var array |
|
| 48 | - */ |
|
| 49 | - protected $fieldMap = [ |
|
| 50 | - /* |
|
| 23 | + /** |
|
| 24 | + * PDO table name for 'principals'. |
|
| 25 | + * |
|
| 26 | + * @var string |
|
| 27 | + */ |
|
| 28 | + public $tableName = 'principals'; |
|
| 29 | + |
|
| 30 | + /** |
|
| 31 | + * PDO table name for 'group members'. |
|
| 32 | + * |
|
| 33 | + * @var string |
|
| 34 | + */ |
|
| 35 | + public $groupMembersTableName = 'groupmembers'; |
|
| 36 | + |
|
| 37 | + /** |
|
| 38 | + * pdo. |
|
| 39 | + * |
|
| 40 | + * @var PDO |
|
| 41 | + */ |
|
| 42 | + protected $pdo; |
|
| 43 | + |
|
| 44 | + /** |
|
| 45 | + * A list of additional fields to support. |
|
| 46 | + * |
|
| 47 | + * @var array |
|
| 48 | + */ |
|
| 49 | + protected $fieldMap = [ |
|
| 50 | + /* |
|
| 51 | 51 | * This property can be used to display the users' real name. |
| 52 | 52 | */ |
| 53 | - '{DAV:}displayname' => [ |
|
| 54 | - 'dbField' => 'displayname', |
|
| 55 | - ], |
|
| 53 | + '{DAV:}displayname' => [ |
|
| 54 | + 'dbField' => 'displayname', |
|
| 55 | + ], |
|
| 56 | 56 | |
| 57 | - /* |
|
| 57 | + /* |
|
| 58 | 58 | * This is the users' primary email-address. |
| 59 | 59 | */ |
| 60 | - '{http://sabredav.org/ns}email-address' => [ |
|
| 61 | - 'dbField' => 'email', |
|
| 62 | - ], |
|
| 63 | - ]; |
|
| 64 | - |
|
| 65 | - /** |
|
| 66 | - * Sets up the backend. |
|
| 67 | - */ |
|
| 68 | - public function __construct(\PDO $pdo) |
|
| 69 | - { |
|
| 70 | - $this->pdo = $pdo; |
|
| 71 | - } |
|
| 72 | - |
|
| 73 | - /** |
|
| 74 | - * Returns a list of principals based on a prefix. |
|
| 75 | - * |
|
| 76 | - * This prefix will often contain something like 'principals'. You are only |
|
| 77 | - * expected to return principals that are in this base path. |
|
| 78 | - * |
|
| 79 | - * You are expected to return at least a 'uri' for every user, you can |
|
| 80 | - * return any additional properties if you wish so. Common properties are: |
|
| 81 | - * {DAV:}displayname |
|
| 82 | - * {http://sabredav.org/ns}email-address - This is a custom SabreDAV |
|
| 83 | - * field that's actualy injected in a number of other properties. If |
|
| 84 | - * you have an email address, use this property. |
|
| 85 | - * |
|
| 86 | - * @param string $prefixPath |
|
| 87 | - * |
|
| 88 | - * @return array |
|
| 89 | - */ |
|
| 90 | - public function getPrincipalsByPrefix($prefixPath) |
|
| 91 | - { |
|
| 92 | - $fields = [ |
|
| 93 | - 'uri', |
|
| 94 | - ]; |
|
| 95 | - |
|
| 96 | - foreach ($this->fieldMap as $key => $value) { |
|
| 97 | - $fields[] = $value['dbField']; |
|
| 98 | - } |
|
| 99 | - $result = $this->pdo->query('SELECT '.implode(',', $fields).' FROM '.$this->tableName); |
|
| 100 | - |
|
| 101 | - $principals = []; |
|
| 102 | - |
|
| 103 | - while ($row = $result->fetch(\PDO::FETCH_ASSOC)) { |
|
| 104 | - // Checking if the principal is in the prefix |
|
| 105 | - list($rowPrefix) = Uri\split($row['uri']); |
|
| 106 | - if ($rowPrefix !== $prefixPath) { |
|
| 107 | - continue; |
|
| 108 | - } |
|
| 109 | - |
|
| 110 | - $principal = [ |
|
| 111 | - 'uri' => $row['uri'], |
|
| 112 | - ]; |
|
| 113 | - foreach ($this->fieldMap as $key => $value) { |
|
| 114 | - if ($row[$value['dbField']]) { |
|
| 115 | - $principal[$key] = $row[$value['dbField']]; |
|
| 116 | - } |
|
| 117 | - } |
|
| 118 | - $principals[] = $principal; |
|
| 119 | - } |
|
| 120 | - |
|
| 121 | - return $principals; |
|
| 122 | - } |
|
| 123 | - |
|
| 124 | - /** |
|
| 125 | - * Returns a specific principal, specified by it's path. |
|
| 126 | - * The returned structure should be the exact same as from |
|
| 127 | - * getPrincipalsByPrefix. |
|
| 128 | - * |
|
| 129 | - * @param string $path |
|
| 130 | - * |
|
| 131 | - * @return array |
|
| 132 | - */ |
|
| 133 | - public function getPrincipalByPath($path) |
|
| 134 | - { |
|
| 135 | - $fields = [ |
|
| 136 | - 'id', |
|
| 137 | - 'uri', |
|
| 138 | - ]; |
|
| 139 | - |
|
| 140 | - foreach ($this->fieldMap as $key => $value) { |
|
| 141 | - $fields[] = $value['dbField']; |
|
| 142 | - } |
|
| 143 | - $stmt = $this->pdo->prepare('SELECT '.implode(',', $fields).' FROM '.$this->tableName.' WHERE uri = ?'); |
|
| 144 | - $stmt->execute([$path]); |
|
| 145 | - |
|
| 146 | - $row = $stmt->fetch(\PDO::FETCH_ASSOC); |
|
| 147 | - if (!$row) { |
|
| 148 | - return; |
|
| 149 | - } |
|
| 150 | - |
|
| 151 | - $principal = [ |
|
| 152 | - 'id' => $row['id'], |
|
| 153 | - 'uri' => $row['uri'], |
|
| 154 | - ]; |
|
| 155 | - foreach ($this->fieldMap as $key => $value) { |
|
| 156 | - if ($row[$value['dbField']]) { |
|
| 157 | - $principal[$key] = $row[$value['dbField']]; |
|
| 158 | - } |
|
| 159 | - } |
|
| 160 | - |
|
| 161 | - return $principal; |
|
| 162 | - } |
|
| 163 | - |
|
| 164 | - /** |
|
| 165 | - * Updates one ore more webdav properties on a principal. |
|
| 166 | - * |
|
| 167 | - * The list of mutations is stored in a Sabre\DAV\PropPatch object. |
|
| 168 | - * To do the actual updates, you must tell this object which properties |
|
| 169 | - * you're going to process with the handle() method. |
|
| 170 | - * |
|
| 171 | - * Calling the handle method is like telling the PropPatch object "I |
|
| 172 | - * promise I can handle updating this property". |
|
| 173 | - * |
|
| 174 | - * Read the PropPatch documentation for more info and examples. |
|
| 175 | - * |
|
| 176 | - * @param string $path |
|
| 177 | - */ |
|
| 178 | - public function updatePrincipal($path, DAV\PropPatch $propPatch) |
|
| 179 | - { |
|
| 180 | - $propPatch->handle(array_keys($this->fieldMap), function ($properties) use ($path) { |
|
| 181 | - $query = 'UPDATE '.$this->tableName.' SET '; |
|
| 182 | - $first = true; |
|
| 183 | - |
|
| 184 | - $values = []; |
|
| 185 | - |
|
| 186 | - foreach ($properties as $key => $value) { |
|
| 187 | - $dbField = $this->fieldMap[$key]['dbField']; |
|
| 188 | - |
|
| 189 | - if (!$first) { |
|
| 190 | - $query .= ', '; |
|
| 191 | - } |
|
| 192 | - $first = false; |
|
| 193 | - $query .= $dbField.' = :'.$dbField; |
|
| 194 | - $values[$dbField] = $value; |
|
| 195 | - } |
|
| 196 | - |
|
| 197 | - $query .= ' WHERE uri = :uri'; |
|
| 198 | - $values['uri'] = $path; |
|
| 199 | - |
|
| 200 | - $stmt = $this->pdo->prepare($query); |
|
| 201 | - $stmt->execute($values); |
|
| 202 | - |
|
| 203 | - return true; |
|
| 204 | - }); |
|
| 205 | - } |
|
| 206 | - |
|
| 207 | - /** |
|
| 208 | - * This method is used to search for principals matching a set of |
|
| 209 | - * properties. |
|
| 210 | - * |
|
| 211 | - * This search is specifically used by RFC3744's principal-property-search |
|
| 212 | - * REPORT. |
|
| 213 | - * |
|
| 214 | - * The actual search should be a unicode-non-case-sensitive search. The |
|
| 215 | - * keys in searchProperties are the WebDAV property names, while the values |
|
| 216 | - * are the property values to search on. |
|
| 217 | - * |
|
| 218 | - * By default, if multiple properties are submitted to this method, the |
|
| 219 | - * various properties should be combined with 'AND'. If $test is set to |
|
| 220 | - * 'anyof', it should be combined using 'OR'. |
|
| 221 | - * |
|
| 222 | - * This method should simply return an array with full principal uri's. |
|
| 223 | - * |
|
| 224 | - * If somebody attempted to search on a property the backend does not |
|
| 225 | - * support, you should simply return 0 results. |
|
| 226 | - * |
|
| 227 | - * You can also just return 0 results if you choose to not support |
|
| 228 | - * searching at all, but keep in mind that this may stop certain features |
|
| 229 | - * from working. |
|
| 230 | - * |
|
| 231 | - * @param string $prefixPath |
|
| 232 | - * @param string $test |
|
| 233 | - * |
|
| 234 | - * @return array |
|
| 235 | - */ |
|
| 236 | - public function searchPrincipals($prefixPath, array $searchProperties, $test = 'allof') |
|
| 237 | - { |
|
| 238 | - if (0 == count($searchProperties)) { |
|
| 239 | - return []; |
|
| 240 | - } //No criteria |
|
| 241 | - |
|
| 242 | - $query = 'SELECT uri FROM '.$this->tableName.' WHERE '; |
|
| 243 | - $values = []; |
|
| 244 | - foreach ($searchProperties as $property => $value) { |
|
| 245 | - switch ($property) { |
|
| 246 | - case '{DAV:}displayname': |
|
| 247 | - $column = 'displayname'; |
|
| 248 | - break; |
|
| 249 | - case '{http://sabredav.org/ns}email-address': |
|
| 250 | - $column = 'email'; |
|
| 251 | - break; |
|
| 252 | - default: |
|
| 253 | - // Unsupported property |
|
| 254 | - return []; |
|
| 255 | - } |
|
| 256 | - if (count($values) > 0) { |
|
| 257 | - $query .= (0 == strcmp($test, 'anyof') ? ' OR ' : ' AND '); |
|
| 258 | - } |
|
| 259 | - $query .= 'lower('.$column.') LIKE lower(?)'; |
|
| 260 | - $values[] = '%'.$value.'%'; |
|
| 261 | - } |
|
| 262 | - $stmt = $this->pdo->prepare($query); |
|
| 263 | - $stmt->execute($values); |
|
| 264 | - |
|
| 265 | - $principals = []; |
|
| 266 | - while ($row = $stmt->fetch(\PDO::FETCH_ASSOC)) { |
|
| 267 | - // Checking if the principal is in the prefix |
|
| 268 | - list($rowPrefix) = Uri\split($row['uri']); |
|
| 269 | - if ($rowPrefix !== $prefixPath) { |
|
| 270 | - continue; |
|
| 271 | - } |
|
| 272 | - |
|
| 273 | - $principals[] = $row['uri']; |
|
| 274 | - } |
|
| 275 | - |
|
| 276 | - return $principals; |
|
| 277 | - } |
|
| 278 | - |
|
| 279 | - /** |
|
| 280 | - * Finds a principal by its URI. |
|
| 281 | - * |
|
| 282 | - * This method may receive any type of uri, but mailto: addresses will be |
|
| 283 | - * the most common. |
|
| 284 | - * |
|
| 285 | - * Implementation of this API is optional. It is currently used by the |
|
| 286 | - * CalDAV system to find principals based on their email addresses. If this |
|
| 287 | - * API is not implemented, some features may not work correctly. |
|
| 288 | - * |
|
| 289 | - * This method must return a relative principal path, or null, if the |
|
| 290 | - * principal was not found or you refuse to find it. |
|
| 291 | - * |
|
| 292 | - * @param string $uri |
|
| 293 | - * @param string $principalPrefix |
|
| 294 | - * |
|
| 295 | - * @return string |
|
| 296 | - */ |
|
| 297 | - public function findByUri($uri, $principalPrefix) |
|
| 298 | - { |
|
| 299 | - $uriParts = Uri\parse($uri); |
|
| 300 | - |
|
| 301 | - // Only two types of uri are supported : |
|
| 302 | - // - the "mailto:" scheme with some non-empty address |
|
| 303 | - // - a principals uri, in the form "principals/NAME" |
|
| 304 | - // In both cases, `path` must not be empty. |
|
| 305 | - if (empty($uriParts['path'])) { |
|
| 306 | - return null; |
|
| 307 | - } |
|
| 308 | - |
|
| 309 | - $uri = null; |
|
| 310 | - if ('mailto' === $uriParts['scheme']) { |
|
| 311 | - $query = 'SELECT uri FROM '.$this->tableName.' WHERE lower(email)=lower(?)'; |
|
| 312 | - $stmt = $this->pdo->prepare($query); |
|
| 313 | - $stmt->execute([$uriParts['path']]); |
|
| 314 | - |
|
| 315 | - while ($row = $stmt->fetch(\PDO::FETCH_ASSOC)) { |
|
| 316 | - // Checking if the principal is in the prefix |
|
| 317 | - list($rowPrefix) = Uri\split($row['uri']); |
|
| 318 | - if ($rowPrefix !== $principalPrefix) { |
|
| 319 | - continue; |
|
| 320 | - } |
|
| 321 | - |
|
| 322 | - $uri = $row['uri']; |
|
| 323 | - break; //Stop on first match |
|
| 324 | - } |
|
| 325 | - } else { |
|
| 326 | - $pathParts = Uri\split($uriParts['path']); // We can do this since $uriParts['path'] is not null |
|
| 327 | - |
|
| 328 | - if (2 === count($pathParts) && $pathParts[0] === $principalPrefix) { |
|
| 329 | - // Checking that this uri exists |
|
| 330 | - $query = 'SELECT * FROM '.$this->tableName.' WHERE uri = ?'; |
|
| 331 | - $stmt = $this->pdo->prepare($query); |
|
| 332 | - $stmt->execute([$uriParts['path']]); |
|
| 333 | - $rows = $stmt->fetchAll(); |
|
| 334 | - |
|
| 335 | - if (count($rows) > 0) { |
|
| 336 | - $uri = $uriParts['path']; |
|
| 337 | - } |
|
| 338 | - } |
|
| 339 | - } |
|
| 340 | - |
|
| 341 | - return $uri; |
|
| 342 | - } |
|
| 343 | - |
|
| 344 | - /** |
|
| 345 | - * Returns the list of members for a group-principal. |
|
| 346 | - * |
|
| 347 | - * @param string $principal |
|
| 348 | - * |
|
| 349 | - * @return array |
|
| 350 | - */ |
|
| 351 | - public function getGroupMemberSet($principal) |
|
| 352 | - { |
|
| 353 | - $principal = $this->getPrincipalByPath($principal); |
|
| 354 | - if (!$principal) { |
|
| 355 | - throw new DAV\Exception('Principal not found'); |
|
| 356 | - } |
|
| 357 | - $stmt = $this->pdo->prepare('SELECT principals.uri as uri FROM '.$this->groupMembersTableName.' AS groupmembers LEFT JOIN '.$this->tableName.' AS principals ON groupmembers.member_id = principals.id WHERE groupmembers.principal_id = ?'); |
|
| 358 | - $stmt->execute([$principal['id']]); |
|
| 359 | - |
|
| 360 | - $result = []; |
|
| 361 | - while ($row = $stmt->fetch(\PDO::FETCH_ASSOC)) { |
|
| 362 | - $result[] = $row['uri']; |
|
| 363 | - } |
|
| 364 | - |
|
| 365 | - return $result; |
|
| 366 | - } |
|
| 367 | - |
|
| 368 | - /** |
|
| 369 | - * Returns the list of groups a principal is a member of. |
|
| 370 | - * |
|
| 371 | - * @param string $principal |
|
| 372 | - * |
|
| 373 | - * @return array |
|
| 374 | - */ |
|
| 375 | - public function getGroupMembership($principal) |
|
| 376 | - { |
|
| 377 | - $principal = $this->getPrincipalByPath($principal); |
|
| 378 | - if (!$principal) { |
|
| 379 | - throw new DAV\Exception('Principal not found'); |
|
| 380 | - } |
|
| 381 | - $stmt = $this->pdo->prepare('SELECT principals.uri as uri FROM '.$this->groupMembersTableName.' AS groupmembers LEFT JOIN '.$this->tableName.' AS principals ON groupmembers.principal_id = principals.id WHERE groupmembers.member_id = ?'); |
|
| 382 | - $stmt->execute([$principal['id']]); |
|
| 383 | - |
|
| 384 | - $result = []; |
|
| 385 | - while ($row = $stmt->fetch(\PDO::FETCH_ASSOC)) { |
|
| 386 | - $result[] = $row['uri']; |
|
| 387 | - } |
|
| 388 | - |
|
| 389 | - return $result; |
|
| 390 | - } |
|
| 391 | - |
|
| 392 | - /** |
|
| 393 | - * Updates the list of group members for a group principal. |
|
| 394 | - * |
|
| 395 | - * The principals should be passed as a list of uri's. |
|
| 396 | - * |
|
| 397 | - * @param string $principal |
|
| 398 | - */ |
|
| 399 | - public function setGroupMemberSet($principal, array $members) |
|
| 400 | - { |
|
| 401 | - // Grabbing the list of principal id's. |
|
| 402 | - $stmt = $this->pdo->prepare('SELECT id, uri FROM '.$this->tableName.' WHERE uri IN (? '.str_repeat(', ? ', count($members)).');'); |
|
| 403 | - $stmt->execute(array_merge([$principal], $members)); |
|
| 404 | - |
|
| 405 | - $memberIds = []; |
|
| 406 | - $principalId = null; |
|
| 407 | - |
|
| 408 | - while ($row = $stmt->fetch(\PDO::FETCH_ASSOC)) { |
|
| 409 | - if ($row['uri'] == $principal) { |
|
| 410 | - $principalId = $row['id']; |
|
| 411 | - } else { |
|
| 412 | - $memberIds[] = $row['id']; |
|
| 413 | - } |
|
| 414 | - } |
|
| 415 | - if (!$principalId) { |
|
| 416 | - throw new DAV\Exception('Principal not found'); |
|
| 417 | - } |
|
| 418 | - // Wiping out old members |
|
| 419 | - $stmt = $this->pdo->prepare('DELETE FROM '.$this->groupMembersTableName.' WHERE principal_id = ?;'); |
|
| 420 | - $stmt->execute([$principalId]); |
|
| 421 | - |
|
| 422 | - foreach ($memberIds as $memberId) { |
|
| 423 | - $stmt = $this->pdo->prepare('INSERT INTO '.$this->groupMembersTableName.' (principal_id, member_id) VALUES (?, ?);'); |
|
| 424 | - $stmt->execute([$principalId, $memberId]); |
|
| 425 | - } |
|
| 426 | - } |
|
| 427 | - |
|
| 428 | - /** |
|
| 429 | - * Creates a new principal. |
|
| 430 | - * |
|
| 431 | - * This method receives a full path for the new principal. The mkCol object |
|
| 432 | - * contains any additional webdav properties specified during the creation |
|
| 433 | - * of the principal. |
|
| 434 | - * |
|
| 435 | - * @param string $path |
|
| 436 | - */ |
|
| 437 | - public function createPrincipal($path, MkCol $mkCol) |
|
| 438 | - { |
|
| 439 | - $stmt = $this->pdo->prepare('INSERT INTO '.$this->tableName.' (uri) VALUES (?)'); |
|
| 440 | - $stmt->execute([$path]); |
|
| 441 | - $this->updatePrincipal($path, $mkCol); |
|
| 442 | - } |
|
| 60 | + '{http://sabredav.org/ns}email-address' => [ |
|
| 61 | + 'dbField' => 'email', |
|
| 62 | + ], |
|
| 63 | + ]; |
|
| 64 | + |
|
| 65 | + /** |
|
| 66 | + * Sets up the backend. |
|
| 67 | + */ |
|
| 68 | + public function __construct(\PDO $pdo) |
|
| 69 | + { |
|
| 70 | + $this->pdo = $pdo; |
|
| 71 | + } |
|
| 72 | + |
|
| 73 | + /** |
|
| 74 | + * Returns a list of principals based on a prefix. |
|
| 75 | + * |
|
| 76 | + * This prefix will often contain something like 'principals'. You are only |
|
| 77 | + * expected to return principals that are in this base path. |
|
| 78 | + * |
|
| 79 | + * You are expected to return at least a 'uri' for every user, you can |
|
| 80 | + * return any additional properties if you wish so. Common properties are: |
|
| 81 | + * {DAV:}displayname |
|
| 82 | + * {http://sabredav.org/ns}email-address - This is a custom SabreDAV |
|
| 83 | + * field that's actualy injected in a number of other properties. If |
|
| 84 | + * you have an email address, use this property. |
|
| 85 | + * |
|
| 86 | + * @param string $prefixPath |
|
| 87 | + * |
|
| 88 | + * @return array |
|
| 89 | + */ |
|
| 90 | + public function getPrincipalsByPrefix($prefixPath) |
|
| 91 | + { |
|
| 92 | + $fields = [ |
|
| 93 | + 'uri', |
|
| 94 | + ]; |
|
| 95 | + |
|
| 96 | + foreach ($this->fieldMap as $key => $value) { |
|
| 97 | + $fields[] = $value['dbField']; |
|
| 98 | + } |
|
| 99 | + $result = $this->pdo->query('SELECT '.implode(',', $fields).' FROM '.$this->tableName); |
|
| 100 | + |
|
| 101 | + $principals = []; |
|
| 102 | + |
|
| 103 | + while ($row = $result->fetch(\PDO::FETCH_ASSOC)) { |
|
| 104 | + // Checking if the principal is in the prefix |
|
| 105 | + list($rowPrefix) = Uri\split($row['uri']); |
|
| 106 | + if ($rowPrefix !== $prefixPath) { |
|
| 107 | + continue; |
|
| 108 | + } |
|
| 109 | + |
|
| 110 | + $principal = [ |
|
| 111 | + 'uri' => $row['uri'], |
|
| 112 | + ]; |
|
| 113 | + foreach ($this->fieldMap as $key => $value) { |
|
| 114 | + if ($row[$value['dbField']]) { |
|
| 115 | + $principal[$key] = $row[$value['dbField']]; |
|
| 116 | + } |
|
| 117 | + } |
|
| 118 | + $principals[] = $principal; |
|
| 119 | + } |
|
| 120 | + |
|
| 121 | + return $principals; |
|
| 122 | + } |
|
| 123 | + |
|
| 124 | + /** |
|
| 125 | + * Returns a specific principal, specified by it's path. |
|
| 126 | + * The returned structure should be the exact same as from |
|
| 127 | + * getPrincipalsByPrefix. |
|
| 128 | + * |
|
| 129 | + * @param string $path |
|
| 130 | + * |
|
| 131 | + * @return array |
|
| 132 | + */ |
|
| 133 | + public function getPrincipalByPath($path) |
|
| 134 | + { |
|
| 135 | + $fields = [ |
|
| 136 | + 'id', |
|
| 137 | + 'uri', |
|
| 138 | + ]; |
|
| 139 | + |
|
| 140 | + foreach ($this->fieldMap as $key => $value) { |
|
| 141 | + $fields[] = $value['dbField']; |
|
| 142 | + } |
|
| 143 | + $stmt = $this->pdo->prepare('SELECT '.implode(',', $fields).' FROM '.$this->tableName.' WHERE uri = ?'); |
|
| 144 | + $stmt->execute([$path]); |
|
| 145 | + |
|
| 146 | + $row = $stmt->fetch(\PDO::FETCH_ASSOC); |
|
| 147 | + if (!$row) { |
|
| 148 | + return; |
|
| 149 | + } |
|
| 150 | + |
|
| 151 | + $principal = [ |
|
| 152 | + 'id' => $row['id'], |
|
| 153 | + 'uri' => $row['uri'], |
|
| 154 | + ]; |
|
| 155 | + foreach ($this->fieldMap as $key => $value) { |
|
| 156 | + if ($row[$value['dbField']]) { |
|
| 157 | + $principal[$key] = $row[$value['dbField']]; |
|
| 158 | + } |
|
| 159 | + } |
|
| 160 | + |
|
| 161 | + return $principal; |
|
| 162 | + } |
|
| 163 | + |
|
| 164 | + /** |
|
| 165 | + * Updates one ore more webdav properties on a principal. |
|
| 166 | + * |
|
| 167 | + * The list of mutations is stored in a Sabre\DAV\PropPatch object. |
|
| 168 | + * To do the actual updates, you must tell this object which properties |
|
| 169 | + * you're going to process with the handle() method. |
|
| 170 | + * |
|
| 171 | + * Calling the handle method is like telling the PropPatch object "I |
|
| 172 | + * promise I can handle updating this property". |
|
| 173 | + * |
|
| 174 | + * Read the PropPatch documentation for more info and examples. |
|
| 175 | + * |
|
| 176 | + * @param string $path |
|
| 177 | + */ |
|
| 178 | + public function updatePrincipal($path, DAV\PropPatch $propPatch) |
|
| 179 | + { |
|
| 180 | + $propPatch->handle(array_keys($this->fieldMap), function ($properties) use ($path) { |
|
| 181 | + $query = 'UPDATE '.$this->tableName.' SET '; |
|
| 182 | + $first = true; |
|
| 183 | + |
|
| 184 | + $values = []; |
|
| 185 | + |
|
| 186 | + foreach ($properties as $key => $value) { |
|
| 187 | + $dbField = $this->fieldMap[$key]['dbField']; |
|
| 188 | + |
|
| 189 | + if (!$first) { |
|
| 190 | + $query .= ', '; |
|
| 191 | + } |
|
| 192 | + $first = false; |
|
| 193 | + $query .= $dbField.' = :'.$dbField; |
|
| 194 | + $values[$dbField] = $value; |
|
| 195 | + } |
|
| 196 | + |
|
| 197 | + $query .= ' WHERE uri = :uri'; |
|
| 198 | + $values['uri'] = $path; |
|
| 199 | + |
|
| 200 | + $stmt = $this->pdo->prepare($query); |
|
| 201 | + $stmt->execute($values); |
|
| 202 | + |
|
| 203 | + return true; |
|
| 204 | + }); |
|
| 205 | + } |
|
| 206 | + |
|
| 207 | + /** |
|
| 208 | + * This method is used to search for principals matching a set of |
|
| 209 | + * properties. |
|
| 210 | + * |
|
| 211 | + * This search is specifically used by RFC3744's principal-property-search |
|
| 212 | + * REPORT. |
|
| 213 | + * |
|
| 214 | + * The actual search should be a unicode-non-case-sensitive search. The |
|
| 215 | + * keys in searchProperties are the WebDAV property names, while the values |
|
| 216 | + * are the property values to search on. |
|
| 217 | + * |
|
| 218 | + * By default, if multiple properties are submitted to this method, the |
|
| 219 | + * various properties should be combined with 'AND'. If $test is set to |
|
| 220 | + * 'anyof', it should be combined using 'OR'. |
|
| 221 | + * |
|
| 222 | + * This method should simply return an array with full principal uri's. |
|
| 223 | + * |
|
| 224 | + * If somebody attempted to search on a property the backend does not |
|
| 225 | + * support, you should simply return 0 results. |
|
| 226 | + * |
|
| 227 | + * You can also just return 0 results if you choose to not support |
|
| 228 | + * searching at all, but keep in mind that this may stop certain features |
|
| 229 | + * from working. |
|
| 230 | + * |
|
| 231 | + * @param string $prefixPath |
|
| 232 | + * @param string $test |
|
| 233 | + * |
|
| 234 | + * @return array |
|
| 235 | + */ |
|
| 236 | + public function searchPrincipals($prefixPath, array $searchProperties, $test = 'allof') |
|
| 237 | + { |
|
| 238 | + if (0 == count($searchProperties)) { |
|
| 239 | + return []; |
|
| 240 | + } //No criteria |
|
| 241 | + |
|
| 242 | + $query = 'SELECT uri FROM '.$this->tableName.' WHERE '; |
|
| 243 | + $values = []; |
|
| 244 | + foreach ($searchProperties as $property => $value) { |
|
| 245 | + switch ($property) { |
|
| 246 | + case '{DAV:}displayname': |
|
| 247 | + $column = 'displayname'; |
|
| 248 | + break; |
|
| 249 | + case '{http://sabredav.org/ns}email-address': |
|
| 250 | + $column = 'email'; |
|
| 251 | + break; |
|
| 252 | + default: |
|
| 253 | + // Unsupported property |
|
| 254 | + return []; |
|
| 255 | + } |
|
| 256 | + if (count($values) > 0) { |
|
| 257 | + $query .= (0 == strcmp($test, 'anyof') ? ' OR ' : ' AND '); |
|
| 258 | + } |
|
| 259 | + $query .= 'lower('.$column.') LIKE lower(?)'; |
|
| 260 | + $values[] = '%'.$value.'%'; |
|
| 261 | + } |
|
| 262 | + $stmt = $this->pdo->prepare($query); |
|
| 263 | + $stmt->execute($values); |
|
| 264 | + |
|
| 265 | + $principals = []; |
|
| 266 | + while ($row = $stmt->fetch(\PDO::FETCH_ASSOC)) { |
|
| 267 | + // Checking if the principal is in the prefix |
|
| 268 | + list($rowPrefix) = Uri\split($row['uri']); |
|
| 269 | + if ($rowPrefix !== $prefixPath) { |
|
| 270 | + continue; |
|
| 271 | + } |
|
| 272 | + |
|
| 273 | + $principals[] = $row['uri']; |
|
| 274 | + } |
|
| 275 | + |
|
| 276 | + return $principals; |
|
| 277 | + } |
|
| 278 | + |
|
| 279 | + /** |
|
| 280 | + * Finds a principal by its URI. |
|
| 281 | + * |
|
| 282 | + * This method may receive any type of uri, but mailto: addresses will be |
|
| 283 | + * the most common. |
|
| 284 | + * |
|
| 285 | + * Implementation of this API is optional. It is currently used by the |
|
| 286 | + * CalDAV system to find principals based on their email addresses. If this |
|
| 287 | + * API is not implemented, some features may not work correctly. |
|
| 288 | + * |
|
| 289 | + * This method must return a relative principal path, or null, if the |
|
| 290 | + * principal was not found or you refuse to find it. |
|
| 291 | + * |
|
| 292 | + * @param string $uri |
|
| 293 | + * @param string $principalPrefix |
|
| 294 | + * |
|
| 295 | + * @return string |
|
| 296 | + */ |
|
| 297 | + public function findByUri($uri, $principalPrefix) |
|
| 298 | + { |
|
| 299 | + $uriParts = Uri\parse($uri); |
|
| 300 | + |
|
| 301 | + // Only two types of uri are supported : |
|
| 302 | + // - the "mailto:" scheme with some non-empty address |
|
| 303 | + // - a principals uri, in the form "principals/NAME" |
|
| 304 | + // In both cases, `path` must not be empty. |
|
| 305 | + if (empty($uriParts['path'])) { |
|
| 306 | + return null; |
|
| 307 | + } |
|
| 308 | + |
|
| 309 | + $uri = null; |
|
| 310 | + if ('mailto' === $uriParts['scheme']) { |
|
| 311 | + $query = 'SELECT uri FROM '.$this->tableName.' WHERE lower(email)=lower(?)'; |
|
| 312 | + $stmt = $this->pdo->prepare($query); |
|
| 313 | + $stmt->execute([$uriParts['path']]); |
|
| 314 | + |
|
| 315 | + while ($row = $stmt->fetch(\PDO::FETCH_ASSOC)) { |
|
| 316 | + // Checking if the principal is in the prefix |
|
| 317 | + list($rowPrefix) = Uri\split($row['uri']); |
|
| 318 | + if ($rowPrefix !== $principalPrefix) { |
|
| 319 | + continue; |
|
| 320 | + } |
|
| 321 | + |
|
| 322 | + $uri = $row['uri']; |
|
| 323 | + break; //Stop on first match |
|
| 324 | + } |
|
| 325 | + } else { |
|
| 326 | + $pathParts = Uri\split($uriParts['path']); // We can do this since $uriParts['path'] is not null |
|
| 327 | + |
|
| 328 | + if (2 === count($pathParts) && $pathParts[0] === $principalPrefix) { |
|
| 329 | + // Checking that this uri exists |
|
| 330 | + $query = 'SELECT * FROM '.$this->tableName.' WHERE uri = ?'; |
|
| 331 | + $stmt = $this->pdo->prepare($query); |
|
| 332 | + $stmt->execute([$uriParts['path']]); |
|
| 333 | + $rows = $stmt->fetchAll(); |
|
| 334 | + |
|
| 335 | + if (count($rows) > 0) { |
|
| 336 | + $uri = $uriParts['path']; |
|
| 337 | + } |
|
| 338 | + } |
|
| 339 | + } |
|
| 340 | + |
|
| 341 | + return $uri; |
|
| 342 | + } |
|
| 343 | + |
|
| 344 | + /** |
|
| 345 | + * Returns the list of members for a group-principal. |
|
| 346 | + * |
|
| 347 | + * @param string $principal |
|
| 348 | + * |
|
| 349 | + * @return array |
|
| 350 | + */ |
|
| 351 | + public function getGroupMemberSet($principal) |
|
| 352 | + { |
|
| 353 | + $principal = $this->getPrincipalByPath($principal); |
|
| 354 | + if (!$principal) { |
|
| 355 | + throw new DAV\Exception('Principal not found'); |
|
| 356 | + } |
|
| 357 | + $stmt = $this->pdo->prepare('SELECT principals.uri as uri FROM '.$this->groupMembersTableName.' AS groupmembers LEFT JOIN '.$this->tableName.' AS principals ON groupmembers.member_id = principals.id WHERE groupmembers.principal_id = ?'); |
|
| 358 | + $stmt->execute([$principal['id']]); |
|
| 359 | + |
|
| 360 | + $result = []; |
|
| 361 | + while ($row = $stmt->fetch(\PDO::FETCH_ASSOC)) { |
|
| 362 | + $result[] = $row['uri']; |
|
| 363 | + } |
|
| 364 | + |
|
| 365 | + return $result; |
|
| 366 | + } |
|
| 367 | + |
|
| 368 | + /** |
|
| 369 | + * Returns the list of groups a principal is a member of. |
|
| 370 | + * |
|
| 371 | + * @param string $principal |
|
| 372 | + * |
|
| 373 | + * @return array |
|
| 374 | + */ |
|
| 375 | + public function getGroupMembership($principal) |
|
| 376 | + { |
|
| 377 | + $principal = $this->getPrincipalByPath($principal); |
|
| 378 | + if (!$principal) { |
|
| 379 | + throw new DAV\Exception('Principal not found'); |
|
| 380 | + } |
|
| 381 | + $stmt = $this->pdo->prepare('SELECT principals.uri as uri FROM '.$this->groupMembersTableName.' AS groupmembers LEFT JOIN '.$this->tableName.' AS principals ON groupmembers.principal_id = principals.id WHERE groupmembers.member_id = ?'); |
|
| 382 | + $stmt->execute([$principal['id']]); |
|
| 383 | + |
|
| 384 | + $result = []; |
|
| 385 | + while ($row = $stmt->fetch(\PDO::FETCH_ASSOC)) { |
|
| 386 | + $result[] = $row['uri']; |
|
| 387 | + } |
|
| 388 | + |
|
| 389 | + return $result; |
|
| 390 | + } |
|
| 391 | + |
|
| 392 | + /** |
|
| 393 | + * Updates the list of group members for a group principal. |
|
| 394 | + * |
|
| 395 | + * The principals should be passed as a list of uri's. |
|
| 396 | + * |
|
| 397 | + * @param string $principal |
|
| 398 | + */ |
|
| 399 | + public function setGroupMemberSet($principal, array $members) |
|
| 400 | + { |
|
| 401 | + // Grabbing the list of principal id's. |
|
| 402 | + $stmt = $this->pdo->prepare('SELECT id, uri FROM '.$this->tableName.' WHERE uri IN (? '.str_repeat(', ? ', count($members)).');'); |
|
| 403 | + $stmt->execute(array_merge([$principal], $members)); |
|
| 404 | + |
|
| 405 | + $memberIds = []; |
|
| 406 | + $principalId = null; |
|
| 407 | + |
|
| 408 | + while ($row = $stmt->fetch(\PDO::FETCH_ASSOC)) { |
|
| 409 | + if ($row['uri'] == $principal) { |
|
| 410 | + $principalId = $row['id']; |
|
| 411 | + } else { |
|
| 412 | + $memberIds[] = $row['id']; |
|
| 413 | + } |
|
| 414 | + } |
|
| 415 | + if (!$principalId) { |
|
| 416 | + throw new DAV\Exception('Principal not found'); |
|
| 417 | + } |
|
| 418 | + // Wiping out old members |
|
| 419 | + $stmt = $this->pdo->prepare('DELETE FROM '.$this->groupMembersTableName.' WHERE principal_id = ?;'); |
|
| 420 | + $stmt->execute([$principalId]); |
|
| 421 | + |
|
| 422 | + foreach ($memberIds as $memberId) { |
|
| 423 | + $stmt = $this->pdo->prepare('INSERT INTO '.$this->groupMembersTableName.' (principal_id, member_id) VALUES (?, ?);'); |
|
| 424 | + $stmt->execute([$principalId, $memberId]); |
|
| 425 | + } |
|
| 426 | + } |
|
| 427 | + |
|
| 428 | + /** |
|
| 429 | + * Creates a new principal. |
|
| 430 | + * |
|
| 431 | + * This method receives a full path for the new principal. The mkCol object |
|
| 432 | + * contains any additional webdav properties specified during the creation |
|
| 433 | + * of the principal. |
|
| 434 | + * |
|
| 435 | + * @param string $path |
|
| 436 | + */ |
|
| 437 | + public function createPrincipal($path, MkCol $mkCol) |
|
| 438 | + { |
|
| 439 | + $stmt = $this->pdo->prepare('INSERT INTO '.$this->tableName.' (uri) VALUES (?)'); |
|
| 440 | + $stmt->execute([$path]); |
|
| 441 | + $this->updatePrincipal($path, $mkCol); |
|
| 442 | + } |
|
| 443 | 443 | } |
@@ -177,7 +177,7 @@ |
||
| 177 | 177 | */ |
| 178 | 178 | public function updatePrincipal($path, DAV\PropPatch $propPatch) |
| 179 | 179 | { |
| 180 | - $propPatch->handle(array_keys($this->fieldMap), function ($properties) use ($path) { |
|
| 180 | + $propPatch->handle(array_keys($this->fieldMap), function($properties) use ($path) { |
|
| 181 | 181 | $query = 'UPDATE '.$this->tableName.' SET '; |
| 182 | 182 | $first = true; |
| 183 | 183 | |