diff --git a/admin.php b/admin.php new file mode 100644 index 00000000..249e05e5 --- /dev/null +++ b/admin.php @@ -0,0 +1,17 @@ +fetchPage(); \ No newline at end of file diff --git a/appinfo/app.php b/appinfo/app.php index 775f6ab8..e328c3a0 100644 --- a/appinfo/app.php +++ b/appinfo/app.php @@ -53,18 +53,20 @@ $api->connectHook('OC_Calendar', 'getEvents', 'OCA\Contacts\Hooks', 'getBirthday $api->connectHook('OC_Calendar', 'getSources', 'OCA\Contacts\Hooks', 'getCalenderSources'); \OCP\Util::addscript('contacts', 'loader'); +\OCP\Util::addscript('contacts', 'admin'); \OC_Search::registerProvider('OCA\Contacts\SearchProvider'); //\OCP\Share::registerBackend('contact', 'OCA\Contacts\Share_Backend_Contact'); \OCP\Share::registerBackend('addressbook', 'OCA\Contacts\Share\Addressbook', 'contact'); //\OCP\App::registerPersonal('contacts','personalsettings'); +\OCP\App::registerAdmin('contacts', 'admin'); if (\OCP\User::isLoggedIn()) { $app = new App($api->getUserId()); $addressBooks = $app->getAddressBooksForUser(); foreach ($addressBooks as $addressBook) { if ($addressBook->isActive()) { - \OCP\Contacts::registerAddressBook($addressBook->getSearchProvider()); + \OCP\Contacts::registerAddressBook(new AddressbookProvider($addressBook)); } } } diff --git a/appinfo/remote.php b/appinfo/remote.php index bd477a47..95fc56d7 100644 --- a/appinfo/remote.php +++ b/appinfo/remote.php @@ -40,7 +40,11 @@ $principalBackend = new OC_Connector_Sabre_Principal(); $addressbookbackends = array(); $addressbookbackends[] = new OCA\Contacts\Backend\Database(\OCP\User::getUser()); -$carddavBackend = new OCA\Contacts\CardDAV\Backend(array('local', 'shared', 'ldap')); +$backends = array('local', 'shared'); +if (\OCP\Config::getAppValue('contacts', 'backend_ldap', "false") === "true") { + $backends[] = 'ldap' +} +$carddavBackend = new OCA\Contacts\CardDAV\Backend($backends); $requestBackend = new OC_Connector_Sabre_Request(); // Root nodes diff --git a/appinfo/routes.php b/appinfo/routes.php index 7fc441b2..a6ceca7c 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -34,6 +34,39 @@ $this->create('contacts_address_books_for_user', 'addressbooks/') } ); +$this->create('contacts_address_book_connectors', 'connectors/{backend}') + ->get() + ->action( + function($params) { + \OC::$session->close(); + $dispatcher = new Dispatcher($params); + $dispatcher->dispatch('BackendController', 'getConnectors'); + } + ) + ->requirements(array('backend')); + +$this->create('contacts_backend_enable', 'backend/{backend}/{enable}') + ->get() + ->action( + function($params) { + \OC::$session->close(); + $dispatcher = new Dispatcher($params); + $dispatcher->dispatch('BackendController', 'enableBackend'); + } + ) + ->requirements(array('backend', 'enable')); + +$this->create('contacts_backend_status', 'backend/{backend}') + ->get() + ->action( + function($params) { + \OC::$session->close(); + $dispatcher = new Dispatcher($params); + $dispatcher->dispatch('BackendController', 'backendStatus'); + } + ) + ->requirements(array('backend')); + $this->create('contacts_address_book_add', 'addressbook/{backend}/add') ->post() ->action( @@ -428,4 +461,3 @@ $this->create('contacts_index_properties', 'indexproperties/{user}/') ) ->requirements(array('user')) ->defaults(array('user' => \OCP\User::getUser())); - diff --git a/backendcontroller.php b/backendcontroller.php new file mode 100644 index 00000000..ec7df4cd --- /dev/null +++ b/backendcontroller.php @@ -0,0 +1,73 @@ + $formatId, 'name' => (string)$format['name'], 'xml' => $format->asXML()); + } + } + } + } + } + return $response->setData($formats); + } + + /** + * @NoAdminRequired + * @NoCSRFRequired + */ + public function enableBackend() { + $response = new JSONResponse(); + $params = $this->request->urlParams; + $backend = $params['backend']; + $enable = $params['enable']; + return $response->setData(\OCP\Config::setAppValue('contacts', 'backend_'.$backend, $enable)); + } + /** + * @NoAdminRequired + * @NoCSRFRequired + */ + public function backendStatus() { + $response = new JSONResponse(); + $params = $this->request->urlParams; + $backend = $params['backend']; + $enabled = \OCP\Config::getAppValue('contacts', 'backend_'.$backend, "false"); + return $response->setData($enabled); + } +} + diff --git a/js/admin.js b/js/admin.js new file mode 100644 index 00000000..7b6f4369 --- /dev/null +++ b/js/admin.js @@ -0,0 +1,138 @@ +console.log($('#contacts-ldap-enabled')); + +$(document).ready(function() { + + $.when( + backendStatus( + 'ldap' + )) + .then(function(response) { + if(!response.error) { + console.log('response', response.data); + if (response.data === "true") { + $('#contacts-ldap-enabled').prop('checked', true); + } + } else { + console.warn('Error', response.message); + } + }).fail(function(response) { + console.log(response.message); + }); + + $('#contacts-ldap-enabled').change(function() { + var enabled=$(this).prop('checked')?"true":"false"; + $.when( + enableBackend( + 'ldap', + enabled + )) + .then(function(response) { + if(!response.error) { + console.log('response', response.data); + } else { + console.warn('Error', response.message); + } + }).fail(function(response) { + console.log(response.message); + }); + }); +}); + + +function requestRoute(route, type, routeParams, params, additionalHeaders) { + var isJSON = (typeof params === 'string'); + var contentType = isJSON + ? (type === 'PATCH' ? 'application/json-merge-patch' : 'application/json') + : 'application/x-www-form-urlencoded'; + var processData = !isJSON; + contentType += '; charset=UTF-8'; + var url = OC.generateUrl('apps/contacts/' + route, routeParams); + var headers = { + Accept : 'application/json; charset=utf-8' + }; + if(typeof additionalHeaders === 'object') { + headers = $.extend(headers, additionalHeaders); + } + var ajaxParams = { + type: type, + url: url, + dataType: 'json', + headers: headers, + contentType: contentType, + processData: processData, + data: params + }; + + var defer = $.Deferred(); + + $.ajax(ajaxParams) + .done(function(response, textStatus, jqXHR) { + console.log(jqXHR); + defer.resolve(new JSONResponse(jqXHR)); + }) + .fail(function(jqXHR/*, textStatus, error*/) { + console.log(jqXHR); + var response = jqXHR.responseText ? $.parseJSON(jqXHR.responseText) : null; + console.log('response', response); + defer.reject(new JSONResponse(jqXHR)); + }); + + return defer.promise(); +} + +function enableBackend(backend, enable, params) { + return this.requestRoute( + 'backend/{backend}/{enable}', + 'GET', + {backend: backend, enable: enable}, + JSON.stringify(params) + ); +} + +function backendStatus(backend, params) { + return this.requestRoute( + 'backend/{backend}', + 'GET', + {backend: backend}, + JSON.stringify(params) + ); +} + + +var JSONResponse = function(jqXHR) { + this.getAllResponseHeaders = jqXHR.getAllResponseHeaders; + this.getResponseHeader = jqXHR.getResponseHeader; + this.statusCode = jqXHR.status; + var response = jqXHR.responseJSON; + this.error = false; + console.log('jqXHR', jqXHR); + if (!response) { + // 204 == No content + // 304 == Not modified + if ([204, 304].indexOf(this.statusCode) === -1) { + this.error = true; + } + this.message = jqXHR.statusText; + } else { + // We need to allow for both the 'old' success/error status property + // with the body in the data property, and the newer where we rely + // on the status code, and the entire body is used. + if (response.status === 'error'|| this.statusCode >= 400) { + this.error = true; + if (!response.data || !response.data.message) { + this.message = t('contacts', 'Server error! Please inform system administator'); + } else { + console.log('JSONResponse', response); + this.message = (response.data && response.data.message) + ? response.data.message + : response; + } + } else { + this.data = response.data || response; + // Kind of a hack + if (response.metadata) { + this.metadata = response.metadata; + } + } + } +}; diff --git a/lib/app.php b/lib/app.php index 4620f222..0ff80bb4 100644 --- a/lib/app.php +++ b/lib/app.php @@ -13,6 +13,7 @@ namespace OCA\Contacts; use Sabre\VObject, OCP\AppFramework, OCA\Contacts\Controller\AddressBookController, + OCA\Contacts\Controller\BackendController, OCA\Contacts\Controller\GroupController, OCA\Contacts\Controller\ContactController, OCA\Contacts\Controller\ContactPhotoController, @@ -53,7 +54,6 @@ class App { * @var array */ public static $backendClasses = array( - 'ldap' => 'OCA\Contacts\Backend\Ldap', 'local' => 'OCA\Contacts\Backend\Database', 'shared' => 'OCA\Contacts\Backend\Shared', 'localusers' => 'OCA\Contacts\Backend\LocalUsers', @@ -71,6 +71,9 @@ class App { $this->dbBackend = $dbBackend ? $dbBackend : new Backend\Database($user); + if (\OCP\Config::getAppValue('contacts', 'backend_ldap', "false") === "true") { + self::$backendClasses['ldap'] = 'OCA\Contacts\Backend\Ldap'; + } } /** diff --git a/lib/backend/ldap.php b/lib/backend/ldap.php index 4a5ad4c6..b0318093 100644 --- a/lib/backend/ldap.php +++ b/lib/backend/ldap.php @@ -38,10 +38,15 @@ class Ldap extends AbstractBackend { * @var string */ public $name='ldap'; - static private $preparedQueries = array(); private $ldapConnection = null; private $connector = null; + /** + * The cached address books. + * @var array[] + */ + public $addressbooks; + /** * @brief validates and sets the ldap parameters * @param $ldapParams array containing the parameters @@ -50,7 +55,7 @@ class Ldap extends AbstractBackend { public function setLdapParams($aid) { $tmp = $this->getPreferences($aid); if ($tmp != false) { - $this->ldapParams = $tmp; + $this->ldapParams = (array)$tmp; $this->connector = new LdapConnector($this->ldapParams['ldap_vcard_connector']); return true; } else { @@ -213,12 +218,7 @@ class Ldap extends AbstractBackend { */ public function ldapUpdate($ldapDN, $ldapValues) { if (self::ldapIsConnected()) { - $result = @ldap_modify($this->ldapConnection, $ldapDN, $ldapValues); - if (!$result) { - self::ldapDelete($ldapDN); - return self::ldapAdd($ldapDN, $ldapValues); - } - return true; + return @ldap_modify($this->ldapConnection, $ldapDN, $ldapValues); } return false; } @@ -257,12 +257,10 @@ class Ldap extends AbstractBackend { */ public function getAddressBooksForUser(array $options = array()) { $addressbookidList = $this->getAddressbookList(); - $this->addressbooks = array(); foreach($addressbookidList as $addressbookid) { $this->addressbooks[] = self::getAddressBook($addressbookid); } return $this->addressbooks; - } /** @@ -286,16 +284,19 @@ class Ldap extends AbstractBackend { } // Hmm, not found. Lets query the db. $preferences = self::getPreferences($addressbookid); - if ($preferences != false) { - $current = array(); - $current['id'] = (string)$addressbookid; - $current['displayname'] = (string)$preferences['displayname']; - $current['description'] = (string)$preferences['description']; - $current['owner'] = $this->userid; - $current['uri'] = (string)$preferences['uri']; - $current['permissions'] = \OCP\PERMISSION_ALL; - $current['lastmodified'] = self::lastModifiedAddressBook($addressbookid); - return $current; + if (count($preferences) > 0) { + $preferences['id'] = (string)$addressbookid; + $preferences['backend'] = $this->name; + $preferences['owner'] = $this->userid; + $preferences['permissions'] = \OCP\PERMISSION_ALL; + $preferences['lastmodified'] = self::lastModifiedAddressBook($addressbookid); + + // remove the ldappassword from the return value if exists + if (isset($preferences['ldappass']) && (isset($options['getpwd']) && !$options['getpwd'])) { + unset($preferences['ldappass']); + } + + return $preferences; } else { return array(); } @@ -322,14 +323,22 @@ class Ldap extends AbstractBackend { * * @param string $addressbookid * @param array $properties - * @return bool + * @return string|false The ID if the modified AddressBook or false on error. */ public function updateAddressBook($addressbookid, array $properties, array $options = array()) { - // TODO: use backend settings - - return true; + if ($this->hasAddressBook($addressbookid)) { + // Addressbook exists, modify it through the create function + if (isset($properties['ldappassmodified']) && $properties['ldappassmodified'] != 'true') { + // If password hasn't changed, get it from the preferences + $addrbook = $this->getAddressBook($addressbookid, array('getpwd' => true)); + $properties['ldappass'] = base64_decode($addrbook['ldappass']); + } + return $this->setAddressBook($properties, $options); + } else { + return false; + } } - + /** * Creates a new address book * @@ -341,7 +350,80 @@ class Ldap extends AbstractBackend { * @return string|false The ID if the newly created AddressBook or false on error. */ public function createAddressBook(array $properties, array $options = array()) { - // TODO: use backend settings + if (!isset($properties['uri']) || $this->hasAddressBook($properties['uri'])) { + return false; + } else { + return $this->setAddressBook($properties, $options); + } + } + + /* + * Sets the parameters for a new or existing addressbook + * + * @param array $properties + * @return string|false The ID if the newly created AddressBook or false on error. + */ + public function setAddressBook(array $properties, array $options = array()) { + if (count($properties) === 0) { + return false; + } + if (isset($properties['displayname']) && $properties['displayname'] != '' && + isset($properties['uri']) && $properties['uri'] != '' && + isset($properties['ldapurl']) && $properties['ldapurl'] != '' && + isset($properties['ldappagesize']) && $properties['ldappagesize'] != '' && + isset($properties['ldapbasednsearch']) && $properties['ldapbasednsearch'] != '' && + isset($properties['ldapfilter']) && $properties['ldapfilter'] != '' && + isset($properties['ldapvcardconnector']) && + isset($properties['ldapanonymous']) && + ($properties['ldapanonymous']=='true' + || ($properties['ldapanonymous']=='false' + && isset($properties['ldapuser']) && $properties['ldapuser'] != '' + && isset($properties['ldappass']) && $properties['ldappass'] != '' + ) + ) && + isset($properties['ldapreadonly']) && + ($properties['ldapreadonly']=='true' + || ($properties['ldapreadonly']=='false' + && isset($properties['ldapbasednmodify']) && $properties['ldapbasednmodify'] != '' + ) + ) + ) { + $addressbookSettings = array(); + $addressbookSettings['uri'] = $properties['uri']; + $addressbookSettings['displayname'] = $properties['displayname']; + $addressbookSettings['description'] = $properties['description']; + $addressbookSettings['ldapurl'] = $properties['ldapurl']; + $addressbookSettings['ldapanonymous'] = ($properties['ldapanonymous']=='true'); + $addressbookSettings['ldapreadonly'] = ($properties['ldapreadonly']=='true'); + $addressbookSettings['ldapuser'] = ($properties['ldapanonymous']=='false')?$properties['ldapuser']:""; + $addressbookSettings['ldappass'] = ($properties['ldapanonymous']=='false')?base64_encode($properties['ldappass']):""; + $addressbookSettings['ldappagesize'] = $properties['ldappagesize']; + $addressbookSettings['ldapbasednsearch'] = $properties['ldapbasednsearch']; + $addressbookSettings['ldapfilter'] = $properties['ldapfilter']; + $addressbookSettings['ldapbasednmodify'] = ($properties['ldapanonymous']=='false')?$properties['ldapbasednmodify']:""; + $addressbookSettings['ldapconnectorid'] = $properties['ldapvcardconnector']; + + if ($properties['ldapvcardconnector'] != '') { + $prefix = "backend_ldap_"; + $suffix = "_connector.xml"; + $path = __DIR__ . "/../../formats/"; + if (file_exists( $path.$prefix.$properties['ldapvcardconnector'].$suffix )) { + $addressbookSettings['ldap_vcard_connector'] = file_get_contents ( $path.$prefix.$properties['ldapvcardconnector'].$suffix ); + } + } else { + $addressbookSettings['ldap_vcard_connector'] = $properties['ldapvcardconnectorvalue']; + } + + $addressbookList = $this->getAddressbookList(); + if (!in_array($properties['uri'], $addressbookList)) { + $addressbookList[] = $properties['uri']; + $this->setAddressbookList($addressbookList); + } + $this->setPreferences($properties['uri'], $addressbookSettings); + $this->setActive(1, $properties['uri']); + return $properties['uri']; + } + return false; } /** @@ -351,27 +433,21 @@ class Ldap extends AbstractBackend { * @return bool */ public function deleteAddressBook($addressbookid, array $options = array()) { - $addressbook = self::getAddressBook($addressbookid); + //$addressbook = self::getAddressBook($addressbookid); + $addressbookList = $this->getAddressbookList(); + $toRemove = array_search($addressbookid, $addressbookList); + if (is_int($toRemove)) { + unset($addressbookList[$toRemove]); + $addressbookList = array_values($addressbookList); + $this->setAddressbookList($addressbookList); + } + + self::removePreferences($addressbookid); // TODO: use backend settings return true; } - /** - * @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, array $options = array()) { - return null; - } - /** * Returns all contacts for a specific addressbook id. * @@ -399,6 +475,16 @@ class Ldap extends AbstractBackend { * @return array */ public function getContacts($addressbookid, array $options = array()) { + $backtrace = debug_backtrace(); + $trace=array(); + foreach ($backtrace as $elt) { + foreach ($elt as $key => $line) { + if ($key == "file" || $key == "line") { + $trace[] = $line; + } + } + } + $cards = array(); $vcards = array(); if(is_array($addressbookid) && count($addressbookid)) { @@ -448,7 +534,6 @@ class Ldap extends AbstractBackend { $cards = array(); $toReturn = false; - self::setLdapParams($addressbookid); if (self::setLdapParams($addressbookid)) { foreach ($a_ids as $id) { $cid = str_replace(".vcf", "", $id); @@ -465,7 +550,7 @@ class Ldap extends AbstractBackend { $this->connector->getLdapEntries()); } else { $card = self::ldapFindOne(base64_decode($cid), - 'objectClass=*', + $this->ldapParams['ldapfilter'], $this->connector->getLdapEntries()); } } @@ -501,7 +586,7 @@ class Ldap extends AbstractBackend { $URI = (string)$vcard->{'X-LDAP-DN'}; } return array('id' => $UID, - 'permissions' => \OCP\PERMISSION_READ, + 'permissions' => \OCP\PERMISSION_ALL, 'displayname' => $FN, 'carddata' => $vcard->serialize(), 'uri' => $URI, @@ -516,25 +601,16 @@ class Ldap extends AbstractBackend { * @return string|bool The identifier for the new contact or false on error. */ public function createContact($addressbookid, $contact, array $options = array()) { - $backtrace = debug_backtrace(); - $trace=array(); - foreach ($backtrace as $elt) { - foreach ($elt as $key => $line) { - if ($key == "file" || $key == "line") { - $trace[] = $line; - } - } - } - //error_log("stay added ".print_r($trace,1)); $uri = isset($options['uri']) ? $options['uri'] : null; + $contact->REV = (new \DateTime)->format(\DateTime::W3C); + // 2014/02/13 Sometimes, a card is created without a name (I don't like that)... if (!isset($contact->N)) { - $generated = "gruik".rand(0, 65535); + $generated = "nocn-".rand(0, 65535); $contact->N = $generated; $contact->FN = $generated; - error_log("Generated name: $generated"); } if(!$contact instanceof VCard) { @@ -545,7 +621,6 @@ class Ldap extends AbstractBackend { return false; } } - error_log("adding ".$contact->serialize()); try { $contact->validate(VCard::REPAIR|VCard::UPGRADE); @@ -588,16 +663,6 @@ class Ldap extends AbstractBackend { * @return bool */ public function updateContact($addressbookid, $id, $carddata, array $options = array()) { - $backtrace = debug_backtrace(); - $trace=array(); - foreach ($backtrace as $elt) { - foreach ($elt as $key => $line) { - if ($key == "file" || $key == "line") { - $trace[] = $line; - } - } - } - //error_log("stay modified ".print_r($trace,1)); if(!$carddata instanceof VCard) { try { $vcard = \Sabre\VObject\Reader::read($carddata); @@ -609,7 +674,14 @@ class Ldap extends AbstractBackend { $vcard = $carddata; } - //error_log("updating ".$vcard->serialize()); + try { + $vcard->validate(VCard::REPAIR|VCard::UPGRADE); + } catch (\Exception $e) { + OCP\Util::writeLog('contacts', __METHOD__ . ' ' . + 'Error validating vcard: ' . $e->getMessage(), \OCP\Util::ERROR); + return false; + } + //$vcard->REV = (new \DateTime)->format(\DateTime::W3C); if (!is_array($id)) { $a_ids = array($id); @@ -631,6 +703,8 @@ class Ldap extends AbstractBackend { $dn = base64_decode($tmpVCard->{'X-LDAP-DN'}); } // Updates the existing card + $ldifSource = self::ldapFindOne($dn, $this->ldapParams['ldapfilter'], $this->connector->getLdapEntries()); + $this->connector->insertEmptyEntries($ldifSource, $ldifEntries); $result = self::ldapUpdate($dn, $ldifEntries); } self::ldapCloseConnection(); @@ -645,19 +719,8 @@ class Ldap extends AbstractBackend { * @return bool */ public function deleteContact($addressbookid, $id, array $options = array()) { - $backtrace = debug_backtrace(); - $trace=array(); - foreach ($backtrace as $elt) { - foreach ($elt as $key => $line) { - if ($key == "file" || $key == "line") { - $trace[] = $line; - } - } - } - //error_log("stay dead ".print_r($trace, 1)); self::setLdapParams($addressbookid); self::ldapCreateAndBindConnection(); - $card=null; if (is_array($id)) { $card = self::getContact($addressbookid, $id); } else { @@ -694,20 +757,33 @@ class Ldap extends AbstractBackend { } } - // Please remove this - public function debug_string_backtrace() { - ob_start(); - debug_print_backtrace(); - $trace = ob_get_contents(); - ob_end_clean(); + /** + * @brief sets the list of ldap addressbooks in the preferences + * with the list given in parameter + * @param the new list + * @returns result|false + */ + protected function setAddressbookList(array $addressbookList) { + $key = $this->name . "_list"; + $data = json_encode($addressbookList); + + return $data + ? \OCP\Config::setUserValue($this->userid, 'contacts', $key, $data) + : false; + } + + /** + * @brief gets the list of ldap addressbooks in the preferences + * returns array() + */ + protected function getAddressbookList() { + $key = $this->name . "_list"; + $data = \OCP\Config::getUserValue($this->userid, 'contacts', $key, false); + + return $data ? json_decode($data) : array(); + } - // Remove first item from backtrace as it's this function which - // is redundant. - $trace = preg_replace ('/^#0\s+' . __FUNCTION__ . "[^\n]*\n/", '', $trace, 1); - - // Renumber backtrace items. - $trace = preg_replace ('/^#(\d+)/me', '\'#\' . ($1 - 1)', $trace); - - return $trace; - } + public function getSearchProvider($addressbook) { + return new \OCA\Contacts\AddressbookProvider($addressbook); + } } diff --git a/lib/connector/ldapconnector.php b/lib/connector/ldapconnector.php index 890dcdc9..1b1cbf47 100644 --- a/lib/connector/ldapconnector.php +++ b/lib/connector/ldapconnector.php @@ -33,7 +33,14 @@ class LdapConnector { \OCP\Util::writeLog('ldap_vcard_connector', __METHOD__.', error in setting xml config', \OCP\Util::DEBUG); } } - + private function convertDate ($ldapDate) { + + $tstamp = strtotime($ldapDate); + $theDate = new \DateTime; + $theDate->setTimestamp($tstamp); + + return $theDate; + } /** * @brief transform a ldap entry into an VCard object * for each ldap entry which is like "property: value" @@ -43,26 +50,27 @@ class LdapConnector { */ public function ldapToVCard($ldapEntry) { $vcard = \Sabre\VObject\Component::create('VCARD'); - $vcard->REV = $ldapEntry['modifytimestamp'][0]; + $vcard->REV = $this->convertDate($ldapEntry['modifytimestamp'][0])->format(\DateTime::W3C); + //error_log("modifytimestamp: ".$vcard->REV); $vcard->{'X-LDAP-DN'} = base64_encode($ldapEntry['dn']); // OCP\Util::writeLog('ldap_vcard_connector', __METHOD__.' vcard is '.$vcard->serialize(), \OCP\Util::DEBUG); for ($i=0; $i<$ldapEntry["count"]; $i++) { // ldap property name : $ldap_entry[$i] - $l_property = $ldapEntry[$i]; - for ($j=0;$j<$ldapEntry[$l_property]["count"];$j++){ + $lProperty = $ldapEntry[$i]; + for ($j=0;$j<$ldapEntry[$lProperty]["count"];$j++){ // What to do : // convert the ldap property into vcard property, type and position (if needed) // $v_params format: array('property' => property, 'type' => array(types), 'position' => position) - $v_params = $this->getVCardProperty($l_property); + $v_params = $this->getVCardProperty($lProperty); foreach ($v_params as $v_param) { if (isset($v_param['unassigned'])) { // if the value comes from the unassigned entry, it's a vcard property dumped try { - $property = \Sabre\VObject\Reader::read($ldapEntry[$l_property][$j]); + $property = \Sabre\VObject\Reader::read($ldapEntry[$lProperty][$j]); $vcard->add($property); } catch (exception $e) { } @@ -74,9 +82,9 @@ class LdapConnector { // modify the property with the new data if (strcasecmp($v_param['image'], 'true') == 0) { - $this->updateVCardImageProperty($v_property, $ldapEntry[$l_property][$j], $vcard->VERSION); + $this->updateVCardImageProperty($v_property, $ldapEntry[$lProperty][$j], $vcard->VERSION); } else { - $this->updateVCardProperty($v_property, $ldapEntry[$l_property][$j], $v_param['position']); + $this->updateVCardProperty($v_property, $ldapEntry[$lProperty][$j], $v_param['position']); } } } @@ -86,7 +94,6 @@ class LdapConnector { if (!isset($vcard->UID)) { $vcard->UID = base64_encode($ldapEntry['dn']); } - $vcard->validate(\Sabre\VObject\Component\VCard::REPAIR); return $vcard; } @@ -179,16 +186,16 @@ class LdapConnector { /** * @brief gets the vcard property values from an ldif entry name - * @param $l_property the ldif property name + * @param $lProperty the ldif property name * @return array('property' => property, 'type' => type, 'position' => position) */ - public function getVCardProperty($l_property) { + public function getVCardProperty($lProperty) { $properties = array(); - if (strcmp($l_property, $this->getUnassignedVCardProperty()) == 0) { + if (strcmp($lProperty, $this->getUnassignedVCardProperty()) == 0) { $properties[] = array('unassigned' => true); } else { foreach ($this->config_content->ldap_entries->ldif_entry as $ldif_entry) { - if ($l_property == $ldif_entry['name']) { + if ($lProperty == $ldif_entry['name']) { // $ldif_entry['name'] is the right config xml foreach ($ldif_entry->vcard_entry as $vcard_entry) { $type=isset($vcard_entry['type'])?$vcard_entry['type']:""; @@ -421,6 +428,22 @@ class LdapConnector { return false; } } + + /** + * @brief adds empty entries in $dest if $dest doesn't have those entries and if $source has + * otherwise, I couldn't find how to remove attributes + * @param $source the source ldap entry as model + * @param $dest the destination entry to add empty params if we have to + */ + public function insertEmptyEntries($source, &$dest) { + for ($i=0; $i<$source["count"]; $i++) { + + $lProperty = $source[$i]; + if (!isset($dest[$lProperty]) && $lProperty != 'modifytimestamp') { + $dest[$lProperty] = array(); + } + } + } } ?> diff --git a/lib/controller/backendcontroller.php b/lib/controller/backendcontroller.php new file mode 100644 index 00000000..ec7df4cd --- /dev/null +++ b/lib/controller/backendcontroller.php @@ -0,0 +1,73 @@ + $formatId, 'name' => (string)$format['name'], 'xml' => $format->asXML()); + } + } + } + } + } + return $response->setData($formats); + } + + /** + * @NoAdminRequired + * @NoCSRFRequired + */ + public function enableBackend() { + $response = new JSONResponse(); + $params = $this->request->urlParams; + $backend = $params['backend']; + $enable = $params['enable']; + return $response->setData(\OCP\Config::setAppValue('contacts', 'backend_'.$backend, $enable)); + } + /** + * @NoAdminRequired + * @NoCSRFRequired + */ + public function backendStatus() { + $response = new JSONResponse(); + $params = $this->request->urlParams; + $backend = $params['backend']; + $enabled = \OCP\Config::getAppValue('contacts', 'backend_'.$backend, "false"); + return $response->setData($enabled); + } +} + diff --git a/lib/dispatcher.php b/lib/dispatcher.php index 1a9c6d09..f0c1f7d5 100644 --- a/lib/dispatcher.php +++ b/lib/dispatcher.php @@ -21,7 +21,8 @@ use OCP\AppFramework\App as MainApp, OCA\Contacts\Controller\ContactPhotoController, OCA\Contacts\Controller\SettingsController, OCA\Contacts\Controller\ImportController, - OCA\Contacts\Controller\ExportController; + OCA\Contacts\Controller\ExportController, + OCA\Contacts\Controller\BackendController; /** * This class manages our app actions @@ -105,6 +106,10 @@ class Dispatcher extends MainApp { $request = $container->query('Request'); return new ExportController($appName, $request, $app); }); + $this->container->registerService('BackendController', function(IAppContainer $container) use($appName, $app) { + $request = $container->query('Request'); + return new BackendController($appName, $request, $app); + }); } } diff --git a/templates/admin.php b/templates/admin.php new file mode 100644 index 00000000..a6ea1233 --- /dev/null +++ b/templates/admin.php @@ -0,0 +1,21 @@ + + +
+

Contacts

+ +
+ t('Enable LDAP backend for the contacts application')) ?> +
t('Warning: LDAP Backend is in beta mode, use with precautions')) ?> +
diff --git a/templates/contacts.php b/templates/contacts.php index 8afd8b01..646cc66b 100644 --- a/templates/contacts.php +++ b/templates/contacts.php @@ -1,3 +1,6 @@ +

t('Import')); ?>

@@ -31,7 +43,8 @@