mirror of
https://github.com/owncloudarchive/contacts.git
synced 2024-11-28 10:24:11 +01:00
Merge branch 'contacts_backends' into contacts_oc6
Conflicts: contacts/ajax/categories/add.php contacts/ajax/contact/add.php contacts/appinfo/app.php contacts/appinfo/migrate.php contacts/css/contacts.css contacts/index.php contacts/js/app.js contacts/js/contacts.js contacts/js/groups.js contacts/lib/app.php contacts/lib/carddav/addressbook.php contacts/lib/sabre/backend.php contacts/lib/vcard.php contacts/templates/contacts.php contacts/thumbnail.php
This commit is contained in:
commit
c3fa18e4a7
@ -1,37 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* Copyright (c) 2011-2012 Thomas Tanghus <thomas@tanghus.net>
|
|
||||||
* Copyright (c) 2011 Bart Visscher <bartv@thisnet.nl>
|
|
||||||
* This file is licensed under the Affero General Public License version 3 or
|
|
||||||
* later.
|
|
||||||
* See the COPYING-README file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
// Check if we are a user
|
|
||||||
OCP\JSON::checkLoggedIn();
|
|
||||||
OCP\JSON::checkAppEnabled('contacts');
|
|
||||||
OCP\JSON::callCheck();
|
|
||||||
require_once __DIR__.'/../loghandler.php';
|
|
||||||
|
|
||||||
debug('name: '.$_POST['name']);
|
|
||||||
|
|
||||||
$userid = OCP\USER::getUser();
|
|
||||||
$name = isset($_POST['name'])?trim(strip_tags($_POST['name'])):null;
|
|
||||||
$description = isset($_POST['description'])
|
|
||||||
? trim(strip_tags($_POST['description']))
|
|
||||||
: null;
|
|
||||||
|
|
||||||
if(is_null($name)) {
|
|
||||||
bailOut('Cannot add addressbook with an empty name.');
|
|
||||||
}
|
|
||||||
$bookid = OCA\Contacts\Addressbook::add($userid, $name, $description);
|
|
||||||
if(!$bookid) {
|
|
||||||
bailOut('Error adding addressbook: '.$name);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!OCA\Contacts\Addressbook::setActive($bookid, 1)) {
|
|
||||||
bailOut('Error activating addressbook.');
|
|
||||||
}
|
|
||||||
$addressbook = OCA\Contacts\Addressbook::find($bookid);
|
|
||||||
OCP\JSON::success(array('data' => array('addressbook' => $addressbook)));
|
|
@ -1,29 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* Copyright (c) 2012 Thomas Tanghus <thomas@tanghus.net>
|
|
||||||
* This file is licensed under the Affero General Public License version 3 or
|
|
||||||
* later.
|
|
||||||
* See the COPYING-README file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
OCP\JSON::checkLoggedIn();
|
|
||||||
OCP\JSON::checkAppEnabled('contacts');
|
|
||||||
OCP\JSON::callCheck();
|
|
||||||
|
|
||||||
require_once __DIR__.'/../loghandler.php';
|
|
||||||
|
|
||||||
$category = isset($_POST['category']) ? trim(strip_tags($_POST['category'])) : null;
|
|
||||||
|
|
||||||
if(is_null($category) || $category === "") {
|
|
||||||
bailOut(OCA\Contacts\App::$l10n->t('No category name given.'));
|
|
||||||
}
|
|
||||||
|
|
||||||
$catman = new OC_VCategories('contact');
|
|
||||||
$id = $catman->add($category);
|
|
||||||
|
|
||||||
if($id !== false) {
|
|
||||||
OCP\JSON::success(array('data' => array('id'=>$id, 'name' => $category)));
|
|
||||||
} else {
|
|
||||||
bailOut(OCA\Contacts\App::$l10n->t('Error adding group.'));
|
|
||||||
}
|
|
@ -1,34 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* Copyright (c) 2012 Thomas Tanghus <thomas@tanghus.net>
|
|
||||||
* This file is licensed under the Affero General Public License version 3 or
|
|
||||||
* later.
|
|
||||||
* See the COPYING-README file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
OCP\JSON::checkLoggedIn();
|
|
||||||
OCP\JSON::checkAppEnabled('contacts');
|
|
||||||
OCP\JSON::callCheck();
|
|
||||||
|
|
||||||
require_once __DIR__.'/../loghandler.php';
|
|
||||||
|
|
||||||
$categoryid = isset($_POST['categoryid']) ? $_POST['categoryid'] : null;
|
|
||||||
$contactids = isset($_POST['contactids']) ? $_POST['contactids'] : null;
|
|
||||||
|
|
||||||
if(is_null($categoryid)) {
|
|
||||||
bailOut(OCA\Contacts\App::$l10n->t('Group ID missing from request.'));
|
|
||||||
}
|
|
||||||
|
|
||||||
if(is_null($contactids)) {
|
|
||||||
bailOut(OCA\Contacts\App::$l10n->t('Contact ID missing from request.'));
|
|
||||||
}
|
|
||||||
|
|
||||||
$catmgr = OCA\Contacts\App::getVCategories();
|
|
||||||
|
|
||||||
foreach($contactids as $contactid) {
|
|
||||||
debug('contactid: ' . $contactid . ', categoryid: ' . $categoryid);
|
|
||||||
$catmgr->addToCategory($contactid, $categoryid);
|
|
||||||
}
|
|
||||||
|
|
||||||
OCP\JSON::success();
|
|
@ -1,51 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* Copyright (c) 2012 Thomas Tanghus <thomas@tanghus.net>
|
|
||||||
* This file is licensed under the Affero General Public License version 3 or
|
|
||||||
* later.
|
|
||||||
* See the COPYING-README file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
OCP\JSON::checkLoggedIn();
|
|
||||||
OCP\JSON::checkAppEnabled('contacts');
|
|
||||||
OCP\JSON::callCheck();
|
|
||||||
|
|
||||||
require_once __DIR__.'/../loghandler.php';
|
|
||||||
|
|
||||||
$categories = isset($_POST['categories']) ? $_POST['categories'] : null;
|
|
||||||
$fromobjects = (isset($_POST['fromobjects'])
|
|
||||||
&& ($_POST['fromobjects'] === 'true' || $_POST['fromobjects'] === '1')) ? true : false;
|
|
||||||
|
|
||||||
if(is_null($categories)) {
|
|
||||||
bailOut(OCA\Contacts\App::$l10n->t('No categories selected for deletion.'));
|
|
||||||
}
|
|
||||||
|
|
||||||
debug(print_r($categories, true));
|
|
||||||
if($fromobjects) {
|
|
||||||
$addressbooks = OCA\Contacts\Addressbook::all(OCP\USER::getUser());
|
|
||||||
if(count($addressbooks) == 0) {
|
|
||||||
bailOut(OCA\Contacts\App::$l10n->t('No address books found.'));
|
|
||||||
}
|
|
||||||
$addressbookids = array();
|
|
||||||
foreach($addressbooks as $addressbook) {
|
|
||||||
$addressbookids[] = $addressbook['id'];
|
|
||||||
}
|
|
||||||
$contacts = OCA\Contacts\VCard::all($addressbookids);
|
|
||||||
if(count($contacts) == 0) {
|
|
||||||
bailOut(OCA\Contacts\App::$l10n->t('No contacts found.'));
|
|
||||||
}
|
|
||||||
|
|
||||||
$cards = array();
|
|
||||||
foreach($contacts as $contact) {
|
|
||||||
$cards[] = array($contact['id'], $contact['carddata']);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$catman = new OC_VCategories('contact');
|
|
||||||
$catman->delete($categories, $cards);
|
|
||||||
|
|
||||||
if($fromobjects) {
|
|
||||||
OCA\Contacts\VCard::updateDataByID($cards);
|
|
||||||
}
|
|
||||||
OCP\JSON::success();
|
|
@ -1,46 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* Copyright (c) 2012 Thomas Tanghus <thomas@tanghus.net>
|
|
||||||
* This file is licensed under the Affero General Public License version 3 or
|
|
||||||
* later.
|
|
||||||
* See the COPYING-README file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
OCP\JSON::checkLoggedIn();
|
|
||||||
OCP\JSON::checkAppEnabled('contacts');
|
|
||||||
|
|
||||||
$catmgr = OCA\Contacts\App::getVCategories();
|
|
||||||
$categories = $catmgr->categories(OC_VCategories::FORMAT_MAP);
|
|
||||||
foreach($categories as &$category) {
|
|
||||||
$ids = array();
|
|
||||||
$contacts = $catmgr->itemsForCategory(
|
|
||||||
$category['name'],
|
|
||||||
array(
|
|
||||||
'tablename' => '*PREFIX*contacts_cards',
|
|
||||||
'fields' => array('id',),
|
|
||||||
));
|
|
||||||
foreach($contacts as $contact) {
|
|
||||||
$ids[] = $contact['id'];
|
|
||||||
}
|
|
||||||
$category['contacts'] = $ids;
|
|
||||||
}
|
|
||||||
|
|
||||||
$favorites = $catmgr->getFavorites();
|
|
||||||
|
|
||||||
OCP\JSON::success(array(
|
|
||||||
'data' => array(
|
|
||||||
'categories' => $categories,
|
|
||||||
'favorites' => $favorites,
|
|
||||||
'shared' => OCP\Share::getItemsSharedWith('addressbook', OCA\Contacts\Share_Backend_Addressbook::FORMAT_ADDRESSBOOKS),
|
|
||||||
'lastgroup' => OCP\Config::getUserValue(
|
|
||||||
OCP\User::getUser(),
|
|
||||||
'contacts',
|
|
||||||
'lastgroup', 'all'),
|
|
||||||
'sortorder' => OCP\Config::getUserValue(
|
|
||||||
OCP\User::getUser(),
|
|
||||||
'contacts',
|
|
||||||
'groupsort', ''),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
@ -1,34 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* Copyright (c) 2012 Thomas Tanghus <thomas@tanghus.net>
|
|
||||||
* This file is licensed under the Affero General Public License version 3 or
|
|
||||||
* later.
|
|
||||||
* See the COPYING-README file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
OCP\JSON::checkLoggedIn();
|
|
||||||
OCP\JSON::checkAppEnabled('contacts');
|
|
||||||
OCP\JSON::callCheck();
|
|
||||||
|
|
||||||
require_once __DIR__.'/../loghandler.php';
|
|
||||||
|
|
||||||
$categoryid = isset($_POST['categoryid']) ? $_POST['categoryid'] : null;
|
|
||||||
$contactids = isset($_POST['contactids']) ? $_POST['contactids'] : null;
|
|
||||||
|
|
||||||
if(is_null($categoryid)) {
|
|
||||||
bailOut(OCA\Contacts\App::$l10n->t('Group ID missing from request.'));
|
|
||||||
}
|
|
||||||
|
|
||||||
if(is_null($contactids)) {
|
|
||||||
bailOut(OCA\Contacts\App::$l10n->t('Contact ID missing from request.'));
|
|
||||||
}
|
|
||||||
|
|
||||||
$catmgr = OCA\Contacts\App::getVCategories();
|
|
||||||
|
|
||||||
foreach($contactids as $contactid) {
|
|
||||||
debug('id: ' . $contactid .', categoryid: ' . $categoryid);
|
|
||||||
$catmgr->removeFromCategory($contactid, $categoryid);
|
|
||||||
}
|
|
||||||
|
|
||||||
OCP\JSON::success();
|
|
@ -1,73 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* ownCloud - Addressbook
|
|
||||||
*
|
|
||||||
* @author Thomas Tanghus
|
|
||||||
* @copyright 2012 Thomas Tanghus <thomas@tanghus.net>
|
|
||||||
*
|
|
||||||
* 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/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Check if we are a user
|
|
||||||
OCP\JSON::checkLoggedIn();
|
|
||||||
OCP\JSON::checkAppEnabled('contacts');
|
|
||||||
OCP\JSON::callCheck();
|
|
||||||
|
|
||||||
require_once __DIR__.'/../loghandler.php';
|
|
||||||
|
|
||||||
$aid = isset($_POST['aid']) ? $_POST['aid'] : null;
|
|
||||||
if(!$aid) {
|
|
||||||
$ids = OCA\Contacts\Addressbook::activeIds();
|
|
||||||
if(count($ids) > 0) {
|
|
||||||
$aid = min($ids); // first active addressbook.
|
|
||||||
} else {
|
|
||||||
$addressbooks = OCA\Contacts\Addressbook::all(OCP\User::getUser());
|
|
||||||
if(count($addressbooks) === 0) {
|
|
||||||
bailOut(OCA\Contacts\App::$l10n->t('You have no addressbooks.'));
|
|
||||||
} else {
|
|
||||||
$aid = $addressbooks[0]['id'];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$isnew = isset($_POST['isnew']) ? $_POST['isnew'] : false;
|
|
||||||
|
|
||||||
$vcard = Sabre\VObject\Component::create('VCARD');
|
|
||||||
$uid = substr(md5(rand().time()), 0, 10);
|
|
||||||
$vcard->add('UID', $uid);
|
|
||||||
|
|
||||||
$id = null;
|
|
||||||
try {
|
|
||||||
$id = OCA\Contacts\VCard::add($aid, $vcard, null, $isnew);
|
|
||||||
} catch(Exception $e) {
|
|
||||||
bailOut($e->getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!$id) {
|
|
||||||
bailOut('There was an error adding the contact.');
|
|
||||||
}
|
|
||||||
|
|
||||||
$lastmodified = OCA\Contacts\App::lastModified($vcard);
|
|
||||||
if(!$lastmodified) {
|
|
||||||
$lastmodified = new DateTime();
|
|
||||||
}
|
|
||||||
OCP\JSON::success(array(
|
|
||||||
'data' => array(
|
|
||||||
'id' => $id,
|
|
||||||
'aid' => $aid,
|
|
||||||
'details' => OCA\Contacts\VCard::structureContact($vcard),
|
|
||||||
'lastmodified' => $lastmodified->format('U')
|
|
||||||
)
|
|
||||||
));
|
|
@ -1,41 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* ownCloud - Addressbook
|
|
||||||
*
|
|
||||||
* @author Jakob Sack
|
|
||||||
* @copyright 2011 Jakob Sack mail@jakobsack.de
|
|
||||||
* @copyright 2012 Thomas Tanghus (thomas@tanghus.net)
|
|
||||||
*
|
|
||||||
* 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/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
// Check if we are a user
|
|
||||||
OCP\JSON::checkLoggedIn();
|
|
||||||
OCP\JSON::checkAppEnabled('contacts');
|
|
||||||
OCP\JSON::callCheck();
|
|
||||||
|
|
||||||
require_once __DIR__.'/../loghandler.php';
|
|
||||||
|
|
||||||
$id = isset($_POST['id']) ? $_POST['id'] : null;
|
|
||||||
if(!$id) {
|
|
||||||
bailOut(OCA\Contacts\App::$l10n->t('id is not set.'));
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
OCA\Contacts\VCard::delete($id);
|
|
||||||
} catch(Exception $e) {
|
|
||||||
bailOut($e->getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
OCP\JSON::success(array('data' => array( 'id' => $id )));
|
|
@ -1,73 +0,0 @@
|
|||||||
<?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/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Check if we are a user
|
|
||||||
OCP\JSON::checkLoggedIn();
|
|
||||||
OCP\JSON::checkAppEnabled('contacts');
|
|
||||||
OCP\JSON::callCheck();
|
|
||||||
|
|
||||||
require_once __DIR__.'/../loghandler.php';
|
|
||||||
|
|
||||||
$id = isset($_POST['id']) ? $_POST['id'] : null;
|
|
||||||
$name = isset($_POST['name']) ? $_POST['name'] : null;
|
|
||||||
$checksum = isset($_POST['checksum']) ? $_POST['checksum'] : null;
|
|
||||||
$l10n = OCA\Contacts\App::$l10n;
|
|
||||||
|
|
||||||
$multi_properties = array('EMAIL', 'TEL', 'IMPP', 'ADR', 'URL');
|
|
||||||
|
|
||||||
if(!$id) {
|
|
||||||
bailOut(OCA\Contacts\App::$l10n->t('id is not set.'));
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!$name) {
|
|
||||||
bailOut(OCA\Contacts\App::$l10n->t('element name is not set.'));
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!$checksum && in_array($name, $multi_properties)) {
|
|
||||||
bailOut(OCA\Contacts\App::$l10n->t('checksum is not set.'));
|
|
||||||
}
|
|
||||||
|
|
||||||
$vcard = OCA\Contacts\App::getContactVCard( $id );
|
|
||||||
|
|
||||||
if(!is_null($checksum)) {
|
|
||||||
$line = OCA\Contacts\App::getPropertyLineByChecksum($vcard, $checksum);
|
|
||||||
if(is_null($line)) {
|
|
||||||
bailOut($l10n->t('Information about vCard is incorrect. Please reload the page.'));
|
|
||||||
exit();
|
|
||||||
}
|
|
||||||
unset($vcard->children[$line]);
|
|
||||||
} else {
|
|
||||||
unset($vcard->{$name});
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
OCA\Contacts\VCard::edit($id, $vcard);
|
|
||||||
} catch(Exception $e) {
|
|
||||||
bailOut($e->getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
OCP\JSON::success(array(
|
|
||||||
'data' => array(
|
|
||||||
'id' => $id,
|
|
||||||
'lastmodified' => OCA\Contacts\App::lastModified($vcard)->format('U'),
|
|
||||||
)
|
|
||||||
));
|
|
@ -23,10 +23,10 @@ $aid = isset($_GET['aid'])?$_GET['aid']:null;
|
|||||||
$active_addressbooks = array();
|
$active_addressbooks = array();
|
||||||
if(is_null($aid)) {
|
if(is_null($aid)) {
|
||||||
// Called initially to get the active addressbooks.
|
// Called initially to get the active addressbooks.
|
||||||
$active_addressbooks = OCA\Contacts\Addressbook::active(OCP\USER::getUser());
|
$active_addressbooks = OCA\Contacts\AddressbookLegacy::active(OCP\USER::getUser());
|
||||||
} else {
|
} else {
|
||||||
// called each time more contacts has to be shown.
|
// called each time more contacts has to be shown.
|
||||||
$active_addressbooks = array(OCA\Contacts\Addressbook::find($aid));
|
$active_addressbooks = array(OCA\Contacts\AddressbookLegacy::find($aid));
|
||||||
}
|
}
|
||||||
|
|
||||||
$lastModified = OCA\Contacts\App::lastModified();
|
$lastModified = OCA\Contacts\App::lastModified();
|
||||||
@ -42,18 +42,6 @@ $contacts_addressbook = array();
|
|||||||
$ids = array();
|
$ids = array();
|
||||||
foreach($active_addressbooks as $addressbook) {
|
foreach($active_addressbooks as $addressbook) {
|
||||||
$ids[] = $addressbook['id'];
|
$ids[] = $addressbook['id'];
|
||||||
/*if(!isset($contacts_addressbook[$addressbook['id']])) {
|
|
||||||
$contacts_addressbook[$addressbook['id']]
|
|
||||||
= array('contacts' => array('type' => 'book',));
|
|
||||||
$contacts_addressbook[$addressbook['id']]['displayname']
|
|
||||||
= $addressbook['displayname'];
|
|
||||||
$contacts_addressbook[$addressbook['id']]['description']
|
|
||||||
= $addressbook['description'];
|
|
||||||
$contacts_addressbook[$addressbook['id']]['permissions']
|
|
||||||
= $addressbook['permissions'];
|
|
||||||
$contacts_addressbook[$addressbook['id']]['owner']
|
|
||||||
= $addressbook['userid'];
|
|
||||||
}*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$contacts_alphabet = array();
|
$contacts_alphabet = array();
|
||||||
@ -63,14 +51,6 @@ $contacts_alphabet = array_merge(
|
|||||||
$contacts_alphabet,
|
$contacts_alphabet,
|
||||||
OCA\Contacts\VCard::all($ids)
|
OCA\Contacts\VCard::all($ids)
|
||||||
);
|
);
|
||||||
/*foreach($ids as $id) {
|
|
||||||
if($id) {
|
|
||||||
$contacts_alphabet = array_merge(
|
|
||||||
$contacts_alphabet,
|
|
||||||
OCA\Contacts\VCard::all($id, $offset, 50)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
|
|
||||||
uasort($contacts_alphabet, 'cmp');
|
uasort($contacts_alphabet, 'cmp');
|
||||||
|
|
||||||
@ -89,38 +69,11 @@ if($contacts_alphabet) {
|
|||||||
'data' => $details,
|
'data' => $details,
|
||||||
);
|
);
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
|
\OCP\Util::writeLog('contacts', 'Exception: ' . $e->getMessage(), \OCP\Util::DEBUG);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// This should never execute.
|
|
||||||
/*if(!isset($contacts_addressbook[$contact['addressbookid']])) {
|
|
||||||
$contacts_addressbook[$contact['addressbookid']] = array(
|
|
||||||
'contacts' => array('type' => 'book',)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
$display = trim($contact['fullname']);
|
|
||||||
if(!$display) {
|
|
||||||
$vcard = OCA\Contacts\App::getContactVCard($contact['id']);
|
|
||||||
if(!is_null($vcard)) {
|
|
||||||
$struct = OCA\Contacts\VCard::structureContact($vcard);
|
|
||||||
$display = isset($struct['EMAIL'][0])
|
|
||||||
? $struct['EMAIL'][0]['value']
|
|
||||||
: '[UNKNOWN]';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$contacts_addressbook[$contact['addressbookid']]['contacts'][] = array(
|
|
||||||
'type' => 'contact',
|
|
||||||
'id' => $contact['id'],
|
|
||||||
'addressbookid' => $contact['addressbookid'],
|
|
||||||
'displayname' => htmlspecialchars($display),
|
|
||||||
'permissions' =>
|
|
||||||
isset($contacts_addressbook[$contact['addressbookid']]['permissions'])
|
|
||||||
? $contacts_addressbook[$contact['addressbookid']]['permissions']
|
|
||||||
: '0',
|
|
||||||
);*/
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//unset($contacts_alphabet);
|
|
||||||
//uasort($contacts, 'cmp');
|
|
||||||
|
|
||||||
OCP\JSON::success(array(
|
OCP\JSON::success(array(
|
||||||
'data' => array(
|
'data' => array(
|
||||||
|
@ -1,260 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* ownCloud - Addressbook
|
|
||||||
*
|
|
||||||
* @author Thomas Tanghus
|
|
||||||
* @copyright 2012 Thomas Tanghus <thomas@tanghus.net>
|
|
||||||
*
|
|
||||||
* 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;
|
|
||||||
use Sabre\VObject as VObject;
|
|
||||||
|
|
||||||
require_once __DIR__.'/../loghandler.php';
|
|
||||||
|
|
||||||
function setParameters($property, $parameters, $reset = false) {
|
|
||||||
if(!$parameters) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if($reset) {
|
|
||||||
$property->parameters = array();
|
|
||||||
}
|
|
||||||
debug('Setting parameters: ' . print_r($parameters, true));
|
|
||||||
foreach($parameters as $key => $parameter) {
|
|
||||||
debug('Adding parameter: ' . $key);
|
|
||||||
if(is_array($parameter)) {
|
|
||||||
foreach($parameter as $val) {
|
|
||||||
if(is_array($val)) {
|
|
||||||
foreach($val as $val2) {
|
|
||||||
if(trim($key) && trim($val2)) {
|
|
||||||
debug('Adding parameter: '.$key.'=>'.print_r($val2, true));
|
|
||||||
$property->add($key, strip_tags($val2));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if(trim($key) && trim($val)) {
|
|
||||||
debug('Adding parameter: '.$key.'=>'.print_r($val, true));
|
|
||||||
$property->add($key, strip_tags($val));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if(trim($key) && trim($val)) {
|
|
||||||
debug('Adding parameter: '.$key.'=>'.print_r($val, true));
|
|
||||||
$property->add($key, strip_tags($parameter));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if we are a user
|
|
||||||
\OCP\JSON::checkLoggedIn();
|
|
||||||
\OCP\JSON::checkAppEnabled('contacts');
|
|
||||||
\OCP\JSON::callCheck();
|
|
||||||
$id = isset($_POST['id'])?$_POST['id']:null;
|
|
||||||
$name = isset($_POST['name'])?$_POST['name']:null;
|
|
||||||
$value = isset($_POST['value'])?$_POST['value']:null;
|
|
||||||
$parameters = isset($_POST['parameters'])?$_POST['parameters']:null;
|
|
||||||
$checksum = isset($_POST['checksum'])?$_POST['checksum']:null;
|
|
||||||
|
|
||||||
debug('value: ' . print_r($value, 1));
|
|
||||||
|
|
||||||
$multi_properties = array('EMAIL', 'TEL', 'IMPP', 'ADR', 'URL');
|
|
||||||
|
|
||||||
if(!$name) {
|
|
||||||
bailOut(App::$l10n->t('element name is not set.'));
|
|
||||||
}
|
|
||||||
if(!$id) {
|
|
||||||
bailOut(App::$l10n->t('id is not set.'));
|
|
||||||
}
|
|
||||||
if(!$checksum && in_array($name, $multi_properties)) {
|
|
||||||
bailOut(App::$l10n->t('checksum is not set.'));
|
|
||||||
}
|
|
||||||
if(is_array($value)) {
|
|
||||||
$value = array_map('strip_tags', $value);
|
|
||||||
// NOTE: Important, otherwise the compound value will be
|
|
||||||
// set in the order the fields appear in the form!
|
|
||||||
ksort($value);
|
|
||||||
//if($name == 'CATEGORIES') {
|
|
||||||
// $value = VCard::escapeDelimiters($value, ',');
|
|
||||||
//} else {
|
|
||||||
// $value = VCard::escapeDelimiters($value, ';');
|
|
||||||
//}
|
|
||||||
} else {
|
|
||||||
$value = trim(strip_tags($value));
|
|
||||||
}
|
|
||||||
|
|
||||||
$vcard = App::getContactVCard($id);
|
|
||||||
if(!$vcard) {
|
|
||||||
bailOut(App::$l10n->t('Couldn\'t find vCard for %d.', array($id)));
|
|
||||||
}
|
|
||||||
|
|
||||||
$property = null;
|
|
||||||
|
|
||||||
if(in_array($name, $multi_properties)) {
|
|
||||||
if($checksum !== 'new') {
|
|
||||||
$line = App::getPropertyLineByChecksum($vcard, $checksum);
|
|
||||||
if(is_null($line)) {
|
|
||||||
bailOut(App::$l10n->t(
|
|
||||||
'Information about vCard is incorrect. Please reload the page: ').$checksum
|
|
||||||
);
|
|
||||||
}
|
|
||||||
$property = $vcard->children[$line];
|
|
||||||
$element = $property->name;
|
|
||||||
|
|
||||||
if($element != $name) {
|
|
||||||
bailOut(App::$l10n->t(
|
|
||||||
'Something went FUBAR. ').$name.' != '.$element
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Add new property
|
|
||||||
$element = $name;
|
|
||||||
if (!is_scalar($value)) {
|
|
||||||
$property = VObject\Property::create($name);
|
|
||||||
if(in_array($name, array('ADR',))) {
|
|
||||||
$property->setParts($value);
|
|
||||||
} else {
|
|
||||||
bailOut(App::$l10n->t(
|
|
||||||
'Cannot save property of type "%s" as array', array($name,)
|
|
||||||
));
|
|
||||||
}
|
|
||||||
setParameters($property, $parameters);
|
|
||||||
} else {
|
|
||||||
$property = VObject\Property::create($name, $value, $parameters);
|
|
||||||
}
|
|
||||||
$vcard->add($property);
|
|
||||||
$checksum = substr(md5($property->serialize()), 0, 8);
|
|
||||||
try {
|
|
||||||
VCard::edit($id, $vcard);
|
|
||||||
} catch(Exception $e) {
|
|
||||||
bailOut($e->getMessage());
|
|
||||||
}
|
|
||||||
\OCP\JSON::success(array('data' => array(
|
|
||||||
'checksum' => $checksum,
|
|
||||||
'oldchecksum' => $_POST['checksum'],
|
|
||||||
)));
|
|
||||||
exit();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$element = $name;
|
|
||||||
$property = $vcard->select($name);
|
|
||||||
if(count($property) === 0) {
|
|
||||||
$property = VObject\Property::create($name);
|
|
||||||
$vcard->add($property);
|
|
||||||
} else {
|
|
||||||
$property = array_shift($property);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* preprocessing value */
|
|
||||||
switch($element) {
|
|
||||||
case 'BDAY':
|
|
||||||
$date = New \DateTime($value);
|
|
||||||
$value = $date->format('Y-m-d');
|
|
||||||
break;
|
|
||||||
case 'FN':
|
|
||||||
if(!$value) {
|
|
||||||
// create a method thats returns an alternative for FN.
|
|
||||||
//$value = getOtherValue();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'NOTE':
|
|
||||||
$value = str_replace('\n', '\\n', $value);
|
|
||||||
break;
|
|
||||||
case 'EMAIL':
|
|
||||||
$value = strtolower($value);
|
|
||||||
break;
|
|
||||||
case 'IMPP':
|
|
||||||
if(is_null($parameters) || !isset($parameters['X-SERVICE-TYPE'])) {
|
|
||||||
bailOut(App::$l10n->t('Missing IM parameter.'));
|
|
||||||
}
|
|
||||||
$impp = App::getIMOptions($parameters['X-SERVICE-TYPE']);
|
|
||||||
if(is_null($impp)) {
|
|
||||||
bailOut(App::$l10n->t('Unknown IM: '.$parameters['X-SERVICE-TYPE']));
|
|
||||||
}
|
|
||||||
$value = $impp['protocol'] . ':' . $value;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If empty remove the property
|
|
||||||
if(!$value) {
|
|
||||||
if(in_array($name, $multi_properties)) {
|
|
||||||
unset($vcard->children[$line]);
|
|
||||||
$checksum = '';
|
|
||||||
} else {
|
|
||||||
unset($vcard->{$name});
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/* setting value */
|
|
||||||
switch($element) {
|
|
||||||
case 'BDAY':
|
|
||||||
$vcard->BDAY = $value;
|
|
||||||
|
|
||||||
if(!isset($vcard->BDAY['VALUE'])) {
|
|
||||||
$vcard->BDAY->add('VALUE', 'DATE');
|
|
||||||
} else {
|
|
||||||
$vcard->BDAY->VALUE = 'DATE';
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'ADR':
|
|
||||||
case 'N':
|
|
||||||
if(is_array($value)) {
|
|
||||||
$property->setParts($value);
|
|
||||||
} else {
|
|
||||||
debug('Saving N ' . $value);
|
|
||||||
$vcard->N = $value;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'EMAIL':
|
|
||||||
case 'TEL':
|
|
||||||
case 'IMPP':
|
|
||||||
case 'URL':
|
|
||||||
debug('Setting element: (EMAIL/TEL/ADR)'.$element);
|
|
||||||
$property->setValue($value);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
$vcard->{$name} = $value;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
setParameters($property, $parameters, true);
|
|
||||||
|
|
||||||
// Do checksum and be happy
|
|
||||||
if(in_array($name, $multi_properties)) {
|
|
||||||
$checksum = substr(md5($property->serialize()), 0, 8);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//debug('New checksum: '.$checksum);
|
|
||||||
//$vcard->children[$line] = $property; ???
|
|
||||||
try {
|
|
||||||
VCard::edit($id, $vcard);
|
|
||||||
} catch(Exception $e) {
|
|
||||||
bailOut($e->getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
if(in_array($name, $multi_properties)) {
|
|
||||||
\OCP\JSON::success(array('data' => array(
|
|
||||||
'line' => $line,
|
|
||||||
'checksum' => $checksum,
|
|
||||||
'oldchecksum' => $_POST['checksum'],
|
|
||||||
'lastmodified' => App::lastModified($vcard)->format('U'),
|
|
||||||
)));
|
|
||||||
} else {
|
|
||||||
\OCP\JSON::success(array('data' => array(
|
|
||||||
'lastmodified' => App::lastModified($vcard)->format('U'),
|
|
||||||
)));
|
|
||||||
}
|
|
@ -20,22 +20,39 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
namespace OCA\Contacts;
|
||||||
|
|
||||||
// Firefox and Konqueror tries to download application/json for me. --Arthur
|
// Firefox and Konqueror tries to download application/json for me. --Arthur
|
||||||
OCP\JSON::setContentTypeHeader('text/plain');
|
\OCP\JSON::setContentTypeHeader('text/plain');
|
||||||
OCP\JSON::checkLoggedIn();
|
\OCP\JSON::checkLoggedIn();
|
||||||
OCP\JSON::checkAppEnabled('contacts');
|
\OCP\JSON::checkAppEnabled('contacts');
|
||||||
require_once 'loghandler.php';
|
require_once 'loghandler.php';
|
||||||
|
|
||||||
if (!isset($_GET['id'])) {
|
$contactid = isset($_GET['contactid']) ? $_GET['contactid'] : '';
|
||||||
bailOut(OCA\Contacts\App::$l10n->t('No contact ID was submitted.'));
|
$addressbookid = isset($_GET['addressbookid']) ? $_GET['addressbookid'] : '';
|
||||||
|
$backend = isset($_GET['backend']) ? $_GET['backend'] : '';
|
||||||
|
|
||||||
|
if(!$contactid) {
|
||||||
|
bailOut('Missing contact id.');
|
||||||
}
|
}
|
||||||
|
|
||||||
$contact = OCA\Contacts\App::getContactVCard($_GET['id']);
|
if(!$addressbookid) {
|
||||||
|
bailOut('Missing address book id.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$app = new App();
|
||||||
|
// FIXME: Get backend and addressbookid
|
||||||
|
$contact = $app->getContact($backend, $addressbookid, $contactid);
|
||||||
|
if(!$contact) {
|
||||||
|
\OC_Cache::remove($tmpkey);
|
||||||
|
bailOut(App::$l10n
|
||||||
|
->t('Error getting contact object.'));
|
||||||
|
}
|
||||||
// invalid vcard
|
// invalid vcard
|
||||||
if( is_null($contact)) {
|
if(!$contact) {
|
||||||
bailOut(OCA\Contacts\App::$l10n->t('Error reading contact photo.'));
|
bailOut(App::$l10n->t('Error reading contact photo.'));
|
||||||
} else {
|
} else {
|
||||||
$image = new OC_Image();
|
$image = new \OC_Image();
|
||||||
if(!isset($contact->PHOTO) || !$image->loadFromBase64((string)$contact->PHOTO)) {
|
if(!isset($contact->PHOTO) || !$image->loadFromBase64((string)$contact->PHOTO)) {
|
||||||
if(isset($contact->LOGO)) {
|
if(isset($contact->LOGO)) {
|
||||||
$image->loadFromBase64((string)$contact->LOGO);
|
$image->loadFromBase64((string)$contact->LOGO);
|
||||||
@ -43,13 +60,13 @@ if( is_null($contact)) {
|
|||||||
}
|
}
|
||||||
if($image->valid()) {
|
if($image->valid()) {
|
||||||
$tmpkey = 'contact-photo-'.$contact->UID;
|
$tmpkey = 'contact-photo-'.$contact->UID;
|
||||||
if(OC_Cache::set($tmpkey, $image->data(), 600)) {
|
if(\OC_Cache::set($tmpkey, $image->data(), 600)) {
|
||||||
OCP\JSON::success(array('data' => array('id'=>$_GET['id'], 'tmp'=>$tmpkey)));
|
\OCP\JSON::success(array('data' => array('id'=>$_GET['id'], 'tmp'=>$tmpkey)));
|
||||||
exit();
|
exit();
|
||||||
} else {
|
} else {
|
||||||
bailOut(OCA\Contacts\App::$l10n->t('Error saving temporary file.'));
|
bailOut(App::$l10n->t('Error saving temporary file.'));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
bailOut(OCA\Contacts\App::$l10n->t('The loading photo is not valid.'));
|
bailOut(App::$l10n->t('The loading photo is not valid.'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,41 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* Copyright (c) 2011 Thomas Tanghus <thomas@tanghus.net>
|
|
||||||
* This file is licensed under the Affero General Public License version 3 or
|
|
||||||
* later.
|
|
||||||
* See the COPYING-README file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
OCP\JSON::checkLoggedIn();
|
|
||||||
OCP\JSON::checkAppEnabled('contacts');
|
|
||||||
|
|
||||||
$id = $_GET['id'];
|
|
||||||
$checksum = isset($_GET['checksum'])?$_GET['checksum']:'';
|
|
||||||
$vcard = OCA\Contacts\App::getContactVCard($id);
|
|
||||||
$adr_types = OCA\Contacts\App::getTypesOfProperty('ADR');
|
|
||||||
|
|
||||||
$tmpl = new OCP\Template("contacts", "part.edit_address_dialog");
|
|
||||||
if($checksum) {
|
|
||||||
$line = OCA\Contacts\App::getPropertyLineByChecksum($vcard, $checksum);
|
|
||||||
$element = $vcard->children[$line];
|
|
||||||
$adr = OCA\Contacts\VCard::structureProperty($element);
|
|
||||||
$types = array();
|
|
||||||
if(isset($adr['parameters']['TYPE'])) {
|
|
||||||
if(is_array($adr['parameters']['TYPE'])) {
|
|
||||||
$types = array_map('htmlspecialchars', $adr['parameters']['TYPE']);
|
|
||||||
$types = array_map('strtoupper', $types);
|
|
||||||
} else {
|
|
||||||
$types = array(strtoupper(htmlspecialchars($adr['parameters']['TYPE'])));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$tmpl->assign('types', $types, false);
|
|
||||||
$adr = array_map('htmlspecialchars', $adr['value']);
|
|
||||||
$tmpl->assign('adr', $adr, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
$tmpl->assign('id', $id);
|
|
||||||
$tmpl->assign('adr_types', $adr_types);
|
|
||||||
|
|
||||||
$page = $tmpl->fetchPage();
|
|
||||||
OCP\JSON::success(array('data' => array('page'=>$page, 'checksum'=>$checksum)));
|
|
@ -1,34 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* Copyright (c) 2011 Thomas Tanghus <thomas@tanghus.net>
|
|
||||||
* This file is licensed under the Affero General Public License version 3 or
|
|
||||||
* later.
|
|
||||||
* See the COPYING-README file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
OCP\JSON::checkLoggedIn();
|
|
||||||
OCP\JSON::checkAppEnabled('contacts');
|
|
||||||
require_once 'loghandler.php';
|
|
||||||
|
|
||||||
$tmpl = new OCP\Template("contacts", "part.edit_name_dialog");
|
|
||||||
|
|
||||||
$id = isset($_GET['id'])?$_GET['id']:'';
|
|
||||||
|
|
||||||
if($id) {
|
|
||||||
$vcard = OCA\Contacts\App::getContactVCard($id);
|
|
||||||
$name = array('', '', '', '', '');
|
|
||||||
if($vcard->__isset('N')) {
|
|
||||||
$property = $vcard->__get('N');
|
|
||||||
if($property) {
|
|
||||||
$name = OCA\Contacts\VCard::structureProperty($property);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$name = array_map('htmlspecialchars', $name['value']);
|
|
||||||
$tmpl->assign('name', $name, false);
|
|
||||||
$tmpl->assign('id', $id, false);
|
|
||||||
} else {
|
|
||||||
bailOut(OCA\Contacts\App::$l10n->t('Contact ID is missing.'));
|
|
||||||
}
|
|
||||||
$page = $tmpl->fetchPage();
|
|
||||||
OCP\JSON::success(array('data' => array('page'=>$page)));
|
|
@ -1,15 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* Copyright (c) 2012 Georg Ehrke <ownclouddev at georgswebsite dot de>
|
|
||||||
* This file is licensed under the Affero General Public License version 3 or
|
|
||||||
* later.
|
|
||||||
* See the COPYING-README file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
OCP\JSON::checkLoggedIn();
|
|
||||||
OCP\App::checkAppEnabled('contacts');
|
|
||||||
$tmpl = new OCP\Template('contacts', 'part.import');
|
|
||||||
$tmpl->assign('path', $_POST['path']);
|
|
||||||
$tmpl->assign('filename', $_POST['filename']);
|
|
||||||
$tmpl->printpage();
|
|
@ -24,8 +24,8 @@ OCP\JSON::checkLoggedIn();
|
|||||||
OCP\JSON::checkAppEnabled('contacts');
|
OCP\JSON::checkAppEnabled('contacts');
|
||||||
require_once 'loghandler.php';
|
require_once 'loghandler.php';
|
||||||
|
|
||||||
if(!isset($_GET['id'])) {
|
if(!isset($_GET['contact'])) {
|
||||||
bailOut(OCA\Contacts\App::$l10n->t('No contact ID was submitted.'));
|
bailOut(OCA\Contacts\App::$l10n->t('No contact info was submitted.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!isset($_GET['path'])) {
|
if(!isset($_GET['path'])) {
|
||||||
@ -33,7 +33,7 @@ if(!isset($_GET['path'])) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$localpath = \OC\Files\Filesystem::getLocalFile($_GET['path']);
|
$localpath = \OC\Files\Filesystem::getLocalFile($_GET['path']);
|
||||||
$tmpkey = 'contact-photo-'.$_GET['id'];
|
$tmpkey = 'contact-photo-'.$_GET['contact']['contactid'];
|
||||||
|
|
||||||
if(!file_exists($localpath)) {
|
if(!file_exists($localpath)) {
|
||||||
bailOut(OCA\Contacts\App::$l10n->t('File doesn\'t exist:').$localpath);
|
bailOut(OCA\Contacts\App::$l10n->t('File doesn\'t exist:').$localpath);
|
||||||
@ -55,7 +55,7 @@ if(!$image->fixOrientation()) { // No fatal error so we don't bail out.
|
|||||||
OCP\Util::DEBUG);
|
OCP\Util::DEBUG);
|
||||||
}
|
}
|
||||||
if(OC_Cache::set($tmpkey, $image->data(), 600)) {
|
if(OC_Cache::set($tmpkey, $image->data(), 600)) {
|
||||||
OCP\JSON::success(array('data' => array('id'=>$_GET['id'], 'tmp'=>$tmpkey)));
|
OCP\JSON::success(array('data' => array('id'=>$_GET['contact']['contactid'], 'tmp'=>$tmpkey)));
|
||||||
exit();
|
exit();
|
||||||
} else {
|
} else {
|
||||||
bailOut('Couldn\'t save temporary image: '.$tmpkey);
|
bailOut('Couldn\'t save temporary image: '.$tmpkey);
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
* ownCloud - Addressbook
|
* ownCloud - Addressbook
|
||||||
*
|
*
|
||||||
* @author Thomas Tanghus
|
* @author Thomas Tanghus
|
||||||
* @copyright 2012 Thomas Tanghus <thomas@tanghus.net>
|
* @copyright 2012-13 Thomas Tanghus <thomas@tanghus.net>
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||||
@ -19,13 +19,13 @@
|
|||||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
// Check if we are a user
|
|
||||||
OCP\JSON::checkLoggedIn();
|
|
||||||
OCP\JSON::checkAppEnabled('contacts');
|
|
||||||
OCP\JSON::callCheck();
|
|
||||||
|
|
||||||
// Firefox and Konqueror tries to download application/json for me. --Arthur
|
namespace OCA\Contacts;
|
||||||
OCP\JSON::setContentTypeHeader('text/plain; charset=utf-8');
|
|
||||||
|
// Check if we are a user
|
||||||
|
\OCP\JSON::checkLoggedIn();
|
||||||
|
\OCP\JSON::checkAppEnabled('contacts');
|
||||||
|
\OCP\JSON::callCheck();
|
||||||
|
|
||||||
require_once 'loghandler.php';
|
require_once 'loghandler.php';
|
||||||
|
|
||||||
@ -38,92 +38,101 @@ $y1 = (isset($_POST['y1']) && $_POST['y1']) ? $_POST['y1'] : 0;
|
|||||||
$w = (isset($_POST['w']) && $_POST['w']) ? $_POST['w'] : -1;
|
$w = (isset($_POST['w']) && $_POST['w']) ? $_POST['w'] : -1;
|
||||||
$h = (isset($_POST['h']) && $_POST['h']) ? $_POST['h'] : -1;
|
$h = (isset($_POST['h']) && $_POST['h']) ? $_POST['h'] : -1;
|
||||||
$tmpkey = isset($_POST['tmpkey']) ? $_POST['tmpkey'] : '';
|
$tmpkey = isset($_POST['tmpkey']) ? $_POST['tmpkey'] : '';
|
||||||
$id = isset($_POST['id']) ? $_POST['id'] : '';
|
|
||||||
|
$contactid = isset($_POST['contactid']) ? $_POST['contactid'] : '';
|
||||||
|
$addressbookid = isset($_POST['addressbookid']) ? $_POST['addressbookid'] : '';
|
||||||
|
$backend = isset($_POST['backend']) ? $_POST['backend'] : '';
|
||||||
|
|
||||||
if($tmpkey == '') {
|
if($tmpkey == '') {
|
||||||
bailOut('Missing key to temporary file.');
|
bailOut('Missing key to temporary file.');
|
||||||
}
|
}
|
||||||
|
|
||||||
if($id == '') {
|
if($contactid == '') {
|
||||||
bailOut('Missing contact id.');
|
bailOut('Missing contact id.');
|
||||||
}
|
}
|
||||||
|
|
||||||
OCP\Util::writeLog('contacts', 'savecrop.php: key: '.$tmpkey, OCP\Util::DEBUG);
|
if($addressbookid == '') {
|
||||||
|
bailOut('Missing address book id.');
|
||||||
|
}
|
||||||
|
|
||||||
$data = OC_Cache::get($tmpkey);
|
\OCP\Util::writeLog('contacts', 'savecrop.php: key: '.$tmpkey, \OCP\Util::DEBUG);
|
||||||
|
|
||||||
|
$app = new App();
|
||||||
|
// FIXME: Get backend and addressbookid
|
||||||
|
$contact = $app->getContact($backend, $addressbookid, $contactid);
|
||||||
|
if(!$contact) {
|
||||||
|
\OC_Cache::remove($tmpkey);
|
||||||
|
bailOut(App::$l10n
|
||||||
|
->t('Error getting contact object.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = \OC_Cache::get($tmpkey);
|
||||||
if($data) {
|
if($data) {
|
||||||
$image = new OC_Image();
|
$image = new \OC_Image();
|
||||||
if($image->loadFromData($data)) {
|
if($image->loadFromData($data)) {
|
||||||
$w = ($w != -1 ? $w : $image->width());
|
$w = ($w != -1 ? $w : $image->width());
|
||||||
$h = ($h != -1 ? $h : $image->height());
|
$h = ($h != -1 ? $h : $image->height());
|
||||||
OCP\Util::writeLog('contacts',
|
\OCP\Util::writeLog('contacts',
|
||||||
'savecrop.php, x: '.$x1.' y: '.$y1.' w: '.$w.' h: '.$h,
|
'savecrop.php, x: '.$x1.' y: '.$y1.' w: '.$w.' h: '.$h,
|
||||||
OCP\Util::DEBUG);
|
\OCP\Util::DEBUG);
|
||||||
if($image->crop($x1, $y1, $w, $h)) {
|
if($image->crop($x1, $y1, $w, $h)) {
|
||||||
if(($image->width() <= 200 && $image->height() <= 200)
|
if(($image->width() <= 200 && $image->height() <= 200)
|
||||||
|| $image->resize(200)) {
|
|| $image->resize(200)) {
|
||||||
|
|
||||||
$vcard = OCA\Contacts\App::getContactVCard($id);
|
// For vCard 3.0 the type must be e.g. JPEG or PNG
|
||||||
if(!$vcard) {
|
// For version 4.0 the full mimetype should be used.
|
||||||
OC_Cache::remove($tmpkey);
|
// https://tools.ietf.org/html/rfc2426#section-3.1.4
|
||||||
bailOut(OCA\Contacts\App::$l10n
|
$type = strval($contact->VERSION) === '4.0'
|
||||||
->t('Error getting contact object.'));
|
? $image->mimeType()
|
||||||
}
|
: strtoupper(array_pop(explode('/', $image->mimeType())));
|
||||||
if($vcard->__isset('PHOTO')) {
|
if(isset($contact->PHOTO)) {
|
||||||
OCP\Util::writeLog('contacts',
|
\OCP\Util::writeLog('contacts',
|
||||||
'savecrop.php: PHOTO property exists.',
|
'savecrop.php: PHOTO property exists.',
|
||||||
OCP\Util::DEBUG);
|
\OCP\Util::DEBUG);
|
||||||
$property = $vcard->__get('PHOTO');
|
$property = $contact->PHOTO;
|
||||||
if(!$property) {
|
if(!$property) {
|
||||||
OC_Cache::remove($tmpkey);
|
\OC_Cache::remove($tmpkey);
|
||||||
bailOut(OCA\Contacts\App::$l10n
|
bailOut(App::$l10n
|
||||||
->t('Error getting PHOTO property.'));
|
->t('Error getting PHOTO property.'));
|
||||||
}
|
}
|
||||||
$property->setValue($image->__toString());
|
$property->setValue(strval($image));
|
||||||
|
$property->parameters = [];
|
||||||
|
/*$property->ENCODING = 'b';
|
||||||
|
$property->TYPE = $type;*/
|
||||||
$property->parameters[]
|
$property->parameters[]
|
||||||
= new Sabre\VObject\Parameter('ENCODING', 'b');
|
= new \Sabre\VObject\Parameter('ENCODING', 'b');
|
||||||
$property->parameters[]
|
$property->parameters[]
|
||||||
= new Sabre\VObject\Parameter('TYPE', $image->mimeType());
|
= new \Sabre\VObject\Parameter('TYPE', $image->mimeType());
|
||||||
$vcard->__set('PHOTO', $property);
|
$contact->PHOTO = $property;
|
||||||
} else {
|
} else {
|
||||||
OCP\Util::writeLog('contacts',
|
\OCP\Util::writeLog('contacts',
|
||||||
'savecrop.php: files: Adding PHOTO property.',
|
'savecrop.php: files: Adding PHOTO property.',
|
||||||
OCP\Util::DEBUG);
|
\OCP\Util::DEBUG);
|
||||||
// For vCard 3.0 the type must be e.g. JPEG or PNG
|
$contact->add('PHOTO',
|
||||||
// For version 4.0 the full mimetype should be used.
|
strval($image), array('ENCODING' => 'b',
|
||||||
// https://tools.ietf.org/html/rfc2426#section-3.1.4
|
|
||||||
$type = $vcard->VERSION == '4.0'
|
|
||||||
? $image->mimeType()
|
|
||||||
: strtoupper(array_pop(explode('/', $image->mimeType())));
|
|
||||||
$vcard->add('PHOTO',
|
|
||||||
$image->__toString(), array('ENCODING' => 'b',
|
|
||||||
'TYPE' => $type));
|
'TYPE' => $type));
|
||||||
}
|
}
|
||||||
$now = new DateTime;
|
if(!$contact->save()) {
|
||||||
$vcard->{'REV'} = $now->format(DateTime::W3C);
|
bailOut(App::$l10n->t('Error saving contact.'));
|
||||||
if(!OCA\Contacts\VCard::edit($id, $vcard)) {
|
|
||||||
bailOut(OCA\Contacts\App::$l10n->t('Error saving contact.'));
|
|
||||||
}
|
}
|
||||||
OCA\Contacts\App::cacheThumbnail($id, $image);
|
$thumbnail = $contact->cacheThumbnail($image);
|
||||||
OCP\JSON::success(array(
|
\OCP\JSON::success(array(
|
||||||
'data' => array(
|
'data' => array(
|
||||||
'id' => $id,
|
'id' => $contactid,
|
||||||
'width' => $image->width(),
|
'thumbnail' => $thumbnail,
|
||||||
'height' => $image->height(),
|
|
||||||
'lastmodified' => OCA\Contacts\App::lastModified($vcard)->format('U')
|
|
||||||
)
|
)
|
||||||
));
|
));
|
||||||
} else {
|
} else {
|
||||||
bailOut(OCA\Contacts\App::$l10n->t('Error resizing image'));
|
bailOut(App::$l10n->t('Error resizing image'));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
bailOut(OCA\Contacts\App::$l10n->t('Error cropping image'));
|
bailOut(App::$l10n->t('Error cropping image'));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
bailOut(OCA\Contacts\App::$l10n->t('Error creating temporary image'));
|
bailOut(App::$l10n->t('Error creating temporary image'));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
bailOut(OCA\Contacts\App::$l10n->t('Error finding image: ').$tmpkey);
|
bailOut(App::$l10n->t('Error finding image: ').$tmpkey);
|
||||||
}
|
}
|
||||||
|
|
||||||
OC_Cache::remove($tmpkey);
|
\OC_Cache::remove($tmpkey);
|
||||||
|
@ -32,57 +32,48 @@ $view = OCP\Files::getStorage('contacts');
|
|||||||
if(!$view->file_exists('imports')) {
|
if(!$view->file_exists('imports')) {
|
||||||
$view->mkdir('imports');
|
$view->mkdir('imports');
|
||||||
}
|
}
|
||||||
$tmpfile = md5(rand());
|
|
||||||
|
|
||||||
// If it is a Drag'n'Drop transfer it's handled here.
|
|
||||||
$fn = (isset($_SERVER['HTTP_X_FILE_NAME']) ? $_SERVER['HTTP_X_FILE_NAME'] : false);
|
|
||||||
$fn = strtr($fn, array('/' => '', "\\" => ''));
|
|
||||||
if($fn) {
|
|
||||||
if(OC\Files\Filesystem::isFileBlacklisted($fn)) {
|
|
||||||
bailOut($l10n->t('Upload of blacklisted file:') . $fn);
|
|
||||||
}
|
|
||||||
if($view->file_put_contents('/imports/'.$fn, file_get_contents('php://input'))) {
|
|
||||||
OCP\JSON::success(array('data' => array('file'=>$tmpfile, 'name'=>$fn)));
|
|
||||||
exit();
|
|
||||||
} else {
|
|
||||||
bailOut($l10n->t('Error uploading contacts to storage.'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// File input transfers are handled here
|
// File input transfers are handled here
|
||||||
if (!isset($_FILES['importfile'])) {
|
if (!isset($_FILES['file'])) {
|
||||||
OCP\Util::writeLog('contacts',
|
bailOut($l10n->t('No file was uploaded. Unknown error'));
|
||||||
'ajax/uploadphoto.php: No file was uploaded. Unknown error.',
|
|
||||||
OCP\Util::DEBUG);
|
|
||||||
OCP\JSON::error(array('
|
|
||||||
data' => array(
|
|
||||||
'message' => 'No file was uploaded. Unknown error' )));
|
|
||||||
exit();
|
|
||||||
}
|
}
|
||||||
$error = $_FILES['importfile']['error'];
|
|
||||||
if($error !== UPLOAD_ERR_OK) {
|
$file=$_FILES['file'];
|
||||||
|
|
||||||
|
if($file['error'] !== UPLOAD_ERR_OK) {
|
||||||
$errors = array(
|
$errors = array(
|
||||||
0=>$l10n->t("There is no error, the file uploaded with success"),
|
UPLOAD_ERR_OK => $l10n->t("There is no error, the file uploaded with success"),
|
||||||
1=>$l10n->t("The uploaded file exceeds the upload_max_filesize directive in php.ini").ini_get('upload_max_filesize'),
|
UPLOAD_ERR_INI_SIZE => $l10n->t("The uploaded file exceeds the upload_max_filesize directive in php.ini")
|
||||||
2=>$l10n->t("The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form"),
|
.ini_get('upload_max_filesize'),
|
||||||
3=>$l10n->t("The uploaded file was only partially uploaded"),
|
UPLOAD_ERR_FORM_SIZE => $l10n->t("The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form"),
|
||||||
4=>$l10n->t("No file was uploaded"),
|
UPLOAD_ERR_PARTIAL => $l10n->t("The uploaded file was only partially uploaded"),
|
||||||
6=>$l10n->t("Missing a temporary folder")
|
UPLOAD_ERR_NO_FILE => $l10n->t("No file was uploaded"),
|
||||||
|
UPLOAD_ERR_NO_TMP_DIR => $l10n->t('Missing a temporary folder'),
|
||||||
|
UPLOAD_ERR_CANT_WRITE => $l10n->t('Failed to write to disk'),
|
||||||
);
|
);
|
||||||
bailOut($errors[$error]);
|
bailOut($errors[$error]);
|
||||||
}
|
}
|
||||||
$file=$_FILES['importfile'];
|
|
||||||
|
|
||||||
if(file_exists($file['tmp_name'])) {
|
$maxUploadFilesize = OCP\Util::maxUploadFilesize('/');
|
||||||
$filename = strtr($file['name'], array('/' => '', "\\" => ''));
|
$maxHumanFilesize = OCP\Util::humanFileSize($maxUploadFilesize);
|
||||||
|
|
||||||
|
$totalSize = $file['size'];
|
||||||
|
if ($maxUploadFilesize >= 0 and $totalSize > $maxUploadFilesize) {
|
||||||
|
bailOut($l10n->t('Not enough storage available'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$tmpname = $file['tmp_name'];
|
||||||
|
$filename = strtr($file['name'], array('/' => '', "\\" => ''));
|
||||||
|
if(is_uploaded_file($tmpname)) {
|
||||||
if(OC\Files\Filesystem::isFileBlacklisted($filename)) {
|
if(OC\Files\Filesystem::isFileBlacklisted($filename)) {
|
||||||
bailOut($l10n->t('Upload of blacklisted file:') . $filename);
|
bailOut($l10n->t('Upload of blacklisted file:') . $filename);
|
||||||
}
|
}
|
||||||
if($view->file_put_contents('/imports/'.$filename, file_get_contents($file['tmp_name']))) {
|
if($view->file_put_contents('/imports/'.$filename, file_get_contents($tmpname))) {
|
||||||
OCP\JSON::success(array('data' => array('file'=>$filename, 'name'=>$filename)));
|
OCP\JSON::success(array('file'=>$filename));
|
||||||
} else {
|
} else {
|
||||||
bailOut($l10n->t('Error uploading contacts to storage.'));
|
bailOut($l10n->t('Error uploading contacts to storage.'));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
bailOut('Temporary file: \''.$file['tmp_name'].'\' has gone AWOL?');
|
bailOut('Temporary file: \''.$tmpname.'\' has gone AWOL?');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,13 +29,22 @@ OCP\JSON::callCheck();
|
|||||||
OCP\JSON::setContentTypeHeader('text/plain; charset=utf-8');
|
OCP\JSON::setContentTypeHeader('text/plain; charset=utf-8');
|
||||||
require_once 'loghandler.php';
|
require_once 'loghandler.php';
|
||||||
$l10n = OCA\Contacts\App::$l10n;
|
$l10n = OCA\Contacts\App::$l10n;
|
||||||
|
|
||||||
|
$contactid = isset($_POST['contactid']) ? $_POST['contactid'] : '';
|
||||||
|
$addressbookid = isset($_POST['addressbookid']) ? $_POST['addressbookid'] : '';
|
||||||
|
$backend = isset($_POST['backend']) ? $_POST['backend'] : '';
|
||||||
|
|
||||||
|
if($contactid == '') {
|
||||||
|
bailOut('Missing contact id.');
|
||||||
|
}
|
||||||
|
|
||||||
|
if($addressbookid == '') {
|
||||||
|
bailOut('Missing address book id.');
|
||||||
|
}
|
||||||
|
|
||||||
// If it is a Drag'n'Drop transfer it's handled here.
|
// If it is a Drag'n'Drop transfer it's handled here.
|
||||||
$fn = (isset($_SERVER['HTTP_X_FILE_NAME']) ? $_SERVER['HTTP_X_FILE_NAME'] : false);
|
$fn = (isset($_SERVER['HTTP_X_FILE_NAME']) ? $_SERVER['HTTP_X_FILE_NAME'] : false);
|
||||||
if ($fn) {
|
if ($fn) {
|
||||||
if (!isset($_GET['id'])) {
|
|
||||||
bailOut($l10n->t('No contact ID was submitted.'));
|
|
||||||
}
|
|
||||||
$id = $_GET['id'];
|
|
||||||
$tmpkey = 'contact-photo-'.md5($fn);
|
$tmpkey = 'contact-photo-'.md5($fn);
|
||||||
$data = file_get_contents('php://input');
|
$data = file_get_contents('php://input');
|
||||||
$image = new OC_Image();
|
$image = new OC_Image();
|
||||||
@ -50,10 +59,14 @@ if ($fn) {
|
|||||||
if(OC_Cache::set($tmpkey, $image->data(), 600)) {
|
if(OC_Cache::set($tmpkey, $image->data(), 600)) {
|
||||||
OCP\JSON::success(array(
|
OCP\JSON::success(array(
|
||||||
'data' => array(
|
'data' => array(
|
||||||
'mime'=>$_SERVER['CONTENT_TYPE'],
|
'mime'=> $_SERVER['CONTENT_TYPE'],
|
||||||
'name'=>$fn,
|
'name'=> $fn,
|
||||||
'id'=>$id,
|
'contactid'=> $id,
|
||||||
'tmp'=>$tmpkey)));
|
'addressbookid'=> addressbookid,
|
||||||
|
'backend'=> $backend,
|
||||||
|
'tmp'=>$tmpkey
|
||||||
|
))
|
||||||
|
);
|
||||||
exit();
|
exit();
|
||||||
} else {
|
} else {
|
||||||
bailOut($l10n->t('Couldn\'t save temporary image: ').$tmpkey);
|
bailOut($l10n->t('Couldn\'t save temporary image: ').$tmpkey);
|
||||||
@ -63,10 +76,6 @@ if ($fn) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Uploads from file dialog are handled here.
|
|
||||||
if (!isset($_POST['id'])) {
|
|
||||||
bailOut($l10n->t('No contact ID was submitted.'));
|
|
||||||
}
|
|
||||||
if (!isset($_FILES['imagefile'])) {
|
if (!isset($_FILES['imagefile'])) {
|
||||||
bailOut($l10n->t('No file was uploaded. Unknown error'));
|
bailOut($l10n->t('No file was uploaded. Unknown error'));
|
||||||
}
|
}
|
||||||
@ -101,9 +110,14 @@ if(file_exists($file['tmp_name'])) {
|
|||||||
'mime'=>$file['type'],
|
'mime'=>$file['type'],
|
||||||
'size'=>$file['size'],
|
'size'=>$file['size'],
|
||||||
'name'=>$file['name'],
|
'name'=>$file['name'],
|
||||||
'id'=>$_POST['id'],
|
|
||||||
'tmp'=>$tmpkey,
|
'tmp'=>$tmpkey,
|
||||||
)));
|
),
|
||||||
|
'metadata' => array(
|
||||||
|
'contactid'=> $contactid,
|
||||||
|
'addressbookid'=> $addressbookid,
|
||||||
|
'backend'=> $backend,
|
||||||
|
),
|
||||||
|
));
|
||||||
exit();
|
exit();
|
||||||
} else {
|
} else {
|
||||||
bailOut($l10n->t('Couldn\'t save temporary image: ').$tmpkey);
|
bailOut($l10n->t('Couldn\'t save temporary image: ').$tmpkey);
|
||||||
|
@ -1,26 +1,32 @@
|
|||||||
<?php
|
<?php
|
||||||
OC::$CLASSPATH['OCA\Contacts\App'] = 'contacts/lib/app.php';
|
//require_once __DIR__ . '/../lib/contact.php';
|
||||||
OC::$CLASSPATH['OCA\Contacts\Addressbook'] = 'contacts/lib/addressbook.php';
|
Sabre\VObject\Component::$classMap['VCARD'] = 'OCA\Contacts\Contact';
|
||||||
OC::$CLASSPATH['OCA\Contacts\VCard'] = 'contacts/lib/vcard.php';
|
Sabre\VObject\Property::$classMap['FN'] = 'OC\VObject\StringProperty';
|
||||||
OC::$CLASSPATH['OCA\Contacts\Hooks'] = 'contacts/lib/hooks.php';
|
Sabre\VObject\Property::$classMap['TITLE'] = 'OC\VObject\StringProperty';
|
||||||
OC::$CLASSPATH['OCA\Contacts\Share_Backend_Contact'] = 'contacts/lib/share/contact.php';
|
Sabre\VObject\Property::$classMap['ROLE'] = 'OC\VObject\StringProperty';
|
||||||
OC::$CLASSPATH['OCA\Contacts\Share_Backend_Addressbook'] = 'contacts/lib/share/addressbook.php';
|
Sabre\VObject\Property::$classMap['NOTE'] = 'OC\VObject\StringProperty';
|
||||||
OC::$CLASSPATH['OCA\Contacts\AddressbookProvider'] = 'contacts/lib/addressbookprovider.php';
|
Sabre\VObject\Property::$classMap['NICKNAME'] = 'OC\VObject\StringProperty';
|
||||||
OC::$CLASSPATH['OC_Connector_Sabre_CardDAV'] = 'contacts/lib/sabre/backend.php';
|
Sabre\VObject\Property::$classMap['EMAIL'] = 'OC\VObject\StringProperty';
|
||||||
OC::$CLASSPATH['OC_Connector_Sabre_CardDAV_AddressBookRoot'] = 'contacts/lib/sabre/addressbookroot.php';
|
Sabre\VObject\Property::$classMap['TEL'] = 'OC\VObject\StringProperty';
|
||||||
OC::$CLASSPATH['OC_Connector_Sabre_CardDAV_UserAddressBooks'] = 'contacts/lib/sabre/useraddressbooks.php';
|
Sabre\VObject\Property::$classMap['IMPP'] = 'OC\VObject\StringProperty';
|
||||||
OC::$CLASSPATH['OC_Connector_Sabre_CardDAV_AddressBook'] = 'contacts/lib/sabre/addressbook.php';
|
Sabre\VObject\Property::$classMap['URL'] = 'OC\VObject\StringProperty';
|
||||||
OC::$CLASSPATH['OC_Connector_Sabre_CardDAV_Card'] = 'contacts/lib/sabre/card.php';
|
Sabre\VObject\Property::$classMap['GEO'] = 'Sabre\VObject\Property\Compound';
|
||||||
OC::$CLASSPATH['OCA\\Contacts\\SearchProvider'] = 'contacts/lib/search.php';
|
|
||||||
OCP\Util::connectHook('OC_User', 'post_createUser', 'OCA\Contacts\Hooks', 'createUser');
|
OCP\Util::connectHook('OC_User', 'post_createUser', 'OCA\Contacts\Hooks', 'userCreated');
|
||||||
OCP\Util::connectHook('OC_User', 'post_deleteUser', 'OCA\Contacts\Hooks', 'deleteUser');
|
OCP\Util::connectHook('OC_User', 'post_deleteUser', 'OCA\Contacts\Hooks', 'userDeleted');
|
||||||
|
OCP\Util::connectHook('OCA\Contacts', 'pre_deleteAddressBook', 'OCA\Contacts\Hooks', 'addressBookDeletion');
|
||||||
|
OCP\Util::connectHook('OCA\Contacts', 'pre_deleteContact', 'OCA\Contacts\Hooks', 'contactDeletion');
|
||||||
|
OCP\Util::connectHook('OCA\Contacts', 'post_createContact', 'OCA\Contacts\Hooks', 'contactUpdated');
|
||||||
|
OCP\Util::connectHook('OCA\Contacts', 'post_updateContact', 'OCA\Contacts\Hooks', 'contactUpdated');
|
||||||
|
OCP\Util::connectHook('OCA\Contacts', 'scanCategories', 'OCA\Contacts\Hooks', 'scanCategories');
|
||||||
|
OCP\Util::connectHook('OCA\Contacts', 'indexProperties', 'OCA\Contacts\Hooks', 'indexProperties');
|
||||||
OCP\Util::connectHook('OC_Calendar', 'getEvents', 'OCA\Contacts\Hooks', 'getBirthdayEvents');
|
OCP\Util::connectHook('OC_Calendar', 'getEvents', 'OCA\Contacts\Hooks', 'getBirthdayEvents');
|
||||||
OCP\Util::connectHook('OC_Calendar', 'getSources', 'OCA\Contacts\Hooks', 'getCalenderSources');
|
OCP\Util::connectHook('OC_Calendar', 'getSources', 'OCA\Contacts\Hooks', 'getCalenderSources');
|
||||||
|
|
||||||
OCP\App::addNavigationEntry( array(
|
OCP\App::addNavigationEntry( array(
|
||||||
'id' => 'contacts_index',
|
'id' => 'contacts_index',
|
||||||
'order' => 10,
|
'order' => 10,
|
||||||
'href' => OCP\Util::linkTo( 'contacts', 'index.php' ),
|
'href' => \OC_Helper::linkToRoute('contacts_index'),
|
||||||
'icon' => OCP\Util::imagePath( 'contacts', 'contacts.svg' ),
|
'icon' => OCP\Util::imagePath( 'contacts', 'contacts.svg' ),
|
||||||
'name' => OC_L10N::get('contacts')->t('Contacts') ));
|
'name' => OC_L10N::get('contacts')->t('Contacts') ));
|
||||||
|
|
||||||
@ -30,8 +36,9 @@ OC_Search::registerProvider('OCA\Contacts\SearchProvider');
|
|||||||
OCP\Share::registerBackend('contact', 'OCA\Contacts\Share_Backend_Contact');
|
OCP\Share::registerBackend('contact', 'OCA\Contacts\Share_Backend_Contact');
|
||||||
OCP\Share::registerBackend('addressbook', 'OCA\Contacts\Share_Backend_Addressbook', 'contact');
|
OCP\Share::registerBackend('addressbook', 'OCA\Contacts\Share_Backend_Addressbook', 'contact');
|
||||||
|
|
||||||
|
/*
|
||||||
if(OCP\User::isLoggedIn()) {
|
if(OCP\User::isLoggedIn()) {
|
||||||
foreach(OCA\Contacts\Addressbook::all(OCP\USER::getUser()) as $addressbook) {
|
foreach(OCA\Contacts\Addressbook::all(OCP\USER::getUser()) as $addressbook) {
|
||||||
OCP\Contacts::registerAddressBook(new OCA\Contacts\AddressbookProvider($addressbook['id']));
|
OCP\Contacts::registerAddressBook(new OCA\Contacts\AddressbookProvider($addressbook['id']));
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
|
28
appinfo/classpath.php
Normal file
28
appinfo/classpath.php
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
OC::$CLASSPATH['OCA\Contacts\App'] = 'contacts/lib/app.php';
|
||||||
|
OC::$CLASSPATH['OCA\Contacts\AddressBook'] = 'contacts/lib/addressbook.php';
|
||||||
|
OC::$CLASSPATH['OCA\Contacts\Contact'] = 'contacts/lib/contact.php';
|
||||||
|
OC::$CLASSPATH['OCA\Contacts\AddressbookLegacy'] = 'contacts/lib/addressbooklegacy.php';
|
||||||
|
OC::$CLASSPATH['OCA\Contacts\IPIMObject'] = 'contacts/lib/ipimobject.php';
|
||||||
|
OC::$CLASSPATH['OCA\Contacts\PIMCollectionAbstract'] = 'contacts/lib/abstractpimcollection.php';
|
||||||
|
OC::$CLASSPATH['OCA\Contacts\PIMObjectAbstract'] = 'contacts/lib/abstractpimobject.php';
|
||||||
|
OC::$CLASSPATH['OCA\Contacts\VCard'] = 'contacts/lib/vcard.php';
|
||||||
|
OC::$CLASSPATH['OCA\Contacts\Hooks'] = 'contacts/lib/hooks.php';
|
||||||
|
OC::$CLASSPATH['OCA\Contacts\Request'] = 'contacts/lib/request.php';
|
||||||
|
OC::$CLASSPATH['OCA\Contacts\Utils\JSONSerializer'] = 'contacts/lib/utils/jsonserializer.php';
|
||||||
|
OC::$CLASSPATH['OCA\Contacts\Utils\Properties'] = 'contacts/lib/utils/properties.php';
|
||||||
|
OC::$CLASSPATH['OCA\Contacts\Backend\AbstractBackend'] = 'contacts/lib/backend/abstractbackend.php';
|
||||||
|
OC::$CLASSPATH['OCA\Contacts\Backend\Database'] = 'contacts/lib/backend/database.php';
|
||||||
|
OC::$CLASSPATH['OCA\Contacts\Backend\Shared'] = 'contacts/lib/backend/shared.php';
|
||||||
|
OC::$CLASSPATH['OCA\Contacts\Share_Backend_Contact'] = 'contacts/lib/share/contact.php';
|
||||||
|
OC::$CLASSPATH['OCA\Contacts\Share_Backend_Addressbook'] = 'contacts/lib/share/addressbook.php';
|
||||||
|
OC::$CLASSPATH['OCA\Contacts\AddressbookProvider'] = 'contacts/lib/addressbookprovider.php';
|
||||||
|
OC::$CLASSPATH['OCA\Contacts\VObject\VCard'] = 'contacts/lib/vobject/vcard.php';
|
||||||
|
//OC::$CLASSPATH['OCA\Contacts\VObject\StringProperty'] = 'contacts/lib/vobject/stringproperty.php';
|
||||||
|
OC::$CLASSPATH['OCA\Contacts\CardDAV\Backend'] = 'contacts/lib/carddav/backend.php';
|
||||||
|
OC::$CLASSPATH['OCA\Contacts\CardDAV\Plugin'] = 'contacts/lib/carddav/plugin.php';
|
||||||
|
OC::$CLASSPATH['OCA\Contacts\CardDAV\AddressBookRoot'] = 'contacts/lib/carddav/addressbookroot.php';
|
||||||
|
OC::$CLASSPATH['OCA\Contacts\CardDAV\UserAddressBooks'] = 'contacts/lib/carddav/useraddressbooks.php';
|
||||||
|
OC::$CLASSPATH['OCA\Contacts\CardDAV\AddressBook'] = 'contacts/lib/carddav/addressbook.php';
|
||||||
|
OC::$CLASSPATH['OCA\Contacts\CardDAV\Card'] = 'contacts/lib/carddav/card.php';
|
||||||
|
OC::$CLASSPATH['OCA\Contacts\SearchProvider'] = 'contacts/lib/search.php';
|
@ -4,9 +4,121 @@
|
|||||||
<name>*dbname*</name>
|
<name>*dbname*</name>
|
||||||
<create>true</create>
|
<create>true</create>
|
||||||
<overwrite>false</overwrite>
|
<overwrite>false</overwrite>
|
||||||
|
|
||||||
<charset>utf8</charset>
|
<charset>utf8</charset>
|
||||||
|
<!--
|
||||||
|
<table>
|
||||||
|
<name>*dbprefix*addressbook</name>
|
||||||
|
|
||||||
|
<declaration>
|
||||||
|
|
||||||
|
<field>
|
||||||
|
<name>id</name>
|
||||||
|
<type>integer</type>
|
||||||
|
<default>0</default>
|
||||||
|
<notnull>true</notnull>
|
||||||
|
<autoincrement>1</autoincrement>
|
||||||
|
<unsigned>true</unsigned>
|
||||||
|
<length>4</length>
|
||||||
|
</field>
|
||||||
|
|
||||||
|
<field>
|
||||||
|
<name>backend</name>
|
||||||
|
<type>text</type>
|
||||||
|
<default></default>
|
||||||
|
<notnull>true</notnull>
|
||||||
|
<length>255</length>
|
||||||
|
</field>
|
||||||
|
|
||||||
|
<field>
|
||||||
|
<name>addressbookid</name>
|
||||||
|
<type>text</type>
|
||||||
|
<default></default>
|
||||||
|
<notnull>true</notnull>
|
||||||
|
<length>255</length>
|
||||||
|
</field>
|
||||||
|
|
||||||
|
<field>
|
||||||
|
<name>userid</name>
|
||||||
|
<type>text</type>
|
||||||
|
<default></default>
|
||||||
|
<notnull>true</notnull>
|
||||||
|
<length>255</length>
|
||||||
|
</field>
|
||||||
|
|
||||||
|
<field>
|
||||||
|
<name>displayname</name>
|
||||||
|
<type>text</type>
|
||||||
|
<default></default>
|
||||||
|
<notnull>true</notnull>
|
||||||
|
<length>255</length>
|
||||||
|
</field>
|
||||||
|
|
||||||
|
<field>
|
||||||
|
<name>visibility</name>
|
||||||
|
<type>integer</type>
|
||||||
|
<default>1</default>
|
||||||
|
<notnull>true</notnull>
|
||||||
|
<length>1</length>
|
||||||
|
</field>
|
||||||
|
|
||||||
|
<field>
|
||||||
|
<name>ctag</name>
|
||||||
|
<type>integer</type>
|
||||||
|
<default>0</default>
|
||||||
|
<notnull>true</notnull>
|
||||||
|
<unsigned>true</unsigned>
|
||||||
|
<length>4</length>
|
||||||
|
</field>
|
||||||
|
|
||||||
|
<field>
|
||||||
|
<name>order</name>
|
||||||
|
<type>integer</type>
|
||||||
|
<default>0</default>
|
||||||
|
<notnull>true</notnull>
|
||||||
|
<unsigned>true</unsigned>
|
||||||
|
<length>4</length>
|
||||||
|
</field>
|
||||||
|
|
||||||
|
</declaration>
|
||||||
|
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
|
||||||
|
<name>*dbprefix*addressbook_backend</name>
|
||||||
|
|
||||||
|
<declaration>
|
||||||
|
|
||||||
|
<field>
|
||||||
|
<name>id</name>
|
||||||
|
<type>integer</type>
|
||||||
|
<default>0</default>
|
||||||
|
<notnull>true</notnull>
|
||||||
|
<autoincrement>1</autoincrement>
|
||||||
|
<unsigned>true</unsigned>
|
||||||
|
<length>4</length>
|
||||||
|
</field>
|
||||||
|
|
||||||
|
<field>
|
||||||
|
<name>backendname</name>
|
||||||
|
<type>text</type>
|
||||||
|
<default></default>
|
||||||
|
<notnull>true</notnull>
|
||||||
|
<length>255</length>
|
||||||
|
</field>
|
||||||
|
|
||||||
|
<field>
|
||||||
|
<name>enabled</name>
|
||||||
|
<type>integer</type>
|
||||||
|
<default>1</default>
|
||||||
|
<notnull>true</notnull>
|
||||||
|
<length>1</length>
|
||||||
|
</field>
|
||||||
|
|
||||||
|
</declaration>
|
||||||
|
|
||||||
|
</table>
|
||||||
|
-->
|
||||||
<table>
|
<table>
|
||||||
|
|
||||||
<name>*dbprefix*contacts_addressbooks</name>
|
<name>*dbprefix*contacts_addressbooks</name>
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
class OC_Migration_Provider_Contacts extends OC_Migration_Provider{
|
namespace OCA\Contacts;
|
||||||
|
|
||||||
|
class MigrationProvider extends OC_Migration_Provider{
|
||||||
|
|
||||||
// Create the xml for the user supplied
|
// Create the xml for the user supplied
|
||||||
function export( ) {
|
function export( ) {
|
||||||
@ -21,26 +23,31 @@ class OC_Migration_Provider_Contacts extends OC_Migration_Provider{
|
|||||||
$ids2 = $this->content->copyRows( $options );
|
$ids2 = $this->content->copyRows( $options );
|
||||||
|
|
||||||
// If both returned some ids then they worked
|
// If both returned some ids then they worked
|
||||||
if(is_array($ids) && is_array($ids2)) {
|
return (is_array($ids) && is_array($ids2));
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Import function for contacts
|
// Import function for contacts
|
||||||
function import( ) {
|
function import() {
|
||||||
switch( $this->appinfo->version ) {
|
switch($this->appinfo->version) {
|
||||||
default:
|
default:
|
||||||
// All versions of the app have had the same db structure, so all can use the same import function
|
// All versions of the app have had the same db structure, so all can use the same import function
|
||||||
$query = $this->content->prepare( 'SELECT * FROM contacts_addressbooks WHERE userid = ?' );
|
$query = $this->content->prepare('SELECT * FROM `contacts_addressbooks` WHERE `userid` = ?');
|
||||||
$results = $query->execute( array( $this->olduid ) );
|
$results = $query->execute(array($this->olduid));
|
||||||
$idmap = array();
|
$idmap = array();
|
||||||
while( $row = $results->fetchRow() ) {
|
while($row = $results->fetchRow()) {
|
||||||
// Import each addressbook
|
// Import each addressbook
|
||||||
$addressbookquery = OCP\DB::prepare( 'INSERT INTO `*PREFIX*contacts_addressbooks` (`userid`, `displayname`, `uri`, `description`, `ctag`) VALUES (?, ?, ?, ?, ?)' );
|
$addressbookquery = OCP\DB::prepare('INSERT INTO `*PREFIX*contacts_addressbooks` '
|
||||||
$addressbookquery->execute( array( $this->uid, $row['displayname'], $row['uri'], $row['description'], $row['ctag'] ) );
|
. '(`userid`, `displayname`, `uri`, `description`, `ctag`) VALUES (?, ?, ?, ?, ?)');
|
||||||
|
$addressbookquery->execute(
|
||||||
|
array(
|
||||||
|
$this->uid,
|
||||||
|
$row['displayname'],
|
||||||
|
$row['uri'],
|
||||||
|
$row['description'],
|
||||||
|
$row['ctag']
|
||||||
|
)
|
||||||
|
);
|
||||||
// Map the id
|
// Map the id
|
||||||
$idmap[$row['id']] = OCP\DB::insertid('*PREFIX*contacts_addressbooks');
|
$idmap[$row['id']] = OCP\DB::insertid('*PREFIX*contacts_addressbooks');
|
||||||
// Make the addressbook active
|
// Make the addressbook active
|
||||||
@ -49,12 +56,21 @@ class OC_Migration_Provider_Contacts extends OC_Migration_Provider{
|
|||||||
// Now tags
|
// Now tags
|
||||||
foreach($idmap as $oldid => $newid) {
|
foreach($idmap as $oldid => $newid) {
|
||||||
|
|
||||||
$query = $this->content->prepare( 'SELECT * FROM contacts_cards WHERE addressbookid = ?' );
|
$query = $this->content->prepare('SELECT * FROM `contacts_cards` WHERE `addressbookid` = ?');
|
||||||
$results = $query->execute( array( $oldid ) );
|
$results = $query->execute(array($oldid));
|
||||||
while( $row = $results->fetchRow() ) {
|
while($row = $results->fetchRow()) {
|
||||||
// Import the contacts
|
// Import the contacts
|
||||||
$contactquery = OCP\DB::prepare( 'INSERT INTO `*PREFIX*contacts_cards` (`addressbookid`, `fullname`, `carddata`, `uri`, `lastmodified`) VALUES (?, ?, ?, ?, ?)' );
|
$contactquery = OCP\DB::prepare('INSERT INTO `*PREFIX*contacts_cards` '
|
||||||
$contactquery->execute( array( $newid, $row['fullname'], $row['carddata'], $row['uri'], $row['lastmodified'] ) );
|
. '(`addressbookid`, `fullname`, `carddata`, `uri`, `lastmodified`) VALUES (?, ?, ?, ?, ?)');
|
||||||
|
$contactquery->execute(
|
||||||
|
array(
|
||||||
|
$newid,
|
||||||
|
$row['fullname'],
|
||||||
|
$row['carddata'],
|
||||||
|
$row['uri'],
|
||||||
|
$row['lastmodified']
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// All done!
|
// All done!
|
||||||
@ -67,4 +83,4 @@ class OC_Migration_Provider_Contacts extends OC_Migration_Provider{
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Load the provider
|
// Load the provider
|
||||||
new OC_Migration_Provider_Contacts( 'contacts' );
|
new MigrationProvider('contacts');
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
OCP\App::checkAppEnabled('contacts');
|
OCP\App::checkAppEnabled('contacts');
|
||||||
|
require_once __DIR__ . '/classpath.php';
|
||||||
|
|
||||||
if(substr(OCP\Util::getRequestUri(), 0, strlen(OC_App::getAppWebPath('contacts').'/carddav.php')) == OC_App::getAppWebPath('contacts').'/carddav.php') {
|
if(substr(OCP\Util::getRequestUri(), 0, strlen(OC_App::getAppWebPath('contacts').'/carddav.php')) == OC_App::getAppWebPath('contacts').'/carddav.php') {
|
||||||
$baseuri = OC_App::getAppWebPath('contacts').'/carddav.php';
|
$baseuri = OC_App::getAppWebPath('contacts').'/carddav.php';
|
||||||
@ -33,15 +34,19 @@ OC_App::loadApps($RUNTIME_APPTYPES);
|
|||||||
// Backends
|
// Backends
|
||||||
$authBackend = new OC_Connector_Sabre_Auth();
|
$authBackend = new OC_Connector_Sabre_Auth();
|
||||||
$principalBackend = new OC_Connector_Sabre_Principal();
|
$principalBackend = new OC_Connector_Sabre_Principal();
|
||||||
$carddavBackend = new OC_Connector_Sabre_CardDAV();
|
|
||||||
|
$addressbookbackends = array();
|
||||||
|
$addressbookbackends[] = new OCA\Contacts\Backend\Shared();
|
||||||
|
$addressbookbackends[] = new OCA\Contacts\Backend\Database();
|
||||||
|
$carddavBackend = new OCA\Contacts\CardDAV\Backend($addressbookbackends);
|
||||||
$requestBackend = new OC_Connector_Sabre_Request();
|
$requestBackend = new OC_Connector_Sabre_Request();
|
||||||
|
|
||||||
// Root nodes
|
// Root nodes
|
||||||
$principalCollection = new Sabre_CalDAV_Principal_Collection($principalBackend);
|
$principalCollection = new Sabre_CalDAV_Principal_Collection($principalBackend);
|
||||||
$principalCollection->disableListing = true; // Disable listening
|
$principalCollection->disableListing = true; // Disable listing
|
||||||
|
|
||||||
$addressBookRoot = new OC_Connector_Sabre_CardDAV_AddressBookRoot($principalBackend, $carddavBackend);
|
$addressBookRoot = new OCA\Contacts\CardDAV\AddressBookRoot($principalBackend, $carddavBackend);
|
||||||
$addressBookRoot->disableListing = true; // Disable listening
|
$addressBookRoot->disableListing = true; // Disable listing
|
||||||
|
|
||||||
$nodes = array(
|
$nodes = array(
|
||||||
$principalCollection,
|
$principalCollection,
|
||||||
@ -54,10 +59,13 @@ $server->httpRequest = $requestBackend;
|
|||||||
$server->setBaseUri($baseuri);
|
$server->setBaseUri($baseuri);
|
||||||
// Add plugins
|
// Add plugins
|
||||||
$server->addPlugin(new Sabre_DAV_Auth_Plugin($authBackend, 'ownCloud'));
|
$server->addPlugin(new Sabre_DAV_Auth_Plugin($authBackend, 'ownCloud'));
|
||||||
$server->addPlugin(new Sabre_CardDAV_Plugin());
|
$server->addPlugin(new OCA\Contacts\CardDAV\Plugin());
|
||||||
$server->addPlugin(new Sabre_DAVACL_Plugin());
|
$server->addPlugin(new Sabre_DAVACL_Plugin());
|
||||||
$server->addPlugin(new Sabre_DAV_Browser_Plugin(false)); // Show something in the Browser, but no upload
|
$server->addPlugin(new Sabre_DAV_Browser_Plugin(false)); // Show something in the Browser, but no upload
|
||||||
$server->addPlugin(new Sabre_CardDAV_VCFExportPlugin());
|
$server->addPlugin(new Sabre_CardDAV_VCFExportPlugin());
|
||||||
|
|
||||||
|
if(defined('DEBUG') && DEBUG) {
|
||||||
|
$server->debugExceptions = true;
|
||||||
|
}
|
||||||
// And off we go!
|
// And off we go!
|
||||||
$server->exec();
|
$server->exec();
|
||||||
|
532
appinfo/routes.php
Normal file
532
appinfo/routes.php
Normal file
@ -0,0 +1,532 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @author Thomas Tanghus
|
||||||
|
* Copyright (c) 2013 Thomas Tanghus (thomas@tanghus.net)
|
||||||
|
* This file is licensed under the Affero General Public License version 3 or
|
||||||
|
* later.
|
||||||
|
* See the COPYING-README file.
|
||||||
|
*/
|
||||||
|
namespace OCA\Contacts;
|
||||||
|
|
||||||
|
require_once __DIR__.'/../ajax/loghandler.php';
|
||||||
|
|
||||||
|
//define the routes
|
||||||
|
//for the index
|
||||||
|
$this->create('contacts_index', '/')
|
||||||
|
->actionInclude('contacts/index.php');
|
||||||
|
// ->action(
|
||||||
|
// function($params){
|
||||||
|
// //
|
||||||
|
// }
|
||||||
|
// );
|
||||||
|
|
||||||
|
$this->create('contacts_jsconfig', 'ajax/config.js')
|
||||||
|
->actionInclude('contacts/js/config.php');
|
||||||
|
|
||||||
|
/* TODO:
|
||||||
|
- Check what it requires to be a RESTful API. I think maybe {user}
|
||||||
|
shouldn't be in the URI but be authenticated in headers or elsewhere.
|
||||||
|
- Do security checks: logged in, csrf
|
||||||
|
- Move the actual code to controllers.
|
||||||
|
*/
|
||||||
|
$this->create('contacts_address_books_for_user', 'addressbooks/{user}/')
|
||||||
|
->get()
|
||||||
|
->action(
|
||||||
|
function($params) {
|
||||||
|
session_write_close();
|
||||||
|
$app = new App($params['user']);
|
||||||
|
$addressBooks = $app->getAddressBooksForUser();
|
||||||
|
$response = array();
|
||||||
|
foreach($addressBooks as $addressBook) {
|
||||||
|
$response[] = $addressBook->getMetaData();
|
||||||
|
}
|
||||||
|
\OCP\JSON::success(array(
|
||||||
|
'data' => array(
|
||||||
|
'addressbooks' => $response,
|
||||||
|
)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
)
|
||||||
|
->requirements(array('user'))
|
||||||
|
->defaults(array('user' => \OCP\User::getUser()));
|
||||||
|
|
||||||
|
$this->create('contacts_address_book_collection', 'addressbook/{user}/{backend}/{addressbookid}/contacts')
|
||||||
|
->get()
|
||||||
|
->action(
|
||||||
|
function($params) {
|
||||||
|
session_write_close();
|
||||||
|
$app = new App($params['user']);
|
||||||
|
$addressBook = $app->getAddressBook($params['backend'], $params['addressbookid']);
|
||||||
|
$lastModified = $addressBook->lastModified();
|
||||||
|
if(!is_null($lastModified)) {
|
||||||
|
\OCP\Response::enableCaching();
|
||||||
|
\OCP\Response::setLastModifiedHeader($lastModified);
|
||||||
|
\OCP\Response::setETagHeader(md5($lastModified));
|
||||||
|
}
|
||||||
|
$contacts = array();
|
||||||
|
foreach($addressBook->getChildren() as $contact) {
|
||||||
|
//$contact->retrieve();
|
||||||
|
//error_log(__METHOD__.' jsondata: '.print_r($contact, true));
|
||||||
|
$response = Utils\JSONSerializer::serializeContact($contact);
|
||||||
|
if($response !== null) {
|
||||||
|
$contacts[] = $response;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
\OCP\JSON::success(array(
|
||||||
|
'data' => array(
|
||||||
|
'contacts' => $contacts,
|
||||||
|
)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
)
|
||||||
|
->requirements(array('user', 'backend', 'addressbookid'))
|
||||||
|
->defaults(array('user' => \OCP\User::getUser()));
|
||||||
|
|
||||||
|
$this->create('contacts_address_book_add', 'addressbook/{user}/{backend}/add')
|
||||||
|
->post()
|
||||||
|
->action(
|
||||||
|
function($params) {
|
||||||
|
session_write_close();
|
||||||
|
$app = new App($params['user']);
|
||||||
|
$backend = App::getBackend('local', $params['user']);
|
||||||
|
$id = $backend->createAddressBook($_POST);
|
||||||
|
if($id === false) {
|
||||||
|
bailOut(App::$l10n->t('Error creating address book'));
|
||||||
|
}
|
||||||
|
\OCP\JSON::success(array(
|
||||||
|
'data' => $backend->getAddressBook($id)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
)
|
||||||
|
->requirements(array('user', 'backend', 'addressbookid'))
|
||||||
|
->defaults(array('user' => \OCP\User::getUser()));
|
||||||
|
|
||||||
|
$this->create('contacts_address_book_delete', 'addressbook/{user}/{backend}/{addressbookid}/delete')
|
||||||
|
->post()
|
||||||
|
->action(
|
||||||
|
function($params) {
|
||||||
|
session_write_close();
|
||||||
|
$app = new App($params['user']);
|
||||||
|
$backend = App::getBackend('local', $params['user']);
|
||||||
|
if(!$backend->deleteAddressBook($params['addressbookid'])) {
|
||||||
|
bailOut(App::$l10n->t('Error deleting address book'));
|
||||||
|
}
|
||||||
|
\OCP\JSON::success();
|
||||||
|
}
|
||||||
|
)
|
||||||
|
->requirements(array('user', 'backend', 'addressbookid'))
|
||||||
|
->defaults(array('user' => \OCP\User::getUser()));
|
||||||
|
|
||||||
|
$this->create('contacts_address_book_add_contact', 'addressbook/{user}/{backend}/{addressbookid}/contact/add')
|
||||||
|
->post()
|
||||||
|
->action(
|
||||||
|
function($params) {
|
||||||
|
session_write_close();
|
||||||
|
$app = new App($params['user']);
|
||||||
|
$addressBook = $app->getAddressBook($params['backend'], $params['addressbookid']);
|
||||||
|
$id = $addressBook->addChild();
|
||||||
|
if($id === false) {
|
||||||
|
bailOut(App::$l10n->t('Error creating contact.'));
|
||||||
|
}
|
||||||
|
$contact = $addressBook->getChild($id);
|
||||||
|
\OCP\JSON::success(array(
|
||||||
|
'data' => Utils\JSONSerializer::serializeContact($contact),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
)
|
||||||
|
->requirements(array('user', 'backend', 'addressbookid'))
|
||||||
|
->defaults(array('user' => \OCP\User::getUser()));
|
||||||
|
|
||||||
|
$this->create('contacts_address_book_delete_contact', 'addressbook/{user}/{backend}/{addressbookid}/contact/{contactid}/delete')
|
||||||
|
->post()
|
||||||
|
->action(
|
||||||
|
function($params) {
|
||||||
|
session_write_close();
|
||||||
|
$app = new App($params['user']);
|
||||||
|
$addressBook = $app->getAddressBook($params['backend'], $params['addressbookid']);
|
||||||
|
$response = $addressBook->deleteChild($params['contactid']);
|
||||||
|
if($response === false) {
|
||||||
|
bailOut(App::$l10n->t('Error deleting contact.'));
|
||||||
|
}
|
||||||
|
\OCP\JSON::success();
|
||||||
|
}
|
||||||
|
)
|
||||||
|
->requirements(array('user', 'backend', 'addressbookid', 'contactid'))
|
||||||
|
->defaults(array('user' => \OCP\User::getUser()));
|
||||||
|
|
||||||
|
$this->create('contacts_contact_photo', 'addressbook/{user}/{backend}/{addressbookid}/contact/{contactid}/photo')
|
||||||
|
->get()
|
||||||
|
->action(
|
||||||
|
function($params) {
|
||||||
|
// TODO: Cache resized photo
|
||||||
|
session_write_close();
|
||||||
|
$etag = null;
|
||||||
|
$caching = null;
|
||||||
|
$max_size = 170;
|
||||||
|
$app = new App();
|
||||||
|
$contact = $app->getContact($params['backend'], $params['addressbookid'], $params['contactid']);
|
||||||
|
$image = new \OC_Image();
|
||||||
|
if (isset($contact->PHOTO) && $image->loadFromBase64((string)$contact->PHOTO)) {
|
||||||
|
// OK
|
||||||
|
$etag = md5($contact->PHOTO);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
// Logo :-/
|
||||||
|
if (isset($contact->LOGO) && $image->loadFromBase64((string)$contact->LOGO)) {
|
||||||
|
// OK
|
||||||
|
$etag = md5($contact->LOGO);
|
||||||
|
}
|
||||||
|
if ($image->valid()) {
|
||||||
|
$modified = $contact->lastModified();
|
||||||
|
// Force refresh if modified within the last minute.
|
||||||
|
if(!is_null($modified)) {
|
||||||
|
$caching = (time() - $modified > 60) ? null : 0;
|
||||||
|
}
|
||||||
|
\OCP\Response::enableCaching($caching);
|
||||||
|
if(!is_null($modified)) {
|
||||||
|
\OCP\Response::setLastModifiedHeader($modified);
|
||||||
|
}
|
||||||
|
if($etag) {
|
||||||
|
\OCP\Response::setETagHeader($etag);
|
||||||
|
}
|
||||||
|
if ($image->width() > $max_size || $image->height() > $max_size) {
|
||||||
|
$image->resize($max_size);
|
||||||
|
}
|
||||||
|
header('Content-Type: ' . $image->mimeType());
|
||||||
|
$image->show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
->requirements(array('user', 'backend', 'addressbook', 'contactid'))
|
||||||
|
->defaults(array('user' => \OCP\User::getUser()));
|
||||||
|
|
||||||
|
$this->create('contacts_contact_delete_property', 'addressbook/{user}/{backend}/{addressbookid}/contact/{contactid}/property/delete')
|
||||||
|
->post()
|
||||||
|
->action(
|
||||||
|
function($params) {
|
||||||
|
session_write_close();
|
||||||
|
$request = Request::getRequest($params);
|
||||||
|
$name = $request->post['name'];
|
||||||
|
$checksum = isset($request->post['checksum']) ? $request->post['checksum'] : null;
|
||||||
|
|
||||||
|
debug('contacts_contact_delete_property, name: ' . print_r($name, true));
|
||||||
|
debug('contacts_contact_delete_property, checksum: ' . print_r($checksum, true));
|
||||||
|
|
||||||
|
$app = new App($request->parameters['user']);
|
||||||
|
$contact = $app->getContact(
|
||||||
|
$request->parameters['backend'],
|
||||||
|
$request->parameters['addressbookid'],
|
||||||
|
$request->parameters['contactid']
|
||||||
|
);
|
||||||
|
|
||||||
|
if(!$contact) {
|
||||||
|
bailOut(App::$l10n->t('Couldn\'t find contact.'));
|
||||||
|
}
|
||||||
|
if(!$name) {
|
||||||
|
bailOut(App::$l10n->t('Property name is not set.'));
|
||||||
|
}
|
||||||
|
if(!$checksum && in_array($name, Utils\Properties::$multi_properties)) {
|
||||||
|
bailOut(App::$l10n->t('Property checksum is not set.'));
|
||||||
|
}
|
||||||
|
if(!is_null($checksum)) {
|
||||||
|
try {
|
||||||
|
$contact->unsetPropertyByChecksum($checksum);
|
||||||
|
} catch(Exception $e) {
|
||||||
|
bailOut(App::$l10n->t('Information about vCard is incorrect. Please reload the page.'));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
unset($contact->{$name});
|
||||||
|
}
|
||||||
|
if(!$contact->save()) {
|
||||||
|
bailOut(App::$l10n->t('Error saving contact to backend.'));
|
||||||
|
}
|
||||||
|
\OCP\JSON::success(array(
|
||||||
|
'data' => array(
|
||||||
|
'backend' => $request->parameters['backend'],
|
||||||
|
'addressbookid' => $request->parameters['addressbookid'],
|
||||||
|
'contactid' => $request->parameters['contactid'],
|
||||||
|
'lastmodified' => $contact->lastModified(),
|
||||||
|
)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
)
|
||||||
|
->requirements(array('user', 'backend', 'addressbook', 'contactid'))
|
||||||
|
->defaults(array('user' => \OCP\User::getUser()));
|
||||||
|
|
||||||
|
// Save a single property.
|
||||||
|
$this->create('contacts_contact_save_property', 'addressbook/{user}/{backend}/{addressbookid}/contact/{contactid}/property/save')
|
||||||
|
->post()
|
||||||
|
->action(
|
||||||
|
function($params) {
|
||||||
|
session_write_close();
|
||||||
|
$request = Request::getRequest($params);
|
||||||
|
// TODO: When value is empty unset the property and return a checksum of 'new' if multi_property
|
||||||
|
$name = $request->post['name'];
|
||||||
|
$value = $request->post['value'];
|
||||||
|
$parameters = isset($request->post['parameters']) ? $request->post['parameters'] : null;
|
||||||
|
$checksum = isset($request->post['checksum']) ? $request->post['checksum'] : null;
|
||||||
|
|
||||||
|
debug('contacts_contact_save_property, name: ' . print_r($name, true));
|
||||||
|
debug('contacts_contact_save_property, value: ' . print_r($value, true));
|
||||||
|
debug('contacts_contact_save_property, parameters: ' . print_r($parameters, true));
|
||||||
|
debug('contacts_contact_save_property, checksum: ' . print_r($checksum, true));
|
||||||
|
|
||||||
|
$app = new App($params['user']);
|
||||||
|
$contact = $app->getContact($params['backend'], $params['addressbookid'], $params['contactid']);
|
||||||
|
|
||||||
|
$response = array('contactid' => $params['contactid']);
|
||||||
|
|
||||||
|
if(!$contact) {
|
||||||
|
bailOut(App::$l10n->t('Couldn\'t find contact.'));
|
||||||
|
}
|
||||||
|
if(!$name) {
|
||||||
|
bailOut(App::$l10n->t('Property name is not set.'));
|
||||||
|
}
|
||||||
|
if(is_array($value)) {
|
||||||
|
// NOTE: Important, otherwise the compound value will be
|
||||||
|
// set in the order the fields appear in the form!
|
||||||
|
ksort($value);
|
||||||
|
}
|
||||||
|
if(!$checksum && in_array($name, Utils\Properties::$multi_properties)) {
|
||||||
|
bailOut(App::$l10n->t('Property checksum is not set.'));
|
||||||
|
} elseif($checksum && in_array($name, Utils\Properties::$multi_properties)) {
|
||||||
|
try {
|
||||||
|
$checksum = $contact->setPropertyByChecksum($checksum, $name, $value, $parameters);
|
||||||
|
$response['checksum'] = $checksum;
|
||||||
|
} catch(Exception $e) {
|
||||||
|
bailOut(App::$l10n->t('Information about vCard is incorrect. Please reload the page.'));
|
||||||
|
}
|
||||||
|
} elseif(!in_array($name, Utils\Properties::$multi_properties)) {
|
||||||
|
if(!$contact->setPropertyByName($name, $value, $parameters)) {
|
||||||
|
bailOut(App::$l10n->t('Error setting property'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!$contact->save()) {
|
||||||
|
bailOut(App::$l10n->t('Error saving property to backend'));
|
||||||
|
}
|
||||||
|
$response['lastmodified'] = $contact->lastModified();
|
||||||
|
$contact->save();
|
||||||
|
\OCP\JSON::success(array('data' => $response));
|
||||||
|
}
|
||||||
|
)
|
||||||
|
->requirements(array('user', 'backend', 'addressbook', 'contactid'))
|
||||||
|
->defaults(array('user' => \OCP\User::getUser()));
|
||||||
|
|
||||||
|
// Save all properties. Used for merging contacts.
|
||||||
|
$this->create('contacts_contact_save_all', 'addressbook/{user}/{backend}/{addressbookid}/contact/{contactid}/save')
|
||||||
|
->post()
|
||||||
|
->action(
|
||||||
|
function($params) {
|
||||||
|
session_write_close();
|
||||||
|
$request = Request::getRequest($params);
|
||||||
|
\OCP\Util::writeLog('contacts', __METHOD__.' params: '.print_r($request->parameters, true), \OCP\Util::DEBUG);
|
||||||
|
|
||||||
|
$app = new App($params['user']);
|
||||||
|
$contact = $app->getContact($params['backend'], $params['addressbookid'], $params['contactid']);
|
||||||
|
|
||||||
|
$response = array('contactid' => $params['contactid']);
|
||||||
|
|
||||||
|
if(!$contact) {
|
||||||
|
bailOut(App::$l10n->t('Couldn\'t find contact.'));
|
||||||
|
}
|
||||||
|
if(!$contact->mergeFromArray($request->params)) {
|
||||||
|
bailOut(App::$l10n->t('Error merging into contact.'));
|
||||||
|
}
|
||||||
|
if(!$contact->save()) {
|
||||||
|
bailOut(App::$l10n->t('Error saving contact to backend.'));
|
||||||
|
}
|
||||||
|
$data = Utils\JSONSerializer::serializeContact($contact);
|
||||||
|
\OCP\JSON::success(array('data' => $data));
|
||||||
|
}
|
||||||
|
)
|
||||||
|
->requirements(array('user', 'backend', 'addressbook', 'contactid'))
|
||||||
|
->defaults(array('user' => \OCP\User::getUser()));
|
||||||
|
|
||||||
|
$this->create('contacts_categories_list', 'groups/{user}/')
|
||||||
|
->get()
|
||||||
|
->action(
|
||||||
|
function($params) {
|
||||||
|
session_write_close();
|
||||||
|
$catmgr = new \OC_VCategories('contact', $params['user']);
|
||||||
|
$categories = $catmgr->categories(\OC_VCategories::FORMAT_MAP);
|
||||||
|
foreach($categories as &$category) {
|
||||||
|
$ids = $catmgr->idsForCategory($category['name']);
|
||||||
|
$category['contacts'] = $ids;
|
||||||
|
}
|
||||||
|
|
||||||
|
$favorites = $catmgr->getFavorites();
|
||||||
|
|
||||||
|
\OCP\JSON::success(array(
|
||||||
|
'data' => array(
|
||||||
|
'categories' => $categories,
|
||||||
|
'favorites' => $favorites,
|
||||||
|
'shared' => \OCP\Share::getItemsSharedWith('addressbook', Share_Backend_Addressbook::FORMAT_ADDRESSBOOKS),
|
||||||
|
'lastgroup' => \OCP\Config::getUserValue(
|
||||||
|
$params['user'],
|
||||||
|
'contacts',
|
||||||
|
'lastgroup', 'all'),
|
||||||
|
'sortorder' => \OCP\Config::getUserValue(
|
||||||
|
$params['user'],
|
||||||
|
'contacts',
|
||||||
|
'groupsort', ''),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
)
|
||||||
|
->requirements(array('user'))
|
||||||
|
->defaults(array('user' => \OCP\User::getUser()));
|
||||||
|
|
||||||
|
$this->create('contacts_categories_add', 'groups/{user}/add')
|
||||||
|
->post()
|
||||||
|
->action(
|
||||||
|
function($params) {
|
||||||
|
session_write_close();
|
||||||
|
$request = Request::getRequest($params);
|
||||||
|
$name = $request->post['name'];
|
||||||
|
|
||||||
|
if(is_null($name) || $name === "") {
|
||||||
|
bailOut(App::$l10n->t('No group name given.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$catman = new \OC_VCategories('contact', $params['user']);
|
||||||
|
$id = $catman->add($name);
|
||||||
|
|
||||||
|
if($id !== false) {
|
||||||
|
\OCP\JSON::success(array('data' => array('id'=>$id, 'name' => $name)));
|
||||||
|
} else {
|
||||||
|
bailOut(App::$l10n->t('Error adding group.'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
->requirements(array('user'))
|
||||||
|
->defaults(array('user' => \OCP\User::getUser()));
|
||||||
|
|
||||||
|
$this->create('contacts_categories_delete', 'groups/{user}/delete')
|
||||||
|
->post()
|
||||||
|
->action(
|
||||||
|
function($params) {
|
||||||
|
session_write_close();
|
||||||
|
$request = Request::getRequest($params);
|
||||||
|
$name = $request->post['name'];
|
||||||
|
|
||||||
|
if(is_null($name) || $name === "") {
|
||||||
|
bailOut(App::$l10n->t('No group name given.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$catman = new \OC_VCategories('contact', $params['user']);
|
||||||
|
$catman->delete($name);
|
||||||
|
|
||||||
|
\OCP\JSON::success();
|
||||||
|
}
|
||||||
|
)
|
||||||
|
->requirements(array('user'))
|
||||||
|
->defaults(array('user' => \OCP\User::getUser()));
|
||||||
|
|
||||||
|
$this->create('contacts_categories_addto', 'groups/{user}/addto/{categoryid}')
|
||||||
|
->post()
|
||||||
|
->action(
|
||||||
|
function($params) {
|
||||||
|
session_write_close();
|
||||||
|
$request = Request::getRequest($params);
|
||||||
|
$categoryid = $request['categoryid'];
|
||||||
|
$ids = $request['contactids'];
|
||||||
|
debug('request: '.print_r($request->post, true));
|
||||||
|
|
||||||
|
if(is_null($categoryid) || $categoryid === '') {
|
||||||
|
bailOut(App::$l10n->t('Group ID missing from request.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(is_null($ids)) {
|
||||||
|
bailOut(App::$l10n->t('Contact ID missing from request.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$catman = new \OC_VCategories('contact', $params['user']);
|
||||||
|
foreach($ids as $contactid) {
|
||||||
|
debug('contactid: ' . $contactid . ', categoryid: ' . $categoryid);
|
||||||
|
$catman->addToCategory($contactid, $categoryid);
|
||||||
|
}
|
||||||
|
|
||||||
|
\OCP\JSON::success();
|
||||||
|
}
|
||||||
|
)
|
||||||
|
->requirements(array('user', 'categoryid'))
|
||||||
|
->defaults(array('user' => \OCP\User::getUser()));
|
||||||
|
|
||||||
|
$this->create('contacts_categories_removefrom', 'groups/{user}/removefrom/{categoryid}')
|
||||||
|
->post()
|
||||||
|
->action(
|
||||||
|
function($params) {
|
||||||
|
session_write_close();
|
||||||
|
$request = Request::getRequest($params);
|
||||||
|
$categoryid = $request['categoryid'];
|
||||||
|
$ids = $request['contactids'];
|
||||||
|
debug('request: '.print_r($request->post, true));
|
||||||
|
|
||||||
|
if(is_null($categoryid) || $categoryid === '') {
|
||||||
|
bailOut(App::$l10n->t('Group ID missing from request.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(is_null($ids)) {
|
||||||
|
bailOut(App::$l10n->t('Contact ID missing from request.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$catman = new \OC_VCategories('contact', $params['user']);
|
||||||
|
foreach($ids as $contactid) {
|
||||||
|
debug('contactid: ' . $contactid . ', categoryid: ' . $categoryid);
|
||||||
|
$catman->removeFromCategory($contactid, $categoryid);
|
||||||
|
}
|
||||||
|
|
||||||
|
\OCP\JSON::success();
|
||||||
|
}
|
||||||
|
)
|
||||||
|
->requirements(array('user', 'categoryid'))
|
||||||
|
->defaults(array('user' => \OCP\User::getUser()));
|
||||||
|
|
||||||
|
$this->create('contacts_setpreference', 'preference/{user}/set')
|
||||||
|
->post()
|
||||||
|
->action(
|
||||||
|
function($params) {
|
||||||
|
session_write_close();
|
||||||
|
$request = Request::getRequest($params);
|
||||||
|
$key = $request->post['key'];
|
||||||
|
$value = $request->post['value'];
|
||||||
|
|
||||||
|
if(is_null($key) || $key === "") {
|
||||||
|
bailOut(App::$l10n->t('No key is given.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(is_null($value) || $value === "") {
|
||||||
|
bailOut(App::$l10n->t('No value is given.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(\OCP\Config::setUserValue($params['user'], 'contacts', $key, $value)) {
|
||||||
|
\OCP\JSON::success(array(
|
||||||
|
'data' => array(
|
||||||
|
'key' => $key,
|
||||||
|
'value' => $value)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
bailOut(App::$l10n->t(
|
||||||
|
'Could not set preference: ' . $key . ':' . $value)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
->requirements(array('user'))
|
||||||
|
->defaults(array('user' => \OCP\User::getUser()));
|
||||||
|
|
||||||
|
$this->create('contacts_index_properties', 'indexproperties/{user}/')
|
||||||
|
->post()
|
||||||
|
->action(
|
||||||
|
function($params) {
|
||||||
|
session_write_close();
|
||||||
|
\OC_Hook::emit('OCA\Contacts', 'indexProperties', array());
|
||||||
|
|
||||||
|
\OCP\Config::setUserValue($params['user'], 'contacts', 'contacts_properties_indexed', 'yes');
|
||||||
|
\OCP\JSON::success(array('isIndexed' => true));
|
||||||
|
}
|
||||||
|
)
|
||||||
|
->requirements(array('user'))
|
||||||
|
->defaults(array('user' => \OCP\User::getUser()));
|
@ -30,14 +30,14 @@
|
|||||||
top: -8px;
|
top: -8px;
|
||||||
left: -6px;
|
left: -6px;
|
||||||
}
|
}
|
||||||
#content textarea { font-family: inherit; }
|
#contact textarea { font-family: inherit; }
|
||||||
|
|
||||||
#content ::-moz-placeholder, #content input:-moz-placeholder, #content input[placeholder], #content input:placeholder, #content input:-ms-input-placeholder, #content input::-webkit-input-placeholder, #content input:-moz-placeholder {
|
#contact ::-moz-placeholder, #contact input:-moz-placeholder, #contact input[placeholder], #contact input:placeholder, #contact input:-ms-input-placeholder, #contact input::-webkit-input-placeholder, #contact input:-moz-placeholder {
|
||||||
color: #bbb;
|
color: #bbb;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
}
|
}
|
||||||
|
|
||||||
#content input:not([type="checkbox"]), #content select:not(.button), #content textarea {
|
#contact input:not([type="checkbox"]), #contact select:not(.button), #contact textarea {
|
||||||
background-color: #fefefe; border: 1px solid #fff !important;
|
background-color: #fefefe; border: 1px solid #fff !important;
|
||||||
-moz-appearance:none !important; -webkit-appearance: none !important;
|
-moz-appearance:none !important; -webkit-appearance: none !important;
|
||||||
-moz-box-shadow: none; -webkit-box-shadow: none; box-shadow: none;
|
-moz-box-shadow: none; -webkit-box-shadow: none; box-shadow: none;
|
||||||
@ -45,17 +45,17 @@
|
|||||||
-moz-box-sizing: border-box; -webkit-box-sizing: border-box; box-sizing: border-box;
|
-moz-box-sizing: border-box; -webkit-box-sizing: border-box; box-sizing: border-box;
|
||||||
float: left;
|
float: left;
|
||||||
}
|
}
|
||||||
#content input[type="button"]:hover, #content select:hover, #content select:focus, #content select:active, #content input[type="button"]:focus, #content .button:hover, button:hover { background-color:#fff; color:#333; }
|
#contact input[type="button"]:hover, #contact select:hover, #contact select:focus, #contact select:active, #contact input[type="button"]:focus, #contact .button:hover, button:hover { background-color:#fff; color:#333; }
|
||||||
|
|
||||||
#content fieldset, #content div, #content span, #content section {
|
#contact fieldset, #contact div, #contact span, #contact section {
|
||||||
-moz-box-sizing: border-box; -webkit-box-sizing: border-box; box-sizing: border-box;
|
-moz-box-sizing: border-box; -webkit-box-sizing: border-box; box-sizing: border-box;
|
||||||
}
|
}
|
||||||
#content fieldset.editor {
|
#contact fieldset.editor {
|
||||||
padding:4px;
|
padding:4px;
|
||||||
border: 1px solid #1d2d44;
|
border: 1px solid #1d2d44;
|
||||||
-moz-border-radius: 3px; -webkit-border-radius: 3px; border-radius: 3px; outline:none;
|
-moz-border-radius: 3px; -webkit-border-radius: 3px; border-radius: 3px; outline:none;
|
||||||
}
|
}
|
||||||
#content input:invalid, #content input:hover:not([type="checkbox"]), #content input:active:not([type="checkbox"]), #content input:focus:not([type="checkbox"]), #content input.active, #content textarea:focus, #content textarea:hover {
|
#contact input:invalid, #contact input:hover:not([type="checkbox"]), #contact input:active:not([type="checkbox"]), #contact input:focus:not([type="checkbox"]), #contact input.active, #contact textarea:focus, #contact textarea:hover {
|
||||||
border: 1px solid silver !important;
|
border: 1px solid silver !important;
|
||||||
-moz-border-radius:.3em; -webkit-border-radius:.3em; border-radius:.3em;
|
-moz-border-radius:.3em; -webkit-border-radius:.3em; border-radius:.3em;
|
||||||
outline:none; float: left;
|
outline:none; float: left;
|
||||||
@ -137,6 +137,7 @@
|
|||||||
#grouplist { z-index: 100; }
|
#grouplist { z-index: 100; }
|
||||||
#grouplist h3 .action:not(.starred):not(.checked):not(.favorite) { float: right; display: none; padding: 0; margin: auto; }
|
#grouplist h3 .action:not(.starred):not(.checked):not(.favorite) { float: right; display: none; padding: 0; margin: auto; }
|
||||||
#grouplist h3:not([data-type="shared"]):not(.editing):hover .action.numcontacts, #grouplist h3:not([data-type="shared"]):not(.editing) .active.action.numcontacts { display: inline-block; }
|
#grouplist h3:not([data-type="shared"]):not(.editing):hover .action.numcontacts, #grouplist h3:not([data-type="shared"]):not(.editing) .active.action.numcontacts { display: inline-block; }
|
||||||
|
.action.numcontacts { width: 6em; }
|
||||||
#grouplist h3.active[data-type="category"]:not(.editing):hover .action.delete { display: inline-block; }
|
#grouplist h3.active[data-type="category"]:not(.editing):hover .action.delete { display: inline-block; }
|
||||||
#grouplist h3:not(.editing) .action.delete { width: 20px; height: 20px; }
|
#grouplist h3:not(.editing) .action.delete { width: 20px; height: 20px; }
|
||||||
|
|
||||||
@ -201,7 +202,6 @@
|
|||||||
.no-svg .mail { background-image:url('%webroot%/core/img/actions/mail.png'); }
|
.no-svg .mail { background-image:url('%webroot%/core/img/actions/mail.png'); }
|
||||||
.no-svg .import, .no-svg .upload { background-image:url('%webroot%/core/img/actions/upload.png'); }
|
.no-svg .import, .no-svg .upload { background-image:url('%webroot%/core/img/actions/upload.png'); }
|
||||||
.no-svg .export, .no-svg .download { background-image:url('%webroot%/core/img/actions/download.png'); }
|
.no-svg .export, .no-svg .download { background-image:url('%webroot%/core/img/actions/download.png'); }
|
||||||
/*.no-svg .cloud { background-image:url('%webroot%/core/img/places/picture.png'); }*/
|
|
||||||
.no-svg .globe { background-image:url('%webroot%/core/img/actions/public.png'); }
|
.no-svg .globe { background-image:url('%webroot%/core/img/actions/public.png'); }
|
||||||
.no-svg .settings { background-image:url('%webroot%/core/img/actions/settings.svg'); }
|
.no-svg .settings { background-image:url('%webroot%/core/img/actions/settings.svg'); }
|
||||||
.no-svg .starred { background-image:url('%appswebroot%/contacts/img/starred.png'); background-size: contain; }
|
.no-svg .starred { background-image:url('%appswebroot%/contacts/img/starred.png'); background-size: contain; }
|
||||||
@ -222,7 +222,6 @@
|
|||||||
.svg .mail { background-image:url('%webroot%/core/img/actions/mail.svg'); }
|
.svg .mail { background-image:url('%webroot%/core/img/actions/mail.svg'); }
|
||||||
.svg .import,.svg .upload { background-image:url('%webroot%/core/img/actions/upload.svg'); }
|
.svg .import,.svg .upload { background-image:url('%webroot%/core/img/actions/upload.svg'); }
|
||||||
.svg .export,.svg .download { background-image:url('%webroot%/core/img/actions/download.svg'); }
|
.svg .export,.svg .download { background-image:url('%webroot%/core/img/actions/download.svg'); }
|
||||||
/*.svg .cloud { background-image:url('%webroot%/core/img/places/picture.svg'); }*/
|
|
||||||
.svg .globe { background-image:url('%webroot%/core/img/actions/public.svg'); }
|
.svg .globe { background-image:url('%webroot%/core/img/actions/public.svg'); }
|
||||||
.svg .settings { background-image:url('%webroot%/core/img/actions/settings.svg'); }
|
.svg .settings { background-image:url('%webroot%/core/img/actions/settings.svg'); }
|
||||||
.svg .starred { background-image:url('%appswebroot%/contacts/img/starred.svg'); background-size: contain; }
|
.svg .starred { background-image:url('%appswebroot%/contacts/img/starred.svg'); background-size: contain; }
|
||||||
@ -246,11 +245,16 @@
|
|||||||
}
|
}
|
||||||
.control > * { background: none repeat scroll 0 0 #F8F8F8; color: #555 !important; font-size: 100%; margin: 0px; }
|
.control > * { background: none repeat scroll 0 0 #F8F8F8; color: #555 !important; font-size: 100%; margin: 0px; }
|
||||||
|
|
||||||
|
.dim {
|
||||||
|
opacity: .50;filter:Alpha(Opacity=50);
|
||||||
|
z-index: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.ui-draggable { height: 3em; z-index: 1000; }
|
.ui-draggable { height: 3em; z-index: 1000; }
|
||||||
.ui-draggable { height: 3em; z-index: 1000; }
|
.dragContact {
|
||||||
.ui-draggable-dragging {
|
|
||||||
cursor: move;
|
cursor: move;
|
||||||
background-repeat: no-repeat !important;
|
background-repeat: no-repeat !important;
|
||||||
|
background-position: .3em .3em !important;
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
z-index: 5;
|
z-index: 5;
|
||||||
width: 200px; height: 30px;
|
width: 200px; height: 30px;
|
||||||
@ -258,6 +262,8 @@
|
|||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
border: thin solid silver; border-radius: 3px;
|
border: thin solid silver; border-radius: 3px;
|
||||||
padding: 3px;
|
padding: 3px;
|
||||||
|
z-index: 1000;
|
||||||
|
transition: background-image 500ms ease 0s;
|
||||||
}
|
}
|
||||||
.ui-state-hover { border: 1px solid dashed; z-index: 1; }
|
.ui-state-hover { border: 1px solid dashed; z-index: 1; }
|
||||||
|
|
||||||
@ -318,7 +324,7 @@ ul.propertylist { width: 450px; }
|
|||||||
.propertylist li > input[type="checkbox"].impp { clear: none; }
|
.propertylist li > input[type="checkbox"].impp { clear: none; }
|
||||||
.propertylist li > label.xab { display: block; color: #bbb; float:left; clear: both; padding: 0.5em 0 0 2.5em; }
|
.propertylist li > label.xab { display: block; color: #bbb; float:left; clear: both; padding: 0.5em 0 0 2.5em; }
|
||||||
.propertylist li > label.xab:hover { color: #777; }
|
.propertylist li > label.xab:hover { color: #777; }
|
||||||
#rightcontent label, #rightcontent dt, #rightcontent th, #rightcontent .label {
|
#contact label, #contact dt, #contact th, #contact .label {
|
||||||
float: left;
|
float: left;
|
||||||
font-size: 0.7em; font-weight: bold;
|
font-size: 0.7em; font-weight: bold;
|
||||||
color: #bbb !important;
|
color: #bbb !important;
|
||||||
@ -327,9 +333,9 @@ ul.propertylist { width: 450px; }
|
|||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
-moz-box-sizing: border-box;
|
-moz-box-sizing: border-box;
|
||||||
}
|
}
|
||||||
#rightcontent label:hover, #rightcontent dt:hover, #rightcontent input.label:hover { color: #777 !important; }
|
#contact label:hover, #contact dt:hover, #contact input.label:hover { color: #777 !important; }
|
||||||
#rightcontent input.label, #rightcontent input.label { margin:-2px; }
|
#contact input.label, #contact input.label { margin:-2px; }
|
||||||
#rightcontent input.label:hover, #rightcontent input.label:active { border: 0 none !important; border-radius: 0; cursor: pointer; }
|
#contact input.label:hover, #contact input.label:active { border: 0 none !important; border-radius: 0; cursor: pointer; }
|
||||||
.typelist[type="button"] { float: left; max-width: 8em; border: 0; background-color: #fff; color: #bbb; box-shadow: none; } /* for multiselect */
|
.typelist[type="button"] { float: left; max-width: 8em; border: 0; background-color: #fff; color: #bbb; box-shadow: none; } /* for multiselect */
|
||||||
.typelist[type="button"]:hover { color: #777; } /* for multiselect */
|
.typelist[type="button"]:hover { color: #777; } /* for multiselect */
|
||||||
.addresslist { clear: both; font-weight: bold; }
|
.addresslist { clear: both; font-weight: bold; }
|
||||||
@ -407,7 +413,7 @@ ul.propertylist { width: 450px; }
|
|||||||
}
|
}
|
||||||
/* Single elements */
|
/* Single elements */
|
||||||
#file_upload_target, #import_upload_target, #crop_target { display:none; }
|
#file_upload_target, #import_upload_target, #crop_target { display:none; }
|
||||||
#import_fileupload {
|
#import_upload_start {
|
||||||
height: 2.29em;
|
height: 2.29em;
|
||||||
/*width: 2.5em;*/
|
/*width: 2.5em;*/
|
||||||
width: 95%;
|
width: 95%;
|
||||||
@ -417,6 +423,12 @@ ul.propertylist { width: 450px; }
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
z-index: 1001;
|
z-index: 1001;
|
||||||
}
|
}
|
||||||
|
/* Those dang Germans and their long sentences ;) */
|
||||||
|
label[for="import_upload_start"] {
|
||||||
|
display: inline-block;
|
||||||
|
max-width: 16em;
|
||||||
|
white-space: pre-line;
|
||||||
|
}
|
||||||
.import-upload-button {
|
.import-upload-button {
|
||||||
background-image: url("%webroot%/core/img/actions/upload.svg");
|
background-image: url("%webroot%/core/img/actions/upload.svg");
|
||||||
background-position: center center;
|
background-position: center center;
|
||||||
@ -438,6 +450,10 @@ input:not([type="checkbox"]).propertytype {
|
|||||||
text-align: right;
|
text-align: right;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.thumbnail {
|
||||||
|
background-image:url('%appswebroot%/contacts/img/person.png');
|
||||||
|
}
|
||||||
input[type="checkbox"].propertytype { width: 10px; }
|
input[type="checkbox"].propertytype { width: 10px; }
|
||||||
.contactphoto {
|
.contactphoto {
|
||||||
float: left; display: inline-block;
|
float: left; display: inline-block;
|
||||||
@ -466,8 +482,27 @@ input[type="checkbox"].propertytype { width: 10px; }
|
|||||||
#phototools li { display: inline; }
|
#phototools li { display: inline; }
|
||||||
#phototools li a { float:left; opacity: 0.6; }
|
#phototools li a { float:left; opacity: 0.6; }
|
||||||
#phototools li a:hover { opacity: 0.8; }
|
#phototools li a:hover { opacity: 0.8; }
|
||||||
#contactphoto_fileupload, #import_fileupload { -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; filter:alpha(opacity=0); opacity:0; z-index:1001; }
|
#contactphoto_fileupload, #import_upload_start { -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; filter:alpha(opacity=0); opacity:0; z-index:1001; }
|
||||||
|
|
||||||
|
#dialog-merge-contacts .mergelist {
|
||||||
|
margin: 10px;
|
||||||
|
}
|
||||||
|
#dialog-merge-contacts .mergelist > li {
|
||||||
|
height: 30px;
|
||||||
|
-webkit-transition:background-image 500ms; -moz-transition:background-image 500ms; -o-transition:background-image 500ms; transition:background-image 500ms;
|
||||||
|
position:relative;
|
||||||
|
background-position: 0 .2em !important; background-repeat:no-repeat !important;
|
||||||
|
}
|
||||||
|
#dialog-merge-contacts .mergelist > li > input {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
#dialog-merge-contacts .mergelist > li > input:hover, #dialog-merge-contacts .mergelist > li > input:checked {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
#dialog-merge-contacts .mergelist > li > label {
|
||||||
|
padding-left: 20px;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
.no-svg .favorite { display: inline-block; float: left; height: 20px; width: 20px; background-image:url('%appswebroot%/contacts/img/inactive_star.png'); }
|
.no-svg .favorite { display: inline-block; float: left; height: 20px; width: 20px; background-image:url('%appswebroot%/contacts/img/inactive_star.png'); }
|
||||||
.no-svg .favorite.active, .favorite:hover { background-image:url('%appswebroot%/contacts/img/active_star.png'); }
|
.no-svg .favorite.active, .favorite:hover { background-image:url('%appswebroot%/contacts/img/active_star.png'); }
|
||||||
.no-svg .favorite.inactive { background-image:url('%appswebroot%/contacts/img/inactive_star.png'); }
|
.no-svg .favorite.inactive { background-image:url('%appswebroot%/contacts/img/inactive_star.png'); }
|
||||||
@ -558,7 +593,6 @@ input[type="checkbox"].propertytype { width: 10px; }
|
|||||||
#contactlist tr > td.name { font-weight: bold; text-indent: 1.6em; -webkit-transition:background-image 500ms; -moz-transition:background-image 500ms; -o-transition:background-image 500ms; transition:background-image 500ms; position:relative; background-position:1em .5em !important; background-repeat:no-repeat !important; }
|
#contactlist tr > td.name { font-weight: bold; text-indent: 1.6em; -webkit-transition:background-image 500ms; -moz-transition:background-image 500ms; -o-transition:background-image 500ms; transition:background-image 500ms; position:relative; background-position:1em .5em !important; background-repeat:no-repeat !important; }
|
||||||
#contactlist tr > td a.mailto { position: absolute; float: right; clear: none; cursor:pointer; width:16px; height:16px; margin: 2px; z-index: 200; opacity: 0.6; background-image:url('%webroot%/core/img/actions/mail.svg'); }
|
#contactlist tr > td a.mailto { position: absolute; float: right; clear: none; cursor:pointer; width:16px; height:16px; margin: 2px; z-index: 200; opacity: 0.6; background-image:url('%webroot%/core/img/actions/mail.svg'); }
|
||||||
#contactlist tr > td a.mailto:hover { opacity: 0.8; }
|
#contactlist tr > td a.mailto:hover { opacity: 0.8; }
|
||||||
#contactlist.dim { background-image: #ddd; opacity: .50;filter:Alpha(Opacity=50); }
|
|
||||||
|
|
||||||
#contact {
|
#contact {
|
||||||
background-color: white; color: #333333;
|
background-color: white; color: #333333;
|
||||||
|
36
css/jquery.ocdialog.css
Normal file
36
css/jquery.ocdialog.css
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
.oc-dialog {
|
||||||
|
background: white;
|
||||||
|
color: #333333;
|
||||||
|
border-radius: 3px; box-shadow: 0 0 7px #888888;
|
||||||
|
padding: 15px;
|
||||||
|
z-index: 200;
|
||||||
|
font-size: 100%;
|
||||||
|
}
|
||||||
|
.oc-dialog-title {
|
||||||
|
background: white;
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 110%;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
.oc-dialog-content {
|
||||||
|
z-index: 200;
|
||||||
|
background: white;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
.oc-dialog-separator {
|
||||||
|
}
|
||||||
|
.oc-dialog-buttonrow {
|
||||||
|
background: white;
|
||||||
|
float: right;
|
||||||
|
position: relative;
|
||||||
|
bottom: 0;
|
||||||
|
display: block;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.oc-dialog-close {
|
||||||
|
position:absolute;
|
||||||
|
top:7px; right:7px;
|
||||||
|
height:20px; width:20px;
|
||||||
|
background:url('%webroot%/core/img/actions/delete.svg') no-repeat center;
|
||||||
|
}
|
@ -43,7 +43,9 @@ if(!is_null($bookid)) {
|
|||||||
}
|
}
|
||||||
} elseif(!is_null($contactid)) {
|
} elseif(!is_null($contactid)) {
|
||||||
try {
|
try {
|
||||||
$data = OCA\Contacts\VCard::find($contactid);
|
$app = new OCA\Contacts\App();
|
||||||
|
$contact = $app->getContact($_GET['backend'], $_GET['addressbookid'], $_GET['contactid']);
|
||||||
|
$data = $contact->serialize();
|
||||||
} catch(Exception $e) {
|
} catch(Exception $e) {
|
||||||
OCP\JSON::error(
|
OCP\JSON::error(
|
||||||
array(
|
array(
|
||||||
@ -56,8 +58,8 @@ if(!is_null($bookid)) {
|
|||||||
}
|
}
|
||||||
header('Content-Type: text/vcard');
|
header('Content-Type: text/vcard');
|
||||||
header('Content-Disposition: inline; filename='
|
header('Content-Disposition: inline; filename='
|
||||||
. str_replace(' ', '_', $data['fullname']) . '.vcf');
|
. str_replace(' ', '_', $contact->FN) . '.vcf');
|
||||||
echo $data['carddata'];
|
echo $data;
|
||||||
} elseif(!is_null($selectedids)) {
|
} elseif(!is_null($selectedids)) {
|
||||||
$selectedids = explode(',', $selectedids);
|
$selectedids = explode(',', $selectedids);
|
||||||
$l10n = \OC_L10N::get('contacts');
|
$l10n = \OC_L10N::get('contacts');
|
||||||
|
127
import.php
127
import.php
@ -5,12 +5,17 @@
|
|||||||
* later.
|
* later.
|
||||||
* See the COPYING-README file.
|
* See the COPYING-README file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
namespace OCA\Contacts;
|
||||||
|
|
||||||
|
use Sabre\VObject;
|
||||||
|
|
||||||
//check for addressbooks rights or create new one
|
//check for addressbooks rights or create new one
|
||||||
ob_start();
|
ob_start();
|
||||||
|
|
||||||
OCP\JSON::checkLoggedIn();
|
\OCP\JSON::checkLoggedIn();
|
||||||
OCP\App::checkAppEnabled('contacts');
|
\OCP\App::checkAppEnabled('contacts');
|
||||||
OCP\JSON::callCheck();
|
\OCP\JSON::callCheck();
|
||||||
session_write_close();
|
session_write_close();
|
||||||
|
|
||||||
$nl = "\n";
|
$nl = "\n";
|
||||||
@ -19,70 +24,49 @@ global $progresskey;
|
|||||||
$progresskey = 'contacts.import-' . (isset($_GET['progresskey'])?$_GET['progresskey']:'');
|
$progresskey = 'contacts.import-' . (isset($_GET['progresskey'])?$_GET['progresskey']:'');
|
||||||
|
|
||||||
if (isset($_GET['progress']) && $_GET['progress']) {
|
if (isset($_GET['progress']) && $_GET['progress']) {
|
||||||
echo OC_Cache::get($progresskey);
|
echo \OC_Cache::get($progresskey);
|
||||||
die;
|
die;
|
||||||
}
|
}
|
||||||
|
|
||||||
function writeProgress($pct) {
|
function writeProgress($pct) {
|
||||||
global $progresskey;
|
global $progresskey;
|
||||||
OC_Cache::set($progresskey, $pct, 300);
|
\OC_Cache::set($progresskey, $pct, 300);
|
||||||
}
|
}
|
||||||
writeProgress('10');
|
writeProgress('10');
|
||||||
$view = null;
|
$view = null;
|
||||||
$inputfile = strtr($_POST['file'], array('/' => '', "\\" => ''));
|
$inputfile = strtr($_POST['file'], array('/' => '', "\\" => ''));
|
||||||
if(OC\Files\Filesystem::isFileBlacklisted($inputfile)) {
|
if(\OC\Files\Filesystem::isFileBlacklisted($inputfile)) {
|
||||||
OCP\JSON::error(array('data' => array('message' => 'Upload of blacklisted file: ' . $inputfile)));
|
\OCP\JSON::error(array('data' => array('message' => 'Upload of blacklisted file: ' . $inputfile)));
|
||||||
exit();
|
exit();
|
||||||
}
|
}
|
||||||
if(isset($_POST['fstype']) && $_POST['fstype'] == 'OC_FilesystemView') {
|
if(isset($_POST['fstype']) && $_POST['fstype'] == 'OC_FilesystemView') {
|
||||||
$view = OCP\Files::getStorage('contacts');
|
$view = \OCP\Files::getStorage('contacts');
|
||||||
$file = $view->file_get_contents('/imports/' . $inputfile);
|
$file = $view->file_get_contents('/imports/' . $inputfile);
|
||||||
} else {
|
} else {
|
||||||
$file = \OC\Files\Filesystem::file_get_contents($_POST['path'] . '/' . $inputfile);
|
$file = \OC\Files\Filesystem::file_get_contents($_POST['path'] . '/' . $inputfile);
|
||||||
}
|
}
|
||||||
if(!$file) {
|
if(!$file) {
|
||||||
OCP\JSON::error(array('data' => array('message' => 'Import file was empty.')));
|
\OCP\JSON::error(array('data' => array('message' => 'Import file was empty.')));
|
||||||
exit();
|
exit();
|
||||||
}
|
}
|
||||||
if(isset($_POST['method']) && $_POST['method'] == 'new') {
|
|
||||||
$id = OCA\Contacts\Addressbook::add(OCP\USER::getUser(),
|
$id = $_POST['id'];
|
||||||
$_POST['addressbookname']);
|
|
||||||
if(!$id) {
|
if(!$id) {
|
||||||
OCP\JSON::error(
|
\OCP\JSON::error(
|
||||||
array(
|
array(
|
||||||
'data' => array('message' => 'Error creating address book.')
|
'data' => array(
|
||||||
|
'message' => 'Error getting the ID of the address book.',
|
||||||
|
'file'=>\OCP\Util::sanitizeHTML($inputfile)
|
||||||
)
|
)
|
||||||
);
|
)
|
||||||
exit();
|
);
|
||||||
}
|
exit();
|
||||||
OCA\Contacts\Addressbook::setActive($id, 1);
|
|
||||||
}else{
|
|
||||||
$id = $_POST['id'];
|
|
||||||
if(!$id) {
|
|
||||||
OCP\JSON::error(
|
|
||||||
array(
|
|
||||||
'data' => array(
|
|
||||||
'message' => 'Error getting the ID of the address book.',
|
|
||||||
'file'=>OCP\Util::sanitizeHTML($inputfile)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
exit();
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
OCA\Contacts\Addressbook::find($id); // is owner access check
|
|
||||||
} catch(Exception $e) {
|
|
||||||
OCP\JSON::error(
|
|
||||||
array(
|
|
||||||
'data' => array(
|
|
||||||
'message' => $e->getMessage(),
|
|
||||||
'file'=>OCP\Util::sanitizeHTML($inputfile)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
exit();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$app = new App();
|
||||||
|
$addressBook = $app->getAddressBook('local', $id);
|
||||||
|
|
||||||
//analyse the contacts file
|
//analyse the contacts file
|
||||||
writeProgress('40');
|
writeProgress('40');
|
||||||
$file = str_replace(array("\r","\n\n"), array("\n","\n"), $file);
|
$file = str_replace(array("\r","\n\n"), array("\n","\n"), $file);
|
||||||
@ -110,69 +94,72 @@ $imported = 0;
|
|||||||
$failed = 0;
|
$failed = 0;
|
||||||
$partial = 0;
|
$partial = 0;
|
||||||
if(!count($parts) > 0) {
|
if(!count($parts) > 0) {
|
||||||
OCP\JSON::error(
|
\OCP\JSON::error(
|
||||||
array(
|
array(
|
||||||
'data' => array(
|
'data' => array(
|
||||||
'message' => 'No contacts to import in '
|
'message' => 'No contacts to import in '
|
||||||
. OCP\Util::sanitizeHTML($inputfile).'. Please check if the file is corrupted.',
|
. \OCP\Util::sanitizeHTML($inputfile).'. Please check if the file is corrupted.',
|
||||||
'file'=>OCP\Util::sanitizeHTML($inputfile)
|
'file'=>OCP\Util::sanitizeHTML($inputfile)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
if(isset($_POST['fstype']) && $_POST['fstype'] == 'OC_FilesystemView') {
|
if(isset($_POST['fstype']) && $_POST['fstype'] == 'OC_FilesystemView') {
|
||||||
if(!$view->unlink('/imports/' . $inputfile)) {
|
if(!$view->unlink('/imports/' . $inputfile)) {
|
||||||
OCP\Util::writeLog('contacts',
|
\OCP\Util::writeLog('contacts',
|
||||||
'Import: Error unlinking OC_FilesystemView ' . '/' . OCP\Util::sanitizeHTML($inputfile),
|
'Import: Error unlinking OC_FilesystemView ' . '/' . \OCP\Util::sanitizeHTML($inputfile),
|
||||||
OCP\Util::ERROR);
|
\OCP\Util::ERROR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
exit();
|
exit();
|
||||||
}
|
}
|
||||||
foreach($parts as $part) {
|
foreach($parts as $part) {
|
||||||
try {
|
try {
|
||||||
$vcard = Sabre\VObject\Reader::read($part);
|
$vcard = VObject\Reader::read($part);
|
||||||
} catch (Sabre\VObject\ParseException $e) {
|
} catch (VObject\ParseException $e) {
|
||||||
try {
|
try {
|
||||||
$vcard = Sabre\VObject\Reader::read($part, Sabre\VObject\Reader::OPTION_IGNORE_INVALID_LINES);
|
$vcard = VObject\Reader::read($part, VObject\Reader::OPTION_IGNORE_INVALID_LINES);
|
||||||
$partial += 1;
|
$partial += 1;
|
||||||
OCP\Util::writeLog('contacts',
|
\OCP\Util::writeLog('contacts',
|
||||||
'Import: Retrying reading card. Error parsing VCard: ' . $e->getMessage(),
|
'Import: Retrying reading card. Error parsing VCard: ' . $e->getMessage(),
|
||||||
OCP\Util::ERROR);
|
\OCP\Util::ERROR);
|
||||||
} catch (Exception $e) {
|
} catch (\Exception $e) {
|
||||||
$failed += 1;
|
$failed += 1;
|
||||||
OCP\Util::writeLog('contacts',
|
\OCP\Util::writeLog('contacts',
|
||||||
'Import: skipping card. Error parsing VCard: ' . $e->getMessage(),
|
'Import: skipping card. Error parsing VCard: ' . $e->getMessage(),
|
||||||
OCP\Util::ERROR);
|
\OCP\Util::ERROR);
|
||||||
continue; // Ditch cards that can't be parsed by Sabre.
|
continue; // Ditch cards that can't be parsed by Sabre.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
OCA\Contacts\VCard::add($id, $vcard);
|
if($addressBook->addChild($vcard)) {
|
||||||
$imported += 1;
|
$imported += 1;
|
||||||
} catch (Exception $e) {
|
} else {
|
||||||
OCP\Util::writeLog('contacts',
|
$failed += 1;
|
||||||
'Error importing vcard: ' . $e->getMessage() . $nl . $vcard,
|
}
|
||||||
OCP\Util::ERROR);
|
} catch (\Exception $e) {
|
||||||
|
\OCP\Util::writeLog('contacts', __LINE__ . ' ' .
|
||||||
|
'Error importing vcard: ' . $e->getMessage() . $nl . $vcard->serialize(),
|
||||||
|
\OCP\Util::ERROR);
|
||||||
$failed += 1;
|
$failed += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//done the import
|
//done the import
|
||||||
writeProgress('100');
|
writeProgress('100');
|
||||||
sleep(3);
|
sleep(3);
|
||||||
OC_Cache::remove($progresskey);
|
\OC_Cache::remove($progresskey);
|
||||||
if(isset($_POST['fstype']) && $_POST['fstype'] == 'OC_FilesystemView') {
|
if(isset($_POST['fstype']) && $_POST['fstype'] == 'OC_FilesystemView') {
|
||||||
if(!$view->unlink('/imports/' . $inputfile)) {
|
if(!$view->unlink('/imports/' . $inputfile)) {
|
||||||
OCP\Util::writeLog('contacts',
|
\OCP\Util::writeLog('contacts',
|
||||||
'Import: Error unlinking OC_FilesystemView ' . '/' . $inputfile,
|
'Import: Error unlinking OC_FilesystemView ' . '/' . $inputfile,
|
||||||
OCP\Util::ERROR);
|
\OCP\Util::ERROR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
OCP\JSON::success(
|
\OCP\JSON::success(
|
||||||
array(
|
array(
|
||||||
'data' => array(
|
'data' => array(
|
||||||
'imported'=>$imported,
|
'imported'=>$imported,
|
||||||
'failed'=>$failed,
|
'failed'=>$failed,
|
||||||
'file'=>OCP\Util::sanitizeHTML($inputfile),
|
'file'=>\OCP\Util::sanitizeHTML($inputfile),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
71
index.php
71
index.php
@ -1,64 +1,67 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* Copyright (c) 2012 Thomas Tanghus <thomas@tanghus.net>
|
* Copyright (c) 2012, 2013 Thomas Tanghus <thomas@tanghus.net>
|
||||||
* Copyright (c) 2011 Jakob Sack mail@jakobsack.de
|
* Copyright (c) 2011 Jakob Sack mail@jakobsack.de
|
||||||
* This file is licensed under the Affero General Public License version 3 or
|
* This file is licensed under the Affero General Public License version 3 or
|
||||||
* later.
|
* later.
|
||||||
* See the COPYING-README file.
|
* See the COPYING-README file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
namespace OCA\Contacts;
|
||||||
|
|
||||||
// Check if we are a user
|
// Check if we are a user
|
||||||
OCP\User::checkLoggedIn();
|
\OCP\User::checkLoggedIn();
|
||||||
OCP\App::checkAppEnabled('contacts');
|
\OCP\App::checkAppEnabled('contacts');
|
||||||
|
|
||||||
// Get active address books. This creates a default one if none exists.
|
// Get active address books. This creates a default one if none exists.
|
||||||
$ids = OCA\Contacts\Addressbook::activeIds(OCP\USER::getUser());
|
//$ids = OCA\Contacts\Addressbook::activeIds(OCP\USER::getUser());
|
||||||
|
|
||||||
// Load the files we need
|
// Load the files we need
|
||||||
OCP\App::setActiveNavigationEntry('contacts_index');
|
\OCP\App::setActiveNavigationEntry('contacts_index');
|
||||||
|
|
||||||
$impp_types = OCA\Contacts\App::getTypesOfProperty('IMPP');
|
$impp_types = Utils\Properties::getTypesForProperty('IMPP');
|
||||||
$adr_types = OCA\Contacts\App::getTypesOfProperty('ADR');
|
$adr_types = Utils\Properties::getTypesForProperty('ADR');
|
||||||
$phone_types = OCA\Contacts\App::getTypesOfProperty('TEL');
|
$phone_types = Utils\Properties::getTypesForProperty('TEL');
|
||||||
$email_types = OCA\Contacts\App::getTypesOfProperty('EMAIL');
|
$email_types = Utils\Properties::getTypesForProperty('EMAIL');
|
||||||
$ims = OCA\Contacts\App::getIMOptions();
|
$ims = Utils\Properties::getIMOptions();
|
||||||
$im_protocols = array();
|
$im_protocols = array();
|
||||||
foreach($ims as $name => $values) {
|
foreach($ims as $name => $values) {
|
||||||
$im_protocols[$name] = $values['displayname'];
|
$im_protocols[$name] = $values['displayname'];
|
||||||
}
|
}
|
||||||
$categories = OCA\Contacts\App::getCategories();
|
|
||||||
|
|
||||||
$maxUploadFilesize = OCP\Util::maxUploadFilesize('/');
|
$maxUploadFilesize = \OCP\Util::maxUploadFilesize('/');
|
||||||
|
|
||||||
OCP\Util::addscript('', 'multiselect');
|
\OCP\Util::addscript('', 'multiselect');
|
||||||
OCP\Util::addscript('', 'jquery.multiselect');
|
\OCP\Util::addscript('', 'jquery.multiselect');
|
||||||
OCP\Util::addscript('', 'oc-vcategories');
|
\OCP\Util::addscript('', 'oc-vcategories');
|
||||||
OCP\Util::addscript('contacts', 'modernizr.custom');
|
\OCP\Util::addscript('', 'octemplate');
|
||||||
OCP\Util::addscript('contacts', 'app');
|
\OCP\Util::addscript('contacts', 'modernizr.custom');
|
||||||
OCP\Util::addscript('contacts', 'contacts');
|
\OCP\Util::addscript('contacts', 'app');
|
||||||
OCP\Util::addscript('contacts', 'groups');
|
\OCP\Util::addscript('contacts', 'contacts');
|
||||||
OCP\Util::addscript('contacts', 'expanding');
|
\OCP\Util::addscript('contacts', 'storage');
|
||||||
OCP\Util::addscript('contacts', 'jquery.combobox');
|
\OCP\Util::addscript('contacts', 'groups');
|
||||||
OCP\Util::addscript('files', 'jquery.fileupload');
|
//\OCP\Util::addscript('contacts', 'expanding');
|
||||||
OCP\Util::addscript('contacts', 'jquery.Jcrop');
|
\OCP\Util::addscript('contacts', 'jquery.combobox');
|
||||||
OCP\Util::addStyle('3rdparty/fontawesome', 'font-awesome');
|
\OCP\Util::addscript('contacts', 'jquery.ocdialog');
|
||||||
OCP\Util::addStyle('contacts', 'font-awesome');
|
\OCP\Util::addscript('files', 'jquery.fileupload');
|
||||||
OCP\Util::addStyle('', 'multiselect');
|
\OCP\Util::addscript('contacts', 'jquery.Jcrop');
|
||||||
OCP\Util::addStyle('', 'jquery.multiselect');
|
\OCP\Util::addStyle('3rdparty/fontawesome', 'font-awesome');
|
||||||
OCP\Util::addStyle('contacts', 'jquery.combobox');
|
\OCP\Util::addStyle('contacts', 'font-awesome');
|
||||||
OCP\Util::addStyle('contacts', 'jquery.Jcrop');
|
\OCP\Util::addStyle('', 'multiselect');
|
||||||
OCP\Util::addStyle('contacts', 'contacts');
|
\OCP\Util::addStyle('', 'jquery.multiselect');
|
||||||
|
\OCP\Util::addStyle('contacts', 'jquery.combobox');
|
||||||
|
\OCP\Util::addStyle('contacts', 'jquery.ocdialog');
|
||||||
|
\OCP\Util::addStyle('contacts', 'jquery.Jcrop');
|
||||||
|
\OCP\Util::addStyle('contacts', 'contacts');
|
||||||
|
|
||||||
$tmpl = new OCP\Template( "contacts", "contacts", "user" );
|
$tmpl = new \OCP\Template( "contacts", "contacts", "user" );
|
||||||
$tmpl->assign('uploadMaxFilesize', $maxUploadFilesize);
|
$tmpl->assign('uploadMaxFilesize', $maxUploadFilesize);
|
||||||
$tmpl->assign('uploadMaxHumanFilesize',
|
$tmpl->assign('uploadMaxHumanFilesize',
|
||||||
OCP\Util::humanFileSize($maxUploadFilesize), false);
|
\OCP\Util::humanFileSize($maxUploadFilesize), false);
|
||||||
$tmpl->assign('addressbooks', OCA\Contacts\Addressbook::all(OCP\USER::getUser()));
|
//$tmpl->assign('addressbooks', OCA\Contacts\Addressbook::all(OCP\USER::getUser()));
|
||||||
$tmpl->assign('phone_types', $phone_types);
|
$tmpl->assign('phone_types', $phone_types);
|
||||||
$tmpl->assign('email_types', $email_types);
|
$tmpl->assign('email_types', $email_types);
|
||||||
$tmpl->assign('adr_types', $adr_types);
|
$tmpl->assign('adr_types', $adr_types);
|
||||||
$tmpl->assign('impp_types', $impp_types);
|
$tmpl->assign('impp_types', $impp_types);
|
||||||
$tmpl->assign('categories', $categories);
|
|
||||||
$tmpl->assign('im_protocols', $im_protocols);
|
$tmpl->assign('im_protocols', $im_protocols);
|
||||||
$tmpl->printPage();
|
$tmpl->printPage();
|
||||||
|
899
js/app.js
899
js/app.js
@ -74,14 +74,6 @@ utils.moveCursorToEnd = function(el) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if (typeof Object.create !== 'function') {
|
|
||||||
Object.create = function (o) {
|
|
||||||
function F() {}
|
|
||||||
F.prototype = o;
|
|
||||||
return new F();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
Array.prototype.clone = function() {
|
Array.prototype.clone = function() {
|
||||||
return this.slice(0);
|
return this.slice(0);
|
||||||
};
|
};
|
||||||
@ -157,25 +149,25 @@ OC.notify = function(params) {
|
|||||||
OC.Contacts = OC.Contacts || {
|
OC.Contacts = OC.Contacts || {
|
||||||
init:function() {
|
init:function() {
|
||||||
if(oc_debug === true) {
|
if(oc_debug === true) {
|
||||||
$(document).ajaxError(function(e, xhr, settings, exception) {
|
$.error = console.error;
|
||||||
// Don't try to get translation because it's likely a network error.
|
$(document).ajaxError(function(e, xhr, settings, exception) {
|
||||||
OC.notify({
|
console.error('Error in: ', settings.url, ' : ', xhr.responseText, exception);
|
||||||
message: 'error in: ' + settings.url + ', '+'error: ' + xhr.responseText
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
this.scrollTimeoutMiliSecs = 100;
|
this.scrollTimeoutMiliSecs = 100;
|
||||||
this.isScrolling = false;
|
this.isScrolling = false;
|
||||||
this.cacheElements();
|
this.cacheElements();
|
||||||
|
this.storage = new OC.Contacts.Storage();
|
||||||
this.contacts = new OC.Contacts.ContactList(
|
this.contacts = new OC.Contacts.ContactList(
|
||||||
|
this.storage,
|
||||||
this.$contactList,
|
this.$contactList,
|
||||||
this.$contactListItemTemplate,
|
this.$contactListItemTemplate,
|
||||||
this.$contactDragItemTemplate,
|
this.$contactDragItemTemplate,
|
||||||
this.$contactFullTemplate,
|
this.$contactFullTemplate,
|
||||||
this.detailTemplates
|
this.detailTemplates
|
||||||
);
|
);
|
||||||
this.groups = new OC.Contacts.GroupList(this.$groupList, this.$groupListItemTemplate);
|
this.groups = new OC.Contacts.GroupList(this.storage, this.$groupList, this.$groupListItemTemplate);
|
||||||
OCCategories.changed = this.groups.categoriesChanged;
|
OCCategories.changed = this.groups.categoriesChanged;
|
||||||
OCCategories.app = 'contacts';
|
OCCategories.app = 'contacts';
|
||||||
OCCategories.type = 'contact';
|
OCCategories.type = 'contact';
|
||||||
@ -233,7 +225,7 @@ OC.Contacts = OC.Contacts || {
|
|||||||
this.$ninjahelp = $('#ninjahelp');
|
this.$ninjahelp = $('#ninjahelp');
|
||||||
this.$firstRun = $('#firstrun');
|
this.$firstRun = $('#firstrun');
|
||||||
this.$settings = $('#contacts-settings');
|
this.$settings = $('#contacts-settings');
|
||||||
this.$importFileInput = $('#import_fileupload');
|
this.$importFileInput = $('#import_upload_start');
|
||||||
this.$importIntoSelect = $('#import_into');
|
this.$importIntoSelect = $('#import_into');
|
||||||
},
|
},
|
||||||
// Build the select to add/remove from groups.
|
// Build the select to add/remove from groups.
|
||||||
@ -287,13 +279,18 @@ OC.Contacts = OC.Contacts || {
|
|||||||
$(window).trigger('beforeunload');
|
$(window).trigger('beforeunload');
|
||||||
});
|
});
|
||||||
|
|
||||||
$(window).bind('hashchange', function() {
|
this.hashChange = function() {
|
||||||
console.log('hashchange', window.location.hash)
|
//console.log('hashchange', window.location.hash)
|
||||||
var id = parseInt(window.location.hash.substr(1));
|
var id = parseInt(window.location.hash.substr(1));
|
||||||
if(id) {
|
if(id && id !== self.currentid) {
|
||||||
self.openContact(id);
|
self.openContact(id);
|
||||||
|
} else if(!id && self.currentid) {
|
||||||
|
self.closeContact(self.currentid);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
|
$(window).bind('popstate', this.hashChange);
|
||||||
|
$(window).bind('hashchange', this.hashChange);
|
||||||
|
|
||||||
// App specific events
|
// App specific events
|
||||||
$(document).bind('status.contact.deleted', function(e, data) {
|
$(document).bind('status.contact.deleted', function(e, data) {
|
||||||
@ -312,7 +309,10 @@ OC.Contacts = OC.Contacts || {
|
|||||||
self.hideActions();
|
self.hideActions();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Keep error messaging at one place to be able to replace it.
|
||||||
$(document).bind('status.contact.error', function(e, data) {
|
$(document).bind('status.contact.error', function(e, data) {
|
||||||
|
console.warn(data.message);
|
||||||
|
console.trace();
|
||||||
OC.notify({message:data.message});
|
OC.notify({message:data.message});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -344,11 +344,15 @@ OC.Contacts = OC.Contacts || {
|
|||||||
self.openContact(self.currentid);
|
self.openContact(self.currentid);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if(!result.is_indexed) {
|
if(!contacts_properties_indexed) {
|
||||||
// Wait a couple of mins then check if contacts are indexed.
|
// Wait a couple of mins then check if contacts are indexed.
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
OC.notify({message:t('contacts', 'Indexing contacts'), timeout:20});
|
$.when($.post(OC.Router.generate('contacts_index_properties')))
|
||||||
$.post(OC.filePath('contacts', 'ajax', 'indexproperties.php'));
|
.then(function(response) {
|
||||||
|
if(!response.isIndexed) {
|
||||||
|
OC.notify({message:t('contacts', 'Indexing contacts'), timeout:20});
|
||||||
|
}
|
||||||
|
});
|
||||||
}, 10000);
|
}, 10000);
|
||||||
} else {
|
} else {
|
||||||
console.log('contacts are indexed.');
|
console.log('contacts are indexed.');
|
||||||
@ -418,41 +422,79 @@ OC.Contacts = OC.Contacts || {
|
|||||||
});
|
});
|
||||||
|
|
||||||
$(document).bind('request.contact.export', function(e, data) {
|
$(document).bind('request.contact.export', function(e, data) {
|
||||||
var id = parseInt(data.id);
|
var id = String(data.id);
|
||||||
console.log('contact', data.id, 'request.contact.export');
|
console.log('contact', data.id, 'request.contact.export');
|
||||||
document.location.href = OC.linkTo('contacts', 'export.php') + '?contactid=' + self.currentid;
|
document.location.href = OC.linkTo('contacts', 'export.php') + '?' + $.param(data);
|
||||||
});
|
});
|
||||||
|
|
||||||
$(document).bind('request.contact.close', function(e, data) {
|
$(document).bind('request.contact.close', function(e, data) {
|
||||||
var id = parseInt(data.id);
|
var id = String(data.id);
|
||||||
console.log('contact', data.id, 'request.contact.close');
|
console.log('contact', data.id, 'request.contact.close');
|
||||||
self.closeContact(id);
|
self.closeContact(id);
|
||||||
});
|
});
|
||||||
|
|
||||||
$(document).bind('request.contact.delete', function(e, data) {
|
$(document).bind('request.contact.delete', function(e, data) {
|
||||||
var id = parseInt(data.id);
|
var id = String(data.contactid);
|
||||||
console.log('contact', data.id, 'request.contact.delete');
|
console.log('contact', data, 'request.contact.delete');
|
||||||
self.closeContact(id);
|
self.closeContact(id);
|
||||||
self.contacts.delayedDelete(id);
|
self.contacts.delayedDelete(data);
|
||||||
self.$contactList.removeClass('dim');
|
self.$contactList.removeClass('dim');
|
||||||
self.showActions(['add']);
|
self.showActions(['add']);
|
||||||
});
|
});
|
||||||
|
|
||||||
$(document).bind('request.select.contactphoto.fromlocal', function(e, result) {
|
$(document).bind('request.contact.merge', function(e, data) {
|
||||||
console.log('request.select.contactphoto.fromlocal', result);
|
console.log('contact','request.contact.merge', data);
|
||||||
$('#contactphoto_fileupload').trigger('click');
|
var merger = self.contacts.findById(data.merger);
|
||||||
|
var mergees = [];
|
||||||
|
if(!merger) {
|
||||||
|
$(document).trigger('status.contact.error', {
|
||||||
|
message: t('contacts', 'Merge failed. Cannot find contact: {id}', {id:data.merger})
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$.each(data.mergees, function(idx, id) {
|
||||||
|
var contact = self.contacts.findById(id);
|
||||||
|
if(!contact) {
|
||||||
|
console.warn('cannot find', id, 'by id');
|
||||||
|
}
|
||||||
|
mergees.push(contact);
|
||||||
|
});
|
||||||
|
if(!merger.merge(mergees)) {
|
||||||
|
$(document).trigger('status.contact.error', {
|
||||||
|
message: t('contacts', 'Merge failed.')
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
merger.saveAll(function(response) {
|
||||||
|
if(response.error) {
|
||||||
|
$(document).trigger('status.contact.error', {
|
||||||
|
message: t('contacts', 'Merge failed. Error saving contact.')
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
if(data.deleteOther) {
|
||||||
|
self.contacts.delayedDelete(mergees);
|
||||||
|
}
|
||||||
|
self.openContact(merger.getId());
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
$(document).bind('request.select.contactphoto.fromcloud', function(e, result) {
|
$(document).bind('request.select.contactphoto.fromlocal', function(e, metadata) {
|
||||||
console.log('request.select.contactphoto.fromcloud', result);
|
console.log('request.select.contactphoto.fromlocal', metadata);
|
||||||
|
$('#contactphoto_fileupload').trigger('click', metadata);
|
||||||
|
});
|
||||||
|
|
||||||
|
$(document).bind('request.select.contactphoto.fromcloud', function(e, metadata) {
|
||||||
|
console.log('request.select.contactphoto.fromcloud', metadata);
|
||||||
OC.dialogs.filepicker(t('contacts', 'Select photo'), function(path) {
|
OC.dialogs.filepicker(t('contacts', 'Select photo'), function(path) {
|
||||||
self.cloudPhotoSelected(self.currentid, path);
|
self.cloudPhotoSelected(metadata, path);
|
||||||
}, false, 'image', true);
|
}, false, 'image', true);
|
||||||
});
|
});
|
||||||
|
|
||||||
$(document).bind('request.edit.contactphoto', function(e, result) {
|
$(document).bind('request.edit.contactphoto', function(e, metadata) {
|
||||||
console.log('request.edit.contactphoto', result);
|
console.log('request.edit.contactphoto', metadata);
|
||||||
self.editCurrentPhoto(result.id);
|
self.editCurrentPhoto(metadata);
|
||||||
});
|
});
|
||||||
|
|
||||||
$(document).bind('request.addressbook.activate', function(e, result) {
|
$(document).bind('request.addressbook.activate', function(e, result) {
|
||||||
@ -476,9 +518,8 @@ OC.Contacts = OC.Contacts || {
|
|||||||
}
|
}
|
||||||
$.each(result.contacts, function(idx, contactid) {
|
$.each(result.contacts, function(idx, contactid) {
|
||||||
var contact = self.contacts.findById(contactid);
|
var contact = self.contacts.findById(contactid);
|
||||||
console.log('contactid', contactid, contact);
|
|
||||||
|
|
||||||
self.contacts.findById(contactid).removeFromGroup(result.groupname);
|
contact.removeFromGroup(result.groupname);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -494,10 +535,17 @@ OC.Contacts = OC.Contacts || {
|
|||||||
// Group sorted, save the sort order
|
// Group sorted, save the sort order
|
||||||
$(document).bind('status.groups.sorted', function(e, result) {
|
$(document).bind('status.groups.sorted', function(e, result) {
|
||||||
console.log('status.groups.sorted', result);
|
console.log('status.groups.sorted', result);
|
||||||
$.post(OC.filePath('contacts', 'ajax', 'setpreference.php'), {'key':'groupsort', 'value':result.sortorder}, function(jsondata) {
|
$.when(self.storage.setPreference('groupsort', result.sortorder)).then(function(response) {
|
||||||
if(jsondata.status !== 'success') {
|
if(response.error) {
|
||||||
OC.notify({message: jsondata ? jsondata.data.message : t('contacts', 'Network or server error. Please inform administrator.')});
|
OC.notify({message: response ? response.message : t('contacts', 'Network or server error. Please inform administrator.')});
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
.fail(function(jqxhr, textStatus, error) {
|
||||||
|
var err = textStatus + ', ' + error;
|
||||||
|
console.log( "Request Failed: " + err);
|
||||||
|
$(document).trigger('status.contact.error', {
|
||||||
|
message: t('contacts', 'Failed saving sort order: {error}', {error:err})
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
// Group selected, only show contacts from that group
|
// Group selected, only show contacts from that group
|
||||||
@ -520,10 +568,17 @@ OC.Contacts = OC.Contacts || {
|
|||||||
} else {
|
} else {
|
||||||
self.contacts.showContacts(self.currentgroup);
|
self.contacts.showContacts(self.currentgroup);
|
||||||
}
|
}
|
||||||
$.post(OC.filePath('contacts', 'ajax', 'setpreference.php'), {'key':'lastgroup', 'value':self.currentgroup}, function(jsondata) {
|
$.when(self.storage.setPreference('lastgroup', self.currentgroup)).then(function(response) {
|
||||||
if(!jsondata || jsondata.status !== 'success') {
|
if(response.error) {
|
||||||
OC.notify({message: (jsondata && jsondata.data) ? jsondata.data.message : t('contacts', 'Network or server error. Please inform administrator.')});
|
OC.notify({message: response.message});
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
.fail(function(jqxhr, textStatus, error) {
|
||||||
|
var err = textStatus + ', ' + error;
|
||||||
|
console.log( "Request Failed: " + err);
|
||||||
|
$(document).trigger('status.contact.error', {
|
||||||
|
message: t('contacts', 'Failed saving last group: {error}', {error:err})
|
||||||
|
});
|
||||||
});
|
});
|
||||||
self.$rightContent.scrollTop(0);
|
self.$rightContent.scrollTop(0);
|
||||||
});
|
});
|
||||||
@ -567,6 +622,13 @@ OC.Contacts = OC.Contacts || {
|
|||||||
$('body').bind('click', bodyListener);
|
$('body').bind('click', bodyListener);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
$('#contactphoto_fileupload').on('click', function(event, metadata) {
|
||||||
|
var form = $('#file_upload_form');
|
||||||
|
form.find('input[name="contactid"]').val(metadata.contactid);
|
||||||
|
form.find('input[name="addressbookid"]').val(metadata.addressbookid);
|
||||||
|
form.find('input[name="backend"]').val(metadata.backend);
|
||||||
|
});
|
||||||
|
|
||||||
$('#contactphoto_fileupload').on('change', function() {
|
$('#contactphoto_fileupload').on('change', function() {
|
||||||
self.uploadPhoto(this.files);
|
self.uploadPhoto(this.files);
|
||||||
});
|
});
|
||||||
@ -593,38 +655,35 @@ OC.Contacts = OC.Contacts || {
|
|||||||
self.buildGroupSelect();
|
self.buildGroupSelect();
|
||||||
}
|
}
|
||||||
if(isChecked) {
|
if(isChecked) {
|
||||||
self.showActions(['add', 'download', 'groups', 'delete', 'favorite']);
|
self.showActions(['add', 'download', 'groups', 'delete', 'favorite', 'merge']);
|
||||||
} else {
|
} else {
|
||||||
self.showActions(['add']);
|
self.showActions(['add']);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.$contactList.on('change', 'input:checkbox', function(event) {
|
this.$contactList.on('change', 'input:checkbox', function(event) {
|
||||||
if($(this).is(':checked')) {
|
var selected = self.contacts.getSelectedContacts();
|
||||||
if(self.$groups.find('option').length === 1) {
|
console.log('selected', selected.length);
|
||||||
self.buildGroupSelect();
|
if(selected.length > 0 && self.$groups.find('option').length === 1) {
|
||||||
}
|
self.buildGroupSelect();
|
||||||
self.showActions(['add', 'download', 'groups', 'delete', 'favorite']);
|
}
|
||||||
} else if(self.contacts.getSelectedContacts().length === 0) {
|
if(selected.length === 0) {
|
||||||
self.showActions(['add']);
|
self.showActions(['add']);
|
||||||
|
} else if(selected.length === 1) {
|
||||||
|
self.showActions(['add', 'download', 'groups', 'delete', 'favorite']);
|
||||||
|
} else {
|
||||||
|
self.showActions(['add', 'download', 'groups', 'delete', 'favorite', 'merge']);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Add to/remove from group multiple contacts.
|
// Add to/remove from group multiple contacts.
|
||||||
// FIXME: Refactor this to be usable for favoriting also.
|
|
||||||
this.$groups.on('change', function() {
|
this.$groups.on('change', function() {
|
||||||
var $opt = $(this).find('option:selected');
|
var $opt = $(this).find('option:selected');
|
||||||
var action = $opt.parent().data('action');
|
var action = $opt.parent().data('action');
|
||||||
var ids, groupName, groupId, buildnow = false;
|
var groupName, groupId, buildnow = false;
|
||||||
|
|
||||||
// If a contact is open the action is only applied to that,
|
var contacts = self.contacts.getSelectedContacts();
|
||||||
// otherwise on all selected items.
|
var ids = $.map(contacts, function(c) {return c.getId();});
|
||||||
if(self.currentid) {
|
|
||||||
ids = [self.currentid];
|
|
||||||
buildnow = true;
|
|
||||||
} else {
|
|
||||||
ids = self.contacts.getSelectedContacts();
|
|
||||||
}
|
|
||||||
|
|
||||||
self.setAllChecked(false);
|
self.setAllChecked(false);
|
||||||
self.$toggleAll.prop('checked', false);
|
self.$toggleAll.prop('checked', false);
|
||||||
@ -637,7 +696,7 @@ OC.Contacts = OC.Contacts || {
|
|||||||
console.log('add group...');
|
console.log('add group...');
|
||||||
self.$groups.val(-1);
|
self.$groups.val(-1);
|
||||||
self.addGroup(function(response) {
|
self.addGroup(function(response) {
|
||||||
if(response.status === 'success') {
|
if(!response.error) {
|
||||||
groupId = response.id;
|
groupId = response.id;
|
||||||
groupName = response.name;
|
groupName = response.name;
|
||||||
self.groups.addTo(ids, groupId, function(result) {
|
self.groups.addTo(ids, groupId, function(result) {
|
||||||
@ -676,7 +735,6 @@ OC.Contacts = OC.Contacts || {
|
|||||||
|
|
||||||
groupName = $opt.text(), groupId = $opt.val();
|
groupName = $opt.text(), groupId = $opt.val();
|
||||||
|
|
||||||
console.log('trut', groupName, groupId);
|
|
||||||
if(action === 'add') {
|
if(action === 'add') {
|
||||||
self.groups.addTo(ids, $opt.val(), function(result) {
|
self.groups.addTo(ids, $opt.val(), function(result) {
|
||||||
console.log('after add', result);
|
console.log('after add', result);
|
||||||
@ -751,14 +809,12 @@ OC.Contacts = OC.Contacts || {
|
|||||||
if(event.ctrlKey || event.metaKey) {
|
if(event.ctrlKey || event.metaKey) {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
console.log('select', event);
|
|
||||||
self.dontScroll = true;
|
self.dontScroll = true;
|
||||||
self.contacts.select($(this).data('id'), true);
|
self.contacts.select($(this).data('id'), true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if($(event.target).is('a.mailto')) {
|
if($(event.target).is('a.mailto')) {
|
||||||
var mailto = 'mailto:' + $.trim($(this).find('.email').text());
|
var mailto = 'mailto:' + $.trim($(this).find('.email').text());
|
||||||
console.log('mailto', mailto);
|
|
||||||
try {
|
try {
|
||||||
window.location.href=mailto;
|
window.location.href=mailto;
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
@ -774,6 +830,7 @@ OC.Contacts = OC.Contacts || {
|
|||||||
*
|
*
|
||||||
* @param object $list A jquery object of an unordered list
|
* @param object $list A jquery object of an unordered list
|
||||||
* @param object book An object with the properties 'id', 'name' and 'permissions'.
|
* @param object book An object with the properties 'id', 'name' and 'permissions'.
|
||||||
|
* @param bool add Whether the address book list should be updated.
|
||||||
*/
|
*/
|
||||||
var appendAddressBook = function($list, book, add) {
|
var appendAddressBook = function($list, book, add) {
|
||||||
if(add) {
|
if(add) {
|
||||||
@ -791,34 +848,25 @@ OC.Contacts = OC.Contacts || {
|
|||||||
var id = parseInt($(this).parents('li').first().data('id'));
|
var id = parseInt($(this).parents('li').first().data('id'));
|
||||||
console.log('delete', id);
|
console.log('delete', id);
|
||||||
var $li = $(this).parents('li').first();
|
var $li = $(this).parents('li').first();
|
||||||
$.ajax({
|
$.when(self.storage.deleteAddressBook('local',id))
|
||||||
type:'POST',
|
.then(function(response) {
|
||||||
url:OC.filePath('contacts', 'ajax', 'addressbook/delete.php'),
|
if(!response.error) {
|
||||||
data:{ id: id },
|
self.contacts.unsetAddressbook(id);
|
||||||
success:function(jsondata) {
|
$li.remove();
|
||||||
console.log(jsondata);
|
OC.notify({
|
||||||
if(jsondata.status == 'success') {
|
message:t('contacts','Deleting done. Click here to cancel reloading.'),
|
||||||
self.contacts.unsetAddressbook(id);
|
timeout:5,
|
||||||
$li.remove();
|
timeouthandler:function() {
|
||||||
OC.notify({
|
console.log('reloading');
|
||||||
message:t('contacts','Deleting done. Click here to cancel reloading.'),
|
window.location.href = OC.Router.generate('contacts_index');
|
||||||
timeout:5,
|
},
|
||||||
timeouthandler:function() {
|
clickhandler:function() {
|
||||||
console.log('reloading');
|
console.log('reloading cancelled');
|
||||||
window.location.href = OC.linkTo('contacts', 'index.php');
|
OC.notify({cancel:true});
|
||||||
},
|
}
|
||||||
clickhandler:function() {
|
});
|
||||||
console.log('reloading cancelled');
|
} else {
|
||||||
OC.notify({cancel:true});
|
OC.notify({message:response.message});
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
OC.notify({message:jsondata.data.message});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
error:function(jqXHR, textStatus, errorThrown) {
|
|
||||||
OC.notify({message:textStatus + ': ' + errorThrown});
|
|
||||||
id = false;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -827,7 +875,7 @@ OC.Contacts = OC.Contacts || {
|
|||||||
var book = self.contacts.addressbooks[id];
|
var book = self.contacts.addressbooks[id];
|
||||||
var uri = (book.owner === oc_current_user ) ? book.uri : book.uri + '_shared_by_' + book.owner;
|
var uri = (book.owner === oc_current_user ) ? book.uri : book.uri + '_shared_by_' + book.owner;
|
||||||
var link = OC.linkToRemote('carddav')+'/addressbooks/'+encodeURIComponent(oc_current_user)+'/'+encodeURIComponent(uri);
|
var link = OC.linkToRemote('carddav')+'/addressbooks/'+encodeURIComponent(oc_current_user)+'/'+encodeURIComponent(uri);
|
||||||
var $dropdown = $('<div id="dropdown" class="drop"><input type="text" value="' + link + '" /></div>');
|
var $dropdown = $('<div id="dropdown" class="drop"><input type="text" value="' + link + '" readonly /></div>');
|
||||||
$dropdown.appendTo($(this).parents('li').first());
|
$dropdown.appendTo($(this).parents('li').first());
|
||||||
var $input = $dropdown.find('input');
|
var $input = $dropdown.find('input');
|
||||||
$input.focus().get(0).select();
|
$input.focus().get(0).select();
|
||||||
@ -840,60 +888,51 @@ OC.Contacts = OC.Contacts || {
|
|||||||
$list.append($li);
|
$list.append($li);
|
||||||
};
|
};
|
||||||
|
|
||||||
var $addAddressBookNew = this.$settings.find('.addaddressbook');
|
|
||||||
var $addAddressBookPart = $addAddressBookNew.next('ul');
|
|
||||||
var $addInput = $addAddressBookPart.find('input.addaddressbookinput').focus();
|
|
||||||
$addInput.on('keydown', function(event) {
|
|
||||||
if(event.keyCode === 13) {
|
|
||||||
event.stopPropagation();
|
|
||||||
$addAddressBookPart.find('.addaddressbookok').trigger('click');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
$addAddressBookPart.on('click keydown', 'button', function(event) {
|
|
||||||
if(wrongKey(event)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if($(this).is('.addaddressbookok')) {
|
|
||||||
if($addInput.val().trim() === '') {
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
var name = $addInput.val().trim();
|
|
||||||
$addInput.addClass('loading');
|
|
||||||
$addAddressBookPart.find('button input').prop('disabled', true);
|
|
||||||
console.log('adding', name);
|
|
||||||
self.addAddressbook({
|
|
||||||
name: name,
|
|
||||||
description: ''
|
|
||||||
}, function(response) {
|
|
||||||
if(!response || !response.status) {
|
|
||||||
OC.notify({
|
|
||||||
message:t('contacts', 'Network or server error. Please inform administrator.')
|
|
||||||
});
|
|
||||||
return false;
|
|
||||||
} else if(response.status === 'error') {
|
|
||||||
OC.notify({message: response.message});
|
|
||||||
return false;
|
|
||||||
} else if(response.status === 'success') {
|
|
||||||
var book = response.addressbook;
|
|
||||||
var $list = self.$settings.find('[data-id="addressbooks"]').next('ul');
|
|
||||||
appendAddressBook($list, book, true);
|
|
||||||
}
|
|
||||||
$addInput.removeClass('loading');
|
|
||||||
$addAddressBookPart.find('button input').prop('disabled', false);
|
|
||||||
$addAddressBookPart.hide().prev('button').show();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else if($(this).is('.addaddressbookcancel')) {
|
|
||||||
$addAddressBookPart.hide().prev('button').show();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this.$settings.find('.addaddressbook').on('click keydown', function(event) {
|
this.$settings.find('.addaddressbook').on('click keydown', function(event) {
|
||||||
if(wrongKey(event)) {
|
if(wrongKey(event)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$(this).hide();
|
$(this).hide();
|
||||||
$addAddressBookPart.show();
|
var $addAddressbookPart = $(this).next('ul').show();
|
||||||
|
var $addinput = $addAddressbookPart.find('input.addaddressbookinput').focus();
|
||||||
|
$addAddressbookPart.on('click keydown', 'button', function(event) {
|
||||||
|
if(wrongKey(event)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if($(this).is('.addaddressbookok')) {
|
||||||
|
if($addinput.val().trim() === '') {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
var name = $addinput.val().trim();
|
||||||
|
$addinput.addClass('loading');
|
||||||
|
$addAddressbookPart.find('button input').prop('disabled', true);
|
||||||
|
//console.log('adding', name);
|
||||||
|
$.when(self.storage.addAddressBook('local',
|
||||||
|
{displayname: name, description: ''})).then(function(response) {
|
||||||
|
if(response.error) {
|
||||||
|
OC.notify({message: response.message});
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
var book = response.data;
|
||||||
|
var $list = self.$settings.find('[data-id="addressbooks"]').next('ul');
|
||||||
|
appendAddressBook($list, book, true);
|
||||||
|
}
|
||||||
|
$addinput.removeClass('loading');
|
||||||
|
$addAddressbookPart.find('button input').prop('disabled', false);
|
||||||
|
$addAddressbookPart.hide().prev('button').show();
|
||||||
|
})
|
||||||
|
.fail(function(jqxhr, textStatus, error) {
|
||||||
|
var err = textStatus + ', ' + error;
|
||||||
|
console.log( "Request Failed: " + err);
|
||||||
|
$(document).trigger('status.contact.error', {
|
||||||
|
message: t('contacts', 'Failed adding address book: {error}', {error:err})
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else if($(this).is('.addaddressbookcancel')) {
|
||||||
|
$addAddressbookPart.hide().prev('button').show();
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
this.$settings.find('h2').on('click keydown', function(event) {
|
this.$settings.find('h2').on('click keydown', function(event) {
|
||||||
@ -903,10 +942,9 @@ OC.Contacts = OC.Contacts || {
|
|||||||
if($(this).next('ul').is(':visible')) {
|
if($(this).next('ul').is(':visible')) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
console.log('settings');
|
//console.log('settings');
|
||||||
var $list = $(this).next('ul');
|
var $list = $(this).next('ul');
|
||||||
if($(this).data('id') === 'addressbooks') {
|
if($(this).data('id') === 'addressbooks') {
|
||||||
console.log('addressbooks');
|
|
||||||
|
|
||||||
if(!self.$addressbookTmpl) {
|
if(!self.$addressbookTmpl) {
|
||||||
self.$addressbookTmpl = $('#addressbookTemplate');
|
self.$addressbookTmpl = $('#addressbookTemplate');
|
||||||
@ -922,27 +960,26 @@ OC.Contacts = OC.Contacts || {
|
|||||||
$list.find('a.action.share').css('display', 'none');
|
$list.find('a.action.share').css('display', 'none');
|
||||||
}
|
}
|
||||||
} else if($(this).data('id') === 'import') {
|
} else if($(this).data('id') === 'import') {
|
||||||
console.log('import');
|
|
||||||
$('.import-upload').show();
|
$('.import-upload').show();
|
||||||
$('.import-select').hide();
|
$('.import-select').hide();
|
||||||
|
|
||||||
var addAddressbookCallback = function(select, name) {
|
var addAddressbookCallback = function(select, name) {
|
||||||
var id = false;
|
var id = false;
|
||||||
self.addAddressbook({
|
$.when(this.storage.addAddressBook('local',
|
||||||
name: name,
|
{name: name, description: ''})).then(function(response) {
|
||||||
description: ''
|
if(response.error) {
|
||||||
}, function(response) {
|
|
||||||
if(!response || !response.status) {
|
|
||||||
OC.notify({
|
|
||||||
message:t('contacts', 'Network or server error. Please inform administrator.')
|
|
||||||
});
|
|
||||||
return false;
|
|
||||||
} else if(response.status === 'error') {
|
|
||||||
OC.notify({message: response.message});
|
OC.notify({message: response.message});
|
||||||
return false;
|
return false;
|
||||||
} else if(response.status === 'success') {
|
} else {
|
||||||
id = response.addressbook.id;
|
id = response.data.id;
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
.fail(function(jqxhr, textStatus, error) {
|
||||||
|
var err = textStatus + ', ' + error;
|
||||||
|
console.log( "Request Failed: " + err);
|
||||||
|
$(document).trigger('status.contact.error', {
|
||||||
|
message: t('contacts', 'Failed adding addres books: {error}', {error:err})
|
||||||
|
});
|
||||||
});
|
});
|
||||||
return id;
|
return id;
|
||||||
};
|
};
|
||||||
@ -970,6 +1007,7 @@ OC.Contacts = OC.Contacts || {
|
|||||||
self.currentid = 'new';
|
self.currentid = 'new';
|
||||||
// Properties that the contact doesn't know
|
// Properties that the contact doesn't know
|
||||||
console.log('addContact, groupid', self.currentgroup);
|
console.log('addContact, groupid', self.currentgroup);
|
||||||
|
self.$contactList.addClass('dim');
|
||||||
var groupprops = {
|
var groupprops = {
|
||||||
favorite: false,
|
favorite: false,
|
||||||
groups: self.groups.categories,
|
groups: self.groups.categories,
|
||||||
@ -1009,8 +1047,9 @@ OC.Contacts = OC.Contacts || {
|
|||||||
}
|
}
|
||||||
console.log('delete');
|
console.log('delete');
|
||||||
if(self.currentid) {
|
if(self.currentid) {
|
||||||
console.assert(utils.isUInt(self.currentid), 'self.currentid is not an integer');
|
console.assert(typeof self.currentid === 'string', 'self.currentid is not a string');
|
||||||
self.contacts.delayedDelete(self.currentid);
|
contactInfo = self.contacts[self.currentid].metaData();
|
||||||
|
self.contacts.delayedDelete(contactInfo);
|
||||||
} else {
|
} else {
|
||||||
self.contacts.delayedDelete(self.contacts.getSelectedContacts());
|
self.contacts.delayedDelete(self.contacts.getSelectedContacts());
|
||||||
}
|
}
|
||||||
@ -1022,31 +1061,48 @@ OC.Contacts = OC.Contacts || {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
console.log('download');
|
console.log('download');
|
||||||
|
var contacts = self.contacts.getSelectedContacts();
|
||||||
|
var ids = $.map(contacts, function(c) {return c.getId();});
|
||||||
document.location.href = OC.linkTo('contacts', 'export.php')
|
document.location.href = OC.linkTo('contacts', 'export.php')
|
||||||
+ '?selectedids=' + self.contacts.getSelectedContacts().join(',');
|
+ '?selectedids=' + ids.join(',');
|
||||||
|
});
|
||||||
|
|
||||||
|
this.$header.on('click keydown', '.merge', function(event) {
|
||||||
|
if(wrongKey(event)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
console.log('merge');
|
||||||
|
self.mergeSelectedContacts();
|
||||||
});
|
});
|
||||||
|
|
||||||
this.$header.on('click keydown', '.favorite', function(event) {
|
this.$header.on('click keydown', '.favorite', function(event) {
|
||||||
if(wrongKey(event)) {
|
if(wrongKey(event)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(!utils.isUInt(self.currentid)) {
|
|
||||||
return;
|
var contacts = self.contacts.getSelectedContacts();
|
||||||
|
|
||||||
|
self.setAllChecked(false);
|
||||||
|
self.$toggleAll.prop('checked', false);
|
||||||
|
if(!self.currentid) {
|
||||||
|
self.showActions(['add']);
|
||||||
}
|
}
|
||||||
// FIXME: This should only apply for contacts list.
|
|
||||||
var state = self.groups.isFavorite(self.currentid);
|
$.each(contacts, function(idx, contact) {
|
||||||
console.log('Favorite?', this, state);
|
if(!self.groups.isFavorite(contact.getId())) {
|
||||||
self.groups.setAsFavorite(self.currentid, !state, function(jsondata) {
|
self.groups.setAsFavorite(contact.getId(), true, function(result) {
|
||||||
if(jsondata.status === 'success') {
|
if(result.status !== 'success') {
|
||||||
if(state) {
|
OC.notify({message:
|
||||||
self.$header.find('.favorite').switchClass('active', '');
|
t('contacts',
|
||||||
} else {
|
'Error setting {name} as favorite.',
|
||||||
self.$header.find('.favorite').switchClass('', 'active');
|
{name:contact.getDisplayName()})
|
||||||
}
|
});
|
||||||
} else {
|
}
|
||||||
OC.notify({message:t('contacts', jsondata.data.message)});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
self.showActions(['add']);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.$contactList.on('mouseenter', 'td.email', function(event) {
|
this.$contactList.on('mouseenter', 'td.email', function(event) {
|
||||||
@ -1060,14 +1116,28 @@ OC.Contacts = OC.Contacts || {
|
|||||||
|
|
||||||
// Import using jquery.fileupload
|
// Import using jquery.fileupload
|
||||||
$(function() {
|
$(function() {
|
||||||
var uploadingFiles = {}, numfiles = 0, uploadedfiles = 0, retries = 0;
|
var uploadingFiles = {},
|
||||||
|
numfiles = 0,
|
||||||
|
uploadedfiles = 0,
|
||||||
|
importedfiles = 0,
|
||||||
|
retries = 0,
|
||||||
|
succeded = 0
|
||||||
|
failed = 0;
|
||||||
var aid, importError = false;
|
var aid, importError = false;
|
||||||
var $progressbar = $('#import-progress');
|
var $progressbar = $('#import-progress');
|
||||||
var $status = $('#import-status-text');
|
var $status = $('#import-status-text');
|
||||||
|
|
||||||
|
self.$importFileInput.on('fileuploaddone', function(e, data) {
|
||||||
|
console.log('fileuploaddone', data);
|
||||||
|
var file = data.result.file;
|
||||||
|
console.log('fileuploaddone, file', file);
|
||||||
|
uploadedfiles += 1;
|
||||||
|
});
|
||||||
|
|
||||||
var waitForImport = function() {
|
var waitForImport = function() {
|
||||||
if(numfiles == 0 && uploadedfiles == 0) {
|
console.log('waitForImport', numfiles, uploadedfiles, importedfiles);
|
||||||
$progressbar.progressbar('value',100);
|
if(uploadedfiles === importedfiles && importedfiles === numfiles) {
|
||||||
|
$progressbar.progressbar('value', 100);
|
||||||
if(!importError) {
|
if(!importError) {
|
||||||
OC.notify({
|
OC.notify({
|
||||||
message:t('contacts','Import done. Click here to cancel reloading.'),
|
message:t('contacts','Import done. Click here to cancel reloading.'),
|
||||||
@ -1082,7 +1152,9 @@ OC.Contacts = OC.Contacts || {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
retries = aid = 0;
|
$status.text(t('contacts', '{success} imported, {failed} failed.',
|
||||||
|
{success:succeded, failed:failed})).fadeIn();
|
||||||
|
numfiles = uploadedfiles = importedfiles = retries = aid = failed = succeded = 0;
|
||||||
$progressbar.fadeOut();
|
$progressbar.fadeOut();
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
$status.fadeOut('slow');
|
$status.fadeOut('slow');
|
||||||
@ -1110,11 +1182,11 @@ OC.Contacts = OC.Contacts || {
|
|||||||
|
|
||||||
var importFiles = function(aid, uploadingFiles) {
|
var importFiles = function(aid, uploadingFiles) {
|
||||||
console.log('importFiles', aid, uploadingFiles);
|
console.log('importFiles', aid, uploadingFiles);
|
||||||
if(numfiles != uploadedfiles) {
|
if(numfiles !== uploadedfiles) {
|
||||||
OC.notify({message:t('contacts', 'Not all files uploaded. Retrying...')});
|
OC.notify({message:t('contacts', 'Not all files uploaded. Retrying...')});
|
||||||
retries += 1;
|
retries += 1;
|
||||||
if(retries > 3) {
|
if(retries > 3) {
|
||||||
numfiles = uploadedfiles = retries = aid = 0;
|
numfiles = uploadedfiles = importedfiles = retries = failed = succeded = aid = 0;
|
||||||
uploadingFiles = {};
|
uploadingFiles = {};
|
||||||
$progressbar.fadeOut();
|
$progressbar.fadeOut();
|
||||||
OC.dialogs.alert(t('contacts', 'Something went wrong with the upload, please retry.'), t('contacts', 'Error'));
|
OC.dialogs.alert(t('contacts', 'Something went wrong with the upload, please retry.'), t('contacts', 'Error'));
|
||||||
@ -1130,14 +1202,19 @@ OC.Contacts = OC.Contacts || {
|
|||||||
$status.text(t('contacts', 'Importing from {filename}...', {filename:fileName})).fadeIn();
|
$status.text(t('contacts', 'Importing from {filename}...', {filename:fileName})).fadeIn();
|
||||||
doImport(fileName, aid, function(response) {
|
doImport(fileName, aid, function(response) {
|
||||||
if(response.status === 'success') {
|
if(response.status === 'success') {
|
||||||
$status.text(t('contacts', '{success} imported, {failed} failed.',
|
importedfiles += 1;
|
||||||
{success:response.data.imported, failed:response.data.failed})).fadeIn();
|
succeded += response.data.imported;
|
||||||
|
failed += response.data.failed;
|
||||||
|
OC.notify({
|
||||||
|
message:t('contacts', '{success} imported, {failed} failed from {file}',
|
||||||
|
{success:response.data.imported, failed:response.data.failed, file:response.data.failed}
|
||||||
|
)
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
$('.import-upload').show();
|
$('.import-upload').show();
|
||||||
$('.import-select').hide();
|
$('.import-select').hide();
|
||||||
}
|
}
|
||||||
delete uploadingFiles[fileName];
|
delete uploadingFiles[fileName];
|
||||||
numfiles -= 1; uploadedfiles -= 1;
|
|
||||||
$progressbar.progressbar('value',50+(50/(todo-uploadedfiles)));
|
$progressbar.progressbar('value',50+(50/(todo-uploadedfiles)));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -1155,80 +1232,34 @@ OC.Contacts = OC.Contacts || {
|
|||||||
importFiles(aid, uploadingFiles);
|
importFiles(aid, uploadingFiles);
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#import_fileupload').fileupload({
|
self.$importFileInput.fileupload({
|
||||||
acceptFileTypes: /^text\/(directory|vcard|x-vcard)$/i,
|
acceptFileTypes: /^text\/(directory|vcard|x-vcard)$/i,
|
||||||
add: function(e, data) {
|
add: function(e, data) {
|
||||||
var files = data.files;
|
var file = data.files[0];
|
||||||
|
console.log('add', file.name);
|
||||||
var totalSize=0;
|
var totalSize=0;
|
||||||
if(files) {
|
if(file) {
|
||||||
numfiles += files.length; uploadedfiles = 0;
|
numfiles += 1;
|
||||||
for(var i=0;i<files.length;i++) {
|
if(file.size === 0 || file.type== '') {
|
||||||
if(files[i].size ==0 && files[i].type== '') {
|
OC.dialogs.alert(t('contacts', 'Unable to upload your file as it is a directory or has 0 bytes'), t('contacts', 'Upload Error'));
|
||||||
OC.dialogs.alert(t('files', 'Unable to upload your file as it is a directory or has 0 bytes'), t('files', 'Upload Error'));
|
return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
totalSize+=files[i].size;
|
|
||||||
}
|
}
|
||||||
|
totalSize+=file.size;
|
||||||
}
|
}
|
||||||
if(totalSize>$('#max_upload').val()) {
|
if(totalSize>$('#max_upload').val()) {
|
||||||
OC.dialogs.alert(t('contacts','The file you are trying to upload exceed the maximum size for file uploads on this server.'), t('contacts','Upload too large'));
|
OC.dialogs.alert(t('contacts','The file you are trying to upload exceed the maximum size for file uploads on this server.'), t('contacts','Upload too large'));
|
||||||
numfiles = uploadedfiles = retries = aid = 0;
|
numfiles = uploadedfiles = importedfiles = retries = failed = succeded = aid = 0;
|
||||||
uploadingFiles = {};
|
uploadingFiles = {};
|
||||||
return;
|
return;
|
||||||
} else {
|
|
||||||
if($.support.xhrFileUpload) {
|
|
||||||
$.each(files, function(i, file) {
|
|
||||||
var fileName = file.name;
|
|
||||||
console.log('file.name', file.name);
|
|
||||||
var jqXHR = $('#import_fileupload').fileupload('send',
|
|
||||||
{
|
|
||||||
files: file,
|
|
||||||
formData: function(form) {
|
|
||||||
var formArray = form.serializeArray();
|
|
||||||
formArray['aid'] = aid;
|
|
||||||
return formArray;
|
|
||||||
}})
|
|
||||||
.success(function(response, textStatus, jqXHR) {
|
|
||||||
if(response.status == 'success') {
|
|
||||||
// import the file
|
|
||||||
uploadedfiles += 1;
|
|
||||||
} else {
|
|
||||||
OC.notify({message:response.data.message});
|
|
||||||
$('.import-upload').show();
|
|
||||||
$('.import-select').hide();
|
|
||||||
$('#import-progress').hide();
|
|
||||||
$('#import-status-text').hide();
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
})
|
|
||||||
.error(function(jqXHR, textStatus, errorThrown) {
|
|
||||||
console.log(textStatus);
|
|
||||||
OC.notify({message:errorThrown + ': ' + textStatus});
|
|
||||||
});
|
|
||||||
uploadingFiles[fileName] = jqXHR;
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
data.submit().success(function(data, status) {
|
|
||||||
response = jQuery.parseJSON(data[0].body.innerText);
|
|
||||||
if(response[0] != undefined && response[0].status == 'success') {
|
|
||||||
var file=response[0];
|
|
||||||
delete uploadingFiles[file.name];
|
|
||||||
$('tr').filterAttr('data-file',file.name).data('mime',file.mime);
|
|
||||||
var size = $('tr').filterAttr('data-file',file.name).find('td.filesize').text();
|
|
||||||
if(size==t('files','Pending')){
|
|
||||||
$('tr').filterAttr('data-file',file.name).find('td.filesize').text(file.size);
|
|
||||||
}
|
|
||||||
FileList.loadingDone(file.name);
|
|
||||||
} else {
|
|
||||||
OC.notify({message:response.data.message});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
var jqXHR = data.submit();
|
||||||
|
uploadingFiles[file.name] = jqXHR;
|
||||||
|
|
||||||
},
|
},
|
||||||
fail: function(e, data) {
|
fail: function(e, data) {
|
||||||
console.log('fail');
|
console.log('fail');
|
||||||
OC.notify({message:data.errorThrown + ': ' + data.textStatus});
|
OC.notify({message:data.errorThrown + ': ' + data.textStatus});
|
||||||
|
numfiles = uploadedfiles = importedfiles = retries = failed = succeded = aid = 0;
|
||||||
$('.import-upload').show();
|
$('.import-upload').show();
|
||||||
$('.import-select').hide();
|
$('.import-select').hide();
|
||||||
// TODO: Remove file from upload queue.
|
// TODO: Remove file from upload queue.
|
||||||
@ -1240,19 +1271,12 @@ OC.Contacts = OC.Contacts || {
|
|||||||
start: function(e, data) {
|
start: function(e, data) {
|
||||||
$progressbar.progressbar({value:0});
|
$progressbar.progressbar({value:0});
|
||||||
$progressbar.fadeIn();
|
$progressbar.fadeIn();
|
||||||
if(data.dataType != 'iframe ') {
|
|
||||||
$('#upload input.stop').show();
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
stop: function(e, data) {
|
stop: function(e, data) {
|
||||||
console.log('stop, data', data);
|
console.log('stop, data', data);
|
||||||
// stop only gets fired once so we collect uploaded items here.
|
// stop only gets fired once so we collect uploaded items here.
|
||||||
$('.import-upload').hide();
|
$('.import-upload').hide();
|
||||||
$('.import-select').show();
|
$('.import-select').show();
|
||||||
|
|
||||||
if(data.dataType != 'iframe ') {
|
|
||||||
$('#upload input.stop').hide();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -1261,8 +1285,8 @@ OC.Contacts = OC.Contacts || {
|
|||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
});
|
});
|
||||||
|
|
||||||
$(document).on('keypress', function(event) {
|
$(document).on('keyup', function(event) {
|
||||||
if(!$(event.target).is('body')) {
|
if(!$(event.target).is('body') || event.isPropagationStopped()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var keyCode = Math.max(event.keyCode, event.which);
|
var keyCode = Math.max(event.keyCode, event.which);
|
||||||
@ -1350,41 +1374,123 @@ OC.Contacts = OC.Contacts || {
|
|||||||
$('.tooltipped.downwards.onfocus').tipsy({trigger: 'focus', gravity: 'n'});
|
$('.tooltipped.downwards.onfocus').tipsy({trigger: 'focus', gravity: 'n'});
|
||||||
$('.tooltipped.rightwards.onfocus').tipsy({trigger: 'focus', gravity: 'w'});
|
$('.tooltipped.rightwards.onfocus').tipsy({trigger: 'focus', gravity: 'w'});
|
||||||
},
|
},
|
||||||
|
mergeSelectedContacts: function() {
|
||||||
|
var contacts = this.contacts.getSelectedContacts();
|
||||||
|
var self = this;
|
||||||
|
this.$rightContent.append('<div id="merge_contacts_dialog"></div>');
|
||||||
|
if(!this.$mergeContactsTmpl) {
|
||||||
|
this.$mergeContactsTmpl = $('#mergeContactsTemplate');
|
||||||
|
}
|
||||||
|
var $dlg = this.$mergeContactsTmpl.octemplate();
|
||||||
|
var $liTmpl = $dlg.find('li').detach();
|
||||||
|
var $mergeList = $dlg.find('.mergelist');
|
||||||
|
$.each(contacts, function(idx, contact) {
|
||||||
|
var $li = $liTmpl
|
||||||
|
.octemplate({idx: idx, id: contact.getId(), displayname: contact.getDisplayName()});
|
||||||
|
if(!contact.data.thumbnail) {
|
||||||
|
$li.addClass('thumbnail');
|
||||||
|
} else {
|
||||||
|
$li.css('background-image', 'url(data:image/png;base64,' + contact.data.thumbnail + ')');
|
||||||
|
}
|
||||||
|
if(idx === 0) {
|
||||||
|
$li.find('input:radio').prop('checked', true);
|
||||||
|
}
|
||||||
|
$mergeList.append($li);
|
||||||
|
});
|
||||||
|
this.$contactList.addClass('dim');
|
||||||
|
$('#merge_contacts_dialog').html($dlg).ocdialog({
|
||||||
|
closeOnEscape: true,
|
||||||
|
title: t('contacts', 'Merge contacts'),
|
||||||
|
height: 'auto', width: 'auto',
|
||||||
|
buttons: [
|
||||||
|
{
|
||||||
|
text: t('contacts', 'Merge contacts'),
|
||||||
|
click:function() {
|
||||||
|
// Do the merging, use $(this) to get dialog
|
||||||
|
var contactid = $(this).find('input:radio:checked').val();
|
||||||
|
var others = [];
|
||||||
|
var deleteOther = $(this).find('#delete_other').prop('checked');
|
||||||
|
console.log('Selected contact', contactid, 'Delete others', deleteOther);
|
||||||
|
$.each($(this).find('input:radio:not(:checked)'), function(idx, item) {
|
||||||
|
others.push($(item).val());
|
||||||
|
});
|
||||||
|
console.log('others', others);
|
||||||
|
$(document).trigger('request.contact.merge', {
|
||||||
|
merger: contactid,
|
||||||
|
mergees: others,
|
||||||
|
deleteOther: deleteOther
|
||||||
|
});
|
||||||
|
|
||||||
|
$(this).ocdialog('close');
|
||||||
|
},
|
||||||
|
defaultButton: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: t('contacts', 'Cancel'),
|
||||||
|
click:function(dlg) {
|
||||||
|
$(this).ocdialog('close');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
close: function(event, ui) {
|
||||||
|
$(this).ocdialog('destroy').remove();
|
||||||
|
$('#add_group_dialog').remove();
|
||||||
|
self.$contactList.removeClass('dim');
|
||||||
|
},
|
||||||
|
open: function(event, ui) {
|
||||||
|
$dlg.find('input').focus();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
addGroup: function(cb) {
|
addGroup: function(cb) {
|
||||||
var self = this;
|
var self = this;
|
||||||
$('body').append('<div id="add_group_dialog"></div>');
|
this.$rightContent.append('<div id="add_group_dialog"></div>');
|
||||||
if(!this.$addGroupTmpl) {
|
if(!this.$addGroupTmpl) {
|
||||||
this.$addGroupTmpl = $('#addGroupTemplate');
|
this.$addGroupTmpl = $('#addGroupTemplate');
|
||||||
}
|
}
|
||||||
|
this.$contactList.addClass('dim');
|
||||||
var $dlg = this.$addGroupTmpl.octemplate();
|
var $dlg = this.$addGroupTmpl.octemplate();
|
||||||
$('#add_group_dialog').html($dlg).dialog({
|
$('#add_group_dialog').html($dlg).ocdialog({
|
||||||
modal: true,
|
modal: true,
|
||||||
closeOnEscape: true,
|
closeOnEscape: true,
|
||||||
title: t('contacts', 'Add group'),
|
title: t('contacts', 'Add group'),
|
||||||
height: 'auto', width: 'auto',
|
height: 'auto', width: 'auto',
|
||||||
buttons: {
|
buttons: [
|
||||||
'Ok':function() {
|
{
|
||||||
self.groups.addGroup(
|
text: t('contacts', 'OK'),
|
||||||
{name:$dlg.find('input:text').val()},
|
click:function() {
|
||||||
function(response) {
|
var name = $(this).find('input').val();
|
||||||
if(typeof cb === 'function') {
|
if(name.trim() === '') {
|
||||||
cb(response);
|
return false;
|
||||||
} else {
|
}
|
||||||
if(response.status !== 'success') {
|
self.groups.addGroup(
|
||||||
OC.notify({message: response.message});
|
{name:$dlg.find('input:text').val()},
|
||||||
|
function(response) {
|
||||||
|
if(typeof cb === 'function') {
|
||||||
|
cb(response);
|
||||||
|
} else {
|
||||||
|
if(response.error) {
|
||||||
|
OC.notify({message: response.message});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
});
|
$(this).ocdialog('close');
|
||||||
$(this).dialog('close');
|
},
|
||||||
|
defaultButton: true
|
||||||
},
|
},
|
||||||
'Cancel':function() {
|
{
|
||||||
$(this).dialog('close');
|
text: t('contacts', 'Cancel'),
|
||||||
return false;
|
click:function(dlg) {
|
||||||
|
$(this).ocdialog('close');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
],
|
||||||
close: function(event, ui) {
|
close: function(event, ui) {
|
||||||
$(this).dialog('destroy').remove();
|
$(this).ocdialog('destroy').remove();
|
||||||
$('#add_group_dialog').remove();
|
$('#add_group_dialog').remove();
|
||||||
|
self.$contactList.removeClass('dim');
|
||||||
},
|
},
|
||||||
open: function(event, ui) {
|
open: function(event, ui) {
|
||||||
$dlg.find('input').focus();
|
$dlg.find('input').focus();
|
||||||
@ -1401,6 +1507,7 @@ OC.Contacts = OC.Contacts || {
|
|||||||
this.$rightContent.scrollTop(this.contacts.contactPos(id)-30);
|
this.$rightContent.scrollTop(this.contacts.contactPos(id)-30);
|
||||||
},
|
},
|
||||||
closeContact: function(id) {
|
closeContact: function(id) {
|
||||||
|
$(window).unbind('hashchange', this.hashChange);
|
||||||
if(typeof this.currentid === 'number') {
|
if(typeof this.currentid === 'number') {
|
||||||
var contact = this.contacts.findById(id);
|
var contact = this.contacts.findById(id);
|
||||||
if(contact && contact.close()) {
|
if(contact && contact.close()) {
|
||||||
@ -1419,12 +1526,16 @@ OC.Contacts = OC.Contacts || {
|
|||||||
$(document).trigger('status.nomorecontacts');
|
$(document).trigger('status.nomorecontacts');
|
||||||
}
|
}
|
||||||
//$('body').unbind('click', this.bodyListener);
|
//$('body').unbind('click', this.bodyListener);
|
||||||
|
window.location.hash = '';
|
||||||
|
$(window).bind('hashchange', this.hashChange);
|
||||||
},
|
},
|
||||||
openContact: function(id) {
|
openContact: function(id) {
|
||||||
|
this.hideActions();
|
||||||
console.log('Contacts.openContact', id);
|
console.log('Contacts.openContact', id);
|
||||||
if(this.currentid) {
|
if(this.currentid) {
|
||||||
this.closeContact(this.currentid);
|
this.closeContact(this.currentid);
|
||||||
}
|
}
|
||||||
|
$(window).unbind('hashchange', this.hashChange);
|
||||||
this.currentid = parseInt(id);
|
this.currentid = parseInt(id);
|
||||||
console.log('Contacts.openContact, Favorite', this.currentid, this.groups.isFavorite(this.currentid), this.groups);
|
console.log('Contacts.openContact, Favorite', this.currentid, this.groups.isFavorite(this.currentid), this.groups);
|
||||||
this.setAllChecked(false);
|
this.setAllChecked(false);
|
||||||
@ -1458,10 +1569,12 @@ OC.Contacts = OC.Contacts || {
|
|||||||
if($contactelem.find($(e.target)).length === 0) {
|
if($contactelem.find($(e.target)).length === 0) {
|
||||||
self.closeContact(self.currentid);
|
self.closeContact(self.currentid);
|
||||||
}
|
}
|
||||||
};
|
};*/
|
||||||
|
window.location.hash = this.currentid.toString();
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
$('body').bind('click', self.bodyListener);
|
//$('body').bind('click', self.bodyListener);
|
||||||
}, 500);*/
|
$(window).bind('hashchange', this.hashChange);
|
||||||
|
}, 500);
|
||||||
},
|
},
|
||||||
update: function() {
|
update: function() {
|
||||||
console.log('update');
|
console.log('update');
|
||||||
@ -1475,7 +1588,6 @@ OC.Contacts = OC.Contacts || {
|
|||||||
var file = filelist[0];
|
var file = filelist[0];
|
||||||
var target = $('#file_upload_target');
|
var target = $('#file_upload_target');
|
||||||
var form = $('#file_upload_form');
|
var form = $('#file_upload_form');
|
||||||
form.find('input[name="id"]').val(this.currentid);
|
|
||||||
var totalSize=0;
|
var totalSize=0;
|
||||||
if(file.size > $('#max_upload').val()){
|
if(file.size > $('#max_upload').val()){
|
||||||
OC.notify({
|
OC.notify({
|
||||||
@ -1489,7 +1601,10 @@ OC.Contacts = OC.Contacts || {
|
|||||||
var response=jQuery.parseJSON(target.contents().text());
|
var response=jQuery.parseJSON(target.contents().text());
|
||||||
if(response != undefined && response.status == 'success') {
|
if(response != undefined && response.status == 'success') {
|
||||||
console.log('response', response);
|
console.log('response', response);
|
||||||
self.editPhoto(self.currentid, response.data.tmp);
|
self.editPhoto(
|
||||||
|
response.metadata,
|
||||||
|
response.data.tmp
|
||||||
|
);
|
||||||
//alert('File: ' + file.tmp + ' ' + file.name + ' ' + file.mime);
|
//alert('File: ' + file.tmp + ' ' + file.name + ' ' + file.mime);
|
||||||
} else {
|
} else {
|
||||||
OC.notify({message:response.data.message});
|
OC.notify({message:response.data.message});
|
||||||
@ -1498,28 +1613,28 @@ OC.Contacts = OC.Contacts || {
|
|||||||
form.submit();
|
form.submit();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
cloudPhotoSelected:function(id, path) {
|
cloudPhotoSelected:function(metadata, path) {
|
||||||
var self = this;
|
var self = this;
|
||||||
console.log('cloudPhotoSelected, id', id);
|
console.log('cloudPhotoSelected', metadata);
|
||||||
$.getJSON(OC.filePath('contacts', 'ajax', 'oc_photo.php'),
|
$.getJSON(OC.filePath('contacts', 'ajax', 'oc_photo.php'),
|
||||||
{path: path, id: id},function(jsondata) {
|
{path: path, contact: metadata},function(jsondata) {
|
||||||
if(jsondata.status == 'success') {
|
if(jsondata.status == 'success') {
|
||||||
//alert(jsondata.data.page);
|
//alert(jsondata.data.page);
|
||||||
self.editPhoto(jsondata.data.id, jsondata.data.tmp);
|
self.editPhoto(metadata, jsondata.data.tmp);
|
||||||
$('#edit_photo_dialog_img').html(jsondata.data.page);
|
//$('#edit_photo_dialog_img').html(jsondata.data.page);
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
OC.notify({message: jsondata.data.message});
|
OC.notify({message: jsondata.data.message});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
editCurrentPhoto:function(id) {
|
editCurrentPhoto:function(metadata) {
|
||||||
var self = this;
|
var self = this;
|
||||||
$.getJSON(OC.filePath('contacts', 'ajax', 'currentphoto.php'),
|
$.getJSON(OC.filePath('contacts', 'ajax', 'currentphoto.php'), metadata,
|
||||||
{id: id}, function(jsondata) {
|
function(jsondata) {
|
||||||
if(jsondata.status == 'success') {
|
if(jsondata.status == 'success') {
|
||||||
//alert(jsondata.data.page);
|
//alert(jsondata.data.page);
|
||||||
self.editPhoto(jsondata.data.id, jsondata.data.tmp);
|
self.editPhoto(metadata, jsondata.data.tmp);
|
||||||
$('#edit_photo_dialog_img').html(jsondata.data.page);
|
$('#edit_photo_dialog_img').html(jsondata.data.page);
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
@ -1527,8 +1642,8 @@ OC.Contacts = OC.Contacts || {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
editPhoto:function(id, tmpkey) {
|
editPhoto:function(metadata, tmpkey) {
|
||||||
console.log('editPhoto', id, tmpkey);
|
console.log('editPhoto', metadata, tmpkey);
|
||||||
$('.tipsy').remove();
|
$('.tipsy').remove();
|
||||||
// Simple event handler, called from onChange and onSelect
|
// Simple event handler, called from onChange and onSelect
|
||||||
// event handlers, as per the Jcrop invocation above
|
// event handlers, as per the Jcrop invocation above
|
||||||
@ -1550,7 +1665,13 @@ OC.Contacts = OC.Contacts || {
|
|||||||
this.$cropBoxTmpl = $('#cropBoxTemplate');
|
this.$cropBoxTmpl = $('#cropBoxTemplate');
|
||||||
}
|
}
|
||||||
$('body').append('<div id="edit_photo_dialog"></div>');
|
$('body').append('<div id="edit_photo_dialog"></div>');
|
||||||
var $dlg = this.$cropBoxTmpl.octemplate({id: id, tmpkey: tmpkey});
|
var $dlg = this.$cropBoxTmpl.octemplate(
|
||||||
|
{
|
||||||
|
backend: metadata.backend,
|
||||||
|
addressbookid: metadata.addressbookid,
|
||||||
|
contactid: metadata.contactid,
|
||||||
|
tmpkey: tmpkey
|
||||||
|
});
|
||||||
|
|
||||||
var cropphoto = new Image();
|
var cropphoto = new Image();
|
||||||
$(cropphoto).load(function () {
|
$(cropphoto).load(function () {
|
||||||
@ -1590,208 +1711,38 @@ OC.Contacts = OC.Contacts || {
|
|||||||
});
|
});
|
||||||
}).error(function () {
|
}).error(function () {
|
||||||
OC.notify({message:t('contacts','Error loading profile picture.')});
|
OC.notify({message:t('contacts','Error loading profile picture.')});
|
||||||
}).attr('src', OC.linkTo('contacts', 'tmpphoto.php')+'?tmpkey='+tmpkey);
|
}).attr('src', OC.linkTo('contacts', 'tmpphoto.php')+'?tmpkey='+tmpkey+'&refresh='+Math.random());
|
||||||
},
|
},
|
||||||
savePhoto:function($dlg) {
|
savePhoto:function($dlg) {
|
||||||
var form = $dlg.find('#cropform');
|
var form = $dlg.find('#cropform');
|
||||||
q = form.serialize();
|
q = form.serialize();
|
||||||
console.log('savePhoto', q);
|
console.log('savePhoto', q);
|
||||||
$.post(OC.filePath('contacts', 'ajax', 'savecrop.php'), q, function(response) {
|
$.post(OC.filePath('contacts', 'ajax', 'savecrop.php'), q, function(response) {
|
||||||
var jsondata = $.parseJSON(response);
|
//var jsondata = $.parseJSON(response);
|
||||||
console.log('savePhoto, jsondata', typeof jsondata);
|
console.log('savePhoto, response', typeof response);
|
||||||
if(jsondata && jsondata.status === 'success') {
|
if(response && response.status === 'success') {
|
||||||
// load cropped photo.
|
// load cropped photo.
|
||||||
$(document).trigger('status.contact.photoupdated', {
|
$(document).trigger('status.contact.photoupdated', {
|
||||||
id: jsondata.data.id
|
id: response.data.id,
|
||||||
|
thumbnail: response.data.thumbnail
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
if(!jsondata) {
|
if(!response) {
|
||||||
OC.notify({message:t('contacts', 'Network or server error. Please inform administrator.')});
|
OC.notify({message:t('contacts', 'Network or server error. Please inform administrator.')});
|
||||||
} else {
|
} else {
|
||||||
OC.notify({message: jsondata.data.message});
|
OC.notify({message: response.data.message});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
addAddressbook:function(data, cb) {
|
|
||||||
$.ajax({
|
|
||||||
type:'POST',
|
|
||||||
async:false,
|
|
||||||
url:OC.filePath('contacts', 'ajax', 'addressbook/add.php'),
|
|
||||||
data:{ name: data.name, description: data.description },
|
|
||||||
success:function(jsondata) {
|
|
||||||
if(jsondata.status == 'success') {
|
|
||||||
if(typeof cb === 'function') {
|
|
||||||
cb({
|
|
||||||
status:'success',
|
|
||||||
addressbook: jsondata.data.addressbook
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if(typeof cb === 'function') {
|
|
||||||
cb({status:'error', message:jsondata.data.message});
|
|
||||||
} else {
|
|
||||||
OC.notify({message:textStatus + ': ' + errorThrown});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
error:function(jqXHR, textStatus, errorThrown) {
|
|
||||||
if(typeof cb === 'function') {
|
|
||||||
cb({
|
|
||||||
status:'success',
|
|
||||||
message: textStatus + ': ' + errorThrown
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
OC.notify({message:textStatus + ': ' + errorThrown});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
// NOTE: Deprecated
|
|
||||||
selectAddressbook:function(cb) {
|
|
||||||
var self = this;
|
|
||||||
var jqxhr = $.get(OC.filePath('contacts', 'templates', 'selectaddressbook.html'), function(data) {
|
|
||||||
$('body').append('<div id="addressbook_dialog"></div>');
|
|
||||||
var $dlg = $('#addressbook_dialog').html(data).octemplate({
|
|
||||||
nameplaceholder: t('contacts', 'Enter name'),
|
|
||||||
descplaceholder: t('contacts', 'Enter description')
|
|
||||||
}).dialog({
|
|
||||||
modal: true, height: 'auto', width: 'auto',
|
|
||||||
title: t('contacts', 'Select addressbook'),
|
|
||||||
buttons: {
|
|
||||||
'Ok':function() {
|
|
||||||
aid = $(this).find('input:checked').val();
|
|
||||||
if(aid == 'new') {
|
|
||||||
var displayname = $(this).find('input.name').val();
|
|
||||||
var description = $(this).find('input.desc').val();
|
|
||||||
if(!$.trim(displayname)) {
|
|
||||||
OC.dialogs.alert(t('contacts', 'The address book name cannot be empty.'), t('contacts', 'Error'));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
console.log('ID, name and desc', aid, displayname, description);
|
|
||||||
if(typeof cb === 'function') {
|
|
||||||
// TODO: Create addressbook
|
|
||||||
var data = {name:displayname, description:description};
|
|
||||||
self.addAddressbook(data, function(data) {
|
|
||||||
if(data.status === 'success') {
|
|
||||||
cb({
|
|
||||||
status:'success',
|
|
||||||
addressbook:data.addressbook
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
cb({status:'error'});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
$(this).dialog('close');
|
|
||||||
} else {
|
|
||||||
console.log('aid ' + aid);
|
|
||||||
if(typeof cb === 'function') {
|
|
||||||
cb({
|
|
||||||
status:'success',
|
|
||||||
addressbook:self.contacts.addressbooks[parseInt(aid)]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
$(this).dialog('close');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'Cancel':function() {
|
|
||||||
$(this).dialog('close');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
close: function(event, ui) {
|
|
||||||
$(this).dialog('destroy').remove();
|
|
||||||
$('#addressbook_dialog').remove();
|
|
||||||
},
|
|
||||||
open: function(event, ui) {
|
|
||||||
console.log('open', $(this));
|
|
||||||
var $lastrow = $(this).find('tr.new');
|
|
||||||
$.each(self.contacts.addressbooks, function(i, book) {
|
|
||||||
console.log('book', i, book);
|
|
||||||
if(book.owner === OC.currentUser
|
|
||||||
|| (book.permissions & OC.PERMISSION_UPDATE
|
|
||||||
|| book.permissions & OC.PERMISSION_CREATE
|
|
||||||
|| book.permissions & OC.PERMISSION_DELETE)) {
|
|
||||||
var row = '<tr><td><input id="book_{id}" name="book" type="radio" value="{id}"</td>'
|
|
||||||
+ '<td><label for="book_{id}">{displayname}</label></td>'
|
|
||||||
+ '<td>{description}</td></tr>';
|
|
||||||
var $row = $(row).octemplate({
|
|
||||||
id:book.id,
|
|
||||||
displayname:book.displayname,
|
|
||||||
description:book.description
|
|
||||||
});
|
|
||||||
$lastrow.before($row);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
$(this).find('input[type="radio"]').first().prop('checked', true);
|
|
||||||
$lastrow.find('input.name,input.desc').on('focus', function(e) {
|
|
||||||
$lastrow.find('input[type="radio"]').prop('checked', true);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}).error(function() {
|
|
||||||
OC.notify({message: t('contacts', 'Network or server error. Please inform administrator.')});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
(function( $ ) {
|
|
||||||
/**
|
|
||||||
* Object Template
|
|
||||||
* Inspired by micro templating done by e.g. underscore.js
|
|
||||||
*/
|
|
||||||
var Template = {
|
|
||||||
init: function(vars, options, elem) {
|
|
||||||
// Mix in the passed in options with the default options
|
|
||||||
this.vars = vars;
|
|
||||||
this.options = $.extend({},this.options,options);
|
|
||||||
|
|
||||||
this.elem = elem;
|
|
||||||
var self = this;
|
|
||||||
|
|
||||||
if(typeof this.options.escapeFunction === 'function') {
|
|
||||||
$.each(this.vars, function(key, val) {
|
|
||||||
if(typeof val === 'string') {
|
|
||||||
self.vars[key] = self.options.escapeFunction(val);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
var _html = this._build(this.vars);
|
|
||||||
return $(_html);
|
|
||||||
},
|
|
||||||
// From stackoverflow.com/questions/1408289/best-way-to-do-variable-interpolation-in-javascript
|
|
||||||
_build: function(o){
|
|
||||||
var data = this.elem.attr('type') === 'text/template' ? this.elem.html() : this.elem.get(0).outerHTML;
|
|
||||||
try {
|
|
||||||
return data.replace(/{([^{}]*)}/g,
|
|
||||||
function (a, b) {
|
|
||||||
var r = o[b];
|
|
||||||
return typeof r === 'string' || typeof r === 'number' ? r : a;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
} catch(e) {
|
|
||||||
console.error(e, 'data:', data)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
options: {
|
|
||||||
escapeFunction: function(str) {return $('<i></i>').text(str).html();}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
$.fn.octemplate = function(vars, options) {
|
|
||||||
var vars = vars ? vars : {};
|
|
||||||
if(this.length) {
|
|
||||||
var _template = Object.create(Template);
|
|
||||||
return _template.init(vars, options, this);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
})( jQuery );
|
|
||||||
|
|
||||||
|
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
|
|
||||||
OC.Contacts.init();
|
OC.Router.registerLoadedCallback(function() {
|
||||||
|
$.getScript(OC.Router.generate('contacts_jsconfig'), function() {
|
||||||
|
OC.Contacts.init();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
/**
|
/**
|
||||||
* ownCloud - Addressbook
|
* ownCloud - Addressbook
|
||||||
*
|
*
|
||||||
* @author Jakob Sack
|
* @author Thomas Tanghus
|
||||||
* @copyright 2011 Jakob Sack mail@jakobsack.de
|
* @copyright 2012 Thomas Tanghus <thomas@tanghus.net>
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||||
@ -20,21 +20,17 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Check if we are a user
|
OCP\JSON::setContentTypeHeader('text/javascript');
|
||||||
OCP\JSON::checkLoggedIn();
|
OCP\JSON::checkLoggedIn();
|
||||||
OCP\JSON::checkAppEnabled('contacts');
|
OCP\JSON::checkAppEnabled('contacts');
|
||||||
OCP\JSON::callCheck();
|
|
||||||
require_once __DIR__.'/../loghandler.php';
|
|
||||||
|
|
||||||
$id = $_POST['id'];
|
$user = OCP\User::getUser();
|
||||||
if(!$id) {
|
|
||||||
bailOut(OCA\Contacts\App::$l10n->t('id is not set.'));
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
echo 'var contacts_groups_sortorder=[' . OCP\Config::getUserValue($user, 'contacts', 'groupsort', '') . '],';
|
||||||
OCA\Contacts\Addressbook::delete($id);
|
echo 'contacts_properties_indexed = '
|
||||||
} catch(Exception $e) {
|
. (OCP\Config::getUserValue($user, 'contacts', 'contacts_properties_indexed', 'no') === 'no'
|
||||||
bailOut($e->getMessage());
|
? 'false' : 'true') . ',';
|
||||||
}
|
echo 'contacts_categories_indexed = '
|
||||||
|
. (OCP\Config::getUserValue($user, 'contacts', 'contacts_categories_indexed', 'no') === 'no'
|
||||||
OCP\JSON::success(array('data' => array( 'id' => $id )));
|
? 'false' : 'true') . ',';
|
||||||
|
echo 'lang=\'' . OCP\Config::getUserValue($user, 'core', 'lang', 'en') . '\';';
|
780
js/contacts.js
780
js/contacts.js
@ -7,17 +7,18 @@ OC.Contacts = OC.Contacts || {};
|
|||||||
* An item which binds the appropriate html and event handlers
|
* An item which binds the appropriate html and event handlers
|
||||||
* @param parent the parent ContactList
|
* @param parent the parent ContactList
|
||||||
* @param id The integer contact id.
|
* @param id The integer contact id.
|
||||||
* @param access An access object containing and 'owner' string variable and an integer 'permissions' variable.
|
* @param metadata An metadata object containing and 'owner' string variable and an integer 'permissions' variable.
|
||||||
* @param data the data used to populate the contact
|
* @param data the data used to populate the contact
|
||||||
* @param listtemplate the jquery object used to render the contact list item
|
* @param listtemplate the jquery object used to render the contact list item
|
||||||
* @param fulltemplate the jquery object used to render the entire contact
|
* @param fulltemplate the jquery object used to render the entire contact
|
||||||
* @param detailtemplates A map of jquery objects used to render the contact parts e.g. EMAIL, TEL etc.
|
* @param detailtemplates A map of jquery objects used to render the contact parts e.g. EMAIL, TEL etc.
|
||||||
*/
|
*/
|
||||||
var Contact = function(parent, id, access, data, listtemplate, dragtemplate, fulltemplate, detailtemplates) {
|
var Contact = function(parent, id, metadata, data, listtemplate, dragtemplate, fulltemplate, detailtemplates) {
|
||||||
//console.log('contact:', id, access); //parent, id, data, listtemplate, fulltemplate);
|
//console.log('contact:', id, metadata, data); //parent, id, data, listtemplate, fulltemplate);
|
||||||
this.parent = parent,
|
this.parent = parent,
|
||||||
|
this.storage = parent.storage,
|
||||||
this.id = id,
|
this.id = id,
|
||||||
this.access = access,
|
this.metadata = metadata,
|
||||||
this.data = data,
|
this.data = data,
|
||||||
this.$dragTemplate = dragtemplate,
|
this.$dragTemplate = dragtemplate,
|
||||||
this.$listTemplate = listtemplate,
|
this.$listTemplate = listtemplate,
|
||||||
@ -27,6 +28,98 @@ OC.Contacts = OC.Contacts || {};
|
|||||||
this.multi_properties = ['EMAIL', 'TEL', 'IMPP', 'ADR', 'URL'];
|
this.multi_properties = ['EMAIL', 'TEL', 'IMPP', 'ADR', 'URL'];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Contact.prototype.metaData = function() {
|
||||||
|
return {
|
||||||
|
contactid: this.id,
|
||||||
|
addressbookid: this.metadata.parent,
|
||||||
|
backend: this.metadata.backend
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Contact.prototype.getDisplayName = function() {
|
||||||
|
return this.getPreferredValue('FN');
|
||||||
|
};
|
||||||
|
|
||||||
|
Contact.prototype.getId = function() {
|
||||||
|
return this.id;
|
||||||
|
};
|
||||||
|
|
||||||
|
Contact.prototype.getParent = function() {
|
||||||
|
return this.metadata.parent;
|
||||||
|
};
|
||||||
|
|
||||||
|
Contact.prototype.getBackend = function() {
|
||||||
|
return this.metadata.backend;
|
||||||
|
};
|
||||||
|
|
||||||
|
Contact.prototype.merge = function(mergees) {
|
||||||
|
console.log('Contact.merge, mergees', mergees);
|
||||||
|
if(!mergees instanceof Array && !mergees instanceof Contact) {
|
||||||
|
throw new TypeError('BadArgument: Contact.merge() only takes Contacts');
|
||||||
|
} else {
|
||||||
|
if(mergees instanceof Contact) {
|
||||||
|
mergees = [mergees];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// For multi_properties
|
||||||
|
var addIfNotExists = function(name, newproperty) {
|
||||||
|
// If the property isn't set at all just add it and return.
|
||||||
|
if(!self.data[name]) {
|
||||||
|
self.data[name] = [newproperty];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var found = false;
|
||||||
|
$.each(self.data[name], function(idx, property) {
|
||||||
|
if(name === 'ADR') {
|
||||||
|
// Do a simple string comparison
|
||||||
|
if(property.value.join(';').toLowerCase() === newproperty.value.join(';').toLowerCase()) {
|
||||||
|
found = true;
|
||||||
|
return false; // break loop
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(property.value.toLowerCase() === newproperty.value.toLowerCase()) {
|
||||||
|
found = true;
|
||||||
|
return false; // break loop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if(found) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Not found, so adding it.
|
||||||
|
self.data[name].push(newproperty);
|
||||||
|
}
|
||||||
|
|
||||||
|
var self = this;
|
||||||
|
$.each(mergees, function(idx, mergee) {
|
||||||
|
console.log('Contact.merge, mergee', mergee);
|
||||||
|
if(!mergee instanceof Contact) {
|
||||||
|
throw new TypeError('BadArgument: Contact.merge() only takes Contacts');
|
||||||
|
}
|
||||||
|
if(mergee === self) {
|
||||||
|
throw new Error('BadArgument: Why should I merge with myself?');
|
||||||
|
}
|
||||||
|
$.each(mergee.data, function(name, properties) {
|
||||||
|
if(self.multi_properties.indexOf(name) === -1) {
|
||||||
|
if(self.data[name] && self.data[name].length > 0) {
|
||||||
|
// If the property exists don't touch it.
|
||||||
|
return true; // continue
|
||||||
|
} else {
|
||||||
|
// Otherwise add it.
|
||||||
|
self.data[name] = properties;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$.each(properties, function(idx, property) {
|
||||||
|
addIfNotExists(name, property);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
console.log('Merged', self.data);
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
Contact.prototype.showActions = function(act) {
|
Contact.prototype.showActions = function(act) {
|
||||||
this.$footer.children().hide();
|
this.$footer.children().hide();
|
||||||
if(act && act.length > 0) {
|
if(act && act.length > 0) {
|
||||||
@ -68,7 +161,7 @@ OC.Contacts = OC.Contacts || {};
|
|||||||
newvalue: params.newvalue,
|
newvalue: params.newvalue,
|
||||||
oldvalue: params.oldvalue
|
oldvalue: params.oldvalue
|
||||||
});
|
});
|
||||||
console.log('undoQueue', this.undoQueue);
|
//console.log('undoQueue', this.undoQueue);
|
||||||
}
|
}
|
||||||
|
|
||||||
Contact.prototype.addProperty = function($option, name) {
|
Contact.prototype.addProperty = function($option, name) {
|
||||||
@ -137,6 +230,8 @@ OC.Contacts = OC.Contacts || {};
|
|||||||
console.log('Contact.deleteProperty, element', element, $container);
|
console.log('Contact.deleteProperty, element', element, $container);
|
||||||
var params = {
|
var params = {
|
||||||
name: element,
|
name: element,
|
||||||
|
backend: this.metadata.backend,
|
||||||
|
addressbookid: this.metadata.parent,
|
||||||
id: this.id
|
id: this.id
|
||||||
};
|
};
|
||||||
if(this.multi_properties.indexOf(element) !== -1) {
|
if(this.multi_properties.indexOf(element) !== -1) {
|
||||||
@ -153,16 +248,9 @@ OC.Contacts = OC.Contacts || {};
|
|||||||
}
|
}
|
||||||
this.setAsSaving(obj, true);
|
this.setAsSaving(obj, true);
|
||||||
var self = this;
|
var self = this;
|
||||||
$.post(OC.filePath('contacts', 'ajax', 'contact/deleteproperty.php'), params, function(jsondata) {
|
$.when(this.storage.deleteProperty(this.metadata.backend, this.metadata.parent, this.id, params))
|
||||||
if(!jsondata) {
|
.then(function(response) {
|
||||||
$(document).trigger('status.contact.error', {
|
if(!response.error) {
|
||||||
status: 'error',
|
|
||||||
message: t('contacts', 'Network or server error. Please inform administrator.')
|
|
||||||
});
|
|
||||||
self.setAsSaving(obj, false);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if(jsondata.status == 'success') {
|
|
||||||
// TODO: Test if removing from internal data structure works
|
// TODO: Test if removing from internal data structure works
|
||||||
if(self.multi_properties.indexOf(element) !== -1) {
|
if(self.multi_properties.indexOf(element) !== -1) {
|
||||||
// First find out if an existing element by looking for checksum
|
// First find out if an existing element by looking for checksum
|
||||||
@ -206,19 +294,68 @@ OC.Contacts = OC.Contacts || {};
|
|||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
$(document).trigger('status.contact.error', {
|
$(document).trigger('status.contact.error', {
|
||||||
status: 'error',
|
message: response.message
|
||||||
message: jsondata.data.message
|
|
||||||
});
|
});
|
||||||
self.setAsSaving(obj, false);
|
self.setAsSaving(obj, false);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
},'json');
|
})
|
||||||
|
.fail(function(jqxhr, textStatus, error) {
|
||||||
|
var err = textStatus + ', ' + error;
|
||||||
|
console.warn( "Request Failed: " + err);
|
||||||
|
$(document).trigger('status.contact.error', {
|
||||||
|
message: t('contacts', 'Failed deleting property: {error}', {error:err})
|
||||||
|
});
|
||||||
|
});
|
||||||
|
;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Save all properties. Used for merging contacts.
|
||||||
|
* If this is a new contact it will first be saved to the datastore and a
|
||||||
|
* new datastructure will be added to the object.
|
||||||
|
*/
|
||||||
|
Contact.prototype.saveAll = function(cb) {
|
||||||
|
console.log('Contact.saveAll');
|
||||||
|
if(!this.id) {
|
||||||
|
var self = this;
|
||||||
|
this.add({isnew:true}, function(response) {
|
||||||
|
if(response.error) {
|
||||||
|
console.warn('No response object');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
self.saveAll();
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var self = this;
|
||||||
|
this.setAsSaving(this.$fullelem, true);
|
||||||
|
var data = JSON.stringify(this.data);
|
||||||
|
//console.log('stringified', data);
|
||||||
|
$.when(this.storage.saveAllProperties(this.metadata.backend, this.metadata.parent, this.id, data))
|
||||||
|
.then(function(response) {
|
||||||
|
if(!response.error) {
|
||||||
|
self.data = response.data.data;
|
||||||
|
self.metadata = response.data.metadata;
|
||||||
|
if(typeof cb === 'function') {
|
||||||
|
cb({error:false});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$(document).trigger('status.contact.error', {
|
||||||
|
message: response.message
|
||||||
|
});
|
||||||
|
if(typeof cb === 'function') {
|
||||||
|
cb({error:true, message:response.message});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.setAsSaving(self.$fullelem, false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Act on change of a property.
|
* @brief Act on change of a property.
|
||||||
* If this is a new contact it will first be saved to the datastore and a
|
* If this is a new contact it will first be saved to the datastore and a
|
||||||
* new datastructure will be added to the object. FIXME: Not implemented yet.
|
* new datastructure will be added to the object.
|
||||||
* If the obj argument is not provided 'name' and 'value' MUST be provided
|
* If the obj argument is not provided 'name' and 'value' MUST be provided
|
||||||
* and this is only allowed for single elements like N, FN, CATEGORIES.
|
* and this is only allowed for single elements like N, FN, CATEGORIES.
|
||||||
* @param obj. The form form field that has changed.
|
* @param obj. The form form field that has changed.
|
||||||
@ -241,32 +378,25 @@ OC.Contacts = OC.Contacts || {};
|
|||||||
}
|
}
|
||||||
var obj = null;
|
var obj = null;
|
||||||
var element = null;
|
var element = null;
|
||||||
var q = '';
|
var args = [];
|
||||||
if(params.obj) {
|
if(params.obj) {
|
||||||
obj = params.obj;
|
obj = params.obj;
|
||||||
q = this.queryStringFor(obj);
|
args = this.argumentsFor(obj);
|
||||||
|
args['parameters'] = this.parametersFor(obj);
|
||||||
element = this.propertyTypeFor(obj);
|
element = this.propertyTypeFor(obj);
|
||||||
} else {
|
} else {
|
||||||
|
args = params;
|
||||||
element = params.name;
|
element = params.name;
|
||||||
var value = utils.isArray(params.value)
|
var value = utils.isArray(params.value)
|
||||||
? $.param(params.value)
|
? $.param(params.value)
|
||||||
: encodeURIComponent(params.value);
|
: encodeURIComponent(params.value);
|
||||||
q = 'id=' + this.id + '&value=' + value + '&name=' + element;
|
|
||||||
}
|
}
|
||||||
console.log('q', q);
|
console.log('args', args);
|
||||||
var self = this;
|
var self = this;
|
||||||
this.setAsSaving(obj, true);
|
this.setAsSaving(obj, true);
|
||||||
$.post(OC.filePath('contacts', 'ajax', 'contact/saveproperty.php'), q, function(jsondata){
|
$.when(this.storage.saveProperty(this.metadata.backend, this.metadata.parent, this.id, args))
|
||||||
if(!jsondata) {
|
.then(function(response) {
|
||||||
$(document).trigger('status.contact.error', {
|
if(!response.error) {
|
||||||
status: 'error',
|
|
||||||
message: t('contacts', 'Network or server error. Please inform administrator.')
|
|
||||||
});
|
|
||||||
$(obj).addClass('error');
|
|
||||||
self.setAsSaving(obj, false);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if(jsondata.status == 'success') {
|
|
||||||
if(!self.data[element]) {
|
if(!self.data[element]) {
|
||||||
self.data[element] = [];
|
self.data[element] = [];
|
||||||
}
|
}
|
||||||
@ -283,7 +413,7 @@ OC.Contacts = OC.Contacts || {};
|
|||||||
self.pushToUndo({
|
self.pushToUndo({
|
||||||
action:'save',
|
action:'save',
|
||||||
name: element,
|
name: element,
|
||||||
newchecksum: jsondata.data.checksum,
|
newchecksum: response.data.checksum,
|
||||||
oldchecksum: checksum,
|
oldchecksum: checksum,
|
||||||
newvalue: value,
|
newvalue: value,
|
||||||
oldvalue: obj.defaultValue
|
oldvalue: obj.defaultValue
|
||||||
@ -294,7 +424,7 @@ OC.Contacts = OC.Contacts || {};
|
|||||||
name: element,
|
name: element,
|
||||||
value: value,
|
value: value,
|
||||||
parameters: parameters,
|
parameters: parameters,
|
||||||
checksum: jsondata.data.checksum
|
checksum: response.data.checksum
|
||||||
};
|
};
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -304,17 +434,17 @@ OC.Contacts = OC.Contacts || {};
|
|||||||
self.pushToUndo({
|
self.pushToUndo({
|
||||||
action:'add',
|
action:'add',
|
||||||
name: element,
|
name: element,
|
||||||
newchecksum: jsondata.data.checksum,
|
newchecksum: response.data.checksum,
|
||||||
newvalue: value,
|
newvalue: value,
|
||||||
});
|
});
|
||||||
self.data[element].push({
|
self.data[element].push({
|
||||||
name: element,
|
name: element,
|
||||||
value: value,
|
value: value,
|
||||||
parameters: parameters,
|
parameters: parameters,
|
||||||
checksum: jsondata.data.checksum,
|
checksum: response.data.checksum,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
self.propertyContainerFor(obj).data('checksum', jsondata.data.checksum);
|
self.propertyContainerFor(obj).data('checksum', response.data.checksum);
|
||||||
} else {
|
} else {
|
||||||
// Save value and parameters internally
|
// Save value and parameters internally
|
||||||
var value = obj ? self.valueFor(obj) : params.value;
|
var value = obj ? self.valueFor(obj) : params.value;
|
||||||
@ -327,6 +457,16 @@ OC.Contacts = OC.Contacts || {};
|
|||||||
case 'CATEGORIES':
|
case 'CATEGORIES':
|
||||||
// We deal with this in addToGroup()
|
// We deal with this in addToGroup()
|
||||||
break;
|
break;
|
||||||
|
case 'BDAY':
|
||||||
|
// reverse order again.
|
||||||
|
value = $.datepicker.formatDate('yy-mm-dd', $.datepicker.parseDate('dd-mm-yy', value));
|
||||||
|
self.data[element][0] = {
|
||||||
|
name: element,
|
||||||
|
value: value,
|
||||||
|
parameters: self.parametersFor(obj),
|
||||||
|
checksum: response.data.checksum
|
||||||
|
};
|
||||||
|
break;
|
||||||
case 'FN':
|
case 'FN':
|
||||||
if(!self.data.FN || !self.data.FN.length) {
|
if(!self.data.FN || !self.data.FN.length) {
|
||||||
self.data.FN = [{name:'FN', value:'', parameters:[]}];
|
self.data.FN = [{name:'FN', value:'', parameters:[]}];
|
||||||
@ -380,7 +520,6 @@ OC.Contacts = OC.Contacts || {};
|
|||||||
$fullname.val(self.data.FN[0]['value']);
|
$fullname.val(self.data.FN[0]['value']);
|
||||||
update_fn = true;
|
update_fn = true;
|
||||||
} else if($fullname.val() == value[1] + ' ') {
|
} else if($fullname.val() == value[1] + ' ') {
|
||||||
console.log('change', value);
|
|
||||||
self.data.FN[0]['value'] = value[1] + ' ' + value[0];
|
self.data.FN[0]['value'] = value[1] + ' ' + value[0];
|
||||||
$fullname.val(self.data.FN[0]['value']);
|
$fullname.val(self.data.FN[0]['value']);
|
||||||
update_fn = true;
|
update_fn = true;
|
||||||
@ -395,7 +534,6 @@ OC.Contacts = OC.Contacts || {};
|
|||||||
}, 1000);
|
}, 1000);
|
||||||
}
|
}
|
||||||
case 'NICKNAME':
|
case 'NICKNAME':
|
||||||
case 'BDAY':
|
|
||||||
case 'ORG':
|
case 'ORG':
|
||||||
case 'TITLE':
|
case 'TITLE':
|
||||||
case 'NOTE':
|
case 'NOTE':
|
||||||
@ -403,7 +541,7 @@ OC.Contacts = OC.Contacts || {};
|
|||||||
name: element,
|
name: element,
|
||||||
value: value,
|
value: value,
|
||||||
parameters: self.parametersFor(obj),
|
parameters: self.parametersFor(obj),
|
||||||
checksum: jsondata.data.checksum
|
checksum: response.data.checksum
|
||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -418,13 +556,12 @@ OC.Contacts = OC.Contacts || {};
|
|||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
$(document).trigger('status.contact.error', {
|
$(document).trigger('status.contact.error', {
|
||||||
status: 'error',
|
message: response.message
|
||||||
message: jsondata.data.message
|
|
||||||
});
|
});
|
||||||
self.setAsSaving(obj, false);
|
self.setAsSaving(obj, false);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
},'json');
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -499,22 +636,16 @@ OC.Contacts = OC.Contacts || {};
|
|||||||
* @returns The callback gets an object as argument with a variable 'status' of either 'success'
|
* @returns The callback gets an object as argument with a variable 'status' of either 'success'
|
||||||
* or 'error'. On success the 'data' property of that object contains the contact id as 'id', the
|
* or 'error'. On success the 'data' property of that object contains the contact id as 'id', the
|
||||||
* addressbook id as 'aid' and the contact data structure as 'details'.
|
* addressbook id as 'aid' and the contact data structure as 'details'.
|
||||||
|
* TODO: Use Storage for adding and make sure to get all metadata.
|
||||||
*/
|
*/
|
||||||
Contact.prototype.add = function(params, cb) {
|
Contact.prototype.add = function(params, cb) {
|
||||||
var self = this;
|
var self = this;
|
||||||
$.post(OC.filePath('contacts', 'ajax', 'contact/add.php'),
|
$.when(this.storage.addContact(this.metadata.backend, this.metadata.parent))
|
||||||
params, function(jsondata) {
|
.then(function(response) {
|
||||||
if(!jsondata) {
|
if(!response.error) {
|
||||||
$(document).trigger('status.contact.error', {
|
self.id = String(response.data.metadata.id);
|
||||||
status: 'error',
|
self.metadata = response.data.metadata;
|
||||||
message: t('contacts', 'Network or server error. Please inform administrator.')
|
self.data = response.data.data;
|
||||||
});
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if(jsondata.status === 'success') {
|
|
||||||
self.id = parseInt(jsondata.data.id);
|
|
||||||
self.access.id = parseInt(jsondata.data.aid);
|
|
||||||
self.data = jsondata.data.details;
|
|
||||||
self.$groupSelect.multiselect('enable');
|
self.$groupSelect.multiselect('enable');
|
||||||
// Add contact to current group
|
// Add contact to current group
|
||||||
if(self.groupprops && self.groupprops.currentgroup.id !== 'all'
|
if(self.groupprops && self.groupprops.currentgroup.id !== 'all'
|
||||||
@ -534,9 +665,14 @@ OC.Contacts = OC.Contacts || {};
|
|||||||
id: self.id,
|
id: self.id,
|
||||||
contact: self
|
contact: self
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
$(document).trigger('status.contact.error', {
|
||||||
|
message: response.message
|
||||||
|
});
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
if(typeof cb == 'function') {
|
if(typeof cb == 'function') {
|
||||||
cb(jsondata);
|
cb(response);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@ -548,9 +684,14 @@ OC.Contacts = OC.Contacts || {};
|
|||||||
*/
|
*/
|
||||||
Contact.prototype.destroy = function(cb) {
|
Contact.prototype.destroy = function(cb) {
|
||||||
var self = this;
|
var self = this;
|
||||||
$.post(OC.filePath('contacts', 'ajax', 'contact/delete.php'),
|
$.when(this.storage.deleteContact(
|
||||||
{id: this.id}, function(jsondata) {
|
this.metadata.backend,
|
||||||
if(jsondata && jsondata.status === 'success') {
|
this.metadata.parent,
|
||||||
|
this.id)
|
||||||
|
).then(function(response) {
|
||||||
|
//$.post(OC.filePath('contacts', 'ajax', 'contact/delete.php'),
|
||||||
|
// {id: this.id}, function(response) {
|
||||||
|
if(!response.error) {
|
||||||
if(self.$listelem) {
|
if(self.$listelem) {
|
||||||
self.$listelem.remove();
|
self.$listelem.remove();
|
||||||
}
|
}
|
||||||
@ -559,22 +700,49 @@ OC.Contacts = OC.Contacts || {};
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(typeof cb == 'function') {
|
if(typeof cb == 'function') {
|
||||||
var retval = {status: jsondata ? jsondata.status : 'error'};
|
if(response.error) {
|
||||||
if(jsondata) {
|
cb(response);
|
||||||
if(jsondata.status === 'success') {
|
|
||||||
retval['id'] = jsondata.id;
|
|
||||||
} else {
|
|
||||||
retval['message'] = jsondata.message;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
retval['message'] = t('contacts', 'There was an unknown error when trying to delete this contact');
|
cb({id:self.id});
|
||||||
retval['id'] = self.id;
|
|
||||||
}
|
}
|
||||||
cb(retval);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Contact.prototype.argumentsFor = function(obj) {
|
||||||
|
var args = {};
|
||||||
|
var ptype = this.propertyTypeFor(obj);
|
||||||
|
args['name'] = ptype;
|
||||||
|
|
||||||
|
if(this.multi_properties.indexOf(ptype) !== -1) {
|
||||||
|
args['checksum'] = this.checksumFor(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
if($(obj).hasClass('propertycontainer')) {
|
||||||
|
if($(obj).is('select[data-element="categories"]')) {
|
||||||
|
args['value'] = [];
|
||||||
|
$.each($(obj).find(':selected'), function(idx, e) {
|
||||||
|
args['value'].push($(e).text());
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
args['value'] = $(obj).val();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
var $elements = this.propertyContainerFor(obj)
|
||||||
|
.find('input.value,select.value,textarea.value');
|
||||||
|
if($elements.length > 1) {
|
||||||
|
args['value'] = [];
|
||||||
|
$.each($elements, function(idx, e) {
|
||||||
|
args['value'][parseInt($(e).attr('name').substr(6,1))] = $(e).val();
|
||||||
|
//args['value'].push($(e).val());
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
args['value'] = $elements.val();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return args;
|
||||||
|
};
|
||||||
|
|
||||||
Contact.prototype.queryStringFor = function(obj) {
|
Contact.prototype.queryStringFor = function(obj) {
|
||||||
var q = 'id=' + this.id;
|
var q = 'id=' + this.id;
|
||||||
var ptype = this.propertyTypeFor(obj);
|
var ptype = this.propertyTypeFor(obj);
|
||||||
@ -617,7 +785,7 @@ OC.Contacts = OC.Contacts || {};
|
|||||||
Contact.prototype.valueFor = function(obj) {
|
Contact.prototype.valueFor = function(obj) {
|
||||||
var $container = this.propertyContainerFor(obj);
|
var $container = this.propertyContainerFor(obj);
|
||||||
console.assert($container.length > 0, 'Couldn\'t find container for ' + $(obj));
|
console.assert($container.length > 0, 'Couldn\'t find container for ' + $(obj));
|
||||||
return $container.is('input')
|
return $container.is('input.value')
|
||||||
? $container.val()
|
? $container.val()
|
||||||
: (function() {
|
: (function() {
|
||||||
var $elem = $container.find('textarea.value,input.value:not(:checkbox)');
|
var $elem = $container.find('textarea.value,input.value:not(:checkbox)');
|
||||||
@ -636,23 +804,29 @@ OC.Contacts = OC.Contacts || {};
|
|||||||
|
|
||||||
Contact.prototype.parametersFor = function(obj, asText) {
|
Contact.prototype.parametersFor = function(obj, asText) {
|
||||||
var parameters = [];
|
var parameters = [];
|
||||||
$.each(this.propertyContainerFor(obj).find('select.parameter,input:checkbox:checked.parameter,textarea'), function(i, elem) {
|
$.each(this.propertyContainerFor(obj)
|
||||||
|
.find('select.parameter,input:checkbox:checked.parameter,textarea'), // Why do I look for textarea?
|
||||||
|
function(i, elem) {
|
||||||
var $elem = $(elem);
|
var $elem = $(elem);
|
||||||
var paramname = $elem.data('parameter');
|
var paramname = $elem.data('parameter');
|
||||||
if(!parameters[paramname]) {
|
if(!parameters[paramname]) {
|
||||||
parameters[paramname] = [];
|
parameters[paramname] = [];
|
||||||
}
|
}
|
||||||
var val;
|
if($elem.is(':checkbox')) {
|
||||||
if(asText) {
|
if(asText) {
|
||||||
if($elem.is(':checkbox')) {
|
parameters[paramname].push($elem.attr('title'));
|
||||||
val = $elem.attr('title');
|
} else {
|
||||||
} else if($elem.is('select')) {
|
parameters[paramname].push($elem.attr('value'));
|
||||||
val = $elem.find(':selected').text();
|
|
||||||
}
|
}
|
||||||
} else {
|
} else if($elem.is('select')) {
|
||||||
val = $elem.val();
|
$.each($elem.find(':selected'), function(idx, e) {
|
||||||
|
if(asText) {
|
||||||
|
parameters[paramname].push($(e).text());
|
||||||
|
} else {
|
||||||
|
parameters[paramname].push($(e).val());
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
parameters[paramname].push(val);
|
|
||||||
});
|
});
|
||||||
return parameters;
|
return parameters;
|
||||||
};
|
};
|
||||||
@ -673,6 +847,7 @@ OC.Contacts = OC.Contacts || {};
|
|||||||
name: this.getPreferredValue('FN', '')
|
name: this.getPreferredValue('FN', '')
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
this.setThumbnail(this.$dragelem);
|
||||||
return this.$dragelem;
|
return this.$dragelem;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -683,18 +858,23 @@ OC.Contacts = OC.Contacts || {};
|
|||||||
Contact.prototype.renderListItem = function(isnew) {
|
Contact.prototype.renderListItem = function(isnew) {
|
||||||
this.$listelem = this.$listTemplate.octemplate({
|
this.$listelem = this.$listTemplate.octemplate({
|
||||||
id: this.id,
|
id: this.id,
|
||||||
name: isnew ? this.getPreferredValue('FN', '') : this.getPreferredValue('FN', ''),
|
parent: this.metadata.parent,
|
||||||
email: isnew ? this.getPreferredValue('EMAIL', '') : this.getPreferredValue('EMAIL', ''),
|
backend: this.metadata.backend,
|
||||||
tel: isnew ? this.getPreferredValue('TEL', '') : this.getPreferredValue('TEL', ''),
|
name: this.getPreferredValue('FN', ''),
|
||||||
adr: isnew ? this.getPreferredValue('ADR', []).clean('').join(', ') : this.getPreferredValue('ADR', []).clean('').join(', '),
|
email: this.getPreferredValue('EMAIL', ''),
|
||||||
|
tel: this.getPreferredValue('TEL', ''),
|
||||||
|
adr: this.getPreferredValue('ADR', []).clean('').join(', '),
|
||||||
categories: this.getPreferredValue('CATEGORIES', [])
|
categories: this.getPreferredValue('CATEGORIES', [])
|
||||||
.clean('').join(' / ')
|
.clean('').join(' / ')
|
||||||
});
|
});
|
||||||
if(this.access.owner !== OC.currentUser
|
if(this.metadata.owner !== OC.currentUser
|
||||||
&& !(this.access.permissions & OC.PERMISSION_UPDATE
|
&& !(this.metadata.permissions & OC.PERMISSION_UPDATE
|
||||||
|| this.access.permissions & OC.PERMISSION_DELETE)) {
|
|| this.metadata.permissions & OC.PERMISSION_DELETE)) {
|
||||||
this.$listelem.find('input:checkbox').prop('disabled', true).css('opacity', '0');
|
this.$listelem.find('input:checkbox').prop('disabled', true).css('opacity', '0');
|
||||||
}
|
}
|
||||||
|
if(isnew) {
|
||||||
|
this.setThumbnail();
|
||||||
|
}
|
||||||
return this.$listelem;
|
return this.$listelem;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -723,7 +903,7 @@ OC.Contacts = OC.Contacts || {};
|
|||||||
});
|
});
|
||||||
self.$groupSelect.bind('multiselectclick', function(event, ui) {
|
self.$groupSelect.bind('multiselectclick', function(event, ui) {
|
||||||
var action = ui.checked ? 'addtogroup' : 'removefromgroup';
|
var action = ui.checked ? 'addtogroup' : 'removefromgroup';
|
||||||
console.assert(typeof self.id === 'number', 'ID is not a number')
|
console.assert(typeof self.id === 'string', 'ID is not a string')
|
||||||
$(document).trigger('request.contact.' + action, {
|
$(document).trigger('request.contact.' + action, {
|
||||||
id: self.id,
|
id: self.id,
|
||||||
groupid: parseInt(ui.value)
|
groupid: parseInt(ui.value)
|
||||||
@ -739,6 +919,34 @@ OC.Contacts = OC.Contacts || {};
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var buildAddressBookSelect = function(availableAddressBooks) {
|
||||||
|
console.log('address books', availableAddressBooks.length, availableAddressBooks);
|
||||||
|
/* TODO:
|
||||||
|
* - Check address books permissions.
|
||||||
|
* - Add method to change address book.
|
||||||
|
*/
|
||||||
|
$.each(availableAddressBooks, function(idx, addressBook) {
|
||||||
|
//console.log('addressBook', idx, addressBook);
|
||||||
|
var $option = $('<option data-backend="'
|
||||||
|
+ addressBook.backend + '" value="' + addressBook.id + '">'
|
||||||
|
+ addressBook.displayname + '(' + addressBook.backend + ')</option>');
|
||||||
|
if(self.metadata.parent === addressBook.id
|
||||||
|
&& self.metadata.backend === addressBook.backend) {
|
||||||
|
$option.attr('selected', 'selected');
|
||||||
|
}
|
||||||
|
self.$addressBookSelect.append($option);
|
||||||
|
});
|
||||||
|
self.$addressBookSelect.multiselect({
|
||||||
|
header: false,
|
||||||
|
selectedList: 3,
|
||||||
|
noneSelectedText: self.$addressBookSelect.attr('title'),
|
||||||
|
selectedText: t('contacts', '# groups')
|
||||||
|
});
|
||||||
|
if(self.id) {
|
||||||
|
self.$addressBookSelect.multiselect('disable');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
var n = this.getPreferredValue('N', ['', '', '', '', '']);
|
var n = this.getPreferredValue('N', ['', '', '', '', '']);
|
||||||
//console.log('Contact.renderContact', this.data);
|
//console.log('Contact.renderContact', this.data);
|
||||||
var values = this.data
|
var values = this.data
|
||||||
@ -770,6 +978,11 @@ OC.Contacts = OC.Contacts || {};
|
|||||||
this.$groupSelect = this.$fullelem.find('#contactgroups');
|
this.$groupSelect = this.$fullelem.find('#contactgroups');
|
||||||
buildGroupSelect(groupprops.groups);
|
buildGroupSelect(groupprops.groups);
|
||||||
|
|
||||||
|
if(Object.keys(this.parent.addressbooks).length > 1) {
|
||||||
|
this.$addressBookSelect = this.$fullelem.find('#contactaddressbooks');
|
||||||
|
buildAddressBookSelect(this.parent.addressbooks);
|
||||||
|
}
|
||||||
|
|
||||||
this.$addMenu = this.$fullelem.find('#addproperty');
|
this.$addMenu = this.$fullelem.find('#addproperty');
|
||||||
this.$addMenu.on('change', function(event) {
|
this.$addMenu.on('change', function(event) {
|
||||||
//console.log('add', $(this).val());
|
//console.log('add', $(this).val());
|
||||||
@ -820,13 +1033,9 @@ OC.Contacts = OC.Contacts || {};
|
|||||||
id: self.id
|
id: self.id
|
||||||
});
|
});
|
||||||
} else if($(this).is('.export')) {
|
} else if($(this).is('.export')) {
|
||||||
$(document).trigger('request.contact.export', {
|
$(document).trigger('request.contact.export', self.metaData());
|
||||||
id: self.id
|
|
||||||
});
|
|
||||||
} else if($(this).is('.delete')) {
|
} else if($(this).is('.delete')) {
|
||||||
$(document).trigger('request.contact.delete', {
|
$(document).trigger('request.contact.delete', self.metaData());
|
||||||
id: self.id
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
@ -847,7 +1056,8 @@ OC.Contacts = OC.Contacts || {};
|
|||||||
if($(this).hasClass('value') && this.value === this.defaultValue) {
|
if($(this).hasClass('value') && this.value === this.defaultValue) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
console.log('change', this.defaultValue, this.value);
|
//console.log('change', this.defaultValue, this.value);
|
||||||
|
this.defaultValue = this.value;
|
||||||
self.saveProperty({obj:event.target});
|
self.saveProperty({obj:event.target});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -971,9 +1181,9 @@ OC.Contacts = OC.Contacts || {};
|
|||||||
if($meta.length) {
|
if($meta.length) {
|
||||||
$meta.html(meta.join('/'));
|
$meta.html(meta.join('/'));
|
||||||
}
|
}
|
||||||
if(self.access.owner === OC.currentUser
|
if(self.metadata.owner === OC.currentUser
|
||||||
|| self.access.permissions & OC.PERMISSION_UPDATE
|
|| self.metadata.permissions & OC.PERMISSION_UPDATE
|
||||||
|| self.access.permissions & OC.PERMISSION_DELETE) {
|
|| self.metadata.permissions & OC.PERMISSION_DELETE) {
|
||||||
$property.find('select.type[name="parameters[TYPE][]"]')
|
$property.find('select.type[name="parameters[TYPE][]"]')
|
||||||
.combobox({
|
.combobox({
|
||||||
singleclick: true,
|
singleclick: true,
|
||||||
@ -985,9 +1195,9 @@ OC.Contacts = OC.Contacts || {};
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if(this.access.owner !== OC.currentUser
|
if(this.metadata.owner !== OC.currentUser
|
||||||
&& !(this.access.permissions & OC.PERMISSION_UPDATE
|
&& !(this.metadata.permissions & OC.PERMISSION_UPDATE
|
||||||
|| this.access.permissions & OC.PERMISSION_DELETE)) {
|
|| this.metadata.permissions & OC.PERMISSION_DELETE)) {
|
||||||
this.setEnabled(false);
|
this.setEnabled(false);
|
||||||
this.showActions(['close', 'export']);
|
this.showActions(['close', 'export']);
|
||||||
} else {
|
} else {
|
||||||
@ -998,9 +1208,9 @@ OC.Contacts = OC.Contacts || {};
|
|||||||
};
|
};
|
||||||
|
|
||||||
Contact.prototype.isEditable = function() {
|
Contact.prototype.isEditable = function() {
|
||||||
return ((this.access.owner === OC.currentUser)
|
return ((this.metadata.owner === OC.currentUser)
|
||||||
|| (this.access.permissions & OC.PERMISSION_UPDATE
|
|| (this.metadata.permissions & OC.PERMISSION_UPDATE
|
||||||
|| this.access.permissions & OC.PERMISSION_DELETE));
|
|| this.metadata.permissions & OC.PERMISSION_DELETE));
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1063,7 +1273,7 @@ OC.Contacts = OC.Contacts || {};
|
|||||||
var val = self.valueFor(input);
|
var val = self.valueFor(input);
|
||||||
var params = self.parametersFor(input, true);
|
var params = self.parametersFor(input, true);
|
||||||
$(this).find('.meta').html(params['TYPE'].join('/'));
|
$(this).find('.meta').html(params['TYPE'].join('/'));
|
||||||
$(this).find('.adr').html(escapeHTML(self.valueFor($editor.find('input').first()).clean('').join(', ')));
|
$(this).find('.adr').html(self.valueFor($editor.find('input').first()).clean('').join(', '));
|
||||||
$(this).next('.listactions').css('display', 'inline-block');
|
$(this).next('.listactions').css('display', 'inline-block');
|
||||||
$('body').unbind('click', bodyListener);
|
$('body').unbind('click', bodyListener);
|
||||||
});
|
});
|
||||||
@ -1151,27 +1361,68 @@ OC.Contacts = OC.Contacts || {};
|
|||||||
return this.detailTemplates['impp'].octemplate(values);
|
return this.detailTemplates['impp'].octemplate(values);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a thumbnail for the contact if a PHOTO property exists
|
||||||
|
*/
|
||||||
|
Contact.prototype.setThumbnail = function($elem, refresh) {
|
||||||
|
if(!this.data.thumbnail && !refresh) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(!$elem) {
|
||||||
|
$elem = this.getListItemElement().find('td.name');
|
||||||
|
}
|
||||||
|
if(!$elem.hasClass('thumbnail') && !refresh) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(this.data.thumbnail) {
|
||||||
|
$elem.removeClass('thumbnail');
|
||||||
|
$elem.css('background-image', 'url(data:image/png;base64,' + this.data.thumbnail + ')');
|
||||||
|
} else {
|
||||||
|
$elem.addClass('thumbnail');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render the PHOTO property.
|
* Render the PHOTO property.
|
||||||
*/
|
*/
|
||||||
Contact.prototype.loadPhoto = function(dontloadhandlers) {
|
Contact.prototype.loadPhoto = function(dontloadhandlers) {
|
||||||
var self = this;
|
var self = this;
|
||||||
var id = this.id || 'new';
|
var id = this.id || 'new',
|
||||||
var refreshstr = '&refresh='+Math.random();
|
backend = this.metadata.backend,
|
||||||
this.$photowrapper = this.$fullelem.find('#photowrapper');
|
parent = this.metadata.parent,
|
||||||
this.$photowrapper.addClass('loading').addClass('wait');
|
src;
|
||||||
|
|
||||||
var $phototools = this.$fullelem.find('#phototools');
|
var $phototools = this.$fullelem.find('#phototools');
|
||||||
delete this.photo;
|
if(!this.$photowrapper) {
|
||||||
$('img.contactphoto').remove();
|
this.$photowrapper = this.$fullelem.find('#photowrapper');
|
||||||
this.photo = new Image();
|
}
|
||||||
$(this.photo).load(function () {
|
|
||||||
$(this).addClass('contactphoto');
|
var finishLoad = function(image) {
|
||||||
self.$photowrapper.css({width: $(this).get(0).width + 10, height: $(this).get(0).height + 10});
|
console.log('finishLoad', self.getDisplayName(), image.width, image.height);
|
||||||
|
$(image).addClass('contactphoto');
|
||||||
|
self.$photowrapper.css({width: image.width + 10, height: image.height + 10});
|
||||||
self.$photowrapper.removeClass('loading').removeClass('wait');
|
self.$photowrapper.removeClass('loading').removeClass('wait');
|
||||||
$(this).insertAfter($phototools).fadeIn();
|
$(image).insertAfter($phototools).fadeIn();
|
||||||
}).error(function () {
|
};
|
||||||
OC.notify({message:t('contacts','Error loading profile picture.')});
|
|
||||||
}).attr('src', OC.linkTo('contacts', 'photo.php')+'?id='+id+refreshstr);
|
this.$photowrapper.addClass('loading').addClass('wait');
|
||||||
|
if(this.getPreferredValue('PHOTO', null) === null) {
|
||||||
|
$.when(this.storage.getDefaultPhoto())
|
||||||
|
.then(function(image) {
|
||||||
|
$('img.contactphoto').detach();
|
||||||
|
finishLoad(image);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
$.when(this.storage.getContactPhoto(backend, parent, id))
|
||||||
|
.then(function(image) {
|
||||||
|
$('img.contactphoto').remove();
|
||||||
|
finishLoad(image);
|
||||||
|
})
|
||||||
|
.fail(function(defaultImage) {
|
||||||
|
$('img.contactphoto').remove();
|
||||||
|
finishLoad(defaultImage);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if(!dontloadhandlers && this.isEditable()) {
|
if(!dontloadhandlers && this.isEditable()) {
|
||||||
this.$photowrapper.on('mouseenter', function(event) {
|
this.$photowrapper.on('mouseenter', function(event) {
|
||||||
@ -1190,19 +1441,13 @@ OC.Contacts = OC.Contacts || {};
|
|||||||
$phototools.find('li a').tipsy();
|
$phototools.find('li a').tipsy();
|
||||||
|
|
||||||
$phototools.find('.edit').on('click', function() {
|
$phototools.find('.edit').on('click', function() {
|
||||||
$(document).trigger('request.edit.contactphoto', {
|
$(document).trigger('request.edit.contactphoto', self.metaData());
|
||||||
id: self.id
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
$phototools.find('.cloud').on('click', function() {
|
$phototools.find('.cloud').on('click', function() {
|
||||||
$(document).trigger('request.select.contactphoto.fromcloud', {
|
$(document).trigger('request.select.contactphoto.fromcloud', self.metaData());
|
||||||
id: self.id
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
$phototools.find('.upload').on('click', function() {
|
$phototools.find('.upload').on('click', function() {
|
||||||
$(document).trigger('request.select.contactphoto.fromlocal', {
|
$(document).trigger('request.select.contactphoto.fromlocal', self.metaData());
|
||||||
id: self.id
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
if(this.data && this.data.PHOTO) {
|
if(this.data && this.data.PHOTO) {
|
||||||
$phototools.find('.delete').show();
|
$phototools.find('.delete').show();
|
||||||
@ -1211,11 +1456,11 @@ OC.Contacts = OC.Contacts || {};
|
|||||||
$phototools.find('.delete').hide();
|
$phototools.find('.delete').hide();
|
||||||
$phototools.find('.edit').hide();
|
$phototools.find('.edit').hide();
|
||||||
}
|
}
|
||||||
$(document).bind('status.contact.photoupdated', function(e, result) {
|
$(document).bind('status.contact.photoupdated', function(e, data) {
|
||||||
|
console.log('status.contact.photoupdated', data);
|
||||||
self.loadPhoto(true);
|
self.loadPhoto(true);
|
||||||
var refreshstr = '&refresh='+Math.random();
|
self.data.thumbnail = data.thumbnail;
|
||||||
self.getListItemElement().find('td.name')
|
self.setThumbnail(null, true);
|
||||||
.css('background', 'url(' + OC.filePath('', '', 'remote.php')+'/contactthumbnail?id='+self.id+refreshstr + ')');
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -1346,12 +1591,14 @@ OC.Contacts = OC.Contacts || {};
|
|||||||
};
|
};
|
||||||
|
|
||||||
Contact.prototype.next = function() {
|
Contact.prototype.next = function() {
|
||||||
var $next = this.$listelem.next('tr:visible');
|
// This used to work..?
|
||||||
|
//var $next = this.$listelem.next('tr:visible');
|
||||||
|
var $next = this.$listelem.nextAll('tr').filter(':visible').first();
|
||||||
if($next.length > 0) {
|
if($next.length > 0) {
|
||||||
this.$listelem.removeClass('active');
|
this.$listelem.removeClass('active');
|
||||||
$next.addClass('active');
|
$next.addClass('active');
|
||||||
$(document).trigger('status.contact.currentlistitem', {
|
$(document).trigger('status.contact.currentlistitem', {
|
||||||
id: parseInt($next.data('id')),
|
id: String($next.data('id')),
|
||||||
pos: Math.round($next.position().top),
|
pos: Math.round($next.position().top),
|
||||||
height: Math.round($next.height())
|
height: Math.round($next.height())
|
||||||
});
|
});
|
||||||
@ -1359,12 +1606,13 @@ OC.Contacts = OC.Contacts || {};
|
|||||||
};
|
};
|
||||||
|
|
||||||
Contact.prototype.prev = function() {
|
Contact.prototype.prev = function() {
|
||||||
var $prev = this.$listelem.prev('tr:visible');
|
//var $prev = this.$listelem.prev('tr:visible');
|
||||||
|
var $prev = this.$listelem.prevAll('tr').filter(':visible').first();
|
||||||
if($prev.length > 0) {
|
if($prev.length > 0) {
|
||||||
this.$listelem.removeClass('active');
|
this.$listelem.removeClass('active');
|
||||||
$prev.addClass('active');
|
$prev.addClass('active');
|
||||||
$(document).trigger('status.contact.currentlistitem', {
|
$(document).trigger('status.contact.currentlistitem', {
|
||||||
id: parseInt($prev.data('id')),
|
id: String($prev.data('id')),
|
||||||
pos: Math.round($prev.position().top),
|
pos: Math.round($prev.position().top),
|
||||||
height: Math.round($prev.height())
|
height: Math.round($prev.height())
|
||||||
});
|
});
|
||||||
@ -1372,6 +1620,7 @@ OC.Contacts = OC.Contacts || {};
|
|||||||
};
|
};
|
||||||
|
|
||||||
var ContactList = function(
|
var ContactList = function(
|
||||||
|
storage,
|
||||||
contactlist,
|
contactlist,
|
||||||
contactlistitemtemplate,
|
contactlistitemtemplate,
|
||||||
contactdragitemtemplate,
|
contactdragitemtemplate,
|
||||||
@ -1382,17 +1631,19 @@ OC.Contacts = OC.Contacts || {};
|
|||||||
var self = this;
|
var self = this;
|
||||||
this.length = 0;
|
this.length = 0;
|
||||||
this.contacts = {};
|
this.contacts = {};
|
||||||
|
this.addressbooks = {};
|
||||||
this.deletionQueue = [];
|
this.deletionQueue = [];
|
||||||
|
this.storage = storage;
|
||||||
this.$contactList = contactlist;
|
this.$contactList = contactlist;
|
||||||
this.$contactDragItemTemplate = contactdragitemtemplate;
|
this.$contactDragItemTemplate = contactdragitemtemplate;
|
||||||
this.$contactListItemTemplate = contactlistitemtemplate;
|
this.$contactListItemTemplate = contactlistitemtemplate;
|
||||||
this.$contactFullTemplate = contactfulltemplate;
|
this.$contactFullTemplate = contactfulltemplate;
|
||||||
this.contactDetailTemplates = contactdetailtemplates;
|
this.contactDetailTemplates = contactdetailtemplates;
|
||||||
this.$contactList.scrollTop(0);
|
this.$contactList.scrollTop(0);
|
||||||
this.loadContacts(0);
|
this.getAddressBooks();
|
||||||
$(document).bind('status.contact.added', function(e, data) {
|
$(document).bind('status.contact.added', function(e, data) {
|
||||||
self.length += 1;
|
self.length += 1;
|
||||||
self.contacts[parseInt(data.id)] = data.contact;
|
self.contacts[String(data.id)] = data.contact;
|
||||||
self.insertContact(data.contact.renderListItem(true));
|
self.insertContact(data.contact.renderListItem(true));
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -1404,6 +1655,14 @@ OC.Contacts = OC.Contacts || {};
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the number of contacts in the list
|
||||||
|
* @return integer
|
||||||
|
*/
|
||||||
|
ContactList.prototype.count = function() {
|
||||||
|
return Object.keys(this.contacts.contacts).length
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show/hide contacts belonging to an addressbook.
|
* Show/hide contacts belonging to an addressbook.
|
||||||
* @param int aid. Addressbook id.
|
* @param int aid. Addressbook id.
|
||||||
@ -1412,9 +1671,9 @@ OC.Contacts = OC.Contacts || {};
|
|||||||
*/
|
*/
|
||||||
ContactList.prototype.showFromAddressbook = function(aid, show, hideothers) {
|
ContactList.prototype.showFromAddressbook = function(aid, show, hideothers) {
|
||||||
console.log('ContactList.showFromAddressbook', aid, show);
|
console.log('ContactList.showFromAddressbook', aid, show);
|
||||||
aid = parseInt(aid);
|
aid = String(aid);
|
||||||
for(var contact in this.contacts) {
|
for(var contact in this.contacts) {
|
||||||
if(this.contacts[contact].access.id === aid) {
|
if(this.contacts[contact].metadata.parent === aid) {
|
||||||
this.contacts[contact].getListItemElement().toggle(show);
|
this.contacts[contact].getListItemElement().toggle(show);
|
||||||
} else if(hideothers) {
|
} else if(hideothers) {
|
||||||
this.contacts[contact].getListItemElement().hide();
|
this.contacts[contact].getListItemElement().hide();
|
||||||
@ -1429,7 +1688,7 @@ OC.Contacts = OC.Contacts || {};
|
|||||||
ContactList.prototype.showSharedAddressbooks = function(show) {
|
ContactList.prototype.showSharedAddressbooks = function(show) {
|
||||||
console.log('ContactList.showSharedAddressbooks', show);
|
console.log('ContactList.showSharedAddressbooks', show);
|
||||||
for(var contact in this.contacts) {
|
for(var contact in this.contacts) {
|
||||||
if(this.contacts[contact].access.owner !== OC.currentUser) {
|
if(this.contacts[contact].metadata.owner !== OC.currentUser) {
|
||||||
if(show) {
|
if(show) {
|
||||||
this.contacts[contact].getListItemElement().show();
|
this.contacts[contact].getListItemElement().show();
|
||||||
} else {
|
} else {
|
||||||
@ -1444,6 +1703,8 @@ OC.Contacts = OC.Contacts || {};
|
|||||||
* @param Array contacts. A list of contact ids.
|
* @param Array contacts. A list of contact ids.
|
||||||
*/
|
*/
|
||||||
ContactList.prototype.showContacts = function(contacts) {
|
ContactList.prototype.showContacts = function(contacts) {
|
||||||
|
console.log('showContacts', contacts);
|
||||||
|
var self = this;
|
||||||
if(contacts.length === 0) {
|
if(contacts.length === 0) {
|
||||||
// ~5 times faster
|
// ~5 times faster
|
||||||
$('tr:visible.contact').hide();
|
$('tr:visible.contact').hide();
|
||||||
@ -1451,7 +1712,16 @@ OC.Contacts = OC.Contacts || {};
|
|||||||
}
|
}
|
||||||
if(contacts === 'all') {
|
if(contacts === 'all') {
|
||||||
// ~2 times faster
|
// ~2 times faster
|
||||||
$('tr.contact:not(:visible)').show();
|
var $elems = $('tr.contact:not(:visible)');
|
||||||
|
$elems.show();
|
||||||
|
$.each($elems, function(idx, elem) {
|
||||||
|
try {
|
||||||
|
var id = $(elem).data('id');
|
||||||
|
self.contacts[id].setThumbnail();
|
||||||
|
} catch(e) {
|
||||||
|
console.warn('Failed getting id from', $elem, e);
|
||||||
|
}
|
||||||
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for(var id in this.contacts) {
|
for(var id in this.contacts) {
|
||||||
@ -1459,10 +1729,11 @@ OC.Contacts = OC.Contacts || {};
|
|||||||
if(contact === null) {
|
if(contact === null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if(contacts.indexOf(parseInt(id)) === -1) {
|
if(contacts.indexOf(String(id)) === -1) {
|
||||||
contact.getListItemElement().hide();
|
contact.getListItemElement().hide();
|
||||||
} else {
|
} else {
|
||||||
contact.getListItemElement().show();
|
contact.getListItemElement().show();
|
||||||
|
contact.setThumbnail();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -1503,34 +1774,54 @@ OC.Contacts = OC.Contacts || {};
|
|||||||
*/
|
*/
|
||||||
ContactList.prototype.findById = function(id) {
|
ContactList.prototype.findById = function(id) {
|
||||||
if(!id) {
|
if(!id) {
|
||||||
console.warn('id missing');
|
console.warn('ContactList.findById: id missing');
|
||||||
console.trace();
|
console.trace();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
id = parseInt(id);
|
id = String(id);
|
||||||
if(typeof this.contacts[id] === 'undefined') {
|
if(typeof this.contacts[id] === 'undefined') {
|
||||||
console.warn('Could not find contact with id', id);
|
console.warn('Could not find contact with id', id);
|
||||||
console.trace();
|
console.trace();
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return this.contacts[parseInt(id)];
|
return this.contacts[String(id)];
|
||||||
};
|
};
|
||||||
|
|
||||||
ContactList.prototype.delayedDelete = function(id) {
|
/**
|
||||||
|
* @param object data An object or array of objects containing contact identification
|
||||||
|
* {
|
||||||
|
* contactid: '1234',
|
||||||
|
* addressbookid: '4321',
|
||||||
|
* backend: 'local'
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
ContactList.prototype.delayedDelete = function(data) {
|
||||||
|
console.log('delayedDelete, data:', typeof data, data);
|
||||||
var self = this;
|
var self = this;
|
||||||
if(utils.isUInt(id)) {
|
if(!utils.isArray(data)) {
|
||||||
this.currentContact = null;
|
this.currentContact = null;
|
||||||
self.$contactList.show();
|
//self.$contactList.show();
|
||||||
this.deletionQueue.push(id);
|
if(data instanceof Contact) {
|
||||||
} else if(utils.isArray(id)) {
|
this.deletionQueue.push(data);
|
||||||
$.extend(this.deletionQueue, id);
|
} else {
|
||||||
|
var contact = this.findById(data.contactid);
|
||||||
|
this.deletionQueue.push(contact);
|
||||||
|
}
|
||||||
|
} else if(utils.isArray(data)) {
|
||||||
|
$.each(data, function(idx, contact) {
|
||||||
|
//console.log('delayedDelete, meta:', contact);
|
||||||
|
self.deletionQueue.push(contact);
|
||||||
|
});
|
||||||
|
//$.extend(this.deletionQueue, data);
|
||||||
} else {
|
} else {
|
||||||
throw { name: 'WrongParameterType', message: 'ContactList.delayedDelete only accept integers or arrays.'};
|
throw { name: 'WrongParameterType', message: 'ContactList.delayedDelete only accept objects or arrays.'};
|
||||||
}
|
}
|
||||||
$.each(this.deletionQueue, function(idx, id) {
|
//console.log('delayedDelete, deletionQueue', this.deletionQueue);
|
||||||
self.contacts[id].detach().setChecked(false);
|
$.each(this.deletionQueue, function(idx, contact) {
|
||||||
|
//console.log('delayedDelete', contact);
|
||||||
|
contact.detach().setChecked(false);
|
||||||
});
|
});
|
||||||
console.log('deletionQueue', this.deletionQueue);
|
//console.log('deletionQueue', this.deletionQueue);
|
||||||
if(!window.onbeforeunload) {
|
if(!window.onbeforeunload) {
|
||||||
window.onbeforeunload = function(e) {
|
window.onbeforeunload = function(e) {
|
||||||
e = e || window.event;
|
e = e || window.event;
|
||||||
@ -1548,16 +1839,16 @@ OC.Contacts = OC.Contacts || {};
|
|||||||
message:t('contacts','Click to undo deletion of {num} contacts', {num: self.deletionQueue.length}),
|
message:t('contacts','Click to undo deletion of {num} contacts', {num: self.deletionQueue.length}),
|
||||||
//timeout:5,
|
//timeout:5,
|
||||||
timeouthandler:function() {
|
timeouthandler:function() {
|
||||||
console.log('timeout');
|
//console.log('timeout');
|
||||||
// Don't fire all deletes at once
|
// Don't fire all deletes at once
|
||||||
self.deletionTimer = setInterval(function() {
|
self.deletionTimer = setInterval(function() {
|
||||||
self.deleteContacts();
|
self.deleteContacts();
|
||||||
}, 500);
|
}, 500);
|
||||||
},
|
},
|
||||||
clickhandler:function() {
|
clickhandler:function() {
|
||||||
console.log('clickhandler');
|
//console.log('clickhandler');
|
||||||
$.each(self.deletionQueue, function(idx, id) {
|
$.each(self.deletionQueue, function(idx, contact) {
|
||||||
self.insertContact(self.contacts[id].getListItemElement());
|
self.insertContact(contact.getListItemElement());
|
||||||
});
|
});
|
||||||
OC.notify({cancel:true});
|
OC.notify({cancel:true});
|
||||||
OC.notify({message:t('contacts', 'Cancelled deletion of {num}', {num: self.deletionQueue.length})});
|
OC.notify({message:t('contacts', 'Cancelled deletion of {num}', {num: self.deletionQueue.length})});
|
||||||
@ -1568,20 +1859,19 @@ OC.Contacts = OC.Contacts || {};
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete a contact with this id
|
* Delete contacts in the queue
|
||||||
* @param id the id of the contact
|
|
||||||
*/
|
*/
|
||||||
ContactList.prototype.deleteContacts = function() {
|
ContactList.prototype.deleteContacts = function() {
|
||||||
var self = this;
|
var self = this;
|
||||||
console.log('ContactList.deleteContacts, deletionQueue', this.deletionQueue);
|
//console.log('ContactList.deleteContacts, deletionQueue', this.deletionQueue);
|
||||||
if(typeof this.deletionTimer === 'undefined') {
|
if(typeof this.deletionTimer === 'undefined') {
|
||||||
console.log('No deletion timer!');
|
console.log('No deletion timer!');
|
||||||
window.onbeforeunload = null;
|
window.onbeforeunload = null;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var id = this.deletionQueue.shift();
|
var contact = this.deletionQueue.shift();
|
||||||
if(typeof id === 'undefined') {
|
if(typeof contact === 'undefined') {
|
||||||
clearInterval(this.deletionTimer);
|
clearInterval(this.deletionTimer);
|
||||||
delete this.deletionTimer;
|
delete this.deletionTimer;
|
||||||
window.onbeforeunload = null;
|
window.onbeforeunload = null;
|
||||||
@ -1589,13 +1879,10 @@ OC.Contacts = OC.Contacts || {};
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Let contact remove itself.
|
// Let contact remove itself.
|
||||||
var contact = this.findById(id);
|
var id = contact.getId();
|
||||||
if(contact === null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
contact.destroy(function(response) {
|
contact.destroy(function(response) {
|
||||||
console.log('deleteContact', response, self.length);
|
console.log('deleteContact', response, self.length);
|
||||||
if(response.status === 'success') {
|
if(!response.error) {
|
||||||
delete self.contacts[id];
|
delete self.contacts[id];
|
||||||
$(document).trigger('status.contact.deleted', {
|
$(document).trigger('status.contact.deleted', {
|
||||||
id: id
|
id: id
|
||||||
@ -1661,10 +1948,17 @@ OC.Contacts = OC.Contacts || {};
|
|||||||
* @param object props
|
* @param object props
|
||||||
*/
|
*/
|
||||||
ContactList.prototype.addContact = function(props) {
|
ContactList.prototype.addContact = function(props) {
|
||||||
|
var addressBook = this.addressbooks[Object.keys(this.addressbooks)[0]]
|
||||||
|
var metadata = {
|
||||||
|
parent: addressBook.id,
|
||||||
|
backend: addressBook.backend,
|
||||||
|
permissions: addressBook.permissions,
|
||||||
|
owner: addressBook.owner
|
||||||
|
};
|
||||||
var contact = new Contact(
|
var contact = new Contact(
|
||||||
this,
|
this,
|
||||||
null,
|
null,
|
||||||
{owner:OC.currentUser, permissions: 31},
|
metadata,
|
||||||
null,
|
null,
|
||||||
this.$contactListItemTemplate,
|
this.$contactListItemTemplate,
|
||||||
this.$contactDragItemTemplate,
|
this.$contactDragItemTemplate,
|
||||||
@ -1672,7 +1966,6 @@ OC.Contacts = OC.Contacts || {};
|
|||||||
this.contactDetailTemplates
|
this.contactDetailTemplates
|
||||||
);
|
);
|
||||||
if(utils.isUInt(this.currentContact)) {
|
if(utils.isUInt(this.currentContact)) {
|
||||||
console.assert(typeof this.currentContact == 'number', 'this.currentContact is not a number');
|
|
||||||
this.contacts[this.currentContact].close();
|
this.contacts[this.currentContact].close();
|
||||||
}
|
}
|
||||||
return contact.renderContact(props);
|
return contact.renderContact(props);
|
||||||
@ -1681,13 +1974,15 @@ OC.Contacts = OC.Contacts || {};
|
|||||||
/**
|
/**
|
||||||
* Get contacts selected in list
|
* Get contacts selected in list
|
||||||
*
|
*
|
||||||
* @returns array of integer contact ids.
|
* @returns array of contact ids.
|
||||||
*/
|
*/
|
||||||
ContactList.prototype.getSelectedContacts = function() {
|
ContactList.prototype.getSelectedContacts = function() {
|
||||||
var contacts = [];
|
var contacts = [];
|
||||||
|
|
||||||
|
var self = this;
|
||||||
$.each(this.$contactList.find('tr > td > input:checkbox:visible:checked'), function(a, b) {
|
$.each(this.$contactList.find('tr > td > input:checkbox:visible:checked'), function(a, b) {
|
||||||
contacts.push(parseInt($(b).parents('tr').first().data('id')));
|
var id = String($(b).parents('tr').first().data('id'));
|
||||||
|
contacts.push(self.contacts[id]);
|
||||||
});
|
});
|
||||||
return contacts;
|
return contacts;
|
||||||
};
|
};
|
||||||
@ -1703,7 +1998,7 @@ OC.Contacts = OC.Contacts || {};
|
|||||||
self.contacts[contact].setCurrent(false);
|
self.contacts[contact].setCurrent(false);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
this.contacts[parseInt(id)].setCurrent(true);
|
this.contacts[String(id)].setCurrent(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Should only be neccesary with progressive loading, but it's damn fast, so... ;)
|
// Should only be neccesary with progressive loading, but it's damn fast, so... ;)
|
||||||
@ -1715,6 +2010,7 @@ OC.Contacts = OC.Contacts || {};
|
|||||||
return $(a).find('td.name').text().toUpperCase().localeCompare($(b).find('td.name').text().toUpperCase());
|
return $(a).find('td.name').text().toUpperCase().localeCompare($(b).find('td.name').text().toUpperCase());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// TODO: Test if I couldn't just append rows.
|
||||||
var items = [];
|
var items = [];
|
||||||
$.each(rows, function(index, row) {
|
$.each(rows, function(index, row) {
|
||||||
items.push(row);
|
items.push(row);
|
||||||
@ -1741,40 +2037,88 @@ OC.Contacts = OC.Contacts || {};
|
|||||||
* @param object book
|
* @param object book
|
||||||
*/
|
*/
|
||||||
ContactList.prototype.setAddressbook = function(book) {
|
ContactList.prototype.setAddressbook = function(book) {
|
||||||
this.addressbooks[parseInt(book.id)] = {
|
console.log('setAddressbook', book.id, this.addressbooks);
|
||||||
owner: book.userid,
|
var id = String(book.id);
|
||||||
uri: book.uri,
|
this.addressbooks[id] = book;
|
||||||
permissions: parseInt(book.permissions),
|
|
||||||
id: parseInt(book.id),
|
|
||||||
displayname: book.displayname,
|
|
||||||
description: book.description,
|
|
||||||
active: Boolean(parseInt(book.active))
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load contacts
|
* Load contacts
|
||||||
* @param int offset
|
* @param int offset
|
||||||
*/
|
*/
|
||||||
ContactList.prototype.loadContacts = function(offset, cb) {
|
ContactList.prototype.getAddressBooks = function() {
|
||||||
var self = this;
|
var self = this;
|
||||||
// Should the actual ajax call be in the controller?
|
$.when(this.storage.getAddressBooksForUser()).then(function(response) {
|
||||||
$.getJSON(OC.filePath('contacts', 'ajax', 'contact/list.php'), {offset: offset}, function(jsondata) {
|
console.log('ContactList.getAddressBooks', response);
|
||||||
if (jsondata && jsondata.status == 'success') {
|
if(!response.error) {
|
||||||
//console.log('ContactList.loadContacts', jsondata.data);
|
var num = response.data.addressbooks.length;
|
||||||
self.addressbooks = {};
|
$.each(response.data.addressbooks, function(idx, addressBook) {
|
||||||
$.each(jsondata.data.addressbooks, function(i, book) {
|
self.setAddressbook(addressBook);
|
||||||
self.setAddressbook(book);
|
self.loadContacts(
|
||||||
|
addressBook['backend'],
|
||||||
|
addressBook['id'],
|
||||||
|
function(cbresponse) {
|
||||||
|
//console.log('loaded', idx, cbresponse);
|
||||||
|
num -= 1;
|
||||||
|
if(num === 0) {
|
||||||
|
if(self.length > 0) {
|
||||||
|
setTimeout(function() {
|
||||||
|
self.doSort(); // TODO: Test this
|
||||||
|
self.setCurrent(self.$contactList.find('tr:visible').first().data('id'), false);
|
||||||
|
}
|
||||||
|
, 2000);
|
||||||
|
}
|
||||||
|
$(document).trigger('status.contacts.loaded', {
|
||||||
|
status: true,
|
||||||
|
numcontacts: self.length
|
||||||
|
});
|
||||||
|
if(self.length === 0) {
|
||||||
|
$(document).trigger('status.nomorecontacts');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(cbresponse.error) {
|
||||||
|
$(document).trigger('status.contact.error', {
|
||||||
|
message:
|
||||||
|
t('contacts', 'Failed loading contacts from {addressbook}: {error}',
|
||||||
|
{addressbook:addressBook['displayname'], error:err})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
$(document).trigger('status.contact.error', {
|
||||||
|
message: response.message
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.fail(function(jqxhr, textStatus, error) {
|
||||||
|
var err = textStatus + ', ' + error;
|
||||||
|
console.warn( "Request Failed: " + err);
|
||||||
|
$(document).trigger('status.contact.error', {
|
||||||
|
message: t('contacts', 'Failed loading address books: {error}', {error:err})
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load contacts
|
||||||
|
* @param int offset
|
||||||
|
*/
|
||||||
|
ContactList.prototype.loadContacts = function(backend, addressBookId, cb) {
|
||||||
|
var self = this;
|
||||||
|
$.when(this.storage.getContacts(backend, addressBookId)).then(function(response) {
|
||||||
|
//console.log('ContactList.loadContacts', response);
|
||||||
|
if(!response.error) {
|
||||||
var items = [];
|
var items = [];
|
||||||
if(jsondata.data.contacts.length === 0) {
|
$.each(response.data.contacts, function(c, contact) {
|
||||||
$(document).trigger('status.nomorecontacts');
|
var id = String(contact.metadata.id);
|
||||||
}
|
contact.metadata.backend = backend;
|
||||||
$.each(jsondata.data.contacts, function(c, contact) {
|
self.contacts[id]
|
||||||
self.contacts[parseInt(contact.id)]
|
|
||||||
= new Contact(
|
= new Contact(
|
||||||
self,
|
self,
|
||||||
parseInt(contact.id),
|
id,
|
||||||
self.addressbooks[parseInt(contact.aid)],
|
contact.metadata,
|
||||||
contact.data,
|
contact.data,
|
||||||
self.$contactListItemTemplate,
|
self.$contactListItemTemplate,
|
||||||
self.$contactDragItemTemplate,
|
self.$contactDragItemTemplate,
|
||||||
@ -1782,14 +2126,14 @@ OC.Contacts = OC.Contacts || {};
|
|||||||
self.contactDetailTemplates
|
self.contactDetailTemplates
|
||||||
);
|
);
|
||||||
self.length +=1;
|
self.length +=1;
|
||||||
var $item = self.contacts[parseInt(contact.id)].renderListItem();
|
var $item = self.contacts[id].renderListItem();
|
||||||
items.push($item.get(0));
|
items.push($item.get(0));
|
||||||
$item.find('td.name').draggable({
|
$item.find('td.name').draggable({
|
||||||
cursor: 'move',
|
cursor: 'move',
|
||||||
distance: 10,
|
distance: 10,
|
||||||
revert: 'invalid',
|
revert: 'invalid',
|
||||||
helper: function (e,ui) {
|
helper: function (e,ui) {
|
||||||
return self.contacts[parseInt(contact.id)].renderDragItem().appendTo('body');
|
return self.contacts[id].renderDragItem().appendTo('body');
|
||||||
},
|
},
|
||||||
opacity: 1,
|
opacity: 1,
|
||||||
scope: 'contacts'
|
scope: 'contacts'
|
||||||
@ -1802,22 +2146,24 @@ OC.Contacts = OC.Contacts || {};
|
|||||||
if(items.length > 0) {
|
if(items.length > 0) {
|
||||||
self.$contactList.append(items);
|
self.$contactList.append(items);
|
||||||
}
|
}
|
||||||
setTimeout(function() {
|
cb({error:false});
|
||||||
self.doSort();
|
} else {
|
||||||
self.setCurrent(self.$contactList.find('tr:visible:first-child').data('id'), false);
|
$(document).trigger('status.contact.error', {
|
||||||
}
|
message: response.message
|
||||||
, 2000);
|
});
|
||||||
$(document).trigger('status.contacts.loaded', {
|
cb({
|
||||||
status: true,
|
error:true,
|
||||||
numcontacts: jsondata.data.contacts.length,
|
message: response.message
|
||||||
is_indexed: jsondata.data.is_indexed
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if(typeof cb === 'function') {
|
})
|
||||||
cb();
|
.fail(function(jqxhr, textStatus, error) {
|
||||||
}
|
var err = textStatus + ', ' + error;
|
||||||
|
console.warn( "Request Failed: " + err);
|
||||||
|
cb({error: true, message: err});
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
OC.Contacts.ContactList = ContactList;
|
OC.Contacts.ContactList = ContactList;
|
||||||
|
|
||||||
})(window, jQuery, OC);
|
})(window, jQuery, OC);
|
||||||
|
103
js/groups.js
103
js/groups.js
@ -16,7 +16,8 @@ OC.Contacts = OC.Contacts || {};
|
|||||||
* 'contacts': An array of contact ids belonging to that group
|
* 'contacts': An array of contact ids belonging to that group
|
||||||
* 'obj': A reference to the groupList object.
|
* 'obj': A reference to the groupList object.
|
||||||
*/
|
*/
|
||||||
var GroupList = function(groupList, listItemTmpl) {
|
var GroupList = function(storage, groupList, listItemTmpl) {
|
||||||
|
this.storage = storage;
|
||||||
this.$groupList = groupList;
|
this.$groupList = groupList;
|
||||||
var self = this;
|
var self = this;
|
||||||
var numtypes = ['category', 'fav', 'all'];
|
var numtypes = ['category', 'fav', 'all'];
|
||||||
@ -29,7 +30,7 @@ OC.Contacts = OC.Contacts || {};
|
|||||||
if($(event.target).is('.action.delete')) {
|
if($(event.target).is('.action.delete')) {
|
||||||
var id = $(event.target).parents('h3').first().data('id');
|
var id = $(event.target).parents('h3').first().data('id');
|
||||||
self.deleteGroup(id, function(response) {
|
self.deleteGroup(id, function(response) {
|
||||||
if(response.status !== 'success') {
|
if(response.error) {
|
||||||
OC.notify({message:response.data.message});
|
OC.notify({message:response.data.message});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -129,7 +130,6 @@ OC.Contacts = OC.Contacts || {};
|
|||||||
* @param function cb. Optional callback function.
|
* @param function cb. Optional callback function.
|
||||||
*/
|
*/
|
||||||
GroupList.prototype.setAsFavorite = function(contactid, state, cb) {
|
GroupList.prototype.setAsFavorite = function(contactid, state, cb) {
|
||||||
contactid = parseInt(contactid);
|
|
||||||
var $groupelem = this.findById('fav');
|
var $groupelem = this.findById('fav');
|
||||||
var contacts = $groupelem.data('contacts');
|
var contacts = $groupelem.data('contacts');
|
||||||
if(state) {
|
if(state) {
|
||||||
@ -185,7 +185,7 @@ OC.Contacts = OC.Contacts || {};
|
|||||||
}
|
}
|
||||||
var self = this;
|
var self = this;
|
||||||
var doPost = false;
|
var doPost = false;
|
||||||
if(typeof contactid === 'number') {
|
if(typeof contactid === 'string') {
|
||||||
if(contacts.indexOf(contactid) === -1) {
|
if(contacts.indexOf(contactid) === -1) {
|
||||||
ids.push(contactid);
|
ids.push(contactid);
|
||||||
doPost = true;
|
doPost = true;
|
||||||
@ -211,14 +211,8 @@ OC.Contacts = OC.Contacts || {};
|
|||||||
console.warn('Invalid data type: ' + typeof contactid);
|
console.warn('Invalid data type: ' + typeof contactid);
|
||||||
}
|
}
|
||||||
if(doPost) {
|
if(doPost) {
|
||||||
$.post(OC.filePath('contacts', 'ajax', 'categories/addto.php'), {contactids: ids, categoryid: groupid},function(jsondata) {
|
$.when(this.storage.addToGroup(ids, groupid)).then(function(response) {
|
||||||
if(!jsondata) {
|
if(!response.error) {
|
||||||
if(typeof cb === 'function') {
|
|
||||||
cb({status:'error', message:'Network or server error. Please inform administrator.'});
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(jsondata.status === 'success') {
|
|
||||||
contacts = contacts.concat(ids).sort();
|
contacts = contacts.concat(ids).sort();
|
||||||
$groupelem.data('contacts', contacts);
|
$groupelem.data('contacts', contacts);
|
||||||
var $numelem = $groupelem.find('.numcontacts');
|
var $numelem = $groupelem.find('.numcontacts');
|
||||||
@ -237,7 +231,7 @@ OC.Contacts = OC.Contacts || {};
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if(typeof cb == 'function') {
|
if(typeof cb == 'function') {
|
||||||
cb({status:'error', message:jsondata.data.message});
|
cb({status:'error', message:response.message});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -300,14 +294,8 @@ OC.Contacts = OC.Contacts || {};
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(doPost) {
|
if(doPost) {
|
||||||
$.post(OC.filePath('contacts', 'ajax', 'categories/removefrom.php'), {contactids: ids, categoryid: groupid},function(jsondata) {
|
$.when(this.storage.removeFromGroup(ids, groupid)).then(function(response) {
|
||||||
if(!jsondata) {
|
if(!response.error) {
|
||||||
if(typeof cb === 'function') {
|
|
||||||
cb({status:'error', message:'Network or server error. Please inform administrator.'});
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(jsondata.status === 'success') {
|
|
||||||
$.each(ids, function(idx, id) {
|
$.each(ids, function(idx, id) {
|
||||||
contacts.splice(contacts.indexOf(id), 1);
|
contacts.splice(contacts.indexOf(id), 1);
|
||||||
});
|
});
|
||||||
@ -323,7 +311,7 @@ OC.Contacts = OC.Contacts || {};
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if(typeof cb == 'function') {
|
if(typeof cb == 'function') {
|
||||||
cb({status:'error', message:jsondata.data.message});
|
cb({status:'error', message:response.message});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -363,7 +351,7 @@ OC.Contacts = OC.Contacts || {};
|
|||||||
var dragitem = ui.draggable, droptarget = $(this);
|
var dragitem = ui.draggable, droptarget = $(this);
|
||||||
console.log('dropped', dragitem);
|
console.log('dropped', dragitem);
|
||||||
if(dragitem.is('.name')) {
|
if(dragitem.is('.name')) {
|
||||||
var id = dragitem.parent().data('id');
|
var id = String(dragitem.parent().data('id'));
|
||||||
console.log('contact dropped', id, 'on', $(this).data('id'));
|
console.log('contact dropped', id, 'on', $(this).data('id'));
|
||||||
if($(this).data('type') === 'fav') {
|
if($(this).data('type') === 'fav') {
|
||||||
$(this).data('obj').setAsFavorite(id, true);
|
$(this).data('obj').setAsFavorite(id, true);
|
||||||
@ -397,22 +385,35 @@ OC.Contacts = OC.Contacts || {};
|
|||||||
var contacts = $elem.data('contacts');
|
var contacts = $elem.data('contacts');
|
||||||
var self = this;
|
var self = this;
|
||||||
console.log('delete group', groupid, contacts);
|
console.log('delete group', groupid, contacts);
|
||||||
$.post(OC.filePath('contacts', 'ajax', 'categories/delete.php'), {categories: name}, function(jsondata) {
|
$.when(this.storage.deleteGroup(name)).then(function(response) {
|
||||||
if (jsondata && jsondata.status == 'success') {
|
if (!response.error) {
|
||||||
|
$.each(self.categories, function(idx, category) {
|
||||||
|
if(category.id === groupid) {
|
||||||
|
self.categories.splice(self.categories.indexOf(category), 1);
|
||||||
|
return false; // Break loop
|
||||||
|
}
|
||||||
|
});
|
||||||
$(document).trigger('status.group.groupremoved', {
|
$(document).trigger('status.group.groupremoved', {
|
||||||
groupid: groupid,
|
groupid: groupid,
|
||||||
newgroupid: parseInt($newelem.data('id')),
|
newgroupid: parseInt($newelem.data('id')),
|
||||||
groupname: self.nameById(groupid),
|
groupname: name,
|
||||||
contacts: contacts
|
contacts: contacts
|
||||||
});
|
});
|
||||||
$elem.remove();
|
$elem.remove();
|
||||||
self.selectGroup({element:$newelem});
|
self.selectGroup({element:$newelem});
|
||||||
} else {
|
} else {
|
||||||
//
|
console.log('Error', response);
|
||||||
}
|
}
|
||||||
if(typeof cb === 'function') {
|
if(typeof cb === 'function') {
|
||||||
cb(jsondata);
|
cb(response);
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
.fail(function(jqxhr, textStatus, error) {
|
||||||
|
var err = textStatus + ', ' + error;
|
||||||
|
console.log( "Request Failed: " + err);
|
||||||
|
$(document).trigger('status.contact.error', {
|
||||||
|
message: t('contacts', 'Failed deleting group: {error}', {error:err})
|
||||||
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -441,7 +442,7 @@ OC.Contacts = OC.Contacts || {};
|
|||||||
$input.prop('disabled', true);
|
$input.prop('disabled', true);
|
||||||
$elem.data('rawname', '');
|
$elem.data('rawname', '');
|
||||||
self.addGroup({name:name, element: $elem}, function(response) {
|
self.addGroup({name:name, element: $elem}, function(response) {
|
||||||
if(response.status === 'success') {
|
if(!response.error) {
|
||||||
$elem.prepend(escapeHTML(response.name)).removeClass('editing').attr('data-id', response.id);
|
$elem.prepend(escapeHTML(response.name)).removeClass('editing').attr('data-id', response.id);
|
||||||
$input.next('.checked').remove();
|
$input.next('.checked').remove();
|
||||||
$input.remove();
|
$input.remove();
|
||||||
@ -545,10 +546,10 @@ OC.Contacts = OC.Contacts || {};
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$.post(OC.filePath('contacts', 'ajax', 'categories/add.php'), {category: name}, function(jsondata) {
|
$.when(this.storage.addGroup(name)).then(function(response) {
|
||||||
if (jsondata && jsondata.status == 'success') {
|
if (!response.error) {
|
||||||
name = jsondata.data.name;
|
name = response.data.name;
|
||||||
var id = jsondata.data.id;
|
var id = response.data.id;
|
||||||
var tmpl = self.$groupListItemTemplate;
|
var tmpl = self.$groupListItemTemplate;
|
||||||
var $elem = params.element
|
var $elem = params.element
|
||||||
? params.element
|
? params.element
|
||||||
@ -578,13 +579,20 @@ OC.Contacts = OC.Contacts || {};
|
|||||||
$elem.tipsy({trigger:'manual', gravity:'w', fallback: t('contacts', 'You can drag groups to\narrange them as you like.')});
|
$elem.tipsy({trigger:'manual', gravity:'w', fallback: t('contacts', 'You can drag groups to\narrange them as you like.')});
|
||||||
$elem.tipsy('show');
|
$elem.tipsy('show');
|
||||||
if(typeof cb === 'function') {
|
if(typeof cb === 'function') {
|
||||||
cb({status:'success', id:parseInt(id), name:name});
|
cb({id:parseInt(id), name:name});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if(typeof cb === 'function') {
|
if(typeof cb === 'function') {
|
||||||
cb({status:'error', message:jsondata.data.message});
|
cb({error:true, message:response.data.message});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
.fail(function(jqxhr, textStatus, error) {
|
||||||
|
var err = textStatus + ', ' + error;
|
||||||
|
console.log( "Request Failed: " + err);
|
||||||
|
$(document).trigger('status.contact.error', {
|
||||||
|
message: t('contacts', 'Failed adding group: {error}', {error:err})
|
||||||
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -595,15 +603,14 @@ OC.Contacts = OC.Contacts || {};
|
|||||||
var tmpl = this.$groupListItemTemplate;
|
var tmpl = this.$groupListItemTemplate;
|
||||||
|
|
||||||
tmpl.octemplate({id: 'all', type: 'all', num: numcontacts, name: t('contacts', 'All')}).appendTo($groupList);
|
tmpl.octemplate({id: 'all', type: 'all', num: numcontacts, name: t('contacts', 'All')}).appendTo($groupList);
|
||||||
$.getJSON(OC.filePath('contacts', 'ajax', 'categories/list.php'), {}, function(jsondata) {
|
$.when(this.storage.getGroupsForUser()).then(function(response) {
|
||||||
if (jsondata && jsondata.status == 'success') {
|
if (response && !response.error) {
|
||||||
self.lastgroup = jsondata.data.lastgroup;
|
self.lastgroup = response.data.lastgroup;
|
||||||
self.sortorder = jsondata.data.sortorder.length > 0
|
self.sortorder = contacts_groups_sortorder;
|
||||||
? $.map(jsondata.data.sortorder.split(','), function(c) {return parseInt(c);})
|
|
||||||
: [];
|
|
||||||
console.log('sortorder', self.sortorder);
|
console.log('sortorder', self.sortorder);
|
||||||
// Favorites
|
// Favorites
|
||||||
var contacts = $.map(jsondata.data.favorites, function(c) {return parseInt(c);});
|
// Map to strings easier lookup an contacts list.
|
||||||
|
var contacts = $.map(response.data.favorites, function(c) {return String(c);});
|
||||||
var $elem = tmpl.octemplate({
|
var $elem = tmpl.octemplate({
|
||||||
id: 'fav',
|
id: 'fav',
|
||||||
type: 'fav',
|
type: 'fav',
|
||||||
@ -627,8 +634,8 @@ OC.Contacts = OC.Contacts || {};
|
|||||||
}
|
}
|
||||||
console.log('favorites', $elem.data('contacts'));
|
console.log('favorites', $elem.data('contacts'));
|
||||||
// Normal groups
|
// Normal groups
|
||||||
$.each(jsondata.data.categories, function(c, category) {
|
$.each(response.data.categories, function(c, category) {
|
||||||
var contacts = $.map(category.contacts, function(c) {return parseInt(c);});
|
var contacts = $.map(category.contacts, function(c) {return String(c);});
|
||||||
var $elem = (tmpl).octemplate({
|
var $elem = (tmpl).octemplate({
|
||||||
id: category.id,
|
id: category.id,
|
||||||
type: 'category',
|
type: 'category',
|
||||||
@ -663,13 +670,13 @@ OC.Contacts = OC.Contacts || {};
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Shared addressbook
|
// Shared addressbook
|
||||||
$.each(jsondata.data.shared, function(c, shared) {
|
$.each(response.data.shared, function(c, shared) {
|
||||||
var sharedindicator = '<img class="shared svg" src="' + OC.imagePath('core', 'actions/shared') + '"'
|
var sharedindicator = '<img class="shared svg" src="' + OC.imagePath('core', 'actions/shared') + '"'
|
||||||
+ 'title="' + t('contacts', 'Shared by {owner}', {owner:shared.userid}) + '" />';
|
+ 'title="' + t('contacts', 'Shared by {owner}', {owner:shared.userid}) + '" />';
|
||||||
var $elem = (tmpl).octemplate({
|
var $elem = (tmpl).octemplate({
|
||||||
id: shared.id,
|
id: shared.id,
|
||||||
type: 'shared',
|
type: 'shared',
|
||||||
num: '', //jsondata.data.shared.length,
|
num: response.data.shared.length,
|
||||||
name: shared.displayname
|
name: shared.displayname
|
||||||
});
|
});
|
||||||
$elem.find('.numcontacts').after(sharedindicator);
|
$elem.find('.numcontacts').after(sharedindicator);
|
||||||
@ -703,6 +710,10 @@ OC.Contacts = OC.Contacts || {};
|
|||||||
if(typeof cb === 'function') {
|
if(typeof cb === 'function') {
|
||||||
cb();
|
cb();
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
.fail(function(jqxhr, textStatus, error) {
|
||||||
|
var err = textStatus + ', ' + error;
|
||||||
|
console.log( "Request Failed: " + err);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
194
js/jquery.ocdialog.js
Normal file
194
js/jquery.ocdialog.js
Normal file
@ -0,0 +1,194 @@
|
|||||||
|
(function($) {
|
||||||
|
$.widget('oc.ocdialog', {
|
||||||
|
options: {
|
||||||
|
width: 'auto',
|
||||||
|
height: 'auto',
|
||||||
|
closeButton: true,
|
||||||
|
closeOnEscape: true
|
||||||
|
},
|
||||||
|
_create: function() {
|
||||||
|
console.log('ocdialog._create');
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
this.originalCss = {
|
||||||
|
display: this.element[0].style.display,
|
||||||
|
width: this.element[0].style.width,
|
||||||
|
height: this.element[0].style.height,
|
||||||
|
};
|
||||||
|
|
||||||
|
this.originalTitle = this.element.attr('title');
|
||||||
|
this.options.title = this.options.title || this.originalTitle;
|
||||||
|
|
||||||
|
this.$dialog = $('<div class="oc-dialog" />')
|
||||||
|
.attr({
|
||||||
|
// Setting tabIndex makes the div focusable
|
||||||
|
tabIndex: -1,
|
||||||
|
role: 'dialog'
|
||||||
|
})
|
||||||
|
.insertBefore(this.element);
|
||||||
|
this.$dialog.append(this.element.detach());
|
||||||
|
this.element.removeAttr('title').addClass('oc-dialog-content').appendTo(this.$dialog);
|
||||||
|
|
||||||
|
this.$dialog.css({
|
||||||
|
display: 'inline-block',
|
||||||
|
position: 'fixed'
|
||||||
|
});
|
||||||
|
|
||||||
|
$(document).on('keydown keyup', function(event) {
|
||||||
|
if(event.target !== self.$dialog.get(0) && self.$dialog.find($(event.target)).length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Escape
|
||||||
|
if(event.keyCode === 27 && self.options.closeOnEscape) {
|
||||||
|
self.close();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Enter
|
||||||
|
if(event.keyCode === 13) {
|
||||||
|
event.stopImmediatePropagation();
|
||||||
|
if(event.type === 'keyup') {
|
||||||
|
event.preventDefault();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// If no button is selected we trigger the primary
|
||||||
|
if(self.$buttonrow && self.$buttonrow.find($(event.target)).length === 0) {
|
||||||
|
var $button = self.$buttonrow.find('button.primary');
|
||||||
|
if($button) {
|
||||||
|
$button.trigger('click');
|
||||||
|
}
|
||||||
|
} else if(self.$buttonrow) {
|
||||||
|
$(event.target).trigger('click');
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
$(window).resize(function() {
|
||||||
|
self.parent = self.$dialog.parent().length > 0 ? self.$dialog.parent() : $('body');
|
||||||
|
var pos = self.parent.position();
|
||||||
|
self.$dialog.css({
|
||||||
|
left: pos.left + (self.parent.width() - self.$dialog.outerWidth())/2,
|
||||||
|
top: pos.top + (self.parent.height() - self.$dialog.outerHeight())/2
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
this._setOptions(this.options);
|
||||||
|
$(window).trigger('resize');
|
||||||
|
},
|
||||||
|
_init: function() {
|
||||||
|
console.log('ocdialog._init');
|
||||||
|
this.$dialog.focus();
|
||||||
|
this._trigger('open');
|
||||||
|
},
|
||||||
|
_setOption: function(key, value) {
|
||||||
|
console.log('_setOption', key, value);
|
||||||
|
var self = this;
|
||||||
|
switch(key) {
|
||||||
|
case 'title':
|
||||||
|
var $title = $('<h3 class="oc-dialog-title">' + this.options.title
|
||||||
|
+ '</h3>'); //<hr class="oc-dialog-separator" />');
|
||||||
|
if(this.$title) {
|
||||||
|
this.$title.replaceWith($title);
|
||||||
|
} else {
|
||||||
|
this.$title = $title.prependTo(this.$dialog);
|
||||||
|
}
|
||||||
|
this._setSizes();
|
||||||
|
break;
|
||||||
|
case 'buttons':
|
||||||
|
var $buttonrow = $('<div class="oc-dialog-buttonrow" />');
|
||||||
|
if(this.$buttonrow) {
|
||||||
|
this.$buttonrow.replaceWith($buttonrow);
|
||||||
|
} else {
|
||||||
|
this.$buttonrow = $buttonrow.appendTo(this.$dialog);
|
||||||
|
}
|
||||||
|
$.each(value, function(idx, val) {
|
||||||
|
var $button = $('<button>' + val.text + '</button>');
|
||||||
|
if(val.defaultButton) {
|
||||||
|
$button.addClass('primary');
|
||||||
|
self.$defaultButton = $button;
|
||||||
|
}
|
||||||
|
self.$buttonrow.append($button);
|
||||||
|
$button.click(function() {
|
||||||
|
val.click.apply(self.element[0], arguments);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
this.$buttonrow.find('button')
|
||||||
|
.on('focus', function(event) {
|
||||||
|
self.$buttonrow.find('button').removeClass('primary');
|
||||||
|
$(this).addClass('primary');
|
||||||
|
});
|
||||||
|
this._setSizes();
|
||||||
|
break;
|
||||||
|
case 'closeButton':
|
||||||
|
console.log('closeButton', value);
|
||||||
|
if(value) {
|
||||||
|
var $closeButton = $('<a class="oc-dialog-close svg"></a>');
|
||||||
|
console.log('closeButton', $closeButton);
|
||||||
|
this.$dialog.prepend($closeButton);
|
||||||
|
$closeButton.on('click', function() {
|
||||||
|
self.close();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'width':
|
||||||
|
this.$dialog.css('width', value);
|
||||||
|
break;
|
||||||
|
case 'height':
|
||||||
|
this.$dialog.css('height', value);
|
||||||
|
break;
|
||||||
|
case 'close':
|
||||||
|
this.closeCB = value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
//this._super(key, value);
|
||||||
|
$.Widget.prototype._setOption.apply(this, arguments );
|
||||||
|
},
|
||||||
|
_setOptions: function(options) {
|
||||||
|
console.log('_setOptions', options);
|
||||||
|
//this._super(options);
|
||||||
|
$.Widget.prototype._setOptions.apply(this, arguments);
|
||||||
|
},
|
||||||
|
_setSizes: function() {
|
||||||
|
var content_height = this.$dialog.height();
|
||||||
|
if(this.$title) {
|
||||||
|
content_height -= this.$title.outerHeight(true);
|
||||||
|
}
|
||||||
|
if(this.$buttonrow) {
|
||||||
|
content_height -= this.$buttonrow.outerHeight(true);
|
||||||
|
}
|
||||||
|
this.parent = this.$dialog.parent().length > 0 ? this.$dialog.parent() : $('body');
|
||||||
|
content_height = Math.min(content_height, this.parent.height()-20)
|
||||||
|
this.element.css({
|
||||||
|
height: content_height + 'px',
|
||||||
|
width: this.$dialog.innerWidth() + 'px'
|
||||||
|
});
|
||||||
|
},
|
||||||
|
widget: function() {
|
||||||
|
return this.$dialog
|
||||||
|
},
|
||||||
|
close: function() {
|
||||||
|
console.log('close');
|
||||||
|
var self = this;
|
||||||
|
// Ugly hack to catch remaining keyup events.
|
||||||
|
setTimeout(function() {
|
||||||
|
self._trigger('close', self);
|
||||||
|
self.$dialog.hide();
|
||||||
|
}, 200);
|
||||||
|
},
|
||||||
|
destroy: function() {
|
||||||
|
console.log('destroy');
|
||||||
|
if(this.$title) {
|
||||||
|
this.$title.remove()
|
||||||
|
}
|
||||||
|
if(this.$buttonrow) {
|
||||||
|
this.$buttonrow.remove()
|
||||||
|
}
|
||||||
|
|
||||||
|
if(this.originalTitle) {
|
||||||
|
this.element.attr('title', this.originalTitle);
|
||||||
|
}
|
||||||
|
this.element.removeClass('oc-dialog-content')
|
||||||
|
.css(this.originalCss).detach().insertBefore(this.$dialog);
|
||||||
|
this.$dialog.remove();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}(jQuery));
|
444
js/storage.js
Normal file
444
js/storage.js
Normal file
@ -0,0 +1,444 @@
|
|||||||
|
OC.Contacts = OC.Contacts || {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: Use $.Deferred.
|
||||||
|
*/
|
||||||
|
|
||||||
|
(function(window, $, OC) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var JSONResponse = function(response) {
|
||||||
|
if(!response || !response.status || response.status === 'error') {
|
||||||
|
this.error = true;
|
||||||
|
this.message = response.data.message || 'Unknown error.';
|
||||||
|
} else {
|
||||||
|
this.error = false;
|
||||||
|
if(response.data) {
|
||||||
|
this.data = response.data;
|
||||||
|
} else {
|
||||||
|
this.data = response;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An object for saving contact data to backends
|
||||||
|
*
|
||||||
|
* All methods returns a jQuery.Deferred object which resolves
|
||||||
|
* to either the requested response or an error object:
|
||||||
|
* {
|
||||||
|
* status: 'error',
|
||||||
|
* message: The error message
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* @param string user The user to query for. Defaults to current user
|
||||||
|
*/
|
||||||
|
var Storage = function(user) {
|
||||||
|
this.user = user ? user : OC.currentUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all address books registered for this user.
|
||||||
|
*
|
||||||
|
* @return An array containing object of address book metadata e.g.:
|
||||||
|
* {
|
||||||
|
* backend:'local',
|
||||||
|
* id:'1234'
|
||||||
|
* permissions:31,
|
||||||
|
* displayname:'Contacts'
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
Storage.prototype.getAddressBooksForUser = function() {
|
||||||
|
return this.requestRoute(
|
||||||
|
'contacts_address_books_for_user',
|
||||||
|
'GET',
|
||||||
|
{user: this.user}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add an address book to a specific backend
|
||||||
|
*
|
||||||
|
* @param string backend - currently defaults to 'local'
|
||||||
|
* @param object params An object {displayname:"My contacts", description:""}
|
||||||
|
* @return An array containing contact data e.g.:
|
||||||
|
* {
|
||||||
|
* metadata:
|
||||||
|
* {
|
||||||
|
* id:'1234'
|
||||||
|
* permissions:31,
|
||||||
|
* displayname:'My contacts',
|
||||||
|
* lastmodified: (unix timestamp),
|
||||||
|
* owner: 'joye',
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
Storage.prototype.addAddressBook = function(backend, parameters) {
|
||||||
|
console.log('Storage.addAddressBook', backend);
|
||||||
|
return this.requestRoute(
|
||||||
|
'contacts_address_book_add',
|
||||||
|
'POST',
|
||||||
|
{user: this.user, backend: 'local'},
|
||||||
|
parameters
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete an address book from a specific backend
|
||||||
|
*
|
||||||
|
* @param string backend
|
||||||
|
* @param string addressbookid Address book ID
|
||||||
|
*/
|
||||||
|
Storage.prototype.deleteAddressBook = function(backend, addressbookid) {
|
||||||
|
console.log('Storage.deleteAddressBook', backend, addressbookid);
|
||||||
|
return this.requestRoute(
|
||||||
|
'contacts_address_book_delete',
|
||||||
|
'POST',
|
||||||
|
{user: this.user, backend: 'local', addressbookid: addressbookid}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get contacts from an address book from a specific backend
|
||||||
|
*
|
||||||
|
* @param string backend
|
||||||
|
* @param string addressbookid Address book ID
|
||||||
|
* @return An array containing contact data e.g.:
|
||||||
|
* {
|
||||||
|
* metadata:
|
||||||
|
* {
|
||||||
|
* id:'1234'
|
||||||
|
* permissions:31,
|
||||||
|
* displayname:'John Q. Public',
|
||||||
|
* lastmodified: (unix timestamp),
|
||||||
|
* owner: 'joye',
|
||||||
|
* parent: (id of the parent address book)
|
||||||
|
* data: //array of VCard data
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
Storage.prototype.getContacts = function(backend, addressbookid) {
|
||||||
|
return this.requestRoute(
|
||||||
|
'contacts_address_book_collection',
|
||||||
|
'GET',
|
||||||
|
{user: this.user, backend: backend, addressbookid: addressbookid}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a contact to an address book from a specific backend
|
||||||
|
*
|
||||||
|
* @param string backend
|
||||||
|
* @param string addressbookid Address book ID
|
||||||
|
* @return An array containing contact data e.g.:
|
||||||
|
* {
|
||||||
|
* metadata:
|
||||||
|
* {
|
||||||
|
* id:'1234'
|
||||||
|
* permissions:31,
|
||||||
|
* displayname:'John Q. Public',
|
||||||
|
* lastmodified: (unix timestamp),
|
||||||
|
* owner: 'joye',
|
||||||
|
* parent: (id of the parent address book)
|
||||||
|
* data: //array of VCard data
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
Storage.prototype.addContact = function(backend, addressbookid) {
|
||||||
|
console.log('Storage.addContact', backend, addressbookid);
|
||||||
|
return this.requestRoute(
|
||||||
|
'contacts_address_book_add_contact',
|
||||||
|
'POST',
|
||||||
|
{user: this.user, backend: backend, addressbookid: addressbookid}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete a contact from an address book from a specific backend
|
||||||
|
*
|
||||||
|
* @param string backend
|
||||||
|
* @param string addressbookid Address book ID
|
||||||
|
* @param string contactid Address book ID
|
||||||
|
*/
|
||||||
|
Storage.prototype.deleteContact = function(backend, addressbookid, contactid) {
|
||||||
|
console.log('Storage.deleteContact', backend, addressbookid, contactid);
|
||||||
|
return this.requestRoute(
|
||||||
|
'contacts_address_book_delete_contact',
|
||||||
|
'POST',
|
||||||
|
{user: this.user, backend: backend, addressbookid: addressbookid, contactid: contactid}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get Image instance for a contacts profile picture
|
||||||
|
*
|
||||||
|
* @param string backend
|
||||||
|
* @param string addressbookid Address book ID
|
||||||
|
* @param string contactid Address book ID
|
||||||
|
* @return Image
|
||||||
|
*/
|
||||||
|
Storage.prototype.getContactPhoto = function(backend, addressbookid, contactid) {
|
||||||
|
var photo = new Image();
|
||||||
|
var url = OC.Router.generate(
|
||||||
|
'contacts_contact_photo',
|
||||||
|
{user: this.user, backend: backend, addressbookid: addressbookid, contactid: contactid}
|
||||||
|
);
|
||||||
|
var defer = $.Deferred();
|
||||||
|
$.when(
|
||||||
|
$(photo).load(function() {
|
||||||
|
defer.resolve(photo);
|
||||||
|
})
|
||||||
|
.error(function() {
|
||||||
|
console.log('Error loading default photo', arguments)
|
||||||
|
})
|
||||||
|
.attr('src', url + '?refresh=' + Math.random())
|
||||||
|
)
|
||||||
|
.fail(function(jqxhr, textStatus, error) {
|
||||||
|
defer.reject();
|
||||||
|
var err = textStatus + ', ' + error;
|
||||||
|
console.log( "Request Failed: " + err);
|
||||||
|
$(document).trigger('status.contact.error', {
|
||||||
|
message: t('contacts', 'Failed loading photo: {error}', {error:err})
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return defer.promise();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get Image instance for default profile picture
|
||||||
|
*
|
||||||
|
* This method loads the default picture only once and caches it.
|
||||||
|
*
|
||||||
|
* @return Image
|
||||||
|
*/
|
||||||
|
Storage.prototype.getDefaultPhoto = function() {
|
||||||
|
console.log('Storage.getDefaultPhoto');
|
||||||
|
if(!this._defaultPhoto) {
|
||||||
|
var url = OC.imagePath('contacts', 'person_large.png');
|
||||||
|
this._defaultPhoto = new Image();
|
||||||
|
$.when(
|
||||||
|
$(this._defaultPhoto)
|
||||||
|
.load(function() {
|
||||||
|
console.log('Default photo loaded', arguments);
|
||||||
|
}).error(function() {
|
||||||
|
console.log('Error loading default photo', arguments)
|
||||||
|
}).attr('src', url)
|
||||||
|
)
|
||||||
|
.then(function(response) {
|
||||||
|
console.log('Storage.defaultPhoto', response);
|
||||||
|
})
|
||||||
|
.fail(function(jqxhr, textStatus, error) {
|
||||||
|
var err = textStatus + ', ' + error;
|
||||||
|
console.log( "Request Failed: " + err);
|
||||||
|
$(document).trigger('status.contact.error', {
|
||||||
|
message: t('contacts', 'Failed loading default photo: {error}', {error:err})
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
return this._defaultPhoto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete a single property.
|
||||||
|
*
|
||||||
|
* @param string backend
|
||||||
|
* @param string addressbookid Address book ID
|
||||||
|
* @param string contactid Contact ID
|
||||||
|
* @param object params An object with the following properties:
|
||||||
|
* @param string name The name of the property e.g. EMAIL.
|
||||||
|
* @param string checksum For non-singular properties such as email this must contain
|
||||||
|
* an 8 character md5 checksum of the serialized \Sabre\Property
|
||||||
|
*/
|
||||||
|
Storage.prototype.deleteProperty = function(backend, addressbookid, contactid, params) {
|
||||||
|
return this.requestRoute(
|
||||||
|
'contacts_contact_delete_property',
|
||||||
|
'POST',
|
||||||
|
{user: this.user, backend: backend, addressbookid: addressbookid, contactid: contactid},
|
||||||
|
params
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save a property.
|
||||||
|
*
|
||||||
|
* @param string backend
|
||||||
|
* @param string addressbookid Address book ID
|
||||||
|
* @param string contactid Contact ID
|
||||||
|
* @param object params An object with the following properties:
|
||||||
|
* @param string name The name of the property e.g. EMAIL.
|
||||||
|
* @param string|array value The of the property
|
||||||
|
* @param array parameters Optional parameters for the property
|
||||||
|
* @param string checksum For non-singular properties such as email this must contain
|
||||||
|
* an 8 character md5 checksum of the serialized \Sabre\Property
|
||||||
|
*/
|
||||||
|
Storage.prototype.saveProperty = function(backend, addressbookid, contactid, params) {
|
||||||
|
return this.requestRoute(
|
||||||
|
'contacts_contact_save_property',
|
||||||
|
'POST',
|
||||||
|
{user: this.user, backend: backend, addressbookid: addressbookid, contactid: contactid},
|
||||||
|
params
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save all properties. Used when merging contacts.
|
||||||
|
*
|
||||||
|
* @param string backend
|
||||||
|
* @param string addressbookid Address book ID
|
||||||
|
* @param string contactid Contact ID
|
||||||
|
* @param object params An object with the all properties:
|
||||||
|
*/
|
||||||
|
Storage.prototype.saveAllProperties = function(backend, addressbookid, contactid, params) {
|
||||||
|
console.log('Storage.saveAllProperties', params);
|
||||||
|
return this.requestRoute(
|
||||||
|
'contacts_contact_save_all',
|
||||||
|
'POST',
|
||||||
|
{user: this.user, backend: backend, addressbookid: addressbookid, contactid: contactid},
|
||||||
|
params
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all groups for this user.
|
||||||
|
*
|
||||||
|
* @return An array containing the groups, the favorites, any shared
|
||||||
|
* address books, the last selected group and the sort order of the groups.
|
||||||
|
* {
|
||||||
|
* 'categories': [{'id':1',Family'}, {...}],
|
||||||
|
* 'favorites': [123,456],
|
||||||
|
* 'shared': [],
|
||||||
|
* 'lastgroup':'1',
|
||||||
|
* 'sortorder':'3,2,4'
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
Storage.prototype.getGroupsForUser = function() {
|
||||||
|
console.log('getGroupsForUser');
|
||||||
|
return this.requestRoute(
|
||||||
|
'contacts_categories_list',
|
||||||
|
'GET',
|
||||||
|
{user: this.user}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a group
|
||||||
|
*
|
||||||
|
* @param string name
|
||||||
|
* @return A JSON object containing the (maybe sanitized) group name and its ID:
|
||||||
|
* {
|
||||||
|
* 'id':1234,
|
||||||
|
* 'name':'My group'
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
Storage.prototype.addGroup = function(name) {
|
||||||
|
console.log('Storage.addGroup', name);
|
||||||
|
return this.requestRoute(
|
||||||
|
'contacts_categories_add',
|
||||||
|
'POST',
|
||||||
|
{user: this.user},
|
||||||
|
{name: name}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete a group
|
||||||
|
*
|
||||||
|
* @param string name
|
||||||
|
*/
|
||||||
|
Storage.prototype.deleteGroup = function(name) {
|
||||||
|
return this.requestRoute(
|
||||||
|
'contacts_categories_delete',
|
||||||
|
'POST',
|
||||||
|
{user: this.user},
|
||||||
|
{name: name}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add contacts to a group
|
||||||
|
*
|
||||||
|
* @param array contactids
|
||||||
|
*/
|
||||||
|
Storage.prototype.addToGroup = function(contactids, categoryid) {
|
||||||
|
console.log('Storage.addToGroup', contactids, categoryid);
|
||||||
|
return this.requestRoute(
|
||||||
|
'contacts_categories_addto',
|
||||||
|
'POST',
|
||||||
|
{user: this.user, categoryid: categoryid},
|
||||||
|
{contactids: contactids}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove contacts from a group
|
||||||
|
*
|
||||||
|
* @param array contactids
|
||||||
|
*/
|
||||||
|
Storage.prototype.removeFromGroup = function(contactids, categoryid) {
|
||||||
|
console.log('Storage.addToGroup', contactids, categoryid);
|
||||||
|
return this.requestRoute(
|
||||||
|
'contacts_categories_removefrom',
|
||||||
|
'POST',
|
||||||
|
{user: this.user, categoryid: categoryid},
|
||||||
|
{contactids: contactids}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a user preference
|
||||||
|
*
|
||||||
|
* @param string key
|
||||||
|
* @param string value
|
||||||
|
*/
|
||||||
|
Storage.prototype.setPreference = function(key, value) {
|
||||||
|
return this.requestRoute(
|
||||||
|
'contacts_setpreference',
|
||||||
|
'POST',
|
||||||
|
{user: this.user},
|
||||||
|
{key: key, value:value}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Storage.prototype.requestRoute = function(route, type, routeParams, params) {
|
||||||
|
var isJSON = (typeof params === 'string');
|
||||||
|
var contentType = isJSON ? 'application/json' : 'application/x-www-form-urlencoded';
|
||||||
|
var processData = !isJSON;
|
||||||
|
contentType += '; charset=UTF-8';
|
||||||
|
var self = this;
|
||||||
|
var url = OC.Router.generate(route, routeParams);
|
||||||
|
var ajaxParams = {
|
||||||
|
type: type,
|
||||||
|
url: url,
|
||||||
|
dataType: 'json',
|
||||||
|
contentType: contentType,
|
||||||
|
processData: processData,
|
||||||
|
data: params
|
||||||
|
};
|
||||||
|
var defer = $.Deferred();
|
||||||
|
/*$.when($.ajax(ajaxParams)).then(function(response) {
|
||||||
|
defer.resolve(new JSONResponse(response));
|
||||||
|
}).fail(function(jqxhr, textStatus, error) {
|
||||||
|
defer.reject(
|
||||||
|
new JSONResponse({
|
||||||
|
status:'error',
|
||||||
|
data:{message:t('contacts', 'Request failed: {error}', {error:textStatus + ', ' + error})}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});*/
|
||||||
|
|
||||||
|
var jqxhr = $.ajax(ajaxParams)
|
||||||
|
.done(function(response) {
|
||||||
|
defer.resolve(new JSONResponse(response));
|
||||||
|
})
|
||||||
|
.fail(function(jqxhr, textStatus, error) {
|
||||||
|
defer.reject(
|
||||||
|
new JSONResponse({
|
||||||
|
status:'error',
|
||||||
|
data:{message:t('contacts', 'Request failed: {error}', {error:textStatus + ', ' + error})}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
return defer.promise();
|
||||||
|
}
|
||||||
|
|
||||||
|
OC.Contacts.Storage = Storage;
|
||||||
|
|
||||||
|
})(window, jQuery, OC);
|
168
lib/abstractpimcollection.php
Normal file
168
lib/abstractpimcollection.php
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* ownCloud - Collection class for PIM object
|
||||||
|
*
|
||||||
|
* @author Thomas Tanghus
|
||||||
|
* @copyright 2012 Thomas Tanghus (thomas@tanghus.net)
|
||||||
|
*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subclass this for PIM collections
|
||||||
|
*/
|
||||||
|
|
||||||
|
abstract class PIMCollectionAbstract extends PIMObjectAbstract implements \Iterator, \Countable, \ArrayAccess {
|
||||||
|
|
||||||
|
// Iterator properties
|
||||||
|
|
||||||
|
protected $objects = array();
|
||||||
|
|
||||||
|
protected $counter = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is a collection so return null.
|
||||||
|
* @return null
|
||||||
|
*/
|
||||||
|
function getParent() {
|
||||||
|
null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a specific child node, referenced by its id
|
||||||
|
* TODO: Maybe implement it here?
|
||||||
|
*
|
||||||
|
* @param string $id
|
||||||
|
* @return IPIMObject
|
||||||
|
*/
|
||||||
|
abstract function getChild($id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an array with all the child nodes
|
||||||
|
*
|
||||||
|
* @return IPIMObject[]
|
||||||
|
*/
|
||||||
|
abstract function getChildren($limit = null, $offset = null);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a child-node with the specified id exists
|
||||||
|
*
|
||||||
|
* @param string $id
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
abstract function childExists($id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a child to the collection
|
||||||
|
*
|
||||||
|
* It's up to the implementations to "keep track" of the children.
|
||||||
|
*
|
||||||
|
* @param mixed $data
|
||||||
|
* @return string ID of the newly added child
|
||||||
|
*/
|
||||||
|
abstract public function addChild($data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete a child from the collection
|
||||||
|
*
|
||||||
|
* @param string $id
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
abstract public function deleteChild($id);
|
||||||
|
|
||||||
|
// Iterator methods
|
||||||
|
|
||||||
|
public function rewind() {
|
||||||
|
$this->counter = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function next() {
|
||||||
|
$this->counter++;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function valid() {
|
||||||
|
return array_key_exists($this->counter, $this->objects);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function current() {
|
||||||
|
return $this->objects[$this->counter];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Implementations can choose to return the current objects ID/UUID
|
||||||
|
* to be able to iterate over the collection with ID => Object pairs:
|
||||||
|
* foreach($collection as $id => $object) {}
|
||||||
|
*/
|
||||||
|
public function key() {
|
||||||
|
return $this->counter;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Countable method.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For implementations using a backend where fetching all object at once
|
||||||
|
* would give too much overhead, they can maintain an internal count value
|
||||||
|
* and fetch objects progressively. Simply watch the diffence between
|
||||||
|
* $this->counter, the value of count($this->objects) and the internal
|
||||||
|
* value, and fetch more objects when needed.
|
||||||
|
*/
|
||||||
|
public function count() {
|
||||||
|
return count($this->objects);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ArrayAccess methods
|
||||||
|
|
||||||
|
public function offsetSet($offset, $value) {
|
||||||
|
if (is_null($offset)) {
|
||||||
|
$this->objects[] = $value;
|
||||||
|
} else {
|
||||||
|
$this->objects[$offset] = $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function offsetExists($offset) {
|
||||||
|
return isset($this->objects[$offset]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function offsetUnset($offset) {
|
||||||
|
unset($this->objects[$offset]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function offsetGet($offset) {
|
||||||
|
return isset($this->objects[$offset]) ? $this->objects[$offset] : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Magic property accessors
|
||||||
|
// NOTE: They should go in the implementations(?)
|
||||||
|
/*
|
||||||
|
public function __set($id, $value) {
|
||||||
|
$this->objects[$id] = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __get($id) {
|
||||||
|
return $this->objects[$id];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __isset($id) {
|
||||||
|
return isset($this->objects[$id]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __unset($id) {
|
||||||
|
unset($this->objects[$id]);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
}
|
137
lib/abstractpimobject.php
Normal file
137
lib/abstractpimobject.php
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* ownCloud - Interface for PIM object
|
||||||
|
*
|
||||||
|
* @author Thomas Tanghus
|
||||||
|
* @copyright 2012 Thomas Tanghus (thomas@tanghus.net)
|
||||||
|
*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subclass this class or implement IPIMObject interface for PIM objects
|
||||||
|
*/
|
||||||
|
|
||||||
|
abstract class PIMObjectAbstract implements IPIMObject {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This variable holds the ID of this object.
|
||||||
|
* Depending on the backend, this can be either a string
|
||||||
|
* or an integer, so we treat them all as strings.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This variable holds the owner of this object.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $owner;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This variable holds the parent of this object if any.
|
||||||
|
*
|
||||||
|
* @var string|null
|
||||||
|
*/
|
||||||
|
protected $parent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This variable holds the permissions of this object.
|
||||||
|
*
|
||||||
|
* @var integer
|
||||||
|
*/
|
||||||
|
protected $permissions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getId() {
|
||||||
|
return $this->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
function getDisplayName() {
|
||||||
|
return $this->displayName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function getOwner() {
|
||||||
|
return $this->owner;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If this object is part of a collection return a reference
|
||||||
|
* to the parent object, otherwise return null.
|
||||||
|
* @return IPIMObject|null
|
||||||
|
*/
|
||||||
|
function getParent() {
|
||||||
|
return $this->parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** CRUDS permissions (Create, Read, Update, Delete, Share) using a bitmask of
|
||||||
|
*
|
||||||
|
* \OCP\PERMISSION_CREATE
|
||||||
|
* \OCP\PERMISSION_READ
|
||||||
|
* \OCP\PERMISSION_UPDATE
|
||||||
|
* \OCP\PERMISSION_DELETE
|
||||||
|
* \OCP\PERMISSION_SHARE
|
||||||
|
* or
|
||||||
|
* \OCP\PERMISSION_ALL
|
||||||
|
*
|
||||||
|
* @return integer
|
||||||
|
*/
|
||||||
|
function getPermissions() {
|
||||||
|
return $this->permissions;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return AbstractBackend
|
||||||
|
*/
|
||||||
|
function getBackend() {
|
||||||
|
return $this->backend;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param integer $permission
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
function hasPermission($permission) {
|
||||||
|
return $this->getPermissions() & $permission;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save the data to backend
|
||||||
|
*
|
||||||
|
* @param array $data
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
abstract public function update(array $data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete the data from backend
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
abstract public function delete();
|
||||||
|
|
||||||
|
}
|
@ -2,8 +2,8 @@
|
|||||||
/**
|
/**
|
||||||
* ownCloud - Addressbook
|
* ownCloud - Addressbook
|
||||||
*
|
*
|
||||||
* @author Jakob Sack
|
* @author Thomas Tanghus
|
||||||
* @copyright 2011 Jakob Sack mail@jakobsack.de
|
* @copyright 2013 Thomas Tanghus (thomas@tanghus.net)
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||||
@ -19,416 +19,262 @@
|
|||||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
* 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'
|
|
||||||
* );
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace OCA\Contacts;
|
namespace OCA\Contacts;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class manages our addressbooks.
|
* This class manages our addressbooks.
|
||||||
*/
|
*/
|
||||||
class Addressbook {
|
class Addressbook extends PIMCollectionAbstract {
|
||||||
|
|
||||||
|
protected $_count;
|
||||||
/**
|
/**
|
||||||
* @brief Returns the list of addressbooks for a specific user.
|
* @var Backend\AbstractBackend
|
||||||
* @param string $uid
|
|
||||||
* @param boolean $active Only return addressbooks with this $active state, default(=false) is don't care
|
|
||||||
* @param boolean $shared Whether to also return shared addressbook. Defaults to true.
|
|
||||||
* @return array or false.
|
|
||||||
*/
|
*/
|
||||||
public static function all($uid, $active = false, $shared = true) {
|
protected $backend;
|
||||||
$values = array($uid);
|
|
||||||
$active_where = '';
|
/**
|
||||||
if ($active) {
|
* An array containing the mandatory:
|
||||||
$active_where = ' AND `active` = ?';
|
* 'displayname'
|
||||||
$values[] = 1;
|
* 'discription'
|
||||||
}
|
* 'permissions'
|
||||||
try {
|
*
|
||||||
$stmt = \OCP\DB::prepare( 'SELECT * FROM `*PREFIX*contacts_addressbooks` WHERE `userid` = ? ' . $active_where . ' ORDER BY `displayname`' );
|
* And the optional:
|
||||||
$result = $stmt->execute($values);
|
* 'Etag'
|
||||||
if (\OC_DB::isError($result)) {
|
* 'lastModified'
|
||||||
\OCP\Util::write('contacts', __METHOD__. 'DB error: ' . \OC_DB::getErrorMessage($result), \OCP\Util::ERROR);
|
*
|
||||||
return false;
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $addressBookInfo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param AbstractBackend $backend The storage backend
|
||||||
|
* @param array $addressBookInfo
|
||||||
|
*/
|
||||||
|
public function __construct(Backend\AbstractBackend $backend, array $addressBookInfo) {
|
||||||
|
$this->backend = $backend;
|
||||||
|
$this->addressBookInfo = $addressBookInfo;
|
||||||
|
if(is_null($this->getId())) {
|
||||||
|
$id = $this->backend->createAddressBook($addressBookInfo);
|
||||||
|
if($id === false) {
|
||||||
|
throw new \Exception('Error creating address book.');
|
||||||
}
|
}
|
||||||
} catch(\Exception $e) {
|
$this->addressBookInfo = $this->backend->getAddressBook($id);
|
||||||
\OCP\Util::writeLog('contacts', __METHOD__.' exception: '.$e->getMessage(), \OCP\Util::ERROR);
|
//print(__METHOD__. ' '. __LINE__ . ' addressBookInfo: ' . print_r($this->backend->getAddressBook($id), true));
|
||||||
\OCP\Util::writeLog('contacts', __METHOD__.' uid: '.$uid, \OCP\Util::DEBUG);
|
}
|
||||||
|
//\OCP\Util::writeLog('contacts', __METHOD__.' backend: ' . print_r($this->backend, true), \OCP\Util::DEBUG);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function getId() {
|
||||||
|
return isset($this->addressBookInfo['id'])
|
||||||
|
? $this->addressBookInfo['id']
|
||||||
|
: null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getMetaData() {
|
||||||
|
$metadata = $this->addressBookInfo;
|
||||||
|
$metadata['lastmodified'] = $this->lastModified();
|
||||||
|
$metadata['backend'] = $this->getBackend()->name;
|
||||||
|
return $metadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getDisplayName() {
|
||||||
|
return $this->addressBookInfo['displayname'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getURI() {
|
||||||
|
return $this->addressBookInfo['uri'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getOwner() {
|
||||||
|
return $this->addressBookInfo['owner'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getPermissions() {
|
||||||
|
return $this->addressBookInfo['permissions'];
|
||||||
|
}
|
||||||
|
|
||||||
|
function getBackend() {
|
||||||
|
return $this->backend;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a specific child node, referenced by its id
|
||||||
|
*
|
||||||
|
* @param string $id
|
||||||
|
* @return Contact|null
|
||||||
|
*/
|
||||||
|
function getChild($id) {
|
||||||
|
//\OCP\Util::writeLog('contacts', __METHOD__.' id: '.$id, \OCP\Util::DEBUG);
|
||||||
|
if(!isset($this->objects[$id])) {
|
||||||
|
$contact = $this->backend->getContact($this->getId(), $id);
|
||||||
|
if($contact) {
|
||||||
|
$this->objects[$id] = new Contact($this, $this->backend, $contact);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// When requesting a single contact we preparse it
|
||||||
|
if(isset($this->objects[$id])) {
|
||||||
|
$this->objects[$id]->retrieve();
|
||||||
|
return $this->objects[$id];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a child-node with the specified id exists
|
||||||
|
*
|
||||||
|
* @param string $id
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
function childExists($id) {
|
||||||
|
return ($this->getChild($id) !== null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an array with all the child nodes
|
||||||
|
*
|
||||||
|
* @return Contact[]
|
||||||
|
*/
|
||||||
|
function getChildren($limit = null, $offset = null, $omitdata = false) {
|
||||||
|
//\OCP\Util::writeLog('contacts', __METHOD__.' backend: ' . print_r($this->backend, true), \OCP\Util::DEBUG);
|
||||||
|
$contacts = array();
|
||||||
|
|
||||||
|
foreach($this->backend->getContacts($this->getId(), $limit, $offset, $omitdata) as $contact) {
|
||||||
|
//\OCP\Util::writeLog('contacts', __METHOD__.' id: '.$contact['id'], \OCP\Util::DEBUG);
|
||||||
|
if(!isset($this->objects[$contact['id']])) {
|
||||||
|
$this->objects[$contact['id']] = new Contact($this, $this->backend, $contact);
|
||||||
|
}
|
||||||
|
$contacts[] = $this->objects[$contact['id']];
|
||||||
|
}
|
||||||
|
return $contacts;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a contact to the address book
|
||||||
|
* This takes an array or a VCard|Contact and return
|
||||||
|
* the ID or false.
|
||||||
|
*
|
||||||
|
* @param array|VObject\VCard $data
|
||||||
|
* @return int|bool
|
||||||
|
*/
|
||||||
|
public function addChild($data = null) {
|
||||||
|
$contact = new Contact($this, $this->backend, $data);
|
||||||
|
if($contact->save() === false) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
$id = $contact->getId();
|
||||||
$addressbooks = array();
|
if($this->count() !== null) {
|
||||||
while( $row = $result->fetchRow()) {
|
$this->_count += 1;
|
||||||
$row['permissions'] = \OCP\PERMISSION_ALL;
|
|
||||||
$addressbooks[] = $row;
|
|
||||||
}
|
|
||||||
|
|
||||||
if($shared === true) {
|
|
||||||
$addressbooks = array_merge($addressbooks, \OCP\Share::getItemsSharedWith('addressbook', Share_Backend_Addressbook::FORMAT_ADDRESSBOOKS));
|
|
||||||
}
|
|
||||||
if(!$active && !count($addressbooks)) {
|
|
||||||
$id = self::addDefault($uid);
|
|
||||||
return array(self::find($id),);
|
|
||||||
}
|
|
||||||
return $addressbooks;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get active addressbook IDs for a user.
|
|
||||||
* @param integer $uid User id. If null current user will be used.
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public static function activeIds($uid = null) {
|
|
||||||
if(is_null($uid)) {
|
|
||||||
$uid = \OCP\USER::getUser();
|
|
||||||
}
|
|
||||||
|
|
||||||
// query all addressbooks to force creation of default if it desn't exist.
|
|
||||||
$activeaddressbooks = self::all($uid);
|
|
||||||
$ids = array();
|
|
||||||
foreach($activeaddressbooks as $addressbook) {
|
|
||||||
if($addressbook['active']) {
|
|
||||||
$ids[] = $addressbook['id'];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return $ids;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Returns the list of active addressbooks for a specific user.
|
|
||||||
* @param string $uid
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public static function active($uid) {
|
|
||||||
return self::all($uid, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Returns the list of addressbooks for a principal (DAV term of user)
|
|
||||||
* @param string $principaluri
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public static function allWherePrincipalURIIs($principaluri) {
|
|
||||||
$uid = self::extractUserID($principaluri);
|
|
||||||
return self::all($uid);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Gets the data of one address book
|
|
||||||
* @param integer $id
|
|
||||||
* @return associative array or false.
|
|
||||||
*/
|
|
||||||
public static function find($id) {
|
|
||||||
try {
|
|
||||||
$stmt = \OCP\DB::prepare( 'SELECT * FROM `*PREFIX*contacts_addressbooks` WHERE `id` = ?' );
|
|
||||||
$result = $stmt->execute(array($id));
|
|
||||||
if (\OC_DB::isError($result)) {
|
|
||||||
\OC_Log::write('contacts', __METHOD__. 'DB error: ' . \OC_DB::getErrorMessage($result), \OC_Log::ERROR);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} catch(\Exception $e) {
|
|
||||||
\OCP\Util::writeLog('contacts', __METHOD__.', exception: ' . $e->getMessage(), \OCP\Util::ERROR);
|
|
||||||
\OCP\Util::writeLog('contacts', __METHOD__.', id: ' . $id, \OCP\Util::DEBUG);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
$row = $result->fetchRow();
|
|
||||||
|
|
||||||
if($row['userid'] != \OCP\USER::getUser() && !\OC_Group::inGroup(\OCP\User::getUser(), 'admin')) {
|
|
||||||
$sharedAddressbook = \OCP\Share::getItemSharedWithBySource('addressbook', $id);
|
|
||||||
if (!$sharedAddressbook || !($sharedAddressbook['permissions'] & \OCP\PERMISSION_READ)) {
|
|
||||||
throw new \Exception(
|
|
||||||
App::$l10n->t(
|
|
||||||
'You do not have the permissions to read this addressbook.'
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
$row['permissions'] = $sharedAddressbook['permissions'];
|
|
||||||
} else {
|
|
||||||
$row['permissions'] = \OCP\PERMISSION_ALL;
|
|
||||||
}
|
|
||||||
return $row;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Adds default address book
|
|
||||||
* @return $id ID of the newly created addressbook or false on error.
|
|
||||||
*/
|
|
||||||
public static function addDefault($uid = null) {
|
|
||||||
if(is_null($uid)) {
|
|
||||||
$uid = \OCP\USER::getUser();
|
|
||||||
}
|
|
||||||
$id = self::add($uid, 'Contacts', 'Default Address Book');
|
|
||||||
if($id !== false) {
|
|
||||||
self::setActive($id, true);
|
|
||||||
}
|
}
|
||||||
|
\OCP\Util::writeLog('contacts', __METHOD__.' id: '.$id, \OCP\Util::DEBUG);
|
||||||
return $id;
|
return $id;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Creates a new address book
|
* Delete a contact from the address book
|
||||||
* @param string $userid
|
*
|
||||||
* @param string $name
|
* @param string $id
|
||||||
* @param string $description
|
* @return bool
|
||||||
* @return insertid
|
|
||||||
*/
|
*/
|
||||||
public static function add($uid,$name,$description='') {
|
public function deleteChild($id) {
|
||||||
try {
|
if($this->backend->deleteContact($this->getId(), $id)) {
|
||||||
$stmt = \OCP\DB::prepare( 'SELECT `uri` FROM `*PREFIX*contacts_addressbooks` WHERE `userid` = ? ' );
|
if(isset($this->objects[$id])) {
|
||||||
$result = $stmt->execute(array($uid));
|
unset($this->objects[$id]);
|
||||||
if (\OC_DB::isError($result)) {
|
|
||||||
\OC_Log::write('contacts', __METHOD__. 'DB error: ' . \OC_DB::getErrorMessage($result), \OC_Log::ERROR);
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
} catch(\Exception $e) {
|
if($this->count() !== null) {
|
||||||
\OCP\Util::writeLog('contacts', __METHOD__ . ' exception: ' . $e->getMessage(), \OCP\Util::ERROR);
|
$this->_count -= 1;
|
||||||
\OCP\Util::writeLog('contacts', __METHOD__ . ' uid: ' . $uid, \OCP\Util::DEBUG);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
$uris = array();
|
|
||||||
while($row = $result->fetchRow()) {
|
|
||||||
$uris[] = $row['uri'];
|
|
||||||
}
|
|
||||||
|
|
||||||
$uri = self::createURI($name, $uris );
|
|
||||||
try {
|
|
||||||
$stmt = \OCP\DB::prepare( 'INSERT INTO `*PREFIX*contacts_addressbooks` (`userid`,`displayname`,`uri`,`description`,`ctag`) VALUES(?,?,?,?,?)' );
|
|
||||||
$result = $stmt->execute(array($uid,$name,$uri,$description,1));
|
|
||||||
if (\OC_DB::isError($result)) {
|
|
||||||
\OC_Log::write('contacts', __METHOD__. 'DB error: ' . \OC_DB::getErrorMessage($result), \OC_Log::ERROR);
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
} catch(\Exception $e) {
|
|
||||||
\OCP\Util::writeLog('contacts', __METHOD__.', exception: '.$e->getMessage(), \OCP\Util::ERROR);
|
|
||||||
\OCP\Util::writeLog('contacts', __METHOD__.', uid: '.$uid, \OCP\Util::DEBUG);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return \OCP\DB::insertid('*PREFIX*contacts_addressbooks');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Creates a new address book from the data sabredav provides
|
|
||||||
* @param string $principaluri
|
|
||||||
* @param string $uri
|
|
||||||
* @param string $name
|
|
||||||
* @param string $description
|
|
||||||
* @return insertid or false
|
|
||||||
*/
|
|
||||||
public static function addFromDAVData($principaluri, $uri, $name, $description) {
|
|
||||||
$uid = self::extractUserID($principaluri);
|
|
||||||
|
|
||||||
try {
|
|
||||||
$stmt = \OCP\DB::prepare('INSERT INTO `*PREFIX*contacts_addressbooks` '
|
|
||||||
. '(`userid`,`displayname`,`uri`,`description`,`ctag`) VALUES(?,?,?,?,?)');
|
|
||||||
$result = $stmt->execute(array($uid, $name, $uri, $description, 1));
|
|
||||||
if (\OC_DB::isError($result)) {
|
|
||||||
\OC_Log::write('contacts', __METHOD__. 'DB error: ' . \OC_DB::getErrorMessage($result), \OC_Log::ERROR);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} catch(\Exception $e) {
|
|
||||||
\OCP\Util::writeLog('contacts', __METHOD__.', exception: ' . $e->getMessage(), \OCP\Util::ERROR);
|
|
||||||
\OCP\Util::writeLog('contacts', __METHOD__.', uid: ' . $uid, \OCP\Util::DEBUG);
|
|
||||||
\OCP\Util::writeLog('contacts', __METHOD__.', uri: ' . $uri, \OCP\Util::DEBUG);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return \OCP\DB::insertid('*PREFIX*contacts_addressbooks');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Edits an addressbook
|
|
||||||
* @param integer $id
|
|
||||||
* @param string $name
|
|
||||||
* @param string $description
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
public static function edit($id,$name,$description) {
|
|
||||||
// Need these ones for checking uri
|
|
||||||
$addressbook = self::find($id);
|
|
||||||
if ($addressbook['userid'] != \OCP\User::getUser() && !\OC_Group::inGroup(OCP\User::getUser(), 'admin')) {
|
|
||||||
$sharedAddressbook = \OCP\Share::getItemSharedWithBySource('addressbook', $id);
|
|
||||||
if (!$sharedAddressbook || !($sharedAddressbook['permissions'] & \OCP\PERMISSION_UPDATE)) {
|
|
||||||
throw new \Exception(
|
|
||||||
App::$l10n->t(
|
|
||||||
'You do not have the permissions to update this addressbook.'
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(is_null($name)) {
|
|
||||||
$name = $addressbook['name'];
|
|
||||||
}
|
|
||||||
if(is_null($description)) {
|
|
||||||
$description = $addressbook['description'];
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
$stmt = \OCP\DB::prepare('UPDATE `*PREFIX*contacts_addressbooks` SET `displayname`=?,`description`=?, `ctag`=`ctag`+1 WHERE `id`=?');
|
|
||||||
$result = $stmt->execute(array($name,$description,$id));
|
|
||||||
if (\OC_DB::isError($result)) {
|
|
||||||
\OC_Log::write('contacts', __METHOD__. 'DB error: ' . \OC_DB::getErrorMessage($result), \OC_Log::ERROR);
|
|
||||||
throw new \Exception(
|
|
||||||
App::$l10n->t(
|
|
||||||
'There was an error updating the addressbook.'
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} catch(\Exception $e) {
|
|
||||||
\OCP\Util::writeLog('contacts', __METHOD__ . ', exception: ' . $e->getMessage(), \OCP\Util::ERROR);
|
|
||||||
\OCP\Util::writeLog('contacts', __METHOD__ . ', id: ' . $id, \OCP\Util::DEBUG);
|
|
||||||
throw new \Exception(
|
|
||||||
App::$l10n->t(
|
|
||||||
'There was an error updating the addressbook.'
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Activates an addressbook
|
|
||||||
* @param integer $id
|
|
||||||
* @param boolean $active
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
public static function setActive($id,$active) {
|
|
||||||
$sql = 'UPDATE `*PREFIX*contacts_addressbooks` SET `active` = ? WHERE `id` = ?';
|
|
||||||
|
|
||||||
try {
|
|
||||||
$stmt = \OCP\DB::prepare($sql);
|
|
||||||
$stmt->execute(array(intval($active), $id));
|
|
||||||
return true;
|
return true;
|
||||||
} catch(\Exception $e) {
|
}
|
||||||
\OCP\Util::writeLog('contacts', __METHOD__ . ', exception for ' . $id.': ' . $e->getMessage(), \OCP\Util::ERROR);
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal implements Countable
|
||||||
|
* @return int|null
|
||||||
|
*/
|
||||||
|
public function count() {
|
||||||
|
if(!isset($this->_count)) {
|
||||||
|
$this->_count = $this->backend->numContacts($this->getId());
|
||||||
|
}
|
||||||
|
return $this->_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update and save the address book data to backend
|
||||||
|
* NOTE: @see IPIMObject::update for consistency considerations.
|
||||||
|
*
|
||||||
|
* @param array $data
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function update(array $data) {
|
||||||
|
if(count($data) === 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
foreach($data as $key => $value) {
|
||||||
|
switch($key) {
|
||||||
/**
|
case 'displayname':
|
||||||
* @brief Checks if an addressbook is active.
|
$this->addressBookInfo['displayname'] = $value;
|
||||||
* @param integer $id ID of the address book.
|
break;
|
||||||
* @return boolean
|
case 'description':
|
||||||
*/
|
$this->addressBookInfo['description'] = $value;
|
||||||
public static function isActive($id) {
|
break;
|
||||||
$sql = 'SELECT `active` FROM `*PREFIX*contacts_addressbooks` WHERE `id` = ?';
|
|
||||||
try {
|
|
||||||
$stmt = \OCP\DB::prepare( $sql );
|
|
||||||
$result = $stmt->execute(array($id));
|
|
||||||
if (\OC_DB::isError($result)) {
|
|
||||||
\OC_Log::write('contacts', __METHOD__. 'DB error: ' . \OC_DB::getErrorMessage($result), \OC_Log::ERROR);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
$row = $result->fetchRow();
|
|
||||||
return (bool)$row['active'];
|
|
||||||
} catch(\Exception $e) {
|
|
||||||
\OCP\Util::writeLog('contacts', __METHOD__.', exception: ' . $e->getMessage(), \OCP\Util::ERROR);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief removes an address book
|
|
||||||
* @param integer $id
|
|
||||||
* @return boolean true on success, otherwise an exception will be thrown
|
|
||||||
*/
|
|
||||||
public static function delete($id) {
|
|
||||||
$addressbook = self::find($id);
|
|
||||||
|
|
||||||
if ($addressbook['userid'] != \OCP\User::getUser() && !\OC_Group::inGroup(\OCP\User::getUser(), 'admin')) {
|
|
||||||
$sharedAddressbook = \OCP\Share::getItemSharedWithBySource('addressbook', $id);
|
|
||||||
if (!$sharedAddressbook || !($sharedAddressbook['permissions'] & \OCP\PERMISSION_DELETE)) {
|
|
||||||
throw new \Exception(
|
|
||||||
App::$l10n->t(
|
|
||||||
'You do not have the permissions to delete this addressbook.'
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return $this->backend->updateAddressBook($this->getId(), $data);
|
||||||
// First delete cards belonging to this addressbook.
|
|
||||||
$cards = VCard::all($id);
|
|
||||||
foreach($cards as $card) {
|
|
||||||
try {
|
|
||||||
VCard::delete($card['id']);
|
|
||||||
} catch(\Exception $e) {
|
|
||||||
\OCP\Util::writeLog('contacts',
|
|
||||||
__METHOD__.', exception deleting vCard '.$card['id'].': '
|
|
||||||
. $e->getMessage(),
|
|
||||||
\OCP\Util::ERROR);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
$stmt = \OCP\DB::prepare('DELETE FROM `*PREFIX*contacts_addressbooks` WHERE `id` = ?');
|
|
||||||
$stmt->execute(array($id));
|
|
||||||
} catch(\Exception $e) {
|
|
||||||
\OCP\Util::writeLog('contacts',
|
|
||||||
__METHOD__.', exception for ' . $id . ': '
|
|
||||||
. $e->getMessage(),
|
|
||||||
\OCP\Util::ERROR);
|
|
||||||
throw new \Exception(
|
|
||||||
App::$l10n->t(
|
|
||||||
'There was an error deleting this addressbook.'
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
\OCP\Share::unshareAll('addressbook', $id);
|
|
||||||
|
|
||||||
if(count(self::all(\OCP\User::getUser())) == 0) {
|
|
||||||
self::addDefault();
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Updates ctag for addressbook
|
* Save the address book data to backend
|
||||||
* @param integer $id
|
* NOTE: @see IPIMObject::update for consistency considerations.
|
||||||
* @return boolean
|
*
|
||||||
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public static function touch($id) {
|
public function save() {
|
||||||
$stmt = \OCP\DB::prepare( 'UPDATE `*PREFIX*contacts_addressbooks` SET `ctag` = `ctag` + 1 WHERE `id` = ?' );
|
if(!$this->hasPermission(OCP\PERMISSION_UPDATE)) {
|
||||||
$stmt->execute(array($id));
|
throw new Exception('You don\'t have permissions to update the address book.');
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Creates a URI for Addressbook
|
|
||||||
* @param string $name name of the addressbook
|
|
||||||
* @param array $existing existing addressbook URIs
|
|
||||||
* @return string new name
|
|
||||||
*/
|
|
||||||
public static function createURI($name,$existing) {
|
|
||||||
$name = str_replace(' ', '_', strtolower($name));
|
|
||||||
$newname = $name;
|
|
||||||
$i = 1;
|
|
||||||
while(in_array($newname, $existing)) {
|
|
||||||
$newname = $name.$i;
|
|
||||||
$i = $i + 1;
|
|
||||||
}
|
}
|
||||||
return $newname;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief gets the userid from a principal path
|
* Delete the address book from backend
|
||||||
* @return string
|
*
|
||||||
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public static function extractUserID($principaluri) {
|
public function delete() {
|
||||||
list($prefix, $userid) = \Sabre_DAV_URLUtil::splitPath($principaluri);
|
if(!$this->hasPermission(OCP\PERMISSION_DELETE)) {
|
||||||
return $userid;
|
throw new Exception('You don\'t have permissions to delete the address book.');
|
||||||
|
}
|
||||||
|
return $this->backend->deleteAddressBook($this->getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the last modification time for the object.
|
||||||
|
*
|
||||||
|
* Must return a UNIX time stamp or null if the backend
|
||||||
|
* doesn't support it.
|
||||||
|
*
|
||||||
|
* @returns int | null
|
||||||
|
*/
|
||||||
|
public function lastModified() {
|
||||||
|
return $this->backend->lastModifiedAddressBook($this->getId());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
387
lib/addressbooklegacy.php
Normal file
387
lib/addressbooklegacy.php
Normal file
@ -0,0 +1,387 @@
|
|||||||
|
<?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'
|
||||||
|
* );
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace OCA\Contacts;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class manages our addressbooks.
|
||||||
|
*/
|
||||||
|
class AddressbookLegacy {
|
||||||
|
/**
|
||||||
|
* @brief Returns the list of addressbooks for a specific user.
|
||||||
|
* @param string $uid
|
||||||
|
* @param boolean $active Only return addressbooks with this $active state, default(=false) is don't care
|
||||||
|
* @param boolean $shared Whether to also return shared addressbook. Defaults to true.
|
||||||
|
* @return array or false.
|
||||||
|
*/
|
||||||
|
public static function all($uid, $active = false, $shared = true) {
|
||||||
|
$values = array($uid);
|
||||||
|
$active_where = '';
|
||||||
|
if ($active) {
|
||||||
|
$active_where = ' AND `active` = ?';
|
||||||
|
$values[] = 1;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
$stmt = \OCP\DB::prepare( 'SELECT * FROM `*PREFIX*contacts_addressbooks` WHERE `userid` = ? ' . $active_where . ' ORDER BY `displayname`' );
|
||||||
|
$result = $stmt->execute($values);
|
||||||
|
if (\OC_DB::isError($result)) {
|
||||||
|
\OCP\Util::write('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);
|
||||||
|
\OCP\Util::writeLog('contacts', __METHOD__.' uid: '.$uid, \OCP\Util::DEBUG);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$addressbooks = array();
|
||||||
|
while( $row = $result->fetchRow()) {
|
||||||
|
$row['permissions'] = \OCP\PERMISSION_ALL;
|
||||||
|
$addressbooks[] = $row;
|
||||||
|
}
|
||||||
|
|
||||||
|
if($shared === true) {
|
||||||
|
$addressbooks = array_merge($addressbooks, \OCP\Share::getItemsSharedWith('addressbook', Share_Backend_Addressbook::FORMAT_ADDRESSBOOKS));
|
||||||
|
}
|
||||||
|
if(!$active && !count($addressbooks)) {
|
||||||
|
$id = self::addDefault($uid);
|
||||||
|
return array(self::find($id),);
|
||||||
|
}
|
||||||
|
return $addressbooks;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get active addressbook IDs for a user.
|
||||||
|
* @param integer $uid User id. If null current user will be used.
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public static function activeIds($uid = null) {
|
||||||
|
if(is_null($uid)) {
|
||||||
|
$uid = \OCP\USER::getUser();
|
||||||
|
}
|
||||||
|
|
||||||
|
// query all addressbooks to force creation of default if it desn't exist.
|
||||||
|
$activeaddressbooks = self::all($uid);
|
||||||
|
$ids = array();
|
||||||
|
foreach($activeaddressbooks as $addressbook) {
|
||||||
|
if($addressbook['active']) {
|
||||||
|
$ids[] = $addressbook['id'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $ids;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns the list of active addressbooks for a specific user.
|
||||||
|
* @param string $uid
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public static function active($uid) {
|
||||||
|
return self::all($uid, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the data of one address book
|
||||||
|
* @param integer $id
|
||||||
|
* @return associative array or false.
|
||||||
|
*/
|
||||||
|
public static function find($id) {
|
||||||
|
try {
|
||||||
|
$stmt = \OCP\DB::prepare( 'SELECT * FROM `*PREFIX*contacts_addressbooks` WHERE `id` = ?' );
|
||||||
|
$result = $stmt->execute(array($id));
|
||||||
|
if (\OC_DB::isError($result)) {
|
||||||
|
\OC_Log::write('contacts', __METHOD__. 'DB error: ' . \OC_DB::getErrorMessage($result), \OC_Log::ERROR);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} catch(Exception $e) {
|
||||||
|
\OCP\Util::writeLog('contacts', __METHOD__.', exception: ' . $e->getMessage(), \OCP\Util::ERROR);
|
||||||
|
\OCP\Util::writeLog('contacts', __METHOD__.', id: ' . $id, \OCP\Util::DEBUG);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$row = $result->fetchRow();
|
||||||
|
|
||||||
|
if($row['userid'] != \OCP\USER::getUser() && !\OC_Group::inGroup(\OCP\User::getUser(), 'admin')) {
|
||||||
|
$sharedAddressbook = \OCP\Share::getItemSharedWithBySource('addressbook', $id);
|
||||||
|
if (!$sharedAddressbook || !($sharedAddressbook['permissions'] & \OCP\PERMISSION_READ)) {
|
||||||
|
throw new Exception(
|
||||||
|
App::$l10n->t(
|
||||||
|
'You do not have the permissions to read this addressbook.'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
$row['permissions'] = $sharedAddressbook['permissions'];
|
||||||
|
} else {
|
||||||
|
$row['permissions'] = \OCP\PERMISSION_ALL;
|
||||||
|
}
|
||||||
|
return $row;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Adds default address book
|
||||||
|
* @return $id ID of the newly created addressbook or false on error.
|
||||||
|
*/
|
||||||
|
public static function addDefault($uid = null) {
|
||||||
|
if(is_null($uid)) {
|
||||||
|
$uid = \OCP\USER::getUser();
|
||||||
|
}
|
||||||
|
$id = self::add($uid, 'Contacts', 'Default Address Book');
|
||||||
|
if($id !== false) {
|
||||||
|
self::setActive($id, true);
|
||||||
|
}
|
||||||
|
return $id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Creates a new address book
|
||||||
|
* @param string $userid
|
||||||
|
* @param string $name
|
||||||
|
* @param string $description
|
||||||
|
* @return insertid
|
||||||
|
*/
|
||||||
|
public static function add($uid,$name,$description='') {
|
||||||
|
try {
|
||||||
|
$stmt = \OCP\DB::prepare( 'SELECT `uri` FROM `*PREFIX*contacts_addressbooks` WHERE `userid` = ? ' );
|
||||||
|
$result = $stmt->execute(array($uid));
|
||||||
|
if (\OC_DB::isError($result)) {
|
||||||
|
\OC_Log::write('contacts', __METHOD__. 'DB error: ' . \OC_DB::getErrorMessage($result), \OC_Log::ERROR);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} catch(Exception $e) {
|
||||||
|
\OCP\Util::writeLog('contacts', __METHOD__ . ' exception: ' . $e->getMessage(), \OCP\Util::ERROR);
|
||||||
|
\OCP\Util::writeLog('contacts', __METHOD__ . ' uid: ' . $uid, \OCP\Util::DEBUG);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$uris = array();
|
||||||
|
while($row = $result->fetchRow()) {
|
||||||
|
$uris[] = $row['uri'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$uri = self::createURI($name, $uris );
|
||||||
|
try {
|
||||||
|
$stmt = \OCP\DB::prepare( 'INSERT INTO `*PREFIX*contacts_addressbooks` (`userid`,`displayname`,`uri`,`description`,`ctag`) VALUES(?,?,?,?,?)' );
|
||||||
|
$result = $stmt->execute(array($uid,$name,$uri,$description,1));
|
||||||
|
if (\OC_DB::isError($result)) {
|
||||||
|
\OC_Log::write('contacts', __METHOD__. 'DB error: ' . \OC_DB::getErrorMessage($result), \OC_Log::ERROR);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} catch(Exception $e) {
|
||||||
|
\OCP\Util::writeLog('contacts', __METHOD__.', exception: '.$e->getMessage(), \OCP\Util::ERROR);
|
||||||
|
\OCP\Util::writeLog('contacts', __METHOD__.', uid: '.$uid, \OCP\Util::DEBUG);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return \OCP\DB::insertid('*PREFIX*contacts_addressbooks');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Edits an addressbook
|
||||||
|
* @param integer $id
|
||||||
|
* @param string $name
|
||||||
|
* @param string $description
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public static function edit($id,$name,$description) {
|
||||||
|
// Need these ones for checking uri
|
||||||
|
$addressbook = self::find($id);
|
||||||
|
if ($addressbook['userid'] != \OCP\User::getUser() && !\OC_Group::inGroup(OCP\User::getUser(), 'admin')) {
|
||||||
|
$sharedAddressbook = \OCP\Share::getItemSharedWithBySource('addressbook', $id);
|
||||||
|
if (!$sharedAddressbook || !($sharedAddressbook['permissions'] & \OCP\PERMISSION_UPDATE)) {
|
||||||
|
throw new \Exception(
|
||||||
|
App::$l10n->t(
|
||||||
|
'You do not have the permissions to update this addressbook.'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(is_null($name)) {
|
||||||
|
$name = $addressbook['name'];
|
||||||
|
}
|
||||||
|
if(is_null($description)) {
|
||||||
|
$description = $addressbook['description'];
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$stmt = \OCP\DB::prepare('UPDATE `*PREFIX*contacts_addressbooks` SET `displayname`=?,`description`=?, `ctag`=`ctag`+1 WHERE `id`=?');
|
||||||
|
$result = $stmt->execute(array($name,$description,$id));
|
||||||
|
if (\OC_DB::isError($result)) {
|
||||||
|
\OC_Log::write('contacts', __METHOD__. 'DB error: ' . \OC_DB::getErrorMessage($result), \OC_Log::ERROR);
|
||||||
|
throw new Exception(
|
||||||
|
App::$l10n->t(
|
||||||
|
'There was an error updating the addressbook.'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch(Exception $e) {
|
||||||
|
\OCP\Util::writeLog('contacts', __METHOD__ . ', exception: ' . $e->getMessage(), \OCP\Util::ERROR);
|
||||||
|
\OCP\Util::writeLog('contacts', __METHOD__ . ', id: ' . $id, \OCP\Util::DEBUG);
|
||||||
|
throw new Exception(
|
||||||
|
App::$l10n->t(
|
||||||
|
'There was an error updating the addressbook.'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Activates an addressbook
|
||||||
|
* @param integer $id
|
||||||
|
* @param boolean $active
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public static function setActive($id,$active) {
|
||||||
|
$sql = 'UPDATE `*PREFIX*contacts_addressbooks` SET `active` = ? WHERE `id` = ?';
|
||||||
|
|
||||||
|
try {
|
||||||
|
$stmt = \OCP\DB::prepare($sql);
|
||||||
|
$stmt->execute(array(intval($active), $id));
|
||||||
|
return true;
|
||||||
|
} catch(\Exception $e) {
|
||||||
|
\OCP\Util::writeLog('contacts', __METHOD__ . ', exception for ' . $id.': ' . $e->getMessage(), \OCP\Util::ERROR);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Checks if an addressbook is active.
|
||||||
|
* @param integer $id ID of the address book.
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public static function isActive($id) {
|
||||||
|
$sql = 'SELECT `active` FROM `*PREFIX*contacts_addressbooks` WHERE `id` = ?';
|
||||||
|
try {
|
||||||
|
$stmt = \OCP\DB::prepare( $sql );
|
||||||
|
$result = $stmt->execute(array($id));
|
||||||
|
if (\OC_DB::isError($result)) {
|
||||||
|
\OC_Log::write('contacts', __METHOD__. 'DB error: ' . \OC_DB::getErrorMessage($result), \OC_Log::ERROR);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$row = $result->fetchRow();
|
||||||
|
return (bool)$row['active'];
|
||||||
|
} catch(Exception $e) {
|
||||||
|
\OCP\Util::writeLog('contacts', __METHOD__.', exception: ' . $e->getMessage(), \OCP\Util::ERROR);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief removes an address book
|
||||||
|
* @param integer $id
|
||||||
|
* @return boolean true on success, otherwise an exception will be thrown
|
||||||
|
*/
|
||||||
|
public static function delete($id) {
|
||||||
|
$addressbook = self::find($id);
|
||||||
|
|
||||||
|
if ($addressbook['userid'] != \OCP\User::getUser() && !\OC_Group::inGroup(\OCP\User::getUser(), 'admin')) {
|
||||||
|
$sharedAddressbook = \OCP\Share::getItemSharedWithBySource('addressbook', $id);
|
||||||
|
if (!$sharedAddressbook || !($sharedAddressbook['permissions'] & \OCP\PERMISSION_DELETE)) {
|
||||||
|
throw new Exception(
|
||||||
|
App::$l10n->t(
|
||||||
|
'You do not have the permissions to delete this addressbook.'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// First delete cards belonging to this addressbook.
|
||||||
|
$cards = VCard::all($id);
|
||||||
|
foreach($cards as $card) {
|
||||||
|
try {
|
||||||
|
VCard::delete($card['id']);
|
||||||
|
} catch(Exception $e) {
|
||||||
|
\OCP\Util::writeLog('contacts',
|
||||||
|
__METHOD__.', exception deleting vCard '.$card['id'].': '
|
||||||
|
. $e->getMessage(),
|
||||||
|
\OCP\Util::ERROR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$stmt = \OCP\DB::prepare('DELETE FROM `*PREFIX*contacts_addressbooks` WHERE `id` = ?');
|
||||||
|
$stmt->execute(array($id));
|
||||||
|
} catch(\Exception $e) {
|
||||||
|
\OCP\Util::writeLog('contacts',
|
||||||
|
__METHOD__.', exception for ' . $id . ': '
|
||||||
|
. $e->getMessage(),
|
||||||
|
\OCP\Util::ERROR);
|
||||||
|
throw new Exception(
|
||||||
|
App::$l10n->t(
|
||||||
|
'There was an error deleting this addressbook.'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
\OCP\Share::unshareAll('addressbook', $id);
|
||||||
|
|
||||||
|
if(count(self::all(\OCP\User::getUser())) == 0) {
|
||||||
|
self::addDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Updates ctag for addressbook
|
||||||
|
* @param integer $id
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public static function touch($id) {
|
||||||
|
$stmt = \OCP\DB::prepare( 'UPDATE `*PREFIX*contacts_addressbooks` SET `ctag` = `ctag` + 1 WHERE `id` = ?' );
|
||||||
|
$stmt->execute(array($id));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Creates a URI for Addressbook
|
||||||
|
* @param string $name name of the addressbook
|
||||||
|
* @param array $existing existing addressbook URIs
|
||||||
|
* @return string new name
|
||||||
|
*/
|
||||||
|
public static function createURI($name,$existing) {
|
||||||
|
$name = str_replace(' ', '_', strtolower($name));
|
||||||
|
$newname = $name;
|
||||||
|
$i = 1;
|
||||||
|
while(in_array($newname, $existing)) {
|
||||||
|
$newname = $name.$i;
|
||||||
|
$i = $i + 1;
|
||||||
|
}
|
||||||
|
return $newname;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -24,6 +24,7 @@ namespace OCA\Contacts;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* This class manages our addressbooks.
|
* This class manages our addressbooks.
|
||||||
|
* TODO: Port this to use the new backend
|
||||||
*/
|
*/
|
||||||
class AddressbookProvider implements \OCP\IAddressBook {
|
class AddressbookProvider implements \OCP\IAddressBook {
|
||||||
|
|
||||||
@ -48,7 +49,6 @@ class AddressbookProvider implements \OCP\IAddressBook {
|
|||||||
*/
|
*/
|
||||||
public function __construct($id) {
|
public function __construct($id) {
|
||||||
$this->id = $id;
|
$this->id = $id;
|
||||||
\Sabre\VObject\Property::$classMap['GEO'] = 'Sabre\\VObject\\Property\\Compound';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getAddressbook() {
|
public function getAddressbook() {
|
||||||
|
421
lib/app.php
421
lib/app.php
@ -1,6 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* Copyright (c) 2011 Bart Visscher bartv@thisnet.nl
|
* Copyright (c) 2013 Thomas Tanghus (thomas@tanghus.net)
|
||||||
* This file is licensed under the Affero General Public License version 3 or
|
* This file is licensed under the Affero General Public License version 3 or
|
||||||
* later.
|
* later.
|
||||||
* See the COPYING-README file.
|
* See the COPYING-README file.
|
||||||
@ -16,200 +16,152 @@ use Sabre\VObject;
|
|||||||
App::$l10n = \OC_L10N::get('contacts');
|
App::$l10n = \OC_L10N::get('contacts');
|
||||||
|
|
||||||
class App {
|
class App {
|
||||||
/*
|
|
||||||
* @brief language object for calendar app
|
|
||||||
*/
|
|
||||||
|
|
||||||
public static $l10n;
|
/**
|
||||||
/*
|
* @brief Categories of the user
|
||||||
* @brief categories of the user
|
* @var OC_VCategories
|
||||||
*/
|
*/
|
||||||
public static $categories = null;
|
public static $categories = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Properties there can be more than one of.
|
* @brief language object for calendar app
|
||||||
|
*
|
||||||
|
* @var OC_L10N
|
||||||
*/
|
*/
|
||||||
public static $multi_properties = array('EMAIL', 'TEL', 'IMPP', 'ADR', 'URL');
|
public static $l10n;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Properties to index.
|
* An array holding the current users address books.
|
||||||
|
* @var array
|
||||||
*/
|
*/
|
||||||
public static $index_properties = array('BDAY', 'UID', 'N', 'FN', 'TITLE', 'ROLE', 'NOTE', 'NICKNAME', 'ORG', 'CATEGORIES', 'EMAIL', 'TEL', 'IMPP', 'ADR', 'URL', 'GEO', 'PHOTO');
|
protected static $addressBooks = array();
|
||||||
|
|
||||||
const THUMBNAIL_PREFIX = 'contact-thumbnail-';
|
|
||||||
const THUMBNAIL_SIZE = 28;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Gets the VCard as a \Sabre\VObject\Component
|
* If backends are added to this map, they will be automatically mapped
|
||||||
* @param integer $id
|
* to their respective classes, if constructed with the 'getBackend' method.
|
||||||
* @returns \Sabre\VObject\Component|null The card or null if the card could not be parsed.
|
*
|
||||||
*/
|
* @var array
|
||||||
public static function getContactVCard($id) {
|
*/
|
||||||
$card = null;
|
public static $backendClasses = array(
|
||||||
$vcard = null;
|
'local' => 'OCA\Contacts\Backend\Database',
|
||||||
try {
|
'shared' => 'OCA\Contacts\Backend\Shared',
|
||||||
$card = VCard::find($id);
|
);
|
||||||
} catch(\Exception $e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!$card) {
|
public function __construct(
|
||||||
return null;
|
$user = null,
|
||||||
}
|
$addressBooksTableName = '*PREFIX*addressbook',
|
||||||
try {
|
$backendsTableName = '*PREFIX*addressbooks_backend',
|
||||||
$vcard = \Sabre\VObject\Reader::read($card['carddata']);
|
$dbBackend = null
|
||||||
} catch(\Exception $e) {
|
) {
|
||||||
\OCP\Util::writeLog('contacts', __METHOD__.', exception: ' . $e->getMessage(), \OCP\Util::ERROR);
|
$this->user = $user ? $user : \OCP\User::getUser();
|
||||||
\OCP\Util::writeLog('contacts', __METHOD__.', id: ' . $id, \OCP\Util::DEBUG);
|
$this->addressBooksTableName = $addressBooksTableName;
|
||||||
return null;
|
$this->backendsTableName = $backendsTableName;
|
||||||
}
|
$this->dbBackend = $dbBackend
|
||||||
|
? $dbBackend
|
||||||
if (!is_null($vcard) && !isset($vcard->REV)) {
|
: new Backend\Database($user);
|
||||||
$rev = new \DateTime('@'.$card['lastmodified']);
|
|
||||||
$vcard->REV = $rev->format(\DateTime::W3C);
|
|
||||||
}
|
|
||||||
return $vcard;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getPropertyLineByChecksum($vcard, $checksum) {
|
/**
|
||||||
$line = null;
|
* Gets backend by name.
|
||||||
foreach($vcard->children as $i => $property) {
|
*
|
||||||
if(substr(md5($property->serialize()), 0, 8) == $checksum ) {
|
* @param string $name
|
||||||
$line = $i;
|
* @return \Backend\AbstractBackend
|
||||||
break;
|
*/
|
||||||
|
static public function getBackend($name, $user = null) {
|
||||||
|
$name = $name ? $name : 'local';
|
||||||
|
if (isset(self::$backendClasses[$name])) {
|
||||||
|
return new self::$backendClasses[$name]($user);
|
||||||
|
} else {
|
||||||
|
throw new \Exception('No backend for: ' . $name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return all registered address books for current user.
|
||||||
|
* For now this is hard-coded to using the Database and
|
||||||
|
* Shared backends, but eventually admins will be able to
|
||||||
|
* register additional backends, and users will be able to
|
||||||
|
* subscribe to address books using those backends.
|
||||||
|
*
|
||||||
|
* @return AddressBook[]
|
||||||
|
*/
|
||||||
|
public function getAddressBooksForUser() {
|
||||||
|
if(!self::$addressBooks) {
|
||||||
|
foreach(array_keys(self::$backendClasses) as $backendName) {
|
||||||
|
$backend = self::getBackend($backendName, $this->user);
|
||||||
|
$addressBooks = $backend->getAddressBooksForUser();
|
||||||
|
if($backendName === 'local' && count($addressBooks) === 0) {
|
||||||
|
$id = $backend->createAddressBook(array('displayname' => 'Contacts'));
|
||||||
|
if($id !== false) {
|
||||||
|
$addressBook = $backend->getAddressBook($id);
|
||||||
|
$addressBooks = array($addressBook);
|
||||||
|
} else {
|
||||||
|
// TODO: Write log
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach($addressBooks as $addressBook) {
|
||||||
|
$addressBook['backend'] = $backendName;
|
||||||
|
self::$addressBooks[] = new AddressBook($backend, $addressBook);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return $line;
|
return self::$addressBooks;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return array of vcard prop => label
|
* Get an address book from a specific backend.
|
||||||
|
*
|
||||||
|
* @param string $backendName
|
||||||
|
* @param string $addressbookid
|
||||||
|
* @return AddressBook|null
|
||||||
*/
|
*/
|
||||||
public static function getIMOptions($im = null) {
|
public function getAddressBook($backendName, $addressbookid) {
|
||||||
$l10n = self::$l10n;
|
foreach(self::$addressBooks as $addressBook) {
|
||||||
$ims = array(
|
if($addressBook->backend->name === $backendName
|
||||||
'jabber' => array(
|
&& $addressBook->getId() === $addressbookid
|
||||||
'displayname' => (string)$l10n->t('Jabber'),
|
) {
|
||||||
'xname' => 'X-JABBER',
|
return $addressBook;
|
||||||
'protocol' => 'xmpp',
|
}
|
||||||
),
|
|
||||||
'aim' => array(
|
|
||||||
'displayname' => (string)$l10n->t('AIM'),
|
|
||||||
'xname' => 'X-AIM',
|
|
||||||
'protocol' => 'aim',
|
|
||||||
),
|
|
||||||
'msn' => array(
|
|
||||||
'displayname' => (string)$l10n->t('MSN'),
|
|
||||||
'xname' => 'X-MSN',
|
|
||||||
'protocol' => 'msn',
|
|
||||||
),
|
|
||||||
'twitter' => array(
|
|
||||||
'displayname' => (string)$l10n->t('Twitter'),
|
|
||||||
'xname' => 'X-TWITTER',
|
|
||||||
'protocol' => 'twitter',
|
|
||||||
),
|
|
||||||
'googletalk' => array(
|
|
||||||
'displayname' => (string)$l10n->t('GoogleTalk'),
|
|
||||||
'xname' => null,
|
|
||||||
'protocol' => 'xmpp',
|
|
||||||
),
|
|
||||||
'facebook' => array(
|
|
||||||
'displayname' => (string)$l10n->t('Facebook'),
|
|
||||||
'xname' => null,
|
|
||||||
'protocol' => 'xmpp',
|
|
||||||
),
|
|
||||||
'xmpp' => array(
|
|
||||||
'displayname' => (string)$l10n->t('XMPP'),
|
|
||||||
'xname' => null,
|
|
||||||
'protocol' => 'xmpp',
|
|
||||||
),
|
|
||||||
'icq' => array(
|
|
||||||
'displayname' => (string)$l10n->t('ICQ'),
|
|
||||||
'xname' => 'X-ICQ',
|
|
||||||
'protocol' => 'icq',
|
|
||||||
),
|
|
||||||
'yahoo' => array(
|
|
||||||
'displayname' => (string)$l10n->t('Yahoo'),
|
|
||||||
'xname' => 'X-YAHOO',
|
|
||||||
'protocol' => 'ymsgr',
|
|
||||||
),
|
|
||||||
'skype' => array(
|
|
||||||
'displayname' => (string)$l10n->t('Skype'),
|
|
||||||
'xname' => 'X-SKYPE',
|
|
||||||
'protocol' => 'skype',
|
|
||||||
),
|
|
||||||
'qq' => array(
|
|
||||||
'displayname' => (string)$l10n->t('QQ'),
|
|
||||||
'xname' => 'X-SKYPE',
|
|
||||||
'protocol' => 'x-apple',
|
|
||||||
),
|
|
||||||
'gadugadu' => array(
|
|
||||||
'displayname' => (string)$l10n->t('GaduGadu'),
|
|
||||||
'xname' => 'X-SKYPE',
|
|
||||||
'protocol' => 'x-apple',
|
|
||||||
),
|
|
||||||
);
|
|
||||||
if(is_null($im)) {
|
|
||||||
return $ims;
|
|
||||||
} else {
|
|
||||||
$ims['ymsgr'] = $ims['yahoo'];
|
|
||||||
$ims['gtalk'] = $ims['googletalk'];
|
|
||||||
return isset($ims[$im]) ? $ims[$im] : null;
|
|
||||||
}
|
}
|
||||||
|
// TODO: Check for return values
|
||||||
|
$backend = self::getBackend($backendName, $this->user);
|
||||||
|
$info = $backend->getAddressBook($addressbookid);
|
||||||
|
// FIXME: Backend name should be set by the backend.
|
||||||
|
$info['backend'] = $backendName;
|
||||||
|
$addressBook = new AddressBook($backend, $info);
|
||||||
|
self::$addressBooks[] = $addressBook;
|
||||||
|
return $addressBook;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return types for property $prop
|
* Get a Contact from an address book from a specific backend.
|
||||||
|
*
|
||||||
|
* @param string $backendName
|
||||||
|
* @param string $addressbookid
|
||||||
|
* @param string $id - Contact id
|
||||||
|
* @return Contact|null
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
public static function getTypesOfProperty($prop) {
|
public function getContact($backendName, $addressbookid, $id) {
|
||||||
$l = self::$l10n;
|
$addressBook = $this->getAddressBook($backendName, $addressbookid);
|
||||||
switch($prop) {
|
// TODO: Check for return value
|
||||||
case 'ADR':
|
return $addressBook->getChild($id);
|
||||||
case 'IMPP':
|
|
||||||
return array(
|
|
||||||
'WORK' => $l->t('Work'),
|
|
||||||
'HOME' => $l->t('Home'),
|
|
||||||
'OTHER' => $l->t('Other'),
|
|
||||||
);
|
|
||||||
case 'TEL':
|
|
||||||
return array(
|
|
||||||
'HOME' => $l->t('Home'),
|
|
||||||
'CELL' => $l->t('Mobile'),
|
|
||||||
'WORK' => $l->t('Work'),
|
|
||||||
'TEXT' => $l->t('Text'),
|
|
||||||
'VOICE' => $l->t('Voice'),
|
|
||||||
'MSG' => $l->t('Message'),
|
|
||||||
'FAX' => $l->t('Fax'),
|
|
||||||
'VIDEO' => $l->t('Video'),
|
|
||||||
'PAGER' => $l->t('Pager'),
|
|
||||||
'OTHER' => $l->t('Other'),
|
|
||||||
);
|
|
||||||
case 'EMAIL':
|
|
||||||
return array(
|
|
||||||
'WORK' => $l->t('Work'),
|
|
||||||
'HOME' => $l->t('Home'),
|
|
||||||
'INTERNET' => $l->t('Internet'),
|
|
||||||
'OTHER' => $l->t('Other'),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief returns the vcategories object of the user
|
* @brief returns the vcategories object of the user
|
||||||
* @return (object) $vcategories
|
* @return (object) $vcategories
|
||||||
*/
|
*/
|
||||||
public static function getVCategories() {
|
public static function getVCategories() {
|
||||||
if (is_null(self::$categories)) {
|
if (is_null(self::$categories)) {
|
||||||
if(\OC_VCategories::isEmpty('contact')) {
|
if(\OC_VCategories::isEmpty('contact')) {
|
||||||
self::scanCategories();
|
self::scanCategories();
|
||||||
}
|
}
|
||||||
self::$categories = new \OC_VCategories('contact',
|
self::$categories = new \OC_VCategories('contact',
|
||||||
null,
|
null,
|
||||||
self::getDefaultCategories());
|
self::getDefaultCategories());
|
||||||
}
|
}
|
||||||
return self::$categories;
|
return self::$categories;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief returns the categories for the user
|
* @brief returns the categories for the user
|
||||||
* @return (Array) $categories
|
* @return (Array) $categories
|
||||||
@ -219,19 +171,6 @@ class App {
|
|||||||
return ($categories ? $categories : self::getDefaultCategories());
|
return ($categories ? $categories : self::getDefaultCategories());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief returns the default categories of ownCloud
|
|
||||||
* @return (array) $categories
|
|
||||||
*/
|
|
||||||
public static function getDefaultCategories() {
|
|
||||||
return array(
|
|
||||||
(string)self::$l10n->t('Friends'),
|
|
||||||
(string)self::$l10n->t('Family'),
|
|
||||||
(string)self::$l10n->t('Work'),
|
|
||||||
(string)self::$l10n->t('Other'),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* scan vcards for categories.
|
* scan vcards for categories.
|
||||||
* @param $vccontacts VCards to scan. null to check all vcards for the current user.
|
* @param $vccontacts VCards to scan. null to check all vcards for the current user.
|
||||||
@ -269,140 +208,4 @@ class App {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* check VCard for new categories.
|
|
||||||
* @see OC_VCategories::loadFromVObject
|
|
||||||
*/
|
|
||||||
public static function loadCategoriesFromVCard($id, $contact) {
|
|
||||||
if(!$contact instanceof \OC_VObject) {
|
|
||||||
$contact = new \OC_VObject($contact);
|
|
||||||
}
|
|
||||||
self::getVCategories()->loadFromVObject($id, $contact, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get the last modification time.
|
|
||||||
* @param OC_VObject|Sabre\VObject\Component|integer|null $contact
|
|
||||||
* @returns DateTime | null
|
|
||||||
*/
|
|
||||||
public static function lastModified($contact = null) {
|
|
||||||
if(is_null($contact)) {
|
|
||||||
// FIXME: This doesn't take shared address books into account.
|
|
||||||
$sql = 'SELECT MAX(`lastmodified`) FROM `*PREFIX*contacts_cards`, `*PREFIX*contacts_addressbooks` ' .
|
|
||||||
'WHERE `*PREFIX*contacts_cards`.`addressbookid` = `*PREFIX*contacts_addressbooks`.`id` AND ' .
|
|
||||||
'`*PREFIX*contacts_addressbooks`.`userid` = ?';
|
|
||||||
$stmt = \OCP\DB::prepare($sql);
|
|
||||||
$result = $stmt->execute(array(\OCP\USER::getUser()));
|
|
||||||
if (\OC_DB::isError($result)) {
|
|
||||||
\OC_Log::write('contacts', __METHOD__. 'DB error: ' . \OC_DB::getErrorMessage($result), \OC_Log::ERROR);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
$lastModified = $result->fetchOne();
|
|
||||||
if(!is_null($lastModified)) {
|
|
||||||
return new \DateTime('@' . $lastModified);
|
|
||||||
}
|
|
||||||
} else if(is_numeric($contact)) {
|
|
||||||
$card = VCard::find($contact, array('lastmodified'));
|
|
||||||
return ($card ? new \DateTime('@' . $card['lastmodified']) : null);
|
|
||||||
} elseif($contact instanceof \OC_VObject || $contact instanceof VObject\Component) {
|
|
||||||
return isset($contact->REV)
|
|
||||||
? \DateTime::createFromFormat(\DateTime::W3C, $contact->REV)
|
|
||||||
: null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function cacheThumbnail($id, \OC_Image $image = null) {
|
|
||||||
if(\OC_Cache::hasKey(self::THUMBNAIL_PREFIX . $id) && $image === null) {
|
|
||||||
return \OC_Cache::get(self::THUMBNAIL_PREFIX . $id);
|
|
||||||
}
|
|
||||||
if(is_null($image)) {
|
|
||||||
$vcard = self::getContactVCard($id);
|
|
||||||
|
|
||||||
// invalid vcard
|
|
||||||
if(is_null($vcard)) {
|
|
||||||
\OCP\Util::writeLog('contacts',
|
|
||||||
__METHOD__.' The VCard for ID ' . $id . ' is not RFC compatible',
|
|
||||||
\OCP\Util::ERROR);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
$image = new \OC_Image();
|
|
||||||
if(!isset($vcard->PHOTO)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if(!$image->loadFromBase64((string)$vcard->PHOTO)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(!$image->centerCrop()) {
|
|
||||||
\OCP\Util::writeLog('contacts',
|
|
||||||
'thumbnail.php. Couldn\'t crop thumbnail for ID ' . $id,
|
|
||||||
\OCP\Util::ERROR);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if(!$image->resize(self::THUMBNAIL_SIZE)) {
|
|
||||||
\OCP\Util::writeLog('contacts',
|
|
||||||
'thumbnail.php. Couldn\'t resize thumbnail for ID ' . $id,
|
|
||||||
\OCP\Util::ERROR);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// Cache for around a month
|
|
||||||
\OC_Cache::set(self::THUMBNAIL_PREFIX . $id, $image->data(), 3000000);
|
|
||||||
\OCP\Util::writeLog('contacts', 'Caching ' . $id, \OCP\Util::DEBUG);
|
|
||||||
return \OC_Cache::get(self::THUMBNAIL_PREFIX . $id);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function updateDBProperties($contactid, $vcard = null) {
|
|
||||||
$stmt = \OCP\DB::prepare('DELETE FROM `*PREFIX*contacts_cards_properties` WHERE `contactid` = ?');
|
|
||||||
try {
|
|
||||||
$stmt->execute(array($contactid));
|
|
||||||
} catch(\Exception $e) {
|
|
||||||
\OCP\Util::writeLog('contacts', __METHOD__.
|
|
||||||
', exception: ' . $e->getMessage(), \OCP\Util::ERROR);
|
|
||||||
\OCP\Util::writeLog('contacts', __METHOD__.', id: '
|
|
||||||
. $id, \OCP\Util::DEBUG);
|
|
||||||
throw new \Exception(
|
|
||||||
App::$l10n->t(
|
|
||||||
'There was an error deleting properties for this contact.'
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(is_null($vcard)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$stmt = \OCP\DB::prepare( 'INSERT INTO `*PREFIX*contacts_cards_properties` '
|
|
||||||
. '(`userid`, `contactid`,`name`,`value`,`preferred`) VALUES(?,?,?,?,?)' );
|
|
||||||
foreach($vcard->children as $property) {
|
|
||||||
if(!in_array($property->name, self::$index_properties)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
$preferred = 0;
|
|
||||||
foreach($property->parameters as $parameter) {
|
|
||||||
if($parameter->name == 'TYPE' && strtoupper($parameter->value) == 'PREF') {
|
|
||||||
$preferred = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
$result = $stmt->execute(
|
|
||||||
array(
|
|
||||||
\OCP\User::getUser(),
|
|
||||||
$contactid,
|
|
||||||
$property->name,
|
|
||||||
$property->value,
|
|
||||||
$preferred,
|
|
||||||
)
|
|
||||||
);
|
|
||||||
if (\OC_DB::isError($result)) {
|
|
||||||
\OCP\Util::writeLog('contacts', __METHOD__. 'DB error: '
|
|
||||||
. \OC_DB::getErrorMessage($result), \OC_Log::ERROR);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} catch(\Exception $e) {
|
|
||||||
\OCP\Util::writeLog('contacts', __METHOD__.', exception: '.$e->getMessage(), \OCP\Util::ERROR);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
315
lib/backend/abstractbackend.php
Normal file
315
lib/backend/abstractbackend.php
Normal file
@ -0,0 +1,315 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* ownCloud - Base class for Contacts backends
|
||||||
|
*
|
||||||
|
* @author Thomas Tanghus
|
||||||
|
* @copyright 2013 Thomas Tanghus (thomas@tanghus.net)
|
||||||
|
*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subclass this class for address book backends
|
||||||
|
*
|
||||||
|
* The following methods MUST be implemented:
|
||||||
|
* @method array getAddressBooksForUser(string $userid) FIXME: I'm not sure about this one.
|
||||||
|
* @method array getAddressBook(string $addressbookid)
|
||||||
|
* @method array getContacts(string $addressbookid)
|
||||||
|
* @method array getContact(string $addressbookid, mixed $id)
|
||||||
|
* The following methods MAY be implemented:
|
||||||
|
* @method bool hasAddressBook(string $addressbookid)
|
||||||
|
* @method bool updateAddressBook(string $addressbookid, array $updates)
|
||||||
|
* @method string createAddressBook(string $addressbookid, array $properties)
|
||||||
|
* @method bool deleteAddressBook(string $addressbookid)
|
||||||
|
* @method int lastModifiedAddressBook(string $addressbookid)
|
||||||
|
* @method array numContacts(string $addressbookid)
|
||||||
|
* @method bool updateContact(string $addressbookid, string $id, array $updates)
|
||||||
|
* @method string createContact(string $addressbookid, string $id, array $properties)
|
||||||
|
* @method bool deleteContact(string $addressbookid, string $id)
|
||||||
|
* @method int lastModifiedContact(string $addressbookid)
|
||||||
|
*/
|
||||||
|
|
||||||
|
abstract class AbstractBackend {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the backend.
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $name;
|
||||||
|
|
||||||
|
protected $possibleContactPermissions = array(
|
||||||
|
\OCP\PERMISSION_CREATE => 'createContact',
|
||||||
|
\OCP\PERMISSION_READ => 'getContact',
|
||||||
|
\OCP\PERMISSION_UPDATE => 'updateContact',
|
||||||
|
\OCP\PERMISSION_DELETE => 'deleteContact',
|
||||||
|
);
|
||||||
|
|
||||||
|
protected $possibleAddressBookPermissions = array(
|
||||||
|
\OCP\PERMISSION_CREATE => 'createAddressBook',
|
||||||
|
\OCP\PERMISSION_READ => 'getAddressBook',
|
||||||
|
\OCP\PERMISSION_UPDATE => 'updateAddressBook',
|
||||||
|
\OCP\PERMISSION_DELETE => 'deleteAddressBook',
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get all permissions for contacts
|
||||||
|
* @returns bitwise-or'ed actions
|
||||||
|
*
|
||||||
|
* Returns the supported actions as int to be
|
||||||
|
* compared with \OCP\PERMISSION_CREATE etc.
|
||||||
|
* TODO: When getting the permissions we also have to check for
|
||||||
|
* configured permissions and return min() of the two values.
|
||||||
|
* A user can for example configure an address book with a backend
|
||||||
|
* that implements deleteContact() but wants to set it read-only.
|
||||||
|
*/
|
||||||
|
public function getContactPermissions() {
|
||||||
|
$permissions = 0;
|
||||||
|
foreach($this->possibleContactPermissions AS $permission => $methodName) {
|
||||||
|
if(method_exists($this, $methodName)) {
|
||||||
|
$permissions |= $permission;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $permissions;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get all permissions for address book.
|
||||||
|
* @returns bitwise-or'ed actions
|
||||||
|
*
|
||||||
|
* Returns the supported actions as int to be
|
||||||
|
* compared with \OCP\PERMISSION_CREATE etc.
|
||||||
|
*/
|
||||||
|
public function getAddressBookPermissions() {
|
||||||
|
$permissions = 0;
|
||||||
|
foreach($this->possibleAddressBookPermissions AS $permission => $methodName) {
|
||||||
|
if(method_exists($this, $methodName)) {
|
||||||
|
$permissions |= $permission;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $permissions;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Check if backend implements action for contacts
|
||||||
|
* @param $actions bitwise-or'ed actions
|
||||||
|
* @returns boolean
|
||||||
|
*
|
||||||
|
* Returns the supported actions as int to be
|
||||||
|
* compared with \OCP\PERMISSION_CREATE etc.
|
||||||
|
*/
|
||||||
|
public function hasContactPermission($permission) {
|
||||||
|
return (bool)($this->getContactPermissions() & $permission);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Check if backend implements action for contacts
|
||||||
|
* @param $actions bitwise-or'ed actions
|
||||||
|
* @returns boolean
|
||||||
|
*
|
||||||
|
* Returns the supported actions as int to be
|
||||||
|
* compared with \OCP\PERMISSION_CREATE etc.
|
||||||
|
*/
|
||||||
|
public function hasAddressBooksPermission($permission) {
|
||||||
|
return (bool)($this->getAddressBooksPermissions() & $permission);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the backend has the address book
|
||||||
|
*
|
||||||
|
* @param string $addressbookid
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function hasAddressBook($addressbookid) {
|
||||||
|
return count($this->getAddressBook($addressbookid)) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of contacts in an address book.
|
||||||
|
* Implementations can choose to override this method to either
|
||||||
|
* get the result more effectively or to return null if the backend
|
||||||
|
* cannot determine the number.
|
||||||
|
*
|
||||||
|
* @param string $addressbookid
|
||||||
|
* @return integer|null
|
||||||
|
*/
|
||||||
|
public function numContacts($addressbookid) {
|
||||||
|
return count($this->getContacts($addressbookid));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the list of addressbooks for a specific user.
|
||||||
|
*
|
||||||
|
* The returned arrays MUST contain a unique 'id' for the
|
||||||
|
* backend and a 'displayname', and it MAY contain a
|
||||||
|
* 'description'.
|
||||||
|
*
|
||||||
|
* @param string $principaluri
|
||||||
|
* @return array
|
||||||
|
public function getAddressBooksForUser($userid) {
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get an addressbook's properties
|
||||||
|
*
|
||||||
|
* The returned array MUST contain 'displayname' and an integer 'permissions'
|
||||||
|
* value using there ownCloud CRUDS constants (which MUST be at least
|
||||||
|
* \OCP\PERMISSION_READ).
|
||||||
|
* Currently the only ones supported are 'displayname' and
|
||||||
|
* 'description', but backends can implement additional.
|
||||||
|
*
|
||||||
|
* @param string $addressbookid
|
||||||
|
* @return array $properties
|
||||||
|
*/
|
||||||
|
public abstract function getAddressBook($addressbookid);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates an addressbook's properties
|
||||||
|
*
|
||||||
|
* The $properties array contains the changes to be made.
|
||||||
|
*
|
||||||
|
* Currently the only ones supported are 'displayname' and
|
||||||
|
* 'description', but backends can implement additional.
|
||||||
|
*
|
||||||
|
* @param string $addressbookid
|
||||||
|
* @param array $properties
|
||||||
|
* @return bool
|
||||||
|
public function updateAddressBook($addressbookid, array $properties) {
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new address book
|
||||||
|
*
|
||||||
|
* Currently the only ones supported are 'displayname' and
|
||||||
|
* 'description', but backends can implement additional.
|
||||||
|
* 'displayname' MUST be present.
|
||||||
|
*
|
||||||
|
* @param array $properties
|
||||||
|
* @return string|false The ID if the newly created AddressBook or false on error.
|
||||||
|
public function createAddressBook(array $properties) {
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes an entire addressbook and all its contents
|
||||||
|
*
|
||||||
|
* @param string $addressbookid
|
||||||
|
* @return bool
|
||||||
|
public function deleteAddressBook($addressbookid) {
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the last modification time for an address book.
|
||||||
|
*
|
||||||
|
* Must return a UNIX time stamp or null if the backend
|
||||||
|
* doesn't support it.
|
||||||
|
*
|
||||||
|
* TODO: Implement default methods get/set for backends that
|
||||||
|
* don't support.
|
||||||
|
* @param string $addressbookid
|
||||||
|
* @returns int | null
|
||||||
|
*/
|
||||||
|
public function lastModifiedAddressBook($addressbookid) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all contacts for a specific addressbook id.
|
||||||
|
*
|
||||||
|
* The returned array MUST contain the unique ID of the contact mapped to 'id', a
|
||||||
|
* displayname mapped to 'displayname' and an integer 'permissions' value using there
|
||||||
|
* ownCloud CRUDS constants (which MUST be at least \OCP\PERMISSION_READ), and SHOULD
|
||||||
|
* contain the properties of the contact formatted as a vCard 3.0
|
||||||
|
* https://tools.ietf.org/html/rfc2426 mapped to 'carddata' or as an
|
||||||
|
* \OCA\Contacts\VObject\VCard object mapped to 'vcard'.
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
*
|
||||||
|
* array(
|
||||||
|
* 0 => array('id' => '4e111fef5df', 'permissions' => 1, 'displayname' => 'John Q. Public', 'vcard' => $object),
|
||||||
|
* 1 => array('id' => 'bbcca2d1535', 'permissions' => 32, 'displayname' => 'Jane Doe', 'carddata' => $data)
|
||||||
|
* );
|
||||||
|
*
|
||||||
|
* For contacts that contain loads of data, the 'carddata' or 'vcard' MAY be omitted
|
||||||
|
* as it can be fetched later.
|
||||||
|
*
|
||||||
|
* TODO: Some sort of ETag?
|
||||||
|
*
|
||||||
|
* @param string $addressbookid
|
||||||
|
* @param bool $omitdata Don't fetch the entire carddata or vcard.
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public abstract function getContacts($addressbookid, $limit = null, $offset = null, $omitdata = false);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a specfic contact.
|
||||||
|
*
|
||||||
|
* Same as getContacts except that either 'carddata' or 'vcard' is mandatory.
|
||||||
|
*
|
||||||
|
* @param string $addressbookid
|
||||||
|
* @param mixed $id
|
||||||
|
* @return array|bool
|
||||||
|
*/
|
||||||
|
public abstract function getContact($addressbookid, $id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new contact
|
||||||
|
*
|
||||||
|
* @param string $addressbookid
|
||||||
|
* @param string $carddata
|
||||||
|
* @return string|bool The identifier for the new contact or false on error.
|
||||||
|
public function createContact($addressbookid, $carddata) {
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates a contact
|
||||||
|
*
|
||||||
|
* @param string $addressbookid
|
||||||
|
* @param mixed $id
|
||||||
|
* @param string $carddata
|
||||||
|
* @return bool
|
||||||
|
public function updateContact($addressbookid, $id, $carddata) {
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes a contact
|
||||||
|
*
|
||||||
|
* @param string $addressbookid
|
||||||
|
* @param mixed $id
|
||||||
|
* @return bool
|
||||||
|
public function deleteContact($addressbookid, $id) {
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the last modification time for a contact.
|
||||||
|
*
|
||||||
|
* Must return a UNIX time stamp or null if the backend
|
||||||
|
* doesn't support it.
|
||||||
|
*
|
||||||
|
* @param string $addressbookid
|
||||||
|
* @param mixed $id
|
||||||
|
* @returns int | null
|
||||||
|
*/
|
||||||
|
public function lastModifiedContact($addressbookid, $id) {
|
||||||
|
}
|
||||||
|
}
|
724
lib/backend/database.php
Normal file
724
lib/backend/database.php
Normal file
@ -0,0 +1,724 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* ownCloud - Database backend for Contacts
|
||||||
|
*
|
||||||
|
* @author Thomas Tanghus
|
||||||
|
* @copyright 2013 Thomas Tanghus (thomas@tanghus.net)
|
||||||
|
*
|
||||||
|
* 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;
|
||||||
|
use OCA\Contacts\VObject\VCard;
|
||||||
|
use Sabre\VObject\Reader;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subclass this class for Cantacts backends
|
||||||
|
*/
|
||||||
|
|
||||||
|
class Database extends AbstractBackend {
|
||||||
|
|
||||||
|
public $name = 'local';
|
||||||
|
static private $preparedQueries = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets up the backend
|
||||||
|
*
|
||||||
|
* @param string $addressBooksTableName
|
||||||
|
* @param string $cardsTableName
|
||||||
|
*/
|
||||||
|
public function __construct(
|
||||||
|
$userid = null,
|
||||||
|
$addressBooksTableName = '*PREFIX*contacts_addressbooks',
|
||||||
|
$cardsTableName = '*PREFIX*contacts_cards',
|
||||||
|
$indexTableName = '*PREFIX*contacts_cards_properties'
|
||||||
|
) {
|
||||||
|
$this->userid = $userid ? $userid : \OCP\User::getUser();
|
||||||
|
$this->addressBooksTableName = $addressBooksTableName;
|
||||||
|
$this->cardsTableName = $cardsTableName;
|
||||||
|
$this->indexTableName = $indexTableName;
|
||||||
|
$this->addressbooks = array();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the list of addressbooks for a specific user.
|
||||||
|
*
|
||||||
|
* TODO: Create default if none exists.
|
||||||
|
*
|
||||||
|
* @param string $principaluri
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getAddressBooksForUser($userid = null) {
|
||||||
|
$userid = $userid ? $userid : $this->userid;
|
||||||
|
|
||||||
|
try {
|
||||||
|
if(!isset(self::$preparedQueries['addressbooksforuser'])) {
|
||||||
|
$sql = 'SELECT `id`, `displayname`, `description`, `ctag` AS `lastmodified`, `userid` AS `owner`, `uri` FROM `'
|
||||||
|
. $this->addressBooksTableName
|
||||||
|
. '` WHERE `userid` = ? ORDER BY `displayname`';
|
||||||
|
self::$preparedQueries['addressbooksforuser'] = \OCP\DB::prepare($sql);
|
||||||
|
}
|
||||||
|
$result = self::$preparedQueries['addressbooksforuser']->execute(array($userid));
|
||||||
|
if (\OC_DB::isError($result)) {
|
||||||
|
\OCP\Util::write('contacts', __METHOD__. 'DB error: ' . \OC_DB::getErrorMessage($result), \OCP\Util::ERROR);
|
||||||
|
return $this->addressbooks;
|
||||||
|
}
|
||||||
|
} catch(\Exception $e) {
|
||||||
|
\OCP\Util::writeLog('contacts', __METHOD__.' exception: ' . $e->getMessage(), \OCP\Util::ERROR);
|
||||||
|
return $this->addressbooks;
|
||||||
|
}
|
||||||
|
|
||||||
|
while( $row = $result->fetchRow()) {
|
||||||
|
$row['permissions'] = \OCP\PERMISSION_ALL;
|
||||||
|
$this->addressbooks[$row['id']] = $row;
|
||||||
|
}
|
||||||
|
return $this->addressbooks;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAddressBook($addressbookid) {
|
||||||
|
//\OCP\Util::writeLog('contacts', __METHOD__.' id: '
|
||||||
|
// . $addressbookid, \OCP\Util::DEBUG);
|
||||||
|
if($this->addressbooks && isset($this->addressbooks[$addressbookid])) {
|
||||||
|
//print(__METHOD__ . ' ' . __LINE__ .' addressBookInfo: ' . print_r($this->addressbooks[$addressbookid], true));
|
||||||
|
return $this->addressbooks[$addressbookid];
|
||||||
|
}
|
||||||
|
// Hmm, not found. Lets query the db.
|
||||||
|
try {
|
||||||
|
$query = 'SELECT `id`, `displayname`, `description`, `userid` AS `owner`, `ctag` AS `lastmodified`, `uri` FROM `'
|
||||||
|
. $this->addressBooksTableName
|
||||||
|
. '` WHERE `id` = ?';
|
||||||
|
if(!isset(self::$preparedQueries['getaddressbook'])) {
|
||||||
|
self::$preparedQueries['getaddressbook'] = \OCP\DB::prepare($query);
|
||||||
|
}
|
||||||
|
$result = self::$preparedQueries['getaddressbook']->execute(array($addressbookid));
|
||||||
|
if (\OC_DB::isError($result)) {
|
||||||
|
\OCP\Util::write('contacts', __METHOD__. 'DB error: '
|
||||||
|
. \OC_DB::getErrorMessage($result), \OCP\Util::ERROR);
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
$row = $result->fetchRow();
|
||||||
|
$row['permissions'] = \OCP\PERMISSION_ALL;
|
||||||
|
return $row;
|
||||||
|
} catch(\Exception $e) {
|
||||||
|
\OCP\Util::writeLog('contacts', __METHOD__.' exception: '
|
||||||
|
. $e->getMessage(), \OCP\Util::ERROR);
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hasAddressBook($addressbookid) {
|
||||||
|
if($this->addressbooks && isset($this->addressbooks[$addressbookid])) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return count($this->getAddressBook($addressbookid)) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates an addressbook's properties
|
||||||
|
*
|
||||||
|
* @param string $addressbookid
|
||||||
|
* @param array $changes
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function updateAddressBook($addressbookid, array $changes) {
|
||||||
|
if(count($changes) === 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$query = 'UPDATE `' . $this->addressBooksTableName . '` SET ';
|
||||||
|
|
||||||
|
$updates = array();
|
||||||
|
|
||||||
|
if(isset($changes['displayname'])) {
|
||||||
|
$query .= '`displayname` = ?, ';
|
||||||
|
$updates[] = $changes['displayname'];
|
||||||
|
if($this->addressbooks && isset($this->addressbooks[$addressbookid])) {
|
||||||
|
$this->addressbooks[$addressbookid]['displayname'] = $changes['displayname'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(isset($changes['description'])) {
|
||||||
|
$query .= '`description` = ?, ';
|
||||||
|
$updates[] = $changes['description'];
|
||||||
|
if($this->addressbooks && isset($this->addressbooks[$addressbookid])) {
|
||||||
|
$this->addressbooks[$addressbookid]['description'] = $changes['description'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$query .= '`ctag` = `ctag` + 1 WHERE `id` = ?';
|
||||||
|
$updates[] = $addressbookid;
|
||||||
|
|
||||||
|
try {
|
||||||
|
$stmt = \OCP\DB::prepare($query);
|
||||||
|
$result = $stmt->execute($updates);
|
||||||
|
if (\OC_DB::isError($result)) {
|
||||||
|
\OC_Log::write('contacts',
|
||||||
|
__METHOD__. 'DB error: '
|
||||||
|
. \OC_DB::getErrorMessage($result), \OC_Log::ERROR);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} catch(Exception $e) {
|
||||||
|
\OCP\Util::writeLog('contacts',
|
||||||
|
__METHOD__ . ', exception: '
|
||||||
|
. $e->getMessage(), \OCP\Util::ERROR);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new address book
|
||||||
|
*
|
||||||
|
* Supported properties are 'displayname', 'description' and 'uri'.
|
||||||
|
* 'uri' is supported to allow to add from CardDAV requests, and MUST
|
||||||
|
* be used for the 'uri' database field if present.
|
||||||
|
* 'displayname' MUST be present.
|
||||||
|
*
|
||||||
|
* @param array $properties
|
||||||
|
* @return string|false The ID if the newly created AddressBook or false on error.
|
||||||
|
*/
|
||||||
|
public function createAddressBook(array $properties, $userid = null) {
|
||||||
|
$userid = $userid ? $userid : $this->userid;
|
||||||
|
if(count($properties) === 0 || !isset($properties['displayname'])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$query = 'INSERT INTO `' . $this->addressBooksTableName . '` '
|
||||||
|
. '(`userid`,`displayname`,`uri`,`description`,`ctag`) VALUES(?,?,?,?,?)';
|
||||||
|
|
||||||
|
$updates = array($userid, $properties['displayname']);
|
||||||
|
$updates[] = isset($properties['uri'])
|
||||||
|
? $properties['uri']
|
||||||
|
: $this->createAddressBookURI($properties['displayname']);
|
||||||
|
$updates[] = isset($properties['description']) ? $properties['description'] : '';
|
||||||
|
$ctag = time();
|
||||||
|
$updates[] = $ctag;
|
||||||
|
|
||||||
|
try {
|
||||||
|
if(!isset(self::$preparedQueries['createaddressbook'])) {
|
||||||
|
self::$preparedQueries['createaddressbook'] = \OCP\DB::prepare($query);
|
||||||
|
}
|
||||||
|
$result = self::$preparedQueries['createaddressbook']->execute($updates);
|
||||||
|
if (\OC_DB::isError($result)) {
|
||||||
|
\OC_Log::write('contacts', __METHOD__. 'DB error: ' . \OC_DB::getErrorMessage($result), \OC_Log::ERROR);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} catch(Exception $e) {
|
||||||
|
\OCP\Util::writeLog('contacts', __METHOD__ . ', exception: ' . $e->getMessage(), \OCP\Util::ERROR);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$newid = \OCP\DB::insertid($this->addressBooksTableName);
|
||||||
|
if($this->addressbooks) {
|
||||||
|
$updates['id'] = $newid;
|
||||||
|
$updates['ctag'] = $ctag;
|
||||||
|
$updates['lastmodified'] = $ctag;
|
||||||
|
$this->addressbooks[$addressbookid] = $updates;
|
||||||
|
}
|
||||||
|
return $newid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes an entire addressbook and all its contents
|
||||||
|
*
|
||||||
|
* @param string $addressbookid
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function deleteAddressBook($addressbookid) {
|
||||||
|
\OC_Hook::emit('OCA\Contacts', 'pre_deleteAddressBook',
|
||||||
|
array('id' => $addressbookid)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Clean up sharing
|
||||||
|
\OCP\Share::unshareAll('addressbook', $addressbookid);
|
||||||
|
|
||||||
|
// Get all contact ids for this address book
|
||||||
|
$ids = array();
|
||||||
|
$result = null;
|
||||||
|
$stmt = \OCP\DB::prepare('SELECT `id` FROM `' . $this->cardsTableName . '`'
|
||||||
|
. ' WHERE `addressbookid` = ?');
|
||||||
|
try {
|
||||||
|
$result = $stmt->execute(array($addressbookid));
|
||||||
|
if (\OC_DB::isError($result)) {
|
||||||
|
\OCP\Util::writeLog('contacts', __METHOD__. 'DB error: '
|
||||||
|
. \OC_DB::getErrorMessage($result), \OC_Log::ERROR);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch(\Exception $e) {
|
||||||
|
\OCP\Util::writeLog('contacts', __METHOD__.
|
||||||
|
', exception: ' . $e->getMessage(), \OCP\Util::ERROR);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!is_null($result)) {
|
||||||
|
while($id = $result->fetchOne()) {
|
||||||
|
$ids[] = $id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Purge contact property indexes
|
||||||
|
$stmt = \OCP\DB::prepare('DELETE FROM `' . $this->indexTableName
|
||||||
|
.'` WHERE `contactid` IN ('.str_repeat('?,', count($ids)-1).'?)');
|
||||||
|
try {
|
||||||
|
$stmt->execute($ids);
|
||||||
|
} catch(\Exception $e) {
|
||||||
|
\OCP\Util::writeLog('contacts', __METHOD__.
|
||||||
|
', exception: ' . $e->getMessage(), \OCP\Util::ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Purge categories
|
||||||
|
$catctrl = new \OC_VCategories('contact');
|
||||||
|
$catctrl->purgeObjects($ids);
|
||||||
|
|
||||||
|
if(!isset(self::$preparedQueries['deleteaddressbookcontacts'])) {
|
||||||
|
self::$preparedQueries['deleteaddressbookcontacts'] =
|
||||||
|
\OCP\DB::prepare('DELETE FROM `' . $this->cardsTableName
|
||||||
|
. '` WHERE `addressbookid` = ?');
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
self::$preparedQueries['deleteaddressbookcontacts']
|
||||||
|
->execute(array($addressbookid));
|
||||||
|
} catch(\Exception $e) {
|
||||||
|
\OCP\Util::writeLog('contacts', __METHOD__.
|
||||||
|
', exception: ' . $e->getMessage(), \OCP\Util::ERROR);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!isset(self::$preparedQueries['deleteaddressbook'])) {
|
||||||
|
self::$preparedQueries['deleteaddressbook'] =
|
||||||
|
\OCP\DB::prepare('DELETE FROM `'
|
||||||
|
. $this->addressBooksTableName . '` WHERE `id` = ?');
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
self::$preparedQueries['deleteaddressbook']
|
||||||
|
->execute(array($addressbookid));
|
||||||
|
} catch(\Exception $e) {
|
||||||
|
\OCP\Util::writeLog('contacts', __METHOD__.
|
||||||
|
', exception: ' . $e->getMessage(), \OCP\Util::ERROR);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if($this->addressbooks && isset($this->addressbooks[$addressbookid])) {
|
||||||
|
unset($this->addressbooks[$addressbookid]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Updates ctag for addressbook
|
||||||
|
* @param integer $id
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function touchAddressBook($id) {
|
||||||
|
$query = 'UPDATE `' . $this->addressBooksTableName
|
||||||
|
. '` SET `ctag` = `ctag` + 1 WHERE `id` = ?';
|
||||||
|
if(!isset(self::$preparedQueries['touchaddressbook'])) {
|
||||||
|
self::$preparedQueries['touchaddressbook'] = \OCP\DB::prepare($query);
|
||||||
|
}
|
||||||
|
self::$preparedQueries['touchaddressbook']->execute(array($id));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function lastModifiedAddressBook($addressbookid) {
|
||||||
|
if($this->addressbooks && isset($this->addressbooks[$addressbookid])) {
|
||||||
|
return $this->addressbooks[$addressbookid]['lastmodified'];
|
||||||
|
}
|
||||||
|
$sql = 'SELECT MAX(`lastmodified`) FROM `' . $this->cardsTableName . '`, `' . $this->addressBooksTableName . '` ' .
|
||||||
|
'WHERE `' . $this->cardsTableName . '`.`addressbookid` = `*PREFIX*contacts_addressbooks`.`id` AND ' .
|
||||||
|
'`' . $this->addressBooksTableName . '`.`userid` = ? AND `' . $this->addressBooksTableName . '`.`id` = ?';
|
||||||
|
if(!isset(self::$preparedQueries['lastmodifiedaddressbook'])) {
|
||||||
|
self::$preparedQueries['lastmodifiedaddressbook'] = \OCP\DB::prepare($sql);
|
||||||
|
}
|
||||||
|
$result = self::$preparedQueries['lastmodifiedaddressbook']->execute(array($this->userid, $addressbookid));
|
||||||
|
if (\OC_DB::isError($result)) {
|
||||||
|
\OC_Log::write('contacts', __METHOD__. 'DB error: ' . \OC_DB::getErrorMessage($result), \OC_Log::ERROR);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return $result->fetchOne();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of contacts in a specific address book.
|
||||||
|
*
|
||||||
|
* @param string $addressbookid
|
||||||
|
* @param bool $omitdata Don't fetch the entire carddata or vcard.
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function numContacts($addressbookid) {
|
||||||
|
$query = 'SELECT COUNT(*) AS `count` FROM `' . $this->cardsTableName . '` WHERE '
|
||||||
|
. '`addressbookid` = ?';
|
||||||
|
|
||||||
|
if(!isset(self::$preparedQueries['count'])) {
|
||||||
|
self::$preparedQueries['count'] = \OCP\DB::prepare($query);
|
||||||
|
}
|
||||||
|
$result = self::$preparedQueries['count']->execute(array($addressbookid));
|
||||||
|
if (\OC_DB::isError($result)) {
|
||||||
|
\OC_Log::write('contacts', __METHOD__. 'DB error: ' . \OC_DB::getErrorMessage($result), \OC_Log::ERROR);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return (int)$result->fetchOne();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all contacts for a specific addressbook id.
|
||||||
|
*
|
||||||
|
* @param string $addressbookid
|
||||||
|
* @param bool $omitdata Don't fetch the entire carddata or vcard.
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getContacts($addressbookid, $limit = null, $offset = null, $omitdata = false) {
|
||||||
|
//\OCP\Util::writeLog('contacts', __METHOD__.' addressbookid: ' . $addressbookid, \OCP\Util::DEBUG);
|
||||||
|
$cards = array();
|
||||||
|
try {
|
||||||
|
$qfields = $omitdata ? '`id`, `fullname` AS `displayname`' : '*';
|
||||||
|
$query = 'SELECT ' . $qfields . ' FROM `' . $this->cardsTableName
|
||||||
|
. '` WHERE `addressbookid` = ? ORDER BY `fullname`';
|
||||||
|
$stmt = \OCP\DB::prepare($query, $limit, $offset);
|
||||||
|
$result = $stmt->execute(array($addressbookid));
|
||||||
|
if (\OC_DB::isError($result)) {
|
||||||
|
\OC_Log::write('contacts', __METHOD__. 'DB error: ' . \OC_DB::getErrorMessage($result), \OCP\Util::ERROR);
|
||||||
|
return $cards;
|
||||||
|
}
|
||||||
|
} catch(\Exception $e) {
|
||||||
|
\OCP\Util::writeLog('contacts', __METHOD__.', exception: '.$e->getMessage(), \OCP\Util::ERROR);
|
||||||
|
return $cards;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!is_null($result)) {
|
||||||
|
while($row = $result->fetchRow()) {
|
||||||
|
$row['permissions'] = \OCP\PERMISSION_ALL;
|
||||||
|
$cards[] = $row;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $cards;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a specific contact.
|
||||||
|
*
|
||||||
|
* The $id for Database and Shared backends can be an array containing
|
||||||
|
* either 'id' or 'uri' to be able to play seamlessly with the
|
||||||
|
* CardDAV backend.
|
||||||
|
* FIXME: $addressbookid isn't used in the query, so there's no access control.
|
||||||
|
* OTOH the groups backend - OC_VCategories - doesn't no about parent collections
|
||||||
|
* only object IDs. Hmm.
|
||||||
|
* I could make a hack and add an optional, not documented 'nostrict' argument
|
||||||
|
* so it doesn't look for addressbookid.
|
||||||
|
*
|
||||||
|
* @param string $addressbookid
|
||||||
|
* @param mixed $id Contact ID
|
||||||
|
* @return array|false
|
||||||
|
*/
|
||||||
|
public function getContact($addressbookid, $id, $noCollection = false) {
|
||||||
|
//\OCP\Util::writeLog('contacts', __METHOD__.' identifier: ' . $addressbookid . ' ' . $id['uri'], \OCP\Util::DEBUG);
|
||||||
|
|
||||||
|
$where_query = '`id` = ?';
|
||||||
|
if(is_array($id)) {
|
||||||
|
$where_query = '';
|
||||||
|
if(isset($id['id'])) {
|
||||||
|
$id = $id['id'];
|
||||||
|
} elseif(isset($id['uri'])) {
|
||||||
|
$where_query = '`uri` = ?';
|
||||||
|
$id = $id['uri'];
|
||||||
|
} else {
|
||||||
|
throw new \Exception(
|
||||||
|
__METHOD__ . ' If second argument is an array, either \'id\' or \'uri\' has to be set.'
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$ids = array($id);
|
||||||
|
|
||||||
|
if(!$noCollection) {
|
||||||
|
$where_query .= ' AND `addressbookid` = ?';
|
||||||
|
$ids[] = $addressbookid;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$query = 'SELECT `id`, `carddata`, `lastmodified`, `fullname` AS `displayname` FROM `'
|
||||||
|
. $this->cardsTableName . '` WHERE ' . $where_query;
|
||||||
|
$stmt = \OCP\DB::prepare($query);
|
||||||
|
$result = $stmt->execute($ids);
|
||||||
|
if (\OC_DB::isError($result)) {
|
||||||
|
\OC_Log::write('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);
|
||||||
|
\OCP\Util::writeLog('contacts', __METHOD__.', id: '. $id, \OCP\Util::DEBUG);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$row = $result->fetchRow();
|
||||||
|
$row['permissions'] = \OCP\PERMISSION_ALL;
|
||||||
|
return $row;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hasContact($addressbookid, $id) {
|
||||||
|
return $this->getContact($addressbookid, $id) !== false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new contact
|
||||||
|
*
|
||||||
|
* In the Database and Shared backends contact be either a Contact object or a string
|
||||||
|
* with carddata to be able to play seamlessly with the CardDAV backend.
|
||||||
|
* If this method is called by the CardDAV backend, the carddata is already validated.
|
||||||
|
* NOTE: It's assumed that this method is called either from the CardDAV backend, the
|
||||||
|
* import script, or from the ownCloud web UI in which case either the uri parameter is
|
||||||
|
* set, or the contact has a UID. If neither is set, it will fail.
|
||||||
|
*
|
||||||
|
* @param string $addressbookid
|
||||||
|
* @param mixed $contact
|
||||||
|
* @return string|bool The identifier for the new contact or false on error.
|
||||||
|
*/
|
||||||
|
public function createContact($addressbookid, $contact, $uri = null) {
|
||||||
|
|
||||||
|
if(!$contact instanceof Contact) {
|
||||||
|
try {
|
||||||
|
$contact = Reader::read($contact);
|
||||||
|
} catch(\Exception $e) {
|
||||||
|
\OCP\Util::writeLog('contacts', __METHOD__.', exception: '.$e->getMessage(), \OCP\Util::ERROR);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$contact->validate(VCard::REPAIR|VCard::UPGRADE);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
OCP\Util::writeLog('contacts', __METHOD__ . ' ' .
|
||||||
|
'Error validating vcard: ' . $e->getMessage(), \OCP\Util::ERROR);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$uri = is_null($uri) ? $contact->UID . '.vcf' : $uri;
|
||||||
|
$now = new \DateTime;
|
||||||
|
$contact->REV = $now->format(\DateTime::W3C);
|
||||||
|
|
||||||
|
$appinfo = \OCP\App::getAppInfo('contacts');
|
||||||
|
$appversion = \OCP\App::getAppVersion('contacts');
|
||||||
|
$prodid = '-//ownCloud//NONSGML '.$appinfo['name'].' '.$appversion.'//EN';
|
||||||
|
$contact->PRODID = $prodid;
|
||||||
|
|
||||||
|
$data = $contact->serialize();
|
||||||
|
if(!isset(self::$preparedQueries['createcontact'])) {
|
||||||
|
self::$preparedQueries['createcontact'] = \OCP\DB::prepare('INSERT INTO `'
|
||||||
|
. $this->cardsTableName
|
||||||
|
. '` (`addressbookid`,`fullname`,`carddata`,`uri`,`lastmodified`) VALUES(?,?,?,?,?)' );
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
$result = self::$preparedQueries['createcontact']
|
||||||
|
->execute(
|
||||||
|
array(
|
||||||
|
$addressbookid,
|
||||||
|
(string)$contact->FN,
|
||||||
|
$contact->serialize(),
|
||||||
|
$uri,
|
||||||
|
time()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
if (\OC_DB::isError($result)) {
|
||||||
|
\OC_Log::write('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;
|
||||||
|
}
|
||||||
|
$newid = \OCP\DB::insertid($this->cardsTableName);
|
||||||
|
|
||||||
|
$this->touchAddressBook($addressbookid);
|
||||||
|
\OC_Hook::emit('OCA\Contacts', 'post_createContact',
|
||||||
|
array('id' => $newid, 'parent' => $addressbookid, 'contact' => $contact)
|
||||||
|
);
|
||||||
|
return (string)$newid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates a contact
|
||||||
|
*
|
||||||
|
* @param string $addressbookid
|
||||||
|
* @param mixed $id Contact ID
|
||||||
|
* @param mixed $contact
|
||||||
|
* @see getContact
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function updateContact($addressbookid, $id, $contact, $noCollection = false) {
|
||||||
|
if(!$contact instanceof Contact) {
|
||||||
|
try {
|
||||||
|
$contact = Reader::read($contact);
|
||||||
|
} catch(\Exception $e) {
|
||||||
|
\OCP\Util::writeLog('contacts', __METHOD__.', exception: '.$e->getMessage(), \OCP\Util::ERROR);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$where_query = '`id` = ?';
|
||||||
|
if(is_array($id)) {
|
||||||
|
$where_query = '';
|
||||||
|
if(isset($id['id'])) {
|
||||||
|
$id = $id['id'];
|
||||||
|
$qname = 'createcontactbyid';
|
||||||
|
} elseif(isset($id['uri'])) {
|
||||||
|
$where_query = '`id` = ?';
|
||||||
|
$id = $id['uri'];
|
||||||
|
$qname = 'createcontactbyuri';
|
||||||
|
} else {
|
||||||
|
throw new Exception(
|
||||||
|
__METHOD__ . ' If second argument is an array, either \'id\' or \'uri\' has to be set.'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$qname = 'createcontactbyid';
|
||||||
|
}
|
||||||
|
|
||||||
|
$now = new \DateTime;
|
||||||
|
$contact->REV = $now->format(\DateTime::W3C);
|
||||||
|
|
||||||
|
$data = $contact->serialize();
|
||||||
|
|
||||||
|
$updates = array($contact->FN, $data, time(), $id);
|
||||||
|
if(!$noCollection) {
|
||||||
|
$where_query .= ' AND `addressbookid` = ?';
|
||||||
|
$updates[] = $addressbookid;
|
||||||
|
}
|
||||||
|
|
||||||
|
$query = 'UPDATE `' . $this->cardsTableName
|
||||||
|
. '` SET `fullname` = ?,`carddata` = ?, `lastmodified` = ? WHERE ' . $where_query;
|
||||||
|
if(!isset(self::$preparedQueries[$qname])) {
|
||||||
|
self::$preparedQueries[$qname] = \OCP\DB::prepare($query);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
$result = self::$preparedQueries[$qname]->execute($updates);
|
||||||
|
if (\OC_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);
|
||||||
|
\OCP\Util::writeLog('contacts', __METHOD__.', id' . $id, \OCP\Util::DEBUG);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->touchAddressBook($addressbookid);
|
||||||
|
\OC_Hook::emit('OCA\Contacts', 'post_updateContact',
|
||||||
|
array('id' => $id, 'parent' => $addressbookid, 'contact' => $contact)
|
||||||
|
);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes a contact
|
||||||
|
*
|
||||||
|
* @param string $addressbookid
|
||||||
|
* @param string $id
|
||||||
|
* @see getContact
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function deleteContact($addressbookid, $id) {
|
||||||
|
$where_query = '`id` = ?';
|
||||||
|
if(is_array($id)) {
|
||||||
|
$where_query = '';
|
||||||
|
if(isset($id['id'])) {
|
||||||
|
$id = $id['id'];
|
||||||
|
$qname = 'deletecontactsbyid';
|
||||||
|
} elseif(isset($id['uri'])) {
|
||||||
|
$where_query = '`id` = ?';
|
||||||
|
$id = $id['uri'];
|
||||||
|
$qname = 'deletecontactsbyuri';
|
||||||
|
} else {
|
||||||
|
throw new Exception(
|
||||||
|
__METHOD__ . ' If second argument is an array, either \'id\' or \'uri\' has to be set.'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$qname = 'deletecontactsbyid';
|
||||||
|
}
|
||||||
|
\OC_Hook::emit('OCA\Contacts', 'pre_deleteContact',
|
||||||
|
array('id' => $id)
|
||||||
|
);
|
||||||
|
if(!isset(self::$preparedQueries[$qname])) {
|
||||||
|
self::$preparedQueries[$qname] = \OCP\DB::prepare('DELETE FROM `'
|
||||||
|
. $this->cardsTableName
|
||||||
|
. '` WHERE ' . $where_query . ' AND `addressbookid` = ?');
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
$result = self::$preparedQueries[$qname]->execute(array($id, $addressbookid));
|
||||||
|
if (\OC_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);
|
||||||
|
\OCP\Util::writeLog('contacts', __METHOD__.', id: '
|
||||||
|
. $id, \OCP\Util::DEBUG);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the last modification time for a contact.
|
||||||
|
*
|
||||||
|
* Must return a UNIX time stamp or null if the backend
|
||||||
|
* doesn't support it.
|
||||||
|
*
|
||||||
|
* @param string $addressbookid
|
||||||
|
* @param mixed $id
|
||||||
|
* @returns int | null
|
||||||
|
*/
|
||||||
|
public function lastModifiedContact($addressbookid, $id) {
|
||||||
|
$contact = $this->getContact($addressbookid, $id);
|
||||||
|
return ($contact ? $contact['lastmodified'] : null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function createAddressBookURI($displayname, $userid = null) {
|
||||||
|
$userid = $userid ? $userid : \OCP\User::getUser();
|
||||||
|
$name = str_replace(' ', '_', strtolower($displayname));
|
||||||
|
try {
|
||||||
|
$stmt = \OCP\DB::prepare('SELECT `uri` FROM `' . $this->addressBooksTableName . '` WHERE `userid` = ? ');
|
||||||
|
$result = $stmt->execute(array($userid));
|
||||||
|
if (\OC_DB::isError($result)) {
|
||||||
|
\OC_Log::write('contacts', __METHOD__. 'DB error: ' . \OC_DB::getErrorMessage($result), \OC_Log::ERROR);
|
||||||
|
return $name;
|
||||||
|
}
|
||||||
|
} catch(Exception $e) {
|
||||||
|
\OCP\Util::writeLog('contacts', __METHOD__ . ' exception: ' . $e->getMessage(), \OCP\Util::ERROR);
|
||||||
|
return $name;
|
||||||
|
}
|
||||||
|
$uris = array();
|
||||||
|
while($row = $result->fetchRow()) {
|
||||||
|
$uris[] = $row['uri'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$newname = $name;
|
||||||
|
$i = 1;
|
||||||
|
while(in_array($newname, $uris)) {
|
||||||
|
$newname = $name.$i;
|
||||||
|
$i = $i + 1;
|
||||||
|
}
|
||||||
|
return $newname;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
124
lib/backend/shared.php
Normal file
124
lib/backend/shared.php
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* ownCloud - Backend for Shared contacts
|
||||||
|
*
|
||||||
|
* @author Thomas Tanghus
|
||||||
|
* @copyright 2013 Thomas Tanghus (thomas@tanghus.net)
|
||||||
|
*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subclass this class for Cantacts backends
|
||||||
|
*/
|
||||||
|
|
||||||
|
class Shared extends Database {
|
||||||
|
|
||||||
|
public $name = 'shared';
|
||||||
|
public $addressbooks = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the list of addressbooks for a specific user.
|
||||||
|
*
|
||||||
|
* @param string $principaluri
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getAddressBooksForUser($userid = null) {
|
||||||
|
$userid = $userid ? $userid : $this->userid;
|
||||||
|
|
||||||
|
$this->addressbooks = \OCP\Share::getItemsSharedWith(
|
||||||
|
'addressbook',
|
||||||
|
Contacts\Share_Backend_Addressbook::FORMAT_ADDRESSBOOKS
|
||||||
|
);
|
||||||
|
|
||||||
|
return $this->addressbooks;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a specific address book.
|
||||||
|
*
|
||||||
|
* @param string $addressbookid
|
||||||
|
* @param mixed $id Contact ID
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function getAddressBook($addressbookid) {
|
||||||
|
$addressbook = \OCP\Share::getItemSharedWithBySource(
|
||||||
|
'addressbook',
|
||||||
|
$addressbookid,
|
||||||
|
Contacts\Share_Backend_Addressbook::FORMAT_ADDRESSBOOKS
|
||||||
|
);
|
||||||
|
// Not sure if I'm doing it wrongly, or if its supposed to return
|
||||||
|
// the info in an array?
|
||||||
|
return (isset($addressbook['permissions']) ? $addressbook : $addressbook[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all contacts for a specific addressbook id.
|
||||||
|
*
|
||||||
|
* TODO: Check for parent permissions
|
||||||
|
*
|
||||||
|
* @param string $addressbookid
|
||||||
|
* @param bool $omitdata Don't fetch the entire carddata or vcard.
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getContacts($addressbookid, $limit = null, $offset = null, $omitdata = false) {
|
||||||
|
//\OCP\Util::writeLog('contacts', __METHOD__.' addressbookid: '
|
||||||
|
// . $addressbookid, \OCP\Util::DEBUG);
|
||||||
|
$addressbook = \OCP\Share::getItemSharedWithBySource(
|
||||||
|
'addressbook',
|
||||||
|
$addressbookid,
|
||||||
|
Contacts\Share_Backend_Addressbook::FORMAT_ADDRESSBOOKS,
|
||||||
|
null, // parameters
|
||||||
|
true // includeCollection
|
||||||
|
);
|
||||||
|
\OCP\Util::writeLog('contacts', __METHOD__.' shared: '
|
||||||
|
. print_r($addressbook, true), \OCP\Util::DEBUG);
|
||||||
|
|
||||||
|
$addressbook = $this->getAddressBook($addressbookid);
|
||||||
|
$permissions = $addressbook['permissions'];
|
||||||
|
|
||||||
|
$cards = array();
|
||||||
|
try {
|
||||||
|
$qfields = $omitdata ? '`id`, `fullname` AS `displayname`, `lastmodified`' : '*';
|
||||||
|
$query = 'SELECT ' . $qfields . ' FROM `' . $this->cardsTableName
|
||||||
|
. '` WHERE `addressbookid` = ? ORDER BY `fullname`';
|
||||||
|
$stmt = \OCP\DB::prepare($query, $limit, $offset);
|
||||||
|
$result = $stmt->execute(array($addressbookid));
|
||||||
|
if (\OC_DB::isError($result)) {
|
||||||
|
\OC_Log::write('contacts', __METHOD__. 'DB error: '
|
||||||
|
. \OC_DB::getErrorMessage($result), \OCP\Util::ERROR);
|
||||||
|
return $cards;
|
||||||
|
}
|
||||||
|
} catch(\Exception $e) {
|
||||||
|
\OCP\Util::writeLog('contacts', __METHOD__.', exception: '
|
||||||
|
. $e->getMessage(), \OCP\Util::ERROR);
|
||||||
|
return $cards;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!is_null($result)) {
|
||||||
|
while( $row = $result->fetchRow()) {
|
||||||
|
$row['permissions'] = $permissions;
|
||||||
|
$cards[] = $row;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $cards;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -20,14 +20,18 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
namespace OCA\Contacts\CardDAV;
|
||||||
|
|
||||||
|
use OCA\Contacts;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class overrides __construct to get access to $addressBookInfo and
|
* This class overrides __construct to get access to $addressBookInfo and
|
||||||
* $carddavBackend, Sabre_CardDAV_AddressBook::getACL() to return read/write
|
* $carddavBackend, Sabre_CardDAV_AddressBook::getACL() to return read/write
|
||||||
* permissions based on user and shared state and it overrides
|
* permissions based on user and shared state and it overrides
|
||||||
* Sabre_CardDAV_AddressBook::getChild() and Sabre_CardDAV_AddressBook::getChildren()
|
* Sabre_CardDAV_AddressBook::getChild() and Sabre_CardDAV_AddressBook::getChildren()
|
||||||
* to instantiate OC_Connector_Sabre_CardDAV_Cards.
|
* to instantiate \OCA\Contacts\CardDAV\Cards.
|
||||||
*/
|
*/
|
||||||
class OC_Connector_Sabre_CardDAV_AddressBook extends Sabre_CardDAV_AddressBook {
|
class AddressBook extends \Sabre_CardDAV_AddressBook {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CardDAV backend
|
* CardDAV backend
|
||||||
@ -43,7 +47,7 @@ class OC_Connector_Sabre_CardDAV_AddressBook extends Sabre_CardDAV_AddressBook {
|
|||||||
* @param array $addressBookInfo
|
* @param array $addressBookInfo
|
||||||
*/
|
*/
|
||||||
public function __construct(
|
public function __construct(
|
||||||
Sabre_CardDAV_Backend_Abstract $carddavBackend,
|
\Sabre_CardDAV_Backend_Abstract $carddavBackend,
|
||||||
array $addressBookInfo) {
|
array $addressBookInfo) {
|
||||||
|
|
||||||
$this->carddavBackend = $carddavBackend;
|
$this->carddavBackend = $carddavBackend;
|
||||||
@ -70,41 +74,42 @@ class OC_Connector_Sabre_CardDAV_AddressBook extends Sabre_CardDAV_AddressBook {
|
|||||||
$writeprincipal = $this->getOwner();
|
$writeprincipal = $this->getOwner();
|
||||||
$createprincipal = $this->getOwner();
|
$createprincipal = $this->getOwner();
|
||||||
$deleteprincipal = $this->getOwner();
|
$deleteprincipal = $this->getOwner();
|
||||||
$uid = OCA\Contacts\Addressbook::extractUserID($this->getOwner());
|
$uid = $this->carddavBackend->userIDByPrincipal($this->getOwner());
|
||||||
|
|
||||||
$readWriteACL = array(
|
$readWriteACL = array(
|
||||||
array(
|
array(
|
||||||
'privilege' => '{DAV:}read',
|
'privilege' => '{DAV:}read',
|
||||||
'principal' => 'principals/' . OCP\User::getUser(),
|
'principal' => 'principals/' . \OCP\User::getUser(),
|
||||||
'protected' => true,
|
'protected' => true,
|
||||||
),
|
),
|
||||||
array(
|
array(
|
||||||
'privilege' => '{DAV:}write',
|
'privilege' => '{DAV:}write',
|
||||||
'principal' => 'principals/' . OCP\User::getUser(),
|
'principal' => 'principals/' . \OCP\User::getUser(),
|
||||||
'protected' => true,
|
'protected' => true,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
if($uid != OCP\USER::getUser()) {
|
if($uid !== \OCP\User::getUser()) {
|
||||||
$sharedAddressbook = OCP\Share::getItemSharedWithBySource('addressbook', $this->addressBookInfo['id']);
|
list($backendName, $id) = explode('::', $this->addressBookInfo['id']);
|
||||||
|
$sharedAddressbook = \OCP\Share::getItemSharedWithBySource('addressbook', $id);
|
||||||
if($sharedAddressbook) {
|
if($sharedAddressbook) {
|
||||||
if(($sharedAddressbook['permissions'] & OCP\PERMISSION_CREATE)
|
if(($sharedAddressbook['permissions'] & \OCP\PERMISSION_CREATE)
|
||||||
&& ($sharedAddressbook['permissions'] & OCP\PERMISSION_UPDATE)
|
&& ($sharedAddressbook['permissions'] & \OCP\PERMISSION_UPDATE)
|
||||||
&& ($sharedAddressbook['permissions'] & OCP\PERMISSION_DELETE)
|
&& ($sharedAddressbook['permissions'] & \OCP\PERMISSION_DELETE)
|
||||||
) {
|
) {
|
||||||
return $readWriteACL;
|
return $readWriteACL;
|
||||||
}
|
}
|
||||||
if ($sharedAddressbook['permissions'] & OCP\PERMISSION_CREATE) {
|
if ($sharedAddressbook['permissions'] & \OCP\PERMISSION_CREATE) {
|
||||||
$createprincipal = 'principals/' . OCP\USER::getUser();
|
$createprincipal = 'principals/' . \OCP\User::getUser();
|
||||||
}
|
}
|
||||||
if ($sharedAddressbook['permissions'] & OCP\PERMISSION_READ) {
|
if ($sharedAddressbook['permissions'] & \OCP\PERMISSION_READ) {
|
||||||
$readprincipal = 'principals/' . OCP\USER::getUser();
|
$readprincipal = 'principals/' . \OCP\User::getUser();
|
||||||
}
|
}
|
||||||
if ($sharedAddressbook['permissions'] & OCP\PERMISSION_UPDATE) {
|
if ($sharedAddressbook['permissions'] & \OCP\PERMISSION_UPDATE) {
|
||||||
$writeprincipal = 'principals/' . OCP\USER::getUser();
|
$writeprincipal = 'principals/' . \OCP\User::getUser();
|
||||||
}
|
}
|
||||||
if ($sharedAddressbook['permissions'] & OCP\PERMISSION_DELETE) {
|
if ($sharedAddressbook['permissions'] & \OCP\PERMISSION_DELETE) {
|
||||||
$deleteprincipal = 'principals/' . OCP\USER::getUser();
|
$deleteprincipal = 'principals/' . \OCP\User::getUser();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -198,8 +203,10 @@ class OC_Connector_Sabre_CardDAV_AddressBook extends Sabre_CardDAV_AddressBook {
|
|||||||
public function getChild($name) {
|
public function getChild($name) {
|
||||||
|
|
||||||
$obj = $this->carddavBackend->getCard($this->addressBookInfo['id'],$name);
|
$obj = $this->carddavBackend->getCard($this->addressBookInfo['id'],$name);
|
||||||
if (!$obj) throw new Sabre_DAV_Exception_NotFound('Card not found');
|
if (!$obj) {
|
||||||
return new OC_Connector_Sabre_CardDAV_Card($this->carddavBackend,$this->addressBookInfo,$obj);
|
throw new \Sabre_DAV_Exception_NotFound('Card not found');
|
||||||
|
}
|
||||||
|
return new Card($this->carddavBackend,$this->addressBookInfo,$obj);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -213,7 +220,7 @@ class OC_Connector_Sabre_CardDAV_AddressBook extends Sabre_CardDAV_AddressBook {
|
|||||||
$objs = $this->carddavBackend->getCards($this->addressBookInfo['id']);
|
$objs = $this->carddavBackend->getCards($this->addressBookInfo['id']);
|
||||||
$children = array();
|
$children = array();
|
||||||
foreach($objs as $obj) {
|
foreach($objs as $obj) {
|
||||||
$children[] = new OC_Connector_Sabre_CardDAV_Card($this->carddavBackend,$this->addressBookInfo,$obj);
|
$children[] = new Card($this->carddavBackend,$this->addressBookInfo,$obj);
|
||||||
}
|
}
|
||||||
return $children;
|
return $children;
|
||||||
|
|
@ -20,11 +20,13 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
namespace OCA\Contacts\CardDAV;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class overrides Sabre_CardDAV_AddressBookRoot::getChildForPrincipal()
|
* This class overrides Sabre_CardDAV_AddressBookRoot::getChildForPrincipal()
|
||||||
* to instantiate OC_Connector_CardDAV_UserAddressBooks.
|
* to instantiate OC_Connector_CardDAV_UserAddressBooks.
|
||||||
*/
|
*/
|
||||||
class OC_Connector_Sabre_CardDAV_AddressBookRoot extends Sabre_CardDAV_AddressBookRoot {
|
class AddressBookRoot extends \Sabre_CardDAV_AddressBookRoot {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method returns a node for a principal.
|
* This method returns a node for a principal.
|
||||||
@ -38,7 +40,7 @@ class OC_Connector_Sabre_CardDAV_AddressBookRoot extends Sabre_CardDAV_AddressBo
|
|||||||
*/
|
*/
|
||||||
public function getChildForPrincipal(array $principal) {
|
public function getChildForPrincipal(array $principal) {
|
||||||
|
|
||||||
return new OC_Connector_Sabre_CardDAV_UserAddressBooks($this->carddavBackend, $principal['uri']);
|
return new UserAddressBooks($this->carddavBackend, $principal['uri']);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
258
lib/carddav/backend.php
Normal file
258
lib/carddav/backend.php
Normal file
@ -0,0 +1,258 @@
|
|||||||
|
<?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/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace OCA\Contacts\CardDAV;
|
||||||
|
|
||||||
|
use OCA\Contacts;
|
||||||
|
|
||||||
|
class Backend extends \Sabre_CardDAV_Backend_Abstract {
|
||||||
|
|
||||||
|
public function __construct($backends) {
|
||||||
|
//\OCP\Util::writeLog('contacts', __METHOD__, \OCP\Util::DEBUG);
|
||||||
|
$this->backends = $backends;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the list of addressbooks for a specific user.
|
||||||
|
*
|
||||||
|
* @param string $principaluri
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getAddressBooksForUser($principaluri) {
|
||||||
|
$userid = $this->userIDByPrincipal($principaluri);
|
||||||
|
$userAddressBooks = array();
|
||||||
|
foreach($this->backends as $backend) {
|
||||||
|
$addressBooks = $backend->getAddressBooksForUser($userid);
|
||||||
|
|
||||||
|
foreach($addressBooks as $addressBook) {
|
||||||
|
if($addressBook['owner'] != \OCP\USER::getUser()) {
|
||||||
|
$addressBook['uri'] = $addressBook['uri'] . '_shared_by_' . $addressBook['owner'];
|
||||||
|
$addressBook['displayname'] = $addressBook['displayname'];
|
||||||
|
}
|
||||||
|
$userAddressbooks[] = array(
|
||||||
|
'id' => $backend->name . '::' . $addressBook['id'],
|
||||||
|
'uri' => $addressBook['uri'],
|
||||||
|
'principaluri' => 'principals/'.$addressBook['owner'],
|
||||||
|
'{DAV:}displayname' => $addressBook['displayname'],
|
||||||
|
'{' . \Sabre_CardDAV_Plugin::NS_CARDDAV . '}addressbook-description'
|
||||||
|
=> $addressBook['description'],
|
||||||
|
'{http://calendarserver.org/ns/}getctag' => $addressBook['lastmodified'],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $userAddressbooks;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
$changes = array();
|
||||||
|
|
||||||
|
foreach($mutations as $property=>$newvalue) {
|
||||||
|
switch($property) {
|
||||||
|
case '{DAV:}displayname' :
|
||||||
|
$changes['name'] = $newvalue;
|
||||||
|
break;
|
||||||
|
case '{' . \Sabre_CardDAV_Plugin::NS_CARDDAV
|
||||||
|
. '}addressbook-description' :
|
||||||
|
$changes['description'] = $newvalue;
|
||||||
|
break;
|
||||||
|
default :
|
||||||
|
// If any unsupported values were being updated, we must
|
||||||
|
// let the entire request fail.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
list($id, $backend) = $this->getBackendForAddressBook($addressbookid);
|
||||||
|
return $backend->updateAddressBook($id, $changes);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new address book
|
||||||
|
*
|
||||||
|
* @param string $principaluri
|
||||||
|
* @param string $uri Just the 'basename' of the url.
|
||||||
|
* @param array $properties
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function createAddressBook($principaluri, $uri, array $properties) {
|
||||||
|
|
||||||
|
$properties = array();
|
||||||
|
$userid = $this->userIDByPrincipal($principaluri);
|
||||||
|
|
||||||
|
foreach($properties as $property=>$newvalue) {
|
||||||
|
|
||||||
|
switch($property) {
|
||||||
|
case '{DAV:}displayname' :
|
||||||
|
$properties['displayname'] = $newvalue;
|
||||||
|
break;
|
||||||
|
case '{' . \Sabre_CardDAV_Plugin::NS_CARDDAV
|
||||||
|
. '}addressbook-description' :
|
||||||
|
$properties['description'] = $newvalue;
|
||||||
|
break;
|
||||||
|
default :
|
||||||
|
throw new \Sabre_DAV_Exception_BadRequest('Unknown property: '
|
||||||
|
. $property);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
$properties['uri'] = $uri;
|
||||||
|
|
||||||
|
list(,$backend) = $this->getBackendForAddressBook($addressbookid);
|
||||||
|
$backend->createAddressBook($properties, $userid);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes an entire addressbook and all its contents
|
||||||
|
*
|
||||||
|
* @param int $addressbookid
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function deleteAddressBook($addressbookid) {
|
||||||
|
list($id, $backend) = $this->getBackendForAddressBook($addressbookid);
|
||||||
|
$backend->deleteAddressBook($id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all cards for a specific addressbook id.
|
||||||
|
*
|
||||||
|
* @param mixed $addressbookid
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getCards($addressbookid) {
|
||||||
|
$contacts = array();
|
||||||
|
list($id, $backend) = $this->getBackendForAddressBook($addressbookid);
|
||||||
|
$contacts = $backend->getContacts($id);
|
||||||
|
|
||||||
|
$cards = array();
|
||||||
|
foreach($contacts as $contact) {
|
||||||
|
//OCP\Util::writeLog('contacts', __METHOD__.', uri: ' . $i['uri'], OCP\Util::DEBUG);
|
||||||
|
$cards[] = array(
|
||||||
|
'id' => $contact['id'],
|
||||||
|
//'carddata' => $i['carddata'],
|
||||||
|
'size' => strlen($contact['carddata']),
|
||||||
|
'etag' => '"' . md5($contact['carddata']) . '"',
|
||||||
|
'uri' => $contact['uri'],
|
||||||
|
'lastmodified' => $contact['lastmodified'] );
|
||||||
|
}
|
||||||
|
|
||||||
|
return $cards;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a specfic card
|
||||||
|
*
|
||||||
|
* @param mixed $addressbookid
|
||||||
|
* @param string $carduri
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getCard($addressbookid, $carduri) {
|
||||||
|
\OCP\Util::writeLog('contacts', __METHOD__.' identifier: ' . $carduri . ' ' . print_r($addressbookid, true), \OCP\Util::DEBUG);
|
||||||
|
list($id, $backend) = $this->getBackendForAddressBook($addressbookid);
|
||||||
|
$contact = $backend->getContact($id, array('uri' => $carduri));
|
||||||
|
return ($contact ? $contact : false);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new card
|
||||||
|
*
|
||||||
|
* We don't return an Etag as the carddata can have been modified
|
||||||
|
* by Plugin::validate()
|
||||||
|
*
|
||||||
|
* @see Plugin::validate()
|
||||||
|
* @param mixed $addressbookid
|
||||||
|
* @param string $carduri
|
||||||
|
* @param string $carddata
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function createCard($addressbookid, $carduri, $carddata) {
|
||||||
|
list($id, $backend) = $this->getBackendForAddressBook($addressbookid);
|
||||||
|
$backend->createContact($id, $carddata, $carduri);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates a card
|
||||||
|
*
|
||||||
|
* @param mixed $addressbookid
|
||||||
|
* @param string $carduri
|
||||||
|
* @param string $carddata
|
||||||
|
* @return null
|
||||||
|
*/
|
||||||
|
public function updateCard($addressbookid, $carduri, $carddata) {
|
||||||
|
list($id, $backend) = $this->getBackendForAddressBook($addressbookid);
|
||||||
|
$backend->updateContact($id, array('uri' => $carduri,), $carddata);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes a card
|
||||||
|
*
|
||||||
|
* @param mixed $addressbookid
|
||||||
|
* @param string $carduri
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function deleteCard($addressbookid, $carduri) {
|
||||||
|
list($id, $backend) = $this->getBackendForAddressBook($addressbookid);
|
||||||
|
return $backend->deleteContact($id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief gets the userid from a principal path
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function userIDByPrincipal($principaluri) {
|
||||||
|
list(, $userid) = \Sabre_DAV_URLUtil::splitPath($principaluri);
|
||||||
|
return $userid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the backend for an address book
|
||||||
|
*
|
||||||
|
* @param mixed $addressbookid
|
||||||
|
* @return array(string, \OCA\Contacts\Backend\AbstractBackend)
|
||||||
|
*/
|
||||||
|
public function getBackendForAddressBook($addressbookid) {
|
||||||
|
list($backendName, $id) = explode('::', $addressbookid);
|
||||||
|
foreach($this->backends as $backend) {
|
||||||
|
if($backend->name === $backendName && $backend->hasAddressBook($id)) {
|
||||||
|
return array($id, $backend);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new \Sabre_DAV_Exception_NotFound('Backend not found: ' . $addressbookid);
|
||||||
|
}
|
||||||
|
}
|
@ -20,11 +20,15 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
namespace OCA\Contacts\CardDAV;
|
||||||
|
|
||||||
|
use OCA\Contacts;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class overrides Sabre_CardDAV_Card::getACL()
|
* This class overrides Sabre_CardDAV_Card::getACL()
|
||||||
* to return read/write permissions based on user and shared state.
|
* to return read/write permissions based on user and shared state.
|
||||||
*/
|
*/
|
||||||
class OC_Connector_Sabre_CardDAV_Card extends Sabre_CardDAV_Card {
|
class Card extends \Sabre_CardDAV_Card {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Array with information about the containing addressbook
|
* Array with information about the containing addressbook
|
||||||
@ -40,7 +44,7 @@ class OC_Connector_Sabre_CardDAV_Card extends Sabre_CardDAV_Card {
|
|||||||
* @param array $addressBookInfo
|
* @param array $addressBookInfo
|
||||||
* @param array $cardData
|
* @param array $cardData
|
||||||
*/
|
*/
|
||||||
public function __construct(Sabre_CardDAV_Backend_Abstract $carddavBackend, array $addressBookInfo, array $cardData) {
|
public function __construct(\Sabre_CardDAV_Backend_Abstract $carddavBackend, array $addressBookInfo, array $cardData) {
|
||||||
|
|
||||||
$this->addressBookInfo = $addressBookInfo;
|
$this->addressBookInfo = $addressBookInfo;
|
||||||
parent::__construct($carddavBackend, $addressBookInfo, $cardData);
|
parent::__construct($carddavBackend, $addressBookInfo, $cardData);
|
||||||
@ -63,15 +67,16 @@ class OC_Connector_Sabre_CardDAV_Card extends Sabre_CardDAV_Card {
|
|||||||
|
|
||||||
$readprincipal = $this->getOwner();
|
$readprincipal = $this->getOwner();
|
||||||
$writeprincipal = $this->getOwner();
|
$writeprincipal = $this->getOwner();
|
||||||
$uid = OCA\Contacts\Addressbook::extractUserID($this->getOwner());
|
$uid = $this->carddavBackend->userIDByPrincipal($this->getOwner());
|
||||||
|
|
||||||
if($uid != OCP\USER::getUser()) {
|
if($uid != \OCP\USER::getUser()) {
|
||||||
$sharedAddressbook = OCP\Share::getItemSharedWithBySource('addressbook', $this->addressBookInfo['id']);
|
list($backendName, $id) = explode('::', $this->addressBookInfo['id']);
|
||||||
if ($sharedAddressbook && ($sharedAddressbook['permissions'] & OCP\PERMISSION_READ)) {
|
$sharedAddressbook = \OCP\Share::getItemSharedWithBySource('addressbook', $id);
|
||||||
$readprincipal = 'principals/' . OCP\USER::getUser();
|
if ($sharedAddressbook && ($sharedAddressbook['permissions'] & \OCP\PERMISSION_READ)) {
|
||||||
|
$readprincipal = 'principals/' . \OCP\USER::getUser();
|
||||||
}
|
}
|
||||||
if ($sharedAddressbook && ($sharedAddressbook['permissions'] & OCP\PERMISSION_UPDATE)) {
|
if ($sharedAddressbook && ($sharedAddressbook['permissions'] & \OCP\PERMISSION_UPDATE)) {
|
||||||
$writeprincipal = 'principals/' . OCP\USER::getUser();
|
$writeprincipal = 'principals/' . \OCP\USER::getUser();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
69
lib/carddav/plugin.php
Normal file
69
lib/carddav/plugin.php
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* ownCloud - CardDAV plugin
|
||||||
|
*
|
||||||
|
* The CardDAV plugin adds CardDAV functionality to the WebDAV server
|
||||||
|
*
|
||||||
|
* @author Thomas Tanghus
|
||||||
|
* @copyright 2013 Thomas Tanghus (thomas@tanghus.net)
|
||||||
|
*
|
||||||
|
* 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\CardDAV;
|
||||||
|
|
||||||
|
use Sabre\VObject;
|
||||||
|
use OCA\Contacts\VObject\VCard;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class overrides Sabre_CardDAV_Plugin::validateVCard() to be able
|
||||||
|
* to import partially invalid vCards by ignoring invalid lines and to
|
||||||
|
* validate and upgrade using \OCA\Contacts\VCard.
|
||||||
|
*/
|
||||||
|
class Plugin extends \Sabre_CardDAV_Plugin {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the submitted vCard data is in fact, valid.
|
||||||
|
*
|
||||||
|
* An exception is thrown if it's not.
|
||||||
|
*
|
||||||
|
* @param resource|string $data
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
protected function validateVCard(&$data) {
|
||||||
|
\OCP\Util::writeLog('contacts', __METHOD__, \OCP\Util::DEBUG);
|
||||||
|
|
||||||
|
// If it's a stream, we convert it to a string first.
|
||||||
|
if (is_resource($data)) {
|
||||||
|
$data = stream_get_contents($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Converting the data to unicode, if needed.
|
||||||
|
$data = \Sabre_DAV_StringUtil::ensureUTF8($data);
|
||||||
|
|
||||||
|
try {
|
||||||
|
$vobj = VObject\Reader::read($data, VObject\Reader::OPTION_IGNORE_INVALID_LINES);
|
||||||
|
} catch (VObject\ParseException $e) {
|
||||||
|
throw new \Sabre_DAV_Exception_UnsupportedMediaType('This resource only supports valid vcard data. Parse error: ' . $e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($vobj->name !== 'VCARD') {
|
||||||
|
throw new \Sabre_DAV_Exception_UnsupportedMediaType('This collection can only support vcard objects.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$vobj->validate(VCard::REPAIR|VCard::UPGRADE);
|
||||||
|
$data = $vobj->serialize();
|
||||||
|
}
|
||||||
|
}
|
@ -20,11 +20,13 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
namespace OCA\Contacts\CardDAV;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class overrides Sabre_CardDAV_UserAddressBooks::getChildren()
|
* This class overrides Sabre_CardDAV_UserAddressBooks::getChildren()
|
||||||
* to instantiate OC_Connector_Sabre_CardDAV_AddressBooks.
|
* to instantiate \OCA\Contacts\CardDAV\AddressBooks.
|
||||||
*/
|
*/
|
||||||
class OC_Connector_Sabre_CardDAV_UserAddressBooks extends Sabre_CardDAV_UserAddressBooks {
|
class UserAddressBooks extends \Sabre_CardDAV_UserAddressBooks {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a list of addressbooks
|
* Returns a list of addressbooks
|
||||||
@ -36,7 +38,7 @@ class OC_Connector_Sabre_CardDAV_UserAddressBooks extends Sabre_CardDAV_UserAddr
|
|||||||
$addressbooks = $this->carddavBackend->getAddressbooksForUser($this->principalUri);
|
$addressbooks = $this->carddavBackend->getAddressbooksForUser($this->principalUri);
|
||||||
$objs = array();
|
$objs = array();
|
||||||
foreach($addressbooks as $addressbook) {
|
foreach($addressbooks as $addressbook) {
|
||||||
$objs[] = new OC_Connector_Sabre_CardDAV_AddressBook($this->carddavBackend, $addressbook);
|
$objs[] = new AddressBook($this->carddavBackend, $addressbook);
|
||||||
}
|
}
|
||||||
return $objs;
|
return $objs;
|
||||||
|
|
647
lib/contact.php
Normal file
647
lib/contact.php
Normal file
@ -0,0 +1,647 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* ownCloud - Contact object
|
||||||
|
*
|
||||||
|
* @author Thomas Tanghus
|
||||||
|
* @copyright 2012 Thomas Tanghus (thomas@tanghus.net)
|
||||||
|
*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
use Sabre\VObject\Property;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subclass this class or implement IPIMObject interface for PIM objects
|
||||||
|
*/
|
||||||
|
|
||||||
|
class Contact extends VObject\VCard implements IPIMObject {
|
||||||
|
|
||||||
|
const THUMBNAIL_PREFIX = 'contact-thumbnail-';
|
||||||
|
const THUMBNAIL_SIZE = 28;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the object type in this case VCARD.
|
||||||
|
*
|
||||||
|
* This is used when serializing the object.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $name = 'VCARD';
|
||||||
|
|
||||||
|
protected $props = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new Contact object
|
||||||
|
*
|
||||||
|
* @param AddressBook $parent
|
||||||
|
* @param AbstractBackend $backend
|
||||||
|
* @param mixed $data
|
||||||
|
*/
|
||||||
|
public function __construct($parent, $backend, $data = null) {
|
||||||
|
//\OCP\Util::writeLog('contacts', __METHOD__ . ' ' . print_r($data, true), \OCP\Util::DEBUG);
|
||||||
|
//\OCP\Util::writeLog('contacts', __METHOD__, \OCP\Util::DEBUG);
|
||||||
|
$this->props['parent'] = $parent;
|
||||||
|
$this->props['backend'] = $backend;
|
||||||
|
$this->props['retrieved'] = false;
|
||||||
|
$this->props['saved'] = false;
|
||||||
|
|
||||||
|
if(!is_null($data)) {
|
||||||
|
if($data instanceof VObject\VCard) {
|
||||||
|
foreach($data->children as $child) {
|
||||||
|
$this->add($child);
|
||||||
|
$this->setRetrieved(true);
|
||||||
|
}
|
||||||
|
} elseif(is_array($data)) {
|
||||||
|
foreach($data as $key => $value) {
|
||||||
|
switch($key) {
|
||||||
|
case 'id':
|
||||||
|
$this->props['id'] = $value;
|
||||||
|
break;
|
||||||
|
case 'lastmodified':
|
||||||
|
$this->props['lastmodified'] = $value;
|
||||||
|
break;
|
||||||
|
case 'uri':
|
||||||
|
$this->props['uri'] = $value;
|
||||||
|
break;
|
||||||
|
case 'carddata':
|
||||||
|
$this->props['carddata'] = $value;
|
||||||
|
$this->retrieve();
|
||||||
|
break;
|
||||||
|
case 'vcard':
|
||||||
|
$this->props['vcard'] = $value;
|
||||||
|
$this->retrieve();
|
||||||
|
break;
|
||||||
|
case 'displayname':
|
||||||
|
case 'fullname':
|
||||||
|
$this->props['displayname'] = $value;
|
||||||
|
$this->FN = $value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array|null
|
||||||
|
*/
|
||||||
|
public function getMetaData() {
|
||||||
|
if(!isset($this->props['displayname'])) {
|
||||||
|
if(!$this->retrieve()) {
|
||||||
|
\OCP\Util::writeLog('contacts', __METHOD__.' error reading: '.print_r($this->props, true), \OCP\Util::ERROR);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return array(
|
||||||
|
'id' => $this->getId(),
|
||||||
|
'displayname' => $this->getDisplayName(),
|
||||||
|
'permissions' => $this->getPermissions(),
|
||||||
|
'lastmodified' => $this->lastModified(),
|
||||||
|
'owner' => $this->getOwner(),
|
||||||
|
'parent' => $this->getParent()->getId(),
|
||||||
|
'backend' => $this->getBackend()->name,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a unique key combined of backend name, address book id and contact id.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function combinedKey() {
|
||||||
|
return $this->getBackend()->name . '::' . $this->getParent()->getId() . '::' . $this->getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function getOwner() {
|
||||||
|
return $this->props['parent']->getOwner();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function getId() {
|
||||||
|
return isset($this->props['id']) ? $this->props['id'] : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
function getDisplayName() {
|
||||||
|
return isset($this->props['displayname']) ? $this->props['displayname'] : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function getURI() {
|
||||||
|
return isset($this->props['uri']) ? $this->props['uri'] : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If this object is part of a collection return a reference
|
||||||
|
* to the parent object, otherwise return null.
|
||||||
|
* @return IPIMObject|null
|
||||||
|
*/
|
||||||
|
function getParent() {
|
||||||
|
return $this->props['parent'];
|
||||||
|
}
|
||||||
|
|
||||||
|
function getBackend() {
|
||||||
|
return $this->props['backend'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** CRUDS permissions (Create, Read, Update, Delete, Share)
|
||||||
|
*
|
||||||
|
* @return integer
|
||||||
|
*/
|
||||||
|
function getPermissions() {
|
||||||
|
return $this->props['parent']->getPermissions();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param integer $permission
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
function hasPermission($permission) {
|
||||||
|
return $this->getPermissions() & $permission;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save the address book data to backend
|
||||||
|
* FIXME
|
||||||
|
*
|
||||||
|
* @param array $data
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function update(array $data) {
|
||||||
|
|
||||||
|
foreach($data as $key => $value) {
|
||||||
|
switch($key) {
|
||||||
|
case 'displayname':
|
||||||
|
$this->addressBookInfo['displayname'] = $value;
|
||||||
|
break;
|
||||||
|
case 'description':
|
||||||
|
$this->addressBookInfo['description'] = $value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $this->props['backend']->updateContact(
|
||||||
|
$this->getParent()->getId(),
|
||||||
|
$this->getId(),
|
||||||
|
$this
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete the data from backend
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function delete() {
|
||||||
|
return $this->props['backend']->deleteContact(
|
||||||
|
$this->getParent()->getId(),
|
||||||
|
$this->getId()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save the contact data to backend
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function save($force = false) {
|
||||||
|
if($this->isSaved() && !$force) {
|
||||||
|
\OCP\Util::writeLog('contacts', __METHOD__.' Already saved: ' . print_r($this->props, true), \OCP\Util::DEBUG);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if(isset($this->FN)) {
|
||||||
|
$this->props['displayname'] = (string)$this->FN;
|
||||||
|
}
|
||||||
|
if($this->getId()) {
|
||||||
|
if($this->props['backend']
|
||||||
|
->updateContact(
|
||||||
|
$this->getParent()->getId(),
|
||||||
|
$this->getId(),
|
||||||
|
$this->serialize()
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
$this->props['lastmodified'] = time();
|
||||||
|
$this->setSaved(true);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//print(__METHOD__.' ' . print_r($this->getParent(), true));
|
||||||
|
$this->props['id'] = $this->props['backend']->createContact(
|
||||||
|
$this->getParent()->getId(), $this
|
||||||
|
);
|
||||||
|
$this->setSaved(true);
|
||||||
|
return $this->getId() !== false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the data from the backend
|
||||||
|
* FIXME: Clean this up and make sure the logic is OK.
|
||||||
|
*/
|
||||||
|
public function retrieve() {
|
||||||
|
//error_log(__METHOD__);
|
||||||
|
//\OCP\Util::writeLog('contacts', __METHOD__.' ' . print_r($this->props, true), \OCP\Util::DEBUG);
|
||||||
|
if($this->isRetrieved()) {
|
||||||
|
//\OCP\Util::writeLog('contacts', __METHOD__. ' children', \OCP\Util::DEBUG);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
$data = null;
|
||||||
|
if(isset($this->props['vcard'])
|
||||||
|
&& $this->props['vcard'] instanceof VObject\VCard) {
|
||||||
|
foreach($this->props['vcard']->children() as $child) {
|
||||||
|
$this->add($child);
|
||||||
|
if($child->name === 'FN') {
|
||||||
|
$this->props['displayname']
|
||||||
|
= strtr($child->value, array('\,' => ',', '\;' => ';', '\\\\' => '\\'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$this->setRetrieved(true);
|
||||||
|
//$this->children = $this->props['vcard']->children();
|
||||||
|
unset($this->props['vcard']);
|
||||||
|
return true;
|
||||||
|
} elseif(!isset($this->props['carddata'])) {
|
||||||
|
$result = $this->props['backend']->getContact(
|
||||||
|
$this->getParent()->getId(),
|
||||||
|
$this->id
|
||||||
|
);
|
||||||
|
if($result) {
|
||||||
|
if(isset($result['vcard'])
|
||||||
|
&& $result['vcard'] instanceof VObject\VCard) {
|
||||||
|
foreach($result['vcard']->children() as $child) {
|
||||||
|
$this->add($child);
|
||||||
|
}
|
||||||
|
$this->setRetrieved(true);
|
||||||
|
return true;
|
||||||
|
} elseif(isset($result['carddata'])) {
|
||||||
|
// Save internal values
|
||||||
|
$data = $result['carddata'];
|
||||||
|
$this->props['carddata'] = $result['carddata'];
|
||||||
|
$this->props['lastmodified'] = $result['lastmodified'];
|
||||||
|
$this->props['displayname'] = $result['displayname'];
|
||||||
|
$this->props['permissions'] = $result['permissions'];
|
||||||
|
} else {
|
||||||
|
\OCP\Util::writeLog('contacts', __METHOD__
|
||||||
|
. ' Could not get vcard or carddata: '
|
||||||
|
. $this->getId()
|
||||||
|
. print_r($result, true), \OCP\Util::DEBUG);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
\OCP\Util::writeLog('contacts', __METHOD__.' Error getting contact: ' . $this->getId(), \OCP\Util::DEBUG);
|
||||||
|
}
|
||||||
|
} elseif(isset($this->props['carddata'])) {
|
||||||
|
$data = $this->props['carddata'];
|
||||||
|
//error_log(__METHOD__.' data: '.print_r($data, true));
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
$obj = \Sabre\VObject\Reader::read(
|
||||||
|
$data,
|
||||||
|
\Sabre\VObject\Reader::OPTION_IGNORE_INVALID_LINES
|
||||||
|
);
|
||||||
|
if($obj) {
|
||||||
|
foreach($obj->children as $child) {
|
||||||
|
$this->add($child);
|
||||||
|
}
|
||||||
|
$this->setRetrieved(true);
|
||||||
|
} else {
|
||||||
|
\OCP\Util::writeLog('contacts', __METHOD__.' Error reading: ' . print_r($data, true), \OCP\Util::DEBUG);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
\OCP\Util::writeLog('contacts', __METHOD__ .
|
||||||
|
' Error parsing carddata for: ' . $this->getId() . ' ' . $e->getMessage(),
|
||||||
|
\OCP\Util::ERROR);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a property index in the contact by the checksum of its serialized value
|
||||||
|
*
|
||||||
|
* @param string $checksum An 8 char m5d checksum.
|
||||||
|
* @return \Sabre\VObject\Property Property by reference
|
||||||
|
* @throws An exception with error code 404 if the property is not found.
|
||||||
|
*/
|
||||||
|
public function getPropertyIndexByChecksum($checksum) {
|
||||||
|
$this->retrieve();
|
||||||
|
$idx = 0;
|
||||||
|
foreach($this->children as $i => &$property) {
|
||||||
|
if(substr(md5($property->serialize()), 0, 8) == $checksum ) {
|
||||||
|
return $idx;
|
||||||
|
}
|
||||||
|
$idx += 1;
|
||||||
|
}
|
||||||
|
throw new Exception('Property not found', 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a property by the checksum of its serialized value
|
||||||
|
*
|
||||||
|
* @param string $checksum An 8 char m5d checksum.
|
||||||
|
* @return \Sabre\VObject\Property Property by reference
|
||||||
|
* @throws An exception with error code 404 if the property is not found.
|
||||||
|
*/
|
||||||
|
public function getPropertyByChecksum($checksum) {
|
||||||
|
$this->retrieve();
|
||||||
|
foreach($this->children as $i => &$property) {
|
||||||
|
if(substr(md5($property->serialize()), 0, 8) == $checksum ) {
|
||||||
|
return $property;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new \Exception('Property not found', 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete a property by the checksum of its serialized value
|
||||||
|
* It is up to the caller to call ->save()
|
||||||
|
*
|
||||||
|
* @param string $checksum An 8 char m5d checksum.
|
||||||
|
* @throws @see getPropertyByChecksum
|
||||||
|
*/
|
||||||
|
public function unsetPropertyByChecksum($checksum) {
|
||||||
|
$idx = $this->getPropertyIndexByChecksum($checksum);
|
||||||
|
unset($this->children[$idx]);
|
||||||
|
$this->setSaved(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a property by the checksum of its serialized value
|
||||||
|
* It is up to the caller to call ->save()
|
||||||
|
*
|
||||||
|
* @param string $checksum An 8 char m5d checksum.
|
||||||
|
* @param string $name Property name
|
||||||
|
* @param mixed $value
|
||||||
|
* @param array $parameters
|
||||||
|
* @throws @see getPropertyByChecksum
|
||||||
|
* @return string new checksum
|
||||||
|
*/
|
||||||
|
public function setPropertyByChecksum($checksum, $name, $value, $parameters=array()) {
|
||||||
|
// FIXME: Change the debug and bailOut calls
|
||||||
|
if($checksum === 'new') {
|
||||||
|
$property = Property::create($name);
|
||||||
|
$this->add($property);
|
||||||
|
} else {
|
||||||
|
$property = $this->getPropertyByChecksum($checksum);
|
||||||
|
}
|
||||||
|
switch($name) {
|
||||||
|
case 'EMAIL':
|
||||||
|
$value = strtolower($value);
|
||||||
|
$property->setValue($value);
|
||||||
|
break;
|
||||||
|
case 'ADR':
|
||||||
|
if(is_array($value)) {
|
||||||
|
$property->setParts($value);
|
||||||
|
} else {
|
||||||
|
debug('Saving ADR ' . $value);
|
||||||
|
$property->setValue($value);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'IMPP':
|
||||||
|
if(is_null($parameters) || !isset($parameters['X-SERVICE-TYPE'])) {
|
||||||
|
bailOut(App::$l10n->t('Missing IM parameter.'));
|
||||||
|
}
|
||||||
|
$impp = Utils\Properties::getIMOptions($parameters['X-SERVICE-TYPE']);
|
||||||
|
if(is_null($impp)) {
|
||||||
|
bailOut(App::$l10n->t('Unknown IM: '.$parameters['X-SERVICE-TYPE']));
|
||||||
|
}
|
||||||
|
$value = $impp['protocol'] . ':' . $value;
|
||||||
|
$property->setValue($value);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
\OCP\Util::writeLog('contacts', __METHOD__.' adding: '.$name. ' ' . $value, \OCP\Util::DEBUG);
|
||||||
|
$property->setValue($value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$this->setParameters($property, $parameters);
|
||||||
|
$this->setSaved(false);
|
||||||
|
return substr(md5($property->serialize()), 0, 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a property by the property name.
|
||||||
|
* It is up to the caller to call ->save()
|
||||||
|
*
|
||||||
|
* @param string $name Property name
|
||||||
|
* @param mixed $value
|
||||||
|
* @param array $parameters
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function setPropertyByName($name, $value, $parameters=array()) {
|
||||||
|
// TODO: parameters are ignored for now.
|
||||||
|
switch($name) {
|
||||||
|
case 'BDAY':
|
||||||
|
try {
|
||||||
|
$date = New \DateTime($value);
|
||||||
|
} catch(\Exception $e) {
|
||||||
|
\OCP\Util::writeLog('contacts',
|
||||||
|
__METHOD__.' DateTime exception: ' . $e->getMessage(),
|
||||||
|
\OCP\Util::ERROR
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$value = $date->format('Y-m-d');
|
||||||
|
$this->BDAY = $value;
|
||||||
|
$this->BDAY->add('VALUE', 'DATE');
|
||||||
|
//\OCP\Util::writeLog('contacts', __METHOD__.' BDAY: '.$this->BDAY->serialize(), \OCP\Util::DEBUG);
|
||||||
|
break;
|
||||||
|
case 'CATEGORIES':
|
||||||
|
case 'N':
|
||||||
|
case 'ORG':
|
||||||
|
$property = $this->select($name);
|
||||||
|
if(count($property) === 0) {
|
||||||
|
$property = \Sabre\VObject\Property::create($name);
|
||||||
|
$this->add($property);
|
||||||
|
} else {
|
||||||
|
// Actually no idea why this works
|
||||||
|
$property = array_shift($property);
|
||||||
|
}
|
||||||
|
if(is_array($value)) {
|
||||||
|
$property->setParts($value);
|
||||||
|
} else {
|
||||||
|
$this->{$name} = $value;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
\OCP\Util::writeLog('contacts', __METHOD__.' adding: '.$name. ' ' . $value, \OCP\Util::DEBUG);
|
||||||
|
$this->{$name} = $value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$this->setSaved(false);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function setParameters($property, $parameters, $reset = false) {
|
||||||
|
if(!$parameters) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if($reset) {
|
||||||
|
$property->parameters = array();
|
||||||
|
}
|
||||||
|
debug('Setting parameters: ' . print_r($parameters, true));
|
||||||
|
foreach($parameters as $key => $parameter) {
|
||||||
|
debug('Adding parameter: ' . $key);
|
||||||
|
if(is_array($parameter)) {
|
||||||
|
foreach($parameter as $val) {
|
||||||
|
if(is_array($val)) {
|
||||||
|
foreach($val as $val2) {
|
||||||
|
if(trim($key) && trim($val2)) {
|
||||||
|
debug('Adding parameter: '.$key.'=>'.print_r($val2, true));
|
||||||
|
$property->add($key, strip_tags($val2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(trim($key) && trim($val)) {
|
||||||
|
debug('Adding parameter: '.$key.'=>'.print_r($val, true));
|
||||||
|
$property->add($key, strip_tags($val));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(trim($key) && trim($parameter)) {
|
||||||
|
debug('Adding parameter: '.$key.'=>'.print_r($parameter, true));
|
||||||
|
$property->add($key, strip_tags($parameter));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function lastModified() {
|
||||||
|
if(!isset($this->props['lastmodified'])) {
|
||||||
|
$this->retrieve();
|
||||||
|
}
|
||||||
|
return isset($this->props['lastmodified'])
|
||||||
|
? $this->props['lastmodified']
|
||||||
|
: null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Merge in data from a multi-dimentional array
|
||||||
|
*
|
||||||
|
* NOTE: This is *NOT* tested!
|
||||||
|
* The data array has this structure:
|
||||||
|
*
|
||||||
|
* array(
|
||||||
|
* 'EMAIL' => array(array('value' => 'johndoe@example.com', 'parameters' = array('TYPE' => array('HOME','VOICE'))))
|
||||||
|
* );
|
||||||
|
* @param array $data
|
||||||
|
*/
|
||||||
|
public function mergeFromArray(array $data) {
|
||||||
|
foreach($data as $name => $properties) {
|
||||||
|
if(in_array($name, array('PHOTO', 'UID'))) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(!is_array($properties)) {
|
||||||
|
\OCP\Util::writeLog('contacts', __METHOD__.' not an array?: ' .$name. ' '.print_r($properties, true), \OCP\Util::DEBUG);
|
||||||
|
}
|
||||||
|
if(in_array($name, Utils\Properties::$multi_properties)) {
|
||||||
|
unset($this->{$name});
|
||||||
|
}
|
||||||
|
foreach($properties as $parray) {
|
||||||
|
//$property = Property::create($name, $parray['value'], $parray['parameters']);
|
||||||
|
\OCP\Util::writeLog('contacts', __METHOD__.' adding: ' .$name. ' '.print_r($parray['value'], true) . ' ' . print_r($parray['parameters'], true), \OCP\Util::DEBUG);
|
||||||
|
if(in_array($name, Utils\Properties::$multi_properties)) {
|
||||||
|
// TODO: wrap in try/catch, check return value
|
||||||
|
$this->setPropertyByChecksum('new', $name, $parray['value'], $parray['parameters']);
|
||||||
|
} else {
|
||||||
|
// TODO: Check return value
|
||||||
|
if(!isset($this->{$name})) {
|
||||||
|
$this->setPropertyByName($name, $parray['value'], $parray['parameters']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//$this->add($name, $parray['value'], $parray['parameters']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$this->setSaved(false);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function cacheThumbnail(\OC_Image $image = null) {
|
||||||
|
$key = self::THUMBNAIL_PREFIX . $this->combinedKey();
|
||||||
|
//\OC_Cache::remove($key);
|
||||||
|
if(\OC_Cache::hasKey($key) && $image === null) {
|
||||||
|
return \OC_Cache::get($key);
|
||||||
|
}
|
||||||
|
if(is_null($image)) {
|
||||||
|
$this->retrieve();
|
||||||
|
$image = new \OC_Image();
|
||||||
|
if(!isset($this->PHOTO) && !isset($this->LOGO)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if(!$image->loadFromBase64((string)$this->PHOTO)) {
|
||||||
|
if(!$image->loadFromBase64((string)$this->LOGO)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!$image->centerCrop()) {
|
||||||
|
\OCP\Util::writeLog('contacts',
|
||||||
|
'thumbnail.php. Couldn\'t crop thumbnail for ID ' . $key,
|
||||||
|
\OCP\Util::ERROR);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if(!$image->resize(self::THUMBNAIL_SIZE)) {
|
||||||
|
\OCP\Util::writeLog('contacts',
|
||||||
|
'thumbnail.php. Couldn\'t resize thumbnail for ID ' . $key,
|
||||||
|
\OCP\Util::ERROR);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Cache as base64 for around a month
|
||||||
|
\OC_Cache::set($key, strval($image), 3000000);
|
||||||
|
\OCP\Util::writeLog('contacts', 'Caching ' . $key, \OCP\Util::DEBUG);
|
||||||
|
return \OC_Cache::get($key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __set($key, $value) {
|
||||||
|
parent::__set($key, $value);
|
||||||
|
$this->setSaved(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __unset($key) {
|
||||||
|
parent::__unset($key);
|
||||||
|
$this->setSaved(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function setRetrieved($state) {
|
||||||
|
$this->props['retrieved'] = $state;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function isRetrieved() {
|
||||||
|
return $this->props['retrieved'];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function setSaved($state) {
|
||||||
|
$this->props['saved'] = $state;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function isSaved() {
|
||||||
|
return $this->props['saved'];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
103
lib/hooks.php
103
lib/hooks.php
@ -42,8 +42,8 @@ class Hooks{
|
|||||||
* @param paramters parameters from postCreateUser-Hook
|
* @param paramters parameters from postCreateUser-Hook
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
static public function createUser($parameters) {
|
public static function userCreated($parameters) {
|
||||||
Addressbook::addDefault($parameters['uid']);
|
//Addressbook::addDefault($parameters['uid']);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,17 +52,101 @@ class Hooks{
|
|||||||
* @param paramters parameters from postDeleteUser-Hook
|
* @param paramters parameters from postDeleteUser-Hook
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
static public function deleteUser($parameters) {
|
public static function userDeleted($parameters) {
|
||||||
$addressbooks = Addressbook::all($parameters['uid']);
|
$backend = new Backend\Database();
|
||||||
|
$addressbook = $backend->getAddressBooksForUser($parameters['uid']);
|
||||||
|
|
||||||
foreach($addressbooks as $addressbook) {
|
foreach($addressbooks as $addressbook) {
|
||||||
Addressbook::delete($addressbook['id']);
|
// Purging of contact categories and and properties is done by backend.
|
||||||
|
$backend->deleteAddressBook($addressbook['id']);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static public function getCalenderSources($parameters) {
|
/**
|
||||||
|
* Delete any registred address books (Future)
|
||||||
|
*/
|
||||||
|
public static function addressBookDeletion($parameters) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function contactDeletion($parameters) {
|
||||||
|
$catctrl = new \OC_VCategories('contact');
|
||||||
|
$catctrl->purgeObjects(array($parameters['id']));
|
||||||
|
Utils\Properties::updateIndex($parameters['id']);
|
||||||
|
|
||||||
|
// Contact sharing not implemented, but keep for future.
|
||||||
|
//\OCP\Share::unshareAll('contact', $id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function contactUpdated($parameters) {
|
||||||
|
//\OCP\Util::writeLog('contacts', __METHOD__.' parameters: '.print_r($parameters, true), \OCP\Util::DEBUG);
|
||||||
|
$catctrl = new \OC_VCategories('contact');
|
||||||
|
$catctrl->loadFromVObject(
|
||||||
|
$parameters['id'],
|
||||||
|
new \OC_VObject($parameters['contact']), // OC_VCategories still uses OC_VObject
|
||||||
|
true // force save
|
||||||
|
);
|
||||||
|
Utils\Properties::updateIndex($parameters['id'], $parameters['contact']);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scan vCards for categories.
|
||||||
|
*/
|
||||||
|
public static function scanCategories() {
|
||||||
|
$offset = 0;
|
||||||
|
$limit = 10;
|
||||||
|
|
||||||
|
$categories = new \OC_VCategories('contact');
|
||||||
|
|
||||||
|
$app = new App();
|
||||||
|
$backend = $app->getBackend('local');
|
||||||
|
$addressBookInfos = $backend->getAddressBooksForUser();
|
||||||
|
|
||||||
|
foreach($addressBookInfos as $addressBookInfo) {
|
||||||
|
$addressBook = new AddressBook($backend, $addressBookInfo);
|
||||||
|
while($contacts = $addressBook->getChildren($limit, $offset, false)) {
|
||||||
|
foreach($contacts as $contact) {
|
||||||
|
$cards[] = array($contact['id'], $contact['carddata']);
|
||||||
|
}
|
||||||
|
\OCP\Util::writeLog('contacts',
|
||||||
|
__CLASS__.'::'.__METHOD__
|
||||||
|
.', scanning: ' . $limit . ' starting from ' . $offset,
|
||||||
|
\OCP\Util::DEBUG);
|
||||||
|
// only reset on first batch.
|
||||||
|
$categories->rescan($cards, true, ($offset === 0 ? true : false));
|
||||||
|
$offset += $limit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scan vCards for categories.
|
||||||
|
*/
|
||||||
|
public static function indexProperties() {
|
||||||
|
$offset = 0;
|
||||||
|
$limit = 10;
|
||||||
|
|
||||||
|
$app = new App();
|
||||||
|
$backend = $app->getBackend('local');
|
||||||
|
$addressBookInfos = $backend->getAddressBooksForUser();
|
||||||
|
|
||||||
|
foreach($addressBookInfos as $addressBookInfo) {
|
||||||
|
$addressBook = new AddressBook($backend, $addressBookInfo);
|
||||||
|
while($contacts = $addressBook->getChildren($limit, $offset, false)) {
|
||||||
|
foreach($contacts as $contact) {
|
||||||
|
$contact->retrieve();
|
||||||
|
}
|
||||||
|
\OCP\Util::writeLog('contacts',
|
||||||
|
__CLASS__.'::'.__METHOD__
|
||||||
|
.', indexing: ' . $limit . ' starting from ' . $offset,
|
||||||
|
\OCP\Util::DEBUG);
|
||||||
|
Utils\Properties::updateIndex($contact->getId(), $contact);
|
||||||
|
$offset += $limit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getCalenderSources($parameters) {
|
||||||
|
/*
|
||||||
$base_url = \OCP\Util::linkTo('calendar', 'ajax/events.php').'?calendar_id=';
|
$base_url = \OCP\Util::linkTo('calendar', 'ajax/events.php').'?calendar_id=';
|
||||||
foreach(Addressbook::all(\OCP\USER::getUser()) as $addressbook) {
|
foreach(Addressbook::all(\OCP\USER::getUser()) as $addressbook) {
|
||||||
$parameters['sources'][]
|
$parameters['sources'][]
|
||||||
@ -75,9 +159,10 @@ class Hooks{
|
|||||||
'editable' => false,
|
'editable' => false,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
static public function getBirthdayEvents($parameters) {
|
public static function getBirthdayEvents($parameters) {
|
||||||
$name = $parameters['calendar_id'];
|
$name = $parameters['calendar_id'];
|
||||||
if (strpos($name, 'birthday_') != 0) {
|
if (strpos($name, 'birthday_') != 0) {
|
||||||
return;
|
return;
|
||||||
|
139
lib/ipimobject.php
Normal file
139
lib/ipimobject.php
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* ownCloud - Interface for PIM object
|
||||||
|
*
|
||||||
|
* @author Thomas Tanghus
|
||||||
|
* @copyright 2013 Thomas Tanghus (thomas@tanghus.net)
|
||||||
|
*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implement this interface for PIM objects
|
||||||
|
*/
|
||||||
|
|
||||||
|
interface IPIMObject {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If this object is part of a collection return a reference
|
||||||
|
* to the parent object, otherwise return null.
|
||||||
|
* @return IPIMObject|null
|
||||||
|
*/
|
||||||
|
//function getParent();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the identifier for the object.
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getId();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A convenience method for getting all the info about the object.
|
||||||
|
*
|
||||||
|
* The returned array MUST contain:
|
||||||
|
* 'id' @see getId().
|
||||||
|
* 'displayname' @see getDisplayName()
|
||||||
|
* 'owner' @see getOwner()
|
||||||
|
* 'permissions' @see getPermissions
|
||||||
|
* 'lastmodified' @see lastModified()
|
||||||
|
*
|
||||||
|
* If the object is part of a collection it MUST contain
|
||||||
|
* 'parent' The identifier for the parent object. @see getParent()
|
||||||
|
*
|
||||||
|
* @return array|null
|
||||||
|
*/
|
||||||
|
public function getMetaData();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FIXME: This should probably not be in the interface
|
||||||
|
* as it's *DAV specific.
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getURI();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
function getDisplayName();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the owner of the object.
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
function getOwner();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If this object is part of a collection return a reference
|
||||||
|
* to the parent object, otherwise return null.
|
||||||
|
* @return IPIMObject|null
|
||||||
|
*/
|
||||||
|
function getParent();
|
||||||
|
|
||||||
|
|
||||||
|
/** CRUDS permissions (Create, Read, Update, Delete, Share) using a bitmask of
|
||||||
|
*
|
||||||
|
* \OCP\PERMISSION_CREATE
|
||||||
|
* \OCP\PERMISSION_READ
|
||||||
|
* \OCP\PERMISSION_UPDATE
|
||||||
|
* \OCP\PERMISSION_DELETE
|
||||||
|
* \OCP\PERMISSION_SHARE
|
||||||
|
* or
|
||||||
|
* \OCP\PERMISSION_ALL
|
||||||
|
*
|
||||||
|
* @return integer
|
||||||
|
*/
|
||||||
|
function getPermissions();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return AbstractBackend
|
||||||
|
*/
|
||||||
|
function getBackend();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param integer $permission
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
function hasPermission($permission);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save the contact data to backend
|
||||||
|
* FIXME: This isn't consistent. We need a proper interface
|
||||||
|
* for creating new instances and saving to storage.
|
||||||
|
*
|
||||||
|
* @param array $data
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function update(array $data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the last modification time for the object.
|
||||||
|
*
|
||||||
|
* Must return a UNIX time stamp or null if the backend
|
||||||
|
* doesn't support it.
|
||||||
|
*
|
||||||
|
* @returns int | null
|
||||||
|
*/
|
||||||
|
public function lastModified();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete the data from backend
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function delete();
|
||||||
|
|
||||||
|
}
|
208
lib/request.php
Normal file
208
lib/request.php
Normal file
@ -0,0 +1,208 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* ownCloud - Request
|
||||||
|
*
|
||||||
|
* @author Thomas Tanghus
|
||||||
|
* @copyright 2013 Thomas Tanghus (thomas@tanghus.net)
|
||||||
|
*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class for accessing variables in the request.
|
||||||
|
* This class provides an immutable object with request variables.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class Request implements \ArrayAccess, \Countable {
|
||||||
|
|
||||||
|
protected $items = array();
|
||||||
|
|
||||||
|
protected $varnames = array('get', 'post', 'files', 'server', 'env', 'session', 'cookies', 'urlParams', 'params', 'parameters', 'method');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $vars And associative array with the following optional values:
|
||||||
|
* @param array 'params' the parsed json array
|
||||||
|
* @param array 'urlParams' the parameters which were matched from the URL
|
||||||
|
* @param array 'get' the $_GET array
|
||||||
|
* @param array 'post' the $_POST array
|
||||||
|
* @param array 'files' the $_FILES array
|
||||||
|
* @param array 'server' the $_SERVER array
|
||||||
|
* @param array 'env' the $_ENV array
|
||||||
|
* @param array 'session' the $_SESSION array
|
||||||
|
* @param array 'cookies' the $_COOKIE array
|
||||||
|
* @param string 'method' the request method (GET, POST etc)
|
||||||
|
* @see http://www.php.net/manual/en/reserved.variables.php
|
||||||
|
*/
|
||||||
|
public function __construct(array $vars = array()) {
|
||||||
|
|
||||||
|
foreach($this->varnames as $name) {
|
||||||
|
$this->items[$name] = isset($vars[$name]) ? $vars[$name] : array();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->items['parameters'] = array_merge(
|
||||||
|
$this->items['params'],
|
||||||
|
$this->items['get'],
|
||||||
|
$this->items['post'],
|
||||||
|
$this->items['urlParams']
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an instance of Request using default request variables.
|
||||||
|
*/
|
||||||
|
public static function getRequest($urlParams) {
|
||||||
|
// Ensure that params is an array, not null
|
||||||
|
$params = json_decode(file_get_contents('php://input'), true);
|
||||||
|
\OCP\Util::writeLog('contacts', __METHOD__.' params: '.print_r($params, true), \OCP\Util::DEBUG);
|
||||||
|
$params = is_null($params) ? array() : $params;
|
||||||
|
return new self(
|
||||||
|
array(
|
||||||
|
'get' => $_GET,
|
||||||
|
'post' => $_POST,
|
||||||
|
'files' => $_FILES,
|
||||||
|
'server' => $_SERVER,
|
||||||
|
'env' => $_ENV,
|
||||||
|
'session' => $_SESSION,
|
||||||
|
'cookies' => $_COOKIE,
|
||||||
|
'method' => (isset($_SERVER) && isset($_SERVER['REQUEST_METHOD']))
|
||||||
|
? $_SERVER['REQUEST_METHOD']
|
||||||
|
: '',
|
||||||
|
'params' => $params,
|
||||||
|
'urlParams' => $urlParams
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Countable method.
|
||||||
|
public function count() {
|
||||||
|
return count(array_keys($this->items['parameters']));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ArrayAccess methods
|
||||||
|
*
|
||||||
|
* Gives access to the combined GET, POST and urlParams arrays
|
||||||
|
*
|
||||||
|
* Examples:
|
||||||
|
*
|
||||||
|
* $var = $request['myvar'];
|
||||||
|
*
|
||||||
|
* or
|
||||||
|
*
|
||||||
|
* if(!isset($request['myvar']) {
|
||||||
|
* // Do something
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* $request['myvar'] = 'something'; // This throws an exception.
|
||||||
|
*
|
||||||
|
* @param string offset The key to lookup
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function offsetExists($offset) {
|
||||||
|
return isset($this->items['parameters'][$offset]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see offsetExists
|
||||||
|
*/
|
||||||
|
public function offsetGet($offset) {
|
||||||
|
return isset($this->items['parameters'][$offset])
|
||||||
|
? $this->items['parameters'][$offset]
|
||||||
|
: null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see offsetExists
|
||||||
|
*/
|
||||||
|
public function offsetSet($offset, $value) {
|
||||||
|
throw new \RuntimeException('You cannot change the contents of the request object');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see offsetExists
|
||||||
|
*/
|
||||||
|
public function offsetUnset($offset) {
|
||||||
|
throw new \RuntimeException('You cannot change the contents of the request object');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a value from a request variable or the default value e.g:
|
||||||
|
* $request->get('post', 'some_key', 'default value');
|
||||||
|
*
|
||||||
|
* @param string $vars Which variables to look in e.g. 'get', 'post, 'session'
|
||||||
|
* @param string $name
|
||||||
|
* @param string $default
|
||||||
|
*/
|
||||||
|
public function getVar($vars, $name, $default = null) {
|
||||||
|
return isset($this->{$vars}[$name]) ? $this->{$vars}[$name] : $default;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Magic property accessors
|
||||||
|
public function __set($name, $value) {
|
||||||
|
throw new \RuntimeException('You cannot change the contents of the request object');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Access request variables by method and name.
|
||||||
|
* Examples:
|
||||||
|
*
|
||||||
|
* $request->post['myvar']; // Only look for POST variables
|
||||||
|
* $request->myvar; or $request->{'myvar'}; or $request->{$myvar}
|
||||||
|
* Looks in the combined GET, POST and urlParams array.
|
||||||
|
*
|
||||||
|
* if($request->method !== 'POST') {
|
||||||
|
* throw new Exception('This function can only be invoked using POST');
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* @param string $name The key to look for.
|
||||||
|
* @return mixed|null
|
||||||
|
*/
|
||||||
|
public function __get($name) {
|
||||||
|
switch($name) {
|
||||||
|
case 'get':
|
||||||
|
case 'post':
|
||||||
|
case 'files':
|
||||||
|
case 'server':
|
||||||
|
case 'env':
|
||||||
|
case 'session':
|
||||||
|
case 'cookies':
|
||||||
|
case 'params':
|
||||||
|
case 'parameters':
|
||||||
|
case 'urlParams':
|
||||||
|
return isset($this->items[$name])
|
||||||
|
? $this->items[$name]
|
||||||
|
: null;
|
||||||
|
break;
|
||||||
|
case 'method':
|
||||||
|
return $this->items['method'];
|
||||||
|
break;
|
||||||
|
default;
|
||||||
|
return isset($this[$name]) ? $this[$name] : null;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __isset($name) {
|
||||||
|
return isset($this->items['parameters'][$name]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __unset($id) {
|
||||||
|
throw new \RunTimeException('You cannot change the contents of the request object');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,212 +0,0 @@
|
|||||||
<?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/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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 = OCA\Contacts\Addressbook::allWherePrincipalURIIs($principaluri);
|
|
||||||
$addressbooks = array();
|
|
||||||
|
|
||||||
foreach($data as $i) {
|
|
||||||
if($i['userid'] != OCP\USER::getUser()) {
|
|
||||||
$i['uri'] = $i['uri'] . '_shared_by_' . $i['userid'];
|
|
||||||
}
|
|
||||||
$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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
OCA\Contacts\Addressbook::edit($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' :
|
|
||||||
$name = $newvalue;
|
|
||||||
break;
|
|
||||||
case '{' . Sabre_CardDAV_Plugin::NS_CARDDAV
|
|
||||||
. '}addressbook-description' :
|
|
||||||
$description = $newvalue;
|
|
||||||
break;
|
|
||||||
default :
|
|
||||||
throw new Sabre_DAV_Exception_BadRequest('Unknown property: '
|
|
||||||
. $property);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
OCA\Contacts\Addressbook::addFromDAVData(
|
|
||||||
$principaluri,
|
|
||||||
$url,
|
|
||||||
$name,
|
|
||||||
$description
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Deletes an entire addressbook and all its contents
|
|
||||||
*
|
|
||||||
* @param int $addressbookid
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function deleteAddressBook($addressbookid) {
|
|
||||||
OCA\Contacts\Addressbook::delete($addressbookid);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns all cards for a specific addressbook id.
|
|
||||||
*
|
|
||||||
* @param mixed $addressbookid
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function getCards($addressbookid) {
|
|
||||||
$data = OCA\Contacts\VCard::all($addressbookid);
|
|
||||||
$cards = array();
|
|
||||||
foreach($data as $i) {
|
|
||||||
//OCP\Util::writeLog('contacts', __METHOD__.', uri: ' . $i['uri'], OCP\Util::DEBUG);
|
|
||||||
$cards[] = array(
|
|
||||||
'id' => $i['id'],
|
|
||||||
//'carddata' => $i['carddata'],
|
|
||||||
'size' => strlen($i['carddata']),
|
|
||||||
'etag' => '"' . md5($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 OCA\Contacts\VCard::findWhereDAVDataIs($addressbookid, $carduri);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new card
|
|
||||||
*
|
|
||||||
* @param mixed $addressbookid
|
|
||||||
* @param string $carduri
|
|
||||||
* @param string $carddata
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function createCard($addressbookid, $carduri, $carddata) {
|
|
||||||
OCA\Contacts\VCard::addFromDAVData($addressbookid, $carduri, $carddata);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates a card
|
|
||||||
*
|
|
||||||
* @param mixed $addressbookid
|
|
||||||
* @param string $carduri
|
|
||||||
* @param string $carddata
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function updateCard($addressbookid, $carduri, $carddata) {
|
|
||||||
return OCA\Contacts\VCard::editFromDAVData(
|
|
||||||
$addressbookid, $carduri, $carddata
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Deletes a card
|
|
||||||
*
|
|
||||||
* @param mixed $addressbookid
|
|
||||||
* @param string $carduri
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function deleteCard($addressbookid, $carduri) {
|
|
||||||
return OCA\Contacts\VCard::deleteFromDAVData($addressbookid, $carduri);
|
|
||||||
}
|
|
||||||
}
|
|
@ -10,6 +10,14 @@ namespace OCA\Contacts;
|
|||||||
|
|
||||||
class Share_Backend_Addressbook implements \OCP\Share_Backend_Collection {
|
class Share_Backend_Addressbook implements \OCP\Share_Backend_Collection {
|
||||||
const FORMAT_ADDRESSBOOKS = 1;
|
const FORMAT_ADDRESSBOOKS = 1;
|
||||||
|
const FORMAT_COLLECTION = 2;
|
||||||
|
|
||||||
|
public $backend;
|
||||||
|
|
||||||
|
public function __construct() {
|
||||||
|
// Currently only share
|
||||||
|
$this->backend = new Backend\Database();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get the source of the item to be stored in the database
|
* @brief Get the source of the item to be stored in the database
|
||||||
@ -23,8 +31,8 @@ class Share_Backend_Addressbook implements \OCP\Share_Backend_Collection {
|
|||||||
* The formatItems() function will translate the source returned back into the item
|
* The formatItems() function will translate the source returned back into the item
|
||||||
*/
|
*/
|
||||||
public function isValidSource($itemSource, $uidOwner) {
|
public function isValidSource($itemSource, $uidOwner) {
|
||||||
$addressbook = Addressbook::find( $itemSource );
|
$addressbook = $this->backend->getAddressBook($itemSource);
|
||||||
if( $addressbook === false || $addressbook['userid'] != $uidOwner) {
|
if(!$addressbook || $addressbook['userid'] !== $uidOwner) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -41,17 +49,20 @@ class Share_Backend_Addressbook implements \OCP\Share_Backend_Collection {
|
|||||||
* If it does generate a new name e.g. name_#
|
* If it does generate a new name e.g. name_#
|
||||||
*/
|
*/
|
||||||
public function generateTarget($itemSource, $shareWith, $exclude = null) {
|
public function generateTarget($itemSource, $shareWith, $exclude = null) {
|
||||||
$addressbook = Addressbook::find( $itemSource );
|
$addressbook = $this->backend->getAddressBook($itemSource);
|
||||||
|
|
||||||
$user_addressbooks = array();
|
$user_addressbooks = array();
|
||||||
foreach(Addressbook::all($shareWith) as $user_addressbook) {
|
|
||||||
|
foreach($this->backend->getAddressBooksForUser($shareWith) as $user_addressbook) {
|
||||||
$user_addressbooks[] = $user_addressbook['displayname'];
|
$user_addressbooks[] = $user_addressbook['displayname'];
|
||||||
}
|
}
|
||||||
$name = $addressbook['displayname'];
|
$name = $addressbook['displayname'] . '(' . $addressbook['userid'] . ')';
|
||||||
$suffix = '';
|
$suffix = '';
|
||||||
while (in_array($name.$suffix, $user_addressbooks)) {
|
while (in_array($name.$suffix, $user_addressbooks)) {
|
||||||
$suffix++;
|
$suffix++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$suffix = $suffix ? ' ' . $suffix : '';
|
||||||
return $name.$suffix;
|
return $name.$suffix;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,26 +79,33 @@ class Share_Backend_Addressbook implements \OCP\Share_Backend_Collection {
|
|||||||
* This function allows the backend to control the output of shared items with custom formats.
|
* This function allows the backend to control the output of shared items with custom formats.
|
||||||
* It is only called through calls to the public getItem(s)Shared(With) functions.
|
* It is only called through calls to the public getItem(s)Shared(With) functions.
|
||||||
*/
|
*/
|
||||||
public function formatItems($items, $format, $parameters = null) {
|
public function formatItems($items, $format, $parameters = null, $include = false) {
|
||||||
|
//\OCP\Util::writeLog('contacts', __METHOD__
|
||||||
|
// . ' ' . $include . ' ' . print_r($items, true), \OCP\Util::DEBUG);
|
||||||
$addressbooks = array();
|
$addressbooks = array();
|
||||||
if ($format == self::FORMAT_ADDRESSBOOKS) {
|
if ($format === self::FORMAT_ADDRESSBOOKS) {
|
||||||
foreach ($items as $item) {
|
foreach ($items as $item) {
|
||||||
$addressbook = Addressbook::find($item['item_source']);
|
//\OCP\Util::writeLog('contacts', __METHOD__.' item_source: ' . $item['item_source'] . ' include: '
|
||||||
|
// . (int)$include, \OCP\Util::DEBUG);
|
||||||
|
$addressbook = $this->backend->getAddressBook($item['item_source']);
|
||||||
if ($addressbook) {
|
if ($addressbook) {
|
||||||
$addressbook['displayname'] = $item['item_target'];
|
$addressbook['displayname'] = $addressbook['displayname'] . ' (' . $addressbook['owner'] . ')';
|
||||||
$addressbook['permissions'] = $item['permissions'];
|
$addressbook['permissions'] = $item['permissions'];
|
||||||
$addressbooks[] = $addressbook;
|
$addressbooks[] = $addressbook;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} elseif ($format === self::FORMAT_COLLECTION) {
|
||||||
|
foreach ($items as $item) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return $addressbooks;
|
return $addressbooks;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getChildren($itemSource) {
|
public function getChildren($itemSource) {
|
||||||
$query = \OCP\DB::prepare('SELECT `id`, `fullname` FROM `*PREFIX*contacts_cards` WHERE `addressbookid` = ?');
|
\OCP\Util::writeLog('contacts', __METHOD__.' item_source: ' . $itemSource, \OCP\Util::DEBUG);
|
||||||
$result = $query->execute(array($itemSource));
|
$contacts = $this->backend->getContacts($itemSource, null, null, true);
|
||||||
$children = array();
|
$children = array();
|
||||||
while ($contact = $result->fetchRow()) {
|
foreach($contacts as $contact) {
|
||||||
$children[] = array('source' => $contact['id'], 'target' => $contact['fullname']);
|
$children[] = array('source' => $contact['id'], 'target' => $contact['fullname']);
|
||||||
}
|
}
|
||||||
return $children;
|
return $children;
|
||||||
|
@ -27,6 +27,11 @@ class Share_Backend_Contact implements \OCP\Share_Backend {
|
|||||||
|
|
||||||
private static $contact;
|
private static $contact;
|
||||||
|
|
||||||
|
public function __construct() {
|
||||||
|
// Currently only share
|
||||||
|
$this->backend = new Backend\Database();
|
||||||
|
}
|
||||||
|
|
||||||
public function isValidSource($itemSource, $uidOwner) {
|
public function isValidSource($itemSource, $uidOwner) {
|
||||||
self::$contact = VCard::find($itemSource);
|
self::$contact = VCard::find($itemSource);
|
||||||
if (self::$contact) {
|
if (self::$contact) {
|
||||||
|
207
lib/utils/jsonserializer.php
Normal file
207
lib/utils/jsonserializer.php
Normal file
@ -0,0 +1,207 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* ownCloud - JSONSerializer
|
||||||
|
*
|
||||||
|
* @author Thomas Tanghus, Jakob Sack
|
||||||
|
* @copyright 2011 Jakob Sack mail@jakobsack.de
|
||||||
|
* @copyright 2013 Thomas Tanghus (thomas@tanghus.net)
|
||||||
|
*
|
||||||
|
* 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\Utils;
|
||||||
|
|
||||||
|
use OCA\Contacts\VObject;
|
||||||
|
use OCA\Contacts\Contact;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class serializes properties, components an
|
||||||
|
* arrays of components into a format suitable for
|
||||||
|
* passing to a JSON response.
|
||||||
|
* TODO: Return jCard (almost) compliant data, but still omitting unneeded data.
|
||||||
|
* http://tools.ietf.org/html/draft-kewisch-vcard-in-json-01
|
||||||
|
*/
|
||||||
|
|
||||||
|
class JSONSerializer {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* General method serialize method. Use this for arrays
|
||||||
|
* of contacts.
|
||||||
|
*
|
||||||
|
* @param Contact[] $input
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public static function serialize($input) {
|
||||||
|
$response = array();
|
||||||
|
if(is_array($input)) {
|
||||||
|
foreach($input as $object) {
|
||||||
|
if($object instanceof Contact) {
|
||||||
|
\OCP\Util::writeLog('contacts', __METHOD__.' serializing: ' . print_r($object, true), \OCP\Util::DEBUG);
|
||||||
|
$tmp = self::serializeContact($object);
|
||||||
|
if($tmp !== null) {
|
||||||
|
$response[] = $tmp;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new \Exception(
|
||||||
|
'Only arrays of OCA\\Contacts\\VObject\\VCard '
|
||||||
|
. 'and Sabre\VObject\Property are accepted.'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if($input instanceof VObject\VCard) {
|
||||||
|
return self::serializeContact($input);
|
||||||
|
} elseif($input instanceof Sabre\VObject\Property) {
|
||||||
|
return self::serializeProperty($input);
|
||||||
|
} else {
|
||||||
|
throw new \Exception(
|
||||||
|
'Only instances of OCA\\Contacts\\VObject\\VCard '
|
||||||
|
. 'and Sabre\VObject\Property are accepted.'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Data structure of vCard
|
||||||
|
* @param VObject\VCard $contact
|
||||||
|
* @return associative array|null
|
||||||
|
*/
|
||||||
|
public static function serializeContact(Contact $contact) {
|
||||||
|
|
||||||
|
if(!$contact->retrieve()) {
|
||||||
|
\OCP\Util::writeLog('contacts', __METHOD__.' error reading: ' . print_r($contact, true), \OCP\Util::DEBUG);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$details = array();
|
||||||
|
|
||||||
|
if(isset($contact->PHOTO) || isset($contact->LOGO)) {
|
||||||
|
$details['thumbnail'] = $contact->cacheThumbnail();
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach($contact->children as $property) {
|
||||||
|
$pname = $property->name;
|
||||||
|
$temp = self::serializeProperty($property);
|
||||||
|
if(!is_null($temp)) {
|
||||||
|
// Get Apple X-ABLabels
|
||||||
|
if(isset($contact->{$property->group . '.X-ABLABEL'})) {
|
||||||
|
$temp['label'] = $contact->{$property->group . '.X-ABLABEL'}->value;
|
||||||
|
if($temp['label'] == '_$!<Other>!$_') {
|
||||||
|
$temp['label'] = Properties::$l10n->t('Other');
|
||||||
|
}
|
||||||
|
if($temp['label'] == '_$!<HomePage>!$_') {
|
||||||
|
$temp['label'] = Properties::$l10n->t('HomePage');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(array_key_exists($pname, $details)) {
|
||||||
|
$details[$pname][] = $temp;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
$details[$pname] = array($temp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return array('data' =>$details, 'metadata' => $contact->getMetaData());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get data structure of property.
|
||||||
|
* @param \Sabre\VObject\Property $property
|
||||||
|
* @return associative array
|
||||||
|
*
|
||||||
|
* returns an associative array with
|
||||||
|
* ['name'] name of property
|
||||||
|
* ['value'] htmlspecialchars escaped value of property
|
||||||
|
* ['parameters'] associative array name=>value
|
||||||
|
* ['checksum'] checksum of whole property
|
||||||
|
* NOTE: $value is not escaped anymore. It shouldn't make any difference
|
||||||
|
* but we should look out for any problems.
|
||||||
|
*/
|
||||||
|
public static function serializeProperty(\Sabre\VObject\Property $property) {
|
||||||
|
if(!in_array($property->name, Properties::$index_properties)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$value = $property->value;
|
||||||
|
if($property->name == 'ADR' || $property->name == 'N' || $property->name == 'ORG' || $property->name == 'CATEGORIES') {
|
||||||
|
$value = $property->getParts();
|
||||||
|
$value = array_map('trim', $value);
|
||||||
|
}
|
||||||
|
elseif($property->name == 'BDAY') {
|
||||||
|
if(strpos($value, '-') === false) {
|
||||||
|
if(strlen($value) >= 8) {
|
||||||
|
$value = substr($value, 0, 4).'-'.substr($value, 4, 2).'-'.substr($value, 6, 2);
|
||||||
|
} else {
|
||||||
|
return null; // Badly malformed :-(
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} elseif($property->name == 'PHOTO') {
|
||||||
|
$value = true;
|
||||||
|
}
|
||||||
|
elseif($property->name == 'IMPP') {
|
||||||
|
if(strpos($value, ':') !== false) {
|
||||||
|
$value = explode(':', $value);
|
||||||
|
$protocol = array_shift($value);
|
||||||
|
if(!isset($property['X-SERVICE-TYPE'])) {
|
||||||
|
$property['X-SERVICE-TYPE'] = strtoupper($protocol);
|
||||||
|
}
|
||||||
|
$value = implode('', $value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(is_string($value)) {
|
||||||
|
$value = strtr($value, array('\,' => ',', '\;' => ';'));
|
||||||
|
}
|
||||||
|
$temp = array(
|
||||||
|
//'name' => $property->name,
|
||||||
|
'value' => $value,
|
||||||
|
'parameters' => array()
|
||||||
|
);
|
||||||
|
|
||||||
|
// This cuts around a 3rd off of the json response size.
|
||||||
|
if(in_array($property->name, Properties::$multi_properties)) {
|
||||||
|
$temp['checksum'] = substr(md5($property->serialize()), 0, 8);
|
||||||
|
}
|
||||||
|
foreach($property->parameters as $parameter) {
|
||||||
|
// Faulty entries by kaddressbook
|
||||||
|
// Actually TYPE=PREF is correct according to RFC 2426
|
||||||
|
// but this way is more handy in the UI. Tanghus.
|
||||||
|
if($parameter->name == 'TYPE' && strtoupper($parameter->value) == 'PREF') {
|
||||||
|
$parameter->name = 'PREF';
|
||||||
|
$parameter->value = '1';
|
||||||
|
}
|
||||||
|
// NOTE: Apparently Sabre_VObject_Reader can't always deal with value list parameters
|
||||||
|
// like TYPE=HOME,CELL,VOICE. Tanghus.
|
||||||
|
// TODO: Check if parameter is has commas and split + merge if so.
|
||||||
|
if ($parameter->name == 'TYPE') {
|
||||||
|
$pvalue = $parameter->value;
|
||||||
|
if(is_string($pvalue) && strpos($pvalue, ',') !== false) {
|
||||||
|
$pvalue = array_map('trim', explode(',', $pvalue));
|
||||||
|
}
|
||||||
|
$pvalue = is_array($pvalue) ? $pvalue : array($pvalue);
|
||||||
|
if (isset($temp['parameters'][$parameter->name])) {
|
||||||
|
$temp['parameters'][$parameter->name][] = \OCP\Util::sanitizeHTML($pvalue);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$temp['parameters'][$parameter->name] = \OCP\Util::sanitizeHTML($pvalue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
$temp['parameters'][$parameter->name] = \OCP\Util::sanitizeHTML($parameter->value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $temp;
|
||||||
|
}
|
||||||
|
}
|
263
lib/utils/properties.php
Normal file
263
lib/utils/properties.php
Normal file
@ -0,0 +1,263 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* ownCloud - Interface for PIM object
|
||||||
|
*
|
||||||
|
* @author Thomas Tanghus
|
||||||
|
* @copyright 2013 Thomas Tanghus (thomas@tanghus.net)
|
||||||
|
*
|
||||||
|
* 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\Utils;
|
||||||
|
|
||||||
|
Properties::$l10n = \OC_L10N::get('contacts');
|
||||||
|
|
||||||
|
Class Properties {
|
||||||
|
|
||||||
|
private static $deleteindexstmt;
|
||||||
|
private static $updateindexstmt;
|
||||||
|
protected static $cardsTableName = '*PREFIX*contacts_cards';
|
||||||
|
protected static $indexTableName = '*PREFIX*contacts_cards_properties';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief language object for calendar app
|
||||||
|
*
|
||||||
|
* @var OC_L10N
|
||||||
|
*/
|
||||||
|
public static $l10n;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Properties there can be more than one of.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
public static $multi_properties = array('EMAIL', 'TEL', 'IMPP', 'ADR', 'URL');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Properties to index.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
public static $index_properties = array(
|
||||||
|
'BDAY', 'UID', 'N', 'FN', 'TITLE', 'ROLE', 'NOTE', 'NICKNAME',
|
||||||
|
'ORG', 'CATEGORIES', 'EMAIL', 'TEL', 'IMPP', 'ADR', 'URL', 'GEO', 'PHOTO');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get options for IMPP properties
|
||||||
|
* @param string $im
|
||||||
|
* @return array of vcard prop => label
|
||||||
|
*/
|
||||||
|
public static function getIMOptions($im = null) {
|
||||||
|
$l10n = self::$l10n;
|
||||||
|
$ims = array(
|
||||||
|
'jabber' => array(
|
||||||
|
'displayname' => (string)$l10n->t('Jabber'),
|
||||||
|
'xname' => 'X-JABBER',
|
||||||
|
'protocol' => 'xmpp',
|
||||||
|
),
|
||||||
|
'aim' => array(
|
||||||
|
'displayname' => (string)$l10n->t('AIM'),
|
||||||
|
'xname' => 'X-AIM',
|
||||||
|
'protocol' => 'aim',
|
||||||
|
),
|
||||||
|
'msn' => array(
|
||||||
|
'displayname' => (string)$l10n->t('MSN'),
|
||||||
|
'xname' => 'X-MSN',
|
||||||
|
'protocol' => 'msn',
|
||||||
|
),
|
||||||
|
'twitter' => array(
|
||||||
|
'displayname' => (string)$l10n->t('Twitter'),
|
||||||
|
'xname' => 'X-TWITTER',
|
||||||
|
'protocol' => 'twitter',
|
||||||
|
),
|
||||||
|
'googletalk' => array(
|
||||||
|
'displayname' => (string)$l10n->t('GoogleTalk'),
|
||||||
|
'xname' => null,
|
||||||
|
'protocol' => 'xmpp',
|
||||||
|
),
|
||||||
|
'facebook' => array(
|
||||||
|
'displayname' => (string)$l10n->t('Facebook'),
|
||||||
|
'xname' => null,
|
||||||
|
'protocol' => 'xmpp',
|
||||||
|
),
|
||||||
|
'xmpp' => array(
|
||||||
|
'displayname' => (string)$l10n->t('XMPP'),
|
||||||
|
'xname' => null,
|
||||||
|
'protocol' => 'xmpp',
|
||||||
|
),
|
||||||
|
'icq' => array(
|
||||||
|
'displayname' => (string)$l10n->t('ICQ'),
|
||||||
|
'xname' => 'X-ICQ',
|
||||||
|
'protocol' => 'icq',
|
||||||
|
),
|
||||||
|
'yahoo' => array(
|
||||||
|
'displayname' => (string)$l10n->t('Yahoo'),
|
||||||
|
'xname' => 'X-YAHOO',
|
||||||
|
'protocol' => 'ymsgr',
|
||||||
|
),
|
||||||
|
'skype' => array(
|
||||||
|
'displayname' => (string)$l10n->t('Skype'),
|
||||||
|
'xname' => 'X-SKYPE',
|
||||||
|
'protocol' => 'skype',
|
||||||
|
),
|
||||||
|
'qq' => array(
|
||||||
|
'displayname' => (string)$l10n->t('QQ'),
|
||||||
|
'xname' => 'X-SKYPE',
|
||||||
|
'protocol' => 'x-apple',
|
||||||
|
),
|
||||||
|
'gadugadu' => array(
|
||||||
|
'displayname' => (string)$l10n->t('GaduGadu'),
|
||||||
|
'xname' => 'X-SKYPE',
|
||||||
|
'protocol' => 'x-apple',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
if(is_null($im)) {
|
||||||
|
return $ims;
|
||||||
|
} else {
|
||||||
|
$ims['ymsgr'] = $ims['yahoo'];
|
||||||
|
$ims['gtalk'] = $ims['googletalk'];
|
||||||
|
return isset($ims[$im]) ? $ims[$im] : null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get standard set of TYPE values for different properties.
|
||||||
|
*
|
||||||
|
* @param string $prop
|
||||||
|
* @return array Type values for property $prop
|
||||||
|
*/
|
||||||
|
public static function getTypesForProperty($prop) {
|
||||||
|
$l = self::$l10n;
|
||||||
|
switch($prop) {
|
||||||
|
case 'LABEL':
|
||||||
|
case 'ADR':
|
||||||
|
case 'IMPP':
|
||||||
|
return array(
|
||||||
|
'WORK' => (string)$l->t('Work'),
|
||||||
|
'HOME' => (string)$l->t('Home'),
|
||||||
|
'OTHER' => (string)$l->t('Other'),
|
||||||
|
);
|
||||||
|
case 'TEL':
|
||||||
|
return array(
|
||||||
|
'HOME' => (string)$l->t('Home'),
|
||||||
|
'CELL' => (string)$l->t('Mobile'),
|
||||||
|
'WORK' => (string)$l->t('Work'),
|
||||||
|
'TEXT' => (string)$l->t('Text'),
|
||||||
|
'VOICE' => (string)$l->t('Voice'),
|
||||||
|
'MSG' => (string)$l->t('Message'),
|
||||||
|
'FAX' => (string)$l->t('Fax'),
|
||||||
|
'VIDEO' => (string)$l->t('Video'),
|
||||||
|
'PAGER' => (string)$l->t('Pager'),
|
||||||
|
'OTHER' => (string)$l->t('Other'),
|
||||||
|
);
|
||||||
|
case 'EMAIL':
|
||||||
|
return array(
|
||||||
|
'WORK' => (string)$l->t('Work'),
|
||||||
|
'HOME' => (string)$l->t('Home'),
|
||||||
|
'INTERNET' => (string)$l->t('Internet'),
|
||||||
|
'OTHER' => (string)$l->t('Other'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief returns the default categories of ownCloud
|
||||||
|
* @return (array) $categories
|
||||||
|
*/
|
||||||
|
public static function getDefaultCategories() {
|
||||||
|
$l10n = self::$l10n;
|
||||||
|
return array(
|
||||||
|
(string)$l10n->t('Friends'),
|
||||||
|
(string)$l10n->t('Family'),
|
||||||
|
(string)$l10n->t('Work'),
|
||||||
|
(string)$l10n->t('Other'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function generateUID($app = 'contacts') {
|
||||||
|
return date('Ymd\\THis') . '.' . time(). '@' . OCP\Util::getServerHostName();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the contact property index.
|
||||||
|
*
|
||||||
|
* If vcard is null the properties for that contact will be purged.
|
||||||
|
* If it is a valid object the old properties will first be purged
|
||||||
|
* and the current properties indexed.
|
||||||
|
*
|
||||||
|
* @param string $contactid
|
||||||
|
* @param \OCA\VObject\VCard|null $vcard
|
||||||
|
*/
|
||||||
|
public static function updateIndex($contactid, $vcard = null) {
|
||||||
|
if(!isset(self::$deleteindexstmt)) {
|
||||||
|
self::$deleteindexstmt
|
||||||
|
= \OCP\DB::prepare('DELETE FROM `' . self::$indexTableName . '`'
|
||||||
|
. ' WHERE `contactid` = ?');
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
self::$deleteindexstmt->execute(array($contactid));
|
||||||
|
} catch(\Exception $e) {
|
||||||
|
\OCP\Util::writeLog('contacts', __METHOD__.
|
||||||
|
', exception: ' . $e->getMessage(), \OCP\Util::ERROR);
|
||||||
|
\OCP\Util::writeLog('contacts', __METHOD__.', id: '
|
||||||
|
. $id, \OCP\Util::DEBUG);
|
||||||
|
throw new \Exception(
|
||||||
|
App::$l10n->t(
|
||||||
|
'There was an error deleting properties for this contact.'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(is_null($vcard)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!isset(self::$updateindexstmt)) {
|
||||||
|
self::$updateindexstmt = \OCP\DB::prepare( 'INSERT INTO `' . self::$indexTableName . '` '
|
||||||
|
. '(`userid`, `contactid`,`name`,`value`,`preferred`) VALUES(?,?,?,?,?)' );
|
||||||
|
}
|
||||||
|
foreach($vcard->children as $property) {
|
||||||
|
if(!in_array($property->name, self::$index_properties)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$preferred = 0;
|
||||||
|
foreach($property->parameters as $parameter) {
|
||||||
|
if($parameter->name == 'TYPE' && strtoupper($parameter->value) == 'PREF') {
|
||||||
|
$preferred = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
$result = self::$updateindexstmt->execute(
|
||||||
|
array(
|
||||||
|
\OCP\User::getUser(),
|
||||||
|
$contactid,
|
||||||
|
$property->name,
|
||||||
|
$property->value,
|
||||||
|
$preferred,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
if (\OC_DB::isError($result)) {
|
||||||
|
\OCP\Util::writeLog('contacts', __METHOD__. 'DB error: '
|
||||||
|
. \OC_DB::getErrorMessage($result), \OC_Log::ERROR);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} catch(\Exception $e) {
|
||||||
|
\OCP\Util::writeLog('contacts', __METHOD__.', exception: '.$e->getMessage(), \OCP\Util::ERROR);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
818
lib/vcard.php
818
lib/vcard.php
@ -4,7 +4,7 @@
|
|||||||
*
|
*
|
||||||
* @author Jakob Sack
|
* @author Jakob Sack
|
||||||
* @copyright 2011 Jakob Sack mail@jakobsack.de
|
* @copyright 2011 Jakob Sack mail@jakobsack.de
|
||||||
* @copyright 2012 Thomas Tanghus <thomas@tanghus.net>
|
* @copyright 2012-2013 Thomas Tanghus <thomas@tanghus.net>
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||||
@ -43,377 +43,6 @@ use Sabre\VObject;
|
|||||||
* This class manages our vCards
|
* This class manages our vCards
|
||||||
*/
|
*/
|
||||||
class VCard {
|
class VCard {
|
||||||
/**
|
|
||||||
* @brief Returns all cards of an address book
|
|
||||||
* @param integer $id
|
|
||||||
* @param integer $offset
|
|
||||||
* @param integer $limit
|
|
||||||
* @param array $fields An array of the fields to return. Defaults to all.
|
|
||||||
* @return array|false
|
|
||||||
*
|
|
||||||
* The cards are associative arrays. You'll find the original vCard in
|
|
||||||
* ['carddata']
|
|
||||||
*/
|
|
||||||
public static function all($id, $offset=null, $limit=null, $fields = array()) {
|
|
||||||
$result = null;
|
|
||||||
\OCP\Util::writeLog('contacts', __METHOD__.'count fields:' . count($fields), \OCP\Util::DEBUG);
|
|
||||||
$qfields = count($fields) > 0
|
|
||||||
? '`' . implode('`,`', $fields) . '`'
|
|
||||||
: '*';
|
|
||||||
if(is_array($id) && count($id)) {
|
|
||||||
$id_sql = join(',', array_fill(0, count($id), '?'));
|
|
||||||
$sql = 'SELECT ' . $qfields . ' FROM `*PREFIX*contacts_cards` WHERE `addressbookid` IN ('.$id_sql.') ORDER BY `fullname`';
|
|
||||||
try {
|
|
||||||
$stmt = \OCP\DB::prepare($sql, $limit, $offset);
|
|
||||||
$result = $stmt->execute($id);
|
|
||||||
if (\OC_DB::isError($result)) {
|
|
||||||
\OC_Log::write('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);
|
|
||||||
\OCP\Util::writeLog('contacts', __METHOD__.', ids: ' . join(',', $id), \OCP\Util::DEBUG);
|
|
||||||
\OCP\Util::writeLog('contacts', __METHOD__.'SQL:' . $sql, \OCP\Util::DEBUG);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} elseif(is_int($id) || is_string($id)) {
|
|
||||||
try {
|
|
||||||
$sql = 'SELECT ' . $qfields . ' FROM `*PREFIX*contacts_cards` WHERE `addressbookid` = ? ORDER BY `fullname`';
|
|
||||||
$stmt = \OCP\DB::prepare($sql, $limit, $offset);
|
|
||||||
$result = $stmt->execute(array($id));
|
|
||||||
if (\OC_DB::isError($result)) {
|
|
||||||
\OC_Log::write('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);
|
|
||||||
\OCP\Util::writeLog('contacts', __METHOD__.', ids: '. $id, \OCP\Util::DEBUG);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
\OCP\Util::writeLog('contacts', __METHOD__
|
|
||||||
. '. Addressbook id(s) argument is empty: '
|
|
||||||
. print_r($id, true), \OCP\Util::DEBUG);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
$cards = array();
|
|
||||||
if(!is_null($result)) {
|
|
||||||
while( $row = $result->fetchRow()) {
|
|
||||||
$cards[] = $row;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $cards;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Returns a card
|
|
||||||
* @param integer $id
|
|
||||||
* @param array $fields An array of the fields to return. Defaults to all.
|
|
||||||
* @return associative array or false.
|
|
||||||
*/
|
|
||||||
public static function find($id, $fields = array() ) {
|
|
||||||
if(count($fields) > 0 && !in_array('addressbookid', $fields)) {
|
|
||||||
$fields[] = 'addressbookid';
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
$qfields = count($fields) > 0
|
|
||||||
? '`' . implode('`,`', $fields) . '`'
|
|
||||||
: '*';
|
|
||||||
$stmt = \OCP\DB::prepare( 'SELECT ' . $qfields . ' FROM `*PREFIX*contacts_cards` WHERE `id` = ?' );
|
|
||||||
$result = $stmt->execute(array($id));
|
|
||||||
if (\OC_DB::isError($result)) {
|
|
||||||
\OC_Log::write('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);
|
|
||||||
\OCP\Util::writeLog('contacts', __METHOD__.', id: '. $id, \OCP\Util::DEBUG);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$row = $result->fetchRow();
|
|
||||||
if($row) {
|
|
||||||
try {
|
|
||||||
$addressbook = Addressbook::find($row['addressbookid']);
|
|
||||||
} catch(\Exception $e) {
|
|
||||||
\OCP\Util::writeLog('contacts', __METHOD__.', exception: '.$e->getMessage(), \OCP\Util::ERROR);
|
|
||||||
\OCP\Util::writeLog('contacts', __METHOD__.', id: '. $id, \OCP\Util::DEBUG);
|
|
||||||
throw $e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return $row;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief finds a card by its DAV Data
|
|
||||||
* @param integer $aid Addressbook id
|
|
||||||
* @param string $uri the uri ('filename')
|
|
||||||
* @return associative array or false.
|
|
||||||
*/
|
|
||||||
public static function findWhereDAVDataIs($aid, $uri) {
|
|
||||||
try {
|
|
||||||
$stmt = \OCP\DB::prepare( 'SELECT * FROM `*PREFIX*contacts_cards` WHERE `addressbookid` = ? AND `uri` = ?' );
|
|
||||||
$result = $stmt->execute(array($aid,$uri));
|
|
||||||
if (\OC_DB::isError($result)) {
|
|
||||||
\OC_Log::write('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);
|
|
||||||
\OCP\Util::writeLog('contacts', __METHOD__.', aid: '.$aid.' uri'.$uri, \OCP\Util::DEBUG);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $result->fetchRow();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Format property TYPE parameters for upgrading from v. 2.1
|
|
||||||
* @param $property Reference to a Sabre_VObject_Property.
|
|
||||||
* In version 2.1 e.g. a phone can be formatted like: TEL;HOME;CELL:123456789
|
|
||||||
* This has to be changed to either TEL;TYPE=HOME,CELL:123456789 or TEL;TYPE=HOME;TYPE=CELL:123456789 - both are valid.
|
|
||||||
*/
|
|
||||||
public static function formatPropertyTypes(&$property) {
|
|
||||||
foreach($property->parameters as $key=>&$parameter) {
|
|
||||||
$types = App::getTypesOfProperty($property->name);
|
|
||||||
if(is_array($types) && in_array(strtoupper($parameter->name), array_keys($types)) || strtoupper($parameter->name) == 'PREF') {
|
|
||||||
$property->parameters[] = new \Sabre\VObject\Parameter('TYPE', $parameter->name);
|
|
||||||
}
|
|
||||||
unset($property->parameters[$key]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Decode properties for upgrading from v. 2.1
|
|
||||||
* @param $property Reference to a Sabre_VObject_Property.
|
|
||||||
* The only encoding allowed in version 3.0 is 'b' for binary. All encoded strings
|
|
||||||
* must therefor be decoded and the parameters removed.
|
|
||||||
*/
|
|
||||||
public static function decodeProperty(&$property) {
|
|
||||||
// Check out for encoded string and decode them :-[
|
|
||||||
foreach($property->parameters as $key=>&$parameter) {
|
|
||||||
if(strtoupper($parameter->name) == 'ENCODING') {
|
|
||||||
if(strtoupper($parameter->value) == 'QUOTED-PRINTABLE') { // what kind of other encodings could be used?
|
|
||||||
// Decode quoted-printable and strip any control chars
|
|
||||||
// except \n and \r
|
|
||||||
$property->value = preg_replace(
|
|
||||||
'/[\x00-\x09\x0B\x0C\x0E-\x1F\x7F]/',
|
|
||||||
'',
|
|
||||||
quoted_printable_decode($property->value)
|
|
||||||
);
|
|
||||||
unset($property->parameters[$key]);
|
|
||||||
}
|
|
||||||
} elseif(strtoupper($parameter->name) == 'CHARSET') {
|
|
||||||
unset($property->parameters[$key]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Checks if a contact with the same UID already exist in the address book.
|
|
||||||
* @param $aid Address book ID.
|
|
||||||
* @param $uid UID (passed by reference).
|
|
||||||
* @returns true if the UID has been changed.
|
|
||||||
*/
|
|
||||||
protected static function trueUID($aid, &$uid) {
|
|
||||||
$stmt = \OCP\DB::prepare( 'SELECT * FROM `*PREFIX*contacts_cards` WHERE `addressbookid` = ? AND `uri` = ?' );
|
|
||||||
$uri = $uid.'.vcf';
|
|
||||||
try {
|
|
||||||
$result = $stmt->execute(array($aid,$uri));
|
|
||||||
if (\OC_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);
|
|
||||||
\OCP\Util::writeLog('contacts', __METHOD__.', aid: '.$aid.' uid'.$uid, \OCP\Util::DEBUG);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if($result->numRows() > 0) {
|
|
||||||
while(true) {
|
|
||||||
$tmpuid = substr(md5(rand().time()), 0, 10);
|
|
||||||
$uri = $tmpuid.'.vcf';
|
|
||||||
$result = $stmt->execute(array($aid, $uri));
|
|
||||||
if($result->numRows() > 0) {
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
$uid = $tmpuid;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Tries to update imported VCards to adhere to rfc2426 (VERSION: 3.0) and add mandatory fields if missing.
|
|
||||||
* @param aid Address book id.
|
|
||||||
* @param vcard A Sabre\VObject\Component of type VCARD (passed by reference).
|
|
||||||
*/
|
|
||||||
protected static function updateValuesFromAdd($aid, &$vcard) { // any suggestions for a better method name? ;-)
|
|
||||||
$stringprops = array('N', 'FN', 'ORG', 'NICK', 'ADR', 'NOTE');
|
|
||||||
$typeprops = array('ADR', 'TEL', 'EMAIL');
|
|
||||||
$upgrade = false;
|
|
||||||
$fn = $n = $uid = $email = $org = null;
|
|
||||||
$version = isset($vcard->VERSION) ? $vcard->VERSION : null;
|
|
||||||
// Add version if needed
|
|
||||||
if($version && $version < '3.0') {
|
|
||||||
$upgrade = true;
|
|
||||||
//OCP\Util::writeLog('contacts', 'OCA\Contacts\VCard::updateValuesFromAdd. Updating from version: '.$version, OCP\Util::DEBUG);
|
|
||||||
}
|
|
||||||
foreach($vcard->children as &$property) {
|
|
||||||
// Decode string properties and remove obsolete properties.
|
|
||||||
if($upgrade && in_array($property->name, $stringprops)) {
|
|
||||||
self::decodeProperty($property);
|
|
||||||
}
|
|
||||||
if(function_exists('iconv')) {
|
|
||||||
$property->value = str_replace("\r\n", "\n", iconv(mb_detect_encoding($property->value, 'UTF-8, ISO-8859-1'), 'utf-8', $property->value));
|
|
||||||
} else {
|
|
||||||
$property->value = str_replace("\r\n", "\n", mb_convert_encoding($property->value, 'UTF-8', mb_detect_encoding($property->value, 'UTF-8, ISO-8859-1'), $property->value));
|
|
||||||
}
|
|
||||||
if(in_array($property->name, $stringprops)) {
|
|
||||||
$property->value = strip_tags($property->value);
|
|
||||||
}
|
|
||||||
// Fix format of type parameters.
|
|
||||||
if($upgrade && in_array($property->name, $typeprops)) {
|
|
||||||
//OCP\Util::writeLog('contacts', 'OCA\Contacts\VCard::updateValuesFromAdd. before: '.$property->serialize(), OCP\Util::DEBUG);
|
|
||||||
self::formatPropertyTypes($property);
|
|
||||||
//OCP\Util::writeLog('contacts', 'OCA\Contacts\VCard::updateValuesFromAdd. after: '.$property->serialize(), OCP\Util::DEBUG);
|
|
||||||
}
|
|
||||||
if($property->name == 'FN') {
|
|
||||||
$fn = $property->value;
|
|
||||||
}
|
|
||||||
else if($property->name == 'N') {
|
|
||||||
$n = $property->value;
|
|
||||||
}
|
|
||||||
else if($property->name == 'UID') {
|
|
||||||
$uid = $property->value;
|
|
||||||
}
|
|
||||||
else if($property->name == 'ORG') {
|
|
||||||
$org = $property->value;
|
|
||||||
}
|
|
||||||
else if($property->name == 'EMAIL' && is_null($email)) { // only use the first email as substitute for missing N or FN.
|
|
||||||
$email = $property->value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Check for missing 'N', 'FN' and 'UID' properties
|
|
||||||
if(!$fn) {
|
|
||||||
if($n && $n != ';;;;') {
|
|
||||||
$fn = join(' ', array_reverse(array_slice(explode(';', $n), 0, 2)));
|
|
||||||
} elseif($email) {
|
|
||||||
$fn = $email;
|
|
||||||
} elseif($org) {
|
|
||||||
$fn = $org;
|
|
||||||
} else {
|
|
||||||
$fn = 'Unknown Name';
|
|
||||||
}
|
|
||||||
$vcard->FN = $fn;
|
|
||||||
//OCP\Util::writeLog('contacts', 'OCA\Contacts\VCard::updateValuesFromAdd. Added missing \'FN\' field: '.$fn, OCP\Util::DEBUG);
|
|
||||||
}
|
|
||||||
if(!$n || $n == ';;;;') { // Fix missing 'N' field. Ugly hack ahead ;-)
|
|
||||||
$slice = array_reverse(array_slice(explode(' ', $fn), 0, 2)); // Take 2 first name parts of 'FN' and reverse.
|
|
||||||
if(count($slice) < 2) { // If not enought, add one more...
|
|
||||||
$slice[] = "";
|
|
||||||
}
|
|
||||||
$n = implode(';', $slice).';;;';
|
|
||||||
$vcard->N = $n;
|
|
||||||
//OCP\Util::writeLog('contacts', 'OCA\Contacts\VCard::updateValuesFromAdd. Added missing \'N\' field: '.$n, OCP\Util::DEBUG);
|
|
||||||
}
|
|
||||||
if(!$uid) {
|
|
||||||
$uid = substr(md5(rand().time()), 0, 10);
|
|
||||||
$vcard->add('UID', $uid);
|
|
||||||
//OCP\Util::writeLog('contacts', 'OCA\Contacts\VCard::updateValuesFromAdd. Added missing \'UID\' field: '.$uid, OCP\Util::DEBUG);
|
|
||||||
}
|
|
||||||
if(self::trueUID($aid, $uid)) {
|
|
||||||
$vcard->{'UID'} = $uid;
|
|
||||||
}
|
|
||||||
$now = new \DateTime;
|
|
||||||
$vcard->{'REV'} = $now->format(\DateTime::W3C);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Adds a card
|
|
||||||
* @param $aid integer Addressbook id
|
|
||||||
* @param $card Sabre\VObject\Component vCard file
|
|
||||||
* @param $uri string the uri of the card, default based on the UID
|
|
||||||
* @param $isChecked boolean If the vCard should be checked for validity and version.
|
|
||||||
* @return insertid on success or false.
|
|
||||||
*/
|
|
||||||
public static function add($aid, VObject\Component $card, $uri=null, $isChecked=false) {
|
|
||||||
if(is_null($card)) {
|
|
||||||
\OCP\Util::writeLog('contacts', __METHOD__ . ', No vCard supplied', \OCP\Util::ERROR);
|
|
||||||
return null;
|
|
||||||
};
|
|
||||||
$addressbook = Addressbook::find($aid);
|
|
||||||
if ($addressbook['userid'] != \OCP\User::getUser()) {
|
|
||||||
$sharedAddressbook = \OCP\Share::getItemSharedWithBySource('addressbook', $aid);
|
|
||||||
if (!$sharedAddressbook || !($sharedAddressbook['permissions'] & \OCP\PERMISSION_CREATE)) {
|
|
||||||
throw new \Exception(
|
|
||||||
App::$l10n->t(
|
|
||||||
'You do not have the permissions to add contacts to this addressbook.'
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(!$isChecked) {
|
|
||||||
self::updateValuesFromAdd($aid, $card);
|
|
||||||
}
|
|
||||||
$card->{'VERSION'} = '3.0';
|
|
||||||
// Add product ID is missing.
|
|
||||||
//$prodid = trim($card->getAsString('PRODID'));
|
|
||||||
//if(!$prodid) {
|
|
||||||
if(!isset($card->PRODID)) {
|
|
||||||
$appinfo = \OCP\App::getAppInfo('contacts');
|
|
||||||
$appversion = \OCP\App::getAppVersion('contacts');
|
|
||||||
$prodid = '-//ownCloud//NONSGML '.$appinfo['name'].' '.$appversion.'//EN';
|
|
||||||
$card->add('PRODID', $prodid);
|
|
||||||
}
|
|
||||||
|
|
||||||
$fn = isset($card->FN) ? $card->FN : '';
|
|
||||||
|
|
||||||
$uri = isset($uri) ? $uri : $card->UID . '.vcf';
|
|
||||||
|
|
||||||
$data = $card->serialize();
|
|
||||||
$stmt = \OCP\DB::prepare( 'INSERT INTO `*PREFIX*contacts_cards` (`addressbookid`,`fullname`,`carddata`,`uri`,`lastmodified`) VALUES(?,?,?,?,?)' );
|
|
||||||
try {
|
|
||||||
$result = $stmt->execute(array($aid, $fn, $data, $uri, time()));
|
|
||||||
if (\OC_DB::isError($result)) {
|
|
||||||
\OC_Log::write('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);
|
|
||||||
\OCP\Util::writeLog('contacts', __METHOD__.', aid: '.$aid.' uri'.$uri, \OCP\Util::DEBUG);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
$newid = \OCP\DB::insertid('*PREFIX*contacts_cards');
|
|
||||||
App::loadCategoriesFromVCard($newid, $card);
|
|
||||||
App::updateDBProperties($newid, $card);
|
|
||||||
App::cacheThumbnail($newid);
|
|
||||||
|
|
||||||
Addressbook::touch($aid);
|
|
||||||
\OC_Hook::emit('\OCA\Contacts\VCard', 'post_createVCard', $newid);
|
|
||||||
return $newid;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Adds a card with the data provided by sabredav
|
|
||||||
* @param integer $id Addressbook id
|
|
||||||
* @param string $uri the uri the card will have
|
|
||||||
* @param string $data vCard file
|
|
||||||
* @returns integer|false insertid or false on error
|
|
||||||
*/
|
|
||||||
public static function addFromDAVData($id, $uri, $data) {
|
|
||||||
try {
|
|
||||||
$vcard = \Sabre\VObject\Reader::read($data);
|
|
||||||
return self::add($id, $vcard, $uri);
|
|
||||||
} catch(\Exception $e) {
|
|
||||||
\OCP\Util::writeLog('contacts', __METHOD__.', exception: '.$e->getMessage(), \OCP\Util::ERROR);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Mass updates an array of cards
|
* @brief Mass updates an array of cards
|
||||||
@ -435,13 +64,6 @@ class VCard {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$addressbook = Addressbook::find($oldcard['addressbookid']);
|
|
||||||
if ($addressbook['userid'] != \OCP\User::getUser()) {
|
|
||||||
$sharedContact = \OCP\Share::getItemSharedWithBySource('contact', $object[0], \OCP\Share::FORMAT_NONE, null, true);
|
|
||||||
if (!$sharedContact || !($sharedContact['permissions'] & \OCP\PERMISSION_UPDATE)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$vcard->{'REV'} = $now->format(\DateTime::W3C);
|
$vcard->{'REV'} = $now->format(\DateTime::W3C);
|
||||||
$data = $vcard->serialize();
|
$data = $vcard->serialize();
|
||||||
try {
|
try {
|
||||||
@ -459,442 +81,4 @@ class VCard {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief edits a card
|
|
||||||
* @param integer $id id of card
|
|
||||||
* @param Sabre\VObject\Component $card vCard file
|
|
||||||
* @return boolean true on success, otherwise an exception will be thrown
|
|
||||||
*/
|
|
||||||
public static function edit($id, VObject\Component $card) {
|
|
||||||
$oldcard = self::find($id);
|
|
||||||
if (!$oldcard) {
|
|
||||||
\OCP\Util::writeLog('contacts', __METHOD__.', id: '
|
|
||||||
. $id . ' not found.', \OCP\Util::DEBUG);
|
|
||||||
throw new \Exception(
|
|
||||||
App::$l10n->t(
|
|
||||||
'Could not find the vCard with ID.' . $id
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if(is_null($card)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// NOTE: Owner checks are being made in the ajax files, which should be done
|
|
||||||
// inside the lib files to prevent any redundancies with sharing checks
|
|
||||||
$addressbook = Addressbook::find($oldcard['addressbookid']);
|
|
||||||
if ($addressbook['userid'] != \OCP\User::getUser()) {
|
|
||||||
$sharedAddressbook = \OCP\Share::getItemSharedWithBySource(
|
|
||||||
'addressbook',
|
|
||||||
$oldcard['addressbookid'],
|
|
||||||
\OCP\Share::FORMAT_NONE, null, true);
|
|
||||||
$sharedContact = \OCP\Share::getItemSharedWithBySource('contact', $id, \OCP\Share::FORMAT_NONE, null, true);
|
|
||||||
$addressbook_permissions = 0;
|
|
||||||
$contact_permissions = 0;
|
|
||||||
if ($sharedAddressbook) {
|
|
||||||
$addressbook_permissions = $sharedAddressbook['permissions'];
|
|
||||||
}
|
|
||||||
if ($sharedContact) {
|
|
||||||
$contact_permissions = $sharedEvent['permissions'];
|
|
||||||
}
|
|
||||||
$permissions = max($addressbook_permissions, $contact_permissions);
|
|
||||||
if (!($permissions & \OCP\PERMISSION_UPDATE)) {
|
|
||||||
throw new \Exception(
|
|
||||||
App::$l10n->t(
|
|
||||||
'You do not have the permissions to edit this contact.'
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
App::loadCategoriesFromVCard($id, $card);
|
|
||||||
|
|
||||||
$fn = isset($card->FN) ? $card->FN : '';
|
|
||||||
|
|
||||||
$now = new \DateTime;
|
|
||||||
$card->REV = $now->format(\DateTime::W3C);
|
|
||||||
|
|
||||||
$data = $card->serialize();
|
|
||||||
$stmt = \OCP\DB::prepare( 'UPDATE `*PREFIX*contacts_cards` SET `fullname` = ?,`carddata` = ?, `lastmodified` = ? WHERE `id` = ?' );
|
|
||||||
try {
|
|
||||||
$result = $stmt->execute(array($fn, $data, time(), $id));
|
|
||||||
if (\OC_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);
|
|
||||||
\OCP\Util::writeLog('contacts', __METHOD__.', id'.$id, \OCP\Util::DEBUG);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
App::cacheThumbnail($oldcard['id']);
|
|
||||||
App::updateDBProperties($id, $card);
|
|
||||||
Addressbook::touch($oldcard['addressbookid']);
|
|
||||||
\OC_Hook::emit('\OCA\Contacts\VCard', 'post_updateVCard', $id);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief edits a card with the data provided by sabredav
|
|
||||||
* @param integer $id Addressbook id
|
|
||||||
* @param string $uri the uri of the card
|
|
||||||
* @param string $data vCard file
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
public static function editFromDAVData($aid, $uri, $data) {
|
|
||||||
$oldcard = self::findWhereDAVDataIs($aid, $uri);
|
|
||||||
try {
|
|
||||||
$vcard = \Sabre\VObject\Reader::read($data);
|
|
||||||
} catch(\Exception $e) {
|
|
||||||
\OCP\Util::writeLog('contacts', __METHOD__.
|
|
||||||
', Unable to parse VCARD, : ' . $e->getMessage(), \OCP\Util::ERROR);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
self::edit($oldcard['id'], $vcard);
|
|
||||||
return true;
|
|
||||||
} catch(\Exception $e) {
|
|
||||||
\OCP\Util::writeLog('contacts', __METHOD__.', exception: '
|
|
||||||
. $e->getMessage() . ', '
|
|
||||||
. \OCP\USER::getUser(), \OCP\Util::ERROR);
|
|
||||||
\OCP\Util::writeLog('contacts', __METHOD__.', uri'
|
|
||||||
. $uri, \OCP\Util::DEBUG);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief deletes a card
|
|
||||||
* @param integer $id id of card
|
|
||||||
* @return boolean true on success, otherwise an exception will be thrown
|
|
||||||
*/
|
|
||||||
public static function delete($id) {
|
|
||||||
$contact = self::find($id);
|
|
||||||
if (!$contact) {
|
|
||||||
\OCP\Util::writeLog('contacts', __METHOD__.', id: '
|
|
||||||
. $id . ' not found.', \OCP\Util::DEBUG);
|
|
||||||
throw new \Exception(
|
|
||||||
App::$l10n->t(
|
|
||||||
'Could not find the vCard with ID: ' . $id, 404
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
$addressbook = Addressbook::find($contact['addressbookid']);
|
|
||||||
if(!$addressbook) {
|
|
||||||
throw new \Exception(
|
|
||||||
App::$l10n->t(
|
|
||||||
'Could not find the Addressbook with ID: '
|
|
||||||
. $contact['addressbookid'], 404
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($addressbook['userid'] != \OCP\User::getUser() && !\OC_Group::inGroup(\OCP\User::getUser(), 'admin')) {
|
|
||||||
\OCP\Util::writeLog('contacts', __METHOD__.', '
|
|
||||||
. $addressbook['userid'] . ' != ' . \OCP\User::getUser(), \OCP\Util::DEBUG);
|
|
||||||
$sharedAddressbook = \OCP\Share::getItemSharedWithBySource(
|
|
||||||
'addressbook',
|
|
||||||
$contact['addressbookid'],
|
|
||||||
\OCP\Share::FORMAT_NONE, null, true);
|
|
||||||
$sharedContact = \OCP\Share::getItemSharedWithBySource(
|
|
||||||
'contact',
|
|
||||||
$id,
|
|
||||||
\OCP\Share::FORMAT_NONE, null, true);
|
|
||||||
$addressbook_permissions = 0;
|
|
||||||
$contact_permissions = 0;
|
|
||||||
if ($sharedAddressbook) {
|
|
||||||
$addressbook_permissions = $sharedAddressbook['permissions'];
|
|
||||||
}
|
|
||||||
if ($sharedContact) {
|
|
||||||
$contact_permissions = $sharedEvent['permissions'];
|
|
||||||
}
|
|
||||||
$permissions = max($addressbook_permissions, $contact_permissions);
|
|
||||||
|
|
||||||
if (!($permissions & \OCP\PERMISSION_DELETE)) {
|
|
||||||
throw new \Exception(
|
|
||||||
App::$l10n->t(
|
|
||||||
'You do not have the permissions to delete this contact.', 403
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$aid = $contact['addressbookid'];
|
|
||||||
\OC_Hook::emit('\OCA\Contacts\VCard', 'pre_deleteVCard',
|
|
||||||
array('aid' => null, 'id' => $id, 'uri' => null)
|
|
||||||
);
|
|
||||||
$stmt = \OCP\DB::prepare('DELETE FROM `*PREFIX*contacts_cards` WHERE `id` = ?');
|
|
||||||
try {
|
|
||||||
$stmt->execute(array($id));
|
|
||||||
} catch(\Exception $e) {
|
|
||||||
\OCP\Util::writeLog('contacts', __METHOD__.
|
|
||||||
', exception: ' . $e->getMessage(), \OCP\Util::ERROR);
|
|
||||||
\OCP\Util::writeLog('contacts', __METHOD__.', id: '
|
|
||||||
. $id, \OCP\Util::DEBUG);
|
|
||||||
throw new \Exception(
|
|
||||||
App::$l10n->t(
|
|
||||||
'There was an error deleting this contact.'
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
App::updateDBProperties($id);
|
|
||||||
App::getVCategories()->purgeObjects(array($id));
|
|
||||||
Addressbook::touch($addressbook['id']);
|
|
||||||
|
|
||||||
// Contact sharing not enabled, so comment out this
|
|
||||||
//\OCP\Share::unshareAll('contact', $id);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief deletes a card with the data provided by sabredav
|
|
||||||
* @param integer $aid Addressbook id
|
|
||||||
* @param string $uri the uri of the card
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
public static function deleteFromDAVData($aid, $uri) {
|
|
||||||
$contact = self::findWhereDAVDataIs($aid, $uri);
|
|
||||||
if(!$contact) {
|
|
||||||
\OCP\Util::writeLog('contacts', __METHOD__.', contact not found: '
|
|
||||||
. $uri, \OCP\Util::DEBUG);
|
|
||||||
throw new \Sabre_DAV_Exception_NotFound(
|
|
||||||
App::$l10n->t(
|
|
||||||
'Contact not found.'
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
$id = $contact['id'];
|
|
||||||
try {
|
|
||||||
return self::delete($id);
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
switch($e->getCode()) {
|
|
||||||
case 403:
|
|
||||||
\OCP\Util::writeLog('contacts', __METHOD__.', forbidden: '
|
|
||||||
. $uri, \OCP\Util::DEBUG);
|
|
||||||
throw new \Sabre_DAV_Exception_Forbidden(
|
|
||||||
App::$l10n->t(
|
|
||||||
$e->getMessage()
|
|
||||||
)
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
case 404:
|
|
||||||
\OCP\Util::writeLog('contacts', __METHOD__.', contact not found: '
|
|
||||||
. $uri, \OCP\Util::DEBUG);
|
|
||||||
throw new \Sabre_DAV_Exception_NotFound(
|
|
||||||
App::$l10n->t(
|
|
||||||
$e->getMessage()
|
|
||||||
)
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw $e;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Data structure of vCard
|
|
||||||
* @param Sabre\VObject\Component $property
|
|
||||||
* @return associative array
|
|
||||||
*
|
|
||||||
* look at code ...
|
|
||||||
*/
|
|
||||||
public static function structureContact($vcard) {
|
|
||||||
$details = array();
|
|
||||||
|
|
||||||
foreach($vcard->children as $property) {
|
|
||||||
$pname = $property->name;
|
|
||||||
$temp = self::structureProperty($property);
|
|
||||||
if(!is_null($temp)) {
|
|
||||||
// Get Apple X-ABLabels
|
|
||||||
if(isset($vcard->{$property->group . '.X-ABLABEL'})) {
|
|
||||||
$temp['label'] = $vcard->{$property->group . '.X-ABLABEL'}->value;
|
|
||||||
if($temp['label'] == '_$!<Other>!$_') {
|
|
||||||
$temp['label'] = App::$l10n->t('Other');
|
|
||||||
}
|
|
||||||
if($temp['label'] == '_$!<HomePage>!$_') {
|
|
||||||
$temp['label'] = App::$l10n->t('HomePage');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(array_key_exists($pname, $details)) {
|
|
||||||
$details[$pname][] = $temp;
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
$details[$pname] = array($temp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return $details;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Data structure of properties
|
|
||||||
* @param object $property
|
|
||||||
* @return associative array
|
|
||||||
*
|
|
||||||
* returns an associative array with
|
|
||||||
* ['name'] name of property
|
|
||||||
* ['value'] htmlspecialchars escaped value of property
|
|
||||||
* ['parameters'] associative array name=>value
|
|
||||||
* ['checksum'] checksum of whole property
|
|
||||||
* NOTE: $value is not escaped anymore. It shouldn't make any difference
|
|
||||||
* but we should look out for any problems.
|
|
||||||
*/
|
|
||||||
public static function structureProperty($property) {
|
|
||||||
if(!in_array($property->name, App::$index_properties)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
$value = $property->value;
|
|
||||||
if($property->name == 'ADR' || $property->name == 'N' || $property->name == 'ORG' || $property->name == 'CATEGORIES') {
|
|
||||||
$value = $property->getParts();
|
|
||||||
$value = array_map('trim', $value);
|
|
||||||
}
|
|
||||||
elseif($property->name == 'BDAY') {
|
|
||||||
if(strpos($value, '-') === false) {
|
|
||||||
if(strlen($value) >= 8) {
|
|
||||||
$value = substr($value, 0, 4).'-'.substr($value, 4, 2).'-'.substr($value, 6, 2);
|
|
||||||
} else {
|
|
||||||
return null; // Badly malformed :-(
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} elseif($property->name == 'PHOTO') {
|
|
||||||
$value = true;
|
|
||||||
}
|
|
||||||
elseif($property->name == 'IMPP') {
|
|
||||||
if(strpos($value, ':') !== false) {
|
|
||||||
$value = explode(':', $value);
|
|
||||||
$protocol = array_shift($value);
|
|
||||||
if(!isset($property['X-SERVICE-TYPE'])) {
|
|
||||||
$property['X-SERVICE-TYPE'] = strtoupper(\OCP\Util::sanitizeHTML($protocol));
|
|
||||||
}
|
|
||||||
$value = implode('', $value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(is_string($value)) {
|
|
||||||
$value = strtr($value, array('\,' => ',', '\;' => ';'));
|
|
||||||
}
|
|
||||||
$temp = array(
|
|
||||||
//'name' => $property->name,
|
|
||||||
'value' => $value,
|
|
||||||
'parameters' => array()
|
|
||||||
);
|
|
||||||
|
|
||||||
// This cuts around a 3rd off of the json response size.
|
|
||||||
if(in_array($property->name, App::$multi_properties)) {
|
|
||||||
$temp['checksum'] = substr(md5($property->serialize()), 0, 8);
|
|
||||||
}
|
|
||||||
foreach($property->parameters as $parameter) {
|
|
||||||
// Faulty entries by kaddressbook
|
|
||||||
// Actually TYPE=PREF is correct according to RFC 2426
|
|
||||||
// but this way is more handy in the UI. Tanghus.
|
|
||||||
if($parameter->name == 'TYPE' && strtoupper($parameter->value) == 'PREF') {
|
|
||||||
$parameter->name = 'PREF';
|
|
||||||
$parameter->value = '1';
|
|
||||||
}
|
|
||||||
// NOTE: Apparently Sabre_VObject_Reader can't always deal with value list parameters
|
|
||||||
// like TYPE=HOME,CELL,VOICE. Tanghus.
|
|
||||||
// TODO: Check if parameter is has commas and split + merge if so.
|
|
||||||
if ($parameter->name == 'TYPE') {
|
|
||||||
$pvalue = $parameter->value;
|
|
||||||
if(is_string($pvalue) && strpos($pvalue, ',') !== false) {
|
|
||||||
$pvalue = array_map('trim', explode(',', $pvalue));
|
|
||||||
}
|
|
||||||
$pvalue = is_array($pvalue) ? $pvalue : array($pvalue);
|
|
||||||
if (isset($temp['parameters'][$parameter->name])) {
|
|
||||||
$temp['parameters'][$parameter->name][] = \OCP\Util::sanitizeHTML($pvalue);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$temp['parameters'][$parameter->name] = \OCP\Util::sanitizeHTML($pvalue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
$temp['parameters'][$parameter->name] = \OCP\Util::sanitizeHTML($parameter->value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return $temp;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Move card(s) to an address book
|
|
||||||
* @param integer $aid Address book id
|
|
||||||
* @param $id Array or integer of cards to be moved.
|
|
||||||
* @return boolean
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public static function moveToAddressBook($aid, $id, $isAddressbook = false) {
|
|
||||||
Addressbook::find($aid);
|
|
||||||
$addressbook = Addressbook::find($aid);
|
|
||||||
if ($addressbook['userid'] != \OCP\User::getUser()) {
|
|
||||||
$sharedAddressbook = \OCP\Share::getItemSharedWithBySource('addressbook', $aid);
|
|
||||||
if (!$sharedAddressbook || !($sharedAddressbook['permissions'] & \OCP\PERMISSION_CREATE)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(is_array($id)) {
|
|
||||||
foreach ($id as $index => $cardId) {
|
|
||||||
$card = self::find($cardId);
|
|
||||||
if (!$card) {
|
|
||||||
unset($id[$index]);
|
|
||||||
}
|
|
||||||
$oldAddressbook = Addressbook::find($card['addressbookid']);
|
|
||||||
if ($oldAddressbook['userid'] != \OCP\User::getUser()) {
|
|
||||||
$sharedContact = \OCP\Share::getItemSharedWithBySource('contact', $cardId, \OCP\Share::FORMAT_NONE, null, true);
|
|
||||||
if (!$sharedContact || !($sharedContact['permissions'] & \OCP\PERMISSION_DELETE)) {
|
|
||||||
unset($id[$index]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$id_sql = join(',', array_fill(0, count($id), '?'));
|
|
||||||
$prep = 'UPDATE `*PREFIX*contacts_cards` SET `addressbookid` = ? WHERE `id` IN ('.$id_sql.')';
|
|
||||||
try {
|
|
||||||
$stmt = \OCP\DB::prepare( $prep );
|
|
||||||
//$aid = array($aid);
|
|
||||||
$vals = array_merge((array)$aid, $id);
|
|
||||||
$result = $stmt->execute($vals);
|
|
||||||
if (\OC_DB::isError($result)) {
|
|
||||||
\OC_Log::write('contacts', __METHOD__. 'DB error: ' . \OC_DB::getErrorMessage($result), \OC_Log::ERROR);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} catch(\Exception $e) {
|
|
||||||
\OCP\Util::writeLog('contacts', __METHOD__.', exception: '.$e->getMessage(), \OCP\Util::ERROR);
|
|
||||||
\OCP\Util::writeLog('contacts', __METHOD__.', ids: '.join(',', $vals), \OCP\Util::DEBUG);
|
|
||||||
\OCP\Util::writeLog('contacts', __METHOD__.', SQL:'.$prep, \OCP\Util::DEBUG);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$stmt = null;
|
|
||||||
if($isAddressbook) {
|
|
||||||
$stmt = \OCP\DB::prepare( 'UPDATE `*PREFIX*contacts_cards` SET `addressbookid` = ? WHERE `addressbookid` = ?' );
|
|
||||||
} else {
|
|
||||||
$card = self::find($id);
|
|
||||||
if (!$card) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
$oldAddressbook = Addressbook::find($card['addressbookid']);
|
|
||||||
if ($oldAddressbook['userid'] != \OCP\User::getUser()) {
|
|
||||||
$sharedContact = \OCP\Share::getItemSharedWithBySource('contact', $id, \OCP\Share::FORMAT_NONE, null, true);
|
|
||||||
if (!$sharedContact || !($sharedContact['permissions'] & \OCP\PERMISSION_DELETE)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$stmt = \OCP\DB::prepare( 'UPDATE `*PREFIX*contacts_cards` SET `addressbookid` = ? WHERE `id` = ?' );
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
$result = $stmt->execute(array($aid, $id));
|
|
||||||
if (\OC_DB::isError($result)) {
|
|
||||||
\OC_Log::write('contacts', __METHOD__. 'DB error: ' . \OC_DB::getErrorMessage($result), \OC_Log::ERROR);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} catch(\Exception $e) {
|
|
||||||
\OCP\Util::writeLog('contacts', __METHOD__.', exception: '.$e->getMessage(), \OCP\Util::DEBUG);
|
|
||||||
\OCP\Util::writeLog('contacts', __METHOD__.' id: '.$id, \OCP\Util::DEBUG);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
\OC_Hook::emit('\OCA\Contacts\VCard', 'post_moveToAddressbook', array('aid' => $aid, 'id' => $id));
|
|
||||||
Addressbook::touch($aid);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
82
lib/vobject/stringproperty.php
Normal file
82
lib/vobject/stringproperty.php
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* ownCloud - VObject String Property
|
||||||
|
*
|
||||||
|
* This class adds escaping/unescaping of simple string properties.
|
||||||
|
*
|
||||||
|
* @author Thomas Tanghus
|
||||||
|
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||||
|
*
|
||||||
|
* 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\VObject;
|
||||||
|
|
||||||
|
use Sabre\VObject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class overrides \Sabre\VObject\Property::serialize() properly
|
||||||
|
* escape commas and semi-colons in string properties.
|
||||||
|
*/
|
||||||
|
class StringProperty extends VObject\Property {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Turns the object back into a serialized blob.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function serialize() {
|
||||||
|
|
||||||
|
$str = $this->name;
|
||||||
|
if ($this->group) {
|
||||||
|
$str = $this->group . '.' . $this->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach($this->parameters as $param) {
|
||||||
|
$str.=';' . $param->serialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
$src = array(
|
||||||
|
'\\',
|
||||||
|
"\n",
|
||||||
|
';',
|
||||||
|
',',
|
||||||
|
);
|
||||||
|
$out = array(
|
||||||
|
'\\\\',
|
||||||
|
'\n',
|
||||||
|
'\;',
|
||||||
|
'\,',
|
||||||
|
);
|
||||||
|
$value = strtr($this->value, array('\,' => ',', '\;' => ';', '\\\\' => '\\'));
|
||||||
|
$str.=':' . str_replace($src, $out, $value);
|
||||||
|
|
||||||
|
$out = '';
|
||||||
|
while(strlen($str) > 0) {
|
||||||
|
if (strlen($str) > 75) {
|
||||||
|
$out .= mb_strcut($str, 0, 75, 'utf-8') . "\r\n";
|
||||||
|
$str = ' ' . mb_strcut($str, 75, strlen($str), 'utf-8');
|
||||||
|
} else {
|
||||||
|
$out .= $str . "\r\n";
|
||||||
|
$str = '';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $out;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
229
lib/vobject/vcard.php
Normal file
229
lib/vobject/vcard.php
Normal file
@ -0,0 +1,229 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* ownCloud - VCard component
|
||||||
|
*
|
||||||
|
* This component represents the BEGIN:VCARD and END:VCARD found in every
|
||||||
|
* vcard.
|
||||||
|
*
|
||||||
|
* @author Thomas Tanghus
|
||||||
|
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||||
|
*
|
||||||
|
* 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\VObject;
|
||||||
|
|
||||||
|
use OCA\Contacts\Utils;
|
||||||
|
use Sabre\VObject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class overrides \Sabre\VObject\Component\VCard::validate() to be add
|
||||||
|
* to import partially invalid vCards by ignoring invalid lines and to
|
||||||
|
* validate and upgrade using ....
|
||||||
|
*/
|
||||||
|
class VCard extends VObject\Component\VCard {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The following constants are used by the validate() method.
|
||||||
|
*/
|
||||||
|
const REPAIR = 1;
|
||||||
|
const UPGRADE = 2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* VCards with version 2.1, 3.0 and 4.0 are found.
|
||||||
|
*
|
||||||
|
* If the VCARD doesn't know its version, 3.0 is assumed and if
|
||||||
|
* option UPGRADE is given it will be upgraded to version 3.0.
|
||||||
|
*/
|
||||||
|
const DEFAULT_VERSION = '3.0';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Format property TYPE parameters for upgrading from v. 2.1
|
||||||
|
* @param $property Reference to a \Sabre\VObject\Property.
|
||||||
|
* In version 2.1 e.g. a phone can be formatted like: TEL;HOME;CELL:123456789
|
||||||
|
* This has to be changed to either TEL;TYPE=HOME,CELL:123456789 or TEL;TYPE=HOME;TYPE=CELL:123456789 - both are valid.
|
||||||
|
*/
|
||||||
|
protected function formatPropertyTypes(&$property) {
|
||||||
|
foreach($property->parameters as $key=>&$parameter) {
|
||||||
|
$types = Utils\Properties::getTypesForProperty($property->name);
|
||||||
|
if(is_array($types) && in_array(strtoupper($parameter->name), array_keys($types))
|
||||||
|
|| strtoupper($parameter->name) == 'PREF') {
|
||||||
|
unset($property->parameters[$key]);
|
||||||
|
$property->add('TYPE', $parameter->name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Decode properties for upgrading from v. 2.1
|
||||||
|
* @param $property Reference to a \Sabre\VObject\Property.
|
||||||
|
* The only encoding allowed in version 3.0 is 'b' for binary. All encoded strings
|
||||||
|
* must therefore be decoded and the parameters removed.
|
||||||
|
*/
|
||||||
|
protected function decodeProperty(&$property) {
|
||||||
|
// Check out for encoded string and decode them :-[
|
||||||
|
foreach($property->parameters as $key=>&$parameter) {
|
||||||
|
if(strtoupper($parameter->name) == 'ENCODING') {
|
||||||
|
if(strtoupper($parameter->value) == 'QUOTED-PRINTABLE') {
|
||||||
|
// Decode quoted-printable and strip any control chars
|
||||||
|
// except \n and \r
|
||||||
|
$property->value = str_replace(
|
||||||
|
"\r\n", "\n",
|
||||||
|
VObject\StringUtil::convertToUTF8(
|
||||||
|
quoted_printable_decode($property->value)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
unset($property->parameters[$key]);
|
||||||
|
} else if(strtoupper($parameter->value) == 'BASE64') {
|
||||||
|
$parameter->value = 'b';
|
||||||
|
}
|
||||||
|
} elseif(strtoupper($parameter->name) == 'CHARSET') {
|
||||||
|
unset($property->parameters[$key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates the node for correctness.
|
||||||
|
*
|
||||||
|
* The following options are supported:
|
||||||
|
* - VCard::REPAIR - If something is broken, and automatic repair may
|
||||||
|
* be attempted.
|
||||||
|
* - VCard::UPGRADE - If needed the vCard will be upgraded to version 3.0.
|
||||||
|
*
|
||||||
|
* An array is returned with warnings.
|
||||||
|
*
|
||||||
|
* Every item in the array has the following properties:
|
||||||
|
* * level - (number between 1 and 3 with severity information)
|
||||||
|
* * message - (human readable message)
|
||||||
|
* * node - (reference to the offending node)
|
||||||
|
*
|
||||||
|
* @param int $options
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function validate($options = 0) {
|
||||||
|
|
||||||
|
$warnings = array();
|
||||||
|
|
||||||
|
$version = $this->select('VERSION');
|
||||||
|
if (count($version) !== 1) {
|
||||||
|
$warnings[] = array(
|
||||||
|
'level' => 1,
|
||||||
|
'message' => 'The VERSION property must appear in the VCARD component exactly 1 time',
|
||||||
|
'node' => $this,
|
||||||
|
);
|
||||||
|
if ($options & self::REPAIR) {
|
||||||
|
$this->VERSION = self::DEFAULT_VERSION;
|
||||||
|
if (!$options & self::UPGRADE) {
|
||||||
|
$options |= self::UPGRADE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$version = (string)$this->VERSION;
|
||||||
|
if ($version!=='2.1' && $version!=='3.0' && $version!=='4.0') {
|
||||||
|
$warnings[] = array(
|
||||||
|
'level' => 1,
|
||||||
|
'message' => 'Only vcard version 4.0 (RFC6350), version 3.0 (RFC2426) or version 2.1 (icm-vcard-2.1) are supported.',
|
||||||
|
'node' => $this,
|
||||||
|
);
|
||||||
|
if ($options & self::REPAIR) {
|
||||||
|
$this->VERSION = self::DEFAULT_VERSION;
|
||||||
|
if (!$options & self::UPGRADE) {
|
||||||
|
$options |= self::UPGRADE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
$fn = $this->select('FN');
|
||||||
|
if (count($fn) !== 1) {
|
||||||
|
$warnings[] = array(
|
||||||
|
'level' => 1,
|
||||||
|
'message' => 'The FN property must appear in the VCARD component exactly 1 time',
|
||||||
|
'node' => $this,
|
||||||
|
);
|
||||||
|
if (($options & self::REPAIR) && count($fn) === 0) {
|
||||||
|
// We're going to try to see if we can use the contents of the
|
||||||
|
// N property.
|
||||||
|
if (isset($this->N)) {
|
||||||
|
$value = explode(';', (string)$this->N);
|
||||||
|
if (isset($value[1]) && $value[1]) {
|
||||||
|
$this->FN = $value[1] . ' ' . $value[0];
|
||||||
|
} else {
|
||||||
|
$this->FN = $value[0];
|
||||||
|
}
|
||||||
|
// Otherwise, the ORG property may work
|
||||||
|
} elseif (isset($this->ORG)) {
|
||||||
|
$this->FN = (string)$this->ORG;
|
||||||
|
} elseif (isset($this->EMAIL)) {
|
||||||
|
$this->FN = (string)$this->EMAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$n = $this->select('N');
|
||||||
|
if (count($n) !== 1) {
|
||||||
|
$warnings[] = array(
|
||||||
|
'level' => 1,
|
||||||
|
'message' => 'The N property must appear in the VCARD component exactly 1 time',
|
||||||
|
'node' => $this,
|
||||||
|
);
|
||||||
|
// TODO: Make a better effort parsing FN.
|
||||||
|
if (($options & self::REPAIR) && count($n) === 0) {
|
||||||
|
// Take 2 first name parts of 'FN' and reverse.
|
||||||
|
$slice = array_reverse(array_slice(explode(' ', (string)$this->FN), 0, 2));
|
||||||
|
if(count($slice) < 2) { // If not enought, add one more...
|
||||||
|
$slice[] = "";
|
||||||
|
}
|
||||||
|
$this->N = implode(';', $slice).';;;';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($this->UID)) {
|
||||||
|
$warnings[] = array(
|
||||||
|
'level' => 1,
|
||||||
|
'message' => 'Every vCard must have a UID',
|
||||||
|
'node' => $this,
|
||||||
|
);
|
||||||
|
if ($options & self::REPAIR) {
|
||||||
|
$this->UID = Utils\Properties::generateUID();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($options & self::UPGRADE) {
|
||||||
|
$this->VERSION = self::DEFAULT_VERSION;
|
||||||
|
foreach($this->children as &$property) {
|
||||||
|
$this->decodeProperty($property);
|
||||||
|
$this->formatPropertyTypes($property);
|
||||||
|
//\OCP\Util::writeLog('contacts', __METHOD__.' upgrade: '.$property->name, \OCP\Util::DEBUG);
|
||||||
|
switch((string)$property->name) {
|
||||||
|
case 'LOGO':
|
||||||
|
case 'SOUND':
|
||||||
|
case 'PHOTO':
|
||||||
|
if(isset($property['TYPE']) && strpos((string)$property['TYPE'], '/') === false) {
|
||||||
|
$property['TYPE'] = 'image/' . strtolower($property['TYPE']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return array_merge(
|
||||||
|
parent::validate($options),
|
||||||
|
$warnings
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -21,6 +21,8 @@ function getStandardImage() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$id = isset($_GET['id']) ? $_GET['id'] : null;
|
$id = isset($_GET['id']) ? $_GET['id'] : null;
|
||||||
|
$parent = isset($_GET['parent']) ? $_GET['parent'] : null;
|
||||||
|
$backend = isset($_GET['backend']) ? $_GET['backend'] : null;
|
||||||
$etag = null;
|
$etag = null;
|
||||||
$caching = null;
|
$caching = null;
|
||||||
$max_size = 170;
|
$max_size = 170;
|
||||||
@ -35,7 +37,8 @@ if(!extension_loaded('gd') || !function_exists('gd_info')) {
|
|||||||
getStandardImage();
|
getStandardImage();
|
||||||
}
|
}
|
||||||
|
|
||||||
$contact = OCA\Contacts\App::getContactVCard($id);
|
$app = new OCA\Contacts\App();
|
||||||
|
$contact = $app->getContact($backend, $parent, $id);
|
||||||
$image = new OC_Image();
|
$image = new OC_Image();
|
||||||
if (!$image || !$contact) {
|
if (!$image || !$contact) {
|
||||||
getStandardImage();
|
getStandardImage();
|
||||||
@ -58,10 +61,10 @@ if (is_null($contact)) {
|
|||||||
$etag = md5($contact->LOGO);
|
$etag = md5($contact->LOGO);
|
||||||
}
|
}
|
||||||
if ($image->valid()) {
|
if ($image->valid()) {
|
||||||
$modified = OCA\Contacts\App::lastModified($contact);
|
$modified = $contact->lastModified();
|
||||||
// Force refresh if modified within the last minute.
|
// Force refresh if modified within the last minute.
|
||||||
if(!is_null($modified)) {
|
if(!is_null($modified)) {
|
||||||
$caching = (time() - $modified->format('U') > 60) ? null : 0;
|
$caching = (time() - $modified > 60) ? null : 0;
|
||||||
}
|
}
|
||||||
OCP\Response::enableCaching($caching);
|
OCP\Response::enableCaching($caching);
|
||||||
if(!is_null($modified)) {
|
if(!is_null($modified)) {
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
<form class="float" id="file_upload_form" action="<?php print_unescaped(OCP\Util::linkTo('contacts', 'ajax/uploadphoto.php')); ?>" method="post" enctype="multipart/form-data" target="file_upload_target">
|
<form class="float" id="file_upload_form" action="<?php print_unescaped(OCP\Util::linkTo('contacts', 'ajax/uploadphoto.php')); ?>" method="post" enctype="multipart/form-data" target="file_upload_target">
|
||||||
<input type="hidden" name="id" value="">
|
<input type="hidden" name="contactid" value="">
|
||||||
|
<input type="hidden" name="addressbookid" value="">
|
||||||
|
<input type="hidden" name="backend" value="">
|
||||||
<input type="hidden" name="requesttoken" value="<?php p($_['requesttoken']) ?>">
|
<input type="hidden" name="requesttoken" value="<?php p($_['requesttoken']) ?>">
|
||||||
<input type="hidden" name="MAX_FILE_SIZE" value="<?php p($_['uploadMaxFilesize']) ?>" id="max_upload">
|
<input type="hidden" name="MAX_FILE_SIZE" value="<?php p($_['uploadMaxFilesize']) ?>" id="max_upload">
|
||||||
<input type="hidden" class="max_human_file_size" value="(max <?php p($_['uploadMaxHumanFilesize']); ?>)">
|
<input type="hidden" class="max_human_file_size" value="(max <?php p($_['uploadMaxHumanFilesize']); ?>)">
|
||||||
@ -25,17 +27,30 @@
|
|||||||
<button class="addaddressbookcancel"><?php p($l->t('Cancel')); ?></button>
|
<button class="addaddressbookcancel"><?php p($l->t('Cancel')); ?></button>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
<button class="addaddressbook icon-plus text"><?php p($l->t('New')); ?></button>
|
||||||
|
<ul class="hidden">
|
||||||
|
<li><input class="addaddressbookinput" type="text" placeholder="<?php p($l->t('Display name')); ?>" /></li>
|
||||||
|
<li>
|
||||||
|
<button class="addaddressbookok"><?php p($l->t('OK')); ?></button>
|
||||||
|
<button class="addaddressbookcancel"><?php p($l->t('Cancel')); ?></button>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
<h2 data-id="import" tabindex="0" role="button"><?php p($l->t('Import')); ?></h2>
|
<h2 data-id="import" tabindex="0" role="button"><?php p($l->t('Import')); ?></h2>
|
||||||
<ul class="hidden">
|
<ul class="hidden">
|
||||||
<li class="import-upload">
|
<li class="import-upload">
|
||||||
<form id="import_upload_form" action="<?php print_unescaped(OCP\Util::linkTo('contacts', 'ajax/uploadimport.php')); ?>" method="post" enctype="multipart/form-data" target="import_upload_target">
|
<form
|
||||||
|
id="import_upload_form"
|
||||||
|
data-upload-id="1"
|
||||||
|
action="<?php print_unescaped(OCP\Util::linkTo('contacts', 'ajax/uploadimport.php')); ?>"
|
||||||
|
method="post" enctype="multipart/form-data"
|
||||||
|
target="import_upload_target_1">
|
||||||
<input type="hidden" name="MAX_FILE_SIZE" value="<?php p($_['uploadMaxFilesize']) ?>" id="max_upload">
|
<input type="hidden" name="MAX_FILE_SIZE" value="<?php p($_['uploadMaxFilesize']) ?>" id="max_upload">
|
||||||
<label for="import_fileupload"><?php p($l->t('Select files to import')); ?>
|
<label for="import_upload_start"><?php p($l->t('Select files to import')); ?>
|
||||||
<button class="import-upload-button" title="<?php p($l->t('Select files')); ?>"></button>
|
<button class="import-upload-button" title="<?php p($l->t('Select files')); ?>"></button>
|
||||||
</label>
|
</label>
|
||||||
<input id="import_fileupload" type="file" accept="text/vcard,text/x-vcard,text/directory" multiple="multiple" name="importfile" />
|
<input id="import_upload_start" type="file" accept="text/vcard,text/x-vcard,text/directory" multiple="multiple" name="file" />
|
||||||
</form>
|
</form>
|
||||||
<iframe name="import_upload_target" id='import_upload_target' src=""></iframe>
|
<!-- iframe name="import_upload_target" id='import_upload_target' src=""></iframe -->
|
||||||
</li>
|
</li>
|
||||||
<li class="import-select hidden"><label><?php p($l->t('Import into:')); ?></label></li>
|
<li class="import-select hidden"><label><?php p($l->t('Import into:')); ?></label></li>
|
||||||
<li class="import-select hidden">
|
<li class="import-select hidden">
|
||||||
@ -59,6 +74,7 @@
|
|||||||
<option value="-1" disabled="disabled" selected="selected"><?php p($l->t('Groups')); ?></option>
|
<option value="-1" disabled="disabled" selected="selected"><?php p($l->t('Groups')); ?></option>
|
||||||
</select>
|
</select>
|
||||||
<button class="favorite action svg inactive control" title="<?php p($l->t('Favorite')); ?>"></button>
|
<button class="favorite action svg inactive control" title="<?php p($l->t('Favorite')); ?>"></button>
|
||||||
|
<button class="merge"><?php p($l->t('Merge selected')); ?></button>
|
||||||
<a class="delete action" title="<?php p($l->t('Delete Contact')); ?>"></a>
|
<a class="delete action" title="<?php p($l->t('Delete Contact')); ?>"></a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -113,7 +129,9 @@
|
|||||||
enctype="multipart/form-data"
|
enctype="multipart/form-data"
|
||||||
target="crop_target"
|
target="crop_target"
|
||||||
action="<?php print_unescaped(OCP\Util::linkToAbsolute('contacts', 'ajax/savecrop.php')); ?>">
|
action="<?php print_unescaped(OCP\Util::linkToAbsolute('contacts', 'ajax/savecrop.php')); ?>">
|
||||||
<input type="hidden" id="id" name="id" value="{id}" />
|
<input type="hidden" id="contactid" name="contactid" value="{contactid}" />
|
||||||
|
<input type="hidden" id="addressbookid" name="addressbookid" value="{addressbookid}" />
|
||||||
|
<input type="hidden" id="backend" name="backend" value="{backend}" />
|
||||||
<input type="hidden" id="tmpkey" name="tmpkey" value="{tmpkey}" />
|
<input type="hidden" id="tmpkey" name="tmpkey" value="{tmpkey}" />
|
||||||
<fieldset id="coords">
|
<fieldset id="coords">
|
||||||
<input type="hidden" id="x1" name="x1" value="" />
|
<input type="hidden" id="x1" name="x1" value="" />
|
||||||
@ -134,10 +152,24 @@
|
|||||||
</div>
|
</div>
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<script id="mergeContactsTemplate" type="text/template">
|
||||||
|
<div id="dialog-merge-contacts" title="<?php p($l->t('Merge contacts')); ?>">
|
||||||
|
<p><?php p($l->t('Which contact should the data be merged into?')); ?></p>
|
||||||
|
<fieldset>
|
||||||
|
<ul class="mergelist">
|
||||||
|
<li><input id="mergee_{idx}" type="radio" name="contact" value="{id}"><label for="mergee_{idx}" >{displayname}</label></li>
|
||||||
|
</ul>
|
||||||
|
</fieldset>
|
||||||
|
<p>
|
||||||
|
<input type="checkbox" id="delete_other" name="delete_other" />
|
||||||
|
<label for="delete_other"><?php p($l->t('Delete the other(s) after successful merge?')); ?></label>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</script>
|
||||||
|
|
||||||
<script id="contactListItemTemplate" type="text/template">
|
<script id="contactListItemTemplate" type="text/template">
|
||||||
<tr class="contact" data-id="{id}">
|
<tr class="contact" data-id="{id}">
|
||||||
<td class="name"
|
<td class="name thumbnail">
|
||||||
style="background: url('<?php print_unescaped(OC_Helper::linkToRemoteBase('contactthumbnail')); ?>?id={id}')">
|
|
||||||
<input type="checkbox" name="id" value="{id}" /><span class="nametext">{name}</span>
|
<input type="checkbox" name="id" value="{id}" /><span class="nametext">{name}</span>
|
||||||
</td>
|
</td>
|
||||||
<td class="email">
|
<td class="email">
|
||||||
@ -151,8 +183,7 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script id="contactDragItemTemplate" type="text/template">
|
<script id="contactDragItemTemplate" type="text/template">
|
||||||
<div class="dragContact" data-id="{id}"
|
<div class="dragContact thumbnail" data-id="{id}">
|
||||||
style="background: url('<?php print_unescaped(OC_Helper::linkToRemoteBase('contactthumbnail')); ?>?id={id}')">
|
|
||||||
{name}
|
{name}
|
||||||
</div>
|
</div>
|
||||||
</script>
|
</script>
|
||||||
@ -173,10 +204,10 @@
|
|||||||
<li>
|
<li>
|
||||||
<div id="photowrapper" class="propertycontainer" data-element="photo">
|
<div id="photowrapper" class="propertycontainer" data-element="photo">
|
||||||
<ul id="phototools" class="transparent hidden">
|
<ul id="phototools" class="transparent hidden">
|
||||||
<li><a class="action delete" title="<?php p($l->t('Delete current photo')); ?>"></a></li>
|
<li><a class="action delete" title="<?php echo $l->t('Delete current photo'); ?>"></a></li>
|
||||||
<li><a class="action edit" title="<?php p($l->t('Edit current photo')); ?>"></a></li>
|
<li><a class="action edit" title="<?php echo $l->t('Edit current photo'); ?>"></a></li>
|
||||||
<li><a class="action upload" title="<?php p($l->t('Upload new photo')); ?>"></a></li>
|
<li><a class="action upload" title="<?php echo $l->t('Upload new photo'); ?>"></a></li>
|
||||||
<li><a class="action cloud icon-cloud" title="<?php p($l->t('Select photo from ownCloud')); ?>"></a></li>
|
<li><a class="action cloud icon-cloud" title="<?php echo $l->t('Select photo from ownCloud'); ?>"></a></li>
|
||||||
</ul>
|
</ul>
|
||||||
<a class="favorite action {favorite}"></a>
|
<a class="favorite action {favorite}"></a>
|
||||||
</div>
|
</div>
|
||||||
@ -207,6 +238,9 @@
|
|||||||
<div class="groupscontainer propertycontainer" data-element="categories">
|
<div class="groupscontainer propertycontainer" data-element="categories">
|
||||||
<select id="contactgroups" title="<?php p($l->t('Select groups')); ?>" name="value" multiple></select>
|
<select id="contactgroups" title="<?php p($l->t('Select groups')); ?>" name="value" multiple></select>
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<select class="hidden" id="contactaddressbooks" title="<?php p($l->t('Select address book')); ?>" name="value" multiple></select>
|
||||||
|
</div>
|
||||||
<dl class="form">
|
<dl class="form">
|
||||||
<dt data-element="nickname">
|
<dt data-element="nickname">
|
||||||
<?php p($l->t('Nickname')); ?>
|
<?php p($l->t('Nickname')); ?>
|
||||||
@ -289,7 +323,7 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script id="contactDetailsTemplate" class="hidden" type="text/template">
|
<script id="contactDetailsTemplate" class="hidden" type="text/template">
|
||||||
<div class="email">
|
<div class="email" type="text/template">
|
||||||
<li data-element="email" data-checksum="{checksum}" class="propertycontainer">
|
<li data-element="email" data-checksum="{checksum}" class="propertycontainer">
|
||||||
<span class="parameters">
|
<span class="parameters">
|
||||||
<select class="rtl type parameter" data-parameter="TYPE" name="parameters[TYPE][]">
|
<select class="rtl type parameter" data-parameter="TYPE" name="parameters[TYPE][]">
|
||||||
@ -304,7 +338,7 @@
|
|||||||
</span>
|
</span>
|
||||||
</li>
|
</li>
|
||||||
</div>
|
</div>
|
||||||
<div class="tel">
|
<div class="tel" type="text/template">
|
||||||
<li data-element="tel" data-checksum="{checksum}" class="propertycontainer">
|
<li data-element="tel" data-checksum="{checksum}" class="propertycontainer">
|
||||||
<span class="parameters">
|
<span class="parameters">
|
||||||
<select class="rtl type parameter" data-parameter="TYPE" name="parameters[TYPE][]">
|
<select class="rtl type parameter" data-parameter="TYPE" name="parameters[TYPE][]">
|
||||||
@ -318,7 +352,7 @@
|
|||||||
</span>
|
</span>
|
||||||
</li>
|
</li>
|
||||||
</div>
|
</div>
|
||||||
<div class="url">
|
<div class="url" type="text/template">
|
||||||
<li data-element="url" data-checksum="{checksum}" class="propertycontainer">
|
<li data-element="url" data-checksum="{checksum}" class="propertycontainer">
|
||||||
<span class="parameters">
|
<span class="parameters">
|
||||||
<select class="rtl type parameter" data-parameter="TYPE" name="parameters[TYPE][]">
|
<select class="rtl type parameter" data-parameter="TYPE" name="parameters[TYPE][]">
|
||||||
@ -333,7 +367,7 @@
|
|||||||
</span>
|
</span>
|
||||||
</li>
|
</li>
|
||||||
</div>
|
</div>
|
||||||
<div class="adr">
|
<div class="adr" type="text/template">
|
||||||
<li data-element="adr" data-checksum="{checksum}" data-lang="<?php p(OCP\Config::getUserValue(OCP\USER::getUser(), 'core', 'lang', 'en')); ?>" class="propertycontainer">
|
<li data-element="adr" data-checksum="{checksum}" data-lang="<?php p(OCP\Config::getUserValue(OCP\USER::getUser(), 'core', 'lang', 'en')); ?>" class="propertycontainer">
|
||||||
<span class="float display">
|
<span class="float display">
|
||||||
<label class="meta parameters"></label>
|
<label class="meta parameters"></label>
|
||||||
@ -380,7 +414,7 @@
|
|||||||
</fieldset>
|
</fieldset>
|
||||||
</li>
|
</li>
|
||||||
</div>
|
</div>
|
||||||
<div class="impp">
|
<div class="impp" type="text/template">
|
||||||
<li data-element="impp" data-checksum="{checksum}" class="propertycontainer">
|
<li data-element="impp" data-checksum="{checksum}" class="propertycontainer">
|
||||||
<span class="parameters">
|
<span class="parameters">
|
||||||
<select class="type parameter" data-parameter="TYPE" name="parameters[TYPE][]">
|
<select class="type parameter" data-parameter="TYPE" name="parameters[TYPE][]">
|
||||||
|
121
tests/contacts.php
Normal file
121
tests/contacts.php
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2013 Thomas Tanghus (thomas@tanghus.net)
|
||||||
|
* This file is licensed under the Affero General Public License version 3 or
|
||||||
|
* later.
|
||||||
|
* See the COPYING-README file.
|
||||||
|
*/
|
||||||
|
OC_App::loadApp('contacts');
|
||||||
|
class Test_Contacts_Backend_Datebase extends PHPUnit_Framework_TestCase {
|
||||||
|
protected static $schema_file = 'static://test_db_scheme';
|
||||||
|
protected static $test_prefix;
|
||||||
|
protected static $backend;
|
||||||
|
protected static $user;
|
||||||
|
protected static $addressBooksTableName;
|
||||||
|
protected static $cardsTableName;
|
||||||
|
|
||||||
|
public static function setUpBeforeClass() {
|
||||||
|
$dbfile = __DIR__.'/../appinfo/database.xml';
|
||||||
|
|
||||||
|
self::$test_prefix = '_'.OC_Util::generate_random_bytes('4').'_';
|
||||||
|
$content = file_get_contents($dbfile);
|
||||||
|
$content = str_replace( '*dbprefix*', '*dbprefix*'.self::$test_prefix, $content );
|
||||||
|
file_put_contents( self::$schema_file, $content );
|
||||||
|
OC_DB::createDbFromStructure(self::$schema_file);
|
||||||
|
|
||||||
|
self::$addressBooksTableName = '*PREFIX*'.self::$test_prefix.'contacts_addressbooks';
|
||||||
|
self::$cardsTableName = '*PREFIX*'.self::$test_prefix.'contacts_cards';
|
||||||
|
|
||||||
|
OC_User::clearBackends();
|
||||||
|
OC_User::useBackend('dummy');
|
||||||
|
self::$user = uniqid('user_');
|
||||||
|
OC_User::createUser(self::$user, 'pass');
|
||||||
|
OC_User::setUserId(self::$user);
|
||||||
|
|
||||||
|
self::$backend = new OCA\Contacts\Backend\Database(
|
||||||
|
self::$user,
|
||||||
|
self::$addressBooksTableName,
|
||||||
|
self::$cardsTableName
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function tearDownAfterClass() {
|
||||||
|
OC_DB::removeDBStructure(self::$schema_file);
|
||||||
|
unlink(self::$schema_file);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testDatabaseBackend() {
|
||||||
|
|
||||||
|
$this->assertEquals(array(), self::$backend->getAddressBooksForUser());
|
||||||
|
|
||||||
|
$aid = self::$backend->createAddressBook(
|
||||||
|
array(
|
||||||
|
'displayname' => 'Contacts',
|
||||||
|
'description' => 'My Contacts',
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Test address books
|
||||||
|
$this->assertEquals(1, count(self::$backend->getAddressBooksForUser()));
|
||||||
|
$this->assertTrue(self::$backend->hasAddressBook($aid));
|
||||||
|
$addressBook = self::$backend->getAddressBook($aid);
|
||||||
|
$this->assertEquals('Contacts', $addressBook['displayname']);
|
||||||
|
$this->assertEquals('My Contacts', $addressBook['description']);
|
||||||
|
self::$backend->updateAddressBook($aid, array('description' => 'All my contacts'));
|
||||||
|
$addressBook = self::$backend->getAddressBook($aid);
|
||||||
|
$this->assertEquals('All my contacts', $addressBook['description']);
|
||||||
|
|
||||||
|
// Test contacts
|
||||||
|
$this->assertEquals(array(), self::$backend->getContacts($aid));
|
||||||
|
|
||||||
|
$carddata = file_get_contents(__DIR__ . '/data/test.vcf');
|
||||||
|
$id = self::$backend->createContact($aid, $carddata);
|
||||||
|
$this->assertNotEquals(false, $id); // Isn't there an assertNotFalse() ?
|
||||||
|
$this->assertEquals(1, count(self::$backend->getContacts($aid)));
|
||||||
|
$this->assertTrue(self::$backend->hasContact($aid, $id));
|
||||||
|
$contact = self::$backend->getContact($aid, $id);
|
||||||
|
$this->assertEquals('Max Mustermann', $contact['displayname']);
|
||||||
|
$carddata = file_get_contents(__DIR__ . '/data/test2.vcf');
|
||||||
|
$this->assertTrue(self::$backend->updateContact($aid, $id, $carddata));
|
||||||
|
$contact = self::$backend->getContact($aid, $id);
|
||||||
|
$this->assertEquals('John Q. Public', $contact['displayname']);
|
||||||
|
$this->assertTrue(self::$backend->deleteContact($aid, $id));
|
||||||
|
|
||||||
|
$this->assertTrue(self::$backend->deleteAddressBook($aid));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testAddressBook() {
|
||||||
|
$addressBook = new OCA\Contacts\AddressBook(
|
||||||
|
self::$backend,
|
||||||
|
array(
|
||||||
|
'displayname' => 'Contacts',
|
||||||
|
'description' => 'My Contacts',
|
||||||
|
)
|
||||||
|
);
|
||||||
|
$this->assertEquals(0, count($addressBook));
|
||||||
|
$id = $addressBook->addChild(
|
||||||
|
array(
|
||||||
|
'displayname' => 'John Q. Public'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
$this->assertNotEquals(false, $id);
|
||||||
|
$this->assertEquals(1, count($addressBook));
|
||||||
|
$contact = $addressBook->getChild($id);
|
||||||
|
$this->assertEquals('John Q. Public', (string)$contact->FN);
|
||||||
|
$contact->FN = 'Max Mustermann';
|
||||||
|
$contact->save();
|
||||||
|
$contact = $addressBook[$id];
|
||||||
|
$metadata = $contact->getMetaData();
|
||||||
|
$this->assertEquals('Max Mustermann', $metadata['displayname']);
|
||||||
|
|
||||||
|
// Array access
|
||||||
|
$this->assertEquals($contact, $addressBook[$id]);
|
||||||
|
$this->assertTrue(isset($addressBook[$id]));
|
||||||
|
|
||||||
|
// Magic accessors
|
||||||
|
//$this->assertEquals($contact, $addressBook->{$id});
|
||||||
|
|
||||||
|
$this->assertTrue($addressBook->deleteChild($id));
|
||||||
|
$this->assertEquals(0, count($addressBook));
|
||||||
|
}
|
||||||
|
}
|
11
tests/data/test.vcf
Normal file
11
tests/data/test.vcf
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
BEGIN:VCARD
|
||||||
|
VERSION:3.0
|
||||||
|
N:Mustermann;Max;;;
|
||||||
|
FN:Max Mustermann
|
||||||
|
ORG:ownCloud
|
||||||
|
URL:http://owncloud.org/
|
||||||
|
UID:e472ea61
|
||||||
|
EMAIL;TYPE=INTERNET:max.mustermann@example.org
|
||||||
|
TEL;TYPE=voice,work,pref:+49 1234 56788
|
||||||
|
ADR;TYPE=intl,work,postal,parcel:;;Musterstraße 1;Musterstadt;;12345;Germany
|
||||||
|
END:VCARD
|
11
tests/data/test2.vcf
Normal file
11
tests/data/test2.vcf
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
BEGIN:VCARD
|
||||||
|
VERSION:3.0
|
||||||
|
N:Public;John;Quinlan;;
|
||||||
|
FN:John Q. Public
|
||||||
|
ORG:ownCloud
|
||||||
|
URL:http://owncloud.org/
|
||||||
|
UID:e472ea61
|
||||||
|
EMAIL;TYPE=INTERNET:joe.public@example.org
|
||||||
|
TEL;TYPE=voice,work,pref:+49 1234 56788
|
||||||
|
ADR;TYPE=intl,work,postal,parcel:;;Elm Street 1;Metropolis;;12345;USA
|
||||||
|
END:VCARD
|
91
tests/request.php
Normal file
91
tests/request.php
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2013 Thomas Tanghus (thomas@tanghus.net)
|
||||||
|
* This file is licensed under the Affero General Public License version 3 or
|
||||||
|
* later.
|
||||||
|
* See the COPYING-README file.
|
||||||
|
*/
|
||||||
|
OC_App::loadApp('contacts');
|
||||||
|
class Test_Contacts_Request extends PHPUnit_Framework_TestCase {
|
||||||
|
protected static $user;
|
||||||
|
|
||||||
|
public static function setUpBeforeClass() {
|
||||||
|
OC_User::clearBackends();
|
||||||
|
OC_User::useBackend('dummy');
|
||||||
|
self::$user = uniqid('user_');
|
||||||
|
OC_User::createUser(self::$user, 'pass');
|
||||||
|
OC_User::setUserId(self::$user);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testRequestAccessors() {
|
||||||
|
$vars = array(
|
||||||
|
'get' => array('name' => 'John Q. Public', 'nickname' => 'Joey'),
|
||||||
|
'urlParams' => array('user' => self::$user, 'trut' => 'trat'),
|
||||||
|
);
|
||||||
|
|
||||||
|
$request = new OCA\Contacts\Request($vars);
|
||||||
|
|
||||||
|
$this->assertEquals(4, count($request));
|
||||||
|
$this->assertEquals('Joey', $request['nickname']);
|
||||||
|
$this->assertEquals('Joey', $request->{'nickname'});
|
||||||
|
$this->assertEquals('Joey', $request->get['nickname']);
|
||||||
|
$this->assertEquals('Joey', $request->getVar('get', 'nickname'));
|
||||||
|
$this->assertTrue(isset($request['nickname']));
|
||||||
|
$this->assertTrue(isset($request->{'nickname'}));
|
||||||
|
$this->assertEquals(false, isset($request->{'flickname'}));
|
||||||
|
$this->assertEquals(null, $request->{'flickname'});
|
||||||
|
}
|
||||||
|
|
||||||
|
// urlParams has precedence over POST which has precedence over GET
|
||||||
|
public function testPrecedence() {
|
||||||
|
$vars = array(
|
||||||
|
'get' => array('name' => 'John Q. Public', 'nickname' => 'Joey'),
|
||||||
|
'post' => array('name' => 'Jane Doe', 'nickname' => 'Janey'),
|
||||||
|
'urlParams' => array('user' => self::$user, 'name' => 'Johnny Weissmüller'),
|
||||||
|
);
|
||||||
|
|
||||||
|
$request = new OCA\Contacts\Request($vars);
|
||||||
|
|
||||||
|
$this->assertEquals(3, count($request));
|
||||||
|
$this->assertEquals('Janey', $request->{'nickname'});
|
||||||
|
$this->assertEquals('Johnny Weissmüller', $request->{'name'});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test default value
|
||||||
|
public function testDefaultValue() {
|
||||||
|
$vars = array(
|
||||||
|
'get' => array('name' => 'John Q. Public', 'nickname' => 'Joey'),
|
||||||
|
);
|
||||||
|
|
||||||
|
$request = new OCA\Contacts\Request($vars);
|
||||||
|
|
||||||
|
$this->assertEquals(2, count($request));
|
||||||
|
$this->assertEquals('Joey', $request->getVar('get', 'nickname', 'Janey'));
|
||||||
|
$this->assertEquals('Apocalypse Now', $request->getVar('get', 'flickname', 'Apocalypse Now'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException RuntimeException
|
||||||
|
*/
|
||||||
|
public function testImmutableArrayAccess() {
|
||||||
|
$vars = array(
|
||||||
|
'get' => array('name' => 'John Q. Public', 'nickname' => 'Joey'),
|
||||||
|
);
|
||||||
|
|
||||||
|
$request = new OCA\Contacts\Request($vars);
|
||||||
|
$request['nickname'] = 'Janey';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException RuntimeException
|
||||||
|
*/
|
||||||
|
public function testImmutableMagicAccess() {
|
||||||
|
$vars = array(
|
||||||
|
'get' => array('name' => 'John Q. Public', 'nickname' => 'Joey'),
|
||||||
|
);
|
||||||
|
|
||||||
|
$request = new OCA\Contacts\Request($vars);
|
||||||
|
$request->{'nickname'} = 'Janey';
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -27,30 +27,36 @@ session_write_close();
|
|||||||
//OCP\Util::writeLog('contacts', OCP\Util::getRequestUri(), OCP\Util::DEBUG);
|
//OCP\Util::writeLog('contacts', OCP\Util::getRequestUri(), OCP\Util::DEBUG);
|
||||||
|
|
||||||
function getStandardImage() {
|
function getStandardImage() {
|
||||||
|
$image = new \OC_Image();
|
||||||
|
$file = __DIR__ . DIRECTORY_SEPARATOR . 'img' . DIRECTORY_SEPARATOR . 'person.png';
|
||||||
|
OCP\Response::setLastModifiedHeader(filemtime($file));
|
||||||
OCP\Response::enableCaching();
|
OCP\Response::enableCaching();
|
||||||
OCP\Response::redirect(OCP\Util::imagePath('contacts', 'person.png'));
|
$image->loadFromFile($file);
|
||||||
|
$image();
|
||||||
exit();
|
exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!extension_loaded('gd') || !function_exists('gd_info')) {
|
if(!extension_loaded('gd') || !function_exists('gd_info')) {
|
||||||
OCP\Util::writeLog('contacts',
|
OCP\Util::writeLog('contacts',
|
||||||
'thumbnail.php. GD module not installed', OCP\Util::DEBUG);
|
'thumbnail.php. GD module not installed', OCP\Util::DEBUG);
|
||||||
getStandardImage();
|
OCP\Response::enableCaching();
|
||||||
|
OCP\Response::redirect(OCP\Util::imagePath('contacts', 'person.png'));
|
||||||
|
exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
$id = $_GET['id'];
|
$id = $_GET['id'];
|
||||||
|
$parent = $_GET['parent'];
|
||||||
|
$backend = $_GET['backend'];
|
||||||
$caching = null;
|
$caching = null;
|
||||||
|
|
||||||
$image = OCA\Contacts\App::cacheThumbnail($id);
|
$app = new OCA\Contacts\App();
|
||||||
|
$contact = $app->getContact($backend, $parent, $id);
|
||||||
|
$image = $contact->cacheThumbnail();
|
||||||
if($image !== false) {
|
if($image !== false) {
|
||||||
try {
|
$modified = $contact->lastModified();
|
||||||
$modified = OCA\Contacts\App::lastModified($id);
|
|
||||||
} catch(Exception $e) {
|
|
||||||
getStandardImage();
|
|
||||||
}
|
|
||||||
// Force refresh if modified within the last minute.
|
// Force refresh if modified within the last minute.
|
||||||
if(!is_null($modified)) {
|
if(!is_null($modified)) {
|
||||||
$caching = (time() - $modified->format('U') > 60) ? null : 0;
|
$caching = (time() - $modified > 60) ? null : 0;
|
||||||
OCP\Response::setLastModifiedHeader($modified);
|
OCP\Response::setLastModifiedHeader($modified);
|
||||||
}
|
}
|
||||||
OCP\Response::enableCaching($caching);
|
OCP\Response::enableCaching($caching);
|
||||||
|
Loading…
Reference in New Issue
Block a user