397 lines
16 KiB
PHP
397 lines
16 KiB
PHP
<?php namespace Gdoo\Calendar\Sabre\Connector\Share;
|
|
|
|
use Gdoo\Calendar\Sabre\Connector;
|
|
|
|
use Auth;
|
|
|
|
use Gdoo\Calendar\Models\Calendar;
|
|
use Gdoo\Index\Services\ShareService;
|
|
use Gdoo\Calendar\Services\CalendarService;
|
|
|
|
class CalDAV extends Connector\CalDAV implements \Sabre\CalDAV\Backend\SharingSupport
|
|
{
|
|
/**
|
|
* List of properties for the calendar shares table
|
|
* This list maps exactly to the field names in the db table
|
|
*/
|
|
public $sharesProperties = array(
|
|
'calendarId',
|
|
'member',
|
|
'status',
|
|
'readOnly',
|
|
'summary',
|
|
//'displayName',
|
|
//'colour'
|
|
);
|
|
|
|
public $sharedEvents = array(
|
|
'displayname' => '共享事件',
|
|
'color' => '#999999',
|
|
);
|
|
|
|
/**
|
|
* Updates the list of shares.
|
|
*
|
|
* The first array is a list of people that are to be added to the
|
|
* calendar.
|
|
*
|
|
* 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.
|
|
*
|
|
* Note that if the calendar is currently marked as 'not shared' by and
|
|
* this method is called, the calendar should be 'upgraded' to a shared
|
|
* calendar.
|
|
*
|
|
* @param mixed $calendarId
|
|
* @param array $add
|
|
* @param array $remove
|
|
* @return void
|
|
*/
|
|
public function updateShares($calendarId, array $add, array $remove)
|
|
{
|
|
$fields = array();
|
|
$fields[':calendarId'] = $calendarId;
|
|
// get the principal based on the supplied email address
|
|
$principal = $this->getPrincipalByEmail($add[0]['href']);
|
|
$fields[':member'] = $principal['id'];
|
|
$fields[':status'] = \Sabre\CalDAV\SharingPlugin::STATUS_NORESPONSE;
|
|
// check we have all the required fields
|
|
foreach ($this->sharesProperties as $field) {
|
|
if (isset($add[0][$field])) {
|
|
$fields[':'.$field] = $add[0][$field];
|
|
}
|
|
}
|
|
$stmt = $this->pdo->prepare("INSERT INTO ".$this->calendarSharesTableName." (".implode(', ', $this->sharesProperties).") VALUES (".implode(', ', array_keys($fields)).")");
|
|
$stmt->execute($fields);
|
|
|
|
// are we removing any shares?
|
|
if (count($remove)>0) {
|
|
$r_ids = array();
|
|
foreach ($remove as $r_mailto) {
|
|
// get the principalid
|
|
$r_principal = $this->getPrincipalByEmail($r_mailto);
|
|
$r_ids[] = $r_principal['id'];
|
|
}
|
|
$stmt = $this->pdo->prepare("DELETE FROM ".$this->calendarSharesTableName." WHERE MEMBER = ?");
|
|
$stmt->execute($r_ids);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns the list of people whom this calendar 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($calendarId)
|
|
{
|
|
|
|
//$fields = implode(',', $this->sharesProperties);
|
|
//$shareRows = Share::getItemsSourceId('calendar',$calendarId);
|
|
|
|
//print_r($shareRows);
|
|
//$stmt = $this->pdo->prepare("SELECT * FROM ".$this->calendarSharesTableName." AS calendarShares LEFT JOIN ".$this->principalsTableName." AS principals ON calendarShares.member = principals.id WHERE calendarShares.calendarId = ? ORDER BY calendarShares.calendarId ASC");
|
|
//$stmt->execute(array($calendarId));
|
|
|
|
$shareRows = array();
|
|
|
|
$shares = array();
|
|
foreach ($shareRows as $row) {
|
|
//while($row = $stmt->fetch(\PDO::FETCH_ASSOC)) {
|
|
$share = array(
|
|
'calendarId' => $row['calendarId'],
|
|
'principalPath' => $row['uri'],
|
|
'readOnly' => $row['readonly'],
|
|
'summary' => $row['summary'],
|
|
'href' => $row['email'],
|
|
'commonName' => $row['displayname'],
|
|
'displayName' => $row['displayname'],
|
|
'status' => $row['status']
|
|
/*
|
|
'colour'=>$row['colour'],
|
|
'displayName'=>$row['displayName'],
|
|
*/
|
|
);
|
|
// map the status integer to a predefined constant
|
|
/*
|
|
switch($row['status']) {
|
|
case 1:
|
|
$share['status'] = 'STATUS_ACCEPTED';
|
|
break;
|
|
case 2:
|
|
$share['status'] = 'STATUS_DECLINED';
|
|
break;
|
|
case 3:
|
|
$share['status'] = 'STATUS_DELETED';
|
|
break;
|
|
case 4:
|
|
$share['status'] = 'STATUS_NORESPONSE';
|
|
break;
|
|
case 5:
|
|
$share['status'] = 'STATUS_INVALID';
|
|
break;
|
|
}*/
|
|
// add it to main array
|
|
$shares[] = $share;
|
|
}
|
|
return $shares;
|
|
}
|
|
|
|
/**
|
|
* Returns a list of calendars for a principal.
|
|
*
|
|
* Every project is an array with the following keys:
|
|
* * id, a unique id that will be used by other functions to modify the
|
|
* calendar. This can be the same as the uri or a database key.
|
|
* * uri, which the basename of the uri with which the calendar is
|
|
* accessed.
|
|
* * principaluri. The owner of the calendar. Almost always the same as
|
|
* principalUri passed to this method.
|
|
*
|
|
* Furthermore it can contain webdav properties in clark notation. A very
|
|
* common one is '{DAV:}displayname'.
|
|
*
|
|
* MODIFIED: THIS METHOD NOW NEEDS TO BE ABLE TO RETRIEVE SHARED CALENDARS
|
|
*
|
|
* @param string $principalUri
|
|
* @return array
|
|
*/
|
|
public function getCalendarsForUser($principalUri)
|
|
{
|
|
// get the principal id
|
|
$principalBackend = $this->getPrincipalBackend();
|
|
$principal = $principalBackend->getPrincipalByPath($principalUri);
|
|
|
|
$fields = array_values($this->propertyMap);
|
|
$fields[] = 'id';
|
|
$fields[] = 'uri';
|
|
$fields[] = 'ctag';
|
|
$fields[] = 'components';
|
|
$fields[] = 'principaluri';
|
|
$fields[] = 'transparent';
|
|
|
|
$uri = 'principals/'.$principal['id'];
|
|
|
|
// Making fields a comma-delimited list
|
|
$rows = Calendar::where('principaluri', $uri)->get($fields);
|
|
|
|
foreach ($rows as $row) {
|
|
$components = array();
|
|
if ($row->components) {
|
|
$components = explode(',', $row->components);
|
|
}
|
|
$calendar = array(
|
|
'id' => $row->id,
|
|
'uri' => $row->uri,
|
|
'principaluri' => $principalUri,
|
|
'{' . \Sabre\CalDAV\Plugin::NS_CALENDARSERVER . '}getctag' => $row->ctag ? $row->ctag : '0',
|
|
'{' . \Sabre\CalDAV\Plugin::NS_CALDAV . '}supported-calendar-component-set' => new \Sabre\CalDAV\Property\SupportedCalendarComponentSet($components),
|
|
'{' . \Sabre\CalDAV\Plugin::NS_CALDAV . '}schedule-calendar-transp' => new \Sabre\CalDAV\Property\ScheduleCalendarTransp($row->transparent ? 'transparent' : 'opaque'),
|
|
);
|
|
foreach ($this->propertyMap as $xmlName => $dbName) {
|
|
$calendar[$xmlName] = $row[$dbName];
|
|
}
|
|
$calendars[] = $calendar;
|
|
}
|
|
|
|
// now let's get any shared calendars
|
|
$shareFields = implode(', ', $this->sharesProperties);
|
|
$shareRows = ShareService::getItemsSourceBy(['calendar'], $principal['id']);
|
|
|
|
foreach ($shareRows as $shareRow) {
|
|
// get the original calendar
|
|
$calendarShareRow = CalendarService::getCalendar($shareRow['source_id'], false);
|
|
|
|
$shareComponents = array();
|
|
if ($calendarShareRow['components']) {
|
|
$shareComponents = explode(',', $calendarShareRow['components']);
|
|
}
|
|
|
|
$sharedCalendar = array(
|
|
'id' => $calendarShareRow['id'],
|
|
'uri' => $calendarShareRow['uri'],
|
|
'principaluri' => $principalUri,
|
|
'{' . \Sabre\CalDAV\Plugin::NS_CALENDARSERVER . '}getctag' => $calendarShareRow['ctag']?$calendarShareRow['ctag']:'0',
|
|
'{' . \Sabre\CalDAV\Plugin::NS_CALDAV . '}supported-calendar-component-set' => new \Sabre\CalDAV\Property\SupportedCalendarComponentSet($shareComponents),
|
|
'{' . \Sabre\CalDAV\Plugin::NS_CALDAV . '}schedule-calendar-transp' => new \Sabre\CalDAV\Property\ScheduleCalendarTransp($calendarShareRow['transparent']?'transparent':'opaque'),
|
|
);
|
|
|
|
// some specific properies for shared calendars
|
|
$shareRow['displayname'] = '['.$shareRow['name'].']'.$calendarShareRow['displayname'];
|
|
$sharedCalendar['{http://calendarserver.org/ns/}shared-url'] = $calendarShareRow['uri'];
|
|
$sharedCalendar['{http://sabredav.org/ns}owner-principal'] = $calendarShareRow['principaluri'];
|
|
$sharedCalendar['{http://sabredav.org/ns}read-only'] = true;
|
|
$sharedCalendar['{http://calendarserver.org/ns/}summary'] = $shareRow['summary'];
|
|
|
|
foreach ($this->propertyMap as $xmlName => $dbName) {
|
|
if ($xmlName == '{DAV:}displayname') {
|
|
$sharedCalendar[$xmlName] = $shareRow['displayname'] == null ? $calendarShareRow['displayname'] : $shareRow['displayname'];
|
|
} elseif ($xmlName == '{http://apple.com/ns/ical/}calendar-color') {
|
|
$sharedCalendar[$xmlName] = $shareRow['colour'] == null ? $calendarShareRow['calendarcolor'] : $shareRow['color'];
|
|
} else {
|
|
$sharedCalendar[$xmlName] = $calendarShareRow[$dbName];
|
|
}
|
|
}
|
|
$calendars[] = $sharedCalendar;
|
|
}
|
|
|
|
// 获取分享记录
|
|
$shareSource = ShareService::getItemsSourceBy(['event'], Auth::id());
|
|
$sharedEvent = array(
|
|
'id' => 'share-events',
|
|
'uri' => 'share-events',
|
|
'principaluri' => $principalUri,
|
|
'{'.\Sabre\CalDAV\Plugin::NS_CALENDARSERVER.'}getctag' => count($shareSource),
|
|
'{'.\Sabre\CalDAV\Plugin::NS_CALDAV.'}supported-calendar-component-set' => new \Sabre\CalDAV\Property\SupportedCalendarComponentSet(array('VEVENT')),
|
|
'{'.\Sabre\CalDAV\Plugin::NS_CALDAV.'}schedule-calendar-transp' => new \Sabre\CalDAV\Property\ScheduleCalendarTransp('opaque'),
|
|
);
|
|
$sharedEvent['{http://calendarserver.org/ns/}shared-url'] = 'share-events';
|
|
$sharedEvent['{http://sabredav.org/ns}owner-principal'] = 'principals/owner';
|
|
$sharedEvent['{http://sabredav.org/ns}read-only'] = true;
|
|
$sharedEvent['{DAV:}displayname'] = $this->sharedEvents['displayname'];
|
|
$calendars[] = $sharedEvent;
|
|
|
|
return $calendars;
|
|
}
|
|
|
|
/**
|
|
* This method is called when a user replied to a request to share.
|
|
*
|
|
* If the user chose to accept the share, this method should return the
|
|
* newly created calendar url.
|
|
*
|
|
* @param string href The sharee who is replying (often a mailto: address)
|
|
* @param int status One of the SharingPlugin::STATUS_* constants
|
|
* @param string $calendarUri The url to the calendar thats being shared
|
|
* @param string $inReplyTo The unique id this message is a response to
|
|
* @param string $summary A description of the reply
|
|
* @return null|string
|
|
*/
|
|
public function shareReply($href, $status, $calendarUri, $inReplyTo, $summary = null)
|
|
{
|
|
}
|
|
|
|
/**
|
|
* Marks this calendar as published.
|
|
*
|
|
* Publishing a calendar should automatically create a read-only, public,
|
|
* subscribable calendar.
|
|
*
|
|
* @param bool $value
|
|
* @return void
|
|
*/
|
|
public function setPublishStatus($calendarId, $value)
|
|
{
|
|
}
|
|
|
|
/**
|
|
* Returns a list of notifications for a given principal url.
|
|
*
|
|
* The returned array should only consist of implementations of
|
|
* \Sabre\CalDAV\Notifications\INotificationType.
|
|
*
|
|
* @param string $principalUri
|
|
* @return array
|
|
*/
|
|
public function getNotificationsForPrincipal($principalUri)
|
|
{
|
|
// get ALL notifications for the user NB. Any read or out of date notifications should be already deleted.
|
|
$stmt = $this->pdo->prepare("SELECT * FROM ".$this->notificationsTableName." WHERE principaluri = ? ORDER BY dtstamp ASC");
|
|
$stmt->execute(array($principalUri));
|
|
|
|
$notifications = array();
|
|
while ($row = $stmt->fetch(\PDO::FETCH_ASSOC)) {
|
|
// we need to return the correct type of notification
|
|
switch ($row['notification']) {
|
|
case 'Invite':
|
|
$values = array();
|
|
// sort out the required data
|
|
if ($row['id']) {
|
|
$values['id'] = $row['id'];
|
|
}
|
|
if ($row['etag']) {
|
|
$values['etag'] = $row['etag'];
|
|
}
|
|
if ($row['principalUri']) {
|
|
$values['href'] = $row['principalUri'];
|
|
}
|
|
if ($row['dtstamp']) {
|
|
$values['dtstamp'] = $row['dtstamp'];
|
|
}
|
|
if ($row['type']) {
|
|
$values['type'] = $row['type'];
|
|
}
|
|
if ($row['readOnly']) {
|
|
$values['readOnly'] = $row['readOnly'];
|
|
}
|
|
if ($row['hostUrl']) {
|
|
$values['hostUrl'] = $row['hostUrl'];
|
|
}
|
|
if ($row['organizer']) {
|
|
$values['organizer'] = $row['organizer'];
|
|
}
|
|
if ($row['commonName']) {
|
|
$values['commonName'] = $row['commonName'];
|
|
}
|
|
if ($row['firstName']) {
|
|
$values['firstName'] = $row['firstName'];
|
|
}
|
|
if ($row['lastName']) {
|
|
$values['lastName'] = $row['lastName'];
|
|
}
|
|
if ($row['summary']) {
|
|
$values['summary'] = $row['summary'];
|
|
}
|
|
$notifications[] = new \Sabre\CalDAV\Notifications\Notification\Invite($values);
|
|
break;
|
|
|
|
case 'InviteReply':
|
|
break;
|
|
case 'SystemStatus':
|
|
break;
|
|
}
|
|
}
|
|
return $notifications;
|
|
}
|
|
|
|
/**
|
|
* This deletes a specific notifcation.
|
|
*
|
|
* This may be called by a client once it deems a notification handled.
|
|
*
|
|
* @param string $principalUri
|
|
* @param \Sabre\CalDAV\Notifications\INotificationType $notification
|
|
* @return void
|
|
*/
|
|
public function deleteNotification($principalUri, \Sabre\CalDAV\Notifications\INotificationType $notification)
|
|
{
|
|
}
|
|
|
|
private function getPrincipalByEmail($email)
|
|
{
|
|
$principalBackend = $this->getPrincipalBackend();
|
|
$principalPath = $principalBackend->searchPrincipals('principals/users', array('{http://sabredav.org/ns}email-address'=>$email));
|
|
if ($principalPath == 0) {
|
|
throw new \Exception("Unknown email address");
|
|
}
|
|
// use the path to get the principal
|
|
return $principalBackend->getPrincipalByPath($principalPath);
|
|
}
|
|
|
|
private function getPrincipalBackend()
|
|
{
|
|
return new \Gdoo\Calendar\Sabre\Connector\Principal();
|
|
}
|
|
}
|