mirror of
https://github.com/EGroupware/egroupware.git
synced 2024-12-26 16:48:49 +01:00
* Calendar/REST API: adding of participants to events
This commit is contained in:
parent
19552059b3
commit
b6a0e650fe
@ -95,7 +95,7 @@ class JsCalendar
|
|||||||
* @param string $method='PUT' 'PUT', 'POST' or 'PATCH'
|
* @param string $method='PUT' 'PUT', 'POST' or 'PATCH'
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public static function parseJsEvent(string $json, array $old=[], string $content_type=null, $method='PUT')
|
public static function parseJsEvent(string $json, array $old=[], string $content_type=null, $method='PUT', int $calendar_owner=null)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -147,7 +147,7 @@ class JsCalendar
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 'participants':
|
case 'participants':
|
||||||
$event['participants'] = self::parseParticipants($value);
|
$event['participants'] = self::parseParticipants($value, $strict, $calendar_owner);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'priority':
|
case 'priority':
|
||||||
@ -537,21 +537,22 @@ class JsCalendar
|
|||||||
|
|
||||||
const TYPE_PARTICIPANT = 'Participant';
|
const TYPE_PARTICIPANT = 'Participant';
|
||||||
|
|
||||||
|
static $status2jscal = [
|
||||||
|
'U' => 'needs-action',
|
||||||
|
'A' => 'accepted',
|
||||||
|
'R' => 'declined',
|
||||||
|
'T' => 'tentative',
|
||||||
|
//'' => 'delegated',
|
||||||
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return participants object
|
* Return participants object
|
||||||
*
|
*
|
||||||
* @param array $event
|
* @param array $event
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
* @todo Resources and Groups without email */
|
||||||
protected static function Participants(array $event)
|
protected static function Participants(array $event)
|
||||||
{
|
{
|
||||||
static $status2jscal = [
|
|
||||||
'U' => 'needs-action',
|
|
||||||
'A' => 'accepted',
|
|
||||||
'R' => 'declined',
|
|
||||||
'T' => 'tentative',
|
|
||||||
//'' => 'delegated',
|
|
||||||
];
|
|
||||||
$participants = [];
|
$participants = [];
|
||||||
foreach($event['participants'] as $uid => $status)
|
foreach($event['participants'] as $uid => $status)
|
||||||
{
|
{
|
||||||
@ -589,7 +590,7 @@ class JsCalendar
|
|||||||
'optional' => $role === 'OPT-PARTICIPANT',
|
'optional' => $role === 'OPT-PARTICIPANT',
|
||||||
'informational' => $role === 'NON-PARTICIPANT',
|
'informational' => $role === 'NON-PARTICIPANT',
|
||||||
]),
|
]),
|
||||||
'participationStatus' => $status2jscal[$status],
|
'participationStatus' => self::$status2jscal[$status],
|
||||||
]);
|
]);
|
||||||
$participants[$uid] = $participant;
|
$participants[$uid] = $participant;
|
||||||
}
|
}
|
||||||
@ -597,6 +598,101 @@ class JsCalendar
|
|||||||
return $participants;
|
return $participants;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse participants object
|
||||||
|
*
|
||||||
|
* @param array $participants
|
||||||
|
* @param bool $strict true: require @types and objects with attributes name, email, ...
|
||||||
|
* @param ?int $calendar_owner owner of the calendar / collection
|
||||||
|
* @return array
|
||||||
|
* @todo Resources and Groups without email
|
||||||
|
*/
|
||||||
|
protected static function parseParticipants(array $participants, bool $strict=true, int $calendar_owner=null)
|
||||||
|
{
|
||||||
|
$parsed = [];
|
||||||
|
|
||||||
|
foreach($participants as $uid => $participant)
|
||||||
|
{
|
||||||
|
if ($strict && (!is_array($participant) || $participant[self::AT_TYPE] !== self::TYPE_PARTICIPANT))
|
||||||
|
{
|
||||||
|
throw new \InvalidArgumentException("Missing or invalid @type: ".json_encode($participant, self::JSON_OPTIONS_ERROR));
|
||||||
|
}
|
||||||
|
elseif (!is_array($participant))
|
||||||
|
{
|
||||||
|
$participant = [
|
||||||
|
'email' => $participant,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
// check if the uid is valid and matches the data in the object
|
||||||
|
if (($test_uid = self::Participants(['participants' => [
|
||||||
|
$uid => 'U'
|
||||||
|
]])) && ($test_uid['email'] ?? null) === $participant['email'] &&
|
||||||
|
($test_uid['kind'] ?? null) === ($participant['kind'] ?? null) &&
|
||||||
|
($test_uid['name'] ?? null) === ($participant['name'] ?? null))
|
||||||
|
{
|
||||||
|
// use $uid as is
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (empty($participant['email']) || !preg_match(Api\Etemplate\Widget\Url::EMAIL_PREG, $participant['email']))
|
||||||
|
{
|
||||||
|
throw new \InvalidArgumentException("Missing or invalid email address: ".json_encode($participant, self::JSON_OPTIONS_ERROR));
|
||||||
|
}
|
||||||
|
static $contacts = null;
|
||||||
|
if (!isset($contacts)) $contacts = new Api\Contacts();
|
||||||
|
if ((list($data) = $contacts->search([
|
||||||
|
'email' => $participant['email'],
|
||||||
|
'email_home' => $participant['email'],
|
||||||
|
], ['id','egw_addressbook.account_id as account_id','n_fn'],
|
||||||
|
'egw_addressbook.account_id IS NOT NULL DESC, n_fn IS NOT NULL DESC',
|
||||||
|
'','',false,'OR')))
|
||||||
|
{
|
||||||
|
// found an addressbook entry
|
||||||
|
$uid = $data['account_id'] ? (int)$data['account_id'] : 'c'.$data['id'];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$uid = 'e'.(empty($participant['name']) ? $participant['email'] : $participant['name'].' <'.$participant['email'].'>');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$default_status = $uid === $GLOBALS['egw_info']['user']['account_id'] ? 'A' : 'U';
|
||||||
|
$default_role = $uid === $calendar_owner ? 'CHAIR' : 'REQ-PARTICIPANT';
|
||||||
|
$parsed[$uid] = \calendar_so::combine_status(array_search($participant['participationStatus'] ?? $default_status, self::$status2jscal) ?: $default_status,
|
||||||
|
1, self::jscalRoles2role($participant['roles'] ?? null, $default_role));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $parsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static function jscalRoles2role(array $roles=null, string $default_role=null)
|
||||||
|
{
|
||||||
|
$role = $default_role ?? 'REQ-PARTICIPANT';
|
||||||
|
foreach($roles ?? [] as $name => $value)
|
||||||
|
{
|
||||||
|
if ($value && $role !== 'CHAIR')
|
||||||
|
{
|
||||||
|
switch($name)
|
||||||
|
{
|
||||||
|
case 'owner': // we ignore the owner, it's set automatic to the owner of the calendar/collection
|
||||||
|
break;
|
||||||
|
case 'attendee':
|
||||||
|
$role = 'REQ-PARTICIPANT';
|
||||||
|
break;
|
||||||
|
case 'optional':
|
||||||
|
$role = 'OPT-PARTICIPANT';
|
||||||
|
break;
|
||||||
|
case 'informational':
|
||||||
|
$role = 'NON-PARTICIPANT';
|
||||||
|
break;
|
||||||
|
case 'chair':
|
||||||
|
$role = 'CHAIR';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $role;
|
||||||
|
}
|
||||||
|
|
||||||
const TYPE_LOCATION = 'Location';
|
const TYPE_LOCATION = 'Location';
|
||||||
const TYPE_VIRTALLOCATION = 'VirtualLocation';
|
const TYPE_VIRTALLOCATION = 'VirtualLocation';
|
||||||
|
|
||||||
|
@ -1227,7 +1227,7 @@ class calendar_groupdav extends Api\CalDAV\Handler
|
|||||||
$type = null;
|
$type = null;
|
||||||
if (($is_json=Api\CalDAV::isJSON($type)))
|
if (($is_json=Api\CalDAV::isJSON($type)))
|
||||||
{
|
{
|
||||||
$event = Api\CalDAV\JsCalendar::parseJsEvent($options['content'], $oldEvent ?? [], $type, $method);
|
$event = Api\CalDAV\JsCalendar::parseJsEvent($options['content'], $oldEvent ?? [], $type, $method, $user);
|
||||||
$cal_id = $this->bo->save($event);
|
$cal_id = $this->bo->save($event);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -202,7 +202,7 @@ curl https://example.org/egroupware/groupdav.php/<username>/calendar/ -H "Accept
|
|||||||
|
|
||||||
following GET parameters are supported to customize the returned properties:
|
following GET parameters are supported to customize the returned properties:
|
||||||
- props[]=<DAV-prop-name> eg. props[]=getetag to return only the ETAG (multiple DAV properties can be specified)
|
- props[]=<DAV-prop-name> eg. props[]=getetag to return only the ETAG (multiple DAV properties can be specified)
|
||||||
Default for addressbook collections is to only return address-data (JsContact), other collections return all props.
|
Default for calendar collections is to only return calendar-data (JsEvent), other collections return all props.
|
||||||
- sync-token=<token> to only request change since last sync-token, like rfc6578 sync-collection REPORT
|
- sync-token=<token> to only request change since last sync-token, like rfc6578 sync-collection REPORT
|
||||||
- nresults=N limit number of responses (only for sync-collection / given sync-token parameter!)
|
- nresults=N limit number of responses (only for sync-collection / given sync-token parameter!)
|
||||||
this will return a "more-results"=true attribute and a new "sync-token" attribute to query for the next chunk
|
this will return a "more-results"=true attribute and a new "sync-token" attribute to query for the next chunk
|
||||||
@ -215,7 +215,7 @@ Examples: see addressbook
|
|||||||
<summary>Example: GET request for a single resource</summary>
|
<summary>Example: GET request for a single resource</summary>
|
||||||
|
|
||||||
```
|
```
|
||||||
curl 'https://example.org/egroupware/groupdav.php/addressbook/6502' -H "Accept: application/pretty+json" --user <username>
|
curl 'https://example.org/egroupware/groupdav.php/calendar/6502' -H "Accept: application/pretty+json" --user <username>
|
||||||
{
|
{
|
||||||
"@type": "Event",
|
"@type": "Event",
|
||||||
"prodId": "EGroupware Calendar 23.1.002",
|
"prodId": "EGroupware Calendar 23.1.002",
|
||||||
|
Loading…
Reference in New Issue
Block a user