mirror of
https://github.com/EGroupware/egroupware.git
synced 2024-12-28 01:29:05 +01:00
WIP REST Api for contacts
This commit is contained in:
parent
fc3aba9c39
commit
0768f5fadf
@ -73,9 +73,14 @@ class addressbook_groupdav extends Api\CalDAV\Handler
|
|||||||
|
|
||||||
$this->bo = new Api\Contacts();
|
$this->bo = new Api\Contacts();
|
||||||
|
|
||||||
|
if (Api\CalDAV::isJSON())
|
||||||
|
{
|
||||||
|
self::$path_attr = 'id';
|
||||||
|
self::$path_extension = '';
|
||||||
|
}
|
||||||
// since 1.9.007 we allow clients to specify the URL when creating a new contact, as specified by CardDAV
|
// since 1.9.007 we allow clients to specify the URL when creating a new contact, as specified by CardDAV
|
||||||
// LDAP does NOT have a carddav_name attribute --> stick with id mapped to LDAP attribute uid
|
// LDAP does NOT have a carddav_name attribute --> stick with id mapped to LDAP attribute uid
|
||||||
if (version_compare($GLOBALS['egw_info']['apps']['api']['version'], '1.9.007', '<') ||
|
elseif (version_compare($GLOBALS['egw_info']['apps']['api']['version'], '1.9.007', '<') ||
|
||||||
$this->bo->contact_repository != 'sql' ||
|
$this->bo->contact_repository != 'sql' ||
|
||||||
$this->bo->account_repository != 'sql' && strpos($_SERVER['REQUEST_URI'].'/','/addressbook-accounts/') !== false)
|
$this->bo->account_repository != 'sql' && strpos($_SERVER['REQUEST_URI'].'/','/addressbook-accounts/') !== false)
|
||||||
{
|
{
|
||||||
@ -173,12 +178,12 @@ class addressbook_groupdav extends Api\CalDAV\Handler
|
|||||||
if ($options['root']['name'] == 'sync-collection' && $this->bo->total > $nresults)
|
if ($options['root']['name'] == 'sync-collection' && $this->bo->total > $nresults)
|
||||||
{
|
{
|
||||||
--$this->sync_collection_token;
|
--$this->sync_collection_token;
|
||||||
$files['sync-token-params'][] = true; // tel get_sync_collection_token that we have more entries
|
$files['sync-token-params'][] = true; // tell get_sync_collection_token that we have more entries
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// return iterator, calling ourself to return result in chunks
|
// return iterator, calling ourselves to return result in chunks
|
||||||
$files['files'] = new Api\CalDAV\PropfindIterator($this,$path,$filter,$files['files']);
|
$files['files'] = new Api\CalDAV\PropfindIterator($this,$path,$filter,$files['files']);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -270,6 +275,7 @@ class addressbook_groupdav extends Api\CalDAV\Handler
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$is_jscontact = Api\CalDAV::isJSON();
|
||||||
foreach($contacts as &$contact)
|
foreach($contacts as &$contact)
|
||||||
{
|
{
|
||||||
// remove contact from requested multiget ids, to be able to report not found urls
|
// remove contact from requested multiget ids, to be able to report not found urls
|
||||||
@ -284,15 +290,16 @@ class addressbook_groupdav extends Api\CalDAV\Handler
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$props = array(
|
$props = array(
|
||||||
'getcontenttype' => Api\CalDAV::mkprop('getcontenttype', 'text/vcard'),
|
'getcontenttype' => Api\CalDAV::mkprop('getcontenttype', $is_jscontact ? JsContact::MIME_TYPE_JSCARD : 'text/vcard'),
|
||||||
'getlastmodified' => $contact['modified'],
|
'getlastmodified' => $contact['modified'],
|
||||||
'displayname' => $contact['n_fn'],
|
'displayname' => $contact['n_fn'],
|
||||||
);
|
);
|
||||||
if ($address_data)
|
if ($address_data)
|
||||||
{
|
{
|
||||||
$content = $handler->getVCard($contact['id'],$this->charset,false);
|
$content = $is_jscontact ? JsContact::getJsCard($contact['id'], false) :
|
||||||
|
$handler->getVCard($contact['id'],$this->charset,false);
|
||||||
$props['getcontentlength'] = bytes($content);
|
$props['getcontentlength'] = bytes($content);
|
||||||
$props[] = Api\CalDAV::mkprop(Api\CalDAV::CARDDAV, 'address-data', $content);
|
$props['address-data'] = Api\CalDAV::mkprop(Api\CalDAV::CARDDAV, 'address-data', $content);
|
||||||
}
|
}
|
||||||
$files[] = $this->add_resource($path, $contact, $props);
|
$files[] = $this->add_resource($path, $contact, $props);
|
||||||
}
|
}
|
||||||
@ -351,16 +358,16 @@ class addressbook_groupdav extends Api\CalDAV\Handler
|
|||||||
$etag .= ':'.implode('-',$filter['owner']);
|
$etag .= ':'.implode('-',$filter['owner']);
|
||||||
}
|
}
|
||||||
$props = array(
|
$props = array(
|
||||||
'getcontenttype' => Api\CalDAV::mkprop('getcontenttype', 'text/vcard'),
|
'getcontenttype' => Api\CalDAV::mkprop('getcontenttype', $is_jscontact ? JsContact::MIME_TYPE_JSCARDGROUP : 'text/vcard'),
|
||||||
'getlastmodified' => Api\DateTime::to($list['list_modified'],'ts'),
|
'getlastmodified' => Api\DateTime::to($list['list_modified'],'ts'),
|
||||||
'displayname' => $list['list_name'],
|
'displayname' => $list['list_name'],
|
||||||
'getetag' => '"'.$etag.'"',
|
'getetag' => '"'.$etag.'"',
|
||||||
);
|
);
|
||||||
if ($address_data)
|
if ($address_data)
|
||||||
{
|
{
|
||||||
$content = $handler->getGroupVCard($list);
|
$content = $is_jscontact ? JsContact::getJsCardGroup($list) : $handler->getGroupVCard($list);
|
||||||
$props['getcontentlength'] = bytes($content);
|
$props['getcontentlength'] = bytes($content);
|
||||||
$props[] = Api\CalDAV::mkprop(Api\CalDAV::CARDDAV, 'address-data', $content);
|
$props['address-data'] = Api\CalDAV::mkprop(Api\CalDAV::CARDDAV, 'address-data', $content);
|
||||||
}
|
}
|
||||||
$files[] = $this->add_resource($path, $list, $props);
|
$files[] = $this->add_resource($path, $list, $props);
|
||||||
|
|
||||||
@ -452,7 +459,7 @@ class addressbook_groupdav extends Api\CalDAV\Handler
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
switch($filter['attrs']['collation']) // todo: which other collations allowed, we are allways unicode
|
switch($filter['attrs']['collation']) // todo: which other collations allowed, we are always unicode
|
||||||
{
|
{
|
||||||
case 'i;unicode-casemap':
|
case 'i;unicode-casemap':
|
||||||
default:
|
default:
|
||||||
@ -590,7 +597,7 @@ class addressbook_groupdav extends Api\CalDAV\Handler
|
|||||||
return $contact;
|
return $contact;
|
||||||
}
|
}
|
||||||
// jsContact or vCard
|
// jsContact or vCard
|
||||||
if (JsContact::isJsContact())
|
if (Api\CalDAV::isJSON())
|
||||||
{
|
{
|
||||||
$options['data'] = $contact['list_id'] ? JsContact::getJsCardGroup($contact) : JsContact::getJsCard($contact);
|
$options['data'] = $contact['list_id'] ? JsContact::getJsCardGroup($contact) : JsContact::getJsCard($contact);
|
||||||
$options['mimetype'] = $contact['list_id'] ? JsContact::MIME_TYPE_JSCARDGROUP : JsContact::MIME_TYPE_JSCARD;
|
$options['mimetype'] = $contact['list_id'] ? JsContact::MIME_TYPE_JSCARDGROUP : JsContact::MIME_TYPE_JSCARD;
|
||||||
@ -628,7 +635,7 @@ class addressbook_groupdav extends Api\CalDAV\Handler
|
|||||||
return $oldContact;
|
return $oldContact;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (JsContact::isJsContact())
|
if (Api\CalDAV::isJSON())
|
||||||
{
|
{
|
||||||
$contact = JsContact::parseJsCard($options['content']);
|
$contact = JsContact::parseJsCard($options['content']);
|
||||||
// just output it again for now
|
// just output it again for now
|
||||||
|
@ -18,6 +18,8 @@ use EGroupware\Api\CalDAV\Principals;
|
|||||||
|
|
||||||
// explicit import non-namespaced classes
|
// explicit import non-namespaced classes
|
||||||
require_once(__DIR__.'/WebDAV/Server.php');
|
require_once(__DIR__.'/WebDAV/Server.php');
|
||||||
|
|
||||||
|
use EGroupware\Api\Contacts\JsContact;
|
||||||
use HTTP_WebDAV_Server;
|
use HTTP_WebDAV_Server;
|
||||||
use calendar_hooks;
|
use calendar_hooks;
|
||||||
|
|
||||||
@ -976,6 +978,21 @@ class CalDAV extends HTTP_WebDAV_Server
|
|||||||
parent::http_PROPFIND('REPORT');
|
parent::http_PROPFIND('REPORT');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if clients want's or sends JSON
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public static function isJSON(string $type=null)
|
||||||
|
{
|
||||||
|
if (!isset($type))
|
||||||
|
{
|
||||||
|
$type = in_array($_SERVER['REQUEST_METHOD'], ['PUT', 'POST', 'PROPPATCH']) ?
|
||||||
|
$_SERVER['HTTP_CONTENT_TYPE'] : $_SERVER['HTTP_ACCEPT'];
|
||||||
|
}
|
||||||
|
return (bool)preg_match('#application/([^+ ;]+\+)?json#', $type);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GET method handler
|
* GET method handler
|
||||||
*
|
*
|
||||||
@ -989,6 +1006,10 @@ class CalDAV extends HTTP_WebDAV_Server
|
|||||||
$id = $app = $user = null;
|
$id = $app = $user = null;
|
||||||
if (!$this->_parse_path($options['path'],$id,$app,$user) || $app == 'principals')
|
if (!$this->_parse_path($options['path'],$id,$app,$user) || $app == 'principals')
|
||||||
{
|
{
|
||||||
|
if (self::isJSON())
|
||||||
|
{
|
||||||
|
return $this->jsonIndex($options);
|
||||||
|
}
|
||||||
return $this->autoindex($options);
|
return $this->autoindex($options);
|
||||||
}
|
}
|
||||||
if (($handler = self::app_handler($app)))
|
if (($handler = self::app_handler($app)))
|
||||||
@ -999,6 +1020,170 @@ class CalDAV extends HTTP_WebDAV_Server
|
|||||||
return '501 Not Implemented';
|
return '501 Not Implemented';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const JSON_OPTIONS = JSON_UNESCAPED_SLASHES|JSON_UNESCAPED_UNICODE|JSON_THROW_ON_ERROR;
|
||||||
|
const JSON_OPTIONS_PRETTY = JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES|JSON_UNESCAPED_UNICODE|JSON_THROW_ON_ERROR;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JSON encode incl. modified pretty-print
|
||||||
|
*
|
||||||
|
* @param $data
|
||||||
|
* @return array|string|string[]|null
|
||||||
|
*/
|
||||||
|
public static function json_encode($data, $pretty = true)
|
||||||
|
{
|
||||||
|
if (!$pretty)
|
||||||
|
{
|
||||||
|
return self::json_encode($data, self::JSON_OPTIONS);
|
||||||
|
}
|
||||||
|
return preg_replace('/: {\n\s*(.*?)\n\s*(},?\n)/', ': { $1 $2',
|
||||||
|
json_encode($data, self::JSON_OPTIONS_PRETTY));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PROPFIND/REPORT like output for GET request on collection with Accept: application/(.*+)?json
|
||||||
|
*
|
||||||
|
* For addressbook-collections we give a REST-like output without any other properties
|
||||||
|
* {
|
||||||
|
* "/addressbook/ID": {
|
||||||
|
* JsContact-data
|
||||||
|
* },
|
||||||
|
* ...
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* @param array $options
|
||||||
|
* @return bool|string|void
|
||||||
|
*/
|
||||||
|
protected function jsonIndex(array $options)
|
||||||
|
{
|
||||||
|
header('Content-Type: application/json; charset=utf-8');
|
||||||
|
$is_addressbook = strpos($options['path'], '/addressbook') !== false;
|
||||||
|
$propfind_options = array(
|
||||||
|
'path' => $options['path'],
|
||||||
|
'depth' => 1,
|
||||||
|
'props' => $is_addressbook ? [
|
||||||
|
'address-data' => self::mkprop(self::CARDDAV, 'address-data', '')
|
||||||
|
] : 'all',
|
||||||
|
'other' => [],
|
||||||
|
);
|
||||||
|
|
||||||
|
// sync-collection report via GET parameter sync-token
|
||||||
|
if (isset($_GET['sync-token']))
|
||||||
|
{
|
||||||
|
$propfind_options['root'] = ['name' => 'sync-collection'];
|
||||||
|
$propfind_options['other'][] = ['name' => 'sync-token', 'data' => $_GET['sync-token']];
|
||||||
|
$propfind_options['other'][] = ['name' => 'sync-level', 'data' => $_GET['sync-level'] ?? 1];
|
||||||
|
|
||||||
|
// clients want's pagination
|
||||||
|
if (isset($_GET['nresults']))
|
||||||
|
{
|
||||||
|
$propfind_options['other'][] = ['name' => 'nresults', 'data' => (int)$_GET['nresults']];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToDo: client want data filtered
|
||||||
|
if (isset($_GET['filters']))
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// properties to NOT get the default address-data for addressbook-collections and "all" for the rest
|
||||||
|
if (isset($_GET['props']))
|
||||||
|
{
|
||||||
|
$propfind_options['props'] = [];
|
||||||
|
foreach((array)$_GET['props'] as $value)
|
||||||
|
{
|
||||||
|
$parts = explode(':', $value);
|
||||||
|
$name = array_pop($parts);
|
||||||
|
$ns = $parts ? implode(':', $parts) : 'DAV:';
|
||||||
|
$propfind_options['props'][$name] = self::mkprop($ns, $name, '');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$files = array();
|
||||||
|
if (($ret = $this->REPORT($propfind_options,$files)) !== true)
|
||||||
|
{
|
||||||
|
return $ret; // no collection
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "{\n";
|
||||||
|
$prefix = " ";
|
||||||
|
foreach($files['files'] as $resource)
|
||||||
|
{
|
||||||
|
$path = $resource['path'];
|
||||||
|
echo $prefix.json_encode($path, JSON_UNESCAPED_SLASHES|JSON_UNESCAPED_UNICODE).': ';
|
||||||
|
if (!isset($resource['props']))
|
||||||
|
{
|
||||||
|
echo 'null'; // deleted in sync-report
|
||||||
|
}
|
||||||
|
/*elseif (isset($resource['props']['address-data']))
|
||||||
|
{
|
||||||
|
echo $resource['props']['address-data']['val'];
|
||||||
|
}*/
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$props = $propfind_options['props'] === 'all' ? $resource['props'] :
|
||||||
|
array_intersect_key($resource['props'], $propfind_options['props']);
|
||||||
|
|
||||||
|
if (count($props) > 1)
|
||||||
|
{
|
||||||
|
$props = self::jsonProps($props);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$props = current($props)['val'];
|
||||||
|
}
|
||||||
|
echo self::json_encode($props);
|
||||||
|
}
|
||||||
|
$prefix = ",\n ";
|
||||||
|
}
|
||||||
|
// add sync-token to response
|
||||||
|
if (isset($files['sync-token']))
|
||||||
|
{
|
||||||
|
echo $prefix.'"sync-token": '.json_encode(!is_callable($files['sync-token']) ? $files['sync-token'] :
|
||||||
|
call_user_func_array($files['sync-token'], (array)$files['sync-token-params']), JSON_UNESCAPED_SLASHES|JSON_UNESCAPED_UNICODE);
|
||||||
|
}
|
||||||
|
echo "\n}\n";
|
||||||
|
|
||||||
|
// exit now, so WebDAV::GET does NOT add Content-Type: application/octet-stream
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Nicer way to display/encode DAV properties
|
||||||
|
*
|
||||||
|
* @param array $props
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
protected function jsonProps(array $props)
|
||||||
|
{
|
||||||
|
$json = [];
|
||||||
|
foreach($props as $key => $prop)
|
||||||
|
{
|
||||||
|
if (is_scalar($prop['val']))
|
||||||
|
{
|
||||||
|
$value = is_int($key) && $prop['val'] === '' ?
|
||||||
|
/*$prop['ns'].':'.*/$prop['name'] : $prop['val'];
|
||||||
|
}
|
||||||
|
// check if this is a property-object
|
||||||
|
elseif (count($prop) === 3 && isset($prop['name']) && isset($prop['ns']) && isset($prop['val']))
|
||||||
|
{
|
||||||
|
$value = $prop['name'] === 'address-data' ? $prop['val'] : self::jsonProps($prop['val']);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$value = $prop;
|
||||||
|
}
|
||||||
|
if (is_int($key))
|
||||||
|
{
|
||||||
|
$json[] = $value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$json[/*($prop['ns'] === 'DAV:' ? '' : $prop['ns'].':').*/$prop['name']] = $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $json;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Display an automatic index (listing and properties) for a collection
|
* Display an automatic index (listing and properties) for a collection
|
||||||
*
|
*
|
||||||
|
@ -712,16 +712,23 @@ abstract class Handler
|
|||||||
//error_log(__METHOD__."('$path', $user, more_results=$more_results) this->sync_collection_token=".$this->sync_collection_token);
|
//error_log(__METHOD__."('$path', $user, more_results=$more_results) this->sync_collection_token=".$this->sync_collection_token);
|
||||||
if ($more_results)
|
if ($more_results)
|
||||||
{
|
{
|
||||||
$error =
|
if (Api\CalDAV::isJSON())
|
||||||
' <D:response>
|
{
|
||||||
<D:href>'.htmlspecialchars($this->caldav->base_uri.$this->caldav->path).'</D:href>
|
$error = ",\n".' "more-results": true';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$error =
|
||||||
|
' <D:response>
|
||||||
|
<D:href>' . htmlspecialchars($this->caldav->base_uri . $this->caldav->path) . '</D:href>
|
||||||
<D:status>HTTP/1.1 507 Insufficient Storage</D:status>
|
<D:status>HTTP/1.1 507 Insufficient Storage</D:status>
|
||||||
<D:error><D:number-of-matches-within-limits/></D:error>
|
<D:error><D:number-of-matches-within-limits/></D:error>
|
||||||
</D:response>
|
</D:response>
|
||||||
';
|
';
|
||||||
if ($this->caldav->crrnd)
|
if ($this->caldav->crrnd)
|
||||||
{
|
{
|
||||||
$error = str_replace(array('<D:', '</D:'), array('<', '</'), $error);
|
$error = str_replace(array('<D:', '</D:'), array('<', '</'), $error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
echo $error;
|
echo $error;
|
||||||
}
|
}
|
||||||
|
@ -26,39 +26,21 @@ class JsContact
|
|||||||
const MIME_TYPE_JSCARDGROUP = "application/jscontact+json;type=cardgroup";
|
const MIME_TYPE_JSCARDGROUP = "application/jscontact+json;type=cardgroup";
|
||||||
const MIME_TYPE_JSON = "application/json";
|
const MIME_TYPE_JSON = "application/json";
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if request want's JSON
|
|
||||||
*
|
|
||||||
* @param ?string $type default use Content-Type or Accept HTTP header depending on request method
|
|
||||||
* @return bool true: jsContact, false: other eg. vCard
|
|
||||||
*/
|
|
||||||
public static function isJsContact(string $type=null)
|
|
||||||
{
|
|
||||||
if (!isset($type))
|
|
||||||
{
|
|
||||||
$type = in_array($_SERVER['REQUEST_METHOD'], ['PUT', 'POST']) ?
|
|
||||||
$_SERVER['HTTP_CONTENT_TYPE'] : $_SERVER['HTTP_ACCEPT'];
|
|
||||||
}
|
|
||||||
return strpos($type, self::MIME_TYPE) !== false ||
|
|
||||||
strpos($type, self::MIME_TYPE_JSON) !== false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const JSON_OPTIONS = JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES|JSON_UNESCAPED_UNICODE;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get jsCard for given contact
|
* Get jsCard for given contact
|
||||||
*
|
*
|
||||||
* @param int|array $contact
|
* @param int|array $contact
|
||||||
* @return string
|
* @param bool $encode=true true: JSON encode, false: return raw data eg. from listing
|
||||||
|
* @return string|array
|
||||||
* @throws Api\Exception\NotFound
|
* @throws Api\Exception\NotFound
|
||||||
*/
|
*/
|
||||||
public static function getJsCard($contact)
|
public static function getJsCard($contact, $encode=true)
|
||||||
{
|
{
|
||||||
if (is_scalar($contact) && !($contact = self::getContacts()->read($contact)))
|
if (is_scalar($contact) && !($contact = self::getContacts()->read($contact)))
|
||||||
{
|
{
|
||||||
throw new Api\Exception\NotFound();
|
throw new Api\Exception\NotFound();
|
||||||
}
|
}
|
||||||
return json_encode(array_filter([
|
$data = array_filter([
|
||||||
'uid' => $contact['uid'],
|
'uid' => $contact['uid'],
|
||||||
'prodId' => 'EGroupware Addressbook '.$GLOBALS['egw_info']['apps']['api']['version'],
|
'prodId' => 'EGroupware Addressbook '.$GLOBALS['egw_info']['apps']['api']['version'],
|
||||||
'created' => self::UTCDateTime($contact['created']),
|
'created' => self::UTCDateTime($contact['created']),
|
||||||
@ -90,7 +72,12 @@ class JsContact
|
|||||||
'egroupware.org/customfields' => self::customfields($contact),
|
'egroupware.org/customfields' => self::customfields($contact),
|
||||||
'egroupware.org/assistant' => $contact['assistent'],
|
'egroupware.org/assistant' => $contact['assistent'],
|
||||||
'egroupware.org/fileAs' => $contact['fileas'],
|
'egroupware.org/fileAs' => $contact['fileas'],
|
||||||
]), self::JSON_OPTIONS);
|
]);
|
||||||
|
if ($encode)
|
||||||
|
{
|
||||||
|
return Api\CalDAV::json_encode($data);
|
||||||
|
}
|
||||||
|
return $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -526,14 +513,19 @@ class JsContact
|
|||||||
* @param ?string $street2=null 2. address line
|
* @param ?string $street2=null 2. address line
|
||||||
* @return array[] array of objects with attributes type and value
|
* @return array[] array of objects with attributes type and value
|
||||||
*/
|
*/
|
||||||
protected static function streetComponents(string $street, ?string $street2=null)
|
protected static function streetComponents(?string $street, ?string $street2=null)
|
||||||
{
|
{
|
||||||
$components = [['type' => 'name', 'value' => $street]];
|
$components = [];
|
||||||
|
foreach(func_get_args() as $street)
|
||||||
if (!empty($street2))
|
|
||||||
{
|
{
|
||||||
$components[] = ['type' => 'separator', 'value' => "\n"];
|
if ($components)
|
||||||
$components[] = ['type' => 'name', 'value' => $street2];
|
{
|
||||||
|
$components[] = ['type' => 'separator', 'value' => "\n"];
|
||||||
|
}
|
||||||
|
if (!empty($street))
|
||||||
|
{
|
||||||
|
$components[] = ['type' => 'name', 'value' => $street];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return $components;
|
return $components;
|
||||||
}
|
}
|
||||||
@ -968,7 +960,7 @@ class JsContact
|
|||||||
$vCard->setAttribute('UID',$list['list_uid']);
|
$vCard->setAttribute('UID',$list['list_uid']);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
return json_encode($group, self::JSON_OPTIONS);
|
return Api\CalDAV::json_encode($group);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
Reference in New Issue
Block a user