mirror of
https://github.com/owncloudarchive/contacts.git
synced 2024-12-01 13:24:10 +01:00
418 lines
12 KiB
PHP
418 lines
12 KiB
PHP
<?php
|
|
/**
|
|
* ownCloud - ownCloud users backend for Contacts
|
|
*
|
|
* @author Tobia De Koninck
|
|
* @copyright 2014 Tobia De Koninck (tobia@ledfan.be)
|
|
*
|
|
* 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/>.
|
|
*
|
|
*/
|
|
|
|
namespace OCA\Contacts\Backend;
|
|
|
|
use OCA\Contacts\Contact,
|
|
OCA\Contacts\VObject\VCard,
|
|
OCA\Contacts\Utils\Properties,
|
|
Sabre\VObject\Reader,
|
|
OCA\Contacts\Addressbook,
|
|
OCA\Contacts\LocalUsersAddressbookProvider;
|
|
|
|
/**
|
|
* Contact backend for storing all the ownCloud users in this installation.
|
|
* Every user has *1* personal addressbook. The id of this addresbook is the
|
|
* userid of the owner.
|
|
*/
|
|
class LocalUsers extends AbstractBackend {
|
|
|
|
public $name = 'localusers';
|
|
|
|
/**
|
|
* The table that holds the address books.
|
|
* For every user there is *1* addressbook.
|
|
* @var string
|
|
*/
|
|
private $addressBooksTableName = '*PREFIX*contacts_ocu_addressbooks';
|
|
|
|
/**
|
|
* The table that holds the contacts.
|
|
* @var string
|
|
*/
|
|
private $cardsTableName = '*PREFIX*contacts_ocu_cards';
|
|
|
|
/**
|
|
* The table that holds the properties of the contacts.
|
|
* This is used to provice a search function.
|
|
* @var string
|
|
*/
|
|
private $indexTableName = '*PREFIX*contacts_ocu_cards_properties';
|
|
|
|
/**
|
|
* All possible properties which can be stored in the $indexTableName.
|
|
* @var string
|
|
*/
|
|
private $indexProperties = array(
|
|
'BDAY', 'UID', 'N', 'FN', 'TITLE', 'ROLE', 'NOTE', 'NICKNAME',
|
|
'ORG', 'CATEGORIES', 'EMAIL', 'TEL', 'IMPP', 'ADR', 'URL', 'GEO'
|
|
);
|
|
|
|
/**
|
|
* language object
|
|
* @var OC_L10N
|
|
*/
|
|
public static $l10n;
|
|
|
|
/**
|
|
* Defaults object
|
|
* @var OC_Defaults
|
|
*/
|
|
public static $defaults;
|
|
|
|
public function __construct($userid) {
|
|
self::$l10n = \OCP\Util::getL10N('contacts');
|
|
self::$defaults = new \OCP\Defaults();
|
|
$this->userid = $userid ? $userid : \OCP\User::getUser();
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*/
|
|
public function getAddressBooksForUser(array $options = array()) {
|
|
return array($this->getAddressBook($this->userid));
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
* Only 1 addressbook for every user
|
|
*/
|
|
public function getAddressBook($addressBookId, array $options = array()) {
|
|
return array(
|
|
'id' => $addressBookId,
|
|
'displayname' => (string)self::$l10n->t('On this %s', array(self::$defaults->getName())),
|
|
'description' => (string)self::$l10n->t('On this %s', array(self::$defaults->getName())),
|
|
'lastmodified' => $this->lastModifiedAddressBook($addressBookId),
|
|
'permissions' => \OCP\PERMISSION_READ,
|
|
'backend' => $this->name
|
|
);
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
* There are as many contacts in this addressbook as in this ownCloud installation
|
|
*/
|
|
public function getContacts($addressBookId, array $options = array()) {
|
|
$this->updateDatabase($addressBookId);
|
|
$contacts = array();
|
|
try {
|
|
$sql = 'SELECT * FROM ' . $this->cardsTableName . ' WHERE addressbookid = ?';
|
|
$query = \OCP\DB::prepare($sql);
|
|
$result = $query->execute(array($addressBookId));
|
|
|
|
if (\OCP\DB::isError($result)) {
|
|
\OCP\Util::writeLog('contacts', __METHOD__. 'DB error: '
|
|
. \OC_DB::getErrorMessage($result), \OCP\Util::ERROR);
|
|
return $contacts;
|
|
} else {
|
|
while($row = $result->fetchRow()){
|
|
$row['permissions'] = \OCP\PERMISSION_READ | \OCP\PERMISSION_UPDATE;
|
|
$contacts[] = $row;
|
|
}
|
|
}
|
|
return $contacts;
|
|
} catch(\Exception $e) {
|
|
\OCP\Util::writeLog('contacts', __METHOD__.' exception: '
|
|
. $e->getMessage(), \OCP\Util::ERROR);
|
|
return $contacts;
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
* If your username is "admin" and you want to retrieve your own contact
|
|
* the params would be: $addressbookid = 'admin'; $id = 'admin';
|
|
* If your username is 'foo' and you want to retrieve the contact with
|
|
* ownCloud username 'bar' the params would be: $addressbookid = 'foo'; $id = 'bar';
|
|
*/
|
|
public function getContact($addressBookId, $id, array $options = array()) {
|
|
try{
|
|
$sql = 'SELECT * FROM ' . $this->cardsTableName . ' WHERE addressbookid = ? AND id = ?';
|
|
$query = \OCP\DB::prepare($sql);
|
|
$result = $query->execute(array($addressBookId, $id));
|
|
|
|
if (\OCP\DB::isError($result)) {
|
|
\OCP\Util::writeLog('contacts', __METHOD__. 'DB error: '
|
|
. \OC_DB::getErrorMessage($result), \OCP\Util::ERROR);
|
|
return null;
|
|
} else {
|
|
$row = $result->fetchRow();
|
|
$row['permissions'] = \OCP\PERMISSION_READ | \OCP\PERMISSION_UPDATE;
|
|
return $row;
|
|
}
|
|
} catch(\Exception $e) {
|
|
\OCP\Util::writeLog('contacts', __METHOD__.' exception: '
|
|
. $e->getMessage(), \OCP\Util::ERROR);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Help function to add contacts to an addressbook.
|
|
* This only happens when an admin creates new users
|
|
* @param array $contacts array with userid of ownCloud users
|
|
* @param string $addressBookId
|
|
* @return bool
|
|
*/
|
|
private function addContacts($contacts, $addressBookId) {
|
|
foreach ($contacts as $user) {
|
|
try {
|
|
$sql = 'INSERT INTO ' . $this->cardsTableName . ' ('
|
|
. 'id, '
|
|
. 'addressbookid, '
|
|
. 'displayname, '
|
|
. 'carddata, '
|
|
. 'lastmodified'
|
|
. ') VALUES ('
|
|
. '?,'
|
|
. '?,'
|
|
. '?,'
|
|
. '?,'
|
|
. '?'
|
|
. ')';
|
|
|
|
$query = \OCP\DB::prepare($sql);
|
|
|
|
$vcard = \Sabre\VObject\Component::create('VCARD');
|
|
$vcard->FN = \OCP\User::getDisplayName($user);
|
|
$now = new \DateTime('now');
|
|
$vcard->REV = $now->format(\DateTime::W3C);
|
|
|
|
$appinfo = \OCP\App::getAppInfo('contacts');
|
|
$appversion = \OCP\App::getAppVersion('contacts');
|
|
$prodid = '-//ownCloud//NONSGML ' . $appinfo['name'] . ' ' . $appversion.'//EN';
|
|
$vcard->PRODID = $prodid;
|
|
$vcard->add('IMPP', 'x-owncloud-handle:' . $user, array("X-SERVICE-TYPE" => array("owncloud-handle")));
|
|
|
|
$result = $query->execute(array($user, $addressBookId, \OCP\User::getDisplayName($user), $vcard->serialize(), time()));
|
|
|
|
if (\OCP\DB::isError($result)) {
|
|
\OCP\Util::writeLog('contacts', __METHOD__. 'DB error: '
|
|
. \OC_DB::getErrorMessage($result), \OCP\Util::ERROR);
|
|
return false;
|
|
} else {
|
|
// All done
|
|
// now update the index table with all the properties
|
|
$this->updateIndex($user, $vcard);
|
|
}
|
|
} catch(\Exception $e) {
|
|
\OCP\Util::writeLog('contacts', __METHOD__.' exception: '
|
|
. $e->getMessage(), \OCP\Util::ERROR);
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Help function to remove contacts from an addressbook.
|
|
* This only happens when an admin remove an ownCloud user
|
|
* @param array $contacts array with userid of ownCloud users
|
|
* @param string $addressBookId
|
|
* @return bool
|
|
*/
|
|
private function removeContacts($contacts, $addressBookId) {
|
|
foreach ($contacts as $user) {
|
|
\OCP\Util::writeLog('contacts', 'Removing: ' . $user . ' from ' . $addressBookId, \OCP\Util::DEBUG);
|
|
try {
|
|
$sql = 'DELETE FROM ' . $this->cardsTableName . ' WHERE addressbookid = ? AND id = ?';
|
|
$query = \OCP\DB::prepare($sql);
|
|
$result = $query->execute(array($addressBookId, $user));
|
|
if (\OCP\DB::isError($result)) {
|
|
\OCP\Util::writeLog('contacts', __METHOD__. 'DB error: '
|
|
. \OC_DB::getErrorMessage($result), \OCP\Util::ERROR);
|
|
return false;
|
|
}
|
|
} catch(\Exception $e) {
|
|
\OCP\Util::writeLog('contacts', __METHOD__.' exception: '
|
|
. $e->getMessage(), \OCP\Util::ERROR);
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* @inheritdoc
|
|
*/
|
|
public function updateContact($addressBookId, $id, $contact, array $options = array()) {
|
|
|
|
$updateRevision = true;
|
|
$isCardDAV = false;
|
|
|
|
if (!$contact instanceof VCard) {
|
|
try {
|
|
$contact = Reader::read($contact);
|
|
} catch(\Exception $e) {
|
|
\OCP\Util::writeLog('contacts', __METHOD__.', exception: '.$e->getMessage(), \OCP\Util::ERROR);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if ($updateRevision || !isset($contact->REV)) {
|
|
$now = new \DateTime;
|
|
$contact->REV = $now->format(\DateTime::W3C);
|
|
}
|
|
|
|
try{
|
|
$sql = 'UPDATE ' . $this->cardsTableName
|
|
. ' SET '
|
|
. '`displayname` = ?, '
|
|
. '`carddata` = ?, '
|
|
. '`lastmodified` = ? '
|
|
. ' WHERE '
|
|
. '`id` = ? '
|
|
. 'AND `addressbookid` = ? ';
|
|
$query = \OCP\DB::prepare($sql);
|
|
$result = $query->execute(array($contact->FN, $contact->serialize(), time(), $id, $addressBookId));
|
|
if (\OCP\DB::isError($result)) {
|
|
\OCP\Util::writeLog('contacts', __METHOD__. 'DB error: '
|
|
. \OC_DB::getErrorMessage($result), \OCP\Util::ERROR);
|
|
return false;
|
|
} else {
|
|
// All done
|
|
// now update the indexes in the DB
|
|
$this->updateIndex($id, $contact);
|
|
return true;
|
|
}
|
|
} catch(\Exception $e) {
|
|
\OCP\Util::writeLog('contacts', __METHOD__.' exception: '
|
|
. $e->getMessage(), \OCP\Util::ERROR);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* This is a hack so backends can have different search functions.
|
|
* @return \OCA\Contacts\LocalUsersAddressbookProvider
|
|
*/
|
|
public function getSearchProvider($addressBook) {
|
|
return new LocalUsersAddressbookProvider($addressBook);
|
|
}
|
|
|
|
/**
|
|
* Updates the index table. All properties of a contact are stored in it.
|
|
* Needed for the search function.
|
|
* @param type $contactId
|
|
* @param type $vcard
|
|
* @return boolean
|
|
*/
|
|
private function updateIndex($contactId, $vcard) {
|
|
// Utils\Properties::updateIndex($parameters['id'], $contact);
|
|
$this->purgeIndex($contactId);
|
|
$updatestmt = \OCP\DB::prepare('INSERT INTO `' . $this->indexTableName . '` '
|
|
. '(`addressbookid`, `contactid`,`name`,`value`,`preferred`) VALUES(?,?,?,?,?)');
|
|
// Insert all properties in the table
|
|
foreach ($vcard->children as $property) {
|
|
if (!in_array($property->name, $this->indexProperties)) {
|
|
continue;
|
|
}
|
|
$preferred = 0;
|
|
foreach ($property->parameters as $parameter) {
|
|
if ($parameter->name == 'TYPE' && strtoupper($parameter->value) == 'PREF') {
|
|
$preferred = 1;
|
|
break;
|
|
}
|
|
}
|
|
try {
|
|
$result = $updatestmt->execute(
|
|
array(
|
|
\OCP\User::getUser(),
|
|
$contactId,
|
|
$property->name,
|
|
substr($property->value, 0, 254),
|
|
$preferred,
|
|
)
|
|
);
|
|
if (\OCP\DB::isError($result)) {
|
|
\OCP\Util::writeLog('contacts', __METHOD__. 'DB error: '
|
|
. \OC_DB::getErrorMessage($result), \OCP\Util::ERROR);
|
|
return false;
|
|
}
|
|
} catch(\Exception $e) {
|
|
\OCP\Util::writeLog('contacts', __METHOD__.', exception: '.$e->getMessage(), \OCP\Util::ERROR);
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Remove all indexes from the table.
|
|
* This is always called before adding new properties.
|
|
* @param type $contactId
|
|
* @param type $vcard
|
|
* @return boolean
|
|
*/
|
|
private function purgeIndex($id) {
|
|
// Remove all indexes from the table
|
|
try {
|
|
$query = \OCP\DB::prepare('DELETE FROM `' . $this->indexTableName . '`'
|
|
. ' WHERE `contactid` = ?');
|
|
$query->execute(array($id));
|
|
|
|
} catch(\Exception $e) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public function updateDatabase($addressBookId) {
|
|
$sql = 'SELECT * FROM ' . $this->cardsTableName . ' WHERE addressbookid = ?';
|
|
$query = \OCP\DB::prepare($sql);
|
|
$result = $query->execute(array($addressBookId));
|
|
|
|
if (\OCP\DB::isError($result)) {
|
|
\OCP\Util::writeLog('contacts', __METHOD__. 'DB error: '
|
|
. \OC_DB::getErrorMessage($result), \OCP\Util::ERROR);
|
|
return true; // Huh?
|
|
} else {
|
|
$contactsId = array();
|
|
while ($row = $result->fetchRow()) {
|
|
$contactsId[] = $row['id'];
|
|
}
|
|
|
|
$users = \OCP\User::getUsers();
|
|
|
|
$add = array_diff($users, $contactsId);
|
|
$remove = array_diff($contactsId, $users);
|
|
if (count($add) > 0) {
|
|
$this->addContacts($add, $addressBookId);
|
|
$recall = true;
|
|
}
|
|
|
|
if (count($remove) > 0) {
|
|
$this->removeContacts($remove, $addressBookId);
|
|
$recall = true;
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Don't cache
|
|
*/
|
|
public function lastModifiedAddressBook($addressBookId) {
|
|
return time();
|
|
}
|
|
|
|
}
|