Page MenuHomePhabricator

No OneTemporary

diff --git a/action/ajax.php b/action/ajax.php
--- a/action/ajax.php
+++ b/action/ajax.php
@@ -1,123 +1,199 @@
<?php
/**
* DokuWiki DAVCard PlugIn - Ajax component
*/
if(!defined('DOKU_INC')) die();
class action_plugin_davcard_ajax extends DokuWiki_Action_Plugin {
/**
* @var helper_plugin_davcard
*/
private $hlp = null;
function __construct() {
$this->hlp =& plugin_load('helper','davcard');
}
function register(Doku_Event_Handler $controller) {
$controller->register_hook('AJAX_CALL_UNKNOWN', 'BEFORE', $this, 'handle_ajax_call_unknown');
}
function handle_ajax_call_unknown(&$event, $param) {
if($event->data != 'plugin_davcard') return;
$event->preventDefault();
$event->stopPropagation();
global $INPUT;
$action = trim($INPUT->post->str('action'));
$id = trim($INPUT->post->str('id'));
$page = trim($INPUT->post->str('page'));
$params = $INPUT->post->arr('params');
if(isset($_SERVER['REMOTE_USER']) && !is_null($_SERVER['REMOTE_USER']))
$user = $_SERVER['REMOTE_USER'];
else
$user = null;
if(!checkSecurityToken())
{
echo "CSRF Attack.";
return;
}
$data = array();
$data['result'] = false;
$data['html'] = $this->getLang('unknown_error');
// Parse the requested action
switch($action)
{
// Add a new Contact
case 'newContact':
if($this->hlp->addContactEntryToAddressbookForPage($id, $user, $params) === true)
{
$data['result'] = true;
}
else
{
$data['result'] = false;
$data['html'] = $this->getLang('error_adding');
}
break;
// Edit a contact
case 'editContact':
break;
// Delete a Contact
case 'deleteContact':
break;
// Get AJAX popup
case 'getContactAjax':
$contactdata = $this->hlp->getContactByUri($id, $params['uri']);
+ $cardpattern = $this->getConf('popup_content');
+ echo '<div class="plugin_davcard_popup_container">';
foreach($contactdata['photo'] as $type => $photodata)
{
+ echo '<div class="plugin_davcard_popup_image">';
$type = strtolower($type);
$imgdata = base64_encode($photodata);
$pattern = '/^(?:[;\/?:@&=+$,]|(?:[^\W_]|[-_.!~*\()\[\] ])|(?:%[\da-fA-F]{2}))*$/';
// PNG images
if($type == 'png')
{
$imgdata = 'data:image/png;base64,'.$imgdata;
echo '<img src="'.$imgdata.'" alt="contact image" />';
}
// JPEG images
elseif(($type == 'jpeg') || ($type == 'jpg'))
{
$imgdata = 'data:image/jpeg;base64,'.$imgdata;
echo '<img src="'.$imgdata.'" alt="contact image" />';
}
// GIF images
elseif($type == 'gif')
{
$imgdata = 'data:image/gif;base64,'.$imgdata;
echo '<img src="'.$imgdata.'" alt="contact image" />';
}
// URLs (no type given)
elseif(preg_match( $pattern, $string ) == 1)
{
echo '<img src="'.$photodata.'" alt="contact image" />';
}
+ echo '</div>';
}
+ echo '<div class="plugin_davcard_popup_content">';
+ $contactname = explode(';', $contactdata['structuredname']);
+ if(count($contactname) > 1)
+ {
+ $cardpattern = str_replace('<DCLASTNAME>', $contactname[0], $cardpattern);
+ $cardpattern = str_replace('<DCFIRSTNAME>', $contactname[1], $cardpattern);
+ }
+ if(count($contactdata['addr']) > 0)
+ {
+ foreach($contactdata['addr'] as $type => $addr)
+ {
+ $type = strtolower($type);
+ if($type == 'work')
+ $prefix = 'WORK';
+ else
+ $prefix = 'PRIVATE';
+ $cardpattern = str_replace('<DC'.$prefix.'STREET>', $addr[2], $cardpattern);
+ $cardpattern = str_replace('<DC'.$prefix.'CITY>', $addr[3], $cardpattern);
+ $cardpattern = str_replace('<DC'.$prefix.'ZIP>', $addr[5], $cardpattern);
+ $cardpattern = str_replace('<DC'.$prefix.'COUNTRY>', $addr[6], $cardpattern);
+ }
+ }
+ if(count($contactdata['tel']) > 0)
+ {
+ $telArr = array();
+ foreach($contactdata['tel'] as $type => $tel)
+ {
+ $type = strtolower($type);
+ $telArr[] = $this->getLang('tel'.strtolower($type)).': '.$tel;
+ }
+ $telStr = implode(' \\\\ ', $telArr);
+ $cardpattern = str_replace('<DCPHONE>', $telStr, $cardpattern);
+ }
+ if(count($contactdata['mail']) > 0)
+ {
+ $mailArr = array();
+ foreach($contactdata['mail'] as $type => $mail)
+ {
+ $mailArr[] = '[['.$mail.']]';
+ }
+ $mailStr = implode(' \\\\ ', $mailArr);
+ $cardpattern = str_replace('<DCEMAIL>', $mailStr, $cardpattern);
+ }
+ if($contactdata['birthday'] != '')
+ {
+ $date = DateTime::createFromFormat('Ymd', $contactdata['birthday']);
+ $dateStr = $date->format($this->getConf('date_format'));
+ $cardpattern = str_replace('<DCBIRTHDAY>', $dateStr, $cardpattern);
+ }
+ if($contactdata['note'] != '')
+ {
+ $notestr = str_replace('\n', ' \\ ', $contactdata['note']);
+ $cardpattern = str_replace('<DCNOTE>', $notestr, $cardpattern);
+ }
+ if($contactdata['title'] != '')
+ {
+ $cardpattern = str_replace('<DCTITLE>', $contactdata['title'], $cardpattern);
+ }
+ if($contactdata['url'] != '')
+ {
+ $url = $contactdata['url'];
+ if(strpos($url, '://') === false)
+ $url = 'http://'.$url;
+ $url = '[['.$url.']]';
+ $cardpattern = str_replace('<DCWEBSITE>', $url, $cardpattern);
+ }
+
+ $replace_match = '/^.*<DC.*>.*$(?:\r\n|\n)?/m';
+ $cardpattern = preg_replace($replace_match, '', $cardpattern);
+ echo $this->render_text($cardpattern);
+ echo '</div>';
+ echo '</div>';
return;
break;
}
// If we are still here, JSON output is requested
//json library of DokuWiki
require_once DOKU_INC . 'inc/JSON.php';
$json = new JSON();
//set content type
header('Content-Type: application/json');
echo $json->encode($data);
}
}
diff --git a/conf/default.php b/conf/default.php
--- a/conf/default.php
+++ b/conf/default.php
@@ -1,8 +1,18 @@
<?php
/**
* Default settings for the davcard plugin
*
* @author Andreas Boehler <dev@aboehler.at>
*/
$conf['default_client_id'] = '';
+$conf['popup_content'] = '| **Name** | <DCFIRSTNAME> <DCLASTNAME> |
+| **Title** | <DCTITLE> |
+| **Address (Work)** | <DCWORKSTREET> \\\\ <DCWORKZIP> <DCWORKCITY> |
+| **Address (Private)** | <DCPRIVATESTREET> \\\\ <DCPRIVATEZIP> <DCPRIVATECITY> |
+| **Phone** | <DCPHONE> |
+| **E-Mail** | <DCEMAIL> |
+| **Website** | <DCWEBSITE> |
+| **Birthday** | <DCBIRTHDAY> |
+| **Note** | <DCNOTE>';
+$conf['date_format'] = 'Y-m-d';
diff --git a/conf/metadata.php b/conf/metadata.php
--- a/conf/metadata.php
+++ b/conf/metadata.php
@@ -1,8 +1,10 @@
<?php
/**
* Options for the davcard plugin
*
* @author Andreas Boehler <dev@aboehler.at>
*/
$meta['default_client_id'] = array('string');
+$meta['popup_content'] = array('');
+$meta['date_format'] = array('string');
diff --git a/helper.php b/helper.php
--- a/helper.php
+++ b/helper.php
@@ -1,423 +1,452 @@
<?php
/**
* Helper Class for the DAVCard plugin
* This helper does the actual work.
*
*/
// must be run within Dokuwiki
if(!defined('DOKU_INC')) die();
class helper_plugin_davcard extends DokuWiki_Plugin {
protected $sqlite = null;
/**
* Constructor to load the configuration
*/
public function helper_plugin_davcard() {
$this->sqlite =& plugin_load('helper', 'sqlite');
global $conf;
if(!$this->sqlite)
{
if($conf['allowdebug'])
dbglog('This plugin requires the sqlite plugin. Please install it.');
msg('This plugin requires the sqlite plugin. Please install it.');
return;
}
if(!$this->sqlite->init('davcard', DOKU_PLUGIN.'davcard/db/'))
{
if($conf['allowdebug'])
dbglog('Error initialising the SQLite DB for DAVCard');
return;
}
}
private function getContactByDetails($id, $type, $params = array())
{
if(strpos($id, 'webdav://') === 0)
{
$wdc =& plugin_load('helper', 'webdavclient');
if(is_null($wdc))
return $this->getLang('no_wdc');
$connectionId = str_replace('webdav://', '', $id);
$settings = $wdc->getConnection($connectionId);
if($settings === false)
return array('formattedname' => $this->getLang('settings_not_found'));
if($settings['type'] !== 'contacts')
return array('formattedname' => $this->getLang('wrong_type'));
$entries = $wdc->getAddressbookEntries($connectionId);
foreach($entries as $entry)
{
switch($type)
{
case 'structuredname':
$contactdata = explode(';', strtolower($entry['structuredname']));
if(count($contactdata) < 2) // We need at least first and lat name
return array('formattedname' => $this->getLang('contact_not_found'));
if(($params['lastname'] != '') &&
($contactdata[0] === $params['lastname'])
|| $params['lastname'] === '')
{
// last name matched or no last name given
if(($params['firstname'] != '') &&
($contactdata[1] === $params['firstname'])
|| $params['firstname'] === '')
{
// first name matched too or no first name given
$info = $this->parseVcard($entry['contactdata'], $entry['uri']);
return $info;
}
}
break;
case 'formattedname':
if(trim(strtolower($entry['formattedname'])) == $params['formattedname'])
{
$info = $this->parseVcard($entry['contactdata'], $entry['uri']);
return $info;
}
break;
case 'email':
$info = $this->parseVcard($entry['contactdata'], $entry['uri']);
foreach($info['mail'] as $key => $mail)
{
if($mail === strtolower($params['email']))
return $info;
}
break;
}
}
}
return array('formattedname' => $this->getLang('contact_not_found'));
}
public function getContactByStructuredName($id, $firstname = '', $lastname = '')
{
return $this->getContactByDetails($id, 'structuredname',
array('firstname' => strtolower($firstname), 'lastname' => strtolower($lastname)));
}
public function getContactByEmail($id, $email)
{
// FIXME: Maybe it's a good idea to save the e-mail in the database as well!
return $this->getContactByDetails($id, 'email', array('email' => strtolower($email)));
}
public function getContactByFormattedName($id, $name)
{
return $this->getContactByDetails($id, 'formattedname', array('formattedname' => strtolower($name)));
}
public function getContactByUri($id, $uri)
{
if(strpos($id, 'webdav://') === 0)
{
$wdc =& plugin_load('helper', 'webdavclient');
if(is_null($wdc))
return $this->getLang('no_wdc');
$connectionId = str_replace('webdav://', '', $id);
$settings = $wdc->getConnection($connectionId);
if($settings === false)
return array('formattedname' => $this->getLang('settings_not_found'));
if($settings['type'] !== 'contacts')
return array('formattedname' => $this->getLang('wrong_type'));
$row = $wdc->getAddressbookEntryByUri($connectionId, $uri);
if($row === false)
return array('formattedname' => $this->getLang('contact_not_found'));
$info = $this->parseVcard($row['contactdata'], $row['uri']);
return $info;
}
return array('formattedname' => $this->getLang('contact_not_found'));
}
public function setAddressbookNameForPage($name, $description, $id = null, $userid = null)
{
if(is_null($id))
{
global $ID;
$id = $ID;
}
if(is_null($userid))
{
if(isset($_SERVER['REMOTE_USER']) && !is_null($_SERVER['REMOTE_USER']))
{
$userid = $_SERVER['REMOTE_USER'];
}
else
{
$userid = uniqid('davcard-');
}
}
$bookid = $this->getAddressbookIdForPage($id);
if($bookid === false)
return $this->createAddressbookForPage($name, $description, $id, $userid);
$query = "UPDATE addressbooks SET displayname = ?, description = ? WHERE id = ?";
$res = $this->sqlite->query($query, $name, $description, $bookid);
if($res !== false)
return true;
return false;
}
public function getAddressbookIdForPage($id = null)
{
if(is_null($id))
{
global $ID;
$id = $ID;
}
$query = "SELECT addressbookid FROM pagetoaddressbookmapping WHERE page = ?";
$res = $this->sqlite->query($query, $id);
$row = $this->sqlite->res2row($res);
if(isset($row['addressbookid']))
{
$calid = $row['addressbookid'];
return $calid;
}
return false;
}
public function createAddressbookForPage($name, $description, $id = null, $userid = null)
{
if(is_null($id))
{
global $ID;
$id = $ID;
}
if(is_null($userid))
{
if(isset($_SERVER['REMOTE_USER']) && !is_null($_SERVER['REMOTE_USER']))
{
$userid = $_SERVER['REMOTE_USER'];
}
else
{
$userid = uniqid('davcard-');
}
}
$values = array('principals/'.$userid,
$name,
str_replace(array('/', ' ', ':'), '_', $id),
$description,
1);
$query = "INSERT INTO addressbooks (principaluri, displayname, uri, description, synctoken) ".
"VALUES (?, ?, ?, ?, ?)";
$res = $this->sqlite->query($query, $values);
if($res === false)
return false;
// Get the new addressbook ID
$query = "SELECT id FROM addressbooks WHERE principaluri = ? AND displayname = ? AND ".
"uri = ? AND description = ? AND synctoken = ?";
$res = $this->sqlite->query($query, $values);
$row = $this->sqlite->res2row($res);
// Update the pagetocalendarmapping table with the new calendar ID
if(isset($row['id']))
{
$query = "INSERT INTO pagetoaddressbookmapping (page, addressbookid) VALUES (?, ?)";
$res = $this->sqlite->query($query, $id, $row['id']);
return ($res !== false);
}
return false;
}
public function addContactEntryToAddressbookForPage($id, $user, $params)
{
require_once(DOKU_PLUGIN.'davcard/vendor/autoload.php');
$vcard = new \Sabre\VObject\Component\VCard();
$formattedname = $params['firstname'].' '.$params['lastname']; // FIXME: Make this configurable?
$structuredname = array($params['lastname'], $params['firstname'], '', '', '');
$vcard->FN = $formattedname;
if($params['cellphone'] != '')
{
$vcard->add('TEL', $params['cellphone'], array('type' => 'cell'));
}
if($params['phone'] != '')
{
$vcard->add('TEL', $params['phone'], array('type' => 'home'));
}
$vcard->N = $structuredname;
$vcard->add('ADR', array('', '', $params['street'], $params['city'], '', $params['zipcode'], $params['country']), array('type' => 'home'));
$contactdata = $vcard->serialize();
if(strpos($id, 'webdav://') === 0)
{
$wdc =& plugin_load('helper', 'webdavclient');
if(is_null($wdc))
return false;
$connectionId = str_replace('webdav://', '', $id);
return $wdc->addAddressbookEntry($connectionId, $contactdata);
}
else
{
$addressbookid = $this->getAddressbookIdForPage($id);
$uri = uniqid('dokuwiki-').'.vcf';
$now = new \DateTime();
$query = "INSERT INTO addressbookobjects (contactdata, uri, addressbookid, lastmodified, etag, size, formattedname, structuredname) VALUES (?, ?, ?, ?, ?, ?, ?, ?)";
$res = $this->sqlite->query($query,
$contactdata,
$uri,
$addressbookid,
$now->getTimestamp(),
md5($contactdata),
strlen($contactdata),
$formattedname,
implode(';', $structuredname)
);
// If successfully, update the sync token database
if($res !== false)
{
$this->updateSyncTokenLog($addressbookid, $uri, 'added');
return true;
}
}
}
private function parseVcard($card, $uri)
{
require_once(DOKU_PLUGIN.'davcard/vendor/autoload.php');
$vObject = \Sabre\VObject\Reader::read($card);
$formattedname = '';
$structuredname = '';
$tel = array();
$addr = array();
$mail = array();
$photo = array();
+ $birthday = '';
+ $note = '';
+ $title = '';
+ $url = '';
if(isset($vObject->FN))
$formattedname = (string)$vObject->FN;
if(isset($vObject->N))
$structuredname = join(';', $vObject->N->getParts());
if(isset($vObject->TEL))
{
foreach($vObject->TEL as $number)
{
if(isset($number['TYPE']))
$tel[(string)$number['TYPE']] = (string)$number;
else
$tel[] = (string)$number;
}
}
if(isset($vObject->ADR))
{
foreach($vObject->ADR as $adr)
{
if(isset($adr['TYPE']))
$addr[(string)$adr['TYPE']] = $adr->getParts();
else
$addr[] = $adr->getParts();
}
}
if(isset($vObject->EMAIL))
{
foreach($vObject->EMAIL as $email)
{
if(isset($email['TYPE']))
$mail[(string)$email['TYPE']] = (string)$email;
else
$mail[] = (string)$email;
}
}
if(isset($vObject->PHOTO))
{
if(isset($vObject->PHOTO['TYPE']))
{
$photo[(string)$vObject->PHOTO['TYPE']] = (string)$vObject->PHOTO;
}
else
$photo[] = (string)$vObject->PHOTO;
}
+ if(isset($vObject->BDAY))
+ {
+ $birthday = (string)$vObject->BDAY;
+ $birthday = str_replace('-', '', $birthday);
+ }
+
+ if(isset($vObject->NOTE))
+ {
+ $note = (string)$vObject->NOTE;
+ }
+
+ if(isset($vObject->TITLE))
+ {
+ $title = (string)$vObject->TITLE;
+ }
+
+ if(isset($vObject->URL))
+ {
+ $url = (string)$vObject->URL;
+ }
+
return array(
'formattedname' => $formattedname,
'structuredname' => $structuredname,
'tel' => $tel,
'mail' => $mail,
'addr' => $addr,
'uri' => $uri,
- 'photo' => $photo
+ 'photo' => $photo,
+ 'birthday' => $birthday,
+ 'note' => $note,
+ 'title' => $title,
+ 'url' => $url,
);
}
public function getAddressbookSettings($addressbookid)
{
$query = "SELECT id, principaluri, displayname, uri, description, synctoken FROM addressbooks WHERE id= ? ";
$res = $this->sqlite->query($query, $addressbookid);
$row = $this->sqlite->res2row($res);
return $row;
}
public function getSyncTokenForAddressbook($addressbookid)
{
$row = $this->getAddressbookSettings($addressbookid);
if(isset($row['synctoken']))
return $row['synctoken'];
return false;
}
/**
* Helper function to convert the operation name to
* an operation code as stored in the database
*
* @param string $operationName The operation name
*
* @return mixed The operation code or false
*/
public function operationNameToOperation($operationName)
{
switch($operationName)
{
case 'added':
return 1;
break;
case 'modified':
return 2;
break;
case 'deleted':
return 3;
break;
}
return false;
}
private function updateSyncTokenLog($addressbookid, $uri, $operation)
{
$currentToken = $this->getSyncTokenForAddressbook($addressbookid);
$operationCode = $this->operationNameToOperation($operation);
if(($operationCode === false) || ($currentToken === false))
return false;
$values = array($uri,
$currentToken,
$addressbookid,
$operationCode
);
$query = "INSERT INTO addressbookchanges (uri, synctoken, addressbookid, operation) VALUES(?, ?, ?, ?)";
$res = $this->sqlite->query($query, $uri, $currentToken, $addressbookid, $operationCode);
if($res === false)
return false;
$currentToken++;
$query = "UPDATE addressbooks SET synctoken = ? WHERE id = ?";
$res = $this->sqlite->query($query, $currentToken, $addressbookid);
return ($res !== false);
}
}
diff --git a/style.css b/style.css
--- a/style.css
+++ b/style.css
@@ -1,82 +1,104 @@
div.dokuwiki a.plugin_davcard_url:link,
div.dokuwiki a.plugin_davcard_url:active,
div.dokuwiki a.plugin_davcard_url:hover,
div.dokuwiki a.plugin_davcard_url:visited {
position: relative;
padding-left: 18px;
z-index: 10;
}
div.dokuwiki a.plugin_davcard_url:link span.plugin_davcard_popup,
div.dokuwiki a.plugin_davcard_url:active span.plugin_davcard_popup,
div.dokuwiki a.plugin_davcard_url:visited span.plugin_davcard_popup {
display: none;
}
div.dokuwiki a.plugin_davcard_url:hover {
text-decoration: none !important;
z-index: 15;
}
div.dokuwiki a.plugin_davcard_url:hover span.plugin_davcard_popup {
display: block;
position: absolute;
top: 1.2em;
left: 18px;
width: 20em;
height: 64px;
min-height: 64px;
height: auto;
background-color: __background__;
border: 1px solid __border__;
padding: 0.5em;
font-size: 90%;
}
div.dokuwiki a.plugin_davcard_url span.plugin_davcard_nopopup {
display:none;
}
div.dokuwiki a.plugin_davcard_url:hover span.plugin_davcard_popup span.adr,
div.dokuwiki a.plugin_davcard_url:hover span.plugin_davcard_popup span.tel,
div.dokuwiki a.plugin_davcard_url:hover span.plugin_davcard_popup span.email_outer,
{
display:block;
position: relative;
margin-left: 45px;
}
div.dokuwiki a.plugin_davcard_url:hover span.plugin_davcard_popup span.adr span.type,
div.dokuwiki a.plugin_davcard_url:hover span.plugin_davcard_popup span.tel span.type,
div.dokuwiki a.plugin_davcard_url:hover span.plugin_davcard_popup span.email_type,
{
font-weight: bold;
margin-left: -45px;
position: absolute;
}
div.dokuwiki .plugin_davcard_popup_overlay {
position: absolute;
padding: 0.5em;
margin-top: 1em;
}
div.dokuwiki .plugin_davcard_popup_overlay ul {
margin: 0;
list-style-type: none;
}
div.dokuwiki .plugin_davcard_popup_overlay ul li {
margin-left: 2em;
}
div.dokuwiki .plugin_davcard_popup_overlay ul li.dataov_name {
margin-left: 0;
margin-bottom: 0.3em;
}
div.dokuwiki .plugin_davcard_popup_overlay ul li.dataov_name div {
font-weight: bold;
}
+div.dokuwiki .plugin_davcard_popup_overlay img {
+ max-width: 100px;
+ height: auto;
+}
+
+div.dokuwiki .plugin_davcard_popup_overlay .plugin_davcard_popup_container {
+
+}
+
+div.dokuwiki .plugin_davcard_popup_overlay .plugin_davcard_popup_image {
+ float: left;
+}
+
+div.dokuwiki .plugin_davcard_popup_overlay .plugin_davcard_popup_content {
+ float: right;
+}
+
+div.dokuwiki .plugin_davcard_popup_overlay .plugin_davcard_popup_container::after {
+ content:"";
+ display:block;
+ clear:both;
+}
\ No newline at end of file

File Metadata

Mime Type
text/x-diff
Expires
Sat, Nov 23, 4:37 AM (4 h, 41 m ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
529879
Default Alt Text
(26 KB)

Event Timeline