gdoo/app/Gdoo/Calendar/Sabre/Connector/Share/CalDAV.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();
}
}