1
0
mirror of https://github.com/owncloudarchive/contacts.git synced 2025-01-19 08:52:22 +01:00

Merge pull request #460 from owncloud/ldap

Ldap Backend read/write
This commit is contained in:
Nicolas Mora 2014-05-10 11:29:05 -04:00
commit 0882b982b3
25 changed files with 1414 additions and 224 deletions

17
admin.php Normal file
View File

@ -0,0 +1,17 @@
<?php
/**
* ownCloud - Contact Admin settings
*
* @author Nicolas Mora
* @copyright 2014 Nicolas Mora mail@babelouest.org
*
* This file is licensed under the Affero General Public License version 3 or
* later.
*/
namespace OCA\Contacts;
\OCP\User::checkAdminUser();
$tmpl = new \OCP\Template('contacts', 'admin');
return $tmpl->fetchPage();

View File

@ -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));
}
}
}

View File

@ -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'));
$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

View File

@ -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()));

View File

@ -824,6 +824,27 @@ tbody tr.contact.active, tbody tr.contact:hover {
transition: all 0.5s ease-in-out;
}
#addressbooks-ui-div > p > select {
width:200px;
display: inline-block;
}
#addressbooks-ui-div > p > input:not([type="checkbox"]) {
width:200px;
display: inline-block;
}
#addressbooks-ui-div > p > textarea {
width:200px;
display: inline-block;
}
#addressbooks-ui-div > p > label {
vertical-align:top;
width:200px;
display: inline-block;
}
@media screen and (min-width: 1400px) {
#contact > ul.propertylist {
-moz-column-count: 3;

View File

@ -0,0 +1,157 @@
<?xml version='1.0' standalone='yes'?>
<entries name="inetOrgPerson">
<vcard_entries>
<vcard_entry property="FN" enabled="true">
<!--<ldif_entry name="cn"/>-->
<ldif_entry name="displayname" unique="true"/>
</vcard_entry>
<vcard_entry property="EMAIL" enabled="true">
<ldif_entry name="mail" unique="true"/>
</vcard_entry>
<vcard_entry property="NOTE" enabled="true">
<ldif_entry name="description" unique="true"/>
</vcard_entry>
<vcard_entry property="N" enabled="true">
<ldif_entry vcard_position="0" name="sn" unique="true"/>
<ldif_entry vcard_position="1" name="givenname"/>
</vcard_entry>
<vcard_entry property="TEL" type="FAX" enabled="true">
<ldif_entry name="facsimiletelephonenumber" unique="true"/>
</vcard_entry>
<vcard_entry property="TEL" type="HOME" enabled="true">
<ldif_entry name="telephonenumber" unique="true"/>
</vcard_entry>
<vcard_entry property="TEL" type="CELL" enabled="true">
<ldif_entry name="mobile" unique="true"/>
</vcard_entry>
<vcard_entry property="PHOTO" image="true" enabled="true">
<ldif_entry name="jpegphoto"/>
</vcard_entry>
<vcard_entry property="ADR" type="HOME" enabled="true">
<ldif_entry vcard_position="2" name="street"/>
<ldif_entry vcard_position="3" name="l"/>
<ldif_entry vcard_position="4" name="st"/>
<ldif_entry vcard_position="5" name="postalcode"/>
<ldif_entry vcard_position="6" name="vcardcountry" unique="true"/>
</vcard_entry>
<vcard_entry property="CATEGORIES" enabled="true">
<ldif_entry name="o" unique="true"/>
</vcard_entry>
<!--<vcard_entry property="" type="" enabled="true">
<ldap_entry vcard_position="" unique="" name=""/>
</vcard_entry>-->
</vcard_entries>
<ldap_entries>
<ldap_core>
<object_class name="top" />
<object_class name="inetOrgPerson" />
<unassigned_vcard_property ldap_name="businessCategory" />
<ldap_id name="cn" />
<not_null name="sn">
<action_switch name="givenname"/>
<!--<action_default value="value"/>-->
</not_null>
</ldap_core>
<ldif_entry name="mail" enabled="true">
<vcard_entry property="EMAIL" type="HOME">
</vcard_entry>
</ldif_entry>
<ldif_entry name="description" enabled="true">
<vcard_entry property="NOTE">
</vcard_entry>
</ldif_entry>
<ldif_entry name="displayname" enabled="true">
<vcard_entry property="FN">
</vcard_entry>
</ldif_entry>
<ldif_entry name="sn" enabled="true">
<vcard_entry property="N" position="0">
</vcard_entry>
</ldif_entry>
<ldif_entry name="givenname" enabled="true">
<vcard_entry property="N" position="1">
</vcard_entry>
</ldif_entry>
<ldif_entry name="facsimiletelephonenumber" enabled="true">
<vcard_entry property="TEL" type="FAX">
</vcard_entry>
</ldif_entry>
<ldif_entry name="telephonenumber" enabled="true">
<vcard_entry property="TEL" type="HOME">
</vcard_entry>
</ldif_entry>
<ldif_entry name="mobile" enabled="true">
<vcard_entry property="TEL" type="CELL">
</vcard_entry>
</ldif_entry>
<ldif_entry name="jpegphoto" enabled="true" image="true">
<vcard_entry property="PHOTO">
</vcard_entry>
</ldif_entry>
<ldif_entry name="street" enabled="true">
<vcard_entry property="ADR" type="HOME" position="2">
</vcard_entry>
</ldif_entry>
<ldif_entry name="l" enabled="true">
<vcard_entry property="ADR" type="HOME" position="3">
</vcard_entry>
</ldif_entry>
<ldif_entry name="st" enabled="true">
<vcard_entry property="ADR" type="HOME" position="4">
</vcard_entry>
</ldif_entry>
<ldif_entry name="postalcode" enabled="true">
<vcard_entry property="ADR" type="HOME" position="5">
</vcard_entry>
</ldif_entry>
<ldif_entry name="c" enabled="true">
<vcard_entry property="ADR" type="HOME" position="6">
</vcard_entry>
</ldif_entry>
<ldif_entry name="o" enabled="true">
<vcard_entry property="CATEGORIES">
</vcard_entry>
</ldif_entry>
<ldif_entry name="ou" enabled="true">
<vcard_entry property="CATEGORIES">
</vcard_entry>
</ldif_entry>
<!--<ldif_entry name="" enabled="true">
<vcard_entry property="" type="" prefix="" position="">
</vcard_entry>
</ldif_entry>-->
</ldap_entries>
</entries>

View File

@ -1,5 +1,5 @@
<?xml version='1.0' standalone='yes'?>
<entries name="inetOrgPersonModify">
<entries name="VCardUnassigned">
<vcard_entries>
@ -139,11 +139,6 @@
</vcard_entry>
</ldif_entry>
<ldif_entry name="c" enabled="true">
<vcard_entry property="ADR" type="HOME" position="6">
</vcard_entry>
</ldif_entry>
<ldif_entry name="o" enabled="true">
<vcard_entry property="CATEGORIES">
</vcard_entry>

19
formats/vcardunassigned.schema Executable file
View File

@ -0,0 +1,19 @@
attributetype ( 1.3.6.1.4.1.4203.666.1.41
NAME 'vcardcountry'
DESC 'RFC2256: ISO-3166 country 2-letter code multiple values allowed'
SUP name
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{2} )
attributetype ( 1.3.6.1.4.1.4203.666.1.42
NAME 'unassignedproperty'
EQUALITY caseIgnoreMatch
SUBSTR caseIgnoreSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1024} )
objectClass ( 1.3.6.1.4.1.4203.666.1.100
NAME 'VCardUnassigned'
DESC 'VCard unassigned properties'
SUP inetOrgPerson
STRUCTURAL
MAY ( unassignedproperty $ vcardcountry )
)

View File

@ -13,6 +13,8 @@ OC.Contacts = OC.Contacts || {};
AddressBook.prototype.render = function() {
var self = this;
//var dialog = OC.Contacts.Dialog(null, null);
this.$li = this.$template.octemplate({
id: this.book.id,
displayname: this.book.displayname,
@ -72,41 +74,127 @@ OC.Contacts = OC.Contacts || {};
});
});
});
this.$li.find('a.action.edit').on('click keypress', function(event) {
if($(this).data('open')) {
return;
}
var editor = this;
event.stopPropagation();
event.preventDefault();
var $dropdown = $('<li><div><input type="text" value="{name}" /></div></li>')
.octemplate({name:self.getDisplayName()}).insertAfter(self.$li);
var $input = $dropdown.find('input');
//$input.focus().get(0).select();
$input.addnew({
autoOpen: true,
//autoClose: false,
addText: t('contacts', 'Save'),
ok: function(event, name) {
console.log('edit-address-book ok', name);
$input.addClass('loading');
self.update({displayname:name}, function(response) {
console.log('response', response);
if(response.error) {
$(document).trigger('status.contacts.error', response);
} else {
self.setDisplayName(response.data.displayname);
$input.addnew('close');
$('#add-ldap-address-book-element').on('click keypress', function() {
var $rightContent = $('#app-content');
$rightContent.append('<div id="addressbook-ui-dialog"></div>');
var $dlg = $('#addressBookConfigTemplate').octemplate({backend: 'ldap'});
var $divDlg = $('#addressbook-ui-dialog');
$divDlg.html($dlg).ocdialog({
modal: true,
closeOnEscape: true,
title: t('contacts', 'Add new LDAP Addressbook'),
height: 'auto',
width: 'auto',
buttons: [
{
text: t('contacts', 'Ok'),
click: function() {
OC.Contacts.otherBackendConfig.addressbookUiOk($divDlg);
},
defaultButton: true
},
{
text: t('contacts', 'Cancel'),
click: function() {
OC.Contacts.otherBackendConfig.addressbookUiClose($divDlg);
}
$input.removeClass('loading');
});
}
],
close: function(/*event, ui*/) {
OC.Contacts.otherBackendConfig.addressbookUiClose($divDlg);
},
close: function() {
$dropdown.remove();
$(editor).data('open', false);
open: function(/*event, ui*/) {
OC.Contacts.otherBackendConfig.openAddressbookUi();
}
});
$(this).data('open', true);
});
this.$li.find('a.action.edit').on('click keypress', function(event) {
$.when(self.storage.getAddressBook(self.getBackend(), self.getId()))
.then(function(response) {
if(!response.error) {
if(response.data) {
var addressbook = response.data;
console.log('addressbook', addressbook);
if (addressbook.backend === 'local') {
if($(this).data('open')) {
return;
}
var editor = this;
event.stopPropagation();
event.preventDefault();
var $dropdown = $('<li><div><input type="text" value="{name}" /></div></li>')
.octemplate({name:self.getDisplayName()}).insertAfter(self.$li);
var $input = $dropdown.find('input');
//$input.focus().get(0).select();
$input.addnew({
autoOpen: true,
//autoClose: false,
addText: t('contacts', 'Save'),
ok: function(event, name) {
console.log('edit-address-book ok', name);
$input.addClass('loading');
self.update({displayname:name}, function(response) {
console.log('response', response);
if(response.error) {
$(document).trigger('status.contacts.error', response);
} else {
self.setDisplayName(response.data.displayname);
$input.addnew('close');
}
$input.removeClass('loading');
});
},
close: function() {
$dropdown.remove();
$(editor).data('open', false);
}
});
$(this).data('open', true);
} else {
var $rightContent = $('#app-content');
$rightContent.append('<div id="addressbook-ui-dialog"></div>');
var $dlg = $('#addressBookConfigTemplate').octemplate({backend: 'ldap'});
var $divDlg = $('#addressbook-ui-dialog');
//var $divDlg = $('#addressbook-ui-dialog');
$divDlg.html($dlg).ocdialog({
modal: true,
closeOnEscape: true,
title: t('contacts', 'Edit Addressbook'),
height: 'auto', width: 'auto',
buttons: [
{
text: t('contacts', 'Ok'),
click: function() {
OC.Contacts.otherBackendConfig.addressbookUiEditOk($divDlg);
self.setDisplayName($('#addressbooks-ui-name').val());
},
defaultButton: true
},
{
text: t('contacts', 'Cancel'),
click: function() {
OC.Contacts.otherBackendConfig.addressbookUiClose($divDlg);
}
}
],
close: function() {
OC.Contacts.otherBackendConfig.addressbookUiClose($divDlg);
},
open: function() {
OC.Contacts.otherBackendConfig.editAddressbookUI(addressbook);
}
});
}
return this.$li;
}
} else {
console.warn('Addressbook getAddressbook - no data !!');
}
})
.fail(function(response) {
console.warn('Request Failed:', response.message);
$(document).trigger('status.contacts.error', response);
});
});
return this.$li;
};
@ -303,7 +391,7 @@ OC.Contacts = OC.Contacts || {};
});
this.$importFileInput.fileupload({
dataType: 'json',
start: function(e, data) {
start: function(/*e, data*/) {
self.$importProgress.progressbar({value:false});
$('.tipsy').remove();
$('.import-upload').hide();

107
js/admin.js Normal file
View File

@ -0,0 +1,107 @@
$(document).ready(function() {
$('#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 requestRoute(
'backend/{backend}/{enable}',
'GET',
{backend: backend, enable: enable},
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;
}
}
}
};

View File

@ -168,6 +168,11 @@ OC.notify = function(params) {
$('#app-settings-content'),
$('#addressBookTemplate')
);
this.otherBackendConfig = new OC.Contacts.OtherBackendConfig(
this.storage,
this.addressBooks,
$('#addressBookConfigTemplate')
);
this.contacts = new OC.Contacts.ContactList(
this.storage,
this.addressBooks,

View File

@ -146,4 +146,5 @@ $(document).ready(function(){
FileActions.register('text/x-vcard','importaddressbook', OC.PERMISSION_READ, '', OC.ContactsImporter.init);
FileActions.setDefault('text/x-vcard','importaddressbook');
}
});

340
js/otherbackendconfig.js Normal file
View File

@ -0,0 +1,340 @@
OC.Contacts = OC.Contacts || {};
(function(window, $, OC) {
'use strict';
var OtherBackendConfig = function(storage, addressbooks, $template) {
this.storage = storage;
this.addressbooks = addressbooks;
this.$template = $template;
this.getConnectors();
};
OC.Contacts.OtherBackendConfig = OtherBackendConfig;
OtherBackendConfig.prototype.openAddressbookUi = function() {
this.addressbookUiInit();
};
OtherBackendConfig.prototype.editAddressbookUI = function(addressbook) {
var self = this;
$('#addressbooks-ui-addressbookid').val(addressbook.id);
$('#addressbooks-ui-name').val(addressbook.displayname);
$('#addressbooks-ui-uri').val(addressbook.uri);
$('#addressbooks-ui-description').val(addressbook.description);
$('#addressbooks-ui-ldapurl').val(addressbook.ldapurl);
$('#addressbooks-ui-ldapanonymous').attr('checked', (addressbook.ldapanonymous===true));
$('#addressbooks-ui-ldapreadonly').attr('checked', (addressbook.ldapreadonly===true));
$('#addressbooks-ui-ldapuser').val(addressbook.ldapuser);
$('#addressbooks-ui-ldappass').val('nochange');
$('#addressbooks-ui-ldappass-modified').val('false');
$('#addressbooks-ui-ldappagesize').val(addressbook.ldappagesize);
$('#addressbooks-ui-ldapbasednsearch').val(addressbook.ldapbasednsearch);
$('#addressbooks-ui-ldapfilter').val(addressbook.ldapfilter);
$('#addressbooks-ui-ldapbasednmodify').val(addressbook.ldapbasednmodify);
$('#addressbooks-ui-uri').prop('disabled', true);
if ($('#addressbooks-ui-ldapanonymous').prop('checked')) {
$('#addressbooks-ui-ldapuser').prop('disabled', true);
$('#addressbooks-ui-ldappass').prop('disabled', true);
} else {
$('#addressbooks-ui-ldapuser').removeProp('disabled');
$('#addressbooks-ui-ldappass').removeProp('disabled');
}
if ($('#addressbooks-ui-ldapreadonly').prop('checked')) {
$('#addressbooks-ui-ldapbasednmodify').prop('disabled', true);
} else {
$('#addressbooks-ui-ldapbasednmodify').removeProp('disabled');
}
$('#addressbooks-ui-ldappass').change(function() {
$('#addressbooks-ui-ldappass-modified').val('true');
});
this.addressbookUiInit();
var connectors = self.getConnectors();
$('#addressbooks-ui-ldapvcardconnector').empty();
var custom = true;
var $option = null;
for (var id = 0; id < connectors.length; id++) {
if (connectors[id].id === addressbook.ldapconnectorid) {
$option = $('<option value="' + connectors[id].id + '">' + connectors[id].name + '</option>').attr('selected','selected');
custom = false;
} else {
$option = $('<option value="' + connectors[id].id + '">' + connectors[id].name + '</option>');
}
$('#addressbooks-ui-ldapvcardconnector').append($option);
}
if (custom) {
$option = $('<option value="">' + 'Custom connector' + '</option>').attr('selected','selected');
$('#addressbooks-ui-ldapvcardconnector').append($option);
$('#addressbooks-ui-ldapvcardconnector-value-p').show();
$('#addressbooks-ui-ldapvcardconnector-copyfrom-p').show();
$('#addressbooks-ui-ldapvcardconnector-copyfrom').empty();
$option = $('<option value="">' + 'Select connector' + '</option>').attr('selected','selected');
$('#addressbooks-ui-ldapvcardconnector-copyfrom').append($option);
for (var id = 0; id < connectors.length; id++) {
$option = $('<option value="' + connectors[id].id + '">' + connectors[id].name + '</option>');
$('#addressbooks-ui-ldapvcardconnector-copyfrom').append($option);
}
$('#addressbooks-ui-ldapvcardconnector-value').text(addressbook.ldap_vcard_connector);
} else {
$option = $('<option value="">' + 'Custom connector' + '</option>');
$('#addressbooks-ui-ldapvcardconnector').append($option);
}
};
OtherBackendConfig.prototype.addressbookUiOk = function($divDlg) {
var defer = $.Deferred();
var addressbook = OC.Contacts.addressBooks;
var error=false;
var errorFields = [];
$('[required]').each(function() {
if ($(this).val() === '' && !$(this).attr('disabled')){
error = true;
errorFields.push($(this).attr('placeholder'));
}
});
if (!error) {
$('#addressbooks-ui-errortitle-p').empty();
$('#addressbooks-ui-errormessage-p').empty();
$.when(this.storage.addAddressBook($('#addressbooks-ui-backend').val(),
{
displayname: $('#addressbooks-ui-name').val(),
description: $('#addressbooks-ui-description').val(),
uri: ($('#addressbooks-ui-uri').val()==='')?$('#addressbooks-ui-name').val():$('#addressbooks-ui-uri').val(),
ldapurl: $('#addressbooks-ui-ldapurl').val(),
ldapanonymous: $('#addressbooks-ui-ldapanonymous').prop('checked')===true?'true':'false',
ldapreadonly: $('#addressbooks-ui-ldapreadonly').prop('checked')===true?'true':'false',
ldapuser: $('#addressbooks-ui-ldapuser').val(),
ldappass: $('#addressbooks-ui-ldappass').val(),
ldappagesize: $('#addressbooks-ui-ldappagesize').val(),
ldapbasednsearch: $('#addressbooks-ui-ldapbasednsearch').val(),
ldapfilter: $('#addressbooks-ui-ldapfilter').val(),
ldapbasednmodify: $('#addressbooks-ui-ldapbasednmodify').val(),
ldapvcardconnector: $('#addressbooks-ui-ldapvcardconnector').val(),
ldapvcardconnectorvalue: $('#addressbooks-ui-ldapvcardconnector-value').val(),
}
)).then(function(response) {
if(response.error) {
var error = response.message;
if(typeof cb === 'function') {
cb({error:true, message:error});
}
defer.reject(response);
} else {
var book = addressbook.insertAddressBook(response.data);
$(document).trigger('status.addressbook.added');
if(typeof cb === 'function') {
cb({error:false, addressbook: book});
}
defer.resolve({error:false, addressbook: book});
}
OC.Contacts.otherBackendConfig.addressbookUiClose($divDlg);
})
.fail(function(jqxhr, textStatus, error) {
$(this).removeClass('loading');
var err = textStatus + ', ' + error;
console.log('Request Failed', + err);
error = t('contacts', 'Failed adding address book: {error}', {error:err});
if(typeof cb === 'function') {
cb({error:true, message:error});
}
defer.reject({error:true, message:error});
OC.Contacts.otherBackendConfig.addressbookUiClose($divDlg);
});
} else {
$('#addressbooks-ui-errortitle-p').css('color', 'red').text(t('contacts', 'Error, missing parameters: '));
$('#addressbooks-ui-errormessage-p').css('color', 'red').text(errorFields.join(', '));
}
};
OtherBackendConfig.prototype.addressbookUiEditOk = function($divDlg) {
var defer = $.Deferred();
var error=false;
var errorFields = [];
$('[required]').each(function() {
if ($(this).val() === '' && !$(this).attr('disabled')){
error = true;
errorFields.push($(this).attr('placeholder'));
}
});
if (!error) {
$.when(this.storage.updateAddressBook($('#addressbooks-ui-backend').val(), $('#addressbooks-ui-addressbookid').val(),
{properties:
{
displayname: $('#addressbooks-ui-name').val(),
description: $('#addressbooks-ui-description').val(),
uri: $('#addressbooks-ui-uri').val(),
ldapurl: $('#addressbooks-ui-ldapurl').val(),
ldapanonymous: $('#addressbooks-ui-ldapanonymous').prop('checked')===true?'true':'false',
ldapreadonly: $('#addressbooks-ui-ldapreadonly').prop('checked')===true?'true':'false',
ldapuser: $('#addressbooks-ui-ldapuser').val(),
ldappassmodified: $('#addressbooks-ui-ldappass-modified').val(),
ldappass: $('#addressbooks-ui-ldappass').val(),
ldappagesize: $('#addressbooks-ui-ldappagesize').val(),
ldapbasednsearch: $('#addressbooks-ui-ldapbasednsearch').val(),
ldapfilter: $('#addressbooks-ui-ldapfilter').val(),
ldapbasednmodify: $('#addressbooks-ui-ldapbasednmodify').val(),
ldapvcardconnector: $('#addressbooks-ui-ldapvcardconnector').val(),
ldapvcardconnectorvalue: $('#addressbooks-ui-ldapvcardconnector-value').val(),
}
}
)).then(function(response) {
if(response.error) {
error = response.message;
if(typeof cb === 'function') {
cb({error:true, message:error});
}
defer.reject(response);
}
OC.Contacts.otherBackendConfig.addressbookUiClose($divDlg);
})
.fail(function(jqxhr, textStatus, error) {
$(this).removeClass('loading');
var err = textStatus + ', ' + error;
console.log('Request Failed', + err);
error = t('contacts', 'Failed adding address book: {error}', {error:err});
if(typeof cb === 'function') {
cb({error:true, message:error});
}
defer.reject({error:true, message:error});
});
} else {
$('#addressbooks-ui-errortitle-p').css('color', 'red').text(t('contacts', 'Error, missing parameters: '));
$('#addressbooks-ui-errormessage-p').css('color', 'red').text(errorFields.join(', '));
}
};
OtherBackendConfig.prototype.addressbookUiClose = function($divDlg) {
$divDlg.ocdialog().ocdialog('close');
$divDlg.ocdialog().ocdialog('destroy').remove();
};
OtherBackendConfig.prototype.addressbookUiInit = function() {
var self = this;
$('#addressbooks-ui-ldapvcardconnector-value-p').hide();
$('#addressbooks-ui-ldapvcardconnector-copyfrom-p').hide();
$('#addressbooks-ui-name').change(function() {
if ($('#addressbooks-ui-uri').val() === '') {
$('#addressbooks-ui-uri').val($('#addressbooks-ui-name').val().toLowerCase().replace(' ', '-'));
}
});
$('#addressbooks-ui-ldapanonymous').change(function() {
if ($('#addressbooks-ui-ldapanonymous').prop('checked')) {
$('#addressbooks-ui-ldapuser').prop('disabled', true);
$('#addressbooks-ui-ldappass').prop('disabled', true);
} else {
$('#addressbooks-ui-ldapuser').removeProp('disabled');
$('#addressbooks-ui-ldappass').removeProp('disabled');
}
});
$('#addressbooks-ui-ldapreadonly').change(function() {
if ($('#addressbooks-ui-ldapreadonly').prop('checked')) {
$('#addressbooks-ui-ldapbasednmodify').prop('disabled', true);
} else {
$('#addressbooks-ui-ldapbasednmodify').removeProp('disabled');
}
});
$('#addressbooks-ui-ldapbasednsearch').change(function() {
if ($('#addressbooks-ui-ldapbasednmodify').val() === '') {
$('#addressbooks-ui-ldapbasednmodify').val($('#addressbooks-ui-ldapbasednsearch').val());
}
});
$('#addressbooks-ui-ldapbasednmodify').change(function() {
if ($('#addressbooks-ui-ldapbasednsearch').val() === '') {
$('#addressbooks-ui-ldapbasednsearch').val($('#addressbooks-ui-ldapbasednmodify').val());
}
});
$('#addressbooks-ui-ldapvcardconnector').empty();
var $option = null;
var connectors = self.getConnectors();
for (var id = 0; id < connectors.length; id++) {
if (connectors[id] !== null) {
$option = $('<option value="' + connectors[id].id + '">' + connectors[id].name + '</option>');
$('#addressbooks-ui-ldapvcardconnector').append($option);
}
}
$option = $('<option value="">' + 'Custom connector' + '</option>');
$('#addressbooks-ui-ldapvcardconnector').append($option);
$('#addressbooks-ui-ldapvcardconnector').change(function() {
// Custom connector
if ($('#addressbooks-ui-ldapvcardconnector').val() === '') {
$('#addressbooks-ui-ldapvcardconnector-value-p').show();
$('#addressbooks-ui-ldapvcardconnector-copyfrom-p').show();
var connectors = self.getConnectors();
$('#addressbooks-ui-ldapvcardconnector-copyfrom').empty();
var $option = $('<option value="">' + 'Select connector' + '</option>').attr('selected','selected');
$('#addressbooks-ui-ldapvcardconnector-copyfrom').append($option);
for (var id = 0; id < connectors.length; id++) {
$option = $('<option value="' + connectors[id].id + '">' + connectors[id].name + '</option>');
$('#addressbooks-ui-ldapvcardconnector-copyfrom').append($option);
}
} else {
$('#addressbooks-ui-ldapvcardconnector-value-p').hide();
$('#addressbooks-ui-ldapvcardconnector-copyfrom-p').hide();
}
});
$('#addressbooks-ui-ldapvcardconnector-copyfrom').change(function() {
if ($('#addressbooks-ui-ldapvcardconnector-copyfrom').val() !== '') {
var connectors = self.getConnectors();
for (var id = 0; id < connectors.length; id++) {
if ($('#addressbooks-ui-ldapvcardconnector-copyfrom').val() === connectors[id].id) {
$('#addressbooks-ui-ldapvcardconnector-value').text(connectors[id].xml);
}
}
}
});
$('#addressbooks-ui-ldappagesize').forceNumericOnly();
};
OtherBackendConfig.prototype.getConnectors = function() {
var self = this;
if (self.connectors === null) {
$.when(self.storage.getConnectors($('#addressbooks-ui-backend').val()))
.then(function(response) {
self.connectors = response.data;
return self.connectors;
})
.fail(function(jqxhr, textStatus, error) {
var err = textStatus + ', ' + error;
console.log('Request Failed', + err);
defer.reject({error:true, message:error});
});
} else {
return self.connectors;
}
};
jQuery.fn.forceNumericOnly = function()
{
return this.each(function()
{
$(this).keydown(function(e)
{
var key = e.charCode || e.keyCode || 0;
// allow backspace, tab, delete, enter, arrows, numbers and keypad numbers ONLY
// home, end, period, and numpad decimal
return (
key === 8 ||
key === 9 ||
key === 13 ||
key === 46 ||
key === 110 ||
key === 190 ||
(key >= 35 && key <= 40) ||
(key >= 48 && key <= 57) ||
(key >= 96 && key <= 105));
});
});
};
})(window, jQuery, OC);

View File

@ -127,7 +127,7 @@ OC.Contacts = OC.Contacts || {};
return this.requestRoute(
'addressbook/{backend}/add',
'POST',
{backend: 'local'},
{backend: backend},
JSON.stringify(parameters)
);
};
@ -150,7 +150,7 @@ OC.Contacts = OC.Contacts || {};
* }
*/
Storage.prototype.updateAddressBook = function(backend, addressBookId, properties) {
console.log('Storage.updateAddressBook', backend);
console.log('Storage.updateAddressBook', backend, addressBookId, properties);
return this.requestRoute(
'addressbook/{backend}/{addressBookId}',
'POST',
@ -196,6 +196,32 @@ OC.Contacts = OC.Contacts || {};
JSON.stringify({state: state})
);
};
/**
* Update an address book in a specific backend
*
* @param string backend
* @param string addressBookId Address book ID
* @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.getConnectors = function(backend) {
console.log('Storage.getConnectors', backend);
return this.requestRoute(
'connectors/{backend}',
'GET',
{backend: backend}
);
};
/**
* Get metadata from an address book from a specific backend
@ -649,7 +675,7 @@ OC.Contacts = OC.Contacts || {};
params
);
};
Storage.prototype.requestRoute = function(route, type, routeParams, params, additionalHeaders) {
var isJSON = (typeof params === 'string');
var contentType = isJSON

View File

@ -174,7 +174,8 @@ class Addressbook extends AbstractPIMCollection {
if (!isset($this->objects[$id])) {
$contact = $this->backend->getContact($this->getId(), $id);
if ($contact) {
$this->objects[$id] = new Contact($this, $this->backend, $contact);
//$this->objects[$id] = new Contact($this, $this->backend, $contact);
$curContact = new Contact($this, $this->backend, $contact);
} else {
throw new \Exception(
self::$l10n->t('Contact not found'),
@ -184,9 +185,10 @@ class Addressbook extends AbstractPIMCollection {
}
// When requesting a single contact we preparse it
if (isset($this->objects[$id])) {
$this->objects[$id]->retrieve();
return $this->objects[$id];
if (isset($curContact)) {
$curContact->retrieve();
$this->objects[$id] = $curContact;
return $curContact;
}
}

View File

@ -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';
}
}
/**

View File

@ -36,9 +36,7 @@ abstract class AbstractBackend {
* @method array|null getAddressBook(string $addressbookid, array $options = array())
* @method array getContacts(string $addressbookid, array $options = array())
* @method array|null getContact(string $addressbookid, mixed $id, array $options = array())
*
* The following methods MAY be implemented but ONLY if the backend can actually perform the action
* as the existence of the methods is used to determine the backends capabilities:
* The following methods MAY be implemented:
* @method bool hasAddressBook(string $addressbookid)
* @method bool updateAddressBook(string $addressbookid, array $updates, array $options = array())
* @method string createAddressBook(array $properties, array $options = array())
@ -53,26 +51,24 @@ abstract class AbstractBackend {
/**
* The name of the backend.
*
* @var string
*/
public $name;
/**
* The current user.
*
* The current usert.
* @var string
*/
public $userid;
protected $possibleContactCapabilities = array(
protected $possibleContactPermissions = array(
\OCP\PERMISSION_CREATE => 'createContact',
\OCP\PERMISSION_READ => 'getContact',
\OCP\PERMISSION_UPDATE => 'updateContact',
\OCP\PERMISSION_DELETE => 'deleteContact',
);
protected $possibleAddressBookCapabilities = array(
protected $possibleAddressBookPermissions = array(
\OCP\PERMISSION_CREATE => 'createAddressBook',
\OCP\PERMISSION_READ => 'getAddressBook',
\OCP\PERMISSION_UPDATE => 'updateAddressBook',
@ -88,17 +84,16 @@ abstract class AbstractBackend {
}
/**
* @brief Get all capabilities for contacts based on what the backend implements.
* @brief Get all possible permissions for contacts based on what the backend implements.
* @returns bitwise-or'ed actions
*
* Returns the supported actions as an int to be
* compared with \OCP\PERMISSION_CREATE etc.
* @see AbstractBackend::hasContactMethodFor()
* @returns bitwise-or'ed actions
*/
protected function getContactCapacilities() {
protected function getContactPermissions() {
$permissions = 0;
foreach ($this->possibleContactCapabilities as $permission => $methodName) {
foreach ($this->possibleContactPermissions as $permission => $methodName) {
if(method_exists($this, $methodName)) {
$permissions |= $permission;
}
@ -110,18 +105,17 @@ abstract class AbstractBackend {
}
/**
* @brief Get all capabilities for address books based on what the backend implements.
* @brief Get all permissions for address book based on what the backend implements.
* @returns bitwise-or'ed actions
*
* Returns the supported actions as int to be
* compared with \OCP\PERMISSION_CREATE etc.
* @see AbstractBackend::hasAddressBookMethodFor()
* @returns bitwise-or'ed actions
*/
protected function getAddressBookCapabilities() {
protected function getAddressBookPermissions() {
$permissions = 0;
foreach ($this->possibleAddressBookCapabilities as $permission => $methodName) {
foreach ($this->possibleAddressBookPermissions as $permission => $methodName) {
if (method_exists($this, $methodName)) {
$permissions |= $permission;
}
@ -134,36 +128,34 @@ abstract class AbstractBackend {
/**
* @brief Check if backend implements action for contacts
*
* Returns true if the backend supports an action for a given permission
* for example \OCP\PERMISSION_CREATE etc.
*
* @param $permission bitwise-or'ed actions
* @param $actions bitwise-or'ed actions
* @returns boolean
*
* Returns the supported actions as int to be
* compared with \OCP\PERMISSION_CREATE etc.
*/
public function hasContactMethodFor($permission) {
return (bool)($this->getContactCapacilities() & $permission);
return (bool)($this->getContactPermissions() & $permission);
}
/**
* @brief Check if backend implements action for contacts
*
* Returns true if the backend supports an action for a given permission
* for example \OCP\PERMISSION_CREATE etc.
*
* @param $permission bitwise-or'ed actions
* @param $actions bitwise-or'ed actions
* @returns boolean
*
* Returns the supported actions as int to be
* compared with \OCP\PERMISSION_CREATE etc.
*/
public function hasAddressBookMethodFor($permission) {
return (bool)($this->getAddressBookCapabilities() & $permission);
return (bool)($this->getAddressBookPermissions() & $permission);
}
/**
* @brief Check if the backend has the address book
* Check if the backend has the address book
*
* This can be reimplemented in the backend to improve performance.
*
@ -177,8 +169,7 @@ abstract class AbstractBackend {
}
/**
* @brief Returns the number of contacts in an address book.
*
* 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.
@ -193,13 +184,12 @@ abstract class AbstractBackend {
}
/**
* @brief Returns the list of addressbooks for a specific user.
* Returns the list of addressbooks for a specific user.
*
* The returned arrays MUST contain a unique 'id' for the
* backend a string 'displayname' and an integer
* 'permissions', and it MAY contain a string 'description'.
* backend and a 'displayname', and it MAY contain a
* 'description'.
*
* @see AbstractBackend::getAddressBook()
* @param array $options - Optional (backend specific options)
* @return array
*/
@ -211,8 +201,8 @@ abstract class AbstractBackend {
* The returned array MUST contain string: 'displayname',string: 'backend'
* and integer: 'permissions' value using there ownCloud CRUDS constants
* (which MUST be at least \OCP\PERMISSION_READ).
* The backend MAY also add the optional entries 'description' and 'owner',
* and can add additional entries if needed internally.
* Currently the only ones supported are 'displayname' and
* 'description', but backends can implement additional.
*
* @param string $addressBookId
* @param array $options - Optional (backend specific options)
@ -225,10 +215,9 @@ abstract class AbstractBackend {
*
* The $properties array contains the changes to be made.
*
* The backend MUST NOT implement this method if it doesn't support updating,
* and the implementation is commented out here intentionally!
* Currently the only ones supported are 'displayname' and
* 'description', but backends can implement additional.
*
* @see AbstractBackend::getAddressBook()
* @param string $addressBookId
* @param array $properties
* @param array $options - Optional (backend specific options)
@ -239,7 +228,7 @@ abstract class AbstractBackend {
/**
* Creates a new address book
*
* Backends that doesn't support adding address books MUST NOT implement this method.
* Classes that doesn't support adding address books MUST NOT implement this method.
*
* Currently the only ones supported are 'displayname' and
* 'description', but backends can implement additional.
@ -254,7 +243,7 @@ abstract class AbstractBackend {
/**
* Deletes an entire address book and all its contents
*
* Backends that doesn't support deleting address books MUST NOT implement this method.
* Classes that doesn't support deleting address books MUST NOT implement this method.
*
* @param string $addressBookId
* @param array $options - Optional (backend specific options)
@ -290,18 +279,11 @@ abstract class AbstractBackend {
* Returns all contacts for a specific addressbook id.
*
* The returned array MUST contain the unique ID a string value 'id', a string
* value 'displayname' and an integer 'permissions' value using there
* value 'displayname', a string value 'owner' 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'.
* If the backend supports different ownerships it can add an 'owner' entry.
*
* NOTE: To improve performance $options can contain the boolean value 'omitdata'
* that if true indicates that the backend SHOULD NOT add 'vcard' or 'carddata'.
*
* NOTE: If the backend doesn't support fetching in batches 'offset' and 'limit'
* MUST be ignored and all contacts MUST be returned.
*
* Example:
*
@ -310,6 +292,9 @@ abstract class AbstractBackend {
* 1 => array('id' => 'bbcca2d1535', 'owner' => 'bar', '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.
*
* The following options are supported in the $options array:
*
* - 'limit': An integer value for the number of contacts to fetch in each call.
@ -343,7 +328,7 @@ abstract class AbstractBackend {
* @param VCard $contact
* @param array $options - Optional options
* @return string|bool The identifier for the new contact or false on error.
public function createContact($addressBookId, $contact, array $options = array());
public function createContact($addressbookid, $contact, array $options = array());
*/
/**
@ -356,7 +341,7 @@ abstract class AbstractBackend {
* @param VCard $contact
* @param array $options - Optional options
* @return bool
public function updateContact($addressBookId, $id, $carddata, array $options = array());
public function updateContact($addressbookid, $id, $carddata, array $options = array());
*/
/**
@ -368,7 +353,7 @@ abstract class AbstractBackend {
* @param mixed $id
* @param array $options - Optional options
* @return bool
public function deleteContact($addressBookId, $id, array $options = array());
public function deleteContact($addressbookid, $id, array $options = array());
*/
/**
@ -449,11 +434,10 @@ abstract class AbstractBackend {
*/
public function getPreferences($addressBookId) {
$key = $this->combinedKey($addressBookId);
$key = 'prefs_' . $key;
$key = 'prefs_' . $this->combinedKey($addressBookId);
$data = \OCP\Config::getUserValue($this->userid, 'contacts', $key, false);
return $data ? json_decode($data) : array();
return $data ? json_decode($data, true) : array();
}
/**
@ -462,18 +446,20 @@ abstract class AbstractBackend {
* @param array the preferences, format array('param1' => 'value', 'param2' => 'value')
* @return boolean
*/
public function setPreferences($addressBookId, array $params) {
$key = $this->combinedKey($addressBookId);
$key = 'prefs_' . $key;
public function setPreferences($addressbookid, array $params) {
$key = 'prefs_' . $this->combinedKey($addressbookid);
$data = json_encode($params);
return $data
? \OCP\Config::setUserValue($this->userid, 'contacts', $key, $data)
: false;
}
public function getSearchProvider($addressbook) {
public function removePreferences($addressbookid) {
$key = $this->combinedKey($addressbookid);
$key = 'prefs_' . $key;
\OC_Preferences::deleteKey( $this->userid, 'contacts', $key );
}
}

View File

@ -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 {
@ -175,7 +180,7 @@ class Ldap extends AbstractBackend {
if ($num==null) {
$num=PHP_INT_MAX;
}
\OC_Log::write('contacts_ldap', __METHOD__." - search what $ldapbasedn, $bindsearch ", \OC_Log::DEBUG);
\OC_Log::write('contacts_ldap', __METHOD__." - search $ldapbasedn, $bindsearch ", \OC_Log::DEBUG);
$ldap_results = @ldap_search ($this->ldapConnection, $ldapbasedn, $bindsearch, $entries);
if ($ldap_results) {
@ -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;
}
@ -256,29 +256,11 @@ class Ldap extends AbstractBackend {
* @return array
*/
public function getAddressBooksForUser(array $options = array()) {
try {
if(!isset(self::$preparedQueries['addressbooksforuser'])) {
$sql = 'SELECT `configkey` from *PREFIX*preferences where `configkey` like ?';
$configkeyPrefix = $this->name . "_%_uri";
self::$preparedQueries['addressbooksforuser'] = \OCP\DB::prepare($sql);
$result = self::$preparedQueries['addressbooksforuser']->execute(array($configkeyPrefix));
if (\OC_DB::isError($result)) {
\OCP\Util::write('contacts', __METHOD__. 'DB error: ' . \OC_DB::getErrorMessage($result), \OCP\Util::ERROR);
return $this->addressbooks;
}
$this->addressbooks = array();
while($row = $result->fetchRow()) {
$id = str_replace("_uri", "", str_replace($this->name."_", "", $row['configkey']));
$this->addressbooks[] = self::getAddressBook($id);
}
return $this->addressbooks;
}
} catch(\Exception $e) {
\OC_Log::write('contacts', __METHOD__.' exception: ' . $e->getMessage(), \OCP\Util::ERROR);
return $this->addressbooks;
$addressbookidList = $this->getAddressbookList();
foreach($addressbookidList as $addressbookid) {
$this->addressbooks[] = self::getAddressBook($addressbookid);
}
return $this->addressbooks;
}
/**
@ -302,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'] = $addressbookid;
$current['displayname'] = $preferences['displayname'];
$current['description'] = $preferences['description'];
$current['owner'] = $this->userid;
$current['uri'] = $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();
}
@ -338,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
*
@ -357,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;
}
/**
@ -367,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.
*
@ -415,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)) {
@ -431,7 +501,7 @@ class Ldap extends AbstractBackend {
//OCP\Util::writeLog('contacts_ldap', __METHOD__.' Connector OK', \OC_Log::DEBUG);
$info = self::ldapFindMultiple(
$this->ldapParams['ldapbasednsearch'],
'(objectclass=person)',
$this->ldapParams['ldapfilter'],
$this->connector->getLdapEntries(),
isset($options['offset']) ? $options['offset'] : null,
isset($options['limit']) ? $options['limit'] : null
@ -464,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);
@ -481,7 +550,7 @@ class Ldap extends AbstractBackend {
$this->connector->getLdapEntries());
} else {
$card = self::ldapFindOne(base64_decode($cid),
'objectClass=*',
$this->ldapParams['ldapfilter'],
$this->connector->getLdapEntries());
}
}
@ -517,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,
@ -534,6 +603,15 @@ class Ldap extends AbstractBackend {
public function createContact($addressbookid, $contact, array $options = array()) {
$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 = "nocn-".rand(0, 65535);
$contact->N = $generated;
$contact->FN = $generated;
}
if(!$contact instanceof VCard) {
try {
@ -559,6 +637,8 @@ class Ldap extends AbstractBackend {
$contact->{'X-LDAP-DN'} = base64_encode($newDN);
if ($uri!=null) {
$contact->{'X-URI'} = $uri;
} else {
$contact->{'X-URI'} = $contact->{'UID'}.".vcf";
}
$ldifEntries = $this->connector->VCardToLdap($contact);
@ -583,7 +663,25 @@ class Ldap extends AbstractBackend {
* @return bool
*/
public function updateContact($addressbookid, $id, $carddata, array $options = array()) {
$vcard = \Sabre\VObject\Reader::read($carddata);
if(!$carddata instanceof VCard) {
try {
$vcard = \Sabre\VObject\Reader::read($carddata);
} catch(\Exception $e) {
\OCP\Util::writeLog('contacts', __METHOD__.', exception: '.$e->getMessage(), \OCP\Util::ERROR);
return false;
}
} else {
$vcard = $carddata;
}
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);
@ -605,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();
@ -621,13 +721,21 @@ class Ldap extends AbstractBackend {
public function deleteContact($addressbookid, $id, array $options = array()) {
self::setLdapParams($addressbookid);
self::ldapCreateAndBindConnection();
$card = self::getContact($addressbookid, array($id));
$vcard = \Sabre\VObject\Reader::read($card['carddata']);
$decodedId = base64_decode($vcard->{'X-LDAP-DN'});
// Deletes the existing card
$result = self::ldapDelete($decodedId);
self::ldapCloseConnection();
return $result;
if (is_array($id)) {
$card = self::getContact($addressbookid, $id);
} else {
$card = self::getContact($addressbookid, array($id));
}
if ($card) {
$vcard = \Sabre\VObject\Reader::read($card['carddata']);
$decodedId = base64_decode($vcard->{'X-LDAP-DN'});
// Deletes the existing card
$result = self::ldapDelete($decodedId);
self::ldapCloseConnection();
return $result;
} else {
return false;
}
}
/**
@ -649,4 +757,33 @@ class Ldap extends AbstractBackend {
}
}
/**
* @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();
}
public function getSearchProvider($addressbook) {
return new \OCA\Contacts\AddressbookProvider($addressbook);
}
}

View File

@ -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();
}
}
}
}
?>

View File

@ -113,7 +113,6 @@ class AddressBookController extends Controller {
$response->setETag($etag);
}
//$response->debug('comparing: "' . $etag . '" to ' . $this->request->getHeader('If-None-Match'));
if (!is_null($etag)
&& $this->request->getHeader('If-None-Match') === '"'.$etag.'"')
{

View File

@ -0,0 +1,73 @@
<?php
/**
* @author Nicolas Mora
* @copyright 2014 Nicolas Mora (mail@babelouest.org)
* This file is licensed under the Affero General Public License version 3 or
* later.
* See the COPYING-README file.
*/
namespace OCA\Contacts\Controller;
use OCA\Contacts\App,
OCA\Contacts\JSONResponse,
OCA\Contacts\Utils\JSONSerializer,
OCA\Contacts\Controller,
OCP\AppFramework\Http;
/**
* Controller class For Address Books
*/
class BackendController extends Controller {
/**
* @NoAdminRequired
* @NoCSRFRequired
*/
public function getConnectors() {
$response = new JSONResponse();
$prefix = "backend_ldap_";
$suffix = "_connector.xml";
$path = __DIR__ . "/../../formats/";
$files = scandir($path);
$formats = array();
foreach ($files as $file) {
if (!strncmp($file, $prefix, strlen($prefix)) && substr($file, - strlen($suffix)) === $suffix) {
if (file_exists($path.$file)) {
$format = simplexml_load_file ( $path.$file );
if ($format) {
if (isset($format['name'])) {
$formatId = substr($file, strlen($prefix), - strlen($suffix));
$formats[] = array('id' => $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);
}
}

View File

@ -52,6 +52,7 @@ class PageController extends Controller {
\OCP\Util::addScript('contacts', 'storage');
\OCP\Util::addScript('contacts', 'groups');
\OCP\Util::addScript('contacts', 'jquery.ocaddnew');
\OCP\Util::addScript('contacts', 'otherbackendconfig');
\OCP\Util::addScript('files', 'jquery.fileupload');
\OCP\Util::addScript('3rdparty/Jcrop', 'jquery.Jcrop');
\OCP\Util::addStyle('', 'jquery.multiselect');

View File

@ -16,6 +16,7 @@ use OCP\AppFramework\App as MainApp,
OCA\Contacts\Middleware\Http as HttpMiddleware,
OCA\Contacts\Controller\PageController,
OCA\Contacts\Controller\AddressBookController,
OCA\Contacts\Controller\BackendController,
OCA\Contacts\Controller\GroupController,
OCA\Contacts\Controller\ContactController,
OCA\Contacts\Controller\ContactPhotoController,
@ -63,47 +64,50 @@ class Dispatcher extends MainApp {
public function registerServices() {
$app = $this->app;
$appName = $this->appName;
$this->container->registerService('HttpMiddleware', function($container) {
return new HttpMiddleware();
});
$this->container->registerService('PageController', function(IAppContainer $container) use($appName) {
$this->container->registerService('PageController', function(IAppContainer $container) use($app) {
$request = $container->query('Request');
return new PageController($appName, $request);
return new PageController($this->appName, $request);
});
$this->container->registerService('AddressBookController', function(IAppContainer $container) use($appName, $app) {
$this->container->registerService('AddressBookController', function(IAppContainer $container) use($app) {
$request = $container->query('Request');
$api = $container->query('API');
return new AddressBookController($appName, $request, $app, $api);
return new AddressBookController($this->appName, $request, $app, $api);
});
$this->container->registerService('GroupController', function(IAppContainer $container) use($appName, $app) {
$this->container->registerService('BackendController', function(IAppContainer $container) use($app) {
$request = $container->query('Request');
$tags = $container->getServer()->getTagManager()->load('contact');
return new GroupController($appName, $request, $app, $tags);
return new BackendController($container, $request, $app);
});
$this->container->registerService('ContactController', function(IAppContainer $container) use($appName, $app) {
$this->container->registerService('GroupController', function(IAppContainer $container) use($app) {
$request = $container->query('Request');
return new ContactController($appName, $request, $app);
$tags = $this->server->getTagManager()->load('contact');
return new GroupController($this->appName, $request, $app, $tags);
});
$this->container->registerService('ContactPhotoController', function(IAppContainer $container) use($appName, $app) {
$this->container->registerService('ContactController', function(IAppContainer $container) use($app) {
$request = $container->query('Request');
$cache = $container->getServer()->getCache();
return new ContactPhotoController($appName, $request, $app, $cache);
return new ContactController($this->appName, $request, $app);
});
$this->container->registerService('SettingsController', function(IAppContainer $container) use($appName, $app) {
$this->container->registerService('ContactPhotoController', function(IAppContainer $container) use($app) {
$request = $container->query('Request');
return new SettingsController($appName, $request, $app);
$cache = $this->server->getCache();
return new ContactPhotoController($this->appName, $request, $app, $cache);
});
$this->container->registerService('ImportController', function(IAppContainer $container) use($appName, $app) {
$this->container->registerService('SettingsController', function(IAppContainer $container) use($app) {
$request = $container->query('Request');
$cache = $container->getServer()->getCache();
return new ImportController($appName, $request, $app, $cache);
return new SettingsController($this->appName, $request, $app);
});
$this->container->registerService('ExportController', function(IAppContainer $container) use($appName, $app) {
$this->container->registerService('ImportController', function(IAppContainer $container) use($app) {
$request = $container->query('Request');
return new ExportController($appName, $request, $app);
$cache = $this->server->getCache();
return new ImportController($this->appName, $request, $app, $cache);
});
$this->container->registerService('ExportController', function(IAppContainer $container) use($app) {
$request = $container->query('Request');
return new ExportController($this->appName, $request, $app);
});
}

21
templates/admin.php Normal file
View File

@ -0,0 +1,21 @@
<?php
/**
* ownCloud - Contacts
*
* @author Nicolas Mora
* @copyright 2014 Nicolas Mora mail@babelouest.org
*
* This file is licensed under the Affero General Public License version 3 or
* later.
*/
?>
<div class="section">
<h2>Contacts</h2>
<input type="checkbox" name="contacts-ldap-enabled" id="contacts-ldap-enabled" value="checked" <?php (\OCP\Config::getAppValue('contacts', 'backend_ldap', "false") === "true")?print "checked":print ""?> />
<label for="contacts-ldap-enabled"><?php p($l->t('Enable LDAP Backend')) ?></label><br>
<em><?php p($l->t('Enable LDAP backend for the contacts application')) ?></em>
<br/><em><?php p($l->t('Warning: LDAP Backend is in beta mode, use with precautions')) ?></em>
</div>

View File

@ -1,3 +1,6 @@
<?php
use OCA\Contacts\ImportManager;
?>
<div id="app">
<div id="app-navigation" class="loading">
<ul id="grouplist" class="hidden-on-load">
@ -20,6 +23,15 @@
<ul class="addressbooklist">
</ul>
<input type="text" tabindex="0" autofocus id="add-address-book" placeholder="<?php p($l->t('Display name')); ?>" title="<?php p($l->t('Add Address Book')); ?>" />
<?php
if (\OCP\Config::getAppValue('contacts', 'backend_ldap', "false") === "true") {
?>
<ul class="oc-addnew">
<li id="add-ldap-address-book-element"><a class="oc-addnew-init"><?php p($l->t('Add LDAP Address Book')); ?></a></li>
</ul>
<?php
}
?>
</div>
<div id="import">
<h2 data-id="import" tabindex="0" role="button"><?php p($l->t('Import')); ?></h2>
@ -31,7 +43,8 @@
<select id="import_format">
<option value="automatic"><?php p($l->t('Automatic format')); ?></option>
<?php
$types = $_['importManager']->getTypes();
$importManager = new ImportManager();
$types = $importManager->getTypes();
foreach ($types as $id => $label) {
echo "<option value=\"$id\">$label</option>";
}
@ -503,3 +516,117 @@
</span>
</li>
</script>
<script id="addressBookConfigTemplate" class="hidden" type="text/template">
<div id="addressbooks-ui-div" class="addressbooks-ui-class">
<input type="hidden" id="addressbooks-ui-addressbookid" />
<input type="hidden" id="addressbooks-ui-backend" value="{backend}" />
<p id="addressbooks-ui-name-p">
<label for="addressbooks-ui-name">
<?php p($l->t('Name')); ?>:
</label>
<input type="text" class="nonempty value" id="addressbooks-ui-name" value=""
placeholder="<?php p($l->t('Name')); ?>" required />
</p>
<p id="addressbooks-ui-uri-p">
<label for="addressbooks-ui-uri">
<?php p($l->t('Addressbook URI')); ?>:
</label>
<input type="text" class="nonempty value" id="addressbooks-ui-uri" value=""
placeholder="<?php p($l->t('URI')); ?>" required />
</p>
<p id="addressbooks-ui-description-p">
<label for="addressbooks-ui-description">
<?php p($l->t('Description')); ?>:
</label>
<input type="text" class="nonempty value" id="addressbooks-ui-description" value=""
placeholder="<?php p($l->t('Description')); ?>" />
</p>
<p id="addressbooks-ui-ldapurl-p">
<label for="addressbooks-ui-ldapurl">
<?php p($l->t('LDAP URL')); ?>:
</label>
<input type="text" class="nonempty value" id="addressbooks-ui-ldapurl" value=""
placeholder="<?php p($l->t('LDAP URL')); ?>" required />
</p>
<p id="addressbooks-ui-ldapanonymous-p">
<label for="addressbooks-ui-ldapanonymous">
<?php p($l->t('Anonymous')); ?>:
</label>
<input type="checkbox" id="addressbooks-ui-ldapanonymous" title="<?php p($l->t('Anonymous')); ?>" />
</p>
<p id="addressbooks-ui-ldapreadonly-p">
<label for="addressbooks-ui-ldapreadonly">
<?php p($l->t('Read-only')); ?>:
</label>
<input type="checkbox" id="addressbooks-ui-ldapreadonly" title="<?php p($l->t('Read-Only')); ?>" />
</p>
<p id="addressbooks-ui-ldapuser-p">
<label for="addressbooks-ui-ldapuser">
<?php p($l->t('User')); ?>:
</label>
<input type="text" class="nonempty value" id="addressbooks-ui-ldapuser" value=""
placeholder="<?php p($l->t('User')); ?>" required />
</p>
<p id="addressbooks-ui-ldappass-p">
<input type="hidden" id="addressbooks-ui-ldappass-modified" />
<label for="addressbooks-ui-ldappass">
<?php p($l->t('Password')); ?>:
</label>
<input type="password" class="nonempty value" id="addressbooks-ui-ldappass" value=""
placeholder="<?php p($l->t('Password')); ?>" required />
</p>
<p id="addressbooks-ui-ldappagesize-p">
<label for="addressbooks-ui-ldappagesize">
<?php p($l->t('Page size')); ?>:
</label>
<input type="text" class="nonempty value" id="addressbooks-ui-ldappagesize" value="20"
placeholder="<?php p($l->t('Page size')); ?>" required />
</p>
<p id="addressbooks-ui-ldapbasednsearch-p">
<label for="addressbooks-ui-ldapbasednsearch">
<?php p($l->t('Base DN for search')); ?>:
</label>
<input type="text" class="nonempty value" id="addressbooks-ui-ldapbasednsearch" value=""
placeholder="<?php p($l->t('Base DN')); ?>" required />
</p>
<p id="addressbooks-ui-ldapfilter-p">
<label for="addressbooks-ui-ldapfilter">
<?php p($l->t('Search filter')); ?>:
</label>
<input type="text" class="nonempty value" id="addressbooks-ui-ldapfilter" value=""
placeholder="<?php p($l->t('Filter')); ?>" required />
</p>
<p id="addressbooks-ui-ldapbasednmodify-p">
<label for="addressbooks-ui-ldapbasednmodify">
<?php p($l->t('Base DN for modification')); ?>:
</label>
<input type="text" class="nonempty value" id="addressbooks-ui-ldapbasednmodify" value=""
placeholder="<?php p($l->t('Base DN modification')); ?>" required />
</p>
<p id="addressbooks-ui-ldapvcardconnector-p">
<label for="addressbooks-ui-ldapvcardconnector">
<?php p($l->t('Connector')); ?>:
</label>
<select id="addressbooks-ui-ldapvcardconnector">
</select>
</p>
<p id="addressbooks-ui-ldapvcardconnector-value-p">
<label for="addressbooks-ui-ldapvcardconnector-value">
<?php p($l->t('Connector value (Better use external editor and copy/paste)')); ?>:
</label>
<textarea id="addressbooks-ui-ldapvcardconnector-value"></textarea>
</p>
<p id="addressbooks-ui-ldapvcardconnector-copyfrom-p">
<label for="addressbooks-ui-ldapvcardconnector-copyfrom">
<?php p($l->t('Copy from (Warning, replaces current custom value)')); ?>:
</label>
<select id="addressbooks-ui-ldapvcardconnector-copyfrom">
</select>
</p>
<p id="addressbooks-ui-errortitle-p">&nbsp;
</p>
<p id="addressbooks-ui-errormessage-p">&nbsp;
</p>
</div>
</script>