New app: contacts

This commit is contained in:
Jakob Sack 2011-08-06 22:32:06 +02:00
parent d9ccbe96dd
commit 2f10598af6
14 changed files with 773 additions and 0 deletions

View file

@ -0,0 +1,18 @@
<?php
OC::$CLASSPATH['OC_Contacts_Addressbook'] = 'apps/contacts/lib/addressbook.php';
OC::$CLASSPATH['OC_Connector_Sabre_CardDAV'] = 'apps/contacts/lib/connector_sabre.php';
OC_App::register( array(
'order' => 10,
'id' => 'contacts',
'name' => 'Contacts' ));
OC_App::addNavigationEntry( array(
'id' => 'contacts_index',
'order' => 10,
'href' => OC_Helper::linkTo( 'contacts', 'index.php' ),
'icon' => OC_Helper::imagePath( 'contacts', 'icon.png' ),
'name' => 'Addressbook' ));
?>

View file

@ -0,0 +1,9 @@
<?xml version="1.0"?>
<info>
<id>contacts</id>
<name>Contacts</name>
<version>0.1</version>
<licence>AGPL</licence>
<author>Jakob Sack</author>
<require>2</require>
</info>

28
apps/contacts/carddav.php Normal file
View file

@ -0,0 +1,28 @@
<?php
// Do not load FS ...
$RUNTIME_NOSETUPFS = true;
require_once('../../lib/base.php');
// Backends
$authBackend = new OC_Connector_Sabre_Auth();
$principalBackend = new OC_Connector_Sabre_Principal();
$carddavBackend = new OC_Connector_Sabre_CardDAV();
// Root nodes
$nodes = array(
new Sabre_DAVACL_PrincipalCollection($principalBackend),
new Sabre_CardDAV_AddressBookRoot($principalBackend, $carddavBackend),
);
// Fire up server
$server = new Sabre_DAV_Server($nodes);
$server->setBaseUri($WEBROOT.'/apps/contacts/carddav.php');
// Add plugins
$server->addPlugin(new Sabre_DAV_Auth_Plugin($authBackend,'ownCloud'));
$server->addPlugin(new Sabre_CardDAV_Plugin());
$server->addPlugin(new Sabre_DAVACL_Plugin());
// And off we go!
$server->exec();

View file

@ -0,0 +1 @@

57
apps/contacts/details.php Normal file
View file

@ -0,0 +1,57 @@
<?php
/**
* ownCloud - Addressbook
*
* @author Jakob Sack
* @copyright 2011 Jakob Sack mail@jakobsack.de
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
* License as published by the Free Software Foundation; either
* version 3 of the License, or any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
*
* You should have received a copy of the GNU Affero General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
// Init owncloud
require_once('../../lib/base.php');
$id = $_GET['id'];
$l10n = new OC_L10N('contacts');
// Check if we are a user
if( !OC_User::isLoggedIn()){
echo $l10n->t('You need to log in!');
exit();
}
$card = OC_Contacts_Addressbook::findCard( $id );
if( $card === false ){
echo json_encode( array( 'status' => 'error', 'data' => array( 'message' => $l10n->t('Can not find Contact!'))));
exit();
}
$addressbook = OC_Contacts_Addressbook::findAddressbook( $card['addressbookid'] );
if( $addressbook === false || $addressbook['userid'] != OC_USER::getUser()){
echo json_encode( array( 'status' => 'error', 'data' => array( 'message' => $l10n->t('This is not your contact!'))));
exit();
}
$vcard = Sabre_VObject_Reader::read($card['carddata']);
$details = OC_Contacts_Addressbook::structureContact($vcard);
$tmpl = new OC_Template('contacts','_details');
$tmpl->assign('details',$details);
$tmpl->assign('id',$id);
$page = $tmpl->fetchPage();
echo json_encode( array( 'status' => 'success', 'data' => array( 'page' => $page )));

BIN
apps/contacts/img/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 741 B

68
apps/contacts/index.php Normal file
View file

@ -0,0 +1,68 @@
<?php
/**
* ownCloud - Addressbook
*
* @author Jakob Sack
* @copyright 2011 Jakob Sack mail@jakobsack.de
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
* License as published by the Free Software Foundation; either
* version 3 of the License, or any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
*
* You should have received a copy of the GNU Affero General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
function contactsort($a,$b){
return strcmp($a['name'],$b['name']);
}
// Init owncloud
require_once('../../lib/base.php');
// Check if we are a user
if( !OC_User::isLoggedIn()){
header( 'Location: '.OC_Helper::linkTo( '', 'index.php' ));
exit();
}
// Load the files we need
OC_App::setActiveNavigationEntry( 'contacts_index' );
// Load a specific user?
$id = isset( $_GET['id'] ) ? $_GET['id'] : null;
// Addressbooks to load
$openaddressbooks = explode(';',OC_Preferences::getValue(OC_User::getUser(),'contacts','openaddressbooks',null));
$contacts = array();
foreach( $openaddressbooks as $addressbook ){
$addressbookcontacts = OC_Contacts_Addressbook::allCards($addressbook);
foreach( $addressbookcontacts as $contact ){
$contacts[] = array( 'name' => $contact['fullname'], 'id' => $contact['id'] );
}
}
usort($contacts,'contactsort');
$details = array();
if( !is_null($id) || count($contacts)){
$contact = OC_Contacts_Addressbook::findCard(is_null($id)?$contacts[0]['id']:$id);
$vcard = Sabre_VObject_Reader::read($contact['carddata']);
$details = OC_Contacts_Addressbook::structureContact($vcard);
}
// Process the template
$tmpl = new OC_Template( 'contacts', 'index', 'user' );
$tmpl->assign('contacts', $contacts);
$tmpl->assign('details', $details );
$tmpl->assign('id',$id);
$tmpl->printPage();

View file

@ -0,0 +1,14 @@
$(document).ready(function(){
$('.contacts_contacts').find('li').live('click',function(){
var id = $(this).attr('x-id');
$.getJSON('details.php',{'id':id},function(jsondata){
if(jsondata.status == 'success'){
$('.contacts_details').html(jsondata.data.page);
}
else{
alert(jsondata.data.message);
}
});
return false;
});
});

View file

@ -0,0 +1,287 @@
<?php
/**
* ownCloud - Addressbook
*
* @author Jakob Sack
* @copyright 2011 Jakob Sack mail@jakobsack.de
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
* License as published by the Free Software Foundation; either
* version 3 of the License, or any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
*
* You should have received a copy of the GNU Affero General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
*
* The following SQL statement is just a help for developers and will not be
* executed!
*
* CREATE TABLE contacts_addressbooks (
* id INT(11) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
* userid VARCHAR(255) NOT NULL,
* displayname VARCHAR(255),
* uri VARCHAR(100),
* description TEXT,
* ctag INT(11) UNSIGNED NOT NULL DEFAULT '1'
* );
*
* CREATE TABLE contacts_cards (
* id INT(11) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
* addressbookid INT(11) UNSIGNED NOT NULL,
* fullname VARCHAR(255),
* carddata TEXT,
* uri VARCHAR(100),
* lastmodified INT(11) UNSIGNED
* );
*/
/**
* This class manages our addressbooks.
*/
class OC_Contacts_Addressbook{
public static function allAddressbooks($uid){
$stmt = OC_DB::prepare( 'SELECT * FROM *PREFIX*contacts_addressbooks WHERE userid = ?' );
$result = $stmt->execute(array($uid));
$addressbooks = array();
while( $row = $result->fetchRow()){
$addressbooks[] = $row;
}
return $addressbooks;
}
public static function allAddressbooksWherePrincipalURIIs($principaluri){
$uid = self::extractUserID($principaluri);
return self::allAddressbooks($uid);
}
public static function findAddressbook($id){
$stmt = OC_DB::prepare( 'SELECT * FROM *PREFIX*contacts_addressbooks WHERE id = ?' );
$result = $stmt->execute(array($id));
return $result->fetchRow();
}
public static function addAddressbook($userid,$name,$description){
$all = self::allAddressbooks($userid);
$uris = array();
foreach($all as $i){
$uris[] = $i['uri'];
}
$uri = self::createURI('name', $uris );
$stmt = OC_DB::prepare( 'INSERT INTO *PREFIX*contacts_addressbooks (userid,displayname,uri,description,ctag) VALUES(?,?,?,?,?)' );
$result = $stmt->execute(array($userid,$name,$uri,$description,1));
return OC_DB::insertid();
}
public static function addAddressbookFromDAVData($principaluri,$uri,$name,$description){
$userid = self::extractUserID($principaluri);
$stmt = OC_DB::prepare( 'INSERT INTO *PREFIX*contacts_addressbooks (userid,displayname,uri,description,ctag) VALUES(?,?,?,?,?)' );
$result = $stmt->execute(array($userid,$name,$uri,$description,1));
return OC_DB::insertid();
}
public static function editAddressbook($id,$name,$description){
// Need these ones for checking uri
$addressbook = self::find($id);
if(is_null($name)){
$name = $addressbook['name'];
}
if(is_null($description)){
$description = $addressbook['description'];
}
$stmt = OC_DB::prepare( 'UPDATE *PREFIX*contacts_addressbooks SET displayname=?,description=?, ctag=ctag+1 WHERE id=?' );
$result = $stmt->execute(array($name,$description,$id));
return true;
}
public static function touchAddressbook($id){
$stmt = OC_DB::prepare( 'UPDATE *PREFIX*contacts_addressbooks SET ctag = ctag + 1 WHERE id = ?' );
$stmt->execute(array($id));
return true;
}
public static function deleteAddressbook($id){
$stmt = OC_DB::prepare( 'DELETE FROM *PREFIX*contacts_cards WHERE id = ?' );
$stmt->execute(array($id));
$stmt = OC_DB::prepare( 'DELETE FROM *PREFIX*contacts_addressbooks WHERE addressbookid = ?' );
$stmt->execute(array($id));
return true;
}
public static function allCards($id){
$stmt = OC_DB::prepare( 'SELECT * FROM *PREFIX*contacts_cards WHERE addressbookid = ?' );
$result = $stmt->execute(array($id));
$addressbooks = array();
while( $row = $result->fetchRow()){
$addressbooks[] = $row;
}
return $addressbooks;
}
public static function findCard($id){
$stmt = OC_DB::prepare( 'SELECT * FROM *PREFIX*contacts_cards WHERE id = ?' );
$result = $stmt->execute(array($id));
return $result->fetchRow();
}
public static function findCardWhereDAVDataIs($aid,$uri){
$stmt = OC_DB::prepare( 'SELECT * FROM *PREFIX*contacts_cards WHERE addressbookid = ? AND uri = ?' );
$result = $stmt->execute(array($aid,$uri));
return $result->fetchRow();
}
public static function addCard($id,$data){
$fn = null;
$uri = null;
$card = Sabre_VObject_Reader::read($data);
foreach($card->children as $property){
if($property->name == 'FN'){
$fn = $property->value;
}
elseif(is_null($uri) && $property->name == 'UID' ){
$uri = $property->value.'.vcf';
}
}
$uri = self::createUID().'.vcf';
$stmt = OC_DB::prepare( 'INSERT INTO *PREFIX*contacts_cards (addressbookid,fullname,carddata,uri,lastmodified) VALUES(?,?,?,?,?)' );
$result = $stmt->execute(array($id,$fn,$data,$uri,time()));
self::touch($id);
return OC_DB::insertid;
}
public static function addCardFromDAVData($id,$uri,$data){
$fn = null;
$card = Sabre_VObject_Reader::read($data);
foreach($card->children as $property){
if($property->name == 'FN'){
$fn = $property->value;
}
}
$stmt = OC_DB::prepare( 'INSERT INTO *PREFIX*contacts_cards (addressbookid,fullname,carddata,uri,lastmodified) VALUES(?,?,?,?,?)' );
$result = $stmt->execute(array($id,$fn,$data,$uri,time()));
self::touch($id);
return OC_DB::insertid;
}
public static function editCard($id, $data){
$oldcard = self::findCard($id,$aid,$uri);
$fn = null;
$card = Sabre_VObject_Reader::read($data);
foreach($card->children as $property){
if($property->name == 'FN'){
$fn = $property->value;
}
}
$stmt = OC_DB::prepare( 'UPDATE *PREFIX*contacts_cards SET fullname = ?,carddata = ?, lastmodified = ? WHERE id = ?' );
$result = $stmt->execute(array($fn,$data,time(),$id));
self::touch($oldcard['addressbookid']);
return true;
}
public static function editCardFromDAVData($aid,$uri,$data){
$oldcard = self::findCardWhereDAVDataIs($aid,$uri);
$fn = null;
$card = Sabre_VObject_Reader::read($data);
foreach($card->children as $property){
if($property->name == 'FN'){
$fn = $property->value;
}
}
$stmt = OC_DB::prepare( 'UPDATE *PREFIX*contacts_cards SET fullname = ?,carddata = ?, lastmodified = ? WHERE id = ?' );
$result = $stmt->execute(array($fn,$data,time(),$oldcard['id']));
self::touch($oldcard['addressbookid']);
return true;
}
public static function deleteCard($id){
$stmt = OC_DB::prepare( 'DELETE FROM *PREFIX*contacts_addressbooks WHERE id = ?' );
$stmt->execute(array($id));
return true;
}
public static function deleteCardFromDAVData($aid,$uri){
$stmt = OC_DB::prepare( 'DELETE FROM *PREFIX*contacts_addressbooks WHERE addressbookid = ? AND uri=?' );
$stmt->execute(array($aid,$uri));
return true;
}
public static function createURI($name,$existing){
$name = strtolower($name);
$newname = $name;
$i = 1;
while(in_array($newname,$existing)){
$newname = $name.$i;
$i = $i + 1;
}
return $newname;
}
public static function createUID(){
return substr(md5(rand().time()),0,10);
}
public static function extractUserID($principaluri){
list($prefix,$userid) = Sabre_DAV_URLUtil::splitPath($principaluri);
return $userid;
}
public static function structureContact($object){
$details = array();
foreach($object->children as $property){
$temp = array(
'name' => $property->name,
'value' => ($property->name == 'PHOTO' || $property->name == 'LOGO' ? null : $property->value ),
'parameters' => array());
foreach($property->parameters as $parameter){
$temp['parameters'][] = array( 'name' => $parameter->name, 'value' => $parameter->value);
}
if(array_key_exists($property->name,$details)){
$details[$property->name][] = $temp;
}
else{
$details[$property->name] = array($temp);
}
}
return $details;
}
}

View file

@ -0,0 +1,186 @@
<?php
/**
* PDO CardDAV backend
*
* @package Sabre
* @subpackage CardDAV
* @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved.
* @author Evert Pot (http://www.rooftopsolutions.nl/)
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
*/
/**
* This CardDAV backend uses PDO to store addressbooks
*/
class OC_Connector_Sabre_CardDAV extends Sabre_CardDAV_Backend_Abstract {
/**
* Returns the list of addressbooks for a specific user.
*
* @param string $principaluri
* @return array
*/
public function getAddressBooksForUser($principaluri) {
$data = OC_Contacts_Addressbook::allAddressbooksWherePrincipalURIIs($principaluri);
$addressbooks = array();
foreach($data as $i) {
$addressbooks[] = array(
'id' => $i['id'],
'uri' => $i['uri'],
'principaluri' => 'principals/'.$i['userid'],
'{DAV:}displayname' => $i['displayname'],
'{' . Sabre_CardDAV_Plugin::NS_CARDDAV . '}addressbook-description' => $i['description'],
'{http://calendarserver.org/ns/}getctag' => $i['ctag'],
);
}
return $addressbooks;
}
/**
* Updates an addressbook's properties
*
* See Sabre_DAV_IProperties for a description of the mutations array, as
* well as the return value.
*
* @param mixed $addressbookid
* @param array $mutations
* @see Sabre_DAV_IProperties::updateProperties
* @return bool|array
*/
public function updateAddressBook($addressbookid, array $mutations) {
$name = null;
$description = null;
foreach($mutations as $property=>$newvalue) {
switch($property) {
case '{DAV:}displayname' :
$name = $newvalue;
break;
case '{' . Sabre_CardDAV_Plugin::NS_CARDDAV . '}addressbook-description' :
$description = $newvalue;
break;
default :
// If any unsupported values were being updated, we must
// let the entire request fail.
return false;
}
}
OC_Contacts_Addressbook::editAddressbook($addressbookid,$name,$description);
return true;
}
/**
* Creates a new address book
*
* @param string $principaluri
* @param string $url Just the 'basename' of the url.
* @param array $properties
* @return void
*/
public function createAddressBook($principaluri, $url, array $properties) {
$displayname = null;
$description = null;
foreach($properties as $property=>$newvalue) {
switch($property) {
case '{DAV:}displayname' :
$displayname = $newvalue;
break;
case '{' . Sabre_CardDAV_Plugin::NS_CARDDAV . '}addressbook-description' :
$description = $newvalue;
break;
default :
throw new Sabre_DAV_Exception_BadRequest('Unknown property: ' . $property);
}
}
OC_Contacts_Addressbook::addAddressbookFromDAVData($principaluri,$url,$name,$description);
}
/**
* Deletes an entire addressbook and all its contents
*
* @param int $addressbookid
* @return void
*/
public function deleteAddressBook($addressbookid) {
OC_Contacts_Addressbook::deleteAddressbook($addressbookid);
}
/**
* Returns all cards for a specific addressbook id.
*
* @param mixed $addressbookid
* @return array
*/
public function getCards($addressbookid) {
$data = OC_Contacts_Addressbook::allCards($addressbookid);
$cards = array();
foreach($data as $i){
$cards[] = array(
'id' => $i['id'],
'carddata' => $i['carddata'],
'uri' => $i['uri'],
'lastmodified' => $i['lastmodified'] );
}
return $cards;
}
/**
* Returns a specfic card
*
* @param mixed $addressbookid
* @param string $carduri
* @return array
*/
public function getCard($addressbookid, $carduri) {
return OC_Contacts_Addressbook::findCardWhereDAVDataIs($addressbookid,$carduri);
}
/**
* Creates a new card
*
* @param mixed $addressbookid
* @param string $carduri
* @param string $carddata
* @return bool
*/
public function createCard($addressbookid, $carduri, $carddata) {
OC_Contacts_Addressbook::addCardFromDAVData($addressbookid, $carduri, $carddata);
return true;
}
/**
* Updates a card
*
* @param mixed $addressbookid
* @param string $carduri
* @param string $carddata
* @return bool
*/
public function updateCard($addressbookid, $carduri, $carddata) {
return OC_Contacts_Addressbook::editCardFromDAVData($addressbookid, $carduri, $carddata);
}
/**
* Deletes a card
*
* @param mixed $addressbookid
* @param string $carduri
* @return bool
*/
public function deleteCard($addressbookid, $carduri) {
return OC_Contacts_Addressbook::deleteCardFromDAVData($addressbookid, $carduri);
}
}

85
apps/contacts/photo.php Normal file
View file

@ -0,0 +1,85 @@
<?php
/**
* ownCloud - Addressbook
*
* @author Jakob Sack
* @copyright 2011 Jakob Sack mail@jakobsack.de
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
* License as published by the Free Software Foundation; either
* version 3 of the License, or any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
*
* You should have received a copy of the GNU Affero General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
// Init owncloud
require_once('../../lib/base.php');
$id = $_GET['id'];
$l10n = new OC_L10N('contacts');
// Check if we are a user
if( !OC_User::isLoggedIn()){
echo $l10n->t('You need to log in!');
exit();
}
$card = OC_Contacts_Addressbook::findCard( $id );
if( $card === false ){
echo $l10n->t('Can not find Contact!');
exit();
}
$addressbook = OC_Contacts_Addressbook::findAddressbook( $card['addressbookid'] );
if( $addressbook === false || $addressbook['userid'] != OC_USER::getUser()){
echo $l10n->t('This is not your contact!');
exit();
}
$content = Sabre_VObject_Reader::read($card['carddata']);
// Photo :-)
foreach($content->children as $child){
if($child->name == 'PHOTO'){
$mime = 'image/jpeg';
foreach($child->parameters as $parameter){
if( $parameter->name == 'TYPE' ){
$mime = $parameter->value;
}
}
$photo = base64_decode($child->value);
header('Content-Type: '.$mime);
header('Content-Length: ' . strlen($photo));
echo $photo;
exit();
}
}
// Logo :-/
foreach($content->children as $child){
if($child->name == 'PHOTO'){
$mime = 'image/jpeg';
foreach($child->parameters as $parameter){
if($parameter->name == 'TYPE'){
$mime = $parameter->value;
}
}
$photo = base64_decode($child->value());
header('Content-Type: '.$mime);
header('Content-Length: ' . strlen($photo));
echo $photo;
exit();
}
}
// Not found :-(
echo $l10n->t('This card does not contain photo data!');

View file

@ -0,0 +1,3 @@
<?php foreach( $_['contacts'] as $contact ): ?>
<li x-id="<?php echo $contact['id']; ?>"><a href="index.php?id=<?php echo $contact['id']; ?>"><?php echo $contact['name']; ?></a></li>
<?php endforeach; ?>

View file

@ -0,0 +1,4 @@
Name <?php echo $_['details']['FN'][0]['value']; ?>
<?php if(array_key_exists('PHOTO',$_['details'])): ?>
<img src="photo.php?id=<?php echo $_['id']; ?>">
<?php endif; ?>

View file

@ -0,0 +1,13 @@
<?php // Include Style and Script
OC_Util::addScript('contacts','interface');
OC_Util::addStyle('contacts','styles');
?>
<div class="contacts_contacts leftcontent">
<ul>
<?php echo $this->inc("_contacts"); ?>
</ul>
</div>
<div class="contacts_details rightcontent">
<?php echo $this->inc("_details"); ?>
</div>